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,093 bytes, lines 166-410
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);
vendor: 6,188 bytes, lines 411-835
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 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: 63,929 bytes, lines 836-4475
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], 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 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 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 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,544 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,510 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,528 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: 4,268 bytes, lines 5451-5628
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.
vendor: 4,218 bytes, lines 5629-5841
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: 4,722 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: 35,895 bytes, lines 6108-7968
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 const scaleXSq = te[0] * te[0] + te[1] * te[1] + te[2] * te[2]; 6430 const scaleYSq = te[4] * te[4] + te[5] * te[5] + te[6] * te[6]; 6431 const scaleZSq = te[8] * te[8] + te[9] * te[9] + te[10] * te[10]; 6432 6433 return Math.sqrt(Math.max(scaleXSq, scaleYSq, scaleZSq)); 6434 6435 } 6436 6437 makeTranslation(x, y, z) { 6438 6439 if (x.isVector3) { 6440 6441 this.set( 6442 6443 1, 0, 0, x.x, 6444 0, 1, 0, x.y, 6445 0, 0, 1, x.z, 6446 0, 0, 0, 1 6447 6448 ); 6449 6450 } else { 6451 6452 this.set( 6453 6454 1, 0, 0, x, 6455 0, 1, 0, y, 6456 0, 0, 1, z, 6457 0, 0, 0, 1 6458 6459 ); 6460 6461 } 6462 6463 return this; 6464 6465 } 6466 6467 makeRotationX(theta) { 6468 6469 const c = Math.cos(theta), s = Math.sin(theta); 6470 6471 this.set( 6472 6473 1, 0, 0, 0, 6474 0, c, - s, 0, 6475 0, s, c, 0, 6476 0, 0, 0, 1 6477 6478 ); 6479 6480 return this; 6481 6482 } 6483 6484 makeRotationY(theta) { 6485 6486 const c = Math.cos(theta), s = Math.sin(theta); 6487 6488 this.set( 6489 6490 c, 0, s, 0, 6491 0, 1, 0, 0, 6492 - s, 0, c, 0, 6493 0, 0, 0, 1 6494 6495 ); 6496 6497 return this; 6498 6499 } 6500 6501 makeRotationZ(theta) { 6502 6503 const c = Math.cos(theta), s = Math.sin(theta); 6504 6505 this.set( 6506 6507 c, - s, 0, 0, 6508 s, c, 0, 0, 6509 0, 0, 1, 0, 6510 0, 0, 0, 1 6511 6512 ); 6513 6514 return this; 6515 6516 } 6517 6518 makeRotationAxis(axis, angle) { 6519 6520 // Based on http://www.gamedev.net/reference/articles/article1199.asp 6521 6522 const c = Math.cos(angle); 6523 const s = Math.sin(angle); 6524 const t = 1 - c; 6525 const x = axis.x, y = axis.y, z = axis.z; 6526 const tx = t * x, ty = t * y; 6527 6528 this.set( 6529 6530 tx * x + c, tx * y - s * z, tx * z + s * y, 0, 6531 tx * y + s * z, ty * y + c, ty * z - s * x, 0, 6532 tx * z - s * y, ty * z + s * x, t * z * z + c, 0, 6533 0, 0, 0, 1 6534 6535 ); 6536 6537 return this; 6538 6539 } 6540 6541 makeScale(x, y, z) { 6542 6543 this.set( 6544 6545 x, 0, 0, 0, 6546 0, y, 0, 0, 6547 0, 0, z, 0, 6548 0, 0, 0, 1 6549 6550 ); 6551 6552 return this; 6553 6554 } 6555 6556 makeShear(xy, xz, yx, yz, zx, zy) { 6557 6558 this.set( 6559 6560 1, yx, zx, 0, 6561 xy, 1, zy, 0, 6562 xz, yz, 1, 0, 6563 0, 0, 0, 1 6564 6565 ); 6566 6567 return this; 6568 6569 } 6570 6571 compose(position, quaternion, scale) { 6572 6573 const te = this.elements; 6574 6575 const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w; 6576 const x2 = x + x, y2 = y + y, z2 = z + z; 6577 const xx = x * x2, xy = x * y2, xz = x * z2; 6578 const yy = y * y2, yz = y * z2, zz = z * z2; 6579 const wx = w * x2, wy = w * y2, wz = w * z2; 6580 6581 const sx = scale.x, sy = scale.y, sz = scale.z; 6582 6583 te[0] = (1 - (yy + zz)) * sx; 6584 te[1] = (xy + wz) * sx; 6585 te[2] = (xz - wy) * sx; 6586 te[3] = 0; 6587 6588 te[4] = (xy - wz) * sy; 6589 te[5] = (1 - (xx + zz)) * sy; 6590 te[6] = (yz + wx) * sy; 6591 te[7] = 0; 6592 6593 te[8] = (xz + wy) * sz; 6594 te[9] = (yz - wx) * sz; 6595 te[10] = (1 - (xx + yy)) * sz; 6596 te[11] = 0; 6597 6598 te[12] = position.x; 6599 te[13] = position.y; 6600 te[14] = position.z; 6601 te[15] = 1; 6602 6603 return this; 6604 6605 } 6606 6607 decompose(position, quaternion, scale) { 6608 6609 const te = this.elements; 6610 6611 let sx = _v1$5.set(te[0], te[1], te[2]).length(); 6612 const sy = _v1$5.set(te[4], te[5], te[6]).length(); 6613 const sz = _v1$5.set(te[8], te[9], te[10]).length(); 6614 6615 // if determine is negative, we need to invert one scale 6616 const det = this.determinant(); 6617 if (det < 0) sx = - sx; 6618 6619 position.x = te[12]; 6620 position.y = te[13]; 6621 position.z = te[14]; 6622 6623 // scale the rotation part 6624 _m1$2.copy(this); 6625 6626 const invSX = 1 / sx; 6627 const invSY = 1 / sy; 6628 const invSZ = 1 / sz; 6629 6630 _m1$2.elements[0] *= invSX; 6631 _m1$2.elements[1] *= invSX; 6632 _m1$2.elements[2] *= invSX; 6633 6634 _m1$2.elements[4] *= invSY; 6635 _m1$2.elements[5] *= invSY; 6636 _m1$2.elements[6] *= invSY; 6637 6638 _m1$2.elements[8] *= invSZ; 6639 _m1$2.elements[9] *= invSZ; 6640 _m1$2.elements[10] *= invSZ; 6641 6642 quaternion.setFromRotationMatrix(_m1$2); 6643 6644 scale.x = sx; 6645 scale.y = sy; 6646 scale.z = sz; 6647 6648 return this; 6649 6650 } 6651 6652 makePerspective(left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem) { 6653 6654 const te = this.elements; 6655 const x = 2 * near / (right - left); 6656 const y = 2 * near / (top - bottom); 6657 6658 const a = (right + left) / (right - left); 6659 const b = (top + bottom) / (top - bottom); 6660 6661 let c, d; 6662 6663 if (coordinateSystem === WebGLCoordinateSystem) { 6664 6665 c = - (far + near) / (far - near); 6666 d = (- 2 * far * near) / (far - near); 6667 6668 } else if (coordinateSystem === WebGPUCoordinateSystem) { 6669 6670 c = - far / (far - near); 6671 d = (- far * near) / (far - near); 6672 6673 } else { 6674 6675 throw new Error('THREE.Matrix4.makePerspective(): Invalid coordinate system: ' + coordinateSystem); 6676 6677 } 6678 6679 te[0] = x; te[4] = 0; te[8] = a; te[12] = 0; 6680 te[1] = 0; te[5] = y; te[9] = b; te[13] = 0; 6681 te[2] = 0; te[6] = 0; te[10] = c; te[14] = d; 6682 te[3] = 0; te[7] = 0; te[11] = - 1; te[15] = 0; 6683 6684 return this; 6685 6686 } 6687 6688 makeOrthographic(left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem) { 6689 6690 const te = this.elements; 6691 const w = 1.0 / (right - left); 6692 const h = 1.0 / (top - bottom); 6693 const p = 1.0 / (far - near); 6694 6695 const x = (right + left) * w; 6696 const y = (top + bottom) * h; 6697 6698 let z, zInv; 6699 6700 if (coordinateSystem === WebGLCoordinateSystem) { 6701 6702 z = (far + near) * p; 6703 zInv = - 2 * p; 6704 6705 } else if (coordinateSystem === WebGPUCoordinateSystem) { 6706 6707 z = near * p; 6708 zInv = - 1 * p; 6709 6710 } else { 6711 6712 throw new Error('THREE.Matrix4.makeOrthographic(): Invalid coordinate system: ' + coordinateSystem); 6713 6714 } 6715 6716 te[0] = 2 * w; te[4] = 0; te[8] = 0; te[12] = - x; 6717 te[1] = 0; te[5] = 2 * h; te[9] = 0; te[13] = - y; 6718 te[2] = 0; te[6] = 0; te[10] = zInv; te[14] = - z; 6719 te[3] = 0; te[7] = 0; te[11] = 0; te[15] = 1; 6720 6721 return this; 6722 6723 } 6724 6725 equals(matrix) { 6726 6727 const te = this.elements; 6728 const me = matrix.elements; 6729 6730 for (let i = 0; i < 16; i++) { 6731 6732 if (te[i] !== me[i]) return false; 6733 6734 } 6735 6736 return true; 6737 6738 } 6739 6740 fromArray(array, offset = 0) { 6741 6742 for (let i = 0; i < 16; i++) { 6743 6744 this.elements[i] = array[i + offset]; 6745 6746 } 6747 6748 return this; 6749 6750 } 6751 6752 toArray(array = [], offset = 0) { 6753 6754 const te = this.elements; 6755 6756 array[offset] = te[0]; 6757 array[offset + 1] = te[1]; 6758 array[offset + 2] = te[2]; 6759 array[offset + 3] = te[3]; 6760 6761 array[offset + 4] = te[4]; 6762 array[offset + 5] = te[5]; 6763 array[offset + 6] = te[6]; 6764 array[offset + 7] = te[7]; 6765 6766 array[offset + 8] = te[8]; 6767 array[offset + 9] = te[9]; 6768 array[offset + 10] = te[10]; 6769 array[offset + 11] = te[11]; 6770 6771 array[offset + 12] = te[12]; 6772 array[offset + 13] = te[13]; 6773 array[offset + 14] = te[14]; 6774 array[offset + 15] = te[15]; 6775 6776 return array; 6777 6778 } 6779 6780} 6781 6782const _v1$5 = /*@__PURE__*/ new Vector3(); 6783const _m1$2 = /*@__PURE__*/ new Matrix4(); 6784const _zero = /*@__PURE__*/ new Vector3(0, 0, 0); 6785const _one = /*@__PURE__*/ new Vector3(1, 1, 1); 6786const _x = /*@__PURE__*/ new Vector3(); 6787const _y = /*@__PURE__*/ new Vector3(); 6788const _z = /*@__PURE__*/ new Vector3(); 6789 6790const _matrix$1 = /*@__PURE__*/ new Matrix4(); 6791const _quaternion$3 = /*@__PURE__*/ new Quaternion(); 6792 6793class Euler { 6794 6795 constructor(x = 0, y = 0, z = 0, order = Euler.DEFAULT_ORDER) { 6796 6797 this.isEuler = true; 6798 6799 this._x = x; 6800 this._y = y; 6801 this._z = z; 6802 this._order = order; 6803 6804 } 6805 6806 get x() { 6807 6808 return this._x; 6809 6810 } 6811 6812 set x(value) { 6813 6814 this._x = value; 6815 this._onChangeCallback(); 6816 6817 } 6818 6819 get y() { 6820 6821 return this._y; 6822 6823 } 6824 6825 set y(value) { 6826 6827 this._y = value; 6828 this._onChangeCallback(); 6829 6830 } 6831 6832 get z() { 6833 6834 return this._z; 6835 6836 } 6837 6838 set z(value) { 6839 6840 this._z = value; 6841 this._onChangeCallback(); 6842 6843 } 6844 6845 get order() { 6846 6847 return this._order; 6848 6849 } 6850 6851 set order(value) { 6852 6853 this._order = value; 6854 this._onChangeCallback(); 6855 6856 } 6857 6858 set(x, y, z, order = this._order) { 6859 6860 this._x = x; 6861 this._y = y; 6862 this._z = z; 6863 this._order = order; 6864 6865 this._onChangeCallback(); 6866 6867 return this; 6868 6869 } 6870 6871 clone() { 6872 6873 return new this.constructor(this._x, this._y, this._z, this._order); 6874 6875 } 6876 6877 copy(euler) { 6878 6879 this._x = euler._x; 6880 this._y = euler._y; 6881 this._z = euler._z; 6882 this._order = euler._order; 6883 6884 this._onChangeCallback(); 6885 6886 return this; 6887 6888 } 6889 6890 setFromRotationMatrix(m, order = this._order, update = true) { 6891 6892 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 6893 6894 const te = m.elements; 6895 const m11 = te[0], m12 = te[4], m13 = te[8]; 6896 const m21 = te[1], m22 = te[5], m23 = te[9]; 6897 const m31 = te[2], m32 = te[6], m33 = te[10]; 6898 6899 switch (order) { 6900 6901 case 'XYZ': 6902 6903 this._y = Math.asin(clamp(m13, - 1, 1)); 6904 6905 if (Math.abs(m13) < 0.9999999) { 6906 6907 this._x = Math.atan2(- m23, m33); 6908 this._z = Math.atan2(- m12, m11); 6909 6910 } else { 6911 6912 this._x = Math.atan2(m32, m22); 6913 this._z = 0; 6914 6915 } 6916 6917 break; 6918 6919 case 'YXZ': 6920 6921 this._x = Math.asin(- clamp(m23, - 1, 1)); 6922 6923 if (Math.abs(m23) < 0.9999999) { 6924 6925 this._y = Math.atan2(m13, m33); 6926 this._z = Math.atan2(m21, m22); 6927 6928 } else { 6929 6930 this._y = Math.atan2(- m31, m11); 6931 this._z = 0; 6932 6933 } 6934 6935 break; 6936 6937 case 'ZXY': 6938 6939 this._x = Math.asin(clamp(m32, - 1, 1)); 6940 6941 if (Math.abs(m32) < 0.9999999) { 6942 6943 this._y = Math.atan2(- m31, m33); 6944 this._z = Math.atan2(- m12, m22); 6945 6946 } else { 6947 6948 this._y = 0; 6949 this._z = Math.atan2(m21, m11); 6950 6951 } 6952 6953 break; 6954 6955 case 'ZYX': 6956 6957 this._y = Math.asin(- clamp(m31, - 1, 1)); 6958 6959 if (Math.abs(m31) < 0.9999999) { 6960 6961 this._x = Math.atan2(m32, m33); 6962 this._z = Math.atan2(m21, m11); 6963 6964 } else { 6965 6966 this._x = 0; 6967 this._z = Math.atan2(- m12, m22); 6968 6969 } 6970 6971 break; 6972 6973 case 'YZX': 6974 6975 this._z = Math.asin(clamp(m21, - 1, 1)); 6976 6977 if (Math.abs(m21) < 0.9999999) { 6978 6979 this._x = Math.atan2(- m23, m22); 6980 this._y = Math.atan2(- m31, m11); 6981 6982 } else { 6983 6984 this._x = 0; 6985 this._y = Math.atan2(m13, m33); 6986 6987 } 6988 6989 break; 6990 6991 case 'XZY': 6992 6993 this._z = Math.asin(- clamp(m12, - 1, 1)); 6994 6995 if (Math.abs(m12) < 0.9999999) { 6996 6997 this._x = Math.atan2(m32, m22); 6998 this._y = Math.atan2(m13, m11); 6999 7000 } else { 7001 7002 this._x = Math.atan2(- m23, m33); 7003 this._y = 0; 7004 7005 } 7006 7007 break; 7008 7009 default: 7010 7011 console.warn('THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order); 7012 7013 } 7014 7015 this._order = order; 7016 7017 if (update === true) this._onChangeCallback(); 7018 7019 return this; 7020 7021 } 7022 7023 setFromQuaternion(q, order, update) { 7024 7025 _matrix$1.makeRotationFromQuaternion(q); 7026 7027 return this.setFromRotationMatrix(_matrix$1, order, update); 7028 7029 } 7030 7031 setFromVector3(v, order = this._order) { 7032 7033 return this.set(v.x, v.y, v.z, order); 7034 7035 } 7036 7037 reorder(newOrder) { 7038 7039 // WARNING: this discards revolution information -bhouston 7040 7041 _quaternion$3.setFromEuler(this); 7042 7043 return this.setFromQuaternion(_quaternion$3, newOrder); 7044 7045 } 7046 7047 equals(euler) { 7048 7049 return (euler._x === this._x) && (euler._y === this._y) && (euler._z === this._z) && (euler._order === this._order); 7050 7051 } 7052 7053 fromArray(array) { 7054 7055 this._x = array[0]; 7056 this._y = array[1]; 7057 this._z = array[2]; 7058 if (array[3] !== undefined) this._order = array[3]; 7059 7060 this._onChangeCallback(); 7061 7062 return this; 7063 7064 } 7065 7066 toArray(array = [], offset = 0) { 7067 7068 array[offset] = this._x; 7069 array[offset + 1] = this._y; 7070 array[offset + 2] = this._z; 7071 array[offset + 3] = this._order; 7072 7073 return array; 7074 7075 } 7076 7077 _onChange(callback) { 7078 7079 this._onChangeCallback = callback; 7080 7081 return this; 7082 7083 } 7084 7085 _onChangeCallback() { } 7086 7087 *[Symbol.iterator]() { 7088 7089 yield this._x; 7090 yield this._y; 7091 yield this._z; 7092 yield this._order; 7093 7094 } 7095 7096} 7097 7098Euler.DEFAULT_ORDER = 'XYZ'; 7099 7100class Layers { 7101 7102 constructor() { 7103 7104 this.mask = 1 | 0; 7105 7106 } 7107 7108 set(channel) { 7109 7110 this.mask = (1 << channel | 0) >>> 0; 7111 7112 } 7113 7114 enable(channel) { 7115 7116 this.mask |= 1 << channel | 0; 7117 7118 } 7119 7120 enableAll() { 7121 7122 this.mask = 0xffffffff | 0; 7123 7124 } 7125 7126 toggle(channel) { 7127 7128 this.mask ^= 1 << channel | 0; 7129 7130 } 7131 7132 disable(channel) { 7133 7134 this.mask &= ~(1 << channel | 0); 7135 7136 } 7137 7138 disableAll() { 7139 7140 this.mask = 0; 7141 7142 } 7143 7144 test(layers) { 7145 7146 return (this.mask & layers.mask) !== 0; 7147 7148 } 7149 7150 isEnabled(channel) { 7151 7152 return (this.mask & (1 << channel | 0)) !== 0; 7153 7154 } 7155 7156} 7157 7158let _object3DId = 0; 7159 7160const _v1$4 = /*@__PURE__*/ new Vector3(); 7161const _q1 = /*@__PURE__*/ new Quaternion(); 7162const _m1$1 = /*@__PURE__*/ new Matrix4(); 7163const _target = /*@__PURE__*/ new Vector3(); 7164 7165const _position$3 = /*@__PURE__*/ new Vector3(); 7166const _scale$2 = /*@__PURE__*/ new Vector3(); 7167const _quaternion$2 = /*@__PURE__*/ new Quaternion(); 7168 7169const _xAxis = /*@__PURE__*/ new Vector3(1, 0, 0); 7170const _yAxis = /*@__PURE__*/ new Vector3(0, 1, 0); 7171const _zAxis = /*@__PURE__*/ new Vector3(0, 0, 1); 7172 7173const _addedEvent = { type: 'added' }; 7174const _removedEvent = { type: 'removed' }; 7175 7176class Object3D extends EventDispatcher { 7177 7178 constructor() { 7179 7180 super(); 7181 7182 this.isObject3D = true; 7183 7184 Object.defineProperty(this, 'id', { value: _object3DId++ }); 7185 7186 this.uuid = generateUUID(); 7187 7188 this.name = ''; 7189 this.type = 'Object3D'; 7190 7191 this.parent = null; 7192 this.children = []; 7193 7194 this.up = Object3D.DEFAULT_UP.clone(); 7195 7196 const position = new Vector3(); 7197 const rotation = new Euler(); 7198 const quaternion = new Quaternion(); 7199 const scale = new Vector3(1, 1, 1); 7200 7201 function onRotationChange() { 7202 7203 quaternion.setFromEuler(rotation, false); 7204 7205 } 7206 7207 function onQuaternionChange() { 7208 7209 rotation.setFromQuaternion(quaternion, undefined, false); 7210 7211 } 7212 7213 rotation._onChange(onRotationChange); 7214 quaternion._onChange(onQuaternionChange); 7215 7216 Object.defineProperties(this, { 7217 position: { 7218 configurable: true, 7219 enumerable: true, 7220 value: position 7221 }, 7222 rotation: { 7223 configurable: true, 7224 enumerable: true, 7225 value: rotation 7226 }, 7227 quaternion: { 7228 configurable: true, 7229 enumerable: true, 7230 value: quaternion 7231 }, 7232 scale: { 7233 configurable: true, 7234 enumerable: true, 7235 value: scale 7236 }, 7237 modelViewMatrix: { 7238 value: new Matrix4() 7239 }, 7240 normalMatrix: { 7241 value: new Matrix3() 7242 } 7243 }); 7244 7245 this.matrix = new Matrix4(); 7246 this.matrixWorld = new Matrix4(); 7247 7248 this.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE; 7249 7250 this.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE; // checked by the renderer 7251 this.matrixWorldNeedsUpdate = false; 7252 7253 this.layers = new Layers(); 7254 this.visible = true; 7255 7256 this.castShadow = false; 7257 this.receiveShadow = false; 7258 7259 this.frustumCulled = true; 7260 this.renderOrder = 0; 7261 7262 this.animations = []; 7263 7264 this.userData = {}; 7265 7266 } 7267 7268 onBeforeShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */) { } 7269 7270 onAfterShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */) { } 7271 7272 onBeforeRender( /* renderer, scene, camera, geometry, material, group */) { } 7273 7274 onAfterRender( /* renderer, scene, camera, geometry, material, group */) { } 7275 7276 applyMatrix4(matrix) { 7277 7278 if (this.matrixAutoUpdate) this.updateMatrix(); 7279 7280 this.matrix.premultiply(matrix); 7281 7282 this.matrix.decompose(this.position, this.quaternion, this.scale); 7283 7284 } 7285 7286 applyQuaternion(q) { 7287 7288 this.quaternion.premultiply(q); 7289 7290 return this; 7291 7292 } 7293 7294 setRotationFromAxisAngle(axis, angle) { 7295 7296 // assumes axis is normalized 7297 7298 this.quaternion.setFromAxisAngle(axis, angle); 7299 7300 } 7301 7302 setRotationFromEuler(euler) { 7303 7304 this.quaternion.setFromEuler(euler, true); 7305 7306 } 7307 7308 setRotationFromMatrix(m) { 7309 7310 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 7311 7312 this.quaternion.setFromRotationMatrix(m); 7313 7314 } 7315 7316 setRotationFromQuaternion(q) { 7317 7318 // assumes q is normalized 7319 7320 this.quaternion.copy(q); 7321 7322 } 7323 7324 rotateOnAxis(axis, angle) { 7325 7326 // rotate object on axis in object space 7327 // axis is assumed to be normalized 7328 7329 _q1.setFromAxisAngle(axis, angle); 7330 7331 this.quaternion.multiply(_q1); 7332 7333 return this; 7334 7335 } 7336 7337 rotateOnWorldAxis(axis, angle) { 7338 7339 // rotate object on axis in world space 7340 // axis is assumed to be normalized 7341 // method assumes no rotated parent 7342 7343 _q1.setFromAxisAngle(axis, angle); 7344 7345 this.quaternion.premultiply(_q1); 7346 7347 return this; 7348 7349 } 7350 7351 rotateX(angle) { 7352 7353 return this.rotateOnAxis(_xAxis, angle); 7354 7355 } 7356 7357 rotateY(angle) { 7358 7359 return this.rotateOnAxis(_yAxis, angle); 7360 7361 } 7362 7363 rotateZ(angle) { 7364 7365 return this.rotateOnAxis(_zAxis, angle); 7366 7367 } 7368 7369 translateOnAxis(axis, distance) { 7370 7371 // translate object by distance along axis in object space 7372 // axis is assumed to be normalized 7373 7374 _v1$4.copy(axis).applyQuaternion(this.quaternion); 7375 7376 this.position.add(_v1$4.multiplyScalar(distance)); 7377 7378 return this; 7379 7380 } 7381 7382 translateX(distance) { 7383 7384 return this.translateOnAxis(_xAxis, distance); 7385 7386 } 7387 7388 translateY(distance) { 7389 7390 return this.translateOnAxis(_yAxis, distance); 7391 7392 } 7393 7394 translateZ(distance) { 7395 7396 return this.translateOnAxis(_zAxis, distance); 7397 7398 } 7399 7400 localToWorld(vector) { 7401 7402 this.updateWorldMatrix(true, false); 7403 7404 return vector.applyMatrix4(this.matrixWorld); 7405 7406 } 7407 7408 worldToLocal(vector) { 7409 7410 this.updateWorldMatrix(true, false); 7411 7412 return vector.applyMatrix4(_m1$1.copy(this.matrixWorld).invert()); 7413 7414 } 7415 7416 lookAt(x, y, z) { 7417 7418 // This method does not support objects having non-uniformly-scaled parent(s) 7419 7420 if (x.isVector3) { 7421 7422 _target.copy(x); 7423 7424 } else { 7425 7426 _target.set(x, y, z); 7427 7428 } 7429 7430 const parent = this.parent; 7431 7432 this.updateWorldMatrix(true, false); 7433 7434 _position$3.setFromMatrixPosition(this.matrixWorld); 7435 7436 if (this.isCamera || this.isLight) { 7437 7438 _m1$1.lookAt(_position$3, _target, this.up); 7439 7440 } else { 7441 7442 _m1$1.lookAt(_target, _position$3, this.up); 7443 7444 } 7445 7446 this.quaternion.setFromRotationMatrix(_m1$1); 7447 7448 if (parent) { 7449 7450 _m1$1.extractRotation(parent.matrixWorld); 7451 _q1.setFromRotationMatrix(_m1$1); 7452 this.quaternion.premultiply(_q1.invert()); 7453 7454 } 7455 7456 } 7457 7458 add(object) { 7459 7460 if (arguments.length > 1) { 7461 7462 for (let i = 0; i < arguments.length; i++) { 7463 7464 this.add(arguments[i]); 7465 7466 } 7467 7468 return this; 7469 7470 } 7471 7472 if (object === this) { 7473 7474 console.error('THREE.Object3D.add: object can\'t be added as a child of itself.', object); 7475 return this; 7476 7477 } 7478 7479 if (object && object.isObject3D) { 7480 7481 if (object.parent !== null) { 7482 7483 object.parent.remove(object); 7484 7485 } 7486 7487 object.parent = this; 7488 this.children.push(object); 7489 7490 object.dispatchEvent(_addedEvent); 7491 7492 } else { 7493 7494 console.error('THREE.Object3D.add: object not an instance of THREE.Object3D.', object); 7495 7496 } 7497 7498 return this; 7499 7500 } 7501 7502 remove(object) { 7503 7504 if (arguments.length > 1) { 7505 7506 for (let i = 0; i < arguments.length; i++) { 7507 7508 this.remove(arguments[i]); 7509 7510 } 7511 7512 return this; 7513 7514 } 7515 7516 const index = this.children.indexOf(object); 7517 7518 if (index !== - 1) { 7519 7520 object.parent = null; 7521 this.children.splice(index, 1); 7522 7523 object.dispatchEvent(_removedEvent); 7524 7525 } 7526 7527 return this; 7528 7529 } 7530 7531 removeFromParent() { 7532 7533 const parent = this.parent; 7534 7535 if (parent !== null) { 7536 7537 parent.remove(this); 7538 7539 } 7540 7541 return this; 7542 7543 } 7544 7545 clear() { 7546 7547 return this.remove(... this.children); 7548 7549 } 7550 7551 attach(object) { 7552 7553 // adds object as a child of this, while maintaining the object's world transform 7554 7555 // Note: This method does not support scene graphs having non-uniformly-scaled nodes(s) 7556 7557 this.updateWorldMatrix(true, false); 7558 7559 _m1$1.copy(this.matrixWorld).invert(); 7560 7561 if (object.parent !== null) { 7562 7563 object.parent.updateWorldMatrix(true, false); 7564 7565 _m1$1.multiply(object.parent.matrixWorld); 7566 7567 } 7568 7569 object.applyMatrix4(_m1$1); 7570 7571 this.add(object); 7572 7573 object.updateWorldMatrix(false, true); 7574 7575 return this; 7576 7577 } 7578 7579 getObjectById(id) { 7580 7581 return this.getObjectByProperty('id', id); 7582 7583 } 7584 7585 getObjectByName(name) { 7586 7587 return this.getObjectByProperty('name', name); 7588 7589 } 7590 7591 getObjectByProperty(name, value) { 7592 7593 if (this[name] === value) return this; 7594 7595 for (let i = 0, l = this.children.length; i < l; i++) { 7596 7597 const child = this.children[i]; 7598 const object = child.getObjectByProperty(name, value); 7599 7600 if (object !== undefined) { 7601 7602 return object; 7603 7604 } 7605 7606 } 7607 7608 return undefined; 7609 7610 } 7611 7612 getObjectsByProperty(name, value, result = []) { 7613 7614 if (this[name] === value) result.push(this); 7615 7616 const children = this.children; 7617 7618 for (let i = 0, l = children.length; i < l; i++) { 7619 7620 children[i].getObjectsByProperty(name, value, result); 7621 7622 } 7623 7624 return result; 7625 7626 } 7627 7628 getWorldPosition(target) { 7629 7630 this.updateWorldMatrix(true, false); 7631 7632 return target.setFromMatrixPosition(this.matrixWorld); 7633 7634 } 7635 7636 getWorldQuaternion(target) { 7637 7638 this.updateWorldMatrix(true, false); 7639 7640 this.matrixWorld.decompose(_position$3, target, _scale$2); 7641 7642 return target; 7643 7644 } 7645 7646 getWorldScale(target) { 7647 7648 this.updateWorldMatrix(true, false); 7649 7650 this.matrixWorld.decompose(_position$3, _quaternion$2, target); 7651 7652 return target; 7653 7654 } 7655 7656 getWorldDirection(target) { 7657 7658 this.updateWorldMatrix(true, false); 7659 7660 const e = this.matrixWorld.elements; 7661 7662 return target.set(e[8], e[9], e[10]).normalize(); 7663 7664 } 7665 7666 raycast( /* raycaster, intersects */) { } 7667 7668 traverse(callback) { 7669 7670 callback(this); 7671 7672 const children = this.children; 7673 7674 for (let i = 0, l = children.length; i < l; i++) { 7675 7676 children[i].traverse(callback); 7677 7678 } 7679 7680 } 7681 7682 traverseVisible(callback) { 7683 7684 if (this.visible === false) return; 7685 7686 callback(this); 7687 7688 const children = this.children; 7689 7690 for (let i = 0, l = children.length; i < l; i++) { 7691 7692 children[i].traverseVisible(callback); 7693 7694 } 7695 7696 } 7697 7698 traverseAncestors(callback) { 7699 7700 const parent = this.parent; 7701 7702 if (parent !== null) { 7703 7704 callback(parent); 7705 7706 parent.traverseAncestors(callback); 7707 7708 } 7709 7710 } 7711 7712 updateMatrix() { 7713 7714 this.matrix.compose(this.position, this.quaternion, this.scale); 7715 7716 this.matrixWorldNeedsUpdate = true; 7717 7718 } 7719 7720 updateMatrixWorld(force) { 7721 7722 if (this.matrixAutoUpdate) this.updateMatrix(); 7723 7724 if (this.matrixWorldNeedsUpdate || force) { 7725 7726 if (this.parent === null) { 7727 7728 this.matrixWorld.copy(this.matrix); 7729 7730 } else { 7731 7732 this.matrixWorld.multiplyMatrices(this.parent.matrixWorld, this.matrix); 7733 7734 } 7735 7736 this.matrixWorldNeedsUpdate = false; 7737 7738 force = true; 7739 7740 } 7741 7742 // update children 7743 7744 const children = this.children; 7745 7746 for (let i = 0, l = children.length; i < l; i++) { 7747 7748 const child = children[i]; 7749 7750 if (child.matrixWorldAutoUpdate === true || force === true) { 7751 7752 child.updateMatrixWorld(force); 7753 7754 } 7755 7756 } 7757 7758 } 7759 7760 updateWorldMatrix(updateParents, updateChildren) { 7761 7762 const parent = this.parent; 7763 7764 if (updateParents === true && parent !== null && parent.matrixWorldAutoUpdate === true) { 7765 7766 parent.updateWorldMatrix(true, false); 7767 7768 } 7769 7770 if (this.matrixAutoUpdate) this.updateMatrix(); 7771 7772 if (this.parent === null) { 7773 7774 this.matrixWorld.copy(this.matrix); 7775 7776 } else { 7777 7778 this.matrixWorld.multiplyMatrices(this.parent.matrixWorld, this.matrix); 7779 7780 } 7781 7782 // update children 7783 7784 if (updateChildren === true) { 7785 7786 const children = this.children; 7787 7788 for (let i = 0, l = children.length; i < l; i++) { 7789 7790 const child = children[i]; 7791 7792 if (child.matrixWorldAutoUpdate === true) { 7793 7794 child.updateWorldMatrix(false, true); 7795 7796 } 7797 7798 } 7799 7800 } 7801 7802 } 7803 7804 toJSON(meta) { 7805 7806 // meta is a string when called from JSON.stringify 7807 const isRootObject = (meta === undefined || typeof meta === 'string'); 7808 7809 const output = {}; 7810 7811 // meta is a hash used to collect geometries, materials. 7812 // not providing it implies that this is the root object 7813 // being serialized. 7814 if (isRootObject) { 7815 7816 // initialize meta obj 7817 meta = { 7818 geometries: {}, 7819 materials: {}, 7820 textures: {}, 7821 images: {}, 7822 shapes: {}, 7823 skeletons: {}, 7824 animations: {}, 7825 nodes: {} 7826 }; 7827 7828 output.metadata = { 7829 version: 4.6, 7830 type: 'Object', 7831 generator: 'Object3D.toJSON' 7832 }; 7833 7834 } 7835 7836 // standard Object3D serialization 7837 7838 const object = {}; 7839 7840 object.uuid = this.uuid; 7841 object.type = this.type; 7842 7843 if (this.name !== '') object.name = this.name; 7844 if (this.castShadow === true) object.castShadow = true; 7845 if (this.receiveShadow === true) object.receiveShadow = true; 7846 if (this.visible === false) object.visible = false; 7847 if (this.frustumCulled === false) object.frustumCulled = false; 7848 if (this.renderOrder !== 0) object.renderOrder = this.renderOrder; 7849 if (Object.keys(this.userData).length > 0) object.userData = this.userData; 7850 7851 object.layers = this.layers.mask; 7852 object.matrix = this.matrix.toArray(); 7853 object.up = this.up.toArray(); 7854 7855 if (this.matrixAutoUpdate === false) object.matrixAutoUpdate = false; 7856 7857 // object specific properties 7858 7859 if (this.isInstancedMesh) { 7860 7861 object.type = 'InstancedMesh'; 7862 object.count = this.count; 7863 object.instanceMatrix = this.instanceMatrix.toJSON(); 7864 if (this.instanceColor !== null) object.instanceColor = this.instanceColor.toJSON(); 7865 7866 } 7867 7868 if (this.isBatchedMesh) { 7869 7870 object.type = 'BatchedMesh'; 7871 object.perObjectFrustumCulled = this.perObjectFrustumCulled; 7872 object.sortObjects = this.sortObjects; 7873 7874 object.drawRanges = this._drawRanges; 7875 object.reservedRanges = this._reservedRanges; 7876 7877 object.visibility = this._visibility; 7878 object.active = this._active; 7879 object.bounds = this._bounds.map(bound => ({ 7880 boxInitialized: bound.boxInitialized, 7881 boxMin: bound.box.min.toArray(), 7882 boxMax: bound.box.max.toArray(), 7883 7884 sphereInitialized: bound.sphereInitialized, 7885 sphereRadius: bound.sphere.radius, 7886 sphereCenter: bound.sphere.center.toArray() 7887 })); 7888 7889 object.maxGeometryCount = this._maxGeometryCount; 7890 object.maxVertexCount = this._maxVertexCount; 7891 object.maxIndexCount = this._maxIndexCount; 7892 7893 object.geometryInitialized = this._geometryInitialized; 7894 object.geometryCount = this._geometryCount; 7895 7896 object.matricesTexture = this._matricesTexture.toJSON(meta); 7897 7898 if (this.boundingSphere !== null) { 7899 7900 object.boundingSphere = { 7901 center: object.boundingSphere.center.toArray(), 7902 radius: object.boundingSphere.radius 7903 }; 7904 7905 } 7906 7907 if (this.boundingBox !== null) { 7908 7909 object.boundingBox = { 7910 min: object.boundingBox.min.toArray(), 7911 max: object.boundingBox.max.toArray() 7912 }; 7913 7914 } 7915 7916 } 7917 7918 // 7919 7920 function serialize(library, element) { 7921 7922 if (library[element.uuid] === undefined) { 7923 7924 library[element.uuid] = element.toJSON(meta); 7925 7926 } 7927 7928 return element.uuid; 7929 7930 } 7931 7932 if (this.isScene) { 7933 7934 if (this.background) { 7935 7936 if (this.background.isColor) { 7937 7938 object.background = this.background.toJSON(); 7939 7940 } else if (this.background.isTexture) { 7941 7942 object.background = this.background.toJSON(meta).uuid; 7943 7944 } 7945 7946 } 7947 7948 if (this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true) { 7949 7950 object.environment = this.environment.toJSON(meta).uuid; 7951 7952 } 7953 7954 } else if (this.isMesh || this.isLine || this.isPoints) { 7955 7956 object.geometry = serialize(meta.geometries, this.geometry); 7957 7958 const parameters = this.geometry.parameters; 7959 7960 if (parameters !== undefined && parameters.shapes !== undefined) { 7961 7962 const shapes = parameters.shapes; 7963 7964 if (Array.isArray(shapes)) { 7965 7966 for (let i = 0, l = shapes.length; i < l; i++) { 7967 7968 const shape = shapes[i];
vendor: 9,257 bytes, lines 7969-8412
7969 7970 serialize(meta.shapes, shape); 7971 7972 } 7973 7974 } else { 7975 7976 serialize(meta.shapes, shapes); 7977 7978 } 7979 7980 } 7981 7982 } 7983 7984 if (this.isSkinnedMesh) { 7985 7986 object.bindMode = this.bindMode; 7987 object.bindMatrix = this.bindMatrix.toArray(); 7988 7989 if (this.skeleton !== undefined) { 7990 7991 serialize(meta.skeletons, this.skeleton); 7992 7993 object.skeleton = this.skeleton.uuid; 7994 7995 } 7996 7997 } 7998 7999 if (this.material !== undefined) { 8000 8001 if (Array.isArray(this.material)) { 8002 8003 const uuids = []; 8004 8005 for (let i = 0, l = this.material.length; i < l; i++) { 8006 8007 uuids.push(serialize(meta.materials, this.material[i])); 8008 8009 } 8010 8011 object.material = uuids; 8012 8013 } else { 8014 8015 object.material = serialize(meta.materials, this.material); 8016 8017 } 8018 8019 } 8020 8021 // 8022 8023 if (this.children.length > 0) { 8024 8025 object.children = []; 8026 8027 for (let i = 0; i < this.children.length; i++) { 8028 8029 object.children.push(this.children[i].toJSON(meta).object); 8030 8031 } 8032 8033 } 8034 8035 // 8036 8037 if (this.animations.length > 0) { 8038 8039 object.animations = []; 8040 8041 for (let i = 0; i < this.animations.length; i++) { 8042 8043 const animation = this.animations[i]; 8044 8045 object.animations.push(serialize(meta.animations, animation)); 8046 8047 } 8048 8049 } 8050 8051 if (isRootObject) { 8052 8053 const geometries = extractFromCache(meta.geometries); 8054 const materials = extractFromCache(meta.materials); 8055 const textures = extractFromCache(meta.textures); 8056 const images = extractFromCache(meta.images); 8057 const shapes = extractFromCache(meta.shapes); 8058 const skeletons = extractFromCache(meta.skeletons); 8059 const animations = extractFromCache(meta.animations); 8060 const nodes = extractFromCache(meta.nodes); 8061 8062 if (geometries.length > 0) output.geometries = geometries; 8063 if (materials.length > 0) output.materials = materials; 8064 if (textures.length > 0) output.textures = textures; 8065 if (images.length > 0) output.images = images; 8066 if (shapes.length > 0) output.shapes = shapes; 8067 if (skeletons.length > 0) output.skeletons = skeletons; 8068 if (animations.length > 0) output.animations = animations; 8069 if (nodes.length > 0) output.nodes = nodes; 8070 8071 } 8072 8073 output.object = object; 8074 8075 return output; 8076 8077 // extract data from the cache hash 8078 // remove metadata on each item 8079 // and return as array 8080 function extractFromCache(cache) { 8081 8082 const values = []; 8083 for (const key in cache) { 8084 8085 const data = cache[key]; 8086 delete data.metadata; 8087 values.push(data); 8088 8089 } 8090 8091 return values; 8092 8093 } 8094 8095 } 8096 8097 clone(recursive) { 8098 8099 return new this.constructor().copy(this, recursive); 8100 8101 } 8102 8103 copy(source, recursive = true) { 8104 8105 this.name = source.name; 8106 8107 this.up.copy(source.up); 8108 8109 this.position.copy(source.position); 8110 this.rotation.order = source.rotation.order; 8111 this.quaternion.copy(source.quaternion); 8112 this.scale.copy(source.scale); 8113 8114 this.matrix.copy(source.matrix); 8115 this.matrixWorld.copy(source.matrixWorld); 8116 8117 this.matrixAutoUpdate = source.matrixAutoUpdate; 8118 8119 this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate; 8120 this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; 8121 8122 this.layers.mask = source.layers.mask; 8123 this.visible = source.visible; 8124 8125 this.castShadow = source.castShadow; 8126 this.receiveShadow = source.receiveShadow; 8127 8128 this.frustumCulled = source.frustumCulled; 8129 this.renderOrder = source.renderOrder; 8130 8131 this.animations = source.animations.slice(); 8132 8133 this.userData = JSON.parse(JSON.stringify(source.userData)); 8134 8135 if (recursive === true) { 8136 8137 for (let i = 0; i < source.children.length; i++) { 8138 8139 const child = source.children[i]; 8140 this.add(child.clone()); 8141 8142 } 8143 8144 } 8145 8146 return this; 8147 8148 } 8149 8150} 8151 8152Object3D.DEFAULT_UP = /*@__PURE__*/ new Vector3(0, 1, 0); 8153Object3D.DEFAULT_MATRIX_AUTO_UPDATE = true; 8154Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = true; 8155 8156const _v0$1 = /*@__PURE__*/ new Vector3(); 8157const _v1$3 = /*@__PURE__*/ new Vector3(); 8158const _v2$2 = /*@__PURE__*/ new Vector3(); 8159const _v3$1 = /*@__PURE__*/ new Vector3(); 8160 8161const _vab = /*@__PURE__*/ new Vector3(); 8162const _vac = /*@__PURE__*/ new Vector3(); 8163const _vbc = /*@__PURE__*/ new Vector3(); 8164const _vap = /*@__PURE__*/ new Vector3(); 8165const _vbp = /*@__PURE__*/ new Vector3(); 8166const _vcp = /*@__PURE__*/ new Vector3(); 8167 8168let warnedGetUV = false; 8169 8170class Triangle { 8171 8172 constructor(a = new Vector3(), b = new Vector3(), c = new Vector3()) { 8173 8174 this.a = a; 8175 this.b = b; 8176 this.c = c; 8177 8178 } 8179 8180 static getNormal(a, b, c, target) { 8181 8182 target.subVectors(c, b); 8183 _v0$1.subVectors(a, b); 8184 target.cross(_v0$1); 8185 8186 const targetLengthSq = target.lengthSq(); 8187 if (targetLengthSq > 0) { 8188 8189 return target.multiplyScalar(1 / Math.sqrt(targetLengthSq)); 8190 8191 } 8192 8193 return target.set(0, 0, 0); 8194 8195 } 8196 8197 // static/instance method to calculate barycentric coordinates 8198 // based on: http://www.blackpawn.com/texts/pointinpoly/default.html 8199 static getBarycoord(point, a, b, c, target) { 8200 8201 _v0$1.subVectors(c, a); 8202 _v1$3.subVectors(b, a); 8203 _v2$2.subVectors(point, a); 8204 8205 const dot00 = _v0$1.dot(_v0$1); 8206 const dot01 = _v0$1.dot(_v1$3); 8207 const dot02 = _v0$1.dot(_v2$2); 8208 const dot11 = _v1$3.dot(_v1$3); 8209 const dot12 = _v1$3.dot(_v2$2); 8210 8211 const denom = (dot00 * dot11 - dot01 * dot01); 8212 8213 // collinear or singular triangle 8214 if (denom === 0) { 8215 8216 target.set(0, 0, 0); 8217 return null; 8218 8219 } 8220 8221 const invDenom = 1 / denom; 8222 const u = (dot11 * dot02 - dot01 * dot12) * invDenom; 8223 const v = (dot00 * dot12 - dot01 * dot02) * invDenom; 8224 8225 // barycentric coordinates must always sum to 1 8226 return target.set(1 - u - v, v, u); 8227 8228 } 8229 8230 static containsPoint(point, a, b, c) { 8231 8232 // if the triangle is degenerate then we can't contain a point 8233 if (this.getBarycoord(point, a, b, c, _v3$1) === null) { 8234 8235 return false; 8236 8237 } 8238 8239 return (_v3$1.x >= 0) && (_v3$1.y >= 0) && ((_v3$1.x + _v3$1.y) <= 1); 8240 8241 } 8242 8243 static getUV(point, p1, p2, p3, uv1, uv2, uv3, target) { // @deprecated, r151 8244 8245 if (warnedGetUV === false) { 8246 8247 console.warn('THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation().'); 8248 8249 warnedGetUV = true; 8250 8251 } 8252 8253 return this.getInterpolation(point, p1, p2, p3, uv1, uv2, uv3, target); 8254 8255 } 8256 8257 static getInterpolation(point, p1, p2, p3, v1, v2, v3, target) { 8258 8259 if (this.getBarycoord(point, p1, p2, p3, _v3$1) === null) { 8260 8261 target.x = 0; 8262 target.y = 0; 8263 if ('z' in target) target.z = 0; 8264 if ('w' in target) target.w = 0; 8265 return null; 8266 8267 } 8268 8269 target.setScalar(0); 8270 target.addScaledVector(v1, _v3$1.x); 8271 target.addScaledVector(v2, _v3$1.y); 8272 target.addScaledVector(v3, _v3$1.z); 8273 8274 return target; 8275 8276 } 8277 8278 static isFrontFacing(a, b, c, direction) { 8279 8280 _v0$1.subVectors(c, b); 8281 _v1$3.subVectors(a, b); 8282 8283 // strictly front facing 8284 return (_v0$1.cross(_v1$3).dot(direction) < 0) ? true : false; 8285 8286 } 8287 8288 set(a, b, c) { 8289 8290 this.a.copy(a); 8291 this.b.copy(b); 8292 this.c.copy(c); 8293 8294 return this; 8295 8296 } 8297 8298 setFromPointsAndIndices(points, i0, i1, i2) { 8299 8300 this.a.copy(points[i0]); 8301 this.b.copy(points[i1]); 8302 this.c.copy(points[i2]); 8303 8304 return this; 8305 8306 } 8307 8308 setFromAttributeAndIndices(attribute, i0, i1, i2) { 8309 8310 this.a.fromBufferAttribute(attribute, i0); 8311 this.b.fromBufferAttribute(attribute, i1); 8312 this.c.fromBufferAttribute(attribute, i2); 8313 8314 return this; 8315 8316 } 8317 8318 clone() { 8319 8320 return new this.constructor().copy(this); 8321 8322 } 8323 8324 copy(triangle) { 8325 8326 this.a.copy(triangle.a); 8327 this.b.copy(triangle.b); 8328 this.c.copy(triangle.c); 8329 8330 return this; 8331 8332 } 8333 8334 getArea() { 8335 8336 _v0$1.subVectors(this.c, this.b); 8337 _v1$3.subVectors(this.a, this.b); 8338 8339 return _v0$1.cross(_v1$3).length() * 0.5; 8340 8341 } 8342 8343 getMidpoint(target) { 8344 8345 return target.addVectors(this.a, this.b).add(this.c).multiplyScalar(1 / 3); 8346 8347 } 8348 8349 getNormal(target) { 8350 8351 return Triangle.getNormal(this.a, this.b, this.c, target); 8352 8353 } 8354 8355 getPlane(target) { 8356 8357 return target.setFromCoplanarPoints(this.a, this.b, this.c); 8358 8359 } 8360 8361 getBarycoord(point, target) { 8362 8363 return Triangle.getBarycoord(point, this.a, this.b, this.c, target); 8364 8365 } 8366 8367 getUV(point, uv1, uv2, uv3, target) { // @deprecated, r151 8368 8369 if (warnedGetUV === false) { 8370 8371 console.warn('THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation().'); 8372 8373 warnedGetUV = true; 8374 8375 } 8376 8377 return Triangle.getInterpolation(point, this.a, this.b, this.c, uv1, uv2, uv3, target); 8378 8379 } 8380 8381 getInterpolation(point, v1, v2, v3, target) { 8382 8383 return Triangle.getInterpolation(point, this.a, this.b, this.c, v1, v2, v3, target); 8384 8385 } 8386 8387 containsPoint(point) { 8388 8389 return Triangle.containsPoint(point, this.a, this.b, this.c); 8390 8391 } 8392 8393 isFrontFacing(direction) { 8394 8395 return Triangle.isFrontFacing(this.a, this.b, this.c, direction); 8396 8397 } 8398 8399 intersectsBox(box) { 8400 8401 return box.intersectsTriangle(this); 8402 8403 } 8404 8405 closestPointToPoint(p, target) { 8406 8407 const a = this.a, b = this.b, c = this.c; 8408 let v, w; 8409 8410 // algorithm thanks to Real-Time Collision Detection by Christer Ericson, 8411 // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc., 8412 // under the accompanying license; see chapter 5.1.5 for detailed explanation.
vendor: 26,380 bytes, lines 8413-9456
8413 // basically, we're distinguishing which of the voronoi regions of the triangle 8414 // the point lies in with the minimum amount of redundant computation. 8415 8416 _vab.subVectors(b, a); 8417 _vac.subVectors(c, a); 8418 _vap.subVectors(p, a); 8419 const d1 = _vab.dot(_vap); 8420 const d2 = _vac.dot(_vap); 8421 if (d1 <= 0 && d2 <= 0) { 8422 8423 // vertex region of A; barycentric coords (1, 0, 0) 8424 return target.copy(a); 8425 8426 } 8427 8428 _vbp.subVectors(p, b); 8429 const d3 = _vab.dot(_vbp); 8430 const d4 = _vac.dot(_vbp); 8431 if (d3 >= 0 && d4 <= d3) { 8432 8433 // vertex region of B; barycentric coords (0, 1, 0) 8434 return target.copy(b); 8435 8436 } 8437 8438 const vc = d1 * d4 - d3 * d2; 8439 if (vc <= 0 && d1 >= 0 && d3 <= 0) { 8440 8441 v = d1 / (d1 - d3); 8442 // edge region of AB; barycentric coords (1-v, v, 0) 8443 return target.copy(a).addScaledVector(_vab, v); 8444 8445 } 8446 8447 _vcp.subVectors(p, c); 8448 const d5 = _vab.dot(_vcp); 8449 const d6 = _vac.dot(_vcp); 8450 if (d6 >= 0 && d5 <= d6) { 8451 8452 // vertex region of C; barycentric coords (0, 0, 1) 8453 return target.copy(c); 8454 8455 } 8456 8457 const vb = d5 * d2 - d1 * d6; 8458 if (vb <= 0 && d2 >= 0 && d6 <= 0) { 8459 8460 w = d2 / (d2 - d6); 8461 // edge region of AC; barycentric coords (1-w, 0, w) 8462 return target.copy(a).addScaledVector(_vac, w); 8463 8464 } 8465 8466 const va = d3 * d6 - d5 * d4; 8467 if (va <= 0 && (d4 - d3) >= 0 && (d5 - d6) >= 0) { 8468 8469 _vbc.subVectors(c, b); 8470 w = (d4 - d3) / ((d4 - d3) + (d5 - d6)); 8471 // edge region of BC; barycentric coords (0, 1-w, w) 8472 return target.copy(b).addScaledVector(_vbc, w); // edge region of BC 8473 8474 } 8475 8476 // face region 8477 const denom = 1 / (va + vb + vc); 8478 // u = va * denom 8479 v = vb * denom; 8480 w = vc * denom; 8481 8482 return target.copy(a).addScaledVector(_vab, v).addScaledVector(_vac, w); 8483 8484 } 8485 8486 equals(triangle) { 8487 8488 return triangle.a.equals(this.a) && triangle.b.equals(this.b) && triangle.c.equals(this.c); 8489 8490 } 8491 8492} 8493 8494const _colorKeywords = { 8495 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, 8496 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, 8497 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, 8498 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, 8499 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, 8500 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, 8501 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, 8502 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, 8503 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, 8504 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, 8505 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, 8506 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, 8507 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, 8508 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, 8509 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, 8510 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, 8511 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, 8512 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, 8513 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, 8514 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, 8515 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, 8516 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, 8517 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, 8518 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 8519}; 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 this.g = g; 8609 this.b = b; 8610 8611 ColorManagement.toWorkingColorSpace(this, colorSpace); 8612 8613 return this; 8614 8615 } 8616 8617 setHSL(h, s, l, colorSpace = ColorManagement.workingColorSpace) { 8618 8619 // h,s,l ranges are in 0.0 - 1.0 8620 h = euclideanModulo(h, 1); 8621 s = clamp(s, 0, 1); 8622 l = clamp(l, 0, 1); 8623 8624 if (s === 0) { 8625 8626 this.r = this.g = this.b = l; 8627 8628 } else { 8629 8630 const p = l <= 0.5 ? l * (1 + s) : l + s - (l * s); 8631 const q = (2 * l) - p; 8632 8633 this.r = hue2rgb(q, p, h + 1 / 3); 8634 this.g = hue2rgb(q, p, h); 8635 this.b = hue2rgb(q, p, h - 1 / 3); 8636 8637 } 8638 8639 ColorManagement.toWorkingColorSpace(this, colorSpace); 8640 8641 return this; 8642 8643 } 8644 8645 setStyle(style, colorSpace = SRGBColorSpace) { 8646 8647 function handleAlpha(string) { 8648 8649 if (string === undefined) return; 8650 8651 if (parseFloat(string) < 1) { 8652 8653 console.warn('THREE.Color: Alpha component of ' + style + ' will be ignored.'); 8654 8655 } 8656 8657 } 8658 8659 8660 let m; 8661 8662 if (m = /^(\w+)\(([^\)]*)\)/.exec(style)) { 8663 8664 // rgb / hsl 8665 8666 let color; 8667 const name = m[1]; 8668 const components = m[2]; 8669 8670 switch (name) { 8671 8672 case 'rgb': 8673 case 'rgba': 8674 8675 if (color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(components)) { 8676 8677 // rgb(255,0,0) rgba(255,0,0,0.5) 8678 8679 handleAlpha(color[4]); 8680 8681 return this.setRGB( 8682 Math.min(255, parseInt(color[1], 10)) / 255, 8683 Math.min(255, parseInt(color[2], 10)) / 255, 8684 Math.min(255, parseInt(color[3], 10)) / 255, 8685 colorSpace 8686 ); 8687 8688 } 8689 8690 if (color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(components)) { 8691 8692 // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5) 8693 8694 handleAlpha(color[4]); 8695 8696 return this.setRGB( 8697 Math.min(100, parseInt(color[1], 10)) / 100, 8698 Math.min(100, parseInt(color[2], 10)) / 100, 8699 Math.min(100, parseInt(color[3], 10)) / 100, 8700 colorSpace 8701 ); 8702 8703 } 8704 8705 break; 8706 8707 case 'hsl': 8708 case 'hsla': 8709 8710 if (color = /^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(components)) { 8711 8712 // hsl(120,50%,50%) hsla(120,50%,50%,0.5) 8713 8714 handleAlpha(color[4]); 8715 8716 return this.setHSL( 8717 parseFloat(color[1]) / 360, 8718 parseFloat(color[2]) / 100, 8719 parseFloat(color[3]) / 100, 8720 colorSpace 8721 ); 8722 8723 } 8724 8725 break; 8726 8727 default: 8728 8729 console.warn('THREE.Color: Unknown color model ' + style); 8730 8731 } 8732 8733 } else if (m = /^\#([A-Fa-f\d]+)$/.exec(style)) { 8734 8735 // hex color 8736 8737 const hex = m[1]; 8738 const size = hex.length; 8739 8740 if (size === 3) { 8741 8742 // #ff0 8743 return this.setRGB( 8744 parseInt(hex.charAt(0), 16) / 15, 8745 parseInt(hex.charAt(1), 16) / 15, 8746 parseInt(hex.charAt(2), 16) / 15, 8747 colorSpace 8748 ); 8749 8750 } else if (size === 6) { 8751 8752 // #ff0000 8753 return this.setHex(parseInt(hex, 16), colorSpace); 8754 8755 } else { 8756 8757 console.warn('THREE.Color: Invalid hex color ' + style); 8758 8759 } 8760 8761 } else if (style && style.length > 0) { 8762 8763 return this.setColorName(style, colorSpace); 8764 8765 } 8766 8767 return this; 8768 8769 } 8770 8771 setColorName(style, colorSpace = SRGBColorSpace) { 8772 8773 // color keywords 8774 const hex = _colorKeywords[style.toLowerCase()]; 8775 8776 if (hex !== undefined) { 8777 8778 // red 8779 this.setHex(hex, colorSpace); 8780 8781 } else { 8782 8783 // unknown color 8784 console.warn('THREE.Color: Unknown color ' + style); 8785 8786 } 8787 8788 return this; 8789 8790 } 8791 8792 clone() { 8793 8794 return new this.constructor(this.r, this.g, this.b); 8795 8796 } 8797 8798 copy(color) { 8799 8800 this.r = color.r; 8801 this.g = color.g; 8802 this.b = color.b; 8803 8804 return this; 8805 8806 } 8807 8808 copySRGBToLinear(color) { 8809 8810 this.r = SRGBToLinear(color.r); 8811 this.g = SRGBToLinear(color.g); 8812 this.b = SRGBToLinear(color.b); 8813 8814 return this; 8815 8816 } 8817 8818 copyLinearToSRGB(color) { 8819 8820 this.r = LinearToSRGB(color.r); 8821 this.g = LinearToSRGB(color.g); 8822 this.b = LinearToSRGB(color.b); 8823 8824 return this; 8825 8826 } 8827 8828 convertSRGBToLinear() { 8829 8830 this.copySRGBToLinear(this); 8831 8832 return this; 8833 8834 } 8835 8836 convertLinearToSRGB() { 8837 8838 this.copyLinearToSRGB(this); 8839 8840 return this; 8841 8842 } 8843 8844 getHex(colorSpace = SRGBColorSpace) { 8845 8846 ColorManagement.fromWorkingColorSpace(_color.copy(this), colorSpace); 8847 8848 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)); 8849 8850 } 8851 8852 getHexString(colorSpace = SRGBColorSpace) { 8853 8854 return ('000000' + this.getHex(colorSpace).toString(16)).slice(- 6); 8855 8856 } 8857 8858 getHSL(target, colorSpace = ColorManagement.workingColorSpace) { 8859 8860 // h,s,l ranges are in 0.0 - 1.0 8861 8862 ColorManagement.fromWorkingColorSpace(_color.copy(this), colorSpace); 8863 8864 const r = _color.r, g = _color.g, b = _color.b; 8865 8866 const max = Math.max(r, g, b); 8867 const min = Math.min(r, g, b); 8868 8869 let hue, saturation; 8870 const lightness = (min + max) / 2.0; 8871 8872 if (min === max) { 8873 8874 hue = 0; 8875 saturation = 0; 8876 8877 } else { 8878 8879 const delta = max - min; 8880 8881 saturation = lightness <= 0.5 ? delta / (max + min) : delta / (2 - max - min); 8882 8883 switch (max) { 8884 8885 case r: hue = (g - b) / delta + (g < b ? 6 : 0); break; 8886 case g: hue = (b - r) / delta + 2; break; 8887 case b: hue = (r - g) / delta + 4; break; 8888 8889 } 8890 8891 hue /= 6; 8892 8893 } 8894 8895 target.h = hue; 8896 target.s = saturation; 8897 target.l = lightness; 8898 8899 return target; 8900 8901 } 8902 8903 getRGB(target, colorSpace = ColorManagement.workingColorSpace) { 8904 8905 ColorManagement.fromWorkingColorSpace(_color.copy(this), colorSpace); 8906 8907 target.r = _color.r; 8908 target.g = _color.g; 8909 target.b = _color.b; 8910 8911 return target; 8912 8913 } 8914 8915 getStyle(colorSpace = SRGBColorSpace) { 8916 8917 ColorManagement.fromWorkingColorSpace(_color.copy(this), colorSpace); 8918 8919 const r = _color.r, g = _color.g, b = _color.b; 8920 8921 if (colorSpace !== SRGBColorSpace) { 8922 8923 // Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/). 8924 return `color(${colorSpace} ${r.toFixed(3)} ${g.toFixed(3)} ${b.toFixed(3)})`; 8925 8926 } 8927 8928 return `rgb(${Math.round(r * 255)},${Math.round(g * 255)},${Math.round(b * 255)})`; 8929 8930 } 8931 8932 offsetHSL(h, s, l) { 8933 8934 this.getHSL(_hslA); 8935 8936 return this.setHSL(_hslA.h + h, _hslA.s + s, _hslA.l + l); 8937 8938 } 8939 8940 add(color) { 8941 8942 this.r += color.r; 8943 this.g += color.g; 8944 this.b += color.b; 8945 8946 return this; 8947 8948 } 8949 8950 addColors(color1, color2) { 8951 8952 this.r = color1.r + color2.r; 8953 this.g = color1.g + color2.g; 8954 this.b = color1.b + color2.b; 8955 8956 return this; 8957 8958 } 8959 8960 addScalar(s) { 8961 8962 this.r += s; 8963 this.g += s; 8964 this.b += s; 8965 8966 return this; 8967 8968 } 8969 8970 sub(color) { 8971 8972 this.r = Math.max(0, this.r - color.r); 8973 this.g = Math.max(0, this.g - color.g); 8974 this.b = Math.max(0, this.b - color.b); 8975 8976 return this; 8977 8978 } 8979 8980 multiply(color) { 8981 8982 this.r *= color.r; 8983 this.g *= color.g; 8984 this.b *= color.b; 8985 8986 return this; 8987 8988 } 8989 8990 multiplyScalar(s) { 8991 8992 this.r *= s; 8993 this.g *= s; 8994 this.b *= s; 8995 8996 return this; 8997 8998 } 8999 9000 lerp(color, alpha) { 9001 9002 this.r += (color.r - this.r) * alpha; 9003 this.g += (color.g - this.g) * alpha; 9004 this.b += (color.b - this.b) * alpha; 9005 9006 return this; 9007 9008 } 9009 9010 lerpColors(color1, color2, alpha) { 9011 9012 this.r = color1.r + (color2.r - color1.r) * alpha; 9013 this.g = color1.g + (color2.g - color1.g) * alpha; 9014 this.b = color1.b + (color2.b - color1.b) * alpha; 9015 9016 return this; 9017 9018 } 9019 9020 lerpHSL(color, alpha) { 9021 9022 this.getHSL(_hslA); 9023 color.getHSL(_hslB); 9024 9025 const h = lerp(_hslA.h, _hslB.h, alpha); 9026 const s = lerp(_hslA.s, _hslB.s, alpha); 9027 const l = lerp(_hslA.l, _hslB.l, alpha); 9028 9029 this.setHSL(h, s, l); 9030 9031 return this; 9032 9033 } 9034 9035 setFromVector3(v) { 9036 9037 this.r = v.x; 9038 this.g = v.y; 9039 this.b = v.z; 9040 9041 return this; 9042 9043 } 9044 9045 applyMatrix3(m) { 9046 9047 const r = this.r, g = this.g, b = this.b; 9048 const e = m.elements; 9049 9050 this.r = e[0] * r + e[3] * g + e[6] * b; 9051 this.g = e[1] * r + e[4] * g + e[7] * b; 9052 this.b = e[2] * r + e[5] * g + e[8] * b; 9053 9054 return this; 9055 9056 } 9057 9058 equals(c) { 9059 9060 return (c.r === this.r) && (c.g === this.g) && (c.b === this.b); 9061 9062 } 9063 9064 fromArray(array, offset = 0) { 9065 9066 this.r = array[offset]; 9067 this.g = array[offset + 1]; 9068 this.b = array[offset + 2]; 9069 9070 return this; 9071 9072 } 9073 9074 toArray(array = [], offset = 0) { 9075 9076 array[offset] = this.r; 9077 array[offset + 1] = this.g; 9078 array[offset + 2] = this.b; 9079 9080 return array; 9081 9082 } 9083 9084 fromBufferAttribute(attribute, index) { 9085 9086 this.r = attribute.getX(index); 9087 this.g = attribute.getY(index); 9088 this.b = attribute.getZ(index); 9089 9090 return this; 9091 9092 } 9093 9094 toJSON() { 9095 9096 return this.getHex(); 9097 9098 } 9099 9100 *[Symbol.iterator]() { 9101 9102 yield this.r; 9103 yield this.g; 9104 yield this.b; 9105 9106 } 9107 9108} 9109 9110const _color = /*@__PURE__*/ new Color(); 9111 9112Color.NAMES = _colorKeywords; 9113 9114let _materialId = 0; 9115 9116class Material extends EventDispatcher { 9117 9118 constructor() { 9119 9120 super(); 9121 9122 this.isMaterial = true; 9123 9124 Object.defineProperty(this, 'id', { value: _materialId++ }); 9125 9126 this.uuid = generateUUID(); 9127 9128 this.name = ''; 9129 this.type = 'Material'; 9130 9131 this.blending = NormalBlending; 9132 this.side = FrontSide; 9133 this.vertexColors = false; 9134 9135 this.opacity = 1; 9136 this.transparent = false; 9137 this.alphaHash = false; 9138 9139 this.blendSrc = SrcAlphaFactor; 9140 this.blendDst = OneMinusSrcAlphaFactor; 9141 this.blendEquation = AddEquation; 9142 this.blendSrcAlpha = null; 9143 this.blendDstAlpha = null; 9144 this.blendEquationAlpha = null; 9145 this.blendColor = new Color(0, 0, 0); 9146 this.blendAlpha = 0; 9147 9148 this.depthFunc = LessEqualDepth; 9149 this.depthTest = true; 9150 this.depthWrite = true; 9151 9152 this.stencilWriteMask = 0xff; 9153 this.stencilFunc = AlwaysStencilFunc; 9154 this.stencilRef = 0; 9155 this.stencilFuncMask = 0xff; 9156 this.stencilFail = KeepStencilOp; 9157 this.stencilZFail = KeepStencilOp; 9158 this.stencilZPass = KeepStencilOp; 9159 this.stencilWrite = false; 9160 9161 this.clippingPlanes = null; 9162 this.clipIntersection = false; 9163 this.clipShadows = false; 9164 9165 this.shadowSide = null; 9166 9167 this.colorWrite = true; 9168 9169 this.precision = null; // override the renderer's default precision for this material 9170 9171 this.polygonOffset = false; 9172 this.polygonOffsetFactor = 0; 9173 this.polygonOffsetUnits = 0; 9174 9175 this.dithering = false; 9176 9177 this.alphaToCoverage = false; 9178 this.premultipliedAlpha = false; 9179 this.forceSinglePass = false; 9180 9181 this.visible = true; 9182 9183 this.toneMapped = true; 9184 9185 this.userData = {}; 9186 9187 this.version = 0; 9188 9189 this._alphaTest = 0; 9190 9191 } 9192 9193 get alphaTest() { 9194 9195 return this._alphaTest; 9196 9197 } 9198 9199 set alphaTest(value) { 9200 9201 if (this._alphaTest > 0 !== value > 0) { 9202 9203 this.version++; 9204 9205 } 9206 9207 this._alphaTest = value; 9208 9209 } 9210 9211 onBuild( /* shaderobject, renderer */) { } 9212 9213 onBeforeRender( /* renderer, scene, camera, geometry, object, group */) { } 9214 9215 onBeforeCompile( /* shaderobject, renderer */) { } 9216 9217 customProgramCacheKey() { 9218 9219 return this.onBeforeCompile.toString(); 9220 9221 } 9222 9223 setValues(values) { 9224 9225 if (values === undefined) return; 9226 9227 for (const key in values) { 9228 9229 const newValue = values[key]; 9230 9231 if (newValue === undefined) { 9232 9233 console.warn(`THREE.Material: parameter '${key}' has value of undefined.`); 9234 continue; 9235 9236 } 9237 9238 const currentValue = this[key]; 9239 9240 if (currentValue === undefined) { 9241 9242 console.warn(`THREE.Material: '${key}' is not a property of THREE.${this.type}.`); 9243 continue; 9244 9245 } 9246 9247 if (currentValue && currentValue.isColor) { 9248 9249 currentValue.set(newValue); 9250 9251 } else if ((currentValue && currentValue.isVector3) && (newValue && newValue.isVector3)) { 9252 9253 currentValue.copy(newValue); 9254 9255 } else { 9256 9257 this[key] = newValue; 9258 9259 } 9260 9261 } 9262 9263 } 9264 9265 toJSON(meta) { 9266 9267 const isRootObject = (meta === undefined || typeof meta === 'string'); 9268 9269 if (isRootObject) { 9270 9271 meta = { 9272 textures: {}, 9273 images: {} 9274 }; 9275 9276 } 9277 9278 const data = { 9279 metadata: { 9280 version: 4.6, 9281 type: 'Material', 9282 generator: 'Material.toJSON' 9283 } 9284 }; 9285 9286 // standard Material serialization 9287 data.uuid = this.uuid; 9288 data.type = this.type; 9289 9290 if (this.name !== '') data.name = this.name; 9291 9292 if (this.color && this.color.isColor) data.color = this.color.getHex(); 9293 9294 if (this.roughness !== undefined) data.roughness = this.roughness; 9295 if (this.metalness !== undefined) data.metalness = this.metalness; 9296 9297 if (this.sheen !== undefined) data.sheen = this.sheen; 9298 if (this.sheenColor && this.sheenColor.isColor) data.sheenColor = this.sheenColor.getHex(); 9299 if (this.sheenRoughness !== undefined) data.sheenRoughness = this.sheenRoughness; 9300 if (this.emissive && this.emissive.isColor) data.emissive = this.emissive.getHex(); 9301 if (this.emissiveIntensity && this.emissiveIntensity !== 1) data.emissiveIntensity = this.emissiveIntensity; 9302 9303 if (this.specular && this.specular.isColor) data.specular = this.specular.getHex(); 9304 if (this.specularIntensity !== undefined) data.specularIntensity = this.specularIntensity; 9305 if (this.specularColor && this.specularColor.isColor) data.specularColor = this.specularColor.getHex(); 9306 if (this.shininess !== undefined) data.shininess = this.shininess; 9307 if (this.clearcoat !== undefined) data.clearcoat = this.clearcoat; 9308 if (this.clearcoatRoughness !== undefined) data.clearcoatRoughness = this.clearcoatRoughness; 9309 9310 if (this.clearcoatMap && this.clearcoatMap.isTexture) { 9311 9312 data.clearcoatMap = this.clearcoatMap.toJSON(meta).uuid; 9313 9314 } 9315 9316 if (this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture) { 9317 9318 data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON(meta).uuid; 9319 9320 } 9321 9322 if (this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture) { 9323 9324 data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON(meta).uuid; 9325 data.clearcoatNormalScale = this.clearcoatNormalScale.toArray(); 9326 9327 } 9328 9329 if (this.iridescence !== undefined) data.iridescence = this.iridescence; 9330 if (this.iridescenceIOR !== undefined) data.iridescenceIOR = this.iridescenceIOR; 9331 if (this.iridescenceThicknessRange !== undefined) data.iridescenceThicknessRange = this.iridescenceThicknessRange; 9332 9333 if (this.iridescenceMap && this.iridescenceMap.isTexture) { 9334 9335 data.iridescenceMap = this.iridescenceMap.toJSON(meta).uuid; 9336 9337 } 9338 9339 if (this.iridescenceThicknessMap && this.iridescenceThicknessMap.isTexture) { 9340 9341 data.iridescenceThicknessMap = this.iridescenceThicknessMap.toJSON(meta).uuid; 9342 9343 } 9344 9345 if (this.anisotropy !== undefined) data.anisotropy = this.anisotropy; 9346 if (this.anisotropyRotation !== undefined) data.anisotropyRotation = this.anisotropyRotation; 9347 9348 if (this.anisotropyMap && this.anisotropyMap.isTexture) { 9349 9350 data.anisotropyMap = this.anisotropyMap.toJSON(meta).uuid; 9351 9352 } 9353 9354 if (this.map && this.map.isTexture) data.map = this.map.toJSON(meta).uuid; 9355 if (this.matcap && this.matcap.isTexture) data.matcap = this.matcap.toJSON(meta).uuid; 9356 if (this.alphaMap && this.alphaMap.isTexture) data.alphaMap = this.alphaMap.toJSON(meta).uuid; 9357 9358 if (this.lightMap && this.lightMap.isTexture) { 9359 9360 data.lightMap = this.lightMap.toJSON(meta).uuid; 9361 data.lightMapIntensity = this.lightMapIntensity; 9362 9363 } 9364 9365 if (this.aoMap && this.aoMap.isTexture) { 9366 9367 data.aoMap = this.aoMap.toJSON(meta).uuid; 9368 data.aoMapIntensity = this.aoMapIntensity; 9369 9370 } 9371 9372 if (this.bumpMap && this.bumpMap.isTexture) { 9373 9374 data.bumpMap = this.bumpMap.toJSON(meta).uuid; 9375 data.bumpScale = this.bumpScale; 9376 9377 } 9378 9379 if (this.normalMap && this.normalMap.isTexture) { 9380 9381 data.normalMap = this.normalMap.toJSON(meta).uuid; 9382 data.normalMapType = this.normalMapType; 9383 data.normalScale = this.normalScale.toArray(); 9384 9385 } 9386 9387 if (this.displacementMap && this.displacementMap.isTexture) { 9388 9389 data.displacementMap = this.displacementMap.toJSON(meta).uuid; 9390 data.displacementScale = this.displacementScale; 9391 data.displacementBias = this.displacementBias; 9392 9393 } 9394 9395 if (this.roughnessMap && this.roughnessMap.isTexture) data.roughnessMap = this.roughnessMap.toJSON(meta).uuid; 9396 if (this.metalnessMap && this.metalnessMap.isTexture) data.metalnessMap = this.metalnessMap.toJSON(meta).uuid; 9397 9398 if (this.emissiveMap && this.emissiveMap.isTexture) data.emissiveMap = this.emissiveMap.toJSON(meta).uuid; 9399 if (this.specularMap && this.specularMap.isTexture) data.specularMap = this.specularMap.toJSON(meta).uuid; 9400 if (this.specularIntensityMap && this.specularIntensityMap.isTexture) data.specularIntensityMap = this.specularIntensityMap.toJSON(meta).uuid; 9401 if (this.specularColorMap && this.specularColorMap.isTexture) data.specularColorMap = this.specularColorMap.toJSON(meta).uuid; 9402 9403 if (this.envMap && this.envMap.isTexture) { 9404 9405 data.envMap = this.envMap.toJSON(meta).uuid; 9406 9407 if (this.combine !== undefined) data.combine = this.combine; 9408 9409 } 9410 9411 if (this.envMapIntensity !== undefined) data.envMapIntensity = this.envMapIntensity; 9412 if (this.reflectivity !== undefined) data.reflectivity = this.reflectivity; 9413 if (this.refractionRatio !== undefined) data.refractionRatio = this.refractionRatio; 9414 9415 if (this.gradientMap && this.gradientMap.isTexture) { 9416 9417 data.gradientMap = this.gradientMap.toJSON(meta).uuid; 9418 9419 } 9420 9421 if (this.transmission !== undefined) data.transmission = this.transmission; 9422 if (this.transmissionMap && this.transmissionMap.isTexture) data.transmissionMap = this.transmissionMap.toJSON(meta).uuid; 9423 if (this.thickness !== undefined) data.thickness = this.thickness; 9424 if (this.thicknessMap && this.thicknessMap.isTexture) data.thicknessMap = this.thicknessMap.toJSON(meta).uuid; 9425 if (this.attenuationDistance !== undefined && this.attenuationDistance !== Infinity) data.attenuationDistance = this.attenuationDistance; 9426 if (this.attenuationColor !== undefined) data.attenuationColor = this.attenuationColor.getHex(); 9427 9428 if (this.size !== undefined) data.size = this.size; 9429 if (this.shadowSide !== null) data.shadowSide = this.shadowSide; 9430 if (this.sizeAttenuation !== undefined) data.sizeAttenuation = this.sizeAttenuation; 9431 9432 if (this.blending !== NormalBlending) data.blending = this.blending; 9433 if (this.side !== FrontSide) data.side = this.side; 9434 if (this.vertexColors === true) data.vertexColors = true; 9435 9436 if (this.opacity < 1) data.opacity = this.opacity; 9437 if (this.transparent === true) data.transparent = true; 9438 9439 if (this.blendSrc !== SrcAlphaFactor) data.blendSrc = this.blendSrc; 9440 if (this.blendDst !== OneMinusSrcAlphaFactor) data.blendDst = this.blendDst; 9441 if (this.blendEquation !== AddEquation) data.blendEquation = this.blendEquation; 9442 if (this.blendSrcAlpha !== null) data.blendSrcAlpha = this.blendSrcAlpha; 9443 if (this.blendDstAlpha !== null) data.blendDstAlpha = this.blendDstAlpha; 9444 if (this.blendEquationAlpha !== null) data.blendEquationAlpha = this.blendEquationAlpha; 9445 if (this.blendColor && this.blendColor.isColor) data.blendColor = this.blendColor.getHex(); 9446 if (this.blendAlpha !== 0) data.blendAlpha = this.blendAlpha; 9447 9448 if (this.depthFunc !== LessEqualDepth) data.depthFunc = this.depthFunc; 9449 if (this.depthTest === false) data.depthTest = this.depthTest; 9450 if (this.depthWrite === false) data.depthWrite = this.depthWrite; 9451 if (this.colorWrite === false) data.colorWrite = this.colorWrite; 9452 9453 if (this.stencilWriteMask !== 0xff) data.stencilWriteMask = this.stencilWriteMask; 9454 if (this.stencilFunc !== AlwaysStencilFunc) data.stencilFunc = this.stencilFunc; 9455 if (this.stencilRef !== 0) data.stencilRef = this.stencilRef; 9456 if (this.stencilFuncMask !== 0xff) data.stencilFuncMask = this.stencilFuncMask;
vendor: 3,811 bytes, lines 9457-9574
9457 if (this.stencilFail !== KeepStencilOp) data.stencilFail = this.stencilFail; 9458 if (this.stencilZFail !== KeepStencilOp) data.stencilZFail = this.stencilZFail; 9459 if (this.stencilZPass !== KeepStencilOp) data.stencilZPass = this.stencilZPass; 9460 if (this.stencilWrite === true) data.stencilWrite = this.stencilWrite; 9461 9462 // rotation (SpriteMaterial) 9463 if (this.rotation !== undefined && this.rotation !== 0) data.rotation = this.rotation; 9464 9465 if (this.polygonOffset === true) data.polygonOffset = true; 9466 if (this.polygonOffsetFactor !== 0) data.polygonOffsetFactor = this.polygonOffsetFactor; 9467 if (this.polygonOffsetUnits !== 0) data.polygonOffsetUnits = this.polygonOffsetUnits; 9468 9469 if (this.linewidth !== undefined && this.linewidth !== 1) data.linewidth = this.linewidth; 9470 if (this.dashSize !== undefined) data.dashSize = this.dashSize; 9471 if (this.gapSize !== undefined) data.gapSize = this.gapSize; 9472 if (this.scale !== undefined) data.scale = this.scale; 9473 9474 if (this.dithering === true) data.dithering = true; 9475 9476 if (this.alphaTest > 0) data.alphaTest = this.alphaTest; 9477 if (this.alphaHash === true) data.alphaHash = true; 9478 if (this.alphaToCoverage === true) data.alphaToCoverage = true; 9479 if (this.premultipliedAlpha === true) data.premultipliedAlpha = true; 9480 if (this.forceSinglePass === true) data.forceSinglePass = true; 9481 9482 if (this.wireframe === true) data.wireframe = true; 9483 if (this.wireframeLinewidth > 1) data.wireframeLinewidth = this.wireframeLinewidth; 9484 if (this.wireframeLinecap !== 'round') data.wireframeLinecap = this.wireframeLinecap; 9485 if (this.wireframeLinejoin !== 'round') data.wireframeLinejoin = this.wireframeLinejoin; 9486 9487 if (this.flatShading === true) data.flatShading = true; 9488 9489 if (this.visible === false) data.visible = false; 9490 9491 if (this.toneMapped === false) data.toneMapped = false; 9492 9493 if (this.fog === false) data.fog = false; 9494 9495 if (Object.keys(this.userData).length > 0) data.userData = this.userData; 9496 9497 // TODO: Copied from Object3D.toJSON 9498 9499 function extractFromCache(cache) { 9500 9501 const values = []; 9502 9503 for (const key in cache) { 9504 9505 const data = cache[key]; 9506 delete data.metadata; 9507 values.push(data); 9508 9509 } 9510 9511 return values; 9512 9513 } 9514 9515 if (isRootObject) { 9516 9517 const textures = extractFromCache(meta.textures); 9518 const images = extractFromCache(meta.images); 9519 9520 if (textures.length > 0) data.textures = textures; 9521 if (images.length > 0) data.images = images; 9522 9523 } 9524 9525 return data; 9526 9527 } 9528 9529 clone() { 9530 9531 return new this.constructor().copy(this); 9532 9533 } 9534 9535 copy(source) { 9536 9537 this.name = source.name; 9538 9539 this.blending = source.blending; 9540 this.side = source.side; 9541 this.vertexColors = source.vertexColors; 9542 9543 this.opacity = source.opacity; 9544 this.transparent = source.transparent; 9545 9546 this.blendSrc = source.blendSrc; 9547 this.blendDst = source.blendDst; 9548 this.blendEquation = source.blendEquation; 9549 this.blendSrcAlpha = source.blendSrcAlpha; 9550 this.blendDstAlpha = source.blendDstAlpha; 9551 this.blendEquationAlpha = source.blendEquationAlpha; 9552 this.blendColor.copy(source.blendColor); 9553 this.blendAlpha = source.blendAlpha; 9554 9555 this.depthFunc = source.depthFunc; 9556 this.depthTest = source.depthTest; 9557 this.depthWrite = source.depthWrite; 9558 9559 this.stencilWriteMask = source.stencilWriteMask; 9560 this.stencilFunc = source.stencilFunc; 9561 this.stencilRef = source.stencilRef; 9562 this.stencilFuncMask = source.stencilFuncMask; 9563 this.stencilFail = source.stencilFail; 9564 this.stencilZFail = source.stencilZFail; 9565 this.stencilZPass = source.stencilZPass; 9566 this.stencilWrite = source.stencilWrite; 9567 9568 const srcPlanes = source.clippingPlanes; 9569 let dstPlanes = null; 9570 9571 if (srcPlanes !== null) { 9572 9573 const n = srcPlanes.length; 9574 dstPlanes = new Array(n);
vendor: 7,338 bytes, lines 9575-9944
9575 9576 for (let i = 0; i !== n; ++i) { 9577 9578 dstPlanes[i] = srcPlanes[i].clone(); 9579 9580 } 9581 9582 } 9583 9584 this.clippingPlanes = dstPlanes; 9585 this.clipIntersection = source.clipIntersection; 9586 this.clipShadows = source.clipShadows; 9587 9588 this.shadowSide = source.shadowSide; 9589 9590 this.colorWrite = source.colorWrite; 9591 9592 this.precision = source.precision; 9593 9594 this.polygonOffset = source.polygonOffset; 9595 this.polygonOffsetFactor = source.polygonOffsetFactor; 9596 this.polygonOffsetUnits = source.polygonOffsetUnits; 9597 9598 this.dithering = source.dithering; 9599 9600 this.alphaTest = source.alphaTest; 9601 this.alphaHash = source.alphaHash; 9602 this.alphaToCoverage = source.alphaToCoverage; 9603 this.premultipliedAlpha = source.premultipliedAlpha; 9604 this.forceSinglePass = source.forceSinglePass; 9605 9606 this.visible = source.visible; 9607 9608 this.toneMapped = source.toneMapped; 9609 9610 this.userData = JSON.parse(JSON.stringify(source.userData)); 9611 9612 return this; 9613 9614 } 9615 9616 dispose() { 9617 9618 this.dispatchEvent({ type: 'dispose' }); 9619 9620 } 9621 9622 set needsUpdate(value) { 9623 9624 if (value === true) this.version++; 9625 9626 } 9627 9628} 9629 9630class MeshBasicMaterial extends Material { 9631 9632 constructor(parameters) { 9633 9634 super(); 9635 9636 this.isMeshBasicMaterial = true; 9637 9638 this.type = 'MeshBasicMaterial'; 9639 9640 this.color = new Color(0xffffff); // emissive 9641 9642 this.map = null; 9643 9644 this.lightMap = null; 9645 this.lightMapIntensity = 1.0; 9646 9647 this.aoMap = null; 9648 this.aoMapIntensity = 1.0; 9649 9650 this.specularMap = null; 9651 9652 this.alphaMap = null; 9653 9654 this.envMap = null; 9655 this.combine = MultiplyOperation; 9656 this.reflectivity = 1; 9657 this.refractionRatio = 0.98; 9658 9659 this.wireframe = false; 9660 this.wireframeLinewidth = 1; 9661 this.wireframeLinecap = 'round'; 9662 this.wireframeLinejoin = 'round'; 9663 9664 this.fog = true; 9665 9666 this.setValues(parameters); 9667 9668 } 9669 9670 copy(source) { 9671 9672 super.copy(source); 9673 9674 this.color.copy(source.color); 9675 9676 this.map = source.map; 9677 9678 this.lightMap = source.lightMap; 9679 this.lightMapIntensity = source.lightMapIntensity; 9680 9681 this.aoMap = source.aoMap; 9682 this.aoMapIntensity = source.aoMapIntensity; 9683 9684 this.specularMap = source.specularMap; 9685 9686 this.alphaMap = source.alphaMap; 9687 9688 this.envMap = source.envMap; 9689 this.combine = source.combine; 9690 this.reflectivity = source.reflectivity; 9691 this.refractionRatio = source.refractionRatio; 9692 9693 this.wireframe = source.wireframe; 9694 this.wireframeLinewidth = source.wireframeLinewidth; 9695 this.wireframeLinecap = source.wireframeLinecap; 9696 this.wireframeLinejoin = source.wireframeLinejoin; 9697 9698 this.fog = source.fog; 9699 9700 return this; 9701 9702 } 9703 9704} 9705 9706// Fast Half Float Conversions, http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf 9707 9708const _tables = /*@__PURE__*/ _generateTables(); 9709 9710function _generateTables() { 9711 9712 // float32 to float16 helpers 9713 9714 const buffer = new ArrayBuffer(4); 9715 const floatView = new Float32Array(buffer); 9716 const uint32View = new Uint32Array(buffer); 9717 9718 const baseTable = new Uint32Array(512); 9719 const shiftTable = new Uint32Array(512); 9720 9721 for (let i = 0; i < 256; ++i) { 9722 9723 const e = i - 127; 9724 9725 // very small number (0, -0) 9726 9727 if (e < - 27) { 9728 9729 baseTable[i] = 0x0000; 9730 baseTable[i | 0x100] = 0x8000; 9731 shiftTable[i] = 24; 9732 shiftTable[i | 0x100] = 24; 9733 9734 // small number (denorm) 9735 9736 } else if (e < - 14) { 9737 9738 baseTable[i] = 0x0400 >> (- e - 14); 9739 baseTable[i | 0x100] = (0x0400 >> (- e - 14)) | 0x8000; 9740 shiftTable[i] = - e - 1; 9741 shiftTable[i | 0x100] = - e - 1; 9742 9743 // normal number 9744 9745 } else if (e <= 15) { 9746 9747 baseTable[i] = (e + 15) << 10; 9748 baseTable[i | 0x100] = ((e + 15) << 10) | 0x8000; 9749 shiftTable[i] = 13; 9750 shiftTable[i | 0x100] = 13; 9751 9752 // large number (Infinity, -Infinity) 9753 9754 } else if (e < 128) { 9755 9756 baseTable[i] = 0x7c00; 9757 baseTable[i | 0x100] = 0xfc00; 9758 shiftTable[i] = 24; 9759 shiftTable[i | 0x100] = 24; 9760 9761 // stay (NaN, Infinity, -Infinity) 9762 9763 } else { 9764 9765 baseTable[i] = 0x7c00; 9766 baseTable[i | 0x100] = 0xfc00; 9767 shiftTable[i] = 13; 9768 shiftTable[i | 0x100] = 13; 9769 9770 } 9771 9772 } 9773 9774 // float16 to float32 helpers 9775 9776 const mantissaTable = new Uint32Array(2048); 9777 const exponentTable = new Uint32Array(64); 9778 const offsetTable = new Uint32Array(64); 9779 9780 for (let i = 1; i < 1024; ++i) { 9781 9782 let m = i << 13; // zero pad mantissa bits 9783 let e = 0; // zero exponent 9784 9785 // normalized 9786 while ((m & 0x00800000) === 0) { 9787 9788 m <<= 1; 9789 e -= 0x00800000; // decrement exponent 9790 9791 } 9792 9793 m &= ~0x00800000; // clear leading 1 bit 9794 e += 0x38800000; // adjust bias 9795 9796 mantissaTable[i] = m | e; 9797 9798 } 9799 9800 for (let i = 1024; i < 2048; ++i) { 9801 9802 mantissaTable[i] = 0x38000000 + ((i - 1024) << 13); 9803 9804 } 9805 9806 for (let i = 1; i < 31; ++i) { 9807 9808 exponentTable[i] = i << 23; 9809 9810 } 9811 9812 exponentTable[31] = 0x47800000; 9813 exponentTable[32] = 0x80000000; 9814 9815 for (let i = 33; i < 63; ++i) { 9816 9817 exponentTable[i] = 0x80000000 + ((i - 32) << 23); 9818 9819 } 9820 9821 exponentTable[63] = 0xc7800000; 9822 9823 for (let i = 1; i < 64; ++i) { 9824 9825 if (i !== 32) { 9826 9827 offsetTable[i] = 1024; 9828 9829 } 9830 9831 } 9832 9833 return { 9834 floatView: floatView, 9835 uint32View: uint32View, 9836 baseTable: baseTable, 9837 shiftTable: shiftTable, 9838 mantissaTable: mantissaTable, 9839 exponentTable: exponentTable, 9840 offsetTable: offsetTable 9841 }; 9842 9843} 9844 9845// float32 to float16 9846 9847function toHalfFloat(val) { 9848 9849 if (Math.abs(val) > 65504) console.warn('THREE.DataUtils.toHalfFloat(): Value out of range.'); 9850 9851 val = clamp(val, - 65504, 65504); 9852 9853 _tables.floatView[0] = val; 9854 const f = _tables.uint32View[0]; 9855 const e = (f >> 23) & 0x1ff; 9856 return _tables.baseTable[e] + ((f & 0x007fffff) >> _tables.shiftTable[e]); 9857 9858} 9859 9860// float16 to float32 9861 9862function fromHalfFloat(val) { 9863 9864 const m = val >> 10; 9865 _tables.uint32View[0] = _tables.mantissaTable[_tables.offsetTable[m] + (val & 0x3ff)] + _tables.exponentTable[m]; 9866 return _tables.floatView[0]; 9867 9868} 9869 9870const DataUtils = { 9871 toHalfFloat: toHalfFloat, 9872 fromHalfFloat: fromHalfFloat, 9873}; 9874 9875const _vector$9 = /*@__PURE__*/ new Vector3(); 9876const _vector2$1 = /*@__PURE__*/ new Vector2(); 9877 9878class BufferAttribute { 9879 9880 constructor(array, itemSize, normalized = false) { 9881 9882 if (Array.isArray(array)) { 9883 9884 throw new TypeError('THREE.BufferAttribute: array should be a Typed Array.'); 9885 9886 } 9887 9888 this.isBufferAttribute = true; 9889 9890 this.name = ''; 9891 9892 this.array = array; 9893 this.itemSize = itemSize; 9894 this.count = array !== undefined ? array.length / itemSize : 0; 9895 this.normalized = normalized; 9896 9897 this.usage = StaticDrawUsage; 9898 this._updateRange = { offset: 0, count: - 1 }; 9899 this.updateRanges = []; 9900 this.gpuType = FloatType; 9901 9902 this.version = 0; 9903 9904 } 9905 9906 onUploadCallback() { } 9907 9908 set needsUpdate(value) { 9909 9910 if (value === true) this.version++; 9911 9912 } 9913 9914 get updateRange() { 9915 9916 console.warn('THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.'); // @deprecated, r159 9917 return this._updateRange; 9918 9919 } 9920 9921 setUsage(value) { 9922 9923 this.usage = value; 9924 9925 return this; 9926 9927 } 9928 9929 addUpdateRange(start, count) { 9930 9931 this.updateRanges.push({ start, count }); 9932 9933 } 9934 9935 clearUpdateRanges() { 9936 9937 this.updateRanges.length = 0; 9938 9939 } 9940 9941 copy(source) { 9942 9943 this.name = source.name; 9944 this.array = new source.array.constructor(source.array);
vendor: 9,392 bytes, lines 9945-10511
9945 this.itemSize = source.itemSize; 9946 this.count = source.count; 9947 this.normalized = source.normalized; 9948 9949 this.usage = source.usage; 9950 this.gpuType = source.gpuType; 9951 9952 return this; 9953 9954 } 9955 9956 copyAt(index1, attribute, index2) { 9957 9958 index1 *= this.itemSize; 9959 index2 *= attribute.itemSize; 9960 9961 for (let i = 0, l = this.itemSize; i < l; i++) { 9962 9963 this.array[index1 + i] = attribute.array[index2 + i]; 9964 9965 } 9966 9967 return this; 9968 9969 } 9970 9971 copyArray(array) { 9972 9973 this.array.set(array); 9974 9975 return this; 9976 9977 } 9978 9979 applyMatrix3(m) { 9980 9981 if (this.itemSize === 2) { 9982 9983 for (let i = 0, l = this.count; i < l; i++) { 9984 9985 _vector2$1.fromBufferAttribute(this, i); 9986 _vector2$1.applyMatrix3(m); 9987 9988 this.setXY(i, _vector2$1.x, _vector2$1.y); 9989 9990 } 9991 9992 } else if (this.itemSize === 3) { 9993 9994 for (let i = 0, l = this.count; i < l; i++) { 9995 9996 _vector$9.fromBufferAttribute(this, i); 9997 _vector$9.applyMatrix3(m); 9998 9999 this.setXYZ(i, _vector$9.x, _vector$9.y, _vector$9.z); 10000 10001 } 10002 10003 } 10004 10005 return this; 10006 10007 } 10008 10009 applyMatrix4(m) { 10010 10011 for (let i = 0, l = this.count; i < l; i++) { 10012 10013 _vector$9.fromBufferAttribute(this, i); 10014 10015 _vector$9.applyMatrix4(m); 10016 10017 this.setXYZ(i, _vector$9.x, _vector$9.y, _vector$9.z); 10018 10019 } 10020 10021 return this; 10022 10023 } 10024 10025 applyNormalMatrix(m) { 10026 10027 for (let i = 0, l = this.count; i < l; i++) { 10028 10029 _vector$9.fromBufferAttribute(this, i); 10030 10031 _vector$9.applyNormalMatrix(m); 10032 10033 this.setXYZ(i, _vector$9.x, _vector$9.y, _vector$9.z); 10034 10035 } 10036 10037 return this; 10038 10039 } 10040 10041 transformDirection(m) { 10042 10043 for (let i = 0, l = this.count; i < l; i++) { 10044 10045 _vector$9.fromBufferAttribute(this, i); 10046 10047 _vector$9.transformDirection(m); 10048 10049 this.setXYZ(i, _vector$9.x, _vector$9.y, _vector$9.z); 10050 10051 } 10052 10053 return this; 10054 10055 } 10056 10057 set(value, offset = 0) { 10058 10059 // Matching BufferAttribute constructor, do not normalize the array. 10060 this.array.set(value, offset); 10061 10062 return this; 10063 10064 } 10065 10066 getComponent(index, component) { 10067 10068 let value = this.array[index * this.itemSize + component]; 10069 10070 if (this.normalized) value = denormalize(value, this.array); 10071 10072 return value; 10073 10074 } 10075 10076 setComponent(index, component, value) { 10077 10078 if (this.normalized) value = normalize(value, this.array); 10079 10080 this.array[index * this.itemSize + component] = value; 10081 10082 return this; 10083 10084 } 10085 10086 getX(index) { 10087 10088 let x = this.array[index * this.itemSize]; 10089 10090 if (this.normalized) x = denormalize(x, this.array); 10091 10092 return x; 10093 10094 } 10095 10096 setX(index, x) { 10097 10098 if (this.normalized) x = normalize(x, this.array); 10099 10100 this.array[index * this.itemSize] = x; 10101 10102 return this; 10103 10104 } 10105 10106 getY(index) { 10107 10108 let y = this.array[index * this.itemSize + 1]; 10109 10110 if (this.normalized) y = denormalize(y, this.array); 10111 10112 return y; 10113 10114 } 10115 10116 setY(index, y) { 10117 10118 if (this.normalized) y = normalize(y, this.array); 10119 10120 this.array[index * this.itemSize + 1] = y; 10121 10122 return this; 10123 10124 } 10125 10126 getZ(index) { 10127 10128 let z = this.array[index * this.itemSize + 2]; 10129 10130 if (this.normalized) z = denormalize(z, this.array); 10131 10132 return z; 10133 10134 } 10135 10136 setZ(index, z) { 10137 10138 if (this.normalized) z = normalize(z, this.array); 10139 10140 this.array[index * this.itemSize + 2] = z; 10141 10142 return this; 10143 10144 } 10145 10146 getW(index) { 10147 10148 let w = this.array[index * this.itemSize + 3]; 10149 10150 if (this.normalized) w = denormalize(w, this.array); 10151 10152 return w; 10153 10154 } 10155 10156 setW(index, w) { 10157 10158 if (this.normalized) w = normalize(w, this.array); 10159 10160 this.array[index * this.itemSize + 3] = w; 10161 10162 return this; 10163 10164 } 10165 10166 setXY(index, x, y) { 10167 10168 index *= this.itemSize; 10169 10170 if (this.normalized) { 10171 10172 x = normalize(x, this.array); 10173 y = normalize(y, this.array); 10174 10175 } 10176 10177 this.array[index + 0] = x; 10178 this.array[index + 1] = y; 10179 10180 return this; 10181 10182 } 10183 10184 setXYZ(index, x, y, z) { 10185 10186 index *= this.itemSize; 10187 10188 if (this.normalized) { 10189 10190 x = normalize(x, this.array); 10191 y = normalize(y, this.array); 10192 z = normalize(z, this.array); 10193 10194 } 10195 10196 this.array[index + 0] = x; 10197 this.array[index + 1] = y; 10198 this.array[index + 2] = z; 10199 10200 return this; 10201 10202 } 10203 10204 setXYZW(index, x, y, z, w) { 10205 10206 index *= this.itemSize; 10207 10208 if (this.normalized) { 10209 10210 x = normalize(x, this.array); 10211 y = normalize(y, this.array); 10212 z = normalize(z, this.array); 10213 w = normalize(w, this.array); 10214 10215 } 10216 10217 this.array[index + 0] = x; 10218 this.array[index + 1] = y; 10219 this.array[index + 2] = z; 10220 this.array[index + 3] = w; 10221 10222 return this; 10223 10224 } 10225 10226 onUpload(callback) { 10227 10228 this.onUploadCallback = callback; 10229 10230 return this; 10231 10232 } 10233 10234 clone() { 10235 10236 return new this.constructor(this.array, this.itemSize).copy(this); 10237 10238 } 10239 10240 toJSON() { 10241 10242 const data = { 10243 itemSize: this.itemSize, 10244 type: this.array.constructor.name, 10245 array: Array.from(this.array), 10246 normalized: this.normalized 10247 }; 10248 10249 if (this.name !== '') data.name = this.name; 10250 if (this.usage !== StaticDrawUsage) data.usage = this.usage; 10251 10252 return data; 10253 10254 } 10255 10256} 10257 10258// 10259 10260class Int8BufferAttribute extends BufferAttribute { 10261 10262 constructor(array, itemSize, normalized) { 10263 10264 super(new Int8Array(array), itemSize, normalized); 10265 10266 } 10267 10268} 10269 10270class Uint8BufferAttribute extends BufferAttribute { 10271 10272 constructor(array, itemSize, normalized) { 10273 10274 super(new Uint8Array(array), itemSize, normalized); 10275 10276 } 10277 10278} 10279 10280class Uint8ClampedBufferAttribute extends BufferAttribute { 10281 10282 constructor(array, itemSize, normalized) { 10283 10284 super(new Uint8ClampedArray(array), itemSize, normalized); 10285 10286 } 10287 10288} 10289 10290class Int16BufferAttribute extends BufferAttribute { 10291 10292 constructor(array, itemSize, normalized) { 10293 10294 super(new Int16Array(array), itemSize, normalized); 10295 10296 } 10297 10298} 10299 10300class Uint16BufferAttribute extends BufferAttribute { 10301 10302 constructor(array, itemSize, normalized) { 10303 10304 super(new Uint16Array(array), itemSize, normalized); 10305 10306 } 10307 10308} 10309 10310class Int32BufferAttribute extends BufferAttribute { 10311 10312 constructor(array, itemSize, normalized) { 10313 10314 super(new Int32Array(array), itemSize, normalized); 10315 10316 } 10317 10318} 10319 10320class Uint32BufferAttribute extends BufferAttribute { 10321 10322 constructor(array, itemSize, normalized) { 10323 10324 super(new Uint32Array(array), itemSize, normalized); 10325 10326 } 10327 10328} 10329 10330class Float16BufferAttribute extends BufferAttribute { 10331 10332 constructor(array, itemSize, normalized) { 10333 10334 super(new Uint16Array(array), itemSize, normalized); 10335 10336 this.isFloat16BufferAttribute = true; 10337 10338 } 10339 10340 getX(index) { 10341 10342 let x = fromHalfFloat(this.array[index * this.itemSize]); 10343 10344 if (this.normalized) x = denormalize(x, this.array); 10345 10346 return x; 10347 10348 } 10349 10350 setX(index, x) { 10351 10352 if (this.normalized) x = normalize(x, this.array); 10353 10354 this.array[index * this.itemSize] = toHalfFloat(x); 10355 10356 return this; 10357 10358 } 10359 10360 getY(index) { 10361 10362 let y = fromHalfFloat(this.array[index * this.itemSize + 1]); 10363 10364 if (this.normalized) y = denormalize(y, this.array); 10365 10366 return y; 10367 10368 } 10369 10370 setY(index, y) { 10371 10372 if (this.normalized) y = normalize(y, this.array); 10373 10374 this.array[index * this.itemSize + 1] = toHalfFloat(y); 10375 10376 return this; 10377 10378 } 10379 10380 getZ(index) { 10381 10382 let z = fromHalfFloat(this.array[index * this.itemSize + 2]); 10383 10384 if (this.normalized) z = denormalize(z, this.array); 10385 10386 return z; 10387 10388 } 10389 10390 setZ(index, z) { 10391 10392 if (this.normalized) z = normalize(z, this.array); 10393 10394 this.array[index * this.itemSize + 2] = toHalfFloat(z); 10395 10396 return this; 10397 10398 } 10399 10400 getW(index) { 10401 10402 let w = fromHalfFloat(this.array[index * this.itemSize + 3]); 10403 10404 if (this.normalized) w = denormalize(w, this.array); 10405 10406 return w; 10407 10408 } 10409 10410 setW(index, w) { 10411 10412 if (this.normalized) w = normalize(w, this.array); 10413 10414 this.array[index * this.itemSize + 3] = toHalfFloat(w); 10415 10416 return this; 10417 10418 } 10419 10420 setXY(index, x, y) { 10421 10422 index *= this.itemSize; 10423 10424 if (this.normalized) { 10425 10426 x = normalize(x, this.array); 10427 y = normalize(y, this.array); 10428 10429 } 10430 10431 this.array[index + 0] = toHalfFloat(x); 10432 this.array[index + 1] = toHalfFloat(y); 10433 10434 return this; 10435 10436 } 10437 10438 setXYZ(index, x, y, z) { 10439 10440 index *= this.itemSize; 10441 10442 if (this.normalized) { 10443 10444 x = normalize(x, this.array); 10445 y = normalize(y, this.array); 10446 z = normalize(z, this.array); 10447 10448 } 10449 10450 this.array[index + 0] = toHalfFloat(x); 10451 this.array[index + 1] = toHalfFloat(y); 10452 this.array[index + 2] = toHalfFloat(z); 10453 10454 return this; 10455 10456 } 10457 10458 setXYZW(index, x, y, z, w) { 10459 10460 index *= this.itemSize; 10461 10462 if (this.normalized) { 10463 10464 x = normalize(x, this.array); 10465 y = normalize(y, this.array); 10466 z = normalize(z, this.array); 10467 w = normalize(w, this.array); 10468 10469 } 10470 10471 this.array[index + 0] = toHalfFloat(x); 10472 this.array[index + 1] = toHalfFloat(y); 10473 this.array[index + 2] = toHalfFloat(z); 10474 this.array[index + 3] = toHalfFloat(w); 10475 10476 return this; 10477 10478 } 10479 10480} 10481 10482 10483class Float32BufferAttribute extends BufferAttribute { 10484 10485 constructor(array, itemSize, normalized) { 10486 10487 super(new Float32Array(array), itemSize, normalized); 10488 10489 } 10490 10491} 10492 10493class Float64BufferAttribute extends BufferAttribute { 10494 10495 constructor(array, itemSize, normalized) { 10496 10497 super(new Float64Array(array), itemSize, normalized); 10498 10499 } 10500 10501} 10502 10503let _id$2 = 0; 10504 10505const _m1 = /*@__PURE__*/ new Matrix4(); 10506const _obj = /*@__PURE__*/ new Object3D(); 10507const _offset = /*@__PURE__*/ new Vector3(); 10508const _box$2 = /*@__PURE__*/ new Box3(); 10509const _boxMorphTargets = /*@__PURE__*/ new Box3(); 10510const _vector$8 = /*@__PURE__*/ new Vector3(); 10511
vendor: 5,870 bytes, lines 10512-10863
10512class BufferGeometry extends EventDispatcher { 10513 10514 constructor() { 10515 10516 super(); 10517 10518 this.isBufferGeometry = true; 10519 10520 Object.defineProperty(this, 'id', { value: _id$2++ }); 10521 10522 this.uuid = generateUUID(); 10523 10524 this.name = ''; 10525 this.type = 'BufferGeometry'; 10526 10527 this.index = null; 10528 this.attributes = {}; 10529 10530 this.morphAttributes = {}; 10531 this.morphTargetsRelative = false; 10532 10533 this.groups = []; 10534 10535 this.boundingBox = null; 10536 this.boundingSphere = null; 10537 10538 this.drawRange = { start: 0, count: Infinity }; 10539 10540 this.userData = {}; 10541 10542 } 10543 10544 getIndex() { 10545 10546 return this.index; 10547 10548 } 10549 10550 setIndex(index) { 10551 10552 if (Array.isArray(index)) { 10553 10554 this.index = new (arrayNeedsUint32(index) ? Uint32BufferAttribute : Uint16BufferAttribute)(index, 1); 10555 10556 } else { 10557 10558 this.index = index; 10559 10560 } 10561 10562 return this; 10563 10564 } 10565 10566 getAttribute(name) { 10567 10568 return this.attributes[name]; 10569 10570 } 10571 10572 setAttribute(name, attribute) { 10573 10574 this.attributes[name] = attribute; 10575 10576 return this; 10577 10578 } 10579 10580 deleteAttribute(name) { 10581 10582 delete this.attributes[name]; 10583 10584 return this; 10585 10586 } 10587 10588 hasAttribute(name) { 10589 10590 return this.attributes[name] !== undefined; 10591 10592 } 10593 10594 addGroup(start, count, materialIndex = 0) { 10595 10596 this.groups.push({ 10597 10598 start: start, 10599 count: count, 10600 materialIndex: materialIndex 10601 10602 }); 10603 10604 } 10605 10606 clearGroups() { 10607 10608 this.groups = []; 10609 10610 } 10611 10612 setDrawRange(start, count) { 10613 10614 this.drawRange.start = start; 10615 this.drawRange.count = count; 10616 10617 } 10618 10619 applyMatrix4(matrix) { 10620 10621 const position = this.attributes.position; 10622 10623 if (position !== undefined) { 10624 10625 position.applyMatrix4(matrix); 10626 10627 position.needsUpdate = true; 10628 10629 } 10630 10631 const normal = this.attributes.normal; 10632 10633 if (normal !== undefined) { 10634 10635 const normalMatrix = new Matrix3().getNormalMatrix(matrix); 10636 10637 normal.applyNormalMatrix(normalMatrix); 10638 10639 normal.needsUpdate = true; 10640 10641 } 10642 10643 const tangent = this.attributes.tangent; 10644 10645 if (tangent !== undefined) { 10646 10647 tangent.transformDirection(matrix); 10648 10649 tangent.needsUpdate = true; 10650 10651 } 10652 10653 if (this.boundingBox !== null) { 10654 10655 this.computeBoundingBox(); 10656 10657 } 10658 10659 if (this.boundingSphere !== null) { 10660 10661 this.computeBoundingSphere(); 10662 10663 } 10664 10665 return this; 10666 10667 } 10668 10669 applyQuaternion(q) { 10670 10671 _m1.makeRotationFromQuaternion(q); 10672 10673 this.applyMatrix4(_m1); 10674 10675 return this; 10676 10677 } 10678 10679 rotateX(angle) { 10680 10681 // rotate geometry around world x-axis 10682 10683 _m1.makeRotationX(angle); 10684 10685 this.applyMatrix4(_m1); 10686 10687 return this; 10688 10689 } 10690 10691 rotateY(angle) { 10692 10693 // rotate geometry around world y-axis 10694 10695 _m1.makeRotationY(angle); 10696 10697 this.applyMatrix4(_m1); 10698 10699 return this; 10700 10701 } 10702 10703 rotateZ(angle) { 10704 10705 // rotate geometry around world z-axis 10706 10707 _m1.makeRotationZ(angle); 10708 10709 this.applyMatrix4(_m1); 10710 10711 return this; 10712 10713 } 10714 10715 translate(x, y, z) { 10716 10717 // translate geometry 10718 10719 _m1.makeTranslation(x, y, z); 10720 10721 this.applyMatrix4(_m1); 10722 10723 return this; 10724 10725 } 10726 10727 scale(x, y, z) { 10728 10729 // scale geometry 10730 10731 _m1.makeScale(x, y, z); 10732 10733 this.applyMatrix4(_m1); 10734 10735 return this; 10736 10737 } 10738 10739 lookAt(vector) { 10740 10741 _obj.lookAt(vector); 10742 10743 _obj.updateMatrix(); 10744 10745 this.applyMatrix4(_obj.matrix); 10746 10747 return this; 10748 10749 } 10750 10751 center() { 10752 10753 this.computeBoundingBox(); 10754 10755 this.boundingBox.getCenter(_offset).negate(); 10756 10757 this.translate(_offset.x, _offset.y, _offset.z); 10758 10759 return this; 10760 10761 } 10762 10763 setFromPoints(points) { 10764 10765 const position = []; 10766 10767 for (let i = 0, l = points.length; i < l; i++) { 10768 10769 const point = points[i]; 10770 position.push(point.x, point.y, point.z || 0); 10771 10772 } 10773 10774 this.setAttribute('position', new Float32BufferAttribute(position, 3)); 10775 10776 return this; 10777 10778 } 10779 10780 computeBoundingBox() { 10781 10782 if (this.boundingBox === null) { 10783 10784 this.boundingBox = new Box3(); 10785 10786 } 10787 10788 const position = this.attributes.position; 10789 const morphAttributesPosition = this.morphAttributes.position; 10790 10791 if (position && position.isGLBufferAttribute) { 10792 10793 console.error('THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box. Alternatively set "mesh.frustumCulled" to "false".', this); 10794 10795 this.boundingBox.set( 10796 new Vector3(- Infinity, - Infinity, - Infinity), 10797 new Vector3(+ Infinity, + Infinity, + Infinity) 10798 ); 10799 10800 return; 10801 10802 } 10803 10804 if (position !== undefined) { 10805 10806 this.boundingBox.setFromBufferAttribute(position); 10807 10808 // process morph attributes if present 10809 10810 if (morphAttributesPosition) { 10811 10812 for (let i = 0, il = morphAttributesPosition.length; i < il; i++) { 10813 10814 const morphAttribute = morphAttributesPosition[i]; 10815 _box$2.setFromBufferAttribute(morphAttribute); 10816 10817 if (this.morphTargetsRelative) { 10818 10819 _vector$8.addVectors(this.boundingBox.min, _box$2.min); 10820 this.boundingBox.expandByPoint(_vector$8); 10821 10822 _vector$8.addVectors(this.boundingBox.max, _box$2.max); 10823 this.boundingBox.expandByPoint(_vector$8); 10824 10825 } else { 10826 10827 this.boundingBox.expandByPoint(_box$2.min); 10828 this.boundingBox.expandByPoint(_box$2.max); 10829 10830 } 10831 10832 } 10833 10834 } 10835 10836 } else { 10837 10838 this.boundingBox.makeEmpty(); 10839 10840 } 10841 10842 if (isNaN(this.boundingBox.min.x) || isNaN(this.boundingBox.min.y) || isNaN(this.boundingBox.min.z)) { 10843 10844 console.error('THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this); 10845 10846 } 10847 10848 } 10849 10850 computeBoundingSphere() { 10851 10852 if (this.boundingSphere === null) { 10853 10854 this.boundingSphere = new Sphere(); 10855 10856 } 10857 10858 const position = this.attributes.position; 10859 const morphAttributesPosition = this.morphAttributes.position; 10860 10861 if (position && position.isGLBufferAttribute) { 10862 10863 console.error('THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere. Alternatively set "mesh.frustumCulled" to "fal
vendor: 5,054 bytes, lines 10863-11091
10863se".', this); 10864 10865 this.boundingSphere.set(new Vector3(), Infinity); 10866 10867 return; 10868 10869 } 10870 10871 if (position) { 10872 10873 // first, find the center of the bounding sphere 10874 10875 const center = this.boundingSphere.center; 10876 10877 _box$2.setFromBufferAttribute(position); 10878 10879 // process morph attributes if present 10880 10881 if (morphAttributesPosition) { 10882 10883 for (let i = 0, il = morphAttributesPosition.length; i < il; i++) { 10884 10885 const morphAttribute = morphAttributesPosition[i]; 10886 _boxMorphTargets.setFromBufferAttribute(morphAttribute); 10887 10888 if (this.morphTargetsRelative) { 10889 10890 _vector$8.addVectors(_box$2.min, _boxMorphTargets.min); 10891 _box$2.expandByPoint(_vector$8); 10892 10893 _vector$8.addVectors(_box$2.max, _boxMorphTargets.max); 10894 _box$2.expandByPoint(_vector$8); 10895 10896 } else { 10897 10898 _box$2.expandByPoint(_boxMorphTargets.min); 10899 _box$2.expandByPoint(_boxMorphTargets.max); 10900 10901 } 10902 10903 } 10904 10905 } 10906 10907 _box$2.getCenter(center); 10908 10909 // second, try to find a boundingSphere with a radius smaller than the 10910 // boundingSphere of the boundingBox: sqrt(3) smaller in the best case 10911 10912 let maxRadiusSq = 0; 10913 10914 for (let i = 0, il = position.count; i < il; i++) { 10915 10916 _vector$8.fromBufferAttribute(position, i); 10917 10918 maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(_vector$8)); 10919 10920 } 10921 10922 // process morph attributes if present 10923 10924 if (morphAttributesPosition) { 10925 10926 for (let i = 0, il = morphAttributesPosition.length; i < il; i++) { 10927 10928 const morphAttribute = morphAttributesPosition[i]; 10929 const morphTargetsRelative = this.morphTargetsRelative; 10930 10931 for (let j = 0, jl = morphAttribute.count; j < jl; j++) { 10932 10933 _vector$8.fromBufferAttribute(morphAttribute, j); 10934 10935 if (morphTargetsRelative) { 10936 10937 _offset.fromBufferAttribute(position, j); 10938 _vector$8.add(_offset); 10939 10940 } 10941 10942 maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(_vector$8)); 10943 10944 } 10945 10946 } 10947 10948 } 10949 10950 this.boundingSphere.radius = Math.sqrt(maxRadiusSq); 10951 10952 if (isNaN(this.boundingSphere.radius)) { 10953 10954 console.error('THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this); 10955 10956 } 10957 10958 } 10959 10960 } 10961 10962 computeTangents() { 10963 10964 const index = this.index; 10965 const attributes = this.attributes; 10966 10967 // based on http://www.terathon.com/code/tangent.html 10968 // (per vertex tangents) 10969 10970 if (index === null || 10971 attributes.position === undefined || 10972 attributes.normal === undefined || 10973 attributes.uv === undefined) { 10974 10975 console.error('THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)'); 10976 return; 10977 10978 } 10979 10980 const indices = index.array; 10981 const positions = attributes.position.array; 10982 const normals = attributes.normal.array; 10983 const uvs = attributes.uv.array; 10984 10985 const nVertices = positions.length / 3; 10986 10987 if (this.hasAttribute('tangent') === false) { 10988 10989 this.setAttribute('tangent', new BufferAttribute(new Float32Array(4 * nVertices), 4)); 10990 10991 } 10992 10993 const tangents = this.getAttribute('tangent').array; 10994 10995 const tan1 = [], tan2 = []; 10996 10997 for (let i = 0; i < nVertices; i++) { 10998 10999 tan1[i] = new Vector3(); 11000 tan2[i] = new Vector3(); 11001 11002 } 11003 11004 const vA = new Vector3(), 11005 vB = new Vector3(), 11006 vC = new Vector3(), 11007 11008 uvA = new Vector2(), 11009 uvB = new Vector2(), 11010 uvC = new Vector2(), 11011 11012 sdir = new Vector3(), 11013 tdir = new Vector3(); 11014 11015 function handleTriangle(a, b, c) { 11016 11017 vA.fromArray(positions, a * 3); 11018 vB.fromArray(positions, b * 3); 11019 vC.fromArray(positions, c * 3); 11020 11021 uvA.fromArray(uvs, a * 2); 11022 uvB.fromArray(uvs, b * 2); 11023 uvC.fromArray(uvs, c * 2); 11024 11025 vB.sub(vA); 11026 vC.sub(vA); 11027 11028 uvB.sub(uvA); 11029 uvC.sub(uvA); 11030 11031 const r = 1.0 / (uvB.x * uvC.y - uvC.x * uvB.y); 11032 11033 // silently ignore degenerate uv triangles having coincident or colinear vertices 11034 11035 if (!isFinite(r)) return; 11036 11037 sdir.copy(vB).multiplyScalar(uvC.y).addScaledVector(vC, - uvB.y).multiplyScalar(r); 11038 tdir.copy(vC).multiplyScalar(uvB.x).addScaledVector(vB, - uvC.x).multiplyScalar(r); 11039 11040 tan1[a].add(sdir); 11041 tan1[b].add(sdir); 11042 tan1[c].add(sdir); 11043 11044 tan2[a].add(tdir); 11045 tan2[b].add(tdir); 11046 tan2[c].add(tdir); 11047 11048 } 11049 11050 let groups = this.groups; 11051 11052 if (groups.length === 0) { 11053 11054 groups = [{ 11055 start: 0, 11056 count: indices.length 11057 }]; 11058 11059 } 11060 11061 for (let i = 0, il = groups.length; i < il; ++i) { 11062 11063 const group = groups[i]; 11064 11065 const start = group.start; 11066 const count = group.count; 11067 11068 for (let j = start, jl = start + count; j < jl; j += 3) { 11069 11070 handleTriangle( 11071 indices[j + 0], 11072 indices[j + 1], 11073 indices[j + 2] 11074 ); 11075 11076 } 11077 11078 } 11079 11080 const tmp = new Vector3(), tmp2 = new Vector3(); 11081 const n = new Vector3(), n2 = new Vector3(); 11082 11083 function handleVertex(v) { 11084 11085 n.fromArray(normals, v * 3); 11086 n2.copy(n); 11087 11088 const t = tan1[v]; 11089 11090 // Gram-Schmidt orthogonalize 11091
vendor: 4,638 bytes, lines 11092-11303
11092 tmp.copy(t); 11093 tmp.sub(n.multiplyScalar(n.dot(t))).normalize(); 11094 11095 // Calculate handedness 11096 11097 tmp2.crossVectors(n2, t); 11098 const test = tmp2.dot(tan2[v]); 11099 const w = (test < 0.0) ? - 1.0 : 1.0; 11100 11101 tangents[v * 4] = tmp.x; 11102 tangents[v * 4 + 1] = tmp.y; 11103 tangents[v * 4 + 2] = tmp.z; 11104 tangents[v * 4 + 3] = w; 11105 11106 } 11107 11108 for (let i = 0, il = groups.length; i < il; ++i) { 11109 11110 const group = groups[i]; 11111 11112 const start = group.start; 11113 const count = group.count; 11114 11115 for (let j = start, jl = start + count; j < jl; j += 3) { 11116 11117 handleVertex(indices[j + 0]); 11118 handleVertex(indices[j + 1]); 11119 handleVertex(indices[j + 2]); 11120 11121 } 11122 11123 } 11124 11125 } 11126 11127 computeVertexNormals() { 11128 11129 const index = this.index; 11130 const positionAttribute = this.getAttribute('position'); 11131 11132 if (positionAttribute !== undefined) { 11133 11134 let normalAttribute = this.getAttribute('normal'); 11135 11136 if (normalAttribute === undefined) { 11137 11138 normalAttribute = new BufferAttribute(new Float32Array(positionAttribute.count * 3), 3); 11139 this.setAttribute('normal', normalAttribute); 11140 11141 } else { 11142 11143 // reset existing normals to zero 11144 11145 for (let i = 0, il = normalAttribute.count; i < il; i++) { 11146 11147 normalAttribute.setXYZ(i, 0, 0, 0); 11148 11149 } 11150 11151 } 11152 11153 const pA = new Vector3(), pB = new Vector3(), pC = new Vector3(); 11154 const nA = new Vector3(), nB = new Vector3(), nC = new Vector3(); 11155 const cb = new Vector3(), ab = new Vector3(); 11156 11157 // indexed elements 11158 11159 if (index) { 11160 11161 for (let i = 0, il = index.count; i < il; i += 3) { 11162 11163 const vA = index.getX(i + 0); 11164 const vB = index.getX(i + 1); 11165 const vC = index.getX(i + 2); 11166 11167 pA.fromBufferAttribute(positionAttribute, vA); 11168 pB.fromBufferAttribute(positionAttribute, vB); 11169 pC.fromBufferAttribute(positionAttribute, vC); 11170 11171 cb.subVectors(pC, pB); 11172 ab.subVectors(pA, pB); 11173 cb.cross(ab); 11174 11175 nA.fromBufferAttribute(normalAttribute, vA); 11176 nB.fromBufferAttribute(normalAttribute, vB); 11177 nC.fromBufferAttribute(normalAttribute, vC); 11178 11179 nA.add(cb); 11180 nB.add(cb); 11181 nC.add(cb); 11182 11183 normalAttribute.setXYZ(vA, nA.x, nA.y, nA.z); 11184 normalAttribute.setXYZ(vB, nB.x, nB.y, nB.z); 11185 normalAttribute.setXYZ(vC, nC.x, nC.y, nC.z); 11186 11187 } 11188 11189 } else { 11190 11191 // non-indexed elements (unconnected triangle soup) 11192 11193 for (let i = 0, il = positionAttribute.count; i < il; i += 3) { 11194 11195 pA.fromBufferAttribute(positionAttribute, i + 0); 11196 pB.fromBufferAttribute(positionAttribute, i + 1); 11197 pC.fromBufferAttribute(positionAttribute, i + 2); 11198 11199 cb.subVectors(pC, pB); 11200 ab.subVectors(pA, pB); 11201 cb.cross(ab); 11202 11203 normalAttribute.setXYZ(i + 0, cb.x, cb.y, cb.z); 11204 normalAttribute.setXYZ(i + 1, cb.x, cb.y, cb.z); 11205 normalAttribute.setXYZ(i + 2, cb.x, cb.y, cb.z); 11206 11207 } 11208 11209 } 11210 11211 this.normalizeNormals(); 11212 11213 normalAttribute.needsUpdate = true; 11214 11215 } 11216 11217 } 11218 11219 normalizeNormals() { 11220 11221 const normals = this.attributes.normal; 11222 11223 for (let i = 0, il = normals.count; i < il; i++) { 11224 11225 _vector$8.fromBufferAttribute(normals, i); 11226 11227 _vector$8.normalize(); 11228 11229 normals.setXYZ(i, _vector$8.x, _vector$8.y, _vector$8.z); 11230 11231 } 11232 11233 } 11234 11235 toNonIndexed() { 11236 11237 function convertBufferAttribute(attribute, indices) { 11238 11239 const array = attribute.array; 11240 const itemSize = attribute.itemSize; 11241 const normalized = attribute.normalized; 11242 11243 const array2 = new array.constructor(indices.length * itemSize); 11244 11245 let index = 0, index2 = 0; 11246 11247 for (let i = 0, l = indices.length; i < l; i++) { 11248 11249 if (attribute.isInterleavedBufferAttribute) { 11250 11251 index = indices[i] * attribute.data.stride + attribute.offset; 11252 11253 } else { 11254 11255 index = indices[i] * itemSize; 11256 11257 } 11258 11259 for (let j = 0; j < itemSize; j++) { 11260 11261 array2[index2++] = array[index++]; 11262 11263 } 11264 11265 } 11266 11267 return new BufferAttribute(array2, itemSize, normalized); 11268 11269 } 11270 11271 // 11272 11273 if (this.index === null) { 11274 11275 console.warn('THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.'); 11276 return this; 11277 11278 } 11279 11280 const geometry2 = new BufferGeometry(); 11281 11282 const indices = this.index.array; 11283 const attributes = this.attributes; 11284 11285 // attributes 11286 11287 for (const name in attributes) { 11288 11289 const attribute = attributes[name]; 11290 11291 const newAttribute = convertBufferAttribute(attribute, indices); 11292 11293 geometry2.setAttribute(name, newAttribute); 11294 11295 } 11296 11297 // morph attributes 11298 11299 const morphAttributes = this.morphAttributes; 11300 11301 for (const name in morphAttributes) { 11302 11303 const morphArray = [];
vendor: 6,640 bytes, lines 11304-11641
11304 const morphAttribute = morphAttributes[name]; // morphAttribute: array of Float32BufferAttributes 11305 11306 for (let i = 0, il = morphAttribute.length; i < il; i++) { 11307 11308 const attribute = morphAttribute[i]; 11309 11310 const newAttribute = convertBufferAttribute(attribute, indices); 11311 11312 morphArray.push(newAttribute); 11313 11314 } 11315 11316 geometry2.morphAttributes[name] = morphArray; 11317 11318 } 11319 11320 geometry2.morphTargetsRelative = this.morphTargetsRelative; 11321 11322 // groups 11323 11324 const groups = this.groups; 11325 11326 for (let i = 0, l = groups.length; i < l; i++) { 11327 11328 const group = groups[i]; 11329 geometry2.addGroup(group.start, group.count, group.materialIndex); 11330 11331 } 11332 11333 return geometry2; 11334 11335 } 11336 11337 toJSON() { 11338 11339 const data = { 11340 metadata: { 11341 version: 4.6, 11342 type: 'BufferGeometry', 11343 generator: 'BufferGeometry.toJSON' 11344 } 11345 }; 11346 11347 // standard BufferGeometry serialization 11348 11349 data.uuid = this.uuid; 11350 data.type = this.type; 11351 if (this.name !== '') data.name = this.name; 11352 if (Object.keys(this.userData).length > 0) data.userData = this.userData; 11353 11354 if (this.parameters !== undefined) { 11355 11356 const parameters = this.parameters; 11357 11358 for (const key in parameters) { 11359 11360 if (parameters[key] !== undefined) data[key] = parameters[key]; 11361 11362 } 11363 11364 return data; 11365 11366 } 11367 11368 // for simplicity the code assumes attributes are not shared across geometries, see #15811 11369 11370 data.data = { attributes: {} }; 11371 11372 const index = this.index; 11373 11374 if (index !== null) { 11375 11376 data.data.index = { 11377 type: index.array.constructor.name, 11378 array: Array.prototype.slice.call(index.array) 11379 }; 11380 11381 } 11382 11383 const attributes = this.attributes; 11384 11385 for (const key in attributes) { 11386 11387 const attribute = attributes[key]; 11388 11389 data.data.attributes[key] = attribute.toJSON(data.data); 11390 11391 } 11392 11393 const morphAttributes = {}; 11394 let hasMorphAttributes = false; 11395 11396 for (const key in this.morphAttributes) { 11397 11398 const attributeArray = this.morphAttributes[key]; 11399 11400 const array = []; 11401 11402 for (let i = 0, il = attributeArray.length; i < il; i++) { 11403 11404 const attribute = attributeArray[i]; 11405 11406 array.push(attribute.toJSON(data.data)); 11407 11408 } 11409 11410 if (array.length > 0) { 11411 11412 morphAttributes[key] = array; 11413 11414 hasMorphAttributes = true; 11415 11416 } 11417 11418 } 11419 11420 if (hasMorphAttributes) { 11421 11422 data.data.morphAttributes = morphAttributes; 11423 data.data.morphTargetsRelative = this.morphTargetsRelative; 11424 11425 } 11426 11427 const groups = this.groups; 11428 11429 if (groups.length > 0) { 11430 11431 data.data.groups = JSON.parse(JSON.stringify(groups)); 11432 11433 } 11434 11435 const boundingSphere = this.boundingSphere; 11436 11437 if (boundingSphere !== null) { 11438 11439 data.data.boundingSphere = { 11440 center: boundingSphere.center.toArray(), 11441 radius: boundingSphere.radius 11442 }; 11443 11444 } 11445 11446 return data; 11447 11448 } 11449 11450 clone() { 11451 11452 return new this.constructor().copy(this); 11453 11454 } 11455 11456 copy(source) { 11457 11458 // reset 11459 11460 this.index = null; 11461 this.attributes = {}; 11462 this.morphAttributes = {}; 11463 this.groups = []; 11464 this.boundingBox = null; 11465 this.boundingSphere = null; 11466 11467 // used for storing cloned, shared data 11468 11469 const data = {}; 11470 11471 // name 11472 11473 this.name = source.name; 11474 11475 // index 11476 11477 const index = source.index; 11478 11479 if (index !== null) { 11480 11481 this.setIndex(index.clone(data)); 11482 11483 } 11484 11485 // attributes 11486 11487 const attributes = source.attributes; 11488 11489 for (const name in attributes) { 11490 11491 const attribute = attributes[name]; 11492 this.setAttribute(name, attribute.clone(data)); 11493 11494 } 11495 11496 // morph attributes 11497 11498 const morphAttributes = source.morphAttributes; 11499 11500 for (const name in morphAttributes) { 11501 11502 const array = []; 11503 const morphAttribute = morphAttributes[name]; // morphAttribute: array of Float32BufferAttributes 11504 11505 for (let i = 0, l = morphAttribute.length; i < l; i++) { 11506 11507 array.push(morphAttribute[i].clone(data)); 11508 11509 } 11510 11511 this.morphAttributes[name] = array; 11512 11513 } 11514 11515 this.morphTargetsRelative = source.morphTargetsRelative; 11516 11517 // groups 11518 11519 const groups = source.groups; 11520 11521 for (let i = 0, l = groups.length; i < l; i++) { 11522 11523 const group = groups[i]; 11524 this.addGroup(group.start, group.count, group.materialIndex); 11525 11526 } 11527 11528 // bounding box 11529 11530 const boundingBox = source.boundingBox; 11531 11532 if (boundingBox !== null) { 11533 11534 this.boundingBox = boundingBox.clone(); 11535 11536 } 11537 11538 // bounding sphere 11539 11540 const boundingSphere = source.boundingSphere; 11541 11542 if (boundingSphere !== null) { 11543 11544 this.boundingSphere = boundingSphere.clone(); 11545 11546 } 11547 11548 // draw range 11549 11550 this.drawRange.start = source.drawRange.start; 11551 this.drawRange.count = source.drawRange.count; 11552 11553 // user data 11554 11555 this.userData = source.userData; 11556 11557 return this; 11558 11559 } 11560 11561 dispose() { 11562 11563 this.dispatchEvent({ type: 'dispose' }); 11564 11565 } 11566 11567} 11568 11569const _inverseMatrix$3 = /*@__PURE__*/ new Matrix4(); 11570const _ray$3 = /*@__PURE__*/ new Ray(); 11571const _sphere$6 = /*@__PURE__*/ new Sphere(); 11572const _sphereHitAt = /*@__PURE__*/ new Vector3(); 11573 11574const _vA$1 = /*@__PURE__*/ new Vector3(); 11575const _vB$1 = /*@__PURE__*/ new Vector3(); 11576const _vC$1 = /*@__PURE__*/ new Vector3(); 11577 11578const _tempA = /*@__PURE__*/ new Vector3(); 11579const _morphA = /*@__PURE__*/ new Vector3(); 11580 11581const _uvA$1 = /*@__PURE__*/ new Vector2(); 11582const _uvB$1 = /*@__PURE__*/ new Vector2(); 11583const _uvC$1 = /*@__PURE__*/ new Vector2(); 11584 11585const _normalA = /*@__PURE__*/ new Vector3(); 11586const _normalB = /*@__PURE__*/ new Vector3(); 11587const _normalC = /*@__PURE__*/ new Vector3(); 11588 11589const _intersectionPoint = /*@__PURE__*/ new Vector3(); 11590const _intersectionPointWorld = /*@__PURE__*/ new Vector3(); 11591 11592class Mesh extends Object3D { 11593 11594 constructor(geometry = new BufferGeometry(), material = new MeshBasicMaterial()) { 11595 11596 super(); 11597 11598 this.isMesh = true; 11599 11600 this.type = 'Mesh'; 11601 11602 this.geometry = geometry; 11603 this.material = material; 11604 11605 this.updateMorphTargets(); 11606 11607 } 11608 11609 copy(source, recursive) { 11610 11611 super.copy(source, recursive); 11612 11613 if (source.morphTargetInfluences !== undefined) { 11614 11615 this.morphTargetInfluences = source.morphTargetInfluences.slice(); 11616 11617 } 11618 11619 if (source.morphTargetDictionary !== undefined) { 11620 11621 this.morphTargetDictionary = Object.assign({}, source.morphTargetDictionary); 11622 11623 } 11624 11625 this.material = Array.isArray(source.material) ? source.material.slice() : source.material; 11626 this.geometry = source.geometry; 11627 11628 return this; 11629 11630 } 11631 11632 updateMorphTargets() { 11633 11634 const geometry = this.geometry; 11635 11636 const morphAttributes = geometry.morphAttributes; 11637 const keys = Object.keys(morphAttributes); 11638 11639 if (keys.length > 0) { 11640 11641 const morphAttribute = morphAttributes[keys[0]];
vendor: 7,934 bytes, lines 11642-11957
11642 11643 if (morphAttribute !== undefined) { 11644 11645 this.morphTargetInfluences = []; 11646 this.morphTargetDictionary = {}; 11647 11648 for (let m = 0, ml = morphAttribute.length; m < ml; m++) { 11649 11650 const name = morphAttribute[m].name || String(m); 11651 11652 this.morphTargetInfluences.push(0); 11653 this.morphTargetDictionary[name] = m; 11654 11655 } 11656 11657 } 11658 11659 } 11660 11661 } 11662 11663 getVertexPosition(index, target) { 11664 11665 const geometry = this.geometry; 11666 const position = geometry.attributes.position; 11667 const morphPosition = geometry.morphAttributes.position; 11668 const morphTargetsRelative = geometry.morphTargetsRelative; 11669 11670 target.fromBufferAttribute(position, index); 11671 11672 const morphInfluences = this.morphTargetInfluences; 11673 11674 if (morphPosition && morphInfluences) { 11675 11676 _morphA.set(0, 0, 0); 11677 11678 for (let i = 0, il = morphPosition.length; i < il; i++) { 11679 11680 const influence = morphInfluences[i]; 11681 const morphAttribute = morphPosition[i]; 11682 11683 if (influence === 0) continue; 11684 11685 _tempA.fromBufferAttribute(morphAttribute, index); 11686 11687 if (morphTargetsRelative) { 11688 11689 _morphA.addScaledVector(_tempA, influence); 11690 11691 } else { 11692 11693 _morphA.addScaledVector(_tempA.sub(target), influence); 11694 11695 } 11696 11697 } 11698 11699 target.add(_morphA); 11700 11701 } 11702 11703 return target; 11704 11705 } 11706 11707 raycast(raycaster, intersects) { 11708 11709 const geometry = this.geometry; 11710 const material = this.material; 11711 const matrixWorld = this.matrixWorld; 11712 11713 if (material === undefined) return; 11714 11715 // test with bounding sphere in world space 11716 11717 if (geometry.boundingSphere === null) geometry.computeBoundingSphere(); 11718 11719 _sphere$6.copy(geometry.boundingSphere); 11720 _sphere$6.applyMatrix4(matrixWorld); 11721 11722 // check distance from ray origin to bounding sphere 11723 11724 _ray$3.copy(raycaster.ray).recast(raycaster.near); 11725 11726 if (_sphere$6.containsPoint(_ray$3.origin) === false) { 11727 11728 if (_ray$3.intersectSphere(_sphere$6, _sphereHitAt) === null) return; 11729 11730 if (_ray$3.origin.distanceToSquared(_sphereHitAt) > (raycaster.far - raycaster.near) ** 2) return; 11731 11732 } 11733 11734 // convert ray to local space of mesh 11735 11736 _inverseMatrix$3.copy(matrixWorld).invert(); 11737 _ray$3.copy(raycaster.ray).applyMatrix4(_inverseMatrix$3); 11738 11739 // test with bounding box in local space 11740 11741 if (geometry.boundingBox !== null) { 11742 11743 if (_ray$3.intersectsBox(geometry.boundingBox) === false) return; 11744 11745 } 11746 11747 // test for intersections with geometry 11748 11749 this._computeIntersections(raycaster, intersects, _ray$3); 11750 11751 } 11752 11753 _computeIntersections(raycaster, intersects, rayLocalSpace) { 11754 11755 let intersection; 11756 11757 const geometry = this.geometry; 11758 const material = this.material; 11759 11760 const index = geometry.index; 11761 const position = geometry.attributes.position; 11762 const uv = geometry.attributes.uv; 11763 const uv1 = geometry.attributes.uv1; 11764 const normal = geometry.attributes.normal; 11765 const groups = geometry.groups; 11766 const drawRange = geometry.drawRange; 11767 11768 if (index !== null) { 11769 11770 // indexed buffer geometry 11771 11772 if (Array.isArray(material)) { 11773 11774 for (let i = 0, il = groups.length; i < il; i++) { 11775 11776 const group = groups[i]; 11777 const groupMaterial = material[group.materialIndex]; 11778 11779 const start = Math.max(group.start, drawRange.start); 11780 const end = Math.min(index.count, Math.min((group.start + group.count), (drawRange.start + drawRange.count))); 11781 11782 for (let j = start, jl = end; j < jl; j += 3) { 11783 11784 const a = index.getX(j); 11785 const b = index.getX(j + 1); 11786 const c = index.getX(j + 2); 11787 11788 intersection = checkGeometryIntersection(this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c); 11789 11790 if (intersection) { 11791 11792 intersection.faceIndex = Math.floor(j / 3); // triangle number in indexed buffer semantics 11793 intersection.face.materialIndex = group.materialIndex; 11794 intersects.push(intersection); 11795 11796 } 11797 11798 } 11799 11800 } 11801 11802 } else { 11803 11804 const start = Math.max(0, drawRange.start); 11805 const end = Math.min(index.count, (drawRange.start + drawRange.count)); 11806 11807 for (let i = start, il = end; i < il; i += 3) { 11808 11809 const a = index.getX(i); 11810 const b = index.getX(i + 1); 11811 const c = index.getX(i + 2); 11812 11813 intersection = checkGeometryIntersection(this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c); 11814 11815 if (intersection) { 11816 11817 intersection.faceIndex = Math.floor(i / 3); // triangle number in indexed buffer semantics 11818 intersects.push(intersection); 11819 11820 } 11821 11822 } 11823 11824 } 11825 11826 } else if (position !== undefined) { 11827 11828 // non-indexed buffer geometry 11829 11830 if (Array.isArray(material)) { 11831 11832 for (let i = 0, il = groups.length; i < il; i++) { 11833 11834 const group = groups[i]; 11835 const groupMaterial = material[group.materialIndex]; 11836 11837 const start = Math.max(group.start, drawRange.start); 11838 const end = Math.min(position.count, Math.min((group.start + group.count), (drawRange.start + drawRange.count))); 11839 11840 for (let j = start, jl = end; j < jl; j += 3) { 11841 11842 const a = j; 11843 const b = j + 1; 11844 const c = j + 2; 11845 11846 intersection = checkGeometryIntersection(this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c); 11847 11848 if (intersection) { 11849 11850 intersection.faceIndex = Math.floor(j / 3); // triangle number in non-indexed buffer semantics 11851 intersection.face.materialIndex = group.materialIndex; 11852 intersects.push(intersection); 11853 11854 } 11855 11856 } 11857 11858 } 11859 11860 } else { 11861 11862 const start = Math.max(0, drawRange.start); 11863 const end = Math.min(position.count, (drawRange.start + drawRange.count)); 11864 11865 for (let i = start, il = end; i < il; i += 3) { 11866 11867 const a = i; 11868 const b = i + 1; 11869 const c = i + 2; 11870 11871 intersection = checkGeometryIntersection(this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c); 11872 11873 if (intersection) { 11874 11875 intersection.faceIndex = Math.floor(i / 3); // triangle number in non-indexed buffer semantics 11876 intersects.push(intersection); 11877 11878 } 11879 11880 } 11881 11882 } 11883 11884 } 11885 11886 } 11887 11888} 11889 11890function checkIntersection(object, material, raycaster, ray, pA, pB, pC, point) { 11891 11892 let intersect; 11893 11894 if (material.side === BackSide) { 11895 11896 intersect = ray.intersectTriangle(pC, pB, pA, true, point); 11897 11898 } else { 11899 11900 intersect = ray.intersectTriangle(pA, pB, pC, (material.side === FrontSide), point); 11901 11902 } 11903 11904 if (intersect === null) return null; 11905 11906 _intersectionPointWorld.copy(point); 11907 _intersectionPointWorld.applyMatrix4(object.matrixWorld); 11908 11909 const distance = raycaster.ray.origin.distanceTo(_intersectionPointWorld); 11910 11911 if (distance < raycaster.near || distance > raycaster.far) return null; 11912 11913 return { 11914 distance: distance, 11915 point: _intersectionPointWorld.clone(), 11916 object: object 11917 }; 11918 11919} 11920 11921function checkGeometryIntersection(object, material, raycaster, ray, uv, uv1, normal, a, b, c) { 11922 11923 object.getVertexPosition(a, _vA$1); 11924 object.getVertexPosition(b, _vB$1); 11925 object.getVertexPosition(c, _vC$1); 11926 11927 const intersection = checkIntersection(object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint); 11928 11929 if (intersection) { 11930 11931 if (uv) { 11932 11933 _uvA$1.fromBufferAttribute(uv, a); 11934 _uvB$1.fromBufferAttribute(uv, b); 11935 _uvC$1.fromBufferAttribute(uv, c); 11936 11937 intersection.uv = Triangle.getInterpolation(_intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2()); 11938 11939 } 11940 11941 if (uv1) { 11942 11943 _uvA$1.fromBufferAttribute(uv1, a); 11944 _uvB$1.fromBufferAttribute(uv1, b); 11945 _uvC$1.fromBufferAttribute(uv1, c); 11946 11947 intersection.uv1 = Triangle.getInterpolation(_intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2()); 11948 intersection.uv2 = intersection.uv1; // @deprecated, r152 11949 11950 } 11951 11952 if (normal) { 11953 11954 _normalA.fromBufferAttribute(normal, a); 11955 _normalB.fromBufferAttribute(normal, b); 11956 _normalC.fromBufferAttribute(normal, c); 11957
vendor: 42,323 bytes, lines 11958-13846
11958 intersection.normal = Triangle.getInterpolation(_intersectionPoint, _vA$1, _vB$1, _vC$1, _normalA, _normalB, _normalC, new Vector3()); 11959 11960 if (intersection.normal.dot(ray.direction) > 0) { 11961 11962 intersection.normal.multiplyScalar(- 1); 11963 11964 } 11965 11966 } 11967 11968 const face = { 11969 a: a, 11970 b: b, 11971 c: c, 11972 normal: new Vector3(), 11973 materialIndex: 0 11974 }; 11975 11976 Triangle.getNormal(_vA$1, _vB$1, _vC$1, face.normal); 11977 11978 intersection.face = face; 11979 11980 } 11981 11982 return intersection; 11983 11984} 11985 11986class BoxGeometry extends BufferGeometry { 11987 11988 constructor(width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1) { 11989 11990 super(); 11991 11992 this.type = 'BoxGeometry'; 11993 11994 this.parameters = { 11995 width: width, 11996 height: height, 11997 depth: depth, 11998 widthSegments: widthSegments, 11999 heightSegments: heightSegments, 12000 depthSegments: depthSegments 12001 }; 12002 12003 const scope = this; 12004 12005 // segments 12006 12007 widthSegments = Math.floor(widthSegments); 12008 heightSegments = Math.floor(heightSegments); 12009 depthSegments = Math.floor(depthSegments); 12010 12011 // buffers 12012 12013 const indices = []; 12014 const vertices = []; 12015 const normals = []; 12016 const uvs = []; 12017 12018 // helper variables 12019 12020 let numberOfVertices = 0; 12021 let groupStart = 0; 12022 12023 // build each side of the box geometry 12024 12025 buildPlane('z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0); // px 12026 buildPlane('z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1); // nx 12027 buildPlane('x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2); // py 12028 buildPlane('x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3); // ny 12029 buildPlane('x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4); // pz 12030 buildPlane('x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5); // nz 12031 12032 // build geometry 12033 12034 this.setIndex(indices); 12035 this.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 12036 this.setAttribute('normal', new Float32BufferAttribute(normals, 3)); 12037 this.setAttribute('uv', new Float32BufferAttribute(uvs, 2)); 12038 12039 function buildPlane(u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex) { 12040 12041 const segmentWidth = width / gridX; 12042 const segmentHeight = height / gridY; 12043 12044 const widthHalf = width / 2; 12045 const heightHalf = height / 2; 12046 const depthHalf = depth / 2; 12047 12048 const gridX1 = gridX + 1; 12049 const gridY1 = gridY + 1; 12050 12051 let vertexCounter = 0; 12052 let groupCount = 0; 12053 12054 const vector = new Vector3(); 12055 12056 // generate vertices, normals and uvs 12057 12058 for (let iy = 0; iy < gridY1; iy++) { 12059 12060 const y = iy * segmentHeight - heightHalf; 12061 12062 for (let ix = 0; ix < gridX1; ix++) { 12063 12064 const x = ix * segmentWidth - widthHalf; 12065 12066 // set values to correct vector component 12067 12068 vector[u] = x * udir; 12069 vector[v] = y * vdir; 12070 vector[w] = depthHalf; 12071 12072 // now apply vector to vertex buffer 12073 12074 vertices.push(vector.x, vector.y, vector.z); 12075 12076 // set values to correct vector component 12077 12078 vector[u] = 0; 12079 vector[v] = 0; 12080 vector[w] = depth > 0 ? 1 : - 1; 12081 12082 // now apply vector to normal buffer 12083 12084 normals.push(vector.x, vector.y, vector.z); 12085 12086 // uvs 12087 12088 uvs.push(ix / gridX); 12089 uvs.push(1 - (iy / gridY)); 12090 12091 // counters 12092 12093 vertexCounter += 1; 12094 12095 } 12096 12097 } 12098 12099 // indices 12100 12101 // 1. you need three indices to draw a single face 12102 // 2. a single segment consists of two faces 12103 // 3. so we need to generate six (2*3) indices per segment 12104 12105 for (let iy = 0; iy < gridY; iy++) { 12106 12107 for (let ix = 0; ix < gridX; ix++) { 12108 12109 const a = numberOfVertices + ix + gridX1 * iy; 12110 const b = numberOfVertices + ix + gridX1 * (iy + 1); 12111 const c = numberOfVertices + (ix + 1) + gridX1 * (iy + 1); 12112 const d = numberOfVertices + (ix + 1) + gridX1 * iy; 12113 12114 // faces 12115 12116 indices.push(a, b, d); 12117 indices.push(b, c, d); 12118 12119 // increase counter 12120 12121 groupCount += 6; 12122 12123 } 12124 12125 } 12126 12127 // add a group to the geometry. this will ensure multi material support 12128 12129 scope.addGroup(groupStart, groupCount, materialIndex); 12130 12131 // calculate new start value for groups 12132 12133 groupStart += groupCount; 12134 12135 // update total number of vertices 12136 12137 numberOfVertices += vertexCounter; 12138 12139 } 12140 12141 } 12142 12143 copy(source) { 12144 12145 super.copy(source); 12146 12147 this.parameters = Object.assign({}, source.parameters); 12148 12149 return this; 12150 12151 } 12152 12153 static fromJSON(data) { 12154 12155 return new BoxGeometry(data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments); 12156 12157 } 12158 12159} 12160 12161/** 12162 * Uniform Utilities 12163 */ 12164 12165function cloneUniforms(src) { 12166 12167 const dst = {}; 12168 12169 for (const u in src) { 12170 12171 dst[u] = {}; 12172 12173 for (const p in src[u]) { 12174 12175 const property = src[u][p]; 12176 12177 if (property && (property.isColor || 12178 property.isMatrix3 || property.isMatrix4 || 12179 property.isVector2 || property.isVector3 || property.isVector4 || 12180 property.isTexture || property.isQuaternion)) { 12181 12182 if (property.isRenderTargetTexture) { 12183 12184 console.warn('UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().'); 12185 dst[u][p] = null; 12186 12187 } else { 12188 12189 dst[u][p] = property.clone(); 12190 12191 } 12192 12193 } else if (Array.isArray(property)) { 12194 12195 dst[u][p] = property.slice(); 12196 12197 } else { 12198 12199 dst[u][p] = property; 12200 12201 } 12202 12203 } 12204 12205 } 12206 12207 return dst; 12208 12209} 12210 12211function mergeUniforms(uniforms) { 12212 12213 const merged = {}; 12214 12215 for (let u = 0; u < uniforms.length; u++) { 12216 12217 const tmp = cloneUniforms(uniforms[u]); 12218 12219 for (const p in tmp) { 12220 12221 merged[p] = tmp[p]; 12222 12223 } 12224 12225 } 12226 12227 return merged; 12228 12229} 12230 12231function cloneUniformsGroups(src) { 12232 12233 const dst = []; 12234 12235 for (let u = 0; u < src.length; u++) { 12236 12237 dst.push(src[u].clone()); 12238 12239 } 12240 12241 return dst; 12242 12243} 12244 12245function getUnlitUniformColorSpace(renderer) { 12246 12247 if (renderer.getRenderTarget() === null) { 12248 12249 // https://github.com/mrdoob/three.js/pull/23937#issuecomment-1111067398 12250 return renderer.outputColorSpace; 12251 12252 } 12253 12254 return ColorManagement.workingColorSpace; 12255 12256} 12257 12258// Legacy 12259 12260const UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms }; 12261 12262var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}"; 12263 12264var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}"; 12265 12266class ShaderMaterial extends Material { 12267 12268 constructor(parameters) { 12269 12270 super(); 12271 12272 this.isShaderMaterial = true; 12273 12274 this.type = 'ShaderMaterial'; 12275 12276 this.defines = {}; 12277 this.uniforms = {}; 12278 this.uniformsGroups = []; 12279 12280 this.vertexShader = default_vertex; 12281 this.fragmentShader = default_fragment; 12282 12283 this.linewidth = 1; 12284 12285 this.wireframe = false; 12286 this.wireframeLinewidth = 1; 12287 12288 this.fog = false; // set to use scene fog 12289 this.lights = false; // set to use scene lights 12290 this.clipping = false; // set to use user-defined clipping planes 12291 12292 this.forceSinglePass = true; 12293 12294 this.extensions = { 12295 derivatives: false, // set to use derivatives 12296 fragDepth: false, // set to use fragment depth values 12297 drawBuffers: false, // set to use draw buffers 12298 shaderTextureLOD: false, // set to use shader texture LOD 12299 clipCullDistance: false // set to use vertex shader clipping 12300 }; 12301 12302 // When rendered geometry doesn't include these attributes but the material does, 12303 // use these default values in WebGL. This avoids errors when buffer data is missing. 12304 this.defaultAttributeValues = { 12305 'color': [1, 1, 1], 12306 'uv': [0, 0], 12307 'uv1': [0, 0] 12308 }; 12309 12310 this.index0AttributeName = undefined; 12311 this.uniformsNeedUpdate = false; 12312 12313 this.glslVersion = null; 12314 12315 if (parameters !== undefined) { 12316 12317 this.setValues(parameters); 12318 12319 } 12320 12321 } 12322 12323 copy(source) { 12324 12325 super.copy(source); 12326 12327 this.fragmentShader = source.fragmentShader; 12328 this.vertexShader = source.vertexShader; 12329 12330 this.uniforms = cloneUniforms(source.uniforms); 12331 this.uniformsGroups = cloneUniformsGroups(source.uniformsGroups); 12332 12333 this.defines = Object.assign({}, source.defines); 12334 12335 this.wireframe = source.wireframe; 12336 this.wireframeLinewidth = source.wireframeLinewidth; 12337 12338 this.fog = source.fog; 12339 this.lights = source.lights; 12340 this.clipping = source.clipping; 12341 12342 this.extensions = Object.assign({}, source.extensions); 12343 12344 this.glslVersion = source.glslVersion; 12345 12346 return this; 12347 12348 } 12349 12350 toJSON(meta) { 12351 12352 const data = super.toJSON(meta); 12353 12354 data.glslVersion = this.glslVersion; 12355 data.uniforms = {}; 12356 12357 for (const name in this.uniforms) { 12358 12359 const uniform = this.uniforms[name]; 12360 const value = uniform.value; 12361 12362 if (value && value.isTexture) { 12363 12364 data.uniforms[name] = { 12365 type: 't', 12366 value: value.toJSON(meta).uuid 12367 }; 12368 12369 } else if (value && value.isColor) { 12370 12371 data.uniforms[name] = { 12372 type: 'c', 12373 value: value.getHex() 12374 }; 12375 12376 } else if (value && value.isVector2) { 12377 12378 data.uniforms[name] = { 12379 type: 'v2', 12380 value: value.toArray() 12381 }; 12382 12383 } else if (value && value.isVector3) { 12384 12385 data.uniforms[name] = { 12386 type: 'v3', 12387 value: value.toArray() 12388 }; 12389 12390 } else if (value && value.isVector4) { 12391 12392 data.uniforms[name] = { 12393 type: 'v4', 12394 value: value.toArray() 12395 }; 12396 12397 } else if (value && value.isMatrix3) { 12398 12399 data.uniforms[name] = { 12400 type: 'm3', 12401 value: value.toArray() 12402 }; 12403 12404 } else if (value && value.isMatrix4) { 12405 12406 data.uniforms[name] = { 12407 type: 'm4', 12408 value: value.toArray() 12409 }; 12410 12411 } else { 12412 12413 data.uniforms[name] = { 12414 value: value 12415 }; 12416 12417 // note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far 12418 12419 } 12420 12421 } 12422 12423 if (Object.keys(this.defines).length > 0) data.defines = this.defines; 12424 12425 data.vertexShader = this.vertexShader; 12426 data.fragmentShader = this.fragmentShader; 12427 12428 data.lights = this.lights; 12429 data.clipping = this.clipping; 12430 12431 const extensions = {}; 12432 12433 for (const key in this.extensions) { 12434 12435 if (this.extensions[key] === true) extensions[key] = true; 12436 12437 } 12438 12439 if (Object.keys(extensions).length > 0) data.extensions = extensions; 12440 12441 return data; 12442 12443 } 12444 12445} 12446 12447class Camera extends Object3D { 12448 12449 constructor() { 12450 12451 super(); 12452 12453 this.isCamera = true; 12454 12455 this.type = 'Camera'; 12456 12457 this.matrixWorldInverse = new Matrix4(); 12458 12459 this.projectionMatrix = new Matrix4(); 12460 this.projectionMatrixInverse = new Matrix4(); 12461 12462 this.coordinateSystem = WebGLCoordinateSystem; 12463 12464 } 12465 12466 copy(source, recursive) { 12467 12468 super.copy(source, recursive); 12469 12470 this.matrixWorldInverse.copy(source.matrixWorldInverse); 12471 12472 this.projectionMatrix.copy(source.projectionMatrix); 12473 this.projectionMatrixInverse.copy(source.projectionMatrixInverse); 12474 12475 this.coordinateSystem = source.coordinateSystem; 12476 12477 return this; 12478 12479 } 12480 12481 getWorldDirection(target) { 12482 12483 return super.getWorldDirection(target).negate(); 12484 12485 } 12486 12487 updateMatrixWorld(force) { 12488 12489 super.updateMatrixWorld(force); 12490 12491 this.matrixWorldInverse.copy(this.matrixWorld).invert(); 12492 12493 } 12494 12495 updateWorldMatrix(updateParents, updateChildren) { 12496 12497 super.updateWorldMatrix(updateParents, updateChildren); 12498 12499 this.matrixWorldInverse.copy(this.matrixWorld).invert(); 12500 12501 } 12502 12503 clone() { 12504 12505 return new this.constructor().copy(this); 12506 12507 } 12508 12509} 12510 12511class PerspectiveCamera extends Camera { 12512 12513 constructor(fov = 50, aspect = 1, near = 0.1, far = 2000) { 12514 12515 super(); 12516 12517 this.isPerspectiveCamera = true; 12518 12519 this.type = 'PerspectiveCamera'; 12520 12521 this.fov = fov; 12522 this.zoom = 1; 12523 12524 this.near = near; 12525 this.far = far; 12526 this.focus = 10; 12527 12528 this.aspect = aspect; 12529 this.view = null; 12530 12531 this.filmGauge = 35; // width of the film (default in millimeters) 12532 this.filmOffset = 0; // horizontal film offset (same unit as gauge) 12533 12534 this.updateProjectionMatrix(); 12535 12536 } 12537 12538 copy(source, recursive) { 12539 12540 super.copy(source, recursive); 12541 12542 this.fov = source.fov; 12543 this.zoom = source.zoom; 12544 12545 this.near = source.near; 12546 this.far = source.far; 12547 this.focus = source.focus; 12548 12549 this.aspect = source.aspect; 12550 this.view = source.view === null ? null : Object.assign({}, source.view); 12551 12552 this.filmGauge = source.filmGauge; 12553 this.filmOffset = source.filmOffset; 12554 12555 return this; 12556 12557 } 12558 12559 /** 12560 * Sets the FOV by focal length in respect to the current .filmGauge. 12561 * 12562 * The default film gauge is 35, so that the focal length can be specified for 12563 * a 35mm (full frame) camera. 12564 * 12565 * Values for focal length and film gauge must have the same unit. 12566 */ 12567 setFocalLength(focalLength) { 12568 12569 /** see {@link http://www.bobatkins.com/photography/technical/field_of_view.html} */ 12570 const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength; 12571 12572 this.fov = RAD2DEG * 2 * Math.atan(vExtentSlope); 12573 this.updateProjectionMatrix(); 12574 12575 } 12576 12577 /** 12578 * Calculates the focal length from the current .fov and .filmGauge. 12579 */ 12580 getFocalLength() { 12581 12582 const vExtentSlope = Math.tan(DEG2RAD * 0.5 * this.fov); 12583 12584 return 0.5 * this.getFilmHeight() / vExtentSlope; 12585 12586 } 12587 12588 getEffectiveFOV() { 12589 12590 return RAD2DEG * 2 * Math.atan( 12591 Math.tan(DEG2RAD * 0.5 * this.fov) / this.zoom); 12592 12593 } 12594 12595 getFilmWidth() { 12596 12597 // film not completely covered in portrait format (aspect < 1) 12598 return this.filmGauge * Math.min(this.aspect, 1); 12599 12600 } 12601 12602 getFilmHeight() { 12603 12604 // film not completely covered in landscape format (aspect > 1) 12605 return this.filmGauge / Math.max(this.aspect, 1); 12606 12607 } 12608 12609 /** 12610 * Sets an offset in a larger frustum. This is useful for multi-window or 12611 * multi-monitor/multi-machine setups. 12612 * 12613 * For example, if you have 3x2 monitors and each monitor is 1920x1080 and 12614 * the monitors are in grid like this 12615 * 12616 * +---+---+---+ 12617 * | A | B | C | 12618 * +---+---+---+ 12619 * | D | E | F | 12620 * +---+---+---+ 12621 * 12622 * then for each monitor you would call it like this 12623 * 12624 * const w = 1920; 12625 * const h = 1080; 12626 * const fullWidth = w * 3; 12627 * const fullHeight = h * 2; 12628 * 12629 * --A-- 12630 * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); 12631 * --B-- 12632 * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); 12633 * --C-- 12634 * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); 12635 * --D-- 12636 * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); 12637 * --E-- 12638 * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); 12639 * --F-- 12640 * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); 12641 * 12642 * Note there is no reason monitors have to be the same size or in a grid. 12643 */ 12644 setViewOffset(fullWidth, fullHeight, x, y, width, height) { 12645 12646 this.aspect = fullWidth / fullHeight; 12647 12648 if (this.view === null) { 12649 12650 this.view = { 12651 enabled: true, 12652 fullWidth: 1, 12653 fullHeight: 1, 12654 offsetX: 0, 12655 offsetY: 0, 12656 width: 1, 12657 height: 1 12658 }; 12659 12660 } 12661 12662 this.view.enabled = true; 12663 this.view.fullWidth = fullWidth; 12664 this.view.fullHeight = fullHeight; 12665 this.view.offsetX = x; 12666 this.view.offsetY = y; 12667 this.view.width = width; 12668 this.view.height = height; 12669 12670 this.updateProjectionMatrix(); 12671 12672 } 12673 12674 clearViewOffset() { 12675 12676 if (this.view !== null) { 12677 12678 this.view.enabled = false; 12679 12680 } 12681 12682 this.updateProjectionMatrix(); 12683 12684 } 12685 12686 updateProjectionMatrix() { 12687 12688 const near = this.near; 12689 let top = near * Math.tan(DEG2RAD * 0.5 * this.fov) / this.zoom; 12690 let height = 2 * top; 12691 let width = this.aspect * height; 12692 let left = - 0.5 * width; 12693 const view = this.view; 12694 12695 if (this.view !== null && this.view.enabled) { 12696 12697 const fullWidth = view.fullWidth, 12698 fullHeight = view.fullHeight; 12699 12700 left += view.offsetX * width / fullWidth; 12701 top -= view.offsetY * height / fullHeight; 12702 width *= view.width / fullWidth; 12703 height *= view.height / fullHeight; 12704 12705 } 12706 12707 const skew = this.filmOffset; 12708 if (skew !== 0) left += near * skew / this.getFilmWidth(); 12709 12710 this.projectionMatrix.makePerspective(left, left + width, top, top - height, near, this.far, this.coordinateSystem); 12711 12712 this.projectionMatrixInverse.copy(this.projectionMatrix).invert(); 12713 12714 } 12715 12716 toJSON(meta) { 12717 12718 const data = super.toJSON(meta); 12719 12720 data.object.fov = this.fov; 12721 data.object.zoom = this.zoom; 12722 12723 data.object.near = this.near; 12724 data.object.far = this.far; 12725 data.object.focus = this.focus; 12726 12727 data.object.aspect = this.aspect; 12728 12729 if (this.view !== null) data.object.view = Object.assign({}, this.view); 12730 12731 data.object.filmGauge = this.filmGauge; 12732 data.object.filmOffset = this.filmOffset; 12733 12734 return data; 12735 12736 } 12737 12738} 12739 12740const fov = - 90; // negative fov is not an error 12741const aspect = 1; 12742 12743class CubeCamera extends Object3D { 12744 12745 constructor(near, far, renderTarget) { 12746 12747 super(); 12748 12749 this.type = 'CubeCamera'; 12750 12751 this.renderTarget = renderTarget; 12752 this.coordinateSystem = null; 12753 this.activeMipmapLevel = 0; 12754 12755 const cameraPX = new PerspectiveCamera(fov, aspect, near, far); 12756 cameraPX.layers = this.layers; 12757 this.add(cameraPX); 12758 12759 const cameraNX = new PerspectiveCamera(fov, aspect, near, far); 12760 cameraNX.layers = this.layers; 12761 this.add(cameraNX); 12762 12763 const cameraPY = new PerspectiveCamera(fov, aspect, near, far); 12764 cameraPY.layers = this.layers; 12765 this.add(cameraPY); 12766 12767 const cameraNY = new PerspectiveCamera(fov, aspect, near, far); 12768 cameraNY.layers = this.layers; 12769 this.add(cameraNY); 12770 12771 const cameraPZ = new PerspectiveCamera(fov, aspect, near, far); 12772 cameraPZ.layers = this.layers; 12773 this.add(cameraPZ); 12774 12775 const cameraNZ = new PerspectiveCamera(fov, aspect, near, far); 12776 cameraNZ.layers = this.layers; 12777 this.add(cameraNZ); 12778 12779 } 12780 12781 updateCoordinateSystem() { 12782 12783 const coordinateSystem = this.coordinateSystem; 12784 12785 const cameras = this.children.concat(); 12786 12787 const [cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ] = cameras; 12788 12789 for (const camera of cameras) this.remove(camera); 12790 12791 if (coordinateSystem === WebGLCoordinateSystem) { 12792 12793 cameraPX.up.set(0, 1, 0); 12794 cameraPX.lookAt(1, 0, 0); 12795 12796 cameraNX.up.set(0, 1, 0); 12797 cameraNX.lookAt(- 1, 0, 0); 12798 12799 cameraPY.up.set(0, 0, - 1); 12800 cameraPY.lookAt(0, 1, 0); 12801 12802 cameraNY.up.set(0, 0, 1); 12803 cameraNY.lookAt(0, - 1, 0); 12804 12805 cameraPZ.up.set(0, 1, 0); 12806 cameraPZ.lookAt(0, 0, 1); 12807 12808 cameraNZ.up.set(0, 1, 0); 12809 cameraNZ.lookAt(0, 0, - 1); 12810 12811 } else if (coordinateSystem === WebGPUCoordinateSystem) { 12812 12813 cameraPX.up.set(0, - 1, 0); 12814 cameraPX.lookAt(- 1, 0, 0); 12815 12816 cameraNX.up.set(0, - 1, 0); 12817 cameraNX.lookAt(1, 0, 0); 12818 12819 cameraPY.up.set(0, 0, 1); 12820 cameraPY.lookAt(0, 1, 0); 12821 12822 cameraNY.up.set(0, 0, - 1); 12823 cameraNY.lookAt(0, - 1, 0); 12824 12825 cameraPZ.up.set(0, - 1, 0); 12826 cameraPZ.lookAt(0, 0, 1); 12827 12828 cameraNZ.up.set(0, - 1, 0); 12829 cameraNZ.lookAt(0, 0, - 1); 12830 12831 } else { 12832 12833 throw new Error('THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: ' + coordinateSystem); 12834 12835 } 12836 12837 for (const camera of cameras) { 12838 12839 this.add(camera); 12840 12841 camera.updateMatrixWorld(); 12842 12843 } 12844 12845 } 12846 12847 update(renderer, scene) { 12848 12849 if (this.parent === null) this.updateMatrixWorld(); 12850 12851 const { renderTarget, activeMipmapLevel } = this; 12852 12853 if (this.coordinateSystem !== renderer.coordinateSystem) { 12854 12855 this.coordinateSystem = renderer.coordinateSystem; 12856 12857 this.updateCoordinateSystem(); 12858 12859 } 12860 12861 const [cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ] = this.children; 12862 12863 const currentRenderTarget = renderer.getRenderTarget(); 12864 const currentActiveCubeFace = renderer.getActiveCubeFace(); 12865 const currentActiveMipmapLevel = renderer.getActiveMipmapLevel(); 12866 12867 const currentXrEnabled = renderer.xr.enabled; 12868 12869 renderer.xr.enabled = false; 12870 12871 const generateMipmaps = renderTarget.texture.generateMipmaps; 12872 12873 renderTarget.texture.generateMipmaps = false; 12874 12875 renderer.setRenderTarget(renderTarget, 0, activeMipmapLevel); 12876 renderer.render(scene, cameraPX); 12877 12878 renderer.setRenderTarget(renderTarget, 1, activeMipmapLevel); 12879 renderer.render(scene, cameraNX); 12880 12881 renderer.setRenderTarget(renderTarget, 2, activeMipmapLevel); 12882 renderer.render(scene, cameraPY); 12883 12884 renderer.setRenderTarget(renderTarget, 3, activeMipmapLevel); 12885 renderer.render(scene, cameraNY); 12886 12887 renderer.setRenderTarget(renderTarget, 4, activeMipmapLevel); 12888 renderer.render(scene, cameraPZ); 12889 12890 // mipmaps are generated during the last call of render() 12891 // at this point, all sides of the cube render target are defined 12892 12893 renderTarget.texture.generateMipmaps = generateMipmaps; 12894 12895 renderer.setRenderTarget(renderTarget, 5, activeMipmapLevel); 12896 renderer.render(scene, cameraNZ); 12897 12898 renderer.setRenderTarget(currentRenderTarget, currentActiveCubeFace, currentActiveMipmapLevel); 12899 12900 renderer.xr.enabled = currentXrEnabled; 12901 12902 renderTarget.texture.needsPMREMUpdate = true; 12903 12904 } 12905 12906} 12907 12908class CubeTexture extends Texture { 12909 12910 constructor(images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace) { 12911 12912 images = images !== undefined ? images : []; 12913 mapping = mapping !== undefined ? mapping : CubeReflectionMapping; 12914 12915 super(images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace); 12916 12917 this.isCubeTexture = true; 12918 12919 this.flipY = false; 12920 12921 } 12922 12923 get images() { 12924 12925 return this.image; 12926 12927 } 12928 12929 set images(value) { 12930 12931 this.image = value; 12932 12933 } 12934 12935} 12936 12937class WebGLCubeRenderTarget extends WebGLRenderTarget { 12938 12939 constructor(size = 1, options = {}) { 12940 12941 super(size, size, options); 12942 12943 this.isWebGLCubeRenderTarget = true; 12944 12945 const image = { width: size, height: size, depth: 1 }; 12946 const images = [image, image, image, image, image, image]; 12947 12948 if (options.encoding !== undefined) { 12949 12950 // @deprecated, r152 12951 warnOnce('THREE.WebGLCubeRenderTarget: option.encoding has been replaced by option.colorSpace.'); 12952 options.colorSpace = options.encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace; 12953 12954 } 12955 12956 this.texture = new CubeTexture(images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace); 12957 12958 // By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js) 12959 // in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words, 12960 // in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly. 12961 12962 // three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped 12963 // and the flag isRenderTargetTexture controls this conversion. The flip is not required when using WebGLCubeRenderTarget.texture 12964 // as a cube texture (this is detected when isRenderTargetTexture is set to true for cube textures). 12965 12966 this.texture.isRenderTargetTexture = true; 12967 12968 this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; 12969 this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter; 12970 12971 } 12972 12973 fromEquirectangularTexture(renderer, texture) { 12974 12975 this.texture.type = texture.type; 12976 this.texture.colorSpace = texture.colorSpace; 12977 12978 this.texture.generateMipmaps = texture.generateMipmaps; 12979 this.texture.minFilter = texture.minFilter; 12980 this.texture.magFilter = texture.magFilter; 12981 12982 const shader = { 12983 12984 uniforms: { 12985 tEquirect: { value: null }, 12986 }, 12987 12988 vertexShader: /* glsl */` 12989 12990 varying vec3 vWorldDirection; 12991 12992 vec3 transformDirection( in vec3 dir, in mat4 matrix ) { 12993 12994 return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); 12995 12996 } 12997 12998 void main() { 12999 13000 vWorldDirection = transformDirection( position, modelMatrix ); 13001 13002 #include <begin_vertex> 13003 #include <project_vertex> 13004 13005 } 13006 `, 13007 13008 fragmentShader: /* glsl */` 13009 13010 uniform sampler2D tEquirect; 13011 13012 varying vec3 vWorldDirection; 13013 13014 #include <common> 13015 13016 void main() { 13017 13018 vec3 direction = normalize( vWorldDirection ); 13019 13020 vec2 sampleUV = equirectUv( direction ); 13021 13022 gl_FragColor = texture2D( tEquirect, sampleUV ); 13023 13024 } 13025 ` 13026 }; 13027 13028 const geometry = new BoxGeometry(5, 5, 5); 13029 13030 const material = new ShaderMaterial({ 13031 13032 name: 'CubemapFromEquirect', 13033 13034 uniforms: cloneUniforms(shader.uniforms), 13035 vertexShader: shader.vertexShader, 13036 fragmentShader: shader.fragmentShader, 13037 side: BackSide, 13038 blending: NoBlending 13039 13040 }); 13041 13042 material.uniforms.tEquirect.value = texture; 13043 13044 const mesh = new Mesh(geometry, material); 13045 13046 const currentMinFilter = texture.minFilter; 13047 13048 // Avoid blurred poles 13049 if (texture.minFilter === LinearMipmapLinearFilter) texture.minFilter = LinearFilter; 13050 13051 const camera = new CubeCamera(1, 10, this); 13052 camera.update(renderer, mesh); 13053 13054 texture.minFilter = currentMinFilter; 13055 13056 mesh.geometry.dispose(); 13057 mesh.material.dispose(); 13058 13059 return this; 13060 13061 } 13062 13063 clear(renderer, color, depth, stencil) { 13064 13065 const currentRenderTarget = renderer.getRenderTarget(); 13066 13067 for (let i = 0; i < 6; i++) { 13068 13069 renderer.setRenderTarget(this, i); 13070 13071 renderer.clear(color, depth, stencil); 13072 13073 } 13074 13075 renderer.setRenderTarget(currentRenderTarget); 13076 13077 } 13078 13079} 13080 13081const _vector1 = /*@__PURE__*/ new Vector3(); 13082const _vector2 = /*@__PURE__*/ new Vector3(); 13083const _normalMatrix = /*@__PURE__*/ new Matrix3(); 13084 13085class Plane { 13086 13087 constructor(normal = new Vector3(1, 0, 0), constant = 0) { 13088 13089 this.isPlane = true; 13090 13091 // normal is assumed to be normalized 13092 13093 this.normal = normal; 13094 this.constant = constant; 13095 13096 } 13097 13098 set(normal, constant) { 13099 13100 this.normal.copy(normal); 13101 this.constant = constant; 13102 13103 return this; 13104 13105 } 13106 13107 setComponents(x, y, z, w) { 13108 13109 this.normal.set(x, y, z); 13110 this.constant = w; 13111 13112 return this; 13113 13114 } 13115 13116 setFromNormalAndCoplanarPoint(normal, point) { 13117 13118 this.normal.copy(normal); 13119 this.constant = - point.dot(this.normal); 13120 13121 return this; 13122 13123 } 13124 13125 setFromCoplanarPoints(a, b, c) { 13126 13127 const normal = _vector1.subVectors(c, b).cross(_vector2.subVectors(a, b)).normalize(); 13128 13129 // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? 13130 13131 this.setFromNormalAndCoplanarPoint(normal, a); 13132 13133 return this; 13134 13135 } 13136 13137 copy(plane) { 13138 13139 this.normal.copy(plane.normal); 13140 this.constant = plane.constant; 13141 13142 return this; 13143 13144 } 13145 13146 normalize() { 13147 13148 // Note: will lead to a divide by zero if the plane is invalid. 13149 13150 const inverseNormalLength = 1.0 / this.normal.length(); 13151 this.normal.multiplyScalar(inverseNormalLength); 13152 this.constant *= inverseNormalLength; 13153 13154 return this; 13155 13156 } 13157 13158 negate() { 13159 13160 this.constant *= - 1; 13161 this.normal.negate(); 13162 13163 return this; 13164 13165 } 13166 13167 distanceToPoint(point) { 13168 13169 return this.normal.dot(point) + this.constant; 13170 13171 } 13172 13173 distanceToSphere(sphere) { 13174 13175 return this.distanceToPoint(sphere.center) - sphere.radius; 13176 13177 } 13178 13179 projectPoint(point, target) { 13180 13181 return target.copy(point).addScaledVector(this.normal, - this.distanceToPoint(point)); 13182 13183 } 13184 13185 intersectLine(line, target) { 13186 13187 const direction = line.delta(_vector1); 13188 13189 const denominator = this.normal.dot(direction); 13190 13191 if (denominator === 0) { 13192 13193 // line is coplanar, return origin 13194 if (this.distanceToPoint(line.start) === 0) { 13195 13196 return target.copy(line.start); 13197 13198 } 13199 13200 // Unsure if this is the correct method to handle this case. 13201 return null; 13202 13203 } 13204 13205 const t = - (line.start.dot(this.normal) + this.constant) / denominator; 13206 13207 if (t < 0 || t > 1) { 13208 13209 return null; 13210 13211 } 13212 13213 return target.copy(line.start).addScaledVector(direction, t); 13214 13215 } 13216 13217 intersectsLine(line) { 13218 13219 // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. 13220 13221 const startSign = this.distanceToPoint(line.start); 13222 const endSign = this.distanceToPoint(line.end); 13223 13224 return (startSign < 0 && endSign > 0) || (endSign < 0 && startSign > 0); 13225 13226 } 13227 13228 intersectsBox(box) { 13229 13230 return box.intersectsPlane(this); 13231 13232 } 13233 13234 intersectsSphere(sphere) { 13235 13236 return sphere.intersectsPlane(this); 13237 13238 } 13239 13240 coplanarPoint(target) { 13241 13242 return target.copy(this.normal).multiplyScalar(- this.constant); 13243 13244 } 13245 13246 applyMatrix4(matrix, optionalNormalMatrix) { 13247 13248 const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix(matrix); 13249 13250 const referencePoint = this.coplanarPoint(_vector1).applyMatrix4(matrix); 13251 13252 const normal = this.normal.applyMatrix3(normalMatrix).normalize(); 13253 13254 this.constant = - referencePoint.dot(normal); 13255 13256 return this; 13257 13258 } 13259 13260 translate(offset) { 13261 13262 this.constant -= offset.dot(this.normal); 13263 13264 return this; 13265 13266 } 13267 13268 equals(plane) { 13269 13270 return plane.normal.equals(this.normal) && (plane.constant === this.constant); 13271 13272 } 13273 13274 clone() { 13275 13276 return new this.constructor().copy(this); 13277 13278 } 13279 13280} 13281 13282const _sphere$5 = /*@__PURE__*/ new Sphere(); 13283const _vector$7 = /*@__PURE__*/ new Vector3(); 13284 13285class Frustum { 13286 13287 constructor(p0 = new Plane(), p1 = new Plane(), p2 = new Plane(), p3 = new Plane(), p4 = new Plane(), p5 = new Plane()) { 13288 13289 this.planes = [p0, p1, p2, p3, p4, p5]; 13290 13291 } 13292 13293 set(p0, p1, p2, p3, p4, p5) { 13294 13295 const planes = this.planes; 13296 13297 planes[0].copy(p0); 13298 planes[1].copy(p1); 13299 planes[2].copy(p2); 13300 planes[3].copy(p3); 13301 planes[4].copy(p4); 13302 planes[5].copy(p5); 13303 13304 return this; 13305 13306 } 13307 13308 copy(frustum) { 13309 13310 const planes = this.planes; 13311 13312 for (let i = 0; i < 6; i++) { 13313 13314 planes[i].copy(frustum.planes[i]); 13315 13316 } 13317 13318 return this; 13319 13320 } 13321 13322 setFromProjectionMatrix(m, coordinateSystem = WebGLCoordinateSystem) { 13323 13324 const planes = this.planes; 13325 const me = m.elements; 13326 const me0 = me[0], me1 = me[1], me2 = me[2], me3 = me[3]; 13327 const me4 = me[4], me5 = me[5], me6 = me[6], me7 = me[7]; 13328 const me8 = me[8], me9 = me[9], me10 = me[10], me11 = me[11]; 13329 const me12 = me[12], me13 = me[13], me14 = me[14], me15 = me[15]; 13330 13331 planes[0].setComponents(me3 - me0, me7 - me4, me11 - me8, me15 - me12).normalize(); 13332 planes[1].setComponents(me3 + me0, me7 + me4, me11 + me8, me15 + me12).normalize(); 13333 planes[2].setComponents(me3 + me1, me7 + me5, me11 + me9, me15 + me13).normalize(); 13334 planes[3].setComponents(me3 - me1, me7 - me5, me11 - me9, me15 - me13).normalize(); 13335 planes[4].setComponents(me3 - me2, me7 - me6, me11 - me10, me15 - me14).normalize(); 13336 13337 if (coordinateSystem === WebGLCoordinateSystem) { 13338 13339 planes[5].setComponents(me3 + me2, me7 + me6, me11 + me10, me15 + me14).normalize(); 13340 13341 } else if (coordinateSystem === WebGPUCoordinateSystem) { 13342 13343 planes[5].setComponents(me2, me6, me10, me14).normalize(); 13344 13345 } else { 13346 13347 throw new Error('THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: ' + coordinateSystem); 13348 13349 } 13350 13351 return this; 13352 13353 } 13354 13355 intersectsObject(object) { 13356 13357 if (object.boundingSphere !== undefined) { 13358 13359 if (object.boundingSphere === null) object.computeBoundingSphere(); 13360 13361 _sphere$5.copy(object.boundingSphere).applyMatrix4(object.matrixWorld); 13362 13363 } else { 13364 13365 const geometry = object.geometry; 13366 13367 if (geometry.boundingSphere === null) geometry.computeBoundingSphere(); 13368 13369 _sphere$5.copy(geometry.boundingSphere).applyMatrix4(object.matrixWorld); 13370 13371 } 13372 13373 return this.intersectsSphere(_sphere$5); 13374 13375 } 13376 13377 intersectsSprite(sprite) { 13378 13379 _sphere$5.center.set(0, 0, 0); 13380 _sphere$5.radius = 0.7071067811865476; 13381 _sphere$5.applyMatrix4(sprite.matrixWorld); 13382 13383 return this.intersectsSphere(_sphere$5); 13384 13385 } 13386 13387 intersectsSphere(sphere) { 13388 13389 const planes = this.planes; 13390 const center = sphere.center; 13391 const negRadius = - sphere.radius; 13392 13393 for (let i = 0; i < 6; i++) { 13394 13395 const distance = planes[i].distanceToPoint(center); 13396 13397 if (distance < negRadius) { 13398 13399 return false; 13400 13401 } 13402 13403 } 13404 13405 return true; 13406 13407 } 13408 13409 intersectsBox(box) { 13410 13411 const planes = this.planes; 13412 13413 for (let i = 0; i < 6; i++) { 13414 13415 const plane = planes[i]; 13416 13417 // corner at max distance 13418 13419 _vector$7.x = plane.normal.x > 0 ? box.max.x : box.min.x; 13420 _vector$7.y = plane.normal.y > 0 ? box.max.y : box.min.y; 13421 _vector$7.z = plane.normal.z > 0 ? box.max.z : box.min.z; 13422 13423 if (plane.distanceToPoint(_vector$7) < 0) { 13424 13425 return false; 13426 13427 } 13428 13429 } 13430 13431 return true; 13432 13433 } 13434 13435 containsPoint(point) { 13436 13437 const planes = this.planes; 13438 13439 for (let i = 0; i < 6; i++) { 13440 13441 if (planes[i].distanceToPoint(point) < 0) { 13442 13443 return false; 13444 13445 } 13446 13447 } 13448 13449 return true; 13450 13451 } 13452 13453 clone() { 13454 13455 return new this.constructor().copy(this); 13456 13457 } 13458 13459} 13460 13461function WebGLAnimation() { 13462 13463 let context = null; 13464 let isAnimating = false; 13465 let animationLoop = null; 13466 let requestId = null; 13467 13468 function onAnimationFrame(time, frame) { 13469 13470 animationLoop(time, frame); 13471 13472 requestId = context.requestAnimationFrame(onAnimationFrame); 13473 13474 } 13475 13476 return { 13477 13478 start: function () { 13479 13480 if (isAnimating === true) return; 13481 if (animationLoop === null) return; 13482 13483 requestId = context.requestAnimationFrame(onAnimationFrame); 13484 13485 isAnimating = true; 13486 13487 }, 13488 13489 stop: function () { 13490 13491 context.cancelAnimationFrame(requestId); 13492 13493 isAnimating = false; 13494 13495 }, 13496 13497 setAnimationLoop: function (callback) { 13498 13499 animationLoop = callback; 13500 13501 }, 13502 13503 setContext: function (value) { 13504 13505 context = value; 13506 13507 } 13508 13509 }; 13510 13511} 13512 13513function WebGLAttributes(gl, capabilities) { 13514 13515 const isWebGL2 = capabilities.isWebGL2; 13516 13517 const buffers = new WeakMap(); 13518 13519 function createBuffer(attribute, bufferType) { 13520 13521 const array = attribute.array; 13522 const usage = attribute.usage; 13523 const size = array.byteLength; 13524 13525 const buffer = gl.createBuffer(); 13526 13527 gl.bindBuffer(bufferType, buffer); 13528 gl.bufferData(bufferType, array, usage); 13529 13530 attribute.onUploadCallback(); 13531 13532 let type; 13533 13534 if (array instanceof Float32Array) { 13535 13536 type = gl.FLOAT; 13537 13538 } else if (array instanceof Uint16Array) { 13539 13540 if (attribute.isFloat16BufferAttribute) { 13541 13542 if (isWebGL2) { 13543 13544 type = gl.HALF_FLOAT; 13545 13546 } else { 13547 13548 throw new Error('THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2.'); 13549 13550 } 13551 13552 } else { 13553 13554 type = gl.UNSIGNED_SHORT; 13555 13556 } 13557 13558 } else if (array instanceof Int16Array) { 13559 13560 type = gl.SHORT; 13561 13562 } else if (array instanceof Uint32Array) { 13563 13564 type = gl.UNSIGNED_INT; 13565 13566 } else if (array instanceof Int32Array) { 13567 13568 type = gl.INT; 13569 13570 } else if (array instanceof Int8Array) { 13571 13572 type = gl.BYTE; 13573 13574 } else if (array instanceof Uint8Array) { 13575 13576 type = gl.UNSIGNED_BYTE; 13577 13578 } else if (array instanceof Uint8ClampedArray) { 13579 13580 type = gl.UNSIGNED_BYTE; 13581 13582 } else { 13583 13584 throw new Error('THREE.WebGLAttributes: Unsupported buffer data format: ' + array); 13585 13586 } 13587 13588 return { 13589 buffer: buffer, 13590 type: type, 13591 bytesPerElement: array.BYTES_PER_ELEMENT, 13592 version: attribute.version, 13593 size: size 13594 }; 13595 13596 } 13597 13598 function updateBuffer(buffer, attribute, bufferType) { 13599 13600 const array = attribute.array; 13601 const updateRange = attribute._updateRange; // deprecated 13602 const updateRanges = attribute.updateRanges; 13603 13604 gl.bindBuffer(bufferType, buffer); 13605 13606 if (updateRange.count === - 1 && updateRanges.length === 0) { 13607 13608 // Not using update ranges 13609 gl.bufferSubData(bufferType, 0, array); 13610 13611 } 13612 13613 if (updateRanges.length !== 0) { 13614 13615 for (let i = 0, l = updateRanges.length; i < l; i++) { 13616 13617 const range = updateRanges[i]; 13618 if (isWebGL2) { 13619 13620 gl.bufferSubData(bufferType, range.start * array.BYTES_PER_ELEMENT, 13621 array, range.start, range.count); 13622 13623 } else { 13624 13625 gl.bufferSubData(bufferType, range.start * array.BYTES_PER_ELEMENT, 13626 array.subarray(range.start, range.start + range.count)); 13627 13628 } 13629 13630 } 13631 13632 attribute.clearUpdateRanges(); 13633 13634 } 13635 13636 // deprecated 13637 if (updateRange.count !== - 1) { 13638 13639 if (isWebGL2) { 13640 13641 gl.bufferSubData(bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, 13642 array, updateRange.offset, updateRange.count); 13643 13644 } else { 13645 13646 gl.bufferSubData(bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, 13647 array.subarray(updateRange.offset, updateRange.offset + updateRange.count)); 13648 13649 } 13650 13651 updateRange.count = - 1; // reset range 13652 13653 } 13654 13655 attribute.onUploadCallback(); 13656 13657 } 13658 13659 // 13660 13661 function get(attribute) { 13662 13663 if (attribute.isInterleavedBufferAttribute) attribute = attribute.data; 13664 13665 return buffers.get(attribute); 13666 13667 } 13668 13669 function remove(attribute) { 13670 13671 if (attribute.isInterleavedBufferAttribute) attribute = attribute.data; 13672 13673 const data = buffers.get(attribute); 13674 13675 if (data) { 13676 13677 gl.deleteBuffer(data.buffer); 13678 13679 buffers.delete(attribute); 13680 13681 } 13682 13683 } 13684 13685 function update(attribute, bufferType) { 13686 13687 if (attribute.isGLBufferAttribute) { 13688 13689 const cached = buffers.get(attribute); 13690 13691 if (!cached || cached.version < attribute.version) { 13692 13693 buffers.set(attribute, { 13694 buffer: attribute.buffer, 13695 type: attribute.type, 13696 bytesPerElement: attribute.elementSize, 13697 version: attribute.version 13698 }); 13699 13700 } 13701 13702 return; 13703 13704 } 13705 13706 if (attribute.isInterleavedBufferAttribute) attribute = attribute.data; 13707 13708 const data = buffers.get(attribute); 13709 13710 if (data === undefined) { 13711 13712 buffers.set(attribute, createBuffer(attribute, bufferType)); 13713 13714 } else if (data.version < attribute.version) { 13715 13716 if (data.size !== attribute.array.byteLength) { 13717 13718 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.'); 13719 13720 } 13721 13722 updateBuffer(data.buffer, attribute, bufferType); 13723 13724 data.version = attribute.version; 13725 13726 } 13727 13728 } 13729 13730 return { 13731 13732 get: get, 13733 remove: remove, 13734 update: update 13735 13736 }; 13737 13738} 13739 13740class PlaneGeometry extends BufferGeometry { 13741 13742 constructor(width = 1, height = 1, widthSegments = 1, heightSegments = 1) { 13743 13744 super(); 13745 13746 this.type = 'PlaneGeometry'; 13747 13748 this.parameters = { 13749 width: width, 13750 height: height, 13751 widthSegments: widthSegments, 13752 heightSegments: heightSegments 13753 }; 13754 13755 const width_half = width / 2; 13756 const height_half = height / 2; 13757 13758 const gridX = Math.floor(widthSegments); 13759 const gridY = Math.floor(heightSegments); 13760 13761 const gridX1 = gridX + 1; 13762 const gridY1 = gridY + 1; 13763 13764 const segment_width = width / gridX; 13765 const segment_height = height / gridY; 13766 13767 // 13768 13769 const indices = []; 13770 const vertices = []; 13771 const normals = []; 13772 const uvs = []; 13773 13774 for (let iy = 0; iy < gridY1; iy++) { 13775 13776 const y = iy * segment_height - height_half; 13777 13778 for (let ix = 0; ix < gridX1; ix++) { 13779 13780 const x = ix * segment_width - width_half; 13781 13782 vertices.push(x, - y, 0); 13783 13784 normals.push(0, 0, 1); 13785 13786 uvs.push(ix / gridX); 13787 uvs.push(1 - (iy / gridY)); 13788 13789 } 13790 13791 } 13792 13793 for (let iy = 0; iy < gridY; iy++) { 13794 13795 for (let ix = 0; ix < gridX; ix++) { 13796 13797 const a = ix + gridX1 * iy; 13798 const b = ix + gridX1 * (iy + 1); 13799 const c = (ix + 1) + gridX1 * (iy + 1); 13800 const d = (ix + 1) + gridX1 * iy; 13801 13802 indices.push(a, b, d); 13803 indices.push(b, c, d); 13804 13805 } 13806 13807 } 13808 13809 this.setIndex(indices); 13810 this.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 13811 this.setAttribute('normal', new Float32BufferAttribute(normals, 3)); 13812 this.setAttribute('uv', new Float32BufferAttribute(uvs, 2)); 13813 13814 } 13815 13816 copy(source) { 13817 13818 super.copy(source); 13819 13820 this.parameters = Object.assign({}, source.parameters); 13821 13822 return this; 13823 13824 } 13825 13826 static fromJSON(data) { 13827 13828 return new PlaneGeometry(data.width, data.height, data.widthSegments, data.heightSegments); 13829 13830 } 13831 13832} 13833 13834var alphahash_fragment = "#ifdef USE_ALPHAHASH\n\tif ( diffuseColor.a < getAlphaHashThreshold( vPosition ) ) discard;\n#endif"; 13835 13836var 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"; 13837 13838var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vAlphaMapUv ).g;\n#endif"; 13839 13840var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; 13841 13842var alphatest_fragment = "#ifdef USE_ALPHATEST\n\tif ( diffuseColor.a < alphaTest ) discard;\n#endif"; 13843 13844var alphatest_pars_fragment = "#ifdef USE_ALPHATEST\n\tuniform float alphaTest;\n#endif"; 13845 13846var 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
13846( geometryNormal, geometryViewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif"; 13847 13848var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; 13849 13850var 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"; 13851 13852var batching_vertex = "#ifdef USE_BATCHING\n\tmat4 batchingMatrix = getBatchingMatrix( batchId );\n#endif"; 13853 13854var begin_vertex = "vec3 transformed = vec3( position );\n#ifdef USE_ALPHAHASH\n\tvPosition = vec3( position );\n#endif"; 13855 13856var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif"; 13857 13858var 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"; 13859 13860var 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 );
13860\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"; 13861 13862var 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"; 13863 13864var 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"; 13865 13866var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif"; 13867 13868var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif"; 13869 13870var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif"; 13871 13872var color_fragment = "#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( USE_COLOR )\n\tdiffuseColor.rgb *= vColor;\n#endif"; 13873 13874var color_pars_fragment = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR )\n\tvarying vec3 vColor;\n#endif"; 13875 13876var 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"; 13877 13878var 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"; 13879 13880var 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"; 13881 13882var 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"; 13883 13884var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = objectTangent;\n#endif\n#ifdef USE_BATCHING\n\tmat3 bm = mat3( batchingMatrix );
13884\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"; 13885 13886var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif"; 13887 13888var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias );\n#endif"; 13889 13890var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv );\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif"; 13891 13892var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif"; 13893 13894var colorspace_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );"; 13895 13896var 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}"; 13897 13898var 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"; 13899 13900var 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"; 13901 13902var 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"; 13903 13904var 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"; 13905 13906var 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}
13906 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"; 13907 13908var fog_vertex = "#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif"; 13909 13910var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif"; 13911 13912var 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"; 13913 13914var 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"; 13915 13916var 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}"; 13917 13918var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\treflectedLight.indirectDiffuse += lightMapIrradiance;\n#endif"; 13919 13920var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; 13921 13922var lights_lambert_fragment = "LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularStrength = specularStrength;"; 13923 13924var 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"; 13925 13926var 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}
13926\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"; 13927 13928var 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"; 13929 13930var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;"; 13931 13932var 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"; 13933 13934var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;"; 13935 13936var 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
13936( 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"; 13937 13938var 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;
13938\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"; 13939�
vendor: 15,344 bytes, lines 13939-13940
13939 13940var 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}";
13940 13941 13942var 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"; 13943 13944var 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"; 13945 13946var 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"; 13947 13948var 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"; 13949 13950var 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"; 13951 13952var 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"; 13953 13954var 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"; 13955 13956var 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"; 13957 13958var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif"; 13959 13960var 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"; 13961 13962var 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"; 13963 13964var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif"; 13965 13966var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"; 13967 13968var 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"; 13969 13970var 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"; 13971 13972var 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"; 13973 13974var 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"; 13975 13976var 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;"; 13977 13978var 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 );
13978\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif"; 13979 13980var 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"; 13981 13982var 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"; 13983 13984var 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"; 13985 13986var 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"; 13987 13988var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = nonPerturbedNormal;\n#endif"; 13989 13990var 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"; 13991 13992var 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"; 13993 13994var iridescence_pars_fragment = "#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform sampler2D iridescenceThicknessMap;\n#endif"; 13995 13996var 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 );"; 13997 13998var 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}"; 13999 14000var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif"; 14001 14002var 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;"; 14003 14004var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif"; 14005 14006var 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"; 14007 14008var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv );\n\troughnessFactor *= texelRoughness.g;\n#endif"; 14009 14010var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"; 14011�
vendor: 9,177 bytes, lines 14011-14012
14011 14012var 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";
14012 14013 14014var 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"; 14015 14016var 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"; 14017 14018var 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}"; 14019 14020var 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"; 14021 14022var 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"; 14023 14024var 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"; 14025 14026var 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"; 14027 14028var 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"; 14029 14030var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif"; 14031 14032var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif"; 14033�
vendor: 2,514 bytes, lines 14033-14034
14033 14034var 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
14034= 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; }"; 14035 14036var 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"; 14037 14038var 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"; 14039 14040var uv_pars_fragment = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tvarying vec2 vMapUv;
14040\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"; 14041 14042var 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"; 14043 14044var 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;
14044\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"; 14045 14046var 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"; 14047 14048const 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}"; 14049 14050const 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}"; 14051 14052const 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}"; 14053 14054const 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}"; 14055 14056const 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}"; 14057 14058const 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}"; 14059 14060const 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}"; 14061 14062const 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}"; 14063 14064const 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}"; 14065 14066const 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}"; 14067 14068const 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}"; 14069 14070const 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}"; 14071 14072const 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}"; 14073 14074const 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}"; 14075 14076const 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}"; 14077 14078const 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}"; 14079 14080const 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}"; 14081 14082const 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}"; 14083 14084const 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>
14084\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n\tvViewPosition = - mvPosition.xyz;\n}"; 14085 14086const 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}"; 14087 14088const 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}"; 14089 14090const 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}"; 14091 14092const 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}"; 14093 14094const 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}"; 14095 14096const 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}"; 14097 14098const 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;
14098\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;
14098\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}"; 14099 14100const 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}"; 14101 14102const 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}"; 14103 14104const 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}"; 14105 14106const 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}"; 14107 14108const 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}"; 14109 14110const 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}"; 14111 14112const 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}"; 14113 14114const 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}"; 14115 14116const ShaderChunk = { 14117 alphahash_fragment: alphahash_fragment, 14118 alphahash_pars_fragment: alphahash_pars_fragment, 14119 alphamap_fragment: alphamap_fragment, 14120 alphamap_pars_fragment: alphamap_pars_fragment, 14121 alphatest_fragment: alphatest_fragment, 14122 alphatest_pars_fragment: alphatest_pars_fragment, 14123 aomap_fragment: aomap_fragment, 14124 aomap_pars_fragment: aomap_pars_fragment, 14125 batching_pars_vertex: batching_pars_vertex, 14126 batching_vertex: batching_vertex, 14127 begin_vertex: begin_vertex, 14128 beginnormal_vertex: beginnormal_vertex, 14129 bsdfs: bsdfs, 14130 iridescence_fragment: iridescence_fragment, 14131 bumpmap_pars_fragment: bumpmap_pars_fragment, 14132 clipping_planes_fragment: clipping_planes_fragment, 14133 clipping_planes_pars_fragment: clipping_planes_pars_fragment, 14134 clipping_planes_pars_vertex: clipping_planes_pars_vertex, 14135 clipping_planes_vertex: clipping_planes_vertex, 14136 color_fragment: color_fragment, 14137 color_pars_fragment: color_pars_fragment, 14138 color_pars_vertex: color_pars_vertex, 14139 color_vertex: color_vertex, 14140 common: common, 14141 cube_uv_reflection_fragment: cube_uv_reflection_fragment, 14142 defaultnormal_vertex: defaultnormal_vertex,
vendor: 12,289 bytes, lines 14143-14629
14143 displacementmap_pars_vertex: displacementmap_pars_vertex, 14144 displacementmap_vertex: displacementmap_vertex, 14145 emissivemap_fragment: emissivemap_fragment, 14146 emissivemap_pars_fragment: emissivemap_pars_fragment, 14147 colorspace_fragment: colorspace_fragment, 14148 colorspace_pars_fragment: colorspace_pars_fragment, 14149 envmap_fragment: envmap_fragment, 14150 envmap_common_pars_fragment: envmap_common_pars_fragment, 14151 envmap_pars_fragment: envmap_pars_fragment, 14152 envmap_pars_vertex: envmap_pars_vertex, 14153 envmap_physical_pars_fragment: envmap_physical_pars_fragment, 14154 envmap_vertex: envmap_vertex, 14155 fog_vertex: fog_vertex, 14156 fog_pars_vertex: fog_pars_vertex, 14157 fog_fragment: fog_fragment, 14158 fog_pars_fragment: fog_pars_fragment, 14159 gradientmap_pars_fragment: gradientmap_pars_fragment, 14160 lightmap_fragment: lightmap_fragment, 14161 lightmap_pars_fragment: lightmap_pars_fragment, 14162 lights_lambert_fragment: lights_lambert_fragment, 14163 lights_lambert_pars_fragment: lights_lambert_pars_fragment, 14164 lights_pars_begin: lights_pars_begin, 14165 lights_toon_fragment: lights_toon_fragment, 14166 lights_toon_pars_fragment: lights_toon_pars_fragment, 14167 lights_phong_fragment: lights_phong_fragment, 14168 lights_phong_pars_fragment: lights_phong_pars_fragment, 14169 lights_physical_fragment: lights_physical_fragment, 14170 lights_physical_pars_fragment: lights_physical_pars_fragment, 14171 lights_fragment_begin: lights_fragment_begin, 14172 lights_fragment_maps: lights_fragment_maps, 14173 lights_fragment_end: lights_fragment_end, 14174 logdepthbuf_fragment: logdepthbuf_fragment, 14175 logdepthbuf_pars_fragment: logdepthbuf_pars_fragment, 14176 logdepthbuf_pars_vertex: logdepthbuf_pars_vertex, 14177 logdepthbuf_vertex: logdepthbuf_vertex, 14178 map_fragment: map_fragment, 14179 map_pars_fragment: map_pars_fragment, 14180 map_particle_fragment: map_particle_fragment, 14181 map_particle_pars_fragment: map_particle_pars_fragment, 14182 metalnessmap_fragment: metalnessmap_fragment, 14183 metalnessmap_pars_fragment: metalnessmap_pars_fragment, 14184 morphcolor_vertex: morphcolor_vertex, 14185 morphnormal_vertex: morphnormal_vertex, 14186 morphtarget_pars_vertex: morphtarget_pars_vertex, 14187 morphtarget_vertex: morphtarget_vertex, 14188 normal_fragment_begin: normal_fragment_begin, 14189 normal_fragment_maps: normal_fragment_maps, 14190 normal_pars_fragment: normal_pars_fragment, 14191 normal_pars_vertex: normal_pars_vertex, 14192 normal_vertex: normal_vertex, 14193 normalmap_pars_fragment: normalmap_pars_fragment, 14194 clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin, 14195 clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps, 14196 clearcoat_pars_fragment: clearcoat_pars_fragment, 14197 iridescence_pars_fragment: iridescence_pars_fragment, 14198 opaque_fragment: opaque_fragment, 14199 packing: packing, 14200 premultiplied_alpha_fragment: premultiplied_alpha_fragment, 14201 project_vertex: project_vertex, 14202 dithering_fragment: dithering_fragment, 14203 dithering_pars_fragment: dithering_pars_fragment, 14204 roughnessmap_fragment: roughnessmap_fragment, 14205 roughnessmap_pars_fragment: roughnessmap_pars_fragment, 14206 shadowmap_pars_fragment: shadowmap_pars_fragment, 14207 shadowmap_pars_vertex: shadowmap_pars_vertex, 14208 shadowmap_vertex: shadowmap_vertex, 14209 shadowmask_pars_fragment: shadowmask_pars_fragment, 14210 skinbase_vertex: skinbase_vertex, 14211 skinning_pars_vertex: skinning_pars_vertex, 14212 skinning_vertex: skinning_vertex, 14213 skinnormal_vertex: skinnormal_vertex, 14214 specularmap_fragment: specularmap_fragment, 14215 specularmap_pars_fragment: specularmap_pars_fragment, 14216 tonemapping_fragment: tonemapping_fragment, 14217 tonemapping_pars_fragment: tonemapping_pars_fragment, 14218 transmission_fragment: transmission_fragment, 14219 transmission_pars_fragment: transmission_pars_fragment, 14220 uv_pars_fragment: uv_pars_fragment, 14221 uv_pars_vertex: uv_pars_vertex, 14222 uv_vertex: uv_vertex, 14223 worldpos_vertex: worldpos_vertex, 14224 14225 background_vert: vertex$h, 14226 background_frag: fragment$h, 14227 backgroundCube_vert: vertex$g, 14228 backgroundCube_frag: fragment$g, 14229 cube_vert: vertex$f, 14230 cube_frag: fragment$f, 14231 depth_vert: vertex$e, 14232 depth_frag: fragment$e, 14233 distanceRGBA_vert: vertex$d, 14234 distanceRGBA_frag: fragment$d, 14235 equirect_vert: vertex$c, 14236 equirect_frag: fragment$c, 14237 linedashed_vert: vertex$b, 14238 linedashed_frag: fragment$b, 14239 meshbasic_vert: vertex$a, 14240 meshbasic_frag: fragment$a, 14241 meshlambert_vert: vertex$9, 14242 meshlambert_frag: fragment$9, 14243 meshmatcap_vert: vertex$8, 14244 meshmatcap_frag: fragment$8, 14245 meshnormal_vert: vertex$7, 14246 meshnormal_frag: fragment$7, 14247 meshphong_vert: vertex$6, 14248 meshphong_frag: fragment$6, 14249 meshphysical_vert: vertex$5, 14250 meshphysical_frag: fragment$5, 14251 meshtoon_vert: vertex$4, 14252 meshtoon_frag: fragment$4, 14253 points_vert: vertex$3, 14254 points_frag: fragment$3, 14255 shadow_vert: vertex$2, 14256 shadow_frag: fragment$2, 14257 sprite_vert: vertex$1, 14258 sprite_frag: fragment$1 14259}; 14260 14261/** 14262 * Uniforms library for shared webgl shaders 14263 */ 14264 14265const UniformsLib = { 14266 14267 common: { 14268 14269 diffuse: { value: /*@__PURE__*/ new Color(0xffffff) }, 14270 opacity: { value: 1.0 }, 14271 14272 map: { value: null }, 14273 mapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14274 14275 alphaMap: { value: null }, 14276 alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14277 14278 alphaTest: { value: 0 } 14279 14280 }, 14281 14282 specularmap: { 14283 14284 specularMap: { value: null }, 14285 specularMapTransform: { value: /*@__PURE__*/ new Matrix3() } 14286 14287 }, 14288 14289 envmap: { 14290 14291 envMap: { value: null }, 14292 flipEnvMap: { value: - 1 }, 14293 reflectivity: { value: 1.0 }, // basic, lambert, phong 14294 ior: { value: 1.5 }, // physical 14295 refractionRatio: { value: 0.98 }, // basic, lambert, phong 14296 14297 }, 14298 14299 aomap: { 14300 14301 aoMap: { value: null }, 14302 aoMapIntensity: { value: 1 }, 14303 aoMapTransform: { value: /*@__PURE__*/ new Matrix3() } 14304 14305 }, 14306 14307 lightmap: { 14308 14309 lightMap: { value: null }, 14310 lightMapIntensity: { value: 1 }, 14311 lightMapTransform: { value: /*@__PURE__*/ new Matrix3() } 14312 14313 }, 14314 14315 bumpmap: { 14316 14317 bumpMap: { value: null }, 14318 bumpMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14319 bumpScale: { value: 1 } 14320 14321 }, 14322 14323 normalmap: { 14324 14325 normalMap: { value: null }, 14326 normalMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14327 normalScale: { value: /*@__PURE__*/ new Vector2(1, 1) } 14328 14329 }, 14330 14331 displacementmap: { 14332 14333 displacementMap: { value: null }, 14334 displacementMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14335 displacementScale: { value: 1 }, 14336 displacementBias: { value: 0 } 14337 14338 }, 14339 14340 emissivemap: { 14341 14342 emissiveMap: { value: null }, 14343 emissiveMapTransform: { value: /*@__PURE__*/ new Matrix3() } 14344 14345 }, 14346 14347 metalnessmap: { 14348 14349 metalnessMap: { value: null }, 14350 metalnessMapTransform: { value: /*@__PURE__*/ new Matrix3() } 14351 14352 }, 14353 14354 roughnessmap: { 14355 14356 roughnessMap: { value: null }, 14357 roughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() } 14358 14359 }, 14360 14361 gradientmap: { 14362 14363 gradientMap: { value: null } 14364 14365 }, 14366 14367 fog: { 14368 14369 fogDensity: { value: 0.00025 }, 14370 fogNear: { value: 1 }, 14371 fogFar: { value: 2000 }, 14372 fogColor: { value: /*@__PURE__*/ new Color(0xffffff) } 14373 14374 }, 14375 14376 lights: { 14377 14378 ambientLightColor: { value: [] }, 14379 14380 lightProbe: { value: [] }, 14381 14382 directionalLights: { 14383 value: [], properties: { 14384 direction: {}, 14385 color: {} 14386 } 14387 }, 14388 14389 directionalLightShadows: { 14390 value: [], properties: { 14391 shadowBias: {}, 14392 shadowNormalBias: {}, 14393 shadowRadius: {}, 14394 shadowMapSize: {} 14395 } 14396 }, 14397 14398 directionalShadowMap: { value: [] }, 14399 directionalShadowMatrix: { value: [] }, 14400 14401 spotLights: { 14402 value: [], properties: { 14403 color: {}, 14404 position: {}, 14405 direction: {}, 14406 distance: {}, 14407 coneCos: {}, 14408 penumbraCos: {}, 14409 decay: {} 14410 } 14411 }, 14412 14413 spotLightShadows: { 14414 value: [], properties: { 14415 shadowBias: {}, 14416 shadowNormalBias: {}, 14417 shadowRadius: {}, 14418 shadowMapSize: {} 14419 } 14420 }, 14421 14422 spotLightMap: { value: [] }, 14423 spotShadowMap: { value: [] }, 14424 spotLightMatrix: { value: [] }, 14425 14426 pointLights: { 14427 value: [], properties: { 14428 color: {}, 14429 position: {}, 14430 decay: {}, 14431 distance: {} 14432 } 14433 }, 14434 14435 pointLightShadows: { 14436 value: [], properties: { 14437 shadowBias: {}, 14438 shadowNormalBias: {}, 14439 shadowRadius: {}, 14440 shadowMapSize: {}, 14441 shadowCameraNear: {}, 14442 shadowCameraFar: {} 14443 } 14444 }, 14445 14446 pointShadowMap: { value: [] }, 14447 pointShadowMatrix: { value: [] }, 14448 14449 hemisphereLights: { 14450 value: [], properties: { 14451 direction: {}, 14452 skyColor: {}, 14453 groundColor: {} 14454 } 14455 }, 14456 14457 // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src 14458 rectAreaLights: { 14459 value: [], properties: { 14460 color: {}, 14461 position: {}, 14462 width: {}, 14463 height: {} 14464 } 14465 }, 14466 14467 ltc_1: { value: null }, 14468 ltc_2: { value: null } 14469 14470 }, 14471 14472 points: { 14473 14474 diffuse: { value: /*@__PURE__*/ new Color(0xffffff) }, 14475 opacity: { value: 1.0 }, 14476 size: { value: 1.0 }, 14477 scale: { value: 1.0 }, 14478 map: { value: null }, 14479 alphaMap: { value: null }, 14480 alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14481 alphaTest: { value: 0 }, 14482 uvTransform: { value: /*@__PURE__*/ new Matrix3() } 14483 14484 }, 14485 14486 sprite: { 14487 14488 diffuse: { value: /*@__PURE__*/ new Color(0xffffff) }, 14489 opacity: { value: 1.0 }, 14490 center: { value: /*@__PURE__*/ new Vector2(0.5, 0.5) }, 14491 rotation: { value: 0.0 }, 14492 map: { value: null }, 14493 mapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14494 alphaMap: { value: null }, 14495 alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14496 alphaTest: { value: 0 } 14497 14498 } 14499 14500}; 14501 14502const ShaderLib = { 14503 14504 basic: { 14505 14506 uniforms: /*@__PURE__*/ mergeUniforms([ 14507 UniformsLib.common, 14508 UniformsLib.specularmap, 14509 UniformsLib.envmap, 14510 UniformsLib.aomap, 14511 UniformsLib.lightmap, 14512 UniformsLib.fog 14513 ]), 14514 14515 vertexShader: ShaderChunk.meshbasic_vert, 14516 fragmentShader: ShaderChunk.meshbasic_frag 14517 14518 }, 14519 14520 lambert: { 14521 14522 uniforms: /*@__PURE__*/ mergeUniforms([ 14523 UniformsLib.common, 14524 UniformsLib.specularmap, 14525 UniformsLib.envmap, 14526 UniformsLib.aomap, 14527 UniformsLib.lightmap, 14528 UniformsLib.emissivemap, 14529 UniformsLib.bumpmap, 14530 UniformsLib.normalmap, 14531 UniformsLib.displacementmap, 14532 UniformsLib.fog, 14533 UniformsLib.lights, 14534 { 14535 emissive: { value: /*@__PURE__*/ new Color(0x000000) } 14536 } 14537 ]), 14538 14539 vertexShader: ShaderChunk.meshlambert_vert, 14540 fragmentShader: ShaderChunk.meshlambert_frag 14541 14542 }, 14543 14544 phong: { 14545 14546 uniforms: /*@__PURE__*/ mergeUniforms([ 14547 UniformsLib.common, 14548 UniformsLib.specularmap, 14549 UniformsLib.envmap, 14550 UniformsLib.aomap, 14551 UniformsLib.lightmap, 14552 UniformsLib.emissivemap, 14553 UniformsLib.bumpmap, 14554 UniformsLib.normalmap, 14555 UniformsLib.displacementmap, 14556 UniformsLib.fog, 14557 UniformsLib.lights, 14558 { 14559 emissive: { value: /*@__PURE__*/ new Color(0x000000) }, 14560 specular: { value: /*@__PURE__*/ new Color(0x111111) }, 14561 shininess: { value: 30 } 14562 } 14563 ]), 14564 14565 vertexShader: ShaderChunk.meshphong_vert, 14566 fragmentShader: ShaderChunk.meshphong_frag 14567 14568 }, 14569 14570 standard: { 14571 14572 uniforms: /*@__PURE__*/ mergeUniforms([ 14573 UniformsLib.common, 14574 UniformsLib.envmap, 14575 UniformsLib.aomap, 14576 UniformsLib.lightmap, 14577 UniformsLib.emissivemap, 14578 UniformsLib.bumpmap, 14579 UniformsLib.normalmap, 14580 UniformsLib.displacementmap, 14581 UniformsLib.roughnessmap, 14582 UniformsLib.metalnessmap, 14583 UniformsLib.fog, 14584 UniformsLib.lights, 14585 { 14586 emissive: { value: /*@__PURE__*/ new Color(0x000000) }, 14587 roughness: { value: 1.0 }, 14588 metalness: { value: 0.0 }, 14589 envMapIntensity: { value: 1 } // temporary 14590 } 14591 ]), 14592 14593 vertexShader: ShaderChunk.meshphysical_vert, 14594 fragmentShader: ShaderChunk.meshphysical_frag 14595 14596 }, 14597 14598 toon: { 14599 14600 uniforms: /*@__PURE__*/ mergeUniforms([ 14601 UniformsLib.common, 14602 UniformsLib.aomap, 14603 UniformsLib.lightmap, 14604 UniformsLib.emissivemap, 14605 UniformsLib.bumpmap, 14606 UniformsLib.normalmap, 14607 UniformsLib.displacementmap, 14608 UniformsLib.gradientmap, 14609 UniformsLib.fog, 14610 UniformsLib.lights, 14611 { 14612 emissive: { value: /*@__PURE__*/ new Color(0x000000) } 14613 } 14614 ]), 14615 14616 vertexShader: ShaderChunk.meshtoon_vert, 14617 fragmentShader: ShaderChunk.meshtoon_frag 14618 14619 }, 14620 14621 matcap: { 14622 14623 uniforms: /*@__PURE__*/ mergeUniforms([ 14624 UniformsLib.common, 14625 UniformsLib.bumpmap, 14626 UniformsLib.normalmap, 14627 UniformsLib.displacementmap, 14628 UniformsLib.fog, 14629 {
vendor: 5,467 bytes, lines 14630-14852
14630 matcap: { value: null } 14631 } 14632 ]), 14633 14634 vertexShader: ShaderChunk.meshmatcap_vert, 14635 fragmentShader: ShaderChunk.meshmatcap_frag 14636 14637 }, 14638 14639 points: { 14640 14641 uniforms: /*@__PURE__*/ mergeUniforms([ 14642 UniformsLib.points, 14643 UniformsLib.fog 14644 ]), 14645 14646 vertexShader: ShaderChunk.points_vert, 14647 fragmentShader: ShaderChunk.points_frag 14648 14649 }, 14650 14651 dashed: { 14652 14653 uniforms: /*@__PURE__*/ mergeUniforms([ 14654 UniformsLib.common, 14655 UniformsLib.fog, 14656 { 14657 scale: { value: 1 }, 14658 dashSize: { value: 1 }, 14659 totalSize: { value: 2 } 14660 } 14661 ]), 14662 14663 vertexShader: ShaderChunk.linedashed_vert, 14664 fragmentShader: ShaderChunk.linedashed_frag 14665 14666 }, 14667 14668 depth: { 14669 14670 uniforms: /*@__PURE__*/ mergeUniforms([ 14671 UniformsLib.common, 14672 UniformsLib.displacementmap 14673 ]), 14674 14675 vertexShader: ShaderChunk.depth_vert, 14676 fragmentShader: ShaderChunk.depth_frag 14677 14678 }, 14679 14680 normal: { 14681 14682 uniforms: /*@__PURE__*/ mergeUniforms([ 14683 UniformsLib.common, 14684 UniformsLib.bumpmap, 14685 UniformsLib.normalmap, 14686 UniformsLib.displacementmap, 14687 { 14688 opacity: { value: 1.0 } 14689 } 14690 ]), 14691 14692 vertexShader: ShaderChunk.meshnormal_vert, 14693 fragmentShader: ShaderChunk.meshnormal_frag 14694 14695 }, 14696 14697 sprite: { 14698 14699 uniforms: /*@__PURE__*/ mergeUniforms([ 14700 UniformsLib.sprite, 14701 UniformsLib.fog 14702 ]), 14703 14704 vertexShader: ShaderChunk.sprite_vert, 14705 fragmentShader: ShaderChunk.sprite_frag 14706 14707 }, 14708 14709 background: { 14710 14711 uniforms: { 14712 uvTransform: { value: /*@__PURE__*/ new Matrix3() }, 14713 t2D: { value: null }, 14714 backgroundIntensity: { value: 1 } 14715 }, 14716 14717 vertexShader: ShaderChunk.background_vert, 14718 fragmentShader: ShaderChunk.background_frag 14719 14720 }, 14721 14722 backgroundCube: { 14723 14724 uniforms: { 14725 envMap: { value: null }, 14726 flipEnvMap: { value: - 1 }, 14727 backgroundBlurriness: { value: 0 }, 14728 backgroundIntensity: { value: 1 } 14729 }, 14730 14731 vertexShader: ShaderChunk.backgroundCube_vert, 14732 fragmentShader: ShaderChunk.backgroundCube_frag 14733 14734 }, 14735 14736 cube: { 14737 14738 uniforms: { 14739 tCube: { value: null }, 14740 tFlip: { value: - 1 }, 14741 opacity: { value: 1.0 } 14742 }, 14743 14744 vertexShader: ShaderChunk.cube_vert, 14745 fragmentShader: ShaderChunk.cube_frag 14746 14747 }, 14748 14749 equirect: { 14750 14751 uniforms: { 14752 tEquirect: { value: null }, 14753 }, 14754 14755 vertexShader: ShaderChunk.equirect_vert, 14756 fragmentShader: ShaderChunk.equirect_frag 14757 14758 }, 14759 14760 distanceRGBA: { 14761 14762 uniforms: /*@__PURE__*/ mergeUniforms([ 14763 UniformsLib.common, 14764 UniformsLib.displacementmap, 14765 { 14766 referencePosition: { value: /*@__PURE__*/ new Vector3() }, 14767 nearDistance: { value: 1 }, 14768 farDistance: { value: 1000 } 14769 } 14770 ]), 14771 14772 vertexShader: ShaderChunk.distanceRGBA_vert, 14773 fragmentShader: ShaderChunk.distanceRGBA_frag 14774 14775 }, 14776 14777 shadow: { 14778 14779 uniforms: /*@__PURE__*/ mergeUniforms([ 14780 UniformsLib.lights, 14781 UniformsLib.fog, 14782 { 14783 color: { value: /*@__PURE__*/ new Color(0x00000) }, 14784 opacity: { value: 1.0 } 14785 }, 14786 ]), 14787 14788 vertexShader: ShaderChunk.shadow_vert, 14789 fragmentShader: ShaderChunk.shadow_frag 14790 14791 } 14792 14793}; 14794 14795ShaderLib.physical = { 14796 14797 uniforms: /*@__PURE__*/ mergeUniforms([ 14798 ShaderLib.standard.uniforms, 14799 { 14800 clearcoat: { value: 0 }, 14801 clearcoatMap: { value: null }, 14802 clearcoatMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14803 clearcoatNormalMap: { value: null }, 14804 clearcoatNormalMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14805 clearcoatNormalScale: { value: /*@__PURE__*/ new Vector2(1, 1) }, 14806 clearcoatRoughness: { value: 0 }, 14807 clearcoatRoughnessMap: { value: null }, 14808 clearcoatRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14809 iridescence: { value: 0 }, 14810 iridescenceMap: { value: null }, 14811 iridescenceMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14812 iridescenceIOR: { value: 1.3 }, 14813 iridescenceThicknessMinimum: { value: 100 }, 14814 iridescenceThicknessMaximum: { value: 400 }, 14815 iridescenceThicknessMap: { value: null }, 14816 iridescenceThicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14817 sheen: { value: 0 }, 14818 sheenColor: { value: /*@__PURE__*/ new Color(0x000000) }, 14819 sheenColorMap: { value: null }, 14820 sheenColorMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14821 sheenRoughness: { value: 1 }, 14822 sheenRoughnessMap: { value: null }, 14823 sheenRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14824 transmission: { value: 0 }, 14825 transmissionMap: { value: null }, 14826 transmissionMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14827 transmissionSamplerSize: { value: /*@__PURE__*/ new Vector2() }, 14828 transmissionSamplerMap: { value: null }, 14829 thickness: { value: 0 }, 14830 thicknessMap: { value: null }, 14831 thicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14832 attenuationDistance: { value: 0 }, 14833 attenuationColor: { value: /*@__PURE__*/ new Color(0x000000) }, 14834 specularColor: { value: /*@__PURE__*/ new Color(1, 1, 1) }, 14835 specularColorMap: { value: null }, 14836 specularColorMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14837 specularIntensity: { value: 1 }, 14838 specularIntensityMap: { value: null }, 14839 specularIntensityMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14840 anisotropyVector: { value: /*@__PURE__*/ new Vector2() }, 14841 anisotropyMap: { value: null }, 14842 anisotropyMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 14843 } 14844 ]), 14845 14846 vertexShader: ShaderChunk.meshphysical_vert, 14847 fragmentShader: ShaderChunk.meshphysical_frag 14848 14849}; 14850 14851const _rgb = { r: 0, b: 0, g: 0 }; 14852
vendor: 49,453 bytes, lines 14853-16947
14853function WebGLBackground(renderer, cubemaps, cubeuvmaps, state, objects, alpha, premultipliedAlpha) { 14854 14855 const clearColor = new Color(0x000000); 14856 let clearAlpha = alpha === true ? 0 : 1; 14857 14858 let planeMesh; 14859 let boxMesh; 14860 14861 let currentBackground = null; 14862 let currentBackgroundVersion = 0; 14863 let currentTonemapping = null; 14864 14865 function render(renderList, scene) { 14866 14867 let forceClear = false; 14868 let background = scene.isScene === true ? scene.background : null; 14869 14870 if (background && background.isTexture) { 14871 14872 const usePMREM = scene.backgroundBlurriness > 0; // use PMREM if the user wants to blur the background 14873 background = (usePMREM ? cubeuvmaps : cubemaps).get(background); 14874 14875 } 14876 14877 if (background === null) { 14878 14879 setClear(clearColor, clearAlpha); 14880 14881 } else if (background && background.isColor) { 14882 14883 setClear(background, 1); 14884 forceClear = true; 14885 14886 } 14887 14888 const environmentBlendMode = renderer.xr.getEnvironmentBlendMode(); 14889 14890 if (environmentBlendMode === 'additive') { 14891 14892 state.buffers.color.setClear(0, 0, 0, 1, premultipliedAlpha); 14893 14894 } else if (environmentBlendMode === 'alpha-blend') { 14895 14896 state.buffers.color.setClear(0, 0, 0, 0, premultipliedAlpha); 14897 14898 } 14899 14900 if (renderer.autoClear || forceClear) { 14901 14902 renderer.clear(renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil); 14903 14904 } 14905 14906 if (background && (background.isCubeTexture || background.mapping === CubeUVReflectionMapping)) { 14907 14908 if (boxMesh === undefined) { 14909 14910 boxMesh = new Mesh( 14911 new BoxGeometry(1, 1, 1), 14912 new ShaderMaterial({ 14913 name: 'BackgroundCubeMaterial', 14914 uniforms: cloneUniforms(ShaderLib.backgroundCube.uniforms), 14915 vertexShader: ShaderLib.backgroundCube.vertexShader, 14916 fragmentShader: ShaderLib.backgroundCube.fragmentShader, 14917 side: BackSide, 14918 depthTest: false, 14919 depthWrite: false, 14920 fog: false 14921 }) 14922 ); 14923 14924 boxMesh.geometry.deleteAttribute('normal'); 14925 boxMesh.geometry.deleteAttribute('uv'); 14926 14927 boxMesh.onBeforeRender = function (renderer, scene, camera) { 14928 14929 this.matrixWorld.copyPosition(camera.matrixWorld); 14930 14931 }; 14932 14933 // add "envMap" material property so the renderer can evaluate it like for built-in materials 14934 Object.defineProperty(boxMesh.material, 'envMap', { 14935 14936 get: function () { 14937 14938 return this.uniforms.envMap.value; 14939 14940 } 14941 14942 }); 14943 14944 objects.update(boxMesh); 14945 14946 } 14947 14948 boxMesh.material.uniforms.envMap.value = background; 14949 boxMesh.material.uniforms.flipEnvMap.value = (background.isCubeTexture && background.isRenderTargetTexture === false) ? - 1 : 1; 14950 boxMesh.material.uniforms.backgroundBlurriness.value = scene.backgroundBlurriness; 14951 boxMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity; 14952 boxMesh.material.toneMapped = ColorManagement.getTransfer(background.colorSpace) !== SRGBTransfer; 14953 14954 if (currentBackground !== background || 14955 currentBackgroundVersion !== background.version || 14956 currentTonemapping !== renderer.toneMapping) { 14957 14958 boxMesh.material.needsUpdate = true; 14959 14960 currentBackground = background; 14961 currentBackgroundVersion = background.version; 14962 currentTonemapping = renderer.toneMapping; 14963 14964 } 14965 14966 boxMesh.layers.enableAll(); 14967 14968 // push to the pre-sorted opaque render list 14969 renderList.unshift(boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null); 14970 14971 } else if (background && background.isTexture) { 14972 14973 if (planeMesh === undefined) { 14974 14975 planeMesh = new Mesh( 14976 new PlaneGeometry(2, 2), 14977 new ShaderMaterial({ 14978 name: 'BackgroundMaterial', 14979 uniforms: cloneUniforms(ShaderLib.background.uniforms), 14980 vertexShader: ShaderLib.background.vertexShader, 14981 fragmentShader: ShaderLib.background.fragmentShader, 14982 side: FrontSide, 14983 depthTest: false, 14984 depthWrite: false, 14985 fog: false 14986 }) 14987 ); 14988 14989 planeMesh.geometry.deleteAttribute('normal'); 14990 14991 // add "map" material property so the renderer can evaluate it like for built-in materials 14992 Object.defineProperty(planeMesh.material, 'map', { 14993 14994 get: function () { 14995 14996 return this.uniforms.t2D.value; 14997 14998 } 14999 15000 }); 15001 15002 objects.update(planeMesh); 15003 15004 } 15005 15006 planeMesh.material.uniforms.t2D.value = background; 15007 planeMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity; 15008 planeMesh.material.toneMapped = ColorManagement.getTransfer(background.colorSpace) !== SRGBTransfer; 15009 15010 if (background.matrixAutoUpdate === true) { 15011 15012 background.updateMatrix(); 15013 15014 } 15015 15016 planeMesh.material.uniforms.uvTransform.value.copy(background.matrix); 15017 15018 if (currentBackground !== background || 15019 currentBackgroundVersion !== background.version || 15020 currentTonemapping !== renderer.toneMapping) { 15021 15022 planeMesh.material.needsUpdate = true; 15023 15024 currentBackground = background; 15025 currentBackgroundVersion = background.version; 15026 currentTonemapping = renderer.toneMapping; 15027 15028 } 15029 15030 planeMesh.layers.enableAll(); 15031 15032 // push to the pre-sorted opaque render list 15033 renderList.unshift(planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null); 15034 15035 } 15036 15037 } 15038 15039 function setClear(color, alpha) { 15040 15041 color.getRGB(_rgb, getUnlitUniformColorSpace(renderer)); 15042 15043 state.buffers.color.setClear(_rgb.r, _rgb.g, _rgb.b, alpha, premultipliedAlpha); 15044 15045 } 15046 15047 return { 15048 15049 getClearColor: function () { 15050 15051 return clearColor; 15052 15053 }, 15054 setClearColor: function (color, alpha = 1) { 15055 15056 clearColor.set(color); 15057 clearAlpha = alpha; 15058 setClear(clearColor, clearAlpha); 15059 15060 }, 15061 getClearAlpha: function () { 15062 15063 return clearAlpha; 15064 15065 }, 15066 setClearAlpha: function (alpha) { 15067 15068 clearAlpha = alpha; 15069 setClear(clearColor, clearAlpha); 15070 15071 }, 15072 render: render 15073 15074 }; 15075 15076} 15077 15078function WebGLBindingStates(gl, extensions, attributes, capabilities) { 15079 15080 const maxVertexAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS); 15081 15082 const extension = capabilities.isWebGL2 ? null : extensions.get('OES_vertex_array_object'); 15083 const vaoAvailable = capabilities.isWebGL2 || extension !== null; 15084 15085 const bindingStates = {}; 15086 15087 const defaultState = createBindingState(null); 15088 let currentState = defaultState; 15089 let forceUpdate = false; 15090 15091 function setup(object, material, program, geometry, index) { 15092 15093 let updateBuffers = false; 15094 15095 if (vaoAvailable) { 15096 15097 const state = getBindingState(geometry, program, material); 15098 15099 if (currentState !== state) { 15100 15101 currentState = state; 15102 bindVertexArrayObject(currentState.object); 15103 15104 } 15105 15106 updateBuffers = needsUpdate(object, geometry, program, index); 15107 15108 if (updateBuffers) saveCache(object, geometry, program, index); 15109 15110 } else { 15111 15112 const wireframe = (material.wireframe === true); 15113 15114 if (currentState.geometry !== geometry.id || 15115 currentState.program !== program.id || 15116 currentState.wireframe !== wireframe) { 15117 15118 currentState.geometry = geometry.id; 15119 currentState.program = program.id; 15120 currentState.wireframe = wireframe; 15121 15122 updateBuffers = true; 15123 15124 } 15125 15126 } 15127 15128 if (index !== null) { 15129 15130 attributes.update(index, gl.ELEMENT_ARRAY_BUFFER); 15131 15132 } 15133 15134 if (updateBuffers || forceUpdate) { 15135 15136 forceUpdate = false; 15137 15138 setupVertexAttributes(object, material, program, geometry); 15139 15140 if (index !== null) { 15141 15142 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, attributes.get(index).buffer); 15143 15144 } 15145 15146 } 15147 15148 } 15149 15150 function createVertexArrayObject() { 15151 15152 if (capabilities.isWebGL2) return gl.createVertexArray(); 15153 15154 return extension.createVertexArrayOES(); 15155 15156 } 15157 15158 function bindVertexArrayObject(vao) { 15159 15160 if (capabilities.isWebGL2) return gl.bindVertexArray(vao); 15161 15162 return extension.bindVertexArrayOES(vao); 15163 15164 } 15165 15166 function deleteVertexArrayObject(vao) { 15167 15168 if (capabilities.isWebGL2) return gl.deleteVertexArray(vao); 15169 15170 return extension.deleteVertexArrayOES(vao); 15171 15172 } 15173 15174 function getBindingState(geometry, program, material) { 15175 15176 const wireframe = (material.wireframe === true); 15177 15178 let programMap = bindingStates[geometry.id]; 15179 15180 if (programMap === undefined) { 15181 15182 programMap = {}; 15183 bindingStates[geometry.id] = programMap; 15184 15185 } 15186 15187 let stateMap = programMap[program.id]; 15188 15189 if (stateMap === undefined) { 15190 15191 stateMap = {}; 15192 programMap[program.id] = stateMap; 15193 15194 } 15195 15196 let state = stateMap[wireframe]; 15197 15198 if (state === undefined) { 15199 15200 state = createBindingState(createVertexArrayObject()); 15201 stateMap[wireframe] = state; 15202 15203 } 15204 15205 return state; 15206 15207 } 15208 15209 function createBindingState(vao) { 15210 15211 const newAttributes = []; 15212 const enabledAttributes = []; 15213 const attributeDivisors = []; 15214 15215 for (let i = 0; i < maxVertexAttributes; i++) { 15216 15217 newAttributes[i] = 0; 15218 enabledAttributes[i] = 0; 15219 attributeDivisors[i] = 0; 15220 15221 } 15222 15223 return { 15224 15225 // for backward compatibility on non-VAO support browser 15226 geometry: null, 15227 program: null, 15228 wireframe: false, 15229 15230 newAttributes: newAttributes, 15231 enabledAttributes: enabledAttributes, 15232 attributeDivisors: attributeDivisors, 15233 object: vao, 15234 attributes: {}, 15235 index: null 15236 15237 }; 15238 15239 } 15240 15241 function needsUpdate(object, geometry, program, index) { 15242 15243 const cachedAttributes = currentState.attributes; 15244 const geometryAttributes = geometry.attributes; 15245 15246 let attributesNum = 0; 15247 15248 const programAttributes = program.getAttributes(); 15249 15250 for (const name in programAttributes) { 15251 15252 const programAttribute = programAttributes[name]; 15253 15254 if (programAttribute.location >= 0) { 15255 15256 const cachedAttribute = cachedAttributes[name]; 15257 let geometryAttribute = geometryAttributes[name]; 15258 15259 if (geometryAttribute === undefined) { 15260 15261 if (name === 'instanceMatrix' && object.instanceMatrix) geometryAttribute = object.instanceMatrix; 15262 if (name === 'instanceColor' && object.instanceColor) geometryAttribute = object.instanceColor; 15263 15264 } 15265 15266 if (cachedAttribute === undefined) return true; 15267 15268 if (cachedAttribute.attribute !== geometryAttribute) return true; 15269 15270 if (geometryAttribute && cachedAttribute.data !== geometryAttribute.data) return true; 15271 15272 attributesNum++; 15273 15274 } 15275 15276 } 15277 15278 if (currentState.attributesNum !== attributesNum) return true; 15279 15280 if (currentState.index !== index) return true; 15281 15282 return false; 15283 15284 } 15285 15286 function saveCache(object, geometry, program, index) { 15287 15288 const cache = {}; 15289 const attributes = geometry.attributes; 15290 let attributesNum = 0; 15291 15292 const programAttributes = program.getAttributes(); 15293 15294 for (const name in programAttributes) { 15295 15296 const programAttribute = programAttributes[name]; 15297 15298 if (programAttribute.location >= 0) { 15299 15300 let attribute = attributes[name]; 15301 15302 if (attribute === undefined) { 15303 15304 if (name === 'instanceMatrix' && object.instanceMatrix) attribute = object.instanceMatrix; 15305 if (name === 'instanceColor' && object.instanceColor) attribute = object.instanceColor; 15306 15307 } 15308 15309 const data = {}; 15310 data.attribute = attribute; 15311 15312 if (attribute && attribute.data) { 15313 15314 data.data = attribute.data; 15315 15316 } 15317 15318 cache[name] = data; 15319 15320 attributesNum++; 15321 15322 } 15323 15324 } 15325 15326 currentState.attributes = cache; 15327 currentState.attributesNum = attributesNum; 15328 15329 currentState.index = index; 15330 15331 } 15332 15333 function initAttributes() { 15334 15335 const newAttributes = currentState.newAttributes; 15336 15337 for (let i = 0, il = newAttributes.length; i < il; i++) { 15338 15339 newAttributes[i] = 0; 15340 15341 } 15342 15343 } 15344 15345 function enableAttribute(attribute) { 15346 15347 enableAttributeAndDivisor(attribute, 0); 15348 15349 } 15350 15351 function enableAttributeAndDivisor(attribute, meshPerAttribute) { 15352 15353 const newAttributes = currentState.newAttributes; 15354 const enabledAttributes = currentState.enabledAttributes; 15355 const attributeDivisors = currentState.attributeDivisors; 15356 15357 newAttributes[attribute] = 1; 15358 15359 if (enabledAttributes[attribute] === 0) { 15360 15361 gl.enableVertexAttribArray(attribute); 15362 enabledAttributes[attribute] = 1; 15363 15364 } 15365 15366 if (attributeDivisors[attribute] !== meshPerAttribute) { 15367 15368 const extension = capabilities.isWebGL2 ? gl : extensions.get('ANGLE_instanced_arrays'); 15369 15370 extension[capabilities.isWebGL2 ? 'vertexAttribDivisor' : 'vertexAttribDivisorANGLE'](attribute, meshPerAttribute); 15371 attributeDivisors[attribute] = meshPerAttribute; 15372 15373 } 15374 15375 } 15376 15377 function disableUnusedAttributes() { 15378 15379 const newAttributes = currentState.newAttributes; 15380 const enabledAttributes = currentState.enabledAttributes; 15381 15382 for (let i = 0, il = enabledAttributes.length; i < il; i++) { 15383 15384 if (enabledAttributes[i] !== newAttributes[i]) { 15385 15386 gl.disableVertexAttribArray(i); 15387 enabledAttributes[i] = 0; 15388 15389 } 15390 15391 } 15392 15393 } 15394 15395 function vertexAttribPointer(index, size, type, normalized, stride, offset, integer) { 15396 15397 if (integer === true) { 15398 15399 gl.vertexAttribIPointer(index, size, type, stride, offset); 15400 15401 } else { 15402 15403 gl.vertexAttribPointer(index, size, type, normalized, stride, offset); 15404 15405 } 15406 15407 } 15408 15409 function setupVertexAttributes(object, material, program, geometry) { 15410 15411 if (capabilities.isWebGL2 === false && (object.isInstancedMesh || geometry.isInstancedBufferGeometry)) { 15412 15413 if (extensions.get('ANGLE_instanced_arrays') === null) return; 15414 15415 } 15416 15417 initAttributes(); 15418 15419 const geometryAttributes = geometry.attributes; 15420 15421 const programAttributes = program.getAttributes(); 15422 15423 const materialDefaultAttributeValues = material.defaultAttributeValues; 15424 15425 for (const name in programAttributes) { 15426 15427 const programAttribute = programAttributes[name]; 15428 15429 if (programAttribute.location >= 0) { 15430 15431 let geometryAttribute = geometryAttributes[name]; 15432 15433 if (geometryAttribute === undefined) { 15434 15435 if (name === 'instanceMatrix' && object.instanceMatrix) geometryAttribute = object.instanceMatrix; 15436 if (name === 'instanceColor' && object.instanceColor) geometryAttribute = object.instanceColor; 15437 15438 } 15439 15440 if (geometryAttribute !== undefined) { 15441 15442 const normalized = geometryAttribute.normalized; 15443 const size = geometryAttribute.itemSize; 15444 15445 const attribute = attributes.get(geometryAttribute); 15446 15447 // TODO Attribute may not be available on context restore 15448 15449 if (attribute === undefined) continue; 15450 15451 const buffer = attribute.buffer; 15452 const type = attribute.type; 15453 const bytesPerElement = attribute.bytesPerElement; 15454 15455 // check for integer attributes (WebGL 2 only) 15456 15457 const integer = (capabilities.isWebGL2 === true && (type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === IntType)); 15458 15459 if (geometryAttribute.isInterleavedBufferAttribute) { 15460 15461 const data = geometryAttribute.data; 15462 const stride = data.stride; 15463 const offset = geometryAttribute.offset; 15464 15465 if (data.isInstancedInterleavedBuffer) { 15466 15467 for (let i = 0; i < programAttribute.locationSize; i++) { 15468 15469 enableAttributeAndDivisor(programAttribute.location + i, data.meshPerAttribute); 15470 15471 } 15472 15473 if (object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined) { 15474 15475 geometry._maxInstanceCount = data.meshPerAttribute * data.count; 15476 15477 } 15478 15479 } else { 15480 15481 for (let i = 0; i < programAttribute.locationSize; i++) { 15482 15483 enableAttribute(programAttribute.location + i); 15484 15485 } 15486 15487 } 15488 15489 gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 15490 15491 for (let i = 0; i < programAttribute.locationSize; i++) { 15492 15493 vertexAttribPointer( 15494 programAttribute.location + i, 15495 size / programAttribute.locationSize, 15496 type, 15497 normalized, 15498 stride * bytesPerElement, 15499 (offset + (size / programAttribute.locationSize) * i) * bytesPerElement, 15500 integer 15501 ); 15502 15503 } 15504 15505 } else { 15506 15507 if (geometryAttribute.isInstancedBufferAttribute) { 15508 15509 for (let i = 0; i < programAttribute.locationSize; i++) { 15510 15511 enableAttributeAndDivisor(programAttribute.location + i, geometryAttribute.meshPerAttribute); 15512 15513 } 15514 15515 if (object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined) { 15516 15517 geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; 15518 15519 } 15520 15521 } else { 15522 15523 for (let i = 0; i < programAttribute.locationSize; i++) { 15524 15525 enableAttribute(programAttribute.location + i); 15526 15527 } 15528 15529 } 15530 15531 gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 15532 15533 for (let i = 0; i < programAttribute.locationSize; i++) { 15534 15535 vertexAttribPointer( 15536 programAttribute.location + i, 15537 size / programAttribute.locationSize, 15538 type, 15539 normalized, 15540 size * bytesPerElement, 15541 (size / programAttribute.locationSize) * i * bytesPerElement, 15542 integer 15543 ); 15544 15545 } 15546 15547 } 15548 15549 } else if (materialDefaultAttributeValues !== undefined) { 15550 15551 const value = materialDefaultAttributeValues[name]; 15552 15553 if (value !== undefined) { 15554 15555 switch (value.length) { 15556 15557 case 2: 15558 gl.vertexAttrib2fv(programAttribute.location, value); 15559 break; 15560 15561 case 3: 15562 gl.vertexAttrib3fv(programAttribute.location, value); 15563 break; 15564 15565 case 4: 15566 gl.vertexAttrib4fv(programAttribute.location, value); 15567 break; 15568 15569 default: 15570 gl.vertexAttrib1fv(programAttribute.location, value); 15571 15572 } 15573 15574 } 15575 15576 } 15577 15578 } 15579 15580 } 15581 15582 disableUnusedAttributes(); 15583 15584 } 15585 15586 function dispose() { 15587 15588 reset(); 15589 15590 for (const geometryId in bindingStates) { 15591 15592 const programMap = bindingStates[geometryId]; 15593 15594 for (const programId in programMap) { 15595 15596 const stateMap = programMap[programId]; 15597 15598 for (const wireframe in stateMap) { 15599 15600 deleteVertexArrayObject(stateMap[wireframe].object); 15601 15602 delete stateMap[wireframe]; 15603 15604 } 15605 15606 delete programMap[programId]; 15607 15608 } 15609 15610 delete bindingStates[geometryId]; 15611 15612 } 15613 15614 } 15615 15616 function releaseStatesOfGeometry(geometry) { 15617 15618 if (bindingStates[geometry.id] === undefined) return; 15619 15620 const programMap = bindingStates[geometry.id]; 15621 15622 for (const programId in programMap) { 15623 15624 const stateMap = programMap[programId]; 15625 15626 for (const wireframe in stateMap) { 15627 15628 deleteVertexArrayObject(stateMap[wireframe].object); 15629 15630 delete stateMap[wireframe]; 15631 15632 } 15633 15634 delete programMap[programId]; 15635 15636 } 15637 15638 delete bindingStates[geometry.id]; 15639 15640 } 15641 15642 function releaseStatesOfProgram(program) { 15643 15644 for (const geometryId in bindingStates) { 15645 15646 const programMap = bindingStates[geometryId]; 15647 15648 if (programMap[program.id] === undefined) continue; 15649 15650 const stateMap = programMap[program.id]; 15651 15652 for (const wireframe in stateMap) { 15653 15654 deleteVertexArrayObject(stateMap[wireframe].object); 15655 15656 delete stateMap[wireframe]; 15657 15658 } 15659 15660 delete programMap[program.id]; 15661 15662 } 15663 15664 } 15665 15666 function reset() { 15667 15668 resetDefaultState(); 15669 forceUpdate = true; 15670 15671 if (currentState === defaultState) return; 15672 15673 currentState = defaultState; 15674 bindVertexArrayObject(currentState.object); 15675 15676 } 15677 15678 // for backward-compatibility 15679 15680 function resetDefaultState() { 15681 15682 defaultState.geometry = null; 15683 defaultState.program = null; 15684 defaultState.wireframe = false; 15685 15686 } 15687 15688 return { 15689 15690 setup: setup, 15691 reset: reset, 15692 resetDefaultState: resetDefaultState, 15693 dispose: dispose, 15694 releaseStatesOfGeometry: releaseStatesOfGeometry, 15695 releaseStatesOfProgram: releaseStatesOfProgram, 15696 15697 initAttributes: initAttributes, 15698 enableAttribute: enableAttribute, 15699 disableUnusedAttributes: disableUnusedAttributes 15700 15701 }; 15702 15703} 15704 15705function WebGLBufferRenderer(gl, extensions, info, capabilities) { 15706 15707 const isWebGL2 = capabilities.isWebGL2; 15708 15709 let mode; 15710 15711 function setMode(value) { 15712 15713 mode = value; 15714 15715 } 15716 15717 function render(start, count) { 15718 15719 gl.drawArrays(mode, start, count); 15720 15721 info.update(count, mode, 1); 15722 15723 } 15724 15725 function renderInstances(start, count, primcount) { 15726 15727 if (primcount === 0) return; 15728 15729 let extension, methodName; 15730 15731 if (isWebGL2) { 15732 15733 extension = gl; 15734 methodName = 'drawArraysInstanced'; 15735 15736 } else { 15737 15738 extension = extensions.get('ANGLE_instanced_arrays'); 15739 methodName = 'drawArraysInstancedANGLE'; 15740 15741 if (extension === null) { 15742 15743 console.error('THREE.WebGLBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.'); 15744 return; 15745 15746 } 15747 15748 } 15749 15750 extension[methodName](mode, start, count, primcount); 15751 15752 info.update(count, mode, primcount); 15753 15754 } 15755 15756 function renderMultiDraw(starts, counts, drawCount) { 15757 15758 if (drawCount === 0) return; 15759 15760 const extension = extensions.get('WEBGL_multi_draw'); 15761 if (extension === null) { 15762 15763 for (let i = 0; i < drawCount; i++) { 15764 15765 this.render(starts[i], counts[i]); 15766 15767 } 15768 15769 } else { 15770 15771 extension.multiDrawArraysWEBGL(mode, starts, 0, counts, 0, drawCount); 15772 15773 let elementCount = 0; 15774 for (let i = 0; i < drawCount; i++) { 15775 15776 elementCount += counts[i]; 15777 15778 } 15779 15780 info.update(elementCount, mode, 1); 15781 15782 } 15783 15784 } 15785 15786 // 15787 15788 this.setMode = setMode; 15789 this.render = render; 15790 this.renderInstances = renderInstances; 15791 this.renderMultiDraw = renderMultiDraw; 15792 15793} 15794 15795function WebGLCapabilities(gl, extensions, parameters) { 15796 15797 let maxAnisotropy; 15798 15799 function getMaxAnisotropy() { 15800 15801 if (maxAnisotropy !== undefined) return maxAnisotropy; 15802 15803 if (extensions.has('EXT_texture_filter_anisotropic') === true) { 15804 15805 const extension = extensions.get('EXT_texture_filter_anisotropic'); 15806 15807 maxAnisotropy = gl.getParameter(extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT); 15808 15809 } else { 15810 15811 maxAnisotropy = 0; 15812 15813 } 15814 15815 return maxAnisotropy; 15816 15817 } 15818 15819 function getMaxPrecision(precision) { 15820 15821 if (precision === 'highp') { 15822 15823 if (gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.HIGH_FLOAT).precision > 0 && 15824 gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT).precision > 0) { 15825 15826 return 'highp'; 15827 15828 } 15829 15830 precision = 'mediump'; 15831 15832 } 15833 15834 if (precision === 'mediump') { 15835 15836 if (gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.MEDIUM_FLOAT).precision > 0 && 15837 gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT).precision > 0) { 15838 15839 return 'mediump'; 15840 15841 } 15842 15843 } 15844 15845 return 'lowp'; 15846 15847 } 15848 15849 const isWebGL2 = typeof WebGL2RenderingContext !== 'undefined' && gl.constructor.name === 'WebGL2RenderingContext'; 15850 15851 let precision = parameters.precision !== undefined ? parameters.precision : 'highp'; 15852 const maxPrecision = getMaxPrecision(precision); 15853 15854 if (maxPrecision !== precision) { 15855 15856 console.warn('THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.'); 15857 precision = maxPrecision; 15858 15859 } 15860 15861 const drawBuffers = isWebGL2 || extensions.has('WEBGL_draw_buffers'); 15862 15863 const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true; 15864 15865 const maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS); 15866 const maxVertexTextures = gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS); 15867 const maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE); 15868 const maxCubemapSize = gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE); 15869 15870 const maxAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS); 15871 const maxVertexUniforms = gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS); 15872 const maxVaryings = gl.getParameter(gl.MAX_VARYING_VECTORS); 15873 const maxFragmentUniforms = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS); 15874 15875 const vertexTextures = maxVertexTextures > 0; 15876 const floatFragmentTextures = isWebGL2 || extensions.has('OES_texture_float'); 15877 const floatVertexTextures = vertexTextures && floatFragmentTextures; 15878 15879 const maxSamples = isWebGL2 ? gl.getParameter(gl.MAX_SAMPLES) : 0; 15880 15881 return { 15882 15883 isWebGL2: isWebGL2, 15884 15885 drawBuffers: drawBuffers, 15886 15887 getMaxAnisotropy: getMaxAnisotropy, 15888 getMaxPrecision: getMaxPrecision, 15889 15890 precision: precision, 15891 logarithmicDepthBuffer: logarithmicDepthBuffer, 15892 15893 maxTextures: maxTextures, 15894 maxVertexTextures: maxVertexTextures, 15895 maxTextureSize: maxTextureSize, 15896 maxCubemapSize: maxCubemapSize, 15897 15898 maxAttributes: maxAttributes, 15899 maxVertexUniforms: maxVertexUniforms, 15900 maxVaryings: maxVaryings, 15901 maxFragmentUniforms: maxFragmentUniforms, 15902 15903 vertexTextures: vertexTextures, 15904 floatFragmentTextures: floatFragmentTextures, 15905 floatVertexTextures: floatVertexTextures, 15906 15907 maxSamples: maxSamples 15908 15909 }; 15910 15911} 15912 15913function WebGLClipping(properties) { 15914 15915 const scope = this; 15916 15917 let globalState = null, 15918 numGlobalPlanes = 0, 15919 localClippingEnabled = false, 15920 renderingShadows = false; 15921 15922 const plane = new Plane(), 15923 viewNormalMatrix = new Matrix3(), 15924 15925 uniform = { value: null, needsUpdate: false }; 15926 15927 this.uniform = uniform; 15928 this.numPlanes = 0; 15929 this.numIntersection = 0; 15930 15931 this.init = function (planes, enableLocalClipping) { 15932 15933 const enabled = 15934 planes.length !== 0 || 15935 enableLocalClipping || 15936 // enable state of previous frame - the clipping code has to 15937 // run another frame in order to reset the state: 15938 numGlobalPlanes !== 0 || 15939 localClippingEnabled; 15940 15941 localClippingEnabled = enableLocalClipping; 15942 15943 numGlobalPlanes = planes.length; 15944 15945 return enabled; 15946 15947 }; 15948 15949 this.beginShadows = function () { 15950 15951 renderingShadows = true; 15952 projectPlanes(null); 15953 15954 }; 15955 15956 this.endShadows = function () { 15957 15958 renderingShadows = false; 15959 15960 }; 15961 15962 this.setGlobalState = function (planes, camera) { 15963 15964 globalState = projectPlanes(planes, camera, 0); 15965 15966 }; 15967 15968 this.setState = function (material, camera, useCache) { 15969 15970 const planes = material.clippingPlanes, 15971 clipIntersection = material.clipIntersection, 15972 clipShadows = material.clipShadows; 15973 15974 const materialProperties = properties.get(material); 15975 15976 if (!localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && !clipShadows) { 15977 15978 // there's no local clipping 15979 15980 if (renderingShadows) { 15981 15982 // there's no global clipping 15983 15984 projectPlanes(null); 15985 15986 } else { 15987 15988 resetGlobalState(); 15989 15990 } 15991 15992 } else { 15993 15994 const nGlobal = renderingShadows ? 0 : numGlobalPlanes, 15995 lGlobal = nGlobal * 4; 15996 15997 let dstArray = materialProperties.clippingState || null; 15998 15999 uniform.value = dstArray; // ensure unique state 16000 16001 dstArray = projectPlanes(planes, camera, lGlobal, useCache); 16002 16003 for (let i = 0; i !== lGlobal; ++i) { 16004 16005 dstArray[i] = globalState[i]; 16006 16007 } 16008 16009 materialProperties.clippingState = dstArray; 16010 this.numIntersection = clipIntersection ? this.numPlanes : 0; 16011 this.numPlanes += nGlobal; 16012 16013 } 16014 16015 16016 }; 16017 16018 function resetGlobalState() { 16019 16020 if (uniform.value !== globalState) { 16021 16022 uniform.value = globalState; 16023 uniform.needsUpdate = numGlobalPlanes > 0; 16024 16025 } 16026 16027 scope.numPlanes = numGlobalPlanes; 16028 scope.numIntersection = 0; 16029 16030 } 16031 16032 function projectPlanes(planes, camera, dstOffset, skipTransform) { 16033 16034 const nPlanes = planes !== null ? planes.length : 0; 16035 let dstArray = null; 16036 16037 if (nPlanes !== 0) { 16038 16039 dstArray = uniform.value; 16040 16041 if (skipTransform !== true || dstArray === null) { 16042 16043 const flatSize = dstOffset + nPlanes * 4, 16044 viewMatrix = camera.matrixWorldInverse; 16045 16046 viewNormalMatrix.getNormalMatrix(viewMatrix); 16047 16048 if (dstArray === null || dstArray.length < flatSize) { 16049 16050 dstArray = new Float32Array(flatSize); 16051 16052 } 16053 16054 for (let i = 0, i4 = dstOffset; i !== nPlanes; ++i, i4 += 4) { 16055 16056 plane.copy(planes[i]).applyMatrix4(viewMatrix, viewNormalMatrix); 16057 16058 plane.normal.toArray(dstArray, i4); 16059 dstArray[i4 + 3] = plane.constant; 16060 16061 } 16062 16063 } 16064 16065 uniform.value = dstArray; 16066 uniform.needsUpdate = true; 16067 16068 } 16069 16070 scope.numPlanes = nPlanes; 16071 scope.numIntersection = 0; 16072 16073 return dstArray; 16074 16075 } 16076 16077} 16078 16079function WebGLCubeMaps(renderer) { 16080 16081 let cubemaps = new WeakMap(); 16082 16083 function mapTextureMapping(texture, mapping) { 16084 16085 if (mapping === EquirectangularReflectionMapping) { 16086 16087 texture.mapping = CubeReflectionMapping; 16088 16089 } else if (mapping === EquirectangularRefractionMapping) { 16090 16091 texture.mapping = CubeRefractionMapping; 16092 16093 } 16094 16095 return texture; 16096 16097 } 16098 16099 function get(texture) { 16100 16101 if (texture && texture.isTexture) { 16102 16103 const mapping = texture.mapping; 16104 16105 if (mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping) { 16106 16107 if (cubemaps.has(texture)) { 16108 16109 const cubemap = cubemaps.get(texture).texture; 16110 return mapTextureMapping(cubemap, texture.mapping); 16111 16112 } else { 16113 16114 const image = texture.image; 16115 16116 if (image && image.height > 0) { 16117 16118 const renderTarget = new WebGLCubeRenderTarget(image.height / 2); 16119 renderTarget.fromEquirectangularTexture(renderer, texture); 16120 cubemaps.set(texture, renderTarget); 16121 16122 texture.addEventListener('dispose', onTextureDispose); 16123 16124 return mapTextureMapping(renderTarget.texture, texture.mapping); 16125 16126 } else { 16127 16128 // image not yet ready. try the conversion next frame 16129 16130 return null; 16131 16132 } 16133 16134 } 16135 16136 } 16137 16138 } 16139 16140 return texture; 16141 16142 } 16143 16144 function onTextureDispose(event) { 16145 16146 const texture = event.target; 16147 16148 texture.removeEventListener('dispose', onTextureDispose); 16149 16150 const cubemap = cubemaps.get(texture); 16151 16152 if (cubemap !== undefined) { 16153 16154 cubemaps.delete(texture); 16155 cubemap.dispose(); 16156 16157 } 16158 16159 } 16160 16161 function dispose() { 16162 16163 cubemaps = new WeakMap(); 16164 16165 } 16166 16167 return { 16168 get: get, 16169 dispose: dispose 16170 }; 16171 16172} 16173 16174class OrthographicCamera extends Camera { 16175 16176 constructor(left = - 1, right = 1, top = 1, bottom = - 1, near = 0.1, far = 2000) { 16177 16178 super(); 16179 16180 this.isOrthographicCamera = true; 16181 16182 this.type = 'OrthographicCamera'; 16183 16184 this.zoom = 1; 16185 this.view = null; 16186 16187 this.left = left; 16188 this.right = right; 16189 this.top = top; 16190 this.bottom = bottom; 16191 16192 this.near = near; 16193 this.far = far; 16194 16195 this.updateProjectionMatrix(); 16196 16197 } 16198 16199 copy(source, recursive) { 16200 16201 super.copy(source, recursive); 16202 16203 this.left = source.left; 16204 this.right = source.right; 16205 this.top = source.top; 16206 this.bottom = source.bottom; 16207 this.near = source.near; 16208 this.far = source.far; 16209 16210 this.zoom = source.zoom; 16211 this.view = source.view === null ? null : Object.assign({}, source.view); 16212 16213 return this; 16214 16215 } 16216 16217 setViewOffset(fullWidth, fullHeight, x, y, width, height) { 16218 16219 if (this.view === null) { 16220 16221 this.view = { 16222 enabled: true, 16223 fullWidth: 1, 16224 fullHeight: 1, 16225 offsetX: 0, 16226 offsetY: 0, 16227 width: 1, 16228 height: 1 16229 }; 16230 16231 } 16232 16233 this.view.enabled = true; 16234 this.view.fullWidth = fullWidth; 16235 this.view.fullHeight = fullHeight; 16236 this.view.offsetX = x; 16237 this.view.offsetY = y; 16238 this.view.width = width; 16239 this.view.height = height; 16240 16241 this.updateProjectionMatrix(); 16242 16243 } 16244 16245 clearViewOffset() { 16246 16247 if (this.view !== null) { 16248 16249 this.view.enabled = false; 16250 16251 } 16252 16253 this.updateProjectionMatrix(); 16254 16255 } 16256 16257 updateProjectionMatrix() { 16258 16259 const dx = (this.right - this.left) / (2 * this.zoom); 16260 const dy = (this.top - this.bottom) / (2 * this.zoom); 16261 const cx = (this.right + this.left) / 2; 16262 const cy = (this.top + this.bottom) / 2; 16263 16264 let left = cx - dx; 16265 let right = cx + dx; 16266 let top = cy + dy; 16267 let bottom = cy - dy; 16268 16269 if (this.view !== null && this.view.enabled) { 16270 16271 const scaleW = (this.right - this.left) / this.view.fullWidth / this.zoom; 16272 const scaleH = (this.top - this.bottom) / this.view.fullHeight / this.zoom; 16273 16274 left += scaleW * this.view.offsetX; 16275 right = left + scaleW * this.view.width; 16276 top -= scaleH * this.view.offsetY; 16277 bottom = top - scaleH * this.view.height; 16278 16279 } 16280 16281 this.projectionMatrix.makeOrthographic(left, right, top, bottom, this.near, this.far, this.coordinateSystem); 16282 16283 this.projectionMatrixInverse.copy(this.projectionMatrix).invert(); 16284 16285 } 16286 16287 toJSON(meta) { 16288 16289 const data = super.toJSON(meta); 16290 16291 data.object.zoom = this.zoom; 16292 data.object.left = this.left; 16293 data.object.right = this.right; 16294 data.object.top = this.top; 16295 data.object.bottom = this.bottom; 16296 data.object.near = this.near; 16297 data.object.far = this.far; 16298 16299 if (this.view !== null) data.object.view = Object.assign({}, this.view); 16300 16301 return data; 16302 16303 } 16304 16305} 16306 16307const LOD_MIN = 4; 16308 16309// The standard deviations (radians) associated with the extra mips. These are 16310// chosen to approximate a Trowbridge-Reitz distribution function times the 16311// geometric shadowing function. These sigma values squared must match the 16312// variance #defines in cube_uv_reflection_fragment.glsl.js. 16313const EXTRA_LOD_SIGMA = [0.125, 0.215, 0.35, 0.446, 0.526, 0.582]; 16314 16315// The maximum length of the blur for loop. Smaller sigmas will use fewer 16316// samples and exit early, but not recompile the shader. 16317const MAX_SAMPLES = 20; 16318 16319const _flatCamera = /*@__PURE__*/ new OrthographicCamera(); 16320const _clearColor = /*@__PURE__*/ new Color(); 16321let _oldTarget = null; 16322let _oldActiveCubeFace = 0; 16323let _oldActiveMipmapLevel = 0; 16324 16325// Golden Ratio 16326const PHI = (1 + Math.sqrt(5)) / 2; 16327const INV_PHI = 1 / PHI; 16328 16329// Vertices of a dodecahedron (except the opposites, which represent the 16330// same axis), used as axis directions evenly spread on a sphere. 16331const _axisDirections = [ 16332 /*@__PURE__*/ new Vector3(1, 1, 1), 16333 /*@__PURE__*/ new Vector3(- 1, 1, 1), 16334 /*@__PURE__*/ new Vector3(1, 1, - 1), 16335 /*@__PURE__*/ new Vector3(- 1, 1, - 1), 16336 /*@__PURE__*/ new Vector3(0, PHI, INV_PHI), 16337 /*@__PURE__*/ new Vector3(0, PHI, - INV_PHI), 16338 /*@__PURE__*/ new Vector3(INV_PHI, 0, PHI), 16339 /*@__PURE__*/ new Vector3(- INV_PHI, 0, PHI), 16340 /*@__PURE__*/ new Vector3(PHI, INV_PHI, 0), 16341 /*@__PURE__*/ new Vector3(- PHI, INV_PHI, 0)]; 16342 16343/** 16344 * This class generates a Prefiltered, Mipmapped Radiance Environment Map 16345 * (PMREM) from a cubeMap environment texture. This allows different levels of 16346 * blur to be quickly accessed based on material roughness. It is packed into a 16347 * special CubeUV format that allows us to perform custom interpolation so that 16348 * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap 16349 * chain, it only goes down to the LOD_MIN level (above), and then creates extra 16350 * even more filtered 'mips' at the same LOD_MIN resolution, associated with 16351 * higher roughness levels. In this way we maintain resolution to smoothly 16352 * interpolate diffuse lighting while limiting sampling computation. 16353 * 16354 * Paper: Fast, Accurate Image-Based Lighting 16355 * https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view 16356*/ 16357 16358class PMREMGenerator { 16359 16360 constructor(renderer) { 16361 16362 this._renderer = renderer; 16363 this._pingPongRenderTarget = null; 16364 16365 this._lodMax = 0; 16366 this._cubeSize = 0; 16367 this._lodPlanes = []; 16368 this._sizeLods = []; 16369 this._sigmas = []; 16370 16371 this._blurMaterial = null; 16372 this._cubemapMaterial = null; 16373 this._equirectMaterial = null; 16374 16375 this._compileMaterial(this._blurMaterial); 16376 16377 } 16378 16379 /** 16380 * Generates a PMREM from a supplied Scene, which can be faster than using an 16381 * image if networking bandwidth is low. Optional sigma specifies a blur radius 16382 * in radians to be applied to the scene before PMREM generation. Optional near 16383 * and far planes ensure the scene is rendered in its entirety (the cubeCamera 16384 * is placed at the origin). 16385 */ 16386 fromScene(scene, sigma = 0, near = 0.1, far = 100) { 16387 16388 _oldTarget = this._renderer.getRenderTarget(); 16389 _oldActiveCubeFace = this._renderer.getActiveCubeFace(); 16390 _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); 16391 16392 this._setSize(256); 16393 16394 const cubeUVRenderTarget = this._allocateTargets(); 16395 cubeUVRenderTarget.depthBuffer = true; 16396 16397 this._sceneToCubeUV(scene, near, far, cubeUVRenderTarget); 16398 16399 if (sigma > 0) { 16400 16401 this._blur(cubeUVRenderTarget, 0, 0, sigma); 16402 16403 } 16404 16405 this._applyPMREM(cubeUVRenderTarget); 16406 this._cleanup(cubeUVRenderTarget); 16407 16408 return cubeUVRenderTarget; 16409 16410 } 16411 16412 /** 16413 * Generates a PMREM from an equirectangular texture, which can be either LDR 16414 * or HDR. The ideal input image size is 1k (1024 x 512), 16415 * as this matches best with the 256 x 256 cubemap output. 16416 */ 16417 fromEquirectangular(equirectangular, renderTarget = null) { 16418 16419 return this._fromTexture(equirectangular, renderTarget); 16420 16421 } 16422 16423 /** 16424 * Generates a PMREM from an cubemap texture, which can be either LDR 16425 * or HDR. The ideal input cube size is 256 x 256, 16426 * as this matches best with the 256 x 256 cubemap output. 16427 */ 16428 fromCubemap(cubemap, renderTarget = null) { 16429 16430 return this._fromTexture(cubemap, renderTarget); 16431 16432 } 16433 16434 /** 16435 * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during 16436 * your texture's network fetch for increased concurrency. 16437 */ 16438 compileCubemapShader() { 16439 16440 if (this._cubemapMaterial === null) { 16441 16442 this._cubemapMaterial = _getCubemapMaterial(); 16443 this._compileMaterial(this._cubemapMaterial); 16444 16445 } 16446 16447 } 16448 16449 /** 16450 * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during 16451 * your texture's network fetch for increased concurrency. 16452 */ 16453 compileEquirectangularShader() { 16454 16455 if (this._equirectMaterial === null) { 16456 16457 this._equirectMaterial = _getEquirectMaterial(); 16458 this._compileMaterial(this._equirectMaterial); 16459 16460 } 16461 16462 } 16463 16464 /** 16465 * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class, 16466 * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on 16467 * one of them will cause any others to also become unusable. 16468 */ 16469 dispose() { 16470 16471 this._dispose(); 16472 16473 if (this._cubemapMaterial !== null) this._cubemapMaterial.dispose(); 16474 if (this._equirectMaterial !== null) this._equirectMaterial.dispose(); 16475 16476 } 16477 16478 // private interface 16479 16480 _setSize(cubeSize) { 16481 16482 this._lodMax = Math.floor(Math.log2(cubeSize)); 16483 this._cubeSize = Math.pow(2, this._lodMax); 16484 16485 } 16486 16487 _dispose() { 16488 16489 if (this._blurMaterial !== null) this._blurMaterial.dispose(); 16490 16491 if (this._pingPongRenderTarget !== null) this._pingPongRenderTarget.dispose(); 16492 16493 for (let i = 0; i < this._lodPlanes.length; i++) { 16494 16495 this._lodPlanes[i].dispose(); 16496 16497 } 16498 16499 } 16500 16501 _cleanup(outputTarget) { 16502 16503 this._renderer.setRenderTarget(_oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel); 16504 outputTarget.scissorTest = false; 16505 _setViewport(outputTarget, 0, 0, outputTarget.width, outputTarget.height); 16506 16507 } 16508 16509 _fromTexture(texture, renderTarget) { 16510 16511 if (texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping) { 16512 16513 this._setSize(texture.image.length === 0 ? 16 : (texture.image[0].width || texture.image[0].image.width)); 16514 16515 } else { // Equirectangular 16516 16517 this._setSize(texture.image.width / 4); 16518 16519 } 16520 16521 _oldTarget = this._renderer.getRenderTarget(); 16522 _oldActiveCubeFace = this._renderer.getActiveCubeFace(); 16523 _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); 16524 16525 const cubeUVRenderTarget = renderTarget || this._allocateTargets(); 16526 this._textureToCubeUV(texture, cubeUVRenderTarget); 16527 this._applyPMREM(cubeUVRenderTarget); 16528 this._cleanup(cubeUVRenderTarget); 16529 16530 return cubeUVRenderTarget; 16531 16532 } 16533 16534 _allocateTargets() { 16535 16536 const width = 3 * Math.max(this._cubeSize, 16 * 7); 16537 const height = 4 * this._cubeSize; 16538 16539 const params = { 16540 magFilter: LinearFilter, 16541 minFilter: LinearFilter, 16542 generateMipmaps: false, 16543 type: HalfFloatType, 16544 format: RGBAFormat, 16545 colorSpace: LinearSRGBColorSpace, 16546 depthBuffer: false 16547 }; 16548 16549 const cubeUVRenderTarget = _createRenderTarget(width, height, params); 16550 16551 if (this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height) { 16552 16553 if (this._pingPongRenderTarget !== null) { 16554 16555 this._dispose(); 16556 16557 } 16558 16559 this._pingPongRenderTarget = _createRenderTarget(width, height, params); 16560 16561 const { _lodMax } = this; 16562 ({ sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas } = _createPlanes(_lodMax)); 16563 16564 this._blurMaterial = _getBlurShader(_lodMax, width, height); 16565 16566 } 16567 16568 return cubeUVRenderTarget; 16569 16570 } 16571 16572 _compileMaterial(material) { 16573 16574 const tmpMesh = new Mesh(this._lodPlanes[0], material); 16575 this._renderer.compile(tmpMesh, _flatCamera); 16576 16577 } 16578 16579 _sceneToCubeUV(scene, near, far, cubeUVRenderTarget) { 16580 16581 const fov = 90; 16582 const aspect = 1; 16583 const cubeCamera = new PerspectiveCamera(fov, aspect, near, far); 16584 const upSign = [1, - 1, 1, 1, 1, 1]; 16585 const forwardSign = [1, 1, 1, - 1, - 1, - 1]; 16586 const renderer = this._renderer; 16587 16588 const originalAutoClear = renderer.autoClear; 16589 const toneMapping = renderer.toneMapping; 16590 renderer.getClearColor(_clearColor); 16591 16592 renderer.toneMapping = NoToneMapping; 16593 renderer.autoClear = false; 16594 16595 const backgroundMaterial = new MeshBasicMaterial({ 16596 name: 'PMREM.Background', 16597 side: BackSide, 16598 depthWrite: false, 16599 depthTest: false, 16600 }); 16601 16602 const backgroundBox = new Mesh(new BoxGeometry(), backgroundMaterial); 16603 16604 let useSolidColor = false; 16605 const background = scene.background; 16606 16607 if (background) { 16608 16609 if (background.isColor) { 16610 16611 backgroundMaterial.color.copy(background); 16612 scene.background = null; 16613 useSolidColor = true; 16614 16615 } 16616 16617 } else { 16618 16619 backgroundMaterial.color.copy(_clearColor); 16620 useSolidColor = true; 16621 16622 } 16623 16624 for (let i = 0; i < 6; i++) { 16625 16626 const col = i % 3; 16627 16628 if (col === 0) { 16629 16630 cubeCamera.up.set(0, upSign[i], 0); 16631 cubeCamera.lookAt(forwardSign[i], 0, 0); 16632 16633 } else if (col === 1) { 16634 16635 cubeCamera.up.set(0, 0, upSign[i]); 16636 cubeCamera.lookAt(0, forwardSign[i], 0); 16637 16638 } else { 16639 16640 cubeCamera.up.set(0, upSign[i], 0); 16641 cubeCamera.lookAt(0, 0, forwardSign[i]); 16642 16643 } 16644 16645 const size = this._cubeSize; 16646 16647 _setViewport(cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size); 16648 16649 renderer.setRenderTarget(cubeUVRenderTarget); 16650 16651 if (useSolidColor) { 16652 16653 renderer.render(backgroundBox, cubeCamera); 16654 16655 } 16656 16657 renderer.render(scene, cubeCamera); 16658 16659 } 16660 16661 backgroundBox.geometry.dispose(); 16662 backgroundBox.material.dispose(); 16663 16664 renderer.toneMapping = toneMapping; 16665 renderer.autoClear = originalAutoClear; 16666 scene.background = background; 16667 16668 } 16669 16670 _textureToCubeUV(texture, cubeUVRenderTarget) { 16671 16672 const renderer = this._renderer; 16673 16674 const isCubeTexture = (texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping); 16675 16676 if (isCubeTexture) { 16677 16678 if (this._cubemapMaterial === null) { 16679 16680 this._cubemapMaterial = _getCubemapMaterial(); 16681 16682 } 16683 16684 this._cubemapMaterial.uniforms.flipEnvMap.value = (texture.isRenderTargetTexture === false) ? - 1 : 1; 16685 16686 } else { 16687 16688 if (this._equirectMaterial === null) { 16689 16690 this._equirectMaterial = _getEquirectMaterial(); 16691 16692 } 16693 16694 } 16695 16696 const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial; 16697 const mesh = new Mesh(this._lodPlanes[0], material); 16698 16699 const uniforms = material.uniforms; 16700 16701 uniforms['envMap'].value = texture; 16702 16703 const size = this._cubeSize; 16704 16705 _setViewport(cubeUVRenderTarget, 0, 0, 3 * size, 2 * size); 16706 16707 renderer.setRenderTarget(cubeUVRenderTarget); 16708 renderer.render(mesh, _flatCamera); 16709 16710 } 16711 16712 _applyPMREM(cubeUVRenderTarget) { 16713 16714 const renderer = this._renderer; 16715 const autoClear = renderer.autoClear; 16716 renderer.autoClear = false; 16717 16718 for (let i = 1; i < this._lodPlanes.length; i++) { 16719 16720 const sigma = Math.sqrt(this._sigmas[i] * this._sigmas[i] - this._sigmas[i - 1] * this._sigmas[i - 1]); 16721 16722 const poleAxis = _axisDirections[(i - 1) % _axisDirections.length]; 16723 16724 this._blur(cubeUVRenderTarget, i - 1, i, sigma, poleAxis); 16725 16726 } 16727 16728 renderer.autoClear = autoClear; 16729 16730 } 16731 16732 /** 16733 * This is a two-pass Gaussian blur for a cubemap. Normally this is done 16734 * vertically and horizontally, but this breaks down on a cube. Here we apply 16735 * the blur latitudinally (around the poles), and then longitudinally (towards 16736 * the poles) to approximate the orthogonally-separable blur. It is least 16737 * accurate at the poles, but still does a decent job. 16738 */ 16739 _blur(cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis) { 16740 16741 const pingPongRenderTarget = this._pingPongRenderTarget; 16742 16743 this._halfBlur( 16744 cubeUVRenderTarget, 16745 pingPongRenderTarget, 16746 lodIn, 16747 lodOut, 16748 sigma, 16749 'latitudinal', 16750 poleAxis); 16751 16752 this._halfBlur( 16753 pingPongRenderTarget, 16754 cubeUVRenderTarget, 16755 lodOut, 16756 lodOut, 16757 sigma, 16758 'longitudinal', 16759 poleAxis); 16760 16761 } 16762 16763 _halfBlur(targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis) { 16764 16765 const renderer = this._renderer; 16766 const blurMaterial = this._blurMaterial; 16767 16768 if (direction !== 'latitudinal' && direction !== 'longitudinal') { 16769 16770 console.error( 16771 'blur direction must be either latitudinal or longitudinal!'); 16772 16773 } 16774 16775 // Number of standard deviations at which to cut off the discrete approximation. 16776 const STANDARD_DEVIATIONS = 3; 16777 16778 const blurMesh = new Mesh(this._lodPlanes[lodOut], blurMaterial); 16779 const blurUniforms = blurMaterial.uniforms; 16780 16781 const pixels = this._sizeLods[lodIn] - 1; 16782 const radiansPerPixel = isFinite(sigmaRadians) ? Math.PI / (2 * pixels) : 2 * Math.PI / (2 * MAX_SAMPLES - 1); 16783 const sigmaPixels = sigmaRadians / radiansPerPixel; 16784 const samples = isFinite(sigmaRadians) ? 1 + Math.floor(STANDARD_DEVIATIONS * sigmaPixels) : MAX_SAMPLES; 16785 16786 if (samples > MAX_SAMPLES) { 16787 16788 console.warn(`sigmaRadians, ${sigmaRadians}, is too large and will clip, as it requested ${samples} samples when the maximum is set to ${MAX_SAMPLES}`); 16789 16790 } 16791 16792 const weights = []; 16793 let sum = 0; 16794 16795 for (let i = 0; i < MAX_SAMPLES; ++i) { 16796 16797 const x = i / sigmaPixels; 16798 const weight = Math.exp(- x * x / 2); 16799 weights.push(weight); 16800 16801 if (i === 0) { 16802 16803 sum += weight; 16804 16805 } else if (i < samples) { 16806 16807 sum += 2 * weight; 16808 16809 } 16810 16811 } 16812 16813 for (let i = 0; i < weights.length; i++) { 16814 16815 weights[i] = weights[i] / sum; 16816 16817 } 16818 16819 blurUniforms['envMap'].value = targetIn.texture; 16820 blurUniforms['samples'].value = samples; 16821 blurUniforms['weights'].value = weights; 16822 blurUniforms['latitudinal'].value = direction === 'latitudinal'; 16823 16824 if (poleAxis) { 16825 16826 blurUniforms['poleAxis'].value = poleAxis; 16827 16828 } 16829 16830 const { _lodMax } = this; 16831 blurUniforms['dTheta'].value = radiansPerPixel; 16832 blurUniforms['mipInt'].value = _lodMax - lodIn; 16833 16834 const outputSize = this._sizeLods[lodOut]; 16835 const x = 3 * outputSize * (lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0); 16836 const y = 4 * (this._cubeSize - outputSize); 16837 16838 _setViewport(targetOut, x, y, 3 * outputSize, 2 * outputSize); 16839 renderer.setRenderTarget(targetOut); 16840 renderer.render(blurMesh, _flatCamera); 16841 16842 } 16843 16844} 16845 16846 16847 16848function _createPlanes(lodMax) { 16849 16850 const lodPlanes = []; 16851 const sizeLods = []; 16852 const sigmas = []; 16853 16854 let lod = lodMax; 16855 16856 const totalLods = lodMax - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length; 16857 16858 for (let i = 0; i < totalLods; i++) { 16859 16860 const sizeLod = Math.pow(2, lod); 16861 sizeLods.push(sizeLod); 16862 let sigma = 1.0 / sizeLod; 16863 16864 if (i > lodMax - LOD_MIN) { 16865 16866 sigma = EXTRA_LOD_SIGMA[i - lodMax + LOD_MIN - 1]; 16867 16868 } else if (i === 0) { 16869 16870 sigma = 0; 16871 16872 } 16873 16874 sigmas.push(sigma); 16875 16876 const texelSize = 1.0 / (sizeLod - 2); 16877 const min = - texelSize; 16878 const max = 1 + texelSize; 16879 const uv1 = [min, min, max, min, max, max, min, min, max, max, min, max]; 16880 16881 const cubeFaces = 6; 16882 const vertices = 6; 16883 const positionSize = 3; 16884 const uvSize = 2; 16885 const faceIndexSize = 1; 16886 16887 const position = new Float32Array(positionSize * vertices * cubeFaces); 16888 const uv = new Float32Array(uvSize * vertices * cubeFaces); 16889 const faceIndex = new Float32Array(faceIndexSize * vertices * cubeFaces); 16890 16891 for (let face = 0; face < cubeFaces; face++) { 16892 16893 const x = (face % 3) * 2 / 3 - 1; 16894 const y = face > 2 ? 0 : - 1; 16895 const coordinates = [ 16896 x, y, 0, 16897 x + 2 / 3, y, 0, 16898 x + 2 / 3, y + 1, 0, 16899 x, y, 0, 16900 x + 2 / 3, y + 1, 0, 16901 x, y + 1, 0 16902 ]; 16903 position.set(coordinates, positionSize * vertices * face); 16904 uv.set(uv1, uvSize * vertices * face); 16905 const fill = [face, face, face, face, face, face]; 16906 faceIndex.set(fill, faceIndexSize * vertices * face); 16907 16908 } 16909 16910 const planes = new BufferGeometry(); 16911 planes.setAttribute('position', new BufferAttribute(position, positionSize)); 16912 planes.setAttribute('uv', new BufferAttribute(uv, uvSize)); 16913 planes.setAttribute('faceIndex', new BufferAttribute(faceIndex, faceIndexSize)); 16914 lodPlanes.push(planes); 16915 16916 if (lod > LOD_MIN) { 16917 16918 lod--; 16919 16920 } 16921 16922 } 16923 16924 return { lodPlanes, sizeLods, sigmas }; 16925 16926} 16927 16928function _createRenderTarget(width, height, params) { 16929 16930 const cubeUVRenderTarget = new WebGLRenderTarget(width, height, params); 16931 cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping; 16932 cubeUVRenderTarget.texture.name = 'PMREM.cubeUv'; 16933 cubeUVRenderTarget.scissorTest = true; 16934 return cubeUVRenderTarget; 16935 16936} 16937 16938function _setViewport(target, x, y, width, height) { 16939 16940 target.viewport.set(x, y, width, height); 16941 target.scissor.set(x, y, width, height); 16942 16943} 16944 16945function _getBlurShader(lodMax, width, height) { 16946 16947 const weights = new Float32Array(MAX_SAMPLES);
vendor: 3,245 bytes, lines 16948-17107
16948 const poleAxis = new Vector3(0, 1, 0); 16949 const shaderMaterial = new ShaderMaterial({ 16950 16951 name: 'SphericalGaussianBlur', 16952 16953 defines: { 16954 'n': MAX_SAMPLES, 16955 'CUBEUV_TEXEL_WIDTH': 1.0 / width, 16956 'CUBEUV_TEXEL_HEIGHT': 1.0 / height, 16957 'CUBEUV_MAX_MIP': `${lodMax}.0`, 16958 }, 16959 16960 uniforms: { 16961 'envMap': { value: null }, 16962 'samples': { value: 1 }, 16963 'weights': { value: weights }, 16964 'latitudinal': { value: false }, 16965 'dTheta': { value: 0 }, 16966 'mipInt': { value: 0 }, 16967 'poleAxis': { value: poleAxis } 16968 }, 16969 16970 vertexShader: _getCommonVertexShader(), 16971 16972 fragmentShader: /* glsl */` 16973 16974 precision mediump float; 16975 precision mediump int; 16976 16977 varying vec3 vOutputDirection; 16978 16979 uniform sampler2D envMap; 16980 uniform int samples; 16981 uniform float weights[ n ]; 16982 uniform bool latitudinal; 16983 uniform float dTheta; 16984 uniform float mipInt; 16985 uniform vec3 poleAxis; 16986 16987 #define ENVMAP_TYPE_CUBE_UV 16988 #include <cube_uv_reflection_fragment> 16989 16990 vec3 getSample( float theta, vec3 axis ) { 16991 16992 float cosTheta = cos( theta ); 16993 // Rodrigues' axis-angle rotation 16994 vec3 sampleDirection = vOutputDirection * cosTheta 16995 + cross( axis, vOutputDirection ) * sin( theta ) 16996 + axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta ); 16997 16998 return bilinearCubeUV( envMap, sampleDirection, mipInt ); 16999 17000 } 17001 17002 void main() { 17003 17004 vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection ); 17005 17006 if ( all( equal( axis, vec3( 0.0 ) ) ) ) { 17007 17008 axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x ); 17009 17010 } 17011 17012 axis = normalize( axis ); 17013 17014 gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 ); 17015 gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis ); 17016 17017 for ( int i = 1; i < n; i++ ) { 17018 17019 if ( i >= samples ) { 17020 17021 break; 17022 17023 } 17024 17025 float theta = dTheta * float( i ); 17026 gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis ); 17027 gl_FragColor.rgb += weights[ i ] * getSample( theta, axis ); 17028 17029 } 17030 17031 } 17032 `, 17033 17034 blending: NoBlending, 17035 depthTest: false, 17036 depthWrite: false 17037 17038 }); 17039 17040 return shaderMaterial; 17041 17042} 17043 17044function _getEquirectMaterial() { 17045 17046 return new ShaderMaterial({ 17047 17048 name: 'EquirectangularToCubeUV', 17049 17050 uniforms: { 17051 'envMap': { value: null } 17052 }, 17053 17054 vertexShader: _getCommonVertexShader(), 17055 17056 fragmentShader: /* glsl */` 17057 17058 precision mediump float; 17059 precision mediump int; 17060 17061 varying vec3 vOutputDirection; 17062 17063 uniform sampler2D envMap; 17064 17065 #include <common> 17066 17067 void main() { 17068 17069 vec3 outputDirection = normalize( vOutputDirection ); 17070 vec2 uv = equirectUv( outputDirection ); 17071 17072 gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 ); 17073 17074 } 17075 `, 17076 17077 blending: NoBlending, 17078 depthTest: false, 17079 depthWrite: false 17080 17081 }); 17082 17083} 17084 17085function _getCubemapMaterial() { 17086 17087 return new ShaderMaterial({ 17088 17089 name: 'CubemapToCubeUV', 17090 17091 uniforms: { 17092 'envMap': { value: null }, 17093 'flipEnvMap': { value: - 1 } 17094 }, 17095 17096 vertexShader: _getCommonVertexShader(), 17097 17098 fragmentShader: /* glsl */` 17099 17100 precision mediump float; 17101 precision mediump int; 17102 17103 uniform float flipEnvMap; 17104 17105 varying vec3 vOutputDirection; 17106 17107 uniform samplerCube envMap;
17108 17109 void main() { 17110 17111 gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) ); 17112 17113 } 17114 `, 17115 17116 blending: NoBlending, 17117 depthTest: false, 17118 depthWrite: false 17119 17120 }); 17121 17122} 17123 17124function _getCommonVertexShader() { 17125 17126 return /* glsl */` 17127 17128 precision mediump float; 17129 precision mediump int; 17130 17131 attribute float faceIndex; 17132 17133 varying vec3 vOutputDirection; 17134 17135 // RH coordinate system; PMREM face-indexing convention 17136 vec3 getDirection( vec2 uv, float face ) { 17137 17138 uv = 2.0 * uv - 1.0; 17139 17140 vec3 direction = vec3( uv, 1.0 ); 17141 17142 if ( face == 0.0 ) { 17143 17144 direction = direction.zyx; // ( 1, v, u ) pos x 17145 17146 } else if ( face == 1.0 ) { 17147 17148 direction = direction.xzy; 17149 direction.xz *= -1.0; // ( -u, 1, -v ) pos y 17150 17151 } else if ( face == 2.0 ) { 17152 17153 direction.x *= -1.0; // ( -u, v, 1 ) pos z 17154 17155 } else if ( face == 3.0 ) { 17156 17157 direction = direction.zyx; 17158 direction.xz *= -1.0; // ( -1, v, -u ) neg x 17159 17160 } else if ( face == 4.0 ) { 17161 17162 direction = direction.xzy; 17163 direction.xy *= -1.0; // ( -u, -1, v ) neg y 17164 17165 } else if ( face == 5.0 ) { 17166 17167 direction.z *= -1.0; // ( u, v, -1 ) neg z 17168 17169 } 17170 17171 return direction; 17172 17173 } 17174 17175 void main() { 17176 17177 vOutputDirection = getDirection( uv, faceIndex ); 17178 gl_Position = vec4( position, 1.0 ); 17179 17180 } 17181 `; 17182 17183} 17184 17185function WebGLCubeUVMaps(renderer) { 17186 17187 let cubeUVmaps = new WeakMap(); 17188 17189 let pmremGenerator = null; 17190 17191 function get(texture) { 17192 17193 if (texture && texture.isTexture) { 17194 17195 const mapping = texture.mapping; 17196 17197 const isEquirectMap = (mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping); 17198 const isCubeMap = (mapping === CubeReflectionMapping || mapping === CubeRefractionMapping); 17199 17200 // equirect/cube map to cubeUV conversion 17201 17202 if (isEquirectMap || isCubeMap) { 17203 17204 if (texture.isRenderTargetTexture && texture.needsPMREMUpdate === true) { 17205 17206 texture.needsPMREMUpdate = false; 17207 17208 let renderTarget = cubeUVmaps.get(texture); 17209 17210 if (pmremGenerator === null) pmremGenerator = new PMREMGenerator(renderer); 17211 17212 renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular(texture, renderTarget) : pmremGenerator.fromCubemap(texture, renderTarget); 17213 cubeUVmaps.set(texture, renderTarget); 17214 17215 return renderTarget.texture; 17216 17217 } else { 17218 17219 if (cubeUVmaps.has(texture)) { 17220 17221 return cubeUVmaps.get(texture).texture; 17222 17223 } else { 17224 17225 const image = texture.image; 17226 17227 if ((isEquirectMap && image && image.height > 0) || (isCubeMap && image && isCubeTextureComplete(image))) { 17228 17229 if (pmremGenerator === null) pmremGenerator = new PMREMGenerator(renderer); 17230 17231 const renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular(texture) : pmremGenerator.fromCubemap(texture); 17232 cubeUVmaps.set(texture, renderTarget); 17233 17234 texture.addEventListener('dispose', onTextureDispose); 17235 17236 return renderTarget.texture; 17237 17238 } else { 17239 17240 // image not yet ready. try the conversion next frame 17241 17242 return null; 17243 17244 } 17245 17246 } 17247 17248 } 17249 17250 } 17251 17252 } 17253 17254 return texture; 17255 17256 } 17257 17258 function isCubeTextureComplete(image) { 17259 17260 let count = 0; 17261 const length = 6; 17262 17263 for (let i = 0; i < length; i++) { 17264 17265 if (image[i] !== undefined) count++; 17266 17267 } 17268 17269 return count === length; 17270 17271 17272 } 17273 17274 function onTextureDispose(event) { 17275 17276 const texture = event.target; 17277 17278 texture.removeEventListener('dispose', onTextureDispose); 17279 17280 const cubemapUV = cubeUVmaps.get(texture); 17281 17282 if (cubemapUV !== undefined) { 17283 17284 cubeUVmaps.delete(texture); 17285 cubemapUV.dispose(); 17286 17287 } 17288 17289 } 17290 17291 function dispose() { 17292 17293 cubeUVmaps = new WeakMap(); 17294 17295 if (pmremGenerator !== null) { 17296 17297 pmremGenerator.dispose(); 17298 pmremGenerator = null; 17299 17300 } 17301 17302 } 17303 17304 return { 17305 get: get, 17306 dispose: dispose 17307 }; 17308 17309} 17310 17311function WebGLExtensions(gl) { 17312 17313 const extensions = {}; 17314 17315 function getExtension(name) { 17316 17317 if (extensions[name] !== undefined) { 17318 17319 return extensions[name]; 17320 17321 } 17322 17323 let extension; 17324 17325 switch (name) { 17326 17327 case 'WEBGL_depth_texture': 17328 extension = gl.getExtension('WEBGL_depth_texture') || gl.getExtension('MOZ_WEBGL_depth_texture') || gl.getExtension('WEBKIT_WEBGL_depth_texture'); 17329 break; 17330 17331 case 'EXT_texture_filter_anisotropic': 17332 extension = gl.getExtension('EXT_texture_filter_anisotropic') || gl.getExtension('MOZ_EXT_texture_filter_anisotropic') || gl.getExtension('WEBKIT_EXT_texture_filter_anisotropic'); 17333 break; 17334 17335 case 'WEBGL_compressed_texture_s3tc': 17336 extension = gl.getExtension('WEBGL_compressed_texture_s3tc') || gl.getExtension('MOZ_WEBGL_compressed_texture_s3tc') || gl.getExtension('WEBKIT_WEBGL_compressed_texture_s3tc'); 17337 break; 17338 17339 case 'WEBGL_compressed_texture_pvrtc': 17340 extension = gl.getExtension('WEBGL_compressed_texture_pvrtc') || gl.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc'); 17341 break; 17342 17343 default: 17344 extension = gl.getExtension(name); 17345 17346 } 17347 17348 extensions[name] = extension; 17349 17350 return extension; 17351 17352 } 17353 17354 return { 17355 17356 has: function (name) { 17357 17358 return getExtension(name) !== null; 17359 17360 }, 17361 17362 init: function (capabilities) { 17363 17364 if (capabilities.isWebGL2) { 17365 17366 getExtension('EXT_color_buffer_float'); 17367 getExtension('WEBGL_clip_cull_distance'); 17368 17369 } else { 17370 17371 getExtension('WEBGL_depth_texture'); 17372 getExtension('OES_texture_float'); 17373 getExtension('OES_texture_half_float'); 17374 getExtension('OES_texture_half_float_linear'); 17375 getExtension('OES_standard_derivatives'); 17376 getExtension('OES_element_index_uint'); 17377 getExtension('OES_vertex_array_object'); 17378 getExtension('ANGLE_instanced_arrays'); 17379 17380 } 17381 17382 getExtension('OES_texture_float_linear'); 17383 getExtension('EXT_color_buffer_half_float'); 17384 getExtension('WEBGL_multisampled_render_to_texture'); 17385 17386 }, 17387 17388 get: function (name) { 17389 17390 const extension = getExtension(name); 17391 17392 if (extension === null) { 17393 17394 console.warn('THREE.WebGLRenderer: ' + name + ' extension not supported.'); 17395 17396 } 17397 17398 return extension; 17399 17400 } 17401 17402 }; 17403 17404} 17405 17406function WebGLGeometries(gl, attributes, info, bindingStates) { 17407 17408 const geometries = {}; 17409 const wireframeAttributes = new WeakMap(); 17410 17411 function onGeometryDispose(event) { 17412 17413 const geometry = event.target; 17414 17415 if (geometry.index !== null) { 17416 17417 attributes.remove(geometry.index); 17418 17419 } 17420 17421 for (const name in geometry.attributes) { 17422 17423 attributes.remove(geometry.attributes[name]); 17424 17425 } 17426 17427 for (const name in geometry.morphAttributes) { 17428 17429 const array = geometry.morphAttributes[name]; 17430 17431 for (let i = 0, l = array.length; i < l; i++) { 17432 17433 attributes.remove(array[i]); 17434 17435 } 17436 17437 } 17438 17439 geometry.removeEventListener('dispose', onGeometryDispose); 17440 17441 delete geometries[geometry.id]; 17442 17443 const attribute = wireframeAttributes.get(geometry); 17444 17445 if (attribute) { 17446 17447 attributes.remove(attribute); 17448 wireframeAttributes.delete(geometry); 17449 17450 } 17451 17452 bindingStates.releaseStatesOfGeometry(geometry); 17453 17454 if (geometry.isInstancedBufferGeometry === true) { 17455 17456 delete geometry._maxInstanceCount; 17457 17458 } 17459 17460 // 17461 17462 info.memory.geometries--; 17463 17464 } 17465 17466 function get(object, geometry) { 17467 17468 if (geometries[geometry.id] === true) return geometry; 17469 17470 geometry.addEventListener('dispose', onGeometryDispose); 17471 17472 geometries[geometry.id] = true; 17473 17474 info.memory.geometries++; 17475 17476 return geometry; 17477 17478 } 17479 17480 function update(geometry) { 17481 17482 const geometryAttributes = geometry.attributes; 17483 17484 // Updating index buffer in VAO now. See WebGLBindingStates. 17485 17486 for (const name in geometryAttributes) { 17487 17488 attributes.update(geometryAttributes[name], gl.ARRAY_BUFFER); 17489 17490 } 17491 17492 // morph targets 17493 17494 const morphAttributes = geometry.morphAttributes; 17495 17496 for (const name in morphAttributes) { 17497 17498 const array = morphAttributes[name]; 17499 17500 for (let i = 0, l = array.length; i < l; i++) { 17501 17502 attributes.update(array[i], gl.ARRAY_BUFFER); 17503 17504 } 17505 17506 } 17507 17508 } 17509 17510 function updateWireframeAttribute(geometry) { 17511 17512 const indices = []; 17513 17514 const geometryIndex = geometry.index; 17515 const geometryPosition = geometry.attributes.position; 17516 let version = 0; 17517 17518 if (geometryIndex !== null) { 17519 17520 const array = geometryIndex.array; 17521 version = geometryIndex.version; 17522 17523 for (let i = 0, l = array.length; i < l; i += 3) { 17524 17525 const a = array[i + 0]; 17526 const b = array[i + 1];
vendor: 16,321 bytes, lines 17527-18272
17527 const c = array[i + 2]; 17528 17529 indices.push(a, b, b, c, c, a); 17530 17531 } 17532 17533 } else if (geometryPosition !== undefined) { 17534 17535 const array = geometryPosition.array; 17536 version = geometryPosition.version; 17537 17538 for (let i = 0, l = (array.length / 3) - 1; i < l; i += 3) { 17539 17540 const a = i + 0; 17541 const b = i + 1; 17542 const c = i + 2; 17543 17544 indices.push(a, b, b, c, c, a); 17545 17546 } 17547 17548 } else { 17549 17550 return; 17551 17552 } 17553 17554 const attribute = new (arrayNeedsUint32(indices) ? Uint32BufferAttribute : Uint16BufferAttribute)(indices, 1); 17555 attribute.version = version; 17556 17557 // Updating index buffer in VAO now. See WebGLBindingStates 17558 17559 // 17560 17561 const previousAttribute = wireframeAttributes.get(geometry); 17562 17563 if (previousAttribute) attributes.remove(previousAttribute); 17564 17565 // 17566 17567 wireframeAttributes.set(geometry, attribute); 17568 17569 } 17570 17571 function getWireframeAttribute(geometry) { 17572 17573 const currentAttribute = wireframeAttributes.get(geometry); 17574 17575 if (currentAttribute) { 17576 17577 const geometryIndex = geometry.index; 17578 17579 if (geometryIndex !== null) { 17580 17581 // if the attribute is obsolete, create a new one 17582 17583 if (currentAttribute.version < geometryIndex.version) { 17584 17585 updateWireframeAttribute(geometry); 17586 17587 } 17588 17589 } 17590 17591 } else { 17592 17593 updateWireframeAttribute(geometry); 17594 17595 } 17596 17597 return wireframeAttributes.get(geometry); 17598 17599 } 17600 17601 return { 17602 17603 get: get, 17604 update: update, 17605 17606 getWireframeAttribute: getWireframeAttribute 17607 17608 }; 17609 17610} 17611 17612function WebGLIndexedBufferRenderer(gl, extensions, info, capabilities) { 17613 17614 const isWebGL2 = capabilities.isWebGL2; 17615 17616 let mode; 17617 17618 function setMode(value) { 17619 17620 mode = value; 17621 17622 } 17623 17624 let type, bytesPerElement; 17625 17626 function setIndex(value) { 17627 17628 type = value.type; 17629 bytesPerElement = value.bytesPerElement; 17630 17631 } 17632 17633 function render(start, count) { 17634 17635 gl.drawElements(mode, count, type, start * bytesPerElement); 17636 17637 info.update(count, mode, 1); 17638 17639 } 17640 17641 function renderInstances(start, count, primcount) { 17642 17643 if (primcount === 0) return; 17644 17645 let extension, methodName; 17646 17647 if (isWebGL2) { 17648 17649 extension = gl; 17650 methodName = 'drawElementsInstanced'; 17651 17652 } else { 17653 17654 extension = extensions.get('ANGLE_instanced_arrays'); 17655 methodName = 'drawElementsInstancedANGLE'; 17656 17657 if (extension === null) { 17658 17659 console.error('THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.'); 17660 return; 17661 17662 } 17663 17664 } 17665 17666 extension[methodName](mode, count, type, start * bytesPerElement, primcount); 17667 17668 info.update(count, mode, primcount); 17669 17670 } 17671 17672 function renderMultiDraw(starts, counts, drawCount) { 17673 17674 if (drawCount === 0) return; 17675 17676 const extension = extensions.get('WEBGL_multi_draw'); 17677 if (extension === null) { 17678 17679 for (let i = 0; i < drawCount; i++) { 17680 17681 this.render(starts[i] / bytesPerElement, counts[i]); 17682 17683 } 17684 17685 } else { 17686 17687 extension.multiDrawElementsWEBGL(mode, counts, 0, type, starts, 0, drawCount); 17688 17689 let elementCount = 0; 17690 for (let i = 0; i < drawCount; i++) { 17691 17692 elementCount += counts[i]; 17693 17694 } 17695 17696 info.update(elementCount, mode, 1); 17697 17698 } 17699 17700 } 17701 17702 // 17703 17704 this.setMode = setMode; 17705 this.setIndex = setIndex; 17706 this.render = render; 17707 this.renderInstances = renderInstances; 17708 this.renderMultiDraw = renderMultiDraw; 17709 17710} 17711 17712function WebGLInfo(gl) { 17713 17714 const memory = { 17715 geometries: 0, 17716 textures: 0 17717 }; 17718 17719 const render = { 17720 frame: 0, 17721 calls: 0, 17722 triangles: 0, 17723 points: 0, 17724 lines: 0 17725 }; 17726 17727 function update(count, mode, instanceCount) { 17728 17729 render.calls++; 17730 17731 switch (mode) { 17732 17733 case gl.TRIANGLES: 17734 render.triangles += instanceCount * (count / 3); 17735 break; 17736 17737 case gl.LINES: 17738 render.lines += instanceCount * (count / 2); 17739 break; 17740 17741 case gl.LINE_STRIP: 17742 render.lines += instanceCount * (count - 1); 17743 break; 17744 17745 case gl.LINE_LOOP: 17746 render.lines += instanceCount * count; 17747 break; 17748 17749 case gl.POINTS: 17750 render.points += instanceCount * count; 17751 break; 17752 17753 default: 17754 console.error('THREE.WebGLInfo: Unknown draw mode:', mode); 17755 break; 17756 17757 } 17758 17759 } 17760 17761 function reset() { 17762 17763 render.calls = 0; 17764 render.triangles = 0; 17765 render.points = 0; 17766 render.lines = 0; 17767 17768 } 17769 17770 return { 17771 memory: memory, 17772 render: render, 17773 programs: null, 17774 autoReset: true, 17775 reset: reset, 17776 update: update 17777 }; 17778 17779} 17780 17781function numericalSort(a, b) { 17782 17783 return a[0] - b[0]; 17784 17785} 17786 17787function absNumericalSort(a, b) { 17788 17789 return Math.abs(b[1]) - Math.abs(a[1]); 17790 17791} 17792 17793function WebGLMorphtargets(gl, capabilities, textures) { 17794 17795 const influencesList = {}; 17796 const morphInfluences = new Float32Array(8); 17797 const morphTextures = new WeakMap(); 17798 const morph = new Vector4(); 17799 17800 const workInfluences = []; 17801 17802 for (let i = 0; i < 8; i++) { 17803 17804 workInfluences[i] = [i, 0]; 17805 17806 } 17807 17808 function update(object, geometry, program) { 17809 17810 const objectInfluences = object.morphTargetInfluences; 17811 17812 if (capabilities.isWebGL2 === true) { 17813 17814 // instead of using attributes, the WebGL 2 code path encodes morph targets 17815 // into an array of data textures. Each layer represents a single morph target. 17816 17817 const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; 17818 const morphTargetsCount = (morphAttribute !== undefined) ? morphAttribute.length : 0; 17819 17820 let entry = morphTextures.get(geometry); 17821 17822 if (entry === undefined || entry.count !== morphTargetsCount) { 17823 17824 if (entry !== undefined) entry.texture.dispose(); 17825 17826 const hasMorphPosition = geometry.morphAttributes.position !== undefined; 17827 const hasMorphNormals = geometry.morphAttributes.normal !== undefined; 17828 const hasMorphColors = geometry.morphAttributes.color !== undefined; 17829 17830 const morphTargets = geometry.morphAttributes.position || []; 17831 const morphNormals = geometry.morphAttributes.normal || []; 17832 const morphColors = geometry.morphAttributes.color || []; 17833 17834 let vertexDataCount = 0; 17835 17836 if (hasMorphPosition === true) vertexDataCount = 1; 17837 if (hasMorphNormals === true) vertexDataCount = 2; 17838 if (hasMorphColors === true) vertexDataCount = 3; 17839 17840 let width = geometry.attributes.position.count * vertexDataCount; 17841 let height = 1; 17842 17843 if (width > capabilities.maxTextureSize) { 17844 17845 height = Math.ceil(width / capabilities.maxTextureSize); 17846 width = capabilities.maxTextureSize; 17847 17848 } 17849 17850 const buffer = new Float32Array(width * height * 4 * morphTargetsCount); 17851 17852 const texture = new DataArrayTexture(buffer, width, height, morphTargetsCount); 17853 texture.type = FloatType; 17854 texture.needsUpdate = true; 17855 17856 // fill buffer 17857 17858 const vertexDataStride = vertexDataCount * 4; 17859 17860 for (let i = 0; i < morphTargetsCount; i++) { 17861 17862 const morphTarget = morphTargets[i]; 17863 const morphNormal = morphNormals[i]; 17864 const morphColor = morphColors[i]; 17865 17866 const offset = width * height * 4 * i; 17867 17868 for (let j = 0; j < morphTarget.count; j++) { 17869 17870 const stride = j * vertexDataStride; 17871 17872 if (hasMorphPosition === true) { 17873 17874 morph.fromBufferAttribute(morphTarget, j); 17875 17876 buffer[offset + stride + 0] = morph.x; 17877 buffer[offset + stride + 1] = morph.y; 17878 buffer[offset + stride + 2] = morph.z; 17879 buffer[offset + stride + 3] = 0; 17880 17881 } 17882 17883 if (hasMorphNormals === true) { 17884 17885 morph.fromBufferAttribute(morphNormal, j); 17886 17887 buffer[offset + stride + 4] = morph.x; 17888 buffer[offset + stride + 5] = morph.y; 17889 buffer[offset + stride + 6] = morph.z; 17890 buffer[offset + stride + 7] = 0; 17891 17892 } 17893 17894 if (hasMorphColors === true) { 17895 17896 morph.fromBufferAttribute(morphColor, j); 17897 17898 buffer[offset + stride + 8] = morph.x; 17899 buffer[offset + stride + 9] = morph.y; 17900 buffer[offset + stride + 10] = morph.z; 17901 buffer[offset + stride + 11] = (morphColor.itemSize === 4) ? morph.w : 1; 17902 17903 } 17904 17905 } 17906 17907 } 17908 17909 entry = { 17910 count: morphTargetsCount, 17911 texture: texture, 17912 size: new Vector2(width, height) 17913 }; 17914 17915 morphTextures.set(geometry, entry); 17916 17917 function disposeTexture() { 17918 17919 texture.dispose(); 17920 17921 morphTextures.delete(geometry); 17922 17923 geometry.removeEventListener('dispose', disposeTexture); 17924 17925 } 17926 17927 geometry.addEventListener('dispose', disposeTexture); 17928 17929 } 17930 17931 // 17932 17933 let morphInfluencesSum = 0; 17934 17935 for (let i = 0; i < objectInfluences.length; i++) { 17936 17937 morphInfluencesSum += objectInfluences[i]; 17938 17939 } 17940 17941 const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum; 17942 17943 program.getUniforms().setValue(gl, 'morphTargetBaseInfluence', morphBaseInfluence); 17944 program.getUniforms().setValue(gl, 'morphTargetInfluences', objectInfluences); 17945 17946 program.getUniforms().setValue(gl, 'morphTargetsTexture', entry.texture, textures); 17947 program.getUniforms().setValue(gl, 'morphTargetsTextureSize', entry.size); 17948 17949 17950 } else { 17951 17952 // When object doesn't have morph target influences defined, we treat it as a 0-length array 17953 // This is important to make sure we set up morphTargetBaseInfluence / morphTargetInfluences 17954 17955 const length = objectInfluences === undefined ? 0 : objectInfluences.length; 17956 17957 let influences = influencesList[geometry.id]; 17958 17959 if (influences === undefined || influences.length !== length) { 17960 17961 // initialise list 17962 17963 influences = []; 17964 17965 for (let i = 0; i < length; i++) { 17966 17967 influences[i] = [i, 0]; 17968 17969 } 17970 17971 influencesList[geometry.id] = influences; 17972 17973 } 17974 17975 // Collect influences 17976 17977 for (let i = 0; i < length; i++) { 17978 17979 const influence = influences[i]; 17980 17981 influence[0] = i; 17982 influence[1] = objectInfluences[i]; 17983 17984 } 17985 17986 influences.sort(absNumericalSort); 17987 17988 for (let i = 0; i < 8; i++) { 17989 17990 if (i < length && influences[i][1]) { 17991 17992 workInfluences[i][0] = influences[i][0]; 17993 workInfluences[i][1] = influences[i][1]; 17994 17995 } else { 17996 17997 workInfluences[i][0] = Number.MAX_SAFE_INTEGER; 17998 workInfluences[i][1] = 0; 17999 18000 } 18001 18002 } 18003 18004 workInfluences.sort(numericalSort); 18005 18006 const morphTargets = geometry.morphAttributes.position; 18007 const morphNormals = geometry.morphAttributes.normal; 18008 18009 let morphInfluencesSum = 0; 18010 18011 for (let i = 0; i < 8; i++) { 18012 18013 const influence = workInfluences[i]; 18014 const index = influence[0]; 18015 const value = influence[1]; 18016 18017 if (index !== Number.MAX_SAFE_INTEGER && value) { 18018 18019 if (morphTargets && geometry.getAttribute('morphTarget' + i) !== morphTargets[index]) { 18020 18021 geometry.setAttribute('morphTarget' + i, morphTargets[index]); 18022 18023 } 18024 18025 if (morphNormals && geometry.getAttribute('morphNormal' + i) !== morphNormals[index]) { 18026 18027 geometry.setAttribute('morphNormal' + i, morphNormals[index]); 18028 18029 } 18030 18031 morphInfluences[i] = value; 18032 morphInfluencesSum += value; 18033 18034 } else { 18035 18036 if (morphTargets && geometry.hasAttribute('morphTarget' + i) === true) { 18037 18038 geometry.deleteAttribute('morphTarget' + i); 18039 18040 } 18041 18042 if (morphNormals && geometry.hasAttribute('morphNormal' + i) === true) { 18043 18044 geometry.deleteAttribute('morphNormal' + i); 18045 18046 } 18047 18048 morphInfluences[i] = 0; 18049 18050 } 18051 18052 } 18053 18054 // GLSL shader uses formula baseinfluence * base + sum(target * influence) 18055 // This allows us to switch between absolute morphs and relative morphs without changing shader code 18056 // When baseinfluence = 1 - sum(influence), the above is equivalent to sum((target - base) * influence) 18057 const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum; 18058 18059 program.getUniforms().setValue(gl, 'morphTargetBaseInfluence', morphBaseInfluence); 18060 program.getUniforms().setValue(gl, 'morphTargetInfluences', morphInfluences); 18061 18062 } 18063 18064 } 18065 18066 return { 18067 18068 update: update 18069 18070 }; 18071 18072} 18073 18074function WebGLObjects(gl, geometries, attributes, info) { 18075 18076 let updateMap = new WeakMap(); 18077 18078 function update(object) { 18079 18080 const frame = info.render.frame; 18081 18082 const geometry = object.geometry; 18083 const buffergeometry = geometries.get(object, geometry); 18084 18085 // Update once per frame 18086 18087 if (updateMap.get(buffergeometry) !== frame) { 18088 18089 geometries.update(buffergeometry); 18090 18091 updateMap.set(buffergeometry, frame); 18092 18093 } 18094 18095 if (object.isInstancedMesh) { 18096 18097 if (object.hasEventListener('dispose', onInstancedMeshDispose) === false) { 18098 18099 object.addEventListener('dispose', onInstancedMeshDispose); 18100 18101 } 18102 18103 if (updateMap.get(object) !== frame) { 18104 18105 attributes.update(object.instanceMatrix, gl.ARRAY_BUFFER); 18106 18107 if (object.instanceColor !== null) { 18108 18109 attributes.update(object.instanceColor, gl.ARRAY_BUFFER); 18110 18111 } 18112 18113 updateMap.set(object, frame); 18114 18115 } 18116 18117 } 18118 18119 if (object.isSkinnedMesh) { 18120 18121 const skeleton = object.skeleton; 18122 18123 if (updateMap.get(skeleton) !== frame) { 18124 18125 skeleton.update(); 18126 18127 updateMap.set(skeleton, frame); 18128 18129 } 18130 18131 } 18132 18133 return buffergeometry; 18134 18135 } 18136 18137 function dispose() { 18138 18139 updateMap = new WeakMap(); 18140 18141 } 18142 18143 function onInstancedMeshDispose(event) { 18144 18145 const instancedMesh = event.target; 18146 18147 instancedMesh.removeEventListener('dispose', onInstancedMeshDispose); 18148 18149 attributes.remove(instancedMesh.instanceMatrix); 18150 18151 if (instancedMesh.instanceColor !== null) attributes.remove(instancedMesh.instanceColor); 18152 18153 } 18154 18155 return { 18156 18157 update: update, 18158 dispose: dispose 18159 18160 }; 18161 18162} 18163 18164class DepthTexture extends Texture { 18165 18166 constructor(width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format) { 18167 18168 format = format !== undefined ? format : DepthFormat; 18169 18170 if (format !== DepthFormat && format !== DepthStencilFormat) { 18171 18172 throw new Error('DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat'); 18173 18174 } 18175 18176 if (type === undefined && format === DepthFormat) type = UnsignedIntType; 18177 if (type === undefined && format === DepthStencilFormat) type = UnsignedInt248Type; 18178 18179 super(null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy); 18180 18181 this.isDepthTexture = true; 18182 18183 this.image = { width: width, height: height }; 18184 18185 this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; 18186 this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; 18187 18188 this.flipY = false; 18189 this.generateMipmaps = false; 18190 18191 this.compareFunction = null; 18192 18193 } 18194 18195 18196 copy(source) { 18197 18198 super.copy(source); 18199 18200 this.compareFunction = source.compareFunction; 18201 18202 return this; 18203 18204 } 18205 18206 toJSON(meta) { 18207 18208 const data = super.toJSON(meta); 18209 18210 if (this.compareFunction !== null) data.compareFunction = this.compareFunction; 18211 18212 return data; 18213 18214 } 18215 18216} 18217 18218/** 18219 * Uniforms of a program. 18220 * Those form a tree structure with a special top-level container for the root, 18221 * which you get by calling 'new WebGLUniforms( gl, program )'. 18222 * 18223 * 18224 * Properties of inner nodes including the top-level container: 18225 * 18226 * .seq - array of nested uniforms 18227 * .map - nested uniforms by name 18228 * 18229 * 18230 * Methods of all nodes except the top-level container: 18231 * 18232 * .setValue( gl, value, [textures] ) 18233 * 18234 * uploads a uniform value(s) 18235 * the 'textures' parameter is needed for sampler uniforms 18236 * 18237 * 18238 * Static methods of the top-level container (textures factorizations): 18239 * 18240 * .upload( gl, seq, values, textures ) 18241 * 18242 * sets uniforms in 'seq' to 'values[id].value' 18243 * 18244 * .seqWithValue( seq, values ) : filteredSeq 18245 * 18246 * filters 'seq' entries with corresponding entry in values 18247 * 18248 * 18249 * Methods of the top-level container (textures factorizations): 18250 * 18251 * .setValue( gl, name, value, textures ) 18252 * 18253 * sets uniform with name 'name' to 'value' 18254 * 18255 * .setOptional( gl, obj, prop ) 18256 * 18257 * like .set for an optional property of the object 18258 * 18259 */ 18260 18261 18262const emptyTexture = /*@__PURE__*/ new Texture(); 18263 18264const emptyShadowTexture = /*@__PURE__*/ new DepthTexture(1, 1); 18265emptyShadowTexture.compareFunction = LessEqualCompare; 18266 18267const emptyArrayTexture = /*@__PURE__*/ new DataArrayTexture(); 18268const empty3dTexture = /*@__PURE__*/ new Data3DTexture(); 18269const emptyCubeTexture = /*@__PURE__*/ new CubeTexture(); 18270 18271// --- Utilities --- 18272
vendor: 1,384 bytes, lines 18273-18353
18273// Array Caches (provide typed arrays for temporary by size) 18274 18275const arrayCacheF32 = []; 18276const arrayCacheI32 = []; 18277 18278// Float32Array caches used for uploading Matrix uniforms 18279 18280const mat4array = new Float32Array(16); 18281const mat3array = new Float32Array(9); 18282const mat2array = new Float32Array(4); 18283 18284// Flattening for arrays of vectors and matrices 18285 18286function flatten(array, nBlocks, blockSize) { 18287 18288 const firstElem = array[0]; 18289 18290 if (firstElem <= 0 || firstElem > 0) return array; 18291 // unoptimized: ! isNaN( firstElem ) 18292 // see http://jacksondunstan.com/articles/983 18293 18294 const n = nBlocks * blockSize; 18295 let r = arrayCacheF32[n]; 18296 18297 if (r === undefined) { 18298 18299 r = new Float32Array(n); 18300 arrayCacheF32[n] = r; 18301 18302 } 18303 18304 if (nBlocks !== 0) { 18305 18306 firstElem.toArray(r, 0); 18307 18308 for (let i = 1, offset = 0; i !== nBlocks; ++i) { 18309 18310 offset += blockSize; 18311 array[i].toArray(r, offset); 18312 18313 } 18314 18315 } 18316 18317 return r; 18318 18319} 18320 18321function arraysEqual(a, b) { 18322 18323 if (a.length !== b.length) return false; 18324 18325 for (let i = 0, l = a.length; i < l; i++) { 18326 18327 if (a[i] !== b[i]) return false; 18328 18329 } 18330 18331 return true; 18332 18333} 18334 18335function copyArray(a, b) { 18336 18337 for (let i = 0, l = b.length; i < l; i++) { 18338 18339 a[i] = b[i]; 18340 18341 } 18342 18343} 18344 18345// Texture unit allocation 18346 18347function allocTexUnits(textures, n) { 18348 18349 let r = arrayCacheI32[n]; 18350 18351 if (r === undefined) { 18352 18353 r = new Int32Array(n);
vendor: 6,498 bytes, lines 18354-18783
18354 arrayCacheI32[n] = r; 18355 18356 } 18357 18358 for (let i = 0; i !== n; ++i) { 18359 18360 r[i] = textures.allocateTextureUnit(); 18361 18362 } 18363 18364 return r; 18365 18366} 18367 18368// --- Setters --- 18369 18370// Note: Defining these methods externally, because they come in a bunch 18371// and this way their names minify. 18372 18373// Single scalar 18374 18375function setValueV1f(gl, v) { 18376 18377 const cache = this.cache; 18378 18379 if (cache[0] === v) return; 18380 18381 gl.uniform1f(this.addr, v); 18382 18383 cache[0] = v; 18384 18385} 18386 18387// Single float vector (from flat array or THREE.VectorN) 18388 18389function setValueV2f(gl, v) { 18390 18391 const cache = this.cache; 18392 18393 if (v.x !== undefined) { 18394 18395 if (cache[0] !== v.x || cache[1] !== v.y) { 18396 18397 gl.uniform2f(this.addr, v.x, v.y); 18398 18399 cache[0] = v.x; 18400 cache[1] = v.y; 18401 18402 } 18403 18404 } else { 18405 18406 if (arraysEqual(cache, v)) return; 18407 18408 gl.uniform2fv(this.addr, v); 18409 18410 copyArray(cache, v); 18411 18412 } 18413 18414} 18415 18416function setValueV3f(gl, v) { 18417 18418 const cache = this.cache; 18419 18420 if (v.x !== undefined) { 18421 18422 if (cache[0] !== v.x || cache[1] !== v.y || cache[2] !== v.z) { 18423 18424 gl.uniform3f(this.addr, v.x, v.y, v.z); 18425 18426 cache[0] = v.x; 18427 cache[1] = v.y; 18428 cache[2] = v.z; 18429 18430 } 18431 18432 } else if (v.r !== undefined) { 18433 18434 if (cache[0] !== v.r || cache[1] !== v.g || cache[2] !== v.b) { 18435 18436 gl.uniform3f(this.addr, v.r, v.g, v.b); 18437 18438 cache[0] = v.r; 18439 cache[1] = v.g; 18440 cache[2] = v.b; 18441 18442 } 18443 18444 } else { 18445 18446 if (arraysEqual(cache, v)) return; 18447 18448 gl.uniform3fv(this.addr, v); 18449 18450 copyArray(cache, v); 18451 18452 } 18453 18454} 18455 18456function setValueV4f(gl, v) { 18457 18458 const cache = this.cache; 18459 18460 if (v.x !== undefined) { 18461 18462 if (cache[0] !== v.x || cache[1] !== v.y || cache[2] !== v.z || cache[3] !== v.w) { 18463 18464 gl.uniform4f(this.addr, v.x, v.y, v.z, v.w); 18465 18466 cache[0] = v.x; 18467 cache[1] = v.y; 18468 cache[2] = v.z; 18469 cache[3] = v.w; 18470 18471 } 18472 18473 } else { 18474 18475 if (arraysEqual(cache, v)) return; 18476 18477 gl.uniform4fv(this.addr, v); 18478 18479 copyArray(cache, v); 18480 18481 } 18482 18483} 18484 18485// Single matrix (from flat array or THREE.MatrixN) 18486 18487function setValueM2(gl, v) { 18488 18489 const cache = this.cache; 18490 const elements = v.elements; 18491 18492 if (elements === undefined) { 18493 18494 if (arraysEqual(cache, v)) return; 18495 18496 gl.uniformMatrix2fv(this.addr, false, v); 18497 18498 copyArray(cache, v); 18499 18500 } else { 18501 18502 if (arraysEqual(cache, elements)) return; 18503 18504 mat2array.set(elements); 18505 18506 gl.uniformMatrix2fv(this.addr, false, mat2array); 18507 18508 copyArray(cache, elements); 18509 18510 } 18511 18512} 18513 18514function setValueM3(gl, v) { 18515 18516 const cache = this.cache; 18517 const elements = v.elements; 18518 18519 if (elements === undefined) { 18520 18521 if (arraysEqual(cache, v)) return; 18522 18523 gl.uniformMatrix3fv(this.addr, false, v); 18524 18525 copyArray(cache, v); 18526 18527 } else { 18528 18529 if (arraysEqual(cache, elements)) return; 18530 18531 mat3array.set(elements); 18532 18533 gl.uniformMatrix3fv(this.addr, false, mat3array); 18534 18535 copyArray(cache, elements); 18536 18537 } 18538 18539} 18540 18541function setValueM4(gl, v) { 18542 18543 const cache = this.cache; 18544 const elements = v.elements; 18545 18546 if (elements === undefined) { 18547 18548 if (arraysEqual(cache, v)) return; 18549 18550 gl.uniformMatrix4fv(this.addr, false, v); 18551 18552 copyArray(cache, v); 18553 18554 } else { 18555 18556 if (arraysEqual(cache, elements)) return; 18557 18558 mat4array.set(elements); 18559 18560 gl.uniformMatrix4fv(this.addr, false, mat4array); 18561 18562 copyArray(cache, elements); 18563 18564 } 18565 18566} 18567 18568// Single integer / boolean 18569 18570function setValueV1i(gl, v) { 18571 18572 const cache = this.cache; 18573 18574 if (cache[0] === v) return; 18575 18576 gl.uniform1i(this.addr, v); 18577 18578 cache[0] = v; 18579 18580} 18581 18582// Single integer / boolean vector (from flat array or THREE.VectorN) 18583 18584function setValueV2i(gl, v) { 18585 18586 const cache = this.cache; 18587 18588 if (v.x !== undefined) { 18589 18590 if (cache[0] !== v.x || cache[1] !== v.y) { 18591 18592 gl.uniform2i(this.addr, v.x, v.y); 18593 18594 cache[0] = v.x; 18595 cache[1] = v.y; 18596 18597 } 18598 18599 } else { 18600 18601 if (arraysEqual(cache, v)) return; 18602 18603 gl.uniform2iv(this.addr, v); 18604 18605 copyArray(cache, v); 18606 18607 } 18608 18609} 18610 18611function setValueV3i(gl, v) { 18612 18613 const cache = this.cache; 18614 18615 if (v.x !== undefined) { 18616 18617 if (cache[0] !== v.x || cache[1] !== v.y || cache[2] !== v.z) { 18618 18619 gl.uniform3i(this.addr, v.x, v.y, v.z); 18620 18621 cache[0] = v.x; 18622 cache[1] = v.y; 18623 cache[2] = v.z; 18624 18625 } 18626 18627 } else { 18628 18629 if (arraysEqual(cache, v)) return; 18630 18631 gl.uniform3iv(this.addr, v); 18632 18633 copyArray(cache, v); 18634 18635 } 18636 18637} 18638 18639function setValueV4i(gl, v) { 18640 18641 const cache = this.cache; 18642 18643 if (v.x !== undefined) { 18644 18645 if (cache[0] !== v.x || cache[1] !== v.y || cache[2] !== v.z || cache[3] !== v.w) { 18646 18647 gl.uniform4i(this.addr, v.x, v.y, v.z, v.w); 18648 18649 cache[0] = v.x; 18650 cache[1] = v.y; 18651 cache[2] = v.z; 18652 cache[3] = v.w; 18653 18654 } 18655 18656 } else { 18657 18658 if (arraysEqual(cache, v)) return; 18659 18660 gl.uniform4iv(this.addr, v); 18661 18662 copyArray(cache, v); 18663 18664 } 18665 18666} 18667 18668// Single unsigned integer 18669 18670function setValueV1ui(gl, v) { 18671 18672 const cache = this.cache; 18673 18674 if (cache[0] === v) return; 18675 18676 gl.uniform1ui(this.addr, v); 18677 18678 cache[0] = v; 18679 18680} 18681 18682// Single unsigned integer vector (from flat array or THREE.VectorN) 18683 18684function setValueV2ui(gl, v) { 18685 18686 const cache = this.cache; 18687 18688 if (v.x !== undefined) { 18689 18690 if (cache[0] !== v.x || cache[1] !== v.y) { 18691 18692 gl.uniform2ui(this.addr, v.x, v.y); 18693 18694 cache[0] = v.x; 18695 cache[1] = v.y; 18696 18697 } 18698 18699 } else { 18700 18701 if (arraysEqual(cache, v)) return; 18702 18703 gl.uniform2uiv(this.addr, v); 18704 18705 copyArray(cache, v); 18706 18707 } 18708 18709} 18710 18711function setValueV3ui(gl, v) { 18712 18713 const cache = this.cache; 18714 18715 if (v.x !== undefined) { 18716 18717 if (cache[0] !== v.x || cache[1] !== v.y || cache[2] !== v.z) { 18718 18719 gl.uniform3ui(this.addr, v.x, v.y, v.z); 18720 18721 cache[0] = v.x; 18722 cache[1] = v.y; 18723 cache[2] = v.z; 18724 18725 } 18726 18727 } else { 18728 18729 if (arraysEqual(cache, v)) return; 18730 18731 gl.uniform3uiv(this.addr, v); 18732 18733 copyArray(cache, v); 18734 18735 } 18736 18737} 18738 18739function setValueV4ui(gl, v) { 18740 18741 const cache = this.cache; 18742 18743 if (v.x !== undefined) { 18744 18745 if (cache[0] !== v.x || cache[1] !== v.y || cache[2] !== v.z || cache[3] !== v.w) { 18746 18747 gl.uniform4ui(this.addr, v.x, v.y, v.z, v.w); 18748 18749 cache[0] = v.x; 18750 cache[1] = v.y; 18751 cache[2] = v.z; 18752 cache[3] = v.w; 18753 18754 } 18755 18756 } else { 18757 18758 if (arraysEqual(cache, v)) return; 18759 18760 gl.uniform4uiv(this.addr, v); 18761 18762 copyArray(cache, v); 18763 18764 } 18765 18766} 18767 18768 18769// Single texture (2D / Cube) 18770 18771function setValueT1(gl, v, textures) { 18772 18773 const cache = this.cache; 18774 const unit = textures.allocateTextureUnit(); 18775 18776 if (cache[0] !== unit) { 18777 18778 gl.uniform1i(this.addr, unit); 18779 cache[0] = unit; 18780 18781 } 18782 18783 const emptyTexture2D = (this.type === gl.SAMPLER_2D_SHADOW) ? emptySh
vendor: 7,261 bytes, lines 18783-19146
18783adowTexture : emptyTexture; 18784 18785 textures.setTexture2D(v || emptyTexture2D, unit); 18786 18787} 18788 18789function setValueT3D1(gl, v, textures) { 18790 18791 const cache = this.cache; 18792 const unit = textures.allocateTextureUnit(); 18793 18794 if (cache[0] !== unit) { 18795 18796 gl.uniform1i(this.addr, unit); 18797 cache[0] = unit; 18798 18799 } 18800 18801 textures.setTexture3D(v || empty3dTexture, unit); 18802 18803} 18804 18805function setValueT6(gl, v, textures) { 18806 18807 const cache = this.cache; 18808 const unit = textures.allocateTextureUnit(); 18809 18810 if (cache[0] !== unit) { 18811 18812 gl.uniform1i(this.addr, unit); 18813 cache[0] = unit; 18814 18815 } 18816 18817 textures.setTextureCube(v || emptyCubeTexture, unit); 18818 18819} 18820 18821function setValueT2DArray1(gl, v, textures) { 18822 18823 const cache = this.cache; 18824 const unit = textures.allocateTextureUnit(); 18825 18826 if (cache[0] !== unit) { 18827 18828 gl.uniform1i(this.addr, unit); 18829 cache[0] = unit; 18830 18831 } 18832 18833 textures.setTexture2DArray(v || emptyArrayTexture, unit); 18834 18835} 18836 18837// Helper to pick the right setter for the singular case 18838 18839function getSingularSetter(type) { 18840 18841 switch (type) { 18842 18843 case 0x1406: return setValueV1f; // FLOAT 18844 case 0x8b50: return setValueV2f; // _VEC2 18845 case 0x8b51: return setValueV3f; // _VEC3 18846 case 0x8b52: return setValueV4f; // _VEC4 18847 18848 case 0x8b5a: return setValueM2; // _MAT2 18849 case 0x8b5b: return setValueM3; // _MAT3 18850 case 0x8b5c: return setValueM4; // _MAT4 18851 18852 case 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL 18853 case 0x8b53: case 0x8b57: return setValueV2i; // _VEC2 18854 case 0x8b54: case 0x8b58: return setValueV3i; // _VEC3 18855 case 0x8b55: case 0x8b59: return setValueV4i; // _VEC4 18856 18857 case 0x1405: return setValueV1ui; // UINT 18858 case 0x8dc6: return setValueV2ui; // _VEC2 18859 case 0x8dc7: return setValueV3ui; // _VEC3 18860 case 0x8dc8: return setValueV4ui; // _VEC4 18861 18862 case 0x8b5e: // SAMPLER_2D 18863 case 0x8d66: // SAMPLER_EXTERNAL_OES 18864 case 0x8dca: // INT_SAMPLER_2D 18865 case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D 18866 case 0x8b62: // SAMPLER_2D_SHADOW 18867 return setValueT1; 18868 18869 case 0x8b5f: // SAMPLER_3D 18870 case 0x8dcb: // INT_SAMPLER_3D 18871 case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D 18872 return setValueT3D1; 18873 18874 case 0x8b60: // SAMPLER_CUBE 18875 case 0x8dcc: // INT_SAMPLER_CUBE 18876 case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE 18877 case 0x8dc5: // SAMPLER_CUBE_SHADOW 18878 return setValueT6; 18879 18880 case 0x8dc1: // SAMPLER_2D_ARRAY 18881 case 0x8dcf: // INT_SAMPLER_2D_ARRAY 18882 case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY 18883 case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW 18884 return setValueT2DArray1; 18885 18886 } 18887 18888} 18889 18890 18891// Array of scalars 18892 18893function setValueV1fArray(gl, v) { 18894 18895 gl.uniform1fv(this.addr, v); 18896 18897} 18898 18899// Array of vectors (from flat array or array of THREE.VectorN) 18900 18901function setValueV2fArray(gl, v) { 18902 18903 const data = flatten(v, this.size, 2); 18904 18905 gl.uniform2fv(this.addr, data); 18906 18907} 18908 18909function setValueV3fArray(gl, v) { 18910 18911 const data = flatten(v, this.size, 3); 18912 18913 gl.uniform3fv(this.addr, data); 18914 18915} 18916 18917function setValueV4fArray(gl, v) { 18918 18919 const data = flatten(v, this.size, 4); 18920 18921 gl.uniform4fv(this.addr, data); 18922 18923} 18924 18925// Array of matrices (from flat array or array of THREE.MatrixN) 18926 18927function setValueM2Array(gl, v) { 18928 18929 const data = flatten(v, this.size, 4); 18930 18931 gl.uniformMatrix2fv(this.addr, false, data); 18932 18933} 18934 18935function setValueM3Array(gl, v) { 18936 18937 const data = flatten(v, this.size, 9); 18938 18939 gl.uniformMatrix3fv(this.addr, false, data); 18940 18941} 18942 18943function setValueM4Array(gl, v) { 18944 18945 const data = flatten(v, this.size, 16); 18946 18947 gl.uniformMatrix4fv(this.addr, false, data); 18948 18949} 18950 18951// Array of integer / boolean 18952 18953function setValueV1iArray(gl, v) { 18954 18955 gl.uniform1iv(this.addr, v); 18956 18957} 18958 18959// Array of integer / boolean vectors (from flat array) 18960 18961function setValueV2iArray(gl, v) { 18962 18963 gl.uniform2iv(this.addr, v); 18964 18965} 18966 18967function setValueV3iArray(gl, v) { 18968 18969 gl.uniform3iv(this.addr, v); 18970 18971} 18972 18973function setValueV4iArray(gl, v) { 18974 18975 gl.uniform4iv(this.addr, v); 18976 18977} 18978 18979// Array of unsigned integer 18980 18981function setValueV1uiArray(gl, v) { 18982 18983 gl.uniform1uiv(this.addr, v); 18984 18985} 18986 18987// Array of unsigned integer vectors (from flat array) 18988 18989function setValueV2uiArray(gl, v) { 18990 18991 gl.uniform2uiv(this.addr, v); 18992 18993} 18994 18995function setValueV3uiArray(gl, v) { 18996 18997 gl.uniform3uiv(this.addr, v); 18998 18999} 19000 19001function setValueV4uiArray(gl, v) { 19002 19003 gl.uniform4uiv(this.addr, v); 19004 19005} 19006 19007 19008// Array of textures (2D / 3D / Cube / 2DArray) 19009 19010function setValueT1Array(gl, v, textures) { 19011 19012 const cache = this.cache; 19013 19014 const n = v.length; 19015 19016 const units = allocTexUnits(textures, n); 19017 19018 if (!arraysEqual(cache, units)) { 19019 19020 gl.uniform1iv(this.addr, units); 19021 19022 copyArray(cache, units); 19023 19024 } 19025 19026 for (let i = 0; i !== n; ++i) { 19027 19028 textures.setTexture2D(v[i] || emptyTexture, units[i]); 19029 19030 } 19031 19032} 19033 19034function setValueT3DArray(gl, v, textures) { 19035 19036 const cache = this.cache; 19037 19038 const n = v.length; 19039 19040 const units = allocTexUnits(textures, n); 19041 19042 if (!arraysEqual(cache, units)) { 19043 19044 gl.uniform1iv(this.addr, units); 19045 19046 copyArray(cache, units); 19047 19048 } 19049 19050 for (let i = 0; i !== n; ++i) { 19051 19052 textures.setTexture3D(v[i] || empty3dTexture, units[i]); 19053 19054 } 19055 19056} 19057 19058function setValueT6Array(gl, v, textures) { 19059 19060 const cache = this.cache; 19061 19062 const n = v.length; 19063 19064 const units = allocTexUnits(textures, n); 19065 19066 if (!arraysEqual(cache, units)) { 19067 19068 gl.uniform1iv(this.addr, units); 19069 19070 copyArray(cache, units); 19071 19072 } 19073 19074 for (let i = 0; i !== n; ++i) { 19075 19076 textures.setTextureCube(v[i] || emptyCubeTexture, units[i]); 19077 19078 } 19079 19080} 19081 19082function setValueT2DArrayArray(gl, v, textures) { 19083 19084 const cache = this.cache; 19085 19086 const n = v.length; 19087 19088 const units = allocTexUnits(textures, n); 19089 19090 if (!arraysEqual(cache, units)) { 19091 19092 gl.uniform1iv(this.addr, units); 19093 19094 copyArray(cache, units); 19095 19096 } 19097 19098 for (let i = 0; i !== n; ++i) { 19099 19100 textures.setTexture2DArray(v[i] || emptyArrayTexture, units[i]); 19101 19102 } 19103 19104} 19105 19106 19107// Helper to pick the right setter for a pure (bottom-level) array 19108 19109function getPureArraySetter(type) { 19110 19111 switch (type) { 19112 19113 case 0x1406: return setValueV1fArray; // FLOAT 19114 case 0x8b50: return setValueV2fArray; // _VEC2 19115 case 0x8b51: return setValueV3fArray; // _VEC3 19116 case 0x8b52: return setValueV4fArray; // _VEC4 19117 19118 case 0x8b5a: return setValueM2Array; // _MAT2 19119 case 0x8b5b: return setValueM3Array; // _MAT3 19120 case 0x8b5c: return setValueM4Array; // _MAT4 19121 19122 case 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL 19123 case 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2 19124 case 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3 19125 case 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4 19126 19127 case 0x1405: return setValueV1uiArray; // UINT 19128 case 0x8dc6: return setValueV2uiArray; // _VEC2 19129 case 0x8dc7: return setValueV3uiArray; // _VEC3 19130 case 0x8dc8: return setValueV4uiArray; // _VEC4 19131 19132 case 0x8b5e: // SAMPLER_2D 19133 case 0x8d66: // SAMPLER_EXTERNAL_OES 19134 case 0x8dca: // INT_SAMPLER_2D 19135 case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D 19136 case 0x8b62: // SAMPLER_2D_SHADOW 19137 return setValueT1Array; 19138 19139 case 0x8b5f: // SAMPLER_3D 19140 case 0x8dcb: // INT_SAMPLER_3D 19141 case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D 19142 return setValueT3DArray; 19143 19144 case 0x8b60: // SAMPLER_CUBE 19145 case 0x8dcc: // INT_SAMPLER_CUBE 19146 case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
vendor: 59,264 bytes, lines 19147-21260
19147 case 0x8dc5: // SAMPLER_CUBE_SHADOW 19148 return setValueT6Array; 19149 19150 case 0x8dc1: // SAMPLER_2D_ARRAY 19151 case 0x8dcf: // INT_SAMPLER_2D_ARRAY 19152 case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY 19153 case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW 19154 return setValueT2DArrayArray; 19155 19156 } 19157 19158} 19159 19160// --- Uniform Classes --- 19161 19162class SingleUniform { 19163 19164 constructor(id, activeInfo, addr) { 19165 19166 this.id = id; 19167 this.addr = addr; 19168 this.cache = []; 19169 this.type = activeInfo.type; 19170 this.setValue = getSingularSetter(activeInfo.type); 19171 19172 // this.path = activeInfo.name; // DEBUG 19173 19174 } 19175 19176} 19177 19178class PureArrayUniform { 19179 19180 constructor(id, activeInfo, addr) { 19181 19182 this.id = id; 19183 this.addr = addr; 19184 this.cache = []; 19185 this.type = activeInfo.type; 19186 this.size = activeInfo.size; 19187 this.setValue = getPureArraySetter(activeInfo.type); 19188 19189 // this.path = activeInfo.name; // DEBUG 19190 19191 } 19192 19193} 19194 19195class StructuredUniform { 19196 19197 constructor(id) { 19198 19199 this.id = id; 19200 19201 this.seq = []; 19202 this.map = {}; 19203 19204 } 19205 19206 setValue(gl, value, textures) { 19207 19208 const seq = this.seq; 19209 19210 for (let i = 0, n = seq.length; i !== n; ++i) { 19211 19212 const u = seq[i]; 19213 u.setValue(gl, value[u.id], textures); 19214 19215 } 19216 19217 } 19218 19219} 19220 19221// --- Top-level --- 19222 19223// Parser - builds up the property tree from the path strings 19224 19225const RePathPart = /(\w+)(\])?(\[|\.)?/g; 19226 19227// extracts 19228// - the identifier (member name or array index) 19229// - followed by an optional right bracket (found when array index) 19230// - followed by an optional left bracket or dot (type of subscript) 19231// 19232// Note: These portions can be read in a non-overlapping fashion and 19233// allow straightforward parsing of the hierarchy that WebGL encodes 19234// in the uniform names. 19235 19236function addUniform(container, uniformObject) { 19237 19238 container.seq.push(uniformObject); 19239 container.map[uniformObject.id] = uniformObject; 19240 19241} 19242 19243function parseUniform(activeInfo, addr, container) { 19244 19245 const path = activeInfo.name, 19246 pathLength = path.length; 19247 19248 // reset RegExp object, because of the early exit of a previous run 19249 RePathPart.lastIndex = 0; 19250 19251 while (true) { 19252 19253 const match = RePathPart.exec(path), 19254 matchEnd = RePathPart.lastIndex; 19255 19256 let id = match[1]; 19257 const idIsIndex = match[2] === ']', 19258 subscript = match[3]; 19259 19260 if (idIsIndex) id = id | 0; // convert to integer 19261 19262 if (subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength) { 19263 19264 // bare name or "pure" bottom-level array "[0]" suffix 19265 19266 addUniform(container, subscript === undefined ? 19267 new SingleUniform(id, activeInfo, addr) : 19268 new PureArrayUniform(id, activeInfo, addr)); 19269 19270 break; 19271 19272 } else { 19273 19274 // step into inner node / create it in case it doesn't exist 19275 19276 const map = container.map; 19277 let next = map[id]; 19278 19279 if (next === undefined) { 19280 19281 next = new StructuredUniform(id); 19282 addUniform(container, next); 19283 19284 } 19285 19286 container = next; 19287 19288 } 19289 19290 } 19291 19292} 19293 19294// Root Container 19295 19296class WebGLUniforms { 19297 19298 constructor(gl, program) { 19299 19300 this.seq = []; 19301 this.map = {}; 19302 19303 const n = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); 19304 19305 for (let i = 0; i < n; ++i) { 19306 19307 const info = gl.getActiveUniform(program, i), 19308 addr = gl.getUniformLocation(program, info.name); 19309 19310 parseUniform(info, addr, this); 19311 19312 } 19313 19314 } 19315 19316 setValue(gl, name, value, textures) { 19317 19318 const u = this.map[name]; 19319 19320 if (u !== undefined) u.setValue(gl, value, textures); 19321 19322 } 19323 19324 setOptional(gl, object, name) { 19325 19326 const v = object[name]; 19327 19328 if (v !== undefined) this.setValue(gl, name, v); 19329 19330 } 19331 19332 static upload(gl, seq, values, textures) { 19333 19334 for (let i = 0, n = seq.length; i !== n; ++i) { 19335 19336 const u = seq[i], 19337 v = values[u.id]; 19338 19339 if (v.needsUpdate !== false) { 19340 19341 // note: always updating when .needsUpdate is undefined 19342 u.setValue(gl, v.value, textures); 19343 19344 } 19345 19346 } 19347 19348 } 19349 19350 static seqWithValue(seq, values) { 19351 19352 const r = []; 19353 19354 for (let i = 0, n = seq.length; i !== n; ++i) { 19355 19356 const u = seq[i]; 19357 if (u.id in values) r.push(u); 19358 19359 } 19360 19361 return r; 19362 19363 } 19364 19365} 19366 19367function WebGLShader(gl, type, string) { 19368 19369 const shader = gl.createShader(type); 19370 19371 gl.shaderSource(shader, string); 19372 gl.compileShader(shader); 19373 19374 return shader; 19375 19376} 19377 19378// From https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/ 19379const COMPLETION_STATUS_KHR = 0x91B1; 19380 19381let programIdCount = 0; 19382 19383function handleSource(string, errorLine) { 19384 19385 const lines = string.split('\n'); 19386 const lines2 = []; 19387 19388 const from = Math.max(errorLine - 6, 0); 19389 const to = Math.min(errorLine + 6, lines.length); 19390 19391 for (let i = from; i < to; i++) { 19392 19393 const line = i + 1; 19394 lines2.push(`${line === errorLine ? '>' : ' '} ${line}: ${lines[i]}`); 19395 19396 } 19397 19398 return lines2.join('\n'); 19399 19400} 19401 19402function getEncodingComponents(colorSpace) { 19403 19404 const workingPrimaries = ColorManagement.getPrimaries(ColorManagement.workingColorSpace); 19405 const encodingPrimaries = ColorManagement.getPrimaries(colorSpace); 19406 19407 let gamutMapping; 19408 19409 if (workingPrimaries === encodingPrimaries) { 19410 19411 gamutMapping = ''; 19412 19413 } else if (workingPrimaries === P3Primaries && encodingPrimaries === Rec709Primaries) { 19414 19415 gamutMapping = 'LinearDisplayP3ToLinearSRGB'; 19416 19417 } else if (workingPrimaries === Rec709Primaries && encodingPrimaries === P3Primaries) { 19418 19419 gamutMapping = 'LinearSRGBToLinearDisplayP3'; 19420 19421 } 19422 19423 switch (colorSpace) { 19424 19425 case LinearSRGBColorSpace: 19426 case LinearDisplayP3ColorSpace: 19427 return [gamutMapping, 'LinearTransferOETF']; 19428 19429 case SRGBColorSpace: 19430 case DisplayP3ColorSpace: 19431 return [gamutMapping, 'sRGBTransferOETF']; 19432 19433 default: 19434 console.warn('THREE.WebGLProgram: Unsupported color space:', colorSpace); 19435 return [gamutMapping, 'LinearTransferOETF']; 19436 19437 } 19438 19439} 19440 19441function getShaderErrors(gl, shader, type) { 19442 19443 const status = gl.getShaderParameter(shader, gl.COMPILE_STATUS); 19444 const errors = gl.getShaderInfoLog(shader).trim(); 19445 19446 if (status && errors === '') return ''; 19447 19448 const errorMatches = /ERROR: 0:(\d+)/.exec(errors); 19449 if (errorMatches) { 19450 19451 // --enable-privileged-webgl-extension 19452 // console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); 19453 19454 const errorLine = parseInt(errorMatches[1]); 19455 return type.toUpperCase() + '\n\n' + errors + '\n\n' + handleSource(gl.getShaderSource(shader), errorLine); 19456 19457 } else { 19458 19459 return errors; 19460 19461 } 19462 19463} 19464 19465function getTexelEncodingFunction(functionName, colorSpace) { 19466 19467 const components = getEncodingComponents(colorSpace); 19468 return `vec4 ${functionName}( vec4 value ) { return ${components[0]}( ${components[1]}( value ) ); }`; 19469 19470} 19471 19472function getToneMappingFunction(functionName, toneMapping) { 19473 19474 let toneMappingName; 19475 19476 switch (toneMapping) { 19477 19478 case LinearToneMapping: 19479 toneMappingName = 'Linear'; 19480 break; 19481 19482 case ReinhardToneMapping: 19483 toneMappingName = 'Reinhard'; 19484 break; 19485 19486 case CineonToneMapping: 19487 toneMappingName = 'OptimizedCineon'; 19488 break; 19489 19490 case ACESFilmicToneMapping: 19491 toneMappingName = 'ACESFilmic'; 19492 break; 19493 19494 case AgXToneMapping: 19495 toneMappingName = 'AgX'; 19496 break; 19497 19498 case CustomToneMapping: 19499 toneMappingName = 'Custom'; 19500 break; 19501 19502 default: 19503 console.warn('THREE.WebGLProgram: Unsupported toneMapping:', toneMapping); 19504 toneMappingName = 'Linear'; 19505 19506 } 19507 19508 return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }'; 19509 19510} 19511 19512function generateExtensions(parameters) { 19513 19514 const chunks = [ 19515 (parameters.extensionDerivatives || !!parameters.envMapCubeUVHeight || parameters.bumpMap || parameters.normalMapTangentSpace || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical') ? '#extension GL_OES_standard_derivatives : enable' : '', 19516 (parameters.extensionFragDepth || parameters.logarithmicDepthBuffer) && parameters.rendererExtensionFragDepth ? '#extension GL_EXT_frag_depth : enable' : '', 19517 (parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers) ? '#extension GL_EXT_draw_buffers : require' : '', 19518 (parameters.extensionShaderTextureLOD || parameters.envMap || parameters.transmission) && parameters.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : '' 19519 ]; 19520 19521 return chunks.filter(filterEmptyLine).join('\n'); 19522 19523} 19524 19525function generateVertexExtensions(parameters) { 19526 19527 const chunks = [ 19528 parameters.extensionClipCullDistance ? '#extension GL_ANGLE_clip_cull_distance : require' : '' 19529 ]; 19530 19531 return chunks.filter(filterEmptyLine).join('\n'); 19532 19533} 19534 19535function generateDefines(defines) { 19536 19537 const chunks = []; 19538 19539 for (const name in defines) { 19540 19541 const value = defines[name]; 19542 19543 if (value === false) continue; 19544 19545 chunks.push('#define ' + name + ' ' + value); 19546 19547 } 19548 19549 return chunks.join('\n'); 19550 19551} 19552 19553function fetchAttributeLocations(gl, program) { 19554 19555 const attributes = {}; 19556 19557 const n = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES); 19558 19559 for (let i = 0; i < n; i++) { 19560 19561 const info = gl.getActiveAttrib(program, i); 19562 const name = info.name; 19563 19564 let locationSize = 1; 19565 if (info.type === gl.FLOAT_MAT2) locationSize = 2; 19566 if (info.type === gl.FLOAT_MAT3) locationSize = 3; 19567 if (info.type === gl.FLOAT_MAT4) locationSize = 4; 19568 19569 // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i ); 19570 19571 attributes[name] = { 19572 type: info.type, 19573 location: gl.getAttribLocation(program, name), 19574 locationSize: locationSize 19575 }; 19576 19577 } 19578 19579 return attributes; 19580 19581} 19582 19583function filterEmptyLine(string) { 19584 19585 return string !== ''; 19586 19587} 19588 19589function replaceLightNums(string, parameters) { 19590 19591 const numSpotLightCoords = parameters.numSpotLightShadows + parameters.numSpotLightMaps - parameters.numSpotLightShadowsWithMaps; 19592 19593 return string 19594 .replace(/NUM_DIR_LIGHTS/g, parameters.numDirLights) 19595 .replace(/NUM_SPOT_LIGHTS/g, parameters.numSpotLights) 19596 .replace(/NUM_SPOT_LIGHT_MAPS/g, parameters.numSpotLightMaps) 19597 .replace(/NUM_SPOT_LIGHT_COORDS/g, numSpotLightCoords) 19598 .replace(/NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights) 19599 .replace(/NUM_POINT_LIGHTS/g, parameters.numPointLights) 19600 .replace(/NUM_HEMI_LIGHTS/g, parameters.numHemiLights) 19601 .replace(/NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows) 19602 .replace(/NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g, parameters.numSpotLightShadowsWithMaps) 19603 .replace(/NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows) 19604 .replace(/NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows); 19605 19606} 19607 19608function replaceClippingPlaneNums(string, parameters) { 19609 19610 return string 19611 .replace(/NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes) 19612 .replace(/UNION_CLIPPING_PLANES/g, (parameters.numClippingPlanes - parameters.numClipIntersection)); 19613 19614} 19615 19616// Resolve Includes 19617 19618const includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm; 19619 19620function resolveIncludes(string) { 19621 19622 return string.replace(includePattern, includeReplacer); 19623 19624} 19625 19626const shaderChunkMap = new Map([ 19627 ['encodings_fragment', 'colorspace_fragment'], // @deprecated, r154 19628 ['encodings_pars_fragment', 'colorspace_pars_fragment'], // @deprecated, r154 19629 ['output_fragment', 'opaque_fragment'], // @deprecated, r154 19630]); 19631 19632function includeReplacer(match, include) { 19633 19634 let string = ShaderChunk[include]; 19635 19636 if (string === undefined) { 19637 19638 const newInclude = shaderChunkMap.get(include); 19639 19640 if (newInclude !== undefined) { 19641 19642 string = ShaderChunk[newInclude]; 19643 console.warn('THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.', include, newInclude); 19644 19645 } else { 19646 19647 throw new Error('Can not resolve #include <' + include + '>'); 19648 19649 } 19650 19651 } 19652 19653 return resolveIncludes(string); 19654 19655} 19656 19657// Unroll Loops 19658 19659const 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; 19660 19661function unrollLoops(string) { 19662 19663 return string.replace(unrollLoopPattern, loopReplacer); 19664 19665} 19666 19667function loopReplacer(match, start, end, snippet) { 19668 19669 let string = ''; 19670 19671 for (let i = parseInt(start); i < parseInt(end); i++) { 19672 19673 string += snippet 19674 .replace(/\[\s*i\s*\]/g, '[ ' + i + ' ]') 19675 .replace(/UNROLLED_LOOP_INDEX/g, i); 19676 19677 } 19678 19679 return string; 19680 19681} 19682 19683// 19684 19685function generatePrecision(parameters) { 19686 19687 let precisionstring = 'precision ' + parameters.precision + ' float;\nprecision ' + parameters.precision + ' int;'; 19688 19689 if (parameters.precision === 'highp') { 19690 19691 precisionstring += '\n#define HIGH_PRECISION'; 19692 19693 } else if (parameters.precision === 'mediump') { 19694 19695 precisionstring += '\n#define MEDIUM_PRECISION'; 19696 19697 } else if (parameters.precision === 'lowp') { 19698 19699 precisionstring += '\n#define LOW_PRECISION'; 19700 19701 } 19702 19703 return precisionstring; 19704 19705} 19706 19707function generateShadowMapTypeDefine(parameters) { 19708 19709 let shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; 19710 19711 if (parameters.shadowMapType === PCFShadowMap) { 19712 19713 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; 19714 19715 } else if (parameters.shadowMapType === PCFSoftShadowMap) { 19716 19717 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT'; 19718 19719 } else if (parameters.shadowMapType === VSMShadowMap) { 19720 19721 shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM'; 19722 19723 } 19724 19725 return shadowMapTypeDefine; 19726 19727} 19728 19729function generateEnvMapTypeDefine(parameters) { 19730 19731 let envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; 19732 19733 if (parameters.envMap) { 19734 19735 switch (parameters.envMapMode) { 19736 19737 case CubeReflectionMapping: 19738 case CubeRefractionMapping: 19739 envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; 19740 break; 19741 19742 case CubeUVReflectionMapping: 19743 envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV'; 19744 break; 19745 19746 } 19747 19748 } 19749 19750 return envMapTypeDefine; 19751 19752} 19753 19754function generateEnvMapModeDefine(parameters) { 19755 19756 let envMapModeDefine = 'ENVMAP_MODE_REFLECTION'; 19757 19758 if (parameters.envMap) { 19759 19760 switch (parameters.envMapMode) { 19761 19762 case CubeRefractionMapping: 19763 19764 envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; 19765 break; 19766 19767 } 19768 19769 } 19770 19771 return envMapModeDefine; 19772 19773} 19774 19775function generateEnvMapBlendingDefine(parameters) { 19776 19777 let envMapBlendingDefine = 'ENVMAP_BLENDING_NONE'; 19778 19779 if (parameters.envMap) { 19780 19781 switch (parameters.combine) { 19782 19783 case MultiplyOperation: 19784 envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; 19785 break; 19786 19787 case MixOperation: 19788 envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; 19789 break; 19790 19791 case AddOperation: 19792 envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; 19793 break; 19794 19795 } 19796 19797 } 19798 19799 return envMapBlendingDefine; 19800 19801} 19802 19803function generateCubeUVSize(parameters) { 19804 19805 const imageHeight = parameters.envMapCubeUVHeight; 19806 19807 if (imageHeight === null) return null; 19808 19809 const maxMip = Math.log2(imageHeight) - 2; 19810 19811 const texelHeight = 1.0 / imageHeight; 19812 19813 const texelWidth = 1.0 / (3 * Math.max(Math.pow(2, maxMip), 7 * 16)); 19814 19815 return { texelWidth, texelHeight, maxMip }; 19816 19817} 19818 19819function WebGLProgram(renderer, cacheKey, parameters, bindingStates) { 19820 19821 // TODO Send this event to Three.js DevTools 19822 // console.log( 'WebGLProgram', cacheKey ); 19823 19824 const gl = renderer.getContext(); 19825 19826 const defines = parameters.defines; 19827 19828 let vertexShader = parameters.vertexShader; 19829 let fragmentShader = parameters.fragmentShader; 19830 19831 const shadowMapTypeDefine = generateShadowMapTypeDefine(parameters); 19832 const envMapTypeDefine = generateEnvMapTypeDefine(parameters); 19833 const envMapModeDefine = generateEnvMapModeDefine(parameters); 19834 const envMapBlendingDefine = generateEnvMapBlendingDefine(parameters); 19835 const envMapCubeUVSize = generateCubeUVSize(parameters); 19836 19837 const customExtensions = parameters.isWebGL2 ? '' : generateExtensions(parameters); 19838 19839 const customVertexExtensions = generateVertexExtensions(parameters); 19840 19841 const customDefines = generateDefines(defines); 19842 19843 const program = gl.createProgram(); 19844 19845 let prefixVertex, prefixFragment; 19846 let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : ''; 19847 19848 if (parameters.isRawShaderMaterial) { 19849 19850 prefixVertex = [ 19851 19852 '#define SHADER_TYPE ' + parameters.shaderType, 19853 '#define SHADER_NAME ' + parameters.shaderName, 19854 19855 customDefines 19856 19857 ].filter(filterEmptyLine).join('\n'); 19858 19859 if (prefixVertex.length > 0) { 19860 19861 prefixVertex += '\n'; 19862 19863 } 19864 19865 prefixFragment = [ 19866 19867 customExtensions, 19868 19869 '#define SHADER_TYPE ' + parameters.shaderType, 19870 '#define SHADER_NAME ' + parameters.shaderName, 19871 19872 customDefines 19873 19874 ].filter(filterEmptyLine).join('\n'); 19875 19876 if (prefixFragment.length > 0) { 19877 19878 prefixFragment += '\n'; 19879 19880 } 19881 19882 } else { 19883 19884 prefixVertex = [ 19885 19886 generatePrecision(parameters), 19887 19888 '#define SHADER_TYPE ' + parameters.shaderType, 19889 '#define SHADER_NAME ' + parameters.shaderName, 19890 19891 customDefines, 19892 19893 parameters.extensionClipCullDistance ? '#define USE_CLIP_DISTANCE' : '', 19894 parameters.batching ? '#define USE_BATCHING' : '', 19895 parameters.instancing ? '#define USE_INSTANCING' : '', 19896 parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '', 19897 19898 parameters.useFog && parameters.fog ? '#define USE_FOG' : '', 19899 parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '', 19900 19901 parameters.map ? '#define USE_MAP' : '', 19902 parameters.envMap ? '#define USE_ENVMAP' : '', 19903 parameters.envMap ? '#define ' + envMapModeDefine : '', 19904 parameters.lightMap ? '#define USE_LIGHTMAP' : '', 19905 parameters.aoMap ? '#define USE_AOMAP' : '', 19906 parameters.bumpMap ? '#define USE_BUMPMAP' : '', 19907 parameters.normalMap ? '#define USE_NORMALMAP' : '', 19908 parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '', 19909 parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '', 19910 parameters.displacementMap ? '#define USE_DISPLACEMENTMAP' : '', 19911 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', 19912 19913 parameters.anisotropy ? '#define USE_ANISOTROPY' : '', 19914 parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '', 19915 19916 parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', 19917 parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', 19918 parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '', 19919 19920 parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '', 19921 parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', 19922 19923 parameters.specularMap ? '#define USE_SPECULARMAP' : '', 19924 parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '', 19925 parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '', 19926 19927 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', 19928 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', 19929 parameters.alphaMap ? '#define USE_ALPHAMAP' : '', 19930 parameters.alphaHash ? '#define USE_ALPHAHASH' : '', 19931 19932 parameters.transmission ? '#define USE_TRANSMISSION' : '', 19933 parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', 19934 parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', 19935 19936 parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '', 19937 parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '', 19938 19939 // 19940 19941 parameters.mapUv ? '#define MAP_UV ' + parameters.mapUv : '', 19942 parameters.alphaMapUv ? '#define ALPHAMAP_UV ' + parameters.alphaMapUv : '', 19943 parameters.lightMapUv ? '#define LIGHTMAP_UV ' + parameters.lightMapUv : '', 19944 parameters.aoMapUv ? '#define AOMAP_UV ' + parameters.aoMapUv : '', 19945 parameters.emissiveMapUv ? '#define EMISSIVEMAP_UV ' + parameters.emissiveMapUv : '', 19946 parameters.bumpMapUv ? '#define BUMPMAP_UV ' + parameters.bumpMapUv : '', 19947 parameters.normalMapUv ? '#define NORMALMAP_UV ' + parameters.normalMapUv : '', 19948 parameters.displacementMapUv ? '#define DISPLACEMENTMAP_UV ' + parameters.displacementMapUv : '', 19949 19950 parameters.metalnessMapUv ? '#define METALNESSMAP_UV ' + parameters.metalnessMapUv : '', 19951 parameters.roughnessMapUv ? '#define ROUGHNESSMAP_UV ' + parameters.roughnessMapUv : '', 19952 19953 parameters.anisotropyMapUv ? '#define ANISOTROPYMAP_UV ' + parameters.anisotropyMapUv : '', 19954 19955 parameters.clearcoatMapUv ? '#define CLEARCOATMAP_UV ' + parameters.clearcoatMapUv : '', 19956 parameters.clearcoatNormalMapUv ? '#define CLEARCOAT_NORMALMAP_UV ' + parameters.clearcoatNormalMapUv : '', 19957 parameters.clearcoatRoughnessMapUv ? '#define CLEARCOAT_ROUGHNESSMAP_UV ' + parameters.clearcoatRoughnessMapUv : '', 19958 19959 parameters.iridescenceMapUv ? '#define IRIDESCENCEMAP_UV ' + parameters.iridescenceMapUv : '', 19960 parameters.iridescenceThicknessMapUv ? '#define IRIDESCENCE_THICKNESSMAP_UV ' + parameters.iridescenceThicknessMapUv : '', 19961 19962 parameters.sheenColorMapUv ? '#define SHEEN_COLORMAP_UV ' + parameters.sheenColorMapUv : '', 19963 parameters.sheenRoughnessMapUv ? '#define SHEEN_ROUGHNESSMAP_UV ' + parameters.sheenRoughnessMapUv : '', 19964 19965 parameters.specularMapUv ? '#define SPECULARMAP_UV ' + parameters.specularMapUv : '', 19966 parameters.specularColorMapUv ? '#define SPECULAR_COLORMAP_UV ' + parameters.specularColorMapUv : '', 19967 parameters.specularIntensityMapUv ? '#define SPECULAR_INTENSITYMAP_UV ' + parameters.specularIntensityMapUv : '', 19968 19969 parameters.transmissionMapUv ? '#define TRANSMISSIONMAP_UV ' + parameters.transmissionMapUv : '', 19970 parameters.thicknessMapUv ? '#define THICKNESSMAP_UV ' + parameters.thicknessMapUv : '', 19971 19972 // 19973 19974 parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '', 19975 parameters.vertexColors ? '#define USE_COLOR' : '', 19976 parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', 19977 parameters.vertexUv1s ? '#define USE_UV1' : '', 19978 parameters.vertexUv2s ? '#define USE_UV2' : '', 19979 parameters.vertexUv3s ? '#define USE_UV3' : '', 19980 19981 parameters.pointsUvs ? '#define USE_POINTS_UV' : '', 19982 19983 parameters.flatShading ? '#define FLAT_SHADED' : '', 19984 19985 parameters.skinning ? '#define USE_SKINNING' : '', 19986 19987 parameters.morphTargets ? '#define USE_MORPHTARGETS' : '', 19988 parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '', 19989 (parameters.morphColors && parameters.isWebGL2) ? '#define USE_MORPHCOLORS' : '', 19990 (parameters.morphTargetsCount > 0 && parameters.isWebGL2) ? '#define MORPHTARGETS_TEXTURE' : '', 19991 (parameters.morphTargetsCount > 0 && parameters.isWebGL2) ? '#define MORPHTARGETS_TEXTURE_STRIDE ' + parameters.morphTextureStride : '', 19992 (parameters.morphTargetsCount > 0 && parameters.isWebGL2) ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '', 19993 parameters.doubleSided ? '#define DOUBLE_SIDED' : '', 19994 parameters.flipSided ? '#define FLIP_SIDED' : '', 19995 19996 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', 19997 parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', 19998 19999 parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', 20000 20001 parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', 20002 20003 parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '', 20004 20005 parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', 20006 (parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth) ? '#define USE_LOGDEPTHBUF_EXT' : '', 20007 20008 'uniform mat4 modelMatrix;', 20009 'uniform mat4 modelViewMatrix;', 20010 'uniform mat4 projectionMatrix;', 20011 'uniform mat4 viewMatrix;', 20012 'uniform mat3 normalMatrix;', 20013 'uniform vec3 cameraPosition;', 20014 'uniform bool isOrthographic;', 20015 20016 '#ifdef USE_INSTANCING', 20017 20018 ' attribute mat4 instanceMatrix;', 20019 20020 '#endif', 20021 20022 '#ifdef USE_INSTANCING_COLOR', 20023 20024 ' attribute vec3 instanceColor;', 20025 20026 '#endif', 20027 20028 'attribute vec3 position;', 20029 'attribute vec3 normal;', 20030 'attribute vec2 uv;', 20031 20032 '#ifdef USE_UV1', 20033 20034 ' attribute vec2 uv1;', 20035 20036 '#endif', 20037 20038 '#ifdef USE_UV2', 20039 20040 ' attribute vec2 uv2;', 20041 20042 '#endif', 20043 20044 '#ifdef USE_UV3', 20045 20046 ' attribute vec2 uv3;', 20047 20048 '#endif', 20049 20050 '#ifdef USE_TANGENT', 20051 20052 ' attribute vec4 tangent;', 20053 20054 '#endif', 20055 20056 '#if defined( USE_COLOR_ALPHA )', 20057 20058 ' attribute vec4 color;', 20059 20060 '#elif defined( USE_COLOR )', 20061 20062 ' attribute vec3 color;', 20063 20064 '#endif', 20065 20066 '#if ( defined( USE_MORPHTARGETS ) && ! defined( MORPHTARGETS_TEXTURE ) )', 20067 20068 ' attribute vec3 morphTarget0;', 20069 ' attribute vec3 morphTarget1;', 20070 ' attribute vec3 morphTarget2;', 20071 ' attribute vec3 morphTarget3;', 20072 20073 ' #ifdef USE_MORPHNORMALS', 20074 20075 ' attribute vec3 morphNormal0;', 20076 ' attribute vec3 morphNormal1;', 20077 ' attribute vec3 morphNormal2;', 20078 ' attribute vec3 morphNormal3;', 20079 20080 ' #else', 20081 20082 ' attribute vec3 morphTarget4;', 20083 ' attribute vec3 morphTarget5;', 20084 ' attribute vec3 morphTarget6;', 20085 ' attribute vec3 morphTarget7;', 20086 20087 ' #endif', 20088 20089 '#endif', 20090 20091 '#ifdef USE_SKINNING', 20092 20093 ' attribute vec4 skinIndex;', 20094 ' attribute vec4 skinWeight;', 20095 20096 '#endif', 20097 20098 '\n' 20099 20100 ].filter(filterEmptyLine).join('\n'); 20101 20102 prefixFragment = [ 20103 20104 customExtensions, 20105 20106 generatePrecision(parameters), 20107 20108 '#define SHADER_TYPE ' + parameters.shaderType, 20109 '#define SHADER_NAME ' + parameters.shaderName, 20110 20111 customDefines, 20112 20113 parameters.useFog && parameters.fog ? '#define USE_FOG' : '', 20114 parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '', 20115 20116 parameters.map ? '#define USE_MAP' : '', 20117 parameters.matcap ? '#define USE_MATCAP' : '', 20118 parameters.envMap ? '#define USE_ENVMAP' : '', 20119 parameters.envMap ? '#define ' + envMapTypeDefine : '', 20120 parameters.envMap ? '#define ' + envMapModeDefine : '', 20121 parameters.envMap ? '#define ' + envMapBlendingDefine : '', 20122 envMapCubeUVSize ? '#define CUBEUV_TEXEL_WIDTH ' + envMapCubeUVSize.texelWidth : '', 20123 envMapCubeUVSize ? '#define CUBEUV_TEXEL_HEIGHT ' + envMapCubeUVSize.texelHeight : '', 20124 envMapCubeUVSize ? '#define CUBEUV_MAX_MIP ' + envMapCubeUVSize.maxMip + '.0' : '', 20125 parameters.lightMap ? '#define USE_LIGHTMAP' : '', 20126 parameters.aoMap ? '#define USE_AOMAP' : '', 20127 parameters.bumpMap ? '#define USE_BUMPMAP' : '', 20128 parameters.normalMap ? '#define USE_NORMALMAP' : '', 20129 parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '', 20130 parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '', 20131 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', 20132 20133 parameters.anisotropy ? '#define USE_ANISOTROPY' : '', 20134 parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '', 20135 20136 parameters.clearcoat ? '#define USE_CLEARCOAT' : '', 20137 parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', 20138 parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', 20139 parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '', 20140 20141 parameters.iridescence ? '#define USE_IRIDESCENCE' : '', 20142 parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '', 20143 parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', 20144 20145 parameters.specularMap ? '#define USE_SPECULARMAP' : '', 20146 parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '', 20147 parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '', 20148 20149 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', 20150 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', 20151 20152 parameters.alphaMap ? '#define USE_ALPHAMAP' : '', 20153 parameters.alphaTest ? '#define USE_ALPHATEST' : '', 20154 parameters.alphaHash ? '#define USE_ALPHAHASH' : '', 20155 20156 parameters.sheen ? '#define USE_SHEEN' : '', 20157 parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '', 20158 parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '', 20159 20160 parameters.transmission ? '#define USE_TRANSMISSION' : '', 20161 parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', 20162 parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', 20163 20164 parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '', 20165 parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '', 20166 parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', 20167 parameters.vertexUv1s ? '#define USE_UV1' : '', 20168 parameters.vertexUv2s ? '#define USE_UV2' : '', 20169 parameters.vertexUv3s ? '#define USE_UV3' : '', 20170 20171 parameters.pointsUvs ? '#define USE_POINTS_UV' : '', 20172 20173 parameters.gradientMap ? '#define USE_GRADIENTMAP' : '', 20174 20175 parameters.flatShading ? '#define FLAT_SHADED' : '', 20176 20177 parameters.doubleSided ? '#define DOUBLE_SIDED' : '', 20178 parameters.flipSided ? '#define FLIP_SIDED' : '', 20179 20180 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', 20181 parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', 20182 20183 parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '', 20184 20185 parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', 20186 20187 parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '', 20188 20189 parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '', 20190 20191 parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', 20192 (parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth) ? '#define USE_LOGDEPTHBUF_EXT' : '', 20193 20194 'uniform mat4 viewMatrix;', 20195 'uniform vec3 cameraPosition;', 20196 'uniform bool isOrthographic;', 20197 20198 (parameters.toneMapping !== NoToneMapping) ? '#define TONE_MAPPING' : '', 20199 (parameters.toneMapping !== NoToneMapping) ? ShaderChunk['tonemapping_pars_fragment'] : '', // this code is required here because it is used by the toneMapping() function defined below 20200 (parameters.toneMapping !== NoToneMapping) ? getToneMappingFunction('toneMapping', parameters.toneMapping) : '', 20201 20202 parameters.dithering ? '#define DITHERING' : '', 20203 parameters.opaque ? '#define OPAQUE' : '', 20204 20205 ShaderChunk['colorspace_pars_fragment'], // this code is required here because it is used by the various encoding/decoding function defined below 20206 getTexelEncodingFunction('linearToOutputTexel', parameters.outputColorSpace), 20207 20208 parameters.useDepthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '', 20209 20210 '\n' 20211 20212 ].filter(filterEmptyLine).join('\n'); 20213 20214 } 20215 20216 vertexShader = resolveIncludes(vertexShader); 20217 vertexShader = replaceLightNums(vertexShader, parameters); 20218 vertexShader = replaceClippingPlaneNums(vertexShader, parameters); 20219 20220 fragmentShader = resolveIncludes(fragmentShader); 20221 fragmentShader = replaceLightNums(fragmentShader, parameters); 20222 fragmentShader = replaceClippingPlaneNums(fragmentShader, parameters); 20223 20224 vertexShader = unrollLoops(vertexShader); 20225 fragmentShader = unrollLoops(fragmentShader); 20226 20227 if (parameters.isWebGL2 && parameters.isRawShaderMaterial !== true) { 20228 20229 // GLSL 3.0 conversion for built-in materials and ShaderMaterial 20230 20231 versionString = '#version 300 es\n'; 20232 20233 prefixVertex = [ 20234 customVertexExtensions, 20235 'precision mediump sampler2DArray;', 20236 '#define attribute in', 20237 '#define varying out', 20238 '#define texture2D texture' 20239 ].join('\n') + '\n' + prefixVertex; 20240 20241 prefixFragment = [ 20242 'precision mediump sampler2DArray;', 20243 '#define varying in', 20244 (parameters.glslVersion === GLSL3) ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;', 20245 (parameters.glslVersion === GLSL3) ? '' : '#define gl_FragColor pc_fragColor', 20246 '#define gl_FragDepthEXT gl_FragDepth', 20247 '#define texture2D texture', 20248 '#define textureCube texture', 20249 '#define texture2DProj textureProj', 20250 '#define texture2DLodEXT textureLod', 20251 '#define texture2DProjLodEXT textureProjLod', 20252 '#define textureCubeLodEXT textureLod', 20253 '#define texture2DGradEXT textureGrad', 20254 '#define texture2DProjGradEXT textureProjGrad', 20255 '#define textureCubeGradEXT textureGrad' 20256 ].join('\n') + '\n' + prefixFragment; 20257 20258 } 20259 20260 const vertexGlsl = versionString + prefixVertex + vertexShader; 20261 const fragmentGlsl = versionString + prefixFragment + fragmentShader; 20262 20263 // console.log( '*VERTEX*', vertexGlsl ); 20264 // console.log( '*FRAGMENT*', fragmentGlsl ); 20265 20266 const glVertexShader = WebGLShader(gl, gl.VERTEX_SHADER, vertexGlsl); 20267 const glFragmentShader = WebGLShader(gl, gl.FRAGMENT_SHADER, fragmentGlsl); 20268 20269 gl.attachShader(program, glVertexShader); 20270 gl.attachShader(program, glFragmentShader); 20271 20272 // Force a particular attribute to index 0. 20273 20274 if (parameters.index0AttributeName !== undefined) { 20275 20276 gl.bindAttribLocation(program, 0, parameters.index0AttributeName); 20277 20278 } else if (parameters.morphTargets === true) { 20279 20280 // programs with morphTargets displace position out of attribute 0 20281 gl.bindAttribLocation(program, 0, 'position'); 20282 20283 } 20284 20285 gl.linkProgram(program); 20286 20287 function onFirstUse(self) { 20288 20289 // check for link errors 20290 if (renderer.debug.checkShaderErrors) { 20291 20292 const programLog = gl.getProgramInfoLog(program).trim(); 20293 const vertexLog = gl.getShaderInfoLog(glVertexShader).trim(); 20294 const fragmentLog = gl.getShaderInfoLog(glFragmentShader).trim(); 20295 20296 let runnable = true; 20297 let haveDiagnostics = true; 20298 20299 if (gl.getProgramParameter(program, gl.LINK_STATUS) === false) { 20300 20301 runnable = false; 20302 20303 if (typeof renderer.debug.onShaderError === 'function') { 20304 20305 renderer.debug.onShaderError(gl, program, glVertexShader, glFragmentShader); 20306 20307 } else { 20308 20309 // default error reporting 20310 20311 const vertexErrors = getShaderErrors(gl, glVertexShader, 'vertex'); 20312 const fragmentErrors = getShaderErrors(gl, glFragmentShader, 'fragment'); 20313 20314 console.error( 20315 'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' + 20316 'VALIDATE_STATUS ' + gl.getProgramParameter(program, gl.VALIDATE_STATUS) + '\n\n' + 20317 'Program Info Log: ' + programLog + '\n' + 20318 vertexErrors + '\n' + 20319 fragmentErrors 20320 ); 20321 20322 } 20323 20324 } else if (programLog !== '') { 20325 20326 console.warn('THREE.WebGLProgram: Program Info Log:', programLog); 20327 20328 } else if (vertexLog === '' || fragmentLog === '') { 20329 20330 haveDiagnostics = false; 20331 20332 } 20333 20334 if (haveDiagnostics) { 20335 20336 self.diagnostics = { 20337 20338 runnable: runnable, 20339 20340 programLog: programLog, 20341 20342 vertexShader: { 20343 20344 log: vertexLog, 20345 prefix: prefixVertex 20346 20347 }, 20348 20349 fragmentShader: { 20350 20351 log: fragmentLog, 20352 prefix: prefixFragment 20353 20354 } 20355 20356 }; 20357 20358 } 20359 20360 } 20361 20362 // Clean up 20363 20364 // Crashes in iOS9 and iOS10. #18402 20365 // gl.detachShader( program, glVertexShader ); 20366 // gl.detachShader( program, glFragmentShader ); 20367 20368 gl.deleteShader(glVertexShader); 20369 gl.deleteShader(glFragmentShader); 20370 20371 cachedUniforms = new WebGLUniforms(gl, program); 20372 cachedAttributes = fetchAttributeLocations(gl, program); 20373 20374 } 20375 20376 // set up caching for uniform locations 20377 20378 let cachedUniforms; 20379 20380 this.getUniforms = function () { 20381 20382 if (cachedUniforms === undefined) { 20383 20384 // Populates cachedUniforms and cachedAttributes 20385 onFirstUse(this); 20386 20387 } 20388 20389 return cachedUniforms; 20390 20391 }; 20392 20393 // set up caching for attribute locations 20394 20395 let cachedAttributes; 20396 20397 this.getAttributes = function () { 20398 20399 if (cachedAttributes === undefined) { 20400 20401 // Populates cachedAttributes and cachedUniforms 20402 onFirstUse(this); 20403 20404 } 20405 20406 return cachedAttributes; 20407 20408 }; 20409 20410 // indicate when the program is ready to be used. if the KHR_parallel_shader_compile extension isn't supported, 20411 // flag the program as ready immediately. It may cause a stall when it's first used. 20412 20413 let programReady = (parameters.rendererExtensionParallelShaderCompile === false); 20414 20415 this.isReady = function () { 20416 20417 if (programReady === false) { 20418 20419 programReady = gl.getProgramParameter(program, COMPLETION_STATUS_KHR); 20420 20421 } 20422 20423 return programReady; 20424 20425 }; 20426 20427 // free resource 20428 20429 this.destroy = function () { 20430 20431 bindingStates.releaseStatesOfProgram(this); 20432 20433 gl.deleteProgram(program); 20434 this.program = undefined; 20435 20436 }; 20437 20438 // 20439 20440 this.type = parameters.shaderType; 20441 this.name = parameters.shaderName; 20442 this.id = programIdCount++; 20443 this.cacheKey = cacheKey; 20444 this.usedTimes = 1; 20445 this.program = program; 20446 this.vertexShader = glVertexShader; 20447 this.fragmentShader = glFragmentShader; 20448 20449 return this; 20450 20451} 20452 20453let _id$1 = 0; 20454 20455class WebGLShaderCache { 20456 20457 constructor() { 20458 20459 this.shaderCache = new Map(); 20460 this.materialCache = new Map(); 20461 20462 } 20463 20464 update(material) { 20465 20466 const vertexShader = material.vertexShader; 20467 const fragmentShader = material.fragmentShader; 20468 20469 const vertexShaderStage = this._getShaderStage(vertexShader); 20470 const fragmentShaderStage = this._getShaderStage(fragmentShader); 20471 20472 const materialShaders = this._getShaderCacheForMaterial(material); 20473 20474 if (materialShaders.has(vertexShaderStage) === false) { 20475 20476 materialShaders.add(vertexShaderStage); 20477 vertexShaderStage.usedTimes++; 20478 20479 } 20480 20481 if (materialShaders.has(fragmentShaderStage) === false) { 20482 20483 materialShaders.add(fragmentShaderStage); 20484 fragmentShaderStage.usedTimes++; 20485 20486 } 20487 20488 return this; 20489 20490 } 20491 20492 remove(material) { 20493 20494 const materialShaders = this.materialCache.get(material); 20495 20496 for (const shaderStage of materialShaders) { 20497 20498 shaderStage.usedTimes--; 20499 20500 if (shaderStage.usedTimes === 0) this.shaderCache.delete(shaderStage.code); 20501 20502 } 20503 20504 this.materialCache.delete(material); 20505 20506 return this; 20507 20508 } 20509 20510 getVertexShaderID(material) { 20511 20512 return this._getShaderStage(material.vertexShader).id; 20513 20514 } 20515 20516 getFragmentShaderID(material) { 20517 20518 return this._getShaderStage(material.fragmentShader).id; 20519 20520 } 20521 20522 dispose() { 20523 20524 this.shaderCache.clear(); 20525 this.materialCache.clear(); 20526 20527 } 20528 20529 _getShaderCacheForMaterial(material) { 20530 20531 const cache = this.materialCache; 20532 let set = cache.get(material); 20533 20534 if (set === undefined) { 20535 20536 set = new Set(); 20537 cache.set(material, set); 20538 20539 } 20540 20541 return set; 20542 20543 } 20544 20545 _getShaderStage(code) { 20546 20547 const cache = this.shaderCache; 20548 let stage = cache.get(code); 20549 20550 if (stage === undefined) { 20551 20552 stage = new WebGLShaderStage(code); 20553 cache.set(code, stage); 20554 20555 } 20556 20557 return stage; 20558 20559 } 20560 20561} 20562 20563class WebGLShaderStage { 20564 20565 constructor(code) { 20566 20567 this.id = _id$1++; 20568 20569 this.code = code; 20570 this.usedTimes = 0; 20571 20572 } 20573 20574} 20575 20576function WebGLPrograms(renderer, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping) { 20577 20578 const _programLayers = new Layers(); 20579 const _customShaders = new WebGLShaderCache(); 20580 const programs = []; 20581 20582 const IS_WEBGL2 = capabilities.isWebGL2; 20583 const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer; 20584 const SUPPORTS_VERTEX_TEXTURES = capabilities.vertexTextures; 20585 20586 let precision = capabilities.precision; 20587 20588 const shaderIDs = { 20589 MeshDepthMaterial: 'depth', 20590 MeshDistanceMaterial: 'distanceRGBA', 20591 MeshNormalMaterial: 'normal', 20592 MeshBasicMaterial: 'basic', 20593 MeshLambertMaterial: 'lambert', 20594 MeshPhongMaterial: 'phong', 20595 MeshToonMaterial: 'toon', 20596 MeshStandardMaterial: 'physical', 20597 MeshPhysicalMaterial: 'physical', 20598 MeshMatcapMaterial: 'matcap', 20599 LineBasicMaterial: 'basic', 20600 LineDashedMaterial: 'dashed', 20601 PointsMaterial: 'points', 20602 ShadowMaterial: 'shadow', 20603 SpriteMaterial: 'sprite' 20604 }; 20605 20606 function getChannel(value) { 20607 20608 if (value === 0) return 'uv'; 20609 20610 return `uv${value}`; 20611 20612 } 20613 20614 function getParameters(material, lights, shadows, scene, object) { 20615 20616 const fog = scene.fog; 20617 const geometry = object.geometry; 20618 const environment = material.isMeshStandardMaterial ? scene.environment : null; 20619 20620 const envMap = (material.isMeshStandardMaterial ? cubeuvmaps : cubemaps).get(material.envMap || environment); 20621 const envMapCubeUVHeight = (!!envMap) && (envMap.mapping === CubeUVReflectionMapping) ? envMap.image.height : null; 20622 20623 const shaderID = shaderIDs[material.type]; 20624 20625 // heuristics to create shader parameters according to lights in the scene 20626 // (not to blow over maxLights budget) 20627 20628 if (material.precision !== null) { 20629 20630 precision = capabilities.getMaxPrecision(material.precision); 20631 20632 if (precision !== material.precision) { 20633 20634 console.warn('THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.'); 20635 20636 } 20637 20638 } 20639 20640 // 20641 20642 const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; 20643 const morphTargetsCount = (morphAttribute !== undefined) ? morphAttribute.length : 0; 20644 20645 let morphTextureStride = 0; 20646 20647 if (geometry.morphAttributes.position !== undefined) morphTextureStride = 1; 20648 if (geometry.morphAttributes.normal !== undefined) morphTextureStride = 2; 20649 if (geometry.morphAttributes.color !== undefined) morphTextureStride = 3; 20650 20651 // 20652 20653 let vertexShader, fragmentShader; 20654 let customVertexShaderID, customFragmentShaderID; 20655 20656 if (shaderID) { 20657 20658 const shader = ShaderLib[shaderID]; 20659 20660 vertexShader = shader.vertexShader; 20661 fragmentShader = shader.fragmentShader; 20662 20663 } else { 20664 20665 vertexShader = material.vertexShader; 20666 fragmentShader = material.fragmentShader; 20667 20668 _customShaders.update(material); 20669 20670 customVertexShaderID = _customShaders.getVertexShaderID(material); 20671 customFragmentShaderID = _customShaders.getFragmentShaderID(material); 20672 20673 } 20674 20675 const currentRenderTarget = renderer.getRenderTarget(); 20676 20677 const IS_INSTANCEDMESH = object.isInstancedMesh === true; 20678 const IS_BATCHEDMESH = object.isBatchedMesh === true; 20679 20680 const HAS_MAP = !!material.map; 20681 const HAS_MATCAP = !!material.matcap; 20682 const HAS_ENVMAP = !!envMap; 20683 const HAS_AOMAP = !!material.aoMap; 20684 const HAS_LIGHTMAP = !!material.lightMap; 20685 const HAS_BUMPMAP = !!material.bumpMap; 20686 const HAS_NORMALMAP = !!material.normalMap; 20687 const HAS_DISPLACEMENTMAP = !!material.displacementMap; 20688 const HAS_EMISSIVEMAP = !!material.emissiveMap; 20689 20690 const HAS_METALNESSMAP = !!material.metalnessMap; 20691 const HAS_ROUGHNESSMAP = !!material.roughnessMap; 20692 20693 const HAS_ANISOTROPY = material.anisotropy > 0; 20694 const HAS_CLEARCOAT = material.clearcoat > 0; 20695 const HAS_IRIDESCENCE = material.iridescence > 0; 20696 const HAS_SHEEN = material.sheen > 0; 20697 const HAS_TRANSMISSION = material.transmission > 0; 20698 20699 const HAS_ANISOTROPYMAP = HAS_ANISOTROPY && !!material.anisotropyMap; 20700 20701 const HAS_CLEARCOATMAP = HAS_CLEARCOAT && !!material.clearcoatMap; 20702 const HAS_CLEARCOAT_NORMALMAP = HAS_CLEARCOAT && !!material.clearcoatNormalMap; 20703 const HAS_CLEARCOAT_ROUGHNESSMAP = HAS_CLEARCOAT && !!material.clearcoatRoughnessMap; 20704 20705 const HAS_IRIDESCENCEMAP = HAS_IRIDESCENCE && !!material.iridescenceMap; 20706 const HAS_IRIDESCENCE_THICKNESSMAP = HAS_IRIDESCENCE && !!material.iridescenceThicknessMap; 20707 20708 const HAS_SHEEN_COLORMAP = HAS_SHEEN && !!material.sheenColorMap; 20709 const HAS_SHEEN_ROUGHNESSMAP = HAS_SHEEN && !!material.sheenRoughnessMap; 20710 20711 const HAS_SPECULARMAP = !!material.specularMap; 20712 const HAS_SPECULAR_COLORMAP = !!material.specularColorMap; 20713 const HAS_SPECULAR_INTENSITYMAP = !!material.specularIntensityMap; 20714 20715 const HAS_TRANSMISSIONMAP = HAS_TRANSMISSION && !!material.transmissionMap; 20716 const HAS_THICKNESSMAP = HAS_TRANSMISSION && !!material.thicknessMap; 20717 20718 const HAS_GRADIENTMAP = !!material.gradientMap; 20719 20720 const HAS_ALPHAMAP = !!material.alphaMap; 20721 20722 const HAS_ALPHATEST = material.alphaTest > 0; 20723 20724 const HAS_ALPHAHASH = !!material.alphaHash; 20725 20726 const HAS_EXTENSIONS = !!material.extensions; 20727 20728 const HAS_ATTRIBUTE_UV1 = !!geometry.attributes.uv1; 20729 const HAS_ATTRIBUTE_UV2 = !!geometry.attributes.uv2; 20730 const HAS_ATTRIBUTE_UV3 = !!geometry.attributes.uv3; 20731 20732 let toneMapping = NoToneMapping; 20733 20734 if (material.toneMapped) { 20735 20736 if (currentRenderTarget === null || currentRenderTarget.isXRRenderTarget === true) { 20737 20738 toneMapping = renderer.toneMapping; 20739 20740 } 20741 20742 } 20743 20744 const parameters = { 20745 20746 isWebGL2: IS_WEBGL2, 20747 20748 shaderID: shaderID, 20749 shaderType: material.type, 20750 shaderName: material.name, 20751 20752 vertexShader: vertexShader, 20753 fragmentShader: fragmentShader, 20754 defines: material.defines, 20755 20756 customVertexShaderID: customVertexShaderID, 20757 customFragmentShaderID: customFragmentShaderID, 20758 20759 isRawShaderMaterial: material.isRawShaderMaterial === true, 20760 glslVersion: material.glslVersion, 20761 20762 precision: precision, 20763 20764 batching: IS_BATCHEDMESH, 20765 instancing: IS_INSTANCEDMESH, 20766 instancingColor: IS_INSTANCEDMESH && object.instanceColor !== null, 20767 20768 supportsVertexTextures: SUPPORTS_VERTEX_TEXTURES, 20769 outputColorSpace: (currentRenderTarget === null) ? renderer.outputColorSpace : (currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace), 20770 20771 map: HAS_MAP, 20772 matcap: HAS_MATCAP, 20773 envMap: HAS_ENVMAP, 20774 envMapMode: HAS_ENVMAP && envMap.mapping, 20775 envMapCubeUVHeight: envMapCubeUVHeight, 20776 aoMap: HAS_AOMAP, 20777 lightMap: HAS_LIGHTMAP, 20778 bumpMap: HAS_BUMPMAP, 20779 normalMap: HAS_NORMALMAP, 20780 displacementMap: SUPPORTS_VERTEX_TEXTURES && HAS_DISPLACEMENTMAP, 20781 emissiveMap: HAS_EMISSIVEMAP, 20782 20783 normalMapObjectSpace: HAS_NORMALMAP && material.normalMapType === ObjectSpaceNormalMap, 20784 normalMapTangentSpace: HAS_NORMALMAP && material.normalMapType === TangentSpaceNormalMap, 20785 20786 metalnessMap: HAS_METALNESSMAP, 20787 roughnessMap: HAS_ROUGHNESSMAP, 20788 20789 anisotropy: HAS_ANISOTROPY, 20790 anisotropyMap: HAS_ANISOTROPYMAP, 20791 20792 clearcoat: HAS_CLEARCOAT, 20793 clearcoatMap: HAS_CLEARCOATMAP, 20794 clearcoatNormalMap: HAS_CLEARCOAT_NORMALMAP, 20795 clearcoatRoughnessMap: HAS_CLEARCOAT_ROUGHNESSMAP, 20796 20797 iridescence: HAS_IRIDESCENCE, 20798 iridescenceMap: HAS_IRIDESCENCEMAP, 20799 iridescenceThicknessMap: HAS_IRIDESCENCE_THICKNESSMAP, 20800 20801 sheen: HAS_SHEEN, 20802 sheenColorMap: HAS_SHEEN_COLORMAP, 20803 sheenRoughnessMap: HAS_SHEEN_ROUGHNESSMAP, 20804 20805 specularMap: HAS_SPECULARMAP, 20806 specularColorMap: HAS_SPECULAR_COLORMAP, 20807 specularIntensityMap: HAS_SPECULAR_INTENSITYMAP, 20808 20809 transmission: HAS_TRANSMISSION, 20810 transmissionMap: HAS_TRANSMISSIONMAP, 20811 thicknessMap: HAS_THICKNESSMAP, 20812 20813 gradientMap: HAS_GRADIENTMAP, 20814 20815 opaque: material.transparent === false && material.blending === NormalBlending, 20816 20817 alphaMap: HAS_ALPHAMAP, 20818 alphaTest: HAS_ALPHATEST, 20819 alphaHash: HAS_ALPHAHASH, 20820 20821 combine: material.combine, 20822 20823 // 20824 20825 mapUv: HAS_MAP && getChannel(material.map.channel), 20826 aoMapUv: HAS_AOMAP && getChannel(material.aoMap.channel), 20827 lightMapUv: HAS_LIGHTMAP && getChannel(material.lightMap.channel), 20828 bumpMapUv: HAS_BUMPMAP && getChannel(material.bumpMap.channel), 20829 normalMapUv: HAS_NORMALMAP && getChannel(material.normalMap.channel), 20830 displacementMapUv: HAS_DISPLACEMENTMAP && getChannel(material.displacementMap.channel), 20831 emissiveMapUv: HAS_EMISSIVEMAP && getChannel(material.emissiveMap.channel), 20832 20833 metalnessMapUv: HAS_METALNESSMAP && getChannel(material.metalnessMap.channel), 20834 roughnessMapUv: HAS_ROUGHNESSMAP && getChannel(material.roughnessMap.channel), 20835 20836 anisotropyMapUv: HAS_ANISOTROPYMAP && getChannel(material.anisotropyMap.channel), 20837 20838 clearcoatMapUv: HAS_CLEARCOATMAP && getChannel(material.clearcoatMap.channel), 20839 clearcoatNormalMapUv: HAS_CLEARCOAT_NORMALMAP && getChannel(material.clearcoatNormalMap.channel), 20840 clearcoatRoughnessMapUv: HAS_CLEARCOAT_ROUGHNESSMAP && getChannel(material.clearcoatRoughnessMap.channel), 20841 20842 iridescenceMapUv: HAS_IRIDESCENCEMAP && getChannel(material.iridescenceMap.channel), 20843 iridescenceThicknessMapUv: HAS_IRIDESCENCE_THICKNESSMAP && getChannel(material.iridescenceThicknessMap.channel), 20844 20845 sheenColorMapUv: HAS_SHEEN_COLORMAP && getChannel(material.sheenColorMap.channel), 20846 sheenRoughnessMapUv: HAS_SHEEN_ROUGHNESSMAP && getChannel(material.sheenRoughnessMap.channel), 20847 20848 specularMapUv: HAS_SPECULARMAP && getChannel(material.specularMap.channel), 20849 specularColorMapUv: HAS_SPECULAR_COLORMAP && getChannel(material.specularColorMap.channel), 20850 specularIntensityMapUv: HAS_SPECULAR_INTENSITYMAP && getChannel(material.specularIntensityMap.channel), 20851 20852 transmissionMapUv: HAS_TRANSMISSIONMAP && getChannel(material.transmissionMap.channel), 20853 thicknessMapUv: HAS_THICKNESSMAP && getChannel(material.thicknessMap.channel), 20854 20855 alphaMapUv: HAS_ALPHAMAP && getChannel(material.alphaMap.channel), 20856 20857 // 20858 20859 vertexTangents: !!geometry.attributes.tangent && (HAS_NORMALMAP || HAS_ANISOTROPY), 20860 vertexColors: material.vertexColors, 20861 vertexAlphas: material.vertexColors === true && !!geometry.attributes.color && geometry.attributes.color.itemSize === 4, 20862 vertexUv1s: HAS_ATTRIBUTE_UV1, 20863 vertexUv2s: HAS_ATTRIBUTE_UV2, 20864 vertexUv3s: HAS_ATTRIBUTE_UV3, 20865 20866 pointsUvs: object.isPoints === true && !!geometry.attributes.uv && (HAS_MAP || HAS_ALPHAMAP), 20867 20868 fog: !!fog, 20869 useFog: material.fog === true, 20870 fogExp2: (fog && fog.isFogExp2), 20871 20872 flatShading: material.flatShading === true, 20873 20874 sizeAttenuation: material.sizeAttenuation === true, 20875 logarithmicDepthBuffer: logarithmicDepthBuffer, 20876 20877 skinning: object.isSkinnedMesh === true, 20878 20879 morphTargets: geometry.morphAttributes.position !== undefined, 20880 morphNormals: geometry.morphAttributes.normal !== undefined, 20881 morphColors: geometry.morphAttributes.color !== undefined, 20882 morphTargetsCount: morphTargetsCount, 20883 morphTextureStride: morphTextureStride, 20884 20885 numDirLights: lights.directional.length, 20886 numPointLights: lights.point.length, 20887 numSpotLights: lights.spot.length, 20888 numSpotLightMaps: lights.spotLightMap.length, 20889 numRectAreaLights: lights.rectArea.length, 20890 numHemiLights: lights.hemi.length, 20891 20892 numDirLightShadows: lights.directionalShadowMap.length, 20893 numPointLightShadows: lights.pointShadowMap.length, 20894 numSpotLightShadows: lights.spotShadowMap.length, 20895 numSpotLightShadowsWithMaps: lights.numSpotLightShadowsWithMaps, 20896 20897 numLightProbes: lights.numLightProbes, 20898 20899 numClippingPlanes: clipping.numPlanes, 20900 numClipIntersection: clipping.numIntersection, 20901 20902 dithering: material.dithering, 20903 20904 shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0, 20905 shadowMapType: renderer.shadowMap.type, 20906 20907 toneMapping: toneMapping, 20908 useLegacyLights: renderer._useLegacyLights, 20909 20910 decodeVideoTexture: HAS_MAP && (material.map.isVideoTexture === true) && (ColorManagement.getTransfer(material.map.colorSpace) === SRGBTransfer), 20911 20912 premultipliedAlpha: material.premultipliedAlpha, 20913 20914 doubleSided: material.side === DoubleSide, 20915 flipSided: material.side === BackSide, 20916 20917 useDepthPacking: material.depthPacking >= 0, 20918 depthPacking: material.depthPacking || 0, 20919 20920 index0AttributeName: material.index0AttributeName, 20921 20922 extensionDerivatives: HAS_EXTENSIONS && material.extensions.derivatives === true, 20923 extensionFragDepth: HAS_EXTENSIONS && material.extensions.fragDepth === true, 20924 extensionDrawBuffers: HAS_EXTENSIONS && material.extensions.drawBuffers === true, 20925 extensionShaderTextureLOD: HAS_EXTENSIONS && material.extensions.shaderTextureLOD === true, 20926 extensionClipCullDistance: HAS_EXTENSIONS && material.extensions.clipCullDistance && extensions.has('WEBGL_clip_cull_distance'), 20927 20928 rendererExtensionFragDepth: IS_WEBGL2 || extensions.has('EXT_frag_depth'), 20929 rendererExtensionDrawBuffers: IS_WEBGL2 || extensions.has('WEBGL_draw_buffers'), 20930 rendererExtensionShaderTextureLod: IS_WEBGL2 || extensions.has('EXT_shader_texture_lod'), 20931 rendererExtensionParallelShaderCompile: extensions.has('KHR_parallel_shader_compile'), 20932 20933 customProgramCacheKey: material.customProgramCacheKey() 20934 20935 }; 20936 20937 return parameters; 20938 20939 } 20940 20941 function getProgramCacheKey(parameters) { 20942 20943 const array = []; 20944 20945 if (parameters.shaderID) { 20946 20947 array.push(parameters.shaderID); 20948 20949 } else { 20950 20951 array.push(parameters.customVertexShaderID); 20952 array.push(parameters.customFragmentShaderID); 20953 20954 } 20955 20956 if (parameters.defines !== undefined) { 20957 20958 for (const name in parameters.defines) { 20959 20960 array.push(name); 20961 array.push(parameters.defines[name]); 20962 20963 } 20964 20965 } 20966 20967 if (parameters.isRawShaderMaterial === false) { 20968 20969 getProgramCacheKeyParameters(array, parameters); 20970 getProgramCacheKeyBooleans(array, parameters); 20971 array.push(renderer.outputColorSpace); 20972 20973 } 20974 20975 array.push(parameters.customProgramCacheKey); 20976 20977 return array.join(); 20978 20979 } 20980 20981 function getProgramCacheKeyParameters(array, parameters) { 20982 20983 array.push(parameters.precision); 20984 array.push(parameters.outputColorSpace); 20985 array.push(parameters.envMapMode); 20986 array.push(parameters.envMapCubeUVHeight); 20987 array.push(parameters.mapUv); 20988 array.push(parameters.alphaMapUv); 20989 array.push(parameters.lightMapUv); 20990 array.push(parameters.aoMapUv); 20991 array.push(parameters.bumpMapUv); 20992 array.push(parameters.normalMapUv); 20993 array.push(parameters.displacementMapUv); 20994 array.push(parameters.emissiveMapUv); 20995 array.push(parameters.metalnessMapUv); 20996 array.push(parameters.roughnessMapUv); 20997 array.push(parameters.anisotropyMapUv); 20998 array.push(parameters.clearcoatMapUv); 20999 array.push(parameters.clearcoatNormalMapUv); 21000 array.push(parameters.clearcoatRoughnessMapUv); 21001 array.push(parameters.iridescenceMapUv); 21002 array.push(parameters.iridescenceThicknessMapUv); 21003 array.push(parameters.sheenColorMapUv); 21004 array.push(parameters.sheenRoughnessMapUv); 21005 array.push(parameters.specularMapUv); 21006 array.push(parameters.specularColorMapUv); 21007 array.push(parameters.specularIntensityMapUv); 21008 array.push(parameters.transmissionMapUv); 21009 array.push(parameters.thicknessMapUv); 21010 array.push(parameters.combine); 21011 array.push(parameters.fogExp2); 21012 array.push(parameters.sizeAttenuation); 21013 array.push(parameters.morphTargetsCount); 21014 array.push(parameters.morphAttributeCount); 21015 array.push(parameters.numDirLights); 21016 array.push(parameters.numPointLights); 21017 array.push(parameters.numSpotLights); 21018 array.push(parameters.numSpotLightMaps); 21019 array.push(parameters.numHemiLights); 21020 array.push(parameters.numRectAreaLights); 21021 array.push(parameters.numDirLightShadows); 21022 array.push(parameters.numPointLightShadows); 21023 array.push(parameters.numSpotLightShadows); 21024 array.push(parameters.numSpotLightShadowsWithMaps); 21025 array.push(parameters.numLightProbes); 21026 array.push(parameters.shadowMapType); 21027 array.push(parameters.toneMapping); 21028 array.push(parameters.numClippingPlanes); 21029 array.push(parameters.numClipIntersection); 21030 array.push(parameters.depthPacking); 21031 21032 } 21033 21034 function getProgramCacheKeyBooleans(array, parameters) { 21035 21036 _programLayers.disableAll(); 21037 21038 if (parameters.isWebGL2) 21039 _programLayers.enable(0); 21040 if (parameters.supportsVertexTextures) 21041 _programLayers.enable(1); 21042 if (parameters.instancing) 21043 _programLayers.enable(2); 21044 if (parameters.instancingColor) 21045 _programLayers.enable(3); 21046 if (parameters.matcap) 21047 _programLayers.enable(4); 21048 if (parameters.envMap) 21049 _programLayers.enable(5); 21050 if (parameters.normalMapObjectSpace) 21051 _programLayers.enable(6); 21052 if (parameters.normalMapTangentSpace) 21053 _programLayers.enable(7); 21054 if (parameters.clearcoat) 21055 _programLayers.enable(8); 21056 if (parameters.iridescence) 21057 _programLayers.enable(9); 21058 if (parameters.alphaTest) 21059 _programLayers.enable(10); 21060 if (parameters.vertexColors) 21061 _programLayers.enable(11); 21062 if (parameters.vertexAlphas) 21063 _programLayers.enable(12); 21064 if (parameters.vertexUv1s) 21065 _programLayers.enable(13); 21066 if (parameters.vertexUv2s) 21067 _programLayers.enable(14); 21068 if (parameters.vertexUv3s) 21069 _programLayers.enable(15); 21070 if (parameters.vertexTangents) 21071 _programLayers.enable(16); 21072 if (parameters.anisotropy) 21073 _programLayers.enable(17); 21074 if (parameters.alphaHash) 21075 _programLayers.enable(18); 21076 if (parameters.batching) 21077 _programLayers.enable(19); 21078 21079 array.push(_programLayers.mask); 21080 _programLayers.disableAll(); 21081 21082 if (parameters.fog) 21083 _programLayers.enable(0); 21084 if (parameters.useFog) 21085 _programLayers.enable(1); 21086 if (parameters.flatShading) 21087 _programLayers.enable(2); 21088 if (parameters.logarithmicDepthBuffer) 21089 _programLayers.enable(3); 21090 if (parameters.skinning) 21091 _programLayers.enable(4); 21092 if (parameters.morphTargets) 21093 _programLayers.enable(5); 21094 if (parameters.morphNormals) 21095 _programLayers.enable(6); 21096 if (parameters.morphColors) 21097 _programLayers.enable(7); 21098 if (parameters.premultipliedAlpha) 21099 _programLayers.enable(8); 21100 if (parameters.shadowMapEnabled) 21101 _programLayers.enable(9); 21102 if (parameters.useLegacyLights) 21103 _programLayers.enable(10); 21104 if (parameters.doubleSided) 21105 _programLayers.enable(11); 21106 if (parameters.flipSided) 21107 _programLayers.enable(12); 21108 if (parameters.useDepthPacking) 21109 _programLayers.enable(13); 21110 if (parameters.dithering) 21111 _programLayers.enable(14); 21112 if (parameters.transmission) 21113 _programLayers.enable(15); 21114 if (parameters.sheen) 21115 _programLayers.enable(16); 21116 if (parameters.opaque) 21117 _programLayers.enable(17); 21118 if (parameters.pointsUvs) 21119 _programLayers.enable(18); 21120 if (parameters.decodeVideoTexture) 21121 _programLayers.enable(19); 21122 21123 array.push(_programLayers.mask); 21124 21125 } 21126 21127 function getUniforms(material) { 21128 21129 const shaderID = shaderIDs[material.type]; 21130 let uniforms; 21131 21132 if (shaderID) { 21133 21134 const shader = ShaderLib[shaderID]; 21135 uniforms = UniformsUtils.clone(shader.uniforms); 21136 21137 } else { 21138 21139 uniforms = material.uniforms; 21140 21141 } 21142 21143 return uniforms; 21144 21145 } 21146 21147 function acquireProgram(parameters, cacheKey) { 21148 21149 let program; 21150 21151 // Check if code has been already compiled 21152 for (let p = 0, pl = programs.length; p < pl; p++) { 21153 21154 const preexistingProgram = programs[p]; 21155 21156 if (preexistingProgram.cacheKey === cacheKey) { 21157 21158 program = preexistingProgram; 21159 ++program.usedTimes; 21160 21161 break; 21162 21163 } 21164 21165 } 21166 21167 if (program === undefined) { 21168 21169 program = new WebGLProgram(renderer, cacheKey, parameters, bindingStates); 21170 programs.push(program); 21171 21172 } 21173 21174 return program; 21175 21176 } 21177 21178 function releaseProgram(program) { 21179 21180 if (--program.usedTimes === 0) { 21181 21182 // Remove from unordered set 21183 const i = programs.indexOf(program); 21184 programs[i] = programs[programs.length - 1]; 21185 programs.pop(); 21186 21187 // Free WebGL resources 21188 program.destroy(); 21189 21190 } 21191 21192 } 21193 21194 function releaseShaderCache(material) { 21195 21196 _customShaders.remove(material); 21197 21198 } 21199 21200 function dispose() { 21201 21202 _customShaders.dispose(); 21203 21204 } 21205 21206 return { 21207 getParameters: getParameters, 21208 getProgramCacheKey: getProgramCacheKey, 21209 getUniforms: getUniforms, 21210 acquireProgram: acquireProgram, 21211 releaseProgram: releaseProgram, 21212 releaseShaderCache: releaseShaderCache, 21213 // Exposed for resource monitoring & error feedback via renderer.info: 21214 programs: programs, 21215 dispose: dispose 21216 }; 21217 21218} 21219 21220function WebGLProperties() { 21221 21222 let properties = new WeakMap(); 21223 21224 function get(object) { 21225 21226 let map = properties.get(object); 21227 21228 if (map === undefined) { 21229 21230 map = {}; 21231 properties.set(object, map); 21232 21233 } 21234 21235 return map; 21236 21237 } 21238 21239 function remove(object) { 21240 21241 properties.delete(object); 21242 21243 } 21244 21245 function update(object, key, value) { 21246 21247 properties.get(object)[key] = value; 21248 21249 } 21250 21251 function dispose() { 21252 21253 properties = new WeakMap(); 21254 21255 } 21256 21257 return { 21258 get: get, 21259 remove: remove, 21260 update: update,
vendor: 4,151 bytes, lines 21261-21496
21261 dispose: dispose 21262 }; 21263 21264} 21265 21266function painterSortStable(a, b) { 21267 21268 if (a.groupOrder !== b.groupOrder) { 21269 21270 return a.groupOrder - b.groupOrder; 21271 21272 } else if (a.renderOrder !== b.renderOrder) { 21273 21274 return a.renderOrder - b.renderOrder; 21275 21276 } else if (a.material.id !== b.material.id) { 21277 21278 return a.material.id - b.material.id; 21279 21280 } else if (a.z !== b.z) { 21281 21282 return a.z - b.z; 21283 21284 } else { 21285 21286 return a.id - b.id; 21287 21288 } 21289 21290} 21291 21292function reversePainterSortStable(a, b) { 21293 21294 if (a.groupOrder !== b.groupOrder) { 21295 21296 return a.groupOrder - b.groupOrder; 21297 21298 } else if (a.renderOrder !== b.renderOrder) { 21299 21300 return a.renderOrder - b.renderOrder; 21301 21302 } else if (a.z !== b.z) { 21303 21304 return b.z - a.z; 21305 21306 } else { 21307 21308 return a.id - b.id; 21309 21310 } 21311 21312} 21313 21314 21315function WebGLRenderList() { 21316 21317 const renderItems = []; 21318 let renderItemsIndex = 0; 21319 21320 const opaque = []; 21321 const transmissive = []; 21322 const transparent = []; 21323 21324 function init() { 21325 21326 renderItemsIndex = 0; 21327 21328 opaque.length = 0; 21329 transmissive.length = 0; 21330 transparent.length = 0; 21331 21332 } 21333 21334 function getNextRenderItem(object, geometry, material, groupOrder, z, group) { 21335 21336 let renderItem = renderItems[renderItemsIndex]; 21337 21338 if (renderItem === undefined) { 21339 21340 renderItem = { 21341 id: object.id, 21342 object: object, 21343 geometry: geometry, 21344 material: material, 21345 groupOrder: groupOrder, 21346 renderOrder: object.renderOrder, 21347 z: z, 21348 group: group 21349 }; 21350 21351 renderItems[renderItemsIndex] = renderItem; 21352 21353 } else { 21354 21355 renderItem.id = object.id; 21356 renderItem.object = object; 21357 renderItem.geometry = geometry; 21358 renderItem.material = material; 21359 renderItem.groupOrder = groupOrder; 21360 renderItem.renderOrder = object.renderOrder; 21361 renderItem.z = z; 21362 renderItem.group = group; 21363 21364 } 21365 21366 renderItemsIndex++; 21367 21368 return renderItem; 21369 21370 } 21371 21372 function push(object, geometry, material, groupOrder, z, group) { 21373 21374 const renderItem = getNextRenderItem(object, geometry, material, groupOrder, z, group); 21375 21376 if (material.transmission > 0.0) { 21377 21378 transmissive.push(renderItem); 21379 21380 } else if (material.transparent === true) { 21381 21382 transparent.push(renderItem); 21383 21384 } else { 21385 21386 opaque.push(renderItem); 21387 21388 } 21389 21390 } 21391 21392 function unshift(object, geometry, material, groupOrder, z, group) { 21393 21394 const renderItem = getNextRenderItem(object, geometry, material, groupOrder, z, group); 21395 21396 if (material.transmission > 0.0) { 21397 21398 transmissive.unshift(renderItem); 21399 21400 } else if (material.transparent === true) { 21401 21402 transparent.unshift(renderItem); 21403 21404 } else { 21405 21406 opaque.unshift(renderItem); 21407 21408 } 21409 21410 } 21411 21412 function sort(customOpaqueSort, customTransparentSort) { 21413 21414 if (opaque.length > 1) opaque.sort(customOpaqueSort || painterSortStable); 21415 if (transmissive.length > 1) transmissive.sort(customTransparentSort || reversePainterSortStable); 21416 if (transparent.length > 1) transparent.sort(customTransparentSort || reversePainterSortStable); 21417 21418 } 21419 21420 function finish() { 21421 21422 // Clear references from inactive renderItems in the list 21423 21424 for (let i = renderItemsIndex, il = renderItems.length; i < il; i++) { 21425 21426 const renderItem = renderItems[i]; 21427 21428 if (renderItem.id === null) break; 21429 21430 renderItem.id = null; 21431 renderItem.object = null; 21432 renderItem.geometry = null; 21433 renderItem.material = null; 21434 renderItem.group = null; 21435 21436 } 21437 21438 } 21439 21440 return { 21441 21442 opaque: opaque, 21443 transmissive: transmissive, 21444 transparent: transparent, 21445 21446 init: init, 21447 push: push, 21448 unshift: unshift, 21449 finish: finish, 21450 21451 sort: sort 21452 }; 21453 21454} 21455 21456function WebGLRenderLists() { 21457 21458 let lists = new WeakMap(); 21459 21460 function get(scene, renderCallDepth) { 21461 21462 const listArray = lists.get(scene); 21463 let list; 21464 21465 if (listArray === undefined) { 21466 21467 list = new WebGLRenderList(); 21468 lists.set(scene, [list]); 21469 21470 } else { 21471 21472 if (renderCallDepth >= listArray.length) { 21473 21474 list = new WebGLRenderList(); 21475 listArray.push(list); 21476 21477 } else { 21478 21479 list = listArray[renderCallDepth]; 21480 21481 } 21482 21483 } 21484 21485 return list; 21486 21487 } 21488 21489 function dispose() { 21490 21491 lists = new WeakMap(); 21492 21493 } 21494 21495 return { 21496 get: get,
vendor: 17,259 bytes, lines 21497-22279
21497 dispose: dispose 21498 }; 21499 21500} 21501 21502function UniformsCache() { 21503 21504 const lights = {}; 21505 21506 return { 21507 21508 get: function (light) { 21509 21510 if (lights[light.id] !== undefined) { 21511 21512 return lights[light.id]; 21513 21514 } 21515 21516 let uniforms; 21517 21518 switch (light.type) { 21519 21520 case 'DirectionalLight': 21521 uniforms = { 21522 direction: new Vector3(), 21523 color: new Color() 21524 }; 21525 break; 21526 21527 case 'SpotLight': 21528 uniforms = { 21529 position: new Vector3(), 21530 direction: new Vector3(), 21531 color: new Color(), 21532 distance: 0, 21533 coneCos: 0, 21534 penumbraCos: 0, 21535 decay: 0 21536 }; 21537 break; 21538 21539 case 'PointLight': 21540 uniforms = { 21541 position: new Vector3(), 21542 color: new Color(), 21543 distance: 0, 21544 decay: 0 21545 }; 21546 break; 21547 21548 case 'HemisphereLight': 21549 uniforms = { 21550 direction: new Vector3(), 21551 skyColor: new Color(), 21552 groundColor: new Color() 21553 }; 21554 break; 21555 21556 case 'RectAreaLight': 21557 uniforms = { 21558 color: new Color(), 21559 position: new Vector3(), 21560 halfWidth: new Vector3(), 21561 halfHeight: new Vector3() 21562 }; 21563 break; 21564 21565 } 21566 21567 lights[light.id] = uniforms; 21568 21569 return uniforms; 21570 21571 } 21572 21573 }; 21574 21575} 21576 21577function ShadowUniformsCache() { 21578 21579 const lights = {}; 21580 21581 return { 21582 21583 get: function (light) { 21584 21585 if (lights[light.id] !== undefined) { 21586 21587 return lights[light.id]; 21588 21589 } 21590 21591 let uniforms; 21592 21593 switch (light.type) { 21594 21595 case 'DirectionalLight': 21596 uniforms = { 21597 shadowBias: 0, 21598 shadowNormalBias: 0, 21599 shadowRadius: 1, 21600 shadowMapSize: new Vector2() 21601 }; 21602 break; 21603 21604 case 'SpotLight': 21605 uniforms = { 21606 shadowBias: 0, 21607 shadowNormalBias: 0, 21608 shadowRadius: 1, 21609 shadowMapSize: new Vector2() 21610 }; 21611 break; 21612 21613 case 'PointLight': 21614 uniforms = { 21615 shadowBias: 0, 21616 shadowNormalBias: 0, 21617 shadowRadius: 1, 21618 shadowMapSize: new Vector2(), 21619 shadowCameraNear: 1, 21620 shadowCameraFar: 1000 21621 }; 21622 break; 21623 21624 // TODO (abelnation): set RectAreaLight shadow uniforms 21625 21626 } 21627 21628 lights[light.id] = uniforms; 21629 21630 return uniforms; 21631 21632 } 21633 21634 }; 21635 21636} 21637 21638 21639 21640let nextVersion = 0; 21641 21642function shadowCastingAndTexturingLightsFirst(lightA, lightB) { 21643 21644 return (lightB.castShadow ? 2 : 0) - (lightA.castShadow ? 2 : 0) + (lightB.map ? 1 : 0) - (lightA.map ? 1 : 0); 21645 21646} 21647 21648function WebGLLights(extensions, capabilities) { 21649 21650 const cache = new UniformsCache(); 21651 21652 const shadowCache = ShadowUniformsCache(); 21653 21654 const state = { 21655 21656 version: 0, 21657 21658 hash: { 21659 directionalLength: - 1, 21660 pointLength: - 1, 21661 spotLength: - 1, 21662 rectAreaLength: - 1, 21663 hemiLength: - 1, 21664 21665 numDirectionalShadows: - 1, 21666 numPointShadows: - 1, 21667 numSpotShadows: - 1, 21668 numSpotMaps: - 1, 21669 21670 numLightProbes: - 1 21671 }, 21672 21673 ambient: [0, 0, 0], 21674 probe: [], 21675 directional: [], 21676 directionalShadow: [], 21677 directionalShadowMap: [], 21678 directionalShadowMatrix: [], 21679 spot: [], 21680 spotLightMap: [], 21681 spotShadow: [], 21682 spotShadowMap: [], 21683 spotLightMatrix: [], 21684 rectArea: [], 21685 rectAreaLTC1: null, 21686 rectAreaLTC2: null, 21687 point: [], 21688 pointShadow: [], 21689 pointShadowMap: [], 21690 pointShadowMatrix: [], 21691 hemi: [], 21692 numSpotLightShadowsWithMaps: 0, 21693 numLightProbes: 0 21694 21695 }; 21696 21697 for (let i = 0; i < 9; i++) state.probe.push(new Vector3()); 21698 21699 const vector3 = new Vector3(); 21700 const matrix4 = new Matrix4(); 21701 const matrix42 = new Matrix4(); 21702 21703 function setup(lights, useLegacyLights) { 21704 21705 let r = 0, g = 0, b = 0; 21706 21707 for (let i = 0; i < 9; i++) state.probe[i].set(0, 0, 0); 21708 21709 let directionalLength = 0; 21710 let pointLength = 0; 21711 let spotLength = 0; 21712 let rectAreaLength = 0; 21713 let hemiLength = 0; 21714 21715 let numDirectionalShadows = 0; 21716 let numPointShadows = 0; 21717 let numSpotShadows = 0; 21718 let numSpotMaps = 0; 21719 let numSpotShadowsWithMaps = 0; 21720 21721 let numLightProbes = 0; 21722 21723 // ordering : [shadow casting + map texturing, map texturing, shadow casting, none ] 21724 lights.sort(shadowCastingAndTexturingLightsFirst); 21725 21726 // artist-friendly light intensity scaling factor 21727 const scaleFactor = (useLegacyLights === true) ? Math.PI : 1; 21728 21729 for (let i = 0, l = lights.length; i < l; i++) { 21730 21731 const light = lights[i]; 21732 21733 const color = light.color; 21734 const intensity = light.intensity; 21735 const distance = light.distance; 21736 21737 const shadowMap = (light.shadow && light.shadow.map) ? light.shadow.map.texture : null; 21738 21739 if (light.isAmbientLight) { 21740 21741 r += color.r * intensity * scaleFactor; 21742 g += color.g * intensity * scaleFactor; 21743 b += color.b * intensity * scaleFactor; 21744 21745 } else if (light.isLightProbe) { 21746 21747 for (let j = 0; j < 9; j++) { 21748 21749 state.probe[j].addScaledVector(light.sh.coefficients[j], intensity); 21750 21751 } 21752 21753 numLightProbes++; 21754 21755 } else if (light.isDirectionalLight) { 21756 21757 const uniforms = cache.get(light); 21758 21759 uniforms.color.copy(light.color).multiplyScalar(light.intensity * scaleFactor); 21760 21761 if (light.castShadow) { 21762 21763 const shadow = light.shadow; 21764 21765 const shadowUniforms = shadowCache.get(light); 21766 21767 shadowUniforms.shadowBias = shadow.bias; 21768 shadowUniforms.shadowNormalBias = shadow.normalBias; 21769 shadowUniforms.shadowRadius = shadow.radius; 21770 shadowUniforms.shadowMapSize = shadow.mapSize; 21771 21772 state.directionalShadow[directionalLength] = shadowUniforms; 21773 state.directionalShadowMap[directionalLength] = shadowMap; 21774 state.directionalShadowMatrix[directionalLength] = light.shadow.matrix; 21775 21776 numDirectionalShadows++; 21777 21778 } 21779 21780 state.directional[directionalLength] = uniforms; 21781 21782 directionalLength++; 21783 21784 } else if (light.isSpotLight) { 21785 21786 const uniforms = cache.get(light); 21787 21788 uniforms.position.setFromMatrixPosition(light.matrixWorld); 21789 21790 uniforms.color.copy(color).multiplyScalar(intensity * scaleFactor); 21791 uniforms.distance = distance; 21792 21793 uniforms.coneCos = Math.cos(light.angle); 21794 uniforms.penumbraCos = Math.cos(light.angle * (1 - light.penumbra)); 21795 uniforms.decay = light.decay; 21796 21797 state.spot[spotLength] = uniforms; 21798 21799 const shadow = light.shadow; 21800 21801 if (light.map) { 21802 21803 state.spotLightMap[numSpotMaps] = light.map; 21804 numSpotMaps++; 21805 21806 // make sure the lightMatrix is up to date 21807 // TODO : do it if required only 21808 shadow.updateMatrices(light); 21809 21810 if (light.castShadow) numSpotShadowsWithMaps++; 21811 21812 } 21813 21814 state.spotLightMatrix[spotLength] = shadow.matrix; 21815 21816 if (light.castShadow) { 21817 21818 const shadowUniforms = shadowCache.get(light); 21819 21820 shadowUniforms.shadowBias = shadow.bias; 21821 shadowUniforms.shadowNormalBias = shadow.normalBias; 21822 shadowUniforms.shadowRadius = shadow.radius; 21823 shadowUniforms.shadowMapSize = shadow.mapSize; 21824 21825 state.spotShadow[spotLength] = shadowUniforms; 21826 state.spotShadowMap[spotLength] = shadowMap; 21827 21828 numSpotShadows++; 21829 21830 } 21831 21832 spotLength++; 21833 21834 } else if (light.isRectAreaLight) { 21835 21836 const uniforms = cache.get(light); 21837 21838 uniforms.color.copy(color).multiplyScalar(intensity); 21839 21840 uniforms.halfWidth.set(light.width * 0.5, 0.0, 0.0); 21841 uniforms.halfHeight.set(0.0, light.height * 0.5, 0.0); 21842 21843 state.rectArea[rectAreaLength] = uniforms; 21844 21845 rectAreaLength++; 21846 21847 } else if (light.isPointLight) { 21848 21849 const uniforms = cache.get(light); 21850 21851 uniforms.color.copy(light.color).multiplyScalar(light.intensity * scaleFactor); 21852 uniforms.distance = light.distance; 21853 uniforms.decay = light.decay; 21854 21855 if (light.castShadow) { 21856 21857 const shadow = light.shadow; 21858 21859 const shadowUniforms = shadowCache.get(light); 21860 21861 shadowUniforms.shadowBias = shadow.bias; 21862 shadowUniforms.shadowNormalBias = shadow.normalBias; 21863 shadowUniforms.shadowRadius = shadow.radius; 21864 shadowUniforms.shadowMapSize = shadow.mapSize; 21865 shadowUniforms.shadowCameraNear = shadow.camera.near; 21866 shadowUniforms.shadowCameraFar = shadow.camera.far; 21867 21868 state.pointShadow[pointLength] = shadowUniforms; 21869 state.pointShadowMap[pointLength] = shadowMap; 21870 state.pointShadowMatrix[pointLength] = light.shadow.matrix; 21871 21872 numPointShadows++; 21873 21874 } 21875 21876 state.point[pointLength] = uniforms; 21877 21878 pointLength++; 21879 21880 } else if (light.isHemisphereLight) { 21881 21882 const uniforms = cache.get(light); 21883 21884 uniforms.skyColor.copy(light.color).multiplyScalar(intensity * scaleFactor); 21885 uniforms.groundColor.copy(light.groundColor).multiplyScalar(intensity * scaleFactor); 21886 21887 state.hemi[hemiLength] = uniforms; 21888 21889 hemiLength++; 21890 21891 } 21892 21893 } 21894 21895 if (rectAreaLength > 0) { 21896 21897 if (capabilities.isWebGL2) { 21898 21899 // WebGL 2 21900 21901 if (extensions.has('OES_texture_float_linear') === true) { 21902 21903 state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1; 21904 state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2; 21905 21906 } else { 21907 21908 state.rectAreaLTC1 = UniformsLib.LTC_HALF_1; 21909 state.rectAreaLTC2 = UniformsLib.LTC_HALF_2; 21910 21911 } 21912 21913 } else { 21914 21915 // WebGL 1 21916 21917 if (extensions.has('OES_texture_float_linear') === true) { 21918 21919 state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1; 21920 state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2; 21921 21922 } else if (extensions.has('OES_texture_half_float_linear') === true) { 21923 21924 state.rectAreaLTC1 = UniformsLib.LTC_HALF_1; 21925 state.rectAreaLTC2 = UniformsLib.LTC_HALF_2; 21926 21927 } else { 21928 21929 console.error('THREE.WebGLRenderer: Unable to use RectAreaLight. Missing WebGL extensions.'); 21930 21931 } 21932 21933 } 21934 21935 } 21936 21937 state.ambient[0] = r; 21938 state.ambient[1] = g; 21939 state.ambient[2] = b; 21940 21941 const hash = state.hash; 21942 21943 if (hash.directionalLength !== directionalLength || 21944 hash.pointLength !== pointLength || 21945 hash.spotLength !== spotLength || 21946 hash.rectAreaLength !== rectAreaLength || 21947 hash.hemiLength !== hemiLength || 21948 hash.numDirectionalShadows !== numDirectionalShadows || 21949 hash.numPointShadows !== numPointShadows || 21950 hash.numSpotShadows !== numSpotShadows || 21951 hash.numSpotMaps !== numSpotMaps || 21952 hash.numLightProbes !== numLightProbes) { 21953 21954 state.directional.length = directionalLength; 21955 state.spot.length = spotLength; 21956 state.rectArea.length = rectAreaLength; 21957 state.point.length = pointLength; 21958 state.hemi.length = hemiLength; 21959 21960 state.directionalShadow.length = numDirectionalShadows; 21961 state.directionalShadowMap.length = numDirectionalShadows; 21962 state.pointShadow.length = numPointShadows; 21963 state.pointShadowMap.length = numPointShadows; 21964 state.spotShadow.length = numSpotShadows; 21965 state.spotShadowMap.length = numSpotShadows; 21966 state.directionalShadowMatrix.length = numDirectionalShadows; 21967 state.pointShadowMatrix.length = numPointShadows; 21968 state.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps; 21969 state.spotLightMap.length = numSpotMaps; 21970 state.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps; 21971 state.numLightProbes = numLightProbes; 21972 21973 hash.directionalLength = directionalLength; 21974 hash.pointLength = pointLength; 21975 hash.spotLength = spotLength; 21976 hash.rectAreaLength = rectAreaLength; 21977 hash.hemiLength = hemiLength; 21978 21979 hash.numDirectionalShadows = numDirectionalShadows; 21980 hash.numPointShadows = numPointShadows; 21981 hash.numSpotShadows = numSpotShadows; 21982 hash.numSpotMaps = numSpotMaps; 21983 21984 hash.numLightProbes = numLightProbes; 21985 21986 state.version = nextVersion++; 21987 21988 } 21989 21990 } 21991 21992 function setupView(lights, camera) { 21993 21994 let directionalLength = 0; 21995 let pointLength = 0; 21996 let spotLength = 0; 21997 let rectAreaLength = 0; 21998 let hemiLength = 0; 21999 22000 const viewMatrix = camera.matrixWorldInverse; 22001 22002 for (let i = 0, l = lights.length; i < l; i++) { 22003 22004 const light = lights[i]; 22005 22006 if (light.isDirectionalLight) { 22007 22008 const uniforms = state.directional[directionalLength]; 22009 22010 uniforms.direction.setFromMatrixPosition(light.matrixWorld); 22011 vector3.setFromMatrixPosition(light.target.matrixWorld); 22012 uniforms.direction.sub(vector3); 22013 uniforms.direction.transformDirection(viewMatrix); 22014 22015 directionalLength++; 22016 22017 } else if (light.isSpotLight) { 22018 22019 const uniforms = state.spot[spotLength]; 22020 22021 uniforms.position.setFromMatrixPosition(light.matrixWorld); 22022 uniforms.position.applyMatrix4(viewMatrix); 22023 22024 uniforms.direction.setFromMatrixPosition(light.matrixWorld); 22025 vector3.setFromMatrixPosition(light.target.matrixWorld); 22026 uniforms.direction.sub(vector3); 22027 uniforms.direction.transformDirection(viewMatrix); 22028 22029 spotLength++; 22030 22031 } else if (light.isRectAreaLight) { 22032 22033 const uniforms = state.rectArea[rectAreaLength]; 22034 22035 uniforms.position.setFromMatrixPosition(light.matrixWorld); 22036 uniforms.position.applyMatrix4(viewMatrix); 22037 22038 // extract local rotation of light to derive width/height half vectors 22039 matrix42.identity(); 22040 matrix4.copy(light.matrixWorld); 22041 matrix4.premultiply(viewMatrix); 22042 matrix42.extractRotation(matrix4); 22043 22044 uniforms.halfWidth.set(light.width * 0.5, 0.0, 0.0); 22045 uniforms.halfHeight.set(0.0, light.height * 0.5, 0.0); 22046 22047 uniforms.halfWidth.applyMatrix4(matrix42); 22048 uniforms.halfHeight.applyMatrix4(matrix42); 22049 22050 rectAreaLength++; 22051 22052 } else if (light.isPointLight) { 22053 22054 const uniforms = state.point[pointLength]; 22055 22056 uniforms.position.setFromMatrixPosition(light.matrixWorld); 22057 uniforms.position.applyMatrix4(viewMatrix); 22058 22059 pointLength++; 22060 22061 } else if (light.isHemisphereLight) { 22062 22063 const uniforms = state.hemi[hemiLength]; 22064 22065 uniforms.direction.setFromMatrixPosition(light.matrixWorld); 22066 uniforms.direction.transformDirection(viewMatrix); 22067 22068 hemiLength++; 22069 22070 } 22071 22072 } 22073 22074 } 22075 22076 return { 22077 setup: setup, 22078 setupView: setupView, 22079 state: state 22080 }; 22081 22082} 22083 22084function WebGLRenderState(extensions, capabilities) { 22085 22086 const lights = new WebGLLights(extensions, capabilities); 22087 22088 const lightsArray = []; 22089 const shadowsArray = []; 22090 22091 function init() { 22092 22093 lightsArray.length = 0; 22094 shadowsArray.length = 0; 22095 22096 } 22097 22098 function pushLight(light) { 22099 22100 lightsArray.push(light); 22101 22102 } 22103 22104 function pushShadow(shadowLight) { 22105 22106 shadowsArray.push(shadowLight); 22107 22108 } 22109 22110 function setupLights(useLegacyLights) { 22111 22112 lights.setup(lightsArray, useLegacyLights); 22113 22114 } 22115 22116 function setupLightsView(camera) { 22117 22118 lights.setupView(lightsArray, camera); 22119 22120 } 22121 22122 const state = { 22123 lightsArray: lightsArray, 22124 shadowsArray: shadowsArray, 22125 22126 lights: lights 22127 }; 22128 22129 return { 22130 init: init, 22131 state: state, 22132 setupLights: setupLights, 22133 setupLightsView: setupLightsView, 22134 22135 pushLight: pushLight, 22136 pushShadow: pushShadow 22137 }; 22138 22139} 22140 22141function WebGLRenderStates(extensions, capabilities) { 22142 22143 let renderStates = new WeakMap(); 22144 22145 function get(scene, renderCallDepth = 0) { 22146 22147 const renderStateArray = renderStates.get(scene); 22148 let renderState; 22149 22150 if (renderStateArray === undefined) { 22151 22152 renderState = new WebGLRenderState(extensions, capabilities); 22153 renderStates.set(scene, [renderState]); 22154 22155 } else { 22156 22157 if (renderCallDepth >= renderStateArray.length) { 22158 22159 renderState = new WebGLRenderState(extensions, capabilities); 22160 renderStateArray.push(renderState); 22161 22162 } else { 22163 22164 renderState = renderStateArray[renderCallDepth]; 22165 22166 } 22167 22168 } 22169 22170 return renderState; 22171 22172 } 22173 22174 function dispose() { 22175 22176 renderStates = new WeakMap(); 22177 22178 } 22179 22180 return { 22181 get: get, 22182 dispose: dispose 22183 }; 22184 22185} 22186 22187class MeshDepthMaterial extends Material { 22188 22189 constructor(parameters) { 22190 22191 super(); 22192 22193 this.isMeshDepthMaterial = true; 22194 22195 this.type = 'MeshDepthMaterial'; 22196 22197 this.depthPacking = BasicDepthPacking; 22198 22199 this.map = null; 22200 22201 this.alphaMap = null; 22202 22203 this.displacementMap = null; 22204 this.displacementScale = 1; 22205 this.displacementBias = 0; 22206 22207 this.wireframe = false; 22208 this.wireframeLinewidth = 1; 22209 22210 this.setValues(parameters); 22211 22212 } 22213 22214 copy(source) { 22215 22216 super.copy(source); 22217 22218 this.depthPacking = source.depthPacking; 22219 22220 this.map = source.map; 22221 22222 this.alphaMap = source.alphaMap; 22223 22224 this.displacementMap = source.displacementMap; 22225 this.displacementScale = source.displacementScale; 22226 this.displacementBias = source.displacementBias; 22227 22228 this.wireframe = source.wireframe; 22229 this.wireframeLinewidth = source.wireframeLinewidth; 22230 22231 return this; 22232 22233 } 22234 22235} 22236 22237class MeshDistanceMaterial extends Material { 22238 22239 constructor(parameters) { 22240 22241 super(); 22242 22243 this.isMeshDistanceMaterial = true; 22244 22245 this.type = 'MeshDistanceMaterial'; 22246 22247 this.map = null; 22248 22249 this.alphaMap = null; 22250 22251 this.displacementMap = null; 22252 this.displacementScale = 1; 22253 this.displacementBias = 0; 22254 22255 this.setValues(parameters); 22256 22257 } 22258 22259 copy(source) { 22260 22261 super.copy(source); 22262 22263 this.map = source.map; 22264 22265 this.alphaMap = source.alphaMap; 22266 22267 this.displacementMap = source.displacementMap; 22268 this.displacementScale = source.displacementScale; 22269 this.displacementBias = source.displacementBias; 22270 22271 return this; 22272 22273 } 22274 22275} 22276 22277const vertex = "void main() {\n\tgl_Position = vec4( position, 1.0 );\n}"; 22278 22279const fragment = "uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\n#include <packing>
22279\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}"; 22280 22281function WebGLShadowMap(_renderer, _objects, _capabilities) { 22282 22283 let _frustum = new Frustum(); 22284 22285 const _shadowMapSize = new Vector2(), 22286 _viewportSize = new Vector2(), 22287 22288 _viewport = new Vector4(), 22289 22290 _depthMaterial = new MeshDepthMaterial({ depthPacking: RGBADepthPacking }), 22291 _distanceMaterial = new MeshDistanceMaterial(), 22292 22293 _materialCache = {}, 22294 22295 _maxTextureSize = _capabilities.maxTextureSize; 22296 22297 const shadowSide = { [FrontSide]: BackSide, [BackSide]: FrontSide, [DoubleSide]: DoubleSide }; 22298 22299 const shadowMaterialVertical = new ShaderMaterial({ 22300 defines: { 22301 VSM_SAMPLES: 8 22302 }, 22303 uniforms: { 22304 shadow_pass: { value: null }, 22305 resolution: { value: new Vector2() }, 22306 radius: { value: 4.0 } 22307 }, 22308 22309 vertexShader: vertex, 22310 fragmentShader: fragment 22311 22312 }); 22313 22314 const shadowMaterialHorizontal = shadowMaterialVertical.clone(); 22315 shadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1; 22316 22317 const fullScreenTri = new BufferGeometry(); 22318 fullScreenTri.setAttribute( 22319 'position', 22320 new BufferAttribute( 22321 new Float32Array([- 1, - 1, 0.5, 3, - 1, 0.5, - 1, 3, 0.5]), 22322 3 22323 ) 22324 ); 22325 22326 const fullScreenMesh = new Mesh(fullScreenTri, shadowMaterialVertical); 22327 22328 const scope = this; 22329 22330 this.enabled = false; 22331 22332 this.autoUpdate = true; 22333 this.needsUpdate = false; 22334 22335 this.type = PCFShadowMap; 22336 let _previousType = this.type; 22337 22338 this.render = function (lights, scene, camera) { 22339 22340 if (scope.enabled === false) return; 22341 if (scope.autoUpdate === false && scope.needsUpdate === false) return; 22342 22343 if (lights.length === 0) return; 22344 22345 const currentRenderTarget = _renderer.getRenderTarget(); 22346 const activeCubeFace = _renderer.getActiveCubeFace(); 22347 const activeMipmapLevel = _renderer.getActiveMipmapLevel(); 22348 22349 const _state = _renderer.state; 22350 22351 // Set GL state for depth map. 22352 _state.setBlending(NoBlending); 22353 _state.buffers.color.setClear(1, 1, 1, 1); 22354 _state.buffers.depth.setTest(true); 22355 _state.setScissorTest(false); 22356 22357 // check for shadow map type changes 22358 22359 const toVSM = (_previousType !== VSMShadowMap && this.type === VSMShadowMap); 22360 const fromVSM = (_previousType === VSMShadowMap && this.type !== VSMShadowMap); 22361 22362 // render depth map 22363 22364 for (let i = 0, il = lights.length; i < il; i++) { 22365 22366 const light = lights[i]; 22367 const shadow = light.shadow; 22368 22369 if (shadow === undefined) { 22370 22371 console.warn('THREE.WebGLShadowMap:', light, 'has no shadow.'); 22372 continue; 22373 22374 } 22375 22376 if (shadow.autoUpdate === false && shadow.needsUpdate === false) continue; 22377 22378 _shadowMapSize.copy(shadow.mapSize); 22379 22380 const shadowFrameExtents = shadow.getFrameExtents(); 22381 22382 _shadowMapSize.multiply(shadowFrameExtents); 22383 22384 _viewportSize.copy(shadow.mapSize); 22385 22386 if (_shadowMapSize.x > _maxTextureSize || _shadowMapSize.y > _maxTextureSize) { 22387 22388 if (_shadowMapSize.x > _maxTextureSize) { 22389 22390 _viewportSize.x = Math.floor(_maxTextureSize / shadowFrameExtents.x); 22391 _shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x; 22392 shadow.mapSize.x = _viewportSize.x; 22393 22394 } 22395 22396 if (_shadowMapSize.y > _maxTextureSize) { 22397 22398 _viewportSize.y = Math.floor(_maxTextureSize / shadowFrameExtents.y); 22399 _shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y; 22400 shadow.mapSize.y = _viewportSize.y; 22401 22402 } 22403 22404 } 22405 22406 if (shadow.map === null || toVSM === true || fromVSM === true) { 22407 22408 const pars = (this.type !== VSMShadowMap) ? { minFilter: NearestFilter, magFilter: NearestFilter } : {}; 22409 22410 if (shadow.map !== null) { 22411 22412 shadow.map.dispose(); 22413 22414 } 22415 22416 shadow.map = new WebGLRenderTarget(_shadowMapSize.x, _shadowMapSize.y, pars); 22417 shadow.map.texture.name = light.name + '.shadowMap'; 22418 22419 shadow.camera.updateProjectionMatrix(); 22420 22421 } 22422 22423 _renderer.setRenderTarget(shadow.map); 22424 _renderer.clear(); 22425 22426 const viewportCount = shadow.getViewportCount(); 22427
vendor: 2,558 bytes, lines 22428-22522
22428 for (let vp = 0; vp < viewportCount; vp++) { 22429 22430 const viewport = shadow.getViewport(vp); 22431 22432 _viewport.set( 22433 _viewportSize.x * viewport.x, 22434 _viewportSize.y * viewport.y, 22435 _viewportSize.x * viewport.z, 22436 _viewportSize.y * viewport.w 22437 ); 22438 22439 _state.viewport(_viewport); 22440 22441 shadow.updateMatrices(light, vp); 22442 22443 _frustum = shadow.getFrustum(); 22444 22445 renderObject(scene, camera, shadow.camera, light, this.type); 22446 22447 } 22448 22449 // do blur pass for VSM 22450 22451 if (shadow.isPointLightShadow !== true && this.type === VSMShadowMap) { 22452 22453 VSMPass(shadow, camera); 22454 22455 } 22456 22457 shadow.needsUpdate = false; 22458 22459 } 22460 22461 _previousType = this.type; 22462 22463 scope.needsUpdate = false; 22464 22465 _renderer.setRenderTarget(currentRenderTarget, activeCubeFace, activeMipmapLevel); 22466 22467 }; 22468 22469 function VSMPass(shadow, camera) { 22470 22471 const geometry = _objects.update(fullScreenMesh); 22472 22473 if (shadowMaterialVertical.defines.VSM_SAMPLES !== shadow.blurSamples) { 22474 22475 shadowMaterialVertical.defines.VSM_SAMPLES = shadow.blurSamples; 22476 shadowMaterialHorizontal.defines.VSM_SAMPLES = shadow.blurSamples; 22477 22478 shadowMaterialVertical.needsUpdate = true; 22479 shadowMaterialHorizontal.needsUpdate = true; 22480 22481 } 22482 22483 if (shadow.mapPass === null) { 22484 22485 shadow.mapPass = new WebGLRenderTarget(_shadowMapSize.x, _shadowMapSize.y); 22486 22487 } 22488 22489 // vertical pass 22490 22491 shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture; 22492 shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize; 22493 shadowMaterialVertical.uniforms.radius.value = shadow.radius; 22494 _renderer.setRenderTarget(shadow.mapPass); 22495 _renderer.clear(); 22496 _renderer.renderBufferDirect(camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null); 22497 22498 // horizontal pass 22499 22500 shadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture; 22501 shadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize; 22502 shadowMaterialHorizontal.uniforms.radius.value = shadow.radius; 22503 _renderer.setRenderTarget(shadow.map); 22504 _renderer.clear(); 22505 _renderer.renderBufferDirect(camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null); 22506 22507 } 22508 22509 function getDepthMaterial(object, material, light, type) { 22510 22511 let result = null; 22512 22513 const customMaterial = (light.isPointLight === true) ? object.customDistanceMaterial : object.customDepthMaterial; 22514 22515 if (customMaterial !== undefined) { 22516 22517 result = customMaterial; 22518 22519 } else { 22520 22521 result = (light.isPointLight === true) ? _distanceMaterial : _depthMaterial; 22522
vendor: 123,361 bytes, lines 22523-27444
22523 if ((_renderer.localClippingEnabled && material.clipShadows === true && Array.isArray(material.clippingPlanes) && material.clippingPlanes.length !== 0) || 22524 (material.displacementMap && material.displacementScale !== 0) || 22525 (material.alphaMap && material.alphaTest > 0) || 22526 (material.map && material.alphaTest > 0)) { 22527 22528 // in this case we need a unique material instance reflecting the 22529 // appropriate state 22530 22531 const keyA = result.uuid, keyB = material.uuid; 22532 22533 let materialsForVariant = _materialCache[keyA]; 22534 22535 if (materialsForVariant === undefined) { 22536 22537 materialsForVariant = {}; 22538 _materialCache[keyA] = materialsForVariant; 22539 22540 } 22541 22542 let cachedMaterial = materialsForVariant[keyB]; 22543 22544 if (cachedMaterial === undefined) { 22545 22546 cachedMaterial = result.clone(); 22547 materialsForVariant[keyB] = cachedMaterial; 22548 material.addEventListener('dispose', onMaterialDispose); 22549 22550 } 22551 22552 result = cachedMaterial; 22553 22554 } 22555 22556 } 22557 22558 result.visible = material.visible; 22559 result.wireframe = material.wireframe; 22560 22561 if (type === VSMShadowMap) { 22562 22563 result.side = (material.shadowSide !== null) ? material.shadowSide : material.side; 22564 22565 } else { 22566 22567 result.side = (material.shadowSide !== null) ? material.shadowSide : shadowSide[material.side]; 22568 22569 } 22570 22571 result.alphaMap = material.alphaMap; 22572 result.alphaTest = material.alphaTest; 22573 result.map = material.map; 22574 22575 result.clipShadows = material.clipShadows; 22576 result.clippingPlanes = material.clippingPlanes; 22577 result.clipIntersection = material.clipIntersection; 22578 22579 result.displacementMap = material.displacementMap; 22580 result.displacementScale = material.displacementScale; 22581 result.displacementBias = material.displacementBias; 22582 22583 result.wireframeLinewidth = material.wireframeLinewidth; 22584 result.linewidth = material.linewidth; 22585 22586 if (light.isPointLight === true && result.isMeshDistanceMaterial === true) { 22587 22588 const materialProperties = _renderer.properties.get(result); 22589 materialProperties.light = light; 22590 22591 } 22592 22593 return result; 22594 22595 } 22596 22597 function renderObject(object, camera, shadowCamera, light, type) { 22598 22599 if (object.visible === false) return; 22600 22601 const visible = object.layers.test(camera.layers); 22602 22603 if (visible && (object.isMesh || object.isLine || object.isPoints)) { 22604 22605 if ((object.castShadow || (object.receiveShadow && type === VSMShadowMap)) && (!object.frustumCulled || _frustum.intersectsObject(object))) { 22606 22607 object.modelViewMatrix.multiplyMatrices(shadowCamera.matrixWorldInverse, object.matrixWorld); 22608 22609 const geometry = _objects.update(object); 22610 const material = object.material; 22611 22612 if (Array.isArray(material)) { 22613 22614 const groups = geometry.groups; 22615 22616 for (let k = 0, kl = groups.length; k < kl; k++) { 22617 22618 const group = groups[k]; 22619 const groupMaterial = material[group.materialIndex]; 22620 22621 if (groupMaterial && groupMaterial.visible) { 22622 22623 const depthMaterial = getDepthMaterial(object, groupMaterial, light, type); 22624 22625 object.onBeforeShadow(_renderer, object, camera, shadowCamera, geometry, depthMaterial, group); 22626 22627 _renderer.renderBufferDirect(shadowCamera, null, geometry, depthMaterial, object, group); 22628 22629 object.onAfterShadow(_renderer, object, camera, shadowCamera, geometry, depthMaterial, group); 22630 22631 } 22632 22633 } 22634 22635 } else if (material.visible) { 22636 22637 const depthMaterial = getDepthMaterial(object, material, light, type); 22638 22639 object.onBeforeShadow(_renderer, object, camera, shadowCamera, geometry, depthMaterial, null); 22640 22641 _renderer.renderBufferDirect(shadowCamera, null, geometry, depthMaterial, object, null); 22642 22643 object.onAfterShadow(_renderer, object, camera, shadowCamera, geometry, depthMaterial, null); 22644 22645 } 22646 22647 } 22648 22649 } 22650 22651 const children = object.children; 22652 22653 for (let i = 0, l = children.length; i < l; i++) { 22654 22655 renderObject(children[i], camera, shadowCamera, light, type); 22656 22657 } 22658 22659 } 22660 22661 function onMaterialDispose(event) { 22662 22663 const material = event.target; 22664 22665 material.removeEventListener('dispose', onMaterialDispose); 22666 22667 // make sure to remove the unique distance/depth materials used for shadow map rendering 22668 22669 for (const id in _materialCache) { 22670 22671 const cache = _materialCache[id]; 22672 22673 const uuid = event.target.uuid; 22674 22675 if (uuid in cache) { 22676 22677 const shadowMaterial = cache[uuid]; 22678 shadowMaterial.dispose(); 22679 delete cache[uuid]; 22680 22681 } 22682 22683 } 22684 22685 } 22686 22687} 22688 22689function WebGLState(gl, extensions, capabilities) { 22690 22691 const isWebGL2 = capabilities.isWebGL2; 22692 22693 function ColorBuffer() { 22694 22695 let locked = false; 22696 22697 const color = new Vector4(); 22698 let currentColorMask = null; 22699 const currentColorClear = new Vector4(0, 0, 0, 0); 22700 22701 return { 22702 22703 setMask: function (colorMask) { 22704 22705 if (currentColorMask !== colorMask && !locked) { 22706 22707 gl.colorMask(colorMask, colorMask, colorMask, colorMask); 22708 currentColorMask = colorMask; 22709 22710 } 22711 22712 }, 22713 22714 setLocked: function (lock) { 22715 22716 locked = lock; 22717 22718 }, 22719 22720 setClear: function (r, g, b, a, premultipliedAlpha) { 22721 22722 if (premultipliedAlpha === true) { 22723 22724 r *= a; g *= a; b *= a; 22725 22726 } 22727 22728 color.set(r, g, b, a); 22729 22730 if (currentColorClear.equals(color) === false) { 22731 22732 gl.clearColor(r, g, b, a); 22733 currentColorClear.copy(color); 22734 22735 } 22736 22737 }, 22738 22739 reset: function () { 22740 22741 locked = false; 22742 22743 currentColorMask = null; 22744 currentColorClear.set(- 1, 0, 0, 0); // set to invalid state 22745 22746 } 22747 22748 }; 22749 22750 } 22751 22752 function DepthBuffer() { 22753 22754 let locked = false; 22755 22756 let currentDepthMask = null; 22757 let currentDepthFunc = null; 22758 let currentDepthClear = null; 22759 22760 return { 22761 22762 setTest: function (depthTest) { 22763 22764 if (depthTest) { 22765 22766 enable(gl.DEPTH_TEST); 22767 22768 } else { 22769 22770 disable(gl.DEPTH_TEST); 22771 22772 } 22773 22774 }, 22775 22776 setMask: function (depthMask) { 22777 22778 if (currentDepthMask !== depthMask && !locked) { 22779 22780 gl.depthMask(depthMask); 22781 currentDepthMask = depthMask; 22782 22783 } 22784 22785 }, 22786 22787 setFunc: function (depthFunc) { 22788 22789 if (currentDepthFunc !== depthFunc) { 22790 22791 switch (depthFunc) { 22792 22793 case NeverDepth: 22794 22795 gl.depthFunc(gl.NEVER); 22796 break; 22797 22798 case AlwaysDepth: 22799 22800 gl.depthFunc(gl.ALWAYS); 22801 break; 22802 22803 case LessDepth: 22804 22805 gl.depthFunc(gl.LESS); 22806 break; 22807 22808 case LessEqualDepth: 22809 22810 gl.depthFunc(gl.LEQUAL); 22811 break; 22812 22813 case EqualDepth: 22814 22815 gl.depthFunc(gl.EQUAL); 22816 break; 22817 22818 case GreaterEqualDepth: 22819 22820 gl.depthFunc(gl.GEQUAL); 22821 break; 22822 22823 case GreaterDepth: 22824 22825 gl.depthFunc(gl.GREATER); 22826 break; 22827 22828 case NotEqualDepth: 22829 22830 gl.depthFunc(gl.NOTEQUAL); 22831 break; 22832 22833 default: 22834 22835 gl.depthFunc(gl.LEQUAL); 22836 22837 } 22838 22839 currentDepthFunc = depthFunc; 22840 22841 } 22842 22843 }, 22844 22845 setLocked: function (lock) { 22846 22847 locked = lock; 22848 22849 }, 22850 22851 setClear: function (depth) { 22852 22853 if (currentDepthClear !== depth) { 22854 22855 gl.clearDepth(depth); 22856 currentDepthClear = depth; 22857 22858 } 22859 22860 }, 22861 22862 reset: function () { 22863 22864 locked = false; 22865 22866 currentDepthMask = null; 22867 currentDepthFunc = null; 22868 currentDepthClear = null; 22869 22870 } 22871 22872 }; 22873 22874 } 22875 22876 function StencilBuffer() { 22877 22878 let locked = false; 22879 22880 let currentStencilMask = null; 22881 let currentStencilFunc = null; 22882 let currentStencilRef = null; 22883 let currentStencilFuncMask = null; 22884 let currentStencilFail = null; 22885 let currentStencilZFail = null; 22886 let currentStencilZPass = null; 22887 let currentStencilClear = null; 22888 22889 return { 22890 22891 setTest: function (stencilTest) { 22892 22893 if (!locked) { 22894 22895 if (stencilTest) { 22896 22897 enable(gl.STENCIL_TEST); 22898 22899 } else { 22900 22901 disable(gl.STENCIL_TEST); 22902 22903 } 22904 22905 } 22906 22907 }, 22908 22909 setMask: function (stencilMask) { 22910 22911 if (currentStencilMask !== stencilMask && !locked) { 22912 22913 gl.stencilMask(stencilMask); 22914 currentStencilMask = stencilMask; 22915 22916 } 22917 22918 }, 22919 22920 setFunc: function (stencilFunc, stencilRef, stencilMask) { 22921 22922 if (currentStencilFunc !== stencilFunc || 22923 currentStencilRef !== stencilRef || 22924 currentStencilFuncMask !== stencilMask) { 22925 22926 gl.stencilFunc(stencilFunc, stencilRef, stencilMask); 22927 22928 currentStencilFunc = stencilFunc; 22929 currentStencilRef = stencilRef; 22930 currentStencilFuncMask = stencilMask; 22931 22932 } 22933 22934 }, 22935 22936 setOp: function (stencilFail, stencilZFail, stencilZPass) { 22937 22938 if (currentStencilFail !== stencilFail || 22939 currentStencilZFail !== stencilZFail || 22940 currentStencilZPass !== stencilZPass) { 22941 22942 gl.stencilOp(stencilFail, stencilZFail, stencilZPass); 22943 22944 currentStencilFail = stencilFail; 22945 currentStencilZFail = stencilZFail; 22946 currentStencilZPass = stencilZPass; 22947 22948 } 22949 22950 }, 22951 22952 setLocked: function (lock) { 22953 22954 locked = lock; 22955 22956 }, 22957 22958 setClear: function (stencil) { 22959 22960 if (currentStencilClear !== stencil) { 22961 22962 gl.clearStencil(stencil); 22963 currentStencilClear = stencil; 22964 22965 } 22966 22967 }, 22968 22969 reset: function () { 22970 22971 locked = false; 22972 22973 currentStencilMask = null; 22974 currentStencilFunc = null; 22975 currentStencilRef = null; 22976 currentStencilFuncMask = null; 22977 currentStencilFail = null; 22978 currentStencilZFail = null; 22979 currentStencilZPass = null; 22980 currentStencilClear = null; 22981 22982 } 22983 22984 }; 22985 22986 } 22987 22988 // 22989 22990 const colorBuffer = new ColorBuffer(); 22991 const depthBuffer = new DepthBuffer(); 22992 const stencilBuffer = new StencilBuffer(); 22993 22994 const uboBindings = new WeakMap(); 22995 const uboProgramMap = new WeakMap(); 22996 22997 let enabledCapabilities = {}; 22998 22999 let currentBoundFramebuffers = {}; 23000 let currentDrawbuffers = new WeakMap(); 23001 let defaultDrawbuffers = []; 23002 23003 let currentProgram = null; 23004 23005 let currentBlendingEnabled = false; 23006 let currentBlending = null; 23007 let currentBlendEquation = null; 23008 let currentBlendSrc = null; 23009 let currentBlendDst = null; 23010 let currentBlendEquationAlpha = null; 23011 let currentBlendSrcAlpha = null; 23012 let currentBlendDstAlpha = null; 23013 let currentBlendColor = new Color(0, 0, 0); 23014 let currentBlendAlpha = 0; 23015 let currentPremultipledAlpha = false; 23016 23017 let currentFlipSided = null; 23018 let currentCullFace = null; 23019 23020 let currentLineWidth = null; 23021 23022 let currentPolygonOffsetFactor = null; 23023 let currentPolygonOffsetUnits = null; 23024 23025 const maxTextures = gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS); 23026 23027 let lineWidthAvailable = false; 23028 let version = 0; 23029 const glVersion = gl.getParameter(gl.VERSION); 23030 23031 if (glVersion.indexOf('WebGL') !== - 1) { 23032 23033 version = parseFloat(/^WebGL (\d)/.exec(glVersion)[1]); 23034 lineWidthAvailable = (version >= 1.0); 23035 23036 } else if (glVersion.indexOf('OpenGL ES') !== - 1) { 23037 23038 version = parseFloat(/^OpenGL ES (\d)/.exec(glVersion)[1]); 23039 lineWidthAvailable = (version >= 2.0); 23040 23041 } 23042 23043 let currentTextureSlot = null; 23044 let currentBoundTextures = {}; 23045 23046 const scissorParam = gl.getParameter(gl.SCISSOR_BOX); 23047 const viewportParam = gl.getParameter(gl.VIEWPORT); 23048 23049 const currentScissor = new Vector4().fromArray(scissorParam); 23050 const currentViewport = new Vector4().fromArray(viewportParam); 23051 23052 function createTexture(type, target, count, dimensions) { 23053 23054 const data = new Uint8Array(4); // 4 is required to match default unpack alignment of 4. 23055 const texture = gl.createTexture(); 23056 23057 gl.bindTexture(type, texture); 23058 gl.texParameteri(type, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 23059 gl.texParameteri(type, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 23060 23061 for (let i = 0; i < count; i++) { 23062 23063 if (isWebGL2 && (type === gl.TEXTURE_3D || type === gl.TEXTURE_2D_ARRAY)) { 23064 23065 gl.texImage3D(target, 0, gl.RGBA, 1, 1, dimensions, 0, gl.RGBA, gl.UNSIGNED_BYTE, data); 23066 23067 } else { 23068 23069 gl.texImage2D(target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data); 23070 23071 } 23072 23073 } 23074 23075 return texture; 23076 23077 } 23078 23079 const emptyTextures = {}; 23080 emptyTextures[gl.TEXTURE_2D] = createTexture(gl.TEXTURE_2D, gl.TEXTURE_2D, 1); 23081 emptyTextures[gl.TEXTURE_CUBE_MAP] = createTexture(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6); 23082 23083 if (isWebGL2) { 23084 23085 emptyTextures[gl.TEXTURE_2D_ARRAY] = createTexture(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_2D_ARRAY, 1, 1); 23086 emptyTextures[gl.TEXTURE_3D] = createTexture(gl.TEXTURE_3D, gl.TEXTURE_3D, 1, 1); 23087 23088 } 23089 23090 // init 23091 23092 colorBuffer.setClear(0, 0, 0, 1); 23093 depthBuffer.setClear(1); 23094 stencilBuffer.setClear(0); 23095 23096 enable(gl.DEPTH_TEST); 23097 depthBuffer.setFunc(LessEqualDepth); 23098 23099 setFlipSided(false); 23100 setCullFace(CullFaceBack); 23101 enable(gl.CULL_FACE); 23102 23103 setBlending(NoBlending); 23104 23105 // 23106 23107 function enable(id) { 23108 23109 if (enabledCapabilities[id] !== true) { 23110 23111 gl.enable(id); 23112 enabledCapabilities[id] = true; 23113 23114 } 23115 23116 } 23117 23118 function disable(id) { 23119 23120 if (enabledCapabilities[id] !== false) { 23121 23122 gl.disable(id); 23123 enabledCapabilities[id] = false; 23124 23125 } 23126 23127 } 23128 23129 function bindFramebuffer(target, framebuffer) { 23130 23131 if (currentBoundFramebuffers[target] !== framebuffer) { 23132 23133 gl.bindFramebuffer(target, framebuffer); 23134 23135 currentBoundFramebuffers[target] = framebuffer; 23136 23137 if (isWebGL2) { 23138 23139 // gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER 23140 23141 if (target === gl.DRAW_FRAMEBUFFER) { 23142 23143 currentBoundFramebuffers[gl.FRAMEBUFFER] = framebuffer; 23144 23145 } 23146 23147 if (target === gl.FRAMEBUFFER) { 23148 23149 currentBoundFramebuffers[gl.DRAW_FRAMEBUFFER] = framebuffer; 23150 23151 } 23152 23153 } 23154 23155 return true; 23156 23157 } 23158 23159 return false; 23160 23161 } 23162 23163 function drawBuffers(renderTarget, framebuffer) { 23164 23165 let drawBuffers = defaultDrawbuffers; 23166 23167 let needsUpdate = false; 23168 23169 if (renderTarget) { 23170 23171 drawBuffers = currentDrawbuffers.get(framebuffer); 23172 23173 if (drawBuffers === undefined) { 23174 23175 drawBuffers = []; 23176 currentDrawbuffers.set(framebuffer, drawBuffers); 23177 23178 } 23179 23180 if (renderTarget.isWebGLMultipleRenderTargets) { 23181 23182 const textures = renderTarget.texture; 23183 23184 if (drawBuffers.length !== textures.length || drawBuffers[0] !== gl.COLOR_ATTACHMENT0) { 23185 23186 for (let i = 0, il = textures.length; i < il; i++) { 23187 23188 drawBuffers[i] = gl.COLOR_ATTACHMENT0 + i; 23189 23190 } 23191 23192 drawBuffers.length = textures.length; 23193 23194 needsUpdate = true; 23195 23196 } 23197 23198 } else { 23199 23200 if (drawBuffers[0] !== gl.COLOR_ATTACHMENT0) { 23201 23202 drawBuffers[0] = gl.COLOR_ATTACHMENT0; 23203 23204 needsUpdate = true; 23205 23206 } 23207 23208 } 23209 23210 } else { 23211 23212 if (drawBuffers[0] !== gl.BACK) { 23213 23214 drawBuffers[0] = gl.BACK; 23215 23216 needsUpdate = true; 23217 23218 } 23219 23220 } 23221 23222 if (needsUpdate) { 23223 23224 if (capabilities.isWebGL2) { 23225 23226 gl.drawBuffers(drawBuffers); 23227 23228 } else { 23229 23230 extensions.get('WEBGL_draw_buffers').drawBuffersWEBGL(drawBuffers); 23231 23232 } 23233 23234 } 23235 23236 23237 } 23238 23239 function useProgram(program) { 23240 23241 if (currentProgram !== program) { 23242 23243 gl.useProgram(program); 23244 23245 currentProgram = program; 23246 23247 return true; 23248 23249 } 23250 23251 return false; 23252 23253 } 23254 23255 const equationToGL = { 23256 [AddEquation]: gl.FUNC_ADD, 23257 [SubtractEquation]: gl.FUNC_SUBTRACT, 23258 [ReverseSubtractEquation]: gl.FUNC_REVERSE_SUBTRACT 23259 }; 23260 23261 if (isWebGL2) { 23262 23263 equationToGL[MinEquation] = gl.MIN; 23264 equationToGL[MaxEquation] = gl.MAX; 23265 23266 } else { 23267 23268 const extension = extensions.get('EXT_blend_minmax'); 23269 23270 if (extension !== null) { 23271 23272 equationToGL[MinEquation] = extension.MIN_EXT; 23273 equationToGL[MaxEquation] = extension.MAX_EXT; 23274 23275 } 23276 23277 } 23278 23279 const factorToGL = { 23280 [ZeroFactor]: gl.ZERO, 23281 [OneFactor]: gl.ONE, 23282 [SrcColorFactor]: gl.SRC_COLOR, 23283 [SrcAlphaFactor]: gl.SRC_ALPHA, 23284 [SrcAlphaSaturateFactor]: gl.SRC_ALPHA_SATURATE, 23285 [DstColorFactor]: gl.DST_COLOR, 23286 [DstAlphaFactor]: gl.DST_ALPHA, 23287 [OneMinusSrcColorFactor]: gl.ONE_MINUS_SRC_COLOR, 23288 [OneMinusSrcAlphaFactor]: gl.ONE_MINUS_SRC_ALPHA, 23289 [OneMinusDstColorFactor]: gl.ONE_MINUS_DST_COLOR, 23290 [OneMinusDstAlphaFactor]: gl.ONE_MINUS_DST_ALPHA, 23291 [ConstantColorFactor]: gl.CONSTANT_COLOR, 23292 [OneMinusConstantColorFactor]: gl.ONE_MINUS_CONSTANT_COLOR, 23293 [ConstantAlphaFactor]: gl.CONSTANT_ALPHA, 23294 [OneMinusConstantAlphaFactor]: gl.ONE_MINUS_CONSTANT_ALPHA 23295 }; 23296 23297 function setBlending(blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, blendColor, blendAlpha, premultipliedAlpha) { 23298 23299 if (blending === NoBlending) { 23300 23301 if (currentBlendingEnabled === true) { 23302 23303 disable(gl.BLEND); 23304 currentBlendingEnabled = false; 23305 23306 } 23307 23308 return; 23309 23310 } 23311 23312 if (currentBlendingEnabled === false) { 23313 23314 enable(gl.BLEND); 23315 currentBlendingEnabled = true; 23316 23317 } 23318 23319 if (blending !== CustomBlending) { 23320 23321 if (blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha) { 23322 23323 if (currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation) { 23324 23325 gl.blendEquation(gl.FUNC_ADD); 23326 23327 currentBlendEquation = AddEquation; 23328 currentBlendEquationAlpha = AddEquation; 23329 23330 } 23331 23332 if (premultipliedAlpha) { 23333 23334 switch (blending) { 23335 23336 case NormalBlending: 23337 gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); 23338 break; 23339 23340 case AdditiveBlending: 23341 gl.blendFunc(gl.ONE, gl.ONE); 23342 break; 23343 23344 case SubtractiveBlending: 23345 gl.blendFuncSeparate(gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE); 23346 break; 23347 23348 case MultiplyBlending: 23349 gl.blendFuncSeparate(gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA); 23350 break; 23351 23352 default: 23353 console.error('THREE.WebGLState: Invalid blending: ', blending); 23354 break; 23355 23356 } 23357 23358 } else { 23359 23360 switch (blending) { 23361 23362 case NormalBlending: 23363 gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); 23364 break; 23365 23366 case AdditiveBlending: 23367 gl.blendFunc(gl.SRC_ALPHA, gl.ONE); 23368 break; 23369 23370 case SubtractiveBlending: 23371 gl.blendFuncSeparate(gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE); 23372 break; 23373 23374 case MultiplyBlending: 23375 gl.blendFunc(gl.ZERO, gl.SRC_COLOR); 23376 break; 23377 23378 default: 23379 console.error('THREE.WebGLState: Invalid blending: ', blending); 23380 break; 23381 23382 } 23383 23384 } 23385 23386 currentBlendSrc = null; 23387 currentBlendDst = null; 23388 currentBlendSrcAlpha = null; 23389 currentBlendDstAlpha = null; 23390 currentBlendColor.set(0, 0, 0); 23391 currentBlendAlpha = 0; 23392 23393 currentBlending = blending; 23394 currentPremultipledAlpha = premultipliedAlpha; 23395 23396 } 23397 23398 return; 23399 23400 } 23401 23402 // custom blending 23403 23404 blendEquationAlpha = blendEquationAlpha || blendEquation; 23405 blendSrcAlpha = blendSrcAlpha || blendSrc; 23406 blendDstAlpha = blendDstAlpha || blendDst; 23407 23408 if (blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha) { 23409 23410 gl.blendEquationSeparate(equationToGL[blendEquation], equationToGL[blendEquationAlpha]); 23411 23412 currentBlendEquation = blendEquation; 23413 currentBlendEquationAlpha = blendEquationAlpha; 23414 23415 } 23416 23417 if (blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha) { 23418 23419 gl.blendFuncSeparate(factorToGL[blendSrc], factorToGL[blendDst], factorToGL[blendSrcAlpha], factorToGL[blendDstAlpha]); 23420 23421 currentBlendSrc = blendSrc; 23422 currentBlendDst = blendDst; 23423 currentBlendSrcAlpha = blendSrcAlpha; 23424 currentBlendDstAlpha = blendDstAlpha; 23425 23426 } 23427 23428 if (blendColor.equals(currentBlendColor) === false || blendAlpha !== currentBlendAlpha) { 23429 23430 gl.blendColor(blendColor.r, blendColor.g, blendColor.b, blendAlpha); 23431 23432 currentBlendColor.copy(blendColor); 23433 currentBlendAlpha = blendAlpha; 23434 23435 } 23436 23437 currentBlending = blending; 23438 currentPremultipledAlpha = false; 23439 23440 } 23441 23442 function setMaterial(material, frontFaceCW) { 23443 23444 material.side === DoubleSide 23445 ? disable(gl.CULL_FACE) 23446 : enable(gl.CULL_FACE); 23447 23448 let flipSided = (material.side === BackSide); 23449 if (frontFaceCW) flipSided = !flipSided; 23450 23451 setFlipSided(flipSided); 23452 23453 (material.blending === NormalBlending && material.transparent === false) 23454 ? setBlending(NoBlending) 23455 : setBlending(material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha); 23456 23457 depthBuffer.setFunc(material.depthFunc); 23458 depthBuffer.setTest(material.depthTest); 23459 depthBuffer.setMask(material.depthWrite); 23460 colorBuffer.setMask(material.colorWrite); 23461 23462 const stencilWrite = material.stencilWrite; 23463 stencilBuffer.setTest(stencilWrite); 23464 if (stencilWrite) { 23465 23466 stencilBuffer.setMask(material.stencilWriteMask); 23467 stencilBuffer.setFunc(material.stencilFunc, material.stencilRef, material.stencilFuncMask); 23468 stencilBuffer.setOp(material.stencilFail, material.stencilZFail, material.stencilZPass); 23469 23470 } 23471 23472 setPolygonOffset(material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits); 23473 23474 material.alphaToCoverage === true 23475 ? enable(gl.SAMPLE_ALPHA_TO_COVERAGE) 23476 : disable(gl.SAMPLE_ALPHA_TO_COVERAGE); 23477 23478 } 23479 23480 // 23481 23482 function setFlipSided(flipSided) { 23483 23484 if (currentFlipSided !== flipSided) { 23485 23486 if (flipSided) { 23487 23488 gl.frontFace(gl.CW); 23489 23490 } else { 23491 23492 gl.frontFace(gl.CCW); 23493 23494 } 23495 23496 currentFlipSided = flipSided; 23497 23498 } 23499 23500 } 23501 23502 function setCullFace(cullFace) { 23503 23504 if (cullFace !== CullFaceNone) { 23505 23506 enable(gl.CULL_FACE); 23507 23508 if (cullFace !== currentCullFace) { 23509 23510 if (cullFace === CullFaceBack) { 23511 23512 gl.cullFace(gl.BACK); 23513 23514 } else if (cullFace === CullFaceFront) { 23515 23516 gl.cullFace(gl.FRONT); 23517 23518 } else { 23519 23520 gl.cullFace(gl.FRONT_AND_BACK); 23521 23522 } 23523 23524 } 23525 23526 } else { 23527 23528 disable(gl.CULL_FACE); 23529 23530 } 23531 23532 currentCullFace = cullFace; 23533 23534 } 23535 23536 function setLineWidth(width) { 23537 23538 if (width !== currentLineWidth) { 23539 23540 if (lineWidthAvailable) gl.lineWidth(width); 23541 23542 currentLineWidth = width; 23543 23544 } 23545 23546 } 23547 23548 function setPolygonOffset(polygonOffset, factor, units) { 23549 23550 if (polygonOffset) { 23551 23552 enable(gl.POLYGON_OFFSET_FILL); 23553 23554 if (currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units) { 23555 23556 gl.polygonOffset(factor, units); 23557 23558 currentPolygonOffsetFactor = factor; 23559 currentPolygonOffsetUnits = units; 23560 23561 } 23562 23563 } else { 23564 23565 disable(gl.POLYGON_OFFSET_FILL); 23566 23567 } 23568 23569 } 23570 23571 function setScissorTest(scissorTest) { 23572 23573 if (scissorTest) { 23574 23575 enable(gl.SCISSOR_TEST); 23576 23577 } else { 23578 23579 disable(gl.SCISSOR_TEST); 23580 23581 } 23582 23583 } 23584 23585 // texture 23586 23587 function activeTexture(webglSlot) { 23588 23589 if (webglSlot === undefined) webglSlot = gl.TEXTURE0 + maxTextures - 1; 23590 23591 if (currentTextureSlot !== webglSlot) { 23592 23593 gl.activeTexture(webglSlot); 23594 currentTextureSlot = webglSlot; 23595 23596 } 23597 23598 } 23599 23600 function bindTexture(webglType, webglTexture, webglSlot) { 23601 23602 if (webglSlot === undefined) { 23603 23604 if (currentTextureSlot === null) { 23605 23606 webglSlot = gl.TEXTURE0 + maxTextures - 1; 23607 23608 } else { 23609 23610 webglSlot = currentTextureSlot; 23611 23612 } 23613 23614 } 23615 23616 let boundTexture = currentBoundTextures[webglSlot]; 23617 23618 if (boundTexture === undefined) { 23619 23620 boundTexture = { type: undefined, texture: undefined }; 23621 currentBoundTextures[webglSlot] = boundTexture; 23622 23623 } 23624 23625 if (boundTexture.type !== webglType || boundTexture.texture !== webglTexture) { 23626 23627 if (currentTextureSlot !== webglSlot) { 23628 23629 gl.activeTexture(webglSlot); 23630 currentTextureSlot = webglSlot; 23631 23632 } 23633 23634 gl.bindTexture(webglType, webglTexture || emptyTextures[webglType]); 23635 23636 boundTexture.type = webglType; 23637 boundTexture.texture = webglTexture; 23638 23639 } 23640 23641 } 23642 23643 function unbindTexture() { 23644 23645 const boundTexture = currentBoundTextures[currentTextureSlot]; 23646 23647 if (boundTexture !== undefined && boundTexture.type !== undefined) { 23648 23649 gl.bindTexture(boundTexture.type, null); 23650 23651 boundTexture.type = undefined; 23652 boundTexture.texture = undefined; 23653 23654 } 23655 23656 } 23657 23658 function compressedTexImage2D() { 23659 23660 try { 23661 23662 gl.compressedTexImage2D.apply(gl, arguments); 23663 23664 } catch (error) { 23665 23666 console.error('THREE.WebGLState:', error); 23667 23668 } 23669 23670 } 23671 23672 function compressedTexImage3D() { 23673 23674 try { 23675 23676 gl.compressedTexImage3D.apply(gl, arguments); 23677 23678 } catch (error) { 23679 23680 console.error('THREE.WebGLState:', error); 23681 23682 } 23683 23684 } 23685 23686 function texSubImage2D() { 23687 23688 try { 23689 23690 gl.texSubImage2D.apply(gl, arguments); 23691 23692 } catch (error) { 23693 23694 console.error('THREE.WebGLState:', error); 23695 23696 } 23697 23698 } 23699 23700 function texSubImage3D() { 23701 23702 try { 23703 23704 gl.texSubImage3D.apply(gl, arguments); 23705 23706 } catch (error) { 23707 23708 console.error('THREE.WebGLState:', error); 23709 23710 } 23711 23712 } 23713 23714 function compressedTexSubImage2D() { 23715 23716 try { 23717 23718 gl.compressedTexSubImage2D.apply(gl, arguments); 23719 23720 } catch (error) { 23721 23722 console.error('THREE.WebGLState:', error); 23723 23724 } 23725 23726 } 23727 23728 function compressedTexSubImage3D() { 23729 23730 try { 23731 23732 gl.compressedTexSubImage3D.apply(gl, arguments); 23733 23734 } catch (error) { 23735 23736 console.error('THREE.WebGLState:', error); 23737 23738 } 23739 23740 } 23741 23742 function texStorage2D() { 23743 23744 try { 23745 23746 gl.texStorage2D.apply(gl, arguments); 23747 23748 } catch (error) { 23749 23750 console.error('THREE.WebGLState:', error); 23751 23752 } 23753 23754 } 23755 23756 function texStorage3D() { 23757 23758 try { 23759 23760 gl.texStorage3D.apply(gl, arguments); 23761 23762 } catch (error) { 23763 23764 console.error('THREE.WebGLState:', error); 23765 23766 } 23767 23768 } 23769 23770 function texImage2D() { 23771 23772 try { 23773 23774 gl.texImage2D.apply(gl, arguments); 23775 23776 } catch (error) { 23777 23778 console.error('THREE.WebGLState:', error); 23779 23780 } 23781 23782 } 23783 23784 function texImage3D() { 23785 23786 try { 23787 23788 gl.texImage3D.apply(gl, arguments); 23789 23790 } catch (error) { 23791 23792 console.error('THREE.WebGLState:', error); 23793 23794 } 23795 23796 } 23797 23798 // 23799 23800 function scissor(scissor) { 23801 23802 if (currentScissor.equals(scissor) === false) { 23803 23804 gl.scissor(scissor.x, scissor.y, scissor.z, scissor.w); 23805 currentScissor.copy(scissor); 23806 23807 } 23808 23809 } 23810 23811 function viewport(viewport) { 23812 23813 if (currentViewport.equals(viewport) === false) { 23814 23815 gl.viewport(viewport.x, viewport.y, viewport.z, viewport.w); 23816 currentViewport.copy(viewport); 23817 23818 } 23819 23820 } 23821 23822 function updateUBOMapping(uniformsGroup, program) { 23823 23824 let mapping = uboProgramMap.get(program); 23825 23826 if (mapping === undefined) { 23827 23828 mapping = new WeakMap(); 23829 23830 uboProgramMap.set(program, mapping); 23831 23832 } 23833 23834 let blockIndex = mapping.get(uniformsGroup); 23835 23836 if (blockIndex === undefined) { 23837 23838 blockIndex = gl.getUniformBlockIndex(program, uniformsGroup.name); 23839 23840 mapping.set(uniformsGroup, blockIndex); 23841 23842 } 23843 23844 } 23845 23846 function uniformBlockBinding(uniformsGroup, program) { 23847 23848 const mapping = uboProgramMap.get(program); 23849 const blockIndex = mapping.get(uniformsGroup); 23850 23851 if (uboBindings.get(program) !== blockIndex) { 23852 23853 // bind shader specific block index to global block point 23854 gl.uniformBlockBinding(program, blockIndex, uniformsGroup.__bindingPointIndex); 23855 23856 uboBindings.set(program, blockIndex); 23857 23858 } 23859 23860 } 23861 23862 // 23863 23864 function reset() { 23865 23866 // reset state 23867 23868 gl.disable(gl.BLEND); 23869 gl.disable(gl.CULL_FACE); 23870 gl.disable(gl.DEPTH_TEST); 23871 gl.disable(gl.POLYGON_OFFSET_FILL); 23872 gl.disable(gl.SCISSOR_TEST); 23873 gl.disable(gl.STENCIL_TEST); 23874 gl.disable(gl.SAMPLE_ALPHA_TO_COVERAGE); 23875 23876 gl.blendEquation(gl.FUNC_ADD); 23877 gl.blendFunc(gl.ONE, gl.ZERO); 23878 gl.blendFuncSeparate(gl.ONE, gl.ZERO, gl.ONE, gl.ZERO); 23879 gl.blendColor(0, 0, 0, 0); 23880 23881 gl.colorMask(true, true, true, true); 23882 gl.clearColor(0, 0, 0, 0); 23883 23884 gl.depthMask(true); 23885 gl.depthFunc(gl.LESS); 23886 gl.clearDepth(1); 23887 23888 gl.stencilMask(0xffffffff); 23889 gl.stencilFunc(gl.ALWAYS, 0, 0xffffffff); 23890 gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); 23891 gl.clearStencil(0); 23892 23893 gl.cullFace(gl.BACK); 23894 gl.frontFace(gl.CCW); 23895 23896 gl.polygonOffset(0, 0); 23897 23898 gl.activeTexture(gl.TEXTURE0); 23899 23900 gl.bindFramebuffer(gl.FRAMEBUFFER, null); 23901 23902 if (isWebGL2 === true) { 23903 23904 gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); 23905 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); 23906 23907 } 23908 23909 gl.useProgram(null); 23910 23911 gl.lineWidth(1); 23912 23913 gl.scissor(0, 0, gl.canvas.width, gl.canvas.height); 23914 gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); 23915 23916 // reset internals 23917 23918 enabledCapabilities = {}; 23919 23920 currentTextureSlot = null; 23921 currentBoundTextures = {}; 23922 23923 currentBoundFramebuffers = {}; 23924 currentDrawbuffers = new WeakMap(); 23925 defaultDrawbuffers = []; 23926 23927 currentProgram = null; 23928 23929 currentBlendingEnabled = false; 23930 currentBlending = null; 23931 currentBlendEquation = null; 23932 currentBlendSrc = null; 23933 currentBlendDst = null; 23934 currentBlendEquationAlpha = null; 23935 currentBlendSrcAlpha = null; 23936 currentBlendDstAlpha = null; 23937 currentBlendColor = new Color(0, 0, 0); 23938 currentBlendAlpha = 0; 23939 currentPremultipledAlpha = false; 23940 23941 currentFlipSided = null; 23942 currentCullFace = null; 23943 23944 currentLineWidth = null; 23945 23946 currentPolygonOffsetFactor = null; 23947 currentPolygonOffsetUnits = null; 23948 23949 currentScissor.set(0, 0, gl.canvas.width, gl.canvas.height); 23950 currentViewport.set(0, 0, gl.canvas.width, gl.canvas.height); 23951 23952 colorBuffer.reset(); 23953 depthBuffer.reset(); 23954 stencilBuffer.reset(); 23955 23956 } 23957 23958 return { 23959 23960 buffers: { 23961 color: colorBuffer, 23962 depth: depthBuffer, 23963 stencil: stencilBuffer 23964 }, 23965 23966 enable: enable, 23967 disable: disable, 23968 23969 bindFramebuffer: bindFramebuffer, 23970 drawBuffers: drawBuffers, 23971 23972 useProgram: useProgram, 23973 23974 setBlending: setBlending, 23975 setMaterial: setMaterial, 23976 23977 setFlipSided: setFlipSided, 23978 setCullFace: setCullFace, 23979 23980 setLineWidth: setLineWidth, 23981 setPolygonOffset: setPolygonOffset, 23982 23983 setScissorTest: setScissorTest, 23984 23985 activeTexture: activeTexture, 23986 bindTexture: bindTexture, 23987 unbindTexture: unbindTexture, 23988 compressedTexImage2D: compressedTexImage2D, 23989 compressedTexImage3D: compressedTexImage3D, 23990 texImage2D: texImage2D, 23991 texImage3D: texImage3D, 23992 23993 updateUBOMapping: updateUBOMapping, 23994 uniformBlockBinding: uniformBlockBinding, 23995 23996 texStorage2D: texStorage2D, 23997 texStorage3D: texStorage3D, 23998 texSubImage2D: texSubImage2D, 23999 texSubImage3D: texSubImage3D, 24000 compressedTexSubImage2D: compressedTexSubImage2D, 24001 compressedTexSubImage3D: compressedTexSubImage3D, 24002 24003 scissor: scissor, 24004 viewport: viewport, 24005 24006 reset: reset 24007 24008 }; 24009 24010} 24011 24012function WebGLTextures(_gl, extensions, state, properties, capabilities, utils, info) { 24013 24014 const isWebGL2 = capabilities.isWebGL2; 24015 const multisampledRTTExt = extensions.has('WEBGL_multisampled_render_to_texture') ? extensions.get('WEBGL_multisampled_render_to_texture') : null; 24016 const supportsInvalidateFramebuffer = typeof navigator === 'undefined' ? false : /OculusBrowser/g.test(navigator.userAgent); 24017 24018 const _videoTextures = new WeakMap(); 24019 let _canvas; 24020 24021 const _sources = new WeakMap(); // maps WebglTexture objects to instances of Source 24022 24023 // cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas, 24024 // also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")! 24025 // Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d). 24026 24027 let useOffscreenCanvas = false; 24028 24029 try { 24030 24031 useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined' 24032 // eslint-disable-next-line compat/compat 24033 && (new OffscreenCanvas(1, 1).getContext('2d')) !== null; 24034 24035 } catch (err) { 24036 24037 // Ignore any errors 24038 24039 } 24040 24041 function createCanvas(width, height) { 24042 24043 // Use OffscreenCanvas when available. Specially needed in web workers 24044 24045 return useOffscreenCanvas ? 24046 // eslint-disable-next-line compat/compat 24047 new OffscreenCanvas(width, height) : createElementNS('canvas'); 24048 24049 } 24050 24051 function resizeImage(image, needsPowerOfTwo, needsNewCanvas, maxSize) { 24052 24053 let scale = 1; 24054 24055 // handle case if texture exceeds max size 24056 24057 if (image.width > maxSize || image.height > maxSize) { 24058 24059 scale = maxSize / Math.max(image.width, image.height); 24060 24061 } 24062 24063 // only perform resize if necessary 24064 24065 if (scale < 1 || needsPowerOfTwo === true) { 24066 24067 // only perform resize for certain image types 24068 24069 if ((typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement) || 24070 (typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement) || 24071 (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap)) { 24072 24073 const floor = needsPowerOfTwo ? floorPowerOfTwo : Math.floor; 24074 24075 const width = floor(scale * image.width); 24076 const height = floor(scale * image.height); 24077 24078 if (_canvas === undefined) _canvas = createCanvas(width, height); 24079 24080 // cube textures can't reuse the same canvas 24081 24082 const canvas = needsNewCanvas ? createCanvas(width, height) : _canvas; 24083 24084 canvas.width = width; 24085 canvas.height = height; 24086 24087 const context = canvas.getContext('2d'); 24088 context.drawImage(image, 0, 0, width, height); 24089 24090 console.warn('THREE.WebGLRenderer: Texture has been resized from (' + image.width + 'x' + image.height + ') to (' + width + 'x' + height + ').'); 24091 24092 return canvas; 24093 24094 } else { 24095 24096 if ('data' in image) { 24097 24098 console.warn('THREE.WebGLRenderer: Image in DataTexture is too big (' + image.width + 'x' + image.height + ').'); 24099 24100 } 24101 24102 return image; 24103 24104 } 24105 24106 } 24107 24108 return image; 24109 24110 } 24111 24112 function isPowerOfTwo$1(image) { 24113 24114 return isPowerOfTwo(image.width) && isPowerOfTwo(image.height); 24115 24116 } 24117 24118 function textureNeedsPowerOfTwo(texture) { 24119 24120 if (isWebGL2) return false; 24121 24122 return (texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping) || 24123 (texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter); 24124 24125 } 24126 24127 function textureNeedsGenerateMipmaps(texture, supportsMips) { 24128 24129 return texture.generateMipmaps && supportsMips && 24130 texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter; 24131 24132 } 24133 24134 function generateMipmap(target) { 24135 24136 _gl.generateMipmap(target); 24137 24138 } 24139 24140 function getInternalFormat(internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false) { 24141 24142 if (isWebGL2 === false) return glFormat; 24143 24144 if (internalFormatName !== null) { 24145 24146 if (_gl[internalFormatName] !== undefined) return _gl[internalFormatName]; 24147 24148 console.warn('THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\''); 24149 24150 } 24151 24152 let internalFormat = glFormat; 24153 24154 if (glFormat === _gl.RED) { 24155 24156 if (glType === _gl.FLOAT) internalFormat = _gl.R32F; 24157 if (glType === _gl.HALF_FLOAT) internalFormat = _gl.R16F; 24158 if (glType === _gl.UNSIGNED_BYTE) internalFormat = _gl.R8; 24159 24160 } 24161 24162 if (glFormat === _gl.RED_INTEGER) { 24163 24164 if (glType === _gl.UNSIGNED_BYTE) internalFormat = _gl.R8UI; 24165 if (glType === _gl.UNSIGNED_SHORT) internalFormat = _gl.R16UI; 24166 if (glType === _gl.UNSIGNED_INT) internalFormat = _gl.R32UI; 24167 if (glType === _gl.BYTE) internalFormat = _gl.R8I; 24168 if (glType === _gl.SHORT) internalFormat = _gl.R16I; 24169 if (glType === _gl.INT) internalFormat = _gl.R32I; 24170 24171 } 24172 24173 if (glFormat === _gl.RG) { 24174 24175 if (glType === _gl.FLOAT) internalFormat = _gl.RG32F; 24176 if (glType === _gl.HALF_FLOAT) internalFormat = _gl.RG16F; 24177 if (glType === _gl.UNSIGNED_BYTE) internalFormat = _gl.RG8; 24178 24179 } 24180 24181 if (glFormat === _gl.RGBA) { 24182 24183 const transfer = forceLinearTransfer ? LinearTransfer : ColorManagement.getTransfer(colorSpace); 24184 24185 if (glType === _gl.FLOAT) internalFormat = _gl.RGBA32F; 24186 if (glType === _gl.HALF_FLOAT) internalFormat = _gl.RGBA16F; 24187 if (glType === _gl.UNSIGNED_BYTE) internalFormat = (transfer === SRGBTransfer) ? _gl.SRGB8_ALPHA8 : _gl.RGBA8; 24188 if (glType === _gl.UNSIGNED_SHORT_4_4_4_4) internalFormat = _gl.RGBA4; 24189 if (glType === _gl.UNSIGNED_SHORT_5_5_5_1) internalFormat = _gl.RGB5_A1; 24190 24191 } 24192 24193 if (internalFormat === _gl.R16F || internalFormat === _gl.R32F || 24194 internalFormat === _gl.RG16F || internalFormat === _gl.RG32F || 24195 internalFormat === _gl.RGBA16F || internalFormat === _gl.RGBA32F) { 24196 24197 extensions.get('EXT_color_buffer_float'); 24198 24199 } 24200 24201 return internalFormat; 24202 24203 } 24204 24205 function getMipLevels(texture, image, supportsMips) { 24206 24207 if (textureNeedsGenerateMipmaps(texture, supportsMips) === true || (texture.isFramebufferTexture && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter)) { 24208 24209 return Math.log2(Math.max(image.width, image.height)) + 1; 24210 24211 } else if (texture.mipmaps !== undefined && texture.mipmaps.length > 0) { 24212 24213 // user-defined mipmaps 24214 24215 return texture.mipmaps.length; 24216 24217 } else if (texture.isCompressedTexture && Array.isArray(texture.image)) { 24218 24219 return image.mipmaps.length; 24220 24221 } else { 24222 24223 // texture without mipmaps (only base level) 24224 24225 return 1; 24226 24227 } 24228 24229 } 24230 24231 // Fallback filters for non-power-of-2 textures 24232 24233 function filterFallback(f) { 24234 24235 if (f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter) { 24236 24237 return _gl.NEAREST; 24238 24239 } 24240 24241 return _gl.LINEAR; 24242 24243 } 24244 24245 // 24246 24247 function onTextureDispose(event) { 24248 24249 const texture = event.target; 24250 24251 texture.removeEventListener('dispose', onTextureDispose); 24252 24253 deallocateTexture(texture); 24254 24255 if (texture.isVideoTexture) { 24256 24257 _videoTextures.delete(texture); 24258 24259 } 24260 24261 } 24262 24263 function onRenderTargetDispose(event) { 24264 24265 const renderTarget = event.target; 24266 24267 renderTarget.removeEventListener('dispose', onRenderTargetDispose); 24268 24269 deallocateRenderTarget(renderTarget); 24270 24271 } 24272 24273 // 24274 24275 function deallocateTexture(texture) { 24276 24277 const textureProperties = properties.get(texture); 24278 24279 if (textureProperties.__webglInit === undefined) return; 24280 24281 // check if it's necessary to remove the WebGLTexture object 24282 24283 const source = texture.source; 24284 const webglTextures = _sources.get(source); 24285 24286 if (webglTextures) { 24287 24288 const webglTexture = webglTextures[textureProperties.__cacheKey]; 24289 webglTexture.usedTimes--; 24290 24291 // the WebGLTexture object is not used anymore, remove it 24292 24293 if (webglTexture.usedTimes === 0) { 24294 24295 deleteTexture(texture); 24296 24297 } 24298 24299 // remove the weak map entry if no WebGLTexture uses the source anymore 24300 24301 if (Object.keys(webglTextures).length === 0) { 24302 24303 _sources.delete(source); 24304 24305 } 24306 24307 } 24308 24309 properties.remove(texture); 24310 24311 } 24312 24313 function deleteTexture(texture) { 24314 24315 const textureProperties = properties.get(texture); 24316 _gl.deleteTexture(textureProperties.__webglTexture); 24317 24318 const source = texture.source; 24319 const webglTextures = _sources.get(source); 24320 delete webglTextures[textureProperties.__cacheKey]; 24321 24322 info.memory.textures--; 24323 24324 } 24325 24326 function deallocateRenderTarget(renderTarget) { 24327 24328 const texture = renderTarget.texture; 24329 24330 const renderTargetProperties = properties.get(renderTarget); 24331 const textureProperties = properties.get(texture); 24332 24333 if (textureProperties.__webglTexture !== undefined) { 24334 24335 _gl.deleteTexture(textureProperties.__webglTexture); 24336 24337 info.memory.textures--; 24338 24339 } 24340 24341 if (renderTarget.depthTexture) { 24342 24343 renderTarget.depthTexture.dispose(); 24344 24345 } 24346 24347 if (renderTarget.isWebGLCubeRenderTarget) { 24348 24349 for (let i = 0; i < 6; i++) { 24350 24351 if (Array.isArray(renderTargetProperties.__webglFramebuffer[i])) { 24352 24353 for (let level = 0; level < renderTargetProperties.__webglFramebuffer[i].length; level++) _gl.deleteFramebuffer(renderTargetProperties.__webglFramebuffer[i][level]); 24354 24355 } else { 24356 24357 _gl.deleteFramebuffer(renderTargetProperties.__webglFramebuffer[i]); 24358 24359 } 24360 24361 if (renderTargetProperties.__webglDepthbuffer) _gl.deleteRenderbuffer(renderTargetProperties.__webglDepthbuffer[i]); 24362 24363 } 24364 24365 } else { 24366 24367 if (Array.isArray(renderTargetProperties.__webglFramebuffer)) { 24368 24369 for (let level = 0; level < renderTargetProperties.__webglFramebuffer.length; level++) _gl.deleteFramebuffer(renderTargetProperties.__webglFramebuffer[level]); 24370 24371 } else { 24372 24373 _gl.deleteFramebuffer(renderTargetProperties.__webglFramebuffer); 24374 24375 } 24376 24377 if (renderTargetProperties.__webglDepthbuffer) _gl.deleteRenderbuffer(renderTargetProperties.__webglDepthbuffer); 24378 if (renderTargetProperties.__webglMultisampledFramebuffer) _gl.deleteFramebuffer(renderTargetProperties.__webglMultisampledFramebuffer); 24379 24380 if (renderTargetProperties.__webglColorRenderbuffer) { 24381 24382 for (let i = 0; i < renderTargetProperties.__webglColorRenderbuffer.length; i++) { 24383 24384 if (renderTargetProperties.__webglColorRenderbuffer[i]) _gl.deleteRenderbuffer(renderTargetProperties.__webglColorRenderbuffer[i]); 24385 24386 } 24387 24388 } 24389 24390 if (renderTargetProperties.__webglDepthRenderbuffer) _gl.deleteRenderbuffer(renderTargetProperties.__webglDepthRenderbuffer); 24391 24392 } 24393 24394 if (renderTarget.isWebGLMultipleRenderTargets) { 24395 24396 for (let i = 0, il = texture.length; i < il; i++) { 24397 24398 const attachmentProperties = properties.get(texture[i]); 24399 24400 if (attachmentProperties.__webglTexture) { 24401 24402 _gl.deleteTexture(attachmentProperties.__webglTexture); 24403 24404 info.memory.textures--; 24405 24406 } 24407 24408 properties.remove(texture[i]); 24409 24410 } 24411 24412 } 24413 24414 properties.remove(texture); 24415 properties.remove(renderTarget); 24416 24417 } 24418 24419 // 24420 24421 let textureUnits = 0; 24422 24423 function resetTextureUnits() { 24424 24425 textureUnits = 0; 24426 24427 } 24428 24429 function allocateTextureUnit() { 24430 24431 const textureUnit = textureUnits; 24432 24433 if (textureUnit >= capabilities.maxTextures) { 24434 24435 console.warn('THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures); 24436 24437 } 24438 24439 textureUnits += 1; 24440 24441 return textureUnit; 24442 24443 } 24444 24445 function getTextureCacheKey(texture) { 24446 24447 const array = []; 24448 24449 array.push(texture.wrapS); 24450 array.push(texture.wrapT); 24451 array.push(texture.wrapR || 0); 24452 array.push(texture.magFilter); 24453 array.push(texture.minFilter); 24454 array.push(texture.anisotropy); 24455 array.push(texture.internalFormat); 24456 array.push(texture.format); 24457 array.push(texture.type); 24458 array.push(texture.generateMipmaps); 24459 array.push(texture.premultiplyAlpha); 24460 array.push(texture.flipY); 24461 array.push(texture.unpackAlignment); 24462 array.push(texture.colorSpace); 24463 24464 return array.join(); 24465 24466 } 24467 24468 // 24469 24470 function setTexture2D(texture, slot) { 24471 24472 const textureProperties = properties.get(texture); 24473 24474 if (texture.isVideoTexture) updateVideoTexture(texture); 24475 24476 if (texture.isRenderTargetTexture === false && texture.version > 0 && textureProperties.__version !== texture.version) { 24477 24478 const image = texture.image; 24479 24480 if (image === null) { 24481 24482 console.warn('THREE.WebGLRenderer: Texture marked for update but no image data found.'); 24483 24484 } else if (image.complete === false) { 24485 24486 console.warn('THREE.WebGLRenderer: Texture marked for update but image is incomplete'); 24487 24488 } else { 24489 24490 uploadTexture(textureProperties, texture, slot); 24491 return; 24492 24493 } 24494 24495 } 24496 24497 state.bindTexture(_gl.TEXTURE_2D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot); 24498 24499 } 24500 24501 function setTexture2DArray(texture, slot) { 24502 24503 const textureProperties = properties.get(texture); 24504 24505 if (texture.version > 0 && textureProperties.__version !== texture.version) { 24506 24507 uploadTexture(textureProperties, texture, slot); 24508 return; 24509 24510 } 24511 24512 state.bindTexture(_gl.TEXTURE_2D_ARRAY, textureProperties.__webglTexture, _gl.TEXTURE0 + slot); 24513 24514 } 24515 24516 function setTexture3D(texture, slot) { 24517 24518 const textureProperties = properties.get(texture); 24519 24520 if (texture.version > 0 && textureProperties.__version !== texture.version) { 24521 24522 uploadTexture(textureProperties, texture, slot); 24523 return; 24524 24525 } 24526 24527 state.bindTexture(_gl.TEXTURE_3D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot); 24528 24529 } 24530 24531 function setTextureCube(texture, slot) { 24532 24533 const textureProperties = properties.get(texture); 24534 24535 if (texture.version > 0 && textureProperties.__version !== texture.version) { 24536 24537 uploadCubeTexture(textureProperties, texture, slot); 24538 return; 24539 24540 } 24541 24542 state.bindTexture(_gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot); 24543 24544 } 24545 24546 const wrappingToGL = { 24547 [RepeatWrapping]: _gl.REPEAT, 24548 [ClampToEdgeWrapping]: _gl.CLAMP_TO_EDGE, 24549 [MirroredRepeatWrapping]: _gl.MIRRORED_REPEAT 24550 }; 24551 24552 const filterToGL = { 24553 [NearestFilter]: _gl.NEAREST, 24554 [NearestMipmapNearestFilter]: _gl.NEAREST_MIPMAP_NEAREST, 24555 [NearestMipmapLinearFilter]: _gl.NEAREST_MIPMAP_LINEAR, 24556 24557 [LinearFilter]: _gl.LINEAR, 24558 [LinearMipmapNearestFilter]: _gl.LINEAR_MIPMAP_NEAREST, 24559 [LinearMipmapLinearFilter]: _gl.LINEAR_MIPMAP_LINEAR 24560 }; 24561 24562 const compareToGL = { 24563 [NeverCompare]: _gl.NEVER, 24564 [AlwaysCompare]: _gl.ALWAYS, 24565 [LessCompare]: _gl.LESS, 24566 [LessEqualCompare]: _gl.LEQUAL, 24567 [EqualCompare]: _gl.EQUAL, 24568 [GreaterEqualCompare]: _gl.GEQUAL, 24569 [GreaterCompare]: _gl.GREATER, 24570 [NotEqualCompare]: _gl.NOTEQUAL 24571 }; 24572 24573 function setTextureParameters(textureType, texture, supportsMips) { 24574 24575 if (supportsMips) { 24576 24577 _gl.texParameteri(textureType, _gl.TEXTURE_WRAP_S, wrappingToGL[texture.wrapS]); 24578 _gl.texParameteri(textureType, _gl.TEXTURE_WRAP_T, wrappingToGL[texture.wrapT]); 24579 24580 if (textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY) { 24581 24582 _gl.texParameteri(textureType, _gl.TEXTURE_WRAP_R, wrappingToGL[texture.wrapR]); 24583 24584 } 24585 24586 _gl.texParameteri(textureType, _gl.TEXTURE_MAG_FILTER, filterToGL[texture.magFilter]); 24587 _gl.texParameteri(textureType, _gl.TEXTURE_MIN_FILTER, filterToGL[texture.minFilter]); 24588 24589 } else { 24590 24591 _gl.texParameteri(textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE); 24592 _gl.texParameteri(textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE); 24593 24594 if (textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY) { 24595 24596 _gl.texParameteri(textureType, _gl.TEXTURE_WRAP_R, _gl.CLAMP_TO_EDGE); 24597 24598 } 24599 24600 if (texture.wrapS !== ClampToEdgeWrapping || texture.wrapT !== ClampToEdgeWrapping) { 24601 24602 console.warn('THREE.WebGLRenderer: Texture is not power of two. Texture.wrapS and Texture.wrapT should be set to THREE.ClampToEdgeWrapping.'); 24603 24604 } 24605 24606 _gl.texParameteri(textureType, _gl.TEXTURE_MAG_FILTER, filterFallback(texture.magFilter)); 24607 _gl.texParameteri(textureType, _gl.TEXTURE_MIN_FILTER, filterFallback(texture.minFilter)); 24608 24609 if (texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter) { 24610 24611 console.warn('THREE.WebGLRenderer: Texture is not power of two. Texture.minFilter should be set to THREE.NearestFilter or THREE.LinearFilter.'); 24612 24613 } 24614 24615 } 24616 24617 if (texture.compareFunction) { 24618 24619 _gl.texParameteri(textureType, _gl.TEXTURE_COMPARE_MODE, _gl.COMPARE_REF_TO_TEXTURE); 24620 _gl.texParameteri(textureType, _gl.TEXTURE_COMPARE_FUNC, compareToGL[texture.compareFunction]); 24621 24622 } 24623 24624 if (extensions.has('EXT_texture_filter_anisotropic') === true) { 24625 24626 const extension = extensions.get('EXT_texture_filter_anisotropic'); 24627 24628 if (texture.magFilter === NearestFilter) return; 24629 if (texture.minFilter !== NearestMipmapLinearFilter && texture.minFilter !== LinearMipmapLinearFilter) return; 24630 if (texture.type === FloatType && extensions.has('OES_texture_float_linear') === false) return; // verify extension for WebGL 1 and WebGL 2 24631 if (isWebGL2 === false && (texture.type === HalfFloatType && extensions.has('OES_texture_half_float_linear') === false)) return; // verify extension for WebGL 1 only 24632 24633 if (texture.anisotropy > 1 || properties.get(texture).__currentAnisotropy) { 24634 24635 _gl.texParameterf(textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min(texture.anisotropy, capabilities.getMaxAnisotropy())); 24636 properties.get(texture).__currentAnisotropy = texture.anisotropy; 24637 24638 } 24639 24640 } 24641 24642 } 24643 24644 function initTexture(textureProperties, texture) { 24645 24646 let forceUpload = false; 24647 24648 if (textureProperties.__webglInit === undefined) { 24649 24650 textureProperties.__webglInit = true; 24651 24652 texture.addEventListener('dispose', onTextureDispose); 24653 24654 } 24655 24656 // create Source <-> WebGLTextures mapping if necessary 24657 24658 const source = texture.source; 24659 let webglTextures = _sources.get(source); 24660 24661 if (webglTextures === undefined) { 24662 24663 webglTextures = {}; 24664 _sources.set(source, webglTextures); 24665 24666 } 24667 24668 // check if there is already a WebGLTexture object for the given texture parameters 24669 24670 const textureCacheKey = getTextureCacheKey(texture); 24671 24672 if (textureCacheKey !== textureProperties.__cacheKey) { 24673 24674 // if not, create a new instance of WebGLTexture 24675 24676 if (webglTextures[textureCacheKey] === undefined) { 24677 24678 // create new entry 24679 24680 webglTextures[textureCacheKey] = { 24681 texture: _gl.createTexture(), 24682 usedTimes: 0 24683 }; 24684 24685 info.memory.textures++; 24686 24687 // when a new instance of WebGLTexture was created, a texture upload is required 24688 // even if the image contents are identical 24689 24690 forceUpload = true; 24691 24692 } 24693 24694 webglTextures[textureCacheKey].usedTimes++; 24695 24696 // every time the texture cache key changes, it's necessary to check if an instance of 24697 // WebGLTexture can be deleted in order to avoid a memory leak. 24698 24699 const webglTexture = webglTextures[textureProperties.__cacheKey]; 24700 24701 if (webglTexture !== undefined) { 24702 24703 webglTextures[textureProperties.__cacheKey].usedTimes--; 24704 24705 if (webglTexture.usedTimes === 0) { 24706 24707 deleteTexture(texture); 24708 24709 } 24710 24711 } 24712 24713 // store references to cache key and WebGLTexture object 24714 24715 textureProperties.__cacheKey = textureCacheKey; 24716 textureProperties.__webglTexture = webglTextures[textureCacheKey].texture; 24717 24718 } 24719 24720 return forceUpload; 24721 24722 } 24723 24724 function uploadTexture(textureProperties, texture, slot) { 24725 24726 let textureType = _gl.TEXTURE_2D; 24727 24728 if (texture.isDataArrayTexture || texture.isCompressedArrayTexture) textureType = _gl.TEXTURE_2D_ARRAY; 24729 if (texture.isData3DTexture) textureType = _gl.TEXTURE_3D; 24730 24731 const forceUpload = initTexture(textureProperties, texture); 24732 const source = texture.source; 24733 24734 state.bindTexture(textureType, textureProperties.__webglTexture, _gl.TEXTURE0 + slot); 24735 24736 const sourceProperties = properties.get(source); 24737 24738 if (source.version !== sourceProperties.__version || forceUpload === true) { 24739 24740 state.activeTexture(_gl.TEXTURE0 + slot); 24741 24742 const workingPrimaries = ColorManagement.getPrimaries(ColorManagement.workingColorSpace); 24743 const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries(texture.colorSpace); 24744 const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL; 24745 24746 _gl.pixelStorei(_gl.UNPACK_FLIP_Y_WEBGL, texture.flipY); 24747 _gl.pixelStorei(_gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha); 24748 _gl.pixelStorei(_gl.UNPACK_ALIGNMENT, texture.unpackAlignment); 24749 _gl.pixelStorei(_gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion); 24750 24751 const needsPowerOfTwo = textureNeedsPowerOfTwo(texture) && isPowerOfTwo$1(texture.image) === false; 24752 let image = resizeImage(texture.image, needsPowerOfTwo, false, capabilities.maxTextureSize); 24753 image = verifyColorSpace(texture, image); 24754 24755 const supportsMips = isPowerOfTwo$1(image) || isWebGL2, 24756 glFormat = utils.convert(texture.format, texture.colorSpace); 24757 24758 let glType = utils.convert(texture.type), 24759 glInternalFormat = getInternalFormat(texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture); 24760 24761 setTextureParameters(textureType, texture, supportsMips); 24762 24763 let mipmap; 24764 const mipmaps = texture.mipmaps; 24765 24766 const useTexStorage = (isWebGL2 && texture.isVideoTexture !== true && glInternalFormat !== RGB_ETC1_Format); 24767 const allocateMemory = (sourceProperties.__version === undefined) || (forceUpload === true); 24768 const levels = getMipLevels(texture, image, supportsMips); 24769 24770 if (texture.isDepthTexture) { 24771 24772 // populate depth texture with dummy data 24773 24774 glInternalFormat = _gl.DEPTH_COMPONENT; 24775 24776 if (isWebGL2) { 24777 24778 if (texture.type === FloatType) { 24779 24780 glInternalFormat = _gl.DEPTH_COMPONENT32F; 24781 24782 } else if (texture.type === UnsignedIntType) { 24783 24784 glInternalFormat = _gl.DEPTH_COMPONENT24; 24785 24786 } else if (texture.type === UnsignedInt248Type) { 24787 24788 glInternalFormat = _gl.DEPTH24_STENCIL8; 24789 24790 } else { 24791 24792 glInternalFormat = _gl.DEPTH_COMPONENT16; // WebGL2 requires sized internalformat for glTexImage2D 24793 24794 } 24795 24796 } else { 24797 24798 if (texture.type === FloatType) { 24799 24800 console.error('WebGLRenderer: Floating point depth texture requires WebGL2.'); 24801 24802 } 24803 24804 } 24805 24806 // validation checks for WebGL 1 24807 24808 if (texture.format === DepthFormat && glInternalFormat === _gl.DEPTH_COMPONENT) { 24809 24810 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are 24811 // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT 24812 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) 24813 if (texture.type !== UnsignedShortType && texture.type !== UnsignedIntType) { 24814 24815 console.warn('THREE.WebGLRenderer: Use UnsignedShortType or UnsignedIntType for DepthFormat DepthTexture.'); 24816 24817 texture.type = UnsignedIntType; 24818 glType = utils.convert(texture.type); 24819 24820 } 24821 24822 } 24823 24824 if (texture.format === DepthStencilFormat && glInternalFormat === _gl.DEPTH_COMPONENT) { 24825 24826 // Depth stencil textures need the DEPTH_STENCIL internal format 24827 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) 24828 glInternalFormat = _gl.DEPTH_STENCIL; 24829 24830 // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are 24831 // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL. 24832 // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) 24833 if (texture.type !== UnsignedInt248Type) { 24834 24835 console.warn('THREE.WebGLRenderer: Use UnsignedInt248Type for DepthStencilFormat DepthTexture.'); 24836 24837 texture.type = UnsignedInt248Type; 24838 glType = utils.convert(texture.type); 24839 24840 } 24841 24842 } 24843 24844 // 24845 24846 if (allocateMemory) { 24847 24848 if (useTexStorage) { 24849 24850 state.texStorage2D(_gl.TEXTURE_2D, 1, glInternalFormat, image.width, image.height); 24851 24852 } else { 24853 24854 state.texImage2D(_gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null); 24855 24856 } 24857 24858 } 24859 24860 } else if (texture.isDataTexture) { 24861 24862 // use manually created mipmaps if available 24863 // if there are no manual mipmaps 24864 // set 0 level mipmap and then use GL to generate other mipmap levels 24865 24866 if (mipmaps.length > 0 && supportsMips) { 24867 24868 if (useTexStorage && allocateMemory) { 24869 24870 state.texStorage2D(_gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[0].width, mipmaps[0].height); 24871 24872 } 24873 24874 for (let i = 0, il = mipmaps.length; i < il; i++) { 24875 24876 mipmap = mipmaps[i]; 24877 24878 if (useTexStorage) { 24879 24880 state.texSubImage2D(_gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data); 24881 24882 } else { 24883 24884 state.texImage2D(_gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data); 24885 24886 } 24887 24888 } 24889 24890 texture.generateMipmaps = false; 24891 24892 } else { 24893 24894 if (useTexStorage) { 24895 24896 if (allocateMemory) { 24897 24898 state.texStorage2D(_gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height); 24899 24900 } 24901 24902 state.texSubImage2D(_gl.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data); 24903 24904 } else { 24905 24906 state.texImage2D(_gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data); 24907 24908 } 24909 24910 } 24911 24912 } else if (texture.isCompressedTexture) { 24913 24914 if (texture.isCompressedArrayTexture) { 24915 24916 if (useTexStorage && allocateMemory) { 24917 24918 state.texStorage3D(_gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, mipmaps[0].width, mipmaps[0].height, image.depth); 24919 24920 } 24921 24922 for (let i = 0, il = mipmaps.length; i < il; i++) { 24923 24924 mipmap = mipmaps[i]; 24925 24926 if (texture.format !== RGBAFormat) { 24927 24928 if (glFormat !== null) { 24929 24930 if (useTexStorage) { 24931 24932 state.compressedTexSubImage3D(_gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0); 24933 24934 } else { 24935 24936 state.compressedTexImage3D(_gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, mipmap.data, 0, 0); 24937 24938 } 24939 24940 } else { 24941 24942 console.warn('THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()'); 24943 24944 } 24945 24946 } else { 24947 24948 if (useTexStorage) { 24949 24950 state.texSubImage3D(_gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data); 24951 24952 } else { 24953 24954 state.texImage3D(_gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, glFormat, glType, mipmap.data); 24955 24956 } 24957 24958 } 24959 24960 } 24961 24962 } else { 24963 24964 if (useTexStorage && allocateMemory) { 24965 24966 state.texStorage2D(_gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[0].width, mipmaps[0].height); 24967 24968 } 24969 24970 for (let i = 0, il = mipmaps.length; i < il; i++) { 24971 24972 mipmap = mipmaps[i]; 24973 24974 if (texture.format !== RGBAFormat) { 24975 24976 if (glFormat !== null) { 24977 24978 if (useTexStorage) { 24979 24980 state.compressedTexSubImage2D(_gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data); 24981 24982 } else { 24983 24984 state.compressedTexImage2D(_gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data); 24985 24986 } 24987 24988 } else { 24989 24990 console.warn('THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()'); 24991 24992 } 24993 24994 } else { 24995 24996 if (useTexStorage) { 24997 24998 state.texSubImage2D(_gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data); 24999 25000 } else { 25001 25002 state.texImage2D(_gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data); 25003 25004 } 25005 25006 } 25007 25008 } 25009 25010 } 25011 25012 } else if (texture.isDataArrayTexture) { 25013 25014 if (useTexStorage) { 25015 25016 if (allocateMemory) { 25017 25018 state.texStorage3D(_gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, image.width, image.height, image.depth); 25019 25020 } 25021 25022 state.texSubImage3D(_gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data); 25023 25024 } else { 25025 25026 state.texImage3D(_gl.TEXTURE_2D_ARRAY, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data); 25027 25028 } 25029 25030 } else if (texture.isData3DTexture) { 25031 25032 if (useTexStorage) { 25033 25034 if (allocateMemory) { 25035 25036 state.texStorage3D(_gl.TEXTURE_3D, levels, glInternalFormat, image.width, image.height, image.depth); 25037 25038 } 25039 25040 state.texSubImage3D(_gl.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data); 25041 25042 } else { 25043 25044 state.texImage3D(_gl.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data); 25045 25046 } 25047 25048 } else if (texture.isFramebufferTexture) { 25049 25050 if (allocateMemory) { 25051 25052 if (useTexStorage) { 25053 25054 state.texStorage2D(_gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height); 25055 25056 } else { 25057 25058 let width = image.width, height = image.height; 25059 25060 for (let i = 0; i < levels; i++) { 25061 25062 state.texImage2D(_gl.TEXTURE_2D, i, glInternalFormat, width, height, 0, glFormat, glType, null); 25063 25064 width >>= 1; 25065 height >>= 1; 25066 25067 } 25068 25069 } 25070 25071 } 25072 25073 } else { 25074 25075 // regular Texture (image, video, canvas) 25076 25077 // use manually created mipmaps if available 25078 // if there are no manual mipmaps 25079 // set 0 level mipmap and then use GL to generate other mipmap levels 25080 25081 if (mipmaps.length > 0 && supportsMips) { 25082 25083 if (useTexStorage && allocateMemory) { 25084 25085 state.texStorage2D(_gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[0].width, mipmaps[0].height); 25086 25087 } 25088 25089 for (let i = 0, il = mipmaps.length; i < il; i++) { 25090 25091 mipmap = mipmaps[i]; 25092 25093 if (useTexStorage) { 25094 25095 state.texSubImage2D(_gl.TEXTURE_2D, i, 0, 0, glFormat, glType, mipmap); 25096 25097 } else { 25098 25099 state.texImage2D(_gl.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap); 25100 25101 } 25102 25103 } 25104 25105 texture.generateMipmaps = false; 25106 25107 } else { 25108 25109 if (useTexStorage) { 25110 25111 if (allocateMemory) { 25112 25113 state.texStorage2D(_gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height); 25114 25115 } 25116 25117 state.texSubImage2D(_gl.TEXTURE_2D, 0, 0, 0, glFormat, glType, image); 25118 25119 } else { 25120 25121 state.texImage2D(_gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image); 25122 25123 } 25124 25125 } 25126 25127 } 25128 25129 if (textureNeedsGenerateMipmaps(texture, supportsMips)) { 25130 25131 generateMipmap(textureType); 25132 25133 } 25134 25135 sourceProperties.__version = source.version; 25136 25137 if (texture.onUpdate) texture.onUpdate(texture); 25138 25139 } 25140 25141 textureProperties.__version = texture.version; 25142 25143 } 25144 25145 function uploadCubeTexture(textureProperties, texture, slot) { 25146 25147 if (texture.image.length !== 6) return; 25148 25149 const forceUpload = initTexture(textureProperties, texture); 25150 const source = texture.source; 25151 25152 state.bindTexture(_gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot); 25153 25154 const sourceProperties = properties.get(source); 25155 25156 if (source.version !== sourceProperties.__version || forceUpload === true) { 25157 25158 state.activeTexture(_gl.TEXTURE0 + slot); 25159 25160 const workingPrimaries = ColorManagement.getPrimaries(ColorManagement.workingColorSpace); 25161 const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries(texture.colorSpace); 25162 const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL; 25163 25164 _gl.pixelStorei(_gl.UNPACK_FLIP_Y_WEBGL, texture.flipY); 25165 _gl.pixelStorei(_gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha); 25166 _gl.pixelStorei(_gl.UNPACK_ALIGNMENT, texture.unpackAlignment); 25167 _gl.pixelStorei(_gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion); 25168 25169 const isCompressed = (texture.isCompressedTexture || texture.image[0].isCompressedTexture); 25170 const isDataTexture = (texture.image[0] && texture.image[0].isDataTexture); 25171 25172 const cubeImage = []; 25173 25174 for (let i = 0; i < 6; i++) { 25175 25176 if (!isCompressed && !isDataTexture) { 25177 25178 cubeImage[i] = resizeImage(texture.image[i], false, true, capabilities.maxCubemapSize); 25179 25180 } else { 25181 25182 cubeImage[i] = isDataTexture ? texture.image[i].image : texture.image[i]; 25183 25184 } 25185 25186 cubeImage[i] = verifyColorSpace(texture, cubeImage[i]); 25187 25188 } 25189 25190 const image = cubeImage[0], 25191 supportsMips = isPowerOfTwo$1(image) || isWebGL2, 25192 glFormat = utils.convert(texture.format, texture.colorSpace), 25193 glType = utils.convert(texture.type), 25194 glInternalFormat = getInternalFormat(texture.internalFormat, glFormat, glType, texture.colorSpace); 25195 25196 const useTexStorage = (isWebGL2 && texture.isVideoTexture !== true); 25197 const allocateMemory = (sourceProperties.__version === undefined) || (forceUpload === true); 25198 let levels = getMipLevels(texture, image, supportsMips); 25199 25200 setTextureParameters(_gl.TEXTURE_CUBE_MAP, texture, supportsMips); 25201 25202 let mipmaps; 25203 25204 if (isCompressed) { 25205 25206 if (useTexStorage && allocateMemory) { 25207 25208 state.texStorage2D(_gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, image.width, image.height); 25209 25210 } 25211 25212 for (let i = 0; i < 6; i++) { 25213 25214 mipmaps = cubeImage[i].mipmaps; 25215 25216 for (let j = 0; j < mipmaps.length; j++) { 25217 25218 const mipmap = mipmaps[j]; 25219 25220 if (texture.format !== RGBAFormat) { 25221 25222 if (glFormat !== null) { 25223 25224 if (useTexStorage) { 25225 25226 state.compressedTexSubImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data); 25227 25228 } else { 25229 25230 state.compressedTexImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data); 25231 25232 } 25233 25234 } else { 25235 25236 console.warn('THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()'); 25237 25238 } 25239 25240 } else { 25241 25242 if (useTexStorage) { 25243 25244 state.texSubImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data); 25245 25246 } else { 25247 25248 state.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data); 25249 25250 } 25251 25252 } 25253 25254 } 25255 25256 } 25257 25258 } else { 25259 25260 mipmaps = texture.mipmaps; 25261 25262 if (useTexStorage && allocateMemory) { 25263 25264 // TODO: Uniformly handle mipmap definitions 25265 // Normal textures and compressed cube textures define base level + mips with their mipmap array 25266 // Uncompressed cube textures use their mipmap array only for mips (no base level) 25267 25268 if (mipmaps.length > 0) levels++; 25269 25270 state.texStorage2D(_gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, cubeImage[0].width, cubeImage[0].height); 25271 25272 } 25273 25274 for (let i = 0; i < 6; i++) { 25275 25276 if (isDataTexture) { 25277 25278 if (useTexStorage) { 25279 25280 state.texSubImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, cubeImage[i].width, cubeImage[i].height, glFormat, glType, cubeImage[i].data); 25281 25282 } else { 25283 25284 state.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, cubeImage[i].width, cubeImage[i].height, 0, glFormat, glType, cubeImage[i].data); 25285 25286 } 25287 25288 for (let j = 0; j < mipmaps.length; j++) { 25289 25290 const mipmap = mipmaps[j]; 25291 const mipmapImage = mipmap.image[i].image; 25292 25293 if (useTexStorage) { 25294 25295 state.texSubImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data); 25296 25297 } else { 25298 25299 state.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data); 25300 25301 } 25302 25303 } 25304 25305 } else { 25306 25307 if (useTexStorage) { 25308 25309 state.texSubImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, glFormat, glType, cubeImage[i]); 25310 25311 } else { 25312 25313 state.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, glFormat, glType, cubeImage[i]); 25314 25315 } 25316 25317 for (let j = 0; j < mipmaps.length; j++) { 25318 25319 const mipmap = mipmaps[j]; 25320 25321 if (useTexStorage) { 25322 25323 state.texSubImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, glFormat, glType, mipmap.image[i]); 25324 25325 } else { 25326 25327 state.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[i]); 25328 25329 } 25330 25331 } 25332 25333 } 25334 25335 } 25336 25337 } 25338 25339 if (textureNeedsGenerateMipmaps(texture, supportsMips)) { 25340 25341 // We assume images for cube map have the same size. 25342 generateMipmap(_gl.TEXTURE_CUBE_MAP); 25343 25344 } 25345 25346 sourceProperties.__version = source.version; 25347 25348 if (texture.onUpdate) texture.onUpdate(texture); 25349 25350 } 25351 25352 textureProperties.__version = texture.version; 25353 25354 } 25355 25356 // Render targets 25357 25358 // Setup storage for target texture and bind it to correct framebuffer 25359 function setupFrameBufferTexture(framebuffer, renderTarget, texture, attachment, textureTarget, level) { 25360 25361 const glFormat = utils.convert(texture.format, texture.colorSpace); 25362 const glType = utils.convert(texture.type); 25363 const glInternalFormat = getInternalFormat(texture.internalFormat, glFormat, glType, texture.colorSpace); 25364 const renderTargetProperties = properties.get(renderTarget); 25365 25366 if (!renderTargetProperties.__hasExternalTextures) { 25367 25368 const width = Math.max(1, renderTarget.width >> level); 25369 const height = Math.max(1, renderTarget.height >> level); 25370 25371 if (textureTarget === _gl.TEXTURE_3D || textureTarget === _gl.TEXTURE_2D_ARRAY) { 25372 25373 state.texImage3D(textureTarget, level, glInternalFormat, width, height, renderTarget.depth, 0, glFormat, glType, null); 25374 25375 } else { 25376 25377 state.texImage2D(textureTarget, level, glInternalFormat, width, height, 0, glFormat, glType, null); 25378 25379 } 25380 25381 } 25382 25383 state.bindFramebuffer(_gl.FRAMEBUFFER, framebuffer); 25384 25385 if (useMultisampledRTT(renderTarget)) { 25386 25387 multisampledRTTExt.framebufferTexture2DMultisampleEXT(_gl.FRAMEBUFFER, attachment, textureTarget, properties.get(texture).__webglTexture, 0, getRenderTargetSamples(renderTarget)); 25388 25389 } else if (textureTarget === _gl.TEXTURE_2D || (textureTarget >= _gl.TEXTURE_CUBE_MAP_POSITIVE_X && textureTarget <= _gl.TEXTURE_CUBE_MAP_NEGATIVE_Z)) { // see #24753 25390 25391 _gl.framebufferTexture2D(_gl.FRAMEBUFFER, attachment, textureTarget, properties.get(texture).__webglTexture, level); 25392 25393 } 25394 25395 state.bindFramebuffer(_gl.FRAMEBUFFER, null); 25396 25397 } 25398 25399 25400 // Setup storage for internal depth/stencil buffers and bind to correct framebuffer 25401 function setupRenderBufferStorage(renderbuffer, renderTarget, isMultisample) { 25402 25403 _gl.bindRenderbuffer(_gl.RENDERBUFFER, renderbuffer); 25404 25405 if (renderTarget.depthBuffer && !renderTarget.stencilBuffer) { 25406 25407 let glInternalFormat = (isWebGL2 === true) ? _gl.DEPTH_COMPONENT24 : _gl.DEPTH_COMPONENT16; 25408 25409 if (isMultisample || useMultisampledRTT(renderTarget)) { 25410 25411 const depthTexture = renderTarget.depthTexture; 25412 25413 if (depthTexture && depthTexture.isDepthTexture) { 25414 25415 if (depthTexture.type === FloatType) { 25416 25417 glInternalFormat = _gl.DEPTH_COMPONENT32F; 25418 25419 } else if (depthTexture.type === UnsignedIntType) { 25420 25421 glInternalFormat = _gl.DEPTH_COMPONENT24; 25422 25423 } 25424 25425 } 25426 25427 const samples = getRenderTargetSamples(renderTarget); 25428 25429 if (useMultisampledRTT(renderTarget)) { 25430 25431 multisampledRTTExt.renderbufferStorageMultisampleEXT(_gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height); 25432 25433 } else { 25434 25435 _gl.renderbufferStorageMultisample(_gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height); 25436 25437 } 25438 25439 } else { 25440 25441 _gl.renderbufferStorage(_gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height); 25442 25443 } 25444 25445 _gl.framebufferRenderbuffer(_gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer); 25446 25447 } else if (renderTarget.depthBuffer && renderTarget.stencilBuffer) { 25448 25449 const samples = getRenderTargetSamples(renderTarget); 25450 25451 if (isMultisample && useMultisampledRTT(renderTarget) === false) { 25452 25453 _gl.renderbufferStorageMultisample(_gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height); 25454 25455 } else if (useMultisampledRTT(renderTarget)) { 25456 25457 multisampledRTTExt.renderbufferStorageMultisampleEXT(_gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height); 25458 25459 } else { 25460 25461 _gl.renderbufferStorage(_gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height); 25462 25463 } 25464 25465 25466 _gl.framebufferRenderbuffer(_gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer); 25467 25468 } else { 25469 25470 const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [renderTarget.texture]; 25471 25472 for (let i = 0; i < textures.length; i++) { 25473 25474 const texture = textures[i]; 25475 25476 const glFormat = utils.convert(texture.format, texture.colorSpace); 25477 const glType = utils.convert(texture.type); 25478 const glInternalFormat = getInternalFormat(texture.internalFormat, glFormat, glType, texture.colorSpace); 25479 const samples = getRenderTargetSamples(renderTarget); 25480 25481 if (isMultisample && useMultisampledRTT(renderTarget) === false) { 25482 25483 _gl.renderbufferStorageMultisample(_gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height); 25484 25485 } else if (useMultisampledRTT(renderTarget)) { 25486 25487 multisampledRTTExt.renderbufferStorageMultisampleEXT(_gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height); 25488 25489 } else { 25490 25491 _gl.renderbufferStorage(_gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height); 25492 25493 } 25494 25495 } 25496 25497 } 25498 25499 _gl.bindRenderbuffer(_gl.RENDERBUFFER, null); 25500 25501 } 25502 25503 // Setup resources for a Depth Texture for a FBO (needs an extension) 25504 function setupDepthTexture(framebuffer, renderTarget) { 25505 25506 const isCube = (renderTarget && renderTarget.isWebGLCubeRenderTarget); 25507 if (isCube) throw new Error('Depth Texture with cube render targets is not supported'); 25508 25509 state.bindFramebuffer(_gl.FRAMEBUFFER, framebuffer); 25510 25511 if (!(renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture)) { 25512 25513 throw new Error('renderTarget.depthTexture must be an instance of THREE.DepthTexture'); 25514 25515 } 25516 25517 // upload an empty depth texture with framebuffer size 25518 if (!properties.get(renderTarget.depthTexture).__webglTexture || 25519 renderTarget.depthTexture.image.width !== renderTarget.width || 25520 renderTarget.depthTexture.image.height !== renderTarget.height) { 25521 25522 renderTarget.depthTexture.image.width = renderTarget.width; 25523 renderTarget.depthTexture.image.height = renderTarget.height; 25524 renderTarget.depthTexture.needsUpdate = true; 25525 25526 } 25527 25528 setTexture2D(renderTarget.depthTexture, 0); 25529 25530 const webglDepthTexture = properties.get(renderTarget.depthTexture).__webglTexture; 25531 const samples = getRenderTargetSamples(renderTarget); 25532 25533 if (renderTarget.depthTexture.format === DepthFormat) { 25534 25535 if (useMultisampledRTT(renderTarget)) { 25536 25537 multisampledRTTExt.framebufferTexture2DMultisampleEXT(_gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples); 25538 25539 } else { 25540 25541 _gl.framebufferTexture2D(_gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0); 25542 25543 } 25544 25545 } else if (renderTarget.depthTexture.format === DepthStencilFormat) { 25546 25547 if (useMultisampledRTT(renderTarget)) { 25548 25549 multisampledRTTExt.framebufferTexture2DMultisampleEXT(_gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples); 25550 25551 } else { 25552 25553 _gl.framebufferTexture2D(_gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0); 25554 25555 } 25556 25557 } else { 25558 25559 throw new Error('Unknown depthTexture format'); 25560 25561 } 25562 25563 } 25564 25565 // Setup GL resources for a non-texture depth buffer 25566 function setupDepthRenderbuffer(renderTarget) { 25567 25568 const renderTargetProperties = properties.get(renderTarget); 25569 const isCube = (renderTarget.isWebGLCubeRenderTarget === true); 25570 25571 if (renderTarget.depthTexture && !renderTargetProperties.__autoAllocateDepthBuffer) { 25572 25573 if (isCube) throw new Error('target.depthTexture not supported in Cube render targets'); 25574 25575 setupDepthTexture(renderTargetProperties.__webglFramebuffer, renderTarget); 25576 25577 } else { 25578 25579 if (isCube) { 25580 25581 renderTargetProperties.__webglDepthbuffer = []; 25582 25583 for (let i = 0; i < 6; i++) { 25584 25585 state.bindFramebuffer(_gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[i]); 25586 renderTargetProperties.__webglDepthbuffer[i] = _gl.createRenderbuffer(); 25587 setupRenderBufferStorage(renderTargetProperties.__webglDepthbuffer[i], renderTarget, false); 25588 25589 } 25590 25591 } else { 25592 25593 state.bindFramebuffer(_gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer); 25594 renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer(); 25595 setupRenderBufferStorage(renderTargetProperties.__webglDepthbuffer, renderTarget, false); 25596 25597 } 25598 25599 } 25600 25601 state.bindFramebuffer(_gl.FRAMEBUFFER, null); 25602 25603 } 25604 25605 // rebind framebuffer with external textures 25606 function rebindTextures(renderTarget, colorTexture, depthTexture) { 25607 25608 const renderTargetProperties = properties.get(renderTarget); 25609 25610 if (colorTexture !== undefined) { 25611 25612 setupFrameBufferTexture(renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, 0); 25613 25614 } 25615 25616 if (depthTexture !== undefined) { 25617 25618 setupDepthRenderbuffer(renderTarget); 25619 25620 } 25621 25622 } 25623 25624 // Set up GL resources for the render target 25625 function setupRenderTarget(renderTarget) { 25626 25627 const texture = renderTarget.texture; 25628 25629 const renderTargetProperties = properties.get(renderTarget); 25630 const textureProperties = properties.get(texture); 25631 25632 renderTarget.addEventListener('dispose', onRenderTargetDispose); 25633 25634 if (renderTarget.isWebGLMultipleRenderTargets !== true) { 25635 25636 if (textureProperties.__webglTexture === undefined) { 25637 25638 textureProperties.__webglTexture = _gl.createTexture(); 25639 25640 } 25641 25642 textureProperties.__version = texture.version; 25643 info.memory.textures++; 25644 25645 } 25646 25647 const isCube = (renderTarget.isWebGLCubeRenderTarget === true); 25648 const isMultipleRenderTargets = (renderTarget.isWebGLMultipleRenderTargets === true); 25649 const supportsMips = isPowerOfTwo$1(renderTarget) || isWebGL2; 25650 25651 // Setup framebuffer 25652 25653 if (isCube) { 25654 25655 renderTargetProperties.__webglFramebuffer = []; 25656 25657 for (let i = 0; i < 6; i++) { 25658 25659 if (isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0) { 25660 25661 renderTargetProperties.__webglFramebuffer[i] = []; 25662 25663 for (let level = 0; level < texture.mipmaps.length; level++) { 25664 25665 renderTargetProperties.__webglFramebuffer[i][level] = _gl.createFramebuffer(); 25666 25667 } 25668 25669 } else { 25670 25671 renderTargetProperties.__webglFramebuffer[i] = _gl.createFramebuffer(); 25672 25673 } 25674 25675 } 25676 25677 } else { 25678 25679 if (isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0) { 25680 25681 renderTargetProperties.__webglFramebuffer = []; 25682 25683 for (let level = 0; level < texture.mipmaps.length; level++) { 25684 25685 renderTargetProperties.__webglFramebuffer[level] = _gl.createFramebuffer(); 25686 25687 } 25688 25689 } else { 25690 25691 renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); 25692 25693 } 25694 25695 if (isMultipleRenderTargets) { 25696 25697 if (capabilities.drawBuffers) { 25698 25699 const textures = renderTarget.texture; 25700 25701 for (let i = 0, il = textures.length; i < il; i++) { 25702 25703 const attachmentProperties = properties.get(textures[i]); 25704 25705 if (attachmentProperties.__webglTexture === undefined) { 25706 25707 attachmentProperties.__webglTexture = _gl.createTexture(); 25708 25709 info.memory.textures++; 25710 25711 } 25712 25713 } 25714 25715 } else { 25716 25717 console.warn('THREE.WebGLRenderer: WebGLMultipleRenderTargets can only be used with WebGL2 or WEBGL_draw_buffers extension.'); 25718 25719 } 25720 25721 } 25722 25723 if ((isWebGL2 && renderTarget.samples > 0) && useMultisampledRTT(renderTarget) === false) { 25724 25725 const textures = isMultipleRenderTargets ? texture : [texture]; 25726 25727 renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer(); 25728 renderTargetProperties.__webglColorRenderbuffer = []; 25729 25730 state.bindFramebuffer(_gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer); 25731 25732 for (let i = 0; i < textures.length; i++) { 25733 25734 const texture = textures[i]; 25735 renderTargetProperties.__webglColorRenderbuffer[i] = _gl.createRenderbuffer(); 25736 25737 _gl.bindRenderbuffer(_gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[i]); 25738 25739 const glFormat = utils.convert(texture.format, texture.colorSpace); 25740 const glType = utils.convert(texture.type); 25741 const glInternalFormat = getInternalFormat(texture.internalFormat, glFormat, glType, texture.colorSpace, renderTarget.isXRRenderTarget === true); 25742 const samples = getRenderTargetSamples(renderTarget); 25743 _gl.renderbufferStorageMultisample(_gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height); 25744 25745 _gl.framebufferRenderbuffer(_gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[i]); 25746 25747 } 25748 25749 _gl.bindRenderbuffer(_gl.RENDERBUFFER, null); 25750 25751 if (renderTarget.depthBuffer) { 25752 25753 renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer(); 25754 setupRenderBufferStorage(renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true); 25755 25756 } 25757 25758 state.bindFramebuffer(_gl.FRAMEBUFFER, null); 25759 25760 } 25761 25762 } 25763 25764 // Setup color buffer 25765 25766 if (isCube) { 25767 25768 state.bindTexture(_gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture); 25769 setTextureParameters(_gl.TEXTURE_CUBE_MAP, texture, supportsMips); 25770 25771 for (let i = 0; i < 6; i++) { 25772 25773 if (isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0) { 25774 25775 for (let level = 0; level < texture.mipmaps.length; level++) { 25776 25777 setupFrameBufferTexture(renderTargetProperties.__webglFramebuffer[i][level], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level); 25778 25779 } 25780 25781 } else { 25782 25783 setupFrameBufferTexture(renderTargetProperties.__webglFramebuffer[i], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0); 25784 25785 } 25786 25787 } 25788 25789 if (textureNeedsGenerateMipmaps(texture, supportsMips)) { 25790 25791 generateMipmap(_gl.TEXTURE_CUBE_MAP); 25792 25793 } 25794 25795 state.unbindTexture(); 25796 25797 } else if (isMultipleRenderTargets) { 25798 25799 const textures = renderTarget.texture; 25800 25801 for (let i = 0, il = textures.length; i < il; i++) { 25802 25803 const attachment = textures[i]; 25804 const attachmentProperties = properties.get(attachment); 25805 25806 state.bindTexture(_gl.TEXTURE_2D, attachmentProperties.__webglTexture); 25807 setTextureParameters(_gl.TEXTURE_2D, attachment, supportsMips); 25808 setupFrameBufferTexture(renderTargetProperties.__webglFramebuffer, renderTarget, attachment, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, 0); 25809 25810 if (textureNeedsGenerateMipmaps(attachment, supportsMips)) { 25811 25812 generateMipmap(_gl.TEXTURE_2D); 25813 25814 } 25815 25816 } 25817 25818 state.unbindTexture(); 25819 25820 } else { 25821 25822 let glTextureType = _gl.TEXTURE_2D; 25823 25824 if (renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget) { 25825 25826 if (isWebGL2) { 25827 25828 glTextureType = renderTarget.isWebGL3DRenderTarget ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY; 25829 25830 } else { 25831 25832 console.error('THREE.WebGLTextures: THREE.Data3DTexture and THREE.DataArrayTexture only supported with WebGL2.'); 25833 25834 } 25835 25836 } 25837 25838 state.bindTexture(glTextureType, textureProperties.__webglTexture); 25839 setTextureParameters(glTextureType, texture, supportsMips); 25840 25841 if (isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0) { 25842 25843 for (let level = 0; level < texture.mipmaps.length; level++) { 25844 25845 setupFrameBufferTexture(renderTargetProperties.__webglFramebuffer[level], renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, level); 25846 25847 } 25848 25849 } else { 25850 25851 setupFrameBufferTexture(renderTargetProperties.__webglFramebuffer, renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, 0); 25852 25853 } 25854 25855 if (textureNeedsGenerateMipmaps(texture, supportsMips)) { 25856 25857 generateMipmap(glTextureType); 25858 25859 } 25860 25861 state.unbindTexture(); 25862 25863 } 25864 25865 // Setup depth and stencil buffers 25866 25867 if (renderTarget.depthBuffer) { 25868 25869 setupDepthRenderbuffer(renderTarget); 25870 25871 } 25872 25873 } 25874 25875 function updateRenderTargetMipmap(renderTarget) { 25876 25877 const supportsMips = isPowerOfTwo$1(renderTarget) || isWebGL2; 25878 25879 const textures = renderTarget.isWebGLMultipleRenderTargets === true ? renderTarget.texture : [renderTarget.texture]; 25880 25881 for (let i = 0, il = textures.length; i < il; i++) { 25882 25883 const texture = textures[i]; 25884 25885 if (textureNeedsGenerateMipmaps(texture, supportsMips)) { 25886 25887 const target = renderTarget.isWebGLCubeRenderTarget ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D; 25888 const webglTexture = properties.get(texture).__webglTexture; 25889 25890 state.bindTexture(target, webglTexture); 25891 generateMipmap(target); 25892 state.unbindTexture(); 25893 25894 } 25895 25896 } 25897 25898 } 25899 25900 function updateMultisampleRenderTarget(renderTarget) { 25901 25902 if ((isWebGL2 && renderTarget.samples > 0) && useMultisampledRTT(renderTarget) === false) { 25903 25904 const textures = renderTarget.isWebGLMultipleRenderTargets ? renderTarget.texture : [renderTarget.texture]; 25905 const width = renderTarget.width; 25906 const height = renderTarget.height; 25907 let mask = _gl.COLOR_BUFFER_BIT; 25908 const invalidationArray = []; 25909 const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT; 25910 const renderTargetProperties = properties.get(renderTarget); 25911 const isMultipleRenderTargets = (renderTarget.isWebGLMultipleRenderTargets === true); 25912 25913 // If MRT we need to remove FBO attachments 25914 if (isMultipleRenderTargets) { 25915 25916 for (let i = 0; i < textures.length; i++) { 25917 25918 state.bindFramebuffer(_gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer); 25919 _gl.framebufferRenderbuffer(_gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, null); 25920 25921 state.bindFramebuffer(_gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer); 25922 _gl.framebufferTexture2D(_gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, null, 0); 25923 25924 } 25925 25926 } 25927 25928 state.bindFramebuffer(_gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer); 25929 state.bindFramebuffer(_gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer); 25930 25931 for (let i = 0; i < textures.length; i++) { 25932 25933 invalidationArray.push(_gl.COLOR_ATTACHMENT0 + i); 25934 25935 if (renderTarget.depthBuffer) { 25936 25937 invalidationArray.push(depthStyle); 25938 25939 } 25940 25941 const ignoreDepthValues = (renderTargetProperties.__ignoreDepthValues !== undefined) ? renderTargetProperties.__ignoreDepthValues : false; 25942 25943 if (ignoreDepthValues === false) { 25944 25945 if (renderTarget.depthBuffer) mask |= _gl.DEPTH_BUFFER_BIT; 25946 if (renderTarget.stencilBuffer) mask |= _gl.STENCIL_BUFFER_BIT; 25947 25948 } 25949 25950 if (isMultipleRenderTargets) { 25951 25952 _gl.framebufferRenderbuffer(_gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[i]); 25953 25954 } 25955 25956 if (ignoreDepthValues === true) { 25957 25958 _gl.invalidateFramebuffer(_gl.READ_FRAMEBUFFER, [depthStyle]); 25959 _gl.invalidateFramebuffer(_gl.DRAW_FRAMEBUFFER, [depthStyle]); 25960 25961 } 25962 25963 if (isMultipleRenderTargets) { 25964 25965 const webglTexture = properties.get(textures[i]).__webglTexture; 25966 _gl.framebufferTexture2D(_gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, webglTexture, 0); 25967 25968 } 25969 25970 _gl.blitFramebuffer(0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST); 25971 25972 if (supportsInvalidateFramebuffer) { 25973 25974 _gl.invalidateFramebuffer(_gl.READ_FRAMEBUFFER, invalidationArray); 25975 25976 } 25977 25978 25979 } 25980 25981 state.bindFramebuffer(_gl.READ_FRAMEBUFFER, null); 25982 state.bindFramebuffer(_gl.DRAW_FRAMEBUFFER, null); 25983 25984 // If MRT since pre-blit we removed the FBO we need to reconstruct the attachments 25985 if (isMultipleRenderTargets) { 25986 25987 for (let i = 0; i < textures.length; i++) { 25988 25989 state.bindFramebuffer(_gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer); 25990 _gl.framebufferRenderbuffer(_gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[i]); 25991 25992 const webglTexture = properties.get(textures[i]).__webglTexture; 25993 25994 state.bindFramebuffer(_gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer); 25995 _gl.framebufferTexture2D(_gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, webglTexture, 0); 25996 25997 } 25998 25999 } 26000 26001 state.bindFramebuffer(_gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer); 26002 26003 } 26004 26005 } 26006 26007 function getRenderTargetSamples(renderTarget) { 26008 26009 return Math.min(capabilities.maxSamples, renderTarget.samples); 26010 26011 } 26012 26013 function useMultisampledRTT(renderTarget) { 26014 26015 const renderTargetProperties = properties.get(renderTarget); 26016 26017 return isWebGL2 && renderTarget.samples > 0 && extensions.has('WEBGL_multisampled_render_to_texture') === true && renderTargetProperties.__useRenderToTexture !== false; 26018 26019 } 26020 26021 function updateVideoTexture(texture) { 26022 26023 const frame = info.render.frame; 26024 26025 // Check the last frame we updated the VideoTexture 26026 26027 if (_videoTextures.get(texture) !== frame) { 26028 26029 _videoTextures.set(texture, frame); 26030 texture.update(); 26031 26032 } 26033 26034 } 26035 26036 function verifyColorSpace(texture, image) { 26037 26038 const colorSpace = texture.colorSpace; 26039 const format = texture.format; 26040 const type = texture.type; 26041 26042 if (texture.isCompressedTexture === true || texture.isVideoTexture === true || texture.format === _SRGBAFormat) return image; 26043 26044 if (colorSpace !== LinearSRGBColorSpace && colorSpace !== NoColorSpace) { 26045 26046 // sRGB 26047 26048 if (ColorManagement.getTransfer(colorSpace) === SRGBTransfer) { 26049 26050 if (isWebGL2 === false) { 26051 26052 // in WebGL 1, try to use EXT_sRGB extension and unsized formats 26053 26054 if (extensions.has('EXT_sRGB') === true && format === RGBAFormat) { 26055 26056 texture.format = _SRGBAFormat; 26057 26058 // it's not possible to generate mips in WebGL 1 with this extension 26059 26060 texture.minFilter = LinearFilter; 26061 texture.generateMipmaps = false; 26062 26063 } else { 26064 26065 // slow fallback (CPU decode) 26066 26067 image = ImageUtils.sRGBToLinear(image); 26068 26069 } 26070 26071 } else { 26072 26073 // in WebGL 2 uncompressed textures can only be sRGB encoded if they have the RGBA8 format 26074 26075 if (format !== RGBAFormat || type !== UnsignedByteType) { 26076 26077 console.warn('THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType.'); 26078 26079 } 26080 26081 } 26082 26083 } else { 26084 26085 console.error('THREE.WebGLTextures: Unsupported texture color space:', colorSpace); 26086 26087 } 26088 26089 } 26090 26091 return image; 26092 26093 } 26094 26095 // 26096 26097 this.allocateTextureUnit = allocateTextureUnit; 26098 this.resetTextureUnits = resetTextureUnits; 26099 26100 this.setTexture2D = setTexture2D; 26101 this.setTexture2DArray = setTexture2DArray; 26102 this.setTexture3D = setTexture3D; 26103 this.setTextureCube = setTextureCube; 26104 this.rebindTextures = rebindTextures; 26105 this.setupRenderTarget = setupRenderTarget; 26106 this.updateRenderTargetMipmap = updateRenderTargetMipmap; 26107 this.updateMultisampleRenderTarget = updateMultisampleRenderTarget; 26108 this.setupDepthRenderbuffer = setupDepthRenderbuffer; 26109 this.setupFrameBufferTexture = setupFrameBufferTexture; 26110 this.useMultisampledRTT = useMultisampledRTT; 26111 26112} 26113 26114function WebGLUtils(gl, extensions, capabilities) { 26115 26116 const isWebGL2 = capabilities.isWebGL2; 26117 26118 function convert(p, colorSpace = NoColorSpace) { 26119 26120 let extension; 26121 26122 const transfer = ColorManagement.getTransfer(colorSpace); 26123 26124 if (p === UnsignedByteType) return gl.UNSIGNED_BYTE; 26125 if (p === UnsignedShort4444Type) return gl.UNSIGNED_SHORT_4_4_4_4; 26126 if (p === UnsignedShort5551Type) return gl.UNSIGNED_SHORT_5_5_5_1; 26127 26128 if (p === ByteType) return gl.BYTE; 26129 if (p === ShortType) return gl.SHORT; 26130 if (p === UnsignedShortType) return gl.UNSIGNED_SHORT; 26131 if (p === IntType) return gl.INT; 26132 if (p === UnsignedIntType) return gl.UNSIGNED_INT; 26133 if (p === FloatType) return gl.FLOAT; 26134 26135 if (p === HalfFloatType) { 26136 26137 if (isWebGL2) return gl.HALF_FLOAT; 26138 26139 extension = extensions.get('OES_texture_half_float'); 26140 26141 if (extension !== null) { 26142 26143 return extension.HALF_FLOAT_OES; 26144 26145 } else { 26146 26147 return null; 26148 26149 } 26150 26151 } 26152 26153 if (p === AlphaFormat) return gl.ALPHA; 26154 if (p === RGBAFormat) return gl.RGBA; 26155 if (p === LuminanceFormat) return gl.LUMINANCE; 26156 if (p === LuminanceAlphaFormat) return gl.LUMINANCE_ALPHA; 26157 if (p === DepthFormat) return gl.DEPTH_COMPONENT; 26158 if (p === DepthStencilFormat) return gl.DEPTH_STENCIL; 26159 26160 // WebGL 1 sRGB fallback 26161 26162 if (p === _SRGBAFormat) { 26163 26164 extension = extensions.get('EXT_sRGB'); 26165 26166 if (extension !== null) { 26167 26168 return extension.SRGB_ALPHA_EXT; 26169 26170 } else { 26171 26172 return null; 26173 26174 } 26175 26176 } 26177 26178 // WebGL2 formats. 26179 26180 if (p === RedFormat) return gl.RED; 26181 if (p === RedIntegerFormat) return gl.RED_INTEGER; 26182 if (p === RGFormat) return gl.RG; 26183 if (p === RGIntegerFormat) return gl.RG_INTEGER; 26184 if (p === RGBAIntegerFormat) return gl.RGBA_INTEGER; 26185 26186 // S3TC 26187 26188 if (p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format) { 26189 26190 if (transfer === SRGBTransfer) { 26191 26192 extension = extensions.get('WEBGL_compressed_texture_s3tc_srgb'); 26193 26194 if (extension !== null) { 26195 26196 if (p === RGB_S3TC_DXT1_Format) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT; 26197 if (p === RGBA_S3TC_DXT1_Format) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; 26198 if (p === RGBA_S3TC_DXT3_Format) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; 26199 if (p === RGBA_S3TC_DXT5_Format) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; 26200 26201 } else { 26202 26203 return null; 26204 26205 } 26206 26207 } else { 26208 26209 extension = extensions.get('WEBGL_compressed_texture_s3tc'); 26210 26211 if (extension !== null) { 26212 26213 if (p === RGB_S3TC_DXT1_Format) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; 26214 if (p === RGBA_S3TC_DXT1_Format) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; 26215 if (p === RGBA_S3TC_DXT3_Format) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; 26216 if (p === RGBA_S3TC_DXT5_Format) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; 26217 26218 } else { 26219 26220 return null; 26221 26222 } 26223 26224 } 26225 26226 } 26227 26228 // PVRTC 26229 26230 if (p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format) { 26231 26232 extension = extensions.get('WEBGL_compressed_texture_pvrtc'); 26233 26234 if (extension !== null) { 26235 26236 if (p === RGB_PVRTC_4BPPV1_Format) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; 26237 if (p === RGB_PVRTC_2BPPV1_Format) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; 26238 if (p === RGBA_PVRTC_4BPPV1_Format) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; 26239 if (p === RGBA_PVRTC_2BPPV1_Format) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; 26240 26241 } else { 26242 26243 return null; 26244 26245 } 26246 26247 } 26248 26249 // ETC1 26250 26251 if (p === RGB_ETC1_Format) { 26252 26253 extension = extensions.get('WEBGL_compressed_texture_etc1'); 26254 26255 if (extension !== null) { 26256 26257 return extension.COMPRESSED_RGB_ETC1_WEBGL; 26258 26259 } else { 26260 26261 return null; 26262 26263 } 26264 26265 } 26266 26267 // ETC2 26268 26269 if (p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format) { 26270 26271 extension = extensions.get('WEBGL_compressed_texture_etc'); 26272 26273 if (extension !== null) { 26274 26275 if (p === RGB_ETC2_Format) return (transfer === SRGBTransfer) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2; 26276 if (p === RGBA_ETC2_EAC_Format) return (transfer === SRGBTransfer) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC; 26277 26278 } else { 26279 26280 return null; 26281 26282 } 26283 26284 } 26285 26286 // ASTC 26287 26288 if (p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format || 26289 p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format || 26290 p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format || 26291 p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format || 26292 p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format) { 26293 26294 extension = extensions.get('WEBGL_compressed_texture_astc'); 26295 26296 if (extension !== null) { 26297 26298 if (p === RGBA_ASTC_4x4_Format) return (transfer === SRGBTransfer) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR; 26299 if (p === RGBA_ASTC_5x4_Format) return (transfer === SRGBTransfer) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR; 26300 if (p === RGBA_ASTC_5x5_Format) return (transfer === SRGBTransfer) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR; 26301 if (p === RGBA_ASTC_6x5_Format) return (transfer === SRGBTransfer) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR; 26302 if (p === RGBA_ASTC_6x6_Format) return (transfer === SRGBTransfer) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR; 26303 if (p === RGBA_ASTC_8x5_Format) return (transfer === SRGBTransfer) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR; 26304 if (p === RGBA_ASTC_8x6_Format) return (transfer === SRGBTransfer) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR; 26305 if (p === RGBA_ASTC_8x8_Format) return (transfer === SRGBTransfer) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR; 26306 if (p === RGBA_ASTC_10x5_Format) return (transfer === SRGBTransfer) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR; 26307 if (p === RGBA_ASTC_10x6_Format) return (transfer === SRGBTransfer) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR; 26308 if (p === RGBA_ASTC_10x8_Format) return (transfer === SRGBTransfer) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR; 26309 if (p === RGBA_ASTC_10x10_Format) return (transfer === SRGBTransfer) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR; 26310 if (p === RGBA_ASTC_12x10_Format) return (transfer === SRGBTransfer) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR; 26311 if (p === RGBA_ASTC_12x12_Format) return (transfer === SRGBTransfer) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR; 26312 26313 } else { 26314 26315 return null; 26316 26317 } 26318 26319 } 26320 26321 // BPTC 26322 26323 if (p === RGBA_BPTC_Format || p === RGB_BPTC_SIGNED_Format || p === RGB_BPTC_UNSIGNED_Format) { 26324 26325 extension = extensions.get('EXT_texture_compression_bptc'); 26326 26327 if (extension !== null) { 26328 26329 if (p === RGBA_BPTC_Format) return (transfer === SRGBTransfer) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT; 26330 if (p === RGB_BPTC_SIGNED_Format) return extension.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT; 26331 if (p === RGB_BPTC_UNSIGNED_Format) return extension.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT; 26332 26333 } else { 26334 26335 return null; 26336 26337 } 26338 26339 } 26340 26341 // RGTC 26342 26343 if (p === RED_RGTC1_Format || p === SIGNED_RED_RGTC1_Format || p === RED_GREEN_RGTC2_Format || p === SIGNED_RED_GREEN_RGTC2_Format) { 26344 26345 extension = extensions.get('EXT_texture_compression_rgtc'); 26346 26347 if (extension !== null) { 26348 26349 if (p === RGBA_BPTC_Format) return extension.COMPRESSED_RED_RGTC1_EXT; 26350 if (p === SIGNED_RED_RGTC1_Format) return extension.COMPRESSED_SIGNED_RED_RGTC1_EXT; 26351 if (p === RED_GREEN_RGTC2_Format) return extension.COMPRESSED_RED_GREEN_RGTC2_EXT; 26352 if (p === SIGNED_RED_GREEN_RGTC2_Format) return extension.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT; 26353 26354 } else { 26355 26356 return null; 26357 26358 } 26359 26360 } 26361 26362 // 26363 26364 if (p === UnsignedInt248Type) { 26365 26366 if (isWebGL2) return gl.UNSIGNED_INT_24_8; 26367 26368 extension = extensions.get('WEBGL_depth_texture'); 26369 26370 if (extension !== null) { 26371 26372 return extension.UNSIGNED_INT_24_8_WEBGL; 26373 26374 } else { 26375 26376 return null; 26377 26378 } 26379 26380 } 26381 26382 // if "p" can't be resolved, assume the user defines a WebGL constant as a string (fallback/workaround for packed RGB formats) 26383 26384 return (gl[p] !== undefined) ? gl[p] : null; 26385 26386 } 26387 26388 return { convert: convert }; 26389 26390} 26391 26392class ArrayCamera extends PerspectiveCamera { 26393 26394 constructor(array = []) { 26395 26396 super(); 26397 26398 this.isArrayCamera = true; 26399 26400 this.cameras = array; 26401 26402 } 26403 26404} 26405 26406class Group extends Object3D { 26407 26408 constructor() { 26409 26410 super(); 26411 26412 this.isGroup = true; 26413 26414 this.type = 'Group'; 26415 26416 } 26417 26418} 26419 26420const _moveEvent = { type: 'move' }; 26421 26422class WebXRController { 26423 26424 constructor() { 26425 26426 this._targetRay = null; 26427 this._grip = null; 26428 this._hand = null; 26429 26430 } 26431 26432 getHandSpace() { 26433 26434 if (this._hand === null) { 26435 26436 this._hand = new Group(); 26437 this._hand.matrixAutoUpdate = false; 26438 this._hand.visible = false; 26439 26440 this._hand.joints = {}; 26441 this._hand.inputState = { pinching: false }; 26442 26443 } 26444 26445 return this._hand; 26446 26447 } 26448 26449 getTargetRaySpace() { 26450 26451 if (this._targetRay === null) { 26452 26453 this._targetRay = new Group(); 26454 this._targetRay.matrixAutoUpdate = false; 26455 this._targetRay.visible = false; 26456 this._targetRay.hasLinearVelocity = false; 26457 this._targetRay.linearVelocity = new Vector3(); 26458 this._targetRay.hasAngularVelocity = false; 26459 this._targetRay.angularVelocity = new Vector3(); 26460 26461 } 26462 26463 return this._targetRay; 26464 26465 } 26466 26467 getGripSpace() { 26468 26469 if (this._grip === null) { 26470 26471 this._grip = new Group(); 26472 this._grip.matrixAutoUpdate = false; 26473 this._grip.visible = false; 26474 this._grip.hasLinearVelocity = false; 26475 this._grip.linearVelocity = new Vector3(); 26476 this._grip.hasAngularVelocity = false; 26477 this._grip.angularVelocity = new Vector3(); 26478 26479 } 26480 26481 return this._grip; 26482 26483 } 26484 26485 dispatchEvent(event) { 26486 26487 if (this._targetRay !== null) { 26488 26489 this._targetRay.dispatchEvent(event); 26490 26491 } 26492 26493 if (this._grip !== null) { 26494 26495 this._grip.dispatchEvent(event); 26496 26497 } 26498 26499 if (this._hand !== null) { 26500 26501 this._hand.dispatchEvent(event); 26502 26503 } 26504 26505 return this; 26506 26507 } 26508 26509 connect(inputSource) { 26510 26511 if (inputSource && inputSource.hand) { 26512 26513 const hand = this._hand; 26514 26515 if (hand) { 26516 26517 for (const inputjoint of inputSource.hand.values()) { 26518 26519 // Initialize hand with joints when connected 26520 this._getHandJoint(hand, inputjoint); 26521 26522 } 26523 26524 } 26525 26526 } 26527 26528 this.dispatchEvent({ type: 'connected', data: inputSource }); 26529 26530 return this; 26531 26532 } 26533 26534 disconnect(inputSource) { 26535 26536 this.dispatchEvent({ type: 'disconnected', data: inputSource }); 26537 26538 if (this._targetRay !== null) { 26539 26540 this._targetRay.visible = false; 26541 26542 } 26543 26544 if (this._grip !== null) { 26545 26546 this._grip.visible = false; 26547 26548 } 26549 26550 if (this._hand !== null) { 26551 26552 this._hand.visible = false; 26553 26554 } 26555 26556 return this; 26557 26558 } 26559 26560 update(inputSource, frame, referenceSpace) { 26561 26562 let inputPose = null; 26563 let gripPose = null; 26564 let handPose = null; 26565 26566 const targetRay = this._targetRay; 26567 const grip = this._grip; 26568 const hand = this._hand; 26569 26570 if (inputSource && frame.session.visibilityState !== 'visible-blurred') { 26571 26572 if (hand && inputSource.hand) { 26573 26574 handPose = true; 26575 26576 for (const inputjoint of inputSource.hand.values()) { 26577 26578 // Update the joints groups with the XRJoint poses 26579 const jointPose = frame.getJointPose(inputjoint, referenceSpace); 26580 26581 // The transform of this joint will be updated with the joint pose on each frame 26582 const joint = this._getHandJoint(hand, inputjoint); 26583 26584 if (jointPose !== null) { 26585 26586 joint.matrix.fromArray(jointPose.transform.matrix); 26587 joint.matrix.decompose(joint.position, joint.rotation, joint.scale); 26588 joint.matrixWorldNeedsUpdate = true; 26589 joint.jointRadius = jointPose.radius; 26590 26591 } 26592 26593 joint.visible = jointPose !== null; 26594 26595 } 26596 26597 // Custom events 26598 26599 // Check pinchz 26600 const indexTip = hand.joints['index-finger-tip']; 26601 const thumbTip = hand.joints['thumb-tip']; 26602 const distance = indexTip.position.distanceTo(thumbTip.position); 26603 26604 const distanceToPinch = 0.02; 26605 const threshold = 0.005; 26606 26607 if (hand.inputState.pinching && distance > distanceToPinch + threshold) { 26608 26609 hand.inputState.pinching = false; 26610 this.dispatchEvent({ 26611 type: 'pinchend', 26612 handedness: inputSource.handedness, 26613 target: this 26614 }); 26615 26616 } else if (!hand.inputState.pinching && distance <= distanceToPinch - threshold) { 26617 26618 hand.inputState.pinching = true; 26619 this.dispatchEvent({ 26620 type: 'pinchstart', 26621 handedness: inputSource.handedness, 26622 target: this 26623 }); 26624 26625 } 26626 26627 } else { 26628 26629 if (grip !== null && inputSource.gripSpace) { 26630 26631 gripPose = frame.getPose(inputSource.gripSpace, referenceSpace); 26632 26633 if (gripPose !== null) { 26634 26635 grip.matrix.fromArray(gripPose.transform.matrix); 26636 grip.matrix.decompose(grip.position, grip.rotation, grip.scale); 26637 grip.matrixWorldNeedsUpdate = true; 26638 26639 if (gripPose.linearVelocity) { 26640 26641 grip.hasLinearVelocity = true; 26642 grip.linearVelocity.copy(gripPose.linearVelocity); 26643 26644 } else { 26645 26646 grip.hasLinearVelocity = false; 26647 26648 } 26649 26650 if (gripPose.angularVelocity) { 26651 26652 grip.hasAngularVelocity = true; 26653 grip.angularVelocity.copy(gripPose.angularVelocity); 26654 26655 } else { 26656 26657 grip.hasAngularVelocity = false; 26658 26659 } 26660 26661 } 26662 26663 } 26664 26665 } 26666 26667 if (targetRay !== null) { 26668 26669 inputPose = frame.getPose(inputSource.targetRaySpace, referenceSpace); 26670 26671 // Some runtimes (namely Vive Cosmos with Vive OpenXR Runtime) have only grip space and ray space is equal to it 26672 if (inputPose === null && gripPose !== null) { 26673 26674 inputPose = gripPose; 26675 26676 } 26677 26678 if (inputPose !== null) { 26679 26680 targetRay.matrix.fromArray(inputPose.transform.matrix); 26681 targetRay.matrix.decompose(targetRay.position, targetRay.rotation, targetRay.scale); 26682 targetRay.matrixWorldNeedsUpdate = true; 26683 26684 if (inputPose.linearVelocity) { 26685 26686 targetRay.hasLinearVelocity = true; 26687 targetRay.linearVelocity.copy(inputPose.linearVelocity); 26688 26689 } else { 26690 26691 targetRay.hasLinearVelocity = false; 26692 26693 } 26694 26695 if (inputPose.angularVelocity) { 26696 26697 targetRay.hasAngularVelocity = true; 26698 targetRay.angularVelocity.copy(inputPose.angularVelocity); 26699 26700 } else { 26701 26702 targetRay.hasAngularVelocity = false; 26703 26704 } 26705 26706 this.dispatchEvent(_moveEvent); 26707 26708 } 26709 26710 } 26711 26712 26713 } 26714 26715 if (targetRay !== null) { 26716 26717 targetRay.visible = (inputPose !== null); 26718 26719 } 26720 26721 if (grip !== null) { 26722 26723 grip.visible = (gripPose !== null); 26724 26725 } 26726 26727 if (hand !== null) { 26728 26729 hand.visible = (handPose !== null); 26730 26731 } 26732 26733 return this; 26734 26735 } 26736 26737 // private method 26738 26739 _getHandJoint(hand, inputjoint) { 26740 26741 if (hand.joints[inputjoint.jointName] === undefined) { 26742 26743 const joint = new Group(); 26744 joint.matrixAutoUpdate = false; 26745 joint.visible = false; 26746 hand.joints[inputjoint.jointName] = joint; 26747 26748 hand.add(joint); 26749 26750 } 26751 26752 return hand.joints[inputjoint.jointName]; 26753 26754 } 26755 26756} 26757 26758class WebXRManager extends EventDispatcher { 26759 26760 constructor(renderer, gl) { 26761 26762 super(); 26763 26764 const scope = this; 26765 26766 let session = null; 26767 26768 let framebufferScaleFactor = 1.0; 26769 26770 let referenceSpace = null; 26771 let referenceSpaceType = 'local-floor'; 26772 // Set default foveation to maximum. 26773 let foveation = 1.0; 26774 let customReferenceSpace = null; 26775 26776 let pose = null; 26777 let glBinding = null; 26778 let glProjLayer = null; 26779 let glBaseLayer = null; 26780 let xrFrame = null; 26781 const attributes = gl.getContextAttributes(); 26782 let initialRenderTarget = null; 26783 let newRenderTarget = null; 26784 26785 const controllers = []; 26786 const controllerInputSources = []; 26787 26788 const currentSize = new Vector2(); 26789 let currentPixelRatio = null; 26790 26791 // 26792 26793 const cameraL = new PerspectiveCamera(); 26794 cameraL.layers.enable(1); 26795 cameraL.viewport = new Vector4(); 26796 26797 const cameraR = new PerspectiveCamera(); 26798 cameraR.layers.enable(2); 26799 cameraR.viewport = new Vector4(); 26800 26801 const cameras = [cameraL, cameraR]; 26802 26803 const cameraXR = new ArrayCamera(); 26804 cameraXR.layers.enable(1); 26805 cameraXR.layers.enable(2); 26806 26807 let _currentDepthNear = null; 26808 let _currentDepthFar = null; 26809 26810 // 26811 26812 this.cameraAutoUpdate = true; 26813 this.enabled = false; 26814 26815 this.isPresenting = false; 26816 26817 this.getController = function (index) { 26818 26819 let controller = controllers[index]; 26820 26821 if (controller === undefined) { 26822 26823 controller = new WebXRController(); 26824 controllers[index] = controller; 26825 26826 } 26827 26828 return controller.getTargetRaySpace(); 26829 26830 }; 26831 26832 this.getControllerGrip = function (index) { 26833 26834 let controller = controllers[index]; 26835 26836 if (controller === undefined) { 26837 26838 controller = new WebXRController(); 26839 controllers[index] = controller; 26840 26841 } 26842 26843 return controller.getGripSpace(); 26844 26845 }; 26846 26847 this.getHand = function (index) { 26848 26849 let controller = controllers[index]; 26850 26851 if (controller === undefined) { 26852 26853 controller = new WebXRController(); 26854 controllers[index] = controller; 26855 26856 } 26857 26858 return controller.getHandSpace(); 26859 26860 }; 26861 26862 // 26863 26864 function onSessionEvent(event) { 26865 26866 const controllerIndex = controllerInputSources.indexOf(event.inputSource); 26867 26868 if (controllerIndex === - 1) { 26869 26870 return; 26871 26872 } 26873 26874 const controller = controllers[controllerIndex]; 26875 26876 if (controller !== undefined) { 26877 26878 controller.update(event.inputSource, event.frame, customReferenceSpace || referenceSpace); 26879 controller.dispatchEvent({ type: event.type, data: event.inputSource }); 26880 26881 } 26882 26883 } 26884 26885 function onSessionEnd() { 26886 26887 session.removeEventListener('select', onSessionEvent); 26888 session.removeEventListener('selectstart', onSessionEvent); 26889 session.removeEventListener('selectend', onSessionEvent); 26890 session.removeEventListener('squeeze', onSessionEvent); 26891 session.removeEventListener('squeezestart', onSessionEvent); 26892 session.removeEventListener('squeezeend', onSessionEvent); 26893 session.removeEventListener('end', onSessionEnd); 26894 session.removeEventListener('inputsourceschange', onInputSourcesChange); 26895 26896 for (let i = 0; i < controllers.length; i++) { 26897 26898 const inputSource = controllerInputSources[i]; 26899 26900 if (inputSource === null) continue; 26901 26902 controllerInputSources[i] = null; 26903 26904 controllers[i].disconnect(inputSource); 26905 26906 } 26907 26908 _currentDepthNear = null; 26909 _currentDepthFar = null; 26910 26911 // restore framebuffer/rendering state 26912 26913 renderer.setRenderTarget(initialRenderTarget); 26914 26915 glBaseLayer = null; 26916 glProjLayer = null; 26917 glBinding = null; 26918 session = null; 26919 newRenderTarget = null; 26920 26921 // 26922 26923 animation.stop(); 26924 26925 scope.isPresenting = false; 26926 26927 renderer.setPixelRatio(currentPixelRatio); 26928 renderer.setSize(currentSize.width, currentSize.height, false); 26929 26930 scope.dispatchEvent({ type: 'sessionend' }); 26931 26932 } 26933 26934 this.setFramebufferScaleFactor = function (value) { 26935 26936 framebufferScaleFactor = value; 26937 26938 if (scope.isPresenting === true) { 26939 26940 console.warn('THREE.WebXRManager: Cannot change framebuffer scale while presenting.'); 26941 26942 } 26943 26944 }; 26945 26946 this.setReferenceSpaceType = function (value) { 26947 26948 referenceSpaceType = value; 26949 26950 if (scope.isPresenting === true) { 26951 26952 console.warn('THREE.WebXRManager: Cannot change reference space type while presenting.'); 26953 26954 } 26955 26956 }; 26957 26958 this.getReferenceSpace = function () { 26959 26960 return customReferenceSpace || referenceSpace; 26961 26962 }; 26963 26964 this.setReferenceSpace = function (space) { 26965 26966 customReferenceSpace = space; 26967 26968 }; 26969 26970 this.getBaseLayer = function () { 26971 26972 return glProjLayer !== null ? glProjLayer : glBaseLayer; 26973 26974 }; 26975 26976 this.getBinding = function () { 26977 26978 return glBinding; 26979 26980 }; 26981 26982 this.getFrame = function () { 26983 26984 return xrFrame; 26985 26986 }; 26987 26988 this.getSession = function () { 26989 26990 return session; 26991 26992 }; 26993 26994 this.setSession = async function (value) { 26995 26996 session = value; 26997 26998 if (session !== null) { 26999 27000 initialRenderTarget = renderer.getRenderTarget(); 27001 27002 session.addEventListener('select', onSessionEvent); 27003 session.addEventListener('selectstart', onSessionEvent); 27004 session.addEventListener('selectend', onSessionEvent); 27005 session.addEventListener('squeeze', onSessionEvent); 27006 session.addEventListener('squeezestart', onSessionEvent); 27007 session.addEventListener('squeezeend', onSessionEvent); 27008 session.addEventListener('end', onSessionEnd); 27009 session.addEventListener('inputsourceschange', onInputSourcesChange); 27010 27011 if (attributes.xrCompatible !== true) { 27012 27013 await gl.makeXRCompatible(); 27014 27015 } 27016 27017 currentPixelRatio = renderer.getPixelRatio(); 27018 renderer.getSize(currentSize); 27019 27020 if ((session.renderState.layers === undefined) || (renderer.capabilities.isWebGL2 === false)) { 27021 27022 const layerInit = { 27023 antialias: (session.renderState.layers === undefined) ? attributes.antialias : true, 27024 alpha: true, 27025 depth: attributes.depth, 27026 stencil: attributes.stencil, 27027 framebufferScaleFactor: framebufferScaleFactor 27028 }; 27029 27030 glBaseLayer = new XRWebGLLayer(session, gl, layerInit); 27031 27032 session.updateRenderState({ baseLayer: glBaseLayer }); 27033 27034 renderer.setPixelRatio(1); 27035 renderer.setSize(glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, false); 27036 27037 newRenderTarget = new WebGLRenderTarget( 27038 glBaseLayer.framebufferWidth, 27039 glBaseLayer.framebufferHeight, 27040 { 27041 format: RGBAFormat, 27042 type: UnsignedByteType, 27043 colorSpace: renderer.outputColorSpace, 27044 stencilBuffer: attributes.stencil 27045 } 27046 ); 27047 27048 } else { 27049 27050 let depthFormat = null; 27051 let depthType = null; 27052 let glDepthFormat = null; 27053 27054 if (attributes.depth) { 27055 27056 glDepthFormat = attributes.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24; 27057 depthFormat = attributes.stencil ? DepthStencilFormat : DepthFormat; 27058 depthType = attributes.stencil ? UnsignedInt248Type : UnsignedIntType; 27059 27060 } 27061 27062 const projectionlayerInit = { 27063 colorFormat: gl.RGBA8, 27064 depthFormat: glDepthFormat, 27065 scaleFactor: framebufferScaleFactor 27066 }; 27067 27068 glBinding = new XRWebGLBinding(session, gl); 27069 27070 glProjLayer = glBinding.createProjectionLayer(projectionlayerInit); 27071 27072 session.updateRenderState({ layers: [glProjLayer] }); 27073 27074 renderer.setPixelRatio(1); 27075 renderer.setSize(glProjLayer.textureWidth, glProjLayer.textureHeight, false); 27076 27077 newRenderTarget = new WebGLRenderTarget( 27078 glProjLayer.textureWidth, 27079 glProjLayer.textureHeight, 27080 { 27081 format: RGBAFormat, 27082 type: UnsignedByteType, 27083 depthTexture: new DepthTexture(glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat), 27084 stencilBuffer: attributes.stencil, 27085 colorSpace: renderer.outputColorSpace, 27086 samples: attributes.antialias ? 4 : 0 27087 }); 27088 27089 const renderTargetProperties = renderer.properties.get(newRenderTarget); 27090 renderTargetProperties.__ignoreDepthValues = glProjLayer.ignoreDepthValues; 27091 27092 } 27093 27094 newRenderTarget.isXRRenderTarget = true; // TODO Remove this when possible, see #23278 27095 27096 this.setFoveation(foveation); 27097 27098 customReferenceSpace = null; 27099 referenceSpace = await session.requestReferenceSpace(referenceSpaceType); 27100 27101 animation.setContext(session); 27102 animation.start(); 27103 27104 scope.isPresenting = true; 27105 27106 scope.dispatchEvent({ type: 'sessionstart' }); 27107 27108 } 27109 27110 }; 27111 27112 this.getEnvironmentBlendMode = function () { 27113 27114 if (session !== null) { 27115 27116 return session.environmentBlendMode; 27117 27118 } 27119 27120 }; 27121 27122 function onInputSourcesChange(event) { 27123 27124 // Notify disconnected 27125 27126 for (let i = 0; i < event.removed.length; i++) { 27127 27128 const inputSource = event.removed[i]; 27129 const index = controllerInputSources.indexOf(inputSource); 27130 27131 if (index >= 0) { 27132 27133 controllerInputSources[index] = null; 27134 controllers[index].disconnect(inputSource); 27135 27136 } 27137 27138 } 27139 27140 // Notify connected 27141 27142 for (let i = 0; i < event.added.length; i++) { 27143 27144 const inputSource = event.added[i]; 27145 27146 let controllerIndex = controllerInputSources.indexOf(inputSource); 27147 27148 if (controllerIndex === - 1) { 27149 27150 // Assign input source a controller that currently has no input source 27151 27152 for (let i = 0; i < controllers.length; i++) { 27153 27154 if (i >= controllerInputSources.length) { 27155 27156 controllerInputSources.push(inputSource); 27157 controllerIndex = i; 27158 break; 27159 27160 } else if (controllerInputSources[i] === null) { 27161 27162 controllerInputSources[i] = inputSource; 27163 controllerIndex = i; 27164 break; 27165 27166 } 27167 27168 } 27169 27170 // If all controllers do currently receive input we ignore new ones 27171 27172 if (controllerIndex === - 1) break; 27173 27174 } 27175 27176 const controller = controllers[controllerIndex]; 27177 27178 if (controller) { 27179 27180 controller.connect(inputSource); 27181 27182 } 27183 27184 } 27185 27186 } 27187 27188 // 27189 27190 const cameraLPos = new Vector3(); 27191 const cameraRPos = new Vector3(); 27192 27193 /** 27194 * Assumes 2 cameras that are parallel and share an X-axis, and that 27195 * the cameras' projection and world matrices have already been set. 27196 * And that near and far planes are identical for both cameras. 27197 * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765 27198 */ 27199 function setProjectionFromUnion(camera, cameraL, cameraR) { 27200 27201 cameraLPos.setFromMatrixPosition(cameraL.matrixWorld); 27202 cameraRPos.setFromMatrixPosition(cameraR.matrixWorld); 27203 27204 const ipd = cameraLPos.distanceTo(cameraRPos); 27205 27206 const projL = cameraL.projectionMatrix.elements; 27207 const projR = cameraR.projectionMatrix.elements; 27208 27209 // VR systems will have identical far and near planes, and 27210 // most likely identical top and bottom frustum extents. 27211 // Use the left camera for these values. 27212 const near = projL[14] / (projL[10] - 1); 27213 const far = projL[14] / (projL[10] + 1); 27214 const topFov = (projL[9] + 1) / projL[5]; 27215 const bottomFov = (projL[9] - 1) / projL[5]; 27216 27217 const leftFov = (projL[8] - 1) / projL[0]; 27218 const rightFov = (projR[8] + 1) / projR[0]; 27219 const left = near * leftFov; 27220 const right = near * rightFov; 27221 27222 // Calculate the new camera's position offset from the 27223 // left camera. xOffset should be roughly half `ipd`. 27224 const zOffset = ipd / (- leftFov + rightFov); 27225 const xOffset = zOffset * - leftFov; 27226 27227 // TODO: Better way to apply this offset? 27228 cameraL.matrixWorld.decompose(camera.position, camera.quaternion, camera.scale); 27229 camera.translateX(xOffset); 27230 camera.translateZ(zOffset); 27231 camera.matrixWorld.compose(camera.position, camera.quaternion, camera.scale); 27232 camera.matrixWorldInverse.copy(camera.matrixWorld).invert(); 27233 27234 // Find the union of the frustum values of the cameras and scale 27235 // the values so that the near plane's position does not change in world space, 27236 // although must now be relative to the new union camera. 27237 const near2 = near + zOffset; 27238 const far2 = far + zOffset; 27239 const left2 = left - xOffset; 27240 const right2 = right + (ipd - xOffset); 27241 const top2 = topFov * far / far2 * near2; 27242 const bottom2 = bottomFov * far / far2 * near2; 27243 27244 camera.projectionMatrix.makePerspective(left2, right2, top2, bottom2, near2, far2); 27245 camera.projectionMatrixInverse.copy(camera.projectionMatrix).invert(); 27246 27247 } 27248 27249 function updateCamera(camera, parent) { 27250 27251 if (parent === null) { 27252 27253 camera.matrixWorld.copy(camera.matrix); 27254 27255 } else { 27256 27257 camera.matrixWorld.multiplyMatrices(parent.matrixWorld, camera.matrix); 27258 27259 } 27260 27261 camera.matrixWorldInverse.copy(camera.matrixWorld).invert(); 27262 27263 } 27264 27265 this.updateCamera = function (camera) { 27266 27267 if (session === null) return; 27268 27269 cameraXR.near = cameraR.near = cameraL.near = camera.near; 27270 cameraXR.far = cameraR.far = cameraL.far = camera.far; 27271 27272 if (_currentDepthNear !== cameraXR.near || _currentDepthFar !== cameraXR.far) { 27273 27274 // Note that the new renderState won't apply until the next frame. See #18320 27275 27276 session.updateRenderState({ 27277 depthNear: cameraXR.near, 27278 depthFar: cameraXR.far 27279 }); 27280 27281 _currentDepthNear = cameraXR.near; 27282 _currentDepthFar = cameraXR.far; 27283 27284 } 27285 27286 const parent = camera.parent; 27287 const cameras = cameraXR.cameras; 27288 27289 updateCamera(cameraXR, parent); 27290 27291 for (let i = 0; i < cameras.length; i++) { 27292 27293 updateCamera(cameras[i], parent); 27294 27295 } 27296 27297 // update projection matrix for proper view frustum culling 27298 27299 if (cameras.length === 2) { 27300 27301 setProjectionFromUnion(cameraXR, cameraL, cameraR); 27302 27303 } else { 27304 27305 // assume single camera setup (AR) 27306 27307 cameraXR.projectionMatrix.copy(cameraL.projectionMatrix); 27308 27309 } 27310 27311 // update user camera and its children 27312 27313 updateUserCamera(camera, cameraXR, parent); 27314 27315 }; 27316 27317 function updateUserCamera(camera, cameraXR, parent) { 27318 27319 if (parent === null) { 27320 27321 camera.matrix.copy(cameraXR.matrixWorld); 27322 27323 } else { 27324 27325 camera.matrix.copy(parent.matrixWorld); 27326 camera.matrix.invert(); 27327 camera.matrix.multiply(cameraXR.matrixWorld); 27328 27329 } 27330 27331 camera.matrix.decompose(camera.position, camera.quaternion, camera.scale); 27332 camera.updateMatrixWorld(true); 27333 27334 camera.projectionMatrix.copy(cameraXR.projectionMatrix); 27335 camera.projectionMatrixInverse.copy(cameraXR.projectionMatrixInverse); 27336 27337 if (camera.isPerspectiveCamera) { 27338 27339 camera.fov = RAD2DEG * 2 * Math.atan(1 / camera.projectionMatrix.elements[5]); 27340 camera.zoom = 1; 27341 27342 } 27343 27344 } 27345 27346 this.getCamera = function () { 27347 27348 return cameraXR; 27349 27350 }; 27351 27352 this.getFoveation = function () { 27353 27354 if (glProjLayer === null && glBaseLayer === null) { 27355 27356 return undefined; 27357 27358 } 27359 27360 return foveation; 27361 27362 }; 27363 27364 this.setFoveation = function (value) { 27365 27366 // 0 = no foveation = full resolution 27367 // 1 = maximum foveation = the edges render at lower resolution 27368 27369 foveation = value; 27370 27371 if (glProjLayer !== null) { 27372 27373 glProjLayer.fixedFoveation = value; 27374 27375 } 27376 27377 if (glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined) { 27378 27379 glBaseLayer.fixedFoveation = value; 27380 27381 } 27382 27383 }; 27384 27385 // Animation Loop 27386 27387 let onAnimationFrameCallback = null; 27388 27389 function onAnimationFrame(time, frame) { 27390 27391 pose = frame.getViewerPose(customReferenceSpace || referenceSpace); 27392 xrFrame = frame; 27393 27394 if (pose !== null) { 27395 27396 const views = pose.views; 27397 27398 if (glBaseLayer !== null) { 27399 27400 renderer.setRenderTargetFramebuffer(newRenderTarget, glBaseLayer.framebuffer); 27401 renderer.setRenderTarget(newRenderTarget); 27402 27403 } 27404 27405 let cameraXRNeedsUpdate = false; 27406 27407 // check if it's necessary to rebuild cameraXR's camera list 27408 27409 if (views.length !== cameraXR.cameras.length) { 27410 27411 cameraXR.cameras.length = 0; 27412 cameraXRNeedsUpdate = true; 27413 27414 } 27415 27416 for (let i = 0; i < views.length; i++) { 27417 27418 const view = views[i]; 27419 27420 let viewport = null; 27421 27422 if (glBaseLayer !== null) { 27423 27424 viewport = glBaseLayer.getViewport(view); 27425 27426 } else { 27427 27428 const glSubImage = glBinding.getViewSubImage(glProjLayer, view); 27429 viewport = glSubImage.viewport; 27430 27431 // For side-by-side projection, we only produce a single texture for both eyes. 27432 if (i === 0) { 27433 27434 renderer.setRenderTargetTextures( 27435 newRenderTarget, 27436 glSubImage.colorTexture, 27437 glProjLayer.ignoreDepthValues ? undefined : glSubImage.depthStencilTexture); 27438 27439 renderer.setRenderTarget(newRenderTarget); 27440 27441 } 27442 27443 } 27444
vendor: 6,300 bytes, lines 27445-27730
27445 let camera = cameras[i]; 27446 27447 if (camera === undefined) { 27448 27449 camera = new PerspectiveCamera(); 27450 camera.layers.enable(i); 27451 camera.viewport = new Vector4(); 27452 cameras[i] = camera; 27453 27454 } 27455 27456 camera.matrix.fromArray(view.transform.matrix); 27457 camera.matrix.decompose(camera.position, camera.quaternion, camera.scale); 27458 camera.projectionMatrix.fromArray(view.projectionMatrix); 27459 camera.projectionMatrixInverse.copy(camera.projectionMatrix).invert(); 27460 camera.viewport.set(viewport.x, viewport.y, viewport.width, viewport.height); 27461 27462 if (i === 0) { 27463 27464 cameraXR.matrix.copy(camera.matrix); 27465 cameraXR.matrix.decompose(cameraXR.position, cameraXR.quaternion, cameraXR.scale); 27466 27467 } 27468 27469 if (cameraXRNeedsUpdate === true) { 27470 27471 cameraXR.cameras.push(camera); 27472 27473 } 27474 27475 } 27476 27477 } 27478 27479 // 27480 27481 for (let i = 0; i < controllers.length; i++) { 27482 27483 const inputSource = controllerInputSources[i]; 27484 const controller = controllers[i]; 27485 27486 if (inputSource !== null && controller !== undefined) { 27487 27488 controller.update(inputSource, frame, customReferenceSpace || referenceSpace); 27489 27490 } 27491 27492 } 27493 27494 if (onAnimationFrameCallback) onAnimationFrameCallback(time, frame); 27495 27496 if (frame.detectedPlanes) { 27497 27498 scope.dispatchEvent({ type: 'planesdetected', data: frame }); 27499 27500 } 27501 27502 xrFrame = null; 27503 27504 } 27505 27506 const animation = new WebGLAnimation(); 27507 27508 animation.setAnimationLoop(onAnimationFrame); 27509 27510 this.setAnimationLoop = function (callback) { 27511 27512 onAnimationFrameCallback = callback; 27513 27514 }; 27515 27516 this.dispose = function () { }; 27517 27518 } 27519 27520} 27521 27522function WebGLMaterials(renderer, properties) { 27523 27524 function refreshTransformUniform(map, uniform) { 27525 27526 if (map.matrixAutoUpdate === true) { 27527 27528 map.updateMatrix(); 27529 27530 } 27531 27532 uniform.value.copy(map.matrix); 27533 27534 } 27535 27536 function refreshFogUniforms(uniforms, fog) { 27537 27538 fog.color.getRGB(uniforms.fogColor.value, getUnlitUniformColorSpace(renderer)); 27539 27540 if (fog.isFog) { 27541 27542 uniforms.fogNear.value = fog.near; 27543 uniforms.fogFar.value = fog.far; 27544 27545 } else if (fog.isFogExp2) { 27546 27547 uniforms.fogDensity.value = fog.density; 27548 27549 } 27550 27551 } 27552 27553 function refreshMaterialUniforms(uniforms, material, pixelRatio, height, transmissionRenderTarget) { 27554 27555 if (material.isMeshBasicMaterial) { 27556 27557 refreshUniformsCommon(uniforms, material); 27558 27559 } else if (material.isMeshLambertMaterial) { 27560 27561 refreshUniformsCommon(uniforms, material); 27562 27563 } else if (material.isMeshToonMaterial) { 27564 27565 refreshUniformsCommon(uniforms, material); 27566 refreshUniformsToon(uniforms, material); 27567 27568 } else if (material.isMeshPhongMaterial) { 27569 27570 refreshUniformsCommon(uniforms, material); 27571 refreshUniformsPhong(uniforms, material); 27572 27573 } else if (material.isMeshStandardMaterial) { 27574 27575 refreshUniformsCommon(uniforms, material); 27576 refreshUniformsStandard(uniforms, material); 27577 27578 if (material.isMeshPhysicalMaterial) { 27579 27580 refreshUniformsPhysical(uniforms, material, transmissionRenderTarget); 27581 27582 } 27583 27584 } else if (material.isMeshMatcapMaterial) { 27585 27586 refreshUniformsCommon(uniforms, material); 27587 refreshUniformsMatcap(uniforms, material); 27588 27589 } else if (material.isMeshDepthMaterial) { 27590 27591 refreshUniformsCommon(uniforms, material); 27592 27593 } else if (material.isMeshDistanceMaterial) { 27594 27595 refreshUniformsCommon(uniforms, material); 27596 refreshUniformsDistance(uniforms, material); 27597 27598 } else if (material.isMeshNormalMaterial) { 27599 27600 refreshUniformsCommon(uniforms, material); 27601 27602 } else if (material.isLineBasicMaterial) { 27603 27604 refreshUniformsLine(uniforms, material); 27605 27606 if (material.isLineDashedMaterial) { 27607 27608 refreshUniformsDash(uniforms, material); 27609 27610 } 27611 27612 } else if (material.isPointsMaterial) { 27613 27614 refreshUniformsPoints(uniforms, material, pixelRatio, height); 27615 27616 } else if (material.isSpriteMaterial) { 27617 27618 refreshUniformsSprites(uniforms, material); 27619 27620 } else if (material.isShadowMaterial) { 27621 27622 uniforms.color.value.copy(material.color); 27623 uniforms.opacity.value = material.opacity; 27624 27625 } else if (material.isShaderMaterial) { 27626 27627 material.uniformsNeedUpdate = false; // #15581 27628 27629 } 27630 27631 } 27632 27633 function refreshUniformsCommon(uniforms, material) { 27634 27635 uniforms.opacity.value = material.opacity; 27636 27637 if (material.color) { 27638 27639 uniforms.diffuse.value.copy(material.color); 27640 27641 } 27642 27643 if (material.emissive) { 27644 27645 uniforms.emissive.value.copy(material.emissive).multiplyScalar(material.emissiveIntensity); 27646 27647 } 27648 27649 if (material.map) { 27650 27651 uniforms.map.value = material.map; 27652 27653 refreshTransformUniform(material.map, uniforms.mapTransform); 27654 27655 } 27656 27657 if (material.alphaMap) { 27658 27659 uniforms.alphaMap.value = material.alphaMap; 27660 27661 refreshTransformUniform(material.alphaMap, uniforms.alphaMapTransform); 27662 27663 } 27664 27665 if (material.bumpMap) { 27666 27667 uniforms.bumpMap.value = material.bumpMap; 27668 27669 refreshTransformUniform(material.bumpMap, uniforms.bumpMapTransform); 27670 27671 uniforms.bumpScale.value = material.bumpScale; 27672 27673 if (material.side === BackSide) { 27674 27675 uniforms.bumpScale.value *= - 1; 27676 27677 } 27678 27679 } 27680 27681 if (material.normalMap) { 27682 27683 uniforms.normalMap.value = material.normalMap; 27684 27685 refreshTransformUniform(material.normalMap, uniforms.normalMapTransform); 27686 27687 uniforms.normalScale.value.copy(material.normalScale); 27688 27689 if (material.side === BackSide) { 27690 27691 uniforms.normalScale.value.negate(); 27692 27693 } 27694 27695 } 27696 27697 if (material.displacementMap) { 27698 27699 uniforms.displacementMap.value = material.displacementMap; 27700 27701 refreshTransformUniform(material.displacementMap, uniforms.displacementMapTransform); 27702 27703 uniforms.displacementScale.value = material.displacementScale; 27704 uniforms.displacementBias.value = material.displacementBias; 27705 27706 } 27707 27708 if (material.emissiveMap) { 27709 27710 uniforms.emissiveMap.value = material.emissiveMap; 27711 27712 refreshTransformUniform(material.emissiveMap, uniforms.emissiveMapTransform); 27713 27714 } 27715 27716 if (material.specularMap) { 27717 27718 uniforms.specularMap.value = material.specularMap; 27719 27720 refreshTransformUniform(material.specularMap, uniforms.specularMapTransform); 27721 27722 } 27723 27724 if (material.alphaTest > 0) { 27725 27726 uniforms.alphaTest.value = material.alphaTest; 27727 27728 } 27729 27730 const envMap = properties.get(material).envMap;
vendor: 85,181 bytes, lines 27731-31041
27731 27732 if (envMap) { 27733 27734 uniforms.envMap.value = envMap; 27735 27736 uniforms.flipEnvMap.value = (envMap.isCubeTexture && envMap.isRenderTargetTexture === false) ? - 1 : 1; 27737 27738 uniforms.reflectivity.value = material.reflectivity; 27739 uniforms.ior.value = material.ior; 27740 uniforms.refractionRatio.value = material.refractionRatio; 27741 27742 } 27743 27744 if (material.lightMap) { 27745 27746 uniforms.lightMap.value = material.lightMap; 27747 27748 // artist-friendly light intensity scaling factor 27749 const scaleFactor = (renderer._useLegacyLights === true) ? Math.PI : 1; 27750 27751 uniforms.lightMapIntensity.value = material.lightMapIntensity * scaleFactor; 27752 27753 refreshTransformUniform(material.lightMap, uniforms.lightMapTransform); 27754 27755 } 27756 27757 if (material.aoMap) { 27758 27759 uniforms.aoMap.value = material.aoMap; 27760 uniforms.aoMapIntensity.value = material.aoMapIntensity; 27761 27762 refreshTransformUniform(material.aoMap, uniforms.aoMapTransform); 27763 27764 } 27765 27766 } 27767 27768 function refreshUniformsLine(uniforms, material) { 27769 27770 uniforms.diffuse.value.copy(material.color); 27771 uniforms.opacity.value = material.opacity; 27772 27773 if (material.map) { 27774 27775 uniforms.map.value = material.map; 27776 27777 refreshTransformUniform(material.map, uniforms.mapTransform); 27778 27779 } 27780 27781 } 27782 27783 function refreshUniformsDash(uniforms, material) { 27784 27785 uniforms.dashSize.value = material.dashSize; 27786 uniforms.totalSize.value = material.dashSize + material.gapSize; 27787 uniforms.scale.value = material.scale; 27788 27789 } 27790 27791 function refreshUniformsPoints(uniforms, material, pixelRatio, height) { 27792 27793 uniforms.diffuse.value.copy(material.color); 27794 uniforms.opacity.value = material.opacity; 27795 uniforms.size.value = material.size * pixelRatio; 27796 uniforms.scale.value = height * 0.5; 27797 27798 if (material.map) { 27799 27800 uniforms.map.value = material.map; 27801 27802 refreshTransformUniform(material.map, uniforms.uvTransform); 27803 27804 } 27805 27806 if (material.alphaMap) { 27807 27808 uniforms.alphaMap.value = material.alphaMap; 27809 27810 refreshTransformUniform(material.alphaMap, uniforms.alphaMapTransform); 27811 27812 } 27813 27814 if (material.alphaTest > 0) { 27815 27816 uniforms.alphaTest.value = material.alphaTest; 27817 27818 } 27819 27820 } 27821 27822 function refreshUniformsSprites(uniforms, material) { 27823 27824 uniforms.diffuse.value.copy(material.color); 27825 uniforms.opacity.value = material.opacity; 27826 uniforms.rotation.value = material.rotation; 27827 27828 if (material.map) { 27829 27830 uniforms.map.value = material.map; 27831 27832 refreshTransformUniform(material.map, uniforms.mapTransform); 27833 27834 } 27835 27836 if (material.alphaMap) { 27837 27838 uniforms.alphaMap.value = material.alphaMap; 27839 27840 refreshTransformUniform(material.alphaMap, uniforms.alphaMapTransform); 27841 27842 } 27843 27844 if (material.alphaTest > 0) { 27845 27846 uniforms.alphaTest.value = material.alphaTest; 27847 27848 } 27849 27850 } 27851 27852 function refreshUniformsPhong(uniforms, material) { 27853 27854 uniforms.specular.value.copy(material.specular); 27855 uniforms.shininess.value = Math.max(material.shininess, 1e-4); // to prevent pow( 0.0, 0.0 ) 27856 27857 } 27858 27859 function refreshUniformsToon(uniforms, material) { 27860 27861 if (material.gradientMap) { 27862 27863 uniforms.gradientMap.value = material.gradientMap; 27864 27865 } 27866 27867 } 27868 27869 function refreshUniformsStandard(uniforms, material) { 27870 27871 uniforms.metalness.value = material.metalness; 27872 27873 if (material.metalnessMap) { 27874 27875 uniforms.metalnessMap.value = material.metalnessMap; 27876 27877 refreshTransformUniform(material.metalnessMap, uniforms.metalnessMapTransform); 27878 27879 } 27880 27881 uniforms.roughness.value = material.roughness; 27882 27883 if (material.roughnessMap) { 27884 27885 uniforms.roughnessMap.value = material.roughnessMap; 27886 27887 refreshTransformUniform(material.roughnessMap, uniforms.roughnessMapTransform); 27888 27889 } 27890 27891 const envMap = properties.get(material).envMap; 27892 27893 if (envMap) { 27894 27895 //uniforms.envMap.value = material.envMap; // part of uniforms common 27896 uniforms.envMapIntensity.value = material.envMapIntensity; 27897 27898 } 27899 27900 } 27901 27902 function refreshUniformsPhysical(uniforms, material, transmissionRenderTarget) { 27903 27904 uniforms.ior.value = material.ior; // also part of uniforms common 27905 27906 if (material.sheen > 0) { 27907 27908 uniforms.sheenColor.value.copy(material.sheenColor).multiplyScalar(material.sheen); 27909 27910 uniforms.sheenRoughness.value = material.sheenRoughness; 27911 27912 if (material.sheenColorMap) { 27913 27914 uniforms.sheenColorMap.value = material.sheenColorMap; 27915 27916 refreshTransformUniform(material.sheenColorMap, uniforms.sheenColorMapTransform); 27917 27918 } 27919 27920 if (material.sheenRoughnessMap) { 27921 27922 uniforms.sheenRoughnessMap.value = material.sheenRoughnessMap; 27923 27924 refreshTransformUniform(material.sheenRoughnessMap, uniforms.sheenRoughnessMapTransform); 27925 27926 } 27927 27928 } 27929 27930 if (material.clearcoat > 0) { 27931 27932 uniforms.clearcoat.value = material.clearcoat; 27933 uniforms.clearcoatRoughness.value = material.clearcoatRoughness; 27934 27935 if (material.clearcoatMap) { 27936 27937 uniforms.clearcoatMap.value = material.clearcoatMap; 27938 27939 refreshTransformUniform(material.clearcoatMap, uniforms.clearcoatMapTransform); 27940 27941 } 27942 27943 if (material.clearcoatRoughnessMap) { 27944 27945 uniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap; 27946 27947 refreshTransformUniform(material.clearcoatRoughnessMap, uniforms.clearcoatRoughnessMapTransform); 27948 27949 } 27950 27951 if (material.clearcoatNormalMap) { 27952 27953 uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap; 27954 27955 refreshTransformUniform(material.clearcoatNormalMap, uniforms.clearcoatNormalMapTransform); 27956 27957 uniforms.clearcoatNormalScale.value.copy(material.clearcoatNormalScale); 27958 27959 if (material.side === BackSide) { 27960 27961 uniforms.clearcoatNormalScale.value.negate(); 27962 27963 } 27964 27965 } 27966 27967 } 27968 27969 if (material.iridescence > 0) { 27970 27971 uniforms.iridescence.value = material.iridescence; 27972 uniforms.iridescenceIOR.value = material.iridescenceIOR; 27973 uniforms.iridescenceThicknessMinimum.value = material.iridescenceThicknessRange[0]; 27974 uniforms.iridescenceThicknessMaximum.value = material.iridescenceThicknessRange[1]; 27975 27976 if (material.iridescenceMap) { 27977 27978 uniforms.iridescenceMap.value = material.iridescenceMap; 27979 27980 refreshTransformUniform(material.iridescenceMap, uniforms.iridescenceMapTransform); 27981 27982 } 27983 27984 if (material.iridescenceThicknessMap) { 27985 27986 uniforms.iridescenceThicknessMap.value = material.iridescenceThicknessMap; 27987 27988 refreshTransformUniform(material.iridescenceThicknessMap, uniforms.iridescenceThicknessMapTransform); 27989 27990 } 27991 27992 } 27993 27994 if (material.transmission > 0) { 27995 27996 uniforms.transmission.value = material.transmission; 27997 uniforms.transmissionSamplerMap.value = transmissionRenderTarget.texture; 27998 uniforms.transmissionSamplerSize.value.set(transmissionRenderTarget.width, transmissionRenderTarget.height); 27999 28000 if (material.transmissionMap) { 28001 28002 uniforms.transmissionMap.value = material.transmissionMap; 28003 28004 refreshTransformUniform(material.transmissionMap, uniforms.transmissionMapTransform); 28005 28006 } 28007 28008 uniforms.thickness.value = material.thickness; 28009 28010 if (material.thicknessMap) { 28011 28012 uniforms.thicknessMap.value = material.thicknessMap; 28013 28014 refreshTransformUniform(material.thicknessMap, uniforms.thicknessMapTransform); 28015 28016 } 28017 28018 uniforms.attenuationDistance.value = material.attenuationDistance; 28019 uniforms.attenuationColor.value.copy(material.attenuationColor); 28020 28021 } 28022 28023 if (material.anisotropy > 0) { 28024 28025 uniforms.anisotropyVector.value.set(material.anisotropy * Math.cos(material.anisotropyRotation), material.anisotropy * Math.sin(material.anisotropyRotation)); 28026 28027 if (material.anisotropyMap) { 28028 28029 uniforms.anisotropyMap.value = material.anisotropyMap; 28030 28031 refreshTransformUniform(material.anisotropyMap, uniforms.anisotropyMapTransform); 28032 28033 } 28034 28035 } 28036 28037 uniforms.specularIntensity.value = material.specularIntensity; 28038 uniforms.specularColor.value.copy(material.specularColor); 28039 28040 if (material.specularColorMap) { 28041 28042 uniforms.specularColorMap.value = material.specularColorMap; 28043 28044 refreshTransformUniform(material.specularColorMap, uniforms.specularColorMapTransform); 28045 28046 } 28047 28048 if (material.specularIntensityMap) { 28049 28050 uniforms.specularIntensityMap.value = material.specularIntensityMap; 28051 28052 refreshTransformUniform(material.specularIntensityMap, uniforms.specularIntensityMapTransform); 28053 28054 } 28055 28056 } 28057 28058 function refreshUniformsMatcap(uniforms, material) { 28059 28060 if (material.matcap) { 28061 28062 uniforms.matcap.value = material.matcap; 28063 28064 } 28065 28066 } 28067 28068 function refreshUniformsDistance(uniforms, material) { 28069 28070 const light = properties.get(material).light; 28071 28072 uniforms.referencePosition.value.setFromMatrixPosition(light.matrixWorld); 28073 uniforms.nearDistance.value = light.shadow.camera.near; 28074 uniforms.farDistance.value = light.shadow.camera.far; 28075 28076 } 28077 28078 return { 28079 refreshFogUniforms: refreshFogUniforms, 28080 refreshMaterialUniforms: refreshMaterialUniforms 28081 }; 28082 28083} 28084 28085function WebGLUniformsGroups(gl, info, capabilities, state) { 28086 28087 let buffers = {}; 28088 let updateList = {}; 28089 let allocatedBindingPoints = []; 28090 28091 const maxBindingPoints = (capabilities.isWebGL2) ? gl.getParameter(gl.MAX_UNIFORM_BUFFER_BINDINGS) : 0; // binding points are global whereas block indices are per shader program 28092 28093 function bind(uniformsGroup, program) { 28094 28095 const webglProgram = program.program; 28096 state.uniformBlockBinding(uniformsGroup, webglProgram); 28097 28098 } 28099 28100 function update(uniformsGroup, program) { 28101 28102 let buffer = buffers[uniformsGroup.id]; 28103 28104 if (buffer === undefined) { 28105 28106 prepareUniformsGroup(uniformsGroup); 28107 28108 buffer = createBuffer(uniformsGroup); 28109 buffers[uniformsGroup.id] = buffer; 28110 28111 uniformsGroup.addEventListener('dispose', onUniformsGroupsDispose); 28112 28113 } 28114 28115 // ensure to update the binding points/block indices mapping for this program 28116 28117 const webglProgram = program.program; 28118 state.updateUBOMapping(uniformsGroup, webglProgram); 28119 28120 // update UBO once per frame 28121 28122 const frame = info.render.frame; 28123 28124 if (updateList[uniformsGroup.id] !== frame) { 28125 28126 updateBufferData(uniformsGroup); 28127 28128 updateList[uniformsGroup.id] = frame; 28129 28130 } 28131 28132 } 28133 28134 function createBuffer(uniformsGroup) { 28135 28136 // the setup of an UBO is independent of a particular shader program but global 28137 28138 const bindingPointIndex = allocateBindingPointIndex(); 28139 uniformsGroup.__bindingPointIndex = bindingPointIndex; 28140 28141 const buffer = gl.createBuffer(); 28142 const size = uniformsGroup.__size; 28143 const usage = uniformsGroup.usage; 28144 28145 gl.bindBuffer(gl.UNIFORM_BUFFER, buffer); 28146 gl.bufferData(gl.UNIFORM_BUFFER, size, usage); 28147 gl.bindBuffer(gl.UNIFORM_BUFFER, null); 28148 gl.bindBufferBase(gl.UNIFORM_BUFFER, bindingPointIndex, buffer); 28149 28150 return buffer; 28151 28152 } 28153 28154 function allocateBindingPointIndex() { 28155 28156 for (let i = 0; i < maxBindingPoints; i++) { 28157 28158 if (allocatedBindingPoints.indexOf(i) === - 1) { 28159 28160 allocatedBindingPoints.push(i); 28161 return i; 28162 28163 } 28164 28165 } 28166 28167 console.error('THREE.WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached.'); 28168 28169 return 0; 28170 28171 } 28172 28173 function updateBufferData(uniformsGroup) { 28174 28175 const buffer = buffers[uniformsGroup.id]; 28176 const uniforms = uniformsGroup.uniforms; 28177 const cache = uniformsGroup.__cache; 28178 28179 gl.bindBuffer(gl.UNIFORM_BUFFER, buffer); 28180 28181 for (let i = 0, il = uniforms.length; i < il; i++) { 28182 28183 const uniformArray = Array.isArray(uniforms[i]) ? uniforms[i] : [uniforms[i]]; 28184 28185 for (let j = 0, jl = uniformArray.length; j < jl; j++) { 28186 28187 const uniform = uniformArray[j]; 28188 28189 if (hasUniformChanged(uniform, i, j, cache) === true) { 28190 28191 const offset = uniform.__offset; 28192 28193 const values = Array.isArray(uniform.value) ? uniform.value : [uniform.value]; 28194 28195 let arrayOffset = 0; 28196 28197 for (let k = 0; k < values.length; k++) { 28198 28199 const value = values[k]; 28200 28201 const info = getUniformSize(value); 28202 28203 // TODO add integer and struct support 28204 if (typeof value === 'number' || typeof value === 'boolean') { 28205 28206 uniform.__data[0] = value; 28207 gl.bufferSubData(gl.UNIFORM_BUFFER, offset + arrayOffset, uniform.__data); 28208 28209 } else if (value.isMatrix3) { 28210 28211 // manually converting 3x3 to 3x4 28212 28213 uniform.__data[0] = value.elements[0]; 28214 uniform.__data[1] = value.elements[1]; 28215 uniform.__data[2] = value.elements[2]; 28216 uniform.__data[3] = 0; 28217 uniform.__data[4] = value.elements[3]; 28218 uniform.__data[5] = value.elements[4]; 28219 uniform.__data[6] = value.elements[5]; 28220 uniform.__data[7] = 0; 28221 uniform.__data[8] = value.elements[6]; 28222 uniform.__data[9] = value.elements[7]; 28223 uniform.__data[10] = value.elements[8]; 28224 uniform.__data[11] = 0; 28225 28226 } else { 28227 28228 value.toArray(uniform.__data, arrayOffset); 28229 28230 arrayOffset += info.storage / Float32Array.BYTES_PER_ELEMENT; 28231 28232 } 28233 28234 } 28235 28236 gl.bufferSubData(gl.UNIFORM_BUFFER, offset, uniform.__data); 28237 28238 } 28239 28240 } 28241 28242 } 28243 28244 gl.bindBuffer(gl.UNIFORM_BUFFER, null); 28245 28246 } 28247 28248 function hasUniformChanged(uniform, index, indexArray, cache) { 28249 28250 const value = uniform.value; 28251 const indexString = index + '_' + indexArray; 28252 28253 if (cache[indexString] === undefined) { 28254 28255 // cache entry does not exist so far 28256 28257 if (typeof value === 'number' || typeof value === 'boolean') { 28258 28259 cache[indexString] = value; 28260 28261 } else { 28262 28263 cache[indexString] = value.clone(); 28264 28265 } 28266 28267 return true; 28268 28269 } else { 28270 28271 const cachedObject = cache[indexString]; 28272 28273 // compare current value with cached entry 28274 28275 if (typeof value === 'number' || typeof value === 'boolean') { 28276 28277 if (cachedObject !== value) { 28278 28279 cache[indexString] = value; 28280 return true; 28281 28282 } 28283 28284 } else { 28285 28286 if (cachedObject.equals(value) === false) { 28287 28288 cachedObject.copy(value); 28289 return true; 28290 28291 } 28292 28293 } 28294 28295 } 28296 28297 return false; 28298 28299 } 28300 28301 function prepareUniformsGroup(uniformsGroup) { 28302 28303 // determine total buffer size according to the STD140 layout 28304 // Hint: STD140 is the only supported layout in WebGL 2 28305 28306 const uniforms = uniformsGroup.uniforms; 28307 28308 let offset = 0; // global buffer offset in bytes 28309 const chunkSize = 16; // size of a chunk in bytes 28310 28311 for (let i = 0, l = uniforms.length; i < l; i++) { 28312 28313 const uniformArray = Array.isArray(uniforms[i]) ? uniforms[i] : [uniforms[i]]; 28314 28315 for (let j = 0, jl = uniformArray.length; j < jl; j++) { 28316 28317 const uniform = uniformArray[j]; 28318 28319 const values = Array.isArray(uniform.value) ? uniform.value : [uniform.value]; 28320 28321 for (let k = 0, kl = values.length; k < kl; k++) { 28322 28323 const value = values[k]; 28324 28325 const info = getUniformSize(value); 28326 28327 // Calculate the chunk offset 28328 const chunkOffsetUniform = offset % chunkSize; 28329 28330 // Check for chunk overflow 28331 if (chunkOffsetUniform !== 0 && (chunkSize - chunkOffsetUniform) < info.boundary) { 28332 28333 // Add padding and adjust offset 28334 offset += (chunkSize - chunkOffsetUniform); 28335 28336 } 28337 28338 // the following two properties will be used for partial buffer updates 28339 28340 uniform.__data = new Float32Array(info.storage / Float32Array.BYTES_PER_ELEMENT); 28341 uniform.__offset = offset; 28342 28343 28344 // Update the global offset 28345 offset += info.storage; 28346 28347 28348 } 28349 28350 } 28351 28352 } 28353 28354 // ensure correct final padding 28355 28356 const chunkOffset = offset % chunkSize; 28357 28358 if (chunkOffset > 0) offset += (chunkSize - chunkOffset); 28359 28360 // 28361 28362 uniformsGroup.__size = offset; 28363 uniformsGroup.__cache = {}; 28364 28365 return this; 28366 28367 } 28368 28369 function getUniformSize(value) { 28370 28371 const info = { 28372 boundary: 0, // bytes 28373 storage: 0 // bytes 28374 }; 28375 28376 // determine sizes according to STD140 28377 28378 if (typeof value === 'number' || typeof value === 'boolean') { 28379 28380 // float/int/bool 28381 28382 info.boundary = 4; 28383 info.storage = 4; 28384 28385 } else if (value.isVector2) { 28386 28387 // vec2 28388 28389 info.boundary = 8; 28390 info.storage = 8; 28391 28392 } else if (value.isVector3 || value.isColor) { 28393 28394 // vec3 28395 28396 info.boundary = 16; 28397 info.storage = 12; // evil: vec3 must start on a 16-byte boundary but it only consumes 12 bytes 28398 28399 } else if (value.isVector4) { 28400 28401 // vec4 28402 28403 info.boundary = 16; 28404 info.storage = 16; 28405 28406 } else if (value.isMatrix3) { 28407 28408 // mat3 (in STD140 a 3x3 matrix is represented as 3x4) 28409 28410 info.boundary = 48; 28411 info.storage = 48; 28412 28413 } else if (value.isMatrix4) { 28414 28415 // mat4 28416 28417 info.boundary = 64; 28418 info.storage = 64; 28419 28420 } else if (value.isTexture) { 28421 28422 console.warn('THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.'); 28423 28424 } else { 28425 28426 console.warn('THREE.WebGLRenderer: Unsupported uniform value type.', value); 28427 28428 } 28429 28430 return info; 28431 28432 } 28433 28434 function onUniformsGroupsDispose(event) { 28435 28436 const uniformsGroup = event.target; 28437 28438 uniformsGroup.removeEventListener('dispose', onUniformsGroupsDispose); 28439 28440 const index = allocatedBindingPoints.indexOf(uniformsGroup.__bindingPointIndex); 28441 allocatedBindingPoints.splice(index, 1); 28442 28443 gl.deleteBuffer(buffers[uniformsGroup.id]); 28444 28445 delete buffers[uniformsGroup.id]; 28446 delete updateList[uniformsGroup.id]; 28447 28448 } 28449 28450 function dispose() { 28451 28452 for (const id in buffers) { 28453 28454 gl.deleteBuffer(buffers[id]); 28455 28456 } 28457 28458 allocatedBindingPoints = []; 28459 buffers = {}; 28460 updateList = {}; 28461 28462 } 28463 28464 return { 28465 28466 bind: bind, 28467 update: update, 28468 28469 dispose: dispose 28470 28471 }; 28472 28473} 28474 28475class WebGLRenderer { 28476 28477 constructor(parameters = {}) { 28478 28479 const { 28480 canvas = createCanvasElement(), 28481 context = null, 28482 depth = true, 28483 stencil = true, 28484 alpha = false, 28485 antialias = false, 28486 premultipliedAlpha = true, 28487 preserveDrawingBuffer = false, 28488 powerPreference = 'default', 28489 failIfMajorPerformanceCaveat = false, 28490 } = parameters; 28491 28492 this.isWebGLRenderer = true; 28493 28494 let _alpha; 28495 28496 if (context !== null) { 28497 28498 _alpha = context.getContextAttributes().alpha; 28499 28500 } else { 28501 28502 _alpha = alpha; 28503 28504 } 28505 28506 const uintClearColor = new Uint32Array(4); 28507 const intClearColor = new Int32Array(4); 28508 28509 let currentRenderList = null; 28510 let currentRenderState = null; 28511 28512 // render() can be called from within a callback triggered by another render. 28513 // We track this so that the nested render call gets its list and state isolated from the parent render call. 28514 28515 const renderListStack = []; 28516 const renderStateStack = []; 28517 28518 // public properties 28519 28520 this.domElement = canvas; 28521 28522 // Debug configuration container 28523 this.debug = { 28524 28525 /** 28526 * Enables error checking and reporting when shader programs are being compiled 28527 * @type {boolean} 28528 */ 28529 checkShaderErrors: true, 28530 /** 28531 * Callback for custom error reporting. 28532 * @type {?Function} 28533 */ 28534 onShaderError: null 28535 }; 28536 28537 // clearing 28538 28539 this.autoClear = true; 28540 this.autoClearColor = true; 28541 this.autoClearDepth = true; 28542 this.autoClearStencil = true; 28543 28544 // scene graph 28545 28546 this.sortObjects = true; 28547 28548 // user-defined clipping 28549 28550 this.clippingPlanes = []; 28551 this.localClippingEnabled = false; 28552 28553 // physically based shading 28554 28555 this._outputColorSpace = SRGBColorSpace; 28556 28557 // physical lights 28558 28559 this._useLegacyLights = false; 28560 28561 // tone mapping 28562 28563 this.toneMapping = NoToneMapping; 28564 this.toneMappingExposure = 1.0; 28565 28566 // internal properties 28567 28568 const _this = this; 28569 28570 let _isContextLost = false; 28571 28572 // internal state cache 28573 28574 let _currentActiveCubeFace = 0; 28575 let _currentActiveMipmapLevel = 0; 28576 let _currentRenderTarget = null; 28577 let _currentMaterialId = - 1; 28578 28579 let _currentCamera = null; 28580 28581 const _currentViewport = new Vector4(); 28582 const _currentScissor = new Vector4(); 28583 let _currentScissorTest = null; 28584 28585 const _currentClearColor = new Color(0x000000); 28586 let _currentClearAlpha = 0; 28587 28588 // 28589 28590 let _width = canvas.width; 28591 let _height = canvas.height; 28592 28593 let _pixelRatio = 1; 28594 let _opaqueSort = null; 28595 let _transparentSort = null; 28596 28597 const _viewport = new Vector4(0, 0, _width, _height); 28598 const _scissor = new Vector4(0, 0, _width, _height); 28599 let _scissorTest = false; 28600 28601 // frustum 28602 28603 const _frustum = new Frustum(); 28604 28605 // clipping 28606 28607 let _clippingEnabled = false; 28608 let _localClippingEnabled = false; 28609 28610 // transmission 28611 28612 let _transmissionRenderTarget = null; 28613 28614 // camera matrices cache 28615 28616 const _projScreenMatrix = new Matrix4(); 28617 28618 const _vector2 = new Vector2(); 28619 const _vector3 = new Vector3(); 28620 28621 const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true }; 28622 28623 function getTargetPixelRatio() { 28624 28625 return _currentRenderTarget === null ? _pixelRatio : 1; 28626 28627 } 28628 28629 // initialize 28630 28631 let _gl = context; 28632 28633 function getContext(contextNames, contextAttributes) { 28634 28635 for (let i = 0; i < contextNames.length; i++) { 28636 28637 const contextName = contextNames[i]; 28638 const context = canvas.getContext(contextName, contextAttributes); 28639 if (context !== null) return context; 28640 28641 } 28642 28643 return null; 28644 28645 } 28646 28647 try { 28648 28649 const contextAttributes = { 28650 alpha: true, 28651 depth, 28652 stencil, 28653 antialias, 28654 premultipliedAlpha, 28655 preserveDrawingBuffer, 28656 powerPreference, 28657 failIfMajorPerformanceCaveat, 28658 }; 28659 28660 // OffscreenCanvas does not have setAttribute, see #22811 28661 if ('setAttribute' in canvas) canvas.setAttribute('data-engine', `three.js r${REVISION}`); 28662 28663 // event listeners must be registered before WebGL context is created, see #12753 28664 canvas.addEventListener('webglcontextlost', onContextLost, false); 28665 canvas.addEventListener('webglcontextrestored', onContextRestore, false); 28666 canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false); 28667 28668 if (_gl === null) { 28669 28670 const contextNames = ['webgl2', 'webgl', 'experimental-webgl']; 28671 28672 if (_this.isWebGL1Renderer === true) { 28673 28674 contextNames.shift(); 28675 28676 } 28677 28678 _gl = getContext(contextNames, contextAttributes); 28679 28680 if (_gl === null) { 28681 28682 if (getContext(contextNames)) { 28683 28684 throw new Error('Error creating WebGL context with your selected attributes.'); 28685 28686 } else { 28687 28688 throw new Error('Error creating WebGL context.'); 28689 28690 } 28691 28692 } 28693 28694 } 28695 28696 if (typeof WebGLRenderingContext !== 'undefined' && _gl instanceof WebGLRenderingContext) { // @deprecated, r153 28697 28698 console.warn('THREE.WebGLRenderer: WebGL 1 support was deprecated in r153 and will be removed in r163.'); 28699 28700 } 28701 28702 // Some experimental-webgl implementations do not have getShaderPrecisionFormat 28703 28704 if (_gl.getShaderPrecisionFormat === undefined) { 28705 28706 _gl.getShaderPrecisionFormat = function () { 28707 28708 return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; 28709 28710 }; 28711 28712 } 28713 28714 } catch (error) { 28715 28716 console.error('THREE.WebGLRenderer: ' + error.message); 28717 throw error; 28718 28719 } 28720 28721 let extensions, capabilities, state, info; 28722 let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects; 28723 let programCache, materials, renderLists, renderStates, clipping, shadowMap; 28724 28725 let background, morphtargets, bufferRenderer, indexedBufferRenderer; 28726 28727 let utils, bindingStates, uniformsGroups; 28728 28729 function initGLContext() { 28730 28731 extensions = new WebGLExtensions(_gl); 28732 28733 capabilities = new WebGLCapabilities(_gl, extensions, parameters); 28734 28735 extensions.init(capabilities); 28736 28737 utils = new WebGLUtils(_gl, extensions, capabilities); 28738 28739 state = new WebGLState(_gl, extensions, capabilities); 28740 28741 info = new WebGLInfo(_gl); 28742 properties = new WebGLProperties(); 28743 textures = new WebGLTextures(_gl, extensions, state, properties, capabilities, utils, info); 28744 cubemaps = new WebGLCubeMaps(_this); 28745 cubeuvmaps = new WebGLCubeUVMaps(_this); 28746 attributes = new WebGLAttributes(_gl, capabilities); 28747 bindingStates = new WebGLBindingStates(_gl, extensions, attributes, capabilities); 28748 geometries = new WebGLGeometries(_gl, attributes, info, bindingStates); 28749 objects = new WebGLObjects(_gl, geometries, attributes, info); 28750 morphtargets = new WebGLMorphtargets(_gl, capabilities, textures); 28751 clipping = new WebGLClipping(properties); 28752 programCache = new WebGLPrograms(_this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping); 28753 materials = new WebGLMaterials(_this, properties); 28754 renderLists = new WebGLRenderLists(); 28755 renderStates = new WebGLRenderStates(extensions, capabilities); 28756 background = new WebGLBackground(_this, cubemaps, cubeuvmaps, state, objects, _alpha, premultipliedAlpha); 28757 shadowMap = new WebGLShadowMap(_this, objects, capabilities); 28758 uniformsGroups = new WebGLUniformsGroups(_gl, info, capabilities, state); 28759 28760 bufferRenderer = new WebGLBufferRenderer(_gl, extensions, info, capabilities); 28761 indexedBufferRenderer = new WebGLIndexedBufferRenderer(_gl, extensions, info, capabilities); 28762 28763 info.programs = programCache.programs; 28764 28765 _this.capabilities = capabilities; 28766 _this.extensions = extensions; 28767 _this.properties = properties; 28768 _this.renderLists = renderLists; 28769 _this.shadowMap = shadowMap; 28770 _this.state = state; 28771 _this.info = info; 28772 28773 } 28774 28775 initGLContext(); 28776 28777 // xr 28778 28779 const xr = new WebXRManager(_this, _gl); 28780 28781 this.xr = xr; 28782 28783 // API 28784 28785 this.getContext = function () { 28786 28787 return _gl; 28788 28789 }; 28790 28791 this.getContextAttributes = function () { 28792 28793 return _gl.getContextAttributes(); 28794 28795 }; 28796 28797 this.forceContextLoss = function () { 28798 28799 const extension = extensions.get('WEBGL_lose_context'); 28800 if (extension) extension.loseContext(); 28801 28802 }; 28803 28804 this.forceContextRestore = function () { 28805 28806 const extension = extensions.get('WEBGL_lose_context'); 28807 if (extension) extension.restoreContext(); 28808 28809 }; 28810 28811 this.getPixelRatio = function () { 28812 28813 return _pixelRatio; 28814 28815 }; 28816 28817 this.setPixelRatio = function (value) { 28818 28819 if (value === undefined) return; 28820 28821 _pixelRatio = value; 28822 28823 this.setSize(_width, _height, false); 28824 28825 }; 28826 28827 this.getSize = function (target) { 28828 28829 return target.set(_width, _height); 28830 28831 }; 28832 28833 this.setSize = function (width, height, updateStyle = true) { 28834 28835 if (xr.isPresenting) { 28836 28837 console.warn('THREE.WebGLRenderer: Can\'t change size while VR device is presenting.'); 28838 return; 28839 28840 } 28841 28842 _width = width; 28843 _height = height; 28844 28845 canvas.width = Math.floor(width * _pixelRatio); 28846 canvas.height = Math.floor(height * _pixelRatio); 28847 28848 if (updateStyle === true) { 28849 28850 canvas.style.width = width + 'px'; 28851 canvas.style.height = height + 'px'; 28852 28853 } 28854 28855 this.setViewport(0, 0, width, height); 28856 28857 }; 28858 28859 this.getDrawingBufferSize = function (target) { 28860 28861 return target.set(_width * _pixelRatio, _height * _pixelRatio).floor(); 28862 28863 }; 28864 28865 this.setDrawingBufferSize = function (width, height, pixelRatio) { 28866 28867 _width = width; 28868 _height = height; 28869 28870 _pixelRatio = pixelRatio; 28871 28872 canvas.width = Math.floor(width * pixelRatio); 28873 canvas.height = Math.floor(height * pixelRatio); 28874 28875 this.setViewport(0, 0, width, height); 28876 28877 }; 28878 28879 this.getCurrentViewport = function (target) { 28880 28881 return target.copy(_currentViewport); 28882 28883 }; 28884 28885 this.getViewport = function (target) { 28886 28887 return target.copy(_viewport); 28888 28889 }; 28890 28891 this.setViewport = function (x, y, width, height) { 28892 28893 if (x.isVector4) { 28894 28895 _viewport.set(x.x, x.y, x.z, x.w); 28896 28897 } else { 28898 28899 _viewport.set(x, y, width, height); 28900 28901 } 28902 28903 state.viewport(_currentViewport.copy(_viewport).multiplyScalar(_pixelRatio).floor()); 28904 28905 }; 28906 28907 this.getScissor = function (target) { 28908 28909 return target.copy(_scissor); 28910 28911 }; 28912 28913 this.setScissor = function (x, y, width, height) { 28914 28915 if (x.isVector4) { 28916 28917 _scissor.set(x.x, x.y, x.z, x.w); 28918 28919 } else { 28920 28921 _scissor.set(x, y, width, height); 28922 28923 } 28924 28925 state.scissor(_currentScissor.copy(_scissor).multiplyScalar(_pixelRatio).floor()); 28926 28927 }; 28928 28929 this.getScissorTest = function () { 28930 28931 return _scissorTest; 28932 28933 }; 28934 28935 this.setScissorTest = function (boolean) { 28936 28937 state.setScissorTest(_scissorTest = boolean); 28938 28939 }; 28940 28941 this.setOpaqueSort = function (method) { 28942 28943 _opaqueSort = method; 28944 28945 }; 28946 28947 this.setTransparentSort = function (method) { 28948 28949 _transparentSort = method; 28950 28951 }; 28952 28953 // Clearing 28954 28955 this.getClearColor = function (target) { 28956 28957 return target.copy(background.getClearColor()); 28958 28959 }; 28960 28961 this.setClearColor = function () { 28962 28963 background.setClearColor.apply(background, arguments); 28964 28965 }; 28966 28967 this.getClearAlpha = function () { 28968 28969 return background.getClearAlpha(); 28970 28971 }; 28972 28973 this.setClearAlpha = function () { 28974 28975 background.setClearAlpha.apply(background, arguments); 28976 28977 }; 28978 28979 this.clear = function (color = true, depth = true, stencil = true) { 28980 28981 let bits = 0; 28982 28983 if (color) { 28984 28985 // check if we're trying to clear an integer target 28986 let isIntegerFormat = false; 28987 if (_currentRenderTarget !== null) { 28988 28989 const targetFormat = _currentRenderTarget.texture.format; 28990 isIntegerFormat = targetFormat === RGBAIntegerFormat || 28991 targetFormat === RGIntegerFormat || 28992 targetFormat === RedIntegerFormat; 28993 28994 } 28995 28996 // use the appropriate clear functions to clear the target if it's a signed 28997 // or unsigned integer target 28998 if (isIntegerFormat) { 28999 29000 const targetType = _currentRenderTarget.texture.type; 29001 const isUnsignedType = targetType === UnsignedByteType || 29002 targetType === UnsignedIntType || 29003 targetType === UnsignedShortType || 29004 targetType === UnsignedInt248Type || 29005 targetType === UnsignedShort4444Type || 29006 targetType === UnsignedShort5551Type; 29007 29008 const clearColor = background.getClearColor(); 29009 const a = background.getClearAlpha(); 29010 const r = clearColor.r; 29011 const g = clearColor.g; 29012 const b = clearColor.b; 29013 29014 if (isUnsignedType) { 29015 29016 uintClearColor[0] = r; 29017 uintClearColor[1] = g; 29018 uintClearColor[2] = b; 29019 uintClearColor[3] = a; 29020 _gl.clearBufferuiv(_gl.COLOR, 0, uintClearColor); 29021 29022 } else { 29023 29024 intClearColor[0] = r; 29025 intClearColor[1] = g; 29026 intClearColor[2] = b; 29027 intClearColor[3] = a; 29028 _gl.clearBufferiv(_gl.COLOR, 0, intClearColor); 29029 29030 } 29031 29032 } else { 29033 29034 bits |= _gl.COLOR_BUFFER_BIT; 29035 29036 } 29037 29038 } 29039 29040 if (depth) bits |= _gl.DEPTH_BUFFER_BIT; 29041 if (stencil) { 29042 29043 bits |= _gl.STENCIL_BUFFER_BIT; 29044 this.state.buffers.stencil.setMask(0xffffffff); 29045 29046 } 29047 29048 _gl.clear(bits); 29049 29050 }; 29051 29052 this.clearColor = function () { 29053 29054 this.clear(true, false, false); 29055 29056 }; 29057 29058 this.clearDepth = function () { 29059 29060 this.clear(false, true, false); 29061 29062 }; 29063 29064 this.clearStencil = function () { 29065 29066 this.clear(false, false, true); 29067 29068 }; 29069 29070 // 29071 29072 this.dispose = function () { 29073 29074 canvas.removeEventListener('webglcontextlost', onContextLost, false); 29075 canvas.removeEventListener('webglcontextrestored', onContextRestore, false); 29076 canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false); 29077 29078 renderLists.dispose(); 29079 renderStates.dispose(); 29080 properties.dispose(); 29081 cubemaps.dispose(); 29082 cubeuvmaps.dispose(); 29083 objects.dispose(); 29084 bindingStates.dispose(); 29085 uniformsGroups.dispose(); 29086 programCache.dispose(); 29087 29088 xr.dispose(); 29089 29090 xr.removeEventListener('sessionstart', onXRSessionStart); 29091 xr.removeEventListener('sessionend', onXRSessionEnd); 29092 29093 if (_transmissionRenderTarget) { 29094 29095 _transmissionRenderTarget.dispose(); 29096 _transmissionRenderTarget = null; 29097 29098 } 29099 29100 animation.stop(); 29101 29102 }; 29103 29104 // Events 29105 29106 function onContextLost(event) { 29107 29108 event.preventDefault(); 29109 29110 console.log('THREE.WebGLRenderer: Context Lost.'); 29111 29112 _isContextLost = true; 29113 29114 } 29115 29116 function onContextRestore( /* event */) { 29117 29118 console.log('THREE.WebGLRenderer: Context Restored.'); 29119 29120 _isContextLost = false; 29121 29122 const infoAutoReset = info.autoReset; 29123 const shadowMapEnabled = shadowMap.enabled; 29124 const shadowMapAutoUpdate = shadowMap.autoUpdate; 29125 const shadowMapNeedsUpdate = shadowMap.needsUpdate; 29126 const shadowMapType = shadowMap.type; 29127 29128 initGLContext(); 29129 29130 info.autoReset = infoAutoReset; 29131 shadowMap.enabled = shadowMapEnabled; 29132 shadowMap.autoUpdate = shadowMapAutoUpdate; 29133 shadowMap.needsUpdate = shadowMapNeedsUpdate; 29134 shadowMap.type = shadowMapType; 29135 29136 } 29137 29138 function onContextCreationError(event) { 29139 29140 console.error('THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage); 29141 29142 } 29143 29144 function onMaterialDispose(event) { 29145 29146 const material = event.target; 29147 29148 material.removeEventListener('dispose', onMaterialDispose); 29149 29150 deallocateMaterial(material); 29151 29152 } 29153 29154 // Buffer deallocation 29155 29156 function deallocateMaterial(material) { 29157 29158 releaseMaterialProgramReferences(material); 29159 29160 properties.remove(material); 29161 29162 } 29163 29164 29165 function releaseMaterialProgramReferences(material) { 29166 29167 const programs = properties.get(material).programs; 29168 29169 if (programs !== undefined) { 29170 29171 programs.forEach(function (program) { 29172 29173 programCache.releaseProgram(program); 29174 29175 }); 29176 29177 if (material.isShaderMaterial) { 29178 29179 programCache.releaseShaderCache(material); 29180 29181 } 29182 29183 } 29184 29185 } 29186 29187 // Buffer rendering 29188 29189 this.renderBufferDirect = function (camera, scene, geometry, material, object, group) { 29190 29191 if (scene === null) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null) 29192 29193 const frontFaceCW = (object.isMesh && object.matrixWorld.determinant() < 0); 29194 29195 const program = setProgram(camera, scene, geometry, material, object); 29196 29197 state.setMaterial(material, frontFaceCW); 29198 29199 // 29200 29201 let index = geometry.index; 29202 let rangeFactor = 1; 29203 29204 if (material.wireframe === true) { 29205 29206 index = geometries.getWireframeAttribute(geometry); 29207 29208 if (index === undefined) return; 29209 29210 rangeFactor = 2; 29211 29212 } 29213 29214 // 29215 29216 const drawRange = geometry.drawRange; 29217 const position = geometry.attributes.position; 29218 29219 let drawStart = drawRange.start * rangeFactor; 29220 let drawEnd = (drawRange.start + drawRange.count) * rangeFactor; 29221 29222 if (group !== null) { 29223 29224 drawStart = Math.max(drawStart, group.start * rangeFactor); 29225 drawEnd = Math.min(drawEnd, (group.start + group.count) * rangeFactor); 29226 29227 } 29228 29229 if (index !== null) { 29230 29231 drawStart = Math.max(drawStart, 0); 29232 drawEnd = Math.min(drawEnd, index.count); 29233 29234 } else if (position !== undefined && position !== null) { 29235 29236 drawStart = Math.max(drawStart, 0); 29237 drawEnd = Math.min(drawEnd, position.count); 29238 29239 } 29240 29241 const drawCount = drawEnd - drawStart; 29242 29243 if (drawCount < 0 || drawCount === Infinity) return; 29244 29245 // 29246 29247 bindingStates.setup(object, material, program, geometry, index); 29248 29249 let attribute; 29250 let renderer = bufferRenderer; 29251 29252 if (index !== null) { 29253 29254 attribute = attributes.get(index); 29255 29256 renderer = indexedBufferRenderer; 29257 renderer.setIndex(attribute); 29258 29259 } 29260 29261 // 29262 29263 if (object.isMesh) { 29264 29265 if (material.wireframe === true) { 29266 29267 state.setLineWidth(material.wireframeLinewidth * getTargetPixelRatio()); 29268 renderer.setMode(_gl.LINES); 29269 29270 } else { 29271 29272 renderer.setMode(_gl.TRIANGLES); 29273 29274 } 29275 29276 } else if (object.isLine) { 29277 29278 let lineWidth = material.linewidth; 29279 29280 if (lineWidth === undefined) lineWidth = 1; // Not using Line*Material 29281 29282 state.setLineWidth(lineWidth * getTargetPixelRatio()); 29283 29284 if (object.isLineSegments) { 29285 29286 renderer.setMode(_gl.LINES); 29287 29288 } else if (object.isLineLoop) { 29289 29290 renderer.setMode(_gl.LINE_LOOP); 29291 29292 } else { 29293 29294 renderer.setMode(_gl.LINE_STRIP); 29295 29296 } 29297 29298 } else if (object.isPoints) { 29299 29300 renderer.setMode(_gl.POINTS); 29301 29302 } else if (object.isSprite) { 29303 29304 renderer.setMode(_gl.TRIANGLES); 29305 29306 } 29307 29308 if (object.isBatchedMesh) { 29309 29310 renderer.renderMultiDraw(object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount); 29311 29312 } else if (object.isInstancedMesh) { 29313 29314 renderer.renderInstances(drawStart, drawCount, object.count); 29315 29316 } else if (geometry.isInstancedBufferGeometry) { 29317 29318 const maxInstanceCount = geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity; 29319 const instanceCount = Math.min(geometry.instanceCount, maxInstanceCount); 29320 29321 renderer.renderInstances(drawStart, drawCount, instanceCount); 29322 29323 } else { 29324 29325 renderer.render(drawStart, drawCount); 29326 29327 } 29328 29329 }; 29330 29331 // Compile 29332 29333 function prepareMaterial(material, scene, object) { 29334 29335 if (material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false) { 29336 29337 material.side = BackSide; 29338 material.needsUpdate = true; 29339 getProgram(material, scene, object); 29340 29341 material.side = FrontSide; 29342 material.needsUpdate = true; 29343 getProgram(material, scene, object); 29344 29345 material.side = DoubleSide; 29346 29347 } else { 29348 29349 getProgram(material, scene, object); 29350 29351 } 29352 29353 } 29354 29355 this.compile = function (scene, camera, targetScene = null) { 29356 29357 if (targetScene === null) targetScene = scene; 29358 29359 currentRenderState = renderStates.get(targetScene); 29360 currentRenderState.init(); 29361 29362 renderStateStack.push(currentRenderState); 29363 29364 // gather lights from both the target scene and the new object that will be added to the scene. 29365 29366 targetScene.traverseVisible(function (object) { 29367 29368 if (object.isLight && object.layers.test(camera.layers)) { 29369 29370 currentRenderState.pushLight(object); 29371 29372 if (object.castShadow) { 29373 29374 currentRenderState.pushShadow(object); 29375 29376 } 29377 29378 } 29379 29380 }); 29381 29382 if (scene !== targetScene) { 29383 29384 scene.traverseVisible(function (object) { 29385 29386 if (object.isLight && object.layers.test(camera.layers)) { 29387 29388 currentRenderState.pushLight(object); 29389 29390 if (object.castShadow) { 29391 29392 currentRenderState.pushShadow(object); 29393 29394 } 29395 29396 } 29397 29398 }); 29399 29400 } 29401 29402 currentRenderState.setupLights(_this._useLegacyLights); 29403 29404 // Only initialize materials in the new scene, not the targetScene. 29405 29406 const materials = new Set(); 29407 29408 scene.traverse(function (object) { 29409 29410 const material = object.material; 29411 29412 if (material) { 29413 29414 if (Array.isArray(material)) { 29415 29416 for (let i = 0; i < material.length; i++) { 29417 29418 const material2 = material[i]; 29419 29420 prepareMaterial(material2, targetScene, object); 29421 materials.add(material2); 29422 29423 } 29424 29425 } else { 29426 29427 prepareMaterial(material, targetScene, object); 29428 materials.add(material); 29429 29430 } 29431 29432 } 29433 29434 }); 29435 29436 renderStateStack.pop(); 29437 currentRenderState = null; 29438 29439 return materials; 29440 29441 }; 29442 29443 // compileAsync 29444 29445 this.compileAsync = function (scene, camera, targetScene = null) { 29446 29447 const materials = this.compile(scene, camera, targetScene); 29448 29449 // Wait for all the materials in the new object to indicate that they're 29450 // ready to be used before resolving the promise. 29451 29452 return new Promise((resolve) => { 29453 29454 function checkMaterialsReady() { 29455 29456 materials.forEach(function (material) { 29457 29458 const materialProperties = properties.get(material); 29459 const program = materialProperties.currentProgram; 29460 29461 if (program.isReady()) { 29462 29463 // remove any programs that report they're ready to use from the list 29464 materials.delete(material); 29465 29466 } 29467 29468 }); 29469 29470 // once the list of compiling materials is empty, call the callback 29471 29472 if (materials.size === 0) { 29473 29474 resolve(scene); 29475 return; 29476 29477 } 29478 29479 // if some materials are still not ready, wait a bit and check again 29480 29481 setTimeout(checkMaterialsReady, 10); 29482 29483 } 29484 29485 if (extensions.get('KHR_parallel_shader_compile') !== null) { 29486 29487 // If we can check the compilation status of the materials without 29488 // blocking then do so right away. 29489 29490 checkMaterialsReady(); 29491 29492 } else { 29493 29494 // Otherwise start by waiting a bit to give the materials we just 29495 // initialized a chance to finish. 29496 29497 setTimeout(checkMaterialsReady, 10); 29498 29499 } 29500 29501 }); 29502 29503 }; 29504 29505 // Animation Loop 29506 29507 let onAnimationFrameCallback = null; 29508 29509 function onAnimationFrame(time) { 29510 29511 if (onAnimationFrameCallback) onAnimationFrameCallback(time); 29512 29513 } 29514 29515 function onXRSessionStart() { 29516 29517 animation.stop(); 29518 29519 } 29520 29521 function onXRSessionEnd() { 29522 29523 animation.start(); 29524 29525 } 29526 29527 const animation = new WebGLAnimation(); 29528 animation.setAnimationLoop(onAnimationFrame); 29529 29530 if (typeof self !== 'undefined') animation.setContext(self); 29531 29532 this.setAnimationLoop = function (callback) { 29533 29534 onAnimationFrameCallback = callback; 29535 xr.setAnimationLoop(callback); 29536 29537 (callback === null) ? animation.stop() : animation.start(); 29538 29539 }; 29540 29541 xr.addEventListener('sessionstart', onXRSessionStart); 29542 xr.addEventListener('sessionend', onXRSessionEnd); 29543 29544 // Rendering 29545 29546 this.render = function (scene, camera) { 29547 29548 if (camera !== undefined && camera.isCamera !== true) { 29549 29550 console.error('THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.'); 29551 return; 29552 29553 } 29554 29555 if (_isContextLost === true) return; 29556 29557 // update scene graph 29558 29559 if (scene.matrixWorldAutoUpdate === true) scene.updateMatrixWorld(); 29560 29561 // update camera matrices and frustum 29562 29563 if (camera.parent === null && camera.matrixWorldAutoUpdate === true) camera.updateMatrixWorld(); 29564 29565 if (xr.enabled === true && xr.isPresenting === true) { 29566 29567 if (xr.cameraAutoUpdate === true) xr.updateCamera(camera); 29568 29569 camera = xr.getCamera(); // use XR camera for rendering 29570 29571 } 29572 29573 // 29574 if (scene.isScene === true) scene.onBeforeRender(_this, scene, camera, _currentRenderTarget); 29575 29576 currentRenderState = renderStates.get(scene, renderStateStack.length); 29577 currentRenderState.init(); 29578 29579 renderStateStack.push(currentRenderState); 29580 29581 _projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse); 29582 _frustum.setFromProjectionMatrix(_projScreenMatrix); 29583 29584 _localClippingEnabled = this.localClippingEnabled; 29585 _clippingEnabled = clipping.init(this.clippingPlanes, _localClippingEnabled); 29586 29587 currentRenderList = renderLists.get(scene, renderListStack.length); 29588 currentRenderList.init(); 29589 29590 renderListStack.push(currentRenderList); 29591 29592 projectObject(scene, camera, 0, _this.sortObjects); 29593 29594 currentRenderList.finish(); 29595 29596 if (_this.sortObjects === true) { 29597 29598 currentRenderList.sort(_opaqueSort, _transparentSort); 29599 29600 } 29601 29602 // 29603 29604 this.info.render.frame++; 29605 29606 if (_clippingEnabled === true) clipping.beginShadows(); 29607 29608 const shadowsArray = currentRenderState.state.shadowsArray; 29609 29610 shadowMap.render(shadowsArray, scene, camera); 29611 29612 if (_clippingEnabled === true) clipping.endShadows(); 29613 29614 // 29615 29616 if (this.info.autoReset === true) this.info.reset(); 29617 29618 29619 // 29620 29621 background.render(currentRenderList, scene); 29622 29623 // render scene 29624 29625 currentRenderState.setupLights(_this._useLegacyLights); 29626 29627 if (camera.isArrayCamera) { 29628 29629 const cameras = camera.cameras; 29630 29631 for (let i = 0, l = cameras.length; i < l; i++) { 29632 29633 const camera2 = cameras[i]; 29634 29635 renderScene(currentRenderList, scene, camera2, camera2.viewport); 29636 29637 } 29638 29639 } else { 29640 29641 renderScene(currentRenderList, scene, camera); 29642 29643 } 29644 29645 // 29646 29647 if (_currentRenderTarget !== null) { 29648 29649 // resolve multisample renderbuffers to a single-sample texture if necessary 29650 29651 textures.updateMultisampleRenderTarget(_currentRenderTarget); 29652 29653 // Generate mipmap if we're using any kind of mipmap filtering 29654 29655 textures.updateRenderTargetMipmap(_currentRenderTarget); 29656 29657 } 29658 29659 // 29660 29661 if (scene.isScene === true) scene.onAfterRender(_this, scene, camera); 29662 29663 // _gl.finish(); 29664 29665 bindingStates.resetDefaultState(); 29666 _currentMaterialId = - 1; 29667 _currentCamera = null; 29668 29669 renderStateStack.pop(); 29670 29671 if (renderStateStack.length > 0) { 29672 29673 currentRenderState = renderStateStack[renderStateStack.length - 1]; 29674 29675 } else { 29676 29677 currentRenderState = null; 29678 29679 } 29680 29681 renderListStack.pop(); 29682 29683 if (renderListStack.length > 0) { 29684 29685 currentRenderList = renderListStack[renderListStack.length - 1]; 29686 29687 } else { 29688 29689 currentRenderList = null; 29690 29691 } 29692 29693 }; 29694 29695 function projectObject(object, camera, groupOrder, sortObjects) { 29696 29697 if (object.visible === false) return; 29698 29699 const visible = object.layers.test(camera.layers); 29700 29701 if (visible) { 29702 29703 if (object.isGroup) { 29704 29705 groupOrder = object.renderOrder; 29706 29707 } else if (object.isLOD) { 29708 29709 if (object.autoUpdate === true) object.update(camera); 29710 29711 } else if (object.isLight) { 29712 29713 currentRenderState.pushLight(object); 29714 29715 if (object.castShadow) { 29716 29717 currentRenderState.pushShadow(object); 29718 29719 } 29720 29721 } else if (object.isSprite) { 29722 29723 if (!object.frustumCulled || _frustum.intersectsSprite(object)) { 29724 29725 if (sortObjects) { 29726 29727 _vector3.setFromMatrixPosition(object.matrixWorld) 29728 .applyMatrix4(_projScreenMatrix); 29729 29730 } 29731 29732 const geometry = objects.update(object); 29733 const material = object.material; 29734 29735 if (material.visible) { 29736 29737 currentRenderList.push(object, geometry, material, groupOrder, _vector3.z, null); 29738 29739 } 29740 29741 } 29742 29743 } else if (object.isMesh || object.isLine || object.isPoints) { 29744 29745 if (!object.frustumCulled || _frustum.intersectsObject(object)) { 29746 29747 const geometry = objects.update(object); 29748 const material = object.material; 29749 29750 if (sortObjects) { 29751 29752 if (object.boundingSphere !== undefined) { 29753 29754 if (object.boundingSphere === null) object.computeBoundingSphere(); 29755 _vector3.copy(object.boundingSphere.center); 29756 29757 } else { 29758 29759 if (geometry.boundingSphere === null) geometry.computeBoundingSphere(); 29760 _vector3.copy(geometry.boundingSphere.center); 29761 29762 } 29763 29764 _vector3 29765 .applyMatrix4(object.matrixWorld) 29766 .applyMatrix4(_projScreenMatrix); 29767 29768 } 29769 29770 if (Array.isArray(material)) { 29771 29772 const groups = geometry.groups; 29773 29774 for (let i = 0, l = groups.length; i < l; i++) { 29775 29776 const group = groups[i]; 29777 const groupMaterial = material[group.materialIndex]; 29778 29779 if (groupMaterial && groupMaterial.visible) { 29780 29781 currentRenderList.push(object, geometry, groupMaterial, groupOrder, _vector3.z, group); 29782 29783 } 29784 29785 } 29786 29787 } else if (material.visible) { 29788 29789 currentRenderList.push(object, geometry, material, groupOrder, _vector3.z, null); 29790 29791 } 29792 29793 } 29794 29795 } 29796 29797 } 29798 29799 const children = object.children; 29800 29801 for (let i = 0, l = children.length; i < l; i++) { 29802 29803 projectObject(children[i], camera, groupOrder, sortObjects); 29804 29805 } 29806 29807 } 29808 29809 function renderScene(currentRenderList, scene, camera, viewport) { 29810 29811 const opaqueObjects = currentRenderList.opaque; 29812 const transmissiveObjects = currentRenderList.transmissive; 29813 const transparentObjects = currentRenderList.transparent; 29814 29815 currentRenderState.setupLightsView(camera); 29816 29817 if (_clippingEnabled === true) clipping.setGlobalState(_this.clippingPlanes, camera); 29818 29819 if (transmissiveObjects.length > 0) renderTransmissionPass(opaqueObjects, transmissiveObjects, scene, camera); 29820 29821 if (viewport) state.viewport(_currentViewport.copy(viewport)); 29822 29823 if (opaqueObjects.length > 0) renderObjects(opaqueObjects, scene, camera); 29824 if (transmissiveObjects.length > 0) renderObjects(transmissiveObjects, scene, camera); 29825 if (transparentObjects.length > 0) renderObjects(transparentObjects, scene, camera); 29826 29827 // Ensure depth buffer writing is enabled so it can be cleared on next render 29828 29829 state.buffers.depth.setTest(true); 29830 state.buffers.depth.setMask(true); 29831 state.buffers.color.setMask(true); 29832 29833 state.setPolygonOffset(false); 29834 29835 } 29836 29837 function renderTransmissionPass(opaqueObjects, transmissiveObjects, scene, camera) { 29838 29839 const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; 29840 29841 if (overrideMaterial !== null) { 29842 29843 return; 29844 29845 } 29846 29847 const isWebGL2 = capabilities.isWebGL2; 29848 29849 if (_transmissionRenderTarget === null) { 29850 29851 _transmissionRenderTarget = new WebGLRenderTarget(1, 1, { 29852 generateMipmaps: true, 29853 type: extensions.has('EXT_color_buffer_half_float') ? HalfFloatType : UnsignedByteType, 29854 minFilter: LinearMipmapLinearFilter, 29855 samples: (isWebGL2) ? 4 : 0 29856 }); 29857 29858 // debug 29859 29860 /* 29861 const geometry = new PlaneGeometry(); 29862 const material = new MeshBasicMaterial( { map: _transmissionRenderTarget.texture } ); 29863 29864 const mesh = new Mesh( geometry, material ); 29865 scene.add( mesh ); 29866 */ 29867 29868 } 29869 29870 _this.getDrawingBufferSize(_vector2); 29871 29872 if (isWebGL2) { 29873 29874 _transmissionRenderTarget.setSize(_vector2.x, _vector2.y); 29875 29876 } else { 29877 29878 _transmissionRenderTarget.setSize(floorPowerOfTwo(_vector2.x), floorPowerOfTwo(_vector2.y)); 29879 29880 } 29881 29882 // 29883 29884 const currentRenderTarget = _this.getRenderTarget(); 29885 _this.setRenderTarget(_transmissionRenderTarget); 29886 29887 _this.getClearColor(_currentClearColor); 29888 _currentClearAlpha = _this.getClearAlpha(); 29889 if (_currentClearAlpha < 1) _this.setClearColor(0xffffff, 0.5); 29890 29891 _this.clear(); 29892 29893 // Turn off the features which can affect the frag color for opaque objects pass. 29894 // Otherwise they are applied twice in opaque objects pass and transmission objects pass. 29895 const currentToneMapping = _this.toneMapping; 29896 _this.toneMapping = NoToneMapping; 29897 29898 renderObjects(opaqueObjects, scene, camera); 29899 29900 textures.updateMultisampleRenderTarget(_transmissionRenderTarget); 29901 textures.updateRenderTargetMipmap(_transmissionRenderTarget); 29902 29903 let renderTargetNeedsUpdate = false; 29904 29905 for (let i = 0, l = transmissiveObjects.length; i < l; i++) { 29906 29907 const renderItem = transmissiveObjects[i]; 29908 29909 const object = renderItem.object; 29910 const geometry = renderItem.geometry; 29911 const material = renderItem.material; 29912 const group = renderItem.group; 29913 29914 if (material.side === DoubleSide && object.layers.test(camera.layers)) { 29915 29916 const currentSide = material.side; 29917 29918 material.side = BackSide; 29919 material.needsUpdate = true; 29920 29921 renderObject(object, scene, camera, geometry, material, group); 29922 29923 material.side = currentSide; 29924 material.needsUpdate = true; 29925 29926 renderTargetNeedsUpdate = true; 29927 29928 } 29929 29930 } 29931 29932 if (renderTargetNeedsUpdate === true) { 29933 29934 textures.updateMultisampleRenderTarget(_transmissionRenderTarget); 29935 textures.updateRenderTargetMipmap(_transmissionRenderTarget); 29936 29937 } 29938 29939 _this.setRenderTarget(currentRenderTarget); 29940 29941 _this.setClearColor(_currentClearColor, _currentClearAlpha); 29942 29943 _this.toneMapping = currentToneMapping; 29944 29945 } 29946 29947 function renderObjects(renderList, scene, camera) { 29948 29949 const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; 29950 29951 for (let i = 0, l = renderList.length; i < l; i++) { 29952 29953 const renderItem = renderList[i]; 29954 29955 const object = renderItem.object; 29956 const geometry = renderItem.geometry; 29957 const material = overrideMaterial === null ? renderItem.material : overrideMaterial; 29958 const group = renderItem.group; 29959 29960 if (object.layers.test(camera.layers)) { 29961 29962 renderObject(object, scene, camera, geometry, material, group); 29963 29964 } 29965 29966 } 29967 29968 } 29969 29970 function renderObject(object, scene, camera, geometry, material, group) { 29971 29972 object.onBeforeRender(_this, scene, camera, geometry, material, group); 29973 29974 object.modelViewMatrix.multiplyMatrices(camera.matrixWorldInverse, object.matrixWorld); 29975 object.normalMatrix.getNormalMatrix(object.modelViewMatrix); 29976 29977 material.onBeforeRender(_this, scene, camera, geometry, object, group); 29978 29979 if (material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false) { 29980 29981 material.side = BackSide; 29982 material.needsUpdate = true; 29983 _this.renderBufferDirect(camera, scene, geometry, material, object, group); 29984 29985 material.side = FrontSide; 29986 material.needsUpdate = true; 29987 _this.renderBufferDirect(camera, scene, geometry, material, object, group); 29988 29989 material.side = DoubleSide; 29990 29991 } else { 29992 29993 _this.renderBufferDirect(camera, scene, geometry, material, object, group); 29994 29995 } 29996 29997 object.onAfterRender(_this, scene, camera, geometry, material, group); 29998 29999 } 30000 30001 function getProgram(material, scene, object) { 30002 30003 if (scene.isScene !== true) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... 30004 30005 const materialProperties = properties.get(material); 30006 30007 const lights = currentRenderState.state.lights; 30008 const shadowsArray = currentRenderState.state.shadowsArray; 30009 30010 const lightsStateVersion = lights.state.version; 30011 30012 const parameters = programCache.getParameters(material, lights.state, shadowsArray, scene, object); 30013 const programCacheKey = programCache.getProgramCacheKey(parameters); 30014 30015 let programs = materialProperties.programs; 30016 30017 // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change 30018 30019 materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null; 30020 materialProperties.fog = scene.fog; 30021 materialProperties.envMap = (material.isMeshStandardMaterial ? cubeuvmaps : cubemaps).get(material.envMap || materialProperties.environment); 30022 30023 if (programs === undefined) { 30024 30025 // new material 30026 30027 material.addEventListener('dispose', onMaterialDispose); 30028 30029 programs = new Map(); 30030 materialProperties.programs = programs; 30031 30032 } 30033 30034 let program = programs.get(programCacheKey); 30035 30036 if (program !== undefined) { 30037 30038 // early out if program and light state is identical 30039 30040 if (materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion) { 30041 30042 updateCommonMaterialProperties(material, parameters); 30043 30044 return program; 30045 30046 } 30047 30048 } else { 30049 30050 parameters.uniforms = programCache.getUniforms(material); 30051 30052 material.onBuild(object, parameters, _this); 30053 30054 material.onBeforeCompile(parameters, _this); 30055 30056 program = programCache.acquireProgram(parameters, programCacheKey); 30057 programs.set(programCacheKey, program); 30058 30059 materialProperties.uniforms = parameters.uniforms; 30060 30061 } 30062 30063 const uniforms = materialProperties.uniforms; 30064 30065 if ((!material.isShaderMaterial && !material.isRawShaderMaterial) || material.clipping === true) { 30066 30067 uniforms.clippingPlanes = clipping.uniform; 30068 30069 } 30070 30071 updateCommonMaterialProperties(material, parameters); 30072 30073 // store the light setup it was created for 30074 30075 materialProperties.needsLights = materialNeedsLights(material); 30076 materialProperties.lightsStateVersion = lightsStateVersion; 30077 30078 if (materialProperties.needsLights) { 30079 30080 // wire up the material to this renderer's lighting state 30081 30082 uniforms.ambientLightColor.value = lights.state.ambient; 30083 uniforms.lightProbe.value = lights.state.probe; 30084 uniforms.directionalLights.value = lights.state.directional; 30085 uniforms.directionalLightShadows.value = lights.state.directionalShadow; 30086 uniforms.spotLights.value = lights.state.spot; 30087 uniforms.spotLightShadows.value = lights.state.spotShadow; 30088 uniforms.rectAreaLights.value = lights.state.rectArea; 30089 uniforms.ltc_1.value = lights.state.rectAreaLTC1; 30090 uniforms.ltc_2.value = lights.state.rectAreaLTC2; 30091 uniforms.pointLights.value = lights.state.point; 30092 uniforms.pointLightShadows.value = lights.state.pointShadow; 30093 uniforms.hemisphereLights.value = lights.state.hemi; 30094 30095 uniforms.directionalShadowMap.value = lights.state.directionalShadowMap; 30096 uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix; 30097 uniforms.spotShadowMap.value = lights.state.spotShadowMap; 30098 uniforms.spotLightMatrix.value = lights.state.spotLightMatrix; 30099 uniforms.spotLightMap.value = lights.state.spotLightMap; 30100 uniforms.pointShadowMap.value = lights.state.pointShadowMap; 30101 uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix; 30102 // TODO (abelnation): add area lights shadow info to uniforms 30103 30104 } 30105 30106 materialProperties.currentProgram = program; 30107 materialProperties.uniformsList = null; 30108 30109 return program; 30110 30111 } 30112 30113 function getUniformList(materialProperties) { 30114 30115 if (materialProperties.uniformsList === null) { 30116 30117 const progUniforms = materialProperties.currentProgram.getUniforms(); 30118 materialProperties.uniformsList = WebGLUniforms.seqWithValue(progUniforms.seq, materialProperties.uniforms); 30119 30120 } 30121 30122 return materialProperties.uniformsList; 30123 30124 } 30125 30126 function updateCommonMaterialProperties(material, parameters) { 30127 30128 const materialProperties = properties.get(material); 30129 30130 materialProperties.outputColorSpace = parameters.outputColorSpace; 30131 materialProperties.batching = parameters.batching; 30132 materialProperties.instancing = parameters.instancing; 30133 materialProperties.instancingColor = parameters.instancingColor; 30134 materialProperties.skinning = parameters.skinning; 30135 materialProperties.morphTargets = parameters.morphTargets; 30136 materialProperties.morphNormals = parameters.morphNormals; 30137 materialProperties.morphColors = parameters.morphColors; 30138 materialProperties.morphTargetsCount = parameters.morphTargetsCount; 30139 materialProperties.numClippingPlanes = parameters.numClippingPlanes; 30140 materialProperties.numIntersection = parameters.numClipIntersection; 30141 materialProperties.vertexAlphas = parameters.vertexAlphas; 30142 materialProperties.vertexTangents = parameters.vertexTangents; 30143 materialProperties.toneMapping = parameters.toneMapping; 30144 30145 } 30146 30147 function setProgram(camera, scene, geometry, material, object) { 30148 30149 if (scene.isScene !== true) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... 30150 30151 textures.resetTextureUnits(); 30152 30153 const fog = scene.fog; 30154 const environment = material.isMeshStandardMaterial ? scene.environment : null; 30155 const colorSpace = (_currentRenderTarget === null) ? _this.outputColorSpace : (_currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace); 30156 const envMap = (material.isMeshStandardMaterial ? cubeuvmaps : cubemaps).get(material.envMap || environment); 30157 const vertexAlphas = material.vertexColors === true && !!geometry.attributes.color && geometry.attributes.color.itemSize === 4; 30158 const vertexTangents = !!geometry.attributes.tangent && (!!material.normalMap || material.anisotropy > 0); 30159 const morphTargets = !!geometry.morphAttributes.position; 30160 const morphNormals = !!geometry.morphAttributes.normal; 30161 const morphColors = !!geometry.morphAttributes.color; 30162 30163 let toneMapping = NoToneMapping; 30164 30165 if (material.toneMapped) { 30166 30167 if (_currentRenderTarget === null || _currentRenderTarget.isXRRenderTarget === true) { 30168 30169 toneMapping = _this.toneMapping; 30170 30171 } 30172 30173 } 30174 30175 const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; 30176 const morphTargetsCount = (morphAttribute !== undefined) ? morphAttribute.length : 0; 30177 30178 const materialProperties = properties.get(material); 30179 const lights = currentRenderState.state.lights; 30180 30181 if (_clippingEnabled === true) { 30182 30183 if (_localClippingEnabled === true || camera !== _currentCamera) { 30184 30185 const useCache = 30186 camera === _currentCamera && 30187 material.id === _currentMaterialId; 30188 30189 // we might want to call this function with some ClippingGroup 30190 // object instead of the material, once it becomes feasible 30191 // (#8465, #8379) 30192 clipping.setState(material, camera, useCache); 30193 30194 } 30195 30196 } 30197 30198 // 30199 30200 let needsProgramChange = false; 30201 30202 if (material.version === materialProperties.__version) { 30203 30204 if (materialProperties.needsLights && (materialProperties.lightsStateVersion !== lights.state.version)) { 30205 30206 needsProgramChange = true; 30207 30208 } else if (materialProperties.outputColorSpace !== colorSpace) { 30209 30210 needsProgramChange = true; 30211 30212 } else if (object.isBatchedMesh && materialProperties.batching === false) { 30213 30214 needsProgramChange = true; 30215 30216 } else if (!object.isBatchedMesh && materialProperties.batching === true) { 30217 30218 needsProgramChange = true; 30219 30220 } else if (object.isInstancedMesh && materialProperties.instancing === false) { 30221 30222 needsProgramChange = true; 30223 30224 } else if (!object.isInstancedMesh && materialProperties.instancing === true) { 30225 30226 needsProgramChange = true; 30227 30228 } else if (object.isSkinnedMesh && materialProperties.skinning === false) { 30229 30230 needsProgramChange = true; 30231 30232 } else if (!object.isSkinnedMesh && materialProperties.skinning === true) { 30233 30234 needsProgramChange = true; 30235 30236 } else if (object.isInstancedMesh && materialProperties.instancingColor === true && object.instanceColor === null) { 30237 30238 needsProgramChange = true; 30239 30240 } else if (object.isInstancedMesh && materialProperties.instancingColor === false && object.instanceColor !== null) { 30241 30242 needsProgramChange = true; 30243 30244 } else if (materialProperties.envMap !== envMap) { 30245 30246 needsProgramChange = true; 30247 30248 } else if (material.fog === true && materialProperties.fog !== fog) { 30249 30250 needsProgramChange = true; 30251 30252 } else if (materialProperties.numClippingPlanes !== undefined && 30253 (materialProperties.numClippingPlanes !== clipping.numPlanes || 30254 materialProperties.numIntersection !== clipping.numIntersection)) { 30255 30256 needsProgramChange = true; 30257 30258 } else if (materialProperties.vertexAlphas !== vertexAlphas) { 30259 30260 needsProgramChange = true; 30261 30262 } else if (materialProperties.vertexTangents !== vertexTangents) { 30263 30264 needsProgramChange = true; 30265 30266 } else if (materialProperties.morphTargets !== morphTargets) { 30267 30268 needsProgramChange = true; 30269 30270 } else if (materialProperties.morphNormals !== morphNormals) { 30271 30272 needsProgramChange = true; 30273 30274 } else if (materialProperties.morphColors !== morphColors) { 30275 30276 needsProgramChange = true; 30277 30278 } else if (materialProperties.toneMapping !== toneMapping) { 30279 30280 needsProgramChange = true; 30281 30282 } else if (capabilities.isWebGL2 === true && materialProperties.morphTargetsCount !== morphTargetsCount) { 30283 30284 needsProgramChange = true; 30285 30286 } 30287 30288 } else { 30289 30290 needsProgramChange = true; 30291 materialProperties.__version = material.version; 30292 30293 } 30294 30295 // 30296 30297 let program = materialProperties.currentProgram; 30298 30299 if (needsProgramChange === true) { 30300 30301 program = getProgram(material, scene, object); 30302 30303 } 30304 30305 let refreshProgram = false; 30306 let refreshMaterial = false; 30307 let refreshLights = false; 30308 30309 const p_uniforms = program.getUniforms(), 30310 m_uniforms = materialProperties.uniforms; 30311 30312 if (state.useProgram(program.program)) { 30313 30314 refreshProgram = true; 30315 refreshMaterial = true; 30316 refreshLights = true; 30317 30318 } 30319 30320 if (material.id !== _currentMaterialId) { 30321 30322 _currentMaterialId = material.id; 30323 30324 refreshMaterial = true; 30325 30326 } 30327 30328 if (refreshProgram || _currentCamera !== camera) { 30329 30330 // common camera uniforms 30331 30332 p_uniforms.setValue(_gl, 'projectionMatrix', camera.projectionMatrix); 30333 p_uniforms.setValue(_gl, 'viewMatrix', camera.matrixWorldInverse); 30334 30335 const uCamPos = p_uniforms.map.cameraPosition; 30336 30337 if (uCamPos !== undefined) { 30338 30339 uCamPos.setValue(_gl, _vector3.setFromMatrixPosition(camera.matrixWorld)); 30340 30341 } 30342 30343 if (capabilities.logarithmicDepthBuffer) { 30344 30345 p_uniforms.setValue(_gl, 'logDepthBufFC', 30346 2.0 / (Math.log(camera.far + 1.0) / Math.LN2)); 30347 30348 } 30349 30350 // consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067 30351 30352 if (material.isMeshPhongMaterial || 30353 material.isMeshToonMaterial || 30354 material.isMeshLambertMaterial || 30355 material.isMeshBasicMaterial || 30356 material.isMeshStandardMaterial || 30357 material.isShaderMaterial) { 30358 30359 p_uniforms.setValue(_gl, 'isOrthographic', camera.isOrthographicCamera === true); 30360 30361 } 30362 30363 if (_currentCamera !== camera) { 30364 30365 _currentCamera = camera; 30366 30367 // lighting uniforms depend on the camera so enforce an update 30368 // now, in case this material supports lights - or later, when 30369 // the next material that does gets activated: 30370 30371 refreshMaterial = true; // set to true on material change 30372 refreshLights = true; // remains set until update done 30373 30374 } 30375 30376 } 30377 30378 // skinning and morph target uniforms must be set even if material didn't change 30379 // auto-setting of texture unit for bone and morph texture must go before other textures 30380 // otherwise textures used for skinning and morphing can take over texture units reserved for other material textures 30381 30382 if (object.isSkinnedMesh) { 30383 30384 p_uniforms.setOptional(_gl, object, 'bindMatrix'); 30385 p_uniforms.setOptional(_gl, object, 'bindMatrixInverse'); 30386 30387 const skeleton = object.skeleton; 30388 30389 if (skeleton) { 30390 30391 if (capabilities.floatVertexTextures) { 30392 30393 if (skeleton.boneTexture === null) skeleton.computeBoneTexture(); 30394 30395 p_uniforms.setValue(_gl, 'boneTexture', skeleton.boneTexture, textures); 30396 30397 } else { 30398 30399 console.warn('THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required.'); 30400 30401 } 30402 30403 } 30404 30405 } 30406 30407 if (object.isBatchedMesh) { 30408 30409 p_uniforms.setOptional(_gl, object, 'batchingTexture'); 30410 p_uniforms.setValue(_gl, 'batchingTexture', object._matricesTexture, textures); 30411 30412 } 30413 30414 const morphAttributes = geometry.morphAttributes; 30415 30416 if (morphAttributes.position !== undefined || morphAttributes.normal !== undefined || (morphAttributes.color !== undefined && capabilities.isWebGL2 === true)) { 30417 30418 morphtargets.update(object, geometry, program); 30419 30420 } 30421 30422 if (refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow) { 30423 30424 materialProperties.receiveShadow = object.receiveShadow; 30425 p_uniforms.setValue(_gl, 'receiveShadow', object.receiveShadow); 30426 30427 } 30428 30429 // https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512 30430 30431 if (material.isMeshGouraudMaterial && material.envMap !== null) { 30432 30433 m_uniforms.envMap.value = envMap; 30434 30435 m_uniforms.flipEnvMap.value = (envMap.isCubeTexture && envMap.isRenderTargetTexture === false) ? - 1 : 1; 30436 30437 } 30438 30439 if (refreshMaterial) { 30440 30441 p_uniforms.setValue(_gl, 'toneMappingExposure', _this.toneMappingExposure); 30442 30443 if (materialProperties.needsLights) { 30444 30445 // the current material requires lighting info 30446 30447 // note: all lighting uniforms are always set correctly 30448 // they simply reference the renderer's state for their 30449 // values 30450 // 30451 // use the current material's .needsUpdate flags to set 30452 // the GL state when required 30453 30454 markUniformsLightsNeedsUpdate(m_uniforms, refreshLights); 30455 30456 } 30457 30458 // refresh uniforms common to several materials 30459 30460 if (fog && material.fog === true) { 30461 30462 materials.refreshFogUniforms(m_uniforms, fog); 30463 30464 } 30465 30466 materials.refreshMaterialUniforms(m_uniforms, material, _pixelRatio, _height, _transmissionRenderTarget); 30467 30468 WebGLUniforms.upload(_gl, getUniformList(materialProperties), m_uniforms, textures); 30469 30470 } 30471 30472 if (material.isShaderMaterial && material.uniformsNeedUpdate === true) { 30473 30474 WebGLUniforms.upload(_gl, getUniformList(materialProperties), m_uniforms, textures); 30475 material.uniformsNeedUpdate = false; 30476 30477 } 30478 30479 if (material.isSpriteMaterial) { 30480 30481 p_uniforms.setValue(_gl, 'center', object.center); 30482 30483 } 30484 30485 // common matrices 30486 30487 p_uniforms.setValue(_gl, 'modelViewMatrix', object.modelViewMatrix); 30488 p_uniforms.setValue(_gl, 'normalMatrix', object.normalMatrix); 30489 p_uniforms.setValue(_gl, 'modelMatrix', object.matrixWorld); 30490 30491 // UBOs 30492 30493 if (material.isShaderMaterial || material.isRawShaderMaterial) { 30494 30495 const groups = material.uniformsGroups; 30496 30497 for (let i = 0, l = groups.length; i < l; i++) { 30498 30499 if (capabilities.isWebGL2) { 30500 30501 const group = groups[i]; 30502 30503 uniformsGroups.update(group, program); 30504 uniformsGroups.bind(group, program); 30505 30506 } else { 30507 30508 console.warn('THREE.WebGLRenderer: Uniform Buffer Objects can only be used with WebGL 2.'); 30509 30510 } 30511 30512 } 30513 30514 } 30515 30516 return program; 30517 30518 } 30519 30520 // If uniforms are marked as clean, they don't need to be loaded to the GPU. 30521 30522 function markUniformsLightsNeedsUpdate(uniforms, value) { 30523 30524 uniforms.ambientLightColor.needsUpdate = value; 30525 uniforms.lightProbe.needsUpdate = value; 30526 30527 uniforms.directionalLights.needsUpdate = value; 30528 uniforms.directionalLightShadows.needsUpdate = value; 30529 uniforms.pointLights.needsUpdate = value; 30530 uniforms.pointLightShadows.needsUpdate = value; 30531 uniforms.spotLights.needsUpdate = value; 30532 uniforms.spotLightShadows.needsUpdate = value; 30533 uniforms.rectAreaLights.needsUpdate = value; 30534 uniforms.hemisphereLights.needsUpdate = value; 30535 30536 } 30537 30538 function materialNeedsLights(material) { 30539 30540 return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial || 30541 material.isMeshStandardMaterial || material.isShadowMaterial || 30542 (material.isShaderMaterial && material.lights === true); 30543 30544 } 30545 30546 this.getActiveCubeFace = function () { 30547 30548 return _currentActiveCubeFace; 30549 30550 }; 30551 30552 this.getActiveMipmapLevel = function () { 30553 30554 return _currentActiveMipmapLevel; 30555 30556 }; 30557 30558 this.getRenderTarget = function () { 30559 30560 return _currentRenderTarget; 30561 30562 }; 30563 30564 this.setRenderTargetTextures = function (renderTarget, colorTexture, depthTexture) { 30565 30566 properties.get(renderTarget.texture).__webglTexture = colorTexture; 30567 properties.get(renderTarget.depthTexture).__webglTexture = depthTexture; 30568 30569 const renderTargetProperties = properties.get(renderTarget); 30570 renderTargetProperties.__hasExternalTextures = true; 30571 30572 if (renderTargetProperties.__hasExternalTextures) { 30573 30574 renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined; 30575 30576 if (!renderTargetProperties.__autoAllocateDepthBuffer) { 30577 30578 // The multisample_render_to_texture extension doesn't work properly if there 30579 // are midframe flushes and an external depth buffer. Disable use of the extension. 30580 if (extensions.has('WEBGL_multisampled_render_to_texture') === true) { 30581 30582 console.warn('THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided'); 30583 renderTargetProperties.__useRenderToTexture = false; 30584 30585 } 30586 30587 } 30588 30589 } 30590 30591 }; 30592 30593 this.setRenderTargetFramebuffer = function (renderTarget, defaultFramebuffer) { 30594 30595 const renderTargetProperties = properties.get(renderTarget); 30596 renderTargetProperties.__webglFramebuffer = defaultFramebuffer; 30597 renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined; 30598 30599 }; 30600 30601 this.setRenderTarget = function (renderTarget, activeCubeFace = 0, activeMipmapLevel = 0) { 30602 30603 _currentRenderTarget = renderTarget; 30604 _currentActiveCubeFace = activeCubeFace; 30605 _currentActiveMipmapLevel = activeMipmapLevel; 30606 30607 let useDefaultFramebuffer = true; 30608 let framebuffer = null; 30609 let isCube = false; 30610 let isRenderTarget3D = false; 30611 30612 if (renderTarget) { 30613 30614 const renderTargetProperties = properties.get(renderTarget); 30615 30616 if (renderTargetProperties.__useDefaultFramebuffer !== undefined) { 30617 30618 // We need to make sure to rebind the framebuffer. 30619 state.bindFramebuffer(_gl.FRAMEBUFFER, null); 30620 useDefaultFramebuffer = false; 30621 30622 } else if (renderTargetProperties.__webglFramebuffer === undefined) { 30623 30624 textures.setupRenderTarget(renderTarget); 30625 30626 } else if (renderTargetProperties.__hasExternalTextures) { 30627 30628 // Color and depth texture must be rebound in order for the swapchain to update. 30629 textures.rebindTextures(renderTarget, properties.get(renderTarget.texture).__webglTexture, properties.get(renderTarget.depthTexture).__webglTexture); 30630 30631 } 30632 30633 const texture = renderTarget.texture; 30634 30635 if (texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture) { 30636 30637 isRenderTarget3D = true; 30638 30639 } 30640 30641 const __webglFramebuffer = properties.get(renderTarget).__webglFramebuffer; 30642 30643 if (renderTarget.isWebGLCubeRenderTarget) { 30644 30645 if (Array.isArray(__webglFramebuffer[activeCubeFace])) { 30646 30647 framebuffer = __webglFramebuffer[activeCubeFace][activeMipmapLevel]; 30648 30649 } else { 30650 30651 framebuffer = __webglFramebuffer[activeCubeFace]; 30652 30653 } 30654 30655 isCube = true; 30656 30657 } else if ((capabilities.isWebGL2 && renderTarget.samples > 0) && textures.useMultisampledRTT(renderTarget) === false) { 30658 30659 framebuffer = properties.get(renderTarget).__webglMultisampledFramebuffer; 30660 30661 } else { 30662 30663 if (Array.isArray(__webglFramebuffer)) { 30664 30665 framebuffer = __webglFramebuffer[activeMipmapLevel]; 30666 30667 } else { 30668 30669 framebuffer = __webglFramebuffer; 30670 30671 } 30672 30673 } 30674 30675 _currentViewport.copy(renderTarget.viewport); 30676 _currentScissor.copy(renderTarget.scissor); 30677 _currentScissorTest = renderTarget.scissorTest; 30678 30679 } else { 30680 30681 _currentViewport.copy(_viewport).multiplyScalar(_pixelRatio).floor(); 30682 _currentScissor.copy(_scissor).multiplyScalar(_pixelRatio).floor(); 30683 _currentScissorTest = _scissorTest; 30684 30685 } 30686 30687 const framebufferBound = state.bindFramebuffer(_gl.FRAMEBUFFER, framebuffer); 30688 30689 if (framebufferBound && capabilities.drawBuffers && useDefaultFramebuffer) { 30690 30691 state.drawBuffers(renderTarget, framebuffer); 30692 30693 } 30694 30695 state.viewport(_currentViewport); 30696 state.scissor(_currentScissor); 30697 state.setScissorTest(_currentScissorTest); 30698 30699 if (isCube) { 30700 30701 const textureProperties = properties.get(renderTarget.texture); 30702 _gl.framebufferTexture2D(_gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel); 30703 30704 } else if (isRenderTarget3D) { 30705 30706 const textureProperties = properties.get(renderTarget.texture); 30707 const layer = activeCubeFace || 0; 30708 _gl.framebufferTextureLayer(_gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel || 0, layer); 30709 30710 } 30711 30712 _currentMaterialId = - 1; // reset current material to ensure correct uniform bindings 30713 30714 }; 30715 30716 this.readRenderTargetPixels = function (renderTarget, x, y, width, height, buffer, activeCubeFaceIndex) { 30717 30718 if (!(renderTarget && renderTarget.isWebGLRenderTarget)) { 30719 30720 console.error('THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.'); 30721 return; 30722 30723 } 30724 30725 let framebuffer = properties.get(renderTarget).__webglFramebuffer; 30726 30727 if (renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined) { 30728 30729 framebuffer = framebuffer[activeCubeFaceIndex]; 30730 30731 } 30732 30733 if (framebuffer) { 30734 30735 state.bindFramebuffer(_gl.FRAMEBUFFER, framebuffer); 30736 30737 try { 30738 30739 const texture = renderTarget.texture; 30740 const textureFormat = texture.format; 30741 const textureType = texture.type; 30742 30743 if (textureFormat !== RGBAFormat && utils.convert(textureFormat) !== _gl.getParameter(_gl.IMPLEMENTATION_COLOR_READ_FORMAT)) { 30744 30745 console.error('THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.'); 30746 return; 30747 30748 } 30749 30750 const halfFloatSupportedByExt = (textureType === HalfFloatType) && (extensions.has('EXT_color_buffer_half_float') || (capabilities.isWebGL2 && extensions.has('EXT_color_buffer_float'))); 30751 30752 if (textureType !== UnsignedByteType && utils.convert(textureType) !== _gl.getParameter(_gl.IMPLEMENTATION_COLOR_READ_TYPE) && // Edge and Chrome Mac < 52 (#9513) 30753 !(textureType === FloatType && (capabilities.isWebGL2 || extensions.has('OES_texture_float') || extensions.has('WEBGL_color_buffer_float'))) && // Chrome Mac >= 52 and Firefox 30754 !halfFloatSupportedByExt) { 30755 30756 console.error('THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.'); 30757 return; 30758 30759 } 30760 30761 // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) 30762 30763 if ((x >= 0 && x <= (renderTarget.width - width)) && (y >= 0 && y <= (renderTarget.height - height))) { 30764 30765 _gl.readPixels(x, y, width, height, utils.convert(textureFormat), utils.convert(textureType), buffer); 30766 30767 } 30768 30769 } finally { 30770 30771 // restore framebuffer of current render target if necessary 30772 30773 const framebuffer = (_currentRenderTarget !== null) ? properties.get(_currentRenderTarget).__webglFramebuffer : null; 30774 state.bindFramebuffer(_gl.FRAMEBUFFER, framebuffer); 30775 30776 } 30777 30778 } 30779 30780 }; 30781 30782 this.copyFramebufferToTexture = function (position, texture, level = 0) { 30783 30784 const levelScale = Math.pow(2, - level); 30785 const width = Math.floor(texture.image.width * levelScale); 30786 const height = Math.floor(texture.image.height * levelScale); 30787 30788 textures.setTexture2D(texture, 0); 30789 30790 _gl.copyTexSubImage2D(_gl.TEXTURE_2D, level, 0, 0, position.x, position.y, width, height); 30791 30792 state.unbindTexture(); 30793 30794 }; 30795 30796 this.copyTextureToTexture = function (position, srcTexture, dstTexture, level = 0) { 30797 30798 const width = srcTexture.image.width; 30799 const height = srcTexture.image.height; 30800 const glFormat = utils.convert(dstTexture.format); 30801 const glType = utils.convert(dstTexture.type); 30802 30803 textures.setTexture2D(dstTexture, 0); 30804 30805 // As another texture upload may have changed pixelStorei 30806 // parameters, make sure they are correct for the dstTexture 30807 _gl.pixelStorei(_gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY); 30808 _gl.pixelStorei(_gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha); 30809 _gl.pixelStorei(_gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment); 30810 30811 if (srcTexture.isDataTexture) { 30812 30813 _gl.texSubImage2D(_gl.TEXTURE_2D, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data); 30814 30815 } else { 30816 30817 if (srcTexture.isCompressedTexture) { 30818 30819 _gl.compressedTexSubImage2D(_gl.TEXTURE_2D, level, position.x, position.y, srcTexture.mipmaps[0].width, srcTexture.mipmaps[0].height, glFormat, srcTexture.mipmaps[0].data); 30820 30821 } else { 30822 30823 _gl.texSubImage2D(_gl.TEXTURE_2D, level, position.x, position.y, glFormat, glType, srcTexture.image); 30824 30825 } 30826 30827 } 30828 30829 // Generate mipmaps only when copying level 0 30830 if (level === 0 && dstTexture.generateMipmaps) _gl.generateMipmap(_gl.TEXTURE_2D); 30831 30832 state.unbindTexture(); 30833 30834 }; 30835 30836 this.copyTextureToTexture3D = function (sourceBox, position, srcTexture, dstTexture, level = 0) { 30837 30838 if (_this.isWebGL1Renderer) { 30839 30840 console.warn('THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.'); 30841 return; 30842 30843 } 30844 30845 const width = sourceBox.max.x - sourceBox.min.x + 1; 30846 const height = sourceBox.max.y - sourceBox.min.y + 1; 30847 const depth = sourceBox.max.z - sourceBox.min.z + 1; 30848 const glFormat = utils.convert(dstTexture.format); 30849 const glType = utils.convert(dstTexture.type); 30850 let glTarget; 30851 30852 if (dstTexture.isData3DTexture) { 30853 30854 textures.setTexture3D(dstTexture, 0); 30855 glTarget = _gl.TEXTURE_3D; 30856 30857 } else if (dstTexture.isDataArrayTexture || dstTexture.isCompressedArrayTexture) { 30858 30859 textures.setTexture2DArray(dstTexture, 0); 30860 glTarget = _gl.TEXTURE_2D_ARRAY; 30861 30862 } else { 30863 30864 console.warn('THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.'); 30865 return; 30866 30867 } 30868 30869 _gl.pixelStorei(_gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY); 30870 _gl.pixelStorei(_gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha); 30871 _gl.pixelStorei(_gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment); 30872 30873 const unpackRowLen = _gl.getParameter(_gl.UNPACK_ROW_LENGTH); 30874 const unpackImageHeight = _gl.getParameter(_gl.UNPACK_IMAGE_HEIGHT); 30875 const unpackSkipPixels = _gl.getParameter(_gl.UNPACK_SKIP_PIXELS); 30876 const unpackSkipRows = _gl.getParameter(_gl.UNPACK_SKIP_ROWS); 30877 const unpackSkipImages = _gl.getParameter(_gl.UNPACK_SKIP_IMAGES); 30878 30879 const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[level] : srcTexture.image; 30880 30881 _gl.pixelStorei(_gl.UNPACK_ROW_LENGTH, image.width); 30882 _gl.pixelStorei(_gl.UNPACK_IMAGE_HEIGHT, image.height); 30883 _gl.pixelStorei(_gl.UNPACK_SKIP_PIXELS, sourceBox.min.x); 30884 _gl.pixelStorei(_gl.UNPACK_SKIP_ROWS, sourceBox.min.y); 30885 _gl.pixelStorei(_gl.UNPACK_SKIP_IMAGES, sourceBox.min.z); 30886 30887 if (srcTexture.isDataTexture || srcTexture.isData3DTexture) { 30888 30889 _gl.texSubImage3D(glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image.data); 30890 30891 } else { 30892 30893 if (srcTexture.isCompressedArrayTexture) { 30894 30895 console.warn('THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture.'); 30896 _gl.compressedTexSubImage3D(glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, image.data); 30897 30898 } else { 30899 30900 _gl.texSubImage3D(glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image); 30901 30902 } 30903 30904 } 30905 30906 _gl.pixelStorei(_gl.UNPACK_ROW_LENGTH, unpackRowLen); 30907 _gl.pixelStorei(_gl.UNPACK_IMAGE_HEIGHT, unpackImageHeight); 30908 _gl.pixelStorei(_gl.UNPACK_SKIP_PIXELS, unpackSkipPixels); 30909 _gl.pixelStorei(_gl.UNPACK_SKIP_ROWS, unpackSkipRows); 30910 _gl.pixelStorei(_gl.UNPACK_SKIP_IMAGES, unpackSkipImages); 30911 30912 // Generate mipmaps only when copying level 0 30913 if (level === 0 && dstTexture.generateMipmaps) _gl.generateMipmap(glTarget); 30914 30915 state.unbindTexture(); 30916 30917 }; 30918 30919 this.initTexture = function (texture) { 30920 30921 if (texture.isCubeTexture) { 30922 30923 textures.setTextureCube(texture, 0); 30924 30925 } else if (texture.isData3DTexture) { 30926 30927 textures.setTexture3D(texture, 0); 30928 30929 } else if (texture.isDataArrayTexture || texture.isCompressedArrayTexture) { 30930 30931 textures.setTexture2DArray(texture, 0); 30932 30933 } else { 30934 30935 textures.setTexture2D(texture, 0); 30936 30937 } 30938 30939 state.unbindTexture(); 30940 30941 }; 30942 30943 this.resetState = function () { 30944 30945 _currentActiveCubeFace = 0; 30946 _currentActiveMipmapLevel = 0; 30947 _currentRenderTarget = null; 30948 30949 state.reset(); 30950 bindingStates.reset(); 30951 30952 }; 30953 30954 if (typeof __THREE_DEVTOOLS__ !== 'undefined') { 30955 30956 __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent('observe', { detail: this })); 30957 30958 } 30959 30960 } 30961 30962 get coordinateSystem() { 30963 30964 return WebGLCoordinateSystem; 30965 30966 } 30967 30968 get outputColorSpace() { 30969 30970 return this._outputColorSpace; 30971 30972 } 30973 30974 set outputColorSpace(colorSpace) { 30975 30976 this._outputColorSpace = colorSpace; 30977 30978 const gl = this.getContext(); 30979 gl.drawingBufferColorSpace = colorSpace === DisplayP3ColorSpace ? 'display-p3' : 'srgb'; 30980 gl.unpackColorSpace = ColorManagement.workingColorSpace === LinearDisplayP3ColorSpace ? 'display-p3' : 'srgb'; 30981 30982 } 30983 30984 get outputEncoding() { // @deprecated, r152 30985 30986 console.warn('THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead.'); 30987 return this.outputColorSpace === SRGBColorSpace ? sRGBEncoding : LinearEncoding; 30988 30989 } 30990 30991 set outputEncoding(encoding) { // @deprecated, r152 30992 30993 console.warn('THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead.'); 30994 this.outputColorSpace = encoding === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace; 30995 30996 } 30997 30998 get useLegacyLights() { // @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 return this._useLegacyLights; 31002 31003 } 31004 31005 set useLegacyLights(value) { // @deprecated, r155 31006 31007 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.'); 31008 this._useLegacyLights = value; 31009 31010 } 31011 31012} 31013 31014class WebGL1Renderer extends WebGLRenderer { } 31015 31016WebGL1Renderer.prototype.isWebGL1Renderer = true; 31017 31018class FogExp2 { 31019 31020 constructor(color, density = 0.00025) { 31021 31022 this.isFogExp2 = true; 31023 31024 this.name = ''; 31025 31026 this.color = new Color(color); 31027 this.density = density; 31028 31029 } 31030 31031 clone() { 31032 31033 return new FogExp2(this.color, this.density); 31034 31035 } 31036 31037 toJSON( /* meta */) { 31038 31039 return { 31040 type: 'FogExp2', 31041 name: this.name,
vendor: 5,137 bytes, lines 31042-31341
31042 color: this.color.getHex(), 31043 density: this.density 31044 }; 31045 31046 } 31047 31048} 31049 31050class Fog { 31051 31052 constructor(color, near = 1, far = 1000) { 31053 31054 this.isFog = true; 31055 31056 this.name = ''; 31057 31058 this.color = new Color(color); 31059 31060 this.near = near; 31061 this.far = far; 31062 31063 } 31064 31065 clone() { 31066 31067 return new Fog(this.color, this.near, this.far); 31068 31069 } 31070 31071 toJSON( /* meta */) { 31072 31073 return { 31074 type: 'Fog', 31075 name: this.name, 31076 color: this.color.getHex(), 31077 near: this.near, 31078 far: this.far 31079 }; 31080 31081 } 31082 31083} 31084 31085class Scene extends Object3D { 31086 31087 constructor() { 31088 31089 super(); 31090 31091 this.isScene = true; 31092 31093 this.type = 'Scene'; 31094 31095 this.background = null; 31096 this.environment = null; 31097 this.fog = null; 31098 31099 this.backgroundBlurriness = 0; 31100 this.backgroundIntensity = 1; 31101 31102 this.overrideMaterial = null; 31103 31104 if (typeof __THREE_DEVTOOLS__ !== 'undefined') { 31105 31106 __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent('observe', { detail: this })); 31107 31108 } 31109 31110 } 31111 31112 copy(source, recursive) { 31113 31114 super.copy(source, recursive); 31115 31116 if (source.background !== null) this.background = source.background.clone(); 31117 if (source.environment !== null) this.environment = source.environment.clone(); 31118 if (source.fog !== null) this.fog = source.fog.clone(); 31119 31120 this.backgroundBlurriness = source.backgroundBlurriness; 31121 this.backgroundIntensity = source.backgroundIntensity; 31122 31123 if (source.overrideMaterial !== null) this.overrideMaterial = source.overrideMaterial.clone(); 31124 31125 this.matrixAutoUpdate = source.matrixAutoUpdate; 31126 31127 return this; 31128 31129 } 31130 31131 toJSON(meta) { 31132 31133 const data = super.toJSON(meta); 31134 31135 if (this.fog !== null) data.object.fog = this.fog.toJSON(); 31136 if (this.backgroundBlurriness > 0) data.object.backgroundBlurriness = this.backgroundBlurriness; 31137 if (this.backgroundIntensity !== 1) data.object.backgroundIntensity = this.backgroundIntensity; 31138 31139 return data; 31140 31141 } 31142 31143} 31144 31145class InterleavedBuffer { 31146 31147 constructor(array, stride) { 31148 31149 this.isInterleavedBuffer = true; 31150 31151 this.array = array; 31152 this.stride = stride; 31153 this.count = array !== undefined ? array.length / stride : 0; 31154 31155 this.usage = StaticDrawUsage; 31156 this._updateRange = { offset: 0, count: - 1 }; 31157 this.updateRanges = []; 31158 31159 this.version = 0; 31160 31161 this.uuid = generateUUID(); 31162 31163 } 31164 31165 onUploadCallback() { } 31166 31167 set needsUpdate(value) { 31168 31169 if (value === true) this.version++; 31170 31171 } 31172 31173 get updateRange() { 31174 31175 console.warn('THREE.InterleavedBuffer: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.'); // @deprecated, r159 31176 return this._updateRange; 31177 31178 } 31179 31180 setUsage(value) { 31181 31182 this.usage = value; 31183 31184 return this; 31185 31186 } 31187 31188 addUpdateRange(start, count) { 31189 31190 this.updateRanges.push({ start, count }); 31191 31192 } 31193 31194 clearUpdateRanges() { 31195 31196 this.updateRanges.length = 0; 31197 31198 } 31199 31200 copy(source) { 31201 31202 this.array = new source.array.constructor(source.array); 31203 this.count = source.count; 31204 this.stride = source.stride; 31205 this.usage = source.usage; 31206 31207 return this; 31208 31209 } 31210 31211 copyAt(index1, attribute, index2) { 31212 31213 index1 *= this.stride; 31214 index2 *= attribute.stride; 31215 31216 for (let i = 0, l = this.stride; i < l; i++) { 31217 31218 this.array[index1 + i] = attribute.array[index2 + i]; 31219 31220 } 31221 31222 return this; 31223 31224 } 31225 31226 set(value, offset = 0) { 31227 31228 this.array.set(value, offset); 31229 31230 return this; 31231 31232 } 31233 31234 clone(data) { 31235 31236 if (data.arrayBuffers === undefined) { 31237 31238 data.arrayBuffers = {}; 31239 31240 } 31241 31242 if (this.array.buffer._uuid === undefined) { 31243 31244 this.array.buffer._uuid = generateUUID(); 31245 31246 } 31247 31248 if (data.arrayBuffers[this.array.buffer._uuid] === undefined) { 31249 31250 data.arrayBuffers[this.array.buffer._uuid] = this.array.slice(0).buffer; 31251 31252 } 31253 31254 const array = new this.array.constructor(data.arrayBuffers[this.array.buffer._uuid]); 31255 31256 const ib = new this.constructor(array, this.stride); 31257 ib.setUsage(this.usage); 31258 31259 return ib; 31260 31261 } 31262 31263 onUpload(callback) { 31264 31265 this.onUploadCallback = callback; 31266 31267 return this; 31268 31269 } 31270 31271 toJSON(data) { 31272 31273 if (data.arrayBuffers === undefined) { 31274 31275 data.arrayBuffers = {}; 31276 31277 } 31278 31279 // generate UUID for array buffer if necessary 31280 31281 if (this.array.buffer._uuid === undefined) { 31282 31283 this.array.buffer._uuid = generateUUID(); 31284 31285 } 31286 31287 if (data.arrayBuffers[this.array.buffer._uuid] === undefined) { 31288 31289 data.arrayBuffers[this.array.buffer._uuid] = Array.from(new Uint32Array(this.array.buffer)); 31290 31291 } 31292 31293 // 31294 31295 return { 31296 uuid: this.uuid, 31297 buffer: this.array.buffer._uuid, 31298 type: this.array.constructor.name, 31299 stride: this.stride 31300 }; 31301 31302 } 31303 31304} 31305 31306const _vector$6 = /*@__PURE__*/ new Vector3(); 31307 31308class InterleavedBufferAttribute { 31309 31310 constructor(interleavedBuffer, itemSize, offset, normalized = false) { 31311 31312 this.isInterleavedBufferAttribute = true; 31313 31314 this.name = ''; 31315 31316 this.data = interleavedBuffer; 31317 this.itemSize = itemSize; 31318 this.offset = offset; 31319 31320 this.normalized = normalized; 31321 31322 } 31323 31324 get count() { 31325 31326 return this.data.count; 31327 31328 } 31329 31330 get array() { 31331 31332 return this.data.array; 31333 31334 } 31335 31336 set needsUpdate(value) { 31337 31338 this.data.needsUpdate = value; 31339 31340 } 31341
vendor: 15,636 bytes, lines 31342-32161
31342 applyMatrix4(m) { 31343 31344 for (let i = 0, l = this.data.count; i < l; i++) { 31345 31346 _vector$6.fromBufferAttribute(this, i); 31347 31348 _vector$6.applyMatrix4(m); 31349 31350 this.setXYZ(i, _vector$6.x, _vector$6.y, _vector$6.z); 31351 31352 } 31353 31354 return this; 31355 31356 } 31357 31358 applyNormalMatrix(m) { 31359 31360 for (let i = 0, l = this.count; i < l; i++) { 31361 31362 _vector$6.fromBufferAttribute(this, i); 31363 31364 _vector$6.applyNormalMatrix(m); 31365 31366 this.setXYZ(i, _vector$6.x, _vector$6.y, _vector$6.z); 31367 31368 } 31369 31370 return this; 31371 31372 } 31373 31374 transformDirection(m) { 31375 31376 for (let i = 0, l = this.count; i < l; i++) { 31377 31378 _vector$6.fromBufferAttribute(this, i); 31379 31380 _vector$6.transformDirection(m); 31381 31382 this.setXYZ(i, _vector$6.x, _vector$6.y, _vector$6.z); 31383 31384 } 31385 31386 return this; 31387 31388 } 31389 31390 setX(index, x) { 31391 31392 if (this.normalized) x = normalize(x, this.array); 31393 31394 this.data.array[index * this.data.stride + this.offset] = x; 31395 31396 return this; 31397 31398 } 31399 31400 setY(index, y) { 31401 31402 if (this.normalized) y = normalize(y, this.array); 31403 31404 this.data.array[index * this.data.stride + this.offset + 1] = y; 31405 31406 return this; 31407 31408 } 31409 31410 setZ(index, z) { 31411 31412 if (this.normalized) z = normalize(z, this.array); 31413 31414 this.data.array[index * this.data.stride + this.offset + 2] = z; 31415 31416 return this; 31417 31418 } 31419 31420 setW(index, w) { 31421 31422 if (this.normalized) w = normalize(w, this.array); 31423 31424 this.data.array[index * this.data.stride + this.offset + 3] = w; 31425 31426 return this; 31427 31428 } 31429 31430 getX(index) { 31431 31432 let x = this.data.array[index * this.data.stride + this.offset]; 31433 31434 if (this.normalized) x = denormalize(x, this.array); 31435 31436 return x; 31437 31438 } 31439 31440 getY(index) { 31441 31442 let y = this.data.array[index * this.data.stride + this.offset + 1]; 31443 31444 if (this.normalized) y = denormalize(y, this.array); 31445 31446 return y; 31447 31448 } 31449 31450 getZ(index) { 31451 31452 let z = this.data.array[index * this.data.stride + this.offset + 2]; 31453 31454 if (this.normalized) z = denormalize(z, this.array); 31455 31456 return z; 31457 31458 } 31459 31460 getW(index) { 31461 31462 let w = this.data.array[index * this.data.stride + this.offset + 3]; 31463 31464 if (this.normalized) w = denormalize(w, this.array); 31465 31466 return w; 31467 31468 } 31469 31470 setXY(index, x, y) { 31471 31472 index = index * this.data.stride + this.offset; 31473 31474 if (this.normalized) { 31475 31476 x = normalize(x, this.array); 31477 y = normalize(y, this.array); 31478 31479 } 31480 31481 this.data.array[index + 0] = x; 31482 this.data.array[index + 1] = y; 31483 31484 return this; 31485 31486 } 31487 31488 setXYZ(index, x, y, z) { 31489 31490 index = index * this.data.stride + this.offset; 31491 31492 if (this.normalized) { 31493 31494 x = normalize(x, this.array); 31495 y = normalize(y, this.array); 31496 z = normalize(z, this.array); 31497 31498 } 31499 31500 this.data.array[index + 0] = x; 31501 this.data.array[index + 1] = y; 31502 this.data.array[index + 2] = z; 31503 31504 return this; 31505 31506 } 31507 31508 setXYZW(index, x, y, z, w) { 31509 31510 index = index * this.data.stride + this.offset; 31511 31512 if (this.normalized) { 31513 31514 x = normalize(x, this.array); 31515 y = normalize(y, this.array); 31516 z = normalize(z, this.array); 31517 w = normalize(w, this.array); 31518 31519 } 31520 31521 this.data.array[index + 0] = x; 31522 this.data.array[index + 1] = y; 31523 this.data.array[index + 2] = z; 31524 this.data.array[index + 3] = w; 31525 31526 return this; 31527 31528 } 31529 31530 clone(data) { 31531 31532 if (data === undefined) { 31533 31534 console.log('THREE.InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will de-interleave buffer data.'); 31535 31536 const array = []; 31537 31538 for (let i = 0; i < this.count; i++) { 31539 31540 const index = i * this.data.stride + this.offset; 31541 31542 for (let j = 0; j < this.itemSize; j++) { 31543 31544 array.push(this.data.array[index + j]); 31545 31546 } 31547 31548 } 31549 31550 return new BufferAttribute(new this.array.constructor(array), this.itemSize, this.normalized); 31551 31552 } else { 31553 31554 if (data.interleavedBuffers === undefined) { 31555 31556 data.interleavedBuffers = {}; 31557 31558 } 31559 31560 if (data.interleavedBuffers[this.data.uuid] === undefined) { 31561 31562 data.interleavedBuffers[this.data.uuid] = this.data.clone(data); 31563 31564 } 31565 31566 return new InterleavedBufferAttribute(data.interleavedBuffers[this.data.uuid], this.itemSize, this.offset, this.normalized); 31567 31568 } 31569 31570 } 31571 31572 toJSON(data) { 31573 31574 if (data === undefined) { 31575 31576 console.log('THREE.InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will de-interleave buffer data.'); 31577 31578 const array = []; 31579 31580 for (let i = 0; i < this.count; i++) { 31581 31582 const index = i * this.data.stride + this.offset; 31583 31584 for (let j = 0; j < this.itemSize; j++) { 31585 31586 array.push(this.data.array[index + j]); 31587 31588 } 31589 31590 } 31591 31592 // de-interleave data and save it as an ordinary buffer attribute for now 31593 31594 return { 31595 itemSize: this.itemSize, 31596 type: this.array.constructor.name, 31597 array: array, 31598 normalized: this.normalized 31599 }; 31600 31601 } else { 31602 31603 // save as true interleaved attribute 31604 31605 if (data.interleavedBuffers === undefined) { 31606 31607 data.interleavedBuffers = {}; 31608 31609 } 31610 31611 if (data.interleavedBuffers[this.data.uuid] === undefined) { 31612 31613 data.interleavedBuffers[this.data.uuid] = this.data.toJSON(data); 31614 31615 } 31616 31617 return { 31618 isInterleavedBufferAttribute: true, 31619 itemSize: this.itemSize, 31620 data: this.data.uuid, 31621 offset: this.offset, 31622 normalized: this.normalized 31623 }; 31624 31625 } 31626 31627 } 31628 31629} 31630 31631class SpriteMaterial extends Material { 31632 31633 constructor(parameters) { 31634 31635 super(); 31636 31637 this.isSpriteMaterial = true; 31638 31639 this.type = 'SpriteMaterial'; 31640 31641 this.color = new Color(0xffffff); 31642 31643 this.map = null; 31644 31645 this.alphaMap = null; 31646 31647 this.rotation = 0; 31648 31649 this.sizeAttenuation = true; 31650 31651 this.transparent = true; 31652 31653 this.fog = true; 31654 31655 this.setValues(parameters); 31656 31657 } 31658 31659 copy(source) { 31660 31661 super.copy(source); 31662 31663 this.color.copy(source.color); 31664 31665 this.map = source.map; 31666 31667 this.alphaMap = source.alphaMap; 31668 31669 this.rotation = source.rotation; 31670 31671 this.sizeAttenuation = source.sizeAttenuation; 31672 31673 this.fog = source.fog; 31674 31675 return this; 31676 31677 } 31678 31679} 31680 31681let _geometry; 31682 31683const _intersectPoint = /*@__PURE__*/ new Vector3(); 31684const _worldScale = /*@__PURE__*/ new Vector3(); 31685const _mvPosition = /*@__PURE__*/ new Vector3(); 31686 31687const _alignedPosition = /*@__PURE__*/ new Vector2(); 31688const _rotatedPosition = /*@__PURE__*/ new Vector2(); 31689const _viewWorldMatrix = /*@__PURE__*/ new Matrix4(); 31690 31691const _vA = /*@__PURE__*/ new Vector3(); 31692const _vB = /*@__PURE__*/ new Vector3(); 31693const _vC = /*@__PURE__*/ new Vector3(); 31694 31695const _uvA = /*@__PURE__*/ new Vector2(); 31696const _uvB = /*@__PURE__*/ new Vector2(); 31697const _uvC = /*@__PURE__*/ new Vector2(); 31698 31699class Sprite extends Object3D { 31700 31701 constructor(material = new SpriteMaterial()) { 31702 31703 super(); 31704 31705 this.isSprite = true; 31706 31707 this.type = 'Sprite'; 31708 31709 if (_geometry === undefined) { 31710 31711 _geometry = new BufferGeometry(); 31712 31713 const float32Array = new Float32Array([ 31714 - 0.5, - 0.5, 0, 0, 0, 31715 0.5, - 0.5, 0, 1, 0, 31716 0.5, 0.5, 0, 1, 1, 31717 - 0.5, 0.5, 0, 0, 1 31718 ]); 31719 31720 const interleavedBuffer = new InterleavedBuffer(float32Array, 5); 31721 31722 _geometry.setIndex([0, 1, 2, 0, 2, 3]); 31723 _geometry.setAttribute('position', new InterleavedBufferAttribute(interleavedBuffer, 3, 0, false)); 31724 _geometry.setAttribute('uv', new InterleavedBufferAttribute(interleavedBuffer, 2, 3, false)); 31725 31726 } 31727 31728 this.geometry = _geometry; 31729 this.material = material; 31730 31731 this.center = new Vector2(0.5, 0.5); 31732 31733 } 31734 31735 raycast(raycaster, intersects) { 31736 31737 if (raycaster.camera === null) { 31738 31739 console.error('THREE.Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.'); 31740 31741 } 31742 31743 _worldScale.setFromMatrixScale(this.matrixWorld); 31744 31745 _viewWorldMatrix.copy(raycaster.camera.matrixWorld); 31746 this.modelViewMatrix.multiplyMatrices(raycaster.camera.matrixWorldInverse, this.matrixWorld); 31747 31748 _mvPosition.setFromMatrixPosition(this.modelViewMatrix); 31749 31750 if (raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false) { 31751 31752 _worldScale.multiplyScalar(- _mvPosition.z); 31753 31754 } 31755 31756 const rotation = this.material.rotation; 31757 let sin, cos; 31758 31759 if (rotation !== 0) { 31760 31761 cos = Math.cos(rotation); 31762 sin = Math.sin(rotation); 31763 31764 } 31765 31766 const center = this.center; 31767 31768 transformVertex(_vA.set(- 0.5, - 0.5, 0), _mvPosition, center, _worldScale, sin, cos); 31769 transformVertex(_vB.set(0.5, - 0.5, 0), _mvPosition, center, _worldScale, sin, cos); 31770 transformVertex(_vC.set(0.5, 0.5, 0), _mvPosition, center, _worldScale, sin, cos); 31771 31772 _uvA.set(0, 0); 31773 _uvB.set(1, 0); 31774 _uvC.set(1, 1); 31775 31776 // check first triangle 31777 let intersect = raycaster.ray.intersectTriangle(_vA, _vB, _vC, false, _intersectPoint); 31778 31779 if (intersect === null) { 31780 31781 // check second triangle 31782 transformVertex(_vB.set(- 0.5, 0.5, 0), _mvPosition, center, _worldScale, sin, cos); 31783 _uvB.set(0, 1); 31784 31785 intersect = raycaster.ray.intersectTriangle(_vA, _vC, _vB, false, _intersectPoint); 31786 if (intersect === null) { 31787 31788 return; 31789 31790 } 31791 31792 } 31793 31794 const distance = raycaster.ray.origin.distanceTo(_intersectPoint); 31795 31796 if (distance < raycaster.near || distance > raycaster.far) return; 31797 31798 intersects.push({ 31799 31800 distance: distance, 31801 point: _intersectPoint.clone(), 31802 uv: Triangle.getInterpolation(_intersectPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2()), 31803 face: null, 31804 object: this 31805 31806 }); 31807 31808 } 31809 31810 copy(source, recursive) { 31811 31812 super.copy(source, recursive); 31813 31814 if (source.center !== undefined) this.center.copy(source.center); 31815 31816 this.material = source.material; 31817 31818 return this; 31819 31820 } 31821 31822} 31823 31824function transformVertex(vertexPosition, mvPosition, center, scale, sin, cos) { 31825 31826 // compute position in camera space 31827 _alignedPosition.subVectors(vertexPosition, center).addScalar(0.5).multiply(scale); 31828 31829 // to check if rotation is not zero 31830 if (sin !== undefined) { 31831 31832 _rotatedPosition.x = (cos * _alignedPosition.x) - (sin * _alignedPosition.y); 31833 _rotatedPosition.y = (sin * _alignedPosition.x) + (cos * _alignedPosition.y); 31834 31835 } else { 31836 31837 _rotatedPosition.copy(_alignedPosition); 31838 31839 } 31840 31841 31842 vertexPosition.copy(mvPosition); 31843 vertexPosition.x += _rotatedPosition.x; 31844 vertexPosition.y += _rotatedPosition.y; 31845 31846 // transform to world space 31847 vertexPosition.applyMatrix4(_viewWorldMatrix); 31848 31849} 31850 31851const _v1$2 = /*@__PURE__*/ new Vector3(); 31852const _v2$1 = /*@__PURE__*/ new Vector3(); 31853 31854class LOD extends Object3D { 31855 31856 constructor() { 31857 31858 super(); 31859 31860 this._currentLevel = 0; 31861 31862 this.type = 'LOD'; 31863 31864 Object.defineProperties(this, { 31865 levels: { 31866 enumerable: true, 31867 value: [] 31868 }, 31869 isLOD: { 31870 value: true, 31871 } 31872 }); 31873 31874 this.autoUpdate = true; 31875 31876 } 31877 31878 copy(source) { 31879 31880 super.copy(source, false); 31881 31882 const levels = source.levels; 31883 31884 for (let i = 0, l = levels.length; i < l; i++) { 31885 31886 const level = levels[i]; 31887 31888 this.addLevel(level.object.clone(), level.distance, level.hysteresis); 31889 31890 } 31891 31892 this.autoUpdate = source.autoUpdate; 31893 31894 return this; 31895 31896 } 31897 31898 addLevel(object, distance = 0, hysteresis = 0) { 31899 31900 distance = Math.abs(distance); 31901 31902 const levels = this.levels; 31903 31904 let l; 31905 31906 for (l = 0; l < levels.length; l++) { 31907 31908 if (distance < levels[l].distance) { 31909 31910 break; 31911 31912 } 31913 31914 } 31915 31916 levels.splice(l, 0, { distance: distance, hysteresis: hysteresis, object: object }); 31917 31918 this.add(object); 31919 31920 return this; 31921 31922 } 31923 31924 getCurrentLevel() { 31925 31926 return this._currentLevel; 31927 31928 } 31929 31930 31931 31932 getObjectForDistance(distance) { 31933 31934 const levels = this.levels; 31935 31936 if (levels.length > 0) { 31937 31938 let i, l; 31939 31940 for (i = 1, l = levels.length; i < l; i++) { 31941 31942 let levelDistance = levels[i].distance; 31943 31944 if (levels[i].object.visible) { 31945 31946 levelDistance -= levelDistance * levels[i].hysteresis; 31947 31948 } 31949 31950 if (distance < levelDistance) { 31951 31952 break; 31953 31954 } 31955 31956 } 31957 31958 return levels[i - 1].object; 31959 31960 } 31961 31962 return null; 31963 31964 } 31965 31966 raycast(raycaster, intersects) { 31967 31968 const levels = this.levels; 31969 31970 if (levels.length > 0) { 31971 31972 _v1$2.setFromMatrixPosition(this.matrixWorld); 31973 31974 const distance = raycaster.ray.origin.distanceTo(_v1$2); 31975 31976 this.getObjectForDistance(distance).raycast(raycaster, intersects); 31977 31978 } 31979 31980 } 31981 31982 update(camera) { 31983 31984 const levels = this.levels; 31985 31986 if (levels.length > 1) { 31987 31988 _v1$2.setFromMatrixPosition(camera.matrixWorld); 31989 _v2$1.setFromMatrixPosition(this.matrixWorld); 31990 31991 const distance = _v1$2.distanceTo(_v2$1) / camera.zoom; 31992 31993 levels[0].object.visible = true; 31994 31995 let i, l; 31996 31997 for (i = 1, l = levels.length; i < l; i++) { 31998 31999 let levelDistance = levels[i].distance; 32000 32001 if (levels[i].object.visible) { 32002 32003 levelDistance -= levelDistance * levels[i].hysteresis; 32004 32005 } 32006 32007 if (distance >= levelDistance) { 32008 32009 levels[i - 1].object.visible = false; 32010 levels[i].object.visible = true; 32011 32012 } else { 32013 32014 break; 32015 32016 } 32017 32018 } 32019 32020 this._currentLevel = i - 1; 32021 32022 for (; i < l; i++) { 32023 32024 levels[i].object.visible = false; 32025 32026 } 32027 32028 } 32029 32030 } 32031 32032 toJSON(meta) { 32033 32034 const data = super.toJSON(meta); 32035 32036 if (this.autoUpdate === false) data.object.autoUpdate = false; 32037 32038 data.object.levels = []; 32039 32040 const levels = this.levels; 32041 32042 for (let i = 0, l = levels.length; i < l; i++) { 32043 32044 const level = levels[i]; 32045 32046 data.object.levels.push({ 32047 object: level.object.uuid, 32048 distance: level.distance, 32049 hysteresis: level.hysteresis 32050 }); 32051 32052 } 32053 32054 return data; 32055 32056 } 32057 32058} 32059 32060const _basePosition = /*@__PURE__*/ new Vector3(); 32061 32062const _skinIndex = /*@__PURE__*/ new Vector4(); 32063const _skinWeight = /*@__PURE__*/ new Vector4(); 32064 32065const _vector3 = /*@__PURE__*/ new Vector3(); 32066const _matrix4 = /*@__PURE__*/ new Matrix4(); 32067const _vertex = /*@__PURE__*/ new Vector3(); 32068 32069const _sphere$4 = /*@__PURE__*/ new Sphere(); 32070const _inverseMatrix$2 = /*@__PURE__*/ new Matrix4(); 32071const _ray$2 = /*@__PURE__*/ new Ray(); 32072 32073class SkinnedMesh extends Mesh { 32074 32075 constructor(geometry, material) { 32076 32077 super(geometry, material); 32078 32079 this.isSkinnedMesh = true; 32080 32081 this.type = 'SkinnedMesh'; 32082 32083 this.bindMode = AttachedBindMode; 32084 this.bindMatrix = new Matrix4(); 32085 this.bindMatrixInverse = new Matrix4(); 32086 32087 this.boundingBox = null; 32088 this.boundingSphere = null; 32089 32090 } 32091 32092 computeBoundingBox() { 32093 32094 const geometry = this.geometry; 32095 32096 if (this.boundingBox === null) { 32097 32098 this.boundingBox = new Box3(); 32099 32100 } 32101 32102 this.boundingBox.makeEmpty(); 32103 32104 const positionAttribute = geometry.getAttribute('position'); 32105 32106 for (let i = 0; i < positionAttribute.count; i++) { 32107 32108 this.getVertexPosition(i, _vertex); 32109 this.boundingBox.expandByPoint(_vertex); 32110 32111 } 32112 32113 } 32114 32115 computeBoundingSphere() { 32116 32117 const geometry = this.geometry; 32118 32119 if (this.boundingSphere === null) { 32120 32121 this.boundingSphere = new Sphere(); 32122 32123 } 32124 32125 this.boundingSphere.makeEmpty(); 32126 32127 const positionAttribute = geometry.getAttribute('position'); 32128 32129 for (let i = 0; i < positionAttribute.count; i++) { 32130 32131 this.getVertexPosition(i, _vertex); 32132 this.boundingSphere.expandByPoint(_vertex); 32133 32134 } 32135 32136 } 32137 32138 copy(source, recursive) { 32139 32140 super.copy(source, recursive); 32141 32142 this.bindMode = source.bindMode; 32143 this.bindMatrix.copy(source.bindMatrix); 32144 this.bindMatrixInverse.copy(source.bindMatrixInverse); 32145 32146 this.skeleton = source.skeleton; 32147 32148 if (source.boundingBox !== null) this.boundingBox = source.boundingBox.clone(); 32149 if (source.boundingSphere !== null) this.boundingSphere = source.boundingSphere.clone(); 32150 32151 return this; 32152 32153 } 32154 32155 raycast(raycaster, intersects) { 32156 32157 const material = this.material; 32158 const matrixWorld = this.matrixWorld; 32159 32160 if (material === undefined) return; 32161
vendor: 13,367 bytes, lines 32162-32838
32162 // test with bounding sphere in world space 32163 32164 if (this.boundingSphere === null) this.computeBoundingSphere(); 32165 32166 _sphere$4.copy(this.boundingSphere); 32167 _sphere$4.applyMatrix4(matrixWorld); 32168 32169 if (raycaster.ray.intersectsSphere(_sphere$4) === false) return; 32170 32171 // convert ray to local space of skinned mesh 32172 32173 _inverseMatrix$2.copy(matrixWorld).invert(); 32174 _ray$2.copy(raycaster.ray).applyMatrix4(_inverseMatrix$2); 32175 32176 // test with bounding box in local space 32177 32178 if (this.boundingBox !== null) { 32179 32180 if (_ray$2.intersectsBox(this.boundingBox) === false) return; 32181 32182 } 32183 32184 // test for intersections with geometry 32185 32186 this._computeIntersections(raycaster, intersects, _ray$2); 32187 32188 } 32189 32190 getVertexPosition(index, target) { 32191 32192 super.getVertexPosition(index, target); 32193 32194 this.applyBoneTransform(index, target); 32195 32196 return target; 32197 32198 } 32199 32200 bind(skeleton, bindMatrix) { 32201 32202 this.skeleton = skeleton; 32203 32204 if (bindMatrix === undefined) { 32205 32206 this.updateMatrixWorld(true); 32207 32208 this.skeleton.calculateInverses(); 32209 32210 bindMatrix = this.matrixWorld; 32211 32212 } 32213 32214 this.bindMatrix.copy(bindMatrix); 32215 this.bindMatrixInverse.copy(bindMatrix).invert(); 32216 32217 } 32218 32219 pose() { 32220 32221 this.skeleton.pose(); 32222 32223 } 32224 32225 normalizeSkinWeights() { 32226 32227 const vector = new Vector4(); 32228 32229 const skinWeight = this.geometry.attributes.skinWeight; 32230 32231 for (let i = 0, l = skinWeight.count; i < l; i++) { 32232 32233 vector.fromBufferAttribute(skinWeight, i); 32234 32235 const scale = 1.0 / vector.manhattanLength(); 32236 32237 if (scale !== Infinity) { 32238 32239 vector.multiplyScalar(scale); 32240 32241 } else { 32242 32243 vector.set(1, 0, 0, 0); // do something reasonable 32244 32245 } 32246 32247 skinWeight.setXYZW(i, vector.x, vector.y, vector.z, vector.w); 32248 32249 } 32250 32251 } 32252 32253 updateMatrixWorld(force) { 32254 32255 super.updateMatrixWorld(force); 32256 32257 if (this.bindMode === AttachedBindMode) { 32258 32259 this.bindMatrixInverse.copy(this.matrixWorld).invert(); 32260 32261 } else if (this.bindMode === DetachedBindMode) { 32262 32263 this.bindMatrixInverse.copy(this.bindMatrix).invert(); 32264 32265 } else { 32266 32267 console.warn('THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode); 32268 32269 } 32270 32271 } 32272 32273 applyBoneTransform(index, vector) { 32274 32275 const skeleton = this.skeleton; 32276 const geometry = this.geometry; 32277 32278 _skinIndex.fromBufferAttribute(geometry.attributes.skinIndex, index); 32279 _skinWeight.fromBufferAttribute(geometry.attributes.skinWeight, index); 32280 32281 _basePosition.copy(vector).applyMatrix4(this.bindMatrix); 32282 32283 vector.set(0, 0, 0); 32284 32285 for (let i = 0; i < 4; i++) { 32286 32287 const weight = _skinWeight.getComponent(i); 32288 32289 if (weight !== 0) { 32290 32291 const boneIndex = _skinIndex.getComponent(i); 32292 32293 _matrix4.multiplyMatrices(skeleton.bones[boneIndex].matrixWorld, skeleton.boneInverses[boneIndex]); 32294 32295 vector.addScaledVector(_vector3.copy(_basePosition).applyMatrix4(_matrix4), weight); 32296 32297 } 32298 32299 } 32300 32301 return vector.applyMatrix4(this.bindMatrixInverse); 32302 32303 } 32304 32305 boneTransform(index, vector) { // @deprecated, r151 32306 32307 console.warn('THREE.SkinnedMesh: .boneTransform() was renamed to .applyBoneTransform() in r151.'); 32308 return this.applyBoneTransform(index, vector); 32309 32310 } 32311 32312 32313} 32314 32315class Bone extends Object3D { 32316 32317 constructor() { 32318 32319 super(); 32320 32321 this.isBone = true; 32322 32323 this.type = 'Bone'; 32324 32325 } 32326 32327} 32328 32329class DataTexture extends Texture { 32330 32331 constructor(data = null, width = 1, height = 1, format, type, mapping, wrapS, wrapT, magFilter = NearestFilter, minFilter = NearestFilter, anisotropy, colorSpace) { 32332 32333 super(null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace); 32334 32335 this.isDataTexture = true; 32336 32337 this.image = { data: data, width: width, height: height }; 32338 32339 this.generateMipmaps = false; 32340 this.flipY = false; 32341 this.unpackAlignment = 1; 32342 32343 } 32344 32345} 32346 32347const _offsetMatrix = /*@__PURE__*/ new Matrix4(); 32348const _identityMatrix$1 = /*@__PURE__*/ new Matrix4(); 32349 32350class Skeleton { 32351 32352 constructor(bones = [], boneInverses = []) { 32353 32354 this.uuid = generateUUID(); 32355 32356 this.bones = bones.slice(0); 32357 this.boneInverses = boneInverses; 32358 this.boneMatrices = null; 32359 32360 this.boneTexture = null; 32361 32362 this.init(); 32363 32364 } 32365 32366 init() { 32367 32368 const bones = this.bones; 32369 const boneInverses = this.boneInverses; 32370 32371 this.boneMatrices = new Float32Array(bones.length * 16); 32372 32373 // calculate inverse bone matrices if necessary 32374 32375 if (boneInverses.length === 0) { 32376 32377 this.calculateInverses(); 32378 32379 } else { 32380 32381 // handle special case 32382 32383 if (bones.length !== boneInverses.length) { 32384 32385 console.warn('THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.'); 32386 32387 this.boneInverses = []; 32388 32389 for (let i = 0, il = this.bones.length; i < il; i++) { 32390 32391 this.boneInverses.push(new Matrix4()); 32392 32393 } 32394 32395 } 32396 32397 } 32398 32399 } 32400 32401 calculateInverses() { 32402 32403 this.boneInverses.length = 0; 32404 32405 for (let i = 0, il = this.bones.length; i < il; i++) { 32406 32407 const inverse = new Matrix4(); 32408 32409 if (this.bones[i]) { 32410 32411 inverse.copy(this.bones[i].matrixWorld).invert(); 32412 32413 } 32414 32415 this.boneInverses.push(inverse); 32416 32417 } 32418 32419 } 32420 32421 pose() { 32422 32423 // recover the bind-time world matrices 32424 32425 for (let i = 0, il = this.bones.length; i < il; i++) { 32426 32427 const bone = this.bones[i]; 32428 32429 if (bone) { 32430 32431 bone.matrixWorld.copy(this.boneInverses[i]).invert(); 32432 32433 } 32434 32435 } 32436 32437 // compute the local matrices, positions, rotations and scales 32438 32439 for (let i = 0, il = this.bones.length; i < il; i++) { 32440 32441 const bone = this.bones[i]; 32442 32443 if (bone) { 32444 32445 if (bone.parent && bone.parent.isBone) { 32446 32447 bone.matrix.copy(bone.parent.matrixWorld).invert(); 32448 bone.matrix.multiply(bone.matrixWorld); 32449 32450 } else { 32451 32452 bone.matrix.copy(bone.matrixWorld); 32453 32454 } 32455 32456 bone.matrix.decompose(bone.position, bone.quaternion, bone.scale); 32457 32458 } 32459 32460 } 32461 32462 } 32463 32464 update() { 32465 32466 const bones = this.bones; 32467 const boneInverses = this.boneInverses; 32468 const boneMatrices = this.boneMatrices; 32469 const boneTexture = this.boneTexture; 32470 32471 // flatten bone matrices to array 32472 32473 for (let i = 0, il = bones.length; i < il; i++) { 32474 32475 // compute the offset between the current and the original transform 32476 32477 const matrix = bones[i] ? bones[i].matrixWorld : _identityMatrix$1; 32478 32479 _offsetMatrix.multiplyMatrices(matrix, boneInverses[i]); 32480 _offsetMatrix.toArray(boneMatrices, i * 16); 32481 32482 } 32483 32484 if (boneTexture !== null) { 32485 32486 boneTexture.needsUpdate = true; 32487 32488 } 32489 32490 } 32491 32492 clone() { 32493 32494 return new Skeleton(this.bones, this.boneInverses); 32495 32496 } 32497 32498 computeBoneTexture() { 32499 32500 // layout (1 matrix = 4 pixels) 32501 // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) 32502 // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8) 32503 // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16) 32504 // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32) 32505 // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64) 32506 32507 let size = Math.sqrt(this.bones.length * 4); // 4 pixels needed for 1 matrix 32508 size = Math.ceil(size / 4) * 4; 32509 size = Math.max(size, 4); 32510 32511 const boneMatrices = new Float32Array(size * size * 4); // 4 floats per RGBA pixel 32512 boneMatrices.set(this.boneMatrices); // copy current values 32513 32514 const boneTexture = new DataTexture(boneMatrices, size, size, RGBAFormat, FloatType); 32515 boneTexture.needsUpdate = true; 32516 32517 this.boneMatrices = boneMatrices; 32518 this.boneTexture = boneTexture; 32519 32520 return this; 32521 32522 } 32523 32524 getBoneByName(name) { 32525 32526 for (let i = 0, il = this.bones.length; i < il; i++) { 32527 32528 const bone = this.bones[i]; 32529 32530 if (bone.name === name) { 32531 32532 return bone; 32533 32534 } 32535 32536 } 32537 32538 return undefined; 32539 32540 } 32541 32542 dispose() { 32543 32544 if (this.boneTexture !== null) { 32545 32546 this.boneTexture.dispose(); 32547 32548 this.boneTexture = null; 32549 32550 } 32551 32552 } 32553 32554 fromJSON(json, bones) { 32555 32556 this.uuid = json.uuid; 32557 32558 for (let i = 0, l = json.bones.length; i < l; i++) { 32559 32560 const uuid = json.bones[i]; 32561 let bone = bones[uuid]; 32562 32563 if (bone === undefined) { 32564 32565 console.warn('THREE.Skeleton: No bone found with UUID:', uuid); 32566 bone = new Bone(); 32567 32568 } 32569 32570 this.bones.push(bone); 32571 this.boneInverses.push(new Matrix4().fromArray(json.boneInverses[i])); 32572 32573 } 32574 32575 this.init(); 32576 32577 return this; 32578 32579 } 32580 32581 toJSON() { 32582 32583 const data = { 32584 metadata: { 32585 version: 4.6, 32586 type: 'Skeleton', 32587 generator: 'Skeleton.toJSON' 32588 }, 32589 bones: [], 32590 boneInverses: [] 32591 }; 32592 32593 data.uuid = this.uuid; 32594 32595 const bones = this.bones; 32596 const boneInverses = this.boneInverses; 32597 32598 for (let i = 0, l = bones.length; i < l; i++) { 32599 32600 const bone = bones[i]; 32601 data.bones.push(bone.uuid); 32602 32603 const boneInverse = boneInverses[i]; 32604 data.boneInverses.push(boneInverse.toArray()); 32605 32606 } 32607 32608 return data; 32609 32610 } 32611 32612} 32613 32614class InstancedBufferAttribute extends BufferAttribute { 32615 32616 constructor(array, itemSize, normalized, meshPerAttribute = 1) { 32617 32618 super(array, itemSize, normalized); 32619 32620 this.isInstancedBufferAttribute = true; 32621 32622 this.meshPerAttribute = meshPerAttribute; 32623 32624 } 32625 32626 copy(source) { 32627 32628 super.copy(source); 32629 32630 this.meshPerAttribute = source.meshPerAttribute; 32631 32632 return this; 32633 32634 } 32635 32636 toJSON() { 32637 32638 const data = super.toJSON(); 32639 32640 data.meshPerAttribute = this.meshPerAttribute; 32641 32642 data.isInstancedBufferAttribute = true; 32643 32644 return data; 32645 32646 } 32647 32648} 32649 32650const _instanceLocalMatrix = /*@__PURE__*/ new Matrix4(); 32651const _instanceWorldMatrix = /*@__PURE__*/ new Matrix4(); 32652 32653const _instanceIntersects = []; 32654 32655const _box3 = /*@__PURE__*/ new Box3(); 32656const _identity = /*@__PURE__*/ new Matrix4(); 32657const _mesh$1 = /*@__PURE__*/ new Mesh(); 32658const _sphere$3 = /*@__PURE__*/ new Sphere(); 32659 32660class InstancedMesh extends Mesh { 32661 32662 constructor(geometry, material, count) { 32663 32664 super(geometry, material); 32665 32666 this.isInstancedMesh = true; 32667 32668 this.instanceMatrix = new InstancedBufferAttribute(new Float32Array(count * 16), 16); 32669 this.instanceColor = null; 32670 32671 this.count = count; 32672 32673 this.boundingBox = null; 32674 this.boundingSphere = null; 32675 32676 for (let i = 0; i < count; i++) { 32677 32678 this.setMatrixAt(i, _identity); 32679 32680 } 32681 32682 } 32683 32684 computeBoundingBox() { 32685 32686 const geometry = this.geometry; 32687 const count = this.count; 32688 32689 if (this.boundingBox === null) { 32690 32691 this.boundingBox = new Box3(); 32692 32693 } 32694 32695 if (geometry.boundingBox === null) { 32696 32697 geometry.computeBoundingBox(); 32698 32699 } 32700 32701 this.boundingBox.makeEmpty(); 32702 32703 for (let i = 0; i < count; i++) { 32704 32705 this.getMatrixAt(i, _instanceLocalMatrix); 32706 32707 _box3.copy(geometry.boundingBox).applyMatrix4(_instanceLocalMatrix); 32708 32709 this.boundingBox.union(_box3); 32710 32711 } 32712 32713 } 32714 32715 computeBoundingSphere() { 32716 32717 const geometry = this.geometry; 32718 const count = this.count; 32719 32720 if (this.boundingSphere === null) { 32721 32722 this.boundingSphere = new Sphere(); 32723 32724 } 32725 32726 if (geometry.boundingSphere === null) { 32727 32728 geometry.computeBoundingSphere(); 32729 32730 } 32731 32732 this.boundingSphere.makeEmpty(); 32733 32734 for (let i = 0; i < count; i++) { 32735 32736 this.getMatrixAt(i, _instanceLocalMatrix); 32737 32738 _sphere$3.copy(geometry.boundingSphere).applyMatrix4(_instanceLocalMatrix); 32739 32740 this.boundingSphere.union(_sphere$3); 32741 32742 } 32743 32744 } 32745 32746 copy(source, recursive) { 32747 32748 super.copy(source, recursive); 32749 32750 this.instanceMatrix.copy(source.instanceMatrix); 32751 32752 if (source.instanceColor !== null) this.instanceColor = source.instanceColor.clone(); 32753 32754 this.count = source.count; 32755 32756 if (source.boundingBox !== null) this.boundingBox = source.boundingBox.clone(); 32757 if (source.boundingSphere !== null) this.boundingSphere = source.boundingSphere.clone(); 32758 32759 return this; 32760 32761 } 32762 32763 getColorAt(index, color) { 32764 32765 color.fromArray(this.instanceColor.array, index * 3); 32766 32767 } 32768 32769 getMatrixAt(index, matrix) { 32770 32771 matrix.fromArray(this.instanceMatrix.array, index * 16); 32772 32773 } 32774 32775 raycast(raycaster, intersects) { 32776 32777 const matrixWorld = this.matrixWorld; 32778 const raycastTimes = this.count; 32779 32780 _mesh$1.geometry = this.geometry; 32781 _mesh$1.material = this.material; 32782 32783 if (_mesh$1.material === undefined) return; 32784 32785 // test with bounding sphere first 32786 32787 if (this.boundingSphere === null) this.computeBoundingSphere(); 32788 32789 _sphere$3.copy(this.boundingSphere); 32790 _sphere$3.applyMatrix4(matrixWorld); 32791 32792 if (raycaster.ray.intersectsSphere(_sphere$3) === false) return; 32793 32794 // now test each instance 32795 32796 for (let instanceId = 0; instanceId < raycastTimes; instanceId++) { 32797 32798 // calculate the world matrix for each instance 32799 32800 this.getMatrixAt(instanceId, _instanceLocalMatrix); 32801 32802 _instanceWorldMatrix.multiplyMatrices(matrixWorld, _instanceLocalMatrix); 32803 32804 // the mesh represents this single instance 32805 32806 _mesh$1.matrixWorld = _instanceWorldMatrix; 32807 32808 _mesh$1.raycast(raycaster, _instanceIntersects); 32809 32810 // process the result of raycast 32811 32812 for (let i = 0, l = _instanceIntersects.length; i < l; i++) { 32813 32814 const intersect = _instanceIntersects[i]; 32815 intersect.instanceId = instanceId; 32816 intersect.object = this; 32817 intersects.push(intersect); 32818 32819 } 32820 32821 _instanceIntersects.length = 0; 32822 32823 } 32824 32825 } 32826 32827 setColorAt(index, color) { 32828 32829 if (this.instanceColor === null) { 32830 32831 this.instanceColor = new InstancedBufferAttribute(new Float32Array(this.instanceMatrix.count * 3), 3); 32832 32833 } 32834 32835 color.toArray(this.instanceColor.array, index * 3); 32836 32837 } 32838
32839 setMatrixAt(index, matrix) { 32840 32841 matrix.toArray(this.instanceMatrix.array, index * 16); 32842 32843 } 32844 32845 updateMorphTargets() { 32846 32847 } 32848 32849 dispose() { 32850 32851 this.dispatchEvent({ type: 'dispose' }); 32852 32853 } 32854 32855} 32856 32857function sortOpaque(a, b) { 32858 32859 return a.z - b.z; 32860 32861} 32862 32863function sortTransparent(a, b) { 32864 32865 return b.z - a.z; 32866 32867} 32868 32869class MultiDrawRenderList { 32870 32871 constructor() { 32872 32873 this.index = 0; 32874 this.pool = []; 32875 this.list = []; 32876 32877 } 32878 32879 push(drawRange, z) { 32880 32881 const pool = this.pool; 32882 const list = this.list; 32883 if (this.index >= pool.length) { 32884 32885 pool.push({ 32886 32887 start: - 1, 32888 count: - 1, 32889 z: - 1, 32890 32891 }); 32892 32893 } 32894 32895 const item = pool[this.index]; 32896 list.push(item); 32897 this.index++; 32898 32899 item.start = drawRange.start; 32900 item.count = drawRange.count; 32901 item.z = z; 32902 32903 } 32904 32905 reset() { 32906 32907 this.list.length = 0; 32908 this.index = 0; 32909 32910 } 32911 32912} 32913 32914const ID_ATTR_NAME = 'batchId'; 32915const _matrix = /*@__PURE__*/ new Matrix4(); 32916const _invMatrixWorld = /*@__PURE__*/ new Matrix4(); 32917const _identityMatrix = /*@__PURE__*/ new Matrix4(); 32918const _projScreenMatrix$2 = /*@__PURE__*/ new Matrix4(); 32919const _frustum = /*@__PURE__*/ new Frustum(); 32920const _box$1 = /*@__PURE__*/ new Box3(); 32921const _sphere$2 = /*@__PURE__*/ new Sphere(); 32922const _vector$5 = /*@__PURE__*/ new Vector3(); 32923const _renderList = /*@__PURE__*/ new MultiDrawRenderList(); 32924const _mesh = /*@__PURE__*/ new Mesh(); 32925const _batchIntersects = []; 32926 32927// @TODO: SkinnedMesh support? 32928// @TODO: geometry.groups support? 32929// @TODO: geometry.drawRange support? 32930// @TODO: geometry.morphAttributes support? 32931// @TODO: Support uniform parameter per geometry 32932// @TODO: Add an "optimize" function to pack geometry and remove data gaps 32933 32934// copies data from attribute "src" into "target" starting at "targetOffset" 32935function copyAttributeData(src, target, targetOffset = 0) { 32936 32937 const itemSize = target.itemSize; 32938 if (src.isInterleavedBufferAttribute || src.array.constructor !== target.array.constructor) { 32939 32940 // use the component getters and setters if the array data cannot 32941 // be copied directly 32942 const vertexCount = src.count; 32943 for (let i = 0; i < vertexCount; i++) { 32944 32945 for (let c = 0; c < itemSize; c++) { 32946 32947 target.setComponent(i + targetOffset, c, src.getComponent(i, c)); 32948 32949 } 32950 32951 } 32952 32953 } else { 32954 32955 // faster copy approach using typed array set function 32956 target.array.set(src.array, targetOffset * itemSize); 32957 32958 } 32959 32960 target.needsUpdate = true; 32961 32962} 32963 32964class BatchedMesh extends Mesh { 32965 32966 get maxGeometryCount() { 32967 32968 return this._maxGeometryCount; 32969 32970 } 32971 32972 constructor(maxGeometryCount, maxVertexCount, maxIndexCount = maxVertexCount * 2, material) { 32973 32974 super(new BufferGeometry(), material); 32975 32976 this.isBatchedMesh = true; 32977 this.perObjectFrustumCulled = true; 32978 this.sortObjects = true; 32979 this.boundingBox = null; 32980 this.boundingSphere = null; 32981 this.customSort = null; 32982 32983 this._drawRanges = []; 32984 this._reservedRanges = []; 32985 32986 this._visibility = []; 32987 this._active = []; 32988 this._bounds = []; 32989 32990 this._maxGeometryCount = maxGeometryCount; 32991 this._maxVertexCount = maxVertexCount; 32992 this._maxIndexCount = maxIndexCount; 32993 32994 this._geometryInitialized = false; 32995 this._geometryCount = 0; 32996 this._multiDrawCounts = new Int32Array(maxGeometryCount); 32997 this._multiDrawStarts = new Int32Array(maxGeometryCount); 32998 this._multiDrawCount = 0; 32999 this._visibilityChanged = true; 33000 33001 // Local matrix per geometry by using data texture 33002 this._matricesTexture = null; 33003 33004 this._initMatricesTexture(); 33005 33006 } 33007 33008 _initMatricesTexture() { 33009 33010 // layout (1 matrix = 4 pixels) 33011 // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) 33012 // with 8x8 pixel texture max 16 matrices * 4 pixels = (8 * 8) 33013 // 16x16 pixel texture max 64 matrices * 4 pixels = (16 * 16) 33014 // 32x32 pixel texture max 256 matrices * 4 pixels = (32 * 32) 33015 // 64x64 pixel texture max 1024 matrices * 4 pixels = (64 * 64) 33016 33017 let size = Math.sqrt(this._maxGeometryCount * 4); // 4 pixels needed for 1 matrix 33018 size = Math.ceil(size / 4) * 4; 33019 size = Math.max(size, 4); 33020 33021 const matricesArray = new Float32Array(size * size * 4); // 4 floats per RGBA pixel 33022 const matricesTexture = new DataTexture(matricesArray, size, size, RGBAFormat, FloatType); 33023 33024 this._matricesTexture = matricesTexture; 33025 33026 } 33027 33028 _initializeGeometry(reference) { 33029 33030 const geometry = this.geometry; 33031 const maxVertexCount = this._maxVertexCount; 33032 const maxGeometryCount = this._maxGeometryCount; 33033 const maxIndexCount = this._maxIndexCount; 33034 if (this._geometryInitialized === false) { 33035 33036 for (const attributeName in reference.attributes) { 33037 33038 const srcAttribute = reference.getAttribute(attributeName); 33039 const { array, itemSize, normalized } = srcAttribute; 33040 33041 const dstArray = new array.constructor(maxVertexCount * itemSize); 33042 const dstAttribute = new srcAttribute.constructor(dstArray, itemSize, normalized); 33043 dstAttribute.setUsage(srcAttribute.usage); 33044 33045 geometry.setAttribute(attributeName, dstAttribute); 33046 33047 } 33048 33049 if (reference.getIndex() !== null) { 33050 33051 const indexArray = maxVertexCount > 65536 33052 ? new Uint32Array(maxIndexCount) 33053 : new Uint16Array(maxIndexCount); 33054 33055 geometry.setIndex(new BufferAttribute(indexArray, 1)); 33056 33057 } 33058 33059 const idArray = maxGeometryCount > 65536 33060 ? new Uint32Array(maxVertexCount) 33061 : new Uint16Array(maxVertexCount); 33062 geometry.setAttribute(ID_ATTR_NAME, new BufferAttribute(idArray, 1)); 33063 33064 this._geometryInitialized = true; 33065 33066 } 33067 33068 } 33069 33070 // Make sure the geometry is compatible with the existing combined geometry atributes 33071 _validateGeometry(geometry) { 33072
33073 // check that the geometry doesn't have a version of our reserved id attribute 33074 if (geometry.getAttribute(ID_ATTR_NAME)) { 33075 33076 throw new Error(`BatchedMesh: Geometry cannot use attribute "${ID_ATTR_NAME}"`); 33077 33078 } 33079 33080 // check to ensure the geometries are using consistent attributes and indices 33081 const batchGeometry = this.geometry; 33082 if (Boolean(geometry.getIndex()) !== Boolean(batchGeometry.getIndex())) { 33083 33084 throw new Error('BatchedMesh: All geometries must consistently have "index".'); 33085 33086 } 33087 33088 for (const attributeName in batchGeometry.attributes) { 33089 33090 if (attributeName === ID_ATTR_NAME) { 33091 33092 continue; 33093 33094 } 33095 33096 if (!geometry.hasAttribute(attributeName)) { 33097 33098 throw new Error(`BatchedMesh: Added geometry missing "${attributeName}". All geometries must have consistent attributes.`); 33099 33100 } 33101 33102 const srcAttribute = geometry.getAttribute(attributeName); 33103 const dstAttribute = batchGeometry.getAttribute(attributeName); 33104 if (srcAttribute.itemSize !== dstAttribute.itemSize || srcAttribute.normalized !== dstAttribute.normalized) { 33105 33106 throw new Error('BatchedMesh: All attributes must have a consistent itemSize and normalized value.'); 33107 33108 } 33109 33110 } 33111 33112 } 33113 33114 setCustomSort(func) { 33115 33116 this.customSort = func; 33117 return this; 33118 33119 } 33120 33121 computeBoundingBox() { 33122 33123 if (this.boundingBox === null) { 33124 33125 this.boundingBox = new Box3(); 33126 33127 } 33128 33129 const geometryCount = this._geometryCount; 33130 const boundingBox = this.boundingBox; 33131 const active = this._active; 33132 33133 boundingBox.makeEmpty(); 33134 for (let i = 0; i < geometryCount; i++) { 33135 33136 if (active[i] === false) continue; 33137 33138 this.getMatrixAt(i, _matrix); 33139 this.getBoundingBoxAt(i, _box$1).applyMatrix4(_matrix); 33140 boundingBox.union(_box$1); 33141 33142 } 33143 33144 } 33145 33146 computeBoundingSphere() { 33147 33148 if (this.boundingSphere === null) { 33149 33150 this.boundingSphere = new Sphere(); 33151 33152 } 33153 33154 const geometryCount = this._geometryCount; 33155 const boundingSphere = this.boundingSphere; 33156 const active = this._active; 33157 33158 boundingSphere.makeEmpty(); 33159 for (let i = 0; i < geometryCount; i++) { 33160 33161 if (active[i] === false) continue; 33162 33163 this.getMatrixAt(i, _matrix); 33164 this.getBoundingSphereAt(i, _sphere$2).applyMatrix4(_matrix); 33165 boundingSphere.union(_sphere$2); 33166 33167 } 33168 33169 } 33170 33171 addGeometry(geometry, vertexCount = - 1, indexCount = - 1) { 33172 33173 this._initializeGeometry(geometry); 33174 33175 this._validateGeometry(geometry); 33176 33177 // ensure we're not over geometry 33178 if (this._geometryCount >= this._maxGeometryCount) { 33179 33180 throw new Error('BatchedMesh: Maximum geometry count reached.'); 33181 33182 } 33183 33184 // get the necessary range fo the geometry 33185 const reservedRange = { 33186 vertexStart: - 1, 33187 vertexCount: - 1, 33188 indexStart: - 1, 33189 indexCount: - 1, 33190 }; 33191 33192 let lastRange = null; 33193 const reservedRanges = this._reservedRanges; 33194 const drawRanges = this._drawRanges; 33195 const bounds = this._bounds; 33196 if (this._geometryCount !== 0) { 33197 33198 lastRange = reservedRanges[reservedRanges.length - 1]; 33199 33200 } 33201 33202 if (vertexCount === - 1) { 33203 33204 reservedRange.vertexCount = geometry.getAttribute('position').count; 33205 33206 } else { 33207 33208 reservedRange.vertexCount = vertexCount; 33209 33210 } 33211 33212 if (lastRange === null) { 33213 33214 reservedRange.vertexStart = 0; 33215 33216 } else { 33217 33218 reservedRange.vertexStart = lastRange.vertexStart + lastRange.vertexCount; 33219 33220 } 33221 33222 const index = geometry.getIndex(); 33223 const hasIndex = index !== null; 33224 if (hasIndex) { 33225 33226 if (indexCount === - 1) { 33227 33228 reservedRange.indexCount = index.count; 33229 33230 } else { 33231 33232 reservedRange.indexCount = indexCount; 33233 33234 } 33235 33236 if (lastRange === null) { 33237 33238 reservedRange.indexStart = 0; 33239 33240 } else { 33241 33242 reservedRange.indexStart = lastRange.indexStart + lastRange.indexCount; 33243 33244 } 33245 33246 } 33247 33248 if ( 33249 reservedRange.indexStart !== - 1 && 33250 reservedRange.indexStart + reservedRange.indexCount > this._maxIndexCount || 33251 reservedRange.vertexStart + reservedRange.vertexCount > this._maxVertexCount 33252 ) { 33253 33254 throw new Error('BatchedMesh: Reserved space request exceeds the maximum buffer size.'); 33255 33256 } 33257 33258 const visibility = this._visibility; 33259 const active = this._active; 33260 const matricesTexture = this._matricesTexture; 33261 const matricesArray = this._matricesTexture.image.data; 33262 33263 // push new visibility states 33264 visibility.push(true); 33265 active.push(true); 33266 33267 // update id 33268 const geometryId = this._geometryCount; 33269 this._geometryCount++; 33270 33271 // initialize matrix information 33272 _identityMatrix.toArray(matricesArray, geometryId * 16); 33273 matricesTexture.needsUpdate = true; 33274 33275 // add the reserved range and draw range objects 33276 reservedRanges.push(reservedRange); 33277 drawRanges.push({ 33278 start: hasIndex ? reservedRange.indexStart : reservedRange.vertexStart, 33279 count: - 1 33280 }); 33281 bounds.push({ 33282 boxInitialized: false, 33283 box: new Box3(), 33284 33285 sphereInitialized: false, 33286 sphere: new Sphere() 33287 }); 33288 33289 // set the id for the geometry 33290 const idAttribute = this.geometry.getAttribute(ID_ATTR_NAME); 33291 for (let i = 0; i < reservedRange.vertexCount; i++) { 33292 33293 idAttribute.setX(reservedRange.vertexStart + i, geometryId); 33294 33295 } 33296 33297 idAttribute.needsUpdate = true; 33298 33299 // update the geometry 33300 this.setGeometryAt(geometryId, geometry); 33301 33302 return geometryId; 33303 33304 } 33305 33306 setGeometryAt(id, geometry) { 33307 33308 if (id >= this._geometryCount) { 33309 33310 throw new Error('BatchedMesh: Maximum geometry count reached.'); 33311 33312 } 33313
33314 this._validateGeometry(geometry); 33315 33316 const batchGeometry = this.geometry; 33317 const hasIndex = batchGeometry.getIndex() !== null; 33318 const dstIndex = batchGeometry.getIndex(); 33319 const srcIndex = geometry.getIndex(); 33320 const reservedRange = this._reservedRanges[id]; 33321 if ( 33322 hasIndex && 33323 srcIndex.count > reservedRange.indexCount || 33324 geometry.attributes.position.count > reservedRange.vertexCount 33325 ) { 33326 33327 throw new Error('BatchedMesh: Reserved space not large enough for provided geometry.'); 33328 33329 } 33330 33331 // copy geometry over 33332 const vertexStart = reservedRange.vertexStart; 33333 const vertexCount = reservedRange.vertexCount; 33334 for (const attributeName in batchGeometry.attributes) { 33335 33336 if (attributeName === ID_ATTR_NAME) { 33337 33338 continue; 33339 33340 } 33341 33342 // copy attribute data 33343 const srcAttribute = geometry.getAttribute(attributeName); 33344 const dstAttribute = batchGeometry.getAttribute(attributeName); 33345 copyAttributeData(srcAttribute, dstAttribute, vertexStart); 33346 33347 // fill the rest in with zeroes 33348 const itemSize = srcAttribute.itemSize; 33349 for (let i = srcAttribute.count, l = vertexCount; i < l; i++) { 33350 33351 const index = vertexStart + i; 33352 for (let c = 0; c < itemSize; c++) { 33353 33354 dstAttribute.setComponent(index, c, 0); 33355 33356 } 33357 33358 } 33359 33360 dstAttribute.needsUpdate = true; 33361 33362 } 33363 33364 // copy index 33365 if (hasIndex) { 33366 33367 const indexStart = reservedRange.indexStart; 33368 33369 // copy index data over 33370 for (let i = 0; i < srcIndex.count; i++) { 33371 33372 dstIndex.setX(indexStart + i, vertexStart + srcIndex.getX(i)); 33373 33374 } 33375 33376 // fill the rest in with zeroes 33377 for (let i = srcIndex.count, l = reservedRange.indexCount; i < l; i++) { 33378 33379 dstIndex.setX(indexStart + i, vertexStart); 33380 33381 } 33382 33383 dstIndex.needsUpdate = true; 33384 33385 } 33386 33387 // store the bounding boxes 33388 const bound = this._bounds[id]; 33389 if (geometry.boundingBox !== null) { 33390 33391 bound.box.copy(geometry.boundingBox); 33392 bound.boxInitialized = true; 33393 33394 } else { 33395 33396 bound.boxInitialized = false; 33397 33398 } 33399 33400 if (geometry.boundingSphere !== null) { 33401 33402 bound.sphere.copy(geometry.boundingSphere); 33403 bound.sphereInitialized = true; 33404 33405 } else { 33406 33407 bound.sphereInitialized = false; 33408 33409 } 33410 33411 // set drawRange count 33412 const drawRange = this._drawRanges[id]; 33413 const posAttr = geometry.getAttribute('position'); 33414 drawRange.count = hasIndex ? srcIndex.count : posAttr.count; 33415 this._visibilityChanged = true; 33416 33417 return id; 33418 33419 } 33420 33421 deleteGeometry(geometryId) { 33422 33423 // Note: User needs to call optimize() afterward to pack the data. 33424 33425 const active = this._active; 33426 if (geometryId >= active.length || active[geometryId] === false) { 33427 33428 return this; 33429 33430 } 33431 33432 active[geometryId] = false; 33433 this._visibilityChanged = true; 33434 33435 return this; 33436 33437 } 33438 33439 // get bounding box and compute it if it doesn't exist 33440 getBoundingBoxAt(id, target) { 33441 33442 const active = this._active; 33443 if (active[id] === false) { 33444 33445 return this; 33446 33447 } 33448 33449 // compute bounding box 33450 const bound = this._bounds[id]; 33451 const box = bound.box; 33452 const geometry = this.geometry; 33453 if (bound.boxInitialized === false) { 33454 33455 box.makeEmpty(); 33456 33457 const index = geometry.index; 33458 const position = geometry.attributes.position; 33459 const drawRange = this._drawRanges[id]; 33460 for (let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i++) { 33461 33462 let iv = i; 33463 if (index) { 33464 33465 iv = index.getX(iv); 33466 33467 } 33468 33469 box.expandByPoint(_vector$5.fromBufferAttribute(position, iv)); 33470 33471 } 33472 33473 bound.boxInitialized = true; 33474 33475 } 33476 33477 target.copy(box); 33478 return target; 33479 33480 } 33481 33482 // get bounding sphere and compute it if it doesn't exist 33483 getBoundingSphereAt(id, target) { 33484 33485 const active = this._active; 33486 if (active[id] === false) { 33487 33488 return this; 33489 33490 } 33491 33492 // compute bounding sphere 33493 const bound = this._bounds[id]; 33494 const sphere = bound.sphere; 33495 const geometry = this.geometry; 33496 if (bound.sphereInitialized === false) { 33497 33498 sphere.makeEmpty(); 33499 33500 this.getBoundingBoxAt(id, _box$1); 33501 _box$1.getCenter(sphere.center); 33502 33503 const index = geometry.index;
33504 const position = geometry.attributes.position; 33505 const drawRange = this._drawRanges[id]; 33506 33507 let maxRadiusSq = 0; 33508 for (let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i++) { 33509 33510 let iv = i; 33511 if (index) { 33512 33513 iv = index.getX(iv); 33514 33515 } 33516 33517 _vector$5.fromBufferAttribute(position, iv); 33518 maxRadiusSq = Math.max(maxRadiusSq, sphere.center.distanceToSquared(_vector$5)); 33519 33520 } 33521 33522 sphere.radius = Math.sqrt(maxRadiusSq); 33523 bound.sphereInitialized = true; 33524 33525 } 33526 33527 target.copy(sphere); 33528 return target; 33529 33530 } 33531 33532 setMatrixAt(geometryId, matrix) { 33533 33534 // @TODO: Map geometryId to index of the arrays because 33535 // optimize() can make geometryId mismatch the index 33536 33537 const active = this._active; 33538 const matricesTexture = this._matricesTexture; 33539 const matricesArray = this._matricesTexture.image.data; 33540 const geometryCount = this._geometryCount; 33541 if (geometryId >= geometryCount || active[geometryId] === false) { 33542 33543 return this; 33544 33545 } 33546 33547 matrix.toArray(matricesArray, geometryId * 16); 33548 matricesTexture.needsUpdate = true; 33549 33550 return this; 33551 33552 } 33553 33554 getMatrixAt(geometryId, matrix) { 33555 33556 const active = this._active; 33557 const matricesArray = this._matricesTexture.image.data; 33558 const geometryCount = this._geometryCount; 33559 if (geometryId >= geometryCount || active[geometryId] === false) { 33560 33561 return null; 33562 33563 } 33564 33565 return matrix.fromArray(matricesArray, geometryId * 16); 33566 33567 } 33568 33569 setVisibleAt(geometryId, value) { 33570 33571 const visibility = this._visibility; 33572 const active = this._active; 33573 const geometryCount = this._geometryCount; 33574 33575 // if the geometry is out of range, not active, or visibility state 33576 // does not change then return early 33577 if ( 33578 geometryId >= geometryCount || 33579 active[geometryId] === false || 33580 visibility[geometryId] === value 33581 ) { 33582 33583 return this; 33584 33585 } 33586 33587 visibility[geometryId] = value; 33588 this._visibilityChanged = true; 33589 33590 return this; 33591 33592 } 33593 33594 getVisibleAt(geometryId) { 33595 33596 const visibility = this._visibility; 33597 const active = this._active; 33598 const geometryCount = this._geometryCount; 33599 33600 // return early if the geometry is out of range or not active 33601 if (geometryId >= geometryCount || active[geometryId] === false) { 33602 33603 return false; 33604 33605 } 33606 33607 return visibility[geometryId]; 33608 33609 } 33610 33611 raycast(raycaster, intersects) { 33612 33613 const visibility = this._visibility; 33614 const active = this._active; 33615 const drawRanges = this._drawRanges; 33616 const geometryCount = this._geometryCount; 33617 const matrixWorld = this.matrixWorld; 33618 const batchGeometry = this.geometry; 33619 33620 // iterate over each geometry 33621 _mesh.material = this.material; 33622 _mesh.geometry.index = batchGeometry.index; 33623 _mesh.geometry.attributes = batchGeometry.attributes; 33624 if (_mesh.geometry.boundingBox === null) { 33625 33626 _mesh.geometry.boundingBox = new Box3(); 33627 33628 } 33629 33630 if (_mesh.geometry.boundingSphere === null) { 33631 33632 _mesh.geometry.boundingSphere = new Sphere(); 33633 33634 } 33635 33636 for (let i = 0; i < geometryCount; i++) { 33637 33638 if (!visibility[i] || !active[i]) { 33639 33640 continue; 33641 33642 } 33643 33644 const drawRange = drawRanges[i]; 33645 _mesh.geometry.setDrawRange(drawRange.start, drawRange.count); 33646 33647 // ge the intersects 33648 this.getMatrixAt(i, _mesh.matrixWorld).premultiply(matrixWorld); 33649 this.getBoundingBoxAt(i, _mesh.geometry.boundingBox); 33650 this.getBoundingSphereAt(i, _mesh.geometry.boundingSphere); 33651 _mesh.raycast(raycaster, _batchIntersects); 33652 33653 // add batch id to the intersects 33654 for (let j = 0, l = _batchIntersects.length; j < l; j++) { 33655 33656 const intersect = _batchIntersects[j]; 33657 intersect.object = this; 33658 intersect.batchId = i; 33659 intersects.push(intersect); 33660 33661 } 33662 33663 _batchIntersects.length = 0; 33664 33665 } 33666 33667 _mesh.material = null; 33668 _mesh.geometry.index = null; 33669 _mesh.geometry.attributes = {}; 33670 _mesh.geometry.setDrawRange(0, Infinity); 33671 33672 } 33673 33674 copy(source) { 33675 33676 super.copy(source); 33677 33678 this.geometry = source.geometry.clone(); 33679 this.perObjectFrustumCulled = source.perObjectFrustumCulled; 33680 this.sortObjects = source.sortObjects; 33681 this.boundingBox = source.boundingBox !== null ? source.boundingBox.clone() : null; 33682 this.boundingSphere = source.boundingSphere !== null ? source.boundingSphere.clone() : null; 33683 33684 this._drawRanges = source._drawRanges.map(range => ({ ...range })); 33685 this._reservedRanges = source._reservedRanges.map(range => ({ ...range })); 33686 33687 this._visibility = source._visibility.slice(); 33688 this._active = source._active.slice(); 33689 this._bounds = source._bounds.map(bound => ({
33690 boxInitialized: bound.boxInitialized, 33691 box: bound.box.clone(), 33692 33693 sphereInitialized: bound.sphereInitialized, 33694 sphere: bound.sphere.clone() 33695 })); 33696 33697 this._maxGeometryCount = source._maxGeometryCount; 33698 this._maxVertexCount = source._maxVertexCount; 33699 this._maxIndexCount = source._maxIndexCount; 33700 33701 this._geometryInitialized = source._geometryInitialized; 33702 this._geometryCount = source._geometryCount; 33703 this._multiDrawCounts = source._multiDrawCounts.slice(); 33704 this._multiDrawStarts = source._multiDrawStarts.slice(); 33705 33706 this._matricesTexture = source._matricesTexture.clone(); 33707 this._matricesTexture.image.data = this._matricesTexture.image.slice(); 33708 33709 return this; 33710 33711 } 33712 33713 dispose() { 33714 33715 // Assuming the geometry is not shared with other meshes 33716 this.geometry.dispose(); 33717 33718 this._matricesTexture.dispose(); 33719 this._matricesTexture = null; 33720 return this; 33721 33722 } 33723 33724 onBeforeRender(renderer, scene, camera, geometry, material/*, _group*/) { 33725 33726 // if visibility has not changed and frustum culling and object sorting is not required 33727 // then skip iterating over all items 33728 if (!this._visibilityChanged && !this.perObjectFrustumCulled && !this.sortObjects) { 33729 33730 return; 33731 33732 } 33733 33734 // the indexed version of the multi draw function requires specifying the start 33735 // offset in bytes. 33736 const index = geometry.getIndex(); 33737 const bytesPerElement = index === null ? 1 : index.array.BYTES_PER_ELEMENT; 33738 33739 const visibility = this._visibility; 33740 const multiDrawStarts = this._multiDrawStarts; 33741 const multiDrawCounts = this._multiDrawCounts; 33742 const drawRanges = this._drawRanges; 33743 const perObjectFrustumCulled = this.perObjectFrustumCulled; 33744 33745 // prepare the frustum in the local frame 33746 if (perObjectFrustumCulled) { 33747 33748 _projScreenMatrix$2 33749 .multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse) 33750 .multiply(this.matrixWorld); 33751 _frustum.setFromProjectionMatrix( 33752 _projScreenMatrix$2, 33753 renderer.isWebGPURenderer ? WebGPUCoordinateSystem : WebGLCoordinateSystem 33754 ); 33755 33756 } 33757 33758 let count = 0; 33759 if (this.sortObjects) { 33760 33761 // get the camera position in the local frame 33762 _invMatrixWorld.copy(this.matrixWorld).invert(); 33763 _vector$5.setFromMatrixPosition(camera.matrixWorld).applyMatrix4(_invMatrixWorld); 33764 33765 for (let i = 0, l = visibility.length; i < l; i++) { 33766 33767 if (visibility[i]) { 33768 33769 // get the bounds in world space 33770 this.getMatrixAt(i, _matrix); 33771 this.getBoundingSphereAt(i, _sphere$2).applyMatrix4(_matrix); 33772 33773 // determine whether the batched geometry is within the frustum 33774 let culled = false; 33775 if (perObjectFrustumCulled) { 33776 33777 culled = !_frustum.intersectsSphere(_sphere$2); 33778 33779 } 33780 33781 if (!culled) { 33782 33783 // get the distance from camera used for sorting 33784 const z = _vector$5.distanceTo(_sphere$2.center); 33785 _renderList.push(drawRanges[i], z); 33786 33787 } 33788 33789 } 33790 33791 } 33792 33793 // Sort the draw ranges and prep for rendering 33794 const list = _renderList.list; 33795 const customSort = this.customSort; 33796 if (customSort === null) { 33797 33798 list.sort(material.transparent ? sortTransparent : sortOpaque); 33799 33800 } else { 33801 33802 customSort.call(this, list, camera); 33803 33804 } 33805 33806 for (let i = 0, l = list.length; i < l; i++) { 33807 33808 const item = list[i]; 33809 multiDrawStarts[count] = item.start * bytesPerElement; 33810 multiDrawCounts[count] = item.count; 33811 count++; 33812 33813 } 33814 33815 _renderList.reset(); 33816 33817 } else { 33818 33819 for (let i = 0, l = visibility.length; i < l; i++) { 33820 33821 if (visibility[i]) { 33822 33823 // determine whether the batched geometry is within the frustum 33824 let culled = false; 33825 if (perObjectFrustumCulled) { 33826 33827 // get the bounds in world space 33828 this.getMatrixAt(i, _matrix); 33829 this.getBoundingSphereAt(i, _sphere$2).applyMatrix4(_matrix); 33830 culled = !_frustum.intersectsSphere(_sphere$2); 33831 33832 } 33833 33834 if (!culled) { 33835 33836 const range = drawRanges[i]; 33837 multiDrawStarts[count] = range.start * bytesPerElement; 33838 multiDrawCounts[count] = range.count; 33839 count++; 33840 33841 } 33842 33843 } 33844 33845 } 33846 33847 } 33848 33849 this._multiDrawCount = count; 33850 this._visibilityChanged = false; 33851 33852 } 33853 33854 onBeforeShadow(renderer, object, camera, shadowCamera, geometry, depthMaterial/* , group */) { 33855 33856 this.onBeforeRender(renderer, null, shadowCamera, geometry, depthMaterial); 33857 33858 } 33859 33860} 33861 33862class LineBasicMaterial extends Material { 33863 33864 constructor(parameters) { 33865 33866 super(); 33867 33868 this.isLineBasicMaterial = true; 33869 33870 this.type = 'LineBasicMaterial'; 33871 33872 this.color = new Color(0xffffff); 33873 33874 this.map = null; 33875 33876 this.linewidth = 1; 33877 this.linecap = 'round'; 33878 this.linejoin = 'round'; 33879 33880 this.fog = true; 33881 33882 this.setValues(parameters); 33883 33884 } 33885 33886 33887 copy(source) { 33888 33889 super.copy(source); 33890 33891 this.color.copy(source.color); 33892 33893 this.map = source.map; 33894 33895 this.linewidth = source.linewidth; 33896 this.linecap = source.linecap; 33897 this.linejoin = source.linejoin; 33898
vendor: 5,092 bytes, lines 33899-34095
33899 this.fog = source.fog; 33900 33901 return this; 33902 33903 } 33904 33905} 33906 33907const _start$1 = /*@__PURE__*/ new Vector3(); 33908const _end$1 = /*@__PURE__*/ new Vector3(); 33909const _inverseMatrix$1 = /*@__PURE__*/ new Matrix4(); 33910const _ray$1 = /*@__PURE__*/ new Ray(); 33911const _sphere$1 = /*@__PURE__*/ new Sphere(); 33912 33913class Line extends Object3D { 33914 33915 constructor(geometry = new BufferGeometry(), material = new LineBasicMaterial()) { 33916 33917 super(); 33918 33919 this.isLine = true; 33920 33921 this.type = 'Line'; 33922 33923 this.geometry = geometry; 33924 this.material = material; 33925 33926 this.updateMorphTargets(); 33927 33928 } 33929 33930 copy(source, recursive) { 33931 33932 super.copy(source, recursive); 33933 33934 this.material = Array.isArray(source.material) ? source.material.slice() : source.material; 33935 this.geometry = source.geometry; 33936 33937 return this; 33938 33939 } 33940 33941 computeLineDistances() { 33942 33943 const geometry = this.geometry; 33944 33945 // we assume non-indexed geometry 33946 33947 if (geometry.index === null) { 33948 33949 const positionAttribute = geometry.attributes.position; 33950 const lineDistances = [0]; 33951 33952 for (let i = 1, l = positionAttribute.count; i < l; i++) { 33953 33954 _start$1.fromBufferAttribute(positionAttribute, i - 1); 33955 _end$1.fromBufferAttribute(positionAttribute, i); 33956 33957 lineDistances[i] = lineDistances[i - 1]; 33958 lineDistances[i] += _start$1.distanceTo(_end$1); 33959 33960 } 33961 33962 geometry.setAttribute('lineDistance', new Float32BufferAttribute(lineDistances, 1)); 33963 33964 } else { 33965 33966 console.warn('THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.'); 33967 33968 } 33969 33970 return this; 33971 33972 } 33973 33974 raycast(raycaster, intersects) { 33975 33976 const geometry = this.geometry; 33977 const matrixWorld = this.matrixWorld; 33978 const threshold = raycaster.params.Line.threshold; 33979 const drawRange = geometry.drawRange; 33980 33981 // Checking boundingSphere distance to ray 33982 33983 if (geometry.boundingSphere === null) geometry.computeBoundingSphere(); 33984 33985 _sphere$1.copy(geometry.boundingSphere); 33986 _sphere$1.applyMatrix4(matrixWorld); 33987 _sphere$1.radius += threshold; 33988 33989 if (raycaster.ray.intersectsSphere(_sphere$1) === false) return; 33990 33991 // 33992 33993 _inverseMatrix$1.copy(matrixWorld).invert(); 33994 _ray$1.copy(raycaster.ray).applyMatrix4(_inverseMatrix$1); 33995 33996 const localThreshold = threshold / ((this.scale.x + this.scale.y + this.scale.z) / 3); 33997 const localThresholdSq = localThreshold * localThreshold; 33998 33999 const vStart = new Vector3(); 34000 const vEnd = new Vector3(); 34001 const interSegment = new Vector3(); 34002 const interRay = new Vector3(); 34003 const step = this.isLineSegments ? 2 : 1; 34004 34005 const index = geometry.index; 34006 const attributes = geometry.attributes; 34007 const positionAttribute = attributes.position; 34008 34009 if (index !== null) { 34010 34011 const start = Math.max(0, drawRange.start); 34012 const end = Math.min(index.count, (drawRange.start + drawRange.count)); 34013 34014 for (let i = start, l = end - 1; i < l; i += step) { 34015 34016 const a = index.getX(i); 34017 const b = index.getX(i + 1); 34018 34019 vStart.fromBufferAttribute(positionAttribute, a); 34020 vEnd.fromBufferAttribute(positionAttribute, b); 34021 34022 const distSq = _ray$1.distanceSqToSegment(vStart, vEnd, interRay, interSegment); 34023 34024 if (distSq > localThresholdSq) continue; 34025 34026 interRay.applyMatrix4(this.matrixWorld); //Move back to world space for distance calculation 34027 34028 const distance = raycaster.ray.origin.distanceTo(interRay); 34029 34030 if (distance < raycaster.near || distance > raycaster.far) continue; 34031 34032 intersects.push({ 34033 34034 distance: distance, 34035 // What do we want? intersection point on the ray or on the segment?? 34036 // point: raycaster.ray.at( distance ), 34037 point: interSegment.clone().applyMatrix4(this.matrixWorld), 34038 index: i, 34039 face: null, 34040 faceIndex: null, 34041 object: this 34042 34043 }); 34044 34045 } 34046 34047 } else { 34048 34049 const start = Math.max(0, drawRange.start); 34050 const end = Math.min(positionAttribute.count, (drawRange.start + drawRange.count)); 34051 34052 for (let i = start, l = end - 1; i < l; i += step) { 34053 34054 vStart.fromBufferAttribute(positionAttribute, i); 34055 vEnd.fromBufferAttribute(positionAttribute, i + 1); 34056 34057 const distSq = _ray$1.distanceSqToSegment(vStart, vEnd, interRay, interSegment); 34058 34059 if (distSq > localThresholdSq) continue; 34060 34061 interRay.applyMatrix4(this.matrixWorld); //Move back to world space for distance calculation 34062 34063 const distance = raycaster.ray.origin.distanceTo(interRay); 34064 34065 if (distance < raycaster.near || distance > raycaster.far) continue; 34066 34067 intersects.push({ 34068 34069 distance: distance, 34070 // What do we want? intersection point on the ray or on the segment?? 34071 // point: raycaster.ray.at( distance ), 34072 point: interSegment.clone().applyMatrix4(this.matrixWorld), 34073 index: i, 34074 face: null, 34075 faceIndex: null, 34076 object: this 34077 34078 }); 34079 34080 } 34081 34082 } 34083 34084 } 34085 34086 updateMorphTargets() { 34087 34088 const geometry = this.geometry; 34089 34090 const morphAttributes = geometry.morphAttributes; 34091 const keys = Object.keys(morphAttributes); 34092 34093 if (keys.length > 0) { 34094 34095 const morphAttribute = morphAttributes[keys[0]];
vendor: 13,861 bytes, lines 34096-34779
34096 34097 if (morphAttribute !== undefined) { 34098 34099 this.morphTargetInfluences = []; 34100 this.morphTargetDictionary = {}; 34101 34102 for (let m = 0, ml = morphAttribute.length; m < ml; m++) { 34103 34104 const name = morphAttribute[m].name || String(m); 34105 34106 this.morphTargetInfluences.push(0); 34107 this.morphTargetDictionary[name] = m; 34108 34109 } 34110 34111 } 34112 34113 } 34114 34115 } 34116 34117} 34118 34119const _start = /*@__PURE__*/ new Vector3(); 34120const _end = /*@__PURE__*/ new Vector3(); 34121 34122class LineSegments extends Line { 34123 34124 constructor(geometry, material) { 34125 34126 super(geometry, material); 34127 34128 this.isLineSegments = true; 34129 34130 this.type = 'LineSegments'; 34131 34132 } 34133 34134 computeLineDistances() { 34135 34136 const geometry = this.geometry; 34137 34138 // we assume non-indexed geometry 34139 34140 if (geometry.index === null) { 34141 34142 const positionAttribute = geometry.attributes.position; 34143 const lineDistances = []; 34144 34145 for (let i = 0, l = positionAttribute.count; i < l; i += 2) { 34146 34147 _start.fromBufferAttribute(positionAttribute, i); 34148 _end.fromBufferAttribute(positionAttribute, i + 1); 34149 34150 lineDistances[i] = (i === 0) ? 0 : lineDistances[i - 1]; 34151 lineDistances[i + 1] = lineDistances[i] + _start.distanceTo(_end); 34152 34153 } 34154 34155 geometry.setAttribute('lineDistance', new Float32BufferAttribute(lineDistances, 1)); 34156 34157 } else { 34158 34159 console.warn('THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.'); 34160 34161 } 34162 34163 return this; 34164 34165 } 34166 34167} 34168 34169class LineLoop extends Line { 34170 34171 constructor(geometry, material) { 34172 34173 super(geometry, material); 34174 34175 this.isLineLoop = true; 34176 34177 this.type = 'LineLoop'; 34178 34179 } 34180 34181} 34182 34183class PointsMaterial extends Material { 34184 34185 constructor(parameters) { 34186 34187 super(); 34188 34189 this.isPointsMaterial = true; 34190 34191 this.type = 'PointsMaterial'; 34192 34193 this.color = new Color(0xffffff); 34194 34195 this.map = null; 34196 34197 this.alphaMap = null; 34198 34199 this.size = 1; 34200 this.sizeAttenuation = true; 34201 34202 this.fog = true; 34203 34204 this.setValues(parameters); 34205 34206 } 34207 34208 copy(source) { 34209 34210 super.copy(source); 34211 34212 this.color.copy(source.color); 34213 34214 this.map = source.map; 34215 34216 this.alphaMap = source.alphaMap; 34217 34218 this.size = source.size; 34219 this.sizeAttenuation = source.sizeAttenuation; 34220 34221 this.fog = source.fog; 34222 34223 return this; 34224 34225 } 34226 34227} 34228 34229const _inverseMatrix = /*@__PURE__*/ new Matrix4(); 34230const _ray = /*@__PURE__*/ new Ray(); 34231const _sphere = /*@__PURE__*/ new Sphere(); 34232const _position$2 = /*@__PURE__*/ new Vector3(); 34233 34234class Points extends Object3D { 34235 34236 constructor(geometry = new BufferGeometry(), material = new PointsMaterial()) { 34237 34238 super(); 34239 34240 this.isPoints = true; 34241 34242 this.type = 'Points'; 34243 34244 this.geometry = geometry; 34245 this.material = material; 34246 34247 this.updateMorphTargets(); 34248 34249 } 34250 34251 copy(source, recursive) { 34252 34253 super.copy(source, recursive); 34254 34255 this.material = Array.isArray(source.material) ? source.material.slice() : source.material; 34256 this.geometry = source.geometry; 34257 34258 return this; 34259 34260 } 34261 34262 raycast(raycaster, intersects) { 34263 34264 const geometry = this.geometry; 34265 const matrixWorld = this.matrixWorld; 34266 const threshold = raycaster.params.Points.threshold; 34267 const drawRange = geometry.drawRange; 34268 34269 // Checking boundingSphere distance to ray 34270 34271 if (geometry.boundingSphere === null) geometry.computeBoundingSphere(); 34272 34273 _sphere.copy(geometry.boundingSphere); 34274 _sphere.applyMatrix4(matrixWorld); 34275 _sphere.radius += threshold; 34276 34277 if (raycaster.ray.intersectsSphere(_sphere) === false) return; 34278 34279 // 34280 34281 _inverseMatrix.copy(matrixWorld).invert(); 34282 _ray.copy(raycaster.ray).applyMatrix4(_inverseMatrix); 34283 34284 const localThreshold = threshold / ((this.scale.x + this.scale.y + this.scale.z) / 3); 34285 const localThresholdSq = localThreshold * localThreshold; 34286 34287 const index = geometry.index; 34288 const attributes = geometry.attributes; 34289 const positionAttribute = attributes.position; 34290 34291 if (index !== null) { 34292 34293 const start = Math.max(0, drawRange.start); 34294 const end = Math.min(index.count, (drawRange.start + drawRange.count)); 34295 34296 for (let i = start, il = end; i < il; i++) { 34297 34298 const a = index.getX(i); 34299 34300 _position$2.fromBufferAttribute(positionAttribute, a); 34301 34302 testPoint(_position$2, a, localThresholdSq, matrixWorld, raycaster, intersects, this); 34303 34304 } 34305 34306 } else { 34307 34308 const start = Math.max(0, drawRange.start); 34309 const end = Math.min(positionAttribute.count, (drawRange.start + drawRange.count)); 34310 34311 for (let i = start, l = end; i < l; i++) { 34312 34313 _position$2.fromBufferAttribute(positionAttribute, i); 34314 34315 testPoint(_position$2, i, localThresholdSq, matrixWorld, raycaster, intersects, this); 34316 34317 } 34318 34319 } 34320 34321 } 34322 34323 updateMorphTargets() { 34324 34325 const geometry = this.geometry; 34326 34327 const morphAttributes = geometry.morphAttributes; 34328 const keys = Object.keys(morphAttributes); 34329 34330 if (keys.length > 0) { 34331 34332 const morphAttribute = morphAttributes[keys[0]]; 34333 34334 if (morphAttribute !== undefined) { 34335 34336 this.morphTargetInfluences = []; 34337 this.morphTargetDictionary = {}; 34338 34339 for (let m = 0, ml = morphAttribute.length; m < ml; m++) { 34340 34341 const name = morphAttribute[m].name || String(m); 34342 34343 this.morphTargetInfluences.push(0); 34344 this.morphTargetDictionary[name] = m; 34345 34346 } 34347 34348 } 34349 34350 } 34351 34352 } 34353 34354} 34355 34356function testPoint(point, index, localThresholdSq, matrixWorld, raycaster, intersects, object) { 34357 34358 const rayPointDistanceSq = _ray.distanceSqToPoint(point); 34359 34360 if (rayPointDistanceSq < localThresholdSq) { 34361 34362 const intersectPoint = new Vector3(); 34363 34364 _ray.closestPointToPoint(point, intersectPoint); 34365 intersectPoint.applyMatrix4(matrixWorld); 34366 34367 const distance = raycaster.ray.origin.distanceTo(intersectPoint); 34368 34369 if (distance < raycaster.near || distance > raycaster.far) return; 34370 34371 intersects.push({ 34372 34373 distance: distance, 34374 distanceToRay: Math.sqrt(rayPointDistanceSq), 34375 point: intersectPoint, 34376 index: index, 34377 face: null, 34378 object: object 34379 34380 }); 34381 34382 } 34383 34384} 34385 34386class VideoTexture extends Texture { 34387 34388 constructor(video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy) { 34389 34390 super(video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy); 34391 34392 this.isVideoTexture = true; 34393 34394 this.minFilter = minFilter !== undefined ? minFilter : LinearFilter; 34395 this.magFilter = magFilter !== undefined ? magFilter : LinearFilter; 34396 34397 this.generateMipmaps = false; 34398 34399 const scope = this; 34400 34401 function updateVideo() { 34402 34403 scope.needsUpdate = true; 34404 video.requestVideoFrameCallback(updateVideo); 34405 34406 } 34407 34408 if ('requestVideoFrameCallback' in video) { 34409 34410 video.requestVideoFrameCallback(updateVideo); 34411 34412 } 34413 34414 } 34415 34416 clone() { 34417 34418 return new this.constructor(this.image).copy(this); 34419 34420 } 34421 34422 update() { 34423 34424 const video = this.image; 34425 const hasVideoFrameCallback = 'requestVideoFrameCallback' in video; 34426 34427 if (hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA) { 34428 34429 this.needsUpdate = true; 34430 34431 } 34432 34433 } 34434 34435} 34436 34437class FramebufferTexture extends Texture { 34438 34439 constructor(width, height) { 34440 34441 super({ width, height }); 34442 34443 this.isFramebufferTexture = true; 34444 34445 this.magFilter = NearestFilter; 34446 this.minFilter = NearestFilter; 34447 34448 this.generateMipmaps = false; 34449 34450 this.needsUpdate = true; 34451 34452 } 34453 34454} 34455 34456class CompressedTexture extends Texture { 34457 34458 constructor(mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, colorSpace) { 34459 34460 super(null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace); 34461 34462 this.isCompressedTexture = true; 34463 34464 this.image = { width: width, height: height }; 34465 this.mipmaps = mipmaps; 34466 34467 // no flipping for cube textures 34468 // (also flipping doesn't work for compressed textures ) 34469 34470 this.flipY = false; 34471 34472 // can't generate mipmaps for compressed textures 34473 // mips must be embedded in DDS files 34474 34475 this.generateMipmaps = false; 34476 34477 } 34478 34479} 34480 34481class CompressedArrayTexture extends CompressedTexture { 34482 34483 constructor(mipmaps, width, height, depth, format, type) { 34484 34485 super(mipmaps, width, height, format, type); 34486 34487 this.isCompressedArrayTexture = true; 34488 this.image.depth = depth; 34489 this.wrapR = ClampToEdgeWrapping; 34490 34491 } 34492 34493} 34494 34495class CompressedCubeTexture extends CompressedTexture { 34496 34497 constructor(images, format, type) { 34498 34499 super(undefined, images[0].width, images[0].height, format, type, CubeReflectionMapping); 34500 34501 this.isCompressedCubeTexture = true; 34502 this.isCubeTexture = true; 34503 34504 this.image = images; 34505 34506 } 34507 34508} 34509 34510class CanvasTexture extends Texture { 34511 34512 constructor(canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy) { 34513 34514 super(canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy); 34515 34516 this.isCanvasTexture = true; 34517 34518 this.needsUpdate = true; 34519 34520 } 34521 34522} 34523 34524/** 34525 * Extensible curve object. 34526 * 34527 * Some common of curve methods: 34528 * .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget ) 34529 * .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget ) 34530 * .getPoints(), .getSpacedPoints() 34531 * .getLength() 34532 * .updateArcLengths() 34533 * 34534 * This following curves inherit from THREE.Curve: 34535 * 34536 * -- 2D curves -- 34537 * THREE.ArcCurve 34538 * THREE.CubicBezierCurve 34539 * THREE.EllipseCurve 34540 * THREE.LineCurve 34541 * THREE.QuadraticBezierCurve 34542 * THREE.SplineCurve 34543 * 34544 * -- 3D curves -- 34545 * THREE.CatmullRomCurve3 34546 * THREE.CubicBezierCurve3 34547 * THREE.LineCurve3 34548 * THREE.QuadraticBezierCurve3 34549 * 34550 * A series of curves can be represented as a THREE.CurvePath. 34551 * 34552 **/ 34553 34554class Curve { 34555 34556 constructor() { 34557 34558 this.type = 'Curve'; 34559 34560 this.arcLengthDivisions = 200; 34561 34562 } 34563 34564 // Virtual base class method to overwrite and implement in subclasses 34565 // - t [0 .. 1] 34566 34567 getPoint( /* t, optionalTarget */) { 34568 34569 console.warn('THREE.Curve: .getPoint() not implemented.'); 34570 return null; 34571 34572 } 34573 34574 // Get point at relative position in curve according to arc length 34575 // - u [0 .. 1] 34576 34577 getPointAt(u, optionalTarget) { 34578 34579 const t = this.getUtoTmapping(u); 34580 return this.getPoint(t, optionalTarget); 34581 34582 } 34583 34584 // Get sequence of points using getPoint( t ) 34585 34586 getPoints(divisions = 5) { 34587 34588 const points = []; 34589 34590 for (let d = 0; d <= divisions; d++) { 34591 34592 points.push(this.getPoint(d / divisions)); 34593 34594 } 34595 34596 return points; 34597 34598 } 34599 34600 // Get sequence of points using getPointAt( u ) 34601 34602 getSpacedPoints(divisions = 5) { 34603 34604 const points = []; 34605 34606 for (let d = 0; d <= divisions; d++) { 34607 34608 points.push(this.getPointAt(d / divisions)); 34609 34610 } 34611 34612 return points; 34613 34614 } 34615 34616 // Get total curve arc length 34617 34618 getLength() { 34619 34620 const lengths = this.getLengths(); 34621 return lengths[lengths.length - 1]; 34622 34623 } 34624 34625 // Get list of cumulative segment lengths 34626 34627 getLengths(divisions = this.arcLengthDivisions) { 34628 34629 if (this.cacheArcLengths && 34630 (this.cacheArcLengths.length === divisions + 1) && 34631 !this.needsUpdate) { 34632 34633 return this.cacheArcLengths; 34634 34635 } 34636 34637 this.needsUpdate = false; 34638 34639 const cache = []; 34640 let current, last = this.getPoint(0); 34641 let sum = 0; 34642 34643 cache.push(0); 34644 34645 for (let p = 1; p <= divisions; p++) { 34646 34647 current = this.getPoint(p / divisions); 34648 sum += current.distanceTo(last); 34649 cache.push(sum); 34650 last = current; 34651 34652 } 34653 34654 this.cacheArcLengths = cache; 34655 34656 return cache; // { sums: cache, sum: sum }; Sum is in the last element. 34657 34658 } 34659 34660 updateArcLengths() { 34661 34662 this.needsUpdate = true; 34663 this.getLengths(); 34664 34665 } 34666 34667 // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant 34668 34669 getUtoTmapping(u, distance) { 34670 34671 const arcLengths = this.getLengths(); 34672 34673 let i = 0; 34674 const il = arcLengths.length; 34675 34676 let targetArcLength; // The targeted u distance value to get 34677 34678 if (distance) { 34679 34680 targetArcLength = distance; 34681 34682 } else { 34683 34684 targetArcLength = u * arcLengths[il - 1]; 34685 34686 } 34687 34688 // binary search for the index with largest value smaller than target u distance 34689 34690 let low = 0, high = il - 1, comparison; 34691 34692 while (low <= high) { 34693 34694 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 34695 34696 comparison = arcLengths[i] - targetArcLength; 34697 34698 if (comparison < 0) { 34699 34700 low = i + 1; 34701 34702 } else if (comparison > 0) { 34703 34704 high = i - 1; 34705 34706 } else { 34707 34708 high = i; 34709 break; 34710 34711 // DONE 34712 34713 } 34714 34715 } 34716 34717 i = high; 34718 34719 if (arcLengths[i] === targetArcLength) { 34720 34721 return i / (il - 1); 34722 34723 } 34724 34725 // we could get finer grain at lengths, or use simple interpolation between two points 34726 34727 const lengthBefore = arcLengths[i]; 34728 const lengthAfter = arcLengths[i + 1]; 34729 34730 const segmentLength = lengthAfter - lengthBefore; 34731 34732 // determine where we are between the 'before' and 'after' points 34733 34734 const segmentFraction = (targetArcLength - lengthBefore) / segmentLength; 34735 34736 // add that fractional amount to t 34737 34738 const t = (i + segmentFraction) / (il - 1); 34739 34740 return t; 34741 34742 } 34743 34744 // Returns a unit vector tangent at t 34745 // In case any sub curve does not implement its tangent derivation, 34746 // 2 points a small delta apart will be used to find its gradient 34747 // which seems to give a reasonable approximation 34748 34749 getTangent(t, optionalTarget) { 34750 34751 const delta = 0.0001; 34752 let t1 = t - delta; 34753 let t2 = t + delta; 34754 34755 // Capping in case of danger 34756 34757 if (t1 < 0) t1 = 0; 34758 if (t2 > 1) t2 = 1; 34759 34760 const pt1 = this.getPoint(t1); 34761 const pt2 = this.getPoint(t2); 34762 34763 const tangent = optionalTarget || ((pt1.isVector2) ? new Vector2() : new Vector3()); 34764 34765 tangent.copy(pt2).sub(pt1).normalize(); 34766 34767 return tangent; 34768 34769 } 34770 34771 getTangentAt(u, optionalTarget) { 34772 34773 const t = this.getUtoTmapping(u); 34774 return this.getTangent(t, optionalTarget); 34775 34776 } 34777 34778 computeFrenetFrames(segments, closed) { 34779
vendor: 4,437 bytes, lines 34780-35007
34780 // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf 34781 34782 const normal = new Vector3(); 34783 34784 const tangents = []; 34785 const normals = []; 34786 const binormals = []; 34787 34788 const vec = new Vector3(); 34789 const mat = new Matrix4(); 34790 34791 // compute the tangent vectors for each segment on the curve 34792 34793 for (let i = 0; i <= segments; i++) { 34794 34795 const u = i / segments; 34796 34797 tangents[i] = this.getTangentAt(u, new Vector3()); 34798 34799 } 34800 34801 // select an initial normal vector perpendicular to the first tangent vector, 34802 // and in the direction of the minimum tangent xyz component 34803 34804 normals[0] = new Vector3(); 34805 binormals[0] = new Vector3(); 34806 let min = Number.MAX_VALUE; 34807 const tx = Math.abs(tangents[0].x); 34808 const ty = Math.abs(tangents[0].y); 34809 const tz = Math.abs(tangents[0].z); 34810 34811 if (tx <= min) { 34812 34813 min = tx; 34814 normal.set(1, 0, 0); 34815 34816 } 34817 34818 if (ty <= min) { 34819 34820 min = ty; 34821 normal.set(0, 1, 0); 34822 34823 } 34824 34825 if (tz <= min) { 34826 34827 normal.set(0, 0, 1); 34828 34829 } 34830 34831 vec.crossVectors(tangents[0], normal).normalize(); 34832 34833 normals[0].crossVectors(tangents[0], vec); 34834 binormals[0].crossVectors(tangents[0], normals[0]); 34835 34836 34837 // compute the slowly-varying normal and binormal vectors for each segment on the curve 34838 34839 for (let i = 1; i <= segments; i++) { 34840 34841 normals[i] = normals[i - 1].clone(); 34842 34843 binormals[i] = binormals[i - 1].clone(); 34844 34845 vec.crossVectors(tangents[i - 1], tangents[i]); 34846 34847 if (vec.length() > Number.EPSILON) { 34848 34849 vec.normalize(); 34850 34851 const theta = Math.acos(clamp(tangents[i - 1].dot(tangents[i]), - 1, 1)); // clamp for floating pt errors 34852 34853 normals[i].applyMatrix4(mat.makeRotationAxis(vec, theta)); 34854 34855 } 34856 34857 binormals[i].crossVectors(tangents[i], normals[i]); 34858 34859 } 34860 34861 // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same 34862 34863 if (closed === true) { 34864 34865 let theta = Math.acos(clamp(normals[0].dot(normals[segments]), - 1, 1)); 34866 theta /= segments; 34867 34868 if (tangents[0].dot(vec.crossVectors(normals[0], normals[segments])) > 0) { 34869 34870 theta = - theta; 34871 34872 } 34873 34874 for (let i = 1; i <= segments; i++) { 34875 34876 // twist a little... 34877 normals[i].applyMatrix4(mat.makeRotationAxis(tangents[i], theta * i)); 34878 binormals[i].crossVectors(tangents[i], normals[i]); 34879 34880 } 34881 34882 } 34883 34884 return { 34885 tangents: tangents, 34886 normals: normals, 34887 binormals: binormals 34888 }; 34889 34890 } 34891 34892 clone() { 34893 34894 return new this.constructor().copy(this); 34895 34896 } 34897 34898 copy(source) { 34899 34900 this.arcLengthDivisions = source.arcLengthDivisions; 34901 34902 return this; 34903 34904 } 34905 34906 toJSON() { 34907 34908 const data = { 34909 metadata: { 34910 version: 4.6, 34911 type: 'Curve', 34912 generator: 'Curve.toJSON' 34913 } 34914 }; 34915 34916 data.arcLengthDivisions = this.arcLengthDivisions; 34917 data.type = this.type; 34918 34919 return data; 34920 34921 } 34922 34923 fromJSON(json) { 34924 34925 this.arcLengthDivisions = json.arcLengthDivisions; 34926 34927 return this; 34928 34929 } 34930 34931} 34932 34933class EllipseCurve extends Curve { 34934 34935 constructor(aX = 0, aY = 0, xRadius = 1, yRadius = 1, aStartAngle = 0, aEndAngle = Math.PI * 2, aClockwise = false, aRotation = 0) { 34936 34937 super(); 34938 34939 this.isEllipseCurve = true; 34940 34941 this.type = 'EllipseCurve'; 34942 34943 this.aX = aX; 34944 this.aY = aY; 34945 34946 this.xRadius = xRadius; 34947 this.yRadius = yRadius; 34948 34949 this.aStartAngle = aStartAngle; 34950 this.aEndAngle = aEndAngle; 34951 34952 this.aClockwise = aClockwise; 34953 34954 this.aRotation = aRotation; 34955 34956 } 34957 34958 getPoint(t, optionalTarget) { 34959 34960 const point = optionalTarget || new Vector2(); 34961 34962 const twoPi = Math.PI * 2; 34963 let deltaAngle = this.aEndAngle - this.aStartAngle; 34964 const samePoints = Math.abs(deltaAngle) < Number.EPSILON; 34965 34966 // ensures that deltaAngle is 0 .. 2 PI 34967 while (deltaAngle < 0) deltaAngle += twoPi; 34968 while (deltaAngle > twoPi) deltaAngle -= twoPi; 34969 34970 if (deltaAngle < Number.EPSILON) { 34971 34972 if (samePoints) { 34973 34974 deltaAngle = 0; 34975 34976 } else { 34977 34978 deltaAngle = twoPi; 34979 34980 } 34981 34982 } 34983 34984 if (this.aClockwise === true && !samePoints) { 34985 34986 if (deltaAngle === twoPi) { 34987 34988 deltaAngle = - twoPi; 34989 34990 } else { 34991 34992 deltaAngle = deltaAngle - twoPi; 34993 34994 } 34995 34996 } 34997 34998 const angle = this.aStartAngle + t * deltaAngle; 34999 let x = this.aX + this.xRadius * Math.cos(angle); 35000 let y = this.aY + this.yRadius * Math.sin(angle); 35001 35002 if (this.aRotation !== 0) { 35003 35004 const cos = Math.cos(this.aRotation); 35005 const sin = Math.sin(this.aRotation); 35006 35007 const tx = x - this.aX;
vendor: 29,584 bytes, lines 35008-36647
35008 const ty = y - this.aY; 35009 35010 // Rotate the point about the center of the ellipse. 35011 x = tx * cos - ty * sin + this.aX; 35012 y = tx * sin + ty * cos + this.aY; 35013 35014 } 35015 35016 return point.set(x, y); 35017 35018 } 35019 35020 copy(source) { 35021 35022 super.copy(source); 35023 35024 this.aX = source.aX; 35025 this.aY = source.aY; 35026 35027 this.xRadius = source.xRadius; 35028 this.yRadius = source.yRadius; 35029 35030 this.aStartAngle = source.aStartAngle; 35031 this.aEndAngle = source.aEndAngle; 35032 35033 this.aClockwise = source.aClockwise; 35034 35035 this.aRotation = source.aRotation; 35036 35037 return this; 35038 35039 } 35040 35041 toJSON() { 35042 35043 const data = super.toJSON(); 35044 35045 data.aX = this.aX; 35046 data.aY = this.aY; 35047 35048 data.xRadius = this.xRadius; 35049 data.yRadius = this.yRadius; 35050 35051 data.aStartAngle = this.aStartAngle; 35052 data.aEndAngle = this.aEndAngle; 35053 35054 data.aClockwise = this.aClockwise; 35055 35056 data.aRotation = this.aRotation; 35057 35058 return data; 35059 35060 } 35061 35062 fromJSON(json) { 35063 35064 super.fromJSON(json); 35065 35066 this.aX = json.aX; 35067 this.aY = json.aY; 35068 35069 this.xRadius = json.xRadius; 35070 this.yRadius = json.yRadius; 35071 35072 this.aStartAngle = json.aStartAngle; 35073 this.aEndAngle = json.aEndAngle; 35074 35075 this.aClockwise = json.aClockwise; 35076 35077 this.aRotation = json.aRotation; 35078 35079 return this; 35080 35081 } 35082 35083} 35084 35085class ArcCurve extends EllipseCurve { 35086 35087 constructor(aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise) { 35088 35089 super(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise); 35090 35091 this.isArcCurve = true; 35092 35093 this.type = 'ArcCurve'; 35094 35095 } 35096 35097} 35098 35099/** 35100 * Centripetal CatmullRom Curve - which is useful for avoiding 35101 * cusps and self-intersections in non-uniform catmull rom curves. 35102 * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf 35103 * 35104 * curve.type accepts centripetal(default), chordal and catmullrom 35105 * curve.tension is used for catmullrom which defaults to 0.5 35106 */ 35107 35108 35109/* 35110Based on an optimized c++ solution in 35111 - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/ 35112 - http://ideone.com/NoEbVM 35113 35114This CubicPoly class could be used for reusing some variables and calculations, 35115but for three.js curve use, it could be possible inlined and flatten into a single function call 35116which can be placed in CurveUtils. 35117*/ 35118 35119function CubicPoly() { 35120 35121 let c0 = 0, c1 = 0, c2 = 0, c3 = 0; 35122 35123 /* 35124 * Compute coefficients for a cubic polynomial 35125 * p(s) = c0 + c1*s + c2*s^2 + c3*s^3 35126 * such that 35127 * p(0) = x0, p(1) = x1 35128 * and 35129 * p'(0) = t0, p'(1) = t1. 35130 */ 35131 function init(x0, x1, t0, t1) { 35132 35133 c0 = x0; 35134 c1 = t0; 35135 c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1; 35136 c3 = 2 * x0 - 2 * x1 + t0 + t1; 35137 35138 } 35139 35140 return { 35141 35142 initCatmullRom: function (x0, x1, x2, x3, tension) { 35143 35144 init(x1, x2, tension * (x2 - x0), tension * (x3 - x1)); 35145 35146 }, 35147 35148 initNonuniformCatmullRom: function (x0, x1, x2, x3, dt0, dt1, dt2) { 35149 35150 // compute tangents when parameterized in [t1,t2] 35151 let t1 = (x1 - x0) / dt0 - (x2 - x0) / (dt0 + dt1) + (x2 - x1) / dt1; 35152 let t2 = (x2 - x1) / dt1 - (x3 - x1) / (dt1 + dt2) + (x3 - x2) / dt2; 35153 35154 // rescale tangents for parametrization in [0,1] 35155 t1 *= dt1; 35156 t2 *= dt1; 35157 35158 init(x1, x2, t1, t2); 35159 35160 }, 35161 35162 calc: function (t) { 35163 35164 const t2 = t * t; 35165 const t3 = t2 * t; 35166 return c0 + c1 * t + c2 * t2 + c3 * t3; 35167 35168 } 35169 35170 }; 35171 35172} 35173 35174// 35175 35176const tmp = /*@__PURE__*/ new Vector3(); 35177const px = /*@__PURE__*/ new CubicPoly(); 35178const py = /*@__PURE__*/ new CubicPoly(); 35179const pz = /*@__PURE__*/ new CubicPoly(); 35180 35181class CatmullRomCurve3 extends Curve { 35182 35183 constructor(points = [], closed = false, curveType = 'centripetal', tension = 0.5) { 35184 35185 super(); 35186 35187 this.isCatmullRomCurve3 = true; 35188 35189 this.type = 'CatmullRomCurve3'; 35190 35191 this.points = points; 35192 this.closed = closed; 35193 this.curveType = curveType; 35194 this.tension = tension; 35195 35196 } 35197 35198 getPoint(t, optionalTarget = new Vector3()) { 35199 35200 const point = optionalTarget; 35201 35202 const points = this.points; 35203 const l = points.length; 35204 35205 const p = (l - (this.closed ? 0 : 1)) * t; 35206 let intPoint = Math.floor(p); 35207 let weight = p - intPoint; 35208 35209 if (this.closed) { 35210 35211 intPoint += intPoint > 0 ? 0 : (Math.floor(Math.abs(intPoint) / l) + 1) * l; 35212 35213 } else if (weight === 0 && intPoint === l - 1) { 35214 35215 intPoint = l - 2; 35216 weight = 1; 35217 35218 } 35219 35220 let p0, p3; // 4 points (p1 & p2 defined below) 35221 35222 if (this.closed || intPoint > 0) { 35223 35224 p0 = points[(intPoint - 1) % l]; 35225 35226 } else { 35227 35228 // extrapolate first point 35229 tmp.subVectors(points[0], points[1]).add(points[0]); 35230 p0 = tmp; 35231 35232 } 35233 35234 const p1 = points[intPoint % l]; 35235 const p2 = points[(intPoint + 1) % l]; 35236 35237 if (this.closed || intPoint + 2 < l) { 35238 35239 p3 = points[(intPoint + 2) % l]; 35240 35241 } else { 35242 35243 // extrapolate last point 35244 tmp.subVectors(points[l - 1], points[l - 2]).add(points[l - 1]); 35245 p3 = tmp; 35246 35247 } 35248 35249 if (this.curveType === 'centripetal' || this.curveType === 'chordal') { 35250 35251 // init Centripetal / Chordal Catmull-Rom 35252 const pow = this.curveType === 'chordal' ? 0.5 : 0.25; 35253 let dt0 = Math.pow(p0.distanceToSquared(p1), pow); 35254 let dt1 = Math.pow(p1.distanceToSquared(p2), pow); 35255 let dt2 = Math.pow(p2.distanceToSquared(p3), pow); 35256 35257 // safety check for repeated points 35258 if (dt1 < 1e-4) dt1 = 1.0; 35259 if (dt0 < 1e-4) dt0 = dt1; 35260 if (dt2 < 1e-4) dt2 = dt1; 35261 35262 px.initNonuniformCatmullRom(p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2); 35263 py.initNonuniformCatmullRom(p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2); 35264 pz.initNonuniformCatmullRom(p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2); 35265 35266 } else if (this.curveType === 'catmullrom') { 35267 35268 px.initCatmullRom(p0.x, p1.x, p2.x, p3.x, this.tension); 35269 py.initCatmullRom(p0.y, p1.y, p2.y, p3.y, this.tension); 35270 pz.initCatmullRom(p0.z, p1.z, p2.z, p3.z, this.tension); 35271 35272 } 35273 35274 point.set( 35275 px.calc(weight), 35276 py.calc(weight), 35277 pz.calc(weight) 35278 ); 35279 35280 return point; 35281 35282 } 35283 35284 copy(source) { 35285 35286 super.copy(source); 35287 35288 this.points = []; 35289 35290 for (let i = 0, l = source.points.length; i < l; i++) { 35291 35292 const point = source.points[i]; 35293 35294 this.points.push(point.clone()); 35295 35296 } 35297 35298 this.closed = source.closed; 35299 this.curveType = source.curveType; 35300 this.tension = source.tension; 35301 35302 return this; 35303 35304 } 35305 35306 toJSON() { 35307 35308 const data = super.toJSON(); 35309 35310 data.points = []; 35311 35312 for (let i = 0, l = this.points.length; i < l; i++) { 35313 35314 const point = this.points[i]; 35315 data.points.push(point.toArray()); 35316 35317 } 35318 35319 data.closed = this.closed; 35320 data.curveType = this.curveType; 35321 data.tension = this.tension; 35322 35323 return data; 35324 35325 } 35326 35327 fromJSON(json) { 35328 35329 super.fromJSON(json); 35330 35331 this.points = []; 35332 35333 for (let i = 0, l = json.points.length; i < l; i++) { 35334 35335 const point = json.points[i]; 35336 this.points.push(new Vector3().fromArray(point)); 35337 35338 } 35339 35340 this.closed = json.closed; 35341 this.curveType = json.curveType; 35342 this.tension = json.tension; 35343 35344 return this; 35345 35346 } 35347 35348} 35349 35350/** 35351 * Bezier Curves formulas obtained from 35352 * https://en.wikipedia.org/wiki/B%C3%A9zier_curve 35353 */ 35354 35355function CatmullRom(t, p0, p1, p2, p3) { 35356 35357 const v0 = (p2 - p0) * 0.5; 35358 const v1 = (p3 - p1) * 0.5; 35359 const t2 = t * t; 35360 const t3 = t * t2; 35361 return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (- 3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1; 35362 35363} 35364 35365// 35366 35367function QuadraticBezierP0(t, p) { 35368 35369 const k = 1 - t; 35370 return k * k * p; 35371 35372} 35373 35374function QuadraticBezierP1(t, p) { 35375 35376 return 2 * (1 - t) * t * p; 35377 35378} 35379 35380function QuadraticBezierP2(t, p) { 35381 35382 return t * t * p; 35383 35384} 35385 35386function QuadraticBezier(t, p0, p1, p2) { 35387 35388 return QuadraticBezierP0(t, p0) + QuadraticBezierP1(t, p1) + 35389 QuadraticBezierP2(t, p2); 35390 35391} 35392 35393// 35394 35395function CubicBezierP0(t, p) { 35396 35397 const k = 1 - t; 35398 return k * k * k * p; 35399 35400} 35401 35402function CubicBezierP1(t, p) { 35403 35404 const k = 1 - t; 35405 return 3 * k * k * t * p; 35406 35407} 35408 35409function CubicBezierP2(t, p) { 35410 35411 return 3 * (1 - t) * t * t * p; 35412 35413} 35414 35415function CubicBezierP3(t, p) { 35416 35417 return t * t * t * p; 35418 35419} 35420 35421function CubicBezier(t, p0, p1, p2, p3) { 35422 35423 return CubicBezierP0(t, p0) + CubicBezierP1(t, p1) + CubicBezierP2(t, p2) + 35424 CubicBezierP3(t, p3); 35425 35426} 35427 35428class CubicBezierCurve extends Curve { 35429 35430 constructor(v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2()) { 35431 35432 super(); 35433 35434 this.isCubicBezierCurve = true; 35435 35436 this.type = 'CubicBezierCurve'; 35437 35438 this.v0 = v0; 35439 this.v1 = v1; 35440 this.v2 = v2; 35441 this.v3 = v3; 35442 35443 } 35444 35445 getPoint(t, optionalTarget = new Vector2()) { 35446 35447 const point = optionalTarget; 35448 35449 const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; 35450 35451 point.set( 35452 CubicBezier(t, v0.x, v1.x, v2.x, v3.x), 35453 CubicBezier(t, v0.y, v1.y, v2.y, v3.y) 35454 ); 35455 35456 return point; 35457 35458 } 35459 35460 copy(source) { 35461 35462 super.copy(source); 35463 35464 this.v0.copy(source.v0); 35465 this.v1.copy(source.v1); 35466 this.v2.copy(source.v2); 35467 this.v3.copy(source.v3); 35468 35469 return this; 35470 35471 } 35472 35473 toJSON() { 35474 35475 const data = super.toJSON(); 35476 35477 data.v0 = this.v0.toArray(); 35478 data.v1 = this.v1.toArray(); 35479 data.v2 = this.v2.toArray(); 35480 data.v3 = this.v3.toArray(); 35481 35482 return data; 35483 35484 } 35485 35486 fromJSON(json) { 35487 35488 super.fromJSON(json); 35489 35490 this.v0.fromArray(json.v0); 35491 this.v1.fromArray(json.v1); 35492 this.v2.fromArray(json.v2); 35493 this.v3.fromArray(json.v3); 35494 35495 return this; 35496 35497 } 35498 35499} 35500 35501class CubicBezierCurve3 extends Curve { 35502 35503 constructor(v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3()) { 35504 35505 super(); 35506 35507 this.isCubicBezierCurve3 = true; 35508 35509 this.type = 'CubicBezierCurve3'; 35510 35511 this.v0 = v0; 35512 this.v1 = v1; 35513 this.v2 = v2; 35514 this.v3 = v3; 35515 35516 } 35517 35518 getPoint(t, optionalTarget = new Vector3()) { 35519 35520 const point = optionalTarget; 35521 35522 const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; 35523 35524 point.set( 35525 CubicBezier(t, v0.x, v1.x, v2.x, v3.x), 35526 CubicBezier(t, v0.y, v1.y, v2.y, v3.y), 35527 CubicBezier(t, v0.z, v1.z, v2.z, v3.z) 35528 ); 35529 35530 return point; 35531 35532 } 35533 35534 copy(source) { 35535 35536 super.copy(source); 35537 35538 this.v0.copy(source.v0); 35539 this.v1.copy(source.v1); 35540 this.v2.copy(source.v2); 35541 this.v3.copy(source.v3); 35542 35543 return this; 35544 35545 } 35546 35547 toJSON() { 35548 35549 const data = super.toJSON(); 35550 35551 data.v0 = this.v0.toArray(); 35552 data.v1 = this.v1.toArray(); 35553 data.v2 = this.v2.toArray(); 35554 data.v3 = this.v3.toArray(); 35555 35556 return data; 35557 35558 } 35559 35560 fromJSON(json) { 35561 35562 super.fromJSON(json); 35563 35564 this.v0.fromArray(json.v0); 35565 this.v1.fromArray(json.v1); 35566 this.v2.fromArray(json.v2); 35567 this.v3.fromArray(json.v3); 35568 35569 return this; 35570 35571 } 35572 35573} 35574 35575class LineCurve extends Curve { 35576 35577 constructor(v1 = new Vector2(), v2 = new Vector2()) { 35578 35579 super(); 35580 35581 this.isLineCurve = true; 35582 35583 this.type = 'LineCurve'; 35584 35585 this.v1 = v1; 35586 this.v2 = v2; 35587 35588 } 35589 35590 getPoint(t, optionalTarget = new Vector2()) { 35591 35592 const point = optionalTarget; 35593 35594 if (t === 1) { 35595 35596 point.copy(this.v2); 35597 35598 } else { 35599 35600 point.copy(this.v2).sub(this.v1); 35601 point.multiplyScalar(t).add(this.v1); 35602 35603 } 35604 35605 return point; 35606 35607 } 35608 35609 // Line curve is linear, so we can overwrite default getPointAt 35610 getPointAt(u, optionalTarget) { 35611 35612 return this.getPoint(u, optionalTarget); 35613 35614 } 35615 35616 getTangent(t, optionalTarget = new Vector2()) { 35617 35618 return optionalTarget.subVectors(this.v2, this.v1).normalize(); 35619 35620 } 35621 35622 getTangentAt(u, optionalTarget) { 35623 35624 return this.getTangent(u, optionalTarget); 35625 35626 } 35627 35628 copy(source) { 35629 35630 super.copy(source); 35631 35632 this.v1.copy(source.v1); 35633 this.v2.copy(source.v2); 35634 35635 return this; 35636 35637 } 35638 35639 toJSON() { 35640 35641 const data = super.toJSON(); 35642 35643 data.v1 = this.v1.toArray(); 35644 data.v2 = this.v2.toArray(); 35645 35646 return data; 35647 35648 } 35649 35650 fromJSON(json) { 35651 35652 super.fromJSON(json); 35653 35654 this.v1.fromArray(json.v1); 35655 this.v2.fromArray(json.v2); 35656 35657 return this; 35658 35659 } 35660 35661} 35662 35663class LineCurve3 extends Curve { 35664 35665 constructor(v1 = new Vector3(), v2 = new Vector3()) { 35666 35667 super(); 35668 35669 this.isLineCurve3 = true; 35670 35671 this.type = 'LineCurve3'; 35672 35673 this.v1 = v1; 35674 this.v2 = v2; 35675 35676 } 35677 35678 getPoint(t, optionalTarget = new Vector3()) { 35679 35680 const point = optionalTarget; 35681 35682 if (t === 1) { 35683 35684 point.copy(this.v2); 35685 35686 } else { 35687 35688 point.copy(this.v2).sub(this.v1); 35689 point.multiplyScalar(t).add(this.v1); 35690 35691 } 35692 35693 return point; 35694 35695 } 35696 35697 // Line curve is linear, so we can overwrite default getPointAt 35698 getPointAt(u, optionalTarget) { 35699 35700 return this.getPoint(u, optionalTarget); 35701 35702 } 35703 35704 getTangent(t, optionalTarget = new Vector3()) { 35705 35706 return optionalTarget.subVectors(this.v2, this.v1).normalize(); 35707 35708 } 35709 35710 getTangentAt(u, optionalTarget) { 35711 35712 return this.getTangent(u, optionalTarget); 35713 35714 } 35715 35716 copy(source) { 35717 35718 super.copy(source); 35719 35720 this.v1.copy(source.v1); 35721 this.v2.copy(source.v2); 35722 35723 return this; 35724 35725 } 35726 35727 toJSON() { 35728 35729 const data = super.toJSON(); 35730 35731 data.v1 = this.v1.toArray(); 35732 data.v2 = this.v2.toArray(); 35733 35734 return data; 35735 35736 } 35737 35738 fromJSON(json) { 35739 35740 super.fromJSON(json); 35741 35742 this.v1.fromArray(json.v1); 35743 this.v2.fromArray(json.v2); 35744 35745 return this; 35746 35747 } 35748 35749} 35750 35751class QuadraticBezierCurve extends Curve { 35752 35753 constructor(v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2()) { 35754 35755 super(); 35756 35757 this.isQuadraticBezierCurve = true; 35758 35759 this.type = 'QuadraticBezierCurve'; 35760 35761 this.v0 = v0; 35762 this.v1 = v1; 35763 this.v2 = v2; 35764 35765 } 35766 35767 getPoint(t, optionalTarget = new Vector2()) { 35768 35769 const point = optionalTarget; 35770 35771 const v0 = this.v0, v1 = this.v1, v2 = this.v2; 35772 35773 point.set( 35774 QuadraticBezier(t, v0.x, v1.x, v2.x), 35775 QuadraticBezier(t, v0.y, v1.y, v2.y) 35776 ); 35777 35778 return point; 35779 35780 } 35781 35782 copy(source) { 35783 35784 super.copy(source); 35785 35786 this.v0.copy(source.v0); 35787 this.v1.copy(source.v1); 35788 this.v2.copy(source.v2); 35789 35790 return this; 35791 35792 } 35793 35794 toJSON() { 35795 35796 const data = super.toJSON(); 35797 35798 data.v0 = this.v0.toArray(); 35799 data.v1 = this.v1.toArray(); 35800 data.v2 = this.v2.toArray(); 35801 35802 return data; 35803 35804 } 35805 35806 fromJSON(json) { 35807 35808 super.fromJSON(json); 35809 35810 this.v0.fromArray(json.v0); 35811 this.v1.fromArray(json.v1); 35812 this.v2.fromArray(json.v2); 35813 35814 return this; 35815 35816 } 35817 35818} 35819 35820class QuadraticBezierCurve3 extends Curve { 35821 35822 constructor(v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3()) { 35823 35824 super(); 35825 35826 this.isQuadraticBezierCurve3 = true; 35827 35828 this.type = 'QuadraticBezierCurve3'; 35829 35830 this.v0 = v0; 35831 this.v1 = v1; 35832 this.v2 = v2; 35833 35834 } 35835 35836 getPoint(t, optionalTarget = new Vector3()) { 35837 35838 const point = optionalTarget; 35839 35840 const v0 = this.v0, v1 = this.v1, v2 = this.v2; 35841 35842 point.set( 35843 QuadraticBezier(t, v0.x, v1.x, v2.x), 35844 QuadraticBezier(t, v0.y, v1.y, v2.y), 35845 QuadraticBezier(t, v0.z, v1.z, v2.z) 35846 ); 35847 35848 return point; 35849 35850 } 35851 35852 copy(source) { 35853 35854 super.copy(source); 35855 35856 this.v0.copy(source.v0); 35857 this.v1.copy(source.v1); 35858 this.v2.copy(source.v2); 35859 35860 return this; 35861 35862 } 35863 35864 toJSON() { 35865 35866 const data = super.toJSON(); 35867 35868 data.v0 = this.v0.toArray(); 35869 data.v1 = this.v1.toArray(); 35870 data.v2 = this.v2.toArray(); 35871 35872 return data; 35873 35874 } 35875 35876 fromJSON(json) { 35877 35878 super.fromJSON(json); 35879 35880 this.v0.fromArray(json.v0); 35881 this.v1.fromArray(json.v1); 35882 this.v2.fromArray(json.v2); 35883 35884 return this; 35885 35886 } 35887 35888} 35889 35890class SplineCurve extends Curve { 35891 35892 constructor(points = []) { 35893 35894 super(); 35895 35896 this.isSplineCurve = true; 35897 35898 this.type = 'SplineCurve'; 35899 35900 this.points = points; 35901 35902 } 35903 35904 getPoint(t, optionalTarget = new Vector2()) { 35905 35906 const point = optionalTarget; 35907 35908 const points = this.points; 35909 const p = (points.length - 1) * t; 35910 35911 const intPoint = Math.floor(p); 35912 const weight = p - intPoint; 35913 35914 const p0 = points[intPoint === 0 ? intPoint : intPoint - 1]; 35915 const p1 = points[intPoint]; 35916 const p2 = points[intPoint > points.length - 2 ? points.length - 1 : intPoint + 1]; 35917 const p3 = points[intPoint > points.length - 3 ? points.length - 1 : intPoint + 2]; 35918 35919 point.set( 35920 CatmullRom(weight, p0.x, p1.x, p2.x, p3.x), 35921 CatmullRom(weight, p0.y, p1.y, p2.y, p3.y) 35922 ); 35923 35924 return point; 35925 35926 } 35927 35928 copy(source) { 35929 35930 super.copy(source); 35931 35932 this.points = []; 35933 35934 for (let i = 0, l = source.points.length; i < l; i++) { 35935 35936 const point = source.points[i]; 35937 35938 this.points.push(point.clone()); 35939 35940 } 35941 35942 return this; 35943 35944 } 35945 35946 toJSON() { 35947 35948 const data = super.toJSON(); 35949 35950 data.points = []; 35951 35952 for (let i = 0, l = this.points.length; i < l; i++) { 35953 35954 const point = this.points[i]; 35955 data.points.push(point.toArray()); 35956 35957 } 35958 35959 return data; 35960 35961 } 35962 35963 fromJSON(json) { 35964 35965 super.fromJSON(json); 35966 35967 this.points = []; 35968 35969 for (let i = 0, l = json.points.length; i < l; i++) { 35970 35971 const point = json.points[i]; 35972 this.points.push(new Vector2().fromArray(point)); 35973 35974 } 35975 35976 return this; 35977 35978 } 35979 35980} 35981 35982var Curves = /*#__PURE__*/Object.freeze({ 35983 __proto__: null, 35984 ArcCurve: ArcCurve, 35985 CatmullRomCurve3: CatmullRomCurve3, 35986 CubicBezierCurve: CubicBezierCurve, 35987 CubicBezierCurve3: CubicBezierCurve3, 35988 EllipseCurve: EllipseCurve, 35989 LineCurve: LineCurve, 35990 LineCurve3: LineCurve3, 35991 QuadraticBezierCurve: QuadraticBezierCurve, 35992 QuadraticBezierCurve3: QuadraticBezierCurve3, 35993 SplineCurve: SplineCurve 35994}); 35995 35996/************************************************************** 35997 * Curved Path - a curve path is simply a array of connected 35998 * curves, but retains the api of a curve 35999 **************************************************************/ 36000 36001class CurvePath extends Curve { 36002 36003 constructor() { 36004 36005 super(); 36006 36007 this.type = 'CurvePath'; 36008 36009 this.curves = []; 36010 this.autoClose = false; // Automatically closes the path 36011 36012 } 36013 36014 add(curve) { 36015 36016 this.curves.push(curve); 36017 36018 } 36019 36020 closePath() { 36021 36022 // Add a line curve if start and end of lines are not connected 36023 const startPoint = this.curves[0].getPoint(0); 36024 const endPoint = this.curves[this.curves.length - 1].getPoint(1); 36025 36026 if (!startPoint.equals(endPoint)) { 36027 36028 const lineType = (startPoint.isVector2 === true) ? 'LineCurve' : 'LineCurve3'; 36029 this.curves.push(new Curves[lineType](endPoint, startPoint)); 36030 36031 } 36032 36033 return this; 36034 36035 } 36036 36037 // To get accurate point with reference to 36038 // entire path distance at time t, 36039 // following has to be done: 36040 36041 // 1. Length of each sub path have to be known 36042 // 2. Locate and identify type of curve 36043 // 3. Get t for the curve 36044 // 4. Return curve.getPointAt(t') 36045 36046 getPoint(t, optionalTarget) { 36047 36048 const d = t * this.getLength(); 36049 const curveLengths = this.getCurveLengths(); 36050 let i = 0; 36051 36052 // To think about boundaries points. 36053 36054 while (i < curveLengths.length) { 36055 36056 if (curveLengths[i] >= d) { 36057 36058 const diff = curveLengths[i] - d; 36059 const curve = this.curves[i]; 36060 36061 const segmentLength = curve.getLength(); 36062 const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; 36063 36064 return curve.getPointAt(u, optionalTarget); 36065 36066 } 36067 36068 i++; 36069 36070 } 36071 36072 return null; 36073 36074 // loop where sum != 0, sum > d , sum+1 <d 36075 36076 } 36077 36078 // We cannot use the default THREE.Curve getPoint() with getLength() because in 36079 // THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath 36080 // getPoint() depends on getLength 36081 36082 getLength() { 36083 36084 const lens = this.getCurveLengths(); 36085 return lens[lens.length - 1]; 36086 36087 } 36088 36089 // cacheLengths must be recalculated. 36090 updateArcLengths() { 36091 36092 this.needsUpdate = true; 36093 this.cacheLengths = null; 36094 this.getCurveLengths(); 36095 36096 } 36097 36098 // Compute lengths and cache them 36099 // We cannot overwrite getLengths() because UtoT mapping uses it. 36100 36101 getCurveLengths() { 36102 36103 // We use cache values if curves and cache array are same length 36104 36105 if (this.cacheLengths && this.cacheLengths.length === this.curves.length) { 36106 36107 return this.cacheLengths; 36108 36109 } 36110 36111 // Get length of sub-curve 36112 // Push sums into cached array 36113 36114 const lengths = []; 36115 let sums = 0; 36116 36117 for (let i = 0, l = this.curves.length; i < l; i++) { 36118 36119 sums += this.curves[i].getLength(); 36120 lengths.push(sums); 36121 36122 } 36123 36124 this.cacheLengths = lengths; 36125 36126 return lengths; 36127 36128 } 36129 36130 getSpacedPoints(divisions = 40) { 36131 36132 const points = []; 36133 36134 for (let i = 0; i <= divisions; i++) { 36135 36136 points.push(this.getPoint(i / divisions)); 36137 36138 } 36139 36140 if (this.autoClose) { 36141 36142 points.push(points[0]); 36143 36144 } 36145 36146 return points; 36147 36148 } 36149 36150 getPoints(divisions = 12) { 36151 36152 const points = []; 36153 let last; 36154 36155 for (let i = 0, curves = this.curves; i < curves.length; i++) { 36156 36157 const curve = curves[i]; 36158 const resolution = curve.isEllipseCurve ? divisions * 2 36159 : (curve.isLineCurve || curve.isLineCurve3) ? 1 36160 : curve.isSplineCurve ? divisions * curve.points.length 36161 : divisions; 36162 36163 const pts = curve.getPoints(resolution); 36164 36165 for (let j = 0; j < pts.length; j++) { 36166 36167 const point = pts[j]; 36168 36169 if (last && last.equals(point)) continue; // ensures no consecutive points are duplicates 36170 36171 points.push(point); 36172 last = point; 36173 36174 } 36175 36176 } 36177 36178 if (this.autoClose && points.length > 1 && !points[points.length - 1].equals(points[0])) { 36179 36180 points.push(points[0]); 36181 36182 } 36183 36184 return points; 36185 36186 } 36187 36188 copy(source) { 36189 36190 super.copy(source); 36191 36192 this.curves = []; 36193 36194 for (let i = 0, l = source.curves.length; i < l; i++) { 36195 36196 const curve = source.curves[i]; 36197 36198 this.curves.push(curve.clone()); 36199 36200 } 36201 36202 this.autoClose = source.autoClose; 36203 36204 return this; 36205 36206 } 36207 36208 toJSON() { 36209 36210 const data = super.toJSON(); 36211 36212 data.autoClose = this.autoClose; 36213 data.curves = []; 36214 36215 for (let i = 0, l = this.curves.length; i < l; i++) { 36216 36217 const curve = this.curves[i]; 36218 data.curves.push(curve.toJSON()); 36219 36220 } 36221 36222 return data; 36223 36224 } 36225 36226 fromJSON(json) { 36227 36228 super.fromJSON(json); 36229 36230 this.autoClose = json.autoClose; 36231 this.curves = []; 36232 36233 for (let i = 0, l = json.curves.length; i < l; i++) { 36234 36235 const curve = json.curves[i]; 36236 this.curves.push(new Curves[curve.type]().fromJSON(curve)); 36237 36238 } 36239 36240 return this; 36241 36242 } 36243 36244} 36245 36246class Path extends CurvePath { 36247 36248 constructor(points) { 36249 36250 super(); 36251 36252 this.type = 'Path'; 36253 36254 this.currentPoint = new Vector2(); 36255 36256 if (points) { 36257 36258 this.setFromPoints(points); 36259 36260 } 36261 36262 } 36263 36264 setFromPoints(points) { 36265 36266 this.moveTo(points[0].x, points[0].y); 36267 36268 for (let i = 1, l = points.length; i < l; i++) { 36269 36270 this.lineTo(points[i].x, points[i].y); 36271 36272 } 36273 36274 return this; 36275 36276 } 36277 36278 moveTo(x, y) { 36279 36280 this.currentPoint.set(x, y); // TODO consider referencing vectors instead of copying? 36281 36282 return this; 36283 36284 } 36285 36286 lineTo(x, y) { 36287 36288 const curve = new LineCurve(this.currentPoint.clone(), new Vector2(x, y)); 36289 this.curves.push(curve); 36290 36291 this.currentPoint.set(x, y); 36292 36293 return this; 36294 36295 } 36296 36297 quadraticCurveTo(aCPx, aCPy, aX, aY) { 36298 36299 const curve = new QuadraticBezierCurve( 36300 this.currentPoint.clone(), 36301 new Vector2(aCPx, aCPy), 36302 new Vector2(aX, aY) 36303 ); 36304 36305 this.curves.push(curve); 36306 36307 this.currentPoint.set(aX, aY); 36308 36309 return this; 36310 36311 } 36312 36313 bezierCurveTo(aCP1x, aCP1y, aCP2x, aCP2y, aX, aY) { 36314 36315 const curve = new CubicBezierCurve( 36316 this.currentPoint.clone(), 36317 new Vector2(aCP1x, aCP1y), 36318 new Vector2(aCP2x, aCP2y), 36319 new Vector2(aX, aY) 36320 ); 36321 36322 this.curves.push(curve); 36323 36324 this.currentPoint.set(aX, aY); 36325 36326 return this; 36327 36328 } 36329 36330 splineThru(pts /*Array of Vector*/) { 36331 36332 const npts = [this.currentPoint.clone()].concat(pts); 36333 36334 const curve = new SplineCurve(npts); 36335 this.curves.push(curve); 36336 36337 this.currentPoint.copy(pts[pts.length - 1]); 36338 36339 return this; 36340 36341 } 36342 36343 arc(aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise) { 36344 36345 const x0 = this.currentPoint.x; 36346 const y0 = this.currentPoint.y; 36347 36348 this.absarc(aX + x0, aY + y0, aRadius, 36349 aStartAngle, aEndAngle, aClockwise); 36350 36351 return this; 36352 36353 } 36354 36355 absarc(aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise) { 36356 36357 this.absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise); 36358 36359 return this; 36360 36361 } 36362 36363 ellipse(aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation) { 36364 36365 const x0 = this.currentPoint.x; 36366 const y0 = this.currentPoint.y; 36367 36368 this.absellipse(aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation); 36369 36370 return this; 36371 36372 } 36373 36374 absellipse(aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation) { 36375 36376 const curve = new EllipseCurve(aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation); 36377 36378 if (this.curves.length > 0) { 36379 36380 // if a previous curve is present, attempt to join 36381 const firstPoint = curve.getPoint(0); 36382 36383 if (!firstPoint.equals(this.currentPoint)) { 36384 36385 this.lineTo(firstPoint.x, firstPoint.y); 36386 36387 } 36388 36389 } 36390 36391 this.curves.push(curve); 36392 36393 const lastPoint = curve.getPoint(1); 36394 this.currentPoint.copy(lastPoint); 36395 36396 return this; 36397 36398 } 36399 36400 copy(source) { 36401 36402 super.copy(source); 36403 36404 this.currentPoint.copy(source.currentPoint); 36405 36406 return this; 36407 36408 } 36409 36410 toJSON() { 36411 36412 const data = super.toJSON(); 36413 36414 data.currentPoint = this.currentPoint.toArray(); 36415 36416 return data; 36417 36418 } 36419 36420 fromJSON(json) { 36421 36422 super.fromJSON(json); 36423 36424 this.currentPoint.fromArray(json.currentPoint); 36425 36426 return this; 36427 36428 } 36429 36430} 36431 36432class LatheGeometry extends BufferGeometry { 36433 36434 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) { 36435 36436 super(); 36437 36438 this.type = 'LatheGeometry'; 36439 36440 this.parameters = { 36441 points: points, 36442 segments: segments, 36443 phiStart: phiStart, 36444 phiLength: phiLength 36445 }; 36446 36447 segments = Math.floor(segments); 36448 36449 // clamp phiLength so it's in range of [ 0, 2PI ] 36450 36451 phiLength = clamp(phiLength, 0, Math.PI * 2); 36452 36453 // buffers 36454 36455 const indices = []; 36456 const vertices = []; 36457 const uvs = []; 36458 const initNormals = []; 36459 const normals = []; 36460 36461 // helper variables 36462 36463 const inverseSegments = 1.0 / segments; 36464 const vertex = new Vector3(); 36465 const uv = new Vector2(); 36466 const normal = new Vector3(); 36467 const curNormal = new Vector3(); 36468 const prevNormal = new Vector3(); 36469 let dx = 0; 36470 let dy = 0; 36471 36472 // pre-compute normals for initial "meridian" 36473 36474 for (let j = 0; j <= (points.length - 1); j++) { 36475 36476 switch (j) { 36477 36478 case 0: // special handling for 1st vertex on path 36479 36480 dx = points[j + 1].x - points[j].x; 36481 dy = points[j + 1].y - points[j].y; 36482 36483 normal.x = dy * 1.0; 36484 normal.y = - dx; 36485 normal.z = dy * 0.0; 36486 36487 prevNormal.copy(normal); 36488 36489 normal.normalize(); 36490 36491 initNormals.push(normal.x, normal.y, normal.z); 36492 36493 break; 36494 36495 case (points.length - 1): // special handling for last Vertex on path 36496 36497 initNormals.push(prevNormal.x, prevNormal.y, prevNormal.z); 36498 36499 break; 36500 36501 default: // default handling for all vertices in between 36502 36503 dx = points[j + 1].x - points[j].x; 36504 dy = points[j + 1].y - points[j].y; 36505 36506 normal.x = dy * 1.0; 36507 normal.y = - dx; 36508 normal.z = dy * 0.0; 36509 36510 curNormal.copy(normal); 36511 36512 normal.x += prevNormal.x; 36513 normal.y += prevNormal.y; 36514 normal.z += prevNormal.z; 36515 36516 normal.normalize(); 36517 36518 initNormals.push(normal.x, normal.y, normal.z); 36519 36520 prevNormal.copy(curNormal); 36521 36522 } 36523 36524 } 36525 36526 // generate vertices, uvs and normals 36527 36528 for (let i = 0; i <= segments; i++) { 36529 36530 const phi = phiStart + i * inverseSegments * phiLength; 36531 36532 const sin = Math.sin(phi); 36533 const cos = Math.cos(phi); 36534 36535 for (let j = 0; j <= (points.length - 1); j++) { 36536 36537 // vertex 36538 36539 vertex.x = points[j].x * sin; 36540 vertex.y = points[j].y; 36541 vertex.z = points[j].x * cos; 36542 36543 vertices.push(vertex.x, vertex.y, vertex.z); 36544 36545 // uv 36546 36547 uv.x = i / segments; 36548 uv.y = j / (points.length - 1); 36549 36550 uvs.push(uv.x, uv.y); 36551 36552 // normal 36553 36554 const x = initNormals[3 * j + 0] * sin; 36555 const y = initNormals[3 * j + 1]; 36556 const z = initNormals[3 * j + 0] * cos; 36557 36558 normals.push(x, y, z); 36559 36560 } 36561 36562 } 36563 36564 // indices 36565 36566 for (let i = 0; i < segments; i++) { 36567 36568 for (let j = 0; j < (points.length - 1); j++) { 36569 36570 const base = j + i * points.length; 36571 36572 const a = base; 36573 const b = base + points.length; 36574 const c = base + points.length + 1; 36575 const d = base + 1; 36576 36577 // faces 36578 36579 indices.push(a, b, d); 36580 indices.push(c, d, b); 36581 36582 } 36583 36584 } 36585 36586 // build geometry 36587 36588 this.setIndex(indices); 36589 this.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 36590 this.setAttribute('uv', new Float32BufferAttribute(uvs, 2)); 36591 this.setAttribute('normal', new Float32BufferAttribute(normals, 3)); 36592 36593 } 36594 36595 copy(source) { 36596 36597 super.copy(source); 36598 36599 this.parameters = Object.assign({}, source.parameters); 36600 36601 return this; 36602 36603 } 36604 36605 static fromJSON(data) { 36606 36607 return new LatheGeometry(data.points, data.segments, data.phiStart, data.phiLength); 36608 36609 } 36610 36611} 36612 36613class CapsuleGeometry extends LatheGeometry { 36614 36615 constructor(radius = 1, length = 1, capSegments = 4, radialSegments = 8) { 36616 36617 const path = new Path(); 36618 path.absarc(0, - length / 2, radius, Math.PI * 1.5, 0); 36619 path.absarc(0, length / 2, radius, 0, Math.PI * 0.5); 36620 36621 super(path.getPoints(capSegments), radialSegments); 36622 36623 this.type = 'CapsuleGeometry'; 36624 36625 this.parameters = { 36626 radius: radius, 36627 length: length, 36628 capSegments: capSegments, 36629 radialSegments: radialSegments, 36630 }; 36631 36632 } 36633 36634 static fromJSON(data) { 36635 36636 return new CapsuleGeometry(data.radius, data.length, data.capSegments, data.radialSegments); 36637 36638 } 36639 36640} 36641 36642class CircleGeometry extends BufferGeometry { 36643 36644 constructor(radius = 1, segments = 32, thetaStart = 0, thetaLength = Math.PI * 2) { 36645 36646 super(); 36647
vendor: 5,120 bytes, lines 36648-36896
36648 this.type = 'CircleGeometry'; 36649 36650 this.parameters = { 36651 radius: radius, 36652 segments: segments, 36653 thetaStart: thetaStart, 36654 thetaLength: thetaLength 36655 }; 36656 36657 segments = Math.max(3, segments); 36658 36659 // buffers 36660 36661 const indices = []; 36662 const vertices = []; 36663 const normals = []; 36664 const uvs = []; 36665 36666 // helper variables 36667 36668 const vertex = new Vector3(); 36669 const uv = new Vector2(); 36670 36671 // center point 36672 36673 vertices.push(0, 0, 0); 36674 normals.push(0, 0, 1); 36675 uvs.push(0.5, 0.5); 36676 36677 for (let s = 0, i = 3; s <= segments; s++, i += 3) { 36678 36679 const segment = thetaStart + s / segments * thetaLength; 36680 36681 // vertex 36682 36683 vertex.x = radius * Math.cos(segment); 36684 vertex.y = radius * Math.sin(segment); 36685 36686 vertices.push(vertex.x, vertex.y, vertex.z); 36687 36688 // normal 36689 36690 normals.push(0, 0, 1); 36691 36692 // uvs 36693 36694 uv.x = (vertices[i] / radius + 1) / 2; 36695 uv.y = (vertices[i + 1] / radius + 1) / 2; 36696 36697 uvs.push(uv.x, uv.y); 36698 36699 } 36700 36701 // indices 36702 36703 for (let i = 1; i <= segments; i++) { 36704 36705 indices.push(i, i + 1, 0); 36706 36707 } 36708 36709 // build geometry 36710 36711 this.setIndex(indices); 36712 this.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 36713 this.setAttribute('normal', new Float32BufferAttribute(normals, 3)); 36714 this.setAttribute('uv', new Float32BufferAttribute(uvs, 2)); 36715 36716 } 36717 36718 copy(source) { 36719 36720 super.copy(source); 36721 36722 this.parameters = Object.assign({}, source.parameters); 36723 36724 return this; 36725 36726 } 36727 36728 static fromJSON(data) { 36729 36730 return new CircleGeometry(data.radius, data.segments, data.thetaStart, data.thetaLength); 36731 36732 } 36733 36734} 36735 36736class CylinderGeometry extends BufferGeometry { 36737 36738 constructor(radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2) { 36739 36740 super(); 36741 36742 this.type = 'CylinderGeometry'; 36743 36744 this.parameters = { 36745 radiusTop: radiusTop, 36746 radiusBottom: radiusBottom, 36747 height: height, 36748 radialSegments: radialSegments, 36749 heightSegments: heightSegments, 36750 openEnded: openEnded, 36751 thetaStart: thetaStart, 36752 thetaLength: thetaLength 36753 }; 36754 36755 const scope = this; 36756 36757 radialSegments = Math.floor(radialSegments); 36758 heightSegments = Math.floor(heightSegments); 36759 36760 // buffers 36761 36762 const indices = []; 36763 const vertices = []; 36764 const normals = []; 36765 const uvs = []; 36766 36767 // helper variables 36768 36769 let index = 0; 36770 const indexArray = []; 36771 const halfHeight = height / 2; 36772 let groupStart = 0; 36773 36774 // generate geometry 36775 36776 generateTorso(); 36777 36778 if (openEnded === false) { 36779 36780 if (radiusTop > 0) generateCap(true); 36781 if (radiusBottom > 0) generateCap(false); 36782 36783 } 36784 36785 // build geometry 36786 36787 this.setIndex(indices); 36788 this.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 36789 this.setAttribute('normal', new Float32BufferAttribute(normals, 3)); 36790 this.setAttribute('uv', new Float32BufferAttribute(uvs, 2)); 36791 36792 function generateTorso() { 36793 36794 const normal = new Vector3(); 36795 const vertex = new Vector3(); 36796 36797 let groupCount = 0; 36798 36799 // this will be used to calculate the normal 36800 const slope = (radiusBottom - radiusTop) / height; 36801 36802 // generate vertices, normals and uvs 36803 36804 for (let y = 0; y <= heightSegments; y++) { 36805 36806 const indexRow = []; 36807 36808 const v = y / heightSegments; 36809 36810 // calculate the radius of the current row 36811 36812 const radius = v * (radiusBottom - radiusTop) + radiusTop; 36813 36814 for (let x = 0; x <= radialSegments; x++) { 36815 36816 const u = x / radialSegments; 36817 36818 const theta = u * thetaLength + thetaStart; 36819 36820 const sinTheta = Math.sin(theta); 36821 const cosTheta = Math.cos(theta); 36822 36823 // vertex 36824 36825 vertex.x = radius * sinTheta; 36826 vertex.y = - v * height + halfHeight; 36827 vertex.z = radius * cosTheta; 36828 vertices.push(vertex.x, vertex.y, vertex.z); 36829 36830 // normal 36831 36832 normal.set(sinTheta, slope, cosTheta).normalize(); 36833 normals.push(normal.x, normal.y, normal.z); 36834 36835 // uv 36836 36837 uvs.push(u, 1 - v); 36838 36839 // save index of vertex in respective row 36840 36841 indexRow.push(index++); 36842 36843 } 36844 36845 // now save vertices of the row in our index array 36846 36847 indexArray.push(indexRow); 36848 36849 } 36850 36851 // generate indices 36852 36853 for (let x = 0; x < radialSegments; x++) { 36854 36855 for (let y = 0; y < heightSegments; y++) { 36856 36857 // we use the index array to access the correct indices 36858 36859 const a = indexArray[y][x]; 36860 const b = indexArray[y + 1][x]; 36861 const c = indexArray[y + 1][x + 1]; 36862 const d = indexArray[y][x + 1]; 36863 36864 // faces 36865 36866 indices.push(a, b, d); 36867 indices.push(b, c, d); 36868 36869 // update group counter 36870 36871 groupCount += 6; 36872 36873 } 36874 36875 } 36876 36877 // add a group to the geometry. this will ensure multi material support 36878 36879 scope.addGroup(groupStart, groupCount, 0); 36880 36881 // calculate new start value for groups 36882 36883 groupStart += groupCount; 36884 36885 } 36886 36887 function generateCap(top) { 36888 36889 // save the index of the first center vertex 36890 const centerIndexStart = index; 36891 36892 const uv = new Vector2(); 36893 const vertex = new Vector3(); 36894 36895 let groupCount = 0; 36896
vendor: 16,422 bytes, lines 36897-37688
36897 const radius = (top === true) ? radiusTop : radiusBottom; 36898 const sign = (top === true) ? 1 : - 1; 36899 36900 // first we generate the center vertex data of the cap. 36901 // because the geometry needs one set of uvs per face, 36902 // we must generate a center vertex per face/segment 36903 36904 for (let x = 1; x <= radialSegments; x++) { 36905 36906 // vertex 36907 36908 vertices.push(0, halfHeight * sign, 0); 36909 36910 // normal 36911 36912 normals.push(0, sign, 0); 36913 36914 // uv 36915 36916 uvs.push(0.5, 0.5); 36917 36918 // increase index 36919 36920 index++; 36921 36922 } 36923 36924 // save the index of the last center vertex 36925 const centerIndexEnd = index; 36926 36927 // now we generate the surrounding vertices, normals and uvs 36928 36929 for (let x = 0; x <= radialSegments; x++) { 36930 36931 const u = x / radialSegments; 36932 const theta = u * thetaLength + thetaStart; 36933 36934 const cosTheta = Math.cos(theta); 36935 const sinTheta = Math.sin(theta); 36936 36937 // vertex 36938 36939 vertex.x = radius * sinTheta; 36940 vertex.y = halfHeight * sign; 36941 vertex.z = radius * cosTheta; 36942 vertices.push(vertex.x, vertex.y, vertex.z); 36943 36944 // normal 36945 36946 normals.push(0, sign, 0); 36947 36948 // uv 36949 36950 uv.x = (cosTheta * 0.5) + 0.5; 36951 uv.y = (sinTheta * 0.5 * sign) + 0.5; 36952 uvs.push(uv.x, uv.y); 36953 36954 // increase index 36955 36956 index++; 36957 36958 } 36959 36960 // generate indices 36961 36962 for (let x = 0; x < radialSegments; x++) { 36963 36964 const c = centerIndexStart + x; 36965 const i = centerIndexEnd + x; 36966 36967 if (top === true) { 36968 36969 // face top 36970 36971 indices.push(i, i + 1, c); 36972 36973 } else { 36974 36975 // face bottom 36976 36977 indices.push(i + 1, i, c); 36978 36979 } 36980 36981 groupCount += 3; 36982 36983 } 36984 36985 // add a group to the geometry. this will ensure multi material support 36986 36987 scope.addGroup(groupStart, groupCount, top === true ? 1 : 2); 36988 36989 // calculate new start value for groups 36990 36991 groupStart += groupCount; 36992 36993 } 36994 36995 } 36996 36997 copy(source) { 36998 36999 super.copy(source); 37000 37001 this.parameters = Object.assign({}, source.parameters); 37002 37003 return this; 37004 37005 } 37006 37007 static fromJSON(data) { 37008 37009 return new CylinderGeometry(data.radiusTop, data.radiusBottom, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength); 37010 37011 } 37012 37013} 37014 37015class ConeGeometry extends CylinderGeometry { 37016 37017 constructor(radius = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2) { 37018 37019 super(0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength); 37020 37021 this.type = 'ConeGeometry'; 37022 37023 this.parameters = { 37024 radius: radius, 37025 height: height, 37026 radialSegments: radialSegments, 37027 heightSegments: heightSegments, 37028 openEnded: openEnded, 37029 thetaStart: thetaStart, 37030 thetaLength: thetaLength 37031 }; 37032 37033 } 37034 37035 static fromJSON(data) { 37036 37037 return new ConeGeometry(data.radius, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength); 37038 37039 } 37040 37041} 37042 37043class PolyhedronGeometry extends BufferGeometry { 37044 37045 constructor(vertices = [], indices = [], radius = 1, detail = 0) { 37046 37047 super(); 37048 37049 this.type = 'PolyhedronGeometry'; 37050 37051 this.parameters = { 37052 vertices: vertices, 37053 indices: indices, 37054 radius: radius, 37055 detail: detail 37056 }; 37057 37058 // default buffer data 37059 37060 const vertexBuffer = []; 37061 const uvBuffer = []; 37062 37063 // the subdivision creates the vertex buffer data 37064 37065 subdivide(detail); 37066 37067 // all vertices should lie on a conceptual sphere with a given radius 37068 37069 applyRadius(radius); 37070 37071 // finally, create the uv data 37072 37073 generateUVs(); 37074 37075 // build non-indexed geometry 37076 37077 this.setAttribute('position', new Float32BufferAttribute(vertexBuffer, 3)); 37078 this.setAttribute('normal', new Float32BufferAttribute(vertexBuffer.slice(), 3)); 37079 this.setAttribute('uv', new Float32BufferAttribute(uvBuffer, 2)); 37080 37081 if (detail === 0) { 37082 37083 this.computeVertexNormals(); // flat normals 37084 37085 } else { 37086 37087 this.normalizeNormals(); // smooth normals 37088 37089 } 37090 37091 // helper functions 37092 37093 function subdivide(detail) { 37094 37095 const a = new Vector3(); 37096 const b = new Vector3(); 37097 const c = new Vector3(); 37098 37099 // iterate over all faces and apply a subdivision with the given detail value 37100 37101 for (let i = 0; i < indices.length; i += 3) { 37102 37103 // get the vertices of the face 37104 37105 getVertexByIndex(indices[i + 0], a); 37106 getVertexByIndex(indices[i + 1], b); 37107 getVertexByIndex(indices[i + 2], c); 37108 37109 // perform subdivision 37110 37111 subdivideFace(a, b, c, detail); 37112 37113 } 37114 37115 } 37116 37117 function subdivideFace(a, b, c, detail) { 37118 37119 const cols = detail + 1; 37120 37121 // we use this multidimensional array as a data structure for creating the subdivision 37122 37123 const v = []; 37124 37125 // construct all of the vertices for this subdivision 37126 37127 for (let i = 0; i <= cols; i++) { 37128 37129 v[i] = []; 37130 37131 const aj = a.clone().lerp(c, i / cols); 37132 const bj = b.clone().lerp(c, i / cols); 37133 37134 const rows = cols - i; 37135 37136 for (let j = 0; j <= rows; j++) { 37137 37138 if (j === 0 && i === cols) { 37139 37140 v[i][j] = aj; 37141 37142 } else { 37143 37144 v[i][j] = aj.clone().lerp(bj, j / rows); 37145 37146 } 37147 37148 } 37149 37150 } 37151 37152 // construct all of the faces 37153 37154 for (let i = 0; i < cols; i++) { 37155 37156 for (let j = 0; j < 2 * (cols - i) - 1; j++) { 37157 37158 const k = Math.floor(j / 2); 37159 37160 if (j % 2 === 0) { 37161 37162 pushVertex(v[i][k + 1]); 37163 pushVertex(v[i + 1][k]); 37164 pushVertex(v[i][k]); 37165 37166 } else { 37167 37168 pushVertex(v[i][k + 1]); 37169 pushVertex(v[i + 1][k + 1]); 37170 pushVertex(v[i + 1][k]); 37171 37172 } 37173 37174 } 37175 37176 } 37177 37178 } 37179 37180 function applyRadius(radius) { 37181 37182 const vertex = new Vector3(); 37183 37184 // iterate over the entire buffer and apply the radius to each vertex 37185 37186 for (let i = 0; i < vertexBuffer.length; i += 3) { 37187 37188 vertex.x = vertexBuffer[i + 0]; 37189 vertex.y = vertexBuffer[i + 1]; 37190 vertex.z = vertexBuffer[i + 2]; 37191 37192 vertex.normalize().multiplyScalar(radius); 37193 37194 vertexBuffer[i + 0] = vertex.x; 37195 vertexBuffer[i + 1] = vertex.y; 37196 vertexBuffer[i + 2] = vertex.z; 37197 37198 } 37199 37200 } 37201 37202 function generateUVs() { 37203 37204 const vertex = new Vector3(); 37205 37206 for (let i = 0; i < vertexBuffer.length; i += 3) { 37207 37208 vertex.x = vertexBuffer[i + 0]; 37209 vertex.y = vertexBuffer[i + 1]; 37210 vertex.z = vertexBuffer[i + 2]; 37211 37212 const u = azimuth(vertex) / 2 / Math.PI + 0.5; 37213 const v = inclination(vertex) / Math.PI + 0.5; 37214 uvBuffer.push(u, 1 - v); 37215 37216 } 37217 37218 correctUVs(); 37219 37220 correctSeam(); 37221 37222 } 37223 37224 function correctSeam() { 37225 37226 // handle case when face straddles the seam, see #3269 37227 37228 for (let i = 0; i < uvBuffer.length; i += 6) { 37229 37230 // uv data of a single face 37231 37232 const x0 = uvBuffer[i + 0]; 37233 const x1 = uvBuffer[i + 2]; 37234 const x2 = uvBuffer[i + 4]; 37235 37236 const max = Math.max(x0, x1, x2); 37237 const min = Math.min(x0, x1, x2); 37238 37239 // 0.9 is somewhat arbitrary 37240 37241 if (max > 0.9 && min < 0.1) { 37242 37243 if (x0 < 0.2) uvBuffer[i + 0] += 1; 37244 if (x1 < 0.2) uvBuffer[i + 2] += 1; 37245 if (x2 < 0.2) uvBuffer[i + 4] += 1; 37246 37247 } 37248 37249 } 37250 37251 } 37252 37253 function pushVertex(vertex) { 37254 37255 vertexBuffer.push(vertex.x, vertex.y, vertex.z); 37256 37257 } 37258 37259 function getVertexByIndex(index, vertex) { 37260 37261 const stride = index * 3; 37262 37263 vertex.x = vertices[stride + 0]; 37264 vertex.y = vertices[stride + 1]; 37265 vertex.z = vertices[stride + 2]; 37266 37267 } 37268 37269 function correctUVs() { 37270 37271 const a = new Vector3(); 37272 const b = new Vector3(); 37273 const c = new Vector3(); 37274 37275 const centroid = new Vector3(); 37276 37277 const uvA = new Vector2(); 37278 const uvB = new Vector2(); 37279 const uvC = new Vector2(); 37280 37281 for (let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6) { 37282 37283 a.set(vertexBuffer[i + 0], vertexBuffer[i + 1], vertexBuffer[i + 2]); 37284 b.set(vertexBuffer[i + 3], vertexBuffer[i + 4], vertexBuffer[i + 5]); 37285 c.set(vertexBuffer[i + 6], vertexBuffer[i + 7], vertexBuffer[i + 8]); 37286 37287 uvA.set(uvBuffer[j + 0], uvBuffer[j + 1]); 37288 uvB.set(uvBuffer[j + 2], uvBuffer[j + 3]); 37289 uvC.set(uvBuffer[j + 4], uvBuffer[j + 5]); 37290 37291 centroid.copy(a).add(b).add(c).divideScalar(3); 37292 37293 const azi = azimuth(centroid); 37294 37295 correctUV(uvA, j + 0, a, azi); 37296 correctUV(uvB, j + 2, b, azi); 37297 correctUV(uvC, j + 4, c, azi); 37298 37299 } 37300 37301 } 37302 37303 function correctUV(uv, stride, vector, azimuth) { 37304 37305 if ((azimuth < 0) && (uv.x === 1)) { 37306 37307 uvBuffer[stride] = uv.x - 1; 37308 37309 } 37310 37311 if ((vector.x === 0) && (vector.z === 0)) { 37312 37313 uvBuffer[stride] = azimuth / 2 / Math.PI + 0.5; 37314 37315 } 37316 37317 } 37318 37319 // Angle around the Y axis, counter-clockwise when looking from above. 37320 37321 function azimuth(vector) { 37322 37323 return Math.atan2(vector.z, - vector.x); 37324 37325 } 37326 37327 37328 // Angle above the XZ plane. 37329 37330 function inclination(vector) { 37331 37332 return Math.atan2(- vector.y, Math.sqrt((vector.x * vector.x) + (vector.z * vector.z))); 37333 37334 } 37335 37336 } 37337 37338 copy(source) { 37339 37340 super.copy(source); 37341 37342 this.parameters = Object.assign({}, source.parameters); 37343 37344 return this; 37345 37346 } 37347 37348 static fromJSON(data) { 37349 37350 return new PolyhedronGeometry(data.vertices, data.indices, data.radius, data.details); 37351 37352 } 37353 37354} 37355 37356class DodecahedronGeometry extends PolyhedronGeometry { 37357 37358 constructor(radius = 1, detail = 0) { 37359 37360 const t = (1 + Math.sqrt(5)) / 2; 37361 const r = 1 / t; 37362 37363 const vertices = [ 37364 37365 // (±1, ±1, ±1) 37366 - 1, - 1, - 1, - 1, - 1, 1, 37367 - 1, 1, - 1, - 1, 1, 1, 37368 1, - 1, - 1, 1, - 1, 1, 37369 1, 1, - 1, 1, 1, 1, 37370 37371 // (0, ±1/Ï, ±Ï) 37372 0, - r, - t, 0, - r, t, 37373 0, r, - t, 0, r, t, 37374 37375 // (±1/Ï, ±Ï, 0) 37376 - r, - t, 0, - r, t, 0, 37377 r, - t, 0, r, t, 0, 37378 37379 // (±Ï, 0, ±1/Ï) 37380 - t, 0, - r, t, 0, - r, 37381 - t, 0, r, t, 0, r 37382 ]; 37383 37384 const indices = [ 37385 3, 11, 7, 3, 7, 15, 3, 15, 13, 37386 7, 19, 17, 7, 17, 6, 7, 6, 15, 37387 17, 4, 8, 17, 8, 10, 17, 10, 6, 37388 8, 0, 16, 8, 16, 2, 8, 2, 10, 37389 0, 12, 1, 0, 1, 18, 0, 18, 16, 37390 6, 10, 2, 6, 2, 13, 6, 13, 15, 37391 2, 16, 18, 2, 18, 3, 2, 3, 13, 37392 18, 1, 9, 18, 9, 11, 18, 11, 3, 37393 4, 14, 12, 4, 12, 0, 4, 0, 8, 37394 11, 9, 5, 11, 5, 19, 11, 19, 7, 37395 19, 5, 14, 19, 14, 4, 19, 4, 17, 37396 1, 12, 14, 1, 14, 5, 1, 5, 9 37397 ]; 37398 37399 super(vertices, indices, radius, detail); 37400 37401 this.type = 'DodecahedronGeometry'; 37402 37403 this.parameters = { 37404 radius: radius, 37405 detail: detail 37406 }; 37407 37408 } 37409 37410 static fromJSON(data) { 37411 37412 return new DodecahedronGeometry(data.radius, data.detail); 37413 37414 } 37415 37416} 37417 37418const _v0 = /*@__PURE__*/ new Vector3(); 37419const _v1$1 = /*@__PURE__*/ new Vector3(); 37420const _normal = /*@__PURE__*/ new Vector3(); 37421const _triangle = /*@__PURE__*/ new Triangle(); 37422 37423class EdgesGeometry extends BufferGeometry { 37424 37425 constructor(geometry = null, thresholdAngle = 1) { 37426 37427 super(); 37428 37429 this.type = 'EdgesGeometry'; 37430 37431 this.parameters = { 37432 geometry: geometry, 37433 thresholdAngle: thresholdAngle 37434 }; 37435 37436 if (geometry !== null) { 37437 37438 const precisionPoints = 4; 37439 const precision = Math.pow(10, precisionPoints); 37440 const thresholdDot = Math.cos(DEG2RAD * thresholdAngle); 37441 37442 const indexAttr = geometry.getIndex(); 37443 const positionAttr = geometry.getAttribute('position'); 37444 const indexCount = indexAttr ? indexAttr.count : positionAttr.count; 37445 37446 const indexArr = [0, 0, 0]; 37447 const vertKeys = ['a', 'b', 'c']; 37448 const hashes = new Array(3); 37449 37450 const edgeData = {}; 37451 const vertices = []; 37452 for (let i = 0; i < indexCount; i += 3) { 37453 37454 if (indexAttr) { 37455 37456 indexArr[0] = indexAttr.getX(i); 37457 indexArr[1] = indexAttr.getX(i + 1); 37458 indexArr[2] = indexAttr.getX(i + 2); 37459 37460 } else { 37461 37462 indexArr[0] = i; 37463 indexArr[1] = i + 1; 37464 indexArr[2] = i + 2; 37465 37466 } 37467 37468 const { a, b, c } = _triangle; 37469 a.fromBufferAttribute(positionAttr, indexArr[0]); 37470 b.fromBufferAttribute(positionAttr, indexArr[1]); 37471 c.fromBufferAttribute(positionAttr, indexArr[2]); 37472 _triangle.getNormal(_normal); 37473 37474 // create hashes for the edge from the vertices 37475 hashes[0] = `${Math.round(a.x * precision)},${Math.round(a.y * precision)},${Math.round(a.z * precision)}`; 37476 hashes[1] = `${Math.round(b.x * precision)},${Math.round(b.y * precision)},${Math.round(b.z * precision)}`; 37477 hashes[2] = `${Math.round(c.x * precision)},${Math.round(c.y * precision)},${Math.round(c.z * precision)}`; 37478 37479 // skip degenerate triangles 37480 if (hashes[0] === hashes[1] || hashes[1] === hashes[2] || hashes[2] === hashes[0]) { 37481 37482 continue; 37483 37484 } 37485 37486 // iterate over every edge 37487 for (let j = 0; j < 3; j++) { 37488 37489 // get the first and next vertex making up the edge 37490 const jNext = (j + 1) % 3; 37491 const vecHash0 = hashes[j]; 37492 const vecHash1 = hashes[jNext]; 37493 const v0 = _triangle[vertKeys[j]]; 37494 const v1 = _triangle[vertKeys[jNext]]; 37495 37496 const hash = `${vecHash0}_${vecHash1}`; 37497 const reverseHash = `${vecHash1}_${vecHash0}`; 37498 37499 if (reverseHash in edgeData && edgeData[reverseHash]) { 37500 37501 // if we found a sibling edge add it into the vertex array if 37502 // it meets the angle threshold and delete the edge from the map. 37503 if (_normal.dot(edgeData[reverseHash].normal) <= thresholdDot) { 37504 37505 vertices.push(v0.x, v0.y, v0.z); 37506 vertices.push(v1.x, v1.y, v1.z); 37507 37508 } 37509 37510 edgeData[reverseHash] = null; 37511 37512 } else if (!(hash in edgeData)) { 37513 37514 // if we've already got an edge here then skip adding a new one 37515 edgeData[hash] = { 37516 37517 index0: indexArr[j], 37518 index1: indexArr[jNext], 37519 normal: _normal.clone(), 37520 37521 }; 37522 37523 } 37524 37525 } 37526 37527 } 37528 37529 // iterate over all remaining, unmatched edges and add them to the vertex array 37530 for (const key in edgeData) { 37531 37532 if (edgeData[key]) { 37533 37534 const { index0, index1 } = edgeData[key]; 37535 _v0.fromBufferAttribute(positionAttr, index0); 37536 _v1$1.fromBufferAttribute(positionAttr, index1); 37537 37538 vertices.push(_v0.x, _v0.y, _v0.z); 37539 vertices.push(_v1$1.x, _v1$1.y, _v1$1.z); 37540 37541 } 37542 37543 } 37544 37545 this.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 37546 37547 } 37548 37549 } 37550 37551 copy(source) { 37552 37553 super.copy(source); 37554 37555 this.parameters = Object.assign({}, source.parameters); 37556 37557 return this; 37558 37559 } 37560 37561} 37562 37563class Shape extends Path { 37564 37565 constructor(points) { 37566 37567 super(points); 37568 37569 this.uuid = generateUUID(); 37570 37571 this.type = 'Shape'; 37572 37573 this.holes = []; 37574 37575 } 37576 37577 getPointsHoles(divisions) { 37578 37579 const holesPts = []; 37580 37581 for (let i = 0, l = this.holes.length; i < l; i++) { 37582 37583 holesPts[i] = this.holes[i].getPoints(divisions); 37584 37585 } 37586 37587 return holesPts; 37588 37589 } 37590 37591 // get points of shape and holes (keypoints based on segments parameter) 37592 37593 extractPoints(divisions) { 37594 37595 return { 37596 37597 shape: this.getPoints(divisions), 37598 holes: this.getPointsHoles(divisions) 37599 37600 }; 37601 37602 } 37603 37604 copy(source) { 37605 37606 super.copy(source); 37607 37608 this.holes = []; 37609 37610 for (let i = 0, l = source.holes.length; i < l; i++) { 37611 37612 const hole = source.holes[i]; 37613 37614 this.holes.push(hole.clone()); 37615 37616 } 37617 37618 return this; 37619 37620 } 37621 37622 toJSON() { 37623 37624 const data = super.toJSON(); 37625 37626 data.uuid = this.uuid; 37627 data.holes = []; 37628 37629 for (let i = 0, l = this.holes.length; i < l; i++) { 37630 37631 const hole = this.holes[i]; 37632 data.holes.push(hole.toJSON()); 37633 37634 } 37635 37636 return data; 37637 37638 } 37639 37640 fromJSON(json) { 37641 37642 super.fromJSON(json); 37643 37644 this.uuid = json.uuid; 37645 this.holes = []; 37646 37647 for (let i = 0, l = json.holes.length; i < l; i++) { 37648 37649 const hole = json.holes[i]; 37650 this.holes.push(new Path().fromJSON(hole)); 37651 37652 } 37653 37654 return this; 37655 37656 } 37657 37658} 37659 37660/** 37661 * Port from https://github.com/mapbox/earcut (v2.2.4) 37662 */ 37663 37664const Earcut = { 37665 37666 triangulate: function (data, holeIndices, dim = 2) { 37667 37668 const hasHoles = holeIndices && holeIndices.length; 37669 const outerLen = hasHoles ? holeIndices[0] * dim : data.length; 37670 let outerNode = linkedList(data, 0, outerLen, dim, true); 37671 const triangles = []; 37672 37673 if (!outerNode || outerNode.next === outerNode.prev) return triangles; 37674 37675 let minX, minY, maxX, maxY, x, y, invSize; 37676 37677 if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim); 37678 37679 // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox 37680 if (data.length > 80 * dim) { 37681 37682 minX = maxX = data[0]; 37683 minY = maxY = data[1]; 37684 37685 for (let i = dim; i < outerLen; i += dim) { 37686 37687 x = data[i]; 37688 y = data[i + 1];
vendor: 13,292 bytes, lines 37689-38274
37689 if (x < minX) minX = x; 37690 if (y < minY) minY = y; 37691 if (x > maxX) maxX = x; 37692 if (y > maxY) maxY = y; 37693 37694 } 37695 37696 // minX, minY and invSize are later used to transform coords into integers for z-order calculation 37697 invSize = Math.max(maxX - minX, maxY - minY); 37698 invSize = invSize !== 0 ? 32767 / invSize : 0; 37699 37700 } 37701 37702 earcutLinked(outerNode, triangles, dim, minX, minY, invSize, 0); 37703 37704 return triangles; 37705 37706 } 37707 37708}; 37709 37710// create a circular doubly linked list from polygon points in the specified winding order 37711function linkedList(data, start, end, dim, clockwise) { 37712 37713 let i, last; 37714 37715 if (clockwise === (signedArea(data, start, end, dim) > 0)) { 37716 37717 for (i = start; i < end; i += dim) last = insertNode(i, data[i], data[i + 1], last); 37718 37719 } else { 37720 37721 for (i = end - dim; i >= start; i -= dim) last = insertNode(i, data[i], data[i + 1], last); 37722 37723 } 37724 37725 if (last && equals(last, last.next)) { 37726 37727 removeNode(last); 37728 last = last.next; 37729 37730 } 37731 37732 return last; 37733 37734} 37735 37736// eliminate colinear or duplicate points 37737function filterPoints(start, end) { 37738 37739 if (!start) return start; 37740 if (!end) end = start; 37741 37742 let p = start, 37743 again; 37744 do { 37745 37746 again = false; 37747 37748 if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) { 37749 37750 removeNode(p); 37751 p = end = p.prev; 37752 if (p === p.next) break; 37753 again = true; 37754 37755 } else { 37756 37757 p = p.next; 37758 37759 } 37760 37761 } while (again || p !== end); 37762 37763 return end; 37764 37765} 37766 37767// main ear slicing loop which triangulates a polygon (given as a linked list) 37768function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) { 37769 37770 if (!ear) return; 37771 37772 // interlink polygon nodes in z-order 37773 if (!pass && invSize) indexCurve(ear, minX, minY, invSize); 37774 37775 let stop = ear, 37776 prev, next; 37777 37778 // iterate through ears, slicing them one by one 37779 while (ear.prev !== ear.next) { 37780 37781 prev = ear.prev; 37782 next = ear.next; 37783 37784 if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) { 37785 37786 // cut off the triangle 37787 triangles.push(prev.i / dim | 0); 37788 triangles.push(ear.i / dim | 0); 37789 triangles.push(next.i / dim | 0); 37790 37791 removeNode(ear); 37792 37793 // skipping the next vertex leads to less sliver triangles 37794 ear = next.next; 37795 stop = next.next; 37796 37797 continue; 37798 37799 } 37800 37801 ear = next; 37802 37803 // if we looped through the whole remaining polygon and can't find any more ears 37804 if (ear === stop) { 37805 37806 // try filtering points and slicing again 37807 if (!pass) { 37808 37809 earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1); 37810 37811 // if this didn't work, try curing all small self-intersections locally 37812 37813 } else if (pass === 1) { 37814 37815 ear = cureLocalIntersections(filterPoints(ear), triangles, dim); 37816 earcutLinked(ear, triangles, dim, minX, minY, invSize, 2); 37817 37818 // as a last resort, try splitting the remaining polygon into two 37819 37820 } else if (pass === 2) { 37821 37822 splitEarcut(ear, triangles, dim, minX, minY, invSize); 37823 37824 } 37825 37826 break; 37827 37828 } 37829 37830 } 37831 37832} 37833 37834// check whether a polygon node forms a valid ear with adjacent nodes 37835function isEar(ear) { 37836 37837 const a = ear.prev, 37838 b = ear, 37839 c = ear.next; 37840 37841 if (area(a, b, c) >= 0) return false; // reflex, can't be an ear 37842 37843 // now make sure we don't have other points inside the potential ear 37844 const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y; 37845 37846 // triangle bbox; min & max are calculated like this for speed 37847 const x0 = ax < bx ? (ax < cx ? ax : cx) : (bx < cx ? bx : cx), 37848 y0 = ay < by ? (ay < cy ? ay : cy) : (by < cy ? by : cy), 37849 x1 = ax > bx ? (ax > cx ? ax : cx) : (bx > cx ? bx : cx), 37850 y1 = ay > by ? (ay > cy ? ay : cy) : (by > cy ? by : cy); 37851 37852 let p = c.next; 37853 while (p !== a) { 37854 37855 if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && 37856 pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && 37857 area(p.prev, p, p.next) >= 0) return false; 37858 p = p.next; 37859 37860 } 37861 37862 return true; 37863 37864} 37865 37866function isEarHashed(ear, minX, minY, invSize) { 37867 37868 const a = ear.prev, 37869 b = ear, 37870 c = ear.next; 37871 37872 if (area(a, b, c) >= 0) return false; // reflex, can't be an ear 37873 37874 const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y; 37875 37876 // triangle bbox; min & max are calculated like this for speed 37877 const x0 = ax < bx ? (ax < cx ? ax : cx) : (bx < cx ? bx : cx), 37878 y0 = ay < by ? (ay < cy ? ay : cy) : (by < cy ? by : cy), 37879 x1 = ax > bx ? (ax > cx ? ax : cx) : (bx > cx ? bx : cx), 37880 y1 = ay > by ? (ay > cy ? ay : cy) : (by > cy ? by : cy); 37881 37882 // z-order range for the current triangle bbox; 37883 const minZ = zOrder(x0, y0, minX, minY, invSize), 37884 maxZ = zOrder(x1, y1, minX, minY, invSize); 37885 37886 let p = ear.prevZ, 37887 n = ear.nextZ; 37888 37889 // look for points inside the triangle in both directions 37890 while (p && p.z >= minZ && n && n.z <= maxZ) { 37891 37892 if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && 37893 pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false; 37894 p = p.prevZ; 37895 37896 if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && 37897 pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false; 37898 n = n.nextZ; 37899 37900 } 37901 37902 // look for remaining points in decreasing z-order 37903 while (p && p.z >= minZ) { 37904 37905 if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && 37906 pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false; 37907 p = p.prevZ; 37908 37909 } 37910 37911 // look for remaining points in increasing z-order 37912 while (n && n.z <= maxZ) { 37913 37914 if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && 37915 pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false; 37916 n = n.nextZ; 37917 37918 } 37919 37920 return true; 37921 37922} 37923 37924// go through all polygon nodes and cure small local self-intersections 37925function cureLocalIntersections(start, triangles, dim) { 37926 37927 let p = start; 37928 do { 37929 37930 const a = p.prev, 37931 b = p.next.next; 37932 37933 if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) { 37934 37935 triangles.push(a.i / dim | 0); 37936 triangles.push(p.i / dim | 0); 37937 triangles.push(b.i / dim | 0); 37938 37939 // remove two nodes involved 37940 removeNode(p); 37941 removeNode(p.next); 37942 37943 p = start = b; 37944 37945 } 37946 37947 p = p.next; 37948 37949 } while (p !== start); 37950 37951 return filterPoints(p); 37952 37953} 37954 37955// try splitting polygon into two and triangulate them independently 37956function splitEarcut(start, triangles, dim, minX, minY, invSize) { 37957 37958 // look for a valid diagonal that divides the polygon into two 37959 let a = start; 37960 do { 37961 37962 let b = a.next.next; 37963 while (b !== a.prev) { 37964 37965 if (a.i !== b.i && isValidDiagonal(a, b)) { 37966 37967 // split the polygon in two by the diagonal 37968 let c = splitPolygon(a, b); 37969 37970 // filter colinear points around the cuts 37971 a = filterPoints(a, a.next); 37972 c = filterPoints(c, c.next); 37973 37974 // run earcut on each half 37975 earcutLinked(a, triangles, dim, minX, minY, invSize, 0); 37976 earcutLinked(c, triangles, dim, minX, minY, invSize, 0); 37977 return; 37978 37979 } 37980 37981 b = b.next; 37982 37983 } 37984 37985 a = a.next; 37986 37987 } while (a !== start); 37988 37989} 37990 37991// link every hole into the outer loop, producing a single-ring polygon without holes 37992function eliminateHoles(data, holeIndices, outerNode, dim) { 37993 37994 const queue = []; 37995 let i, len, start, end, list; 37996 37997 for (i = 0, len = holeIndices.length; i < len; i++) { 37998 37999 start = holeIndices[i] * dim; 38000 end = i < len - 1 ? holeIndices[i + 1] * dim : data.length; 38001 list = linkedList(data, start, end, dim, false); 38002 if (list === list.next) list.steiner = true; 38003 queue.push(getLeftmost(list)); 38004 38005 } 38006 38007 queue.sort(compareX); 38008 38009 // process holes from left to right 38010 for (i = 0; i < queue.length; i++) { 38011 38012 outerNode = eliminateHole(queue[i], outerNode); 38013 38014 } 38015 38016 return outerNode; 38017 38018} 38019 38020function compareX(a, b) { 38021 38022 return a.x - b.x; 38023 38024} 38025 38026// find a bridge between vertices that connects hole with an outer ring and link it 38027function eliminateHole(hole, outerNode) { 38028 38029 const bridge = findHoleBridge(hole, outerNode); 38030 if (!bridge) { 38031 38032 return outerNode; 38033 38034 } 38035 38036 const bridgeReverse = splitPolygon(bridge, hole); 38037 38038 // filter collinear points around the cuts 38039 filterPoints(bridgeReverse, bridgeReverse.next); 38040 return filterPoints(bridge, bridge.next); 38041 38042} 38043 38044// David Eberly's algorithm for finding a bridge between hole and outer polygon 38045function findHoleBridge(hole, outerNode) { 38046 38047 let p = outerNode, 38048 qx = - Infinity, 38049 m; 38050 38051 const hx = hole.x, hy = hole.y; 38052 38053 // find a segment intersected by a ray from the hole's leftmost point to the left; 38054 // segment's endpoint with lesser x will be potential connection point 38055 do { 38056 38057 if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) { 38058 38059 const x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y); 38060 if (x <= hx && x > qx) { 38061 38062 qx = x; 38063 m = p.x < p.next.x ? p : p.next; 38064 if (x === hx) return m; // hole touches outer segment; pick leftmost endpoint 38065 38066 } 38067 38068 } 38069 38070 p = p.next; 38071 38072 } while (p !== outerNode); 38073 38074 if (!m) return null; 38075 38076 // look for points inside the triangle of hole point, segment intersection and endpoint; 38077 // if there are no points found, we have a valid connection; 38078 // otherwise choose the point of the minimum angle with the ray as connection point 38079 38080 const stop = m, 38081 mx = m.x, 38082 my = m.y; 38083 let tanMin = Infinity, tan; 38084 38085 p = m; 38086 38087 do { 38088 38089 if (hx >= p.x && p.x >= mx && hx !== p.x && 38090 pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) { 38091 38092 tan = Math.abs(hy - p.y) / (hx - p.x); // tangential 38093 38094 if (locallyInside(p, hole) && (tan < tanMin || (tan === tanMin && (p.x > m.x || (p.x === m.x && sectorContainsSector(m, p)))))) { 38095 38096 m = p; 38097 tanMin = tan; 38098 38099 } 38100 38101 } 38102 38103 p = p.next; 38104 38105 } while (p !== stop); 38106 38107 return m; 38108 38109} 38110 38111// whether sector in vertex m contains sector in vertex p in the same coordinates 38112function sectorContainsSector(m, p) { 38113 38114 return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0; 38115 38116} 38117 38118// interlink polygon nodes in z-order 38119function indexCurve(start, minX, minY, invSize) { 38120 38121 let p = start; 38122 do { 38123 38124 if (p.z === 0) p.z = zOrder(p.x, p.y, minX, minY, invSize); 38125 p.prevZ = p.prev; 38126 p.nextZ = p.next; 38127 p = p.next; 38128 38129 } while (p !== start); 38130 38131 p.prevZ.nextZ = null; 38132 p.prevZ = null; 38133 38134 sortLinked(p); 38135 38136} 38137 38138// Simon Tatham's linked list merge sort algorithm 38139// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html 38140function sortLinked(list) { 38141 38142 let i, p, q, e, tail, numMerges, pSize, qSize, 38143 inSize = 1; 38144 38145 do { 38146 38147 p = list; 38148 list = null; 38149 tail = null; 38150 numMerges = 0; 38151 38152 while (p) { 38153 38154 numMerges++; 38155 q = p; 38156 pSize = 0; 38157 for (i = 0; i < inSize; i++) { 38158 38159 pSize++; 38160 q = q.nextZ; 38161 if (!q) break; 38162 38163 } 38164 38165 qSize = inSize; 38166 38167 while (pSize > 0 || (qSize > 0 && q)) { 38168 38169 if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) { 38170 38171 e = p; 38172 p = p.nextZ; 38173 pSize--; 38174 38175 } else { 38176 38177 e = q; 38178 q = q.nextZ; 38179 qSize--; 38180 38181 } 38182 38183 if (tail) tail.nextZ = e; 38184 else list = e; 38185 38186 e.prevZ = tail; 38187 tail = e; 38188 38189 } 38190 38191 p = q; 38192 38193 } 38194 38195 tail.nextZ = null; 38196 inSize *= 2; 38197 38198 } while (numMerges > 1); 38199 38200 return list; 38201 38202} 38203 38204// z-order of a point given coords and inverse of the longer side of data bbox 38205function zOrder(x, y, minX, minY, invSize) { 38206 38207 // coords are transformed into non-negative 15-bit integer range 38208 x = (x - minX) * invSize | 0; 38209 y = (y - minY) * invSize | 0; 38210 38211 x = (x | (x << 8)) & 0x00FF00FF; 38212 x = (x | (x << 4)) & 0x0F0F0F0F; 38213 x = (x | (x << 2)) & 0x33333333; 38214 x = (x | (x << 1)) & 0x55555555; 38215 38216 y = (y | (y << 8)) & 0x00FF00FF; 38217 y = (y | (y << 4)) & 0x0F0F0F0F; 38218 y = (y | (y << 2)) & 0x33333333; 38219 y = (y | (y << 1)) & 0x55555555; 38220 38221 return x | (y << 1); 38222 38223} 38224 38225// find the leftmost node of a polygon ring 38226function getLeftmost(start) { 38227 38228 let p = start, 38229 leftmost = start; 38230 do { 38231 38232 if (p.x < leftmost.x || (p.x === leftmost.x && p.y < leftmost.y)) leftmost = p; 38233 p = p.next; 38234 38235 } while (p !== start); 38236 38237 return leftmost; 38238 38239} 38240 38241// check if a point lies within a convex triangle 38242function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) { 38243 38244 return (cx - px) * (ay - py) >= (ax - px) * (cy - py) && 38245 (ax - px) * (by - py) >= (bx - px) * (ay - py) && 38246 (bx - px) * (cy - py) >= (cx - px) * (by - py); 38247 38248} 38249 38250// check if a diagonal between two polygon nodes is valid (lies in polygon interior) 38251function isValidDiagonal(a, b) { 38252 38253 return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && // dones't intersect other edges 38254 (locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible 38255 (area(a.prev, a, b.prev) || area(a, b.prev, b)) || // does not create opposite-facing sectors 38256 equals(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0); // special zero-length case 38257 38258} 38259 38260// signed area of a triangle 38261function area(p, q, r) { 38262 38263 return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y); 38264 38265} 38266 38267// check if two points are equal 38268function equals(p1, p2) { 38269 38270 return p1.x === p2.x && p1.y === p2.y; 38271 38272} 38273 38274// check if two segments intersect
vendor: 7,761 bytes, lines 38275-38622
38275function intersects(p1, q1, p2, q2) { 38276 38277 const o1 = sign(area(p1, q1, p2)); 38278 const o2 = sign(area(p1, q1, q2)); 38279 const o3 = sign(area(p2, q2, p1)); 38280 const o4 = sign(area(p2, q2, q1)); 38281 38282 if (o1 !== o2 && o3 !== o4) return true; // general case 38283 38284 if (o1 === 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1 38285 if (o2 === 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1 38286 if (o3 === 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2 38287 if (o4 === 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2 38288 38289 return false; 38290 38291} 38292 38293// for collinear points p, q, r, check if point q lies on segment pr 38294function onSegment(p, q, r) { 38295 38296 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); 38297 38298} 38299 38300function sign(num) { 38301 38302 return num > 0 ? 1 : num < 0 ? - 1 : 0; 38303 38304} 38305 38306// check if a polygon diagonal intersects any polygon segments 38307function intersectsPolygon(a, b) { 38308 38309 let p = a; 38310 do { 38311 38312 if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && 38313 intersects(p, p.next, a, b)) return true; 38314 p = p.next; 38315 38316 } while (p !== a); 38317 38318 return false; 38319 38320} 38321 38322// check if a polygon diagonal is locally inside the polygon 38323function locallyInside(a, b) { 38324 38325 return area(a.prev, a, a.next) < 0 ? 38326 area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 : 38327 area(a, b, a.prev) < 0 || area(a, a.next, b) < 0; 38328 38329} 38330 38331// check if the middle point of a polygon diagonal is inside the polygon 38332function middleInside(a, b) { 38333 38334 let p = a, 38335 inside = false; 38336 const px = (a.x + b.x) / 2, 38337 py = (a.y + b.y) / 2; 38338 do { 38339 38340 if (((p.y > py) !== (p.next.y > py)) && p.next.y !== p.y && 38341 (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x)) 38342 inside = !inside; 38343 p = p.next; 38344 38345 } while (p !== a); 38346 38347 return inside; 38348 38349} 38350 38351// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two; 38352// if one belongs to the outer ring and another to a hole, it merges it into a single ring 38353function splitPolygon(a, b) { 38354 38355 const a2 = new Node(a.i, a.x, a.y), 38356 b2 = new Node(b.i, b.x, b.y), 38357 an = a.next, 38358 bp = b.prev; 38359 38360 a.next = b; 38361 b.prev = a; 38362 38363 a2.next = an; 38364 an.prev = a2; 38365 38366 b2.next = a2; 38367 a2.prev = b2; 38368 38369 bp.next = b2; 38370 b2.prev = bp; 38371 38372 return b2; 38373 38374} 38375 38376// create a node and optionally link it with previous one (in a circular doubly linked list) 38377function insertNode(i, x, y, last) { 38378 38379 const p = new Node(i, x, y); 38380 38381 if (!last) { 38382 38383 p.prev = p; 38384 p.next = p; 38385 38386 } else { 38387 38388 p.next = last.next; 38389 p.prev = last; 38390 last.next.prev = p; 38391 last.next = p; 38392 38393 } 38394 38395 return p; 38396 38397} 38398 38399function removeNode(p) { 38400 38401 p.next.prev = p.prev; 38402 p.prev.next = p.next; 38403 38404 if (p.prevZ) p.prevZ.nextZ = p.nextZ; 38405 if (p.nextZ) p.nextZ.prevZ = p.prevZ; 38406 38407} 38408 38409function Node(i, x, y) { 38410 38411 // vertex index in coordinates array 38412 this.i = i; 38413 38414 // vertex coordinates 38415 this.x = x; 38416 this.y = y; 38417 38418 // previous and next vertex nodes in a polygon ring 38419 this.prev = null; 38420 this.next = null; 38421 38422 // z-order curve value 38423 this.z = 0; 38424 38425 // previous and next nodes in z-order 38426 this.prevZ = null; 38427 this.nextZ = null; 38428 38429 // indicates whether this is a steiner point 38430 this.steiner = false; 38431 38432} 38433 38434function signedArea(data, start, end, dim) { 38435 38436 let sum = 0; 38437 for (let i = start, j = end - dim; i < end; i += dim) { 38438 38439 sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]); 38440 j = i; 38441 38442 } 38443 38444 return sum; 38445 38446} 38447 38448class ShapeUtils { 38449 38450 // calculate area of the contour polygon 38451 38452 static area(contour) { 38453 38454 const n = contour.length; 38455 let a = 0.0; 38456 38457 for (let p = n - 1, q = 0; q < n; p = q++) { 38458 38459 a += contour[p].x * contour[q].y - contour[q].x * contour[p].y; 38460 38461 } 38462 38463 return a * 0.5; 38464 38465 } 38466 38467 static isClockWise(pts) { 38468 38469 return ShapeUtils.area(pts) < 0; 38470 38471 } 38472 38473 static triangulateShape(contour, holes) { 38474 38475 const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ] 38476 const holeIndices = []; // array of hole indices 38477 const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ] 38478 38479 removeDupEndPts(contour); 38480 addContour(vertices, contour); 38481 38482 // 38483 38484 let holeIndex = contour.length; 38485 38486 holes.forEach(removeDupEndPts); 38487 38488 for (let i = 0; i < holes.length; i++) { 38489 38490 holeIndices.push(holeIndex); 38491 holeIndex += holes[i].length; 38492 addContour(vertices, holes[i]); 38493 38494 } 38495 38496 // 38497 38498 const triangles = Earcut.triangulate(vertices, holeIndices); 38499 38500 // 38501 38502 for (let i = 0; i < triangles.length; i += 3) { 38503 38504 faces.push(triangles.slice(i, i + 3)); 38505 38506 } 38507 38508 return faces; 38509 38510 } 38511 38512} 38513 38514function removeDupEndPts(points) { 38515 38516 const l = points.length; 38517 38518 if (l > 2 && points[l - 1].equals(points[0])) { 38519 38520 points.pop(); 38521 38522 } 38523 38524} 38525 38526function addContour(vertices, contour) { 38527 38528 for (let i = 0; i < contour.length; i++) { 38529 38530 vertices.push(contour[i].x); 38531 vertices.push(contour[i].y); 38532 38533 } 38534 38535} 38536 38537/** 38538 * Creates extruded geometry from a path shape. 38539 * 38540 * parameters = { 38541 * 38542 * curveSegments: <int>, // number of points on the curves 38543 * steps: <int>, // number of points for z-side extrusions / used for subdividing segments of extrude spline too 38544 * depth: <float>, // Depth to extrude the shape 38545 * 38546 * bevelEnabled: <bool>, // turn on bevel 38547 * bevelThickness: <float>, // how deep into the original shape bevel goes 38548 * bevelSize: <float>, // how far from shape outline (including bevelOffset) is bevel 38549 * bevelOffset: <float>, // how far from shape outline does bevel start 38550 * bevelSegments: <int>, // number of bevel layers 38551 * 38552 * extrudePath: <THREE.Curve> // curve to extrude shape along 38553 * 38554 * UVGenerator: <Object> // object that provides UV generator functions 38555 * 38556 * } 38557 */ 38558 38559 38560class ExtrudeGeometry extends BufferGeometry { 38561 38562 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 = {}) { 38563 38564 super(); 38565 38566 this.type = 'ExtrudeGeometry'; 38567 38568 this.parameters = { 38569 shapes: shapes, 38570 options: options 38571 }; 38572 38573 shapes = Array.isArray(shapes) ? shapes : [shapes]; 38574 38575 const scope = this; 38576 38577 const verticesArray = []; 38578 const uvArray = []; 38579 38580 for (let i = 0, l = shapes.length; i < l; i++) { 38581 38582 const shape = shapes[i]; 38583 addShape(shape); 38584 38585 } 38586 38587 // build geometry 38588 38589 this.setAttribute('position', new Float32BufferAttribute(verticesArray, 3)); 38590 this.setAttribute('uv', new Float32BufferAttribute(uvArray, 2)); 38591 38592 this.computeVertexNormals(); 38593 38594 // functions 38595 38596 function addShape(shape) { 38597 38598 const placeholder = []; 38599 38600 // options 38601 38602 const curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; 38603 const steps = options.steps !== undefined ? options.steps : 1; 38604 const depth = options.depth !== undefined ? options.depth : 1; 38605 38606 let bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; 38607 let bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 0.2; 38608 let bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 0.1; 38609 let bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0; 38610 let bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; 38611 38612 const extrudePath = options.extrudePath; 38613 38614 const uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator; 38615 38616 // 38617 38618 let extrudePts, extrudeByPath = false; 38619 let splineTube, binormal, normal, position2; 38620 38621 if (extrudePath) { 38622
vendor: 2,780 bytes, lines 38623-38732
38623 extrudePts = extrudePath.getSpacedPoints(steps); 38624 38625 extrudeByPath = true; 38626 bevelEnabled = false; // bevels not supported for path extrusion 38627 38628 // SETUP TNB variables 38629 38630 // TODO1 - have a .isClosed in spline? 38631 38632 splineTube = extrudePath.computeFrenetFrames(steps, false); 38633 38634 // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); 38635 38636 binormal = new Vector3(); 38637 normal = new Vector3(); 38638 position2 = new Vector3(); 38639 38640 } 38641 38642 // Safeguards if bevels are not enabled 38643 38644 if (!bevelEnabled) { 38645 38646 bevelSegments = 0; 38647 bevelThickness = 0; 38648 bevelSize = 0; 38649 bevelOffset = 0; 38650 38651 } 38652 38653 // Variables initialization 38654 38655 const shapePoints = shape.extractPoints(curveSegments); 38656 38657 let vertices = shapePoints.shape; 38658 const holes = shapePoints.holes; 38659 38660 const reverse = !ShapeUtils.isClockWise(vertices); 38661 38662 if (reverse) { 38663 38664 vertices = vertices.reverse(); 38665 38666 // Maybe we should also check if holes are in the opposite direction, just to be safe ... 38667 38668 for (let h = 0, hl = holes.length; h < hl; h++) { 38669 38670 const ahole = holes[h]; 38671 38672 if (ShapeUtils.isClockWise(ahole)) { 38673 38674 holes[h] = ahole.reverse(); 38675 38676 } 38677 38678 } 38679 38680 } 38681 38682 38683 const faces = ShapeUtils.triangulateShape(vertices, holes); 38684 38685 /* Vertices */ 38686 38687 const contour = vertices; // vertices has all points but contour has only points of circumference 38688 38689 for (let h = 0, hl = holes.length; h < hl; h++) { 38690 38691 const ahole = holes[h]; 38692 38693 vertices = vertices.concat(ahole); 38694 38695 } 38696 38697 38698 function scalePt2(pt, vec, size) { 38699 38700 if (!vec) console.error('THREE.ExtrudeGeometry: vec does not exist'); 38701 38702 return pt.clone().addScaledVector(vec, size); 38703 38704 } 38705 38706 const vlen = vertices.length, flen = faces.length; 38707 38708 38709 // Find directions for point movement 38710 38711 38712 function getBevelVec(inPt, inPrev, inNext) { 38713 38714 // computes for inPt the corresponding point inPt' on a new contour 38715 // shifted by 1 unit (length of normalized vector) to the left 38716 // if we walk along contour clockwise, this new contour is outside the old one 38717 // 38718 // inPt' is the intersection of the two lines parallel to the two 38719 // adjacent edges of inPt at a distance of 1 unit on the left side. 38720 38721 let v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt 38722 38723 // good reading for geometry algorithms (here: line-line intersection) 38724 // http://geomalgorithms.com/a05-_intersect-1.html 38725 38726 const v_prev_x = inPt.x - inPrev.x, 38727 v_prev_y = inPt.y - inPrev.y; 38728 const v_next_x = inNext.x - inPt.x, 38729 v_next_y = inNext.y - inPt.y; 38730 38731 const v_prev_lensq = (v_prev_x * v_prev_x + v_prev_y * v_prev_y); 38732
vendor: 17,749 bytes, lines 38733-39586
38733 // check for collinear edges 38734 const collinear0 = (v_prev_x * v_next_y - v_prev_y * v_next_x); 38735 38736 if (Math.abs(collinear0) > Number.EPSILON) { 38737 38738 // not collinear 38739 38740 // length of vectors for normalizing 38741 38742 const v_prev_len = Math.sqrt(v_prev_lensq); 38743 const v_next_len = Math.sqrt(v_next_x * v_next_x + v_next_y * v_next_y); 38744 38745 // shift adjacent points by unit vectors to the left 38746 38747 const ptPrevShift_x = (inPrev.x - v_prev_y / v_prev_len); 38748 const ptPrevShift_y = (inPrev.y + v_prev_x / v_prev_len); 38749 38750 const ptNextShift_x = (inNext.x - v_next_y / v_next_len); 38751 const ptNextShift_y = (inNext.y + v_next_x / v_next_len); 38752 38753 // scaling factor for v_prev to intersection point 38754 38755 const sf = ((ptNextShift_x - ptPrevShift_x) * v_next_y - 38756 (ptNextShift_y - ptPrevShift_y) * v_next_x) / 38757 (v_prev_x * v_next_y - v_prev_y * v_next_x); 38758 38759 // vector from inPt to intersection point 38760 38761 v_trans_x = (ptPrevShift_x + v_prev_x * sf - inPt.x); 38762 v_trans_y = (ptPrevShift_y + v_prev_y * sf - inPt.y); 38763 38764 // Don't normalize!, otherwise sharp corners become ugly 38765 // but prevent crazy spikes 38766 const v_trans_lensq = (v_trans_x * v_trans_x + v_trans_y * v_trans_y); 38767 if (v_trans_lensq <= 2) { 38768 38769 return new Vector2(v_trans_x, v_trans_y); 38770 38771 } else { 38772 38773 shrink_by = Math.sqrt(v_trans_lensq / 2); 38774 38775 } 38776 38777 } else { 38778 38779 // handle special case of collinear edges 38780 38781 let direction_eq = false; // assumes: opposite 38782 38783 if (v_prev_x > Number.EPSILON) { 38784 38785 if (v_next_x > Number.EPSILON) { 38786 38787 direction_eq = true; 38788 38789 } 38790 38791 } else { 38792 38793 if (v_prev_x < - Number.EPSILON) { 38794 38795 if (v_next_x < - Number.EPSILON) { 38796 38797 direction_eq = true; 38798 38799 } 38800 38801 } else { 38802 38803 if (Math.sign(v_prev_y) === Math.sign(v_next_y)) { 38804 38805 direction_eq = true; 38806 38807 } 38808 38809 } 38810 38811 } 38812 38813 if (direction_eq) { 38814 38815 // console.log("Warning: lines are a straight sequence"); 38816 v_trans_x = - v_prev_y; 38817 v_trans_y = v_prev_x; 38818 shrink_by = Math.sqrt(v_prev_lensq); 38819 38820 } else { 38821 38822 // console.log("Warning: lines are a straight spike"); 38823 v_trans_x = v_prev_x; 38824 v_trans_y = v_prev_y; 38825 shrink_by = Math.sqrt(v_prev_lensq / 2); 38826 38827 } 38828 38829 } 38830 38831 return new Vector2(v_trans_x / shrink_by, v_trans_y / shrink_by); 38832 38833 } 38834 38835 38836 const contourMovements = []; 38837 38838 for (let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i++, j++, k++) { 38839 38840 if (j === il) j = 0; 38841 if (k === il) k = 0; 38842 38843 // (j)---(i)---(k) 38844 // console.log('i,j,k', i, j , k) 38845 38846 contourMovements[i] = getBevelVec(contour[i], contour[j], contour[k]); 38847 38848 } 38849 38850 const holesMovements = []; 38851 let oneHoleMovements, verticesMovements = contourMovements.concat(); 38852 38853 for (let h = 0, hl = holes.length; h < hl; h++) { 38854 38855 const ahole = holes[h]; 38856 38857 oneHoleMovements = []; 38858 38859 for (let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i++, j++, k++) { 38860 38861 if (j === il) j = 0; 38862 if (k === il) k = 0; 38863 38864 // (j)---(i)---(k) 38865 oneHoleMovements[i] = getBevelVec(ahole[i], ahole[j], ahole[k]); 38866 38867 } 38868 38869 holesMovements.push(oneHoleMovements); 38870 verticesMovements = verticesMovements.concat(oneHoleMovements); 38871 38872 } 38873 38874 38875 // Loop bevelSegments, 1 for the front, 1 for the back 38876 38877 for (let b = 0; b < bevelSegments; b++) { 38878 38879 //for ( b = bevelSegments; b > 0; b -- ) { 38880 38881 const t = b / bevelSegments; 38882 const z = bevelThickness * Math.cos(t * Math.PI / 2); 38883 const bs = bevelSize * Math.sin(t * Math.PI / 2) + bevelOffset; 38884 38885 // contract shape 38886 38887 for (let i = 0, il = contour.length; i < il; i++) { 38888 38889 const vert = scalePt2(contour[i], contourMovements[i], bs); 38890 38891 v(vert.x, vert.y, - z); 38892 38893 } 38894 38895 // expand holes 38896 38897 for (let h = 0, hl = holes.length; h < hl; h++) { 38898 38899 const ahole = holes[h]; 38900 oneHoleMovements = holesMovements[h]; 38901 38902 for (let i = 0, il = ahole.length; i < il; i++) { 38903 38904 const vert = scalePt2(ahole[i], oneHoleMovements[i], bs); 38905 38906 v(vert.x, vert.y, - z); 38907 38908 } 38909 38910 } 38911 38912 } 38913 38914 const bs = bevelSize + bevelOffset; 38915 38916 // Back facing vertices 38917 38918 for (let i = 0; i < vlen; i++) { 38919 38920 const vert = bevelEnabled ? scalePt2(vertices[i], verticesMovements[i], bs) : vertices[i]; 38921 38922 if (!extrudeByPath) { 38923 38924 v(vert.x, vert.y, 0); 38925 38926 } else { 38927 38928 // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); 38929 38930 normal.copy(splineTube.normals[0]).multiplyScalar(vert.x); 38931 binormal.copy(splineTube.binormals[0]).multiplyScalar(vert.y); 38932 38933 position2.copy(extrudePts[0]).add(normal).add(binormal); 38934 38935 v(position2.x, position2.y, position2.z); 38936 38937 } 38938 38939 } 38940 38941 // Add stepped vertices... 38942 // Including front facing vertices 38943 38944 for (let s = 1; s <= steps; s++) { 38945 38946 for (let i = 0; i < vlen; i++) { 38947 38948 const vert = bevelEnabled ? scalePt2(vertices[i], verticesMovements[i], bs) : vertices[i]; 38949 38950 if (!extrudeByPath) { 38951 38952 v(vert.x, vert.y, depth / steps * s); 38953 38954 } else { 38955 38956 // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); 38957 38958 normal.copy(splineTube.normals[s]).multiplyScalar(vert.x); 38959 binormal.copy(splineTube.binormals[s]).multiplyScalar(vert.y); 38960 38961 position2.copy(extrudePts[s]).add(normal).add(binormal); 38962 38963 v(position2.x, position2.y, position2.z); 38964 38965 } 38966 38967 } 38968 38969 } 38970 38971 38972 // Add bevel segments planes 38973 38974 //for ( b = 1; b <= bevelSegments; b ++ ) { 38975 for (let b = bevelSegments - 1; b >= 0; b--) { 38976 38977 const t = b / bevelSegments; 38978 const z = bevelThickness * Math.cos(t * Math.PI / 2); 38979 const bs = bevelSize * Math.sin(t * Math.PI / 2) + bevelOffset; 38980 38981 // contract shape 38982 38983 for (let i = 0, il = contour.length; i < il; i++) { 38984 38985 const vert = scalePt2(contour[i], contourMovements[i], bs); 38986 v(vert.x, vert.y, depth + z); 38987 38988 } 38989 38990 // expand holes 38991 38992 for (let h = 0, hl = holes.length; h < hl; h++) { 38993 38994 const ahole = holes[h]; 38995 oneHoleMovements = holesMovements[h]; 38996 38997 for (let i = 0, il = ahole.length; i < il; i++) { 38998 38999 const vert = scalePt2(ahole[i], oneHoleMovements[i], bs); 39000 39001 if (!extrudeByPath) { 39002 39003 v(vert.x, vert.y, depth + z); 39004 39005 } else { 39006 39007 v(vert.x, vert.y + extrudePts[steps - 1].y, extrudePts[steps - 1].x + z); 39008 39009 } 39010 39011 } 39012 39013 } 39014 39015 } 39016 39017 /* Faces */ 39018 39019 // Top and bottom faces 39020 39021 buildLidFaces(); 39022 39023 // Sides faces 39024 39025 buildSideFaces(); 39026 39027 39028 ///// Internal functions 39029 39030 function buildLidFaces() { 39031 39032 const start = verticesArray.length / 3; 39033 39034 if (bevelEnabled) { 39035 39036 let layer = 0; // steps + 1 39037 let offset = vlen * layer; 39038 39039 // Bottom faces 39040 39041 for (let i = 0; i < flen; i++) { 39042 39043 const face = faces[i]; 39044 f3(face[2] + offset, face[1] + offset, face[0] + offset); 39045 39046 } 39047 39048 layer = steps + bevelSegments * 2; 39049 offset = vlen * layer; 39050 39051 // Top faces 39052 39053 for (let i = 0; i < flen; i++) { 39054 39055 const face = faces[i]; 39056 f3(face[0] + offset, face[1] + offset, face[2] + offset); 39057 39058 } 39059 39060 } else { 39061 39062 // Bottom faces 39063 39064 for (let i = 0; i < flen; i++) { 39065 39066 const face = faces[i]; 39067 f3(face[2], face[1], face[0]); 39068 39069 } 39070 39071 // Top faces 39072 39073 for (let i = 0; i < flen; i++) { 39074 39075 const face = faces[i]; 39076 f3(face[0] + vlen * steps, face[1] + vlen * steps, face[2] + vlen * steps); 39077 39078 } 39079 39080 } 39081 39082 scope.addGroup(start, verticesArray.length / 3 - start, 0); 39083 39084 } 39085 39086 // Create faces for the z-sides of the shape 39087 39088 function buildSideFaces() { 39089 39090 const start = verticesArray.length / 3; 39091 let layeroffset = 0; 39092 sidewalls(contour, layeroffset); 39093 layeroffset += contour.length; 39094 39095 for (let h = 0, hl = holes.length; h < hl; h++) { 39096 39097 const ahole = holes[h]; 39098 sidewalls(ahole, layeroffset); 39099 39100 //, true 39101 layeroffset += ahole.length; 39102 39103 } 39104 39105 39106 scope.addGroup(start, verticesArray.length / 3 - start, 1); 39107 39108 39109 } 39110 39111 function sidewalls(contour, layeroffset) { 39112 39113 let i = contour.length; 39114 39115 while (--i >= 0) { 39116 39117 const j = i; 39118 let k = i - 1; 39119 if (k < 0) k = contour.length - 1; 39120 39121 //console.log('b', i,j, i-1, k,vertices.length); 39122 39123 for (let s = 0, sl = (steps + bevelSegments * 2); s < sl; s++) { 39124 39125 const slen1 = vlen * s; 39126 const slen2 = vlen * (s + 1); 39127 39128 const a = layeroffset + j + slen1, 39129 b = layeroffset + k + slen1, 39130 c = layeroffset + k + slen2, 39131 d = layeroffset + j + slen2; 39132 39133 f4(a, b, c, d); 39134 39135 } 39136 39137 } 39138 39139 } 39140 39141 function v(x, y, z) { 39142 39143 placeholder.push(x); 39144 placeholder.push(y); 39145 placeholder.push(z); 39146 39147 } 39148 39149 39150 function f3(a, b, c) { 39151 39152 addVertex(a); 39153 addVertex(b); 39154 addVertex(c); 39155 39156 const nextIndex = verticesArray.length / 3; 39157 const uvs = uvgen.generateTopUV(scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1); 39158 39159 addUV(uvs[0]); 39160 addUV(uvs[1]); 39161 addUV(uvs[2]); 39162 39163 } 39164 39165 function f4(a, b, c, d) { 39166 39167 addVertex(a); 39168 addVertex(b); 39169 addVertex(d); 39170 39171 addVertex(b); 39172 addVertex(c); 39173 addVertex(d); 39174 39175 39176 const nextIndex = verticesArray.length / 3; 39177 const uvs = uvgen.generateSideWallUV(scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1); 39178 39179 addUV(uvs[0]); 39180 addUV(uvs[1]); 39181 addUV(uvs[3]); 39182 39183 addUV(uvs[1]); 39184 addUV(uvs[2]); 39185 addUV(uvs[3]); 39186 39187 } 39188 39189 function addVertex(index) { 39190 39191 verticesArray.push(placeholder[index * 3 + 0]); 39192 verticesArray.push(placeholder[index * 3 + 1]); 39193 verticesArray.push(placeholder[index * 3 + 2]); 39194 39195 } 39196 39197 39198 function addUV(vector2) { 39199 39200 uvArray.push(vector2.x); 39201 uvArray.push(vector2.y); 39202 39203 } 39204 39205 } 39206 39207 } 39208 39209 copy(source) { 39210 39211 super.copy(source); 39212 39213 this.parameters = Object.assign({}, source.parameters); 39214 39215 return this; 39216 39217 } 39218 39219 toJSON() { 39220 39221 const data = super.toJSON(); 39222 39223 const shapes = this.parameters.shapes; 39224 const options = this.parameters.options; 39225 39226 return toJSON$1(shapes, options, data); 39227 39228 } 39229 39230 static fromJSON(data, shapes) { 39231 39232 const geometryShapes = []; 39233 39234 for (let j = 0, jl = data.shapes.length; j < jl; j++) { 39235 39236 const shape = shapes[data.shapes[j]]; 39237 39238 geometryShapes.push(shape); 39239 39240 } 39241 39242 const extrudePath = data.options.extrudePath; 39243 39244 if (extrudePath !== undefined) { 39245 39246 data.options.extrudePath = new Curves[extrudePath.type]().fromJSON(extrudePath); 39247 39248 } 39249 39250 return new ExtrudeGeometry(geometryShapes, data.options); 39251 39252 } 39253 39254} 39255 39256const WorldUVGenerator = { 39257 39258 generateTopUV: function (geometry, vertices, indexA, indexB, indexC) { 39259 39260 const a_x = vertices[indexA * 3]; 39261 const a_y = vertices[indexA * 3 + 1]; 39262 const b_x = vertices[indexB * 3]; 39263 const b_y = vertices[indexB * 3 + 1]; 39264 const c_x = vertices[indexC * 3]; 39265 const c_y = vertices[indexC * 3 + 1]; 39266 39267 return [ 39268 new Vector2(a_x, a_y), 39269 new Vector2(b_x, b_y), 39270 new Vector2(c_x, c_y) 39271 ]; 39272 39273 }, 39274 39275 generateSideWallUV: function (geometry, vertices, indexA, indexB, indexC, indexD) { 39276 39277 const a_x = vertices[indexA * 3]; 39278 const a_y = vertices[indexA * 3 + 1]; 39279 const a_z = vertices[indexA * 3 + 2]; 39280 const b_x = vertices[indexB * 3]; 39281 const b_y = vertices[indexB * 3 + 1]; 39282 const b_z = vertices[indexB * 3 + 2]; 39283 const c_x = vertices[indexC * 3]; 39284 const c_y = vertices[indexC * 3 + 1]; 39285 const c_z = vertices[indexC * 3 + 2]; 39286 const d_x = vertices[indexD * 3]; 39287 const d_y = vertices[indexD * 3 + 1]; 39288 const d_z = vertices[indexD * 3 + 2]; 39289 39290 if (Math.abs(a_y - b_y) < Math.abs(a_x - b_x)) { 39291 39292 return [ 39293 new Vector2(a_x, 1 - a_z), 39294 new Vector2(b_x, 1 - b_z), 39295 new Vector2(c_x, 1 - c_z), 39296 new Vector2(d_x, 1 - d_z) 39297 ]; 39298 39299 } else { 39300 39301 return [ 39302 new Vector2(a_y, 1 - a_z), 39303 new Vector2(b_y, 1 - b_z), 39304 new Vector2(c_y, 1 - c_z), 39305 new Vector2(d_y, 1 - d_z) 39306 ]; 39307 39308 } 39309 39310 } 39311 39312}; 39313 39314function toJSON$1(shapes, options, data) { 39315 39316 data.shapes = []; 39317 39318 if (Array.isArray(shapes)) { 39319 39320 for (let i = 0, l = shapes.length; i < l; i++) { 39321 39322 const shape = shapes[i]; 39323 39324 data.shapes.push(shape.uuid); 39325 39326 } 39327 39328 } else { 39329 39330 data.shapes.push(shapes.uuid); 39331 39332 } 39333 39334 data.options = Object.assign({}, options); 39335 39336 if (options.extrudePath !== undefined) data.options.extrudePath = options.extrudePath.toJSON(); 39337 39338 return data; 39339 39340} 39341 39342class IcosahedronGeometry extends PolyhedronGeometry { 39343 39344 constructor(radius = 1, detail = 0) { 39345 39346 const t = (1 + Math.sqrt(5)) / 2; 39347 39348 const vertices = [ 39349 - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0, 39350 0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 39351 t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1 39352 ]; 39353 39354 const indices = [ 39355 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11, 39356 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8, 39357 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9, 39358 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1 39359 ]; 39360 39361 super(vertices, indices, radius, detail); 39362 39363 this.type = 'IcosahedronGeometry'; 39364 39365 this.parameters = { 39366 radius: radius, 39367 detail: detail 39368 }; 39369 39370 } 39371 39372 static fromJSON(data) { 39373 39374 return new IcosahedronGeometry(data.radius, data.detail); 39375 39376 } 39377 39378} 39379 39380class OctahedronGeometry extends PolyhedronGeometry { 39381 39382 constructor(radius = 1, detail = 0) { 39383 39384 const vertices = [ 39385 1, 0, 0, - 1, 0, 0, 0, 1, 0, 39386 0, - 1, 0, 0, 0, 1, 0, 0, - 1 39387 ]; 39388 39389 const indices = [ 39390 0, 2, 4, 0, 4, 3, 0, 3, 5, 39391 0, 5, 2, 1, 2, 5, 1, 5, 3, 39392 1, 3, 4, 1, 4, 2 39393 ]; 39394 39395 super(vertices, indices, radius, detail); 39396 39397 this.type = 'OctahedronGeometry'; 39398 39399 this.parameters = { 39400 radius: radius, 39401 detail: detail 39402 }; 39403 39404 } 39405 39406 static fromJSON(data) { 39407 39408 return new OctahedronGeometry(data.radius, data.detail); 39409 39410 } 39411 39412} 39413 39414class RingGeometry extends BufferGeometry { 39415 39416 constructor(innerRadius = 0.5, outerRadius = 1, thetaSegments = 32, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2) { 39417 39418 super(); 39419 39420 this.type = 'RingGeometry'; 39421 39422 this.parameters = { 39423 innerRadius: innerRadius, 39424 outerRadius: outerRadius, 39425 thetaSegments: thetaSegments, 39426 phiSegments: phiSegments, 39427 thetaStart: thetaStart, 39428 thetaLength: thetaLength 39429 }; 39430 39431 thetaSegments = Math.max(3, thetaSegments); 39432 phiSegments = Math.max(1, phiSegments); 39433 39434 // buffers 39435 39436 const indices = []; 39437 const vertices = []; 39438 const normals = []; 39439 const uvs = []; 39440 39441 // some helper variables 39442 39443 let radius = innerRadius; 39444 const radiusStep = ((outerRadius - innerRadius) / phiSegments); 39445 const vertex = new Vector3(); 39446 const uv = new Vector2(); 39447 39448 // generate vertices, normals and uvs 39449 39450 for (let j = 0; j <= phiSegments; j++) { 39451 39452 for (let i = 0; i <= thetaSegments; i++) { 39453 39454 // values are generate from the inside of the ring to the outside 39455 39456 const segment = thetaStart + i / thetaSegments * thetaLength; 39457 39458 // vertex 39459 39460 vertex.x = radius * Math.cos(segment); 39461 vertex.y = radius * Math.sin(segment); 39462 39463 vertices.push(vertex.x, vertex.y, vertex.z); 39464 39465 // normal 39466 39467 normals.push(0, 0, 1); 39468 39469 // uv 39470 39471 uv.x = (vertex.x / outerRadius + 1) / 2; 39472 uv.y = (vertex.y / outerRadius + 1) / 2; 39473 39474 uvs.push(uv.x, uv.y); 39475 39476 } 39477 39478 // increase the radius for next row of vertices 39479 39480 radius += radiusStep; 39481 39482 } 39483 39484 // indices 39485 39486 for (let j = 0; j < phiSegments; j++) { 39487 39488 const thetaSegmentLevel = j * (thetaSegments + 1); 39489 39490 for (let i = 0; i < thetaSegments; i++) { 39491 39492 const segment = i + thetaSegmentLevel; 39493 39494 const a = segment; 39495 const b = segment + thetaSegments + 1; 39496 const c = segment + thetaSegments + 2; 39497 const d = segment + 1; 39498 39499 // faces 39500 39501 indices.push(a, b, d); 39502 indices.push(b, c, d); 39503 39504 } 39505 39506 } 39507 39508 // build geometry 39509 39510 this.setIndex(indices); 39511 this.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 39512 this.setAttribute('normal', new Float32BufferAttribute(normals, 3)); 39513 this.setAttribute('uv', new Float32BufferAttribute(uvs, 2)); 39514 39515 } 39516 39517 copy(source) { 39518 39519 super.copy(source); 39520 39521 this.parameters = Object.assign({}, source.parameters); 39522 39523 return this; 39524 39525 } 39526 39527 static fromJSON(data) { 39528 39529 return new RingGeometry(data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength); 39530 39531 } 39532 39533} 39534 39535class ShapeGeometry extends BufferGeometry { 39536 39537 constructor(shapes = new Shape([new Vector2(0, 0.5), new Vector2(- 0.5, - 0.5), new Vector2(0.5, - 0.5)]), curveSegments = 12) { 39538 39539 super(); 39540 39541 this.type = 'ShapeGeometry'; 39542 39543 this.parameters = { 39544 shapes: shapes, 39545 curveSegments: curveSegments 39546 }; 39547 39548 // buffers 39549 39550 const indices = []; 39551 const vertices = []; 39552 const normals = []; 39553 const uvs = []; 39554 39555 // helper variables 39556 39557 let groupStart = 0; 39558 let groupCount = 0; 39559 39560 // allow single and array values for "shapes" parameter 39561 39562 if (Array.isArray(shapes) === false) { 39563 39564 addShape(shapes); 39565 39566 } else { 39567 39568 for (let i = 0; i < shapes.length; i++) { 39569 39570 addShape(shapes[i]); 39571 39572 this.addGroup(groupStart, groupCount, i); // enables MultiMaterial support 39573 39574 groupStart += groupCount; 39575 groupCount = 0; 39576 39577 } 39578 39579 } 39580 39581 // build geometry 39582 39583 this.setIndex(indices); 39584 this.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 39585 this.setAttribute('normal', new Float32BufferAttribute(normals, 3)); 39586 this.setAttribute('uv', new Float32BufferAttribute(uvs, 2));
vendor: 4,428 bytes, lines 39587-39816
39587 39588 39589 // helper functions 39590 39591 function addShape(shape) { 39592 39593 const indexOffset = vertices.length / 3; 39594 const points = shape.extractPoints(curveSegments); 39595 39596 let shapeVertices = points.shape; 39597 const shapeHoles = points.holes; 39598 39599 // check direction of vertices 39600 39601 if (ShapeUtils.isClockWise(shapeVertices) === false) { 39602 39603 shapeVertices = shapeVertices.reverse(); 39604 39605 } 39606 39607 for (let i = 0, l = shapeHoles.length; i < l; i++) { 39608 39609 const shapeHole = shapeHoles[i]; 39610 39611 if (ShapeUtils.isClockWise(shapeHole) === true) { 39612 39613 shapeHoles[i] = shapeHole.reverse(); 39614 39615 } 39616 39617 } 39618 39619 const faces = ShapeUtils.triangulateShape(shapeVertices, shapeHoles); 39620 39621 // join vertices of inner and outer paths to a single array 39622 39623 for (let i = 0, l = shapeHoles.length; i < l; i++) { 39624 39625 const shapeHole = shapeHoles[i]; 39626 shapeVertices = shapeVertices.concat(shapeHole); 39627 39628 } 39629 39630 // vertices, normals, uvs 39631 39632 for (let i = 0, l = shapeVertices.length; i < l; i++) { 39633 39634 const vertex = shapeVertices[i]; 39635 39636 vertices.push(vertex.x, vertex.y, 0); 39637 normals.push(0, 0, 1); 39638 uvs.push(vertex.x, vertex.y); // world uvs 39639 39640 } 39641 39642 // indices 39643 39644 for (let i = 0, l = faces.length; i < l; i++) { 39645 39646 const face = faces[i]; 39647 39648 const a = face[0] + indexOffset; 39649 const b = face[1] + indexOffset; 39650 const c = face[2] + indexOffset; 39651 39652 indices.push(a, b, c); 39653 groupCount += 3; 39654 39655 } 39656 39657 } 39658 39659 } 39660 39661 copy(source) { 39662 39663 super.copy(source); 39664 39665 this.parameters = Object.assign({}, source.parameters); 39666 39667 return this; 39668 39669 } 39670 39671 toJSON() { 39672 39673 const data = super.toJSON(); 39674 39675 const shapes = this.parameters.shapes; 39676 39677 return toJSON(shapes, data); 39678 39679 } 39680 39681 static fromJSON(data, shapes) { 39682 39683 const geometryShapes = []; 39684 39685 for (let j = 0, jl = data.shapes.length; j < jl; j++) { 39686 39687 const shape = shapes[data.shapes[j]]; 39688 39689 geometryShapes.push(shape); 39690 39691 } 39692 39693 return new ShapeGeometry(geometryShapes, data.curveSegments); 39694 39695 } 39696 39697} 39698 39699function toJSON(shapes, data) { 39700 39701 data.shapes = []; 39702 39703 if (Array.isArray(shapes)) { 39704 39705 for (let i = 0, l = shapes.length; i < l; i++) { 39706 39707 const shape = shapes[i]; 39708 39709 data.shapes.push(shape.uuid); 39710 39711 } 39712 39713 } else { 39714 39715 data.shapes.push(shapes.uuid); 39716 39717 } 39718 39719 return data; 39720 39721} 39722 39723class SphereGeometry extends BufferGeometry { 39724 39725 constructor(radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI) { 39726 39727 super(); 39728 39729 this.type = 'SphereGeometry'; 39730 39731 this.parameters = { 39732 radius: radius, 39733 widthSegments: widthSegments, 39734 heightSegments: heightSegments, 39735 phiStart: phiStart, 39736 phiLength: phiLength, 39737 thetaStart: thetaStart, 39738 thetaLength: thetaLength 39739 }; 39740 39741 widthSegments = Math.max(3, Math.floor(widthSegments)); 39742 heightSegments = Math.max(2, Math.floor(heightSegments)); 39743 39744 const thetaEnd = Math.min(thetaStart + thetaLength, Math.PI); 39745 39746 let index = 0; 39747 const grid = []; 39748 39749 const vertex = new Vector3(); 39750 const normal = new Vector3(); 39751 39752 // buffers 39753 39754 const indices = []; 39755 const vertices = []; 39756 const normals = []; 39757 const uvs = []; 39758 39759 // generate vertices, normals and uvs 39760 39761 for (let iy = 0; iy <= heightSegments; iy++) { 39762 39763 const verticesRow = []; 39764 39765 const v = iy / heightSegments; 39766 39767 // special case for the poles 39768 39769 let uOffset = 0; 39770 39771 if (iy === 0 && thetaStart === 0) { 39772 39773 uOffset = 0.5 / widthSegments; 39774 39775 } else if (iy === heightSegments && thetaEnd === Math.PI) { 39776 39777 uOffset = - 0.5 / widthSegments; 39778 39779 } 39780 39781 for (let ix = 0; ix <= widthSegments; ix++) { 39782 39783 const u = ix / widthSegments; 39784 39785 // vertex 39786 39787 vertex.x = - radius * Math.cos(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength); 39788 vertex.y = radius * Math.cos(thetaStart + v * thetaLength); 39789 vertex.z = radius * Math.sin(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength); 39790 39791 vertices.push(vertex.x, vertex.y, vertex.z); 39792 39793 // normal 39794 39795 normal.copy(vertex).normalize(); 39796 normals.push(normal.x, normal.y, normal.z); 39797 39798 // uv 39799 39800 uvs.push(u + uOffset, 1 - v); 39801 39802 verticesRow.push(index++); 39803 39804 } 39805 39806 grid.push(verticesRow); 39807 39808 } 39809 39810 // indices 39811 39812 for (let iy = 0; iy < heightSegments; iy++) { 39813 39814 for (let ix = 0; ix < widthSegments; ix++) { 39815 39816 const a = grid[iy][ix + 1];
vendor: 7,187 bytes, lines 39817-40126
39817 const b = grid[iy][ix]; 39818 const c = grid[iy + 1][ix]; 39819 const d = grid[iy + 1][ix + 1]; 39820 39821 if (iy !== 0 || thetaStart > 0) indices.push(a, b, d); 39822 if (iy !== heightSegments - 1 || thetaEnd < Math.PI) indices.push(b, c, d); 39823 39824 } 39825 39826 } 39827 39828 // build geometry 39829 39830 this.setIndex(indices); 39831 this.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 39832 this.setAttribute('normal', new Float32BufferAttribute(normals, 3)); 39833 this.setAttribute('uv', new Float32BufferAttribute(uvs, 2)); 39834 39835 } 39836 39837 copy(source) { 39838 39839 super.copy(source); 39840 39841 this.parameters = Object.assign({}, source.parameters); 39842 39843 return this; 39844 39845 } 39846 39847 static fromJSON(data) { 39848 39849 return new SphereGeometry(data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength); 39850 39851 } 39852 39853} 39854 39855class TetrahedronGeometry extends PolyhedronGeometry { 39856 39857 constructor(radius = 1, detail = 0) { 39858 39859 const vertices = [ 39860 1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1 39861 ]; 39862 39863 const indices = [ 39864 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 39865 ]; 39866 39867 super(vertices, indices, radius, detail); 39868 39869 this.type = 'TetrahedronGeometry'; 39870 39871 this.parameters = { 39872 radius: radius, 39873 detail: detail 39874 }; 39875 39876 } 39877 39878 static fromJSON(data) { 39879 39880 return new TetrahedronGeometry(data.radius, data.detail); 39881 39882 } 39883 39884} 39885 39886class TorusGeometry extends BufferGeometry { 39887 39888 constructor(radius = 1, tube = 0.4, radialSegments = 12, tubularSegments = 48, arc = Math.PI * 2) { 39889 39890 super(); 39891 39892 this.type = 'TorusGeometry'; 39893 39894 this.parameters = { 39895 radius: radius, 39896 tube: tube, 39897 radialSegments: radialSegments, 39898 tubularSegments: tubularSegments, 39899 arc: arc 39900 }; 39901 39902 radialSegments = Math.floor(radialSegments); 39903 tubularSegments = Math.floor(tubularSegments); 39904 39905 // buffers 39906 39907 const indices = []; 39908 const vertices = []; 39909 const normals = []; 39910 const uvs = []; 39911 39912 // helper variables 39913 39914 const center = new Vector3(); 39915 const vertex = new Vector3(); 39916 const normal = new Vector3(); 39917 39918 // generate vertices, normals and uvs 39919 39920 for (let j = 0; j <= radialSegments; j++) { 39921 39922 for (let i = 0; i <= tubularSegments; i++) { 39923 39924 const u = i / tubularSegments * arc; 39925 const v = j / radialSegments * Math.PI * 2; 39926 39927 // vertex 39928 39929 vertex.x = (radius + tube * Math.cos(v)) * Math.cos(u); 39930 vertex.y = (radius + tube * Math.cos(v)) * Math.sin(u); 39931 vertex.z = tube * Math.sin(v); 39932 39933 vertices.push(vertex.x, vertex.y, vertex.z); 39934 39935 // normal 39936 39937 center.x = radius * Math.cos(u); 39938 center.y = radius * Math.sin(u); 39939 normal.subVectors(vertex, center).normalize(); 39940 39941 normals.push(normal.x, normal.y, normal.z); 39942 39943 // uv 39944 39945 uvs.push(i / tubularSegments); 39946 uvs.push(j / radialSegments); 39947 39948 } 39949 39950 } 39951 39952 // generate indices 39953 39954 for (let j = 1; j <= radialSegments; j++) { 39955 39956 for (let i = 1; i <= tubularSegments; i++) { 39957 39958 // indices 39959 39960 const a = (tubularSegments + 1) * j + i - 1; 39961 const b = (tubularSegments + 1) * (j - 1) + i - 1; 39962 const c = (tubularSegments + 1) * (j - 1) + i; 39963 const d = (tubularSegments + 1) * j + i; 39964 39965 // faces 39966 39967 indices.push(a, b, d); 39968 indices.push(b, c, d); 39969 39970 } 39971 39972 } 39973 39974 // build geometry 39975 39976 this.setIndex(indices); 39977 this.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 39978 this.setAttribute('normal', new Float32BufferAttribute(normals, 3)); 39979 this.setAttribute('uv', new Float32BufferAttribute(uvs, 2)); 39980 39981 } 39982 39983 copy(source) { 39984 39985 super.copy(source); 39986 39987 this.parameters = Object.assign({}, source.parameters); 39988 39989 return this; 39990 39991 } 39992 39993 static fromJSON(data) { 39994 39995 return new TorusGeometry(data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc); 39996 39997 } 39998 39999} 40000 40001class TorusKnotGeometry extends BufferGeometry { 40002 40003 constructor(radius = 1, tube = 0.4, tubularSegments = 64, radialSegments = 8, p = 2, q = 3) { 40004 40005 super(); 40006 40007 this.type = 'TorusKnotGeometry'; 40008 40009 this.parameters = { 40010 radius: radius, 40011 tube: tube, 40012 tubularSegments: tubularSegments, 40013 radialSegments: radialSegments, 40014 p: p, 40015 q: q 40016 }; 40017 40018 tubularSegments = Math.floor(tubularSegments); 40019 radialSegments = Math.floor(radialSegments); 40020 40021 // buffers 40022 40023 const indices = []; 40024 const vertices = []; 40025 const normals = []; 40026 const uvs = []; 40027 40028 // helper variables 40029 40030 const vertex = new Vector3(); 40031 const normal = new Vector3(); 40032 40033 const P1 = new Vector3(); 40034 const P2 = new Vector3(); 40035 40036 const B = new Vector3(); 40037 const T = new Vector3(); 40038 const N = new Vector3(); 40039 40040 // generate vertices, normals and uvs 40041 40042 for (let i = 0; i <= tubularSegments; ++i) { 40043 40044 // the radian "u" is used to calculate the position on the torus curve of the current tubular segment 40045 40046 const u = i / tubularSegments * p * Math.PI * 2; 40047 40048 // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead. 40049 // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions 40050 40051 calculatePositionOnCurve(u, p, q, radius, P1); 40052 calculatePositionOnCurve(u + 0.01, p, q, radius, P2); 40053 40054 // calculate orthonormal basis 40055 40056 T.subVectors(P2, P1); 40057 N.addVectors(P2, P1); 40058 B.crossVectors(T, N); 40059 N.crossVectors(B, T); 40060 40061 // normalize B, N. T can be ignored, we don't use it 40062 40063 B.normalize(); 40064 N.normalize(); 40065 40066 for (let j = 0; j <= radialSegments; ++j) { 40067 40068 // now calculate the vertices. they are nothing more than an extrusion of the torus curve. 40069 // because we extrude a shape in the xy-plane, there is no need to calculate a z-value. 40070 40071 const v = j / radialSegments * Math.PI * 2; 40072 const cx = - tube * Math.cos(v); 40073 const cy = tube * Math.sin(v); 40074 40075 // now calculate the final vertex position. 40076 // first we orient the extrusion with our basis vectors, then we add it to the current position on the curve 40077 40078 vertex.x = P1.x + (cx * N.x + cy * B.x); 40079 vertex.y = P1.y + (cx * N.y + cy * B.y); 40080 vertex.z = P1.z + (cx * N.z + cy * B.z); 40081 40082 vertices.push(vertex.x, vertex.y, vertex.z); 40083 40084 // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal) 40085 40086 normal.subVectors(vertex, P1).normalize(); 40087 40088 normals.push(normal.x, normal.y, normal.z); 40089 40090 // uv 40091 40092 uvs.push(i / tubularSegments); 40093 uvs.push(j / radialSegments); 40094 40095 } 40096 40097 } 40098 40099 // generate indices 40100 40101 for (let j = 1; j <= tubularSegments; j++) { 40102 40103 for (let i = 1; i <= radialSegments; i++) { 40104 40105 // indices 40106 40107 const a = (radialSegments + 1) * (j - 1) + (i - 1); 40108 const b = (radialSegments + 1) * j + (i - 1); 40109 const c = (radialSegments + 1) * j + i; 40110 const d = (radialSegments + 1) * (j - 1) + i; 40111 40112 // faces 40113 40114 indices.push(a, b, d); 40115 indices.push(b, c, d); 40116 40117 } 40118 40119 } 40120 40121 // build geometry 40122 40123 this.setIndex(indices); 40124 this.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 40125 this.setAttribute('normal', new Float32BufferAttribute(normals, 3)); 40126 this.setAttribute('uv', new Float32BufferAttribute(uvs, 2));
vendor: 42,316 bytes, lines 40127-42180
40127 40128 // this function calculates the current position on the torus curve 40129 40130 function calculatePositionOnCurve(u, p, q, radius, position) { 40131 40132 const cu = Math.cos(u); 40133 const su = Math.sin(u); 40134 const quOverP = q / p * u; 40135 const cs = Math.cos(quOverP); 40136 40137 position.x = radius * (2 + cs) * 0.5 * cu; 40138 position.y = radius * (2 + cs) * su * 0.5; 40139 position.z = radius * Math.sin(quOverP) * 0.5; 40140 40141 } 40142 40143 } 40144 40145 copy(source) { 40146 40147 super.copy(source); 40148 40149 this.parameters = Object.assign({}, source.parameters); 40150 40151 return this; 40152 40153 } 40154 40155 static fromJSON(data) { 40156 40157 return new TorusKnotGeometry(data.radius, data.tube, data.tubularSegments, data.radialSegments, data.p, data.q); 40158 40159 } 40160 40161} 40162 40163class TubeGeometry extends BufferGeometry { 40164 40165 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) { 40166 40167 super(); 40168 40169 this.type = 'TubeGeometry'; 40170 40171 this.parameters = { 40172 path: path, 40173 tubularSegments: tubularSegments, 40174 radius: radius, 40175 radialSegments: radialSegments, 40176 closed: closed 40177 }; 40178 40179 const frames = path.computeFrenetFrames(tubularSegments, closed); 40180 40181 // expose internals 40182 40183 this.tangents = frames.tangents; 40184 this.normals = frames.normals; 40185 this.binormals = frames.binormals; 40186 40187 // helper variables 40188 40189 const vertex = new Vector3(); 40190 const normal = new Vector3(); 40191 const uv = new Vector2(); 40192 let P = new Vector3(); 40193 40194 // buffer 40195 40196 const vertices = []; 40197 const normals = []; 40198 const uvs = []; 40199 const indices = []; 40200 40201 // create buffer data 40202 40203 generateBufferData(); 40204 40205 // build geometry 40206 40207 this.setIndex(indices); 40208 this.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 40209 this.setAttribute('normal', new Float32BufferAttribute(normals, 3)); 40210 this.setAttribute('uv', new Float32BufferAttribute(uvs, 2)); 40211 40212 // functions 40213 40214 function generateBufferData() { 40215 40216 for (let i = 0; i < tubularSegments; i++) { 40217 40218 generateSegment(i); 40219 40220 } 40221 40222 // if the geometry is not closed, generate the last row of vertices and normals 40223 // at the regular position on the given path 40224 // 40225 // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ) 40226 40227 generateSegment((closed === false) ? tubularSegments : 0); 40228 40229 // uvs are generated in a separate function. 40230 // this makes it easy compute correct values for closed geometries 40231 40232 generateUVs(); 40233 40234 // finally create faces 40235 40236 generateIndices(); 40237 40238 } 40239 40240 function generateSegment(i) { 40241 40242 // we use getPointAt to sample evenly distributed points from the given path 40243 40244 P = path.getPointAt(i / tubularSegments, P); 40245 40246 // retrieve corresponding normal and binormal 40247 40248 const N = frames.normals[i]; 40249 const B = frames.binormals[i]; 40250 40251 // generate normals and vertices for the current segment 40252 40253 for (let j = 0; j <= radialSegments; j++) { 40254 40255 const v = j / radialSegments * Math.PI * 2; 40256 40257 const sin = Math.sin(v); 40258 const cos = - Math.cos(v); 40259 40260 // normal 40261 40262 normal.x = (cos * N.x + sin * B.x); 40263 normal.y = (cos * N.y + sin * B.y); 40264 normal.z = (cos * N.z + sin * B.z); 40265 normal.normalize(); 40266 40267 normals.push(normal.x, normal.y, normal.z); 40268 40269 // vertex 40270 40271 vertex.x = P.x + radius * normal.x; 40272 vertex.y = P.y + radius * normal.y; 40273 vertex.z = P.z + radius * normal.z; 40274 40275 vertices.push(vertex.x, vertex.y, vertex.z); 40276 40277 } 40278 40279 } 40280 40281 function generateIndices() { 40282 40283 for (let j = 1; j <= tubularSegments; j++) { 40284 40285 for (let i = 1; i <= radialSegments; i++) { 40286 40287 const a = (radialSegments + 1) * (j - 1) + (i - 1); 40288 const b = (radialSegments + 1) * j + (i - 1); 40289 const c = (radialSegments + 1) * j + i; 40290 const d = (radialSegments + 1) * (j - 1) + i; 40291 40292 // faces 40293 40294 indices.push(a, b, d); 40295 indices.push(b, c, d); 40296 40297 } 40298 40299 } 40300 40301 } 40302 40303 function generateUVs() { 40304 40305 for (let i = 0; i <= tubularSegments; i++) { 40306 40307 for (let j = 0; j <= radialSegments; j++) { 40308 40309 uv.x = i / tubularSegments; 40310 uv.y = j / radialSegments; 40311 40312 uvs.push(uv.x, uv.y); 40313 40314 } 40315 40316 } 40317 40318 } 40319 40320 } 40321 40322 copy(source) { 40323 40324 super.copy(source); 40325 40326 this.parameters = Object.assign({}, source.parameters); 40327 40328 return this; 40329 40330 } 40331 40332 toJSON() { 40333 40334 const data = super.toJSON(); 40335 40336 data.path = this.parameters.path.toJSON(); 40337 40338 return data; 40339 40340 } 40341 40342 static fromJSON(data) { 40343 40344 // This only works for built-in curves (e.g. CatmullRomCurve3). 40345 // User defined curves or instances of CurvePath will not be deserialized. 40346 return new TubeGeometry( 40347 new Curves[data.path.type]().fromJSON(data.path), 40348 data.tubularSegments, 40349 data.radius, 40350 data.radialSegments, 40351 data.closed 40352 ); 40353 40354 } 40355 40356} 40357 40358class WireframeGeometry extends BufferGeometry { 40359 40360 constructor(geometry = null) { 40361 40362 super(); 40363 40364 this.type = 'WireframeGeometry'; 40365 40366 this.parameters = { 40367 geometry: geometry 40368 }; 40369 40370 if (geometry !== null) { 40371 40372 // buffer 40373 40374 const vertices = []; 40375 const edges = new Set(); 40376 40377 // helper variables 40378 40379 const start = new Vector3(); 40380 const end = new Vector3(); 40381 40382 if (geometry.index !== null) { 40383 40384 // indexed BufferGeometry 40385 40386 const position = geometry.attributes.position; 40387 const indices = geometry.index; 40388 let groups = geometry.groups; 40389 40390 if (groups.length === 0) { 40391 40392 groups = [{ start: 0, count: indices.count, materialIndex: 0 }]; 40393 40394 } 40395 40396 // create a data structure that contains all edges without duplicates 40397 40398 for (let o = 0, ol = groups.length; o < ol; ++o) { 40399 40400 const group = groups[o]; 40401 40402 const groupStart = group.start; 40403 const groupCount = group.count; 40404 40405 for (let i = groupStart, l = (groupStart + groupCount); i < l; i += 3) { 40406 40407 for (let j = 0; j < 3; j++) { 40408 40409 const index1 = indices.getX(i + j); 40410 const index2 = indices.getX(i + (j + 1) % 3); 40411 40412 start.fromBufferAttribute(position, index1); 40413 end.fromBufferAttribute(position, index2); 40414 40415 if (isUniqueEdge(start, end, edges) === true) { 40416 40417 vertices.push(start.x, start.y, start.z); 40418 vertices.push(end.x, end.y, end.z); 40419 40420 } 40421 40422 } 40423 40424 } 40425 40426 } 40427 40428 } else { 40429 40430 // non-indexed BufferGeometry 40431 40432 const position = geometry.attributes.position; 40433 40434 for (let i = 0, l = (position.count / 3); i < l; i++) { 40435 40436 for (let j = 0; j < 3; j++) { 40437 40438 // three edges per triangle, an edge is represented as (index1, index2) 40439 // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0) 40440 40441 const index1 = 3 * i + j; 40442 const index2 = 3 * i + ((j + 1) % 3); 40443 40444 start.fromBufferAttribute(position, index1); 40445 end.fromBufferAttribute(position, index2); 40446 40447 if (isUniqueEdge(start, end, edges) === true) { 40448 40449 vertices.push(start.x, start.y, start.z); 40450 vertices.push(end.x, end.y, end.z); 40451 40452 } 40453 40454 } 40455 40456 } 40457 40458 } 40459 40460 // build geometry 40461 40462 this.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 40463 40464 } 40465 40466 } 40467 40468 copy(source) { 40469 40470 super.copy(source); 40471 40472 this.parameters = Object.assign({}, source.parameters); 40473 40474 return this; 40475 40476 } 40477 40478} 40479 40480function isUniqueEdge(start, end, edges) { 40481 40482 const hash1 = `${start.x},${start.y},${start.z}-${end.x},${end.y},${end.z}`; 40483 const hash2 = `${end.x},${end.y},${end.z}-${start.x},${start.y},${start.z}`; // coincident edge 40484 40485 if (edges.has(hash1) === true || edges.has(hash2) === true) { 40486 40487 return false; 40488 40489 } else { 40490 40491 edges.add(hash1); 40492 edges.add(hash2); 40493 return true; 40494 40495 } 40496 40497} 40498 40499var Geometries = /*#__PURE__*/Object.freeze({ 40500 __proto__: null, 40501 BoxGeometry: BoxGeometry, 40502 CapsuleGeometry: CapsuleGeometry, 40503 CircleGeometry: CircleGeometry, 40504 ConeGeometry: ConeGeometry, 40505 CylinderGeometry: CylinderGeometry, 40506 DodecahedronGeometry: DodecahedronGeometry, 40507 EdgesGeometry: EdgesGeometry, 40508 ExtrudeGeometry: ExtrudeGeometry, 40509 IcosahedronGeometry: IcosahedronGeometry, 40510 LatheGeometry: LatheGeometry, 40511 OctahedronGeometry: OctahedronGeometry, 40512 PlaneGeometry: PlaneGeometry, 40513 PolyhedronGeometry: PolyhedronGeometry, 40514 RingGeometry: RingGeometry, 40515 ShapeGeometry: ShapeGeometry, 40516 SphereGeometry: SphereGeometry, 40517 TetrahedronGeometry: TetrahedronGeometry, 40518 TorusGeometry: TorusGeometry, 40519 TorusKnotGeometry: TorusKnotGeometry, 40520 TubeGeometry: TubeGeometry, 40521 WireframeGeometry: WireframeGeometry 40522}); 40523 40524class ShadowMaterial extends Material { 40525 40526 constructor(parameters) { 40527 40528 super(); 40529 40530 this.isShadowMaterial = true; 40531 40532 this.type = 'ShadowMaterial'; 40533 40534 this.color = new Color(0x000000); 40535 this.transparent = true; 40536 40537 this.fog = true; 40538 40539 this.setValues(parameters); 40540 40541 } 40542 40543 copy(source) { 40544 40545 super.copy(source); 40546 40547 this.color.copy(source.color); 40548 40549 this.fog = source.fog; 40550 40551 return this; 40552 40553 } 40554 40555} 40556 40557class RawShaderMaterial extends ShaderMaterial { 40558 40559 constructor(parameters) { 40560 40561 super(parameters); 40562 40563 this.isRawShaderMaterial = true; 40564 40565 this.type = 'RawShaderMaterial'; 40566 40567 } 40568 40569} 40570 40571class MeshStandardMaterial extends Material { 40572 40573 constructor(parameters) { 40574 40575 super(); 40576 40577 this.isMeshStandardMaterial = true; 40578 40579 this.defines = { 'STANDARD': '' }; 40580 40581 this.type = 'MeshStandardMaterial'; 40582 40583 this.color = new Color(0xffffff); // diffuse 40584 this.roughness = 1.0; 40585 this.metalness = 0.0; 40586 40587 this.map = null; 40588 40589 this.lightMap = null; 40590 this.lightMapIntensity = 1.0; 40591 40592 this.aoMap = null; 40593 this.aoMapIntensity = 1.0; 40594 40595 this.emissive = new Color(0x000000); 40596 this.emissiveIntensity = 1.0; 40597 this.emissiveMap = null; 40598 40599 this.bumpMap = null; 40600 this.bumpScale = 1; 40601 40602 this.normalMap = null; 40603 this.normalMapType = TangentSpaceNormalMap; 40604 this.normalScale = new Vector2(1, 1); 40605 40606 this.displacementMap = null; 40607 this.displacementScale = 1; 40608 this.displacementBias = 0; 40609 40610 this.roughnessMap = null; 40611 40612 this.metalnessMap = null; 40613 40614 this.alphaMap = null; 40615 40616 this.envMap = null; 40617 this.envMapIntensity = 1.0; 40618 40619 this.wireframe = false; 40620 this.wireframeLinewidth = 1; 40621 this.wireframeLinecap = 'round'; 40622 this.wireframeLinejoin = 'round'; 40623 40624 this.flatShading = false; 40625 40626 this.fog = true; 40627 40628 this.setValues(parameters); 40629 40630 } 40631 40632 copy(source) { 40633 40634 super.copy(source); 40635 40636 this.defines = { 'STANDARD': '' }; 40637 40638 this.color.copy(source.color); 40639 this.roughness = source.roughness; 40640 this.metalness = source.metalness; 40641 40642 this.map = source.map; 40643 40644 this.lightMap = source.lightMap; 40645 this.lightMapIntensity = source.lightMapIntensity; 40646 40647 this.aoMap = source.aoMap; 40648 this.aoMapIntensity = source.aoMapIntensity; 40649 40650 this.emissive.copy(source.emissive); 40651 this.emissiveMap = source.emissiveMap; 40652 this.emissiveIntensity = source.emissiveIntensity; 40653 40654 this.bumpMap = source.bumpMap; 40655 this.bumpScale = source.bumpScale; 40656 40657 this.normalMap = source.normalMap; 40658 this.normalMapType = source.normalMapType; 40659 this.normalScale.copy(source.normalScale); 40660 40661 this.displacementMap = source.displacementMap; 40662 this.displacementScale = source.displacementScale; 40663 this.displacementBias = source.displacementBias; 40664 40665 this.roughnessMap = source.roughnessMap; 40666 40667 this.metalnessMap = source.metalnessMap; 40668 40669 this.alphaMap = source.alphaMap; 40670 40671 this.envMap = source.envMap; 40672 this.envMapIntensity = source.envMapIntensity; 40673 40674 this.wireframe = source.wireframe; 40675 this.wireframeLinewidth = source.wireframeLinewidth; 40676 this.wireframeLinecap = source.wireframeLinecap; 40677 this.wireframeLinejoin = source.wireframeLinejoin; 40678 40679 this.flatShading = source.flatShading; 40680 40681 this.fog = source.fog; 40682 40683 return this; 40684 40685 } 40686 40687} 40688 40689class MeshPhysicalMaterial extends MeshStandardMaterial { 40690 40691 constructor(parameters) { 40692 40693 super(); 40694 40695 this.isMeshPhysicalMaterial = true; 40696 40697 this.defines = { 40698 40699 'STANDARD': '', 40700 'PHYSICAL': '' 40701 40702 }; 40703 40704 this.type = 'MeshPhysicalMaterial'; 40705 40706 this.anisotropyRotation = 0; 40707 this.anisotropyMap = null; 40708 40709 this.clearcoatMap = null; 40710 this.clearcoatRoughness = 0.0; 40711 this.clearcoatRoughnessMap = null; 40712 this.clearcoatNormalScale = new Vector2(1, 1); 40713 this.clearcoatNormalMap = null; 40714 40715 this.ior = 1.5; 40716 40717 Object.defineProperty(this, 'reflectivity', { 40718 get: function () { 40719 40720 return (clamp(2.5 * (this.ior - 1) / (this.ior + 1), 0, 1)); 40721 40722 }, 40723 set: function (reflectivity) { 40724 40725 this.ior = (1 + 0.4 * reflectivity) / (1 - 0.4 * reflectivity); 40726 40727 } 40728 }); 40729 40730 this.iridescenceMap = null; 40731 this.iridescenceIOR = 1.3; 40732 this.iridescenceThicknessRange = [100, 400]; 40733 this.iridescenceThicknessMap = null; 40734 40735 this.sheenColor = new Color(0x000000); 40736 this.sheenColorMap = null; 40737 this.sheenRoughness = 1.0; 40738 this.sheenRoughnessMap = null; 40739 40740 this.transmissionMap = null; 40741 40742 this.thickness = 0; 40743 this.thicknessMap = null; 40744 this.attenuationDistance = Infinity; 40745 this.attenuationColor = new Color(1, 1, 1); 40746 40747 this.specularIntensity = 1.0; 40748 this.specularIntensityMap = null; 40749 this.specularColor = new Color(1, 1, 1); 40750 this.specularColorMap = null; 40751 40752 this._anisotropy = 0; 40753 this._clearcoat = 0; 40754 this._iridescence = 0; 40755 this._sheen = 0.0; 40756 this._transmission = 0; 40757 40758 this.setValues(parameters); 40759 40760 } 40761 40762 get anisotropy() { 40763 40764 return this._anisotropy; 40765 40766 } 40767 40768 set anisotropy(value) { 40769 40770 if (this._anisotropy > 0 !== value > 0) { 40771 40772 this.version++; 40773 40774 } 40775 40776 this._anisotropy = value; 40777 40778 } 40779 40780 get clearcoat() { 40781 40782 return this._clearcoat; 40783 40784 } 40785 40786 set clearcoat(value) { 40787 40788 if (this._clearcoat > 0 !== value > 0) { 40789 40790 this.version++; 40791 40792 } 40793 40794 this._clearcoat = value; 40795 40796 } 40797 40798 get iridescence() { 40799 40800 return this._iridescence; 40801 40802 } 40803 40804 set iridescence(value) { 40805 40806 if (this._iridescence > 0 !== value > 0) { 40807 40808 this.version++; 40809 40810 } 40811 40812 this._iridescence = value; 40813 40814 } 40815 40816 get sheen() { 40817 40818 return this._sheen; 40819 40820 } 40821 40822 set sheen(value) { 40823 40824 if (this._sheen > 0 !== value > 0) { 40825 40826 this.version++; 40827 40828 } 40829 40830 this._sheen = value; 40831 40832 } 40833 40834 get transmission() { 40835 40836 return this._transmission; 40837 40838 } 40839 40840 set transmission(value) { 40841 40842 if (this._transmission > 0 !== value > 0) { 40843 40844 this.version++; 40845 40846 } 40847 40848 this._transmission = value; 40849 40850 } 40851 40852 copy(source) { 40853 40854 super.copy(source); 40855 40856 this.defines = { 40857 40858 'STANDARD': '', 40859 'PHYSICAL': '' 40860 40861 }; 40862 40863 this.anisotropy = source.anisotropy; 40864 this.anisotropyRotation = source.anisotropyRotation; 40865 this.anisotropyMap = source.anisotropyMap; 40866 40867 this.clearcoat = source.clearcoat; 40868 this.clearcoatMap = source.clearcoatMap; 40869 this.clearcoatRoughness = source.clearcoatRoughness; 40870 this.clearcoatRoughnessMap = source.clearcoatRoughnessMap; 40871 this.clearcoatNormalMap = source.clearcoatNormalMap; 40872 this.clearcoatNormalScale.copy(source.clearcoatNormalScale); 40873 40874 this.ior = source.ior; 40875 40876 this.iridescence = source.iridescence; 40877 this.iridescenceMap = source.iridescenceMap; 40878 this.iridescenceIOR = source.iridescenceIOR; 40879 this.iridescenceThicknessRange = [...source.iridescenceThicknessRange]; 40880 this.iridescenceThicknessMap = source.iridescenceThicknessMap; 40881 40882 this.sheen = source.sheen; 40883 this.sheenColor.copy(source.sheenColor); 40884 this.sheenColorMap = source.sheenColorMap; 40885 this.sheenRoughness = source.sheenRoughness; 40886 this.sheenRoughnessMap = source.sheenRoughnessMap; 40887 40888 this.transmission = source.transmission; 40889 this.transmissionMap = source.transmissionMap; 40890 40891 this.thickness = source.thickness; 40892 this.thicknessMap = source.thicknessMap; 40893 this.attenuationDistance = source.attenuationDistance; 40894 this.attenuationColor.copy(source.attenuationColor); 40895 40896 this.specularIntensity = source.specularIntensity; 40897 this.specularIntensityMap = source.specularIntensityMap; 40898 this.specularColor.copy(source.specularColor); 40899 this.specularColorMap = source.specularColorMap; 40900 40901 return this; 40902 40903 } 40904 40905} 40906 40907class MeshPhongMaterial extends Material { 40908 40909 constructor(parameters) { 40910 40911 super(); 40912 40913 this.isMeshPhongMaterial = true; 40914 40915 this.type = 'MeshPhongMaterial'; 40916 40917 this.color = new Color(0xffffff); // diffuse 40918 this.specular = new Color(0x111111); 40919 this.shininess = 30; 40920 40921 this.map = null; 40922 40923 this.lightMap = null; 40924 this.lightMapIntensity = 1.0; 40925 40926 this.aoMap = null; 40927 this.aoMapIntensity = 1.0; 40928 40929 this.emissive = new Color(0x000000); 40930 this.emissiveIntensity = 1.0; 40931 this.emissiveMap = null; 40932 40933 this.bumpMap = null; 40934 this.bumpScale = 1; 40935 40936 this.normalMap = null; 40937 this.normalMapType = TangentSpaceNormalMap; 40938 this.normalScale = new Vector2(1, 1); 40939 40940 this.displacementMap = null; 40941 this.displacementScale = 1; 40942 this.displacementBias = 0; 40943 40944 this.specularMap = null; 40945 40946 this.alphaMap = null; 40947 40948 this.envMap = null; 40949 this.combine = MultiplyOperation; 40950 this.reflectivity = 1; 40951 this.refractionRatio = 0.98; 40952 40953 this.wireframe = false; 40954 this.wireframeLinewidth = 1; 40955 this.wireframeLinecap = 'round'; 40956 this.wireframeLinejoin = 'round'; 40957 40958 this.flatShading = false; 40959 40960 this.fog = true; 40961 40962 this.setValues(parameters); 40963 40964 } 40965 40966 copy(source) { 40967 40968 super.copy(source); 40969 40970 this.color.copy(source.color); 40971 this.specular.copy(source.specular); 40972 this.shininess = source.shininess; 40973 40974 this.map = source.map; 40975 40976 this.lightMap = source.lightMap; 40977 this.lightMapIntensity = source.lightMapIntensity; 40978 40979 this.aoMap = source.aoMap; 40980 this.aoMapIntensity = source.aoMapIntensity; 40981 40982 this.emissive.copy(source.emissive); 40983 this.emissiveMap = source.emissiveMap; 40984 this.emissiveIntensity = source.emissiveIntensity; 40985 40986 this.bumpMap = source.bumpMap; 40987 this.bumpScale = source.bumpScale; 40988 40989 this.normalMap = source.normalMap; 40990 this.normalMapType = source.normalMapType; 40991 this.normalScale.copy(source.normalScale); 40992 40993 this.displacementMap = source.displacementMap; 40994 this.displacementScale = source.displacementScale; 40995 this.displacementBias = source.displacementBias; 40996 40997 this.specularMap = source.specularMap; 40998 40999 this.alphaMap = source.alphaMap; 41000 41001 this.envMap = source.envMap; 41002 this.combine = source.combine; 41003 this.reflectivity = source.reflectivity; 41004 this.refractionRatio = source.refractionRatio; 41005 41006 this.wireframe = source.wireframe; 41007 this.wireframeLinewidth = source.wireframeLinewidth; 41008 this.wireframeLinecap = source.wireframeLinecap; 41009 this.wireframeLinejoin = source.wireframeLinejoin; 41010 41011 this.flatShading = source.flatShading; 41012 41013 this.fog = source.fog; 41014 41015 return this; 41016 41017 } 41018 41019} 41020 41021class MeshToonMaterial extends Material { 41022 41023 constructor(parameters) { 41024 41025 super(); 41026 41027 this.isMeshToonMaterial = true; 41028 41029 this.defines = { 'TOON': '' }; 41030 41031 this.type = 'MeshToonMaterial'; 41032 41033 this.color = new Color(0xffffff); 41034 41035 this.map = null; 41036 this.gradientMap = null; 41037 41038 this.lightMap = null; 41039 this.lightMapIntensity = 1.0; 41040 41041 this.aoMap = null; 41042 this.aoMapIntensity = 1.0; 41043 41044 this.emissive = new Color(0x000000); 41045 this.emissiveIntensity = 1.0; 41046 this.emissiveMap = null; 41047 41048 this.bumpMap = null; 41049 this.bumpScale = 1; 41050 41051 this.normalMap = null; 41052 this.normalMapType = TangentSpaceNormalMap; 41053 this.normalScale = new Vector2(1, 1); 41054 41055 this.displacementMap = null; 41056 this.displacementScale = 1; 41057 this.displacementBias = 0; 41058 41059 this.alphaMap = null; 41060 41061 this.wireframe = false; 41062 this.wireframeLinewidth = 1; 41063 this.wireframeLinecap = 'round'; 41064 this.wireframeLinejoin = 'round'; 41065 41066 this.fog = true; 41067 41068 this.setValues(parameters); 41069 41070 } 41071 41072 copy(source) { 41073 41074 super.copy(source); 41075 41076 this.color.copy(source.color); 41077 41078 this.map = source.map; 41079 this.gradientMap = source.gradientMap; 41080 41081 this.lightMap = source.lightMap; 41082 this.lightMapIntensity = source.lightMapIntensity; 41083 41084 this.aoMap = source.aoMap; 41085 this.aoMapIntensity = source.aoMapIntensity; 41086 41087 this.emissive.copy(source.emissive); 41088 this.emissiveMap = source.emissiveMap; 41089 this.emissiveIntensity = source.emissiveIntensity; 41090 41091 this.bumpMap = source.bumpMap; 41092 this.bumpScale = source.bumpScale; 41093 41094 this.normalMap = source.normalMap; 41095 this.normalMapType = source.normalMapType; 41096 this.normalScale.copy(source.normalScale); 41097 41098 this.displacementMap = source.displacementMap; 41099 this.displacementScale = source.displacementScale; 41100 this.displacementBias = source.displacementBias; 41101 41102 this.alphaMap = source.alphaMap; 41103 41104 this.wireframe = source.wireframe; 41105 this.wireframeLinewidth = source.wireframeLinewidth; 41106 this.wireframeLinecap = source.wireframeLinecap; 41107 this.wireframeLinejoin = source.wireframeLinejoin; 41108 41109 this.fog = source.fog; 41110 41111 return this; 41112 41113 } 41114 41115} 41116 41117class MeshNormalMaterial extends Material { 41118 41119 constructor(parameters) { 41120 41121 super(); 41122 41123 this.isMeshNormalMaterial = true; 41124 41125 this.type = 'MeshNormalMaterial'; 41126 41127 this.bumpMap = null; 41128 this.bumpScale = 1; 41129 41130 this.normalMap = null; 41131 this.normalMapType = TangentSpaceNormalMap; 41132 this.normalScale = new Vector2(1, 1); 41133 41134 this.displacementMap = null; 41135 this.displacementScale = 1; 41136 this.displacementBias = 0; 41137 41138 this.wireframe = false; 41139 this.wireframeLinewidth = 1; 41140 41141 this.flatShading = false; 41142 41143 this.setValues(parameters); 41144 41145 } 41146 41147 copy(source) { 41148 41149 super.copy(source); 41150 41151 this.bumpMap = source.bumpMap; 41152 this.bumpScale = source.bumpScale; 41153 41154 this.normalMap = source.normalMap; 41155 this.normalMapType = source.normalMapType; 41156 this.normalScale.copy(source.normalScale); 41157 41158 this.displacementMap = source.displacementMap; 41159 this.displacementScale = source.displacementScale; 41160 this.displacementBias = source.displacementBias; 41161 41162 this.wireframe = source.wireframe; 41163 this.wireframeLinewidth = source.wireframeLinewidth; 41164 41165 this.flatShading = source.flatShading; 41166 41167 return this; 41168 41169 } 41170 41171} 41172 41173class MeshLambertMaterial extends Material { 41174 41175 constructor(parameters) { 41176 41177 super(); 41178 41179 this.isMeshLambertMaterial = true; 41180 41181 this.type = 'MeshLambertMaterial'; 41182 41183 this.color = new Color(0xffffff); // diffuse 41184 41185 this.map = null; 41186 41187 this.lightMap = null; 41188 this.lightMapIntensity = 1.0; 41189 41190 this.aoMap = null; 41191 this.aoMapIntensity = 1.0; 41192 41193 this.emissive = new Color(0x000000); 41194 this.emissiveIntensity = 1.0; 41195 this.emissiveMap = null; 41196 41197 this.bumpMap = null; 41198 this.bumpScale = 1; 41199 41200 this.normalMap = null; 41201 this.normalMapType = TangentSpaceNormalMap; 41202 this.normalScale = new Vector2(1, 1); 41203 41204 this.displacementMap = null; 41205 this.displacementScale = 1; 41206 this.displacementBias = 0; 41207 41208 this.specularMap = null; 41209 41210 this.alphaMap = null; 41211 41212 this.envMap = null; 41213 this.combine = MultiplyOperation; 41214 this.reflectivity = 1; 41215 this.refractionRatio = 0.98; 41216 41217 this.wireframe = false; 41218 this.wireframeLinewidth = 1; 41219 this.wireframeLinecap = 'round'; 41220 this.wireframeLinejoin = 'round'; 41221 41222 this.flatShading = false; 41223 41224 this.fog = true; 41225 41226 this.setValues(parameters); 41227 41228 } 41229 41230 copy(source) { 41231 41232 super.copy(source); 41233 41234 this.color.copy(source.color); 41235 41236 this.map = source.map; 41237 41238 this.lightMap = source.lightMap; 41239 this.lightMapIntensity = source.lightMapIntensity; 41240 41241 this.aoMap = source.aoMap; 41242 this.aoMapIntensity = source.aoMapIntensity; 41243 41244 this.emissive.copy(source.emissive); 41245 this.emissiveMap = source.emissiveMap; 41246 this.emissiveIntensity = source.emissiveIntensity; 41247 41248 this.bumpMap = source.bumpMap; 41249 this.bumpScale = source.bumpScale; 41250 41251 this.normalMap = source.normalMap; 41252 this.normalMapType = source.normalMapType; 41253 this.normalScale.copy(source.normalScale); 41254 41255 this.displacementMap = source.displacementMap; 41256 this.displacementScale = source.displacementScale; 41257 this.displacementBias = source.displacementBias; 41258 41259 this.specularMap = source.specularMap; 41260 41261 this.alphaMap = source.alphaMap; 41262 41263 this.envMap = source.envMap; 41264 this.combine = source.combine; 41265 this.reflectivity = source.reflectivity; 41266 this.refractionRatio = source.refractionRatio; 41267 41268 this.wireframe = source.wireframe; 41269 this.wireframeLinewidth = source.wireframeLinewidth; 41270 this.wireframeLinecap = source.wireframeLinecap; 41271 this.wireframeLinejoin = source.wireframeLinejoin; 41272 41273 this.flatShading = source.flatShading; 41274 41275 this.fog = source.fog; 41276 41277 return this; 41278 41279 } 41280 41281} 41282 41283class MeshMatcapMaterial extends Material { 41284 41285 constructor(parameters) { 41286 41287 super(); 41288 41289 this.isMeshMatcapMaterial = true; 41290 41291 this.defines = { 'MATCAP': '' }; 41292 41293 this.type = 'MeshMatcapMaterial'; 41294 41295 this.color = new Color(0xffffff); // diffuse 41296 41297 this.matcap = null; 41298 41299 this.map = null; 41300 41301 this.bumpMap = null; 41302 this.bumpScale = 1; 41303 41304 this.normalMap = null; 41305 this.normalMapType = TangentSpaceNormalMap; 41306 this.normalScale = new Vector2(1, 1); 41307 41308 this.displacementMap = null; 41309 this.displacementScale = 1; 41310 this.displacementBias = 0; 41311 41312 this.alphaMap = null; 41313 41314 this.flatShading = false; 41315 41316 this.fog = true; 41317 41318 this.setValues(parameters); 41319 41320 } 41321 41322 41323 copy(source) { 41324 41325 super.copy(source); 41326 41327 this.defines = { 'MATCAP': '' }; 41328 41329 this.color.copy(source.color); 41330 41331 this.matcap = source.matcap; 41332 41333 this.map = source.map; 41334 41335 this.bumpMap = source.bumpMap; 41336 this.bumpScale = source.bumpScale; 41337 41338 this.normalMap = source.normalMap; 41339 this.normalMapType = source.normalMapType; 41340 this.normalScale.copy(source.normalScale); 41341 41342 this.displacementMap = source.displacementMap; 41343 this.displacementScale = source.displacementScale; 41344 this.displacementBias = source.displacementBias; 41345 41346 this.alphaMap = source.alphaMap; 41347 41348 this.flatShading = source.flatShading; 41349 41350 this.fog = source.fog; 41351 41352 return this; 41353 41354 } 41355 41356} 41357 41358class LineDashedMaterial extends LineBasicMaterial { 41359 41360 constructor(parameters) { 41361 41362 super(); 41363 41364 this.isLineDashedMaterial = true; 41365 41366 this.type = 'LineDashedMaterial'; 41367 41368 this.scale = 1; 41369 this.dashSize = 3; 41370 this.gapSize = 1; 41371 41372 this.setValues(parameters); 41373 41374 } 41375 41376 copy(source) { 41377 41378 super.copy(source); 41379 41380 this.scale = source.scale; 41381 this.dashSize = source.dashSize; 41382 this.gapSize = source.gapSize; 41383 41384 return this; 41385 41386 } 41387 41388} 41389 41390// converts an array to a specific type 41391function convertArray(array, type, forceClone) { 41392 41393 if (!array || // let 'undefined' and 'null' pass 41394 !forceClone && array.constructor === type) return array; 41395 41396 if (typeof type.BYTES_PER_ELEMENT === 'number') { 41397 41398 return new type(array); // create typed array 41399 41400 } 41401 41402 return Array.prototype.slice.call(array); // create Array 41403 41404} 41405 41406function isTypedArray(object) { 41407 41408 return ArrayBuffer.isView(object) && 41409 !(object instanceof DataView); 41410 41411} 41412 41413// returns an array by which times and values can be sorted 41414function getKeyframeOrder(times) { 41415 41416 function compareTime(i, j) { 41417 41418 return times[i] - times[j]; 41419 41420 } 41421 41422 const n = times.length; 41423 const result = new Array(n); 41424 for (let i = 0; i !== n; ++i) result[i] = i; 41425 41426 result.sort(compareTime); 41427 41428 return result; 41429 41430} 41431 41432// uses the array previously returned by 'getKeyframeOrder' to sort data 41433function sortedArray(values, stride, order) { 41434 41435 const nValues = values.length; 41436 const result = new values.constructor(nValues); 41437 41438 for (let i = 0, dstOffset = 0; dstOffset !== nValues; ++i) { 41439 41440 const srcOffset = order[i] * stride; 41441 41442 for (let j = 0; j !== stride; ++j) { 41443 41444 result[dstOffset++] = values[srcOffset + j]; 41445 41446 } 41447 41448 } 41449 41450 return result; 41451 41452} 41453 41454// function for parsing AOS keyframe formats 41455function flattenJSON(jsonKeys, times, values, valuePropertyName) { 41456 41457 let i = 1, key = jsonKeys[0]; 41458 41459 while (key !== undefined && key[valuePropertyName] === undefined) { 41460 41461 key = jsonKeys[i++]; 41462 41463 } 41464 41465 if (key === undefined) return; // no data 41466 41467 let value = key[valuePropertyName]; 41468 if (value === undefined) return; // no data 41469 41470 if (Array.isArray(value)) { 41471 41472 do { 41473 41474 value = key[valuePropertyName]; 41475 41476 if (value !== undefined) { 41477 41478 times.push(key.time); 41479 values.push.apply(values, value); // push all elements 41480 41481 } 41482 41483 key = jsonKeys[i++]; 41484 41485 } while (key !== undefined); 41486 41487 } else if (value.toArray !== undefined) { 41488 41489 // ...assume THREE.Math-ish 41490 41491 do { 41492 41493 value = key[valuePropertyName]; 41494 41495 if (value !== undefined) { 41496 41497 times.push(key.time); 41498 value.toArray(values, values.length); 41499 41500 } 41501 41502 key = jsonKeys[i++]; 41503 41504 } while (key !== undefined); 41505 41506 } else { 41507 41508 // otherwise push as-is 41509 41510 do { 41511 41512 value = key[valuePropertyName]; 41513 41514 if (value !== undefined) { 41515 41516 times.push(key.time); 41517 values.push(value); 41518 41519 } 41520 41521 key = jsonKeys[i++]; 41522 41523 } while (key !== undefined); 41524 41525 } 41526 41527} 41528 41529function subclip(sourceClip, name, startFrame, endFrame, fps = 30) { 41530 41531 const clip = sourceClip.clone(); 41532 41533 clip.name = name; 41534 41535 const tracks = []; 41536 41537 for (let i = 0; i < clip.tracks.length; ++i) { 41538 41539 const track = clip.tracks[i]; 41540 const valueSize = track.getValueSize(); 41541 41542 const times = []; 41543 const values = []; 41544 41545 for (let j = 0; j < track.times.length; ++j) { 41546 41547 const frame = track.times[j] * fps; 41548 41549 if (frame < startFrame || frame >= endFrame) continue; 41550 41551 times.push(track.times[j]); 41552 41553 for (let k = 0; k < valueSize; ++k) { 41554 41555 values.push(track.values[j * valueSize + k]); 41556 41557 } 41558 41559 } 41560 41561 if (times.length === 0) continue; 41562 41563 track.times = convertArray(times, track.times.constructor); 41564 track.values = convertArray(values, track.values.constructor); 41565 41566 tracks.push(track); 41567 41568 } 41569 41570 clip.tracks = tracks; 41571 41572 // find minimum .times value across all tracks in the trimmed clip 41573 41574 let minStartTime = Infinity; 41575 41576 for (let i = 0; i < clip.tracks.length; ++i) { 41577 41578 if (minStartTime > clip.tracks[i].times[0]) { 41579 41580 minStartTime = clip.tracks[i].times[0]; 41581 41582 } 41583 41584 } 41585 41586 // shift all tracks such that clip begins at t=0 41587 41588 for (let i = 0; i < clip.tracks.length; ++i) { 41589 41590 clip.tracks[i].shift(- 1 * minStartTime); 41591 41592 } 41593 41594 clip.resetDuration(); 41595 41596 return clip; 41597 41598} 41599 41600function makeClipAdditive(targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30) { 41601 41602 if (fps <= 0) fps = 30; 41603 41604 const numTracks = referenceClip.tracks.length; 41605 const referenceTime = referenceFrame / fps; 41606 41607 // Make each track's values relative to the values at the reference frame 41608 for (let i = 0; i < numTracks; ++i) { 41609 41610 const referenceTrack = referenceClip.tracks[i]; 41611 const referenceTrackType = referenceTrack.ValueTypeName; 41612 41613 // Skip this track if it's non-numeric 41614 if (referenceTrackType === 'bool' || referenceTrackType === 'string') continue; 41615 41616 // Find the track in the target clip whose name and type matches the reference track 41617 const targetTrack = targetClip.tracks.find(function (track) { 41618 41619 return track.name === referenceTrack.name 41620 && track.ValueTypeName === referenceTrackType; 41621 41622 }); 41623 41624 if (targetTrack === undefined) continue; 41625 41626 let referenceOffset = 0; 41627 const referenceValueSize = referenceTrack.getValueSize(); 41628 41629 if (referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline) { 41630 41631 referenceOffset = referenceValueSize / 3; 41632 41633 } 41634 41635 let targetOffset = 0; 41636 const targetValueSize = targetTrack.getValueSize(); 41637 41638 if (targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline) { 41639 41640 targetOffset = targetValueSize / 3; 41641 41642 } 41643 41644 const lastIndex = referenceTrack.times.length - 1; 41645 let referenceValue; 41646 41647 // Find the value to subtract out of the track 41648 if (referenceTime <= referenceTrack.times[0]) { 41649 41650 // Reference frame is earlier than the first keyframe, so just use the first keyframe 41651 const startIndex = referenceOffset; 41652 const endIndex = referenceValueSize - referenceOffset; 41653 referenceValue = referenceTrack.values.slice(startIndex, endIndex); 41654 41655 } else if (referenceTime >= referenceTrack.times[lastIndex]) { 41656 41657 // Reference frame is after the last keyframe, so just use the last keyframe 41658 const startIndex = lastIndex * referenceValueSize + referenceOffset; 41659 const endIndex = startIndex + referenceValueSize - referenceOffset; 41660 referenceValue = referenceTrack.values.slice(startIndex, endIndex); 41661 41662 } else { 41663 41664 // Interpolate to the reference value 41665 const interpolant = referenceTrack.createInterpolant(); 41666 const startIndex = referenceOffset; 41667 const endIndex = referenceValueSize - referenceOffset; 41668 interpolant.evaluate(referenceTime); 41669 referenceValue = interpolant.resultBuffer.slice(startIndex, endIndex); 41670 41671 } 41672 41673 // Conjugate the quaternion 41674 if (referenceTrackType === 'quaternion') { 41675 41676 const referenceQuat = new Quaternion().fromArray(referenceValue).normalize().conjugate(); 41677 referenceQuat.toArray(referenceValue); 41678 41679 } 41680 41681 // Subtract the reference value from all of the track values 41682 41683 const numTimes = targetTrack.times.length; 41684 for (let j = 0; j < numTimes; ++j) { 41685 41686 const valueStart = j * targetValueSize + targetOffset; 41687 41688 if (referenceTrackType === 'quaternion') { 41689 41690 // Multiply the conjugate for quaternion track types 41691 Quaternion.multiplyQuaternionsFlat( 41692 targetTrack.values, 41693 valueStart, 41694 referenceValue, 41695 0, 41696 targetTrack.values, 41697 valueStart 41698 ); 41699 41700 } else { 41701 41702 const valueEnd = targetValueSize - targetOffset * 2; 41703 41704 // Subtract each value for all other numeric track types 41705 for (let k = 0; k < valueEnd; ++k) { 41706 41707 targetTrack.values[valueStart + k] -= referenceValue[k]; 41708 41709 } 41710 41711 } 41712 41713 } 41714 41715 } 41716 41717 targetClip.blendMode = AdditiveAnimationBlendMode; 41718 41719 return targetClip; 41720 41721} 41722 41723const AnimationUtils = { 41724 convertArray: convertArray, 41725 isTypedArray: isTypedArray, 41726 getKeyframeOrder: getKeyframeOrder, 41727 sortedArray: sortedArray, 41728 flattenJSON: flattenJSON, 41729 subclip: subclip, 41730 makeClipAdditive: makeClipAdditive 41731}; 41732 41733/** 41734 * Abstract base class of interpolants over parametric samples. 41735 * 41736 * The parameter domain is one dimensional, typically the time or a path 41737 * along a curve defined by the data. 41738 * 41739 * The sample values can have any dimensionality and derived classes may 41740 * apply special interpretations to the data. 41741 * 41742 * This class provides the interval seek in a Template Method, deferring 41743 * the actual interpolation to derived classes. 41744 * 41745 * Time complexity is O(1) for linear access crossing at most two points 41746 * and O(log N) for random access, where N is the number of positions. 41747 * 41748 * References: 41749 * 41750 * http://www.oodesign.com/template-method-pattern.html 41751 * 41752 */ 41753 41754class Interpolant { 41755 41756 constructor(parameterPositions, sampleValues, sampleSize, resultBuffer) { 41757 41758 this.parameterPositions = parameterPositions; 41759 this._cachedIndex = 0; 41760 41761 this.resultBuffer = resultBuffer !== undefined ? 41762 resultBuffer : new sampleValues.constructor(sampleSize); 41763 this.sampleValues = sampleValues; 41764 this.valueSize = sampleSize; 41765 41766 this.settings = null; 41767 this.DefaultSettings_ = {}; 41768 41769 } 41770 41771 evaluate(t) { 41772 41773 const pp = this.parameterPositions; 41774 let i1 = this._cachedIndex, 41775 t1 = pp[i1], 41776 t0 = pp[i1 - 1]; 41777 41778 validate_interval: { 41779 41780 seek: { 41781 41782 let right; 41783 41784 linear_scan: { 41785 41786 //- See http://jsperf.com/comparison-to-undefined/3 41787 //- slower code: 41788 //- 41789 //- if ( t >= t1 || t1 === undefined ) { 41790 forward_scan: if (!(t < t1)) { 41791 41792 for (let giveUpAt = i1 + 2; ;) { 41793 41794 if (t1 === undefined) { 41795 41796 if (t < t0) break forward_scan; 41797 41798 // after end 41799 41800 i1 = pp.length; 41801 this._cachedIndex = i1; 41802 return this.copySampleValue_(i1 - 1); 41803 41804 } 41805 41806 if (i1 === giveUpAt) break; // this loop 41807 41808 t0 = t1; 41809 t1 = pp[++i1]; 41810 41811 if (t < t1) { 41812 41813 // we have arrived at the sought interval 41814 break seek; 41815 41816 } 41817 41818 } 41819 41820 // prepare binary search on the right side of the index 41821 right = pp.length; 41822 break linear_scan; 41823 41824 } 41825 41826 //- slower code: 41827 //- if ( t < t0 || t0 === undefined ) { 41828 if (!(t >= t0)) { 41829 41830 // looping? 41831 41832 const t1global = pp[1]; 41833 41834 if (t < t1global) { 41835 41836 i1 = 2; // + 1, using the scan for the details 41837 t0 = t1global; 41838 41839 } 41840 41841 // linear reverse scan 41842 41843 for (let giveUpAt = i1 - 2; ;) { 41844 41845 if (t0 === undefined) { 41846 41847 // before start 41848 41849 this._cachedIndex = 0; 41850 return this.copySampleValue_(0); 41851 41852 } 41853 41854 if (i1 === giveUpAt) break; // this loop 41855 41856 t1 = t0; 41857 t0 = pp[--i1 - 1]; 41858 41859 if (t >= t0) { 41860 41861 // we have arrived at the sought interval 41862 break seek; 41863 41864 } 41865 41866 } 41867 41868 // prepare binary search on the left side of the index 41869 right = i1; 41870 i1 = 0; 41871 break linear_scan; 41872 41873 } 41874 41875 // the interval is valid 41876 41877 break validate_interval; 41878 41879 } // linear scan 41880 41881 // binary search 41882 41883 while (i1 < right) { 41884 41885 const mid = (i1 + right) >>> 1; 41886 41887 if (t < pp[mid]) { 41888 41889 right = mid; 41890 41891 } else { 41892 41893 i1 = mid + 1; 41894 41895 } 41896 41897 } 41898 41899 t1 = pp[i1]; 41900 t0 = pp[i1 - 1]; 41901 41902 // check boundary cases, again 41903 41904 if (t0 === undefined) { 41905 41906 this._cachedIndex = 0; 41907 return this.copySampleValue_(0); 41908 41909 } 41910 41911 if (t1 === undefined) { 41912 41913 i1 = pp.length; 41914 this._cachedIndex = i1; 41915 return this.copySampleValue_(i1 - 1); 41916 41917 } 41918 41919 } // seek 41920 41921 this._cachedIndex = i1; 41922 41923 this.intervalChanged_(i1, t0, t1); 41924 41925 } // validate_interval 41926 41927 return this.interpolate_(i1, t0, t, t1); 41928 41929 } 41930 41931 getSettings_() { 41932 41933 return this.settings || this.DefaultSettings_; 41934 41935 } 41936 41937 copySampleValue_(index) { 41938 41939 // copies a sample value to the result buffer 41940 41941 const result = this.resultBuffer, 41942 values = this.sampleValues, 41943 stride = this.valueSize, 41944 offset = index * stride; 41945 41946 for (let i = 0; i !== stride; ++i) { 41947 41948 result[i] = values[offset + i]; 41949 41950 } 41951 41952 return result; 41953 41954 } 41955 41956 // Template methods for derived classes: 41957 41958 interpolate_( /* i1, t0, t, t1 */) { 41959 41960 throw new Error('call to abstract method'); 41961 // implementations shall return this.resultBuffer 41962 41963 } 41964 41965 intervalChanged_( /* i1, t0, t1 */) { 41966 41967 // empty 41968 41969 } 41970 41971} 41972 41973/** 41974 * Fast and simple cubic spline interpolant. 41975 * 41976 * It was derived from a Hermitian construction setting the first derivative 41977 * at each sample position to the linear slope between neighboring positions 41978 * over their parameter interval. 41979 */ 41980 41981class CubicInterpolant extends Interpolant { 41982 41983 constructor(parameterPositions, sampleValues, sampleSize, resultBuffer) { 41984 41985 super(parameterPositions, sampleValues, sampleSize, resultBuffer); 41986 41987 this._weightPrev = - 0; 41988 this._offsetPrev = - 0; 41989 this._weightNext = - 0; 41990 this._offsetNext = - 0; 41991 41992 this.DefaultSettings_ = { 41993 41994 endingStart: ZeroCurvatureEnding, 41995 endingEnd: ZeroCurvatureEnding 41996 41997 }; 41998 41999 } 42000 42001 intervalChanged_(i1, t0, t1) { 42002 42003 const pp = this.parameterPositions; 42004 let iPrev = i1 - 2, 42005 iNext = i1 + 1, 42006 42007 tPrev = pp[iPrev], 42008 tNext = pp[iNext]; 42009 42010 if (tPrev === undefined) { 42011 42012 switch (this.getSettings_().endingStart) { 42013 42014 case ZeroSlopeEnding: 42015 42016 // f'(t0) = 0 42017 iPrev = i1; 42018 tPrev = 2 * t0 - t1; 42019 42020 break; 42021 42022 case WrapAroundEnding: 42023 42024 // use the other end of the curve 42025 iPrev = pp.length - 2; 42026 tPrev = t0 + pp[iPrev] - pp[iPrev + 1]; 42027 42028 break; 42029 42030 default: // ZeroCurvatureEnding 42031 42032 // f''(t0) = 0 a.k.a. Natural Spline 42033 iPrev = i1; 42034 tPrev = t1; 42035 42036 } 42037 42038 } 42039 42040 if (tNext === undefined) { 42041 42042 switch (this.getSettings_().endingEnd) { 42043 42044 case ZeroSlopeEnding: 42045 42046 // f'(tN) = 0 42047 iNext = i1; 42048 tNext = 2 * t1 - t0; 42049 42050 break; 42051 42052 case WrapAroundEnding: 42053 42054 // use the other end of the curve 42055 iNext = 1; 42056 tNext = t1 + pp[1] - pp[0]; 42057 42058 break; 42059 42060 default: // ZeroCurvatureEnding 42061 42062 // f''(tN) = 0, a.k.a. Natural Spline 42063 iNext = i1 - 1; 42064 tNext = t0; 42065 42066 } 42067 42068 } 42069 42070 const halfDt = (t1 - t0) * 0.5, 42071 stride = this.valueSize; 42072 42073 this._weightPrev = halfDt / (t0 - tPrev); 42074 this._weightNext = halfDt / (tNext - t1); 42075 this._offsetPrev = iPrev * stride; 42076 this._offsetNext = iNext * stride; 42077 42078 } 42079 42080 interpolate_(i1, t0, t, t1) { 42081 42082 const result = this.resultBuffer, 42083 values = this.sampleValues, 42084 stride = this.valueSize, 42085 42086 o1 = i1 * stride, o0 = o1 - stride, 42087 oP = this._offsetPrev, oN = this._offsetNext, 42088 wP = this._weightPrev, wN = this._weightNext, 42089 42090 p = (t - t0) / (t1 - t0), 42091 pp = p * p, 42092 ppp = pp * p; 42093 42094 // evaluate polynomials 42095 42096 const sP = - wP * ppp + 2 * wP * pp - wP * p; 42097 const s0 = (1 + wP) * ppp + (- 1.5 - 2 * wP) * pp + (- 0.5 + wP) * p + 1; 42098 const s1 = (- 1 - wN) * ppp + (1.5 + wN) * pp + 0.5 * p; 42099 const sN = wN * ppp - wN * pp; 42100 42101 // combine data linearly 42102 42103 for (let i = 0; i !== stride; ++i) { 42104 42105 result[i] = 42106 sP * values[oP + i] + 42107 s0 * values[o0 + i] + 42108 s1 * values[o1 + i] + 42109 sN * values[oN + i]; 42110 42111 } 42112 42113 return result; 42114 42115 } 42116 42117} 42118 42119class LinearInterpolant extends Interpolant { 42120 42121 constructor(parameterPositions, sampleValues, sampleSize, resultBuffer) { 42122 42123 super(parameterPositions, sampleValues, sampleSize, resultBuffer); 42124 42125 } 42126 42127 interpolate_(i1, t0, t, t1) { 42128 42129 const result = this.resultBuffer, 42130 values = this.sampleValues, 42131 stride = this.valueSize, 42132 42133 offset1 = i1 * stride, 42134 offset0 = offset1 - stride, 42135 42136 weight1 = (t - t0) / (t1 - t0), 42137 weight0 = 1 - weight1; 42138 42139 for (let i = 0; i !== stride; ++i) { 42140 42141 result[i] = 42142 values[offset0 + i] * weight0 + 42143 values[offset1 + i] * weight1; 42144 42145 } 42146 42147 return result; 42148 42149 } 42150 42151} 42152 42153/** 42154 * 42155 * Interpolant that evaluates to the sample value at the position preceding 42156 * the parameter. 42157 */ 42158 42159class DiscreteInterpolant extends Interpolant { 42160 42161 constructor(parameterPositions, sampleValues, sampleSize, resultBuffer) { 42162 42163 super(parameterPositions, sampleValues, sampleSize, resultBuffer); 42164 42165 } 42166 42167 interpolate_(i1 /*, t0, t, t1 */) { 42168 42169 return this.copySampleValue_(i1 - 1); 42170 42171 } 42172 42173} 42174 42175class KeyframeTrack { 42176 42177 constructor(name, times, values, interpolation) { 42178 42179 if (name === undefined) throw new Error('THREE.KeyframeTrack: track name is undefined'); 42180 if (times === undefined || times.length === 0) throw new Error('THREE.KeyframeTrack: no keyframes in track named ' + n
vendor: 26,993 bytes, lines 42180-43579
42180ame); 42181 42182 this.name = name; 42183 42184 this.times = convertArray(times, this.TimeBufferType); 42185 this.values = convertArray(values, this.ValueBufferType); 42186 42187 this.setInterpolation(interpolation || this.DefaultInterpolation); 42188 42189 } 42190 42191 // Serialization (in static context, because of constructor invocation 42192 // and automatic invocation of .toJSON): 42193 42194 static toJSON(track) { 42195 42196 const trackType = track.constructor; 42197 42198 let json; 42199 42200 // derived classes can define a static toJSON method 42201 if (trackType.toJSON !== this.toJSON) { 42202 42203 json = trackType.toJSON(track); 42204 42205 } else { 42206 42207 // by default, we assume the data can be serialized as-is 42208 json = { 42209 42210 'name': track.name, 42211 'times': convertArray(track.times, Array), 42212 'values': convertArray(track.values, Array) 42213 42214 }; 42215 42216 const interpolation = track.getInterpolation(); 42217 42218 if (interpolation !== track.DefaultInterpolation) { 42219 42220 json.interpolation = interpolation; 42221 42222 } 42223 42224 } 42225 42226 json.type = track.ValueTypeName; // mandatory 42227 42228 return json; 42229 42230 } 42231 42232 InterpolantFactoryMethodDiscrete(result) { 42233 42234 return new DiscreteInterpolant(this.times, this.values, this.getValueSize(), result); 42235 42236 } 42237 42238 InterpolantFactoryMethodLinear(result) { 42239 42240 return new LinearInterpolant(this.times, this.values, this.getValueSize(), result); 42241 42242 } 42243 42244 InterpolantFactoryMethodSmooth(result) { 42245 42246 return new CubicInterpolant(this.times, this.values, this.getValueSize(), result); 42247 42248 } 42249 42250 setInterpolation(interpolation) { 42251 42252 let factoryMethod; 42253 42254 switch (interpolation) { 42255 42256 case InterpolateDiscrete: 42257 42258 factoryMethod = this.InterpolantFactoryMethodDiscrete; 42259 42260 break; 42261 42262 case InterpolateLinear: 42263 42264 factoryMethod = this.InterpolantFactoryMethodLinear; 42265 42266 break; 42267 42268 case InterpolateSmooth: 42269 42270 factoryMethod = this.InterpolantFactoryMethodSmooth; 42271 42272 break; 42273 42274 } 42275 42276 if (factoryMethod === undefined) { 42277 42278 const message = 'unsupported interpolation for ' + 42279 this.ValueTypeName + ' keyframe track named ' + this.name; 42280 42281 if (this.createInterpolant === undefined) { 42282 42283 // fall back to default, unless the default itself is messed up 42284 if (interpolation !== this.DefaultInterpolation) { 42285 42286 this.setInterpolation(this.DefaultInterpolation); 42287 42288 } else { 42289 42290 throw new Error(message); // fatal, in this case 42291 42292 } 42293 42294 } 42295 42296 console.warn('THREE.KeyframeTrack:', message); 42297 return this; 42298 42299 } 42300 42301 this.createInterpolant = factoryMethod; 42302 42303 return this; 42304 42305 } 42306 42307 getInterpolation() { 42308 42309 switch (this.createInterpolant) { 42310 42311 case this.InterpolantFactoryMethodDiscrete: 42312 42313 return InterpolateDiscrete; 42314 42315 case this.InterpolantFactoryMethodLinear: 42316 42317 return InterpolateLinear; 42318 42319 case this.InterpolantFactoryMethodSmooth: 42320 42321 return InterpolateSmooth; 42322 42323 } 42324 42325 } 42326 42327 getValueSize() { 42328 42329 return this.values.length / this.times.length; 42330 42331 } 42332 42333 // move all keyframes either forwards or backwards in time 42334 shift(timeOffset) { 42335 42336 if (timeOffset !== 0.0) { 42337 42338 const times = this.times; 42339 42340 for (let i = 0, n = times.length; i !== n; ++i) { 42341 42342 times[i] += timeOffset; 42343 42344 } 42345 42346 } 42347 42348 return this; 42349 42350 } 42351 42352 // scale all keyframe times by a factor (useful for frame <-> seconds conversions) 42353 scale(timeScale) { 42354 42355 if (timeScale !== 1.0) { 42356 42357 const times = this.times; 42358 42359 for (let i = 0, n = times.length; i !== n; ++i) { 42360 42361 times[i] *= timeScale; 42362 42363 } 42364 42365 } 42366 42367 return this; 42368 42369 } 42370 42371 // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. 42372 // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values 42373 trim(startTime, endTime) { 42374 42375 const times = this.times, 42376 nKeys = times.length; 42377 42378 let from = 0, 42379 to = nKeys - 1; 42380 42381 while (from !== nKeys && times[from] < startTime) { 42382 42383 ++from; 42384 42385 } 42386 42387 while (to !== - 1 && times[to] > endTime) { 42388 42389 --to; 42390 42391 } 42392 42393 ++to; // inclusive -> exclusive bound 42394 42395 if (from !== 0 || to !== nKeys) { 42396 42397 // empty tracks are forbidden, so keep at least one keyframe 42398 if (from >= to) { 42399 42400 to = Math.max(to, 1); 42401 from = to - 1; 42402 42403 } 42404 42405 const stride = this.getValueSize(); 42406 this.times = times.slice(from, to); 42407 this.values = this.values.slice(from * stride, to * stride); 42408 42409 } 42410 42411 return this; 42412 42413 } 42414 42415 // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable 42416 validate() { 42417 42418 let valid = true; 42419 42420 const valueSize = this.getValueSize(); 42421 if (valueSize - Math.floor(valueSize) !== 0) { 42422 42423 console.error('THREE.KeyframeTrack: Invalid value size in track.', this); 42424 valid = false; 42425 42426 } 42427 42428 const times = this.times, 42429 values = this.values, 42430 42431 nKeys = times.length; 42432 42433 if (nKeys === 0) { 42434 42435 console.error('THREE.KeyframeTrack: Track is empty.', this); 42436 valid = false; 42437 42438 } 42439 42440 let prevTime = null; 42441 42442 for (let i = 0; i !== nKeys; i++) { 42443 42444 const currTime = times[i]; 42445 42446 if (typeof currTime === 'number' && isNaN(currTime)) { 42447 42448 console.error('THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime); 42449 valid = false; 42450 break; 42451 42452 } 42453 42454 if (prevTime !== null && prevTime > currTime) { 42455 42456 console.error('THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime); 42457 valid = false; 42458 break; 42459 42460 } 42461 42462 prevTime = currTime; 42463 42464 } 42465 42466 if (values !== undefined) { 42467 42468 if (isTypedArray(values)) { 42469 42470 for (let i = 0, n = values.length; i !== n; ++i) { 42471 42472 const value = values[i]; 42473 42474 if (isNaN(value)) { 42475 42476 console.error('THREE.KeyframeTrack: Value is not a valid number.', this, i, value); 42477 valid = false; 42478 break; 42479 42480 } 42481 42482 } 42483 42484 } 42485 42486 } 42487 42488 return valid; 42489 42490 } 42491 42492 // removes equivalent sequential keys as common in morph target sequences 42493 // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) 42494 optimize() { 42495 42496 // times or values may be shared with other tracks, so overwriting is unsafe 42497 const times = this.times.slice(), 42498 values = this.values.slice(), 42499 stride = this.getValueSize(), 42500 42501 smoothInterpolation = this.getInterpolation() === InterpolateSmooth, 42502 42503 lastIndex = times.length - 1; 42504 42505 let writeIndex = 1; 42506 42507 for (let i = 1; i < lastIndex; ++i) { 42508 42509 let keep = false; 42510 42511 const time = times[i]; 42512 const timeNext = times[i + 1]; 42513 42514 // remove adjacent keyframes scheduled at the same time 42515 42516 if (time !== timeNext && (i !== 1 || time !== times[0])) { 42517 42518 if (!smoothInterpolation) { 42519 42520 // remove unnecessary keyframes same as their neighbors 42521 42522 const offset = i * stride, 42523 offsetP = offset - stride, 42524 offsetN = offset + stride; 42525 42526 for (let j = 0; j !== stride; ++j) { 42527 42528 const value = values[offset + j]; 42529 42530 if (value !== values[offsetP + j] || 42531 value !== values[offsetN + j]) { 42532 42533 keep = true; 42534 break; 42535 42536 } 42537 42538 } 42539 42540 } else { 42541 42542 keep = true; 42543 42544 } 42545 42546 } 42547 42548 // in-place compaction 42549 42550 if (keep) { 42551 42552 if (i !== writeIndex) { 42553 42554 times[writeIndex] = times[i]; 42555 42556 const readOffset = i * stride, 42557 writeOffset = writeIndex * stride; 42558 42559 for (let j = 0; j !== stride; ++j) { 42560 42561 values[writeOffset + j] = values[readOffset + j]; 42562 42563 } 42564 42565 } 42566 42567 ++writeIndex; 42568 42569 } 42570 42571 } 42572 42573 // flush last keyframe (compaction looks ahead) 42574 42575 if (lastIndex > 0) { 42576 42577 times[writeIndex] = times[lastIndex]; 42578 42579 for (let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++j) { 42580 42581 values[writeOffset + j] = values[readOffset + j]; 42582 42583 } 42584 42585 ++writeIndex; 42586 42587 } 42588 42589 if (writeIndex !== times.length) { 42590 42591 this.times = times.slice(0, writeIndex); 42592 this.values = values.slice(0, writeIndex * stride); 42593 42594 } else { 42595 42596 this.times = times; 42597 this.values = values; 42598 42599 } 42600 42601 return this; 42602 42603 } 42604 42605 clone() { 42606 42607 const times = this.times.slice(); 42608 const values = this.values.slice(); 42609 42610 const TypedKeyframeTrack = this.constructor; 42611 const track = new TypedKeyframeTrack(this.name, times, values); 42612 42613 // Interpolant argument to constructor is not saved, so copy the factory method directly. 42614 track.createInterpolant = this.createInterpolant; 42615 42616 return track; 42617 42618 } 42619 42620} 42621 42622KeyframeTrack.prototype.TimeBufferType = Float32Array; 42623KeyframeTrack.prototype.ValueBufferType = Float32Array; 42624KeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear; 42625 42626/** 42627 * A Track of Boolean keyframe values. 42628 */ 42629class BooleanKeyframeTrack extends KeyframeTrack { } 42630 42631BooleanKeyframeTrack.prototype.ValueTypeName = 'bool'; 42632BooleanKeyframeTrack.prototype.ValueBufferType = Array; 42633BooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; 42634BooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; 42635BooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; 42636 42637/** 42638 * A Track of keyframe values that represent color. 42639 */ 42640class ColorKeyframeTrack extends KeyframeTrack { } 42641 42642ColorKeyframeTrack.prototype.ValueTypeName = 'color'; 42643 42644/** 42645 * A Track of numeric keyframe values. 42646 */ 42647class NumberKeyframeTrack extends KeyframeTrack { } 42648 42649NumberKeyframeTrack.prototype.ValueTypeName = 'number'; 42650 42651/** 42652 * Spherical linear unit quaternion interpolant. 42653 */ 42654 42655class QuaternionLinearInterpolant extends Interpolant { 42656 42657 constructor(parameterPositions, sampleValues, sampleSize, resultBuffer) { 42658 42659 super(parameterPositions, sampleValues, sampleSize, resultBuffer); 42660 42661 } 42662 42663 interpolate_(i1, t0, t, t1) { 42664 42665 const result = this.resultBuffer, 42666 values = this.sampleValues, 42667 stride = this.valueSize, 42668 42669 alpha = (t - t0) / (t1 - t0); 42670 42671 let offset = i1 * stride; 42672 42673 for (let end = offset + stride; offset !== end; offset += 4) { 42674 42675 Quaternion.slerpFlat(result, 0, values, offset - stride, values, offset, alpha); 42676 42677 } 42678 42679 return result; 42680 42681 } 42682 42683} 42684 42685/** 42686 * A Track of quaternion keyframe values. 42687 */ 42688class QuaternionKeyframeTrack extends KeyframeTrack { 42689 42690 InterpolantFactoryMethodLinear(result) { 42691 42692 return new QuaternionLinearInterpolant(this.times, this.values, this.getValueSize(), result); 42693 42694 } 42695 42696} 42697 42698QuaternionKeyframeTrack.prototype.ValueTypeName = 'quaternion'; 42699// ValueBufferType is inherited 42700QuaternionKeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear; 42701QuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; 42702 42703/** 42704 * A Track that interpolates Strings 42705 */ 42706class StringKeyframeTrack extends KeyframeTrack { } 42707 42708StringKeyframeTrack.prototype.ValueTypeName = 'string'; 42709StringKeyframeTrack.prototype.ValueBufferType = Array; 42710StringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; 42711StringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; 42712StringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; 42713 42714/** 42715 * A Track of vectored keyframe values. 42716 */ 42717class VectorKeyframeTrack extends KeyframeTrack { } 42718 42719VectorKeyframeTrack.prototype.ValueTypeName = 'vector'; 42720 42721class AnimationClip { 42722 42723 constructor(name, duration = - 1, tracks, blendMode = NormalAnimationBlendMode) { 42724 42725 this.name = name; 42726 this.tracks = tracks; 42727 this.duration = duration; 42728 this.blendMode = blendMode; 42729 42730 this.uuid = generateUUID(); 42731 42732 // this means it should figure out its duration by scanning the tracks 42733 if (this.duration < 0) { 42734 42735 this.resetDuration(); 42736 42737 } 42738 42739 } 42740 42741 42742 static parse(json) { 42743 42744 const tracks = [], 42745 jsonTracks = json.tracks, 42746 frameTime = 1.0 / (json.fps || 1.0); 42747 42748 for (let i = 0, n = jsonTracks.length; i !== n; ++i) { 42749 42750 tracks.push(parseKeyframeTrack(jsonTracks[i]).scale(frameTime)); 42751 42752 } 42753 42754 const clip = new this(json.name, json.duration, tracks, json.blendMode); 42755 clip.uuid = json.uuid; 42756 42757 return clip; 42758 42759 } 42760 42761 static toJSON(clip) { 42762 42763 const tracks = [], 42764 clipTracks = clip.tracks; 42765 42766 const json = { 42767 42768 'name': clip.name, 42769 'duration': clip.duration, 42770 'tracks': tracks, 42771 'uuid': clip.uuid, 42772 'blendMode': clip.blendMode 42773 42774 }; 42775 42776 for (let i = 0, n = clipTracks.length; i !== n; ++i) { 42777 42778 tracks.push(KeyframeTrack.toJSON(clipTracks[i])); 42779 42780 } 42781 42782 return json; 42783 42784 } 42785 42786 static CreateFromMorphTargetSequence(name, morphTargetSequence, fps, noLoop) { 42787 42788 const numMorphTargets = morphTargetSequence.length; 42789 const tracks = []; 42790 42791 for (let i = 0; i < numMorphTargets; i++) { 42792 42793 let times = []; 42794 let values = []; 42795 42796 times.push( 42797 (i + numMorphTargets - 1) % numMorphTargets, 42798 i, 42799 (i + 1) % numMorphTargets); 42800 42801 values.push(0, 1, 0); 42802 42803 const order = getKeyframeOrder(times); 42804 times = sortedArray(times, 1, order); 42805 values = sortedArray(values, 1, order); 42806 42807 // if there is a key at the first frame, duplicate it as the 42808 // last frame as well for perfect loop. 42809 if (!noLoop && times[0] === 0) { 42810 42811 times.push(numMorphTargets); 42812 values.push(values[0]); 42813 42814 } 42815 42816 tracks.push( 42817 new NumberKeyframeTrack( 42818 '.morphTargetInfluences[' + morphTargetSequence[i].name + ']', 42819 times, values 42820 ).scale(1.0 / fps)); 42821 42822 } 42823 42824 return new this(name, - 1, tracks); 42825 42826 } 42827 42828 static findByName(objectOrClipArray, name) { 42829 42830 let clipArray = objectOrClipArray; 42831 42832 if (!Array.isArray(objectOrClipArray)) { 42833 42834 const o = objectOrClipArray; 42835 clipArray = o.geometry && o.geometry.animations || o.animations; 42836 42837 } 42838 42839 for (let i = 0; i < clipArray.length; i++) { 42840 42841 if (clipArray[i].name === name) { 42842 42843 return clipArray[i]; 42844 42845 } 42846 42847 } 42848 42849 return null; 42850 42851 } 42852 42853 static CreateClipsFromMorphTargetSequences(morphTargets, fps, noLoop) { 42854 42855 const animationToMorphTargets = {}; 42856 42857 // tested with https://regex101.com/ on trick sequences 42858 // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 42859 const pattern = /^([\w-]*?)([\d]+)$/; 42860 42861 // sort morph target names into animation groups based 42862 // patterns like Walk_001, Walk_002, Run_001, Run_002 42863 for (let i = 0, il = morphTargets.length; i < il; i++) { 42864 42865 const morphTarget = morphTargets[i]; 42866 const parts = morphTarget.name.match(pattern); 42867 42868 if (parts && parts.length > 1) { 42869 42870 const name = parts[1]; 42871 42872 let animationMorphTargets = animationToMorphTargets[name]; 42873 42874 if (!animationMorphTargets) { 42875 42876 animationToMorphTargets[name] = animationMorphTargets = []; 42877 42878 } 42879 42880 animationMorphTargets.push(morphTarget); 42881 42882 } 42883 42884 } 42885 42886 const clips = []; 42887 42888 for (const name in animationToMorphTargets) { 42889 42890 clips.push(this.CreateFromMorphTargetSequence(name, animationToMorphTargets[name], fps, noLoop)); 42891 42892 } 42893 42894 return clips; 42895 42896 } 42897 42898 // parse the animation.hierarchy format 42899 static parseAnimation(animation, bones) { 42900 42901 if (!animation) { 42902 42903 console.error('THREE.AnimationClip: No animation in JSONLoader data.'); 42904 return null; 42905 42906 } 42907 42908 const addNonemptyTrack = function (trackType, trackName, animationKeys, propertyName, destTracks) { 42909 42910 // only return track if there are actually keys. 42911 if (animationKeys.length !== 0) { 42912 42913 const times = []; 42914 const values = []; 42915 42916 flattenJSON(animationKeys, times, values, propertyName); 42917 42918 // empty keys are filtered out, so check again 42919 if (times.length !== 0) { 42920 42921 destTracks.push(new trackType(trackName, times, values)); 42922 42923 } 42924 42925 } 42926 42927 }; 42928 42929 const tracks = []; 42930 42931 const clipName = animation.name || 'default'; 42932 const fps = animation.fps || 30; 42933 const blendMode = animation.blendMode; 42934 42935 // automatic length determination in AnimationClip. 42936 let duration = animation.length || - 1; 42937 42938 const hierarchyTracks = animation.hierarchy || []; 42939 42940 for (let h = 0; h < hierarchyTracks.length; h++) { 42941 42942 const animationKeys = hierarchyTracks[h].keys; 42943 42944 // skip empty tracks 42945 if (!animationKeys || animationKeys.length === 0) continue; 42946 42947 // process morph targets 42948 if (animationKeys[0].morphTargets) { 42949 42950 // figure out all morph targets used in this track 42951 const morphTargetNames = {}; 42952 42953 let k; 42954 42955 for (k = 0; k < animationKeys.length; k++) { 42956 42957 if (animationKeys[k].morphTargets) { 42958 42959 for (let m = 0; m < animationKeys[k].morphTargets.length; m++) { 42960 42961 morphTargetNames[animationKeys[k].morphTargets[m]] = - 1; 42962 42963 } 42964 42965 } 42966 42967 } 42968 42969 // create a track for each morph target with all zero 42970 // morphTargetInfluences except for the keys in which 42971 // the morphTarget is named. 42972 for (const morphTargetName in morphTargetNames) { 42973 42974 const times = []; 42975 const values = []; 42976 42977 for (let m = 0; m !== animationKeys[k].morphTargets.length; ++m) { 42978 42979 const animationKey = animationKeys[k]; 42980 42981 times.push(animationKey.time); 42982 values.push((animationKey.morphTarget === morphTargetName) ? 1 : 0); 42983 42984 } 42985 42986 tracks.push(new NumberKeyframeTrack('.morphTargetInfluence[' + morphTargetName + ']', times, values)); 42987 42988 } 42989 42990 duration = morphTargetNames.length * fps; 42991 42992 } else { 42993 42994 // ...assume skeletal animation 42995 42996 const boneName = '.bones[' + bones[h].name + ']'; 42997 42998 addNonemptyTrack( 42999 VectorKeyframeTrack, boneName + '.position', 43000 animationKeys, 'pos', tracks); 43001 43002 addNonemptyTrack( 43003 QuaternionKeyframeTrack, boneName + '.quaternion', 43004 animationKeys, 'rot', tracks); 43005 43006 addNonemptyTrack( 43007 VectorKeyframeTrack, boneName + '.scale', 43008 animationKeys, 'scl', tracks); 43009 43010 } 43011 43012 } 43013 43014 if (tracks.length === 0) { 43015 43016 return null; 43017 43018 } 43019 43020 const clip = new this(clipName, duration, tracks, blendMode); 43021 43022 return clip; 43023 43024 } 43025 43026 resetDuration() { 43027 43028 const tracks = this.tracks; 43029 let duration = 0; 43030 43031 for (let i = 0, n = tracks.length; i !== n; ++i) { 43032 43033 const track = this.tracks[i]; 43034 43035 duration = Math.max(duration, track.times[track.times.length - 1]); 43036 43037 } 43038 43039 this.duration = duration; 43040 43041 return this; 43042 43043 } 43044 43045 trim() { 43046 43047 for (let i = 0; i < this.tracks.length; i++) { 43048 43049 this.tracks[i].trim(0, this.duration); 43050 43051 } 43052 43053 return this; 43054 43055 } 43056 43057 validate() { 43058 43059 let valid = true; 43060 43061 for (let i = 0; i < this.tracks.length; i++) { 43062 43063 valid = valid && this.tracks[i].validate(); 43064 43065 } 43066 43067 return valid; 43068 43069 } 43070 43071 optimize() { 43072 43073 for (let i = 0; i < this.tracks.length; i++) { 43074 43075 this.tracks[i].optimize(); 43076 43077 } 43078 43079 return this; 43080 43081 } 43082 43083 clone() { 43084 43085 const tracks = []; 43086 43087 for (let i = 0; i < this.tracks.length; i++) { 43088 43089 tracks.push(this.tracks[i].clone()); 43090 43091 } 43092 43093 return new this.constructor(this.name, this.duration, tracks, this.blendMode); 43094 43095 } 43096 43097 toJSON() { 43098 43099 return this.constructor.toJSON(this); 43100 43101 } 43102 43103} 43104 43105function getTrackTypeForValueTypeName(typeName) { 43106 43107 switch (typeName.toLowerCase()) { 43108 43109 case 'scalar': 43110 case 'double': 43111 case 'float': 43112 case 'number': 43113 case 'integer': 43114 43115 return NumberKeyframeTrack; 43116 43117 case 'vector': 43118 case 'vector2': 43119 case 'vector3': 43120 case 'vector4': 43121 43122 return VectorKeyframeTrack; 43123 43124 case 'color': 43125 43126 return ColorKeyframeTrack; 43127 43128 case 'quaternion': 43129 43130 return QuaternionKeyframeTrack; 43131 43132 case 'bool': 43133 case 'boolean': 43134 43135 return BooleanKeyframeTrack; 43136 43137 case 'string': 43138 43139 return StringKeyframeTrack; 43140 43141 } 43142 43143 throw new Error('THREE.KeyframeTrack: Unsupported typeName: ' + typeName); 43144 43145} 43146 43147function parseKeyframeTrack(json) { 43148 43149 if (json.type === undefined) { 43150 43151 throw new Error('THREE.KeyframeTrack: track type undefined, can not parse'); 43152 43153 } 43154 43155 const trackType = getTrackTypeForValueTypeName(json.type); 43156 43157 if (json.times === undefined) { 43158 43159 const times = [], values = []; 43160 43161 flattenJSON(json.keys, times, values, 'value'); 43162 43163 json.times = times; 43164 json.values = values; 43165 43166 } 43167 43168 // derived classes can define a static parse method 43169 if (trackType.parse !== undefined) { 43170 43171 return trackType.parse(json); 43172 43173 } else { 43174 43175 // by default, we assume a constructor compatible with the base 43176 return new trackType(json.name, json.times, json.values, json.interpolation); 43177 43178 } 43179 43180} 43181 43182const Cache = { 43183 43184 enabled: false, 43185 43186 files: {}, 43187 43188 add: function (key, file) { 43189 43190 if (this.enabled === false) return; 43191 43192 // console.log( 'THREE.Cache', 'Adding key:', key ); 43193 43194 this.files[key] = file; 43195 43196 }, 43197 43198 get: function (key) { 43199 43200 if (this.enabled === false) return; 43201 43202 // console.log( 'THREE.Cache', 'Checking key:', key ); 43203 43204 return this.files[key]; 43205 43206 }, 43207 43208 remove: function (key) { 43209 43210 delete this.files[key]; 43211 43212 }, 43213 43214 clear: function () { 43215 43216 this.files = {}; 43217 43218 } 43219 43220}; 43221 43222class LoadingManager { 43223 43224 constructor(onLoad, onProgress, onError) { 43225 43226 const scope = this; 43227 43228 let isLoading = false; 43229 let itemsLoaded = 0; 43230 let itemsTotal = 0; 43231 let urlModifier = undefined; 43232 const handlers = []; 43233 43234 // Refer to #5689 for the reason why we don't set .onStart 43235 // in the constructor 43236 43237 this.onStart = undefined; 43238 this.onLoad = onLoad; 43239 this.onProgress = onProgress; 43240 this.onError = onError; 43241 43242 this.itemStart = function (url) { 43243 43244 itemsTotal++; 43245 43246 if (isLoading === false) { 43247 43248 if (scope.onStart !== undefined) { 43249 43250 scope.onStart(url, itemsLoaded, itemsTotal); 43251 43252 } 43253 43254 } 43255 43256 isLoading = true; 43257 43258 }; 43259 43260 this.itemEnd = function (url) { 43261 43262 itemsLoaded++; 43263 43264 if (scope.onProgress !== undefined) { 43265 43266 scope.onProgress(url, itemsLoaded, itemsTotal); 43267 43268 } 43269 43270 if (itemsLoaded === itemsTotal) { 43271 43272 isLoading = false; 43273 43274 if (scope.onLoad !== undefined) { 43275 43276 scope.onLoad(); 43277 43278 } 43279 43280 } 43281 43282 }; 43283 43284 this.itemError = function (url) { 43285 43286 if (scope.onError !== undefined) { 43287 43288 scope.onError(url); 43289 43290 } 43291 43292 }; 43293 43294 this.resolveURL = function (url) { 43295 43296 if (urlModifier) { 43297 43298 return urlModifier(url); 43299 43300 } 43301 43302 return url; 43303 43304 }; 43305 43306 this.setURLModifier = function (transform) { 43307 43308 urlModifier = transform; 43309 43310 return this; 43311 43312 }; 43313 43314 this.addHandler = function (regex, loader) { 43315 43316 handlers.push(regex, loader); 43317 43318 return this; 43319 43320 }; 43321 43322 this.removeHandler = function (regex) { 43323 43324 const index = handlers.indexOf(regex); 43325 43326 if (index !== - 1) { 43327 43328 handlers.splice(index, 2); 43329 43330 } 43331 43332 return this; 43333 43334 }; 43335 43336 this.getHandler = function (file) { 43337 43338 for (let i = 0, l = handlers.length; i < l; i += 2) { 43339 43340 const regex = handlers[i]; 43341 const loader = handlers[i + 1]; 43342 43343 if (regex.global) regex.lastIndex = 0; // see #17920 43344 43345 if (regex.test(file)) { 43346 43347 return loader; 43348 43349 } 43350 43351 } 43352 43353 return null; 43354 43355 }; 43356 43357 } 43358 43359} 43360 43361const DefaultLoadingManager = /*@__PURE__*/ new LoadingManager(); 43362 43363class Loader { 43364 43365 constructor(manager) { 43366 43367 this.manager = (manager !== undefined) ? manager : DefaultLoadingManager; 43368 43369 this.crossOrigin = 'anonymous'; 43370 this.withCredentials = false; 43371 this.path = ''; 43372 this.resourcePath = ''; 43373 this.requestHeader = {}; 43374 43375 } 43376 43377 load( /* url, onLoad, onProgress, onError */) { } 43378 43379 loadAsync(url, onProgress) { 43380 43381 const scope = this; 43382 43383 return new Promise(function (resolve, reject) { 43384 43385 scope.load(url, resolve, onProgress, reject); 43386 43387 }); 43388 43389 } 43390 43391 parse( /* data */) { } 43392 43393 setCrossOrigin(crossOrigin) { 43394 43395 this.crossOrigin = crossOrigin; 43396 return this; 43397 43398 } 43399 43400 setWithCredentials(value) { 43401 43402 this.withCredentials = value; 43403 return this; 43404 43405 } 43406 43407 setPath(path) { 43408 43409 this.path = path; 43410 return this; 43411 43412 } 43413 43414 setResourcePath(resourcePath) { 43415 43416 this.resourcePath = resourcePath; 43417 return this; 43418 43419 } 43420 43421 setRequestHeader(requestHeader) { 43422 43423 this.requestHeader = requestHeader; 43424 return this; 43425 43426 } 43427 43428} 43429 43430Loader.DEFAULT_MATERIAL_NAME = '__DEFAULT'; 43431 43432const loading = {}; 43433 43434class HttpError extends Error { 43435 43436 constructor(message, response) { 43437 43438 super(message); 43439 this.response = response; 43440 43441 } 43442 43443} 43444 43445class FileLoader extends Loader { 43446 43447 constructor(manager) { 43448 43449 super(manager); 43450 43451 } 43452 43453 load(url, onLoad, onProgress, onError) { 43454 43455 if (url === undefined) url = ''; 43456 43457 if (this.path !== undefined) url = this.path + url; 43458 43459 url = this.manager.resolveURL(url); 43460 43461 const cached = Cache.get(url); 43462 43463 if (cached !== undefined) { 43464 43465 this.manager.itemStart(url); 43466 43467 setTimeout(() => { 43468 43469 if (onLoad) onLoad(cached); 43470 43471 this.manager.itemEnd(url); 43472 43473 }, 0); 43474 43475 return cached; 43476 43477 } 43478 43479 // Check if request is duplicate 43480 43481 if (loading[url] !== undefined) { 43482 43483 loading[url].push({ 43484 43485 onLoad: onLoad, 43486 onProgress: onProgress, 43487 onError: onError 43488 43489 }); 43490 43491 return; 43492 43493 } 43494 43495 // Initialise array for duplicate requests 43496 loading[url] = []; 43497 43498 loading[url].push({ 43499 onLoad: onLoad, 43500 onProgress: onProgress, 43501 onError: onError, 43502 }); 43503 43504 // create request 43505 const req = new Request(url, { 43506 headers: new Headers(this.requestHeader), 43507 credentials: this.withCredentials ? 'include' : 'same-origin', 43508 // An abort controller could be added within a future PR 43509 }); 43510 43511 // record states ( avoid data race ) 43512 const mimeType = this.mimeType; 43513 const responseType = this.responseType; 43514 43515 // start the fetch 43516 fetch(req) 43517 .then(response => { 43518 43519 if (response.status === 200 || response.status === 0) { 43520 43521 // Some browsers return HTTP Status 0 when using non-http protocol 43522 // e.g. 'file://' or 'data://'. Handle as success. 43523 43524 if (response.status === 0) { 43525 43526 console.warn('THREE.FileLoader: HTTP Status 0 received.'); 43527 43528 } 43529 43530 // Workaround: Checking if response.body === undefined for Alipay browser #23548 43531 43532 if (typeof ReadableStream === 'undefined' || response.body === undefined || response.body.getReader === undefined) { 43533 43534 return response; 43535 43536 } 43537 43538 const callbacks = loading[url]; 43539 const reader = response.body.getReader(); 43540 43541 // Nginx needs X-File-Size check 43542 // https://serverfault.com/questions/482875/why-does-nginx-remove-content-length-header-for-chunked-content 43543 const contentLength = response.headers.get('Content-Length') || response.headers.get('X-File-Size'); 43544 const total = contentLength ? parseInt(contentLength) : 0; 43545 const lengthComputable = total !== 0; 43546 let loaded = 0; 43547 43548 // periodically read data into the new stream tracking while download progress 43549 const stream = new ReadableStream({ 43550 start(controller) { 43551 43552 readData(); 43553 43554 function readData() { 43555 43556 reader.read().then(({ done, value }) => { 43557 43558 if (done) { 43559 43560 controller.close(); 43561 43562 } else { 43563 43564 loaded += value.byteLength; 43565 43566 const event = new ProgressEvent('progress', { lengthComputable, loaded, total }); 43567 for (let i = 0, il = callbacks.length; i < il; i++) { 43568 43569 const callback = callbacks[i]; 43570 if (callback.onProgress) callback.onProgress(event); 43571 43572 } 43573 43574 controller.enqueue(value); 43575 readData(); 43576 43577 } 43578 43579 });
vendor: 9,077 bytes, lines 43580-44096
43580 43581 } 43582 43583 } 43584 43585 }); 43586 43587 return new Response(stream); 43588 43589 } else { 43590 43591 throw new HttpError(`fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`, response); 43592 43593 } 43594 43595 }) 43596 .then(response => { 43597 43598 switch (responseType) { 43599 43600 case 'arraybuffer': 43601 43602 return response.arrayBuffer(); 43603 43604 case 'blob': 43605 43606 return response.blob(); 43607 43608 case 'document': 43609 43610 return response.text() 43611 .then(text => { 43612 43613 const parser = new DOMParser(); 43614 return parser.parseFromString(text, mimeType); 43615 43616 }); 43617 43618 case 'json': 43619 43620 return response.json(); 43621 43622 default: 43623 43624 if (mimeType === undefined) { 43625 43626 return response.text(); 43627 43628 } else { 43629 43630 // sniff encoding 43631 const re = /charset="?([^;"\s]*)"?/i; 43632 const exec = re.exec(mimeType); 43633 const label = exec && exec[1] ? exec[1].toLowerCase() : undefined; 43634 const decoder = new TextDecoder(label); 43635 return response.arrayBuffer().then(ab => decoder.decode(ab)); 43636 43637 } 43638 43639 } 43640 43641 }) 43642 .then(data => { 43643 43644 // Add to cache only on HTTP success, so that we do not cache 43645 // error response bodies as proper responses to requests. 43646 Cache.add(url, data); 43647 43648 const callbacks = loading[url]; 43649 delete loading[url]; 43650 43651 for (let i = 0, il = callbacks.length; i < il; i++) { 43652 43653 const callback = callbacks[i]; 43654 if (callback.onLoad) callback.onLoad(data); 43655 43656 } 43657 43658 }) 43659 .catch(err => { 43660 43661 // Abort errors and other errors are handled the same 43662 43663 const callbacks = loading[url]; 43664 43665 if (callbacks === undefined) { 43666 43667 // When onLoad was called and url was deleted in `loading` 43668 this.manager.itemError(url); 43669 throw err; 43670 43671 } 43672 43673 delete loading[url]; 43674 43675 for (let i = 0, il = callbacks.length; i < il; i++) { 43676 43677 const callback = callbacks[i]; 43678 if (callback.onError) callback.onError(err); 43679 43680 } 43681 43682 this.manager.itemError(url); 43683 43684 }) 43685 .finally(() => { 43686 43687 this.manager.itemEnd(url); 43688 43689 }); 43690 43691 this.manager.itemStart(url); 43692 43693 } 43694 43695 setResponseType(value) { 43696 43697 this.responseType = value; 43698 return this; 43699 43700 } 43701 43702 setMimeType(value) { 43703 43704 this.mimeType = value; 43705 return this; 43706 43707 } 43708 43709} 43710 43711class AnimationLoader extends Loader { 43712 43713 constructor(manager) { 43714 43715 super(manager); 43716 43717 } 43718 43719 load(url, onLoad, onProgress, onError) { 43720 43721 const scope = this; 43722 43723 const loader = new FileLoader(this.manager); 43724 loader.setPath(this.path); 43725 loader.setRequestHeader(this.requestHeader); 43726 loader.setWithCredentials(this.withCredentials); 43727 loader.load(url, function (text) { 43728 43729 try { 43730 43731 onLoad(scope.parse(JSON.parse(text))); 43732 43733 } catch (e) { 43734 43735 if (onError) { 43736 43737 onError(e); 43738 43739 } else { 43740 43741 console.error(e); 43742 43743 } 43744 43745 scope.manager.itemError(url); 43746 43747 } 43748 43749 }, onProgress, onError); 43750 43751 } 43752 43753 parse(json) { 43754 43755 const animations = []; 43756 43757 for (let i = 0; i < json.length; i++) { 43758 43759 const clip = AnimationClip.parse(json[i]); 43760 43761 animations.push(clip); 43762 43763 } 43764 43765 return animations; 43766 43767 } 43768 43769} 43770 43771/** 43772 * Abstract Base class to block based textures loader (dds, pvr, ...) 43773 * 43774 * Sub classes have to implement the parse() method which will be used in load(). 43775 */ 43776 43777class CompressedTextureLoader extends Loader { 43778 43779 constructor(manager) { 43780 43781 super(manager); 43782 43783 } 43784 43785 load(url, onLoad, onProgress, onError) { 43786 43787 const scope = this; 43788 43789 const images = []; 43790 43791 const texture = new CompressedTexture(); 43792 43793 const loader = new FileLoader(this.manager); 43794 loader.setPath(this.path); 43795 loader.setResponseType('arraybuffer'); 43796 loader.setRequestHeader(this.requestHeader); 43797 loader.setWithCredentials(scope.withCredentials); 43798 43799 let loaded = 0; 43800 43801 function loadTexture(i) { 43802 43803 loader.load(url[i], function (buffer) { 43804 43805 const texDatas = scope.parse(buffer, true); 43806 43807 images[i] = { 43808 width: texDatas.width, 43809 height: texDatas.height, 43810 format: texDatas.format, 43811 mipmaps: texDatas.mipmaps 43812 }; 43813 43814 loaded += 1; 43815 43816 if (loaded === 6) { 43817 43818 if (texDatas.mipmapCount === 1) texture.minFilter = LinearFilter; 43819 43820 texture.image = images; 43821 texture.format = texDatas.format; 43822 texture.needsUpdate = true; 43823 43824 if (onLoad) onLoad(texture); 43825 43826 } 43827 43828 }, onProgress, onError); 43829 43830 } 43831 43832 if (Array.isArray(url)) { 43833 43834 for (let i = 0, il = url.length; i < il; ++i) { 43835 43836 loadTexture(i); 43837 43838 } 43839 43840 } else { 43841 43842 // compressed cubemap texture stored in a single DDS file 43843 43844 loader.load(url, function (buffer) { 43845 43846 const texDatas = scope.parse(buffer, true); 43847 43848 if (texDatas.isCubemap) { 43849 43850 const faces = texDatas.mipmaps.length / texDatas.mipmapCount; 43851 43852 for (let f = 0; f < faces; f++) { 43853 43854 images[f] = { mipmaps: [] }; 43855 43856 for (let i = 0; i < texDatas.mipmapCount; i++) { 43857 43858 images[f].mipmaps.push(texDatas.mipmaps[f * texDatas.mipmapCount + i]); 43859 images[f].format = texDatas.format; 43860 images[f].width = texDatas.width; 43861 images[f].height = texDatas.height; 43862 43863 } 43864 43865 } 43866 43867 texture.image = images; 43868 43869 } else { 43870 43871 texture.image.width = texDatas.width; 43872 texture.image.height = texDatas.height; 43873 texture.mipmaps = texDatas.mipmaps; 43874 43875 } 43876 43877 if (texDatas.mipmapCount === 1) { 43878 43879 texture.minFilter = LinearFilter; 43880 43881 } 43882 43883 texture.format = texDatas.format; 43884 texture.needsUpdate = true; 43885 43886 if (onLoad) onLoad(texture); 43887 43888 }, onProgress, onError); 43889 43890 } 43891 43892 return texture; 43893 43894 } 43895 43896} 43897 43898class ImageLoader extends Loader { 43899 43900 constructor(manager) { 43901 43902 super(manager); 43903 43904 } 43905 43906 load(url, onLoad, onProgress, onError) { 43907 43908 if (this.path !== undefined) url = this.path + url; 43909 43910 url = this.manager.resolveURL(url); 43911 43912 const scope = this; 43913 43914 const cached = Cache.get(url); 43915 43916 if (cached !== undefined) { 43917 43918 scope.manager.itemStart(url); 43919 43920 setTimeout(function () { 43921 43922 if (onLoad) onLoad(cached); 43923 43924 scope.manager.itemEnd(url); 43925 43926 }, 0); 43927 43928 return cached; 43929 43930 } 43931 43932 const image = createElementNS('img'); 43933 43934 function onImageLoad() { 43935 43936 removeEventListeners(); 43937 43938 Cache.add(url, this); 43939 43940 if (onLoad) onLoad(this); 43941 43942 scope.manager.itemEnd(url); 43943 43944 } 43945 43946 function onImageError(event) { 43947 43948 removeEventListeners(); 43949 43950 if (onError) onError(event); 43951 43952 scope.manager.itemError(url); 43953 scope.manager.itemEnd(url); 43954 43955 } 43956 43957 function removeEventListeners() { 43958 43959 image.removeEventListener('load', onImageLoad, false); 43960 image.removeEventListener('error', onImageError, false); 43961 43962 } 43963 43964 image.addEventListener('load', onImageLoad, false); 43965 image.addEventListener('error', onImageError, false); 43966 43967 if (url.slice(0, 5) !== 'data:') { 43968 43969 if (this.crossOrigin !== undefined) image.crossOrigin = this.crossOrigin; 43970 43971 } 43972 43973 scope.manager.itemStart(url); 43974 43975 image.src = url; 43976 43977 return image; 43978 43979 } 43980 43981} 43982 43983class CubeTextureLoader extends Loader { 43984 43985 constructor(manager) { 43986 43987 super(manager); 43988 43989 } 43990 43991 load(urls, onLoad, onProgress, onError) { 43992 43993 const texture = new CubeTexture(); 43994 texture.colorSpace = SRGBColorSpace; 43995 43996 const loader = new ImageLoader(this.manager); 43997 loader.setCrossOrigin(this.crossOrigin); 43998 loader.setPath(this.path); 43999 44000 let loaded = 0; 44001 44002 function loadTexture(i) { 44003 44004 loader.load(urls[i], function (image) { 44005 44006 texture.images[i] = image; 44007 44008 loaded++; 44009 44010 if (loaded === 6) { 44011 44012 texture.needsUpdate = true; 44013 44014 if (onLoad) onLoad(texture); 44015 44016 } 44017 44018 }, undefined, onError); 44019 44020 } 44021 44022 for (let i = 0; i < urls.length; ++i) { 44023 44024 loadTexture(i); 44025 44026 } 44027 44028 return texture; 44029 44030 } 44031 44032} 44033 44034/** 44035 * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) 44036 * 44037 * Sub classes have to implement the parse() method which will be used in load(). 44038 */ 44039 44040class DataTextureLoader extends Loader { 44041 44042 constructor(manager) { 44043 44044 super(manager); 44045 44046 } 44047 44048 load(url, onLoad, onProgress, onError) { 44049 44050 const scope = this; 44051 44052 const texture = new DataTexture(); 44053 44054 const loader = new FileLoader(this.manager); 44055 loader.setResponseType('arraybuffer'); 44056 loader.setRequestHeader(this.requestHeader); 44057 loader.setPath(this.path); 44058 loader.setWithCredentials(scope.withCredentials); 44059 loader.load(url, function (buffer) { 44060 44061 let texData; 44062 44063 try { 44064 44065 texData = scope.parse(buffer); 44066 44067 } catch (error) { 44068 44069 if (onError !== undefined) { 44070 44071 onError(error); 44072 44073 } else { 44074 44075 console.error(error); 44076 return; 44077 44078 } 44079 44080 } 44081 44082 if (texData.image !== undefined) { 44083 44084 texture.image = texData.image; 44085 44086 } else if (texData.data !== undefined) { 44087 44088 texture.image.width = texData.width; 44089 texture.image.height = texData.height; 44090 texture.image.data = texData.data; 44091 44092 } 44093 44094 texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping; 44095 texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping; 44096
vendor: 5,243 bytes, lines 44097-44387
44097 texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter; 44098 texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter; 44099 44100 texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1; 44101 44102 if (texData.colorSpace !== undefined) { 44103 44104 texture.colorSpace = texData.colorSpace; 44105 44106 } else if (texData.encoding !== undefined) { // @deprecated, r152 44107 44108 texture.encoding = texData.encoding; 44109 44110 } 44111 44112 if (texData.flipY !== undefined) { 44113 44114 texture.flipY = texData.flipY; 44115 44116 } 44117 44118 if (texData.format !== undefined) { 44119 44120 texture.format = texData.format; 44121 44122 } 44123 44124 if (texData.type !== undefined) { 44125 44126 texture.type = texData.type; 44127 44128 } 44129 44130 if (texData.mipmaps !== undefined) { 44131 44132 texture.mipmaps = texData.mipmaps; 44133 texture.minFilter = LinearMipmapLinearFilter; // presumably... 44134 44135 } 44136 44137 if (texData.mipmapCount === 1) { 44138 44139 texture.minFilter = LinearFilter; 44140 44141 } 44142 44143 if (texData.generateMipmaps !== undefined) { 44144 44145 texture.generateMipmaps = texData.generateMipmaps; 44146 44147 } 44148 44149 texture.needsUpdate = true; 44150 44151 if (onLoad) onLoad(texture, texData); 44152 44153 }, onProgress, onError); 44154 44155 44156 return texture; 44157 44158 } 44159 44160} 44161 44162class TextureLoader extends Loader { 44163 44164 constructor(manager) { 44165 44166 super(manager); 44167 44168 } 44169 44170 load(url, onLoad, onProgress, onError) { 44171 44172 const texture = new Texture(); 44173 44174 const loader = new ImageLoader(this.manager); 44175 loader.setCrossOrigin(this.crossOrigin); 44176 loader.setPath(this.path); 44177 44178 loader.load(url, function (image) { 44179 44180 texture.image = image; 44181 texture.needsUpdate = true; 44182 44183 if (onLoad !== undefined) { 44184 44185 onLoad(texture); 44186 44187 } 44188 44189 }, onProgress, onError); 44190 44191 return texture; 44192 44193 } 44194 44195} 44196 44197class Light extends Object3D { 44198 44199 constructor(color, intensity = 1) { 44200 44201 super(); 44202 44203 this.isLight = true; 44204 44205 this.type = 'Light'; 44206 44207 this.color = new Color(color); 44208 this.intensity = intensity; 44209 44210 } 44211 44212 dispose() { 44213 44214 // Empty here in base class; some subclasses override. 44215 44216 } 44217 44218 copy(source, recursive) { 44219 44220 super.copy(source, recursive); 44221 44222 this.color.copy(source.color); 44223 this.intensity = source.intensity; 44224 44225 return this; 44226 44227 } 44228 44229 toJSON(meta) { 44230 44231 const data = super.toJSON(meta); 44232 44233 data.object.color = this.color.getHex(); 44234 data.object.intensity = this.intensity; 44235 44236 if (this.groundColor !== undefined) data.object.groundColor = this.groundColor.getHex(); 44237 44238 if (this.distance !== undefined) data.object.distance = this.distance; 44239 if (this.angle !== undefined) data.object.angle = this.angle; 44240 if (this.decay !== undefined) data.object.decay = this.decay; 44241 if (this.penumbra !== undefined) data.object.penumbra = this.penumbra; 44242 44243 if (this.shadow !== undefined) data.object.shadow = this.shadow.toJSON(); 44244 44245 return data; 44246 44247 } 44248 44249} 44250 44251class HemisphereLight extends Light { 44252 44253 constructor(skyColor, groundColor, intensity) { 44254 44255 super(skyColor, intensity); 44256 44257 this.isHemisphereLight = true; 44258 44259 this.type = 'HemisphereLight'; 44260 44261 this.position.copy(Object3D.DEFAULT_UP); 44262 this.updateMatrix(); 44263 44264 this.groundColor = new Color(groundColor); 44265 44266 } 44267 44268 copy(source, recursive) { 44269 44270 super.copy(source, recursive); 44271 44272 this.groundColor.copy(source.groundColor); 44273 44274 return this; 44275 44276 } 44277 44278} 44279 44280const _projScreenMatrix$1 = /*@__PURE__*/ new Matrix4(); 44281const _lightPositionWorld$1 = /*@__PURE__*/ new Vector3(); 44282const _lookTarget$1 = /*@__PURE__*/ new Vector3(); 44283 44284class LightShadow { 44285 44286 constructor(camera) { 44287 44288 this.camera = camera; 44289 44290 this.bias = 0; 44291 this.normalBias = 0; 44292 this.radius = 1; 44293 this.blurSamples = 8; 44294 44295 this.mapSize = new Vector2(512, 512); 44296 44297 this.map = null; 44298 this.mapPass = null; 44299 this.matrix = new Matrix4(); 44300 44301 this.autoUpdate = true; 44302 this.needsUpdate = false; 44303 44304 this._frustum = new Frustum(); 44305 this._frameExtents = new Vector2(1, 1); 44306 44307 this._viewportCount = 1; 44308 44309 this._viewports = [ 44310 44311 new Vector4(0, 0, 1, 1) 44312 44313 ]; 44314 44315 } 44316 44317 getViewportCount() { 44318 44319 return this._viewportCount; 44320 44321 } 44322 44323 getFrustum() { 44324 44325 return this._frustum; 44326 44327 } 44328 44329 updateMatrices(light) { 44330 44331 const shadowCamera = this.camera; 44332 const shadowMatrix = this.matrix; 44333 44334 _lightPositionWorld$1.setFromMatrixPosition(light.matrixWorld); 44335 shadowCamera.position.copy(_lightPositionWorld$1); 44336 44337 _lookTarget$1.setFromMatrixPosition(light.target.matrixWorld); 44338 shadowCamera.lookAt(_lookTarget$1); 44339 shadowCamera.updateMatrixWorld(); 44340 44341 _projScreenMatrix$1.multiplyMatrices(shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse); 44342 this._frustum.setFromProjectionMatrix(_projScreenMatrix$1); 44343 44344 shadowMatrix.set( 44345 0.5, 0.0, 0.0, 0.5, 44346 0.0, 0.5, 0.0, 0.5, 44347 0.0, 0.0, 0.5, 0.5, 44348 0.0, 0.0, 0.0, 1.0 44349 ); 44350 44351 shadowMatrix.multiply(_projScreenMatrix$1); 44352 44353 } 44354 44355 getViewport(viewportIndex) { 44356 44357 return this._viewports[viewportIndex]; 44358 44359 } 44360 44361 getFrameExtents() { 44362 44363 return this._frameExtents; 44364 44365 } 44366 44367 dispose() { 44368 44369 if (this.map) { 44370 44371 this.map.dispose(); 44372 44373 } 44374 44375 if (this.mapPass) { 44376 44377 this.mapPass.dispose(); 44378 44379 } 44380 44381 } 44382 44383 copy(source) { 44384 44385 this.camera = source.camera.clone(); 44386 44387 this.bias = source.bias;
vendor: 5,877 bytes, lines 44388-44675
44388 this.radius = source.radius; 44389 44390 this.mapSize.copy(source.mapSize); 44391 44392 return this; 44393 44394 } 44395 44396 clone() { 44397 44398 return new this.constructor().copy(this); 44399 44400 } 44401 44402 toJSON() { 44403 44404 const object = {}; 44405 44406 if (this.bias !== 0) object.bias = this.bias; 44407 if (this.normalBias !== 0) object.normalBias = this.normalBias; 44408 if (this.radius !== 1) object.radius = this.radius; 44409 if (this.mapSize.x !== 512 || this.mapSize.y !== 512) object.mapSize = this.mapSize.toArray(); 44410 44411 object.camera = this.camera.toJSON(false).object; 44412 delete object.camera.matrix; 44413 44414 return object; 44415 44416 } 44417 44418} 44419 44420class SpotLightShadow extends LightShadow { 44421 44422 constructor() { 44423 44424 super(new PerspectiveCamera(50, 1, 0.5, 500)); 44425 44426 this.isSpotLightShadow = true; 44427 44428 this.focus = 1; 44429 44430 } 44431 44432 updateMatrices(light) { 44433 44434 const camera = this.camera; 44435 44436 const fov = RAD2DEG * 2 * light.angle * this.focus; 44437 const aspect = this.mapSize.width / this.mapSize.height; 44438 const far = light.distance || camera.far; 44439 44440 if (fov !== camera.fov || aspect !== camera.aspect || far !== camera.far) { 44441 44442 camera.fov = fov; 44443 camera.aspect = aspect; 44444 camera.far = far; 44445 camera.updateProjectionMatrix(); 44446 44447 } 44448 44449 super.updateMatrices(light); 44450 44451 } 44452 44453 copy(source) { 44454 44455 super.copy(source); 44456 44457 this.focus = source.focus; 44458 44459 return this; 44460 44461 } 44462 44463} 44464 44465class SpotLight extends Light { 44466 44467 constructor(color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 2) { 44468 44469 super(color, intensity); 44470 44471 this.isSpotLight = true; 44472 44473 this.type = 'SpotLight'; 44474 44475 this.position.copy(Object3D.DEFAULT_UP); 44476 this.updateMatrix(); 44477 44478 this.target = new Object3D(); 44479 44480 this.distance = distance; 44481 this.angle = angle; 44482 this.penumbra = penumbra; 44483 this.decay = decay; 44484 44485 this.map = null; 44486 44487 this.shadow = new SpotLightShadow(); 44488 44489 } 44490 44491 get power() { 44492 44493 // compute the light's luminous power (in lumens) from its intensity (in candela) 44494 // by convention for a spotlight, luminous power (lm) = Ï * luminous intensity (cd) 44495 return this.intensity * Math.PI; 44496 44497 } 44498 44499 set power(power) { 44500 44501 // set the light's intensity (in candela) from the desired luminous power (in lumens) 44502 this.intensity = power / Math.PI; 44503 44504 } 44505 44506 dispose() { 44507 44508 this.shadow.dispose(); 44509 44510 } 44511 44512 copy(source, recursive) { 44513 44514 super.copy(source, recursive); 44515 44516 this.distance = source.distance; 44517 this.angle = source.angle; 44518 this.penumbra = source.penumbra; 44519 this.decay = source.decay; 44520 44521 this.target = source.target.clone(); 44522 44523 this.shadow = source.shadow.clone(); 44524 44525 return this; 44526 44527 } 44528 44529} 44530 44531const _projScreenMatrix = /*@__PURE__*/ new Matrix4(); 44532const _lightPositionWorld = /*@__PURE__*/ new Vector3(); 44533const _lookTarget = /*@__PURE__*/ new Vector3(); 44534 44535class PointLightShadow extends LightShadow { 44536 44537 constructor() { 44538 44539 super(new PerspectiveCamera(90, 1, 0.5, 500)); 44540 44541 this.isPointLightShadow = true; 44542 44543 this._frameExtents = new Vector2(4, 2); 44544 44545 this._viewportCount = 6; 44546 44547 this._viewports = [ 44548 // These viewports map a cube-map onto a 2D texture with the 44549 // following orientation: 44550 // 44551 // xzXZ 44552 // y Y 44553 // 44554 // X - Positive x direction 44555 // x - Negative x direction 44556 // Y - Positive y direction 44557 // y - Negative y direction 44558 // Z - Positive z direction 44559 // z - Negative z direction 44560 44561 // positive X 44562 new Vector4(2, 1, 1, 1), 44563 // negative X 44564 new Vector4(0, 1, 1, 1), 44565 // positive Z 44566 new Vector4(3, 1, 1, 1), 44567 // negative Z 44568 new Vector4(1, 1, 1, 1), 44569 // positive Y 44570 new Vector4(3, 0, 1, 1), 44571 // negative Y 44572 new Vector4(1, 0, 1, 1) 44573 ]; 44574 44575 this._cubeDirections = [ 44576 new Vector3(1, 0, 0), new Vector3(- 1, 0, 0), new Vector3(0, 0, 1), 44577 new Vector3(0, 0, - 1), new Vector3(0, 1, 0), new Vector3(0, - 1, 0) 44578 ]; 44579 44580 this._cubeUps = [ 44581 new Vector3(0, 1, 0), new Vector3(0, 1, 0), new Vector3(0, 1, 0), 44582 new Vector3(0, 1, 0), new Vector3(0, 0, 1), new Vector3(0, 0, - 1) 44583 ]; 44584 44585 } 44586 44587 updateMatrices(light, viewportIndex = 0) { 44588 44589 const camera = this.camera; 44590 const shadowMatrix = this.matrix; 44591 44592 const far = light.distance || camera.far; 44593 44594 if (far !== camera.far) { 44595 44596 camera.far = far; 44597 camera.updateProjectionMatrix(); 44598 44599 } 44600 44601 _lightPositionWorld.setFromMatrixPosition(light.matrixWorld); 44602 camera.position.copy(_lightPositionWorld); 44603 44604 _lookTarget.copy(camera.position); 44605 _lookTarget.add(this._cubeDirections[viewportIndex]); 44606 camera.up.copy(this._cubeUps[viewportIndex]); 44607 camera.lookAt(_lookTarget); 44608 camera.updateMatrixWorld(); 44609 44610 shadowMatrix.makeTranslation(- _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z); 44611 44612 _projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse); 44613 this._frustum.setFromProjectionMatrix(_projScreenMatrix); 44614 44615 } 44616 44617} 44618 44619class PointLight extends Light { 44620 44621 constructor(color, intensity, distance = 0, decay = 2) { 44622 44623 super(color, intensity); 44624 44625 this.isPointLight = true; 44626 44627 this.type = 'PointLight'; 44628 44629 this.distance = distance; 44630 this.decay = decay; 44631 44632 this.shadow = new PointLightShadow(); 44633 44634 } 44635 44636 get power() { 44637 44638 // compute the light's luminous power (in lumens) from its intensity (in candela) 44639 // for an isotropic light source, luminous power (lm) = 4 Ï luminous intensity (cd) 44640 return this.intensity * 4 * Math.PI; 44641 44642 } 44643 44644 set power(power) { 44645 44646 // set the light's intensity (in candela) from the desired luminous power (in lumens) 44647 this.intensity = power / (4 * Math.PI); 44648 44649 } 44650 44651 dispose() { 44652 44653 this.shadow.dispose(); 44654 44655 } 44656 44657 copy(source, recursive) { 44658 44659 super.copy(source, recursive); 44660 44661 this.distance = source.distance; 44662 this.decay = source.decay; 44663 44664 this.shadow = source.shadow.clone(); 44665 44666 return this; 44667 44668 } 44669 44670} 44671 44672class DirectionalLightShadow extends LightShadow { 44673 44674 constructor() { 44675
vendor: 4,346 bytes, lines 44676-44897
44676 super(new OrthographicCamera(- 5, 5, 5, - 5, 0.5, 500)); 44677 44678 this.isDirectionalLightShadow = true; 44679 44680 } 44681 44682} 44683 44684class DirectionalLight extends Light { 44685 44686 constructor(color, intensity) { 44687 44688 super(color, intensity); 44689 44690 this.isDirectionalLight = true; 44691 44692 this.type = 'DirectionalLight'; 44693 44694 this.position.copy(Object3D.DEFAULT_UP); 44695 this.updateMatrix(); 44696 44697 this.target = new Object3D(); 44698 44699 this.shadow = new DirectionalLightShadow(); 44700 44701 } 44702 44703 dispose() { 44704 44705 this.shadow.dispose(); 44706 44707 } 44708 44709 copy(source) { 44710 44711 super.copy(source); 44712 44713 this.target = source.target.clone(); 44714 this.shadow = source.shadow.clone(); 44715 44716 return this; 44717 44718 } 44719 44720} 44721 44722class AmbientLight extends Light { 44723 44724 constructor(color, intensity) { 44725 44726 super(color, intensity); 44727 44728 this.isAmbientLight = true; 44729 44730 this.type = 'AmbientLight'; 44731 44732 } 44733 44734} 44735 44736class RectAreaLight extends Light { 44737 44738 constructor(color, intensity, width = 10, height = 10) { 44739 44740 super(color, intensity); 44741 44742 this.isRectAreaLight = true; 44743 44744 this.type = 'RectAreaLight'; 44745 44746 this.width = width; 44747 this.height = height; 44748 44749 } 44750 44751 get power() { 44752 44753 // compute the light's luminous power (in lumens) from its intensity (in nits) 44754 return this.intensity * this.width * this.height * Math.PI; 44755 44756 } 44757 44758 set power(power) { 44759 44760 // set the light's intensity (in nits) from the desired luminous power (in lumens) 44761 this.intensity = power / (this.width * this.height * Math.PI); 44762 44763 } 44764 44765 copy(source) { 44766 44767 super.copy(source); 44768 44769 this.width = source.width; 44770 this.height = source.height; 44771 44772 return this; 44773 44774 } 44775 44776 toJSON(meta) { 44777 44778 const data = super.toJSON(meta); 44779 44780 data.object.width = this.width; 44781 data.object.height = this.height; 44782 44783 return data; 44784 44785 } 44786 44787} 44788 44789/** 44790 * Primary reference: 44791 * https://graphics.stanford.edu/papers/envmap/envmap.pdf 44792 * 44793 * Secondary reference: 44794 * https://www.ppsloan.org/publications/StupidSH36.pdf 44795 */ 44796 44797// 3-band SH defined by 9 coefficients 44798 44799class SphericalHarmonics3 { 44800 44801 constructor() { 44802 44803 this.isSphericalHarmonics3 = true; 44804 44805 this.coefficients = []; 44806 44807 for (let i = 0; i < 9; i++) { 44808 44809 this.coefficients.push(new Vector3()); 44810 44811 } 44812 44813 } 44814 44815 set(coefficients) { 44816 44817 for (let i = 0; i < 9; i++) { 44818 44819 this.coefficients[i].copy(coefficients[i]); 44820 44821 } 44822 44823 return this; 44824 44825 } 44826 44827 zero() { 44828 44829 for (let i = 0; i < 9; i++) { 44830 44831 this.coefficients[i].set(0, 0, 0); 44832 44833 } 44834 44835 return this; 44836 44837 } 44838 44839 // get the radiance in the direction of the normal 44840 // target is a Vector3 44841 getAt(normal, target) { 44842 44843 // normal is assumed to be unit length 44844 44845 const x = normal.x, y = normal.y, z = normal.z; 44846 44847 const coeff = this.coefficients; 44848 44849 // band 0 44850 target.copy(coeff[0]).multiplyScalar(0.282095); 44851 44852 // band 1 44853 target.addScaledVector(coeff[1], 0.488603 * y); 44854 target.addScaledVector(coeff[2], 0.488603 * z); 44855 target.addScaledVector(coeff[3], 0.488603 * x); 44856 44857 // band 2 44858 target.addScaledVector(coeff[4], 1.092548 * (x * y)); 44859 target.addScaledVector(coeff[5], 1.092548 * (y * z)); 44860 target.addScaledVector(coeff[6], 0.315392 * (3.0 * z * z - 1.0)); 44861 target.addScaledVector(coeff[7], 1.092548 * (x * z)); 44862 target.addScaledVector(coeff[8], 0.546274 * (x * x - y * y)); 44863 44864 return target; 44865 44866 } 44867 44868 // get the irradiance (radiance convolved with cosine lobe) in the direction of the normal 44869 // target is a Vector3 44870 // https://graphics.stanford.edu/papers/envmap/envmap.pdf 44871 getIrradianceAt(normal, target) { 44872 44873 // normal is assumed to be unit length 44874 44875 const x = normal.x, y = normal.y, z = normal.z; 44876 44877 const coeff = this.coefficients; 44878 44879 // band 0 44880 target.copy(coeff[0]).multiplyScalar(0.886227); // Ï * 0.282095 44881 44882 // band 1 44883 target.addScaledVector(coeff[1], 2.0 * 0.511664 * y); // ( 2 * Ï / 3 ) * 0.488603 44884 target.addScaledVector(coeff[2], 2.0 * 0.511664 * z); 44885 target.addScaledVector(coeff[3], 2.0 * 0.511664 * x); 44886 44887 // band 2 44888 target.addScaledVector(coeff[4], 2.0 * 0.429043 * x * y); // ( Ï / 4 ) * 1.092548 44889 target.addScaledVector(coeff[5], 2.0 * 0.429043 * y * z); 44890 target.addScaledVector(coeff[6], 0.743125 * z * z - 0.247708); // ( Ï / 4 ) * 0.315392 * 3 44891 target.addScaledVector(coeff[7], 2.0 * 0.429043 * x * z); 44892 target.addScaledVector(coeff[8], 0.429043 * (x * x - y * y)); // ( Ï / 4 ) * 0.546274 44893 44894 return target; 44895 44896 } 44897
vendor: 24,027 bytes, lines 44898-45786
44898 add(sh) { 44899 44900 for (let i = 0; i < 9; i++) { 44901 44902 this.coefficients[i].add(sh.coefficients[i]); 44903 44904 } 44905 44906 return this; 44907 44908 } 44909 44910 addScaledSH(sh, s) { 44911 44912 for (let i = 0; i < 9; i++) { 44913 44914 this.coefficients[i].addScaledVector(sh.coefficients[i], s); 44915 44916 } 44917 44918 return this; 44919 44920 } 44921 44922 scale(s) { 44923 44924 for (let i = 0; i < 9; i++) { 44925 44926 this.coefficients[i].multiplyScalar(s); 44927 44928 } 44929 44930 return this; 44931 44932 } 44933 44934 lerp(sh, alpha) { 44935 44936 for (let i = 0; i < 9; i++) { 44937 44938 this.coefficients[i].lerp(sh.coefficients[i], alpha); 44939 44940 } 44941 44942 return this; 44943 44944 } 44945 44946 equals(sh) { 44947 44948 for (let i = 0; i < 9; i++) { 44949 44950 if (!this.coefficients[i].equals(sh.coefficients[i])) { 44951 44952 return false; 44953 44954 } 44955 44956 } 44957 44958 return true; 44959 44960 } 44961 44962 copy(sh) { 44963 44964 return this.set(sh.coefficients); 44965 44966 } 44967 44968 clone() { 44969 44970 return new this.constructor().copy(this); 44971 44972 } 44973 44974 fromArray(array, offset = 0) { 44975 44976 const coefficients = this.coefficients; 44977 44978 for (let i = 0; i < 9; i++) { 44979 44980 coefficients[i].fromArray(array, offset + (i * 3)); 44981 44982 } 44983 44984 return this; 44985 44986 } 44987 44988 toArray(array = [], offset = 0) { 44989 44990 const coefficients = this.coefficients; 44991 44992 for (let i = 0; i < 9; i++) { 44993 44994 coefficients[i].toArray(array, offset + (i * 3)); 44995 44996 } 44997 44998 return array; 44999 45000 } 45001 45002 // evaluate the basis functions 45003 // shBasis is an Array[ 9 ] 45004 static getBasisAt(normal, shBasis) { 45005 45006 // normal is assumed to be unit length 45007 45008 const x = normal.x, y = normal.y, z = normal.z; 45009 45010 // band 0 45011 shBasis[0] = 0.282095; 45012 45013 // band 1 45014 shBasis[1] = 0.488603 * y; 45015 shBasis[2] = 0.488603 * z; 45016 shBasis[3] = 0.488603 * x; 45017 45018 // band 2 45019 shBasis[4] = 1.092548 * x * y; 45020 shBasis[5] = 1.092548 * y * z; 45021 shBasis[6] = 0.315392 * (3 * z * z - 1); 45022 shBasis[7] = 1.092548 * x * z; 45023 shBasis[8] = 0.546274 * (x * x - y * y); 45024 45025 } 45026 45027} 45028 45029class LightProbe extends Light { 45030 45031 constructor(sh = new SphericalHarmonics3(), intensity = 1) { 45032 45033 super(undefined, intensity); 45034 45035 this.isLightProbe = true; 45036 45037 this.sh = sh; 45038 45039 } 45040 45041 copy(source) { 45042 45043 super.copy(source); 45044 45045 this.sh.copy(source.sh); 45046 45047 return this; 45048 45049 } 45050 45051 fromJSON(json) { 45052 45053 this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON(); 45054 this.sh.fromArray(json.sh); 45055 45056 return this; 45057 45058 } 45059 45060 toJSON(meta) { 45061 45062 const data = super.toJSON(meta); 45063 45064 data.object.sh = this.sh.toArray(); 45065 45066 return data; 45067 45068 } 45069 45070} 45071 45072class MaterialLoader extends Loader { 45073 45074 constructor(manager) { 45075 45076 super(manager); 45077 this.textures = {}; 45078 45079 } 45080 45081 load(url, onLoad, onProgress, onError) { 45082 45083 const scope = this; 45084 45085 const loader = new FileLoader(scope.manager); 45086 loader.setPath(scope.path); 45087 loader.setRequestHeader(scope.requestHeader); 45088 loader.setWithCredentials(scope.withCredentials); 45089 loader.load(url, function (text) { 45090 45091 try { 45092 45093 onLoad(scope.parse(JSON.parse(text))); 45094 45095 } catch (e) { 45096 45097 if (onError) { 45098 45099 onError(e); 45100 45101 } else { 45102 45103 console.error(e); 45104 45105 } 45106 45107 scope.manager.itemError(url); 45108 45109 } 45110 45111 }, onProgress, onError); 45112 45113 } 45114 45115 parse(json) { 45116 45117 const textures = this.textures; 45118 45119 function getTexture(name) { 45120 45121 if (textures[name] === undefined) { 45122 45123 console.warn('THREE.MaterialLoader: Undefined texture', name); 45124 45125 } 45126 45127 return textures[name]; 45128 45129 } 45130 45131 const material = MaterialLoader.createMaterialFromType(json.type); 45132 45133 if (json.uuid !== undefined) material.uuid = json.uuid; 45134 if (json.name !== undefined) material.name = json.name; 45135 if (json.color !== undefined && material.color !== undefined) material.color.setHex(json.color); 45136 if (json.roughness !== undefined) material.roughness = json.roughness; 45137 if (json.metalness !== undefined) material.metalness = json.metalness; 45138 if (json.sheen !== undefined) material.sheen = json.sheen; 45139 if (json.sheenColor !== undefined) material.sheenColor = new Color().setHex(json.sheenColor); 45140 if (json.sheenRoughness !== undefined) material.sheenRoughness = json.sheenRoughness; 45141 if (json.emissive !== undefined && material.emissive !== undefined) material.emissive.setHex(json.emissive); 45142 if (json.specular !== undefined && material.specular !== undefined) material.specular.setHex(json.specular); 45143 if (json.specularIntensity !== undefined) material.specularIntensity = json.specularIntensity; 45144 if (json.specularColor !== undefined && material.specularColor !== undefined) material.specularColor.setHex(json.specularColor); 45145 if (json.shininess !== undefined) material.shininess = json.shininess; 45146 if (json.clearcoat !== undefined) material.clearcoat = json.clearcoat; 45147 if (json.clearcoatRoughness !== undefined) material.clearcoatRoughness = json.clearcoatRoughness; 45148 if (json.iridescence !== undefined) material.iridescence = json.iridescence; 45149 if (json.iridescenceIOR !== undefined) material.iridescenceIOR = json.iridescenceIOR; 45150 if (json.iridescenceThicknessRange !== undefined) material.iridescenceThicknessRange = json.iridescenceThicknessRange; 45151 if (json.transmission !== undefined) material.transmission = json.transmission; 45152 if (json.thickness !== undefined) material.thickness = json.thickness; 45153 if (json.attenuationDistance !== undefined) material.attenuationDistance = json.attenuationDistance; 45154 if (json.attenuationColor !== undefined && material.attenuationColor !== undefined) material.attenuationColor.setHex(json.attenuationColor); 45155 if (json.anisotropy !== undefined) material.anisotropy = json.anisotropy; 45156 if (json.anisotropyRotation !== undefined) material.anisotropyRotation = json.anisotropyRotation; 45157 if (json.fog !== undefined) material.fog = json.fog; 45158 if (json.flatShading !== undefined) material.flatShading = json.flatShading; 45159 if (json.blending !== undefined) material.blending = json.blending; 45160 if (json.combine !== undefined) material.combine = json.combine; 45161 if (json.side !== undefined) material.side = json.side; 45162 if (json.shadowSide !== undefined) material.shadowSide = json.shadowSide; 45163 if (json.opacity !== undefined) material.opacity = json.opacity; 45164 if (json.transparent !== undefined) material.transparent = json.transparent; 45165 if (json.alphaTest !== undefined) material.alphaTest = json.alphaTest; 45166 if (json.alphaHash !== undefined) material.alphaHash = json.alphaHash; 45167 if (json.depthFunc !== undefined) material.depthFunc = json.depthFunc; 45168 if (json.depthTest !== undefined) material.depthTest = json.depthTest; 45169 if (json.depthWrite !== undefined) material.depthWrite = json.depthWrite; 45170 if (json.colorWrite !== undefined) material.colorWrite = json.colorWrite; 45171 if (json.blendSrc !== undefined) material.blendSrc = json.blendSrc; 45172 if (json.blendDst !== undefined) material.blendDst = json.blendDst; 45173 if (json.blendEquation !== undefined) material.blendEquation = json.blendEquation; 45174 if (json.blendSrcAlpha !== undefined) material.blendSrcAlpha = json.blendSrcAlpha; 45175 if (json.blendDstAlpha !== undefined) material.blendDstAlpha = json.blendDstAlpha; 45176 if (json.blendEquationAlpha !== undefined) material.blendEquationAlpha = json.blendEquationAlpha; 45177 if (json.blendColor !== undefined && material.blendColor !== undefined) material.blendColor.setHex(json.blendColor); 45178 if (json.blendAlpha !== undefined) material.blendAlpha = json.blendAlpha; 45179 if (json.stencilWriteMask !== undefined) material.stencilWriteMask = json.stencilWriteMask; 45180 if (json.stencilFunc !== undefined) material.stencilFunc = json.stencilFunc; 45181 if (json.stencilRef !== undefined) material.stencilRef = json.stencilRef; 45182 if (json.stencilFuncMask !== undefined) material.stencilFuncMask = json.stencilFuncMask; 45183 if (json.stencilFail !== undefined) material.stencilFail = json.stencilFail; 45184 if (json.stencilZFail !== undefined) material.stencilZFail = json.stencilZFail; 45185 if (json.stencilZPass !== undefined) material.stencilZPass = json.stencilZPass; 45186 if (json.stencilWrite !== undefined) material.stencilWrite = json.stencilWrite; 45187 45188 if (json.wireframe !== undefined) material.wireframe = json.wireframe; 45189 if (json.wireframeLinewidth !== undefined) material.wireframeLinewidth = json.wireframeLinewidth; 45190 if (json.wireframeLinecap !== undefined) material.wireframeLinecap = json.wireframeLinecap; 45191 if (json.wireframeLinejoin !== undefined) material.wireframeLinejoin = json.wireframeLinejoin; 45192 45193 if (json.rotation !== undefined) material.rotation = json.rotation; 45194 45195 if (json.linewidth !== undefined) material.linewidth = json.linewidth; 45196 if (json.dashSize !== undefined) material.dashSize = json.dashSize; 45197 if (json.gapSize !== undefined) material.gapSize = json.gapSize; 45198 if (json.scale !== undefined) material.scale = json.scale; 45199 45200 if (json.polygonOffset !== undefined) material.polygonOffset = json.polygonOffset; 45201 if (json.polygonOffsetFactor !== undefined) material.polygonOffsetFactor = json.polygonOffsetFactor; 45202 if (json.polygonOffsetUnits !== undefined) material.polygonOffsetUnits = json.polygonOffsetUnits; 45203 45204 if (json.dithering !== undefined) material.dithering = json.dithering; 45205 45206 if (json.alphaToCoverage !== undefined) material.alphaToCoverage = json.alphaToCoverage; 45207 if (json.premultipliedAlpha !== undefined) material.premultipliedAlpha = json.premultipliedAlpha; 45208 if (json.forceSinglePass !== undefined) material.forceSinglePass = json.forceSinglePass; 45209 45210 if (json.visible !== undefined) material.visible = json.visible; 45211 45212 if (json.toneMapped !== undefined) material.toneMapped = json.toneMapped; 45213 45214 if (json.userData !== undefined) material.userData = json.userData; 45215 45216 if (json.vertexColors !== undefined) { 45217 45218 if (typeof json.vertexColors === 'number') { 45219 45220 material.vertexColors = (json.vertexColors > 0) ? true : false; 45221 45222 } else { 45223 45224 material.vertexColors = json.vertexColors; 45225 45226 } 45227 45228 } 45229 45230 // Shader Material 45231 45232 if (json.uniforms !== undefined) { 45233 45234 for (const name in json.uniforms) { 45235 45236 const uniform = json.uniforms[name]; 45237 45238 material.uniforms[name] = {}; 45239 45240 switch (uniform.type) { 45241 45242 case 't': 45243 material.uniforms[name].value = getTexture(uniform.value); 45244 break; 45245 45246 case 'c': 45247 material.uniforms[name].value = new Color().setHex(uniform.value); 45248 break; 45249 45250 case 'v2': 45251 material.uniforms[name].value = new Vector2().fromArray(uniform.value); 45252 break; 45253 45254 case 'v3': 45255 material.uniforms[name].value = new Vector3().fromArray(uniform.value); 45256 break; 45257 45258 case 'v4': 45259 material.uniforms[name].value = new Vector4().fromArray(uniform.value); 45260 break; 45261 45262 case 'm3': 45263 material.uniforms[name].value = new Matrix3().fromArray(uniform.value); 45264 break; 45265 45266 case 'm4': 45267 material.uniforms[name].value = new Matrix4().fromArray(uniform.value); 45268 break; 45269 45270 default: 45271 material.uniforms[name].value = uniform.value; 45272 45273 } 45274 45275 } 45276 45277 } 45278 45279 if (json.defines !== undefined) material.defines = json.defines; 45280 if (json.vertexShader !== undefined) material.vertexShader = json.vertexShader; 45281 if (json.fragmentShader !== undefined) material.fragmentShader = json.fragmentShader; 45282 if (json.glslVersion !== undefined) material.glslVersion = json.glslVersion; 45283 45284 if (json.extensions !== undefined) { 45285 45286 for (const key in json.extensions) { 45287 45288 material.extensions[key] = json.extensions[key]; 45289 45290 } 45291 45292 } 45293 45294 if (json.lights !== undefined) material.lights = json.lights; 45295 if (json.clipping !== undefined) material.clipping = json.clipping; 45296 45297 // for PointsMaterial 45298 45299 if (json.size !== undefined) material.size = json.size; 45300 if (json.sizeAttenuation !== undefined) material.sizeAttenuation = json.sizeAttenuation; 45301 45302 // maps 45303 45304 if (json.map !== undefined) material.map = getTexture(json.map); 45305 if (json.matcap !== undefined) material.matcap = getTexture(json.matcap); 45306 45307 if (json.alphaMap !== undefined) material.alphaMap = getTexture(json.alphaMap); 45308 45309 if (json.bumpMap !== undefined) material.bumpMap = getTexture(json.bumpMap); 45310 if (json.bumpScale !== undefined) material.bumpScale = json.bumpScale; 45311 45312 if (json.normalMap !== undefined) material.normalMap = getTexture(json.normalMap); 45313 if (json.normalMapType !== undefined) material.normalMapType = json.normalMapType; 45314 if (json.normalScale !== undefined) { 45315 45316 let normalScale = json.normalScale; 45317 45318 if (Array.isArray(normalScale) === false) { 45319 45320 // Blender exporter used to export a scalar. See #7459 45321 45322 normalScale = [normalScale, normalScale]; 45323 45324 } 45325 45326 material.normalScale = new Vector2().fromArray(normalScale); 45327 45328 } 45329 45330 if (json.displacementMap !== undefined) material.displacementMap = getTexture(json.displacementMap); 45331 if (json.displacementScale !== undefined) material.displacementScale = json.displacementScale; 45332 if (json.displacementBias !== undefined) material.displacementBias = json.displacementBias; 45333 45334 if (json.roughnessMap !== undefined) material.roughnessMap = getTexture(json.roughnessMap); 45335 if (json.metalnessMap !== undefined) material.metalnessMap = getTexture(json.metalnessMap); 45336 45337 if (json.emissiveMap !== undefined) material.emissiveMap = getTexture(json.emissiveMap); 45338 if (json.emissiveIntensity !== undefined) material.emissiveIntensity = json.emissiveIntensity; 45339 45340 if (json.specularMap !== undefined) material.specularMap = getTexture(json.specularMap); 45341 if (json.specularIntensityMap !== undefined) material.specularIntensityMap = getTexture(json.specularIntensityMap); 45342 if (json.specularColorMap !== undefined) material.specularColorMap = getTexture(json.specularColorMap); 45343 45344 if (json.envMap !== undefined) material.envMap = getTexture(json.envMap); 45345 if (json.envMapIntensity !== undefined) material.envMapIntensity = json.envMapIntensity; 45346 45347 if (json.reflectivity !== undefined) material.reflectivity = json.reflectivity; 45348 if (json.refractionRatio !== undefined) material.refractionRatio = json.refractionRatio; 45349 45350 if (json.lightMap !== undefined) material.lightMap = getTexture(json.lightMap); 45351 if (json.lightMapIntensity !== undefined) material.lightMapIntensity = json.lightMapIntensity; 45352 45353 if (json.aoMap !== undefined) material.aoMap = getTexture(json.aoMap); 45354 if (json.aoMapIntensity !== undefined) material.aoMapIntensity = json.aoMapIntensity; 45355 45356 if (json.gradientMap !== undefined) material.gradientMap = getTexture(json.gradientMap); 45357 45358 if (json.clearcoatMap !== undefined) material.clearcoatMap = getTexture(json.clearcoatMap); 45359 if (json.clearcoatRoughnessMap !== undefined) material.clearcoatRoughnessMap = getTexture(json.clearcoatRoughnessMap); 45360 if (json.clearcoatNormalMap !== undefined) material.clearcoatNormalMap = getTexture(json.clearcoatNormalMap); 45361 if (json.clearcoatNormalScale !== undefined) material.clearcoatNormalScale = new Vector2().fromArray(json.clearcoatNormalScale); 45362 45363 if (json.iridescenceMap !== undefined) material.iridescenceMap = getTexture(json.iridescenceMap); 45364 if (json.iridescenceThicknessMap !== undefined) material.iridescenceThicknessMap = getTexture(json.iridescenceThicknessMap); 45365 45366 if (json.transmissionMap !== undefined) material.transmissionMap = getTexture(json.transmissionMap); 45367 if (json.thicknessMap !== undefined) material.thicknessMap = getTexture(json.thicknessMap); 45368 45369 if (json.anisotropyMap !== undefined) material.anisotropyMap = getTexture(json.anisotropyMap); 45370 45371 if (json.sheenColorMap !== undefined) material.sheenColorMap = getTexture(json.sheenColorMap); 45372 if (json.sheenRoughnessMap !== undefined) material.sheenRoughnessMap = getTexture(json.sheenRoughnessMap); 45373 45374 return material; 45375 45376 } 45377 45378 setTextures(value) { 45379 45380 this.textures = value; 45381 return this; 45382 45383 } 45384 45385 static createMaterialFromType(type) { 45386 45387 const materialLib = { 45388 ShadowMaterial, 45389 SpriteMaterial, 45390 RawShaderMaterial, 45391 ShaderMaterial, 45392 PointsMaterial, 45393 MeshPhysicalMaterial, 45394 MeshStandardMaterial, 45395 MeshPhongMaterial, 45396 MeshToonMaterial, 45397 MeshNormalMaterial, 45398 MeshLambertMaterial, 45399 MeshDepthMaterial, 45400 MeshDistanceMaterial, 45401 MeshBasicMaterial, 45402 MeshMatcapMaterial, 45403 LineDashedMaterial, 45404 LineBasicMaterial, 45405 Material 45406 }; 45407 45408 return new materialLib[type](); 45409 45410 } 45411 45412} 45413 45414class LoaderUtils { 45415 45416 static decodeText(array) { 45417 45418 if (typeof TextDecoder !== 'undefined') { 45419 45420 return new TextDecoder().decode(array); 45421 45422 } 45423 45424 // Avoid the String.fromCharCode.apply(null, array) shortcut, which 45425 // throws a "maximum call stack size exceeded" error for large arrays. 45426 45427 let s = ''; 45428 45429 for (let i = 0, il = array.length; i < il; i++) { 45430 45431 // Implicitly assumes little-endian. 45432 s += String.fromCharCode(array[i]); 45433 45434 } 45435 45436 try { 45437 45438 // merges multi-byte utf-8 characters. 45439 45440 return decodeURIComponent(escape(s)); 45441 45442 } catch (e) { // see #16358 45443 45444 return s; 45445 45446 } 45447 45448 } 45449 45450 static extractUrlBase(url) { 45451 45452 const index = url.lastIndexOf('/'); 45453 45454 if (index === - 1) return './'; 45455 45456 return url.slice(0, index + 1); 45457 45458 } 45459 45460 static resolveURL(url, path) { 45461 45462 // Invalid URL 45463 if (typeof url !== 'string' || url === '') return ''; 45464 45465 // Host Relative URL 45466 if (/^https?:\/\//i.test(path) && /^\//.test(url)) { 45467 45468 path = path.replace(/(^https?:\/\/[^\/]+).*/i, '$1'); 45469 45470 } 45471 45472 // Absolute URL http://,https://,// 45473 if (/^(https?:)?\/\//i.test(url)) return url; 45474 45475 // Data URI 45476 if (/^data:.*,.*$/i.test(url)) return url; 45477 45478 // Blob URL 45479 if (/^blob:.*$/i.test(url)) return url; 45480 45481 // Relative URL 45482 return path + url; 45483 45484 } 45485 45486} 45487 45488class InstancedBufferGeometry extends BufferGeometry { 45489 45490 constructor() { 45491 45492 super(); 45493 45494 this.isInstancedBufferGeometry = true; 45495 45496 this.type = 'InstancedBufferGeometry'; 45497 this.instanceCount = Infinity; 45498 45499 } 45500 45501 copy(source) { 45502 45503 super.copy(source); 45504 45505 this.instanceCount = source.instanceCount; 45506 45507 return this; 45508 45509 } 45510 45511 toJSON() { 45512 45513 const data = super.toJSON(); 45514 45515 data.instanceCount = this.instanceCount; 45516 45517 data.isInstancedBufferGeometry = true; 45518 45519 return data; 45520 45521 } 45522 45523} 45524 45525class BufferGeometryLoader extends Loader { 45526 45527 constructor(manager) { 45528 45529 super(manager); 45530 45531 } 45532 45533 load(url, onLoad, onProgress, onError) { 45534 45535 const scope = this; 45536 45537 const loader = new FileLoader(scope.manager); 45538 loader.setPath(scope.path); 45539 loader.setRequestHeader(scope.requestHeader); 45540 loader.setWithCredentials(scope.withCredentials); 45541 loader.load(url, function (text) { 45542 45543 try { 45544 45545 onLoad(scope.parse(JSON.parse(text))); 45546 45547 } catch (e) { 45548 45549 if (onError) { 45550 45551 onError(e); 45552 45553 } else { 45554 45555 console.error(e); 45556 45557 } 45558 45559 scope.manager.itemError(url); 45560 45561 } 45562 45563 }, onProgress, onError); 45564 45565 } 45566 45567 parse(json) { 45568 45569 const interleavedBufferMap = {}; 45570 const arrayBufferMap = {}; 45571 45572 function getInterleavedBuffer(json, uuid) { 45573 45574 if (interleavedBufferMap[uuid] !== undefined) return interleavedBufferMap[uuid]; 45575 45576 const interleavedBuffers = json.interleavedBuffers; 45577 const interleavedBuffer = interleavedBuffers[uuid]; 45578 45579 const buffer = getArrayBuffer(json, interleavedBuffer.buffer); 45580 45581 const array = getTypedArray(interleavedBuffer.type, buffer); 45582 const ib = new InterleavedBuffer(array, interleavedBuffer.stride); 45583 ib.uuid = interleavedBuffer.uuid; 45584 45585 interleavedBufferMap[uuid] = ib; 45586 45587 return ib; 45588 45589 } 45590 45591 function getArrayBuffer(json, uuid) { 45592 45593 if (arrayBufferMap[uuid] !== undefined) return arrayBufferMap[uuid]; 45594 45595 const arrayBuffers = json.arrayBuffers; 45596 const arrayBuffer = arrayBuffers[uuid]; 45597 45598 const ab = new Uint32Array(arrayBuffer).buffer; 45599 45600 arrayBufferMap[uuid] = ab; 45601 45602 return ab; 45603 45604 } 45605 45606 const geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry(); 45607 45608 const index = json.data.index; 45609 45610 if (index !== undefined) { 45611 45612 const typedArray = getTypedArray(index.type, index.array); 45613 geometry.setIndex(new BufferAttribute(typedArray, 1)); 45614 45615 } 45616 45617 const attributes = json.data.attributes; 45618 45619 for (const key in attributes) { 45620 45621 const attribute = attributes[key]; 45622 let bufferAttribute; 45623 45624 if (attribute.isInterleavedBufferAttribute) { 45625 45626 const interleavedBuffer = getInterleavedBuffer(json.data, attribute.data); 45627 bufferAttribute = new InterleavedBufferAttribute(interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized); 45628 45629 } else { 45630 45631 const typedArray = getTypedArray(attribute.type, attribute.array); 45632 const bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute; 45633 bufferAttribute = new bufferAttributeConstr(typedArray, attribute.itemSize, attribute.normalized); 45634 45635 } 45636 45637 if (attribute.name !== undefined) bufferAttribute.name = attribute.name; 45638 if (attribute.usage !== undefined) bufferAttribute.setUsage(attribute.usage); 45639 45640 geometry.setAttribute(key, bufferAttribute); 45641 45642 } 45643 45644 const morphAttributes = json.data.morphAttributes; 45645 45646 if (morphAttributes) { 45647 45648 for (const key in morphAttributes) { 45649 45650 const attributeArray = morphAttributes[key]; 45651 45652 const array = []; 45653 45654 for (let i = 0, il = attributeArray.length; i < il; i++) { 45655 45656 const attribute = attributeArray[i]; 45657 let bufferAttribute; 45658 45659 if (attribute.isInterleavedBufferAttribute) { 45660 45661 const interleavedBuffer = getInterleavedBuffer(json.data, attribute.data); 45662 bufferAttribute = new InterleavedBufferAttribute(interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized); 45663 45664 } else { 45665 45666 const typedArray = getTypedArray(attribute.type, attribute.array); 45667 bufferAttribute = new BufferAttribute(typedArray, attribute.itemSize, attribute.normalized); 45668 45669 } 45670 45671 if (attribute.name !== undefined) bufferAttribute.name = attribute.name; 45672 array.push(bufferAttribute); 45673 45674 } 45675 45676 geometry.morphAttributes[key] = array; 45677 45678 } 45679 45680 } 45681 45682 const morphTargetsRelative = json.data.morphTargetsRelative; 45683 45684 if (morphTargetsRelative) { 45685 45686 geometry.morphTargetsRelative = true; 45687 45688 } 45689 45690 const groups = json.data.groups || json.data.drawcalls || json.data.offsets; 45691 45692 if (groups !== undefined) { 45693 45694 for (let i = 0, n = groups.length; i !== n; ++i) { 45695 45696 const group = groups[i]; 45697 45698 geometry.addGroup(group.start, group.count, group.materialIndex); 45699 45700 } 45701 45702 } 45703 45704 const boundingSphere = json.data.boundingSphere; 45705 45706 if (boundingSphere !== undefined) { 45707 45708 const center = new Vector3(); 45709 45710 if (boundingSphere.center !== undefined) { 45711 45712 center.fromArray(boundingSphere.center); 45713 45714 } 45715 45716 geometry.boundingSphere = new Sphere(center, boundingSphere.radius); 45717 45718 } 45719 45720 if (json.name) geometry.name = json.name; 45721 if (json.userData) geometry.userData = json.userData; 45722 45723 return geometry; 45724 45725 } 45726 45727} 45728 45729class ObjectLoader extends Loader { 45730 45731 constructor(manager) { 45732 45733 super(manager); 45734 45735 } 45736 45737 load(url, onLoad, onProgress, onError) { 45738 45739 const scope = this; 45740 45741 const path = (this.path === '') ? LoaderUtils.extractUrlBase(url) : this.path; 45742 this.resourcePath = this.resourcePath || path; 45743 45744 const loader = new FileLoader(this.manager); 45745 loader.setPath(this.path); 45746 loader.setRequestHeader(this.requestHeader); 45747 loader.setWithCredentials(this.withCredentials); 45748 loader.load(url, function (text) { 45749 45750 let json = null; 45751 45752 try { 45753 45754 json = JSON.parse(text); 45755 45756 } catch (error) { 45757 45758 if (onError !== undefined) onError(error); 45759 45760 console.error('THREE:ObjectLoader: Can\'t parse ' + url + '.', error.message); 45761 45762 return; 45763 45764 } 45765 45766 const metadata = json.metadata; 45767 45768 if (metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry') { 45769 45770 if (onError !== undefined) onError(new Error('THREE.ObjectLoader: Can\'t load ' + url)); 45771 45772 console.error('THREE.ObjectLoader: Can\'t load ' + url); 45773 return; 45774 45775 } 45776 45777 scope.parse(json, onLoad); 45778 45779 }, onProgress, onError); 45780 45781 } 45782 45783 async loadAsync(url, onProgress) { 45784 45785 const scope = this; 45786
vendor: 7,138 bytes, lines 45787-46160
45787 const path = (this.path === '') ? LoaderUtils.extractUrlBase(url) : this.path; 45788 this.resourcePath = this.resourcePath || path; 45789 45790 const loader = new FileLoader(this.manager); 45791 loader.setPath(this.path); 45792 loader.setRequestHeader(this.requestHeader); 45793 loader.setWithCredentials(this.withCredentials); 45794 45795 const text = await loader.loadAsync(url, onProgress); 45796 45797 const json = JSON.parse(text); 45798 45799 const metadata = json.metadata; 45800 45801 if (metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry') { 45802 45803 throw new Error('THREE.ObjectLoader: Can\'t load ' + url); 45804 45805 } 45806 45807 return await scope.parseAsync(json); 45808 45809 } 45810 45811 parse(json, onLoad) { 45812 45813 const animations = this.parseAnimations(json.animations); 45814 const shapes = this.parseShapes(json.shapes); 45815 const geometries = this.parseGeometries(json.geometries, shapes); 45816 45817 const images = this.parseImages(json.images, function () { 45818 45819 if (onLoad !== undefined) onLoad(object); 45820 45821 }); 45822 45823 const textures = this.parseTextures(json.textures, images); 45824 const materials = this.parseMaterials(json.materials, textures); 45825 45826 const object = this.parseObject(json.object, geometries, materials, textures, animations); 45827 const skeletons = this.parseSkeletons(json.skeletons, object); 45828 45829 this.bindSkeletons(object, skeletons); 45830 45831 // 45832 45833 if (onLoad !== undefined) { 45834 45835 let hasImages = false; 45836 45837 for (const uuid in images) { 45838 45839 if (images[uuid].data instanceof HTMLImageElement) { 45840 45841 hasImages = true; 45842 break; 45843 45844 } 45845 45846 } 45847 45848 if (hasImages === false) onLoad(object); 45849 45850 } 45851 45852 return object; 45853 45854 } 45855 45856 async parseAsync(json) { 45857 45858 const animations = this.parseAnimations(json.animations); 45859 const shapes = this.parseShapes(json.shapes); 45860 const geometries = this.parseGeometries(json.geometries, shapes); 45861 45862 const images = await this.parseImagesAsync(json.images); 45863 45864 const textures = this.parseTextures(json.textures, images); 45865 const materials = this.parseMaterials(json.materials, textures); 45866 45867 const object = this.parseObject(json.object, geometries, materials, textures, animations); 45868 const skeletons = this.parseSkeletons(json.skeletons, object); 45869 45870 this.bindSkeletons(object, skeletons); 45871 45872 return object; 45873 45874 } 45875 45876 parseShapes(json) { 45877 45878 const shapes = {}; 45879 45880 if (json !== undefined) { 45881 45882 for (let i = 0, l = json.length; i < l; i++) { 45883 45884 const shape = new Shape().fromJSON(json[i]); 45885 45886 shapes[shape.uuid] = shape; 45887 45888 } 45889 45890 } 45891 45892 return shapes; 45893 45894 } 45895 45896 parseSkeletons(json, object) { 45897 45898 const skeletons = {}; 45899 const bones = {}; 45900 45901 // generate bone lookup table 45902 45903 object.traverse(function (child) { 45904 45905 if (child.isBone) bones[child.uuid] = child; 45906 45907 }); 45908 45909 // create skeletons 45910 45911 if (json !== undefined) { 45912 45913 for (let i = 0, l = json.length; i < l; i++) { 45914 45915 const skeleton = new Skeleton().fromJSON(json[i], bones); 45916 45917 skeletons[skeleton.uuid] = skeleton; 45918 45919 } 45920 45921 } 45922 45923 return skeletons; 45924 45925 } 45926 45927 parseGeometries(json, shapes) { 45928 45929 const geometries = {}; 45930 45931 if (json !== undefined) { 45932 45933 const bufferGeometryLoader = new BufferGeometryLoader(); 45934 45935 for (let i = 0, l = json.length; i < l; i++) { 45936 45937 let geometry; 45938 const data = json[i]; 45939 45940 switch (data.type) { 45941 45942 case 'BufferGeometry': 45943 case 'InstancedBufferGeometry': 45944 45945 geometry = bufferGeometryLoader.parse(data); 45946 break; 45947 45948 default: 45949 45950 if (data.type in Geometries) { 45951 45952 geometry = Geometries[data.type].fromJSON(data, shapes); 45953 45954 } else { 45955 45956 console.warn(`THREE.ObjectLoader: Unsupported geometry type "${data.type}"`); 45957 45958 } 45959 45960 } 45961 45962 geometry.uuid = data.uuid; 45963 45964 if (data.name !== undefined) geometry.name = data.name; 45965 if (data.userData !== undefined) geometry.userData = data.userData; 45966 45967 geometries[data.uuid] = geometry; 45968 45969 } 45970 45971 } 45972 45973 return geometries; 45974 45975 } 45976 45977 parseMaterials(json, textures) { 45978 45979 const cache = {}; // MultiMaterial 45980 const materials = {}; 45981 45982 if (json !== undefined) { 45983 45984 const loader = new MaterialLoader(); 45985 loader.setTextures(textures); 45986 45987 for (let i = 0, l = json.length; i < l; i++) { 45988 45989 const data = json[i]; 45990 45991 if (cache[data.uuid] === undefined) { 45992 45993 cache[data.uuid] = loader.parse(data); 45994 45995 } 45996 45997 materials[data.uuid] = cache[data.uuid]; 45998 45999 } 46000 46001 } 46002 46003 return materials; 46004 46005 } 46006 46007 parseAnimations(json) { 46008 46009 const animations = {}; 46010 46011 if (json !== undefined) { 46012 46013 for (let i = 0; i < json.length; i++) { 46014 46015 const data = json[i]; 46016 46017 const clip = AnimationClip.parse(data); 46018 46019 animations[clip.uuid] = clip; 46020 46021 } 46022 46023 } 46024 46025 return animations; 46026 46027 } 46028 46029 parseImages(json, onLoad) { 46030 46031 const scope = this; 46032 const images = {}; 46033 46034 let loader; 46035 46036 function loadImage(url) { 46037 46038 scope.manager.itemStart(url); 46039 46040 return loader.load(url, function () { 46041 46042 scope.manager.itemEnd(url); 46043 46044 }, undefined, function () { 46045 46046 scope.manager.itemError(url); 46047 scope.manager.itemEnd(url); 46048 46049 }); 46050 46051 } 46052 46053 function deserializeImage(image) { 46054 46055 if (typeof image === 'string') { 46056 46057 const url = image; 46058 46059 const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test(url) ? url : scope.resourcePath + url; 46060 46061 return loadImage(path); 46062 46063 } else { 46064 46065 if (image.data) { 46066 46067 return { 46068 data: getTypedArray(image.type, image.data), 46069 width: image.width, 46070 height: image.height 46071 }; 46072 46073 } else { 46074 46075 return null; 46076 46077 } 46078 46079 } 46080 46081 } 46082 46083 if (json !== undefined && json.length > 0) { 46084 46085 const manager = new LoadingManager(onLoad); 46086 46087 loader = new ImageLoader(manager); 46088 loader.setCrossOrigin(this.crossOrigin); 46089 46090 for (let i = 0, il = json.length; i < il; i++) { 46091 46092 const image = json[i]; 46093 const url = image.url; 46094 46095 if (Array.isArray(url)) { 46096 46097 // load array of images e.g CubeTexture 46098 46099 const imageArray = []; 46100 46101 for (let j = 0, jl = url.length; j < jl; j++) { 46102 46103 const currentUrl = url[j]; 46104 46105 const deserializedImage = deserializeImage(currentUrl); 46106 46107 if (deserializedImage !== null) { 46108 46109 if (deserializedImage instanceof HTMLImageElement) { 46110 46111 imageArray.push(deserializedImage); 46112 46113 } else { 46114 46115 // special case: handle array of data textures for cube textures 46116 46117 imageArray.push(new DataTexture(deserializedImage.data, deserializedImage.width, deserializedImage.height)); 46118 46119 } 46120 46121 } 46122 46123 } 46124 46125 images[image.uuid] = new Source(imageArray); 46126 46127 } else { 46128 46129 // load single image 46130 46131 const deserializedImage = deserializeImage(image.url); 46132 images[image.uuid] = new Source(deserializedImage); 46133 46134 46135 } 46136 46137 } 46138 46139 } 46140 46141 return images; 46142 46143 } 46144 46145 async parseImagesAsync(json) { 46146 46147 const scope = this; 46148 const images = {}; 46149 46150 let loader; 46151 46152 async function deserializeImage(image) { 46153 46154 if (typeof image === 'string') { 46155 46156 const url = image; 46157 46158 const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test(url) ? url : scope.resourcePath + url; 46159 46160 return await loader.loadAsync(path);
vendor: 10,365 bytes, lines 46161-46591
46161 46162 } else { 46163 46164 if (image.data) { 46165 46166 return { 46167 data: getTypedArray(image.type, image.data), 46168 width: image.width, 46169 height: image.height 46170 }; 46171 46172 } else { 46173 46174 return null; 46175 46176 } 46177 46178 } 46179 46180 } 46181 46182 if (json !== undefined && json.length > 0) { 46183 46184 loader = new ImageLoader(this.manager); 46185 loader.setCrossOrigin(this.crossOrigin); 46186 46187 for (let i = 0, il = json.length; i < il; i++) { 46188 46189 const image = json[i]; 46190 const url = image.url; 46191 46192 if (Array.isArray(url)) { 46193 46194 // load array of images e.g CubeTexture 46195 46196 const imageArray = []; 46197 46198 for (let j = 0, jl = url.length; j < jl; j++) { 46199 46200 const currentUrl = url[j]; 46201 46202 const deserializedImage = await deserializeImage(currentUrl); 46203 46204 if (deserializedImage !== null) { 46205 46206 if (deserializedImage instanceof HTMLImageElement) { 46207 46208 imageArray.push(deserializedImage); 46209 46210 } else { 46211 46212 // special case: handle array of data textures for cube textures 46213 46214 imageArray.push(new DataTexture(deserializedImage.data, deserializedImage.width, deserializedImage.height)); 46215 46216 } 46217 46218 } 46219 46220 } 46221 46222 images[image.uuid] = new Source(imageArray); 46223 46224 } else { 46225 46226 // load single image 46227 46228 const deserializedImage = await deserializeImage(image.url); 46229 images[image.uuid] = new Source(deserializedImage); 46230 46231 } 46232 46233 } 46234 46235 } 46236 46237 return images; 46238 46239 } 46240 46241 parseTextures(json, images) { 46242 46243 function parseConstant(value, type) { 46244 46245 if (typeof value === 'number') return value; 46246 46247 console.warn('THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value); 46248 46249 return type[value]; 46250 46251 } 46252 46253 const textures = {}; 46254 46255 if (json !== undefined) { 46256 46257 for (let i = 0, l = json.length; i < l; i++) { 46258 46259 const data = json[i]; 46260 46261 if (data.image === undefined) { 46262 46263 console.warn('THREE.ObjectLoader: No "image" specified for', data.uuid); 46264 46265 } 46266 46267 if (images[data.image] === undefined) { 46268 46269 console.warn('THREE.ObjectLoader: Undefined image', data.image); 46270 46271 } 46272 46273 const source = images[data.image]; 46274 const image = source.data; 46275 46276 let texture; 46277 46278 if (Array.isArray(image)) { 46279 46280 texture = new CubeTexture(); 46281 46282 if (image.length === 6) texture.needsUpdate = true; 46283 46284 } else { 46285 46286 if (image && image.data) { 46287 46288 texture = new DataTexture(); 46289 46290 } else { 46291 46292 texture = new Texture(); 46293 46294 } 46295 46296 if (image) texture.needsUpdate = true; // textures can have undefined image data 46297 46298 } 46299 46300 texture.source = source; 46301 46302 texture.uuid = data.uuid; 46303 46304 if (data.name !== undefined) texture.name = data.name; 46305 46306 if (data.mapping !== undefined) texture.mapping = parseConstant(data.mapping, TEXTURE_MAPPING); 46307 if (data.channel !== undefined) texture.channel = data.channel; 46308 46309 if (data.offset !== undefined) texture.offset.fromArray(data.offset); 46310 if (data.repeat !== undefined) texture.repeat.fromArray(data.repeat); 46311 if (data.center !== undefined) texture.center.fromArray(data.center); 46312 if (data.rotation !== undefined) texture.rotation = data.rotation; 46313 46314 if (data.wrap !== undefined) { 46315 46316 texture.wrapS = parseConstant(data.wrap[0], TEXTURE_WRAPPING); 46317 texture.wrapT = parseConstant(data.wrap[1], TEXTURE_WRAPPING); 46318 46319 } 46320 46321 if (data.format !== undefined) texture.format = data.format; 46322 if (data.internalFormat !== undefined) texture.internalFormat = data.internalFormat; 46323 if (data.type !== undefined) texture.type = data.type; 46324 if (data.colorSpace !== undefined) texture.colorSpace = data.colorSpace; 46325 if (data.encoding !== undefined) texture.encoding = data.encoding; // @deprecated, r152 46326 46327 if (data.minFilter !== undefined) texture.minFilter = parseConstant(data.minFilter, TEXTURE_FILTER); 46328 if (data.magFilter !== undefined) texture.magFilter = parseConstant(data.magFilter, TEXTURE_FILTER); 46329 if (data.anisotropy !== undefined) texture.anisotropy = data.anisotropy; 46330 46331 if (data.flipY !== undefined) texture.flipY = data.flipY; 46332 46333 if (data.generateMipmaps !== undefined) texture.generateMipmaps = data.generateMipmaps; 46334 if (data.premultiplyAlpha !== undefined) texture.premultiplyAlpha = data.premultiplyAlpha; 46335 if (data.unpackAlignment !== undefined) texture.unpackAlignment = data.unpackAlignment; 46336 if (data.compareFunction !== undefined) texture.compareFunction = data.compareFunction; 46337 46338 if (data.userData !== undefined) texture.userData = data.userData; 46339 46340 textures[data.uuid] = texture; 46341 46342 } 46343 46344 } 46345 46346 return textures; 46347 46348 } 46349 46350 parseObject(data, geometries, materials, textures, animations) { 46351 46352 let object; 46353 46354 function getGeometry(name) { 46355 46356 if (geometries[name] === undefined) { 46357 46358 console.warn('THREE.ObjectLoader: Undefined geometry', name); 46359 46360 } 46361 46362 return geometries[name]; 46363 46364 } 46365 46366 function getMaterial(name) { 46367 46368 if (name === undefined) return undefined; 46369 46370 if (Array.isArray(name)) { 46371 46372 const array = []; 46373 46374 for (let i = 0, l = name.length; i < l; i++) { 46375 46376 const uuid = name[i]; 46377 46378 if (materials[uuid] === undefined) { 46379 46380 console.warn('THREE.ObjectLoader: Undefined material', uuid); 46381 46382 } 46383 46384 array.push(materials[uuid]); 46385 46386 } 46387 46388 return array; 46389 46390 } 46391 46392 if (materials[name] === undefined) { 46393 46394 console.warn('THREE.ObjectLoader: Undefined material', name); 46395 46396 } 46397 46398 return materials[name]; 46399 46400 } 46401 46402 function getTexture(uuid) { 46403 46404 if (textures[uuid] === undefined) { 46405 46406 console.warn('THREE.ObjectLoader: Undefined texture', uuid); 46407 46408 } 46409 46410 return textures[uuid]; 46411 46412 } 46413 46414 let geometry, material; 46415 46416 switch (data.type) { 46417 46418 case 'Scene': 46419 46420 object = new Scene(); 46421 46422 if (data.background !== undefined) { 46423 46424 if (Number.isInteger(data.background)) { 46425 46426 object.background = new Color(data.background); 46427 46428 } else { 46429 46430 object.background = getTexture(data.background); 46431 46432 } 46433 46434 } 46435 46436 if (data.environment !== undefined) { 46437 46438 object.environment = getTexture(data.environment); 46439 46440 } 46441 46442 if (data.fog !== undefined) { 46443 46444 if (data.fog.type === 'Fog') { 46445 46446 object.fog = new Fog(data.fog.color, data.fog.near, data.fog.far); 46447 46448 } else if (data.fog.type === 'FogExp2') { 46449 46450 object.fog = new FogExp2(data.fog.color, data.fog.density); 46451 46452 } 46453 46454 if (data.fog.name !== '') { 46455 46456 object.fog.name = data.fog.name; 46457 46458 } 46459 46460 } 46461 46462 if (data.backgroundBlurriness !== undefined) object.backgroundBlurriness = data.backgroundBlurriness; 46463 if (data.backgroundIntensity !== undefined) object.backgroundIntensity = data.backgroundIntensity; 46464 46465 break; 46466 46467 case 'PerspectiveCamera': 46468 46469 object = new PerspectiveCamera(data.fov, data.aspect, data.near, data.far); 46470 46471 if (data.focus !== undefined) object.focus = data.focus; 46472 if (data.zoom !== undefined) object.zoom = data.zoom; 46473 if (data.filmGauge !== undefined) object.filmGauge = data.filmGauge; 46474 if (data.filmOffset !== undefined) object.filmOffset = data.filmOffset; 46475 if (data.view !== undefined) object.view = Object.assign({}, data.view); 46476 46477 break; 46478 46479 case 'OrthographicCamera': 46480 46481 object = new OrthographicCamera(data.left, data.right, data.top, data.bottom, data.near, data.far); 46482 46483 if (data.zoom !== undefined) object.zoom = data.zoom; 46484 if (data.view !== undefined) object.view = Object.assign({}, data.view); 46485 46486 break; 46487 46488 case 'AmbientLight': 46489 46490 object = new AmbientLight(data.color, data.intensity); 46491 46492 break; 46493 46494 case 'DirectionalLight': 46495 46496 object = new DirectionalLight(data.color, data.intensity); 46497 46498 break; 46499 46500 case 'PointLight': 46501 46502 object = new PointLight(data.color, data.intensity, data.distance, data.decay); 46503 46504 break; 46505 46506 case 'RectAreaLight': 46507 46508 object = new RectAreaLight(data.color, data.intensity, data.width, data.height); 46509 46510 break; 46511 46512 case 'SpotLight': 46513 46514 object = new SpotLight(data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay); 46515 46516 break; 46517 46518 case 'HemisphereLight': 46519 46520 object = new HemisphereLight(data.color, data.groundColor, data.intensity); 46521 46522 break; 46523 46524 case 'LightProbe': 46525 46526 object = new LightProbe().fromJSON(data); 46527 46528 break; 46529 46530 case 'SkinnedMesh': 46531 46532 geometry = getGeometry(data.geometry); 46533 material = getMaterial(data.material); 46534 46535 object = new SkinnedMesh(geometry, material); 46536 46537 if (data.bindMode !== undefined) object.bindMode = data.bindMode; 46538 if (data.bindMatrix !== undefined) object.bindMatrix.fromArray(data.bindMatrix); 46539 if (data.skeleton !== undefined) object.skeleton = data.skeleton; 46540 46541 break; 46542 46543 case 'Mesh': 46544 46545 geometry = getGeometry(data.geometry); 46546 material = getMaterial(data.material); 46547 46548 object = new Mesh(geometry, material); 46549 46550 break; 46551 46552 case 'InstancedMesh': 46553 46554 geometry = getGeometry(data.geometry); 46555 material = getMaterial(data.material); 46556 const count = data.count; 46557 const instanceMatrix = data.instanceMatrix; 46558 const instanceColor = data.instanceColor; 46559 46560 object = new InstancedMesh(geometry, material, count); 46561 object.instanceMatrix = new InstancedBufferAttribute(new Float32Array(instanceMatrix.array), 16); 46562 if (instanceColor !== undefined) object.instanceColor = new InstancedBufferAttribute(new Float32Array(instanceColor.array), instanceColor.itemSize); 46563 46564 break; 46565 46566 case 'BatchedMesh': 46567 46568 geometry = getGeometry(data.geometry); 46569 material = getMaterial(data.material); 46570 46571 object = new BatchedMesh(data.maxGeometryCount, data.maxVertexCount, data.maxIndexCount, material); 46572 object.geometry = geometry; 46573 object.perObjectFrustumCulled = data.perObjectFrustumCulled; 46574 object.sortObjects = data.sortObjects; 46575 46576 object._drawRanges = data.drawRanges; 46577 object._reservedRanges = data.reservedRanges; 46578 46579 object._visibility = data.visibility; 46580 object._active = data.active; 46581 object._bounds = data.bounds.map(bound => { 46582 46583 const box = new Box3(); 46584 box.min.fromArray(bound.boxMin); 46585 box.max.fromArray(bound.boxMax); 46586 46587 const sphere = new Sphere(); 46588 sphere.radius = bound.sphereRadius; 46589 sphere.center.fromArray(bound.sphereCenter); 46590 46591 return {
vendor: 11,586 bytes, lines 46592-47124
46592 boxInitialized: bound.boxInitialized, 46593 box: box, 46594 46595 sphereInitialized: bound.sphereInitialized, 46596 sphere: sphere 46597 }; 46598 46599 }); 46600 46601 object._maxGeometryCount = data.maxGeometryCount; 46602 object._maxVertexCount = data.maxVertexCount; 46603 object._maxIndexCount = data.maxIndexCount; 46604 46605 object._geometryInitialized = data.geometryInitialized; 46606 object._geometryCount = data.geometryCount; 46607 46608 object._matricesTexture = getTexture(data.matricesTexture.uuid); 46609 46610 break; 46611 46612 case 'LOD': 46613 46614 object = new LOD(); 46615 46616 break; 46617 46618 case 'Line': 46619 46620 object = new Line(getGeometry(data.geometry), getMaterial(data.material)); 46621 46622 break; 46623 46624 case 'LineLoop': 46625 46626 object = new LineLoop(getGeometry(data.geometry), getMaterial(data.material)); 46627 46628 break; 46629 46630 case 'LineSegments': 46631 46632 object = new LineSegments(getGeometry(data.geometry), getMaterial(data.material)); 46633 46634 break; 46635 46636 case 'PointCloud': 46637 case 'Points': 46638 46639 object = new Points(getGeometry(data.geometry), getMaterial(data.material)); 46640 46641 break; 46642 46643 case 'Sprite': 46644 46645 object = new Sprite(getMaterial(data.material)); 46646 46647 break; 46648 46649 case 'Group': 46650 46651 object = new Group(); 46652 46653 break; 46654 46655 case 'Bone': 46656 46657 object = new Bone(); 46658 46659 break; 46660 46661 default: 46662 46663 object = new Object3D(); 46664 46665 } 46666 46667 object.uuid = data.uuid; 46668 46669 if (data.name !== undefined) object.name = data.name; 46670 46671 if (data.matrix !== undefined) { 46672 46673 object.matrix.fromArray(data.matrix); 46674 46675 if (data.matrixAutoUpdate !== undefined) object.matrixAutoUpdate = data.matrixAutoUpdate; 46676 if (object.matrixAutoUpdate) object.matrix.decompose(object.position, object.quaternion, object.scale); 46677 46678 } else { 46679 46680 if (data.position !== undefined) object.position.fromArray(data.position); 46681 if (data.rotation !== undefined) object.rotation.fromArray(data.rotation); 46682 if (data.quaternion !== undefined) object.quaternion.fromArray(data.quaternion); 46683 if (data.scale !== undefined) object.scale.fromArray(data.scale); 46684 46685 } 46686 46687 if (data.up !== undefined) object.up.fromArray(data.up); 46688 46689 if (data.castShadow !== undefined) object.castShadow = data.castShadow; 46690 if (data.receiveShadow !== undefined) object.receiveShadow = data.receiveShadow; 46691 46692 if (data.shadow) { 46693 46694 if (data.shadow.bias !== undefined) object.shadow.bias = data.shadow.bias; 46695 if (data.shadow.normalBias !== undefined) object.shadow.normalBias = data.shadow.normalBias; 46696 if (data.shadow.radius !== undefined) object.shadow.radius = data.shadow.radius; 46697 if (data.shadow.mapSize !== undefined) object.shadow.mapSize.fromArray(data.shadow.mapSize); 46698 if (data.shadow.camera !== undefined) object.shadow.camera = this.parseObject(data.shadow.camera); 46699 46700 } 46701 46702 if (data.visible !== undefined) object.visible = data.visible; 46703 if (data.frustumCulled !== undefined) object.frustumCulled = data.frustumCulled; 46704 if (data.renderOrder !== undefined) object.renderOrder = data.renderOrder; 46705 if (data.userData !== undefined) object.userData = data.userData; 46706 if (data.layers !== undefined) object.layers.mask = data.layers; 46707 46708 if (data.children !== undefined) { 46709 46710 const children = data.children; 46711 46712 for (let i = 0; i < children.length; i++) { 46713 46714 object.add(this.parseObject(children[i], geometries, materials, textures, animations)); 46715 46716 } 46717 46718 } 46719 46720 if (data.animations !== undefined) { 46721 46722 const objectAnimations = data.animations; 46723 46724 for (let i = 0; i < objectAnimations.length; i++) { 46725 46726 const uuid = objectAnimations[i]; 46727 46728 object.animations.push(animations[uuid]); 46729 46730 } 46731 46732 } 46733 46734 if (data.type === 'LOD') { 46735 46736 if (data.autoUpdate !== undefined) object.autoUpdate = data.autoUpdate; 46737 46738 const levels = data.levels; 46739 46740 for (let l = 0; l < levels.length; l++) { 46741 46742 const level = levels[l]; 46743 const child = object.getObjectByProperty('uuid', level.object); 46744 46745 if (child !== undefined) { 46746 46747 object.addLevel(child, level.distance, level.hysteresis); 46748 46749 } 46750 46751 } 46752 46753 } 46754 46755 return object; 46756 46757 } 46758 46759 bindSkeletons(object, skeletons) { 46760 46761 if (Object.keys(skeletons).length === 0) return; 46762 46763 object.traverse(function (child) { 46764 46765 if (child.isSkinnedMesh === true && child.skeleton !== undefined) { 46766 46767 const skeleton = skeletons[child.skeleton]; 46768 46769 if (skeleton === undefined) { 46770 46771 console.warn('THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton); 46772 46773 } else { 46774 46775 child.bind(skeleton, child.bindMatrix); 46776 46777 } 46778 46779 } 46780 46781 }); 46782 46783 } 46784 46785} 46786 46787const TEXTURE_MAPPING = { 46788 UVMapping: UVMapping, 46789 CubeReflectionMapping: CubeReflectionMapping, 46790 CubeRefractionMapping: CubeRefractionMapping, 46791 EquirectangularReflectionMapping: EquirectangularReflectionMapping, 46792 EquirectangularRefractionMapping: EquirectangularRefractionMapping, 46793 CubeUVReflectionMapping: CubeUVReflectionMapping 46794}; 46795 46796const TEXTURE_WRAPPING = { 46797 RepeatWrapping: RepeatWrapping, 46798 ClampToEdgeWrapping: ClampToEdgeWrapping, 46799 MirroredRepeatWrapping: MirroredRepeatWrapping 46800}; 46801 46802const TEXTURE_FILTER = { 46803 NearestFilter: NearestFilter, 46804 NearestMipmapNearestFilter: NearestMipmapNearestFilter, 46805 NearestMipmapLinearFilter: NearestMipmapLinearFilter, 46806 LinearFilter: LinearFilter, 46807 LinearMipmapNearestFilter: LinearMipmapNearestFilter, 46808 LinearMipmapLinearFilter: LinearMipmapLinearFilter 46809}; 46810 46811class ImageBitmapLoader extends Loader { 46812 46813 constructor(manager) { 46814 46815 super(manager); 46816 46817 this.isImageBitmapLoader = true; 46818 46819 if (typeof createImageBitmap === 'undefined') { 46820 46821 console.warn('THREE.ImageBitmapLoader: createImageBitmap() not supported.'); 46822 46823 } 46824 46825 if (typeof fetch === 'undefined') { 46826 46827 console.warn('THREE.ImageBitmapLoader: fetch() not supported.'); 46828 46829 } 46830 46831 this.options = { premultiplyAlpha: 'none' }; 46832 46833 } 46834 46835 setOptions(options) { 46836 46837 this.options = options; 46838 46839 return this; 46840 46841 } 46842 46843 load(url, onLoad, onProgress, onError) { 46844 46845 if (url === undefined) url = ''; 46846 46847 if (this.path !== undefined) url = this.path + url; 46848 46849 url = this.manager.resolveURL(url); 46850 46851 const scope = this; 46852 46853 const cached = Cache.get(url); 46854 46855 if (cached !== undefined) { 46856 46857 scope.manager.itemStart(url); 46858 46859 // If cached is a promise, wait for it to resolve 46860 if (cached.then) { 46861 46862 cached.then(imageBitmap => { 46863 46864 if (onLoad) onLoad(imageBitmap); 46865 46866 scope.manager.itemEnd(url); 46867 46868 }).catch(e => { 46869 46870 if (onError) onError(e); 46871 46872 }); 46873 return; 46874 46875 } 46876 46877 // If cached is not a promise (i.e., it's already an imageBitmap) 46878 setTimeout(function () { 46879 46880 if (onLoad) onLoad(cached); 46881 46882 scope.manager.itemEnd(url); 46883 46884 }, 0); 46885 46886 return cached; 46887 46888 } 46889 46890 const fetchOptions = {}; 46891 fetchOptions.credentials = (this.crossOrigin === 'anonymous') ? 'same-origin' : 'include'; 46892 fetchOptions.headers = this.requestHeader; 46893 46894 const promise = fetch(url, fetchOptions).then(function (res) { 46895 46896 return res.blob(); 46897 46898 }).then(function (blob) { 46899 46900 return createImageBitmap(blob, Object.assign(scope.options, { colorSpaceConversion: 'none' })); 46901 46902 }).then(function (imageBitmap) { 46903 46904 Cache.add(url, imageBitmap); 46905 46906 if (onLoad) onLoad(imageBitmap); 46907 46908 scope.manager.itemEnd(url); 46909 46910 return imageBitmap; 46911 46912 }).catch(function (e) { 46913 46914 if (onError) onError(e); 46915 46916 Cache.remove(url); 46917 46918 scope.manager.itemError(url); 46919 scope.manager.itemEnd(url); 46920 46921 }); 46922 46923 Cache.add(url, promise); 46924 scope.manager.itemStart(url); 46925 46926 } 46927 46928} 46929 46930let _context; 46931 46932class AudioContext { 46933 46934 static getContext() { 46935 46936 if (_context === undefined) { 46937 46938 _context = new (window.AudioContext || window.webkitAudioContext)(); 46939 46940 } 46941 46942 return _context; 46943 46944 } 46945 46946 static setContext(value) { 46947 46948 _context = value; 46949 46950 } 46951 46952} 46953 46954class AudioLoader extends Loader { 46955 46956 constructor(manager) { 46957 46958 super(manager); 46959 46960 } 46961 46962 load(url, onLoad, onProgress, onError) { 46963 46964 const scope = this; 46965 46966 const loader = new FileLoader(this.manager); 46967 loader.setResponseType('arraybuffer'); 46968 loader.setPath(this.path); 46969 loader.setRequestHeader(this.requestHeader); 46970 loader.setWithCredentials(this.withCredentials); 46971 loader.load(url, function (buffer) { 46972 46973 try { 46974 46975 // Create a copy of the buffer. The `decodeAudioData` method 46976 // detaches the buffer when complete, preventing reuse. 46977 const bufferCopy = buffer.slice(0); 46978 46979 const context = AudioContext.getContext(); 46980 context.decodeAudioData(bufferCopy, function (audioBuffer) { 46981 46982 onLoad(audioBuffer); 46983 46984 }).catch(handleError); 46985 46986 } catch (e) { 46987 46988 handleError(e); 46989 46990 } 46991 46992 }, onProgress, onError); 46993 46994 function handleError(e) { 46995 46996 if (onError) { 46997 46998 onError(e); 46999 47000 } else { 47001 47002 console.error(e); 47003 47004 } 47005 47006 scope.manager.itemError(url); 47007 47008 } 47009 47010 } 47011 47012} 47013 47014const _eyeRight = /*@__PURE__*/ new Matrix4(); 47015const _eyeLeft = /*@__PURE__*/ new Matrix4(); 47016const _projectionMatrix = /*@__PURE__*/ new Matrix4(); 47017 47018class StereoCamera { 47019 47020 constructor() { 47021 47022 this.type = 'StereoCamera'; 47023 47024 this.aspect = 1; 47025 47026 this.eyeSep = 0.064; 47027 47028 this.cameraL = new PerspectiveCamera(); 47029 this.cameraL.layers.enable(1); 47030 this.cameraL.matrixAutoUpdate = false; 47031 47032 this.cameraR = new PerspectiveCamera(); 47033 this.cameraR.layers.enable(2); 47034 this.cameraR.matrixAutoUpdate = false; 47035 47036 this._cache = { 47037 focus: null, 47038 fov: null, 47039 aspect: null, 47040 near: null, 47041 far: null, 47042 zoom: null, 47043 eyeSep: null 47044 }; 47045 47046 } 47047 47048 update(camera) { 47049 47050 const cache = this._cache; 47051 47052 const needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov || 47053 cache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near || 47054 cache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep; 47055 47056 if (needsUpdate) { 47057 47058 cache.focus = camera.focus; 47059 cache.fov = camera.fov; 47060 cache.aspect = camera.aspect * this.aspect; 47061 cache.near = camera.near; 47062 cache.far = camera.far; 47063 cache.zoom = camera.zoom; 47064 cache.eyeSep = this.eyeSep; 47065 47066 // Off-axis stereoscopic effect based on 47067 // http://paulbourke.net/stereographics/stereorender/ 47068 47069 _projectionMatrix.copy(camera.projectionMatrix); 47070 const eyeSepHalf = cache.eyeSep / 2; 47071 const eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus; 47072 const ymax = (cache.near * Math.tan(DEG2RAD * cache.fov * 0.5)) / cache.zoom; 47073 let xmin, xmax; 47074 47075 // translate xOffset 47076 47077 _eyeLeft.elements[12] = - eyeSepHalf; 47078 _eyeRight.elements[12] = eyeSepHalf; 47079 47080 // for left eye 47081 47082 xmin = - ymax * cache.aspect + eyeSepOnProjection; 47083 xmax = ymax * cache.aspect + eyeSepOnProjection; 47084 47085 _projectionMatrix.elements[0] = 2 * cache.near / (xmax - xmin); 47086 _projectionMatrix.elements[8] = (xmax + xmin) / (xmax - xmin); 47087 47088 this.cameraL.projectionMatrix.copy(_projectionMatrix); 47089 47090 // for right eye 47091 47092 xmin = - ymax * cache.aspect - eyeSepOnProjection; 47093 xmax = ymax * cache.aspect - eyeSepOnProjection; 47094 47095 _projectionMatrix.elements[0] = 2 * cache.near / (xmax - xmin); 47096 _projectionMatrix.elements[8] = (xmax + xmin) / (xmax - xmin); 47097 47098 this.cameraR.projectionMatrix.copy(_projectionMatrix); 47099 47100 } 47101 47102 this.cameraL.matrixWorld.copy(camera.matrixWorld).multiply(_eyeLeft); 47103 this.cameraR.matrixWorld.copy(camera.matrixWorld).multiply(_eyeRight); 47104 47105 } 47106 47107} 47108 47109class Clock { 47110 47111 constructor(autoStart = true) { 47112 47113 this.autoStart = autoStart; 47114 47115 this.startTime = 0; 47116 this.oldTime = 0; 47117 this.elapsedTime = 0; 47118 47119 this.running = false; 47120 47121 } 47122 47123 start() { 47124
vendor: 13,529 bytes, lines 47125-47914
47125 this.startTime = now(); 47126 47127 this.oldTime = this.startTime; 47128 this.elapsedTime = 0; 47129 this.running = true; 47130 47131 } 47132 47133 stop() { 47134 47135 this.getElapsedTime(); 47136 this.running = false; 47137 this.autoStart = false; 47138 47139 } 47140 47141 getElapsedTime() { 47142 47143 this.getDelta(); 47144 return this.elapsedTime; 47145 47146 } 47147 47148 getDelta() { 47149 47150 let diff = 0; 47151 47152 if (this.autoStart && !this.running) { 47153 47154 this.start(); 47155 return 0; 47156 47157 } 47158 47159 if (this.running) { 47160 47161 const newTime = now(); 47162 47163 diff = (newTime - this.oldTime) / 1000; 47164 this.oldTime = newTime; 47165 47166 this.elapsedTime += diff; 47167 47168 } 47169 47170 return diff; 47171 47172 } 47173 47174} 47175 47176function now() { 47177 47178 return (typeof performance === 'undefined' ? Date : performance).now(); // see #10732 47179 47180} 47181 47182const _position$1 = /*@__PURE__*/ new Vector3(); 47183const _quaternion$1 = /*@__PURE__*/ new Quaternion(); 47184const _scale$1 = /*@__PURE__*/ new Vector3(); 47185const _orientation$1 = /*@__PURE__*/ new Vector3(); 47186 47187class AudioListener extends Object3D { 47188 47189 constructor() { 47190 47191 super(); 47192 47193 this.type = 'AudioListener'; 47194 47195 this.context = AudioContext.getContext(); 47196 47197 this.gain = this.context.createGain(); 47198 this.gain.connect(this.context.destination); 47199 47200 this.filter = null; 47201 47202 this.timeDelta = 0; 47203 47204 // private 47205 47206 this._clock = new Clock(); 47207 47208 } 47209 47210 getInput() { 47211 47212 return this.gain; 47213 47214 } 47215 47216 removeFilter() { 47217 47218 if (this.filter !== null) { 47219 47220 this.gain.disconnect(this.filter); 47221 this.filter.disconnect(this.context.destination); 47222 this.gain.connect(this.context.destination); 47223 this.filter = null; 47224 47225 } 47226 47227 return this; 47228 47229 } 47230 47231 getFilter() { 47232 47233 return this.filter; 47234 47235 } 47236 47237 setFilter(value) { 47238 47239 if (this.filter !== null) { 47240 47241 this.gain.disconnect(this.filter); 47242 this.filter.disconnect(this.context.destination); 47243 47244 } else { 47245 47246 this.gain.disconnect(this.context.destination); 47247 47248 } 47249 47250 this.filter = value; 47251 this.gain.connect(this.filter); 47252 this.filter.connect(this.context.destination); 47253 47254 return this; 47255 47256 } 47257 47258 getMasterVolume() { 47259 47260 return this.gain.gain.value; 47261 47262 } 47263 47264 setMasterVolume(value) { 47265 47266 this.gain.gain.setTargetAtTime(value, this.context.currentTime, 0.01); 47267 47268 return this; 47269 47270 } 47271 47272 updateMatrixWorld(force) { 47273 47274 super.updateMatrixWorld(force); 47275 47276 const listener = this.context.listener; 47277 const up = this.up; 47278 47279 this.timeDelta = this._clock.getDelta(); 47280 47281 this.matrixWorld.decompose(_position$1, _quaternion$1, _scale$1); 47282 47283 _orientation$1.set(0, 0, - 1).applyQuaternion(_quaternion$1); 47284 47285 if (listener.positionX) { 47286 47287 // code path for Chrome (see #14393) 47288 47289 const endTime = this.context.currentTime + this.timeDelta; 47290 47291 listener.positionX.linearRampToValueAtTime(_position$1.x, endTime); 47292 listener.positionY.linearRampToValueAtTime(_position$1.y, endTime); 47293 listener.positionZ.linearRampToValueAtTime(_position$1.z, endTime); 47294 listener.forwardX.linearRampToValueAtTime(_orientation$1.x, endTime); 47295 listener.forwardY.linearRampToValueAtTime(_orientation$1.y, endTime); 47296 listener.forwardZ.linearRampToValueAtTime(_orientation$1.z, endTime); 47297 listener.upX.linearRampToValueAtTime(up.x, endTime); 47298 listener.upY.linearRampToValueAtTime(up.y, endTime); 47299 listener.upZ.linearRampToValueAtTime(up.z, endTime); 47300 47301 } else { 47302 47303 listener.setPosition(_position$1.x, _position$1.y, _position$1.z); 47304 listener.setOrientation(_orientation$1.x, _orientation$1.y, _orientation$1.z, up.x, up.y, up.z); 47305 47306 } 47307 47308 } 47309 47310} 47311 47312class Audio extends Object3D { 47313 47314 constructor(listener) { 47315 47316 super(); 47317 47318 this.type = 'Audio'; 47319 47320 this.listener = listener; 47321 this.context = listener.context; 47322 47323 this.gain = this.context.createGain(); 47324 this.gain.connect(listener.getInput()); 47325 47326 this.autoplay = false; 47327 47328 this.buffer = null; 47329 this.detune = 0; 47330 this.loop = false; 47331 this.loopStart = 0; 47332 this.loopEnd = 0; 47333 this.offset = 0; 47334 this.duration = undefined; 47335 this.playbackRate = 1; 47336 this.isPlaying = false; 47337 this.hasPlaybackControl = true; 47338 this.source = null; 47339 this.sourceType = 'empty'; 47340 47341 this._startedAt = 0; 47342 this._progress = 0; 47343 this._connected = false; 47344 47345 this.filters = []; 47346 47347 } 47348 47349 getOutput() { 47350 47351 return this.gain; 47352 47353 } 47354 47355 setNodeSource(audioNode) { 47356 47357 this.hasPlaybackControl = false; 47358 this.sourceType = 'audioNode'; 47359 this.source = audioNode; 47360 this.connect(); 47361 47362 return this; 47363 47364 } 47365 47366 setMediaElementSource(mediaElement) { 47367 47368 this.hasPlaybackControl = false; 47369 this.sourceType = 'mediaNode'; 47370 this.source = this.context.createMediaElementSource(mediaElement); 47371 this.connect(); 47372 47373 return this; 47374 47375 } 47376 47377 setMediaStreamSource(mediaStream) { 47378 47379 this.hasPlaybackControl = false; 47380 this.sourceType = 'mediaStreamNode'; 47381 this.source = this.context.createMediaStreamSource(mediaStream); 47382 this.connect(); 47383 47384 return this; 47385 47386 } 47387 47388 setBuffer(audioBuffer) { 47389 47390 this.buffer = audioBuffer; 47391 this.sourceType = 'buffer'; 47392 47393 if (this.autoplay) this.play(); 47394 47395 return this; 47396 47397 } 47398 47399 play(delay = 0) { 47400 47401 if (this.isPlaying === true) { 47402 47403 console.warn('THREE.Audio: Audio is already playing.'); 47404 return; 47405 47406 } 47407 47408 if (this.hasPlaybackControl === false) { 47409 47410 console.warn('THREE.Audio: this Audio has no playback control.'); 47411 return; 47412 47413 } 47414 47415 this._startedAt = this.context.currentTime + delay; 47416 47417 const source = this.context.createBufferSource(); 47418 source.buffer = this.buffer; 47419 source.loop = this.loop; 47420 source.loopStart = this.loopStart; 47421 source.loopEnd = this.loopEnd; 47422 source.onended = this.onEnded.bind(this); 47423 source.start(this._startedAt, this._progress + this.offset, this.duration); 47424 47425 this.isPlaying = true; 47426 47427 this.source = source; 47428 47429 this.setDetune(this.detune); 47430 this.setPlaybackRate(this.playbackRate); 47431 47432 return this.connect(); 47433 47434 } 47435 47436 pause() { 47437 47438 if (this.hasPlaybackControl === false) { 47439 47440 console.warn('THREE.Audio: this Audio has no playback control.'); 47441 return; 47442 47443 } 47444 47445 if (this.isPlaying === true) { 47446 47447 // update current progress 47448 47449 this._progress += Math.max(this.context.currentTime - this._startedAt, 0) * this.playbackRate; 47450 47451 if (this.loop === true) { 47452 47453 // ensure _progress does not exceed duration with looped audios 47454 47455 this._progress = this._progress % (this.duration || this.buffer.duration); 47456 47457 } 47458 47459 this.source.stop(); 47460 this.source.onended = null; 47461 47462 this.isPlaying = false; 47463 47464 } 47465 47466 return this; 47467 47468 } 47469 47470 stop() { 47471 47472 if (this.hasPlaybackControl === false) { 47473 47474 console.warn('THREE.Audio: this Audio has no playback control.'); 47475 return; 47476 47477 } 47478 47479 this._progress = 0; 47480 47481 if (this.source !== null) { 47482 47483 this.source.stop(); 47484 this.source.onended = null; 47485 47486 } 47487 47488 this.isPlaying = false; 47489 47490 return this; 47491 47492 } 47493 47494 connect() { 47495 47496 if (this.filters.length > 0) { 47497 47498 this.source.connect(this.filters[0]); 47499 47500 for (let i = 1, l = this.filters.length; i < l; i++) { 47501 47502 this.filters[i - 1].connect(this.filters[i]); 47503 47504 } 47505 47506 this.filters[this.filters.length - 1].connect(this.getOutput()); 47507 47508 } else { 47509 47510 this.source.connect(this.getOutput()); 47511 47512 } 47513 47514 this._connected = true; 47515 47516 return this; 47517 47518 } 47519 47520 disconnect() { 47521 47522 if (this._connected === false) { 47523 47524 return; 47525 47526 } 47527 47528 if (this.filters.length > 0) { 47529 47530 this.source.disconnect(this.filters[0]); 47531 47532 for (let i = 1, l = this.filters.length; i < l; i++) { 47533 47534 this.filters[i - 1].disconnect(this.filters[i]); 47535 47536 } 47537 47538 this.filters[this.filters.length - 1].disconnect(this.getOutput()); 47539 47540 } else { 47541 47542 this.source.disconnect(this.getOutput()); 47543 47544 } 47545 47546 this._connected = false; 47547 47548 return this; 47549 47550 } 47551 47552 getFilters() { 47553 47554 return this.filters; 47555 47556 } 47557 47558 setFilters(value) { 47559 47560 if (!value) value = []; 47561 47562 if (this._connected === true) { 47563 47564 this.disconnect(); 47565 this.filters = value.slice(); 47566 this.connect(); 47567 47568 } else { 47569 47570 this.filters = value.slice(); 47571 47572 } 47573 47574 return this; 47575 47576 } 47577 47578 setDetune(value) { 47579 47580 this.detune = value; 47581 47582 if (this.source.detune === undefined) return; // only set detune when available 47583 47584 if (this.isPlaying === true) { 47585 47586 this.source.detune.setTargetAtTime(this.detune, this.context.currentTime, 0.01); 47587 47588 } 47589 47590 return this; 47591 47592 } 47593 47594 getDetune() { 47595 47596 return this.detune; 47597 47598 } 47599 47600 getFilter() { 47601 47602 return this.getFilters()[0]; 47603 47604 } 47605 47606 setFilter(filter) { 47607 47608 return this.setFilters(filter ? [filter] : []); 47609 47610 } 47611 47612 setPlaybackRate(value) { 47613 47614 if (this.hasPlaybackControl === false) { 47615 47616 console.warn('THREE.Audio: this Audio has no playback control.'); 47617 return; 47618 47619 } 47620 47621 this.playbackRate = value; 47622 47623 if (this.isPlaying === true) { 47624 47625 this.source.playbackRate.setTargetAtTime(this.playbackRate, this.context.currentTime, 0.01); 47626 47627 } 47628 47629 return this; 47630 47631 } 47632 47633 getPlaybackRate() { 47634 47635 return this.playbackRate; 47636 47637 } 47638 47639 onEnded() { 47640 47641 this.isPlaying = false; 47642 47643 } 47644 47645 getLoop() { 47646 47647 if (this.hasPlaybackControl === false) { 47648 47649 console.warn('THREE.Audio: this Audio has no playback control.'); 47650 return false; 47651 47652 } 47653 47654 return this.loop; 47655 47656 } 47657 47658 setLoop(value) { 47659 47660 if (this.hasPlaybackControl === false) { 47661 47662 console.warn('THREE.Audio: this Audio has no playback control.'); 47663 return; 47664 47665 } 47666 47667 this.loop = value; 47668 47669 if (this.isPlaying === true) { 47670 47671 this.source.loop = this.loop; 47672 47673 } 47674 47675 return this; 47676 47677 } 47678 47679 setLoopStart(value) { 47680 47681 this.loopStart = value; 47682 47683 return this; 47684 47685 } 47686 47687 setLoopEnd(value) { 47688 47689 this.loopEnd = value; 47690 47691 return this; 47692 47693 } 47694 47695 getVolume() { 47696 47697 return this.gain.gain.value; 47698 47699 } 47700 47701 setVolume(value) { 47702 47703 this.gain.gain.setTargetAtTime(value, this.context.currentTime, 0.01); 47704 47705 return this; 47706 47707 } 47708 47709} 47710 47711const _position = /*@__PURE__*/ new Vector3(); 47712const _quaternion = /*@__PURE__*/ new Quaternion(); 47713const _scale = /*@__PURE__*/ new Vector3(); 47714const _orientation = /*@__PURE__*/ new Vector3(); 47715 47716class PositionalAudio extends Audio { 47717 47718 constructor(listener) { 47719 47720 super(listener); 47721 47722 this.panner = this.context.createPanner(); 47723 this.panner.panningModel = 'HRTF'; 47724 this.panner.connect(this.gain); 47725 47726 } 47727 47728 connect() { 47729 47730 super.connect(); 47731 47732 this.panner.connect(this.gain); 47733 47734 } 47735 47736 disconnect() { 47737 47738 super.disconnect(); 47739 47740 this.panner.disconnect(this.gain); 47741 47742 } 47743 47744 getOutput() { 47745 47746 return this.panner; 47747 47748 } 47749 47750 getRefDistance() { 47751 47752 return this.panner.refDistance; 47753 47754 } 47755 47756 setRefDistance(value) { 47757 47758 this.panner.refDistance = value; 47759 47760 return this; 47761 47762 } 47763 47764 getRolloffFactor() { 47765 47766 return this.panner.rolloffFactor; 47767 47768 } 47769 47770 setRolloffFactor(value) { 47771 47772 this.panner.rolloffFactor = value; 47773 47774 return this; 47775 47776 } 47777 47778 getDistanceModel() { 47779 47780 return this.panner.distanceModel; 47781 47782 } 47783 47784 setDistanceModel(value) { 47785 47786 this.panner.distanceModel = value; 47787 47788 return this; 47789 47790 } 47791 47792 getMaxDistance() { 47793 47794 return this.panner.maxDistance; 47795 47796 } 47797 47798 setMaxDistance(value) { 47799 47800 this.panner.maxDistance = value; 47801 47802 return this; 47803 47804 } 47805 47806 setDirectionalCone(coneInnerAngle, coneOuterAngle, coneOuterGain) { 47807 47808 this.panner.coneInnerAngle = coneInnerAngle; 47809 this.panner.coneOuterAngle = coneOuterAngle; 47810 this.panner.coneOuterGain = coneOuterGain; 47811 47812 return this; 47813 47814 } 47815 47816 updateMatrixWorld(force) { 47817 47818 super.updateMatrixWorld(force); 47819 47820 if (this.hasPlaybackControl === true && this.isPlaying === false) return; 47821 47822 this.matrixWorld.decompose(_position, _quaternion, _scale); 47823 47824 _orientation.set(0, 0, 1).applyQuaternion(_quaternion); 47825 47826 const panner = this.panner; 47827 47828 if (panner.positionX) { 47829 47830 // code path for Chrome and Firefox (see #14393) 47831 47832 const endTime = this.context.currentTime + this.listener.timeDelta; 47833 47834 panner.positionX.linearRampToValueAtTime(_position.x, endTime); 47835 panner.positionY.linearRampToValueAtTime(_position.y, endTime); 47836 panner.positionZ.linearRampToValueAtTime(_position.z, endTime); 47837 panner.orientationX.linearRampToValueAtTime(_orientation.x, endTime); 47838 panner.orientationY.linearRampToValueAtTime(_orientation.y, endTime); 47839 panner.orientationZ.linearRampToValueAtTime(_orientation.z, endTime); 47840 47841 } else { 47842 47843 panner.setPosition(_position.x, _position.y, _position.z); 47844 panner.setOrientation(_orientation.x, _orientation.y, _orientation.z); 47845 47846 } 47847 47848 } 47849 47850} 47851 47852class AudioAnalyser { 47853 47854 constructor(audio, fftSize = 2048) { 47855 47856 this.analyser = audio.context.createAnalyser(); 47857 this.analyser.fftSize = fftSize; 47858 47859 this.data = new Uint8Array(this.analyser.frequencyBinCount); 47860 47861 audio.getOutput().connect(this.analyser); 47862 47863 } 47864 47865 47866 getFrequencyData() { 47867 47868 this.analyser.getByteFrequencyData(this.data); 47869 47870 return this.data; 47871 47872 } 47873 47874 getAverageFrequency() { 47875 47876 let value = 0; 47877 const data = this.getFrequencyData(); 47878 47879 for (let i = 0; i < data.length; i++) { 47880 47881 value += data[i]; 47882 47883 } 47884 47885 return value / data.length; 47886 47887 } 47888 47889} 47890 47891class PropertyMixer { 47892 47893 constructor(binding, typeName, valueSize) { 47894 47895 this.binding = binding; 47896 this.valueSize = valueSize; 47897 47898 let mixFunction, 47899 mixFunctionAdditive, 47900 setIdentity; 47901 47902 // buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ] 47903 // 47904 // interpolators can use .buffer as their .result 47905 // the data then goes to 'incoming' 47906 // 47907 // 'accu0' and 'accu1' are used frame-interleaved for 47908 // the cumulative result and are compared to detect 47909 // changes 47910 // 47911 // 'orig' stores the original state of the property 47912 // 47913 // 'add' is used for additive cumulative results 47914 //
vendor: 14,096 bytes, lines 47915-48545
47915 // 'work' is optional and is only present for quaternion types. It is used 47916 // to store intermediate quaternion multiplication results 47917 47918 switch (typeName) { 47919 47920 case 'quaternion': 47921 mixFunction = this._slerp; 47922 mixFunctionAdditive = this._slerpAdditive; 47923 setIdentity = this._setAdditiveIdentityQuaternion; 47924 47925 this.buffer = new Float64Array(valueSize * 6); 47926 this._workIndex = 5; 47927 break; 47928 47929 case 'string': 47930 case 'bool': 47931 mixFunction = this._select; 47932 47933 // Use the regular mix function and for additive on these types, 47934 // additive is not relevant for non-numeric types 47935 mixFunctionAdditive = this._select; 47936 47937 setIdentity = this._setAdditiveIdentityOther; 47938 47939 this.buffer = new Array(valueSize * 5); 47940 break; 47941 47942 default: 47943 mixFunction = this._lerp; 47944 mixFunctionAdditive = this._lerpAdditive; 47945 setIdentity = this._setAdditiveIdentityNumeric; 47946 47947 this.buffer = new Float64Array(valueSize * 5); 47948 47949 } 47950 47951 this._mixBufferRegion = mixFunction; 47952 this._mixBufferRegionAdditive = mixFunctionAdditive; 47953 this._setIdentity = setIdentity; 47954 this._origIndex = 3; 47955 this._addIndex = 4; 47956 47957 this.cumulativeWeight = 0; 47958 this.cumulativeWeightAdditive = 0; 47959 47960 this.useCount = 0; 47961 this.referenceCount = 0; 47962 47963 } 47964 47965 // accumulate data in the 'incoming' region into 'accu<i>' 47966 accumulate(accuIndex, weight) { 47967 47968 // note: happily accumulating nothing when weight = 0, the caller knows 47969 // the weight and shouldn't have made the call in the first place 47970 47971 const buffer = this.buffer, 47972 stride = this.valueSize, 47973 offset = accuIndex * stride + stride; 47974 47975 let currentWeight = this.cumulativeWeight; 47976 47977 if (currentWeight === 0) { 47978 47979 // accuN := incoming * weight 47980 47981 for (let i = 0; i !== stride; ++i) { 47982 47983 buffer[offset + i] = buffer[i]; 47984 47985 } 47986 47987 currentWeight = weight; 47988 47989 } else { 47990 47991 // accuN := accuN + incoming * weight 47992 47993 currentWeight += weight; 47994 const mix = weight / currentWeight; 47995 this._mixBufferRegion(buffer, offset, 0, mix, stride); 47996 47997 } 47998 47999 this.cumulativeWeight = currentWeight; 48000 48001 } 48002 48003 // accumulate data in the 'incoming' region into 'add' 48004 accumulateAdditive(weight) { 48005 48006 const buffer = this.buffer, 48007 stride = this.valueSize, 48008 offset = stride * this._addIndex; 48009 48010 if (this.cumulativeWeightAdditive === 0) { 48011 48012 // add = identity 48013 48014 this._setIdentity(); 48015 48016 } 48017 48018 // add := add + incoming * weight 48019 48020 this._mixBufferRegionAdditive(buffer, offset, 0, weight, stride); 48021 this.cumulativeWeightAdditive += weight; 48022 48023 } 48024 48025 // apply the state of 'accu<i>' to the binding when accus differ 48026 apply(accuIndex) { 48027 48028 const stride = this.valueSize, 48029 buffer = this.buffer, 48030 offset = accuIndex * stride + stride, 48031 48032 weight = this.cumulativeWeight, 48033 weightAdditive = this.cumulativeWeightAdditive, 48034 48035 binding = this.binding; 48036 48037 this.cumulativeWeight = 0; 48038 this.cumulativeWeightAdditive = 0; 48039 48040 if (weight < 1) { 48041 48042 // accuN := accuN + original * ( 1 - cumulativeWeight ) 48043 48044 const originalValueOffset = stride * this._origIndex; 48045 48046 this._mixBufferRegion( 48047 buffer, offset, originalValueOffset, 1 - weight, stride); 48048 48049 } 48050 48051 if (weightAdditive > 0) { 48052 48053 // accuN := accuN + additive accuN 48054 48055 this._mixBufferRegionAdditive(buffer, offset, this._addIndex * stride, 1, stride); 48056 48057 } 48058 48059 for (let i = stride, e = stride + stride; i !== e; ++i) { 48060 48061 if (buffer[i] !== buffer[i + stride]) { 48062 48063 // value has changed -> update scene graph 48064 48065 binding.setValue(buffer, offset); 48066 break; 48067 48068 } 48069 48070 } 48071 48072 } 48073 48074 // remember the state of the bound property and copy it to both accus 48075 saveOriginalState() { 48076 48077 const binding = this.binding; 48078 48079 const buffer = this.buffer, 48080 stride = this.valueSize, 48081 48082 originalValueOffset = stride * this._origIndex; 48083 48084 binding.getValue(buffer, originalValueOffset); 48085 48086 // accu[0..1] := orig -- initially detect changes against the original 48087 for (let i = stride, e = originalValueOffset; i !== e; ++i) { 48088 48089 buffer[i] = buffer[originalValueOffset + (i % stride)]; 48090 48091 } 48092 48093 // Add to identity for additive 48094 this._setIdentity(); 48095 48096 this.cumulativeWeight = 0; 48097 this.cumulativeWeightAdditive = 0; 48098 48099 } 48100 48101 // apply the state previously taken via 'saveOriginalState' to the binding 48102 restoreOriginalState() { 48103 48104 const originalValueOffset = this.valueSize * 3; 48105 this.binding.setValue(this.buffer, originalValueOffset); 48106 48107 } 48108 48109 _setAdditiveIdentityNumeric() { 48110 48111 const startIndex = this._addIndex * this.valueSize; 48112 const endIndex = startIndex + this.valueSize; 48113 48114 for (let i = startIndex; i < endIndex; i++) { 48115 48116 this.buffer[i] = 0; 48117 48118 } 48119 48120 } 48121 48122 _setAdditiveIdentityQuaternion() { 48123 48124 this._setAdditiveIdentityNumeric(); 48125 this.buffer[this._addIndex * this.valueSize + 3] = 1; 48126 48127 } 48128 48129 _setAdditiveIdentityOther() { 48130 48131 const startIndex = this._origIndex * this.valueSize; 48132 const targetIndex = this._addIndex * this.valueSize; 48133 48134 for (let i = 0; i < this.valueSize; i++) { 48135 48136 this.buffer[targetIndex + i] = this.buffer[startIndex + i]; 48137 48138 } 48139 48140 } 48141 48142 48143 // mix functions 48144 48145 _select(buffer, dstOffset, srcOffset, t, stride) { 48146 48147 if (t >= 0.5) { 48148 48149 for (let i = 0; i !== stride; ++i) { 48150 48151 buffer[dstOffset + i] = buffer[srcOffset + i]; 48152 48153 } 48154 48155 } 48156 48157 } 48158 48159 _slerp(buffer, dstOffset, srcOffset, t) { 48160 48161 Quaternion.slerpFlat(buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t); 48162 48163 } 48164 48165 _slerpAdditive(buffer, dstOffset, srcOffset, t, stride) { 48166 48167 const workOffset = this._workIndex * stride; 48168 48169 // Store result in intermediate buffer offset 48170 Quaternion.multiplyQuaternionsFlat(buffer, workOffset, buffer, dstOffset, buffer, srcOffset); 48171 48172 // Slerp to the intermediate result 48173 Quaternion.slerpFlat(buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t); 48174 48175 } 48176 48177 _lerp(buffer, dstOffset, srcOffset, t, stride) { 48178 48179 const s = 1 - t; 48180 48181 for (let i = 0; i !== stride; ++i) { 48182 48183 const j = dstOffset + i; 48184 48185 buffer[j] = buffer[j] * s + buffer[srcOffset + i] * t; 48186 48187 } 48188 48189 } 48190 48191 _lerpAdditive(buffer, dstOffset, srcOffset, t, stride) { 48192 48193 for (let i = 0; i !== stride; ++i) { 48194 48195 const j = dstOffset + i; 48196 48197 buffer[j] = buffer[j] + buffer[srcOffset + i] * t; 48198 48199 } 48200 48201 } 48202 48203} 48204 48205// Characters [].:/ are reserved for track binding syntax. 48206const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/'; 48207const _reservedRe = new RegExp('[' + _RESERVED_CHARS_RE + ']', 'g'); 48208 48209// Attempts to allow node names from any language. ES5's `\w` regexp matches 48210// only latin characters, and the unicode \p{L} is not yet supported. So 48211// instead, we exclude reserved characters and match everything else. 48212const _wordChar = '[^' + _RESERVED_CHARS_RE + ']'; 48213const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace('\\.', '') + ']'; 48214 48215// Parent directories, delimited by '/' or ':'. Currently unused, but must 48216// be matched to parse the rest of the track name. 48217const _directoryRe = /*@__PURE__*/ /((?:WC+[\/:])*)/.source.replace('WC', _wordChar); 48218 48219// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'. 48220const _nodeRe = /*@__PURE__*/ /(WCOD+)?/.source.replace('WCOD', _wordCharOrDot); 48221 48222// Object on target node, and accessor. May not contain reserved 48223// characters. Accessor may contain any character except closing bracket. 48224const _objectRe = /*@__PURE__*/ /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace('WC', _wordChar); 48225 48226// Property and accessor. May not contain reserved characters. Accessor may 48227// contain any non-bracket characters. 48228const _propertyRe = /*@__PURE__*/ /\.(WC+)(?:\[(.+)\])?/.source.replace('WC', _wordChar); 48229 48230const _trackRe = new RegExp('' 48231 + '^' 48232 + _directoryRe 48233 + _nodeRe 48234 + _objectRe 48235 + _propertyRe 48236 + '$' 48237); 48238 48239const _supportedObjectNames = ['material', 'materials', 'bones', 'map']; 48240 48241class Composite { 48242 48243 constructor(targetGroup, path, optionalParsedPath) { 48244 48245 const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName(path); 48246 48247 this._targetGroup = targetGroup; 48248 this._bindings = targetGroup.subscribe_(path, parsedPath); 48249 48250 } 48251 48252 getValue(array, offset) { 48253 48254 this.bind(); // bind all binding 48255 48256 const firstValidIndex = this._targetGroup.nCachedObjects_, 48257 binding = this._bindings[firstValidIndex]; 48258 48259 // and only call .getValue on the first 48260 if (binding !== undefined) binding.getValue(array, offset); 48261 48262 } 48263 48264 setValue(array, offset) { 48265 48266 const bindings = this._bindings; 48267 48268 for (let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++i) { 48269 48270 bindings[i].setValue(array, offset); 48271 48272 } 48273 48274 } 48275 48276 bind() { 48277 48278 const bindings = this._bindings; 48279 48280 for (let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++i) { 48281 48282 bindings[i].bind(); 48283 48284 } 48285 48286 } 48287 48288 unbind() { 48289 48290 const bindings = this._bindings; 48291 48292 for (let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++i) { 48293 48294 bindings[i].unbind(); 48295 48296 } 48297 48298 } 48299 48300} 48301 48302// Note: This class uses a State pattern on a per-method basis: 48303// 'bind' sets 'this.getValue' / 'setValue' and shadows the 48304// prototype version of these methods with one that represents 48305// the bound state. When the property is not found, the methods 48306// become no-ops. 48307class PropertyBinding { 48308 48309 constructor(rootNode, path, parsedPath) { 48310 48311 this.path = path; 48312 this.parsedPath = parsedPath || PropertyBinding.parseTrackName(path); 48313 48314 this.node = PropertyBinding.findNode(rootNode, this.parsedPath.nodeName); 48315 48316 this.rootNode = rootNode; 48317 48318 // initial state of these methods that calls 'bind' 48319 this.getValue = this._getValue_unbound; 48320 this.setValue = this._setValue_unbound; 48321 48322 } 48323 48324 48325 static create(root, path, parsedPath) { 48326 48327 if (!(root && root.isAnimationObjectGroup)) { 48328 48329 return new PropertyBinding(root, path, parsedPath); 48330 48331 } else { 48332 48333 return new PropertyBinding.Composite(root, path, parsedPath); 48334 48335 } 48336 48337 } 48338 48339 /** 48340 * Replaces spaces with underscores and removes unsupported characters from 48341 * node names, to ensure compatibility with parseTrackName(). 48342 * 48343 * @param {string} name Node name to be sanitized. 48344 * @return {string} 48345 */ 48346 static sanitizeNodeName(name) { 48347 48348 return name.replace(/\s/g, '_').replace(_reservedRe, ''); 48349 48350 } 48351 48352 static parseTrackName(trackName) { 48353 48354 const matches = _trackRe.exec(trackName); 48355 48356 if (matches === null) { 48357 48358 throw new Error('PropertyBinding: Cannot parse trackName: ' + trackName); 48359 48360 } 48361 48362 const results = { 48363 // directoryName: matches[ 1 ], // (tschw) currently unused 48364 nodeName: matches[2], 48365 objectName: matches[3], 48366 objectIndex: matches[4], 48367 propertyName: matches[5], // required 48368 propertyIndex: matches[6] 48369 }; 48370 48371 const lastDot = results.nodeName && results.nodeName.lastIndexOf('.'); 48372 48373 if (lastDot !== undefined && lastDot !== - 1) { 48374 48375 const objectName = results.nodeName.substring(lastDot + 1); 48376 48377 // Object names must be checked against an allowlist. Otherwise, there 48378 // is no way to parse 'foo.bar.baz': 'baz' must be a property, but 48379 // 'bar' could be the objectName, or part of a nodeName (which can 48380 // include '.' characters). 48381 if (_supportedObjectNames.indexOf(objectName) !== - 1) { 48382 48383 results.nodeName = results.nodeName.substring(0, lastDot); 48384 results.objectName = objectName; 48385 48386 } 48387 48388 } 48389 48390 if (results.propertyName === null || results.propertyName.length === 0) { 48391 48392 throw new Error('PropertyBinding: can not parse propertyName from trackName: ' + trackName); 48393 48394 } 48395 48396 return results; 48397 48398 } 48399 48400 static findNode(root, nodeName) { 48401 48402 if (nodeName === undefined || nodeName === '' || nodeName === '.' || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid) { 48403 48404 return root; 48405 48406 } 48407 48408 // search into skeleton bones. 48409 if (root.skeleton) { 48410 48411 const bone = root.skeleton.getBoneByName(nodeName); 48412 48413 if (bone !== undefined) { 48414 48415 return bone; 48416 48417 } 48418 48419 } 48420 48421 // search into node subtree. 48422 if (root.children) { 48423 48424 const searchNodeSubtree = function (children) { 48425 48426 for (let i = 0; i < children.length; i++) { 48427 48428 const childNode = children[i]; 48429 48430 if (childNode.name === nodeName || childNode.uuid === nodeName) { 48431 48432 return childNode; 48433 48434 } 48435 48436 const result = searchNodeSubtree(childNode.children); 48437 48438 if (result) return result; 48439 48440 } 48441 48442 return null; 48443 48444 }; 48445 48446 const subTreeNode = searchNodeSubtree(root.children); 48447 48448 if (subTreeNode) { 48449 48450 return subTreeNode; 48451 48452 } 48453 48454 } 48455 48456 return null; 48457 48458 } 48459 48460 // these are used to "bind" a nonexistent property 48461 _getValue_unavailable() { } 48462 _setValue_unavailable() { } 48463 48464 // Getters 48465 48466 _getValue_direct(buffer, offset) { 48467 48468 buffer[offset] = this.targetObject[this.propertyName]; 48469 48470 } 48471 48472 _getValue_array(buffer, offset) { 48473 48474 const source = this.resolvedProperty; 48475 48476 for (let i = 0, n = source.length; i !== n; ++i) { 48477 48478 buffer[offset++] = source[i]; 48479 48480 } 48481 48482 } 48483 48484 _getValue_arrayElement(buffer, offset) { 48485 48486 buffer[offset] = this.resolvedProperty[this.propertyIndex]; 48487 48488 } 48489 48490 _getValue_toArray(buffer, offset) { 48491 48492 this.resolvedProperty.toArray(buffer, offset); 48493 48494 } 48495 48496 // Direct 48497 48498 _setValue_direct(buffer, offset) { 48499 48500 this.targetObject[this.propertyName] = buffer[offset]; 48501 48502 } 48503 48504 _setValue_direct_setNeedsUpdate(buffer, offset) { 48505 48506 this.targetObject[this.propertyName] = buffer[offset]; 48507 this.targetObject.needsUpdate = true; 48508 48509 } 48510 48511 _setValue_direct_setMatrixWorldNeedsUpdate(buffer, offset) { 48512 48513 this.targetObject[this.propertyName] = buffer[offset]; 48514 this.targetObject.matrixWorldNeedsUpdate = true; 48515 48516 } 48517 48518 // EntireArray 48519 48520 _setValue_array(buffer, offset) { 48521 48522 const dest = this.resolvedProperty; 48523 48524 for (let i = 0, n = dest.length; i !== n; ++i) { 48525 48526 dest[i] = buffer[offset++]; 48527 48528 } 48529 48530 } 48531 48532 _setValue_array_setNeedsUpdate(buffer, offset) { 48533 48534 const dest = this.resolvedProperty; 48535 48536 for (let i = 0, n = dest.length; i !== n; ++i) { 48537 48538 dest[i] = buffer[offset++]; 48539 48540 } 48541 48542 this.targetObject.needsUpdate = true; 48543 48544 } 48545
vendor: 7,729 bytes, lines 48546-48877
48546 _setValue_array_setMatrixWorldNeedsUpdate(buffer, offset) { 48547 48548 const dest = this.resolvedProperty; 48549 48550 for (let i = 0, n = dest.length; i !== n; ++i) { 48551 48552 dest[i] = buffer[offset++]; 48553 48554 } 48555 48556 this.targetObject.matrixWorldNeedsUpdate = true; 48557 48558 } 48559 48560 // ArrayElement 48561 48562 _setValue_arrayElement(buffer, offset) { 48563 48564 this.resolvedProperty[this.propertyIndex] = buffer[offset]; 48565 48566 } 48567 48568 _setValue_arrayElement_setNeedsUpdate(buffer, offset) { 48569 48570 this.resolvedProperty[this.propertyIndex] = buffer[offset]; 48571 this.targetObject.needsUpdate = true; 48572 48573 } 48574 48575 _setValue_arrayElement_setMatrixWorldNeedsUpdate(buffer, offset) { 48576 48577 this.resolvedProperty[this.propertyIndex] = buffer[offset]; 48578 this.targetObject.matrixWorldNeedsUpdate = true; 48579 48580 } 48581 48582 // HasToFromArray 48583 48584 _setValue_fromArray(buffer, offset) { 48585 48586 this.resolvedProperty.fromArray(buffer, offset); 48587 48588 } 48589 48590 _setValue_fromArray_setNeedsUpdate(buffer, offset) { 48591 48592 this.resolvedProperty.fromArray(buffer, offset); 48593 this.targetObject.needsUpdate = true; 48594 48595 } 48596 48597 _setValue_fromArray_setMatrixWorldNeedsUpdate(buffer, offset) { 48598 48599 this.resolvedProperty.fromArray(buffer, offset); 48600 this.targetObject.matrixWorldNeedsUpdate = true; 48601 48602 } 48603 48604 _getValue_unbound(targetArray, offset) { 48605 48606 this.bind(); 48607 this.getValue(targetArray, offset); 48608 48609 } 48610 48611 _setValue_unbound(sourceArray, offset) { 48612 48613 this.bind(); 48614 this.setValue(sourceArray, offset); 48615 48616 } 48617 48618 // create getter / setter pair for a property in the scene graph 48619 bind() { 48620 48621 let targetObject = this.node; 48622 const parsedPath = this.parsedPath; 48623 48624 const objectName = parsedPath.objectName; 48625 const propertyName = parsedPath.propertyName; 48626 let propertyIndex = parsedPath.propertyIndex; 48627 48628 if (!targetObject) { 48629 48630 targetObject = PropertyBinding.findNode(this.rootNode, parsedPath.nodeName); 48631 48632 this.node = targetObject; 48633 48634 } 48635 48636 // set fail state so we can just 'return' on error 48637 this.getValue = this._getValue_unavailable; 48638 this.setValue = this._setValue_unavailable; 48639 48640 // ensure there is a value node 48641 if (!targetObject) { 48642 48643 console.warn('THREE.PropertyBinding: No target node found for track: ' + this.path + '.'); 48644 return; 48645 48646 } 48647 48648 if (objectName) { 48649 48650 let objectIndex = parsedPath.objectIndex; 48651 48652 // special cases were we need to reach deeper into the hierarchy to get the face materials.... 48653 switch (objectName) { 48654 48655 case 'materials': 48656 48657 if (!targetObject.material) { 48658 48659 console.error('THREE.PropertyBinding: Can not bind to material as node does not have a material.', this); 48660 return; 48661 48662 } 48663 48664 if (!targetObject.material.materials) { 48665 48666 console.error('THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this); 48667 return; 48668 48669 } 48670 48671 targetObject = targetObject.material.materials; 48672 48673 break; 48674 48675 case 'bones': 48676 48677 if (!targetObject.skeleton) { 48678 48679 console.error('THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this); 48680 return; 48681 48682 } 48683 48684 // potential future optimization: skip this if propertyIndex is already an integer 48685 // and convert the integer string to a true integer. 48686 48687 targetObject = targetObject.skeleton.bones; 48688 48689 // support resolving morphTarget names into indices. 48690 for (let i = 0; i < targetObject.length; i++) { 48691 48692 if (targetObject[i].name === objectIndex) { 48693 48694 objectIndex = i; 48695 break; 48696 48697 } 48698 48699 } 48700 48701 break; 48702 48703 case 'map': 48704 48705 if ('map' in targetObject) { 48706 48707 targetObject = targetObject.map; 48708 break; 48709 48710 } 48711 48712 if (!targetObject.material) { 48713 48714 console.error('THREE.PropertyBinding: Can not bind to material as node does not have a material.', this); 48715 return; 48716 48717 } 48718 48719 if (!targetObject.material.map) { 48720 48721 console.error('THREE.PropertyBinding: Can not bind to material.map as node.material does not have a map.', this); 48722 return; 48723 48724 } 48725 48726 targetObject = targetObject.material.map; 48727 break; 48728 48729 default: 48730 48731 if (targetObject[objectName] === undefined) { 48732 48733 console.error('THREE.PropertyBinding: Can not bind to objectName of node undefined.', this); 48734 return; 48735 48736 } 48737 48738 targetObject = targetObject[objectName]; 48739 48740 } 48741 48742 48743 if (objectIndex !== undefined) { 48744 48745 if (targetObject[objectIndex] === undefined) { 48746 48747 console.error('THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject); 48748 return; 48749 48750 } 48751 48752 targetObject = targetObject[objectIndex]; 48753 48754 } 48755 48756 } 48757 48758 // resolve property 48759 const nodeProperty = targetObject[propertyName]; 48760 48761 if (nodeProperty === undefined) { 48762 48763 const nodeName = parsedPath.nodeName; 48764 48765 console.error('THREE.PropertyBinding: Trying to update property for track: ' + nodeName + 48766 '.' + propertyName + ' but it wasn\'t found.', targetObject); 48767 return; 48768 48769 } 48770 48771 // determine versioning scheme 48772 let versioning = this.Versioning.None; 48773 48774 this.targetObject = targetObject; 48775 48776 if (targetObject.needsUpdate !== undefined) { // material 48777 48778 versioning = this.Versioning.NeedsUpdate; 48779 48780 } else if (targetObject.matrixWorldNeedsUpdate !== undefined) { // node transform 48781 48782 versioning = this.Versioning.MatrixWorldNeedsUpdate; 48783 48784 } 48785 48786 // determine how the property gets bound 48787 let bindingType = this.BindingType.Direct; 48788 48789 if (propertyIndex !== undefined) { 48790 48791 // access a sub element of the property array (only primitives are supported right now) 48792 48793 if (propertyName === 'morphTargetInfluences') { 48794 48795 // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. 48796 48797 // support resolving morphTarget names into indices. 48798 if (!targetObject.geometry) { 48799 48800 console.error('THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this); 48801 return; 48802 48803 } 48804 48805 if (!targetObject.geometry.morphAttributes) { 48806 48807 console.error('THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this); 48808 return; 48809 48810 } 48811 48812 if (targetObject.morphTargetDictionary[propertyIndex] !== undefined) { 48813 48814 propertyIndex = targetObject.morphTargetDictionary[propertyIndex]; 48815 48816 } 48817 48818 } 48819 48820 bindingType = this.BindingType.ArrayElement; 48821 48822 this.resolvedProperty = nodeProperty; 48823 this.propertyIndex = propertyIndex; 48824 48825 } else if (nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined) { 48826 48827 // must use copy for Object3D.Euler/Quaternion 48828 48829 bindingType = this.BindingType.HasFromToArray; 48830 48831 this.resolvedProperty = nodeProperty; 48832 48833 } else if (Array.isArray(nodeProperty)) { 48834 48835 bindingType = this.BindingType.EntireArray; 48836 48837 this.resolvedProperty = nodeProperty; 48838 48839 } else { 48840 48841 this.propertyName = propertyName; 48842 48843 } 48844 48845 // select getter / setter 48846 this.getValue = this.GetterByBindingType[bindingType]; 48847 this.setValue = this.SetterByBindingTypeAndVersioning[bindingType][versioning]; 48848 48849 } 48850 48851 unbind() { 48852 48853 this.node = null; 48854 48855 // back to the prototype version of getValue / setValue 48856 // note: avoiding to mutate the shape of 'this' via 'delete' 48857 this.getValue = this._getValue_unbound; 48858 this.setValue = this._setValue_unbound; 48859 48860 } 48861 48862} 48863 48864PropertyBinding.Composite = Composite; 48865 48866PropertyBinding.prototype.BindingType = { 48867 Direct: 0, 48868 EntireArray: 1, 48869 ArrayElement: 2, 48870 HasFromToArray: 3 48871}; 48872 48873PropertyBinding.prototype.Versioning = { 48874 None: 0, 48875 NeedsUpdate: 1, 48876 MatrixWorldNeedsUpdate: 2 48877};
vendor: 4,388 bytes, lines 48878-49058
48878 48879PropertyBinding.prototype.GetterByBindingType = [ 48880 48881 PropertyBinding.prototype._getValue_direct, 48882 PropertyBinding.prototype._getValue_array, 48883 PropertyBinding.prototype._getValue_arrayElement, 48884 PropertyBinding.prototype._getValue_toArray, 48885 48886]; 48887 48888PropertyBinding.prototype.SetterByBindingTypeAndVersioning = [ 48889 48890 [ 48891 // Direct 48892 PropertyBinding.prototype._setValue_direct, 48893 PropertyBinding.prototype._setValue_direct_setNeedsUpdate, 48894 PropertyBinding.prototype._setValue_direct_setMatrixWorldNeedsUpdate, 48895 48896 ], [ 48897 48898 // EntireArray 48899 48900 PropertyBinding.prototype._setValue_array, 48901 PropertyBinding.prototype._setValue_array_setNeedsUpdate, 48902 PropertyBinding.prototype._setValue_array_setMatrixWorldNeedsUpdate, 48903 48904 ], [ 48905 48906 // ArrayElement 48907 PropertyBinding.prototype._setValue_arrayElement, 48908 PropertyBinding.prototype._setValue_arrayElement_setNeedsUpdate, 48909 PropertyBinding.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate, 48910 48911 ], [ 48912 48913 // HasToFromArray 48914 PropertyBinding.prototype._setValue_fromArray, 48915 PropertyBinding.prototype._setValue_fromArray_setNeedsUpdate, 48916 PropertyBinding.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate, 48917 48918 ] 48919 48920]; 48921 48922/** 48923 * 48924 * A group of objects that receives a shared animation state. 48925 * 48926 * Usage: 48927 * 48928 * - Add objects you would otherwise pass as 'root' to the 48929 * constructor or the .clipAction method of AnimationMixer. 48930 * 48931 * - Instead pass this object as 'root'. 48932 * 48933 * - You can also add and remove objects later when the mixer 48934 * is running. 48935 * 48936 * Note: 48937 * 48938 * Objects of this class appear as one object to the mixer, 48939 * so cache control of the individual objects must be done 48940 * on the group. 48941 * 48942 * Limitation: 48943 * 48944 * - The animated properties must be compatible among the 48945 * all objects in the group. 48946 * 48947 * - A single property can either be controlled through a 48948 * target group or directly, but not both. 48949 */ 48950 48951class AnimationObjectGroup { 48952 48953 constructor() { 48954 48955 this.isAnimationObjectGroup = true; 48956 48957 this.uuid = generateUUID(); 48958 48959 // cached objects followed by the active ones 48960 this._objects = Array.prototype.slice.call(arguments); 48961 48962 this.nCachedObjects_ = 0; // threshold 48963 // note: read by PropertyBinding.Composite 48964 48965 const indices = {}; 48966 this._indicesByUUID = indices; // for bookkeeping 48967 48968 for (let i = 0, n = arguments.length; i !== n; ++i) { 48969 48970 indices[arguments[i].uuid] = i; 48971 48972 } 48973 48974 this._paths = []; // inside: string 48975 this._parsedPaths = []; // inside: { we don't care, here } 48976 this._bindings = []; // inside: Array< PropertyBinding > 48977 this._bindingsIndicesByPath = {}; // inside: indices in these arrays 48978 48979 const scope = this; 48980 48981 this.stats = { 48982 48983 objects: { 48984 get total() { 48985 48986 return scope._objects.length; 48987 48988 }, 48989 get inUse() { 48990 48991 return this.total - scope.nCachedObjects_; 48992 48993 } 48994 }, 48995 get bindingsPerObject() { 48996 48997 return scope._bindings.length; 48998 48999 } 49000 49001 }; 49002 49003 } 49004 49005 add() { 49006 49007 const objects = this._objects, 49008 indicesByUUID = this._indicesByUUID, 49009 paths = this._paths, 49010 parsedPaths = this._parsedPaths, 49011 bindings = this._bindings, 49012 nBindings = bindings.length; 49013 49014 let knownObject = undefined, 49015 nObjects = objects.length, 49016 nCachedObjects = this.nCachedObjects_; 49017 49018 for (let i = 0, n = arguments.length; i !== n; ++i) { 49019 49020 const object = arguments[i], 49021 uuid = object.uuid; 49022 let index = indicesByUUID[uuid]; 49023 49024 if (index === undefined) { 49025 49026 // unknown object -> add it to the ACTIVE region 49027 49028 index = nObjects++; 49029 indicesByUUID[uuid] = index; 49030 objects.push(object); 49031 49032 // accounting is done, now do the same for all bindings 49033 49034 for (let j = 0, m = nBindings; j !== m; ++j) { 49035 49036 bindings[j].push(new PropertyBinding(object, paths[j], parsedPaths[j])); 49037 49038 } 49039 49040 } else if (index < nCachedObjects) { 49041 49042 knownObject = objects[index]; 49043 49044 // move existing object to the ACTIVE region 49045 49046 const firstActiveIndex = --nCachedObjects, 49047 lastCachedObject = objects[firstActiveIndex]; 49048 49049 indicesByUUID[lastCachedObject.uuid] = index; 49050 objects[index] = lastCachedObject; 49051 49052 indicesByUUID[uuid] = firstActiveIndex; 49053 objects[firstActiveIndex] = object; 49054 49055 // accounting is done, now do the same for all bindings 49056 49057 for (let j = 0, m = nBindings; j !== m; ++j) { 49058
vendor: 4,615 bytes, lines 49059-49241
49059 const bindingsForPath = bindings[j], 49060 lastCached = bindingsForPath[firstActiveIndex]; 49061 49062 let binding = bindingsForPath[index]; 49063 49064 bindingsForPath[index] = lastCached; 49065 49066 if (binding === undefined) { 49067 49068 // since we do not bother to create new bindings 49069 // for objects that are cached, the binding may 49070 // or may not exist 49071 49072 binding = new PropertyBinding(object, paths[j], parsedPaths[j]); 49073 49074 } 49075 49076 bindingsForPath[firstActiveIndex] = binding; 49077 49078 } 49079 49080 } else if (objects[index] !== knownObject) { 49081 49082 console.error('THREE.AnimationObjectGroup: Different objects with the same UUID ' + 49083 'detected. Clean the caches or recreate your infrastructure when reloading scenes.'); 49084 49085 } // else the object is already where we want it to be 49086 49087 } // for arguments 49088 49089 this.nCachedObjects_ = nCachedObjects; 49090 49091 } 49092 49093 remove() { 49094 49095 const objects = this._objects, 49096 indicesByUUID = this._indicesByUUID, 49097 bindings = this._bindings, 49098 nBindings = bindings.length; 49099 49100 let nCachedObjects = this.nCachedObjects_; 49101 49102 for (let i = 0, n = arguments.length; i !== n; ++i) { 49103 49104 const object = arguments[i], 49105 uuid = object.uuid, 49106 index = indicesByUUID[uuid]; 49107 49108 if (index !== undefined && index >= nCachedObjects) { 49109 49110 // move existing object into the CACHED region 49111 49112 const lastCachedIndex = nCachedObjects++, 49113 firstActiveObject = objects[lastCachedIndex]; 49114 49115 indicesByUUID[firstActiveObject.uuid] = index; 49116 objects[index] = firstActiveObject; 49117 49118 indicesByUUID[uuid] = lastCachedIndex; 49119 objects[lastCachedIndex] = object; 49120 49121 // accounting is done, now do the same for all bindings 49122 49123 for (let j = 0, m = nBindings; j !== m; ++j) { 49124 49125 const bindingsForPath = bindings[j], 49126 firstActive = bindingsForPath[lastCachedIndex], 49127 binding = bindingsForPath[index]; 49128 49129 bindingsForPath[index] = firstActive; 49130 bindingsForPath[lastCachedIndex] = binding; 49131 49132 } 49133 49134 } 49135 49136 } // for arguments 49137 49138 this.nCachedObjects_ = nCachedObjects; 49139 49140 } 49141 49142 // remove & forget 49143 uncache() { 49144 49145 const objects = this._objects, 49146 indicesByUUID = this._indicesByUUID, 49147 bindings = this._bindings, 49148 nBindings = bindings.length; 49149 49150 let nCachedObjects = this.nCachedObjects_, 49151 nObjects = objects.length; 49152 49153 for (let i = 0, n = arguments.length; i !== n; ++i) { 49154 49155 const object = arguments[i], 49156 uuid = object.uuid, 49157 index = indicesByUUID[uuid]; 49158 49159 if (index !== undefined) { 49160 49161 delete indicesByUUID[uuid]; 49162 49163 if (index < nCachedObjects) { 49164 49165 // object is cached, shrink the CACHED region 49166 49167 const firstActiveIndex = --nCachedObjects, 49168 lastCachedObject = objects[firstActiveIndex], 49169 lastIndex = --nObjects, 49170 lastObject = objects[lastIndex]; 49171 49172 // last cached object takes this object's place 49173 indicesByUUID[lastCachedObject.uuid] = index; 49174 objects[index] = lastCachedObject; 49175 49176 // last object goes to the activated slot and pop 49177 indicesByUUID[lastObject.uuid] = firstActiveIndex; 49178 objects[firstActiveIndex] = lastObject; 49179 objects.pop(); 49180 49181 // accounting is done, now do the same for all bindings 49182 49183 for (let j = 0, m = nBindings; j !== m; ++j) { 49184 49185 const bindingsForPath = bindings[j], 49186 lastCached = bindingsForPath[firstActiveIndex], 49187 last = bindingsForPath[lastIndex]; 49188 49189 bindingsForPath[index] = lastCached; 49190 bindingsForPath[firstActiveIndex] = last; 49191 bindingsForPath.pop(); 49192 49193 } 49194 49195 } else { 49196 49197 // object is active, just swap with the last and pop 49198 49199 const lastIndex = --nObjects, 49200 lastObject = objects[lastIndex]; 49201 49202 if (lastIndex > 0) { 49203 49204 indicesByUUID[lastObject.uuid] = index; 49205 49206 } 49207 49208 objects[index] = lastObject; 49209 objects.pop(); 49210 49211 // accounting is done, now do the same for all bindings 49212 49213 for (let j = 0, m = nBindings; j !== m; ++j) { 49214 49215 const bindingsForPath = bindings[j]; 49216 49217 bindingsForPath[index] = bindingsForPath[lastIndex]; 49218 bindingsForPath.pop(); 49219 49220 } 49221 49222 } // cached or active 49223 49224 } // if object is known 49225 49226 } // for arguments 49227 49228 this.nCachedObjects_ = nCachedObjects; 49229 49230 } 49231 49232 // Internal interface used by befriended PropertyBinding.Composite: 49233 49234 subscribe_(path, parsedPath) { 49235 49236 // returns an array of bindings for the given path that is changed 49237 // according to the contained objects in the group 49238 49239 const indicesByPath = this._bindingsIndicesByPath; 49240 let index = indicesByPath[path]; 49241 const bindings = this._bindings;
vendor: 8,095 bytes, lines 49242-49643
49242 49243 if (index !== undefined) return bindings[index]; 49244 49245 const paths = this._paths, 49246 parsedPaths = this._parsedPaths, 49247 objects = this._objects, 49248 nObjects = objects.length, 49249 nCachedObjects = this.nCachedObjects_, 49250 bindingsForPath = new Array(nObjects); 49251 49252 index = bindings.length; 49253 49254 indicesByPath[path] = index; 49255 49256 paths.push(path); 49257 parsedPaths.push(parsedPath); 49258 bindings.push(bindingsForPath); 49259 49260 for (let i = nCachedObjects, n = objects.length; i !== n; ++i) { 49261 49262 const object = objects[i]; 49263 bindingsForPath[i] = new PropertyBinding(object, path, parsedPath); 49264 49265 } 49266 49267 return bindingsForPath; 49268 49269 } 49270 49271 unsubscribe_(path) { 49272 49273 // tells the group to forget about a property path and no longer 49274 // update the array previously obtained with 'subscribe_' 49275 49276 const indicesByPath = this._bindingsIndicesByPath, 49277 index = indicesByPath[path]; 49278 49279 if (index !== undefined) { 49280 49281 const paths = this._paths, 49282 parsedPaths = this._parsedPaths, 49283 bindings = this._bindings, 49284 lastBindingsIndex = bindings.length - 1, 49285 lastBindings = bindings[lastBindingsIndex], 49286 lastBindingsPath = path[lastBindingsIndex]; 49287 49288 indicesByPath[lastBindingsPath] = index; 49289 49290 bindings[index] = lastBindings; 49291 bindings.pop(); 49292 49293 parsedPaths[index] = parsedPaths[lastBindingsIndex]; 49294 parsedPaths.pop(); 49295 49296 paths[index] = paths[lastBindingsIndex]; 49297 paths.pop(); 49298 49299 } 49300 49301 } 49302 49303} 49304 49305class AnimationAction { 49306 49307 constructor(mixer, clip, localRoot = null, blendMode = clip.blendMode) { 49308 49309 this._mixer = mixer; 49310 this._clip = clip; 49311 this._localRoot = localRoot; 49312 this.blendMode = blendMode; 49313 49314 const tracks = clip.tracks, 49315 nTracks = tracks.length, 49316 interpolants = new Array(nTracks); 49317 49318 const interpolantSettings = { 49319 endingStart: ZeroCurvatureEnding, 49320 endingEnd: ZeroCurvatureEnding 49321 }; 49322 49323 for (let i = 0; i !== nTracks; ++i) { 49324 49325 const interpolant = tracks[i].createInterpolant(null); 49326 interpolants[i] = interpolant; 49327 interpolant.settings = interpolantSettings; 49328 49329 } 49330 49331 this._interpolantSettings = interpolantSettings; 49332 49333 this._interpolants = interpolants; // bound by the mixer 49334 49335 // inside: PropertyMixer (managed by the mixer) 49336 this._propertyBindings = new Array(nTracks); 49337 49338 this._cacheIndex = null; // for the memory manager 49339 this._byClipCacheIndex = null; // for the memory manager 49340 49341 this._timeScaleInterpolant = null; 49342 this._weightInterpolant = null; 49343 49344 this.loop = LoopRepeat; 49345 this._loopCount = - 1; 49346 49347 // global mixer time when the action is to be started 49348 // it's set back to 'null' upon start of the action 49349 this._startTime = null; 49350 49351 // scaled local time of the action 49352 // gets clamped or wrapped to 0..clip.duration according to loop 49353 this.time = 0; 49354 49355 this.timeScale = 1; 49356 this._effectiveTimeScale = 1; 49357 49358 this.weight = 1; 49359 this._effectiveWeight = 1; 49360 49361 this.repetitions = Infinity; // no. of repetitions when looping 49362 49363 this.paused = false; // true -> zero effective time scale 49364 this.enabled = true; // false -> zero effective weight 49365 49366 this.clampWhenFinished = false;// keep feeding the last frame? 49367 49368 this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate 49369 this.zeroSlopeAtEnd = true;// clips for start, loop and end 49370 49371 } 49372 49373 // State & Scheduling 49374 49375 play() { 49376 49377 this._mixer._activateAction(this); 49378 49379 return this; 49380 49381 } 49382 49383 stop() { 49384 49385 this._mixer._deactivateAction(this); 49386 49387 return this.reset(); 49388 49389 } 49390 49391 reset() { 49392 49393 this.paused = false; 49394 this.enabled = true; 49395 49396 this.time = 0; // restart clip 49397 this._loopCount = - 1;// forget previous loops 49398 this._startTime = null;// forget scheduling 49399 49400 return this.stopFading().stopWarping(); 49401 49402 } 49403 49404 isRunning() { 49405 49406 return this.enabled && !this.paused && this.timeScale !== 0 && 49407 this._startTime === null && this._mixer._isActiveAction(this); 49408 49409 } 49410 49411 // return true when play has been called 49412 isScheduled() { 49413 49414 return this._mixer._isActiveAction(this); 49415 49416 } 49417 49418 startAt(time) { 49419 49420 this._startTime = time; 49421 49422 return this; 49423 49424 } 49425 49426 setLoop(mode, repetitions) { 49427 49428 this.loop = mode; 49429 this.repetitions = repetitions; 49430 49431 return this; 49432 49433 } 49434 49435 // Weight 49436 49437 // set the weight stopping any scheduled fading 49438 // although .enabled = false yields an effective weight of zero, this 49439 // method does *not* change .enabled, because it would be confusing 49440 setEffectiveWeight(weight) { 49441 49442 this.weight = weight; 49443 49444 // note: same logic as when updated at runtime 49445 this._effectiveWeight = this.enabled ? weight : 0; 49446 49447 return this.stopFading(); 49448 49449 } 49450 49451 // return the weight considering fading and .enabled 49452 getEffectiveWeight() { 49453 49454 return this._effectiveWeight; 49455 49456 } 49457 49458 fadeIn(duration) { 49459 49460 return this._scheduleFading(duration, 0, 1); 49461 49462 } 49463 49464 fadeOut(duration) { 49465 49466 return this._scheduleFading(duration, 1, 0); 49467 49468 } 49469 49470 crossFadeFrom(fadeOutAction, duration, warp) { 49471 49472 fadeOutAction.fadeOut(duration); 49473 this.fadeIn(duration); 49474 49475 if (warp) { 49476 49477 const fadeInDuration = this._clip.duration, 49478 fadeOutDuration = fadeOutAction._clip.duration, 49479 49480 startEndRatio = fadeOutDuration / fadeInDuration, 49481 endStartRatio = fadeInDuration / fadeOutDuration; 49482 49483 fadeOutAction.warp(1.0, startEndRatio, duration); 49484 this.warp(endStartRatio, 1.0, duration); 49485 49486 } 49487 49488 return this; 49489 49490 } 49491 49492 crossFadeTo(fadeInAction, duration, warp) { 49493 49494 return fadeInAction.crossFadeFrom(this, duration, warp); 49495 49496 } 49497 49498 stopFading() { 49499 49500 const weightInterpolant = this._weightInterpolant; 49501 49502 if (weightInterpolant !== null) { 49503 49504 this._weightInterpolant = null; 49505 this._mixer._takeBackControlInterpolant(weightInterpolant); 49506 49507 } 49508 49509 return this; 49510 49511 } 49512 49513 // Time Scale Control 49514 49515 // set the time scale stopping any scheduled warping 49516 // although .paused = true yields an effective time scale of zero, this 49517 // method does *not* change .paused, because it would be confusing 49518 setEffectiveTimeScale(timeScale) { 49519 49520 this.timeScale = timeScale; 49521 this._effectiveTimeScale = this.paused ? 0 : timeScale; 49522 49523 return this.stopWarping(); 49524 49525 } 49526 49527 // return the time scale considering warping and .paused 49528 getEffectiveTimeScale() { 49529 49530 return this._effectiveTimeScale; 49531 49532 } 49533 49534 setDuration(duration) { 49535 49536 this.timeScale = this._clip.duration / duration; 49537 49538 return this.stopWarping(); 49539 49540 } 49541 49542 syncWith(action) { 49543 49544 this.time = action.time; 49545 this.timeScale = action.timeScale; 49546 49547 return this.stopWarping(); 49548 49549 } 49550 49551 halt(duration) { 49552 49553 return this.warp(this._effectiveTimeScale, 0, duration); 49554 49555 } 49556 49557 warp(startTimeScale, endTimeScale, duration) { 49558 49559 const mixer = this._mixer, 49560 now = mixer.time, 49561 timeScale = this.timeScale; 49562 49563 let interpolant = this._timeScaleInterpolant; 49564 49565 if (interpolant === null) { 49566 49567 interpolant = mixer._lendControlInterpolant(); 49568 this._timeScaleInterpolant = interpolant; 49569 49570 } 49571 49572 const times = interpolant.parameterPositions, 49573 values = interpolant.sampleValues; 49574 49575 times[0] = now; 49576 times[1] = now + duration; 49577 49578 values[0] = startTimeScale / timeScale; 49579 values[1] = endTimeScale / timeScale; 49580 49581 return this; 49582 49583 } 49584 49585 stopWarping() { 49586 49587 const timeScaleInterpolant = this._timeScaleInterpolant; 49588 49589 if (timeScaleInterpolant !== null) { 49590 49591 this._timeScaleInterpolant = null; 49592 this._mixer._takeBackControlInterpolant(timeScaleInterpolant); 49593 49594 } 49595 49596 return this; 49597 49598 } 49599 49600 // Object Accessors 49601 49602 getMixer() { 49603 49604 return this._mixer; 49605 49606 } 49607 49608 getClip() { 49609 49610 return this._clip; 49611 49612 } 49613 49614 getRoot() { 49615 49616 return this._localRoot || this._mixer._root; 49617 49618 } 49619 49620 // Interna 49621 49622 _update(time, deltaTime, timeDirection, accuIndex) { 49623 49624 // called by the mixer 49625 49626 if (!this.enabled) { 49627 49628 // call ._updateWeight() to update ._effectiveWeight 49629 49630 this._updateWeight(time); 49631 return; 49632 49633 } 49634 49635 const startTime = this._startTime; 49636 49637 if (startTime !== null) { 49638 49639 // check for scheduled start of action 49640 49641 const timeRunning = (time - startTime) * timeDirection; 49642 if (timeRunning < 0 || timeDirection === 0) { 49643
vendor: 8,546 bytes, lines 49644-50107
49644 deltaTime = 0; 49645 49646 } else { 49647 49648 49649 this._startTime = null; // unschedule 49650 deltaTime = timeDirection * timeRunning; 49651 49652 } 49653 49654 } 49655 49656 // apply time scale and advance time 49657 49658 deltaTime *= this._updateTimeScale(time); 49659 const clipTime = this._updateTime(deltaTime); 49660 49661 // note: _updateTime may disable the action resulting in 49662 // an effective weight of 0 49663 49664 const weight = this._updateWeight(time); 49665 49666 if (weight > 0) { 49667 49668 const interpolants = this._interpolants; 49669 const propertyMixers = this._propertyBindings; 49670 49671 switch (this.blendMode) { 49672 49673 case AdditiveAnimationBlendMode: 49674 49675 for (let j = 0, m = interpolants.length; j !== m; ++j) { 49676 49677 interpolants[j].evaluate(clipTime); 49678 propertyMixers[j].accumulateAdditive(weight); 49679 49680 } 49681 49682 break; 49683 49684 case NormalAnimationBlendMode: 49685 default: 49686 49687 for (let j = 0, m = interpolants.length; j !== m; ++j) { 49688 49689 interpolants[j].evaluate(clipTime); 49690 propertyMixers[j].accumulate(accuIndex, weight); 49691 49692 } 49693 49694 } 49695 49696 } 49697 49698 } 49699 49700 _updateWeight(time) { 49701 49702 let weight = 0; 49703 49704 if (this.enabled) { 49705 49706 weight = this.weight; 49707 const interpolant = this._weightInterpolant; 49708 49709 if (interpolant !== null) { 49710 49711 const interpolantValue = interpolant.evaluate(time)[0]; 49712 49713 weight *= interpolantValue; 49714 49715 if (time > interpolant.parameterPositions[1]) { 49716 49717 this.stopFading(); 49718 49719 if (interpolantValue === 0) { 49720 49721 // faded out, disable 49722 this.enabled = false; 49723 49724 } 49725 49726 } 49727 49728 } 49729 49730 } 49731 49732 this._effectiveWeight = weight; 49733 return weight; 49734 49735 } 49736 49737 _updateTimeScale(time) { 49738 49739 let timeScale = 0; 49740 49741 if (!this.paused) { 49742 49743 timeScale = this.timeScale; 49744 49745 const interpolant = this._timeScaleInterpolant; 49746 49747 if (interpolant !== null) { 49748 49749 const interpolantValue = interpolant.evaluate(time)[0]; 49750 49751 timeScale *= interpolantValue; 49752 49753 if (time > interpolant.parameterPositions[1]) { 49754 49755 this.stopWarping(); 49756 49757 if (timeScale === 0) { 49758 49759 // motion has halted, pause 49760 this.paused = true; 49761 49762 } else { 49763 49764 // warp done - apply final time scale 49765 this.timeScale = timeScale; 49766 49767 } 49768 49769 } 49770 49771 } 49772 49773 } 49774 49775 this._effectiveTimeScale = timeScale; 49776 return timeScale; 49777 49778 } 49779 49780 _updateTime(deltaTime) { 49781 49782 const duration = this._clip.duration; 49783 const loop = this.loop; 49784 49785 let time = this.time + deltaTime; 49786 let loopCount = this._loopCount; 49787 49788 const pingPong = (loop === LoopPingPong); 49789 49790 if (deltaTime === 0) { 49791 49792 if (loopCount === - 1) return time; 49793 49794 return (pingPong && (loopCount & 1) === 1) ? duration - time : time; 49795 49796 } 49797 49798 if (loop === LoopOnce) { 49799 49800 if (loopCount === - 1) { 49801 49802 // just started 49803 49804 this._loopCount = 0; 49805 this._setEndings(true, true, false); 49806 49807 } 49808 49809 handle_stop: { 49810 49811 if (time >= duration) { 49812 49813 time = duration; 49814 49815 } else if (time < 0) { 49816 49817 time = 0; 49818 49819 } else { 49820 49821 this.time = time; 49822 49823 break handle_stop; 49824 49825 } 49826 49827 if (this.clampWhenFinished) this.paused = true; 49828 else this.enabled = false; 49829 49830 this.time = time; 49831 49832 this._mixer.dispatchEvent({ 49833 type: 'finished', action: this, 49834 direction: deltaTime < 0 ? - 1 : 1 49835 }); 49836 49837 } 49838 49839 } else { // repetitive Repeat or PingPong 49840 49841 if (loopCount === - 1) { 49842 49843 // just started 49844 49845 if (deltaTime >= 0) { 49846 49847 loopCount = 0; 49848 49849 this._setEndings(true, this.repetitions === 0, pingPong); 49850 49851 } else { 49852 49853 // when looping in reverse direction, the initial 49854 // transition through zero counts as a repetition, 49855 // so leave loopCount at -1 49856 49857 this._setEndings(this.repetitions === 0, true, pingPong); 49858 49859 } 49860 49861 } 49862 49863 if (time >= duration || time < 0) { 49864 49865 // wrap around 49866 49867 const loopDelta = Math.floor(time / duration); // signed 49868 time -= duration * loopDelta; 49869 49870 loopCount += Math.abs(loopDelta); 49871 49872 const pending = this.repetitions - loopCount; 49873 49874 if (pending <= 0) { 49875 49876 // have to stop (switch state, clamp time, fire event) 49877 49878 if (this.clampWhenFinished) this.paused = true; 49879 else this.enabled = false; 49880 49881 time = deltaTime > 0 ? duration : 0; 49882 49883 this.time = time; 49884 49885 this._mixer.dispatchEvent({ 49886 type: 'finished', action: this, 49887 direction: deltaTime > 0 ? 1 : - 1 49888 }); 49889 49890 } else { 49891 49892 // keep running 49893 49894 if (pending === 1) { 49895 49896 // entering the last round 49897 49898 const atStart = deltaTime < 0; 49899 this._setEndings(atStart, !atStart, pingPong); 49900 49901 } else { 49902 49903 this._setEndings(false, false, pingPong); 49904 49905 } 49906 49907 this._loopCount = loopCount; 49908 49909 this.time = time; 49910 49911 this._mixer.dispatchEvent({ 49912 type: 'loop', action: this, loopDelta: loopDelta 49913 }); 49914 49915 } 49916 49917 } else { 49918 49919 this.time = time; 49920 49921 } 49922 49923 if (pingPong && (loopCount & 1) === 1) { 49924 49925 // invert time for the "pong round" 49926 49927 return duration - time; 49928 49929 } 49930 49931 } 49932 49933 return time; 49934 49935 } 49936 49937 _setEndings(atStart, atEnd, pingPong) { 49938 49939 const settings = this._interpolantSettings; 49940 49941 if (pingPong) { 49942 49943 settings.endingStart = ZeroSlopeEnding; 49944 settings.endingEnd = ZeroSlopeEnding; 49945 49946 } else { 49947 49948 // assuming for LoopOnce atStart == atEnd == true 49949 49950 if (atStart) { 49951 49952 settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding; 49953 49954 } else { 49955 49956 settings.endingStart = WrapAroundEnding; 49957 49958 } 49959 49960 if (atEnd) { 49961 49962 settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding; 49963 49964 } else { 49965 49966 settings.endingEnd = WrapAroundEnding; 49967 49968 } 49969 49970 } 49971 49972 } 49973 49974 _scheduleFading(duration, weightNow, weightThen) { 49975 49976 const mixer = this._mixer, now = mixer.time; 49977 let interpolant = this._weightInterpolant; 49978 49979 if (interpolant === null) { 49980 49981 interpolant = mixer._lendControlInterpolant(); 49982 this._weightInterpolant = interpolant; 49983 49984 } 49985 49986 const times = interpolant.parameterPositions, 49987 values = interpolant.sampleValues; 49988 49989 times[0] = now; 49990 values[0] = weightNow; 49991 times[1] = now + duration; 49992 values[1] = weightThen; 49993 49994 return this; 49995 49996 } 49997 49998} 49999 50000const _controlInterpolantsResultBuffer = new Float32Array(1); 50001 50002 50003class AnimationMixer extends EventDispatcher { 50004 50005 constructor(root) { 50006 50007 super(); 50008 50009 this._root = root; 50010 this._initMemoryManager(); 50011 this._accuIndex = 0; 50012 this.time = 0; 50013 this.timeScale = 1.0; 50014 50015 } 50016 50017 _bindAction(action, prototypeAction) { 50018 50019 const root = action._localRoot || this._root, 50020 tracks = action._clip.tracks, 50021 nTracks = tracks.length, 50022 bindings = action._propertyBindings, 50023 interpolants = action._interpolants, 50024 rootUuid = root.uuid, 50025 bindingsByRoot = this._bindingsByRootAndName; 50026 50027 let bindingsByName = bindingsByRoot[rootUuid]; 50028 50029 if (bindingsByName === undefined) { 50030 50031 bindingsByName = {}; 50032 bindingsByRoot[rootUuid] = bindingsByName; 50033 50034 } 50035 50036 for (let i = 0; i !== nTracks; ++i) { 50037 50038 const track = tracks[i], 50039 trackName = track.name; 50040 50041 let binding = bindingsByName[trackName]; 50042 50043 if (binding !== undefined) { 50044 50045 ++binding.referenceCount; 50046 bindings[i] = binding; 50047 50048 } else { 50049 50050 binding = bindings[i]; 50051 50052 if (binding !== undefined) { 50053 50054 // existing binding, make sure the cache knows 50055 50056 if (binding._cacheIndex === null) { 50057 50058 ++binding.referenceCount; 50059 this._addInactiveBinding(binding, rootUuid, trackName); 50060 50061 } 50062 50063 continue; 50064 50065 } 50066 50067 const path = prototypeAction && prototypeAction. 50068 _propertyBindings[i].binding.parsedPath; 50069 50070 binding = new PropertyMixer( 50071 PropertyBinding.create(root, trackName, path), 50072 track.ValueTypeName, track.getValueSize()); 50073 50074 ++binding.referenceCount; 50075 this._addInactiveBinding(binding, rootUuid, trackName); 50076 50077 bindings[i] = binding; 50078 50079 } 50080 50081 interpolants[i].resultBuffer = binding.buffer; 50082 50083 } 50084 50085 } 50086 50087 _activateAction(action) { 50088 50089 if (!this._isActiveAction(action)) { 50090 50091 if (action._cacheIndex === null) { 50092 50093 // this action has been forgotten by the cache, but the user 50094 // appears to be still using it -> rebind 50095 50096 const rootUuid = (action._localRoot || this._root).uuid, 50097 clipUuid = action._clip.uuid, 50098 actionsForClip = this._actionsByClip[clipUuid]; 50099 50100 this._bindAction(action, 50101 actionsForClip && actionsForClip.knownActions[0]); 50102 50103 this._addInactiveAction(action, clipUuid, rootUuid); 50104 50105 } 50106 50107 const bindings = action._propertyBindings;
vendor: 11,327 bytes, lines 50108-50632
50108 50109 // increment reference counts / sort out state 50110 for (let i = 0, n = bindings.length; i !== n; ++i) { 50111 50112 const binding = bindings[i]; 50113 50114 if (binding.useCount++ === 0) { 50115 50116 this._lendBinding(binding); 50117 binding.saveOriginalState(); 50118 50119 } 50120 50121 } 50122 50123 this._lendAction(action); 50124 50125 } 50126 50127 } 50128 50129 _deactivateAction(action) { 50130 50131 if (this._isActiveAction(action)) { 50132 50133 const bindings = action._propertyBindings; 50134 50135 // decrement reference counts / sort out state 50136 for (let i = 0, n = bindings.length; i !== n; ++i) { 50137 50138 const binding = bindings[i]; 50139 50140 if (--binding.useCount === 0) { 50141 50142 binding.restoreOriginalState(); 50143 this._takeBackBinding(binding); 50144 50145 } 50146 50147 } 50148 50149 this._takeBackAction(action); 50150 50151 } 50152 50153 } 50154 50155 // Memory manager 50156 50157 _initMemoryManager() { 50158 50159 this._actions = []; // 'nActiveActions' followed by inactive ones 50160 this._nActiveActions = 0; 50161 50162 this._actionsByClip = {}; 50163 // inside: 50164 // { 50165 // knownActions: Array< AnimationAction > - used as prototypes 50166 // actionByRoot: AnimationAction - lookup 50167 // } 50168 50169 50170 this._bindings = []; // 'nActiveBindings' followed by inactive ones 50171 this._nActiveBindings = 0; 50172 50173 this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer > 50174 50175 50176 this._controlInterpolants = []; // same game as above 50177 this._nActiveControlInterpolants = 0; 50178 50179 const scope = this; 50180 50181 this.stats = { 50182 50183 actions: { 50184 get total() { 50185 50186 return scope._actions.length; 50187 50188 }, 50189 get inUse() { 50190 50191 return scope._nActiveActions; 50192 50193 } 50194 }, 50195 bindings: { 50196 get total() { 50197 50198 return scope._bindings.length; 50199 50200 }, 50201 get inUse() { 50202 50203 return scope._nActiveBindings; 50204 50205 } 50206 }, 50207 controlInterpolants: { 50208 get total() { 50209 50210 return scope._controlInterpolants.length; 50211 50212 }, 50213 get inUse() { 50214 50215 return scope._nActiveControlInterpolants; 50216 50217 } 50218 } 50219 50220 }; 50221 50222 } 50223 50224 // Memory management for AnimationAction objects 50225 50226 _isActiveAction(action) { 50227 50228 const index = action._cacheIndex; 50229 return index !== null && index < this._nActiveActions; 50230 50231 } 50232 50233 _addInactiveAction(action, clipUuid, rootUuid) { 50234 50235 const actions = this._actions, 50236 actionsByClip = this._actionsByClip; 50237 50238 let actionsForClip = actionsByClip[clipUuid]; 50239 50240 if (actionsForClip === undefined) { 50241 50242 actionsForClip = { 50243 50244 knownActions: [action], 50245 actionByRoot: {} 50246 50247 }; 50248 50249 action._byClipCacheIndex = 0; 50250 50251 actionsByClip[clipUuid] = actionsForClip; 50252 50253 } else { 50254 50255 const knownActions = actionsForClip.knownActions; 50256 50257 action._byClipCacheIndex = knownActions.length; 50258 knownActions.push(action); 50259 50260 } 50261 50262 action._cacheIndex = actions.length; 50263 actions.push(action); 50264 50265 actionsForClip.actionByRoot[rootUuid] = action; 50266 50267 } 50268 50269 _removeInactiveAction(action) { 50270 50271 const actions = this._actions, 50272 lastInactiveAction = actions[actions.length - 1], 50273 cacheIndex = action._cacheIndex; 50274 50275 lastInactiveAction._cacheIndex = cacheIndex; 50276 actions[cacheIndex] = lastInactiveAction; 50277 actions.pop(); 50278 50279 action._cacheIndex = null; 50280 50281 50282 const clipUuid = action._clip.uuid, 50283 actionsByClip = this._actionsByClip, 50284 actionsForClip = actionsByClip[clipUuid], 50285 knownActionsForClip = actionsForClip.knownActions, 50286 50287 lastKnownAction = 50288 knownActionsForClip[knownActionsForClip.length - 1], 50289 50290 byClipCacheIndex = action._byClipCacheIndex; 50291 50292 lastKnownAction._byClipCacheIndex = byClipCacheIndex; 50293 knownActionsForClip[byClipCacheIndex] = lastKnownAction; 50294 knownActionsForClip.pop(); 50295 50296 action._byClipCacheIndex = null; 50297 50298 50299 const actionByRoot = actionsForClip.actionByRoot, 50300 rootUuid = (action._localRoot || this._root).uuid; 50301 50302 delete actionByRoot[rootUuid]; 50303 50304 if (knownActionsForClip.length === 0) { 50305 50306 delete actionsByClip[clipUuid]; 50307 50308 } 50309 50310 this._removeInactiveBindingsForAction(action); 50311 50312 } 50313 50314 _removeInactiveBindingsForAction(action) { 50315 50316 const bindings = action._propertyBindings; 50317 50318 for (let i = 0, n = bindings.length; i !== n; ++i) { 50319 50320 const binding = bindings[i]; 50321 50322 if (--binding.referenceCount === 0) { 50323 50324 this._removeInactiveBinding(binding); 50325 50326 } 50327 50328 } 50329 50330 } 50331 50332 _lendAction(action) { 50333 50334 // [ active actions | inactive actions ] 50335 // [ active actions >| inactive actions ] 50336 // s a 50337 // <-swap-> 50338 // a s 50339 50340 const actions = this._actions, 50341 prevIndex = action._cacheIndex, 50342 50343 lastActiveIndex = this._nActiveActions++, 50344 50345 firstInactiveAction = actions[lastActiveIndex]; 50346 50347 action._cacheIndex = lastActiveIndex; 50348 actions[lastActiveIndex] = action; 50349 50350 firstInactiveAction._cacheIndex = prevIndex; 50351 actions[prevIndex] = firstInactiveAction; 50352 50353 } 50354 50355 _takeBackAction(action) { 50356 50357 // [ active actions | inactive actions ] 50358 // [ active actions |< inactive actions ] 50359 // a s 50360 // <-swap-> 50361 // s a 50362 50363 const actions = this._actions, 50364 prevIndex = action._cacheIndex, 50365 50366 firstInactiveIndex = --this._nActiveActions, 50367 50368 lastActiveAction = actions[firstInactiveIndex]; 50369 50370 action._cacheIndex = firstInactiveIndex; 50371 actions[firstInactiveIndex] = action; 50372 50373 lastActiveAction._cacheIndex = prevIndex; 50374 actions[prevIndex] = lastActiveAction; 50375 50376 } 50377 50378 // Memory management for PropertyMixer objects 50379 50380 _addInactiveBinding(binding, rootUuid, trackName) { 50381 50382 const bindingsByRoot = this._bindingsByRootAndName, 50383 bindings = this._bindings; 50384 50385 let bindingByName = bindingsByRoot[rootUuid]; 50386 50387 if (bindingByName === undefined) { 50388 50389 bindingByName = {}; 50390 bindingsByRoot[rootUuid] = bindingByName; 50391 50392 } 50393 50394 bindingByName[trackName] = binding; 50395 50396 binding._cacheIndex = bindings.length; 50397 bindings.push(binding); 50398 50399 } 50400 50401 _removeInactiveBinding(binding) { 50402 50403 const bindings = this._bindings, 50404 propBinding = binding.binding, 50405 rootUuid = propBinding.rootNode.uuid, 50406 trackName = propBinding.path, 50407 bindingsByRoot = this._bindingsByRootAndName, 50408 bindingByName = bindingsByRoot[rootUuid], 50409 50410 lastInactiveBinding = bindings[bindings.length - 1], 50411 cacheIndex = binding._cacheIndex; 50412 50413 lastInactiveBinding._cacheIndex = cacheIndex; 50414 bindings[cacheIndex] = lastInactiveBinding; 50415 bindings.pop(); 50416 50417 delete bindingByName[trackName]; 50418 50419 if (Object.keys(bindingByName).length === 0) { 50420 50421 delete bindingsByRoot[rootUuid]; 50422 50423 } 50424 50425 } 50426 50427 _lendBinding(binding) { 50428 50429 const bindings = this._bindings, 50430 prevIndex = binding._cacheIndex, 50431 50432 lastActiveIndex = this._nActiveBindings++, 50433 50434 firstInactiveBinding = bindings[lastActiveIndex]; 50435 50436 binding._cacheIndex = lastActiveIndex; 50437 bindings[lastActiveIndex] = binding; 50438 50439 firstInactiveBinding._cacheIndex = prevIndex; 50440 bindings[prevIndex] = firstInactiveBinding; 50441 50442 } 50443 50444 _takeBackBinding(binding) { 50445 50446 const bindings = this._bindings, 50447 prevIndex = binding._cacheIndex, 50448 50449 firstInactiveIndex = --this._nActiveBindings, 50450 50451 lastActiveBinding = bindings[firstInactiveIndex]; 50452 50453 binding._cacheIndex = firstInactiveIndex; 50454 bindings[firstInactiveIndex] = binding; 50455 50456 lastActiveBinding._cacheIndex = prevIndex; 50457 bindings[prevIndex] = lastActiveBinding; 50458 50459 } 50460 50461 50462 // Memory management of Interpolants for weight and time scale 50463 50464 _lendControlInterpolant() { 50465 50466 const interpolants = this._controlInterpolants, 50467 lastActiveIndex = this._nActiveControlInterpolants++; 50468 50469 let interpolant = interpolants[lastActiveIndex]; 50470 50471 if (interpolant === undefined) { 50472 50473 interpolant = new LinearInterpolant( 50474 new Float32Array(2), new Float32Array(2), 50475 1, _controlInterpolantsResultBuffer); 50476 50477 interpolant.__cacheIndex = lastActiveIndex; 50478 interpolants[lastActiveIndex] = interpolant; 50479 50480 } 50481 50482 return interpolant; 50483 50484 } 50485 50486 _takeBackControlInterpolant(interpolant) { 50487 50488 const interpolants = this._controlInterpolants, 50489 prevIndex = interpolant.__cacheIndex, 50490 50491 firstInactiveIndex = --this._nActiveControlInterpolants, 50492 50493 lastActiveInterpolant = interpolants[firstInactiveIndex]; 50494 50495 interpolant.__cacheIndex = firstInactiveIndex; 50496 interpolants[firstInactiveIndex] = interpolant; 50497 50498 lastActiveInterpolant.__cacheIndex = prevIndex; 50499 interpolants[prevIndex] = lastActiveInterpolant; 50500 50501 } 50502 50503 // return an action for a clip optionally using a custom root target 50504 // object (this method allocates a lot of dynamic memory in case a 50505 // previously unknown clip/root combination is specified) 50506 clipAction(clip, optionalRoot, blendMode) { 50507 50508 const root = optionalRoot || this._root, 50509 rootUuid = root.uuid; 50510 50511 let clipObject = typeof clip === 'string' ? AnimationClip.findByName(root, clip) : clip; 50512 50513 const clipUuid = clipObject !== null ? clipObject.uuid : clip; 50514 50515 const actionsForClip = this._actionsByClip[clipUuid]; 50516 let prototypeAction = null; 50517 50518 if (blendMode === undefined) { 50519 50520 if (clipObject !== null) { 50521 50522 blendMode = clipObject.blendMode; 50523 50524 } else { 50525 50526 blendMode = NormalAnimationBlendMode; 50527 50528 } 50529 50530 } 50531 50532 if (actionsForClip !== undefined) { 50533 50534 const existingAction = actionsForClip.actionByRoot[rootUuid]; 50535 50536 if (existingAction !== undefined && existingAction.blendMode === blendMode) { 50537 50538 return existingAction; 50539 50540 } 50541 50542 // we know the clip, so we don't have to parse all 50543 // the bindings again but can just copy 50544 prototypeAction = actionsForClip.knownActions[0]; 50545 50546 // also, take the clip from the prototype action 50547 if (clipObject === null) 50548 clipObject = prototypeAction._clip; 50549 50550 } 50551 50552 // clip must be known when specified via string 50553 if (clipObject === null) return null; 50554 50555 // allocate all resources required to run it 50556 const newAction = new AnimationAction(this, clipObject, optionalRoot, blendMode); 50557 50558 this._bindAction(newAction, prototypeAction); 50559 50560 // and make the action known to the memory manager 50561 this._addInactiveAction(newAction, clipUuid, rootUuid); 50562 50563 return newAction; 50564 50565 } 50566 50567 // get an existing action 50568 existingAction(clip, optionalRoot) { 50569 50570 const root = optionalRoot || this._root, 50571 rootUuid = root.uuid, 50572 50573 clipObject = typeof clip === 'string' ? 50574 AnimationClip.findByName(root, clip) : clip, 50575 50576 clipUuid = clipObject ? clipObject.uuid : clip, 50577 50578 actionsForClip = this._actionsByClip[clipUuid]; 50579 50580 if (actionsForClip !== undefined) { 50581 50582 return actionsForClip.actionByRoot[rootUuid] || null; 50583 50584 } 50585 50586 return null; 50587 50588 } 50589 50590 // deactivates all previously scheduled actions 50591 stopAllAction() { 50592 50593 const actions = this._actions, 50594 nActions = this._nActiveActions; 50595 50596 for (let i = nActions - 1; i >= 0; --i) { 50597 50598 actions[i].stop(); 50599 50600 } 50601 50602 return this; 50603 50604 } 50605 50606 // advance the time and update apply the animation 50607 update(deltaTime) { 50608 50609 deltaTime *= this.timeScale; 50610 50611 const actions = this._actions, 50612 nActions = this._nActiveActions, 50613 50614 time = this.time += deltaTime, 50615 timeDirection = Math.sign(deltaTime), 50616 50617 accuIndex = this._accuIndex ^= 1; 50618 50619 // run active actions 50620 50621 for (let i = 0; i !== nActions; ++i) { 50622 50623 const action = actions[i]; 50624 50625 action._update(time, deltaTime, timeDirection, accuIndex); 50626 50627 } 50628 50629 // update scene graph 50630 50631 const bindings = this._bindings, 50632 nBindings = this._nActiveBindings;
vendor: 2,943 bytes, lines 50633-50777
50633 50634 for (let i = 0; i !== nBindings; ++i) { 50635 50636 bindings[i].apply(accuIndex); 50637 50638 } 50639 50640 return this; 50641 50642 } 50643 50644 // Allows you to seek to a specific time in an animation. 50645 setTime(timeInSeconds) { 50646 50647 this.time = 0; // Zero out time attribute for AnimationMixer object; 50648 for (let i = 0; i < this._actions.length; i++) { 50649 50650 this._actions[i].time = 0; // Zero out time attribute for all associated AnimationAction objects. 50651 50652 } 50653 50654 return this.update(timeInSeconds); // Update used to set exact time. Returns "this" AnimationMixer object. 50655 50656 } 50657 50658 // return this mixer's root target object 50659 getRoot() { 50660 50661 return this._root; 50662 50663 } 50664 50665 // free all resources specific to a particular clip 50666 uncacheClip(clip) { 50667 50668 const actions = this._actions, 50669 clipUuid = clip.uuid, 50670 actionsByClip = this._actionsByClip, 50671 actionsForClip = actionsByClip[clipUuid]; 50672 50673 if (actionsForClip !== undefined) { 50674 50675 // note: just calling _removeInactiveAction would mess up the 50676 // iteration state and also require updating the state we can 50677 // just throw away 50678 50679 const actionsToRemove = actionsForClip.knownActions; 50680 50681 for (let i = 0, n = actionsToRemove.length; i !== n; ++i) { 50682 50683 const action = actionsToRemove[i]; 50684 50685 this._deactivateAction(action); 50686 50687 const cacheIndex = action._cacheIndex, 50688 lastInactiveAction = actions[actions.length - 1]; 50689 50690 action._cacheIndex = null; 50691 action._byClipCacheIndex = null; 50692 50693 lastInactiveAction._cacheIndex = cacheIndex; 50694 actions[cacheIndex] = lastInactiveAction; 50695 actions.pop(); 50696 50697 this._removeInactiveBindingsForAction(action); 50698 50699 } 50700 50701 delete actionsByClip[clipUuid]; 50702 50703 } 50704 50705 } 50706 50707 // free all resources specific to a particular root target object 50708 uncacheRoot(root) { 50709 50710 const rootUuid = root.uuid, 50711 actionsByClip = this._actionsByClip; 50712 50713 for (const clipUuid in actionsByClip) { 50714 50715 const actionByRoot = actionsByClip[clipUuid].actionByRoot, 50716 action = actionByRoot[rootUuid]; 50717 50718 if (action !== undefined) { 50719 50720 this._deactivateAction(action); 50721 this._removeInactiveAction(action); 50722 50723 } 50724 50725 } 50726 50727 const bindingsByRoot = this._bindingsByRootAndName, 50728 bindingByName = bindingsByRoot[rootUuid]; 50729 50730 if (bindingByName !== undefined) { 50731 50732 for (const trackName in bindingByName) { 50733 50734 const binding = bindingByName[trackName]; 50735 binding.restoreOriginalState(); 50736 this._removeInactiveBinding(binding); 50737 50738 } 50739 50740 } 50741 50742 } 50743 50744 // remove a targeted clip from the cache 50745 uncacheAction(clip, optionalRoot) { 50746 50747 const action = this.existingAction(clip, optionalRoot); 50748 50749 if (action !== null) { 50750 50751 this._deactivateAction(action); 50752 this._removeInactiveAction(action); 50753 50754 } 50755 50756 } 50757 50758} 50759 50760class Uniform { 50761 50762 constructor(value) { 50763 50764 this.value = value; 50765 50766 } 50767 50768 clone() { 50769 50770 return new Uniform(this.value.clone === undefined ? this.value : this.value.clone()); 50771 50772 } 50773 50774} 50775 50776let _id = 0; 50777
vendor: 4,517 bytes, lines 50778-51059
50778class UniformsGroup extends EventDispatcher { 50779 50780 constructor() { 50781 50782 super(); 50783 50784 this.isUniformsGroup = true; 50785 50786 Object.defineProperty(this, 'id', { value: _id++ }); 50787 50788 this.name = ''; 50789 50790 this.usage = StaticDrawUsage; 50791 this.uniforms = []; 50792 50793 } 50794 50795 add(uniform) { 50796 50797 this.uniforms.push(uniform); 50798 50799 return this; 50800 50801 } 50802 50803 remove(uniform) { 50804 50805 const index = this.uniforms.indexOf(uniform); 50806 50807 if (index !== - 1) this.uniforms.splice(index, 1); 50808 50809 return this; 50810 50811 } 50812 50813 setName(name) { 50814 50815 this.name = name; 50816 50817 return this; 50818 50819 } 50820 50821 setUsage(value) { 50822 50823 this.usage = value; 50824 50825 return this; 50826 50827 } 50828 50829 dispose() { 50830 50831 this.dispatchEvent({ type: 'dispose' }); 50832 50833 return this; 50834 50835 } 50836 50837 copy(source) { 50838 50839 this.name = source.name; 50840 this.usage = source.usage; 50841 50842 const uniformsSource = source.uniforms; 50843 50844 this.uniforms.length = 0; 50845 50846 for (let i = 0, l = uniformsSource.length; i < l; i++) { 50847 50848 const uniforms = Array.isArray(uniformsSource[i]) ? uniformsSource[i] : [uniformsSource[i]]; 50849 50850 for (let j = 0; j < uniforms.length; j++) { 50851 50852 this.uniforms.push(uniforms[j].clone()); 50853 50854 } 50855 50856 } 50857 50858 return this; 50859 50860 } 50861 50862 clone() { 50863 50864 return new this.constructor().copy(this); 50865 50866 } 50867 50868} 50869 50870class InstancedInterleavedBuffer extends InterleavedBuffer { 50871 50872 constructor(array, stride, meshPerAttribute = 1) { 50873 50874 super(array, stride); 50875 50876 this.isInstancedInterleavedBuffer = true; 50877 50878 this.meshPerAttribute = meshPerAttribute; 50879 50880 } 50881 50882 copy(source) { 50883 50884 super.copy(source); 50885 50886 this.meshPerAttribute = source.meshPerAttribute; 50887 50888 return this; 50889 50890 } 50891 50892 clone(data) { 50893 50894 const ib = super.clone(data); 50895 50896 ib.meshPerAttribute = this.meshPerAttribute; 50897 50898 return ib; 50899 50900 } 50901 50902 toJSON(data) { 50903 50904 const json = super.toJSON(data); 50905 50906 json.isInstancedInterleavedBuffer = true; 50907 json.meshPerAttribute = this.meshPerAttribute; 50908 50909 return json; 50910 50911 } 50912 50913} 50914 50915class GLBufferAttribute { 50916 50917 constructor(buffer, type, itemSize, elementSize, count) { 50918 50919 this.isGLBufferAttribute = true; 50920 50921 this.name = ''; 50922 50923 this.buffer = buffer; 50924 this.type = type; 50925 this.itemSize = itemSize; 50926 this.elementSize = elementSize; 50927 this.count = count; 50928 50929 this.version = 0; 50930 50931 } 50932 50933 set needsUpdate(value) { 50934 50935 if (value === true) this.version++; 50936 50937 } 50938 50939 setBuffer(buffer) { 50940 50941 this.buffer = buffer; 50942 50943 return this; 50944 50945 } 50946 50947 setType(type, elementSize) { 50948 50949 this.type = type; 50950 this.elementSize = elementSize; 50951 50952 return this; 50953 50954 } 50955 50956 setItemSize(itemSize) { 50957 50958 this.itemSize = itemSize; 50959 50960 return this; 50961 50962 } 50963 50964 setCount(count) { 50965 50966 this.count = count; 50967 50968 return this; 50969 50970 } 50971 50972} 50973 50974class Raycaster { 50975 50976 constructor(origin, direction, near = 0, far = Infinity) { 50977 50978 this.ray = new Ray(origin, direction); 50979 // direction is assumed to be normalized (for accurate distance calculations) 50980 50981 this.near = near; 50982 this.far = far; 50983 this.camera = null; 50984 this.layers = new Layers(); 50985 50986 this.params = { 50987 Mesh: {}, 50988 Line: { threshold: 1 }, 50989 LOD: {}, 50990 Points: { threshold: 1 }, 50991 Sprite: {} 50992 }; 50993 50994 } 50995 50996 set(origin, direction) { 50997 50998 // direction is assumed to be normalized (for accurate distance calculations) 50999 51000 this.ray.set(origin, direction); 51001 51002 } 51003 51004 setFromCamera(coords, camera) { 51005 51006 if (camera.isPerspectiveCamera) { 51007 51008 this.ray.origin.setFromMatrixPosition(camera.matrixWorld); 51009 this.ray.direction.set(coords.x, coords.y, 0.5).unproject(camera).sub(this.ray.origin).normalize(); 51010 this.camera = camera; 51011 51012 } else if (camera.isOrthographicCamera) { 51013 51014 this.ray.origin.set(coords.x, coords.y, (camera.near + camera.far) / (camera.near - camera.far)).unproject(camera); // set origin in plane of camera 51015 this.ray.direction.set(0, 0, - 1).transformDirection(camera.matrixWorld); 51016 this.camera = camera; 51017 51018 } else { 51019 51020 console.error('THREE.Raycaster: Unsupported camera type: ' + camera.type); 51021 51022 } 51023 51024 } 51025 51026 intersectObject(object, recursive = true, intersects = []) { 51027 51028 intersectObject(object, this, intersects, recursive); 51029 51030 intersects.sort(ascSort); 51031 51032 return intersects; 51033 51034 } 51035 51036 intersectObjects(objects, recursive = true, intersects = []) { 51037 51038 for (let i = 0, l = objects.length; i < l; i++) { 51039 51040 intersectObject(objects[i], this, intersects, recursive); 51041 51042 } 51043 51044 intersects.sort(ascSort); 51045 51046 return intersects; 51047 51048 } 51049 51050} 51051 51052function ascSort(a, b) { 51053 51054 return a.distance - b.distance; 51055 51056} 51057 51058function intersectObject(object, raycaster, intersects, recursive) { 51059
vendor: 24,314 bytes, lines 51060-52274
51060 if (object.layers.test(raycaster.layers)) { 51061 51062 object.raycast(raycaster, intersects); 51063 51064 } 51065 51066 if (recursive === true) { 51067 51068 const children = object.children; 51069 51070 for (let i = 0, l = children.length; i < l; i++) { 51071 51072 intersectObject(children[i], raycaster, intersects, true); 51073 51074 } 51075 51076 } 51077 51078} 51079 51080/** 51081 * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system 51082 * 51083 * The polar angle (phi) is measured from the positive y-axis. The positive y-axis is up. 51084 * The azimuthal angle (theta) is measured from the positive z-axis. 51085 */ 51086 51087 51088class Spherical { 51089 51090 constructor(radius = 1, phi = 0, theta = 0) { 51091 51092 this.radius = radius; 51093 this.phi = phi; // polar angle 51094 this.theta = theta; // azimuthal angle 51095 51096 return this; 51097 51098 } 51099 51100 set(radius, phi, theta) { 51101 51102 this.radius = radius; 51103 this.phi = phi; 51104 this.theta = theta; 51105 51106 return this; 51107 51108 } 51109 51110 copy(other) { 51111 51112 this.radius = other.radius; 51113 this.phi = other.phi; 51114 this.theta = other.theta; 51115 51116 return this; 51117 51118 } 51119 51120 // restrict phi to be between EPS and PI-EPS 51121 makeSafe() { 51122 51123 const EPS = 0.000001; 51124 this.phi = Math.max(EPS, Math.min(Math.PI - EPS, this.phi)); 51125 51126 return this; 51127 51128 } 51129 51130 setFromVector3(v) { 51131 51132 return this.setFromCartesianCoords(v.x, v.y, v.z); 51133 51134 } 51135 51136 setFromCartesianCoords(x, y, z) { 51137 51138 this.radius = Math.sqrt(x * x + y * y + z * z); 51139 51140 if (this.radius === 0) { 51141 51142 this.theta = 0; 51143 this.phi = 0; 51144 51145 } else { 51146 51147 this.theta = Math.atan2(x, z); 51148 this.phi = Math.acos(clamp(y / this.radius, - 1, 1)); 51149 51150 } 51151 51152 return this; 51153 51154 } 51155 51156 clone() { 51157 51158 return new this.constructor().copy(this); 51159 51160 } 51161 51162} 51163 51164/** 51165 * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system 51166 */ 51167 51168class Cylindrical { 51169 51170 constructor(radius = 1, theta = 0, y = 0) { 51171 51172 this.radius = radius; // distance from the origin to a point in the x-z plane 51173 this.theta = theta; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis 51174 this.y = y; // height above the x-z plane 51175 51176 return this; 51177 51178 } 51179 51180 set(radius, theta, y) { 51181 51182 this.radius = radius; 51183 this.theta = theta; 51184 this.y = y; 51185 51186 return this; 51187 51188 } 51189 51190 copy(other) { 51191 51192 this.radius = other.radius; 51193 this.theta = other.theta; 51194 this.y = other.y; 51195 51196 return this; 51197 51198 } 51199 51200 setFromVector3(v) { 51201 51202 return this.setFromCartesianCoords(v.x, v.y, v.z); 51203 51204 } 51205 51206 setFromCartesianCoords(x, y, z) { 51207 51208 this.radius = Math.sqrt(x * x + z * z); 51209 this.theta = Math.atan2(x, z); 51210 this.y = y; 51211 51212 return this; 51213 51214 } 51215 51216 clone() { 51217 51218 return new this.constructor().copy(this); 51219 51220 } 51221 51222} 51223 51224const _vector$4 = /*@__PURE__*/ new Vector2(); 51225 51226class Box2 { 51227 51228 constructor(min = new Vector2(+ Infinity, + Infinity), max = new Vector2(- Infinity, - Infinity)) { 51229 51230 this.isBox2 = true; 51231 51232 this.min = min; 51233 this.max = max; 51234 51235 } 51236 51237 set(min, max) { 51238 51239 this.min.copy(min); 51240 this.max.copy(max); 51241 51242 return this; 51243 51244 } 51245 51246 setFromPoints(points) { 51247 51248 this.makeEmpty(); 51249 51250 for (let i = 0, il = points.length; i < il; i++) { 51251 51252 this.expandByPoint(points[i]); 51253 51254 } 51255 51256 return this; 51257 51258 } 51259 51260 setFromCenterAndSize(center, size) { 51261 51262 const halfSize = _vector$4.copy(size).multiplyScalar(0.5); 51263 this.min.copy(center).sub(halfSize); 51264 this.max.copy(center).add(halfSize); 51265 51266 return this; 51267 51268 } 51269 51270 clone() { 51271 51272 return new this.constructor().copy(this); 51273 51274 } 51275 51276 copy(box) { 51277 51278 this.min.copy(box.min); 51279 this.max.copy(box.max); 51280 51281 return this; 51282 51283 } 51284 51285 makeEmpty() { 51286 51287 this.min.x = this.min.y = + Infinity; 51288 this.max.x = this.max.y = - Infinity; 51289 51290 return this; 51291 51292 } 51293 51294 isEmpty() { 51295 51296 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes 51297 51298 return (this.max.x < this.min.x) || (this.max.y < this.min.y); 51299 51300 } 51301 51302 getCenter(target) { 51303 51304 return this.isEmpty() ? target.set(0, 0) : target.addVectors(this.min, this.max).multiplyScalar(0.5); 51305 51306 } 51307 51308 getSize(target) { 51309 51310 return this.isEmpty() ? target.set(0, 0) : target.subVectors(this.max, this.min); 51311 51312 } 51313 51314 expandByPoint(point) { 51315 51316 this.min.min(point); 51317 this.max.max(point); 51318 51319 return this; 51320 51321 } 51322 51323 expandByVector(vector) { 51324 51325 this.min.sub(vector); 51326 this.max.add(vector); 51327 51328 return this; 51329 51330 } 51331 51332 expandByScalar(scalar) { 51333 51334 this.min.addScalar(- scalar); 51335 this.max.addScalar(scalar); 51336 51337 return this; 51338 51339 } 51340 51341 containsPoint(point) { 51342 51343 return point.x < this.min.x || point.x > this.max.x || 51344 point.y < this.min.y || point.y > this.max.y ? false : true; 51345 51346 } 51347 51348 containsBox(box) { 51349 51350 return this.min.x <= box.min.x && box.max.x <= this.max.x && 51351 this.min.y <= box.min.y && box.max.y <= this.max.y; 51352 51353 } 51354 51355 getParameter(point, target) { 51356 51357 // This can potentially have a divide by zero if the box 51358 // has a size dimension of 0. 51359 51360 return target.set( 51361 (point.x - this.min.x) / (this.max.x - this.min.x), 51362 (point.y - this.min.y) / (this.max.y - this.min.y) 51363 ); 51364 51365 } 51366 51367 intersectsBox(box) { 51368 51369 // using 4 splitting planes to rule out intersections 51370 51371 return box.max.x < this.min.x || box.min.x > this.max.x || 51372 box.max.y < this.min.y || box.min.y > this.max.y ? false : true; 51373 51374 } 51375 51376 clampPoint(point, target) { 51377 51378 return target.copy(point).clamp(this.min, this.max); 51379 51380 } 51381 51382 distanceToPoint(point) { 51383 51384 return this.clampPoint(point, _vector$4).distanceTo(point); 51385 51386 } 51387 51388 intersect(box) { 51389 51390 this.min.max(box.min); 51391 this.max.min(box.max); 51392 51393 if (this.isEmpty()) this.makeEmpty(); 51394 51395 return this; 51396 51397 } 51398 51399 union(box) { 51400 51401 this.min.min(box.min); 51402 this.max.max(box.max); 51403 51404 return this; 51405 51406 } 51407 51408 translate(offset) { 51409 51410 this.min.add(offset); 51411 this.max.add(offset); 51412 51413 return this; 51414 51415 } 51416 51417 equals(box) { 51418 51419 return box.min.equals(this.min) && box.max.equals(this.max); 51420 51421 } 51422 51423} 51424 51425const _startP = /*@__PURE__*/ new Vector3(); 51426const _startEnd = /*@__PURE__*/ new Vector3(); 51427 51428class Line3 { 51429 51430 constructor(start = new Vector3(), end = new Vector3()) { 51431 51432 this.start = start; 51433 this.end = end; 51434 51435 } 51436 51437 set(start, end) { 51438 51439 this.start.copy(start); 51440 this.end.copy(end); 51441 51442 return this; 51443 51444 } 51445 51446 copy(line) { 51447 51448 this.start.copy(line.start); 51449 this.end.copy(line.end); 51450 51451 return this; 51452 51453 } 51454 51455 getCenter(target) { 51456 51457 return target.addVectors(this.start, this.end).multiplyScalar(0.5); 51458 51459 } 51460 51461 delta(target) { 51462 51463 return target.subVectors(this.end, this.start); 51464 51465 } 51466 51467 distanceSq() { 51468 51469 return this.start.distanceToSquared(this.end); 51470 51471 } 51472 51473 distance() { 51474 51475 return this.start.distanceTo(this.end); 51476 51477 } 51478 51479 at(t, target) { 51480 51481 return this.delta(target).multiplyScalar(t).add(this.start); 51482 51483 } 51484 51485 closestPointToPointParameter(point, clampToLine) { 51486 51487 _startP.subVectors(point, this.start); 51488 _startEnd.subVectors(this.end, this.start); 51489 51490 const startEnd2 = _startEnd.dot(_startEnd); 51491 const startEnd_startP = _startEnd.dot(_startP); 51492 51493 let t = startEnd_startP / startEnd2; 51494 51495 if (clampToLine) { 51496 51497 t = clamp(t, 0, 1); 51498 51499 } 51500 51501 return t; 51502 51503 } 51504 51505 closestPointToPoint(point, clampToLine, target) { 51506 51507 const t = this.closestPointToPointParameter(point, clampToLine); 51508 51509 return this.delta(target).multiplyScalar(t).add(this.start); 51510 51511 } 51512 51513 applyMatrix4(matrix) { 51514 51515 this.start.applyMatrix4(matrix); 51516 this.end.applyMatrix4(matrix); 51517 51518 return this; 51519 51520 } 51521 51522 equals(line) { 51523 51524 return line.start.equals(this.start) && line.end.equals(this.end); 51525 51526 } 51527 51528 clone() { 51529 51530 return new this.constructor().copy(this); 51531 51532 } 51533 51534} 51535 51536const _vector$3 = /*@__PURE__*/ new Vector3(); 51537 51538class SpotLightHelper extends Object3D { 51539 51540 constructor(light, color) { 51541 51542 super(); 51543 51544 this.light = light; 51545 51546 this.matrix = light.matrixWorld; 51547 this.matrixAutoUpdate = false; 51548 51549 this.color = color; 51550 51551 this.type = 'SpotLightHelper'; 51552 51553 const geometry = new BufferGeometry(); 51554 51555 const positions = [ 51556 0, 0, 0, 0, 0, 1, 51557 0, 0, 0, 1, 0, 1, 51558 0, 0, 0, - 1, 0, 1, 51559 0, 0, 0, 0, 1, 1, 51560 0, 0, 0, 0, - 1, 1 51561 ]; 51562 51563 for (let i = 0, j = 1, l = 32; i < l; i++, j++) { 51564 51565 const p1 = (i / l) * Math.PI * 2; 51566 const p2 = (j / l) * Math.PI * 2; 51567 51568 positions.push( 51569 Math.cos(p1), Math.sin(p1), 1, 51570 Math.cos(p2), Math.sin(p2), 1 51571 ); 51572 51573 } 51574 51575 geometry.setAttribute('position', new Float32BufferAttribute(positions, 3)); 51576 51577 const material = new LineBasicMaterial({ fog: false, toneMapped: false }); 51578 51579 this.cone = new LineSegments(geometry, material); 51580 this.add(this.cone); 51581 51582 this.update(); 51583 51584 } 51585 51586 dispose() { 51587 51588 this.cone.geometry.dispose(); 51589 this.cone.material.dispose(); 51590 51591 } 51592 51593 update() { 51594 51595 this.light.updateWorldMatrix(true, false); 51596 this.light.target.updateWorldMatrix(true, false); 51597 51598 const coneLength = this.light.distance ? this.light.distance : 1000; 51599 const coneWidth = coneLength * Math.tan(this.light.angle); 51600 51601 this.cone.scale.set(coneWidth, coneWidth, coneLength); 51602 51603 _vector$3.setFromMatrixPosition(this.light.target.matrixWorld); 51604 51605 this.cone.lookAt(_vector$3); 51606 51607 if (this.color !== undefined) { 51608 51609 this.cone.material.color.set(this.color); 51610 51611 } else { 51612 51613 this.cone.material.color.copy(this.light.color); 51614 51615 } 51616 51617 } 51618 51619} 51620 51621const _vector$2 = /*@__PURE__*/ new Vector3(); 51622const _boneMatrix = /*@__PURE__*/ new Matrix4(); 51623const _matrixWorldInv = /*@__PURE__*/ new Matrix4(); 51624 51625 51626class SkeletonHelper extends LineSegments { 51627 51628 constructor(object) { 51629 51630 const bones = getBoneList(object); 51631 51632 const geometry = new BufferGeometry(); 51633 51634 const vertices = []; 51635 const colors = []; 51636 51637 const color1 = new Color(0, 0, 1); 51638 const color2 = new Color(0, 1, 0); 51639 51640 for (let i = 0; i < bones.length; i++) { 51641 51642 const bone = bones[i]; 51643 51644 if (bone.parent && bone.parent.isBone) { 51645 51646 vertices.push(0, 0, 0); 51647 vertices.push(0, 0, 0); 51648 colors.push(color1.r, color1.g, color1.b); 51649 colors.push(color2.r, color2.g, color2.b); 51650 51651 } 51652 51653 } 51654 51655 geometry.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 51656 geometry.setAttribute('color', new Float32BufferAttribute(colors, 3)); 51657 51658 const material = new LineBasicMaterial({ vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true }); 51659 51660 super(geometry, material); 51661 51662 this.isSkeletonHelper = true; 51663 51664 this.type = 'SkeletonHelper'; 51665 51666 this.root = object; 51667 this.bones = bones; 51668 51669 this.matrix = object.matrixWorld; 51670 this.matrixAutoUpdate = false; 51671 51672 } 51673 51674 updateMatrixWorld(force) { 51675 51676 const bones = this.bones; 51677 51678 const geometry = this.geometry; 51679 const position = geometry.getAttribute('position'); 51680 51681 _matrixWorldInv.copy(this.root.matrixWorld).invert(); 51682 51683 for (let i = 0, j = 0; i < bones.length; i++) { 51684 51685 const bone = bones[i]; 51686 51687 if (bone.parent && bone.parent.isBone) { 51688 51689 _boneMatrix.multiplyMatrices(_matrixWorldInv, bone.matrixWorld); 51690 _vector$2.setFromMatrixPosition(_boneMatrix); 51691 position.setXYZ(j, _vector$2.x, _vector$2.y, _vector$2.z); 51692 51693 _boneMatrix.multiplyMatrices(_matrixWorldInv, bone.parent.matrixWorld); 51694 _vector$2.setFromMatrixPosition(_boneMatrix); 51695 position.setXYZ(j + 1, _vector$2.x, _vector$2.y, _vector$2.z); 51696 51697 j += 2; 51698 51699 } 51700 51701 } 51702 51703 geometry.getAttribute('position').needsUpdate = true; 51704 51705 super.updateMatrixWorld(force); 51706 51707 } 51708 51709 dispose() { 51710 51711 this.geometry.dispose(); 51712 this.material.dispose(); 51713 51714 } 51715 51716} 51717 51718 51719function getBoneList(object) { 51720 51721 const boneList = []; 51722 51723 if (object.isBone === true) { 51724 51725 boneList.push(object); 51726 51727 } 51728 51729 for (let i = 0; i < object.children.length; i++) { 51730 51731 boneList.push.apply(boneList, getBoneList(object.children[i])); 51732 51733 } 51734 51735 return boneList; 51736 51737} 51738 51739class PointLightHelper extends Mesh { 51740 51741 constructor(light, sphereSize, color) { 51742 51743 const geometry = new SphereGeometry(sphereSize, 4, 2); 51744 const material = new MeshBasicMaterial({ wireframe: true, fog: false, toneMapped: false }); 51745 51746 super(geometry, material); 51747 51748 this.light = light; 51749 51750 this.color = color; 51751 51752 this.type = 'PointLightHelper'; 51753 51754 this.matrix = this.light.matrixWorld; 51755 this.matrixAutoUpdate = false; 51756 51757 this.update(); 51758 51759 51760 /* 51761 // TODO: delete this comment? 51762 const distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); 51763 const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); 51764 51765 this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); 51766 this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); 51767 51768 const d = light.distance; 51769 51770 if ( d === 0.0 ) { 51771 51772 this.lightDistance.visible = false; 51773 51774 } else { 51775 51776 this.lightDistance.scale.set( d, d, d ); 51777 51778 } 51779 51780 this.add( this.lightDistance ); 51781 */ 51782 51783 } 51784 51785 dispose() { 51786 51787 this.geometry.dispose(); 51788 this.material.dispose(); 51789 51790 } 51791 51792 update() { 51793 51794 this.light.updateWorldMatrix(true, false); 51795 51796 if (this.color !== undefined) { 51797 51798 this.material.color.set(this.color); 51799 51800 } else { 51801 51802 this.material.color.copy(this.light.color); 51803 51804 } 51805 51806 /* 51807 const d = this.light.distance; 51808 51809 if ( d === 0.0 ) { 51810 51811 this.lightDistance.visible = false; 51812 51813 } else { 51814 51815 this.lightDistance.visible = true; 51816 this.lightDistance.scale.set( d, d, d ); 51817 51818 } 51819 */ 51820 51821 } 51822 51823} 51824 51825const _vector$1 = /*@__PURE__*/ new Vector3(); 51826const _color1 = /*@__PURE__*/ new Color(); 51827const _color2 = /*@__PURE__*/ new Color(); 51828 51829class HemisphereLightHelper extends Object3D { 51830 51831 constructor(light, size, color) { 51832 51833 super(); 51834 51835 this.light = light; 51836 51837 this.matrix = light.matrixWorld; 51838 this.matrixAutoUpdate = false; 51839 51840 this.color = color; 51841 51842 this.type = 'HemisphereLightHelper'; 51843 51844 const geometry = new OctahedronGeometry(size); 51845 geometry.rotateY(Math.PI * 0.5); 51846 51847 this.material = new MeshBasicMaterial({ wireframe: true, fog: false, toneMapped: false }); 51848 if (this.color === undefined) this.material.vertexColors = true; 51849 51850 const position = geometry.getAttribute('position'); 51851 const colors = new Float32Array(position.count * 3); 51852 51853 geometry.setAttribute('color', new BufferAttribute(colors, 3)); 51854 51855 this.add(new Mesh(geometry, this.material)); 51856 51857 this.update(); 51858 51859 } 51860 51861 dispose() { 51862 51863 this.children[0].geometry.dispose(); 51864 this.children[0].material.dispose(); 51865 51866 } 51867 51868 update() { 51869 51870 const mesh = this.children[0]; 51871 51872 if (this.color !== undefined) { 51873 51874 this.material.color.set(this.color); 51875 51876 } else { 51877 51878 const colors = mesh.geometry.getAttribute('color'); 51879 51880 _color1.copy(this.light.color); 51881 _color2.copy(this.light.groundColor); 51882 51883 for (let i = 0, l = colors.count; i < l; i++) { 51884 51885 const color = (i < (l / 2)) ? _color1 : _color2; 51886 51887 colors.setXYZ(i, color.r, color.g, color.b); 51888 51889 } 51890 51891 colors.needsUpdate = true; 51892 51893 } 51894 51895 this.light.updateWorldMatrix(true, false); 51896 51897 mesh.lookAt(_vector$1.setFromMatrixPosition(this.light.matrixWorld).negate()); 51898 51899 } 51900 51901} 51902 51903class GridHelper extends LineSegments { 51904 51905 constructor(size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888) { 51906 51907 color1 = new Color(color1); 51908 color2 = new Color(color2); 51909 51910 const center = divisions / 2; 51911 const step = size / divisions; 51912 const halfSize = size / 2; 51913 51914 const vertices = [], colors = []; 51915 51916 for (let i = 0, j = 0, k = - halfSize; i <= divisions; i++, k += step) { 51917 51918 vertices.push(- halfSize, 0, k, halfSize, 0, k); 51919 vertices.push(k, 0, - halfSize, k, 0, halfSize); 51920 51921 const color = i === center ? color1 : color2; 51922 51923 color.toArray(colors, j); j += 3; 51924 color.toArray(colors, j); j += 3; 51925 color.toArray(colors, j); j += 3; 51926 color.toArray(colors, j); j += 3; 51927 51928 } 51929 51930 const geometry = new BufferGeometry(); 51931 geometry.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 51932 geometry.setAttribute('color', new Float32BufferAttribute(colors, 3)); 51933 51934 const material = new LineBasicMaterial({ vertexColors: true, toneMapped: false }); 51935 51936 super(geometry, material); 51937 51938 this.type = 'GridHelper'; 51939 51940 } 51941 51942 dispose() { 51943 51944 this.geometry.dispose(); 51945 this.material.dispose(); 51946 51947 } 51948 51949} 51950 51951class PolarGridHelper extends LineSegments { 51952 51953 constructor(radius = 10, sectors = 16, rings = 8, divisions = 64, color1 = 0x444444, color2 = 0x888888) { 51954 51955 color1 = new Color(color1); 51956 color2 = new Color(color2); 51957 51958 const vertices = []; 51959 const colors = []; 51960 51961 // create the sectors 51962 51963 if (sectors > 1) { 51964 51965 for (let i = 0; i < sectors; i++) { 51966 51967 const v = (i / sectors) * (Math.PI * 2); 51968 51969 const x = Math.sin(v) * radius; 51970 const z = Math.cos(v) * radius; 51971 51972 vertices.push(0, 0, 0); 51973 vertices.push(x, 0, z); 51974 51975 const color = (i & 1) ? color1 : color2; 51976 51977 colors.push(color.r, color.g, color.b); 51978 colors.push(color.r, color.g, color.b); 51979 51980 } 51981 51982 } 51983 51984 // create the rings 51985 51986 for (let i = 0; i < rings; i++) { 51987 51988 const color = (i & 1) ? color1 : color2; 51989 51990 const r = radius - (radius / rings * i); 51991 51992 for (let j = 0; j < divisions; j++) { 51993 51994 // first vertex 51995 51996 let v = (j / divisions) * (Math.PI * 2); 51997 51998 let x = Math.sin(v) * r; 51999 let z = Math.cos(v) * r; 52000 52001 vertices.push(x, 0, z); 52002 colors.push(color.r, color.g, color.b); 52003 52004 // second vertex 52005 52006 v = ((j + 1) / divisions) * (Math.PI * 2); 52007 52008 x = Math.sin(v) * r; 52009 z = Math.cos(v) * r; 52010 52011 vertices.push(x, 0, z); 52012 colors.push(color.r, color.g, color.b); 52013 52014 } 52015 52016 } 52017 52018 const geometry = new BufferGeometry(); 52019 geometry.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 52020 geometry.setAttribute('color', new Float32BufferAttribute(colors, 3)); 52021 52022 const material = new LineBasicMaterial({ vertexColors: true, toneMapped: false }); 52023 52024 super(geometry, material); 52025 52026 this.type = 'PolarGridHelper'; 52027 52028 } 52029 52030 dispose() { 52031 52032 this.geometry.dispose(); 52033 this.material.dispose(); 52034 52035 } 52036 52037} 52038 52039const _v1 = /*@__PURE__*/ new Vector3(); 52040const _v2 = /*@__PURE__*/ new Vector3(); 52041const _v3 = /*@__PURE__*/ new Vector3(); 52042 52043class DirectionalLightHelper extends Object3D { 52044 52045 constructor(light, size, color) { 52046 52047 super(); 52048 52049 this.light = light; 52050 52051 this.matrix = light.matrixWorld; 52052 this.matrixAutoUpdate = false; 52053 52054 this.color = color; 52055 52056 this.type = 'DirectionalLightHelper'; 52057 52058 if (size === undefined) size = 1; 52059 52060 let geometry = new BufferGeometry(); 52061 geometry.setAttribute('position', new Float32BufferAttribute([ 52062 - size, size, 0, 52063 size, size, 0, 52064 size, - size, 0, 52065 - size, - size, 0, 52066 - size, size, 0 52067 ], 3)); 52068 52069 const material = new LineBasicMaterial({ fog: false, toneMapped: false }); 52070 52071 this.lightPlane = new Line(geometry, material); 52072 this.add(this.lightPlane); 52073 52074 geometry = new BufferGeometry(); 52075 geometry.setAttribute('position', new Float32BufferAttribute([0, 0, 0, 0, 0, 1], 3)); 52076 52077 this.targetLine = new Line(geometry, material); 52078 this.add(this.targetLine); 52079 52080 this.update(); 52081 52082 } 52083 52084 dispose() { 52085 52086 this.lightPlane.geometry.dispose(); 52087 this.lightPlane.material.dispose(); 52088 this.targetLine.geometry.dispose(); 52089 this.targetLine.material.dispose(); 52090 52091 } 52092 52093 update() { 52094 52095 this.light.updateWorldMatrix(true, false); 52096 this.light.target.updateWorldMatrix(true, false); 52097 52098 _v1.setFromMatrixPosition(this.light.matrixWorld); 52099 _v2.setFromMatrixPosition(this.light.target.matrixWorld); 52100 _v3.subVectors(_v2, _v1); 52101 52102 this.lightPlane.lookAt(_v2); 52103 52104 if (this.color !== undefined) { 52105 52106 this.lightPlane.material.color.set(this.color); 52107 this.targetLine.material.color.set(this.color); 52108 52109 } else { 52110 52111 this.lightPlane.material.color.copy(this.light.color); 52112 this.targetLine.material.color.copy(this.light.color); 52113 52114 } 52115 52116 this.targetLine.lookAt(_v2); 52117 this.targetLine.scale.z = _v3.length(); 52118 52119 } 52120 52121} 52122 52123const _vector = /*@__PURE__*/ new Vector3(); 52124const _camera = /*@__PURE__*/ new Camera(); 52125 52126/** 52127 * - shows frustum, line of sight and up of the camera 52128 * - suitable for fast updates 52129 * - based on frustum visualization in lightgl.js shadowmap example 52130 * https://github.com/evanw/lightgl.js/blob/master/tests/shadowmap.html 52131 */ 52132 52133class CameraHelper extends LineSegments { 52134 52135 constructor(camera) { 52136 52137 const geometry = new BufferGeometry(); 52138 const material = new LineBasicMaterial({ color: 0xffffff, vertexColors: true, toneMapped: false }); 52139 52140 const vertices = []; 52141 const colors = []; 52142 52143 const pointMap = {}; 52144 52145 // near 52146 52147 addLine('n1', 'n2'); 52148 addLine('n2', 'n4'); 52149 addLine('n4', 'n3'); 52150 addLine('n3', 'n1'); 52151 52152 // far 52153 52154 addLine('f1', 'f2'); 52155 addLine('f2', 'f4'); 52156 addLine('f4', 'f3'); 52157 addLine('f3', 'f1'); 52158 52159 // sides 52160 52161 addLine('n1', 'f1'); 52162 addLine('n2', 'f2'); 52163 addLine('n3', 'f3'); 52164 addLine('n4', 'f4'); 52165 52166 // cone 52167 52168 addLine('p', 'n1'); 52169 addLine('p', 'n2'); 52170 addLine('p', 'n3'); 52171 addLine('p', 'n4'); 52172 52173 // up 52174 52175 addLine('u1', 'u2'); 52176 addLine('u2', 'u3'); 52177 addLine('u3', 'u1'); 52178 52179 // target 52180 52181 addLine('c', 't'); 52182 addLine('p', 'c'); 52183 52184 // cross 52185 52186 addLine('cn1', 'cn2'); 52187 addLine('cn3', 'cn4'); 52188 52189 addLine('cf1', 'cf2'); 52190 addLine('cf3', 'cf4'); 52191 52192 function addLine(a, b) { 52193 52194 addPoint(a); 52195 addPoint(b); 52196 52197 } 52198 52199 function addPoint(id) { 52200 52201 vertices.push(0, 0, 0); 52202 colors.push(0, 0, 0); 52203 52204 if (pointMap[id] === undefined) { 52205 52206 pointMap[id] = []; 52207 52208 } 52209 52210 pointMap[id].push((vertices.length / 3) - 1); 52211 52212 } 52213 52214 geometry.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 52215 geometry.setAttribute('color', new Float32BufferAttribute(colors, 3)); 52216 52217 super(geometry, material); 52218 52219 this.type = 'CameraHelper'; 52220 52221 this.camera = camera; 52222 if (this.camera.updateProjectionMatrix) this.camera.updateProjectionMatrix(); 52223 52224 this.matrix = camera.matrixWorld; 52225 this.matrixAutoUpdate = false; 52226 52227 this.pointMap = pointMap; 52228 52229 this.update(); 52230 52231 // colors 52232 52233 const colorFrustum = new Color(0xffaa00); 52234 const colorCone = new Color(0xff0000); 52235 const colorUp = new Color(0x00aaff); 52236 const colorTarget = new Color(0xffffff); 52237 const colorCross = new Color(0x333333); 52238 52239 this.setColors(colorFrustum, colorCone, colorUp, colorTarget, colorCross); 52240 52241 } 52242 52243 setColors(frustum, cone, up, target, cross) { 52244 52245 const geometry = this.geometry; 52246 52247 const colorAttribute = geometry.getAttribute('color'); 52248 52249 // near 52250 52251 colorAttribute.setXYZ(0, frustum.r, frustum.g, frustum.b); colorAttribute.setXYZ(1, frustum.r, frustum.g, frustum.b); // n1, n2 52252 colorAttribute.setXYZ(2, frustum.r, frustum.g, frustum.b); colorAttribute.setXYZ(3, frustum.r, frustum.g, frustum.b); // n2, n4 52253 colorAttribute.setXYZ(4, frustum.r, frustum.g, frustum.b); colorAttribute.setXYZ(5, frustum.r, frustum.g, frustum.b); // n4, n3 52254 colorAttribute.setXYZ(6, frustum.r, frustum.g, frustum.b); colorAttribute.setXYZ(7, frustum.r, frustum.g, frustum.b); // n3, n1 52255 52256 // far 52257 52258 colorAttribute.setXYZ(8, frustum.r, frustum.g, frustum.b); colorAttribute.setXYZ(9, frustum.r, frustum.g, frustum.b); // f1, f2 52259 colorAttribute.setXYZ(10, frustum.r, frustum.g, frustum.b); colorAttribute.setXYZ(11, frustum.r, frustum.g, frustum.b); // f2, f4 52260 colorAttribute.setXYZ(12, frustum.r, frustum.g, frustum.b); colorAttribute.setXYZ(13, frustum.r, frustum.g, frustum.b); // f4, f3 52261 colorAttribute.setXYZ(14, frustum.r, frustum.g, frustum.b); colorAttribute.setXYZ(15, frustum.r, frustum.g, frustum.b); // f3, f1 52262 52263 // sides 52264 52265 colorAttribute.setXYZ(16, frustum.r, frustum.g, frustum.b); colorAttribute.setXYZ(17, frustum.r, frustum.g, frustum.b); // n1, f1 52266 colorAttribute.setXYZ(18, frustum.r, frustum.g, frustum.b); colorAttribute.setXYZ(19, frustum.r, frustum.g, frustum.b); // n2, f2 52267 colorAttribute.setXYZ(20, frustum.r, frustum.g, frustum.b); colorAttribute.setXYZ(21, frustum.r, frustum.g, frustum.b); // n3, f3 52268 colorAttribute.setXYZ(22, frustum.r, frustum.g, frustum.b); colorAttribute.setXYZ(23, frustum.r, frustum.g, frustum.b); // n4, f4 52269 52270 // cone 52271 52272 colorAttribute.setXYZ(24, cone.r, cone.g, cone.b); colorAttribute.setXYZ(25, cone.r, cone.g, cone.b); // p, n1 52273 colorAttribute.setXYZ(26, cone.r, cone.g, cone.b); colorAttribute.setXYZ(27, cone.r, cone.g, cone.b); // p, n2 52274 colorAttribute.setXYZ(28, cone.r, cone.g, cone.b); colorAttribute.setXYZ(29, cone.r, cone.g, cone.b); // p, n3
52275 colorAttribute.setXYZ(30, cone.r, cone.g, cone.b); colorAttribute.setXYZ(31, cone.r, cone.g, cone.b); // p, n4 52276 52277 // up 52278 52279 colorAttribute.setXYZ(32, up.r, up.g, up.b); colorAttribute.setXYZ(33, up.r, up.g, up.b); // u1, u2 52280 colorAttribute.setXYZ(34, up.r, up.g, up.b); colorAttribute.setXYZ(35, up.r, up.g, up.b); // u2, u3 52281 colorAttribute.setXYZ(36, up.r, up.g, up.b); colorAttribute.setXYZ(37, up.r, up.g, up.b); // u3, u1 52282 52283 // target 52284 52285 colorAttribute.setXYZ(38, target.r, target.g, target.b); colorAttribute.setXYZ(39, target.r, target.g, target.b); // c, t 52286 colorAttribute.setXYZ(40, cross.r, cross.g, cross.b); colorAttribute.setXYZ(41, cross.r, cross.g, cross.b); // p, c 52287 52288 // cross 52289 52290 colorAttribute.setXYZ(42, cross.r, cross.g, cross.b); colorAttribute.setXYZ(43, cross.r, cross.g, cross.b); // cn1, cn2 52291 colorAttribute.setXYZ(44, cross.r, cross.g, cross.b); colorAttribute.setXYZ(45, cross.r, cross.g, cross.b); // cn3, cn4 52292 52293 colorAttribute.setXYZ(46, cross.r, cross.g, cross.b); colorAttribute.setXYZ(47, cross.r, cross.g, cross.b); // cf1, cf2 52294 colorAttribute.setXYZ(48, cross.r, cross.g, cross.b); colorAttribute.setXYZ(49, cross.r, cross.g, cross.b); // cf3, cf4 52295 52296 colorAttribute.needsUpdate = true; 52297 52298 } 52299 52300 update() { 52301 52302 const geometry = this.geometry; 52303 const pointMap = this.pointMap; 52304 52305 const w = 1, h = 1; 52306 52307 // we need just camera projection matrix inverse 52308 // world matrix must be identity 52309 52310 _camera.projectionMatrixInverse.copy(this.camera.projectionMatrixInverse); 52311 52312 // center / target 52313 52314 setPoint('c', pointMap, geometry, _camera, 0, 0, - 1); 52315 setPoint('t', pointMap, geometry, _camera, 0, 0, 1); 52316 52317 // near 52318 52319 setPoint('n1', pointMap, geometry, _camera, - w, - h, - 1); 52320 setPoint('n2', pointMap, geometry, _camera, w, - h, - 1); 52321 setPoint('n3', pointMap, geometry, _camera, - w, h, - 1); 52322 setPoint('n4', pointMap, geometry, _camera, w, h, - 1); 52323 52324 // far 52325 52326 setPoint('f1', pointMap, geometry, _camera, - w, - h, 1); 52327 setPoint('f2', pointMap, geometry, _camera, w, - h, 1); 52328 setPoint('f3', pointMap, geometry, _camera, - w, h, 1); 52329 setPoint('f4', pointMap, geometry, _camera, w, h, 1); 52330 52331 // up 52332 52333 setPoint('u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1); 52334 setPoint('u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1); 52335 setPoint('u3', pointMap, geometry, _camera, 0, h * 2, - 1); 52336 52337 // cross 52338 52339 setPoint('cf1', pointMap, geometry, _camera, - w, 0, 1); 52340 setPoint('cf2', pointMap, geometry, _camera, w, 0, 1); 52341 setPoint('cf3', pointMap, geometry, _camera, 0, - h, 1); 52342 setPoint('cf4', pointMap, geometry, _camera, 0, h, 1); 52343 52344 setPoint('cn1', pointMap, geometry, _camera, - w, 0, - 1); 52345 setPoint('cn2', pointMap, geometry, _camera, w, 0, - 1); 52346 setPoint('cn3', pointMap, geometry, _camera, 0, - h, - 1); 52347 setPoint('cn4', pointMap, geometry, _camera, 0, h, - 1); 52348 52349 geometry.getAttribute('position').needsUpdate = true; 52350 52351 } 52352 52353 dispose() { 52354 52355 this.geometry.dispose(); 52356 this.material.dispose(); 52357 52358 } 52359 52360} 52361 52362 52363function setPoint(point, pointMap, geometry, camera, x, y, z) { 52364 52365 _vector.set(x, y, z).unproject(camera); 52366 52367 const points = pointMap[point]; 52368 52369 if (points !== undefined) { 52370 52371 const position = geometry.getAttribute('position'); 52372 52373 for (let i = 0, l = points.length; i < l; i++) { 52374 52375 position.setXYZ(points[i], _vector.x, _vector.y, _vector.z); 52376 52377 } 52378 52379 } 52380 52381} 52382 52383const _box = /*@__PURE__*/ new Box3(); 52384 52385class BoxHelper extends LineSegments { 52386 52387 constructor(object, color = 0xffff00) { 52388 52389 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]); 52390 const positions = new Float32Array(8 * 3); 52391 52392 const geometry = new BufferGeometry(); 52393 geometry.setIndex(new BufferAttribute(indices, 1)); 52394 geometry.setAttribute('position', new BufferAttribute(positions, 3)); 52395 52396 super(geometry, new LineBasicMaterial({ color: color, toneMapped: false })); 52397 52398 this.object = object; 52399 this.type = 'BoxHelper'; 52400 52401 this.matrixAutoUpdate = false; 52402 52403 this.update(); 52404 52405 } 52406 52407 update(object) { 52408 52409 if (object !== undefined) { 52410
vendor: 5,317 bytes, lines 52411-52648
52411 console.warn('THREE.BoxHelper: .update() has no longer arguments.'); 52412 52413 } 52414 52415 if (this.object !== undefined) { 52416 52417 _box.setFromObject(this.object); 52418 52419 } 52420 52421 if (_box.isEmpty()) return; 52422 52423 const min = _box.min; 52424 const max = _box.max; 52425 52426 /* 52427 5____4 52428 1/___0/| 52429 | 6__|_7 52430 2/___3/ 52431 52432 0: max.x, max.y, max.z 52433 1: min.x, max.y, max.z 52434 2: min.x, min.y, max.z 52435 3: max.x, min.y, max.z 52436 4: max.x, max.y, min.z 52437 5: min.x, max.y, min.z 52438 6: min.x, min.y, min.z 52439 7: max.x, min.y, min.z 52440 */ 52441 52442 const position = this.geometry.attributes.position; 52443 const array = position.array; 52444 52445 array[0] = max.x; array[1] = max.y; array[2] = max.z; 52446 array[3] = min.x; array[4] = max.y; array[5] = max.z; 52447 array[6] = min.x; array[7] = min.y; array[8] = max.z; 52448 array[9] = max.x; array[10] = min.y; array[11] = max.z; 52449 array[12] = max.x; array[13] = max.y; array[14] = min.z; 52450 array[15] = min.x; array[16] = max.y; array[17] = min.z; 52451 array[18] = min.x; array[19] = min.y; array[20] = min.z; 52452 array[21] = max.x; array[22] = min.y; array[23] = min.z; 52453 52454 position.needsUpdate = true; 52455 52456 this.geometry.computeBoundingSphere(); 52457 52458 } 52459 52460 setFromObject(object) { 52461 52462 this.object = object; 52463 this.update(); 52464 52465 return this; 52466 52467 } 52468 52469 copy(source, recursive) { 52470 52471 super.copy(source, recursive); 52472 52473 this.object = source.object; 52474 52475 return this; 52476 52477 } 52478 52479 dispose() { 52480 52481 this.geometry.dispose(); 52482 this.material.dispose(); 52483 52484 } 52485 52486} 52487 52488class Box3Helper extends LineSegments { 52489 52490 constructor(box, color = 0xffff00) { 52491 52492 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]); 52493 52494 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]; 52495 52496 const geometry = new BufferGeometry(); 52497 52498 geometry.setIndex(new BufferAttribute(indices, 1)); 52499 52500 geometry.setAttribute('position', new Float32BufferAttribute(positions, 3)); 52501 52502 super(geometry, new LineBasicMaterial({ color: color, toneMapped: false })); 52503 52504 this.box = box; 52505 52506 this.type = 'Box3Helper'; 52507 52508 this.geometry.computeBoundingSphere(); 52509 52510 } 52511 52512 updateMatrixWorld(force) { 52513 52514 const box = this.box; 52515 52516 if (box.isEmpty()) return; 52517 52518 box.getCenter(this.position); 52519 52520 box.getSize(this.scale); 52521 52522 this.scale.multiplyScalar(0.5); 52523 52524 super.updateMatrixWorld(force); 52525 52526 } 52527 52528 dispose() { 52529 52530 this.geometry.dispose(); 52531 this.material.dispose(); 52532 52533 } 52534 52535} 52536 52537class PlaneHelper extends Line { 52538 52539 constructor(plane, size = 1, hex = 0xffff00) { 52540 52541 const color = hex; 52542 52543 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]; 52544 52545 const geometry = new BufferGeometry(); 52546 geometry.setAttribute('position', new Float32BufferAttribute(positions, 3)); 52547 geometry.computeBoundingSphere(); 52548 52549 super(geometry, new LineBasicMaterial({ color: color, toneMapped: false })); 52550 52551 this.type = 'PlaneHelper'; 52552 52553 this.plane = plane; 52554 52555 this.size = size; 52556 52557 const positions2 = [1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, - 1, 0]; 52558 52559 const geometry2 = new BufferGeometry(); 52560 geometry2.setAttribute('position', new Float32BufferAttribute(positions2, 3)); 52561 geometry2.computeBoundingSphere(); 52562 52563 this.add(new Mesh(geometry2, new MeshBasicMaterial({ color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false }))); 52564 52565 } 52566 52567 updateMatrixWorld(force) { 52568 52569 this.position.set(0, 0, 0); 52570 52571 this.scale.set(0.5 * this.size, 0.5 * this.size, 1); 52572 52573 this.lookAt(this.plane.normal); 52574 52575 this.translateZ(- this.plane.constant); 52576 52577 super.updateMatrixWorld(force); 52578 52579 } 52580 52581 dispose() { 52582 52583 this.geometry.dispose(); 52584 this.material.dispose(); 52585 this.children[0].geometry.dispose(); 52586 this.children[0].material.dispose(); 52587 52588 } 52589 52590} 52591 52592const _axis = /*@__PURE__*/ new Vector3(); 52593let _lineGeometry, _coneGeometry; 52594 52595class ArrowHelper extends Object3D { 52596 52597 // dir is assumed to be normalized 52598 52599 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) { 52600 52601 super(); 52602 52603 this.type = 'ArrowHelper'; 52604 52605 if (_lineGeometry === undefined) { 52606 52607 _lineGeometry = new BufferGeometry(); 52608 _lineGeometry.setAttribute('position', new Float32BufferAttribute([0, 0, 0, 0, 1, 0], 3)); 52609 52610 _coneGeometry = new CylinderGeometry(0, 0.5, 1, 5, 1); 52611 _coneGeometry.translate(0, - 0.5, 0); 52612 52613 } 52614 52615 this.position.copy(origin); 52616 52617 this.line = new Line(_lineGeometry, new LineBasicMaterial({ color: color, toneMapped: false })); 52618 this.line.matrixAutoUpdate = false; 52619 this.add(this.line); 52620 52621 this.cone = new Mesh(_coneGeometry, new MeshBasicMaterial({ color: color, toneMapped: false })); 52622 this.cone.matrixAutoUpdate = false; 52623 this.add(this.cone); 52624 52625 this.setDirection(dir); 52626 this.setLength(length, headLength, headWidth); 52627 52628 } 52629 52630 setDirection(dir) { 52631 52632 // dir is assumed to be normalized 52633 52634 if (dir.y > 0.99999) { 52635 52636 this.quaternion.set(0, 0, 0, 1); 52637 52638 } else if (dir.y < - 0.99999) { 52639 52640 this.quaternion.set(1, 0, 0, 0); 52641 52642 } else { 52643 52644 _axis.set(dir.z, 0, - dir.x).normalize(); 52645 52646 const radians = Math.acos(dir.y); 52647 52648 this.quaternion.setFromAxisAngle(_axis, radians);
vendor: 12,207 bytes, lines 52649-53062
52649 52650 } 52651 52652 } 52653 52654 setLength(length, headLength = length * 0.2, headWidth = headLength * 0.2) { 52655 52656 this.line.scale.set(1, Math.max(0.0001, length - headLength), 1); // see #17458 52657 this.line.updateMatrix(); 52658 52659 this.cone.scale.set(headWidth, headLength, headWidth); 52660 this.cone.position.y = length; 52661 this.cone.updateMatrix(); 52662 52663 } 52664 52665 setColor(color) { 52666 52667 this.line.material.color.set(color); 52668 this.cone.material.color.set(color); 52669 52670 } 52671 52672 copy(source) { 52673 52674 super.copy(source, false); 52675 52676 this.line.copy(source.line); 52677 this.cone.copy(source.cone); 52678 52679 return this; 52680 52681 } 52682 52683 dispose() { 52684 52685 this.line.geometry.dispose(); 52686 this.line.material.dispose(); 52687 this.cone.geometry.dispose(); 52688 this.cone.material.dispose(); 52689 52690 } 52691 52692} 52693 52694class AxesHelper extends LineSegments { 52695 52696 constructor(size = 1) { 52697 52698 const vertices = [ 52699 0, 0, 0, size, 0, 0, 52700 0, 0, 0, 0, size, 0, 52701 0, 0, 0, 0, 0, size 52702 ]; 52703 52704 const colors = [ 52705 1, 0, 0, 1, 0.6, 0, 52706 0, 1, 0, 0.6, 1, 0, 52707 0, 0, 1, 0, 0.6, 1 52708 ]; 52709 52710 const geometry = new BufferGeometry(); 52711 geometry.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 52712 geometry.setAttribute('color', new Float32BufferAttribute(colors, 3)); 52713 52714 const material = new LineBasicMaterial({ vertexColors: true, toneMapped: false }); 52715 52716 super(geometry, material); 52717 52718 this.type = 'AxesHelper'; 52719 52720 } 52721 52722 setColors(xAxisColor, yAxisColor, zAxisColor) { 52723 52724 const color = new Color(); 52725 const array = this.geometry.attributes.color.array; 52726 52727 color.set(xAxisColor); 52728 color.toArray(array, 0); 52729 color.toArray(array, 3); 52730 52731 color.set(yAxisColor); 52732 color.toArray(array, 6); 52733 color.toArray(array, 9); 52734 52735 color.set(zAxisColor); 52736 color.toArray(array, 12); 52737 color.toArray(array, 15); 52738 52739 this.geometry.attributes.color.needsUpdate = true; 52740 52741 return this; 52742 52743 } 52744 52745 dispose() { 52746 52747 this.geometry.dispose(); 52748 this.material.dispose(); 52749 52750 } 52751 52752} 52753 52754class ShapePath { 52755 52756 constructor() { 52757 52758 this.type = 'ShapePath'; 52759 52760 this.color = new Color(); 52761 52762 this.subPaths = []; 52763 this.currentPath = null; 52764 52765 } 52766 52767 moveTo(x, y) { 52768 52769 this.currentPath = new Path(); 52770 this.subPaths.push(this.currentPath); 52771 this.currentPath.moveTo(x, y); 52772 52773 return this; 52774 52775 } 52776 52777 lineTo(x, y) { 52778 52779 this.currentPath.lineTo(x, y); 52780 52781 return this; 52782 52783 } 52784 52785 quadraticCurveTo(aCPx, aCPy, aX, aY) { 52786 52787 this.currentPath.quadraticCurveTo(aCPx, aCPy, aX, aY); 52788 52789 return this; 52790 52791 } 52792 52793 bezierCurveTo(aCP1x, aCP1y, aCP2x, aCP2y, aX, aY) { 52794 52795 this.currentPath.bezierCurveTo(aCP1x, aCP1y, aCP2x, aCP2y, aX, aY); 52796 52797 return this; 52798 52799 } 52800 52801 splineThru(pts) { 52802 52803 this.currentPath.splineThru(pts); 52804 52805 return this; 52806 52807 } 52808 52809 toShapes(isCCW) { 52810 52811 function toShapesNoHoles(inSubpaths) { 52812 52813 const shapes = []; 52814 52815 for (let i = 0, l = inSubpaths.length; i < l; i++) { 52816 52817 const tmpPath = inSubpaths[i]; 52818 52819 const tmpShape = new Shape(); 52820 tmpShape.curves = tmpPath.curves; 52821 52822 shapes.push(tmpShape); 52823 52824 } 52825 52826 return shapes; 52827 52828 } 52829 52830 function isPointInsidePolygon(inPt, inPolygon) { 52831 52832 const polyLen = inPolygon.length; 52833 52834 // inPt on polygon contour => immediate success or 52835 // toggling of inside/outside at every single! intersection point of an edge 52836 // with the horizontal line through inPt, left of inPt 52837 // not counting lowerY endpoints of edges and whole edges on that line 52838 let inside = false; 52839 for (let p = polyLen - 1, q = 0; q < polyLen; p = q++) { 52840 52841 let edgeLowPt = inPolygon[p]; 52842 let edgeHighPt = inPolygon[q]; 52843 52844 let edgeDx = edgeHighPt.x - edgeLowPt.x; 52845 let edgeDy = edgeHighPt.y - edgeLowPt.y; 52846 52847 if (Math.abs(edgeDy) > Number.EPSILON) { 52848 52849 // not parallel 52850 if (edgeDy < 0) { 52851 52852 edgeLowPt = inPolygon[q]; edgeDx = - edgeDx; 52853 edgeHighPt = inPolygon[p]; edgeDy = - edgeDy; 52854 52855 } 52856 52857 if ((inPt.y < edgeLowPt.y) || (inPt.y > edgeHighPt.y)) continue; 52858 52859 if (inPt.y === edgeLowPt.y) { 52860 52861 if (inPt.x === edgeLowPt.x) return true; // inPt is on contour ? 52862 // continue; // no intersection or edgeLowPt => doesn't count !!! 52863 52864 } else { 52865 52866 const perpEdge = edgeDy * (inPt.x - edgeLowPt.x) - edgeDx * (inPt.y - edgeLowPt.y); 52867 if (perpEdge === 0) return true; // inPt is on contour ? 52868 if (perpEdge < 0) continue; 52869 inside = !inside; // true intersection left of inPt 52870 52871 } 52872 52873 } else { 52874 52875 // parallel or collinear 52876 if (inPt.y !== edgeLowPt.y) continue; // parallel 52877 // edge lies on the same horizontal line as inPt 52878 if (((edgeHighPt.x <= inPt.x) && (inPt.x <= edgeLowPt.x)) || 52879 ((edgeLowPt.x <= inPt.x) && (inPt.x <= edgeHighPt.x))) return true; // inPt: Point on contour ! 52880 // continue; 52881 52882 } 52883 52884 } 52885 52886 return inside; 52887 52888 } 52889 52890 const isClockWise = ShapeUtils.isClockWise; 52891 52892 const subPaths = this.subPaths; 52893 if (subPaths.length === 0) return []; 52894 52895 let solid, tmpPath, tmpShape; 52896 const shapes = []; 52897 52898 if (subPaths.length === 1) { 52899 52900 tmpPath = subPaths[0]; 52901 tmpShape = new Shape(); 52902 tmpShape.curves = tmpPath.curves; 52903 shapes.push(tmpShape); 52904 return shapes; 52905 52906 } 52907 52908 let holesFirst = !isClockWise(subPaths[0].getPoints()); 52909 holesFirst = isCCW ? !holesFirst : holesFirst; 52910 52911 // console.log("Holes first", holesFirst); 52912 52913 const betterShapeHoles = []; 52914 const newShapes = []; 52915 let newShapeHoles = []; 52916 let mainIdx = 0; 52917 let tmpPoints; 52918 52919 newShapes[mainIdx] = undefined; 52920 newShapeHoles[mainIdx] = []; 52921 52922 for (let i = 0, l = subPaths.length; i < l; i++) { 52923 52924 tmpPath = subPaths[i]; 52925 tmpPoints = tmpPath.getPoints(); 52926 solid = isClockWise(tmpPoints); 52927 solid = isCCW ? !solid : solid; 52928 52929 if (solid) { 52930 52931 if ((!holesFirst) && (newShapes[mainIdx])) mainIdx++; 52932 52933 newShapes[mainIdx] = { s: new Shape(), p: tmpPoints }; 52934 newShapes[mainIdx].s.curves = tmpPath.curves; 52935 52936 if (holesFirst) mainIdx++; 52937 newShapeHoles[mainIdx] = []; 52938 52939 //console.log('cw', i); 52940 52941 } else { 52942 52943 newShapeHoles[mainIdx].push({ h: tmpPath, p: tmpPoints[0] }); 52944 52945 //console.log('ccw', i); 52946 52947 } 52948 52949 } 52950 52951 // only Holes? -> probably all Shapes with wrong orientation 52952 if (!newShapes[0]) return toShapesNoHoles(subPaths); 52953 52954 52955 if (newShapes.length > 1) { 52956 52957 let ambiguous = false; 52958 let toChange = 0; 52959 52960 for (let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx++) { 52961 52962 betterShapeHoles[sIdx] = []; 52963 52964 } 52965 52966 for (let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx++) { 52967 52968 const sho = newShapeHoles[sIdx]; 52969 52970 for (let hIdx = 0; hIdx < sho.length; hIdx++) { 52971 52972 const ho = sho[hIdx]; 52973 let hole_unassigned = true; 52974 52975 for (let s2Idx = 0; s2Idx < newShapes.length; s2Idx++) { 52976 52977 if (isPointInsidePolygon(ho.p, newShapes[s2Idx].p)) { 52978 52979 if (sIdx !== s2Idx) toChange++; 52980 52981 if (hole_unassigned) { 52982 52983 hole_unassigned = false; 52984 betterShapeHoles[s2Idx].push(ho); 52985 52986 } else { 52987 52988 ambiguous = true; 52989 52990 } 52991 52992 } 52993 52994 } 52995 52996 if (hole_unassigned) { 52997 52998 betterShapeHoles[sIdx].push(ho); 52999 53000 } 53001 53002 } 53003 53004 } 53005 53006 if (toChange > 0 && ambiguous === false) { 53007 53008 newShapeHoles = betterShapeHoles; 53009 53010 } 53011 53012 } 53013 53014 let tmpHoles; 53015 53016 for (let i = 0, il = newShapes.length; i < il; i++) { 53017 53018 tmpShape = newShapes[i].s; 53019 shapes.push(tmpShape); 53020 tmpHoles = newShapeHoles[i]; 53021 53022 for (let j = 0, jl = tmpHoles.length; j < jl; j++) { 53023 53024 tmpShape.holes.push(tmpHoles[j].h); 53025 53026 } 53027 53028 } 53029 53030 //console.log("shape", shapes); 53031 53032 return shapes; 53033 53034 } 53035 53036} 53037 53038if (typeof __THREE_DEVTOOLS__ !== 'undefined') { 53039 53040 __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent('register', { 53041 detail: { 53042 revision: REVISION, 53043 } 53044 })); 53045 53046} 53047 53048if (typeof window !== 'undefined') { 53049 53050 if (window.__THREE__) { 53051 53052 console.warn('WARNING: Multiple instances of Three.js being imported.'); 53053 53054 } else { 53055 53056 window.__THREE__ = REVISION; 53057 53058 } 53059 53060} 53061 53062export { 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
53062phicCamera, 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.