1/** 2 * @license 3 * Copyright 2010-2023 Three.js Authors 4 * SPDX-License-Identifier: MIT 5 */ 6const REVISION = '160'; 7 8const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 }; 9const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 }; 10const CullFaceNone = 0; 11const CullFaceBack = 1; 12const CullFaceFront = 2; 13const CullFaceFrontBack = 3; 14const BasicShadowMap = 0; 15const PCFShadowMap = 1; 16const PCFSoftShadowMap = 2; 17const VSMShadowMap = 3; 18const FrontSide = 0; 19const BackSide = 1; 20const DoubleSide = 2; 21const TwoPassDoubleSide = 2; // r149 22const NoBlending = 0; 23const NormalBlending = 1; 24const AdditiveBlending = 2; 25const SubtractiveBlending = 3; 26const MultiplyBlending = 4; 27const CustomBlending = 5; 28const AddEquation = 100; 29const SubtractEquation = 101; 30const ReverseSubtractEquation = 102; 31const MinEquation = 103; 32const MaxEquation = 104; 33const ZeroFactor = 200; 34const OneFactor = 201; 35const SrcColorFactor = 202; 36const OneMinusSrcColorFactor = 203; 37const SrcAlphaFactor = 204; 38const OneMinusSrcAlphaFactor = 205; 39const DstAlphaFactor = 206; 40const OneMinusDstAlphaFactor = 207; 41const DstColorFactor = 208;
42const OneMinusDstColorFactor = 209; 43const SrcAlphaSaturateFactor = 210; 44const ConstantColorFactor = 211; 45const OneMinusConstantColorFactor = 212; 46const ConstantAlphaFactor = 213; 47const OneMinusConstantAlphaFactor = 214; 48const NeverDepth = 0; 49const AlwaysDepth = 1; 50const LessDepth = 2; 51const LessEqualDepth = 3; 52const EqualDepth = 4; 53const GreaterEqualDepth = 5; 54const GreaterDepth = 6; 55const NotEqualDepth = 7; 56const MultiplyOperation = 0; 57const MixOperation = 1; 58const AddOperation = 2; 59const NoToneMapping = 0; 60const LinearToneMapping = 1; 61const ReinhardToneMapping = 2; 62const CineonToneMapping = 3; 63const ACESFilmicToneMapping = 4; 64const CustomToneMapping = 5; 65const AgXToneMapping = 6; 66const AttachedBindMode = 'attached'; 67const DetachedBindMode = 'detached'; 68 69const UVMapping = 300; 70const CubeReflectionMapping = 301; 71const CubeRefractionMapping = 302; 72const EquirectangularReflectionMapping = 303; 73const EquirectangularRefractionMapping = 304; 74const CubeUVReflectionMapping = 306; 75const RepeatWrapping = 1000; 76const ClampToEdgeWrapping = 1001; 77const MirroredRepeatWrapping = 1002; 78const NearestFilter = 1003; 79const NearestMipmapNearestFilter = 1004; 80const NearestMipMapNearestFilter = 1004; 81const NearestMipmapLinearFilter = 1005; 82const NearestMipMapLinearFilter = 1005; 83const LinearFilter = 1006; 84const LinearMipmapNearestFilter = 1007; 85const LinearMipMapNearestFilter = 1007; 86const LinearMipmapLinearFilter = 1008; 87const LinearMipMapLinearFilter = 1008; 88const UnsignedByteType = 1009; 89const ByteType = 1010; 90const ShortType = 1011; 91const UnsignedShortType = 1012; 92const IntType = 1013; 93const UnsignedIntType = 1014; 94const FloatType = 1015; 95const HalfFloatType = 1016; 96const UnsignedShort4444Type = 1017; 97const UnsignedShort5551Type = 1018; 98const UnsignedInt248Type = 1020; 99const AlphaFormat = 1021; 100const RGBAFormat = 1023; 101const LuminanceFormat = 1024; 102const LuminanceAlphaFormat = 1025; 103const DepthFormat = 1026; 104const DepthStencilFormat = 1027; 105const RedFormat = 1028; 106const RedIntegerFormat = 1029; 107const RGFormat = 1030; 108const RGIntegerFormat = 1031; 109const RGBAIntegerFormat = 1033; 110 111const RGB_S3TC_DXT1_Format = 33776; 112const RGBA_S3TC_DXT1_Format = 33777; 113const RGBA_S3TC_DXT3_Format = 33778; 114const RGBA_S3TC_DXT5_Format = 33779; 115const RGB_PVRTC_4BPPV1_Format = 35840; 116const RGB_PVRTC_2BPPV1_Format = 35841; 117const RGBA_PVRTC_4BPPV1_Format = 35842; 118const RGBA_PVRTC_2BPPV1_Format = 35843; 119const RGB_ETC1_Format = 36196; 120const RGB_ETC2_Format = 37492; 121const RGBA_ETC2_EAC_Format = 37496; 122const RGBA_ASTC_4x4_Format = 37808; 123const RGBA_ASTC_5x4_Format = 37809; 124const RGBA_ASTC_5x5_Format = 37810; 125const RGBA_ASTC_6x5_Format = 37811; 126const RGBA_ASTC_6x6_Format = 37812; 127const RGBA_ASTC_8x5_Format = 37813; 128const RGBA_ASTC_8x6_Format = 37814; 129const RGBA_ASTC_8x8_Format = 37815; 130const RGBA_ASTC_10x5_Format = 37816; 131const RGBA_ASTC_10x6_Format = 37817; 132const RGBA_ASTC_10x8_Format = 37818; 133const RGBA_ASTC_10x10_Format = 37819; 134const RGBA_ASTC_12x10_Format = 37820; 135const RGBA_ASTC_12x12_Format = 37821; 136const RGBA_BPTC_Format = 36492; 137const RGB_BPTC_SIGNED_Format = 36494; 138const RGB_BPTC_UNSIGNED_Format = 36495; 139const RED_RGTC1_Format = 36283; 140const SIGNED_RED_RGTC1_Format = 36284; 141const RED_GREEN_RGTC2_Format = 36285; 142const SIGNED_RED_GREEN_RGTC2_Format = 36286; 143const LoopOnce = 2200; 144const LoopRepeat = 2201; 145const LoopPingPong = 2202; 146const InterpolateDiscrete = 2300; 147const InterpolateLinear = 2301; 148const InterpolateSmooth = 2302; 149const ZeroCurvatureEnding = 2400; 150const ZeroSlopeEnding = 2401; 151const WrapAroundEnding = 2402; 152const NormalAnimationBlendMode = 2500; 153const AdditiveAnimationBlendMode = 2501; 154const TrianglesDrawMode = 0; 155const TriangleStripDrawMode = 1; 156const TriangleFanDrawMode = 2; 157/** @deprecated Use LinearSRGBColorSpace or NoColorSpace in three.js r152+. */ 158const LinearEncoding = 3000; 159/** @deprecated Use SRGBColorSpace in three.js r152+. */ 160const sRGBEncoding = 3001; 161const BasicDepthPacking = 3200; 162const RGBADepthPacking = 3201; 163const TangentSpaceNormalMap = 0; 164const ObjectSpaceNormalMap = 1; 165 166// Color space string identifiers, matching CSS Color Module Level 4 and WebGPU n
vendor: 7,693 bytes, lines 166-434
166ames where available. 167const NoColorSpace = ''; 168const SRGBColorSpace = 'srgb'; 169const LinearSRGBColorSpace = 'srgb-linear'; 170const DisplayP3ColorSpace = 'display-p3'; 171const LinearDisplayP3ColorSpace = 'display-p3-linear'; 172 173const LinearTransfer = 'linear'; 174const SRGBTransfer = 'srgb'; 175 176const Rec709Primaries = 'rec709'; 177const P3Primaries = 'p3'; 178 179const ZeroStencilOp = 0; 180const KeepStencilOp = 7680; 181const ReplaceStencilOp = 7681; 182const IncrementStencilOp = 7682; 183const DecrementStencilOp = 7683; 184const IncrementWrapStencilOp = 34055; 185const DecrementWrapStencilOp = 34056; 186const InvertStencilOp = 5386; 187 188const NeverStencilFunc = 512; 189const LessStencilFunc = 513; 190const EqualStencilFunc = 514; 191const LessEqualStencilFunc = 515; 192const GreaterStencilFunc = 516; 193const NotEqualStencilFunc = 517; 194const GreaterEqualStencilFunc = 518; 195const AlwaysStencilFunc = 519; 196 197const NeverCompare = 512; 198const LessCompare = 513; 199const EqualCompare = 514; 200const LessEqualCompare = 515; 201const GreaterCompare = 516; 202const NotEqualCompare = 517; 203const GreaterEqualCompare = 518; 204const AlwaysCompare = 519; 205 206const StaticDrawUsage = 35044; 207const DynamicDrawUsage = 35048; 208const StreamDrawUsage = 35040; 209const StaticReadUsage = 35045; 210const DynamicReadUsage = 35049; 211const StreamReadUsage = 35041; 212const StaticCopyUsage = 35046; 213const DynamicCopyUsage = 35050; 214const StreamCopyUsage = 35042; 215 216const GLSL1 = '100'; 217const GLSL3 = '300 es'; 218 219const _SRGBAFormat = 1035; // fallback for WebGL 1 220 221const WebGLCoordinateSystem = 2000; 222const WebGPUCoordinateSystem = 2001; 223 224/** 225 * https://github.com/mrdoob/eventdispatcher.js/ 226 */ 227 228class EventDispatcher { 229 230 addEventListener( type, listener ) { 231 232 if ( this._listeners === undefined ) this._listeners = {}; 233 234 const listeners = this._listeners; 235 236 if ( listeners[ type ] === undefined ) { 237 238 listeners[ type ] = []; 239 240 } 241 242 if ( listeners[ type ].indexOf( listener ) === - 1 ) { 243 244 listeners[ type ].push( listener ); 245 246 } 247 248 } 249 250 hasEventListener( type, listener ) { 251 252 if ( this._listeners === undefined ) return false; 253 254 const listeners = this._listeners; 255 256 return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1; 257 258 } 259 260 removeEventListener( type, listener ) { 261 262 if ( this._listeners === undefined ) return; 263 264 const listeners = this._listeners; 265 const listenerArray = listeners[ type ]; 266 267 if ( listenerArray !== undefined ) { 268 269 const index = listenerArray.indexOf( listener ); 270 271 if ( index !== - 1 ) { 272 273 listenerArray.splice( index, 1 ); 274 275 } 276 277 } 278 279 } 280 281 dispatchEvent( event ) { 282 283 if ( this._listeners === undefined ) return; 284 285 const listeners = this._listeners; 286 const listenerArray = listeners[ event.type ]; 287 288 if ( listenerArray !== undefined ) { 289 290 event.target = this; 291 292 // Make a copy, in case listeners are removed while iterating. 293 const array = listenerArray.slice( 0 ); 294 295 for ( let i = 0, l = array.length; i < l; i ++ ) { 296 297 array[ i ].call( this, event ); 298 299 } 300 301 event.target = null; 302 303 } 304 305 } 306 307} 308 309const _lut = [ '00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '0a', '0b', '0c', '0d', '0e', '0f', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '1a', '1b', '1c', '1d', '1e', '1f', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '2a', '2b', '2c', '2d', '2e', '2f', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '3a', '3b', '3c', '3d', '3e', '3f', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '4a', '4b', '4c', '4d', '4e', '4f', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '5a', '5b', '5c', '5d', '5e', '5f', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '6a', '6b', '6c', '6d', '6e', '6f', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '7a', '7b', '7c', '7d', '7e', '7f', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '8a', '8b', '8c', '8d', '8e', '8f', '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', '9a', '9b', '9c', '9d', '9e', '9f', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'a9', 'aa', 'ab', 'ac', 'ad', 'ae', 'af', 'b0', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'b9', 'ba', 'bb', 'bc', 'bd', 'be', 'bf', 'c0', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'ca', 'cb', 'cc', 'cd', 'ce', 'cf', 'd0', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9', 'da', 'db', 'dc', 'dd', 'de', 'df', 'e0', 'e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7', 'e8', 'e9', 'ea', 'eb', 'ec', 'ed', 'ee', 'ef', 'f0', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'fa', 'fb', 'fc', 'fd', 'fe', 'ff' ]; 310 311let _seed = 1234567; 312 313 314const DEG2RAD = Math.PI / 180; 315const RAD2DEG = 180 / Math.PI; 316 317// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 318function generateUUID() { 319 320 const d0 = Math.random() * 0xffffffff | 0; 321 const d1 = Math.random() * 0xffffffff | 0; 322 const d2 = Math.random() * 0xffffffff | 0; 323 const d3 = Math.random() * 0xffffffff | 0; 324 const uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' + 325 _lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' + 326 _lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] + 327 _lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ]; 328 329 // .toLowerCase() here flattens concatenated strings to save heap memory space. 330 return uuid.toLowerCase(); 331 332} 333 334function clamp( value, min, max ) { 335 336 return Math.max( min, Math.min( max, value ) ); 337 338} 339 340// compute euclidean modulo of m % n 341// https://en.wikipedia.org/wiki/Modulo_operation 342function euclideanModulo( n, m ) { 343 344 return ( ( n % m ) + m ) % m; 345 346} 347 348// Linear mapping from range <a1, a2> to range <b1, b2> 349function mapLinear( x, a1, a2, b1, b2 ) { 350 351 return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); 352 353} 354 355// https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/ 356function inverseLerp( x, y, value ) { 357 358 if ( x !== y ) { 359 360 return ( value - x ) / ( y - x ); 361 362 } else { 363 364 return 0; 365 366 } 367 368} 369 370// https://en.wikipedia.org/wiki/Linear_interpolation 371function lerp( x, y, t ) { 372 373 return ( 1 - t ) * x + t * y; 374 375} 376 377// http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/ 378function damp( x, y, lambda, dt ) { 379 380 return lerp( x, y, 1 - Math.exp( - lambda * dt ) ); 381 382} 383 384// https://www.desmos.com/calculator/vcsjnyz7x4 385function pingpong( x, length = 1 ) { 386 387 return length - Math.abs( euclideanModulo( x, length * 2 ) - length ); 388 389} 390 391// http://en.wikipedia.org/wiki/Smoothstep 392function smoothstep( x, min, max ) { 393 394 if ( x <= min ) return 0; 395 if ( x >= max ) return 1; 396 397 x = ( x - min ) / ( max - min ); 398 399 return x * x * ( 3 - 2 * x ); 400 401} 402 403function smootherstep( x, min, max ) { 404 405 if ( x <= min ) return 0; 406 if ( x >= max ) return 1; 407 408 x = ( x - min ) / ( max - min ); 409 410 return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); 411 412} 413 414// Random integer from <low, high> interval 415function randInt( low, high ) { 416 417 return low + Math.floor( Math.random() * ( high - low + 1 ) ); 418 419} 420 421// Random float from <low, high> interval 422function randFloat( low, high ) { 423 424 return low + Math.random() * ( high - low ); 425 426} 427 428// Random float from <-range/2, range/2> interval 429function randFloatSpread( range ) { 430 431 return range * ( 0.5 - Math.random() ); 432 433} 434
vendor: 5,932 bytes, lines 435-835
435// Deterministic pseudo-random float in the interval [ 0, 1 ] 436function seededRandom( s ) { 437 438 if ( s !== undefined ) _seed = s; 439 440 // Mulberry32 generator 441 442 let t = _seed += 0x6D2B79F5; 443 444 t = Math.imul( t ^ t >>> 15, t | 1 ); 445 446 t ^= t + Math.imul( t ^ t >>> 7, t | 61 ); 447 448 return ( ( t ^ t >>> 14 ) >>> 0 ) / 4294967296; 449 450} 451 452function degToRad( degrees ) { 453 454 return degrees * DEG2RAD; 455 456} 457 458function radToDeg( radians ) { 459 460 return radians * RAD2DEG; 461 462} 463 464function isPowerOfTwo( value ) { 465 466 return ( value & ( value - 1 ) ) === 0 && value !== 0; 467 468} 469 470function ceilPowerOfTwo( value ) { 471 472 return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) ); 473 474} 475 476function floorPowerOfTwo( value ) { 477 478 return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) ); 479 480} 481 482function setQuaternionFromProperEuler( q, a, b, c, order ) { 483 484 // Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles 485 486 // rotations are applied to the axes in the order specified by 'order' 487 // rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c' 488 // angles are in radians 489 490 const cos = Math.cos; 491 const sin = Math.sin; 492 493 const c2 = cos( b / 2 ); 494 const s2 = sin( b / 2 ); 495 496 const c13 = cos( ( a + c ) / 2 ); 497 const s13 = sin( ( a + c ) / 2 ); 498 499 const c1_3 = cos( ( a - c ) / 2 ); 500 const s1_3 = sin( ( a - c ) / 2 ); 501 502 const c3_1 = cos( ( c - a ) / 2 ); 503 const s3_1 = sin( ( c - a ) / 2 ); 504 505 switch ( order ) { 506 507 case 'XYX': 508 q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 ); 509 break; 510 511 case 'YZY': 512 q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 ); 513 break; 514 515 case 'ZXZ': 516 q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 ); 517 break; 518 519 case 'XZX': 520 q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 ); 521 break; 522 523 case 'YXY': 524 q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 ); 525 break; 526 527 case 'ZYZ': 528 q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 ); 529 break; 530 531 default: 532 console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order ); 533 534 } 535 536} 537 538function denormalize( value, array ) { 539 540 switch ( array.constructor ) { 541 542 case Float32Array: 543 544 return value; 545 546 case Uint32Array: 547 548 return value / 4294967295.0; 549 550 case Uint16Array: 551 552 return value / 65535.0; 553 554 case Uint8Array: 555 556 return value / 255.0; 557 558 case Int32Array: 559 560 return Math.max( value / 2147483647.0, - 1.0 ); 561 562 case Int16Array: 563 564 return Math.max( value / 32767.0, - 1.0 ); 565 566 case Int8Array: 567 568 return Math.max( value / 127.0, - 1.0 ); 569 570 default: 571 572 throw new Error( 'Invalid component type.' ); 573 574 } 575 576} 577 578function normalize( value, array ) { 579 580 switch ( array.constructor ) { 581 582 case Float32Array: 583 584 return value; 585 586 case Uint32Array: 587 588 return Math.round( value * 4294967295.0 ); 589 590 case Uint16Array: 591 592 return Math.round( value * 65535.0 ); 593 594 case Uint8Array: 595 596 return Math.round( value * 255.0 ); 597 598 case Int32Array: 599 600 return Math.round( value * 2147483647.0 ); 601 602 case Int16Array: 603 604 return Math.round( value * 32767.0 ); 605 606 case Int8Array: 607 608 return Math.round( value * 127.0 ); 609 610 default: 611 612 throw new Error( 'Invalid component type.' ); 613 614 } 615 616} 617 618const MathUtils = { 619 DEG2RAD: DEG2RAD, 620 RAD2DEG: RAD2DEG, 621 generateUUID: generateUUID, 622 clamp: clamp, 623 euclideanModulo: euclideanModulo, 624 mapLinear: mapLinear, 625 inverseLerp: inverseLerp, 626 lerp: lerp, 627 damp: damp, 628 pingpong: pingpong, 629 smoothstep: smoothstep, 630 smootherstep: smootherstep, 631 randInt: randInt, 632 randFloat: randFloat, 633 randFloatSpread: randFloatSpread, 634 seededRandom: seededRandom, 635 degToRad: degToRad, 636 radToDeg: radToDeg, 637 isPowerOfTwo: isPowerOfTwo, 638 ceilPowerOfTwo: ceilPowerOfTwo, 639 floorPowerOfTwo: floorPowerOfTwo, 640 setQuaternionFromProperEuler: setQuaternionFromProperEuler, 641 normalize: normalize, 642 denormalize: denormalize 643}; 644 645class Vector2 { 646 647 constructor( x = 0, y = 0 ) { 648 649 Vector2.prototype.isVector2 = true; 650 651 this.x = x; 652 this.y = y; 653 654 } 655 656 get width() { 657 658 return this.x; 659 660 } 661 662 set width( value ) { 663 664 this.x = value; 665 666 } 667 668 get height() { 669 670 return this.y; 671 672 } 673 674 set height( value ) { 675 676 this.y = value; 677 678 } 679 680 set( x, y ) { 681 682 this.x = x; 683 this.y = y; 684 685 return this; 686 687 } 688 689 setScalar( scalar ) { 690 691 this.x = scalar; 692 this.y = scalar; 693 694 return this; 695 696 } 697 698 setX( x ) { 699 700 this.x = x; 701 702 return this; 703 704 } 705 706 setY( y ) { 707 708 this.y = y; 709 710 return this; 711 712 } 713 714 setComponent( index, value ) { 715 716 switch ( index ) { 717 718 case 0: this.x = value; break; 719 case 1: this.y = value; break; 720 default: throw new Error( 'index is out of range: ' + index ); 721 722 } 723 724 return this; 725 726 } 727 728 getComponent( index ) { 729 730 switch ( index ) { 731 732 case 0: return this.x; 733 case 1: return this.y; 734 default: throw new Error( 'index is out of range: ' + index ); 735 736 } 737 738 } 739 740 clone() { 741 742 return new this.constructor( this.x, this.y ); 743 744 } 745 746 copy( v ) { 747 748 this.x = v.x; 749 this.y = v.y; 750 751 return this; 752 753 } 754 755 add( v ) { 756 757 this.x += v.x; 758 this.y += v.y; 759 760 return this; 761 762 } 763 764 addScalar( s ) { 765 766 this.x += s; 767 this.y += s; 768 769 return this; 770 771 } 772 773 addVectors( a, b ) { 774 775 this.x = a.x + b.x; 776 this.y = a.y + b.y; 777 778 return this; 779 780 } 781 782 addScaledVector( v, s ) { 783 784 this.x += v.x * s; 785 this.y += v.y * s; 786 787 return this; 788 789 } 790 791 sub( v ) { 792 793 this.x -= v.x; 794 this.y -= v.y; 795 796 return this; 797 798 } 799 800 subScalar( s ) { 801 802 this.x -= s; 803 this.y -= s; 804 805 return this; 806 807 } 808 809 subVectors( a, b ) { 810 811 this.x = a.x - b.x; 812 this.y = a.y - b.y; 813 814 return this; 815 816 } 817 818 multiply( v ) { 819 820 this.x *= v.x; 821 this.y *= v.y; 822 823 return this; 824 825 } 826 827 multiplyScalar( scalar ) { 828 829 this.x *= scalar; 830 this.y *= scalar; 831 832 return this; 833 834 } 835
vendor: 6,898 bytes, lines 836-1268
836 divide( v ) { 837 838 this.x /= v.x; 839 this.y /= v.y; 840 841 return this; 842 843 } 844 845 divideScalar( scalar ) { 846 847 return this.multiplyScalar( 1 / scalar ); 848 849 } 850 851 applyMatrix3( m ) { 852 853 const x = this.x, y = this.y; 854 const e = m.elements; 855 856 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ]; 857 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ]; 858 859 return this; 860 861 } 862 863 min( v ) { 864 865 this.x = Math.min( this.x, v.x ); 866 this.y = Math.min( this.y, v.y ); 867 868 return this; 869 870 } 871 872 max( v ) { 873 874 this.x = Math.max( this.x, v.x ); 875 this.y = Math.max( this.y, v.y ); 876 877 return this; 878 879 } 880 881 clamp( min, max ) { 882 883 // assumes min < max, componentwise 884 885 this.x = Math.max( min.x, Math.min( max.x, this.x ) ); 886 this.y = Math.max( min.y, Math.min( max.y, this.y ) ); 887 888 return this; 889 890 } 891 892 clampScalar( minVal, maxVal ) { 893 894 this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); 895 this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); 896 897 return this; 898 899 } 900 901 clampLength( min, max ) { 902 903 const length = this.length(); 904 905 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); 906 907 } 908 909 floor() { 910 911 this.x = Math.floor( this.x ); 912 this.y = Math.floor( this.y ); 913 914 return this; 915 916 } 917 918 ceil() { 919 920 this.x = Math.ceil( this.x ); 921 this.y = Math.ceil( this.y ); 922 923 return this; 924 925 } 926 927 round() { 928 929 this.x = Math.round( this.x ); 930 this.y = Math.round( this.y ); 931 932 return this; 933 934 } 935 936 roundToZero() { 937 938 this.x = Math.trunc( this.x ); 939 this.y = Math.trunc( this.y ); 940 941 return this; 942 943 } 944 945 negate() { 946 947 this.x = - this.x; 948 this.y = - this.y; 949 950 return this; 951 952 } 953 954 dot( v ) { 955 956 return this.x * v.x + this.y * v.y; 957 958 } 959 960 cross( v ) { 961 962 return this.x * v.y - this.y * v.x; 963 964 } 965 966 lengthSq() { 967 968 return this.x * this.x + this.y * this.y; 969 970 } 971 972 length() { 973 974 return Math.sqrt( this.x * this.x + this.y * this.y ); 975 976 } 977 978 manhattanLength() { 979 980 return Math.abs( this.x ) + Math.abs( this.y ); 981 982 } 983 984 normalize() { 985 986 return this.divideScalar( this.length() || 1 ); 987 988 } 989 990 angle() { 991 992 // computes the angle in radians with respect to the positive x-axis 993 994 const angle = Math.atan2( - this.y, - this.x ) + Math.PI; 995 996 return angle; 997 998 } 999 1000 angleTo( v ) { 1001 1002 const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); 1003 1004 if ( denominator === 0 ) return Math.PI / 2; 1005 1006 const theta = this.dot( v ) / denominator; 1007 1008 // clamp, to handle numerical problems 1009 1010 return Math.acos( clamp( theta, - 1, 1 ) ); 1011 1012 } 1013 1014 distanceTo( v ) { 1015 1016 return Math.sqrt( this.distanceToSquared( v ) ); 1017 1018 } 1019 1020 distanceToSquared( v ) { 1021 1022 const dx = this.x - v.x, dy = this.y - v.y; 1023 return dx * dx + dy * dy; 1024 1025 } 1026 1027 manhattanDistanceTo( v ) { 1028 1029 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ); 1030 1031 } 1032 1033 setLength( length ) { 1034 1035 return this.normalize().multiplyScalar( length ); 1036 1037 } 1038 1039 lerp( v, alpha ) { 1040 1041 this.x += ( v.x - this.x ) * alpha; 1042 this.y += ( v.y - this.y ) * alpha; 1043 1044 return this; 1045 1046 } 1047 1048 lerpVectors( v1, v2, alpha ) { 1049 1050 this.x = v1.x + ( v2.x - v1.x ) * alpha; 1051 this.y = v1.y + ( v2.y - v1.y ) * alpha; 1052 1053 return this; 1054 1055 } 1056 1057 equals( v ) { 1058 1059 return ( ( v.x === this.x ) && ( v.y === this.y ) ); 1060 1061 } 1062 1063 fromArray( array, offset = 0 ) { 1064 1065 this.x = array[ offset ]; 1066 this.y = array[ offset + 1 ]; 1067 1068 return this; 1069 1070 } 1071 1072 toArray( array = [], offset = 0 ) { 1073 1074 array[ offset ] = this.x; 1075 array[ offset + 1 ] = this.y; 1076 1077 return array; 1078 1079 } 1080 1081 fromBufferAttribute( attribute, index ) { 1082 1083 this.x = attribute.getX( index ); 1084 this.y = attribute.getY( index ); 1085 1086 return this; 1087 1088 } 1089 1090 rotateAround( center, angle ) { 1091 1092 const c = Math.cos( angle ), s = Math.sin( angle ); 1093 1094 const x = this.x - center.x; 1095 const y = this.y - center.y; 1096 1097 this.x = x * c - y * s + center.x; 1098 this.y = x * s + y * c + center.y; 1099 1100 return this; 1101 1102 } 1103 1104 random() { 1105 1106 this.x = Math.random(); 1107 this.y = Math.random(); 1108 1109 return this; 1110 1111 } 1112 1113 *[ Symbol.iterator ]() { 1114 1115 yield this.x; 1116 yield this.y; 1117 1118 } 1119 1120} 1121 1122class Matrix3 { 1123 1124 constructor( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { 1125 1126 Matrix3.prototype.isMatrix3 = true; 1127 1128 this.elements = [ 1129 1130 1, 0, 0, 1131 0, 1, 0, 1132 0, 0, 1 1133 1134 ]; 1135 1136 if ( n11 !== undefined ) { 1137 1138 this.set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ); 1139 1140 } 1141 1142 } 1143 1144 set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { 1145 1146 const te = this.elements; 1147 1148 te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31; 1149 te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32; 1150 te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33; 1151 1152 return this; 1153 1154 } 1155 1156 identity() { 1157 1158 this.set( 1159 1160 1, 0, 0, 1161 0, 1, 0, 1162 0, 0, 1 1163 1164 ); 1165 1166 return this; 1167 1168 } 1169 1170 copy( m ) { 1171 1172 const te = this.elements; 1173 const me = m.elements; 1174 1175 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; 1176 te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; 1177 te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ]; 1178 1179 return this; 1180 1181 } 1182 1183 extractBasis( xAxis, yAxis, zAxis ) { 1184 1185 xAxis.setFromMatrix3Column( this, 0 ); 1186 yAxis.setFromMatrix3Column( this, 1 ); 1187 zAxis.setFromMatrix3Column( this, 2 ); 1188 1189 return this; 1190 1191 } 1192 1193 setFromMatrix4( m ) { 1194 1195 const me = m.elements; 1196 1197 this.set( 1198 1199 me[ 0 ], me[ 4 ], me[ 8 ], 1200 me[ 1 ], me[ 5 ], me[ 9 ], 1201 me[ 2 ], me[ 6 ], me[ 10 ] 1202 1203 ); 1204 1205 return this; 1206 1207 } 1208 1209 multiply( m ) { 1210 1211 return this.multiplyMatrices( this, m ); 1212 1213 } 1214 1215 premultiply( m ) { 1216 1217 return this.multiplyMatrices( m, this ); 1218 1219 } 1220 1221 multiplyMatrices( a, b ) { 1222 1223 const ae = a.elements; 1224 const be = b.elements; 1225 const te = this.elements; 1226 1227 const a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ]; 1228 const a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ]; 1229 const a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ]; 1230 1231 const b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ]; 1232 const b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ]; 1233 const b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ]; 1234 1235 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31; 1236 te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32; 1237 te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33; 1238 1239 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31; 1240 te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32; 1241 te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33; 1242 1243 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31; 1244 te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32; 1245 te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33; 1246 1247 return this; 1248 1249 } 1250 1251 multiplyScalar( s ) { 1252 1253 const te = this.elements; 1254 1255 te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s; 1256 te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s; 1257 te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s; 1258 1259 return this; 1260 1261 } 1262 1263 determinant() { 1264 1265 const te = this.elements; 1266 1267 const a = te[ 0 ], b = te[ 1 ], c = te[ 2 ], 1268 d = te[ 3 ], e = te[ 4 ], f = te[ 5 ],
vendor: 4,678 bytes, lines 1269-1560
1269 g = te[ 6 ], h = te[ 7 ], i = te[ 8 ]; 1270 1271 return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g; 1272 1273 } 1274 1275 invert() { 1276 1277 const te = this.elements, 1278 1279 n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], 1280 n12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ], 1281 n13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ], 1282 1283 t11 = n33 * n22 - n32 * n23, 1284 t12 = n32 * n13 - n33 * n12, 1285 t13 = n23 * n12 - n22 * n13, 1286 1287 det = n11 * t11 + n21 * t12 + n31 * t13; 1288 1289 if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 ); 1290 1291 const detInv = 1 / det; 1292 1293 te[ 0 ] = t11 * detInv; 1294 te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv; 1295 te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv; 1296 1297 te[ 3 ] = t12 * detInv; 1298 te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv; 1299 te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv; 1300 1301 te[ 6 ] = t13 * detInv; 1302 te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv; 1303 te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv; 1304 1305 return this; 1306 1307 } 1308 1309 transpose() { 1310 1311 let tmp; 1312 const m = this.elements; 1313 1314 tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp; 1315 tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp; 1316 tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp; 1317 1318 return this; 1319 1320 } 1321 1322 getNormalMatrix( matrix4 ) { 1323 1324 return this.setFromMatrix4( matrix4 ).invert().transpose(); 1325 1326 } 1327 1328 transposeIntoArray( r ) { 1329 1330 const m = this.elements; 1331 1332 r[ 0 ] = m[ 0 ]; 1333 r[ 1 ] = m[ 3 ]; 1334 r[ 2 ] = m[ 6 ]; 1335 r[ 3 ] = m[ 1 ]; 1336 r[ 4 ] = m[ 4 ]; 1337 r[ 5 ] = m[ 7 ]; 1338 r[ 6 ] = m[ 2 ]; 1339 r[ 7 ] = m[ 5 ]; 1340 r[ 8 ] = m[ 8 ]; 1341 1342 return this; 1343 1344 } 1345 1346 setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) { 1347 1348 const c = Math.cos( rotation ); 1349 const s = Math.sin( rotation ); 1350 1351 this.set( 1352 sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx, 1353 - sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty, 1354 0, 0, 1 1355 ); 1356 1357 return this; 1358 1359 } 1360 1361 // 1362 1363 scale( sx, sy ) { 1364 1365 this.premultiply( _m3.makeScale( sx, sy ) ); 1366 1367 return this; 1368 1369 } 1370 1371 rotate( theta ) { 1372 1373 this.premultiply( _m3.makeRotation( - theta ) ); 1374 1375 return this; 1376 1377 } 1378 1379 translate( tx, ty ) { 1380 1381 this.premultiply( _m3.makeTranslation( tx, ty ) ); 1382 1383 return this; 1384 1385 } 1386 1387 // for 2D Transforms 1388 1389 makeTranslation( x, y ) { 1390 1391 if ( x.isVector2 ) { 1392 1393 this.set( 1394 1395 1, 0, x.x, 1396 0, 1, x.y, 1397 0, 0, 1 1398 1399 ); 1400 1401 } else { 1402 1403 this.set( 1404 1405 1, 0, x, 1406 0, 1, y, 1407 0, 0, 1 1408 1409 ); 1410 1411 } 1412 1413 return this; 1414 1415 } 1416 1417 makeRotation( theta ) { 1418 1419 // counterclockwise 1420 1421 const c = Math.cos( theta ); 1422 const s = Math.sin( theta ); 1423 1424 this.set( 1425 1426 c, - s, 0, 1427 s, c, 0, 1428 0, 0, 1 1429 1430 ); 1431 1432 return this; 1433 1434 } 1435 1436 makeScale( x, y ) { 1437 1438 this.set( 1439 1440 x, 0, 0, 1441 0, y, 0, 1442 0, 0, 1 1443 1444 ); 1445 1446 return this; 1447 1448 } 1449 1450 // 1451 1452 equals( matrix ) { 1453 1454 const te = this.elements; 1455 const me = matrix.elements; 1456 1457 for ( let i = 0; i < 9; i ++ ) { 1458 1459 if ( te[ i ] !== me[ i ] ) return false; 1460 1461 } 1462 1463 return true; 1464 1465 } 1466 1467 fromArray( array, offset = 0 ) { 1468 1469 for ( let i = 0; i < 9; i ++ ) { 1470 1471 this.elements[ i ] = array[ i + offset ]; 1472 1473 } 1474 1475 return this; 1476 1477 } 1478 1479 toArray( array = [], offset = 0 ) { 1480 1481 const te = this.elements; 1482 1483 array[ offset ] = te[ 0 ]; 1484 array[ offset + 1 ] = te[ 1 ]; 1485 array[ offset + 2 ] = te[ 2 ]; 1486 1487 array[ offset + 3 ] = te[ 3 ]; 1488 array[ offset + 4 ] = te[ 4 ]; 1489 array[ offset + 5 ] = te[ 5 ]; 1490 1491 array[ offset + 6 ] = te[ 6 ]; 1492 array[ offset + 7 ] = te[ 7 ]; 1493 array[ offset + 8 ] = te[ 8 ]; 1494 1495 return array; 1496 1497 } 1498 1499 clone() { 1500 1501 return new this.constructor().fromArray( this.elements ); 1502 1503 } 1504 1505} 1506 1507const _m3 = /*@__PURE__*/ new Matrix3(); 1508 1509function arrayNeedsUint32( array ) { 1510 1511 // assumes larger values usually on last 1512 1513 for ( let i = array.length - 1; i >= 0; -- i ) { 1514 1515 if ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565 1516 1517 } 1518 1519 return false; 1520 1521} 1522 1523const TYPED_ARRAYS = { 1524 Int8Array: Int8Array, 1525 Uint8Array: Uint8Array, 1526 Uint8ClampedArray: Uint8ClampedArray, 1527 Int16Array: Int16Array, 1528 Uint16Array: Uint16Array, 1529 Int32Array: Int32Array, 1530 Uint32Array: Uint32Array, 1531 Float32Array: Float32Array, 1532 Float64Array: Float64Array 1533}; 1534 1535function getTypedArray( type, buffer ) { 1536 1537 return new TYPED_ARRAYS[ type ]( buffer ); 1538 1539} 1540 1541function createElementNS( name ) { 1542 1543 return document.createElementNS( 'http://www.w3.org/1999/xhtml', name ); 1544 1545} 1546 1547function createCanvasElement() { 1548 1549 const canvas = createElementNS( 'canvas' ); 1550 canvas.style.display = 'block'; 1551 return canvas; 1552 1553} 1554 1555const _cache = {}; 1556 1557function warnOnce( message ) { 1558 1559 if ( message in _cache ) return; 1560
vendor: 8,200 bytes, lines 1561-1953
1561 _cache[ message ] = true; 1562 1563 console.warn( message ); 1564 1565} 1566 1567/** 1568 * Matrices converting P3 <-> Rec. 709 primaries, without gamut mapping 1569 * or clipping. Based on W3C specifications for sRGB and Display P3, 1570 * and ICC specifications for the D50 connection space. Values in/out 1571 * are _linear_ sRGB and _linear_ Display P3. 1572 * 1573 * Note that both sRGB and Display P3 use the sRGB transfer functions. 1574 * 1575 * Reference: 1576 * - http://www.russellcottrell.com/photo/matrixCalculator.htm 1577 */ 1578 1579const LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = /*@__PURE__*/ new Matrix3().set( 1580 0.8224621, 0.177538, 0.0, 1581 0.0331941, 0.9668058, 0.0, 1582 0.0170827, 0.0723974, 0.9105199, 1583); 1584 1585const LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = /*@__PURE__*/ new Matrix3().set( 1586 1.2249401, - 0.2249404, 0.0, 1587 - 0.0420569, 1.0420571, 0.0, 1588 - 0.0196376, - 0.0786361, 1.0982735 1589); 1590 1591/** 1592 * Defines supported color spaces by transfer function and primaries, 1593 * and provides conversions to/from the Linear-sRGB reference space. 1594 */ 1595const COLOR_SPACES = { 1596 [ LinearSRGBColorSpace ]: { 1597 transfer: LinearTransfer, 1598 primaries: Rec709Primaries, 1599 toReference: ( color ) => color, 1600 fromReference: ( color ) => color, 1601 }, 1602 [ SRGBColorSpace ]: { 1603 transfer: SRGBTransfer, 1604 primaries: Rec709Primaries, 1605 toReference: ( color ) => color.convertSRGBToLinear(), 1606 fromReference: ( color ) => color.convertLinearToSRGB(), 1607 }, 1608 [ LinearDisplayP3ColorSpace ]: { 1609 transfer: LinearTransfer, 1610 primaries: P3Primaries, 1611 toReference: ( color ) => color.applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ), 1612 fromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ), 1613 }, 1614 [ DisplayP3ColorSpace ]: { 1615 transfer: SRGBTransfer, 1616 primaries: P3Primaries, 1617 toReference: ( color ) => color.convertSRGBToLinear().applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ), 1618 fromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ).convertLinearToSRGB(), 1619 }, 1620}; 1621 1622const SUPPORTED_WORKING_COLOR_SPACES = new Set( [ LinearSRGBColorSpace, LinearDisplayP3ColorSpace ] ); 1623 1624const ColorManagement = { 1625 1626 enabled: true, 1627 1628 _workingColorSpace: LinearSRGBColorSpace, 1629 1630 get workingColorSpace() { 1631 1632 return this._workingColorSpace; 1633 1634 }, 1635 1636 set workingColorSpace( colorSpace ) { 1637 1638 if ( ! SUPPORTED_WORKING_COLOR_SPACES.has( colorSpace ) ) { 1639 1640 throw new Error( `Unsupported working color space, "${ colorSpace }".` ); 1641 1642 } 1643 1644 this._workingColorSpace = colorSpace; 1645 1646 }, 1647 1648 convert: function ( color, sourceColorSpace, targetColorSpace ) { 1649 1650 if ( this.enabled === false || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) { 1651 1652 return color; 1653 1654 } 1655 1656 const sourceToReference = COLOR_SPACES[ sourceColorSpace ].toReference; 1657 const targetFromReference = COLOR_SPACES[ targetColorSpace ].fromReference; 1658 1659 return targetFromReference( sourceToReference( color ) ); 1660 1661 }, 1662 1663 fromWorkingColorSpace: function ( color, targetColorSpace ) { 1664 1665 return this.convert( color, this._workingColorSpace, targetColorSpace ); 1666 1667 }, 1668 1669 toWorkingColorSpace: function ( color, sourceColorSpace ) { 1670 1671 return this.convert( color, sourceColorSpace, this._workingColorSpace ); 1672 1673 }, 1674 1675 getPrimaries: function ( colorSpace ) { 1676 1677 return COLOR_SPACES[ colorSpace ].primaries; 1678 1679 }, 1680 1681 getTransfer: function ( colorSpace ) { 1682 1683 if ( colorSpace === NoColorSpace ) return LinearTransfer; 1684 1685 return COLOR_SPACES[ colorSpace ].transfer; 1686 1687 }, 1688 1689}; 1690 1691 1692function SRGBToLinear( c ) { 1693 1694 return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 ); 1695 1696} 1697 1698function LinearToSRGB( c ) { 1699 1700 return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055; 1701 1702} 1703 1704let _canvas; 1705 1706class ImageUtils { 1707 1708 static getDataURL( image ) { 1709 1710 if ( /^data:/i.test( image.src ) ) { 1711 1712 return image.src; 1713 1714 } 1715 1716 if ( typeof HTMLCanvasElement === 'undefined' ) { 1717 1718 return image.src; 1719 1720 } 1721 1722 let canvas; 1723 1724 if ( image instanceof HTMLCanvasElement ) { 1725 1726 canvas = image; 1727 1728 } else { 1729 1730 if ( _canvas === undefined ) _canvas = createElementNS( 'canvas' ); 1731 1732 _canvas.width = image.width; 1733 _canvas.height = image.height; 1734 1735 const context = _canvas.getContext( '2d' ); 1736 1737 if ( image instanceof ImageData ) { 1738 1739 context.putImageData( image, 0, 0 ); 1740 1741 } else { 1742 1743 context.drawImage( image, 0, 0, image.width, image.height ); 1744 1745 } 1746 1747 canvas = _canvas; 1748 1749 } 1750 1751 if ( canvas.width > 2048 || canvas.height > 2048 ) { 1752 1753 console.warn( 'THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons', image ); 1754 1755 return canvas.toDataURL( 'image/jpeg', 0.6 ); 1756 1757 } else { 1758 1759 return canvas.toDataURL( 'image/png' ); 1760 1761 } 1762 1763 } 1764 1765 static sRGBToLinear( image ) { 1766 1767 if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || 1768 ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || 1769 ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { 1770 1771 const canvas = createElementNS( 'canvas' ); 1772 1773 canvas.width = image.width; 1774 canvas.height = image.height; 1775 1776 const context = canvas.getContext( '2d' ); 1777 context.drawImage( image, 0, 0, image.width, image.height ); 1778 1779 const imageData = context.getImageData( 0, 0, image.width, image.height ); 1780 const data = imageData.data; 1781 1782 for ( let i = 0; i < data.length; i ++ ) { 1783 1784 data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255; 1785 1786 } 1787 1788 context.putImageData( imageData, 0, 0 ); 1789 1790 return canvas; 1791 1792 } else if ( image.data ) { 1793 1794 const data = image.data.slice( 0 ); 1795 1796 for ( let i = 0; i < data.length; i ++ ) { 1797 1798 if ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) { 1799 1800 data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 ); 1801 1802 } else { 1803 1804 // assuming float 1805 1806 data[ i ] = SRGBToLinear( data[ i ] ); 1807 1808 } 1809 1810 } 1811 1812 return { 1813 data: data, 1814 width: image.width, 1815 height: image.height 1816 }; 1817 1818 } else { 1819 1820 console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' ); 1821 return image; 1822 1823 } 1824 1825 } 1826 1827} 1828 1829let _sourceId = 0; 1830 1831class Source { 1832 1833 constructor( data = null ) { 1834 1835 this.isSource = true; 1836 1837 Object.defineProperty( this, 'id', { value: _sourceId ++ } ); 1838 1839 this.uuid = generateUUID(); 1840 1841 this.data = data; 1842 1843 this.version = 0; 1844 1845 } 1846 1847 set needsUpdate( value ) { 1848 1849 if ( value === true ) this.version ++; 1850 1851 } 1852 1853 toJSON( meta ) { 1854 1855 const isRootObject = ( meta === undefined || typeof meta === 'string' ); 1856 1857 if ( ! isRootObject && meta.images[ this.uuid ] !== undefined ) { 1858 1859 return meta.images[ this.uuid ]; 1860 1861 } 1862 1863 const output = { 1864 uuid: this.uuid, 1865 url: '' 1866 }; 1867 1868 const data = this.data; 1869 1870 if ( data !== null ) { 1871 1872 let url; 1873 1874 if ( Array.isArray( data ) ) { 1875 1876 // cube texture 1877 1878 url = []; 1879 1880 for ( let i = 0, l = data.length; i < l; i ++ ) { 1881 1882 if ( data[ i ].isDataTexture ) { 1883 1884 url.push( serializeImage( data[ i ].image ) ); 1885 1886 } else { 1887 1888 url.push( serializeImage( data[ i ] ) ); 1889 1890 } 1891 1892 } 1893 1894 } else { 1895 1896 // texture 1897 1898 url = serializeImage( data ); 1899 1900 } 1901 1902 output.url = url; 1903 1904 } 1905 1906 if ( ! isRootObject ) { 1907 1908 meta.images[ this.uuid ] = output; 1909 1910 } 1911 1912 return output; 1913 1914 } 1915 1916} 1917 1918function serializeImage( image ) { 1919 1920 if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || 1921 ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || 1922 ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { 1923 1924 // default images 1925 1926 return ImageUtils.getDataURL( image ); 1927 1928 } else { 1929 1930 if ( image.data ) { 1931 1932 // images of DataTexture 1933 1934 return { 1935 data: Array.from( image.data ), 1936 width: image.width, 1937 height: image.height, 1938 type: image.data.constructor.name 1939 }; 1940 1941 } else { 1942 1943 console.warn( 'THREE.Texture: Unable to serialize Texture.' ); 1944 return {}; 1945 1946 } 1947 1948 } 1949 1950} 1951 1952let _textureId = 0; 1953
vendor: 9,254 bytes, lines 1954-2504
1954class Texture extends EventDispatcher { 1955 1956 constructor( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = Texture.DEFAULT_ANISOTROPY, colorSpace = NoColorSpace ) { 1957 1958 super(); 1959 1960 this.isTexture = true; 1961 1962 Object.defineProperty( this, 'id', { value: _textureId ++ } ); 1963 1964 this.uuid = generateUUID(); 1965 1966 this.name = ''; 1967 1968 this.source = new Source( image ); 1969 this.mipmaps = []; 1970 1971 this.mapping = mapping; 1972 this.channel = 0; 1973 1974 this.wrapS = wrapS; 1975 this.wrapT = wrapT; 1976 1977 this.magFilter = magFilter; 1978 this.minFilter = minFilter; 1979 1980 this.anisotropy = anisotropy; 1981 1982 this.format = format; 1983 this.internalFormat = null; 1984 this.type = type; 1985 1986 this.offset = new Vector2( 0, 0 ); 1987 this.repeat = new Vector2( 1, 1 ); 1988 this.center = new Vector2( 0, 0 ); 1989 this.rotation = 0; 1990 1991 this.matrixAutoUpdate = true; 1992 this.matrix = new Matrix3(); 1993 1994 this.generateMipmaps = true; 1995 this.premultiplyAlpha = false; 1996 this.flipY = true; 1997 this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) 1998 1999 if ( typeof colorSpace === 'string' ) { 2000 2001 this.colorSpace = colorSpace; 2002 2003 } else { // @deprecated, r152 2004 2005 warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' ); 2006 this.colorSpace = colorSpace === sRGBEncoding ? SRGBColorSpace : NoColorSpace; 2007 2008 } 2009 2010 2011 this.userData = {}; 2012 2013 this.version = 0; 2014 this.onUpdate = null; 2015 2016 this.isRenderTargetTexture = false; // indicates whether a texture belongs to a render target or not 2017 this.needsPMREMUpdate = false; // indicates whether this texture should be processed by PMREMGenerator or not (only relevant for render target textures) 2018 2019 } 2020 2021 get image() { 2022 2023 return this.source.data; 2024 2025 } 2026 2027 set image( value = null ) { 2028 2029 this.source.data = value; 2030 2031 } 2032 2033 updateMatrix() { 2034 2035 this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y ); 2036 2037 } 2038 2039 clone() { 2040 2041 return new this.constructor().copy( this ); 2042 2043 } 2044 2045 copy( source ) { 2046 2047 this.name = source.name; 2048 2049 this.source = source.source; 2050 this.mipmaps = source.mipmaps.slice( 0 ); 2051 2052 this.mapping = source.mapping; 2053 this.channel = source.channel; 2054 2055 this.wrapS = source.wrapS; 2056 this.wrapT = source.wrapT; 2057 2058 this.magFilter = source.magFilter; 2059 this.minFilter = source.minFilter; 2060 2061 this.anisotropy = source.anisotropy; 2062 2063 this.format = source.format; 2064 this.internalFormat = source.internalFormat; 2065 this.type = source.type; 2066 2067 this.offset.copy( source.offset ); 2068 this.repeat.copy( source.repeat ); 2069 this.center.copy( source.center ); 2070 this.rotation = source.rotation; 2071 2072 this.matrixAutoUpdate = source.matrixAutoUpdate; 2073 this.matrix.copy( source.matrix ); 2074 2075 this.generateMipmaps = source.generateMipmaps; 2076 this.premultiplyAlpha = source.premultiplyAlpha; 2077 this.flipY = source.flipY; 2078 this.unpackAlignment = source.unpackAlignment; 2079 this.colorSpace = source.colorSpace; 2080 2081 this.userData = JSON.parse( JSON.stringify( source.userData ) ); 2082 2083 this.needsUpdate = true; 2084 2085 return this; 2086 2087 } 2088 2089 toJSON( meta ) { 2090 2091 const isRootObject = ( meta === undefined || typeof meta === 'string' ); 2092 2093 if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) { 2094 2095 return meta.textures[ this.uuid ]; 2096 2097 } 2098 2099 const output = { 2100 2101 metadata: { 2102 version: 4.6, 2103 type: 'Texture', 2104 generator: 'Texture.toJSON' 2105 }, 2106 2107 uuid: this.uuid, 2108 name: this.name, 2109 2110 image: this.source.toJSON( meta ).uuid, 2111 2112 mapping: this.mapping, 2113 channel: this.channel, 2114 2115 repeat: [ this.repeat.x, this.repeat.y ], 2116 offset: [ this.offset.x, this.offset.y ], 2117 center: [ this.center.x, this.center.y ], 2118 rotation: this.rotation, 2119 2120 wrap: [ this.wrapS, this.wrapT ], 2121 2122 format: this.format, 2123 internalFormat: this.internalFormat, 2124 type: this.type, 2125 colorSpace: this.colorSpace, 2126 2127 minFilter: this.minFilter, 2128 magFilter: this.magFilter, 2129 anisotropy: this.anisotropy, 2130 2131 flipY: this.flipY, 2132 2133 generateMipmaps: this.generateMipmaps, 2134 premultiplyAlpha: this.premultiplyAlpha, 2135 unpackAlignment: this.unpackAlignment 2136 2137 }; 2138 2139 if ( Object.keys( this.userData ).length > 0 ) output.userData = this.userData; 2140 2141 if ( ! isRootObject ) { 2142 2143 meta.textures[ this.uuid ] = output; 2144 2145 } 2146 2147 return output; 2148 2149 } 2150 2151 dispose() { 2152 2153 this.dispatchEvent( { type: 'dispose' } ); 2154 2155 } 2156 2157 transformUv( uv ) { 2158 2159 if ( this.mapping !== UVMapping ) return uv; 2160 2161 uv.applyMatrix3( this.matrix ); 2162 2163 if ( uv.x < 0 || uv.x > 1 ) { 2164 2165 switch ( this.wrapS ) { 2166 2167 case RepeatWrapping: 2168 2169 uv.x = uv.x - Math.floor( uv.x ); 2170 break; 2171 2172 case ClampToEdgeWrapping: 2173 2174 uv.x = uv.x < 0 ? 0 : 1; 2175 break; 2176 2177 case MirroredRepeatWrapping: 2178 2179 if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { 2180 2181 uv.x = Math.ceil( uv.x ) - uv.x; 2182 2183 } else { 2184 2185 uv.x = uv.x - Math.floor( uv.x ); 2186 2187 } 2188 2189 break; 2190 2191 } 2192 2193 } 2194 2195 if ( uv.y < 0 || uv.y > 1 ) { 2196 2197 switch ( this.wrapT ) { 2198 2199 case RepeatWrapping: 2200 2201 uv.y = uv.y - Math.floor( uv.y ); 2202 break; 2203 2204 case ClampToEdgeWrapping: 2205 2206 uv.y = uv.y < 0 ? 0 : 1; 2207 break; 2208 2209 case MirroredRepeatWrapping: 2210 2211 if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { 2212 2213 uv.y = Math.ceil( uv.y ) - uv.y; 2214 2215 } else { 2216 2217 uv.y = uv.y - Math.floor( uv.y ); 2218 2219 } 2220 2221 break; 2222 2223 } 2224 2225 } 2226 2227 if ( this.flipY ) { 2228 2229 uv.y = 1 - uv.y; 2230 2231 } 2232 2233 return uv; 2234 2235 } 2236 2237 set needsUpdate( value ) { 2238 2239 if ( value === true ) { 2240 2241 this.version ++; 2242 this.source.needsUpdate = true; 2243 2244 } 2245 2246 } 2247 2248 get encoding() { // @deprecated, r152 2249 2250 warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' ); 2251 return this.colorSpace === SRGBColorSpace ? sRGBEncoding : LinearEncoding; 2252 2253 } 2254 2255 set encoding( encoding ) { // @deprecated, r152 2256 2257 warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' ); 2258 this.colorSpace = encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace; 2259 2260 } 2261 2262} 2263 2264Texture.DEFAULT_IMAGE = null; 2265Texture.DEFAULT_MAPPING = UVMapping; 2266Texture.DEFAULT_ANISOTROPY = 1; 2267 2268class Vector4 { 2269 2270 constructor( x = 0, y = 0, z = 0, w = 1 ) { 2271 2272 Vector4.prototype.isVector4 = true; 2273 2274 this.x = x; 2275 this.y = y; 2276 this.z = z; 2277 this.w = w; 2278 2279 } 2280 2281 get width() { 2282 2283 return this.z; 2284 2285 } 2286 2287 set width( value ) { 2288 2289 this.z = value; 2290 2291 } 2292 2293 get height() { 2294 2295 return this.w; 2296 2297 } 2298 2299 set height( value ) { 2300 2301 this.w = value; 2302 2303 } 2304 2305 set( x, y, z, w ) { 2306 2307 this.x = x; 2308 this.y = y; 2309 this.z = z; 2310 this.w = w; 2311 2312 return this; 2313 2314 } 2315 2316 setScalar( scalar ) { 2317 2318 this.x = scalar; 2319 this.y = scalar; 2320 this.z = scalar; 2321 this.w = scalar; 2322 2323 return this; 2324 2325 } 2326 2327 setX( x ) { 2328 2329 this.x = x; 2330 2331 return this; 2332 2333 } 2334 2335 setY( y ) { 2336 2337 this.y = y; 2338 2339 return this; 2340 2341 } 2342 2343 setZ( z ) { 2344 2345 this.z = z; 2346 2347 return this; 2348 2349 } 2350 2351 setW( w ) { 2352 2353 this.w = w; 2354 2355 return this; 2356 2357 } 2358 2359 setComponent( index, value ) { 2360 2361 switch ( index ) { 2362 2363 case 0: this.x = value; break; 2364 case 1: this.y = value; break; 2365 case 2: this.z = value; break; 2366 case 3: this.w = value; break; 2367 default: throw new Error( 'index is out of range: ' + index ); 2368 2369 } 2370 2371 return this; 2372 2373 } 2374 2375 getComponent( index ) { 2376 2377 switch ( index ) { 2378 2379 case 0: return this.x; 2380 case 1: return this.y; 2381 case 2: return this.z; 2382 case 3: return this.w; 2383 default: throw new Error( 'index is out of range: ' + index ); 2384 2385 } 2386 2387 } 2388 2389 clone() { 2390 2391 return new this.constructor( this.x, this.y, this.z, this.w ); 2392 2393 } 2394 2395 copy( v ) { 2396 2397 this.x = v.x; 2398 this.y = v.y; 2399 this.z = v.z; 2400 this.w = ( v.w !== undefined ) ? v.w : 1; 2401 2402 return this; 2403 2404 } 2405 2406 add( v ) { 2407 2408 this.x += v.x; 2409 this.y += v.y; 2410 this.z += v.z; 2411 this.w += v.w; 2412 2413 return this; 2414 2415 } 2416 2417 addScalar( s ) { 2418 2419 this.x += s; 2420 this.y += s; 2421 this.z += s; 2422 this.w += s; 2423 2424 return this; 2425 2426 } 2427 2428 addVectors( a, b ) { 2429 2430 this.x = a.x + b.x; 2431 this.y = a.y + b.y; 2432 this.z = a.z + b.z; 2433 this.w = a.w + b.w; 2434 2435 return this; 2436 2437 } 2438 2439 addScaledVector( v, s ) { 2440 2441 this.x += v.x * s; 2442 this.y += v.y * s; 2443 this.z += v.z * s; 2444 this.w += v.w * s; 2445 2446 return this; 2447 2448 } 2449 2450 sub( v ) { 2451 2452 this.x -= v.x; 2453 this.y -= v.y; 2454 this.z -= v.z; 2455 this.w -= v.w; 2456 2457 return this; 2458 2459 } 2460 2461 subScalar( s ) { 2462 2463 this.x -= s; 2464 this.y -= s; 2465 this.z -= s; 2466 this.w -= s; 2467 2468 return this; 2469 2470 } 2471 2472 subVectors( a, b ) { 2473 2474 this.x = a.x - b.x; 2475 this.y = a.y - b.y; 2476 this.z = a.z - b.z; 2477 this.w = a.w - b.w; 2478 2479 return this; 2480 2481 } 2482 2483 multiply( v ) { 2484 2485 this.x *= v.x; 2486 this.y *= v.y; 2487 this.z *= v.z; 2488 this.w *= v.w; 2489 2490 return this; 2491 2492 } 2493 2494 multiplyScalar( scalar ) { 2495 2496 this.x *= scalar; 2497 this.y *= scalar; 2498 this.z *= scalar; 2499 this.w *= scalar; 2500 2501 return this; 2502 2503 } 2504
vendor: 37,104 bytes, lines 2505-4475
2505 applyMatrix4( m ) { 2506 2507 const x = this.x, y = this.y, z = this.z, w = this.w; 2508 const e = m.elements; 2509 2510 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w; 2511 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w; 2512 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w; 2513 this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w; 2514 2515 return this; 2516 2517 } 2518 2519 divideScalar( scalar ) { 2520 2521 return this.multiplyScalar( 1 / scalar ); 2522 2523 } 2524 2525 setAxisAngleFromQuaternion( q ) { 2526 2527 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm 2528 2529 // q is assumed to be normalized 2530 2531 this.w = 2 * Math.acos( q.w ); 2532 2533 const s = Math.sqrt( 1 - q.w * q.w ); 2534 2535 if ( s < 0.0001 ) { 2536 2537 this.x = 1; 2538 this.y = 0; 2539 this.z = 0; 2540 2541 } else { 2542 2543 this.x = q.x / s; 2544 this.y = q.y / s; 2545 this.z = q.z / s; 2546 2547 } 2548 2549 return this; 2550 2551 } 2552 2553 setAxisAngleFromRotationMatrix( m ) { 2554 2555 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm 2556 2557 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 2558 2559 let angle, x, y, z; // variables for result 2560 const epsilon = 0.01, // margin to allow for rounding errors 2561 epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees 2562 2563 te = m.elements, 2564 2565 m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], 2566 m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], 2567 m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; 2568 2569 if ( ( Math.abs( m12 - m21 ) < epsilon ) && 2570 ( Math.abs( m13 - m31 ) < epsilon ) && 2571 ( Math.abs( m23 - m32 ) < epsilon ) ) { 2572 2573 // singularity found 2574 // first check for identity matrix which must have +1 for all terms 2575 // in leading diagonal and zero in other terms 2576 2577 if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && 2578 ( Math.abs( m13 + m31 ) < epsilon2 ) && 2579 ( Math.abs( m23 + m32 ) < epsilon2 ) && 2580 ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { 2581 2582 // this singularity is identity matrix so angle = 0 2583 2584 this.set( 1, 0, 0, 0 ); 2585 2586 return this; // zero angle, arbitrary axis 2587 2588 } 2589 2590 // otherwise this singularity is angle = 180 2591 2592 angle = Math.PI; 2593 2594 const xx = ( m11 + 1 ) / 2; 2595 const yy = ( m22 + 1 ) / 2; 2596 const zz = ( m33 + 1 ) / 2; 2597 const xy = ( m12 + m21 ) / 4; 2598 const xz = ( m13 + m31 ) / 4; 2599 const yz = ( m23 + m32 ) / 4; 2600 2601 if ( ( xx > yy ) && ( xx > zz ) ) { 2602 2603 // m11 is the largest diagonal term 2604 2605 if ( xx < epsilon ) { 2606 2607 x = 0; 2608 y = 0.707106781; 2609 z = 0.707106781; 2610 2611 } else { 2612 2613 x = Math.sqrt( xx ); 2614 y = xy / x; 2615 z = xz / x; 2616 2617 } 2618 2619 } else if ( yy > zz ) { 2620 2621 // m22 is the largest diagonal term 2622 2623 if ( yy < epsilon ) { 2624 2625 x = 0.707106781; 2626 y = 0; 2627 z = 0.707106781; 2628 2629 } else { 2630 2631 y = Math.sqrt( yy ); 2632 x = xy / y; 2633 z = yz / y; 2634 2635 } 2636 2637 } else { 2638 2639 // m33 is the largest diagonal term so base result on this 2640 2641 if ( zz < epsilon ) { 2642 2643 x = 0.707106781; 2644 y = 0.707106781; 2645 z = 0; 2646 2647 } else { 2648 2649 z = Math.sqrt( zz ); 2650 x = xz / z; 2651 y = yz / z; 2652 2653 } 2654 2655 } 2656 2657 this.set( x, y, z, angle ); 2658 2659 return this; // return 180 deg rotation 2660 2661 } 2662 2663 // as we have reached here there are no singularities so we can handle normally 2664 2665 let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + 2666 ( m13 - m31 ) * ( m13 - m31 ) + 2667 ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize 2668 2669 if ( Math.abs( s ) < 0.001 ) s = 1; 2670 2671 // prevent divide by zero, should not happen if matrix is orthogonal and should be 2672 // caught by singularity test above, but I've left it in just in case 2673 2674 this.x = ( m32 - m23 ) / s; 2675 this.y = ( m13 - m31 ) / s; 2676 this.z = ( m21 - m12 ) / s; 2677 this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); 2678 2679 return this; 2680 2681 } 2682 2683 min( v ) { 2684 2685 this.x = Math.min( this.x, v.x ); 2686 this.y = Math.min( this.y, v.y ); 2687 this.z = Math.min( this.z, v.z ); 2688 this.w = Math.min( this.w, v.w ); 2689 2690 return this; 2691 2692 } 2693 2694 max( v ) { 2695 2696 this.x = Math.max( this.x, v.x ); 2697 this.y = Math.max( this.y, v.y ); 2698 this.z = Math.max( this.z, v.z ); 2699 this.w = Math.max( this.w, v.w ); 2700 2701 return this; 2702 2703 } 2704 2705 clamp( min, max ) { 2706 2707 // assumes min < max, componentwise 2708 2709 this.x = Math.max( min.x, Math.min( max.x, this.x ) ); 2710 this.y = Math.max( min.y, Math.min( max.y, this.y ) ); 2711 this.z = Math.max( min.z, Math.min( max.z, this.z ) ); 2712 this.w = Math.max( min.w, Math.min( max.w, this.w ) ); 2713 2714 return this; 2715 2716 } 2717 2718 clampScalar( minVal, maxVal ) { 2719 2720 this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); 2721 this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); 2722 this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); 2723 this.w = Math.max( minVal, Math.min( maxVal, this.w ) ); 2724 2725 return this; 2726 2727 } 2728 2729 clampLength( min, max ) { 2730 2731 const length = this.length(); 2732 2733 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); 2734 2735 } 2736 2737 floor() { 2738 2739 this.x = Math.floor( this.x ); 2740 this.y = Math.floor( this.y ); 2741 this.z = Math.floor( this.z ); 2742 this.w = Math.floor( this.w ); 2743 2744 return this; 2745 2746 } 2747 2748 ceil() { 2749 2750 this.x = Math.ceil( this.x ); 2751 this.y = Math.ceil( this.y ); 2752 this.z = Math.ceil( this.z ); 2753 this.w = Math.ceil( this.w ); 2754 2755 return this; 2756 2757 } 2758 2759 round() { 2760 2761 this.x = Math.round( this.x ); 2762 this.y = Math.round( this.y ); 2763 this.z = Math.round( this.z ); 2764 this.w = Math.round( this.w ); 2765 2766 return this; 2767 2768 } 2769 2770 roundToZero() { 2771 2772 this.x = Math.trunc( this.x ); 2773 this.y = Math.trunc( this.y ); 2774 this.z = Math.trunc( this.z ); 2775 this.w = Math.trunc( this.w ); 2776 2777 return this; 2778 2779 } 2780 2781 negate() { 2782 2783 this.x = - this.x; 2784 this.y = - this.y; 2785 this.z = - this.z; 2786 this.w = - this.w; 2787 2788 return this; 2789 2790 } 2791 2792 dot( v ) { 2793 2794 return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; 2795 2796 } 2797 2798 lengthSq() { 2799 2800 return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; 2801 2802 } 2803 2804 length() { 2805 2806 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); 2807 2808 } 2809 2810 manhattanLength() { 2811 2812 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); 2813 2814 } 2815 2816 normalize() { 2817 2818 return this.divideScalar( this.length() || 1 ); 2819 2820 } 2821 2822 setLength( length ) { 2823 2824 return this.normalize().multiplyScalar( length ); 2825 2826 } 2827 2828 lerp( v, alpha ) { 2829 2830 this.x += ( v.x - this.x ) * alpha; 2831 this.y += ( v.y - this.y ) * alpha; 2832 this.z += ( v.z - this.z ) * alpha; 2833 this.w += ( v.w - this.w ) * alpha; 2834 2835 return this; 2836 2837 } 2838 2839 lerpVectors( v1, v2, alpha ) { 2840 2841 this.x = v1.x + ( v2.x - v1.x ) * alpha; 2842 this.y = v1.y + ( v2.y - v1.y ) * alpha; 2843 this.z = v1.z + ( v2.z - v1.z ) * alpha; 2844 this.w = v1.w + ( v2.w - v1.w ) * alpha; 2845 2846 return this; 2847 2848 } 2849 2850 equals( v ) { 2851 2852 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); 2853 2854 } 2855 2856 fromArray( array, offset = 0 ) { 2857 2858 this.x = array[ offset ]; 2859 this.y = array[ offset + 1 ]; 2860 this.z = array[ offset + 2 ]; 2861 this.w = array[ offset + 3 ]; 2862 2863 return this; 2864 2865 } 2866 2867 toArray( array = [], offset = 0 ) { 2868 2869 array[ offset ] = this.x; 2870 array[ offset + 1 ] = this.y; 2871 array[ offset + 2 ] = this.z; 2872 array[ offset + 3 ] = this.w; 2873 2874 return array; 2875 2876 } 2877 2878 fromBufferAttribute( attribute, index ) { 2879 2880 this.x = attribute.getX( index ); 2881 this.y = attribute.getY( index ); 2882 this.z = attribute.getZ( index ); 2883 this.w = attribute.getW( index ); 2884 2885 return this; 2886 2887 } 2888 2889 random() { 2890 2891 this.x = Math.random(); 2892 this.y = Math.random(); 2893 this.z = Math.random(); 2894 this.w = Math.random(); 2895 2896 return this; 2897 2898 } 2899 2900 *[ Symbol.iterator ]() { 2901 2902 yield this.x; 2903 yield this.y; 2904 yield this.z; 2905 yield this.w; 2906 2907 } 2908 2909} 2910 2911/* 2912 In options, we can specify: 2913 * Texture parameters for an auto-generated target texture 2914 * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers 2915*/ 2916class RenderTarget extends EventDispatcher { 2917 2918 constructor( width = 1, height = 1, options = {} ) { 2919 2920 super(); 2921 2922 this.isRenderTarget = true; 2923 2924 this.width = width; 2925 this.height = height; 2926 this.depth = 1; 2927 2928 this.scissor = new Vector4( 0, 0, width, height ); 2929 this.scissorTest = false; 2930 2931 this.viewport = new Vector4( 0, 0, width, height ); 2932 2933 const image = { width: width, height: height, depth: 1 }; 2934 2935 if ( options.encoding !== undefined ) { 2936 2937 // @deprecated, r152 2938 warnOnce( 'THREE.WebGLRenderTarget: option.encoding has been replaced by option.colorSpace.' ); 2939 options.colorSpace = options.encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace; 2940 2941 } 2942 2943 options = Object.assign( { 2944 generateMipmaps: false, 2945 internalFormat: null, 2946 minFilter: LinearFilter, 2947 depthBuffer: true, 2948 stencilBuffer: false, 2949 depthTexture: null, 2950 samples: 0 2951 }, options ); 2952 2953 this.texture = new Texture( image, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace ); 2954 this.texture.isRenderTargetTexture = true; 2955 2956 this.texture.flipY = false; 2957 this.texture.generateMipmaps = options.generateMipmaps; 2958 this.texture.internalFormat = options.internalFormat; 2959 2960 this.depthBuffer = options.depthBuffer; 2961 this.stencilBuffer = options.stencilBuffer; 2962 2963 this.depthTexture = options.depthTexture; 2964 2965 this.samples = options.samples; 2966 2967 } 2968 2969 setSize( width, height, depth = 1 ) { 2970 2971 if ( this.width !== width || this.height !== height || this.depth !== depth ) { 2972 2973 this.width = width; 2974 this.height = height; 2975 this.depth = depth; 2976 2977 this.texture.image.width = width; 2978 this.texture.image.height = height; 2979 this.texture.image.depth = depth; 2980 2981 this.dispose(); 2982 2983 } 2984 2985 this.viewport.set( 0, 0, width, height ); 2986 this.scissor.set( 0, 0, width, height ); 2987 2988 } 2989 2990 clone() { 2991 2992 return new this.constructor().copy( this ); 2993 2994 } 2995 2996 copy( source ) { 2997 2998 this.width = source.width; 2999 this.height = source.height; 3000 this.depth = source.depth; 3001 3002 this.scissor.copy( source.scissor ); 3003 this.scissorTest = source.scissorTest; 3004 3005 this.viewport.copy( source.viewport ); 3006 3007 this.texture = source.texture.clone(); 3008 this.texture.isRenderTargetTexture = true; 3009 3010 // ensure image object is not shared, see #20328 3011 3012 const image = Object.assign( {}, source.texture.image ); 3013 this.texture.source = new Source( image ); 3014 3015 this.depthBuffer = source.depthBuffer; 3016 this.stencilBuffer = source.stencilBuffer; 3017 3018 if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone(); 3019 3020 this.samples = source.samples; 3021 3022 return this; 3023 3024 } 3025 3026 dispose() { 3027 3028 this.dispatchEvent( { type: 'dispose' } ); 3029 3030 } 3031 3032} 3033 3034class WebGLRenderTarget extends RenderTarget { 3035 3036 constructor( width = 1, height = 1, options = {} ) { 3037 3038 super( width, height, options ); 3039 3040 this.isWebGLRenderTarget = true; 3041 3042 } 3043 3044} 3045 3046class DataArrayTexture extends Texture { 3047 3048 constructor( data = null, width = 1, height = 1, depth = 1 ) { 3049 3050 super( null ); 3051 3052 this.isDataArrayTexture = true; 3053 3054 this.image = { data, width, height, depth }; 3055 3056 this.magFilter = NearestFilter; 3057 this.minFilter = NearestFilter; 3058 3059 this.wrapR = ClampToEdgeWrapping; 3060 3061 this.generateMipmaps = false; 3062 this.flipY = false; 3063 this.unpackAlignment = 1; 3064 3065 } 3066 3067} 3068 3069class WebGLArrayRenderTarget extends WebGLRenderTarget { 3070 3071 constructor( width = 1, height = 1, depth = 1, options = {} ) { 3072 3073 super( width, height, options ); 3074 3075 this.isWebGLArrayRenderTarget = true; 3076 3077 this.depth = depth; 3078 3079 this.texture = new DataArrayTexture( null, width, height, depth ); 3080 3081 this.texture.isRenderTargetTexture = true; 3082 3083 } 3084 3085} 3086 3087class Data3DTexture extends Texture { 3088 3089 constructor( data = null, width = 1, height = 1, depth = 1 ) { 3090 3091 // We're going to add .setXXX() methods for setting properties later. 3092 // Users can still set in DataTexture3D directly. 3093 // 3094 // const texture = new THREE.DataTexture3D( data, width, height, depth ); 3095 // texture.anisotropy = 16; 3096 // 3097 // See #14839 3098 3099 super( null ); 3100 3101 this.isData3DTexture = true; 3102 3103 this.image = { data, width, height, depth }; 3104 3105 this.magFilter = NearestFilter; 3106 this.minFilter = NearestFilter; 3107 3108 this.wrapR = ClampToEdgeWrapping; 3109 3110 this.generateMipmaps = false; 3111 this.flipY = false; 3112 this.unpackAlignment = 1; 3113 3114 } 3115 3116} 3117 3118class WebGL3DRenderTarget extends WebGLRenderTarget { 3119 3120 constructor( width = 1, height = 1, depth = 1, options = {} ) { 3121 3122 super( width, height, options ); 3123 3124 this.isWebGL3DRenderTarget = true; 3125 3126 this.depth = depth; 3127 3128 this.texture = new Data3DTexture( null, width, height, depth ); 3129 3130 this.texture.isRenderTargetTexture = true; 3131 3132 } 3133 3134} 3135 3136class WebGLMultipleRenderTargets extends WebGLRenderTarget { 3137 3138 constructor( width = 1, height = 1, count = 1, options = {} ) { 3139 3140 super( width, height, options ); 3141 3142 this.isWebGLMultipleRenderTargets = true; 3143 3144 const texture = this.texture; 3145 3146 this.texture = []; 3147 3148 for ( let i = 0; i < count; i ++ ) { 3149 3150 this.texture[ i ] = texture.clone(); 3151 this.texture[ i ].isRenderTargetTexture = true; 3152 3153 } 3154 3155 } 3156 3157 setSize( width, height, depth = 1 ) { 3158 3159 if ( this.width !== width || this.height !== height || this.depth !== depth ) { 3160 3161 this.width = width; 3162 this.height = height; 3163 this.depth = depth; 3164 3165 for ( let i = 0, il = this.texture.length; i < il; i ++ ) { 3166 3167 this.texture[ i ].image.width = width; 3168 this.texture[ i ].image.height = height; 3169 this.texture[ i ].image.depth = depth; 3170 3171 } 3172 3173 this.dispose(); 3174 3175 } 3176 3177 this.viewport.set( 0, 0, width, height ); 3178 this.scissor.set( 0, 0, width, height ); 3179 3180 } 3181 3182 copy( source ) { 3183 3184 this.dispose(); 3185 3186 this.width = source.width; 3187 this.height = source.height; 3188 this.depth = source.depth; 3189 3190 this.scissor.copy( source.scissor ); 3191 this.scissorTest = source.scissorTest; 3192 3193 this.viewport.copy( source.viewport ); 3194 3195 this.depthBuffer = source.depthBuffer; 3196 this.stencilBuffer = source.stencilBuffer; 3197 3198 if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone(); 3199 3200 this.texture.length = 0; 3201 3202 for ( let i = 0, il = source.texture.length; i < il; i ++ ) { 3203 3204 this.texture[ i ] = source.texture[ i ].clone(); 3205 this.texture[ i ].isRenderTargetTexture = true; 3206 3207 } 3208 3209 return this; 3210 3211 } 3212 3213} 3214 3215class Quaternion { 3216 3217 constructor( x = 0, y = 0, z = 0, w = 1 ) { 3218 3219 this.isQuaternion = true; 3220 3221 this._x = x; 3222 this._y = y; 3223 this._z = z; 3224 this._w = w; 3225 3226 } 3227 3228 static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { 3229 3230 // fuzz-free, array-based Quaternion SLERP operation 3231 3232 let x0 = src0[ srcOffset0 + 0 ], 3233 y0 = src0[ srcOffset0 + 1 ], 3234 z0 = src0[ srcOffset0 + 2 ], 3235 w0 = src0[ srcOffset0 + 3 ]; 3236 3237 const x1 = src1[ srcOffset1 + 0 ], 3238 y1 = src1[ srcOffset1 + 1 ], 3239 z1 = src1[ srcOffset1 + 2 ], 3240 w1 = src1[ srcOffset1 + 3 ]; 3241 3242 if ( t === 0 ) { 3243 3244 dst[ dstOffset + 0 ] = x0; 3245 dst[ dstOffset + 1 ] = y0; 3246 dst[ dstOffset + 2 ] = z0; 3247 dst[ dstOffset + 3 ] = w0; 3248 return; 3249 3250 } 3251 3252 if ( t === 1 ) { 3253 3254 dst[ dstOffset + 0 ] = x1; 3255 dst[ dstOffset + 1 ] = y1; 3256 dst[ dstOffset + 2 ] = z1; 3257 dst[ dstOffset + 3 ] = w1; 3258 return; 3259 3260 } 3261 3262 if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { 3263 3264 let s = 1 - t; 3265 const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, 3266 dir = ( cos >= 0 ? 1 : - 1 ), 3267 sqrSin = 1 - cos * cos; 3268 3269 // Skip the Slerp for tiny steps to avoid numeric problems: 3270 if ( sqrSin > Number.EPSILON ) { 3271 3272 const sin = Math.sqrt( sqrSin ), 3273 len = Math.atan2( sin, cos * dir ); 3274 3275 s = Math.sin( s * len ) / sin; 3276 t = Math.sin( t * len ) / sin; 3277 3278 } 3279 3280 const tDir = t * dir; 3281 3282 x0 = x0 * s + x1 * tDir; 3283 y0 = y0 * s + y1 * tDir; 3284 z0 = z0 * s + z1 * tDir; 3285 w0 = w0 * s + w1 * tDir; 3286 3287 // Normalize in case we just did a lerp: 3288 if ( s === 1 - t ) { 3289 3290 const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); 3291 3292 x0 *= f; 3293 y0 *= f; 3294 z0 *= f; 3295 w0 *= f; 3296 3297 } 3298 3299 } 3300 3301 dst[ dstOffset ] = x0; 3302 dst[ dstOffset + 1 ] = y0; 3303 dst[ dstOffset + 2 ] = z0; 3304 dst[ dstOffset + 3 ] = w0; 3305 3306 } 3307 3308 static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) { 3309 3310 const x0 = src0[ srcOffset0 ]; 3311 const y0 = src0[ srcOffset0 + 1 ]; 3312 const z0 = src0[ srcOffset0 + 2 ]; 3313 const w0 = src0[ srcOffset0 + 3 ]; 3314 3315 const x1 = src1[ srcOffset1 ]; 3316 const y1 = src1[ srcOffset1 + 1 ]; 3317 const z1 = src1[ srcOffset1 + 2 ]; 3318 const w1 = src1[ srcOffset1 + 3 ]; 3319 3320 dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1; 3321 dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1; 3322 dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1; 3323 dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1; 3324 3325 return dst; 3326 3327 } 3328 3329 get x() { 3330 3331 return this._x; 3332 3333 } 3334 3335 set x( value ) { 3336 3337 this._x = value; 3338 this._onChangeCallback(); 3339 3340 } 3341 3342 get y() { 3343 3344 return this._y; 3345 3346 } 3347 3348 set y( value ) { 3349 3350 this._y = value; 3351 this._onChangeCallback(); 3352 3353 } 3354 3355 get z() { 3356 3357 return this._z; 3358 3359 } 3360 3361 set z( value ) { 3362 3363 this._z = value; 3364 this._onChangeCallback(); 3365 3366 } 3367 3368 get w() { 3369 3370 return this._w; 3371 3372 } 3373 3374 set w( value ) { 3375 3376 this._w = value; 3377 this._onChangeCallback(); 3378 3379 } 3380 3381 set( x, y, z, w ) { 3382 3383 this._x = x; 3384 this._y = y; 3385 this._z = z; 3386 this._w = w; 3387 3388 this._onChangeCallback(); 3389 3390 return this; 3391 3392 } 3393 3394 clone() { 3395 3396 return new this.constructor( this._x, this._y, this._z, this._w ); 3397 3398 } 3399 3400 copy( quaternion ) { 3401 3402 this._x = quaternion.x; 3403 this._y = quaternion.y; 3404 this._z = quaternion.z; 3405 this._w = quaternion.w; 3406 3407 this._onChangeCallback(); 3408 3409 return this; 3410 3411 } 3412 3413 setFromEuler( euler, update = true ) { 3414 3415 const x = euler._x, y = euler._y, z = euler._z, order = euler._order; 3416 3417 // http://www.mathworks.com/matlabcentral/fileexchange/ 3418 // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ 3419 // content/SpinCalc.m 3420 3421 const cos = Math.cos; 3422 const sin = Math.sin; 3423 3424 const c1 = cos( x / 2 ); 3425 const c2 = cos( y / 2 ); 3426 const c3 = cos( z / 2 ); 3427 3428 const s1 = sin( x / 2 ); 3429 const s2 = sin( y / 2 ); 3430 const s3 = sin( z / 2 ); 3431 3432 switch ( order ) { 3433 3434 case 'XYZ': 3435 this._x = s1 * c2 * c3 + c1 * s2 * s3; 3436 this._y = c1 * s2 * c3 - s1 * c2 * s3; 3437 this._z = c1 * c2 * s3 + s1 * s2 * c3; 3438 this._w = c1 * c2 * c3 - s1 * s2 * s3; 3439 break; 3440 3441 case 'YXZ': 3442 this._x = s1 * c2 * c3 + c1 * s2 * s3; 3443 this._y = c1 * s2 * c3 - s1 * c2 * s3; 3444 this._z = c1 * c2 * s3 - s1 * s2 * c3; 3445 this._w = c1 * c2 * c3 + s1 * s2 * s3; 3446 break; 3447 3448 case 'ZXY': 3449 this._x = s1 * c2 * c3 - c1 * s2 * s3; 3450 this._y = c1 * s2 * c3 + s1 * c2 * s3; 3451 this._z = c1 * c2 * s3 + s1 * s2 * c3; 3452 this._w = c1 * c2 * c3 - s1 * s2 * s3; 3453 break; 3454 3455 case 'ZYX': 3456 this._x = s1 * c2 * c3 - c1 * s2 * s3; 3457 this._y = c1 * s2 * c3 + s1 * c2 * s3; 3458 this._z = c1 * c2 * s3 - s1 * s2 * c3; 3459 this._w = c1 * c2 * c3 + s1 * s2 * s3; 3460 break; 3461 3462 case 'YZX': 3463 this._x = s1 * c2 * c3 + c1 * s2 * s3; 3464 this._y = c1 * s2 * c3 + s1 * c2 * s3; 3465 this._z = c1 * c2 * s3 - s1 * s2 * c3; 3466 this._w = c1 * c2 * c3 - s1 * s2 * s3; 3467 break; 3468 3469 case 'XZY': 3470 this._x = s1 * c2 * c3 - c1 * s2 * s3; 3471 this._y = c1 * s2 * c3 - s1 * c2 * s3; 3472 this._z = c1 * c2 * s3 + s1 * s2 * c3; 3473 this._w = c1 * c2 * c3 + s1 * s2 * s3; 3474 break; 3475 3476 default: 3477 console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order ); 3478 3479 } 3480 3481 if ( update === true ) this._onChangeCallback(); 3482 3483 return this; 3484 3485 } 3486 3487 setFromAxisAngle( axis, angle ) { 3488 3489 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm 3490 3491 // assumes axis is normalized 3492 3493 const halfAngle = angle / 2, s = Math.sin( halfAngle ); 3494 3495 this._x = axis.x * s; 3496 this._y = axis.y * s; 3497 this._z = axis.z * s; 3498 this._w = Math.cos( halfAngle ); 3499 3500 this._onChangeCallback(); 3501 3502 return this; 3503 3504 } 3505 3506 setFromRotationMatrix( m ) { 3507 3508 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm 3509 3510 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 3511 3512 const te = m.elements, 3513 3514 m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], 3515 m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], 3516 m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], 3517 3518 trace = m11 + m22 + m33; 3519 3520 if ( trace > 0 ) { 3521 3522 const s = 0.5 / Math.sqrt( trace + 1.0 ); 3523 3524 this._w = 0.25 / s; 3525 this._x = ( m32 - m23 ) * s; 3526 this._y = ( m13 - m31 ) * s; 3527 this._z = ( m21 - m12 ) * s; 3528 3529 } else if ( m11 > m22 && m11 > m33 ) { 3530 3531 const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); 3532 3533 this._w = ( m32 - m23 ) / s; 3534 this._x = 0.25 * s; 3535 this._y = ( m12 + m21 ) / s; 3536 this._z = ( m13 + m31 ) / s; 3537 3538 } else if ( m22 > m33 ) { 3539 3540 const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); 3541 3542 this._w = ( m13 - m31 ) / s; 3543 this._x = ( m12 + m21 ) / s; 3544 this._y = 0.25 * s; 3545 this._z = ( m23 + m32 ) / s; 3546 3547 } else { 3548 3549 const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); 3550 3551 this._w = ( m21 - m12 ) / s; 3552 this._x = ( m13 + m31 ) / s; 3553 this._y = ( m23 + m32 ) / s; 3554 this._z = 0.25 * s; 3555 3556 } 3557 3558 this._onChangeCallback(); 3559 3560 return this; 3561 3562 } 3563 3564 setFromUnitVectors( vFrom, vTo ) { 3565 3566 // assumes direction vectors vFrom and vTo are normalized 3567 3568 let r = vFrom.dot( vTo ) + 1; 3569 3570 if ( r < Number.EPSILON ) { 3571 3572 // vFrom and vTo point in opposite directions 3573 3574 r = 0; 3575 3576 if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { 3577 3578 this._x = - vFrom.y; 3579 this._y = vFrom.x; 3580 this._z = 0; 3581 this._w = r; 3582 3583 } else { 3584 3585 this._x = 0; 3586 this._y = - vFrom.z; 3587 this._z = vFrom.y; 3588 this._w = r; 3589 3590 } 3591 3592 } else { 3593 3594 // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3 3595 3596 this._x = vFrom.y * vTo.z - vFrom.z * vTo.y; 3597 this._y = vFrom.z * vTo.x - vFrom.x * vTo.z; 3598 this._z = vFrom.x * vTo.y - vFrom.y * vTo.x; 3599 this._w = r; 3600 3601 } 3602 3603 return this.normalize(); 3604 3605 } 3606 3607 angleTo( q ) { 3608 3609 return 2 * Math.acos( Math.abs( clamp( this.dot( q ), - 1, 1 ) ) ); 3610 3611 } 3612 3613 rotateTowards( q, step ) { 3614 3615 const angle = this.angleTo( q ); 3616 3617 if ( angle === 0 ) return this; 3618 3619 const t = Math.min( 1, step / angle ); 3620 3621 this.slerp( q, t ); 3622 3623 return this; 3624 3625 } 3626 3627 identity() { 3628 3629 return this.set( 0, 0, 0, 1 ); 3630 3631 } 3632 3633 invert() { 3634 3635 // quaternion is assumed to have unit length 3636 3637 return this.conjugate(); 3638 3639 } 3640 3641 conjugate() { 3642 3643 this._x *= - 1; 3644 this._y *= - 1; 3645 this._z *= - 1; 3646 3647 this._onChangeCallback(); 3648 3649 return this; 3650 3651 } 3652 3653 dot( v ) { 3654 3655 return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; 3656 3657 } 3658 3659 lengthSq() { 3660 3661 return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; 3662 3663 } 3664 3665 length() { 3666 3667 return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); 3668 3669 } 3670 3671 normalize() { 3672 3673 let l = this.length(); 3674 3675 if ( l === 0 ) { 3676 3677 this._x = 0; 3678 this._y = 0; 3679 this._z = 0; 3680 this._w = 1; 3681 3682 } else { 3683 3684 l = 1 / l; 3685 3686 this._x = this._x * l; 3687 this._y = this._y * l; 3688 this._z = this._z * l; 3689 this._w = this._w * l; 3690 3691 } 3692 3693 this._onChangeCallback(); 3694 3695 return this; 3696 3697 } 3698 3699 multiply( q ) { 3700 3701 return this.multiplyQuaternions( this, q ); 3702 3703 } 3704 3705 premultiply( q ) { 3706 3707 return this.multiplyQuaternions( q, this ); 3708 3709 } 3710 3711 multiplyQuaternions( a, b ) { 3712 3713 // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm 3714 3715 const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; 3716 const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; 3717 3718 this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; 3719 this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; 3720 this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; 3721 this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; 3722 3723 this._onChangeCallback(); 3724 3725 return this; 3726 3727 } 3728 3729 slerp( qb, t ) { 3730 3731 if ( t === 0 ) return this; 3732 if ( t === 1 ) return this.copy( qb ); 3733 3734 const x = this._x, y = this._y, z = this._z, w = this._w; 3735 3736 // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ 3737 3738 let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; 3739 3740 if ( cosHalfTheta < 0 ) { 3741 3742 this._w = - qb._w; 3743 this._x = - qb._x; 3744 this._y = - qb._y; 3745 this._z = - qb._z; 3746 3747 cosHalfTheta = - cosHalfTheta; 3748 3749 } else { 3750 3751 this.copy( qb ); 3752 3753 } 3754 3755 if ( cosHalfTheta >= 1.0 ) { 3756 3757 this._w = w; 3758 this._x = x; 3759 this._y = y; 3760 this._z = z; 3761 3762 return this; 3763 3764 } 3765 3766 const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; 3767 3768 if ( sqrSinHalfTheta <= Number.EPSILON ) { 3769 3770 const s = 1 - t; 3771 this._w = s * w + t * this._w; 3772 this._x = s * x + t * this._x; 3773 this._y = s * y + t * this._y; 3774 this._z = s * z + t * this._z; 3775 3776 this.normalize(); // normalize calls _onChangeCallback() 3777 3778 return this; 3779 3780 } 3781 3782 const sinHalfTheta = Math.sqrt( sqrSinHalfTheta ); 3783 const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); 3784 const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, 3785 ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; 3786 3787 this._w = ( w * ratioA + this._w * ratioB ); 3788 this._x = ( x * ratioA + this._x * ratioB ); 3789 this._y = ( y * ratioA + this._y * ratioB ); 3790 this._z = ( z * ratioA + this._z * ratioB ); 3791 3792 this._onChangeCallback(); 3793 3794 return this; 3795 3796 } 3797 3798 slerpQuaternions( qa, qb, t ) { 3799 3800 return this.copy( qa ).slerp( qb, t ); 3801 3802 } 3803 3804 random() { 3805 3806 // Derived from http://planning.cs.uiuc.edu/node198.html 3807 // Note, this source uses w, x, y, z ordering, 3808 // so we swap the order below. 3809 3810 const u1 = Math.random(); 3811 const sqrt1u1 = Math.sqrt( 1 - u1 ); 3812 const sqrtu1 = Math.sqrt( u1 ); 3813 3814 const u2 = 2 * Math.PI * Math.random(); 3815 3816 const u3 = 2 * Math.PI * Math.random(); 3817 3818 return this.set( 3819 sqrt1u1 * Math.cos( u2 ), 3820 sqrtu1 * Math.sin( u3 ), 3821 sqrtu1 * Math.cos( u3 ), 3822 sqrt1u1 * Math.sin( u2 ), 3823 ); 3824 3825 } 3826 3827 equals( quaternion ) { 3828 3829 return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); 3830 3831 } 3832 3833 fromArray( array, offset = 0 ) { 3834 3835 this._x = array[ offset ]; 3836 this._y = array[ offset + 1 ]; 3837 this._z = array[ offset + 2 ]; 3838 this._w = array[ offset + 3 ]; 3839 3840 this._onChangeCallback(); 3841 3842 return this; 3843 3844 } 3845 3846 toArray( array = [], offset = 0 ) { 3847 3848 array[ offset ] = this._x; 3849 array[ offset + 1 ] = this._y; 3850 array[ offset + 2 ] = this._z; 3851 array[ offset + 3 ] = this._w; 3852 3853 return array; 3854 3855 } 3856 3857 fromBufferAttribute( attribute, index ) { 3858 3859 this._x = attribute.getX( index ); 3860 this._y = attribute.getY( index ); 3861 this._z = attribute.getZ( index ); 3862 this._w = attribute.getW( index ); 3863 3864 this._onChangeCallback(); 3865 3866 return this; 3867 3868 } 3869 3870 toJSON() { 3871 3872 return this.toArray(); 3873 3874 } 3875 3876 _onChange( callback ) { 3877 3878 this._onChangeCallback = callback; 3879 3880 return this; 3881 3882 } 3883 3884 _onChangeCallback() {} 3885 3886 *[ Symbol.iterator ]() { 3887 3888 yield this._x; 3889 yield this._y; 3890 yield this._z; 3891 yield this._w; 3892 3893 } 3894 3895} 3896 3897class Vector3 { 3898 3899 constructor( x = 0, y = 0, z = 0 ) { 3900 3901 Vector3.prototype.isVector3 = true; 3902 3903 this.x = x; 3904 this.y = y; 3905 this.z = z; 3906 3907 } 3908 3909 set( x, y, z ) { 3910 3911 if ( z === undefined ) z = this.z; // sprite.scale.set(x,y) 3912 3913 this.x = x; 3914 this.y = y; 3915 this.z = z; 3916 3917 return this; 3918 3919 } 3920 3921 setScalar( scalar ) { 3922 3923 this.x = scalar; 3924 this.y = scalar; 3925 this.z = scalar; 3926 3927 return this; 3928 3929 } 3930 3931 setX( x ) { 3932 3933 this.x = x; 3934 3935 return this; 3936 3937 } 3938 3939 setY( y ) { 3940 3941 this.y = y; 3942 3943 return this; 3944 3945 } 3946 3947 setZ( z ) { 3948 3949 this.z = z; 3950 3951 return this; 3952 3953 } 3954 3955 setComponent( index, value ) { 3956 3957 switch ( index ) { 3958 3959 case 0: this.x = value; break; 3960 case 1: this.y = value; break; 3961 case 2: this.z = value; break; 3962 default: throw new Error( 'index is out of range: ' + index ); 3963 3964 } 3965 3966 return this; 3967 3968 } 3969 3970 getComponent( index ) { 3971 3972 switch ( index ) { 3973 3974 case 0: return this.x; 3975 case 1: return this.y; 3976 case 2: return this.z; 3977 default: throw new Error( 'index is out of range: ' + index ); 3978 3979 } 3980 3981 } 3982 3983 clone() { 3984 3985 return new this.constructor( this.x, this.y, this.z ); 3986 3987 } 3988 3989 copy( v ) { 3990 3991 this.x = v.x; 3992 this.y = v.y; 3993 this.z = v.z; 3994 3995 return this; 3996 3997 } 3998 3999 add( v ) { 4000 4001 this.x += v.x; 4002 this.y += v.y; 4003 this.z += v.z; 4004 4005 return this; 4006 4007 } 4008 4009 addScalar( s ) { 4010 4011 this.x += s; 4012 this.y += s; 4013 this.z += s; 4014 4015 return this; 4016 4017 } 4018 4019 addVectors( a, b ) { 4020 4021 this.x = a.x + b.x; 4022 this.y = a.y + b.y; 4023 this.z = a.z + b.z; 4024 4025 return this; 4026 4027 } 4028 4029 addScaledVector( v, s ) { 4030 4031 this.x += v.x * s; 4032 this.y += v.y * s; 4033 this.z += v.z * s; 4034 4035 return this; 4036 4037 } 4038 4039 sub( v ) { 4040 4041 this.x -= v.x; 4042 this.y -= v.y; 4043 this.z -= v.z; 4044 4045 return this; 4046 4047 } 4048 4049 subScalar( s ) { 4050 4051 this.x -= s; 4052 this.y -= s; 4053 this.z -= s; 4054 4055 return this; 4056 4057 } 4058 4059 subVectors( a, b ) { 4060 4061 this.x = a.x - b.x; 4062 this.y = a.y - b.y; 4063 this.z = a.z - b.z; 4064 4065 return this; 4066 4067 } 4068 4069 multiply( v ) { 4070 4071 this.x *= v.x; 4072 this.y *= v.y; 4073 this.z *= v.z; 4074 4075 return this; 4076 4077 } 4078 4079 multiplyScalar( scalar ) { 4080 4081 this.x *= scalar; 4082 this.y *= scalar; 4083 this.z *= scalar; 4084 4085 return this; 4086 4087 } 4088 4089 multiplyVectors( a, b ) { 4090 4091 this.x = a.x * b.x; 4092 this.y = a.y * b.y; 4093 this.z = a.z * b.z; 4094 4095 return this; 4096 4097 } 4098 4099 applyEuler( euler ) { 4100 4101 return this.applyQuaternion( _quaternion$4.setFromEuler( euler ) ); 4102 4103 } 4104 4105 applyAxisAngle( axis, angle ) { 4106 4107 return this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) ); 4108 4109 } 4110 4111 applyMatrix3( m ) { 4112 4113 const x = this.x, y = this.y, z = this.z; 4114 const e = m.elements; 4115 4116 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z; 4117 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z; 4118 this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z; 4119 4120 return this; 4121 4122 } 4123 4124 applyNormalMatrix( m ) { 4125 4126 return this.applyMatrix3( m ).normalize(); 4127 4128 } 4129 4130 applyMatrix4( m ) { 4131 4132 const x = this.x, y = this.y, z = this.z; 4133 const e = m.elements; 4134 4135 const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); 4136 4137 this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w; 4138 this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w; 4139 this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w; 4140 4141 return this; 4142 4143 } 4144 4145 applyQuaternion( q ) { 4146 4147 // quaternion q is assumed to have unit length 4148 4149 const vx = this.x, vy = this.y, vz = this.z; 4150 const qx = q.x, qy = q.y, qz = q.z, qw = q.w; 4151 4152 // t = 2 * cross( q.xyz, v ); 4153 const tx = 2 * ( qy * vz - qz * vy ); 4154 const ty = 2 * ( qz * vx - qx * vz ); 4155 const tz = 2 * ( qx * vy - qy * vx ); 4156 4157 // v + q.w * t + cross( q.xyz, t ); 4158 this.x = vx + qw * tx + qy * tz - qz * ty; 4159 this.y = vy + qw * ty + qz * tx - qx * tz; 4160 this.z = vz + qw * tz + qx * ty - qy * tx; 4161 4162 return this; 4163 4164 } 4165 4166 project( camera ) { 4167 4168 return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix ); 4169 4170 } 4171 4172 unproject( camera ) { 4173 4174 return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld ); 4175 4176 } 4177 4178 transformDirection( m ) { 4179 4180 // input: THREE.Matrix4 affine matrix 4181 // vector interpreted as a direction 4182 4183 const x = this.x, y = this.y, z = this.z; 4184 const e = m.elements; 4185 4186 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z; 4187 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z; 4188 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z; 4189 4190 return this.normalize(); 4191 4192 } 4193 4194 divide( v ) { 4195 4196 this.x /= v.x; 4197 this.y /= v.y; 4198 this.z /= v.z; 4199 4200 return this; 4201 4202 } 4203 4204 divideScalar( scalar ) { 4205 4206 return this.multiplyScalar( 1 / scalar ); 4207 4208 } 4209 4210 min( v ) { 4211 4212 this.x = Math.min( this.x, v.x ); 4213 this.y = Math.min( this.y, v.y ); 4214 this.z = Math.min( this.z, v.z ); 4215 4216 return this; 4217 4218 } 4219 4220 max( v ) { 4221 4222 this.x = Math.max( this.x, v.x ); 4223 this.y = Math.max( this.y, v.y ); 4224 this.z = Math.max( this.z, v.z ); 4225 4226 return this; 4227 4228 } 4229 4230 clamp( min, max ) { 4231 4232 // assumes min < max, componentwise 4233 4234 this.x = Math.max( min.x, Math.min( max.x, this.x ) ); 4235 this.y = Math.max( min.y, Math.min( max.y, this.y ) ); 4236 this.z = Math.max( min.z, Math.min( max.z, this.z ) ); 4237 4238 return this; 4239 4240 } 4241 4242 clampScalar( minVal, maxVal ) { 4243 4244 this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); 4245 this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); 4246 this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); 4247 4248 return this; 4249 4250 } 4251 4252 clampLength( min, max ) { 4253 4254 const length = this.length(); 4255 4256 return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); 4257 4258 } 4259 4260 floor() { 4261 4262 this.x = Math.floor( this.x ); 4263 this.y = Math.floor( this.y ); 4264 this.z = Math.floor( this.z ); 4265 4266 return this; 4267 4268 } 4269 4270 ceil() { 4271 4272 this.x = Math.ceil( this.x ); 4273 this.y = Math.ceil( this.y ); 4274 this.z = Math.ceil( this.z ); 4275 4276 return this; 4277 4278 } 4279 4280 round() { 4281 4282 this.x = Math.round( this.x ); 4283 this.y = Math.round( this.y ); 4284 this.z = Math.round( this.z ); 4285 4286 return this; 4287 4288 } 4289 4290 roundToZero() { 4291 4292 this.x = Math.trunc( this.x ); 4293 this.y = Math.trunc( this.y ); 4294 this.z = Math.trunc( this.z ); 4295 4296 return this; 4297 4298 } 4299 4300 negate() { 4301 4302 this.x = - this.x; 4303 this.y = - this.y; 4304 this.z = - this.z; 4305 4306 return this; 4307 4308 } 4309 4310 dot( v ) { 4311 4312 return this.x * v.x + this.y * v.y + this.z * v.z; 4313 4314 } 4315 4316 // TODO lengthSquared? 4317 4318 lengthSq() { 4319 4320 return this.x * this.x + this.y * this.y + this.z * this.z; 4321 4322 } 4323 4324 length() { 4325 4326 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); 4327 4328 } 4329 4330 manhattanLength() { 4331 4332 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); 4333 4334 } 4335 4336 normalize() { 4337 4338 return this.divideScalar( this.length() || 1 ); 4339 4340 } 4341 4342 setLength( length ) { 4343 4344 return this.normalize().multiplyScalar( length ); 4345 4346 } 4347 4348 lerp( v, alpha ) { 4349 4350 this.x += ( v.x - this.x ) * alpha; 4351 this.y += ( v.y - this.y ) * alpha; 4352 this.z += ( v.z - this.z ) * alpha; 4353 4354 return this; 4355 4356 } 4357 4358 lerpVectors( v1, v2, alpha ) { 4359 4360 this.x = v1.x + ( v2.x - v1.x ) * alpha; 4361 this.y = v1.y + ( v2.y - v1.y ) * alpha; 4362 this.z = v1.z + ( v2.z - v1.z ) * alpha; 4363 4364 return this; 4365 4366 } 4367 4368 cross( v ) { 4369 4370 return this.crossVectors( this, v ); 4371 4372 } 4373 4374 crossVectors( a, b ) { 4375 4376 const ax = a.x, ay = a.y, az = a.z; 4377 const bx = b.x, by = b.y, bz = b.z; 4378 4379 this.x = ay * bz - az * by; 4380 this.y = az * bx - ax * bz; 4381 this.z = ax * by - ay * bx; 4382 4383 return this; 4384 4385 } 4386 4387 projectOnVector( v ) { 4388 4389 const denominator = v.lengthSq(); 4390 4391 if ( denominator === 0 ) return this.set( 0, 0, 0 ); 4392 4393 const scalar = v.dot( this ) / denominator; 4394 4395 return this.copy( v ).multiplyScalar( scalar ); 4396 4397 } 4398 4399 projectOnPlane( planeNormal ) { 4400 4401 _vector$c.copy( this ).projectOnVector( planeNormal ); 4402 4403 return this.sub( _vector$c ); 4404 4405 } 4406 4407 reflect( normal ) { 4408 4409 // reflect incident vector off plane orthogonal to normal 4410 // normal is assumed to have unit length 4411 4412 return this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); 4413 4414 } 4415 4416 angleTo( v ) { 4417 4418 const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); 4419 4420 if ( denominator === 0 ) return Math.PI / 2; 4421 4422 const theta = this.dot( v ) / denominator; 4423 4424 // clamp, to handle numerical problems 4425 4426 return Math.acos( clamp( theta, - 1, 1 ) ); 4427 4428 } 4429 4430 distanceTo( v ) { 4431 4432 return Math.sqrt( this.distanceToSquared( v ) ); 4433 4434 } 4435 4436 distanceToSquared( v ) { 4437 4438 const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; 4439 4440 return dx * dx + dy * dy + dz * dz; 4441 4442 } 4443 4444 manhattanDistanceTo( v ) { 4445 4446 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); 4447 4448 } 4449 4450 setFromSpherical( s ) { 4451 4452 return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); 4453 4454 } 4455 4456 setFromSphericalCoords( radius, phi, theta ) { 4457 4458 const sinPhiRadius = Math.sin( phi ) * radius; 4459 4460 this.x = sinPhiRadius * Math.sin( theta ); 4461 this.y = Math.cos( phi ) * radius; 4462 this.z = sinPhiRadius * Math.cos( theta ); 4463 4464 return this; 4465 4466 } 4467 4468 setFromCylindrical( c ) { 4469 4470 return this.setFromCylindricalCoords( c.radius, c.theta, c.y ); 4471 4472 } 4473 4474 setFromCylindricalCoords( radius, theta, y ) { 4475
vendor: 4,724 bytes, lines 4476-4770
4476 this.x = radius * Math.sin( theta ); 4477 this.y = y; 4478 this.z = radius * Math.cos( theta ); 4479 4480 return this; 4481 4482 } 4483 4484 setFromMatrixPosition( m ) { 4485 4486 const e = m.elements; 4487 4488 this.x = e[ 12 ]; 4489 this.y = e[ 13 ]; 4490 this.z = e[ 14 ]; 4491 4492 return this; 4493 4494 } 4495 4496 setFromMatrixScale( m ) { 4497 4498 const sx = this.setFromMatrixColumn( m, 0 ).length(); 4499 const sy = this.setFromMatrixColumn( m, 1 ).length(); 4500 const sz = this.setFromMatrixColumn( m, 2 ).length(); 4501 4502 this.x = sx; 4503 this.y = sy; 4504 this.z = sz; 4505 4506 return this; 4507 4508 } 4509 4510 setFromMatrixColumn( m, index ) { 4511 4512 return this.fromArray( m.elements, index * 4 ); 4513 4514 } 4515 4516 setFromMatrix3Column( m, index ) { 4517 4518 return this.fromArray( m.elements, index * 3 ); 4519 4520 } 4521 4522 setFromEuler( e ) { 4523 4524 this.x = e._x; 4525 this.y = e._y; 4526 this.z = e._z; 4527 4528 return this; 4529 4530 } 4531 4532 setFromColor( c ) { 4533 4534 this.x = c.r; 4535 this.y = c.g; 4536 this.z = c.b; 4537 4538 return this; 4539 4540 } 4541 4542 equals( v ) { 4543 4544 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); 4545 4546 } 4547 4548 fromArray( array, offset = 0 ) { 4549 4550 this.x = array[ offset ]; 4551 this.y = array[ offset + 1 ]; 4552 this.z = array[ offset + 2 ]; 4553 4554 return this; 4555 4556 } 4557 4558 toArray( array = [], offset = 0 ) { 4559 4560 array[ offset ] = this.x; 4561 array[ offset + 1 ] = this.y; 4562 array[ offset + 2 ] = this.z; 4563 4564 return array; 4565 4566 } 4567 4568 fromBufferAttribute( attribute, index ) { 4569 4570 this.x = attribute.getX( index ); 4571 this.y = attribute.getY( index ); 4572 this.z = attribute.getZ( index ); 4573 4574 return this; 4575 4576 } 4577 4578 random() { 4579 4580 this.x = Math.random(); 4581 this.y = Math.random(); 4582 this.z = Math.random(); 4583 4584 return this; 4585 4586 } 4587 4588 randomDirection() { 4589 4590 // Derived from https://mathworld.wolfram.com/SpherePointPicking.html 4591 4592 const u = ( Math.random() - 0.5 ) * 2; 4593 const t = Math.random() * Math.PI * 2; 4594 const f = Math.sqrt( 1 - u ** 2 ); 4595 4596 this.x = f * Math.cos( t ); 4597 this.y = f * Math.sin( t ); 4598 this.z = u; 4599 4600 return this; 4601 4602 } 4603 4604 *[ Symbol.iterator ]() { 4605 4606 yield this.x; 4607 yield this.y; 4608 yield this.z; 4609 4610 } 4611 4612} 4613 4614const _vector$c = /*@__PURE__*/ new Vector3(); 4615const _quaternion$4 = /*@__PURE__*/ new Quaternion(); 4616 4617class Box3 { 4618 4619 constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) { 4620 4621 this.isBox3 = true; 4622 4623 this.min = min; 4624 this.max = max; 4625 4626 } 4627 4628 set( min, max ) { 4629 4630 this.min.copy( min ); 4631 this.max.copy( max ); 4632 4633 return this; 4634 4635 } 4636 4637 setFromArray( array ) { 4638 4639 this.makeEmpty(); 4640 4641 for ( let i = 0, il = array.length; i < il; i += 3 ) { 4642 4643 this.expandByPoint( _vector$b.fromArray( array, i ) ); 4644 4645 } 4646 4647 return this; 4648 4649 } 4650 4651 setFromBufferAttribute( attribute ) { 4652 4653 this.makeEmpty(); 4654 4655 for ( let i = 0, il = attribute.count; i < il; i ++ ) { 4656 4657 this.expandByPoint( _vector$b.fromBufferAttribute( attribute, i ) ); 4658 4659 } 4660 4661 return this; 4662 4663 } 4664 4665 setFromPoints( points ) { 4666 4667 this.makeEmpty(); 4668 4669 for ( let i = 0, il = points.length; i < il; i ++ ) { 4670 4671 this.expandByPoint( points[ i ] ); 4672 4673 } 4674 4675 return this; 4676 4677 } 4678 4679 setFromCenterAndSize( center, size ) { 4680 4681 const halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 ); 4682 4683 this.min.copy( center ).sub( halfSize ); 4684 this.max.copy( center ).add( halfSize ); 4685 4686 return this; 4687 4688 } 4689 4690 setFromObject( object, precise = false ) { 4691 4692 this.makeEmpty(); 4693 4694 return this.expandByObject( object, precise ); 4695 4696 } 4697 4698 clone() { 4699 4700 return new this.constructor().copy( this ); 4701 4702 } 4703 4704 copy( box ) { 4705 4706 this.min.copy( box.min ); 4707 this.max.copy( box.max ); 4708 4709 return this; 4710 4711 } 4712 4713 makeEmpty() { 4714 4715 this.min.x = this.min.y = this.min.z = + Infinity; 4716 this.max.x = this.max.y = this.max.z = - Infinity; 4717 4718 return this; 4719 4720 } 4721 4722 isEmpty() { 4723 4724 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes 4725 4726 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); 4727 4728 } 4729 4730 getCenter( target ) { 4731 4732 return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); 4733 4734 } 4735 4736 getSize( target ) { 4737 4738 return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min ); 4739 4740 } 4741 4742 expandByPoint( point ) { 4743 4744 this.min.min( point ); 4745 this.max.max( point ); 4746 4747 return this; 4748 4749 } 4750 4751 expandByVector( vector ) { 4752 4753 this.min.sub( vector ); 4754 this.max.add( vector ); 4755 4756 return this; 4757 4758 } 4759 4760 expandByScalar( scalar ) { 4761 4762 this.min.addScalar( - scalar ); 4763 this.max.addScalar( scalar ); 4764 4765 return this; 4766 4767 } 4768 4769 expandByObject( object, precise = false ) { 4770
vendor: 9,756 bytes, lines 4771-5158
4771 // Computes the world-axis-aligned bounding box of an object (including its children), 4772 // accounting for both the object's, and children's, world transforms 4773 4774 object.updateWorldMatrix( false, false ); 4775 4776 const geometry = object.geometry; 4777 4778 if ( geometry !== undefined ) { 4779 4780 const positionAttribute = geometry.getAttribute( 'position' ); 4781 4782 // precise AABB computation based on vertex data requires at least a position attribute. 4783 // instancing isn't supported so far and uses the normal (conservative) code path. 4784 4785 if ( precise === true && positionAttribute !== undefined && object.isInstancedMesh !== true ) { 4786 4787 for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) { 4788 4789 if ( object.isMesh === true ) { 4790 4791 object.getVertexPosition( i, _vector$b ); 4792 4793 } else { 4794 4795 _vector$b.fromBufferAttribute( positionAttribute, i ); 4796 4797 } 4798 4799 _vector$b.applyMatrix4( object.matrixWorld ); 4800 this.expandByPoint( _vector$b ); 4801 4802 } 4803 4804 } else { 4805 4806 if ( object.boundingBox !== undefined ) { 4807 4808 // object-level bounding box 4809 4810 if ( object.boundingBox === null ) { 4811 4812 object.computeBoundingBox(); 4813 4814 } 4815 4816 _box$4.copy( object.boundingBox ); 4817 4818 4819 } else { 4820 4821 // geometry-level bounding box 4822 4823 if ( geometry.boundingBox === null ) { 4824 4825 geometry.computeBoundingBox(); 4826 4827 } 4828 4829 _box$4.copy( geometry.boundingBox ); 4830 4831 } 4832 4833 _box$4.applyMatrix4( object.matrixWorld ); 4834 4835 this.union( _box$4 ); 4836 4837 } 4838 4839 } 4840 4841 const children = object.children; 4842 4843 for ( let i = 0, l = children.length; i < l; i ++ ) { 4844 4845 this.expandByObject( children[ i ], precise ); 4846 4847 } 4848 4849 return this; 4850 4851 } 4852 4853 containsPoint( point ) { 4854 4855 return point.x < this.min.x || point.x > this.max.x || 4856 point.y < this.min.y || point.y > this.max.y || 4857 point.z < this.min.z || point.z > this.max.z ? false : true; 4858 4859 } 4860 4861 containsBox( box ) { 4862 4863 return this.min.x <= box.min.x && box.max.x <= this.max.x && 4864 this.min.y <= box.min.y && box.max.y <= this.max.y && 4865 this.min.z <= box.min.z && box.max.z <= this.max.z; 4866 4867 } 4868 4869 getParameter( point, target ) { 4870 4871 // This can potentially have a divide by zero if the box 4872 // has a size dimension of 0. 4873 4874 return target.set( 4875 ( point.x - this.min.x ) / ( this.max.x - this.min.x ), 4876 ( point.y - this.min.y ) / ( this.max.y - this.min.y ), 4877 ( point.z - this.min.z ) / ( this.max.z - this.min.z ) 4878 ); 4879 4880 } 4881 4882 intersectsBox( box ) { 4883 4884 // using 6 splitting planes to rule out intersections. 4885 return box.max.x < this.min.x || box.min.x > this.max.x || 4886 box.max.y < this.min.y || box.min.y > this.max.y || 4887 box.max.z < this.min.z || box.min.z > this.max.z ? false : true; 4888 4889 } 4890 4891 intersectsSphere( sphere ) { 4892 4893 // Find the point on the AABB closest to the sphere center. 4894 this.clampPoint( sphere.center, _vector$b ); 4895 4896 // If that point is inside the sphere, the AABB and sphere intersect. 4897 return _vector$b.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius ); 4898 4899 } 4900 4901 intersectsPlane( plane ) { 4902 4903 // We compute the minimum and maximum dot product values. If those values 4904 // are on the same side (back or front) of the plane, then there is no intersection. 4905 4906 let min, max; 4907 4908 if ( plane.normal.x > 0 ) { 4909 4910 min = plane.normal.x * this.min.x; 4911 max = plane.normal.x * this.max.x; 4912 4913 } else { 4914 4915 min = plane.normal.x * this.max.x; 4916 max = plane.normal.x * this.min.x; 4917 4918 } 4919 4920 if ( plane.normal.y > 0 ) { 4921 4922 min += plane.normal.y * this.min.y; 4923 max += plane.normal.y * this.max.y; 4924 4925 } else { 4926 4927 min += plane.normal.y * this.max.y; 4928 max += plane.normal.y * this.min.y; 4929 4930 } 4931 4932 if ( plane.normal.z > 0 ) { 4933 4934 min += plane.normal.z * this.min.z; 4935 max += plane.normal.z * this.max.z; 4936 4937 } else { 4938 4939 min += plane.normal.z * this.max.z; 4940 max += plane.normal.z * this.min.z; 4941 4942 } 4943 4944 return ( min <= - plane.constant && max >= - plane.constant ); 4945 4946 } 4947 4948 intersectsTriangle( triangle ) { 4949 4950 if ( this.isEmpty() ) { 4951 4952 return false; 4953 4954 } 4955 4956 // compute box center and extents 4957 this.getCenter( _center ); 4958 _extents.subVectors( this.max, _center ); 4959 4960 // translate triangle to aabb origin 4961 _v0$2.subVectors( triangle.a, _center ); 4962 _v1$7.subVectors( triangle.b, _center ); 4963 _v2$4.subVectors( triangle.c, _center ); 4964 4965 // compute edge vectors for triangle 4966 _f0.subVectors( _v1$7, _v0$2 ); 4967 _f1.subVectors( _v2$4, _v1$7 ); 4968 _f2.subVectors( _v0$2, _v2$4 ); 4969 4970 // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb 4971 // make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation 4972 // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned) 4973 let axes = [ 4974 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y, 4975 _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x, 4976 - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0 4977 ]; 4978 if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { 4979 4980 return false; 4981 4982 } 4983 4984 // test 3 face normals from the aabb 4985 axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]; 4986 if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { 4987 4988 return false; 4989 4990 } 4991 4992 // finally testing the face normal of the triangle 4993 // use already existing triangle edge vectors here 4994 _triangleNormal.crossVectors( _f0, _f1 ); 4995 axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ]; 4996 4997 return satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ); 4998 4999 } 5000 5001 clampPoint( point, target ) { 5002 5003 return target.copy( point ).clamp( this.min, this.max ); 5004 5005 } 5006 5007 distanceToPoint( point ) { 5008 5009 return this.clampPoint( point, _vector$b ).distanceTo( point ); 5010 5011 } 5012 5013 getBoundingSphere( target ) { 5014 5015 if ( this.isEmpty() ) { 5016 5017 target.makeEmpty(); 5018 5019 } else { 5020 5021 this.getCenter( target.center ); 5022 5023 target.radius = this.getSize( _vector$b ).length() * 0.5; 5024 5025 } 5026 5027 return target; 5028 5029 } 5030 5031 intersect( box ) { 5032 5033 this.min.max( box.min ); 5034 this.max.min( box.max ); 5035 5036 // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values. 5037 if ( this.isEmpty() ) this.makeEmpty(); 5038 5039 return this; 5040 5041 } 5042 5043 union( box ) { 5044 5045 this.min.min( box.min ); 5046 this.max.max( box.max ); 5047 5048 return this; 5049 5050 } 5051 5052 applyMatrix4( matrix ) { 5053 5054 // transform of empty box is an empty box. 5055 if ( this.isEmpty() ) return this; 5056 5057 // NOTE: I am using a binary pattern to specify all 2^3 combinations below 5058 _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 5059 _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 5060 _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 5061 _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 5062 _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 5063 _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 5064 _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 5065 _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 5066 5067 this.setFromPoints( _points ); 5068 5069 return this; 5070 5071 } 5072 5073 translate( offset ) { 5074 5075 this.min.add( offset ); 5076 this.max.add( offset ); 5077 5078 return this; 5079 5080 } 5081 5082 equals( box ) { 5083 5084 return box.min.equals( this.min ) && box.max.equals( this.max ); 5085 5086 } 5087 5088} 5089 5090const _points = [ 5091 /*@__PURE__*/ new Vector3(), 5092 /*@__PURE__*/ new Vector3(), 5093 /*@__PURE__*/ new Vector3(), 5094 /*@__PURE__*/ new Vector3(), 5095 /*@__PURE__*/ new Vector3(), 5096 /*@__PURE__*/ new Vector3(), 5097 /*@__PURE__*/ new Vector3(), 5098 /*@__PURE__*/ new Vector3() 5099]; 5100 5101const _vector$b = /*@__PURE__*/ new Vector3(); 5102 5103const _box$4 = /*@__PURE__*/ new Box3(); 5104 5105// triangle centered vertices 5106 5107const _v0$2 = /*@__PURE__*/ new Vector3(); 5108const _v1$7 = /*@__PURE__*/ new Vector3(); 5109const _v2$4 = /*@__PURE__*/ new Vector3(); 5110 5111// triangle edge vectors 5112 5113const _f0 = /*@__PURE__*/ new Vector3(); 5114const _f1 = /*@__PURE__*/ new Vector3(); 5115const _f2 = /*@__PURE__*/ new Vector3(); 5116 5117const _center = /*@__PURE__*/ new Vector3(); 5118const _extents = /*@__PURE__*/ new Vector3(); 5119const _triangleNormal = /*@__PURE__*/ new Vector3(); 5120const _testAxis = /*@__PURE__*/ new Vector3(); 5121 5122function satForAxes( axes, v0, v1, v2, extents ) { 5123 5124 for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) { 5125 5126 _testAxis.fromArray( axes, i ); 5127 // project the aabb onto the separating axis 5128 const r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z ); 5129 // project all 3 vertices of the triangle onto the separating axis 5130 const p0 = v0.dot( _testAxis ); 5131 const p1 = v1.dot( _testAxis ); 5132 const p2 = v2.dot( _testAxis ); 5133 // actual test, basically see if either of the most extreme of the triangle points intersects r 5134 if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) { 5135 5136 // points of the projected triangle are outside the projected half-length of the aabb 5137 // the axis is separating and we can exit 5138 return false; 5139 5140 } 5141 5142 } 5143 5144 return true; 5145 5146} 5147 5148const _box$3 = /*@__PURE__*/ new Box3(); 5149const _v1$6 = /*@__PURE__*/ new Vector3(); 5150const _v2$3 = /*@__PURE__*/ new Vector3(); 5151 5152class Sphere { 5153 5154 constructor( center = new Vector3(), radius = - 1 ) { 5155 5156 this.isSphere = true; 5157 5158 this.center = center;
vendor: 4,718 bytes, lines 5159-5450
5159 this.radius = radius; 5160 5161 } 5162 5163 set( center, radius ) { 5164 5165 this.center.copy( center ); 5166 this.radius = radius; 5167 5168 return this; 5169 5170 } 5171 5172 setFromPoints( points, optionalCenter ) { 5173 5174 const center = this.center; 5175 5176 if ( optionalCenter !== undefined ) { 5177 5178 center.copy( optionalCenter ); 5179 5180 } else { 5181 5182 _box$3.setFromPoints( points ).getCenter( center ); 5183 5184 } 5185 5186 let maxRadiusSq = 0; 5187 5188 for ( let i = 0, il = points.length; i < il; i ++ ) { 5189 5190 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); 5191 5192 } 5193 5194 this.radius = Math.sqrt( maxRadiusSq ); 5195 5196 return this; 5197 5198 } 5199 5200 copy( sphere ) { 5201 5202 this.center.copy( sphere.center ); 5203 this.radius = sphere.radius; 5204 5205 return this; 5206 5207 } 5208 5209 isEmpty() { 5210 5211 return ( this.radius < 0 ); 5212 5213 } 5214 5215 makeEmpty() { 5216 5217 this.center.set( 0, 0, 0 ); 5218 this.radius = - 1; 5219 5220 return this; 5221 5222 } 5223 5224 containsPoint( point ) { 5225 5226 return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); 5227 5228 } 5229 5230 distanceToPoint( point ) { 5231 5232 return ( point.distanceTo( this.center ) - this.radius ); 5233 5234 } 5235 5236 intersectsSphere( sphere ) { 5237 5238 const radiusSum = this.radius + sphere.radius; 5239 5240 return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); 5241 5242 } 5243 5244 intersectsBox( box ) { 5245 5246 return box.intersectsSphere( this ); 5247 5248 } 5249 5250 intersectsPlane( plane ) { 5251 5252 return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; 5253 5254 } 5255 5256 clampPoint( point, target ) { 5257 5258 const deltaLengthSq = this.center.distanceToSquared( point ); 5259 5260 target.copy( point ); 5261 5262 if ( deltaLengthSq > ( this.radius * this.radius ) ) { 5263 5264 target.sub( this.center ).normalize(); 5265 target.multiplyScalar( this.radius ).add( this.center ); 5266 5267 } 5268 5269 return target; 5270 5271 } 5272 5273 getBoundingBox( target ) { 5274 5275 if ( this.isEmpty() ) { 5276 5277 // Empty sphere produces empty bounding box 5278 target.makeEmpty(); 5279 return target; 5280 5281 } 5282 5283 target.set( this.center, this.center ); 5284 target.expandByScalar( this.radius ); 5285 5286 return target; 5287 5288 } 5289 5290 applyMatrix4( matrix ) { 5291 5292 this.center.applyMatrix4( matrix ); 5293 this.radius = this.radius * matrix.getMaxScaleOnAxis(); 5294 5295 return this; 5296 5297 } 5298 5299 translate( offset ) { 5300 5301 this.center.add( offset ); 5302 5303 return this; 5304 5305 } 5306 5307 expandByPoint( point ) { 5308 5309 if ( this.isEmpty() ) { 5310 5311 this.center.copy( point ); 5312 5313 this.radius = 0; 5314 5315 return this; 5316 5317 } 5318 5319 _v1$6.subVectors( point, this.center ); 5320 5321 const lengthSq = _v1$6.lengthSq(); 5322 5323 if ( lengthSq > ( this.radius * this.radius ) ) { 5324 5325 // calculate the minimal sphere 5326 5327 const length = Math.sqrt( lengthSq ); 5328 5329 const delta = ( length - this.radius ) * 0.5; 5330 5331 this.center.addScaledVector( _v1$6, delta / length ); 5332 5333 this.radius += delta; 5334 5335 } 5336 5337 return this; 5338 5339 } 5340 5341 union( sphere ) { 5342 5343 if ( sphere.isEmpty() ) { 5344 5345 return this; 5346 5347 } 5348 5349 if ( this.isEmpty() ) { 5350 5351 this.copy( sphere ); 5352 5353 return this; 5354 5355 } 5356 5357 if ( this.center.equals( sphere.center ) === true ) { 5358 5359 this.radius = Math.max( this.radius, sphere.radius ); 5360 5361 } else { 5362 5363 _v2$3.subVectors( sphere.center, this.center ).setLength( sphere.radius ); 5364 5365 this.expandByPoint( _v1$6.copy( sphere.center ).add( _v2$3 ) ); 5366 5367 this.expandByPoint( _v1$6.copy( sphere.center ).sub( _v2$3 ) ); 5368 5369 } 5370 5371 return this; 5372 5373 } 5374 5375 equals( sphere ) { 5376 5377 return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); 5378 5379 } 5380 5381 clone() { 5382 5383 return new this.constructor().copy( this ); 5384 5385 } 5386 5387} 5388 5389const _vector$a = /*@__PURE__*/ new Vector3(); 5390const _segCenter = /*@__PURE__*/ new Vector3(); 5391const _segDir = /*@__PURE__*/ new Vector3(); 5392const _diff = /*@__PURE__*/ new Vector3(); 5393 5394const _edge1 = /*@__PURE__*/ new Vector3(); 5395const _edge2 = /*@__PURE__*/ new Vector3(); 5396const _normal$1 = /*@__PURE__*/ new Vector3(); 5397 5398class Ray { 5399 5400 constructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) { 5401 5402 this.origin = origin; 5403 this.direction = direction; 5404 5405 } 5406 5407 set( origin, direction ) { 5408 5409 this.origin.copy( origin ); 5410 this.direction.copy( direction ); 5411 5412 return this; 5413 5414 } 5415 5416 copy( ray ) { 5417 5418 this.origin.copy( ray.origin ); 5419 this.direction.copy( ray.direction ); 5420 5421 return this; 5422 5423 } 5424 5425 at( t, target ) { 5426 5427 return target.copy( this.origin ).addScaledVector( this.direction, t ); 5428 5429 } 5430 5431 lookAt( v ) { 5432 5433 this.direction.copy( v ).sub( this.origin ).normalize(); 5434 5435 return this; 5436 5437 } 5438 5439 recast( t ) { 5440 5441 this.origin.copy( this.at( t, _vector$a ) ); 5442 5443 return this; 5444 5445 } 5446 5447 closestPointToPoint( point, target ) { 5448 5449 target.subVectors( point, this.origin ); 5450
vendor: 8,776 bytes, lines 5451-5841
5451 const directionDistance = target.dot( this.direction ); 5452 5453 if ( directionDistance < 0 ) { 5454 5455 return target.copy( this.origin ); 5456 5457 } 5458 5459 return target.copy( this.origin ).addScaledVector( this.direction, directionDistance ); 5460 5461 } 5462 5463 distanceToPoint( point ) { 5464 5465 return Math.sqrt( this.distanceSqToPoint( point ) ); 5466 5467 } 5468 5469 distanceSqToPoint( point ) { 5470 5471 const directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction ); 5472 5473 // point behind the ray 5474 5475 if ( directionDistance < 0 ) { 5476 5477 return this.origin.distanceToSquared( point ); 5478 5479 } 5480 5481 _vector$a.copy( this.origin ).addScaledVector( this.direction, directionDistance ); 5482 5483 return _vector$a.distanceToSquared( point ); 5484 5485 } 5486 5487 distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { 5488 5489 // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteDistRaySegment.h 5490 // It returns the min distance between the ray and the segment 5491 // defined by v0 and v1 5492 // It can also set two optional targets : 5493 // - The closest point on the ray 5494 // - The closest point on the segment 5495 5496 _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); 5497 _segDir.copy( v1 ).sub( v0 ).normalize(); 5498 _diff.copy( this.origin ).sub( _segCenter ); 5499 5500 const segExtent = v0.distanceTo( v1 ) * 0.5; 5501 const a01 = - this.direction.dot( _segDir ); 5502 const b0 = _diff.dot( this.direction ); 5503 const b1 = - _diff.dot( _segDir ); 5504 const c = _diff.lengthSq(); 5505 const det = Math.abs( 1 - a01 * a01 ); 5506 let s0, s1, sqrDist, extDet; 5507 5508 if ( det > 0 ) { 5509 5510 // The ray and segment are not parallel. 5511 5512 s0 = a01 * b1 - b0; 5513 s1 = a01 * b0 - b1; 5514 extDet = segExtent * det; 5515 5516 if ( s0 >= 0 ) { 5517 5518 if ( s1 >= - extDet ) { 5519 5520 if ( s1 <= extDet ) { 5521 5522 // region 0 5523 // Minimum at interior points of ray and segment. 5524 5525 const invDet = 1 / det; 5526 s0 *= invDet; 5527 s1 *= invDet; 5528 sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; 5529 5530 } else { 5531 5532 // region 1 5533 5534 s1 = segExtent; 5535 s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); 5536 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 5537 5538 } 5539 5540 } else { 5541 5542 // region 5 5543 5544 s1 = - segExtent; 5545 s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); 5546 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 5547 5548 } 5549 5550 } else { 5551 5552 if ( s1 <= - extDet ) { 5553 5554 // region 4 5555 5556 s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); 5557 s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); 5558 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 5559 5560 } else if ( s1 <= extDet ) { 5561 5562 // region 3 5563 5564 s0 = 0; 5565 s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); 5566 sqrDist = s1 * ( s1 + 2 * b1 ) + c; 5567 5568 } else { 5569 5570 // region 2 5571 5572 s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); 5573 s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); 5574 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 5575 5576 } 5577 5578 } 5579 5580 } else { 5581 5582 // Ray and segment are parallel. 5583 5584 s1 = ( a01 > 0 ) ? - segExtent : segExtent; 5585 s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); 5586 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 5587 5588 } 5589 5590 if ( optionalPointOnRay ) { 5591 5592 optionalPointOnRay.copy( this.origin ).addScaledVector( this.direction, s0 ); 5593 5594 } 5595 5596 if ( optionalPointOnSegment ) { 5597 5598 optionalPointOnSegment.copy( _segCenter ).addScaledVector( _segDir, s1 ); 5599 5600 } 5601 5602 return sqrDist; 5603 5604 } 5605 5606 intersectSphere( sphere, target ) { 5607 5608 _vector$a.subVectors( sphere.center, this.origin ); 5609 const tca = _vector$a.dot( this.direction ); 5610 const d2 = _vector$a.dot( _vector$a ) - tca * tca; 5611 const radius2 = sphere.radius * sphere.radius; 5612 5613 if ( d2 > radius2 ) return null; 5614 5615 const thc = Math.sqrt( radius2 - d2 ); 5616 5617 // t0 = first intersect point - entrance on front of sphere 5618 const t0 = tca - thc; 5619 5620 // t1 = second intersect point - exit point on back of sphere 5621 const t1 = tca + thc; 5622 5623 // test to see if t1 is behind the ray - if so, return null 5624 if ( t1 < 0 ) return null; 5625 5626 // test to see if t0 is behind the ray: 5627 // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, 5628 // in order to always return an intersect point that is in front of the ray. 5629 if ( t0 < 0 ) return this.at( t1, target ); 5630 5631 // else t0 is in front of the ray, so return the first collision point scaled by t0 5632 return this.at( t0, target ); 5633 5634 } 5635 5636 intersectsSphere( sphere ) { 5637 5638 return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius ); 5639 5640 } 5641 5642 distanceToPlane( plane ) { 5643 5644 const denominator = plane.normal.dot( this.direction ); 5645 5646 if ( denominator === 0 ) { 5647 5648 // line is coplanar, return origin 5649 if ( plane.distanceToPoint( this.origin ) === 0 ) { 5650 5651 return 0; 5652 5653 } 5654 5655 // Null is preferable to undefined since undefined means.... it is undefined 5656 5657 return null; 5658 5659 } 5660 5661 const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; 5662 5663 // Return if the ray never intersects the plane 5664 5665 return t >= 0 ? t : null; 5666 5667 } 5668 5669 intersectPlane( plane, target ) { 5670 5671 const t = this.distanceToPlane( plane ); 5672 5673 if ( t === null ) { 5674 5675 return null; 5676 5677 } 5678 5679 return this.at( t, target ); 5680 5681 } 5682 5683 intersectsPlane( plane ) { 5684 5685 // check if the ray lies on the plane first 5686 5687 const distToPoint = plane.distanceToPoint( this.origin ); 5688 5689 if ( distToPoint === 0 ) { 5690 5691 return true; 5692 5693 } 5694 5695 const denominator = plane.normal.dot( this.direction ); 5696 5697 if ( denominator * distToPoint < 0 ) { 5698 5699 return true; 5700 5701 } 5702 5703 // ray origin is behind the plane (and is pointing behind it) 5704 5705 return false; 5706 5707 } 5708 5709 intersectBox( box, target ) { 5710 5711 let tmin, tmax, tymin, tymax, tzmin, tzmax; 5712 5713 const invdirx = 1 / this.direction.x, 5714 invdiry = 1 / this.direction.y, 5715 invdirz = 1 / this.direction.z; 5716 5717 const origin = this.origin; 5718 5719 if ( invdirx >= 0 ) { 5720 5721 tmin = ( box.min.x - origin.x ) * invdirx; 5722 tmax = ( box.max.x - origin.x ) * invdirx; 5723 5724 } else { 5725 5726 tmin = ( box.max.x - origin.x ) * invdirx; 5727 tmax = ( box.min.x - origin.x ) * invdirx; 5728 5729 } 5730 5731 if ( invdiry >= 0 ) { 5732 5733 tymin = ( box.min.y - origin.y ) * invdiry; 5734 tymax = ( box.max.y - origin.y ) * invdiry; 5735 5736 } else { 5737 5738 tymin = ( box.max.y - origin.y ) * invdiry; 5739 tymax = ( box.min.y - origin.y ) * invdiry; 5740 5741 } 5742 5743 if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; 5744 5745 if ( tymin > tmin || isNaN( tmin ) ) tmin = tymin; 5746 5747 if ( tymax < tmax || isNaN( tmax ) ) tmax = tymax; 5748 5749 if ( invdirz >= 0 ) { 5750 5751 tzmin = ( box.min.z - origin.z ) * invdirz; 5752 tzmax = ( box.max.z - origin.z ) * invdirz; 5753 5754 } else { 5755 5756 tzmin = ( box.max.z - origin.z ) * invdirz; 5757 tzmax = ( box.min.z - origin.z ) * invdirz; 5758 5759 } 5760 5761 if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; 5762 5763 if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; 5764 5765 if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; 5766 5767 //return point closest to the ray (positive side) 5768 5769 if ( tmax < 0 ) return null; 5770 5771 return this.at( tmin >= 0 ? tmin : tmax, target ); 5772 5773 } 5774 5775 intersectsBox( box ) { 5776 5777 return this.intersectBox( box, _vector$a ) !== null; 5778 5779 } 5780 5781 intersectTriangle( a, b, c, backfaceCulling, target ) { 5782 5783 // Compute the offset origin, edges, and normal. 5784 5785 // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h 5786 5787 _edge1.subVectors( b, a ); 5788 _edge2.subVectors( c, a ); 5789 _normal$1.crossVectors( _edge1, _edge2 ); 5790 5791 // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, 5792 // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by 5793 // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) 5794 // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) 5795 // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) 5796 let DdN = this.direction.dot( _normal$1 ); 5797 let sign; 5798 5799 if ( DdN > 0 ) { 5800 5801 if ( backfaceCulling ) return null; 5802 sign = 1; 5803 5804 } else if ( DdN < 0 ) { 5805 5806 sign = - 1; 5807 DdN = - DdN; 5808 5809 } else { 5810 5811 return null; 5812 5813 } 5814 5815 _diff.subVectors( this.origin, a ); 5816 const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) ); 5817 5818 // b1 < 0, no intersection 5819 if ( DdQxE2 < 0 ) { 5820 5821 return null; 5822 5823 } 5824 5825 const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) ); 5826 5827 // b2 < 0, no intersection 5828 if ( DdE1xQ < 0 ) { 5829 5830 return null; 5831 5832 } 5833 5834 // b1+b2 > 1, no intersection 5835 if ( DdQxE2 + DdE1xQ > DdN ) { 5836 5837 return null; 5838 5839 } 5840 5841 // Line intersects triangle, check if ray does.
vendor: 5,044 bytes, lines 5842-6107
5842 const QdN = - sign * _diff.dot( _normal$1 ); 5843 5844 // t < 0, no intersection 5845 if ( QdN < 0 ) { 5846 5847 return null; 5848 5849 } 5850 5851 // Ray intersects triangle. 5852 return this.at( QdN / DdN, target ); 5853 5854 } 5855 5856 applyMatrix4( matrix4 ) { 5857 5858 this.origin.applyMatrix4( matrix4 ); 5859 this.direction.transformDirection( matrix4 ); 5860 5861 return this; 5862 5863 } 5864 5865 equals( ray ) { 5866 5867 return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); 5868 5869 } 5870 5871 clone() { 5872 5873 return new this.constructor().copy( this ); 5874 5875 } 5876 5877} 5878 5879class Matrix4 { 5880 5881 constructor( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { 5882 5883 Matrix4.prototype.isMatrix4 = true; 5884 5885 this.elements = [ 5886 5887 1, 0, 0, 0, 5888 0, 1, 0, 0, 5889 0, 0, 1, 0, 5890 0, 0, 0, 1 5891 5892 ]; 5893 5894 if ( n11 !== undefined ) { 5895 5896 this.set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ); 5897 5898 } 5899 5900 } 5901 5902 set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { 5903 5904 const te = this.elements; 5905 5906 te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; 5907 te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; 5908 te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; 5909 te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; 5910 5911 return this; 5912 5913 } 5914 5915 identity() { 5916 5917 this.set( 5918 5919 1, 0, 0, 0, 5920 0, 1, 0, 0, 5921 0, 0, 1, 0, 5922 0, 0, 0, 1 5923 5924 ); 5925 5926 return this; 5927 5928 } 5929 5930 clone() { 5931 5932 return new Matrix4().fromArray( this.elements ); 5933 5934 } 5935 5936 copy( m ) { 5937 5938 const te = this.elements; 5939 const me = m.elements; 5940 5941 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ]; 5942 te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; 5943 te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ]; 5944 te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ]; 5945 5946 return this; 5947 5948 } 5949 5950 copyPosition( m ) { 5951 5952 const te = this.elements, me = m.elements; 5953 5954 te[ 12 ] = me[ 12 ]; 5955 te[ 13 ] = me[ 13 ]; 5956 te[ 14 ] = me[ 14 ]; 5957 5958 return this; 5959 5960 } 5961 5962 setFromMatrix3( m ) { 5963 5964 const me = m.elements; 5965 5966 this.set( 5967 5968 me[ 0 ], me[ 3 ], me[ 6 ], 0, 5969 me[ 1 ], me[ 4 ], me[ 7 ], 0, 5970 me[ 2 ], me[ 5 ], me[ 8 ], 0, 5971 0, 0, 0, 1 5972 5973 ); 5974 5975 return this; 5976 5977 } 5978 5979 extractBasis( xAxis, yAxis, zAxis ) { 5980 5981 xAxis.setFromMatrixColumn( this, 0 ); 5982 yAxis.setFromMatrixColumn( this, 1 ); 5983 zAxis.setFromMatrixColumn( this, 2 ); 5984 5985 return this; 5986 5987 } 5988 5989 makeBasis( xAxis, yAxis, zAxis ) { 5990 5991 this.set( 5992 xAxis.x, yAxis.x, zAxis.x, 0, 5993 xAxis.y, yAxis.y, zAxis.y, 0, 5994 xAxis.z, yAxis.z, zAxis.z, 0, 5995 0, 0, 0, 1 5996 ); 5997 5998 return this; 5999 6000 } 6001 6002 extractRotation( m ) { 6003 6004 // this method does not support reflection matrices 6005 6006 const te = this.elements; 6007 const me = m.elements; 6008 6009 const scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length(); 6010 const scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length(); 6011 const scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length(); 6012 6013 te[ 0 ] = me[ 0 ] * scaleX; 6014 te[ 1 ] = me[ 1 ] * scaleX; 6015 te[ 2 ] = me[ 2 ] * scaleX; 6016 te[ 3 ] = 0; 6017 6018 te[ 4 ] = me[ 4 ] * scaleY; 6019 te[ 5 ] = me[ 5 ] * scaleY; 6020 te[ 6 ] = me[ 6 ] * scaleY; 6021 te[ 7 ] = 0; 6022 6023 te[ 8 ] = me[ 8 ] * scaleZ; 6024 te[ 9 ] = me[ 9 ] * scaleZ; 6025 te[ 10 ] = me[ 10 ] * scaleZ; 6026 te[ 11 ] = 0; 6027 6028 te[ 12 ] = 0; 6029 te[ 13 ] = 0; 6030 te[ 14 ] = 0; 6031 te[ 15 ] = 1; 6032 6033 return this; 6034 6035 } 6036 6037 makeRotationFromEuler( euler ) { 6038 6039 const te = this.elements; 6040 6041 const x = euler.x, y = euler.y, z = euler.z; 6042 const a = Math.cos( x ), b = Math.sin( x ); 6043 const c = Math.cos( y ), d = Math.sin( y ); 6044 const e = Math.cos( z ), f = Math.sin( z ); 6045 6046 if ( euler.order === 'XYZ' ) { 6047 6048 const ae = a * e, af = a * f, be = b * e, bf = b * f; 6049 6050 te[ 0 ] = c * e; 6051 te[ 4 ] = - c * f; 6052 te[ 8 ] = d; 6053 6054 te[ 1 ] = af + be * d; 6055 te[ 5 ] = ae - bf * d; 6056 te[ 9 ] = - b * c; 6057 6058 te[ 2 ] = bf - ae * d; 6059 te[ 6 ] = be + af * d; 6060 te[ 10 ] = a * c; 6061 6062 } else if ( euler.order === 'YXZ' ) { 6063 6064 const ce = c * e, cf = c * f, de = d * e, df = d * f; 6065 6066 te[ 0 ] = ce + df * b; 6067 te[ 4 ] = de * b - cf; 6068 te[ 8 ] = a * d; 6069 6070 te[ 1 ] = a * f; 6071 te[ 5 ] = a * e; 6072 te[ 9 ] = - b; 6073 6074 te[ 2 ] = cf * b - de; 6075 te[ 6 ] = df + ce * b; 6076 te[ 10 ] = a * c; 6077 6078 } else if ( euler.order === 'ZXY' ) { 6079 6080 const ce = c * e, cf = c * f, de = d * e, df = d * f; 6081 6082 te[ 0 ] = ce - df * b; 6083 te[ 4 ] = - a * f; 6084 te[ 8 ] = de + cf * b; 6085 6086 te[ 1 ] = cf + de * b; 6087 te[ 5 ] = a * e; 6088 te[ 9 ] = df - ce * b; 6089 6090 te[ 2 ] = - a * d; 6091 te[ 6 ] = b; 6092 te[ 10 ] = a * c; 6093 6094 } else if ( euler.order === 'ZYX' ) { 6095 6096 const ae = a * e, af = a * f, be = b * e, bf = b * f; 6097 6098 te[ 0 ] = c * e; 6099 te[ 4 ] = be * d - af; 6100 te[ 8 ] = ae * d + bf; 6101 6102 te[ 1 ] = c * f; 6103 te[ 5 ] = bf * d + ae; 6104 te[ 9 ] = af * d - be; 6105 6106 te[ 2 ] = - d; 6107 te[ 6 ] = b * c;
vendor: 42,655 bytes, lines 6108-8206
6108 te[ 10 ] = a * c; 6109 6110 } else if ( euler.order === 'YZX' ) { 6111 6112 const ac = a * c, ad = a * d, bc = b * c, bd = b * d; 6113 6114 te[ 0 ] = c * e; 6115 te[ 4 ] = bd - ac * f; 6116 te[ 8 ] = bc * f + ad; 6117 6118 te[ 1 ] = f; 6119 te[ 5 ] = a * e; 6120 te[ 9 ] = - b * e; 6121 6122 te[ 2 ] = - d * e; 6123 te[ 6 ] = ad * f + bc; 6124 te[ 10 ] = ac - bd * f; 6125 6126 } else if ( euler.order === 'XZY' ) { 6127 6128 const ac = a * c, ad = a * d, bc = b * c, bd = b * d; 6129 6130 te[ 0 ] = c * e; 6131 te[ 4 ] = - f; 6132 te[ 8 ] = d * e; 6133 6134 te[ 1 ] = ac * f + bd; 6135 te[ 5 ] = a * e; 6136 te[ 9 ] = ad * f - bc; 6137 6138 te[ 2 ] = bc * f - ad; 6139 te[ 6 ] = b * e; 6140 te[ 10 ] = bd * f + ac; 6141 6142 } 6143 6144 // bottom row 6145 te[ 3 ] = 0; 6146 te[ 7 ] = 0; 6147 te[ 11 ] = 0; 6148 6149 // last column 6150 te[ 12 ] = 0; 6151 te[ 13 ] = 0; 6152 te[ 14 ] = 0; 6153 te[ 15 ] = 1; 6154 6155 return this; 6156 6157 } 6158 6159 makeRotationFromQuaternion( q ) { 6160 6161 return this.compose( _zero, q, _one ); 6162 6163 } 6164 6165 lookAt( eye, target, up ) { 6166 6167 const te = this.elements; 6168 6169 _z.subVectors( eye, target ); 6170 6171 if ( _z.lengthSq() === 0 ) { 6172 6173 // eye and target are in the same position 6174 6175 _z.z = 1; 6176 6177 } 6178 6179 _z.normalize(); 6180 _x.crossVectors( up, _z ); 6181 6182 if ( _x.lengthSq() === 0 ) { 6183 6184 // up and z are parallel 6185 6186 if ( Math.abs( up.z ) === 1 ) { 6187 6188 _z.x += 0.0001; 6189 6190 } else { 6191 6192 _z.z += 0.0001; 6193 6194 } 6195 6196 _z.normalize(); 6197 _x.crossVectors( up, _z ); 6198 6199 } 6200 6201 _x.normalize(); 6202 _y.crossVectors( _z, _x ); 6203 6204 te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x; 6205 te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y; 6206 te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z; 6207 6208 return this; 6209 6210 } 6211 6212 multiply( m ) { 6213 6214 return this.multiplyMatrices( this, m ); 6215 6216 } 6217 6218 premultiply( m ) { 6219 6220 return this.multiplyMatrices( m, this ); 6221 6222 } 6223 6224 multiplyMatrices( a, b ) { 6225 6226 const ae = a.elements; 6227 const be = b.elements; 6228 const te = this.elements; 6229 6230 const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; 6231 const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; 6232 const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; 6233 const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; 6234 6235 const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; 6236 const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; 6237 const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; 6238 const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; 6239 6240 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; 6241 te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; 6242 te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; 6243 te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; 6244 6245 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; 6246 te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; 6247 te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; 6248 te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; 6249 6250 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; 6251 te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; 6252 te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; 6253 te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; 6254 6255 te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; 6256 te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; 6257 te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; 6258 te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; 6259 6260 return this; 6261 6262 } 6263 6264 multiplyScalar( s ) { 6265 6266 const te = this.elements; 6267 6268 te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s; 6269 te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s; 6270 te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s; 6271 te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s; 6272 6273 return this; 6274 6275 } 6276 6277 determinant() { 6278 6279 const te = this.elements; 6280 6281 const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; 6282 const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; 6283 const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; 6284 const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; 6285 6286 //TODO: make this more efficient 6287 //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) 6288 6289 return ( 6290 n41 * ( 6291 + n14 * n23 * n32 6292 - n13 * n24 * n32 6293 - n14 * n22 * n33 6294 + n12 * n24 * n33 6295 + n13 * n22 * n34 6296 - n12 * n23 * n34 6297 ) + 6298 n42 * ( 6299 + n11 * n23 * n34 6300 - n11 * n24 * n33 6301 + n14 * n21 * n33 6302 - n13 * n21 * n34 6303 + n13 * n24 * n31 6304 - n14 * n23 * n31 6305 ) + 6306 n43 * ( 6307 + n11 * n24 * n32 6308 - n11 * n22 * n34 6309 - n14 * n21 * n32 6310 + n12 * n21 * n34 6311 + n14 * n22 * n31 6312 - n12 * n24 * n31 6313 ) + 6314 n44 * ( 6315 - n13 * n22 * n31 6316 - n11 * n23 * n32 6317 + n11 * n22 * n33 6318 + n13 * n21 * n32 6319 - n12 * n21 * n33 6320 + n12 * n23 * n31 6321 ) 6322 6323 ); 6324 6325 } 6326 6327 transpose() { 6328 6329 const te = this.elements; 6330 let tmp; 6331 6332 tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp; 6333 tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp; 6334 tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp; 6335 6336 tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp; 6337 tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp; 6338 tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp; 6339 6340 return this; 6341 6342 } 6343 6344 setPosition( x, y, z ) { 6345 6346 const te = this.elements; 6347 6348 if ( x.isVector3 ) { 6349 6350 te[ 12 ] = x.x; 6351 te[ 13 ] = x.y; 6352 te[ 14 ] = x.z; 6353 6354 } else { 6355 6356 te[ 12 ] = x; 6357 te[ 13 ] = y; 6358 te[ 14 ] = z; 6359 6360 } 6361 6362 return this; 6363 6364 } 6365 6366 invert() { 6367 6368 // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm 6369 const te = this.elements, 6370 6371 n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ], 6372 n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ], 6373 n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ], 6374 n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ], 6375 6376 t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44, 6377 t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44, 6378 t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44, 6379 t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; 6380 6381 const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; 6382 6383 if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); 6384 6385 const detInv = 1 / det; 6386 6387 te[ 0 ] = t11 * detInv; 6388 te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv; 6389 te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv; 6390 te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv; 6391 6392 te[ 4 ] = t12 * detInv; 6393 te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv; 6394 te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv; 6395 te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv; 6396 6397 te[ 8 ] = t13 * detInv; 6398 te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv; 6399 te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv; 6400 te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv; 6401 6402 te[ 12 ] = t14 * detInv; 6403 te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv; 6404 te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv; 6405 te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv; 6406 6407 return this; 6408 6409 } 6410 6411 scale( v ) { 6412 6413 const te = this.elements; 6414 const x = v.x, y = v.y, z = v.z; 6415 6416 te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; 6417 te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; 6418 te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; 6419 te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; 6420 6421 return this; 6422 6423 } 6424 6425 getMaxScaleOnAxis() { 6426 6427 const te = this.elements; 6428 6429 6430 const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; 6431 const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; 6432 const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; 6433 6434 return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); 6435 6436 } 6437 6438 makeTranslation( x, y, z ) { 6439 6440 if ( x.isVector3 ) { 6441 6442 this.set( 6443 6444 1, 0, 0, x.x, 6445 0, 1, 0, x.y, 6446 0, 0, 1, x.z, 6447 0, 0, 0, 1 6448 6449 ); 6450 6451 } else { 6452 6453 this.set( 6454 6455 1, 0, 0, x, 6456 0, 1, 0, y, 6457 0, 0, 1, z, 6458 0, 0, 0, 1 6459 6460 ); 6461 6462 } 6463 6464 return this; 6465 6466 } 6467 6468 makeRotationX( theta ) { 6469 6470 const c = Math.cos( theta ), s = Math.sin( theta ); 6471 6472 this.set( 6473 6474 1, 0, 0, 0, 6475 0, c, - s, 0, 6476 0, s, c, 0, 6477 0, 0, 0, 1 6478 6479 ); 6480 6481 return this; 6482 6483 } 6484 6485 makeRotationY( theta ) { 6486 6487 const c = Math.cos( theta ), s = Math.sin( theta ); 6488 6489 this.set( 6490 6491 c, 0, s, 0, 6492 0, 1, 0, 0, 6493 - s, 0, c, 0, 6494 0, 0, 0, 1 6495 6496 ); 6497 6498 return this; 6499 6500 } 6501 6502 makeRotationZ( theta ) { 6503 6504 const c = Math.cos( theta ), s = Math.sin( theta ); 6505 6506 this.set( 6507 6508 c, - s, 0, 0, 6509 s, c, 0, 0, 6510 0, 0, 1, 0, 6511 0, 0, 0, 1 6512 6513 ); 6514 6515 return this; 6516 6517 } 6518 6519 makeRotationAxis( axis, angle ) { 6520 6521 // Based on http://www.gamedev.net/reference/articles/article1199.asp 6522 6523 const c = Math.cos( angle ); 6524 const s = Math.sin( angle ); 6525 const t = 1 - c; 6526 const x = axis.x, y = axis.y, z = axis.z; 6527 const tx = t * x, ty = t * y; 6528 6529 this.set( 6530 6531 tx * x + c, tx * y - s * z, tx * z + s * y, 0, 6532 tx * y + s * z, ty * y + c, ty * z - s * x, 0, 6533 tx * z - s * y, ty * z + s * x, t * z * z + c, 0, 6534 0, 0, 0, 1 6535 6536 ); 6537 6538 return this; 6539 6540 } 6541 6542 makeScale( x, y, z ) { 6543 6544 this.set( 6545 6546 x, 0, 0, 0, 6547 0, y, 0, 0, 6548 0, 0, z, 0, 6549 0, 0, 0, 1 6550 6551 ); 6552 6553 return this; 6554 6555 } 6556 6557 makeShear( xy, xz, yx, yz, zx, zy ) { 6558 6559 this.set( 6560 6561 1, yx, zx, 0, 6562 xy, 1, zy, 0, 6563 xz, yz, 1, 0, 6564 0, 0, 0, 1 6565 6566 ); 6567 6568 return this; 6569 6570 } 6571 6572 compose( position, quaternion, scale ) { 6573 6574 const te = this.elements; 6575 6576 const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w; 6577 const x2 = x + x, y2 = y + y, z2 = z + z; 6578 const xx = x * x2, xy = x * y2, xz = x * z2; 6579 const yy = y * y2, yz = y * z2, zz = z * z2; 6580 const wx = w * x2, wy = w * y2, wz = w * z2; 6581 6582 const sx = scale.x, sy = scale.y, sz = scale.z; 6583 6584 te[ 0 ] = ( 1 - ( yy + zz ) ) * sx; 6585 te[ 1 ] = ( xy + wz ) * sx; 6586 te[ 2 ] = ( xz - wy ) * sx; 6587 te[ 3 ] = 0; 6588 6589 te[ 4 ] = ( xy - wz ) * sy; 6590 te[ 5 ] = ( 1 - ( xx + zz ) ) * sy; 6591 te[ 6 ] = ( yz + wx ) * sy; 6592 te[ 7 ] = 0; 6593 6594 te[ 8 ] = ( xz + wy ) * sz; 6595 te[ 9 ] = ( yz - wx ) * sz; 6596 te[ 10 ] = ( 1 - ( xx + yy ) ) * sz; 6597 te[ 11 ] = 0; 6598 6599 te[ 12 ] = position.x; 6600 te[ 13 ] = position.y; 6601 te[ 14 ] = position.z; 6602 te[ 15 ] = 1; 6603 6604 return this; 6605 6606 } 6607 6608 decompose( position, quaternion, scale ) { 6609 6610 const te = this.elements; 6611 6612 let sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); 6613 const sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); 6614 const sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); 6615 6616 // if determine is negative, we need to invert one scale 6617 const det = this.determinant(); 6618 if ( det < 0 ) sx = - sx; 6619 6620 position.x = te[ 12 ]; 6621 position.y = te[ 13 ]; 6622 position.z = te[ 14 ]; 6623 6624 // scale the rotation part 6625 _m1$2.copy( this ); 6626 6627 const invSX = 1 / sx; 6628 const invSY = 1 / sy; 6629 const invSZ = 1 / sz; 6630 6631 _m1$2.elements[ 0 ] *= invSX; 6632 _m1$2.elements[ 1 ] *= invSX; 6633 _m1$2.elements[ 2 ] *= invSX; 6634 6635 _m1$2.elements[ 4 ] *= invSY; 6636 _m1$2.elements[ 5 ] *= invSY; 6637 _m1$2.elements[ 6 ] *= invSY; 6638 6639 _m1$2.elements[ 8 ] *= invSZ; 6640 _m1$2.elements[ 9 ] *= invSZ; 6641 _m1$2.elements[ 10 ] *= invSZ; 6642 6643 quaternion.setFromRotationMatrix( _m1$2 ); 6644 6645 scale.x = sx; 6646 scale.y = sy; 6647 scale.z = sz; 6648 6649 return this; 6650 6651 } 6652 6653 makePerspective( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) { 6654 6655 const te = this.elements; 6656 const x = 2 * near / ( right - left ); 6657 const y = 2 * near / ( top - bottom ); 6658 6659 const a = ( right + left ) / ( right - left ); 6660 const b = ( top + bottom ) / ( top - bottom ); 6661 6662 let c, d; 6663 6664 if ( coordinateSystem === WebGLCoordinateSystem ) { 6665 6666 c = - ( far + near ) / ( far - near ); 6667 d = ( - 2 * far * near ) / ( far - near ); 6668 6669 } else if ( coordinateSystem === WebGPUCoordinateSystem ) { 6670 6671 c = - far / ( far - near ); 6672 d = ( - far * near ) / ( far - near ); 6673 6674 } else { 6675 6676 throw new Error( 'THREE.Matrix4.makePerspective(): Invalid coordinate system: ' + coordinateSystem ); 6677 6678 } 6679 6680 te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; 6681 te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; 6682 te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; 6683 te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0; 6684 6685 return this; 6686 6687 } 6688 6689 makeOrthographic( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) { 6690 6691 const te = this.elements; 6692 const w = 1.0 / ( right - left ); 6693 const h = 1.0 / ( top - bottom ); 6694 const p = 1.0 / ( far - near ); 6695 6696 const x = ( right + left ) * w; 6697 const y = ( top + bottom ) * h; 6698 6699 let z, zInv; 6700 6701 if ( coordinateSystem === WebGLCoordinateSystem ) { 6702 6703 z = ( far + near ) * p; 6704 zInv = - 2 * p; 6705 6706 } else if ( coordinateSystem === WebGPUCoordinateSystem ) { 6707 6708 z = near * p; 6709 zInv = - 1 * p; 6710 6711 } else { 6712 6713 throw new Error( 'THREE.Matrix4.makeOrthographic(): Invalid coordinate system: ' + coordinateSystem ); 6714 6715 } 6716 6717 te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x; 6718 te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y; 6719 te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = zInv; te[ 14 ] = - z; 6720 te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; 6721 6722 return this; 6723 6724 } 6725 6726 equals( matrix ) { 6727 6728 const te = this.elements; 6729 const me = matrix.elements; 6730 6731 for ( let i = 0; i < 16; i ++ ) { 6732 6733 if ( te[ i ] !== me[ i ] ) return false; 6734 6735 } 6736 6737 return true; 6738 6739 } 6740 6741 fromArray( array, offset = 0 ) { 6742 6743 for ( let i = 0; i < 16; i ++ ) { 6744 6745 this.elements[ i ] = array[ i + offset ]; 6746 6747 } 6748 6749 return this; 6750 6751 } 6752 6753 toArray( array = [], offset = 0 ) { 6754 6755 const te = this.elements; 6756 6757 array[ offset ] = te[ 0 ]; 6758 array[ offset + 1 ] = te[ 1 ]; 6759 array[ offset + 2 ] = te[ 2 ]; 6760 array[ offset + 3 ] = te[ 3 ]; 6761 6762 array[ offset + 4 ] = te[ 4 ]; 6763 array[ offset + 5 ] = te[ 5 ]; 6764 array[ offset + 6 ] = te[ 6 ]; 6765 array[ offset + 7 ] = te[ 7 ]; 6766 6767 array[ offset + 8 ] = te[ 8 ]; 6768 array[ offset + 9 ] = te[ 9 ]; 6769 array[ offset + 10 ] = te[ 10 ]; 6770 array[ offset + 11 ] = te[ 11 ]; 6771 6772 array[ offset + 12 ] = te[ 12 ]; 6773 array[ offset + 13 ] = te[ 13 ]; 6774 array[ offset + 14 ] = te[ 14 ]; 6775 array[ offset + 15 ] = te[ 15 ]; 6776 6777 return array; 6778 6779 } 6780 6781} 6782 6783const _v1$5 = /*@__PURE__*/ new Vector3(); 6784const _m1$2 = /*@__PURE__*/ new Matrix4(); 6785const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 ); 6786const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 ); 6787const _x = /*@__PURE__*/ new Vector3(); 6788const _y = /*@__PURE__*/ new Vector3(); 6789const _z = /*@__PURE__*/ new Vector3(); 6790 6791const _matrix$1 = /*@__PURE__*/ new Matrix4(); 6792const _quaternion$3 = /*@__PURE__*/ new Quaternion(); 6793 6794class Euler { 6795 6796 constructor( x = 0, y = 0, z = 0, order = Euler.DEFAULT_ORDER ) { 6797 6798 this.isEuler = true; 6799 6800 this._x = x; 6801 this._y = y; 6802 this._z = z; 6803 this._order = order; 6804 6805 } 6806 6807 get x() { 6808 6809 return this._x; 6810 6811 } 6812 6813 set x( value ) { 6814 6815 this._x = value; 6816 this._onChangeCallback(); 6817 6818 } 6819 6820 get y() { 6821 6822 return this._y; 6823 6824 } 6825 6826 set y( value ) { 6827 6828 this._y = value; 6829 this._onChangeCallback(); 6830 6831 } 6832 6833 get z() { 6834 6835 return this._z; 6836 6837 } 6838 6839 set z( value ) { 6840 6841 this._z = value; 6842 this._onChangeCallback(); 6843 6844 } 6845 6846 get order() { 6847 6848 return this._order; 6849 6850 } 6851 6852 set order( value ) { 6853 6854 this._order = value; 6855 this._onChangeCallback(); 6856 6857 } 6858 6859 set( x, y, z, order = this._order ) { 6860 6861 this._x = x; 6862 this._y = y; 6863 this._z = z; 6864 this._order = order; 6865 6866 this._onChangeCallback(); 6867 6868 return this; 6869 6870 } 6871 6872 clone() { 6873 6874 return new this.constructor( this._x, this._y, this._z, this._order ); 6875 6876 } 6877 6878 copy( euler ) { 6879 6880 this._x = euler._x; 6881 this._y = euler._y; 6882 this._z = euler._z; 6883 this._order = euler._order; 6884 6885 this._onChangeCallback(); 6886 6887 return this; 6888 6889 } 6890 6891 setFromRotationMatrix( m, order = this._order, update = true ) { 6892 6893 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 6894 6895 const te = m.elements; 6896 const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ]; 6897 const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ]; 6898 const m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; 6899 6900 switch ( order ) { 6901 6902 case 'XYZ': 6903 6904 this._y = Math.asin( clamp( m13, - 1, 1 ) ); 6905 6906 if ( Math.abs( m13 ) < 0.9999999 ) { 6907 6908 this._x = Math.atan2( - m23, m33 ); 6909 this._z = Math.atan2( - m12, m11 ); 6910 6911 } else { 6912 6913 this._x = Math.atan2( m32, m22 ); 6914 this._z = 0; 6915 6916 } 6917 6918 break; 6919 6920 case 'YXZ': 6921 6922 this._x = Math.asin( - clamp( m23, - 1, 1 ) ); 6923 6924 if ( Math.abs( m23 ) < 0.9999999 ) { 6925 6926 this._y = Math.atan2( m13, m33 ); 6927 this._z = Math.atan2( m21, m22 ); 6928 6929 } else { 6930 6931 this._y = Math.atan2( - m31, m11 ); 6932 this._z = 0; 6933 6934 } 6935 6936 break; 6937 6938 case 'ZXY': 6939 6940 this._x = Math.asin( clamp( m32, - 1, 1 ) ); 6941 6942 if ( Math.abs( m32 ) < 0.9999999 ) { 6943 6944 this._y = Math.atan2( - m31, m33 ); 6945 this._z = Math.atan2( - m12, m22 ); 6946 6947 } else { 6948 6949 this._y = 0; 6950 this._z = Math.atan2( m21, m11 ); 6951 6952 } 6953 6954 break; 6955 6956 case 'ZYX': 6957 6958 this._y = Math.asin( - clamp( m31, - 1, 1 ) ); 6959 6960 if ( Math.abs( m31 ) < 0.9999999 ) { 6961 6962 this._x = Math.atan2( m32, m33 ); 6963 this._z = Math.atan2( m21, m11 ); 6964 6965 } else { 6966 6967 this._x = 0; 6968 this._z = Math.atan2( - m12, m22 ); 6969 6970 } 6971 6972 break; 6973 6974 case 'YZX': 6975 6976 this._z = Math.asin( clamp( m21, - 1, 1 ) ); 6977 6978 if ( Math.abs( m21 ) < 0.9999999 ) { 6979 6980 this._x = Math.atan2( - m23, m22 ); 6981 this._y = Math.atan2( - m31, m11 ); 6982 6983 } else { 6984 6985 this._x = 0; 6986 this._y = Math.atan2( m13, m33 ); 6987 6988 } 6989 6990 break; 6991 6992 case 'XZY': 6993 6994 this._z = Math.asin( - clamp( m12, - 1, 1 ) ); 6995 6996 if ( Math.abs( m12 ) < 0.9999999 ) { 6997 6998 this._x = Math.atan2( m32, m22 ); 6999 this._y = Math.atan2( m13, m11 ); 7000 7001 } else { 7002 7003 this._x = Math.atan2( - m23, m33 ); 7004 this._y = 0; 7005 7006 } 7007 7008 break; 7009 7010 default: 7011 7012 console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order ); 7013 7014 } 7015 7016 this._order = order; 7017 7018 if ( update === true ) this._onChangeCallback(); 7019 7020 return this; 7021 7022 } 7023 7024 setFromQuaternion( q, order, update ) { 7025 7026 _matrix$1.makeRotationFromQuaternion( q ); 7027 7028 return this.setFromRotationMatrix( _matrix$1, order, update ); 7029 7030 } 7031 7032 setFromVector3( v, order = this._order ) { 7033 7034 return this.set( v.x, v.y, v.z, order ); 7035 7036 } 7037 7038 reorder( newOrder ) { 7039 7040 // WARNING: this discards revolution information -bhouston 7041 7042 _quaternion$3.setFromEuler( this ); 7043 7044 return this.setFromQuaternion( _quaternion$3, newOrder ); 7045 7046 } 7047 7048 equals( euler ) { 7049 7050 return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); 7051 7052 } 7053 7054 fromArray( array ) { 7055 7056 this._x = array[ 0 ]; 7057 this._y = array[ 1 ]; 7058 this._z = array[ 2 ]; 7059 if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; 7060 7061 this._onChangeCallback(); 7062 7063 return this; 7064 7065 } 7066 7067 toArray( array = [], offset = 0 ) { 7068 7069 array[ offset ] = this._x; 7070 array[ offset + 1 ] = this._y; 7071 array[ offset + 2 ] = this._z; 7072 array[ offset + 3 ] = this._order; 7073 7074 return array; 7075 7076 } 7077 7078 _onChange( callback ) { 7079 7080 this._onChangeCallback = callback; 7081 7082 return this; 7083 7084 } 7085 7086 _onChangeCallback() {} 7087 7088 *[ Symbol.iterator ]() { 7089 7090 yield this._x; 7091 yield this._y; 7092 yield this._z; 7093 yield this._order; 7094 7095 } 7096 7097} 7098 7099Euler.DEFAULT_ORDER = 'XYZ'; 7100 7101class Layers { 7102 7103 constructor() { 7104 7105 this.mask = 1 | 0; 7106 7107 } 7108 7109 set( channel ) { 7110 7111 this.mask = ( 1 << channel | 0 ) >>> 0; 7112 7113 } 7114 7115 enable( channel ) { 7116 7117 this.mask |= 1 << channel | 0; 7118 7119 } 7120 7121 enableAll() { 7122 7123 this.mask = 0xffffffff | 0; 7124 7125 } 7126 7127 toggle( channel ) { 7128 7129 this.mask ^= 1 << channel | 0; 7130 7131 } 7132 7133 disable( channel ) { 7134 7135 this.mask &= ~ ( 1 << channel | 0 ); 7136 7137 } 7138 7139 disableAll() { 7140 7141 this.mask = 0; 7142 7143 } 7144 7145 test( layers ) { 7146 7147 return ( this.mask & layers.mask ) !== 0; 7148 7149 } 7150 7151 isEnabled( channel ) { 7152 7153 return ( this.mask & ( 1 << channel | 0 ) ) !== 0; 7154 7155 } 7156 7157} 7158 7159let _object3DId = 0; 7160 7161const _v1$4 = /*@__PURE__*/ new Vector3(); 7162const _q1 = /*@__PURE__*/ new Quaternion(); 7163const _m1$1 = /*@__PURE__*/ new Matrix4(); 7164const _target = /*@__PURE__*/ new Vector3(); 7165 7166const _position$3 = /*@__PURE__*/ new Vector3(); 7167const _scale$2 = /*@__PURE__*/ new Vector3(); 7168const _quaternion$2 = /*@__PURE__*/ new Quaternion(); 7169 7170const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 ); 7171const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 ); 7172const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 ); 7173 7174const _addedEvent = { type: 'added' }; 7175const _removedEvent = { type: 'removed' }; 7176 7177class Object3D extends EventDispatcher { 7178 7179 constructor() { 7180 7181 super(); 7182 7183 this.isObject3D = true; 7184 7185 Object.defineProperty( this, 'id', { value: _object3DId ++ } ); 7186 7187 this.uuid = generateUUID(); 7188 7189 this.name = ''; 7190 this.type = 'Object3D'; 7191 7192 this.parent = null; 7193 this.children = []; 7194 7195 this.up = Object3D.DEFAULT_UP.clone(); 7196 7197 const position = new Vector3(); 7198 const rotation = new Euler(); 7199 const quaternion = new Quaternion(); 7200 const scale = new Vector3( 1, 1, 1 ); 7201 7202 function onRotationChange() { 7203 7204 quaternion.setFromEuler( rotation, false ); 7205 7206 } 7207 7208 function onQuaternionChange() { 7209 7210 rotation.setFromQuaternion( quaternion, undefined, false ); 7211 7212 } 7213 7214 rotation._onChange( onRotationChange ); 7215 quaternion._onChange( onQuaternionChange ); 7216 7217 Object.defineProperties( this, { 7218 position: { 7219 configurable: true, 7220 enumerable: true, 7221 value: position 7222 }, 7223 rotation: { 7224 configurable: true, 7225 enumerable: true, 7226 value: rotation 7227 }, 7228 quaternion: { 7229 configurable: true, 7230 enumerable: true, 7231 value: quaternion 7232 }, 7233 scale: { 7234 configurable: true, 7235 enumerable: true, 7236 value: scale 7237 }, 7238 modelViewMatrix: { 7239 value: new Matrix4() 7240 }, 7241 normalMatrix: { 7242 value: new Matrix3() 7243 } 7244 } ); 7245 7246 this.matrix = new Matrix4(); 7247 this.matrixWorld = new Matrix4(); 7248 7249 this.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE; 7250 7251 this.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE; // checked by the renderer 7252 this.matrixWorldNeedsUpdate = false; 7253 7254 this.layers = new Layers(); 7255 this.visible = true; 7256 7257 this.castShadow = false; 7258 this.receiveShadow = false; 7259 7260 this.frustumCulled = true; 7261 this.renderOrder = 0; 7262 7263 this.animations = []; 7264 7265 this.userData = {}; 7266 7267 } 7268 7269 onBeforeShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {} 7270 7271 onAfterShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {} 7272 7273 onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {} 7274 7275 onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {} 7276 7277 applyMatrix4( matrix ) { 7278 7279 if ( this.matrixAutoUpdate ) this.updateMatrix(); 7280 7281 this.matrix.premultiply( matrix ); 7282 7283 this.matrix.decompose( this.position, this.quaternion, this.scale ); 7284 7285 } 7286 7287 applyQuaternion( q ) { 7288 7289 this.quaternion.premultiply( q ); 7290 7291 return this; 7292 7293 } 7294 7295 setRotationFromAxisAngle( axis, angle ) { 7296 7297 // assumes axis is normalized 7298 7299 this.quaternion.setFromAxisAngle( axis, angle ); 7300 7301 } 7302 7303 setRotationFromEuler( euler ) { 7304 7305 this.quaternion.setFromEuler( euler, true ); 7306 7307 } 7308 7309 setRotationFromMatrix( m ) { 7310 7311 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 7312 7313 this.quaternion.setFromRotationMatrix( m ); 7314 7315 } 7316 7317 setRotationFromQuaternion( q ) { 7318 7319 // assumes q is normalized 7320 7321 this.quaternion.copy( q ); 7322 7323 7324 } 7325 7326 rotateOnAxis( axis, angle ) { 7327 7328 // rotate object on axis in object space 7329 // axis is assumed to be normalized 7330 7331 _q1.setFromAxisAngle( axis, angle ); 7332 7333 this.quaternion.multiply( _q1 ); 7334 7335 return this; 7336 7337 } 7338 7339 rotateOnWorldAxis( axis, angle ) { 7340 7341 // rotate object on axis in world space 7342 // axis is assumed to be normalized 7343 // method assumes no rotated parent 7344 7345 _q1.setFromAxisAngle( axis, angle ); 7346 7347 this.quaternion.premultiply( _q1 ); 7348 7349 return this; 7350 7351 } 7352 7353 rotateX( angle ) { 7354 7355 return this.rotateOnAxis( _xAxis, angle ); 7356 7357 } 7358 7359 rotateY( angle ) { 7360 7361 return this.rotateOnAxis( _yAxis, angle ); 7362 7363 } 7364 7365 rotateZ( angle ) { 7366 7367 return this.rotateOnAxis( _zAxis, angle ); 7368 7369 } 7370 7371 translateOnAxis( axis, distance ) { 7372 7373 // translate object by distance along axis in object space 7374 // axis is assumed to be normalized 7375 7376 _v1$4.copy( axis ).applyQuaternion( this.quaternion ); 7377 7378 this.position.add( _v1$4.multiplyScalar( distance ) ); 7379 7380 return this; 7381 7382 } 7383 7384 translateX( distance ) { 7385 7386 return this.translateOnAxis( _xAxis, distance ); 7387 7388 } 7389 7390 translateY( distance ) { 7391 7392 return this.translateOnAxis( _yAxis, distance ); 7393 7394 } 7395 7396 translateZ( distance ) { 7397 7398 return this.translateOnAxis( _zAxis, distance ); 7399 7400 } 7401 7402 localToWorld( vector ) { 7403 7404 this.updateWorldMatrix( true, false ); 7405 7406 return vector.applyMatrix4( this.matrixWorld ); 7407 7408 } 7409 7410 worldToLocal( vector ) { 7411 7412 this.updateWorldMatrix( true, false ); 7413 7414 return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() ); 7415 7416 } 7417 7418 lookAt( x, y, z ) { 7419 7420 // This method does not support objects having non-uniformly-scaled parent(s) 7421 7422 if ( x.isVector3 ) { 7423 7424 _target.copy( x ); 7425 7426 } else { 7427 7428 _target.set( x, y, z ); 7429 7430 } 7431 7432 const parent = this.parent; 7433 7434 this.updateWorldMatrix( true, false ); 7435 7436 _position$3.setFromMatrixPosition( this.matrixWorld ); 7437 7438 if ( this.isCamera || this.isLight ) { 7439 7440 _m1$1.lookAt( _position$3, _target, this.up ); 7441 7442 } else { 7443 7444 _m1$1.lookAt( _target, _position$3, this.up ); 7445 7446 } 7447 7448 this.quaternion.setFromRotationMatrix( _m1$1 ); 7449 7450 if ( parent ) { 7451 7452 _m1$1.extractRotation( parent.matrixWorld ); 7453 _q1.setFromRotationMatrix( _m1$1 ); 7454 this.quaternion.premultiply( _q1.invert() ); 7455 7456 } 7457 7458 } 7459 7460 add( object ) { 7461 7462 if ( arguments.length > 1 ) { 7463 7464 for ( let i = 0; i < arguments.length; i ++ ) { 7465 7466 this.add( arguments[ i ] ); 7467 7468 } 7469 7470 return this; 7471 7472 } 7473 7474 if ( object === this ) { 7475 7476 console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object ); 7477 return this; 7478 7479 } 7480 7481 if ( object && object.isObject3D ) { 7482 7483 if ( object.parent !== null ) { 7484 7485 object.parent.remove( object ); 7486 7487 } 7488 7489 object.parent = this; 7490 this.children.push( object ); 7491 7492 object.dispatchEvent( _addedEvent ); 7493 7494 } else { 7495 7496 console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object ); 7497 7498 } 7499 7500 return this; 7501 7502 } 7503 7504 remove( object ) { 7505 7506 if ( arguments.length > 1 ) { 7507 7508 for ( let i = 0; i < arguments.length; i ++ ) { 7509 7510 this.remove( arguments[ i ] ); 7511 7512 } 7513 7514 return this; 7515 7516 } 7517 7518 const index = this.children.indexOf( object ); 7519 7520 if ( index !== - 1 ) { 7521 7522 object.parent = null; 7523 this.children.splice( index, 1 ); 7524 7525 object.dispatchEvent( _removedEvent ); 7526 7527 } 7528 7529 return this; 7530 7531 } 7532 7533 removeFromParent() { 7534 7535 const parent = this.parent; 7536 7537 if ( parent !== null ) { 7538 7539 parent.remove( this ); 7540 7541 } 7542 7543 return this; 7544 7545 } 7546 7547 clear() { 7548 7549 return this.remove( ... this.children ); 7550 7551 } 7552 7553 attach( object ) { 7554 7555 // adds object as a child of this, while maintaining the object's world transform 7556 7557 // Note: This method does not support scene graphs having non-uniformly-scaled nodes(s) 7558 7559 this.updateWorldMatrix( true, false ); 7560 7561 _m1$1.copy( this.matrixWorld ).invert(); 7562 7563 if ( object.parent !== null ) { 7564 7565 object.parent.updateWorldMatrix( true, false ); 7566 7567 _m1$1.multiply( object.parent.matrixWorld ); 7568 7569 } 7570 7571 object.applyMatrix4( _m1$1 ); 7572 7573 this.add( object ); 7574 7575 object.updateWorldMatrix( false, true ); 7576 7577 return this; 7578 7579 } 7580 7581 getObjectById( id ) { 7582 7583 return this.getObjectByProperty( 'id', id ); 7584 7585 } 7586 7587 getObjectByName( name ) { 7588 7589 return this.getObjectByProperty( 'name', name ); 7590 7591 } 7592 7593 getObjectByProperty( name, value ) { 7594 7595 if ( this[ name ] === value ) return this; 7596 7597 for ( let i = 0, l = this.children.length; i < l; i ++ ) { 7598 7599 const child = this.children[ i ]; 7600 const object = child.getObjectByProperty( name, value ); 7601 7602 if ( object !== undefined ) { 7603 7604 return object; 7605 7606 } 7607 7608 } 7609 7610 return undefined; 7611 7612 } 7613 7614 getObjectsByProperty( name, value, result = [] ) { 7615 7616 if ( this[ name ] === value ) result.push( this ); 7617 7618 const children = this.children; 7619 7620 for ( let i = 0, l = children.length; i < l; i ++ ) { 7621 7622 children[ i ].getObjectsByProperty( name, value, result ); 7623 7624 } 7625 7626 return result; 7627 7628 } 7629 7630 getWorldPosition( target ) { 7631 7632 this.updateWorldMatrix( true, false ); 7633 7634 return target.setFromMatrixPosition( this.matrixWorld ); 7635 7636 } 7637 7638 getWorldQuaternion( target ) { 7639 7640 this.updateWorldMatrix( true, false ); 7641 7642 this.matrixWorld.decompose( _position$3, target, _scale$2 ); 7643 7644 return target; 7645 7646 } 7647 7648 getWorldScale( target ) { 7649 7650 this.updateWorldMatrix( true, false ); 7651 7652 this.matrixWorld.decompose( _position$3, _quaternion$2, target ); 7653 7654 return target; 7655 7656 } 7657 7658 getWorldDirection( target ) { 7659 7660 this.updateWorldMatrix( true, false ); 7661 7662 const e = this.matrixWorld.elements; 7663 7664 return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize(); 7665 7666 } 7667 7668 raycast( /* raycaster, intersects */ ) {} 7669 7670 traverse( callback ) { 7671 7672 callback( this ); 7673 7674 const children = this.children; 7675 7676 for ( let i = 0, l = children.length; i < l; i ++ ) { 7677 7678 children[ i ].traverse( callback ); 7679 7680 } 7681 7682 } 7683 7684 traverseVisible( callback ) { 7685 7686 if ( this.visible === false ) return; 7687 7688 callback( this ); 7689 7690 const children = this.children; 7691 7692 for ( let i = 0, l = children.length; i < l; i ++ ) { 7693 7694 children[ i ].traverseVisible( callback ); 7695 7696 } 7697 7698 } 7699 7700 traverseAncestors( callback ) { 7701 7702 const parent = this.parent; 7703 7704 if ( parent !== null ) { 7705 7706 callback( parent ); 7707 7708 parent.traverseAncestors( callback ); 7709 7710 } 7711 7712 } 7713 7714 updateMatrix() { 7715 7716 this.matrix.compose( this.position, this.quaternion, this.scale ); 7717 7718 this.matrixWorldNeedsUpdate = true; 7719 7720 } 7721 7722 updateMatrixWorld( force ) { 7723 7724 if ( this.matrixAutoUpdate ) this.updateMatrix(); 7725 7726 if ( this.matrixWorldNeedsUpdate || force ) { 7727 7728 if ( this.parent === null ) { 7729 7730 this.matrixWorld.copy( this.matrix ); 7731 7732 } else { 7733 7734 this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); 7735 7736 } 7737 7738 this.matrixWorldNeedsUpdate = false; 7739 7740 force = true; 7741 7742 } 7743 7744 // update children 7745 7746 const children = this.children; 7747 7748 for ( let i = 0, l = children.length; i < l; i ++ ) { 7749 7750 const child = children[ i ]; 7751 7752 if ( child.matrixWorldAutoUpdate === true || force === true ) { 7753 7754 child.updateMatrixWorld( force ); 7755 7756 } 7757 7758 } 7759 7760 } 7761 7762 updateWorldMatrix( updateParents, updateChildren ) { 7763 7764 const parent = this.parent; 7765 7766 if ( updateParents === true && parent !== null && parent.matrixWorldAutoUpdate === true ) { 7767 7768 parent.updateWorldMatrix( true, false ); 7769 7770 } 7771 7772 if ( this.matrixAutoUpdate ) this.updateMatrix(); 7773 7774 if ( this.parent === null ) { 7775 7776 this.matrixWorld.copy( this.matrix ); 7777 7778 } else { 7779 7780 this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); 7781 7782 } 7783 7784 // update children 7785 7786 if ( updateChildren === true ) { 7787 7788 const children = this.children; 7789 7790 for ( let i = 0, l = children.length; i < l; i ++ ) { 7791 7792 const child = children[ i ]; 7793 7794 if ( child.matrixWorldAutoUpdate === true ) { 7795 7796 child.updateWorldMatrix( false, true ); 7797 7798 } 7799 7800 } 7801 7802 } 7803 7804 } 7805 7806 toJSON( meta ) { 7807 7808 // meta is a string when called from JSON.stringify 7809 const isRootObject = ( meta === undefined || typeof meta === 'string' ); 7810 7811 const output = {}; 7812 7813 // meta is a hash used to collect geometries, materials. 7814 // not providing it implies that this is the root object 7815 // being serialized. 7816 if ( isRootObject ) { 7817 7818 // initialize meta obj 7819 meta = { 7820 geometries: {}, 7821 materials: {}, 7822 textures: {}, 7823 images: {}, 7824 shapes: {}, 7825 skeletons: {}, 7826 animations: {}, 7827 nodes: {} 7828 }; 7829 7830 output.metadata = { 7831 version: 4.6, 7832 type: 'Object', 7833 generator: 'Object3D.toJSON' 7834 }; 7835 7836 } 7837 7838 // standard Object3D serialization 7839 7840 const object = {}; 7841 7842 object.uuid = this.uuid; 7843 object.type = this.type; 7844 7845 if ( this.name !== '' ) object.name = this.name; 7846 if ( this.castShadow === true ) object.castShadow = true; 7847 if ( this.receiveShadow === true ) object.receiveShadow = true; 7848 if ( this.visible === false ) object.visible = false; 7849 if ( this.frustumCulled === false ) object.frustumCulled = false; 7850 if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder; 7851 if ( Object.keys( this.userData ).length > 0 ) object.userData = this.userData; 7852 7853 object.layers = this.layers.mask; 7854 object.matrix = this.matrix.toArray(); 7855 object.up = this.up.toArray(); 7856 7857 if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false; 7858 7859 // object specific properties 7860 7861 if ( this.isInstancedMesh ) { 7862 7863 object.type = 'InstancedMesh'; 7864 object.count = this.count; 7865 object.instanceMatrix = this.instanceMatrix.toJSON(); 7866 if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON(); 7867 7868 } 7869 7870 if ( this.isBatchedMesh ) { 7871 7872 object.type = 'BatchedMesh'; 7873 object.perObjectFrustumCulled = this.perObjectFrustumCulled; 7874 object.sortObjects = this.sortObjects; 7875 7876 object.drawRanges = this._drawRanges; 7877 object.reservedRanges = this._reservedRanges; 7878 7879 object.visibility = this._visibility; 7880 object.active = this._active; 7881 object.bounds = this._bounds.map( bound => ( { 7882 boxInitialized: bound.boxInitialized, 7883 boxMin: bound.box.min.toArray(), 7884 boxMax: bound.box.max.toArray(), 7885 7886 sphereInitialized: bound.sphereInitialized, 7887 sphereRadius: bound.sphere.radius, 7888 sphereCenter: bound.sphere.center.toArray() 7889 } ) ); 7890 7891 object.maxGeometryCount = this._maxGeometryCount; 7892 object.maxVertexCount = this._maxVertexCount; 7893 object.maxIndexCount = this._maxIndexCount; 7894 7895 object.geometryInitialized = this._geometryInitialized; 7896 object.geometryCount = this._geometryCount; 7897 7898 object.matricesTexture = this._matricesTexture.toJSON( meta ); 7899 7900 if ( this.boundingSphere !== null ) { 7901 7902 object.boundingSphere = { 7903 center: object.boundingSphere.center.toArray(), 7904 radius: object.boundingSphere.radius 7905 }; 7906 7907 } 7908 7909 if ( this.boundingBox !== null ) { 7910 7911 object.boundingBox = { 7912 min: object.boundingBox.min.toArray(), 7913 max: object.boundingBox.max.toArray() 7914 }; 7915 7916 } 7917 7918 } 7919 7920 // 7921 7922 function serialize( library, element ) { 7923 7924 if ( library[ element.uuid ] === undefined ) { 7925 7926 library[ element.uuid ] = element.toJSON( meta ); 7927 7928 } 7929 7930 return element.uuid; 7931 7932 } 7933 7934 if ( this.isScene ) { 7935 7936 if ( this.background ) { 7937 7938 if ( this.background.isColor ) { 7939 7940 object.background = this.background.toJSON(); 7941 7942 } else if ( this.background.isTexture ) { 7943 7944 object.background = this.background.toJSON( meta ).uuid; 7945 7946 } 7947 7948 } 7949 7950 if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) { 7951 7952 object.environment = this.environment.toJSON( meta ).uuid; 7953 7954 } 7955 7956 } else if ( this.isMesh || this.isLine || this.isPoints ) { 7957 7958 object.geometry = serialize( meta.geometries, this.geometry ); 7959 7960 const parameters = this.geometry.parameters; 7961 7962 if ( parameters !== undefined && parameters.shapes !== undefined ) { 7963 7964 const shapes = parameters.shapes; 7965 7966 if ( Array.isArray( shapes ) ) { 7967 7968 for ( let i = 0, l = shapes.length; i < l; i ++ ) { 7969 7970 const shape = shapes[ i ]; 7971 7972 serialize( meta.shapes, shape ); 7973 7974 } 7975 7976 } else { 7977 7978 serialize( meta.shapes, shapes ); 7979 7980 } 7981 7982 } 7983 7984 } 7985 7986 if ( this.isSkinnedMesh ) { 7987 7988 object.bindMode = this.bindMode; 7989 object.bindMatrix = this.bindMatrix.toArray(); 7990 7991 if ( this.skeleton !== undefined ) { 7992 7993 serialize( meta.skeletons, this.skeleton ); 7994 7995 object.skeleton = this.skeleton.uuid; 7996 7997 } 7998 7999 } 8000 8001 if ( this.material !== undefined ) { 8002 8003 if ( Array.isArray( this.material ) ) { 8004 8005 const uuids = []; 8006 8007 for ( let i = 0, l = this.material.length; i < l; i ++ ) { 8008 8009 uuids.push( serialize( meta.materials, this.material[ i ] ) ); 8010 8011 } 8012 8013 object.material = uuids; 8014 8015 } else { 8016 8017 object.material = serialize( meta.materials, this.material ); 8018 8019 } 8020 8021 } 8022 8023 // 8024 8025 if ( this.children.length > 0 ) { 8026 8027 object.children = []; 8028 8029 for ( let i = 0; i < this.children.length; i ++ ) { 8030 8031 object.children.push( this.children[ i ].toJSON( meta ).object ); 8032 8033 } 8034 8035 } 8036 8037 // 8038 8039 if ( this.animations.length > 0 ) { 8040 8041 object.animations = []; 8042 8043 for ( let i = 0; i < this.animations.length; i ++ ) { 8044 8045 const animation = this.animations[ i ]; 8046 8047 object.animations.push( serialize( meta.animations, animation ) ); 8048 8049 } 8050 8051 } 8052 8053 if ( isRootObject ) { 8054 8055 const geometries = extractFromCache( meta.geometries ); 8056 const materials = extractFromCache( meta.materials ); 8057 const textures = extractFromCache( meta.textures ); 8058 const images = extractFromCache( meta.images ); 8059 const shapes = extractFromCache( meta.shapes ); 8060 const skeletons = extractFromCache( meta.skeletons ); 8061 const animations = extractFromCache( meta.animations ); 8062 const nodes = extractFromCache( meta.nodes ); 8063 8064 if ( geometries.length > 0 ) output.geometries = geometries; 8065 if ( materials.length > 0 ) output.materials = materials; 8066 if ( textures.length > 0 ) output.textures = textures; 8067 if ( images.length > 0 ) output.images = images; 8068 if ( shapes.length > 0 ) output.shapes = shapes; 8069 if ( skeletons.length > 0 ) output.skeletons = skeletons; 8070 if ( animations.length > 0 ) output.animations = animations; 8071 if ( nodes.length > 0 ) output.nodes = nodes; 8072 8073 } 8074 8075 output.object = object; 8076 8077 return output; 8078 8079 // extract data from the cache hash 8080 // remove metadata on each item 8081 // and return as array 8082 function extractFromCache( cache ) { 8083 8084 const values = []; 8085 for ( const key in cache ) { 8086 8087 const data = cache[ key ]; 8088 delete data.metadata; 8089 values.push( data ); 8090 8091 } 8092 8093 return values; 8094 8095 } 8096 8097 } 8098 8099 clone( recursive ) { 8100 8101 return new this.constructor().copy( this, recursive ); 8102 8103 } 8104 8105 copy( source, recursive = true ) { 8106 8107 this.name = source.name; 8108 8109 this.up.copy( source.up ); 8110 8111 this.position.copy( source.position ); 8112 this.rotation.order = source.rotation.order; 8113 this.quaternion.copy( source.quaternion ); 8114 this.scale.copy( source.scale ); 8115 8116 this.matrix.copy( source.matrix ); 8117 this.matrixWorld.copy( source.matrixWorld ); 8118 8119 this.matrixAutoUpdate = source.matrixAutoUpdate; 8120 8121 this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate; 8122 this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; 8123 8124 this.layers.mask = source.layers.mask; 8125 this.visible = source.visible; 8126 8127 this.castShadow = source.castShadow; 8128 this.receiveShadow = source.receiveShadow; 8129 8130 this.frustumCulled = source.frustumCulled; 8131 this.renderOrder = source.renderOrder; 8132 8133 this.animations = source.animations.slice(); 8134 8135 this.userData = JSON.parse( JSON.stringify( source.userData ) ); 8136 8137 if ( recursive === true ) { 8138 8139 for ( let i = 0; i < source.children.length; i ++ ) { 8140 8141 const child = source.children[ i ]; 8142 this.add( child.clone() ); 8143 8144 } 8145 8146 } 8147 8148 return this; 8149 8150 } 8151 8152} 8153 8154Object3D.DEFAULT_UP = /*@__PURE__*/ new Vector3( 0, 1, 0 ); 8155Object3D.DEFAULT_MATRIX_AUTO_UPDATE = true; 8156Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = true; 8157 8158const _v0$1 = /*@__PURE__*/ new Vector3(); 8159const _v1$3 = /*@__PURE__*/ new Vector3(); 8160const _v2$2 = /*@__PURE__*/ new Vector3(); 8161const _v3$1 = /*@__PURE__*/ new Vector3(); 8162 8163const _vab = /*@__PURE__*/ new Vector3(); 8164const _vac = /*@__PURE__*/ new Vector3(); 8165const _vbc = /*@__PURE__*/ new Vector3(); 8166const _vap = /*@__PURE__*/ new Vector3(); 8167const _vbp = /*@__PURE__*/ new Vector3(); 8168const _vcp = /*@__PURE__*/ new Vector3(); 8169 8170let warnedGetUV = false; 8171 8172class Triangle { 8173 8174 constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) { 8175 8176 this.a = a; 8177 this.b = b; 8178 this.c = c; 8179 8180 } 8181 8182 static getNormal( a, b, c, target ) { 8183 8184 target.subVectors( c, b ); 8185 _v0$1.subVectors( a, b ); 8186 target.cross( _v0$1 ); 8187 8188 const targetLengthSq = target.lengthSq(); 8189 if ( targetLengthSq > 0 ) { 8190 8191 return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) ); 8192 8193 } 8194 8195 return target.set( 0, 0, 0 ); 8196 8197 } 8198 8199 // static/instance method to calculate barycentric coordinates 8200 // based on: http://www.blackpawn.com/texts/pointinpoly/default.html 8201 static getBarycoord( point, a, b, c, target ) { 8202 8203 _v0$1.subVectors( c, a ); 8204 _v1$3.subVectors( b, a ); 8205 _v2$2.subVectors( point, a ); 8206
vendor: 4,337 bytes, lines 8207-8414
8207 const dot00 = _v0$1.dot( _v0$1 ); 8208 const dot01 = _v0$1.dot( _v1$3 ); 8209 const dot02 = _v0$1.dot( _v2$2 ); 8210 const dot11 = _v1$3.dot( _v1$3 ); 8211 const dot12 = _v1$3.dot( _v2$2 ); 8212 8213 const denom = ( dot00 * dot11 - dot01 * dot01 ); 8214 8215 // collinear or singular triangle 8216 if ( denom === 0 ) { 8217 8218 target.set( 0, 0, 0 ); 8219 return null; 8220 8221 } 8222 8223 const invDenom = 1 / denom; 8224 const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; 8225 const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; 8226 8227 // barycentric coordinates must always sum to 1 8228 return target.set( 1 - u - v, v, u ); 8229 8230 } 8231 8232 static containsPoint( point, a, b, c ) { 8233 8234 // if the triangle is degenerate then we can't contain a point 8235 if ( this.getBarycoord( point, a, b, c, _v3$1 ) === null ) { 8236 8237 return false; 8238 8239 } 8240 8241 return ( _v3$1.x >= 0 ) && ( _v3$1.y >= 0 ) && ( ( _v3$1.x + _v3$1.y ) <= 1 ); 8242 8243 } 8244 8245 static getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) { // @deprecated, r151 8246 8247 if ( warnedGetUV === false ) { 8248 8249 console.warn( 'THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation().' ); 8250 8251 warnedGetUV = true; 8252 8253 } 8254 8255 return this.getInterpolation( point, p1, p2, p3, uv1, uv2, uv3, target ); 8256 8257 } 8258 8259 static getInterpolation( point, p1, p2, p3, v1, v2, v3, target ) { 8260 8261 if ( this.getBarycoord( point, p1, p2, p3, _v3$1 ) === null ) { 8262 8263 target.x = 0; 8264 target.y = 0; 8265 if ( 'z' in target ) target.z = 0; 8266 if ( 'w' in target ) target.w = 0; 8267 return null; 8268 8269 } 8270 8271 target.setScalar( 0 ); 8272 target.addScaledVector( v1, _v3$1.x ); 8273 target.addScaledVector( v2, _v3$1.y ); 8274 target.addScaledVector( v3, _v3$1.z ); 8275 8276 return target; 8277 8278 } 8279 8280 static isFrontFacing( a, b, c, direction ) { 8281 8282 _v0$1.subVectors( c, b ); 8283 _v1$3.subVectors( a, b ); 8284 8285 // strictly front facing 8286 return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false; 8287 8288 } 8289 8290 set( a, b, c ) { 8291 8292 this.a.copy( a ); 8293 this.b.copy( b ); 8294 this.c.copy( c ); 8295 8296 return this; 8297 8298 } 8299 8300 setFromPointsAndIndices( points, i0, i1, i2 ) { 8301 8302 this.a.copy( points[ i0 ] ); 8303 this.b.copy( points[ i1 ] ); 8304 this.c.copy( points[ i2 ] ); 8305 8306 return this; 8307 8308 } 8309 8310 setFromAttributeAndIndices( attribute, i0, i1, i2 ) { 8311 8312 this.a.fromBufferAttribute( attribute, i0 ); 8313 this.b.fromBufferAttribute( attribute, i1 ); 8314 this.c.fromBufferAttribute( attribute, i2 ); 8315 8316 return this; 8317 8318 } 8319 8320 clone() { 8321 8322 return new this.constructor().copy( this ); 8323 8324 } 8325 8326 copy( triangle ) { 8327 8328 this.a.copy( triangle.a ); 8329 this.b.copy( triangle.b ); 8330 this.c.copy( triangle.c ); 8331 8332 return this; 8333 8334 } 8335 8336 getArea() { 8337 8338 _v0$1.subVectors( this.c, this.b ); 8339 _v1$3.subVectors( this.a, this.b ); 8340 8341 return _v0$1.cross( _v1$3 ).length() * 0.5; 8342 8343 } 8344 8345 getMidpoint( target ) { 8346 8347 return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); 8348 8349 } 8350 8351 getNormal( target ) { 8352 8353 return Triangle.getNormal( this.a, this.b, this.c, target ); 8354 8355 } 8356 8357 getPlane( target ) { 8358 8359 return target.setFromCoplanarPoints( this.a, this.b, this.c ); 8360 8361 } 8362 8363 getBarycoord( point, target ) { 8364 8365 return Triangle.getBarycoord( point, this.a, this.b, this.c, target ); 8366 8367 } 8368 8369 getUV( point, uv1, uv2, uv3, target ) { // @deprecated, r151 8370 8371 if ( warnedGetUV === false ) { 8372 8373 console.warn( 'THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation().' ); 8374 8375 warnedGetUV = true; 8376 8377 } 8378 8379 return Triangle.getInterpolation( point, this.a, this.b, this.c, uv1, uv2, uv3, target ); 8380 8381 } 8382 8383 getInterpolation( point, v1, v2, v3, target ) { 8384 8385 return Triangle.getInterpolation( point, this.a, this.b, this.c, v1, v2, v3, target ); 8386 8387 } 8388 8389 containsPoint( point ) { 8390 8391 return Triangle.containsPoint( point, this.a, this.b, this.c ); 8392 8393 } 8394 8395 isFrontFacing( direction ) { 8396 8397 return Triangle.isFrontFacing( this.a, this.b, this.c, direction ); 8398 8399 } 8400 8401 intersectsBox( box ) { 8402 8403 return box.intersectsTriangle( this ); 8404 8405 } 8406 8407 closestPointToPoint( p, target ) { 8408 8409 const a = this.a, b = this.b, c = this.c; 8410 let v, w; 8411 8412 // algorithm thanks to Real-Time Collision Detection by Christer Ericson, 8413 // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc., 8414 // under the accompanying license; see chapter 5.1.5 for detailed explanation.
vendor: 27,169 bytes, lines 8415-9457
8415 // basically, we're distinguishing which of the voronoi regions of the triangle 8416 // the point lies in with the minimum amount of redundant computation. 8417 8418 _vab.subVectors( b, a ); 8419 _vac.subVectors( c, a ); 8420 _vap.subVectors( p, a ); 8421 const d1 = _vab.dot( _vap ); 8422 const d2 = _vac.dot( _vap ); 8423 if ( d1 <= 0 && d2 <= 0 ) { 8424 8425 // vertex region of A; barycentric coords (1, 0, 0) 8426 return target.copy( a ); 8427 8428 } 8429 8430 _vbp.subVectors( p, b ); 8431 const d3 = _vab.dot( _vbp ); 8432 const d4 = _vac.dot( _vbp ); 8433 if ( d3 >= 0 && d4 <= d3 ) { 8434 8435 // vertex region of B; barycentric coords (0, 1, 0) 8436 return target.copy( b ); 8437 8438 } 8439 8440 const vc = d1 * d4 - d3 * d2; 8441 if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) { 8442 8443 v = d1 / ( d1 - d3 ); 8444 // edge region of AB; barycentric coords (1-v, v, 0) 8445 return target.copy( a ).addScaledVector( _vab, v ); 8446 8447 } 8448 8449 _vcp.subVectors( p, c ); 8450 const d5 = _vab.dot( _vcp ); 8451 const d6 = _vac.dot( _vcp ); 8452 if ( d6 >= 0 && d5 <= d6 ) { 8453 8454 // vertex region of C; barycentric coords (0, 0, 1) 8455 return target.copy( c ); 8456 8457 } 8458 8459 const vb = d5 * d2 - d1 * d6; 8460 if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) { 8461 8462 w = d2 / ( d2 - d6 ); 8463 // edge region of AC; barycentric coords (1-w, 0, w) 8464 return target.copy( a ).addScaledVector( _vac, w ); 8465 8466 } 8467 8468 const va = d3 * d6 - d5 * d4; 8469 if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) { 8470 8471 _vbc.subVectors( c, b ); 8472 w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) ); 8473 // edge region of BC; barycentric coords (0, 1-w, w) 8474 return target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC 8475 8476 } 8477 8478 // face region 8479 const denom = 1 / ( va + vb + vc ); 8480 // u = va * denom 8481 v = vb * denom; 8482 w = vc * denom; 8483 8484 return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w ); 8485 8486 } 8487 8488 equals( triangle ) { 8489 8490 return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); 8491 8492 } 8493 8494} 8495 8496const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, 8497 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, 8498 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, 8499 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, 8500 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, 8501 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, 8502 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, 8503 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, 8504 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, 8505 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, 8506 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, 8507 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, 8508 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, 8509 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, 8510 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, 8511 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, 8512 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, 8513 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, 8514 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, 8515 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, 8516 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, 8517 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, 8518 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, 8519 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; 8520 8521const _hslA = { h: 0, s: 0, l: 0 }; 8522const _hslB = { h: 0, s: 0, l: 0 }; 8523 8524function hue2rgb( p, q, t ) { 8525 8526 if ( t < 0 ) t += 1; 8527 if ( t > 1 ) t -= 1; 8528 if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; 8529 if ( t < 1 / 2 ) return q; 8530 if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); 8531 return p; 8532 8533} 8534 8535class Color { 8536 8537 constructor( r, g, b ) { 8538 8539 this.isColor = true; 8540 8541 this.r = 1; 8542 this.g = 1; 8543 this.b = 1; 8544 8545 return this.set( r, g, b ); 8546 8547 } 8548 8549 set( r, g, b ) { 8550 8551 if ( g === undefined && b === undefined ) { 8552 8553 // r is THREE.Color, hex or string 8554 8555 const value = r; 8556 8557 if ( value && value.isColor ) { 8558 8559 this.copy( value ); 8560 8561 } else if ( typeof value === 'number' ) { 8562 8563 this.setHex( value ); 8564 8565 } else if ( typeof value === 'string' ) { 8566 8567 this.setStyle( value ); 8568 8569 } 8570 8571 } else { 8572 8573 this.setRGB( r, g, b ); 8574 8575 } 8576 8577 return this; 8578 8579 } 8580 8581 setScalar( scalar ) { 8582 8583 this.r = scalar; 8584 this.g = scalar; 8585 this.b = scalar; 8586 8587 return this; 8588 8589 } 8590 8591 setHex( hex, colorSpace = SRGBColorSpace ) { 8592 8593 hex = Math.floor( hex ); 8594 8595 this.r = ( hex >> 16 & 255 ) / 255; 8596 this.g = ( hex >> 8 & 255 ) / 255; 8597 this.b = ( hex & 255 ) / 255; 8598 8599 ColorManagement.toWorkingColorSpace( this, colorSpace ); 8600 8601 return this; 8602 8603 } 8604 8605 setRGB( r, g, b, colorSpace = ColorManagement.workingColorSpace ) { 8606 8607 this.r = r; 8608 8609 this.g = g; 8610 this.b = b; 8611 8612 ColorManagement.toWorkingColorSpace( this, colorSpace ); 8613 8614 return this; 8615 8616 } 8617 8618 setHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) { 8619 8620 // h,s,l ranges are in 0.0 - 1.0 8621 h = euclideanModulo( h, 1 ); 8622 s = clamp( s, 0, 1 ); 8623 l = clamp( l, 0, 1 ); 8624 8625 if ( s === 0 ) { 8626 8627 this.r = this.g = this.b = l; 8628 8629 } else { 8630 8631 const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); 8632 const q = ( 2 * l ) - p; 8633 8634 this.r = hue2rgb( q, p, h + 1 / 3 ); 8635 this.g = hue2rgb( q, p, h ); 8636 this.b = hue2rgb( q, p, h - 1 / 3 ); 8637 8638 } 8639 8640 ColorManagement.toWorkingColorSpace( this, colorSpace ); 8641 8642 return this; 8643 8644 } 8645 8646 setStyle( style, colorSpace = SRGBColorSpace ) { 8647 8648 function handleAlpha( string ) { 8649 8650 if ( string === undefined ) return; 8651 8652 if ( parseFloat( string ) < 1 ) { 8653 8654 console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); 8655 8656 } 8657 8658 } 8659 8660 8661 let m; 8662 8663 if ( m = /^(\w+)\(([^\)]*)\)/.exec( style ) ) { 8664 8665 // rgb / hsl 8666 8667 let color; 8668 const name = m[ 1 ]; 8669 const components = m[ 2 ]; 8670 8671 switch ( name ) { 8672 8673 case 'rgb': 8674 case 'rgba': 8675 8676 if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { 8677 8678 // rgb(255,0,0) rgba(255,0,0,0.5) 8679 8680 handleAlpha( color[ 4 ] ); 8681 8682 return this.setRGB( 8683 Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255, 8684 Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255, 8685 Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255, 8686 colorSpace 8687 ); 8688 8689 } 8690 8691 if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { 8692 8693 // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5) 8694 8695 handleAlpha( color[ 4 ] ); 8696 8697 return this.setRGB( 8698 Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100, 8699 Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100, 8700 Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100, 8701 colorSpace 8702 ); 8703 8704 } 8705 8706 break; 8707 8708 case 'hsl': 8709 case 'hsla': 8710 8711 if ( color = /^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { 8712 8713 // hsl(120,50%,50%) hsla(120,50%,50%,0.5) 8714 8715 handleAlpha( color[ 4 ] ); 8716 8717 return this.setHSL( 8718 parseFloat( color[ 1 ] ) / 360, 8719 parseFloat( color[ 2 ] ) / 100, 8720 parseFloat( color[ 3 ] ) / 100, 8721 colorSpace 8722 ); 8723 8724 } 8725 8726 break; 8727 8728 default: 8729 8730 console.warn( 'THREE.Color: Unknown color model ' + style ); 8731 8732 } 8733 8734 } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) { 8735 8736 // hex color 8737 8738 const hex = m[ 1 ]; 8739 const size = hex.length; 8740 8741 if ( size === 3 ) { 8742 8743 // #ff0 8744 return this.setRGB( 8745 parseInt( hex.charAt( 0 ), 16 ) / 15, 8746 parseInt( hex.charAt( 1 ), 16 ) / 15, 8747 parseInt( hex.charAt( 2 ), 16 ) / 15, 8748 colorSpace 8749 ); 8750 8751 } else if ( size === 6 ) { 8752 8753 // #ff0000 8754 return this.setHex( parseInt( hex, 16 ), colorSpace ); 8755 8756 } else { 8757 8758 console.warn( 'THREE.Color: Invalid hex color ' + style ); 8759 8760 } 8761 8762 } else if ( style && style.length > 0 ) { 8763 8764 return this.setColorName( style, colorSpace ); 8765 8766 } 8767 8768 return this; 8769 8770 } 8771 8772 setColorName( style, colorSpace = SRGBColorSpace ) { 8773 8774 // color keywords 8775 const hex = _colorKeywords[ style.toLowerCase() ]; 8776 8777 if ( hex !== undefined ) { 8778 8779 // red 8780 this.setHex( hex, colorSpace ); 8781 8782 } else { 8783 8784 // unknown color 8785 console.warn( 'THREE.Color: Unknown color ' + style ); 8786 8787 } 8788 8789 return this; 8790 8791 } 8792 8793 clone() { 8794 8795 return new this.constructor( this.r, this.g, this.b ); 8796 8797 } 8798 8799 copy( color ) { 8800 8801 this.r = color.r; 8802 this.g = color.g; 8803 this.b = color.b; 8804 8805 return this; 8806 8807 } 8808 8809 copySRGBToLinear( color ) { 8810 8811 this.r = SRGBToLinear( color.r ); 8812 this.g = SRGBToLinear( color.g ); 8813 this.b = SRGBToLinear( color.b ); 8814 8815 return this; 8816 8817 } 8818 8819 copyLinearToSRGB( color ) { 8820 8821 this.r = LinearToSRGB( color.r ); 8822 this.g = LinearToSRGB( color.g ); 8823 this.b = LinearToSRGB( color.b ); 8824 8825 return this; 8826 8827 } 8828 8829 convertSRGBToLinear() { 8830 8831 this.copySRGBToLinear( this ); 8832 8833 return this; 8834 8835 } 8836 8837 convertLinearToSRGB() { 8838 8839 this.copyLinearToSRGB( this ); 8840 8841 return this; 8842 8843 } 8844 8845 getHex( colorSpace = SRGBColorSpace ) { 8846 8847 ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); 8848 8849 return Math.round( clamp( _color.r * 255, 0, 255 ) ) * 65536 + Math.round( clamp( _color.g * 255, 0, 255 ) ) * 256 + Math.round( clamp( _color.b * 255, 0, 255 ) ); 8850 8851 } 8852 8853 getHexString( colorSpace = SRGBColorSpace ) { 8854 8855 return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 ); 8856 8857 } 8858 8859 getHSL( target, colorSpace = ColorManagement.workingColorSpace ) { 8860 8861 // h,s,l ranges are in 0.0 - 1.0 8862 8863 ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); 8864 8865 const r = _color.r, g = _color.g, b = _color.b; 8866 8867 const max = Math.max( r, g, b ); 8868 const min = Math.min( r, g, b ); 8869 8870 let hue, saturation; 8871 const lightness = ( min + max ) / 2.0; 8872 8873 if ( min === max ) { 8874 8875 hue = 0; 8876 saturation = 0; 8877 8878 } else { 8879 8880 const delta = max - min; 8881 8882 saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); 8883 8884 switch ( max ) { 8885 8886 case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; 8887 case g: hue = ( b - r ) / delta + 2; break; 8888 case b: hue = ( r - g ) / delta + 4; break; 8889 8890 } 8891 8892 hue /= 6; 8893 8894 } 8895 8896 target.h = hue; 8897 target.s = saturation; 8898 target.l = lightness; 8899 8900 return target; 8901 8902 } 8903 8904 getRGB( target, colorSpace = ColorManagement.workingColorSpace ) { 8905 8906 ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); 8907 8908 target.r = _color.r; 8909 target.g = _color.g; 8910 target.b = _color.b; 8911 8912 return target; 8913 8914 } 8915 8916 getStyle( colorSpace = SRGBColorSpace ) { 8917 8918 ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); 8919 8920 const r = _color.r, g = _color.g, b = _color.b; 8921 8922 if ( colorSpace !== SRGBColorSpace ) { 8923 8924 // Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/). 8925 return `color(${ colorSpace } ${ r.toFixed( 3 ) } ${ g.toFixed( 3 ) } ${ b.toFixed( 3 ) })`; 8926 8927 } 8928 8929 return `rgb(${ Math.round( r * 255 ) },${ Math.round( g * 255 ) },${ Math.round( b * 255 ) })`; 8930 8931 } 8932 8933 offsetHSL( h, s, l ) { 8934 8935 this.getHSL( _hslA ); 8936 8937 return this.setHSL( _hslA.h + h, _hslA.s + s, _hslA.l + l ); 8938 8939 } 8940 8941 add( color ) { 8942 8943 this.r += color.r; 8944 this.g += color.g; 8945 this.b += color.b; 8946 8947 return this; 8948 8949 } 8950 8951 addColors( color1, color2 ) { 8952 8953 this.r = color1.r + color2.r; 8954 this.g = color1.g + color2.g; 8955 this.b = color1.b + color2.b; 8956 8957 return this; 8958 8959 } 8960 8961 addScalar( s ) { 8962 8963 this.r += s; 8964 this.g += s; 8965 this.b += s; 8966 8967 return this; 8968 8969 } 8970 8971 sub( color ) { 8972 8973 this.r = Math.max( 0, this.r - color.r ); 8974 this.g = Math.max( 0, this.g - color.g ); 8975 this.b = Math.max( 0, this.b - color.b ); 8976 8977 return this; 8978 8979 } 8980 8981 multiply( color ) { 8982 8983 this.r *= color.r; 8984 this.g *= color.g; 8985 this.b *= color.b; 8986 8987 return this; 8988 8989 } 8990 8991 multiplyScalar( s ) { 8992 8993 this.r *= s; 8994 this.g *= s; 8995 this.b *= s; 8996 8997 return this; 8998 8999 } 9000 9001 lerp( color, alpha ) { 9002 9003 this.r += ( color.r - this.r ) * alpha; 9004 this.g += ( color.g - this.g ) * alpha; 9005 this.b += ( color.b - this.b ) * alpha; 9006 9007 return this; 9008 9009 } 9010 9011 lerpColors( color1, color2, alpha ) { 9012 9013 this.r = color1.r + ( color2.r - color1.r ) * alpha; 9014 this.g = color1.g + ( color2.g - color1.g ) * alpha; 9015 this.b = color1.b + ( color2.b - color1.b ) * alpha; 9016 9017 return this; 9018 9019 } 9020 9021 lerpHSL( color, alpha ) { 9022 9023 this.getHSL( _hslA ); 9024 color.getHSL( _hslB ); 9025 9026 const h = lerp( _hslA.h, _hslB.h, alpha ); 9027 const s = lerp( _hslA.s, _hslB.s, alpha ); 9028 const l = lerp( _hslA.l, _hslB.l, alpha ); 9029 9030 this.setHSL( h, s, l ); 9031 9032 return this; 9033 9034 } 9035 9036 setFromVector3( v ) { 9037 9038 this.r = v.x; 9039 this.g = v.y; 9040 this.b = v.z; 9041 9042 return this; 9043 9044 } 9045 9046 applyMatrix3( m ) { 9047 9048 const r = this.r, g = this.g, b = this.b; 9049 const e = m.elements; 9050 9051 this.r = e[ 0 ] * r + e[ 3 ] * g + e[ 6 ] * b; 9052 this.g = e[ 1 ] * r + e[ 4 ] * g + e[ 7 ] * b; 9053 this.b = e[ 2 ] * r + e[ 5 ] * g + e[ 8 ] * b; 9054 9055 return this; 9056 9057 } 9058 9059 equals( c ) { 9060 9061 return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); 9062 9063 } 9064 9065 fromArray( array, offset = 0 ) { 9066 9067 this.r = array[ offset ]; 9068 this.g = array[ offset + 1 ]; 9069 this.b = array[ offset + 2 ]; 9070 9071 return this; 9072 9073 } 9074 9075 toArray( array = [], offset = 0 ) { 9076 9077 array[ offset ] = this.r; 9078 array[ offset + 1 ] = this.g; 9079 array[ offset + 2 ] = this.b; 9080 9081 return array; 9082 9083 } 9084 9085 fromBufferAttribute( attribute, index ) { 9086 9087 this.r = attribute.getX( index ); 9088 this.g = attribute.getY( index ); 9089 this.b = attribute.getZ( index ); 9090 9091 return this; 9092 9093 } 9094 9095 toJSON() { 9096 9097 return this.getHex(); 9098 9099 } 9100 9101 *[ Symbol.iterator ]() { 9102 9103 yield this.r; 9104 yield this.g; 9105 yield this.b; 9106 9107 } 9108 9109} 9110 9111const _color = /*@__PURE__*/ new Color(); 9112 9113Color.NAMES = _colorKeywords; 9114 9115let _materialId = 0; 9116 9117class Material extends EventDispatcher { 9118 9119 constructor() { 9120 9121 super(); 9122 9123 this.isMaterial = true; 9124 9125 Object.defineProperty( this, 'id', { value: _materialId ++ } ); 9126 9127 this.uuid = generateUUID(); 9128 9129 this.name = ''; 9130 this.type = 'Material'; 9131 9132 this.blending = NormalBlending; 9133 this.side = FrontSide; 9134 this.vertexColors = false; 9135 9136 this.opacity = 1; 9137 this.transparent = false; 9138 this.alphaHash = false; 9139 9140 this.blendSrc = SrcAlphaFactor; 9141 this.blendDst = OneMinusSrcAlphaFactor; 9142 this.blendEquation = AddEquation; 9143 this.blendSrcAlpha = null; 9144 this.blendDstAlpha = null; 9145 this.blendEquationAlpha = null; 9146 this.blendColor = new Color( 0, 0, 0 ); 9147 this.blendAlpha = 0; 9148 9149 this.depthFunc = LessEqualDepth; 9150 this.depthTest = true; 9151 this.depthWrite = true; 9152 9153 this.stencilWriteMask = 0xff; 9154 this.stencilFunc = AlwaysStencilFunc; 9155 this.stencilRef = 0; 9156 this.stencilFuncMask = 0xff; 9157 this.stencilFail = KeepStencilOp; 9158 this.stencilZFail = KeepStencilOp; 9159 this.stencilZPass = KeepStencilOp; 9160 this.stencilWrite = false; 9161 9162 this.clippingPlanes = null; 9163 this.clipIntersection = false; 9164 this.clipShadows = false; 9165 9166 this.shadowSide = null; 9167 9168 this.colorWrite = true; 9169 9170 this.precision = null; // override the renderer's default precision for this material 9171 9172 this.polygonOffset = false; 9173 this.polygonOffsetFactor = 0; 9174 this.polygonOffsetUnits = 0; 9175 9176 this.dithering = false; 9177 9178 this.alphaToCoverage = false; 9179 this.premultipliedAlpha = false; 9180 this.forceSinglePass = false; 9181 9182 this.visible = true; 9183 9184 this.toneMapped = true; 9185 9186 this.userData = {}; 9187 9188 this.version = 0; 9189 9190 this._alphaTest = 0; 9191 9192 } 9193 9194 get alphaTest() { 9195 9196 return this._alphaTest; 9197 9198 } 9199 9200 set alphaTest( value ) { 9201 9202 if ( this._alphaTest > 0 !== value > 0 ) { 9203 9204 this.version ++; 9205 9206 } 9207 9208 this._alphaTest = value; 9209 9210 } 9211 9212 onBuild( /* shaderobject, renderer */ ) {} 9213 9214 onBeforeRender( /* renderer, scene, camera, geometry, object, group */ ) {} 9215 9216 onBeforeCompile( /* shaderobject, renderer */ ) {} 9217 9218 customProgramCacheKey() { 9219 9220 return this.onBeforeCompile.toString(); 9221 9222 } 9223 9224 setValues( values ) { 9225 9226 if ( values === undefined ) return; 9227 9228 for ( const key in values ) { 9229 9230 const newValue = values[ key ]; 9231 9232 if ( newValue === undefined ) { 9233 9234 console.warn( `THREE.Material: parameter '${ key }' has value of undefined.` ); 9235 continue; 9236 9237 } 9238 9239 const currentValue = this[ key ]; 9240 9241 if ( currentValue === undefined ) { 9242 9243 console.warn( `THREE.Material: '${ key }' is not a property of THREE.${ this.type }.` ); 9244 continue; 9245 9246 } 9247 9248 if ( currentValue && currentValue.isColor ) { 9249 9250 currentValue.set( newValue ); 9251 9252 } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) { 9253 9254 currentValue.copy( newValue ); 9255 9256 } else { 9257 9258 this[ key ] = newValue; 9259 9260 } 9261 9262 } 9263 9264 } 9265 9266 toJSON( meta ) { 9267 9268 const isRootObject = ( meta === undefined || typeof meta === 'string' ); 9269 9270 if ( isRootObject ) { 9271 9272 meta = { 9273 textures: {}, 9274 images: {} 9275 }; 9276 9277 } 9278 9279 const data = { 9280 metadata: { 9281 version: 4.6, 9282 type: 'Material', 9283 generator: 'Material.toJSON' 9284 } 9285 }; 9286 9287 // standard Material serialization 9288 data.uuid = this.uuid; 9289 data.type = this.type; 9290 9291 if ( this.name !== '' ) data.name = this.name; 9292 9293 if ( this.color && this.color.isColor ) data.color = this.color.getHex(); 9294 9295 if ( this.roughness !== undefined ) data.roughness = this.roughness; 9296 if ( this.metalness !== undefined ) data.metalness = this.metalness; 9297 9298 if ( this.sheen !== undefined ) data.sheen = this.sheen; 9299 if ( this.sheenColor && this.sheenColor.isColor ) data.sheenColor = this.sheenColor.getHex(); 9300 if ( this.sheenRoughness !== undefined ) data.sheenRoughness = this.sheenRoughness; 9301 if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex(); 9302 if ( this.emissiveIntensity && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity; 9303 9304 if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex(); 9305 if ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity; 9306 if ( this.specularColor && this.specularColor.isColor ) data.specularColor = this.specularColor.getHex(); 9307 if ( this.shininess !== undefined ) data.shininess = this.shininess; 9308 if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat; 9309 if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness; 9310 9311 if ( this.clearcoatMap && this.clearcoatMap.isTexture ) { 9312 9313 data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid; 9314 9315 } 9316 9317 if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) { 9318 9319 data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid; 9320 9321 } 9322 9323 if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) { 9324 9325 data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid; 9326 data.clearcoatNormalScale = this.clearcoatNormalScale.toArray(); 9327 9328 } 9329 9330 if ( this.iridescence !== undefined ) data.iridescence = this.iridescence; 9331 if ( this.iridescenceIOR !== undefined ) data.iridescenceIOR = this.iridescenceIOR; 9332 if ( this.iridescenceThicknessRange !== undefined ) data.iridescenceThicknessRange = this.iridescenceThicknessRange; 9333 9334 if ( this.iridescenceMap && this.iridescenceMap.isTexture ) { 9335 9336 data.iridescenceMap = this.iridescenceMap.toJSON( meta ).uuid; 9337 9338 } 9339 9340 if ( this.iridescenceThicknessMap && this.iridescenceThicknessMap.isTexture ) { 9341 9342 data.iridescenceThicknessMap = this.iridescenceThicknessMap.toJSON( meta ).uuid; 9343 9344 } 9345 9346 if ( this.anisotropy !== undefined ) data.anisotropy = this.anisotropy; 9347 if ( this.anisotropyRotation !== undefined ) data.anisotropyRotation = this.anisotropyRotation; 9348 9349 if ( this.anisotropyMap && this.anisotropyMap.isTexture ) { 9350 9351 data.anisotropyMap = this.anisotropyMap.toJSON( meta ).uuid; 9352 9353 } 9354 9355 if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid; 9356 if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid; 9357 if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid; 9358 9359 if ( this.lightMap && this.lightMap.isTexture ) { 9360 9361 data.lightMap = this.lightMap.toJSON( meta ).uuid; 9362 data.lightMapIntensity = this.lightMapIntensity; 9363 9364 } 9365 9366 if ( this.aoMap && this.aoMap.isTexture ) { 9367 9368 data.aoMap = this.aoMap.toJSON( meta ).uuid; 9369 data.aoMapIntensity = this.aoMapIntensity; 9370 9371 } 9372 9373 if ( this.bumpMap && this.bumpMap.isTexture ) { 9374 9375 data.bumpMap = this.bumpMap.toJSON( meta ).uuid; 9376 data.bumpScale = this.bumpScale; 9377 9378 } 9379 9380 if ( this.normalMap && this.normalMap.isTexture ) { 9381 9382 data.normalMap = this.normalMap.toJSON( meta ).uuid; 9383 data.normalMapType = this.normalMapType; 9384 data.normalScale = this.normalScale.toArray(); 9385 9386 } 9387 9388 if ( this.displacementMap && this.displacementMap.isTexture ) { 9389 9390 data.displacementMap = this.displacementMap.toJSON( meta ).uuid; 9391 data.displacementScale = this.displacementScale; 9392 data.displacementBias = this.displacementBias; 9393 9394 } 9395 9396 if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid; 9397 if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid; 9398 9399 if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid; 9400 if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid; 9401 if ( this.specularIntensityMap && this.specularIntensityMap.isTexture ) data.specularIntensityMap = this.specularIntensityMap.toJSON( meta ).uuid; 9402 if ( this.specularColorMap && this.specularColorMap.isTexture ) data.specularColorMap = this.specularColorMap.toJSON( meta ).uuid; 9403 9404 if ( this.envMap && this.envMap.isTexture ) { 9405 9406 data.envMap = this.envMap.toJSON( meta ).uuid; 9407 9408 if ( this.combine !== undefined ) data.combine = this.combine; 9409 9410 } 9411 9412 if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity; 9413 if ( this.reflectivity !== undefined ) data.reflectivity = this.reflectivity; 9414 if ( this.refractionRatio !== undefined ) data.refractionRatio = this.refractionRatio; 9415 9416 if ( this.gradientMap && this.gradientMap.isTexture ) { 9417 9418 data.gradientMap = this.gradientMap.toJSON( meta ).uuid; 9419 9420 } 9421 9422 if ( this.transmission !== undefined ) data.transmission = this.transmission; 9423 if ( this.transmissionMap && this.transmissionMap.isTexture ) data.transmissionMap = this.transmissionMap.toJSON( meta ).uuid; 9424 if ( this.thickness !== undefined ) data.thickness = this.thickness; 9425 if ( this.thicknessMap && this.thicknessMap.isTexture ) data.thicknessMap = this.thicknessMap.toJSON( meta ).uuid; 9426 if ( this.attenuationDistance !== undefined && this.attenuationDistance !== Infinity ) data.attenuationDistance = this.attenuationDistance; 9427 if ( this.attenuationColor !== undefined ) data.attenuationColor = this.attenuationColor.getHex(); 9428 9429 if ( this.size !== undefined ) data.size = this.size; 9430 if ( this.shadowSide !== null ) data.shadowSide = this.shadowSide; 9431 if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation; 9432 9433 if ( this.blending !== NormalBlending ) data.blending = this.blending; 9434 if ( this.side !== FrontSide ) data.side = this.side; 9435 if ( this.vertexColors === true ) data.vertexColors = true; 9436 9437 if ( this.opacity < 1 ) data.opacity = this.opacity; 9438 if ( this.transparent === true ) data.transparent = true; 9439 9440 if ( this.blendSrc !== SrcAlphaFactor ) data.blendSrc = this.blendSrc; 9441 if ( this.blendDst !== OneMinusSrcAlphaFactor ) data.blendDst = this.blendDst; 9442 if ( this.blendEquation !== AddEquation ) data.blendEquation = this.blendEquation; 9443 if ( this.blendSrcAlpha !== null ) data.blendSrcAlpha = this.blendSrcAlpha; 9444 if ( this.blendDstAlpha !== null ) data.blendDstAlpha = this.blendDstAlpha; 9445 if ( this.blendEquationAlpha !== null ) data.blendEquationAlpha = this.blendEquationAlpha; 9446 if ( this.blendColor && this.blendColor.isColor ) data.blendColor = this.blendColor.getHex(); 9447 if ( this.blendAlpha !== 0 ) data.blendAlpha = this.blendAlpha; 9448 9449 if ( this.depthFunc !== LessEqualDepth ) data.depthFunc = this.depthFunc; 9450 if ( this.depthTest === false ) data.depthTest = this.depthTest; 9451 if ( this.depthWrite === false ) data.depthWrite = this.depthWrite; 9452 if ( this.colorWrite === false ) data.colorWrite = this.colorWrite; 9453 9454 if ( this.stencilWriteMask !== 0xff ) data.stencilWriteMask = this.stencilWriteMask; 9455 if ( this.stencilFunc !== AlwaysStencilFunc ) data.stencilFunc = this.stencilFunc; 9456 if ( this.stencilRef !== 0 ) data.stencilRef = this.stencilRef; 9457 if ( this.stencilFuncMask !== 0xff ) data.stencilFuncMask = this.stencilFuncMask;
vendor: 4,089 bytes, lines 9458-9586
9458 if ( this.stencilFail !== KeepStencilOp ) data.stencilFail = this.stencilFail; 9459 if ( this.stencilZFail !== KeepStencilOp ) data.stencilZFail = this.stencilZFail; 9460 if ( this.stencilZPass !== KeepStencilOp ) data.stencilZPass = this.stencilZPass; 9461 if ( this.stencilWrite === true ) data.stencilWrite = this.stencilWrite; 9462 9463 // rotation (SpriteMaterial) 9464 if ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation; 9465 9466 if ( this.polygonOffset === true ) data.polygonOffset = true; 9467 if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor; 9468 if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits; 9469 9470 if ( this.linewidth !== undefined && this.linewidth !== 1 ) data.linewidth = this.linewidth; 9471 if ( this.dashSize !== undefined ) data.dashSize = this.dashSize; 9472 if ( this.gapSize !== undefined ) data.gapSize = this.gapSize; 9473 if ( this.scale !== undefined ) data.scale = this.scale; 9474 9475 if ( this.dithering === true ) data.dithering = true; 9476 9477 if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; 9478 if ( this.alphaHash === true ) data.alphaHash = true; 9479 if ( this.alphaToCoverage === true ) data.alphaToCoverage = true; 9480 if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = true; 9481 if ( this.forceSinglePass === true ) data.forceSinglePass = true; 9482 9483 if ( this.wireframe === true ) data.wireframe = true; 9484 if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth; 9485 if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap; 9486 if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin; 9487 9488 if ( this.flatShading === true ) data.flatShading = true; 9489 9490 if ( this.visible === false ) data.visible = false; 9491 9492 if ( this.toneMapped === false ) data.toneMapped = false; 9493 9494 if ( this.fog === false ) data.fog = false; 9495 9496 if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData; 9497 9498 // TODO: Copied from Object3D.toJSON 9499 9500 function extractFromCache( cache ) { 9501 9502 const values = []; 9503 9504 for ( const key in cache ) { 9505 9506 const data = cache[ key ]; 9507 delete data.metadata; 9508 values.push( data ); 9509 9510 } 9511 9512 return values; 9513 9514 } 9515 9516 if ( isRootObject ) { 9517 9518 const textures = extractFromCache( meta.textures ); 9519 const images = extractFromCache( meta.images ); 9520 9521 if ( textures.length > 0 ) data.textures = textures; 9522 if ( images.length > 0 ) data.images = images; 9523 9524 } 9525 9526 return data; 9527 9528 } 9529 9530 clone() { 9531 9532 return new this.constructor().copy( this ); 9533 9534 } 9535 9536 copy( source ) { 9537 9538 this.name = source.name; 9539 9540 this.blending = source.blending; 9541 this.side = source.side; 9542 this.vertexColors = source.vertexColors; 9543 9544 this.opacity = source.opacity; 9545 this.transparent = source.transparent; 9546 9547 this.blendSrc = source.blendSrc; 9548 this.blendDst = source.blendDst; 9549 this.blendEquation = source.blendEquation; 9550 this.blendSrcAlpha = source.blendSrcAlpha; 9551 this.blendDstAlpha = source.blendDstAlpha; 9552 this.blendEquationAlpha = source.blendEquationAlpha; 9553 this.blendColor.copy( source.blendColor ); 9554 this.blendAlpha = source.blendAlpha; 9555 9556 this.depthFunc = source.depthFunc; 9557 this.depthTest = source.depthTest; 9558 this.depthWrite = source.depthWrite; 9559 9560 this.stencilWriteMask = source.stencilWriteMask; 9561 this.stencilFunc = source.stencilFunc; 9562 this.stencilRef = source.stencilRef; 9563 this.stencilFuncMask = source.stencilFuncMask; 9564 this.stencilFail = source.stencilFail; 9565 this.stencilZFail = source.stencilZFail; 9566 this.stencilZPass = source.stencilZPass; 9567 this.stencilWrite = source.stencilWrite; 9568 9569 const srcPlanes = source.clippingPlanes; 9570 let dstPlanes = null; 9571 9572 if ( srcPlanes !== null ) { 9573 9574 const n = srcPlanes.length; 9575 dstPlanes = new Array( n ); 9576 9577 for ( let i = 0; i !== n; ++ i ) { 9578 9579 dstPlanes[ i ] = srcPlanes[ i ].clone(); 9580 9581 } 9582 9583 } 9584 9585 this.clippingPlanes = dstPlanes; 9586 this.clipIntersection = source.clipIntersection;
vendor: 7,363 bytes, lines 9587-9946
9587 this.clipShadows = source.clipShadows; 9588 9589 this.shadowSide = source.shadowSide; 9590 9591 this.colorWrite = source.colorWrite; 9592 9593 this.precision = source.precision; 9594 9595 9596 this.polygonOffset = source.polygonOffset; 9597 this.polygonOffsetFactor = source.polygonOffsetFactor; 9598 this.polygonOffsetUnits = source.polygonOffsetUnits; 9599 9600 this.dithering = source.dithering; 9601 9602 this.alphaTest = source.alphaTest; 9603 this.alphaHash = source.alphaHash; 9604 this.alphaToCoverage = source.alphaToCoverage; 9605 this.premultipliedAlpha = source.premultipliedAlpha; 9606 this.forceSinglePass = source.forceSinglePass; 9607 9608 this.visible = source.visible; 9609 9610 this.toneMapped = source.toneMapped; 9611 9612 this.userData = JSON.parse( JSON.stringify( source.userData ) ); 9613 9614 return this; 9615 9616 } 9617 9618 dispose() { 9619 9620 this.dispatchEvent( { type: 'dispose' } ); 9621 9622 } 9623 9624 set needsUpdate( value ) { 9625 9626 if ( value === true ) this.version ++; 9627 9628 } 9629 9630} 9631 9632class MeshBasicMaterial extends Material { 9633 9634 constructor( parameters ) { 9635 9636 super(); 9637 9638 this.isMeshBasicMaterial = true; 9639 9640 this.type = 'MeshBasicMaterial'; 9641 9642 this.color = new Color( 0xffffff ); // emissive 9643 9644 this.map = null; 9645 9646 this.lightMap = null; 9647 this.lightMapIntensity = 1.0; 9648 9649 this.aoMap = null; 9650 this.aoMapIntensity = 1.0; 9651 9652 this.specularMap = null; 9653 9654 this.alphaMap = null; 9655 9656 this.envMap = null; 9657 this.combine = MultiplyOperation; 9658 this.reflectivity = 1; 9659 this.refractionRatio = 0.98; 9660 9661 this.wireframe = false; 9662 this.wireframeLinewidth = 1; 9663 this.wireframeLinecap = 'round'; 9664 this.wireframeLinejoin = 'round'; 9665 9666 this.fog = true; 9667 9668 this.setValues( parameters ); 9669 9670 } 9671 9672 copy( source ) { 9673 9674 super.copy( source ); 9675 9676 this.color.copy( source.color ); 9677 9678 this.map = source.map; 9679 9680 this.lightMap = source.lightMap; 9681 this.lightMapIntensity = source.lightMapIntensity; 9682 9683 this.aoMap = source.aoMap; 9684 this.aoMapIntensity = source.aoMapIntensity; 9685 9686 this.specularMap = source.specularMap; 9687 9688 this.alphaMap = source.alphaMap; 9689 9690 this.envMap = source.envMap; 9691 this.combine = source.combine; 9692 this.reflectivity = source.reflectivity; 9693 this.refractionRatio = source.refractionRatio; 9694 9695 this.wireframe = source.wireframe; 9696 this.wireframeLinewidth = source.wireframeLinewidth; 9697 this.wireframeLinecap = source.wireframeLinecap; 9698 this.wireframeLinejoin = source.wireframeLinejoin; 9699 9700 this.fog = source.fog; 9701 9702 return this; 9703 9704 } 9705 9706} 9707 9708// Fast Half Float Conversions, http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf 9709 9710const _tables = /*@__PURE__*/ _generateTables(); 9711 9712function _generateTables() { 9713 9714 // float32 to float16 helpers 9715 9716 const buffer = new ArrayBuffer( 4 ); 9717 const floatView = new Float32Array( buffer ); 9718 const uint32View = new Uint32Array( buffer ); 9719 9720 const baseTable = new Uint32Array( 512 ); 9721 const shiftTable = new Uint32Array( 512 ); 9722 9723 for ( let i = 0; i < 256; ++ i ) { 9724 9725 const e = i - 127; 9726 9727 // very small number (0, -0) 9728 9729 if ( e < - 27 ) { 9730 9731 baseTable[ i ] = 0x0000; 9732 baseTable[ i | 0x100 ] = 0x8000; 9733 shiftTable[ i ] = 24; 9734 shiftTable[ i | 0x100 ] = 24; 9735 9736 // small number (denorm) 9737 9738 } else if ( e < - 14 ) { 9739 9740 baseTable[ i ] = 0x0400 >> ( - e - 14 ); 9741 baseTable[ i | 0x100 ] = ( 0x0400 >> ( - e - 14 ) ) | 0x8000; 9742 shiftTable[ i ] = - e - 1; 9743 shiftTable[ i | 0x100 ] = - e - 1; 9744 9745 // normal number 9746 9747 } else if ( e <= 15 ) { 9748 9749 baseTable[ i ] = ( e + 15 ) << 10; 9750 baseTable[ i | 0x100 ] = ( ( e + 15 ) << 10 ) | 0x8000; 9751 shiftTable[ i ] = 13; 9752 shiftTable[ i | 0x100 ] = 13; 9753 9754 // large number (Infinity, -Infinity) 9755 9756 } else if ( e < 128 ) { 9757 9758 baseTable[ i ] = 0x7c00; 9759 baseTable[ i | 0x100 ] = 0xfc00; 9760 shiftTable[ i ] = 24; 9761 shiftTable[ i | 0x100 ] = 24; 9762 9763 // stay (NaN, Infinity, -Infinity) 9764 9765 } else { 9766 9767 baseTable[ i ] = 0x7c00; 9768 baseTable[ i | 0x100 ] = 0xfc00; 9769 shiftTable[ i ] = 13; 9770 shiftTable[ i | 0x100 ] = 13; 9771 9772 } 9773 9774 } 9775 9776 // float16 to float32 helpers 9777 9778 const mantissaTable = new Uint32Array( 2048 ); 9779 const exponentTable = new Uint32Array( 64 ); 9780 const offsetTable = new Uint32Array( 64 ); 9781 9782 for ( let i = 1; i < 1024; ++ i ) { 9783 9784 let m = i << 13; // zero pad mantissa bits 9785 let e = 0; // zero exponent 9786 9787 // normalized 9788 while ( ( m & 0x00800000 ) === 0 ) { 9789 9790 m <<= 1; 9791 e -= 0x00800000; // decrement exponent 9792 9793 } 9794 9795 m &= ~ 0x00800000; // clear leading 1 bit 9796 e += 0x38800000; // adjust bias 9797 9798 mantissaTable[ i ] = m | e; 9799 9800 } 9801 9802 for ( let i = 1024; i < 2048; ++ i ) { 9803 9804 mantissaTable[ i ] = 0x38000000 + ( ( i - 1024 ) << 13 ); 9805 9806 } 9807 9808 for ( let i = 1; i < 31; ++ i ) { 9809 9810 exponentTable[ i ] = i << 23; 9811 9812 } 9813 9814 exponentTable[ 31 ] = 0x47800000; 9815 exponentTable[ 32 ] = 0x80000000; 9816 9817 for ( let i = 33; i < 63; ++ i ) { 9818 9819 exponentTable[ i ] = 0x80000000 + ( ( i - 32 ) << 23 ); 9820 9821 } 9822 9823 exponentTable[ 63 ] = 0xc7800000; 9824 9825 for ( let i = 1; i < 64; ++ i ) { 9826 9827 if ( i !== 32 ) { 9828 9829 offsetTable[ i ] = 1024; 9830 9831 } 9832 9833 } 9834 9835 return { 9836 floatView: floatView, 9837 uint32View: uint32View, 9838 baseTable: baseTable, 9839 shiftTable: shiftTable, 9840 mantissaTable: mantissaTable, 9841 exponentTable: exponentTable, 9842 offsetTable: offsetTable 9843 }; 9844 9845} 9846 9847// float32 to float16 9848 9849function toHalfFloat( val ) { 9850 9851 if ( Math.abs( val ) > 65504 ) console.warn( 'THREE.DataUtils.toHalfFloat(): Value out of range.' ); 9852 9853 val = clamp( val, - 65504, 65504 ); 9854 9855 _tables.floatView[ 0 ] = val; 9856 const f = _tables.uint32View[ 0 ]; 9857 const e = ( f >> 23 ) & 0x1ff; 9858 return _tables.baseTable[ e ] + ( ( f & 0x007fffff ) >> _tables.shiftTable[ e ] ); 9859 9860} 9861 9862// float16 to float32 9863 9864function fromHalfFloat( val ) { 9865 9866 const m = val >> 10; 9867 _tables.uint32View[ 0 ] = _tables.mantissaTable[ _tables.offsetTable[ m ] + ( val & 0x3ff ) ] + _tables.exponentTable[ m ]; 9868 return _tables.floatView[ 0 ]; 9869 9870} 9871 9872const DataUtils = { 9873 toHalfFloat: toHalfFloat, 9874 fromHalfFloat: fromHalfFloat, 9875}; 9876 9877const _vector$9 = /*@__PURE__*/ new Vector3(); 9878const _vector2$1 = /*@__PURE__*/ new Vector2(); 9879 9880class BufferAttribute { 9881 9882 constructor( array, itemSize, normalized = false ) { 9883 9884 if ( Array.isArray( array ) ) { 9885 9886 throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); 9887 9888 } 9889 9890 this.isBufferAttribute = true; 9891 9892 this.name = ''; 9893 9894 this.array = array; 9895 this.itemSize = itemSize; 9896 this.count = array !== undefined ? array.length / itemSize : 0; 9897 this.normalized = normalized; 9898 9899 this.usage = StaticDrawUsage; 9900 this._updateRange = { offset: 0, count: - 1 }; 9901 this.updateRanges = []; 9902 this.gpuType = FloatType; 9903 9904 this.version = 0; 9905 9906 } 9907 9908 onUploadCallback() {} 9909 9910 set needsUpdate( value ) { 9911 9912 if ( value === true ) this.version ++; 9913 9914 } 9915 9916 get updateRange() { 9917 9918 console.warn( 'THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159 9919 return this._updateRange; 9920 9921 } 9922 9923 setUsage( value ) { 9924 9925 this.usage = value; 9926 9927 return this; 9928 9929 } 9930 9931 addUpdateRange( start, count ) { 9932 9933 this.updateRanges.push( { start, count } ); 9934 9935 } 9936 9937 clearUpdateRanges() { 9938 9939 this.updateRanges.length = 0; 9940 9941 } 9942 9943 copy( source ) { 9944 9945 this.name = source.name; 9946 this.array = new source.array.constructor( source.array );
vendor: 9,812 bytes, lines 9947-10513
9947 this.itemSize = source.itemSize; 9948 this.count = source.count; 9949 this.normalized = source.normalized; 9950 9951 this.usage = source.usage; 9952 this.gpuType = source.gpuType; 9953 9954 return this; 9955 9956 } 9957 9958 copyAt( index1, attribute, index2 ) { 9959 9960 index1 *= this.itemSize; 9961 index2 *= attribute.itemSize; 9962 9963 for ( let i = 0, l = this.itemSize; i < l; i ++ ) { 9964 9965 this.array[ index1 + i ] = attribute.array[ index2 + i ]; 9966 9967 } 9968 9969 return this; 9970 9971 } 9972 9973 copyArray( array ) { 9974 9975 this.array.set( array ); 9976 9977 return this; 9978 9979 } 9980 9981 applyMatrix3( m ) { 9982 9983 if ( this.itemSize === 2 ) { 9984 9985 for ( let i = 0, l = this.count; i < l; i ++ ) { 9986 9987 _vector2$1.fromBufferAttribute( this, i ); 9988 _vector2$1.applyMatrix3( m ); 9989 9990 this.setXY( i, _vector2$1.x, _vector2$1.y ); 9991 9992 } 9993 9994 } else if ( this.itemSize === 3 ) { 9995 9996 for ( let i = 0, l = this.count; i < l; i ++ ) { 9997 9998 _vector$9.fromBufferAttribute( this, i ); 9999 _vector$9.applyMatrix3( m ); 10000 10001 this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); 10002 10003 } 10004 10005 } 10006 10007 return this; 10008 10009 } 10010 10011 applyMatrix4( m ) { 10012 10013 for ( let i = 0, l = this.count; i < l; i ++ ) { 10014 10015 _vector$9.fromBufferAttribute( this, i ); 10016 10017 _vector$9.applyMatrix4( m ); 10018 10019 this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); 10020 10021 } 10022 10023 return this; 10024 10025 } 10026 10027 applyNormalMatrix( m ) { 10028 10029 for ( let i = 0, l = this.count; i < l; i ++ ) { 10030 10031 _vector$9.fromBufferAttribute( this, i ); 10032 10033 _vector$9.applyNormalMatrix( m ); 10034 10035 this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); 10036 10037 } 10038 10039 return this; 10040 10041 } 10042 10043 transformDirection( m ) { 10044 10045 for ( let i = 0, l = this.count; i < l; i ++ ) { 10046 10047 _vector$9.fromBufferAttribute( this, i ); 10048 10049 _vector$9.transformDirection( m ); 10050 10051 this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); 10052 10053 } 10054 10055 return this; 10056 10057 } 10058 10059 set( value, offset = 0 ) { 10060 10061 // Matching BufferAttribute constructor, do not normalize the array. 10062 this.array.set( value, offset ); 10063 10064 return this; 10065 10066 } 10067 10068 getComponent( index, component ) { 10069 10070 let value = this.array[ index * this.itemSize + component ]; 10071 10072 if ( this.normalized ) value = denormalize( value, this.array ); 10073 10074 return value; 10075 10076 } 10077 10078 setComponent( index, component, value ) { 10079 10080 if ( this.normalized ) value = normalize( value, this.array ); 10081 10082 this.array[ index * this.itemSize + component ] = value; 10083 10084 return this; 10085 10086 } 10087 10088 getX( index ) { 10089 10090 let x = this.array[ index * this.itemSize ]; 10091 10092 if ( this.normalized ) x = denormalize( x, this.array ); 10093 10094 return x; 10095 10096 } 10097 10098 setX( index, x ) { 10099 10100 if ( this.normalized ) x = normalize( x, this.array ); 10101 10102 this.array[ index * this.itemSize ] = x; 10103 10104 return this; 10105 10106 } 10107 10108 getY( index ) { 10109 10110 let y = this.array[ index * this.itemSize + 1 ]; 10111 10112 if ( this.normalized ) y = denormalize( y, this.array ); 10113 10114 return y; 10115 10116 } 10117 10118 setY( index, y ) { 10119 10120 if ( this.normalized ) y = normalize( y, this.array ); 10121 10122 this.array[ index * this.itemSize + 1 ] = y; 10123 10124 return this; 10125 10126 } 10127 10128 getZ( index ) { 10129 10130 let z = this.array[ index * this.itemSize + 2 ]; 10131 10132 if ( this.normalized ) z = denormalize( z, this.array ); 10133 10134 return z; 10135 10136 } 10137 10138 setZ( index, z ) { 10139 10140 if ( this.normalized ) z = normalize( z, this.array ); 10141 10142 this.array[ index * this.itemSize + 2 ] = z; 10143 10144 return this; 10145 10146 } 10147 10148 getW( index ) { 10149 10150 let w = this.array[ index * this.itemSize + 3 ]; 10151 10152 if ( this.normalized ) w = denormalize( w, this.array ); 10153 10154 return w; 10155 10156 } 10157 10158 setW( index, w ) { 10159 10160 if ( this.normalized ) w = normalize( w, this.array ); 10161 10162 this.array[ index * this.itemSize + 3 ] = w; 10163 10164 return this; 10165 10166 } 10167 10168 setXY( index, x, y ) { 10169 10170 index *= this.itemSize; 10171 10172 if ( this.normalized ) { 10173 10174 x = normalize( x, this.array ); 10175 y = normalize( y, this.array ); 10176 10177 } 10178 10179 this.array[ index + 0 ] = x; 10180 this.array[ index + 1 ] = y; 10181 10182 return this; 10183 10184 } 10185 10186 setXYZ( index, x, y, z ) { 10187 10188 index *= this.itemSize; 10189 10190 if ( this.normalized ) { 10191 10192 x = normalize( x, this.array ); 10193 y = normalize( y, this.array ); 10194 z = normalize( z, this.array ); 10195 10196 } 10197 10198 this.array[ index + 0 ] = x; 10199 this.array[ index + 1 ] = y; 10200 this.array[ index + 2 ] = z; 10201 10202 return this; 10203 10204 } 10205 10206 setXYZW( index, x, y, z, w ) { 10207 10208 index *= this.itemSize; 10209 10210 if ( this.normalized ) { 10211 10212 x = normalize( x, this.array ); 10213 y = normalize( y, this.array ); 10214 z = normalize( z, this.array ); 10215 w = normalize( w, this.array ); 10216 10217 } 10218 10219 this.array[ index + 0 ] = x; 10220 this.array[ index + 1 ] = y; 10221 this.array[ index + 2 ] = z; 10222 this.array[ index + 3 ] = w; 10223 10224 return this; 10225 10226 } 10227 10228 onUpload( callback ) { 10229 10230 this.onUploadCallback = callback; 10231 10232 return this; 10233 10234 } 10235 10236 clone() { 10237 10238 return new this.constructor( this.array, this.itemSize ).copy( this ); 10239 10240 } 10241 10242 toJSON() { 10243 10244 const data = { 10245 itemSize: this.itemSize, 10246 type: this.array.constructor.name, 10247 array: Array.from( this.array ), 10248 normalized: this.normalized 10249 }; 10250 10251 if ( this.name !== '' ) data.name = this.name; 10252 if ( this.usage !== StaticDrawUsage ) data.usage = this.usage; 10253 10254 return data; 10255 10256 } 10257 10258} 10259 10260// 10261 10262class Int8BufferAttribute extends BufferAttribute { 10263 10264 constructor( array, itemSize, normalized ) { 10265 10266 super( new Int8Array( array ), itemSize, normalized ); 10267 10268 } 10269 10270} 10271 10272class Uint8BufferAttribute extends BufferAttribute { 10273 10274 constructor( array, itemSize, normalized ) { 10275 10276 super( new Uint8Array( array ), itemSize, normalized ); 10277 10278 } 10279 10280} 10281 10282class Uint8ClampedBufferAttribute extends BufferAttribute { 10283 10284 constructor( array, itemSize, normalized ) { 10285 10286 super( new Uint8ClampedArray( array ), itemSize, normalized ); 10287 10288 } 10289 10290} 10291 10292class Int16BufferAttribute extends BufferAttribute { 10293 10294 constructor( array, itemSize, normalized ) { 10295 10296 super( new Int16Array( array ), itemSize, normalized ); 10297 10298 } 10299 10300} 10301 10302class Uint16BufferAttribute extends BufferAttribute { 10303 10304 constructor( array, itemSize, normalized ) { 10305 10306 super( new Uint16Array( array ), itemSize, normalized ); 10307 10308 } 10309 10310} 10311 10312class Int32BufferAttribute extends BufferAttribute { 10313 10314 constructor( array, itemSize, normalized ) { 10315 10316 super( new Int32Array( array ), itemSize, normalized ); 10317 10318 } 10319 10320} 10321 10322class Uint32BufferAttribute extends BufferAttribute { 10323 10324 constructor( array, itemSize, normalized ) { 10325 10326 super( new Uint32Array( array ), itemSize, normalized ); 10327 10328 } 10329 10330} 10331 10332class Float16BufferAttribute extends BufferAttribute { 10333 10334 constructor( array, itemSize, normalized ) { 10335 10336 super( new Uint16Array( array ), itemSize, normalized ); 10337 10338 this.isFloat16BufferAttribute = true; 10339 10340 } 10341 10342 getX( index ) { 10343 10344 let x = fromHalfFloat( this.array[ index * this.itemSize ] ); 10345 10346 if ( this.normalized ) x = denormalize( x, this.array ); 10347 10348 return x; 10349 10350 } 10351 10352 setX( index, x ) { 10353 10354 if ( this.normalized ) x = normalize( x, this.array ); 10355 10356 this.array[ index * this.itemSize ] = toHalfFloat( x ); 10357 10358 return this; 10359 10360 } 10361 10362 getY( index ) { 10363 10364 let y = fromHalfFloat( this.array[ index * this.itemSize + 1 ] ); 10365 10366 if ( this.normalized ) y = denormalize( y, this.array ); 10367 10368 return y; 10369 10370 } 10371 10372 setY( index, y ) { 10373 10374 if ( this.normalized ) y = normalize( y, this.array ); 10375 10376 this.array[ index * this.itemSize + 1 ] = toHalfFloat( y ); 10377 10378 return this; 10379 10380 } 10381 10382 getZ( index ) { 10383 10384 let z = fromHalfFloat( this.array[ index * this.itemSize + 2 ] ); 10385 10386 if ( this.normalized ) z = denormalize( z, this.array ); 10387 10388 return z; 10389 10390 } 10391 10392 setZ( index, z ) { 10393 10394 if ( this.normalized ) z = normalize( z, this.array ); 10395 10396 this.array[ index * this.itemSize + 2 ] = toHalfFloat( z ); 10397 10398 return this; 10399 10400 } 10401 10402 getW( index ) { 10403 10404 let w = fromHalfFloat( this.array[ index * this.itemSize + 3 ] ); 10405 10406 if ( this.normalized ) w = denormalize( w, this.array ); 10407 10408 return w; 10409 10410 } 10411 10412 setW( index, w ) { 10413 10414 if ( this.normalized ) w = normalize( w, this.array ); 10415 10416 this.array[ index * this.itemSize + 3 ] = toHalfFloat( w ); 10417 10418 return this; 10419 10420 } 10421 10422 setXY( index, x, y ) { 10423 10424 index *= this.itemSize; 10425 10426 if ( this.normalized ) { 10427 10428 x = normalize( x, this.array ); 10429 y = normalize( y, this.array ); 10430 10431 } 10432 10433 this.array[ index + 0 ] = toHalfFloat( x ); 10434 this.array[ index + 1 ] = toHalfFloat( y ); 10435 10436 return this; 10437 10438 } 10439 10440 setXYZ( index, x, y, z ) { 10441 10442 index *= this.itemSize; 10443 10444 if ( this.normalized ) { 10445 10446 x = normalize( x, this.array ); 10447 y = normalize( y, this.array ); 10448 z = normalize( z, this.array ); 10449 10450 } 10451 10452 this.array[ index + 0 ] = toHalfFloat( x ); 10453 this.array[ index + 1 ] = toHalfFloat( y ); 10454 this.array[ index + 2 ] = toHalfFloat( z ); 10455 10456 return this; 10457 10458 } 10459 10460 setXYZW( index, x, y, z, w ) { 10461 10462 index *= this.itemSize; 10463 10464 if ( this.normalized ) { 10465 10466 x = normalize( x, this.array ); 10467 y = normalize( y, this.array ); 10468 z = normalize( z, this.array ); 10469 w = normalize( w, this.array ); 10470 10471 } 10472 10473 this.array[ index + 0 ] = toHalfFloat( x ); 10474 this.array[ index + 1 ] = toHalfFloat( y ); 10475 this.array[ index + 2 ] = toHalfFloat( z ); 10476 this.array[ index + 3 ] = toHalfFloat( w ); 10477 10478 return this; 10479 10480 } 10481 10482} 10483 10484 10485class Float32BufferAttribute extends BufferAttribute { 10486 10487 constructor( array, itemSize, normalized ) { 10488 10489 super( new Float32Array( array ), itemSize, normalized ); 10490 10491 } 10492 10493} 10494 10495class Float64BufferAttribute extends BufferAttribute { 10496 10497 constructor( array, itemSize, normalized ) { 10498 10499 super( new Float64Array( array ), itemSize, normalized ); 10500 10501 } 10502 10503} 10504 10505let _id$2 = 0; 10506 10507const _m1 = /*@__PURE__*/ new Matrix4(); 10508const _obj = /*@__PURE__*/ new Object3D(); 10509const _offset = /*@__PURE__*/ new Vector3(); 10510const _box$2 = /*@__PURE__*/ new Box3(); 10511const _boxMorphTargets = /*@__PURE__*/ new Box3(); 10512const _vector$8 = /*@__PURE__*/ new Vector3(); 10513
vendor: 6,038 bytes, lines 10514-10865
10514class BufferGeometry extends EventDispatcher { 10515 10516 constructor() { 10517 10518 super(); 10519 10520 this.isBufferGeometry = true; 10521 10522 Object.defineProperty( this, 'id', { value: _id$2 ++ } ); 10523 10524 this.uuid = generateUUID(); 10525 10526 this.name = ''; 10527 this.type = 'BufferGeometry'; 10528 10529 this.index = null; 10530 this.attributes = {}; 10531 10532 this.morphAttributes = {}; 10533 this.morphTargetsRelative = false; 10534 10535 this.groups = []; 10536 10537 this.boundingBox = null; 10538 this.boundingSphere = null; 10539 10540 this.drawRange = { start: 0, count: Infinity }; 10541 10542 this.userData = {}; 10543 10544 } 10545 10546 getIndex() { 10547 10548 return this.index; 10549 10550 } 10551 10552 setIndex( index ) { 10553 10554 if ( Array.isArray( index ) ) { 10555 10556 this.index = new ( arrayNeedsUint32( index ) ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 ); 10557 10558 } else { 10559 10560 this.index = index; 10561 10562 } 10563 10564 return this; 10565 10566 } 10567 10568 getAttribute( name ) { 10569 10570 return this.attributes[ name ]; 10571 10572 } 10573 10574 setAttribute( name, attribute ) { 10575 10576 this.attributes[ name ] = attribute; 10577 10578 return this; 10579 10580 } 10581 10582 deleteAttribute( name ) { 10583 10584 delete this.attributes[ name ]; 10585 10586 return this; 10587 10588 } 10589 10590 hasAttribute( name ) { 10591 10592 return this.attributes[ name ] !== undefined; 10593 10594 } 10595 10596 addGroup( start, count, materialIndex = 0 ) { 10597 10598 this.groups.push( { 10599 10600 start: start, 10601 count: count, 10602 materialIndex: materialIndex 10603 10604 } ); 10605 10606 } 10607 10608 clearGroups() { 10609 10610 this.groups = []; 10611 10612 } 10613 10614 setDrawRange( start, count ) { 10615 10616 this.drawRange.start = start; 10617 this.drawRange.count = count; 10618 10619 } 10620 10621 applyMatrix4( matrix ) { 10622 10623 const position = this.attributes.position; 10624 10625 if ( position !== undefined ) { 10626 10627 position.applyMatrix4( matrix ); 10628 10629 position.needsUpdate = true; 10630 10631 } 10632 10633 const normal = this.attributes.normal; 10634 10635 if ( normal !== undefined ) { 10636 10637 const normalMatrix = new Matrix3().getNormalMatrix( matrix ); 10638 10639 normal.applyNormalMatrix( normalMatrix ); 10640 10641 normal.needsUpdate = true; 10642 10643 } 10644 10645 const tangent = this.attributes.tangent; 10646 10647 if ( tangent !== undefined ) { 10648 10649 tangent.transformDirection( matrix ); 10650 10651 tangent.needsUpdate = true; 10652 10653 } 10654 10655 if ( this.boundingBox !== null ) { 10656 10657 this.computeBoundingBox(); 10658 10659 } 10660 10661 if ( this.boundingSphere !== null ) { 10662 10663 this.computeBoundingSphere(); 10664 10665 } 10666 10667 return this; 10668 10669 } 10670 10671 applyQuaternion( q ) { 10672 10673 _m1.makeRotationFromQuaternion( q ); 10674 10675 this.applyMatrix4( _m1 ); 10676 10677 return this; 10678 10679 } 10680 10681 rotateX( angle ) { 10682 10683 // rotate geometry around world x-axis 10684 10685 _m1.makeRotationX( angle ); 10686 10687 this.applyMatrix4( _m1 ); 10688 10689 return this; 10690 10691 } 10692 10693 rotateY( angle ) { 10694 10695 // rotate geometry around world y-axis 10696 10697 _m1.makeRotationY( angle ); 10698 10699 this.applyMatrix4( _m1 ); 10700 10701 return this; 10702 10703 } 10704 10705 rotateZ( angle ) { 10706 10707 // rotate geometry around world z-axis 10708 10709 _m1.makeRotationZ( angle ); 10710 10711 this.applyMatrix4( _m1 ); 10712 10713 return this; 10714 10715 } 10716 10717 translate( x, y, z ) { 10718 10719 // translate geometry 10720 10721 _m1.makeTranslation( x, y, z ); 10722 10723 this.applyMatrix4( _m1 ); 10724 10725 return this; 10726 10727 } 10728 10729 scale( x, y, z ) { 10730 10731 // scale geometry 10732 10733 _m1.makeScale( x, y, z ); 10734 10735 this.applyMatrix4( _m1 ); 10736 10737 return this; 10738 10739 } 10740 10741 lookAt( vector ) { 10742 10743 _obj.lookAt( vector ); 10744 10745 _obj.updateMatrix(); 10746 10747 this.applyMatrix4( _obj.matrix ); 10748 10749 return this; 10750 10751 } 10752 10753 center() { 10754 10755 this.computeBoundingBox(); 10756 10757 this.boundingBox.getCenter( _offset ).negate(); 10758 10759 this.translate( _offset.x, _offset.y, _offset.z ); 10760 10761 return this; 10762 10763 } 10764 10765 setFromPoints( points ) { 10766 10767 const position = []; 10768 10769 for ( let i = 0, l = points.length; i < l; i ++ ) { 10770 10771 const point = points[ i ]; 10772 position.push( point.x, point.y, point.z || 0 ); 10773 10774 } 10775 10776 this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) ); 10777 10778 return this; 10779 10780 } 10781 10782 computeBoundingBox() { 10783 10784 if ( this.boundingBox === null ) { 10785 10786 this.boundingBox = new Box3(); 10787 10788 } 10789 10790 const position = this.attributes.position; 10791 const morphAttributesPosition = this.morphAttributes.position; 10792 10793 if ( position && position.isGLBufferAttribute ) { 10794 10795 console.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box. Alternatively set "mesh.frustumCulled" to "false".', this ); 10796 10797 this.boundingBox.set( 10798 new Vector3( - Infinity, - Infinity, - Infinity ), 10799 new Vector3( + Infinity, + Infinity, + Infinity ) 10800 ); 10801 10802 return; 10803 10804 } 10805 10806 if ( position !== undefined ) { 10807 10808 this.boundingBox.setFromBufferAttribute( position ); 10809 10810 // process morph attributes if present 10811 10812 if ( morphAttributesPosition ) { 10813 10814 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { 10815 10816 const morphAttribute = morphAttributesPosition[ i ]; 10817 _box$2.setFromBufferAttribute( morphAttribute ); 10818 10819 if ( this.morphTargetsRelative ) { 10820 10821 _vector$8.addVectors( this.boundingBox.min, _box$2.min ); 10822 this.boundingBox.expandByPoint( _vector$8 ); 10823 10824 _vector$8.addVectors( this.boundingBox.max, _box$2.max ); 10825 this.boundingBox.expandByPoint( _vector$8 ); 10826 10827 } else { 10828 10829 this.boundingBox.expandByPoint( _box$2.min ); 10830 this.boundingBox.expandByPoint( _box$2.max ); 10831 10832 } 10833 10834 } 10835 10836 } 10837 10838 } else { 10839 10840 this.boundingBox.makeEmpty(); 10841 10842 } 10843 10844 if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { 10845 10846 console.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this ); 10847 10848 } 10849 10850 } 10851 10852 computeBoundingSphere() { 10853 10854 if ( this.boundingSphere === null ) { 10855 10856 this.boundingSphere = new Sphere(); 10857 10858 } 10859 10860 const position = this.attributes.position; 10861 const morphAttributesPosition = this.morphAttributes.position; 10862 10863 if ( position && position.isGLBufferAttribute ) { 10864 10865 console.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere. Alternatively set "mesh.frustumCulled" to "fal
vendor: 5,245 bytes, lines 10865-11093
10865se".', this ); 10866 10867 this.boundingSphere.set( new Vector3(), Infinity ); 10868 10869 return; 10870 10871 } 10872 10873 if ( position ) { 10874 10875 // first, find the center of the bounding sphere 10876 10877 const center = this.boundingSphere.center; 10878 10879 _box$2.setFromBufferAttribute( position ); 10880 10881 // process morph attributes if present 10882 10883 if ( morphAttributesPosition ) { 10884 10885 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { 10886 10887 const morphAttribute = morphAttributesPosition[ i ]; 10888 _boxMorphTargets.setFromBufferAttribute( morphAttribute ); 10889 10890 if ( this.morphTargetsRelative ) { 10891 10892 _vector$8.addVectors( _box$2.min, _boxMorphTargets.min ); 10893 _box$2.expandByPoint( _vector$8 ); 10894 10895 _vector$8.addVectors( _box$2.max, _boxMorphTargets.max ); 10896 _box$2.expandByPoint( _vector$8 ); 10897 10898 } else { 10899 10900 _box$2.expandByPoint( _boxMorphTargets.min ); 10901 _box$2.expandByPoint( _boxMorphTargets.max ); 10902 10903 } 10904 10905 } 10906 10907 } 10908 10909 _box$2.getCenter( center ); 10910 10911 // second, try to find a boundingSphere with a radius smaller than the 10912 // boundingSphere of the boundingBox: sqrt(3) smaller in the best case 10913 10914 let maxRadiusSq = 0; 10915 10916 for ( let i = 0, il = position.count; i < il; i ++ ) { 10917 10918 _vector$8.fromBufferAttribute( position, i ); 10919 10920 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) ); 10921 10922 } 10923 10924 // process morph attributes if present 10925 10926 if ( morphAttributesPosition ) { 10927 10928 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { 10929 10930 const morphAttribute = morphAttributesPosition[ i ]; 10931 const morphTargetsRelative = this.morphTargetsRelative; 10932 10933 for ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) { 10934 10935 _vector$8.fromBufferAttribute( morphAttribute, j ); 10936 10937 if ( morphTargetsRelative ) { 10938 10939 _offset.fromBufferAttribute( position, j ); 10940 _vector$8.add( _offset ); 10941 10942 } 10943 10944 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) ); 10945 10946 } 10947 10948 } 10949 10950 } 10951 10952 this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); 10953 10954 if ( isNaN( this.boundingSphere.radius ) ) { 10955 10956 console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); 10957 10958 } 10959 10960 } 10961 10962 } 10963 10964 computeTangents() { 10965 10966 const index = this.index; 10967 const attributes = this.attributes; 10968 10969 // based on http://www.terathon.com/code/tangent.html 10970 // (per vertex tangents) 10971 10972 if ( index === null || 10973 attributes.position === undefined || 10974 attributes.normal === undefined || 10975 attributes.uv === undefined ) { 10976 10977 console.error( 'THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' ); 10978 return; 10979 10980 } 10981 10982 const indices = index.array; 10983 const positions = attributes.position.array; 10984 const normals = attributes.normal.array; 10985 const uvs = attributes.uv.array; 10986 10987 const nVertices = positions.length / 3; 10988 10989 if ( this.hasAttribute( 'tangent' ) === false ) { 10990 10991 this.setAttribute( 'tangent', new BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) ); 10992 10993 } 10994 10995 const tangents = this.getAttribute( 'tangent' ).array; 10996 10997 const tan1 = [], tan2 = []; 10998 10999 for ( let i = 0; i < nVertices; i ++ ) { 11000 11001 tan1[ i ] = new Vector3(); 11002 tan2[ i ] = new Vector3(); 11003 11004 } 11005 11006 const vA = new Vector3(), 11007 vB = new Vector3(), 11008 vC = new Vector3(), 11009 11010 uvA = new Vector2(), 11011 uvB = new Vector2(), 11012 uvC = new Vector2(), 11013 11014 sdir = new Vector3(), 11015 tdir = new Vector3(); 11016 11017 function handleTriangle( a, b, c ) { 11018 11019 vA.fromArray( positions, a * 3 ); 11020 vB.fromArray( positions, b * 3 ); 11021 vC.fromArray( positions, c * 3 ); 11022 11023 uvA.fromArray( uvs, a * 2 ); 11024 uvB.fromArray( uvs, b * 2 ); 11025 uvC.fromArray( uvs, c * 2 ); 11026 11027 vB.sub( vA ); 11028 vC.sub( vA ); 11029 11030 uvB.sub( uvA ); 11031 uvC.sub( uvA ); 11032 11033 const r = 1.0 / ( uvB.x * uvC.y - uvC.x * uvB.y ); 11034 11035 // silently ignore degenerate uv triangles having coincident or colinear vertices 11036 11037 if ( ! isFinite( r ) ) return; 11038 11039 sdir.copy( vB ).multiplyScalar( uvC.y ).addScaledVector( vC, - uvB.y ).multiplyScalar( r ); 11040 tdir.copy( vC ).multiplyScalar( uvB.x ).addScaledVector( vB, - uvC.x ).multiplyScalar( r ); 11041 11042 tan1[ a ].add( sdir ); 11043 tan1[ b ].add( sdir ); 11044 tan1[ c ].add( sdir ); 11045 11046 tan2[ a ].add( tdir ); 11047 tan2[ b ].add( tdir ); 11048 tan2[ c ].add( tdir ); 11049 11050 } 11051 11052 let groups = this.groups; 11053 11054 if ( groups.length === 0 ) { 11055 11056 groups = [ { 11057 start: 0, 11058 count: indices.length 11059 } ]; 11060 11061 } 11062 11063 for ( let i = 0, il = groups.length; i < il; ++ i ) { 11064 11065 const group = groups[ i ]; 11066 11067 const start = group.start; 11068 const count = group.count; 11069 11070 for ( let j = start, jl = start + count; j < jl; j += 3 ) { 11071 11072 handleTriangle( 11073 indices[ j + 0 ], 11074 indices[ j + 1 ], 11075 indices[ j + 2 ] 11076 ); 11077 11078 } 11079 11080 } 11081 11082 const tmp = new Vector3(), tmp2 = new Vector3(); 11083 const n = new Vector3(), n2 = new Vector3(); 11084 11085 function handleVertex( v ) { 11086 11087 n.fromArray( normals, v * 3 ); 11088 n2.copy( n ); 11089 11090 const t = tan1[ v ]; 11091 11092 // Gram-Schmidt orthogonalize 11093
vendor: 4,805 bytes, lines 11094-11305
11094 tmp.copy( t ); 11095 tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); 11096 11097 // Calculate handedness 11098 11099 tmp2.crossVectors( n2, t ); 11100 const test = tmp2.dot( tan2[ v ] ); 11101 const w = ( test < 0.0 ) ? - 1.0 : 1.0; 11102 11103 tangents[ v * 4 ] = tmp.x; 11104 tangents[ v * 4 + 1 ] = tmp.y; 11105 tangents[ v * 4 + 2 ] = tmp.z; 11106 tangents[ v * 4 + 3 ] = w; 11107 11108 } 11109 11110 for ( let i = 0, il = groups.length; i < il; ++ i ) { 11111 11112 const group = groups[ i ]; 11113 11114 const start = group.start; 11115 const count = group.count; 11116 11117 for ( let j = start, jl = start + count; j < jl; j += 3 ) { 11118 11119 handleVertex( indices[ j + 0 ] ); 11120 handleVertex( indices[ j + 1 ] ); 11121 handleVertex( indices[ j + 2 ] ); 11122 11123 } 11124 11125 } 11126 11127 } 11128 11129 computeVertexNormals() { 11130 11131 const index = this.index; 11132 const positionAttribute = this.getAttribute( 'position' ); 11133 11134 if ( positionAttribute !== undefined ) { 11135 11136 let normalAttribute = this.getAttribute( 'normal' ); 11137 11138 if ( normalAttribute === undefined ) { 11139 11140 normalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 ); 11141 this.setAttribute( 'normal', normalAttribute ); 11142 11143 } else { 11144 11145 // reset existing normals to zero 11146 11147 for ( let i = 0, il = normalAttribute.count; i < il; i ++ ) { 11148 11149 normalAttribute.setXYZ( i, 0, 0, 0 ); 11150 11151 } 11152 11153 } 11154 11155 const pA = new Vector3(), pB = new Vector3(), pC = new Vector3(); 11156 const nA = new Vector3(), nB = new Vector3(), nC = new Vector3(); 11157 const cb = new Vector3(), ab = new Vector3(); 11158 11159 // indexed elements 11160 11161 if ( index ) { 11162 11163 for ( let i = 0, il = index.count; i < il; i += 3 ) { 11164 11165 const vA = index.getX( i + 0 ); 11166 const vB = index.getX( i + 1 ); 11167 const vC = index.getX( i + 2 ); 11168 11169 pA.fromBufferAttribute( positionAttribute, vA ); 11170 pB.fromBufferAttribute( positionAttribute, vB ); 11171 pC.fromBufferAttribute( positionAttribute, vC ); 11172 11173 cb.subVectors( pC, pB ); 11174 ab.subVectors( pA, pB ); 11175 cb.cross( ab ); 11176 11177 nA.fromBufferAttribute( normalAttribute, vA ); 11178 nB.fromBufferAttribute( normalAttribute, vB ); 11179 nC.fromBufferAttribute( normalAttribute, vC ); 11180 11181 nA.add( cb ); 11182 nB.add( cb ); 11183 nC.add( cb ); 11184 11185 normalAttribute.setXYZ( vA, nA.x, nA.y, nA.z ); 11186 normalAttribute.setXYZ( vB, nB.x, nB.y, nB.z ); 11187 normalAttribute.setXYZ( vC, nC.x, nC.y, nC.z ); 11188 11189 } 11190 11191 } else { 11192 11193 // non-indexed elements (unconnected triangle soup) 11194 11195 for ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) { 11196 11197 pA.fromBufferAttribute( positionAttribute, i + 0 ); 11198 pB.fromBufferAttribute( positionAttribute, i + 1 ); 11199 pC.fromBufferAttribute( positionAttribute, i + 2 ); 11200 11201 cb.subVectors( pC, pB ); 11202 ab.subVectors( pA, pB ); 11203 cb.cross( ab ); 11204 11205 normalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z ); 11206 normalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z ); 11207 normalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z ); 11208 11209 } 11210 11211 } 11212 11213 this.normalizeNormals(); 11214 11215 normalAttribute.needsUpdate = true; 11216 11217 } 11218 11219 } 11220 11221 normalizeNormals() { 11222 11223 const normals = this.attributes.normal; 11224 11225 for ( let i = 0, il = normals.count; i < il; i ++ ) { 11226 11227 _vector$8.fromBufferAttribute( normals, i ); 11228 11229 _vector$8.normalize(); 11230 11231 normals.setXYZ( i, _vector$8.x, _vector$8.y, _vector$8.z ); 11232 11233 } 11234 11235 } 11236 11237 toNonIndexed() { 11238 11239 function convertBufferAttribute( attribute, indices ) { 11240 11241 const array = attribute.array; 11242 const itemSize = attribute.itemSize; 11243 const normalized = attribute.normalized; 11244 11245 const array2 = new array.constructor( indices.length * itemSize ); 11246 11247 let index = 0, index2 = 0; 11248 11249 for ( let i = 0, l = indices.length; i < l; i ++ ) { 11250 11251 if ( attribute.isInterleavedBufferAttribute ) { 11252 11253 index = indices[ i ] * attribute.data.stride + attribute.offset; 11254 11255 } else { 11256 11257 index = indices[ i ] * itemSize; 11258 11259 } 11260 11261 for ( let j = 0; j < itemSize; j ++ ) { 11262 11263 array2[ index2 ++ ] = array[ index ++ ]; 11264 11265 } 11266 11267 } 11268 11269 return new BufferAttribute( array2, itemSize, normalized ); 11270 11271 } 11272 11273 // 11274 11275 if ( this.index === null ) { 11276 11277 console.warn( 'THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' ); 11278 return this; 11279 11280 } 11281 11282 const geometry2 = new BufferGeometry(); 11283 11284 const indices = this.index.array; 11285 const attributes = this.attributes; 11286 11287 // attributes 11288 11289 for ( const name in attributes ) { 11290 11291 const attribute = attributes[ name ]; 11292 11293 const newAttribute = convertBufferAttribute( attribute, indices ); 11294 11295 geometry2.setAttribute( name, newAttribute ); 11296 11297 } 11298 11299 // morph attributes 11300 11301 const morphAttributes = this.morphAttributes; 11302 11303 for ( const name in morphAttributes ) { 11304 11305 const morphArray = [];
vendor: 8,310 bytes, lines 11306-11716
11306 const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes 11307 11308 for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) { 11309 11310 const attribute = morphAttribute[ i ]; 11311 11312 const newAttribute = convertBufferAttribute( attribute, indices ); 11313 11314 morphArray.push( newAttribute ); 11315 11316 } 11317 11318 geometry2.morphAttributes[ name ] = morphArray; 11319 11320 } 11321 11322 geometry2.morphTargetsRelative = this.morphTargetsRelative; 11323 11324 // groups 11325 11326 const groups = this.groups; 11327 11328 for ( let i = 0, l = groups.length; i < l; i ++ ) { 11329 11330 const group = groups[ i ]; 11331 geometry2.addGroup( group.start, group.count, group.materialIndex ); 11332 11333 } 11334 11335 return geometry2; 11336 11337 } 11338 11339 toJSON() { 11340 11341 const data = { 11342 metadata: { 11343 version: 4.6, 11344 type: 'BufferGeometry', 11345 generator: 'BufferGeometry.toJSON' 11346 } 11347 }; 11348 11349 // standard BufferGeometry serialization 11350 11351 data.uuid = this.uuid; 11352 data.type = this.type; 11353 if ( this.name !== '' ) data.name = this.name; 11354 if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData; 11355 11356 if ( this.parameters !== undefined ) { 11357 11358 const parameters = this.parameters; 11359 11360 for ( const key in parameters ) { 11361 11362 if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; 11363 11364 } 11365 11366 return data; 11367 11368 } 11369 11370 // for simplicity the code assumes attributes are not shared across geometries, see #15811 11371 11372 data.data = { attributes: {} }; 11373 11374 const index = this.index; 11375 11376 if ( index !== null ) { 11377 11378 data.data.index = { 11379 type: index.array.constructor.name, 11380 array: Array.prototype.slice.call( index.array ) 11381 }; 11382 11383 } 11384 11385 const attributes = this.attributes; 11386 11387 for ( const key in attributes ) { 11388 11389 const attribute = attributes[ key ]; 11390 11391 data.data.attributes[ key ] = attribute.toJSON( data.data ); 11392 11393 } 11394 11395 const morphAttributes = {}; 11396 let hasMorphAttributes = false; 11397 11398 for ( const key in this.morphAttributes ) { 11399 11400 const attributeArray = this.morphAttributes[ key ]; 11401 11402 const array = []; 11403 11404 for ( let i = 0, il = attributeArray.length; i < il; i ++ ) { 11405 11406 const attribute = attributeArray[ i ]; 11407 11408 array.push( attribute.toJSON( data.data ) ); 11409 11410 } 11411 11412 if ( array.length > 0 ) { 11413 11414 morphAttributes[ key ] = array; 11415 11416 hasMorphAttributes = true; 11417 11418 } 11419 11420 } 11421 11422 if ( hasMorphAttributes ) { 11423 11424 data.data.morphAttributes = morphAttributes; 11425 data.data.morphTargetsRelative = this.morphTargetsRelative; 11426 11427 } 11428 11429 const groups = this.groups; 11430 11431 if ( groups.length > 0 ) { 11432 11433 data.data.groups = JSON.parse( JSON.stringify( groups ) ); 11434 11435 } 11436 11437 const boundingSphere = this.boundingSphere; 11438 11439 if ( boundingSphere !== null ) { 11440 11441 data.data.boundingSphere = { 11442 center: boundingSphere.center.toArray(), 11443 radius: boundingSphere.radius 11444 }; 11445 11446 } 11447 11448 return data; 11449 11450 } 11451 11452 clone() { 11453 11454 return new this.constructor().copy( this ); 11455 11456 } 11457 11458 copy( source ) { 11459 11460 // reset 11461 11462 this.index = null; 11463 this.attributes = {}; 11464 this.morphAttributes = {}; 11465 this.groups = []; 11466 this.boundingBox = null; 11467 this.boundingSphere = null; 11468 11469 // used for storing cloned, shared data 11470 11471 const data = {}; 11472 11473 // name 11474 11475 this.name = source.name; 11476 11477 // index 11478 11479 const index = source.index; 11480 11481 if ( index !== null ) { 11482 11483 this.setIndex( index.clone( data ) ); 11484 11485 } 11486 11487 // attributes 11488 11489 const attributes = source.attributes; 11490 11491 for ( const name in attributes ) { 11492 11493 const attribute = attributes[ name ]; 11494 this.setAttribute( name, attribute.clone( data ) ); 11495 11496 } 11497 11498 // morph attributes 11499 11500 const morphAttributes = source.morphAttributes; 11501 11502 for ( const name in morphAttributes ) { 11503 11504 const array = []; 11505 const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes 11506 11507 for ( let i = 0, l = morphAttribute.length; i < l; i ++ ) { 11508 11509 array.push( morphAttribute[ i ].clone( data ) ); 11510 11511 } 11512 11513 this.morphAttributes[ name ] = array; 11514 11515 } 11516 11517 this.morphTargetsRelative = source.morphTargetsRelative; 11518 11519 // groups 11520 11521 const groups = source.groups; 11522 11523 for ( let i = 0, l = groups.length; i < l; i ++ ) { 11524 11525 const group = groups[ i ]; 11526 this.addGroup( group.start, group.count, group.materialIndex ); 11527 11528 } 11529 11530 // bounding box 11531 11532 const boundingBox = source.boundingBox; 11533 11534 if ( boundingBox !== null ) { 11535 11536 this.boundingBox = boundingBox.clone(); 11537 11538 } 11539 11540 // bounding sphere 11541 11542 const boundingSphere = source.boundingSphere; 11543 11544 if ( boundingSphere !== null ) { 11545 11546 this.boundingSphere = boundingSphere.clone(); 11547 11548 } 11549 11550 // draw range 11551 11552 this.drawRange.start = source.drawRange.start; 11553 this.drawRange.count = source.drawRange.count; 11554 11555 // user data 11556 11557 this.userData = source.userData; 11558 11559 return this; 11560 11561 } 11562 11563 dispose() { 11564 11565 this.dispatchEvent( { type: 'dispose' } ); 11566 11567 } 11568 11569} 11570 11571const _inverseMatrix$3 = /*@__PURE__*/ new Matrix4(); 11572const _ray$3 = /*@__PURE__*/ new Ray(); 11573const _sphere$6 = /*@__PURE__*/ new Sphere(); 11574const _sphereHitAt = /*@__PURE__*/ new Vector3(); 11575 11576const _vA$1 = /*@__PURE__*/ new Vector3(); 11577const _vB$1 = /*@__PURE__*/ new Vector3(); 11578const _vC$1 = /*@__PURE__*/ new Vector3(); 11579 11580const _tempA = /*@__PURE__*/ new Vector3(); 11581const _morphA = /*@__PURE__*/ new Vector3(); 11582 11583const _uvA$1 = /*@__PURE__*/ new Vector2(); 11584const _uvB$1 = /*@__PURE__*/ new Vector2(); 11585const _uvC$1 = /*@__PURE__*/ new Vector2(); 11586 11587const _normalA = /*@__PURE__*/ new Vector3(); 11588const _normalB = /*@__PURE__*/ new Vector3(); 11589const _normalC = /*@__PURE__*/ new Vector3(); 11590 11591const _intersectionPoint = /*@__PURE__*/ new Vector3(); 11592const _intersectionPointWorld = /*@__PURE__*/ new Vector3(); 11593 11594class Mesh extends Object3D { 11595 11596 constructor( geometry = new BufferGeometry(), material = new MeshBasicMaterial() ) { 11597 11598 super(); 11599 11600 this.isMesh = true; 11601 11602 this.type = 'Mesh'; 11603 11604 this.geometry = geometry; 11605 this.material = material; 11606 11607 this.updateMorphTargets(); 11608 11609 } 11610 11611 copy( source, recursive ) { 11612 11613 super.copy( source, recursive ); 11614 11615 if ( source.morphTargetInfluences !== undefined ) { 11616 11617 this.morphTargetInfluences = source.morphTargetInfluences.slice(); 11618 11619 } 11620 11621 if ( source.morphTargetDictionary !== undefined ) { 11622 11623 this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary ); 11624 11625 } 11626 11627 this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; 11628 this.geometry = source.geometry; 11629 11630 return this; 11631 11632 } 11633 11634 updateMorphTargets() { 11635 11636 const geometry = this.geometry; 11637 11638 const morphAttributes = geometry.morphAttributes; 11639 const keys = Object.keys( morphAttributes ); 11640 11641 if ( keys.length > 0 ) { 11642 11643 const morphAttribute = morphAttributes[ keys[ 0 ] ]; 11644 11645 if ( morphAttribute !== undefined ) { 11646 11647 this.morphTargetInfluences = []; 11648 this.morphTargetDictionary = {}; 11649 11650 for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { 11651 11652 const name = morphAttribute[ m ].name || String( m ); 11653 11654 this.morphTargetInfluences.push( 0 ); 11655 this.morphTargetDictionary[ name ] = m; 11656 11657 } 11658 11659 } 11660 11661 } 11662 11663 } 11664 11665 getVertexPosition( index, target ) { 11666 11667 const geometry = this.geometry; 11668 const position = geometry.attributes.position; 11669 const morphPosition = geometry.morphAttributes.position; 11670 const morphTargetsRelative = geometry.morphTargetsRelative; 11671 11672 target.fromBufferAttribute( position, index ); 11673 11674 const morphInfluences = this.morphTargetInfluences; 11675 11676 if ( morphPosition && morphInfluences ) { 11677 11678 _morphA.set( 0, 0, 0 ); 11679 11680 for ( let i = 0, il = morphPosition.length; i < il; i ++ ) { 11681 11682 const influence = morphInfluences[ i ]; 11683 const morphAttribute = morphPosition[ i ]; 11684 11685 if ( influence === 0 ) continue; 11686 11687 _tempA.fromBufferAttribute( morphAttribute, index ); 11688 11689 if ( morphTargetsRelative ) { 11690 11691 _morphA.addScaledVector( _tempA, influence ); 11692 11693 } else { 11694 11695 _morphA.addScaledVector( _tempA.sub( target ), influence ); 11696 11697 } 11698 11699 } 11700 11701 target.add( _morphA ); 11702 11703 } 11704 11705 return target; 11706 11707 } 11708 11709 raycast( raycaster, intersects ) { 11710 11711 const geometry = this.geometry; 11712 const material = this.material; 11713 const matrixWorld = this.matrixWorld; 11714 11715 if ( material === undefined ) return; 11716
vendor: 6,665 bytes, lines 11717-11959
11717 // test with bounding sphere in world space 11718 11719 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); 11720 11721 _sphere$6.copy( geometry.boundingSphere ); 11722 _sphere$6.applyMatrix4( matrixWorld ); 11723 11724 // check distance from ray origin to bounding sphere 11725 11726 _ray$3.copy( raycaster.ray ).recast( raycaster.near ); 11727 11728 if ( _sphere$6.containsPoint( _ray$3.origin ) === false ) { 11729 11730 if ( _ray$3.intersectSphere( _sphere$6, _sphereHitAt ) === null ) return; 11731 11732 if ( _ray$3.origin.distanceToSquared( _sphereHitAt ) > ( raycaster.far - raycaster.near ) ** 2 ) return; 11733 11734 } 11735 11736 // convert ray to local space of mesh 11737 11738 _inverseMatrix$3.copy( matrixWorld ).invert(); 11739 _ray$3.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$3 ); 11740 11741 // test with bounding box in local space 11742 11743 if ( geometry.boundingBox !== null ) { 11744 11745 if ( _ray$3.intersectsBox( geometry.boundingBox ) === false ) return; 11746 11747 } 11748 11749 // test for intersections with geometry 11750 11751 this._computeIntersections( raycaster, intersects, _ray$3 ); 11752 11753 } 11754 11755 _computeIntersections( raycaster, intersects, rayLocalSpace ) { 11756 11757 let intersection; 11758 11759 const geometry = this.geometry; 11760 const material = this.material; 11761 11762 const index = geometry.index; 11763 const position = geometry.attributes.position; 11764 const uv = geometry.attributes.uv; 11765 const uv1 = geometry.attributes.uv1; 11766 const normal = geometry.attributes.normal; 11767 const groups = geometry.groups; 11768 const drawRange = geometry.drawRange; 11769 11770 if ( index !== null ) { 11771 11772 // indexed buffer geometry 11773 11774 if ( Array.isArray( material ) ) { 11775 11776 for ( let i = 0, il = groups.length; i < il; i ++ ) { 11777 11778 const group = groups[ i ]; 11779 const groupMaterial = material[ group.materialIndex ]; 11780 11781 const start = Math.max( group.start, drawRange.start ); 11782 const end = Math.min( index.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) ); 11783 11784 for ( let j = start, jl = end; j < jl; j += 3 ) { 11785 11786 const a = index.getX( j ); 11787 const b = index.getX( j + 1 ); 11788 const c = index.getX( j + 2 ); 11789 11790 intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); 11791 11792 if ( intersection ) { 11793 11794 intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics 11795 intersection.face.materialIndex = group.materialIndex; 11796 intersects.push( intersection ); 11797 11798 } 11799 11800 } 11801 11802 } 11803 11804 } else { 11805 11806 const start = Math.max( 0, drawRange.start ); 11807 const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); 11808 11809 for ( let i = start, il = end; i < il; i += 3 ) { 11810 11811 const a = index.getX( i ); 11812 const b = index.getX( i + 1 ); 11813 const c = index.getX( i + 2 ); 11814 11815 intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); 11816 11817 if ( intersection ) { 11818 11819 intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics 11820 intersects.push( intersection ); 11821 11822 } 11823 11824 } 11825 11826 } 11827 11828 } else if ( position !== undefined ) { 11829 11830 // non-indexed buffer geometry 11831 11832 if ( Array.isArray( material ) ) { 11833 11834 for ( let i = 0, il = groups.length; i < il; i ++ ) { 11835 11836 const group = groups[ i ]; 11837 const groupMaterial = material[ group.materialIndex ]; 11838 11839 const start = Math.max( group.start, drawRange.start ); 11840 const end = Math.min( position.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) ); 11841 11842 for ( let j = start, jl = end; j < jl; j += 3 ) { 11843 11844 const a = j; 11845 const b = j + 1; 11846 const c = j + 2; 11847 11848 intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); 11849 11850 if ( intersection ) { 11851 11852 intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics 11853 intersection.face.materialIndex = group.materialIndex; 11854 intersects.push( intersection ); 11855 11856 } 11857 11858 } 11859 11860 } 11861 11862 } else { 11863 11864 const start = Math.max( 0, drawRange.start ); 11865 const end = Math.min( position.count, ( drawRange.start + drawRange.count ) ); 11866 11867 for ( let i = start, il = end; i < il; i += 3 ) { 11868 11869 const a = i; 11870 const b = i + 1; 11871 const c = i + 2; 11872 11873 intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); 11874 11875 if ( intersection ) { 11876 11877 intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics 11878 intersects.push( intersection ); 11879 11880 } 11881 11882 } 11883 11884 } 11885 11886 } 11887 11888 } 11889 11890} 11891 11892function checkIntersection( object, material, raycaster, ray, pA, pB, pC, point ) { 11893 11894 let intersect; 11895 11896 if ( material.side === BackSide ) { 11897 11898 intersect = ray.intersectTriangle( pC, pB, pA, true, point ); 11899 11900 } else { 11901 11902 intersect = ray.intersectTriangle( pA, pB, pC, ( material.side === FrontSide ), point ); 11903 11904 } 11905 11906 if ( intersect === null ) return null; 11907 11908 _intersectionPointWorld.copy( point ); 11909 _intersectionPointWorld.applyMatrix4( object.matrixWorld ); 11910 11911 const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld ); 11912 11913 if ( distance < raycaster.near || distance > raycaster.far ) return null; 11914 11915 return { 11916 distance: distance, 11917 point: _intersectionPointWorld.clone(), 11918 object: object 11919 }; 11920 11921} 11922 11923function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, normal, a, b, c ) { 11924 11925 object.getVertexPosition( a, _vA$1 ); 11926 object.getVertexPosition( b, _vB$1 ); 11927 object.getVertexPosition( c, _vC$1 ); 11928 11929 const intersection = checkIntersection( object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint ); 11930 11931 if ( intersection ) { 11932 11933 if ( uv ) { 11934 11935 _uvA$1.fromBufferAttribute( uv, a ); 11936 _uvB$1.fromBufferAttribute( uv, b ); 11937 _uvC$1.fromBufferAttribute( uv, c ); 11938 11939 intersection.uv = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); 11940 11941 } 11942 11943 if ( uv1 ) { 11944 11945 _uvA$1.fromBufferAttribute( uv1, a ); 11946 _uvB$1.fromBufferAttribute( uv1, b ); 11947 _uvC$1.fromBufferAttribute( uv1, c ); 11948 11949 intersection.uv1 = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); 11950 intersection.uv2 = intersection.uv1; // @deprecated, r152 11951 11952 } 11953 11954 if ( normal ) { 11955 11956 _normalA.fromBufferAttribute( normal, a ); 11957 _normalB.fromBufferAttribute( normal, b ); 11958 _normalC.fromBufferAttribute( normal, c ); 11959
vendor: 43,307 bytes, lines 11960-13849
11960 intersection.normal = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _normalA, _normalB, _normalC, new Vector3() ); 11961 11962 if ( intersection.normal.dot( ray.direction ) > 0 ) { 11963 11964 intersection.normal.multiplyScalar( - 1 ); 11965 11966 } 11967 11968 } 11969 11970 const face = { 11971 a: a, 11972 b: b, 11973 c: c, 11974 normal: new Vector3(), 11975 materialIndex: 0 11976 }; 11977 11978 Triangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal ); 11979 11980 intersection.face = face; 11981 11982 } 11983 11984 return intersection; 11985 11986} 11987 11988class BoxGeometry extends BufferGeometry { 11989 11990 constructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) { 11991 11992 super(); 11993 11994 this.type = 'BoxGeometry'; 11995 11996 this.parameters = { 11997 width: width, 11998 height: height, 11999 depth: depth, 12000 widthSegments: widthSegments, 12001 heightSegments: heightSegments, 12002 depthSegments: depthSegments 12003 }; 12004 12005 const scope = this; 12006 12007 // segments 12008 12009 widthSegments = Math.floor( widthSegments ); 12010 heightSegments = Math.floor( heightSegments ); 12011 depthSegments = Math.floor( depthSegments ); 12012 12013 12014 // buffers 12015 12016 const indices = []; 12017 const vertices = []; 12018 const normals = []; 12019 const uvs = []; 12020 12021 // helper variables 12022 12023 let numberOfVertices = 0; 12024 let groupStart = 0; 12025 12026 // build each side of the box geometry 12027 12028 buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px 12029 buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx 12030 buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py 12031 buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny 12032 buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz 12033 buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz 12034 12035 // build geometry 12036 12037 this.setIndex( indices ); 12038 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 12039 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 12040 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 12041 12042 function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) { 12043 12044 const segmentWidth = width / gridX; 12045 const segmentHeight = height / gridY; 12046 12047 const widthHalf = width / 2; 12048 const heightHalf = height / 2; 12049 const depthHalf = depth / 2; 12050 12051 const gridX1 = gridX + 1; 12052 const gridY1 = gridY + 1; 12053 12054 let vertexCounter = 0; 12055 let groupCount = 0; 12056 12057 const vector = new Vector3(); 12058 12059 // generate vertices, normals and uvs 12060 12061 for ( let iy = 0; iy < gridY1; iy ++ ) { 12062 12063 const y = iy * segmentHeight - heightHalf; 12064 12065 for ( let ix = 0; ix < gridX1; ix ++ ) { 12066 12067 const x = ix * segmentWidth - widthHalf; 12068 12069 // set values to correct vector component 12070 12071 vector[ u ] = x * udir; 12072 vector[ v ] = y * vdir; 12073 vector[ w ] = depthHalf; 12074 12075 // now apply vector to vertex buffer 12076 12077 vertices.push( vector.x, vector.y, vector.z ); 12078 12079 // set values to correct vector component 12080 12081 vector[ u ] = 0; 12082 vector[ v ] = 0; 12083 vector[ w ] = depth > 0 ? 1 : - 1; 12084 12085 // now apply vector to normal buffer 12086 12087 normals.push( vector.x, vector.y, vector.z ); 12088 12089 // uvs 12090 12091 uvs.push( ix / gridX ); 12092 uvs.push( 1 - ( iy / gridY ) ); 12093 12094 // counters 12095 12096 vertexCounter += 1; 12097 12098 } 12099 12100 } 12101 12102 // indices 12103 12104 // 1. you need three indices to draw a single face 12105 // 2. a single segment consists of two faces 12106 // 3. so we need to generate six (2*3) indices per segment 12107 12108 for ( let iy = 0; iy < gridY; iy ++ ) { 12109 12110 for ( let ix = 0; ix < gridX; ix ++ ) { 12111 12112 const a = numberOfVertices + ix + gridX1 * iy; 12113 const b = numberOfVertices + ix + gridX1 * ( iy + 1 ); 12114 const c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 ); 12115 const d = numberOfVertices + ( ix + 1 ) + gridX1 * iy; 12116 12117 // faces 12118 12119 indices.push( a, b, d ); 12120 indices.push( b, c, d ); 12121 12122 // increase counter 12123 12124 groupCount += 6; 12125 12126 } 12127 12128 } 12129 12130 // add a group to the geometry. this will ensure multi material support 12131 12132 scope.addGroup( groupStart, groupCount, materialIndex ); 12133 12134 // calculate new start value for groups 12135 12136 groupStart += groupCount; 12137 12138 // update total number of vertices 12139 12140 numberOfVertices += vertexCounter; 12141 12142 } 12143 12144 } 12145 12146 copy( source ) { 12147 12148 super.copy( source ); 12149 12150 this.parameters = Object.assign( {}, source.parameters ); 12151 12152 return this; 12153 12154 } 12155 12156 static fromJSON( data ) { 12157 12158 return new BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments ); 12159 12160 } 12161 12162} 12163 12164/** 12165 * Uniform Utilities 12166 */ 12167 12168function cloneUniforms( src ) { 12169 12170 const dst = {}; 12171 12172 for ( const u in src ) { 12173 12174 dst[ u ] = {}; 12175 12176 for ( const p in src[ u ] ) { 12177 12178 const property = src[ u ][ p ]; 12179 12180 if ( property && ( property.isColor || 12181 property.isMatrix3 || property.isMatrix4 || 12182 property.isVector2 || property.isVector3 || property.isVector4 || 12183 property.isTexture || property.isQuaternion ) ) { 12184 12185 if ( property.isRenderTargetTexture ) { 12186 12187 console.warn( 'UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().' ); 12188 dst[ u ][ p ] = null; 12189 12190 } else { 12191 12192 dst[ u ][ p ] = property.clone(); 12193 12194 } 12195 12196 } else if ( Array.isArray( property ) ) { 12197 12198 dst[ u ][ p ] = property.slice(); 12199 12200 } else { 12201 12202 dst[ u ][ p ] = property; 12203 12204 } 12205 12206 } 12207 12208 } 12209 12210 return dst; 12211 12212} 12213 12214function mergeUniforms( uniforms ) { 12215 12216 const merged = {}; 12217 12218 for ( let u = 0; u < uniforms.length; u ++ ) { 12219 12220 const tmp = cloneUniforms( uniforms[ u ] ); 12221 12222 for ( const p in tmp ) { 12223 12224 merged[ p ] = tmp[ p ]; 12225 12226 } 12227 12228 } 12229 12230 return merged; 12231 12232} 12233 12234function cloneUniformsGroups( src ) { 12235 12236 const dst = []; 12237 12238 for ( let u = 0; u < src.length; u ++ ) { 12239 12240 dst.push( src[ u ].clone() ); 12241 12242 } 12243 12244 return dst; 12245 12246} 12247 12248function getUnlitUniformColorSpace( renderer ) { 12249 12250 if ( renderer.getRenderTarget() === null ) { 12251 12252 // https://github.com/mrdoob/three.js/pull/23937#issuecomment-1111067398 12253 return renderer.outputColorSpace; 12254 12255 } 12256 12257 return ColorManagement.workingColorSpace; 12258 12259} 12260 12261// Legacy 12262 12263const UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms }; 12264 12265var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}"; 12266 12267var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}"; 12268 12269class ShaderMaterial extends Material { 12270 12271 constructor( parameters ) { 12272 12273 super(); 12274 12275 this.isShaderMaterial = true; 12276 12277 this.type = 'ShaderMaterial'; 12278 12279 this.defines = {}; 12280 this.uniforms = {}; 12281 this.uniformsGroups = []; 12282 12283 this.vertexShader = default_vertex; 12284 this.fragmentShader = default_fragment; 12285 12286 this.linewidth = 1; 12287 12288 this.wireframe = false; 12289 this.wireframeLinewidth = 1; 12290 12291 this.fog = false; // set to use scene fog 12292 this.lights = false; // set to use scene lights 12293 this.clipping = false; // set to use user-defined clipping planes 12294 12295 this.forceSinglePass = true; 12296 12297 this.extensions = { 12298 derivatives: false, // set to use derivatives 12299 fragDepth: false, // set to use fragment depth values 12300 drawBuffers: false, // set to use draw buffers 12301 shaderTextureLOD: false, // set to use shader texture LOD 12302 clipCullDistance: false // set to use vertex shader clipping 12303 }; 12304 12305 // When rendered geometry doesn't include these attributes but the material does, 12306 // use these default values in WebGL. This avoids errors when buffer data is missing. 12307 this.defaultAttributeValues = { 12308 'color': [ 1, 1, 1 ], 12309 'uv': [ 0, 0 ], 12310 'uv1': [ 0, 0 ] 12311 }; 12312 12313 this.index0AttributeName = undefined; 12314 this.uniformsNeedUpdate = false; 12315 12316 this.glslVersion = null; 12317 12318 if ( parameters !== undefined ) { 12319 12320 this.setValues( parameters ); 12321 12322 } 12323 12324 } 12325 12326 copy( source ) { 12327 12328 super.copy( source ); 12329 12330 this.fragmentShader = source.fragmentShader; 12331 this.vertexShader = source.vertexShader; 12332 12333 this.uniforms = cloneUniforms( source.uniforms ); 12334 this.uniformsGroups = cloneUniformsGroups( source.uniformsGroups ); 12335 12336 this.defines = Object.assign( {}, source.defines ); 12337 12338 this.wireframe = source.wireframe; 12339 this.wireframeLinewidth = source.wireframeLinewidth; 12340 12341 this.fog = source.fog; 12342 this.lights = source.lights; 12343 this.clipping = source.clipping; 12344 12345 this.extensions = Object.assign( {}, source.extensions ); 12346 12347 this.glslVersion = source.glslVersion; 12348 12349 return this; 12350 12351 } 12352 12353 toJSON( meta ) { 12354 12355 const data = super.toJSON( meta ); 12356 12357 data.glslVersion = this.glslVersion; 12358 data.uniforms = {}; 12359 12360 for ( const name in this.uniforms ) { 12361 12362 const uniform = this.uniforms[ name ]; 12363 const value = uniform.value; 12364 12365 if ( value && value.isTexture ) { 12366 12367 data.uniforms[ name ] = { 12368 type: 't', 12369 value: value.toJSON( meta ).uuid 12370 }; 12371 12372 } else if ( value && value.isColor ) { 12373 12374 data.uniforms[ name ] = { 12375 type: 'c', 12376 value: value.getHex() 12377 }; 12378 12379 } else if ( value && value.isVector2 ) { 12380 12381 data.uniforms[ name ] = { 12382 type: 'v2', 12383 value: value.toArray() 12384 }; 12385 12386 } else if ( value && value.isVector3 ) { 12387 12388 data.uniforms[ name ] = { 12389 type: 'v3', 12390 value: value.toArray() 12391 }; 12392 12393 } else if ( value && value.isVector4 ) { 12394 12395 data.uniforms[ name ] = { 12396 type: 'v4', 12397 value: value.toArray() 12398 }; 12399 12400 } else if ( value && value.isMatrix3 ) { 12401 12402 data.uniforms[ name ] = { 12403 type: 'm3', 12404 value: value.toArray() 12405 }; 12406 12407 } else if ( value && value.isMatrix4 ) { 12408 12409 data.uniforms[ name ] = { 12410 type: 'm4', 12411 value: value.toArray() 12412 }; 12413 12414 } else { 12415 12416 data.uniforms[ name ] = { 12417 value: value 12418 }; 12419 12420 // note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far 12421 12422 } 12423 12424 } 12425 12426 if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines; 12427 12428 data.vertexShader = this.vertexShader; 12429 data.fragmentShader = this.fragmentShader; 12430 12431 data.lights = this.lights; 12432 data.clipping = this.clipping; 12433 12434 const extensions = {}; 12435 12436 for ( const key in this.extensions ) { 12437 12438 if ( this.extensions[ key ] === true ) extensions[ key ] = true; 12439 12440 } 12441 12442 if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions; 12443 12444 return data; 12445 12446 } 12447 12448} 12449 12450class Camera extends Object3D { 12451 12452 constructor() { 12453 12454 super(); 12455 12456 this.isCamera = true; 12457 12458 this.type = 'Camera'; 12459 12460 this.matrixWorldInverse = new Matrix4(); 12461 12462 this.projectionMatrix = new Matrix4(); 12463 this.projectionMatrixInverse = new Matrix4(); 12464 12465 this.coordinateSystem = WebGLCoordinateSystem; 12466 12467 } 12468 12469 copy( source, recursive ) { 12470 12471 super.copy( source, recursive ); 12472 12473 this.matrixWorldInverse.copy( source.matrixWorldInverse ); 12474 12475 this.projectionMatrix.copy( source.projectionMatrix ); 12476 this.projectionMatrixInverse.copy( source.projectionMatrixInverse ); 12477 12478 this.coordinateSystem = source.coordinateSystem; 12479 12480 return this; 12481 12482 } 12483 12484 getWorldDirection( target ) { 12485 12486 return super.getWorldDirection( target ).negate(); 12487 12488 } 12489 12490 updateMatrixWorld( force ) { 12491 12492 super.updateMatrixWorld( force ); 12493 12494 this.matrixWorldInverse.copy( this.matrixWorld ).invert(); 12495 12496 } 12497 12498 updateWorldMatrix( updateParents, updateChildren ) { 12499 12500 super.updateWorldMatrix( updateParents, updateChildren ); 12501 12502 this.matrixWorldInverse.copy( this.matrixWorld ).invert(); 12503 12504 } 12505 12506 clone() { 12507 12508 return new this.constructor().copy( this ); 12509 12510 } 12511 12512} 12513 12514class PerspectiveCamera extends Camera { 12515 12516 constructor( fov = 50, aspect = 1, near = 0.1, far = 2000 ) { 12517 12518 super(); 12519 12520 this.isPerspectiveCamera = true; 12521 12522 this.type = 'PerspectiveCamera'; 12523 12524 this.fov = fov; 12525 this.zoom = 1; 12526 12527 this.near = near; 12528 this.far = far; 12529 this.focus = 10; 12530 12531 this.aspect = aspect; 12532 this.view = null; 12533 12534 this.filmGauge = 35; // width of the film (default in millimeters) 12535 this.filmOffset = 0; // horizontal film offset (same unit as gauge) 12536 12537 this.updateProjectionMatrix(); 12538 12539 } 12540 12541 copy( source, recursive ) { 12542 12543 super.copy( source, recursive ); 12544 12545 this.fov = source.fov; 12546 this.zoom = source.zoom; 12547 12548 this.near = source.near; 12549 this.far = source.far; 12550 this.focus = source.focus; 12551 12552 this.aspect = source.aspect; 12553 this.view = source.view === null ? null : Object.assign( {}, source.view ); 12554 12555 this.filmGauge = source.filmGauge; 12556 this.filmOffset = source.filmOffset; 12557 12558 return this; 12559 12560 } 12561 12562 /** 12563 * Sets the FOV by focal length in respect to the current .filmGauge. 12564 * 12565 * The default film gauge is 35, so that the focal length can be specified for 12566 * a 35mm (full frame) camera. 12567 * 12568 * Values for focal length and film gauge must have the same unit. 12569 */ 12570 setFocalLength( focalLength ) { 12571 12572 /** see {@link http://www.bobatkins.com/photography/technical/field_of_view.html} */ 12573 const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength; 12574 12575 this.fov = RAD2DEG * 2 * Math.atan( vExtentSlope ); 12576 this.updateProjectionMatrix(); 12577 12578 } 12579 12580 /** 12581 * Calculates the focal length from the current .fov and .filmGauge. 12582 */ 12583 getFocalLength() { 12584 12585 const vExtentSlope = Math.tan( DEG2RAD * 0.5 * this.fov ); 12586 12587 return 0.5 * this.getFilmHeight() / vExtentSlope; 12588 12589 } 12590 12591 getEffectiveFOV() { 12592 12593 return RAD2DEG * 2 * Math.atan( 12594 Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom ); 12595 12596 } 12597 12598 getFilmWidth() { 12599 12600 // film not completely covered in portrait format (aspect < 1) 12601 return this.filmGauge * Math.min( this.aspect, 1 ); 12602 12603 } 12604 12605 getFilmHeight() { 12606 12607 // film not completely covered in landscape format (aspect > 1) 12608 return this.filmGauge / Math.max( this.aspect, 1 ); 12609 12610 } 12611 12612 /** 12613 * Sets an offset in a larger frustum. This is useful for multi-window or 12614 * multi-monitor/multi-machine setups. 12615 * 12616 * For example, if you have 3x2 monitors and each monitor is 1920x1080 and 12617 * the monitors are in grid like this 12618 * 12619 * +---+---+---+ 12620 * | A | B | C | 12621 * +---+---+---+ 12622 * | D | E | F | 12623 * +---+---+---+ 12624 * 12625 * then for each monitor you would call it like this 12626 * 12627 * const w = 1920; 12628 * const h = 1080; 12629 * const fullWidth = w * 3; 12630 * const fullHeight = h * 2; 12631 * 12632 * --A-- 12633 * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); 12634 * --B-- 12635 * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); 12636 * --C-- 12637 * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); 12638 * --D-- 12639 * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); 12640 * --E-- 12641 * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); 12642 * --F-- 12643 * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); 12644 * 12645 * Note there is no reason monitors have to be the same size or in a grid. 12646 */ 12647 setViewOffset( fullWidth, fullHeight, x, y, width, height ) { 12648 12649 this.aspect = fullWidth / fullHeight; 12650 12651 if ( this.view === null ) { 12652 12653 this.view = { 12654 enabled: true, 12655 fullWidth: 1, 12656 fullHeight: 1, 12657 offsetX: 0, 12658 offsetY: 0, 12659 width: 1, 12660 height: 1 12661 }; 12662 12663 } 12664 12665 this.view.enabled = true; 12666 this.view.fullWidth = fullWidth; 12667 this.view.fullHeight = fullHeight; 12668 this.view.offsetX = x; 12669 this.view.offsetY = y; 12670 this.view.width = width; 12671 this.view.height = height; 12672 12673 this.updateProjectionMatrix(); 12674 12675 } 12676 12677 clearViewOffset() { 12678 12679 if ( this.view !== null ) { 12680 12681 this.view.enabled = false; 12682 12683 } 12684 12685 this.updateProjectionMatrix(); 12686 12687 } 12688 12689 updateProjectionMatrix() { 12690 12691 const near = this.near; 12692 let top = near * Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom; 12693 let height = 2 * top; 12694 let width = this.aspect * height; 12695 let left = - 0.5 * width; 12696 const view = this.view; 12697 12698 if ( this.view !== null && this.view.enabled ) { 12699 12700 const fullWidth = view.fullWidth, 12701 fullHeight = view.fullHeight; 12702 12703 left += view.offsetX * width / fullWidth; 12704 top -= view.offsetY * height / fullHeight; 12705 width *= view.width / fullWidth; 12706 height *= view.height / fullHeight; 12707 12708 } 12709 12710 const skew = this.filmOffset; 12711 if ( skew !== 0 ) left += near * skew / this.getFilmWidth(); 12712 12713 this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far, this.coordinateSystem ); 12714 12715 this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); 12716 12717 } 12718 12719 toJSON( meta ) { 12720 12721 const data = super.toJSON( meta ); 12722 12723 data.object.fov = this.fov; 12724 data.object.zoom = this.zoom; 12725 12726 data.object.near = this.near; 12727 data.object.far = this.far; 12728 data.object.focus = this.focus; 12729 12730 data.object.aspect = this.aspect; 12731 12732 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); 12733 12734 data.object.filmGauge = this.filmGauge; 12735 data.object.filmOffset = this.filmOffset; 12736 12737 return data; 12738 12739 } 12740 12741} 12742 12743const fov = - 90; // negative fov is not an error 12744const aspect = 1; 12745 12746class CubeCamera extends Object3D { 12747 12748 constructor( near, far, renderTarget ) { 12749 12750 super(); 12751 12752 this.type = 'CubeCamera'; 12753 12754 this.renderTarget = renderTarget; 12755 this.coordinateSystem = null; 12756 this.activeMipmapLevel = 0; 12757 12758 const cameraPX = new PerspectiveCamera( fov, aspect, near, far ); 12759 cameraPX.layers = this.layers; 12760 this.add( cameraPX ); 12761 12762 const cameraNX = new PerspectiveCamera( fov, aspect, near, far ); 12763 cameraNX.layers = this.layers; 12764 this.add( cameraNX ); 12765 12766 const cameraPY = new PerspectiveCamera( fov, aspect, near, far ); 12767 cameraPY.layers = this.layers; 12768 this.add( cameraPY ); 12769 12770 const cameraNY = new PerspectiveCamera( fov, aspect, near, far ); 12771 cameraNY.layers = this.layers; 12772 this.add( cameraNY ); 12773 12774 const cameraPZ = new PerspectiveCamera( fov, aspect, near, far ); 12775 cameraPZ.layers = this.layers; 12776 this.add( cameraPZ ); 12777 12778 const cameraNZ = new PerspectiveCamera( fov, aspect, near, far ); 12779 cameraNZ.layers = this.layers; 12780 this.add( cameraNZ ); 12781 12782 } 12783 12784 updateCoordinateSystem() { 12785 12786 const coordinateSystem = this.coordinateSystem; 12787 12788 const cameras = this.children.concat(); 12789 12790 const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = cameras; 12791 12792 for ( const camera of cameras ) this.remove( camera ); 12793 12794 if ( coordinateSystem === WebGLCoordinateSystem ) { 12795 12796 cameraPX.up.set( 0, 1, 0 ); 12797 cameraPX.lookAt( 1, 0, 0 ); 12798 12799 cameraNX.up.set( 0, 1, 0 ); 12800 cameraNX.lookAt( - 1, 0, 0 ); 12801 12802 cameraPY.up.set( 0, 0, - 1 ); 12803 cameraPY.lookAt( 0, 1, 0 ); 12804 12805 cameraNY.up.set( 0, 0, 1 ); 12806 cameraNY.lookAt( 0, - 1, 0 ); 12807 12808 cameraPZ.up.set( 0, 1, 0 ); 12809 cameraPZ.lookAt( 0, 0, 1 ); 12810 12811 cameraNZ.up.set( 0, 1, 0 ); 12812 cameraNZ.lookAt( 0, 0, - 1 ); 12813 12814 } else if ( coordinateSystem === WebGPUCoordinateSystem ) { 12815 12816 cameraPX.up.set( 0, - 1, 0 ); 12817 cameraPX.lookAt( - 1, 0, 0 ); 12818 12819 cameraNX.up.set( 0, - 1, 0 ); 12820 cameraNX.lookAt( 1, 0, 0 ); 12821 12822 cameraPY.up.set( 0, 0, 1 ); 12823 cameraPY.lookAt( 0, 1, 0 ); 12824 12825 cameraNY.up.set( 0, 0, - 1 ); 12826 cameraNY.lookAt( 0, - 1, 0 ); 12827 12828 cameraPZ.up.set( 0, - 1, 0 ); 12829 cameraPZ.lookAt( 0, 0, 1 ); 12830 12831 cameraNZ.up.set( 0, - 1, 0 ); 12832 cameraNZ.lookAt( 0, 0, - 1 ); 12833 12834 } else { 12835 12836 throw new Error( 'THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: ' + coordinateSystem ); 12837 12838 } 12839 12840 for ( const camera of cameras ) { 12841 12842 this.add( camera ); 12843 12844 camera.updateMatrixWorld(); 12845 12846 } 12847 12848 } 12849 12850 update( renderer, scene ) { 12851 12852 if ( this.parent === null ) this.updateMatrixWorld(); 12853 12854 const { renderTarget, activeMipmapLevel } = this; 12855 12856 if ( this.coordinateSystem !== renderer.coordinateSystem ) { 12857 12858 this.coordinateSystem = renderer.coordinateSystem; 12859 12860 this.updateCoordinateSystem(); 12861 12862 } 12863 12864 const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = this.children; 12865 12866 const currentRenderTarget = renderer.getRenderTarget(); 12867 const currentActiveCubeFace = renderer.getActiveCubeFace(); 12868 const currentActiveMipmapLevel = renderer.getActiveMipmapLevel(); 12869 12870 const currentXrEnabled = renderer.xr.enabled; 12871 12872 renderer.xr.enabled = false; 12873 12874 const generateMipmaps = renderTarget.texture.generateMipmaps; 12875 12876 renderTarget.texture.generateMipmaps = false; 12877 12878 renderer.setRenderTarget( renderTarget, 0, activeMipmapLevel ); 12879 renderer.render( scene, cameraPX ); 12880 12881 renderer.setRenderTarget( renderTarget, 1, activeMipmapLevel ); 12882 renderer.render( scene, cameraNX ); 12883 12884 renderer.setRenderTarget( renderTarget, 2, activeMipmapLevel ); 12885 renderer.render( scene, cameraPY ); 12886 12887 renderer.setRenderTarget( renderTarget, 3, activeMipmapLevel ); 12888 renderer.render( scene, cameraNY ); 12889 12890 renderer.setRenderTarget( renderTarget, 4, activeMipmapLevel ); 12891 renderer.render( scene, cameraPZ ); 12892 12893 // mipmaps are generated during the last call of render() 12894 // at this point, all sides of the cube render target are defined 12895 12896 renderTarget.texture.generateMipmaps = generateMipmaps; 12897 12898 renderer.setRenderTarget( renderTarget, 5, activeMipmapLevel ); 12899 renderer.render( scene, cameraNZ ); 12900 12901 renderer.setRenderTarget( currentRenderTarget, currentActiveCubeFace, currentActiveMipmapLevel ); 12902 12903 renderer.xr.enabled = currentXrEnabled; 12904 12905 renderTarget.texture.needsPMREMUpdate = true; 12906 12907 } 12908 12909} 12910 12911class CubeTexture extends Texture { 12912 12913 constructor( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ) { 12914 12915 images = images !== undefined ? images : []; 12916 mapping = mapping !== undefined ? mapping : CubeReflectionMapping; 12917 12918 super( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ); 12919 12920 this.isCubeTexture = true; 12921 12922 this.flipY = false; 12923 12924 } 12925 12926 get images() { 12927 12928 return this.image; 12929 12930 } 12931 12932 set images( value ) { 12933 12934 this.image = value; 12935 12936 } 12937 12938} 12939 12940class WebGLCubeRenderTarget extends WebGLRenderTarget { 12941 12942 constructor( size = 1, options = {} ) { 12943 12944 super( size, size, options ); 12945 12946 this.isWebGLCubeRenderTarget = true; 12947 12948 const image = { width: size, height: size, depth: 1 }; 12949 const images = [ image, image, image, image, image, image ]; 12950 12951 if ( options.encoding !== undefined ) { 12952 12953 // @deprecated, r152 12954 warnOnce( 'THREE.WebGLCubeRenderTarget: option.encoding has been replaced by option.colorSpace.' ); 12955 options.colorSpace = options.encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace; 12956 12957 } 12958 12959 this.texture = new CubeTexture( images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace ); 12960 12961 // By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js) 12962 // in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words, 12963 // in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly. 12964 12965 // three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped 12966 // and the flag isRenderTargetTexture controls this conversion. The flip is not required when using WebGLCubeRenderTarget.texture 12967 // as a cube texture (this is detected when isRenderTargetTexture is set to true for cube textures). 12968 12969 this.texture.isRenderTargetTexture = true; 12970 12971 this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; 12972 this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter; 12973 12974 } 12975 12976 fromEquirectangularTexture( renderer, texture ) { 12977 12978 this.texture.type = texture.type; 12979 this.texture.colorSpace = texture.colorSpace; 12980 12981 this.texture.generateMipmaps = texture.generateMipmaps; 12982 this.texture.minFilter = texture.minFilter; 12983 this.texture.magFilter = texture.magFilter; 12984 12985 const shader = { 12986 12987 uniforms: { 12988 tEquirect: { value: null }, 12989 }, 12990 12991 vertexShader: /* glsl */` 12992 12993 varying vec3 vWorldDirection; 12994 12995 vec3 transformDirection( in vec3 dir, in mat4 matrix ) { 12996 12997 return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); 12998 12999 } 13000 13001 void main() { 13002 13003 vWorldDirection = transformDirection( position, modelMatrix ); 13004 13005 #include <begin_vertex> 13006 #include <project_vertex> 13007 13008 } 13009 `, 13010 13011 fragmentShader: /* glsl */` 13012 13013 uniform sampler2D tEquirect; 13014 13015 varying vec3 vWorldDirection; 13016 13017 #include <common> 13018 13019 void main() { 13020 13021 vec3 direction = normalize( vWorldDirection ); 13022 13023 vec2 sampleUV = equirectUv( direction ); 13024 13025 gl_FragColor = texture2D( tEquirect, sampleUV ); 13026 13027 } 13028 ` 13029 }; 13030 13031 const geometry = new BoxGeometry( 5, 5, 5 ); 13032 13033 const material = new ShaderMaterial( { 13034 13035 name: 'CubemapFromEquirect', 13036 13037 uniforms: cloneUniforms( shader.uniforms ), 13038 vertexShader: shader.vertexShader, 13039 fragmentShader: shader.fragmentShader, 13040 side: BackSide, 13041 blending: NoBlending 13042 13043 } ); 13044 13045 material.uniforms.tEquirect.value = texture; 13046 13047 const mesh = new Mesh( geometry, material ); 13048 13049 const currentMinFilter = texture.minFilter; 13050 13051 // Avoid blurred poles 13052 if ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter; 13053 13054 const camera = new CubeCamera( 1, 10, this ); 13055 camera.update( renderer, mesh ); 13056 13057 texture.minFilter = currentMinFilter; 13058 13059 mesh.geometry.dispose(); 13060 mesh.material.dispose(); 13061 13062 return this; 13063 13064 } 13065 13066 clear( renderer, color, depth, stencil ) { 13067 13068 const currentRenderTarget = renderer.getRenderTarget(); 13069 13070 for ( let i = 0; i < 6; i ++ ) { 13071 13072 renderer.setRenderTarget( this, i ); 13073 13074 renderer.clear( color, depth, stencil ); 13075 13076 } 13077 13078 renderer.setRenderTarget( currentRenderTarget ); 13079 13080 } 13081 13082} 13083 13084const _vector1 = /*@__PURE__*/ new Vector3(); 13085const _vector2 = /*@__PURE__*/ new Vector3(); 13086const _normalMatrix = /*@__PURE__*/ new Matrix3(); 13087 13088class Plane { 13089 13090 constructor( normal = new Vector3( 1, 0, 0 ), constant = 0 ) { 13091 13092 this.isPlane = true; 13093 13094 // normal is assumed to be normalized 13095 13096 this.normal = normal; 13097 this.constant = constant; 13098 13099 } 13100 13101 set( normal, constant ) { 13102 13103 this.normal.copy( normal ); 13104 this.constant = constant; 13105 13106 return this; 13107 13108 } 13109 13110 setComponents( x, y, z, w ) { 13111 13112 this.normal.set( x, y, z ); 13113 this.constant = w; 13114 13115 return this; 13116 13117 } 13118 13119 setFromNormalAndCoplanarPoint( normal, point ) { 13120 13121 this.normal.copy( normal ); 13122 this.constant = - point.dot( this.normal ); 13123 13124 return this; 13125 13126 } 13127 13128 setFromCoplanarPoints( a, b, c ) { 13129 13130 const normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize(); 13131 13132 // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? 13133 13134 this.setFromNormalAndCoplanarPoint( normal, a ); 13135 13136 return this; 13137 13138 } 13139 13140 copy( plane ) { 13141 13142 this.normal.copy( plane.normal ); 13143 this.constant = plane.constant; 13144 13145 return this; 13146 13147 } 13148 13149 normalize() { 13150 13151 // Note: will lead to a divide by zero if the plane is invalid. 13152 13153 const inverseNormalLength = 1.0 / this.normal.length(); 13154 this.normal.multiplyScalar( inverseNormalLength ); 13155 this.constant *= inverseNormalLength; 13156 13157 return this; 13158 13159 } 13160 13161 negate() { 13162 13163 this.constant *= - 1; 13164 this.normal.negate(); 13165 13166 return this; 13167 13168 } 13169 13170 distanceToPoint( point ) { 13171 13172 return this.normal.dot( point ) + this.constant; 13173 13174 } 13175 13176 distanceToSphere( sphere ) { 13177 13178 return this.distanceToPoint( sphere.center ) - sphere.radius; 13179 13180 } 13181 13182 projectPoint( point, target ) { 13183 13184 return target.copy( point ).addScaledVector( this.normal, - this.distanceToPoint( point ) ); 13185 13186 } 13187 13188 intersectLine( line, target ) { 13189 13190 const direction = line.delta( _vector1 ); 13191 13192 const denominator = this.normal.dot( direction ); 13193 13194 if ( denominator === 0 ) { 13195 13196 // line is coplanar, return origin 13197 if ( this.distanceToPoint( line.start ) === 0 ) { 13198 13199 return target.copy( line.start ); 13200 13201 } 13202 13203 // Unsure if this is the correct method to handle this case. 13204 return null; 13205 13206 } 13207 13208 const t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; 13209 13210 if ( t < 0 || t > 1 ) { 13211 13212 return null; 13213 13214 } 13215 13216 return target.copy( line.start ).addScaledVector( direction, t ); 13217 13218 } 13219 13220 intersectsLine( line ) { 13221 13222 // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. 13223 13224 const startSign = this.distanceToPoint( line.start ); 13225 const endSign = this.distanceToPoint( line.end ); 13226 13227 return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); 13228 13229 } 13230 13231 intersectsBox( box ) { 13232 13233 return box.intersectsPlane( this ); 13234 13235 } 13236 13237 intersectsSphere( sphere ) { 13238 13239 return sphere.intersectsPlane( this ); 13240 13241 } 13242 13243 coplanarPoint( target ) { 13244 13245 return target.copy( this.normal ).multiplyScalar( - this.constant ); 13246 13247 } 13248 13249 applyMatrix4( matrix, optionalNormalMatrix ) { 13250 13251 const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix ); 13252 13253 const referencePoint = this.coplanarPoint( _vector1 ).applyMatrix4( matrix ); 13254 13255 const normal = this.normal.applyMatrix3( normalMatrix ).normalize(); 13256 13257 this.constant = - referencePoint.dot( normal ); 13258 13259 return this; 13260 13261 } 13262 13263 translate( offset ) { 13264 13265 this.constant -= offset.dot( this.normal ); 13266 13267 return this; 13268 13269 } 13270 13271 equals( plane ) { 13272 13273 return plane.normal.equals( this.normal ) && ( plane.constant === this.constant ); 13274 13275 } 13276 13277 clone() { 13278 13279 return new this.constructor().copy( this ); 13280 13281 } 13282 13283} 13284 13285const _sphere$5 = /*@__PURE__*/ new Sphere(); 13286const _vector$7 = /*@__PURE__*/ new Vector3(); 13287 13288class Frustum { 13289 13290 constructor( p0 = new Plane(), p1 = new Plane(), p2 = new Plane(), p3 = new Plane(), p4 = new Plane(), p5 = new Plane() ) { 13291 13292 this.planes = [ p0, p1, p2, p3, p4, p5 ]; 13293 13294 } 13295 13296 set( p0, p1, p2, p3, p4, p5 ) { 13297 13298 const planes = this.planes; 13299 13300 planes[ 0 ].copy( p0 ); 13301 planes[ 1 ].copy( p1 ); 13302 planes[ 2 ].copy( p2 ); 13303 planes[ 3 ].copy( p3 ); 13304 planes[ 4 ].copy( p4 ); 13305 planes[ 5 ].copy( p5 ); 13306 13307 return this; 13308 13309 } 13310 13311 copy( frustum ) { 13312 13313 const planes = this.planes; 13314 13315 for ( let i = 0; i < 6; i ++ ) { 13316 13317 planes[ i ].copy( frustum.planes[ i ] ); 13318 13319 } 13320 13321 return this; 13322 13323 } 13324 13325 setFromProjectionMatrix( m, coordinateSystem = WebGLCoordinateSystem ) { 13326 13327 const planes = this.planes; 13328 const me = m.elements; 13329 const me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ]; 13330 const me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ]; 13331 const me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ]; 13332 const me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ]; 13333 13334 planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize(); 13335 planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize(); 13336 planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); 13337 planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); 13338 planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); 13339 13340 if ( coordinateSystem === WebGLCoordinateSystem ) { 13341 13342 planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); 13343 13344 } else if ( coordinateSystem === WebGPUCoordinateSystem ) { 13345 13346 planes[ 5 ].setComponents( me2, me6, me10, me14 ).normalize(); 13347 13348 } else { 13349 13350 throw new Error( 'THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: ' + coordinateSystem ); 13351 13352 } 13353 13354 return this; 13355 13356 } 13357 13358 intersectsObject( object ) { 13359 13360 if ( object.boundingSphere !== undefined ) { 13361 13362 if ( object.boundingSphere === null ) object.computeBoundingSphere(); 13363 13364 _sphere$5.copy( object.boundingSphere ).applyMatrix4( object.matrixWorld ); 13365 13366 } else { 13367 13368 const geometry = object.geometry; 13369 13370 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); 13371 13372 _sphere$5.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld ); 13373 13374 } 13375 13376 return this.intersectsSphere( _sphere$5 ); 13377 13378 } 13379 13380 intersectsSprite( sprite ) { 13381 13382 _sphere$5.center.set( 0, 0, 0 ); 13383 _sphere$5.radius = 0.7071067811865476; 13384 _sphere$5.applyMatrix4( sprite.matrixWorld ); 13385 13386 return this.intersectsSphere( _sphere$5 ); 13387 13388 } 13389 13390 intersectsSphere( sphere ) { 13391 13392 const planes = this.planes; 13393 const center = sphere.center; 13394 const negRadius = - sphere.radius; 13395 13396 for ( let i = 0; i < 6; i ++ ) { 13397 13398 const distance = planes[ i ].distanceToPoint( center ); 13399 13400 if ( distance < negRadius ) { 13401 13402 return false; 13403 13404 } 13405 13406 } 13407 13408 return true; 13409 13410 } 13411 13412 intersectsBox( box ) { 13413 13414 const planes = this.planes; 13415 13416 for ( let i = 0; i < 6; i ++ ) { 13417 13418 const plane = planes[ i ]; 13419 13420 // corner at max distance 13421 13422 _vector$7.x = plane.normal.x > 0 ? box.max.x : box.min.x; 13423 _vector$7.y = plane.normal.y > 0 ? box.max.y : box.min.y; 13424 _vector$7.z = plane.normal.z > 0 ? box.max.z : box.min.z; 13425 13426 if ( plane.distanceToPoint( _vector$7 ) < 0 ) { 13427 13428 return false; 13429 13430 } 13431 13432 } 13433 13434 return true; 13435 13436 } 13437 13438 containsPoint( point ) { 13439 13440 const planes = this.planes; 13441 13442 for ( let i = 0; i < 6; i ++ ) { 13443 13444 if ( planes[ i ].distanceToPoint( point ) < 0 ) { 13445 13446 return false; 13447 13448 } 13449 13450 } 13451 13452 return true; 13453 13454 } 13455 13456 clone() { 13457 13458 return new this.constructor().copy( this ); 13459 13460 } 13461 13462} 13463 13464function WebGLAnimation() { 13465 13466 let context = null; 13467 let isAnimating = false; 13468 let animationLoop = null; 13469 let requestId = null; 13470 13471 function onAnimationFrame( time, frame ) { 13472 13473 animationLoop( time, frame ); 13474 13475 requestId = context.requestAnimationFrame( onAnimationFrame ); 13476 13477 } 13478 13479 return { 13480 13481 start: function () { 13482 13483 if ( isAnimating === true ) return; 13484 if ( animationLoop === null ) return; 13485 13486 requestId = context.requestAnimationFrame( onAnimationFrame ); 13487 13488 isAnimating = true; 13489 13490 }, 13491 13492 stop: function () { 13493 13494 context.cancelAnimationFrame( requestId ); 13495 13496 isAnimating = false; 13497 13498 }, 13499 13500 setAnimationLoop: function ( callback ) { 13501 13502 animationLoop = callback; 13503 13504 }, 13505 13506 setContext: function ( value ) { 13507 13508 context = value; 13509 13510 } 13511 13512 }; 13513 13514} 13515 13516function WebGLAttributes( gl, capabilities ) { 13517 13518 const isWebGL2 = capabilities.isWebGL2; 13519 13520 const buffers = new WeakMap(); 13521 13522 function createBuffer( attribute, bufferType ) { 13523 13524 const array = attribute.array; 13525 const usage = attribute.usage; 13526 const size = array.byteLength; 13527 13528 const buffer = gl.createBuffer(); 13529 13530 gl.bindBuffer( bufferType, buffer ); 13531 gl.bufferData( bufferType, array, usage ); 13532 13533 attribute.onUploadCallback(); 13534 13535 let type; 13536 13537 if ( array instanceof Float32Array ) { 13538 13539 type = gl.FLOAT; 13540 13541 } else if ( array instanceof Uint16Array ) { 13542 13543 if ( attribute.isFloat16BufferAttribute ) { 13544 13545 if ( isWebGL2 ) { 13546 13547 type = gl.HALF_FLOAT; 13548 13549 } else { 13550 13551 throw new Error( 'THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2.' ); 13552 13553 } 13554 13555 } else { 13556 13557 type = gl.UNSIGNED_SHORT; 13558 13559 } 13560 13561 } else if ( array instanceof Int16Array ) { 13562 13563 type = gl.SHORT; 13564 13565 } else if ( array instanceof Uint32Array ) { 13566 13567 type = gl.UNSIGNED_INT; 13568 13569 } else if ( array instanceof Int32Array ) { 13570 13571 type = gl.INT; 13572 13573 } else if ( array instanceof Int8Array ) { 13574 13575 type = gl.BYTE; 13576 13577 } else if ( array instanceof Uint8Array ) { 13578 13579 type = gl.UNSIGNED_BYTE; 13580 13581 } else if ( array instanceof Uint8ClampedArray ) { 13582 13583 type = gl.UNSIGNED_BYTE; 13584 13585 } else { 13586 13587 throw new Error( 'THREE.WebGLAttributes: Unsupported buffer data format: ' + array ); 13588 13589 } 13590 13591 return { 13592 buffer: buffer, 13593 type: type, 13594 bytesPerElement: array.BYTES_PER_ELEMENT, 13595 version: attribute.version, 13596 size: size 13597 }; 13598 13599 } 13600 13601 function updateBuffer( buffer, attribute, bufferType ) { 13602 13603 const array = attribute.array; 13604 const updateRange = attribute._updateRange; // deprecated 13605 const updateRanges = attribute.updateRanges; 13606 13607 gl.bindBuffer( bufferType, buffer ); 13608 13609 if ( updateRange.count === - 1 && updateRanges.length === 0 ) { 13610 13611 // Not using update ranges 13612 gl.bufferSubData( bufferType, 0, array ); 13613 13614 } 13615 13616 if ( updateRanges.length !== 0 ) { 13617 13618 for ( let i = 0, l = updateRanges.length; i < l; i ++ ) { 13619 13620 const range = updateRanges[ i ]; 13621 if ( isWebGL2 ) { 13622 13623 gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT, 13624 array, range.start, range.count ); 13625 13626 } else { 13627 13628 gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT, 13629 array.subarray( range.start, range.start + range.count ) ); 13630 13631 } 13632 13633 } 13634 13635 attribute.clearUpdateRanges(); 13636 13637 } 13638 13639 // deprecated 13640 if ( updateRange.count !== - 1 ) { 13641 13642 if ( isWebGL2 ) { 13643 13644 gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, 13645 array, updateRange.offset, updateRange.count ); 13646 13647 } else { 13648 13649 gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, 13650 array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) ); 13651 13652 } 13653 13654 updateRange.count = - 1; // reset range 13655 13656 } 13657 13658 attribute.onUploadCallback(); 13659 13660 } 13661 13662 // 13663 13664 function get( attribute ) { 13665 13666 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; 13667 13668 return buffers.get( attribute ); 13669 13670 } 13671 13672 function remove( attribute ) { 13673 13674 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; 13675 13676 const data = buffers.get( attribute ); 13677 13678 if ( data ) { 13679 13680 gl.deleteBuffer( data.buffer ); 13681 13682 buffers.delete( attribute ); 13683 13684 } 13685 13686 } 13687 13688 function update( attribute, bufferType ) { 13689 13690 if ( attribute.isGLBufferAttribute ) { 13691 13692 const cached = buffers.get( attribute ); 13693 13694 if ( ! cached || cached.version < attribute.version ) { 13695 13696 buffers.set( attribute, { 13697 buffer: attribute.buffer, 13698 type: attribute.type, 13699 bytesPerElement: attribute.elementSize, 13700 version: attribute.version 13701 } ); 13702 13703 } 13704 13705 return; 13706 13707 } 13708 13709 if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data; 13710 13711 const data = buffers.get( attribute ); 13712 13713 if ( data === undefined ) { 13714 13715 buffers.set( attribute, createBuffer( attribute, bufferType ) ); 13716 13717 } else if ( data.version < attribute.version ) { 13718 13719 if ( data.size !== attribute.array.byteLength ) { 13720 13721 throw new Error( 'THREE.WebGLAttributes: The size of the buffer attribute\'s array buffer does not match the original size. Resizing buffer attributes is not supported.' ); 13722 13723 } 13724 13725 updateBuffer( data.buffer, attribute, bufferType ); 13726 13727 data.version = attribute.version; 13728 13729 } 13730 13731 } 13732 13733 return { 13734 13735 get: get, 13736 remove: remove, 13737 update: update 13738 13739 }; 13740 13741} 13742 13743class PlaneGeometry extends BufferGeometry { 13744 13745 constructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) { 13746 13747 super(); 13748 13749 this.type = 'PlaneGeometry'; 13750 13751 this.parameters = { 13752 width: width, 13753 height: height, 13754 widthSegments: widthSegments, 13755 heightSegments: heightSegments 13756 }; 13757 13758 const width_half = width / 2; 13759 const height_half = height / 2; 13760 13761 const gridX = Math.floor( widthSegments ); 13762 const gridY = Math.floor( heightSegments ); 13763 13764 const gridX1 = gridX + 1; 13765 const gridY1 = gridY + 1; 13766 13767 const segment_width = width / gridX; 13768 const segment_height = height / gridY; 13769 13770 // 13771 13772 const indices = []; 13773 const vertices = []; 13774 const normals = []; 13775 const uvs = []; 13776 13777 for ( let iy = 0; iy < gridY1; iy ++ ) { 13778 13779 const y = iy * segment_height - height_half; 13780 13781 for ( let ix = 0; ix < gridX1; ix ++ ) { 13782 13783 const x = ix * segment_width - width_half; 13784 13785 vertices.push( x, - y, 0 ); 13786 13787 normals.push( 0, 0, 1 ); 13788 13789 uvs.push( ix / gridX ); 13790 uvs.push( 1 - ( iy / gridY ) ); 13791 13792 } 13793 13794 } 13795 13796 for ( let iy = 0; iy < gridY; iy ++ ) { 13797 13798 for ( let ix = 0; ix < gridX; ix ++ ) { 13799 13800 const a = ix + gridX1 * iy; 13801 const b = ix + gridX1 * ( iy + 1 ); 13802 const c = ( ix + 1 ) + gridX1 * ( iy + 1 ); 13803 const d = ( ix + 1 ) + gridX1 * iy; 13804 13805 indices.push( a, b, d ); 13806 indices.push( b, c, d ); 13807 13808 } 13809 13810 } 13811 13812 this.setIndex( indices ); 13813 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 13814 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 13815 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 13816 13817 } 13818 13819 copy( source ) { 13820 13821 super.copy( source ); 13822 13823 this.parameters = Object.assign( {}, source.parameters ); 13824 13825 return this; 13826 13827 } 13828 13829 static fromJSON( data ) { 13830 13831 return new PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments ); 13832 13833 } 13834 13835} 13836 13837var alphahash_fragment = "#ifdef USE_ALPHAHASH\n\tif ( diffuseColor.a < getAlphaHashThreshold( vPosition ) ) discard;\n#endif"; 13838 13839var alphahash_pars_fragment = "#ifdef USE_ALPHAHASH\n\tconst float ALPHA_HASH_SCALE = 0.05;\n\tfloat hash2D( vec2 value ) {\n\t\treturn fract( 1.0e4 * sin( 17.0 * value.x + 0.1 * value.y ) * ( 0.1 + abs( sin( 13.0 * value.y + value.x ) ) ) );\n\t}\n\tfloat hash3D( vec3 value ) {\n\t\treturn hash2D( vec2( hash2D( value.xy ), value.z ) );\n\t}\n\tfloat getAlphaHashThreshold( vec3 position ) {\n\t\tfloat maxDeriv = max(\n\t\t\tlength( dFdx( position.xyz ) ),\n\t\t\tlength( dFdy( position.xyz ) )\n\t\t);\n\t\tfloat pixScale = 1.0 / ( ALPHA_HASH_SCALE * maxDeriv );\n\t\tvec2 pixScales = vec2(\n\t\t\texp2( floor( log2( pixScale ) ) ),\n\t\t\texp2( ceil( log2( pixScale ) ) )\n\t\t);\n\t\tvec2 alpha = vec2(\n\t\t\thash3D( floor( pixScales.x * position.xyz ) ),\n\t\t\thash3D( floor( pixScales.y * position.xyz ) )\n\t\t);\n\t\tfloat lerpFactor = fract( log2( pixScale ) );\n\t\tfloat x = ( 1.0 - lerpFactor ) * alpha.x + lerpFactor * alpha.y;\n\t\tfloat a = min( lerpFactor, 1.0 - lerpFactor );\n\t\tvec3 cases = vec3(\n\t\t\tx * x / ( 2.0 * a * ( 1.0 - a ) ),\n\t\t\t( x - 0.5 * a ) / ( 1.0 - a ),\n\t\t\t1.0 - ( ( 1.0 - x ) * ( 1.0 - x ) / ( 2.0 * a * ( 1.0 - a ) ) )\n\t\t);\n\t\tfloat threshold = ( x < ( 1.0 - a ) )\n\t\t\t? ( ( x < a ) ? cases.x : cases.y )\n\t\t\t: cases.z;\n\t\treturn clamp( threshold , 1.0e-6, 1.0 );\n\t}\n#endif"; 13840 13841var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vAlphaMapUv ).g;\n#endif"; 13842 13843var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; 13844 13845var alphatest_fragment = "#ifdef USE_ALPHATEST\n\tif ( diffuseColor.a < alphaTest ) discard;\n#endif"; 13846 13847var alphatest_pars_fragment = "#ifdef USE_ALPHATEST\n\tuniform float alphaTest;\n#endif"; 13848 13849var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vAoMapUv ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_CLEARCOAT ) \n\t\tclearcoatSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_SHEEN ) \n\t\tsheenSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot
13849( geometryNormal, geometryViewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif"; 13850 13851var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; 13852 13853var batching_pars_vertex = "#ifdef USE_BATCHING\n\tattribute float batchId;\n\tuniform highp sampler2D batchingTexture;\n\tmat4 getBatchingMatrix( const in float i ) {\n\t\tint size = textureSize( batchingTexture, 0 ).x;\n\t\tint j = int( i ) * 4;\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\tvec4 v1 = texelFetch( batchingTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( batchingTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( batchingTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( batchingTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n#endif"; 13854 13855var batching_vertex = "#ifdef USE_BATCHING\n\tmat4 batchingMatrix = getBatchingMatrix( batchId );\n#endif"; 13856 13857var begin_vertex = "vec3 transformed = vec3( position );\n#ifdef USE_ALPHAHASH\n\tvPosition = vec3( position );\n#endif"; 13858 13859var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif"; 13860 13861var bsdfs = "float G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, 1.0, dotVH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n} // validated"; 13862 13863var iridescence_fragment = "#ifdef USE_IRIDESCENCE\n\tconst mat3 XYZ_TO_REC709 = mat3(\n\t\t 3.2404542, -0.9692660, 0.0556434,\n\t\t-1.5371385, 1.8760108, -0.2040259,\n\t\t-0.4985314, 0.0415560, 1.0572252\n\t);\n\tvec3 Fresnel0ToIor( vec3 fresnel0 ) {\n\t\tvec3 sqrtF0 = sqrt( fresnel0 );\n\t\treturn ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );\n\t}\n\tvec3 IorToFresnel0( vec3 transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) );\n\t}\n\tfloat IorToFresnel0( float transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ));\n\t}\n\tvec3 evalSensitivity( float OPD, vec3 shift ) {\n\t\tfloat phase = 2.0 * PI * OPD * 1.0e-9;\n\t\tvec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );\n\t\tvec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );\n\t\tvec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );\n\t\tvec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - pow2( phase ) * var );\n\t\txyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * pow2( phase ) );\n\t\txyz /= 1.0685e-7;\n\t\tvec3 rgb = XYZ_TO_REC709 * xyz;\n\t\treturn rgb;\n\t}\n\tvec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) {\n\t\tvec3 I;\n\t\tfloat iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );\n\t\tfloat sinTheta2Sq = pow2( outsideIOR / iridescenceIOR ) * ( 1.0 - pow2( cosTheta1 ) );\n\t\tfloat cosTheta2Sq = 1.0 - sinTheta2Sq;\n\t\tif ( cosTheta2Sq < 0.0 ) {\n\t\t\treturn vec3( 1.0 );\n\t\t}\n\t\tfloat cosTheta2 = sqrt( cosTheta2Sq );\n\t\tfloat R0 = IorToFresnel0( iridescenceIOR, outsideIOR );\n\t\tfloat R12 = F_Schlick( R0, 1.0, cosTheta1 );\n\t\tfloat T121 = 1.0 - R12;\n\t\tfloat phi12 = 0.0;\n\t\tif ( iridescenceIOR < outsideIOR ) phi12 = PI;\n\t\tfloat phi21 = PI - phi12;\n\t\tvec3 baseIOR = Fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) );\t\tvec3 R1 = IorToFresnel0( baseIOR, iridescenceIOR );
13863\n\t\tvec3 R23 = F_Schlick( R1, 1.0, cosTheta2 );\n\t\tvec3 phi23 = vec3( 0.0 );\n\t\tif ( baseIOR[ 0 ] < iridescenceIOR ) phi23[ 0 ] = PI;\n\t\tif ( baseIOR[ 1 ] < iridescenceIOR ) phi23[ 1 ] = PI;\n\t\tif ( baseIOR[ 2 ] < iridescenceIOR ) phi23[ 2 ] = PI;\n\t\tfloat OPD = 2.0 * iridescenceIOR * thinFilmThickness * cosTheta2;\n\t\tvec3 phi = vec3( phi21 ) + phi23;\n\t\tvec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 );\n\t\tvec3 r123 = sqrt( R123 );\n\t\tvec3 Rs = pow2( T121 ) * R23 / ( vec3( 1.0 ) - R123 );\n\t\tvec3 C0 = R12 + Rs;\n\t\tI = C0;\n\t\tvec3 Cm = Rs - T121;\n\t\tfor ( int m = 1; m <= 2; ++ m ) {\n\t\t\tCm *= r123;\n\t\t\tvec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );\n\t\t\tI += Cm * Sm;\n\t\t}\n\t\treturn max( I, vec3( 0.0 ) );\n\t}\n#endif"; 13864 13865var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vBumpMapUv );\n\t\tvec2 dSTdy = dFdy( vBumpMapUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vBumpMapUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection ) {\n\t\tvec3 vSigmaX = normalize( dFdx( surf_pos.xyz ) );\n\t\tvec3 vSigmaY = normalize( dFdy( surf_pos.xyz ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 ) * faceDirection;\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif"; 13866 13867var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#pragma unroll_loop_end\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\tif ( clipped ) discard;\n\t#endif\n#endif"; 13868 13869var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif"; 13870 13871var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif"; 13872 13873var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif"; 13874 13875var color_fragment = "#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( USE_COLOR )\n\tdiffuseColor.rgb *= vColor;\n#endif"; 13876 13877var color_pars_fragment = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR )\n\tvarying vec3 vColor;\n#endif"; 13878 13879var color_pars_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvarying vec3 vColor;\n#endif"; 13880 13881var color_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor *= color;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif"; 13882 13883var common = "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nvec3 pow2( const in vec3 x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\n#ifdef USE_ALPHAHASH\n\tvarying vec3 vPosition;\n#endif\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat luminance( const in vec3 rgb ) {\n\tconst vec3 weights = vec3( 0.2126729, 0.7151522, 0.0721750 );\n\treturn dot( weights, rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}\nvec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nfloat F_Schlick( const in float f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n} // validated"; 13884 13885var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\thighp vec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tuv.x += filterInt * 3.0 * cubeUV_minTileSize;\n\t\tuv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize );\n\t\tuv.x *= CUBEUV_TEXEL_WIDTH;\n\t\tuv.y *= CUBEUV_TEXEL_HEIGHT;\n\t\t#ifdef texture2DGradEXT\n\t\t\treturn texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb;\n\t\t#else\n\t\t\treturn texture2D( envMap, uv ).rgb;\n\t\t#endif\n\t}\n\t#define cubeUV_r0 1.0\n\t#define cubeUV_m0 - 2.0\n\t#define cubeUV_r1 0.8\n\t#define cubeUV_m1 - 1.0\n\t#define cubeUV_r4 0.4\n\t#define cubeUV_m4 2.0\n\t#define cubeUV_r5 0.305\n\t#define cubeUV_m5 3.0\n\t#define cubeUV_r6 0.21\n\t#define cubeUV_m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= cubeUV_r1 ) {\n\t\t\tmip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0;\n\t\t} else if ( roughness >= cubeUV_r4 ) {\n\t\t\tmip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1;\n\t\t} else if ( roughness >= cubeUV_r5 ) {\n\t\t\tmip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4;\n\t\t} else if ( roughness >= cubeUV_r6 ) {\n\t\t\tmip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif"; 13886 13887var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = objectTangent;\n#endif\n#ifdef USE_BATCHING\n\tmat3 bm = mat3( batchingMatrix );
13887\n\ttransformedNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) );\n\ttransformedNormal = bm * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = bm * transformedTangent;\n\t#endif\n#endif\n#ifdef USE_INSTANCING\n\tmat3 im = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( im[ 0 ], im[ 0 ] ), dot( im[ 1 ], im[ 1 ] ), dot( im[ 2 ], im[ 2 ] ) );\n\ttransformedNormal = im * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = im * transformedTangent;\n\t#endif\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\ttransformedTangent = ( modelViewMatrix * vec4( transformedTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif"; 13888 13889var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif"; 13890 13891var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias );\n#endif"; 13892 13893var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv );\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif"; 13894 13895var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif"; 13896 13897var colorspace_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );"; 13898 13899var colorspace_pars_fragment = "\nconst mat3 LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = mat3(\n\tvec3( 0.8224621, 0.177538, 0.0 ),\n\tvec3( 0.0331941, 0.9668058, 0.0 ),\n\tvec3( 0.0170827, 0.0723974, 0.9105199 )\n);\nconst mat3 LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.2249401, - 0.2249404, 0.0 ),\n\tvec3( - 0.0420569, 1.0420571, 0.0 ),\n\tvec3( - 0.0196376, - 0.0786361, 1.0982735 )\n);\nvec4 LinearSRGBToLinearDisplayP3( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_SRGB_TO_LINEAR_DISPLAY_P3, value.a );\n}\nvec4 LinearDisplayP3ToLinearSRGB( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_DISPLAY_P3_TO_LINEAR_SRGB, value.a );\n}\nvec4 LinearTransferOETF( in vec4 value ) {\n\treturn value;\n}\nvec4 sRGBTransferOETF( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn sRGBTransferOETF( value );\n}"; 13900 13901var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif"; 13902 13903var envmap_common_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t\n#endif"; 13904 13905var envmap_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif"; 13906 13907var envmap_pars_vertex = "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\t\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif"; 13908 13909var envmap_vertex = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t}
13909 else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif"; 13910 13911var fog_vertex = "#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif"; 13912 13913var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif"; 13914 13915var fog_fragment = "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, vFogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif"; 13916 13917var fog_pars_fragment = "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float vFogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif"; 13918 13919var gradientmap_pars_fragment = "#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn vec3( texture2D( gradientMap, coord ).r );\n\t#else\n\t\tvec2 fw = fwidth( coord ) * 0.5;\n\t\treturn mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) );\n\t#endif\n}"; 13920 13921var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\treflectedLight.indirectDiffuse += lightMapIrradiance;\n#endif"; 13922 13923var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; 13924 13925var lights_lambert_fragment = "LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularStrength = specularStrength;"; 13926 13927var lights_lambert_pars_fragment = "varying vec3 vViewPosition;\nstruct LambertMaterial {\n\tvec3 diffuseColor;\n\tfloat specularStrength;\n};\nvoid RE_Direct_Lambert( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Lambert\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Lambert"; 13928 13929var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\n#if defined( USE_LIGHT_PROBES )\n\tuniform vec3 lightProbe[ 9 ];\n#endif\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t#if defined ( LEGACY_LIGHTS )\n\t\tif ( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\t\treturn pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t\t}\n\t\treturn 1.0;\n\t#else\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tif ( cutoffDistance > 0.0 ) {\n\t\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t}\n\t\treturn distanceFalloff;\n\t#endif\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}
13929\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) {\n\t\tfloat dotNL = dot( normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif"; 13930 13931var envmap_physical_pars_fragment = "#ifdef USE_ENVMAP\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 reflectVec = reflect( - viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\t#ifdef USE_ANISOTROPY\n\t\tvec3 getIBLAnisotropyRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) {\n\t\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\t\tvec3 bentNormal = cross( bitangent, viewDir );\n\t\t\t\tbentNormal = normalize( cross( bentNormal, bitangent ) );\n\t\t\t\tbentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) );\n\t\t\t\treturn getIBLRadiance( viewDir, bentNormal, roughness );\n\t\t\t#else\n\t\t\t\treturn vec3( 0.0 );\n\t\t\t#endif\n\t\t}\n\t#endif\n#endif"; 13932 13933var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;"; 13934 13935var lights_toon_pars_fragment = "varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometryNormal, directLight.direction ) * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon"; 13936 13937var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;"; 13938 13939var lights_phong_pars_fragment = "varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot
13939( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong"; 13940 13941var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\tmaterial.ior = ior;\n\t#ifdef USE_SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULAR_COLORMAP\n\t\t\tspecularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb;\n\t\t#endif\n\t\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;
13941\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vClearcoatMapUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vClearcoatRoughnessMapUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_IRIDESCENCE\n\tmaterial.iridescence = iridescence;\n\tmaterial.iridescenceIOR = iridescenceIOR;\n\t#ifdef USE_IRIDESCENCEMAP\n\t\tmaterial.iridescence *= texture2D( iridescenceMap, vIridescenceMapUv ).r;\n\t#endif\n\t#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\t\tmaterial.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vIridescenceThicknessMapUv ).g + iridescenceThicknessMinimum;\n\t#else\n\t\tmaterial.iridescenceThickness = iridescenceThicknessMaximum;\n\t#endif\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheenColor;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tmaterial.sheenColor *= texture2D( sheenColorMap, vSheenColorMapUv ).rgb;\n\t#endif\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tmaterial.sheenRoughness *= texture2D( sheenRoughnessMap, vSheenRoughnessMapUv ).a;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\t#ifdef USE_ANISOTROPYMAP\n\t\tmat2 anisotropyMat = mat2( anisotropyVector.x, anisotropyVector.y, - anisotropyVector.y, anisotropyVector.x );\n\t\tvec3 anisotropyPolar = texture2D( anisotropyMap, vAnisotropyMapUv ).rgb;\n\t\tvec2 anisotropyV = anisotropyMat * normalize( 2.0 * anisotropyPolar.rg - vec2( 1.0 ) ) * anisotropyPolar.b;\n\t#else\n\t\tvec2 anisotropyV = anisotropyVector;\n\t#endif\n\tmaterial.anisotropy = length( anisotropyV );\n\tif( material.anisotropy == 0.0 ) {\n\t\tanisotropyV = vec2( 1.0, 0.0 );\n\t} else {\n\t\tanisotropyV /= material.anisotropy;\n\t\tmaterial.anisotropy = saturate( material.anisotropy );\n\t}\n\tmaterial.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) );\n\tmaterial.anisotropyT = tbn[ 0 ] * anisotropyV.x + tbn[ 1 ] * anisotropyV.y;\n\tmaterial.anisotropyB = tbn[ 1 ] * anisotropyV.x - tbn[ 0 ] * anisotropyV.y;\n#endif"; 13942�
vendor: 15,344 bytes, lines 13942-13943
13942 13943var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\tfloat iridescence;\n\t\tfloat iridescenceIOR;\n\t\tfloat iridescenceThickness;\n\t\tvec3 iridescenceFresnel;\n\t\tvec3 iridescenceF0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n\t#ifdef IOR\n\t\tfloat ior;\n\t#endif\n\t#ifdef USE_TRANSMISSION\n\t\tfloat transmission;\n\t\tfloat transmissionAlpha;\n\t\tfloat thickness;\n\t\tfloat attenuationDistance;\n\t\tvec3 attenuationColor;\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat anisotropy;\n\t\tfloat alphaT;\n\t\tvec3 anisotropyT;\n\t\tvec3 anisotropyB;\n\t#endif\n};\nvec3 clearcoatSpecularDirect = vec3( 0.0 );\nvec3 clearcoatSpecularIndirect = vec3( 0.0 );\nvec3 sheenSpecularDirect = vec3( 0.0 );\nvec3 sheenSpecularIndirect = vec3(0.0 );\nvec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) {\n float x = clamp( 1.0 - dotVH, 0.0, 1.0 );\n float x2 = x * x;\n float x5 = clamp( x * x2 * x2, 0.0, 0.9999 );\n return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\n#ifdef USE_ANISOTROPY\n\tfloat V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) {\n\t\tfloat gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) );\n\t\tfloat gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) );\n\t\tfloat v = 0.5 / ( gv + gl );\n\t\treturn saturate(v);\n\t}\n\tfloat D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) {\n\t\tfloat a2 = alphaT * alphaB;\n\t\thighp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH );\n\t\thighp float v2 = dot( v, v );\n\t\tfloat w2 = a2 / v2;\n\t\treturn RECIPROCAL_PI * a2 * pow2 ( w2 );\n\t}\n#endif\n#ifdef USE_CLEARCOAT\n\tvec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) {\n\t\tvec3 f0 = material.clearcoatF0;\n\t\tfloat f90 = material.clearcoatF90;\n\t\tfloat roughness = material.clearcoatRoughness;\n\t\tfloat alpha = pow2( roughness );\n\t\tvec3 halfDir = normalize( lightDir + viewDir );\n\t\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\t\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\t\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\t\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\t\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t\treturn F * ( V * D );\n\t}\n#endif\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) {\n\tvec3 f0 = material.specularColor;\n\tfloat f90 = material.specularF90;\n\tfloat roughness = material.roughness;\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t#ifdef USE_IRIDESCENCE\n\t\tF = mix( F, material.iridescenceFresnel, material.iridescence );\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat dotTL = dot( material.anisotropyT, lightDir );\n\t\tfloat dotTV = dot( material.anisotropyT, viewDir );\n\t\tfloat dotTH = dot( material.anisotropyT, halfDir );\n\t\tfloat dotBL = dot( material.anisotropyB, lightDir );\n\t\tfloat dotBV = dot( material.anisotropyB, viewDir );\n\t\tfloat dotBH = dot( material.anisotropyB, halfDir );\n\t\tfloat V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL );\n\t\tfloat D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH );\n\t#else\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t#endif\n\treturn F * ( V * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif\nfloat IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat r2 = roughness * roughness;\n\tfloat a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95;\n\tfloat b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72;\n\tfloat DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) );\n\treturn saturate( DG * RECIPROCAL_PI );\n}\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\t#ifdef USE_IRIDESCENCE\n\t\tvec3 Fr = mix( specularColor, iridescenceF0, iridescence );\n\t#else\n\t\tvec3 Fr = specularColor;\n\t#endif\n\tvec3 FssEss = Fr * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometryNormal;\n\t\tvec3 viewDir = geometryViewDir;\n\t\tvec3 position = geometryPosition;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecularDirect += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularDirect += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness );\n\t#endif\n\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material );\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecularIndirect += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularIndirect += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering );\n\t#else\n\t\tcomputeMultiscattering( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\t#endif\n\tvec3 totalScattering = singleScattering + multiScattering;\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}";
13943 13944 13945var lights_fragment_begin = "\nvec3 geometryPosition = - vViewPosition;\nvec3 geometryNormal = normal;\nvec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\nvec3 geometryClearcoatNormal = vec3( 0.0 );\n#ifdef USE_CLEARCOAT\n\tgeometryClearcoatNormal = clearcoatNormal;\n#endif\n#ifdef USE_IRIDESCENCE\n\tfloat dotNVi = saturate( dot( normal, geometryViewDir ) );\n\tif ( material.iridescenceThickness == 0.0 ) {\n\t\tmaterial.iridescence = 0.0;\n\t} else {\n\t\tmaterial.iridescence = saturate( material.iridescence );\n\t}\n\tif ( material.iridescence > 0.0 ) {\n\t\tmaterial.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tmaterial.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );\n\t}\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometryPosition, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tvec4 spotColor;\n\tvec3 spotLightCoord;\n\tbool inSpotLightMap;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometryPosition, directLight );\n\t\t#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX\n\t\t#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS\n\t\t#else\n\t\t#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#endif\n\t\t#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )\n\t\t\tspotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;\n\t\t\tinSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );\n\t\t\tspotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );\n\t\t\tdirectLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color;\n\t\t#endif\n\t\t#undef SPOT_LIGHT_MAP_INDEX\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#if defined( USE_LIGHT_PROBES )\n\t\tirradiance += getLightProbeIrradiance( lightProbe, geometryNormal );\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif"; 13946 13947var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometryNormal );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\t#ifdef USE_ANISOTROPY\n\t\tradiance += getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy );\n\t#else\n\t\tradiance += getIBLRadiance( geometryViewDir, geometryNormal, material.roughness );\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif"; 13948 13949var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif"; 13950 13951var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif"; 13952 13953var logdepthbuf_pars_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif"; 13954 13955var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t\tvarying float vIsPerspective;\n\t#else\n\t\tuniform float logDepthBufFC;\n\t#endif\n#endif"; 13956 13957var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif"; 13958 13959var map_fragment = "#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vMapUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );\n\t\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif"; 13960 13961var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif"; 13962 13963var map_particle_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t#if defined( USE_POINTS_UV )\n\t\tvec2 uv = vUv;\n\t#else\n\t\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tdiffuseColor *= texture2D( map, uv );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif"; 13964 13965var map_particle_pars_fragment = "#if defined( USE_POINTS_UV )\n\tvarying vec2 vUv;\n#else\n\t#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t\tuniform mat3 uvTransform;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; 13966 13967var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif"; 13968 13969var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"; 13970 13971var morphcolor_vertex = "#if defined( USE_MORPHCOLORS ) && defined( MORPHTARGETS_TEXTURE )\n\tvColor *= morphTargetBaseInfluence;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t#if defined( USE_COLOR_ALPHA )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ) * morphTargetInfluences[ i ];\n\t\t#elif defined( USE_COLOR )\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ).rgb * morphTargetInfluences[ i ];\n\t\t#endif\n\t}\n#endif"; 13972 13973var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\tobjectNormal += morphNormal0 * morphTargetInfluences[ 0 ];\n\t\tobjectNormal += morphNormal1 * morphTargetInfluences[ 1 ];\n\t\tobjectNormal += morphNormal2 * morphTargetInfluences[ 2 ];\n\t\tobjectNormal += morphNormal3 * morphTargetInfluences[ 3 ];\n\t#endif\n#endif"; 13974 13975var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tuniform float morphTargetInfluences[ MORPHTARGETS_COUNT ];\n\t\tuniform sampler2DArray morphTargetsTexture;\n\t\tuniform ivec2 morphTargetsTextureSize;\n\t\tvec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) {\n\t\t\tint texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset;\n\t\t\tint y = texelIndex / morphTargetsTextureSize.x;\n\t\t\tint x = texelIndex - y * morphTargetsTextureSize.x;\n\t\t\tivec3 morphUV = ivec3( x, y, morphTargetIndex );\n\t\t\treturn texelFetch( morphTargetsTexture, morphUV, 0 );\n\t\t}\n\t#else\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\tuniform float morphTargetInfluences[ 8 ];\n\t\t#else\n\t\t\tuniform float morphTargetInfluences[ 4 ];\n\t\t#endif\n\t#endif\n#endif"; 13976 13977var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\t\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\t\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\t\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\t\t\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\t\t\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\t\t\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t\t#endif\n\t#endif\n#endif"; 13978 13979var normal_fragment_begin = "float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal *= faceDirection;\n\t#endif\n#endif\n#if defined( USE_NORMALMAP_TANGENTSPACE ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY )\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn = getTangentFrame( - vViewPosition, normal,\n\t\t#if defined( USE_NORMALMAP )\n\t\t\tvNormalMapUv\n\t\t#elif defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tvClearcoatNormalMapUv\n\t\t#else\n\t\t\tvUv\n\t\t#endif\n\t\t);\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn[0] *= faceDirection;\n\t\ttbn[1] *= faceDirection;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv );\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn2[0] *= faceDirection;\n\t\ttbn2[1] *= faceDirection;\n\t#endif\n#endif\nvec3 nonPerturbedNormal = normal;"; 13980 13981var normal_fragment_maps = "#ifdef USE_NORMALMAP_OBJECTSPACE\n\tnormal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( USE_NORMALMAP_TANGENTSPACE )\n\tvec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\tnormal = normalize( tbn * mapN );
13981\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif"; 13982 13983var normal_pars_fragment = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif"; 13984 13985var normal_pars_vertex = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif"; 13986 13987var normal_vertex = "#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif"; 13988 13989var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef USE_NORMALMAP_OBJECTSPACE\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( USE_NORMALMAP_TANGENTSPACE ) || defined ( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) )\n\tmat3 getTangentFrame( vec3 eye_pos, vec3 surf_norm, vec2 uv ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( uv.st );\n\t\tvec2 st1 = dFdy( uv.st );\n\t\tvec3 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det );\n\t\treturn mat3( T * scale, B * scale, N );\n\t}\n#endif"; 13990 13991var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = nonPerturbedNormal;\n#endif"; 13992 13993var clearcoat_normal_fragment_maps = "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vClearcoatNormalMapUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\tclearcoatNormal = normalize( tbn2 * clearcoatMapN );\n#endif"; 13994 13995var clearcoat_pars_fragment = "#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif"; 13996 13997var iridescence_pars_fragment = "#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform sampler2D iridescenceThicknessMap;\n#endif"; 13998 13999var opaque_fragment = "#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffuseColor.a *= material.transmissionAlpha;\n#endif\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );"; 14000 14001var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec2 packDepthToRG( in highp float v ) {\n\treturn packDepthToRGBA( v ).yx;\n}\nfloat unpackRGToDepth( const in highp vec2 v ) {\n\treturn unpackRGBAToDepth( vec4( v.xy, 0.0, 0.0 ) );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn depth * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * depth - far );\n}"; 14002 14003var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif"; 14004 14005var project_vertex = "vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_BATCHING\n\tmvPosition = batchingMatrix * mvPosition;\n#endif\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;"; 14006 14007var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif"; 14008 14009var dithering_pars_fragment = "#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif"; 14010 14011var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv );\n\troughnessFactor *= texelRoughness.g;\n#endif"; 14012 14013var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"; 14014�
vendor: 9,177 bytes, lines 14014-14015
14014 14015var shadowmap_pars_fragment = "#if NUM_SPOT_LIGHT_COORDS > 0\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#if NUM_SPOT_LIGHT_MAPS > 0\n\tuniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0;\n\t\tbool frustumTest = inFrustum && shadowCoord.z <= 1.0;\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif";
14015 14016 14017var shadowmap_pars_vertex = "#if NUM_SPOT_LIGHT_COORDS > 0\n\tuniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif"; 14018 14019var shadowmap_vertex = "#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\tvec4 shadowWorldPosition;\n#endif\n#if defined( USE_SHADOWMAP )\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if NUM_SPOT_LIGHT_COORDS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition;\n\t\t#if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t\tshadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;\n\t\t#endif\n\t\tvSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n#endif"; 14020 14021var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\n}"; 14022 14023var 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"; 14024 14025var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\tuniform highp sampler2D boneTexture;\n\tmat4 getBoneMatrix( const in float i ) {\n\t\tint size = textureSize( boneTexture, 0 ).x;\n\t\tint j = int( i ) * 4;\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\tvec4 v1 = texelFetch( boneTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( boneTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( boneTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( boneTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n#endif"; 14026 14027var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif"; 14028 14029var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif"; 14030 14031var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vSpecularMapUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif"; 14032 14033var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif"; 14034 14035var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif"; 14036�
vendor: 2,514 bytes, lines 14036-14037
14036 14037var tonemapping_pars_fragment = "#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn saturate( toneMappingExposure * color );\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3( 1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108, 1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605, 1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nconst mat3 LINEAR_REC2020_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.6605, - 0.1246, - 0.0182 ),\n\tvec3( - 0.5876, 1.1329, - 0.1006 ),\n\tvec3( - 0.0728, - 0.0083, 1.1187 )\n);\nconst mat3 LINEAR_SRGB_TO_LINEAR_REC2020 = mat3(\n\tvec3( 0.6274, 0.0691, 0.0164 ),\n\tvec3( 0.3293, 0.9195, 0.0880 ),\n\tvec3( 0.0433, 0.0113, 0.8956 )\n);\nvec3 agxDefaultContrastApprox( vec3 x ) {\n\tvec3 x2 = x * x;\n\tvec3 x4 = x2 * x2;\n\treturn + 15.5 * x4 * x2\n\t\t- 40.14 * x4 * x\n\t\t+ 31.96 * x4\n\t\t- 6.868 * x2 * x\n\t\t+ 0.4298 * x2\n\t\t+ 0.1191 * x\n\t\t- 0.00232;\n}\nvec3 AgXToneMapping( vec3 color ) {\n\tconst mat3 AgXInsetMatrix = mat3(\n\t\tvec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ),\n\t\tvec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ),\n\t\tvec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 )\n\t);\n\tconst mat3 AgXOutsetMatrix = mat3(\n\t\tvec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ),\n\t\tvec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ),\n\t\tvec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 )\n\t);\n\tconst float AgxMinEv = - 12.47393;\tconst float AgxMaxEv = 4.026069;\n\tcolor
14037= LINEAR_SRGB_TO_LINEAR_REC2020 * color;\n\tcolor *= toneMappingExposure;\n\tcolor = AgXInsetMatrix * color;\n\tcolor = max( color, 1e-10 );\tcolor = log2( color );\n\tcolor = ( color - AgxMinEv ) / ( AgxMaxEv - AgxMinEv );\n\tcolor = clamp( color, 0.0, 1.0 );\n\tcolor = agxDefaultContrastApprox( color );\n\tcolor = AgXOutsetMatrix * color;\n\tcolor = pow( max( vec3( 0.0 ), color ), vec3( 2.2 ) );\n\tcolor = LINEAR_REC2020_TO_LINEAR_SRGB * color;\n\treturn color;\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }"; 14038 14039var transmission_fragment = "#ifdef USE_TRANSMISSION\n\tmaterial.transmission = transmission;\n\tmaterial.transmissionAlpha = 1.0;\n\tmaterial.thickness = thickness;\n\tmaterial.attenuationDistance = attenuationDistance;\n\tmaterial.attenuationColor = attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tmaterial.transmission *= texture2D( transmissionMap, vTransmissionMapUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tmaterial.thickness *= texture2D( thicknessMap, vThicknessMapUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmitted = getIBLVolumeRefraction(\n\t\tn, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, material.ior, material.thickness,\n\t\tmaterial.attenuationColor, material.attenuationDistance );\n\tmaterial.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission );\n\ttotalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission );\n#endif"; 14040 14041var transmission_pars_fragment = "#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thickness;\n\tuniform float attenuationDistance;\n\tuniform vec3 attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tuniform sampler2D transmissionMap;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tuniform sampler2D thicknessMap;\n\t#endif\n\tuniform vec2 transmissionSamplerSize;\n\tuniform sampler2D transmissionSamplerMap;\n\tuniform mat4 modelMatrix;\n\tuniform mat4 projectionMatrix;\n\tvarying vec3 vWorldPosition;\n\tfloat w0( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - a + 3.0 ) - 3.0 ) + 1.0 );\n\t}\n\tfloat w1( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * ( 3.0 * a - 6.0 ) + 4.0 );\n\t}\n\tfloat w2( float a ){\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - 3.0 * a + 3.0 ) + 3.0 ) + 1.0 );\n\t}\n\tfloat w3( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * a );\n\t}\n\tfloat g0( float a ) {\n\t\treturn w0( a ) + w1( a );\n\t}\n\tfloat g1( float a ) {\n\t\treturn w2( a ) + w3( a );\n\t}\n\tfloat h0( float a ) {\n\t\treturn - 1.0 + w1( a ) / ( w0( a ) + w1( a ) );\n\t}\n\tfloat h1( float a ) {\n\t\treturn 1.0 + w3( a ) / ( w2( a ) + w3( a ) );\n\t}\n\tvec4 bicubic( sampler2D tex, vec2 uv, vec4 texelSize, float lod ) {\n\t\tuv = uv * texelSize.zw + 0.5;\n\t\tvec2 iuv = floor( uv );\n\t\tvec2 fuv = fract( uv );\n\t\tfloat g0x = g0( fuv.x );\n\t\tfloat g1x = g1( fuv.x );\n\t\tfloat h0x = h0( fuv.x );\n\t\tfloat h1x = h1( fuv.x );\n\t\tfloat h0y = h0( fuv.y );\n\t\tfloat h1y = h1( fuv.y );\n\t\tvec2 p0 = ( vec2( iuv.x + h0x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p1 = ( vec2( iuv.x + h1x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p2 = ( vec2( iuv.x + h0x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p3 = ( vec2( iuv.x + h1x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\treturn g0( fuv.y ) * ( g0x * textureLod( tex, p0, lod ) + g1x * textureLod( tex, p1, lod ) ) +\n\t\t\tg1( fuv.y ) * ( g0x * textureLod( tex, p2, lod ) + g1x * textureLod( tex, p3, lod ) );\n\t}\n\tvec4 textureBicubic( sampler2D sampler, vec2 uv, float lod ) {\n\t\tvec2 fLodSize = vec2( textureSize( sampler, int( lod ) ) );\n\t\tvec2 cLodSize = vec2( textureSize( sampler, int( lod + 1.0 ) ) );\n\t\tvec2 fLodSizeInv = 1.0 / fLodSize;\n\t\tvec2 cLodSizeInv = 1.0 / cLodSize;\n\t\tvec4 fSample = bicubic( sampler, uv, vec4( fLodSizeInv, fLodSize ), floor( lod ) );\n\t\tvec4 cSample = bicubic( sampler, uv, vec4( cLodSizeInv, cLodSize ), ceil( lod ) );\n\t\treturn mix( fSample, cSample, fract( lod ) );\n\t}\n\tvec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) {\n\t\tvec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n\t\tvec3 modelScale;\n\t\tmodelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n\t\tmodelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n\t\tmodelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n\t\treturn normalize( refractionVector ) * thickness * modelScale;\n\t}\n\tfloat applyIorToRoughness( const in float roughness, const in float ior ) {\n\t\treturn roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n\t}\n\tvec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {\n\t\tfloat lod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );\n\t\treturn textureBicubic( transmissionSamplerMap, fragCoord.xy, lod );\n\t}\n\tvec3 volumeAttenuation( const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tif ( isinf( attenuationDistance ) ) {\n\t\t\treturn vec3( 1.0 );\n\t\t} else {\n\t\t\tvec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n\t\t\tvec3 transmittance = exp( - attenuationCoefficient * transmissionDistance );\t\t\treturn transmittance;\n\t\t}\n\t}\n\tvec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,\n\t\tconst in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,\n\t\tconst in mat4 viewMatrix, const in mat4 projMatrix, const in float ior, const in float thickness,\n\t\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\trefractionCoords += 1.0;\n\t\trefractionCoords /= 2.0;\n\t\tvec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\tvec3 transmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\tvec3 attenuatedColor = transmittance * transmittedLight.rgb;\n\t\tvec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n\t\tfloat transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0;\n\t\treturn vec4( ( 1.0 - F ) * attenuatedColor, 1.0 - ( 1.0 - transmittedLight.a ) * transmittanceFactor );\n\t}\n#endif"; 14042 14043var uv_pars_fragment = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tvarying vec2 vMapUv;
14043\n#endif\n#ifdef USE_ALPHAMAP\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif"; 14044 14045var uv_pars_vertex = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tuniform mat3 mapTransform;\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform mat3 alphaMapTransform;\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tuniform mat3 lightMapTransform;\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tuniform mat3 aoMapTransform;\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tuniform mat3 bumpMapTransform;\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tuniform mat3 normalMapTransform;\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tuniform mat3 displacementMapTransform;\n\tvarying vec2 vDisplacementMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tuniform mat3 emissiveMapTransform;\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tuniform mat3 metalnessMapTransform;\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tuniform mat3 roughnessMapTransform;\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tuniform mat3 anisotropyMapTransform;\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tuniform mat3 clearcoatMapTransform;\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform mat3 clearcoatNormalMapTransform;\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform mat3 clearcoatRoughnessMapTransform;\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tuniform mat3 sheenColorMapTransform;\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tuniform mat3 sheenRoughnessMapTransform;\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tuniform mat3 iridescenceMapTransform;\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform mat3 iridescenceThicknessMapTransform;\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tuniform mat3 specularMapTransform;\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tuniform mat3 specularColorMapTransform;\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tuniform mat3 specularIntensityMapTransform;\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif"; 14046 14047var uv_vertex = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvUv = vec3( uv, 1 ).xy;\n#endif\n#ifdef USE_MAP\n\tvMapUv = ( mapTransform * vec3( MAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ALPHAMAP\n\tvAlphaMapUv = ( alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_LIGHTMAP\n\tvLightMapUv = ( lightMapTransform * vec3( LIGHTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_AOMAP\n\tvAoMapUv = ( aoMapTransform * vec3( AOMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_BUMPMAP\n\tvBumpMapUv = ( bumpMapTransform * vec3( BUMPMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_NORMALMAP\n\tvNormalMapUv = ( normalMapTransform * vec3( NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tvDisplacementMapUv = ( displacementMapTransform * vec3( DISPLACEMENTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvEmissiveMapUv = ( emissiveMapTransform * vec3( EMISSIVEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_METALNESSMAP\n\tvMetalnessMapUv = ( metalnessMapTransform * vec3( METALNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvRoughnessMapUv = ( roughnessMapTransform * vec3( ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvAnisotropyMapUv = ( anisotropyMapTransform * vec3( ANISOTROPYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvClearcoatMapUv = ( clearcoatMapTransform * vec3( CLEARCOATMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvClearcoatNormalMapUv = ( clearcoatNormalMapTransform * vec3( CLEARCOAT_NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvClearcoatRoughnessMapUv = ( clearcoatRoughnessMapTransform * vec3( CLEARCOAT_ROUGHNESSMAP_UV, 1 ) ).xy;
14047\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvIridescenceMapUv = ( iridescenceMapTransform * vec3( IRIDESCENCEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvIridescenceThicknessMapUv = ( iridescenceThicknessMapTransform * vec3( IRIDESCENCE_THICKNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvSheenColorMapUv = ( sheenColorMapTransform * vec3( SHEEN_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvSheenRoughnessMapUv = ( sheenRoughnessMapTransform * vec3( SHEEN_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULARMAP\n\tvSpecularMapUv = ( specularMapTransform * vec3( SPECULARMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvSpecularColorMapUv = ( specularColorMapTransform * vec3( SPECULAR_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvSpecularIntensityMapUv = ( specularIntensityMapTransform * vec3( SPECULAR_INTENSITYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tvTransmissionMapUv = ( transmissionMapTransform * vec3( TRANSMISSIONMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_THICKNESSMAP\n\tvThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy;\n#endif"; 14048 14049var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_BATCHING\n\t\tworldPosition = batchingMatrix * worldPosition;\n\t#endif\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif"; 14050 14051const vertex$h = "varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}"; 14052 14053const fragment$h = "uniform sampler2D t2D;\nuniform float backgroundIntensity;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\ttexColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}"; 14054 14055const vertex$g = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\tgl_Position.z = gl_Position.w;\n}"; 14056 14057const fragment$g = "#ifdef ENVMAP_TYPE_CUBE\n\tuniform samplerCube envMap;\n#elif defined( ENVMAP_TYPE_CUBE_UV )\n\tuniform sampler2D envMap;\n#endif\nuniform float flipEnvMap;\nuniform float backgroundBlurriness;\nuniform float backgroundIntensity;\nvarying vec3 vWorldDirection;\n#include <cube_uv_reflection_fragment>\nvoid main() {\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 texColor = textureCube( envMap, vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 texColor = textureCubeUV( envMap, vWorldDirection, backgroundBlurriness );\n\t#else\n\t\tvec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}"; 14058 14059const vertex$f = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\tgl_Position.z = gl_Position.w;\n}"; 14060 14061const fragment$f = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldDirection;\nvoid main() {\n\tvec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) );\n\tgl_FragColor = texColor;\n\tgl_FragColor.a *= opacity;\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}"; 14062 14063const vertex$e = "#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include <uv_vertex>\n\t#include <batching_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvHighPrecisionZW = gl_Position.zw;\n}"; 14064 14065const fragment$e = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include <common>\n#include <packing>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <logdepthbuf_fragment>\n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}"; 14066 14067const vertex$d = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <batching_vertex>\n\t#include <skinbase_vertex>\n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <worldpos_vertex>\n\t#include <clipping_planes_vertex>\n\tvWorldPosition = worldPosition.xyz;\n}"; 14068 14069const fragment$d = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include <common>\n#include <packing>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main () {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}"; 14070 14071const vertex$c = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n}"; 14072 14073const fragment$c = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}"; 14074 14075const vertex$b = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include <common>\n#include <uv_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphcolor_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}"; 14076 14077const fragment$b = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include <common>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n}"; 14078 14079const vertex$a = "#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include <beginnormal_vertex>\n\t\t#include <morphnormal_vertex>\n\t\t#include <skinbase_vertex>\n\t\t#include <skinnormal_vertex>\n\t\t#include <defaultnormal_vertex>\n\t#endif\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <fog_vertex>\n}"; 14080 14081const fragment$a = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include <common>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <specularmap_fragment>\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\treflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include <aomap_fragment>\n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include <envmap_fragment>\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}"; 14082 14083const vertex$9 = "#define LAMBERT\nvarying vec3 vViewPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}"; 14084 14085const fragment$9 = "#define LAMBERT\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <normal_pars_fragment>\n#include <lights_lambert_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <specularmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_lambert_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}"; 14086 14087const vertex$8 = "#define MATCAP\nvarying vec3 vViewPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <color_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>
14087\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n\tvViewPosition = - mvPosition.xyz;\n}"; 14088 14089const fragment$8 = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#include <common>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <fog_pars_fragment>\n#include <normal_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t#else\n\t\tvec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}"; 14090 14091const vertex$7 = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}"; 14092 14093const fragment$7 = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include <packing>\n#include <uv_pars_fragment>\n#include <normal_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\t#include <logdepthbuf_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n\t#ifdef OPAQUE\n\t\tgl_FragColor.a = 1.0;\n\t#endif\n}"; 14094 14095const vertex$6 = "#define PHONG\nvarying vec3 vViewPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <envmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <envmap_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}"; 14096 14097const fragment$6 = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <normal_pars_fragment>\n#include <lights_phong_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <specularmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <specularmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_phong_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include <envmap_fragment>\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}"; 14098 14099const vertex$5 = "#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\n#endif\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}"; 14100 14101const fragment$5 = "#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define USE_SPECULAR\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef IOR\n\tuniform float ior;\n#endif\n#ifdef USE_SPECULAR\n\tuniform float specularIntensity;\n\tuniform vec3 specularColor;\n\t#ifdef USE_SPECULAR_COLORMAP\n\t\tuniform sampler2D specularColorMap;\n\t#endif\n\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\tuniform sampler2D specularIntensityMap;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT\n\tuniform float clearcoat;
14101\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_IRIDESCENCE\n\tuniform float iridescence;\n\tuniform float iridescenceIOR;\n\tuniform float iridescenceThicknessMinimum;\n\tuniform float iridescenceThicknessMaximum;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheenColor;\n\tuniform float sheenRoughness;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tuniform sampler2D sheenColorMap;\n\t#endif\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tuniform sampler2D sheenRoughnessMap;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\tuniform vec2 anisotropyVector;\n\t#ifdef USE_ANISOTROPYMAP\n\t\tuniform sampler2D anisotropyMap;\n\t#endif\n#endif\nvarying vec3 vViewPosition;\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <iridescence_fragment>\n#include <cube_uv_reflection_fragment>\n#include <envmap_common_pars_fragment>\n#include <envmap_physical_pars_fragment>\n#include <fog_pars_fragment>\n#include <lights_pars_begin>\n#include <normal_pars_fragment>\n#include <lights_physical_pars_fragment>\n#include <transmission_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <clearcoat_pars_fragment>\n#include <iridescence_pars_fragment>\n#include <roughnessmap_pars_fragment>\n#include <metalnessmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <roughnessmap_fragment>\n\t#include <metalnessmap_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <clearcoat_normal_fragment_begin>\n\t#include <clearcoat_normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_physical_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include <transmission_fragment>\n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_SHEEN\n\t\tfloat sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );\n\t\toutgoingLight = outgoingLight * sheenEnergyComp + sheenSpecularDirect + sheenSpecularIndirect;\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometryClearcoatNormal, geometryViewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + ( clearcoatSpecularDirect + clearcoatSpecularIndirect ) * material.clearcoat;
14101\n\t#endif\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}"; 14102 14103const vertex$4 = "#define TOON\nvarying vec3 vViewPosition;\n#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex>\n#include <displacementmap_pars_vertex>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <normal_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <shadowmap_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\t#include <color_vertex>\n\t#include <morphcolor_vertex>\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <normal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <displacementmap_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\tvViewPosition = - mvPosition.xyz;\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}"; 14104 14105const fragment$4 = "#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <dithering_pars_fragment>\n#include <color_pars_fragment>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <aomap_pars_fragment>\n#include <lightmap_pars_fragment>\n#include <emissivemap_pars_fragment>\n#include <gradientmap_pars_fragment>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <normal_pars_fragment>\n#include <lights_toon_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <bumpmap_pars_fragment>\n#include <normalmap_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <color_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\t#include <normal_fragment_begin>\n\t#include <normal_fragment_maps>\n\t#include <emissivemap_fragment>\n\t#include <lights_toon_fragment>\n\t#include <lights_fragment_begin>\n\t#include <lights_fragment_maps>\n\t#include <lights_fragment_end>\n\t#include <aomap_fragment>\n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n\t#include <dithering_fragment>\n}"; 14106 14107const vertex$3 = "uniform float size;\nuniform float scale;\n#include <common>\n#include <color_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\n#ifdef USE_POINTS_UV\n\tvarying vec2 vUv;\n\tuniform mat3 uvTransform;\n#endif\nvoid main() {\n\t#ifdef USE_POINTS_UV\n\t\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\t#endif\n\t#include <color_vertex>\n\t#include <morphcolor_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <project_vertex>\n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <worldpos_vertex>\n\t#include <fog_vertex>\n}"; 14108 14109const fragment$3 = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <color_pars_fragment>\n#include <map_particle_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_particle_fragment>\n\t#include <color_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n\t#include <premultiplied_alpha_fragment>\n}"; 14110 14111const vertex$2 = "#include <common>\n#include <batching_pars_vertex>\n#include <fog_pars_vertex>\n#include <morphtarget_pars_vertex>\n#include <skinning_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <shadowmap_pars_vertex>\nvoid main() {\n\t#include <batching_vertex>\n\t#include <beginnormal_vertex>\n\t#include <morphnormal_vertex>\n\t#include <skinbase_vertex>\n\t#include <skinnormal_vertex>\n\t#include <defaultnormal_vertex>\n\t#include <begin_vertex>\n\t#include <morphtarget_vertex>\n\t#include <skinning_vertex>\n\t#include <project_vertex>\n\t#include <logdepthbuf_vertex>\n\t#include <worldpos_vertex>\n\t#include <shadowmap_vertex>\n\t#include <fog_vertex>\n}"; 14112 14113const fragment$2 = "uniform vec3 color;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <logdepthbuf_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\nvoid main() {\n\t#include <logdepthbuf_fragment>\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n}"; 14114 14115const vertex$1 = "uniform float rotation;\nuniform vec2 center;\n#include <common>\n#include <uv_pars_vertex>\n#include <fog_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}"; 14116 14117const fragment$1 = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n}"; 14118 14119const ShaderChunk = { 14120 alphahash_fragment: alphahash_fragment, 14121 alphahash_pars_fragment: alphahash_pars_fragment, 14122 alphamap_fragment: alphamap_fragment, 14123 alphamap_pars_fragment: alphamap_pars_fragment, 14124 alphatest_fragment: alphatest_fragment, 14125 alphatest_pars_fragment: alphatest_pars_fragment, 14126 aomap_fragment: aomap_fragment, 14127 aomap_pars_fragment: aomap_pars_fragment, 14128 batching_pars_vertex: batching_pars_vertex, 14129 batching_vertex: batching_vertex, 14130 begin_vertex: begin_vertex, 14131 beginnormal_vertex: beginnormal_vertex, 14132 bsdfs: bsdfs, 14133 iridescence_fragment: iridescence_fragment, 14134 bumpmap_pars_fragment: bumpmap_pars_fragment, 14135 clipping_planes_fragment: clipping_planes_fragment, 14136 clipping_planes_pars_fragment: clipping_planes_pars_fragment, 14137 clipping_planes_pars_vertex: clipping_planes_pars_vertex, 14138 clipping_planes_vertex: clipping_planes_vertex, 14139 color_fragment: color_fragment, 14140 color_pars_fragment: color_pars_fragment, 14141 color_pars_vertex: color_pars_vertex, 14142 color_vertex: color_vertex, 14143 common: common, 14144 cube_uv_reflection_fragment: cube_uv_reflection_fragment, 14145 defaultnormal_vertex: defaultnormal_vertex,
vendor: 12,224 bytes, lines 14146-14616
14146 displacementmap_pars_vertex: displacementmap_pars_vertex, 14147 displacementmap_vertex: displacementmap_vertex, 14148 emissivemap_fragment: emissivemap_fragment, 14149 emissivemap_pars_fragment: emissivemap_pars_fragment, 14150 colorspace_fragment: colorspace_fragment, 14151 colorspace_pars_fragment: colorspace_pars_fragment, 14152 envmap_fragment: envmap_fragment, 14153 envmap_common_pars_fragment: envmap_common_pars_fragment, 14154 envmap_pars_fragment: envmap_pars_fragment, 14155 envmap_pars_vertex: envmap_pars_vertex, 14156 envmap_physical_pars_fragment: envmap_physical_pars_fragment, 14157 envmap_vertex: envmap_vertex, 14158 fog_vertex: fog_vertex, 14159 fog_pars_vertex: fog_pars_vertex, 14160 fog_fragment: fog_fragment, 14161 fog_pars_fragment: fog_pars_fragment, 14162 gradientmap_pars_fragment: gradientmap_pars_fragment, 14163 lightmap_fragment: lightmap_fragment, 14164 lightmap_pars_fragment: lightmap_pars_fragment, 14165 lights_lambert_fragment: lights_lambert_fragment, 14166 lights_lambert_pars_fragment: lights_lambert_pars_fragment, 14167 lights_pars_begin: lights_pars_begin, 14168 lights_toon_fragment: lights_toon_fragment, 14169 lights_toon_pars_fragment: lights_toon_pars_fragment, 14170 lights_phong_fragment: lights_phong_fragment, 14171 lights_phong_pars_fragment: lights_phong_pars_fragment, 14172 lights_physical_fragment: lights_physical_fragment, 14173 lights_physical_pars_fragment: lights_physical_pars_fragment, 14174 lights_fragment_begin: lights_fragment_begin, 14175 lights_fragment_maps: lights_fragment_maps, 14176 lights_fragment_end: lights_fragment_end, 14177 logdepthbuf_fragment: logdepthbuf_fragment, 14178 logdepthbuf_pars_fragment: logdepthbuf_pars_fragment, 14179 logdepthbuf_pars_vertex: logdepthbuf_pars_vertex, 14180 logdepthbuf_vertex: logdepthbuf_vertex, 14181 map_fragment: map_fragment, 14182 map_pars_fragment: map_pars_fragment, 14183 map_particle_fragment: map_particle_fragment, 14184 map_particle_pars_fragment: map_particle_pars_fragment, 14185 metalnessmap_fragment: metalnessmap_fragment, 14186 metalnessmap_pars_fragment: metalnessmap_pars_fragment, 14187 morphcolor_vertex: morphcolor_vertex, 14188 morphnormal_vertex: morphnormal_vertex, 14189 morphtarget_pars_vertex: morphtarget_pars_vertex, 14190 morphtarget_vertex: morphtarget_vertex, 14191 normal_fragment_begin: normal_fragment_begin, 14192 normal_fragment_maps: normal_fragment_maps, 14193 normal_pars_fragment: normal_pars_fragment, 14194 normal_pars_vertex: normal_pars_vertex, 14195 normal_vertex: normal_vertex, 14196 normalmap_pars_fragment: normalmap_pars_fragment, 14197 clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin, 14198 clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps, 14199 clearcoat_pars_fragment: clearcoat_pars_fragment, 14200 iridescence_pars_fragment: iridescence_pars_fragment, 14201 opaque_fragment: opaque_fragment, 14202 packing: packing, 14203 premultiplied_alpha_fragment: premultiplied_alpha_fragment, 14204 project_vertex: project_vertex, 14205 dithering_fragment: dithering_fragment, 14206 dithering_pars_fragment: dithering_pars_fragment, 14207 roughnessmap_fragment: roughnessmap_fragment, 14208 roughnessmap_pars_fragment: roughnessmap_pars_fragment, 14209 shadowmap_pars_fragment: shadowmap_pars_fragment, 14210 shadowmap_pars_vertex: shadowmap_pars_vertex, 14211 shadowmap_vertex: shadowmap_vertex, 14212 shadowmask_pars_fragment: shadowmask_pars_fragment, 14213 skinbase_vertex: skinbase_vertex, 14214 skinning_pars_vertex: skinning_pars_vertex, 14215 skinning_vertex: skinning_vertex, 14216 skinnormal_vertex: skinnormal_vertex, 14217 specularmap_fragment: specularmap_fragment, 14218 specularmap_pars_fragment: specularmap_pars_fragment, 14219 tonemapping_fragment: tonemapping_fragment, 14220 tonemapping_pars_fragment: tonemapping_pars_fragment, 14221 transmission_fragment: transmission_fragment, 14222 transmission_pars_fragment: transmission_pars_fragment, 14223 uv_pars_fragment: uv_pars_fragment, 14224 uv_pars_vertex: uv_pars_vertex, 14225 uv_vertex: uv_vertex, 14226 worldpos_vertex: worldpos_vertex, 14227 14228 background_vert: vertex$h, 14229 background_frag: fragment$h, 14230 backgroundCube_vert: vertex$g, 14231 backgroundCube_frag: fragment$g, 14232 cube_vert: vertex$f, 14233 cube_frag: fragment$f, 14234 depth_vert: vertex$e, 14235 depth_frag: fragment$e, 14236 distanceRGBA_vert: vertex$d, 14237 distanceRGBA_frag: fragment$d, 14238 equirect_vert: vertex$c, 14239 equirect_frag: fragment$c, 14240 linedashed_vert: vertex$b, 14241 linedashed_frag: fragment$b, 14242 meshbasic_vert: vertex$a, 14243 meshbasic_frag: fragment$a, 14244 meshlambert_vert: vertex$9, 14245 meshlambert_frag: fragment$9, 14246 meshmatcap_vert: vertex$8, 14247 meshmatcap_frag: fragment$8, 14248 meshnormal_vert: vertex$7, 14249 meshnormal_frag: fragment$7, 14250 meshphong_vert: vertex$6, 14251 meshphong_frag: fragment$6, 14252 meshphysical_vert: vertex$5, 14253 meshphysical_frag: fragment$5, 14254 meshtoon_vert: vertex$4, 14255 meshtoon_frag: fragment$4, 14256 points_vert: vertex$3, 14257 points_frag: fragment$3, 14258 shadow_vert: vertex$2, 14259 shadow_frag: fragment$2, 14260 sprite_vert: vertex$1, 14261 sprite_frag: fragment$1 14262}; 14263 14264/** 14265 * Uniforms library for shared webgl shaders 14266 */ 14267 14268const UniformsLib = { 14269 14270 common: { 14271 14272 diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, 14273 opacity: { value: 1.0 }, 14274 14275 map: { value: null }, 14276 mapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14277 14278 alphaMap: { value: null }, 14279 alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14280 14281 alphaTest: { value: 0 } 14282 14283 }, 14284 14285 specularmap: { 14286 14287 specularMap: { value: null }, 14288 specularMapTransform: { value: /*@__PURE__*/ new Matrix3() } 14289 14290 }, 14291 14292 envmap: { 14293 14294 envMap: { value: null }, 14295 flipEnvMap: { value: - 1 }, 14296 reflectivity: { value: 1.0 }, // basic, lambert, phong 14297 ior: { value: 1.5 }, // physical 14298 refractionRatio: { value: 0.98 }, // basic, lambert, phong 14299 14300 }, 14301 14302 aomap: { 14303 14304 aoMap: { value: null }, 14305 aoMapIntensity: { value: 1 }, 14306 aoMapTransform: { value: /*@__PURE__*/ new Matrix3() } 14307 14308 }, 14309 14310 lightmap: { 14311 14312 lightMap: { value: null }, 14313 lightMapIntensity: { value: 1 }, 14314 lightMapTransform: { value: /*@__PURE__*/ new Matrix3() } 14315 14316 }, 14317 14318 bumpmap: { 14319 14320 bumpMap: { value: null }, 14321 bumpMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14322 bumpScale: { value: 1 } 14323 14324 }, 14325 14326 normalmap: { 14327 14328 normalMap: { value: null }, 14329 normalMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14330 normalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) } 14331 14332 }, 14333 14334 displacementmap: { 14335 14336 displacementMap: { value: null }, 14337 displacementMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14338 displacementScale: { value: 1 }, 14339 displacementBias: { value: 0 } 14340 14341 }, 14342 14343 emissivemap: { 14344 14345 emissiveMap: { value: null }, 14346 emissiveMapTransform: { value: /*@__PURE__*/ new Matrix3() } 14347 14348 }, 14349 14350 metalnessmap: { 14351 14352 metalnessMap: { value: null }, 14353 metalnessMapTransform: { value: /*@__PURE__*/ new Matrix3() } 14354 14355 }, 14356 14357 roughnessmap: { 14358 14359 roughnessMap: { value: null }, 14360 roughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() } 14361 14362 }, 14363 14364 gradientmap: { 14365 14366 gradientMap: { value: null } 14367 14368 }, 14369 14370 fog: { 14371 14372 fogDensity: { value: 0.00025 }, 14373 fogNear: { value: 1 }, 14374 fogFar: { value: 2000 }, 14375 fogColor: { value: /*@__PURE__*/ new Color( 0xffffff ) } 14376 14377 }, 14378 14379 lights: { 14380 14381 ambientLightColor: { value: [] }, 14382 14383 lightProbe: { value: [] }, 14384 14385 directionalLights: { value: [], properties: { 14386 direction: {}, 14387 color: {} 14388 } }, 14389 14390 directionalLightShadows: { value: [], properties: { 14391 shadowBias: {}, 14392 shadowNormalBias: {}, 14393 shadowRadius: {}, 14394 shadowMapSize: {} 14395 } }, 14396 14397 directionalShadowMap: { value: [] }, 14398 directionalShadowMatrix: { value: [] }, 14399 14400 spotLights: { value: [], properties: { 14401 color: {}, 14402 position: {}, 14403 direction: {}, 14404 distance: {}, 14405 coneCos: {}, 14406 penumbraCos: {}, 14407 decay: {} 14408 } }, 14409 14410 spotLightShadows: { value: [], properties: { 14411 shadowBias: {}, 14412 shadowNormalBias: {}, 14413 shadowRadius: {}, 14414 shadowMapSize: {} 14415 } }, 14416 14417 spotLightMap: { value: [] }, 14418 spotShadowMap: { value: [] }, 14419 spotLightMatrix: { value: [] }, 14420 14421 pointLights: { value: [], properties: { 14422 color: {}, 14423 position: {}, 14424 decay: {}, 14425 distance: {} 14426 } }, 14427 14428 pointLightShadows: { value: [], properties: { 14429 shadowBias: {}, 14430 shadowNormalBias: {}, 14431 shadowRadius: {}, 14432 shadowMapSize: {}, 14433 shadowCameraNear: {}, 14434 shadowCameraFar: {} 14435 } }, 14436 14437 pointShadowMap: { value: [] }, 14438 pointShadowMatrix: { value: [] }, 14439 14440 hemisphereLights: { value: [], properties: { 14441 direction: {}, 14442 skyColor: {}, 14443 groundColor: {} 14444 } }, 14445 14446 // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src 14447 rectAreaLights: { value: [], properties: { 14448 color: {}, 14449 position: {}, 14450 width: {}, 14451 height: {} 14452 } }, 14453 14454 ltc_1: { value: null }, 14455 ltc_2: { value: null } 14456 14457 }, 14458 14459 points: { 14460 14461 diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, 14462 opacity: { value: 1.0 }, 14463 size: { value: 1.0 }, 14464 scale: { value: 1.0 }, 14465 map: { value: null }, 14466 alphaMap: { value: null }, 14467 alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14468 alphaTest: { value: 0 }, 14469 uvTransform: { value: /*@__PURE__*/ new Matrix3() } 14470 14471 }, 14472 14473 sprite: { 14474 14475 diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, 14476 opacity: { value: 1.0 }, 14477 center: { value: /*@__PURE__*/ new Vector2( 0.5, 0.5 ) }, 14478 rotation: { value: 0.0 }, 14479 map: { value: null }, 14480 mapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14481 alphaMap: { value: null }, 14482 alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14483 alphaTest: { value: 0 } 14484 14485 } 14486 14487}; 14488 14489const ShaderLib = { 14490 14491 basic: { 14492 14493 uniforms: /*@__PURE__*/ mergeUniforms( [ 14494 UniformsLib.common, 14495 UniformsLib.specularmap, 14496 UniformsLib.envmap, 14497 UniformsLib.aomap, 14498 UniformsLib.lightmap, 14499 UniformsLib.fog 14500 ] ), 14501 14502 vertexShader: ShaderChunk.meshbasic_vert, 14503 fragmentShader: ShaderChunk.meshbasic_frag 14504 14505 }, 14506 14507 lambert: { 14508 14509 uniforms: /*@__PURE__*/ mergeUniforms( [ 14510 UniformsLib.common, 14511 UniformsLib.specularmap, 14512 UniformsLib.envmap, 14513 UniformsLib.aomap, 14514 UniformsLib.lightmap, 14515 UniformsLib.emissivemap, 14516 UniformsLib.bumpmap, 14517 UniformsLib.normalmap, 14518 UniformsLib.displacementmap, 14519 UniformsLib.fog, 14520 UniformsLib.lights, 14521 { 14522 emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) } 14523 } 14524 ] ), 14525 14526 vertexShader: ShaderChunk.meshlambert_vert, 14527 fragmentShader: ShaderChunk.meshlambert_frag 14528 14529 }, 14530 14531 phong: { 14532 14533 uniforms: /*@__PURE__*/ mergeUniforms( [ 14534 UniformsLib.common, 14535 UniformsLib.specularmap, 14536 UniformsLib.envmap, 14537 UniformsLib.aomap, 14538 UniformsLib.lightmap, 14539 UniformsLib.emissivemap, 14540 UniformsLib.bumpmap, 14541 UniformsLib.normalmap, 14542 UniformsLib.displacementmap, 14543 UniformsLib.fog, 14544 UniformsLib.lights, 14545 { 14546 emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }, 14547 specular: { value: /*@__PURE__*/ new Color( 0x111111 ) }, 14548 shininess: { value: 30 } 14549 } 14550 ] ), 14551 14552 vertexShader: ShaderChunk.meshphong_vert, 14553 fragmentShader: ShaderChunk.meshphong_frag 14554 14555 }, 14556 14557 standard: { 14558 14559 uniforms: /*@__PURE__*/ mergeUniforms( [ 14560 UniformsLib.common, 14561 UniformsLib.envmap, 14562 UniformsLib.aomap, 14563 UniformsLib.lightmap, 14564 UniformsLib.emissivemap, 14565 UniformsLib.bumpmap, 14566 UniformsLib.normalmap, 14567 UniformsLib.displacementmap, 14568 UniformsLib.roughnessmap, 14569 UniformsLib.metalnessmap, 14570 UniformsLib.fog, 14571 UniformsLib.lights, 14572 { 14573 emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }, 14574 roughness: { value: 1.0 }, 14575 metalness: { value: 0.0 }, 14576 envMapIntensity: { value: 1 } // temporary 14577 } 14578 ] ), 14579 14580 vertexShader: ShaderChunk.meshphysical_vert, 14581 fragmentShader: ShaderChunk.meshphysical_frag 14582 14583 }, 14584 14585 toon: { 14586 14587 uniforms: /*@__PURE__*/ mergeUniforms( [ 14588 UniformsLib.common, 14589 UniformsLib.aomap, 14590 UniformsLib.lightmap, 14591 UniformsLib.emissivemap, 14592 UniformsLib.bumpmap, 14593 UniformsLib.normalmap, 14594 UniformsLib.displacementmap, 14595 UniformsLib.gradientmap, 14596 UniformsLib.fog, 14597 UniformsLib.lights, 14598 { 14599 emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) } 14600 } 14601 ] ), 14602 14603 vertexShader: ShaderChunk.meshtoon_vert, 14604 fragmentShader: ShaderChunk.meshtoon_frag 14605 14606 }, 14607 14608 matcap: { 14609 14610 uniforms: /*@__PURE__*/ mergeUniforms( [ 14611 UniformsLib.common, 14612 UniformsLib.bumpmap, 14613 UniformsLib.normalmap, 14614 UniformsLib.displacementmap, 14615 UniformsLib.fog, 14616 {
vendor: 5,494 bytes, lines 14617-14839
14617 matcap: { value: null } 14618 } 14619 ] ), 14620 14621 vertexShader: ShaderChunk.meshmatcap_vert, 14622 fragmentShader: ShaderChunk.meshmatcap_frag 14623 14624 }, 14625 14626 points: { 14627 14628 uniforms: /*@__PURE__*/ mergeUniforms( [ 14629 UniformsLib.points, 14630 UniformsLib.fog 14631 ] ), 14632 14633 vertexShader: ShaderChunk.points_vert, 14634 fragmentShader: ShaderChunk.points_frag 14635 14636 }, 14637 14638 dashed: { 14639 14640 uniforms: /*@__PURE__*/ mergeUniforms( [ 14641 UniformsLib.common, 14642 UniformsLib.fog, 14643 { 14644 scale: { value: 1 }, 14645 dashSize: { value: 1 }, 14646 totalSize: { value: 2 } 14647 } 14648 ] ), 14649 14650 vertexShader: ShaderChunk.linedashed_vert, 14651 fragmentShader: ShaderChunk.linedashed_frag 14652 14653 }, 14654 14655 depth: { 14656 14657 uniforms: /*@__PURE__*/ mergeUniforms( [ 14658 UniformsLib.common, 14659 UniformsLib.displacementmap 14660 ] ), 14661 14662 vertexShader: ShaderChunk.depth_vert, 14663 fragmentShader: ShaderChunk.depth_frag 14664 14665 }, 14666 14667 normal: { 14668 14669 uniforms: /*@__PURE__*/ mergeUniforms( [ 14670 UniformsLib.common, 14671 UniformsLib.bumpmap, 14672 UniformsLib.normalmap, 14673 UniformsLib.displacementmap, 14674 { 14675 opacity: { value: 1.0 } 14676 } 14677 ] ), 14678 14679 vertexShader: ShaderChunk.meshnormal_vert, 14680 fragmentShader: ShaderChunk.meshnormal_frag 14681 14682 }, 14683 14684 sprite: { 14685 14686 uniforms: /*@__PURE__*/ mergeUniforms( [ 14687 UniformsLib.sprite, 14688 UniformsLib.fog 14689 ] ), 14690 14691 vertexShader: ShaderChunk.sprite_vert, 14692 fragmentShader: ShaderChunk.sprite_frag 14693 14694 }, 14695 14696 background: { 14697 14698 uniforms: { 14699 uvTransform: { value: /*@__PURE__*/ new Matrix3() }, 14700 t2D: { value: null }, 14701 backgroundIntensity: { value: 1 } 14702 }, 14703 14704 vertexShader: ShaderChunk.background_vert, 14705 fragmentShader: ShaderChunk.background_frag 14706 14707 }, 14708 14709 backgroundCube: { 14710 14711 uniforms: { 14712 envMap: { value: null }, 14713 flipEnvMap: { value: - 1 }, 14714 backgroundBlurriness: { value: 0 }, 14715 backgroundIntensity: { value: 1 } 14716 }, 14717 14718 vertexShader: ShaderChunk.backgroundCube_vert, 14719 fragmentShader: ShaderChunk.backgroundCube_frag 14720 14721 }, 14722 14723 cube: { 14724 14725 uniforms: { 14726 tCube: { value: null }, 14727 tFlip: { value: - 1 }, 14728 opacity: { value: 1.0 } 14729 }, 14730 14731 vertexShader: ShaderChunk.cube_vert, 14732 fragmentShader: ShaderChunk.cube_frag 14733 14734 }, 14735 14736 equirect: { 14737 14738 uniforms: { 14739 tEquirect: { value: null }, 14740 }, 14741 14742 vertexShader: ShaderChunk.equirect_vert, 14743 fragmentShader: ShaderChunk.equirect_frag 14744 14745 }, 14746 14747 distanceRGBA: { 14748 14749 uniforms: /*@__PURE__*/ mergeUniforms( [ 14750 UniformsLib.common, 14751 UniformsLib.displacementmap, 14752 { 14753 referencePosition: { value: /*@__PURE__*/ new Vector3() }, 14754 nearDistance: { value: 1 }, 14755 farDistance: { value: 1000 } 14756 } 14757 ] ), 14758 14759 vertexShader: ShaderChunk.distanceRGBA_vert, 14760 fragmentShader: ShaderChunk.distanceRGBA_frag 14761 14762 }, 14763 14764 shadow: { 14765 14766 uniforms: /*@__PURE__*/ mergeUniforms( [ 14767 UniformsLib.lights, 14768 UniformsLib.fog, 14769 { 14770 color: { value: /*@__PURE__*/ new Color( 0x00000 ) }, 14771 opacity: { value: 1.0 } 14772 }, 14773 ] ), 14774 14775 vertexShader: ShaderChunk.shadow_vert, 14776 fragmentShader: ShaderChunk.shadow_frag 14777 14778 } 14779 14780}; 14781 14782ShaderLib.physical = { 14783 14784 uniforms: /*@__PURE__*/ mergeUniforms( [ 14785 ShaderLib.standard.uniforms, 14786 { 14787 clearcoat: { value: 0 }, 14788 clearcoatMap: { value: null }, 14789 clearcoatMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14790 clearcoatNormalMap: { value: null }, 14791 clearcoatNormalMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14792 clearcoatNormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) }, 14793 clearcoatRoughness: { value: 0 }, 14794 clearcoatRoughnessMap: { value: null }, 14795 clearcoatRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14796 iridescence: { value: 0 }, 14797 iridescenceMap: { value: null }, 14798 iridescenceMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14799 iridescenceIOR: { value: 1.3 }, 14800 iridescenceThicknessMinimum: { value: 100 }, 14801 iridescenceThicknessMaximum: { value: 400 }, 14802 iridescenceThicknessMap: { value: null }, 14803 iridescenceThicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14804 sheen: { value: 0 }, 14805 sheenColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, 14806 sheenColorMap: { value: null }, 14807 sheenColorMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14808 sheenRoughness: { value: 1 }, 14809 sheenRoughnessMap: { value: null }, 14810 sheenRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14811 transmission: { value: 0 }, 14812 transmissionMap: { value: null }, 14813 transmissionMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14814 transmissionSamplerSize: { value: /*@__PURE__*/ new Vector2() }, 14815 transmissionSamplerMap: { value: null }, 14816 thickness: { value: 0 }, 14817 thicknessMap: { value: null }, 14818 thicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14819 attenuationDistance: { value: 0 }, 14820 attenuationColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, 14821 specularColor: { value: /*@__PURE__*/ new Color( 1, 1, 1 ) }, 14822 specularColorMap: { value: null }, 14823 specularColorMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14824 specularIntensity: { value: 1 }, 14825 specularIntensityMap: { value: null }, 14826 specularIntensityMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14827 anisotropyVector: { value: /*@__PURE__*/ new Vector2() }, 14828 anisotropyMap: { value: null }, 14829 anisotropyMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14830 } 14831 ] ), 14832 14833 vertexShader: ShaderChunk.meshphysical_vert, 14834 fragmentShader: ShaderChunk.meshphysical_frag 14835 14836}; 14837 14838const _rgb = { r: 0, b: 0, g: 0 }; 14839
vendor: 24,395 bytes, lines 14840-15869
14840function WebGLBackground( renderer, cubemaps, cubeuvmaps, state, objects, alpha, premultipliedAlpha ) { 14841 14842 const clearColor = new Color( 0x000000 ); 14843 let clearAlpha = alpha === true ? 0 : 1; 14844 14845 let planeMesh; 14846 let boxMesh; 14847 14848 let currentBackground = null; 14849 let currentBackgroundVersion = 0; 14850 let currentTonemapping = null; 14851 14852 function render( renderList, scene ) { 14853 14854 let forceClear = false; 14855 let background = scene.isScene === true ? scene.background : null; 14856 14857 if ( background && background.isTexture ) { 14858 14859 const usePMREM = scene.backgroundBlurriness > 0; // use PMREM if the user wants to blur the background 14860 background = ( usePMREM ? cubeuvmaps : cubemaps ).get( background ); 14861 14862 } 14863 14864 if ( background === null ) { 14865 14866 setClear( clearColor, clearAlpha ); 14867 14868 } else if ( background && background.isColor ) { 14869 14870 setClear( background, 1 ); 14871 forceClear = true; 14872 14873 } 14874 14875 const environmentBlendMode = renderer.xr.getEnvironmentBlendMode(); 14876 14877 if ( environmentBlendMode === 'additive' ) { 14878 14879 state.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha ); 14880 14881 } else if ( environmentBlendMode === 'alpha-blend' ) { 14882 14883 state.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha ); 14884 14885 } 14886 14887 if ( renderer.autoClear || forceClear ) { 14888 14889 renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil ); 14890 14891 } 14892 14893 if ( background && ( background.isCubeTexture || background.mapping === CubeUVReflectionMapping ) ) { 14894 14895 if ( boxMesh === undefined ) { 14896 14897 boxMesh = new Mesh( 14898 new BoxGeometry( 1, 1, 1 ), 14899 new ShaderMaterial( { 14900 name: 'BackgroundCubeMaterial', 14901 uniforms: cloneUniforms( ShaderLib.backgroundCube.uniforms ), 14902 vertexShader: ShaderLib.backgroundCube.vertexShader, 14903 fragmentShader: ShaderLib.backgroundCube.fragmentShader, 14904 side: BackSide, 14905 depthTest: false, 14906 depthWrite: false, 14907 fog: false 14908 } ) 14909 ); 14910 14911 boxMesh.geometry.deleteAttribute( 'normal' ); 14912 boxMesh.geometry.deleteAttribute( 'uv' ); 14913 14914 boxMesh.onBeforeRender = function ( renderer, scene, camera ) { 14915 14916 this.matrixWorld.copyPosition( camera.matrixWorld ); 14917 14918 }; 14919 14920 // add "envMap" material property so the renderer can evaluate it like for built-in materials 14921 Object.defineProperty( boxMesh.material, 'envMap', { 14922 14923 get: function () { 14924 14925 return this.uniforms.envMap.value; 14926 14927 } 14928 14929 } ); 14930 14931 objects.update( boxMesh ); 14932 14933 } 14934 14935 boxMesh.material.uniforms.envMap.value = background; 14936 boxMesh.material.uniforms.flipEnvMap.value = ( background.isCubeTexture && background.isRenderTargetTexture === false ) ? - 1 : 1; 14937 boxMesh.material.uniforms.backgroundBlurriness.value = scene.backgroundBlurriness; 14938 boxMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity; 14939 boxMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer; 14940 14941 if ( currentBackground !== background || 14942 currentBackgroundVersion !== background.version || 14943 currentTonemapping !== renderer.toneMapping ) { 14944 14945 boxMesh.material.needsUpdate = true; 14946 14947 currentBackground = background; 14948 currentBackgroundVersion = background.version; 14949 currentTonemapping = renderer.toneMapping; 14950 14951 } 14952 14953 boxMesh.layers.enableAll(); 14954 14955 // push to the pre-sorted opaque render list 14956 renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null ); 14957 14958 } else if ( background && background.isTexture ) { 14959 14960 if ( planeMesh === undefined ) { 14961 14962 planeMesh = new Mesh( 14963 new PlaneGeometry( 2, 2 ), 14964 new ShaderMaterial( { 14965 name: 'BackgroundMaterial', 14966 uniforms: cloneUniforms( ShaderLib.background.uniforms ), 14967 vertexShader: ShaderLib.background.vertexShader, 14968 fragmentShader: ShaderLib.background.fragmentShader, 14969 side: FrontSide, 14970 depthTest: false, 14971 depthWrite: false, 14972 fog: false 14973 } ) 14974 ); 14975 14976 planeMesh.geometry.deleteAttribute( 'normal' ); 14977 14978 // add "map" material property so the renderer can evaluate it like for built-in materials 14979 Object.defineProperty( planeMesh.material, 'map', { 14980 14981 get: function () { 14982 14983 return this.uniforms.t2D.value; 14984 14985 } 14986 14987 } ); 14988 14989 objects.update( planeMesh ); 14990 14991 } 14992 14993 planeMesh.material.uniforms.t2D.value = background; 14994 planeMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity; 14995 planeMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer; 14996 14997 if ( background.matrixAutoUpdate === true ) { 14998 14999 background.updateMatrix(); 15000 15001 } 15002 15003 planeMesh.material.uniforms.uvTransform.value.copy( background.matrix ); 15004 15005 if ( currentBackground !== background || 15006 currentBackgroundVersion !== background.version || 15007 currentTonemapping !== renderer.toneMapping ) { 15008 15009 planeMesh.material.needsUpdate = true; 15010 15011 currentBackground = background; 15012 currentBackgroundVersion = background.version; 15013 currentTonemapping = renderer.toneMapping; 15014 15015 } 15016 15017 planeMesh.layers.enableAll(); 15018 15019 // push to the pre-sorted opaque render list 15020 renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null ); 15021 15022 } 15023 15024 } 15025 15026 function setClear( color, alpha ) { 15027 15028 color.getRGB( _rgb, getUnlitUniformColorSpace( renderer ) ); 15029 15030 state.buffers.color.setClear( _rgb.r, _rgb.g, _rgb.b, alpha, premultipliedAlpha ); 15031 15032 } 15033 15034 return { 15035 15036 getClearColor: function () { 15037 15038 return clearColor; 15039 15040 }, 15041 setClearColor: function ( color, alpha = 1 ) { 15042 15043 clearColor.set( color ); 15044 clearAlpha = alpha; 15045 setClear( clearColor, clearAlpha ); 15046 15047 }, 15048 getClearAlpha: function () { 15049 15050 return clearAlpha; 15051 15052 }, 15053 setClearAlpha: function ( alpha ) { 15054 15055 clearAlpha = alpha; 15056 setClear( clearColor, clearAlpha ); 15057 15058 }, 15059 render: render 15060 15061 }; 15062 15063} 15064 15065function WebGLBindingStates( gl, extensions, attributes, capabilities ) { 15066 15067 const maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); 15068 15069 const extension = capabilities.isWebGL2 ? null : extensions.get( 'OES_vertex_array_object' ); 15070 const vaoAvailable = capabilities.isWebGL2 || extension !== null; 15071 15072 const bindingStates = {}; 15073 15074 const defaultState = createBindingState( null ); 15075 let currentState = defaultState; 15076 let forceUpdate = false; 15077 15078 function setup( object, material, program, geometry, index ) { 15079 15080 let updateBuffers = false; 15081 15082 if ( vaoAvailable ) { 15083 15084 const state = getBindingState( geometry, program, material ); 15085 15086 if ( currentState !== state ) { 15087 15088 currentState = state; 15089 bindVertexArrayObject( currentState.object ); 15090 15091 } 15092 15093 updateBuffers = needsUpdate( object, geometry, program, index ); 15094 15095 if ( updateBuffers ) saveCache( object, geometry, program, index ); 15096 15097 } else { 15098 15099 const wireframe = ( material.wireframe === true ); 15100 15101 if ( currentState.geometry !== geometry.id || 15102 currentState.program !== program.id || 15103 currentState.wireframe !== wireframe ) { 15104 15105 currentState.geometry = geometry.id; 15106 currentState.program = program.id; 15107 currentState.wireframe = wireframe; 15108 15109 updateBuffers = true; 15110 15111 } 15112 15113 } 15114 15115 if ( index !== null ) { 15116 15117 attributes.update( index, gl.ELEMENT_ARRAY_BUFFER ); 15118 15119 } 15120 15121 if ( updateBuffers || forceUpdate ) { 15122 15123 forceUpdate = false; 15124 15125 setupVertexAttributes( object, material, program, geometry ); 15126 15127 if ( index !== null ) { 15128 15129 gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, attributes.get( index ).buffer ); 15130 15131 } 15132 15133 } 15134 15135 } 15136 15137 function createVertexArrayObject() { 15138 15139 if ( capabilities.isWebGL2 ) return gl.createVertexArray(); 15140 15141 return extension.createVertexArrayOES(); 15142 15143 } 15144 15145 function bindVertexArrayObject( vao ) { 15146 15147 if ( capabilities.isWebGL2 ) return gl.bindVertexArray( vao ); 15148 15149 return extension.bindVertexArrayOES( vao ); 15150 15151 } 15152 15153 function deleteVertexArrayObject( vao ) { 15154 15155 if ( capabilities.isWebGL2 ) return gl.deleteVertexArray( vao ); 15156 15157 return extension.deleteVertexArrayOES( vao ); 15158 15159 } 15160 15161 function getBindingState( geometry, program, material ) { 15162 15163 const wireframe = ( material.wireframe === true ); 15164 15165 let programMap = bindingStates[ geometry.id ]; 15166 15167 if ( programMap === undefined ) { 15168 15169 programMap = {}; 15170 bindingStates[ geometry.id ] = programMap; 15171 15172 } 15173 15174 let stateMap = programMap[ program.id ]; 15175 15176 if ( stateMap === undefined ) { 15177 15178 stateMap = {}; 15179 programMap[ program.id ] = stateMap; 15180 15181 } 15182 15183 let state = stateMap[ wireframe ]; 15184 15185 if ( state === undefined ) { 15186 15187 state = createBindingState( createVertexArrayObject() ); 15188 stateMap[ wireframe ] = state; 15189 15190 } 15191 15192 return state; 15193 15194 } 15195 15196 function createBindingState( vao ) { 15197 15198 const newAttributes = []; 15199 const enabledAttributes = []; 15200 const attributeDivisors = []; 15201 15202 for ( let i = 0; i < maxVertexAttributes; i ++ ) { 15203 15204 newAttributes[ i ] = 0; 15205 enabledAttributes[ i ] = 0; 15206 attributeDivisors[ i ] = 0; 15207 15208 } 15209 15210 return { 15211 15212 // for backward compatibility on non-VAO support browser 15213 geometry: null, 15214 program: null, 15215 wireframe: false, 15216 15217 newAttributes: newAttributes, 15218 enabledAttributes: enabledAttributes, 15219 attributeDivisors: attributeDivisors, 15220 object: vao, 15221 attributes: {}, 15222 index: null 15223 15224 }; 15225 15226 } 15227 15228 function needsUpdate( object, geometry, program, index ) { 15229 15230 const cachedAttributes = currentState.attributes; 15231 const geometryAttributes = geometry.attributes; 15232 15233 let attributesNum = 0; 15234 15235 const programAttributes = program.getAttributes(); 15236 15237 for ( const name in programAttributes ) { 15238 15239 const programAttribute = programAttributes[ name ]; 15240 15241 if ( programAttribute.location >= 0 ) { 15242 15243 const cachedAttribute = cachedAttributes[ name ]; 15244 let geometryAttribute = geometryAttributes[ name ]; 15245 15246 if ( geometryAttribute === undefined ) { 15247 15248 if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix; 15249 if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor; 15250 15251 } 15252 15253 if ( cachedAttribute === undefined ) return true; 15254 15255 if ( cachedAttribute.attribute !== geometryAttribute ) return true; 15256 15257 if ( geometryAttribute && cachedAttribute.data !== geometryAttribute.data ) return true; 15258 15259 attributesNum ++; 15260 15261 } 15262 15263 } 15264 15265 if ( currentState.attributesNum !== attributesNum ) return true; 15266 15267 if ( currentState.index !== index ) return true; 15268 15269 return false; 15270 15271 } 15272 15273 function saveCache( object, geometry, program, index ) { 15274 15275 const cache = {}; 15276 const attributes = geometry.attributes; 15277 let attributesNum = 0; 15278 15279 const programAttributes = program.getAttributes(); 15280 15281 for ( const name in programAttributes ) { 15282 15283 const programAttribute = programAttributes[ name ]; 15284 15285 if ( programAttribute.location >= 0 ) { 15286 15287 let attribute = attributes[ name ]; 15288 15289 if ( attribute === undefined ) { 15290 15291 if ( name === 'instanceMatrix' && object.instanceMatrix ) attribute = object.instanceMatrix; 15292 if ( name === 'instanceColor' && object.instanceColor ) attribute = object.instanceColor; 15293 15294 } 15295 15296 const data = {}; 15297 data.attribute = attribute; 15298 15299 if ( attribute && attribute.data ) { 15300 15301 data.data = attribute.data; 15302 15303 } 15304 15305 cache[ name ] = data; 15306 15307 attributesNum ++; 15308 15309 } 15310 15311 } 15312 15313 currentState.attributes = cache; 15314 currentState.attributesNum = attributesNum; 15315 15316 currentState.index = index; 15317 15318 } 15319 15320 function initAttributes() { 15321 15322 const newAttributes = currentState.newAttributes; 15323 15324 for ( let i = 0, il = newAttributes.length; i < il; i ++ ) { 15325 15326 newAttributes[ i ] = 0; 15327 15328 } 15329 15330 } 15331 15332 function enableAttribute( attribute ) { 15333 15334 enableAttributeAndDivisor( attribute, 0 ); 15335 15336 } 15337 15338 function enableAttributeAndDivisor( attribute, meshPerAttribute ) { 15339 15340 const newAttributes = currentState.newAttributes; 15341 const enabledAttributes = currentState.enabledAttributes; 15342 const attributeDivisors = currentState.attributeDivisors; 15343 15344 newAttributes[ attribute ] = 1; 15345 15346 if ( enabledAttributes[ attribute ] === 0 ) { 15347 15348 gl.enableVertexAttribArray( attribute ); 15349 enabledAttributes[ attribute ] = 1; 15350 15351 } 15352 15353 if ( attributeDivisors[ attribute ] !== meshPerAttribute ) { 15354 15355 const extension = capabilities.isWebGL2 ? gl : extensions.get( 'ANGLE_instanced_arrays' ); 15356 15357 extension[ capabilities.isWebGL2 ? 'vertexAttribDivisor' : 'vertexAttribDivisorANGLE' ]( attribute, meshPerAttribute ); 15358 attributeDivisors[ attribute ] = meshPerAttribute; 15359 15360 } 15361 15362 } 15363 15364 function disableUnusedAttributes() { 15365 15366 const newAttributes = currentState.newAttributes; 15367 const enabledAttributes = currentState.enabledAttributes; 15368 15369 for ( let i = 0, il = enabledAttributes.length; i < il; i ++ ) { 15370 15371 if ( enabledAttributes[ i ] !== newAttributes[ i ] ) { 15372 15373 gl.disableVertexAttribArray( i ); 15374 enabledAttributes[ i ] = 0; 15375 15376 } 15377 15378 } 15379 15380 } 15381 15382 function vertexAttribPointer( index, size, type, normalized, stride, offset, integer ) { 15383 15384 if ( integer === true ) { 15385 15386 gl.vertexAttribIPointer( index, size, type, stride, offset ); 15387 15388 } else { 15389 15390 gl.vertexAttribPointer( index, size, type, normalized, stride, offset ); 15391 15392 } 15393 15394 } 15395 15396 function setupVertexAttributes( object, material, program, geometry ) { 15397 15398 if ( capabilities.isWebGL2 === false && ( object.isInstancedMesh || geometry.isInstancedBufferGeometry ) ) { 15399 15400 if ( extensions.get( 'ANGLE_instanced_arrays' ) === null ) return; 15401 15402 } 15403 15404 initAttributes(); 15405 15406 const geometryAttributes = geometry.attributes; 15407 15408 const programAttributes = program.getAttributes(); 15409 15410 const materialDefaultAttributeValues = material.defaultAttributeValues; 15411 15412 for ( const name in programAttributes ) { 15413 15414 const programAttribute = programAttributes[ name ]; 15415 15416 if ( programAttribute.location >= 0 ) { 15417 15418 let geometryAttribute = geometryAttributes[ name ]; 15419 15420 if ( geometryAttribute === undefined ) { 15421 15422 if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix; 15423 if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor; 15424 15425 } 15426 15427 if ( geometryAttribute !== undefined ) { 15428 15429 const normalized = geometryAttribute.normalized; 15430 const size = geometryAttribute.itemSize; 15431 15432 const attribute = attributes.get( geometryAttribute ); 15433 15434 // TODO Attribute may not be available on context restore 15435 15436 if ( attribute === undefined ) continue; 15437 15438 const buffer = attribute.buffer; 15439 const type = attribute.type; 15440 const bytesPerElement = attribute.bytesPerElement; 15441 15442 // check for integer attributes (WebGL 2 only) 15443 15444 const integer = ( capabilities.isWebGL2 === true && ( type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === IntType ) ); 15445 15446 if ( geometryAttribute.isInterleavedBufferAttribute ) { 15447 15448 const data = geometryAttribute.data; 15449 const stride = data.stride; 15450 const offset = geometryAttribute.offset; 15451 15452 if ( data.isInstancedInterleavedBuffer ) { 15453 15454 for ( let i = 0; i < programAttribute.locationSize; i ++ ) { 15455 15456 enableAttributeAndDivisor( programAttribute.location + i, data.meshPerAttribute ); 15457 15458 } 15459 15460 if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) { 15461 15462 geometry._maxInstanceCount = data.meshPerAttribute * data.count; 15463 15464 } 15465 15466 } else { 15467 15468 for ( let i = 0; i < programAttribute.locationSize; i ++ ) { 15469 15470 enableAttribute( programAttribute.location + i ); 15471 15472 } 15473 15474 } 15475 15476 gl.bindBuffer( gl.ARRAY_BUFFER, buffer ); 15477 15478 for ( let i = 0; i < programAttribute.locationSize; i ++ ) { 15479 15480 vertexAttribPointer( 15481 programAttribute.location + i, 15482 size / programAttribute.locationSize, 15483 type, 15484 normalized, 15485 stride * bytesPerElement, 15486 ( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement, 15487 integer 15488 ); 15489 15490 } 15491 15492 } else { 15493 15494 if ( geometryAttribute.isInstancedBufferAttribute ) { 15495 15496 for ( let i = 0; i < programAttribute.locationSize; i ++ ) { 15497 15498 enableAttributeAndDivisor( programAttribute.location + i, geometryAttribute.meshPerAttribute ); 15499 15500 } 15501 15502 if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) { 15503 15504 geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; 15505 15506 } 15507 15508 } else { 15509 15510 for ( let i = 0; i < programAttribute.locationSize; i ++ ) { 15511 15512 enableAttribute( programAttribute.location + i ); 15513 15514 } 15515 15516 } 15517 15518 gl.bindBuffer( gl.ARRAY_BUFFER, buffer ); 15519 15520 for ( let i = 0; i < programAttribute.locationSize; i ++ ) { 15521 15522 vertexAttribPointer( 15523 programAttribute.location + i, 15524 size / programAttribute.locationSize, 15525 type, 15526 normalized, 15527 size * bytesPerElement, 15528 ( size / programAttribute.locationSize ) * i * bytesPerElement, 15529 integer 15530 ); 15531 15532 } 15533 15534 } 15535 15536 } else if ( materialDefaultAttributeValues !== undefined ) { 15537 15538 const value = materialDefaultAttributeValues[ name ]; 15539 15540 if ( value !== undefined ) { 15541 15542 switch ( value.length ) { 15543 15544 case 2: 15545 gl.vertexAttrib2fv( programAttribute.location, value ); 15546 break; 15547 15548 case 3: 15549 gl.vertexAttrib3fv( programAttribute.location, value ); 15550 break; 15551 15552 case 4: 15553 gl.vertexAttrib4fv( programAttribute.location, value ); 15554 break; 15555 15556 default: 15557 gl.vertexAttrib1fv( programAttribute.location, value ); 15558 15559 } 15560 15561 } 15562 15563 } 15564 15565 } 15566 15567 } 15568 15569 disableUnusedAttributes(); 15570 15571 } 15572 15573 function dispose() { 15574 15575 reset(); 15576 15577 for ( const geometryId in bindingStates ) { 15578 15579 const programMap = bindingStates[ geometryId ]; 15580 15581 for ( const programId in programMap ) { 15582 15583 const stateMap = programMap[ programId ]; 15584 15585 for ( const wireframe in stateMap ) { 15586 15587 deleteVertexArrayObject( stateMap[ wireframe ].object ); 15588 15589 delete stateMap[ wireframe ]; 15590 15591 } 15592 15593 delete programMap[ programId ]; 15594 15595 } 15596 15597 delete bindingStates[ geometryId ]; 15598 15599 } 15600 15601 } 15602 15603 function releaseStatesOfGeometry( geometry ) { 15604 15605 if ( bindingStates[ geometry.id ] === undefined ) return; 15606 15607 const programMap = bindingStates[ geometry.id ]; 15608 15609 for ( const programId in programMap ) { 15610 15611 const stateMap = programMap[ programId ]; 15612 15613 for ( const wireframe in stateMap ) { 15614 15615 deleteVertexArrayObject( stateMap[ wireframe ].object ); 15616 15617 delete stateMap[ wireframe ]; 15618 15619 } 15620 15621 delete programMap[ programId ]; 15622 15623 } 15624 15625 delete bindingStates[ geometry.id ]; 15626 15627 } 15628 15629 function releaseStatesOfProgram( program ) { 15630 15631 for ( const geometryId in bindingStates ) { 15632 15633 const programMap = bindingStates[ geometryId ]; 15634 15635 if ( programMap[ program.id ] === undefined ) continue; 15636 15637 const stateMap = programMap[ program.id ]; 15638 15639 for ( const wireframe in stateMap ) { 15640 15641 deleteVertexArrayObject( stateMap[ wireframe ].object ); 15642 15643 delete stateMap[ wireframe ]; 15644 15645 } 15646 15647 delete programMap[ program.id ]; 15648 15649 } 15650 15651 } 15652 15653 function reset() { 15654 15655 resetDefaultState(); 15656 forceUpdate = true; 15657 15658 if ( currentState === defaultState ) return; 15659 15660 currentState = defaultState; 15661 bindVertexArrayObject( currentState.object ); 15662 15663 } 15664 15665 // for backward-compatibility 15666 15667 function resetDefaultState() { 15668 15669 defaultState.geometry = null; 15670 defaultState.program = null; 15671 defaultState.wireframe = false; 15672 15673 } 15674 15675 return { 15676 15677 setup: setup, 15678 reset: reset, 15679 resetDefaultState: resetDefaultState, 15680 dispose: dispose, 15681 releaseStatesOfGeometry: releaseStatesOfGeometry, 15682 releaseStatesOfProgram: releaseStatesOfProgram, 15683 15684 initAttributes: initAttributes, 15685 enableAttribute: enableAttribute, 15686 disableUnusedAttributes: disableUnusedAttributes 15687 15688 }; 15689 15690} 15691 15692function WebGLBufferRenderer( gl, extensions, info, capabilities ) { 15693 15694 const isWebGL2 = capabilities.isWebGL2; 15695 15696 let mode; 15697 15698 function setMode( value ) { 15699 15700 mode = value; 15701 15702 } 15703 15704 function render( start, count ) { 15705 15706 gl.drawArrays( mode, start, count ); 15707 15708 info.update( count, mode, 1 ); 15709 15710 } 15711 15712 function renderInstances( start, count, primcount ) { 15713 15714 if ( primcount === 0 ) return; 15715 15716 let extension, methodName; 15717 15718 if ( isWebGL2 ) { 15719 15720 extension = gl; 15721 methodName = 'drawArraysInstanced'; 15722 15723 } else { 15724 15725 extension = extensions.get( 'ANGLE_instanced_arrays' ); 15726 methodName = 'drawArraysInstancedANGLE'; 15727 15728 if ( extension === null ) { 15729 15730 console.error( 'THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); 15731 return; 15732 15733 } 15734 15735 } 15736 15737 extension[ methodName ]( mode, start, count, primcount ); 15738 15739 info.update( count, mode, primcount ); 15740 15741 } 15742 15743 function renderMultiDraw( starts, counts, drawCount ) { 15744 15745 if ( drawCount === 0 ) return; 15746 15747 const extension = extensions.get( 'WEBGL_multi_draw' ); 15748 if ( extension === null ) { 15749 15750 for ( let i = 0; i < drawCount; i ++ ) { 15751 15752 this.render( starts[ i ], counts[ i ] ); 15753 15754 } 15755 15756 } else { 15757 15758 extension.multiDrawArraysWEBGL( mode, starts, 0, counts, 0, drawCount ); 15759 15760 let elementCount = 0; 15761 for ( let i = 0; i < drawCount; i ++ ) { 15762 15763 elementCount += counts[ i ]; 15764 15765 } 15766 15767 info.update( elementCount, mode, 1 ); 15768 15769 } 15770 15771 } 15772 15773 // 15774 15775 this.setMode = setMode; 15776 this.render = render; 15777 this.renderInstances = renderInstances; 15778 this.renderMultiDraw = renderMultiDraw; 15779 15780} 15781 15782function WebGLCapabilities( gl, extensions, parameters ) { 15783 15784 let maxAnisotropy; 15785 15786 function getMaxAnisotropy() { 15787 15788 if ( maxAnisotropy !== undefined ) return maxAnisotropy; 15789 15790 if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { 15791 15792 const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); 15793 15794 maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ); 15795 15796 } else { 15797 15798 maxAnisotropy = 0; 15799 15800 } 15801 15802 return maxAnisotropy; 15803 15804 } 15805 15806 function getMaxPrecision( precision ) { 15807 15808 if ( precision === 'highp' ) { 15809 15810 if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 && 15811 gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) { 15812 15813 return 'highp'; 15814 15815 } 15816 15817 precision = 'mediump'; 15818 15819 } 15820 15821 if ( precision === 'mediump' ) { 15822 15823 if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 && 15824 gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) { 15825 15826 return 'mediump'; 15827 15828 } 15829 15830 } 15831 15832 return 'lowp'; 15833 15834 } 15835 15836 const isWebGL2 = typeof WebGL2RenderingContext !== 'undefined' && gl.constructor.name === 'WebGL2RenderingContext'; 15837 15838 let precision = parameters.precision !== undefined ? parameters.precision : 'highp'; 15839 const maxPrecision = getMaxPrecision( precision ); 15840 15841 if ( maxPrecision !== precision ) { 15842 15843 console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' ); 15844 precision = maxPrecision; 15845 15846 } 15847 15848 const drawBuffers = isWebGL2 || extensions.has( 'WEBGL_draw_buffers' ); 15849 15850 const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true; 15851 15852 const maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); 15853 const maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); 15854 const maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE ); 15855 const maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE ); 15856 15857 const maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); 15858 const maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS ); 15859 const maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS ); 15860 const maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS ); 15861 15862 const vertexTextures = maxVertexTextures > 0; 15863 const floatFragmentTextures = isWebGL2 || extensions.has( 'OES_texture_float' ); 15864 const floatVertexTextures = vertexTextures && floatFragmentTextures; 15865 15866 const maxSamples = isWebGL2 ? gl.getParameter( gl.MAX_SAMPLES ) : 0; 15867 15868 return { 15869
vendor: 1,924 bytes, lines 15870-15958
15870 isWebGL2: isWebGL2, 15871 15872 drawBuffers: drawBuffers, 15873 15874 getMaxAnisotropy: getMaxAnisotropy, 15875 getMaxPrecision: getMaxPrecision, 15876 15877 precision: precision, 15878 logarithmicDepthBuffer: logarithmicDepthBuffer, 15879 15880 maxTextures: maxTextures, 15881 maxVertexTextures: maxVertexTextures, 15882 maxTextureSize: maxTextureSize, 15883 maxCubemapSize: maxCubemapSize, 15884 15885 maxAttributes: maxAttributes, 15886 maxVertexUniforms: maxVertexUniforms, 15887 maxVaryings: maxVaryings, 15888 maxFragmentUniforms: maxFragmentUniforms, 15889 15890 vertexTextures: vertexTextures, 15891 floatFragmentTextures: floatFragmentTextures, 15892 floatVertexTextures: floatVertexTextures, 15893 15894 maxSamples: maxSamples 15895 15896 }; 15897 15898} 15899 15900function WebGLClipping( properties ) { 15901 15902 const scope = this; 15903 15904 let globalState = null, 15905 numGlobalPlanes = 0, 15906 localClippingEnabled = false, 15907 renderingShadows = false; 15908 15909 const plane = new Plane(), 15910 viewNormalMatrix = new Matrix3(), 15911 15912 uniform = { value: null, needsUpdate: false }; 15913 15914 this.uniform = uniform; 15915 this.numPlanes = 0; 15916 this.numIntersection = 0; 15917 15918 this.init = function ( planes, enableLocalClipping ) { 15919 15920 const enabled = 15921 planes.length !== 0 || 15922 enableLocalClipping || 15923 // enable state of previous frame - the clipping code has to 15924 // run another frame in order to reset the state: 15925 numGlobalPlanes !== 0 || 15926 localClippingEnabled; 15927 15928 localClippingEnabled = enableLocalClipping; 15929 15930 numGlobalPlanes = planes.length; 15931 15932 return enabled; 15933 15934 }; 15935 15936 this.beginShadows = function () { 15937 15938 renderingShadows = true; 15939 projectPlanes( null ); 15940 15941 }; 15942 15943 this.endShadows = function () { 15944 15945 renderingShadows = false; 15946 15947 }; 15948 15949 this.setGlobalState = function ( planes, camera ) { 15950 15951 globalState = projectPlanes( planes, camera, 0 ); 15952 15953 }; 15954 15955 this.setState = function ( material, camera, useCache ) { 15956 15957 const planes = material.clippingPlanes, 15958 clipIntersection = material.clipIntersection,
vendor: 24,263 bytes, lines 15959-16936
15959 clipShadows = material.clipShadows; 15960 15961 const materialProperties = properties.get( material ); 15962 15963 if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) { 15964 15965 // there's no local clipping 15966 15967 if ( renderingShadows ) { 15968 15969 // there's no global clipping 15970 15971 projectPlanes( null ); 15972 15973 } else { 15974 15975 resetGlobalState(); 15976 15977 } 15978 15979 } else { 15980 15981 const nGlobal = renderingShadows ? 0 : numGlobalPlanes, 15982 lGlobal = nGlobal * 4; 15983 15984 let dstArray = materialProperties.clippingState || null; 15985 15986 uniform.value = dstArray; // ensure unique state 15987 15988 dstArray = projectPlanes( planes, camera, lGlobal, useCache ); 15989 15990 for ( let i = 0; i !== lGlobal; ++ i ) { 15991 15992 dstArray[ i ] = globalState[ i ]; 15993 15994 } 15995 15996 materialProperties.clippingState = dstArray; 15997 this.numIntersection = clipIntersection ? this.numPlanes : 0; 15998 this.numPlanes += nGlobal; 15999 16000 } 16001 16002 16003 }; 16004 16005 function resetGlobalState() { 16006 16007 if ( uniform.value !== globalState ) { 16008 16009 uniform.value = globalState; 16010 uniform.needsUpdate = numGlobalPlanes > 0; 16011 16012 } 16013 16014 scope.numPlanes = numGlobalPlanes; 16015 scope.numIntersection = 0; 16016 16017 } 16018 16019 function projectPlanes( planes, camera, dstOffset, skipTransform ) { 16020 16021 const nPlanes = planes !== null ? planes.length : 0; 16022 let dstArray = null; 16023 16024 if ( nPlanes !== 0 ) { 16025 16026 dstArray = uniform.value; 16027 16028 if ( skipTransform !== true || dstArray === null ) { 16029 16030 const flatSize = dstOffset + nPlanes * 4, 16031 viewMatrix = camera.matrixWorldInverse; 16032 16033 viewNormalMatrix.getNormalMatrix( viewMatrix ); 16034 16035 if ( dstArray === null || dstArray.length < flatSize ) { 16036 16037 dstArray = new Float32Array( flatSize ); 16038 16039 } 16040 16041 for ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) { 16042 16043 plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix ); 16044 16045 plane.normal.toArray( dstArray, i4 ); 16046 dstArray[ i4 + 3 ] = plane.constant; 16047 16048 } 16049 16050 } 16051 16052 uniform.value = dstArray; 16053 uniform.needsUpdate = true; 16054 16055 } 16056 16057 scope.numPlanes = nPlanes; 16058 scope.numIntersection = 0; 16059 16060 return dstArray; 16061 16062 } 16063 16064} 16065 16066function WebGLCubeMaps( renderer ) { 16067 16068 let cubemaps = new WeakMap(); 16069 16070 function mapTextureMapping( texture, mapping ) { 16071 16072 if ( mapping === EquirectangularReflectionMapping ) { 16073 16074 texture.mapping = CubeReflectionMapping; 16075 16076 } else if ( mapping === EquirectangularRefractionMapping ) { 16077 16078 texture.mapping = CubeRefractionMapping; 16079 16080 } 16081 16082 return texture; 16083 16084 } 16085 16086 function get( texture ) { 16087 16088 if ( texture && texture.isTexture ) { 16089 16090 const mapping = texture.mapping; 16091 16092 if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) { 16093 16094 if ( cubemaps.has( texture ) ) { 16095 16096 const cubemap = cubemaps.get( texture ).texture; 16097 return mapTextureMapping( cubemap, texture.mapping ); 16098 16099 } else { 16100 16101 const image = texture.image; 16102 16103 if ( image && image.height > 0 ) { 16104 16105 const renderTarget = new WebGLCubeRenderTarget( image.height / 2 ); 16106 renderTarget.fromEquirectangularTexture( renderer, texture ); 16107 cubemaps.set( texture, renderTarget ); 16108 16109 texture.addEventListener( 'dispose', onTextureDispose ); 16110 16111 return mapTextureMapping( renderTarget.texture, texture.mapping ); 16112 16113 } else { 16114 16115 // image not yet ready. try the conversion next frame 16116 16117 return null; 16118 16119 } 16120 16121 } 16122 16123 } 16124 16125 } 16126 16127 return texture; 16128 16129 } 16130 16131 function onTextureDispose( event ) { 16132 16133 const texture = event.target; 16134 16135 texture.removeEventListener( 'dispose', onTextureDispose ); 16136 16137 const cubemap = cubemaps.get( texture ); 16138 16139 if ( cubemap !== undefined ) { 16140 16141 cubemaps.delete( texture ); 16142 cubemap.dispose(); 16143 16144 } 16145 16146 } 16147 16148 function dispose() { 16149 16150 cubemaps = new WeakMap(); 16151 16152 } 16153 16154 return { 16155 get: get, 16156 dispose: dispose 16157 }; 16158 16159} 16160 16161class OrthographicCamera extends Camera { 16162 16163 constructor( left = - 1, right = 1, top = 1, bottom = - 1, near = 0.1, far = 2000 ) { 16164 16165 super(); 16166 16167 this.isOrthographicCamera = true; 16168 16169 this.type = 'OrthographicCamera'; 16170 16171 this.zoom = 1; 16172 this.view = null; 16173 16174 this.left = left; 16175 this.right = right; 16176 this.top = top; 16177 this.bottom = bottom; 16178 16179 this.near = near; 16180 this.far = far; 16181 16182 this.updateProjectionMatrix(); 16183 16184 } 16185 16186 copy( source, recursive ) { 16187 16188 super.copy( source, recursive ); 16189 16190 this.left = source.left; 16191 this.right = source.right; 16192 this.top = source.top; 16193 this.bottom = source.bottom; 16194 this.near = source.near; 16195 this.far = source.far; 16196 16197 this.zoom = source.zoom; 16198 this.view = source.view === null ? null : Object.assign( {}, source.view ); 16199 16200 return this; 16201 16202 } 16203 16204 setViewOffset( fullWidth, fullHeight, x, y, width, height ) { 16205 16206 if ( this.view === null ) { 16207 16208 this.view = { 16209 enabled: true, 16210 fullWidth: 1, 16211 fullHeight: 1, 16212 offsetX: 0, 16213 offsetY: 0, 16214 width: 1, 16215 height: 1 16216 }; 16217 16218 } 16219 16220 this.view.enabled = true; 16221 this.view.fullWidth = fullWidth; 16222 this.view.fullHeight = fullHeight; 16223 this.view.offsetX = x; 16224 this.view.offsetY = y; 16225 this.view.width = width; 16226 this.view.height = height; 16227 16228 this.updateProjectionMatrix(); 16229 16230 } 16231 16232 clearViewOffset() { 16233 16234 if ( this.view !== null ) { 16235 16236 this.view.enabled = false; 16237 16238 } 16239 16240 this.updateProjectionMatrix(); 16241 16242 } 16243 16244 updateProjectionMatrix() { 16245 16246 const dx = ( this.right - this.left ) / ( 2 * this.zoom ); 16247 const dy = ( this.top - this.bottom ) / ( 2 * this.zoom ); 16248 const cx = ( this.right + this.left ) / 2; 16249 const cy = ( this.top + this.bottom ) / 2; 16250 16251 let left = cx - dx; 16252 let right = cx + dx; 16253 let top = cy + dy; 16254 let bottom = cy - dy; 16255 16256 if ( this.view !== null && this.view.enabled ) { 16257 16258 const scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom; 16259 const scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom; 16260 16261 left += scaleW * this.view.offsetX; 16262 right = left + scaleW * this.view.width; 16263 top -= scaleH * this.view.offsetY; 16264 bottom = top - scaleH * this.view.height; 16265 16266 } 16267 16268 this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far, this.coordinateSystem ); 16269 16270 this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); 16271 16272 } 16273 16274 toJSON( meta ) { 16275 16276 const data = super.toJSON( meta ); 16277 16278 data.object.zoom = this.zoom; 16279 data.object.left = this.left; 16280 data.object.right = this.right; 16281 data.object.top = this.top; 16282 data.object.bottom = this.bottom; 16283 data.object.near = this.near; 16284 data.object.far = this.far; 16285 16286 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); 16287 16288 return data; 16289 16290 } 16291 16292} 16293 16294const LOD_MIN = 4; 16295 16296// The standard deviations (radians) associated with the extra mips. These are 16297// chosen to approximate a Trowbridge-Reitz distribution function times the 16298// geometric shadowing function. These sigma values squared must match the 16299// variance #defines in cube_uv_reflection_fragment.glsl.js. 16300const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ]; 16301 16302// The maximum length of the blur for loop. Smaller sigmas will use fewer 16303// samples and exit early, but not recompile the shader. 16304const MAX_SAMPLES = 20; 16305 16306const _flatCamera = /*@__PURE__*/ new OrthographicCamera(); 16307const _clearColor = /*@__PURE__*/ new Color(); 16308let _oldTarget = null; 16309let _oldActiveCubeFace = 0; 16310let _oldActiveMipmapLevel = 0; 16311 16312// Golden Ratio 16313const PHI = ( 1 + Math.sqrt( 5 ) ) / 2; 16314const INV_PHI = 1 / PHI; 16315 16316// Vertices of a dodecahedron (except the opposites, which represent the 16317// same axis), used as axis directions evenly spread on a sphere. 16318const _axisDirections = [ 16319 /*@__PURE__*/ new Vector3( 1, 1, 1 ), 16320 /*@__PURE__*/ new Vector3( - 1, 1, 1 ), 16321 /*@__PURE__*/ new Vector3( 1, 1, - 1 ), 16322 /*@__PURE__*/ new Vector3( - 1, 1, - 1 ), 16323 /*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ), 16324 /*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ), 16325 /*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ), 16326 /*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ), 16327 /*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ), 16328 /*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ) ]; 16329 16330/** 16331 * This class generates a Prefiltered, Mipmapped Radiance Environment Map 16332 * (PMREM) from a cubeMap environment texture. This allows different levels of 16333 * blur to be quickly accessed based on material roughness. It is packed into a 16334 * special CubeUV format that allows us to perform custom interpolation so that 16335 * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap 16336 * chain, it only goes down to the LOD_MIN level (above), and then creates extra 16337 * even more filtered 'mips' at the same LOD_MIN resolution, associated with 16338 * higher roughness levels. In this way we maintain resolution to smoothly 16339 * interpolate diffuse lighting while limiting sampling computation. 16340 * 16341 * Paper: Fast, Accurate Image-Based Lighting 16342 * https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view 16343*/ 16344 16345class PMREMGenerator { 16346 16347 constructor( renderer ) { 16348 16349 this._renderer = renderer; 16350 this._pingPongRenderTarget = null; 16351 16352 this._lodMax = 0; 16353 this._cubeSize = 0; 16354 this._lodPlanes = []; 16355 this._sizeLods = []; 16356 this._sigmas = []; 16357 16358 this._blurMaterial = null; 16359 this._cubemapMaterial = null; 16360 this._equirectMaterial = null; 16361 16362 this._compileMaterial( this._blurMaterial ); 16363 16364 } 16365 16366 /** 16367 * Generates a PMREM from a supplied Scene, which can be faster than using an 16368 * image if networking bandwidth is low. Optional sigma specifies a blur radius 16369 * in radians to be applied to the scene before PMREM generation. Optional near 16370 * and far planes ensure the scene is rendered in its entirety (the cubeCamera 16371 * is placed at the origin). 16372 */ 16373 fromScene( scene, sigma = 0, near = 0.1, far = 100 ) { 16374 16375 _oldTarget = this._renderer.getRenderTarget(); 16376 _oldActiveCubeFace = this._renderer.getActiveCubeFace(); 16377 _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); 16378 16379 this._setSize( 256 ); 16380 16381 const cubeUVRenderTarget = this._allocateTargets(); 16382 cubeUVRenderTarget.depthBuffer = true; 16383 16384 this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget ); 16385 16386 if ( sigma > 0 ) { 16387 16388 this._blur( cubeUVRenderTarget, 0, 0, sigma ); 16389 16390 } 16391 16392 this._applyPMREM( cubeUVRenderTarget ); 16393 this._cleanup( cubeUVRenderTarget ); 16394 16395 return cubeUVRenderTarget; 16396 16397 } 16398 16399 /** 16400 * Generates a PMREM from an equirectangular texture, which can be either LDR 16401 * or HDR. The ideal input image size is 1k (1024 x 512), 16402 * as this matches best with the 256 x 256 cubemap output. 16403 */ 16404 fromEquirectangular( equirectangular, renderTarget = null ) { 16405 16406 return this._fromTexture( equirectangular, renderTarget ); 16407 16408 } 16409 16410 /** 16411 * Generates a PMREM from an cubemap texture, which can be either LDR 16412 * or HDR. The ideal input cube size is 256 x 256, 16413 * as this matches best with the 256 x 256 cubemap output. 16414 */ 16415 fromCubemap( cubemap, renderTarget = null ) { 16416 16417 return this._fromTexture( cubemap, renderTarget ); 16418 16419 } 16420 16421 /** 16422 * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during 16423 * your texture's network fetch for increased concurrency. 16424 */ 16425 compileCubemapShader() { 16426 16427 if ( this._cubemapMaterial === null ) { 16428 16429 this._cubemapMaterial = _getCubemapMaterial(); 16430 this._compileMaterial( this._cubemapMaterial ); 16431 16432 } 16433 16434 } 16435 16436 /** 16437 * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during 16438 * your texture's network fetch for increased concurrency. 16439 */ 16440 compileEquirectangularShader() { 16441 16442 if ( this._equirectMaterial === null ) { 16443 16444 this._equirectMaterial = _getEquirectMaterial(); 16445 this._compileMaterial( this._equirectMaterial ); 16446 16447 } 16448 16449 } 16450 16451 /** 16452 * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class, 16453 * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on 16454 * one of them will cause any others to also become unusable. 16455 */ 16456 dispose() { 16457 16458 this._dispose(); 16459 16460 if ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose(); 16461 if ( this._equirectMaterial !== null ) this._equirectMaterial.dispose(); 16462 16463 } 16464 16465 // private interface 16466 16467 _setSize( cubeSize ) { 16468 16469 this._lodMax = Math.floor( Math.log2( cubeSize ) ); 16470 this._cubeSize = Math.pow( 2, this._lodMax ); 16471 16472 } 16473 16474 _dispose() { 16475 16476 if ( this._blurMaterial !== null ) this._blurMaterial.dispose(); 16477 16478 if ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose(); 16479 16480 for ( let i = 0; i < this._lodPlanes.length; i ++ ) { 16481 16482 this._lodPlanes[ i ].dispose(); 16483 16484 } 16485 16486 } 16487 16488 _cleanup( outputTarget ) { 16489 16490 this._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel ); 16491 outputTarget.scissorTest = false; 16492 _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height ); 16493 16494 } 16495 16496 _fromTexture( texture, renderTarget ) { 16497 16498 if ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) { 16499 16500 this._setSize( texture.image.length === 0 ? 16 : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) ); 16501 16502 } else { // Equirectangular 16503 16504 this._setSize( texture.image.width / 4 ); 16505 16506 } 16507 16508 _oldTarget = this._renderer.getRenderTarget(); 16509 _oldActiveCubeFace = this._renderer.getActiveCubeFace(); 16510 _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); 16511 16512 const cubeUVRenderTarget = renderTarget || this._allocateTargets(); 16513 this._textureToCubeUV( texture, cubeUVRenderTarget ); 16514 this._applyPMREM( cubeUVRenderTarget ); 16515 this._cleanup( cubeUVRenderTarget ); 16516 16517 return cubeUVRenderTarget; 16518 16519 } 16520 16521 _allocateTargets() { 16522 16523 const width = 3 * Math.max( this._cubeSize, 16 * 7 ); 16524 const height = 4 * this._cubeSize; 16525 16526 const params = { 16527 magFilter: LinearFilter, 16528 minFilter: LinearFilter, 16529 generateMipmaps: false, 16530 type: HalfFloatType, 16531 format: RGBAFormat, 16532 colorSpace: LinearSRGBColorSpace, 16533 depthBuffer: false 16534 }; 16535 16536 const cubeUVRenderTarget = _createRenderTarget( width, height, params ); 16537 16538 if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) { 16539 16540 if ( this._pingPongRenderTarget !== null ) { 16541 16542 this._dispose(); 16543 16544 } 16545 16546 this._pingPongRenderTarget = _createRenderTarget( width, height, params ); 16547 16548 const { _lodMax } = this; 16549 ( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas } = _createPlanes( _lodMax ) ); 16550 16551 this._blurMaterial = _getBlurShader( _lodMax, width, height ); 16552 16553 } 16554 16555 return cubeUVRenderTarget; 16556 16557 } 16558 16559 _compileMaterial( material ) { 16560 16561 const tmpMesh = new Mesh( this._lodPlanes[ 0 ], material ); 16562 this._renderer.compile( tmpMesh, _flatCamera ); 16563 16564 } 16565 16566 _sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) { 16567 16568 const fov = 90; 16569 const aspect = 1; 16570 const cubeCamera = new PerspectiveCamera( fov, aspect, near, far ); 16571 const upSign = [ 1, - 1, 1, 1, 1, 1 ]; 16572 const forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ]; 16573 const renderer = this._renderer; 16574 16575 const originalAutoClear = renderer.autoClear; 16576 const toneMapping = renderer.toneMapping; 16577 renderer.getClearColor( _clearColor ); 16578 16579 renderer.toneMapping = NoToneMapping; 16580 renderer.autoClear = false; 16581 16582 const backgroundMaterial = new MeshBasicMaterial( { 16583 name: 'PMREM.Background', 16584 side: BackSide, 16585 depthWrite: false, 16586 depthTest: false, 16587 } ); 16588 16589 const backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial ); 16590 16591 let useSolidColor = false; 16592 const background = scene.background; 16593 16594 if ( background ) { 16595 16596 if ( background.isColor ) { 16597 16598 backgroundMaterial.color.copy( background ); 16599 scene.background = null; 16600 useSolidColor = true; 16601 16602 } 16603 16604 } else { 16605 16606 backgroundMaterial.color.copy( _clearColor ); 16607 useSolidColor = true; 16608 16609 } 16610 16611 for ( let i = 0; i < 6; i ++ ) { 16612 16613 const col = i % 3; 16614 16615 if ( col === 0 ) { 16616 16617 cubeCamera.up.set( 0, upSign[ i ], 0 ); 16618 cubeCamera.lookAt( forwardSign[ i ], 0, 0 ); 16619 16620 } else if ( col === 1 ) { 16621 16622 cubeCamera.up.set( 0, 0, upSign[ i ] ); 16623 cubeCamera.lookAt( 0, forwardSign[ i ], 0 ); 16624 16625 } else { 16626 16627 cubeCamera.up.set( 0, upSign[ i ], 0 ); 16628 cubeCamera.lookAt( 0, 0, forwardSign[ i ] ); 16629 16630 } 16631 16632 const size = this._cubeSize; 16633 16634 _setViewport( cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size ); 16635 16636 renderer.setRenderTarget( cubeUVRenderTarget ); 16637 16638 if ( useSolidColor ) { 16639 16640 renderer.render( backgroundBox, cubeCamera ); 16641 16642 } 16643 16644 renderer.render( scene, cubeCamera ); 16645 16646 } 16647 16648 backgroundBox.geometry.dispose(); 16649 backgroundBox.material.dispose(); 16650 16651 renderer.toneMapping = toneMapping; 16652 renderer.autoClear = originalAutoClear; 16653 scene.background = background; 16654 16655 } 16656 16657 _textureToCubeUV( texture, cubeUVRenderTarget ) { 16658 16659 const renderer = this._renderer; 16660 16661 const isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ); 16662 16663 if ( isCubeTexture ) { 16664 16665 if ( this._cubemapMaterial === null ) { 16666 16667 this._cubemapMaterial = _getCubemapMaterial(); 16668 16669 } 16670 16671 this._cubemapMaterial.uniforms.flipEnvMap.value = ( texture.isRenderTargetTexture === false ) ? - 1 : 1; 16672 16673 } else { 16674 16675 if ( this._equirectMaterial === null ) { 16676 16677 this._equirectMaterial = _getEquirectMaterial(); 16678 16679 } 16680 16681 } 16682 16683 const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial; 16684 const mesh = new Mesh( this._lodPlanes[ 0 ], material ); 16685 16686 const uniforms = material.uniforms; 16687 16688 uniforms[ 'envMap' ].value = texture; 16689 16690 const size = this._cubeSize; 16691 16692 _setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size ); 16693 16694 renderer.setRenderTarget( cubeUVRenderTarget ); 16695 renderer.render( mesh, _flatCamera ); 16696 16697 } 16698 16699 _applyPMREM( cubeUVRenderTarget ) { 16700 16701 const renderer = this._renderer; 16702 const autoClear = renderer.autoClear; 16703 renderer.autoClear = false; 16704 16705 for ( let i = 1; i < this._lodPlanes.length; i ++ ) { 16706 16707 const sigma = Math.sqrt( this._sigmas[ i ] * this._sigmas[ i ] - this._sigmas[ i - 1 ] * this._sigmas[ i - 1 ] ); 16708 16709 const poleAxis = _axisDirections[ ( i - 1 ) % _axisDirections.length ]; 16710 16711 this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis ); 16712 16713 } 16714 16715 renderer.autoClear = autoClear; 16716 16717 } 16718 16719 /** 16720 * This is a two-pass Gaussian blur for a cubemap. Normally this is done 16721 * vertically and horizontally, but this breaks down on a cube. Here we apply 16722 * the blur latitudinally (around the poles), and then longitudinally (towards 16723 * the poles) to approximate the orthogonally-separable blur. It is least 16724 * accurate at the poles, but still does a decent job. 16725 */ 16726 _blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) { 16727 16728 const pingPongRenderTarget = this._pingPongRenderTarget; 16729 16730 this._halfBlur( 16731 cubeUVRenderTarget, 16732 pingPongRenderTarget, 16733 lodIn, 16734 lodOut, 16735 sigma, 16736 'latitudinal', 16737 poleAxis ); 16738 16739 this._halfBlur( 16740 pingPongRenderTarget, 16741 cubeUVRenderTarget, 16742 lodOut, 16743 lodOut, 16744 sigma, 16745 'longitudinal', 16746 poleAxis ); 16747 16748 } 16749 16750 _halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) { 16751 16752 const renderer = this._renderer; 16753 const blurMaterial = this._blurMaterial; 16754 16755 if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) { 16756 16757 console.error( 16758 'blur direction must be either latitudinal or longitudinal!' ); 16759 16760 } 16761 16762 // Number of standard deviations at which to cut off the discrete approximation. 16763 const STANDARD_DEVIATIONS = 3; 16764 16765 const blurMesh = new Mesh( this._lodPlanes[ lodOut ], blurMaterial ); 16766 const blurUniforms = blurMaterial.uniforms; 16767 16768 const pixels = this._sizeLods[ lodIn ] - 1; 16769 const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 ); 16770 const sigmaPixels = sigmaRadians / radiansPerPixel; 16771 const samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES; 16772 16773 if ( samples > MAX_SAMPLES ) { 16774 16775 console.warn( `sigmaRadians, ${ 16776 sigmaRadians}, is too large and will clip, as it requested ${ 16777 samples} samples when the maximum is set to ${MAX_SAMPLES}` ); 16778 16779 } 16780 16781 const weights = []; 16782 let sum = 0; 16783 16784 for ( let i = 0; i < MAX_SAMPLES; ++ i ) { 16785 16786 const x = i / sigmaPixels; 16787 const weight = Math.exp( - x * x / 2 ); 16788 weights.push( weight ); 16789 16790 if ( i === 0 ) { 16791 16792 sum += weight; 16793 16794 } else if ( i < samples ) { 16795 16796 sum += 2 * weight; 16797 16798 } 16799 16800 } 16801 16802 for ( let i = 0; i < weights.length; i ++ ) { 16803 16804 weights[ i ] = weights[ i ] / sum; 16805 16806 } 16807 16808 blurUniforms[ 'envMap' ].value = targetIn.texture; 16809 blurUniforms[ 'samples' ].value = samples; 16810 blurUniforms[ 'weights' ].value = weights; 16811 blurUniforms[ 'latitudinal' ].value = direction === 'latitudinal'; 16812 16813 if ( poleAxis ) { 16814 16815 blurUniforms[ 'poleAxis' ].value = poleAxis; 16816 16817 } 16818 16819 const { _lodMax } = this; 16820 blurUniforms[ 'dTheta' ].value = radiansPerPixel; 16821 blurUniforms[ 'mipInt' ].value = _lodMax - lodIn; 16822 16823 const outputSize = this._sizeLods[ lodOut ]; 16824 const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 ); 16825 const y = 4 * ( this._cubeSize - outputSize ); 16826 16827 _setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize ); 16828 renderer.setRenderTarget( targetOut ); 16829 renderer.render( blurMesh, _flatCamera ); 16830 16831 } 16832 16833} 16834 16835 16836 16837function _createPlanes( lodMax ) { 16838 16839 const lodPlanes = []; 16840 const sizeLods = []; 16841 const sigmas = []; 16842 16843 let lod = lodMax; 16844 16845 const totalLods = lodMax - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length; 16846 16847 for ( let i = 0; i < totalLods; i ++ ) { 16848 16849 const sizeLod = Math.pow( 2, lod ); 16850 sizeLods.push( sizeLod ); 16851 let sigma = 1.0 / sizeLod; 16852 16853 if ( i > lodMax - LOD_MIN ) { 16854 16855 sigma = EXTRA_LOD_SIGMA[ i - lodMax + LOD_MIN - 1 ]; 16856 16857 } else if ( i === 0 ) { 16858 16859 sigma = 0; 16860 16861 } 16862 16863 sigmas.push( sigma ); 16864 16865 const texelSize = 1.0 / ( sizeLod - 2 ); 16866 const min = - texelSize; 16867 const max = 1 + texelSize; 16868 const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ]; 16869 16870 const cubeFaces = 6; 16871 const vertices = 6; 16872 const positionSize = 3; 16873 const uvSize = 2; 16874 const faceIndexSize = 1; 16875 16876 const position = new Float32Array( positionSize * vertices * cubeFaces ); 16877 const uv = new Float32Array( uvSize * vertices * cubeFaces ); 16878 const faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces ); 16879 16880 for ( let face = 0; face < cubeFaces; face ++ ) { 16881 16882 const x = ( face % 3 ) * 2 / 3 - 1; 16883 const y = face > 2 ? 0 : - 1; 16884 const coordinates = [ 16885 x, y, 0, 16886 x + 2 / 3, y, 0, 16887 x + 2 / 3, y + 1, 0, 16888 x, y, 0, 16889 x + 2 / 3, y + 1, 0, 16890 x, y + 1, 0 16891 ]; 16892 position.set( coordinates, positionSize * vertices * face ); 16893 uv.set( uv1, uvSize * vertices * face ); 16894 const fill = [ face, face, face, face, face, face ]; 16895 faceIndex.set( fill, faceIndexSize * vertices * face ); 16896 16897 } 16898 16899 const planes = new BufferGeometry(); 16900 planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) ); 16901 planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) ); 16902 planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) ); 16903 lodPlanes.push( planes ); 16904 16905 if ( lod > LOD_MIN ) { 16906 16907 lod --; 16908 16909 } 16910 16911 } 16912 16913 return { lodPlanes, sizeLods, sigmas }; 16914 16915} 16916 16917function _createRenderTarget( width, height, params ) { 16918 16919 const cubeUVRenderTarget = new WebGLRenderTarget( width, height, params ); 16920 cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping; 16921 cubeUVRenderTarget.texture.name = 'PMREM.cubeUv'; 16922 cubeUVRenderTarget.scissorTest = true; 16923 return cubeUVRenderTarget; 16924 16925} 16926 16927function _setViewport( target, x, y, width, height ) { 16928 16929 target.viewport.set( x, y, width, height ); 16930 target.scissor.set( x, y, width, height ); 16931 16932} 16933 16934function _getBlurShader( lodMax, width, height ) { 16935 16936 const weights = new Float32Array( MAX_SAMPLES );
vendor: 3,252 bytes, lines 16937-17096
16937 const poleAxis = new Vector3( 0, 1, 0 ); 16938 const shaderMaterial = new ShaderMaterial( { 16939 16940 name: 'SphericalGaussianBlur', 16941 16942 defines: { 16943 'n': MAX_SAMPLES, 16944 'CUBEUV_TEXEL_WIDTH': 1.0 / width, 16945 'CUBEUV_TEXEL_HEIGHT': 1.0 / height, 16946 'CUBEUV_MAX_MIP': `${lodMax}.0`, 16947 }, 16948 16949 uniforms: { 16950 'envMap': { value: null }, 16951 'samples': { value: 1 }, 16952 'weights': { value: weights }, 16953 'latitudinal': { value: false }, 16954 'dTheta': { value: 0 }, 16955 'mipInt': { value: 0 }, 16956 'poleAxis': { value: poleAxis } 16957 }, 16958 16959 vertexShader: _getCommonVertexShader(), 16960 16961 fragmentShader: /* glsl */` 16962 16963 precision mediump float; 16964 precision mediump int; 16965 16966 varying vec3 vOutputDirection; 16967 16968 uniform sampler2D envMap; 16969 uniform int samples; 16970 uniform float weights[ n ]; 16971 uniform bool latitudinal; 16972 uniform float dTheta; 16973 uniform float mipInt; 16974 uniform vec3 poleAxis; 16975 16976 #define ENVMAP_TYPE_CUBE_UV 16977 #include <cube_uv_reflection_fragment> 16978 16979 vec3 getSample( float theta, vec3 axis ) { 16980 16981 float cosTheta = cos( theta ); 16982 // Rodrigues' axis-angle rotation 16983 vec3 sampleDirection = vOutputDirection * cosTheta 16984 + cross( axis, vOutputDirection ) * sin( theta ) 16985 + axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta ); 16986 16987 return bilinearCubeUV( envMap, sampleDirection, mipInt ); 16988 16989 } 16990 16991 void main() { 16992 16993 vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection ); 16994 16995 if ( all( equal( axis, vec3( 0.0 ) ) ) ) { 16996 16997 axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x ); 16998 16999 } 17000 17001 axis = normalize( axis ); 17002 17003 gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 ); 17004 gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis ); 17005 17006 for ( int i = 1; i < n; i++ ) { 17007 17008 if ( i >= samples ) { 17009 17010 break; 17011 17012 } 17013 17014 float theta = dTheta * float( i ); 17015 gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis ); 17016 gl_FragColor.rgb += weights[ i ] * getSample( theta, axis ); 17017 17018 } 17019 17020 } 17021 `, 17022 17023 blending: NoBlending, 17024 depthTest: false, 17025 depthWrite: false 17026 17027 } ); 17028 17029 return shaderMaterial; 17030 17031} 17032 17033function _getEquirectMaterial() { 17034 17035 return new ShaderMaterial( { 17036 17037 name: 'EquirectangularToCubeUV', 17038 17039 uniforms: { 17040 'envMap': { value: null } 17041 }, 17042 17043 vertexShader: _getCommonVertexShader(), 17044 17045 fragmentShader: /* glsl */` 17046 17047 precision mediump float; 17048 precision mediump int; 17049 17050 varying vec3 vOutputDirection; 17051 17052 uniform sampler2D envMap; 17053 17054 #include <common> 17055 17056 void main() { 17057 17058 vec3 outputDirection = normalize( vOutputDirection ); 17059 vec2 uv = equirectUv( outputDirection ); 17060 17061 gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 ); 17062 17063 } 17064 `, 17065 17066 blending: NoBlending, 17067 depthTest: false, 17068 depthWrite: false 17069 17070 } ); 17071 17072} 17073 17074function _getCubemapMaterial() { 17075 17076 return new ShaderMaterial( { 17077 17078 name: 'CubemapToCubeUV', 17079 17080 uniforms: { 17081 'envMap': { value: null }, 17082 'flipEnvMap': { value: - 1 } 17083 }, 17084 17085 vertexShader: _getCommonVertexShader(), 17086 17087 fragmentShader: /* glsl */` 17088 17089 precision mediump float; 17090 precision mediump int; 17091 17092 uniform float flipEnvMap; 17093 17094 varying vec3 vOutputDirection; 17095 17096 uniform samplerCube envMap;
17097 17098 void main() { 17099 17100 gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) ); 17101 17102 } 17103 `, 17104 17105 blending: NoBlending, 17106 depthTest: false, 17107 depthWrite: false 17108 17109 } ); 17110 17111} 17112 17113function _getCommonVertexShader() { 17114 17115 return /* glsl */` 17116 17117 precision mediump float; 17118 precision mediump int; 17119 17120 attribute float faceIndex; 17121 17122 varying vec3 vOutputDirection; 17123 17124 // RH coordinate system; PMREM face-indexing convention 17125 vec3 getDirection( vec2 uv, float face ) { 17126 17127 uv = 2.0 * uv - 1.0; 17128 17129 vec3 direction = vec3( uv, 1.0 ); 17130 17131 if ( face == 0.0 ) { 17132 17133 direction = direction.zyx; // ( 1, v, u ) pos x 17134 17135 } else if ( face == 1.0 ) { 17136 17137 direction = direction.xzy; 17138 direction.xz *= -1.0; // ( -u, 1, -v ) pos y 17139 17140 } else if ( face == 2.0 ) { 17141 17142 direction.x *= -1.0; // ( -u, v, 1 ) pos z 17143 17144 } else if ( face == 3.0 ) { 17145 17146 direction = direction.zyx; 17147 direction.xz *= -1.0; // ( -1, v, -u ) neg x 17148 17149 } else if ( face == 4.0 ) { 17150 17151 direction = direction.xzy; 17152 direction.xy *= -1.0; // ( -u, -1, v ) neg y 17153 17154 } else if ( face == 5.0 ) { 17155 17156 direction.z *= -1.0; // ( u, v, -1 ) neg z 17157 17158 } 17159 17160 return direction; 17161 17162 } 17163 17164 void main() { 17165 17166 vOutputDirection = getDirection( uv, faceIndex ); 17167 gl_Position = vec4( position, 1.0 ); 17168 17169 } 17170 `; 17171 17172} 17173 17174function WebGLCubeUVMaps( renderer ) { 17175 17176 let cubeUVmaps = new WeakMap(); 17177 17178 let pmremGenerator = null; 17179 17180 function get( texture ) { 17181 17182 if ( texture && texture.isTexture ) { 17183 17184 const mapping = texture.mapping; 17185 17186 const isEquirectMap = ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ); 17187 const isCubeMap = ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping ); 17188 17189 // equirect/cube map to cubeUV conversion 17190 17191 if ( isEquirectMap || isCubeMap ) { 17192 17193 if ( texture.isRenderTargetTexture && texture.needsPMREMUpdate === true ) { 17194 17195 texture.needsPMREMUpdate = false; 17196 17197 let renderTarget = cubeUVmaps.get( texture ); 17198 17199 if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer ); 17200 17201 renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture, renderTarget ) : pmremGenerator.fromCubemap( texture, renderTarget ); 17202 cubeUVmaps.set( texture, renderTarget ); 17203 17204 return renderTarget.texture; 17205 17206 } else { 17207 17208 if ( cubeUVmaps.has( texture ) ) { 17209 17210 return cubeUVmaps.get( texture ).texture; 17211 17212 } else { 17213 17214 const image = texture.image; 17215 17216 if ( ( isEquirectMap && image && image.height > 0 ) || ( isCubeMap && image && isCubeTextureComplete( image ) ) ) { 17217 17218 if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer ); 17219 17220 const renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture ) : pmremGenerator.fromCubemap( texture ); 17221 cubeUVmaps.set( texture, renderTarget ); 17222 17223 texture.addEventListener( 'dispose', onTextureDispose ); 17224 17225 return renderTarget.texture; 17226 17227 } else { 17228 17229 // image not yet ready. try the conversion next frame 17230 17231 return null; 17232 17233 } 17234 17235 } 17236 17237 } 17238 17239 } 17240 17241 } 17242 17243 return texture; 17244 17245 } 17246 17247 function isCubeTextureComplete( image ) { 17248 17249 let count = 0; 17250 const length = 6; 17251 17252 for ( let i = 0; i < length; i ++ ) { 17253 17254 if ( image[ i ] !== undefined ) count ++; 17255 17256 } 17257 17258 return count === length; 17259 17260 17261 } 17262 17263 function onTextureDispose( event ) { 17264 17265 const texture = event.target; 17266 17267 texture.removeEventListener( 'dispose', onTextureDispose ); 17268 17269 const cubemapUV = cubeUVmaps.get( texture ); 17270 17271 if ( cubemapUV !== undefined ) { 17272 17273 cubeUVmaps.delete( texture ); 17274 cubemapUV.dispose(); 17275 17276 } 17277 17278 } 17279 17280 function dispose() { 17281 17282 cubeUVmaps = new WeakMap(); 17283 17284 if ( pmremGenerator !== null ) { 17285 17286 pmremGenerator.dispose(); 17287 pmremGenerator = null; 17288 17289 } 17290 17291 } 17292 17293 return { 17294 get: get, 17295 dispose: dispose 17296 }; 17297 17298} 17299 17300function WebGLExtensions( gl ) { 17301 17302 const extensions = {}; 17303 17304 function getExtension( name ) { 17305 17306 if ( extensions[ name ] !== undefined ) { 17307 17308 return extensions[ name ]; 17309 17310 } 17311 17312 let extension; 17313 17314 switch ( name ) { 17315 17316 case 'WEBGL_depth_texture': 17317 extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' ); 17318 break; 17319 17320 case 'EXT_texture_filter_anisotropic': 17321 extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); 17322 break; 17323 17324 case 'WEBGL_compressed_texture_s3tc': 17325 extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' ); 17326 break; 17327 17328 case 'WEBGL_compressed_texture_pvrtc': 17329 extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' ); 17330 break; 17331 17332 default: 17333 extension = gl.getExtension( name ); 17334 17335 } 17336 17337 extensions[ name ] = extension; 17338 17339 return extension; 17340 17341 } 17342 17343 return { 17344 17345 has: function ( name ) { 17346 17347 return getExtension( name ) !== null; 17348 17349 }, 17350 17351 init: function ( capabilities ) { 17352 17353 if ( capabilities.isWebGL2 ) { 17354 17355 getExtension( 'EXT_color_buffer_float' ); 17356 getExtension( 'WEBGL_clip_cull_distance' ); 17357 17358 } else { 17359 17360 getExtension( 'WEBGL_depth_texture' ); 17361 getExtension( 'OES_texture_float' ); 17362 getExtension( 'OES_texture_half_float' ); 17363 getExtension( 'OES_texture_half_float_linear' ); 17364 getExtension( 'OES_standard_derivatives' ); 17365 getExtension( 'OES_element_index_uint' ); 17366 getExtension( 'OES_vertex_array_object' );
vendor: 27,956 bytes, lines 17367-18772
17367 getExtension( 'ANGLE_instanced_arrays' ); 17368 17369 } 17370 17371 getExtension( 'OES_texture_float_linear' ); 17372 getExtension( 'EXT_color_buffer_half_float' ); 17373 getExtension( 'WEBGL_multisampled_render_to_texture' ); 17374 17375 }, 17376 17377 get: function ( name ) { 17378 17379 const extension = getExtension( name ); 17380 17381 if ( extension === null ) { 17382 17383 console.warn( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' ); 17384 17385 } 17386 17387 return extension; 17388 17389 } 17390 17391 }; 17392 17393} 17394 17395function WebGLGeometries( gl, attributes, info, bindingStates ) { 17396 17397 const geometries = {}; 17398 const wireframeAttributes = new WeakMap(); 17399 17400 function onGeometryDispose( event ) { 17401 17402 const geometry = event.target; 17403 17404 if ( geometry.index !== null ) { 17405 17406 attributes.remove( geometry.index ); 17407 17408 } 17409 17410 for ( const name in geometry.attributes ) { 17411 17412 attributes.remove( geometry.attributes[ name ] ); 17413 17414 } 17415 17416 for ( const name in geometry.morphAttributes ) { 17417 17418 const array = geometry.morphAttributes[ name ]; 17419 17420 for ( let i = 0, l = array.length; i < l; i ++ ) { 17421 17422 attributes.remove( array[ i ] ); 17423 17424 } 17425 17426 } 17427 17428 geometry.removeEventListener( 'dispose', onGeometryDispose ); 17429 17430 delete geometries[ geometry.id ]; 17431 17432 const attribute = wireframeAttributes.get( geometry ); 17433 17434 if ( attribute ) { 17435 17436 attributes.remove( attribute ); 17437 wireframeAttributes.delete( geometry ); 17438 17439 } 17440 17441 bindingStates.releaseStatesOfGeometry( geometry ); 17442 17443 if ( geometry.isInstancedBufferGeometry === true ) { 17444 17445 delete geometry._maxInstanceCount; 17446 17447 } 17448 17449 // 17450 17451 info.memory.geometries --; 17452 17453 } 17454 17455 function get( object, geometry ) { 17456 17457 if ( geometries[ geometry.id ] === true ) return geometry; 17458 17459 geometry.addEventListener( 'dispose', onGeometryDispose ); 17460 17461 geometries[ geometry.id ] = true; 17462 17463 info.memory.geometries ++; 17464 17465 return geometry; 17466 17467 } 17468 17469 function update( geometry ) { 17470 17471 const geometryAttributes = geometry.attributes; 17472 17473 // Updating index buffer in VAO now. See WebGLBindingStates. 17474 17475 for ( const name in geometryAttributes ) { 17476 17477 attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER ); 17478 17479 } 17480 17481 // morph targets 17482 17483 const morphAttributes = geometry.morphAttributes; 17484 17485 for ( const name in morphAttributes ) { 17486 17487 const array = morphAttributes[ name ]; 17488 17489 for ( let i = 0, l = array.length; i < l; i ++ ) { 17490 17491 attributes.update( array[ i ], gl.ARRAY_BUFFER ); 17492 17493 } 17494 17495 } 17496 17497 } 17498 17499 function updateWireframeAttribute( geometry ) { 17500 17501 const indices = []; 17502 17503 const geometryIndex = geometry.index; 17504 const geometryPosition = geometry.attributes.position; 17505 let version = 0; 17506 17507 if ( geometryIndex !== null ) { 17508 17509 const array = geometryIndex.array; 17510 version = geometryIndex.version; 17511 17512 for ( let i = 0, l = array.length; i < l; i += 3 ) { 17513 17514 const a = array[ i + 0 ]; 17515 const b = array[ i + 1 ]; 17516 const c = array[ i + 2 ]; 17517 17518 indices.push( a, b, b, c, c, a ); 17519 17520 } 17521 17522 } else if ( geometryPosition !== undefined ) { 17523 17524 const array = geometryPosition.array; 17525 version = geometryPosition.version; 17526 17527 for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) { 17528 17529 const a = i + 0; 17530 const b = i + 1; 17531 const c = i + 2; 17532 17533 indices.push( a, b, b, c, c, a ); 17534 17535 } 17536 17537 } else { 17538 17539 return; 17540 17541 } 17542 17543 const attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); 17544 attribute.version = version; 17545 17546 // Updating index buffer in VAO now. See WebGLBindingStates 17547 17548 // 17549 17550 const previousAttribute = wireframeAttributes.get( geometry ); 17551 17552 if ( previousAttribute ) attributes.remove( previousAttribute ); 17553 17554 // 17555 17556 wireframeAttributes.set( geometry, attribute ); 17557 17558 } 17559 17560 function getWireframeAttribute( geometry ) { 17561 17562 const currentAttribute = wireframeAttributes.get( geometry ); 17563 17564 if ( currentAttribute ) { 17565 17566 const geometryIndex = geometry.index; 17567 17568 if ( geometryIndex !== null ) { 17569 17570 // if the attribute is obsolete, create a new one 17571 17572 if ( currentAttribute.version < geometryIndex.version ) { 17573 17574 updateWireframeAttribute( geometry ); 17575 17576 } 17577 17578 } 17579 17580 } else { 17581 17582 updateWireframeAttribute( geometry ); 17583 17584 } 17585 17586 return wireframeAttributes.get( geometry ); 17587 17588 } 17589 17590 return { 17591 17592 get: get, 17593 update: update, 17594 17595 getWireframeAttribute: getWireframeAttribute 17596 17597 }; 17598 17599} 17600 17601function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) { 17602 17603 const isWebGL2 = capabilities.isWebGL2; 17604 17605 let mode; 17606 17607 function setMode( value ) { 17608 17609 mode = value; 17610 17611 } 17612 17613 let type, bytesPerElement; 17614 17615 function setIndex( value ) { 17616 17617 type = value.type; 17618 bytesPerElement = value.bytesPerElement; 17619 17620 } 17621 17622 function render( start, count ) { 17623 17624 gl.drawElements( mode, count, type, start * bytesPerElement ); 17625 17626 info.update( count, mode, 1 ); 17627 17628 } 17629 17630 function renderInstances( start, count, primcount ) { 17631 17632 if ( primcount === 0 ) return; 17633 17634 let extension, methodName; 17635 17636 if ( isWebGL2 ) { 17637 17638 extension = gl; 17639 methodName = 'drawElementsInstanced'; 17640 17641 } else { 17642 17643 extension = extensions.get( 'ANGLE_instanced_arrays' ); 17644 methodName = 'drawElementsInstancedANGLE'; 17645 17646 if ( extension === null ) { 17647 17648 console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); 17649 return; 17650 17651 } 17652 17653 } 17654 17655 extension[ methodName ]( mode, count, type, start * bytesPerElement, primcount ); 17656 17657 info.update( count, mode, primcount ); 17658 17659 } 17660 17661 function renderMultiDraw( starts, counts, drawCount ) { 17662 17663 if ( drawCount === 0 ) return; 17664 17665 const extension = extensions.get( 'WEBGL_multi_draw' ); 17666 if ( extension === null ) { 17667 17668 for ( let i = 0; i < drawCount; i ++ ) { 17669 17670 this.render( starts[ i ] / bytesPerElement, counts[ i ] ); 17671 17672 } 17673 17674 } else { 17675 17676 extension.multiDrawElementsWEBGL( mode, counts, 0, type, starts, 0, drawCount ); 17677 17678 let elementCount = 0; 17679 for ( let i = 0; i < drawCount; i ++ ) { 17680 17681 elementCount += counts[ i ]; 17682 17683 } 17684 17685 info.update( elementCount, mode, 1 ); 17686 17687 } 17688 17689 } 17690 17691 // 17692 17693 this.setMode = setMode; 17694 this.setIndex = setIndex; 17695 this.render = render; 17696 this.renderInstances = renderInstances; 17697 this.renderMultiDraw = renderMultiDraw; 17698 17699} 17700 17701function WebGLInfo( gl ) { 17702 17703 const memory = { 17704 geometries: 0, 17705 textures: 0 17706 }; 17707 17708 const render = { 17709 frame: 0, 17710 calls: 0, 17711 triangles: 0, 17712 points: 0, 17713 lines: 0 17714 }; 17715 17716 function update( count, mode, instanceCount ) { 17717 17718 render.calls ++; 17719 17720 switch ( mode ) { 17721 17722 case gl.TRIANGLES: 17723 render.triangles += instanceCount * ( count / 3 ); 17724 break; 17725 17726 case gl.LINES: 17727 render.lines += instanceCount * ( count / 2 ); 17728 break; 17729 17730 case gl.LINE_STRIP: 17731 render.lines += instanceCount * ( count - 1 ); 17732 break; 17733 17734 case gl.LINE_LOOP: 17735 render.lines += instanceCount * count; 17736 break; 17737 17738 case gl.POINTS: 17739 render.points += instanceCount * count; 17740 break; 17741 17742 default: 17743 console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode ); 17744 break; 17745 17746 } 17747 17748 } 17749 17750 function reset() { 17751 17752 render.calls = 0; 17753 render.triangles = 0; 17754 render.points = 0; 17755 render.lines = 0; 17756 17757 } 17758 17759 return { 17760 memory: memory, 17761 render: render, 17762 programs: null, 17763 autoReset: true, 17764 reset: reset, 17765 update: update 17766 }; 17767 17768} 17769 17770function numericalSort( a, b ) { 17771 17772 return a[ 0 ] - b[ 0 ]; 17773 17774} 17775 17776function absNumericalSort( a, b ) { 17777 17778 return Math.abs( b[ 1 ] ) - Math.abs( a[ 1 ] ); 17779 17780} 17781 17782function WebGLMorphtargets( gl, capabilities, textures ) { 17783 17784 const influencesList = {}; 17785 const morphInfluences = new Float32Array( 8 ); 17786 const morphTextures = new WeakMap(); 17787 const morph = new Vector4(); 17788 17789 const workInfluences = []; 17790 17791 for ( let i = 0; i < 8; i ++ ) { 17792 17793 workInfluences[ i ] = [ i, 0 ]; 17794 17795 } 17796 17797 function update( object, geometry, program ) { 17798 17799 const objectInfluences = object.morphTargetInfluences; 17800 17801 if ( capabilities.isWebGL2 === true ) { 17802 17803 // instead of using attributes, the WebGL 2 code path encodes morph targets 17804 // into an array of data textures. Each layer represents a single morph target. 17805 17806 const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; 17807 const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; 17808 17809 let entry = morphTextures.get( geometry ); 17810 17811 if ( entry === undefined || entry.count !== morphTargetsCount ) { 17812 17813 if ( entry !== undefined ) entry.texture.dispose(); 17814 17815 const hasMorphPosition = geometry.morphAttributes.position !== undefined; 17816 const hasMorphNormals = geometry.morphAttributes.normal !== undefined; 17817 const hasMorphColors = geometry.morphAttributes.color !== undefined; 17818 17819 const morphTargets = geometry.morphAttributes.position || []; 17820 const morphNormals = geometry.morphAttributes.normal || []; 17821 const morphColors = geometry.morphAttributes.color || []; 17822 17823 let vertexDataCount = 0; 17824 17825 if ( hasMorphPosition === true ) vertexDataCount = 1; 17826 if ( hasMorphNormals === true ) vertexDataCount = 2; 17827 if ( hasMorphColors === true ) vertexDataCount = 3; 17828 17829 let width = geometry.attributes.position.count * vertexDataCount; 17830 let height = 1; 17831 17832 if ( width > capabilities.maxTextureSize ) { 17833 17834 height = Math.ceil( width / capabilities.maxTextureSize ); 17835 width = capabilities.maxTextureSize; 17836 17837 } 17838 17839 const buffer = new Float32Array( width * height * 4 * morphTargetsCount ); 17840 17841 const texture = new DataArrayTexture( buffer, width, height, morphTargetsCount ); 17842 texture.type = FloatType; 17843 texture.needsUpdate = true; 17844 17845 // fill buffer 17846 17847 const vertexDataStride = vertexDataCount * 4; 17848 17849 for ( let i = 0; i < morphTargetsCount; i ++ ) { 17850 17851 const morphTarget = morphTargets[ i ]; 17852 const morphNormal = morphNormals[ i ]; 17853 const morphColor = morphColors[ i ]; 17854 17855 const offset = width * height * 4 * i; 17856 17857 for ( let j = 0; j < morphTarget.count; j ++ ) { 17858 17859 const stride = j * vertexDataStride; 17860 17861 if ( hasMorphPosition === true ) { 17862 17863 morph.fromBufferAttribute( morphTarget, j ); 17864 17865 buffer[ offset + stride + 0 ] = morph.x; 17866 buffer[ offset + stride + 1 ] = morph.y; 17867 buffer[ offset + stride + 2 ] = morph.z; 17868 buffer[ offset + stride + 3 ] = 0; 17869 17870 } 17871 17872 if ( hasMorphNormals === true ) { 17873 17874 morph.fromBufferAttribute( morphNormal, j ); 17875 17876 buffer[ offset + stride + 4 ] = morph.x; 17877 buffer[ offset + stride + 5 ] = morph.y; 17878 buffer[ offset + stride + 6 ] = morph.z; 17879 buffer[ offset + stride + 7 ] = 0; 17880 17881 } 17882 17883 if ( hasMorphColors === true ) { 17884 17885 morph.fromBufferAttribute( morphColor, j ); 17886 17887 buffer[ offset + stride + 8 ] = morph.x; 17888 buffer[ offset + stride + 9 ] = morph.y; 17889 buffer[ offset + stride + 10 ] = morph.z; 17890 buffer[ offset + stride + 11 ] = ( morphColor.itemSize === 4 ) ? morph.w : 1; 17891 17892 } 17893 17894 } 17895 17896 } 17897 17898 entry = { 17899 count: morphTargetsCount, 17900 texture: texture, 17901 size: new Vector2( width, height ) 17902 }; 17903 17904 morphTextures.set( geometry, entry ); 17905 17906 function disposeTexture() { 17907 17908 texture.dispose(); 17909 17910 morphTextures.delete( geometry ); 17911 17912 geometry.removeEventListener( 'dispose', disposeTexture ); 17913 17914 } 17915 17916 geometry.addEventListener( 'dispose', disposeTexture ); 17917 17918 } 17919 17920 // 17921 17922 let morphInfluencesSum = 0; 17923 17924 for ( let i = 0; i < objectInfluences.length; i ++ ) { 17925 17926 morphInfluencesSum += objectInfluences[ i ]; 17927 17928 } 17929 17930 const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum; 17931 17932 program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence ); 17933 program.getUniforms().setValue( gl, 'morphTargetInfluences', objectInfluences ); 17934 17935 program.getUniforms().setValue( gl, 'morphTargetsTexture', entry.texture, textures ); 17936 program.getUniforms().setValue( gl, 'morphTargetsTextureSize', entry.size ); 17937 17938 17939 } else { 17940 17941 // When object doesn't have morph target influences defined, we treat it as a 0-length array 17942 // This is important to make sure we set up morphTargetBaseInfluence / morphTargetInfluences 17943 17944 const length = objectInfluences === undefined ? 0 : objectInfluences.length; 17945 17946 let influences = influencesList[ geometry.id ]; 17947 17948 if ( influences === undefined || influences.length !== length ) { 17949 17950 // initialise list 17951 17952 influences = []; 17953 17954 for ( let i = 0; i < length; i ++ ) { 17955 17956 influences[ i ] = [ i, 0 ]; 17957 17958 } 17959 17960 influencesList[ geometry.id ] = influences; 17961 17962 } 17963 17964 // Collect influences 17965 17966 for ( let i = 0; i < length; i ++ ) { 17967 17968 const influence = influences[ i ]; 17969 17970 influence[ 0 ] = i; 17971 influence[ 1 ] = objectInfluences[ i ]; 17972 17973 } 17974 17975 influences.sort( absNumericalSort ); 17976 17977 for ( let i = 0; i < 8; i ++ ) { 17978 17979 if ( i < length && influences[ i ][ 1 ] ) { 17980 17981 workInfluences[ i ][ 0 ] = influences[ i ][ 0 ]; 17982 workInfluences[ i ][ 1 ] = influences[ i ][ 1 ]; 17983 17984 } else { 17985 17986 workInfluences[ i ][ 0 ] = Number.MAX_SAFE_INTEGER; 17987 workInfluences[ i ][ 1 ] = 0; 17988 17989 } 17990 17991 } 17992 17993 workInfluences.sort( numericalSort ); 17994 17995 const morphTargets = geometry.morphAttributes.position; 17996 const morphNormals = geometry.morphAttributes.normal; 17997 17998 let morphInfluencesSum = 0; 17999 18000 for ( let i = 0; i < 8; i ++ ) { 18001 18002 const influence = workInfluences[ i ]; 18003 const index = influence[ 0 ]; 18004 const value = influence[ 1 ]; 18005 18006 if ( index !== Number.MAX_SAFE_INTEGER && value ) { 18007 18008 if ( morphTargets && geometry.getAttribute( 'morphTarget' + i ) !== morphTargets[ index ] ) { 18009 18010 geometry.setAttribute( 'morphTarget' + i, morphTargets[ index ] ); 18011 18012 } 18013 18014 if ( morphNormals && geometry.getAttribute( 'morphNormal' + i ) !== morphNormals[ index ] ) { 18015 18016 geometry.setAttribute( 'morphNormal' + i, morphNormals[ index ] ); 18017 18018 } 18019 18020 morphInfluences[ i ] = value; 18021 morphInfluencesSum += value; 18022 18023 } else { 18024 18025 if ( morphTargets && geometry.hasAttribute( 'morphTarget' + i ) === true ) { 18026 18027 geometry.deleteAttribute( 'morphTarget' + i ); 18028 18029 } 18030 18031 if ( morphNormals && geometry.hasAttribute( 'morphNormal' + i ) === true ) { 18032 18033 geometry.deleteAttribute( 'morphNormal' + i ); 18034 18035 } 18036 18037 morphInfluences[ i ] = 0; 18038 18039 } 18040 18041 } 18042 18043 // GLSL shader uses formula baseinfluence * base + sum(target * influence) 18044 // This allows us to switch between absolute morphs and relative morphs without changing shader code 18045 // When baseinfluence = 1 - sum(influence), the above is equivalent to sum((target - base) * influence) 18046 const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum; 18047 18048 program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence ); 18049 program.getUniforms().setValue( gl, 'morphTargetInfluences', morphInfluences ); 18050 18051 } 18052 18053 } 18054 18055 return { 18056 18057 update: update 18058 18059 }; 18060 18061} 18062 18063function WebGLObjects( gl, geometries, attributes, info ) { 18064 18065 let updateMap = new WeakMap(); 18066 18067 function update( object ) { 18068 18069 const frame = info.render.frame; 18070 18071 const geometry = object.geometry; 18072 const buffergeometry = geometries.get( object, geometry ); 18073 18074 // Update once per frame 18075 18076 if ( updateMap.get( buffergeometry ) !== frame ) { 18077 18078 geometries.update( buffergeometry ); 18079 18080 updateMap.set( buffergeometry, frame ); 18081 18082 } 18083 18084 if ( object.isInstancedMesh ) { 18085 18086 if ( object.hasEventListener( 'dispose', onInstancedMeshDispose ) === false ) { 18087 18088 object.addEventListener( 'dispose', onInstancedMeshDispose ); 18089 18090 } 18091 18092 if ( updateMap.get( object ) !== frame ) { 18093 18094 attributes.update( object.instanceMatrix, gl.ARRAY_BUFFER ); 18095 18096 if ( object.instanceColor !== null ) { 18097 18098 attributes.update( object.instanceColor, gl.ARRAY_BUFFER ); 18099 18100 } 18101 18102 updateMap.set( object, frame ); 18103 18104 } 18105 18106 } 18107 18108 if ( object.isSkinnedMesh ) { 18109 18110 const skeleton = object.skeleton; 18111 18112 if ( updateMap.get( skeleton ) !== frame ) { 18113 18114 skeleton.update(); 18115 18116 updateMap.set( skeleton, frame ); 18117 18118 } 18119 18120 } 18121 18122 return buffergeometry; 18123 18124 } 18125 18126 function dispose() { 18127 18128 updateMap = new WeakMap(); 18129 18130 } 18131 18132 function onInstancedMeshDispose( event ) { 18133 18134 const instancedMesh = event.target; 18135 18136 instancedMesh.removeEventListener( 'dispose', onInstancedMeshDispose ); 18137 18138 attributes.remove( instancedMesh.instanceMatrix ); 18139 18140 if ( instancedMesh.instanceColor !== null ) attributes.remove( instancedMesh.instanceColor ); 18141 18142 } 18143 18144 return { 18145 18146 update: update, 18147 dispose: dispose 18148 18149 }; 18150 18151} 18152 18153class DepthTexture extends Texture { 18154 18155 constructor( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) { 18156 18157 format = format !== undefined ? format : DepthFormat; 18158 18159 if ( format !== DepthFormat && format !== DepthStencilFormat ) { 18160 18161 throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ); 18162 18163 } 18164 18165 if ( type === undefined && format === DepthFormat ) type = UnsignedIntType; 18166 if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type; 18167 18168 super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); 18169 18170 this.isDepthTexture = true; 18171 18172 this.image = { width: width, height: height }; 18173 18174 this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; 18175 this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; 18176 18177 this.flipY = false; 18178 this.generateMipmaps = false; 18179 18180 this.compareFunction = null; 18181 18182 } 18183 18184 18185 copy( source ) { 18186 18187 super.copy( source ); 18188 18189 this.compareFunction = source.compareFunction; 18190 18191 return this; 18192 18193 } 18194 18195 toJSON( meta ) { 18196 18197 const data = super.toJSON( meta ); 18198 18199 if ( this.compareFunction !== null ) data.compareFunction = this.compareFunction; 18200 18201 return data; 18202 18203 } 18204 18205} 18206 18207/** 18208 * Uniforms of a program. 18209 * Those form a tree structure with a special top-level container for the root, 18210 * which you get by calling 'new WebGLUniforms( gl, program )'. 18211 * 18212 * 18213 * Properties of inner nodes including the top-level container: 18214 * 18215 * .seq - array of nested uniforms 18216 * .map - nested uniforms by name 18217 * 18218 * 18219 * Methods of all nodes except the top-level container: 18220 * 18221 * .setValue( gl, value, [textures] ) 18222 * 18223 * uploads a uniform value(s) 18224 * the 'textures' parameter is needed for sampler uniforms 18225 * 18226 * 18227 * Static methods of the top-level container (textures factorizations): 18228 * 18229 * .upload( gl, seq, values, textures ) 18230 * 18231 * sets uniforms in 'seq' to 'values[id].value' 18232 * 18233 * .seqWithValue( seq, values ) : filteredSeq 18234 * 18235 * filters 'seq' entries with corresponding entry in values 18236 * 18237 * 18238 * Methods of the top-level container (textures factorizations): 18239 * 18240 * .setValue( gl, name, value, textures ) 18241 * 18242 * sets uniform with name 'name' to 'value' 18243 * 18244 * .setOptional( gl, obj, prop ) 18245 * 18246 * like .set for an optional property of the object 18247 * 18248 */ 18249 18250 18251const emptyTexture = /*@__PURE__*/ new Texture(); 18252 18253const emptyShadowTexture = /*@__PURE__*/ new DepthTexture( 1, 1 ); 18254emptyShadowTexture.compareFunction = LessEqualCompare; 18255 18256const emptyArrayTexture = /*@__PURE__*/ new DataArrayTexture(); 18257const empty3dTexture = /*@__PURE__*/ new Data3DTexture(); 18258const emptyCubeTexture = /*@__PURE__*/ new CubeTexture(); 18259 18260// --- Utilities --- 18261 18262// Array Caches (provide typed arrays for temporary by size) 18263 18264const arrayCacheF32 = []; 18265const arrayCacheI32 = []; 18266 18267// Float32Array caches used for uploading Matrix uniforms 18268 18269const mat4array = new Float32Array( 16 ); 18270const mat3array = new Float32Array( 9 ); 18271const mat2array = new Float32Array( 4 ); 18272 18273// Flattening for arrays of vectors and matrices 18274 18275function flatten( array, nBlocks, blockSize ) { 18276 18277 const firstElem = array[ 0 ]; 18278 18279 if ( firstElem <= 0 || firstElem > 0 ) return array; 18280 // unoptimized: ! isNaN( firstElem ) 18281 // see http://jacksondunstan.com/articles/983 18282 18283 const n = nBlocks * blockSize; 18284 let r = arrayCacheF32[ n ]; 18285 18286 if ( r === undefined ) { 18287 18288 r = new Float32Array( n ); 18289 arrayCacheF32[ n ] = r; 18290 18291 } 18292 18293 if ( nBlocks !== 0 ) { 18294 18295 firstElem.toArray( r, 0 ); 18296 18297 for ( let i = 1, offset = 0; i !== nBlocks; ++ i ) { 18298 18299 offset += blockSize; 18300 array[ i ].toArray( r, offset ); 18301 18302 } 18303 18304 } 18305 18306 return r; 18307 18308} 18309 18310function arraysEqual( a, b ) { 18311 18312 if ( a.length !== b.length ) return false; 18313 18314 for ( let i = 0, l = a.length; i < l; i ++ ) { 18315 18316 if ( a[ i ] !== b[ i ] ) return false; 18317 18318 } 18319 18320 return true; 18321 18322} 18323 18324function copyArray( a, b ) { 18325 18326 for ( let i = 0, l = b.length; i < l; i ++ ) { 18327 18328 a[ i ] = b[ i ]; 18329 18330 } 18331 18332} 18333 18334// Texture unit allocation 18335 18336function allocTexUnits( textures, n ) { 18337 18338 let r = arrayCacheI32[ n ]; 18339 18340 if ( r === undefined ) { 18341 18342 r = new Int32Array( n ); 18343 arrayCacheI32[ n ] = r; 18344 18345 } 18346 18347 for ( let i = 0; i !== n; ++ i ) { 18348 18349 r[ i ] = textures.allocateTextureUnit(); 18350 18351 } 18352 18353 return r; 18354 18355} 18356 18357// --- Setters --- 18358 18359// Note: Defining these methods externally, because they come in a bunch 18360// and this way their names minify. 18361 18362// Single scalar 18363 18364function setValueV1f( gl, v ) { 18365 18366 const cache = this.cache; 18367 18368 if ( cache[ 0 ] === v ) return; 18369 18370 gl.uniform1f( this.addr, v ); 18371 18372 cache[ 0 ] = v; 18373 18374} 18375 18376// Single float vector (from flat array or THREE.VectorN) 18377 18378function setValueV2f( gl, v ) { 18379 18380 const cache = this.cache; 18381 18382 if ( v.x !== undefined ) { 18383 18384 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) { 18385 18386 gl.uniform2f( this.addr, v.x, v.y ); 18387 18388 cache[ 0 ] = v.x; 18389 cache[ 1 ] = v.y; 18390 18391 } 18392 18393 } else { 18394 18395 if ( arraysEqual( cache, v ) ) return; 18396 18397 gl.uniform2fv( this.addr, v ); 18398 18399 copyArray( cache, v ); 18400 18401 } 18402 18403} 18404 18405function setValueV3f( gl, v ) { 18406 18407 const cache = this.cache; 18408 18409 if ( v.x !== undefined ) { 18410 18411 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) { 18412 18413 gl.uniform3f( this.addr, v.x, v.y, v.z ); 18414 18415 cache[ 0 ] = v.x; 18416 cache[ 1 ] = v.y; 18417 cache[ 2 ] = v.z; 18418 18419 } 18420 18421 } else if ( v.r !== undefined ) { 18422 18423 if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) { 18424 18425 gl.uniform3f( this.addr, v.r, v.g, v.b ); 18426 18427 cache[ 0 ] = v.r; 18428 cache[ 1 ] = v.g; 18429 cache[ 2 ] = v.b; 18430 18431 } 18432 18433 } else { 18434 18435 if ( arraysEqual( cache, v ) ) return; 18436 18437 gl.uniform3fv( this.addr, v ); 18438 18439 copyArray( cache, v ); 18440 18441 } 18442 18443} 18444 18445function setValueV4f( gl, v ) { 18446 18447 const cache = this.cache; 18448 18449 if ( v.x !== undefined ) { 18450 18451 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) { 18452 18453 gl.uniform4f( this.addr, v.x, v.y, v.z, v.w ); 18454 18455 cache[ 0 ] = v.x; 18456 cache[ 1 ] = v.y; 18457 cache[ 2 ] = v.z; 18458 cache[ 3 ] = v.w; 18459 18460 } 18461 18462 } else { 18463 18464 if ( arraysEqual( cache, v ) ) return; 18465 18466 gl.uniform4fv( this.addr, v ); 18467 18468 copyArray( cache, v ); 18469 18470 } 18471 18472} 18473 18474// Single matrix (from flat array or THREE.MatrixN) 18475 18476function setValueM2( gl, v ) { 18477 18478 const cache = this.cache; 18479 const elements = v.elements; 18480 18481 if ( elements === undefined ) { 18482 18483 if ( arraysEqual( cache, v ) ) return; 18484 18485 gl.uniformMatrix2fv( this.addr, false, v ); 18486 18487 copyArray( cache, v ); 18488 18489 } else { 18490 18491 if ( arraysEqual( cache, elements ) ) return; 18492 18493 mat2array.set( elements ); 18494 18495 gl.uniformMatrix2fv( this.addr, false, mat2array ); 18496 18497 copyArray( cache, elements ); 18498 18499 } 18500 18501} 18502 18503function setValueM3( gl, v ) { 18504 18505 const cache = this.cache; 18506 const elements = v.elements; 18507 18508 if ( elements === undefined ) { 18509 18510 if ( arraysEqual( cache, v ) ) return; 18511 18512 gl.uniformMatrix3fv( this.addr, false, v ); 18513 18514 copyArray( cache, v ); 18515 18516 } else { 18517 18518 if ( arraysEqual( cache, elements ) ) return; 18519 18520 mat3array.set( elements ); 18521 18522 gl.uniformMatrix3fv( this.addr, false, mat3array ); 18523 18524 copyArray( cache, elements ); 18525 18526 } 18527 18528} 18529 18530function setValueM4( gl, v ) { 18531 18532 const cache = this.cache; 18533 const elements = v.elements; 18534 18535 if ( elements === undefined ) { 18536 18537 if ( arraysEqual( cache, v ) ) return; 18538 18539 gl.uniformMatrix4fv( this.addr, false, v ); 18540 18541 copyArray( cache, v ); 18542 18543 } else { 18544 18545 if ( arraysEqual( cache, elements ) ) return; 18546 18547 mat4array.set( elements ); 18548 18549 gl.uniformMatrix4fv( this.addr, false, mat4array ); 18550 18551 copyArray( cache, elements ); 18552 18553 } 18554 18555} 18556 18557// Single integer / boolean 18558 18559function setValueV1i( gl, v ) { 18560 18561 const cache = this.cache; 18562 18563 if ( cache[ 0 ] === v ) return; 18564 18565 gl.uniform1i( this.addr, v ); 18566 18567 cache[ 0 ] = v; 18568 18569} 18570 18571// Single integer / boolean vector (from flat array or THREE.VectorN) 18572 18573function setValueV2i( gl, v ) { 18574 18575 const cache = this.cache; 18576 18577 if ( v.x !== undefined ) { 18578 18579 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) { 18580 18581 gl.uniform2i( this.addr, v.x, v.y ); 18582 18583 cache[ 0 ] = v.x; 18584 cache[ 1 ] = v.y; 18585 18586 } 18587 18588 } else { 18589 18590 if ( arraysEqual( cache, v ) ) return; 18591 18592 gl.uniform2iv( this.addr, v ); 18593 18594 copyArray( cache, v ); 18595 18596 } 18597 18598} 18599 18600function setValueV3i( gl, v ) { 18601 18602 const cache = this.cache; 18603 18604 if ( v.x !== undefined ) { 18605 18606 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) { 18607 18608 gl.uniform3i( this.addr, v.x, v.y, v.z ); 18609 18610 cache[ 0 ] = v.x; 18611 cache[ 1 ] = v.y; 18612 cache[ 2 ] = v.z; 18613 18614 } 18615 18616 } else { 18617 18618 if ( arraysEqual( cache, v ) ) return; 18619 18620 gl.uniform3iv( this.addr, v ); 18621 18622 copyArray( cache, v ); 18623 18624 } 18625 18626} 18627 18628function setValueV4i( gl, v ) { 18629 18630 const cache = this.cache; 18631 18632 if ( v.x !== undefined ) { 18633 18634 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) { 18635 18636 gl.uniform4i( this.addr, v.x, v.y, v.z, v.w ); 18637 18638 cache[ 0 ] = v.x; 18639 cache[ 1 ] = v.y; 18640 cache[ 2 ] = v.z; 18641 cache[ 3 ] = v.w; 18642 18643 } 18644 18645 } else { 18646 18647 if ( arraysEqual( cache, v ) ) return; 18648 18649 gl.uniform4iv( this.addr, v ); 18650 18651 copyArray( cache, v ); 18652 18653 } 18654 18655} 18656 18657// Single unsigned integer 18658 18659function setValueV1ui( gl, v ) { 18660 18661 const cache = this.cache; 18662 18663 if ( cache[ 0 ] === v ) return; 18664 18665 gl.uniform1ui( this.addr, v ); 18666 18667 cache[ 0 ] = v; 18668 18669} 18670 18671// Single unsigned integer vector (from flat array or THREE.VectorN) 18672 18673function setValueV2ui( gl, v ) { 18674 18675 const cache = this.cache; 18676 18677 if ( v.x !== undefined ) { 18678 18679 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) { 18680 18681 gl.uniform2ui( this.addr, v.x, v.y ); 18682 18683 cache[ 0 ] = v.x; 18684 cache[ 1 ] = v.y; 18685 18686 } 18687 18688 } else { 18689 18690 if ( arraysEqual( cache, v ) ) return; 18691 18692 gl.uniform2uiv( this.addr, v ); 18693 18694 copyArray( cache, v ); 18695 18696 } 18697 18698} 18699 18700function setValueV3ui( gl, v ) { 18701 18702 const cache = this.cache; 18703 18704 if ( v.x !== undefined ) { 18705 18706 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) { 18707 18708 gl.uniform3ui( this.addr, v.x, v.y, v.z ); 18709 18710 cache[ 0 ] = v.x; 18711 cache[ 1 ] = v.y; 18712 cache[ 2 ] = v.z; 18713 18714 } 18715 18716 } else { 18717 18718 if ( arraysEqual( cache, v ) ) return; 18719 18720 gl.uniform3uiv( this.addr, v ); 18721 18722 copyArray( cache, v ); 18723 18724 } 18725 18726} 18727 18728function setValueV4ui( gl, v ) { 18729 18730 const cache = this.cache; 18731 18732 if ( v.x !== undefined ) { 18733 18734 if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) { 18735 18736 gl.uniform4ui( this.addr, v.x, v.y, v.z, v.w ); 18737 18738 cache[ 0 ] = v.x; 18739 cache[ 1 ] = v.y; 18740 cache[ 2 ] = v.z; 18741 cache[ 3 ] = v.w; 18742 18743 } 18744 18745 } else { 18746 18747 if ( arraysEqual( cache, v ) ) return; 18748 18749 gl.uniform4uiv( this.addr, v ); 18750 18751 copyArray( cache, v ); 18752 18753 } 18754 18755} 18756 18757 18758// Single texture (2D / Cube) 18759 18760function setValueT1( gl, v, textures ) { 18761 18762 const cache = this.cache; 18763 const unit = textures.allocateTextureUnit(); 18764 18765 if ( cache[ 0 ] !== unit ) { 18766 18767 gl.uniform1i( this.addr, unit ); 18768 cache[ 0 ] = unit; 18769 18770 } 18771 18772 const emptyTexture2D = ( this.type === gl.SAMPLER_2D_SHADOW ) ? emptySh
vendor: 7,467 bytes, lines 18772-19135
18772adowTexture : emptyTexture; 18773 18774 textures.setTexture2D( v || emptyTexture2D, unit ); 18775 18776} 18777 18778function setValueT3D1( gl, v, textures ) { 18779 18780 const cache = this.cache; 18781 const unit = textures.allocateTextureUnit(); 18782 18783 if ( cache[ 0 ] !== unit ) { 18784 18785 gl.uniform1i( this.addr, unit ); 18786 cache[ 0 ] = unit; 18787 18788 } 18789 18790 textures.setTexture3D( v || empty3dTexture, unit ); 18791 18792} 18793 18794function setValueT6( gl, v, textures ) { 18795 18796 const cache = this.cache; 18797 const unit = textures.allocateTextureUnit(); 18798 18799 if ( cache[ 0 ] !== unit ) { 18800 18801 gl.uniform1i( this.addr, unit ); 18802 cache[ 0 ] = unit; 18803 18804 } 18805 18806 textures.setTextureCube( v || emptyCubeTexture, unit ); 18807 18808} 18809 18810function setValueT2DArray1( gl, v, textures ) { 18811 18812 const cache = this.cache; 18813 const unit = textures.allocateTextureUnit(); 18814 18815 if ( cache[ 0 ] !== unit ) { 18816 18817 gl.uniform1i( this.addr, unit ); 18818 cache[ 0 ] = unit; 18819 18820 } 18821 18822 textures.setTexture2DArray( v || emptyArrayTexture, unit ); 18823 18824} 18825 18826// Helper to pick the right setter for the singular case 18827 18828function getSingularSetter( type ) { 18829 18830 switch ( type ) { 18831 18832 case 0x1406: return setValueV1f; // FLOAT 18833 case 0x8b50: return setValueV2f; // _VEC2 18834 case 0x8b51: return setValueV3f; // _VEC3 18835 case 0x8b52: return setValueV4f; // _VEC4 18836 18837 case 0x8b5a: return setValueM2; // _MAT2 18838 case 0x8b5b: return setValueM3; // _MAT3 18839 case 0x8b5c: return setValueM4; // _MAT4 18840 18841 case 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL 18842 case 0x8b53: case 0x8b57: return setValueV2i; // _VEC2 18843 case 0x8b54: case 0x8b58: return setValueV3i; // _VEC3 18844 case 0x8b55: case 0x8b59: return setValueV4i; // _VEC4 18845 18846 case 0x1405: return setValueV1ui; // UINT 18847 case 0x8dc6: return setValueV2ui; // _VEC2 18848 case 0x8dc7: return setValueV3ui; // _VEC3 18849 case 0x8dc8: return setValueV4ui; // _VEC4 18850 18851 case 0x8b5e: // SAMPLER_2D 18852 case 0x8d66: // SAMPLER_EXTERNAL_OES 18853 case 0x8dca: // INT_SAMPLER_2D 18854 case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D 18855 case 0x8b62: // SAMPLER_2D_SHADOW 18856 return setValueT1; 18857 18858 case 0x8b5f: // SAMPLER_3D 18859 case 0x8dcb: // INT_SAMPLER_3D 18860 case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D 18861 return setValueT3D1; 18862 18863 case 0x8b60: // SAMPLER_CUBE 18864 case 0x8dcc: // INT_SAMPLER_CUBE 18865 case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE 18866 case 0x8dc5: // SAMPLER_CUBE_SHADOW 18867 return setValueT6; 18868 18869 case 0x8dc1: // SAMPLER_2D_ARRAY 18870 case 0x8dcf: // INT_SAMPLER_2D_ARRAY 18871 case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY 18872 case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW 18873 return setValueT2DArray1; 18874 18875 } 18876 18877} 18878 18879 18880// Array of scalars 18881 18882function setValueV1fArray( gl, v ) { 18883 18884 gl.uniform1fv( this.addr, v ); 18885 18886} 18887 18888// Array of vectors (from flat array or array of THREE.VectorN) 18889 18890function setValueV2fArray( gl, v ) { 18891 18892 const data = flatten( v, this.size, 2 ); 18893 18894 gl.uniform2fv( this.addr, data ); 18895 18896} 18897 18898function setValueV3fArray( gl, v ) { 18899 18900 const data = flatten( v, this.size, 3 ); 18901 18902 gl.uniform3fv( this.addr, data ); 18903 18904} 18905 18906function setValueV4fArray( gl, v ) { 18907 18908 const data = flatten( v, this.size, 4 ); 18909 18910 gl.uniform4fv( this.addr, data ); 18911 18912} 18913 18914// Array of matrices (from flat array or array of THREE.MatrixN) 18915 18916function setValueM2Array( gl, v ) { 18917 18918 const data = flatten( v, this.size, 4 ); 18919 18920 gl.uniformMatrix2fv( this.addr, false, data ); 18921 18922} 18923 18924function setValueM3Array( gl, v ) { 18925 18926 const data = flatten( v, this.size, 9 ); 18927 18928 gl.uniformMatrix3fv( this.addr, false, data ); 18929 18930} 18931 18932function setValueM4Array( gl, v ) { 18933 18934 const data = flatten( v, this.size, 16 ); 18935 18936 gl.uniformMatrix4fv( this.addr, false, data ); 18937 18938} 18939 18940// Array of integer / boolean 18941 18942function setValueV1iArray( gl, v ) { 18943 18944 gl.uniform1iv( this.addr, v ); 18945 18946} 18947 18948// Array of integer / boolean vectors (from flat array) 18949 18950function setValueV2iArray( gl, v ) { 18951 18952 gl.uniform2iv( this.addr, v ); 18953 18954} 18955 18956function setValueV3iArray( gl, v ) { 18957 18958 gl.uniform3iv( this.addr, v ); 18959 18960} 18961 18962function setValueV4iArray( gl, v ) { 18963 18964 gl.uniform4iv( this.addr, v ); 18965 18966} 18967 18968// Array of unsigned integer 18969 18970function setValueV1uiArray( gl, v ) { 18971 18972 gl.uniform1uiv( this.addr, v ); 18973 18974} 18975 18976// Array of unsigned integer vectors (from flat array) 18977 18978function setValueV2uiArray( gl, v ) { 18979 18980 gl.uniform2uiv( this.addr, v ); 18981 18982} 18983 18984function setValueV3uiArray( gl, v ) { 18985 18986 gl.uniform3uiv( this.addr, v ); 18987 18988} 18989 18990function setValueV4uiArray( gl, v ) { 18991 18992 gl.uniform4uiv( this.addr, v ); 18993 18994} 18995 18996 18997// Array of textures (2D / 3D / Cube / 2DArray) 18998 18999function setValueT1Array( gl, v, textures ) { 19000 19001 const cache = this.cache; 19002 19003 const n = v.length; 19004 19005 const units = allocTexUnits( textures, n ); 19006 19007 if ( ! arraysEqual( cache, units ) ) { 19008 19009 gl.uniform1iv( this.addr, units ); 19010 19011 copyArray( cache, units ); 19012 19013 } 19014 19015 for ( let i = 0; i !== n; ++ i ) { 19016 19017 textures.setTexture2D( v[ i ] || emptyTexture, units[ i ] ); 19018 19019 } 19020 19021} 19022 19023function setValueT3DArray( gl, v, textures ) { 19024 19025 const cache = this.cache; 19026 19027 const n = v.length; 19028 19029 const units = allocTexUnits( textures, n ); 19030 19031 if ( ! arraysEqual( cache, units ) ) { 19032 19033 gl.uniform1iv( this.addr, units ); 19034 19035 copyArray( cache, units ); 19036 19037 } 19038 19039 for ( let i = 0; i !== n; ++ i ) { 19040 19041 textures.setTexture3D( v[ i ] || empty3dTexture, units[ i ] ); 19042 19043 } 19044 19045} 19046 19047function setValueT6Array( gl, v, textures ) { 19048 19049 const cache = this.cache; 19050 19051 const n = v.length; 19052 19053 const units = allocTexUnits( textures, n ); 19054 19055 if ( ! arraysEqual( cache, units ) ) { 19056 19057 gl.uniform1iv( this.addr, units ); 19058 19059 copyArray( cache, units ); 19060 19061 } 19062 19063 for ( let i = 0; i !== n; ++ i ) { 19064 19065 textures.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] ); 19066 19067 } 19068 19069} 19070 19071function setValueT2DArrayArray( gl, v, textures ) { 19072 19073 const cache = this.cache; 19074 19075 const n = v.length; 19076 19077 const units = allocTexUnits( textures, n ); 19078 19079 if ( ! arraysEqual( cache, units ) ) { 19080 19081 gl.uniform1iv( this.addr, units ); 19082 19083 copyArray( cache, units ); 19084 19085 } 19086 19087 for ( let i = 0; i !== n; ++ i ) { 19088 19089 textures.setTexture2DArray( v[ i ] || emptyArrayTexture, units[ i ] ); 19090 19091 } 19092 19093} 19094 19095 19096// Helper to pick the right setter for a pure (bottom-level) array 19097 19098function getPureArraySetter( type ) { 19099 19100 switch ( type ) { 19101 19102 case 0x1406: return setValueV1fArray; // FLOAT 19103 case 0x8b50: return setValueV2fArray; // _VEC2 19104 case 0x8b51: return setValueV3fArray; // _VEC3 19105 case 0x8b52: return setValueV4fArray; // _VEC4 19106 19107 case 0x8b5a: return setValueM2Array; // _MAT2 19108 case 0x8b5b: return setValueM3Array; // _MAT3 19109 case 0x8b5c: return setValueM4Array; // _MAT4 19110 19111 case 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL 19112 case 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2 19113 case 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3 19114 case 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4 19115 19116 case 0x1405: return setValueV1uiArray; // UINT 19117 case 0x8dc6: return setValueV2uiArray; // _VEC2 19118 case 0x8dc7: return setValueV3uiArray; // _VEC3 19119 case 0x8dc8: return setValueV4uiArray; // _VEC4 19120 19121 case 0x8b5e: // SAMPLER_2D 19122 case 0x8d66: // SAMPLER_EXTERNAL_OES 19123 case 0x8dca: // INT_SAMPLER_2D 19124 case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D 19125 case 0x8b62: // SAMPLER_2D_SHADOW 19126 return setValueT1Array; 19127 19128 case 0x8b5f: // SAMPLER_3D 19129 case 0x8dcb: // INT_SAMPLER_3D 19130 case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D 19131 return setValueT3DArray; 19132 19133 case 0x8b60: // SAMPLER_CUBE 19134 case 0x8dcc: // INT_SAMPLER_CUBE 19135 case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
vendor: 216,434 bytes, lines 19136-27437
19136 case 0x8dc5: // SAMPLER_CUBE_SHADOW 19137 return setValueT6Array; 19138 19139 case 0x8dc1: // SAMPLER_2D_ARRAY 19140 case 0x8dcf: // INT_SAMPLER_2D_ARRAY 19141 case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY 19142 case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW 19143 return setValueT2DArrayArray; 19144 19145 } 19146 19147} 19148 19149// --- Uniform Classes --- 19150 19151class SingleUniform { 19152 19153 constructor( id, activeInfo, addr ) { 19154 19155 this.id = id; 19156 this.addr = addr; 19157 this.cache = []; 19158 this.type = activeInfo.type; 19159 this.setValue = getSingularSetter( activeInfo.type ); 19160 19161 // this.path = activeInfo.name; // DEBUG 19162 19163 } 19164 19165} 19166 19167class PureArrayUniform { 19168 19169 constructor( id, activeInfo, addr ) { 19170 19171 this.id = id; 19172 this.addr = addr; 19173 this.cache = []; 19174 this.type = activeInfo.type; 19175 this.size = activeInfo.size; 19176 this.setValue = getPureArraySetter( activeInfo.type ); 19177 19178 // this.path = activeInfo.name; // DEBUG 19179 19180 } 19181 19182} 19183 19184class StructuredUniform { 19185 19186 constructor( id ) { 19187 19188 this.id = id; 19189 19190 this.seq = []; 19191 this.map = {}; 19192 19193 } 19194 19195 setValue( gl, value, textures ) { 19196 19197 const seq = this.seq; 19198 19199 for ( let i = 0, n = seq.length; i !== n; ++ i ) { 19200 19201 const u = seq[ i ]; 19202 u.setValue( gl, value[ u.id ], textures ); 19203 19204 } 19205 19206 } 19207 19208} 19209 19210// --- Top-level --- 19211 19212// Parser - builds up the property tree from the path strings 19213 19214const RePathPart = /(\w+)(\])?(\[|\.)?/g; 19215 19216// extracts 19217// - the identifier (member name or array index) 19218// - followed by an optional right bracket (found when array index) 19219// - followed by an optional left bracket or dot (type of subscript) 19220// 19221// Note: These portions can be read in a non-overlapping fashion and 19222// allow straightforward parsing of the hierarchy that WebGL encodes 19223// in the uniform names. 19224 19225function addUniform( container, uniformObject ) { 19226 19227 container.seq.push( uniformObject ); 19228 container.map[ uniformObject.id ] = uniformObject; 19229 19230} 19231 19232function parseUniform( activeInfo, addr, container ) { 19233 19234 const path = activeInfo.name, 19235 pathLength = path.length; 19236 19237 // reset RegExp object, because of the early exit of a previous run 19238 RePathPart.lastIndex = 0; 19239 19240 while ( true ) { 19241 19242 const match = RePathPart.exec( path ), 19243 matchEnd = RePathPart.lastIndex; 19244 19245 let id = match[ 1 ]; 19246 const idIsIndex = match[ 2 ] === ']', 19247 subscript = match[ 3 ]; 19248 19249 if ( idIsIndex ) id = id | 0; // convert to integer 19250 19251 if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) { 19252 19253 // bare name or "pure" bottom-level array "[0]" suffix 19254 19255 addUniform( container, subscript === undefined ? 19256 new SingleUniform( id, activeInfo, addr ) : 19257 new PureArrayUniform( id, activeInfo, addr ) ); 19258 19259 break; 19260 19261 } else { 19262 19263 // step into inner node / create it in case it doesn't exist 19264 19265 const map = container.map; 19266 let next = map[ id ]; 19267 19268 if ( next === undefined ) { 19269 19270 next = new StructuredUniform( id ); 19271 addUniform( container, next ); 19272 19273 } 19274 19275 container = next; 19276 19277 } 19278 19279 } 19280 19281} 19282 19283// Root Container 19284 19285class WebGLUniforms { 19286 19287 constructor( gl, program ) { 19288 19289 this.seq = []; 19290 this.map = {}; 19291 19292 const n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS ); 19293 19294 for ( let i = 0; i < n; ++ i ) { 19295 19296 const info = gl.getActiveUniform( program, i ), 19297 addr = gl.getUniformLocation( program, info.name ); 19298 19299 parseUniform( info, addr, this ); 19300 19301 } 19302 19303 } 19304 19305 setValue( gl, name, value, textures ) { 19306 19307 const u = this.map[ name ]; 19308 19309 if ( u !== undefined ) u.setValue( gl, value, textures ); 19310 19311 } 19312 19313 setOptional( gl, object, name ) { 19314 19315 const v = object[ name ]; 19316 19317 if ( v !== undefined ) this.setValue( gl, name, v ); 19318 19319 } 19320 19321 static upload( gl, seq, values, textures ) { 19322 19323 for ( let i = 0, n = seq.length; i !== n; ++ i ) { 19324 19325 const u = seq[ i ], 19326 19327 v = values[ u.id ]; 19328 19329 if ( v.needsUpdate !== false ) { 19330 19331 // note: always updating when .needsUpdate is undefined 19332 u.setValue( gl, v.value, textures ); 19333 19334 } 19335 19336 } 19337 19338 } 19339 19340 static seqWithValue( seq, values ) { 19341 19342 const r = []; 19343 19344 for ( let i = 0, n = seq.length; i !== n; ++ i ) { 19345 19346 const u = seq[ i ]; 19347 if ( u.id in values ) r.push( u ); 19348 19349 } 19350 19351 return r; 19352 19353 } 19354 19355} 19356 19357function WebGLShader( gl, type, string ) { 19358 19359 const shader = gl.createShader( type ); 19360 19361 gl.shaderSource( shader, string ); 19362 gl.compileShader( shader ); 19363 19364 return shader; 19365 19366} 19367 19368// From https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/ 19369const COMPLETION_STATUS_KHR = 0x91B1; 19370 19371let programIdCount = 0; 19372 19373function handleSource( string, errorLine ) { 19374 19375 const lines = string.split( '\n' ); 19376 const lines2 = []; 19377 19378 const from = Math.max( errorLine - 6, 0 ); 19379 const to = Math.min( errorLine + 6, lines.length ); 19380 19381 for ( let i = from; i < to; i ++ ) { 19382 19383 const line = i + 1; 19384 lines2.push( `${line === errorLine ? '>' : ' '} ${line}: ${lines[ i ]}` ); 19385 19386 } 19387 19388 return lines2.join( '\n' ); 19389 19390} 19391 19392function getEncodingComponents( colorSpace ) { 19393 19394 const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace ); 19395 const encodingPrimaries = ColorManagement.getPrimaries( colorSpace ); 19396 19397 let gamutMapping; 19398 19399 if ( workingPrimaries === encodingPrimaries ) { 19400 19401 gamutMapping = ''; 19402 19403 } else if ( workingPrimaries === P3Primaries && encodingPrimaries === Rec709Primaries ) { 19404 19405 gamutMapping = 'LinearDisplayP3ToLinearSRGB'; 19406 19407 } else if ( workingPrimaries === Rec709Primaries && encodingPrimaries === P3Primaries ) { 19408 19409 gamutMapping = 'LinearSRGBToLinearDisplayP3'; 19410 19411 } 19412 19413 switch ( colorSpace ) { 19414 19415 case LinearSRGBColorSpace: 19416 case LinearDisplayP3ColorSpace: 19417 return [ gamutMapping, 'LinearTransferOETF' ]; 19418 19419 case SRGBColorSpace: 19420 case DisplayP3ColorSpace: 19421 return [ gamutMapping, 'sRGBTransferOETF' ]; 19422 19423 default: 19424 console.warn( 'THREE.WebGLProgram: Unsupported color space:', colorSpace ); 19425 return [ gamutMapping, 'LinearTransferOETF' ]; 19426 19427 } 19428 19429} 19430 19431function getShaderErrors( gl, shader, type ) { 19432 19433 const status = gl.getShaderParameter( shader, gl.COMPILE_STATUS ); 19434 const errors = gl.getShaderInfoLog( shader ).trim(); 19435 19436 if ( status && errors === '' ) return ''; 19437 19438 const errorMatches = /ERROR: 0:(\d+)/.exec( errors ); 19439 if ( errorMatches ) { 19440 19441 // --enable-privileged-webgl-extension 19442 // console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); 19443 19444 const errorLine = parseInt( errorMatches[ 1 ] ); 19445 return type.toUpperCase() + '\n\n' + errors + '\n\n' + handleSource( gl.getShaderSource( shader ), errorLine ); 19446 19447 } else { 19448 19449 return errors; 19450 19451 } 19452 19453} 19454 19455function getTexelEncodingFunction( functionName, colorSpace ) { 19456 19457 const components = getEncodingComponents( colorSpace ); 19458 return `vec4 ${functionName}( vec4 value ) { return ${components[ 0 ]}( ${components[ 1 ]}( value ) ); }`; 19459 19460} 19461 19462function getToneMappingFunction( functionName, toneMapping ) { 19463 19464 let toneMappingName; 19465 19466 switch ( toneMapping ) { 19467 19468 case LinearToneMapping: 19469 toneMappingName = 'Linear'; 19470 break; 19471 19472 case ReinhardToneMapping: 19473 toneMappingName = 'Reinhard'; 19474 break; 19475 19476 case CineonToneMapping: 19477 toneMappingName = 'OptimizedCineon'; 19478 break; 19479 19480 case ACESFilmicToneMapping: 19481 toneMappingName = 'ACESFilmic'; 19482 break; 19483 19484 case AgXToneMapping: 19485 toneMappingName = 'AgX'; 19486 break; 19487 19488 case CustomToneMapping: 19489 toneMappingName = 'Custom'; 19490 break; 19491 19492 default: 19493 console.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping ); 19494 toneMappingName = 'Linear'; 19495 19496 } 19497 19498 return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }'; 19499 19500} 19501 19502function generateExtensions( parameters ) { 19503 19504 const chunks = [ 19505 ( parameters.extensionDerivatives || !! parameters.envMapCubeUVHeight || parameters.bumpMap || parameters.normalMapTangentSpace || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '', 19506 ( parameters.extensionFragDepth || parameters.logarithmicDepthBuffer ) && parameters.rendererExtensionFragDepth ? '#extension GL_EXT_frag_depth : enable' : '', 19507 ( parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers ) ? '#extension GL_EXT_draw_buffers : require' : '', 19508 ( parameters.extensionShaderTextureLOD || parameters.envMap || parameters.transmission ) && parameters.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : '' 19509 ]; 19510 19511 return chunks.filter( filterEmptyLine ).join( '\n' ); 19512 19513} 19514 19515function generateVertexExtensions( parameters ) { 19516 19517 const chunks = [ 19518 parameters.extensionClipCullDistance ? '#extension GL_ANGLE_clip_cull_distance : require' : '' 19519 ]; 19520 19521 return chunks.filter( filterEmptyLine ).join( '\n' ); 19522 19523} 19524 19525function generateDefines( defines ) { 19526 19527 const chunks = []; 19528 19529 for ( const name in defines ) { 19530 19531 const value = defines[ name ]; 19532 19533 if ( value === false ) continue; 19534 19535 chunks.push( '#define ' + name + ' ' + value ); 19536 19537 } 19538 19539 return chunks.join( '\n' ); 19540 19541} 19542 19543function fetchAttributeLocations( gl, program ) { 19544 19545 const attributes = {}; 19546 19547 const n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES ); 19548 19549 for ( let i = 0; i < n; i ++ ) { 19550 19551 const info = gl.getActiveAttrib( program, i ); 19552 const name = info.name; 19553 19554 let locationSize = 1; 19555 if ( info.type === gl.FLOAT_MAT2 ) locationSize = 2; 19556 if ( info.type === gl.FLOAT_MAT3 ) locationSize = 3; 19557 if ( info.type === gl.FLOAT_MAT4 ) locationSize = 4; 19558 19559 // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i ); 19560 19561 attributes[ name ] = { 19562 type: info.type, 19563 location: gl.getAttribLocation( program, name ), 19564 locationSize: locationSize 19565 }; 19566 19567 } 19568 19569 return attributes; 19570 19571} 19572 19573function filterEmptyLine( string ) { 19574 19575 return string !== ''; 19576 19577} 19578 19579function replaceLightNums( string, parameters ) { 19580 19581 const numSpotLightCoords = parameters.numSpotLightShadows + parameters.numSpotLightMaps - parameters.numSpotLightShadowsWithMaps; 19582 19583 return string 19584 .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights ) 19585 .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights ) 19586 .replace( /NUM_SPOT_LIGHT_MAPS/g, parameters.numSpotLightMaps ) 19587 .replace( /NUM_SPOT_LIGHT_COORDS/g, numSpotLightCoords ) 19588 .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights ) 19589 .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights ) 19590 .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights ) 19591 .replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows ) 19592 .replace( /NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g, parameters.numSpotLightShadowsWithMaps ) 19593 .replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows ) 19594 .replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows ); 19595 19596} 19597 19598function replaceClippingPlaneNums( string, parameters ) { 19599 19600 return string 19601 .replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes ) 19602 .replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) ); 19603 19604} 19605 19606// Resolve Includes 19607 19608const includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm; 19609 19610function resolveIncludes( string ) { 19611 19612 return string.replace( includePattern, includeReplacer ); 19613 19614} 19615 19616const shaderChunkMap = new Map( [ 19617 [ 'encodings_fragment', 'colorspace_fragment' ], // @deprecated, r154 19618 [ 'encodings_pars_fragment', 'colorspace_pars_fragment' ], // @deprecated, r154 19619 [ 'output_fragment', 'opaque_fragment' ], // @deprecated, r154 19620] ); 19621 19622function includeReplacer( match, include ) { 19623 19624 let string = ShaderChunk[ include ]; 19625 19626 if ( string === undefined ) { 19627 19628 const newInclude = shaderChunkMap.get( include ); 19629 19630 if ( newInclude !== undefined ) { 19631 19632 string = ShaderChunk[ newInclude ]; 19633 console.warn( 'THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.', include, newInclude ); 19634 19635 } else { 19636 19637 throw new Error( 'Can not resolve #include <' + include + '>' ); 19638 19639 } 19640 19641 } 19642 19643 return resolveIncludes( string ); 19644 19645} 19646 19647// Unroll Loops 19648 19649const unrollLoopPattern = /#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g; 19650 19651function unrollLoops( string ) { 19652 19653 return string.replace( unrollLoopPattern, loopReplacer ); 19654 19655} 19656 19657function loopReplacer( match, start, end, snippet ) { 19658 19659 let string = ''; 19660 19661 for ( let i = parseInt( start ); i < parseInt( end ); i ++ ) { 19662 19663 string += snippet 19664 .replace( /\[\s*i\s*\]/g, '[ ' + i + ' ]' ) 19665 .replace( /UNROLLED_LOOP_INDEX/g, i ); 19666 19667 } 19668 19669 return string; 19670 19671} 19672 19673// 19674 19675function generatePrecision( parameters ) { 19676 19677 let precisionstring = 'precision ' + parameters.precision + ' float;\nprecision ' + parameters.precision + ' int;'; 19678 19679 if ( parameters.precision === 'highp' ) { 19680 19681 precisionstring += '\n#define HIGH_PRECISION'; 19682 19683 } else if ( parameters.precision === 'mediump' ) { 19684 19685 precisionstring += '\n#define MEDIUM_PRECISION'; 19686 19687 } else if ( parameters.precision === 'lowp' ) { 19688 19689 precisionstring += '\n#define LOW_PRECISION'; 19690 19691 } 19692 19693 return precisionstring; 19694 19695} 19696 19697function generateShadowMapTypeDefine( parameters ) { 19698 19699 let shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; 19700 19701 if ( parameters.shadowMapType === PCFShadowMap ) { 19702 19703 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; 19704 19705 } else if ( parameters.shadowMapType === PCFSoftShadowMap ) { 19706 19707 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT'; 19708 19709 } else if ( parameters.shadowMapType === VSMShadowMap ) { 19710 19711 shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM'; 19712 19713 } 19714 19715 return shadowMapTypeDefine; 19716 19717} 19718 19719function generateEnvMapTypeDefine( parameters ) { 19720 19721 let envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; 19722 19723 if ( parameters.envMap ) { 19724 19725 switch ( parameters.envMapMode ) { 19726 19727 case CubeReflectionMapping: 19728 case CubeRefractionMapping: 19729 envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; 19730 break; 19731 19732 case CubeUVReflectionMapping: 19733 envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV'; 19734 break; 19735 19736 } 19737 19738 } 19739 19740 return envMapTypeDefine; 19741 19742} 19743 19744function generateEnvMapModeDefine( parameters ) { 19745 19746 let envMapModeDefine = 'ENVMAP_MODE_REFLECTION'; 19747 19748 if ( parameters.envMap ) { 19749 19750 switch ( parameters.envMapMode ) { 19751 19752 case CubeRefractionMapping: 19753 19754 envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; 19755 break; 19756 19757 } 19758 19759 } 19760 19761 return envMapModeDefine; 19762 19763} 19764 19765function generateEnvMapBlendingDefine( parameters ) { 19766 19767 let envMapBlendingDefine = 'ENVMAP_BLENDING_NONE'; 19768 19769 if ( parameters.envMap ) { 19770 19771 switch ( parameters.combine ) { 19772 19773 case MultiplyOperation: 19774 envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; 19775 break; 19776 19777 case MixOperation: 19778 envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; 19779 break; 19780 19781 case AddOperation: 19782 envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; 19783 break; 19784 19785 } 19786 19787 } 19788 19789 return envMapBlendingDefine; 19790 19791} 19792 19793function generateCubeUVSize( parameters ) { 19794 19795 const imageHeight = parameters.envMapCubeUVHeight; 19796 19797 if ( imageHeight === null ) return null; 19798 19799 const maxMip = Math.log2( imageHeight ) - 2; 19800 19801 const texelHeight = 1.0 / imageHeight; 19802 19803 const texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) ); 19804 19805 return { texelWidth, texelHeight, maxMip }; 19806 19807} 19808 19809function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) { 19810 19811 // TODO Send this event to Three.js DevTools 19812 // console.log( 'WebGLProgram', cacheKey ); 19813 19814 const gl = renderer.getContext(); 19815 19816 const defines = parameters.defines; 19817 19818 let vertexShader = parameters.vertexShader; 19819 let fragmentShader = parameters.fragmentShader; 19820 19821 const shadowMapTypeDefine = generateShadowMapTypeDefine( parameters ); 19822 const envMapTypeDefine = generateEnvMapTypeDefine( parameters ); 19823 const envMapModeDefine = generateEnvMapModeDefine( parameters ); 19824 const envMapBlendingDefine = generateEnvMapBlendingDefine( parameters ); 19825 const envMapCubeUVSize = generateCubeUVSize( parameters ); 19826 19827 const customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters ); 19828 19829 const customVertexExtensions = generateVertexExtensions( parameters ); 19830 19831 const customDefines = generateDefines( defines ); 19832 19833 const program = gl.createProgram(); 19834 19835 let prefixVertex, prefixFragment; 19836 let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : ''; 19837 19838 if ( parameters.isRawShaderMaterial ) { 19839 19840 prefixVertex = [ 19841 19842 '#define SHADER_TYPE ' + parameters.shaderType, 19843 '#define SHADER_NAME ' + parameters.shaderName, 19844 19845 customDefines 19846 19847 ].filter( filterEmptyLine ).join( '\n' ); 19848 19849 if ( prefixVertex.length > 0 ) { 19850 19851 prefixVertex += '\n'; 19852 19853 } 19854 19855 prefixFragment = [ 19856 19857 customExtensions, 19858 19859 '#define SHADER_TYPE ' + parameters.shaderType, 19860 '#define SHADER_NAME ' + parameters.shaderName, 19861 19862 customDefines 19863 19864 ].filter( filterEmptyLine ).join( '\n' ); 19865 19866 if ( prefixFragment.length > 0 ) { 19867 19868 prefixFragment += '\n'; 19869 19870 } 19871 19872 } else { 19873 19874 prefixVertex = [ 19875 19876 generatePrecision( parameters ), 19877 19878 '#define SHADER_TYPE ' + parameters.shaderType, 19879 '#define SHADER_NAME ' + parameters.shaderName, 19880 19881 customDefines, 19882 19883 parameters.extensionClipCullDistance ? '#define USE_CLIP_DISTANCE' : '', 19884 parameters.batching ? '#define USE_BATCHING' : '', 19885 parameters.instancing ? '#define USE_INSTANCING' : '', 19886 parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '', 19887 19888 parameters.useFog && parameters.fog ? '#define USE_FOG' : '', 19889 parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '', 19890 19891 parameters.map ? '#define USE_MAP' : '', 19892 parameters.envMap ? '#define USE_ENVMAP' : '', 19893 parameters.envMap ? '#define ' + envMapModeDefine : '', 19894 parameters.lightMap ? '#define USE_LIGHTMAP' : '', 19895 parameters.aoMap ? '#define USE_AOMAP' : '', 19896 parameters.bumpMap ? '#define USE_BUMPMAP' : '', 19897 parameters.normalMap ? '#define USE_NORMALMAP' : '', 19898 parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '', 19899 parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '', 19900 parameters.displacementMap ? '#define USE_DISPLACEMENTMAP' : '', 19901 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', 19902 19903 parameters.anisotropy ? '#define USE_ANISOTROPY' : '', 19904 parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '', 19905 19906 parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', 19907 parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', 19908 parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '', 19909 19910 parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '', 19911 parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', 19912 19913 parameters.specularMap ? '#define USE_SPECULARMAP' : '', 19914 parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '', 19915 parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '', 19916 19917 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', 19918 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', 19919 parameters.alphaMap ? '#define USE_ALPHAMAP' : '', 19920 parameters.alphaHash ? '#define USE_ALPHAHASH' : '', 19921 19922 parameters.transmission ? '#define USE_TRANSMISSION' : '', 19923 parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', 19924 parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', 19925 19926 parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '', 19927 parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '', 19928 19929 // 19930 19931 parameters.mapUv ? '#define MAP_UV ' + parameters.mapUv : '', 19932 parameters.alphaMapUv ? '#define ALPHAMAP_UV ' + parameters.alphaMapUv : '', 19933 parameters.lightMapUv ? '#define LIGHTMAP_UV ' + parameters.lightMapUv : '', 19934 parameters.aoMapUv ? '#define AOMAP_UV ' + parameters.aoMapUv : '', 19935 parameters.emissiveMapUv ? '#define EMISSIVEMAP_UV ' + parameters.emissiveMapUv : '', 19936 parameters.bumpMapUv ? '#define BUMPMAP_UV ' + parameters.bumpMapUv : '', 19937 parameters.normalMapUv ? '#define NORMALMAP_UV ' + parameters.normalMapUv : '', 19938 parameters.displacementMapUv ? '#define DISPLACEMENTMAP_UV ' + parameters.displacementMapUv : '', 19939 19940 parameters.metalnessMapUv ? '#define METALNESSMAP_UV ' + parameters.metalnessMapUv : '', 19941 parameters.roughnessMapUv ? '#define ROUGHNESSMAP_UV ' + parameters.roughnessMapUv : '', 19942 19943 parameters.anisotropyMapUv ? '#define ANISOTROPYMAP_UV ' + parameters.anisotropyMapUv : '', 19944 19945 parameters.clearcoatMapUv ? '#define CLEARCOATMAP_UV ' + parameters.clearcoatMapUv : '', 19946 parameters.clearcoatNormalMapUv ? '#define CLEARCOAT_NORMALMAP_UV ' + parameters.clearcoatNormalMapUv : '', 19947 parameters.clearcoatRoughnessMapUv ? '#define CLEARCOAT_ROUGHNESSMAP_UV ' + parameters.clearcoatRoughnessMapUv : '', 19948 19949 parameters.iridescenceMapUv ? '#define IRIDESCENCEMAP_UV ' + parameters.iridescenceMapUv : '', 19950 parameters.iridescenceThicknessMapUv ? '#define IRIDESCENCE_THICKNESSMAP_UV ' + parameters.iridescenceThicknessMapUv : '', 19951 19952 parameters.sheenColorMapUv ? '#define SHEEN_COLORMAP_UV ' + parameters.sheenColorMapUv : '', 19953 parameters.sheenRoughnessMapUv ? '#define SHEEN_ROUGHNESSMAP_UV ' + parameters.sheenRoughnessMapUv : '', 19954 19955 parameters.specularMapUv ? '#define SPECULARMAP_UV ' + parameters.specularMapUv : '', 19956 parameters.specularColorMapUv ? '#define SPECULAR_COLORMAP_UV ' + parameters.specularColorMapUv : '', 19957 parameters.specularIntensityMapUv ? '#define SPECULAR_INTENSITYMAP_UV ' + parameters.specularIntensityMapUv : '', 19958 19959 parameters.transmissionMapUv ? '#define TRANSMISSIONMAP_UV ' + parameters.transmissionMapUv : '', 19960 parameters.thicknessMapUv ? '#define THICKNESSMAP_UV ' + parameters.thicknessMapUv : '', 19961 19962 // 19963 19964 parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '', 19965 parameters.vertexColors ? '#define USE_COLOR' : '', 19966 parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', 19967 parameters.vertexUv1s ? '#define USE_UV1' : '', 19968 parameters.vertexUv2s ? '#define USE_UV2' : '', 19969 parameters.vertexUv3s ? '#define USE_UV3' : '', 19970 19971 parameters.pointsUvs ? '#define USE_POINTS_UV' : '', 19972 19973 parameters.flatShading ? '#define FLAT_SHADED' : '', 19974 19975 parameters.skinning ? '#define USE_SKINNING' : '', 19976 19977 parameters.morphTargets ? '#define USE_MORPHTARGETS' : '', 19978 parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '', 19979 ( parameters.morphColors && parameters.isWebGL2 ) ? '#define USE_MORPHCOLORS' : '', 19980 ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE' : '', 19981 ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_TEXTURE_STRIDE ' + parameters.morphTextureStride : '', 19982 ( parameters.morphTargetsCount > 0 && parameters.isWebGL2 ) ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '', 19983 parameters.doubleSided ? '#define DOUBLE_SIDED' : '', 19984 parameters.flipSided ? '#define FLIP_SIDED' : '', 19985 19986 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', 19987 parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', 19988 19989 parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', 19990 19991 parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', 19992 19993 parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '', 19994 19995 parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', 19996 ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', 19997 19998 'uniform mat4 modelMatrix;', 19999 'uniform mat4 modelViewMatrix;', 20000 'uniform mat4 projectionMatrix;', 20001 'uniform mat4 viewMatrix;', 20002 'uniform mat3 normalMatrix;', 20003 'uniform vec3 cameraPosition;', 20004 'uniform bool isOrthographic;', 20005 20006 '#ifdef USE_INSTANCING', 20007 20008 ' attribute mat4 instanceMatrix;', 20009 20010 '#endif', 20011 20012 '#ifdef USE_INSTANCING_COLOR', 20013 20014 ' attribute vec3 instanceColor;', 20015 20016 '#endif', 20017 20018 'attribute vec3 position;', 20019 'attribute vec3 normal;', 20020 'attribute vec2 uv;', 20021 20022 '#ifdef USE_UV1', 20023 20024 ' attribute vec2 uv1;', 20025 20026 '#endif', 20027 20028 '#ifdef USE_UV2', 20029 20030 ' attribute vec2 uv2;', 20031 20032 '#endif', 20033 20034 '#ifdef USE_UV3', 20035 20036 ' attribute vec2 uv3;', 20037 20038 '#endif', 20039 20040 '#ifdef USE_TANGENT', 20041 20042 ' attribute vec4 tangent;', 20043 20044 '#endif', 20045 20046 '#if defined( USE_COLOR_ALPHA )', 20047 20048 ' attribute vec4 color;', 20049 20050 '#elif defined( USE_COLOR )', 20051 20052 ' attribute vec3 color;', 20053 20054 '#endif', 20055 20056 '#if ( defined( USE_MORPHTARGETS ) && ! defined( MORPHTARGETS_TEXTURE ) )', 20057 20058 ' attribute vec3 morphTarget0;', 20059 ' attribute vec3 morphTarget1;', 20060 ' attribute vec3 morphTarget2;', 20061 ' attribute vec3 morphTarget3;', 20062 20063 ' #ifdef USE_MORPHNORMALS', 20064 20065 ' attribute vec3 morphNormal0;', 20066 ' attribute vec3 morphNormal1;', 20067 ' attribute vec3 morphNormal2;', 20068 ' attribute vec3 morphNormal3;', 20069 20070 ' #else', 20071 20072 ' attribute vec3 morphTarget4;', 20073 ' attribute vec3 morphTarget5;', 20074 ' attribute vec3 morphTarget6;', 20075 ' attribute vec3 morphTarget7;', 20076 20077 ' #endif', 20078 20079 '#endif', 20080 20081 '#ifdef USE_SKINNING', 20082 20083 ' attribute vec4 skinIndex;', 20084 ' attribute vec4 skinWeight;', 20085 20086 '#endif', 20087 20088 '\n' 20089 20090 ].filter( filterEmptyLine ).join( '\n' ); 20091 20092 prefixFragment = [ 20093 20094 customExtensions, 20095 20096 generatePrecision( parameters ), 20097 20098 '#define SHADER_TYPE ' + parameters.shaderType, 20099 '#define SHADER_NAME ' + parameters.shaderName, 20100 20101 customDefines, 20102 20103 parameters.useFog && parameters.fog ? '#define USE_FOG' : '', 20104 parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '', 20105 20106 parameters.map ? '#define USE_MAP' : '', 20107 parameters.matcap ? '#define USE_MATCAP' : '', 20108 parameters.envMap ? '#define USE_ENVMAP' : '', 20109 parameters.envMap ? '#define ' + envMapTypeDefine : '', 20110 parameters.envMap ? '#define ' + envMapModeDefine : '', 20111 parameters.envMap ? '#define ' + envMapBlendingDefine : '', 20112 envMapCubeUVSize ? '#define CUBEUV_TEXEL_WIDTH ' + envMapCubeUVSize.texelWidth : '', 20113 envMapCubeUVSize ? '#define CUBEUV_TEXEL_HEIGHT ' + envMapCubeUVSize.texelHeight : '', 20114 envMapCubeUVSize ? '#define CUBEUV_MAX_MIP ' + envMapCubeUVSize.maxMip + '.0' : '', 20115 parameters.lightMap ? '#define USE_LIGHTMAP' : '', 20116 parameters.aoMap ? '#define USE_AOMAP' : '', 20117 parameters.bumpMap ? '#define USE_BUMPMAP' : '', 20118 parameters.normalMap ? '#define USE_NORMALMAP' : '', 20119 parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '', 20120 parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '', 20121 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', 20122 20123 parameters.anisotropy ? '#define USE_ANISOTROPY' : '', 20124 parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '', 20125 20126 parameters.clearcoat ? '#define USE_CLEARCOAT' : '', 20127 parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', 20128 parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', 20129 parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '', 20130 20131 parameters.iridescence ? '#define USE_IRIDESCENCE' : '', 20132 parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '', 20133 parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', 20134 20135 parameters.specularMap ? '#define USE_SPECULARMAP' : '', 20136 parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '', 20137 parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '', 20138 20139 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', 20140 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', 20141 20142 parameters.alphaMap ? '#define USE_ALPHAMAP' : '', 20143 parameters.alphaTest ? '#define USE_ALPHATEST' : '', 20144 parameters.alphaHash ? '#define USE_ALPHAHASH' : '', 20145 20146 parameters.sheen ? '#define USE_SHEEN' : '', 20147 parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '', 20148 parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '', 20149 20150 parameters.transmission ? '#define USE_TRANSMISSION' : '', 20151 parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', 20152 parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', 20153 20154 parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '', 20155 parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '', 20156 parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', 20157 parameters.vertexUv1s ? '#define USE_UV1' : '', 20158 parameters.vertexUv2s ? '#define USE_UV2' : '', 20159 parameters.vertexUv3s ? '#define USE_UV3' : '', 20160 20161 parameters.pointsUvs ? '#define USE_POINTS_UV' : '', 20162 20163 parameters.gradientMap ? '#define USE_GRADIENTMAP' : '', 20164 20165 parameters.flatShading ? '#define FLAT_SHADED' : '', 20166 20167 parameters.doubleSided ? '#define DOUBLE_SIDED' : '', 20168 parameters.flipSided ? '#define FLIP_SIDED' : '', 20169 20170 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', 20171 parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', 20172 20173 parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '', 20174 20175 parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', 20176 20177 parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '', 20178 20179 parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '', 20180 20181 parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', 20182 ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', 20183 20184 'uniform mat4 viewMatrix;', 20185 'uniform vec3 cameraPosition;', 20186 'uniform bool isOrthographic;', 20187 20188 ( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '', 20189 ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below 20190 ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '', 20191 20192 parameters.dithering ? '#define DITHERING' : '', 20193 parameters.opaque ? '#define OPAQUE' : '', 20194 20195 ShaderChunk[ 'colorspace_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below 20196 getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputColorSpace ), 20197 20198 parameters.useDepthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '', 20199 20200 '\n' 20201 20202 ].filter( filterEmptyLine ).join( '\n' ); 20203 20204 } 20205 20206 vertexShader = resolveIncludes( vertexShader ); 20207 vertexShader = replaceLightNums( vertexShader, parameters ); 20208 vertexShader = replaceClippingPlaneNums( vertexShader, parameters ); 20209 20210 fragmentShader = resolveIncludes( fragmentShader ); 20211 fragmentShader = replaceLightNums( fragmentShader, parameters ); 20212 fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters ); 20213 20214 vertexShader = unrollLoops( vertexShader ); 20215 fragmentShader = unrollLoops( fragmentShader ); 20216 20217 if ( parameters.isWebGL2 && parameters.isRawShaderMaterial !== true ) { 20218 20219 // GLSL 3.0 conversion for built-in materials and ShaderMaterial 20220 20221 versionString = '#version 300 es\n'; 20222 20223 prefixVertex = [ 20224 customVertexExtensions, 20225 'precision mediump sampler2DArray;', 20226 '#define attribute in', 20227 '#define varying out', 20228 '#define texture2D texture' 20229 ].join( '\n' ) + '\n' + prefixVertex; 20230 20231 prefixFragment = [ 20232 'precision mediump sampler2DArray;', 20233 '#define varying in', 20234 ( parameters.glslVersion === GLSL3 ) ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;', 20235 ( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor', 20236 '#define gl_FragDepthEXT gl_FragDepth', 20237 '#define texture2D texture', 20238 '#define textureCube texture', 20239 '#define texture2DProj textureProj', 20240 '#define texture2DLodEXT textureLod', 20241 '#define texture2DProjLodEXT textureProjLod', 20242 '#define textureCubeLodEXT textureLod', 20243 '#define texture2DGradEXT textureGrad', 20244 '#define texture2DProjGradEXT textureProjGrad', 20245 '#define textureCubeGradEXT textureGrad' 20246 ].join( '\n' ) + '\n' + prefixFragment; 20247 20248 } 20249 20250 const vertexGlsl = versionString + prefixVertex + vertexShader; 20251 const fragmentGlsl = versionString + prefixFragment + fragmentShader; 20252 20253 // console.log( '*VERTEX*', vertexGlsl ); 20254 // console.log( '*FRAGMENT*', fragmentGlsl ); 20255 20256 const glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl ); 20257 const glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl ); 20258 20259 gl.attachShader( program, glVertexShader ); 20260 gl.attachShader( program, glFragmentShader ); 20261 20262 // Force a particular attribute to index 0. 20263 20264 if ( parameters.index0AttributeName !== undefined ) { 20265 20266 gl.bindAttribLocation( program, 0, parameters.index0AttributeName ); 20267 20268 } else if ( parameters.morphTargets === true ) { 20269 20270 // programs with morphTargets displace position out of attribute 0 20271 gl.bindAttribLocation( program, 0, 'position' ); 20272 20273 } 20274 20275 gl.linkProgram( program ); 20276 20277 function onFirstUse( self ) { 20278 20279 // check for link errors 20280 if ( renderer.debug.checkShaderErrors ) { 20281 20282 const programLog = gl.getProgramInfoLog( program ).trim(); 20283 const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim(); 20284 const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim(); 20285 20286 let runnable = true; 20287 let haveDiagnostics = true; 20288 20289 if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) { 20290 20291 runnable = false; 20292 20293 if ( typeof renderer.debug.onShaderError === 'function' ) { 20294 20295 renderer.debug.onShaderError( gl, program, glVertexShader, glFragmentShader ); 20296 20297 } else { 20298 20299 // default error reporting 20300 20301 const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' ); 20302 const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' ); 20303 20304 console.error( 20305 'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' + 20306 'VALIDATE_STATUS ' + gl.getProgramParameter( program, gl.VALIDATE_STATUS ) + '\n\n' + 20307 'Program Info Log: ' + programLog + '\n' + 20308 vertexErrors + '\n' + 20309 fragmentErrors 20310 ); 20311 20312 } 20313 20314 } else if ( programLog !== '' ) { 20315 20316 console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog ); 20317 20318 } else if ( vertexLog === '' || fragmentLog === '' ) { 20319 20320 haveDiagnostics = false; 20321 20322 } 20323 20324 if ( haveDiagnostics ) { 20325 20326 self.diagnostics = { 20327 20328 runnable: runnable, 20329 20330 programLog: programLog, 20331 20332 vertexShader: { 20333 20334 log: vertexLog, 20335 prefix: prefixVertex 20336 20337 }, 20338 20339 fragmentShader: { 20340 20341 log: fragmentLog, 20342 prefix: prefixFragment 20343 20344 } 20345 20346 }; 20347 20348 } 20349 20350 } 20351 20352 // Clean up 20353 20354 // Crashes in iOS9 and iOS10. #18402 20355 // gl.detachShader( program, glVertexShader ); 20356 // gl.detachShader( program, glFragmentShader ); 20357 20358 gl.deleteShader( glVertexShader ); 20359 gl.deleteShader( glFragmentShader ); 20360 20361 cachedUniforms = new WebGLUniforms( gl, program ); 20362 cachedAttributes = fetchAttributeLocations( gl, program ); 20363 20364 } 20365 20366 // set up caching for uniform locations 20367 20368 let cachedUniforms; 20369 20370 this.getUniforms = function () { 20371 20372 if ( cachedUniforms === undefined ) { 20373 20374 // Populates cachedUniforms and cachedAttributes 20375 onFirstUse( this ); 20376 20377 } 20378 20379 return cachedUniforms; 20380 20381 }; 20382 20383 // set up caching for attribute locations 20384 20385 let cachedAttributes; 20386 20387 this.getAttributes = function () { 20388 20389 if ( cachedAttributes === undefined ) { 20390 20391 // Populates cachedAttributes and cachedUniforms 20392 onFirstUse( this ); 20393 20394 } 20395 20396 return cachedAttributes; 20397 20398 }; 20399 20400 // indicate when the program is ready to be used. if the KHR_parallel_shader_compile extension isn't supported, 20401 // flag the program as ready immediately. It may cause a stall when it's first used. 20402 20403 let programReady = ( parameters.rendererExtensionParallelShaderCompile === false ); 20404 20405 this.isReady = function () { 20406 20407 if ( programReady === false ) { 20408 20409 programReady = gl.getProgramParameter( program, COMPLETION_STATUS_KHR ); 20410 20411 } 20412 20413 return programReady; 20414 20415 }; 20416 20417 // free resource 20418 20419 this.destroy = function () { 20420 20421 bindingStates.releaseStatesOfProgram( this ); 20422 20423 gl.deleteProgram( program ); 20424 this.program = undefined; 20425 20426 }; 20427 20428 // 20429 20430 this.type = parameters.shaderType; 20431 this.name = parameters.shaderName; 20432 this.id = programIdCount ++; 20433 this.cacheKey = cacheKey; 20434 this.usedTimes = 1; 20435 this.program = program; 20436 this.vertexShader = glVertexShader; 20437 this.fragmentShader = glFragmentShader; 20438 20439 return this; 20440 20441} 20442 20443let _id$1 = 0; 20444 20445class WebGLShaderCache { 20446 20447 constructor() { 20448 20449 this.shaderCache = new Map(); 20450 this.materialCache = new Map(); 20451 20452 } 20453 20454 update( material ) { 20455 20456 const vertexShader = material.vertexShader; 20457 const fragmentShader = material.fragmentShader; 20458 20459 const vertexShaderStage = this._getShaderStage( vertexShader ); 20460 const fragmentShaderStage = this._getShaderStage( fragmentShader ); 20461 20462 const materialShaders = this._getShaderCacheForMaterial( material ); 20463 20464 if ( materialShaders.has( vertexShaderStage ) === false ) { 20465 20466 materialShaders.add( vertexShaderStage ); 20467 vertexShaderStage.usedTimes ++; 20468 20469 } 20470 20471 if ( materialShaders.has( fragmentShaderStage ) === false ) { 20472 20473 materialShaders.add( fragmentShaderStage ); 20474 fragmentShaderStage.usedTimes ++; 20475 20476 } 20477 20478 return this; 20479 20480 } 20481 20482 remove( material ) { 20483 20484 const materialShaders = this.materialCache.get( material ); 20485 20486 for ( const shaderStage of materialShaders ) { 20487 20488 shaderStage.usedTimes --; 20489 20490 if ( shaderStage.usedTimes === 0 ) this.shaderCache.delete( shaderStage.code ); 20491 20492 } 20493 20494 this.materialCache.delete( material ); 20495 20496 return this; 20497 20498 } 20499 20500 getVertexShaderID( material ) { 20501 20502 return this._getShaderStage( material.vertexShader ).id; 20503 20504 } 20505 20506 getFragmentShaderID( material ) { 20507 20508 return this._getShaderStage( material.fragmentShader ).id; 20509 20510 } 20511 20512 dispose() { 20513 20514 this.shaderCache.clear(); 20515 this.materialCache.clear(); 20516 20517 } 20518 20519 _getShaderCacheForMaterial( material ) { 20520 20521 const cache = this.materialCache; 20522 let set = cache.get( material ); 20523 20524 if ( set === undefined ) { 20525 20526 set = new Set(); 20527 cache.set( material, set ); 20528 20529 } 20530 20531 return set; 20532 20533 } 20534 20535 _getShaderStage( code ) { 20536 20537 const cache = this.shaderCache; 20538 let stage = cache.get( code ); 20539 20540 if ( stage === undefined ) { 20541 20542 stage = new WebGLShaderStage( code ); 20543 cache.set( code, stage ); 20544 20545 } 20546 20547 return stage; 20548 20549 } 20550 20551} 20552 20553class WebGLShaderStage { 20554 20555 constructor( code ) { 20556 20557 this.id = _id$1 ++; 20558 20559 this.code = code; 20560 this.usedTimes = 0; 20561 20562 } 20563 20564} 20565 20566function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ) { 20567 20568 const _programLayers = new Layers(); 20569 const _customShaders = new WebGLShaderCache(); 20570 const programs = []; 20571 20572 const IS_WEBGL2 = capabilities.isWebGL2; 20573 const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer; 20574 const SUPPORTS_VERTEX_TEXTURES = capabilities.vertexTextures; 20575 20576 let precision = capabilities.precision; 20577 20578 const shaderIDs = { 20579 MeshDepthMaterial: 'depth', 20580 MeshDistanceMaterial: 'distanceRGBA', 20581 MeshNormalMaterial: 'normal', 20582 MeshBasicMaterial: 'basic', 20583 MeshLambertMaterial: 'lambert', 20584 MeshPhongMaterial: 'phong', 20585 MeshToonMaterial: 'toon', 20586 MeshStandardMaterial: 'physical', 20587 MeshPhysicalMaterial: 'physical', 20588 MeshMatcapMaterial: 'matcap', 20589 LineBasicMaterial: 'basic', 20590 LineDashedMaterial: 'dashed', 20591 PointsMaterial: 'points', 20592 ShadowMaterial: 'shadow', 20593 SpriteMaterial: 'sprite' 20594 }; 20595 20596 function getChannel( value ) { 20597 20598 if ( value === 0 ) return 'uv'; 20599 20600 return `uv${ value }`; 20601 20602 } 20603 20604 function getParameters( material, lights, shadows, scene, object ) { 20605 20606 const fog = scene.fog; 20607 const geometry = object.geometry; 20608 const environment = material.isMeshStandardMaterial ? scene.environment : null; 20609 20610 const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment ); 20611 const envMapCubeUVHeight = ( !! envMap ) && ( envMap.mapping === CubeUVReflectionMapping ) ? envMap.image.height : null; 20612 20613 const shaderID = shaderIDs[ material.type ]; 20614 20615 // heuristics to create shader parameters according to lights in the scene 20616 // (not to blow over maxLights budget) 20617 20618 if ( material.precision !== null ) { 20619 20620 precision = capabilities.getMaxPrecision( material.precision ); 20621 20622 if ( precision !== material.precision ) { 20623 20624 console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' ); 20625 20626 } 20627 20628 } 20629 20630 // 20631 20632 const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; 20633 const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; 20634 20635 let morphTextureStride = 0; 20636 20637 if ( geometry.morphAttributes.position !== undefined ) morphTextureStride = 1; 20638 if ( geometry.morphAttributes.normal !== undefined ) morphTextureStride = 2; 20639 if ( geometry.morphAttributes.color !== undefined ) morphTextureStride = 3; 20640 20641 // 20642 20643 let vertexShader, fragmentShader; 20644 let customVertexShaderID, customFragmentShaderID; 20645 20646 if ( shaderID ) { 20647 20648 const shader = ShaderLib[ shaderID ]; 20649 20650 vertexShader = shader.vertexShader; 20651 fragmentShader = shader.fragmentShader; 20652 20653 } else { 20654 20655 vertexShader = material.vertexShader; 20656 fragmentShader = material.fragmentShader; 20657 20658 _customShaders.update( material ); 20659 20660 customVertexShaderID = _customShaders.getVertexShaderID( material ); 20661 customFragmentShaderID = _customShaders.getFragmentShaderID( material ); 20662 20663 } 20664 20665 const currentRenderTarget = renderer.getRenderTarget(); 20666 20667 const IS_INSTANCEDMESH = object.isInstancedMesh === true; 20668 const IS_BATCHEDMESH = object.isBatchedMesh === true; 20669 20670 const HAS_MAP = !! material.map; 20671 const HAS_MATCAP = !! material.matcap; 20672 const HAS_ENVMAP = !! envMap; 20673 const HAS_AOMAP = !! material.aoMap; 20674 const HAS_LIGHTMAP = !! material.lightMap; 20675 const HAS_BUMPMAP = !! material.bumpMap; 20676 const HAS_NORMALMAP = !! material.normalMap; 20677 const HAS_DISPLACEMENTMAP = !! material.displacementMap; 20678 const HAS_EMISSIVEMAP = !! material.emissiveMap; 20679 20680 const HAS_METALNESSMAP = !! material.metalnessMap; 20681 const HAS_ROUGHNESSMAP = !! material.roughnessMap; 20682 20683 const HAS_ANISOTROPY = material.anisotropy > 0; 20684 const HAS_CLEARCOAT = material.clearcoat > 0; 20685 const HAS_IRIDESCENCE = material.iridescence > 0; 20686 const HAS_SHEEN = material.sheen > 0; 20687 const HAS_TRANSMISSION = material.transmission > 0; 20688 20689 const HAS_ANISOTROPYMAP = HAS_ANISOTROPY && !! material.anisotropyMap; 20690 20691 const HAS_CLEARCOATMAP = HAS_CLEARCOAT && !! material.clearcoatMap; 20692 const HAS_CLEARCOAT_NORMALMAP = HAS_CLEARCOAT && !! material.clearcoatNormalMap; 20693 const HAS_CLEARCOAT_ROUGHNESSMAP = HAS_CLEARCOAT && !! material.clearcoatRoughnessMap; 20694 20695 const HAS_IRIDESCENCEMAP = HAS_IRIDESCENCE && !! material.iridescenceMap; 20696 const HAS_IRIDESCENCE_THICKNESSMAP = HAS_IRIDESCENCE && !! material.iridescenceThicknessMap; 20697 20698 const HAS_SHEEN_COLORMAP = HAS_SHEEN && !! material.sheenColorMap; 20699 const HAS_SHEEN_ROUGHNESSMAP = HAS_SHEEN && !! material.sheenRoughnessMap; 20700 20701 const HAS_SPECULARMAP = !! material.specularMap; 20702 const HAS_SPECULAR_COLORMAP = !! material.specularColorMap; 20703 const HAS_SPECULAR_INTENSITYMAP = !! material.specularIntensityMap; 20704 20705 const HAS_TRANSMISSIONMAP = HAS_TRANSMISSION && !! material.transmissionMap; 20706 const HAS_THICKNESSMAP = HAS_TRANSMISSION && !! material.thicknessMap; 20707 20708 const HAS_GRADIENTMAP = !! material.gradientMap; 20709 20710 const HAS_ALPHAMAP = !! material.alphaMap; 20711 20712 const HAS_ALPHATEST = material.alphaTest > 0; 20713 20714 const HAS_ALPHAHASH = !! material.alphaHash; 20715 20716 const HAS_EXTENSIONS = !! material.extensions; 20717 20718 const HAS_ATTRIBUTE_UV1 = !! geometry.attributes.uv1; 20719 const HAS_ATTRIBUTE_UV2 = !! geometry.attributes.uv2; 20720 const HAS_ATTRIBUTE_UV3 = !! geometry.attributes.uv3; 20721 20722 let toneMapping = NoToneMapping; 20723 20724 if ( material.toneMapped ) { 20725 20726 if ( currentRenderTarget === null || currentRenderTarget.isXRRenderTarget === true ) { 20727 20728 toneMapping = renderer.toneMapping; 20729 20730 } 20731 20732 } 20733 20734 const parameters = { 20735 20736 isWebGL2: IS_WEBGL2, 20737 20738 shaderID: shaderID, 20739 shaderType: material.type, 20740 shaderName: material.name, 20741 20742 vertexShader: vertexShader, 20743 fragmentShader: fragmentShader, 20744 defines: material.defines, 20745 20746 customVertexShaderID: customVertexShaderID, 20747 customFragmentShaderID: customFragmentShaderID, 20748 20749 isRawShaderMaterial: material.isRawShaderMaterial === true, 20750 glslVersion: material.glslVersion, 20751 20752 precision: precision, 20753 20754 batching: IS_BATCHEDMESH, 20755 instancing: IS_INSTANCEDMESH, 20756 instancingColor: IS_INSTANCEDMESH && object.instanceColor !== null, 20757 20758 supportsVertexTextures: SUPPORTS_VERTEX_TEXTURES, 20759 outputColorSpace: ( currentRenderTarget === null ) ? renderer.outputColorSpace : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ), 20760 20761 map: HAS_MAP, 20762 matcap: HAS_MATCAP, 20763 envMap: HAS_ENVMAP, 20764 envMapMode: HAS_ENVMAP && envMap.mapping, 20765 envMapCubeUVHeight: envMapCubeUVHeight, 20766 aoMap: HAS_AOMAP, 20767 lightMap: HAS_LIGHTMAP, 20768 bumpMap: HAS_BUMPMAP, 20769 normalMap: HAS_NORMALMAP, 20770 displacementMap: SUPPORTS_VERTEX_TEXTURES && HAS_DISPLACEMENTMAP, 20771 emissiveMap: HAS_EMISSIVEMAP, 20772 20773 normalMapObjectSpace: HAS_NORMALMAP && material.normalMapType === ObjectSpaceNormalMap, 20774 normalMapTangentSpace: HAS_NORMALMAP && material.normalMapType === TangentSpaceNormalMap, 20775 20776 metalnessMap: HAS_METALNESSMAP, 20777 roughnessMap: HAS_ROUGHNESSMAP, 20778 20779 anisotropy: HAS_ANISOTROPY, 20780 anisotropyMap: HAS_ANISOTROPYMAP, 20781 20782 clearcoat: HAS_CLEARCOAT, 20783 clearcoatMap: HAS_CLEARCOATMAP, 20784 clearcoatNormalMap: HAS_CLEARCOAT_NORMALMAP, 20785 clearcoatRoughnessMap: HAS_CLEARCOAT_ROUGHNESSMAP, 20786 20787 iridescence: HAS_IRIDESCENCE, 20788 iridescenceMap: HAS_IRIDESCENCEMAP, 20789 iridescenceThicknessMap: HAS_IRIDESCENCE_THICKNESSMAP, 20790 20791 sheen: HAS_SHEEN, 20792 sheenColorMap: HAS_SHEEN_COLORMAP, 20793 sheenRoughnessMap: HAS_SHEEN_ROUGHNESSMAP, 20794 20795 specularMap: HAS_SPECULARMAP, 20796 specularColorMap: HAS_SPECULAR_COLORMAP, 20797 specularIntensityMap: HAS_SPECULAR_INTENSITYMAP, 20798 20799 transmission: HAS_TRANSMISSION, 20800 transmissionMap: HAS_TRANSMISSIONMAP, 20801 thicknessMap: HAS_THICKNESSMAP, 20802 20803 gradientMap: HAS_GRADIENTMAP, 20804 20805 opaque: material.transparent === false && material.blending === NormalBlending, 20806 20807 alphaMap: HAS_ALPHAMAP, 20808 alphaTest: HAS_ALPHATEST, 20809 alphaHash: HAS_ALPHAHASH, 20810 20811 combine: material.combine, 20812 20813 // 20814 20815 mapUv: HAS_MAP && getChannel( material.map.channel ), 20816 aoMapUv: HAS_AOMAP && getChannel( material.aoMap.channel ), 20817 lightMapUv: HAS_LIGHTMAP && getChannel( material.lightMap.channel ), 20818 bumpMapUv: HAS_BUMPMAP && getChannel( material.bumpMap.channel ), 20819 normalMapUv: HAS_NORMALMAP && getChannel( material.normalMap.channel ), 20820 displacementMapUv: HAS_DISPLACEMENTMAP && getChannel( material.displacementMap.channel ), 20821 emissiveMapUv: HAS_EMISSIVEMAP && getChannel( material.emissiveMap.channel ), 20822 20823 metalnessMapUv: HAS_METALNESSMAP && getChannel( material.metalnessMap.channel ), 20824 roughnessMapUv: HAS_ROUGHNESSMAP && getChannel( material.roughnessMap.channel ), 20825 20826 anisotropyMapUv: HAS_ANISOTROPYMAP && getChannel( material.anisotropyMap.channel ), 20827 20828 clearcoatMapUv: HAS_CLEARCOATMAP && getChannel( material.clearcoatMap.channel ), 20829 clearcoatNormalMapUv: HAS_CLEARCOAT_NORMALMAP && getChannel( material.clearcoatNormalMap.channel ), 20830 clearcoatRoughnessMapUv: HAS_CLEARCOAT_ROUGHNESSMAP && getChannel( material.clearcoatRoughnessMap.channel ), 20831 20832 iridescenceMapUv: HAS_IRIDESCENCEMAP && getChannel( material.iridescenceMap.channel ), 20833 iridescenceThicknessMapUv: HAS_IRIDESCENCE_THICKNESSMAP && getChannel( material.iridescenceThicknessMap.channel ), 20834 20835 sheenColorMapUv: HAS_SHEEN_COLORMAP && getChannel( material.sheenColorMap.channel ), 20836 sheenRoughnessMapUv: HAS_SHEEN_ROUGHNESSMAP && getChannel( material.sheenRoughnessMap.channel ), 20837 20838 specularMapUv: HAS_SPECULARMAP && getChannel( material.specularMap.channel ), 20839 specularColorMapUv: HAS_SPECULAR_COLORMAP && getChannel( material.specularColorMap.channel ), 20840 specularIntensityMapUv: HAS_SPECULAR_INTENSITYMAP && getChannel( material.specularIntensityMap.channel ), 20841 20842 transmissionMapUv: HAS_TRANSMISSIONMAP && getChannel( material.transmissionMap.channel ), 20843 thicknessMapUv: HAS_THICKNESSMAP && getChannel( material.thicknessMap.channel ), 20844 20845 alphaMapUv: HAS_ALPHAMAP && getChannel( material.alphaMap.channel ), 20846 20847 // 20848 20849 vertexTangents: !! geometry.attributes.tangent && ( HAS_NORMALMAP || HAS_ANISOTROPY ), 20850 vertexColors: material.vertexColors, 20851 vertexAlphas: material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4, 20852 vertexUv1s: HAS_ATTRIBUTE_UV1, 20853 vertexUv2s: HAS_ATTRIBUTE_UV2, 20854 vertexUv3s: HAS_ATTRIBUTE_UV3, 20855 20856 pointsUvs: object.isPoints === true && !! geometry.attributes.uv && ( HAS_MAP || HAS_ALPHAMAP ), 20857 20858 fog: !! fog, 20859 useFog: material.fog === true, 20860 fogExp2: ( fog && fog.isFogExp2 ), 20861 20862 flatShading: material.flatShading === true, 20863 20864 sizeAttenuation: material.sizeAttenuation === true, 20865 logarithmicDepthBuffer: logarithmicDepthBuffer, 20866 20867 skinning: object.isSkinnedMesh === true, 20868 20869 morphTargets: geometry.morphAttributes.position !== undefined, 20870 morphNormals: geometry.morphAttributes.normal !== undefined, 20871 morphColors: geometry.morphAttributes.color !== undefined, 20872 morphTargetsCount: morphTargetsCount, 20873 morphTextureStride: morphTextureStride, 20874 20875 numDirLights: lights.directional.length, 20876 numPointLights: lights.point.length, 20877 numSpotLights: lights.spot.length, 20878 numSpotLightMaps: lights.spotLightMap.length, 20879 numRectAreaLights: lights.rectArea.length, 20880 numHemiLights: lights.hemi.length, 20881 20882 numDirLightShadows: lights.directionalShadowMap.length, 20883 numPointLightShadows: lights.pointShadowMap.length, 20884 numSpotLightShadows: lights.spotShadowMap.length, 20885 numSpotLightShadowsWithMaps: lights.numSpotLightShadowsWithMaps, 20886 20887 numLightProbes: lights.numLightProbes, 20888 20889 numClippingPlanes: clipping.numPlanes, 20890 numClipIntersection: clipping.numIntersection, 20891 20892 dithering: material.dithering, 20893 20894 shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0, 20895 shadowMapType: renderer.shadowMap.type, 20896 20897 toneMapping: toneMapping, 20898 useLegacyLights: renderer._useLegacyLights, 20899 20900 decodeVideoTexture: HAS_MAP && ( material.map.isVideoTexture === true ) && ( ColorManagement.getTransfer( material.map.colorSpace ) === SRGBTransfer ), 20901 20902 premultipliedAlpha: material.premultipliedAlpha, 20903 20904 doubleSided: material.side === DoubleSide, 20905 flipSided: material.side === BackSide, 20906 20907 useDepthPacking: material.depthPacking >= 0, 20908 depthPacking: material.depthPacking || 0, 20909 20910 index0AttributeName: material.index0AttributeName, 20911 20912 extensionDerivatives: HAS_EXTENSIONS && material.extensions.derivatives === true, 20913 extensionFragDepth: HAS_EXTENSIONS && material.extensions.fragDepth === true, 20914 extensionDrawBuffers: HAS_EXTENSIONS && material.extensions.drawBuffers === true, 20915 extensionShaderTextureLOD: HAS_EXTENSIONS && material.extensions.shaderTextureLOD === true, 20916 extensionClipCullDistance: HAS_EXTENSIONS && material.extensions.clipCullDistance && extensions.has( 'WEBGL_clip_cull_distance' ), 20917 20918 rendererExtensionFragDepth: IS_WEBGL2 || extensions.has( 'EXT_frag_depth' ), 20919 rendererExtensionDrawBuffers: IS_WEBGL2 || extensions.has( 'WEBGL_draw_buffers' ), 20920 rendererExtensionShaderTextureLod: IS_WEBGL2 || extensions.has( 'EXT_shader_texture_lod' ), 20921 rendererExtensionParallelShaderCompile: extensions.has( 'KHR_parallel_shader_compile' ), 20922 20923 customProgramCacheKey: material.customProgramCacheKey() 20924 20925 }; 20926 20927 return parameters; 20928 20929 } 20930 20931 function getProgramCacheKey( parameters ) { 20932 20933 const array = []; 20934 20935 if ( parameters.shaderID ) { 20936 20937 array.push( parameters.shaderID ); 20938 20939 } else { 20940 20941 array.push( parameters.customVertexShaderID ); 20942 array.push( parameters.customFragmentShaderID ); 20943 20944 } 20945 20946 if ( parameters.defines !== undefined ) { 20947 20948 for ( const name in parameters.defines ) { 20949 20950 array.push( name ); 20951 array.push( parameters.defines[ name ] ); 20952 20953 } 20954 20955 } 20956 20957 if ( parameters.isRawShaderMaterial === false ) { 20958 20959 getProgramCacheKeyParameters( array, parameters ); 20960 getProgramCacheKeyBooleans( array, parameters ); 20961 array.push( renderer.outputColorSpace ); 20962 20963 } 20964 20965 array.push( parameters.customProgramCacheKey ); 20966 20967 return array.join(); 20968 20969 } 20970 20971 function getProgramCacheKeyParameters( array, parameters ) { 20972 20973 array.push( parameters.precision ); 20974 array.push( parameters.outputColorSpace ); 20975 array.push( parameters.envMapMode ); 20976 array.push( parameters.envMapCubeUVHeight ); 20977 array.push( parameters.mapUv ); 20978 array.push( parameters.alphaMapUv ); 20979 array.push( parameters.lightMapUv ); 20980 array.push( parameters.aoMapUv ); 20981 array.push( parameters.bumpMapUv ); 20982 array.push( parameters.normalMapUv ); 20983 array.push( parameters.displacementMapUv ); 20984 array.push( parameters.emissiveMapUv ); 20985 array.push( parameters.metalnessMapUv ); 20986 array.push( parameters.roughnessMapUv ); 20987 array.push( parameters.anisotropyMapUv ); 20988 array.push( parameters.clearcoatMapUv ); 20989 array.push( parameters.clearcoatNormalMapUv ); 20990 array.push( parameters.clearcoatRoughnessMapUv ); 20991 array.push( parameters.iridescenceMapUv ); 20992 array.push( parameters.iridescenceThicknessMapUv ); 20993 array.push( parameters.sheenColorMapUv ); 20994 array.push( parameters.sheenRoughnessMapUv ); 20995 array.push( parameters.specularMapUv ); 20996 array.push( parameters.specularColorMapUv ); 20997 array.push( parameters.specularIntensityMapUv ); 20998 array.push( parameters.transmissionMapUv ); 20999 array.push( parameters.thicknessMapUv ); 21000 array.push( parameters.combine ); 21001 array.push( parameters.fogExp2 ); 21002 array.push( parameters.sizeAttenuation ); 21003 array.push( parameters.morphTargetsCount ); 21004 array.push( parameters.morphAttributeCount ); 21005 array.push( parameters.numDirLights ); 21006 array.push( parameters.numPointLights ); 21007 array.push( parameters.numSpotLights ); 21008 array.push( parameters.numSpotLightMaps ); 21009 array.push( parameters.numHemiLights ); 21010 array.push( parameters.numRectAreaLights ); 21011 array.push( parameters.numDirLightShadows ); 21012 array.push( parameters.numPointLightShadows ); 21013 array.push( parameters.numSpotLightShadows ); 21014 array.push( parameters.numSpotLightShadowsWithMaps ); 21015 array.push( parameters.numLightProbes ); 21016 array.push( parameters.shadowMapType ); 21017 array.push( parameters.toneMapping ); 21018 array.push( parameters.numClippingPlanes ); 21019 array.push( parameters.numClipIntersection ); 21020 array.push( parameters.depthPacking ); 21021 21022 } 21023 21024 function getProgramCacheKeyBooleans( array, parameters ) { 21025 21026 _programLayers.disableAll(); 21027 21028 if ( parameters.isWebGL2 ) 21029 _programLayers.enable( 0 ); 21030 if ( parameters.supportsVertexTextures ) 21031 _programLayers.enable( 1 ); 21032 if ( parameters.instancing ) 21033 _programLayers.enable( 2 ); 21034 if ( parameters.instancingColor ) 21035 _programLayers.enable( 3 ); 21036 if ( parameters.matcap ) 21037 _programLayers.enable( 4 ); 21038 if ( parameters.envMap ) 21039 _programLayers.enable( 5 ); 21040 if ( parameters.normalMapObjectSpace ) 21041 _programLayers.enable( 6 ); 21042 if ( parameters.normalMapTangentSpace ) 21043 _programLayers.enable( 7 ); 21044 if ( parameters.clearcoat ) 21045 _programLayers.enable( 8 ); 21046 if ( parameters.iridescence ) 21047 _programLayers.enable( 9 ); 21048 if ( parameters.alphaTest ) 21049 _programLayers.enable( 10 ); 21050 if ( parameters.vertexColors ) 21051 _programLayers.enable( 11 ); 21052 if ( parameters.vertexAlphas ) 21053 _programLayers.enable( 12 ); 21054 if ( parameters.vertexUv1s ) 21055 _programLayers.enable( 13 ); 21056 if ( parameters.vertexUv2s ) 21057 _programLayers.enable( 14 ); 21058 if ( parameters.vertexUv3s ) 21059 _programLayers.enable( 15 ); 21060 if ( parameters.vertexTangents ) 21061 _programLayers.enable( 16 ); 21062 if ( parameters.anisotropy ) 21063 _programLayers.enable( 17 ); 21064 if ( parameters.alphaHash ) 21065 _programLayers.enable( 18 ); 21066 if ( parameters.batching ) 21067 _programLayers.enable( 19 ); 21068 21069 array.push( _programLayers.mask ); 21070 _programLayers.disableAll(); 21071 21072 if ( parameters.fog ) 21073 _programLayers.enable( 0 ); 21074 if ( parameters.useFog ) 21075 _programLayers.enable( 1 ); 21076 if ( parameters.flatShading ) 21077 _programLayers.enable( 2 ); 21078 if ( parameters.logarithmicDepthBuffer ) 21079 _programLayers.enable( 3 ); 21080 if ( parameters.skinning ) 21081 _programLayers.enable( 4 ); 21082 if ( parameters.morphTargets ) 21083 _programLayers.enable( 5 ); 21084 if ( parameters.morphNormals ) 21085 _programLayers.enable( 6 ); 21086 if ( parameters.morphColors ) 21087 _programLayers.enable( 7 ); 21088 if ( parameters.premultipliedAlpha ) 21089 _programLayers.enable( 8 ); 21090 if ( parameters.shadowMapEnabled ) 21091 _programLayers.enable( 9 ); 21092 if ( parameters.useLegacyLights ) 21093 _programLayers.enable( 10 ); 21094 if ( parameters.doubleSided ) 21095 _programLayers.enable( 11 ); 21096 if ( parameters.flipSided ) 21097 _programLayers.enable( 12 ); 21098 if ( parameters.useDepthPacking ) 21099 _programLayers.enable( 13 ); 21100 if ( parameters.dithering ) 21101 _programLayers.enable( 14 ); 21102 if ( parameters.transmission ) 21103 _programLayers.enable( 15 ); 21104 if ( parameters.sheen ) 21105 _programLayers.enable( 16 ); 21106 if ( parameters.opaque ) 21107 _programLayers.enable( 17 ); 21108 if ( parameters.pointsUvs ) 21109 _programLayers.enable( 18 ); 21110 if ( parameters.decodeVideoTexture ) 21111 _programLayers.enable( 19 ); 21112 21113 array.push( _programLayers.mask ); 21114 21115 } 21116 21117 function getUniforms( material ) { 21118 21119 const shaderID = shaderIDs[ material.type ]; 21120 let uniforms; 21121 21122 if ( shaderID ) { 21123 21124 const shader = ShaderLib[ shaderID ]; 21125 uniforms = UniformsUtils.clone( shader.uniforms ); 21126 21127 } else { 21128 21129 uniforms = material.uniforms; 21130 21131 } 21132 21133 return uniforms; 21134 21135 } 21136 21137 function acquireProgram( parameters, cacheKey ) { 21138 21139 let program; 21140 21141 // Check if code has been already compiled 21142 for ( let p = 0, pl = programs.length; p < pl; p ++ ) { 21143 21144 const preexistingProgram = programs[ p ]; 21145 21146 if ( preexistingProgram.cacheKey === cacheKey ) { 21147 21148 program = preexistingProgram; 21149 ++ program.usedTimes; 21150 21151 break; 21152 21153 } 21154 21155 } 21156 21157 if ( program === undefined ) { 21158 21159 program = new WebGLProgram( renderer, cacheKey, parameters, bindingStates ); 21160 programs.push( program ); 21161 21162 } 21163 21164 return program; 21165 21166 } 21167 21168 function releaseProgram( program ) { 21169 21170 if ( -- program.usedTimes === 0 ) { 21171 21172 // Remove from unordered set 21173 const i = programs.indexOf( program ); 21174 programs[ i ] = programs[ programs.length - 1 ]; 21175 programs.pop(); 21176 21177 // Free WebGL resources 21178 program.destroy(); 21179 21180 } 21181 21182 } 21183 21184 function releaseShaderCache( material ) { 21185 21186 _customShaders.remove( material ); 21187 21188 } 21189 21190 function dispose() { 21191 21192 _customShaders.dispose(); 21193 21194 } 21195 21196 return { 21197 getParameters: getParameters, 21198 getProgramCacheKey: getProgramCacheKey, 21199 getUniforms: getUniforms, 21200 acquireProgram: acquireProgram, 21201 releaseProgram: releaseProgram, 21202 releaseShaderCache: releaseShaderCache, 21203 // Exposed for resource monitoring & error feedback via renderer.info: 21204 programs: programs, 21205 dispose: dispose 21206 }; 21207 21208} 21209 21210function WebGLProperties() { 21211 21212 let properties = new WeakMap(); 21213 21214 function get( object ) { 21215 21216 let map = properties.get( object ); 21217 21218 if ( map === undefined ) { 21219 21220 map = {}; 21221 properties.set( object, map ); 21222 21223 } 21224 21225 return map; 21226 21227 } 21228 21229 function remove( object ) { 21230 21231 properties.delete( object ); 21232 21233 } 21234 21235 function update( object, key, value ) { 21236 21237 properties.get( object )[ key ] = value; 21238 21239 } 21240 21241 function dispose() { 21242 21243 properties = new WeakMap(); 21244 21245 } 21246 21247 return { 21248 get: get, 21249 remove: remove, 21250 update: update, 21251 dispose: dispose 21252 }; 21253 21254} 21255 21256function painterSortStable( a, b ) { 21257 21258 if ( a.groupOrder !== b.groupOrder ) { 21259 21260 return a.groupOrder - b.groupOrder; 21261 21262 } else if ( a.renderOrder !== b.renderOrder ) { 21263 21264 return a.renderOrder - b.renderOrder; 21265 21266 } else if ( a.material.id !== b.material.id ) { 21267 21268 return a.material.id - b.material.id; 21269 21270 } else if ( a.z !== b.z ) { 21271 21272 return a.z - b.z; 21273 21274 } else { 21275 21276 return a.id - b.id; 21277 21278 } 21279 21280} 21281 21282function reversePainterSortStable( a, b ) { 21283 21284 if ( a.groupOrder !== b.groupOrder ) { 21285 21286 return a.groupOrder - b.groupOrder; 21287 21288 } else if ( a.renderOrder !== b.renderOrder ) { 21289 21290 return a.renderOrder - b.renderOrder; 21291 21292 } else if ( a.z !== b.z ) { 21293 21294 return b.z - a.z; 21295 21296 } else { 21297 21298 return a.id - b.id; 21299 21300 } 21301 21302} 21303 21304 21305function WebGLRenderList() { 21306 21307 const renderItems = []; 21308 let renderItemsIndex = 0; 21309 21310 const opaque = []; 21311 const transmissive = []; 21312 const transparent = []; 21313 21314 function init() { 21315 21316 renderItemsIndex = 0; 21317 21318 opaque.length = 0; 21319 transmissive.length = 0; 21320 transparent.length = 0; 21321 21322 } 21323 21324 function getNextRenderItem( object, geometry, material, groupOrder, z, group ) { 21325 21326 let renderItem = renderItems[ renderItemsIndex ]; 21327 21328 if ( renderItem === undefined ) { 21329 21330 renderItem = { 21331 id: object.id, 21332 object: object, 21333 geometry: geometry, 21334 material: material, 21335 groupOrder: groupOrder, 21336 renderOrder: object.renderOrder, 21337 z: z, 21338 group: group 21339 }; 21340 21341 renderItems[ renderItemsIndex ] = renderItem; 21342 21343 } else { 21344 21345 renderItem.id = object.id; 21346 renderItem.object = object; 21347 renderItem.geometry = geometry; 21348 renderItem.material = material; 21349 renderItem.groupOrder = groupOrder; 21350 renderItem.renderOrder = object.renderOrder; 21351 renderItem.z = z; 21352 renderItem.group = group; 21353 21354 } 21355 21356 renderItemsIndex ++; 21357 21358 return renderItem; 21359 21360 } 21361 21362 function push( object, geometry, material, groupOrder, z, group ) { 21363 21364 const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group ); 21365 21366 if ( material.transmission > 0.0 ) { 21367 21368 transmissive.push( renderItem ); 21369 21370 } else if ( material.transparent === true ) { 21371 21372 transparent.push( renderItem ); 21373 21374 } else { 21375 21376 opaque.push( renderItem ); 21377 21378 } 21379 21380 } 21381 21382 function unshift( object, geometry, material, groupOrder, z, group ) { 21383 21384 const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group ); 21385 21386 if ( material.transmission > 0.0 ) { 21387 21388 transmissive.unshift( renderItem ); 21389 21390 } else if ( material.transparent === true ) { 21391 21392 transparent.unshift( renderItem ); 21393 21394 } else { 21395 21396 opaque.unshift( renderItem ); 21397 21398 } 21399 21400 } 21401 21402 function sort( customOpaqueSort, customTransparentSort ) { 21403 21404 if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable ); 21405 if ( transmissive.length > 1 ) transmissive.sort( customTransparentSort || reversePainterSortStable ); 21406 if ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable ); 21407 21408 } 21409 21410 function finish() { 21411 21412 // Clear references from inactive renderItems in the list 21413 21414 for ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) { 21415 21416 const renderItem = renderItems[ i ]; 21417 21418 if ( renderItem.id === null ) break; 21419 21420 renderItem.id = null; 21421 renderItem.object = null; 21422 renderItem.geometry = null; 21423 renderItem.material = null; 21424 renderItem.group = null; 21425 21426 } 21427 21428 } 21429 21430 return { 21431 21432 opaque: opaque, 21433 transmissive: transmissive, 21434 transparent: transparent, 21435 21436 init: init, 21437 push: push, 21438 unshift: unshift, 21439 finish: finish, 21440 21441 sort: sort 21442 }; 21443 21444} 21445 21446function WebGLRenderLists() { 21447 21448 let lists = new WeakMap(); 21449 21450 function get( scene, renderCallDepth ) { 21451 21452 const listArray = lists.get( scene ); 21453 let list; 21454 21455 if ( listArray === undefined ) { 21456 21457 list = new WebGLRenderList(); 21458 lists.set( scene, [ list ] ); 21459 21460 } else { 21461 21462 if ( renderCallDepth >= listArray.length ) { 21463 21464 list = new WebGLRenderList(); 21465 listArray.push( list ); 21466 21467 } else { 21468 21469 list = listArray[ renderCallDepth ]; 21470 21471 } 21472 21473 } 21474 21475 return list; 21476 21477 } 21478 21479 function dispose() { 21480 21481 lists = new WeakMap(); 21482 21483 } 21484 21485 return { 21486 get: get, 21487 dispose: dispose 21488 }; 21489 21490} 21491 21492function UniformsCache() { 21493 21494 const lights = {}; 21495 21496 return { 21497 21498 get: function ( light ) { 21499 21500 if ( lights[ light.id ] !== undefined ) { 21501 21502 return lights[ light.id ]; 21503 21504 } 21505 21506 let uniforms; 21507 21508 switch ( light.type ) { 21509 21510 case 'DirectionalLight': 21511 uniforms = { 21512 direction: new Vector3(), 21513 color: new Color() 21514 }; 21515 break; 21516 21517 case 'SpotLight': 21518 uniforms = { 21519 position: new Vector3(), 21520 direction: new Vector3(), 21521 color: new Color(), 21522 distance: 0, 21523 coneCos: 0, 21524 penumbraCos: 0, 21525 decay: 0 21526 }; 21527 break; 21528 21529 case 'PointLight': 21530 uniforms = { 21531 position: new Vector3(), 21532 color: new Color(), 21533 distance: 0, 21534 decay: 0 21535 }; 21536 break; 21537 21538 case 'HemisphereLight': 21539 uniforms = { 21540 direction: new Vector3(), 21541 skyColor: new Color(), 21542 groundColor: new Color() 21543 }; 21544 break; 21545 21546 case 'RectAreaLight': 21547 uniforms = { 21548 color: new Color(), 21549 position: new Vector3(), 21550 halfWidth: new Vector3(), 21551 halfHeight: new Vector3() 21552 }; 21553 break; 21554 21555 } 21556 21557 lights[ light.id ] = uniforms; 21558 21559 return uniforms; 21560 21561 } 21562 21563 }; 21564 21565} 21566 21567function ShadowUniformsCache() { 21568 21569 const lights = {}; 21570 21571 return { 21572 21573 get: function ( light ) { 21574 21575 if ( lights[ light.id ] !== undefined ) { 21576 21577 return lights[ light.id ]; 21578 21579 } 21580 21581 let uniforms; 21582 21583 switch ( light.type ) { 21584 21585 case 'DirectionalLight': 21586 uniforms = { 21587 shadowBias: 0, 21588 shadowNormalBias: 0, 21589 shadowRadius: 1, 21590 shadowMapSize: new Vector2() 21591 }; 21592 break; 21593 21594 case 'SpotLight': 21595 uniforms = { 21596 shadowBias: 0, 21597 shadowNormalBias: 0, 21598 shadowRadius: 1, 21599 shadowMapSize: new Vector2() 21600 }; 21601 break; 21602 21603 case 'PointLight': 21604 uniforms = { 21605 shadowBias: 0, 21606 shadowNormalBias: 0, 21607 shadowRadius: 1, 21608 shadowMapSize: new Vector2(), 21609 shadowCameraNear: 1, 21610 shadowCameraFar: 1000 21611 }; 21612 break; 21613 21614 // TODO (abelnation): set RectAreaLight shadow uniforms 21615 21616 } 21617 21618 lights[ light.id ] = uniforms; 21619 21620 return uniforms; 21621 21622 } 21623 21624 }; 21625 21626} 21627 21628 21629 21630let nextVersion = 0; 21631 21632function shadowCastingAndTexturingLightsFirst( lightA, lightB ) { 21633 21634 return ( lightB.castShadow ? 2 : 0 ) - ( lightA.castShadow ? 2 : 0 ) + ( lightB.map ? 1 : 0 ) - ( lightA.map ? 1 : 0 ); 21635 21636} 21637 21638function WebGLLights( extensions, capabilities ) { 21639 21640 const cache = new UniformsCache(); 21641 21642 const shadowCache = ShadowUniformsCache(); 21643 21644 const state = { 21645 21646 version: 0, 21647 21648 hash: { 21649 directionalLength: - 1, 21650 pointLength: - 1, 21651 spotLength: - 1, 21652 rectAreaLength: - 1, 21653 hemiLength: - 1, 21654 21655 numDirectionalShadows: - 1, 21656 numPointShadows: - 1, 21657 numSpotShadows: - 1, 21658 numSpotMaps: - 1, 21659 21660 numLightProbes: - 1 21661 }, 21662 21663 ambient: [ 0, 0, 0 ], 21664 probe: [], 21665 directional: [], 21666 directionalShadow: [], 21667 directionalShadowMap: [], 21668 directionalShadowMatrix: [], 21669 spot: [], 21670 spotLightMap: [], 21671 spotShadow: [], 21672 spotShadowMap: [], 21673 spotLightMatrix: [], 21674 rectArea: [], 21675 rectAreaLTC1: null, 21676 rectAreaLTC2: null, 21677 point: [], 21678 pointShadow: [], 21679 pointShadowMap: [], 21680 pointShadowMatrix: [], 21681 hemi: [], 21682 numSpotLightShadowsWithMaps: 0, 21683 numLightProbes: 0 21684 21685 }; 21686 21687 for ( let i = 0; i < 9; i ++ ) state.probe.push( new Vector3() ); 21688 21689 const vector3 = new Vector3(); 21690 const matrix4 = new Matrix4(); 21691 const matrix42 = new Matrix4(); 21692 21693 function setup( lights, useLegacyLights ) { 21694 21695 let r = 0, g = 0, b = 0; 21696 21697 for ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 ); 21698 21699 let directionalLength = 0; 21700 let pointLength = 0; 21701 let spotLength = 0; 21702 let rectAreaLength = 0; 21703 let hemiLength = 0; 21704 21705 let numDirectionalShadows = 0; 21706 let numPointShadows = 0; 21707 let numSpotShadows = 0; 21708 let numSpotMaps = 0; 21709 let numSpotShadowsWithMaps = 0; 21710 21711 let numLightProbes = 0; 21712 21713 // ordering : [shadow casting + map texturing, map texturing, shadow casting, none ] 21714 lights.sort( shadowCastingAndTexturingLightsFirst ); 21715 21716 // artist-friendly light intensity scaling factor 21717 const scaleFactor = ( useLegacyLights === true ) ? Math.PI : 1; 21718 21719 for ( let i = 0, l = lights.length; i < l; i ++ ) { 21720 21721 const light = lights[ i ]; 21722 21723 const color = light.color; 21724 const intensity = light.intensity; 21725 const distance = light.distance; 21726 21727 const shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null; 21728 21729 if ( light.isAmbientLight ) { 21730 21731 r += color.r * intensity * scaleFactor; 21732 g += color.g * intensity * scaleFactor; 21733 b += color.b * intensity * scaleFactor; 21734 21735 } else if ( light.isLightProbe ) { 21736 21737 for ( let j = 0; j < 9; j ++ ) { 21738 21739 state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity ); 21740 21741 } 21742 21743 numLightProbes ++; 21744 21745 } else if ( light.isDirectionalLight ) { 21746 21747 const uniforms = cache.get( light ); 21748 21749 uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor ); 21750 21751 if ( light.castShadow ) { 21752 21753 const shadow = light.shadow; 21754 21755 const shadowUniforms = shadowCache.get( light ); 21756 21757 shadowUniforms.shadowBias = shadow.bias; 21758 shadowUniforms.shadowNormalBias = shadow.normalBias; 21759 shadowUniforms.shadowRadius = shadow.radius; 21760 shadowUniforms.shadowMapSize = shadow.mapSize; 21761 21762 state.directionalShadow[ directionalLength ] = shadowUniforms; 21763 state.directionalShadowMap[ directionalLength ] = shadowMap; 21764 state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix; 21765 21766 numDirectionalShadows ++; 21767 21768 } 21769 21770 state.directional[ directionalLength ] = uniforms; 21771 21772 directionalLength ++; 21773 21774 } else if ( light.isSpotLight ) { 21775 21776 const uniforms = cache.get( light ); 21777 21778 uniforms.position.setFromMatrixPosition( light.matrixWorld ); 21779 21780 uniforms.color.copy( color ).multiplyScalar( intensity * scaleFactor ); 21781 uniforms.distance = distance; 21782 21783 uniforms.coneCos = Math.cos( light.angle ); 21784 uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) ); 21785 uniforms.decay = light.decay; 21786 21787 state.spot[ spotLength ] = uniforms; 21788 21789 const shadow = light.shadow; 21790 21791 if ( light.map ) { 21792 21793 state.spotLightMap[ numSpotMaps ] = light.map; 21794 numSpotMaps ++; 21795 21796 // make sure the lightMatrix is up to date 21797 // TODO : do it if required only 21798 shadow.updateMatrices( light ); 21799 21800 if ( light.castShadow ) numSpotShadowsWithMaps ++; 21801 21802 } 21803 21804 state.spotLightMatrix[ spotLength ] = shadow.matrix; 21805 21806 if ( light.castShadow ) { 21807 21808 const shadowUniforms = shadowCache.get( light ); 21809 21810 shadowUniforms.shadowBias = shadow.bias; 21811 shadowUniforms.shadowNormalBias = shadow.normalBias; 21812 shadowUniforms.shadowRadius = shadow.radius; 21813 shadowUniforms.shadowMapSize = shadow.mapSize; 21814 21815 state.spotShadow[ spotLength ] = shadowUniforms; 21816 state.spotShadowMap[ spotLength ] = shadowMap; 21817 21818 numSpotShadows ++; 21819 21820 } 21821 21822 spotLength ++; 21823 21824 } else if ( light.isRectAreaLight ) { 21825 21826 const uniforms = cache.get( light ); 21827 21828 uniforms.color.copy( color ).multiplyScalar( intensity ); 21829 21830 uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); 21831 uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); 21832 21833 state.rectArea[ rectAreaLength ] = uniforms; 21834 21835 rectAreaLength ++; 21836 21837 } else if ( light.isPointLight ) { 21838 21839 const uniforms = cache.get( light ); 21840 21841 uniforms.color.copy( light.color ).multiplyScalar( light.intensity * scaleFactor ); 21842 uniforms.distance = light.distance; 21843 uniforms.decay = light.decay; 21844 21845 if ( light.castShadow ) { 21846 21847 const shadow = light.shadow; 21848 21849 const shadowUniforms = shadowCache.get( light ); 21850 21851 shadowUniforms.shadowBias = shadow.bias; 21852 shadowUniforms.shadowNormalBias = shadow.normalBias; 21853 shadowUniforms.shadowRadius = shadow.radius; 21854 shadowUniforms.shadowMapSize = shadow.mapSize; 21855 shadowUniforms.shadowCameraNear = shadow.camera.near; 21856 shadowUniforms.shadowCameraFar = shadow.camera.far; 21857 21858 state.pointShadow[ pointLength ] = shadowUniforms; 21859 state.pointShadowMap[ pointLength ] = shadowMap; 21860 state.pointShadowMatrix[ pointLength ] = light.shadow.matrix; 21861 21862 numPointShadows ++; 21863 21864 } 21865 21866 state.point[ pointLength ] = uniforms; 21867 21868 pointLength ++; 21869 21870 } else if ( light.isHemisphereLight ) { 21871 21872 const uniforms = cache.get( light ); 21873 21874 uniforms.skyColor.copy( light.color ).multiplyScalar( intensity * scaleFactor ); 21875 uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity * scaleFactor ); 21876 21877 state.hemi[ hemiLength ] = uniforms; 21878 21879 hemiLength ++; 21880 21881 } 21882 21883 } 21884 21885 if ( rectAreaLength > 0 ) { 21886 21887 if ( capabilities.isWebGL2 ) { 21888 21889 // WebGL 2 21890 21891 if ( extensions.has( 'OES_texture_float_linear' ) === true ) { 21892 21893 state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1; 21894 state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2; 21895 21896 } else { 21897 21898 state.rectAreaLTC1 = UniformsLib.LTC_HALF_1; 21899 state.rectAreaLTC2 = UniformsLib.LTC_HALF_2; 21900 21901 } 21902 21903 } else { 21904 21905 // WebGL 1 21906 21907 if ( extensions.has( 'OES_texture_float_linear' ) === true ) { 21908 21909 state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1; 21910 state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2; 21911 21912 } else if ( extensions.has( 'OES_texture_half_float_linear' ) === true ) { 21913 21914 state.rectAreaLTC1 = UniformsLib.LTC_HALF_1; 21915 state.rectAreaLTC2 = UniformsLib.LTC_HALF_2; 21916 21917 } else { 21918 21919 console.error( 'THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.' ); 21920 21921 } 21922 21923 } 21924 21925 } 21926 21927 state.ambient[ 0 ] = r; 21928 state.ambient[ 1 ] = g; 21929 state.ambient[ 2 ] = b; 21930 21931 const hash = state.hash; 21932 21933 if ( hash.directionalLength !== directionalLength || 21934 hash.pointLength !== pointLength || 21935 hash.spotLength !== spotLength || 21936 hash.rectAreaLength !== rectAreaLength || 21937 hash.hemiLength !== hemiLength || 21938 hash.numDirectionalShadows !== numDirectionalShadows || 21939 hash.numPointShadows !== numPointShadows || 21940 hash.numSpotShadows !== numSpotShadows || 21941 hash.numSpotMaps !== numSpotMaps || 21942 hash.numLightProbes !== numLightProbes ) { 21943 21944 state.directional.length = directionalLength; 21945 state.spot.length = spotLength; 21946 state.rectArea.length = rectAreaLength; 21947 state.point.length = pointLength; 21948 state.hemi.length = hemiLength; 21949 21950 state.directionalShadow.length = numDirectionalShadows; 21951 state.directionalShadowMap.length = numDirectionalShadows; 21952 state.pointShadow.length = numPointShadows; 21953 state.pointShadowMap.length = numPointShadows; 21954 state.spotShadow.length = numSpotShadows; 21955 state.spotShadowMap.length = numSpotShadows; 21956 state.directionalShadowMatrix.length = numDirectionalShadows; 21957 state.pointShadowMatrix.length = numPointShadows; 21958 state.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps; 21959 state.spotLightMap.length = numSpotMaps; 21960 state.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps; 21961 state.numLightProbes = numLightProbes; 21962 21963 hash.directionalLength = directionalLength; 21964 hash.pointLength = pointLength; 21965 hash.spotLength = spotLength; 21966 hash.rectAreaLength = rectAreaLength; 21967 hash.hemiLength = hemiLength; 21968 21969 hash.numDirectionalShadows = numDirectionalShadows; 21970 hash.numPointShadows = numPointShadows; 21971 hash.numSpotShadows = numSpotShadows; 21972 hash.numSpotMaps = numSpotMaps; 21973 21974 hash.numLightProbes = numLightProbes; 21975 21976 state.version = nextVersion ++; 21977 21978 } 21979 21980 } 21981 21982 function setupView( lights, camera ) { 21983 21984 let directionalLength = 0; 21985 let pointLength = 0; 21986 let spotLength = 0; 21987 let rectAreaLength = 0; 21988 let hemiLength = 0; 21989 21990 const viewMatrix = camera.matrixWorldInverse; 21991 21992 for ( let i = 0, l = lights.length; i < l; i ++ ) { 21993 21994 const light = lights[ i ]; 21995 21996 if ( light.isDirectionalLight ) { 21997 21998 const uniforms = state.directional[ directionalLength ]; 21999 22000 uniforms.direction.setFromMatrixPosition( light.matrixWorld ); 22001 vector3.setFromMatrixPosition( light.target.matrixWorld ); 22002 uniforms.direction.sub( vector3 ); 22003 uniforms.direction.transformDirection( viewMatrix ); 22004 22005 directionalLength ++; 22006 22007 } else if ( light.isSpotLight ) { 22008 22009 const uniforms = state.spot[ spotLength ]; 22010 22011 uniforms.position.setFromMatrixPosition( light.matrixWorld ); 22012 uniforms.position.applyMatrix4( viewMatrix ); 22013 22014 uniforms.direction.setFromMatrixPosition( light.matrixWorld ); 22015 vector3.setFromMatrixPosition( light.target.matrixWorld ); 22016 uniforms.direction.sub( vector3 ); 22017 uniforms.direction.transformDirection( viewMatrix ); 22018 22019 spotLength ++; 22020 22021 } else if ( light.isRectAreaLight ) { 22022 22023 const uniforms = state.rectArea[ rectAreaLength ]; 22024 22025 uniforms.position.setFromMatrixPosition( light.matrixWorld ); 22026 uniforms.position.applyMatrix4( viewMatrix ); 22027 22028 // extract local rotation of light to derive width/height half vectors 22029 matrix42.identity(); 22030 matrix4.copy( light.matrixWorld ); 22031 matrix4.premultiply( viewMatrix ); 22032 matrix42.extractRotation( matrix4 ); 22033 22034 uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 ); 22035 uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 ); 22036 22037 uniforms.halfWidth.applyMatrix4( matrix42 ); 22038 uniforms.halfHeight.applyMatrix4( matrix42 ); 22039 22040 rectAreaLength ++; 22041 22042 } else if ( light.isPointLight ) { 22043 22044 const uniforms = state.point[ pointLength ]; 22045 22046 uniforms.position.setFromMatrixPosition( light.matrixWorld ); 22047 uniforms.position.applyMatrix4( viewMatrix ); 22048 22049 pointLength ++; 22050 22051 } else if ( light.isHemisphereLight ) { 22052 22053 const uniforms = state.hemi[ hemiLength ]; 22054 22055 uniforms.direction.setFromMatrixPosition( light.matrixWorld ); 22056 uniforms.direction.transformDirection( viewMatrix ); 22057 22058 hemiLength ++; 22059 22060 } 22061 22062 } 22063 22064 } 22065 22066 return { 22067 setup: setup, 22068 setupView: setupView, 22069 state: state 22070 }; 22071 22072} 22073 22074function WebGLRenderState( extensions, capabilities ) { 22075 22076 const lights = new WebGLLights( extensions, capabilities ); 22077 22078 const lightsArray = []; 22079 const shadowsArray = []; 22080 22081 function init() { 22082 22083 lightsArray.length = 0; 22084 shadowsArray.length = 0; 22085 22086 } 22087 22088 function pushLight( light ) { 22089 22090 lightsArray.push( light ); 22091 22092 } 22093 22094 function pushShadow( shadowLight ) { 22095 22096 shadowsArray.push( shadowLight ); 22097 22098 } 22099 22100 function setupLights( useLegacyLights ) { 22101 22102 lights.setup( lightsArray, useLegacyLights ); 22103 22104 } 22105 22106 function setupLightsView( camera ) { 22107 22108 lights.setupView( lightsArray, camera ); 22109 22110 } 22111 22112 const state = { 22113 lightsArray: lightsArray, 22114 shadowsArray: shadowsArray, 22115 22116 lights: lights 22117 }; 22118 22119 return { 22120 init: init, 22121 state: state, 22122 setupLights: setupLights, 22123 setupLightsView: setupLightsView, 22124 22125 pushLight: pushLight, 22126 pushShadow: pushShadow 22127 }; 22128 22129} 22130 22131function WebGLRenderStates( extensions, capabilities ) { 22132 22133 let renderStates = new WeakMap(); 22134 22135 function get( scene, renderCallDepth = 0 ) { 22136 22137 const renderStateArray = renderStates.get( scene ); 22138 let renderState; 22139 22140 if ( renderStateArray === undefined ) { 22141 22142 renderState = new WebGLRenderState( extensions, capabilities ); 22143 renderStates.set( scene, [ renderState ] ); 22144 22145 } else { 22146 22147 if ( renderCallDepth >= renderStateArray.length ) { 22148 22149 renderState = new WebGLRenderState( extensions, capabilities ); 22150 renderStateArray.push( renderState ); 22151 22152 } else { 22153 22154 renderState = renderStateArray[ renderCallDepth ]; 22155 22156 } 22157 22158 } 22159 22160 return renderState; 22161 22162 } 22163 22164 function dispose() { 22165 22166 renderStates = new WeakMap(); 22167 22168 } 22169 22170 return { 22171 get: get, 22172 dispose: dispose 22173 }; 22174 22175} 22176 22177class MeshDepthMaterial extends Material { 22178 22179 constructor( parameters ) { 22180 22181 super(); 22182 22183 this.isMeshDepthMaterial = true; 22184 22185 this.type = 'MeshDepthMaterial'; 22186 22187 this.depthPacking = BasicDepthPacking; 22188 22189 this.map = null; 22190 22191 this.alphaMap = null; 22192 22193 this.displacementMap = null; 22194 this.displacementScale = 1; 22195 this.displacementBias = 0; 22196 22197 this.wireframe = false; 22198 this.wireframeLinewidth = 1; 22199 22200 this.setValues( parameters ); 22201 22202 } 22203 22204 copy( source ) { 22205 22206 super.copy( source ); 22207 22208 this.depthPacking = source.depthPacking; 22209 22210 this.map = source.map; 22211 22212 this.alphaMap = source.alphaMap; 22213 22214 this.displacementMap = source.displacementMap; 22215 this.displacementScale = source.displacementScale; 22216 this.displacementBias = source.displacementBias; 22217 22218 this.wireframe = source.wireframe; 22219 this.wireframeLinewidth = source.wireframeLinewidth; 22220 22221 return this; 22222 22223 } 22224 22225} 22226 22227class MeshDistanceMaterial extends Material { 22228 22229 constructor( parameters ) { 22230 22231 super(); 22232 22233 this.isMeshDistanceMaterial = true; 22234 22235 this.type = 'MeshDistanceMaterial'; 22236 22237 this.map = null; 22238 22239 this.alphaMap = null; 22240 22241 this.displacementMap = null; 22242 this.displacementScale = 1; 22243 this.displacementBias = 0; 22244 22245 this.setValues( parameters ); 22246 22247 } 22248 22249 copy( source ) { 22250 22251 super.copy( source ); 22252 22253 this.map = source.map; 22254 22255 this.alphaMap = source.alphaMap; 22256 22257 this.displacementMap = source.displacementMap; 22258 this.displacementScale = source.displacementScale; 22259 this.displacementBias = source.displacementBias; 22260 22261 return this; 22262 22263 } 22264 22265} 22266 22267const vertex = "void main() {\n\tgl_Position = vec4( position, 1.0 );\n}"; 22268 22269const fragment = "uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\n#include <packing>\nvoid main() {\n\tconst float samples = float( VSM_SAMPLES );\n\tfloat mean = 0.0;\n\tfloat squared_mean = 0.0;\n\tfloat uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 );\n\tfloat uvStart = samples <= 1.0 ? 0.0 : - 1.0;\n\tfor ( float i = 0.0; i < samples; i ++ ) {\n\t\tfloat uvOffset = uvStart + i * uvStride;\n\t\t#ifdef HORIZONTAL_PASS\n\t\t\tvec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ) );\n\t\t\tmean += distribution.x;\n\t\t\tsquared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n\t\t#else\n\t\t\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ) );\n\t\t\tmean += depth;\n\t\t\tsquared_mean += depth * depth;\n\t\t#endif\n\t}\n\tmean = mean / samples;\n\tsquared_mean = squared_mean / samples;\n\tfloat std_dev = sqrt( squared_mean - mean * mean );\n\tgl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}"; 22270 22271function WebGLShadowMap( _renderer, _objects, _capabilities ) { 22272 22273 let _frustum = new Frustum(); 22274 22275 const _shadowMapSize = new Vector2(), 22276 _viewportSize = new Vector2(), 22277 22278 _viewport = new Vector4(), 22279 22280 _depthMaterial = new MeshDepthMaterial( { depthPacking: RGBADepthPacking } ), 22281 _distanceMaterial = new MeshDistanceMaterial(), 22282 22283 _materialCache = {}, 22284 22285 _maxTextureSize = _capabilities.maxTextureSize; 22286 22287 const shadowSide = { [ FrontSide ]: BackSide, [ BackSide ]: FrontSide, [ DoubleSide ]: DoubleSide }; 22288 22289 const shadowMaterialVertical = new ShaderMaterial( { 22290 defines: { 22291 VSM_SAMPLES: 8 22292 }, 22293 uniforms: { 22294 shadow_pass: { value: null }, 22295 resolution: { value: new Vector2() }, 22296 radius: { value: 4.0 } 22297 }, 22298 22299 vertexShader: vertex, 22300 fragmentShader: fragment 22301 22302 } ); 22303 22304 const shadowMaterialHorizontal = shadowMaterialVertical.clone(); 22305 shadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1; 22306 22307 const fullScreenTri = new BufferGeometry(); 22308 fullScreenTri.setAttribute( 22309 'position', 22310 new BufferAttribute( 22311 new Float32Array( [ - 1, - 1, 0.5, 3, - 1, 0.5, - 1, 3, 0.5 ] ), 22312 3 22313 ) 22314 ); 22315 22316 const fullScreenMesh = new Mesh( fullScreenTri, shadowMaterialVertical ); 22317 22318 const scope = this; 22319 22320 this.enabled = false; 22321 22322 this.autoUpdate = true; 22323 this.needsUpdate = false; 22324 22325 this.type = PCFShadowMap; 22326 let _previousType = this.type; 22327 22328 this.render = function ( lights, scene, camera ) { 22329 22330 if ( scope.enabled === false ) return; 22331 if ( scope.autoUpdate === false && scope.needsUpdate === false ) return; 22332 22333 if ( lights.length === 0 ) return; 22334 22335 const currentRenderTarget = _renderer.getRenderTarget(); 22336 const activeCubeFace = _renderer.getActiveCubeFace(); 22337 const activeMipmapLevel = _renderer.getActiveMipmapLevel(); 22338 22339 const _state = _renderer.state; 22340 22341 // Set GL state for depth map. 22342 _state.setBlending( NoBlending ); 22343 _state.buffers.color.setClear( 1, 1, 1, 1 ); 22344 _state.buffers.depth.setTest( true ); 22345 _state.setScissorTest( false ); 22346 22347 // check for shadow map type changes 22348 22349 const toVSM = ( _previousType !== VSMShadowMap && this.type === VSMShadowMap ); 22350 const fromVSM = ( _previousType === VSMShadowMap && this.type !== VSMShadowMap ); 22351 22352 // render depth map 22353 22354 for ( let i = 0, il = lights.length; i < il; i ++ ) { 22355 22356 const light = lights[ i ]; 22357 const shadow = light.shadow; 22358 22359 if ( shadow === undefined ) { 22360 22361 console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' ); 22362 continue; 22363 22364 } 22365 22366 if ( shadow.autoUpdate === false && shadow.needsUpdate === false ) continue; 22367 22368 _shadowMapSize.copy( shadow.mapSize ); 22369 22370 const shadowFrameExtents = shadow.getFrameExtents(); 22371 22372 _shadowMapSize.multiply( shadowFrameExtents ); 22373 22374 _viewportSize.copy( shadow.mapSize ); 22375 22376 if ( _shadowMapSize.x > _maxTextureSize || _shadowMapSize.y > _maxTextureSize ) { 22377 22378 if ( _shadowMapSize.x > _maxTextureSize ) { 22379 22380 _viewportSize.x = Math.floor( _maxTextureSize / shadowFrameExtents.x ); 22381 _shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x; 22382 shadow.mapSize.x = _viewportSize.x; 22383 22384 } 22385 22386 if ( _shadowMapSize.y > _maxTextureSize ) { 22387 22388 _viewportSize.y = Math.floor( _maxTextureSize / shadowFrameExtents.y ); 22389 _shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y; 22390 shadow.mapSize.y = _viewportSize.y; 22391 22392 } 22393 22394 } 22395 22396 if ( shadow.map === null || toVSM === true || fromVSM === true ) { 22397 22398 const pars = ( this.type !== VSMShadowMap ) ? { minFilter: NearestFilter, magFilter: NearestFilter } : {}; 22399 22400 if ( shadow.map !== null ) { 22401 22402 shadow.map.dispose(); 22403 22404 } 22405 22406 shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); 22407 shadow.map.texture.name = light.name + '.shadowMap'; 22408 22409 shadow.camera.updateProjectionMatrix(); 22410 22411 } 22412 22413 _renderer.setRenderTarget( shadow.map ); 22414 _renderer.clear(); 22415 22416 const viewportCount = shadow.getViewportCount(); 22417 22418 for ( let vp = 0; vp < viewportCount; vp ++ ) { 22419 22420 const viewport = shadow.getViewport( vp ); 22421 22422 _viewport.set( 22423 _viewportSize.x * viewport.x, 22424 _viewportSize.y * viewport.y, 22425 _viewportSize.x * viewport.z, 22426 _viewportSize.y * viewport.w 22427 ); 22428 22429 _state.viewport( _viewport ); 22430 22431 shadow.updateMatrices( light, vp ); 22432 22433 _frustum = shadow.getFrustum(); 22434 22435 renderObject( scene, camera, shadow.camera, light, this.type ); 22436 22437 } 22438 22439 // do blur pass for VSM 22440 22441 if ( shadow.isPointLightShadow !== true && this.type === VSMShadowMap ) { 22442 22443 VSMPass( shadow, camera ); 22444 22445 } 22446 22447 shadow.needsUpdate = false; 22448 22449 } 22450 22451 _previousType = this.type; 22452 22453 scope.needsUpdate = false; 22454 22455 _renderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel ); 22456 22457 }; 22458 22459 function VSMPass( shadow, camera ) { 22460 22461 const geometry = _objects.update( fullScreenMesh ); 22462 22463 if ( shadowMaterialVertical.defines.VSM_SAMPLES !== shadow.blurSamples ) { 22464 22465 shadowMaterialVertical.defines.VSM_SAMPLES = shadow.blurSamples; 22466 shadowMaterialHorizontal.defines.VSM_SAMPLES = shadow.blurSamples; 22467 22468 shadowMaterialVertical.needsUpdate = true; 22469 shadowMaterialHorizontal.needsUpdate = true; 22470 22471 } 22472 22473 if ( shadow.mapPass === null ) { 22474 22475 shadow.mapPass = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y ); 22476 22477 } 22478 22479 // vertical pass 22480 22481 shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture; 22482 shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize; 22483 shadowMaterialVertical.uniforms.radius.value = shadow.radius; 22484 _renderer.setRenderTarget( shadow.mapPass ); 22485 _renderer.clear(); 22486 _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null ); 22487 22488 // horizontal pass 22489 22490 shadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture; 22491 shadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize; 22492 shadowMaterialHorizontal.uniforms.radius.value = shadow.radius; 22493 _renderer.setRenderTarget( shadow.map ); 22494 _renderer.clear(); 22495 _renderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null ); 22496 22497 } 22498 22499 function getDepthMaterial( object, material, light, type ) { 22500 22501 let result = null; 22502 22503 const customMaterial = ( light.isPointLight === true ) ? object.customDistanceMaterial : object.customDepthMaterial; 22504 22505 if ( customMaterial !== undefined ) { 22506 22507 result = customMaterial; 22508 22509 } else { 22510 22511 result = ( light.isPointLight === true ) ? _distanceMaterial : _depthMaterial; 22512 22513 if ( ( _renderer.localClippingEnabled && material.clipShadows === true && Array.isArray( material.clippingPlanes ) && material.clippingPlanes.length !== 0 ) || 22514 ( material.displacementMap && material.displacementScale !== 0 ) || 22515 ( material.alphaMap && material.alphaTest > 0 ) || 22516 ( material.map && material.alphaTest > 0 ) ) { 22517 22518 // in this case we need a unique material instance reflecting the 22519 // appropriate state 22520 22521 const keyA = result.uuid, keyB = material.uuid; 22522 22523 let materialsForVariant = _materialCache[ keyA ]; 22524 22525 if ( materialsForVariant === undefined ) { 22526 22527 materialsForVariant = {}; 22528 _materialCache[ keyA ] = materialsForVariant; 22529 22530 } 22531 22532 let cachedMaterial = materialsForVariant[ keyB ]; 22533 22534 if ( cachedMaterial === undefined ) { 22535 22536 cachedMaterial = result.clone(); 22537 materialsForVariant[ keyB ] = cachedMaterial; 22538 material.addEventListener( 'dispose', onMaterialDispose ); 22539 22540 } 22541 22542 result = cachedMaterial; 22543 22544 } 22545 22546 } 22547 22548 result.visible = material.visible; 22549 result.wireframe = material.wireframe; 22550 22551 if ( type === VSMShadowMap ) { 22552 22553 result.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side; 22554 22555 } else { 22556 22557 result.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ]; 22558 22559 } 22560 22561 result.alphaMap = material.alphaMap; 22562 result.alphaTest = material.alphaTest; 22563 result.map = material.map; 22564 22565 result.clipShadows = material.clipShadows; 22566 result.clippingPlanes = material.clippingPlanes; 22567 result.clipIntersection = material.clipIntersection; 22568 22569 result.displacementMap = material.displacementMap; 22570 result.displacementScale = material.displacementScale; 22571 result.displacementBias = material.displacementBias; 22572 22573 result.wireframeLinewidth = material.wireframeLinewidth; 22574 result.linewidth = material.linewidth; 22575 22576 if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) { 22577 22578 const materialProperties = _renderer.properties.get( result ); 22579 materialProperties.light = light; 22580 22581 } 22582 22583 return result; 22584 22585 } 22586 22587 function renderObject( object, camera, shadowCamera, light, type ) { 22588 22589 if ( object.visible === false ) return; 22590 22591 const visible = object.layers.test( camera.layers ); 22592 22593 if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) { 22594 22595 if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) { 22596 22597 object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); 22598 22599 const geometry = _objects.update( object ); 22600 const material = object.material; 22601 22602 if ( Array.isArray( material ) ) { 22603 22604 const groups = geometry.groups; 22605 22606 for ( let k = 0, kl = groups.length; k < kl; k ++ ) { 22607 22608 const group = groups[ k ]; 22609 const groupMaterial = material[ group.materialIndex ]; 22610 22611 if ( groupMaterial && groupMaterial.visible ) { 22612 22613 const depthMaterial = getDepthMaterial( object, groupMaterial, light, type ); 22614 22615 object.onBeforeShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, group ); 22616 22617 _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group ); 22618 22619 object.onAfterShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, group ); 22620 22621 } 22622 22623 } 22624 22625 } else if ( material.visible ) { 22626 22627 const depthMaterial = getDepthMaterial( object, material, light, type ); 22628 22629 object.onBeforeShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, null ); 22630 22631 _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null ); 22632 22633 object.onAfterShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, null ); 22634 22635 } 22636 22637 } 22638 22639 } 22640 22641 const children = object.children; 22642 22643 for ( let i = 0, l = children.length; i < l; i ++ ) { 22644 22645 renderObject( children[ i ], camera, shadowCamera, light, type ); 22646 22647 } 22648 22649 } 22650 22651 function onMaterialDispose( event ) { 22652 22653 const material = event.target; 22654 22655 material.removeEventListener( 'dispose', onMaterialDispose ); 22656 22657 // make sure to remove the unique distance/depth materials used for shadow map rendering 22658 22659 for ( const id in _materialCache ) { 22660 22661 const cache = _materialCache[ id ]; 22662 22663 const uuid = event.target.uuid; 22664 22665 if ( uuid in cache ) { 22666 22667 const shadowMaterial = cache[ uuid ]; 22668 shadowMaterial.dispose(); 22669 delete cache[ uuid ]; 22670 22671 } 22672 22673 } 22674 22675 } 22676 22677} 22678 22679function WebGLState( gl, extensions, capabilities ) { 22680 22681 const isWebGL2 = capabilities.isWebGL2; 22682 22683 function ColorBuffer() { 22684 22685 let locked = false; 22686 22687 const color = new Vector4(); 22688 let currentColorMask = null; 22689 const currentColorClear = new Vector4( 0, 0, 0, 0 ); 22690 22691 return { 22692 22693 setMask: function ( colorMask ) { 22694 22695 if ( currentColorMask !== colorMask && ! locked ) { 22696 22697 gl.colorMask( colorMask, colorMask, colorMask, colorMask ); 22698 currentColorMask = colorMask; 22699 22700 } 22701 22702 }, 22703 22704 setLocked: function ( lock ) { 22705 22706 locked = lock; 22707 22708 }, 22709 22710 setClear: function ( r, g, b, a, premultipliedAlpha ) { 22711 22712 if ( premultipliedAlpha === true ) { 22713 22714 r *= a; g *= a; b *= a; 22715 22716 } 22717 22718 color.set( r, g, b, a ); 22719 22720 if ( currentColorClear.equals( color ) === false ) { 22721 22722 gl.clearColor( r, g, b, a ); 22723 currentColorClear.copy( color ); 22724 22725 } 22726 22727 }, 22728 22729 reset: function () { 22730 22731 locked = false; 22732 22733 currentColorMask = null; 22734 currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state 22735 22736 } 22737 22738 }; 22739 22740 } 22741 22742 function DepthBuffer() { 22743 22744 let locked = false; 22745 22746 let currentDepthMask = null; 22747 let currentDepthFunc = null; 22748 let currentDepthClear = null; 22749 22750 return { 22751 22752 setTest: function ( depthTest ) { 22753 22754 if ( depthTest ) { 22755 22756 enable( gl.DEPTH_TEST ); 22757 22758 } else { 22759 22760 disable( gl.DEPTH_TEST ); 22761 22762 } 22763 22764 }, 22765 22766 setMask: function ( depthMask ) { 22767 22768 if ( currentDepthMask !== depthMask && ! locked ) { 22769 22770 gl.depthMask( depthMask ); 22771 currentDepthMask = depthMask; 22772 22773 } 22774 22775 }, 22776 22777 setFunc: function ( depthFunc ) { 22778 22779 if ( currentDepthFunc !== depthFunc ) { 22780 22781 switch ( depthFunc ) { 22782 22783 case NeverDepth: 22784 22785 gl.depthFunc( gl.NEVER ); 22786 break; 22787 22788 case AlwaysDepth: 22789 22790 gl.depthFunc( gl.ALWAYS ); 22791 break; 22792 22793 case LessDepth: 22794 22795 gl.depthFunc( gl.LESS ); 22796 break; 22797 22798 case LessEqualDepth: 22799 22800 gl.depthFunc( gl.LEQUAL ); 22801 break; 22802 22803 case EqualDepth: 22804 22805 gl.depthFunc( gl.EQUAL ); 22806 break; 22807 22808 case GreaterEqualDepth: 22809 22810 gl.depthFunc( gl.GEQUAL ); 22811 break; 22812 22813 case GreaterDepth: 22814 22815 gl.depthFunc( gl.GREATER ); 22816 break; 22817 22818 case NotEqualDepth: 22819 22820 gl.depthFunc( gl.NOTEQUAL ); 22821 break; 22822 22823 default: 22824 22825 gl.depthFunc( gl.LEQUAL ); 22826 22827 } 22828 22829 currentDepthFunc = depthFunc; 22830 22831 } 22832 22833 }, 22834 22835 setLocked: function ( lock ) { 22836 22837 locked = lock; 22838 22839 }, 22840 22841 setClear: function ( depth ) { 22842 22843 if ( currentDepthClear !== depth ) { 22844 22845 gl.clearDepth( depth ); 22846 currentDepthClear = depth; 22847 22848 } 22849 22850 }, 22851 22852 reset: function () { 22853 22854 locked = false; 22855 22856 currentDepthMask = null; 22857 currentDepthFunc = null; 22858 currentDepthClear = null; 22859 22860 } 22861 22862 }; 22863 22864 } 22865 22866 function StencilBuffer() { 22867 22868 let locked = false; 22869 22870 let currentStencilMask = null; 22871 let currentStencilFunc = null; 22872 let currentStencilRef = null; 22873 let currentStencilFuncMask = null; 22874 let currentStencilFail = null; 22875 let currentStencilZFail = null; 22876 let currentStencilZPass = null; 22877 let currentStencilClear = null; 22878 22879 return { 22880 22881 setTest: function ( stencilTest ) { 22882 22883 if ( ! locked ) { 22884 22885 if ( stencilTest ) { 22886 22887 enable( gl.STENCIL_TEST ); 22888 22889 } else { 22890 22891 disable( gl.STENCIL_TEST ); 22892 22893 } 22894 22895 } 22896 22897 }, 22898 22899 setMask: function ( stencilMask ) { 22900 22901 if ( currentStencilMask !== stencilMask && ! locked ) { 22902 22903 gl.stencilMask( stencilMask ); 22904 currentStencilMask = stencilMask; 22905 22906 } 22907 22908 }, 22909 22910 setFunc: function ( stencilFunc, stencilRef, stencilMask ) { 22911 22912 if ( currentStencilFunc !== stencilFunc || 22913 currentStencilRef !== stencilRef || 22914 currentStencilFuncMask !== stencilMask ) { 22915 22916 gl.stencilFunc( stencilFunc, stencilRef, stencilMask ); 22917 22918 currentStencilFunc = stencilFunc; 22919 currentStencilRef = stencilRef; 22920 currentStencilFuncMask = stencilMask; 22921 22922 } 22923 22924 }, 22925 22926 setOp: function ( stencilFail, stencilZFail, stencilZPass ) { 22927 22928 if ( currentStencilFail !== stencilFail || 22929 currentStencilZFail !== stencilZFail || 22930 currentStencilZPass !== stencilZPass ) { 22931 22932 gl.stencilOp( stencilFail, stencilZFail, stencilZPass ); 22933 22934 currentStencilFail = stencilFail; 22935 currentStencilZFail = stencilZFail; 22936 currentStencilZPass = stencilZPass; 22937 22938 } 22939 22940 }, 22941 22942 setLocked: function ( lock ) { 22943 22944 locked = lock; 22945 22946 }, 22947 22948 setClear: function ( stencil ) { 22949 22950 if ( currentStencilClear !== stencil ) { 22951 22952 gl.clearStencil( stencil ); 22953 currentStencilClear = stencil; 22954 22955 } 22956 22957 }, 22958 22959 reset: function () { 22960 22961 locked = false; 22962 22963 currentStencilMask = null; 22964 currentStencilFunc = null; 22965 currentStencilRef = null; 22966 currentStencilFuncMask = null; 22967 currentStencilFail = null; 22968 currentStencilZFail = null; 22969 currentStencilZPass = null; 22970 currentStencilClear = null; 22971 22972 } 22973 22974 }; 22975 22976 } 22977 22978 // 22979 22980 const colorBuffer = new ColorBuffer(); 22981 const depthBuffer = new DepthBuffer(); 22982 const stencilBuffer = new StencilBuffer(); 22983 22984 const uboBindings = new WeakMap(); 22985 const uboProgramMap = new WeakMap(); 22986 22987 let enabledCapabilities = {}; 22988 22989 let currentBoundFramebuffers = {}; 22990 let currentDrawbuffers = new WeakMap(); 22991 let defaultDrawbuffers = []; 22992 22993 let currentProgram = null; 22994 22995 let currentBlendingEnabled = false; 22996 let currentBlending = null; 22997 let currentBlendEquation = null; 22998 let currentBlendSrc = null; 22999 let currentBlendDst = null; 23000 let currentBlendEquationAlpha = null; 23001 let currentBlendSrcAlpha = null; 23002 let currentBlendDstAlpha = null; 23003 let currentBlendColor = new Color( 0, 0, 0 ); 23004 let currentBlendAlpha = 0; 23005 let currentPremultipledAlpha = false; 23006 23007 let currentFlipSided = null; 23008 let currentCullFace = null; 23009 23010 let currentLineWidth = null; 23011 23012 let currentPolygonOffsetFactor = null; 23013 let currentPolygonOffsetUnits = null; 23014 23015 const maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS ); 23016 23017 let lineWidthAvailable = false; 23018 let version = 0; 23019 const glVersion = gl.getParameter( gl.VERSION ); 23020 23021 if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) { 23022 23023 version = parseFloat( /^WebGL (\d)/.exec( glVersion )[ 1 ] ); 23024 lineWidthAvailable = ( version >= 1.0 ); 23025 23026 } else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) { 23027 23028 version = parseFloat( /^OpenGL ES (\d)/.exec( glVersion )[ 1 ] ); 23029 lineWidthAvailable = ( version >= 2.0 ); 23030 23031 } 23032 23033 let currentTextureSlot = null; 23034 let currentBoundTextures = {}; 23035 23036 const scissorParam = gl.getParameter( gl.SCISSOR_BOX ); 23037 const viewportParam = gl.getParameter( gl.VIEWPORT ); 23038 23039 const currentScissor = new Vector4().fromArray( scissorParam ); 23040 const currentViewport = new Vector4().fromArray( viewportParam ); 23041 23042 function createTexture( type, target, count, dimensions ) { 23043 23044 const data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4. 23045 const texture = gl.createTexture(); 23046 23047 gl.bindTexture( type, texture ); 23048 gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); 23049 gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); 23050 23051 for ( let i = 0; i < count; i ++ ) { 23052 23053 if ( isWebGL2 && ( type === gl.TEXTURE_3D || type === gl.TEXTURE_2D_ARRAY ) ) { 23054 23055 gl.texImage3D( target, 0, gl.RGBA, 1, 1, dimensions, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); 23056 23057 } else { 23058 23059 gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); 23060 23061 } 23062 23063 } 23064 23065 return texture; 23066 23067 } 23068 23069 const emptyTextures = {}; 23070 emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 ); 23071 emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 ); 23072 23073 if ( isWebGL2 ) { 23074 23075 emptyTextures[ gl.TEXTURE_2D_ARRAY ] = createTexture( gl.TEXTURE_2D_ARRAY, gl.TEXTURE_2D_ARRAY, 1, 1 ); 23076 emptyTextures[ gl.TEXTURE_3D ] = createTexture( gl.TEXTURE_3D, gl.TEXTURE_3D, 1, 1 ); 23077 23078 } 23079 23080 // init 23081 23082 colorBuffer.setClear( 0, 0, 0, 1 ); 23083 depthBuffer.setClear( 1 ); 23084 stencilBuffer.setClear( 0 ); 23085 23086 enable( gl.DEPTH_TEST ); 23087 depthBuffer.setFunc( LessEqualDepth ); 23088 23089 setFlipSided( false ); 23090 setCullFace( CullFaceBack ); 23091 enable( gl.CULL_FACE ); 23092 23093 setBlending( NoBlending ); 23094 23095 // 23096 23097 function enable( id ) { 23098 23099 if ( enabledCapabilities[ id ] !== true ) { 23100 23101 gl.enable( id ); 23102 enabledCapabilities[ id ] = true; 23103 23104 } 23105 23106 } 23107 23108 function disable( id ) { 23109 23110 if ( enabledCapabilities[ id ] !== false ) { 23111 23112 gl.disable( id ); 23113 enabledCapabilities[ id ] = false; 23114 23115 } 23116 23117 } 23118 23119 function bindFramebuffer( target, framebuffer ) { 23120 23121 if ( currentBoundFramebuffers[ target ] !== framebuffer ) { 23122 23123 gl.bindFramebuffer( target, framebuffer ); 23124 23125 currentBoundFramebuffers[ target ] = framebuffer; 23126 23127 if ( isWebGL2 ) { 23128 23129 // gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER 23130 23131 if ( target === gl.DRAW_FRAMEBUFFER ) { 23132 23133 currentBoundFramebuffers[ gl.FRAMEBUFFER ] = framebuffer; 23134 23135 } 23136 23137 if ( target === gl.FRAMEBUFFER ) { 23138 23139 currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] = framebuffer; 23140 23141 } 23142 23143 } 23144 23145 return true; 23146 23147 } 23148 23149 return false; 23150 23151 } 23152 23153 function drawBuffers( renderTarget, framebuffer ) { 23154 23155 let drawBuffers = defaultDrawbuffers; 23156 23157 let needsUpdate = false; 23158 23159 if ( renderTarget ) { 23160 23161 drawBuffers = currentDrawbuffers.get( framebuffer ); 23162 23163 if ( drawBuffers === undefined ) { 23164 23165 drawBuffers = []; 23166 currentDrawbuffers.set( framebuffer, drawBuffers ); 23167 23168 } 23169 23170 if ( renderTarget.isWebGLMultipleRenderTargets ) { 23171 23172 const textures = renderTarget.texture; 23173 23174 if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) { 23175 23176 for ( let i = 0, il = textures.length; i < il; i ++ ) { 23177 23178 drawBuffers[ i ] = gl.COLOR_ATTACHMENT0 + i; 23179 23180 } 23181 23182 drawBuffers.length = textures.length; 23183 23184 needsUpdate = true; 23185 23186 } 23187 23188 } else { 23189 23190 if ( drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) { 23191 23192 drawBuffers[ 0 ] = gl.COLOR_ATTACHMENT0; 23193 23194 needsUpdate = true; 23195 23196 } 23197 23198 } 23199 23200 } else { 23201 23202 if ( drawBuffers[ 0 ] !== gl.BACK ) { 23203 23204 drawBuffers[ 0 ] = gl.BACK; 23205 23206 needsUpdate = true; 23207 23208 } 23209 23210 } 23211 23212 if ( needsUpdate ) { 23213 23214 if ( capabilities.isWebGL2 ) { 23215 23216 gl.drawBuffers( drawBuffers ); 23217 23218 } else { 23219 23220 extensions.get( 'WEBGL_draw_buffers' ).drawBuffersWEBGL( drawBuffers ); 23221 23222 } 23223 23224 } 23225 23226 23227 } 23228 23229 function useProgram( program ) { 23230 23231 if ( currentProgram !== program ) { 23232 23233 gl.useProgram( program ); 23234 23235 currentProgram = program; 23236 23237 return true; 23238 23239 } 23240 23241 return false; 23242 23243 } 23244 23245 const equationToGL = { 23246 [ AddEquation ]: gl.FUNC_ADD, 23247 [ SubtractEquation ]: gl.FUNC_SUBTRACT, 23248 [ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT 23249 }; 23250 23251 if ( isWebGL2 ) { 23252 23253 equationToGL[ MinEquation ] = gl.MIN; 23254 equationToGL[ MaxEquation ] = gl.MAX; 23255 23256 } else { 23257 23258 const extension = extensions.get( 'EXT_blend_minmax' ); 23259 23260 if ( extension !== null ) { 23261 23262 equationToGL[ MinEquation ] = extension.MIN_EXT; 23263 equationToGL[ MaxEquation ] = extension.MAX_EXT; 23264 23265 } 23266 23267 } 23268 23269 const factorToGL = { 23270 [ ZeroFactor ]: gl.ZERO, 23271 [ OneFactor ]: gl.ONE, 23272 [ SrcColorFactor ]: gl.SRC_COLOR, 23273 [ SrcAlphaFactor ]: gl.SRC_ALPHA, 23274 [ SrcAlphaSaturateFactor ]: gl.SRC_ALPHA_SATURATE, 23275 [ DstColorFactor ]: gl.DST_COLOR, 23276 [ DstAlphaFactor ]: gl.DST_ALPHA, 23277 [ OneMinusSrcColorFactor ]: gl.ONE_MINUS_SRC_COLOR, 23278 [ OneMinusSrcAlphaFactor ]: gl.ONE_MINUS_SRC_ALPHA, 23279 [ OneMinusDstColorFactor ]: gl.ONE_MINUS_DST_COLOR, 23280 [ OneMinusDstAlphaFactor ]: gl.ONE_MINUS_DST_ALPHA, 23281 [ ConstantColorFactor ]: gl.CONSTANT_COLOR, 23282 [ OneMinusConstantColorFactor ]: gl.ONE_MINUS_CONSTANT_COLOR, 23283 [ ConstantAlphaFactor ]: gl.CONSTANT_ALPHA, 23284 [ OneMinusConstantAlphaFactor ]: gl.ONE_MINUS_CONSTANT_ALPHA 23285 }; 23286 23287 function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, blendColor, blendAlpha, premultipliedAlpha ) { 23288 23289 if ( blending === NoBlending ) { 23290 23291 if ( currentBlendingEnabled === true ) { 23292 23293 disable( gl.BLEND ); 23294 currentBlendingEnabled = false; 23295 23296 } 23297 23298 return; 23299 23300 } 23301 23302 if ( currentBlendingEnabled === false ) { 23303 23304 enable( gl.BLEND ); 23305 currentBlendingEnabled = true; 23306 23307 } 23308 23309 if ( blending !== CustomBlending ) { 23310 23311 if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) { 23312 23313 if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) { 23314 23315 gl.blendEquation( gl.FUNC_ADD ); 23316 23317 currentBlendEquation = AddEquation; 23318 currentBlendEquationAlpha = AddEquation; 23319 23320 } 23321 23322 if ( premultipliedAlpha ) { 23323 23324 switch ( blending ) { 23325 23326 case NormalBlending: 23327 gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); 23328 break; 23329 23330 case AdditiveBlending: 23331 gl.blendFunc( gl.ONE, gl.ONE ); 23332 break; 23333 23334 case SubtractiveBlending: 23335 gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE ); 23336 break; 23337 23338 case MultiplyBlending: 23339 gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA ); 23340 break; 23341 23342 default: 23343 console.error( 'THREE.WebGLState: Invalid blending: ', blending ); 23344 break; 23345 23346 } 23347 23348 } else { 23349 23350 switch ( blending ) { 23351 23352 case NormalBlending: 23353 gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); 23354 break; 23355 23356 case AdditiveBlending: 23357 gl.blendFunc( gl.SRC_ALPHA, gl.ONE ); 23358 break; 23359 23360 case SubtractiveBlending: 23361 gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE ); 23362 break; 23363 23364 case MultiplyBlending: 23365 gl.blendFunc( gl.ZERO, gl.SRC_COLOR ); 23366 break; 23367 23368 default: 23369 console.error( 'THREE.WebGLState: Invalid blending: ', blending ); 23370 break; 23371 23372 } 23373 23374 } 23375 23376 currentBlendSrc = null; 23377 currentBlendDst = null; 23378 currentBlendSrcAlpha = null; 23379 currentBlendDstAlpha = null; 23380 currentBlendColor.set( 0, 0, 0 ); 23381 currentBlendAlpha = 0; 23382 23383 currentBlending = blending; 23384 currentPremultipledAlpha = premultipliedAlpha; 23385 23386 } 23387 23388 return; 23389 23390 } 23391 23392 // custom blending 23393 23394 blendEquationAlpha = blendEquationAlpha || blendEquation; 23395 blendSrcAlpha = blendSrcAlpha || blendSrc; 23396 blendDstAlpha = blendDstAlpha || blendDst; 23397 23398 if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) { 23399 23400 gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] ); 23401 23402 currentBlendEquation = blendEquation; 23403 currentBlendEquationAlpha = blendEquationAlpha; 23404 23405 } 23406 23407 if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) { 23408 23409 gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] ); 23410 23411 currentBlendSrc = blendSrc; 23412 currentBlendDst = blendDst; 23413 currentBlendSrcAlpha = blendSrcAlpha; 23414 currentBlendDstAlpha = blendDstAlpha; 23415 23416 } 23417 23418 if ( blendColor.equals( currentBlendColor ) === false || blendAlpha !== currentBlendAlpha ) { 23419 23420 gl.blendColor( blendColor.r, blendColor.g, blendColor.b, blendAlpha ); 23421 23422 currentBlendColor.copy( blendColor ); 23423 currentBlendAlpha = blendAlpha; 23424 23425 } 23426 23427 currentBlending = blending; 23428 currentPremultipledAlpha = false; 23429 23430 } 23431 23432 function setMaterial( material, frontFaceCW ) { 23433 23434 material.side === DoubleSide 23435 ? disable( gl.CULL_FACE ) 23436 : enable( gl.CULL_FACE ); 23437 23438 let flipSided = ( material.side === BackSide ); 23439 if ( frontFaceCW ) flipSided = ! flipSided; 23440 23441 setFlipSided( flipSided ); 23442 23443 ( material.blending === NormalBlending && material.transparent === false ) 23444 ? setBlending( NoBlending ) 23445 : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha ); 23446 23447 depthBuffer.setFunc( material.depthFunc ); 23448 depthBuffer.setTest( material.depthTest ); 23449 depthBuffer.setMask( material.depthWrite ); 23450 colorBuffer.setMask( material.colorWrite ); 23451 23452 const stencilWrite = material.stencilWrite; 23453 stencilBuffer.setTest( stencilWrite ); 23454 if ( stencilWrite ) { 23455 23456 stencilBuffer.setMask( material.stencilWriteMask ); 23457 stencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask ); 23458 stencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass ); 23459 23460 } 23461 23462 setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); 23463 23464 material.alphaToCoverage === true 23465 ? enable( gl.SAMPLE_ALPHA_TO_COVERAGE ) 23466 : disable( gl.SAMPLE_ALPHA_TO_COVERAGE ); 23467 23468 } 23469 23470 // 23471 23472 function setFlipSided( flipSided ) { 23473 23474 if ( currentFlipSided !== flipSided ) { 23475 23476 if ( flipSided ) { 23477 23478 gl.frontFace( gl.CW ); 23479 23480 } else { 23481 23482 gl.frontFace( gl.CCW ); 23483 23484 } 23485 23486 currentFlipSided = flipSided; 23487 23488 } 23489 23490 } 23491 23492 function setCullFace( cullFace ) { 23493 23494 if ( cullFace !== CullFaceNone ) { 23495 23496 enable( gl.CULL_FACE ); 23497 23498 if ( cullFace !== currentCullFace ) { 23499 23500 if ( cullFace === CullFaceBack ) { 23501 23502 gl.cullFace( gl.BACK ); 23503 23504 } else if ( cullFace === CullFaceFront ) { 23505 23506 gl.cullFace( gl.FRONT ); 23507 23508 } else { 23509 23510 gl.cullFace( gl.FRONT_AND_BACK ); 23511 23512 } 23513 23514 } 23515 23516 } else { 23517 23518 disable( gl.CULL_FACE ); 23519 23520 } 23521 23522 currentCullFace = cullFace; 23523 23524 } 23525 23526 function setLineWidth( width ) { 23527 23528 if ( width !== currentLineWidth ) { 23529 23530 if ( lineWidthAvailable ) gl.lineWidth( width ); 23531 23532 currentLineWidth = width; 23533 23534 } 23535 23536 } 23537 23538 function setPolygonOffset( polygonOffset, factor, units ) { 23539 23540 if ( polygonOffset ) { 23541 23542 enable( gl.POLYGON_OFFSET_FILL ); 23543 23544 if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) { 23545 23546 gl.polygonOffset( factor, units ); 23547 23548 currentPolygonOffsetFactor = factor; 23549 currentPolygonOffsetUnits = units; 23550 23551 } 23552 23553 } else { 23554 23555 disable( gl.POLYGON_OFFSET_FILL ); 23556 23557 } 23558 23559 } 23560 23561 function setScissorTest( scissorTest ) { 23562 23563 if ( scissorTest ) { 23564 23565 enable( gl.SCISSOR_TEST ); 23566 23567 } else { 23568 23569 disable( gl.SCISSOR_TEST ); 23570 23571 } 23572 23573 } 23574 23575 // texture 23576 23577 function activeTexture( webglSlot ) { 23578 23579 if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1; 23580 23581 if ( currentTextureSlot !== webglSlot ) { 23582 23583 gl.activeTexture( webglSlot ); 23584 currentTextureSlot = webglSlot; 23585 23586 } 23587 23588 } 23589 23590 function bindTexture( webglType, webglTexture, webglSlot ) { 23591 23592 if ( webglSlot === undefined ) { 23593 23594 if ( currentTextureSlot === null ) { 23595 23596 webglSlot = gl.TEXTURE0 + maxTextures - 1; 23597 23598 } else { 23599 23600 webglSlot = currentTextureSlot; 23601 23602 } 23603 23604 } 23605 23606 let boundTexture = currentBoundTextures[ webglSlot ]; 23607 23608 if ( boundTexture === undefined ) { 23609 23610 boundTexture = { type: undefined, texture: undefined }; 23611 currentBoundTextures[ webglSlot ] = boundTexture; 23612 23613 } 23614 23615 if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) { 23616 23617 if ( currentTextureSlot !== webglSlot ) { 23618 23619 gl.activeTexture( webglSlot ); 23620 currentTextureSlot = webglSlot; 23621 23622 } 23623 23624 gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] ); 23625 23626 boundTexture.type = webglType; 23627 boundTexture.texture = webglTexture; 23628 23629 } 23630 23631 } 23632 23633 function unbindTexture() { 23634 23635 const boundTexture = currentBoundTextures[ currentTextureSlot ]; 23636 23637 23638 if ( boundTexture !== undefined && boundTexture.type !== undefined ) { 23639 23640 gl.bindTexture( boundTexture.type, null ); 23641 23642 boundTexture.type = undefined; 23643 boundTexture.texture = undefined; 23644 23645 } 23646 23647 } 23648 23649 function compressedTexImage2D() { 23650 23651 try { 23652 23653 gl.compressedTexImage2D.apply( gl, arguments ); 23654 23655 } catch ( error ) { 23656 23657 console.error( 'THREE.WebGLState:', error ); 23658 23659 } 23660 23661 } 23662 23663 function compressedTexImage3D() { 23664 23665 try { 23666 23667 gl.compressedTexImage3D.apply( gl, arguments ); 23668 23669 } catch ( error ) { 23670 23671 console.error( 'THREE.WebGLState:', error ); 23672 23673 } 23674 23675 } 23676 23677 function texSubImage2D() { 23678 23679 try { 23680 23681 gl.texSubImage2D.apply( gl, arguments ); 23682 23683 } catch ( error ) { 23684 23685 console.error( 'THREE.WebGLState:', error ); 23686 23687 } 23688 23689 } 23690 23691 function texSubImage3D() { 23692 23693 try { 23694 23695 gl.texSubImage3D.apply( gl, arguments ); 23696 23697 } catch ( error ) { 23698 23699 console.error( 'THREE.WebGLState:', error ); 23700 23701 } 23702 23703 } 23704 23705 function compressedTexSubImage2D() { 23706 23707 try { 23708 23709 gl.compressedTexSubImage2D.apply( gl, arguments ); 23710 23711 } catch ( error ) { 23712 23713 console.error( 'THREE.WebGLState:', error ); 23714 23715 } 23716 23717 } 23718 23719 function compressedTexSubImage3D() { 23720 23721 try { 23722 23723 gl.compressedTexSubImage3D.apply( gl, arguments ); 23724 23725 } catch ( error ) { 23726 23727 console.error( 'THREE.WebGLState:', error ); 23728 23729 } 23730 23731 } 23732 23733 function texStorage2D() { 23734 23735 try { 23736 23737 gl.texStorage2D.apply( gl, arguments ); 23738 23739 } catch ( error ) { 23740 23741 console.error( 'THREE.WebGLState:', error ); 23742 23743 } 23744 23745 } 23746 23747 function texStorage3D() { 23748 23749 try { 23750 23751 gl.texStorage3D.apply( gl, arguments ); 23752 23753 } catch ( error ) { 23754 23755 console.error( 'THREE.WebGLState:', error ); 23756 23757 } 23758 23759 } 23760 23761 function texImage2D() { 23762 23763 try { 23764 23765 gl.texImage2D.apply( gl, arguments ); 23766 23767 } catch ( error ) { 23768 23769 console.error( 'THREE.WebGLState:', error ); 23770 23771 } 23772 23773 } 23774 23775 function texImage3D() { 23776 23777 try { 23778 23779 gl.texImage3D.apply( gl, arguments ); 23780 23781 } catch ( error ) { 23782 23783 console.error( 'THREE.WebGLState:', error ); 23784 23785 } 23786 23787 } 23788 23789 // 23790 23791 function scissor( scissor ) { 23792 23793 if ( currentScissor.equals( scissor ) === false ) { 23794 23795 gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w ); 23796 currentScissor.copy( scissor ); 23797 23798 } 23799 23800 } 23801 23802 function viewport( viewport ) { 23803 23804 if ( currentViewport.equals( viewport ) === false ) { 23805 23806 gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w ); 23807 currentViewport.copy( viewport ); 23808 23809 } 23810 23811 } 23812 23813 function updateUBOMapping( uniformsGroup, program ) { 23814 23815 let mapping = uboProgramMap.get( program ); 23816 23817 if ( mapping === undefined ) { 23818 23819 mapping = new WeakMap(); 23820 23821 uboProgramMap.set( program, mapping ); 23822 23823 } 23824 23825 let blockIndex = mapping.get( uniformsGroup ); 23826 23827 if ( blockIndex === undefined ) { 23828 23829 blockIndex = gl.getUniformBlockIndex( program, uniformsGroup.name ); 23830 23831 mapping.set( uniformsGroup, blockIndex ); 23832 23833 } 23834 23835 } 23836 23837 function uniformBlockBinding( uniformsGroup, program ) { 23838 23839 const mapping = uboProgramMap.get( program ); 23840 const blockIndex = mapping.get( uniformsGroup ); 23841 23842 if ( uboBindings.get( program ) !== blockIndex ) { 23843 23844 // bind shader specific block index to global block point 23845 gl.uniformBlockBinding( program, blockIndex, uniformsGroup.__bindingPointIndex ); 23846 23847 uboBindings.set( program, blockIndex ); 23848 23849 } 23850 23851 } 23852 23853 // 23854 23855 function reset() { 23856 23857 // reset state 23858 23859 gl.disable( gl.BLEND ); 23860 gl.disable( gl.CULL_FACE ); 23861 gl.disable( gl.DEPTH_TEST ); 23862 gl.disable( gl.POLYGON_OFFSET_FILL ); 23863 gl.disable( gl.SCISSOR_TEST ); 23864 gl.disable( gl.STENCIL_TEST ); 23865 gl.disable( gl.SAMPLE_ALPHA_TO_COVERAGE ); 23866 23867 gl.blendEquation( gl.FUNC_ADD ); 23868 gl.blendFunc( gl.ONE, gl.ZERO ); 23869 gl.blendFuncSeparate( gl.ONE, gl.ZERO, gl.ONE, gl.ZERO ); 23870 gl.blendColor( 0, 0, 0, 0 ); 23871 23872 gl.colorMask( true, true, true, true ); 23873 gl.clearColor( 0, 0, 0, 0 ); 23874 23875 gl.depthMask( true ); 23876 gl.depthFunc( gl.LESS ); 23877 gl.clearDepth( 1 ); 23878 23879 gl.stencilMask( 0xffffffff ); 23880 gl.stencilFunc( gl.ALWAYS, 0, 0xffffffff ); 23881 gl.stencilOp( gl.KEEP, gl.KEEP, gl.KEEP ); 23882 gl.clearStencil( 0 ); 23883 23884 gl.cullFace( gl.BACK ); 23885 gl.frontFace( gl.CCW ); 23886 23887 gl.polygonOffset( 0, 0 ); 23888 23889 gl.activeTexture( gl.TEXTURE0 ); 23890 23891 gl.bindFramebuffer( gl.FRAMEBUFFER, null ); 23892 23893 if ( isWebGL2 === true ) { 23894 23895 gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null ); 23896 gl.bindFramebuffer( gl.READ_FRAMEBUFFER, null ); 23897 23898 } 23899 23900 gl.useProgram( null ); 23901 23902 gl.lineWidth( 1 ); 23903 23904 gl.scissor( 0, 0, gl.canvas.width, gl.canvas.height ); 23905 gl.viewport( 0, 0, gl.canvas.width, gl.canvas.height ); 23906 23907 // reset internals 23908 23909 enabledCapabilities = {}; 23910 23911 currentTextureSlot = null; 23912 currentBoundTextures = {}; 23913 23914 currentBoundFramebuffers = {}; 23915 currentDrawbuffers = new WeakMap(); 23916 defaultDrawbuffers = []; 23917 23918 currentProgram = null; 23919 23920 currentBlendingEnabled = false; 23921 currentBlending = null; 23922 currentBlendEquation = null; 23923 currentBlendSrc = null; 23924 currentBlendDst = null; 23925 currentBlendEquationAlpha = null; 23926 currentBlendSrcAlpha = null; 23927 currentBlendDstAlpha = null; 23928 currentBlendColor = new Color( 0, 0, 0 ); 23929 currentBlendAlpha = 0; 23930 currentPremultipledAlpha = false; 23931 23932 currentFlipSided = null; 23933 currentCullFace = null; 23934 23935 currentLineWidth = null; 23936 23937 currentPolygonOffsetFactor = null; 23938 currentPolygonOffsetUnits = null; 23939 23940 currentScissor.set( 0, 0, gl.canvas.width, gl.canvas.height ); 23941 currentViewport.set( 0, 0, gl.canvas.width, gl.canvas.height ); 23942 23943 colorBuffer.reset(); 23944 depthBuffer.reset(); 23945 stencilBuffer.reset(); 23946 23947 } 23948 23949 return { 23950 23951 buffers: { 23952 color: colorBuffer, 23953 depth: depthBuffer, 23954 stencil: stencilBuffer 23955 }, 23956 23957 enable: enable, 23958 disable: disable, 23959 23960 bindFramebuffer: bindFramebuffer, 23961 drawBuffers: drawBuffers, 23962 23963 useProgram: useProgram, 23964 23965 setBlending: setBlending, 23966 setMaterial: setMaterial, 23967 23968 setFlipSided: setFlipSided, 23969 setCullFace: setCullFace, 23970 23971 setLineWidth: setLineWidth, 23972 setPolygonOffset: setPolygonOffset, 23973 23974 setScissorTest: setScissorTest, 23975 23976 activeTexture: activeTexture, 23977 bindTexture: bindTexture, 23978 unbindTexture: unbindTexture, 23979 compressedTexImage2D: compressedTexImage2D, 23980 compressedTexImage3D: compressedTexImage3D, 23981 texImage2D: texImage2D, 23982 texImage3D: texImage3D, 23983 23984 updateUBOMapping: updateUBOMapping, 23985 uniformBlockBinding: uniformBlockBinding, 23986 23987 texStorage2D: texStorage2D, 23988 texStorage3D: texStorage3D, 23989 texSubImage2D: texSubImage2D, 23990 texSubImage3D: texSubImage3D, 23991 compressedTexSubImage2D: compressedTexSubImage2D, 23992 compressedTexSubImage3D: compressedTexSubImage3D, 23993 23994 scissor: scissor, 23995 viewport: viewport, 23996 23997 reset: reset 23998 23999 }; 24000 24001} 24002 24003function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) { 24004 24005 const isWebGL2 = capabilities.isWebGL2; 24006 const multisampledRTTExt = extensions.has( 'WEBGL_multisampled_render_to_texture' ) ? extensions.get( 'WEBGL_multisampled_render_to_texture' ) : null; 24007 const supportsInvalidateFramebuffer = typeof navigator === 'undefined' ? false : /OculusBrowser/g.test( navigator.userAgent ); 24008 24009 const _videoTextures = new WeakMap(); 24010 let _canvas; 24011 24012 const _sources = new WeakMap(); // maps WebglTexture objects to instances of Source 24013 24014 // cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas, 24015 // also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")! 24016 // Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d). 24017 24018 let useOffscreenCanvas = false; 24019 24020 try { 24021 24022 useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined' 24023 // eslint-disable-next-line compat/compat 24024 && ( new OffscreenCanvas( 1, 1 ).getContext( '2d' ) ) !== null; 24025 24026 } catch ( err ) { 24027 24028 // Ignore any errors 24029 24030 } 24031 24032 function createCanvas( width, height ) { 24033 24034 // Use OffscreenCanvas when available. Specially needed in web workers 24035 24036 return useOffscreenCanvas ? 24037 // eslint-disable-next-line compat/compat 24038 new OffscreenCanvas( width, height ) : createElementNS( 'canvas' ); 24039 24040 } 24041 24042 function resizeImage( image, needsPowerOfTwo, needsNewCanvas, maxSize ) { 24043 24044 let scale = 1; 24045 24046 // handle case if texture exceeds max size 24047 24048 if ( image.width > maxSize || image.height > maxSize ) { 24049 24050 scale = maxSize / Math.max( image.width, image.height ); 24051 24052 } 24053 24054 // only perform resize if necessary 24055 24056 if ( scale < 1 || needsPowerOfTwo === true ) { 24057 24058 // only perform resize for certain image types 24059 24060 if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || 24061 ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || 24062 ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { 24063 24064 const floor = needsPowerOfTwo ? floorPowerOfTwo : Math.floor; 24065 24066 const width = floor( scale * image.width ); 24067 const height = floor( scale * image.height ); 24068 24069 if ( _canvas === undefined ) _canvas = createCanvas( width, height ); 24070 24071 // cube textures can't reuse the same canvas 24072 24073 const canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas; 24074 24075 canvas.width = width; 24076 canvas.height = height; 24077 24078 const context = canvas.getContext( '2d' ); 24079 context.drawImage( image, 0, 0, width, height ); 24080 24081 console.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + image.width + 'x' + image.height + ') to (' + width + 'x' + height + ').' ); 24082 24083 return canvas; 24084 24085 } else { 24086 24087 if ( 'data' in image ) { 24088 24089 console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + image.width + 'x' + image.height + ').' ); 24090 24091 } 24092 24093 return image; 24094 24095 } 24096 24097 } 24098 24099 return image; 24100 24101 } 24102 24103 function isPowerOfTwo$1( image ) { 24104 24105 return isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ); 24106 24107 } 24108 24109 function textureNeedsPowerOfTwo( texture ) { 24110 24111 if ( isWebGL2 ) return false; 24112 24113 return ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) || 24114 ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ); 24115 24116 } 24117 24118 function textureNeedsGenerateMipmaps( texture, supportsMips ) { 24119 24120 return texture.generateMipmaps && supportsMips && 24121 texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter; 24122 24123 } 24124 24125 function generateMipmap( target ) { 24126 24127 _gl.generateMipmap( target ); 24128 24129 } 24130 24131 function getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) { 24132 24133 if ( isWebGL2 === false ) return glFormat; 24134 24135 if ( internalFormatName !== null ) { 24136 24137 if ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ]; 24138 24139 console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' ); 24140 24141 } 24142 24143 let internalFormat = glFormat; 24144 24145 if ( glFormat === _gl.RED ) { 24146 24147 if ( glType === _gl.FLOAT ) internalFormat = _gl.R32F; 24148 if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.R16F; 24149 if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8; 24150 24151 } 24152 24153 if ( glFormat === _gl.RED_INTEGER ) { 24154 24155 if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8UI; 24156 if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.R16UI; 24157 if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.R32UI; 24158 if ( glType === _gl.BYTE ) internalFormat = _gl.R8I; 24159 if ( glType === _gl.SHORT ) internalFormat = _gl.R16I; 24160 if ( glType === _gl.INT ) internalFormat = _gl.R32I; 24161 24162 } 24163 24164 if ( glFormat === _gl.RG ) { 24165 24166 if ( glType === _gl.FLOAT ) internalFormat = _gl.RG32F; 24167 if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RG16F; 24168 if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RG8; 24169 24170 } 24171 24172 if ( glFormat === _gl.RGBA ) { 24173 24174 const transfer = forceLinearTransfer ? LinearTransfer : ColorManagement.getTransfer( colorSpace ); 24175 24176 if ( glType === _gl.FLOAT ) internalFormat = _gl.RGBA32F; 24177 if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RGBA16F; 24178 if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = ( transfer === SRGBTransfer ) ? _gl.SRGB8_ALPHA8 : _gl.RGBA8; 24179 if ( glType === _gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = _gl.RGBA4; 24180 if ( glType === _gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = _gl.RGB5_A1; 24181 24182 } 24183 24184 if ( internalFormat === _gl.R16F || internalFormat === _gl.R32F || 24185 internalFormat === _gl.RG16F || internalFormat === _gl.RG32F || 24186 internalFormat === _gl.RGBA16F || internalFormat === _gl.RGBA32F ) { 24187 24188 extensions.get( 'EXT_color_buffer_float' ); 24189 24190 } 24191 24192 return internalFormat; 24193 24194 } 24195 24196 function getMipLevels( texture, image, supportsMips ) { 24197 24198 if ( textureNeedsGenerateMipmaps( texture, supportsMips ) === true || ( texture.isFramebufferTexture && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) ) { 24199 24200 return Math.log2( Math.max( image.width, image.height ) ) + 1; 24201 24202 } else if ( texture.mipmaps !== undefined && texture.mipmaps.length > 0 ) { 24203 24204 // user-defined mipmaps 24205 24206 return texture.mipmaps.length; 24207 24208 } else if ( texture.isCompressedTexture && Array.isArray( texture.image ) ) { 24209 24210 return image.mipmaps.length; 24211 24212 } else { 24213 24214 // texture without mipmaps (only base level) 24215 24216 return 1; 24217 24218 } 24219 24220 } 24221 24222 // Fallback filters for non-power-of-2 textures 24223 24224 function filterFallback( f ) { 24225 24226 if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) { 24227 24228 return _gl.NEAREST; 24229 24230 } 24231 24232 return _gl.LINEAR; 24233 24234 } 24235 24236 // 24237 24238 function onTextureDispose( event ) { 24239 24240 const texture = event.target; 24241 24242 texture.removeEventListener( 'dispose', onTextureDispose ); 24243 24244 deallocateTexture( texture ); 24245 24246 if ( texture.isVideoTexture ) { 24247 24248 _videoTextures.delete( texture ); 24249 24250 } 24251 24252 } 24253 24254 function onRenderTargetDispose( event ) { 24255 24256 const renderTarget = event.target; 24257 24258 renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); 24259 24260 deallocateRenderTarget( renderTarget ); 24261 24262 } 24263 24264 // 24265 24266 function deallocateTexture( texture ) { 24267 24268 const textureProperties = properties.get( texture ); 24269 24270 if ( textureProperties.__webglInit === undefined ) return; 24271 24272 // check if it's necessary to remove the WebGLTexture object 24273 24274 const source = texture.source; 24275 const webglTextures = _sources.get( source ); 24276 24277 if ( webglTextures ) { 24278 24279 const webglTexture = webglTextures[ textureProperties.__cacheKey ]; 24280 webglTexture.usedTimes --; 24281 24282 // the WebGLTexture object is not used anymore, remove it 24283 24284 if ( webglTexture.usedTimes === 0 ) { 24285 24286 deleteTexture( texture ); 24287 24288 } 24289 24290 // remove the weak map entry if no WebGLTexture uses the source anymore 24291 24292 if ( Object.keys( webglTextures ).length === 0 ) { 24293 24294 _sources.delete( source ); 24295 24296 } 24297 24298 } 24299 24300 properties.remove( texture ); 24301 24302 } 24303 24304 function deleteTexture( texture ) { 24305 24306 const textureProperties = properties.get( texture ); 24307 _gl.deleteTexture( textureProperties.__webglTexture ); 24308 24309 const source = texture.source; 24310 const webglTextures = _sources.get( source ); 24311 delete webglTextures[ textureProperties.__cacheKey ]; 24312 24313 info.memory.textures --; 24314 24315 } 24316 24317 function deallocateRenderTarget( renderTarget ) { 24318 24319 const texture = renderTarget.texture; 24320 24321 const renderTargetProperties = properties.get( renderTarget ); 24322 const textureProperties = properties.get( texture ); 24323 24324 if ( textureProperties.__webglTexture !== undefined ) { 24325 24326 _gl.deleteTexture( textureProperties.__webglTexture ); 24327 24328 info.memory.textures --; 24329 24330 } 24331 24332 if ( renderTarget.depthTexture ) { 24333 24334 renderTarget.depthTexture.dispose(); 24335 24336 } 24337 24338 if ( renderTarget.isWebGLCubeRenderTarget ) { 24339 24340 for ( let i = 0; i < 6; i ++ ) { 24341 24342 if ( Array.isArray( renderTargetProperties.__webglFramebuffer[ i ] ) ) { 24343 24344 for ( let level = 0; level < renderTargetProperties.__webglFramebuffer[ i ].length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ][ level ] ); 24345 24346 } else { 24347 24348 _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); 24349 24350 } 24351 24352 if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] ); 24353 24354 } 24355 24356 } else { 24357 24358 if ( Array.isArray( renderTargetProperties.__webglFramebuffer ) ) { 24359 24360 for ( let level = 0; level < renderTargetProperties.__webglFramebuffer.length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ level ] ); 24361 24362 } else { 24363 24364 _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); 24365 24366 } 24367 24368 if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer ); 24369 if ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer ); 24370 24371 if ( renderTargetProperties.__webglColorRenderbuffer ) { 24372 24373 for ( let i = 0; i < renderTargetProperties.__webglColorRenderbuffer.length; i ++ ) { 24374 24375 if ( renderTargetProperties.__webglColorRenderbuffer[ i ] ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer[ i ] ); 24376 24377 } 24378 24379 } 24380 24381 if ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer ); 24382 24383 } 24384 24385 if ( renderTarget.isWebGLMultipleRenderTargets ) { 24386 24387 for ( let i = 0, il = texture.length; i < il; i ++ ) { 24388 24389 const attachmentProperties = properties.get( texture[ i ] ); 24390 24391 if ( attachmentProperties.__webglTexture ) { 24392 24393 _gl.deleteTexture( attachmentProperties.__webglTexture ); 24394 24395 info.memory.textures --; 24396 24397 } 24398 24399 properties.remove( texture[ i ] ); 24400 24401 } 24402 24403 } 24404 24405 properties.remove( texture ); 24406 properties.remove( renderTarget ); 24407 24408 } 24409 24410 // 24411 24412 let textureUnits = 0; 24413 24414 function resetTextureUnits() { 24415 24416 textureUnits = 0; 24417 24418 } 24419 24420 function allocateTextureUnit() { 24421 24422 const textureUnit = textureUnits; 24423 24424 if ( textureUnit >= capabilities.maxTextures ) { 24425 24426 console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures ); 24427 24428 } 24429 24430 textureUnits += 1; 24431 24432 return textureUnit; 24433 24434 } 24435 24436 function getTextureCacheKey( texture ) { 24437 24438 const array = []; 24439 24440 array.push( texture.wrapS ); 24441 array.push( texture.wrapT ); 24442 array.push( texture.wrapR || 0 ); 24443 array.push( texture.magFilter ); 24444 array.push( texture.minFilter ); 24445 array.push( texture.anisotropy ); 24446 array.push( texture.internalFormat ); 24447 array.push( texture.format ); 24448 array.push( texture.type ); 24449 array.push( texture.generateMipmaps ); 24450 array.push( texture.premultiplyAlpha ); 24451 array.push( texture.flipY ); 24452 array.push( texture.unpackAlignment ); 24453 array.push( texture.colorSpace ); 24454 24455 return array.join(); 24456 24457 } 24458 24459 // 24460 24461 function setTexture2D( texture, slot ) { 24462 24463 const textureProperties = properties.get( texture ); 24464 24465 if ( texture.isVideoTexture ) updateVideoTexture( texture ); 24466 24467 if ( texture.isRenderTargetTexture === false && texture.version > 0 && textureProperties.__version !== texture.version ) { 24468 24469 const image = texture.image; 24470 24471 if ( image === null ) { 24472 24473 console.warn( 'THREE.WebGLRenderer: Texture marked for update but no image data found.' ); 24474 24475 } else if ( image.complete === false ) { 24476 24477 console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' ); 24478 24479 } else { 24480 24481 uploadTexture( textureProperties, texture, slot ); 24482 return; 24483 24484 } 24485 24486 } 24487 24488 state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); 24489 24490 } 24491 24492 function setTexture2DArray( texture, slot ) { 24493 24494 const textureProperties = properties.get( texture ); 24495 24496 if ( texture.version > 0 && textureProperties.__version !== texture.version ) { 24497 24498 uploadTexture( textureProperties, texture, slot ); 24499 return; 24500 24501 } 24502 24503 state.bindTexture( _gl.TEXTURE_2D_ARRAY, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); 24504 24505 } 24506 24507 function setTexture3D( texture, slot ) { 24508 24509 const textureProperties = properties.get( texture ); 24510 24511 if ( texture.version > 0 && textureProperties.__version !== texture.version ) { 24512 24513 uploadTexture( textureProperties, texture, slot ); 24514 return; 24515 24516 } 24517 24518 state.bindTexture( _gl.TEXTURE_3D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); 24519 24520 } 24521 24522 function setTextureCube( texture, slot ) { 24523 24524 const textureProperties = properties.get( texture ); 24525 24526 if ( texture.version > 0 && textureProperties.__version !== texture.version ) { 24527 24528 uploadCubeTexture( textureProperties, texture, slot ); 24529 return; 24530 24531 } 24532 24533 state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); 24534 24535 } 24536 24537 const wrappingToGL = { 24538 [ RepeatWrapping ]: _gl.REPEAT, 24539 [ ClampToEdgeWrapping ]: _gl.CLAMP_TO_EDGE, 24540 [ MirroredRepeatWrapping ]: _gl.MIRRORED_REPEAT 24541 }; 24542 24543 const filterToGL = { 24544 [ NearestFilter ]: _gl.NEAREST, 24545 [ NearestMipmapNearestFilter ]: _gl.NEAREST_MIPMAP_NEAREST, 24546 [ NearestMipmapLinearFilter ]: _gl.NEAREST_MIPMAP_LINEAR, 24547 24548 [ LinearFilter ]: _gl.LINEAR, 24549 [ LinearMipmapNearestFilter ]: _gl.LINEAR_MIPMAP_NEAREST, 24550 [ LinearMipmapLinearFilter ]: _gl.LINEAR_MIPMAP_LINEAR 24551 }; 24552 24553 const compareToGL = { 24554 [ NeverCompare ]: _gl.NEVER, 24555 [ AlwaysCompare ]: _gl.ALWAYS, 24556 [ LessCompare ]: _gl.LESS, 24557 [ LessEqualCompare ]: _gl.LEQUAL, 24558 [ EqualCompare ]: _gl.EQUAL, 24559 [ GreaterEqualCompare ]: _gl.GEQUAL, 24560 [ GreaterCompare ]: _gl.GREATER, 24561 [ NotEqualCompare ]: _gl.NOTEQUAL 24562 }; 24563 24564 function setTextureParameters( textureType, texture, supportsMips ) { 24565 24566 if ( supportsMips ) { 24567 24568 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, wrappingToGL[ texture.wrapS ] ); 24569 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, wrappingToGL[ texture.wrapT ] ); 24570 24571 if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) { 24572 24573 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, wrappingToGL[ texture.wrapR ] ); 24574 24575 } 24576 24577 _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterToGL[ texture.magFilter ] ); 24578 _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterToGL[ texture.minFilter ] ); 24579 24580 } else { 24581 24582 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); 24583 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); 24584 24585 if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) { 24586 24587 _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, _gl.CLAMP_TO_EDGE ); 24588 24589 } 24590 24591 if ( texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping ) { 24592 24593 console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.' ); 24594 24595 } 24596 24597 _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); 24598 _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); 24599 24600 if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) { 24601 24602 console.warn( 'THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.' ); 24603 24604 } 24605 24606 } 24607 24608 if ( texture.compareFunction ) { 24609 24610 _gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_MODE, _gl.COMPARE_REF_TO_TEXTURE ); 24611 _gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_FUNC, compareToGL[ texture.compareFunction ] ); 24612 24613 } 24614 24615 if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { 24616 24617 const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); 24618 24619 if ( texture.magFilter === NearestFilter ) return; 24620 if ( texture.minFilter !== NearestMipmapLinearFilter && texture.minFilter !== LinearMipmapLinearFilter ) return; 24621 if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension for WebGL 1 and WebGL 2 24622 if ( isWebGL2 === false && ( texture.type === HalfFloatType && extensions.has( 'OES_texture_half_float_linear' ) === false ) ) return; // verify extension for WebGL 1 only 24623 24624 if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) { 24625 24626 _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) ); 24627 properties.get( texture ).__currentAnisotropy = texture.anisotropy; 24628 24629 } 24630 24631 } 24632 24633 } 24634 24635 function initTexture( textureProperties, texture ) { 24636 24637 let forceUpload = false; 24638 24639 if ( textureProperties.__webglInit === undefined ) { 24640 24641 textureProperties.__webglInit = true; 24642 24643 texture.addEventListener( 'dispose', onTextureDispose ); 24644 24645 } 24646 24647 // create Source <-> WebGLTextures mapping if necessary 24648 24649 const source = texture.source; 24650 let webglTextures = _sources.get( source ); 24651 24652 if ( webglTextures === undefined ) { 24653 24654 webglTextures = {}; 24655 _sources.set( source, webglTextures ); 24656 24657 } 24658 24659 // check if there is already a WebGLTexture object for the given texture parameters 24660 24661 const textureCacheKey = getTextureCacheKey( texture ); 24662 24663 if ( textureCacheKey !== textureProperties.__cacheKey ) { 24664 24665 // if not, create a new instance of WebGLTexture 24666 24667 if ( webglTextures[ textureCacheKey ] === undefined ) { 24668 24669 // create new entry 24670 24671 webglTextures[ textureCacheKey ] = { 24672 texture: _gl.createTexture(), 24673 usedTimes: 0 24674 }; 24675 24676 info.memory.textures ++; 24677 24678 // when a new instance of WebGLTexture was created, a texture upload is required 24679 // even if the image contents are identical 24680 24681 forceUpload = true; 24682 24683 } 24684 24685 webglTextures[ textureCacheKey ].usedTimes ++; 24686 24687 // every time the texture cache key changes, it's necessary to check if an instance of 24688 // WebGLTexture can be deleted in order to avoid a memory leak. 24689 24690 const webglTexture = webglTextures[ textureProperties.__cacheKey ]; 24691 24692 if ( webglTexture !== undefined ) { 24693 24694 webglTextures[ textureProperties.__cacheKey ].usedTimes --; 24695 24696 if ( webglTexture.usedTimes === 0 ) { 24697 24698 deleteTexture( texture ); 24699 24700 } 24701 24702 } 24703 24704 // store references to cache key and WebGLTexture object 24705 24706 textureProperties.__cacheKey = textureCacheKey; 24707 textureProperties.__webglTexture = webglTextures[ textureCacheKey ].texture; 24708 24709 } 24710 24711 return forceUpload; 24712 24713 } 24714 24715 function uploadTexture( textureProperties, texture, slot ) { 24716 24717 let textureType = _gl.TEXTURE_2D; 24718 24719 if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) textureType = _gl.TEXTURE_2D_ARRAY; 24720 if ( texture.isData3DTexture ) textureType = _gl.TEXTURE_3D; 24721 24722 const forceUpload = initTexture( textureProperties, texture ); 24723 const source = texture.source; 24724 24725 state.bindTexture( textureType, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); 24726 24727 const sourceProperties = properties.get( source ); 24728 24729 if ( source.version !== sourceProperties.__version || forceUpload === true ) { 24730 24731 state.activeTexture( _gl.TEXTURE0 + slot ); 24732 24733 const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace ); 24734 const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace ); 24735 const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL; 24736 24737 _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); 24738 _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); 24739 _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); 24740 _gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion ); 24741 24742 const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo$1( texture.image ) === false; 24743 let image = resizeImage( texture.image, needsPowerOfTwo, false, capabilities.maxTextureSize ); 24744 image = verifyColorSpace( texture, image ); 24745 24746 const supportsMips = isPowerOfTwo$1( image ) || isWebGL2, 24747 glFormat = utils.convert( texture.format, texture.colorSpace ); 24748 24749 let glType = utils.convert( texture.type ), 24750 glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture ); 24751 24752 setTextureParameters( textureType, texture, supportsMips ); 24753 24754 let mipmap; 24755 const mipmaps = texture.mipmaps; 24756 24757 const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true && glInternalFormat !== RGB_ETC1_Format ); 24758 const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true ); 24759 const levels = getMipLevels( texture, image, supportsMips ); 24760 24761 if ( texture.isDepthTexture ) { 24762 24763 // populate depth texture with dummy data 24764 24765 glInternalFormat = _gl.DEPTH_COMPONENT; 24766 24767 if ( isWebGL2 ) { 24768 24769 if ( texture.type === FloatType ) { 24770 24771 glInternalFormat = _gl.DEPTH_COMPONENT32F; 24772 24773 } else if ( texture.type === UnsignedIntType ) { 24774 24775 glInternalFormat = _gl.DEPTH_COMPONENT24; 24776 24777 } else if ( texture.type === UnsignedInt248Type ) { 24778 24779 glInternalFormat = _gl.DEPTH24_STENCIL8; 24780 24781 } else { 24782 24783 glInternalFormat = _gl.DEPTH_COMPONENT16; // WebGL2 requires sized internalformat for glTexImage2D 24784 24785 } 24786 24787 } else { 24788 24789 if ( texture.type === FloatType ) { 24790 24791 console.error( 'WebGLRenderer: Floating point depth texture requires WebGL2.' ); 24792 24793 } 24794 24795 } 24796 24797 // validation checks for WebGL 1 24798 24799 if ( texture.format === DepthFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) { 24800 24801 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are 24802 // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT 24803 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) 24804 if ( texture.type !== UnsignedShortType && texture.type !== UnsignedIntType ) { 24805 24806 console.warn( 'THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.' ); 24807 24808 texture.type = UnsignedIntType; 24809 glType = utils.convert( texture.type ); 24810 24811 } 24812 24813 } 24814 24815 if ( texture.format === DepthStencilFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) { 24816 24817 // Depth stencil textures need the DEPTH_STENCIL internal format 24818 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) 24819 glInternalFormat = _gl.DEPTH_STENCIL; 24820 24821 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are 24822 // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL. 24823 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) 24824 if ( texture.type !== UnsignedInt248Type ) { 24825 24826 console.warn( 'THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.' ); 24827 24828 texture.type = UnsignedInt248Type; 24829 glType = utils.convert( texture.type ); 24830 24831 } 24832 24833 } 24834 24835 // 24836 24837 if ( allocateMemory ) { 24838 24839 if ( useTexStorage ) { 24840 24841 state.texStorage2D( _gl.TEXTURE_2D, 1, glInternalFormat, image.width, image.height ); 24842 24843 } else { 24844 24845 state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null ); 24846 24847 } 24848 24849 } 24850 24851 } else if ( texture.isDataTexture ) { 24852 24853 // use manually created mipmaps if available 24854 // if there are no manual mipmaps 24855 // set 0 level mipmap and then use GL to generate other mipmap levels 24856 24857 if ( mipmaps.length > 0 && supportsMips ) { 24858 24859 if ( useTexStorage && allocateMemory ) { 24860 24861 state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); 24862 24863 } 24864 24865 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { 24866 24867 mipmap = mipmaps[ i ]; 24868 24869 if ( useTexStorage ) { 24870 24871 state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); 24872 24873 } else { 24874 24875 state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); 24876 24877 } 24878 24879 } 24880 24881 texture.generateMipmaps = false; 24882 24883 } else { 24884 24885 if ( useTexStorage ) { 24886 24887 if ( allocateMemory ) { 24888 24889 state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); 24890 24891 } 24892 24893 state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data ); 24894 24895 } else { 24896 24897 state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data ); 24898 24899 } 24900 24901 } 24902 24903 } else if ( texture.isCompressedTexture ) { 24904 24905 if ( texture.isCompressedArrayTexture ) { 24906 24907 if ( useTexStorage && allocateMemory ) { 24908 24909 state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height, image.depth ); 24910 24911 } 24912 24913 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { 24914 24915 mipmap = mipmaps[ i ]; 24916 24917 if ( texture.format !== RGBAFormat ) { 24918 24919 if ( glFormat !== null ) { 24920 24921 if ( useTexStorage ) { 24922 24923 state.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0 ); 24924 24925 } else { 24926 24927 state.compressedTexImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, mipmap.data, 0, 0 ); 24928 24929 } 24930 24931 } else { 24932 24933 console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' ); 24934 24935 } 24936 24937 } else { 24938 24939 if ( useTexStorage ) { 24940 24941 state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data ); 24942 24943 } else { 24944 24945 state.texImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, glFormat, glType, mipmap.data ); 24946 24947 } 24948 24949 } 24950 24951 } 24952 24953 } else { 24954 24955 if ( useTexStorage && allocateMemory ) { 24956 24957 state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); 24958 24959 } 24960 24961 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { 24962 24963 mipmap = mipmaps[ i ]; 24964 24965 if ( texture.format !== RGBAFormat ) { 24966 24967 if ( glFormat !== null ) { 24968 24969 if ( useTexStorage ) { 24970 24971 state.compressedTexSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); 24972 24973 } else { 24974 24975 state.compressedTexImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); 24976 24977 } 24978 24979 } else { 24980 24981 console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' ); 24982 24983 } 24984 24985 } else { 24986 24987 if ( useTexStorage ) { 24988 24989 state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); 24990 24991 } else { 24992 24993 state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); 24994 24995 } 24996 24997 } 24998 24999 } 25000 25001 } 25002 25003 } else if ( texture.isDataArrayTexture ) { 25004 25005 if ( useTexStorage ) { 25006 25007 if ( allocateMemory ) { 25008 25009 state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, image.width, image.height, image.depth ); 25010 25011 } 25012 25013 state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); 25014 25015 } else { 25016 25017 state.texImage3D( _gl.TEXTURE_2D_ARRAY, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); 25018 25019 } 25020 25021 } else if ( texture.isData3DTexture ) { 25022 25023 if ( useTexStorage ) { 25024 25025 if ( allocateMemory ) { 25026 25027 state.texStorage3D( _gl.TEXTURE_3D, levels, glInternalFormat, image.width, image.height, image.depth ); 25028 25029 } 25030 25031 state.texSubImage3D( _gl.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); 25032 25033 } else { 25034 25035 state.texImage3D( _gl.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); 25036 25037 } 25038 25039 } else if ( texture.isFramebufferTexture ) { 25040 25041 if ( allocateMemory ) { 25042 25043 if ( useTexStorage ) { 25044 25045 state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); 25046 25047 } else { 25048 25049 let width = image.width, height = image.height; 25050 25051 for ( let i = 0; i < levels; i ++ ) { 25052 25053 state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, width, height, 0, glFormat, glType, null ); 25054 25055 width >>= 1; 25056 height >>= 1; 25057 25058 } 25059 25060 } 25061 25062 } 25063 25064 } else { 25065 25066 // regular Texture (image, video, canvas) 25067 25068 // use manually created mipmaps if available 25069 // if there are no manual mipmaps 25070 // set 0 level mipmap and then use GL to generate other mipmap levels 25071 25072 if ( mipmaps.length > 0 && supportsMips ) { 25073 25074 if ( useTexStorage && allocateMemory ) { 25075 25076 state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); 25077 25078 } 25079 25080 for ( let i = 0, il = mipmaps.length; i < il; i ++ ) { 25081 25082 mipmap = mipmaps[ i ]; 25083 25084 if ( useTexStorage ) { 25085 25086 state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, glFormat, glType, mipmap ); 25087 25088 } else { 25089 25090 state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap ); 25091 25092 } 25093 25094 } 25095 25096 texture.generateMipmaps = false; 25097 25098 } else { 25099 25100 if ( useTexStorage ) { 25101 25102 if ( allocateMemory ) { 25103 25104 state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); 25105 25106 } 25107 25108 state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, glFormat, glType, image ); 25109 25110 } else { 25111 25112 state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image ); 25113 25114 } 25115 25116 } 25117 25118 } 25119 25120 if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { 25121 25122 generateMipmap( textureType ); 25123 25124 } 25125 25126 sourceProperties.__version = source.version; 25127 25128 if ( texture.onUpdate ) texture.onUpdate( texture ); 25129 25130 } 25131 25132 textureProperties.__version = texture.version; 25133 25134 } 25135 25136 function uploadCubeTexture( textureProperties, texture, slot ) { 25137 25138 if ( texture.image.length !== 6 ) return; 25139 25140 const forceUpload = initTexture( textureProperties, texture ); 25141 const source = texture.source; 25142 25143 state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); 25144 25145 const sourceProperties = properties.get( source ); 25146 25147 if ( source.version !== sourceProperties.__version || forceUpload === true ) { 25148 25149 state.activeTexture( _gl.TEXTURE0 + slot ); 25150 25151 const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace ); 25152 const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace ); 25153 const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL; 25154 25155 _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); 25156 _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); 25157 _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); 25158 _gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion ); 25159 25160 const isCompressed = ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture ); 25161 const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture ); 25162 25163 const cubeImage = []; 25164 25165 for ( let i = 0; i < 6; i ++ ) { 25166 25167 if ( ! isCompressed && ! isDataTexture ) { 25168 25169 cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, capabilities.maxCubemapSize ); 25170 25171 } else { 25172 25173 cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ]; 25174 25175 } 25176 25177 cubeImage[ i ] = verifyColorSpace( texture, cubeImage[ i ] ); 25178 25179 } 25180 25181 const image = cubeImage[ 0 ], 25182 supportsMips = isPowerOfTwo$1( image ) || isWebGL2, 25183 glFormat = utils.convert( texture.format, texture.colorSpace ), 25184 glType = utils.convert( texture.type ), 25185 glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace ); 25186 25187 const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true ); 25188 const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true ); 25189 let levels = getMipLevels( texture, image, supportsMips ); 25190 25191 setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips ); 25192 25193 let mipmaps; 25194 25195 if ( isCompressed ) { 25196 25197 if ( useTexStorage && allocateMemory ) { 25198 25199 state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, image.width, image.height ); 25200 25201 } 25202 25203 for ( let i = 0; i < 6; i ++ ) { 25204 25205 mipmaps = cubeImage[ i ].mipmaps; 25206 25207 for ( let j = 0; j < mipmaps.length; j ++ ) { 25208 25209 const mipmap = mipmaps[ j ]; 25210 25211 if ( texture.format !== RGBAFormat ) { 25212 25213 if ( glFormat !== null ) { 25214 25215 if ( useTexStorage ) { 25216 25217 state.compressedTexSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); 25218 25219 } else { 25220 25221 state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); 25222 25223 } 25224 25225 } else { 25226 25227 console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' ); 25228 25229 } 25230 25231 } else { 25232 25233 if ( useTexStorage ) { 25234 25235 state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); 25236 25237 } else { 25238 25239 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); 25240 25241 } 25242 25243 } 25244 25245 } 25246 25247 } 25248 25249 } else { 25250 25251 mipmaps = texture.mipmaps; 25252 25253 if ( useTexStorage && allocateMemory ) { 25254 25255 // TODO: Uniformly handle mipmap definitions 25256 // Normal textures and compressed cube textures define base level + mips with their mipmap array 25257 // Uncompressed cube textures use their mipmap array only for mips (no base level) 25258 25259 if ( mipmaps.length > 0 ) levels ++; 25260 25261 state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, cubeImage[ 0 ].width, cubeImage[ 0 ].height ); 25262 25263 } 25264 25265 for ( let i = 0; i < 6; i ++ ) { 25266 25267 if ( isDataTexture ) { 25268 25269 if ( useTexStorage ) { 25270 25271 state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, cubeImage[ i ].width, cubeImage[ i ].height, glFormat, glType, cubeImage[ i ].data ); 25272 25273 } else { 25274 25275 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); 25276 25277 } 25278 25279 for ( let j = 0; j < mipmaps.length; j ++ ) { 25280 25281 const mipmap = mipmaps[ j ]; 25282 const mipmapImage = mipmap.image[ i ].image; 25283 25284 if ( useTexStorage ) { 25285 25286 state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data ); 25287 25288 } else { 25289 25290 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data ); 25291 25292 } 25293 25294 } 25295 25296 } else { 25297 25298 if ( useTexStorage ) { 25299 25300 state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] ); 25301 25302 } else { 25303 25304 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] ); 25305 25306 } 25307 25308 for ( let j = 0; j < mipmaps.length; j ++ ) { 25309 25310 const mipmap = mipmaps[ j ]; 25311 25312 if ( useTexStorage ) { 25313 25314 state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] ); 25315 25316 } else { 25317 25318 state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] ); 25319 25320 } 25321 25322 } 25323 25324 } 25325 25326 } 25327 25328 } 25329 25330 if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { 25331 25332 // We assume images for cube map have the same size. 25333 generateMipmap( _gl.TEXTURE_CUBE_MAP ); 25334 25335 } 25336 25337 sourceProperties.__version = source.version; 25338 25339 if ( texture.onUpdate ) texture.onUpdate( texture ); 25340 25341 } 25342 25343 textureProperties.__version = texture.version; 25344 25345 } 25346 25347 // Render targets 25348 25349 // Setup storage for target texture and bind it to correct framebuffer 25350 function setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget, level ) { 25351 25352 const glFormat = utils.convert( texture.format, texture.colorSpace ); 25353 const glType = utils.convert( texture.type ); 25354 const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace ); 25355 const renderTargetProperties = properties.get( renderTarget ); 25356 25357 if ( ! renderTargetProperties.__hasExternalTextures ) { 25358 25359 const width = Math.max( 1, renderTarget.width >> level ); 25360 const height = Math.max( 1, renderTarget.height >> level ); 25361 25362 if ( textureTarget === _gl.TEXTURE_3D || textureTarget === _gl.TEXTURE_2D_ARRAY ) { 25363 25364 state.texImage3D( textureTarget, level, glInternalFormat, width, height, renderTarget.depth, 0, glFormat, glType, null ); 25365 25366 } else { 25367 25368 state.texImage2D( textureTarget, level, glInternalFormat, width, height, 0, glFormat, glType, null ); 25369 25370 } 25371 25372 } 25373 25374 state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); 25375 25376 if ( useMultisampledRTT( renderTarget ) ) { 25377 25378 multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, 0, getRenderTargetSamples( renderTarget ) ); 25379 25380 } else if ( textureTarget === _gl.TEXTURE_2D || ( textureTarget >= _gl.TEXTURE_CUBE_MAP_POSITIVE_X && textureTarget <= _gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ) ) { // see #24753 25381 25382 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, level ); 25383 25384 } 25385 25386 state.bindFramebuffer( _gl.FRAMEBUFFER, null ); 25387 25388 } 25389 25390 25391 // Setup storage for internal depth/stencil buffers and bind to correct framebuffer 25392 function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) { 25393 25394 _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); 25395 25396 if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { 25397 25398 let glInternalFormat = ( isWebGL2 === true ) ? _gl.DEPTH_COMPONENT24 : _gl.DEPTH_COMPONENT16; 25399 25400 if ( isMultisample || useMultisampledRTT( renderTarget ) ) { 25401 25402 const depthTexture = renderTarget.depthTexture; 25403 25404 if ( depthTexture && depthTexture.isDepthTexture ) { 25405 25406 if ( depthTexture.type === FloatType ) { 25407 25408 glInternalFormat = _gl.DEPTH_COMPONENT32F; 25409 25410 } else if ( depthTexture.type === UnsignedIntType ) { 25411 25412 glInternalFormat = _gl.DEPTH_COMPONENT24; 25413 25414 } 25415 25416 } 25417 25418 const samples = getRenderTargetSamples( renderTarget ); 25419 25420 if ( useMultisampledRTT( renderTarget ) ) { 25421 25422 multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); 25423 25424 } else { 25425 25426 _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); 25427 25428 } 25429 25430 } else { 25431 25432 _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height ); 25433 25434 } 25435 25436 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); 25437 25438 } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { 25439 25440 const samples = getRenderTargetSamples( renderTarget ); 25441 25442 if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) { 25443 25444 _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height ); 25445 25446 } else if ( useMultisampledRTT( renderTarget ) ) { 25447 25448 multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height ); 25449 25450 } else { 25451 25452 _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); 25453 25454 } 25455 25456 25457 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); 25458 25459 } else { 25460 25461 const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [ renderTarget.texture ]; 25462 25463 for ( let i = 0; i < textures.length; i ++ ) { 25464 25465 const texture = textures[ i ]; 25466 25467 const glFormat = utils.convert( texture.format, texture.colorSpace ); 25468 const glType = utils.convert( texture.type ); 25469 const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace ); 25470 const samples = getRenderTargetSamples( renderTarget ); 25471 25472 if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) { 25473 25474 _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); 25475 25476 } else if ( useMultisampledRTT( renderTarget ) ) { 25477 25478 multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); 25479 25480 } else { 25481 25482 _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height ); 25483 25484 } 25485 25486 } 25487 25488 } 25489 25490 _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); 25491 25492 } 25493 25494 // Setup resources for a Depth Texture for a FBO (needs an extension) 25495 function setupDepthTexture( framebuffer, renderTarget ) { 25496 25497 const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget ); 25498 if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' ); 25499 25500 state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); 25501 25502 if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) { 25503 25504 throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' ); 25505 25506 } 25507 25508 // upload an empty depth texture with framebuffer size 25509 if ( ! properties.get( renderTarget.depthTexture ).__webglTexture || 25510 renderTarget.depthTexture.image.width !== renderTarget.width || 25511 renderTarget.depthTexture.image.height !== renderTarget.height ) { 25512 25513 renderTarget.depthTexture.image.width = renderTarget.width; 25514 renderTarget.depthTexture.image.height = renderTarget.height; 25515 renderTarget.depthTexture.needsUpdate = true; 25516 25517 } 25518 25519 setTexture2D( renderTarget.depthTexture, 0 ); 25520 25521 const webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture; 25522 const samples = getRenderTargetSamples( renderTarget ); 25523 25524 if ( renderTarget.depthTexture.format === DepthFormat ) { 25525 25526 if ( useMultisampledRTT( renderTarget ) ) { 25527 25528 multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples ); 25529 25530 } else { 25531 25532 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); 25533 25534 } 25535 25536 } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) { 25537 25538 if ( useMultisampledRTT( renderTarget ) ) { 25539 25540 multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples ); 25541 25542 } else { 25543 25544 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); 25545 25546 } 25547 25548 } else { 25549 25550 throw new Error( 'Unknown depthTexture format' ); 25551 25552 } 25553 25554 } 25555 25556 // Setup GL resources for a non-texture depth buffer 25557 function setupDepthRenderbuffer( renderTarget ) { 25558 25559 const renderTargetProperties = properties.get( renderTarget ); 25560 const isCube = ( renderTarget.isWebGLCubeRenderTarget === true ); 25561 25562 if ( renderTarget.depthTexture && ! renderTargetProperties.__autoAllocateDepthBuffer ) { 25563 25564 if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' ); 25565 25566 setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget ); 25567 25568 } else { 25569 25570 if ( isCube ) { 25571 25572 renderTargetProperties.__webglDepthbuffer = []; 25573 25574 for ( let i = 0; i < 6; i ++ ) { 25575 25576 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] ); 25577 renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer(); 25578 setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false ); 25579 25580 } 25581 25582 } else { 25583 25584 25585 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); 25586 renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer(); 25587 setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false ); 25588 25589 } 25590 25591 } 25592 25593 state.bindFramebuffer( _gl.FRAMEBUFFER, null ); 25594 25595 } 25596 25597 // rebind framebuffer with external textures 25598 function rebindTextures( renderTarget, colorTexture, depthTexture ) { 25599 25600 const renderTargetProperties = properties.get( renderTarget ); 25601 25602 if ( colorTexture !== undefined ) { 25603 25604 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, 0 ); 25605 25606 } 25607 25608 if ( depthTexture !== undefined ) { 25609 25610 setupDepthRenderbuffer( renderTarget ); 25611 25612 } 25613 25614 } 25615 25616 // Set up GL resources for the render target 25617 function setupRenderTarget( renderTarget ) { 25618 25619 const texture = renderTarget.texture; 25620 25621 const renderTargetProperties = properties.get( renderTarget ); 25622 const textureProperties = properties.get( texture ); 25623 25624 renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); 25625 25626 if ( renderTarget.isWebGLMultipleRenderTargets !== true ) { 25627 25628 if ( textureProperties.__webglTexture === undefined ) { 25629 25630 textureProperties.__webglTexture = _gl.createTexture(); 25631 25632 } 25633 25634 textureProperties.__version = texture.version; 25635 info.memory.textures ++; 25636 25637 } 25638 25639 const isCube = ( renderTarget.isWebGLCubeRenderTarget === true ); 25640 const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true ); 25641 const supportsMips = isPowerOfTwo$1( renderTarget ) || isWebGL2; 25642 25643 // Setup framebuffer 25644 25645 if ( isCube ) { 25646 25647 renderTargetProperties.__webglFramebuffer = []; 25648 25649 for ( let i = 0; i < 6; i ++ ) { 25650 25651 if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { 25652 25653 renderTargetProperties.__webglFramebuffer[ i ] = []; 25654 25655 for ( let level = 0; level < texture.mipmaps.length; level ++ ) { 25656 25657 renderTargetProperties.__webglFramebuffer[ i ][ level ] = _gl.createFramebuffer(); 25658 25659 } 25660 25661 } else { 25662 25663 renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); 25664 25665 } 25666 25667 } 25668 25669 } else { 25670 25671 if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { 25672 25673 renderTargetProperties.__webglFramebuffer = []; 25674 25675 for ( let level = 0; level < texture.mipmaps.length; level ++ ) { 25676 25677 renderTargetProperties.__webglFramebuffer[ level ] = _gl.createFramebuffer(); 25678 25679 } 25680 25681 } else { 25682 25683 renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); 25684 25685 } 25686 25687 if ( isMultipleRenderTargets ) { 25688 25689 if ( capabilities.drawBuffers ) { 25690 25691 const textures = renderTarget.texture; 25692 25693 for ( let i = 0, il = textures.length; i < il; i ++ ) { 25694 25695 const attachmentProperties = properties.get( textures[ i ] ); 25696 25697 if ( attachmentProperties.__webglTexture === undefined ) { 25698 25699 attachmentProperties.__webglTexture = _gl.createTexture(); 25700 25701 info.memory.textures ++; 25702 25703 } 25704 25705 } 25706 25707 } else { 25708 25709 console.warn( 'THREE.WebGLRenderer: WebGLMultipleRenderTargets can only be used with WebGL2 or WEBGL_draw_buffers extension.' ); 25710 25711 } 25712 25713 } 25714 25715 if ( ( isWebGL2 && renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) { 25716 25717 const textures = isMultipleRenderTargets ? texture : [ texture ]; 25718 25719 renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer(); 25720 renderTargetProperties.__webglColorRenderbuffer = []; 25721 25722 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); 25723 25724 for ( let i = 0; i < textures.length; i ++ ) { 25725 25726 const texture = textures[ i ]; 25727 renderTargetProperties.__webglColorRenderbuffer[ i ] = _gl.createRenderbuffer(); 25728 25729 _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); 25730 25731 const glFormat = utils.convert( texture.format, texture.colorSpace ); 25732 const glType = utils.convert( texture.type ); 25733 const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, renderTarget.isXRRenderTarget === true ); 25734 const samples = getRenderTargetSamples( renderTarget ); 25735 _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); 25736 25737 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); 25738 25739 } 25740 25741 _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); 25742 25743 if ( renderTarget.depthBuffer ) { 25744 25745 renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer(); 25746 setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true ); 25747 25748 } 25749 25750 state.bindFramebuffer( _gl.FRAMEBUFFER, null ); 25751 25752 } 25753 25754 } 25755 25756 // Setup color buffer 25757 25758 if ( isCube ) { 25759 25760 state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture ); 25761 setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips ); 25762 25763 for ( let i = 0; i < 6; i ++ ) { 25764 25765 if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { 25766 25767 for ( let level = 0; level < texture.mipmaps.length; level ++ ) { 25768 25769 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ][ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level ); 25770 25771 } 25772 25773 } else { 25774 25775 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0 ); 25776 25777 } 25778 25779 } 25780 25781 if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { 25782 25783 generateMipmap( _gl.TEXTURE_CUBE_MAP ); 25784 25785 } 25786 25787 state.unbindTexture(); 25788 25789 } else if ( isMultipleRenderTargets ) { 25790 25791 const textures = renderTarget.texture; 25792 25793 for ( let i = 0, il = textures.length; i < il; i ++ ) { 25794 25795 const attachment = textures[ i ]; 25796 const attachmentProperties = properties.get( attachment ); 25797 25798 state.bindTexture( _gl.TEXTURE_2D, attachmentProperties.__webglTexture ); 25799 setTextureParameters( _gl.TEXTURE_2D, attachment, supportsMips ); 25800 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, 0 ); 25801 25802 if ( textureNeedsGenerateMipmaps( attachment, supportsMips ) ) { 25803 25804 generateMipmap( _gl.TEXTURE_2D ); 25805 25806 } 25807 25808 } 25809 25810 state.unbindTexture(); 25811 25812 } else { 25813 25814 let glTextureType = _gl.TEXTURE_2D; 25815 25816 if ( renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) { 25817 25818 if ( isWebGL2 ) { 25819 25820 glTextureType = renderTarget.isWebGL3DRenderTarget ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY; 25821 25822 } else { 25823 25824 console.error( 'THREE.WebGLTextures: THREE.Data3DTexture and THREE.DataArrayTexture only supported with WebGL2.' ); 25825 25826 } 25827 25828 } 25829 25830 state.bindTexture( glTextureType, textureProperties.__webglTexture ); 25831 setTextureParameters( glTextureType, texture, supportsMips ); 25832 25833 if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { 25834 25835 for ( let level = 0; level < texture.mipmaps.length; level ++ ) { 25836 25837 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, level ); 25838 25839 } 25840 25841 } else { 25842 25843 setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, 0 ); 25844 25845 } 25846 25847 if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { 25848 25849 generateMipmap( glTextureType ); 25850 25851 } 25852 25853 state.unbindTexture(); 25854 25855 } 25856 25857 // Setup depth and stencil buffers 25858 25859 if ( renderTarget.depthBuffer ) { 25860 25861 setupDepthRenderbuffer( renderTarget ); 25862 25863 } 25864 25865 } 25866 25867 function updateRenderTargetMipmap( renderTarget ) { 25868 25869 const supportsMips = isPowerOfTwo$1( renderTarget ) || isWebGL2; 25870 25871 const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [ renderTarget.texture ]; 25872 25873 for ( let i = 0, il = textures.length; i < il; i ++ ) { 25874 25875 const texture = textures[ i ]; 25876 25877 if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { 25878 25879 const target = renderTarget.isWebGLCubeRenderTarget ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D; 25880 const webglTexture = properties.get( texture ).__webglTexture; 25881 25882 state.bindTexture( target, webglTexture ); 25883 generateMipmap( target ); 25884 state.unbindTexture(); 25885 25886 } 25887 25888 } 25889 25890 } 25891 25892 function updateMultisampleRenderTarget( renderTarget ) { 25893 25894 if ( ( isWebGL2 && renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) { 25895 25896 const textures = renderTarget.isWebGLMultipleRenderTargets ? renderTarget.texture : [ renderTarget.texture ]; 25897 const width = renderTarget.width; 25898 const height = renderTarget.height; 25899 let mask = _gl.COLOR_BUFFER_BIT; 25900 const invalidationArray = []; 25901 const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT; 25902 const renderTargetProperties = properties.get( renderTarget ); 25903 const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true ); 25904 25905 // If MRT we need to remove FBO attachments 25906 if ( isMultipleRenderTargets ) { 25907 25908 for ( let i = 0; i < textures.length; i ++ ) { 25909 25910 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); 25911 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, null ); 25912 25913 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); 25914 _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, null, 0 ); 25915 25916 } 25917 25918 } 25919 25920 state.bindFramebuffer( _gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); 25921 state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); 25922 25923 for ( let i = 0; i < textures.length; i ++ ) { 25924 25925 invalidationArray.push( _gl.COLOR_ATTACHMENT0 + i ); 25926 25927 if ( renderTarget.depthBuffer ) { 25928 25929 invalidationArray.push( depthStyle ); 25930 25931 } 25932 25933 const ignoreDepthValues = ( renderTargetProperties.__ignoreDepthValues !== undefined ) ? renderTargetProperties.__ignoreDepthValues : false; 25934 25935 if ( ignoreDepthValues === false ) { 25936 25937 if ( renderTarget.depthBuffer ) mask |= _gl.DEPTH_BUFFER_BIT; 25938 if ( renderTarget.stencilBuffer ) mask |= _gl.STENCIL_BUFFER_BIT; 25939 25940 } 25941 25942 if ( isMultipleRenderTargets ) { 25943 25944 _gl.framebufferRenderbuffer( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); 25945 25946 } 25947 25948 if ( ignoreDepthValues === true ) { 25949 25950 _gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, [ depthStyle ] ); 25951 _gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, [ depthStyle ] ); 25952 25953 } 25954 25955 if ( isMultipleRenderTargets ) { 25956 25957 const webglTexture = properties.get( textures[ i ] ).__webglTexture; 25958 _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, webglTexture, 0 ); 25959 25960 } 25961 25962 _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST ); 25963 25964 if ( supportsInvalidateFramebuffer ) { 25965 25966 _gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, invalidationArray ); 25967 25968 } 25969 25970 25971 } 25972 25973 state.bindFramebuffer( _gl.READ_FRAMEBUFFER, null ); 25974 state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, null ); 25975 25976 // If MRT since pre-blit we removed the FBO we need to reconstruct the attachments 25977 if ( isMultipleRenderTargets ) { 25978 25979 for ( let i = 0; i < textures.length; i ++ ) { 25980 25981 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); 25982 _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); 25983 25984 const webglTexture = properties.get( textures[ i ] ).__webglTexture; 25985 25986 state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); 25987 _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, webglTexture, 0 ); 25988 25989 } 25990 25991 } 25992 25993 state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); 25994 25995 } 25996 25997 } 25998 25999 function getRenderTargetSamples( renderTarget ) { 26000 26001 return Math.min( capabilities.maxSamples, renderTarget.samples ); 26002 26003 } 26004 26005 function useMultisampledRTT( renderTarget ) { 26006 26007 const renderTargetProperties = properties.get( renderTarget ); 26008 26009 return isWebGL2 && renderTarget.samples > 0 && extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true && renderTargetProperties.__useRenderToTexture !== false; 26010 26011 } 26012 26013 function updateVideoTexture( texture ) { 26014 26015 const frame = info.render.frame; 26016 26017 // Check the last frame we updated the VideoTexture 26018 26019 if ( _videoTextures.get( texture ) !== frame ) { 26020 26021 _videoTextures.set( texture, frame ); 26022 texture.update(); 26023 26024 } 26025 26026 } 26027 26028 function verifyColorSpace( texture, image ) { 26029 26030 const colorSpace = texture.colorSpace; 26031 const format = texture.format; 26032 const type = texture.type; 26033 26034 if ( texture.isCompressedTexture === true || texture.isVideoTexture === true || texture.format === _SRGBAFormat ) return image; 26035 26036 if ( colorSpace !== LinearSRGBColorSpace && colorSpace !== NoColorSpace ) { 26037 26038 // sRGB 26039 26040 if ( ColorManagement.getTransfer( colorSpace ) === SRGBTransfer ) { 26041 26042 if ( isWebGL2 === false ) { 26043 26044 // in WebGL 1, try to use EXT_sRGB extension and unsized formats 26045 26046 if ( extensions.has( 'EXT_sRGB' ) === true && format === RGBAFormat ) { 26047 26048 texture.format = _SRGBAFormat; 26049 26050 // it's not possible to generate mips in WebGL 1 with this extension 26051 26052 texture.minFilter = LinearFilter; 26053 texture.generateMipmaps = false; 26054 26055 } else { 26056 26057 // slow fallback (CPU decode) 26058 26059 image = ImageUtils.sRGBToLinear( image ); 26060 26061 } 26062 26063 } else { 26064 26065 // in WebGL 2 uncompressed textures can only be sRGB encoded if they have the RGBA8 format 26066 26067 if ( format !== RGBAFormat || type !== UnsignedByteType ) { 26068 26069 console.warn( 'THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType.' ); 26070 26071 } 26072 26073 } 26074 26075 } else { 26076 26077 console.error( 'THREE.WebGLTextures: Unsupported texture color space:', colorSpace ); 26078 26079 } 26080 26081 } 26082 26083 return image; 26084 26085 } 26086 26087 // 26088 26089 this.allocateTextureUnit = allocateTextureUnit; 26090 this.resetTextureUnits = resetTextureUnits; 26091 26092 this.setTexture2D = setTexture2D; 26093 this.setTexture2DArray = setTexture2DArray; 26094 this.setTexture3D = setTexture3D; 26095 this.setTextureCube = setTextureCube; 26096 this.rebindTextures = rebindTextures; 26097 this.setupRenderTarget = setupRenderTarget; 26098 this.updateRenderTargetMipmap = updateRenderTargetMipmap; 26099 this.updateMultisampleRenderTarget = updateMultisampleRenderTarget; 26100 this.setupDepthRenderbuffer = setupDepthRenderbuffer; 26101 this.setupFrameBufferTexture = setupFrameBufferTexture; 26102 this.useMultisampledRTT = useMultisampledRTT; 26103 26104} 26105 26106function WebGLUtils( gl, extensions, capabilities ) { 26107 26108 const isWebGL2 = capabilities.isWebGL2; 26109 26110 function convert( p, colorSpace = NoColorSpace ) { 26111 26112 let extension; 26113 26114 const transfer = ColorManagement.getTransfer( colorSpace ); 26115 26116 if ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE; 26117 if ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4; 26118 if ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1; 26119 26120 if ( p === ByteType ) return gl.BYTE; 26121 if ( p === ShortType ) return gl.SHORT; 26122 if ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT; 26123 if ( p === IntType ) return gl.INT; 26124 if ( p === UnsignedIntType ) return gl.UNSIGNED_INT; 26125 if ( p === FloatType ) return gl.FLOAT; 26126 26127 if ( p === HalfFloatType ) { 26128 26129 if ( isWebGL2 ) return gl.HALF_FLOAT; 26130 26131 extension = extensions.get( 'OES_texture_half_float' ); 26132 26133 if ( extension !== null ) { 26134 26135 return extension.HALF_FLOAT_OES; 26136 26137 } else { 26138 26139 return null; 26140 26141 } 26142 26143 } 26144 26145 if ( p === AlphaFormat ) return gl.ALPHA; 26146 if ( p === RGBAFormat ) return gl.RGBA; 26147 if ( p === LuminanceFormat ) return gl.LUMINANCE; 26148 if ( p === LuminanceAlphaFormat ) return gl.LUMINANCE_ALPHA; 26149 if ( p === DepthFormat ) return gl.DEPTH_COMPONENT; 26150 if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL; 26151 26152 // WebGL 1 sRGB fallback 26153 26154 if ( p === _SRGBAFormat ) { 26155 26156 extension = extensions.get( 'EXT_sRGB' ); 26157 26158 if ( extension !== null ) { 26159 26160 return extension.SRGB_ALPHA_EXT; 26161 26162 } else { 26163 26164 return null; 26165 26166 } 26167 26168 } 26169 26170 // WebGL2 formats. 26171 26172 if ( p === RedFormat ) return gl.RED; 26173 if ( p === RedIntegerFormat ) return gl.RED_INTEGER; 26174 if ( p === RGFormat ) return gl.RG; 26175 if ( p === RGIntegerFormat ) return gl.RG_INTEGER; 26176 if ( p === RGBAIntegerFormat ) return gl.RGBA_INTEGER; 26177 26178 // S3TC 26179 26180 if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) { 26181 26182 if ( transfer === SRGBTransfer ) { 26183 26184 extension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' ); 26185 26186 if ( extension !== null ) { 26187 26188 if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT; 26189 if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; 26190 if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; 26191 if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; 26192 26193 } else { 26194 26195 return null; 26196 26197 } 26198 26199 } else { 26200 26201 extension = extensions.get( 'WEBGL_compressed_texture_s3tc' ); 26202 26203 if ( extension !== null ) { 26204 26205 if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; 26206 if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; 26207 if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; 26208 if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; 26209 26210 } else { 26211 26212 return null; 26213 26214 } 26215 26216 } 26217 26218 } 26219 26220 // PVRTC 26221 26222 if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) { 26223 26224 extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' ); 26225 26226 if ( extension !== null ) { 26227 26228 if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; 26229 if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; 26230 if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; 26231 if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; 26232 26233 } else { 26234 26235 return null; 26236 26237 } 26238 26239 } 26240 26241 // ETC1 26242 26243 if ( p === RGB_ETC1_Format ) { 26244 26245 extension = extensions.get( 'WEBGL_compressed_texture_etc1' ); 26246 26247 if ( extension !== null ) { 26248 26249 return extension.COMPRESSED_RGB_ETC1_WEBGL; 26250 26251 } else { 26252 26253 return null; 26254 26255 } 26256 26257 } 26258 26259 // ETC2 26260 26261 if ( p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) { 26262 26263 extension = extensions.get( 'WEBGL_compressed_texture_etc' ); 26264 26265 if ( extension !== null ) { 26266 26267 if ( p === RGB_ETC2_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2; 26268 if ( p === RGBA_ETC2_EAC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC; 26269 26270 } else { 26271 26272 return null; 26273 26274 } 26275 26276 } 26277 26278 // ASTC 26279 26280 if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format || 26281 p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format || 26282 p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format || 26283 p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format || 26284 p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ) { 26285 26286 extension = extensions.get( 'WEBGL_compressed_texture_astc' ); 26287 26288 if ( extension !== null ) { 26289 26290 if ( p === RGBA_ASTC_4x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR; 26291 if ( p === RGBA_ASTC_5x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR; 26292 if ( p === RGBA_ASTC_5x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR; 26293 if ( p === RGBA_ASTC_6x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR; 26294 if ( p === RGBA_ASTC_6x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR; 26295 if ( p === RGBA_ASTC_8x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR; 26296 if ( p === RGBA_ASTC_8x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR; 26297 if ( p === RGBA_ASTC_8x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR; 26298 if ( p === RGBA_ASTC_10x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR; 26299 if ( p === RGBA_ASTC_10x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR; 26300 if ( p === RGBA_ASTC_10x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR; 26301 if ( p === RGBA_ASTC_10x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR; 26302 if ( p === RGBA_ASTC_12x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR; 26303 if ( p === RGBA_ASTC_12x12_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR; 26304 26305 } else { 26306 26307 return null; 26308 26309 } 26310 26311 } 26312 26313 // BPTC 26314 26315 if ( p === RGBA_BPTC_Format || p === RGB_BPTC_SIGNED_Format || p === RGB_BPTC_UNSIGNED_Format ) { 26316 26317 extension = extensions.get( 'EXT_texture_compression_bptc' ); 26318 26319 if ( extension !== null ) { 26320 26321 if ( p === RGBA_BPTC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT; 26322 if ( p === RGB_BPTC_SIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT; 26323 if ( p === RGB_BPTC_UNSIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT; 26324 26325 } else { 26326 26327 return null; 26328 26329 } 26330 26331 } 26332 26333 // RGTC 26334 26335 if ( p === RED_RGTC1_Format || p === SIGNED_RED_RGTC1_Format || p === RED_GREEN_RGTC2_Format || p === SIGNED_RED_GREEN_RGTC2_Format ) { 26336 26337 extension = extensions.get( 'EXT_texture_compression_rgtc' ); 26338 26339 if ( extension !== null ) { 26340 26341 if ( p === RGBA_BPTC_Format ) return extension.COMPRESSED_RED_RGTC1_EXT; 26342 if ( p === SIGNED_RED_RGTC1_Format ) return extension.COMPRESSED_SIGNED_RED_RGTC1_EXT; 26343 if ( p === RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_RED_GREEN_RGTC2_EXT; 26344 if ( p === SIGNED_RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT; 26345 26346 } else { 26347 26348 return null; 26349 26350 } 26351 26352 } 26353 26354 // 26355 26356 if ( p === UnsignedInt248Type ) { 26357 26358 if ( isWebGL2 ) return gl.UNSIGNED_INT_24_8; 26359 26360 extension = extensions.get( 'WEBGL_depth_texture' ); 26361 26362 if ( extension !== null ) { 26363 26364 return extension.UNSIGNED_INT_24_8_WEBGL; 26365 26366 } else { 26367 26368 return null; 26369 26370 } 26371 26372 } 26373 26374 // if "p" can't be resolved, assume the user defines a WebGL constant as a string (fallback/workaround for packed RGB formats) 26375 26376 return ( gl[ p ] !== undefined ) ? gl[ p ] : null; 26377 26378 } 26379 26380 return { convert: convert }; 26381 26382} 26383 26384class ArrayCamera extends PerspectiveCamera { 26385 26386 constructor( array = [] ) { 26387 26388 super(); 26389 26390 this.isArrayCamera = true; 26391 26392 this.cameras = array; 26393 26394 } 26395 26396} 26397 26398class Group extends Object3D { 26399 26400 constructor() { 26401 26402 super(); 26403 26404 this.isGroup = true; 26405 26406 this.type = 'Group'; 26407 26408 } 26409 26410} 26411 26412const _moveEvent = { type: 'move' }; 26413 26414class WebXRController { 26415 26416 constructor() { 26417 26418 this._targetRay = null; 26419 this._grip = null; 26420 this._hand = null; 26421 26422 } 26423 26424 getHandSpace() { 26425 26426 if ( this._hand === null ) { 26427 26428 this._hand = new Group(); 26429 this._hand.matrixAutoUpdate = false; 26430 this._hand.visible = false; 26431 26432 this._hand.joints = {}; 26433 this._hand.inputState = { pinching: false }; 26434 26435 } 26436 26437 return this._hand; 26438 26439 } 26440 26441 getTargetRaySpace() { 26442 26443 if ( this._targetRay === null ) { 26444 26445 this._targetRay = new Group(); 26446 this._targetRay.matrixAutoUpdate = false; 26447 this._targetRay.visible = false; 26448 this._targetRay.hasLinearVelocity = false; 26449 this._targetRay.linearVelocity = new Vector3(); 26450 this._targetRay.hasAngularVelocity = false; 26451 this._targetRay.angularVelocity = new Vector3(); 26452 26453 } 26454 26455 return this._targetRay; 26456 26457 } 26458 26459 getGripSpace() { 26460 26461 if ( this._grip === null ) { 26462 26463 this._grip = new Group(); 26464 this._grip.matrixAutoUpdate = false; 26465 this._grip.visible = false; 26466 this._grip.hasLinearVelocity = false; 26467 this._grip.linearVelocity = new Vector3(); 26468 this._grip.hasAngularVelocity = false; 26469 this._grip.angularVelocity = new Vector3(); 26470 26471 } 26472 26473 return this._grip; 26474 26475 } 26476 26477 dispatchEvent( event ) { 26478 26479 if ( this._targetRay !== null ) { 26480 26481 this._targetRay.dispatchEvent( event ); 26482 26483 } 26484 26485 if ( this._grip !== null ) { 26486 26487 this._grip.dispatchEvent( event ); 26488 26489 } 26490 26491 if ( this._hand !== null ) { 26492 26493 this._hand.dispatchEvent( event ); 26494 26495 } 26496 26497 return this; 26498 26499 } 26500 26501 connect( inputSource ) { 26502 26503 if ( inputSource && inputSource.hand ) { 26504 26505 const hand = this._hand; 26506 26507 if ( hand ) { 26508 26509 for ( const inputjoint of inputSource.hand.values() ) { 26510 26511 // Initialize hand with joints when connected 26512 this._getHandJoint( hand, inputjoint ); 26513 26514 } 26515 26516 } 26517 26518 } 26519 26520 this.dispatchEvent( { type: 'connected', data: inputSource } ); 26521 26522 return this; 26523 26524 } 26525 26526 disconnect( inputSource ) { 26527 26528 this.dispatchEvent( { type: 'disconnected', data: inputSource } ); 26529 26530 if ( this._targetRay !== null ) { 26531 26532 this._targetRay.visible = false; 26533 26534 } 26535 26536 if ( this._grip !== null ) { 26537 26538 this._grip.visible = false; 26539 26540 } 26541 26542 if ( this._hand !== null ) { 26543 26544 this._hand.visible = false; 26545 26546 } 26547 26548 return this; 26549 26550 } 26551 26552 update( inputSource, frame, referenceSpace ) { 26553 26554 let inputPose = null; 26555 let gripPose = null; 26556 let handPose = null; 26557 26558 const targetRay = this._targetRay; 26559 const grip = this._grip; 26560 const hand = this._hand; 26561 26562 if ( inputSource && frame.session.visibilityState !== 'visible-blurred' ) { 26563 26564 if ( hand && inputSource.hand ) { 26565 26566 handPose = true; 26567 26568 for ( const inputjoint of inputSource.hand.values() ) { 26569 26570 // Update the joints groups with the XRJoint poses 26571 const jointPose = frame.getJointPose( inputjoint, referenceSpace ); 26572 26573 // The transform of this joint will be updated with the joint pose on each frame 26574 const joint = this._getHandJoint( hand, inputjoint ); 26575 26576 if ( jointPose !== null ) { 26577 26578 joint.matrix.fromArray( jointPose.transform.matrix ); 26579 joint.matrix.decompose( joint.position, joint.rotation, joint.scale ); 26580 joint.matrixWorldNeedsUpdate = true; 26581 joint.jointRadius = jointPose.radius; 26582 26583 } 26584 26585 joint.visible = jointPose !== null; 26586 26587 } 26588 26589 // Custom events 26590 26591 // Check pinchz 26592 const indexTip = hand.joints[ 'index-finger-tip' ]; 26593 const thumbTip = hand.joints[ 'thumb-tip' ]; 26594 const distance = indexTip.position.distanceTo( thumbTip.position ); 26595 26596 const distanceToPinch = 0.02; 26597 const threshold = 0.005; 26598 26599 26600 if ( hand.inputState.pinching && distance > distanceToPinch + threshold ) { 26601 26602 hand.inputState.pinching = false; 26603 this.dispatchEvent( { 26604 type: 'pinchend', 26605 handedness: inputSource.handedness, 26606 target: this 26607 } ); 26608 26609 } else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) { 26610 26611 hand.inputState.pinching = true; 26612 this.dispatchEvent( { 26613 type: 'pinchstart', 26614 handedness: inputSource.handedness, 26615 target: this 26616 } ); 26617 26618 } 26619 26620 } else { 26621 26622 if ( grip !== null && inputSource.gripSpace ) { 26623 26624 gripPose = frame.getPose( inputSource.gripSpace, referenceSpace ); 26625 26626 if ( gripPose !== null ) { 26627 26628 grip.matrix.fromArray( gripPose.transform.matrix ); 26629 grip.matrix.decompose( grip.position, grip.rotation, grip.scale ); 26630 grip.matrixWorldNeedsUpdate = true; 26631 26632 if ( gripPose.linearVelocity ) { 26633 26634 grip.hasLinearVelocity = true; 26635 grip.linearVelocity.copy( gripPose.linearVelocity ); 26636 26637 } else { 26638 26639 grip.hasLinearVelocity = false; 26640 26641 } 26642 26643 if ( gripPose.angularVelocity ) { 26644 26645 grip.hasAngularVelocity = true; 26646 grip.angularVelocity.copy( gripPose.angularVelocity ); 26647 26648 } else { 26649 26650 grip.hasAngularVelocity = false; 26651 26652 } 26653 26654 } 26655 26656 } 26657 26658 } 26659 26660 if ( targetRay !== null ) { 26661 26662 inputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace ); 26663 26664 // Some runtimes (namely Vive Cosmos with Vive OpenXR Runtime) have only grip space and ray space is equal to it 26665 if ( inputPose === null && gripPose !== null ) { 26666 26667 inputPose = gripPose; 26668 26669 } 26670 26671 if ( inputPose !== null ) { 26672 26673 targetRay.matrix.fromArray( inputPose.transform.matrix ); 26674 targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale ); 26675 targetRay.matrixWorldNeedsUpdate = true; 26676 26677 if ( inputPose.linearVelocity ) { 26678 26679 targetRay.hasLinearVelocity = true; 26680 targetRay.linearVelocity.copy( inputPose.linearVelocity ); 26681 26682 } else { 26683 26684 targetRay.hasLinearVelocity = false; 26685 26686 } 26687 26688 if ( inputPose.angularVelocity ) { 26689 26690 targetRay.hasAngularVelocity = true; 26691 targetRay.angularVelocity.copy( inputPose.angularVelocity ); 26692 26693 } else { 26694 26695 targetRay.hasAngularVelocity = false; 26696 26697 } 26698 26699 this.dispatchEvent( _moveEvent ); 26700 26701 } 26702 26703 } 26704 26705 26706 } 26707 26708 if ( targetRay !== null ) { 26709 26710 targetRay.visible = ( inputPose !== null ); 26711 26712 } 26713 26714 if ( grip !== null ) { 26715 26716 grip.visible = ( gripPose !== null ); 26717 26718 } 26719 26720 if ( hand !== null ) { 26721 26722 hand.visible = ( handPose !== null ); 26723 26724 } 26725 26726 return this; 26727 26728 } 26729 26730 // private method 26731 26732 _getHandJoint( hand, inputjoint ) { 26733 26734 if ( hand.joints[ inputjoint.jointName ] === undefined ) { 26735 26736 const joint = new Group(); 26737 joint.matrixAutoUpdate = false; 26738 joint.visible = false; 26739 hand.joints[ inputjoint.jointName ] = joint; 26740 26741 hand.add( joint ); 26742 26743 } 26744 26745 return hand.joints[ inputjoint.jointName ]; 26746 26747 } 26748 26749} 26750 26751class WebXRManager extends EventDispatcher { 26752 26753 constructor( renderer, gl ) { 26754 26755 super(); 26756 26757 const scope = this; 26758 26759 let session = null; 26760 26761 let framebufferScaleFactor = 1.0; 26762 26763 let referenceSpace = null; 26764 let referenceSpaceType = 'local-floor'; 26765 // Set default foveation to maximum. 26766 let foveation = 1.0; 26767 let customReferenceSpace = null; 26768 26769 let pose = null; 26770 let glBinding = null; 26771 let glProjLayer = null; 26772 let glBaseLayer = null; 26773 let xrFrame = null; 26774 const attributes = gl.getContextAttributes(); 26775 let initialRenderTarget = null; 26776 let newRenderTarget = null; 26777 26778 const controllers = []; 26779 const controllerInputSources = []; 26780 26781 const currentSize = new Vector2(); 26782 let currentPixelRatio = null; 26783 26784 // 26785 26786 const cameraL = new PerspectiveCamera(); 26787 cameraL.layers.enable( 1 ); 26788 cameraL.viewport = new Vector4(); 26789 26790 const cameraR = new PerspectiveCamera(); 26791 cameraR.layers.enable( 2 ); 26792 cameraR.viewport = new Vector4(); 26793 26794 const cameras = [ cameraL, cameraR ]; 26795 26796 const cameraXR = new ArrayCamera(); 26797 cameraXR.layers.enable( 1 ); 26798 cameraXR.layers.enable( 2 ); 26799 26800 let _currentDepthNear = null; 26801 let _currentDepthFar = null; 26802 26803 // 26804 26805 this.cameraAutoUpdate = true; 26806 this.enabled = false; 26807 26808 this.isPresenting = false; 26809 26810 this.getController = function ( index ) { 26811 26812 let controller = controllers[ index ]; 26813 26814 if ( controller === undefined ) { 26815 26816 controller = new WebXRController(); 26817 controllers[ index ] = controller; 26818 26819 } 26820 26821 return controller.getTargetRaySpace(); 26822 26823 }; 26824 26825 this.getControllerGrip = function ( index ) { 26826 26827 let controller = controllers[ index ]; 26828 26829 if ( controller === undefined ) { 26830 26831 controller = new WebXRController(); 26832 controllers[ index ] = controller; 26833 26834 } 26835 26836 return controller.getGripSpace(); 26837 26838 }; 26839 26840 this.getHand = function ( index ) { 26841 26842 let controller = controllers[ index ]; 26843 26844 if ( controller === undefined ) { 26845 26846 controller = new WebXRController(); 26847 controllers[ index ] = controller; 26848 26849 } 26850 26851 return controller.getHandSpace(); 26852 26853 }; 26854 26855 // 26856 26857 function onSessionEvent( event ) { 26858 26859 const controllerIndex = controllerInputSources.indexOf( event.inputSource ); 26860 26861 if ( controllerIndex === - 1 ) { 26862 26863 return; 26864 26865 } 26866 26867 const controller = controllers[ controllerIndex ]; 26868 26869 if ( controller !== undefined ) { 26870 26871 controller.update( event.inputSource, event.frame, customReferenceSpace || referenceSpace ); 26872 controller.dispatchEvent( { type: event.type, data: event.inputSource } ); 26873 26874 } 26875 26876 } 26877 26878 function onSessionEnd() { 26879 26880 session.removeEventListener( 'select', onSessionEvent ); 26881 session.removeEventListener( 'selectstart', onSessionEvent ); 26882 session.removeEventListener( 'selectend', onSessionEvent ); 26883 session.removeEventListener( 'squeeze', onSessionEvent ); 26884 session.removeEventListener( 'squeezestart', onSessionEvent ); 26885 session.removeEventListener( 'squeezeend', onSessionEvent ); 26886 session.removeEventListener( 'end', onSessionEnd ); 26887 session.removeEventListener( 'inputsourceschange', onInputSourcesChange ); 26888 26889 for ( let i = 0; i < controllers.length; i ++ ) { 26890 26891 const inputSource = controllerInputSources[ i ]; 26892 26893 if ( inputSource === null ) continue; 26894 26895 controllerInputSources[ i ] = null; 26896 26897 controllers[ i ].disconnect( inputSource ); 26898 26899 } 26900 26901 _currentDepthNear = null; 26902 _currentDepthFar = null; 26903 26904 // restore framebuffer/rendering state 26905 26906 renderer.setRenderTarget( initialRenderTarget ); 26907 26908 glBaseLayer = null; 26909 glProjLayer = null; 26910 glBinding = null; 26911 session = null; 26912 newRenderTarget = null; 26913 26914 // 26915 26916 animation.stop(); 26917 26918 scope.isPresenting = false; 26919 26920 renderer.setPixelRatio( currentPixelRatio ); 26921 renderer.setSize( currentSize.width, currentSize.height, false ); 26922 26923 scope.dispatchEvent( { type: 'sessionend' } ); 26924 26925 } 26926 26927 this.setFramebufferScaleFactor = function ( value ) { 26928 26929 framebufferScaleFactor = value; 26930 26931 if ( scope.isPresenting === true ) { 26932 26933 console.warn( 'THREE.WebXRManager: Cannot change framebuffer scale while presenting.' ); 26934 26935 } 26936 26937 }; 26938 26939 this.setReferenceSpaceType = function ( value ) { 26940 26941 referenceSpaceType = value; 26942 26943 if ( scope.isPresenting === true ) { 26944 26945 console.warn( 'THREE.WebXRManager: Cannot change reference space type while presenting.' ); 26946 26947 } 26948 26949 }; 26950 26951 this.getReferenceSpace = function () { 26952 26953 return customReferenceSpace || referenceSpace; 26954 26955 }; 26956 26957 this.setReferenceSpace = function ( space ) { 26958 26959 customReferenceSpace = space; 26960 26961 }; 26962 26963 this.getBaseLayer = function () { 26964 26965 return glProjLayer !== null ? glProjLayer : glBaseLayer; 26966 26967 }; 26968 26969 this.getBinding = function () { 26970 26971 return glBinding; 26972 26973 }; 26974 26975 this.getFrame = function () { 26976 26977 return xrFrame; 26978 26979 }; 26980 26981 this.getSession = function () { 26982 26983 return session; 26984 26985 }; 26986 26987 this.setSession = async function ( value ) { 26988 26989 session = value; 26990 26991 if ( session !== null ) { 26992 26993 initialRenderTarget = renderer.getRenderTarget(); 26994 26995 session.addEventListener( 'select', onSessionEvent ); 26996 session.addEventListener( 'selectstart', onSessionEvent ); 26997 session.addEventListener( 'selectend', onSessionEvent ); 26998 session.addEventListener( 'squeeze', onSessionEvent ); 26999 session.addEventListener( 'squeezestart', onSessionEvent ); 27000 session.addEventListener( 'squeezeend', onSessionEvent ); 27001 session.addEventListener( 'end', onSessionEnd ); 27002 session.addEventListener( 'inputsourceschange', onInputSourcesChange ); 27003 27004 if ( attributes.xrCompatible !== true ) { 27005 27006 await gl.makeXRCompatible(); 27007 27008 } 27009 27010 currentPixelRatio = renderer.getPixelRatio(); 27011 renderer.getSize( currentSize ); 27012 27013 if ( ( session.renderState.layers === undefined ) || ( renderer.capabilities.isWebGL2 === false ) ) { 27014 27015 const layerInit = { 27016 antialias: ( session.renderState.layers === undefined ) ? attributes.antialias : true, 27017 alpha: true, 27018 depth: attributes.depth, 27019 stencil: attributes.stencil, 27020 framebufferScaleFactor: framebufferScaleFactor 27021 }; 27022 27023 glBaseLayer = new XRWebGLLayer( session, gl, layerInit ); 27024 27025 session.updateRenderState( { baseLayer: glBaseLayer } ); 27026 27027 renderer.setPixelRatio( 1 ); 27028 renderer.setSize( glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, false ); 27029 27030 newRenderTarget = new WebGLRenderTarget( 27031 glBaseLayer.framebufferWidth, 27032 glBaseLayer.framebufferHeight, 27033 { 27034 format: RGBAFormat, 27035 type: UnsignedByteType, 27036 colorSpace: renderer.outputColorSpace, 27037 stencilBuffer: attributes.stencil 27038 } 27039 ); 27040 27041 } else { 27042 27043 let depthFormat = null; 27044 let depthType = null; 27045 let glDepthFormat = null; 27046 27047 if ( attributes.depth ) { 27048 27049 glDepthFormat = attributes.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24; 27050 depthFormat = attributes.stencil ? DepthStencilFormat : DepthFormat; 27051 depthType = attributes.stencil ? UnsignedInt248Type : UnsignedIntType; 27052 27053 } 27054 27055 const projectionlayerInit = { 27056 colorFormat: gl.RGBA8, 27057 depthFormat: glDepthFormat, 27058 scaleFactor: framebufferScaleFactor 27059 }; 27060 27061 glBinding = new XRWebGLBinding( session, gl ); 27062 27063 glProjLayer = glBinding.createProjectionLayer( projectionlayerInit ); 27064 27065 session.updateRenderState( { layers: [ glProjLayer ] } ); 27066 27067 renderer.setPixelRatio( 1 ); 27068 renderer.setSize( glProjLayer.textureWidth, glProjLayer.textureHeight, false ); 27069 27070 newRenderTarget = new WebGLRenderTarget( 27071 glProjLayer.textureWidth, 27072 glProjLayer.textureHeight, 27073 { 27074 format: RGBAFormat, 27075 type: UnsignedByteType, 27076 depthTexture: new DepthTexture( glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat ), 27077 stencilBuffer: attributes.stencil, 27078 colorSpace: renderer.outputColorSpace, 27079 samples: attributes.antialias ? 4 : 0 27080 } ); 27081 27082 const renderTargetProperties = renderer.properties.get( newRenderTarget ); 27083 renderTargetProperties.__ignoreDepthValues = glProjLayer.ignoreDepthValues; 27084 27085 } 27086 27087 newRenderTarget.isXRRenderTarget = true; // TODO Remove this when possible, see #23278 27088 27089 this.setFoveation( foveation ); 27090 27091 customReferenceSpace = null; 27092 referenceSpace = await session.requestReferenceSpace( referenceSpaceType ); 27093 27094 animation.setContext( session ); 27095 animation.start(); 27096 27097 scope.isPresenting = true; 27098 27099 scope.dispatchEvent( { type: 'sessionstart' } ); 27100 27101 } 27102 27103 }; 27104 27105 this.getEnvironmentBlendMode = function () { 27106 27107 if ( session !== null ) { 27108 27109 return session.environmentBlendMode; 27110 27111 } 27112 27113 }; 27114 27115 function onInputSourcesChange( event ) { 27116 27117 // Notify disconnected 27118 27119 for ( let i = 0; i < event.removed.length; i ++ ) { 27120 27121 const inputSource = event.removed[ i ]; 27122 const index = controllerInputSources.indexOf( inputSource ); 27123 27124 if ( index >= 0 ) { 27125 27126 controllerInputSources[ index ] = null; 27127 controllers[ index ].disconnect( inputSource ); 27128 27129 } 27130 27131 } 27132 27133 // Notify connected 27134 27135 for ( let i = 0; i < event.added.length; i ++ ) { 27136 27137 const inputSource = event.added[ i ]; 27138 27139 let controllerIndex = controllerInputSources.indexOf( inputSource ); 27140 27141 if ( controllerIndex === - 1 ) { 27142 27143 // Assign input source a controller that currently has no input source 27144 27145 for ( let i = 0; i < controllers.length; i ++ ) { 27146 27147 if ( i >= controllerInputSources.length ) { 27148 27149 controllerInputSources.push( inputSource ); 27150 controllerIndex = i; 27151 break; 27152 27153 } else if ( controllerInputSources[ i ] === null ) { 27154 27155 controllerInputSources[ i ] = inputSource; 27156 controllerIndex = i; 27157 break; 27158 27159 } 27160 27161 } 27162 27163 // If all controllers do currently receive input we ignore new ones 27164 27165 if ( controllerIndex === - 1 ) break; 27166 27167 } 27168 27169 const controller = controllers[ controllerIndex ]; 27170 27171 if ( controller ) { 27172 27173 controller.connect( inputSource ); 27174 27175 } 27176 27177 } 27178 27179 } 27180 27181 // 27182 27183 const cameraLPos = new Vector3(); 27184 const cameraRPos = new Vector3(); 27185 27186 /** 27187 * Assumes 2 cameras that are parallel and share an X-axis, and that 27188 * the cameras' projection and world matrices have already been set. 27189 * And that near and far planes are identical for both cameras. 27190 * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765 27191 */ 27192 function setProjectionFromUnion( camera, cameraL, cameraR ) { 27193 27194 cameraLPos.setFromMatrixPosition( cameraL.matrixWorld ); 27195 cameraRPos.setFromMatrixPosition( cameraR.matrixWorld ); 27196 27197 const ipd = cameraLPos.distanceTo( cameraRPos ); 27198 27199 const projL = cameraL.projectionMatrix.elements; 27200 const projR = cameraR.projectionMatrix.elements; 27201 27202 // VR systems will have identical far and near planes, and 27203 // most likely identical top and bottom frustum extents. 27204 // Use the left camera for these values. 27205 const near = projL[ 14 ] / ( projL[ 10 ] - 1 ); 27206 const far = projL[ 14 ] / ( projL[ 10 ] + 1 ); 27207 const topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ]; 27208 const bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ]; 27209 27210 const leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ]; 27211 const rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ]; 27212 const left = near * leftFov; 27213 const right = near * rightFov; 27214 27215 // Calculate the new camera's position offset from the 27216 // left camera. xOffset should be roughly half `ipd`. 27217 const zOffset = ipd / ( - leftFov + rightFov ); 27218 const xOffset = zOffset * - leftFov; 27219 27220 // TODO: Better way to apply this offset? 27221 cameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale ); 27222 camera.translateX( xOffset ); 27223 camera.translateZ( zOffset ); 27224 camera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale ); 27225 camera.matrixWorldInverse.copy( camera.matrixWorld ).invert(); 27226 27227 // Find the union of the frustum values of the cameras and scale 27228 // the values so that the near plane's position does not change in world space, 27229 // although must now be relative to the new union camera. 27230 const near2 = near + zOffset; 27231 const far2 = far + zOffset; 27232 const left2 = left - xOffset; 27233 const right2 = right + ( ipd - xOffset ); 27234 const top2 = topFov * far / far2 * near2; 27235 const bottom2 = bottomFov * far / far2 * near2; 27236 27237 camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 ); 27238 camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert(); 27239 27240 } 27241 27242 function updateCamera( camera, parent ) { 27243 27244 if ( parent === null ) { 27245 27246 camera.matrixWorld.copy( camera.matrix ); 27247 27248 } else { 27249 27250 camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix ); 27251 27252 } 27253 27254 camera.matrixWorldInverse.copy( camera.matrixWorld ).invert(); 27255 27256 } 27257 27258 this.updateCamera = function ( camera ) { 27259 27260 if ( session === null ) return; 27261 27262 cameraXR.near = cameraR.near = cameraL.near = camera.near; 27263 cameraXR.far = cameraR.far = cameraL.far = camera.far; 27264 27265 if ( _currentDepthNear !== cameraXR.near || _currentDepthFar !== cameraXR.far ) { 27266 27267 // Note that the new renderState won't apply until the next frame. See #18320 27268 27269 session.updateRenderState( { 27270 depthNear: cameraXR.near, 27271 depthFar: cameraXR.far 27272 } ); 27273 27274 _currentDepthNear = cameraXR.near; 27275 _currentDepthFar = cameraXR.far; 27276 27277 } 27278 27279 const parent = camera.parent; 27280 const cameras = cameraXR.cameras; 27281 27282 updateCamera( cameraXR, parent ); 27283 27284 for ( let i = 0; i < cameras.length; i ++ ) { 27285 27286 updateCamera( cameras[ i ], parent ); 27287 27288 } 27289 27290 // update projection matrix for proper view frustum culling 27291 27292 if ( cameras.length === 2 ) { 27293 27294 setProjectionFromUnion( cameraXR, cameraL, cameraR ); 27295 27296 } else { 27297 27298 // assume single camera setup (AR) 27299 27300 cameraXR.projectionMatrix.copy( cameraL.projectionMatrix ); 27301 27302 } 27303 27304 // update user camera and its children 27305 27306 updateUserCamera( camera, cameraXR, parent ); 27307 27308 }; 27309 27310 function updateUserCamera( camera, cameraXR, parent ) { 27311 27312 if ( parent === null ) { 27313 27314 camera.matrix.copy( cameraXR.matrixWorld ); 27315 27316 } else { 27317 27318 camera.matrix.copy( parent.matrixWorld ); 27319 camera.matrix.invert(); 27320 camera.matrix.multiply( cameraXR.matrixWorld ); 27321 27322 } 27323 27324 camera.matrix.decompose( camera.position, camera.quaternion, camera.scale ); 27325 camera.updateMatrixWorld( true ); 27326 27327 camera.projectionMatrix.copy( cameraXR.projectionMatrix ); 27328 camera.projectionMatrixInverse.copy( cameraXR.projectionMatrixInverse ); 27329 27330 if ( camera.isPerspectiveCamera ) { 27331 27332 camera.fov = RAD2DEG * 2 * Math.atan( 1 / camera.projectionMatrix.elements[ 5 ] ); 27333 camera.zoom = 1; 27334 27335 } 27336 27337 } 27338 27339 this.getCamera = function () { 27340 27341 return cameraXR; 27342 27343 }; 27344 27345 this.getFoveation = function () { 27346 27347 if ( glProjLayer === null && glBaseLayer === null ) { 27348 27349 return undefined; 27350 27351 } 27352 27353 return foveation; 27354 27355 }; 27356 27357 this.setFoveation = function ( value ) { 27358 27359 // 0 = no foveation = full resolution 27360 // 1 = maximum foveation = the edges render at lower resolution 27361 27362 foveation = value; 27363 27364 if ( glProjLayer !== null ) { 27365 27366 glProjLayer.fixedFoveation = value; 27367 27368 } 27369 27370 if ( glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined ) { 27371 27372 glBaseLayer.fixedFoveation = value; 27373 27374 } 27375 27376 }; 27377 27378 // Animation Loop 27379 27380 let onAnimationFrameCallback = null; 27381 27382 function onAnimationFrame( time, frame ) { 27383 27384 pose = frame.getViewerPose( customReferenceSpace || referenceSpace ); 27385 xrFrame = frame; 27386 27387 if ( pose !== null ) { 27388 27389 const views = pose.views; 27390 27391 if ( glBaseLayer !== null ) { 27392 27393 renderer.setRenderTargetFramebuffer( newRenderTarget, glBaseLayer.framebuffer ); 27394 renderer.setRenderTarget( newRenderTarget ); 27395 27396 } 27397 27398 let cameraXRNeedsUpdate = false; 27399 27400 // check if it's necessary to rebuild cameraXR's camera list 27401 27402 if ( views.length !== cameraXR.cameras.length ) { 27403 27404 cameraXR.cameras.length = 0; 27405 cameraXRNeedsUpdate = true; 27406 27407 } 27408 27409 for ( let i = 0; i < views.length; i ++ ) { 27410 27411 const view = views[ i ]; 27412 27413 let viewport = null; 27414 27415 if ( glBaseLayer !== null ) { 27416 27417 viewport = glBaseLayer.getViewport( view ); 27418 27419 } else { 27420 27421 const glSubImage = glBinding.getViewSubImage( glProjLayer, view ); 27422 viewport = glSubImage.viewport; 27423 27424 // For side-by-side projection, we only produce a single texture for both eyes. 27425 if ( i === 0 ) { 27426 27427 renderer.setRenderTargetTextures( 27428 newRenderTarget, 27429 glSubImage.colorTexture, 27430 glProjLayer.ignoreDepthValues ? undefined : glSubImage.depthStencilTexture ); 27431 27432 renderer.setRenderTarget( newRenderTarget ); 27433 27434 } 27435 27436 } 27437
vendor: 6,492 bytes, lines 27438-27723
27438 let camera = cameras[ i ]; 27439 27440 if ( camera === undefined ) { 27441 27442 camera = new PerspectiveCamera(); 27443 camera.layers.enable( i ); 27444 camera.viewport = new Vector4(); 27445 cameras[ i ] = camera; 27446 27447 } 27448 27449 camera.matrix.fromArray( view.transform.matrix ); 27450 camera.matrix.decompose( camera.position, camera.quaternion, camera.scale ); 27451 camera.projectionMatrix.fromArray( view.projectionMatrix ); 27452 camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert(); 27453 camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height ); 27454 27455 if ( i === 0 ) { 27456 27457 cameraXR.matrix.copy( camera.matrix ); 27458 cameraXR.matrix.decompose( cameraXR.position, cameraXR.quaternion, cameraXR.scale ); 27459 27460 } 27461 27462 if ( cameraXRNeedsUpdate === true ) { 27463 27464 cameraXR.cameras.push( camera ); 27465 27466 } 27467 27468 } 27469 27470 } 27471 27472 // 27473 27474 for ( let i = 0; i < controllers.length; i ++ ) { 27475 27476 const inputSource = controllerInputSources[ i ]; 27477 const controller = controllers[ i ]; 27478 27479 if ( inputSource !== null && controller !== undefined ) { 27480 27481 controller.update( inputSource, frame, customReferenceSpace || referenceSpace ); 27482 27483 } 27484 27485 } 27486 27487 if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame ); 27488 27489 if ( frame.detectedPlanes ) { 27490 27491 scope.dispatchEvent( { type: 'planesdetected', data: frame } ); 27492 27493 } 27494 27495 xrFrame = null; 27496 27497 } 27498 27499 const animation = new WebGLAnimation(); 27500 27501 animation.setAnimationLoop( onAnimationFrame ); 27502 27503 this.setAnimationLoop = function ( callback ) { 27504 27505 onAnimationFrameCallback = callback; 27506 27507 }; 27508 27509 this.dispose = function () {}; 27510 27511 } 27512 27513} 27514 27515function WebGLMaterials( renderer, properties ) { 27516 27517 function refreshTransformUniform( map, uniform ) { 27518 27519 if ( map.matrixAutoUpdate === true ) { 27520 27521 map.updateMatrix(); 27522 27523 } 27524 27525 uniform.value.copy( map.matrix ); 27526 27527 } 27528 27529 function refreshFogUniforms( uniforms, fog ) { 27530 27531 fog.color.getRGB( uniforms.fogColor.value, getUnlitUniformColorSpace( renderer ) ); 27532 27533 if ( fog.isFog ) { 27534 27535 uniforms.fogNear.value = fog.near; 27536 uniforms.fogFar.value = fog.far; 27537 27538 } else if ( fog.isFogExp2 ) { 27539 27540 uniforms.fogDensity.value = fog.density; 27541 27542 } 27543 27544 } 27545 27546 function refreshMaterialUniforms( uniforms, material, pixelRatio, height, transmissionRenderTarget ) { 27547 27548 if ( material.isMeshBasicMaterial ) { 27549 27550 refreshUniformsCommon( uniforms, material ); 27551 27552 } else if ( material.isMeshLambertMaterial ) { 27553 27554 refreshUniformsCommon( uniforms, material ); 27555 27556 } else if ( material.isMeshToonMaterial ) { 27557 27558 refreshUniformsCommon( uniforms, material ); 27559 refreshUniformsToon( uniforms, material ); 27560 27561 } else if ( material.isMeshPhongMaterial ) { 27562 27563 refreshUniformsCommon( uniforms, material ); 27564 refreshUniformsPhong( uniforms, material ); 27565 27566 } else if ( material.isMeshStandardMaterial ) { 27567 27568 refreshUniformsCommon( uniforms, material ); 27569 refreshUniformsStandard( uniforms, material ); 27570 27571 if ( material.isMeshPhysicalMaterial ) { 27572 27573 refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ); 27574 27575 } 27576 27577 } else if ( material.isMeshMatcapMaterial ) { 27578 27579 refreshUniformsCommon( uniforms, material ); 27580 refreshUniformsMatcap( uniforms, material ); 27581 27582 } else if ( material.isMeshDepthMaterial ) { 27583 27584 refreshUniformsCommon( uniforms, material ); 27585 27586 } else if ( material.isMeshDistanceMaterial ) { 27587 27588 refreshUniformsCommon( uniforms, material ); 27589 refreshUniformsDistance( uniforms, material ); 27590 27591 } else if ( material.isMeshNormalMaterial ) { 27592 27593 refreshUniformsCommon( uniforms, material ); 27594 27595 } else if ( material.isLineBasicMaterial ) { 27596 27597 refreshUniformsLine( uniforms, material ); 27598 27599 if ( material.isLineDashedMaterial ) { 27600 27601 refreshUniformsDash( uniforms, material ); 27602 27603 } 27604 27605 } else if ( material.isPointsMaterial ) { 27606 27607 refreshUniformsPoints( uniforms, material, pixelRatio, height ); 27608 27609 } else if ( material.isSpriteMaterial ) { 27610 27611 refreshUniformsSprites( uniforms, material ); 27612 27613 } else if ( material.isShadowMaterial ) { 27614 27615 uniforms.color.value.copy( material.color ); 27616 uniforms.opacity.value = material.opacity; 27617 27618 } else if ( material.isShaderMaterial ) { 27619 27620 material.uniformsNeedUpdate = false; // #15581 27621 27622 } 27623 27624 } 27625 27626 function refreshUniformsCommon( uniforms, material ) { 27627 27628 uniforms.opacity.value = material.opacity; 27629 27630 if ( material.color ) { 27631 27632 uniforms.diffuse.value.copy( material.color ); 27633 27634 } 27635 27636 if ( material.emissive ) { 27637 27638 uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity ); 27639 27640 } 27641 27642 if ( material.map ) { 27643 27644 uniforms.map.value = material.map; 27645 27646 refreshTransformUniform( material.map, uniforms.mapTransform ); 27647 27648 } 27649 27650 if ( material.alphaMap ) { 27651 27652 uniforms.alphaMap.value = material.alphaMap; 27653 27654 refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform ); 27655 27656 } 27657 27658 if ( material.bumpMap ) { 27659 27660 uniforms.bumpMap.value = material.bumpMap; 27661 27662 refreshTransformUniform( material.bumpMap, uniforms.bumpMapTransform ); 27663 27664 uniforms.bumpScale.value = material.bumpScale; 27665 27666 if ( material.side === BackSide ) { 27667 27668 uniforms.bumpScale.value *= - 1; 27669 27670 } 27671 27672 } 27673 27674 if ( material.normalMap ) { 27675 27676 uniforms.normalMap.value = material.normalMap; 27677 27678 refreshTransformUniform( material.normalMap, uniforms.normalMapTransform ); 27679 27680 uniforms.normalScale.value.copy( material.normalScale ); 27681 27682 if ( material.side === BackSide ) { 27683 27684 uniforms.normalScale.value.negate(); 27685 27686 } 27687 27688 } 27689 27690 if ( material.displacementMap ) { 27691 27692 uniforms.displacementMap.value = material.displacementMap; 27693 27694 refreshTransformUniform( material.displacementMap, uniforms.displacementMapTransform ); 27695 27696 uniforms.displacementScale.value = material.displacementScale; 27697 uniforms.displacementBias.value = material.displacementBias; 27698 27699 } 27700 27701 if ( material.emissiveMap ) { 27702 27703 uniforms.emissiveMap.value = material.emissiveMap; 27704 27705 refreshTransformUniform( material.emissiveMap, uniforms.emissiveMapTransform ); 27706 27707 } 27708 27709 if ( material.specularMap ) { 27710 27711 uniforms.specularMap.value = material.specularMap; 27712 27713 refreshTransformUniform( material.specularMap, uniforms.specularMapTransform ); 27714 27715 } 27716 27717 if ( material.alphaTest > 0 ) { 27718 27719 uniforms.alphaTest.value = material.alphaTest; 27720 27721 } 27722 27723 const envMap = properties.get( material ).envMap;
vendor: 87,068 bytes, lines 27724-31034
27724 27725 if ( envMap ) { 27726 27727 uniforms.envMap.value = envMap; 27728 27729 uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1; 27730 27731 uniforms.reflectivity.value = material.reflectivity; 27732 uniforms.ior.value = material.ior; 27733 uniforms.refractionRatio.value = material.refractionRatio; 27734 27735 } 27736 27737 if ( material.lightMap ) { 27738 27739 uniforms.lightMap.value = material.lightMap; 27740 27741 // artist-friendly light intensity scaling factor 27742 const scaleFactor = ( renderer._useLegacyLights === true ) ? Math.PI : 1; 27743 27744 uniforms.lightMapIntensity.value = material.lightMapIntensity * scaleFactor; 27745 27746 refreshTransformUniform( material.lightMap, uniforms.lightMapTransform ); 27747 27748 } 27749 27750 if ( material.aoMap ) { 27751 27752 uniforms.aoMap.value = material.aoMap; 27753 uniforms.aoMapIntensity.value = material.aoMapIntensity; 27754 27755 refreshTransformUniform( material.aoMap, uniforms.aoMapTransform ); 27756 27757 } 27758 27759 } 27760 27761 function refreshUniformsLine( uniforms, material ) { 27762 27763 uniforms.diffuse.value.copy( material.color ); 27764 uniforms.opacity.value = material.opacity; 27765 27766 if ( material.map ) { 27767 27768 uniforms.map.value = material.map; 27769 27770 refreshTransformUniform( material.map, uniforms.mapTransform ); 27771 27772 } 27773 27774 } 27775 27776 function refreshUniformsDash( uniforms, material ) { 27777 27778 uniforms.dashSize.value = material.dashSize; 27779 uniforms.totalSize.value = material.dashSize + material.gapSize; 27780 uniforms.scale.value = material.scale; 27781 27782 } 27783 27784 function refreshUniformsPoints( uniforms, material, pixelRatio, height ) { 27785 27786 uniforms.diffuse.value.copy( material.color ); 27787 uniforms.opacity.value = material.opacity; 27788 uniforms.size.value = material.size * pixelRatio; 27789 uniforms.scale.value = height * 0.5; 27790 27791 if ( material.map ) { 27792 27793 uniforms.map.value = material.map; 27794 27795 refreshTransformUniform( material.map, uniforms.uvTransform ); 27796 27797 } 27798 27799 if ( material.alphaMap ) { 27800 27801 uniforms.alphaMap.value = material.alphaMap; 27802 27803 refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform ); 27804 27805 } 27806 27807 if ( material.alphaTest > 0 ) { 27808 27809 uniforms.alphaTest.value = material.alphaTest; 27810 27811 } 27812 27813 } 27814 27815 function refreshUniformsSprites( uniforms, material ) { 27816 27817 uniforms.diffuse.value.copy( material.color ); 27818 uniforms.opacity.value = material.opacity; 27819 uniforms.rotation.value = material.rotation; 27820 27821 if ( material.map ) { 27822 27823 uniforms.map.value = material.map; 27824 27825 refreshTransformUniform( material.map, uniforms.mapTransform ); 27826 27827 } 27828 27829 if ( material.alphaMap ) { 27830 27831 uniforms.alphaMap.value = material.alphaMap; 27832 27833 refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform ); 27834 27835 } 27836 27837 if ( material.alphaTest > 0 ) { 27838 27839 uniforms.alphaTest.value = material.alphaTest; 27840 27841 } 27842 27843 } 27844 27845 function refreshUniformsPhong( uniforms, material ) { 27846 27847 uniforms.specular.value.copy( material.specular ); 27848 uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 ) 27849 27850 } 27851 27852 function refreshUniformsToon( uniforms, material ) { 27853 27854 if ( material.gradientMap ) { 27855 27856 uniforms.gradientMap.value = material.gradientMap; 27857 27858 } 27859 27860 } 27861 27862 function refreshUniformsStandard( uniforms, material ) { 27863 27864 uniforms.metalness.value = material.metalness; 27865 27866 if ( material.metalnessMap ) { 27867 27868 uniforms.metalnessMap.value = material.metalnessMap; 27869 27870 refreshTransformUniform( material.metalnessMap, uniforms.metalnessMapTransform ); 27871 27872 } 27873 27874 uniforms.roughness.value = material.roughness; 27875 27876 if ( material.roughnessMap ) { 27877 27878 uniforms.roughnessMap.value = material.roughnessMap; 27879 27880 refreshTransformUniform( material.roughnessMap, uniforms.roughnessMapTransform ); 27881 27882 } 27883 27884 const envMap = properties.get( material ).envMap; 27885 27886 if ( envMap ) { 27887 27888 //uniforms.envMap.value = material.envMap; // part of uniforms common 27889 uniforms.envMapIntensity.value = material.envMapIntensity; 27890 27891 } 27892 27893 } 27894 27895 function refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ) { 27896 27897 uniforms.ior.value = material.ior; // also part of uniforms common 27898 27899 if ( material.sheen > 0 ) { 27900 27901 uniforms.sheenColor.value.copy( material.sheenColor ).multiplyScalar( material.sheen ); 27902 27903 uniforms.sheenRoughness.value = material.sheenRoughness; 27904 27905 if ( material.sheenColorMap ) { 27906 27907 uniforms.sheenColorMap.value = material.sheenColorMap; 27908 27909 refreshTransformUniform( material.sheenColorMap, uniforms.sheenColorMapTransform ); 27910 27911 } 27912 27913 if ( material.sheenRoughnessMap ) { 27914 27915 uniforms.sheenRoughnessMap.value = material.sheenRoughnessMap; 27916 27917 refreshTransformUniform( material.sheenRoughnessMap, uniforms.sheenRoughnessMapTransform ); 27918 27919 } 27920 27921 } 27922 27923 if ( material.clearcoat > 0 ) { 27924 27925 uniforms.clearcoat.value = material.clearcoat; 27926 uniforms.clearcoatRoughness.value = material.clearcoatRoughness; 27927 27928 if ( material.clearcoatMap ) { 27929 27930 uniforms.clearcoatMap.value = material.clearcoatMap; 27931 27932 refreshTransformUniform( material.clearcoatMap, uniforms.clearcoatMapTransform ); 27933 27934 } 27935 27936 if ( material.clearcoatRoughnessMap ) { 27937 27938 uniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap; 27939 27940 refreshTransformUniform( material.clearcoatRoughnessMap, uniforms.clearcoatRoughnessMapTransform ); 27941 27942 } 27943 27944 if ( material.clearcoatNormalMap ) { 27945 27946 uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap; 27947 27948 refreshTransformUniform( material.clearcoatNormalMap, uniforms.clearcoatNormalMapTransform ); 27949 27950 uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale ); 27951 27952 if ( material.side === BackSide ) { 27953 27954 uniforms.clearcoatNormalScale.value.negate(); 27955 27956 } 27957 27958 } 27959 27960 } 27961 27962 if ( material.iridescence > 0 ) { 27963 27964 uniforms.iridescence.value = material.iridescence; 27965 uniforms.iridescenceIOR.value = material.iridescenceIOR; 27966 uniforms.iridescenceThicknessMinimum.value = material.iridescenceThicknessRange[ 0 ]; 27967 uniforms.iridescenceThicknessMaximum.value = material.iridescenceThicknessRange[ 1 ]; 27968 27969 if ( material.iridescenceMap ) { 27970 27971 uniforms.iridescenceMap.value = material.iridescenceMap; 27972 27973 refreshTransformUniform( material.iridescenceMap, uniforms.iridescenceMapTransform ); 27974 27975 } 27976 27977 if ( material.iridescenceThicknessMap ) { 27978 27979 uniforms.iridescenceThicknessMap.value = material.iridescenceThicknessMap; 27980 27981 refreshTransformUniform( material.iridescenceThicknessMap, uniforms.iridescenceThicknessMapTransform ); 27982 27983 } 27984 27985 } 27986 27987 if ( material.transmission > 0 ) { 27988 27989 uniforms.transmission.value = material.transmission; 27990 uniforms.transmissionSamplerMap.value = transmissionRenderTarget.texture; 27991 uniforms.transmissionSamplerSize.value.set( transmissionRenderTarget.width, transmissionRenderTarget.height ); 27992 27993 if ( material.transmissionMap ) { 27994 27995 uniforms.transmissionMap.value = material.transmissionMap; 27996 27997 refreshTransformUniform( material.transmissionMap, uniforms.transmissionMapTransform ); 27998 27999 } 28000 28001 uniforms.thickness.value = material.thickness; 28002 28003 if ( material.thicknessMap ) { 28004 28005 uniforms.thicknessMap.value = material.thicknessMap; 28006 28007 refreshTransformUniform( material.thicknessMap, uniforms.thicknessMapTransform ); 28008 28009 } 28010 28011 uniforms.attenuationDistance.value = material.attenuationDistance; 28012 uniforms.attenuationColor.value.copy( material.attenuationColor ); 28013 28014 } 28015 28016 if ( material.anisotropy > 0 ) { 28017 28018 uniforms.anisotropyVector.value.set( material.anisotropy * Math.cos( material.anisotropyRotation ), material.anisotropy * Math.sin( material.anisotropyRotation ) ); 28019 28020 if ( material.anisotropyMap ) { 28021 28022 uniforms.anisotropyMap.value = material.anisotropyMap; 28023 28024 refreshTransformUniform( material.anisotropyMap, uniforms.anisotropyMapTransform ); 28025 28026 } 28027 28028 } 28029 28030 uniforms.specularIntensity.value = material.specularIntensity; 28031 uniforms.specularColor.value.copy( material.specularColor ); 28032 28033 if ( material.specularColorMap ) { 28034 28035 uniforms.specularColorMap.value = material.specularColorMap; 28036 28037 refreshTransformUniform( material.specularColorMap, uniforms.specularColorMapTransform ); 28038 28039 } 28040 28041 if ( material.specularIntensityMap ) { 28042 28043 uniforms.specularIntensityMap.value = material.specularIntensityMap; 28044 28045 refreshTransformUniform( material.specularIntensityMap, uniforms.specularIntensityMapTransform ); 28046 28047 } 28048 28049 } 28050 28051 function refreshUniformsMatcap( uniforms, material ) { 28052 28053 if ( material.matcap ) { 28054 28055 uniforms.matcap.value = material.matcap; 28056 28057 } 28058 28059 } 28060 28061 function refreshUniformsDistance( uniforms, material ) { 28062 28063 const light = properties.get( material ).light; 28064 28065 uniforms.referencePosition.value.setFromMatrixPosition( light.matrixWorld ); 28066 uniforms.nearDistance.value = light.shadow.camera.near; 28067 uniforms.farDistance.value = light.shadow.camera.far; 28068 28069 } 28070 28071 return { 28072 refreshFogUniforms: refreshFogUniforms, 28073 refreshMaterialUniforms: refreshMaterialUniforms 28074 }; 28075 28076} 28077 28078function WebGLUniformsGroups( gl, info, capabilities, state ) { 28079 28080 let buffers = {}; 28081 let updateList = {}; 28082 let allocatedBindingPoints = []; 28083 28084 const maxBindingPoints = ( capabilities.isWebGL2 ) ? gl.getParameter( gl.MAX_UNIFORM_BUFFER_BINDINGS ) : 0; // binding points are global whereas block indices are per shader program 28085 28086 function bind( uniformsGroup, program ) { 28087 28088 const webglProgram = program.program; 28089 state.uniformBlockBinding( uniformsGroup, webglProgram ); 28090 28091 } 28092 28093 function update( uniformsGroup, program ) { 28094 28095 let buffer = buffers[ uniformsGroup.id ]; 28096 28097 if ( buffer === undefined ) { 28098 28099 prepareUniformsGroup( uniformsGroup ); 28100 28101 buffer = createBuffer( uniformsGroup ); 28102 buffers[ uniformsGroup.id ] = buffer; 28103 28104 uniformsGroup.addEventListener( 'dispose', onUniformsGroupsDispose ); 28105 28106 } 28107 28108 // ensure to update the binding points/block indices mapping for this program 28109 28110 const webglProgram = program.program; 28111 state.updateUBOMapping( uniformsGroup, webglProgram ); 28112 28113 // update UBO once per frame 28114 28115 const frame = info.render.frame; 28116 28117 if ( updateList[ uniformsGroup.id ] !== frame ) { 28118 28119 updateBufferData( uniformsGroup ); 28120 28121 updateList[ uniformsGroup.id ] = frame; 28122 28123 } 28124 28125 } 28126 28127 function createBuffer( uniformsGroup ) { 28128 28129 // the setup of an UBO is independent of a particular shader program but global 28130 28131 const bindingPointIndex = allocateBindingPointIndex(); 28132 uniformsGroup.__bindingPointIndex = bindingPointIndex; 28133 28134 const buffer = gl.createBuffer(); 28135 const size = uniformsGroup.__size; 28136 const usage = uniformsGroup.usage; 28137 28138 gl.bindBuffer( gl.UNIFORM_BUFFER, buffer ); 28139 gl.bufferData( gl.UNIFORM_BUFFER, size, usage ); 28140 gl.bindBuffer( gl.UNIFORM_BUFFER, null ); 28141 gl.bindBufferBase( gl.UNIFORM_BUFFER, bindingPointIndex, buffer ); 28142 28143 return buffer; 28144 28145 } 28146 28147 function allocateBindingPointIndex() { 28148 28149 for ( let i = 0; i < maxBindingPoints; i ++ ) { 28150 28151 if ( allocatedBindingPoints.indexOf( i ) === - 1 ) { 28152 28153 allocatedBindingPoints.push( i ); 28154 return i; 28155 28156 } 28157 28158 } 28159 28160 console.error( 'THREE.WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached.' ); 28161 28162 return 0; 28163 28164 } 28165 28166 function updateBufferData( uniformsGroup ) { 28167 28168 const buffer = buffers[ uniformsGroup.id ]; 28169 const uniforms = uniformsGroup.uniforms; 28170 const cache = uniformsGroup.__cache; 28171 28172 gl.bindBuffer( gl.UNIFORM_BUFFER, buffer ); 28173 28174 for ( let i = 0, il = uniforms.length; i < il; i ++ ) { 28175 28176 const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ]; 28177 28178 for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) { 28179 28180 const uniform = uniformArray[ j ]; 28181 28182 if ( hasUniformChanged( uniform, i, j, cache ) === true ) { 28183 28184 const offset = uniform.__offset; 28185 28186 const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ]; 28187 28188 let arrayOffset = 0; 28189 28190 for ( let k = 0; k < values.length; k ++ ) { 28191 28192 const value = values[ k ]; 28193 28194 const info = getUniformSize( value ); 28195 28196 // TODO add integer and struct support 28197 if ( typeof value === 'number' || typeof value === 'boolean' ) { 28198 28199 uniform.__data[ 0 ] = value; 28200 gl.bufferSubData( gl.UNIFORM_BUFFER, offset + arrayOffset, uniform.__data ); 28201 28202 } else if ( value.isMatrix3 ) { 28203 28204 // manually converting 3x3 to 3x4 28205 28206 uniform.__data[ 0 ] = value.elements[ 0 ]; 28207 uniform.__data[ 1 ] = value.elements[ 1 ]; 28208 uniform.__data[ 2 ] = value.elements[ 2 ]; 28209 uniform.__data[ 3 ] = 0; 28210 uniform.__data[ 4 ] = value.elements[ 3 ]; 28211 uniform.__data[ 5 ] = value.elements[ 4 ]; 28212 uniform.__data[ 6 ] = value.elements[ 5 ]; 28213 uniform.__data[ 7 ] = 0; 28214 uniform.__data[ 8 ] = value.elements[ 6 ]; 28215 uniform.__data[ 9 ] = value.elements[ 7 ]; 28216 uniform.__data[ 10 ] = value.elements[ 8 ]; 28217 uniform.__data[ 11 ] = 0; 28218 28219 } else { 28220 28221 value.toArray( uniform.__data, arrayOffset ); 28222 28223 arrayOffset += info.storage / Float32Array.BYTES_PER_ELEMENT; 28224 28225 } 28226 28227 } 28228 28229 gl.bufferSubData( gl.UNIFORM_BUFFER, offset, uniform.__data ); 28230 28231 } 28232 28233 } 28234 28235 } 28236 28237 gl.bindBuffer( gl.UNIFORM_BUFFER, null ); 28238 28239 } 28240 28241 function hasUniformChanged( uniform, index, indexArray, cache ) { 28242 28243 const value = uniform.value; 28244 const indexString = index + '_' + indexArray; 28245 28246 if ( cache[ indexString ] === undefined ) { 28247 28248 // cache entry does not exist so far 28249 28250 if ( typeof value === 'number' || typeof value === 'boolean' ) { 28251 28252 cache[ indexString ] = value; 28253 28254 } else { 28255 28256 cache[ indexString ] = value.clone(); 28257 28258 } 28259 28260 return true; 28261 28262 } else { 28263 28264 const cachedObject = cache[ indexString ]; 28265 28266 // compare current value with cached entry 28267 28268 if ( typeof value === 'number' || typeof value === 'boolean' ) { 28269 28270 if ( cachedObject !== value ) { 28271 28272 cache[ indexString ] = value; 28273 return true; 28274 28275 } 28276 28277 } else { 28278 28279 if ( cachedObject.equals( value ) === false ) { 28280 28281 cachedObject.copy( value ); 28282 return true; 28283 28284 } 28285 28286 } 28287 28288 } 28289 28290 return false; 28291 28292 } 28293 28294 function prepareUniformsGroup( uniformsGroup ) { 28295 28296 // determine total buffer size according to the STD140 layout 28297 // Hint: STD140 is the only supported layout in WebGL 2 28298 28299 const uniforms = uniformsGroup.uniforms; 28300 28301 let offset = 0; // global buffer offset in bytes 28302 const chunkSize = 16; // size of a chunk in bytes 28303 28304 for ( let i = 0, l = uniforms.length; i < l; i ++ ) { 28305 28306 const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ]; 28307 28308 for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) { 28309 28310 const uniform = uniformArray[ j ]; 28311 28312 const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ]; 28313 28314 for ( let k = 0, kl = values.length; k < kl; k ++ ) { 28315 28316 const value = values[ k ]; 28317 28318 const info = getUniformSize( value ); 28319 28320 // Calculate the chunk offset 28321 const chunkOffsetUniform = offset % chunkSize; 28322 28323 // Check for chunk overflow 28324 if ( chunkOffsetUniform !== 0 && ( chunkSize - chunkOffsetUniform ) < info.boundary ) { 28325 28326 // Add padding and adjust offset 28327 offset += ( chunkSize - chunkOffsetUniform ); 28328 28329 } 28330 28331 // the following two properties will be used for partial buffer updates 28332 28333 uniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT ); 28334 uniform.__offset = offset; 28335 28336 28337 // Update the global offset 28338 offset += info.storage; 28339 28340 28341 } 28342 28343 } 28344 28345 } 28346 28347 // ensure correct final padding 28348 28349 const chunkOffset = offset % chunkSize; 28350 28351 if ( chunkOffset > 0 ) offset += ( chunkSize - chunkOffset ); 28352 28353 // 28354 28355 uniformsGroup.__size = offset; 28356 uniformsGroup.__cache = {}; 28357 28358 return this; 28359 28360 } 28361 28362 function getUniformSize( value ) { 28363 28364 const info = { 28365 boundary: 0, // bytes 28366 storage: 0 // bytes 28367 }; 28368 28369 // determine sizes according to STD140 28370 28371 if ( typeof value === 'number' || typeof value === 'boolean' ) { 28372 28373 // float/int/bool 28374 28375 info.boundary = 4; 28376 info.storage = 4; 28377 28378 } else if ( value.isVector2 ) { 28379 28380 // vec2 28381 28382 info.boundary = 8; 28383 info.storage = 8; 28384 28385 } else if ( value.isVector3 || value.isColor ) { 28386 28387 // vec3 28388 28389 info.boundary = 16; 28390 info.storage = 12; // evil: vec3 must start on a 16-byte boundary but it only consumes 12 bytes 28391 28392 } else if ( value.isVector4 ) { 28393 28394 // vec4 28395 28396 info.boundary = 16; 28397 info.storage = 16; 28398 28399 } else if ( value.isMatrix3 ) { 28400 28401 // mat3 (in STD140 a 3x3 matrix is represented as 3x4) 28402 28403 info.boundary = 48; 28404 info.storage = 48; 28405 28406 } else if ( value.isMatrix4 ) { 28407 28408 // mat4 28409 28410 info.boundary = 64; 28411 info.storage = 64; 28412 28413 } else if ( value.isTexture ) { 28414 28415 console.warn( 'THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.' ); 28416 28417 } else { 28418 28419 console.warn( 'THREE.WebGLRenderer: Unsupported uniform value type.', value ); 28420 28421 } 28422 28423 return info; 28424 28425 } 28426 28427 function onUniformsGroupsDispose( event ) { 28428 28429 const uniformsGroup = event.target; 28430 28431 uniformsGroup.removeEventListener( 'dispose', onUniformsGroupsDispose ); 28432 28433 const index = allocatedBindingPoints.indexOf( uniformsGroup.__bindingPointIndex ); 28434 allocatedBindingPoints.splice( index, 1 ); 28435 28436 gl.deleteBuffer( buffers[ uniformsGroup.id ] ); 28437 28438 delete buffers[ uniformsGroup.id ]; 28439 delete updateList[ uniformsGroup.id ]; 28440 28441 } 28442 28443 function dispose() { 28444 28445 for ( const id in buffers ) { 28446 28447 gl.deleteBuffer( buffers[ id ] ); 28448 28449 } 28450 28451 allocatedBindingPoints = []; 28452 buffers = {}; 28453 updateList = {}; 28454 28455 } 28456 28457 return { 28458 28459 bind: bind, 28460 update: update, 28461 28462 dispose: dispose 28463 28464 }; 28465 28466} 28467 28468class WebGLRenderer { 28469 28470 constructor( parameters = {} ) { 28471 28472 const { 28473 canvas = createCanvasElement(), 28474 context = null, 28475 depth = true, 28476 stencil = true, 28477 alpha = false, 28478 antialias = false, 28479 premultipliedAlpha = true, 28480 preserveDrawingBuffer = false, 28481 powerPreference = 'default', 28482 failIfMajorPerformanceCaveat = false, 28483 } = parameters; 28484 28485 this.isWebGLRenderer = true; 28486 28487 let _alpha; 28488 28489 if ( context !== null ) { 28490 28491 _alpha = context.getContextAttributes().alpha; 28492 28493 } else { 28494 28495 _alpha = alpha; 28496 28497 } 28498 28499 const uintClearColor = new Uint32Array( 4 ); 28500 const intClearColor = new Int32Array( 4 ); 28501 28502 let currentRenderList = null; 28503 let currentRenderState = null; 28504 28505 // render() can be called from within a callback triggered by another render. 28506 // We track this so that the nested render call gets its list and state isolated from the parent render call. 28507 28508 const renderListStack = []; 28509 const renderStateStack = []; 28510 28511 // public properties 28512 28513 this.domElement = canvas; 28514 28515 // Debug configuration container 28516 this.debug = { 28517 28518 /** 28519 * Enables error checking and reporting when shader programs are being compiled 28520 * @type {boolean} 28521 */ 28522 checkShaderErrors: true, 28523 /** 28524 * Callback for custom error reporting. 28525 * @type {?Function} 28526 */ 28527 onShaderError: null 28528 }; 28529 28530 // clearing 28531 28532 this.autoClear = true; 28533 this.autoClearColor = true; 28534 this.autoClearDepth = true; 28535 this.autoClearStencil = true; 28536 28537 // scene graph 28538 28539 this.sortObjects = true; 28540 28541 // user-defined clipping 28542 28543 this.clippingPlanes = []; 28544 this.localClippingEnabled = false; 28545 28546 // physically based shading 28547 28548 this._outputColorSpace = SRGBColorSpace; 28549 28550 // physical lights 28551 28552 this._useLegacyLights = false; 28553 28554 // tone mapping 28555 28556 this.toneMapping = NoToneMapping; 28557 this.toneMappingExposure = 1.0; 28558 28559 // internal properties 28560 28561 const _this = this; 28562 28563 let _isContextLost = false; 28564 28565 // internal state cache 28566 28567 let _currentActiveCubeFace = 0; 28568 let _currentActiveMipmapLevel = 0; 28569 let _currentRenderTarget = null; 28570 let _currentMaterialId = - 1; 28571 28572 let _currentCamera = null; 28573 28574 const _currentViewport = new Vector4(); 28575 const _currentScissor = new Vector4(); 28576 let _currentScissorTest = null; 28577 28578 const _currentClearColor = new Color( 0x000000 ); 28579 let _currentClearAlpha = 0; 28580 28581 // 28582 28583 let _width = canvas.width; 28584 let _height = canvas.height; 28585 28586 let _pixelRatio = 1; 28587 let _opaqueSort = null; 28588 let _transparentSort = null; 28589 28590 const _viewport = new Vector4( 0, 0, _width, _height ); 28591 const _scissor = new Vector4( 0, 0, _width, _height ); 28592 let _scissorTest = false; 28593 28594 // frustum 28595 28596 const _frustum = new Frustum(); 28597 28598 // clipping 28599 28600 let _clippingEnabled = false; 28601 let _localClippingEnabled = false; 28602 28603 // transmission 28604 28605 let _transmissionRenderTarget = null; 28606 28607 // camera matrices cache 28608 28609 const _projScreenMatrix = new Matrix4(); 28610 28611 const _vector2 = new Vector2(); 28612 const _vector3 = new Vector3(); 28613 28614 const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true }; 28615 28616 function getTargetPixelRatio() { 28617 28618 return _currentRenderTarget === null ? _pixelRatio : 1; 28619 28620 } 28621 28622 // initialize 28623 28624 let _gl = context; 28625 28626 function getContext( contextNames, contextAttributes ) { 28627 28628 for ( let i = 0; i < contextNames.length; i ++ ) { 28629 28630 const contextName = contextNames[ i ]; 28631 const context = canvas.getContext( contextName, contextAttributes ); 28632 if ( context !== null ) return context; 28633 28634 } 28635 28636 return null; 28637 28638 } 28639 28640 try { 28641 28642 const contextAttributes = { 28643 alpha: true, 28644 depth, 28645 stencil, 28646 antialias, 28647 premultipliedAlpha, 28648 preserveDrawingBuffer, 28649 powerPreference, 28650 failIfMajorPerformanceCaveat, 28651 }; 28652 28653 // OffscreenCanvas does not have setAttribute, see #22811 28654 if ( 'setAttribute' in canvas ) canvas.setAttribute( 'data-engine', `three.js r${REVISION}` ); 28655 28656 // event listeners must be registered before WebGL context is created, see #12753 28657 canvas.addEventListener( 'webglcontextlost', onContextLost, false ); 28658 canvas.addEventListener( 'webglcontextrestored', onContextRestore, false ); 28659 canvas.addEventListener( 'webglcontextcreationerror', onContextCreationError, false ); 28660 28661 if ( _gl === null ) { 28662 28663 const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ]; 28664 28665 if ( _this.isWebGL1Renderer === true ) { 28666 28667 contextNames.shift(); 28668 28669 } 28670 28671 _gl = getContext( contextNames, contextAttributes ); 28672 28673 if ( _gl === null ) { 28674 28675 if ( getContext( contextNames ) ) { 28676 28677 throw new Error( 'Error creating WebGL context with your selected attributes.' ); 28678 28679 } else { 28680 28681 throw new Error( 'Error creating WebGL context.' ); 28682 28683 } 28684 28685 } 28686 28687 } 28688 28689 if ( typeof WebGLRenderingContext !== 'undefined' && _gl instanceof WebGLRenderingContext ) { // @deprecated, r153 28690 28691 console.warn( 'THREE.WebGLRenderer: WebGL 1 support was deprecated in r153 and will be removed in r163.' ); 28692 28693 } 28694 28695 // Some experimental-webgl implementations do not have getShaderPrecisionFormat 28696 28697 if ( _gl.getShaderPrecisionFormat === undefined ) { 28698 28699 _gl.getShaderPrecisionFormat = function () { 28700 28701 return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; 28702 28703 }; 28704 28705 } 28706 28707 } catch ( error ) { 28708 28709 console.error( 'THREE.WebGLRenderer: ' + error.message ); 28710 throw error; 28711 28712 } 28713 28714 let extensions, capabilities, state, info; 28715 let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects; 28716 let programCache, materials, renderLists, renderStates, clipping, shadowMap; 28717 28718 let background, morphtargets, bufferRenderer, indexedBufferRenderer; 28719 28720 let utils, bindingStates, uniformsGroups; 28721 28722 function initGLContext() { 28723 28724 extensions = new WebGLExtensions( _gl ); 28725 28726 capabilities = new WebGLCapabilities( _gl, extensions, parameters ); 28727 28728 extensions.init( capabilities ); 28729 28730 utils = new WebGLUtils( _gl, extensions, capabilities ); 28731 28732 state = new WebGLState( _gl, extensions, capabilities ); 28733 28734 info = new WebGLInfo( _gl ); 28735 properties = new WebGLProperties(); 28736 textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ); 28737 cubemaps = new WebGLCubeMaps( _this ); 28738 cubeuvmaps = new WebGLCubeUVMaps( _this ); 28739 attributes = new WebGLAttributes( _gl, capabilities ); 28740 bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities ); 28741 geometries = new WebGLGeometries( _gl, attributes, info, bindingStates ); 28742 objects = new WebGLObjects( _gl, geometries, attributes, info ); 28743 morphtargets = new WebGLMorphtargets( _gl, capabilities, textures ); 28744 clipping = new WebGLClipping( properties ); 28745 programCache = new WebGLPrograms( _this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ); 28746 materials = new WebGLMaterials( _this, properties ); 28747 renderLists = new WebGLRenderLists(); 28748 renderStates = new WebGLRenderStates( extensions, capabilities ); 28749 background = new WebGLBackground( _this, cubemaps, cubeuvmaps, state, objects, _alpha, premultipliedAlpha ); 28750 shadowMap = new WebGLShadowMap( _this, objects, capabilities ); 28751 uniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state ); 28752 28753 bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities ); 28754 indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities ); 28755 28756 info.programs = programCache.programs; 28757 28758 _this.capabilities = capabilities; 28759 _this.extensions = extensions; 28760 _this.properties = properties; 28761 _this.renderLists = renderLists; 28762 _this.shadowMap = shadowMap; 28763 _this.state = state; 28764 _this.info = info; 28765 28766 } 28767 28768 initGLContext(); 28769 28770 // xr 28771 28772 const xr = new WebXRManager( _this, _gl ); 28773 28774 this.xr = xr; 28775 28776 // API 28777 28778 this.getContext = function () { 28779 28780 return _gl; 28781 28782 }; 28783 28784 this.getContextAttributes = function () { 28785 28786 return _gl.getContextAttributes(); 28787 28788 }; 28789 28790 this.forceContextLoss = function () { 28791 28792 const extension = extensions.get( 'WEBGL_lose_context' ); 28793 if ( extension ) extension.loseContext(); 28794 28795 }; 28796 28797 this.forceContextRestore = function () { 28798 28799 const extension = extensions.get( 'WEBGL_lose_context' ); 28800 if ( extension ) extension.restoreContext(); 28801 28802 }; 28803 28804 this.getPixelRatio = function () { 28805 28806 return _pixelRatio; 28807 28808 }; 28809 28810 this.setPixelRatio = function ( value ) { 28811 28812 if ( value === undefined ) return; 28813 28814 _pixelRatio = value; 28815 28816 this.setSize( _width, _height, false ); 28817 28818 }; 28819 28820 this.getSize = function ( target ) { 28821 28822 return target.set( _width, _height ); 28823 28824 }; 28825 28826 this.setSize = function ( width, height, updateStyle = true ) { 28827 28828 if ( xr.isPresenting ) { 28829 28830 console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' ); 28831 return; 28832 28833 } 28834 28835 _width = width; 28836 _height = height; 28837 28838 canvas.width = Math.floor( width * _pixelRatio ); 28839 canvas.height = Math.floor( height * _pixelRatio ); 28840 28841 if ( updateStyle === true ) { 28842 28843 canvas.style.width = width + 'px'; 28844 canvas.style.height = height + 'px'; 28845 28846 } 28847 28848 this.setViewport( 0, 0, width, height ); 28849 28850 }; 28851 28852 this.getDrawingBufferSize = function ( target ) { 28853 28854 return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor(); 28855 28856 }; 28857 28858 this.setDrawingBufferSize = function ( width, height, pixelRatio ) { 28859 28860 _width = width; 28861 _height = height; 28862 28863 _pixelRatio = pixelRatio; 28864 28865 canvas.width = Math.floor( width * pixelRatio ); 28866 canvas.height = Math.floor( height * pixelRatio ); 28867 28868 this.setViewport( 0, 0, width, height ); 28869 28870 }; 28871 28872 this.getCurrentViewport = function ( target ) { 28873 28874 return target.copy( _currentViewport ); 28875 28876 }; 28877 28878 this.getViewport = function ( target ) { 28879 28880 return target.copy( _viewport ); 28881 28882 }; 28883 28884 this.setViewport = function ( x, y, width, height ) { 28885 28886 if ( x.isVector4 ) { 28887 28888 _viewport.set( x.x, x.y, x.z, x.w ); 28889 28890 } else { 28891 28892 _viewport.set( x, y, width, height ); 28893 28894 } 28895 28896 state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() ); 28897 28898 }; 28899 28900 this.getScissor = function ( target ) { 28901 28902 return target.copy( _scissor ); 28903 28904 }; 28905 28906 this.setScissor = function ( x, y, width, height ) { 28907 28908 if ( x.isVector4 ) { 28909 28910 _scissor.set( x.x, x.y, x.z, x.w ); 28911 28912 } else { 28913 28914 _scissor.set( x, y, width, height ); 28915 28916 } 28917 28918 state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() ); 28919 28920 }; 28921 28922 this.getScissorTest = function () { 28923 28924 return _scissorTest; 28925 28926 }; 28927 28928 this.setScissorTest = function ( boolean ) { 28929 28930 state.setScissorTest( _scissorTest = boolean ); 28931 28932 }; 28933 28934 this.setOpaqueSort = function ( method ) { 28935 28936 _opaqueSort = method; 28937 28938 }; 28939 28940 this.setTransparentSort = function ( method ) { 28941 28942 _transparentSort = method; 28943 28944 }; 28945 28946 // Clearing 28947 28948 this.getClearColor = function ( target ) { 28949 28950 return target.copy( background.getClearColor() ); 28951 28952 }; 28953 28954 this.setClearColor = function () { 28955 28956 background.setClearColor.apply( background, arguments ); 28957 28958 }; 28959 28960 this.getClearAlpha = function () { 28961 28962 return background.getClearAlpha(); 28963 28964 }; 28965 28966 this.setClearAlpha = function () { 28967 28968 background.setClearAlpha.apply( background, arguments ); 28969 28970 }; 28971 28972 this.clear = function ( color = true, depth = true, stencil = true ) { 28973 28974 let bits = 0; 28975 28976 if ( color ) { 28977 28978 // check if we're trying to clear an integer target 28979 let isIntegerFormat = false; 28980 if ( _currentRenderTarget !== null ) { 28981 28982 const targetFormat = _currentRenderTarget.texture.format; 28983 isIntegerFormat = targetFormat === RGBAIntegerFormat || 28984 targetFormat === RGIntegerFormat || 28985 targetFormat === RedIntegerFormat; 28986 28987 } 28988 28989 // use the appropriate clear functions to clear the target if it's a signed 28990 // or unsigned integer target 28991 if ( isIntegerFormat ) { 28992 28993 const targetType = _currentRenderTarget.texture.type; 28994 const isUnsignedType = targetType === UnsignedByteType || 28995 targetType === UnsignedIntType || 28996 targetType === UnsignedShortType || 28997 targetType === UnsignedInt248Type || 28998 targetType === UnsignedShort4444Type || 28999 targetType === UnsignedShort5551Type; 29000 29001 const clearColor = background.getClearColor(); 29002 const a = background.getClearAlpha(); 29003 const r = clearColor.r; 29004 const g = clearColor.g; 29005 const b = clearColor.b; 29006 29007 if ( isUnsignedType ) { 29008 29009 uintClearColor[ 0 ] = r; 29010 uintClearColor[ 1 ] = g; 29011 uintClearColor[ 2 ] = b; 29012 uintClearColor[ 3 ] = a; 29013 _gl.clearBufferuiv( _gl.COLOR, 0, uintClearColor ); 29014 29015 } else { 29016 29017 intClearColor[ 0 ] = r; 29018 intClearColor[ 1 ] = g; 29019 intClearColor[ 2 ] = b; 29020 intClearColor[ 3 ] = a; 29021 _gl.clearBufferiv( _gl.COLOR, 0, intClearColor ); 29022 29023 } 29024 29025 } else { 29026 29027 bits |= _gl.COLOR_BUFFER_BIT; 29028 29029 } 29030 29031 } 29032 29033 if ( depth ) bits |= _gl.DEPTH_BUFFER_BIT; 29034 if ( stencil ) { 29035 29036 bits |= _gl.STENCIL_BUFFER_BIT; 29037 this.state.buffers.stencil.setMask( 0xffffffff ); 29038 29039 } 29040 29041 _gl.clear( bits ); 29042 29043 }; 29044 29045 this.clearColor = function () { 29046 29047 this.clear( true, false, false ); 29048 29049 }; 29050 29051 this.clearDepth = function () { 29052 29053 this.clear( false, true, false ); 29054 29055 }; 29056 29057 this.clearStencil = function () { 29058 29059 this.clear( false, false, true ); 29060 29061 }; 29062 29063 // 29064 29065 this.dispose = function () { 29066 29067 canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); 29068 canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); 29069 canvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false ); 29070 29071 renderLists.dispose(); 29072 renderStates.dispose(); 29073 properties.dispose(); 29074 cubemaps.dispose(); 29075 cubeuvmaps.dispose(); 29076 objects.dispose(); 29077 bindingStates.dispose(); 29078 uniformsGroups.dispose(); 29079 programCache.dispose(); 29080 29081 xr.dispose(); 29082 29083 xr.removeEventListener( 'sessionstart', onXRSessionStart ); 29084 xr.removeEventListener( 'sessionend', onXRSessionEnd ); 29085 29086 if ( _transmissionRenderTarget ) { 29087 29088 _transmissionRenderTarget.dispose(); 29089 _transmissionRenderTarget = null; 29090 29091 } 29092 29093 animation.stop(); 29094 29095 }; 29096 29097 // Events 29098 29099 function onContextLost( event ) { 29100 29101 event.preventDefault(); 29102 29103 console.log( 'THREE.WebGLRenderer: Context Lost.' ); 29104 29105 _isContextLost = true; 29106 29107 } 29108 29109 function onContextRestore( /* event */ ) { 29110 29111 console.log( 'THREE.WebGLRenderer: Context Restored.' ); 29112 29113 _isContextLost = false; 29114 29115 const infoAutoReset = info.autoReset; 29116 const shadowMapEnabled = shadowMap.enabled; 29117 const shadowMapAutoUpdate = shadowMap.autoUpdate; 29118 const shadowMapNeedsUpdate = shadowMap.needsUpdate; 29119 const shadowMapType = shadowMap.type; 29120 29121 initGLContext(); 29122 29123 info.autoReset = infoAutoReset; 29124 shadowMap.enabled = shadowMapEnabled; 29125 shadowMap.autoUpdate = shadowMapAutoUpdate; 29126 shadowMap.needsUpdate = shadowMapNeedsUpdate; 29127 shadowMap.type = shadowMapType; 29128 29129 } 29130 29131 function onContextCreationError( event ) { 29132 29133 console.error( 'THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage ); 29134 29135 } 29136 29137 function onMaterialDispose( event ) { 29138 29139 const material = event.target; 29140 29141 material.removeEventListener( 'dispose', onMaterialDispose ); 29142 29143 deallocateMaterial( material ); 29144 29145 } 29146 29147 // Buffer deallocation 29148 29149 function deallocateMaterial( material ) { 29150 29151 releaseMaterialProgramReferences( material ); 29152 29153 properties.remove( material ); 29154 29155 } 29156 29157 29158 function releaseMaterialProgramReferences( material ) { 29159 29160 const programs = properties.get( material ).programs; 29161 29162 if ( programs !== undefined ) { 29163 29164 programs.forEach( function ( program ) { 29165 29166 programCache.releaseProgram( program ); 29167 29168 } ); 29169 29170 if ( material.isShaderMaterial ) { 29171 29172 programCache.releaseShaderCache( material ); 29173 29174 } 29175 29176 } 29177 29178 } 29179 29180 // Buffer rendering 29181 29182 this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) { 29183 29184 if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null) 29185 29186 const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 ); 29187 29188 const program = setProgram( camera, scene, geometry, material, object ); 29189 29190 state.setMaterial( material, frontFaceCW ); 29191 29192 // 29193 29194 let index = geometry.index; 29195 let rangeFactor = 1; 29196 29197 if ( material.wireframe === true ) { 29198 29199 index = geometries.getWireframeAttribute( geometry ); 29200 29201 if ( index === undefined ) return; 29202 29203 rangeFactor = 2; 29204 29205 } 29206 29207 // 29208 29209 const drawRange = geometry.drawRange; 29210 const position = geometry.attributes.position; 29211 29212 let drawStart = drawRange.start * rangeFactor; 29213 let drawEnd = ( drawRange.start + drawRange.count ) * rangeFactor; 29214 29215 if ( group !== null ) { 29216 29217 drawStart = Math.max( drawStart, group.start * rangeFactor ); 29218 drawEnd = Math.min( drawEnd, ( group.start + group.count ) * rangeFactor ); 29219 29220 } 29221 29222 if ( index !== null ) { 29223 29224 drawStart = Math.max( drawStart, 0 ); 29225 drawEnd = Math.min( drawEnd, index.count ); 29226 29227 } else if ( position !== undefined && position !== null ) { 29228 29229 drawStart = Math.max( drawStart, 0 ); 29230 drawEnd = Math.min( drawEnd, position.count ); 29231 29232 } 29233 29234 const drawCount = drawEnd - drawStart; 29235 29236 if ( drawCount < 0 || drawCount === Infinity ) return; 29237 29238 // 29239 29240 bindingStates.setup( object, material, program, geometry, index ); 29241 29242 let attribute; 29243 let renderer = bufferRenderer; 29244 29245 if ( index !== null ) { 29246 29247 attribute = attributes.get( index ); 29248 29249 renderer = indexedBufferRenderer; 29250 renderer.setIndex( attribute ); 29251 29252 } 29253 29254 // 29255 29256 if ( object.isMesh ) { 29257 29258 if ( material.wireframe === true ) { 29259 29260 state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); 29261 renderer.setMode( _gl.LINES ); 29262 29263 } else { 29264 29265 renderer.setMode( _gl.TRIANGLES ); 29266 29267 } 29268 29269 } else if ( object.isLine ) { 29270 29271 let lineWidth = material.linewidth; 29272 29273 if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material 29274 29275 state.setLineWidth( lineWidth * getTargetPixelRatio() ); 29276 29277 if ( object.isLineSegments ) { 29278 29279 renderer.setMode( _gl.LINES ); 29280 29281 } else if ( object.isLineLoop ) { 29282 29283 renderer.setMode( _gl.LINE_LOOP ); 29284 29285 } else { 29286 29287 renderer.setMode( _gl.LINE_STRIP ); 29288 29289 } 29290 29291 } else if ( object.isPoints ) { 29292 29293 renderer.setMode( _gl.POINTS ); 29294 29295 } else if ( object.isSprite ) { 29296 29297 renderer.setMode( _gl.TRIANGLES ); 29298 29299 } 29300 29301 if ( object.isBatchedMesh ) { 29302 29303 renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount ); 29304 29305 } else if ( object.isInstancedMesh ) { 29306 29307 renderer.renderInstances( drawStart, drawCount, object.count ); 29308 29309 } else if ( geometry.isInstancedBufferGeometry ) { 29310 29311 const maxInstanceCount = geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity; 29312 const instanceCount = Math.min( geometry.instanceCount, maxInstanceCount ); 29313 29314 renderer.renderInstances( drawStart, drawCount, instanceCount ); 29315 29316 } else { 29317 29318 renderer.render( drawStart, drawCount ); 29319 29320 } 29321 29322 }; 29323 29324 // Compile 29325 29326 function prepareMaterial( material, scene, object ) { 29327 29328 if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) { 29329 29330 material.side = BackSide; 29331 material.needsUpdate = true; 29332 getProgram( material, scene, object ); 29333 29334 material.side = FrontSide; 29335 material.needsUpdate = true; 29336 getProgram( material, scene, object ); 29337 29338 material.side = DoubleSide; 29339 29340 } else { 29341 29342 getProgram( material, scene, object ); 29343 29344 } 29345 29346 } 29347 29348 this.compile = function ( scene, camera, targetScene = null ) { 29349 29350 if ( targetScene === null ) targetScene = scene; 29351 29352 currentRenderState = renderStates.get( targetScene ); 29353 currentRenderState.init(); 29354 29355 renderStateStack.push( currentRenderState ); 29356 29357 // gather lights from both the target scene and the new object that will be added to the scene. 29358 29359 targetScene.traverseVisible( function ( object ) { 29360 29361 if ( object.isLight && object.layers.test( camera.layers ) ) { 29362 29363 currentRenderState.pushLight( object ); 29364 29365 if ( object.castShadow ) { 29366 29367 currentRenderState.pushShadow( object ); 29368 29369 } 29370 29371 } 29372 29373 } ); 29374 29375 if ( scene !== targetScene ) { 29376 29377 scene.traverseVisible( function ( object ) { 29378 29379 if ( object.isLight && object.layers.test( camera.layers ) ) { 29380 29381 currentRenderState.pushLight( object ); 29382 29383 if ( object.castShadow ) { 29384 29385 currentRenderState.pushShadow( object ); 29386 29387 } 29388 29389 } 29390 29391 } ); 29392 29393 } 29394 29395 currentRenderState.setupLights( _this._useLegacyLights ); 29396 29397 // Only initialize materials in the new scene, not the targetScene. 29398 29399 const materials = new Set(); 29400 29401 scene.traverse( function ( object ) { 29402 29403 const material = object.material; 29404 29405 if ( material ) { 29406 29407 if ( Array.isArray( material ) ) { 29408 29409 for ( let i = 0; i < material.length; i ++ ) { 29410 29411 const material2 = material[ i ]; 29412 29413 prepareMaterial( material2, targetScene, object ); 29414 materials.add( material2 ); 29415 29416 } 29417 29418 } else { 29419 29420 prepareMaterial( material, targetScene, object ); 29421 materials.add( material ); 29422 29423 } 29424 29425 } 29426 29427 } ); 29428 29429 renderStateStack.pop(); 29430 currentRenderState = null; 29431 29432 return materials; 29433 29434 }; 29435 29436 // compileAsync 29437 29438 this.compileAsync = function ( scene, camera, targetScene = null ) { 29439 29440 const materials = this.compile( scene, camera, targetScene ); 29441 29442 // Wait for all the materials in the new object to indicate that they're 29443 // ready to be used before resolving the promise. 29444 29445 return new Promise( ( resolve ) => { 29446 29447 function checkMaterialsReady() { 29448 29449 materials.forEach( function ( material ) { 29450 29451 const materialProperties = properties.get( material ); 29452 const program = materialProperties.currentProgram; 29453 29454 if ( program.isReady() ) { 29455 29456 // remove any programs that report they're ready to use from the list 29457 materials.delete( material ); 29458 29459 } 29460 29461 } ); 29462 29463 // once the list of compiling materials is empty, call the callback 29464 29465 if ( materials.size === 0 ) { 29466 29467 resolve( scene ); 29468 return; 29469 29470 } 29471 29472 // if some materials are still not ready, wait a bit and check again 29473 29474 setTimeout( checkMaterialsReady, 10 ); 29475 29476 } 29477 29478 if ( extensions.get( 'KHR_parallel_shader_compile' ) !== null ) { 29479 29480 // If we can check the compilation status of the materials without 29481 // blocking then do so right away. 29482 29483 checkMaterialsReady(); 29484 29485 } else { 29486 29487 // Otherwise start by waiting a bit to give the materials we just 29488 // initialized a chance to finish. 29489 29490 setTimeout( checkMaterialsReady, 10 ); 29491 29492 } 29493 29494 } ); 29495 29496 }; 29497 29498 // Animation Loop 29499 29500 let onAnimationFrameCallback = null; 29501 29502 function onAnimationFrame( time ) { 29503 29504 if ( onAnimationFrameCallback ) onAnimationFrameCallback( time ); 29505 29506 } 29507 29508 function onXRSessionStart() { 29509 29510 animation.stop(); 29511 29512 } 29513 29514 function onXRSessionEnd() { 29515 29516 animation.start(); 29517 29518 } 29519 29520 const animation = new WebGLAnimation(); 29521 animation.setAnimationLoop( onAnimationFrame ); 29522 29523 if ( typeof self !== 'undefined' ) animation.setContext( self ); 29524 29525 this.setAnimationLoop = function ( callback ) { 29526 29527 onAnimationFrameCallback = callback; 29528 xr.setAnimationLoop( callback ); 29529 29530 ( callback === null ) ? animation.stop() : animation.start(); 29531 29532 }; 29533 29534 xr.addEventListener( 'sessionstart', onXRSessionStart ); 29535 xr.addEventListener( 'sessionend', onXRSessionEnd ); 29536 29537 // Rendering 29538 29539 this.render = function ( scene, camera ) { 29540 29541 if ( camera !== undefined && camera.isCamera !== true ) { 29542 29543 console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); 29544 return; 29545 29546 } 29547 29548 if ( _isContextLost === true ) return; 29549 29550 // update scene graph 29551 29552 if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld(); 29553 29554 // update camera matrices and frustum 29555 29556 if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld(); 29557 29558 if ( xr.enabled === true && xr.isPresenting === true ) { 29559 29560 if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera ); 29561 29562 camera = xr.getCamera(); // use XR camera for rendering 29563 29564 } 29565 29566 // 29567 if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget ); 29568 29569 currentRenderState = renderStates.get( scene, renderStateStack.length ); 29570 currentRenderState.init(); 29571 29572 renderStateStack.push( currentRenderState ); 29573 29574 _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); 29575 _frustum.setFromProjectionMatrix( _projScreenMatrix ); 29576 29577 _localClippingEnabled = this.localClippingEnabled; 29578 _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled ); 29579 29580 currentRenderList = renderLists.get( scene, renderListStack.length ); 29581 currentRenderList.init(); 29582 29583 renderListStack.push( currentRenderList ); 29584 29585 projectObject( scene, camera, 0, _this.sortObjects ); 29586 29587 currentRenderList.finish(); 29588 29589 if ( _this.sortObjects === true ) { 29590 29591 currentRenderList.sort( _opaqueSort, _transparentSort ); 29592 29593 } 29594 29595 // 29596 29597 this.info.render.frame ++; 29598 29599 if ( _clippingEnabled === true ) clipping.beginShadows(); 29600 29601 const shadowsArray = currentRenderState.state.shadowsArray; 29602 29603 shadowMap.render( shadowsArray, scene, camera ); 29604 29605 if ( _clippingEnabled === true ) clipping.endShadows(); 29606 29607 // 29608 29609 if ( this.info.autoReset === true ) this.info.reset(); 29610 29611 29612 // 29613 29614 background.render( currentRenderList, scene ); 29615 29616 // render scene 29617 29618 currentRenderState.setupLights( _this._useLegacyLights ); 29619 29620 if ( camera.isArrayCamera ) { 29621 29622 const cameras = camera.cameras; 29623 29624 for ( let i = 0, l = cameras.length; i < l; i ++ ) { 29625 29626 const camera2 = cameras[ i ]; 29627 29628 renderScene( currentRenderList, scene, camera2, camera2.viewport ); 29629 29630 } 29631 29632 } else { 29633 29634 renderScene( currentRenderList, scene, camera ); 29635 29636 } 29637 29638 // 29639 29640 if ( _currentRenderTarget !== null ) { 29641 29642 // resolve multisample renderbuffers to a single-sample texture if necessary 29643 29644 textures.updateMultisampleRenderTarget( _currentRenderTarget ); 29645 29646 // Generate mipmap if we're using any kind of mipmap filtering 29647 29648 textures.updateRenderTargetMipmap( _currentRenderTarget ); 29649 29650 } 29651 29652 // 29653 29654 if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera ); 29655 29656 // _gl.finish(); 29657 29658 bindingStates.resetDefaultState(); 29659 _currentMaterialId = - 1; 29660 _currentCamera = null; 29661 29662 renderStateStack.pop(); 29663 29664 if ( renderStateStack.length > 0 ) { 29665 29666 currentRenderState = renderStateStack[ renderStateStack.length - 1 ]; 29667 29668 } else { 29669 29670 currentRenderState = null; 29671 29672 } 29673 29674 renderListStack.pop(); 29675 29676 if ( renderListStack.length > 0 ) { 29677 29678 currentRenderList = renderListStack[ renderListStack.length - 1 ]; 29679 29680 } else { 29681 29682 currentRenderList = null; 29683 29684 } 29685 29686 }; 29687 29688 function projectObject( object, camera, groupOrder, sortObjects ) { 29689 29690 if ( object.visible === false ) return; 29691 29692 const visible = object.layers.test( camera.layers ); 29693 29694 if ( visible ) { 29695 29696 if ( object.isGroup ) { 29697 29698 groupOrder = object.renderOrder; 29699 29700 } else if ( object.isLOD ) { 29701 29702 if ( object.autoUpdate === true ) object.update( camera ); 29703 29704 } else if ( object.isLight ) { 29705 29706 currentRenderState.pushLight( object ); 29707 29708 if ( object.castShadow ) { 29709 29710 currentRenderState.pushShadow( object ); 29711 29712 } 29713 29714 } else if ( object.isSprite ) { 29715 29716 if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { 29717 29718 if ( sortObjects ) { 29719 29720 _vector3.setFromMatrixPosition( object.matrixWorld ) 29721 .applyMatrix4( _projScreenMatrix ); 29722 29723 } 29724 29725 const geometry = objects.update( object ); 29726 const material = object.material; 29727 29728 if ( material.visible ) { 29729 29730 currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); 29731 29732 } 29733 29734 } 29735 29736 } else if ( object.isMesh || object.isLine || object.isPoints ) { 29737 29738 if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { 29739 29740 const geometry = objects.update( object ); 29741 const material = object.material; 29742 29743 if ( sortObjects ) { 29744 29745 if ( object.boundingSphere !== undefined ) { 29746 29747 if ( object.boundingSphere === null ) object.computeBoundingSphere(); 29748 _vector3.copy( object.boundingSphere.center ); 29749 29750 } else { 29751 29752 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); 29753 _vector3.copy( geometry.boundingSphere.center ); 29754 29755 } 29756 29757 _vector3 29758 .applyMatrix4( object.matrixWorld ) 29759 .applyMatrix4( _projScreenMatrix ); 29760 29761 } 29762 29763 if ( Array.isArray( material ) ) { 29764 29765 const groups = geometry.groups; 29766 29767 for ( let i = 0, l = groups.length; i < l; i ++ ) { 29768 29769 const group = groups[ i ]; 29770 const groupMaterial = material[ group.materialIndex ]; 29771 29772 if ( groupMaterial && groupMaterial.visible ) { 29773 29774 currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group ); 29775 29776 } 29777 29778 } 29779 29780 } else if ( material.visible ) { 29781 29782 currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); 29783 29784 } 29785 29786 } 29787 29788 } 29789 29790 } 29791 29792 const children = object.children; 29793 29794 for ( let i = 0, l = children.length; i < l; i ++ ) { 29795 29796 projectObject( children[ i ], camera, groupOrder, sortObjects ); 29797 29798 } 29799 29800 } 29801 29802 function renderScene( currentRenderList, scene, camera, viewport ) { 29803 29804 const opaqueObjects = currentRenderList.opaque; 29805 const transmissiveObjects = currentRenderList.transmissive; 29806 const transparentObjects = currentRenderList.transparent; 29807 29808 currentRenderState.setupLightsView( camera ); 29809 29810 if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera ); 29811 29812 if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ); 29813 29814 if ( viewport ) state.viewport( _currentViewport.copy( viewport ) ); 29815 29816 if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera ); 29817 if ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera ); 29818 if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera ); 29819 29820 // Ensure depth buffer writing is enabled so it can be cleared on next render 29821 29822 state.buffers.depth.setTest( true ); 29823 state.buffers.depth.setMask( true ); 29824 state.buffers.color.setMask( true ); 29825 29826 state.setPolygonOffset( false ); 29827 29828 } 29829 29830 function renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ) { 29831 29832 const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; 29833 29834 if ( overrideMaterial !== null ) { 29835 29836 return; 29837 29838 } 29839 29840 const isWebGL2 = capabilities.isWebGL2; 29841 29842 if ( _transmissionRenderTarget === null ) { 29843 29844 _transmissionRenderTarget = new WebGLRenderTarget( 1, 1, { 29845 generateMipmaps: true, 29846 type: extensions.has( 'EXT_color_buffer_half_float' ) ? HalfFloatType : UnsignedByteType, 29847 minFilter: LinearMipmapLinearFilter, 29848 samples: ( isWebGL2 ) ? 4 : 0 29849 } ); 29850 29851 // debug 29852 29853 /* 29854 const geometry = new PlaneGeometry(); 29855 const material = new MeshBasicMaterial( { map: _transmissionRenderTarget.texture } ); 29856 29857 const mesh = new Mesh( geometry, material ); 29858 scene.add( mesh ); 29859 */ 29860 29861 } 29862 29863 _this.getDrawingBufferSize( _vector2 ); 29864 29865 if ( isWebGL2 ) { 29866 29867 _transmissionRenderTarget.setSize( _vector2.x, _vector2.y ); 29868 29869 } else { 29870 29871 _transmissionRenderTarget.setSize( floorPowerOfTwo( _vector2.x ), floorPowerOfTwo( _vector2.y ) ); 29872 29873 } 29874 29875 // 29876 29877 const currentRenderTarget = _this.getRenderTarget(); 29878 _this.setRenderTarget( _transmissionRenderTarget ); 29879 29880 _this.getClearColor( _currentClearColor ); 29881 _currentClearAlpha = _this.getClearAlpha(); 29882 if ( _currentClearAlpha < 1 ) _this.setClearColor( 0xffffff, 0.5 ); 29883 29884 _this.clear(); 29885 29886 // Turn off the features which can affect the frag color for opaque objects pass. 29887 // Otherwise they are applied twice in opaque objects pass and transmission objects pass. 29888 const currentToneMapping = _this.toneMapping; 29889 _this.toneMapping = NoToneMapping; 29890 29891 renderObjects( opaqueObjects, scene, camera ); 29892 29893 textures.updateMultisampleRenderTarget( _transmissionRenderTarget ); 29894 textures.updateRenderTargetMipmap( _transmissionRenderTarget ); 29895 29896 let renderTargetNeedsUpdate = false; 29897 29898 for ( let i = 0, l = transmissiveObjects.length; i < l; i ++ ) { 29899 29900 const renderItem = transmissiveObjects[ i ]; 29901 29902 const object = renderItem.object; 29903 const geometry = renderItem.geometry; 29904 const material = renderItem.material; 29905 const group = renderItem.group; 29906 29907 if ( material.side === DoubleSide && object.layers.test( camera.layers ) ) { 29908 29909 const currentSide = material.side; 29910 29911 material.side = BackSide; 29912 material.needsUpdate = true; 29913 29914 renderObject( object, scene, camera, geometry, material, group ); 29915 29916 material.side = currentSide; 29917 material.needsUpdate = true; 29918 29919 renderTargetNeedsUpdate = true; 29920 29921 } 29922 29923 } 29924 29925 if ( renderTargetNeedsUpdate === true ) { 29926 29927 textures.updateMultisampleRenderTarget( _transmissionRenderTarget ); 29928 textures.updateRenderTargetMipmap( _transmissionRenderTarget ); 29929 29930 } 29931 29932 _this.setRenderTarget( currentRenderTarget ); 29933 29934 _this.setClearColor( _currentClearColor, _currentClearAlpha ); 29935 29936 _this.toneMapping = currentToneMapping; 29937 29938 } 29939 29940 function renderObjects( renderList, scene, camera ) { 29941 29942 const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; 29943 29944 for ( let i = 0, l = renderList.length; i < l; i ++ ) { 29945 29946 const renderItem = renderList[ i ]; 29947 29948 const object = renderItem.object; 29949 const geometry = renderItem.geometry; 29950 const material = overrideMaterial === null ? renderItem.material : overrideMaterial; 29951 const group = renderItem.group; 29952 29953 if ( object.layers.test( camera.layers ) ) { 29954 29955 renderObject( object, scene, camera, geometry, material, group ); 29956 29957 } 29958 29959 } 29960 29961 } 29962 29963 function renderObject( object, scene, camera, geometry, material, group ) { 29964 29965 object.onBeforeRender( _this, scene, camera, geometry, material, group ); 29966 29967 object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); 29968 object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); 29969 29970 material.onBeforeRender( _this, scene, camera, geometry, object, group ); 29971 29972 if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) { 29973 29974 material.side = BackSide; 29975 material.needsUpdate = true; 29976 _this.renderBufferDirect( camera, scene, geometry, material, object, group ); 29977 29978 material.side = FrontSide; 29979 material.needsUpdate = true; 29980 _this.renderBufferDirect( camera, scene, geometry, material, object, group ); 29981 29982 material.side = DoubleSide; 29983 29984 } else { 29985 29986 _this.renderBufferDirect( camera, scene, geometry, material, object, group ); 29987 29988 } 29989 29990 object.onAfterRender( _this, scene, camera, geometry, material, group ); 29991 29992 } 29993 29994 function getProgram( material, scene, object ) { 29995 29996 if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... 29997 29998 const materialProperties = properties.get( material ); 29999 30000 const lights = currentRenderState.state.lights; 30001 const shadowsArray = currentRenderState.state.shadowsArray; 30002 30003 const lightsStateVersion = lights.state.version; 30004 30005 const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object ); 30006 const programCacheKey = programCache.getProgramCacheKey( parameters ); 30007 30008 let programs = materialProperties.programs; 30009 30010 // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change 30011 30012 materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null; 30013 materialProperties.fog = scene.fog; 30014 materialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment ); 30015 30016 if ( programs === undefined ) { 30017 30018 // new material 30019 30020 material.addEventListener( 'dispose', onMaterialDispose ); 30021 30022 programs = new Map(); 30023 materialProperties.programs = programs; 30024 30025 } 30026 30027 let program = programs.get( programCacheKey ); 30028 30029 if ( program !== undefined ) { 30030 30031 // early out if program and light state is identical 30032 30033 if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) { 30034 30035 updateCommonMaterialProperties( material, parameters ); 30036 30037 return program; 30038 30039 } 30040 30041 } else { 30042 30043 parameters.uniforms = programCache.getUniforms( material ); 30044 30045 material.onBuild( object, parameters, _this ); 30046 30047 material.onBeforeCompile( parameters, _this ); 30048 30049 program = programCache.acquireProgram( parameters, programCacheKey ); 30050 programs.set( programCacheKey, program ); 30051 30052 materialProperties.uniforms = parameters.uniforms; 30053 30054 } 30055 30056 const uniforms = materialProperties.uniforms; 30057 30058 if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) { 30059 30060 uniforms.clippingPlanes = clipping.uniform; 30061 30062 } 30063 30064 updateCommonMaterialProperties( material, parameters ); 30065 30066 // store the light setup it was created for 30067 30068 materialProperties.needsLights = materialNeedsLights( material ); 30069 materialProperties.lightsStateVersion = lightsStateVersion; 30070 30071 if ( materialProperties.needsLights ) { 30072 30073 // wire up the material to this renderer's lighting state 30074 30075 uniforms.ambientLightColor.value = lights.state.ambient; 30076 uniforms.lightProbe.value = lights.state.probe; 30077 uniforms.directionalLights.value = lights.state.directional; 30078 uniforms.directionalLightShadows.value = lights.state.directionalShadow; 30079 uniforms.spotLights.value = lights.state.spot; 30080 uniforms.spotLightShadows.value = lights.state.spotShadow; 30081 uniforms.rectAreaLights.value = lights.state.rectArea; 30082 uniforms.ltc_1.value = lights.state.rectAreaLTC1; 30083 uniforms.ltc_2.value = lights.state.rectAreaLTC2; 30084 uniforms.pointLights.value = lights.state.point; 30085 uniforms.pointLightShadows.value = lights.state.pointShadow; 30086 uniforms.hemisphereLights.value = lights.state.hemi; 30087 30088 uniforms.directionalShadowMap.value = lights.state.directionalShadowMap; 30089 uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix; 30090 uniforms.spotShadowMap.value = lights.state.spotShadowMap; 30091 uniforms.spotLightMatrix.value = lights.state.spotLightMatrix; 30092 uniforms.spotLightMap.value = lights.state.spotLightMap; 30093 uniforms.pointShadowMap.value = lights.state.pointShadowMap; 30094 uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix; 30095 // TODO (abelnation): add area lights shadow info to uniforms 30096 30097 } 30098 30099 materialProperties.currentProgram = program; 30100 materialProperties.uniformsList = null; 30101 30102 return program; 30103 30104 } 30105 30106 function getUniformList( materialProperties ) { 30107 30108 if ( materialProperties.uniformsList === null ) { 30109 30110 const progUniforms = materialProperties.currentProgram.getUniforms(); 30111 materialProperties.uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, materialProperties.uniforms ); 30112 30113 } 30114 30115 return materialProperties.uniformsList; 30116 30117 } 30118 30119 function updateCommonMaterialProperties( material, parameters ) { 30120 30121 const materialProperties = properties.get( material ); 30122 30123 materialProperties.outputColorSpace = parameters.outputColorSpace; 30124 materialProperties.batching = parameters.batching; 30125 materialProperties.instancing = parameters.instancing; 30126 materialProperties.instancingColor = parameters.instancingColor; 30127 materialProperties.skinning = parameters.skinning; 30128 materialProperties.morphTargets = parameters.morphTargets; 30129 materialProperties.morphNormals = parameters.morphNormals; 30130 materialProperties.morphColors = parameters.morphColors; 30131 materialProperties.morphTargetsCount = parameters.morphTargetsCount; 30132 materialProperties.numClippingPlanes = parameters.numClippingPlanes; 30133 materialProperties.numIntersection = parameters.numClipIntersection; 30134 materialProperties.vertexAlphas = parameters.vertexAlphas; 30135 materialProperties.vertexTangents = parameters.vertexTangents; 30136 materialProperties.toneMapping = parameters.toneMapping; 30137 30138 } 30139 30140 function setProgram( camera, scene, geometry, material, object ) { 30141 30142 if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... 30143 30144 textures.resetTextureUnits(); 30145 30146 const fog = scene.fog; 30147 const environment = material.isMeshStandardMaterial ? scene.environment : null; 30148 const colorSpace = ( _currentRenderTarget === null ) ? _this.outputColorSpace : ( _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ); 30149 const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment ); 30150 const vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4; 30151 const vertexTangents = !! geometry.attributes.tangent && ( !! material.normalMap || material.anisotropy > 0 ); 30152 const morphTargets = !! geometry.morphAttributes.position; 30153 const morphNormals = !! geometry.morphAttributes.normal; 30154 const morphColors = !! geometry.morphAttributes.color; 30155 30156 let toneMapping = NoToneMapping; 30157 30158 if ( material.toneMapped ) { 30159 30160 if ( _currentRenderTarget === null || _currentRenderTarget.isXRRenderTarget === true ) { 30161 30162 toneMapping = _this.toneMapping; 30163 30164 } 30165 30166 } 30167 30168 const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; 30169 const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; 30170 30171 const materialProperties = properties.get( material ); 30172 const lights = currentRenderState.state.lights; 30173 30174 if ( _clippingEnabled === true ) { 30175 30176 if ( _localClippingEnabled === true || camera !== _currentCamera ) { 30177 30178 const useCache = 30179 camera === _currentCamera && 30180 material.id === _currentMaterialId; 30181 30182 // we might want to call this function with some ClippingGroup 30183 // object instead of the material, once it becomes feasible 30184 // (#8465, #8379) 30185 clipping.setState( material, camera, useCache ); 30186 30187 } 30188 30189 } 30190 30191 // 30192 30193 let needsProgramChange = false; 30194 30195 if ( material.version === materialProperties.__version ) { 30196 30197 if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) { 30198 30199 needsProgramChange = true; 30200 30201 } else if ( materialProperties.outputColorSpace !== colorSpace ) { 30202 30203 needsProgramChange = true; 30204 30205 } else if ( object.isBatchedMesh && materialProperties.batching === false ) { 30206 30207 needsProgramChange = true; 30208 30209 } else if ( ! object.isBatchedMesh && materialProperties.batching === true ) { 30210 30211 needsProgramChange = true; 30212 30213 } else if ( object.isInstancedMesh && materialProperties.instancing === false ) { 30214 30215 needsProgramChange = true; 30216 30217 } else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) { 30218 30219 needsProgramChange = true; 30220 30221 } else if ( object.isSkinnedMesh && materialProperties.skinning === false ) { 30222 30223 needsProgramChange = true; 30224 30225 } else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) { 30226 30227 needsProgramChange = true; 30228 30229 } else if ( object.isInstancedMesh && materialProperties.instancingColor === true && object.instanceColor === null ) { 30230 30231 needsProgramChange = true; 30232 30233 } else if ( object.isInstancedMesh && materialProperties.instancingColor === false && object.instanceColor !== null ) { 30234 30235 needsProgramChange = true; 30236 30237 } else if ( materialProperties.envMap !== envMap ) { 30238 30239 needsProgramChange = true; 30240 30241 } else if ( material.fog === true && materialProperties.fog !== fog ) { 30242 30243 needsProgramChange = true; 30244 30245 } else if ( materialProperties.numClippingPlanes !== undefined && 30246 ( materialProperties.numClippingPlanes !== clipping.numPlanes || 30247 materialProperties.numIntersection !== clipping.numIntersection ) ) { 30248 30249 needsProgramChange = true; 30250 30251 } else if ( materialProperties.vertexAlphas !== vertexAlphas ) { 30252 30253 needsProgramChange = true; 30254 30255 } else if ( materialProperties.vertexTangents !== vertexTangents ) { 30256 30257 needsProgramChange = true; 30258 30259 } else if ( materialProperties.morphTargets !== morphTargets ) { 30260 30261 needsProgramChange = true; 30262 30263 } else if ( materialProperties.morphNormals !== morphNormals ) { 30264 30265 needsProgramChange = true; 30266 30267 } else if ( materialProperties.morphColors !== morphColors ) { 30268 30269 needsProgramChange = true; 30270 30271 } else if ( materialProperties.toneMapping !== toneMapping ) { 30272 30273 needsProgramChange = true; 30274 30275 } else if ( capabilities.isWebGL2 === true && materialProperties.morphTargetsCount !== morphTargetsCount ) { 30276 30277 needsProgramChange = true; 30278 30279 } 30280 30281 } else { 30282 30283 needsProgramChange = true; 30284 materialProperties.__version = material.version; 30285 30286 } 30287 30288 // 30289 30290 let program = materialProperties.currentProgram; 30291 30292 if ( needsProgramChange === true ) { 30293 30294 program = getProgram( material, scene, object ); 30295 30296 } 30297 30298 let refreshProgram = false; 30299 let refreshMaterial = false; 30300 let refreshLights = false; 30301 30302 const p_uniforms = program.getUniforms(), 30303 m_uniforms = materialProperties.uniforms; 30304 30305 if ( state.useProgram( program.program ) ) { 30306 30307 refreshProgram = true; 30308 refreshMaterial = true; 30309 refreshLights = true; 30310 30311 } 30312 30313 if ( material.id !== _currentMaterialId ) { 30314 30315 _currentMaterialId = material.id; 30316 30317 refreshMaterial = true; 30318 30319 } 30320 30321 if ( refreshProgram || _currentCamera !== camera ) { 30322 30323 // common camera uniforms 30324 30325 p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); 30326 p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); 30327 30328 const uCamPos = p_uniforms.map.cameraPosition; 30329 30330 if ( uCamPos !== undefined ) { 30331 30332 uCamPos.setValue( _gl, _vector3.setFromMatrixPosition( camera.matrixWorld ) ); 30333 30334 } 30335 30336 if ( capabilities.logarithmicDepthBuffer ) { 30337 30338 p_uniforms.setValue( _gl, 'logDepthBufFC', 30339 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); 30340 30341 } 30342 30343 // consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067 30344 30345 if ( material.isMeshPhongMaterial || 30346 material.isMeshToonMaterial || 30347 material.isMeshLambertMaterial || 30348 material.isMeshBasicMaterial || 30349 material.isMeshStandardMaterial || 30350 material.isShaderMaterial ) { 30351 30352 p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true ); 30353 30354 } 30355 30356 if ( _currentCamera !== camera ) { 30357 30358 _currentCamera = camera; 30359 30360 // lighting uniforms depend on the camera so enforce an update 30361 // now, in case this material supports lights - or later, when 30362 // the next material that does gets activated: 30363 30364 refreshMaterial = true; // set to true on material change 30365 refreshLights = true; // remains set until update done 30366 30367 } 30368 30369 } 30370 30371 // skinning and morph target uniforms must be set even if material didn't change 30372 // auto-setting of texture unit for bone and morph texture must go before other textures 30373 // otherwise textures used for skinning and morphing can take over texture units reserved for other material textures 30374 30375 if ( object.isSkinnedMesh ) { 30376 30377 p_uniforms.setOptional( _gl, object, 'bindMatrix' ); 30378 p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); 30379 30380 const skeleton = object.skeleton; 30381 30382 if ( skeleton ) { 30383 30384 if ( capabilities.floatVertexTextures ) { 30385 30386 if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture(); 30387 30388 p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures ); 30389 30390 } else { 30391 30392 console.warn( 'THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required.' ); 30393 30394 } 30395 30396 } 30397 30398 } 30399 30400 if ( object.isBatchedMesh ) { 30401 30402 p_uniforms.setOptional( _gl, object, 'batchingTexture' ); 30403 p_uniforms.setValue( _gl, 'batchingTexture', object._matricesTexture, textures ); 30404 30405 } 30406 30407 const morphAttributes = geometry.morphAttributes; 30408 30409 if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined && capabilities.isWebGL2 === true ) ) { 30410 30411 morphtargets.update( object, geometry, program ); 30412 30413 } 30414 30415 if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) { 30416 30417 materialProperties.receiveShadow = object.receiveShadow; 30418 p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow ); 30419 30420 } 30421 30422 // https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512 30423 30424 if ( material.isMeshGouraudMaterial && material.envMap !== null ) { 30425 30426 m_uniforms.envMap.value = envMap; 30427 30428 m_uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1; 30429 30430 } 30431 30432 if ( refreshMaterial ) { 30433 30434 p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); 30435 30436 if ( materialProperties.needsLights ) { 30437 30438 // the current material requires lighting info 30439 30440 // note: all lighting uniforms are always set correctly 30441 // they simply reference the renderer's state for their 30442 // values 30443 // 30444 // use the current material's .needsUpdate flags to set 30445 // the GL state when required 30446 30447 markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); 30448 30449 } 30450 30451 // refresh uniforms common to several materials 30452 30453 if ( fog && material.fog === true ) { 30454 30455 materials.refreshFogUniforms( m_uniforms, fog ); 30456 30457 } 30458 30459 materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, _transmissionRenderTarget ); 30460 30461 WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures ); 30462 30463 } 30464 30465 if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) { 30466 30467 WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures ); 30468 material.uniformsNeedUpdate = false; 30469 30470 } 30471 30472 if ( material.isSpriteMaterial ) { 30473 30474 p_uniforms.setValue( _gl, 'center', object.center ); 30475 30476 } 30477 30478 // common matrices 30479 30480 p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix ); 30481 p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix ); 30482 p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); 30483 30484 // UBOs 30485 30486 if ( material.isShaderMaterial || material.isRawShaderMaterial ) { 30487 30488 const groups = material.uniformsGroups; 30489 30490 for ( let i = 0, l = groups.length; i < l; i ++ ) { 30491 30492 if ( capabilities.isWebGL2 ) { 30493 30494 const group = groups[ i ]; 30495 30496 uniformsGroups.update( group, program ); 30497 uniformsGroups.bind( group, program ); 30498 30499 } else { 30500 30501 console.warn( 'THREE.WebGLRenderer: Uniform Buffer Objects can only be used with WebGL 2.' ); 30502 30503 } 30504 30505 } 30506 30507 } 30508 30509 return program; 30510 30511 } 30512 30513 // If uniforms are marked as clean, they don't need to be loaded to the GPU. 30514 30515 function markUniformsLightsNeedsUpdate( uniforms, value ) { 30516 30517 uniforms.ambientLightColor.needsUpdate = value; 30518 uniforms.lightProbe.needsUpdate = value; 30519 30520 uniforms.directionalLights.needsUpdate = value; 30521 uniforms.directionalLightShadows.needsUpdate = value; 30522 uniforms.pointLights.needsUpdate = value; 30523 uniforms.pointLightShadows.needsUpdate = value; 30524 uniforms.spotLights.needsUpdate = value; 30525 uniforms.spotLightShadows.needsUpdate = value; 30526 uniforms.rectAreaLights.needsUpdate = value; 30527 uniforms.hemisphereLights.needsUpdate = value; 30528 30529 } 30530 30531 function materialNeedsLights( material ) { 30532 30533 return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial || 30534 material.isMeshStandardMaterial || material.isShadowMaterial || 30535 ( material.isShaderMaterial && material.lights === true ); 30536 30537 } 30538 30539 this.getActiveCubeFace = function () { 30540 30541 return _currentActiveCubeFace; 30542 30543 }; 30544 30545 this.getActiveMipmapLevel = function () { 30546 30547 return _currentActiveMipmapLevel; 30548 30549 }; 30550 30551 this.getRenderTarget = function () { 30552 30553 return _currentRenderTarget; 30554 30555 }; 30556 30557 this.setRenderTargetTextures = function ( renderTarget, colorTexture, depthTexture ) { 30558 30559 properties.get( renderTarget.texture ).__webglTexture = colorTexture; 30560 properties.get( renderTarget.depthTexture ).__webglTexture = depthTexture; 30561 30562 const renderTargetProperties = properties.get( renderTarget ); 30563 renderTargetProperties.__hasExternalTextures = true; 30564 30565 if ( renderTargetProperties.__hasExternalTextures ) { 30566 30567 renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined; 30568 30569 if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) { 30570 30571 // The multisample_render_to_texture extension doesn't work properly if there 30572 // are midframe flushes and an external depth buffer. Disable use of the extension. 30573 if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) { 30574 30575 console.warn( 'THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided' ); 30576 renderTargetProperties.__useRenderToTexture = false; 30577 30578 } 30579 30580 } 30581 30582 } 30583 30584 }; 30585 30586 this.setRenderTargetFramebuffer = function ( renderTarget, defaultFramebuffer ) { 30587 30588 const renderTargetProperties = properties.get( renderTarget ); 30589 renderTargetProperties.__webglFramebuffer = defaultFramebuffer; 30590 renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined; 30591 30592 }; 30593 30594 this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { 30595 30596 _currentRenderTarget = renderTarget; 30597 _currentActiveCubeFace = activeCubeFace; 30598 _currentActiveMipmapLevel = activeMipmapLevel; 30599 30600 let useDefaultFramebuffer = true; 30601 let framebuffer = null; 30602 let isCube = false; 30603 let isRenderTarget3D = false; 30604 30605 if ( renderTarget ) { 30606 30607 const renderTargetProperties = properties.get( renderTarget ); 30608 30609 if ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) { 30610 30611 // We need to make sure to rebind the framebuffer. 30612 state.bindFramebuffer( _gl.FRAMEBUFFER, null ); 30613 useDefaultFramebuffer = false; 30614 30615 } else if ( renderTargetProperties.__webglFramebuffer === undefined ) { 30616 30617 textures.setupRenderTarget( renderTarget ); 30618 30619 } else if ( renderTargetProperties.__hasExternalTextures ) { 30620 30621 // Color and depth texture must be rebound in order for the swapchain to update. 30622 textures.rebindTextures( renderTarget, properties.get( renderTarget.texture ).__webglTexture, properties.get( renderTarget.depthTexture ).__webglTexture ); 30623 30624 } 30625 30626 const texture = renderTarget.texture; 30627 30628 if ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { 30629 30630 isRenderTarget3D = true; 30631 30632 } 30633 30634 const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer; 30635 30636 if ( renderTarget.isWebGLCubeRenderTarget ) { 30637 30638 if ( Array.isArray( __webglFramebuffer[ activeCubeFace ] ) ) { 30639 30640 framebuffer = __webglFramebuffer[ activeCubeFace ][ activeMipmapLevel ]; 30641 30642 } else { 30643 30644 framebuffer = __webglFramebuffer[ activeCubeFace ]; 30645 30646 } 30647 30648 isCube = true; 30649 30650 } else if ( ( capabilities.isWebGL2 && renderTarget.samples > 0 ) && textures.useMultisampledRTT( renderTarget ) === false ) { 30651 30652 framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer; 30653 30654 } else { 30655 30656 if ( Array.isArray( __webglFramebuffer ) ) { 30657 30658 framebuffer = __webglFramebuffer[ activeMipmapLevel ]; 30659 30660 } else { 30661 30662 framebuffer = __webglFramebuffer; 30663 30664 } 30665 30666 } 30667 30668 _currentViewport.copy( renderTarget.viewport ); 30669 _currentScissor.copy( renderTarget.scissor ); 30670 _currentScissorTest = renderTarget.scissorTest; 30671 30672 } else { 30673 30674 _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor(); 30675 _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor(); 30676 _currentScissorTest = _scissorTest; 30677 30678 } 30679 30680 const framebufferBound = state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); 30681 30682 if ( framebufferBound && capabilities.drawBuffers && useDefaultFramebuffer ) { 30683 30684 state.drawBuffers( renderTarget, framebuffer ); 30685 30686 } 30687 30688 state.viewport( _currentViewport ); 30689 state.scissor( _currentScissor ); 30690 state.setScissorTest( _currentScissorTest ); 30691 30692 if ( isCube ) { 30693 30694 const textureProperties = properties.get( renderTarget.texture ); 30695 _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel ); 30696 30697 } else if ( isRenderTarget3D ) { 30698 30699 const textureProperties = properties.get( renderTarget.texture ); 30700 const layer = activeCubeFace || 0; 30701 _gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel || 0, layer ); 30702 30703 } 30704 30705 _currentMaterialId = - 1; // reset current material to ensure correct uniform bindings 30706 30707 }; 30708 30709 this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) { 30710 30711 if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { 30712 30713 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); 30714 return; 30715 30716 } 30717 30718 let framebuffer = properties.get( renderTarget ).__webglFramebuffer; 30719 30720 if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) { 30721 30722 framebuffer = framebuffer[ activeCubeFaceIndex ]; 30723 30724 } 30725 30726 if ( framebuffer ) { 30727 30728 state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); 30729 30730 try { 30731 30732 const texture = renderTarget.texture; 30733 const textureFormat = texture.format; 30734 const textureType = texture.type; 30735 30736 if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) { 30737 30738 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); 30739 return; 30740 30741 } 30742 30743 const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) ); 30744 30745 if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // Edge and Chrome Mac < 52 (#9513) 30746 ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox 30747 ! halfFloatSupportedByExt ) { 30748 30749 console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); 30750 return; 30751 30752 } 30753 30754 // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) 30755 30756 if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { 30757 30758 _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer ); 30759 30760 } 30761 30762 } finally { 30763 30764 // restore framebuffer of current render target if necessary 30765 30766 const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null; 30767 state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); 30768 30769 } 30770 30771 } 30772 30773 }; 30774 30775 this.copyFramebufferToTexture = function ( position, texture, level = 0 ) { 30776 30777 const levelScale = Math.pow( 2, - level ); 30778 const width = Math.floor( texture.image.width * levelScale ); 30779 const height = Math.floor( texture.image.height * levelScale ); 30780 30781 textures.setTexture2D( texture, 0 ); 30782 30783 _gl.copyTexSubImage2D( _gl.TEXTURE_2D, level, 0, 0, position.x, position.y, width, height ); 30784 30785 state.unbindTexture(); 30786 30787 }; 30788 30789 this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) { 30790 30791 const width = srcTexture.image.width; 30792 const height = srcTexture.image.height; 30793 const glFormat = utils.convert( dstTexture.format ); 30794 const glType = utils.convert( dstTexture.type ); 30795 30796 textures.setTexture2D( dstTexture, 0 ); 30797 30798 // As another texture upload may have changed pixelStorei 30799 // parameters, make sure they are correct for the dstTexture 30800 _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY ); 30801 _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha ); 30802 _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment ); 30803 30804 if ( srcTexture.isDataTexture ) { 30805 30806 _gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data ); 30807 30808 } else { 30809 30810 if ( srcTexture.isCompressedTexture ) { 30811 30812 _gl.compressedTexSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data ); 30813 30814 } else { 30815 30816 _gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, glFormat, glType, srcTexture.image ); 30817 30818 } 30819 30820 } 30821 30822 // Generate mipmaps only when copying level 0 30823 if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( _gl.TEXTURE_2D ); 30824 30825 state.unbindTexture(); 30826 30827 }; 30828 30829 this.copyTextureToTexture3D = function ( sourceBox, position, srcTexture, dstTexture, level = 0 ) { 30830 30831 if ( _this.isWebGL1Renderer ) { 30832 30833 console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.' ); 30834 return; 30835 30836 } 30837 30838 const width = sourceBox.max.x - sourceBox.min.x + 1; 30839 const height = sourceBox.max.y - sourceBox.min.y + 1; 30840 const depth = sourceBox.max.z - sourceBox.min.z + 1; 30841 const glFormat = utils.convert( dstTexture.format ); 30842 const glType = utils.convert( dstTexture.type ); 30843 let glTarget; 30844 30845 if ( dstTexture.isData3DTexture ) { 30846 30847 textures.setTexture3D( dstTexture, 0 ); 30848 glTarget = _gl.TEXTURE_3D; 30849 30850 } else if ( dstTexture.isDataArrayTexture || dstTexture.isCompressedArrayTexture ) { 30851 30852 textures.setTexture2DArray( dstTexture, 0 ); 30853 glTarget = _gl.TEXTURE_2D_ARRAY; 30854 30855 } else { 30856 30857 console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.' ); 30858 return; 30859 30860 } 30861 30862 _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY ); 30863 _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha ); 30864 _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment ); 30865 30866 const unpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH ); 30867 const unpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT ); 30868 const unpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS ); 30869 const unpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS ); 30870 const unpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES ); 30871 30872 const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ] : srcTexture.image; 30873 30874 _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width ); 30875 _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height ); 30876 _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, sourceBox.min.x ); 30877 _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, sourceBox.min.y ); 30878 _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, sourceBox.min.z ); 30879 30880 if ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) { 30881 30882 _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image.data ); 30883 30884 } else { 30885 30886 if ( srcTexture.isCompressedArrayTexture ) { 30887 30888 console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture.' ); 30889 _gl.compressedTexSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, image.data ); 30890 30891 } else { 30892 30893 _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image ); 30894 30895 } 30896 30897 } 30898 30899 _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, unpackRowLen ); 30900 _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, unpackImageHeight ); 30901 _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, unpackSkipPixels ); 30902 _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, unpackSkipRows ); 30903 _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, unpackSkipImages ); 30904 30905 // Generate mipmaps only when copying level 0 30906 if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget ); 30907 30908 state.unbindTexture(); 30909 30910 }; 30911 30912 this.initTexture = function ( texture ) { 30913 30914 if ( texture.isCubeTexture ) { 30915 30916 textures.setTextureCube( texture, 0 ); 30917 30918 } else if ( texture.isData3DTexture ) { 30919 30920 textures.setTexture3D( texture, 0 ); 30921 30922 } else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { 30923 30924 textures.setTexture2DArray( texture, 0 ); 30925 30926 } else { 30927 30928 textures.setTexture2D( texture, 0 ); 30929 30930 } 30931 30932 state.unbindTexture(); 30933 30934 }; 30935 30936 this.resetState = function () { 30937 30938 _currentActiveCubeFace = 0; 30939 _currentActiveMipmapLevel = 0; 30940 _currentRenderTarget = null; 30941 30942 state.reset(); 30943 bindingStates.reset(); 30944 30945 }; 30946 30947 if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { 30948 30949 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); 30950 30951 } 30952 30953 } 30954 30955 get coordinateSystem() { 30956 30957 return WebGLCoordinateSystem; 30958 30959 } 30960 30961 get outputColorSpace() { 30962 30963 return this._outputColorSpace; 30964 30965 } 30966 30967 set outputColorSpace( colorSpace ) { 30968 30969 this._outputColorSpace = colorSpace; 30970 30971 const gl = this.getContext(); 30972 gl.drawingBufferColorSpace = colorSpace === DisplayP3ColorSpace ? 'display-p3' : 'srgb'; 30973 gl.unpackColorSpace = ColorManagement.workingColorSpace === LinearDisplayP3ColorSpace ? 'display-p3' : 'srgb'; 30974 30975 } 30976 30977 get outputEncoding() { // @deprecated, r152 30978 30979 console.warn( 'THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead.' ); 30980 return this.outputColorSpace === SRGBColorSpace ? sRGBEncoding : LinearEncoding; 30981 30982 } 30983 30984 set outputEncoding( encoding ) { // @deprecated, r152 30985 30986 console.warn( 'THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead.' ); 30987 this.outputColorSpace = encoding === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace; 30988 30989 } 30990 30991 get useLegacyLights() { // @deprecated, r155 30992 30993 console.warn( 'THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733.' ); 30994 return this._useLegacyLights; 30995 30996 } 30997 30998 set useLegacyLights( value ) { // @deprecated, r155 30999 31000 console.warn( 'THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733.' ); 31001 this._useLegacyLights = value; 31002 31003 } 31004 31005} 31006 31007class WebGL1Renderer extends WebGLRenderer {} 31008 31009WebGL1Renderer.prototype.isWebGL1Renderer = true; 31010 31011class FogExp2 { 31012 31013 constructor( color, density = 0.00025 ) { 31014 31015 this.isFogExp2 = true; 31016 31017 this.name = ''; 31018 31019 this.color = new Color( color ); 31020 this.density = density; 31021 31022 } 31023 31024 clone() { 31025 31026 return new FogExp2( this.color, this.density ); 31027 31028 } 31029 31030 toJSON( /* meta */ ) { 31031 31032 return { 31033 type: 'FogExp2', 31034 name: this.name,
vendor: 5,247 bytes, lines 31035-31334
31035 color: this.color.getHex(), 31036 density: this.density 31037 }; 31038 31039 } 31040 31041} 31042 31043class Fog { 31044 31045 constructor( color, near = 1, far = 1000 ) { 31046 31047 this.isFog = true; 31048 31049 this.name = ''; 31050 31051 this.color = new Color( color ); 31052 31053 this.near = near; 31054 this.far = far; 31055 31056 } 31057 31058 clone() { 31059 31060 return new Fog( this.color, this.near, this.far ); 31061 31062 } 31063 31064 toJSON( /* meta */ ) { 31065 31066 return { 31067 type: 'Fog', 31068 name: this.name, 31069 color: this.color.getHex(), 31070 near: this.near, 31071 far: this.far 31072 }; 31073 31074 } 31075 31076} 31077 31078class Scene extends Object3D { 31079 31080 constructor() { 31081 31082 super(); 31083 31084 this.isScene = true; 31085 31086 this.type = 'Scene'; 31087 31088 this.background = null; 31089 this.environment = null; 31090 this.fog = null; 31091 31092 this.backgroundBlurriness = 0; 31093 this.backgroundIntensity = 1; 31094 31095 this.overrideMaterial = null; 31096 31097 if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { 31098 31099 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); 31100 31101 } 31102 31103 } 31104 31105 copy( source, recursive ) { 31106 31107 super.copy( source, recursive ); 31108 31109 if ( source.background !== null ) this.background = source.background.clone(); 31110 if ( source.environment !== null ) this.environment = source.environment.clone(); 31111 if ( source.fog !== null ) this.fog = source.fog.clone(); 31112 31113 this.backgroundBlurriness = source.backgroundBlurriness; 31114 this.backgroundIntensity = source.backgroundIntensity; 31115 31116 if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone(); 31117 31118 this.matrixAutoUpdate = source.matrixAutoUpdate; 31119 31120 return this; 31121 31122 } 31123 31124 toJSON( meta ) { 31125 31126 const data = super.toJSON( meta ); 31127 31128 if ( this.fog !== null ) data.object.fog = this.fog.toJSON(); 31129 if ( this.backgroundBlurriness > 0 ) data.object.backgroundBlurriness = this.backgroundBlurriness; 31130 if ( this.backgroundIntensity !== 1 ) data.object.backgroundIntensity = this.backgroundIntensity; 31131 31132 return data; 31133 31134 } 31135 31136} 31137 31138class InterleavedBuffer { 31139 31140 constructor( array, stride ) { 31141 31142 this.isInterleavedBuffer = true; 31143 31144 this.array = array; 31145 this.stride = stride; 31146 this.count = array !== undefined ? array.length / stride : 0; 31147 31148 this.usage = StaticDrawUsage; 31149 this._updateRange = { offset: 0, count: - 1 }; 31150 this.updateRanges = []; 31151 31152 this.version = 0; 31153 31154 this.uuid = generateUUID(); 31155 31156 } 31157 31158 onUploadCallback() {} 31159 31160 set needsUpdate( value ) { 31161 31162 if ( value === true ) this.version ++; 31163 31164 } 31165 31166 get updateRange() { 31167 31168 console.warn( 'THREE.InterleavedBuffer: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159 31169 return this._updateRange; 31170 31171 } 31172 31173 setUsage( value ) { 31174 31175 this.usage = value; 31176 31177 return this; 31178 31179 } 31180 31181 addUpdateRange( start, count ) { 31182 31183 this.updateRanges.push( { start, count } ); 31184 31185 } 31186 31187 clearUpdateRanges() { 31188 31189 this.updateRanges.length = 0; 31190 31191 } 31192 31193 copy( source ) { 31194 31195 this.array = new source.array.constructor( source.array ); 31196 this.count = source.count; 31197 this.stride = source.stride; 31198 this.usage = source.usage; 31199 31200 return this; 31201 31202 } 31203 31204 copyAt( index1, attribute, index2 ) { 31205 31206 index1 *= this.stride; 31207 index2 *= attribute.stride; 31208 31209 for ( let i = 0, l = this.stride; i < l; i ++ ) { 31210 31211 this.array[ index1 + i ] = attribute.array[ index2 + i ]; 31212 31213 } 31214 31215 return this; 31216 31217 } 31218 31219 set( value, offset = 0 ) { 31220 31221 this.array.set( value, offset ); 31222 31223 return this; 31224 31225 } 31226 31227 clone( data ) { 31228 31229 if ( data.arrayBuffers === undefined ) { 31230 31231 data.arrayBuffers = {}; 31232 31233 } 31234 31235 if ( this.array.buffer._uuid === undefined ) { 31236 31237 this.array.buffer._uuid = generateUUID(); 31238 31239 } 31240 31241 if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) { 31242 31243 data.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer; 31244 31245 } 31246 31247 const array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] ); 31248 31249 const ib = new this.constructor( array, this.stride ); 31250 ib.setUsage( this.usage ); 31251 31252 return ib; 31253 31254 } 31255 31256 onUpload( callback ) { 31257 31258 this.onUploadCallback = callback; 31259 31260 return this; 31261 31262 } 31263 31264 toJSON( data ) { 31265 31266 if ( data.arrayBuffers === undefined ) { 31267 31268 data.arrayBuffers = {}; 31269 31270 } 31271 31272 // generate UUID for array buffer if necessary 31273 31274 if ( this.array.buffer._uuid === undefined ) { 31275 31276 this.array.buffer._uuid = generateUUID(); 31277 31278 } 31279 31280 if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) { 31281 31282 data.arrayBuffers[ this.array.buffer._uuid ] = Array.from( new Uint32Array( this.array.buffer ) ); 31283 31284 } 31285 31286 // 31287 31288 return { 31289 uuid: this.uuid, 31290 buffer: this.array.buffer._uuid, 31291 type: this.array.constructor.name, 31292 stride: this.stride 31293 }; 31294 31295 } 31296 31297} 31298 31299const _vector$6 = /*@__PURE__*/ new Vector3(); 31300 31301class InterleavedBufferAttribute { 31302 31303 constructor( interleavedBuffer, itemSize, offset, normalized = false ) { 31304 31305 this.isInterleavedBufferAttribute = true; 31306 31307 this.name = ''; 31308 31309 this.data = interleavedBuffer; 31310 this.itemSize = itemSize; 31311 this.offset = offset; 31312 31313 this.normalized = normalized; 31314 31315 } 31316 31317 get count() { 31318 31319 return this.data.count; 31320 31321 } 31322 31323 get array() { 31324 31325 return this.data.array; 31326 31327 } 31328 31329 set needsUpdate( value ) { 31330 31331 this.data.needsUpdate = value; 31332 31333 } 31334
vendor: 17,794 bytes, lines 31335-32237
31335 applyMatrix4( m ) { 31336 31337 for ( let i = 0, l = this.data.count; i < l; i ++ ) { 31338 31339 _vector$6.fromBufferAttribute( this, i ); 31340 31341 _vector$6.applyMatrix4( m ); 31342 31343 this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z ); 31344 31345 } 31346 31347 return this; 31348 31349 } 31350 31351 applyNormalMatrix( m ) { 31352 31353 for ( let i = 0, l = this.count; i < l; i ++ ) { 31354 31355 _vector$6.fromBufferAttribute( this, i ); 31356 31357 _vector$6.applyNormalMatrix( m ); 31358 31359 this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z ); 31360 31361 } 31362 31363 return this; 31364 31365 } 31366 31367 transformDirection( m ) { 31368 31369 for ( let i = 0, l = this.count; i < l; i ++ ) { 31370 31371 _vector$6.fromBufferAttribute( this, i ); 31372 31373 _vector$6.transformDirection( m ); 31374 31375 this.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z ); 31376 31377 } 31378 31379 return this; 31380 31381 } 31382 31383 setX( index, x ) { 31384 31385 if ( this.normalized ) x = normalize( x, this.array ); 31386 31387 this.data.array[ index * this.data.stride + this.offset ] = x; 31388 31389 return this; 31390 31391 } 31392 31393 setY( index, y ) { 31394 31395 if ( this.normalized ) y = normalize( y, this.array ); 31396 31397 this.data.array[ index * this.data.stride + this.offset + 1 ] = y; 31398 31399 return this; 31400 31401 } 31402 31403 setZ( index, z ) { 31404 31405 if ( this.normalized ) z = normalize( z, this.array ); 31406 31407 this.data.array[ index * this.data.stride + this.offset + 2 ] = z; 31408 31409 return this; 31410 31411 } 31412 31413 setW( index, w ) { 31414 31415 if ( this.normalized ) w = normalize( w, this.array ); 31416 31417 this.data.array[ index * this.data.stride + this.offset + 3 ] = w; 31418 31419 return this; 31420 31421 } 31422 31423 getX( index ) { 31424 31425 let x = this.data.array[ index * this.data.stride + this.offset ]; 31426 31427 if ( this.normalized ) x = denormalize( x, this.array ); 31428 31429 return x; 31430 31431 } 31432 31433 getY( index ) { 31434 31435 let y = this.data.array[ index * this.data.stride + this.offset + 1 ]; 31436 31437 if ( this.normalized ) y = denormalize( y, this.array ); 31438 31439 return y; 31440 31441 } 31442 31443 getZ( index ) { 31444 31445 let z = this.data.array[ index * this.data.stride + this.offset + 2 ]; 31446 31447 if ( this.normalized ) z = denormalize( z, this.array ); 31448 31449 return z; 31450 31451 } 31452 31453 getW( index ) { 31454 31455 let w = this.data.array[ index * this.data.stride + this.offset + 3 ]; 31456 31457 if ( this.normalized ) w = denormalize( w, this.array ); 31458 31459 return w; 31460 31461 } 31462 31463 setXY( index, x, y ) { 31464 31465 index = index * this.data.stride + this.offset; 31466 31467 if ( this.normalized ) { 31468 31469 x = normalize( x, this.array ); 31470 y = normalize( y, this.array ); 31471 31472 } 31473 31474 this.data.array[ index + 0 ] = x; 31475 this.data.array[ index + 1 ] = y; 31476 31477 return this; 31478 31479 } 31480 31481 setXYZ( index, x, y, z ) { 31482 31483 index = index * this.data.stride + this.offset; 31484 31485 if ( this.normalized ) { 31486 31487 x = normalize( x, this.array ); 31488 y = normalize( y, this.array ); 31489 z = normalize( z, this.array ); 31490 31491 } 31492 31493 this.data.array[ index + 0 ] = x; 31494 this.data.array[ index + 1 ] = y; 31495 this.data.array[ index + 2 ] = z; 31496 31497 return this; 31498 31499 } 31500 31501 setXYZW( index, x, y, z, w ) { 31502 31503 index = index * this.data.stride + this.offset; 31504 31505 if ( this.normalized ) { 31506 31507 x = normalize( x, this.array ); 31508 y = normalize( y, this.array ); 31509 z = normalize( z, this.array ); 31510 w = normalize( w, this.array ); 31511 31512 } 31513 31514 this.data.array[ index + 0 ] = x; 31515 this.data.array[ index + 1 ] = y; 31516 this.data.array[ index + 2 ] = z; 31517 this.data.array[ index + 3 ] = w; 31518 31519 return this; 31520 31521 } 31522 31523 clone( data ) { 31524 31525 if ( data === undefined ) { 31526 31527 console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will de-interleave buffer data.' ); 31528 31529 const array = []; 31530 31531 for ( let i = 0; i < this.count; i ++ ) { 31532 31533 const index = i * this.data.stride + this.offset; 31534 31535 for ( let j = 0; j < this.itemSize; j ++ ) { 31536 31537 array.push( this.data.array[ index + j ] ); 31538 31539 } 31540 31541 } 31542 31543 return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized ); 31544 31545 } else { 31546 31547 if ( data.interleavedBuffers === undefined ) { 31548 31549 data.interleavedBuffers = {}; 31550 31551 } 31552 31553 if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { 31554 31555 data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data ); 31556 31557 } 31558 31559 return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized ); 31560 31561 } 31562 31563 } 31564 31565 toJSON( data ) { 31566 31567 if ( data === undefined ) { 31568 31569 console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will de-interleave buffer data.' ); 31570 31571 const array = []; 31572 31573 for ( let i = 0; i < this.count; i ++ ) { 31574 31575 const index = i * this.data.stride + this.offset; 31576 31577 for ( let j = 0; j < this.itemSize; j ++ ) { 31578 31579 array.push( this.data.array[ index + j ] ); 31580 31581 } 31582 31583 } 31584 31585 // de-interleave data and save it as an ordinary buffer attribute for now 31586 31587 return { 31588 itemSize: this.itemSize, 31589 type: this.array.constructor.name, 31590 array: array, 31591 normalized: this.normalized 31592 }; 31593 31594 } else { 31595 31596 // save as true interleaved attribute 31597 31598 if ( data.interleavedBuffers === undefined ) { 31599 31600 data.interleavedBuffers = {}; 31601 31602 } 31603 31604 if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { 31605 31606 data.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data ); 31607 31608 } 31609 31610 return { 31611 isInterleavedBufferAttribute: true, 31612 itemSize: this.itemSize, 31613 data: this.data.uuid, 31614 offset: this.offset, 31615 normalized: this.normalized 31616 }; 31617 31618 } 31619 31620 } 31621 31622} 31623 31624class SpriteMaterial extends Material { 31625 31626 constructor( parameters ) { 31627 31628 super(); 31629 31630 this.isSpriteMaterial = true; 31631 31632 this.type = 'SpriteMaterial'; 31633 31634 this.color = new Color( 0xffffff ); 31635 31636 this.map = null; 31637 31638 this.alphaMap = null; 31639 31640 this.rotation = 0; 31641 31642 this.sizeAttenuation = true; 31643 31644 this.transparent = true; 31645 31646 this.fog = true; 31647 31648 this.setValues( parameters ); 31649 31650 } 31651 31652 copy( source ) { 31653 31654 super.copy( source ); 31655 31656 this.color.copy( source.color ); 31657 31658 this.map = source.map; 31659 31660 this.alphaMap = source.alphaMap; 31661 31662 this.rotation = source.rotation; 31663 31664 this.sizeAttenuation = source.sizeAttenuation; 31665 31666 this.fog = source.fog; 31667 31668 return this; 31669 31670 } 31671 31672} 31673 31674let _geometry; 31675 31676const _intersectPoint = /*@__PURE__*/ new Vector3(); 31677const _worldScale = /*@__PURE__*/ new Vector3(); 31678const _mvPosition = /*@__PURE__*/ new Vector3(); 31679 31680const _alignedPosition = /*@__PURE__*/ new Vector2(); 31681const _rotatedPosition = /*@__PURE__*/ new Vector2(); 31682const _viewWorldMatrix = /*@__PURE__*/ new Matrix4(); 31683 31684const _vA = /*@__PURE__*/ new Vector3(); 31685const _vB = /*@__PURE__*/ new Vector3(); 31686const _vC = /*@__PURE__*/ new Vector3(); 31687 31688const _uvA = /*@__PURE__*/ new Vector2(); 31689const _uvB = /*@__PURE__*/ new Vector2(); 31690const _uvC = /*@__PURE__*/ new Vector2(); 31691 31692class Sprite extends Object3D { 31693 31694 constructor( material = new SpriteMaterial() ) { 31695 31696 super(); 31697 31698 this.isSprite = true; 31699 31700 this.type = 'Sprite'; 31701 31702 if ( _geometry === undefined ) { 31703 31704 _geometry = new BufferGeometry(); 31705 31706 const float32Array = new Float32Array( [ 31707 - 0.5, - 0.5, 0, 0, 0, 31708 0.5, - 0.5, 0, 1, 0, 31709 0.5, 0.5, 0, 1, 1, 31710 - 0.5, 0.5, 0, 0, 1 31711 ] ); 31712 31713 const interleavedBuffer = new InterleavedBuffer( float32Array, 5 ); 31714 31715 _geometry.setIndex( [ 0, 1, 2, 0, 2, 3 ] ); 31716 _geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) ); 31717 _geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) ); 31718 31719 } 31720 31721 this.geometry = _geometry; 31722 this.material = material; 31723 31724 this.center = new Vector2( 0.5, 0.5 ); 31725 31726 } 31727 31728 raycast( raycaster, intersects ) { 31729 31730 if ( raycaster.camera === null ) { 31731 31732 console.error( 'THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' ); 31733 31734 } 31735 31736 _worldScale.setFromMatrixScale( this.matrixWorld ); 31737 31738 _viewWorldMatrix.copy( raycaster.camera.matrixWorld ); 31739 this.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld ); 31740 31741 _mvPosition.setFromMatrixPosition( this.modelViewMatrix ); 31742 31743 if ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) { 31744 31745 _worldScale.multiplyScalar( - _mvPosition.z ); 31746 31747 } 31748 31749 const rotation = this.material.rotation; 31750 let sin, cos; 31751 31752 if ( rotation !== 0 ) { 31753 31754 cos = Math.cos( rotation ); 31755 sin = Math.sin( rotation ); 31756 31757 } 31758 31759 const center = this.center; 31760 31761 transformVertex( _vA.set( - 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); 31762 transformVertex( _vB.set( 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); 31763 transformVertex( _vC.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); 31764 31765 _uvA.set( 0, 0 ); 31766 _uvB.set( 1, 0 ); 31767 _uvC.set( 1, 1 ); 31768 31769 // check first triangle 31770 let intersect = raycaster.ray.intersectTriangle( _vA, _vB, _vC, false, _intersectPoint ); 31771 31772 if ( intersect === null ) { 31773 31774 // check second triangle 31775 transformVertex( _vB.set( - 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); 31776 _uvB.set( 0, 1 ); 31777 31778 intersect = raycaster.ray.intersectTriangle( _vA, _vC, _vB, false, _intersectPoint ); 31779 if ( intersect === null ) { 31780 31781 return; 31782 31783 } 31784 31785 } 31786 31787 const distance = raycaster.ray.origin.distanceTo( _intersectPoint ); 31788 31789 if ( distance < raycaster.near || distance > raycaster.far ) return; 31790 31791 intersects.push( { 31792 31793 distance: distance, 31794 point: _intersectPoint.clone(), 31795 uv: Triangle.getInterpolation( _intersectPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() ), 31796 face: null, 31797 object: this 31798 31799 } ); 31800 31801 } 31802 31803 copy( source, recursive ) { 31804 31805 super.copy( source, recursive ); 31806 31807 if ( source.center !== undefined ) this.center.copy( source.center ); 31808 31809 this.material = source.material; 31810 31811 return this; 31812 31813 } 31814 31815} 31816 31817function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) { 31818 31819 // compute position in camera space 31820 _alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale ); 31821 31822 // to check if rotation is not zero 31823 if ( sin !== undefined ) { 31824 31825 _rotatedPosition.x = ( cos * _alignedPosition.x ) - ( sin * _alignedPosition.y ); 31826 _rotatedPosition.y = ( sin * _alignedPosition.x ) + ( cos * _alignedPosition.y ); 31827 31828 } else { 31829 31830 _rotatedPosition.copy( _alignedPosition ); 31831 31832 } 31833 31834 31835 vertexPosition.copy( mvPosition ); 31836 vertexPosition.x += _rotatedPosition.x; 31837 vertexPosition.y += _rotatedPosition.y; 31838 31839 // transform to world space 31840 vertexPosition.applyMatrix4( _viewWorldMatrix ); 31841 31842} 31843 31844const _v1$2 = /*@__PURE__*/ new Vector3(); 31845const _v2$1 = /*@__PURE__*/ new Vector3(); 31846 31847class LOD extends Object3D { 31848 31849 constructor() { 31850 31851 super(); 31852 31853 this._currentLevel = 0; 31854 31855 this.type = 'LOD'; 31856 31857 Object.defineProperties( this, { 31858 levels: { 31859 enumerable: true, 31860 value: [] 31861 }, 31862 isLOD: { 31863 value: true, 31864 } 31865 } ); 31866 31867 this.autoUpdate = true; 31868 31869 } 31870 31871 copy( source ) { 31872 31873 super.copy( source, false ); 31874 31875 const levels = source.levels; 31876 31877 for ( let i = 0, l = levels.length; i < l; i ++ ) { 31878 31879 const level = levels[ i ]; 31880 31881 this.addLevel( level.object.clone(), level.distance, level.hysteresis ); 31882 31883 } 31884 31885 this.autoUpdate = source.autoUpdate; 31886 31887 return this; 31888 31889 } 31890 31891 addLevel( object, distance = 0, hysteresis = 0 ) { 31892 31893 distance = Math.abs( distance ); 31894 31895 const levels = this.levels; 31896 31897 let l; 31898 31899 for ( l = 0; l < levels.length; l ++ ) { 31900 31901 if ( distance < levels[ l ].distance ) { 31902 31903 break; 31904 31905 } 31906 31907 } 31908 31909 levels.splice( l, 0, { distance: distance, hysteresis: hysteresis, object: object } ); 31910 31911 this.add( object ); 31912 31913 return this; 31914 31915 } 31916 31917 getCurrentLevel() { 31918 31919 return this._currentLevel; 31920 31921 } 31922 31923 31924 31925 getObjectForDistance( distance ) { 31926 31927 const levels = this.levels; 31928 31929 if ( levels.length > 0 ) { 31930 31931 let i, l; 31932 31933 for ( i = 1, l = levels.length; i < l; i ++ ) { 31934 31935 let levelDistance = levels[ i ].distance; 31936 31937 if ( levels[ i ].object.visible ) { 31938 31939 levelDistance -= levelDistance * levels[ i ].hysteresis; 31940 31941 } 31942 31943 if ( distance < levelDistance ) { 31944 31945 31946 break; 31947 31948 } 31949 31950 } 31951 31952 return levels[ i - 1 ].object; 31953 31954 } 31955 31956 return null; 31957 31958 } 31959 31960 raycast( raycaster, intersects ) { 31961 31962 const levels = this.levels; 31963 31964 if ( levels.length > 0 ) { 31965 31966 _v1$2.setFromMatrixPosition( this.matrixWorld ); 31967 31968 const distance = raycaster.ray.origin.distanceTo( _v1$2 ); 31969 31970 this.getObjectForDistance( distance ).raycast( raycaster, intersects ); 31971 31972 } 31973 31974 } 31975 31976 update( camera ) { 31977 31978 const levels = this.levels; 31979 31980 if ( levels.length > 1 ) { 31981 31982 _v1$2.setFromMatrixPosition( camera.matrixWorld ); 31983 _v2$1.setFromMatrixPosition( this.matrixWorld ); 31984 31985 const distance = _v1$2.distanceTo( _v2$1 ) / camera.zoom; 31986 31987 levels[ 0 ].object.visible = true; 31988 31989 let i, l; 31990 31991 for ( i = 1, l = levels.length; i < l; i ++ ) { 31992 31993 let levelDistance = levels[ i ].distance; 31994 31995 if ( levels[ i ].object.visible ) { 31996 31997 levelDistance -= levelDistance * levels[ i ].hysteresis; 31998 31999 } 32000 32001 if ( distance >= levelDistance ) { 32002 32003 levels[ i - 1 ].object.visible = false; 32004 levels[ i ].object.visible = true; 32005 32006 } else { 32007 32008 break; 32009 32010 } 32011 32012 } 32013 32014 this._currentLevel = i - 1; 32015 32016 for ( ; i < l; i ++ ) { 32017 32018 levels[ i ].object.visible = false; 32019 32020 } 32021 32022 } 32023 32024 } 32025 32026 toJSON( meta ) { 32027 32028 const data = super.toJSON( meta ); 32029 32030 if ( this.autoUpdate === false ) data.object.autoUpdate = false; 32031 32032 data.object.levels = []; 32033 32034 const levels = this.levels; 32035 32036 for ( let i = 0, l = levels.length; i < l; i ++ ) { 32037 32038 const level = levels[ i ]; 32039 32040 data.object.levels.push( { 32041 object: level.object.uuid, 32042 distance: level.distance, 32043 hysteresis: level.hysteresis 32044 } ); 32045 32046 } 32047 32048 return data; 32049 32050 } 32051 32052} 32053 32054const _basePosition = /*@__PURE__*/ new Vector3(); 32055 32056const _skinIndex = /*@__PURE__*/ new Vector4(); 32057const _skinWeight = /*@__PURE__*/ new Vector4(); 32058 32059const _vector3 = /*@__PURE__*/ new Vector3(); 32060const _matrix4 = /*@__PURE__*/ new Matrix4(); 32061const _vertex = /*@__PURE__*/ new Vector3(); 32062 32063const _sphere$4 = /*@__PURE__*/ new Sphere(); 32064const _inverseMatrix$2 = /*@__PURE__*/ new Matrix4(); 32065const _ray$2 = /*@__PURE__*/ new Ray(); 32066 32067class SkinnedMesh extends Mesh { 32068 32069 constructor( geometry, material ) { 32070 32071 super( geometry, material ); 32072 32073 this.isSkinnedMesh = true; 32074 32075 this.type = 'SkinnedMesh'; 32076 32077 this.bindMode = AttachedBindMode; 32078 this.bindMatrix = new Matrix4(); 32079 this.bindMatrixInverse = new Matrix4(); 32080 32081 this.boundingBox = null; 32082 this.boundingSphere = null; 32083 32084 } 32085 32086 computeBoundingBox() { 32087 32088 const geometry = this.geometry; 32089 32090 if ( this.boundingBox === null ) { 32091 32092 this.boundingBox = new Box3(); 32093 32094 } 32095 32096 this.boundingBox.makeEmpty(); 32097 32098 const positionAttribute = geometry.getAttribute( 'position' ); 32099 32100 for ( let i = 0; i < positionAttribute.count; i ++ ) { 32101 32102 this.getVertexPosition( i, _vertex ); 32103 this.boundingBox.expandByPoint( _vertex ); 32104 32105 } 32106 32107 } 32108 32109 computeBoundingSphere() { 32110 32111 const geometry = this.geometry; 32112 32113 if ( this.boundingSphere === null ) { 32114 32115 this.boundingSphere = new Sphere(); 32116 32117 } 32118 32119 this.boundingSphere.makeEmpty(); 32120 32121 const positionAttribute = geometry.getAttribute( 'position' ); 32122 32123 for ( let i = 0; i < positionAttribute.count; i ++ ) { 32124 32125 this.getVertexPosition( i, _vertex ); 32126 this.boundingSphere.expandByPoint( _vertex ); 32127 32128 } 32129 32130 } 32131 32132 copy( source, recursive ) { 32133 32134 super.copy( source, recursive ); 32135 32136 this.bindMode = source.bindMode; 32137 this.bindMatrix.copy( source.bindMatrix ); 32138 this.bindMatrixInverse.copy( source.bindMatrixInverse ); 32139 32140 this.skeleton = source.skeleton; 32141 32142 if ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone(); 32143 if ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone(); 32144 32145 return this; 32146 32147 } 32148 32149 raycast( raycaster, intersects ) { 32150 32151 const material = this.material; 32152 const matrixWorld = this.matrixWorld; 32153 32154 if ( material === undefined ) return; 32155 32156 // test with bounding sphere in world space 32157 32158 if ( this.boundingSphere === null ) this.computeBoundingSphere(); 32159 32160 _sphere$4.copy( this.boundingSphere ); 32161 _sphere$4.applyMatrix4( matrixWorld ); 32162 32163 if ( raycaster.ray.intersectsSphere( _sphere$4 ) === false ) return; 32164 32165 // convert ray to local space of skinned mesh 32166 32167 _inverseMatrix$2.copy( matrixWorld ).invert(); 32168 _ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 ); 32169 32170 // test with bounding box in local space 32171 32172 if ( this.boundingBox !== null ) { 32173 32174 if ( _ray$2.intersectsBox( this.boundingBox ) === false ) return; 32175 32176 } 32177 32178 // test for intersections with geometry 32179 32180 this._computeIntersections( raycaster, intersects, _ray$2 ); 32181 32182 } 32183 32184 getVertexPosition( index, target ) { 32185 32186 super.getVertexPosition( index, target ); 32187 32188 this.applyBoneTransform( index, target ); 32189 32190 return target; 32191 32192 } 32193 32194 bind( skeleton, bindMatrix ) { 32195 32196 this.skeleton = skeleton; 32197 32198 if ( bindMatrix === undefined ) { 32199 32200 this.updateMatrixWorld( true ); 32201 32202 this.skeleton.calculateInverses(); 32203 32204 bindMatrix = this.matrixWorld; 32205 32206 } 32207 32208 this.bindMatrix.copy( bindMatrix ); 32209 this.bindMatrixInverse.copy( bindMatrix ).invert(); 32210 32211 } 32212 32213 pose() { 32214 32215 this.skeleton.pose(); 32216 32217 } 32218 32219 normalizeSkinWeights() { 32220 32221 const vector = new Vector4(); 32222 32223 const skinWeight = this.geometry.attributes.skinWeight; 32224 32225 for ( let i = 0, l = skinWeight.count; i < l; i ++ ) { 32226 32227 vector.fromBufferAttribute( skinWeight, i ); 32228 32229 const scale = 1.0 / vector.manhattanLength(); 32230 32231 if ( scale !== Infinity ) { 32232 32233 vector.multiplyScalar( scale ); 32234 32235 } else { 32236 32237 vector.set( 1, 0, 0, 0 );
vendor: 12,048 bytes, lines 32237-32832
32237 // do something reasonable 32238 32239 } 32240 32241 skinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w ); 32242 32243 } 32244 32245 } 32246 32247 updateMatrixWorld( force ) { 32248 32249 super.updateMatrixWorld( force ); 32250 32251 if ( this.bindMode === AttachedBindMode ) { 32252 32253 this.bindMatrixInverse.copy( this.matrixWorld ).invert(); 32254 32255 } else if ( this.bindMode === DetachedBindMode ) { 32256 32257 this.bindMatrixInverse.copy( this.bindMatrix ).invert(); 32258 32259 } else { 32260 32261 console.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode ); 32262 32263 } 32264 32265 } 32266 32267 applyBoneTransform( index, vector ) { 32268 32269 const skeleton = this.skeleton; 32270 const geometry = this.geometry; 32271 32272 _skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index ); 32273 _skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index ); 32274 32275 _basePosition.copy( vector ).applyMatrix4( this.bindMatrix ); 32276 32277 vector.set( 0, 0, 0 ); 32278 32279 for ( let i = 0; i < 4; i ++ ) { 32280 32281 const weight = _skinWeight.getComponent( i ); 32282 32283 if ( weight !== 0 ) { 32284 32285 const boneIndex = _skinIndex.getComponent( i ); 32286 32287 _matrix4.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] ); 32288 32289 vector.addScaledVector( _vector3.copy( _basePosition ).applyMatrix4( _matrix4 ), weight ); 32290 32291 } 32292 32293 } 32294 32295 return vector.applyMatrix4( this.bindMatrixInverse ); 32296 32297 } 32298 32299 boneTransform( index, vector ) { // @deprecated, r151 32300 32301 console.warn( 'THREE.SkinnedMesh: .boneTransform() was renamed to .applyBoneTransform() in r151.' ); 32302 return this.applyBoneTransform( index, vector ); 32303 32304 } 32305 32306 32307} 32308 32309class Bone extends Object3D { 32310 32311 constructor() { 32312 32313 super(); 32314 32315 this.isBone = true; 32316 32317 this.type = 'Bone'; 32318 32319 } 32320 32321} 32322 32323class DataTexture extends Texture { 32324 32325 constructor( data = null, width = 1, height = 1, format, type, mapping, wrapS, wrapT, magFilter = NearestFilter, minFilter = NearestFilter, anisotropy, colorSpace ) { 32326 32327 super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ); 32328 32329 this.isDataTexture = true; 32330 32331 this.image = { data: data, width: width, height: height }; 32332 32333 this.generateMipmaps = false; 32334 this.flipY = false; 32335 this.unpackAlignment = 1; 32336 32337 } 32338 32339} 32340 32341const _offsetMatrix = /*@__PURE__*/ new Matrix4(); 32342const _identityMatrix$1 = /*@__PURE__*/ new Matrix4(); 32343 32344class Skeleton { 32345 32346 constructor( bones = [], boneInverses = [] ) { 32347 32348 this.uuid = generateUUID(); 32349 32350 this.bones = bones.slice( 0 ); 32351 this.boneInverses = boneInverses; 32352 this.boneMatrices = null; 32353 32354 this.boneTexture = null; 32355 32356 this.init(); 32357 32358 } 32359 32360 init() { 32361 32362 const bones = this.bones; 32363 const boneInverses = this.boneInverses; 32364 32365 this.boneMatrices = new Float32Array( bones.length * 16 ); 32366 32367 // calculate inverse bone matrices if necessary 32368 32369 if ( boneInverses.length === 0 ) { 32370 32371 this.calculateInverses(); 32372 32373 } else { 32374 32375 // handle special case 32376 32377 if ( bones.length !== boneInverses.length ) { 32378 32379 console.warn( 'THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.' ); 32380 32381 this.boneInverses = []; 32382 32383 for ( let i = 0, il = this.bones.length; i < il; i ++ ) { 32384 32385 this.boneInverses.push( new Matrix4() ); 32386 32387 } 32388 32389 } 32390 32391 } 32392 32393 } 32394 32395 calculateInverses() { 32396 32397 this.boneInverses.length = 0; 32398 32399 for ( let i = 0, il = this.bones.length; i < il; i ++ ) { 32400 32401 const inverse = new Matrix4(); 32402 32403 if ( this.bones[ i ] ) { 32404 32405 inverse.copy( this.bones[ i ].matrixWorld ).invert(); 32406 32407 } 32408 32409 this.boneInverses.push( inverse ); 32410 32411 } 32412 32413 } 32414 32415 pose() { 32416 32417 // recover the bind-time world matrices 32418 32419 for ( let i = 0, il = this.bones.length; i < il; i ++ ) { 32420 32421 const bone = this.bones[ i ]; 32422 32423 if ( bone ) { 32424 32425 bone.matrixWorld.copy( this.boneInverses[ i ] ).invert(); 32426 32427 } 32428 32429 } 32430 32431 // compute the local matrices, positions, rotations and scales 32432 32433 for ( let i = 0, il = this.bones.length; i < il; i ++ ) { 32434 32435 const bone = this.bones[ i ]; 32436 32437 if ( bone ) { 32438 32439 if ( bone.parent && bone.parent.isBone ) { 32440 32441 bone.matrix.copy( bone.parent.matrixWorld ).invert(); 32442 bone.matrix.multiply( bone.matrixWorld ); 32443 32444 } else { 32445 32446 bone.matrix.copy( bone.matrixWorld ); 32447 32448 } 32449 32450 bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); 32451 32452 } 32453 32454 } 32455 32456 } 32457 32458 update() { 32459 32460 const bones = this.bones; 32461 const boneInverses = this.boneInverses; 32462 const boneMatrices = this.boneMatrices; 32463 const boneTexture = this.boneTexture; 32464 32465 // flatten bone matrices to array 32466 32467 for ( let i = 0, il = bones.length; i < il; i ++ ) { 32468 32469 // compute the offset between the current and the original transform 32470 32471 const matrix = bones[ i ] ? bones[ i ].matrixWorld : _identityMatrix$1; 32472 32473 _offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] ); 32474 _offsetMatrix.toArray( boneMatrices, i * 16 ); 32475 32476 } 32477 32478 if ( boneTexture !== null ) { 32479 32480 boneTexture.needsUpdate = true; 32481 32482 } 32483 32484 } 32485 32486 clone() { 32487 32488 return new Skeleton( this.bones, this.boneInverses ); 32489 32490 } 32491 32492 computeBoneTexture() { 32493 32494 // layout (1 matrix = 4 pixels) 32495 // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) 32496 // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8) 32497 // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16) 32498 // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32) 32499 // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64) 32500 32501 let size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix 32502 size = Math.ceil( size / 4 ) * 4; 32503 size = Math.max( size, 4 ); 32504 32505 const boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel 32506 boneMatrices.set( this.boneMatrices ); // copy current values 32507 32508 const boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType ); 32509 boneTexture.needsUpdate = true; 32510 32511 this.boneMatrices = boneMatrices; 32512 this.boneTexture = boneTexture; 32513 32514 return this; 32515 32516 } 32517 32518 getBoneByName( name ) { 32519 32520 for ( let i = 0, il = this.bones.length; i < il; i ++ ) { 32521 32522 const bone = this.bones[ i ]; 32523 32524 if ( bone.name === name ) { 32525 32526 return bone; 32527 32528 } 32529 32530 } 32531 32532 return undefined; 32533 32534 } 32535 32536 dispose( ) { 32537 32538 if ( this.boneTexture !== null ) { 32539 32540 this.boneTexture.dispose(); 32541 32542 this.boneTexture = null; 32543 32544 } 32545 32546 } 32547 32548 fromJSON( json, bones ) { 32549 32550 this.uuid = json.uuid; 32551 32552 for ( let i = 0, l = json.bones.length; i < l; i ++ ) { 32553 32554 const uuid = json.bones[ i ]; 32555 let bone = bones[ uuid ]; 32556 32557 if ( bone === undefined ) { 32558 32559 console.warn( 'THREE.Skeleton: No bone found with UUID:', uuid ); 32560 bone = new Bone(); 32561 32562 } 32563 32564 this.bones.push( bone ); 32565 this.boneInverses.push( new Matrix4().fromArray( json.boneInverses[ i ] ) ); 32566 32567 } 32568 32569 this.init(); 32570 32571 return this; 32572 32573 } 32574 32575 toJSON() { 32576 32577 const data = { 32578 metadata: { 32579 version: 4.6, 32580 type: 'Skeleton', 32581 generator: 'Skeleton.toJSON' 32582 }, 32583 bones: [], 32584 boneInverses: [] 32585 }; 32586 32587 data.uuid = this.uuid; 32588 32589 const bones = this.bones; 32590 const boneInverses = this.boneInverses; 32591 32592 for ( let i = 0, l = bones.length; i < l; i ++ ) { 32593 32594 const bone = bones[ i ]; 32595 data.bones.push( bone.uuid ); 32596 32597 const boneInverse = boneInverses[ i ]; 32598 data.boneInverses.push( boneInverse.toArray() ); 32599 32600 } 32601 32602 return data; 32603 32604 } 32605 32606} 32607 32608class InstancedBufferAttribute extends BufferAttribute { 32609 32610 constructor( array, itemSize, normalized, meshPerAttribute = 1 ) { 32611 32612 super( array, itemSize, normalized ); 32613 32614 this.isInstancedBufferAttribute = true; 32615 32616 this.meshPerAttribute = meshPerAttribute; 32617 32618 } 32619 32620 copy( source ) { 32621 32622 super.copy( source ); 32623 32624 this.meshPerAttribute = source.meshPerAttribute; 32625 32626 return this; 32627 32628 } 32629 32630 toJSON() { 32631 32632 const data = super.toJSON(); 32633 32634 data.meshPerAttribute = this.meshPerAttribute; 32635 32636 data.isInstancedBufferAttribute = true; 32637 32638 return data; 32639 32640 } 32641 32642} 32643 32644const _instanceLocalMatrix = /*@__PURE__*/ new Matrix4(); 32645const _instanceWorldMatrix = /*@__PURE__*/ new Matrix4(); 32646 32647const _instanceIntersects = []; 32648 32649const _box3 = /*@__PURE__*/ new Box3(); 32650const _identity = /*@__PURE__*/ new Matrix4(); 32651const _mesh$1 = /*@__PURE__*/ new Mesh(); 32652const _sphere$3 = /*@__PURE__*/ new Sphere(); 32653 32654class InstancedMesh extends Mesh { 32655 32656 constructor( geometry, material, count ) { 32657 32658 super( geometry, material ); 32659 32660 this.isInstancedMesh = true; 32661 32662 this.instanceMatrix = new InstancedBufferAttribute( new Float32Array( count * 16 ), 16 ); 32663 this.instanceColor = null; 32664 32665 this.count = count; 32666 32667 this.boundingBox = null; 32668 this.boundingSphere = null; 32669 32670 for ( let i = 0; i < count; i ++ ) { 32671 32672 this.setMatrixAt( i, _identity ); 32673 32674 } 32675 32676 } 32677 32678 computeBoundingBox() { 32679 32680 const geometry = this.geometry; 32681 const count = this.count; 32682 32683 if ( this.boundingBox === null ) { 32684 32685 this.boundingBox = new Box3(); 32686 32687 } 32688 32689 if ( geometry.boundingBox === null ) { 32690 32691 geometry.computeBoundingBox(); 32692 32693 } 32694 32695 this.boundingBox.makeEmpty(); 32696 32697 for ( let i = 0; i < count; i ++ ) { 32698 32699 this.getMatrixAt( i, _instanceLocalMatrix ); 32700 32701 _box3.copy( geometry.boundingBox ).applyMatrix4( _instanceLocalMatrix ); 32702 32703 this.boundingBox.union( _box3 ); 32704 32705 } 32706 32707 } 32708 32709 computeBoundingSphere() { 32710 32711 const geometry = this.geometry; 32712 const count = this.count; 32713 32714 if ( this.boundingSphere === null ) { 32715 32716 this.boundingSphere = new Sphere(); 32717 32718 } 32719 32720 if ( geometry.boundingSphere === null ) { 32721 32722 geometry.computeBoundingSphere(); 32723 32724 } 32725 32726 this.boundingSphere.makeEmpty(); 32727 32728 for ( let i = 0; i < count; i ++ ) { 32729 32730 this.getMatrixAt( i, _instanceLocalMatrix ); 32731 32732 _sphere$3.copy( geometry.boundingSphere ).applyMatrix4( _instanceLocalMatrix ); 32733 32734 this.boundingSphere.union( _sphere$3 ); 32735 32736 } 32737 32738 } 32739 32740 copy( source, recursive ) { 32741 32742 super.copy( source, recursive ); 32743 32744 this.instanceMatrix.copy( source.instanceMatrix ); 32745 32746 if ( source.instanceColor !== null ) this.instanceColor = source.instanceColor.clone(); 32747 32748 this.count = source.count; 32749 32750 if ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone(); 32751 if ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone(); 32752 32753 return this; 32754 32755 } 32756 32757 getColorAt( index, color ) { 32758 32759 color.fromArray( this.instanceColor.array, index * 3 ); 32760 32761 } 32762 32763 getMatrixAt( index, matrix ) { 32764 32765 matrix.fromArray( this.instanceMatrix.array, index * 16 ); 32766 32767 } 32768 32769 raycast( raycaster, intersects ) { 32770 32771 const matrixWorld = this.matrixWorld; 32772 const raycastTimes = this.count; 32773 32774 _mesh$1.geometry = this.geometry; 32775 _mesh$1.material = this.material; 32776 32777 if ( _mesh$1.material === undefined ) return; 32778 32779 // test with bounding sphere first 32780 32781 if ( this.boundingSphere === null ) this.computeBoundingSphere(); 32782 32783 _sphere$3.copy( this.boundingSphere ); 32784 _sphere$3.applyMatrix4( matrixWorld ); 32785 32786 if ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) return; 32787 32788 // now test each instance 32789 32790 for ( let instanceId = 0; instanceId < raycastTimes; instanceId ++ ) { 32791 32792 // calculate the world matrix for each instance 32793 32794 this.getMatrixAt( instanceId, _instanceLocalMatrix ); 32795 32796 _instanceWorldMatrix.multiplyMatrices( matrixWorld, _instanceLocalMatrix ); 32797 32798 // the mesh represents this single instance 32799 32800 _mesh$1.matrixWorld = _instanceWorldMatrix; 32801 32802 _mesh$1.raycast( raycaster, _instanceIntersects ); 32803 32804 // process the result of raycast 32805 32806 for ( let i = 0, l = _instanceIntersects.length; i < l; i ++ ) { 32807 32808 const intersect = _instanceIntersects[ i ]; 32809 intersect.instanceId = instanceId; 32810 intersect.object = this; 32811 intersects.push( intersect ); 32812 32813 } 32814 32815 _instanceIntersects.length = 0; 32816 32817 } 32818 32819 } 32820 32821 setColorAt( index, color ) { 32822 32823 if ( this.instanceColor === null ) { 32824 32825 this.instanceColor = new InstancedBufferAttribute( new Float32Array( this.instanceMatrix.count * 3 ), 3 ); 32826 32827 } 32828 32829 color.toArray( this.instanceColor.array, index * 3 ); 32830 32831 } 32832
32833 setMatrixAt( index, matrix ) { 32834 32835 matrix.toArray( this.instanceMatrix.array, index * 16 ); 32836 32837 } 32838 32839 updateMorphTargets() { 32840 32841 } 32842 32843 dispose() { 32844 32845 this.dispatchEvent( { type: 'dispose' } ); 32846 32847 } 32848 32849} 32850 32851function sortOpaque( a, b ) { 32852 32853 return a.z - b.z; 32854 32855} 32856 32857function sortTransparent( a, b ) { 32858 32859 return b.z - a.z; 32860 32861} 32862 32863class MultiDrawRenderList { 32864 32865 constructor() { 32866 32867 this.index = 0; 32868 this.pool = []; 32869 this.list = []; 32870 32871 } 32872 32873 push( drawRange, z ) { 32874 32875 const pool = this.pool; 32876 const list = this.list; 32877 if ( this.index >= pool.length ) { 32878 32879 pool.push( { 32880 32881 start: - 1, 32882 count: - 1, 32883 z: - 1, 32884 32885 } ); 32886 32887 } 32888 32889 const item = pool[ this.index ]; 32890 list.push( item ); 32891 this.index ++; 32892 32893 item.start = drawRange.start; 32894 item.count = drawRange.count; 32895 item.z = z; 32896 32897 } 32898 32899 reset() { 32900 32901 this.list.length = 0; 32902 this.index = 0; 32903 32904 } 32905 32906} 32907 32908const ID_ATTR_NAME = 'batchId'; 32909const _matrix = /*@__PURE__*/ new Matrix4(); 32910const _invMatrixWorld = /*@__PURE__*/ new Matrix4(); 32911const _identityMatrix = /*@__PURE__*/ new Matrix4(); 32912const _projScreenMatrix$2 = /*@__PURE__*/ new Matrix4(); 32913const _frustum = /*@__PURE__*/ new Frustum(); 32914const _box$1 = /*@__PURE__*/ new Box3(); 32915const _sphere$2 = /*@__PURE__*/ new Sphere(); 32916const _vector$5 = /*@__PURE__*/ new Vector3(); 32917const _renderList = /*@__PURE__*/ new MultiDrawRenderList(); 32918const _mesh = /*@__PURE__*/ new Mesh(); 32919const _batchIntersects = []; 32920 32921// @TODO: SkinnedMesh support? 32922// @TODO: geometry.groups support? 32923// @TODO: geometry.drawRange support? 32924// @TODO: geometry.morphAttributes support? 32925// @TODO: Support uniform parameter per geometry 32926// @TODO: Add an "optimize" function to pack geometry and remove data gaps 32927 32928// copies data from attribute "src" into "target" starting at "targetOffset" 32929function copyAttributeData( src, target, targetOffset = 0 ) { 32930 32931 const itemSize = target.itemSize; 32932 if ( src.isInterleavedBufferAttribute || src.array.constructor !== target.array.constructor ) { 32933 32934 // use the component getters and setters if the array data cannot 32935 // be copied directly 32936 const vertexCount = src.count; 32937 for ( let i = 0; i < vertexCount; i ++ ) { 32938 32939 for ( let c = 0; c < itemSize; c ++ ) { 32940 32941 target.setComponent( i + targetOffset, c, src.getComponent( i, c ) ); 32942 32943 } 32944 32945 } 32946 32947 } else { 32948 32949 // faster copy approach using typed array set function 32950 target.array.set( src.array, targetOffset * itemSize ); 32951 32952 } 32953 32954 target.needsUpdate = true; 32955 32956} 32957 32958class BatchedMesh extends Mesh { 32959 32960 get maxGeometryCount() { 32961 32962 return this._maxGeometryCount; 32963 32964 } 32965 32966 constructor( maxGeometryCount, maxVertexCount, maxIndexCount = maxVertexCount * 2, material ) { 32967 32968 super( new BufferGeometry(), material ); 32969 32970 this.isBatchedMesh = true; 32971 this.perObjectFrustumCulled = true; 32972 this.sortObjects = true; 32973 this.boundingBox = null; 32974 this.boundingSphere = null; 32975 this.customSort = null; 32976 32977 this._drawRanges = []; 32978 this._reservedRanges = []; 32979 32980 this._visibility = []; 32981 this._active = []; 32982 this._bounds = []; 32983 32984 this._maxGeometryCount = maxGeometryCount; 32985 this._maxVertexCount = maxVertexCount; 32986 this._maxIndexCount = maxIndexCount; 32987 32988 this._geometryInitialized = false; 32989 this._geometryCount = 0; 32990 this._multiDrawCounts = new Int32Array( maxGeometryCount ); 32991 this._multiDrawStarts = new Int32Array( maxGeometryCount ); 32992 this._multiDrawCount = 0; 32993 this._visibilityChanged = true; 32994 32995 // Local matrix per geometry by using data texture 32996 this._matricesTexture = null; 32997 32998 this._initMatricesTexture(); 32999 33000 } 33001 33002 _initMatricesTexture() { 33003 33004 // layout (1 matrix = 4 pixels) 33005 // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) 33006 // with 8x8 pixel texture max 16 matrices * 4 pixels = (8 * 8) 33007 // 16x16 pixel texture max 64 matrices * 4 pixels = (16 * 16) 33008 // 32x32 pixel texture max 256 matrices * 4 pixels = (32 * 32) 33009 // 64x64 pixel texture max 1024 matrices * 4 pixels = (64 * 64) 33010 33011 let size = Math.sqrt( this._maxGeometryCount * 4 ); // 4 pixels needed for 1 matrix
33012 size = Math.ceil( size / 4 ) * 4; 33013 size = Math.max( size, 4 ); 33014 33015 const matricesArray = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel 33016 const matricesTexture = new DataTexture( matricesArray, size, size, RGBAFormat, FloatType ); 33017 33018 this._matricesTexture = matricesTexture; 33019 33020 } 33021 33022 _initializeGeometry( reference ) { 33023 33024 const geometry = this.geometry; 33025 const maxVertexCount = this._maxVertexCount; 33026 const maxGeometryCount = this._maxGeometryCount; 33027 const maxIndexCount = this._maxIndexCount; 33028 if ( this._geometryInitialized === false ) { 33029 33030 for ( const attributeName in reference.attributes ) { 33031 33032 const srcAttribute = reference.getAttribute( attributeName ); 33033 const { array, itemSize, normalized } = srcAttribute; 33034 33035 const dstArray = new array.constructor( maxVertexCount * itemSize ); 33036 const dstAttribute = new srcAttribute.constructor( dstArray, itemSize, normalized ); 33037 dstAttribute.setUsage( srcAttribute.usage ); 33038 33039 geometry.setAttribute( attributeName, dstAttribute ); 33040 33041 } 33042 33043 if ( reference.getIndex() !== null ) { 33044 33045 const indexArray = maxVertexCount > 65536 33046 ? new Uint32Array( maxIndexCount ) 33047 : new Uint16Array( maxIndexCount ); 33048 33049 geometry.setIndex( new BufferAttribute( indexArray, 1 ) ); 33050 33051 } 33052 33053 const idArray = maxGeometryCount > 65536 33054 ? new Uint32Array( maxVertexCount ) 33055 : new Uint16Array( maxVertexCount ); 33056 geometry.setAttribute( ID_ATTR_NAME, new BufferAttribute( idArray, 1 ) ); 33057 33058 this._geometryInitialized = true; 33059 33060 } 33061 33062 } 33063 33064 // Make sure the geometry is compatible with the existing combined geometry atributes 33065 _validateGeometry( geometry ) { 33066 33067 // check that the geometry doesn't have a version of our reserved id attribute 33068 if ( geometry.getAttribute( ID_ATTR_NAME ) ) { 33069 33070 throw new Error( `BatchedMesh: Geometry cannot use attribute "${ ID_ATTR_NAME }"` ); 33071 33072 } 33073 33074 // check to ensure the geometries are using consistent attributes and indices 33075 const batchGeometry = this.geometry; 33076 if ( Boolean( geometry.getIndex() ) !== Boolean( batchGeometry.getIndex() ) ) { 33077 33078 throw new Error( 'BatchedMesh: All geometries must consistently have "index".' ); 33079 33080 } 33081 33082 for ( const attributeName in batchGeometry.attributes ) { 33083 33084 if ( attributeName === ID_ATTR_NAME ) { 33085 33086 continue; 33087 33088 } 33089 33090 if ( ! geometry.hasAttribute( attributeName ) ) { 33091 33092 throw new Error( `BatchedMesh: Added geometry missing "${ attributeName }". All geometries must have consistent attributes.` ); 33093 33094 } 33095 33096 const srcAttribute = geometry.getAttribute( attributeName );
33097 const dstAttribute = batchGeometry.getAttribute( attributeName ); 33098 if ( srcAttribute.itemSize !== dstAttribute.itemSize || srcAttribute.normalized !== dstAttribute.normalized ) { 33099 33100 throw new Error( 'BatchedMesh: All attributes must have a consistent itemSize and normalized value.' ); 33101 33102 } 33103 33104 } 33105 33106 } 33107 33108 setCustomSort( func ) { 33109 33110 this.customSort = func; 33111 return this; 33112 33113 } 33114 33115 computeBoundingBox() { 33116 33117 if ( this.boundingBox === null ) { 33118 33119 this.boundingBox = new Box3(); 33120 33121 } 33122 33123 const geometryCount = this._geometryCount; 33124 const boundingBox = this.boundingBox; 33125 const active = this._active; 33126 33127 boundingBox.makeEmpty(); 33128 for ( let i = 0; i < geometryCount; i ++ ) { 33129 33130 if ( active[ i ] === false ) continue; 33131 33132 this.getMatrixAt( i, _matrix ); 33133 this.getBoundingBoxAt( i, _box$1 ).applyMatrix4( _matrix ); 33134 boundingBox.union( _box$1 ); 33135 33136 } 33137 33138 } 33139 33140 computeBoundingSphere() { 33141 33142 if ( this.boundingSphere === null ) { 33143 33144 this.boundingSphere = new Sphere(); 33145 33146 } 33147 33148 const geometryCount = this._geometryCount; 33149 const boundingSphere = this.boundingSphere; 33150 const active = this._active; 33151 33152 boundingSphere.makeEmpty(); 33153 for ( let i = 0; i < geometryCount; i ++ ) { 33154 33155 if ( active[ i ] === false ) continue; 33156 33157 this.getMatrixAt( i, _matrix ); 33158 this.getBoundingSphereAt( i, _sphere$2 ).applyMatrix4( _matrix ); 33159 boundingSphere.union( _sphere$2 ); 33160 33161 } 33162 33163 } 33164 33165 addGeometry( geometry, vertexCount = - 1, indexCount = - 1 ) { 33166 33167 this._initializeGeometry( geometry ); 33168 33169 this._validateGeometry( geometry ); 33170 33171 // ensure we're not over geometry 33172 if ( this._geometryCount >= this._maxGeometryCount ) { 33173 33174 throw new Error( 'BatchedMesh: Maximum geometry count reached.' ); 33175 33176 } 33177 33178 // get the necessary range fo the geometry 33179 const reservedRange = { 33180 vertexStart: - 1, 33181 vertexCount: - 1, 33182 indexStart: - 1, 33183 indexCount: - 1, 33184 }; 33185 33186 let lastRange = null; 33187 const reservedRanges = this._reservedRanges; 33188 const drawRanges = this._drawRanges; 33189 const bounds = this._bounds; 33190 if ( this._geometryCount !== 0 ) { 33191 33192 lastRange = reservedRanges[ reservedRanges.length - 1 ]; 33193 33194 } 33195 33196 if ( vertexCount === - 1 ) { 33197 33198 reservedRange.vertexCount = geometry.getAttribute( 'position' ).count; 33199 33200 } else { 33201 33202 reservedRange.vertexCount = vertexCount; 33203 33204 } 33205 33206 if ( lastRange === null ) { 33207 33208 reservedRange.vertexStart = 0; 33209 33210 } else { 33211 33212 reservedRange.vertexStart = lastRange.vertexStart + lastRange.vertexCount; 33213 33214 } 33215 33216 const index = geometry.getIndex(); 33217 const hasIndex = index !== null; 33218 if ( hasIndex ) { 33219 33220 if ( indexCount === - 1 ) { 33221 33222 reservedRange.indexCount = index.count; 33223 33224 } else { 33225 33226 reservedRange.indexCount = indexCount; 33227 33228 } 33229 33230 if ( lastRange === null ) { 33231 33232 reservedRange.indexStart = 0; 33233 33234 } else { 33235 33236 reservedRange.indexStart = lastRange.indexStart + lastRange.indexCount; 33237 33238 } 33239 33240 } 33241 33242 if ( 33243 reservedRange.indexStart !== - 1 && 33244 reservedRange.indexStart + reservedRange.indexCount > this._maxIndexCount || 33245 reservedRange.vertexStart + reservedRange.vertexCount > this._maxVertexCount 33246 ) { 33247 33248 throw new Error( 'BatchedMesh: Reserved space request exceeds the maximum buffer size.' ); 33249 33250 } 33251 33252 const visibility = this._visibility; 33253 const active = this._active; 33254 const matricesTexture = this._matricesTexture; 33255 const matricesArray = this._matricesTexture.image.data; 33256 33257 // push new visibility states 33258 visibility.push( true ); 33259 active.push( true ); 33260 33261 // update id 33262 const geometryId = this._geometryCount; 33263 this._geometryCount ++; 33264 33265 // initialize matrix information 33266 _identityMatrix.toArray( matricesArray, geometryId * 16 ); 33267 matricesTexture.needsUpdate = true; 33268 33269 // add the reserved range and draw range objects 33270 reservedRanges.push( reservedRange ); 33271 drawRanges.push( { 33272 start: hasIndex ? reservedRange.indexStart : reservedRange.vertexStart, 33273 count: - 1 33274 } ); 33275 bounds.push( { 33276 boxInitialized: false, 33277 box: new Box3(), 33278 33279 sphereInitialized: false, 33280 sphere: new Sphere() 33281 } ); 33282 33283 // set the id for the geometry 33284 const idAttribute = this.geometry.getAttribute( ID_ATTR_NAME ); 33285 for ( let i = 0; i < reservedRange.vertexCount; i ++ ) { 33286 33287 idAttribute.setX( reservedRange.vertexStart + i, geometryId ); 33288 33289 } 33290 33291 idAttribute.needsUpdate = true; 33292 33293 // update the geometry 33294 this.setGeometryAt( geometryId, geometry ); 33295 33296 return geometryId; 33297 33298 } 33299 33300 setGeometryAt( id, geometry ) { 33301 33302 if ( id >= this._geometryCount ) { 33303 33304 throw new Error( 'BatchedMesh: Maximum geometry count reached.' ); 33305 33306 } 33307
33308 this._validateGeometry( geometry ); 33309 33310 const batchGeometry = this.geometry; 33311 const hasIndex = batchGeometry.getIndex() !== null; 33312 const dstIndex = batchGeometry.getIndex(); 33313 const srcIndex = geometry.getIndex(); 33314 const reservedRange = this._reservedRanges[ id ]; 33315 if ( 33316 hasIndex && 33317 srcIndex.count > reservedRange.indexCount || 33318 geometry.attributes.position.count > reservedRange.vertexCount 33319 ) { 33320 33321 throw new Error( 'BatchedMesh: Reserved space not large enough for provided geometry.' ); 33322 33323 } 33324 33325 // copy geometry over 33326 const vertexStart = reservedRange.vertexStart; 33327 const vertexCount = reservedRange.vertexCount; 33328 for ( const attributeName in batchGeometry.attributes ) { 33329 33330 if ( attributeName === ID_ATTR_NAME ) { 33331 33332 continue; 33333 33334 } 33335 33336 // copy attribute data 33337 const srcAttribute = geometry.getAttribute( attributeName ); 33338 const dstAttribute = batchGeometry.getAttribute( attributeName ); 33339 copyAttributeData( srcAttribute, dstAttribute, vertexStart ); 33340 33341 // fill the rest in with zeroes 33342 const itemSize = srcAttribute.itemSize; 33343 for ( let i = srcAttribute.count, l = vertexCount; i < l; i ++ ) { 33344 33345 const index = vertexStart + i; 33346 for ( let c = 0; c < itemSize; c ++ ) { 33347 33348 dstAttribute.setComponent( index, c, 0 ); 33349 33350 } 33351 33352 } 33353 33354 dstAttribute.needsUpdate = true; 33355 33356 } 33357 33358 // copy index 33359 if ( hasIndex ) { 33360 33361 const indexStart = reservedRange.indexStart; 33362 33363 // copy index data over 33364 for ( let i = 0; i < srcIndex.count; i ++ ) { 33365 33366 dstIndex.setX( indexStart + i, vertexStart + srcIndex.getX( i ) ); 33367 33368 } 33369 33370 // fill the rest in with zeroes 33371 for ( let i = srcIndex.count, l = reservedRange.indexCount; i < l; i ++ ) { 33372 33373 dstIndex.setX( indexStart + i, vertexStart ); 33374 33375 } 33376 33377 dstIndex.needsUpdate = true; 33378 33379 } 33380 33381 // store the bounding boxes 33382 const bound = this._bounds[ id ]; 33383 if ( geometry.boundingBox !== null ) { 33384 33385 bound.box.copy( geometry.boundingBox ); 33386 bound.boxInitialized = true; 33387 33388 } else { 33389 33390 bound.boxInitialized = false; 33391 33392 } 33393 33394 if ( geometry.boundingSphere !== null ) { 33395 33396 bound.sphere.copy( geometry.boundingSphere ); 33397 bound.sphereInitialized = true; 33398 33399 } else { 33400 33401 bound.sphereInitialized = false; 33402 33403 } 33404 33405 // set drawRange count 33406 const drawRange = this._drawRanges[ id ]; 33407 const posAttr = geometry.getAttribute( 'position' ); 33408 drawRange.count = hasIndex ? srcIndex.count : posAttr.count; 33409 this._visibilityChanged = true; 33410 33411 return id; 33412 33413 } 33414 33415 deleteGeometry( geometryId ) { 33416 33417 // Note: User needs to call optimize() afterward to pack the data. 33418 33419 const active = this._active; 33420 if ( geometryId >= active.length || active[ geometryId ] === false ) { 33421 33422 return this; 33423 33424 } 33425 33426 active[ geometryId ] = false; 33427 this._visibilityChanged = true; 33428 33429 return this; 33430 33431 } 33432 33433 // get bounding box and compute it if it doesn't exist 33434 getBoundingBoxAt( id, target ) { 33435 33436 const active = this._active; 33437 if ( active[ id ] === false ) { 33438 33439 return this; 33440 33441 } 33442 33443 // compute bounding box 33444 const bound = this._bounds[ id ]; 33445 const box = bound.box; 33446 const geometry = this.geometry; 33447 if ( bound.boxInitialized === false ) { 33448 33449 box.makeEmpty(); 33450 33451 const index = geometry.index; 33452 const position = geometry.attributes.position; 33453 const drawRange = this._drawRanges[ id ]; 33454 for ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) { 33455 33456 let iv = i; 33457 if ( index ) { 33458 33459 iv = index.getX( iv ); 33460 33461 } 33462 33463 box.expandByPoint( _vector$5.fromBufferAttribute( position, iv ) ); 33464 33465 } 33466 33467 bound.boxInitialized = true; 33468 33469 } 33470 33471 target.copy( box ); 33472 return target; 33473 33474 } 33475 33476 // get bounding sphere and compute it if it doesn't exist 33477 getBoundingSphereAt( id, target ) { 33478 33479 const active = this._active; 33480 if ( active[ id ] === false ) { 33481 33482 return this; 33483 33484 } 33485 33486 // compute bounding sphere 33487 const bound = this._bounds[ id ]; 33488 const sphere = bound.sphere; 33489 const geometry = this.geometry; 33490 if ( bound.sphereInitialized === false ) { 33491 33492 sphere.makeEmpty(); 33493 33494 this.getBoundingBoxAt( id, _box$1 ); 33495 _box$1.getCenter( sphere.center ); 33496 33497 const index = geometry.index;
33498 const position = geometry.attributes.position; 33499 const drawRange = this._drawRanges[ id ]; 33500 33501 let maxRadiusSq = 0; 33502 for ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) { 33503 33504 let iv = i; 33505 if ( index ) { 33506 33507 iv = index.getX( iv ); 33508 33509 } 33510 33511 _vector$5.fromBufferAttribute( position, iv ); 33512 maxRadiusSq = Math.max( maxRadiusSq, sphere.center.distanceToSquared( _vector$5 ) ); 33513 33514 } 33515 33516 sphere.radius = Math.sqrt( maxRadiusSq ); 33517 bound.sphereInitialized = true; 33518 33519 } 33520 33521 target.copy( sphere ); 33522 return target; 33523 33524 } 33525 33526 setMatrixAt( geometryId, matrix ) { 33527 33528 // @TODO: Map geometryId to index of the arrays because 33529 // optimize() can make geometryId mismatch the index 33530 33531 const active = this._active; 33532 const matricesTexture = this._matricesTexture; 33533 const matricesArray = this._matricesTexture.image.data; 33534 const geometryCount = this._geometryCount; 33535 if ( geometryId >= geometryCount || active[ geometryId ] === false ) { 33536 33537 return this; 33538 33539 } 33540 33541 matrix.toArray( matricesArray, geometryId * 16 ); 33542 matricesTexture.needsUpdate = true; 33543 33544 return this; 33545 33546 } 33547 33548 getMatrixAt( geometryId, matrix ) { 33549 33550 const active = this._active; 33551 const matricesArray = this._matricesTexture.image.data; 33552 const geometryCount = this._geometryCount; 33553 if ( geometryId >= geometryCount || active[ geometryId ] === false ) { 33554 33555 return null; 33556 33557 } 33558 33559 return matrix.fromArray( matricesArray, geometryId * 16 ); 33560 33561 } 33562 33563 setVisibleAt( geometryId, value ) { 33564 33565 const visibility = this._visibility; 33566 const active = this._active; 33567 const geometryCount = this._geometryCount; 33568 33569 // if the geometry is out of range, not active, or visibility state 33570 // does not change then return early 33571 if ( 33572 geometryId >= geometryCount || 33573 active[ geometryId ] === false || 33574 visibility[ geometryId ] === value 33575 ) { 33576 33577 return this; 33578 33579 } 33580 33581 visibility[ geometryId ] = value; 33582 this._visibilityChanged = true; 33583 33584 return this; 33585 33586 } 33587 33588 getVisibleAt( geometryId ) { 33589 33590 const visibility = this._visibility; 33591 const active = this._active; 33592 const geometryCount = this._geometryCount; 33593 33594 // return early if the geometry is out of range or not active 33595 if ( geometryId >= geometryCount || active[ geometryId ] === false ) { 33596 33597 return false; 33598 33599 } 33600 33601 return visibility[ geometryId ]; 33602 33603 } 33604 33605 raycast( raycaster, intersects ) { 33606 33607 const visibility = this._visibility; 33608 const active = this._active; 33609 const drawRanges = this._drawRanges; 33610 const geometryCount = this._geometryCount; 33611 const matrixWorld = this.matrixWorld; 33612 const batchGeometry = this.geometry; 33613 33614 // iterate over each geometry 33615 _mesh.material = this.material; 33616 _mesh.geometry.index = batchGeometry.index; 33617 _mesh.geometry.attributes = batchGeometry.attributes; 33618 if ( _mesh.geometry.boundingBox === null ) { 33619 33620 _mesh.geometry.boundingBox = new Box3(); 33621 33622 } 33623 33624 if ( _mesh.geometry.boundingSphere === null ) { 33625 33626 _mesh.geometry.boundingSphere = new Sphere(); 33627 33628 } 33629 33630 for ( let i = 0; i < geometryCount; i ++ ) { 33631 33632 if ( ! visibility[ i ] || ! active[ i ] ) { 33633 33634 continue; 33635 33636 } 33637 33638 const drawRange = drawRanges[ i ]; 33639 _mesh.geometry.setDrawRange( drawRange.start, drawRange.count ); 33640 33641 // ge the intersects 33642 this.getMatrixAt( i, _mesh.matrixWorld ).premultiply( matrixWorld ); 33643 this.getBoundingBoxAt( i, _mesh.geometry.boundingBox ); 33644 this.getBoundingSphereAt( i, _mesh.geometry.boundingSphere ); 33645 _mesh.raycast( raycaster, _batchIntersects ); 33646 33647 // add batch id to the intersects 33648 for ( let j = 0, l = _batchIntersects.length; j < l; j ++ ) { 33649 33650 const intersect = _batchIntersects[ j ]; 33651 intersect.object = this; 33652 intersect.batchId = i; 33653 intersects.push( intersect ); 33654 33655 } 33656 33657 _batchIntersects.length = 0; 33658 33659 } 33660 33661 _mesh.material = null; 33662 _mesh.geometry.index = null; 33663 _mesh.geometry.attributes = {}; 33664 _mesh.geometry.setDrawRange( 0, Infinity ); 33665 33666 } 33667 33668 copy( source ) { 33669 33670 super.copy( source ); 33671 33672 this.geometry = source.geometry.clone(); 33673 this.perObjectFrustumCulled = source.perObjectFrustumCulled; 33674 this.sortObjects = source.sortObjects; 33675 this.boundingBox = source.boundingBox !== null ? source.boundingBox.clone() : null; 33676 this.boundingSphere = source.boundingSphere !== null ? source.boundingSphere.clone() : null; 33677 33678 this._drawRanges = source._drawRanges.map( range => ( { ...range } ) ); 33679 this._reservedRanges = source._reservedRanges.map( range => ( { ...range } ) ); 33680 33681 this._visibility = source._visibility.slice(); 33682 this._active = source._active.slice(); 33683 this._bounds = source._bounds.map( bound => ( {
33684 boxInitialized: bound.boxInitialized, 33685 box: bound.box.clone(), 33686 33687 sphereInitialized: bound.sphereInitialized, 33688 sphere: bound.sphere.clone() 33689 } ) ); 33690 33691 this._maxGeometryCount = source._maxGeometryCount; 33692 this._maxVertexCount = source._maxVertexCount; 33693 this._maxIndexCount = source._maxIndexCount; 33694 33695 this._geometryInitialized = source._geometryInitialized; 33696 this._geometryCount = source._geometryCount; 33697 this._multiDrawCounts = source._multiDrawCounts.slice(); 33698 this._multiDrawStarts = source._multiDrawStarts.slice(); 33699 33700 this._matricesTexture = source._matricesTexture.clone(); 33701 this._matricesTexture.image.data = this._matricesTexture.image.slice(); 33702 33703 return this; 33704 33705 } 33706 33707 dispose() { 33708 33709 // Assuming the geometry is not shared with other meshes 33710 this.geometry.dispose(); 33711 33712 this._matricesTexture.dispose(); 33713 this._matricesTexture = null; 33714 return this; 33715 33716 } 33717 33718 onBeforeRender( renderer, scene, camera, geometry, material/*, _group*/ ) { 33719 33720 // if visibility has not changed and frustum culling and object sorting is not required 33721 // then skip iterating over all items 33722 if ( ! this._visibilityChanged && ! this.perObjectFrustumCulled && ! this.sortObjects ) { 33723 33724 return; 33725 33726 } 33727 33728 // the indexed version of the multi draw function requires specifying the start 33729 // offset in bytes. 33730 const index = geometry.getIndex(); 33731 const bytesPerElement = index === null ? 1 : index.array.BYTES_PER_ELEMENT; 33732 33733 const visibility = this._visibility; 33734 const multiDrawStarts = this._multiDrawStarts; 33735 const multiDrawCounts = this._multiDrawCounts; 33736 const drawRanges = this._drawRanges; 33737 const perObjectFrustumCulled = this.perObjectFrustumCulled; 33738 33739 // prepare the frustum in the local frame 33740 if ( perObjectFrustumCulled ) { 33741 33742 _projScreenMatrix$2 33743 .multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ) 33744 .multiply( this.matrixWorld ); 33745 _frustum.setFromProjectionMatrix( 33746 _projScreenMatrix$2, 33747 renderer.isWebGPURenderer ? WebGPUCoordinateSystem : WebGLCoordinateSystem 33748 ); 33749 33750 } 33751 33752 let count = 0; 33753 if ( this.sortObjects ) { 33754 33755 // get the camera position in the local frame 33756 _invMatrixWorld.copy( this.matrixWorld ).invert(); 33757 _vector$5.setFromMatrixPosition( camera.matrixWorld ).applyMatrix4( _invMatrixWorld ); 33758 33759 for ( let i = 0, l = visibility.length; i < l; i ++ ) { 33760 33761 if ( visibility[ i ] ) { 33762 33763 // get the bounds in world space 33764 this.getMatrixAt( i, _matrix ); 33765 this.getBoundingSphereAt( i, _sphere$2 ).applyMatrix4( _matrix ); 33766 33767 // determine whether the batched geometry is within the frustum 33768 let culled = false; 33769 if ( perObjectFrustumCulled ) { 33770 33771 culled = ! _frustum.intersectsSphere( _sphere$2 ); 33772 33773 } 33774 33775 if ( ! culled ) { 33776 33777 // get the distance from camera used for sorting 33778 const z = _vector$5.distanceTo( _sphere$2.center ); 33779 _renderList.push( drawRanges[ i ], z ); 33780 33781 } 33782 33783 } 33784 33785 } 33786 33787 // Sort the draw ranges and prep for rendering 33788 const list = _renderList.list; 33789 const customSort = this.customSort; 33790 if ( customSort === null ) { 33791 33792 list.sort( material.transparent ? sortTransparent : sortOpaque ); 33793 33794 } else { 33795 33796 customSort.call( this, list, camera ); 33797 33798 } 33799 33800 for ( let i = 0, l = list.length; i < l; i ++ ) { 33801 33802 const item = list[ i ]; 33803 multiDrawStarts[ count ] = item.start * bytesPerElement; 33804 multiDrawCounts[ count ] = item.count; 33805 count ++; 33806 33807 } 33808 33809 _renderList.reset(); 33810 33811 } else { 33812 33813 for ( let i = 0, l = visibility.length; i < l; i ++ ) { 33814 33815 if ( visibility[ i ] ) { 33816 33817 // determine whether the batched geometry is within the frustum 33818 let culled = false; 33819 if ( perObjectFrustumCulled ) { 33820 33821 // get the bounds in world space 33822 this.getMatrixAt( i, _matrix ); 33823 this.getBoundingSphereAt( i, _sphere$2 ).applyMatrix4( _matrix ); 33824 culled = ! _frustum.intersectsSphere( _sphere$2 ); 33825 33826 } 33827 33828 if ( ! culled ) { 33829 33830 const range = drawRanges[ i ]; 33831 multiDrawStarts[ count ] = range.start * bytesPerElement; 33832 multiDrawCounts[ count ] = range.count; 33833 count ++; 33834 33835 } 33836 33837 } 33838 33839 } 33840 33841 } 33842 33843 this._multiDrawCount = count; 33844 this._visibilityChanged = false; 33845 33846 } 33847 33848 onBeforeShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial/* , group */ ) { 33849 33850 this.onBeforeRender( renderer, null, shadowCamera, geometry, depthMaterial ); 33851 33852 } 33853 33854} 33855 33856class LineBasicMaterial extends Material { 33857 33858 constructor( parameters ) { 33859 33860 super(); 33861 33862 this.isLineBasicMaterial = true; 33863 33864 this.type = 'LineBasicMaterial'; 33865 33866 this.color = new Color( 0xffffff ); 33867 33868 this.map = null; 33869 33870 this.linewidth = 1; 33871 this.linecap = 'round'; 33872 this.linejoin = 'round'; 33873 33874 this.fog = true; 33875 33876 this.setValues( parameters ); 33877 33878 } 33879 33880 33881 copy( source ) { 33882 33883 super.copy( source ); 33884 33885 this.color.copy( source.color ); 33886 33887 this.map = source.map; 33888 33889 this.linewidth = source.linewidth; 33890 this.linecap = source.linecap; 33891 this.linejoin = source.linejoin; 33892
vendor: 6,071 bytes, lines 33893-34136
33893 this.fog = source.fog; 33894 33895 return this; 33896 33897 } 33898 33899} 33900 33901const _start$1 = /*@__PURE__*/ new Vector3(); 33902const _end$1 = /*@__PURE__*/ new Vector3(); 33903const _inverseMatrix$1 = /*@__PURE__*/ new Matrix4(); 33904const _ray$1 = /*@__PURE__*/ new Ray(); 33905const _sphere$1 = /*@__PURE__*/ new Sphere(); 33906 33907class Line extends Object3D { 33908 33909 constructor( geometry = new BufferGeometry(), material = new LineBasicMaterial() ) { 33910 33911 super(); 33912 33913 this.isLine = true; 33914 33915 this.type = 'Line'; 33916 33917 this.geometry = geometry; 33918 this.material = material; 33919 33920 this.updateMorphTargets(); 33921 33922 } 33923 33924 copy( source, recursive ) { 33925 33926 super.copy( source, recursive ); 33927 33928 this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; 33929 this.geometry = source.geometry; 33930 33931 return this; 33932 33933 } 33934 33935 computeLineDistances() { 33936 33937 const geometry = this.geometry; 33938 33939 // we assume non-indexed geometry 33940 33941 if ( geometry.index === null ) { 33942 33943 const positionAttribute = geometry.attributes.position; 33944 const lineDistances = [ 0 ]; 33945 33946 for ( let i = 1, l = positionAttribute.count; i < l; i ++ ) { 33947 33948 _start$1.fromBufferAttribute( positionAttribute, i - 1 ); 33949 _end$1.fromBufferAttribute( positionAttribute, i ); 33950 33951 lineDistances[ i ] = lineDistances[ i - 1 ]; 33952 lineDistances[ i ] += _start$1.distanceTo( _end$1 ); 33953 33954 } 33955 33956 geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); 33957 33958 } else { 33959 33960 console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); 33961 33962 } 33963 33964 return this; 33965 33966 } 33967 33968 raycast( raycaster, intersects ) { 33969 33970 const geometry = this.geometry; 33971 const matrixWorld = this.matrixWorld; 33972 const threshold = raycaster.params.Line.threshold; 33973 const drawRange = geometry.drawRange; 33974 33975 // Checking boundingSphere distance to ray 33976 33977 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); 33978 33979 _sphere$1.copy( geometry.boundingSphere ); 33980 _sphere$1.applyMatrix4( matrixWorld ); 33981 _sphere$1.radius += threshold; 33982 33983 if ( raycaster.ray.intersectsSphere( _sphere$1 ) === false ) return; 33984 33985 // 33986 33987 _inverseMatrix$1.copy( matrixWorld ).invert(); 33988 _ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 ); 33989 33990 const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); 33991 const localThresholdSq = localThreshold * localThreshold; 33992 33993 const vStart = new Vector3(); 33994 const vEnd = new Vector3(); 33995 const interSegment = new Vector3(); 33996 const interRay = new Vector3(); 33997 const step = this.isLineSegments ? 2 : 1; 33998 33999 const index = geometry.index; 34000 const attributes = geometry.attributes; 34001 const positionAttribute = attributes.position; 34002 34003 if ( index !== null ) { 34004 34005 const start = Math.max( 0, drawRange.start ); 34006 const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); 34007 34008 for ( let i = start, l = end - 1; i < l; i += step ) { 34009 34010 const a = index.getX( i ); 34011 const b = index.getX( i + 1 ); 34012 34013 vStart.fromBufferAttribute( positionAttribute, a ); 34014 vEnd.fromBufferAttribute( positionAttribute, b ); 34015 34016 const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); 34017 34018 if ( distSq > localThresholdSq ) continue; 34019 34020 interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation 34021 34022 const distance = raycaster.ray.origin.distanceTo( interRay ); 34023 34024 if ( distance < raycaster.near || distance > raycaster.far ) continue; 34025 34026 intersects.push( { 34027 34028 distance: distance, 34029 // What do we want? intersection point on the ray or on the segment?? 34030 // point: raycaster.ray.at( distance ), 34031 point: interSegment.clone().applyMatrix4( this.matrixWorld ), 34032 index: i, 34033 face: null, 34034 faceIndex: null, 34035 object: this 34036 34037 } ); 34038 34039 } 34040 34041 } else { 34042 34043 const start = Math.max( 0, drawRange.start ); 34044 const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) ); 34045 34046 for ( let i = start, l = end - 1; i < l; i += step ) { 34047 34048 vStart.fromBufferAttribute( positionAttribute, i ); 34049 vEnd.fromBufferAttribute( positionAttribute, i + 1 ); 34050 34051 const distSq = _ray$1.distanceSqToSegment( vStart, vEnd, interRay, interSegment ); 34052 34053 if ( distSq > localThresholdSq ) continue; 34054 34055 interRay.applyMatrix4( this.matrixWorld ); //Move back to world space for distance calculation 34056 34057 const distance = raycaster.ray.origin.distanceTo( interRay ); 34058 34059 if ( distance < raycaster.near || distance > raycaster.far ) continue; 34060 34061 intersects.push( { 34062 34063 distance: distance, 34064 // What do we want? intersection point on the ray or on the segment?? 34065 // point: raycaster.ray.at( distance ), 34066 point: interSegment.clone().applyMatrix4( this.matrixWorld ), 34067 index: i, 34068 face: null, 34069 faceIndex: null, 34070 object: this 34071 34072 } ); 34073 34074 } 34075 34076 } 34077 34078 } 34079 34080 updateMorphTargets() { 34081 34082 const geometry = this.geometry; 34083 34084 const morphAttributes = geometry.morphAttributes; 34085 const keys = Object.keys( morphAttributes ); 34086 34087 if ( keys.length > 0 ) { 34088 34089 const morphAttribute = morphAttributes[ keys[ 0 ] ]; 34090 34091 if ( morphAttribute !== undefined ) { 34092 34093 this.morphTargetInfluences = []; 34094 this.morphTargetDictionary = {}; 34095 34096 for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { 34097 34098 const name = morphAttribute[ m ].name || String( m ); 34099 34100 this.morphTargetInfluences.push( 0 ); 34101 this.morphTargetDictionary[ name ] = m; 34102 34103 } 34104 34105 } 34106 34107 } 34108 34109 } 34110 34111} 34112 34113const _start = /*@__PURE__*/ new Vector3(); 34114const _end = /*@__PURE__*/ new Vector3(); 34115 34116class LineSegments extends Line { 34117 34118 constructor( geometry, material ) { 34119 34120 super( geometry, material ); 34121 34122 this.isLineSegments = true; 34123 34124 this.type = 'LineSegments'; 34125 34126 } 34127 34128 computeLineDistances() { 34129 34130 const geometry = this.geometry; 34131 34132 // we assume non-indexed geometry 34133 34134 if ( geometry.index === null ) { 34135 34136 const positionAttribute = geometry.attributes.position;
vendor: 10,680 bytes, lines 34137-34647
34137 const lineDistances = []; 34138 34139 for ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) { 34140 34141 _start.fromBufferAttribute( positionAttribute, i ); 34142 _end.fromBufferAttribute( positionAttribute, i + 1 ); 34143 34144 lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ]; 34145 lineDistances[ i + 1 ] = lineDistances[ i ] + _start.distanceTo( _end ); 34146 34147 } 34148 34149 geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); 34150 34151 } else { 34152 34153 console.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); 34154 34155 } 34156 34157 return this; 34158 34159 } 34160 34161} 34162 34163class LineLoop extends Line { 34164 34165 constructor( geometry, material ) { 34166 34167 super( geometry, material ); 34168 34169 this.isLineLoop = true; 34170 34171 this.type = 'LineLoop'; 34172 34173 } 34174 34175} 34176 34177class PointsMaterial extends Material { 34178 34179 constructor( parameters ) { 34180 34181 super(); 34182 34183 this.isPointsMaterial = true; 34184 34185 this.type = 'PointsMaterial'; 34186 34187 this.color = new Color( 0xffffff ); 34188 34189 this.map = null; 34190 34191 this.alphaMap = null; 34192 34193 this.size = 1; 34194 this.sizeAttenuation = true; 34195 34196 this.fog = true; 34197 34198 this.setValues( parameters ); 34199 34200 } 34201 34202 copy( source ) { 34203 34204 super.copy( source ); 34205 34206 this.color.copy( source.color ); 34207 34208 this.map = source.map; 34209 34210 this.alphaMap = source.alphaMap; 34211 34212 this.size = source.size; 34213 this.sizeAttenuation = source.sizeAttenuation; 34214 34215 this.fog = source.fog; 34216 34217 return this; 34218 34219 } 34220 34221} 34222 34223const _inverseMatrix = /*@__PURE__*/ new Matrix4(); 34224const _ray = /*@__PURE__*/ new Ray(); 34225const _sphere = /*@__PURE__*/ new Sphere(); 34226const _position$2 = /*@__PURE__*/ new Vector3(); 34227 34228class Points extends Object3D { 34229 34230 constructor( geometry = new BufferGeometry(), material = new PointsMaterial() ) { 34231 34232 super(); 34233 34234 this.isPoints = true; 34235 34236 this.type = 'Points'; 34237 34238 this.geometry = geometry; 34239 this.material = material; 34240 34241 this.updateMorphTargets(); 34242 34243 } 34244 34245 copy( source, recursive ) { 34246 34247 super.copy( source, recursive ); 34248 34249 this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; 34250 this.geometry = source.geometry; 34251 34252 return this; 34253 34254 } 34255 34256 raycast( raycaster, intersects ) { 34257 34258 const geometry = this.geometry; 34259 const matrixWorld = this.matrixWorld; 34260 const threshold = raycaster.params.Points.threshold; 34261 const drawRange = geometry.drawRange; 34262 34263 // Checking boundingSphere distance to ray 34264 34265 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); 34266 34267 _sphere.copy( geometry.boundingSphere ); 34268 _sphere.applyMatrix4( matrixWorld ); 34269 _sphere.radius += threshold; 34270 34271 if ( raycaster.ray.intersectsSphere( _sphere ) === false ) return; 34272 34273 // 34274 34275 _inverseMatrix.copy( matrixWorld ).invert(); 34276 _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix ); 34277 34278 const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); 34279 const localThresholdSq = localThreshold * localThreshold; 34280 34281 const index = geometry.index; 34282 const attributes = geometry.attributes; 34283 const positionAttribute = attributes.position; 34284 34285 if ( index !== null ) { 34286 34287 const start = Math.max( 0, drawRange.start ); 34288 const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); 34289 34290 for ( let i = start, il = end; i < il; i ++ ) { 34291 34292 const a = index.getX( i ); 34293 34294 _position$2.fromBufferAttribute( positionAttribute, a ); 34295 34296 testPoint( _position$2, a, localThresholdSq, matrixWorld, raycaster, intersects, this ); 34297 34298 } 34299 34300 } else { 34301 34302 const start = Math.max( 0, drawRange.start ); 34303 const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) ); 34304 34305 for ( let i = start, l = end; i < l; i ++ ) { 34306 34307 _position$2.fromBufferAttribute( positionAttribute, i ); 34308 34309 testPoint( _position$2, i, localThresholdSq, matrixWorld, raycaster, intersects, this ); 34310 34311 } 34312 34313 } 34314 34315 } 34316 34317 updateMorphTargets() { 34318 34319 const geometry = this.geometry; 34320 34321 const morphAttributes = geometry.morphAttributes; 34322 const keys = Object.keys( morphAttributes ); 34323 34324 if ( keys.length > 0 ) { 34325 34326 const morphAttribute = morphAttributes[ keys[ 0 ] ]; 34327 34328 if ( morphAttribute !== undefined ) { 34329 34330 this.morphTargetInfluences = []; 34331 this.morphTargetDictionary = {}; 34332 34333 for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { 34334 34335 const name = morphAttribute[ m ].name || String( m ); 34336 34337 this.morphTargetInfluences.push( 0 ); 34338 this.morphTargetDictionary[ name ] = m; 34339 34340 } 34341 34342 } 34343 34344 } 34345 34346 } 34347 34348} 34349 34350function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) { 34351 34352 const rayPointDistanceSq = _ray.distanceSqToPoint( point ); 34353 34354 if ( rayPointDistanceSq < localThresholdSq ) { 34355 34356 const intersectPoint = new Vector3(); 34357 34358 _ray.closestPointToPoint( point, intersectPoint ); 34359 intersectPoint.applyMatrix4( matrixWorld ); 34360 34361 const distance = raycaster.ray.origin.distanceTo( intersectPoint ); 34362 34363 if ( distance < raycaster.near || distance > raycaster.far ) return; 34364 34365 intersects.push( { 34366 34367 distance: distance, 34368 distanceToRay: Math.sqrt( rayPointDistanceSq ), 34369 point: intersectPoint, 34370 index: index, 34371 face: null, 34372 object: object 34373 34374 } ); 34375 34376 } 34377 34378} 34379 34380class VideoTexture extends Texture { 34381 34382 constructor( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { 34383 34384 super( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); 34385 34386 this.isVideoTexture = true; 34387 34388 this.minFilter = minFilter !== undefined ? minFilter : LinearFilter; 34389 this.magFilter = magFilter !== undefined ? magFilter : LinearFilter; 34390 34391 this.generateMipmaps = false; 34392 34393 const scope = this; 34394 34395 function updateVideo() { 34396 34397 scope.needsUpdate = true; 34398 video.requestVideoFrameCallback( updateVideo ); 34399 34400 } 34401 34402 if ( 'requestVideoFrameCallback' in video ) { 34403 34404 video.requestVideoFrameCallback( updateVideo ); 34405 34406 } 34407 34408 } 34409 34410 clone() { 34411 34412 return new this.constructor( this.image ).copy( this ); 34413 34414 } 34415 34416 update() { 34417 34418 const video = this.image; 34419 const hasVideoFrameCallback = 'requestVideoFrameCallback' in video; 34420 34421 if ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) { 34422 34423 this.needsUpdate = true; 34424 34425 } 34426 34427 } 34428 34429} 34430 34431class FramebufferTexture extends Texture { 34432 34433 constructor( width, height ) { 34434 34435 super( { width, height } ); 34436 34437 this.isFramebufferTexture = true; 34438 34439 this.magFilter = NearestFilter; 34440 this.minFilter = NearestFilter; 34441 34442 this.generateMipmaps = false; 34443 34444 this.needsUpdate = true; 34445 34446 } 34447 34448} 34449 34450class CompressedTexture extends Texture { 34451 34452 constructor( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, colorSpace ) { 34453 34454 super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ); 34455 34456 this.isCompressedTexture = true; 34457 34458 this.image = { width: width, height: height }; 34459 this.mipmaps = mipmaps; 34460 34461 // no flipping for cube textures 34462 // (also flipping doesn't work for compressed textures ) 34463 34464 this.flipY = false; 34465 34466 // can't generate mipmaps for compressed textures 34467 // mips must be embedded in DDS files 34468 34469 this.generateMipmaps = false; 34470 34471 } 34472 34473} 34474 34475class CompressedArrayTexture extends CompressedTexture { 34476 34477 constructor( mipmaps, width, height, depth, format, type ) { 34478 34479 super( mipmaps, width, height, format, type ); 34480 34481 this.isCompressedArrayTexture = true; 34482 this.image.depth = depth; 34483 this.wrapR = ClampToEdgeWrapping; 34484 34485 } 34486 34487} 34488 34489class CompressedCubeTexture extends CompressedTexture { 34490 34491 constructor( images, format, type ) { 34492 34493 super( undefined, images[ 0 ].width, images[ 0 ].height, format, type, CubeReflectionMapping ); 34494 34495 this.isCompressedCubeTexture = true; 34496 this.isCubeTexture = true; 34497 34498 this.image = images; 34499 34500 } 34501 34502} 34503 34504class CanvasTexture extends Texture { 34505 34506 constructor( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { 34507 34508 super( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); 34509 34510 this.isCanvasTexture = true; 34511 34512 this.needsUpdate = true; 34513 34514 } 34515 34516} 34517 34518/** 34519 * Extensible curve object. 34520 * 34521 * Some common of curve methods: 34522 * .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget ) 34523 * .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget ) 34524 * .getPoints(), .getSpacedPoints() 34525 * .getLength() 34526 * .updateArcLengths() 34527 * 34528 * This following curves inherit from THREE.Curve: 34529 * 34530 * -- 2D curves -- 34531 * THREE.ArcCurve 34532 * THREE.CubicBezierCurve 34533 * THREE.EllipseCurve 34534 * THREE.LineCurve 34535 * THREE.QuadraticBezierCurve 34536 * THREE.SplineCurve 34537 * 34538 * -- 3D curves -- 34539 * THREE.CatmullRomCurve3 34540 * THREE.CubicBezierCurve3 34541 * THREE.LineCurve3 34542 * THREE.QuadraticBezierCurve3 34543 * 34544 * A series of curves can be represented as a THREE.CurvePath. 34545 * 34546 **/ 34547 34548class Curve { 34549 34550 constructor() { 34551 34552 this.type = 'Curve'; 34553 34554 this.arcLengthDivisions = 200; 34555 34556 } 34557 34558 // Virtual base class method to overwrite and implement in subclasses 34559 // - t [0 .. 1] 34560 34561 getPoint( /* t, optionalTarget */ ) { 34562 34563 console.warn( 'THREE.Curve: .getPoint() not implemented.' ); 34564 return null; 34565 34566 } 34567 34568 // Get point at relative position in curve according to arc length 34569 // - u [0 .. 1] 34570 34571 getPointAt( u, optionalTarget ) { 34572 34573 const t = this.getUtoTmapping( u ); 34574 return this.getPoint( t, optionalTarget ); 34575 34576 } 34577 34578 // Get sequence of points using getPoint( t ) 34579 34580 getPoints( divisions = 5 ) { 34581 34582 const points = []; 34583 34584 for ( let d = 0; d <= divisions; d ++ ) { 34585 34586 points.push( this.getPoint( d / divisions ) ); 34587 34588 } 34589 34590 return points; 34591 34592 } 34593 34594 // Get sequence of points using getPointAt( u ) 34595 34596 getSpacedPoints( divisions = 5 ) { 34597 34598 const points = []; 34599 34600 for ( let d = 0; d <= divisions; d ++ ) { 34601 34602 points.push( this.getPointAt( d / divisions ) ); 34603 34604 } 34605 34606 return points; 34607 34608 } 34609 34610 // Get total curve arc length 34611 34612 getLength() { 34613 34614 const lengths = this.getLengths(); 34615 return lengths[ lengths.length - 1 ]; 34616 34617 } 34618 34619 // Get list of cumulative segment lengths 34620 34621 getLengths( divisions = this.arcLengthDivisions ) { 34622 34623 if ( this.cacheArcLengths && 34624 ( this.cacheArcLengths.length === divisions + 1 ) && 34625 ! this.needsUpdate ) { 34626 34627 return this.cacheArcLengths; 34628 34629 } 34630 34631 this.needsUpdate = false; 34632 34633 const cache = []; 34634 let current, last = this.getPoint( 0 ); 34635 let sum = 0; 34636 34637 cache.push( 0 ); 34638 34639 for ( let p = 1; p <= divisions; p ++ ) { 34640 34641 current = this.getPoint( p / divisions ); 34642 sum += current.distanceTo( last ); 34643 cache.push( sum ); 34644 last = current; 34645 34646 } 34647
vendor: 7,167 bytes, lines 34648-34998
34648 this.cacheArcLengths = cache; 34649 34650 return cache; // { sums: cache, sum: sum }; Sum is in the last element. 34651 34652 } 34653 34654 updateArcLengths() { 34655 34656 this.needsUpdate = true; 34657 this.getLengths(); 34658 34659 } 34660 34661 // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant 34662 34663 getUtoTmapping( u, distance ) { 34664 34665 const arcLengths = this.getLengths(); 34666 34667 let i = 0; 34668 const il = arcLengths.length; 34669 34670 let targetArcLength; // The targeted u distance value to get 34671 34672 if ( distance ) { 34673 34674 targetArcLength = distance; 34675 34676 } else { 34677 34678 targetArcLength = u * arcLengths[ il - 1 ]; 34679 34680 } 34681 34682 // binary search for the index with largest value smaller than target u distance 34683 34684 let low = 0, high = il - 1, comparison; 34685 34686 while ( low <= high ) { 34687 34688 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 34689 34690 comparison = arcLengths[ i ] - targetArcLength; 34691 34692 if ( comparison < 0 ) { 34693 34694 low = i + 1; 34695 34696 } else if ( comparison > 0 ) { 34697 34698 high = i - 1; 34699 34700 } else { 34701 34702 high = i; 34703 break; 34704 34705 // DONE 34706 34707 } 34708 34709 } 34710 34711 i = high; 34712 34713 if ( arcLengths[ i ] === targetArcLength ) { 34714 34715 return i / ( il - 1 ); 34716 34717 } 34718 34719 // we could get finer grain at lengths, or use simple interpolation between two points 34720 34721 const lengthBefore = arcLengths[ i ]; 34722 const lengthAfter = arcLengths[ i + 1 ]; 34723 34724 const segmentLength = lengthAfter - lengthBefore; 34725 34726 // determine where we are between the 'before' and 'after' points 34727 34728 const segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; 34729 34730 // add that fractional amount to t 34731 34732 const t = ( i + segmentFraction ) / ( il - 1 ); 34733 34734 return t; 34735 34736 } 34737 34738 // Returns a unit vector tangent at t 34739 // In case any sub curve does not implement its tangent derivation, 34740 // 2 points a small delta apart will be used to find its gradient 34741 // which seems to give a reasonable approximation 34742 34743 getTangent( t, optionalTarget ) { 34744 34745 const delta = 0.0001; 34746 let t1 = t - delta; 34747 let t2 = t + delta; 34748 34749 // Capping in case of danger 34750 34751 if ( t1 < 0 ) t1 = 0; 34752 if ( t2 > 1 ) t2 = 1; 34753 34754 const pt1 = this.getPoint( t1 ); 34755 const pt2 = this.getPoint( t2 ); 34756 34757 const tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() ); 34758 34759 tangent.copy( pt2 ).sub( pt1 ).normalize(); 34760 34761 return tangent; 34762 34763 } 34764 34765 getTangentAt( u, optionalTarget ) { 34766 34767 const t = this.getUtoTmapping( u ); 34768 return this.getTangent( t, optionalTarget ); 34769 34770 } 34771 34772 computeFrenetFrames( segments, closed ) { 34773 34774 // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf 34775 34776 const normal = new Vector3(); 34777 34778 const tangents = []; 34779 const normals = []; 34780 const binormals = []; 34781 34782 const vec = new Vector3(); 34783 const mat = new Matrix4(); 34784 34785 // compute the tangent vectors for each segment on the curve 34786 34787 for ( let i = 0; i <= segments; i ++ ) { 34788 34789 const u = i / segments; 34790 34791 tangents[ i ] = this.getTangentAt( u, new Vector3() ); 34792 34793 } 34794 34795 // select an initial normal vector perpendicular to the first tangent vector, 34796 // and in the direction of the minimum tangent xyz component 34797 34798 normals[ 0 ] = new Vector3(); 34799 binormals[ 0 ] = new Vector3(); 34800 let min = Number.MAX_VALUE; 34801 const tx = Math.abs( tangents[ 0 ].x ); 34802 const ty = Math.abs( tangents[ 0 ].y ); 34803 const tz = Math.abs( tangents[ 0 ].z ); 34804 34805 if ( tx <= min ) { 34806 34807 min = tx; 34808 normal.set( 1, 0, 0 ); 34809 34810 } 34811 34812 if ( ty <= min ) { 34813 34814 min = ty; 34815 normal.set( 0, 1, 0 ); 34816 34817 } 34818 34819 if ( tz <= min ) { 34820 34821 normal.set( 0, 0, 1 ); 34822 34823 } 34824 34825 vec.crossVectors( tangents[ 0 ], normal ).normalize(); 34826 34827 normals[ 0 ].crossVectors( tangents[ 0 ], vec ); 34828 binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); 34829 34830 34831 // compute the slowly-varying normal and binormal vectors for each segment on the curve 34832 34833 for ( let i = 1; i <= segments; i ++ ) { 34834 34835 normals[ i ] = normals[ i - 1 ].clone(); 34836 34837 binormals[ i ] = binormals[ i - 1 ].clone(); 34838 34839 vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); 34840 34841 if ( vec.length() > Number.EPSILON ) { 34842 34843 vec.normalize(); 34844 34845 const theta = Math.acos( clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors 34846 34847 normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); 34848 34849 } 34850 34851 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); 34852 34853 } 34854 34855 // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same 34856 34857 if ( closed === true ) { 34858 34859 let theta = Math.acos( clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) ); 34860 theta /= segments; 34861 34862 if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { 34863 34864 theta = - theta; 34865 34866 } 34867 34868 for ( let i = 1; i <= segments; i ++ ) { 34869 34870 // twist a little... 34871 normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); 34872 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); 34873 34874 } 34875 34876 } 34877 34878 return { 34879 tangents: tangents, 34880 normals: normals, 34881 binormals: binormals 34882 }; 34883 34884 } 34885 34886 clone() { 34887 34888 return new this.constructor().copy( this ); 34889 34890 } 34891 34892 copy( source ) { 34893 34894 this.arcLengthDivisions = source.arcLengthDivisions; 34895 34896 return this; 34897 34898 } 34899 34900 toJSON() { 34901 34902 const data = { 34903 metadata: { 34904 version: 4.6, 34905 type: 'Curve', 34906 generator: 'Curve.toJSON' 34907 } 34908 }; 34909 34910 data.arcLengthDivisions = this.arcLengthDivisions; 34911 data.type = this.type; 34912 34913 return data; 34914 34915 } 34916 34917 fromJSON( json ) { 34918 34919 this.arcLengthDivisions = json.arcLengthDivisions; 34920 34921 return this; 34922 34923 } 34924 34925} 34926 34927class EllipseCurve extends Curve { 34928 34929 constructor( aX = 0, aY = 0, xRadius = 1, yRadius = 1, aStartAngle = 0, aEndAngle = Math.PI * 2, aClockwise = false, aRotation = 0 ) { 34930 34931 super(); 34932 34933 this.isEllipseCurve = true; 34934 34935 this.type = 'EllipseCurve'; 34936 34937 this.aX = aX; 34938 this.aY = aY; 34939 34940 this.xRadius = xRadius; 34941 this.yRadius = yRadius; 34942 34943 this.aStartAngle = aStartAngle; 34944 this.aEndAngle = aEndAngle; 34945 34946 this.aClockwise = aClockwise; 34947 34948 this.aRotation = aRotation; 34949 34950 } 34951 34952 getPoint( t, optionalTarget ) { 34953 34954 const point = optionalTarget || new Vector2(); 34955 34956 const twoPi = Math.PI * 2; 34957 let deltaAngle = this.aEndAngle - this.aStartAngle; 34958 const samePoints = Math.abs( deltaAngle ) < Number.EPSILON; 34959 34960 // ensures that deltaAngle is 0 .. 2 PI 34961 while ( deltaAngle < 0 ) deltaAngle += twoPi; 34962 while ( deltaAngle > twoPi ) deltaAngle -= twoPi; 34963 34964 if ( deltaAngle < Number.EPSILON ) { 34965 34966 if ( samePoints ) { 34967 34968 deltaAngle = 0; 34969 34970 } else { 34971 34972 deltaAngle = twoPi; 34973 34974 } 34975 34976 } 34977 34978 if ( this.aClockwise === true && ! samePoints ) { 34979 34980 if ( deltaAngle === twoPi ) { 34981 34982 deltaAngle = - twoPi; 34983 34984 } else { 34985 34986 deltaAngle = deltaAngle - twoPi; 34987 34988 } 34989 34990 } 34991 34992 const angle = this.aStartAngle + t * deltaAngle; 34993 let x = this.aX + this.xRadius * Math.cos( angle ); 34994 let y = this.aY + this.yRadius * Math.sin( angle ); 34995 34996 if ( this.aRotation !== 0 ) { 34997 34998 const cos = Math.cos( this.aRotation );
vendor: 32,499 bytes, lines 34999-36739
34999 const sin = Math.sin( this.aRotation ); 35000 35001 const tx = x - this.aX; 35002 const ty = y - this.aY; 35003 35004 // Rotate the point about the center of the ellipse. 35005 x = tx * cos - ty * sin + this.aX; 35006 y = tx * sin + ty * cos + this.aY; 35007 35008 } 35009 35010 return point.set( x, y ); 35011 35012 } 35013 35014 copy( source ) { 35015 35016 super.copy( source ); 35017 35018 this.aX = source.aX; 35019 this.aY = source.aY; 35020 35021 this.xRadius = source.xRadius; 35022 this.yRadius = source.yRadius; 35023 35024 this.aStartAngle = source.aStartAngle; 35025 this.aEndAngle = source.aEndAngle; 35026 35027 this.aClockwise = source.aClockwise; 35028 35029 this.aRotation = source.aRotation; 35030 35031 return this; 35032 35033 } 35034 35035 toJSON() { 35036 35037 const data = super.toJSON(); 35038 35039 data.aX = this.aX; 35040 data.aY = this.aY; 35041 35042 data.xRadius = this.xRadius; 35043 data.yRadius = this.yRadius; 35044 35045 data.aStartAngle = this.aStartAngle; 35046 data.aEndAngle = this.aEndAngle; 35047 35048 data.aClockwise = this.aClockwise; 35049 35050 data.aRotation = this.aRotation; 35051 35052 return data; 35053 35054 } 35055 35056 fromJSON( json ) { 35057 35058 super.fromJSON( json ); 35059 35060 this.aX = json.aX; 35061 this.aY = json.aY; 35062 35063 this.xRadius = json.xRadius; 35064 this.yRadius = json.yRadius; 35065 35066 this.aStartAngle = json.aStartAngle; 35067 this.aEndAngle = json.aEndAngle; 35068 35069 this.aClockwise = json.aClockwise; 35070 35071 this.aRotation = json.aRotation; 35072 35073 return this; 35074 35075 } 35076 35077} 35078 35079class ArcCurve extends EllipseCurve { 35080 35081 constructor( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { 35082 35083 super( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); 35084 35085 this.isArcCurve = true; 35086 35087 this.type = 'ArcCurve'; 35088 35089 } 35090 35091} 35092 35093/** 35094 * Centripetal CatmullRom Curve - which is useful for avoiding 35095 * cusps and self-intersections in non-uniform catmull rom curves. 35096 * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf 35097 * 35098 * curve.type accepts centripetal(default), chordal and catmullrom 35099 * curve.tension is used for catmullrom which defaults to 0.5 35100 */ 35101 35102 35103/* 35104Based on an optimized c++ solution in 35105 - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/ 35106 - http://ideone.com/NoEbVM 35107 35108This CubicPoly class could be used for reusing some variables and calculations, 35109but for three.js curve use, it could be possible inlined and flatten into a single function call 35110which can be placed in CurveUtils. 35111*/ 35112 35113function CubicPoly() { 35114 35115 let c0 = 0, c1 = 0, c2 = 0, c3 = 0; 35116 35117 /* 35118 * Compute coefficients for a cubic polynomial 35119 * p(s) = c0 + c1*s + c2*s^2 + c3*s^3 35120 * such that 35121 * p(0) = x0, p(1) = x1 35122 * and 35123 * p'(0) = t0, p'(1) = t1. 35124 */ 35125 function init( x0, x1, t0, t1 ) { 35126 35127 c0 = x0; 35128 c1 = t0; 35129 c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; 35130 c3 = 2 * x0 - 2 * x1 + t0 + t1; 35131 35132 } 35133 35134 return { 35135 35136 initCatmullRom: function ( x0, x1, x2, x3, tension ) { 35137 35138 init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); 35139 35140 }, 35141 35142 initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) { 35143 35144 // compute tangents when parameterized in [t1,t2] 35145 let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; 35146 let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2; 35147 35148 // rescale tangents for parametrization in [0,1] 35149 t1 *= dt1; 35150 t2 *= dt1; 35151 35152 init( x1, x2, t1, t2 ); 35153 35154 }, 35155 35156 calc: function ( t ) { 35157 35158 const t2 = t * t; 35159 const t3 = t2 * t; 35160 return c0 + c1 * t + c2 * t2 + c3 * t3; 35161 35162 } 35163 35164 }; 35165 35166} 35167 35168// 35169 35170const tmp = /*@__PURE__*/ new Vector3(); 35171const px = /*@__PURE__*/ new CubicPoly(); 35172const py = /*@__PURE__*/ new CubicPoly(); 35173const pz = /*@__PURE__*/ new CubicPoly(); 35174 35175class CatmullRomCurve3 extends Curve { 35176 35177 constructor( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) { 35178 35179 super(); 35180 35181 this.isCatmullRomCurve3 = true; 35182 35183 this.type = 'CatmullRomCurve3'; 35184 35185 this.points = points; 35186 this.closed = closed; 35187 this.curveType = curveType; 35188 this.tension = tension; 35189 35190 } 35191 35192 getPoint( t, optionalTarget = new Vector3() ) { 35193 35194 const point = optionalTarget; 35195 35196 const points = this.points; 35197 const l = points.length; 35198 35199 const p = ( l - ( this.closed ? 0 : 1 ) ) * t; 35200 let intPoint = Math.floor( p ); 35201 let weight = p - intPoint; 35202 35203 if ( this.closed ) { 35204 35205 intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l; 35206 35207 } else if ( weight === 0 && intPoint === l - 1 ) { 35208 35209 intPoint = l - 2; 35210 weight = 1; 35211 35212 } 35213 35214 let p0, p3; // 4 points (p1 & p2 defined below) 35215 35216 if ( this.closed || intPoint > 0 ) { 35217 35218 p0 = points[ ( intPoint - 1 ) % l ]; 35219 35220 } else { 35221 35222 // extrapolate first point 35223 tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); 35224 p0 = tmp; 35225 35226 } 35227 35228 const p1 = points[ intPoint % l ]; 35229 const p2 = points[ ( intPoint + 1 ) % l ]; 35230 35231 if ( this.closed || intPoint + 2 < l ) { 35232 35233 p3 = points[ ( intPoint + 2 ) % l ]; 35234 35235 } else { 35236 35237 // extrapolate last point 35238 tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] ); 35239 p3 = tmp; 35240 35241 } 35242 35243 if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) { 35244 35245 // init Centripetal / Chordal Catmull-Rom 35246 const pow = this.curveType === 'chordal' ? 0.5 : 0.25; 35247 let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); 35248 let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); 35249 let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); 35250 35251 // safety check for repeated points 35252 if ( dt1 < 1e-4 ) dt1 = 1.0; 35253 if ( dt0 < 1e-4 ) dt0 = dt1; 35254 if ( dt2 < 1e-4 ) dt2 = dt1; 35255 35256 px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 ); 35257 py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 ); 35258 pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 ); 35259 35260 } else if ( this.curveType === 'catmullrom' ) { 35261 35262 px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension ); 35263 py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension ); 35264 pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension ); 35265 35266 } 35267 35268 point.set( 35269 px.calc( weight ), 35270 py.calc( weight ), 35271 pz.calc( weight ) 35272 ); 35273 35274 return point; 35275 35276 } 35277 35278 copy( source ) { 35279 35280 super.copy( source ); 35281 35282 this.points = []; 35283 35284 for ( let i = 0, l = source.points.length; i < l; i ++ ) { 35285 35286 const point = source.points[ i ]; 35287 35288 this.points.push( point.clone() ); 35289 35290 } 35291 35292 this.closed = source.closed; 35293 this.curveType = source.curveType; 35294 this.tension = source.tension; 35295 35296 return this; 35297 35298 } 35299 35300 toJSON() { 35301 35302 const data = super.toJSON(); 35303 35304 data.points = []; 35305 35306 for ( let i = 0, l = this.points.length; i < l; i ++ ) { 35307 35308 const point = this.points[ i ]; 35309 data.points.push( point.toArray() ); 35310 35311 } 35312 35313 data.closed = this.closed; 35314 data.curveType = this.curveType; 35315 data.tension = this.tension; 35316 35317 return data; 35318 35319 } 35320 35321 fromJSON( json ) { 35322 35323 super.fromJSON( json ); 35324 35325 this.points = []; 35326 35327 for ( let i = 0, l = json.points.length; i < l; i ++ ) { 35328 35329 const point = json.points[ i ]; 35330 this.points.push( new Vector3().fromArray( point ) ); 35331 35332 } 35333 35334 this.closed = json.closed; 35335 this.curveType = json.curveType; 35336 this.tension = json.tension; 35337 35338 return this; 35339 35340 } 35341 35342} 35343 35344/** 35345 * Bezier Curves formulas obtained from 35346 * https://en.wikipedia.org/wiki/B%C3%A9zier_curve 35347 */ 35348 35349function CatmullRom( t, p0, p1, p2, p3 ) { 35350 35351 const v0 = ( p2 - p0 ) * 0.5; 35352 const v1 = ( p3 - p1 ) * 0.5; 35353 const t2 = t * t; 35354 const t3 = t * t2; 35355 return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; 35356 35357} 35358 35359// 35360 35361function QuadraticBezierP0( t, p ) { 35362 35363 const k = 1 - t; 35364 return k * k * p; 35365 35366} 35367 35368function QuadraticBezierP1( t, p ) { 35369 35370 return 2 * ( 1 - t ) * t * p; 35371 35372} 35373 35374function QuadraticBezierP2( t, p ) { 35375 35376 return t * t * p; 35377 35378} 35379 35380function QuadraticBezier( t, p0, p1, p2 ) { 35381 35382 return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + 35383 QuadraticBezierP2( t, p2 ); 35384 35385} 35386 35387// 35388 35389function CubicBezierP0( t, p ) { 35390 35391 const k = 1 - t; 35392 return k * k * k * p; 35393 35394} 35395 35396function CubicBezierP1( t, p ) { 35397 35398 const k = 1 - t; 35399 return 3 * k * k * t * p; 35400 35401} 35402 35403function CubicBezierP2( t, p ) { 35404 35405 return 3 * ( 1 - t ) * t * t * p; 35406 35407} 35408 35409function CubicBezierP3( t, p ) { 35410 35411 return t * t * t * p; 35412 35413} 35414 35415function CubicBezier( t, p0, p1, p2, p3 ) { 35416 35417 return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + 35418 CubicBezierP3( t, p3 ); 35419 35420} 35421 35422class CubicBezierCurve extends Curve { 35423 35424 constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) { 35425 35426 super(); 35427 35428 this.isCubicBezierCurve = true; 35429 35430 this.type = 'CubicBezierCurve'; 35431 35432 this.v0 = v0; 35433 this.v1 = v1; 35434 this.v2 = v2; 35435 this.v3 = v3; 35436 35437 } 35438 35439 getPoint( t, optionalTarget = new Vector2() ) { 35440 35441 const point = optionalTarget; 35442 35443 const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; 35444 35445 point.set( 35446 CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), 35447 CubicBezier( t, v0.y, v1.y, v2.y, v3.y ) 35448 ); 35449 35450 return point; 35451 35452 } 35453 35454 copy( source ) { 35455 35456 super.copy( source ); 35457 35458 this.v0.copy( source.v0 ); 35459 this.v1.copy( source.v1 ); 35460 this.v2.copy( source.v2 ); 35461 this.v3.copy( source.v3 ); 35462 35463 return this; 35464 35465 } 35466 35467 toJSON() { 35468 35469 const data = super.toJSON(); 35470 35471 data.v0 = this.v0.toArray(); 35472 data.v1 = this.v1.toArray(); 35473 data.v2 = this.v2.toArray(); 35474 data.v3 = this.v3.toArray(); 35475 35476 return data; 35477 35478 } 35479 35480 fromJSON( json ) { 35481 35482 super.fromJSON( json ); 35483 35484 this.v0.fromArray( json.v0 ); 35485 this.v1.fromArray( json.v1 ); 35486 this.v2.fromArray( json.v2 ); 35487 this.v3.fromArray( json.v3 ); 35488 35489 return this; 35490 35491 } 35492 35493} 35494 35495class CubicBezierCurve3 extends Curve { 35496 35497 constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) { 35498 35499 super(); 35500 35501 this.isCubicBezierCurve3 = true; 35502 35503 this.type = 'CubicBezierCurve3'; 35504 35505 this.v0 = v0; 35506 this.v1 = v1; 35507 this.v2 = v2; 35508 this.v3 = v3; 35509 35510 } 35511 35512 getPoint( t, optionalTarget = new Vector3() ) { 35513 35514 const point = optionalTarget; 35515 35516 const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; 35517 35518 point.set( 35519 CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), 35520 CubicBezier( t, v0.y, v1.y, v2.y, v3.y ), 35521 CubicBezier( t, v0.z, v1.z, v2.z, v3.z ) 35522 ); 35523 35524 return point; 35525 35526 } 35527 35528 copy( source ) { 35529 35530 super.copy( source ); 35531 35532 this.v0.copy( source.v0 ); 35533 this.v1.copy( source.v1 ); 35534 this.v2.copy( source.v2 ); 35535 this.v3.copy( source.v3 ); 35536 35537 return this; 35538 35539 } 35540 35541 toJSON() { 35542 35543 const data = super.toJSON(); 35544 35545 data.v0 = this.v0.toArray(); 35546 data.v1 = this.v1.toArray(); 35547 data.v2 = this.v2.toArray(); 35548 data.v3 = this.v3.toArray(); 35549 35550 return data; 35551 35552 } 35553 35554 fromJSON( json ) { 35555 35556 super.fromJSON( json ); 35557 35558 this.v0.fromArray( json.v0 ); 35559 this.v1.fromArray( json.v1 ); 35560 this.v2.fromArray( json.v2 ); 35561 this.v3.fromArray( json.v3 ); 35562 35563 return this; 35564 35565 } 35566 35567} 35568 35569class LineCurve extends Curve { 35570 35571 constructor( v1 = new Vector2(), v2 = new Vector2() ) { 35572 35573 super(); 35574 35575 this.isLineCurve = true; 35576 35577 this.type = 'LineCurve'; 35578 35579 this.v1 = v1; 35580 this.v2 = v2; 35581 35582 } 35583 35584 getPoint( t, optionalTarget = new Vector2() ) { 35585 35586 const point = optionalTarget; 35587 35588 if ( t === 1 ) { 35589 35590 point.copy( this.v2 ); 35591 35592 } else { 35593 35594 point.copy( this.v2 ).sub( this.v1 ); 35595 point.multiplyScalar( t ).add( this.v1 ); 35596 35597 } 35598 35599 return point; 35600 35601 } 35602 35603 // Line curve is linear, so we can overwrite default getPointAt 35604 getPointAt( u, optionalTarget ) { 35605 35606 return this.getPoint( u, optionalTarget ); 35607 35608 } 35609 35610 getTangent( t, optionalTarget = new Vector2() ) { 35611 35612 return optionalTarget.subVectors( this.v2, this.v1 ).normalize(); 35613 35614 } 35615 35616 getTangentAt( u, optionalTarget ) { 35617 35618 return this.getTangent( u, optionalTarget ); 35619 35620 } 35621 35622 copy( source ) { 35623 35624 super.copy( source ); 35625 35626 this.v1.copy( source.v1 ); 35627 this.v2.copy( source.v2 ); 35628 35629 return this; 35630 35631 } 35632 35633 toJSON() { 35634 35635 const data = super.toJSON(); 35636 35637 data.v1 = this.v1.toArray(); 35638 data.v2 = this.v2.toArray(); 35639 35640 return data; 35641 35642 } 35643 35644 fromJSON( json ) { 35645 35646 super.fromJSON( json ); 35647 35648 this.v1.fromArray( json.v1 ); 35649 this.v2.fromArray( json.v2 ); 35650 35651 return this; 35652 35653 } 35654 35655} 35656 35657class LineCurve3 extends Curve { 35658 35659 constructor( v1 = new Vector3(), v2 = new Vector3() ) { 35660 35661 super(); 35662 35663 this.isLineCurve3 = true; 35664 35665 this.type = 'LineCurve3'; 35666 35667 this.v1 = v1; 35668 this.v2 = v2; 35669 35670 } 35671 35672 getPoint( t, optionalTarget = new Vector3() ) { 35673 35674 const point = optionalTarget; 35675 35676 if ( t === 1 ) { 35677 35678 point.copy( this.v2 ); 35679 35680 } else { 35681 35682 point.copy( this.v2 ).sub( this.v1 ); 35683 point.multiplyScalar( t ).add( this.v1 ); 35684 35685 } 35686 35687 return point; 35688 35689 } 35690 35691 // Line curve is linear, so we can overwrite default getPointAt 35692 getPointAt( u, optionalTarget ) { 35693 35694 return this.getPoint( u, optionalTarget ); 35695 35696 } 35697 35698 getTangent( t, optionalTarget = new Vector3() ) { 35699 35700 return optionalTarget.subVectors( this.v2, this.v1 ).normalize(); 35701 35702 } 35703 35704 getTangentAt( u, optionalTarget ) { 35705 35706 return this.getTangent( u, optionalTarget ); 35707 35708 } 35709 35710 copy( source ) { 35711 35712 super.copy( source ); 35713 35714 this.v1.copy( source.v1 ); 35715 this.v2.copy( source.v2 ); 35716 35717 return this; 35718 35719 } 35720 35721 toJSON() { 35722 35723 const data = super.toJSON(); 35724 35725 data.v1 = this.v1.toArray(); 35726 data.v2 = this.v2.toArray(); 35727 35728 return data; 35729 35730 } 35731 35732 fromJSON( json ) { 35733 35734 super.fromJSON( json ); 35735 35736 this.v1.fromArray( json.v1 ); 35737 this.v2.fromArray( json.v2 ); 35738 35739 return this; 35740 35741 } 35742 35743} 35744 35745class QuadraticBezierCurve extends Curve { 35746 35747 constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) { 35748 35749 super(); 35750 35751 this.isQuadraticBezierCurve = true; 35752 35753 this.type = 'QuadraticBezierCurve'; 35754 35755 this.v0 = v0; 35756 this.v1 = v1; 35757 this.v2 = v2; 35758 35759 } 35760 35761 getPoint( t, optionalTarget = new Vector2() ) { 35762 35763 const point = optionalTarget; 35764 35765 const v0 = this.v0, v1 = this.v1, v2 = this.v2; 35766 35767 point.set( 35768 QuadraticBezier( t, v0.x, v1.x, v2.x ), 35769 QuadraticBezier( t, v0.y, v1.y, v2.y ) 35770 ); 35771 35772 return point; 35773 35774 } 35775 35776 copy( source ) { 35777 35778 super.copy( source ); 35779 35780 this.v0.copy( source.v0 ); 35781 this.v1.copy( source.v1 ); 35782 this.v2.copy( source.v2 ); 35783 35784 return this; 35785 35786 } 35787 35788 toJSON() { 35789 35790 const data = super.toJSON(); 35791 35792 data.v0 = this.v0.toArray(); 35793 data.v1 = this.v1.toArray(); 35794 data.v2 = this.v2.toArray(); 35795 35796 return data; 35797 35798 } 35799 35800 fromJSON( json ) { 35801 35802 super.fromJSON( json ); 35803 35804 this.v0.fromArray( json.v0 ); 35805 this.v1.fromArray( json.v1 ); 35806 this.v2.fromArray( json.v2 ); 35807 35808 return this; 35809 35810 } 35811 35812} 35813 35814class QuadraticBezierCurve3 extends Curve { 35815 35816 constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) { 35817 35818 super(); 35819 35820 this.isQuadraticBezierCurve3 = true; 35821 35822 this.type = 'QuadraticBezierCurve3'; 35823 35824 this.v0 = v0; 35825 this.v1 = v1; 35826 this.v2 = v2; 35827 35828 } 35829 35830 getPoint( t, optionalTarget = new Vector3() ) { 35831 35832 const point = optionalTarget; 35833 35834 const v0 = this.v0, v1 = this.v1, v2 = this.v2; 35835 35836 point.set( 35837 QuadraticBezier( t, v0.x, v1.x, v2.x ), 35838 QuadraticBezier( t, v0.y, v1.y, v2.y ), 35839 QuadraticBezier( t, v0.z, v1.z, v2.z ) 35840 ); 35841 35842 return point; 35843 35844 } 35845 35846 copy( source ) { 35847 35848 super.copy( source ); 35849 35850 this.v0.copy( source.v0 ); 35851 this.v1.copy( source.v1 ); 35852 this.v2.copy( source.v2 ); 35853 35854 return this; 35855 35856 } 35857 35858 toJSON() { 35859 35860 const data = super.toJSON(); 35861 35862 data.v0 = this.v0.toArray(); 35863 data.v1 = this.v1.toArray(); 35864 data.v2 = this.v2.toArray(); 35865 35866 return data; 35867 35868 } 35869 35870 fromJSON( json ) { 35871 35872 super.fromJSON( json ); 35873 35874 this.v0.fromArray( json.v0 ); 35875 this.v1.fromArray( json.v1 ); 35876 this.v2.fromArray( json.v2 ); 35877 35878 return this; 35879 35880 } 35881 35882} 35883 35884class SplineCurve extends Curve { 35885 35886 constructor( points = [] ) { 35887 35888 super(); 35889 35890 this.isSplineCurve = true; 35891 35892 this.type = 'SplineCurve'; 35893 35894 this.points = points; 35895 35896 } 35897 35898 getPoint( t, optionalTarget = new Vector2() ) { 35899 35900 const point = optionalTarget; 35901 35902 const points = this.points; 35903 const p = ( points.length - 1 ) * t; 35904 35905 const intPoint = Math.floor( p ); 35906 const weight = p - intPoint; 35907 35908 const p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; 35909 const p1 = points[ intPoint ]; 35910 const p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; 35911 const p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; 35912 35913 point.set( 35914 CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ), 35915 CatmullRom( weight, p0.y, p1.y, p2.y, p3.y ) 35916 ); 35917 35918 return point; 35919 35920 } 35921 35922 copy( source ) { 35923 35924 super.copy( source ); 35925 35926 this.points = []; 35927 35928 for ( let i = 0, l = source.points.length; i < l; i ++ ) { 35929 35930 const point = source.points[ i ]; 35931 35932 this.points.push( point.clone() ); 35933 35934 } 35935 35936 return this; 35937 35938 } 35939 35940 toJSON() { 35941 35942 const data = super.toJSON(); 35943 35944 data.points = []; 35945 35946 for ( let i = 0, l = this.points.length; i < l; i ++ ) { 35947 35948 const point = this.points[ i ]; 35949 data.points.push( point.toArray() ); 35950 35951 } 35952 35953 return data; 35954 35955 } 35956 35957 fromJSON( json ) { 35958 35959 super.fromJSON( json ); 35960 35961 this.points = []; 35962 35963 for ( let i = 0, l = json.points.length; i < l; i ++ ) { 35964 35965 const point = json.points[ i ]; 35966 this.points.push( new Vector2().fromArray( point ) ); 35967 35968 } 35969 35970 return this; 35971 35972 } 35973 35974} 35975 35976var Curves = /*#__PURE__*/Object.freeze({ 35977 __proto__: null, 35978 ArcCurve: ArcCurve, 35979 CatmullRomCurve3: CatmullRomCurve3, 35980 CubicBezierCurve: CubicBezierCurve, 35981 CubicBezierCurve3: CubicBezierCurve3, 35982 EllipseCurve: EllipseCurve, 35983 LineCurve: LineCurve, 35984 LineCurve3: LineCurve3, 35985 QuadraticBezierCurve: QuadraticBezierCurve, 35986 QuadraticBezierCurve3: QuadraticBezierCurve3, 35987 SplineCurve: SplineCurve 35988}); 35989 35990/************************************************************** 35991 * Curved Path - a curve path is simply a array of connected 35992 * curves, but retains the api of a curve 35993 **************************************************************/ 35994 35995class CurvePath extends Curve { 35996 35997 constructor() { 35998 35999 super(); 36000 36001 this.type = 'CurvePath'; 36002 36003 this.curves = []; 36004 this.autoClose = false; // Automatically closes the path 36005 36006 } 36007 36008 add( curve ) { 36009 36010 this.curves.push( curve ); 36011 36012 } 36013 36014 closePath() { 36015 36016 // Add a line curve if start and end of lines are not connected 36017 const startPoint = this.curves[ 0 ].getPoint( 0 ); 36018 const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 ); 36019 36020 if ( ! startPoint.equals( endPoint ) ) { 36021 36022 const lineType = ( startPoint.isVector2 === true ) ? 'LineCurve' : 'LineCurve3'; 36023 this.curves.push( new Curves[ lineType ]( endPoint, startPoint ) ); 36024 36025 } 36026 36027 return this; 36028 36029 } 36030 36031 // To get accurate point with reference to 36032 // entire path distance at time t, 36033 // following has to be done: 36034 36035 // 1. Length of each sub path have to be known 36036 // 2. Locate and identify type of curve 36037 // 3. Get t for the curve 36038 // 4. Return curve.getPointAt(t') 36039 36040 getPoint( t, optionalTarget ) { 36041 36042 const d = t * this.getLength(); 36043 const curveLengths = this.getCurveLengths(); 36044 let i = 0; 36045 36046 // To think about boundaries points. 36047 36048 while ( i < curveLengths.length ) { 36049 36050 if ( curveLengths[ i ] >= d ) { 36051 36052 const diff = curveLengths[ i ] - d; 36053 const curve = this.curves[ i ]; 36054 36055 const segmentLength = curve.getLength(); 36056 const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; 36057 36058 return curve.getPointAt( u, optionalTarget ); 36059 36060 } 36061 36062 i ++; 36063 36064 } 36065 36066 return null; 36067 36068 // loop where sum != 0, sum > d , sum+1 <d 36069 36070 } 36071 36072 // We cannot use the default THREE.Curve getPoint() with getLength() because in 36073 // THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath 36074 // getPoint() depends on getLength 36075 36076 getLength() { 36077 36078 const lens = this.getCurveLengths(); 36079 return lens[ lens.length - 1 ]; 36080 36081 } 36082 36083 // cacheLengths must be recalculated. 36084 updateArcLengths() { 36085 36086 this.needsUpdate = true; 36087 this.cacheLengths = null; 36088 this.getCurveLengths(); 36089 36090 } 36091 36092 // Compute lengths and cache them 36093 // We cannot overwrite getLengths() because UtoT mapping uses it. 36094 36095 getCurveLengths() { 36096 36097 // We use cache values if curves and cache array are same length 36098 36099 if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) { 36100 36101 return this.cacheLengths; 36102 36103 } 36104 36105 // Get length of sub-curve 36106 // Push sums into cached array 36107 36108 const lengths = []; 36109 let sums = 0; 36110 36111 for ( let i = 0, l = this.curves.length; i < l; i ++ ) { 36112 36113 sums += this.curves[ i ].getLength(); 36114 lengths.push( sums ); 36115 36116 } 36117 36118 this.cacheLengths = lengths; 36119 36120 return lengths; 36121 36122 } 36123 36124 getSpacedPoints( divisions = 40 ) { 36125 36126 const points = []; 36127 36128 for ( let i = 0; i <= divisions; i ++ ) { 36129 36130 points.push( this.getPoint( i / divisions ) ); 36131 36132 } 36133 36134 if ( this.autoClose ) { 36135 36136 points.push( points[ 0 ] ); 36137 36138 } 36139 36140 return points; 36141 36142 } 36143 36144 getPoints( divisions = 12 ) { 36145 36146 const points = []; 36147 let last; 36148 36149 for ( let i = 0, curves = this.curves; i < curves.length; i ++ ) { 36150 36151 const curve = curves[ i ]; 36152 const resolution = curve.isEllipseCurve ? divisions * 2 36153 : ( curve.isLineCurve || curve.isLineCurve3 ) ? 1 36154 : curve.isSplineCurve ? divisions * curve.points.length 36155 : divisions; 36156 36157 const pts = curve.getPoints( resolution ); 36158 36159 for ( let j = 0; j < pts.length; j ++ ) { 36160 36161 const point = pts[ j ]; 36162 36163 if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates 36164 36165 points.push( point ); 36166 last = point; 36167 36168 } 36169 36170 } 36171 36172 if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) { 36173 36174 points.push( points[ 0 ] ); 36175 36176 } 36177 36178 return points; 36179 36180 } 36181 36182 copy( source ) { 36183 36184 super.copy( source ); 36185 36186 this.curves = []; 36187 36188 for ( let i = 0, l = source.curves.length; i < l; i ++ ) { 36189 36190 const curve = source.curves[ i ]; 36191 36192 this.curves.push( curve.clone() ); 36193 36194 } 36195 36196 this.autoClose = source.autoClose; 36197 36198 return this; 36199 36200 } 36201 36202 toJSON() { 36203 36204 const data = super.toJSON(); 36205 36206 data.autoClose = this.autoClose; 36207 data.curves = []; 36208 36209 for ( let i = 0, l = this.curves.length; i < l; i ++ ) { 36210 36211 const curve = this.curves[ i ]; 36212 data.curves.push( curve.toJSON() ); 36213 36214 } 36215 36216 return data; 36217 36218 } 36219 36220 fromJSON( json ) { 36221 36222 super.fromJSON( json ); 36223 36224 this.autoClose = json.autoClose; 36225 this.curves = []; 36226 36227 for ( let i = 0, l = json.curves.length; i < l; i ++ ) { 36228 36229 const curve = json.curves[ i ]; 36230 this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) ); 36231 36232 } 36233 36234 return this; 36235 36236 } 36237 36238} 36239 36240class Path extends CurvePath { 36241 36242 constructor( points ) { 36243 36244 super(); 36245 36246 this.type = 'Path'; 36247 36248 this.currentPoint = new Vector2(); 36249 36250 if ( points ) { 36251 36252 this.setFromPoints( points ); 36253 36254 } 36255 36256 } 36257 36258 setFromPoints( points ) { 36259 36260 this.moveTo( points[ 0 ].x, points[ 0 ].y ); 36261 36262 for ( let i = 1, l = points.length; i < l; i ++ ) { 36263 36264 this.lineTo( points[ i ].x, points[ i ].y ); 36265 36266 } 36267 36268 return this; 36269 36270 } 36271 36272 moveTo( x, y ) { 36273 36274 this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? 36275 36276 return this; 36277 36278 } 36279 36280 lineTo( x, y ) { 36281 36282 const curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); 36283 this.curves.push( curve ); 36284 36285 this.currentPoint.set( x, y ); 36286 36287 return this; 36288 36289 } 36290 36291 quadraticCurveTo( aCPx, aCPy, aX, aY ) { 36292 36293 const curve = new QuadraticBezierCurve( 36294 this.currentPoint.clone(), 36295 new Vector2( aCPx, aCPy ), 36296 new Vector2( aX, aY ) 36297 ); 36298 36299 this.curves.push( curve ); 36300 36301 this.currentPoint.set( aX, aY ); 36302 36303 return this; 36304 36305 } 36306 36307 bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { 36308 36309 const curve = new CubicBezierCurve( 36310 this.currentPoint.clone(), 36311 new Vector2( aCP1x, aCP1y ), 36312 new Vector2( aCP2x, aCP2y ), 36313 new Vector2( aX, aY ) 36314 ); 36315 36316 this.curves.push( curve ); 36317 36318 this.currentPoint.set( aX, aY ); 36319 36320 return this; 36321 36322 } 36323 36324 splineThru( pts /*Array of Vector*/ ) { 36325 36326 const npts = [ this.currentPoint.clone() ].concat( pts ); 36327 36328 const curve = new SplineCurve( npts ); 36329 this.curves.push( curve ); 36330 36331 this.currentPoint.copy( pts[ pts.length - 1 ] ); 36332 36333 return this; 36334 36335 } 36336 36337 arc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { 36338 36339 const x0 = this.currentPoint.x; 36340 const y0 = this.currentPoint.y; 36341 36342 this.absarc( aX + x0, aY + y0, aRadius, 36343 aStartAngle, aEndAngle, aClockwise ); 36344 36345 return this; 36346 36347 } 36348 36349 absarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { 36350 36351 this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); 36352 36353 return this; 36354 36355 } 36356 36357 ellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { 36358 36359 const x0 = this.currentPoint.x; 36360 const y0 = this.currentPoint.y; 36361 36362 this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); 36363 36364 return this; 36365 36366 } 36367 36368 absellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { 36369 36370 const curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); 36371 36372 if ( this.curves.length > 0 ) { 36373 36374 // if a previous curve is present, attempt to join 36375 const firstPoint = curve.getPoint( 0 ); 36376 36377 if ( ! firstPoint.equals( this.currentPoint ) ) { 36378 36379 this.lineTo( firstPoint.x, firstPoint.y ); 36380 36381 } 36382 36383 } 36384 36385 this.curves.push( curve ); 36386 36387 const lastPoint = curve.getPoint( 1 ); 36388 this.currentPoint.copy( lastPoint ); 36389 36390 return this; 36391 36392 } 36393 36394 copy( source ) { 36395 36396 super.copy( source ); 36397 36398 this.currentPoint.copy( source.currentPoint ); 36399 36400 return this; 36401 36402 } 36403 36404 toJSON() { 36405 36406 const data = super.toJSON(); 36407 36408 data.currentPoint = this.currentPoint.toArray(); 36409 36410 return data; 36411 36412 } 36413 36414 fromJSON( json ) { 36415 36416 super.fromJSON( json ); 36417 36418 this.currentPoint.fromArray( json.currentPoint ); 36419 36420 return this; 36421 36422 } 36423 36424} 36425 36426class LatheGeometry extends BufferGeometry { 36427 36428 constructor( points = [ new Vector2( 0, - 0.5 ), new Vector2( 0.5, 0 ), new Vector2( 0, 0.5 ) ], segments = 12, phiStart = 0, phiLength = Math.PI * 2 ) { 36429 36430 super(); 36431 36432 this.type = 'LatheGeometry'; 36433 36434 this.parameters = { 36435 points: points, 36436 segments: segments, 36437 phiStart: phiStart, 36438 phiLength: phiLength 36439 }; 36440 36441 segments = Math.floor( segments ); 36442 36443 // clamp phiLength so it's in range of [ 0, 2PI ] 36444 36445 phiLength = clamp( phiLength, 0, Math.PI * 2 ); 36446 36447 // buffers 36448 36449 const indices = []; 36450 const vertices = []; 36451 const uvs = []; 36452 const initNormals = []; 36453 const normals = []; 36454 36455 // helper variables 36456 36457 const inverseSegments = 1.0 / segments; 36458 const vertex = new Vector3(); 36459 const uv = new Vector2(); 36460 const normal = new Vector3(); 36461 const curNormal = new Vector3(); 36462 const prevNormal = new Vector3(); 36463 let dx = 0; 36464 let dy = 0; 36465 36466 // pre-compute normals for initial "meridian" 36467 36468 for ( let j = 0; j <= ( points.length - 1 ); j ++ ) { 36469 36470 switch ( j ) { 36471 36472 case 0: // special handling for 1st vertex on path 36473 36474 dx = points[ j + 1 ].x - points[ j ].x; 36475 dy = points[ j + 1 ].y - points[ j ].y; 36476 36477 normal.x = dy * 1.0; 36478 normal.y = - dx; 36479 normal.z = dy * 0.0; 36480 36481 prevNormal.copy( normal ); 36482 36483 normal.normalize(); 36484 36485 initNormals.push( normal.x, normal.y, normal.z ); 36486 36487 break; 36488 36489 case ( points.length - 1 ): // special handling for last Vertex on path 36490 36491 initNormals.push( prevNormal.x, prevNormal.y, prevNormal.z ); 36492 36493 break; 36494 36495 default: // default handling for all vertices in between 36496 36497 dx = points[ j + 1 ].x - points[ j ].x; 36498 dy = points[ j + 1 ].y - points[ j ].y; 36499 36500 normal.x = dy * 1.0; 36501 normal.y = - dx; 36502 normal.z = dy * 0.0; 36503 36504 curNormal.copy( normal ); 36505 36506 normal.x += prevNormal.x; 36507 normal.y += prevNormal.y; 36508 normal.z += prevNormal.z; 36509 36510 normal.normalize(); 36511 36512 initNormals.push( normal.x, normal.y, normal.z ); 36513 36514 prevNormal.copy( curNormal ); 36515 36516 } 36517 36518 } 36519 36520 // generate vertices, uvs and normals 36521 36522 for ( let i = 0; i <= segments; i ++ ) { 36523 36524 const phi = phiStart + i * inverseSegments * phiLength; 36525 36526 const sin = Math.sin( phi ); 36527 const cos = Math.cos( phi ); 36528 36529 for ( let j = 0; j <= ( points.length - 1 ); j ++ ) { 36530 36531 // vertex 36532 36533 vertex.x = points[ j ].x * sin; 36534 vertex.y = points[ j ].y; 36535 vertex.z = points[ j ].x * cos; 36536 36537 vertices.push( vertex.x, vertex.y, vertex.z ); 36538 36539 // uv 36540 36541 uv.x = i / segments; 36542 uv.y = j / ( points.length - 1 ); 36543 36544 uvs.push( uv.x, uv.y ); 36545 36546 // normal 36547 36548 const x = initNormals[ 3 * j + 0 ] * sin; 36549 const y = initNormals[ 3 * j + 1 ]; 36550 const z = initNormals[ 3 * j + 0 ] * cos; 36551 36552 normals.push( x, y, z ); 36553 36554 } 36555 36556 } 36557 36558 // indices 36559 36560 for ( let i = 0; i < segments; i ++ ) { 36561 36562 for ( let j = 0; j < ( points.length - 1 ); j ++ ) { 36563 36564 const base = j + i * points.length; 36565 36566 const a = base; 36567 const b = base + points.length; 36568 const c = base + points.length + 1; 36569 const d = base + 1; 36570 36571 // faces 36572 36573 indices.push( a, b, d ); 36574 indices.push( c, d, b ); 36575 36576 } 36577 36578 } 36579 36580 // build geometry 36581 36582 this.setIndex( indices ); 36583 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 36584 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 36585 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 36586 36587 } 36588 36589 copy( source ) { 36590 36591 super.copy( source ); 36592 36593 this.parameters = Object.assign( {}, source.parameters ); 36594 36595 return this; 36596 36597 } 36598 36599 static fromJSON( data ) { 36600 36601 return new LatheGeometry( data.points, data.segments, data.phiStart, data.phiLength ); 36602 36603 } 36604 36605} 36606 36607class CapsuleGeometry extends LatheGeometry { 36608 36609 constructor( radius = 1, length = 1, capSegments = 4, radialSegments = 8 ) { 36610 36611 const path = new Path(); 36612 path.absarc( 0, - length / 2, radius, Math.PI * 1.5, 0 ); 36613 path.absarc( 0, length / 2, radius, 0, Math.PI * 0.5 ); 36614 36615 super( path.getPoints( capSegments ), radialSegments ); 36616 36617 this.type = 'CapsuleGeometry'; 36618 36619 this.parameters = { 36620 radius: radius, 36621 length: length, 36622 capSegments: capSegments, 36623 radialSegments: radialSegments, 36624 }; 36625 36626 } 36627 36628 static fromJSON( data ) { 36629 36630 return new CapsuleGeometry( data.radius, data.length, data.capSegments, data.radialSegments ); 36631 36632 } 36633 36634} 36635 36636class CircleGeometry extends BufferGeometry { 36637 36638 constructor( radius = 1, segments = 32, thetaStart = 0, thetaLength = Math.PI * 2 ) { 36639 36640 super(); 36641 36642 this.type = 'CircleGeometry'; 36643 36644 this.parameters = { 36645 radius: radius, 36646 segments: segments, 36647 thetaStart: thetaStart, 36648 thetaLength: thetaLength 36649 }; 36650 36651 segments = Math.max( 3, segments ); 36652 36653 // buffers 36654 36655 const indices = []; 36656 const vertices = []; 36657 const normals = []; 36658 const uvs = []; 36659 36660 // helper variables 36661 36662 const vertex = new Vector3(); 36663 const uv = new Vector2(); 36664 36665 // center point 36666 36667 vertices.push( 0, 0, 0 ); 36668 normals.push( 0, 0, 1 ); 36669 uvs.push( 0.5, 0.5 ); 36670 36671 for ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) { 36672 36673 const segment = thetaStart + s / segments * thetaLength; 36674 36675 // vertex 36676 36677 vertex.x = radius * Math.cos( segment ); 36678 vertex.y = radius * Math.sin( segment ); 36679 36680 vertices.push( vertex.x, vertex.y, vertex.z ); 36681 36682 // normal 36683 36684 normals.push( 0, 0, 1 ); 36685 36686 // uvs 36687 36688 uv.x = ( vertices[ i ] / radius + 1 ) / 2; 36689 uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2; 36690 36691 uvs.push( uv.x, uv.y ); 36692 36693 } 36694 36695 // indices 36696 36697 for ( let i = 1; i <= segments; i ++ ) { 36698 36699 indices.push( i, i + 1, 0 ); 36700 36701 } 36702 36703 // build geometry 36704 36705 this.setIndex( indices ); 36706 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 36707 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 36708 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 36709 36710 } 36711 36712 copy( source ) { 36713 36714 super.copy( source ); 36715 36716 this.parameters = Object.assign( {}, source.parameters ); 36717 36718 return this; 36719 36720 } 36721 36722 static fromJSON( data ) { 36723 36724 return new CircleGeometry( data.radius, data.segments, data.thetaStart, data.thetaLength ); 36725 36726 } 36727 36728} 36729 36730class CylinderGeometry extends BufferGeometry { 36731 36732 constructor( radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) { 36733 36734 super(); 36735 36736 this.type = 'CylinderGeometry'; 36737 36738 this.parameters = { 36739 radiusTop: radiusTop,
vendor: 4,238 bytes, lines 36740-36932
36740 radiusBottom: radiusBottom, 36741 height: height, 36742 radialSegments: radialSegments, 36743 heightSegments: heightSegments, 36744 openEnded: openEnded, 36745 thetaStart: thetaStart, 36746 thetaLength: thetaLength 36747 }; 36748 36749 const scope = this; 36750 36751 radialSegments = Math.floor( radialSegments ); 36752 heightSegments = Math.floor( heightSegments ); 36753 36754 // buffers 36755 36756 const indices = []; 36757 const vertices = []; 36758 const normals = []; 36759 const uvs = []; 36760 36761 // helper variables 36762 36763 let index = 0; 36764 const indexArray = []; 36765 const halfHeight = height / 2; 36766 let groupStart = 0; 36767 36768 // generate geometry 36769 36770 generateTorso(); 36771 36772 if ( openEnded === false ) { 36773 36774 if ( radiusTop > 0 ) generateCap( true ); 36775 if ( radiusBottom > 0 ) generateCap( false ); 36776 36777 } 36778 36779 // build geometry 36780 36781 this.setIndex( indices ); 36782 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 36783 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 36784 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 36785 36786 function generateTorso() { 36787 36788 const normal = new Vector3(); 36789 const vertex = new Vector3(); 36790 36791 let groupCount = 0; 36792 36793 // this will be used to calculate the normal 36794 const slope = ( radiusBottom - radiusTop ) / height; 36795 36796 // generate vertices, normals and uvs 36797 36798 for ( let y = 0; y <= heightSegments; y ++ ) { 36799 36800 const indexRow = []; 36801 36802 const v = y / heightSegments; 36803 36804 // calculate the radius of the current row 36805 36806 const radius = v * ( radiusBottom - radiusTop ) + radiusTop; 36807 36808 for ( let x = 0; x <= radialSegments; x ++ ) { 36809 36810 const u = x / radialSegments; 36811 36812 const theta = u * thetaLength + thetaStart; 36813 36814 const sinTheta = Math.sin( theta ); 36815 const cosTheta = Math.cos( theta ); 36816 36817 // vertex 36818 36819 vertex.x = radius * sinTheta; 36820 vertex.y = - v * height + halfHeight; 36821 vertex.z = radius * cosTheta; 36822 vertices.push( vertex.x, vertex.y, vertex.z ); 36823 36824 // normal 36825 36826 normal.set( sinTheta, slope, cosTheta ).normalize(); 36827 normals.push( normal.x, normal.y, normal.z ); 36828 36829 // uv 36830 36831 uvs.push( u, 1 - v ); 36832 36833 // save index of vertex in respective row 36834 36835 indexRow.push( index ++ ); 36836 36837 } 36838 36839 // now save vertices of the row in our index array 36840 36841 indexArray.push( indexRow ); 36842 36843 } 36844 36845 // generate indices 36846 36847 for ( let x = 0; x < radialSegments; x ++ ) { 36848 36849 for ( let y = 0; y < heightSegments; y ++ ) { 36850 36851 // we use the index array to access the correct indices 36852 36853 const a = indexArray[ y ][ x ]; 36854 const b = indexArray[ y + 1 ][ x ]; 36855 const c = indexArray[ y + 1 ][ x + 1 ]; 36856 const d = indexArray[ y ][ x + 1 ]; 36857 36858 // faces 36859 36860 indices.push( a, b, d ); 36861 indices.push( b, c, d ); 36862 36863 // update group counter 36864 36865 groupCount += 6; 36866 36867 } 36868 36869 } 36870 36871 // add a group to the geometry. this will ensure multi material support 36872 36873 scope.addGroup( groupStart, groupCount, 0 ); 36874 36875 // calculate new start value for groups 36876 36877 groupStart += groupCount; 36878 36879 } 36880 36881 function generateCap( top ) { 36882 36883 // save the index of the first center vertex 36884 const centerIndexStart = index; 36885 36886 const uv = new Vector2(); 36887 const vertex = new Vector3(); 36888 36889 let groupCount = 0; 36890 36891 const radius = ( top === true ) ? radiusTop : radiusBottom; 36892 const sign = ( top === true ) ? 1 : - 1; 36893 36894 // first we generate the center vertex data of the cap. 36895 // because the geometry needs one set of uvs per face, 36896 // we must generate a center vertex per face/segment 36897 36898 for ( let x = 1; x <= radialSegments; x ++ ) { 36899 36900 // vertex 36901 36902 vertices.push( 0, halfHeight * sign, 0 ); 36903 36904 // normal 36905 36906 normals.push( 0, sign, 0 ); 36907 36908 // uv 36909 36910 uvs.push( 0.5, 0.5 ); 36911 36912 // increase index 36913 36914 index ++; 36915 36916 } 36917 36918 // save the index of the last center vertex 36919 const centerIndexEnd = index; 36920 36921 // now we generate the surrounding vertices, normals and uvs 36922 36923 for ( let x = 0; x <= radialSegments; x ++ ) { 36924 36925 const u = x / radialSegments; 36926 const theta = u * thetaLength + thetaStart; 36927 36928 const cosTheta = Math.cos( theta ); 36929 const sinTheta = Math.sin( theta ); 36930 36931 // vertex 36932
vendor: 16,849 bytes, lines 36933-37712
36933 vertex.x = radius * sinTheta; 36934 vertex.y = halfHeight * sign; 36935 vertex.z = radius * cosTheta; 36936 vertices.push( vertex.x, vertex.y, vertex.z ); 36937 36938 // normal 36939 36940 normals.push( 0, sign, 0 ); 36941 36942 // uv 36943 36944 uv.x = ( cosTheta * 0.5 ) + 0.5; 36945 uv.y = ( sinTheta * 0.5 * sign ) + 0.5; 36946 uvs.push( uv.x, uv.y ); 36947 36948 // increase index 36949 36950 index ++; 36951 36952 } 36953 36954 // generate indices 36955 36956 for ( let x = 0; x < radialSegments; x ++ ) { 36957 36958 const c = centerIndexStart + x; 36959 const i = centerIndexEnd + x; 36960 36961 if ( top === true ) { 36962 36963 // face top 36964 36965 indices.push( i, i + 1, c ); 36966 36967 } else { 36968 36969 // face bottom 36970 36971 indices.push( i + 1, i, c ); 36972 36973 } 36974 36975 groupCount += 3; 36976 36977 } 36978 36979 // add a group to the geometry. this will ensure multi material support 36980 36981 scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 ); 36982 36983 // calculate new start value for groups 36984 36985 groupStart += groupCount; 36986 36987 } 36988 36989 } 36990 36991 copy( source ) { 36992 36993 super.copy( source ); 36994 36995 this.parameters = Object.assign( {}, source.parameters ); 36996 36997 return this; 36998 36999 } 37000 37001 static fromJSON( data ) { 37002 37003 return new CylinderGeometry( data.radiusTop, data.radiusBottom, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ); 37004 37005 } 37006 37007} 37008 37009class ConeGeometry extends CylinderGeometry { 37010 37011 constructor( radius = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) { 37012 37013 super( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); 37014 37015 this.type = 'ConeGeometry'; 37016 37017 this.parameters = { 37018 radius: radius, 37019 height: height, 37020 radialSegments: radialSegments, 37021 heightSegments: heightSegments, 37022 openEnded: openEnded, 37023 thetaStart: thetaStart, 37024 thetaLength: thetaLength 37025 }; 37026 37027 } 37028 37029 static fromJSON( data ) { 37030 37031 return new ConeGeometry( data.radius, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ); 37032 37033 } 37034 37035} 37036 37037class PolyhedronGeometry extends BufferGeometry { 37038 37039 constructor( vertices = [], indices = [], radius = 1, detail = 0 ) { 37040 37041 super(); 37042 37043 this.type = 'PolyhedronGeometry'; 37044 37045 this.parameters = { 37046 vertices: vertices, 37047 indices: indices, 37048 radius: radius, 37049 detail: detail 37050 }; 37051 37052 // default buffer data 37053 37054 const vertexBuffer = []; 37055 const uvBuffer = []; 37056 37057 // the subdivision creates the vertex buffer data 37058 37059 subdivide( detail ); 37060 37061 // all vertices should lie on a conceptual sphere with a given radius 37062 37063 applyRadius( radius ); 37064 37065 // finally, create the uv data 37066 37067 generateUVs(); 37068 37069 // build non-indexed geometry 37070 37071 this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) ); 37072 this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) ); 37073 this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) ); 37074 37075 if ( detail === 0 ) { 37076 37077 this.computeVertexNormals(); // flat normals 37078 37079 } else { 37080 37081 this.normalizeNormals(); // smooth normals 37082 37083 } 37084 37085 // helper functions 37086 37087 function subdivide( detail ) { 37088 37089 const a = new Vector3(); 37090 const b = new Vector3(); 37091 const c = new Vector3(); 37092 37093 // iterate over all faces and apply a subdivision with the given detail value 37094 37095 for ( let i = 0; i < indices.length; i += 3 ) { 37096 37097 // get the vertices of the face 37098 37099 getVertexByIndex( indices[ i + 0 ], a ); 37100 getVertexByIndex( indices[ i + 1 ], b ); 37101 getVertexByIndex( indices[ i + 2 ], c ); 37102 37103 // perform subdivision 37104 37105 subdivideFace( a, b, c, detail ); 37106 37107 } 37108 37109 } 37110 37111 function subdivideFace( a, b, c, detail ) { 37112 37113 const cols = detail + 1; 37114 37115 // we use this multidimensional array as a data structure for creating the subdivision 37116 37117 const v = []; 37118 37119 // construct all of the vertices for this subdivision 37120 37121 for ( let i = 0; i <= cols; i ++ ) { 37122 37123 v[ i ] = []; 37124 37125 const aj = a.clone().lerp( c, i / cols ); 37126 const bj = b.clone().lerp( c, i / cols ); 37127 37128 const rows = cols - i; 37129 37130 for ( let j = 0; j <= rows; j ++ ) { 37131 37132 if ( j === 0 && i === cols ) { 37133 37134 v[ i ][ j ] = aj; 37135 37136 } else { 37137 37138 v[ i ][ j ] = aj.clone().lerp( bj, j / rows ); 37139 37140 } 37141 37142 } 37143 37144 } 37145 37146 // construct all of the faces 37147 37148 for ( let i = 0; i < cols; i ++ ) { 37149 37150 for ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) { 37151 37152 const k = Math.floor( j / 2 ); 37153 37154 if ( j % 2 === 0 ) { 37155 37156 pushVertex( v[ i ][ k + 1 ] ); 37157 pushVertex( v[ i + 1 ][ k ] ); 37158 pushVertex( v[ i ][ k ] ); 37159 37160 } else { 37161 37162 pushVertex( v[ i ][ k + 1 ] ); 37163 pushVertex( v[ i + 1 ][ k + 1 ] ); 37164 pushVertex( v[ i + 1 ][ k ] ); 37165 37166 } 37167 37168 } 37169 37170 } 37171 37172 } 37173 37174 function applyRadius( radius ) { 37175 37176 const vertex = new Vector3(); 37177 37178 // iterate over the entire buffer and apply the radius to each vertex 37179 37180 for ( let i = 0; i < vertexBuffer.length; i += 3 ) { 37181 37182 vertex.x = vertexBuffer[ i + 0 ]; 37183 vertex.y = vertexBuffer[ i + 1 ]; 37184 vertex.z = vertexBuffer[ i + 2 ]; 37185 37186 vertex.normalize().multiplyScalar( radius ); 37187 37188 vertexBuffer[ i + 0 ] = vertex.x; 37189 vertexBuffer[ i + 1 ] = vertex.y; 37190 vertexBuffer[ i + 2 ] = vertex.z; 37191 37192 } 37193 37194 } 37195 37196 function generateUVs() { 37197 37198 const vertex = new Vector3(); 37199 37200 for ( let i = 0; i < vertexBuffer.length; i += 3 ) { 37201 37202 vertex.x = vertexBuffer[ i + 0 ]; 37203 vertex.y = vertexBuffer[ i + 1 ]; 37204 vertex.z = vertexBuffer[ i + 2 ]; 37205 37206 const u = azimuth( vertex ) / 2 / Math.PI + 0.5; 37207 const v = inclination( vertex ) / Math.PI + 0.5; 37208 uvBuffer.push( u, 1 - v ); 37209 37210 } 37211 37212 correctUVs(); 37213 37214 correctSeam(); 37215 37216 } 37217 37218 function correctSeam() { 37219 37220 // handle case when face straddles the seam, see #3269 37221 37222 for ( let i = 0; i < uvBuffer.length; i += 6 ) { 37223 37224 // uv data of a single face 37225 37226 const x0 = uvBuffer[ i + 0 ]; 37227 const x1 = uvBuffer[ i + 2 ]; 37228 const x2 = uvBuffer[ i + 4 ]; 37229 37230 const max = Math.max( x0, x1, x2 ); 37231 const min = Math.min( x0, x1, x2 ); 37232 37233 // 0.9 is somewhat arbitrary 37234 37235 if ( max > 0.9 && min < 0.1 ) { 37236 37237 if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1; 37238 if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1; 37239 if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1; 37240 37241 } 37242 37243 } 37244 37245 } 37246 37247 function pushVertex( vertex ) { 37248 37249 vertexBuffer.push( vertex.x, vertex.y, vertex.z ); 37250 37251 } 37252 37253 function getVertexByIndex( index, vertex ) { 37254 37255 const stride = index * 3; 37256 37257 vertex.x = vertices[ stride + 0 ]; 37258 vertex.y = vertices[ stride + 1 ]; 37259 vertex.z = vertices[ stride + 2 ]; 37260 37261 } 37262 37263 function correctUVs() { 37264 37265 const a = new Vector3(); 37266 const b = new Vector3(); 37267 const c = new Vector3(); 37268 37269 const centroid = new Vector3(); 37270 37271 const uvA = new Vector2(); 37272 const uvB = new Vector2(); 37273 const uvC = new Vector2(); 37274 37275 for ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) { 37276 37277 a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] ); 37278 b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] ); 37279 c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] ); 37280 37281 uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] ); 37282 uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] ); 37283 uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] ); 37284 37285 centroid.copy( a ).add( b ).add( c ).divideScalar( 3 ); 37286 37287 const azi = azimuth( centroid ); 37288 37289 correctUV( uvA, j + 0, a, azi ); 37290 correctUV( uvB, j + 2, b, azi ); 37291 correctUV( uvC, j + 4, c, azi ); 37292 37293 } 37294 37295 } 37296 37297 function correctUV( uv, stride, vector, azimuth ) { 37298 37299 if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) { 37300 37301 uvBuffer[ stride ] = uv.x - 1; 37302 37303 } 37304 37305 if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) { 37306 37307 uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5; 37308 37309 } 37310 37311 } 37312 37313 // Angle around the Y axis, counter-clockwise when looking from above. 37314 37315 function azimuth( vector ) { 37316 37317 return Math.atan2( vector.z, - vector.x ); 37318 37319 } 37320 37321 37322 // Angle above the XZ plane. 37323 37324 function inclination( vector ) { 37325 37326 return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); 37327 37328 } 37329 37330 } 37331 37332 copy( source ) { 37333 37334 super.copy( source ); 37335 37336 this.parameters = Object.assign( {}, source.parameters ); 37337 37338 return this; 37339 37340 } 37341 37342 static fromJSON( data ) { 37343 37344 return new PolyhedronGeometry( data.vertices, data.indices, data.radius, data.details ); 37345 37346 } 37347 37348} 37349 37350class DodecahedronGeometry extends PolyhedronGeometry { 37351 37352 constructor( radius = 1, detail = 0 ) { 37353 37354 const t = ( 1 + Math.sqrt( 5 ) ) / 2; 37355 const r = 1 / t; 37356 37357 const vertices = [ 37358 37359 // (±1, ±1, ±1) 37360 - 1, - 1, - 1, - 1, - 1, 1, 37361 - 1, 1, - 1, - 1, 1, 1, 37362 1, - 1, - 1, 1, - 1, 1, 37363 1, 1, - 1, 1, 1, 1, 37364 37365 // (0, ±1/Ï, ±Ï) 37366 0, - r, - t, 0, - r, t, 37367 0, r, - t, 0, r, t, 37368 37369 // (±1/Ï, ±Ï, 0) 37370 - r, - t, 0, - r, t, 0, 37371 r, - t, 0, r, t, 0, 37372 37373 // (±Ï, 0, ±1/Ï) 37374 - t, 0, - r, t, 0, - r, 37375 - t, 0, r, t, 0, r 37376 ]; 37377 37378 const indices = [ 37379 3, 11, 7, 3, 7, 15, 3, 15, 13, 37380 7, 19, 17, 7, 17, 6, 7, 6, 15, 37381 17, 4, 8, 17, 8, 10, 17, 10, 6, 37382 8, 0, 16, 8, 16, 2, 8, 2, 10, 37383 0, 12, 1, 0, 1, 18, 0, 18, 16, 37384 6, 10, 2, 6, 2, 13, 6, 13, 15, 37385 2, 16, 18, 2, 18, 3, 2, 3, 13, 37386 18, 1, 9, 18, 9, 11, 18, 11, 3, 37387 4, 14, 12, 4, 12, 0, 4, 0, 8, 37388 11, 9, 5, 11, 5, 19, 11, 19, 7, 37389 19, 5, 14, 19, 14, 4, 19, 4, 17, 37390 1, 12, 14, 1, 14, 5, 1, 5, 9 37391 ]; 37392 37393 super( vertices, indices, radius, detail ); 37394 37395 this.type = 'DodecahedronGeometry'; 37396 37397 this.parameters = { 37398 radius: radius, 37399 detail: detail 37400 }; 37401 37402 } 37403 37404 static fromJSON( data ) { 37405 37406 return new DodecahedronGeometry( data.radius, data.detail ); 37407 37408 } 37409 37410} 37411 37412const _v0 = /*@__PURE__*/ new Vector3(); 37413const _v1$1 = /*@__PURE__*/ new Vector3(); 37414const _normal = /*@__PURE__*/ new Vector3(); 37415const _triangle = /*@__PURE__*/ new Triangle(); 37416 37417class EdgesGeometry extends BufferGeometry { 37418 37419 constructor( geometry = null, thresholdAngle = 1 ) { 37420 37421 super(); 37422 37423 this.type = 'EdgesGeometry'; 37424 37425 this.parameters = { 37426 geometry: geometry, 37427 thresholdAngle: thresholdAngle 37428 }; 37429 37430 if ( geometry !== null ) { 37431 37432 const precisionPoints = 4; 37433 const precision = Math.pow( 10, precisionPoints ); 37434 const thresholdDot = Math.cos( DEG2RAD * thresholdAngle ); 37435 37436 const indexAttr = geometry.getIndex(); 37437 const positionAttr = geometry.getAttribute( 'position' ); 37438 const indexCount = indexAttr ? indexAttr.count : positionAttr.count; 37439 37440 const indexArr = [ 0, 0, 0 ]; 37441 const vertKeys = [ 'a', 'b', 'c' ]; 37442 const hashes = new Array( 3 ); 37443 37444 const edgeData = {}; 37445 const vertices = []; 37446 for ( let i = 0; i < indexCount; i += 3 ) { 37447 37448 if ( indexAttr ) { 37449 37450 indexArr[ 0 ] = indexAttr.getX( i ); 37451 indexArr[ 1 ] = indexAttr.getX( i + 1 ); 37452 indexArr[ 2 ] = indexAttr.getX( i + 2 ); 37453 37454 } else { 37455 37456 indexArr[ 0 ] = i; 37457 indexArr[ 1 ] = i + 1; 37458 indexArr[ 2 ] = i + 2; 37459 37460 } 37461 37462 const { a, b, c } = _triangle; 37463 a.fromBufferAttribute( positionAttr, indexArr[ 0 ] ); 37464 b.fromBufferAttribute( positionAttr, indexArr[ 1 ] ); 37465 c.fromBufferAttribute( positionAttr, indexArr[ 2 ] ); 37466 _triangle.getNormal( _normal ); 37467 37468 // create hashes for the edge from the vertices 37469 hashes[ 0 ] = `${ Math.round( a.x * precision ) },${ Math.round( a.y * precision ) },${ Math.round( a.z * precision ) }`; 37470 hashes[ 1 ] = `${ Math.round( b.x * precision ) },${ Math.round( b.y * precision ) },${ Math.round( b.z * precision ) }`; 37471 hashes[ 2 ] = `${ Math.round( c.x * precision ) },${ Math.round( c.y * precision ) },${ Math.round( c.z * precision ) }`; 37472 37473 // skip degenerate triangles 37474 if ( hashes[ 0 ] === hashes[ 1 ] || hashes[ 1 ] === hashes[ 2 ] || hashes[ 2 ] === hashes[ 0 ] ) { 37475 37476 continue; 37477 37478 } 37479 37480 // iterate over every edge 37481 for ( let j = 0; j < 3; j ++ ) { 37482 37483 // get the first and next vertex making up the edge 37484 const jNext = ( j + 1 ) % 3; 37485 const vecHash0 = hashes[ j ]; 37486 const vecHash1 = hashes[ jNext ]; 37487 const v0 = _triangle[ vertKeys[ j ] ]; 37488 const v1 = _triangle[ vertKeys[ jNext ] ]; 37489 37490 const hash = `${ vecHash0 }_${ vecHash1 }`; 37491 const reverseHash = `${ vecHash1 }_${ vecHash0 }`; 37492 37493 if ( reverseHash in edgeData && edgeData[ reverseHash ] ) { 37494 37495 // if we found a sibling edge add it into the vertex array if 37496 // it meets the angle threshold and delete the edge from the map. 37497 if ( _normal.dot( edgeData[ reverseHash ].normal ) <= thresholdDot ) { 37498 37499 vertices.push( v0.x, v0.y, v0.z ); 37500 vertices.push( v1.x, v1.y, v1.z ); 37501 37502 } 37503 37504 edgeData[ reverseHash ] = null; 37505 37506 } else if ( ! ( hash in edgeData ) ) { 37507 37508 // if we've already got an edge here then skip adding a new one 37509 edgeData[ hash ] = { 37510 37511 index0: indexArr[ j ], 37512 index1: indexArr[ jNext ], 37513 normal: _normal.clone(), 37514 37515 }; 37516 37517 } 37518 37519 } 37520 37521 } 37522 37523 // iterate over all remaining, unmatched edges and add them to the vertex array 37524 for ( const key in edgeData ) { 37525 37526 if ( edgeData[ key ] ) { 37527 37528 const { index0, index1 } = edgeData[ key ]; 37529 _v0.fromBufferAttribute( positionAttr, index0 ); 37530 _v1$1.fromBufferAttribute( positionAttr, index1 ); 37531 37532 vertices.push( _v0.x, _v0.y, _v0.z ); 37533 vertices.push( _v1$1.x, _v1$1.y, _v1$1.z ); 37534 37535 } 37536 37537 } 37538 37539 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 37540 37541 } 37542 37543 } 37544 37545 copy( source ) { 37546 37547 super.copy( source ); 37548 37549 this.parameters = Object.assign( {}, source.parameters ); 37550 37551 return this; 37552 37553 } 37554 37555} 37556 37557class Shape extends Path { 37558 37559 constructor( points ) { 37560 37561 super( points ); 37562 37563 this.uuid = generateUUID(); 37564 37565 this.type = 'Shape'; 37566 37567 this.holes = []; 37568 37569 } 37570 37571 getPointsHoles( divisions ) { 37572 37573 const holesPts = []; 37574 37575 for ( let i = 0, l = this.holes.length; i < l; i ++ ) { 37576 37577 holesPts[ i ] = this.holes[ i ].getPoints( divisions ); 37578 37579 } 37580 37581 return holesPts; 37582 37583 } 37584 37585 // get points of shape and holes (keypoints based on segments parameter) 37586 37587 extractPoints( divisions ) { 37588 37589 return { 37590 37591 shape: this.getPoints( divisions ), 37592 holes: this.getPointsHoles( divisions ) 37593 37594 }; 37595 37596 } 37597 37598 copy( source ) { 37599 37600 super.copy( source ); 37601 37602 this.holes = []; 37603 37604 for ( let i = 0, l = source.holes.length; i < l; i ++ ) { 37605 37606 const hole = source.holes[ i ]; 37607 37608 this.holes.push( hole.clone() ); 37609 37610 } 37611 37612 return this; 37613 37614 } 37615 37616 toJSON() { 37617 37618 const data = super.toJSON(); 37619 37620 data.uuid = this.uuid; 37621 data.holes = []; 37622 37623 for ( let i = 0, l = this.holes.length; i < l; i ++ ) { 37624 37625 const hole = this.holes[ i ]; 37626 data.holes.push( hole.toJSON() ); 37627 37628 } 37629 37630 return data; 37631 37632 } 37633 37634 37635 fromJSON( json ) { 37636 37637 super.fromJSON( json ); 37638 37639 this.uuid = json.uuid; 37640 this.holes = []; 37641 37642 for ( let i = 0, l = json.holes.length; i < l; i ++ ) { 37643 37644 const hole = json.holes[ i ]; 37645 this.holes.push( new Path().fromJSON( hole ) ); 37646 37647 } 37648 37649 return this; 37650 37651 } 37652 37653} 37654 37655/** 37656 * Port from https://github.com/mapbox/earcut (v2.2.4) 37657 */ 37658 37659const Earcut = { 37660 37661 triangulate: function ( data, holeIndices, dim = 2 ) { 37662 37663 const hasHoles = holeIndices && holeIndices.length; 37664 const outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length; 37665 let outerNode = linkedList( data, 0, outerLen, dim, true ); 37666 const triangles = []; 37667 37668 if ( ! outerNode || outerNode.next === outerNode.prev ) return triangles; 37669 37670 let minX, minY, maxX, maxY, x, y, invSize; 37671 37672 if ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim ); 37673 37674 // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox 37675 if ( data.length > 80 * dim ) { 37676 37677 minX = maxX = data[ 0 ]; 37678 minY = maxY = data[ 1 ]; 37679 37680 for ( let i = dim; i < outerLen; i += dim ) { 37681 37682 x = data[ i ]; 37683 y = data[ i + 1 ]; 37684 if ( x < minX ) minX = x; 37685 if ( y < minY ) minY = y; 37686 if ( x > maxX ) maxX = x; 37687 if ( y > maxY ) maxY = y; 37688 37689 } 37690 37691 // minX, minY and invSize are later used to transform coords into integers for z-order calculation 37692 invSize = Math.max( maxX - minX, maxY - minY ); 37693 invSize = invSize !== 0 ? 32767 / invSize : 0; 37694 37695 } 37696 37697 earcutLinked( outerNode, triangles, dim, minX, minY, invSize, 0 ); 37698 37699 return triangles; 37700 37701 } 37702 37703}; 37704 37705// create a circular doubly linked list from polygon points in the specified winding order 37706function linkedList( data, start, end, dim, clockwise ) { 37707 37708 let i, last; 37709 37710 if ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) { 37711 37712 for ( i = start; i < end;
vendor: 13,306 bytes, lines 37712-38276
37712 i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); 37713 37714 } else { 37715 37716 for ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last ); 37717 37718 } 37719 37720 if ( last && equals( last, last.next ) ) { 37721 37722 removeNode( last ); 37723 last = last.next; 37724 37725 } 37726 37727 return last; 37728 37729} 37730 37731// eliminate colinear or duplicate points 37732function filterPoints( start, end ) { 37733 37734 if ( ! start ) return start; 37735 if ( ! end ) end = start; 37736 37737 let p = start, 37738 again; 37739 do { 37740 37741 again = false; 37742 37743 if ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) { 37744 37745 removeNode( p ); 37746 p = end = p.prev; 37747 if ( p === p.next ) break; 37748 again = true; 37749 37750 } else { 37751 37752 p = p.next; 37753 37754 } 37755 37756 } while ( again || p !== end ); 37757 37758 return end; 37759 37760} 37761 37762// main ear slicing loop which triangulates a polygon (given as a linked list) 37763function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) { 37764 37765 if ( ! ear ) return; 37766 37767 // interlink polygon nodes in z-order 37768 if ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize ); 37769 37770 let stop = ear, 37771 prev, next; 37772 37773 // iterate through ears, slicing them one by one 37774 while ( ear.prev !== ear.next ) { 37775 37776 prev = ear.prev; 37777 next = ear.next; 37778 37779 if ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) { 37780 37781 // cut off the triangle 37782 triangles.push( prev.i / dim | 0 ); 37783 triangles.push( ear.i / dim | 0 ); 37784 triangles.push( next.i / dim | 0 ); 37785 37786 removeNode( ear ); 37787 37788 // skipping the next vertex leads to less sliver triangles 37789 ear = next.next; 37790 stop = next.next; 37791 37792 continue; 37793 37794 } 37795 37796 ear = next; 37797 37798 // if we looped through the whole remaining polygon and can't find any more ears 37799 if ( ear === stop ) { 37800 37801 // try filtering points and slicing again 37802 if ( ! pass ) { 37803 37804 earcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 ); 37805 37806 // if this didn't work, try curing all small self-intersections locally 37807 37808 } else if ( pass === 1 ) { 37809 37810 ear = cureLocalIntersections( filterPoints( ear ), triangles, dim ); 37811 earcutLinked( ear, triangles, dim, minX, minY, invSize, 2 ); 37812 37813 // as a last resort, try splitting the remaining polygon into two 37814 37815 } else if ( pass === 2 ) { 37816 37817 splitEarcut( ear, triangles, dim, minX, minY, invSize ); 37818 37819 } 37820 37821 break; 37822 37823 } 37824 37825 } 37826 37827} 37828 37829// check whether a polygon node forms a valid ear with adjacent nodes 37830function isEar( ear ) { 37831 37832 const a = ear.prev, 37833 b = ear, 37834 c = ear.next; 37835 37836 if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear 37837 37838 // now make sure we don't have other points inside the potential ear 37839 const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y; 37840 37841 // triangle bbox; min & max are calculated like this for speed 37842 const x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ), 37843 y0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ), 37844 x1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ), 37845 y1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy ); 37846 37847 let p = c.next; 37848 while ( p !== a ) { 37849 37850 if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && 37851 pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && 37852 area( p.prev, p, p.next ) >= 0 ) return false; 37853 p = p.next; 37854 37855 } 37856 37857 return true; 37858 37859} 37860 37861function isEarHashed( ear, minX, minY, invSize ) { 37862 37863 const a = ear.prev, 37864 b = ear, 37865 c = ear.next; 37866 37867 if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear 37868 37869 const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y; 37870 37871 // triangle bbox; min & max are calculated like this for speed 37872 const x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ), 37873 y0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ), 37874 x1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ), 37875 y1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy ); 37876 37877 // z-order range for the current triangle bbox; 37878 const minZ = zOrder( x0, y0, minX, minY, invSize ), 37879 maxZ = zOrder( x1, y1, minX, minY, invSize ); 37880 37881 let p = ear.prevZ, 37882 n = ear.nextZ; 37883 37884 // look for points inside the triangle in both directions 37885 while ( p && p.z >= minZ && n && n.z <= maxZ ) { 37886 37887 if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && 37888 pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false; 37889 p = p.prevZ; 37890 37891 if ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && 37892 pointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false; 37893 n = n.nextZ; 37894 37895 } 37896 37897 // look for remaining points in decreasing z-order 37898 while ( p && p.z >= minZ ) { 37899 37900 if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && 37901 pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false; 37902 p = p.prevZ; 37903 37904 } 37905 37906 // look for remaining points in increasing z-order 37907 while ( n && n.z <= maxZ ) { 37908 37909 if ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && 37910 pointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false; 37911 n = n.nextZ; 37912 37913 } 37914 37915 return true; 37916 37917} 37918 37919// go through all polygon nodes and cure small local self-intersections 37920function cureLocalIntersections( start, triangles, dim ) { 37921 37922 let p = start; 37923 do { 37924 37925 const a = p.prev, 37926 b = p.next.next; 37927 37928 if ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) { 37929 37930 triangles.push( a.i / dim | 0 ); 37931 triangles.push( p.i / dim | 0 ); 37932 triangles.push( b.i / dim | 0 ); 37933 37934 // remove two nodes involved 37935 removeNode( p ); 37936 removeNode( p.next ); 37937 37938 p = start = b; 37939 37940 } 37941 37942 p = p.next; 37943 37944 } while ( p !== start ); 37945 37946 return filterPoints( p ); 37947 37948} 37949 37950// try splitting polygon into two and triangulate them independently 37951function splitEarcut( start, triangles, dim, minX, minY, invSize ) { 37952 37953 // look for a valid diagonal that divides the polygon into two 37954 let a = start; 37955 do { 37956 37957 let b = a.next.next; 37958 while ( b !== a.prev ) { 37959 37960 if ( a.i !== b.i && isValidDiagonal( a, b ) ) { 37961 37962 // split the polygon in two by the diagonal 37963 let c = splitPolygon( a, b ); 37964 37965 // filter colinear points around the cuts 37966 a = filterPoints( a, a.next ); 37967 c = filterPoints( c, c.next ); 37968 37969 // run earcut on each half 37970 earcutLinked( a, triangles, dim, minX, minY, invSize, 0 ); 37971 earcutLinked( c, triangles, dim, minX, minY, invSize, 0 ); 37972 return; 37973 37974 } 37975 37976 b = b.next; 37977 37978 } 37979 37980 a = a.next; 37981 37982 } while ( a !== start ); 37983 37984} 37985 37986// link every hole into the outer loop, producing a single-ring polygon without holes 37987function eliminateHoles( data, holeIndices, outerNode, dim ) { 37988 37989 const queue = []; 37990 let i, len, start, end, list; 37991 37992 for ( i = 0, len = holeIndices.length; i < len; i ++ ) { 37993 37994 start = holeIndices[ i ] * dim; 37995 end = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length; 37996 list = linkedList( data, start, end, dim, false ); 37997 if ( list === list.next ) list.steiner = true; 37998 queue.push( getLeftmost( list ) ); 37999 38000 } 38001 38002 queue.sort( compareX ); 38003 38004 // process holes from left to right 38005 for ( i = 0; i < queue.length; i ++ ) { 38006 38007 outerNode = eliminateHole( queue[ i ], outerNode ); 38008 38009 } 38010 38011 return outerNode; 38012 38013} 38014 38015function compareX( a, b ) { 38016 38017 return a.x - b.x; 38018 38019} 38020 38021// find a bridge between vertices that connects hole with an outer ring and link it 38022function eliminateHole( hole, outerNode ) { 38023 38024 const bridge = findHoleBridge( hole, outerNode ); 38025 if ( ! bridge ) { 38026 38027 return outerNode; 38028 38029 } 38030 38031 const bridgeReverse = splitPolygon( bridge, hole ); 38032 38033 // filter collinear points around the cuts 38034 filterPoints( bridgeReverse, bridgeReverse.next ); 38035 return filterPoints( bridge, bridge.next ); 38036 38037} 38038 38039// David Eberly's algorithm for finding a bridge between hole and outer polygon 38040function findHoleBridge( hole, outerNode ) { 38041 38042 let p = outerNode, 38043 qx = - Infinity, 38044 m; 38045 38046 const hx = hole.x, hy = hole.y; 38047 38048 // find a segment intersected by a ray from the hole's leftmost point to the left; 38049 // segment's endpoint with lesser x will be potential connection point 38050 do { 38051 38052 if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) { 38053 38054 const x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y ); 38055 if ( x <= hx && x > qx ) { 38056 38057 qx = x; 38058 m = p.x < p.next.x ? p : p.next; 38059 if ( x === hx ) return m; // hole touches outer segment; pick leftmost endpoint 38060 38061 } 38062 38063 } 38064 38065 p = p.next; 38066 38067 } while ( p !== outerNode ); 38068 38069 if ( ! m ) return null; 38070 38071 // look for points inside the triangle of hole point, segment intersection and endpoint; 38072 // if there are no points found, we have a valid connection; 38073 // otherwise choose the point of the minimum angle with the ray as connection point 38074 38075 const stop = m, 38076 mx = m.x, 38077 my = m.y; 38078 let tanMin = Infinity, tan; 38079 38080 p = m; 38081 38082 do { 38083 38084 if ( hx >= p.x && p.x >= mx && hx !== p.x && 38085 pointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) { 38086 38087 tan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential 38088 38089 if ( locallyInside( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector( m, p ) ) ) ) ) ) { 38090 38091 m = p; 38092 tanMin = tan; 38093 38094 } 38095 38096 } 38097 38098 p = p.next; 38099 38100 } while ( p !== stop ); 38101 38102 return m; 38103 38104} 38105 38106// whether sector in vertex m contains sector in vertex p in the same coordinates 38107function sectorContainsSector( m, p ) { 38108 38109 return area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0; 38110 38111} 38112 38113// interlink polygon nodes in z-order 38114function indexCurve( start, minX, minY, invSize ) { 38115 38116 let p = start; 38117 do { 38118 38119 if ( p.z === 0 ) p.z = zOrder( p.x, p.y, minX, minY, invSize ); 38120 p.prevZ = p.prev; 38121 p.nextZ = p.next; 38122 p = p.next; 38123 38124 } while ( p !== start ); 38125 38126 p.prevZ.nextZ = null; 38127 p.prevZ = null; 38128 38129 sortLinked( p ); 38130 38131} 38132 38133// Simon Tatham's linked list merge sort algorithm 38134// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html 38135function sortLinked( list ) { 38136 38137 let i, p, q, e, tail, numMerges, pSize, qSize, 38138 inSize = 1; 38139 38140 do { 38141 38142 p = list; 38143 list = null; 38144 tail = null; 38145 numMerges = 0; 38146 38147 while ( p ) { 38148 38149 numMerges ++; 38150 q = p; 38151 pSize = 0; 38152 for ( i = 0; i < inSize; i ++ ) { 38153 38154 pSize ++; 38155 q = q.nextZ; 38156 if ( ! q ) break; 38157 38158 } 38159 38160 qSize = inSize; 38161 38162 while ( pSize > 0 || ( qSize > 0 && q ) ) { 38163 38164 if ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) { 38165 38166 e = p; 38167 p = p.nextZ; 38168 pSize --; 38169 38170 } else { 38171 38172 e = q; 38173 q = q.nextZ; 38174 qSize --; 38175 38176 } 38177 38178 if ( tail ) tail.nextZ = e; 38179 else list = e; 38180 38181 e.prevZ = tail; 38182 tail = e; 38183 38184 } 38185 38186 p = q; 38187 38188 } 38189 38190 tail.nextZ = null; 38191 inSize *= 2; 38192 38193 } while ( numMerges > 1 ); 38194 38195 return list; 38196 38197} 38198 38199// z-order of a point given coords and inverse of the longer side of data bbox 38200function zOrder( x, y, minX, minY, invSize ) { 38201 38202 // coords are transformed into non-negative 15-bit integer range 38203 x = ( x - minX ) * invSize | 0; 38204 y = ( y - minY ) * invSize | 0; 38205 38206 x = ( x | ( x << 8 ) ) & 0x00FF00FF; 38207 x = ( x | ( x << 4 ) ) & 0x0F0F0F0F; 38208 x = ( x | ( x << 2 ) ) & 0x33333333; 38209 x = ( x | ( x << 1 ) ) & 0x55555555; 38210 38211 y = ( y | ( y << 8 ) ) & 0x00FF00FF; 38212 y = ( y | ( y << 4 ) ) & 0x0F0F0F0F; 38213 y = ( y | ( y << 2 ) ) & 0x33333333; 38214 y = ( y | ( y << 1 ) ) & 0x55555555; 38215 38216 return x | ( y << 1 ); 38217 38218} 38219 38220// find the leftmost node of a polygon ring 38221function getLeftmost( start ) { 38222 38223 let p = start, 38224 leftmost = start; 38225 do { 38226 38227 if ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) leftmost = p; 38228 p = p.next; 38229 38230 } while ( p !== start ); 38231 38232 return leftmost; 38233 38234} 38235 38236// check if a point lies within a convex triangle 38237function pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) { 38238 38239 return ( cx - px ) * ( ay - py ) >= ( ax - px ) * ( cy - py ) && 38240 ( ax - px ) * ( by - py ) >= ( bx - px ) * ( ay - py ) && 38241 ( bx - px ) * ( cy - py ) >= ( cx - px ) * ( by - py ); 38242 38243} 38244 38245// check if a diagonal between two polygon nodes is valid (lies in polygon interior) 38246function isValidDiagonal( a, b ) { 38247 38248 return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // dones't intersect other edges 38249 ( locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ) && // locally visible 38250 ( area( a.prev, a, b.prev ) || area( a, b.prev, b ) ) || // does not create opposite-facing sectors 38251 equals( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case 38252 38253} 38254 38255// signed area of a triangle 38256function area( p, q, r ) { 38257 38258 return ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y ); 38259 38260} 38261 38262// check if two points are equal 38263function equals( p1, p2 ) { 38264 38265 return p1.x === p2.x && p1.y === p2.y; 38266 38267} 38268 38269// check if two segments intersect 38270function intersects( p1, q1, p2, q2 ) { 38271 38272 const o1 = sign( area( p1, q1, p2 ) ); 38273 const o2 = sign( area( p1, q1, q2 ) ); 38274 const o3 = sign( area( p2, q2, p1 ) ); 38275 const o4 = sign( area( p2, q2, q1 ) ); 38276
vendor: 7,786 bytes, lines 38277-38617
38277 if ( o1 !== o2 && o3 !== o4 ) return true; // general case 38278 38279 if ( o1 === 0 && onSegment( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1 38280 if ( o2 === 0 && onSegment( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1 38281 if ( o3 === 0 && onSegment( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2 38282 if ( o4 === 0 && onSegment( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2 38283 38284 return false; 38285 38286} 38287 38288// for collinear points p, q, r, check if point q lies on segment pr 38289function onSegment( p, q, r ) { 38290 38291 return q.x <= Math.max( p.x, r.x ) && q.x >= Math.min( p.x, r.x ) && q.y <= Math.max( p.y, r.y ) && q.y >= Math.min( p.y, r.y ); 38292 38293} 38294 38295function sign( num ) { 38296 38297 return num > 0 ? 1 : num < 0 ? - 1 : 0; 38298 38299} 38300 38301// check if a polygon diagonal intersects any polygon segments 38302function intersectsPolygon( a, b ) { 38303 38304 let p = a; 38305 do { 38306 38307 if ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && 38308 intersects( p, p.next, a, b ) ) return true; 38309 p = p.next; 38310 38311 } while ( p !== a ); 38312 38313 return false; 38314 38315} 38316 38317// check if a polygon diagonal is locally inside the polygon 38318function locallyInside( a, b ) { 38319 38320 return area( a.prev, a, a.next ) < 0 ? 38321 area( a, b, a.next ) >= 0 && area( a, a.prev, b ) >= 0 : 38322 area( a, b, a.prev ) < 0 || area( a, a.next, b ) < 0; 38323 38324} 38325 38326// check if the middle point of a polygon diagonal is inside the polygon 38327function middleInside( a, b ) { 38328 38329 let p = a, 38330 inside = false; 38331 const px = ( a.x + b.x ) / 2, 38332 py = ( a.y + b.y ) / 2; 38333 do { 38334 38335 if ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y && 38336 ( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) ) 38337 inside = ! inside; 38338 p = p.next; 38339 38340 } while ( p !== a ); 38341 38342 return inside; 38343 38344} 38345 38346// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two; 38347// if one belongs to the outer ring and another to a hole, it merges it into a single ring 38348function splitPolygon( a, b ) { 38349 38350 const a2 = new Node( a.i, a.x, a.y ), 38351 b2 = new Node( b.i, b.x, b.y ), 38352 an = a.next, 38353 bp = b.prev; 38354 38355 a.next = b; 38356 b.prev = a; 38357 38358 a2.next = an; 38359 an.prev = a2; 38360 38361 b2.next = a2; 38362 a2.prev = b2; 38363 38364 bp.next = b2; 38365 b2.prev = bp; 38366 38367 return b2; 38368 38369} 38370 38371// create a node and optionally link it with previous one (in a circular doubly linked list) 38372function insertNode( i, x, y, last ) { 38373 38374 const p = new Node( i, x, y ); 38375 38376 if ( ! last ) { 38377 38378 p.prev = p; 38379 p.next = p; 38380 38381 } else { 38382 38383 p.next = last.next; 38384 p.prev = last; 38385 last.next.prev = p; 38386 last.next = p; 38387 38388 } 38389 38390 return p; 38391 38392} 38393 38394function removeNode( p ) { 38395 38396 p.next.prev = p.prev; 38397 p.prev.next = p.next; 38398 38399 if ( p.prevZ ) p.prevZ.nextZ = p.nextZ; 38400 if ( p.nextZ ) p.nextZ.prevZ = p.prevZ; 38401 38402} 38403 38404function Node( i, x, y ) { 38405 38406 // vertex index in coordinates array 38407 this.i = i; 38408 38409 // vertex coordinates 38410 this.x = x; 38411 this.y = y; 38412 38413 // previous and next vertex nodes in a polygon ring 38414 this.prev = null; 38415 this.next = null; 38416 38417 // z-order curve value 38418 this.z = 0; 38419 38420 // previous and next nodes in z-order 38421 this.prevZ = null; 38422 this.nextZ = null; 38423 38424 // indicates whether this is a steiner point 38425 this.steiner = false; 38426 38427} 38428 38429function signedArea( data, start, end, dim ) { 38430 38431 let sum = 0; 38432 for ( let i = start, j = end - dim; i < end; i += dim ) { 38433 38434 sum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] ); 38435 j = i; 38436 38437 } 38438 38439 return sum; 38440 38441} 38442 38443class ShapeUtils { 38444 38445 // calculate area of the contour polygon 38446 38447 static area( contour ) { 38448 38449 const n = contour.length; 38450 let a = 0.0; 38451 38452 for ( let p = n - 1, q = 0; q < n; p = q ++ ) { 38453 38454 a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; 38455 38456 } 38457 38458 return a * 0.5; 38459 38460 } 38461 38462 static isClockWise( pts ) { 38463 38464 return ShapeUtils.area( pts ) < 0; 38465 38466 } 38467 38468 static triangulateShape( contour, holes ) { 38469 38470 const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ] 38471 const holeIndices = []; // array of hole indices 38472 const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ] 38473 38474 removeDupEndPts( contour ); 38475 addContour( vertices, contour ); 38476 38477 // 38478 38479 let holeIndex = contour.length; 38480 38481 holes.forEach( removeDupEndPts ); 38482 38483 for ( let i = 0; i < holes.length; i ++ ) { 38484 38485 holeIndices.push( holeIndex ); 38486 holeIndex += holes[ i ].length; 38487 addContour( vertices, holes[ i ] ); 38488 38489 } 38490 38491 // 38492 38493 const triangles = Earcut.triangulate( vertices, holeIndices ); 38494 38495 // 38496 38497 for ( let i = 0; i < triangles.length; i += 3 ) { 38498 38499 faces.push( triangles.slice( i, i + 3 ) ); 38500 38501 } 38502 38503 return faces; 38504 38505 } 38506 38507} 38508 38509function removeDupEndPts( points ) { 38510 38511 const l = points.length; 38512 38513 if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) { 38514 38515 points.pop(); 38516 38517 } 38518 38519} 38520 38521function addContour( vertices, contour ) { 38522 38523 for ( let i = 0; i < contour.length; i ++ ) { 38524 38525 vertices.push( contour[ i ].x ); 38526 vertices.push( contour[ i ].y ); 38527 38528 } 38529 38530} 38531 38532/** 38533 * Creates extruded geometry from a path shape. 38534 * 38535 * parameters = { 38536 * 38537 * curveSegments: <int>, // number of points on the curves 38538 * steps: <int>, // number of points for z-side extrusions / used for subdividing segments of extrude spline too 38539 * depth: <float>, // Depth to extrude the shape 38540 * 38541 * bevelEnabled: <bool>, // turn on bevel 38542 * bevelThickness: <float>, // how deep into the original shape bevel goes 38543 * bevelSize: <float>, // how far from shape outline (including bevelOffset) is bevel 38544 * bevelOffset: <float>, // how far from shape outline does bevel start 38545 * bevelSegments: <int>, // number of bevel layers 38546 * 38547 * extrudePath: <THREE.Curve> // curve to extrude shape along 38548 * 38549 * UVGenerator: <Object> // object that provides UV generator functions 38550 * 38551 * } 38552 */ 38553 38554 38555class ExtrudeGeometry extends BufferGeometry { 38556 38557 constructor( shapes = new Shape( [ new Vector2( 0.5, 0.5 ), new Vector2( - 0.5, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), options = {} ) { 38558 38559 super(); 38560 38561 this.type = 'ExtrudeGeometry'; 38562 38563 this.parameters = { 38564 shapes: shapes, 38565 options: options 38566 }; 38567 38568 shapes = Array.isArray( shapes ) ? shapes : [ shapes ]; 38569 38570 const scope = this; 38571 38572 const verticesArray = []; 38573 const uvArray = []; 38574 38575 for ( let i = 0, l = shapes.length; i < l; i ++ ) { 38576 38577 const shape = shapes[ i ]; 38578 addShape( shape ); 38579 38580 } 38581 38582 // build geometry 38583 38584 this.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) ); 38585 this.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) ); 38586 38587 this.computeVertexNormals(); 38588 38589 // functions 38590 38591 function addShape( shape ) { 38592 38593 const placeholder = []; 38594 38595 // options 38596 38597 const curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; 38598 const steps = options.steps !== undefined ? options.steps : 1; 38599 const depth = options.depth !== undefined ? options.depth : 1; 38600 38601 let bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; 38602 let bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 0.2; 38603 let bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 0.1; 38604 let bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0; 38605 let bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; 38606 38607 const extrudePath = options.extrudePath; 38608 38609 const uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator; 38610 38611 // 38612 38613 let extrudePts, extrudeByPath = false; 38614 let splineTube, binormal, normal, position2; 38615 38616 if ( extrudePath ) { 38617
vendor: 2,827 bytes, lines 38618-38727
38618 extrudePts = extrudePath.getSpacedPoints( steps ); 38619 38620 extrudeByPath = true; 38621 bevelEnabled = false; // bevels not supported for path extrusion 38622 38623 // SETUP TNB variables 38624 38625 // TODO1 - have a .isClosed in spline? 38626 38627 splineTube = extrudePath.computeFrenetFrames( steps, false ); 38628 38629 // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); 38630 38631 binormal = new Vector3(); 38632 normal = new Vector3(); 38633 position2 = new Vector3(); 38634 38635 } 38636 38637 // Safeguards if bevels are not enabled 38638 38639 if ( ! bevelEnabled ) { 38640 38641 bevelSegments = 0; 38642 bevelThickness = 0; 38643 bevelSize = 0; 38644 bevelOffset = 0; 38645 38646 } 38647 38648 // Variables initialization 38649 38650 const shapePoints = shape.extractPoints( curveSegments ); 38651 38652 let vertices = shapePoints.shape; 38653 const holes = shapePoints.holes; 38654 38655 const reverse = ! ShapeUtils.isClockWise( vertices ); 38656 38657 if ( reverse ) { 38658 38659 vertices = vertices.reverse(); 38660 38661 // Maybe we should also check if holes are in the opposite direction, just to be safe ... 38662 38663 for ( let h = 0, hl = holes.length; h < hl; h ++ ) { 38664 38665 const ahole = holes[ h ]; 38666 38667 if ( ShapeUtils.isClockWise( ahole ) ) { 38668 38669 holes[ h ] = ahole.reverse(); 38670 38671 } 38672 38673 } 38674 38675 } 38676 38677 38678 const faces = ShapeUtils.triangulateShape( vertices, holes ); 38679 38680 /* Vertices */ 38681 38682 const contour = vertices; // vertices has all points but contour has only points of circumference 38683 38684 for ( let h = 0, hl = holes.length; h < hl; h ++ ) { 38685 38686 const ahole = holes[ h ]; 38687 38688 vertices = vertices.concat( ahole ); 38689 38690 } 38691 38692 38693 function scalePt2( pt, vec, size ) { 38694 38695 if ( ! vec ) console.error( 'THREE.ExtrudeGeometry: vec does not exist' ); 38696 38697 return pt.clone().addScaledVector( vec, size ); 38698 38699 } 38700 38701 const vlen = vertices.length, flen = faces.length; 38702 38703 38704 // Find directions for point movement 38705 38706 38707 function getBevelVec( inPt, inPrev, inNext ) { 38708 38709 // computes for inPt the corresponding point inPt' on a new contour 38710 // shifted by 1 unit (length of normalized vector) to the left 38711 // if we walk along contour clockwise, this new contour is outside the old one 38712 // 38713 // inPt' is the intersection of the two lines parallel to the two 38714 // adjacent edges of inPt at a distance of 1 unit on the left side. 38715 38716 let v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt 38717 38718 // good reading for geometry algorithms (here: line-line intersection) 38719 // http://geomalgorithms.com/a05-_intersect-1.html 38720 38721 const v_prev_x = inPt.x - inPrev.x, 38722 v_prev_y = inPt.y - inPrev.y; 38723 const v_next_x = inNext.x - inPt.x, 38724 v_next_y = inNext.y - inPt.y; 38725 38726 const v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); 38727
vendor: 18,304 bytes, lines 38728-39579
38728 // check for collinear edges 38729 const collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); 38730 38731 if ( Math.abs( collinear0 ) > Number.EPSILON ) { 38732 38733 // not collinear 38734 38735 // length of vectors for normalizing 38736 38737 const v_prev_len = Math.sqrt( v_prev_lensq ); 38738 const v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y ); 38739 38740 // shift adjacent points by unit vectors to the left 38741 38742 const ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); 38743 const ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); 38744 38745 const ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); 38746 const ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); 38747 38748 // scaling factor for v_prev to intersection point 38749 38750 const sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - 38751 ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / 38752 ( v_prev_x * v_next_y - v_prev_y * v_next_x ); 38753 38754 // vector from inPt to intersection point 38755 38756 v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); 38757 v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); 38758 38759 // Don't normalize!, otherwise sharp corners become ugly 38760 // but prevent crazy spikes 38761 const v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ); 38762 if ( v_trans_lensq <= 2 ) { 38763 38764 return new Vector2( v_trans_x, v_trans_y ); 38765 38766 } else { 38767 38768 shrink_by = Math.sqrt( v_trans_lensq / 2 ); 38769 38770 } 38771 38772 } else { 38773 38774 // handle special case of collinear edges 38775 38776 let direction_eq = false; // assumes: opposite 38777 38778 if ( v_prev_x > Number.EPSILON ) { 38779 38780 if ( v_next_x > Number.EPSILON ) { 38781 38782 direction_eq = true; 38783 38784 } 38785 38786 } else { 38787 38788 if ( v_prev_x < - Number.EPSILON ) { 38789 38790 if ( v_next_x < - Number.EPSILON ) { 38791 38792 direction_eq = true; 38793 38794 } 38795 38796 } else { 38797 38798 if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) { 38799 38800 direction_eq = true; 38801 38802 } 38803 38804 } 38805 38806 } 38807 38808 if ( direction_eq ) { 38809 38810 // console.log("Warning: lines are a straight sequence"); 38811 v_trans_x = - v_prev_y; 38812 v_trans_y = v_prev_x; 38813 shrink_by = Math.sqrt( v_prev_lensq ); 38814 38815 } else { 38816 38817 // console.log("Warning: lines are a straight spike"); 38818 v_trans_x = v_prev_x; 38819 v_trans_y = v_prev_y; 38820 shrink_by = Math.sqrt( v_prev_lensq / 2 ); 38821 38822 } 38823 38824 } 38825 38826 return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); 38827 38828 } 38829 38830 38831 const contourMovements = []; 38832 38833 for ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { 38834 38835 if ( j === il ) j = 0; 38836 if ( k === il ) k = 0; 38837 38838 // (j)---(i)---(k) 38839 // console.log('i,j,k', i, j , k) 38840 38841 contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); 38842 38843 } 38844 38845 const holesMovements = []; 38846 let oneHoleMovements, verticesMovements = contourMovements.concat(); 38847 38848 for ( let h = 0, hl = holes.length; h < hl; h ++ ) { 38849 38850 const ahole = holes[ h ]; 38851 38852 oneHoleMovements = []; 38853 38854 for ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { 38855 38856 if ( j === il ) j = 0; 38857 if ( k === il ) k = 0; 38858 38859 // (j)---(i)---(k) 38860 oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); 38861 38862 } 38863 38864 holesMovements.push( oneHoleMovements ); 38865 verticesMovements = verticesMovements.concat( oneHoleMovements ); 38866 38867 } 38868 38869 38870 // Loop bevelSegments, 1 for the front, 1 for the back 38871 38872 for ( let b = 0; b < bevelSegments; b ++ ) { 38873 38874 //for ( b = bevelSegments; b > 0; b -- ) { 38875 38876 const t = b / bevelSegments; 38877 const z = bevelThickness * Math.cos( t * Math.PI / 2 ); 38878 const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset; 38879 38880 // contract shape 38881 38882 for ( let i = 0, il = contour.length; i < il; i ++ ) { 38883 38884 const vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); 38885 38886 v( vert.x, vert.y, - z ); 38887 38888 } 38889 38890 // expand holes 38891 38892 for ( let h = 0, hl = holes.length; h < hl; h ++ ) { 38893 38894 const ahole = holes[ h ]; 38895 oneHoleMovements = holesMovements[ h ]; 38896 38897 for ( let i = 0, il = ahole.length; i < il; i ++ ) { 38898 38899 const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); 38900 38901 v( vert.x, vert.y, - z ); 38902 38903 } 38904 38905 } 38906 38907 } 38908 38909 const bs = bevelSize + bevelOffset; 38910 38911 // Back facing vertices 38912 38913 for ( let i = 0; i < vlen; i ++ ) { 38914 38915 const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; 38916 38917 if ( ! extrudeByPath ) { 38918 38919 v( vert.x, vert.y, 0 ); 38920 38921 } else { 38922 38923 // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); 38924 38925 normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x ); 38926 binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y ); 38927 38928 position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal ); 38929 38930 v( position2.x, position2.y, position2.z ); 38931 38932 } 38933 38934 } 38935 38936 // Add stepped vertices... 38937 // Including front facing vertices 38938 38939 for ( let s = 1; s <= steps; s ++ ) { 38940 38941 for ( let i = 0; i < vlen; i ++ ) { 38942 38943 const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; 38944 38945 if ( ! extrudeByPath ) { 38946 38947 v( vert.x, vert.y, depth / steps * s ); 38948 38949 } else { 38950 38951 // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); 38952 38953 normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x ); 38954 binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y ); 38955 38956 position2.copy( extrudePts[ s ] ).add( normal ).add( binormal ); 38957 38958 v( position2.x, position2.y, position2.z ); 38959 38960 } 38961 38962 } 38963 38964 } 38965 38966 38967 // Add bevel segments planes 38968 38969 //for ( b = 1; b <= bevelSegments; b ++ ) { 38970 for ( let b = bevelSegments - 1; b >= 0; b -- ) { 38971 38972 const t = b / bevelSegments; 38973 const z = bevelThickness * Math.cos( t * Math.PI / 2 ); 38974 const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset; 38975 38976 // contract shape 38977 38978 for ( let i = 0, il = contour.length; i < il; i ++ ) { 38979 38980 const vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); 38981 v( vert.x, vert.y, depth + z ); 38982 38983 } 38984 38985 // expand holes 38986 38987 for ( let h = 0, hl = holes.length; h < hl; h ++ ) { 38988 38989 const ahole = holes[ h ]; 38990 oneHoleMovements = holesMovements[ h ]; 38991 38992 for ( let i = 0, il = ahole.length; i < il; i ++ ) { 38993 38994 const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); 38995 38996 if ( ! extrudeByPath ) { 38997 38998 v( vert.x, vert.y, depth + z ); 38999 39000 } else { 39001 39002 v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); 39003 39004 } 39005 39006 } 39007 39008 } 39009 39010 } 39011 39012 /* Faces */ 39013 39014 // Top and bottom faces 39015 39016 buildLidFaces(); 39017 39018 // Sides faces 39019 39020 buildSideFaces(); 39021 39022 39023 ///// Internal functions 39024 39025 function buildLidFaces() { 39026 39027 const start = verticesArray.length / 3; 39028 39029 if ( bevelEnabled ) { 39030 39031 let layer = 0; // steps + 1 39032 let offset = vlen * layer; 39033 39034 // Bottom faces 39035 39036 for ( let i = 0; i < flen; i ++ ) { 39037 39038 const face = faces[ i ]; 39039 f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); 39040 39041 } 39042 39043 layer = steps + bevelSegments * 2; 39044 offset = vlen * layer; 39045 39046 // Top faces 39047 39048 for ( let i = 0; i < flen; i ++ ) { 39049 39050 const face = faces[ i ]; 39051 f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset ); 39052 39053 } 39054 39055 } else { 39056 39057 // Bottom faces 39058 39059 for ( let i = 0; i < flen; i ++ ) { 39060 39061 const face = faces[ i ]; 39062 f3( face[ 2 ], face[ 1 ], face[ 0 ] ); 39063 39064 } 39065 39066 // Top faces 39067 39068 for ( let i = 0; i < flen; i ++ ) { 39069 39070 const face = faces[ i ]; 39071 f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps ); 39072 39073 } 39074 39075 } 39076 39077 scope.addGroup( start, verticesArray.length / 3 - start, 0 ); 39078 39079 } 39080 39081 // Create faces for the z-sides of the shape 39082 39083 function buildSideFaces() { 39084 39085 const start = verticesArray.length / 3; 39086 let layeroffset = 0; 39087 sidewalls( contour, layeroffset ); 39088 layeroffset += contour.length; 39089 39090 for ( let h = 0, hl = holes.length; h < hl; h ++ ) { 39091 39092 const ahole = holes[ h ]; 39093 sidewalls( ahole, layeroffset ); 39094 39095 //, true 39096 layeroffset += ahole.length; 39097 39098 } 39099 39100 39101 scope.addGroup( start, verticesArray.length / 3 - start, 1 ); 39102 39103 39104 } 39105 39106 function sidewalls( contour, layeroffset ) { 39107 39108 let i = contour.length; 39109 39110 while ( -- i >= 0 ) { 39111 39112 const j = i; 39113 let k = i - 1; 39114 if ( k < 0 ) k = contour.length - 1; 39115 39116 //console.log('b', i,j, i-1, k,vertices.length); 39117 39118 for ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) { 39119 39120 const slen1 = vlen * s; 39121 const slen2 = vlen * ( s + 1 ); 39122 39123 const a = layeroffset + j + slen1, 39124 b = layeroffset + k + slen1, 39125 c = layeroffset + k + slen2, 39126 d = layeroffset + j + slen2; 39127 39128 f4( a, b, c, d ); 39129 39130 } 39131 39132 } 39133 39134 } 39135 39136 function v( x, y, z ) { 39137 39138 placeholder.push( x ); 39139 placeholder.push( y ); 39140 placeholder.push( z ); 39141 39142 } 39143 39144 39145 function f3( a, b, c ) { 39146 39147 addVertex( a ); 39148 addVertex( b ); 39149 addVertex( c ); 39150 39151 const nextIndex = verticesArray.length / 3; 39152 const uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); 39153 39154 addUV( uvs[ 0 ] ); 39155 addUV( uvs[ 1 ] ); 39156 addUV( uvs[ 2 ] ); 39157 39158 } 39159 39160 function f4( a, b, c, d ) { 39161 39162 addVertex( a ); 39163 addVertex( b ); 39164 addVertex( d ); 39165 39166 addVertex( b ); 39167 addVertex( c ); 39168 addVertex( d ); 39169 39170 39171 const nextIndex = verticesArray.length / 3; 39172 const uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); 39173 39174 addUV( uvs[ 0 ] ); 39175 addUV( uvs[ 1 ] ); 39176 addUV( uvs[ 3 ] ); 39177 39178 addUV( uvs[ 1 ] ); 39179 addUV( uvs[ 2 ] ); 39180 addUV( uvs[ 3 ] ); 39181 39182 } 39183 39184 function addVertex( index ) { 39185 39186 verticesArray.push( placeholder[ index * 3 + 0 ] ); 39187 verticesArray.push( placeholder[ index * 3 + 1 ] ); 39188 verticesArray.push( placeholder[ index * 3 + 2 ] ); 39189 39190 } 39191 39192 39193 function addUV( vector2 ) { 39194 39195 uvArray.push( vector2.x ); 39196 uvArray.push( vector2.y ); 39197 39198 } 39199 39200 } 39201 39202 } 39203 39204 copy( source ) { 39205 39206 super.copy( source ); 39207 39208 this.parameters = Object.assign( {}, source.parameters ); 39209 39210 return this; 39211 39212 } 39213 39214 toJSON() { 39215 39216 const data = super.toJSON(); 39217 39218 const shapes = this.parameters.shapes; 39219 const options = this.parameters.options; 39220 39221 return toJSON$1( shapes, options, data ); 39222 39223 } 39224 39225 static fromJSON( data, shapes ) { 39226 39227 const geometryShapes = []; 39228 39229 for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) { 39230 39231 const shape = shapes[ data.shapes[ j ] ]; 39232 39233 geometryShapes.push( shape ); 39234 39235 } 39236 39237 const extrudePath = data.options.extrudePath; 39238 39239 if ( extrudePath !== undefined ) { 39240 39241 data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath ); 39242 39243 } 39244 39245 return new ExtrudeGeometry( geometryShapes, data.options ); 39246 39247 } 39248 39249} 39250 39251const WorldUVGenerator = { 39252 39253 generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) { 39254 39255 const a_x = vertices[ indexA * 3 ]; 39256 const a_y = vertices[ indexA * 3 + 1 ]; 39257 const b_x = vertices[ indexB * 3 ]; 39258 const b_y = vertices[ indexB * 3 + 1 ]; 39259 const c_x = vertices[ indexC * 3 ]; 39260 const c_y = vertices[ indexC * 3 + 1 ]; 39261 39262 return [ 39263 new Vector2( a_x, a_y ), 39264 new Vector2( b_x, b_y ), 39265 new Vector2( c_x, c_y ) 39266 ]; 39267 39268 }, 39269 39270 generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) { 39271 39272 const a_x = vertices[ indexA * 3 ]; 39273 const a_y = vertices[ indexA * 3 + 1 ]; 39274 const a_z = vertices[ indexA * 3 + 2 ]; 39275 const b_x = vertices[ indexB * 3 ]; 39276 const b_y = vertices[ indexB * 3 + 1 ]; 39277 const b_z = vertices[ indexB * 3 + 2 ]; 39278 const c_x = vertices[ indexC * 3 ]; 39279 const c_y = vertices[ indexC * 3 + 1 ]; 39280 const c_z = vertices[ indexC * 3 + 2 ]; 39281 const d_x = vertices[ indexD * 3 ]; 39282 const d_y = vertices[ indexD * 3 + 1 ]; 39283 const d_z = vertices[ indexD * 3 + 2 ]; 39284 39285 if ( Math.abs( a_y - b_y ) < Math.abs( a_x - b_x ) ) { 39286 39287 return [ 39288 new Vector2( a_x, 1 - a_z ), 39289 new Vector2( b_x, 1 - b_z ), 39290 new Vector2( c_x, 1 - c_z ), 39291 new Vector2( d_x, 1 - d_z ) 39292 ]; 39293 39294 } else { 39295 39296 return [ 39297 new Vector2( a_y, 1 - a_z ), 39298 new Vector2( b_y, 1 - b_z ), 39299 new Vector2( c_y, 1 - c_z ), 39300 new Vector2( d_y, 1 - d_z ) 39301 ]; 39302 39303 } 39304 39305 } 39306 39307}; 39308 39309function toJSON$1( shapes, options, data ) { 39310 39311 data.shapes = []; 39312 39313 if ( Array.isArray( shapes ) ) { 39314 39315 for ( let i = 0, l = shapes.length; i < l; i ++ ) { 39316 39317 const shape = shapes[ i ]; 39318 39319 data.shapes.push( shape.uuid ); 39320 39321 } 39322 39323 } else { 39324 39325 data.shapes.push( shapes.uuid ); 39326 39327 } 39328 39329 data.options = Object.assign( {}, options ); 39330 39331 if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON(); 39332 39333 return data; 39334 39335} 39336 39337class IcosahedronGeometry extends PolyhedronGeometry { 39338 39339 constructor( radius = 1, detail = 0 ) { 39340 39341 const t = ( 1 + Math.sqrt( 5 ) ) / 2; 39342 39343 const vertices = [ 39344 - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0, 39345 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 39346 t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1 39347 ]; 39348 39349 const indices = [ 39350 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11, 39351 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8, 39352 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9, 39353 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1 39354 ]; 39355 39356 super( vertices, indices, radius, detail ); 39357 39358 this.type = 'IcosahedronGeometry'; 39359 39360 this.parameters = { 39361 radius: radius, 39362 detail: detail 39363 }; 39364 39365 } 39366 39367 static fromJSON( data ) { 39368 39369 return new IcosahedronGeometry( data.radius, data.detail ); 39370 39371 } 39372 39373} 39374 39375class OctahedronGeometry extends PolyhedronGeometry { 39376 39377 constructor( radius = 1, detail = 0 ) { 39378 39379 const vertices = [ 39380 1, 0, 0, - 1, 0, 0, 0, 1, 0, 39381 0, - 1, 0, 0, 0, 1, 0, 0, - 1 39382 ]; 39383 39384 const indices = [ 39385 0, 2, 4, 0, 4, 3, 0, 3, 5, 39386 0, 5, 2, 1, 2, 5, 1, 5, 3, 39387 1, 3, 4, 1, 4, 2 39388 ]; 39389 39390 super( vertices, indices, radius, detail ); 39391 39392 this.type = 'OctahedronGeometry'; 39393 39394 this.parameters = { 39395 radius: radius, 39396 detail: detail 39397 }; 39398 39399 } 39400 39401 static fromJSON( data ) { 39402 39403 return new OctahedronGeometry( data.radius, data.detail ); 39404 39405 } 39406 39407} 39408 39409class RingGeometry extends BufferGeometry { 39410 39411 constructor( innerRadius = 0.5, outerRadius = 1, thetaSegments = 32, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2 ) { 39412 39413 super(); 39414 39415 this.type = 'RingGeometry'; 39416 39417 this.parameters = { 39418 innerRadius: innerRadius, 39419 outerRadius: outerRadius, 39420 thetaSegments: thetaSegments, 39421 phiSegments: phiSegments, 39422 thetaStart: thetaStart, 39423 thetaLength: thetaLength 39424 }; 39425 39426 thetaSegments = Math.max( 3, thetaSegments ); 39427 phiSegments = Math.max( 1, phiSegments ); 39428 39429 // buffers 39430 39431 const indices = []; 39432 const vertices = []; 39433 const normals = []; 39434 const uvs = []; 39435 39436 // some helper variables 39437 39438 let radius = innerRadius; 39439 const radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); 39440 const vertex = new Vector3(); 39441 const uv = new Vector2(); 39442 39443 // generate vertices, normals and uvs 39444 39445 for ( let j = 0; j <= phiSegments; j ++ ) { 39446 39447 for ( let i = 0; i <= thetaSegments; i ++ ) { 39448 39449 // values are generate from the inside of the ring to the outside 39450 39451 const segment = thetaStart + i / thetaSegments * thetaLength; 39452 39453 // vertex 39454 39455 vertex.x = radius * Math.cos( segment ); 39456 vertex.y = radius * Math.sin( segment ); 39457 39458 vertices.push( vertex.x, vertex.y, vertex.z ); 39459 39460 // normal 39461 39462 normals.push( 0, 0, 1 ); 39463 39464 // uv 39465 39466 uv.x = ( vertex.x / outerRadius + 1 ) / 2; 39467 uv.y = ( vertex.y / outerRadius + 1 ) / 2; 39468 39469 uvs.push( uv.x, uv.y ); 39470 39471 } 39472 39473 // increase the radius for next row of vertices 39474 39475 radius += radiusStep; 39476 39477 } 39478 39479 // indices 39480 39481 for ( let j = 0; j < phiSegments; j ++ ) { 39482 39483 const thetaSegmentLevel = j * ( thetaSegments + 1 ); 39484 39485 for ( let i = 0; i < thetaSegments; i ++ ) { 39486 39487 const segment = i + thetaSegmentLevel; 39488 39489 const a = segment; 39490 const b = segment + thetaSegments + 1; 39491 const c = segment + thetaSegments + 2; 39492 const d = segment + 1; 39493 39494 // faces 39495 39496 indices.push( a, b, d ); 39497 indices.push( b, c, d ); 39498 39499 } 39500 39501 } 39502 39503 // build geometry 39504 39505 this.setIndex( indices ); 39506 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 39507 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 39508 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 39509 39510 } 39511 39512 copy( source ) { 39513 39514 super.copy( source ); 39515 39516 this.parameters = Object.assign( {}, source.parameters ); 39517 39518 return this; 39519 39520 } 39521 39522 static fromJSON( data ) { 39523 39524 return new RingGeometry( data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength ); 39525 39526 } 39527 39528} 39529 39530class ShapeGeometry extends BufferGeometry { 39531 39532 constructor( shapes = new Shape( [ new Vector2( 0, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), curveSegments = 12 ) { 39533 39534 super(); 39535 39536 this.type = 'ShapeGeometry'; 39537 39538 this.parameters = { 39539 shapes: shapes, 39540 curveSegments: curveSegments 39541 }; 39542 39543 // buffers 39544 39545 const indices = []; 39546 const vertices = []; 39547 const normals = []; 39548 const uvs = []; 39549 39550 // helper variables 39551 39552 let groupStart = 0; 39553 let groupCount = 0; 39554 39555 // allow single and array values for "shapes" parameter 39556 39557 if ( Array.isArray( shapes ) === false ) { 39558 39559 addShape( shapes ); 39560 39561 } else { 39562 39563 for ( let i = 0; i < shapes.length; i ++ ) { 39564 39565 addShape( shapes[ i ] ); 39566 39567 this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support 39568 39569 groupStart += groupCount; 39570 groupCount = 0; 39571 39572 } 39573 39574 } 39575 39576 // build geometry 39577 39578 this.setIndex( indices ); 39579 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
vendor: 4,079 bytes, lines 39580-39782
39580 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 39581 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 39582 39583 39584 // helper functions 39585 39586 function addShape( shape ) { 39587 39588 const indexOffset = vertices.length / 3; 39589 const points = shape.extractPoints( curveSegments ); 39590 39591 let shapeVertices = points.shape; 39592 const shapeHoles = points.holes; 39593 39594 // check direction of vertices 39595 39596 if ( ShapeUtils.isClockWise( shapeVertices ) === false ) { 39597 39598 shapeVertices = shapeVertices.reverse(); 39599 39600 } 39601 39602 for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) { 39603 39604 const shapeHole = shapeHoles[ i ]; 39605 39606 if ( ShapeUtils.isClockWise( shapeHole ) === true ) { 39607 39608 shapeHoles[ i ] = shapeHole.reverse(); 39609 39610 } 39611 39612 } 39613 39614 const faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles ); 39615 39616 // join vertices of inner and outer paths to a single array 39617 39618 for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) { 39619 39620 const shapeHole = shapeHoles[ i ]; 39621 shapeVertices = shapeVertices.concat( shapeHole ); 39622 39623 } 39624 39625 // vertices, normals, uvs 39626 39627 for ( let i = 0, l = shapeVertices.length; i < l; i ++ ) { 39628 39629 const vertex = shapeVertices[ i ]; 39630 39631 vertices.push( vertex.x, vertex.y, 0 ); 39632 normals.push( 0, 0, 1 ); 39633 uvs.push( vertex.x, vertex.y ); // world uvs 39634 39635 } 39636 39637 // indices 39638 39639 for ( let i = 0, l = faces.length; i < l; i ++ ) { 39640 39641 const face = faces[ i ]; 39642 39643 const a = face[ 0 ] + indexOffset; 39644 const b = face[ 1 ] + indexOffset; 39645 const c = face[ 2 ] + indexOffset; 39646 39647 indices.push( a, b, c ); 39648 groupCount += 3; 39649 39650 } 39651 39652 } 39653 39654 } 39655 39656 copy( source ) { 39657 39658 super.copy( source ); 39659 39660 this.parameters = Object.assign( {}, source.parameters ); 39661 39662 return this; 39663 39664 } 39665 39666 toJSON() { 39667 39668 const data = super.toJSON(); 39669 39670 const shapes = this.parameters.shapes; 39671 39672 return toJSON( shapes, data ); 39673 39674 } 39675 39676 static fromJSON( data, shapes ) { 39677 39678 const geometryShapes = []; 39679 39680 for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) { 39681 39682 const shape = shapes[ data.shapes[ j ] ]; 39683 39684 geometryShapes.push( shape ); 39685 39686 } 39687 39688 return new ShapeGeometry( geometryShapes, data.curveSegments ); 39689 39690 } 39691 39692} 39693 39694function toJSON( shapes, data ) { 39695 39696 data.shapes = []; 39697 39698 if ( Array.isArray( shapes ) ) { 39699 39700 for ( let i = 0, l = shapes.length; i < l; i ++ ) { 39701 39702 const shape = shapes[ i ]; 39703 39704 data.shapes.push( shape.uuid ); 39705 39706 } 39707 39708 } else { 39709 39710 data.shapes.push( shapes.uuid ); 39711 39712 } 39713 39714 return data; 39715 39716} 39717 39718class SphereGeometry extends BufferGeometry { 39719 39720 constructor( radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) { 39721 39722 super(); 39723 39724 this.type = 'SphereGeometry'; 39725 39726 this.parameters = { 39727 radius: radius, 39728 widthSegments: widthSegments, 39729 heightSegments: heightSegments, 39730 phiStart: phiStart, 39731 phiLength: phiLength, 39732 thetaStart: thetaStart, 39733 thetaLength: thetaLength 39734 }; 39735 39736 widthSegments = Math.max( 3, Math.floor( widthSegments ) ); 39737 heightSegments = Math.max( 2, Math.floor( heightSegments ) ); 39738 39739 const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI ); 39740 39741 let index = 0; 39742 const grid = []; 39743 39744 const vertex = new Vector3(); 39745 const normal = new Vector3(); 39746 39747 // buffers 39748 39749 const indices = []; 39750 const vertices = []; 39751 const normals = []; 39752 const uvs = []; 39753 39754 // generate vertices, normals and uvs 39755 39756 for ( let iy = 0; iy <= heightSegments; iy ++ ) { 39757 39758 const verticesRow = []; 39759 39760 const v = iy / heightSegments; 39761 39762 // special case for the poles 39763 39764 let uOffset = 0; 39765 39766 if ( iy === 0 && thetaStart === 0 ) { 39767 39768 uOffset = 0.5 / widthSegments; 39769 39770 } else if ( iy === heightSegments && thetaEnd === Math.PI ) { 39771 39772 uOffset = - 0.5 / widthSegments; 39773 39774 } 39775 39776 for ( let ix = 0; ix <= widthSegments; ix ++ ) { 39777 39778 const u = ix / widthSegments; 39779 39780 // vertex 39781 39782 vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
vendor: 4,136 bytes, lines 39783-39972
39783 vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); 39784 vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); 39785 39786 vertices.push( vertex.x, vertex.y, vertex.z ); 39787 39788 // normal 39789 39790 normal.copy( vertex ).normalize(); 39791 normals.push( normal.x, normal.y, normal.z ); 39792 39793 // uv 39794 39795 uvs.push( u + uOffset, 1 - v ); 39796 39797 verticesRow.push( index ++ ); 39798 39799 } 39800 39801 grid.push( verticesRow ); 39802 39803 } 39804 39805 // indices 39806 39807 for ( let iy = 0; iy < heightSegments; iy ++ ) { 39808 39809 for ( let ix = 0; ix < widthSegments; ix ++ ) { 39810 39811 const a = grid[ iy ][ ix + 1 ]; 39812 const b = grid[ iy ][ ix ]; 39813 const c = grid[ iy + 1 ][ ix ]; 39814 const d = grid[ iy + 1 ][ ix + 1 ]; 39815 39816 if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d ); 39817 if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d ); 39818 39819 } 39820 39821 } 39822 39823 // build geometry 39824 39825 this.setIndex( indices ); 39826 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 39827 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 39828 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 39829 39830 } 39831 39832 copy( source ) { 39833 39834 super.copy( source ); 39835 39836 this.parameters = Object.assign( {}, source.parameters ); 39837 39838 return this; 39839 39840 } 39841 39842 static fromJSON( data ) { 39843 39844 return new SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength ); 39845 39846 } 39847 39848} 39849 39850class TetrahedronGeometry extends PolyhedronGeometry { 39851 39852 constructor( radius = 1, detail = 0 ) { 39853 39854 const vertices = [ 39855 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1 39856 ]; 39857 39858 const indices = [ 39859 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 39860 ]; 39861 39862 super( vertices, indices, radius, detail ); 39863 39864 this.type = 'TetrahedronGeometry'; 39865 39866 this.parameters = { 39867 radius: radius, 39868 detail: detail 39869 }; 39870 39871 } 39872 39873 static fromJSON( data ) { 39874 39875 return new TetrahedronGeometry( data.radius, data.detail ); 39876 39877 } 39878 39879} 39880 39881class TorusGeometry extends BufferGeometry { 39882 39883 constructor( radius = 1, tube = 0.4, radialSegments = 12, tubularSegments = 48, arc = Math.PI * 2 ) { 39884 39885 super(); 39886 39887 this.type = 'TorusGeometry'; 39888 39889 this.parameters = { 39890 radius: radius, 39891 tube: tube, 39892 radialSegments: radialSegments, 39893 tubularSegments: tubularSegments, 39894 arc: arc 39895 }; 39896 39897 radialSegments = Math.floor( radialSegments ); 39898 tubularSegments = Math.floor( tubularSegments ); 39899 39900 // buffers 39901 39902 const indices = []; 39903 const vertices = []; 39904 const normals = []; 39905 const uvs = []; 39906 39907 // helper variables 39908 39909 const center = new Vector3(); 39910 const vertex = new Vector3(); 39911 const normal = new Vector3(); 39912 39913 // generate vertices, normals and uvs 39914 39915 for ( let j = 0; j <= radialSegments; j ++ ) { 39916 39917 for ( let i = 0; i <= tubularSegments; i ++ ) { 39918 39919 const u = i / tubularSegments * arc; 39920 const v = j / radialSegments * Math.PI * 2; 39921 39922 // vertex 39923 39924 vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u ); 39925 vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u ); 39926 vertex.z = tube * Math.sin( v ); 39927 39928 vertices.push( vertex.x, vertex.y, vertex.z ); 39929 39930 // normal 39931 39932 center.x = radius * Math.cos( u ); 39933 center.y = radius * Math.sin( u ); 39934 normal.subVectors( vertex, center ).normalize(); 39935 39936 normals.push( normal.x, normal.y, normal.z ); 39937 39938 // uv 39939 39940 uvs.push( i / tubularSegments ); 39941 uvs.push( j / radialSegments ); 39942 39943 } 39944 39945 } 39946 39947 // generate indices 39948 39949 for ( let j = 1; j <= radialSegments; j ++ ) { 39950 39951 for ( let i = 1; i <= tubularSegments; i ++ ) { 39952 39953 // indices 39954 39955 const a = ( tubularSegments + 1 ) * j + i - 1; 39956 const b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1; 39957 const c = ( tubularSegments + 1 ) * ( j - 1 ) + i; 39958 const d = ( tubularSegments + 1 ) * j + i; 39959 39960 // faces 39961 39962 indices.push( a, b, d ); 39963 indices.push( b, c, d ); 39964 39965 } 39966 39967 } 39968 39969 // build geometry 39970 39971 this.setIndex( indices ); 39972 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
vendor: 47,067 bytes, lines 39973-42175
39973 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 39974 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 39975 39976 } 39977 39978 copy( source ) { 39979 39980 super.copy( source ); 39981 39982 this.parameters = Object.assign( {}, source.parameters ); 39983 39984 return this; 39985 39986 } 39987 39988 static fromJSON( data ) { 39989 39990 return new TorusGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc ); 39991 39992 } 39993 39994} 39995 39996class TorusKnotGeometry extends BufferGeometry { 39997 39998 constructor( radius = 1, tube = 0.4, tubularSegments = 64, radialSegments = 8, p = 2, q = 3 ) { 39999 40000 super(); 40001 40002 this.type = 'TorusKnotGeometry'; 40003 40004 this.parameters = { 40005 radius: radius, 40006 tube: tube, 40007 tubularSegments: tubularSegments, 40008 radialSegments: radialSegments, 40009 p: p, 40010 q: q 40011 }; 40012 40013 tubularSegments = Math.floor( tubularSegments ); 40014 radialSegments = Math.floor( radialSegments ); 40015 40016 // buffers 40017 40018 const indices = []; 40019 const vertices = []; 40020 const normals = []; 40021 const uvs = []; 40022 40023 // helper variables 40024 40025 const vertex = new Vector3(); 40026 const normal = new Vector3(); 40027 40028 const P1 = new Vector3(); 40029 const P2 = new Vector3(); 40030 40031 const B = new Vector3(); 40032 const T = new Vector3(); 40033 const N = new Vector3(); 40034 40035 // generate vertices, normals and uvs 40036 40037 for ( let i = 0; i <= tubularSegments; ++ i ) { 40038 40039 // the radian "u" is used to calculate the position on the torus curve of the current tubular segment 40040 40041 const u = i / tubularSegments * p * Math.PI * 2; 40042 40043 // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead. 40044 // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions 40045 40046 calculatePositionOnCurve( u, p, q, radius, P1 ); 40047 calculatePositionOnCurve( u + 0.01, p, q, radius, P2 ); 40048 40049 // calculate orthonormal basis 40050 40051 T.subVectors( P2, P1 ); 40052 N.addVectors( P2, P1 ); 40053 B.crossVectors( T, N ); 40054 N.crossVectors( B, T ); 40055 40056 // normalize B, N. T can be ignored, we don't use it 40057 40058 B.normalize(); 40059 N.normalize(); 40060 40061 for ( let j = 0; j <= radialSegments; ++ j ) { 40062 40063 // now calculate the vertices. they are nothing more than an extrusion of the torus curve. 40064 // because we extrude a shape in the xy-plane, there is no need to calculate a z-value. 40065 40066 const v = j / radialSegments * Math.PI * 2; 40067 const cx = - tube * Math.cos( v ); 40068 const cy = tube * Math.sin( v ); 40069 40070 // now calculate the final vertex position. 40071 // first we orient the extrusion with our basis vectors, then we add it to the current position on the curve 40072 40073 vertex.x = P1.x + ( cx * N.x + cy * B.x ); 40074 vertex.y = P1.y + ( cx * N.y + cy * B.y ); 40075 vertex.z = P1.z + ( cx * N.z + cy * B.z ); 40076 40077 vertices.push( vertex.x, vertex.y, vertex.z ); 40078 40079 // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal) 40080 40081 normal.subVectors( vertex, P1 ).normalize(); 40082 40083 normals.push( normal.x, normal.y, normal.z ); 40084 40085 // uv 40086 40087 uvs.push( i / tubularSegments ); 40088 uvs.push( j / radialSegments ); 40089 40090 } 40091 40092 } 40093 40094 // generate indices 40095 40096 for ( let j = 1; j <= tubularSegments; j ++ ) { 40097 40098 for ( let i = 1; i <= radialSegments; i ++ ) { 40099 40100 // indices 40101 40102 const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); 40103 const b = ( radialSegments + 1 ) * j + ( i - 1 ); 40104 const c = ( radialSegments + 1 ) * j + i; 40105 const d = ( radialSegments + 1 ) * ( j - 1 ) + i; 40106 40107 // faces 40108 40109 indices.push( a, b, d ); 40110 indices.push( b, c, d ); 40111 40112 } 40113 40114 } 40115 40116 // build geometry 40117 40118 this.setIndex( indices ); 40119 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 40120 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 40121 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 40122 40123 // this function calculates the current position on the torus curve 40124 40125 function calculatePositionOnCurve( u, p, q, radius, position ) { 40126 40127 const cu = Math.cos( u ); 40128 const su = Math.sin( u ); 40129 const quOverP = q / p * u; 40130 const cs = Math.cos( quOverP ); 40131 40132 position.x = radius * ( 2 + cs ) * 0.5 * cu; 40133 position.y = radius * ( 2 + cs ) * su * 0.5; 40134 position.z = radius * Math.sin( quOverP ) * 0.5; 40135 40136 } 40137 40138 } 40139 40140 copy( source ) { 40141 40142 super.copy( source ); 40143 40144 this.parameters = Object.assign( {}, source.parameters ); 40145 40146 return this; 40147 40148 } 40149 40150 static fromJSON( data ) { 40151 40152 return new TorusKnotGeometry( data.radius, data.tube, data.tubularSegments, data.radialSegments, data.p, data.q ); 40153 40154 } 40155 40156} 40157 40158class TubeGeometry extends BufferGeometry { 40159 40160 constructor( path = new QuadraticBezierCurve3( new Vector3( - 1, - 1, 0 ), new Vector3( - 1, 1, 0 ), new Vector3( 1, 1, 0 ) ), tubularSegments = 64, radius = 1, radialSegments = 8, closed = false ) { 40161 40162 super(); 40163 40164 this.type = 'TubeGeometry'; 40165 40166 this.parameters = { 40167 path: path, 40168 tubularSegments: tubularSegments, 40169 radius: radius, 40170 radialSegments: radialSegments, 40171 closed: closed 40172 }; 40173 40174 const frames = path.computeFrenetFrames( tubularSegments, closed ); 40175 40176 // expose internals 40177 40178 this.tangents = frames.tangents; 40179 this.normals = frames.normals; 40180 this.binormals = frames.binormals; 40181 40182 // helper variables 40183 40184 const vertex = new Vector3(); 40185 const normal = new Vector3(); 40186 const uv = new Vector2(); 40187 let P = new Vector3(); 40188 40189 // buffer 40190 40191 const vertices = []; 40192 const normals = []; 40193 const uvs = []; 40194 const indices = []; 40195 40196 // create buffer data 40197 40198 generateBufferData(); 40199 40200 // build geometry 40201 40202 this.setIndex( indices ); 40203 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 40204 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 40205 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 40206 40207 // functions 40208 40209 function generateBufferData() { 40210 40211 for ( let i = 0; i < tubularSegments; i ++ ) { 40212 40213 generateSegment( i ); 40214 40215 } 40216 40217 // if the geometry is not closed, generate the last row of vertices and normals 40218 // at the regular position on the given path 40219 // 40220 // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ) 40221 40222 generateSegment( ( closed === false ) ? tubularSegments : 0 ); 40223 40224 // uvs are generated in a separate function. 40225 // this makes it easy compute correct values for closed geometries 40226 40227 generateUVs(); 40228 40229 // finally create faces 40230 40231 generateIndices(); 40232 40233 } 40234 40235 function generateSegment( i ) { 40236 40237 // we use getPointAt to sample evenly distributed points from the given path 40238 40239 P = path.getPointAt( i / tubularSegments, P ); 40240 40241 // retrieve corresponding normal and binormal 40242 40243 const N = frames.normals[ i ]; 40244 const B = frames.binormals[ i ]; 40245 40246 // generate normals and vertices for the current segment 40247 40248 for ( let j = 0; j <= radialSegments; j ++ ) { 40249 40250 const v = j / radialSegments * Math.PI * 2; 40251 40252 const sin = Math.sin( v ); 40253 const cos = - Math.cos( v ); 40254 40255 // normal 40256 40257 normal.x = ( cos * N.x + sin * B.x ); 40258 normal.y = ( cos * N.y + sin * B.y ); 40259 normal.z = ( cos * N.z + sin * B.z ); 40260 normal.normalize(); 40261 40262 normals.push( normal.x, normal.y, normal.z ); 40263 40264 // vertex 40265 40266 vertex.x = P.x + radius * normal.x; 40267 vertex.y = P.y + radius * normal.y; 40268 vertex.z = P.z + radius * normal.z; 40269 40270 vertices.push( vertex.x, vertex.y, vertex.z ); 40271 40272 } 40273 40274 } 40275 40276 function generateIndices() { 40277 40278 for ( let j = 1; j <= tubularSegments; j ++ ) { 40279 40280 for ( let i = 1; i <= radialSegments; i ++ ) { 40281 40282 const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); 40283 const b = ( radialSegments + 1 ) * j + ( i - 1 ); 40284 const c = ( radialSegments + 1 ) * j + i; 40285 const d = ( radialSegments + 1 ) * ( j - 1 ) + i; 40286 40287 // faces 40288 40289 indices.push( a, b, d ); 40290 indices.push( b, c, d ); 40291 40292 } 40293 40294 } 40295 40296 } 40297 40298 function generateUVs() { 40299 40300 for ( let i = 0; i <= tubularSegments; i ++ ) { 40301 40302 for ( let j = 0; j <= radialSegments; j ++ ) { 40303 40304 uv.x = i / tubularSegments; 40305 uv.y = j / radialSegments; 40306 40307 uvs.push( uv.x, uv.y ); 40308 40309 } 40310 40311 } 40312 40313 } 40314 40315 } 40316 40317 copy( source ) { 40318 40319 super.copy( source ); 40320 40321 this.parameters = Object.assign( {}, source.parameters ); 40322 40323 return this; 40324 40325 } 40326 40327 toJSON() { 40328 40329 const data = super.toJSON(); 40330 40331 data.path = this.parameters.path.toJSON(); 40332 40333 return data; 40334 40335 } 40336 40337 static fromJSON( data ) { 40338 40339 // This only works for built-in curves (e.g. CatmullRomCurve3). 40340 // User defined curves or instances of CurvePath will not be deserialized. 40341 return new TubeGeometry( 40342 new Curves[ data.path.type ]().fromJSON( data.path ), 40343 data.tubularSegments, 40344 data.radius, 40345 data.radialSegments, 40346 data.closed 40347 ); 40348 40349 } 40350 40351} 40352 40353class WireframeGeometry extends BufferGeometry { 40354 40355 constructor( geometry = null ) { 40356 40357 super(); 40358 40359 this.type = 'WireframeGeometry'; 40360 40361 this.parameters = { 40362 geometry: geometry 40363 }; 40364 40365 if ( geometry !== null ) { 40366 40367 // buffer 40368 40369 const vertices = []; 40370 const edges = new Set(); 40371 40372 // helper variables 40373 40374 const start = new Vector3(); 40375 const end = new Vector3(); 40376 40377 if ( geometry.index !== null ) { 40378 40379 // indexed BufferGeometry 40380 40381 const position = geometry.attributes.position; 40382 const indices = geometry.index; 40383 let groups = geometry.groups; 40384 40385 if ( groups.length === 0 ) { 40386 40387 groups = [ { start: 0, count: indices.count, materialIndex: 0 } ]; 40388 40389 } 40390 40391 // create a data structure that contains all edges without duplicates 40392 40393 for ( let o = 0, ol = groups.length; o < ol; ++ o ) { 40394 40395 const group = groups[ o ]; 40396 40397 const groupStart = group.start; 40398 const groupCount = group.count; 40399 40400 for ( let i = groupStart, l = ( groupStart + groupCount ); i < l; i += 3 ) { 40401 40402 for ( let j = 0; j < 3; j ++ ) { 40403 40404 const index1 = indices.getX( i + j ); 40405 const index2 = indices.getX( i + ( j + 1 ) % 3 ); 40406 40407 start.fromBufferAttribute( position, index1 ); 40408 end.fromBufferAttribute( position, index2 ); 40409 40410 if ( isUniqueEdge( start, end, edges ) === true ) { 40411 40412 vertices.push( start.x, start.y, start.z ); 40413 vertices.push( end.x, end.y, end.z ); 40414 40415 } 40416 40417 } 40418 40419 } 40420 40421 } 40422 40423 } else { 40424 40425 // non-indexed BufferGeometry 40426 40427 const position = geometry.attributes.position; 40428 40429 for ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) { 40430 40431 for ( let j = 0; j < 3; j ++ ) { 40432 40433 // three edges per triangle, an edge is represented as (index1, index2) 40434 // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0) 40435 40436 const index1 = 3 * i + j; 40437 const index2 = 3 * i + ( ( j + 1 ) % 3 ); 40438 40439 start.fromBufferAttribute( position, index1 ); 40440 end.fromBufferAttribute( position, index2 ); 40441 40442 if ( isUniqueEdge( start, end, edges ) === true ) { 40443 40444 vertices.push( start.x, start.y, start.z ); 40445 vertices.push( end.x, end.y, end.z ); 40446 40447 } 40448 40449 } 40450 40451 } 40452 40453 } 40454 40455 // build geometry 40456 40457 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 40458 40459 } 40460 40461 } 40462 40463 copy( source ) { 40464 40465 super.copy( source ); 40466 40467 this.parameters = Object.assign( {}, source.parameters ); 40468 40469 return this; 40470 40471 } 40472 40473} 40474 40475function isUniqueEdge( start, end, edges ) { 40476 40477 const hash1 = `${start.x},${start.y},${start.z}-${end.x},${end.y},${end.z}`; 40478 const hash2 = `${end.x},${end.y},${end.z}-${start.x},${start.y},${start.z}`; // coincident edge 40479 40480 if ( edges.has( hash1 ) === true || edges.has( hash2 ) === true ) { 40481 40482 return false; 40483 40484 } else { 40485 40486 edges.add( hash1 ); 40487 edges.add( hash2 ); 40488 return true; 40489 40490 } 40491 40492} 40493 40494var Geometries = /*#__PURE__*/Object.freeze({ 40495 __proto__: null, 40496 BoxGeometry: BoxGeometry, 40497 CapsuleGeometry: CapsuleGeometry, 40498 CircleGeometry: CircleGeometry, 40499 ConeGeometry: ConeGeometry, 40500 CylinderGeometry: CylinderGeometry, 40501 DodecahedronGeometry: DodecahedronGeometry, 40502 EdgesGeometry: EdgesGeometry, 40503 ExtrudeGeometry: ExtrudeGeometry, 40504 IcosahedronGeometry: IcosahedronGeometry, 40505 LatheGeometry: LatheGeometry, 40506 OctahedronGeometry: OctahedronGeometry, 40507 PlaneGeometry: PlaneGeometry, 40508 PolyhedronGeometry: PolyhedronGeometry, 40509 RingGeometry: RingGeometry, 40510 ShapeGeometry: ShapeGeometry, 40511 SphereGeometry: SphereGeometry, 40512 TetrahedronGeometry: TetrahedronGeometry, 40513 TorusGeometry: TorusGeometry, 40514 TorusKnotGeometry: TorusKnotGeometry, 40515 TubeGeometry: TubeGeometry, 40516 WireframeGeometry: WireframeGeometry 40517}); 40518 40519class ShadowMaterial extends Material { 40520 40521 constructor( parameters ) { 40522 40523 super(); 40524 40525 this.isShadowMaterial = true; 40526 40527 this.type = 'ShadowMaterial'; 40528 40529 this.color = new Color( 0x000000 ); 40530 this.transparent = true; 40531 40532 this.fog = true; 40533 40534 this.setValues( parameters ); 40535 40536 } 40537 40538 copy( source ) { 40539 40540 super.copy( source ); 40541 40542 this.color.copy( source.color ); 40543 40544 this.fog = source.fog; 40545 40546 return this; 40547 40548 } 40549 40550} 40551 40552class RawShaderMaterial extends ShaderMaterial { 40553 40554 constructor( parameters ) { 40555 40556 super( parameters ); 40557 40558 this.isRawShaderMaterial = true; 40559 40560 this.type = 'RawShaderMaterial'; 40561 40562 } 40563 40564} 40565 40566class MeshStandardMaterial extends Material { 40567 40568 constructor( parameters ) { 40569 40570 super(); 40571 40572 this.isMeshStandardMaterial = true; 40573 40574 this.defines = { 'STANDARD': '' }; 40575 40576 this.type = 'MeshStandardMaterial'; 40577 40578 this.color = new Color( 0xffffff ); // diffuse 40579 this.roughness = 1.0; 40580 this.metalness = 0.0; 40581 40582 this.map = null; 40583 40584 this.lightMap = null; 40585 this.lightMapIntensity = 1.0; 40586 40587 this.aoMap = null; 40588 this.aoMapIntensity = 1.0; 40589 40590 this.emissive = new Color( 0x000000 ); 40591 this.emissiveIntensity = 1.0; 40592 this.emissiveMap = null; 40593 40594 this.bumpMap = null; 40595 this.bumpScale = 1; 40596 40597 this.normalMap = null; 40598 this.normalMapType = TangentSpaceNormalMap; 40599 this.normalScale = new Vector2( 1, 1 ); 40600 40601 this.displacementMap = null; 40602 this.displacementScale = 1; 40603 this.displacementBias = 0; 40604 40605 this.roughnessMap = null; 40606 40607 this.metalnessMap = null; 40608 40609 this.alphaMap = null; 40610 40611 this.envMap = null; 40612 this.envMapIntensity = 1.0; 40613 40614 this.wireframe = false; 40615 this.wireframeLinewidth = 1; 40616 this.wireframeLinecap = 'round'; 40617 this.wireframeLinejoin = 'round'; 40618 40619 this.flatShading = false; 40620 40621 this.fog = true; 40622 40623 this.setValues( parameters ); 40624 40625 } 40626 40627 copy( source ) { 40628 40629 super.copy( source ); 40630 40631 this.defines = { 'STANDARD': '' }; 40632 40633 this.color.copy( source.color ); 40634 this.roughness = source.roughness; 40635 this.metalness = source.metalness; 40636 40637 this.map = source.map; 40638 40639 this.lightMap = source.lightMap; 40640 this.lightMapIntensity = source.lightMapIntensity; 40641 40642 this.aoMap = source.aoMap; 40643 this.aoMapIntensity = source.aoMapIntensity; 40644 40645 this.emissive.copy( source.emissive ); 40646 this.emissiveMap = source.emissiveMap; 40647 this.emissiveIntensity = source.emissiveIntensity; 40648 40649 this.bumpMap = source.bumpMap; 40650 this.bumpScale = source.bumpScale; 40651 40652 this.normalMap = source.normalMap; 40653 this.normalMapType = source.normalMapType; 40654 this.normalScale.copy( source.normalScale ); 40655 40656 this.displacementMap = source.displacementMap; 40657 this.displacementScale = source.displacementScale; 40658 this.displacementBias = source.displacementBias; 40659 40660 this.roughnessMap = source.roughnessMap; 40661 40662 this.metalnessMap = source.metalnessMap; 40663 40664 this.alphaMap = source.alphaMap; 40665 40666 this.envMap = source.envMap; 40667 this.envMapIntensity = source.envMapIntensity; 40668 40669 this.wireframe = source.wireframe; 40670 this.wireframeLinewidth = source.wireframeLinewidth; 40671 this.wireframeLinecap = source.wireframeLinecap; 40672 this.wireframeLinejoin = source.wireframeLinejoin; 40673 40674 this.flatShading = source.flatShading; 40675 40676 this.fog = source.fog; 40677 40678 return this; 40679 40680 } 40681 40682} 40683 40684class MeshPhysicalMaterial extends MeshStandardMaterial { 40685 40686 constructor( parameters ) { 40687 40688 super(); 40689 40690 this.isMeshPhysicalMaterial = true; 40691 40692 this.defines = { 40693 40694 'STANDARD': '', 40695 'PHYSICAL': '' 40696 40697 }; 40698 40699 this.type = 'MeshPhysicalMaterial'; 40700 40701 this.anisotropyRotation = 0; 40702 this.anisotropyMap = null; 40703 40704 this.clearcoatMap = null; 40705 this.clearcoatRoughness = 0.0; 40706 this.clearcoatRoughnessMap = null; 40707 this.clearcoatNormalScale = new Vector2( 1, 1 ); 40708 this.clearcoatNormalMap = null; 40709 40710 this.ior = 1.5; 40711 40712 Object.defineProperty( this, 'reflectivity', { 40713 get: function () { 40714 40715 return ( clamp( 2.5 * ( this.ior - 1 ) / ( this.ior + 1 ), 0, 1 ) ); 40716 40717 }, 40718 set: function ( reflectivity ) { 40719 40720 this.ior = ( 1 + 0.4 * reflectivity ) / ( 1 - 0.4 * reflectivity ); 40721 40722 } 40723 } ); 40724 40725 this.iridescenceMap = null; 40726 this.iridescenceIOR = 1.3; 40727 this.iridescenceThicknessRange = [ 100, 400 ]; 40728 this.iridescenceThicknessMap = null; 40729 40730 this.sheenColor = new Color( 0x000000 ); 40731 this.sheenColorMap = null; 40732 this.sheenRoughness = 1.0; 40733 this.sheenRoughnessMap = null; 40734 40735 this.transmissionMap = null; 40736 40737 this.thickness = 0; 40738 this.thicknessMap = null; 40739 this.attenuationDistance = Infinity; 40740 this.attenuationColor = new Color( 1, 1, 1 ); 40741 40742 this.specularIntensity = 1.0; 40743 this.specularIntensityMap = null; 40744 this.specularColor = new Color( 1, 1, 1 ); 40745 this.specularColorMap = null; 40746 40747 this._anisotropy = 0; 40748 this._clearcoat = 0; 40749 this._iridescence = 0; 40750 this._sheen = 0.0; 40751 this._transmission = 0; 40752 40753 this.setValues( parameters ); 40754 40755 } 40756 40757 get anisotropy() { 40758 40759 return this._anisotropy; 40760 40761 } 40762 40763 set anisotropy( value ) { 40764 40765 if ( this._anisotropy > 0 !== value > 0 ) { 40766 40767 this.version ++; 40768 40769 } 40770 40771 this._anisotropy = value; 40772 40773 } 40774 40775 get clearcoat() { 40776 40777 return this._clearcoat; 40778 40779 } 40780 40781 set clearcoat( value ) { 40782 40783 if ( this._clearcoat > 0 !== value > 0 ) { 40784 40785 this.version ++; 40786 40787 } 40788 40789 this._clearcoat = value; 40790 40791 } 40792 40793 get iridescence() { 40794 40795 return this._iridescence; 40796 40797 } 40798 40799 set iridescence( value ) { 40800 40801 if ( this._iridescence > 0 !== value > 0 ) { 40802 40803 this.version ++; 40804 40805 } 40806 40807 this._iridescence = value; 40808 40809 } 40810 40811 get sheen() { 40812 40813 return this._sheen; 40814 40815 } 40816 40817 set sheen( value ) { 40818 40819 if ( this._sheen > 0 !== value > 0 ) { 40820 40821 this.version ++; 40822 40823 } 40824 40825 this._sheen = value; 40826 40827 } 40828 40829 get transmission() { 40830 40831 return this._transmission; 40832 40833 } 40834 40835 set transmission( value ) { 40836 40837 if ( this._transmission > 0 !== value > 0 ) { 40838 40839 this.version ++; 40840 40841 } 40842 40843 this._transmission = value; 40844 40845 } 40846 40847 copy( source ) { 40848 40849 super.copy( source ); 40850 40851 this.defines = { 40852 40853 'STANDARD': '', 40854 'PHYSICAL': '' 40855 40856 }; 40857 40858 this.anisotropy = source.anisotropy; 40859 this.anisotropyRotation = source.anisotropyRotation; 40860 this.anisotropyMap = source.anisotropyMap; 40861 40862 this.clearcoat = source.clearcoat; 40863 this.clearcoatMap = source.clearcoatMap; 40864 this.clearcoatRoughness = source.clearcoatRoughness; 40865 this.clearcoatRoughnessMap = source.clearcoatRoughnessMap; 40866 this.clearcoatNormalMap = source.clearcoatNormalMap; 40867 this.clearcoatNormalScale.copy( source.clearcoatNormalScale ); 40868 40869 this.ior = source.ior; 40870 40871 this.iridescence = source.iridescence; 40872 this.iridescenceMap = source.iridescenceMap; 40873 this.iridescenceIOR = source.iridescenceIOR; 40874 this.iridescenceThicknessRange = [ ...source.iridescenceThicknessRange ]; 40875 this.iridescenceThicknessMap = source.iridescenceThicknessMap; 40876 40877 this.sheen = source.sheen; 40878 this.sheenColor.copy( source.sheenColor ); 40879 this.sheenColorMap = source.sheenColorMap; 40880 this.sheenRoughness = source.sheenRoughness; 40881 this.sheenRoughnessMap = source.sheenRoughnessMap; 40882 40883 this.transmission = source.transmission; 40884 this.transmissionMap = source.transmissionMap; 40885 40886 this.thickness = source.thickness; 40887 this.thicknessMap = source.thicknessMap; 40888 this.attenuationDistance = source.attenuationDistance; 40889 this.attenuationColor.copy( source.attenuationColor ); 40890 40891 this.specularIntensity = source.specularIntensity; 40892 this.specularIntensityMap = source.specularIntensityMap; 40893 this.specularColor.copy( source.specularColor ); 40894 this.specularColorMap = source.specularColorMap; 40895 40896 return this; 40897 40898 } 40899 40900} 40901 40902class MeshPhongMaterial extends Material { 40903 40904 constructor( parameters ) { 40905 40906 super(); 40907 40908 this.isMeshPhongMaterial = true; 40909 40910 this.type = 'MeshPhongMaterial'; 40911 40912 this.color = new Color( 0xffffff ); // diffuse 40913 this.specular = new Color( 0x111111 ); 40914 this.shininess = 30; 40915 40916 this.map = null; 40917 40918 this.lightMap = null; 40919 this.lightMapIntensity = 1.0; 40920 40921 this.aoMap = null; 40922 this.aoMapIntensity = 1.0; 40923 40924 this.emissive = new Color( 0x000000 ); 40925 this.emissiveIntensity = 1.0; 40926 this.emissiveMap = null; 40927 40928 this.bumpMap = null; 40929 this.bumpScale = 1; 40930 40931 this.normalMap = null; 40932 this.normalMapType = TangentSpaceNormalMap; 40933 this.normalScale = new Vector2( 1, 1 ); 40934 40935 this.displacementMap = null; 40936 this.displacementScale = 1; 40937 this.displacementBias = 0; 40938 40939 this.specularMap = null; 40940 40941 this.alphaMap = null; 40942 40943 this.envMap = null; 40944 this.combine = MultiplyOperation; 40945 this.reflectivity = 1; 40946 this.refractionRatio = 0.98; 40947 40948 this.wireframe = false; 40949 this.wireframeLinewidth = 1; 40950 this.wireframeLinecap = 'round'; 40951 this.wireframeLinejoin = 'round'; 40952 40953 this.flatShading = false; 40954 40955 this.fog = true; 40956 40957 this.setValues( parameters ); 40958 40959 } 40960 40961 copy( source ) { 40962 40963 super.copy( source ); 40964 40965 this.color.copy( source.color ); 40966 this.specular.copy( source.specular ); 40967 this.shininess = source.shininess; 40968 40969 this.map = source.map; 40970 40971 this.lightMap = source.lightMap; 40972 this.lightMapIntensity = source.lightMapIntensity; 40973 40974 this.aoMap = source.aoMap; 40975 this.aoMapIntensity = source.aoMapIntensity; 40976 40977 this.emissive.copy( source.emissive ); 40978 this.emissiveMap = source.emissiveMap; 40979 this.emissiveIntensity = source.emissiveIntensity; 40980 40981 this.bumpMap = source.bumpMap; 40982 this.bumpScale = source.bumpScale; 40983 40984 this.normalMap = source.normalMap; 40985 this.normalMapType = source.normalMapType; 40986 this.normalScale.copy( source.normalScale ); 40987 40988 this.displacementMap = source.displacementMap; 40989 this.displacementScale = source.displacementScale; 40990 this.displacementBias = source.displacementBias; 40991 40992 this.specularMap = source.specularMap; 40993 40994 this.alphaMap = source.alphaMap; 40995 40996 this.envMap = source.envMap; 40997 this.combine = source.combine; 40998 this.reflectivity = source.reflectivity; 40999 this.refractionRatio = source.refractionRatio; 41000 41001 this.wireframe = source.wireframe; 41002 this.wireframeLinewidth = source.wireframeLinewidth; 41003 this.wireframeLinecap = source.wireframeLinecap; 41004 this.wireframeLinejoin = source.wireframeLinejoin; 41005 41006 this.flatShading = source.flatShading; 41007 41008 this.fog = source.fog; 41009 41010 return this; 41011 41012 } 41013 41014} 41015 41016class MeshToonMaterial extends Material { 41017 41018 constructor( parameters ) { 41019 41020 super(); 41021 41022 this.isMeshToonMaterial = true; 41023 41024 this.defines = { 'TOON': '' }; 41025 41026 this.type = 'MeshToonMaterial'; 41027 41028 this.color = new Color( 0xffffff ); 41029 41030 this.map = null; 41031 this.gradientMap = null; 41032 41033 this.lightMap = null; 41034 this.lightMapIntensity = 1.0; 41035 41036 this.aoMap = null; 41037 this.aoMapIntensity = 1.0; 41038 41039 this.emissive = new Color( 0x000000 ); 41040 this.emissiveIntensity = 1.0; 41041 this.emissiveMap = null; 41042 41043 this.bumpMap = null; 41044 this.bumpScale = 1; 41045 41046 this.normalMap = null; 41047 this.normalMapType = TangentSpaceNormalMap; 41048 this.normalScale = new Vector2( 1, 1 ); 41049 41050 this.displacementMap = null; 41051 this.displacementScale = 1; 41052 this.displacementBias = 0; 41053 41054 this.alphaMap = null; 41055 41056 this.wireframe = false; 41057 this.wireframeLinewidth = 1; 41058 this.wireframeLinecap = 'round'; 41059 this.wireframeLinejoin = 'round'; 41060 41061 this.fog = true; 41062 41063 this.setValues( parameters ); 41064 41065 } 41066 41067 copy( source ) { 41068 41069 super.copy( source ); 41070 41071 this.color.copy( source.color ); 41072 41073 this.map = source.map; 41074 this.gradientMap = source.gradientMap; 41075 41076 this.lightMap = source.lightMap; 41077 this.lightMapIntensity = source.lightMapIntensity; 41078 41079 this.aoMap = source.aoMap; 41080 this.aoMapIntensity = source.aoMapIntensity; 41081 41082 this.emissive.copy( source.emissive ); 41083 this.emissiveMap = source.emissiveMap; 41084 this.emissiveIntensity = source.emissiveIntensity; 41085 41086 this.bumpMap = source.bumpMap; 41087 this.bumpScale = source.bumpScale; 41088 41089 this.normalMap = source.normalMap; 41090 this.normalMapType = source.normalMapType; 41091 this.normalScale.copy( source.normalScale ); 41092 41093 this.displacementMap = source.displacementMap; 41094 this.displacementScale = source.displacementScale; 41095 this.displacementBias = source.displacementBias; 41096 41097 this.alphaMap = source.alphaMap; 41098 41099 this.wireframe = source.wireframe; 41100 this.wireframeLinewidth = source.wireframeLinewidth; 41101 this.wireframeLinecap = source.wireframeLinecap; 41102 this.wireframeLinejoin = source.wireframeLinejoin; 41103 41104 this.fog = source.fog; 41105 41106 return this; 41107 41108 } 41109 41110} 41111 41112class MeshNormalMaterial extends Material { 41113 41114 constructor( parameters ) { 41115 41116 super(); 41117 41118 this.isMeshNormalMaterial = true; 41119 41120 this.type = 'MeshNormalMaterial'; 41121 41122 this.bumpMap = null; 41123 this.bumpScale = 1; 41124 41125 this.normalMap = null; 41126 this.normalMapType = TangentSpaceNormalMap; 41127 this.normalScale = new Vector2( 1, 1 ); 41128 41129 this.displacementMap = null; 41130 this.displacementScale = 1; 41131 this.displacementBias = 0; 41132 41133 this.wireframe = false; 41134 this.wireframeLinewidth = 1; 41135 41136 this.flatShading = false; 41137 41138 this.setValues( parameters ); 41139 41140 } 41141 41142 copy( source ) { 41143 41144 super.copy( source ); 41145 41146 this.bumpMap = source.bumpMap; 41147 this.bumpScale = source.bumpScale; 41148 41149 this.normalMap = source.normalMap; 41150 this.normalMapType = source.normalMapType; 41151 this.normalScale.copy( source.normalScale ); 41152 41153 this.displacementMap = source.displacementMap; 41154 this.displacementScale = source.displacementScale; 41155 this.displacementBias = source.displacementBias; 41156 41157 this.wireframe = source.wireframe; 41158 this.wireframeLinewidth = source.wireframeLinewidth; 41159 41160 this.flatShading = source.flatShading; 41161 41162 return this; 41163 41164 } 41165 41166} 41167 41168class MeshLambertMaterial extends Material { 41169 41170 constructor( parameters ) { 41171 41172 super(); 41173 41174 this.isMeshLambertMaterial = true; 41175 41176 this.type = 'MeshLambertMaterial'; 41177 41178 this.color = new Color( 0xffffff ); // diffuse 41179 41180 this.map = null; 41181 41182 this.lightMap = null; 41183 this.lightMapIntensity = 1.0; 41184 41185 this.aoMap = null; 41186 this.aoMapIntensity = 1.0; 41187 41188 this.emissive = new Color( 0x000000 ); 41189 this.emissiveIntensity = 1.0; 41190 this.emissiveMap = null; 41191 41192 this.bumpMap = null; 41193 this.bumpScale = 1; 41194 41195 this.normalMap = null; 41196 this.normalMapType = TangentSpaceNormalMap; 41197 this.normalScale = new Vector2( 1, 1 ); 41198 41199 this.displacementMap = null; 41200 this.displacementScale = 1; 41201 this.displacementBias = 0; 41202 41203 this.specularMap = null; 41204 41205 this.alphaMap = null; 41206 41207 this.envMap = null; 41208 this.combine = MultiplyOperation; 41209 this.reflectivity = 1; 41210 this.refractionRatio = 0.98; 41211 41212 this.wireframe = false; 41213 this.wireframeLinewidth = 1; 41214 this.wireframeLinecap = 'round'; 41215 this.wireframeLinejoin = 'round'; 41216 41217 this.flatShading = false; 41218 41219 this.fog = true; 41220 41221 this.setValues( parameters ); 41222 41223 } 41224 41225 copy( source ) { 41226 41227 super.copy( source ); 41228 41229 this.color.copy( source.color ); 41230 41231 this.map = source.map; 41232 41233 this.lightMap = source.lightMap; 41234 this.lightMapIntensity = source.lightMapIntensity; 41235 41236 this.aoMap = source.aoMap; 41237 this.aoMapIntensity = source.aoMapIntensity; 41238 41239 this.emissive.copy( source.emissive ); 41240 this.emissiveMap = source.emissiveMap; 41241 this.emissiveIntensity = source.emissiveIntensity; 41242 41243 this.bumpMap = source.bumpMap; 41244 this.bumpScale = source.bumpScale; 41245 41246 this.normalMap = source.normalMap; 41247 this.normalMapType = source.normalMapType; 41248 this.normalScale.copy( source.normalScale ); 41249 41250 this.displacementMap = source.displacementMap; 41251 this.displacementScale = source.displacementScale; 41252 this.displacementBias = source.displacementBias; 41253 41254 this.specularMap = source.specularMap; 41255 41256 this.alphaMap = source.alphaMap; 41257 41258 this.envMap = source.envMap; 41259 this.combine = source.combine; 41260 this.reflectivity = source.reflectivity; 41261 this.refractionRatio = source.refractionRatio; 41262 41263 this.wireframe = source.wireframe; 41264 this.wireframeLinewidth = source.wireframeLinewidth; 41265 this.wireframeLinecap = source.wireframeLinecap; 41266 this.wireframeLinejoin = source.wireframeLinejoin; 41267 41268 this.flatShading = source.flatShading; 41269 41270 this.fog = source.fog; 41271 41272 return this; 41273 41274 } 41275 41276} 41277 41278class MeshMatcapMaterial extends Material { 41279 41280 constructor( parameters ) { 41281 41282 super(); 41283 41284 this.isMeshMatcapMaterial = true; 41285 41286 this.defines = { 'MATCAP': '' }; 41287 41288 this.type = 'MeshMatcapMaterial'; 41289 41290 this.color = new Color( 0xffffff ); // diffuse 41291 41292 this.matcap = null; 41293 41294 this.map = null; 41295 41296 this.bumpMap = null; 41297 this.bumpScale = 1; 41298 41299 this.normalMap = null; 41300 this.normalMapType = TangentSpaceNormalMap; 41301 this.normalScale = new Vector2( 1, 1 ); 41302 41303 this.displacementMap = null; 41304 this.displacementScale = 1; 41305 this.displacementBias = 0; 41306 41307 this.alphaMap = null; 41308 41309 this.flatShading = false; 41310 41311 this.fog = true; 41312 41313 this.setValues( parameters ); 41314 41315 } 41316 41317 41318 copy( source ) { 41319 41320 super.copy( source ); 41321 41322 this.defines = { 'MATCAP': '' }; 41323 41324 this.color.copy( source.color ); 41325 41326 this.matcap = source.matcap; 41327 41328 this.map = source.map; 41329 41330 this.bumpMap = source.bumpMap; 41331 this.bumpScale = source.bumpScale; 41332 41333 this.normalMap = source.normalMap; 41334 this.normalMapType = source.normalMapType; 41335 this.normalScale.copy( source.normalScale ); 41336 41337 this.displacementMap = source.displacementMap; 41338 this.displacementScale = source.displacementScale; 41339 this.displacementBias = source.displacementBias; 41340 41341 this.alphaMap = source.alphaMap; 41342 41343 this.flatShading = source.flatShading; 41344 41345 this.fog = source.fog; 41346 41347 return this; 41348 41349 } 41350 41351} 41352 41353class LineDashedMaterial extends LineBasicMaterial { 41354 41355 constructor( parameters ) { 41356 41357 super(); 41358 41359 this.isLineDashedMaterial = true; 41360 41361 this.type = 'LineDashedMaterial'; 41362 41363 this.scale = 1; 41364 this.dashSize = 3; 41365 this.gapSize = 1; 41366 41367 this.setValues( parameters ); 41368 41369 } 41370 41371 copy( source ) { 41372 41373 super.copy( source ); 41374 41375 this.scale = source.scale; 41376 this.dashSize = source.dashSize; 41377 this.gapSize = source.gapSize; 41378 41379 return this; 41380 41381 } 41382 41383} 41384 41385// converts an array to a specific type 41386function convertArray( array, type, forceClone ) { 41387 41388 if ( ! array || // let 'undefined' and 'null' pass 41389 ! forceClone && array.constructor === type ) return array; 41390 41391 if ( typeof type.BYTES_PER_ELEMENT === 'number' ) { 41392 41393 return new type( array ); // create typed array 41394 41395 } 41396 41397 return Array.prototype.slice.call( array ); // create Array 41398 41399} 41400 41401function isTypedArray( object ) { 41402 41403 return ArrayBuffer.isView( object ) && 41404 ! ( object instanceof DataView ); 41405 41406} 41407 41408// returns an array by which times and values can be sorted 41409function getKeyframeOrder( times ) { 41410 41411 function compareTime( i, j ) { 41412 41413 return times[ i ] - times[ j ]; 41414 41415 } 41416 41417 const n = times.length; 41418 const result = new Array( n ); 41419 for ( let i = 0; i !== n; ++ i ) result[ i ] = i; 41420 41421 result.sort( compareTime ); 41422 41423 return result; 41424 41425} 41426 41427// uses the array previously returned by 'getKeyframeOrder' to sort data 41428function sortedArray( values, stride, order ) { 41429 41430 const nValues = values.length; 41431 const result = new values.constructor( nValues ); 41432 41433 for ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { 41434 41435 const srcOffset = order[ i ] * stride; 41436 41437 for ( let j = 0; j !== stride; ++ j ) { 41438 41439 result[ dstOffset ++ ] = values[ srcOffset + j ]; 41440 41441 } 41442 41443 } 41444 41445 return result; 41446 41447} 41448 41449// function for parsing AOS keyframe formats 41450function flattenJSON( jsonKeys, times, values, valuePropertyName ) { 41451 41452 let i = 1, key = jsonKeys[ 0 ]; 41453 41454 while ( key !== undefined && key[ valuePropertyName ] === undefined ) { 41455 41456 key = jsonKeys[ i ++ ]; 41457 41458 } 41459 41460 if ( key === undefined ) return; // no data 41461 41462 let value = key[ valuePropertyName ]; 41463 if ( value === undefined ) return; // no data 41464 41465 if ( Array.isArray( value ) ) { 41466 41467 do { 41468 41469 value = key[ valuePropertyName ]; 41470 41471 if ( value !== undefined ) { 41472 41473 times.push( key.time ); 41474 values.push.apply( values, value ); // push all elements 41475 41476 } 41477 41478 key = jsonKeys[ i ++ ]; 41479 41480 } while ( key !== undefined ); 41481 41482 } else if ( value.toArray !== undefined ) { 41483 41484 // ...assume THREE.Math-ish 41485 41486 do { 41487 41488 value = key[ valuePropertyName ]; 41489 41490 if ( value !== undefined ) { 41491 41492 times.push( key.time ); 41493 value.toArray( values, values.length ); 41494 41495 } 41496 41497 key = jsonKeys[ i ++ ]; 41498 41499 } while ( key !== undefined ); 41500 41501 } else { 41502 41503 // otherwise push as-is 41504 41505 do { 41506 41507 value = key[ valuePropertyName ]; 41508 41509 if ( value !== undefined ) { 41510 41511 times.push( key.time ); 41512 values.push( value ); 41513 41514 } 41515 41516 key = jsonKeys[ i ++ ]; 41517 41518 } while ( key !== undefined ); 41519 41520 } 41521 41522} 41523 41524function subclip( sourceClip, name, startFrame, endFrame, fps = 30 ) { 41525 41526 const clip = sourceClip.clone(); 41527 41528 clip.name = name; 41529 41530 const tracks = []; 41531 41532 for ( let i = 0; i < clip.tracks.length; ++ i ) { 41533 41534 const track = clip.tracks[ i ]; 41535 const valueSize = track.getValueSize(); 41536 41537 const times = []; 41538 const values = []; 41539 41540 for ( let j = 0; j < track.times.length; ++ j ) { 41541 41542 const frame = track.times[ j ] * fps; 41543 41544 if ( frame < startFrame || frame >= endFrame ) continue; 41545 41546 times.push( track.times[ j ] ); 41547 41548 for ( let k = 0; k < valueSize; ++ k ) { 41549 41550 values.push( track.values[ j * valueSize + k ] ); 41551 41552 } 41553 41554 } 41555 41556 if ( times.length === 0 ) continue; 41557 41558 track.times = convertArray( times, track.times.constructor ); 41559 track.values = convertArray( values, track.values.constructor ); 41560 41561 tracks.push( track ); 41562 41563 } 41564 41565 clip.tracks = tracks; 41566 41567 // find minimum .times value across all tracks in the trimmed clip 41568 41569 let minStartTime = Infinity; 41570 41571 for ( let i = 0; i < clip.tracks.length; ++ i ) { 41572 41573 if ( minStartTime > clip.tracks[ i ].times[ 0 ] ) { 41574 41575 minStartTime = clip.tracks[ i ].times[ 0 ]; 41576 41577 } 41578 41579 } 41580 41581 // shift all tracks such that clip begins at t=0 41582 41583 for ( let i = 0; i < clip.tracks.length; ++ i ) { 41584 41585 clip.tracks[ i ].shift( - 1 * minStartTime ); 41586 41587 } 41588 41589 clip.resetDuration(); 41590 41591 return clip; 41592 41593} 41594 41595function makeClipAdditive( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) { 41596 41597 if ( fps <= 0 ) fps = 30; 41598 41599 const numTracks = referenceClip.tracks.length; 41600 const referenceTime = referenceFrame / fps; 41601 41602 // Make each track's values relative to the values at the reference frame 41603 for ( let i = 0; i < numTracks; ++ i ) { 41604 41605 const referenceTrack = referenceClip.tracks[ i ]; 41606 const referenceTrackType = referenceTrack.ValueTypeName; 41607 41608 // Skip this track if it's non-numeric 41609 if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue; 41610 41611 // Find the track in the target clip whose name and type matches the reference track 41612 const targetTrack = targetClip.tracks.find( function ( track ) { 41613 41614 return track.name === referenceTrack.name 41615 && track.ValueTypeName === referenceTrackType; 41616 41617 } ); 41618 41619 if ( targetTrack === undefined ) continue; 41620 41621 let referenceOffset = 0; 41622 const referenceValueSize = referenceTrack.getValueSize(); 41623 41624 if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { 41625 41626 referenceOffset = referenceValueSize / 3; 41627 41628 } 41629 41630 let targetOffset = 0; 41631 const targetValueSize = targetTrack.getValueSize(); 41632 41633 if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { 41634 41635 targetOffset = targetValueSize / 3; 41636 41637 } 41638 41639 const lastIndex = referenceTrack.times.length - 1; 41640 let referenceValue; 41641 41642 // Find the value to subtract out of the track 41643 if ( referenceTime <= referenceTrack.times[ 0 ] ) { 41644 41645 // Reference frame is earlier than the first keyframe, so just use the first keyframe 41646 const startIndex = referenceOffset; 41647 const endIndex = referenceValueSize - referenceOffset; 41648 referenceValue = referenceTrack.values.slice( startIndex, endIndex ); 41649 41650 } else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) { 41651 41652 // Reference frame is after the last keyframe, so just use the last keyframe 41653 const startIndex = lastIndex * referenceValueSize + referenceOffset; 41654 const endIndex = startIndex + referenceValueSize - referenceOffset; 41655 referenceValue = referenceTrack.values.slice( startIndex, endIndex ); 41656 41657 } else { 41658 41659 // Interpolate to the reference value 41660 const interpolant = referenceTrack.createInterpolant(); 41661 const startIndex = referenceOffset; 41662 const endIndex = referenceValueSize - referenceOffset; 41663 interpolant.evaluate( referenceTime ); 41664 referenceValue = interpolant.resultBuffer.slice( startIndex, endIndex ); 41665 41666 } 41667 41668 // Conjugate the quaternion 41669 if ( referenceTrackType === 'quaternion' ) { 41670 41671 const referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate(); 41672 referenceQuat.toArray( referenceValue ); 41673 41674 } 41675 41676 // Subtract the reference value from all of the track values 41677 41678 const numTimes = targetTrack.times.length; 41679 for ( let j = 0; j < numTimes; ++ j ) { 41680 41681 const valueStart = j * targetValueSize + targetOffset; 41682 41683 if ( referenceTrackType === 'quaternion' ) { 41684 41685 // Multiply the conjugate for quaternion track types 41686 Quaternion.multiplyQuaternionsFlat( 41687 targetTrack.values, 41688 valueStart, 41689 referenceValue, 41690 0, 41691 targetTrack.values, 41692 valueStart 41693 ); 41694 41695 } else { 41696 41697 const valueEnd = targetValueSize - targetOffset * 2; 41698 41699 // Subtract each value for all other numeric track types 41700 for ( let k = 0; k < valueEnd; ++ k ) { 41701 41702 targetTrack.values[ valueStart + k ] -= referenceValue[ k ]; 41703 41704 } 41705 41706 } 41707 41708 } 41709 41710 } 41711 41712 targetClip.blendMode = AdditiveAnimationBlendMode; 41713 41714 return targetClip; 41715 41716} 41717 41718const AnimationUtils = { 41719 convertArray: convertArray, 41720 isTypedArray: isTypedArray, 41721 getKeyframeOrder: getKeyframeOrder, 41722 sortedArray: sortedArray, 41723 flattenJSON: flattenJSON, 41724 subclip: subclip, 41725 makeClipAdditive: makeClipAdditive 41726}; 41727 41728/** 41729 * Abstract base class of interpolants over parametric samples. 41730 * 41731 * The parameter domain is one dimensional, typically the time or a path 41732 * along a curve defined by the data. 41733 * 41734 * The sample values can have any dimensionality and derived classes may 41735 * apply special interpretations to the data. 41736 * 41737 * This class provides the interval seek in a Template Method, deferring 41738 * the actual interpolation to derived classes. 41739 * 41740 * Time complexity is O(1) for linear access crossing at most two points 41741 * and O(log N) for random access, where N is the number of positions. 41742 * 41743 * References: 41744 * 41745 * http://www.oodesign.com/template-method-pattern.html 41746 * 41747 */ 41748 41749class Interpolant { 41750 41751 constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { 41752 41753 this.parameterPositions = parameterPositions; 41754 this._cachedIndex = 0; 41755 41756 this.resultBuffer = resultBuffer !== undefined ? 41757 resultBuffer : new sampleValues.constructor( sampleSize ); 41758 this.sampleValues = sampleValues; 41759 this.valueSize = sampleSize; 41760 41761 this.settings = null; 41762 this.DefaultSettings_ = {}; 41763 41764 } 41765 41766 evaluate( t ) { 41767 41768 const pp = this.parameterPositions; 41769 let i1 = this._cachedIndex, 41770 t1 = pp[ i1 ], 41771 t0 = pp[ i1 - 1 ]; 41772 41773 validate_interval: { 41774 41775 seek: { 41776 41777 let right; 41778 41779 linear_scan: { 41780 41781 //- See http://jsperf.com/comparison-to-undefined/3 41782 //- slower code: 41783 //- 41784 //- if ( t >= t1 || t1 === undefined ) { 41785 forward_scan: if ( ! ( t < t1 ) ) { 41786 41787 for ( let giveUpAt = i1 + 2; ; ) { 41788 41789 if ( t1 === undefined ) { 41790 41791 if ( t < t0 ) break forward_scan; 41792 41793 // after end 41794 41795 i1 = pp.length; 41796 this._cachedIndex = i1; 41797 return this.copySampleValue_( i1 - 1 ); 41798 41799 } 41800 41801 if ( i1 === giveUpAt ) break; // this loop 41802 41803 t0 = t1; 41804 t1 = pp[ ++ i1 ]; 41805 41806 if ( t < t1 ) { 41807 41808 // we have arrived at the sought interval 41809 break seek; 41810 41811 } 41812 41813 } 41814 41815 // prepare binary search on the right side of the index 41816 right = pp.length; 41817 break linear_scan; 41818 41819 } 41820 41821 //- slower code: 41822 //- if ( t < t0 || t0 === undefined ) { 41823 if ( ! ( t >= t0 ) ) { 41824 41825 // looping? 41826 41827 const t1global = pp[ 1 ]; 41828 41829 if ( t < t1global ) { 41830 41831 i1 = 2; // + 1, using the scan for the details 41832 t0 = t1global; 41833 41834 } 41835 41836 // linear reverse scan 41837 41838 for ( let giveUpAt = i1 - 2; ; ) { 41839 41840 if ( t0 === undefined ) { 41841 41842 // before start 41843 41844 this._cachedIndex = 0; 41845 return this.copySampleValue_( 0 ); 41846 41847 } 41848 41849 if ( i1 === giveUpAt ) break; // this loop 41850 41851 t1 = t0; 41852 t0 = pp[ -- i1 - 1 ]; 41853 41854 if ( t >= t0 ) { 41855 41856 // we have arrived at the sought interval 41857 break seek; 41858 41859 } 41860 41861 } 41862 41863 // prepare binary search on the left side of the index 41864 right = i1; 41865 i1 = 0; 41866 break linear_scan; 41867 41868 } 41869 41870 // the interval is valid 41871 41872 break validate_interval; 41873 41874 } // linear scan 41875 41876 // binary search 41877 41878 while ( i1 < right ) { 41879 41880 const mid = ( i1 + right ) >>> 1; 41881 41882 if ( t < pp[ mid ] ) { 41883 41884 right = mid; 41885 41886 } else { 41887 41888 i1 = mid + 1; 41889 41890 } 41891 41892 } 41893 41894 t1 = pp[ i1 ]; 41895 t0 = pp[ i1 - 1 ]; 41896 41897 // check boundary cases, again 41898 41899 if ( t0 === undefined ) { 41900 41901 this._cachedIndex = 0; 41902 return this.copySampleValue_( 0 ); 41903 41904 } 41905 41906 if ( t1 === undefined ) { 41907 41908 i1 = pp.length; 41909 this._cachedIndex = i1; 41910 return this.copySampleValue_( i1 - 1 ); 41911 41912 } 41913 41914 } // seek 41915 41916 this._cachedIndex = i1; 41917 41918 this.intervalChanged_( i1, t0, t1 ); 41919 41920 } // validate_interval 41921 41922 return this.interpolate_( i1, t0, t, t1 ); 41923 41924 } 41925 41926 getSettings_() { 41927 41928 return this.settings || this.DefaultSettings_; 41929 41930 } 41931 41932 copySampleValue_( index ) { 41933 41934 // copies a sample value to the result buffer 41935 41936 const result = this.resultBuffer, 41937 values = this.sampleValues, 41938 stride = this.valueSize, 41939 offset = index * stride; 41940 41941 for ( let i = 0; i !== stride; ++ i ) { 41942 41943 result[ i ] = values[ offset + i ]; 41944 41945 } 41946 41947 return result; 41948 41949 } 41950 41951 // Template methods for derived classes: 41952 41953 interpolate_( /* i1, t0, t, t1 */ ) { 41954 41955 throw new Error( 'call to abstract method' ); 41956 // implementations shall return this.resultBuffer 41957 41958 } 41959 41960 intervalChanged_( /* i1, t0, t1 */ ) { 41961 41962 // empty 41963 41964 } 41965 41966} 41967 41968/** 41969 * Fast and simple cubic spline interpolant. 41970 * 41971 * It was derived from a Hermitian construction setting the first derivative 41972 * at each sample position to the linear slope between neighboring positions 41973 * over their parameter interval. 41974 */ 41975 41976class CubicInterpolant extends Interpolant { 41977 41978 constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { 41979 41980 super( parameterPositions, sampleValues, sampleSize, resultBuffer ); 41981 41982 this._weightPrev = - 0; 41983 this._offsetPrev = - 0; 41984 this._weightNext = - 0; 41985 this._offsetNext = - 0; 41986 41987 this.DefaultSettings_ = { 41988 41989 endingStart: ZeroCurvatureEnding, 41990 endingEnd: ZeroCurvatureEnding 41991 41992 }; 41993 41994 } 41995 41996 intervalChanged_( i1, t0, t1 ) { 41997 41998 const pp = this.parameterPositions; 41999 let iPrev = i1 - 2, 42000 iNext = i1 + 1, 42001 42002 tPrev = pp[ iPrev ], 42003 tNext = pp[ iNext ]; 42004 42005 if ( tPrev === undefined ) { 42006 42007 switch ( this.getSettings_().endingStart ) { 42008 42009 case ZeroSlopeEnding: 42010 42011 // f'(t0) = 0 42012 iPrev = i1; 42013 tPrev = 2 * t0 - t1; 42014 42015 break; 42016 42017 case WrapAroundEnding: 42018 42019 // use the other end of the curve 42020 iPrev = pp.length - 2; 42021 tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; 42022 42023 break; 42024 42025 default: // ZeroCurvatureEnding 42026 42027 // f''(t0) = 0 a.k.a. Natural Spline 42028 iPrev = i1; 42029 tPrev = t1; 42030 42031 } 42032 42033 } 42034 42035 if ( tNext === undefined ) { 42036 42037 switch ( this.getSettings_().endingEnd ) { 42038 42039 case ZeroSlopeEnding: 42040 42041 // f'(tN) = 0 42042 iNext = i1; 42043 tNext = 2 * t1 - t0; 42044 42045 break; 42046 42047 case WrapAroundEnding: 42048 42049 // use the other end of the curve 42050 iNext = 1; 42051 tNext = t1 + pp[ 1 ] - pp[ 0 ]; 42052 42053 break; 42054 42055 default: // ZeroCurvatureEnding 42056 42057 // f''(tN) = 0, a.k.a. Natural Spline 42058 iNext = i1 - 1; 42059 tNext = t0; 42060 42061 } 42062 42063 } 42064 42065 const halfDt = ( t1 - t0 ) * 0.5, 42066 stride = this.valueSize; 42067 42068 this._weightPrev = halfDt / ( t0 - tPrev ); 42069 this._weightNext = halfDt / ( tNext - t1 ); 42070 this._offsetPrev = iPrev * stride; 42071 this._offsetNext = iNext * stride; 42072 42073 } 42074 42075 interpolate_( i1, t0, t, t1 ) { 42076 42077 const result = this.resultBuffer, 42078 values = this.sampleValues, 42079 stride = this.valueSize, 42080 42081 o1 = i1 * stride, o0 = o1 - stride, 42082 oP = this._offsetPrev, oN = this._offsetNext, 42083 wP = this._weightPrev, wN = this._weightNext, 42084 42085 p = ( t - t0 ) / ( t1 - t0 ), 42086 pp = p * p, 42087 ppp = pp * p; 42088 42089 // evaluate polynomials 42090 42091 const sP = - wP * ppp + 2 * wP * pp - wP * p; 42092 const s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1; 42093 const s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; 42094 const sN = wN * ppp - wN * pp; 42095 42096 // combine data linearly 42097 42098 for ( let i = 0; i !== stride; ++ i ) { 42099 42100 result[ i ] = 42101 sP * values[ oP + i ] + 42102 s0 * values[ o0 + i ] + 42103 s1 * values[ o1 + i ] + 42104 sN * values[ oN + i ]; 42105 42106 } 42107 42108 return result; 42109 42110 } 42111 42112} 42113 42114class LinearInterpolant extends Interpolant { 42115 42116 constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { 42117 42118 super( parameterPositions, sampleValues, sampleSize, resultBuffer ); 42119 42120 } 42121 42122 interpolate_( i1, t0, t, t1 ) { 42123 42124 const result = this.resultBuffer, 42125 values = this.sampleValues, 42126 stride = this.valueSize, 42127 42128 offset1 = i1 * stride, 42129 offset0 = offset1 - stride, 42130 42131 weight1 = ( t - t0 ) / ( t1 - t0 ), 42132 weight0 = 1 - weight1; 42133 42134 for ( let i = 0; i !== stride; ++ i ) { 42135 42136 result[ i ] = 42137 values[ offset0 + i ] * weight0 + 42138 values[ offset1 + i ] * weight1; 42139 42140 } 42141 42142 return result; 42143 42144 } 42145 42146} 42147 42148/** 42149 * 42150 * Interpolant that evaluates to the sample value at the position preceding 42151 * the parameter. 42152 */ 42153 42154class DiscreteInterpolant extends Interpolant { 42155 42156 constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { 42157 42158 super( parameterPositions, sampleValues, sampleSize, resultBuffer ); 42159 42160 } 42161 42162 interpolate_( i1 /*, t0, t, t1 */ ) { 42163 42164 return this.copySampleValue_( i1 - 1 ); 42165 42166 } 42167 42168} 42169 42170class KeyframeTrack { 42171 42172 constructor( name, times, values, interpolation ) { 42173 42174 if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' ); 42175 if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + n
vendor: 25,402 bytes, lines 42175-43499
42175ame ); 42176 42177 this.name = name; 42178 42179 this.times = convertArray( times, this.TimeBufferType ); 42180 this.values = convertArray( values, this.ValueBufferType ); 42181 42182 this.setInterpolation( interpolation || this.DefaultInterpolation ); 42183 42184 } 42185 42186 // Serialization (in static context, because of constructor invocation 42187 // and automatic invocation of .toJSON): 42188 42189 static toJSON( track ) { 42190 42191 const trackType = track.constructor; 42192 42193 let json; 42194 42195 // derived classes can define a static toJSON method 42196 if ( trackType.toJSON !== this.toJSON ) { 42197 42198 json = trackType.toJSON( track ); 42199 42200 } else { 42201 42202 // by default, we assume the data can be serialized as-is 42203 json = { 42204 42205 'name': track.name, 42206 'times': convertArray( track.times, Array ), 42207 'values': convertArray( track.values, Array ) 42208 42209 }; 42210 42211 const interpolation = track.getInterpolation(); 42212 42213 if ( interpolation !== track.DefaultInterpolation ) { 42214 42215 json.interpolation = interpolation; 42216 42217 } 42218 42219 } 42220 42221 json.type = track.ValueTypeName; // mandatory 42222 42223 return json; 42224 42225 } 42226 42227 InterpolantFactoryMethodDiscrete( result ) { 42228 42229 return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result ); 42230 42231 } 42232 42233 InterpolantFactoryMethodLinear( result ) { 42234 42235 return new LinearInterpolant( this.times, this.values, this.getValueSize(), result ); 42236 42237 } 42238 42239 InterpolantFactoryMethodSmooth( result ) { 42240 42241 return new CubicInterpolant( this.times, this.values, this.getValueSize(), result ); 42242 42243 } 42244 42245 setInterpolation( interpolation ) { 42246 42247 let factoryMethod; 42248 42249 switch ( interpolation ) { 42250 42251 case InterpolateDiscrete: 42252 42253 factoryMethod = this.InterpolantFactoryMethodDiscrete; 42254 42255 break; 42256 42257 case InterpolateLinear: 42258 42259 factoryMethod = this.InterpolantFactoryMethodLinear; 42260 42261 break; 42262 42263 case InterpolateSmooth: 42264 42265 factoryMethod = this.InterpolantFactoryMethodSmooth; 42266 42267 break; 42268 42269 } 42270 42271 if ( factoryMethod === undefined ) { 42272 42273 const message = 'unsupported interpolation for ' + 42274 this.ValueTypeName + ' keyframe track named ' + this.name; 42275 42276 if ( this.createInterpolant === undefined ) { 42277 42278 // fall back to default, unless the default itself is messed up 42279 if ( interpolation !== this.DefaultInterpolation ) { 42280 42281 this.setInterpolation( this.DefaultInterpolation ); 42282 42283 } else { 42284 42285 throw new Error( message ); // fatal, in this case 42286 42287 } 42288 42289 } 42290 42291 console.warn( 'THREE.KeyframeTrack:', message ); 42292 return this; 42293 42294 } 42295 42296 this.createInterpolant = factoryMethod; 42297 42298 return this; 42299 42300 } 42301 42302 getInterpolation() { 42303 42304 switch ( this.createInterpolant ) { 42305 42306 case this.InterpolantFactoryMethodDiscrete: 42307 42308 return InterpolateDiscrete; 42309 42310 case this.InterpolantFactoryMethodLinear: 42311 42312 return InterpolateLinear; 42313 42314 case this.InterpolantFactoryMethodSmooth: 42315 42316 return InterpolateSmooth; 42317 42318 } 42319 42320 } 42321 42322 getValueSize() { 42323 42324 return this.values.length / this.times.length; 42325 42326 } 42327 42328 // move all keyframes either forwards or backwards in time 42329 shift( timeOffset ) { 42330 42331 if ( timeOffset !== 0.0 ) { 42332 42333 const times = this.times; 42334 42335 for ( let i = 0, n = times.length; i !== n; ++ i ) { 42336 42337 times[ i ] += timeOffset; 42338 42339 } 42340 42341 } 42342 42343 return this; 42344 42345 } 42346 42347 // scale all keyframe times by a factor (useful for frame <-> seconds conversions) 42348 scale( timeScale ) { 42349 42350 if ( timeScale !== 1.0 ) { 42351 42352 const times = this.times; 42353 42354 for ( let i = 0, n = times.length; i !== n; ++ i ) { 42355 42356 times[ i ] *= timeScale; 42357 42358 } 42359 42360 } 42361 42362 return this; 42363 42364 } 42365 42366 // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. 42367 // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values 42368 trim( startTime, endTime ) { 42369 42370 const times = this.times, 42371 nKeys = times.length; 42372 42373 let from = 0, 42374 to = nKeys - 1; 42375 42376 while ( from !== nKeys && times[ from ] < startTime ) { 42377 42378 ++ from; 42379 42380 } 42381 42382 while ( to !== - 1 && times[ to ] > endTime ) { 42383 42384 -- to; 42385 42386 } 42387 42388 ++ to; // inclusive -> exclusive bound 42389 42390 if ( from !== 0 || to !== nKeys ) { 42391 42392 // empty tracks are forbidden, so keep at least one keyframe 42393 if ( from >= to ) { 42394 42395 to = Math.max( to, 1 ); 42396 from = to - 1; 42397 42398 } 42399 42400 const stride = this.getValueSize(); 42401 this.times = times.slice( from, to ); 42402 this.values = this.values.slice( from * stride, to * stride ); 42403 42404 } 42405 42406 return this; 42407 42408 } 42409 42410 // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable 42411 validate() { 42412 42413 let valid = true; 42414 42415 const valueSize = this.getValueSize(); 42416 if ( valueSize - Math.floor( valueSize ) !== 0 ) { 42417 42418 console.error( 'THREE.KeyframeTrack: Invalid value size in track.', this ); 42419 valid = false; 42420 42421 } 42422 42423 const times = this.times, 42424 values = this.values, 42425 42426 nKeys = times.length; 42427 42428 if ( nKeys === 0 ) { 42429 42430 console.error( 'THREE.KeyframeTrack: Track is empty.', this ); 42431 valid = false; 42432 42433 } 42434 42435 let prevTime = null; 42436 42437 for ( let i = 0; i !== nKeys; i ++ ) { 42438 42439 const currTime = times[ i ]; 42440 42441 if ( typeof currTime === 'number' && isNaN( currTime ) ) { 42442 42443 console.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime ); 42444 valid = false; 42445 break; 42446 42447 } 42448 42449 if ( prevTime !== null && prevTime > currTime ) { 42450 42451 console.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); 42452 valid = false; 42453 break; 42454 42455 } 42456 42457 prevTime = currTime; 42458 42459 } 42460 42461 if ( values !== undefined ) { 42462 42463 if ( isTypedArray( values ) ) { 42464 42465 for ( let i = 0, n = values.length; i !== n; ++ i ) { 42466 42467 const value = values[ i ]; 42468 42469 if ( isNaN( value ) ) { 42470 42471 console.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value ); 42472 valid = false; 42473 break; 42474 42475 } 42476 42477 } 42478 42479 } 42480 42481 } 42482 42483 return valid; 42484 42485 } 42486 42487 // removes equivalent sequential keys as common in morph target sequences 42488 // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) 42489 optimize() { 42490 42491 // times or values may be shared with other tracks, so overwriting is unsafe 42492 const times = this.times.slice(), 42493 values = this.values.slice(), 42494 stride = this.getValueSize(), 42495 42496 smoothInterpolation = this.getInterpolation() === InterpolateSmooth, 42497 42498 lastIndex = times.length - 1; 42499 42500 let writeIndex = 1; 42501 42502 for ( let i = 1; i < lastIndex; ++ i ) { 42503 42504 let keep = false; 42505 42506 const time = times[ i ]; 42507 const timeNext = times[ i + 1 ]; 42508 42509 // remove adjacent keyframes scheduled at the same time 42510 42511 if ( time !== timeNext && ( i !== 1 || time !== times[ 0 ] ) ) { 42512 42513 if ( ! smoothInterpolation ) { 42514 42515 // remove unnecessary keyframes same as their neighbors 42516 42517 const offset = i * stride, 42518 offsetP = offset - stride, 42519 offsetN = offset + stride; 42520 42521 for ( let j = 0; j !== stride; ++ j ) { 42522 42523 const value = values[ offset + j ]; 42524 42525 if ( value !== values[ offsetP + j ] || 42526 value !== values[ offsetN + j ] ) { 42527 42528 keep = true; 42529 break; 42530 42531 } 42532 42533 } 42534 42535 } else { 42536 42537 keep = true; 42538 42539 } 42540 42541 } 42542 42543 // in-place compaction 42544 42545 if ( keep ) { 42546 42547 if ( i !== writeIndex ) { 42548 42549 times[ writeIndex ] = times[ i ]; 42550 42551 const readOffset = i * stride, 42552 writeOffset = writeIndex * stride; 42553 42554 for ( let j = 0; j !== stride; ++ j ) { 42555 42556 values[ writeOffset + j ] = values[ readOffset + j ]; 42557 42558 } 42559 42560 } 42561 42562 ++ writeIndex; 42563 42564 } 42565 42566 } 42567 42568 // flush last keyframe (compaction looks ahead) 42569 42570 if ( lastIndex > 0 ) { 42571 42572 times[ writeIndex ] = times[ lastIndex ]; 42573 42574 for ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) { 42575 42576 values[ writeOffset + j ] = values[ readOffset + j ]; 42577 42578 } 42579 42580 ++ writeIndex; 42581 42582 } 42583 42584 if ( writeIndex !== times.length ) { 42585 42586 this.times = times.slice( 0, writeIndex ); 42587 this.values = values.slice( 0, writeIndex * stride ); 42588 42589 } else { 42590 42591 this.times = times; 42592 this.values = values; 42593 42594 } 42595 42596 return this; 42597 42598 } 42599 42600 clone() { 42601 42602 const times = this.times.slice(); 42603 const values = this.values.slice(); 42604 42605 const TypedKeyframeTrack = this.constructor; 42606 const track = new TypedKeyframeTrack( this.name, times, values ); 42607 42608 // Interpolant argument to constructor is not saved, so copy the factory method directly. 42609 track.createInterpolant = this.createInterpolant; 42610 42611 return track; 42612 42613 } 42614 42615} 42616 42617KeyframeTrack.prototype.TimeBufferType = Float32Array; 42618KeyframeTrack.prototype.ValueBufferType = Float32Array; 42619KeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear; 42620 42621/** 42622 * A Track of Boolean keyframe values. 42623 */ 42624class BooleanKeyframeTrack extends KeyframeTrack {} 42625 42626BooleanKeyframeTrack.prototype.ValueTypeName = 'bool'; 42627BooleanKeyframeTrack.prototype.ValueBufferType = Array; 42628BooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; 42629BooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; 42630BooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; 42631 42632/** 42633 * A Track of keyframe values that represent color. 42634 */ 42635class ColorKeyframeTrack extends KeyframeTrack {} 42636 42637ColorKeyframeTrack.prototype.ValueTypeName = 'color'; 42638 42639/** 42640 * A Track of numeric keyframe values. 42641 */ 42642class NumberKeyframeTrack extends KeyframeTrack {} 42643 42644NumberKeyframeTrack.prototype.ValueTypeName = 'number'; 42645 42646/** 42647 * Spherical linear unit quaternion interpolant. 42648 */ 42649 42650class QuaternionLinearInterpolant extends Interpolant { 42651 42652 constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { 42653 42654 super( parameterPositions, sampleValues, sampleSize, resultBuffer ); 42655 42656 } 42657 42658 interpolate_( i1, t0, t, t1 ) { 42659 42660 const result = this.resultBuffer, 42661 values = this.sampleValues, 42662 stride = this.valueSize, 42663 42664 alpha = ( t - t0 ) / ( t1 - t0 ); 42665 42666 let offset = i1 * stride; 42667 42668 for ( let end = offset + stride; offset !== end; offset += 4 ) { 42669 42670 Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha ); 42671 42672 } 42673 42674 return result; 42675 42676 } 42677 42678} 42679 42680/** 42681 * A Track of quaternion keyframe values. 42682 */ 42683class QuaternionKeyframeTrack extends KeyframeTrack { 42684 42685 InterpolantFactoryMethodLinear( result ) { 42686 42687 return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result ); 42688 42689 } 42690 42691} 42692 42693QuaternionKeyframeTrack.prototype.ValueTypeName = 'quaternion'; 42694// ValueBufferType is inherited 42695QuaternionKeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear; 42696QuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; 42697 42698/** 42699 * A Track that interpolates Strings 42700 */ 42701class StringKeyframeTrack extends KeyframeTrack {} 42702 42703StringKeyframeTrack.prototype.ValueTypeName = 'string'; 42704StringKeyframeTrack.prototype.ValueBufferType = Array; 42705StringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; 42706StringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; 42707StringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; 42708 42709/** 42710 * A Track of vectored keyframe values. 42711 */ 42712class VectorKeyframeTrack extends KeyframeTrack {} 42713 42714VectorKeyframeTrack.prototype.ValueTypeName = 'vector'; 42715 42716class AnimationClip { 42717 42718 constructor( name, duration = - 1, tracks, blendMode = NormalAnimationBlendMode ) { 42719 42720 this.name = name; 42721 this.tracks = tracks; 42722 this.duration = duration; 42723 this.blendMode = blendMode; 42724 42725 this.uuid = generateUUID(); 42726 42727 // this means it should figure out its duration by scanning the tracks 42728 if ( this.duration < 0 ) { 42729 42730 this.resetDuration(); 42731 42732 } 42733 42734 } 42735 42736 42737 static parse( json ) { 42738 42739 const tracks = [], 42740 jsonTracks = json.tracks, 42741 frameTime = 1.0 / ( json.fps || 1.0 ); 42742 42743 for ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) { 42744 42745 tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) ); 42746 42747 } 42748 42749 const clip = new this( json.name, json.duration, tracks, json.blendMode ); 42750 clip.uuid = json.uuid; 42751 42752 return clip; 42753 42754 } 42755 42756 static toJSON( clip ) { 42757 42758 const tracks = [], 42759 clipTracks = clip.tracks; 42760 42761 const json = { 42762 42763 'name': clip.name, 42764 'duration': clip.duration, 42765 'tracks': tracks, 42766 'uuid': clip.uuid, 42767 'blendMode': clip.blendMode 42768 42769 }; 42770 42771 for ( let i = 0, n = clipTracks.length; i !== n; ++ i ) { 42772 42773 tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); 42774 42775 } 42776 42777 return json; 42778 42779 } 42780 42781 static CreateFromMorphTargetSequence( name, morphTargetSequence, fps, noLoop ) { 42782 42783 const numMorphTargets = morphTargetSequence.length; 42784 const tracks = []; 42785 42786 for ( let i = 0; i < numMorphTargets; i ++ ) { 42787 42788 let times = []; 42789 let values = []; 42790 42791 times.push( 42792 ( i + numMorphTargets - 1 ) % numMorphTargets, 42793 i, 42794 ( i + 1 ) % numMorphTargets ); 42795 42796 values.push( 0, 1, 0 ); 42797 42798 const order = getKeyframeOrder( times ); 42799 times = sortedArray( times, 1, order ); 42800 values = sortedArray( values, 1, order ); 42801 42802 // if there is a key at the first frame, duplicate it as the 42803 // last frame as well for perfect loop. 42804 if ( ! noLoop && times[ 0 ] === 0 ) { 42805 42806 times.push( numMorphTargets ); 42807 values.push( values[ 0 ] ); 42808 42809 } 42810 42811 tracks.push( 42812 new NumberKeyframeTrack( 42813 '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', 42814 times, values 42815 ).scale( 1.0 / fps ) ); 42816 42817 } 42818 42819 return new this( name, - 1, tracks ); 42820 42821 } 42822 42823 static findByName( objectOrClipArray, name ) { 42824 42825 let clipArray = objectOrClipArray; 42826 42827 if ( ! Array.isArray( objectOrClipArray ) ) { 42828 42829 const o = objectOrClipArray; 42830 clipArray = o.geometry && o.geometry.animations || o.animations; 42831 42832 } 42833 42834 for ( let i = 0; i < clipArray.length; i ++ ) { 42835 42836 if ( clipArray[ i ].name === name ) { 42837 42838 return clipArray[ i ]; 42839 42840 } 42841 42842 } 42843 42844 return null; 42845 42846 } 42847 42848 static CreateClipsFromMorphTargetSequences( morphTargets, fps, noLoop ) { 42849 42850 const animationToMorphTargets = {}; 42851 42852 // tested with https://regex101.com/ on trick sequences 42853 // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 42854 const pattern = /^([\w-]*?)([\d]+)$/; 42855 42856 // sort morph target names into animation groups based 42857 // patterns like Walk_001, Walk_002, Run_001, Run_002 42858 for ( let i = 0, il = morphTargets.length; i < il; i ++ ) { 42859 42860 const morphTarget = morphTargets[ i ]; 42861 const parts = morphTarget.name.match( pattern ); 42862 42863 if ( parts && parts.length > 1 ) { 42864 42865 const name = parts[ 1 ]; 42866 42867 let animationMorphTargets = animationToMorphTargets[ name ]; 42868 42869 if ( ! animationMorphTargets ) { 42870 42871 animationToMorphTargets[ name ] = animationMorphTargets = []; 42872 42873 } 42874 42875 animationMorphTargets.push( morphTarget ); 42876 42877 } 42878 42879 } 42880 42881 const clips = []; 42882 42883 for ( const name in animationToMorphTargets ) { 42884 42885 clips.push( this.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); 42886 42887 } 42888 42889 return clips; 42890 42891 } 42892 42893 // parse the animation.hierarchy format 42894 static parseAnimation( animation, bones ) { 42895 42896 if ( ! animation ) { 42897 42898 console.error( 'THREE.AnimationClip: No animation in JSONLoader data.' ); 42899 return null; 42900 42901 } 42902 42903 const addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { 42904 42905 // only return track if there are actually keys. 42906 if ( animationKeys.length !== 0 ) { 42907 42908 const times = []; 42909 const values = []; 42910 42911 flattenJSON( animationKeys, times, values, propertyName ); 42912 42913 // empty keys are filtered out, so check again 42914 if ( times.length !== 0 ) { 42915 42916 destTracks.push( new trackType( trackName, times, values ) ); 42917 42918 } 42919 42920 } 42921 42922 }; 42923 42924 const tracks = []; 42925 42926 const clipName = animation.name || 'default'; 42927 const fps = animation.fps || 30; 42928 const blendMode = animation.blendMode; 42929 42930 // automatic length determination in AnimationClip. 42931 let duration = animation.length || - 1; 42932 42933 const hierarchyTracks = animation.hierarchy || []; 42934 42935 for ( let h = 0; h < hierarchyTracks.length; h ++ ) { 42936 42937 const animationKeys = hierarchyTracks[ h ].keys; 42938 42939 // skip empty tracks 42940 if ( ! animationKeys || animationKeys.length === 0 ) continue; 42941 42942 // process morph targets 42943 if ( animationKeys[ 0 ].morphTargets ) { 42944 42945 // figure out all morph targets used in this track 42946 const morphTargetNames = {}; 42947 42948 let k; 42949 42950 for ( k = 0; k < animationKeys.length; k ++ ) { 42951 42952 if ( animationKeys[ k ].morphTargets ) { 42953 42954 for ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { 42955 42956 morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1; 42957 42958 } 42959 42960 } 42961 42962 } 42963 42964 // create a track for each morph target with all zero 42965 // morphTargetInfluences except for the keys in which 42966 // the morphTarget is named. 42967 for ( const morphTargetName in morphTargetNames ) { 42968 42969 const times = []; 42970 const values = []; 42971 42972 for ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) { 42973 42974 const animationKey = animationKeys[ k ]; 42975 42976 times.push( animationKey.time ); 42977 values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); 42978 42979 } 42980 42981 tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); 42982 42983 } 42984 42985 duration = morphTargetNames.length * fps; 42986 42987 } else { 42988 42989 // ...assume skeletal animation 42990 42991 const boneName = '.bones[' + bones[ h ].name + ']'; 42992 42993 addNonemptyTrack( 42994 VectorKeyframeTrack, boneName + '.position', 42995 animationKeys, 'pos', tracks ); 42996 42997 addNonemptyTrack( 42998 QuaternionKeyframeTrack, boneName + '.quaternion', 42999 animationKeys, 'rot', tracks ); 43000 43001 addNonemptyTrack( 43002 VectorKeyframeTrack, boneName + '.scale', 43003 animationKeys, 'scl', tracks ); 43004 43005 } 43006 43007 } 43008 43009 if ( tracks.length === 0 ) { 43010 43011 return null; 43012 43013 } 43014 43015 const clip = new this( clipName, duration, tracks, blendMode ); 43016 43017 return clip; 43018 43019 } 43020 43021 resetDuration() { 43022 43023 const tracks = this.tracks; 43024 let duration = 0; 43025 43026 for ( let i = 0, n = tracks.length; i !== n; ++ i ) { 43027 43028 const track = this.tracks[ i ]; 43029 43030 duration = Math.max( duration, track.times[ track.times.length - 1 ] ); 43031 43032 } 43033 43034 this.duration = duration; 43035 43036 return this; 43037 43038 } 43039 43040 trim() { 43041 43042 for ( let i = 0; i < this.tracks.length; i ++ ) { 43043 43044 this.tracks[ i ].trim( 0, this.duration ); 43045 43046 } 43047 43048 return this; 43049 43050 } 43051 43052 validate() { 43053 43054 let valid = true; 43055 43056 for ( let i = 0; i < this.tracks.length; i ++ ) { 43057 43058 valid = valid && this.tracks[ i ].validate(); 43059 43060 } 43061 43062 return valid; 43063 43064 } 43065 43066 optimize() { 43067 43068 for ( let i = 0; i < this.tracks.length; i ++ ) { 43069 43070 this.tracks[ i ].optimize(); 43071 43072 } 43073 43074 return this; 43075 43076 } 43077 43078 clone() { 43079 43080 const tracks = []; 43081 43082 for ( let i = 0; i < this.tracks.length; i ++ ) { 43083 43084 tracks.push( this.tracks[ i ].clone() ); 43085 43086 } 43087 43088 return new this.constructor( this.name, this.duration, tracks, this.blendMode ); 43089 43090 } 43091 43092 toJSON() { 43093 43094 return this.constructor.toJSON( this ); 43095 43096 } 43097 43098} 43099 43100function getTrackTypeForValueTypeName( typeName ) { 43101 43102 switch ( typeName.toLowerCase() ) { 43103 43104 case 'scalar': 43105 case 'double': 43106 case 'float': 43107 case 'number': 43108 case 'integer': 43109 43110 return NumberKeyframeTrack; 43111 43112 case 'vector': 43113 case 'vector2': 43114 case 'vector3': 43115 case 'vector4': 43116 43117 return VectorKeyframeTrack; 43118 43119 case 'color': 43120 43121 return ColorKeyframeTrack; 43122 43123 case 'quaternion': 43124 43125 return QuaternionKeyframeTrack; 43126 43127 case 'bool': 43128 case 'boolean': 43129 43130 return BooleanKeyframeTrack; 43131 43132 case 'string': 43133 43134 return StringKeyframeTrack; 43135 43136 } 43137 43138 throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName ); 43139 43140} 43141 43142function parseKeyframeTrack( json ) { 43143 43144 if ( json.type === undefined ) { 43145 43146 throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' ); 43147 43148 } 43149 43150 const trackType = getTrackTypeForValueTypeName( json.type ); 43151 43152 if ( json.times === undefined ) { 43153 43154 const times = [], values = []; 43155 43156 flattenJSON( json.keys, times, values, 'value' ); 43157 43158 json.times = times; 43159 json.values = values; 43160 43161 } 43162 43163 // derived classes can define a static parse method 43164 if ( trackType.parse !== undefined ) { 43165 43166 return trackType.parse( json ); 43167 43168 } else { 43169 43170 // by default, we assume a constructor compatible with the base 43171 return new trackType( json.name, json.times, json.values, json.interpolation ); 43172 43173 } 43174 43175} 43176 43177const Cache = { 43178 43179 enabled: false, 43180 43181 files: {}, 43182 43183 add: function ( key, file ) { 43184 43185 if ( this.enabled === false ) return; 43186 43187 // console.log( 'THREE.Cache', 'Adding key:', key ); 43188 43189 this.files[ key ] = file; 43190 43191 }, 43192 43193 get: function ( key ) { 43194 43195 if ( this.enabled === false ) return; 43196 43197 // console.log( 'THREE.Cache', 'Checking key:', key ); 43198 43199 return this.files[ key ]; 43200 43201 }, 43202 43203 remove: function ( key ) { 43204 43205 delete this.files[ key ]; 43206 43207 }, 43208 43209 clear: function () { 43210 43211 this.files = {}; 43212 43213 } 43214 43215}; 43216 43217class LoadingManager { 43218 43219 constructor( onLoad, onProgress, onError ) { 43220 43221 const scope = this; 43222 43223 let isLoading = false; 43224 let itemsLoaded = 0; 43225 let itemsTotal = 0; 43226 let urlModifier = undefined; 43227 const handlers = []; 43228 43229 // Refer to #5689 for the reason why we don't set .onStart 43230 // in the constructor 43231 43232 this.onStart = undefined; 43233 this.onLoad = onLoad; 43234 this.onProgress = onProgress; 43235 this.onError = onError; 43236 43237 this.itemStart = function ( url ) { 43238 43239 itemsTotal ++; 43240 43241 if ( isLoading === false ) { 43242 43243 if ( scope.onStart !== undefined ) { 43244 43245 scope.onStart( url, itemsLoaded, itemsTotal ); 43246 43247 } 43248 43249 } 43250 43251 isLoading = true; 43252 43253 }; 43254 43255 this.itemEnd = function ( url ) { 43256 43257 itemsLoaded ++; 43258 43259 if ( scope.onProgress !== undefined ) { 43260 43261 scope.onProgress( url, itemsLoaded, itemsTotal ); 43262 43263 } 43264 43265 if ( itemsLoaded === itemsTotal ) { 43266 43267 isLoading = false; 43268 43269 if ( scope.onLoad !== undefined ) { 43270 43271 scope.onLoad(); 43272 43273 } 43274 43275 } 43276 43277 }; 43278 43279 this.itemError = function ( url ) { 43280 43281 if ( scope.onError !== undefined ) { 43282 43283 scope.onError( url ); 43284 43285 } 43286 43287 }; 43288 43289 this.resolveURL = function ( url ) { 43290 43291 if ( urlModifier ) { 43292 43293 return urlModifier( url ); 43294 43295 } 43296 43297 return url; 43298 43299 }; 43300 43301 this.setURLModifier = function ( transform ) { 43302 43303 urlModifier = transform; 43304 43305 return this; 43306 43307 }; 43308 43309 this.addHandler = function ( regex, loader ) { 43310 43311 handlers.push( regex, loader ); 43312 43313 return this; 43314 43315 }; 43316 43317 this.removeHandler = function ( regex ) { 43318 43319 const index = handlers.indexOf( regex ); 43320 43321 if ( index !== - 1 ) { 43322 43323 handlers.splice( index, 2 ); 43324 43325 } 43326 43327 return this; 43328 43329 }; 43330 43331 this.getHandler = function ( file ) { 43332 43333 for ( let i = 0, l = handlers.length; i < l; i += 2 ) { 43334 43335 const regex = handlers[ i ]; 43336 const loader = handlers[ i + 1 ]; 43337 43338 if ( regex.global ) regex.lastIndex = 0; // see #17920 43339 43340 if ( regex.test( file ) ) { 43341 43342 return loader; 43343 43344 } 43345 43346 } 43347 43348 return null; 43349 43350 }; 43351 43352 } 43353 43354} 43355 43356const DefaultLoadingManager = /*@__PURE__*/ new LoadingManager(); 43357 43358class Loader { 43359 43360 constructor( manager ) { 43361 43362 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; 43363 43364 this.crossOrigin = 'anonymous'; 43365 this.withCredentials = false; 43366 this.path = ''; 43367 this.resourcePath = ''; 43368 this.requestHeader = {}; 43369 43370 } 43371 43372 load( /* url, onLoad, onProgress, onError */ ) {} 43373 43374 loadAsync( url, onProgress ) { 43375 43376 const scope = this; 43377 43378 return new Promise( function ( resolve, reject ) { 43379 43380 scope.load( url, resolve, onProgress, reject ); 43381 43382 } ); 43383 43384 } 43385 43386 parse( /* data */ ) {} 43387 43388 setCrossOrigin( crossOrigin ) { 43389 43390 this.crossOrigin = crossOrigin; 43391 return this; 43392 43393 } 43394 43395 setWithCredentials( value ) { 43396 43397 this.withCredentials = value; 43398 return this; 43399 43400 } 43401 43402 setPath( path ) { 43403 43404 this.path = path; 43405 return this; 43406 43407 } 43408 43409 setResourcePath( resourcePath ) { 43410 43411 this.resourcePath = resourcePath; 43412 return this; 43413 43414 } 43415 43416 setRequestHeader( requestHeader ) { 43417 43418 this.requestHeader = requestHeader; 43419 return this; 43420 43421 } 43422 43423} 43424 43425Loader.DEFAULT_MATERIAL_NAME = '__DEFAULT'; 43426 43427const loading = {}; 43428 43429class HttpError extends Error { 43430 43431 constructor( message, response ) { 43432 43433 super( message ); 43434 this.response = response; 43435 43436 } 43437 43438} 43439 43440class FileLoader extends Loader { 43441 43442 constructor( manager ) { 43443 43444 super( manager ); 43445 43446 } 43447 43448 load( url, onLoad, onProgress, onError ) { 43449 43450 if ( url === undefined ) url = ''; 43451 43452 if ( this.path !== undefined ) url = this.path + url; 43453 43454 url = this.manager.resolveURL( url ); 43455 43456 const cached = Cache.get( url ); 43457 43458 if ( cached !== undefined ) { 43459 43460 this.manager.itemStart( url ); 43461 43462 setTimeout( () => { 43463 43464 if ( onLoad ) onLoad( cached ); 43465 43466 this.manager.itemEnd( url ); 43467 43468 }, 0 ); 43469 43470 return cached; 43471 43472 } 43473 43474 // Check if request is duplicate 43475 43476 if ( loading[ url ] !== undefined ) { 43477 43478 loading[ url ].push( { 43479 43480 onLoad: onLoad, 43481 onProgress: onProgress, 43482 onError: onError 43483 43484 } ); 43485 43486 return; 43487 43488 } 43489 43490 // Initialise array for duplicate requests 43491 loading[ url ] = []; 43492 43493 loading[ url ].push( { 43494 onLoad: onLoad, 43495 onProgress: onProgress, 43496 onError: onError, 43497 } ); 43498 43499 // create request
vendor: 11,646 bytes, lines 43500-44091
43500 const req = new Request( url, { 43501 headers: new Headers( this.requestHeader ), 43502 credentials: this.withCredentials ? 'include' : 'same-origin', 43503 // An abort controller could be added within a future PR 43504 } ); 43505 43506 // record states ( avoid data race ) 43507 const mimeType = this.mimeType; 43508 const responseType = this.responseType; 43509 43510 // start the fetch 43511 fetch( req ) 43512 .then( response => { 43513 43514 if ( response.status === 200 || response.status === 0 ) { 43515 43516 // Some browsers return HTTP Status 0 when using non-http protocol 43517 // e.g. 'file://' or 'data://'. Handle as success. 43518 43519 if ( response.status === 0 ) { 43520 43521 console.warn( 'THREE.FileLoader: HTTP Status 0 received.' ); 43522 43523 } 43524 43525 // Workaround: Checking if response.body === undefined for Alipay browser #23548 43526 43527 if ( typeof ReadableStream === 'undefined' || response.body === undefined || response.body.getReader === undefined ) { 43528 43529 return response; 43530 43531 } 43532 43533 const callbacks = loading[ url ]; 43534 const reader = response.body.getReader(); 43535 43536 // Nginx needs X-File-Size check 43537 // https://serverfault.com/questions/482875/why-does-nginx-remove-content-length-header-for-chunked-content 43538 const contentLength = response.headers.get( 'Content-Length' ) || response.headers.get( 'X-File-Size' ); 43539 const total = contentLength ? parseInt( contentLength ) : 0; 43540 const lengthComputable = total !== 0; 43541 let loaded = 0; 43542 43543 // periodically read data into the new stream tracking while download progress 43544 const stream = new ReadableStream( { 43545 start( controller ) { 43546 43547 readData(); 43548 43549 function readData() { 43550 43551 reader.read().then( ( { done, value } ) => { 43552 43553 if ( done ) { 43554 43555 controller.close(); 43556 43557 } else { 43558 43559 loaded += value.byteLength; 43560 43561 const event = new ProgressEvent( 'progress', { lengthComputable, loaded, total } ); 43562 for ( let i = 0, il = callbacks.length; i < il; i ++ ) { 43563 43564 const callback = callbacks[ i ]; 43565 if ( callback.onProgress ) callback.onProgress( event ); 43566 43567 } 43568 43569 controller.enqueue( value ); 43570 readData(); 43571 43572 } 43573 43574 } ); 43575 43576 } 43577 43578 } 43579 43580 } ); 43581 43582 return new Response( stream ); 43583 43584 } else { 43585 43586 throw new HttpError( `fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`, response ); 43587 43588 } 43589 43590 } ) 43591 .then( response => { 43592 43593 switch ( responseType ) { 43594 43595 case 'arraybuffer': 43596 43597 return response.arrayBuffer(); 43598 43599 case 'blob': 43600 43601 return response.blob(); 43602 43603 case 'document': 43604 43605 return response.text() 43606 .then( text => { 43607 43608 const parser = new DOMParser(); 43609 return parser.parseFromString( text, mimeType ); 43610 43611 } ); 43612 43613 case 'json': 43614 43615 return response.json(); 43616 43617 default: 43618 43619 if ( mimeType === undefined ) { 43620 43621 return response.text(); 43622 43623 } else { 43624 43625 // sniff encoding 43626 const re = /charset="?([^;"\s]*)"?/i; 43627 const exec = re.exec( mimeType ); 43628 const label = exec && exec[ 1 ] ? exec[ 1 ].toLowerCase() : undefined; 43629 const decoder = new TextDecoder( label ); 43630 return response.arrayBuffer().then( ab => decoder.decode( ab ) ); 43631 43632 } 43633 43634 } 43635 43636 } ) 43637 .then( data => { 43638 43639 // Add to cache only on HTTP success, so that we do not cache 43640 // error response bodies as proper responses to requests. 43641 Cache.add( url, data ); 43642 43643 const callbacks = loading[ url ]; 43644 delete loading[ url ]; 43645 43646 for ( let i = 0, il = callbacks.length; i < il; i ++ ) { 43647 43648 const callback = callbacks[ i ]; 43649 if ( callback.onLoad ) callback.onLoad( data ); 43650 43651 } 43652 43653 } ) 43654 .catch( err => { 43655 43656 // Abort errors and other errors are handled the same 43657 43658 const callbacks = loading[ url ]; 43659 43660 if ( callbacks === undefined ) { 43661 43662 // When onLoad was called and url was deleted in `loading` 43663 this.manager.itemError( url ); 43664 throw err; 43665 43666 } 43667 43668 delete loading[ url ]; 43669 43670 for ( let i = 0, il = callbacks.length; i < il; i ++ ) { 43671 43672 const callback = callbacks[ i ]; 43673 if ( callback.onError ) callback.onError( err ); 43674 43675 } 43676 43677 this.manager.itemError( url ); 43678 43679 } ) 43680 .finally( () => { 43681 43682 this.manager.itemEnd( url ); 43683 43684 } ); 43685 43686 this.manager.itemStart( url ); 43687 43688 } 43689 43690 setResponseType( value ) { 43691 43692 this.responseType = value; 43693 return this; 43694 43695 } 43696 43697 setMimeType( value ) { 43698 43699 this.mimeType = value; 43700 return this; 43701 43702 } 43703 43704} 43705 43706class AnimationLoader extends Loader { 43707 43708 constructor( manager ) { 43709 43710 super( manager ); 43711 43712 } 43713 43714 load( url, onLoad, onProgress, onError ) { 43715 43716 const scope = this; 43717 43718 const loader = new FileLoader( this.manager ); 43719 loader.setPath( this.path ); 43720 loader.setRequestHeader( this.requestHeader ); 43721 loader.setWithCredentials( this.withCredentials ); 43722 loader.load( url, function ( text ) { 43723 43724 try { 43725 43726 onLoad( scope.parse( JSON.parse( text ) ) ); 43727 43728 } catch ( e ) { 43729 43730 if ( onError ) { 43731 43732 onError( e ); 43733 43734 } else { 43735 43736 console.error( e ); 43737 43738 } 43739 43740 scope.manager.itemError( url ); 43741 43742 } 43743 43744 }, onProgress, onError ); 43745 43746 } 43747 43748 parse( json ) { 43749 43750 const animations = []; 43751 43752 for ( let i = 0; i < json.length; i ++ ) { 43753 43754 const clip = AnimationClip.parse( json[ i ] ); 43755 43756 animations.push( clip ); 43757 43758 } 43759 43760 return animations; 43761 43762 } 43763 43764} 43765 43766/** 43767 * Abstract Base class to block based textures loader (dds, pvr, ...) 43768 * 43769 * Sub classes have to implement the parse() method which will be used in load(). 43770 */ 43771 43772class CompressedTextureLoader extends Loader { 43773 43774 constructor( manager ) { 43775 43776 super( manager ); 43777 43778 } 43779 43780 load( url, onLoad, onProgress, onError ) { 43781 43782 const scope = this; 43783 43784 const images = []; 43785 43786 const texture = new CompressedTexture(); 43787 43788 const loader = new FileLoader( this.manager ); 43789 loader.setPath( this.path ); 43790 loader.setResponseType( 'arraybuffer' ); 43791 loader.setRequestHeader( this.requestHeader ); 43792 loader.setWithCredentials( scope.withCredentials ); 43793 43794 let loaded = 0; 43795 43796 function loadTexture( i ) { 43797 43798 loader.load( url[ i ], function ( buffer ) { 43799 43800 const texDatas = scope.parse( buffer, true ); 43801 43802 images[ i ] = { 43803 width: texDatas.width, 43804 height: texDatas.height, 43805 format: texDatas.format, 43806 mipmaps: texDatas.mipmaps 43807 }; 43808 43809 loaded += 1; 43810 43811 if ( loaded === 6 ) { 43812 43813 if ( texDatas.mipmapCount === 1 ) texture.minFilter = LinearFilter; 43814 43815 texture.image = images; 43816 texture.format = texDatas.format; 43817 texture.needsUpdate = true; 43818 43819 if ( onLoad ) onLoad( texture ); 43820 43821 } 43822 43823 }, onProgress, onError ); 43824 43825 } 43826 43827 if ( Array.isArray( url ) ) { 43828 43829 for ( let i = 0, il = url.length; i < il; ++ i ) { 43830 43831 loadTexture( i ); 43832 43833 } 43834 43835 } else { 43836 43837 // compressed cubemap texture stored in a single DDS file 43838 43839 loader.load( url, function ( buffer ) { 43840 43841 const texDatas = scope.parse( buffer, true ); 43842 43843 if ( texDatas.isCubemap ) { 43844 43845 const faces = texDatas.mipmaps.length / texDatas.mipmapCount; 43846 43847 for ( let f = 0; f < faces; f ++ ) { 43848 43849 images[ f ] = { mipmaps: [] }; 43850 43851 for ( let i = 0; i < texDatas.mipmapCount; i ++ ) { 43852 43853 images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] ); 43854 images[ f ].format = texDatas.format; 43855 images[ f ].width = texDatas.width; 43856 images[ f ].height = texDatas.height; 43857 43858 } 43859 43860 } 43861 43862 texture.image = images; 43863 43864 } else { 43865 43866 texture.image.width = texDatas.width; 43867 texture.image.height = texDatas.height; 43868 texture.mipmaps = texDatas.mipmaps; 43869 43870 } 43871 43872 if ( texDatas.mipmapCount === 1 ) { 43873 43874 texture.minFilter = LinearFilter; 43875 43876 } 43877 43878 texture.format = texDatas.format; 43879 texture.needsUpdate = true; 43880 43881 if ( onLoad ) onLoad( texture ); 43882 43883 }, onProgress, onError ); 43884 43885 } 43886 43887 return texture; 43888 43889 } 43890 43891} 43892 43893class ImageLoader extends Loader { 43894 43895 constructor( manager ) { 43896 43897 super( manager ); 43898 43899 } 43900 43901 load( url, onLoad, onProgress, onError ) { 43902 43903 if ( this.path !== undefined ) url = this.path + url; 43904 43905 url = this.manager.resolveURL( url ); 43906 43907 const scope = this; 43908 43909 const cached = Cache.get( url ); 43910 43911 if ( cached !== undefined ) { 43912 43913 scope.manager.itemStart( url ); 43914 43915 setTimeout( function () { 43916 43917 if ( onLoad ) onLoad( cached ); 43918 43919 scope.manager.itemEnd( url ); 43920 43921 }, 0 ); 43922 43923 return cached; 43924 43925 } 43926 43927 const image = createElementNS( 'img' ); 43928 43929 function onImageLoad() { 43930 43931 removeEventListeners(); 43932 43933 Cache.add( url, this ); 43934 43935 if ( onLoad ) onLoad( this ); 43936 43937 scope.manager.itemEnd( url ); 43938 43939 } 43940 43941 function onImageError( event ) { 43942 43943 removeEventListeners(); 43944 43945 if ( onError ) onError( event ); 43946 43947 scope.manager.itemError( url ); 43948 scope.manager.itemEnd( url ); 43949 43950 } 43951 43952 function removeEventListeners() { 43953 43954 image.removeEventListener( 'load', onImageLoad, false ); 43955 image.removeEventListener( 'error', onImageError, false ); 43956 43957 } 43958 43959 image.addEventListener( 'load', onImageLoad, false ); 43960 image.addEventListener( 'error', onImageError, false ); 43961 43962 if ( url.slice( 0, 5 ) !== 'data:' ) { 43963 43964 if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; 43965 43966 } 43967 43968 scope.manager.itemStart( url ); 43969 43970 image.src = url; 43971 43972 return image; 43973 43974 } 43975 43976} 43977 43978class CubeTextureLoader extends Loader { 43979 43980 constructor( manager ) { 43981 43982 super( manager ); 43983 43984 } 43985 43986 load( urls, onLoad, onProgress, onError ) { 43987 43988 const texture = new CubeTexture(); 43989 texture.colorSpace = SRGBColorSpace; 43990 43991 const loader = new ImageLoader( this.manager ); 43992 loader.setCrossOrigin( this.crossOrigin ); 43993 loader.setPath( this.path ); 43994 43995 let loaded = 0; 43996 43997 function loadTexture( i ) { 43998 43999 loader.load( urls[ i ], function ( image ) { 44000 44001 texture.images[ i ] = image; 44002 44003 loaded ++; 44004 44005 if ( loaded === 6 ) { 44006 44007 texture.needsUpdate = true; 44008 44009 if ( onLoad ) onLoad( texture ); 44010 44011 } 44012 44013 }, undefined, onError ); 44014 44015 } 44016 44017 for ( let i = 0; i < urls.length; ++ i ) { 44018 44019 loadTexture( i ); 44020 44021 } 44022 44023 return texture; 44024 44025 } 44026 44027} 44028 44029/** 44030 * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) 44031 * 44032 * Sub classes have to implement the parse() method which will be used in load(). 44033 */ 44034 44035class DataTextureLoader extends Loader { 44036 44037 constructor( manager ) { 44038 44039 super( manager ); 44040 44041 } 44042 44043 load( url, onLoad, onProgress, onError ) { 44044 44045 const scope = this; 44046 44047 const texture = new DataTexture(); 44048 44049 const loader = new FileLoader( this.manager ); 44050 loader.setResponseType( 'arraybuffer' ); 44051 loader.setRequestHeader( this.requestHeader ); 44052 loader.setPath( this.path ); 44053 loader.setWithCredentials( scope.withCredentials ); 44054 loader.load( url, function ( buffer ) { 44055 44056 let texData; 44057 44058 try { 44059 44060 texData = scope.parse( buffer ); 44061 44062 } catch ( error ) { 44063 44064 if ( onError !== undefined ) { 44065 44066 onError( error ); 44067 44068 } else { 44069 44070 console.error( error ); 44071 return; 44072 44073 } 44074 44075 } 44076 44077 if ( texData.image !== undefined ) { 44078 44079 texture.image = texData.image; 44080 44081 } else if ( texData.data !== undefined ) { 44082 44083 texture.image.width = texData.width; 44084 texture.image.height = texData.height; 44085 texture.image.data = texData.data; 44086 44087 } 44088 44089 texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping; 44090 texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping; 44091
vendor: 5,358 bytes, lines 44092-44382
44092 texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter; 44093 texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter; 44094 44095 texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1; 44096 44097 if ( texData.colorSpace !== undefined ) { 44098 44099 texture.colorSpace = texData.colorSpace; 44100 44101 } else if ( texData.encoding !== undefined ) { // @deprecated, r152 44102 44103 texture.encoding = texData.encoding; 44104 44105 } 44106 44107 if ( texData.flipY !== undefined ) { 44108 44109 texture.flipY = texData.flipY; 44110 44111 } 44112 44113 if ( texData.format !== undefined ) { 44114 44115 texture.format = texData.format; 44116 44117 } 44118 44119 if ( texData.type !== undefined ) { 44120 44121 texture.type = texData.type; 44122 44123 } 44124 44125 if ( texData.mipmaps !== undefined ) { 44126 44127 texture.mipmaps = texData.mipmaps; 44128 texture.minFilter = LinearMipmapLinearFilter; // presumably... 44129 44130 } 44131 44132 if ( texData.mipmapCount === 1 ) { 44133 44134 texture.minFilter = LinearFilter; 44135 44136 } 44137 44138 if ( texData.generateMipmaps !== undefined ) { 44139 44140 texture.generateMipmaps = texData.generateMipmaps; 44141 44142 } 44143 44144 texture.needsUpdate = true; 44145 44146 if ( onLoad ) onLoad( texture, texData ); 44147 44148 }, onProgress, onError ); 44149 44150 44151 return texture; 44152 44153 } 44154 44155} 44156 44157class TextureLoader extends Loader { 44158 44159 constructor( manager ) { 44160 44161 super( manager ); 44162 44163 } 44164 44165 load( url, onLoad, onProgress, onError ) { 44166 44167 const texture = new Texture(); 44168 44169 const loader = new ImageLoader( this.manager ); 44170 loader.setCrossOrigin( this.crossOrigin ); 44171 loader.setPath( this.path ); 44172 44173 loader.load( url, function ( image ) { 44174 44175 texture.image = image; 44176 texture.needsUpdate = true; 44177 44178 if ( onLoad !== undefined ) { 44179 44180 onLoad( texture ); 44181 44182 } 44183 44184 }, onProgress, onError ); 44185 44186 return texture; 44187 44188 } 44189 44190} 44191 44192class Light extends Object3D { 44193 44194 constructor( color, intensity = 1 ) { 44195 44196 super(); 44197 44198 this.isLight = true; 44199 44200 this.type = 'Light'; 44201 44202 this.color = new Color( color ); 44203 this.intensity = intensity; 44204 44205 } 44206 44207 dispose() { 44208 44209 // Empty here in base class; some subclasses override. 44210 44211 } 44212 44213 copy( source, recursive ) { 44214 44215 super.copy( source, recursive ); 44216 44217 this.color.copy( source.color ); 44218 this.intensity = source.intensity; 44219 44220 return this; 44221 44222 } 44223 44224 toJSON( meta ) { 44225 44226 const data = super.toJSON( meta ); 44227 44228 data.object.color = this.color.getHex(); 44229 data.object.intensity = this.intensity; 44230 44231 if ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex(); 44232 44233 if ( this.distance !== undefined ) data.object.distance = this.distance; 44234 if ( this.angle !== undefined ) data.object.angle = this.angle; 44235 if ( this.decay !== undefined ) data.object.decay = this.decay; 44236 if ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra; 44237 44238 if ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON(); 44239 44240 return data; 44241 44242 } 44243 44244} 44245 44246class HemisphereLight extends Light { 44247 44248 constructor( skyColor, groundColor, intensity ) { 44249 44250 super( skyColor, intensity ); 44251 44252 this.isHemisphereLight = true; 44253 44254 this.type = 'HemisphereLight'; 44255 44256 this.position.copy( Object3D.DEFAULT_UP ); 44257 this.updateMatrix(); 44258 44259 this.groundColor = new Color( groundColor ); 44260 44261 } 44262 44263 copy( source, recursive ) { 44264 44265 super.copy( source, recursive ); 44266 44267 this.groundColor.copy( source.groundColor ); 44268 44269 return this; 44270 44271 } 44272 44273} 44274 44275const _projScreenMatrix$1 = /*@__PURE__*/ new Matrix4(); 44276const _lightPositionWorld$1 = /*@__PURE__*/ new Vector3(); 44277const _lookTarget$1 = /*@__PURE__*/ new Vector3(); 44278 44279class LightShadow { 44280 44281 constructor( camera ) { 44282 44283 this.camera = camera; 44284 44285 this.bias = 0; 44286 this.normalBias = 0; 44287 this.radius = 1; 44288 this.blurSamples = 8; 44289 44290 this.mapSize = new Vector2( 512, 512 ); 44291 44292 this.map = null; 44293 this.mapPass = null; 44294 this.matrix = new Matrix4(); 44295 44296 this.autoUpdate = true; 44297 this.needsUpdate = false; 44298 44299 this._frustum = new Frustum(); 44300 this._frameExtents = new Vector2( 1, 1 ); 44301 44302 this._viewportCount = 1; 44303 44304 this._viewports = [ 44305 44306 new Vector4( 0, 0, 1, 1 ) 44307 44308 ]; 44309 44310 } 44311 44312 getViewportCount() { 44313 44314 return this._viewportCount; 44315 44316 } 44317 44318 getFrustum() { 44319 44320 return this._frustum; 44321 44322 } 44323 44324 updateMatrices( light ) { 44325 44326 const shadowCamera = this.camera; 44327 const shadowMatrix = this.matrix; 44328 44329 _lightPositionWorld$1.setFromMatrixPosition( light.matrixWorld ); 44330 shadowCamera.position.copy( _lightPositionWorld$1 ); 44331 44332 _lookTarget$1.setFromMatrixPosition( light.target.matrixWorld ); 44333 shadowCamera.lookAt( _lookTarget$1 ); 44334 shadowCamera.updateMatrixWorld(); 44335 44336 _projScreenMatrix$1.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); 44337 this._frustum.setFromProjectionMatrix( _projScreenMatrix$1 ); 44338 44339 shadowMatrix.set( 44340 0.5, 0.0, 0.0, 0.5, 44341 0.0, 0.5, 0.0, 0.5, 44342 0.0, 0.0, 0.5, 0.5, 44343 0.0, 0.0, 0.0, 1.0 44344 ); 44345 44346 shadowMatrix.multiply( _projScreenMatrix$1 ); 44347 44348 } 44349 44350 getViewport( viewportIndex ) { 44351 44352 return this._viewports[ viewportIndex ]; 44353 44354 } 44355 44356 getFrameExtents() { 44357 44358 return this._frameExtents; 44359 44360 } 44361 44362 dispose() { 44363 44364 if ( this.map ) { 44365 44366 this.map.dispose(); 44367 44368 } 44369 44370 if ( this.mapPass ) { 44371 44372 this.mapPass.dispose(); 44373 44374 } 44375 44376 } 44377 44378 copy( source ) { 44379 44380 this.camera = source.camera.clone(); 44381 44382 this.bias = source.bias;
vendor: 5,997 bytes, lines 44383-44670
44383 this.radius = source.radius; 44384 44385 this.mapSize.copy( source.mapSize ); 44386 44387 return this; 44388 44389 } 44390 44391 clone() { 44392 44393 return new this.constructor().copy( this ); 44394 44395 } 44396 44397 toJSON() { 44398 44399 const object = {}; 44400 44401 if ( this.bias !== 0 ) object.bias = this.bias; 44402 if ( this.normalBias !== 0 ) object.normalBias = this.normalBias; 44403 if ( this.radius !== 1 ) object.radius = this.radius; 44404 if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray(); 44405 44406 object.camera = this.camera.toJSON( false ).object; 44407 delete object.camera.matrix; 44408 44409 return object; 44410 44411 } 44412 44413} 44414 44415class SpotLightShadow extends LightShadow { 44416 44417 constructor() { 44418 44419 super( new PerspectiveCamera( 50, 1, 0.5, 500 ) ); 44420 44421 this.isSpotLightShadow = true; 44422 44423 this.focus = 1; 44424 44425 } 44426 44427 updateMatrices( light ) { 44428 44429 const camera = this.camera; 44430 44431 const fov = RAD2DEG * 2 * light.angle * this.focus; 44432 const aspect = this.mapSize.width / this.mapSize.height; 44433 const far = light.distance || camera.far; 44434 44435 if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { 44436 44437 camera.fov = fov; 44438 camera.aspect = aspect; 44439 camera.far = far; 44440 camera.updateProjectionMatrix(); 44441 44442 } 44443 44444 super.updateMatrices( light ); 44445 44446 } 44447 44448 copy( source ) { 44449 44450 super.copy( source ); 44451 44452 this.focus = source.focus; 44453 44454 return this; 44455 44456 } 44457 44458} 44459 44460class SpotLight extends Light { 44461 44462 constructor( color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 2 ) { 44463 44464 super( color, intensity ); 44465 44466 this.isSpotLight = true; 44467 44468 this.type = 'SpotLight'; 44469 44470 this.position.copy( Object3D.DEFAULT_UP ); 44471 this.updateMatrix(); 44472 44473 this.target = new Object3D(); 44474 44475 this.distance = distance; 44476 this.angle = angle; 44477 this.penumbra = penumbra; 44478 this.decay = decay; 44479 44480 this.map = null; 44481 44482 this.shadow = new SpotLightShadow(); 44483 44484 } 44485 44486 get power() { 44487 44488 // compute the light's luminous power (in lumens) from its intensity (in candela) 44489 // by convention for a spotlight, luminous power (lm) = Ï * luminous intensity (cd) 44490 return this.intensity * Math.PI; 44491 44492 } 44493 44494 set power( power ) { 44495 44496 // set the light's intensity (in candela) from the desired luminous power (in lumens) 44497 this.intensity = power / Math.PI; 44498 44499 } 44500 44501 dispose() { 44502 44503 this.shadow.dispose(); 44504 44505 } 44506 44507 copy( source, recursive ) { 44508 44509 super.copy( source, recursive ); 44510 44511 this.distance = source.distance; 44512 this.angle = source.angle; 44513 this.penumbra = source.penumbra; 44514 this.decay = source.decay; 44515 44516 this.target = source.target.clone(); 44517 44518 this.shadow = source.shadow.clone(); 44519 44520 return this; 44521 44522 } 44523 44524} 44525 44526const _projScreenMatrix = /*@__PURE__*/ new Matrix4(); 44527const _lightPositionWorld = /*@__PURE__*/ new Vector3(); 44528const _lookTarget = /*@__PURE__*/ new Vector3(); 44529 44530class PointLightShadow extends LightShadow { 44531 44532 constructor() { 44533 44534 super( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); 44535 44536 this.isPointLightShadow = true; 44537 44538 this._frameExtents = new Vector2( 4, 2 ); 44539 44540 this._viewportCount = 6; 44541 44542 this._viewports = [ 44543 // These viewports map a cube-map onto a 2D texture with the 44544 // following orientation: 44545 // 44546 // xzXZ 44547 // y Y 44548 // 44549 // X - Positive x direction 44550 // x - Negative x direction 44551 // Y - Positive y direction 44552 // y - Negative y direction 44553 // Z - Positive z direction 44554 // z - Negative z direction 44555 44556 // positive X 44557 new Vector4( 2, 1, 1, 1 ), 44558 // negative X 44559 new Vector4( 0, 1, 1, 1 ), 44560 // positive Z 44561 new Vector4( 3, 1, 1, 1 ), 44562 // negative Z 44563 new Vector4( 1, 1, 1, 1 ), 44564 // positive Y 44565 new Vector4( 3, 0, 1, 1 ), 44566 // negative Y 44567 new Vector4( 1, 0, 1, 1 ) 44568 ]; 44569 44570 this._cubeDirections = [ 44571 new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ), 44572 new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 ) 44573 ]; 44574 44575 this._cubeUps = [ 44576 new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), 44577 new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0, - 1 ) 44578 ]; 44579 44580 } 44581 44582 updateMatrices( light, viewportIndex = 0 ) { 44583 44584 const camera = this.camera; 44585 const shadowMatrix = this.matrix; 44586 44587 const far = light.distance || camera.far; 44588 44589 if ( far !== camera.far ) { 44590 44591 camera.far = far; 44592 camera.updateProjectionMatrix(); 44593 44594 } 44595 44596 _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); 44597 camera.position.copy( _lightPositionWorld ); 44598 44599 _lookTarget.copy( camera.position ); 44600 _lookTarget.add( this._cubeDirections[ viewportIndex ] ); 44601 camera.up.copy( this._cubeUps[ viewportIndex ] ); 44602 camera.lookAt( _lookTarget ); 44603 camera.updateMatrixWorld(); 44604 44605 shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z ); 44606 44607 _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); 44608 this._frustum.setFromProjectionMatrix( _projScreenMatrix ); 44609 44610 } 44611 44612} 44613 44614class PointLight extends Light { 44615 44616 constructor( color, intensity, distance = 0, decay = 2 ) { 44617 44618 super( color, intensity ); 44619 44620 this.isPointLight = true; 44621 44622 this.type = 'PointLight'; 44623 44624 this.distance = distance; 44625 this.decay = decay; 44626 44627 this.shadow = new PointLightShadow(); 44628 44629 } 44630 44631 get power() { 44632 44633 // compute the light's luminous power (in lumens) from its intensity (in candela) 44634 // for an isotropic light source, luminous power (lm) = 4 Ï luminous intensity (cd) 44635 return this.intensity * 4 * Math.PI; 44636 44637 } 44638 44639 set power( power ) { 44640 44641 // set the light's intensity (in candela) from the desired luminous power (in lumens) 44642 this.intensity = power / ( 4 * Math.PI ); 44643 44644 } 44645 44646 dispose() { 44647 44648 this.shadow.dispose(); 44649 44650 } 44651 44652 copy( source, recursive ) { 44653 44654 super.copy( source, recursive ); 44655 44656 this.distance = source.distance; 44657 this.decay = source.decay; 44658 44659 this.shadow = source.shadow.clone(); 44660 44661 return this; 44662 44663 } 44664 44665} 44666 44667class DirectionalLightShadow extends LightShadow { 44668 44669 constructor() { 44670
vendor: 4,703 bytes, lines 44671-44908
44671 super( new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) ); 44672 44673 this.isDirectionalLightShadow = true; 44674 44675 } 44676 44677} 44678 44679class DirectionalLight extends Light { 44680 44681 constructor( color, intensity ) { 44682 44683 super( color, intensity ); 44684 44685 this.isDirectionalLight = true; 44686 44687 this.type = 'DirectionalLight'; 44688 44689 this.position.copy( Object3D.DEFAULT_UP ); 44690 this.updateMatrix(); 44691 44692 this.target = new Object3D(); 44693 44694 this.shadow = new DirectionalLightShadow(); 44695 44696 } 44697 44698 dispose() { 44699 44700 this.shadow.dispose(); 44701 44702 } 44703 44704 copy( source ) { 44705 44706 super.copy( source ); 44707 44708 this.target = source.target.clone(); 44709 this.shadow = source.shadow.clone(); 44710 44711 return this; 44712 44713 } 44714 44715} 44716 44717class AmbientLight extends Light { 44718 44719 constructor( color, intensity ) { 44720 44721 super( color, intensity ); 44722 44723 this.isAmbientLight = true; 44724 44725 this.type = 'AmbientLight'; 44726 44727 } 44728 44729} 44730 44731class RectAreaLight extends Light { 44732 44733 constructor( color, intensity, width = 10, height = 10 ) { 44734 44735 super( color, intensity ); 44736 44737 this.isRectAreaLight = true; 44738 44739 this.type = 'RectAreaLight'; 44740 44741 this.width = width; 44742 this.height = height; 44743 44744 } 44745 44746 get power() { 44747 44748 // compute the light's luminous power (in lumens) from its intensity (in nits) 44749 return this.intensity * this.width * this.height * Math.PI; 44750 44751 } 44752 44753 set power( power ) { 44754 44755 // set the light's intensity (in nits) from the desired luminous power (in lumens) 44756 this.intensity = power / ( this.width * this.height * Math.PI ); 44757 44758 } 44759 44760 copy( source ) { 44761 44762 super.copy( source ); 44763 44764 this.width = source.width; 44765 this.height = source.height; 44766 44767 return this; 44768 44769 } 44770 44771 toJSON( meta ) { 44772 44773 const data = super.toJSON( meta ); 44774 44775 data.object.width = this.width; 44776 data.object.height = this.height; 44777 44778 return data; 44779 44780 } 44781 44782} 44783 44784/** 44785 * Primary reference: 44786 * https://graphics.stanford.edu/papers/envmap/envmap.pdf 44787 * 44788 * Secondary reference: 44789 * https://www.ppsloan.org/publications/StupidSH36.pdf 44790 */ 44791 44792// 3-band SH defined by 9 coefficients 44793 44794class SphericalHarmonics3 { 44795 44796 constructor() { 44797 44798 this.isSphericalHarmonics3 = true; 44799 44800 this.coefficients = []; 44801 44802 for ( let i = 0; i < 9; i ++ ) { 44803 44804 this.coefficients.push( new Vector3() ); 44805 44806 } 44807 44808 } 44809 44810 set( coefficients ) { 44811 44812 for ( let i = 0; i < 9; i ++ ) { 44813 44814 this.coefficients[ i ].copy( coefficients[ i ] ); 44815 44816 } 44817 44818 return this; 44819 44820 } 44821 44822 zero() { 44823 44824 for ( let i = 0; i < 9; i ++ ) { 44825 44826 this.coefficients[ i ].set( 0, 0, 0 ); 44827 44828 } 44829 44830 return this; 44831 44832 } 44833 44834 // get the radiance in the direction of the normal 44835 // target is a Vector3 44836 getAt( normal, target ) { 44837 44838 // normal is assumed to be unit length 44839 44840 const x = normal.x, y = normal.y, z = normal.z; 44841 44842 const coeff = this.coefficients; 44843 44844 // band 0 44845 target.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 ); 44846 44847 // band 1 44848 target.addScaledVector( coeff[ 1 ], 0.488603 * y ); 44849 target.addScaledVector( coeff[ 2 ], 0.488603 * z ); 44850 target.addScaledVector( coeff[ 3 ], 0.488603 * x ); 44851 44852 // band 2 44853 target.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) ); 44854 target.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) ); 44855 target.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) ); 44856 target.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) ); 44857 target.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) ); 44858 44859 return target; 44860 44861 } 44862 44863 // get the irradiance (radiance convolved with cosine lobe) in the direction of the normal 44864 // target is a Vector3 44865 // https://graphics.stanford.edu/papers/envmap/envmap.pdf 44866 getIrradianceAt( normal, target ) { 44867 44868 // normal is assumed to be unit length 44869 44870 const x = normal.x, y = normal.y, z = normal.z; 44871 44872 const coeff = this.coefficients; 44873 44874 // band 0 44875 target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // Ï * 0.282095 44876 44877 // band 1 44878 target.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * Ï / 3 ) * 0.488603 44879 target.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z ); 44880 target.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x ); 44881 44882 // band 2 44883 target.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( Ï / 4 ) * 1.092548 44884 target.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z ); 44885 target.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( Ï / 4 ) * 0.315392 * 3 44886 target.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z ); 44887 target.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( Ï / 4 ) * 0.546274 44888 44889 return target; 44890 44891 } 44892 44893 add( sh ) { 44894 44895 for ( let i = 0; i < 9; i ++ ) { 44896 44897 this.coefficients[ i ].add( sh.coefficients[ i ] ); 44898 44899 } 44900 44901 return this; 44902 44903 } 44904 44905 addScaledSH( sh, s ) { 44906 44907 for ( let i = 0; i < 9; i ++ ) { 44908
vendor: 35,968 bytes, lines 44909-46322
44909 this.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s ); 44910 44911 } 44912 44913 return this; 44914 44915 } 44916 44917 scale( s ) { 44918 44919 for ( let i = 0; i < 9; i ++ ) { 44920 44921 this.coefficients[ i ].multiplyScalar( s ); 44922 44923 } 44924 44925 return this; 44926 44927 } 44928 44929 lerp( sh, alpha ) { 44930 44931 for ( let i = 0; i < 9; i ++ ) { 44932 44933 this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha ); 44934 44935 } 44936 44937 return this; 44938 44939 } 44940 44941 equals( sh ) { 44942 44943 for ( let i = 0; i < 9; i ++ ) { 44944 44945 if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) { 44946 44947 return false; 44948 44949 } 44950 44951 } 44952 44953 return true; 44954 44955 } 44956 44957 copy( sh ) { 44958 44959 return this.set( sh.coefficients ); 44960 44961 } 44962 44963 clone() { 44964 44965 return new this.constructor().copy( this ); 44966 44967 } 44968 44969 fromArray( array, offset = 0 ) { 44970 44971 const coefficients = this.coefficients; 44972 44973 for ( let i = 0; i < 9; i ++ ) { 44974 44975 coefficients[ i ].fromArray( array, offset + ( i * 3 ) ); 44976 44977 } 44978 44979 return this; 44980 44981 } 44982 44983 toArray( array = [], offset = 0 ) { 44984 44985 const coefficients = this.coefficients; 44986 44987 for ( let i = 0; i < 9; i ++ ) { 44988 44989 coefficients[ i ].toArray( array, offset + ( i * 3 ) ); 44990 44991 } 44992 44993 return array; 44994 44995 } 44996 44997 // evaluate the basis functions 44998 // shBasis is an Array[ 9 ] 44999 static getBasisAt( normal, shBasis ) { 45000 45001 // normal is assumed to be unit length 45002 45003 const x = normal.x, y = normal.y, z = normal.z; 45004 45005 // band 0 45006 shBasis[ 0 ] = 0.282095; 45007 45008 // band 1 45009 shBasis[ 1 ] = 0.488603 * y; 45010 shBasis[ 2 ] = 0.488603 * z; 45011 shBasis[ 3 ] = 0.488603 * x; 45012 45013 // band 2 45014 shBasis[ 4 ] = 1.092548 * x * y; 45015 shBasis[ 5 ] = 1.092548 * y * z; 45016 shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 ); 45017 shBasis[ 7 ] = 1.092548 * x * z; 45018 shBasis[ 8 ] = 0.546274 * ( x * x - y * y ); 45019 45020 } 45021 45022} 45023 45024class LightProbe extends Light { 45025 45026 constructor( sh = new SphericalHarmonics3(), intensity = 1 ) { 45027 45028 super( undefined, intensity ); 45029 45030 this.isLightProbe = true; 45031 45032 this.sh = sh; 45033 45034 } 45035 45036 copy( source ) { 45037 45038 super.copy( source ); 45039 45040 this.sh.copy( source.sh ); 45041 45042 return this; 45043 45044 } 45045 45046 fromJSON( json ) { 45047 45048 this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON(); 45049 this.sh.fromArray( json.sh ); 45050 45051 return this; 45052 45053 } 45054 45055 toJSON( meta ) { 45056 45057 const data = super.toJSON( meta ); 45058 45059 data.object.sh = this.sh.toArray(); 45060 45061 return data; 45062 45063 } 45064 45065} 45066 45067class MaterialLoader extends Loader { 45068 45069 constructor( manager ) { 45070 45071 super( manager ); 45072 this.textures = {}; 45073 45074 } 45075 45076 load( url, onLoad, onProgress, onError ) { 45077 45078 const scope = this; 45079 45080 const loader = new FileLoader( scope.manager ); 45081 loader.setPath( scope.path ); 45082 loader.setRequestHeader( scope.requestHeader ); 45083 loader.setWithCredentials( scope.withCredentials ); 45084 loader.load( url, function ( text ) { 45085 45086 try { 45087 45088 onLoad( scope.parse( JSON.parse( text ) ) ); 45089 45090 } catch ( e ) { 45091 45092 if ( onError ) { 45093 45094 onError( e ); 45095 45096 } else { 45097 45098 console.error( e ); 45099 45100 } 45101 45102 scope.manager.itemError( url ); 45103 45104 } 45105 45106 }, onProgress, onError ); 45107 45108 } 45109 45110 parse( json ) { 45111 45112 const textures = this.textures; 45113 45114 function getTexture( name ) { 45115 45116 if ( textures[ name ] === undefined ) { 45117 45118 console.warn( 'THREE.MaterialLoader: Undefined texture', name ); 45119 45120 } 45121 45122 return textures[ name ]; 45123 45124 } 45125 45126 const material = MaterialLoader.createMaterialFromType( json.type ); 45127 45128 if ( json.uuid !== undefined ) material.uuid = json.uuid; 45129 if ( json.name !== undefined ) material.name = json.name; 45130 if ( json.color !== undefined && material.color !== undefined ) material.color.setHex( json.color ); 45131 if ( json.roughness !== undefined ) material.roughness = json.roughness; 45132 if ( json.metalness !== undefined ) material.metalness = json.metalness; 45133 if ( json.sheen !== undefined ) material.sheen = json.sheen; 45134 if ( json.sheenColor !== undefined ) material.sheenColor = new Color().setHex( json.sheenColor ); 45135 if ( json.sheenRoughness !== undefined ) material.sheenRoughness = json.sheenRoughness; 45136 if ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive ); 45137 if ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular ); 45138 if ( json.specularIntensity !== undefined ) material.specularIntensity = json.specularIntensity; 45139 if ( json.specularColor !== undefined && material.specularColor !== undefined ) material.specularColor.setHex( json.specularColor ); 45140 if ( json.shininess !== undefined ) material.shininess = json.shininess; 45141 if ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat; 45142 if ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness; 45143 if ( json.iridescence !== undefined ) material.iridescence = json.iridescence; 45144 if ( json.iridescenceIOR !== undefined ) material.iridescenceIOR = json.iridescenceIOR; 45145 if ( json.iridescenceThicknessRange !== undefined ) material.iridescenceThicknessRange = json.iridescenceThicknessRange; 45146 if ( json.transmission !== undefined ) material.transmission = json.transmission; 45147 if ( json.thickness !== undefined ) material.thickness = json.thickness; 45148 if ( json.attenuationDistance !== undefined ) material.attenuationDistance = json.attenuationDistance; 45149 if ( json.attenuationColor !== undefined && material.attenuationColor !== undefined ) material.attenuationColor.setHex( json.attenuationColor ); 45150 if ( json.anisotropy !== undefined ) material.anisotropy = json.anisotropy; 45151 if ( json.anisotropyRotation !== undefined ) material.anisotropyRotation = json.anisotropyRotation; 45152 if ( json.fog !== undefined ) material.fog = json.fog; 45153 if ( json.flatShading !== undefined ) material.flatShading = json.flatShading; 45154 if ( json.blending !== undefined ) material.blending = json.blending; 45155 if ( json.combine !== undefined ) material.combine = json.combine; 45156 if ( json.side !== undefined ) material.side = json.side; 45157 if ( json.shadowSide !== undefined ) material.shadowSide = json.shadowSide; 45158 if ( json.opacity !== undefined ) material.opacity = json.opacity; 45159 if ( json.transparent !== undefined ) material.transparent = json.transparent; 45160 if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest; 45161 if ( json.alphaHash !== undefined ) material.alphaHash = json.alphaHash; 45162 if ( json.depthFunc !== undefined ) material.depthFunc = json.depthFunc; 45163 if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; 45164 if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; 45165 if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite; 45166 if ( json.blendSrc !== undefined ) material.blendSrc = json.blendSrc; 45167 if ( json.blendDst !== undefined ) material.blendDst = json.blendDst; 45168 if ( json.blendEquation !== undefined ) material.blendEquation = json.blendEquation; 45169 if ( json.blendSrcAlpha !== undefined ) material.blendSrcAlpha = json.blendSrcAlpha; 45170 if ( json.blendDstAlpha !== undefined ) material.blendDstAlpha = json.blendDstAlpha; 45171 if ( json.blendEquationAlpha !== undefined ) material.blendEquationAlpha = json.blendEquationAlpha; 45172 if ( json.blendColor !== undefined && material.blendColor !== undefined ) material.blendColor.setHex( json.blendColor ); 45173 if ( json.blendAlpha !== undefined ) material.blendAlpha = json.blendAlpha; 45174 if ( json.stencilWriteMask !== undefined ) material.stencilWriteMask = json.stencilWriteMask; 45175 if ( json.stencilFunc !== undefined ) material.stencilFunc = json.stencilFunc; 45176 if ( json.stencilRef !== undefined ) material.stencilRef = json.stencilRef; 45177 if ( json.stencilFuncMask !== undefined ) material.stencilFuncMask = json.stencilFuncMask; 45178 if ( json.stencilFail !== undefined ) material.stencilFail = json.stencilFail; 45179 if ( json.stencilZFail !== undefined ) material.stencilZFail = json.stencilZFail; 45180 if ( json.stencilZPass !== undefined ) material.stencilZPass = json.stencilZPass; 45181 if ( json.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite; 45182 45183 if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; 45184 if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; 45185 if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap; 45186 if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin; 45187 45188 if ( json.rotation !== undefined ) material.rotation = json.rotation; 45189 45190 if ( json.linewidth !== undefined ) material.linewidth = json.linewidth; 45191 if ( json.dashSize !== undefined ) material.dashSize = json.dashSize; 45192 if ( json.gapSize !== undefined ) material.gapSize = json.gapSize; 45193 if ( json.scale !== undefined ) material.scale = json.scale; 45194 45195 if ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset; 45196 if ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor; 45197 if ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits; 45198 45199 if ( json.dithering !== undefined ) material.dithering = json.dithering; 45200 45201 if ( json.alphaToCoverage !== undefined ) material.alphaToCoverage = json.alphaToCoverage; 45202 if ( json.premultipliedAlpha !== undefined ) material.premultipliedAlpha = json.premultipliedAlpha; 45203 if ( json.forceSinglePass !== undefined ) material.forceSinglePass = json.forceSinglePass; 45204 45205 if ( json.visible !== undefined ) material.visible = json.visible; 45206 45207 if ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped; 45208 45209 if ( json.userData !== undefined ) material.userData = json.userData; 45210 45211 if ( json.vertexColors !== undefined ) { 45212 45213 if ( typeof json.vertexColors === 'number' ) { 45214 45215 material.vertexColors = ( json.vertexColors > 0 ) ? true : false; 45216 45217 } else { 45218 45219 material.vertexColors = json.vertexColors; 45220 45221 } 45222 45223 } 45224 45225 // Shader Material 45226 45227 if ( json.uniforms !== undefined ) { 45228 45229 for ( const name in json.uniforms ) { 45230 45231 const uniform = json.uniforms[ name ]; 45232 45233 material.uniforms[ name ] = {}; 45234 45235 switch ( uniform.type ) { 45236 45237 case 't': 45238 material.uniforms[ name ].value = getTexture( uniform.value ); 45239 break; 45240 45241 case 'c': 45242 material.uniforms[ name ].value = new Color().setHex( uniform.value ); 45243 break; 45244 45245 case 'v2': 45246 material.uniforms[ name ].value = new Vector2().fromArray( uniform.value ); 45247 break; 45248 45249 case 'v3': 45250 material.uniforms[ name ].value = new Vector3().fromArray( uniform.value ); 45251 break; 45252 45253 case 'v4': 45254 material.uniforms[ name ].value = new Vector4().fromArray( uniform.value ); 45255 break; 45256 45257 case 'm3': 45258 material.uniforms[ name ].value = new Matrix3().fromArray( uniform.value ); 45259 break; 45260 45261 case 'm4': 45262 material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value ); 45263 break; 45264 45265 default: 45266 material.uniforms[ name ].value = uniform.value; 45267 45268 } 45269 45270 } 45271 45272 } 45273 45274 if ( json.defines !== undefined ) material.defines = json.defines; 45275 if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; 45276 if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; 45277 if ( json.glslVersion !== undefined ) material.glslVersion = json.glslVersion; 45278 45279 if ( json.extensions !== undefined ) { 45280 45281 for ( const key in json.extensions ) { 45282 45283 material.extensions[ key ] = json.extensions[ key ]; 45284 45285 } 45286 45287 } 45288 45289 if ( json.lights !== undefined ) material.lights = json.lights; 45290 if ( json.clipping !== undefined ) material.clipping = json.clipping; 45291 45292 // for PointsMaterial 45293 45294 if ( json.size !== undefined ) material.size = json.size; 45295 if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; 45296 45297 // maps 45298 45299 if ( json.map !== undefined ) material.map = getTexture( json.map ); 45300 if ( json.matcap !== undefined ) material.matcap = getTexture( json.matcap ); 45301 45302 if ( json.alphaMap !== undefined ) material.alphaMap = getTexture( json.alphaMap ); 45303 45304 if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap ); 45305 if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; 45306 45307 if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap ); 45308 if ( json.normalMapType !== undefined ) material.normalMapType = json.normalMapType; 45309 if ( json.normalScale !== undefined ) { 45310 45311 let normalScale = json.normalScale; 45312 45313 if ( Array.isArray( normalScale ) === false ) { 45314 45315 // Blender exporter used to export a scalar. See #7459 45316 45317 normalScale = [ normalScale, normalScale ]; 45318 45319 } 45320 45321 material.normalScale = new Vector2().fromArray( normalScale ); 45322 45323 } 45324 45325 if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap ); 45326 if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale; 45327 if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias; 45328 45329 if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap ); 45330 if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap ); 45331 45332 if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap ); 45333 if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity; 45334 45335 if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap ); 45336 if ( json.specularIntensityMap !== undefined ) material.specularIntensityMap = getTexture( json.specularIntensityMap ); 45337 if ( json.specularColorMap !== undefined ) material.specularColorMap = getTexture( json.specularColorMap ); 45338 45339 if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); 45340 if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity; 45341 45342 if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; 45343 if ( json.refractionRatio !== undefined ) material.refractionRatio = json.refractionRatio; 45344 45345 if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap ); 45346 if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; 45347 45348 if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap ); 45349 if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity; 45350 45351 if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); 45352 45353 if ( json.clearcoatMap !== undefined ) material.clearcoatMap = getTexture( json.clearcoatMap ); 45354 if ( json.clearcoatRoughnessMap !== undefined ) material.clearcoatRoughnessMap = getTexture( json.clearcoatRoughnessMap ); 45355 if ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap ); 45356 if ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2().fromArray( json.clearcoatNormalScale ); 45357 45358 if ( json.iridescenceMap !== undefined ) material.iridescenceMap = getTexture( json.iridescenceMap ); 45359 if ( json.iridescenceThicknessMap !== undefined ) material.iridescenceThicknessMap = getTexture( json.iridescenceThicknessMap ); 45360 45361 if ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap ); 45362 if ( json.thicknessMap !== undefined ) material.thicknessMap = getTexture( json.thicknessMap ); 45363 45364 if ( json.anisotropyMap !== undefined ) material.anisotropyMap = getTexture( json.anisotropyMap ); 45365 45366 if ( json.sheenColorMap !== undefined ) material.sheenColorMap = getTexture( json.sheenColorMap ); 45367 if ( json.sheenRoughnessMap !== undefined ) material.sheenRoughnessMap = getTexture( json.sheenRoughnessMap ); 45368 45369 return material; 45370 45371 } 45372 45373 setTextures( value ) { 45374 45375 this.textures = value; 45376 return this; 45377 45378 } 45379 45380 static createMaterialFromType( type ) { 45381 45382 const materialLib = { 45383 ShadowMaterial, 45384 SpriteMaterial, 45385 RawShaderMaterial, 45386 ShaderMaterial, 45387 PointsMaterial, 45388 MeshPhysicalMaterial, 45389 MeshStandardMaterial, 45390 MeshPhongMaterial, 45391 MeshToonMaterial, 45392 MeshNormalMaterial, 45393 MeshLambertMaterial, 45394 MeshDepthMaterial, 45395 MeshDistanceMaterial, 45396 MeshBasicMaterial, 45397 MeshMatcapMaterial, 45398 LineDashedMaterial, 45399 LineBasicMaterial, 45400 Material 45401 }; 45402 45403 return new materialLib[ type ](); 45404 45405 } 45406 45407} 45408 45409class LoaderUtils { 45410 45411 static decodeText( array ) { 45412 45413 if ( typeof TextDecoder !== 'undefined' ) { 45414 45415 return new TextDecoder().decode( array ); 45416 45417 } 45418 45419 // Avoid the String.fromCharCode.apply(null, array) shortcut, which 45420 // throws a "maximum call stack size exceeded" error for large arrays. 45421 45422 let s = ''; 45423 45424 for ( let i = 0, il = array.length; i < il; i ++ ) { 45425 45426 // Implicitly assumes little-endian. 45427 s += String.fromCharCode( array[ i ] ); 45428 45429 } 45430 45431 try { 45432 45433 // merges multi-byte utf-8 characters. 45434 45435 return decodeURIComponent( escape( s ) ); 45436 45437 } catch ( e ) { // see #16358 45438 45439 return s; 45440 45441 } 45442 45443 } 45444 45445 static extractUrlBase( url ) { 45446 45447 const index = url.lastIndexOf( '/' ); 45448 45449 if ( index === - 1 ) return './'; 45450 45451 return url.slice( 0, index + 1 ); 45452 45453 } 45454 45455 static resolveURL( url, path ) { 45456 45457 // Invalid URL 45458 if ( typeof url !== 'string' || url === '' ) return ''; 45459 45460 // Host Relative URL 45461 if ( /^https?:\/\//i.test( path ) && /^\//.test( url ) ) { 45462 45463 path = path.replace( /(^https?:\/\/[^\/]+).*/i, '$1' ); 45464 45465 } 45466 45467 // Absolute URL http://,https://,// 45468 if ( /^(https?:)?\/\//i.test( url ) ) return url; 45469 45470 // Data URI 45471 if ( /^data:.*,.*$/i.test( url ) ) return url; 45472 45473 // Blob URL 45474 if ( /^blob:.*$/i.test( url ) ) return url; 45475 45476 // Relative URL 45477 return path + url; 45478 45479 } 45480 45481} 45482 45483class InstancedBufferGeometry extends BufferGeometry { 45484 45485 constructor() { 45486 45487 super(); 45488 45489 this.isInstancedBufferGeometry = true; 45490 45491 this.type = 'InstancedBufferGeometry'; 45492 this.instanceCount = Infinity; 45493 45494 } 45495 45496 copy( source ) { 45497 45498 super.copy( source ); 45499 45500 this.instanceCount = source.instanceCount; 45501 45502 return this; 45503 45504 } 45505 45506 toJSON() { 45507 45508 const data = super.toJSON(); 45509 45510 data.instanceCount = this.instanceCount; 45511 45512 data.isInstancedBufferGeometry = true; 45513 45514 return data; 45515 45516 } 45517 45518} 45519 45520class BufferGeometryLoader extends Loader { 45521 45522 constructor( manager ) { 45523 45524 super( manager ); 45525 45526 } 45527 45528 load( url, onLoad, onProgress, onError ) { 45529 45530 const scope = this; 45531 45532 const loader = new FileLoader( scope.manager ); 45533 loader.setPath( scope.path ); 45534 loader.setRequestHeader( scope.requestHeader ); 45535 loader.setWithCredentials( scope.withCredentials ); 45536 loader.load( url, function ( text ) { 45537 45538 try { 45539 45540 onLoad( scope.parse( JSON.parse( text ) ) ); 45541 45542 } catch ( e ) { 45543 45544 if ( onError ) { 45545 45546 onError( e ); 45547 45548 } else { 45549 45550 console.error( e ); 45551 45552 } 45553 45554 scope.manager.itemError( url ); 45555 45556 } 45557 45558 }, onProgress, onError ); 45559 45560 } 45561 45562 parse( json ) { 45563 45564 const interleavedBufferMap = {}; 45565 const arrayBufferMap = {}; 45566 45567 function getInterleavedBuffer( json, uuid ) { 45568 45569 if ( interleavedBufferMap[ uuid ] !== undefined ) return interleavedBufferMap[ uuid ]; 45570 45571 const interleavedBuffers = json.interleavedBuffers; 45572 const interleavedBuffer = interleavedBuffers[ uuid ]; 45573 45574 const buffer = getArrayBuffer( json, interleavedBuffer.buffer ); 45575 45576 const array = getTypedArray( interleavedBuffer.type, buffer ); 45577 const ib = new InterleavedBuffer( array, interleavedBuffer.stride ); 45578 ib.uuid = interleavedBuffer.uuid; 45579 45580 interleavedBufferMap[ uuid ] = ib; 45581 45582 return ib; 45583 45584 } 45585 45586 function getArrayBuffer( json, uuid ) { 45587 45588 if ( arrayBufferMap[ uuid ] !== undefined ) return arrayBufferMap[ uuid ]; 45589 45590 const arrayBuffers = json.arrayBuffers; 45591 const arrayBuffer = arrayBuffers[ uuid ]; 45592 45593 const ab = new Uint32Array( arrayBuffer ).buffer; 45594 45595 arrayBufferMap[ uuid ] = ab; 45596 45597 return ab; 45598 45599 } 45600 45601 const geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry(); 45602 45603 const index = json.data.index; 45604 45605 if ( index !== undefined ) { 45606 45607 const typedArray = getTypedArray( index.type, index.array ); 45608 geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); 45609 45610 } 45611 45612 const attributes = json.data.attributes; 45613 45614 for ( const key in attributes ) { 45615 45616 const attribute = attributes[ key ]; 45617 let bufferAttribute; 45618 45619 if ( attribute.isInterleavedBufferAttribute ) { 45620 45621 const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); 45622 bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); 45623 45624 } else { 45625 45626 const typedArray = getTypedArray( attribute.type, attribute.array ); 45627 const bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute; 45628 bufferAttribute = new bufferAttributeConstr( typedArray, attribute.itemSize, attribute.normalized ); 45629 45630 } 45631 45632 if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; 45633 if ( attribute.usage !== undefined ) bufferAttribute.setUsage( attribute.usage ); 45634 45635 geometry.setAttribute( key, bufferAttribute ); 45636 45637 } 45638 45639 const morphAttributes = json.data.morphAttributes; 45640 45641 if ( morphAttributes ) { 45642 45643 for ( const key in morphAttributes ) { 45644 45645 const attributeArray = morphAttributes[ key ]; 45646 45647 const array = []; 45648 45649 for ( let i = 0, il = attributeArray.length; i < il; i ++ ) { 45650 45651 const attribute = attributeArray[ i ]; 45652 let bufferAttribute; 45653 45654 if ( attribute.isInterleavedBufferAttribute ) { 45655 45656 const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); 45657 bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); 45658 45659 } else { 45660 45661 const typedArray = getTypedArray( attribute.type, attribute.array ); 45662 bufferAttribute = new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ); 45663 45664 } 45665 45666 if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; 45667 array.push( bufferAttribute ); 45668 45669 } 45670 45671 geometry.morphAttributes[ key ] = array; 45672 45673 } 45674 45675 } 45676 45677 const morphTargetsRelative = json.data.morphTargetsRelative; 45678 45679 if ( morphTargetsRelative ) { 45680 45681 geometry.morphTargetsRelative = true; 45682 45683 } 45684 45685 const groups = json.data.groups || json.data.drawcalls || json.data.offsets; 45686 45687 if ( groups !== undefined ) { 45688 45689 for ( let i = 0, n = groups.length; i !== n; ++ i ) { 45690 45691 const group = groups[ i ]; 45692 45693 geometry.addGroup( group.start, group.count, group.materialIndex ); 45694 45695 } 45696 45697 } 45698 45699 const boundingSphere = json.data.boundingSphere; 45700 45701 if ( boundingSphere !== undefined ) { 45702 45703 const center = new Vector3(); 45704 45705 if ( boundingSphere.center !== undefined ) { 45706 45707 center.fromArray( boundingSphere.center ); 45708 45709 } 45710 45711 geometry.boundingSphere = new Sphere( center, boundingSphere.radius ); 45712 45713 } 45714 45715 if ( json.name ) geometry.name = json.name; 45716 if ( json.userData ) geometry.userData = json.userData; 45717 45718 return geometry; 45719 45720 } 45721 45722} 45723 45724class ObjectLoader extends Loader { 45725 45726 constructor( manager ) { 45727 45728 super( manager ); 45729 45730 } 45731 45732 load( url, onLoad, onProgress, onError ) { 45733 45734 const scope = this; 45735 45736 const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; 45737 this.resourcePath = this.resourcePath || path; 45738 45739 const loader = new FileLoader( this.manager ); 45740 loader.setPath( this.path ); 45741 loader.setRequestHeader( this.requestHeader ); 45742 loader.setWithCredentials( this.withCredentials ); 45743 loader.load( url, function ( text ) { 45744 45745 let json = null; 45746 45747 try { 45748 45749 json = JSON.parse( text ); 45750 45751 } catch ( error ) { 45752 45753 if ( onError !== undefined ) onError( error ); 45754 45755 console.error( 'THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message ); 45756 45757 return; 45758 45759 } 45760 45761 const metadata = json.metadata; 45762 45763 if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { 45764 45765 if ( onError !== undefined ) onError( new Error( 'THREE.ObjectLoader: Can\'t load ' + url ) ); 45766 45767 console.error( 'THREE.ObjectLoader: Can\'t load ' + url ); 45768 return; 45769 45770 } 45771 45772 scope.parse( json, onLoad ); 45773 45774 }, onProgress, onError ); 45775 45776 } 45777 45778 async loadAsync( url, onProgress ) { 45779 45780 const scope = this; 45781 45782 const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; 45783 this.resourcePath = this.resourcePath || path; 45784 45785 const loader = new FileLoader( this.manager ); 45786 loader.setPath( this.path ); 45787 loader.setRequestHeader( this.requestHeader ); 45788 loader.setWithCredentials( this.withCredentials ); 45789 45790 const text = await loader.loadAsync( url, onProgress ); 45791 45792 const json = JSON.parse( text ); 45793 45794 const metadata = json.metadata; 45795 45796 if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { 45797 45798 throw new Error( 'THREE.ObjectLoader: Can\'t load ' + url ); 45799 45800 } 45801 45802 return await scope.parseAsync( json ); 45803 45804 } 45805 45806 parse( json, onLoad ) { 45807 45808 const animations = this.parseAnimations( json.animations ); 45809 const shapes = this.parseShapes( json.shapes ); 45810 const geometries = this.parseGeometries( json.geometries, shapes ); 45811 45812 const images = this.parseImages( json.images, function () { 45813 45814 if ( onLoad !== undefined ) onLoad( object ); 45815 45816 } ); 45817 45818 const textures = this.parseTextures( json.textures, images ); 45819 const materials = this.parseMaterials( json.materials, textures ); 45820 45821 const object = this.parseObject( json.object, geometries, materials, textures, animations ); 45822 const skeletons = this.parseSkeletons( json.skeletons, object ); 45823 45824 this.bindSkeletons( object, skeletons ); 45825 45826 // 45827 45828 if ( onLoad !== undefined ) { 45829 45830 let hasImages = false; 45831 45832 for ( const uuid in images ) { 45833 45834 if ( images[ uuid ].data instanceof HTMLImageElement ) { 45835 45836 hasImages = true; 45837 break; 45838 45839 } 45840 45841 } 45842 45843 if ( hasImages === false ) onLoad( object ); 45844 45845 } 45846 45847 return object; 45848 45849 } 45850 45851 async parseAsync( json ) { 45852 45853 const animations = this.parseAnimations( json.animations ); 45854 const shapes = this.parseShapes( json.shapes ); 45855 const geometries = this.parseGeometries( json.geometries, shapes ); 45856 45857 const images = await this.parseImagesAsync( json.images ); 45858 45859 const textures = this.parseTextures( json.textures, images ); 45860 const materials = this.parseMaterials( json.materials, textures ); 45861 45862 const object = this.parseObject( json.object, geometries, materials, textures, animations ); 45863 const skeletons = this.parseSkeletons( json.skeletons, object ); 45864 45865 this.bindSkeletons( object, skeletons ); 45866 45867 return object; 45868 45869 } 45870 45871 parseShapes( json ) { 45872 45873 const shapes = {}; 45874 45875 if ( json !== undefined ) { 45876 45877 for ( let i = 0, l = json.length; i < l; i ++ ) { 45878 45879 const shape = new Shape().fromJSON( json[ i ] ); 45880 45881 shapes[ shape.uuid ] = shape; 45882 45883 } 45884 45885 } 45886 45887 return shapes; 45888 45889 } 45890 45891 parseSkeletons( json, object ) { 45892 45893 const skeletons = {}; 45894 const bones = {}; 45895 45896 // generate bone lookup table 45897 45898 object.traverse( function ( child ) { 45899 45900 if ( child.isBone ) bones[ child.uuid ] = child; 45901 45902 } ); 45903 45904 // create skeletons 45905 45906 if ( json !== undefined ) { 45907 45908 for ( let i = 0, l = json.length; i < l; i ++ ) { 45909 45910 const skeleton = new Skeleton().fromJSON( json[ i ], bones ); 45911 45912 skeletons[ skeleton.uuid ] = skeleton; 45913 45914 } 45915 45916 } 45917 45918 return skeletons; 45919 45920 } 45921 45922 parseGeometries( json, shapes ) { 45923 45924 const geometries = {}; 45925 45926 if ( json !== undefined ) { 45927 45928 const bufferGeometryLoader = new BufferGeometryLoader(); 45929 45930 for ( let i = 0, l = json.length; i < l; i ++ ) { 45931 45932 let geometry; 45933 const data = json[ i ]; 45934 45935 switch ( data.type ) { 45936 45937 case 'BufferGeometry': 45938 case 'InstancedBufferGeometry': 45939 45940 geometry = bufferGeometryLoader.parse( data ); 45941 break; 45942 45943 default: 45944 45945 if ( data.type in Geometries ) { 45946 45947 geometry = Geometries[ data.type ].fromJSON( data, shapes ); 45948 45949 } else { 45950 45951 console.warn( `THREE.ObjectLoader: Unsupported geometry type "${ data.type }"` ); 45952 45953 } 45954 45955 } 45956 45957 geometry.uuid = data.uuid; 45958 45959 if ( data.name !== undefined ) geometry.name = data.name; 45960 if ( data.userData !== undefined ) geometry.userData = data.userData; 45961 45962 geometries[ data.uuid ] = geometry; 45963 45964 } 45965 45966 } 45967 45968 return geometries; 45969 45970 } 45971 45972 parseMaterials( json, textures ) { 45973 45974 const cache = {}; // MultiMaterial 45975 const materials = {}; 45976 45977 if ( json !== undefined ) { 45978 45979 const loader = new MaterialLoader(); 45980 loader.setTextures( textures ); 45981 45982 for ( let i = 0, l = json.length; i < l; i ++ ) { 45983 45984 const data = json[ i ]; 45985 45986 if ( cache[ data.uuid ] === undefined ) { 45987 45988 cache[ data.uuid ] = loader.parse( data ); 45989 45990 } 45991 45992 materials[ data.uuid ] = cache[ data.uuid ]; 45993 45994 } 45995 45996 } 45997 45998 return materials; 45999 46000 } 46001 46002 parseAnimations( json ) { 46003 46004 const animations = {}; 46005 46006 if ( json !== undefined ) { 46007 46008 for ( let i = 0; i < json.length; i ++ ) { 46009 46010 const data = json[ i ]; 46011 46012 const clip = AnimationClip.parse( data ); 46013 46014 animations[ clip.uuid ] = clip; 46015 46016 } 46017 46018 } 46019 46020 return animations; 46021 46022 } 46023 46024 parseImages( json, onLoad ) { 46025 46026 const scope = this; 46027 const images = {}; 46028 46029 let loader; 46030 46031 function loadImage( url ) { 46032 46033 scope.manager.itemStart( url ); 46034 46035 return loader.load( url, function () { 46036 46037 scope.manager.itemEnd( url ); 46038 46039 }, undefined, function () { 46040 46041 scope.manager.itemError( url ); 46042 scope.manager.itemEnd( url ); 46043 46044 } ); 46045 46046 } 46047 46048 function deserializeImage( image ) { 46049 46050 if ( typeof image === 'string' ) { 46051 46052 const url = image; 46053 46054 const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; 46055 46056 return loadImage( path ); 46057 46058 } else { 46059 46060 if ( image.data ) { 46061 46062 return { 46063 data: getTypedArray( image.type, image.data ), 46064 width: image.width, 46065 height: image.height 46066 }; 46067 46068 } else { 46069 46070 return null; 46071 46072 } 46073 46074 } 46075 46076 } 46077 46078 if ( json !== undefined && json.length > 0 ) { 46079 46080 const manager = new LoadingManager( onLoad ); 46081 46082 loader = new ImageLoader( manager ); 46083 loader.setCrossOrigin( this.crossOrigin ); 46084 46085 for ( let i = 0, il = json.length; i < il; i ++ ) { 46086 46087 const image = json[ i ]; 46088 const url = image.url; 46089 46090 if ( Array.isArray( url ) ) { 46091 46092 // load array of images e.g CubeTexture 46093 46094 const imageArray = []; 46095 46096 for ( let j = 0, jl = url.length; j < jl; j ++ ) { 46097 46098 const currentUrl = url[ j ]; 46099 46100 const deserializedImage = deserializeImage( currentUrl ); 46101 46102 if ( deserializedImage !== null ) { 46103 46104 if ( deserializedImage instanceof HTMLImageElement ) { 46105 46106 imageArray.push( deserializedImage ); 46107 46108 } else { 46109 46110 // special case: handle array of data textures for cube textures 46111 46112 imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); 46113 46114 } 46115 46116 } 46117 46118 } 46119 46120 images[ image.uuid ] = new Source( imageArray ); 46121 46122 } else { 46123 46124 // load single image 46125 46126 const deserializedImage = deserializeImage( image.url ); 46127 images[ image.uuid ] = new Source( deserializedImage ); 46128 46129 46130 } 46131 46132 } 46133 46134 } 46135 46136 return images; 46137 46138 } 46139 46140 async parseImagesAsync( json ) { 46141 46142 const scope = this; 46143 const images = {}; 46144 46145 let loader; 46146 46147 async function deserializeImage( image ) { 46148 46149 if ( typeof image === 'string' ) { 46150 46151 const url = image; 46152 46153 const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; 46154 46155 return await loader.loadAsync( path ); 46156 46157 } else { 46158 46159 if ( image.data ) { 46160 46161 return { 46162 data: getTypedArray( image.type, image.data ), 46163 width: image.width, 46164 height: image.height 46165 }; 46166 46167 } else { 46168 46169 return null; 46170 46171 } 46172 46173 } 46174 46175 } 46176 46177 if ( json !== undefined && json.length > 0 ) { 46178 46179 loader = new ImageLoader( this.manager ); 46180 loader.setCrossOrigin( this.crossOrigin ); 46181 46182 for ( let i = 0, il = json.length; i < il; i ++ ) { 46183 46184 const image = json[ i ]; 46185 const url = image.url; 46186 46187 if ( Array.isArray( url ) ) { 46188 46189 // load array of images e.g CubeTexture 46190 46191 const imageArray = []; 46192 46193 for ( let j = 0, jl = url.length; j < jl; j ++ ) { 46194 46195 const currentUrl = url[ j ]; 46196 46197 const deserializedImage = await deserializeImage( currentUrl ); 46198 46199 if ( deserializedImage !== null ) { 46200 46201 if ( deserializedImage instanceof HTMLImageElement ) { 46202 46203 imageArray.push( deserializedImage ); 46204 46205 } else { 46206 46207 // special case: handle array of data textures for cube textures 46208 46209 imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); 46210 46211 } 46212 46213 } 46214 46215 } 46216 46217 images[ image.uuid ] = new Source( imageArray ); 46218 46219 } else { 46220 46221 // load single image 46222 46223 const deserializedImage = await deserializeImage( image.url ); 46224 images[ image.uuid ] = new Source( deserializedImage ); 46225 46226 } 46227 46228 } 46229 46230 } 46231 46232 return images; 46233 46234 } 46235 46236 parseTextures( json, images ) { 46237 46238 function parseConstant( value, type ) { 46239 46240 if ( typeof value === 'number' ) return value; 46241 46242 console.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value ); 46243 46244 return type[ value ]; 46245 46246 } 46247 46248 const textures = {}; 46249 46250 if ( json !== undefined ) { 46251 46252 for ( let i = 0, l = json.length; i < l; i ++ ) { 46253 46254 const data = json[ i ]; 46255 46256 if ( data.image === undefined ) { 46257 46258 console.warn( 'THREE.ObjectLoader: No "image" specified for', data.uuid ); 46259 46260 } 46261 46262 if ( images[ data.image ] === undefined ) { 46263 46264 console.warn( 'THREE.ObjectLoader: Undefined image', data.image ); 46265 46266 } 46267 46268 const source = images[ data.image ]; 46269 const image = source.data; 46270 46271 let texture; 46272 46273 if ( Array.isArray( image ) ) { 46274 46275 texture = new CubeTexture(); 46276 46277 if ( image.length === 6 ) texture.needsUpdate = true; 46278 46279 } else { 46280 46281 if ( image && image.data ) { 46282 46283 texture = new DataTexture(); 46284 46285 } else { 46286 46287 texture = new Texture(); 46288 46289 } 46290 46291 if ( image ) texture.needsUpdate = true; // textures can have undefined image data 46292 46293 } 46294 46295 texture.source = source; 46296 46297 texture.uuid = data.uuid; 46298 46299 if ( data.name !== undefined ) texture.name = data.name; 46300 46301 if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); 46302 if ( data.channel !== undefined ) texture.channel = data.channel; 46303 46304 if ( data.offset !== undefined ) texture.offset.fromArray( data.offset ); 46305 if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat ); 46306 if ( data.center !== undefined ) texture.center.fromArray( data.center ); 46307 if ( data.rotation !== undefined ) texture.rotation = data.rotation; 46308 46309 if ( data.wrap !== undefined ) { 46310 46311 texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING ); 46312 texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING ); 46313 46314 } 46315 46316 if ( data.format !== undefined ) texture.format = data.format; 46317 if ( data.internalFormat !== undefined ) texture.internalFormat = data.internalFormat; 46318 if ( data.type !== undefined ) texture.type = data.type; 46319 if ( data.colorSpace !== undefined ) texture.colorSpace = data.colorSpace; 46320 if ( data.encoding !== undefined ) texture.encoding = data.encoding; // @deprecated, r152 46321 46322 if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minF
46322ilter, TEXTURE_FILTER ); 46323 if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER ); 46324 if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; 46325 46326 if ( data.flipY !== undefined ) texture.flipY = data.flipY; 46327 46328 if ( data.generateMipmaps !== undefined ) texture.generateMipmaps = data.generateMipmaps; 46329 if ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha; 46330 if ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment; 46331 if ( data.compareFunction !== undefined ) texture.compareFunction = data.compareFunction; 46332 46333 if ( data.userData !== undefined ) texture.userData = data.userData; 46334 46335 textures[ data.uuid ] = texture; 46336 46337 } 46338 46339 } 46340 46341 return textures; 46342 46343 } 46344 46345 parseObject( data, geometries, materials, textures, animations ) { 46346 46347 let object; 46348 46349 function getGeometry( name ) { 46350 46351 if ( geometries[ name ] === undefined ) { 46352 46353 console.warn( 'THREE.ObjectLoader: Undefined geometry', name ); 46354 46355 } 46356 46357 return geometries[ name ]; 46358 46359 } 46360 46361 function getMaterial( name ) { 46362
vendor: 5,576 bytes, lines 46363-46587
46363 if ( name === undefined ) return undefined; 46364 46365 if ( Array.isArray( name ) ) { 46366 46367 const array = []; 46368 46369 for ( let i = 0, l = name.length; i < l; i ++ ) { 46370 46371 const uuid = name[ i ]; 46372 46373 if ( materials[ uuid ] === undefined ) { 46374 46375 console.warn( 'THREE.ObjectLoader: Undefined material', uuid ); 46376 46377 } 46378 46379 array.push( materials[ uuid ] ); 46380 46381 } 46382 46383 return array; 46384 46385 } 46386 46387 if ( materials[ name ] === undefined ) { 46388 46389 console.warn( 'THREE.ObjectLoader: Undefined material', name ); 46390 46391 } 46392 46393 return materials[ name ]; 46394 46395 } 46396 46397 function getTexture( uuid ) { 46398 46399 if ( textures[ uuid ] === undefined ) { 46400 46401 console.warn( 'THREE.ObjectLoader: Undefined texture', uuid ); 46402 46403 } 46404 46405 return textures[ uuid ]; 46406 46407 } 46408 46409 let geometry, material; 46410 46411 switch ( data.type ) { 46412 46413 case 'Scene': 46414 46415 object = new Scene(); 46416 46417 if ( data.background !== undefined ) { 46418 46419 if ( Number.isInteger( data.background ) ) { 46420 46421 object.background = new Color( data.background ); 46422 46423 } else { 46424 46425 object.background = getTexture( data.background ); 46426 46427 } 46428 46429 } 46430 46431 if ( data.environment !== undefined ) { 46432 46433 object.environment = getTexture( data.environment ); 46434 46435 } 46436 46437 if ( data.fog !== undefined ) { 46438 46439 if ( data.fog.type === 'Fog' ) { 46440 46441 object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); 46442 46443 } else if ( data.fog.type === 'FogExp2' ) { 46444 46445 object.fog = new FogExp2( data.fog.color, data.fog.density ); 46446 46447 } 46448 46449 if ( data.fog.name !== '' ) { 46450 46451 object.fog.name = data.fog.name; 46452 46453 } 46454 46455 } 46456 46457 if ( data.backgroundBlurriness !== undefined ) object.backgroundBlurriness = data.backgroundBlurriness; 46458 if ( data.backgroundIntensity !== undefined ) object.backgroundIntensity = data.backgroundIntensity; 46459 46460 break; 46461 46462 case 'PerspectiveCamera': 46463 46464 object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); 46465 46466 if ( data.focus !== undefined ) object.focus = data.focus; 46467 if ( data.zoom !== undefined ) object.zoom = data.zoom; 46468 if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge; 46469 if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset; 46470 if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); 46471 46472 break; 46473 46474 case 'OrthographicCamera': 46475 46476 object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); 46477 46478 if ( data.zoom !== undefined ) object.zoom = data.zoom; 46479 if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); 46480 46481 break; 46482 46483 case 'AmbientLight': 46484 46485 object = new AmbientLight( data.color, data.intensity ); 46486 46487 break; 46488 46489 case 'DirectionalLight': 46490 46491 object = new DirectionalLight( data.color, data.intensity ); 46492 46493 break; 46494 46495 case 'PointLight': 46496 46497 46498 object = new PointLight( data.color, data.intensity, data.distance, data.decay ); 46499 46500 break; 46501 46502 case 'RectAreaLight': 46503 46504 object = new RectAreaLight( data.color, data.intensity, data.width, data.height ); 46505 46506 break; 46507 46508 case 'SpotLight': 46509 46510 object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); 46511 46512 break; 46513 46514 case 'HemisphereLight': 46515 46516 object = new HemisphereLight( data.color, data.groundColor, data.intensity ); 46517 46518 break; 46519 46520 case 'LightProbe': 46521 46522 object = new LightProbe().fromJSON( data ); 46523 46524 break; 46525 46526 case 'SkinnedMesh': 46527 46528 geometry = getGeometry( data.geometry ); 46529 material = getMaterial( data.material ); 46530 46531 object = new SkinnedMesh( geometry, material ); 46532 46533 if ( data.bindMode !== undefined ) object.bindMode = data.bindMode; 46534 if ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix ); 46535 if ( data.skeleton !== undefined ) object.skeleton = data.skeleton; 46536 46537 break; 46538 46539 case 'Mesh': 46540 46541 geometry = getGeometry( data.geometry ); 46542 material = getMaterial( data.material ); 46543 46544 object = new Mesh( geometry, material ); 46545 46546 break; 46547 46548 case 'InstancedMesh': 46549 46550 geometry = getGeometry( data.geometry ); 46551 material = getMaterial( data.material ); 46552 const count = data.count; 46553 const instanceMatrix = data.instanceMatrix; 46554 const instanceColor = data.instanceColor; 46555 46556 object = new InstancedMesh( geometry, material, count ); 46557 object.instanceMatrix = new InstancedBufferAttribute( new Float32Array( instanceMatrix.array ), 16 ); 46558 if ( instanceColor !== undefined ) object.instanceColor = new InstancedBufferAttribute( new Float32Array( instanceColor.array ), instanceColor.itemSize ); 46559 46560 break; 46561 46562 case 'BatchedMesh': 46563 46564 geometry = getGeometry( data.geometry ); 46565 material = getMaterial( data.material ); 46566 46567 object = new BatchedMesh( data.maxGeometryCount, data.maxVertexCount, data.maxIndexCount, material ); 46568 object.geometry = geometry; 46569 object.perObjectFrustumCulled = data.perObjectFrustumCulled; 46570 object.sortObjects = data.sortObjects; 46571 46572 object._drawRanges = data.drawRanges; 46573 object._reservedRanges = data.reservedRanges; 46574 46575 object._visibility = data.visibility; 46576 object._active = data.active; 46577 object._bounds = data.bounds.map( bound => { 46578 46579 const box = new Box3(); 46580 box.min.fromArray( bound.boxMin ); 46581 box.max.fromArray( bound.boxMax ); 46582 46583 const sphere = new Sphere(); 46584 sphere.radius = bound.sphereRadius; 46585 sphere.center.fromArray( bound.sphereCenter ); 46586 46587 return {
vendor: 40,161 bytes, lines 46588-48541
46588 boxInitialized: bound.boxInitialized, 46589 box: box, 46590 46591 sphereInitialized: bound.sphereInitialized, 46592 sphere: sphere 46593 }; 46594 46595 } ); 46596 46597 object._maxGeometryCount = data.maxGeometryCount; 46598 object._maxVertexCount = data.maxVertexCount; 46599 object._maxIndexCount = data.maxIndexCount; 46600 46601 object._geometryInitialized = data.geometryInitialized; 46602 object._geometryCount = data.geometryCount; 46603 46604 object._matricesTexture = getTexture( data.matricesTexture.uuid ); 46605 46606 break; 46607 46608 case 'LOD': 46609 46610 object = new LOD(); 46611 46612 break; 46613 46614 case 'Line': 46615 46616 object = new Line( getGeometry( data.geometry ), getMaterial( data.material ) ); 46617 46618 break; 46619 46620 case 'LineLoop': 46621 46622 object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); 46623 46624 break; 46625 46626 case 'LineSegments': 46627 46628 object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); 46629 46630 break; 46631 46632 case 'PointCloud': 46633 case 'Points': 46634 46635 object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); 46636 46637 break; 46638 46639 case 'Sprite': 46640 46641 object = new Sprite( getMaterial( data.material ) ); 46642 46643 break; 46644 46645 case 'Group': 46646 46647 object = new Group(); 46648 46649 break; 46650 46651 case 'Bone': 46652 46653 object = new Bone(); 46654 46655 break; 46656 46657 default: 46658 46659 object = new Object3D(); 46660 46661 } 46662 46663 object.uuid = data.uuid; 46664 46665 if ( data.name !== undefined ) object.name = data.name; 46666 46667 if ( data.matrix !== undefined ) { 46668 46669 object.matrix.fromArray( data.matrix ); 46670 46671 if ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate; 46672 if ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale ); 46673 46674 } else { 46675 46676 if ( data.position !== undefined ) object.position.fromArray( data.position ); 46677 if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); 46678 if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion ); 46679 if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); 46680 46681 } 46682 46683 if ( data.up !== undefined ) object.up.fromArray( data.up ); 46684 46685 if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; 46686 if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; 46687 46688 if ( data.shadow ) { 46689 46690 if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias; 46691 if ( data.shadow.normalBias !== undefined ) object.shadow.normalBias = data.shadow.normalBias; 46692 if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius; 46693 if ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize ); 46694 if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera ); 46695 46696 } 46697 46698 if ( data.visible !== undefined ) object.visible = data.visible; 46699 if ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled; 46700 if ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder; 46701 if ( data.userData !== undefined ) object.userData = data.userData; 46702 if ( data.layers !== undefined ) object.layers.mask = data.layers; 46703 46704 if ( data.children !== undefined ) { 46705 46706 const children = data.children; 46707 46708 for ( let i = 0; i < children.length; i ++ ) { 46709 46710 object.add( this.parseObject( children[ i ], geometries, materials, textures, animations ) ); 46711 46712 } 46713 46714 } 46715 46716 if ( data.animations !== undefined ) { 46717 46718 const objectAnimations = data.animations; 46719 46720 for ( let i = 0; i < objectAnimations.length; i ++ ) { 46721 46722 const uuid = objectAnimations[ i ]; 46723 46724 object.animations.push( animations[ uuid ] ); 46725 46726 } 46727 46728 } 46729 46730 if ( data.type === 'LOD' ) { 46731 46732 if ( data.autoUpdate !== undefined ) object.autoUpdate = data.autoUpdate; 46733 46734 const levels = data.levels; 46735 46736 for ( let l = 0; l < levels.length; l ++ ) { 46737 46738 const level = levels[ l ]; 46739 const child = object.getObjectByProperty( 'uuid', level.object ); 46740 46741 if ( child !== undefined ) { 46742 46743 object.addLevel( child, level.distance, level.hysteresis ); 46744 46745 } 46746 46747 } 46748 46749 } 46750 46751 return object; 46752 46753 } 46754 46755 bindSkeletons( object, skeletons ) { 46756 46757 if ( Object.keys( skeletons ).length === 0 ) return; 46758 46759 object.traverse( function ( child ) { 46760 46761 if ( child.isSkinnedMesh === true && child.skeleton !== undefined ) { 46762 46763 const skeleton = skeletons[ child.skeleton ]; 46764 46765 if ( skeleton === undefined ) { 46766 46767 console.warn( 'THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton ); 46768 46769 } else { 46770 46771 child.bind( skeleton, child.bindMatrix ); 46772 46773 } 46774 46775 } 46776 46777 } ); 46778 46779 } 46780 46781} 46782 46783const TEXTURE_MAPPING = { 46784 UVMapping: UVMapping, 46785 CubeReflectionMapping: CubeReflectionMapping, 46786 CubeRefractionMapping: CubeRefractionMapping, 46787 EquirectangularReflectionMapping: EquirectangularReflectionMapping, 46788 EquirectangularRefractionMapping: EquirectangularRefractionMapping, 46789 CubeUVReflectionMapping: CubeUVReflectionMapping 46790}; 46791 46792const TEXTURE_WRAPPING = { 46793 RepeatWrapping: RepeatWrapping, 46794 ClampToEdgeWrapping: ClampToEdgeWrapping, 46795 MirroredRepeatWrapping: MirroredRepeatWrapping 46796}; 46797 46798const TEXTURE_FILTER = { 46799 NearestFilter: NearestFilter, 46800 NearestMipmapNearestFilter: NearestMipmapNearestFilter, 46801 NearestMipmapLinearFilter: NearestMipmapLinearFilter, 46802 LinearFilter: LinearFilter, 46803 LinearMipmapNearestFilter: LinearMipmapNearestFilter, 46804 LinearMipmapLinearFilter: LinearMipmapLinearFilter 46805}; 46806 46807class ImageBitmapLoader extends Loader { 46808 46809 constructor( manager ) { 46810 46811 super( manager ); 46812 46813 this.isImageBitmapLoader = true; 46814 46815 if ( typeof createImageBitmap === 'undefined' ) { 46816 46817 console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' ); 46818 46819 } 46820 46821 if ( typeof fetch === 'undefined' ) { 46822 46823 console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' ); 46824 46825 } 46826 46827 this.options = { premultiplyAlpha: 'none' }; 46828 46829 } 46830 46831 setOptions( options ) { 46832 46833 this.options = options; 46834 46835 return this; 46836 46837 } 46838 46839 load( url, onLoad, onProgress, onError ) { 46840 46841 if ( url === undefined ) url = ''; 46842 46843 if ( this.path !== undefined ) url = this.path + url; 46844 46845 url = this.manager.resolveURL( url ); 46846 46847 const scope = this; 46848 46849 const cached = Cache.get( url ); 46850 46851 if ( cached !== undefined ) { 46852 46853 scope.manager.itemStart( url ); 46854 46855 // If cached is a promise, wait for it to resolve 46856 if ( cached.then ) { 46857 46858 cached.then( imageBitmap => { 46859 46860 if ( onLoad ) onLoad( imageBitmap ); 46861 46862 scope.manager.itemEnd( url ); 46863 46864 } ).catch( e => { 46865 46866 if ( onError ) onError( e ); 46867 46868 } ); 46869 return; 46870 46871 } 46872 46873 // If cached is not a promise (i.e., it's already an imageBitmap) 46874 setTimeout( function () { 46875 46876 if ( onLoad ) onLoad( cached ); 46877 46878 scope.manager.itemEnd( url ); 46879 46880 }, 0 ); 46881 46882 return cached; 46883 46884 } 46885 46886 const fetchOptions = {}; 46887 fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include'; 46888 fetchOptions.headers = this.requestHeader; 46889 46890 const promise = fetch( url, fetchOptions ).then( function ( res ) { 46891 46892 return res.blob(); 46893 46894 } ).then( function ( blob ) { 46895 46896 return createImageBitmap( blob, Object.assign( scope.options, { colorSpaceConversion: 'none' } ) ); 46897 46898 } ).then( function ( imageBitmap ) { 46899 46900 Cache.add( url, imageBitmap ); 46901 46902 if ( onLoad ) onLoad( imageBitmap ); 46903 46904 scope.manager.itemEnd( url ); 46905 46906 return imageBitmap; 46907 46908 } ).catch( function ( e ) { 46909 46910 if ( onError ) onError( e ); 46911 46912 Cache.remove( url ); 46913 46914 scope.manager.itemError( url ); 46915 scope.manager.itemEnd( url ); 46916 46917 } ); 46918 46919 Cache.add( url, promise ); 46920 scope.manager.itemStart( url ); 46921 46922 } 46923 46924} 46925 46926let _context; 46927 46928class AudioContext { 46929 46930 static getContext() { 46931 46932 if ( _context === undefined ) { 46933 46934 _context = new ( window.AudioContext || window.webkitAudioContext )(); 46935 46936 } 46937 46938 return _context; 46939 46940 } 46941 46942 static setContext( value ) { 46943 46944 _context = value; 46945 46946 } 46947 46948} 46949 46950class AudioLoader extends Loader { 46951 46952 constructor( manager ) { 46953 46954 super( manager ); 46955 46956 } 46957 46958 load( url, onLoad, onProgress, onError ) { 46959 46960 const scope = this; 46961 46962 const loader = new FileLoader( this.manager ); 46963 loader.setResponseType( 'arraybuffer' ); 46964 loader.setPath( this.path ); 46965 loader.setRequestHeader( this.requestHeader ); 46966 loader.setWithCredentials( this.withCredentials ); 46967 loader.load( url, function ( buffer ) { 46968 46969 try { 46970 46971 // Create a copy of the buffer. The `decodeAudioData` method 46972 // detaches the buffer when complete, preventing reuse. 46973 const bufferCopy = buffer.slice( 0 ); 46974 46975 const context = AudioContext.getContext(); 46976 context.decodeAudioData( bufferCopy, function ( audioBuffer ) { 46977 46978 onLoad( audioBuffer ); 46979 46980 } ).catch( handleError ); 46981 46982 } catch ( e ) { 46983 46984 handleError( e ); 46985 46986 } 46987 46988 }, onProgress, onError ); 46989 46990 function handleError( e ) { 46991 46992 if ( onError ) { 46993 46994 onError( e ); 46995 46996 } else { 46997 46998 console.error( e ); 46999 47000 } 47001 47002 scope.manager.itemError( url ); 47003 47004 } 47005 47006 } 47007 47008} 47009 47010const _eyeRight = /*@__PURE__*/ new Matrix4(); 47011const _eyeLeft = /*@__PURE__*/ new Matrix4(); 47012const _projectionMatrix = /*@__PURE__*/ new Matrix4(); 47013 47014class StereoCamera { 47015 47016 constructor() { 47017 47018 this.type = 'StereoCamera'; 47019 47020 this.aspect = 1; 47021 47022 this.eyeSep = 0.064; 47023 47024 this.cameraL = new PerspectiveCamera(); 47025 this.cameraL.layers.enable( 1 ); 47026 this.cameraL.matrixAutoUpdate = false; 47027 47028 this.cameraR = new PerspectiveCamera(); 47029 this.cameraR.layers.enable( 2 ); 47030 this.cameraR.matrixAutoUpdate = false; 47031 47032 this._cache = { 47033 focus: null, 47034 fov: null, 47035 aspect: null, 47036 near: null, 47037 far: null, 47038 zoom: null, 47039 eyeSep: null 47040 }; 47041 47042 } 47043 47044 update( camera ) { 47045 47046 const cache = this._cache; 47047 47048 const needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov || 47049 cache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near || 47050 cache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep; 47051 47052 if ( needsUpdate ) { 47053 47054 cache.focus = camera.focus; 47055 cache.fov = camera.fov; 47056 cache.aspect = camera.aspect * this.aspect; 47057 cache.near = camera.near; 47058 cache.far = camera.far; 47059 cache.zoom = camera.zoom; 47060 cache.eyeSep = this.eyeSep; 47061 47062 // Off-axis stereoscopic effect based on 47063 // http://paulbourke.net/stereographics/stereorender/ 47064 47065 _projectionMatrix.copy( camera.projectionMatrix ); 47066 const eyeSepHalf = cache.eyeSep / 2; 47067 const eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus; 47068 const ymax = ( cache.near * Math.tan( DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom; 47069 let xmin, xmax; 47070 47071 // translate xOffset 47072 47073 _eyeLeft.elements[ 12 ] = - eyeSepHalf; 47074 _eyeRight.elements[ 12 ] = eyeSepHalf; 47075 47076 // for left eye 47077 47078 xmin = - ymax * cache.aspect + eyeSepOnProjection; 47079 xmax = ymax * cache.aspect + eyeSepOnProjection; 47080 47081 _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); 47082 _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); 47083 47084 this.cameraL.projectionMatrix.copy( _projectionMatrix ); 47085 47086 // for right eye 47087 47088 xmin = - ymax * cache.aspect - eyeSepOnProjection; 47089 xmax = ymax * cache.aspect - eyeSepOnProjection; 47090 47091 _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); 47092 _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); 47093 47094 this.cameraR.projectionMatrix.copy( _projectionMatrix ); 47095 47096 } 47097 47098 this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeLeft ); 47099 this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight ); 47100 47101 } 47102 47103} 47104 47105class Clock { 47106 47107 constructor( autoStart = true ) { 47108 47109 this.autoStart = autoStart; 47110 47111 this.startTime = 0; 47112 this.oldTime = 0; 47113 this.elapsedTime = 0; 47114 47115 this.running = false; 47116 47117 } 47118 47119 start() { 47120 47121 this.startTime = now(); 47122 47123 this.oldTime = this.startTime; 47124 this.elapsedTime = 0; 47125 this.running = true; 47126 47127 } 47128 47129 stop() { 47130 47131 this.getElapsedTime(); 47132 this.running = false; 47133 this.autoStart = false; 47134 47135 } 47136 47137 getElapsedTime() { 47138 47139 this.getDelta(); 47140 return this.elapsedTime; 47141 47142 } 47143 47144 getDelta() { 47145 47146 let diff = 0; 47147 47148 if ( this.autoStart && ! this.running ) { 47149 47150 this.start(); 47151 return 0; 47152 47153 } 47154 47155 if ( this.running ) { 47156 47157 const newTime = now(); 47158 47159 diff = ( newTime - this.oldTime ) / 1000; 47160 this.oldTime = newTime; 47161 47162 this.elapsedTime += diff; 47163 47164 } 47165 47166 return diff; 47167 47168 } 47169 47170} 47171 47172function now() { 47173 47174 return ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732 47175 47176} 47177 47178const _position$1 = /*@__PURE__*/ new Vector3(); 47179const _quaternion$1 = /*@__PURE__*/ new Quaternion(); 47180const _scale$1 = /*@__PURE__*/ new Vector3(); 47181const _orientation$1 = /*@__PURE__*/ new Vector3(); 47182 47183class AudioListener extends Object3D { 47184 47185 constructor() { 47186 47187 super(); 47188 47189 this.type = 'AudioListener'; 47190 47191 this.context = AudioContext.getContext(); 47192 47193 this.gain = this.context.createGain(); 47194 this.gain.connect( this.context.destination ); 47195 47196 this.filter = null; 47197 47198 this.timeDelta = 0; 47199 47200 // private 47201 47202 this._clock = new Clock(); 47203 47204 } 47205 47206 getInput() { 47207 47208 return this.gain; 47209 47210 } 47211 47212 removeFilter() { 47213 47214 if ( this.filter !== null ) { 47215 47216 this.gain.disconnect( this.filter ); 47217 this.filter.disconnect( this.context.destination ); 47218 this.gain.connect( this.context.destination ); 47219 this.filter = null; 47220 47221 } 47222 47223 return this; 47224 47225 } 47226 47227 getFilter() { 47228 47229 return this.filter; 47230 47231 } 47232 47233 setFilter( value ) { 47234 47235 if ( this.filter !== null ) { 47236 47237 this.gain.disconnect( this.filter ); 47238 this.filter.disconnect( this.context.destination ); 47239 47240 } else { 47241 47242 this.gain.disconnect( this.context.destination ); 47243 47244 } 47245 47246 this.filter = value; 47247 this.gain.connect( this.filter ); 47248 this.filter.connect( this.context.destination ); 47249 47250 return this; 47251 47252 } 47253 47254 getMasterVolume() { 47255 47256 return this.gain.gain.value; 47257 47258 } 47259 47260 setMasterVolume( value ) { 47261 47262 this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); 47263 47264 return this; 47265 47266 } 47267 47268 updateMatrixWorld( force ) { 47269 47270 super.updateMatrixWorld( force ); 47271 47272 const listener = this.context.listener; 47273 const up = this.up; 47274 47275 this.timeDelta = this._clock.getDelta(); 47276 47277 this.matrixWorld.decompose( _position$1, _quaternion$1, _scale$1 ); 47278 47279 _orientation$1.set( 0, 0, - 1 ).applyQuaternion( _quaternion$1 ); 47280 47281 if ( listener.positionX ) { 47282 47283 // code path for Chrome (see #14393) 47284 47285 const endTime = this.context.currentTime + this.timeDelta; 47286 47287 listener.positionX.linearRampToValueAtTime( _position$1.x, endTime ); 47288 listener.positionY.linearRampToValueAtTime( _position$1.y, endTime ); 47289 listener.positionZ.linearRampToValueAtTime( _position$1.z, endTime ); 47290 listener.forwardX.linearRampToValueAtTime( _orientation$1.x, endTime ); 47291 listener.forwardY.linearRampToValueAtTime( _orientation$1.y, endTime ); 47292 listener.forwardZ.linearRampToValueAtTime( _orientation$1.z, endTime ); 47293 listener.upX.linearRampToValueAtTime( up.x, endTime ); 47294 listener.upY.linearRampToValueAtTime( up.y, endTime ); 47295 listener.upZ.linearRampToValueAtTime( up.z, endTime ); 47296 47297 } else { 47298 47299 listener.setPosition( _position$1.x, _position$1.y, _position$1.z ); 47300 listener.setOrientation( _orientation$1.x, _orientation$1.y, _orientation$1.z, up.x, up.y, up.z ); 47301 47302 } 47303 47304 } 47305 47306} 47307 47308class Audio extends Object3D { 47309 47310 constructor( listener ) { 47311 47312 super(); 47313 47314 this.type = 'Audio'; 47315 47316 this.listener = listener; 47317 this.context = listener.context; 47318 47319 this.gain = this.context.createGain(); 47320 this.gain.connect( listener.getInput() ); 47321 47322 this.autoplay = false; 47323 47324 this.buffer = null; 47325 this.detune = 0; 47326 this.loop = false; 47327 this.loopStart = 0; 47328 this.loopEnd = 0; 47329 this.offset = 0; 47330 this.duration = undefined; 47331 this.playbackRate = 1; 47332 this.isPlaying = false; 47333 this.hasPlaybackControl = true; 47334 this.source = null; 47335 this.sourceType = 'empty'; 47336 47337 this._startedAt = 0; 47338 this._progress = 0; 47339 this._connected = false; 47340 47341 this.filters = []; 47342 47343 } 47344 47345 getOutput() { 47346 47347 return this.gain; 47348 47349 } 47350 47351 setNodeSource( audioNode ) { 47352 47353 this.hasPlaybackControl = false; 47354 this.sourceType = 'audioNode'; 47355 this.source = audioNode; 47356 this.connect(); 47357 47358 return this; 47359 47360 } 47361 47362 setMediaElementSource( mediaElement ) { 47363 47364 this.hasPlaybackControl = false; 47365 this.sourceType = 'mediaNode'; 47366 this.source = this.context.createMediaElementSource( mediaElement ); 47367 this.connect(); 47368 47369 return this; 47370 47371 } 47372 47373 setMediaStreamSource( mediaStream ) { 47374 47375 this.hasPlaybackControl = false; 47376 this.sourceType = 'mediaStreamNode'; 47377 this.source = this.context.createMediaStreamSource( mediaStream ); 47378 this.connect(); 47379 47380 return this; 47381 47382 } 47383 47384 setBuffer( audioBuffer ) { 47385 47386 this.buffer = audioBuffer; 47387 this.sourceType = 'buffer'; 47388 47389 if ( this.autoplay ) this.play(); 47390 47391 return this; 47392 47393 } 47394 47395 play( delay = 0 ) { 47396 47397 if ( this.isPlaying === true ) { 47398 47399 console.warn( 'THREE.Audio: Audio is already playing.' ); 47400 return; 47401 47402 } 47403 47404 if ( this.hasPlaybackControl === false ) { 47405 47406 console.warn( 'THREE.Audio: this Audio has no playback control.' ); 47407 return; 47408 47409 } 47410 47411 this._startedAt = this.context.currentTime + delay; 47412 47413 const source = this.context.createBufferSource(); 47414 source.buffer = this.buffer; 47415 source.loop = this.loop; 47416 source.loopStart = this.loopStart; 47417 source.loopEnd = this.loopEnd; 47418 source.onended = this.onEnded.bind( this ); 47419 source.start( this._startedAt, this._progress + this.offset, this.duration ); 47420 47421 this.isPlaying = true; 47422 47423 this.source = source; 47424 47425 this.setDetune( this.detune ); 47426 this.setPlaybackRate( this.playbackRate ); 47427 47428 return this.connect(); 47429 47430 } 47431 47432 pause() { 47433 47434 if ( this.hasPlaybackControl === false ) { 47435 47436 console.warn( 'THREE.Audio: this Audio has no playback control.' ); 47437 return; 47438 47439 } 47440 47441 if ( this.isPlaying === true ) { 47442 47443 // update current progress 47444 47445 this._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate; 47446 47447 if ( this.loop === true ) { 47448 47449 // ensure _progress does not exceed duration with looped audios 47450 47451 this._progress = this._progress % ( this.duration || this.buffer.duration ); 47452 47453 } 47454 47455 this.source.stop(); 47456 this.source.onended = null; 47457 47458 this.isPlaying = false; 47459 47460 } 47461 47462 return this; 47463 47464 } 47465 47466 stop() { 47467 47468 if ( this.hasPlaybackControl === false ) { 47469 47470 console.warn( 'THREE.Audio: this Audio has no playback control.' ); 47471 return; 47472 47473 } 47474 47475 this._progress = 0; 47476 47477 if ( this.source !== null ) { 47478 47479 this.source.stop(); 47480 this.source.onended = null; 47481 47482 } 47483 47484 this.isPlaying = false; 47485 47486 return this; 47487 47488 } 47489 47490 connect() { 47491 47492 if ( this.filters.length > 0 ) { 47493 47494 this.source.connect( this.filters[ 0 ] ); 47495 47496 for ( let i = 1, l = this.filters.length; i < l; i ++ ) { 47497 47498 this.filters[ i - 1 ].connect( this.filters[ i ] ); 47499 47500 } 47501 47502 this.filters[ this.filters.length - 1 ].connect( this.getOutput() ); 47503 47504 } else { 47505 47506 this.source.connect( this.getOutput() ); 47507 47508 } 47509 47510 this._connected = true; 47511 47512 return this; 47513 47514 } 47515 47516 disconnect() { 47517 47518 if ( this._connected === false ) { 47519 47520 return; 47521 47522 } 47523 47524 if ( this.filters.length > 0 ) { 47525 47526 this.source.disconnect( this.filters[ 0 ] ); 47527 47528 for ( let i = 1, l = this.filters.length; i < l; i ++ ) { 47529 47530 this.filters[ i - 1 ].disconnect( this.filters[ i ] ); 47531 47532 } 47533 47534 this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() ); 47535 47536 } else { 47537 47538 this.source.disconnect( this.getOutput() ); 47539 47540 } 47541 47542 this._connected = false; 47543 47544 return this; 47545 47546 } 47547 47548 getFilters() { 47549 47550 return this.filters; 47551 47552 } 47553 47554 setFilters( value ) { 47555 47556 if ( ! value ) value = []; 47557 47558 if ( this._connected === true ) { 47559 47560 this.disconnect(); 47561 this.filters = value.slice(); 47562 this.connect(); 47563 47564 } else { 47565 47566 this.filters = value.slice(); 47567 47568 } 47569 47570 return this; 47571 47572 } 47573 47574 setDetune( value ) { 47575 47576 this.detune = value; 47577 47578 if ( this.source.detune === undefined ) return; // only set detune when available 47579 47580 if ( this.isPlaying === true ) { 47581 47582 this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 ); 47583 47584 } 47585 47586 return this; 47587 47588 } 47589 47590 getDetune() { 47591 47592 return this.detune; 47593 47594 } 47595 47596 getFilter() { 47597 47598 return this.getFilters()[ 0 ]; 47599 47600 } 47601 47602 setFilter( filter ) { 47603 47604 return this.setFilters( filter ? [ filter ] : [] ); 47605 47606 } 47607 47608 setPlaybackRate( value ) { 47609 47610 if ( this.hasPlaybackControl === false ) { 47611 47612 console.warn( 'THREE.Audio: this Audio has no playback control.' ); 47613 return; 47614 47615 } 47616 47617 this.playbackRate = value; 47618 47619 if ( this.isPlaying === true ) { 47620 47621 this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 ); 47622 47623 } 47624 47625 return this; 47626 47627 } 47628 47629 getPlaybackRate() { 47630 47631 return this.playbackRate; 47632 47633 } 47634 47635 onEnded() { 47636 47637 this.isPlaying = false; 47638 47639 } 47640 47641 getLoop() { 47642 47643 if ( this.hasPlaybackControl === false ) { 47644 47645 console.warn( 'THREE.Audio: this Audio has no playback control.' ); 47646 return false; 47647 47648 } 47649 47650 return this.loop; 47651 47652 } 47653 47654 setLoop( value ) { 47655 47656 if ( this.hasPlaybackControl === false ) { 47657 47658 console.warn( 'THREE.Audio: this Audio has no playback control.' ); 47659 return; 47660 47661 } 47662 47663 this.loop = value; 47664 47665 if ( this.isPlaying === true ) { 47666 47667 this.source.loop = this.loop; 47668 47669 } 47670 47671 return this; 47672 47673 } 47674 47675 setLoopStart( value ) { 47676 47677 this.loopStart = value; 47678 47679 return this; 47680 47681 } 47682 47683 setLoopEnd( value ) { 47684 47685 this.loopEnd = value; 47686 47687 return this; 47688 47689 } 47690 47691 getVolume() { 47692 47693 return this.gain.gain.value; 47694 47695 } 47696 47697 setVolume( value ) { 47698 47699 this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); 47700 47701 return this; 47702 47703 } 47704 47705} 47706 47707const _position = /*@__PURE__*/ new Vector3(); 47708const _quaternion = /*@__PURE__*/ new Quaternion(); 47709const _scale = /*@__PURE__*/ new Vector3(); 47710const _orientation = /*@__PURE__*/ new Vector3(); 47711 47712class PositionalAudio extends Audio { 47713 47714 constructor( listener ) { 47715 47716 super( listener ); 47717 47718 this.panner = this.context.createPanner(); 47719 this.panner.panningModel = 'HRTF'; 47720 this.panner.connect( this.gain ); 47721 47722 } 47723 47724 connect() { 47725 47726 super.connect(); 47727 47728 this.panner.connect( this.gain ); 47729 47730 } 47731 47732 disconnect() { 47733 47734 super.disconnect(); 47735 47736 this.panner.disconnect( this.gain ); 47737 47738 } 47739 47740 getOutput() { 47741 47742 return this.panner; 47743 47744 } 47745 47746 getRefDistance() { 47747 47748 return this.panner.refDistance; 47749 47750 } 47751 47752 setRefDistance( value ) { 47753 47754 this.panner.refDistance = value; 47755 47756 return this; 47757 47758 } 47759 47760 getRolloffFactor() { 47761 47762 return this.panner.rolloffFactor; 47763 47764 } 47765 47766 setRolloffFactor( value ) { 47767 47768 this.panner.rolloffFactor = value; 47769 47770 return this; 47771 47772 } 47773 47774 getDistanceModel() { 47775 47776 return this.panner.distanceModel; 47777 47778 } 47779 47780 setDistanceModel( value ) { 47781 47782 this.panner.distanceModel = value; 47783 47784 return this; 47785 47786 } 47787 47788 getMaxDistance() { 47789 47790 return this.panner.maxDistance; 47791 47792 } 47793 47794 setMaxDistance( value ) { 47795 47796 this.panner.maxDistance = value; 47797 47798 return this; 47799 47800 } 47801 47802 setDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) { 47803 47804 this.panner.coneInnerAngle = coneInnerAngle; 47805 this.panner.coneOuterAngle = coneOuterAngle; 47806 this.panner.coneOuterGain = coneOuterGain; 47807 47808 return this; 47809 47810 } 47811 47812 updateMatrixWorld( force ) { 47813 47814 super.updateMatrixWorld( force ); 47815 47816 if ( this.hasPlaybackControl === true && this.isPlaying === false ) return; 47817 47818 this.matrixWorld.decompose( _position, _quaternion, _scale ); 47819 47820 _orientation.set( 0, 0, 1 ).applyQuaternion( _quaternion ); 47821 47822 const panner = this.panner; 47823 47824 if ( panner.positionX ) { 47825 47826 // code path for Chrome and Firefox (see #14393) 47827 47828 const endTime = this.context.currentTime + this.listener.timeDelta; 47829 47830 panner.positionX.linearRampToValueAtTime( _position.x, endTime ); 47831 panner.positionY.linearRampToValueAtTime( _position.y, endTime ); 47832 panner.positionZ.linearRampToValueAtTime( _position.z, endTime ); 47833 panner.orientationX.linearRampToValueAtTime( _orientation.x, endTime ); 47834 panner.orientationY.linearRampToValueAtTime( _orientation.y, endTime ); 47835 panner.orientationZ.linearRampToValueAtTime( _orientation.z, endTime ); 47836 47837 } else { 47838 47839 panner.setPosition( _position.x, _position.y, _position.z ); 47840 panner.setOrientation( _orientation.x, _orientation.y, _orientation.z ); 47841 47842 } 47843 47844 } 47845 47846} 47847 47848class AudioAnalyser { 47849 47850 constructor( audio, fftSize = 2048 ) { 47851 47852 this.analyser = audio.context.createAnalyser(); 47853 this.analyser.fftSize = fftSize; 47854 47855 this.data = new Uint8Array( this.analyser.frequencyBinCount ); 47856 47857 audio.getOutput().connect( this.analyser ); 47858 47859 } 47860 47861 47862 getFrequencyData() { 47863 47864 this.analyser.getByteFrequencyData( this.data ); 47865 47866 return this.data; 47867 47868 } 47869 47870 getAverageFrequency() { 47871 47872 let value = 0; 47873 const data = this.getFrequencyData(); 47874 47875 for ( let i = 0; i < data.length; i ++ ) { 47876 47877 value += data[ i ]; 47878 47879 } 47880 47881 return value / data.length; 47882 47883 } 47884 47885} 47886 47887class PropertyMixer { 47888 47889 constructor( binding, typeName, valueSize ) { 47890 47891 this.binding = binding; 47892 this.valueSize = valueSize; 47893 47894 let mixFunction, 47895 mixFunctionAdditive, 47896 setIdentity; 47897 47898 // buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ] 47899 // 47900 // interpolators can use .buffer as their .result 47901 // the data then goes to 'incoming' 47902 // 47903 // 'accu0' and 'accu1' are used frame-interleaved for 47904 // the cumulative result and are compared to detect 47905 // changes 47906 // 47907 // 'orig' stores the original state of the property 47908 // 47909 // 'add' is used for additive cumulative results 47910 // 47911 // 'work' is optional and is only present for quaternion types. It is used 47912 // to store intermediate quaternion multiplication results 47913 47914 switch ( typeName ) { 47915 47916 case 'quaternion': 47917 mixFunction = this._slerp; 47918 mixFunctionAdditive = this._slerpAdditive; 47919 setIdentity = this._setAdditiveIdentityQuaternion; 47920 47921 this.buffer = new Float64Array( valueSize * 6 ); 47922 this._workIndex = 5; 47923 break; 47924 47925 case 'string': 47926 case 'bool': 47927 mixFunction = this._select; 47928 47929 // Use the regular mix function and for additive on these types, 47930 // additive is not relevant for non-numeric types 47931 mixFunctionAdditive = this._select; 47932 47933 setIdentity = this._setAdditiveIdentityOther; 47934 47935 this.buffer = new Array( valueSize * 5 ); 47936 break; 47937 47938 default: 47939 mixFunction = this._lerp; 47940 mixFunctionAdditive = this._lerpAdditive; 47941 setIdentity = this._setAdditiveIdentityNumeric; 47942 47943 this.buffer = new Float64Array( valueSize * 5 ); 47944 47945 } 47946 47947 this._mixBufferRegion = mixFunction; 47948 this._mixBufferRegionAdditive = mixFunctionAdditive; 47949 this._setIdentity = setIdentity; 47950 this._origIndex = 3; 47951 this._addIndex = 4; 47952 47953 this.cumulativeWeight = 0; 47954 this.cumulativeWeightAdditive = 0; 47955 47956 this.useCount = 0; 47957 this.referenceCount = 0; 47958 47959 } 47960 47961 // accumulate data in the 'incoming' region into 'accu<i>' 47962 accumulate( accuIndex, weight ) { 47963 47964 // note: happily accumulating nothing when weight = 0, the caller knows 47965 // the weight and shouldn't have made the call in the first place 47966 47967 const buffer = this.buffer, 47968 stride = this.valueSize, 47969 offset = accuIndex * stride + stride; 47970 47971 let currentWeight = this.cumulativeWeight; 47972 47973 if ( currentWeight === 0 ) { 47974 47975 // accuN := incoming * weight 47976 47977 for ( let i = 0; i !== stride; ++ i ) { 47978 47979 buffer[ offset + i ] = buffer[ i ]; 47980 47981 } 47982 47983 currentWeight = weight; 47984 47985 } else { 47986 47987 // accuN := accuN + incoming * weight 47988 47989 currentWeight += weight; 47990 const mix = weight / currentWeight; 47991 this._mixBufferRegion( buffer, offset, 0, mix, stride ); 47992 47993 } 47994 47995 this.cumulativeWeight = currentWeight; 47996 47997 } 47998 47999 // accumulate data in the 'incoming' region into 'add' 48000 accumulateAdditive( weight ) { 48001 48002 const buffer = this.buffer, 48003 stride = this.valueSize, 48004 offset = stride * this._addIndex; 48005 48006 if ( this.cumulativeWeightAdditive === 0 ) { 48007 48008 // add = identity 48009 48010 this._setIdentity(); 48011 48012 } 48013 48014 // add := add + incoming * weight 48015 48016 this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride ); 48017 this.cumulativeWeightAdditive += weight; 48018 48019 } 48020 48021 // apply the state of 'accu<i>' to the binding when accus differ 48022 apply( accuIndex ) { 48023 48024 const stride = this.valueSize, 48025 buffer = this.buffer, 48026 offset = accuIndex * stride + stride, 48027 48028 weight = this.cumulativeWeight, 48029 weightAdditive = this.cumulativeWeightAdditive, 48030 48031 binding = this.binding; 48032 48033 this.cumulativeWeight = 0; 48034 this.cumulativeWeightAdditive = 0; 48035 48036 if ( weight < 1 ) { 48037 48038 // accuN := accuN + original * ( 1 - cumulativeWeight ) 48039 48040 const originalValueOffset = stride * this._origIndex; 48041 48042 this._mixBufferRegion( 48043 buffer, offset, originalValueOffset, 1 - weight, stride ); 48044 48045 } 48046 48047 if ( weightAdditive > 0 ) { 48048 48049 // accuN := accuN + additive accuN 48050 48051 this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride ); 48052 48053 } 48054 48055 for ( let i = stride, e = stride + stride; i !== e; ++ i ) { 48056 48057 if ( buffer[ i ] !== buffer[ i + stride ] ) { 48058 48059 // value has changed -> update scene graph 48060 48061 binding.setValue( buffer, offset ); 48062 break; 48063 48064 } 48065 48066 } 48067 48068 } 48069 48070 // remember the state of the bound property and copy it to both accus 48071 saveOriginalState() { 48072 48073 const binding = this.binding; 48074 48075 const buffer = this.buffer, 48076 stride = this.valueSize, 48077 48078 originalValueOffset = stride * this._origIndex; 48079 48080 binding.getValue( buffer, originalValueOffset ); 48081 48082 // accu[0..1] := orig -- initially detect changes against the original 48083 for ( let i = stride, e = originalValueOffset; i !== e; ++ i ) { 48084 48085 buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ]; 48086 48087 } 48088 48089 // Add to identity for additive 48090 this._setIdentity(); 48091 48092 this.cumulativeWeight = 0; 48093 this.cumulativeWeightAdditive = 0; 48094 48095 } 48096 48097 // apply the state previously taken via 'saveOriginalState' to the binding 48098 restoreOriginalState() { 48099 48100 const originalValueOffset = this.valueSize * 3; 48101 this.binding.setValue( this.buffer, originalValueOffset ); 48102 48103 } 48104 48105 _setAdditiveIdentityNumeric() { 48106 48107 const startIndex = this._addIndex * this.valueSize; 48108 const endIndex = startIndex + this.valueSize; 48109 48110 for ( let i = startIndex; i < endIndex; i ++ ) { 48111 48112 this.buffer[ i ] = 0; 48113 48114 } 48115 48116 } 48117 48118 _setAdditiveIdentityQuaternion() { 48119 48120 this._setAdditiveIdentityNumeric(); 48121 this.buffer[ this._addIndex * this.valueSize + 3 ] = 1; 48122 48123 } 48124 48125 _setAdditiveIdentityOther() { 48126 48127 const startIndex = this._origIndex * this.valueSize; 48128 const targetIndex = this._addIndex * this.valueSize; 48129 48130 for ( let i = 0; i < this.valueSize; i ++ ) { 48131 48132 this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ]; 48133 48134 } 48135 48136 } 48137 48138 48139 // mix functions 48140 48141 _select( buffer, dstOffset, srcOffset, t, stride ) { 48142 48143 if ( t >= 0.5 ) { 48144 48145 for ( let i = 0; i !== stride; ++ i ) { 48146 48147 buffer[ dstOffset + i ] = buffer[ srcOffset + i ]; 48148 48149 } 48150 48151 } 48152 48153 } 48154 48155 _slerp( buffer, dstOffset, srcOffset, t ) { 48156 48157 Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t ); 48158 48159 } 48160 48161 _slerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { 48162 48163 const workOffset = this._workIndex * stride; 48164 48165 // Store result in intermediate buffer offset 48166 Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset ); 48167 48168 // Slerp to the intermediate result 48169 Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t ); 48170 48171 } 48172 48173 _lerp( buffer, dstOffset, srcOffset, t, stride ) { 48174 48175 const s = 1 - t; 48176 48177 for ( let i = 0; i !== stride; ++ i ) { 48178 48179 const j = dstOffset + i; 48180 48181 buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t; 48182 48183 } 48184 48185 } 48186 48187 _lerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { 48188 48189 for ( let i = 0; i !== stride; ++ i ) { 48190 48191 const j = dstOffset + i; 48192 48193 buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t; 48194 48195 } 48196 48197 } 48198 48199} 48200 48201// Characters [].:/ are reserved for track binding syntax. 48202const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/'; 48203const _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' ); 48204 48205// Attempts to allow node names from any language. ES5's `\w` regexp matches 48206// only latin characters, and the unicode \p{L} is not yet supported. So 48207// instead, we exclude reserved characters and match everything else. 48208const _wordChar = '[^' + _RESERVED_CHARS_RE + ']'; 48209const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']'; 48210 48211// Parent directories, delimited by '/' or ':'. Currently unused, but must 48212// be matched to parse the rest of the track name. 48213const _directoryRe = /*@__PURE__*/ /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar ); 48214 48215// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'. 48216const _nodeRe = /*@__PURE__*/ /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot ); 48217 48218// Object on target node, and accessor. May not contain reserved 48219// characters. Accessor may contain any character except closing bracket. 48220const _objectRe = /*@__PURE__*/ /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar ); 48221 48222// Property and accessor. May not contain reserved characters. Accessor may 48223// contain any non-bracket characters. 48224const _propertyRe = /*@__PURE__*/ /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar ); 48225 48226const _trackRe = new RegExp( '' 48227 + '^' 48228 + _directoryRe 48229 + _nodeRe 48230 + _objectRe 48231 + _propertyRe 48232 + '$' 48233); 48234 48235const _supportedObjectNames = [ 'material', 'materials', 'bones', 'map' ]; 48236 48237class Composite { 48238 48239 constructor( targetGroup, path, optionalParsedPath ) { 48240 48241 const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path ); 48242 48243 this._targetGroup = targetGroup; 48244 this._bindings = targetGroup.subscribe_( path, parsedPath ); 48245 48246 } 48247 48248 getValue( array, offset ) { 48249 48250 this.bind(); // bind all binding 48251 48252 const firstValidIndex = this._targetGroup.nCachedObjects_, 48253 binding = this._bindings[ firstValidIndex ]; 48254 48255 // and only call .getValue on the first 48256 if ( binding !== undefined ) binding.getValue( array, offset ); 48257 48258 } 48259 48260 setValue( array, offset ) { 48261 48262 const bindings = this._bindings; 48263 48264 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { 48265 48266 bindings[ i ].setValue( array, offset ); 48267 48268 } 48269 48270 } 48271 48272 bind() { 48273 48274 const bindings = this._bindings; 48275 48276 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { 48277 48278 bindings[ i ].bind(); 48279 48280 } 48281 48282 } 48283 48284 unbind() { 48285 48286 const bindings = this._bindings; 48287 48288 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { 48289 48290 bindings[ i ].unbind(); 48291 48292 } 48293 48294 } 48295 48296} 48297 48298// Note: This class uses a State pattern on a per-method basis: 48299// 'bind' sets 'this.getValue' / 'setValue' and shadows the 48300// prototype version of these methods with one that represents 48301// the bound state. When the property is not found, the methods 48302// become no-ops. 48303class PropertyBinding { 48304 48305 constructor( rootNode, path, parsedPath ) { 48306 48307 this.path = path; 48308 this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path ); 48309 48310 this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ); 48311 48312 this.rootNode = rootNode; 48313 48314 // initial state of these methods that calls 'bind' 48315 this.getValue = this._getValue_unbound; 48316 this.setValue = this._setValue_unbound; 48317 48318 } 48319 48320 48321 static create( root, path, parsedPath ) { 48322 48323 if ( ! ( root && root.isAnimationObjectGroup ) ) { 48324 48325 return new PropertyBinding( root, path, parsedPath ); 48326 48327 } else { 48328 48329 return new PropertyBinding.Composite( root, path, parsedPath ); 48330 48331 } 48332 48333 } 48334 48335 /** 48336 * Replaces spaces with underscores and removes unsupported characters from 48337 * node names, to ensure compatibility with parseTrackName(). 48338 * 48339 * @param {string} name Node name to be sanitized. 48340 * @return {string} 48341 */ 48342 static sanitizeNodeName( name ) { 48343 48344 return name.replace( /\s/g, '_' ).replace( _reservedRe, '' ); 48345 48346 } 48347 48348 static parseTrackName( trackName ) { 48349 48350 const matches = _trackRe.exec( trackName ); 48351 48352 if ( matches === null ) { 48353 48354 throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName ); 48355 48356 } 48357 48358 const results = { 48359 // directoryName: matches[ 1 ], // (tschw) currently unused 48360 nodeName: matches[ 2 ], 48361 objectName: matches[ 3 ], 48362 objectIndex: matches[ 4 ], 48363 propertyName: matches[ 5 ], // required 48364 propertyIndex: matches[ 6 ] 48365 }; 48366 48367 const lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' ); 48368 48369 if ( lastDot !== undefined && lastDot !== - 1 ) { 48370 48371 const objectName = results.nodeName.substring( lastDot + 1 ); 48372 48373 // Object names must be checked against an allowlist. Otherwise, there 48374 // is no way to parse 'foo.bar.baz': 'baz' must be a property, but 48375 // 'bar' could be the objectName, or part of a nodeName (which can 48376 // include '.' characters). 48377 if ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) { 48378 48379 results.nodeName = results.nodeName.substring( 0, lastDot ); 48380 results.objectName = objectName; 48381 48382 } 48383 48384 } 48385 48386 if ( results.propertyName === null || results.propertyName.length === 0 ) { 48387 48388 throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName ); 48389 48390 } 48391 48392 return results; 48393 48394 } 48395 48396 static findNode( root, nodeName ) { 48397 48398 if ( nodeName === undefined || nodeName === '' || nodeName === '.' || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) { 48399 48400 return root; 48401 48402 } 48403 48404 // search into skeleton bones. 48405 if ( root.skeleton ) { 48406 48407 const bone = root.skeleton.getBoneByName( nodeName ); 48408 48409 if ( bone !== undefined ) { 48410 48411 return bone; 48412 48413 } 48414 48415 } 48416 48417 // search into node subtree. 48418 if ( root.children ) { 48419 48420 const searchNodeSubtree = function ( children ) { 48421 48422 for ( let i = 0; i < children.length; i ++ ) { 48423 48424 const childNode = children[ i ]; 48425 48426 if ( childNode.name === nodeName || childNode.uuid === nodeName ) { 48427 48428 return childNode; 48429 48430 } 48431 48432 const result = searchNodeSubtree( childNode.children ); 48433 48434 if ( result ) return result; 48435 48436 } 48437 48438 return null; 48439 48440 }; 48441 48442 const subTreeNode = searchNodeSubtree( root.children ); 48443 48444 if ( subTreeNode ) { 48445 48446 return subTreeNode; 48447 48448 } 48449 48450 } 48451 48452 return null; 48453 48454 } 48455 48456 // these are used to "bind" a nonexistent property 48457 _getValue_unavailable() {} 48458 _setValue_unavailable() {} 48459 48460 // Getters 48461 48462 _getValue_direct( buffer, offset ) { 48463 48464 buffer[ offset ] = this.targetObject[ this.propertyName ]; 48465 48466 } 48467 48468 _getValue_array( buffer, offset ) { 48469 48470 const source = this.resolvedProperty; 48471 48472 for ( let i = 0, n = source.length; i !== n; ++ i ) { 48473 48474 buffer[ offset ++ ] = source[ i ]; 48475 48476 } 48477 48478 } 48479 48480 _getValue_arrayElement( buffer, offset ) { 48481 48482 buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ]; 48483 48484 } 48485 48486 _getValue_toArray( buffer, offset ) { 48487 48488 this.resolvedProperty.toArray( buffer, offset ); 48489 48490 } 48491 48492 // Direct 48493 48494 _setValue_direct( buffer, offset ) { 48495 48496 this.targetObject[ this.propertyName ] = buffer[ offset ]; 48497 48498 } 48499 48500 _setValue_direct_setNeedsUpdate( buffer, offset ) { 48501 48502 this.targetObject[ this.propertyName ] = buffer[ offset ]; 48503 this.targetObject.needsUpdate = true; 48504 48505 } 48506 48507 _setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) { 48508 48509 this.targetObject[ this.propertyName ] = buffer[ offset ]; 48510 this.targetObject.matrixWorldNeedsUpdate = true; 48511 48512 } 48513 48514 // EntireArray 48515 48516 _setValue_array( buffer, offset ) { 48517 48518 const dest = this.resolvedProperty; 48519 48520 for ( let i = 0, n = dest.length; i !== n; ++ i ) { 48521 48522 dest[ i ] = buffer[ offset ++ ]; 48523 48524 } 48525 48526 } 48527 48528 _setValue_array_setNeedsUpdate( buffer, offset ) { 48529 48530 const dest = this.resolvedProperty; 48531 48532 for ( let i = 0, n = dest.length; i !== n; ++ i ) { 48533 48534 dest[ i ] = buffer[ offset ++ ]; 48535 48536 } 48537 48538 this.targetObject.needsUpdate = true; 48539 48540 } 48541
vendor: 7,885 bytes, lines 48542-48873
48542 _setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) { 48543 48544 const dest = this.resolvedProperty; 48545 48546 for ( let i = 0, n = dest.length; i !== n; ++ i ) { 48547 48548 dest[ i ] = buffer[ offset ++ ]; 48549 48550 } 48551 48552 this.targetObject.matrixWorldNeedsUpdate = true; 48553 48554 } 48555 48556 // ArrayElement 48557 48558 _setValue_arrayElement( buffer, offset ) { 48559 48560 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; 48561 48562 } 48563 48564 _setValue_arrayElement_setNeedsUpdate( buffer, offset ) { 48565 48566 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; 48567 this.targetObject.needsUpdate = true; 48568 48569 } 48570 48571 _setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) { 48572 48573 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; 48574 this.targetObject.matrixWorldNeedsUpdate = true; 48575 48576 } 48577 48578 // HasToFromArray 48579 48580 _setValue_fromArray( buffer, offset ) { 48581 48582 this.resolvedProperty.fromArray( buffer, offset ); 48583 48584 } 48585 48586 _setValue_fromArray_setNeedsUpdate( buffer, offset ) { 48587 48588 this.resolvedProperty.fromArray( buffer, offset ); 48589 this.targetObject.needsUpdate = true; 48590 48591 } 48592 48593 _setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) { 48594 48595 this.resolvedProperty.fromArray( buffer, offset ); 48596 this.targetObject.matrixWorldNeedsUpdate = true; 48597 48598 } 48599 48600 _getValue_unbound( targetArray, offset ) { 48601 48602 this.bind(); 48603 this.getValue( targetArray, offset ); 48604 48605 } 48606 48607 _setValue_unbound( sourceArray, offset ) { 48608 48609 this.bind(); 48610 this.setValue( sourceArray, offset ); 48611 48612 } 48613 48614 // create getter / setter pair for a property in the scene graph 48615 bind() { 48616 48617 let targetObject = this.node; 48618 const parsedPath = this.parsedPath; 48619 48620 const objectName = parsedPath.objectName; 48621 const propertyName = parsedPath.propertyName; 48622 let propertyIndex = parsedPath.propertyIndex; 48623 48624 if ( ! targetObject ) { 48625 48626 targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ); 48627 48628 this.node = targetObject; 48629 48630 } 48631 48632 // set fail state so we can just 'return' on error 48633 this.getValue = this._getValue_unavailable; 48634 this.setValue = this._setValue_unavailable; 48635 48636 // ensure there is a value node 48637 if ( ! targetObject ) { 48638 48639 console.warn( 'THREE.PropertyBinding: No target node found for track: ' + this.path + '.' ); 48640 return; 48641 48642 } 48643 48644 if ( objectName ) { 48645 48646 let objectIndex = parsedPath.objectIndex; 48647 48648 // special cases were we need to reach deeper into the hierarchy to get the face materials.... 48649 switch ( objectName ) { 48650 48651 case 'materials': 48652 48653 if ( ! targetObject.material ) { 48654 48655 console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); 48656 return; 48657 48658 } 48659 48660 if ( ! targetObject.material.materials ) { 48661 48662 console.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this ); 48663 return; 48664 48665 } 48666 48667 targetObject = targetObject.material.materials; 48668 48669 break; 48670 48671 case 'bones': 48672 48673 if ( ! targetObject.skeleton ) { 48674 48675 console.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this ); 48676 return; 48677 48678 } 48679 48680 // potential future optimization: skip this if propertyIndex is already an integer 48681 // and convert the integer string to a true integer. 48682 48683 targetObject = targetObject.skeleton.bones; 48684 48685 // support resolving morphTarget names into indices. 48686 for ( let i = 0; i < targetObject.length; i ++ ) { 48687 48688 if ( targetObject[ i ].name === objectIndex ) { 48689 48690 objectIndex = i; 48691 break; 48692 48693 } 48694 48695 } 48696 48697 break; 48698 48699 case 'map': 48700 48701 if ( 'map' in targetObject ) { 48702 48703 targetObject = targetObject.map; 48704 break; 48705 48706 } 48707 48708 if ( ! targetObject.material ) { 48709 48710 console.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this ); 48711 return; 48712 48713 } 48714 48715 if ( ! targetObject.material.map ) { 48716 48717 console.error( 'THREE.PropertyBinding: Can not bind to material.map as node.material does not have a map.', this ); 48718 return; 48719 48720 } 48721 48722 targetObject = targetObject.material.map; 48723 break; 48724 48725 default: 48726 48727 if ( targetObject[ objectName ] === undefined ) { 48728 48729 console.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this ); 48730 return; 48731 48732 } 48733 48734 targetObject = targetObject[ objectName ]; 48735 48736 } 48737 48738 48739 if ( objectIndex !== undefined ) { 48740 48741 if ( targetObject[ objectIndex ] === undefined ) { 48742 48743 console.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject ); 48744 return; 48745 48746 } 48747 48748 targetObject = targetObject[ objectIndex ]; 48749 48750 } 48751 48752 } 48753 48754 // resolve property 48755 const nodeProperty = targetObject[ propertyName ]; 48756 48757 if ( nodeProperty === undefined ) { 48758 48759 const nodeName = parsedPath.nodeName; 48760 48761 console.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName + 48762 '.' + propertyName + ' but it wasn\'t found.', targetObject ); 48763 return; 48764 48765 } 48766 48767 // determine versioning scheme 48768 let versioning = this.Versioning.None; 48769 48770 this.targetObject = targetObject; 48771 48772 if ( targetObject.needsUpdate !== undefined ) { // material 48773 48774 versioning = this.Versioning.NeedsUpdate; 48775 48776 } else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform 48777 48778 versioning = this.Versioning.MatrixWorldNeedsUpdate; 48779 48780 } 48781 48782 // determine how the property gets bound 48783 let bindingType = this.BindingType.Direct; 48784 48785 if ( propertyIndex !== undefined ) { 48786 48787 // access a sub element of the property array (only primitives are supported right now) 48788 48789 if ( propertyName === 'morphTargetInfluences' ) { 48790 48791 // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. 48792 48793 // support resolving morphTarget names into indices. 48794 if ( ! targetObject.geometry ) { 48795 48796 console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this ); 48797 return; 48798 48799 } 48800 48801 if ( ! targetObject.geometry.morphAttributes ) { 48802 48803 console.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this ); 48804 return; 48805 48806 } 48807 48808 if ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) { 48809 48810 propertyIndex = targetObject.morphTargetDictionary[ propertyIndex ]; 48811 48812 } 48813 48814 } 48815 48816 bindingType = this.BindingType.ArrayElement; 48817 48818 this.resolvedProperty = nodeProperty; 48819 this.propertyIndex = propertyIndex; 48820 48821 } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) { 48822 48823 // must use copy for Object3D.Euler/Quaternion 48824 48825 bindingType = this.BindingType.HasFromToArray; 48826 48827 this.resolvedProperty = nodeProperty; 48828 48829 } else if ( Array.isArray( nodeProperty ) ) { 48830 48831 bindingType = this.BindingType.EntireArray; 48832 48833 this.resolvedProperty = nodeProperty; 48834 48835 } else { 48836 48837 this.propertyName = propertyName; 48838 48839 } 48840 48841 // select getter / setter 48842 this.getValue = this.GetterByBindingType[ bindingType ]; 48843 this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ]; 48844 48845 } 48846 48847 unbind() { 48848 48849 this.node = null; 48850 48851 // back to the prototype version of getValue / setValue 48852 // note: avoiding to mutate the shape of 'this' via 'delete' 48853 this.getValue = this._getValue_unbound; 48854 this.setValue = this._setValue_unbound; 48855 48856 } 48857 48858} 48859 48860PropertyBinding.Composite = Composite; 48861 48862PropertyBinding.prototype.BindingType = { 48863 Direct: 0, 48864 EntireArray: 1, 48865 ArrayElement: 2, 48866 HasFromToArray: 3 48867}; 48868 48869PropertyBinding.prototype.Versioning = { 48870 None: 0, 48871 NeedsUpdate: 1, 48872 MatrixWorldNeedsUpdate: 2 48873};
vendor: 4,442 bytes, lines 48874-49054
48874 48875PropertyBinding.prototype.GetterByBindingType = [ 48876 48877 PropertyBinding.prototype._getValue_direct, 48878 PropertyBinding.prototype._getValue_array, 48879 PropertyBinding.prototype._getValue_arrayElement, 48880 PropertyBinding.prototype._getValue_toArray, 48881 48882]; 48883 48884PropertyBinding.prototype.SetterByBindingTypeAndVersioning = [ 48885 48886 [ 48887 // Direct 48888 PropertyBinding.prototype._setValue_direct, 48889 PropertyBinding.prototype._setValue_direct_setNeedsUpdate, 48890 PropertyBinding.prototype._setValue_direct_setMatrixWorldNeedsUpdate, 48891 48892 ], [ 48893 48894 // EntireArray 48895 48896 PropertyBinding.prototype._setValue_array, 48897 PropertyBinding.prototype._setValue_array_setNeedsUpdate, 48898 PropertyBinding.prototype._setValue_array_setMatrixWorldNeedsUpdate, 48899 48900 ], [ 48901 48902 // ArrayElement 48903 PropertyBinding.prototype._setValue_arrayElement, 48904 PropertyBinding.prototype._setValue_arrayElement_setNeedsUpdate, 48905 PropertyBinding.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate, 48906 48907 ], [ 48908 48909 // HasToFromArray 48910 PropertyBinding.prototype._setValue_fromArray, 48911 PropertyBinding.prototype._setValue_fromArray_setNeedsUpdate, 48912 PropertyBinding.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate, 48913 48914 ] 48915 48916]; 48917 48918/** 48919 * 48920 * A group of objects that receives a shared animation state. 48921 * 48922 * Usage: 48923 * 48924 * - Add objects you would otherwise pass as 'root' to the 48925 * constructor or the .clipAction method of AnimationMixer. 48926 * 48927 * - Instead pass this object as 'root'. 48928 * 48929 * - You can also add and remove objects later when the mixer 48930 * is running. 48931 * 48932 * Note: 48933 * 48934 * Objects of this class appear as one object to the mixer, 48935 * so cache control of the individual objects must be done 48936 * on the group. 48937 * 48938 * Limitation: 48939 * 48940 * - The animated properties must be compatible among the 48941 * all objects in the group. 48942 * 48943 * - A single property can either be controlled through a 48944 * target group or directly, but not both. 48945 */ 48946 48947class AnimationObjectGroup { 48948 48949 constructor() { 48950 48951 this.isAnimationObjectGroup = true; 48952 48953 this.uuid = generateUUID(); 48954 48955 // cached objects followed by the active ones 48956 this._objects = Array.prototype.slice.call( arguments ); 48957 48958 this.nCachedObjects_ = 0; // threshold 48959 // note: read by PropertyBinding.Composite 48960 48961 const indices = {}; 48962 this._indicesByUUID = indices; // for bookkeeping 48963 48964 for ( let i = 0, n = arguments.length; i !== n; ++ i ) { 48965 48966 indices[ arguments[ i ].uuid ] = i; 48967 48968 } 48969 48970 this._paths = []; // inside: string 48971 this._parsedPaths = []; // inside: { we don't care, here } 48972 this._bindings = []; // inside: Array< PropertyBinding > 48973 this._bindingsIndicesByPath = {}; // inside: indices in these arrays 48974 48975 const scope = this; 48976 48977 this.stats = { 48978 48979 objects: { 48980 get total() { 48981 48982 return scope._objects.length; 48983 48984 }, 48985 get inUse() { 48986 48987 return this.total - scope.nCachedObjects_; 48988 48989 } 48990 }, 48991 get bindingsPerObject() { 48992 48993 return scope._bindings.length; 48994 48995 } 48996 48997 }; 48998 48999 } 49000 49001 add() { 49002 49003 const objects = this._objects, 49004 indicesByUUID = this._indicesByUUID, 49005 paths = this._paths, 49006 parsedPaths = this._parsedPaths, 49007 bindings = this._bindings, 49008 nBindings = bindings.length; 49009 49010 let knownObject = undefined, 49011 nObjects = objects.length, 49012 nCachedObjects = this.nCachedObjects_; 49013 49014 for ( let i = 0, n = arguments.length; i !== n; ++ i ) { 49015 49016 const object = arguments[ i ], 49017 uuid = object.uuid; 49018 let index = indicesByUUID[ uuid ]; 49019 49020 if ( index === undefined ) { 49021 49022 // unknown object -> add it to the ACTIVE region 49023 49024 index = nObjects ++; 49025 indicesByUUID[ uuid ] = index; 49026 objects.push( object ); 49027 49028 // accounting is done, now do the same for all bindings 49029 49030 for ( let j = 0, m = nBindings; j !== m; ++ j ) { 49031 49032 bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) ); 49033 49034 } 49035 49036 } else if ( index < nCachedObjects ) { 49037 49038 knownObject = objects[ index ]; 49039 49040 // move existing object to the ACTIVE region 49041 49042 const firstActiveIndex = -- nCachedObjects, 49043 lastCachedObject = objects[ firstActiveIndex ]; 49044 49045 indicesByUUID[ lastCachedObject.uuid ] = index; 49046 objects[ index ] = lastCachedObject; 49047 49048 indicesByUUID[ uuid ] = firstActiveIndex; 49049 objects[ firstActiveIndex ] = object; 49050 49051 // accounting is done, now do the same for all bindings 49052 49053 for ( let j = 0, m = nBindings; j !== m; ++ j ) { 49054
vendor: 4,084 bytes, lines 49055-49210
49055 const bindingsForPath = bindings[ j ], 49056 lastCached = bindingsForPath[ firstActiveIndex ]; 49057 49058 let binding = bindingsForPath[ index ]; 49059 49060 bindingsForPath[ index ] = lastCached; 49061 49062 if ( binding === undefined ) { 49063 49064 // since we do not bother to create new bindings 49065 // for objects that are cached, the binding may 49066 // or may not exist 49067 49068 binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ); 49069 49070 } 49071 49072 bindingsForPath[ firstActiveIndex ] = binding; 49073 49074 } 49075 49076 } else if ( objects[ index ] !== knownObject ) { 49077 49078 console.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' + 49079 'detected. Clean the caches or recreate your infrastructure when reloading scenes.' ); 49080 49081 } // else the object is already where we want it to be 49082 49083 } // for arguments 49084 49085 this.nCachedObjects_ = nCachedObjects; 49086 49087 } 49088 49089 remove() { 49090 49091 const objects = this._objects, 49092 indicesByUUID = this._indicesByUUID, 49093 bindings = this._bindings, 49094 nBindings = bindings.length; 49095 49096 let nCachedObjects = this.nCachedObjects_; 49097 49098 for ( let i = 0, n = arguments.length; i !== n; ++ i ) { 49099 49100 const object = arguments[ i ], 49101 uuid = object.uuid, 49102 index = indicesByUUID[ uuid ]; 49103 49104 if ( index !== undefined && index >= nCachedObjects ) { 49105 49106 // move existing object into the CACHED region 49107 49108 const lastCachedIndex = nCachedObjects ++, 49109 firstActiveObject = objects[ lastCachedIndex ]; 49110 49111 indicesByUUID[ firstActiveObject.uuid ] = index; 49112 objects[ index ] = firstActiveObject; 49113 49114 indicesByUUID[ uuid ] = lastCachedIndex; 49115 objects[ lastCachedIndex ] = object; 49116 49117 // accounting is done, now do the same for all bindings 49118 49119 for ( let j = 0, m = nBindings; j !== m; ++ j ) { 49120 49121 const bindingsForPath = bindings[ j ], 49122 firstActive = bindingsForPath[ lastCachedIndex ], 49123 binding = bindingsForPath[ index ]; 49124 49125 bindingsForPath[ index ] = firstActive; 49126 bindingsForPath[ lastCachedIndex ] = binding; 49127 49128 } 49129 49130 } 49131 49132 } // for arguments 49133 49134 this.nCachedObjects_ = nCachedObjects; 49135 49136 } 49137 49138 // remove & forget 49139 uncache() { 49140 49141 const objects = this._objects, 49142 indicesByUUID = this._indicesByUUID, 49143 bindings = this._bindings, 49144 nBindings = bindings.length; 49145 49146 let nCachedObjects = this.nCachedObjects_, 49147 nObjects = objects.length; 49148 49149 for ( let i = 0, n = arguments.length; i !== n; ++ i ) { 49150 49151 const object = arguments[ i ], 49152 uuid = object.uuid, 49153 index = indicesByUUID[ uuid ]; 49154 49155 if ( index !== undefined ) { 49156 49157 delete indicesByUUID[ uuid ]; 49158 49159 if ( index < nCachedObjects ) { 49160 49161 // object is cached, shrink the CACHED region 49162 49163 const firstActiveIndex = -- nCachedObjects, 49164 lastCachedObject = objects[ firstActiveIndex ], 49165 lastIndex = -- nObjects, 49166 lastObject = objects[ lastIndex ]; 49167 49168 // last cached object takes this object's place 49169 indicesByUUID[ lastCachedObject.uuid ] = index; 49170 objects[ index ] = lastCachedObject; 49171 49172 // last object goes to the activated slot and pop 49173 indicesByUUID[ lastObject.uuid ] = firstActiveIndex; 49174 objects[ firstActiveIndex ] = lastObject; 49175 objects.pop(); 49176 49177 // accounting is done, now do the same for all bindings 49178 49179 for ( let j = 0, m = nBindings; j !== m; ++ j ) { 49180 49181 const bindingsForPath = bindings[ j ], 49182 lastCached = bindingsForPath[ firstActiveIndex ], 49183 last = bindingsForPath[ lastIndex ]; 49184 49185 bindingsForPath[ index ] = lastCached; 49186 bindingsForPath[ firstActiveIndex ] = last; 49187 bindingsForPath.pop(); 49188 49189 } 49190 49191 } else { 49192 49193 // object is active, just swap with the last and pop 49194 49195 const lastIndex = -- nObjects, 49196 lastObject = objects[ lastIndex ]; 49197 49198 if ( lastIndex > 0 ) { 49199 49200 indicesByUUID[ lastObject.uuid ] = index; 49201 49202 } 49203 49204 objects[ index ] = lastObject; 49205 objects.pop(); 49206 49207 // accounting is done, now do the same for all bindings 49208 49209 for ( let j = 0, m = nBindings; j !== m; ++ j ) { 49210
vendor: 8,887 bytes, lines 49211-49639
49211 const bindingsForPath = bindings[ j ]; 49212 49213 bindingsForPath[ index ] = bindingsForPath[ lastIndex ]; 49214 bindingsForPath.pop(); 49215 49216 } 49217 49218 } // cached or active 49219 49220 } // if object is known 49221 49222 } // for arguments 49223 49224 this.nCachedObjects_ = nCachedObjects; 49225 49226 } 49227 49228 // Internal interface used by befriended PropertyBinding.Composite: 49229 49230 subscribe_( path, parsedPath ) { 49231 49232 // returns an array of bindings for the given path that is changed 49233 // according to the contained objects in the group 49234 49235 const indicesByPath = this._bindingsIndicesByPath; 49236 let index = indicesByPath[ path ]; 49237 const bindings = this._bindings; 49238 49239 if ( index !== undefined ) return bindings[ index ]; 49240 49241 const paths = this._paths, 49242 parsedPaths = this._parsedPaths, 49243 objects = this._objects, 49244 nObjects = objects.length, 49245 nCachedObjects = this.nCachedObjects_, 49246 bindingsForPath = new Array( nObjects ); 49247 49248 index = bindings.length; 49249 49250 indicesByPath[ path ] = index; 49251 49252 paths.push( path ); 49253 parsedPaths.push( parsedPath ); 49254 bindings.push( bindingsForPath ); 49255 49256 for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) { 49257 49258 const object = objects[ i ]; 49259 bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath ); 49260 49261 } 49262 49263 return bindingsForPath; 49264 49265 } 49266 49267 unsubscribe_( path ) { 49268 49269 // tells the group to forget about a property path and no longer 49270 // update the array previously obtained with 'subscribe_' 49271 49272 const indicesByPath = this._bindingsIndicesByPath, 49273 index = indicesByPath[ path ]; 49274 49275 if ( index !== undefined ) { 49276 49277 const paths = this._paths, 49278 parsedPaths = this._parsedPaths, 49279 bindings = this._bindings, 49280 lastBindingsIndex = bindings.length - 1, 49281 lastBindings = bindings[ lastBindingsIndex ], 49282 lastBindingsPath = path[ lastBindingsIndex ]; 49283 49284 indicesByPath[ lastBindingsPath ] = index; 49285 49286 bindings[ index ] = lastBindings; 49287 bindings.pop(); 49288 49289 parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ]; 49290 parsedPaths.pop(); 49291 49292 paths[ index ] = paths[ lastBindingsIndex ]; 49293 paths.pop(); 49294 49295 } 49296 49297 } 49298 49299} 49300 49301class AnimationAction { 49302 49303 constructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) { 49304 49305 this._mixer = mixer; 49306 this._clip = clip; 49307 this._localRoot = localRoot; 49308 this.blendMode = blendMode; 49309 49310 const tracks = clip.tracks, 49311 nTracks = tracks.length, 49312 interpolants = new Array( nTracks ); 49313 49314 const interpolantSettings = { 49315 endingStart: ZeroCurvatureEnding, 49316 endingEnd: ZeroCurvatureEnding 49317 }; 49318 49319 for ( let i = 0; i !== nTracks; ++ i ) { 49320 49321 const interpolant = tracks[ i ].createInterpolant( null ); 49322 interpolants[ i ] = interpolant; 49323 interpolant.settings = interpolantSettings; 49324 49325 } 49326 49327 this._interpolantSettings = interpolantSettings; 49328 49329 this._interpolants = interpolants; // bound by the mixer 49330 49331 // inside: PropertyMixer (managed by the mixer) 49332 this._propertyBindings = new Array( nTracks ); 49333 49334 this._cacheIndex = null; // for the memory manager 49335 this._byClipCacheIndex = null; // for the memory manager 49336 49337 this._timeScaleInterpolant = null; 49338 this._weightInterpolant = null; 49339 49340 this.loop = LoopRepeat; 49341 this._loopCount = - 1; 49342 49343 // global mixer time when the action is to be started 49344 // it's set back to 'null' upon start of the action 49345 this._startTime = null; 49346 49347 // scaled local time of the action 49348 // gets clamped or wrapped to 0..clip.duration according to loop 49349 this.time = 0; 49350 49351 this.timeScale = 1; 49352 this._effectiveTimeScale = 1; 49353 49354 this.weight = 1; 49355 this._effectiveWeight = 1; 49356 49357 this.repetitions = Infinity; // no. of repetitions when looping 49358 49359 this.paused = false; // true -> zero effective time scale 49360 this.enabled = true; // false -> zero effective weight 49361 49362 this.clampWhenFinished = false;// keep feeding the last frame? 49363 49364 this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate 49365 this.zeroSlopeAtEnd = true;// clips for start, loop and end 49366 49367 } 49368 49369 // State & Scheduling 49370 49371 play() { 49372 49373 this._mixer._activateAction( this ); 49374 49375 return this; 49376 49377 } 49378 49379 stop() { 49380 49381 this._mixer._deactivateAction( this ); 49382 49383 return this.reset(); 49384 49385 } 49386 49387 reset() { 49388 49389 this.paused = false; 49390 this.enabled = true; 49391 49392 this.time = 0; // restart clip 49393 this._loopCount = - 1;// forget previous loops 49394 this._startTime = null;// forget scheduling 49395 49396 return this.stopFading().stopWarping(); 49397 49398 } 49399 49400 isRunning() { 49401 49402 return this.enabled && ! this.paused && this.timeScale !== 0 && 49403 this._startTime === null && this._mixer._isActiveAction( this ); 49404 49405 } 49406 49407 // return true when play has been called 49408 isScheduled() { 49409 49410 return this._mixer._isActiveAction( this ); 49411 49412 } 49413 49414 startAt( time ) { 49415 49416 this._startTime = time; 49417 49418 return this; 49419 49420 } 49421 49422 setLoop( mode, repetitions ) { 49423 49424 this.loop = mode; 49425 this.repetitions = repetitions; 49426 49427 return this; 49428 49429 } 49430 49431 // Weight 49432 49433 // set the weight stopping any scheduled fading 49434 // although .enabled = false yields an effective weight of zero, this 49435 // method does *not* change .enabled, because it would be confusing 49436 setEffectiveWeight( weight ) { 49437 49438 this.weight = weight; 49439 49440 // note: same logic as when updated at runtime 49441 this._effectiveWeight = this.enabled ? weight : 0; 49442 49443 return this.stopFading(); 49444 49445 } 49446 49447 // return the weight considering fading and .enabled 49448 getEffectiveWeight() { 49449 49450 return this._effectiveWeight; 49451 49452 } 49453 49454 fadeIn( duration ) { 49455 49456 return this._scheduleFading( duration, 0, 1 ); 49457 49458 } 49459 49460 fadeOut( duration ) { 49461 49462 return this._scheduleFading( duration, 1, 0 ); 49463 49464 } 49465 49466 crossFadeFrom( fadeOutAction, duration, warp ) { 49467 49468 fadeOutAction.fadeOut( duration ); 49469 this.fadeIn( duration ); 49470 49471 if ( warp ) { 49472 49473 const fadeInDuration = this._clip.duration, 49474 fadeOutDuration = fadeOutAction._clip.duration, 49475 49476 startEndRatio = fadeOutDuration / fadeInDuration, 49477 endStartRatio = fadeInDuration / fadeOutDuration; 49478 49479 fadeOutAction.warp( 1.0, startEndRatio, duration ); 49480 this.warp( endStartRatio, 1.0, duration ); 49481 49482 } 49483 49484 return this; 49485 49486 } 49487 49488 crossFadeTo( fadeInAction, duration, warp ) { 49489 49490 return fadeInAction.crossFadeFrom( this, duration, warp ); 49491 49492 } 49493 49494 stopFading() { 49495 49496 const weightInterpolant = this._weightInterpolant; 49497 49498 if ( weightInterpolant !== null ) { 49499 49500 this._weightInterpolant = null; 49501 this._mixer._takeBackControlInterpolant( weightInterpolant ); 49502 49503 } 49504 49505 return this; 49506 49507 } 49508 49509 // Time Scale Control 49510 49511 // set the time scale stopping any scheduled warping 49512 // although .paused = true yields an effective time scale of zero, this 49513 // method does *not* change .paused, because it would be confusing 49514 setEffectiveTimeScale( timeScale ) { 49515 49516 this.timeScale = timeScale; 49517 this._effectiveTimeScale = this.paused ? 0 : timeScale; 49518 49519 return this.stopWarping(); 49520 49521 } 49522 49523 // return the time scale considering warping and .paused 49524 getEffectiveTimeScale() { 49525 49526 return this._effectiveTimeScale; 49527 49528 } 49529 49530 setDuration( duration ) { 49531 49532 this.timeScale = this._clip.duration / duration; 49533 49534 return this.stopWarping(); 49535 49536 } 49537 49538 syncWith( action ) { 49539 49540 this.time = action.time; 49541 this.timeScale = action.timeScale; 49542 49543 return this.stopWarping(); 49544 49545 } 49546 49547 halt( duration ) { 49548 49549 return this.warp( this._effectiveTimeScale, 0, duration ); 49550 49551 } 49552 49553 warp( startTimeScale, endTimeScale, duration ) { 49554 49555 const mixer = this._mixer, 49556 now = mixer.time, 49557 timeScale = this.timeScale; 49558 49559 let interpolant = this._timeScaleInterpolant; 49560 49561 if ( interpolant === null ) { 49562 49563 interpolant = mixer._lendControlInterpolant(); 49564 this._timeScaleInterpolant = interpolant; 49565 49566 } 49567 49568 const times = interpolant.parameterPositions, 49569 values = interpolant.sampleValues; 49570 49571 times[ 0 ] = now; 49572 times[ 1 ] = now + duration; 49573 49574 values[ 0 ] = startTimeScale / timeScale; 49575 values[ 1 ] = endTimeScale / timeScale; 49576 49577 return this; 49578 49579 } 49580 49581 stopWarping() { 49582 49583 const timeScaleInterpolant = this._timeScaleInterpolant; 49584 49585 if ( timeScaleInterpolant !== null ) { 49586 49587 this._timeScaleInterpolant = null; 49588 this._mixer._takeBackControlInterpolant( timeScaleInterpolant ); 49589 49590 } 49591 49592 return this; 49593 49594 } 49595 49596 // Object Accessors 49597 49598 getMixer() { 49599 49600 return this._mixer; 49601 49602 } 49603 49604 getClip() { 49605 49606 return this._clip; 49607 49608 } 49609 49610 getRoot() { 49611 49612 return this._localRoot || this._mixer._root; 49613 49614 } 49615 49616 // Interna 49617 49618 _update( time, deltaTime, timeDirection, accuIndex ) { 49619 49620 // called by the mixer 49621 49622 if ( ! this.enabled ) { 49623 49624 // call ._updateWeight() to update ._effectiveWeight 49625 49626 this._updateWeight( time ); 49627 return; 49628 49629 } 49630 49631 const startTime = this._startTime; 49632 49633 if ( startTime !== null ) { 49634 49635 // check for scheduled start of action 49636 49637 const timeRunning = ( time - startTime ) * timeDirection; 49638 if ( timeRunning < 0 || timeDirection === 0 ) { 49639
vendor: 6,403 bytes, lines 49640-49998
49640 deltaTime = 0; 49641 49642 } else { 49643 49644 49645 this._startTime = null; // unschedule 49646 deltaTime = timeDirection * timeRunning; 49647 49648 } 49649 49650 } 49651 49652 // apply time scale and advance time 49653 49654 deltaTime *= this._updateTimeScale( time ); 49655 const clipTime = this._updateTime( deltaTime ); 49656 49657 // note: _updateTime may disable the action resulting in 49658 // an effective weight of 0 49659 49660 const weight = this._updateWeight( time ); 49661 49662 if ( weight > 0 ) { 49663 49664 const interpolants = this._interpolants; 49665 const propertyMixers = this._propertyBindings; 49666 49667 switch ( this.blendMode ) { 49668 49669 case AdditiveAnimationBlendMode: 49670 49671 for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { 49672 49673 interpolants[ j ].evaluate( clipTime ); 49674 propertyMixers[ j ].accumulateAdditive( weight ); 49675 49676 } 49677 49678 break; 49679 49680 case NormalAnimationBlendMode: 49681 default: 49682 49683 for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { 49684 49685 interpolants[ j ].evaluate( clipTime ); 49686 propertyMixers[ j ].accumulate( accuIndex, weight ); 49687 49688 } 49689 49690 } 49691 49692 } 49693 49694 } 49695 49696 _updateWeight( time ) { 49697 49698 let weight = 0; 49699 49700 if ( this.enabled ) { 49701 49702 weight = this.weight; 49703 const interpolant = this._weightInterpolant; 49704 49705 if ( interpolant !== null ) { 49706 49707 const interpolantValue = interpolant.evaluate( time )[ 0 ]; 49708 49709 weight *= interpolantValue; 49710 49711 if ( time > interpolant.parameterPositions[ 1 ] ) { 49712 49713 this.stopFading(); 49714 49715 if ( interpolantValue === 0 ) { 49716 49717 // faded out, disable 49718 this.enabled = false; 49719 49720 } 49721 49722 } 49723 49724 } 49725 49726 } 49727 49728 this._effectiveWeight = weight; 49729 return weight; 49730 49731 } 49732 49733 _updateTimeScale( time ) { 49734 49735 let timeScale = 0; 49736 49737 if ( ! this.paused ) { 49738 49739 timeScale = this.timeScale; 49740 49741 const interpolant = this._timeScaleInterpolant; 49742 49743 if ( interpolant !== null ) { 49744 49745 const interpolantValue = interpolant.evaluate( time )[ 0 ]; 49746 49747 timeScale *= interpolantValue; 49748 49749 if ( time > interpolant.parameterPositions[ 1 ] ) { 49750 49751 this.stopWarping(); 49752 49753 if ( timeScale === 0 ) { 49754 49755 // motion has halted, pause 49756 this.paused = true; 49757 49758 } else { 49759 49760 // warp done - apply final time scale 49761 this.timeScale = timeScale; 49762 49763 } 49764 49765 } 49766 49767 } 49768 49769 } 49770 49771 this._effectiveTimeScale = timeScale; 49772 return timeScale; 49773 49774 } 49775 49776 _updateTime( deltaTime ) { 49777 49778 const duration = this._clip.duration; 49779 const loop = this.loop; 49780 49781 let time = this.time + deltaTime; 49782 let loopCount = this._loopCount; 49783 49784 const pingPong = ( loop === LoopPingPong ); 49785 49786 if ( deltaTime === 0 ) { 49787 49788 if ( loopCount === - 1 ) return time; 49789 49790 return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time; 49791 49792 } 49793 49794 if ( loop === LoopOnce ) { 49795 49796 if ( loopCount === - 1 ) { 49797 49798 // just started 49799 49800 this._loopCount = 0; 49801 this._setEndings( true, true, false ); 49802 49803 } 49804 49805 handle_stop: { 49806 49807 if ( time >= duration ) { 49808 49809 time = duration; 49810 49811 } else if ( time < 0 ) { 49812 49813 time = 0; 49814 49815 } else { 49816 49817 this.time = time; 49818 49819 break handle_stop; 49820 49821 } 49822 49823 if ( this.clampWhenFinished ) this.paused = true; 49824 else this.enabled = false; 49825 49826 this.time = time; 49827 49828 this._mixer.dispatchEvent( { 49829 type: 'finished', action: this, 49830 direction: deltaTime < 0 ? - 1 : 1 49831 } ); 49832 49833 } 49834 49835 } else { // repetitive Repeat or PingPong 49836 49837 if ( loopCount === - 1 ) { 49838 49839 // just started 49840 49841 if ( deltaTime >= 0 ) { 49842 49843 loopCount = 0; 49844 49845 this._setEndings( true, this.repetitions === 0, pingPong ); 49846 49847 } else { 49848 49849 // when looping in reverse direction, the initial 49850 // transition through zero counts as a repetition, 49851 // so leave loopCount at -1 49852 49853 this._setEndings( this.repetitions === 0, true, pingPong ); 49854 49855 } 49856 49857 } 49858 49859 if ( time >= duration || time < 0 ) { 49860 49861 // wrap around 49862 49863 const loopDelta = Math.floor( time / duration ); // signed 49864 time -= duration * loopDelta; 49865 49866 loopCount += Math.abs( loopDelta ); 49867 49868 const pending = this.repetitions - loopCount; 49869 49870 if ( pending <= 0 ) { 49871 49872 // have to stop (switch state, clamp time, fire event) 49873 49874 if ( this.clampWhenFinished ) this.paused = true; 49875 else this.enabled = false; 49876 49877 time = deltaTime > 0 ? duration : 0; 49878 49879 this.time = time; 49880 49881 this._mixer.dispatchEvent( { 49882 type: 'finished', action: this, 49883 direction: deltaTime > 0 ? 1 : - 1 49884 } ); 49885 49886 } else { 49887 49888 // keep running 49889 49890 if ( pending === 1 ) { 49891 49892 // entering the last round 49893 49894 const atStart = deltaTime < 0; 49895 this._setEndings( atStart, ! atStart, pingPong ); 49896 49897 } else { 49898 49899 this._setEndings( false, false, pingPong ); 49900 49901 } 49902 49903 this._loopCount = loopCount; 49904 49905 this.time = time; 49906 49907 this._mixer.dispatchEvent( { 49908 type: 'loop', action: this, loopDelta: loopDelta 49909 } ); 49910 49911 } 49912 49913 } else { 49914 49915 this.time = time; 49916 49917 } 49918 49919 if ( pingPong && ( loopCount & 1 ) === 1 ) { 49920 49921 // invert time for the "pong round" 49922 49923 return duration - time; 49924 49925 } 49926 49927 } 49928 49929 return time; 49930 49931 } 49932 49933 _setEndings( atStart, atEnd, pingPong ) { 49934 49935 const settings = this._interpolantSettings; 49936 49937 if ( pingPong ) { 49938 49939 settings.endingStart = ZeroSlopeEnding; 49940 settings.endingEnd = ZeroSlopeEnding; 49941 49942 } else { 49943 49944 // assuming for LoopOnce atStart == atEnd == true 49945 49946 if ( atStart ) { 49947 49948 settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding; 49949 49950 } else { 49951 49952 settings.endingStart = WrapAroundEnding; 49953 49954 } 49955 49956 if ( atEnd ) { 49957 49958 settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding; 49959 49960 } else { 49961 49962 settings.endingEnd = WrapAroundEnding; 49963 49964 } 49965 49966 } 49967 49968 } 49969 49970 _scheduleFading( duration, weightNow, weightThen ) { 49971 49972 const mixer = this._mixer, now = mixer.time; 49973 let interpolant = this._weightInterpolant; 49974 49975 if ( interpolant === null ) { 49976 49977 interpolant = mixer._lendControlInterpolant(); 49978 this._weightInterpolant = interpolant; 49979 49980 } 49981 49982 const times = interpolant.parameterPositions, 49983 values = interpolant.sampleValues; 49984 49985 times[ 0 ] = now; 49986 values[ 0 ] = weightNow; 49987 times[ 1 ] = now + duration; 49988 values[ 1 ] = weightThen; 49989 49990 return this; 49991 49992 } 49993 49994} 49995 49996const _controlInterpolantsResultBuffer = new Float32Array( 1 ); 49997 49998
vendor: 13,903 bytes, lines 49999-50629
49999class AnimationMixer extends EventDispatcher { 50000 50001 constructor( root ) { 50002 50003 super(); 50004 50005 this._root = root; 50006 this._initMemoryManager(); 50007 this._accuIndex = 0; 50008 this.time = 0; 50009 this.timeScale = 1.0; 50010 50011 } 50012 50013 _bindAction( action, prototypeAction ) { 50014 50015 const root = action._localRoot || this._root, 50016 tracks = action._clip.tracks, 50017 nTracks = tracks.length, 50018 bindings = action._propertyBindings, 50019 interpolants = action._interpolants, 50020 rootUuid = root.uuid, 50021 bindingsByRoot = this._bindingsByRootAndName; 50022 50023 let bindingsByName = bindingsByRoot[ rootUuid ]; 50024 50025 if ( bindingsByName === undefined ) { 50026 50027 bindingsByName = {}; 50028 bindingsByRoot[ rootUuid ] = bindingsByName; 50029 50030 } 50031 50032 for ( let i = 0; i !== nTracks; ++ i ) { 50033 50034 const track = tracks[ i ], 50035 trackName = track.name; 50036 50037 let binding = bindingsByName[ trackName ]; 50038 50039 if ( binding !== undefined ) { 50040 50041 ++ binding.referenceCount; 50042 bindings[ i ] = binding; 50043 50044 } else { 50045 50046 binding = bindings[ i ]; 50047 50048 if ( binding !== undefined ) { 50049 50050 // existing binding, make sure the cache knows 50051 50052 if ( binding._cacheIndex === null ) { 50053 50054 ++ binding.referenceCount; 50055 this._addInactiveBinding( binding, rootUuid, trackName ); 50056 50057 } 50058 50059 continue; 50060 50061 } 50062 50063 const path = prototypeAction && prototypeAction. 50064 _propertyBindings[ i ].binding.parsedPath; 50065 50066 binding = new PropertyMixer( 50067 PropertyBinding.create( root, trackName, path ), 50068 track.ValueTypeName, track.getValueSize() ); 50069 50070 ++ binding.referenceCount; 50071 this._addInactiveBinding( binding, rootUuid, trackName ); 50072 50073 bindings[ i ] = binding; 50074 50075 } 50076 50077 interpolants[ i ].resultBuffer = binding.buffer; 50078 50079 } 50080 50081 } 50082 50083 _activateAction( action ) { 50084 50085 if ( ! this._isActiveAction( action ) ) { 50086 50087 if ( action._cacheIndex === null ) { 50088 50089 // this action has been forgotten by the cache, but the user 50090 // appears to be still using it -> rebind 50091 50092 const rootUuid = ( action._localRoot || this._root ).uuid, 50093 clipUuid = action._clip.uuid, 50094 actionsForClip = this._actionsByClip[ clipUuid ]; 50095 50096 this._bindAction( action, 50097 actionsForClip && actionsForClip.knownActions[ 0 ] ); 50098 50099 this._addInactiveAction( action, clipUuid, rootUuid ); 50100 50101 } 50102 50103 const bindings = action._propertyBindings; 50104 50105 // increment reference counts / sort out state 50106 for ( let i = 0, n = bindings.length; i !== n; ++ i ) { 50107 50108 const binding = bindings[ i ]; 50109 50110 if ( binding.useCount ++ === 0 ) { 50111 50112 this._lendBinding( binding ); 50113 binding.saveOriginalState(); 50114 50115 } 50116 50117 } 50118 50119 this._lendAction( action ); 50120 50121 } 50122 50123 } 50124 50125 _deactivateAction( action ) { 50126 50127 if ( this._isActiveAction( action ) ) { 50128 50129 const bindings = action._propertyBindings; 50130 50131 // decrement reference counts / sort out state 50132 for ( let i = 0, n = bindings.length; i !== n; ++ i ) { 50133 50134 const binding = bindings[ i ]; 50135 50136 if ( -- binding.useCount === 0 ) { 50137 50138 binding.restoreOriginalState(); 50139 this._takeBackBinding( binding ); 50140 50141 } 50142 50143 } 50144 50145 this._takeBackAction( action ); 50146 50147 } 50148 50149 } 50150 50151 // Memory manager 50152 50153 _initMemoryManager() { 50154 50155 this._actions = []; // 'nActiveActions' followed by inactive ones 50156 this._nActiveActions = 0; 50157 50158 this._actionsByClip = {}; 50159 // inside: 50160 // { 50161 // knownActions: Array< AnimationAction > - used as prototypes 50162 // actionByRoot: AnimationAction - lookup 50163 // } 50164 50165 50166 this._bindings = []; // 'nActiveBindings' followed by inactive ones 50167 this._nActiveBindings = 0; 50168 50169 this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer > 50170 50171 50172 this._controlInterpolants = []; // same game as above 50173 this._nActiveControlInterpolants = 0; 50174 50175 const scope = this; 50176 50177 this.stats = { 50178 50179 actions: { 50180 get total() { 50181 50182 return scope._actions.length; 50183 50184 }, 50185 get inUse() { 50186 50187 return scope._nActiveActions; 50188 50189 } 50190 }, 50191 bindings: { 50192 get total() { 50193 50194 return scope._bindings.length; 50195 50196 }, 50197 get inUse() { 50198 50199 return scope._nActiveBindings; 50200 50201 } 50202 }, 50203 controlInterpolants: { 50204 get total() { 50205 50206 return scope._controlInterpolants.length; 50207 50208 }, 50209 get inUse() { 50210 50211 return scope._nActiveControlInterpolants; 50212 50213 } 50214 } 50215 50216 }; 50217 50218 } 50219 50220 // Memory management for AnimationAction objects 50221 50222 _isActiveAction( action ) { 50223 50224 const index = action._cacheIndex; 50225 return index !== null && index < this._nActiveActions; 50226 50227 } 50228 50229 _addInactiveAction( action, clipUuid, rootUuid ) { 50230 50231 const actions = this._actions, 50232 actionsByClip = this._actionsByClip; 50233 50234 let actionsForClip = actionsByClip[ clipUuid ]; 50235 50236 if ( actionsForClip === undefined ) { 50237 50238 actionsForClip = { 50239 50240 knownActions: [ action ], 50241 actionByRoot: {} 50242 50243 }; 50244 50245 action._byClipCacheIndex = 0; 50246 50247 actionsByClip[ clipUuid ] = actionsForClip; 50248 50249 } else { 50250 50251 const knownActions = actionsForClip.knownActions; 50252 50253 action._byClipCacheIndex = knownActions.length; 50254 knownActions.push( action ); 50255 50256 } 50257 50258 action._cacheIndex = actions.length; 50259 actions.push( action ); 50260 50261 actionsForClip.actionByRoot[ rootUuid ] = action; 50262 50263 } 50264 50265 _removeInactiveAction( action ) { 50266 50267 const actions = this._actions, 50268 lastInactiveAction = actions[ actions.length - 1 ], 50269 cacheIndex = action._cacheIndex; 50270 50271 lastInactiveAction._cacheIndex = cacheIndex; 50272 actions[ cacheIndex ] = lastInactiveAction; 50273 actions.pop(); 50274 50275 action._cacheIndex = null; 50276 50277 50278 const clipUuid = action._clip.uuid, 50279 actionsByClip = this._actionsByClip, 50280 actionsForClip = actionsByClip[ clipUuid ], 50281 knownActionsForClip = actionsForClip.knownActions, 50282 50283 lastKnownAction = 50284 knownActionsForClip[ knownActionsForClip.length - 1 ], 50285 50286 byClipCacheIndex = action._byClipCacheIndex; 50287 50288 lastKnownAction._byClipCacheIndex = byClipCacheIndex; 50289 knownActionsForClip[ byClipCacheIndex ] = lastKnownAction; 50290 knownActionsForClip.pop(); 50291 50292 action._byClipCacheIndex = null; 50293 50294 50295 const actionByRoot = actionsForClip.actionByRoot, 50296 rootUuid = ( action._localRoot || this._root ).uuid; 50297 50298 delete actionByRoot[ rootUuid ]; 50299 50300 if ( knownActionsForClip.length === 0 ) { 50301 50302 delete actionsByClip[ clipUuid ]; 50303 50304 } 50305 50306 this._removeInactiveBindingsForAction( action ); 50307 50308 } 50309 50310 _removeInactiveBindingsForAction( action ) { 50311 50312 const bindings = action._propertyBindings; 50313 50314 for ( let i = 0, n = bindings.length; i !== n; ++ i ) { 50315 50316 const binding = bindings[ i ]; 50317 50318 if ( -- binding.referenceCount === 0 ) { 50319 50320 this._removeInactiveBinding( binding ); 50321 50322 } 50323 50324 } 50325 50326 } 50327 50328 _lendAction( action ) { 50329 50330 // [ active actions | inactive actions ] 50331 // [ active actions >| inactive actions ] 50332 // s a 50333 // <-swap-> 50334 // a s 50335 50336 const actions = this._actions, 50337 prevIndex = action._cacheIndex, 50338 50339 lastActiveIndex = this._nActiveActions ++, 50340 50341 firstInactiveAction = actions[ lastActiveIndex ]; 50342 50343 action._cacheIndex = lastActiveIndex; 50344 actions[ lastActiveIndex ] = action; 50345 50346 firstInactiveAction._cacheIndex = prevIndex; 50347 actions[ prevIndex ] = firstInactiveAction; 50348 50349 } 50350 50351 _takeBackAction( action ) { 50352 50353 // [ active actions | inactive actions ] 50354 // [ active actions |< inactive actions ] 50355 // a s 50356 // <-swap-> 50357 // s a 50358 50359 const actions = this._actions, 50360 prevIndex = action._cacheIndex, 50361 50362 firstInactiveIndex = -- this._nActiveActions, 50363 50364 lastActiveAction = actions[ firstInactiveIndex ]; 50365 50366 action._cacheIndex = firstInactiveIndex; 50367 actions[ firstInactiveIndex ] = action; 50368 50369 lastActiveAction._cacheIndex = prevIndex; 50370 actions[ prevIndex ] = lastActiveAction; 50371 50372 } 50373 50374 // Memory management for PropertyMixer objects 50375 50376 _addInactiveBinding( binding, rootUuid, trackName ) { 50377 50378 const bindingsByRoot = this._bindingsByRootAndName, 50379 bindings = this._bindings; 50380 50381 let bindingByName = bindingsByRoot[ rootUuid ]; 50382 50383 if ( bindingByName === undefined ) { 50384 50385 bindingByName = {}; 50386 bindingsByRoot[ rootUuid ] = bindingByName; 50387 50388 } 50389 50390 bindingByName[ trackName ] = binding; 50391 50392 binding._cacheIndex = bindings.length; 50393 bindings.push( binding ); 50394 50395 } 50396 50397 _removeInactiveBinding( binding ) { 50398 50399 const bindings = this._bindings, 50400 propBinding = binding.binding, 50401 rootUuid = propBinding.rootNode.uuid, 50402 trackName = propBinding.path, 50403 bindingsByRoot = this._bindingsByRootAndName, 50404 bindingByName = bindingsByRoot[ rootUuid ], 50405 50406 lastInactiveBinding = bindings[ bindings.length - 1 ], 50407 cacheIndex = binding._cacheIndex; 50408 50409 lastInactiveBinding._cacheIndex = cacheIndex; 50410 bindings[ cacheIndex ] = lastInactiveBinding; 50411 bindings.pop(); 50412 50413 delete bindingByName[ trackName ]; 50414 50415 if ( Object.keys( bindingByName ).length === 0 ) { 50416 50417 delete bindingsByRoot[ rootUuid ]; 50418 50419 } 50420 50421 } 50422 50423 _lendBinding( binding ) { 50424 50425 const bindings = this._bindings, 50426 prevIndex = binding._cacheIndex, 50427 50428 lastActiveIndex = this._nActiveBindings ++, 50429 50430 firstInactiveBinding = bindings[ lastActiveIndex ]; 50431 50432 binding._cacheIndex = lastActiveIndex; 50433 bindings[ lastActiveIndex ] = binding; 50434 50435 firstInactiveBinding._cacheIndex = prevIndex; 50436 bindings[ prevIndex ] = firstInactiveBinding; 50437 50438 } 50439 50440 _takeBackBinding( binding ) { 50441 50442 const bindings = this._bindings, 50443 prevIndex = binding._cacheIndex, 50444 50445 firstInactiveIndex = -- this._nActiveBindings, 50446 50447 lastActiveBinding = bindings[ firstInactiveIndex ]; 50448 50449 binding._cacheIndex = firstInactiveIndex; 50450 bindings[ firstInactiveIndex ] = binding; 50451 50452 lastActiveBinding._cacheIndex = prevIndex; 50453 bindings[ prevIndex ] = lastActiveBinding; 50454 50455 } 50456 50457 50458 // Memory management of Interpolants for weight and time scale 50459 50460 _lendControlInterpolant() { 50461 50462 const interpolants = this._controlInterpolants, 50463 lastActiveIndex = this._nActiveControlInterpolants ++; 50464 50465 let interpolant = interpolants[ lastActiveIndex ]; 50466 50467 if ( interpolant === undefined ) { 50468 50469 interpolant = new LinearInterpolant( 50470 new Float32Array( 2 ), new Float32Array( 2 ), 50471 1, _controlInterpolantsResultBuffer ); 50472 50473 interpolant.__cacheIndex = lastActiveIndex; 50474 interpolants[ lastActiveIndex ] = interpolant; 50475 50476 } 50477 50478 return interpolant; 50479 50480 } 50481 50482 _takeBackControlInterpolant( interpolant ) { 50483 50484 const interpolants = this._controlInterpolants, 50485 prevIndex = interpolant.__cacheIndex, 50486 50487 firstInactiveIndex = -- this._nActiveControlInterpolants, 50488 50489 lastActiveInterpolant = interpolants[ firstInactiveIndex ]; 50490 50491 interpolant.__cacheIndex = firstInactiveIndex; 50492 interpolants[ firstInactiveIndex ] = interpolant; 50493 50494 lastActiveInterpolant.__cacheIndex = prevIndex; 50495 interpolants[ prevIndex ] = lastActiveInterpolant; 50496 50497 } 50498 50499 // return an action for a clip optionally using a custom root target 50500 // object (this method allocates a lot of dynamic memory in case a 50501 // previously unknown clip/root combination is specified) 50502 clipAction( clip, optionalRoot, blendMode ) { 50503 50504 const root = optionalRoot || this._root, 50505 rootUuid = root.uuid; 50506 50507 let clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip; 50508 50509 const clipUuid = clipObject !== null ? clipObject.uuid : clip; 50510 50511 const actionsForClip = this._actionsByClip[ clipUuid ]; 50512 let prototypeAction = null; 50513 50514 if ( blendMode === undefined ) { 50515 50516 if ( clipObject !== null ) { 50517 50518 50519 blendMode = clipObject.blendMode; 50520 50521 } else { 50522 50523 blendMode = NormalAnimationBlendMode; 50524 50525 } 50526 50527 } 50528 50529 if ( actionsForClip !== undefined ) { 50530 50531 const existingAction = actionsForClip.actionByRoot[ rootUuid ]; 50532 50533 if ( existingAction !== undefined && existingAction.blendMode === blendMode ) { 50534 50535 return existingAction; 50536 50537 } 50538 50539 // we know the clip, so we don't have to parse all 50540 // the bindings again but can just copy 50541 prototypeAction = actionsForClip.knownActions[ 0 ]; 50542 50543 // also, take the clip from the prototype action 50544 if ( clipObject === null ) 50545 clipObject = prototypeAction._clip; 50546 50547 } 50548 50549 // clip must be known when specified via string 50550 if ( clipObject === null ) return null; 50551 50552 // allocate all resources required to run it 50553 const newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode ); 50554 50555 this._bindAction( newAction, prototypeAction ); 50556 50557 // and make the action known to the memory manager 50558 this._addInactiveAction( newAction, clipUuid, rootUuid ); 50559 50560 return newAction; 50561 50562 } 50563 50564 // get an existing action 50565 existingAction( clip, optionalRoot ) { 50566 50567 const root = optionalRoot || this._root, 50568 rootUuid = root.uuid, 50569 50570 clipObject = typeof clip === 'string' ? 50571 AnimationClip.findByName( root, clip ) : clip, 50572 50573 clipUuid = clipObject ? clipObject.uuid : clip, 50574 50575 actionsForClip = this._actionsByClip[ clipUuid ]; 50576 50577 if ( actionsForClip !== undefined ) { 50578 50579 return actionsForClip.actionByRoot[ rootUuid ] || null; 50580 50581 } 50582 50583 return null; 50584 50585 } 50586 50587 // deactivates all previously scheduled actions 50588 stopAllAction() { 50589 50590 const actions = this._actions, 50591 nActions = this._nActiveActions; 50592 50593 for ( let i = nActions - 1; i >= 0; -- i ) { 50594 50595 actions[ i ].stop(); 50596 50597 } 50598 50599 return this; 50600 50601 } 50602 50603 // advance the time and update apply the animation 50604 update( deltaTime ) { 50605 50606 deltaTime *= this.timeScale; 50607 50608 const actions = this._actions, 50609 nActions = this._nActiveActions, 50610 50611 time = this.time += deltaTime, 50612 timeDirection = Math.sign( deltaTime ), 50613 50614 accuIndex = this._accuIndex ^= 1; 50615 50616 // run active actions 50617 50618 for ( let i = 0; i !== nActions; ++ i ) { 50619 50620 const action = actions[ i ]; 50621 50622 action._update( time, deltaTime, timeDirection, accuIndex ); 50623 50624 } 50625 50626 // update scene graph 50627 50628 const bindings = this._bindings, 50629 nBindings = this._nActiveBindings;
vendor: 3,018 bytes, lines 50630-50774
50630 50631 for ( let i = 0; i !== nBindings; ++ i ) { 50632 50633 bindings[ i ].apply( accuIndex ); 50634 50635 } 50636 50637 return this; 50638 50639 } 50640 50641 // Allows you to seek to a specific time in an animation. 50642 setTime( timeInSeconds ) { 50643 50644 this.time = 0; // Zero out time attribute for AnimationMixer object; 50645 for ( let i = 0; i < this._actions.length; i ++ ) { 50646 50647 this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects. 50648 50649 } 50650 50651 return this.update( timeInSeconds ); // Update used to set exact time. Returns "this" AnimationMixer object. 50652 50653 } 50654 50655 // return this mixer's root target object 50656 getRoot() { 50657 50658 return this._root; 50659 50660 } 50661 50662 // free all resources specific to a particular clip 50663 uncacheClip( clip ) { 50664 50665 const actions = this._actions, 50666 clipUuid = clip.uuid, 50667 actionsByClip = this._actionsByClip, 50668 actionsForClip = actionsByClip[ clipUuid ]; 50669 50670 if ( actionsForClip !== undefined ) { 50671 50672 // note: just calling _removeInactiveAction would mess up the 50673 // iteration state and also require updating the state we can 50674 // just throw away 50675 50676 const actionsToRemove = actionsForClip.knownActions; 50677 50678 for ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) { 50679 50680 const action = actionsToRemove[ i ]; 50681 50682 this._deactivateAction( action ); 50683 50684 const cacheIndex = action._cacheIndex, 50685 lastInactiveAction = actions[ actions.length - 1 ]; 50686 50687 action._cacheIndex = null; 50688 action._byClipCacheIndex = null; 50689 50690 lastInactiveAction._cacheIndex = cacheIndex; 50691 actions[ cacheIndex ] = lastInactiveAction; 50692 actions.pop(); 50693 50694 this._removeInactiveBindingsForAction( action ); 50695 50696 } 50697 50698 delete actionsByClip[ clipUuid ]; 50699 50700 } 50701 50702 } 50703 50704 // free all resources specific to a particular root target object 50705 uncacheRoot( root ) { 50706 50707 const rootUuid = root.uuid, 50708 actionsByClip = this._actionsByClip; 50709 50710 for ( const clipUuid in actionsByClip ) { 50711 50712 const actionByRoot = actionsByClip[ clipUuid ].actionByRoot, 50713 action = actionByRoot[ rootUuid ]; 50714 50715 if ( action !== undefined ) { 50716 50717 this._deactivateAction( action ); 50718 this._removeInactiveAction( action ); 50719 50720 } 50721 50722 } 50723 50724 const bindingsByRoot = this._bindingsByRootAndName, 50725 bindingByName = bindingsByRoot[ rootUuid ]; 50726 50727 if ( bindingByName !== undefined ) { 50728 50729 for ( const trackName in bindingByName ) { 50730 50731 const binding = bindingByName[ trackName ]; 50732 binding.restoreOriginalState(); 50733 this._removeInactiveBinding( binding ); 50734 50735 } 50736 50737 } 50738 50739 } 50740 50741 // remove a targeted clip from the cache 50742 uncacheAction( clip, optionalRoot ) { 50743 50744 const action = this.existingAction( clip, optionalRoot ); 50745 50746 if ( action !== null ) { 50747 50748 this._deactivateAction( action ); 50749 this._removeInactiveAction( action ); 50750 50751 } 50752 50753 } 50754 50755} 50756 50757class Uniform { 50758 50759 constructor( value ) { 50760 50761 this.value = value; 50762 50763 } 50764 50765 clone() { 50766 50767 return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() ); 50768 50769 } 50770 50771} 50772 50773let _id = 0; 50774
vendor: 5,238 bytes, lines 50775-51086
50775class UniformsGroup extends EventDispatcher { 50776 50777 constructor() { 50778 50779 super(); 50780 50781 this.isUniformsGroup = true; 50782 50783 Object.defineProperty( this, 'id', { value: _id ++ } ); 50784 50785 this.name = ''; 50786 50787 this.usage = StaticDrawUsage; 50788 this.uniforms = []; 50789 50790 } 50791 50792 add( uniform ) { 50793 50794 this.uniforms.push( uniform ); 50795 50796 return this; 50797 50798 } 50799 50800 remove( uniform ) { 50801 50802 const index = this.uniforms.indexOf( uniform ); 50803 50804 if ( index !== - 1 ) this.uniforms.splice( index, 1 ); 50805 50806 return this; 50807 50808 } 50809 50810 setName( name ) { 50811 50812 this.name = name; 50813 50814 return this; 50815 50816 } 50817 50818 setUsage( value ) { 50819 50820 this.usage = value; 50821 50822 return this; 50823 50824 } 50825 50826 dispose() { 50827 50828 this.dispatchEvent( { type: 'dispose' } ); 50829 50830 return this; 50831 50832 } 50833 50834 copy( source ) { 50835 50836 this.name = source.name; 50837 this.usage = source.usage; 50838 50839 const uniformsSource = source.uniforms; 50840 50841 this.uniforms.length = 0; 50842 50843 for ( let i = 0, l = uniformsSource.length; i < l; i ++ ) { 50844 50845 const uniforms = Array.isArray( uniformsSource[ i ] ) ? uniformsSource[ i ] : [ uniformsSource[ i ] ]; 50846 50847 for ( let j = 0; j < uniforms.length; j ++ ) { 50848 50849 this.uniforms.push( uniforms[ j ].clone() ); 50850 50851 } 50852 50853 } 50854 50855 return this; 50856 50857 } 50858 50859 clone() { 50860 50861 return new this.constructor().copy( this ); 50862 50863 } 50864 50865} 50866 50867class InstancedInterleavedBuffer extends InterleavedBuffer { 50868 50869 constructor( array, stride, meshPerAttribute = 1 ) { 50870 50871 super( array, stride ); 50872 50873 this.isInstancedInterleavedBuffer = true; 50874 50875 this.meshPerAttribute = meshPerAttribute; 50876 50877 } 50878 50879 copy( source ) { 50880 50881 super.copy( source ); 50882 50883 this.meshPerAttribute = source.meshPerAttribute; 50884 50885 return this; 50886 50887 } 50888 50889 clone( data ) { 50890 50891 const ib = super.clone( data ); 50892 50893 ib.meshPerAttribute = this.meshPerAttribute; 50894 50895 return ib; 50896 50897 } 50898 50899 toJSON( data ) { 50900 50901 const json = super.toJSON( data ); 50902 50903 json.isInstancedInterleavedBuffer = true; 50904 json.meshPerAttribute = this.meshPerAttribute; 50905 50906 return json; 50907 50908 } 50909 50910} 50911 50912class GLBufferAttribute { 50913 50914 constructor( buffer, type, itemSize, elementSize, count ) { 50915 50916 this.isGLBufferAttribute = true; 50917 50918 this.name = ''; 50919 50920 this.buffer = buffer; 50921 this.type = type; 50922 this.itemSize = itemSize; 50923 this.elementSize = elementSize; 50924 this.count = count; 50925 50926 this.version = 0; 50927 50928 } 50929 50930 set needsUpdate( value ) { 50931 50932 if ( value === true ) this.version ++; 50933 50934 } 50935 50936 setBuffer( buffer ) { 50937 50938 this.buffer = buffer; 50939 50940 return this; 50941 50942 } 50943 50944 setType( type, elementSize ) { 50945 50946 this.type = type; 50947 this.elementSize = elementSize; 50948 50949 return this; 50950 50951 } 50952 50953 setItemSize( itemSize ) { 50954 50955 this.itemSize = itemSize; 50956 50957 return this; 50958 50959 } 50960 50961 setCount( count ) { 50962 50963 this.count = count; 50964 50965 return this; 50966 50967 } 50968 50969} 50970 50971class Raycaster { 50972 50973 constructor( origin, direction, near = 0, far = Infinity ) { 50974 50975 this.ray = new Ray( origin, direction ); 50976 // direction is assumed to be normalized (for accurate distance calculations) 50977 50978 this.near = near; 50979 this.far = far; 50980 this.camera = null; 50981 this.layers = new Layers(); 50982 50983 this.params = { 50984 Mesh: {}, 50985 Line: { threshold: 1 }, 50986 LOD: {}, 50987 Points: { threshold: 1 }, 50988 Sprite: {} 50989 }; 50990 50991 } 50992 50993 set( origin, direction ) { 50994 50995 // direction is assumed to be normalized (for accurate distance calculations) 50996 50997 this.ray.set( origin, direction ); 50998 50999 } 51000 51001 setFromCamera( coords, camera ) { 51002 51003 if ( camera.isPerspectiveCamera ) { 51004 51005 this.ray.origin.setFromMatrixPosition( camera.matrixWorld ); 51006 this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize(); 51007 this.camera = camera; 51008 51009 } else if ( camera.isOrthographicCamera ) { 51010 51011 this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera 51012 this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ); 51013 this.camera = camera; 51014 51015 } else { 51016 51017 console.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type ); 51018 51019 } 51020 51021 } 51022 51023 intersectObject( object, recursive = true, intersects = [] ) { 51024 51025 intersectObject( object, this, intersects, recursive ); 51026 51027 intersects.sort( ascSort ); 51028 51029 return intersects; 51030 51031 } 51032 51033 intersectObjects( objects, recursive = true, intersects = [] ) { 51034 51035 for ( let i = 0, l = objects.length; i < l; i ++ ) { 51036 51037 intersectObject( objects[ i ], this, intersects, recursive ); 51038 51039 } 51040 51041 intersects.sort( ascSort ); 51042 51043 return intersects; 51044 51045 } 51046 51047} 51048 51049function ascSort( a, b ) { 51050 51051 return a.distance - b.distance; 51052 51053} 51054 51055function intersectObject( object, raycaster, intersects, recursive ) { 51056 51057 if ( object.layers.test( raycaster.layers ) ) { 51058 51059 object.raycast( raycaster, intersects ); 51060 51061 } 51062 51063 if ( recursive === true ) { 51064 51065 const children = object.children; 51066 51067 for ( let i = 0, l = children.length; i < l; i ++ ) { 51068 51069 intersectObject( children[ i ], raycaster, intersects, true ); 51070 51071 } 51072 51073 } 51074 51075} 51076 51077/** 51078 * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system 51079 * 51080 * The polar angle (phi) is measured from the positive y-axis. The positive y-axis is up. 51081 * The azimuthal angle (theta) is measured from the positive z-axis. 51082 */ 51083 51084 51085class Spherical { 51086
vendor: 25,811 bytes, lines 51087-52296
51087 constructor( radius = 1, phi = 0, theta = 0 ) { 51088 51089 this.radius = radius; 51090 this.phi = phi; // polar angle 51091 this.theta = theta; // azimuthal angle 51092 51093 return this; 51094 51095 } 51096 51097 set( radius, phi, theta ) { 51098 51099 this.radius = radius; 51100 this.phi = phi; 51101 this.theta = theta; 51102 51103 return this; 51104 51105 } 51106 51107 copy( other ) { 51108 51109 this.radius = other.radius; 51110 this.phi = other.phi; 51111 this.theta = other.theta; 51112 51113 return this; 51114 51115 } 51116 51117 // restrict phi to be between EPS and PI-EPS 51118 makeSafe() { 51119 51120 const EPS = 0.000001; 51121 this.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) ); 51122 51123 return this; 51124 51125 } 51126 51127 setFromVector3( v ) { 51128 51129 return this.setFromCartesianCoords( v.x, v.y, v.z ); 51130 51131 } 51132 51133 setFromCartesianCoords( x, y, z ) { 51134 51135 this.radius = Math.sqrt( x * x + y * y + z * z ); 51136 51137 if ( this.radius === 0 ) { 51138 51139 this.theta = 0; 51140 this.phi = 0; 51141 51142 } else { 51143 51144 this.theta = Math.atan2( x, z ); 51145 this.phi = Math.acos( clamp( y / this.radius, - 1, 1 ) ); 51146 51147 } 51148 51149 return this; 51150 51151 } 51152 51153 clone() { 51154 51155 return new this.constructor().copy( this ); 51156 51157 } 51158 51159} 51160 51161/** 51162 * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system 51163 */ 51164 51165class Cylindrical { 51166 51167 constructor( radius = 1, theta = 0, y = 0 ) { 51168 51169 this.radius = radius; // distance from the origin to a point in the x-z plane 51170 this.theta = theta; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis 51171 this.y = y; // height above the x-z plane 51172 51173 return this; 51174 51175 } 51176 51177 set( radius, theta, y ) { 51178 51179 this.radius = radius; 51180 this.theta = theta; 51181 this.y = y; 51182 51183 return this; 51184 51185 } 51186 51187 copy( other ) { 51188 51189 this.radius = other.radius; 51190 this.theta = other.theta; 51191 this.y = other.y; 51192 51193 return this; 51194 51195 } 51196 51197 setFromVector3( v ) { 51198 51199 return this.setFromCartesianCoords( v.x, v.y, v.z ); 51200 51201 } 51202 51203 setFromCartesianCoords( x, y, z ) { 51204 51205 this.radius = Math.sqrt( x * x + z * z ); 51206 this.theta = Math.atan2( x, z ); 51207 this.y = y; 51208 51209 return this; 51210 51211 } 51212 51213 clone() { 51214 51215 return new this.constructor().copy( this ); 51216 51217 } 51218 51219} 51220 51221const _vector$4 = /*@__PURE__*/ new Vector2(); 51222 51223class Box2 { 51224 51225 constructor( min = new Vector2( + Infinity, + Infinity ), max = new Vector2( - Infinity, - Infinity ) ) { 51226 51227 this.isBox2 = true; 51228 51229 this.min = min; 51230 this.max = max; 51231 51232 } 51233 51234 set( min, max ) { 51235 51236 this.min.copy( min ); 51237 this.max.copy( max ); 51238 51239 return this; 51240 51241 } 51242 51243 setFromPoints( points ) { 51244 51245 this.makeEmpty(); 51246 51247 for ( let i = 0, il = points.length; i < il; i ++ ) { 51248 51249 this.expandByPoint( points[ i ] ); 51250 51251 } 51252 51253 return this; 51254 51255 } 51256 51257 setFromCenterAndSize( center, size ) { 51258 51259 const halfSize = _vector$4.copy( size ).multiplyScalar( 0.5 ); 51260 this.min.copy( center ).sub( halfSize ); 51261 this.max.copy( center ).add( halfSize ); 51262 51263 return this; 51264 51265 } 51266 51267 clone() { 51268 51269 return new this.constructor().copy( this ); 51270 51271 } 51272 51273 copy( box ) { 51274 51275 this.min.copy( box.min ); 51276 this.max.copy( box.max ); 51277 51278 return this; 51279 51280 } 51281 51282 makeEmpty() { 51283 51284 this.min.x = this.min.y = + Infinity; 51285 this.max.x = this.max.y = - Infinity; 51286 51287 return this; 51288 51289 } 51290 51291 isEmpty() { 51292 51293 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes 51294 51295 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); 51296 51297 } 51298 51299 getCenter( target ) { 51300 51301 return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); 51302 51303 } 51304 51305 getSize( target ) { 51306 51307 return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min ); 51308 51309 } 51310 51311 expandByPoint( point ) { 51312 51313 this.min.min( point ); 51314 this.max.max( point ); 51315 51316 return this; 51317 51318 } 51319 51320 expandByVector( vector ) { 51321 51322 this.min.sub( vector ); 51323 this.max.add( vector ); 51324 51325 return this; 51326 51327 } 51328 51329 expandByScalar( scalar ) { 51330 51331 this.min.addScalar( - scalar ); 51332 this.max.addScalar( scalar ); 51333 51334 return this; 51335 51336 } 51337 51338 containsPoint( point ) { 51339 51340 return point.x < this.min.x || point.x > this.max.x || 51341 point.y < this.min.y || point.y > this.max.y ? false : true; 51342 51343 } 51344 51345 containsBox( box ) { 51346 51347 return this.min.x <= box.min.x && box.max.x <= this.max.x && 51348 this.min.y <= box.min.y && box.max.y <= this.max.y; 51349 51350 } 51351 51352 getParameter( point, target ) { 51353 51354 // This can potentially have a divide by zero if the box 51355 // has a size dimension of 0. 51356 51357 return target.set( 51358 ( point.x - this.min.x ) / ( this.max.x - this.min.x ), 51359 ( point.y - this.min.y ) / ( this.max.y - this.min.y ) 51360 ); 51361 51362 } 51363 51364 intersectsBox( box ) { 51365 51366 // using 4 splitting planes to rule out intersections 51367 51368 return box.max.x < this.min.x || box.min.x > this.max.x || 51369 box.max.y < this.min.y || box.min.y > this.max.y ? false : true; 51370 51371 } 51372 51373 clampPoint( point, target ) { 51374 51375 return target.copy( point ).clamp( this.min, this.max ); 51376 51377 } 51378 51379 distanceToPoint( point ) { 51380 51381 return this.clampPoint( point, _vector$4 ).distanceTo( point ); 51382 51383 } 51384 51385 intersect( box ) { 51386 51387 this.min.max( box.min ); 51388 this.max.min( box.max ); 51389 51390 if ( this.isEmpty() ) this.makeEmpty(); 51391 51392 return this; 51393 51394 } 51395 51396 union( box ) { 51397 51398 this.min.min( box.min ); 51399 this.max.max( box.max ); 51400 51401 return this; 51402 51403 } 51404 51405 translate( offset ) { 51406 51407 this.min.add( offset ); 51408 this.max.add( offset ); 51409 51410 return this; 51411 51412 } 51413 51414 equals( box ) { 51415 51416 return box.min.equals( this.min ) && box.max.equals( this.max ); 51417 51418 } 51419 51420} 51421 51422const _startP = /*@__PURE__*/ new Vector3(); 51423const _startEnd = /*@__PURE__*/ new Vector3(); 51424 51425class Line3 { 51426 51427 constructor( start = new Vector3(), end = new Vector3() ) { 51428 51429 this.start = start; 51430 this.end = end; 51431 51432 } 51433 51434 set( start, end ) { 51435 51436 this.start.copy( start ); 51437 this.end.copy( end ); 51438 51439 return this; 51440 51441 } 51442 51443 copy( line ) { 51444 51445 this.start.copy( line.start ); 51446 this.end.copy( line.end ); 51447 51448 return this; 51449 51450 } 51451 51452 getCenter( target ) { 51453 51454 return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); 51455 51456 } 51457 51458 delta( target ) { 51459 51460 return target.subVectors( this.end, this.start ); 51461 51462 } 51463 51464 distanceSq() { 51465 51466 return this.start.distanceToSquared( this.end ); 51467 51468 } 51469 51470 distance() { 51471 51472 return this.start.distanceTo( this.end ); 51473 51474 } 51475 51476 at( t, target ) { 51477 51478 return this.delta( target ).multiplyScalar( t ).add( this.start ); 51479 51480 } 51481 51482 closestPointToPointParameter( point, clampToLine ) { 51483 51484 _startP.subVectors( point, this.start ); 51485 _startEnd.subVectors( this.end, this.start ); 51486 51487 const startEnd2 = _startEnd.dot( _startEnd ); 51488 const startEnd_startP = _startEnd.dot( _startP ); 51489 51490 let t = startEnd_startP / startEnd2; 51491 51492 if ( clampToLine ) { 51493 51494 t = clamp( t, 0, 1 ); 51495 51496 } 51497 51498 return t; 51499 51500 } 51501 51502 closestPointToPoint( point, clampToLine, target ) { 51503 51504 const t = this.closestPointToPointParameter( point, clampToLine ); 51505 51506 return this.delta( target ).multiplyScalar( t ).add( this.start ); 51507 51508 } 51509 51510 applyMatrix4( matrix ) { 51511 51512 this.start.applyMatrix4( matrix ); 51513 this.end.applyMatrix4( matrix ); 51514 51515 return this; 51516 51517 } 51518 51519 equals( line ) { 51520 51521 return line.start.equals( this.start ) && line.end.equals( this.end ); 51522 51523 } 51524 51525 clone() { 51526 51527 return new this.constructor().copy( this ); 51528 51529 } 51530 51531} 51532 51533const _vector$3 = /*@__PURE__*/ new Vector3(); 51534 51535class SpotLightHelper extends Object3D { 51536 51537 constructor( light, color ) { 51538 51539 super(); 51540 51541 this.light = light; 51542 51543 this.matrix = light.matrixWorld; 51544 this.matrixAutoUpdate = false; 51545 51546 this.color = color; 51547 51548 this.type = 'SpotLightHelper'; 51549 51550 const geometry = new BufferGeometry(); 51551 51552 const positions = [ 51553 0, 0, 0, 0, 0, 1, 51554 0, 0, 0, 1, 0, 1, 51555 0, 0, 0, - 1, 0, 1, 51556 0, 0, 0, 0, 1, 1, 51557 0, 0, 0, 0, - 1, 1 51558 ]; 51559 51560 for ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) { 51561 51562 const p1 = ( i / l ) * Math.PI * 2; 51563 const p2 = ( j / l ) * Math.PI * 2; 51564 51565 positions.push( 51566 Math.cos( p1 ), Math.sin( p1 ), 1, 51567 Math.cos( p2 ), Math.sin( p2 ), 1 51568 ); 51569 51570 } 51571 51572 geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); 51573 51574 const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); 51575 51576 this.cone = new LineSegments( geometry, material ); 51577 this.add( this.cone ); 51578 51579 this.update(); 51580 51581 } 51582 51583 dispose() { 51584 51585 this.cone.geometry.dispose(); 51586 this.cone.material.dispose(); 51587 51588 } 51589 51590 update() { 51591 51592 this.light.updateWorldMatrix( true, false ); 51593 this.light.target.updateWorldMatrix( true, false ); 51594 51595 const coneLength = this.light.distance ? this.light.distance : 1000; 51596 const coneWidth = coneLength * Math.tan( this.light.angle ); 51597 51598 this.cone.scale.set( coneWidth, coneWidth, coneLength ); 51599 51600 _vector$3.setFromMatrixPosition( this.light.target.matrixWorld ); 51601 51602 this.cone.lookAt( _vector$3 ); 51603 51604 if ( this.color !== undefined ) { 51605 51606 this.cone.material.color.set( this.color ); 51607 51608 } else { 51609 51610 this.cone.material.color.copy( this.light.color ); 51611 51612 } 51613 51614 } 51615 51616} 51617 51618const _vector$2 = /*@__PURE__*/ new Vector3(); 51619const _boneMatrix = /*@__PURE__*/ new Matrix4(); 51620const _matrixWorldInv = /*@__PURE__*/ new Matrix4(); 51621 51622 51623class SkeletonHelper extends LineSegments { 51624 51625 constructor( object ) { 51626 51627 const bones = getBoneList( object ); 51628 51629 const geometry = new BufferGeometry(); 51630 51631 const vertices = []; 51632 const colors = []; 51633 51634 const color1 = new Color( 0, 0, 1 ); 51635 const color2 = new Color( 0, 1, 0 ); 51636 51637 for ( let i = 0; i < bones.length; i ++ ) { 51638 51639 const bone = bones[ i ]; 51640 51641 if ( bone.parent && bone.parent.isBone ) { 51642 51643 vertices.push( 0, 0, 0 ); 51644 vertices.push( 0, 0, 0 ); 51645 colors.push( color1.r, color1.g, color1.b ); 51646 colors.push( color2.r, color2.g, color2.b ); 51647 51648 } 51649 51650 } 51651 51652 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 51653 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); 51654 51655 const material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } ); 51656 51657 super( geometry, material ); 51658 51659 this.isSkeletonHelper = true; 51660 51661 this.type = 'SkeletonHelper'; 51662 51663 this.root = object; 51664 this.bones = bones; 51665 51666 this.matrix = object.matrixWorld; 51667 this.matrixAutoUpdate = false; 51668 51669 } 51670 51671 updateMatrixWorld( force ) { 51672 51673 const bones = this.bones; 51674 51675 const geometry = this.geometry; 51676 const position = geometry.getAttribute( 'position' ); 51677 51678 _matrixWorldInv.copy( this.root.matrixWorld ).invert(); 51679 51680 for ( let i = 0, j = 0; i < bones.length; i ++ ) { 51681 51682 const bone = bones[ i ]; 51683 51684 if ( bone.parent && bone.parent.isBone ) { 51685 51686 _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld ); 51687 _vector$2.setFromMatrixPosition( _boneMatrix ); 51688 position.setXYZ( j, _vector$2.x, _vector$2.y, _vector$2.z ); 51689 51690 _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld ); 51691 _vector$2.setFromMatrixPosition( _boneMatrix ); 51692 position.setXYZ( j + 1, _vector$2.x, _vector$2.y, _vector$2.z ); 51693 51694 j += 2; 51695 51696 } 51697 51698 } 51699 51700 geometry.getAttribute( 'position' ).needsUpdate = true; 51701 51702 super.updateMatrixWorld( force ); 51703 51704 } 51705 51706 dispose() { 51707 51708 this.geometry.dispose(); 51709 this.material.dispose(); 51710 51711 } 51712 51713} 51714 51715 51716function getBoneList( object ) { 51717 51718 const boneList = []; 51719 51720 if ( object.isBone === true ) { 51721 51722 boneList.push( object ); 51723 51724 } 51725 51726 for ( let i = 0; i < object.children.length; i ++ ) { 51727 51728 boneList.push.apply( boneList, getBoneList( object.children[ i ] ) ); 51729 51730 } 51731 51732 return boneList; 51733 51734} 51735 51736class PointLightHelper extends Mesh { 51737 51738 constructor( light, sphereSize, color ) { 51739 51740 const geometry = new SphereGeometry( sphereSize, 4, 2 ); 51741 const material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); 51742 51743 super( geometry, material ); 51744 51745 this.light = light; 51746 51747 this.color = color; 51748 51749 this.type = 'PointLightHelper'; 51750 51751 this.matrix = this.light.matrixWorld; 51752 this.matrixAutoUpdate = false; 51753 51754 this.update(); 51755 51756 51757 /* 51758 // TODO: delete this comment? 51759 const distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); 51760 const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); 51761 51762 this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); 51763 this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); 51764 51765 const d = light.distance; 51766 51767 if ( d === 0.0 ) { 51768 51769 this.lightDistance.visible = false; 51770 51771 } else { 51772 51773 this.lightDistance.scale.set( d, d, d ); 51774 51775 } 51776 51777 this.add( this.lightDistance ); 51778 */ 51779 51780 } 51781 51782 dispose() { 51783 51784 this.geometry.dispose(); 51785 this.material.dispose(); 51786 51787 } 51788 51789 update() { 51790 51791 this.light.updateWorldMatrix( true, false ); 51792 51793 if ( this.color !== undefined ) { 51794 51795 this.material.color.set( this.color ); 51796 51797 } else { 51798 51799 this.material.color.copy( this.light.color ); 51800 51801 } 51802 51803 /* 51804 const d = this.light.distance; 51805 51806 if ( d === 0.0 ) { 51807 51808 this.lightDistance.visible = false; 51809 51810 } else { 51811 51812 this.lightDistance.visible = true; 51813 this.lightDistance.scale.set( d, d, d ); 51814 51815 } 51816 */ 51817 51818 } 51819 51820} 51821 51822const _vector$1 = /*@__PURE__*/ new Vector3(); 51823const _color1 = /*@__PURE__*/ new Color(); 51824const _color2 = /*@__PURE__*/ new Color(); 51825 51826class HemisphereLightHelper extends Object3D { 51827 51828 constructor( light, size, color ) { 51829 51830 super(); 51831 51832 this.light = light; 51833 51834 this.matrix = light.matrixWorld; 51835 this.matrixAutoUpdate = false; 51836 51837 this.color = color; 51838 51839 this.type = 'HemisphereLightHelper'; 51840 51841 const geometry = new OctahedronGeometry( size ); 51842 geometry.rotateY( Math.PI * 0.5 ); 51843 51844 this.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); 51845 if ( this.color === undefined ) this.material.vertexColors = true; 51846 51847 const position = geometry.getAttribute( 'position' ); 51848 const colors = new Float32Array( position.count * 3 ); 51849 51850 geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) ); 51851 51852 this.add( new Mesh( geometry, this.material ) ); 51853 51854 this.update(); 51855 51856 } 51857 51858 dispose() { 51859 51860 this.children[ 0 ].geometry.dispose(); 51861 this.children[ 0 ].material.dispose(); 51862 51863 } 51864 51865 update() { 51866 51867 const mesh = this.children[ 0 ]; 51868 51869 if ( this.color !== undefined ) { 51870 51871 this.material.color.set( this.color ); 51872 51873 } else { 51874 51875 const colors = mesh.geometry.getAttribute( 'color' ); 51876 51877 _color1.copy( this.light.color ); 51878 _color2.copy( this.light.groundColor ); 51879 51880 for ( let i = 0, l = colors.count; i < l; i ++ ) { 51881 51882 const color = ( i < ( l / 2 ) ) ? _color1 : _color2; 51883 51884 colors.setXYZ( i, color.r, color.g, color.b ); 51885 51886 } 51887 51888 colors.needsUpdate = true; 51889 51890 } 51891 51892 this.light.updateWorldMatrix( true, false ); 51893 51894 mesh.lookAt( _vector$1.setFromMatrixPosition( this.light.matrixWorld ).negate() ); 51895 51896 } 51897 51898} 51899 51900class GridHelper extends LineSegments { 51901 51902 constructor( size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888 ) { 51903 51904 color1 = new Color( color1 ); 51905 color2 = new Color( color2 ); 51906 51907 const center = divisions / 2; 51908 const step = size / divisions; 51909 const halfSize = size / 2; 51910 51911 const vertices = [], colors = []; 51912 51913 for ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) { 51914 51915 vertices.push( - halfSize, 0, k, halfSize, 0, k ); 51916 vertices.push( k, 0, - halfSize, k, 0, halfSize ); 51917 51918 const color = i === center ? color1 : color2; 51919 51920 color.toArray( colors, j ); j += 3; 51921 color.toArray( colors, j ); j += 3; 51922 color.toArray( colors, j ); j += 3; 51923 color.toArray( colors, j ); j += 3; 51924 51925 } 51926 51927 const geometry = new BufferGeometry(); 51928 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 51929 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); 51930 51931 const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); 51932 51933 super( geometry, material ); 51934 51935 this.type = 'GridHelper'; 51936 51937 } 51938 51939 dispose() { 51940 51941 this.geometry.dispose(); 51942 this.material.dispose(); 51943 51944 } 51945 51946} 51947 51948class PolarGridHelper extends LineSegments { 51949 51950 constructor( radius = 10, sectors = 16, rings = 8, divisions = 64, color1 = 0x444444, color2 = 0x888888 ) { 51951 51952 color1 = new Color( color1 ); 51953 color2 = new Color( color2 ); 51954 51955 const vertices = []; 51956 const colors = []; 51957 51958 // create the sectors 51959 51960 if ( sectors > 1 ) { 51961 51962 for ( let i = 0; i < sectors; i ++ ) { 51963 51964 const v = ( i / sectors ) * ( Math.PI * 2 ); 51965 51966 const x = Math.sin( v ) * radius; 51967 const z = Math.cos( v ) * radius; 51968 51969 vertices.push( 0, 0, 0 ); 51970 vertices.push( x, 0, z ); 51971 51972 const color = ( i & 1 ) ? color1 : color2; 51973 51974 colors.push( color.r, color.g, color.b ); 51975 colors.push( color.r, color.g, color.b ); 51976 51977 } 51978 51979 } 51980 51981 // create the rings 51982 51983 for ( let i = 0; i < rings; i ++ ) { 51984 51985 const color = ( i & 1 ) ? color1 : color2; 51986 51987 const r = radius - ( radius / rings * i ); 51988 51989 for ( let j = 0; j < divisions; j ++ ) { 51990 51991 // first vertex 51992 51993 let v = ( j / divisions ) * ( Math.PI * 2 ); 51994 51995 let x = Math.sin( v ) * r; 51996 let z = Math.cos( v ) * r; 51997 51998 vertices.push( x, 0, z ); 51999 colors.push( color.r, color.g, color.b ); 52000 52001 // second vertex 52002 52003 v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 ); 52004 52005 x = Math.sin( v ) * r; 52006 z = Math.cos( v ) * r; 52007 52008 vertices.push( x, 0, z ); 52009 colors.push( color.r, color.g, color.b ); 52010 52011 } 52012 52013 } 52014 52015 const geometry = new BufferGeometry(); 52016 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 52017 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); 52018 52019 const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); 52020 52021 super( geometry, material ); 52022 52023 this.type = 'PolarGridHelper'; 52024 52025 } 52026 52027 dispose() { 52028 52029 this.geometry.dispose(); 52030 this.material.dispose(); 52031 52032 } 52033 52034} 52035 52036const _v1 = /*@__PURE__*/ new Vector3(); 52037const _v2 = /*@__PURE__*/ new Vector3(); 52038const _v3 = /*@__PURE__*/ new Vector3(); 52039 52040class DirectionalLightHelper extends Object3D { 52041 52042 constructor( light, size, color ) { 52043 52044 super(); 52045 52046 this.light = light; 52047 52048 this.matrix = light.matrixWorld; 52049 this.matrixAutoUpdate = false; 52050 52051 this.color = color; 52052 52053 this.type = 'DirectionalLightHelper'; 52054 52055 if ( size === undefined ) size = 1; 52056 52057 let geometry = new BufferGeometry(); 52058 geometry.setAttribute( 'position', new Float32BufferAttribute( [ 52059 - size, size, 0, 52060 size, size, 0, 52061 size, - size, 0, 52062 - size, - size, 0, 52063 - size, size, 0 52064 ], 3 ) ); 52065 52066 const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); 52067 52068 this.lightPlane = new Line( geometry, material ); 52069 this.add( this.lightPlane ); 52070 52071 geometry = new BufferGeometry(); 52072 geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); 52073 52074 this.targetLine = new Line( geometry, material ); 52075 this.add( this.targetLine ); 52076 52077 this.update(); 52078 52079 } 52080 52081 dispose() { 52082 52083 this.lightPlane.geometry.dispose(); 52084 this.lightPlane.material.dispose(); 52085 this.targetLine.geometry.dispose(); 52086 this.targetLine.material.dispose(); 52087 52088 } 52089 52090 update() { 52091 52092 this.light.updateWorldMatrix( true, false ); 52093 this.light.target.updateWorldMatrix( true, false ); 52094 52095 _v1.setFromMatrixPosition( this.light.matrixWorld ); 52096 _v2.setFromMatrixPosition( this.light.target.matrixWorld ); 52097 _v3.subVectors( _v2, _v1 ); 52098 52099 this.lightPlane.lookAt( _v2 ); 52100 52101 if ( this.color !== undefined ) { 52102 52103 this.lightPlane.material.color.set( this.color ); 52104 this.targetLine.material.color.set( this.color ); 52105 52106 } else { 52107 52108 this.lightPlane.material.color.copy( this.light.color ); 52109 this.targetLine.material.color.copy( this.light.color ); 52110 52111 } 52112 52113 this.targetLine.lookAt( _v2 ); 52114 this.targetLine.scale.z = _v3.length(); 52115 52116 } 52117 52118} 52119 52120const _vector = /*@__PURE__*/ new Vector3(); 52121const _camera = /*@__PURE__*/ new Camera(); 52122 52123/** 52124 * - shows frustum, line of sight and up of the camera 52125 * - suitable for fast updates 52126 * - based on frustum visualization in lightgl.js shadowmap example 52127 * https://github.com/evanw/lightgl.js/blob/master/tests/shadowmap.html 52128 */ 52129 52130class CameraHelper extends LineSegments { 52131 52132 constructor( camera ) { 52133 52134 const geometry = new BufferGeometry(); 52135 const material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } ); 52136 52137 const vertices = []; 52138 const colors = []; 52139 52140 const pointMap = {}; 52141 52142 // near 52143 52144 addLine( 'n1', 'n2' ); 52145 addLine( 'n2', 'n4' ); 52146 addLine( 'n4', 'n3' ); 52147 addLine( 'n3', 'n1' ); 52148 52149 // far 52150 52151 addLine( 'f1', 'f2' ); 52152 addLine( 'f2', 'f4' ); 52153 addLine( 'f4', 'f3' ); 52154 addLine( 'f3', 'f1' ); 52155 52156 // sides 52157 52158 addLine( 'n1', 'f1' ); 52159 addLine( 'n2', 'f2' ); 52160 addLine( 'n3', 'f3' ); 52161 addLine( 'n4', 'f4' ); 52162 52163 // cone 52164 52165 addLine( 'p', 'n1' ); 52166 addLine( 'p', 'n2' ); 52167 addLine( 'p', 'n3' ); 52168 addLine( 'p', 'n4' ); 52169 52170 // up 52171 52172 addLine( 'u1', 'u2' ); 52173 addLine( 'u2', 'u3' ); 52174 addLine( 'u3', 'u1' ); 52175 52176 // target 52177 52178 addLine( 'c', 't' ); 52179 addLine( 'p', 'c' ); 52180 52181 // cross 52182 52183 addLine( 'cn1', 'cn2' ); 52184 addLine( 'cn3', 'cn4' ); 52185 52186 addLine( 'cf1', 'cf2' ); 52187 addLine( 'cf3', 'cf4' ); 52188 52189 function addLine( a, b ) { 52190 52191 addPoint( a ); 52192 addPoint( b ); 52193 52194 } 52195 52196 function addPoint( id ) { 52197 52198 vertices.push( 0, 0, 0 ); 52199 colors.push( 0, 0, 0 ); 52200 52201 if ( pointMap[ id ] === undefined ) { 52202 52203 pointMap[ id ] = []; 52204 52205 } 52206 52207 pointMap[ id ].push( ( vertices.length / 3 ) - 1 ); 52208 52209 } 52210 52211 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 52212 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); 52213 52214 super( geometry, material ); 52215 52216 this.type = 'CameraHelper'; 52217 52218 this.camera = camera; 52219 if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix(); 52220 52221 this.matrix = camera.matrixWorld; 52222 this.matrixAutoUpdate = false; 52223 52224 this.pointMap = pointMap; 52225 52226 this.update(); 52227 52228 // colors 52229 52230 const colorFrustum = new Color( 0xffaa00 ); 52231 const colorCone = new Color( 0xff0000 ); 52232 const colorUp = new Color( 0x00aaff ); 52233 const colorTarget = new Color( 0xffffff ); 52234 const colorCross = new Color( 0x333333 ); 52235 52236 this.setColors( colorFrustum, colorCone, colorUp, colorTarget, colorCross ); 52237 52238 } 52239 52240 setColors( frustum, cone, up, target, cross ) { 52241 52242 const geometry = this.geometry; 52243 52244 const colorAttribute = geometry.getAttribute( 'color' ); 52245 52246 // near 52247 52248 colorAttribute.setXYZ( 0, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 1, frustum.r, frustum.g, frustum.b ); // n1, n2 52249 colorAttribute.setXYZ( 2, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 3, frustum.r, frustum.g, frustum.b ); // n2, n4 52250 colorAttribute.setXYZ( 4, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 5, frustum.r, frustum.g, frustum.b ); // n4, n3 52251 colorAttribute.setXYZ( 6, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 7, frustum.r, frustum.g, frustum.b ); // n3, n1 52252 52253 // far 52254 52255 colorAttribute.setXYZ( 8, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 9, frustum.r, frustum.g, frustum.b ); // f1, f2 52256 colorAttribute.setXYZ( 10, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 11, frustum.r, frustum.g, frustum.b ); // f2, f4 52257 colorAttribute.setXYZ( 12, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 13, frustum.r, frustum.g, frustum.b ); // f4, f3 52258 colorAttribute.setXYZ( 14, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 15, frustum.r, frustum.g, frustum.b ); // f3, f1 52259 52260 // sides 52261 52262 colorAttribute.setXYZ( 16, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 17, frustum.r, frustum.g, frustum.b ); // n1, f1 52263 colorAttribute.setXYZ( 18, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 19, frustum.r, frustum.g, frustum.b ); // n2, f2 52264 colorAttribute.setXYZ( 20, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 21, frustum.r, frustum.g, frustum.b ); // n3, f3 52265 colorAttribute.setXYZ( 22, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 23, frustum.r, frustum.g, frustum.b ); // n4, f4 52266 52267 // cone 52268 52269 colorAttribute.setXYZ( 24, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 25, cone.r, cone.g, cone.b ); // p, n1 52270 colorAttribute.setXYZ( 26, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 27, cone.r, cone.g, cone.b ); // p, n2 52271 colorAttribute.setXYZ( 28, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 29, cone.r, cone.g, cone.b ); // p, n3 52272 colorAttribute.setXYZ( 30, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 31, cone.r, cone.g, cone.b ); // p, n4 52273 52274 // up 52275 52276 colorAttribute.setXYZ( 32, up.r, up.g, up.b ); colorAttribute.setXYZ( 33, up.r, up.g, up.b ); // u1, u2 52277 colorAttribute.setXYZ( 34, up.r, up.g, up.b ); colorAttribute.setXYZ( 35, up.r, up.g, up.b ); // u2, u3 52278 colorAttribute.setXYZ( 36, up.r, up.g, up.b ); colorAttribute.setXYZ( 37, up.r, up.g, up.b ); // u3, u1 52279 52280 // target 52281 52282 colorAttribute.setXYZ( 38, target.r, target.g, target.b ); colorAttribute.setXYZ( 39, target.r, target.g, target.b ); // c, t 52283 colorAttribute.setXYZ( 40, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 41, cross.r, cross.g, cross.b ); // p, c 52284 52285 // cross 52286 52287 colorAttribute.setXYZ( 42, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 43, cross.r, cross.g, cross.b ); // cn1, cn2 52288 colorAttribute.setXYZ( 44, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 45, cross.r, cross.g, cross.b ); // cn3, cn4 52289 52290 colorAttribute.setXYZ( 46, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 47, cross.r, cross.g, cross.b ); // cf1, cf2 52291 colorAttribute.setXYZ( 48, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 49, cross.r, cross.g, cross.b ); // cf3, cf4 52292 52293 colorAttribute.needsUpdate = true; 52294 52295 } 52296
vendor: 20,967 bytes, lines 52297-53057
52297 update() { 52298 52299 const geometry = this.geometry; 52300 const pointMap = this.pointMap; 52301 52302 const w = 1, h = 1; 52303 52304 // we need just camera projection matrix inverse 52305 // world matrix must be identity 52306 52307 _camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse ); 52308 52309 // center / target 52310 52311 setPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 ); 52312 setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 ); 52313 52314 // near 52315 52316 setPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 ); 52317 setPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 ); 52318 setPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 ); 52319 setPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 ); 52320 52321 // far 52322 52323 setPoint( 'f1', pointMap, geometry, _camera, - w, - h, 1 ); 52324 setPoint( 'f2', pointMap, geometry, _camera, w, - h, 1 ); 52325 setPoint( 'f3', pointMap, geometry, _camera, - w, h, 1 ); 52326 setPoint( 'f4', pointMap, geometry, _camera, w, h, 1 ); 52327 52328 // up 52329 52330 setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 ); 52331 setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 ); 52332 setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 ); 52333 52334 // cross 52335 52336 setPoint( 'cf1', pointMap, geometry, _camera, - w, 0, 1 ); 52337 setPoint( 'cf2', pointMap, geometry, _camera, w, 0, 1 ); 52338 setPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 ); 52339 setPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 ); 52340 52341 setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 ); 52342 setPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 ); 52343 setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 ); 52344 setPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 ); 52345 52346 geometry.getAttribute( 'position' ).needsUpdate = true; 52347 52348 } 52349 52350 dispose() { 52351 52352 this.geometry.dispose(); 52353 this.material.dispose(); 52354 52355 } 52356 52357} 52358 52359 52360function setPoint( point, pointMap, geometry, camera, x, y, z ) { 52361 52362 _vector.set( x, y, z ).unproject( camera ); 52363 52364 const points = pointMap[ point ]; 52365 52366 if ( points !== undefined ) { 52367 52368 const position = geometry.getAttribute( 'position' ); 52369 52370 for ( let i = 0, l = points.length; i < l; i ++ ) { 52371 52372 position.setXYZ( points[ i ], _vector.x, _vector.y, _vector.z ); 52373 52374 } 52375 52376 } 52377 52378} 52379 52380const _box = /*@__PURE__*/ new Box3(); 52381 52382class BoxHelper extends LineSegments { 52383 52384 constructor( object, color = 0xffff00 ) { 52385 52386 const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); 52387 const positions = new Float32Array( 8 * 3 ); 52388 52389 const geometry = new BufferGeometry(); 52390 geometry.setIndex( new BufferAttribute( indices, 1 ) ); 52391 geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) ); 52392 52393 super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); 52394 52395 this.object = object; 52396 this.type = 'BoxHelper'; 52397 52398 this.matrixAutoUpdate = false; 52399 52400 this.update(); 52401 52402 } 52403 52404 update( object ) { 52405 52406 if ( object !== undefined ) { 52407 52408 console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' ); 52409 52410 } 52411 52412 if ( this.object !== undefined ) { 52413 52414 _box.setFromObject( this.object ); 52415 52416 } 52417 52418 if ( _box.isEmpty() ) return; 52419 52420 const min = _box.min; 52421 const max = _box.max; 52422 52423 /* 52424 5____4 52425 1/___0/| 52426 | 6__|_7 52427 2/___3/ 52428 52429 0: max.x, max.y, max.z 52430 1: min.x, max.y, max.z 52431 2: min.x, min.y, max.z 52432 3: max.x, min.y, max.z 52433 4: max.x, max.y, min.z 52434 5: min.x, max.y, min.z 52435 6: min.x, min.y, min.z 52436 7: max.x, min.y, min.z 52437 */ 52438 52439 const position = this.geometry.attributes.position; 52440 const array = position.array; 52441 52442 array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z; 52443 array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z; 52444 array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z; 52445 array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z; 52446 array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z; 52447 array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z; 52448 array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z; 52449 array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z; 52450 52451 position.needsUpdate = true; 52452 52453 this.geometry.computeBoundingSphere(); 52454 52455 } 52456 52457 setFromObject( object ) { 52458 52459 this.object = object; 52460 this.update(); 52461 52462 return this; 52463 52464 } 52465 52466 copy( source, recursive ) { 52467 52468 super.copy( source, recursive ); 52469 52470 this.object = source.object; 52471 52472 return this; 52473 52474 } 52475 52476 dispose() { 52477 52478 this.geometry.dispose(); 52479 this.material.dispose(); 52480 52481 } 52482 52483} 52484 52485class Box3Helper extends LineSegments { 52486 52487 constructor( box, color = 0xffff00 ) { 52488 52489 const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); 52490 52491 const positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ]; 52492 52493 const geometry = new BufferGeometry(); 52494 52495 geometry.setIndex( new BufferAttribute( indices, 1 ) ); 52496 52497 geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); 52498 52499 super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); 52500 52501 this.box = box; 52502 52503 this.type = 'Box3Helper'; 52504 52505 this.geometry.computeBoundingSphere(); 52506 52507 } 52508 52509 updateMatrixWorld( force ) { 52510 52511 const box = this.box; 52512 52513 if ( box.isEmpty() ) return; 52514 52515 box.getCenter( this.position ); 52516 52517 box.getSize( this.scale ); 52518 52519 this.scale.multiplyScalar( 0.5 ); 52520 52521 super.updateMatrixWorld( force ); 52522 52523 } 52524 52525 dispose() { 52526 52527 this.geometry.dispose(); 52528 this.material.dispose(); 52529 52530 } 52531 52532} 52533 52534class PlaneHelper extends Line { 52535 52536 constructor( plane, size = 1, hex = 0xffff00 ) { 52537 52538 const color = hex; 52539 52540 const positions = [ 1, - 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, - 1, 0, 1, 1, 0 ]; 52541 52542 const geometry = new BufferGeometry(); 52543 geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); 52544 geometry.computeBoundingSphere(); 52545 52546 super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); 52547 52548 this.type = 'PlaneHelper'; 52549 52550 this.plane = plane; 52551 52552 this.size = size; 52553 52554 const positions2 = [ 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, - 1, 0 ]; 52555 52556 const geometry2 = new BufferGeometry(); 52557 geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) ); 52558 geometry2.computeBoundingSphere(); 52559 52560 this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) ); 52561 52562 } 52563 52564 updateMatrixWorld( force ) { 52565 52566 this.position.set( 0, 0, 0 ); 52567 52568 this.scale.set( 0.5 * this.size, 0.5 * this.size, 1 ); 52569 52570 this.lookAt( this.plane.normal ); 52571 52572 this.translateZ( - this.plane.constant ); 52573 52574 super.updateMatrixWorld( force ); 52575 52576 } 52577 52578 dispose() { 52579 52580 this.geometry.dispose(); 52581 this.material.dispose(); 52582 this.children[ 0 ].geometry.dispose(); 52583 this.children[ 0 ].material.dispose(); 52584 52585 } 52586 52587} 52588 52589const _axis = /*@__PURE__*/ new Vector3(); 52590let _lineGeometry, _coneGeometry; 52591 52592class ArrowHelper extends Object3D { 52593 52594 // dir is assumed to be normalized 52595 52596 constructor( dir = new Vector3( 0, 0, 1 ), origin = new Vector3( 0, 0, 0 ), length = 1, color = 0xffff00, headLength = length * 0.2, headWidth = headLength * 0.2 ) { 52597 52598 super(); 52599 52600 this.type = 'ArrowHelper'; 52601 52602 if ( _lineGeometry === undefined ) { 52603 52604 _lineGeometry = new BufferGeometry(); 52605 _lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); 52606 52607 _coneGeometry = new CylinderGeometry( 0, 0.5, 1, 5, 1 ); 52608 _coneGeometry.translate( 0, - 0.5, 0 ); 52609 52610 } 52611 52612 this.position.copy( origin ); 52613 52614 this.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); 52615 this.line.matrixAutoUpdate = false; 52616 this.add( this.line ); 52617 52618 this.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) ); 52619 this.cone.matrixAutoUpdate = false; 52620 this.add( this.cone ); 52621 52622 this.setDirection( dir ); 52623 this.setLength( length, headLength, headWidth ); 52624 52625 } 52626 52627 setDirection( dir ) { 52628 52629 // dir is assumed to be normalized 52630 52631 if ( dir.y > 0.99999 ) { 52632 52633 this.quaternion.set( 0, 0, 0, 1 ); 52634 52635 } else if ( dir.y < - 0.99999 ) { 52636 52637 this.quaternion.set( 1, 0, 0, 0 ); 52638 52639 } else { 52640 52641 _axis.set( dir.z, 0, - dir.x ).normalize(); 52642 52643 const radians = Math.acos( dir.y ); 52644 52645 this.quaternion.setFromAxisAngle( _axis, radians ); 52646 52647 } 52648 52649 } 52650 52651 setLength( length, headLength = length * 0.2, headWidth = headLength * 0.2 ) { 52652 52653 this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458 52654 this.line.updateMatrix(); 52655 52656 this.cone.scale.set( headWidth, headLength, headWidth ); 52657 this.cone.position.y = length; 52658 this.cone.updateMatrix(); 52659 52660 } 52661 52662 setColor( color ) { 52663 52664 this.line.material.color.set( color ); 52665 this.cone.material.color.set( color ); 52666 52667 } 52668 52669 copy( source ) { 52670 52671 super.copy( source, false ); 52672 52673 this.line.copy( source.line ); 52674 this.cone.copy( source.cone ); 52675 52676 return this; 52677 52678 } 52679 52680 dispose() { 52681 52682 this.line.geometry.dispose(); 52683 this.line.material.dispose(); 52684 this.cone.geometry.dispose(); 52685 this.cone.material.dispose(); 52686 52687 } 52688 52689} 52690 52691class AxesHelper extends LineSegments { 52692 52693 constructor( size = 1 ) { 52694 52695 const vertices = [ 52696 0, 0, 0, size, 0, 0, 52697 0, 0, 0, 0, size, 0, 52698 0, 0, 0, 0, 0, size 52699 ]; 52700 52701 const colors = [ 52702 1, 0, 0, 1, 0.6, 0, 52703 0, 1, 0, 0.6, 1, 0, 52704 0, 0, 1, 0, 0.6, 1 52705 ]; 52706 52707 const geometry = new BufferGeometry(); 52708 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 52709 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); 52710 52711 const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); 52712 52713 super( geometry, material ); 52714 52715 this.type = 'AxesHelper'; 52716 52717 } 52718 52719 setColors( xAxisColor, yAxisColor, zAxisColor ) { 52720 52721 const color = new Color(); 52722 const array = this.geometry.attributes.color.array; 52723 52724 color.set( xAxisColor ); 52725 color.toArray( array, 0 ); 52726 color.toArray( array, 3 ); 52727 52728 color.set( yAxisColor ); 52729 color.toArray( array, 6 ); 52730 color.toArray( array, 9 ); 52731 52732 color.set( zAxisColor ); 52733 color.toArray( array, 12 ); 52734 color.toArray( array, 15 ); 52735 52736 this.geometry.attributes.color.needsUpdate = true; 52737 52738 return this; 52739 52740 } 52741 52742 dispose() { 52743 52744 this.geometry.dispose(); 52745 this.material.dispose(); 52746 52747 } 52748 52749} 52750 52751class ShapePath { 52752 52753 constructor() { 52754 52755 this.type = 'ShapePath'; 52756 52757 this.color = new Color(); 52758 52759 this.subPaths = []; 52760 this.currentPath = null; 52761 52762 } 52763 52764 moveTo( x, y ) { 52765 52766 this.currentPath = new Path(); 52767 this.subPaths.push( this.currentPath ); 52768 this.currentPath.moveTo( x, y ); 52769 52770 return this; 52771 52772 } 52773 52774 lineTo( x, y ) { 52775 52776 this.currentPath.lineTo( x, y ); 52777 52778 return this; 52779 52780 } 52781 52782 quadraticCurveTo( aCPx, aCPy, aX, aY ) { 52783 52784 this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY ); 52785 52786 return this; 52787 52788 } 52789 52790 bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { 52791 52792 this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ); 52793 52794 return this; 52795 52796 } 52797 52798 splineThru( pts ) { 52799 52800 this.currentPath.splineThru( pts ); 52801 52802 return this; 52803 52804 } 52805 52806 toShapes( isCCW ) { 52807 52808 function toShapesNoHoles( inSubpaths ) { 52809 52810 const shapes = []; 52811 52812 for ( let i = 0, l = inSubpaths.length; i < l; i ++ ) { 52813 52814 const tmpPath = inSubpaths[ i ]; 52815 52816 const tmpShape = new Shape(); 52817 tmpShape.curves = tmpPath.curves; 52818 52819 shapes.push( tmpShape ); 52820 52821 } 52822 52823 return shapes; 52824 52825 } 52826 52827 function isPointInsidePolygon( inPt, inPolygon ) { 52828 52829 const polyLen = inPolygon.length; 52830 52831 // inPt on polygon contour => immediate success or 52832 // toggling of inside/outside at every single! intersection point of an edge 52833 // with the horizontal line through inPt, left of inPt 52834 // not counting lowerY endpoints of edges and whole edges on that line 52835 let inside = false; 52836 for ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { 52837 52838 let edgeLowPt = inPolygon[ p ]; 52839 let edgeHighPt = inPolygon[ q ]; 52840 52841 let edgeDx = edgeHighPt.x - edgeLowPt.x; 52842 let edgeDy = edgeHighPt.y - edgeLowPt.y; 52843 52844 if ( Math.abs( edgeDy ) > Number.EPSILON ) { 52845 52846 // not parallel 52847 if ( edgeDy < 0 ) { 52848 52849 edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; 52850 edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; 52851 52852 } 52853 52854 if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; 52855 52856 if ( inPt.y === edgeLowPt.y ) { 52857 52858 if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ? 52859 // continue; // no intersection or edgeLowPt => doesn't count !!! 52860 52861 } else { 52862 52863 const perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y ); 52864 if ( perpEdge === 0 ) return true; // inPt is on contour ? 52865 if ( perpEdge < 0 ) continue; 52866 inside = ! inside; // true intersection left of inPt 52867 52868 } 52869 52870 } else { 52871 52872 // parallel or collinear 52873 if ( inPt.y !== edgeLowPt.y ) continue; // parallel 52874 // edge lies on the same horizontal line as inPt 52875 if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) || 52876 ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour ! 52877 // continue; 52878 52879 } 52880 52881 } 52882 52883 return inside; 52884 52885 } 52886 52887 const isClockWise = ShapeUtils.isClockWise; 52888 52889 const subPaths = this.subPaths; 52890 if ( subPaths.length === 0 ) return []; 52891 52892 let solid, tmpPath, tmpShape; 52893 const shapes = []; 52894 52895 if ( subPaths.length === 1 ) { 52896 52897 tmpPath = subPaths[ 0 ]; 52898 tmpShape = new Shape(); 52899 tmpShape.curves = tmpPath.curves; 52900 shapes.push( tmpShape ); 52901 return shapes; 52902 52903 } 52904 52905 let holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() ); 52906 holesFirst = isCCW ? ! holesFirst : holesFirst; 52907 52908 // console.log("Holes first", holesFirst); 52909 52910 const betterShapeHoles = []; 52911 const newShapes = []; 52912 let newShapeHoles = []; 52913 let mainIdx = 0; 52914 let tmpPoints; 52915 52916 newShapes[ mainIdx ] = undefined; 52917 newShapeHoles[ mainIdx ] = []; 52918 52919 for ( let i = 0, l = subPaths.length; i < l; i ++ ) { 52920 52921 tmpPath = subPaths[ i ]; 52922 tmpPoints = tmpPath.getPoints(); 52923 solid = isClockWise( tmpPoints ); 52924 solid = isCCW ? ! solid : solid; 52925 52926 if ( solid ) { 52927 52928 if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++; 52929 52930 newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints }; 52931 newShapes[ mainIdx ].s.curves = tmpPath.curves; 52932 52933 if ( holesFirst ) mainIdx ++; 52934 newShapeHoles[ mainIdx ] = []; 52935 52936 //console.log('cw', i); 52937 52938 } else { 52939 52940 newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } ); 52941 52942 //console.log('ccw', i); 52943 52944 } 52945 52946 } 52947 52948 // only Holes? -> probably all Shapes with wrong orientation 52949 if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths ); 52950 52951 52952 if ( newShapes.length > 1 ) { 52953 52954 let ambiguous = false; 52955 let toChange = 0; 52956 52957 for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { 52958 52959 betterShapeHoles[ sIdx ] = []; 52960 52961 } 52962 52963 for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { 52964 52965 const sho = newShapeHoles[ sIdx ]; 52966 52967 for ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) { 52968 52969 const ho = sho[ hIdx ]; 52970 let hole_unassigned = true; 52971 52972 for ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) { 52973 52974 if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) { 52975 52976 if ( sIdx !== s2Idx ) toChange ++; 52977 52978 if ( hole_unassigned ) { 52979 52980 hole_unassigned = false; 52981 betterShapeHoles[ s2Idx ].push( ho ); 52982 52983 } else { 52984 52985 ambiguous = true; 52986 52987 } 52988 52989 } 52990 52991 } 52992 52993 if ( hole_unassigned ) { 52994 52995 betterShapeHoles[ sIdx ].push( ho ); 52996 52997 } 52998 52999 } 53000 53001 } 53002 53003 if ( toChange > 0 && ambiguous === false ) { 53004 53005 newShapeHoles = betterShapeHoles; 53006 53007 } 53008 53009 } 53010 53011 let tmpHoles; 53012 53013 for ( let i = 0, il = newShapes.length; i < il; i ++ ) { 53014 53015 tmpShape = newShapes[ i ].s; 53016 shapes.push( tmpShape ); 53017 tmpHoles = newShapeHoles[ i ]; 53018 53019 for ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) { 53020 53021 tmpShape.holes.push( tmpHoles[ j ].h ); 53022 53023 } 53024 53025 } 53026 53027 //console.log("shape", shapes); 53028 53029 return shapes; 53030 53031 } 53032 53033} 53034 53035if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { 53036 53037 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: { 53038 revision: REVISION, 53039 } } ) ); 53040 53041} 53042 53043if ( typeof window !== 'undefined' ) { 53044 53045 if ( window.__THREE__ ) { 53046 53047 console.warn( 'WARNING: Multiple instances of Three.js being imported.' ); 53048 53049 } else { 53050 53051 window.__THREE__ = REVISION; 53052 53053 } 53054 53055} 53056 53057export { ACESFilmicToneMapping, AddEquation, AddOperation, AdditiveAnimationBlendMode, AdditiveBlending, AgXToneMapping, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AmbientLight, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrayCamera, ArrowHelper, AttachedBindMode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BackSide, BasicDepthPacking, BasicShadowMap, BatchedMesh, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxGeometry, BoxHelper, BufferAttribute, BufferGeometry, BufferGeometryLoader, ByteType, Cache, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CineonToneMapping, CircleGeometry, ClampToEdgeWrapping, Clock, Color, ColorKeyframeTrack, ColorManagement, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ConeGeometry, ConstantAlphaFactor, ConstantColorFactor, CubeCamera, CubeReflectionMapping, CubeRefractionMapping, CubeTexture, CubeTextureLoader, CubeUVReflectionMapping, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceBack, CullFaceFront, CullFaceFrontBack, CullFaceNone, Curve, CurvePath, CustomBlending, CustomToneMapping, CylinderGeometry, Cylindrical, Data3DTexture, DataArrayTexture, DataTexture, DataTextureLoader, DataUtils, DecrementStencilOp, DecrementWrapStencilOp, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DepthTexture, DetachedBindMode, DirectionalLight, DirectionalLightHelper, DiscreteInterpolant, DisplayP3ColorSpace, DodecahedronGeometry, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicCopyUsage, DynamicDrawUsage, DynamicReadUsage, EdgesGeometry, EllipseCurve, EqualCompare, EqualDepth, EqualStencilFunc, EquirectangularReflectionMapping, EquirectangularRefractionMapping, Euler, EventDispatcher, ExtrudeGeometry, FileLoader, Float16BufferAttribute, Float32BufferAttribute, Float64BufferAttribute, FloatType, Fog, FogExp2, FramebufferTexture, FrontSide, Frustum, GLBufferAttribute, GLSL1, GLSL3, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, GridHelper, Group, HalfFloatType, HemisphereLight, HemisphereLightHelper, IcosahedronGeometry, ImageBitmapLoader, ImageLoader, ImageUtils, IncrementStencilOp, IncrementWrapStencilOp, InstancedBufferAttribute, InstancedBufferGeometry, InstancedInterleavedBuffer, InstancedMesh, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, IntType, InterleavedBuffer, InterleavedBufferAttribute, Interpolant, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InvertStencilOp, KeepStencilOp, KeyframeTrack, LOD, LatheGeometry, Layers, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, Light, LightProbe, Line, Line3, LineBasicMaterial, LineCurve, LineCurve3, LineDashedMaterial, LineLoop, LineSegments, LinearDisplayP3ColorSpace, LinearEncoding, LinearFilter, LinearInterpolant, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping, LinearTransfer, Loader, LoaderUtils, LoadingManager, LoopOnce, LoopPingPong, LoopRepeat, LuminanceAlphaFormat, LuminanceFormat, MOUSE, Material, MaterialLoader, MathUtils, Matrix3, Matrix4, MaxEquation, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshDistanceMaterial, MeshLambertMaterial, MeshMatcapMaterial, MeshNormalMaterial, MeshPhongMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshToonMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeverCompare, NeverDepth, NeverStencilFunc, NoBlending, NoColorSpace, NoToneMapping, NormalAnimationBlendMode, NormalBlending, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, NumberKeyframeTrack, Object3D, ObjectLoader, ObjectSpaceNormalMap, OctahedronGeometry, OneFactor, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, Orthogra
53057phicCamera, P3Primaries, PCFShadowMap, PCFSoftShadowMap, PMREMGenerator, Path, PerspectiveCamera, Plane, PlaneGeometry, PlaneHelper, PointLight, PointLightHelper, Points, PointsMaterial, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, Quaternion, QuaternionKeyframeTrack, QuaternionLinearInterpolant, RED_GREEN_RGTC2_Format, RED_RGTC1_Format, REVISION, RGBADepthPacking, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, RawShaderMaterial, Ray, Raycaster, Rec709Primaries, RectAreaLight, RedFormat, RedIntegerFormat, ReinhardToneMapping, RenderTarget, RepeatWrapping, ReplaceStencilOp, ReverseSubtractEquation, RingGeometry, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SRGBColorSpace, SRGBTransfer, Scene, ShaderChunk, ShaderLib, ShaderMaterial, ShadowMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, ShortType, Skeleton, SkeletonHelper, SkinnedMesh, Source, Sphere, SphereGeometry, Spherical, SphericalHarmonics3, SplineCurve, SpotLight, SpotLightHelper, Sprite, SpriteMaterial, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StaticCopyUsage, StaticDrawUsage, StaticReadUsage, StereoCamera, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, SubtractEquation, SubtractiveBlending, TOUCH, TangentSpaceNormalMap, TetrahedronGeometry, Texture, TextureLoader, TorusGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry, TwoPassDoubleSide, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsGroup, UniformsLib, UniformsUtils, UnsignedByteType, UnsignedInt248Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VSMShadowMap, Vector2, Vector3, Vector4, VectorKeyframeTrack, VideoTexture, WebGL1Renderer, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGLCoordinateSystem, WebGLCubeRenderTarget, WebGLMultipleRenderTargets, WebGLRenderTarget, WebGLRenderer, WebGLUtils, WebGPUCoordinateSystem, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroFactor, ZeroSlopeEnding, ZeroStencilOp, _SRGBAFormat, createCanvasElement, sRGBEncoding };
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.