vendor: 14,402 bytes, lines 1-397
1(function (global, factory) { 2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : 3 typeof define === 'function' && define.amd ? define(['exports'], factory) : 4 (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ModelViewerElement = {})); 5})(this, (function (exports) { 'use strict'; 6 7 /** 8 * @license 9 * Copyright 2019 Google LLC 10 * SPDX-License-Identifier: BSD-3-Clause 11 */ const t$2 = globalThis, e$2 = t$2.ShadowRoot && (void 0 === t$2.ShadyCSS || t$2.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, s$1 = Symbol(), o$3 = new WeakMap; 12 let n$4 = class n { 13 get styleSheet() { 14 let t = this.o; 15 const s = this.t; 16 if (e$2 && void 0 === t) { 17 const e = void 0 !== s && 1 === s.length; 18 e && (t = o$3.get(s)), void 0 === t && ((this.o = t = new CSSStyleSheet).replaceSync(this.cssText), e && o$3.set(s, t)); 19 } 20 return t; 21 } 22 toString() { 23 return this.cssText; 24 } 25 constructor(t, e, o){ 26 if (this._$cssResult$ = true, o !== s$1) throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead."); 27 this.cssText = t, this.t = e; 28 } 29 }; 30 const r$4 = (t)=>new n$4("string" == typeof t ? t : t + "", void 0, s$1), S$1 = (s, o)=>{ 31 if (e$2) s.adoptedStyleSheets = o.map((t)=>t instanceof CSSStyleSheet ? t : t.styleSheet); 32 else for (const e of o){ 33 const o = document.createElement("style"), n = t$2.litNonce; 34 void 0 !== n && o.setAttribute("nonce", n), o.textContent = e.cssText, s.appendChild(o); 35 } 36 }, c$3 = e$2 ? (t)=>t : (t)=>t instanceof CSSStyleSheet ? ((t)=>{ 37 let e = ""; 38 for (const s of t.cssRules)e += s.cssText; 39 return r$4(e); 40 })(t) : t; 41 42 var _Symbol, _a$a, _a1; 43 /** 44 * @license 45 * Copyright 2017 Google LLC 46 * SPDX-License-Identifier: BSD-3-Clause 47 */ const { is: i$3, defineProperty: e$1, getOwnPropertyDescriptor: r$3, getOwnPropertyNames: h$1, getOwnPropertySymbols: o$2, getPrototypeOf: n$3 } = Object, a$2 = globalThis, c$2 = a$2.trustedTypes, l$1 = c$2 ? c$2.emptyScript : "", p$1 = a$2.reactiveElementPolyfillSupport, d$1 = (t, s)=>t, u$2 = { 48 toAttribute (t, s) { 49 switch(s){ 50 case Boolean: 51 t = t ? l$1 : null; 52 break; 53 case Object: 54 case Array: 55 t = null == t ? t : JSON.stringify(t); 56 } 57 return t; 58 }, 59 fromAttribute (t, s) { 60 let i = t; 61 switch(s){ 62 case Boolean: 63 i = null !== t; 64 break; 65 case Number: 66 i = null === t ? null : Number(t); 67 break; 68 case Object: 69 case Array: 70 try { 71 i = JSON.parse(t); 72 } catch (t) { 73 i = null; 74 } 75 } 76 return i; 77 } 78 }, f$1 = (t, s)=>!i$3(t, s), y$1 = { 79 attribute: true, 80 type: String, 81 converter: u$2, 82 reflect: false, 83 hasChanged: f$1 84 }; 85 (_Symbol = Symbol).metadata ?? (_Symbol.metadata = Symbol("metadata")), (_a$a = a$2).litPropertyMetadata ?? (_a$a.litPropertyMetadata = new WeakMap); 86 let b$1 = class b extends HTMLElement { 87 static addInitializer(t) { 88 this._$Ei(), (this.l ?? (this.l = [])).push(t); 89 } 90 static get observedAttributes() { 91 return this.finalize(), this._$Eh && [ 92 ...this._$Eh.keys() 93 ]; 94 } 95 static createProperty(t, s = y$1) { 96 if (s.state && (s.attribute = false), this._$Ei(), this.elementProperties.set(t, s), !s.noAccessor) { 97 const i = Symbol(), r = this.getPropertyDescriptor(t, i, s); 98 void 0 !== r && e$1(this.prototype, t, r); 99 } 100 } 101 static getPropertyDescriptor(t, s, i) { 102 const { get: e, set: h } = r$3(this.prototype, t) ?? { 103 get () { 104 return this[s]; 105 }, 106 set (t) { 107 this[s] = t; 108 } 109 }; 110 return { 111 get () { 112 return e?.call(this); 113 }, 114 set (s) { 115 const r = e?.call(this); 116 h.call(this, s), this.requestUpdate(t, r, i); 117 }, 118 configurable: true, 119 enumerable: true 120 }; 121 } 122 static getPropertyOptions(t) { 123 return this.elementProperties.get(t) ?? y$1; 124 } 125 static _$Ei() { 126 if (this.hasOwnProperty(d$1("elementProperties"))) return; 127 const t = n$3(this); 128 t.finalize(), void 0 !== t.l && (this.l = [ 129 ...t.l 130 ]), this.elementProperties = new Map(t.elementProperties); 131 } 132 static finalize() { 133 if (this.hasOwnProperty(d$1("finalized"))) return; 134 if (this.finalized = true, this._$Ei(), this.hasOwnProperty(d$1("properties"))) { 135 const t = this.properties, s = [ 136 ...h$1(t), 137 ...o$2(t) 138 ]; 139 for (const i of s)this.createProperty(i, t[i]); 140 } 141 const t = this[Symbol.metadata]; 142 if (null !== t) { 143 const s = litPropertyMetadata.get(t); 144 if (void 0 !== s) for (const [t, i] of s)this.elementProperties.set(t, i); 145 } 146 this._$Eh = new Map; 147 for (const [t, s] of this.elementProperties){ 148 const i = this._$Eu(t, s); 149 void 0 !== i && this._$Eh.set(i, t); 150 } 151 this.elementStyles = this.finalizeStyles(this.styles); 152 } 153 static finalizeStyles(s) { 154 const i = []; 155 if (Array.isArray(s)) { 156 const e = new Set(s.flat(1 / 0).reverse()); 157 for (const s of e)i.unshift(c$3(s)); 158 } else void 0 !== s && i.push(c$3(s)); 159 return i; 160 } 161 static _$Eu(t, s) { 162 const i = s.attribute; 163 return false === i ? void 0 : "string" == typeof i ? i : "string" == typeof t ? t.toLowerCase() : void 0; 164 } 165 _$Ev() { 166 this._$ES = new Promise((t)=>this.enableUpdating = t), this._$AL = new Map, this._$E_(), this.requestUpdate(), this.constructor.l?.forEach((t)=>t(this)); 167 } 168 addController(t) { 169 (this._$EO ?? (this._$EO = new Set)).add(t), void 0 !== this.renderRoot && this.isConnected && t.hostConnected?.(); 170 } 171 removeController(t) { 172 this._$EO?.delete(t); 173 } 174 _$E_() { 175 const t = new Map, s = this.constructor.elementProperties; 176 for (const i of s.keys())this.hasOwnProperty(i) && (t.set(i, this[i]), delete this[i]); 177 t.size > 0 && (this._$Ep = t); 178 } 179 createRenderRoot() { 180 const t = this.shadowRoot ?? this.attachShadow(this.constructor.shadowRootOptions); 181 return S$1(t, this.constructor.elementStyles), t; 182 } 183 connectedCallback() { 184 this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this.enableUpdating(true), this._$EO?.forEach((t)=>t.hostConnected?.()); 185 } 186 enableUpdating(t) {} 187 disconnectedCallback() { 188 this._$EO?.forEach((t)=>t.hostDisconnected?.()); 189 } 190 attributeChangedCallback(t, s, i) { 191 this._$AK(t, i); 192 } 193 _$EC(t, s) { 194 const i = this.constructor.elementProperties.get(t), e = this.constructor._$Eu(t, i); 195 if (void 0 !== e && true === i.reflect) { 196 const r = (void 0 !== i.converter?.toAttribute ? i.converter : u$2).toAttribute(s, i.type); 197 this._$Em = t, null == r ? this.removeAttribute(e) : this.setAttribute(e, r), this._$Em = null; 198 } 199 } 200 _$AK(t, s) { 201 const i = this.constructor, e = i._$Eh.get(t); 202 if (void 0 !== e && this._$Em !== e) { 203 const t = i.getPropertyOptions(e), r = "function" == typeof t.converter ? { 204 fromAttribute: t.converter 205 } : void 0 !== t.converter?.fromAttribute ? t.converter : u$2; 206 this._$Em = e, this[e] = r.fromAttribute(s, t.type), this._$Em = null; 207 } 208 } 209 requestUpdate(t, s, i) { 210 if (void 0 !== t) { 211 if (i ?? (i = this.constructor.getPropertyOptions(t)), !(i.hasChanged ?? f$1)(this[t], s)) return; 212 this.P(t, s, i); 213 } 214 false === this.isUpdatePending && (this._$ES = this._$ET()); 215 } 216 P(t, s, i) { 217 this._$AL.has(t) || this._$AL.set(t, s), true === i.reflect && this._$Em !== t && (this._$Ej ?? (this._$Ej = new Set)).add(t); 218 } 219 async _$ET() { 220 this.isUpdatePending = true; 221 try { 222 await this._$ES; 223 } catch (t) { 224 Promise.reject(t); 225 } 226 const t = this.scheduleUpdate(); 227 return null != t && await t, !this.isUpdatePending; 228 } 229 scheduleUpdate() { 230 return this.performUpdate(); 231 } 232 performUpdate() { 233 if (!this.isUpdatePending) return; 234 if (!this.hasUpdated) { 235 if (this.renderRoot ?? (this.renderRoot = this.createRenderRoot()), this._$Ep) { 236 for (const [t, s] of this._$Ep)this[t] = s; 237 this._$Ep = void 0; 238 } 239 const t = this.constructor.elementProperties; 240 if (t.size > 0) for (const [s, i] of t) true !== i.wrapped || this._$AL.has(s) || void 0 === this[s] || this.P(s, this[s], i); 241 } 242 let t = false; 243 const s = this._$AL; 244 try { 245 t = this.shouldUpdate(s), t ? (this.willUpdate(s), this._$EO?.forEach((t)=>t.hostUpdate?.()), this.update(s)) : this._$EU(); 246 } catch (s) { 247 throw t = false, this._$EU(), s; 248 } 249 t && this._$AE(s); 250 } 251 willUpdate(t) {} 252 _$AE(t) { 253 this._$EO?.forEach((t)=>t.hostUpdated?.()), this.hasUpdated || (this.hasUpdated = true, this.firstUpdated(t)), this.updated(t); 254 } 255 _$EU() { 256 this._$AL = new Map, this.isUpdatePending = false; 257 } 258 get updateComplete() { 259 return this.getUpdateComplete(); 260 } 261 getUpdateComplete() { 262 return this._$ES; 263 } 264 shouldUpdate(t) { 265 return true; 266 } 267 update(t) { 268 this._$Ej && (this._$Ej = this._$Ej.forEach((t)=>this._$EC(t, this[t]))), this._$EU(); 269 } 270 updated(t) {} 271 firstUpdated(t) {} 272 constructor(){ 273 super(), this._$Ep = void 0, this.isUpdatePending = false, this.hasUpdated = false, this._$Em = null, this._$Ev(); 274 } 275 }; 276 b$1.elementStyles = [], b$1.shadowRootOptions = { 277 mode: "open" 278 }, b$1[d$1("elementProperties")] = new Map, b$1[d$1("finalized")] = new Map, p$1?.({ 279 ReactiveElement: b$1 280 }), ((_a1 = a$2).reactiveElementVersions ?? (_a1.reactiveElementVersions = [])).push("2.0.4"); 281 282 /** 283 * @license 284 * Copyright 2017 Google LLC 285 * SPDX-License-Identifier: BSD-3-Clause 286 */ const o$1 = { 287 attribute: true, 288 type: String, 289 converter: u$2, 290 reflect: false, 291 hasChanged: f$1 292 }, r$2 = (t = o$1, e, r)=>{ 293 const { kind: n, metadata: i } = r; 294 let s = globalThis.litPropertyMetadata.get(i); 295 if (void 0 === s && globalThis.litPropertyMetadata.set(i, s = new Map), s.set(r.name, t), "accessor" === n) { 296 const { name: o } = r; 297 return { 298 set (r) { 299 const n = e.get.call(this); 300 e.set.call(this, r), this.requestUpdate(o, n, t); 301 }, 302 init (e) { 303 return void 0 !== e && this.P(o, void 0, t), e; 304 } 305 }; 306 } 307 if ("setter" === n) { 308 const { name: o } = r; 309 return function(r) { 310 const n = this[o]; 311 e.call(this, r), this.requestUpdate(o, n, t); 312 }; 313 } 314 throw Error("Unsupported decorator location: " + n); 315 }; 316 function n$2(t) { 317 return (e, o)=>"object" == typeof o ? r$2(t, e, o) : ((t, e, o)=>{ 318 const r = e.hasOwnProperty(o); 319 return e.constructor.createProperty(o, r ? { 320 ...t, 321 wrapped: true 322 } : t), r ? Object.getOwnPropertyDescriptor(e, o) : void 0; 323 })(t, e, o); 324 } 325 326 /** 327 * @license 328 * Copyright 2010-2025 Three.js Authors 329 * SPDX-License-Identifier: MIT 330 */ const REVISION = '174'; 331 const CullFaceNone = 0; 332 const CullFaceBack = 1; 333 const CullFaceFront = 2; 334 const PCFShadowMap = 1; 335 const PCFSoftShadowMap = 2; 336 const VSMShadowMap = 3; 337 const FrontSide = 0; 338 const BackSide = 1; 339 const DoubleSide = 2; 340 const NoBlending = 0; 341 const NormalBlending = 1; 342 const AdditiveBlending = 2; 343 const SubtractiveBlending = 3; 344 const MultiplyBlending = 4; 345 const CustomBlending = 5; 346 const AddEquation = 100; 347 const SubtractEquation = 101; 348 const ReverseSubtractEquation = 102; 349 const MinEquation = 103; 350 const MaxEquation = 104; 351 const ZeroFactor = 200; 352 const OneFactor = 201; 353 const SrcColorFactor = 202; 354 const OneMinusSrcColorFactor = 203; 355 const SrcAlphaFactor = 204; 356 const OneMinusSrcAlphaFactor = 205; 357 const DstAlphaFactor = 206; 358 const OneMinusDstAlphaFactor = 207; 359 const DstColorFactor = 208; 360 const OneMinusDstColorFactor = 209; 361 const SrcAlphaSaturateFactor = 210; 362 const ConstantColorFactor = 211; 363 const OneMinusConstantColorFactor = 212; 364 const ConstantAlphaFactor = 213; 365 const OneMinusConstantAlphaFactor = 214; 366 const NeverDepth = 0; 367 const AlwaysDepth = 1; 368 const LessDepth = 2; 369 const LessEqualDepth = 3; 370 const EqualDepth = 4; 371 const GreaterEqualDepth = 5; 372 const GreaterDepth = 6; 373 const NotEqualDepth = 7; 374 const MultiplyOperation = 0; 375 const MixOperation = 1; 376 const AddOperation = 2; 377 const NoToneMapping = 0; 378 const LinearToneMapping = 1; 379 const ReinhardToneMapping = 2; 380 const CineonToneMapping = 3; 381 const ACESFilmicToneMapping = 4; 382 const CustomToneMapping = 5; 383 const AgXToneMapping = 6; 384 const NeutralToneMapping = 7; 385 const AttachedBindMode = 'attached'; 386 const DetachedBindMode = 'detached'; 387 const UVMapping = 300; 388 const CubeReflectionMapping = 301; 389 const CubeRefractionMapping = 302; 390 const EquirectangularReflectionMapping = 303; 391 const EquirectangularRefractionMapping = 304; 392 const CubeUVReflectionMapping = 306; 393 const RepeatWrapping = 1000; 394 const ClampToEdgeWrapping = 1001; 395 const MirroredRepeatWrapping = 1002; 396 const NearestFilter = 1003; 397 const NearestMipmapNearestFilter = 1004;
vendor: 10,977 bytes, lines 398-876
398 const NearestMipmapLinearFilter = 1005; 399 const LinearFilter = 1006; 400 const LinearMipmapNearestFilter = 1007; 401 const LinearMipmapLinearFilter = 1008; 402 const LinearMipMapLinearFilter = 1008; 403 const UnsignedByteType = 1009; 404 const ByteType = 1010; 405 const ShortType = 1011; 406 const UnsignedShortType = 1012; 407 const IntType = 1013; 408 const UnsignedIntType = 1014; 409 const FloatType = 1015; 410 const HalfFloatType = 1016; 411 const UnsignedShort4444Type = 1017; 412 const UnsignedShort5551Type = 1018; 413 const UnsignedInt248Type = 1020; 414 const UnsignedInt5999Type = 35902; 415 const AlphaFormat = 1021; 416 const RGBFormat = 1022; 417 const RGBAFormat = 1023; 418 const LuminanceFormat = 1024; 419 const LuminanceAlphaFormat = 1025; 420 const DepthFormat = 1026; 421 const DepthStencilFormat = 1027; 422 const RedFormat = 1028; 423 const RedIntegerFormat = 1029; 424 const RGFormat = 1030; 425 const RGIntegerFormat = 1031; 426 const RGBAIntegerFormat = 1033; 427 const RGB_S3TC_DXT1_Format = 33776; 428 const RGBA_S3TC_DXT1_Format = 33777; 429 const RGBA_S3TC_DXT3_Format = 33778; 430 const RGBA_S3TC_DXT5_Format = 33779; 431 const RGB_PVRTC_4BPPV1_Format = 35840; 432 const RGB_PVRTC_2BPPV1_Format = 35841; 433 const RGBA_PVRTC_4BPPV1_Format = 35842; 434 const RGBA_PVRTC_2BPPV1_Format = 35843; 435 const RGB_ETC1_Format = 36196; 436 const RGB_ETC2_Format = 37492; 437 const RGBA_ETC2_EAC_Format = 37496; 438 const RGBA_ASTC_4x4_Format = 37808; 439 const RGBA_ASTC_5x4_Format = 37809; 440 const RGBA_ASTC_5x5_Format = 37810; 441 const RGBA_ASTC_6x5_Format = 37811; 442 const RGBA_ASTC_6x6_Format = 37812; 443 const RGBA_ASTC_8x5_Format = 37813; 444 const RGBA_ASTC_8x6_Format = 37814; 445 const RGBA_ASTC_8x8_Format = 37815; 446 const RGBA_ASTC_10x5_Format = 37816; 447 const RGBA_ASTC_10x6_Format = 37817; 448 const RGBA_ASTC_10x8_Format = 37818; 449 const RGBA_ASTC_10x10_Format = 37819; 450 const RGBA_ASTC_12x10_Format = 37820; 451 const RGBA_ASTC_12x12_Format = 37821; 452 const RGBA_BPTC_Format = 36492; 453 const RGB_BPTC_SIGNED_Format = 36494; 454 const RGB_BPTC_UNSIGNED_Format = 36495; 455 const RED_RGTC1_Format = 36283; 456 const SIGNED_RED_RGTC1_Format = 36284; 457 const RED_GREEN_RGTC2_Format = 36285; 458 const SIGNED_RED_GREEN_RGTC2_Format = 36286; 459 const LoopOnce = 2200; 460 const LoopRepeat = 2201; 461 const LoopPingPong = 2202; 462 const InterpolateDiscrete = 2300; 463 const InterpolateLinear = 2301; 464 const InterpolateSmooth = 2302; 465 const ZeroCurvatureEnding = 2400; 466 const ZeroSlopeEnding = 2401; 467 const WrapAroundEnding = 2402; 468 const NormalAnimationBlendMode = 2500; 469 const AdditiveAnimationBlendMode = 2501; 470 const TrianglesDrawMode = 0; 471 const TriangleStripDrawMode = 1; 472 const TriangleFanDrawMode = 2; 473 const BasicDepthPacking = 3200; 474 const RGBADepthPacking = 3201; 475 const TangentSpaceNormalMap = 0; 476 const ObjectSpaceNormalMap = 1; 477 // Color space string identifiers, matching CSS Color Module Level 4 and WebGPU names where available. 478 const NoColorSpace = ''; 479 const SRGBColorSpace = 'srgb'; 480 const LinearSRGBColorSpace = 'srgb-linear'; 481 const LinearTransfer = 'linear'; 482 const SRGBTransfer = 'srgb'; 483 const KeepStencilOp = 7680; 484 const AlwaysStencilFunc = 519; 485 const NeverCompare = 512; 486 const LessCompare = 513; 487 const EqualCompare = 514; 488 const LessEqualCompare = 515; 489 const GreaterCompare = 516; 490 const NotEqualCompare = 517; 491 const GreaterEqualCompare = 518; 492 const AlwaysCompare = 519; 493 const StaticDrawUsage = 35044; 494 const GLSL3 = '300 es'; 495 const WebGLCoordinateSystem = 2000; 496 const WebGPUCoordinateSystem = 2001; 497 /** 498 * This modules allows to dispatch event objects on custom JavaScript objects. 499 * 500 * Main repository: [eventdispatcher.js]{@link https://github.com/mrdoob/eventdispatcher.js/} 501 * 502 * Code Example: 503 * ```js 504 * class Car extends EventDispatcher { 505 * start() { 506 * this.dispatchEvent( { type: 'start', message: 'vroom vroom!' } ); 507 * } 508 *}; 509 * 510 * // Using events with the custom object 511 * const car = new Car(); 512 * car.addEventListener( 'start', function ( event ) { 513 * alert( event.message ); 514 * } ); 515 * 516 * car.start(); 517 * ``` 518 */ class EventDispatcher { 519 /** 520 * Adds the given event listener to the given event type. 521 * 522 * @param {string} type - The type of event to listen to. 523 * @param {Function} listener - The function that gets called when the event is fired. 524 */ addEventListener(type, listener) { 525 if (this._listeners === undefined) this._listeners = {}; 526 const listeners = this._listeners; 527 if (listeners[type] === undefined) { 528 listeners[type] = []; 529 } 530 if (listeners[type].indexOf(listener) === -1) { 531 listeners[type].push(listener); 532 } 533 } 534 /** 535 * Returns `true` if the given event listener has been added to the given event type. 536 * 537 * @param {string} type - The type of event. 538 * @param {Function} listener - The listener to check. 539 * @return {boolean} Whether the given event listener has been added to the given event type. 540 */ hasEventListener(type, listener) { 541 const listeners = this._listeners; 542 if (listeners === undefined) return false; 543 return listeners[type] !== undefined && listeners[type].indexOf(listener) !== -1; 544 } 545 /** 546 * Removes the given event listener from the given event type. 547 * 548 * @param {string} type - The type of event. 549 * @param {Function} listener - The listener to remove. 550 */ removeEventListener(type, listener) { 551 const listeners = this._listeners; 552 if (listeners === undefined) return; 553 const listenerArray = listeners[type]; 554 if (listenerArray !== undefined) { 555 const index = listenerArray.indexOf(listener); 556 if (index !== -1) { 557 listenerArray.splice(index, 1); 558 } 559 } 560 } 561 /** 562 * Dispatches an event object. 563 * 564 * @param {Object} event - The event that gets fired. 565 */ dispatchEvent(event) { 566 const listeners = this._listeners; 567 if (listeners === undefined) return; 568 const listenerArray = listeners[event.type]; 569 if (listenerArray !== undefined) { 570 event.target = this; 571 // Make a copy, in case listeners are removed while iterating. 572 const array = listenerArray.slice(0); 573 for(let i = 0, l = array.length; i < l; i++){ 574 array[i].call(this, event); 575 } 576 event.target = null; 577 } 578 } 579 } 580 const _lut = [ 581 '00', 582 '01', 583 '02', 584 '03', 585 '04', 586 '05', 587 '06', 588 '07', 589 '08', 590 '09', 591 '0a', 592 '0b', 593 '0c', 594 '0d', 595 '0e', 596 '0f', 597 '10', 598 '11', 599 '12', 600 '13', 601 '14', 602 '15', 603 '16', 604 '17', 605 '18', 606 '19', 607 '1a', 608 '1b', 609 '1c', 610 '1d', 611 '1e', 612 '1f', 613 '20', 614 '21', 615 '22', 616 '23', 617 '24', 618 '25', 619 '26', 620 '27', 621 '28', 622 '29', 623 '2a', 624 '2b', 625 '2c', 626 '2d', 627 '2e', 628 '2f', 629 '30', 630 '31', 631 '32', 632 '33', 633 '34', 634 '35', 635 '36', 636 '37', 637 '38', 638 '39', 639 '3a', 640 '3b', 641 '3c', 642 '3d', 643 '3e', 644 '3f', 645 '40', 646 '41', 647 '42', 648 '43', 649 '44', 650 '45', 651 '46', 652 '47', 653 '48', 654 '49', 655 '4a', 656 '4b', 657 '4c', 658 '4d', 659 '4e', 660 '4f', 661 '50', 662 '51', 663 '52', 664 '53', 665 '54', 666 '55', 667 '56', 668 '57', 669 '58', 670 '59', 671 '5a', 672 '5b', 673 '5c', 674 '5d', 675 '5e', 676 '5f', 677 '60', 678 '61', 679 '62', 680 '63', 681 '64', 682 '65', 683 '66', 684 '67', 685 '68', 686 '69', 687 '6a', 688 '6b', 689 '6c', 690 '6d', 691 '6e', 692 '6f', 693 '70', 694 '71', 695 '72', 696 '73', 697 '74', 698 '75', 699 '76', 700 '77', 701 '78', 702 '79', 703 '7a', 704 '7b', 705 '7c', 706 '7d', 707 '7e', 708 '7f', 709 '80', 710 '81', 711 '82', 712 '83', 713 '84', 714 '85', 715 '86', 716 '87', 717 '88', 718 '89', 719 '8a', 720 '8b', 721 '8c', 722 '8d', 723 '8e', 724 '8f', 725 '90', 726 '91', 727 '92', 728 '93', 729 '94', 730 '95', 731 '96', 732 '97', 733 '98', 734 '99', 735 '9a', 736 '9b', 737 '9c', 738 '9d', 739 '9e', 740 '9f', 741 'a0', 742 'a1', 743 'a2', 744 'a3', 745 'a4', 746 'a5', 747 'a6', 748 'a7', 749 'a8', 750 'a9', 751 'aa', 752 'ab', 753 'ac', 754 'ad', 755 'ae', 756 'af', 757 'b0', 758 'b1', 759 'b2', 760 'b3', 761 'b4', 762 'b5', 763 'b6', 764 'b7', 765 'b8', 766 'b9', 767 'ba', 768 'bb', 769 'bc', 770 'bd', 771 'be', 772 'bf', 773 'c0', 774 'c1', 775 'c2', 776 'c3', 777 'c4', 778 'c5', 779 'c6', 780 'c7', 781 'c8', 782 'c9', 783 'ca', 784 'cb', 785 'cc', 786 'cd', 787 'ce', 788 'cf', 789 'd0', 790 'd1', 791 'd2', 792 'd3', 793 'd4', 794 'd5', 795 'd6', 796 'd7', 797 'd8', 798 'd9', 799 'da', 800 'db', 801 'dc', 802 'dd', 803 'de', 804 'df', 805 'e0', 806 'e1', 807 'e2', 808 'e3', 809 'e4', 810 'e5', 811 'e6', 812 'e7', 813 'e8', 814 'e9', 815 'ea', 816 'eb', 817 'ec', 818 'ed', 819 'ee', 820 'ef', 821 'f0', 822 'f1', 823 'f2', 824 'f3', 825 'f4', 826 'f5', 827 'f6', 828 'f7', 829 'f8', 830 'f9', 831 'fa', 832 'fb', 833 'fc', 834 'fd', 835 'fe', 836 'ff' 837 ]; 838 let _seed = 1234567; 839 const DEG2RAD = Math.PI / 180; 840 const RAD2DEG = 180 / Math.PI; 841 /** 842 * Generate a [UUID]{@link https://en.wikipedia.org/wiki/Universally_unique_identifier} 843 * (universally unique identifier). 844 * 845 * @return {string} The UUID. 846 */ function generateUUID() { 847 // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 848 const d0 = Math.random() * 0xffffffff | 0; 849 const d1 = Math.random() * 0xffffffff | 0; 850 const d2 = Math.random() * 0xffffffff | 0; 851 const d3 = Math.random() * 0xffffffff | 0; 852 const uuid = _lut[d0 & 0xff] + _lut[d0 >> 8 & 0xff] + _lut[d0 >> 16 & 0xff] + _lut[d0 >> 24 & 0xff] + '-' + _lut[d1 & 0xff] + _lut[d1 >> 8 & 0xff] + '-' + _lut[d1 >> 16 & 0x0f | 0x40] + _lut[d1 >> 24 & 0xff] + '-' + _lut[d2 & 0x3f | 0x80] + _lut[d2 >> 8 & 0xff] + '-' + _lut[d2 >> 16 & 0xff] + _lut[d2 >> 24 & 0xff] + _lut[d3 & 0xff] + _lut[d3 >> 8 & 0xff] + _lut[d3 >> 16 & 0xff] + _lut[d3 >> 24 & 0xff]; 853 // .toLowerCase() here flattens concatenated strings to save heap memory space. 854 return uuid.toLowerCase(); 855 } 856 /** 857 * Clamps the given value between min and max. 858 * 859 * @param {number} value - The value to clamp. 860 * @param {number} min - The min value. 861 * @param {number} max - The max value. 862 * @return {number} The clamped value. 863 */ function clamp$1(value, min, max) { 864 return Math.max(min, Math.min(max, value)); 865 } 866 /** 867 * Computes the Euclidean modulo of the given parameters that 868 * is `( ( n % m ) + m ) % m`. 869 * 870 * @param {number} n - The first parameter. 871 * @param {number} m - The second parameter. 872 * @return {number} The Euclidean modulo. 873 */ function euclideanModulo(n, m) { 874 // https://en.wikipedia.org/wiki/Modulo_operation 875 return (n % m + m) % m; 876 }
vendor: 5,793 bytes, lines 877-1026
877 /** 878 * Performs a linear mapping from range `<a1, a2>` to range `<b1, b2>` 879 * for the given value. 880 * 881 * @param {number} x - The value to be mapped. 882 * @param {number} a1 - Minimum value for range A. 883 * @param {number} a2 - Maximum value for range A. 884 * @param {number} b1 - Minimum value for range B. 885 * @param {number} b2 - Maximum value for range B. 886 * @return {number} The mapped value. 887 */ function mapLinear(x, a1, a2, b1, b2) { 888 return b1 + (x - a1) * (b2 - b1) / (a2 - a1); 889 } 890 /** 891 * Returns the percentage in the closed interval `[0, 1]` of the given value 892 * between the start and end point. 893 * 894 * @param {number} x - The start point 895 * @param {number} y - The end point. 896 * @param {number} value - A value between start and end. 897 * @return {number} The interpolation factor. 898 */ function inverseLerp(x, y, value) { 899 // https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/ 900 if (x !== y) { 901 return (value - x) / (y - x); 902 } else { 903 return 0; 904 } 905 } 906 /** 907 * Returns a value linearly interpolated from two known points based on the given interval - 908 * `t = 0` will return `x` and `t = 1` will return `y`. 909 * 910 * @param {number} x - The start point 911 * @param {number} y - The end point. 912 * @param {number} t - The interpolation factor in the closed interval `[0, 1]`. 913 * @return {number} The interpolated value. 914 */ function lerp$1(x, y, t) { 915 return (1 - t) * x + t * y; 916 } 917 /** 918 * Smoothly interpolate a number from `x` to `y` in a spring-like manner using a delta 919 * time to maintain frame rate independent movement. For details, see 920 * [Frame rate independent damping using lerp]{@link http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/}. 921 * 922 * @param {number} x - The current point. 923 * @param {number} y - The target point. 924 * @param {number} lambda - A higher lambda value will make the movement more sudden, 925 * and a lower value will make the movement more gradual. 926 * @param {number} dt - Delta time in seconds. 927 * @return {number} The interpolated value. 928 */ function damp(x, y, lambda, dt) { 929 return lerp$1(x, y, 1 - Math.exp(-lambda * dt)); 930 } 931 /** 932 * Returns a value that alternates between `0` and the given `length` parameter. 933 * 934 * @param {number} x - The value to pingpong. 935 * @param {number} [length=1] - The positive value the function will pingpong to. 936 * @return {number} The alternated value. 937 */ function pingpong(x, length = 1) { 938 // https://www.desmos.com/calculator/vcsjnyz7x4 939 return length - Math.abs(euclideanModulo(x, length * 2) - length); 940 } 941 /** 942 * Returns a value in the range `[0,1]` that represents the percentage that `x` has 943 * moved between `min` and `max`, but smoothed or slowed down the closer `x` is to 944 * the `min` and `max`. 945 * 946 * See [Smoothstep]{@link http://en.wikipedia.org/wiki/Smoothstep} for more details. 947 * 948 * @param {number} x - The value to evaluate based on its position between min and max. 949 * @param {number} min - The min value. Any x value below min will be `0`. 950 * @param {number} max - The max value. Any x value above max will be `1`. 951 * @return {number} The alternated value. 952 */ function smoothstep(x, min, max) { 953 if (x <= min) return 0; 954 if (x >= max) return 1; 955 x = (x - min) / (max - min); 956 return x * x * (3 - 2 * x); 957 } 958 /** 959 * A [variation on smoothstep]{@link https://en.wikipedia.org/wiki/Smoothstep#Variations} 960 * that has zero 1st and 2nd order derivatives at x=0 and x=1. 961 * 962 * @param {number} x - The value to evaluate based on its position between min and max. 963 * @param {number} min - The min value. Any x value below min will be `0`. 964 * @param {number} max - The max value. Any x value above max will be `1`. 965 * @return {number} The alternated value. 966 */ function smootherstep(x, min, max) { 967 if (x <= min) return 0; 968 if (x >= max) return 1; 969 x = (x - min) / (max - min); 970 return x * x * x * (x * (x * 6 - 15) + 10); 971 } 972 /** 973 * Returns a random integer from `<low, high>` interval. 974 * 975 * @param {number} low - The lower value boundary. 976 * @param {number} high - The upper value boundary 977 * @return {number} A random integer. 978 */ function randInt(low, high) { 979 return low + Math.floor(Math.random() * (high - low + 1)); 980 } 981 /** 982 * Returns a random float from `<low, high>` interval. 983 * 984 * @param {number} low - The lower value boundary. 985 * @param {number} high - The upper value boundary 986 * @return {number} A random float. 987 */ function randFloat(low, high) { 988 return low + Math.random() * (high - low); 989 } 990 /** 991 * Returns a random integer from `<-range/2, range/2>` interval. 992 * 993 * @param {number} range - Defines the value range. 994 * @return {number} A random float. 995 */ function randFloatSpread(range) { 996 return range * (0.5 - Math.random()); 997 } 998 /** 999 * Returns a deterministic pseudo-random float in the interval `[0, 1]`. 1000 * 1001 * @param {number} [s] - The integer seed. 1002 * @return {number} A random float. 1003 */ function seededRandom(s) { 1004 if (s !== undefined) _seed = s; 1005 // Mulberry32 generator 1006 let t = _seed += 0x6D2B79F5; 1007 t = Math.imul(t ^ t >>> 15, t | 1); 1008 t ^= t + Math.imul(t ^ t >>> 7, t | 61); 1009 return ((t ^ t >>> 14) >>> 0) / 4294967296; 1010 } 1011 /** 1012 * Converts degrees to radians. 1013 * 1014 * @param {number} degrees - A value in degrees. 1015 * @return {number} The converted value in radians. 1016 */ function degToRad(degrees) { 1017 return degrees * DEG2RAD; 1018 } 1019 /** 1020 * Converts radians to degrees. 1021 * 1022 * @param {number} radians - A value in radians. 1023 * @return {number} The converted value in degrees. 1024 */ function radToDeg(radians) { 1025 return radians * RAD2DEG; 1026 }
vendor: 39,990 bytes, lines 1027-2191
1027 /** 1028 * Returns `true` if the given number is a power of two. 1029 * 1030 * @param {number} value - The value to check. 1031 * @return {boolean} Whether the given number is a power of two or not. 1032 */ function isPowerOfTwo(value) { 1033 return (value & value - 1) === 0 && value !== 0; 1034 } 1035 /** 1036 * Returns the smallest power of two that is greater than or equal to the given number. 1037 * 1038 * @param {number} value - The value to find a POT for. 1039 * @return {number} The smallest power of two that is greater than or equal to the given number. 1040 */ function ceilPowerOfTwo(value) { 1041 return Math.pow(2, Math.ceil(Math.log(value) / Math.LN2)); 1042 } 1043 /** 1044 * Returns the largest power of two that is less than or equal to the given number. 1045 * 1046 * @param {number} value - The value to find a POT for. 1047 * @return {number} The largest power of two that is less than or equal to the given number. 1048 */ function floorPowerOfTwo(value) { 1049 return Math.pow(2, Math.floor(Math.log(value) / Math.LN2)); 1050 } 1051 /** 1052 * Sets the given quaternion from the [Intrinsic Proper Euler Angles]{@link https://en.wikipedia.org/wiki/Euler_angles} 1053 * defined by the given angles and order. 1054 * 1055 * Rotations are applied to the axes in the order specified by order: 1056 * rotation by angle `a` is applied first, then by angle `b`, then by angle `c`. 1057 * 1058 * @param {Quaternion} q - The quaternion to set. 1059 * @param {number} a - The rotation applied to the first axis, in radians. 1060 * @param {number} b - The rotation applied to the second axis, in radians. 1061 * @param {number} c - The rotation applied to the third axis, in radians. 1062 * @param {('XYX'|'XZX'|'YXY'|'YZY'|'ZXZ'|'ZYZ')} order - A string specifying the axes order. 1063 */ function setQuaternionFromProperEuler(q, a, b, c, order) { 1064 const cos = Math.cos; 1065 const sin = Math.sin; 1066 const c2 = cos(b / 2); 1067 const s2 = sin(b / 2); 1068 const c13 = cos((a + c) / 2); 1069 const s13 = sin((a + c) / 2); 1070 const c1_3 = cos((a - c) / 2); 1071 const s1_3 = sin((a - c) / 2); 1072 const c3_1 = cos((c - a) / 2); 1073 const s3_1 = sin((c - a) / 2); 1074 switch(order){ 1075 case 'XYX': 1076 q.set(c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13); 1077 break; 1078 case 'YZY': 1079 q.set(s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13); 1080 break; 1081 case 'ZXZ': 1082 q.set(s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13); 1083 break; 1084 case 'XZX': 1085 q.set(c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13); 1086 break; 1087 case 'YXY': 1088 q.set(s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13); 1089 break; 1090 case 'ZYZ': 1091 q.set(s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13); 1092 break; 1093 default: 1094 console.warn('THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order); 1095 } 1096 } 1097 /** 1098 * Denormalizes the given value according to the given typed array. 1099 * 1100 * @param {number} value - The value to denormalize. 1101 * @param {TypedArray} array - The typed array that defines the data type of the value. 1102 * @return {number} The denormalize (float) value in the range `[0,1]`. 1103 */ function denormalize(value, array) { 1104 switch(array.constructor){ 1105 case Float32Array: 1106 return value; 1107 case Uint32Array: 1108 return value / 4294967295.0; 1109 case Uint16Array: 1110 return value / 65535.0; 1111 case Uint8Array: 1112 return value / 255.0; 1113 case Int32Array: 1114 return Math.max(value / 2147483647.0, -1); 1115 case Int16Array: 1116 return Math.max(value / 32767.0, -1); 1117 case Int8Array: 1118 return Math.max(value / 127.0, -1); 1119 default: 1120 throw new Error('Invalid component type.'); 1121 } 1122 } 1123 /** 1124 * Normalizes the given value according to the given typed array. 1125 * 1126 * @param {number} value - The float value in the range `[0,1]` to normalize. 1127 * @param {TypedArray} array - The typed array that defines the data type of the value. 1128 * @return {number} The normalize value. 1129 */ function normalize(value, array) { 1130 switch(array.constructor){ 1131 case Float32Array: 1132 return value; 1133 case Uint32Array: 1134 return Math.round(value * 4294967295.0); 1135 case Uint16Array: 1136 return Math.round(value * 65535.0); 1137 case Uint8Array: 1138 return Math.round(value * 255.0); 1139 case Int32Array: 1140 return Math.round(value * 2147483647.0); 1141 case Int16Array: 1142 return Math.round(value * 32767.0); 1143 case Int8Array: 1144 return Math.round(value * 127.0); 1145 default: 1146 throw new Error('Invalid component type.'); 1147 } 1148 } 1149 const MathUtils = { 1150 DEG2RAD: DEG2RAD, 1151 RAD2DEG: RAD2DEG, 1152 generateUUID: generateUUID, 1153 clamp: clamp$1, 1154 euclideanModulo: euclideanModulo, 1155 mapLinear: mapLinear, 1156 inverseLerp: inverseLerp, 1157 lerp: lerp$1, 1158 damp: damp, 1159 pingpong: pingpong, 1160 smoothstep: smoothstep, 1161 smootherstep: smootherstep, 1162 randInt: randInt, 1163 randFloat: randFloat, 1164 randFloatSpread: randFloatSpread, 1165 seededRandom: seededRandom, 1166 degToRad: degToRad, 1167 radToDeg: radToDeg, 1168 isPowerOfTwo: isPowerOfTwo, 1169 ceilPowerOfTwo: ceilPowerOfTwo, 1170 floorPowerOfTwo: floorPowerOfTwo, 1171 setQuaternionFromProperEuler: setQuaternionFromProperEuler, 1172 normalize: normalize, 1173 denormalize: denormalize 1174 }; 1175 /** 1176 * Class representing a 2D vector. A 2D vector is an ordered pair of numbers 1177 * (labeled x and y), which can be used to represent a number of things, such as: 1178 * 1179 * - A point in 2D space (i.e. a position on a plane). 1180 * - A direction and length across a plane. In three.js the length will 1181 * always be the Euclidean distance(straight-line distance) from `(0, 0)` to `(x, y)` 1182 * and the direction is also measured from `(0, 0)` towards `(x, y)`. 1183 * - Any arbitrary ordered pair of numbers. 1184 * 1185 * There are other things a 2D vector can be used to represent, such as 1186 * momentum vectors, complex numbers and so on, however these are the most 1187 * common uses in three.js. 1188 * 1189 * Iterating through a vector instance will yield its components `(x, y)` in 1190 * the corresponding order. 1191 * ```js 1192 * const a = new THREE.Vector2( 0, 1 ); 1193 * 1194 * //no arguments; will be initialised to (0, 0) 1195 * const b = new THREE.Vector2( ); 1196 * 1197 * const d = a.distanceTo( b ); 1198 * ``` 1199 */ class Vector2 { 1200 /** 1201 * Alias for {@link Vector2#x}. 1202 * 1203 * @type {number} 1204 */ get width() { 1205 return this.x; 1206 } 1207 set width(value) { 1208 this.x = value; 1209 } 1210 /** 1211 * Alias for {@link Vector2#y}. 1212 * 1213 * @type {number} 1214 */ get height() { 1215 return this.y; 1216 } 1217 set height(value) { 1218 this.y = value; 1219 } 1220 /** 1221 * Sets the vector components. 1222 * 1223 * @param {number} x - The value of the x component. 1224 * @param {number} y - The value of the y component. 1225 * @return {Vector2} A reference to this vector. 1226 */ set(x, y) { 1227 this.x = x; 1228 this.y = y; 1229 return this; 1230 } 1231 /** 1232 * Sets the vector components to the same value. 1233 * 1234 * @param {number} scalar - The value to set for all vector components. 1235 * @return {Vector2} A reference to this vector. 1236 */ setScalar(scalar) { 1237 this.x = scalar; 1238 this.y = scalar; 1239 return this; 1240 } 1241 /** 1242 * Sets the vector's x component to the given value 1243 * 1244 * @param {number} x - The value to set. 1245 * @return {Vector2} A reference to this vector. 1246 */ setX(x) { 1247 this.x = x; 1248 return this; 1249 } 1250 /** 1251 * Sets the vector's y component to the given value 1252 * 1253 * @param {number} y - The value to set. 1254 * @return {Vector2} A reference to this vector. 1255 */ setY(y) { 1256 this.y = y; 1257 return this; 1258 } 1259 /** 1260 * Allows to set a vector component with an index. 1261 * 1262 * @param {number} index - The component index. `0` equals to x, `1` equals to y. 1263 * @param {number} value - The value to set. 1264 * @return {Vector2} A reference to this vector. 1265 */ setComponent(index, value) { 1266 switch(index){ 1267 case 0: 1268 this.x = value; 1269 break; 1270 case 1: 1271 this.y = value; 1272 break; 1273 default: 1274 throw new Error('index is out of range: ' + index); 1275 } 1276 return this; 1277 } 1278 /** 1279 * Returns the value of the vector component which matches the given index. 1280 * 1281 * @param {number} index - The component index. `0` equals to x, `1` equals to y. 1282 * @return {number} A vector component value. 1283 */ getComponent(index) { 1284 switch(index){ 1285 case 0: 1286 return this.x; 1287 case 1: 1288 return this.y; 1289 default: 1290 throw new Error('index is out of range: ' + index); 1291 } 1292 } 1293 /** 1294 * Returns a new vector with copied values from this instance. 1295 * 1296 * @return {Vector2} A clone of this instance. 1297 */ clone() { 1298 return new this.constructor(this.x, this.y); 1299 } 1300 /** 1301 * Copies the values of the given vector to this instance. 1302 * 1303 * @param {Vector2} v - The vector to copy. 1304 * @return {Vector2} A reference to this vector. 1305 */ copy(v) { 1306 this.x = v.x; 1307 this.y = v.y; 1308 return this; 1309 } 1310 /** 1311 * Adds the given vector to this instance. 1312 * 1313 * @param {Vector2} v - The vector to add. 1314 * @return {Vector2} A reference to this vector. 1315 */ add(v) { 1316 this.x += v.x; 1317 this.y += v.y; 1318 return this; 1319 } 1320 /** 1321 * Adds the given scalar value to all components of this instance. 1322 * 1323 * @param {number} s - The scalar to add. 1324 * @return {Vector2} A reference to this vector. 1325 */ addScalar(s) { 1326 this.x += s; 1327 this.y += s; 1328 return this; 1329 } 1330 /** 1331 * Adds the given vectors and stores the result in this instance. 1332 * 1333 * @param {Vector2} a - The first vector. 1334 * @param {Vector2} b - The second vector. 1335 * @return {Vector2} A reference to this vector. 1336 */ addVectors(a, b) { 1337 this.x = a.x + b.x; 1338 this.y = a.y + b.y; 1339 return this; 1340 } 1341 /** 1342 * Adds the given vector scaled by the given factor to this instance. 1343 * 1344 * @param {Vector2} v - The vector. 1345 * @param {number} s - The factor that scales `v`. 1346 * @return {Vector2} A reference to this vector. 1347 */ addScaledVector(v, s) { 1348 this.x += v.x * s; 1349 this.y += v.y * s; 1350 return this; 1351 } 1352 /** 1353 * Subtracts the given vector from this instance. 1354 * 1355 * @param {Vector2} v - The vector to subtract. 1356 * @return {Vector2} A reference to this vector. 1357 */ sub(v) { 1358 this.x -= v.x; 1359 this.y -= v.y; 1360 return this; 1361 } 1362 /** 1363 * Subtracts the given scalar value from all components of this instance. 1364 * 1365 * @param {number} s - The scalar to subtract. 1366 * @return {Vector2} A reference to this vector. 1367 */ subScalar(s) { 1368 this.x -= s; 1369 this.y -= s; 1370 return this; 1371 } 1372 /** 1373 * Subtracts the given vectors and stores the result in this instance. 1374 * 1375 * @param {Vector2} a - The first vector. 1376 * @param {Vector2} b - The second vector. 1377 * @return {Vector2} A reference to this vector. 1378 */ subVectors(a, b) { 1379 this.x = a.x - b.x; 1380 this.y = a.y - b.y; 1381 return this; 1382 } 1383 /** 1384 * Multiplies the given vector with this instance. 1385 * 1386 * @param {Vector2} v - The vector to multiply. 1387 * @return {Vector2} A reference to this vector. 1388 */ multiply(v) { 1389 this.x *= v.x; 1390 this.y *= v.y; 1391 return this; 1392 } 1393 /** 1394 * Multiplies the given scalar value with all components of this instance. 1395 * 1396 * @param {number} scalar - The scalar to multiply. 1397 * @return {Vector2} A reference to this vector. 1398 */ multiplyScalar(scalar) { 1399 this.x *= scalar; 1400 this.y *= scalar; 1401 return this; 1402 } 1403 /** 1404 * Divides this instance by the given vector. 1405 * 1406 * @param {Vector2} v - The vector to divide. 1407 * @return {Vector2} A reference to this vector. 1408 */ divide(v) { 1409 this.x /= v.x; 1410 this.y /= v.y; 1411 return this; 1412 } 1413 /** 1414 * Divides this vector by the given scalar. 1415 * 1416 * @param {number} scalar - The scalar to divide. 1417 * @return {Vector2} A reference to this vector. 1418 */ divideScalar(scalar) { 1419 return this.multiplyScalar(1 / scalar); 1420 } 1421 /** 1422 * Multiplies this vector (with an implicit 1 as the 3rd component) by 1423 * the given 3x3 matrix. 1424 * 1425 * @param {Matrix3} m - The matrix to apply. 1426 * @return {Vector2} A reference to this vector. 1427 */ applyMatrix3(m) { 1428 const x = this.x, y = this.y; 1429 const e = m.elements; 1430 this.x = e[0] * x + e[3] * y + e[6]; 1431 this.y = e[1] * x + e[4] * y + e[7]; 1432 return this; 1433 } 1434 /** 1435 * If this vector's x or y value is greater than the given vector's x or y 1436 * value, replace that value with the corresponding min value. 1437 * 1438 * @param {Vector2} v - The vector. 1439 * @return {Vector2} A reference to this vector. 1440 */ min(v) { 1441 this.x = Math.min(this.x, v.x); 1442 this.y = Math.min(this.y, v.y); 1443 return this; 1444 } 1445 /** 1446 * If this vector's x or y value is less than the given vector's x or y 1447 * value, replace that value with the corresponding max value. 1448 * 1449 * @param {Vector2} v - The vector. 1450 * @return {Vector2} A reference to this vector. 1451 */ max(v) { 1452 this.x = Math.max(this.x, v.x); 1453 this.y = Math.max(this.y, v.y); 1454 return this; 1455 } 1456 /** 1457 * If this vector's x or y value is greater than the max vector's x or y 1458 * value, it is replaced by the corresponding value. 1459 * If this vector's x or y value is less than the min vector's x or y value, 1460 * it is replaced by the corresponding value. 1461 * 1462 * @param {Vector2} min - The minimum x and y values. 1463 * @param {Vector2} max - The maximum x and y values in the desired range. 1464 * @return {Vector2} A reference to this vector. 1465 */ clamp(min, max) { 1466 // assumes min < max, componentwise 1467 this.x = clamp$1(this.x, min.x, max.x); 1468 this.y = clamp$1(this.y, min.y, max.y); 1469 return this; 1470 } 1471 /** 1472 * If this vector's x or y values are greater than the max value, they are 1473 * replaced by the max value. 1474 * If this vector's x or y values are less than the min value, they are 1475 * replaced by the min value. 1476 * 1477 * @param {number} minVal - The minimum value the components will be clamped to. 1478 * @param {number} maxVal - The maximum value the components will be clamped to. 1479 * @return {Vector2} A reference to this vector. 1480 */ clampScalar(minVal, maxVal) { 1481 this.x = clamp$1(this.x, minVal, maxVal); 1482 this.y = clamp$1(this.y, minVal, maxVal); 1483 return this; 1484 } 1485 /** 1486 * If this vector's length is greater than the max value, it is replaced by 1487 * the max value. 1488 * If this vector's length is less than the min value, it is replaced by the 1489 * min value. 1490 * 1491 * @param {number} min - The minimum value the vector length will be clamped to. 1492 * @param {number} max - The maximum value the vector length will be clamped to. 1493 * @return {Vector2} A reference to this vector. 1494 */ clampLength(min, max) { 1495 const length = this.length(); 1496 return this.divideScalar(length || 1).multiplyScalar(clamp$1(length, min, max)); 1497 } 1498 /** 1499 * The components of this vector are rounded down to the nearest integer value. 1500 * 1501 * @return {Vector2} A reference to this vector. 1502 */ floor() { 1503 this.x = Math.floor(this.x); 1504 this.y = Math.floor(this.y); 1505 return this; 1506 } 1507 /** 1508 * The components of this vector are rounded up to the nearest integer value. 1509 * 1510 * @return {Vector2} A reference to this vector. 1511 */ ceil() { 1512 this.x = Math.ceil(this.x); 1513 this.y = Math.ceil(this.y); 1514 return this; 1515 } 1516 /** 1517 * The components of this vector are rounded to the nearest integer value 1518 * 1519 * @return {Vector2} A reference to this vector. 1520 */ round() { 1521 this.x = Math.round(this.x); 1522 this.y = Math.round(this.y); 1523 return this; 1524 } 1525 /** 1526 * The components of this vector are rounded towards zero (up if negative, 1527 * down if positive) to an integer value. 1528 * 1529 * @return {Vector2} A reference to this vector. 1530 */ roundToZero() { 1531 this.x = Math.trunc(this.x); 1532 this.y = Math.trunc(this.y); 1533 return this; 1534 } 1535 /** 1536 * Inverts this vector - i.e. sets x = -x and y = -y. 1537 * 1538 * @return {Vector2} A reference to this vector. 1539 */ negate() { 1540 this.x = -this.x; 1541 this.y = -this.y; 1542 return this; 1543 } 1544 /** 1545 * Calculates the dot product of the given vector with this instance. 1546 * 1547 * @param {Vector2} v - The vector to compute the dot product with. 1548 * @return {number} The result of the dot product. 1549 */ dot(v) { 1550 return this.x * v.x + this.y * v.y; 1551 } 1552 /** 1553 * Calculates the cross product of the given vector with this instance. 1554 * 1555 * @param {Vector2} v - The vector to compute the cross product with. 1556 * @return {number} The result of the cross product. 1557 */ cross(v) { 1558 return this.x * v.y - this.y * v.x; 1559 } 1560 /** 1561 * Computes the square of the Euclidean length (straight-line length) from 1562 * (0, 0) to (x, y). If you are comparing the lengths of vectors, you should 1563 * compare the length squared instead as it is slightly more efficient to calculate. 1564 * 1565 * @return {number} The square length of this vector. 1566 */ lengthSq() { 1567 return this.x * this.x + this.y * this.y; 1568 } 1569 /** 1570 * Computes the Euclidean length (straight-line length) from (0, 0) to (x, y). 1571 * 1572 * @return {number} The length of this vector. 1573 */ length() { 1574 return Math.sqrt(this.x * this.x + this.y * this.y); 1575 } 1576 /** 1577 * Computes the Manhattan length of this vector. 1578 * 1579 * @return {number} The length of this vector. 1580 */ manhattanLength() { 1581 return Math.abs(this.x) + Math.abs(this.y); 1582 } 1583 /** 1584 * Converts this vector to a unit vector - that is, sets it equal to a vector 1585 * with the same direction as this one, but with a vector length of `1`. 1586 * 1587 * @return {Vector2} A reference to this vector. 1588 */ normalize() { 1589 return this.divideScalar(this.length() || 1); 1590 } 1591 /** 1592 * Computes the angle in radians of this vector with respect to the positive x-axis. 1593 * 1594 * @return {number} The angle in radians. 1595 */ angle() { 1596 const angle = Math.atan2(-this.y, -this.x) + Math.PI; 1597 return angle; 1598 } 1599 /** 1600 * Returns the angle between the given vector and this instance in radians. 1601 * 1602 * @param {Vector2} v - The vector to compute the angle with. 1603 * @return {number} The angle in radians. 1604 */ angleTo(v) { 1605 const denominator = Math.sqrt(this.lengthSq() * v.lengthSq()); 1606 if (denominator === 0) return Math.PI / 2; 1607 const theta = this.dot(v) / denominator; 1608 // clamp, to handle numerical problems 1609 return Math.acos(clamp$1(theta, -1, 1)); 1610 } 1611 /** 1612 * Computes the distance from the given vector to this instance. 1613 * 1614 * @param {Vector2} v - The vector to compute the distance to. 1615 * @return {number} The distance. 1616 */ distanceTo(v) { 1617 return Math.sqrt(this.distanceToSquared(v)); 1618 } 1619 /** 1620 * Computes the squared distance from the given vector to this instance. 1621 * If you are just comparing the distance with another distance, you should compare 1622 * the distance squared instead as it is slightly more efficient to calculate. 1623 * 1624 * @param {Vector2} v - The vector to compute the squared distance to. 1625 * @return {number} The squared distance. 1626 */ distanceToSquared(v) { 1627 const dx = this.x - v.x, dy = this.y - v.y; 1628 return dx * dx + dy * dy; 1629 } 1630 /** 1631 * Computes the Manhattan distance from the given vector to this instance. 1632 * 1633 * @param {Vector2} v - The vector to compute the Manhattan distance to. 1634 * @return {number} The Manhattan distance. 1635 */ manhattanDistanceTo(v) { 1636 return Math.abs(this.x - v.x) + Math.abs(this.y - v.y); 1637 } 1638 /** 1639 * Sets this vector to a vector with the same direction as this one, but 1640 * with the specified length. 1641 * 1642 * @param {number} length - The new length of this vector. 1643 * @return {Vector2} A reference to this vector. 1644 */ setLength(length) { 1645 return this.normalize().multiplyScalar(length); 1646 } 1647 /** 1648 * Linearly interpolates between the given vector and this instance, where 1649 * alpha is the percent distance along the line - alpha = 0 will be this 1650 * vector, and alpha = 1 will be the given one. 1651 * 1652 * @param {Vector2} v - The vector to interpolate towards. 1653 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. 1654 * @return {Vector2} A reference to this vector. 1655 */ lerp(v, alpha) { 1656 this.x += (v.x - this.x) * alpha; 1657 this.y += (v.y - this.y) * alpha; 1658 return this; 1659 } 1660 /** 1661 * Linearly interpolates between the given vectors, where alpha is the percent 1662 * distance along the line - alpha = 0 will be first vector, and alpha = 1 will 1663 * be the second one. The result is stored in this instance. 1664 * 1665 * @param {Vector2} v1 - The first vector. 1666 * @param {Vector2} v2 - The second vector. 1667 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. 1668 * @return {Vector2} A reference to this vector. 1669 */ lerpVectors(v1, v2, alpha) { 1670 this.x = v1.x + (v2.x - v1.x) * alpha; 1671 this.y = v1.y + (v2.y - v1.y) * alpha; 1672 return this; 1673 } 1674 /** 1675 * Returns `true` if this vector is equal with the given one. 1676 * 1677 * @param {Vector2} v - The vector to test for equality. 1678 * @return {boolean} Whether this vector is equal with the given one. 1679 */ equals(v) { 1680 return v.x === this.x && v.y === this.y; 1681 } 1682 /** 1683 * Sets this vector's x value to be `array[ offset ]` and y 1684 * value to be `array[ offset + 1 ]`. 1685 * 1686 * @param {Array<number>} array - An array holding the vector component values. 1687 * @param {number} [offset=0] - The offset into the array. 1688 * @return {Vector2} A reference to this vector. 1689 */ fromArray(array, offset = 0) { 1690 this.x = array[offset]; 1691 this.y = array[offset + 1]; 1692 return this; 1693 } 1694 /** 1695 * Writes the components of this vector to the given array. If no array is provided, 1696 * the method returns a new instance. 1697 * 1698 * @param {Array<number>} [array=[]] - The target array holding the vector components. 1699 * @param {number} [offset=0] - Index of the first element in the array. 1700 * @return {Array<number>} The vector components. 1701 */ toArray(array = [], offset = 0) { 1702 array[offset] = this.x; 1703 array[offset + 1] = this.y; 1704 return array; 1705 } 1706 /** 1707 * Sets the components of this vector from the given buffer attribute. 1708 * 1709 * @param {BufferAttribute} attribute - The buffer attribute holding vector data. 1710 * @param {number} index - The index into the attribute. 1711 * @return {Vector2} A reference to this vector. 1712 */ fromBufferAttribute(attribute, index) { 1713 this.x = attribute.getX(index); 1714 this.y = attribute.getY(index); 1715 return this; 1716 } 1717 /** 1718 * Rotates this vector around the given center by the given angle. 1719 * 1720 * @param {Vector2} center - The point around which to rotate. 1721 * @param {number} angle - The angle to rotate, in radians. 1722 * @return {Vector2} A reference to this vector. 1723 */ rotateAround(center, angle) { 1724 const c = Math.cos(angle), s = Math.sin(angle); 1725 const x = this.x - center.x; 1726 const y = this.y - center.y; 1727 this.x = x * c - y * s + center.x; 1728 this.y = x * s + y * c + center.y; 1729 return this; 1730 } 1731 /** 1732 * Sets each component of this vector to a pseudo-random value between `0` and 1733 * `1`, excluding `1`. 1734 * 1735 * @return {Vector2} A reference to this vector. 1736 */ random() { 1737 this.x = Math.random(); 1738 this.y = Math.random(); 1739 return this; 1740 } 1741 *[Symbol.iterator]() { 1742 yield this.x; 1743 yield this.y; 1744 } 1745 /** 1746 * Constructs a new 2D vector. 1747 * 1748 * @param {number} [x=0] - The x value of this vector. 1749 * @param {number} [y=0] - The y value of this vector. 1750 */ constructor(x = 0, y = 0){ 1751 /** 1752 * This flag can be used for type testing. 1753 * 1754 * @type {boolean} 1755 * @readonly 1756 * @default true 1757 */ Vector2.prototype.isVector2 = true; 1758 /** 1759 * The x value of this vector. 1760 * 1761 * @type {number} 1762 */ this.x = x; 1763 /** 1764 * The y value of this vector. 1765 * 1766 * @type {number} 1767 */ this.y = y; 1768 } 1769 } 1770 /** 1771 * Represents a 3x3 matrix. 1772 * 1773 * A Note on Row-Major and Column-Major Ordering: 1774 * 1775 * The constructor and {@link Matrix3#set} method take arguments in 1776 * [row-major]{@link https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order} 1777 * order, while internally they are stored in the {@link Matrix3#elements} array in column-major order. 1778 * This means that calling: 1779 * ```js 1780 * const m = new THREE.Matrix(); 1781 * m.set( 11, 12, 13, 1782 * 21, 22, 23, 1783 * 31, 32, 33 ); 1784 * ``` 1785 * will result in the elements array containing: 1786 * ```js 1787 * m.elements = [ 11, 21, 31, 1788 * 12, 22, 32, 1789 * 13, 23, 33 ]; 1790 * ``` 1791 * and internally all calculations are performed using column-major ordering. 1792 * However, as the actual ordering makes no difference mathematically and 1793 * most people are used to thinking about matrices in row-major order, the 1794 * three.js documentation shows matrices in row-major order. Just bear in 1795 * mind that if you are reading the source code, you'll have to take the 1796 * transpose of any matrices outlined here to make sense of the calculations. 1797 */ class Matrix3 { 1798 /** 1799 * Sets the elements of the matrix.The arguments are supposed to be 1800 * in row-major order. 1801 * 1802 * @param {number} [n11] - 1-1 matrix element. 1803 * @param {number} [n12] - 1-2 matrix element. 1804 * @param {number} [n13] - 1-3 matrix element. 1805 * @param {number} [n21] - 2-1 matrix element. 1806 * @param {number} [n22] - 2-2 matrix element. 1807 * @param {number} [n23] - 2-3 matrix element. 1808 * @param {number} [n31] - 3-1 matrix element. 1809 * @param {number} [n32] - 3-2 matrix element. 1810 * @param {number} [n33] - 3-3 matrix element. 1811 * @return {Matrix3} A reference to this matrix. 1812 */ set(n11, n12, n13, n21, n22, n23, n31, n32, n33) { 1813 const te = this.elements; 1814 te[0] = n11; 1815 te[1] = n21; 1816 te[2] = n31; 1817 te[3] = n12; 1818 te[4] = n22; 1819 te[5] = n32; 1820 te[6] = n13; 1821 te[7] = n23; 1822 te[8] = n33; 1823 return this; 1824 } 1825 /** 1826 * Sets this matrix to the 3x3 identity matrix. 1827 * 1828 * @return {Matrix3} A reference to this matrix. 1829 */ identity() { 1830 this.set(1, 0, 0, 0, 1, 0, 0, 0, 1); 1831 return this; 1832 } 1833 /** 1834 * Copies the values of the given matrix to this instance. 1835 * 1836 * @param {Matrix3} m - The matrix to copy. 1837 * @return {Matrix3} A reference to this matrix. 1838 */ copy(m) { 1839 const te = this.elements; 1840 const me = m.elements; 1841 te[0] = me[0]; 1842 te[1] = me[1]; 1843 te[2] = me[2]; 1844 te[3] = me[3]; 1845 te[4] = me[4]; 1846 te[5] = me[5]; 1847 te[6] = me[6]; 1848 te[7] = me[7]; 1849 te[8] = me[8]; 1850 return this; 1851 } 1852 /** 1853 * Extracts the basis of this matrix into the three axis vectors provided. 1854 * 1855 * @param {Vector3} xAxis - The basis's x axis. 1856 * @param {Vector3} yAxis - The basis's y axis. 1857 * @param {Vector3} zAxis - The basis's z axis. 1858 * @return {Matrix3} A reference to this matrix. 1859 */ extractBasis(xAxis, yAxis, zAxis) { 1860 xAxis.setFromMatrix3Column(this, 0); 1861 yAxis.setFromMatrix3Column(this, 1); 1862 zAxis.setFromMatrix3Column(this, 2); 1863 return this; 1864 } 1865 /** 1866 * Set this matrix to the upper 3x3 matrix of the given 4x4 matrix. 1867 * 1868 * @param {Matrix4} m - The 4x4 matrix. 1869 * @return {Matrix3} A reference to this matrix. 1870 */ setFromMatrix4(m) { 1871 const me = m.elements; 1872 this.set(me[0], me[4], me[8], me[1], me[5], me[9], me[2], me[6], me[10]); 1873 return this; 1874 } 1875 /** 1876 * Post-multiplies this matrix by the given 3x3 matrix. 1877 * 1878 * @param {Matrix3} m - The matrix to multiply with. 1879 * @return {Matrix3} A reference to this matrix. 1880 */ multiply(m) { 1881 return this.multiplyMatrices(this, m); 1882 } 1883 /** 1884 * Pre-multiplies this matrix by the given 3x3 matrix. 1885 * 1886 * @param {Matrix3} m - The matrix to multiply with. 1887 * @return {Matrix3} A reference to this matrix. 1888 */ premultiply(m) { 1889 return this.multiplyMatrices(m, this); 1890 } 1891 /** 1892 * Multiples the given 3x3 matrices and stores the result 1893 * in this matrix. 1894 * 1895 * @param {Matrix3} a - The first matrix. 1896 * @param {Matrix3} b - The second matrix. 1897 * @return {Matrix3} A reference to this matrix. 1898 */ multiplyMatrices(a, b) { 1899 const ae = a.elements; 1900 const be = b.elements; 1901 const te = this.elements; 1902 const a11 = ae[0], a12 = ae[3], a13 = ae[6]; 1903 const a21 = ae[1], a22 = ae[4], a23 = ae[7]; 1904 const a31 = ae[2], a32 = ae[5], a33 = ae[8]; 1905 const b11 = be[0], b12 = be[3], b13 = be[6]; 1906 const b21 = be[1], b22 = be[4], b23 = be[7]; 1907 const b31 = be[2], b32 = be[5], b33 = be[8]; 1908 te[0] = a11 * b11 + a12 * b21 + a13 * b31; 1909 te[3] = a11 * b12 + a12 * b22 + a13 * b32; 1910 te[6] = a11 * b13 + a12 * b23 + a13 * b33; 1911 te[1] = a21 * b11 + a22 * b21 + a23 * b31; 1912 te[4] = a21 * b12 + a22 * b22 + a23 * b32; 1913 te[7] = a21 * b13 + a22 * b23 + a23 * b33; 1914 te[2] = a31 * b11 + a32 * b21 + a33 * b31; 1915 te[5] = a31 * b12 + a32 * b22 + a33 * b32; 1916 te[8] = a31 * b13 + a32 * b23 + a33 * b33; 1917 return this; 1918 } 1919 /** 1920 * Multiplies every component of the matrix by the given scalar. 1921 * 1922 * @param {number} s - The scalar. 1923 * @return {Matrix3} A reference to this matrix. 1924 */ multiplyScalar(s) { 1925 const te = this.elements; 1926 te[0] *= s; 1927 te[3] *= s; 1928 te[6] *= s; 1929 te[1] *= s; 1930 te[4] *= s; 1931 te[7] *= s; 1932 te[2] *= s; 1933 te[5] *= s; 1934 te[8] *= s; 1935 return this; 1936 } 1937 /** 1938 * Computes and returns the determinant of this matrix. 1939 * 1940 * @return {number} The determinant. 1941 */ determinant() { 1942 const te = this.elements; 1943 const a = te[0], b = te[1], c = te[2], d = te[3], e = te[4], f = te[5], g = te[6], h = te[7], i = te[8]; 1944 return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g; 1945 } 1946 /** 1947 * Inverts this matrix, using the [analytic method]{@link https://en.wikipedia.org/wiki/Invertible_matrix#Analytic_solution}. 1948 * You can not invert with a determinant of zero. If you attempt this, the method produces 1949 * a zero matrix instead. 1950 * 1951 * @return {Matrix3} A reference to this matrix. 1952 */ invert() { 1953 const te = this.elements, n11 = te[0], n21 = te[1], n31 = te[2], n12 = te[3], n22 = te[4], n32 = te[5], n13 = te[6], n23 = te[7], n33 = te[8], t11 = n33 * n22 - n32 * n23, t12 = n32 * n13 - n33 * n12, t13 = n23 * n12 - n22 * n13, det = n11 * t11 + n21 * t12 + n31 * t13; 1954 if (det === 0) return this.set(0, 0, 0, 0, 0, 0, 0, 0, 0); 1955 const detInv = 1 / det; 1956 te[0] = t11 * detInv; 1957 te[1] = (n31 * n23 - n33 * n21) * detInv; 1958 te[2] = (n32 * n21 - n31 * n22) * detInv; 1959 te[3] = t12 * detInv; 1960 te[4] = (n33 * n11 - n31 * n13) * detInv; 1961 te[5] = (n31 * n12 - n32 * n11) * detInv; 1962 te[6] = t13 * detInv; 1963 te[7] = (n21 * n13 - n23 * n11) * detInv; 1964 te[8] = (n22 * n11 - n21 * n12) * detInv; 1965 return this; 1966 } 1967 /** 1968 * Transposes this matrix in place. 1969 * 1970 * @return {Matrix3} A reference to this matrix. 1971 */ transpose() { 1972 let tmp; 1973 const m = this.elements; 1974 tmp = m[1]; 1975 m[1] = m[3]; 1976 m[3] = tmp; 1977 tmp = m[2]; 1978 m[2] = m[6]; 1979 m[6] = tmp; 1980 tmp = m[5]; 1981 m[5] = m[7]; 1982 m[7] = tmp; 1983 return this; 1984 } 1985 /** 1986 * Computes the normal matrix which is the inverse transpose of the upper 1987 * left 3x3 portion of the given 4x4 matrix. 1988 * 1989 * @param {Matrix4} matrix4 - The 4x4 matrix. 1990 * @return {Matrix3} A reference to this matrix. 1991 */ getNormalMatrix(matrix4) { 1992 return this.setFromMatrix4(matrix4).invert().transpose(); 1993 } 1994 /** 1995 * Transposes this matrix into the supplied array, and returns itself unchanged. 1996 * 1997 * @param {Array<number>} r - An array to store the transposed matrix elements. 1998 * @return {Matrix3} A reference to this matrix. 1999 */ transposeIntoArray(r) { 2000 const m = this.elements; 2001 r[0] = m[0]; 2002 r[1] = m[3]; 2003 r[2] = m[6]; 2004 r[3] = m[1]; 2005 r[4] = m[4]; 2006 r[5] = m[7]; 2007 r[6] = m[2]; 2008 r[7] = m[5]; 2009 r[8] = m[8]; 2010 return this; 2011 } 2012 /** 2013 * Sets the UV transform matrix from offset, repeat, rotation, and center. 2014 * 2015 * @param {number} tx - Offset x. 2016 * @param {number} ty - Offset y. 2017 * @param {number} sx - Repeat x. 2018 * @param {number} sy - Repeat y. 2019 * @param {number} rotation - Rotation, in radians. Positive values rotate counterclockwise. 2020 * @param {number} cx - Center x of rotation. 2021 * @param {number} cy - Center y of rotation 2022 * @return {Matrix3} A reference to this matrix. 2023 */ setUvTransform(tx, ty, sx, sy, rotation, cx, cy) { 2024 const c = Math.cos(rotation); 2025 const s = Math.sin(rotation); 2026 this.set(sx * c, sx * s, -sx * (c * cx + s * cy) + cx + tx, -sy * s, sy * c, -sy * (-s * cx + c * cy) + cy + ty, 0, 0, 1); 2027 return this; 2028 } 2029 /** 2030 * Scales this matrix with the given scalar values. 2031 * 2032 * @param {number} sx - The amount to scale in the X axis. 2033 * @param {number} sy - The amount to scale in the Y axis. 2034 * @return {Matrix3} A reference to this matrix. 2035 */ scale(sx, sy) { 2036 this.premultiply(_m3.makeScale(sx, sy)); 2037 return this; 2038 } 2039 /** 2040 * Rotates this matrix by the given angle. 2041 * 2042 * @param {number} theta - The rotation in radians. 2043 * @return {Matrix3} A reference to this matrix. 2044 */ rotate(theta) { 2045 this.premultiply(_m3.makeRotation(-theta)); 2046 return this; 2047 } 2048 /** 2049 * Translates this matrix by the given scalar values. 2050 * 2051 * @param {number} tx - The amount to translate in the X axis. 2052 * @param {number} ty - The amount to translate in the Y axis. 2053 * @return {Matrix3} A reference to this matrix. 2054 */ translate(tx, ty) { 2055 this.premultiply(_m3.makeTranslation(tx, ty)); 2056 return this; 2057 } 2058 // for 2D Transforms 2059 /** 2060 * Sets this matrix as a 2D translation transform. 2061 * 2062 * @param {number|Vector2} x - The amount to translate in the X axis or alternatively a translation vector. 2063 * @param {number} y - The amount to translate in the Y axis. 2064 * @return {Matrix3} A reference to this matrix. 2065 */ makeTranslation(x, y) { 2066 if (x.isVector2) { 2067 this.set(1, 0, x.x, 0, 1, x.y, 0, 0, 1); 2068 } else { 2069 this.set(1, 0, x, 0, 1, y, 0, 0, 1); 2070 } 2071 return this; 2072 } 2073 /** 2074 * Sets this matrix as a 2D rotational transformation. 2075 * 2076 * @param {number} theta - The rotation in radians. 2077 * @return {Matrix3} A reference to this matrix. 2078 */ makeRotation(theta) { 2079 // counterclockwise 2080 const c = Math.cos(theta); 2081 const s = Math.sin(theta); 2082 this.set(c, -s, 0, s, c, 0, 0, 0, 1); 2083 return this; 2084 } 2085 /** 2086 * Sets this matrix as a 2D scale transform. 2087 * 2088 * @param {number} x - The amount to scale in the X axis. 2089 * @param {number} y - The amount to scale in the Y axis. 2090 * @return {Matrix3} A reference to this matrix. 2091 */ makeScale(x, y) { 2092 this.set(x, 0, 0, 0, y, 0, 0, 0, 1); 2093 return this; 2094 } 2095 /** 2096 * Returns `true` if this matrix is equal with the given one. 2097 * 2098 * @param {Matrix3} matrix - The matrix to test for equality. 2099 * @return {boolean} Whether this matrix is equal with the given one. 2100 */ equals(matrix) { 2101 const te = this.elements; 2102 const me = matrix.elements; 2103 for(let i = 0; i < 9; i++){ 2104 if (te[i] !== me[i]) return false; 2105 } 2106 return true; 2107 } 2108 /** 2109 * Sets the elements of the matrix from the given array. 2110 * 2111 * @param {Array<number>} array - The matrix elements in column-major order. 2112 * @param {number} [offset=0] - Index of the first element in the array. 2113 * @return {Matrix3} A reference to this matrix. 2114 */ fromArray(array, offset = 0) { 2115 for(let i = 0; i < 9; i++){ 2116 this.elements[i] = array[i + offset]; 2117 } 2118 return this; 2119 } 2120 /** 2121 * Writes the elements of this matrix to the given array. If no array is provided, 2122 * the method returns a new instance. 2123 * 2124 * @param {Array<number>} [array=[]] - The target array holding the matrix elements in column-major order. 2125 * @param {number} [offset=0] - Index of the first element in the array. 2126 * @return {Array<number>} The matrix elements in column-major order. 2127 */ toArray(array = [], offset = 0) { 2128 const te = this.elements; 2129 array[offset] = te[0]; 2130 array[offset + 1] = te[1]; 2131 array[offset + 2] = te[2]; 2132 array[offset + 3] = te[3]; 2133 array[offset + 4] = te[4]; 2134 array[offset + 5] = te[5]; 2135 array[offset + 6] = te[6]; 2136 array[offset + 7] = te[7]; 2137 array[offset + 8] = te[8]; 2138 return array; 2139 } 2140 /** 2141 * Returns a matrix with copied values from this instance. 2142 * 2143 * @return {Matrix3} A clone of this instance. 2144 */ clone() { 2145 return new this.constructor().fromArray(this.elements); 2146 } 2147 /** 2148 * Constructs a new 3x3 matrix. The arguments are supposed to be 2149 * in row-major order. If no arguments are provided, the constructor 2150 * initializes the matrix as an identity matrix. 2151 * 2152 * @param {number} [n11] - 1-1 matrix element. 2153 * @param {number} [n12] - 1-2 matrix element. 2154 * @param {number} [n13] - 1-3 matrix element. 2155 * @param {number} [n21] - 2-1 matrix element. 2156 * @param {number} [n22] - 2-2 matrix element. 2157 * @param {number} [n23] - 2-3 matrix element. 2158 * @param {number} [n31] - 3-1 matrix element. 2159 * @param {number} [n32] - 3-2 matrix element. 2160 * @param {number} [n33] - 3-3 matrix element. 2161 */ constructor(n11, n12, n13, n21, n22, n23, n31, n32, n33){ 2162 /** 2163 * This flag can be used for type testing. 2164 * 2165 * @type {boolean} 2166 * @readonly 2167 * @default true 2168 */ Matrix3.prototype.isMatrix3 = true; 2169 /** 2170 * A column-major list of matrix values. 2171 * 2172 * @type {Array<number>} 2173 */ this.elements = [ 2174 1, 2175 0, 2176 0, 2177 0, 2178 1, 2179 0, 2180 0, 2181 0, 2182 1 2183 ]; 2184 if (n11 !== undefined) { 2185 this.set(n11, n12, n13, n21, n22, n23, n31, n32, n33); 2186 } 2187 } 2188 } 2189 const _m3 = /*@__PURE__*/ new Matrix3(); 2190 function arrayNeedsUint32(array) { 2191 // assumes larger values usually on last
2192 for(let i = array.length - 1; i >= 0; --i){ 2193 if (array[i] >= 65535) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565 2194 } 2195 return false; 2196 } 2197 function createElementNS(name) { 2198 return document.createElementNS('http://www.w3.org/1999/xhtml', name); 2199 } 2200 function createCanvasElement() { 2201 const canvas = createElementNS('canvas'); 2202 canvas.style.display = 'block'; 2203 return canvas; 2204 } 2205 const _cache = {}; 2206 function warnOnce(message) { 2207 if (message in _cache) return; 2208 _cache[message] = true; 2209 console.warn(message); 2210 } 2211 function probeAsync(gl, sync, interval) { 2212 return new Promise(function(resolve, reject) { 2213 function probe() { 2214 switch(gl.clientWaitSync(sync, gl.SYNC_FLUSH_COMMANDS_BIT, 0)){ 2215 case gl.WAIT_FAILED: 2216 reject(); 2217 break; 2218 case gl.TIMEOUT_EXPIRED: 2219 setTimeout(probe, interval); 2220 break; 2221 default: 2222 resolve(); 2223 } 2224 } 2225 setTimeout(probe, interval); 2226 }); 2227 } 2228 function toNormalizedProjectionMatrix(projectionMatrix) { 2229 const m = projectionMatrix.elements; 2230 // Convert [-1, 1] to [0, 1] projection matrix 2231 m[2] = 0.5 * m[2] + 0.5 * m[3]; 2232 m[6] = 0.5 * m[6] + 0.5 * m[7]; 2233 m[10] = 0.5 * m[10] + 0.5 * m[11]; 2234 m[14] = 0.5 * m[14] + 0.5 * m[15]; 2235 } 2236 function toReversedProjectionMatrix(projectionMatrix) { 2237 const m = projectionMatrix.elements; 2238 const isPerspectiveMatrix = m[11] === -1; 2239 // Reverse [0, 1] projection matrix 2240 if (isPerspectiveMatrix) { 2241 m[10] = -m[10] - 1; 2242 m[14] = -m[14]; 2243 } else { 2244 m[10] = -m[10]; 2245 m[14] = -m[14] + 1; 2246 } 2247 } 2248 const LINEAR_REC709_TO_XYZ = /*@__PURE__*/ new Matrix3().set(0.4123908, 0.3575843, 0.1804808, 0.2126390, 0.7151687, 0.0721923, 0.0193308, 0.1191948, 0.9505322); 2249 const XYZ_TO_LINEAR_REC709 = /*@__PURE__*/ new Matrix3().set(3.2409699, -1.5373832, -0.4986108, -0.9692436, 1.8759675, 0.0415551, 0.0556301, -0.203977, 1.0569715); 2250 function createColorManagement() { 2251 const ColorManagement = { 2252 enabled: true, 2253 workingColorSpace: LinearSRGBColorSpace, 2254 /** 2255 * Implementations of supported color spaces. 2256 * 2257 * Required: 2258 * - primaries: chromaticity coordinates [ rx ry gx gy bx by ] 2259 * - whitePoint: reference white [ x y ] 2260 * - transfer: transfer function (pre-defined) 2261 * - toXYZ: Matrix3 RGB to XYZ transform 2262 * - fromXYZ: Matrix3 XYZ to RGB transform 2263 * - luminanceCoefficients: RGB luminance coefficients 2264 * 2265 * Optional: 2266 * - outputColorSpaceConfig: { drawingBufferColorSpace: ColorSpace } 2267 * - workingColorSpaceConfig: { unpackColorSpace: ColorSpace } 2268 * 2269 * Reference: 2270 * - https://www.russellcottrell.com/photo/matrixCalculator.htm 2271 */ spaces: {}, 2272 convert: function(color, sourceColorSpace, targetColorSpace) { 2273 if (this.enabled === false || sourceColorSpace === targetColorSpace || !sourceColorSpace || !targetColorSpace) { 2274 return color; 2275 } 2276 if (this.spaces[sourceColorSpace].transfer === SRGBTransfer) { 2277 color.r = SRGBToLinear(color.r); 2278 color.g = SRGBToLinear(color.g); 2279 color.b = SRGBToLinear(color.b); 2280 } 2281 if (this.spaces[sourceColorSpace].primaries !== this.spaces[targetColorSpace].primaries) { 2282 color.applyMatrix3(this.spaces[sourceColorSpace].toXYZ); 2283 color.applyMatrix3(this.spaces[targetColorSpace].fromXYZ); 2284 } 2285 if (this.spaces[targetColorSpace].transfer === SRGBTransfer) { 2286 color.r = LinearToSRGB(color.r); 2287 color.g = LinearToSRGB(color.g); 2288 color.b = LinearToSRGB(color.b); 2289 } 2290 return color; 2291 }, 2292 fromWorkingColorSpace: function(color, targetColorSpace) { 2293 return this.convert(color, this.workingColorSpace, targetColorSpace); 2294 }, 2295 toWorkingColorSpace: function(color, sourceColorSpace) { 2296 return this.convert(color, sourceColorSpace, this.workingColorSpace); 2297 }, 2298 getPrimaries: function(colorSpace) { 2299 return this.spaces[colorSpace].primaries; 2300 }, 2301 getTransfer: function(colorSpace) { 2302 if (colorSpace === NoColorSpace) return LinearTransfer; 2303 return this.spaces[colorSpace].transfer; 2304 }, 2305 getLuminanceCoefficients: function(target, colorSpace = this.workingColorSpace) { 2306 return target.fromArray(this.spaces[colorSpace].luminanceCoefficients); 2307 }, 2308 define: function(colorSpaces) { 2309 Object.assign(this.spaces, colorSpaces); 2310 }, 2311 // Internal APIs 2312 _getMatrix: function(targetMatrix, sourceColorSpace, targetColorSpace) { 2313 return targetMatrix.copy(this.spaces[sourceColorSpace].toXYZ).multiply(this.spaces[targetColorSpace].fromXYZ); 2314 }, 2315 _getDrawingBufferColorSpace: function(colorSpace) { 2316 return this.spaces[colorSpace].outputColorSpaceConfig.drawingBufferColorSpace; 2317 }, 2318 _getUnpackColorSpace: function(colorSpace = this.workingColorSpace) { 2319 return this.spaces[colorSpace].workingColorSpaceConfig.unpackColorSpace; 2320 } 2321 }; 2322 /****************************************************************************** 2323 * sRGB definitions 2324 */ const REC709_PRIMARIES = [ 2325 0.640, 2326 0.330, 2327 0.300, 2328 0.600, 2329 0.150, 2330 0.060 2331 ]; 2332 const REC709_LUMINANCE_COEFFICIENTS = [ 2333 0.2126, 2334 0.7152, 2335 0.0722 2336 ]; 2337 const D65 = [ 2338 0.3127, 2339 0.3290 2340 ]; 2341 ColorManagement.define({ 2342 [LinearSRGBColorSpace]: { 2343 primaries: REC709_PRIMARIES,
vendor: 16,707 bytes, lines 2344-2802
2344 whitePoint: D65, 2345 transfer: LinearTransfer, 2346 toXYZ: LINEAR_REC709_TO_XYZ, 2347 fromXYZ: XYZ_TO_LINEAR_REC709, 2348 luminanceCoefficients: REC709_LUMINANCE_COEFFICIENTS, 2349 workingColorSpaceConfig: { 2350 unpackColorSpace: SRGBColorSpace 2351 }, 2352 outputColorSpaceConfig: { 2353 drawingBufferColorSpace: SRGBColorSpace 2354 } 2355 }, 2356 [SRGBColorSpace]: { 2357 primaries: REC709_PRIMARIES, 2358 whitePoint: D65, 2359 transfer: SRGBTransfer, 2360 toXYZ: LINEAR_REC709_TO_XYZ, 2361 fromXYZ: XYZ_TO_LINEAR_REC709, 2362 luminanceCoefficients: REC709_LUMINANCE_COEFFICIENTS, 2363 outputColorSpaceConfig: { 2364 drawingBufferColorSpace: SRGBColorSpace 2365 } 2366 } 2367 }); 2368 return ColorManagement; 2369 } 2370 const ColorManagement = /*@__PURE__*/ createColorManagement(); 2371 function SRGBToLinear(c) { 2372 return c < 0.04045 ? c * 0.0773993808 : Math.pow(c * 0.9478672986 + 0.0521327014, 2.4); 2373 } 2374 function LinearToSRGB(c) { 2375 return c < 0.0031308 ? c * 12.92 : 1.055 * Math.pow(c, 0.41666) - 0.055; 2376 } 2377 let _canvas; 2378 /** 2379 * A class containing utility functions for images. 2380 * 2381 * @hideconstructor 2382 */ class ImageUtils { 2383 /** 2384 * Returns a data URI containing a representation of the given image. 2385 * 2386 * @param {(HTMLImageElement|HTMLCanvasElement)} image - The image object. 2387 * @return {string} The data URI. 2388 */ static getDataURL(image) { 2389 if (/^data:/i.test(image.src)) { 2390 return image.src; 2391 } 2392 if (typeof HTMLCanvasElement === 'undefined') { 2393 return image.src; 2394 } 2395 let canvas; 2396 if (image instanceof HTMLCanvasElement) { 2397 canvas = image; 2398 } else { 2399 if (_canvas === undefined) _canvas = createElementNS('canvas'); 2400 _canvas.width = image.width; 2401 _canvas.height = image.height; 2402 const context = _canvas.getContext('2d'); 2403 if (image instanceof ImageData) { 2404 context.putImageData(image, 0, 0); 2405 } else { 2406 context.drawImage(image, 0, 0, image.width, image.height); 2407 } 2408 canvas = _canvas; 2409 } 2410 return canvas.toDataURL('image/png'); 2411 } 2412 /** 2413 * Converts the given sRGB image data to linear color space. 2414 * 2415 * @param {(HTMLImageElement|HTMLCanvasElement|ImageBitmap|Object)} image - The image object. 2416 * @return {HTMLCanvasElement|Object} The converted image. 2417 */ static sRGBToLinear(image) { 2418 if (typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement || typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement || typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap) { 2419 const canvas = createElementNS('canvas'); 2420 canvas.width = image.width; 2421 canvas.height = image.height; 2422 const context = canvas.getContext('2d'); 2423 context.drawImage(image, 0, 0, image.width, image.height); 2424 const imageData = context.getImageData(0, 0, image.width, image.height); 2425 const data = imageData.data; 2426 for(let i = 0; i < data.length; i++){ 2427 data[i] = SRGBToLinear(data[i] / 255) * 255; 2428 } 2429 context.putImageData(imageData, 0, 0); 2430 return canvas; 2431 } else if (image.data) { 2432 const data = image.data.slice(0); 2433 for(let i = 0; i < data.length; i++){ 2434 if (data instanceof Uint8Array || data instanceof Uint8ClampedArray) { 2435 data[i] = Math.floor(SRGBToLinear(data[i] / 255) * 255); 2436 } else { 2437 // assuming float 2438 data[i] = SRGBToLinear(data[i]); 2439 } 2440 } 2441 return { 2442 data: data, 2443 width: image.width, 2444 height: image.height 2445 }; 2446 } else { 2447 console.warn('THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.'); 2448 return image; 2449 } 2450 } 2451 } 2452 let _sourceId = 0; 2453 class Source { 2454 set needsUpdate(value) { 2455 if (value === true) this.version++; 2456 } 2457 toJSON(meta) { 2458 const isRootObject = meta === undefined || typeof meta === 'string'; 2459 if (!isRootObject && meta.images[this.uuid] !== undefined) { 2460 return meta.images[this.uuid]; 2461 } 2462 const output = { 2463 uuid: this.uuid, 2464 url: '' 2465 }; 2466 const data = this.data; 2467 if (data !== null) { 2468 let url; 2469 if (Array.isArray(data)) { 2470 // cube texture 2471 url = []; 2472 for(let i = 0, l = data.length; i < l; i++){ 2473 if (data[i].isDataTexture) { 2474 url.push(serializeImage(data[i].image)); 2475 } else { 2476 url.push(serializeImage(data[i])); 2477 } 2478 } 2479 } else { 2480 // texture 2481 url = serializeImage(data); 2482 } 2483 output.url = url; 2484 } 2485 if (!isRootObject) { 2486 meta.images[this.uuid] = output; 2487 } 2488 return output; 2489 } 2490 constructor(data = null){ 2491 this.isSource = true; 2492 Object.defineProperty(this, 'id', { 2493 value: _sourceId++ 2494 }); 2495 this.uuid = generateUUID(); 2496 this.data = data; 2497 this.dataReady = true; 2498 this.version = 0; 2499 } 2500 } 2501 function serializeImage(image) { 2502 if (typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement || typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement || typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap) { 2503 // default images 2504 return ImageUtils.getDataURL(image); 2505 } else { 2506 if (image.data) { 2507 // images of DataTexture 2508 return { 2509 data: Array.from(image.data), 2510 width: image.width, 2511 height: image.height, 2512 type: image.data.constructor.name 2513 }; 2514 } else { 2515 console.warn('THREE.Texture: Unable to serialize Texture.'); 2516 return {}; 2517 } 2518 } 2519 } 2520 let _textureId = 0; 2521 /** 2522 * Base class for all textures. 2523 * 2524 * Note: After the initial use of a texture, its dimensions, format, and type 2525 * cannot be changed. Instead, call {@link Texture#dispose} on the texture and instantiate a new one. 2526 * 2527 * @augments EventDispatcher 2528 */ let Texture$1 = class Texture extends EventDispatcher { 2529 /** 2530 * The image object holding the texture data. 2531 * 2532 * @type {?Object} 2533 */ get image() { 2534 return this.source.data; 2535 } 2536 set image(value = null) { 2537 this.source.data = value; 2538 } 2539 /** 2540 * Updates the texture transformation matrix from the from the properties {@link Texture#offset}, 2541 * {@link Texture#repeat}, {@link Texture#rotation}, and {@link Texture#center}. 2542 */ updateMatrix() { 2543 this.matrix.setUvTransform(this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y); 2544 } 2545 /** 2546 * Returns a new texture with copied values from this instance. 2547 * 2548 * @return {Texture} A clone of this instance. 2549 */ clone() { 2550 return new this.constructor().copy(this); 2551 } 2552 /** 2553 * Copies the values of the given texture to this instance. 2554 * 2555 * @param {Texture} source - The texture to copy. 2556 * @return {Texture} A reference to this instance. 2557 */ copy(source) { 2558 this.name = source.name; 2559 this.source = source.source; 2560 this.mipmaps = source.mipmaps.slice(0); 2561 this.mapping = source.mapping; 2562 this.channel = source.channel; 2563 this.wrapS = source.wrapS; 2564 this.wrapT = source.wrapT; 2565 this.magFilter = source.magFilter; 2566 this.minFilter = source.minFilter; 2567 this.anisotropy = source.anisotropy; 2568 this.format = source.format; 2569 this.internalFormat = source.internalFormat; 2570 this.type = source.type; 2571 this.offset.copy(source.offset); 2572 this.repeat.copy(source.repeat); 2573 this.center.copy(source.center); 2574 this.rotation = source.rotation; 2575 this.matrixAutoUpdate = source.matrixAutoUpdate; 2576 this.matrix.copy(source.matrix); 2577 this.generateMipmaps = source.generateMipmaps; 2578 this.premultiplyAlpha = source.premultiplyAlpha; 2579 this.flipY = source.flipY; 2580 this.unpackAlignment = source.unpackAlignment; 2581 this.colorSpace = source.colorSpace; 2582 this.renderTarget = source.renderTarget; 2583 this.isRenderTargetTexture = source.isRenderTargetTexture; 2584 this.userData = JSON.parse(JSON.stringify(source.userData)); 2585 this.needsUpdate = true; 2586 return this; 2587 } 2588 /** 2589 * Serializes the texture into JSON. 2590 * 2591 * @param {?(Object|string)} meta - An optional value holding meta information about the serialization. 2592 * @return {Object} A JSON object representing the serialized texture. 2593 * @see {@link ObjectLoader#parse} 2594 */ toJSON(meta) { 2595 const isRootObject = meta === undefined || typeof meta === 'string'; 2596 if (!isRootObject && meta.textures[this.uuid] !== undefined) { 2597 return meta.textures[this.uuid]; 2598 } 2599 const output = { 2600 metadata: { 2601 version: 4.6, 2602 type: 'Texture', 2603 generator: 'Texture.toJSON' 2604 }, 2605 uuid: this.uuid, 2606 name: this.name, 2607 image: this.source.toJSON(meta).uuid, 2608 mapping: this.mapping, 2609 channel: this.channel, 2610 repeat: [ 2611 this.repeat.x, 2612 this.repeat.y 2613 ], 2614 offset: [ 2615 this.offset.x, 2616 this.offset.y 2617 ], 2618 center: [ 2619 this.center.x, 2620 this.center.y 2621 ], 2622 rotation: this.rotation, 2623 wrap: [ 2624 this.wrapS, 2625 this.wrapT 2626 ], 2627 format: this.format, 2628 internalFormat: this.internalFormat, 2629 type: this.type, 2630 colorSpace: this.colorSpace, 2631 minFilter: this.minFilter, 2632 magFilter: this.magFilter, 2633 anisotropy: this.anisotropy, 2634 flipY: this.flipY, 2635 generateMipmaps: this.generateMipmaps, 2636 premultiplyAlpha: this.premultiplyAlpha, 2637 unpackAlignment: this.unpackAlignment 2638 }; 2639 if (Object.keys(this.userData).length > 0) output.userData = this.userData; 2640 if (!isRootObject) { 2641 meta.textures[this.uuid] = output; 2642 } 2643 return output; 2644 } 2645 /** 2646 * Frees the GPU-related resources allocated by this instance. Call this 2647 * method whenever this instance is no longer used in your app. 2648 * 2649 * @fires Texture#dispose 2650 */ dispose() { 2651 /** 2652 * Fires when the texture has been disposed of. 2653 * 2654 * @event Texture#dispose 2655 * @type {Object} 2656 */ this.dispatchEvent({ 2657 type: 'dispose' 2658 }); 2659 } 2660 /** 2661 * Transforms the given uv vector with the textures uv transformation matrix. 2662 * 2663 * @param {Vector2} uv - The uv vector. 2664 * @return {Vector2} The transformed uv vector. 2665 */ transformUv(uv) { 2666 if (this.mapping !== UVMapping) return uv; 2667 uv.applyMatrix3(this.matrix); 2668 if (uv.x < 0 || uv.x > 1) { 2669 switch(this.wrapS){ 2670 case RepeatWrapping: 2671 uv.x = uv.x - Math.floor(uv.x); 2672 break; 2673 case ClampToEdgeWrapping: 2674 uv.x = uv.x < 0 ? 0 : 1; 2675 break; 2676 case MirroredRepeatWrapping: 2677 if (Math.abs(Math.floor(uv.x) % 2) === 1) { 2678 uv.x = Math.ceil(uv.x) - uv.x; 2679 } else { 2680 uv.x = uv.x - Math.floor(uv.x); 2681 } 2682 break; 2683 } 2684 } 2685 if (uv.y < 0 || uv.y > 1) { 2686 switch(this.wrapT){ 2687 case RepeatWrapping: 2688 uv.y = uv.y - Math.floor(uv.y); 2689 break; 2690 case ClampToEdgeWrapping: 2691 uv.y = uv.y < 0 ? 0 : 1; 2692 break; 2693 case MirroredRepeatWrapping: 2694 if (Math.abs(Math.floor(uv.y) % 2) === 1) { 2695 uv.y = Math.ceil(uv.y) - uv.y; 2696 } else { 2697 uv.y = uv.y - Math.floor(uv.y); 2698 } 2699 break; 2700 } 2701 } 2702 if (this.flipY) { 2703 uv.y = 1 - uv.y; 2704 } 2705 return uv; 2706 } 2707 /** 2708 * Setting this property to `true` indicates the engine the texture 2709 * must be updated in the next render. This triggers a texture upload 2710 * to the GPU and ensures correct texture parameter configuration. 2711 * 2712 * @type {boolean} 2713 * @default false 2714 * @param {boolean} value 2715 */ set needsUpdate(value) { 2716 if (value === true) { 2717 this.version++; 2718 this.source.needsUpdate = true; 2719 } 2720 } 2721 /** 2722 * Setting this property to `true` indicates the engine the PMREM 2723 * must be regenerated. 2724 * 2725 * @type {boolean} 2726 * @default false 2727 * @param {boolean} value 2728 */ set needsPMREMUpdate(value) { 2729 if (value === true) { 2730 this.pmremVersion++; 2731 } 2732 } 2733 /** 2734 * Constructs a new texture. 2735 * 2736 * @param {?Object} [image=Texture.DEFAULT_IMAGE] - The image holding the texture data. 2737 * @param {number} [mapping=Texture.DEFAULT_MAPPING] - The texture mapping. 2738 * @param {number} [wrapS=ClampToEdgeWrapping] - The wrapS value. 2739 * @param {number} [wrapT=ClampToEdgeWrapping] - The wrapT value. 2740 * @param {number} [magFilter=LinearFilter] - The mag filter value. 2741 * @param {number} [minFilter=LinearFilter] - The min filter value. 2742 * @param {number} [format=RGBAFormat] - The min filter value. 2743 * @param {number} [type=UnsignedByteType] - The min filter value. 2744 * @param {number} [anisotropy=Texture.DEFAULT_ANISOTROPY] - The min filter value. 2745 * @param {string} [colorSpace=NoColorSpace] - The min filter value. 2746 */ 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){ 2747 super(); 2748 /** 2749 * This flag can be used for type testing. 2750 * 2751 * @type {boolean} 2752 * @readonly 2753 * @default true 2754 */ this.isTexture = true; 2755 /** 2756 * The ID of the texture. 2757 * 2758 * @name Texture#id 2759 * @type {number} 2760 * @readonly 2761 */ Object.defineProperty(this, 'id', { 2762 value: _textureId++ 2763 }); 2764 /** 2765 * The UUID of the material. 2766 * 2767 * @type {string} 2768 * @readonly 2769 */ this.uuid = generateUUID(); 2770 /** 2771 * The name of the material. 2772 * 2773 * @type {string} 2774 */ this.name = ''; 2775 /** 2776 * The data definition of a texture. A reference to the data source can be 2777 * shared across textures. This is often useful in context of spritesheets 2778 * where multiple textures render the same data but with different texture 2779 * transformations. 2780 * 2781 * @type {Source} 2782 */ this.source = new Source(image); 2783 /** 2784 * An array holding user-defined mipmaps. 2785 * 2786 * @type {Array<Object>} 2787 */ this.mipmaps = []; 2788 /** 2789 * How the texture is applied to the object. The value `UVMapping` 2790 * is the default, where texture or uv coordinates are used to apply the map. 2791 * 2792 * @type {(UVMapping|CubeReflectionMapping|CubeRefractionMapping|EquirectangularReflectionMapping|EquirectangularRefractionMapping|CubeUVReflectionMapping)} 2793 * @default UVMapping 2794 */ this.mapping = mapping; 2795 /** 2796 * Lets you select the uv attribute to map the texture to. `0` for `uv`, 2797 * `1` for `uv1`, `2` for `uv2` and `3` for `uv3`. 2798 * 2799 * @type {number} 2800 * @default 0 2801 */ this.channel = 0; 2802 /**
2803 * This defines how the texture is wrapped horizontally and corresponds to 2804 * *U* in UV mapping. 2805 * 2806 * @type {(RepeatWrapping|ClampToEdgeWrapping|MirroredRepeatWrapping)} 2807 * @default ClampToEdgeWrapping 2808 */ this.wrapS = wrapS; 2809 /** 2810 * This defines how the texture is wrapped horizontally and corresponds to 2811 * *V* in UV mapping. 2812 * 2813 * @type {(RepeatWrapping|ClampToEdgeWrapping|MirroredRepeatWrapping)} 2814 * @default ClampToEdgeWrapping 2815 */ this.wrapT = wrapT; 2816 /** 2817 * How the texture is sampled when a texel covers more than one pixel. 2818 * 2819 * @type {(NearestFilter|NearestMipmapNearestFilter|NearestMipmapLinearFilter|LinearFilter|LinearMipmapNearestFilter|LinearMipmapLinearFilter)} 2820 * @default LinearFilter 2821 */ this.magFilter = magFilter; 2822 /** 2823 * How the texture is sampled when a texel covers less than one pixel. 2824 * 2825 * @type {(NearestFilter|NearestMipmapNearestFilter|NearestMipmapLinearFilter|LinearFilter|LinearMipmapNearestFilter|LinearMipmapLinearFilter)} 2826 * @default LinearMipmapLinearFilter 2827 */ this.minFilter = minFilter; 2828 /** 2829 * The number of samples taken along the axis through the pixel that has the 2830 * highest density of texels. By default, this value is `1`. A higher value 2831 * gives a less blurry result than a basic mipmap, at the cost of more 2832 * texture samples being used. 2833 * 2834 * @type {number} 2835 * @default 0 2836 */ this.anisotropy = anisotropy; 2837 /** 2838 * The format of the texture. 2839 * 2840 * @type {number} 2841 * @default RGBAFormat 2842 */ this.format = format; 2843 /** 2844 * The default internal format is derived from {@link Texture#format} and {@link Texture#type} and 2845 * defines how the texture data is going to be stored on the GPU. 2846 * 2847 * This property allows to overwrite the default format. 2848 * 2849 * @type {?string} 2850 * @default null 2851 */ this.internalFormat = null; 2852 /** 2853 * The data type of the texture. 2854 * 2855 * @type {number} 2856 * @default UnsignedByteType 2857 */ this.type = type; 2858 /** 2859 * How much a single repetition of the texture is offset from the beginning, 2860 * in each direction U and V. Typical range is `0.0` to `1.0`. 2861 * 2862 * @type {Vector2} 2863 * @default (0,0) 2864 */ this.offset = new Vector2(0, 0); 2865 /** 2866 * How many times the texture is repeated across the surface, in each 2867 * direction U and V. If repeat is set greater than `1` in either direction, 2868 * the corresponding wrap parameter should also be set to `RepeatWrapping` 2869 * or `MirroredRepeatWrapping` to achieve the desired tiling effect. 2870 * 2871 * @type {Vector2} 2872 * @default (1,1) 2873 */ this.repeat = new Vector2(1, 1); 2874 /** 2875 * The point around which rotation occurs. A value of `(0.5, 0.5)` corresponds 2876 * to the center of the texture. Default is `(0, 0)`, the lower left. 2877 * 2878 * @type {Vector2} 2879 * @default (0,0) 2880 */ this.center = new Vector2(0, 0); 2881 /** 2882 * How much the texture is rotated around the center point, in radians. 2883 * Positive values are counter-clockwise. 2884 * 2885 * @type {number} 2886 * @default 0 2887 */ this.rotation = 0; 2888 /** 2889 * Whether to update the texture's uv-transformation {@link Texture#matrix} 2890 * from the properties {@link Texture#offset}, {@link Texture#repeat}, 2891 * {@link Texture#rotation}, and {@link Texture#center}. 2892 * 2893 * Set this to `false` if you are specifying the uv-transform matrix directly. 2894 * 2895 * @type {boolean} 2896 * @default true 2897 */ this.matrixAutoUpdate = true; 2898 /** 2899 * The uv-transformation matrix of the texture. 2900 * 2901 * @type {Matrix3} 2902 */ this.matrix = new Matrix3(); 2903 /** 2904 * Whether to generate mipmaps (if possible) for a texture. 2905 * 2906 * Set this to `false` if you are creating mipmaps manually. 2907 * 2908 * @type {boolean} 2909 * @default true 2910 */ this.generateMipmaps = true; 2911 /** 2912 * If set to `true`, the alpha channel, if present, is multiplied into the 2913 * color channels when the texture is uploaded to the GPU. 2914 * 2915 * Note that this property has no effect when using `ImageBitmap`. You need to 2916 * configure premultiply alpha on bitmap creation instead. 2917 * 2918 * @type {boolean} 2919 * @default false 2920 */ this.premultiplyAlpha = false;
vendor: 32,593 bytes, lines 2921-3863
2921 /** 2922 * If set to `true`, the texture is flipped along the vertical axis when 2923 * uploaded to the GPU. 2924 * 2925 * Note that this property has no effect when using `ImageBitmap`. You need to 2926 * configure the flip on bitmap creation instead. 2927 * 2928 * @type {boolean} 2929 * @default true 2930 */ this.flipY = true; 2931 /** 2932 * Specifies the alignment requirements for the start of each pixel row in memory. 2933 * The allowable values are `1` (byte-alignment), `2` (rows aligned to even-numbered bytes), 2934 * `4` (word-alignment), and `8` (rows start on double-word boundaries). 2935 * 2936 * @type {number} 2937 * @default 4 2938 */ this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) 2939 /** 2940 * Textures containing color data should be annotated with `SRGBColorSpace` or `LinearSRGBColorSpace`. 2941 * 2942 * @type {string} 2943 * @default NoColorSpace 2944 */ this.colorSpace = colorSpace; 2945 /** 2946 * An object that can be used to store custom data about the texture. It 2947 * should not hold references to functions as these will not be cloned. 2948 * 2949 * @type {Object} 2950 */ this.userData = {}; 2951 /** 2952 * This starts at `0` and counts how many times {@link Texture#needsUpdate} is set to `true`. 2953 * 2954 * @type {number} 2955 * @readonly 2956 * @default 0 2957 */ this.version = 0; 2958 /** 2959 * A callback function, called when the texture is updated (e.g., when 2960 * {@link Texture#needsUpdate} has been set to true and then the texture is used). 2961 * 2962 * @type {?Function} 2963 * @default null 2964 */ this.onUpdate = null; 2965 /** 2966 * An optional back reference to the textures render target. 2967 * 2968 * @type {?(RenderTarget|WebGLRenderTarget)} 2969 * @default null 2970 */ this.renderTarget = null; 2971 /** 2972 * Indicates whether a texture belongs to a render target or not. 2973 * 2974 * @type {boolean} 2975 * @readonly 2976 * @default false 2977 */ this.isRenderTargetTexture = false; 2978 /** 2979 * Indicates whether this texture should be processed by `PMREMGenerator` or not 2980 * (only relevant for render target textures). 2981 * 2982 * @type {number} 2983 * @readonly 2984 * @default 0 2985 */ this.pmremVersion = 0; 2986 } 2987 }; 2988 /** 2989 * The default image for all textures. 2990 * 2991 * @static 2992 * @type {?Image} 2993 * @default null 2994 */ Texture$1.DEFAULT_IMAGE = null; 2995 /** 2996 * The default mapping for all textures. 2997 * 2998 * @static 2999 * @type {number} 3000 * @default UVMapping 3001 */ Texture$1.DEFAULT_MAPPING = UVMapping; 3002 /** 3003 * The default anisotropy value for all textures. 3004 * 3005 * @static 3006 * @type {number} 3007 * @default 1 3008 */ Texture$1.DEFAULT_ANISOTROPY = 1; 3009 /** 3010 * Class representing a 4D vector. A 4D vector is an ordered quadruplet of numbers 3011 * (labeled x, y, z and w), which can be used to represent a number of things, such as: 3012 * 3013 * - A point in 4D space. 3014 * - A direction and length in 4D space. In three.js the length will 3015 * always be the Euclidean distance(straight-line distance) from `(0, 0, 0, 0)` to `(x, y, z, w)` 3016 * and the direction is also measured from `(0, 0, 0, 0)` towards `(x, y, z, w)`. 3017 * - Any arbitrary ordered quadruplet of numbers. 3018 * 3019 * There are other things a 4D vector can be used to represent, however these 3020 * are the most common uses in *three.js*. 3021 * 3022 * Iterating through a vector instance will yield its components `(x, y, z, w)` in 3023 * the corresponding order. 3024 * ```js 3025 * const a = new THREE.Vector4( 0, 1, 0, 0 ); 3026 * 3027 * //no arguments; will be initialised to (0, 0, 0, 1) 3028 * const b = new THREE.Vector4( ); 3029 * 3030 * const d = a.dot( b ); 3031 * ``` 3032 */ class Vector4 { 3033 /** 3034 * Alias for {@link Vector4#z}. 3035 * 3036 * @type {number} 3037 */ get width() { 3038 return this.z; 3039 } 3040 set width(value) { 3041 this.z = value; 3042 } 3043 /** 3044 * Alias for {@link Vector4#w}. 3045 * 3046 * @type {number} 3047 */ get height() { 3048 return this.w; 3049 } 3050 set height(value) { 3051 this.w = value; 3052 } 3053 /** 3054 * Sets the vector components. 3055 * 3056 * @param {number} x - The value of the x component. 3057 * @param {number} y - The value of the y component. 3058 * @param {number} z - The value of the z component. 3059 * @param {number} w - The value of the w component. 3060 * @return {Vector4} A reference to this vector. 3061 */ set(x, y, z, w) { 3062 this.x = x; 3063 this.y = y; 3064 this.z = z; 3065 this.w = w; 3066 return this; 3067 } 3068 /** 3069 * Sets the vector components to the same value. 3070 * 3071 * @param {number} scalar - The value to set for all vector components. 3072 * @return {Vector4} A reference to this vector. 3073 */ setScalar(scalar) { 3074 this.x = scalar; 3075 this.y = scalar; 3076 this.z = scalar; 3077 this.w = scalar; 3078 return this; 3079 } 3080 /** 3081 * Sets the vector's x component to the given value 3082 * 3083 * @param {number} x - The value to set. 3084 * @return {Vector4} A reference to this vector. 3085 */ setX(x) { 3086 this.x = x; 3087 return this; 3088 } 3089 /** 3090 * Sets the vector's y component to the given value 3091 * 3092 * @param {number} y - The value to set. 3093 * @return {Vector4} A reference to this vector. 3094 */ setY(y) { 3095 this.y = y; 3096 return this; 3097 } 3098 /** 3099 * Sets the vector's z component to the given value 3100 * 3101 * @param {number} z - The value to set. 3102 * @return {Vector4} A reference to this vector. 3103 */ setZ(z) { 3104 this.z = z; 3105 return this; 3106 } 3107 /** 3108 * Sets the vector's w component to the given value 3109 * 3110 * @param {number} w - The value to set. 3111 * @return {Vector4} A reference to this vector. 3112 */ setW(w) { 3113 this.w = w; 3114 return this; 3115 } 3116 /** 3117 * Allows to set a vector component with an index. 3118 * 3119 * @param {number} index - The component index. `0` equals to x, `1` equals to y, 3120 * `2` equals to z, `3` equals to w. 3121 * @param {number} value - The value to set. 3122 * @return {Vector4} A reference to this vector. 3123 */ setComponent(index, value) { 3124 switch(index){ 3125 case 0: 3126 this.x = value; 3127 break; 3128 case 1: 3129 this.y = value; 3130 break; 3131 case 2: 3132 this.z = value; 3133 break; 3134 case 3: 3135 this.w = value; 3136 break; 3137 default: 3138 throw new Error('index is out of range: ' + index); 3139 } 3140 return this; 3141 } 3142 /** 3143 * Returns the value of the vector component which matches the given index. 3144 * 3145 * @param {number} index - The component index. `0` equals to x, `1` equals to y, 3146 * `2` equals to z, `3` equals to w. 3147 * @return {number} A vector component value. 3148 */ getComponent(index) { 3149 switch(index){ 3150 case 0: 3151 return this.x; 3152 case 1: 3153 return this.y; 3154 case 2: 3155 return this.z; 3156 case 3: 3157 return this.w; 3158 default: 3159 throw new Error('index is out of range: ' + index); 3160 } 3161 } 3162 /** 3163 * Returns a new vector with copied values from this instance. 3164 * 3165 * @return {Vector4} A clone of this instance. 3166 */ clone() { 3167 return new this.constructor(this.x, this.y, this.z, this.w); 3168 } 3169 /** 3170 * Copies the values of the given vector to this instance. 3171 * 3172 * @param {Vector3|Vector4} v - The vector to copy. 3173 * @return {Vector4} A reference to this vector. 3174 */ copy(v) { 3175 this.x = v.x; 3176 this.y = v.y; 3177 this.z = v.z; 3178 this.w = v.w !== undefined ? v.w : 1; 3179 return this; 3180 } 3181 /** 3182 * Adds the given vector to this instance. 3183 * 3184 * @param {Vector4} v - The vector to add. 3185 * @return {Vector4} A reference to this vector. 3186 */ add(v) { 3187 this.x += v.x; 3188 this.y += v.y; 3189 this.z += v.z; 3190 this.w += v.w; 3191 return this; 3192 } 3193 /** 3194 * Adds the given scalar value to all components of this instance. 3195 * 3196 * @param {number} s - The scalar to add. 3197 * @return {Vector4} A reference to this vector. 3198 */ addScalar(s) { 3199 this.x += s; 3200 this.y += s; 3201 this.z += s; 3202 this.w += s; 3203 return this; 3204 } 3205 /** 3206 * Adds the given vectors and stores the result in this instance. 3207 * 3208 * @param {Vector4} a - The first vector. 3209 * @param {Vector4} b - The second vector. 3210 * @return {Vector4} A reference to this vector. 3211 */ addVectors(a, b) { 3212 this.x = a.x + b.x; 3213 this.y = a.y + b.y; 3214 this.z = a.z + b.z; 3215 this.w = a.w + b.w; 3216 return this; 3217 } 3218 /** 3219 * Adds the given vector scaled by the given factor to this instance. 3220 * 3221 * @param {Vector4} v - The vector. 3222 * @param {number} s - The factor that scales `v`. 3223 * @return {Vector4} A reference to this vector. 3224 */ addScaledVector(v, s) { 3225 this.x += v.x * s; 3226 this.y += v.y * s; 3227 this.z += v.z * s; 3228 this.w += v.w * s; 3229 return this; 3230 } 3231 /** 3232 * Subtracts the given vector from this instance. 3233 * 3234 * @param {Vector4} v - The vector to subtract. 3235 * @return {Vector4} A reference to this vector. 3236 */ sub(v) { 3237 this.x -= v.x; 3238 this.y -= v.y; 3239 this.z -= v.z; 3240 this.w -= v.w; 3241 return this; 3242 } 3243 /** 3244 * Subtracts the given scalar value from all components of this instance. 3245 * 3246 * @param {number} s - The scalar to subtract. 3247 * @return {Vector4} A reference to this vector. 3248 */ subScalar(s) { 3249 this.x -= s; 3250 this.y -= s; 3251 this.z -= s; 3252 this.w -= s; 3253 return this; 3254 } 3255 /** 3256 * Subtracts the given vectors and stores the result in this instance. 3257 * 3258 * @param {Vector4} a - The first vector. 3259 * @param {Vector4} b - The second vector. 3260 * @return {Vector4} A reference to this vector. 3261 */ subVectors(a, b) { 3262 this.x = a.x - b.x; 3263 this.y = a.y - b.y; 3264 this.z = a.z - b.z; 3265 this.w = a.w - b.w; 3266 return this; 3267 } 3268 /** 3269 * Multiplies the given vector with this instance. 3270 * 3271 * @param {Vector4} v - The vector to multiply. 3272 * @return {Vector4} A reference to this vector. 3273 */ multiply(v) { 3274 this.x *= v.x; 3275 this.y *= v.y; 3276 this.z *= v.z; 3277 this.w *= v.w; 3278 return this; 3279 } 3280 /** 3281 * Multiplies the given scalar value with all components of this instance. 3282 * 3283 * @param {number} scalar - The scalar to multiply. 3284 * @return {Vector4} A reference to this vector. 3285 */ multiplyScalar(scalar) { 3286 this.x *= scalar; 3287 this.y *= scalar; 3288 this.z *= scalar; 3289 this.w *= scalar; 3290 return this; 3291 } 3292 /** 3293 * Multiplies this vector with the given 4x4 matrix. 3294 * 3295 * @param {Matrix4} m - The 4x4 matrix. 3296 * @return {Vector4} A reference to this vector. 3297 */ applyMatrix4(m) { 3298 const x = this.x, y = this.y, z = this.z, w = this.w; 3299 const e = m.elements; 3300 this.x = e[0] * x + e[4] * y + e[8] * z + e[12] * w; 3301 this.y = e[1] * x + e[5] * y + e[9] * z + e[13] * w; 3302 this.z = e[2] * x + e[6] * y + e[10] * z + e[14] * w; 3303 this.w = e[3] * x + e[7] * y + e[11] * z + e[15] * w; 3304 return this; 3305 } 3306 /** 3307 * Divides this instance by the given vector. 3308 * 3309 * @param {Vector4} v - The vector to divide. 3310 * @return {Vector4} A reference to this vector. 3311 */ divide(v) { 3312 this.x /= v.x; 3313 this.y /= v.y; 3314 this.z /= v.z; 3315 this.w /= v.w; 3316 return this; 3317 } 3318 /** 3319 * Divides this vector by the given scalar. 3320 * 3321 * @param {number} scalar - The scalar to divide. 3322 * @return {Vector4} A reference to this vector. 3323 */ divideScalar(scalar) { 3324 return this.multiplyScalar(1 / scalar); 3325 } 3326 /** 3327 * Sets the x, y and z components of this 3328 * vector to the quaternion's axis and w to the angle. 3329 * 3330 * @param {Quaternion} q - The Quaternion to set. 3331 * @return {Vector4} A reference to this vector. 3332 */ setAxisAngleFromQuaternion(q) { 3333 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm 3334 // q is assumed to be normalized 3335 this.w = 2 * Math.acos(q.w); 3336 const s = Math.sqrt(1 - q.w * q.w); 3337 if (s < 0.0001) { 3338 this.x = 1; 3339 this.y = 0; 3340 this.z = 0; 3341 } else { 3342 this.x = q.x / s; 3343 this.y = q.y / s; 3344 this.z = q.z / s; 3345 } 3346 return this; 3347 } 3348 /** 3349 * Sets the x, y and z components of this 3350 * vector to the axis of rotation and w to the angle. 3351 * 3352 * @param {Matrix4} m - A 4x4 matrix of which the upper left 3x3 matrix is a pure rotation matrix. 3353 * @return {Vector4} A reference to this vector. 3354 */ setAxisAngleFromRotationMatrix(m) { 3355 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm 3356 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 3357 let angle, x, y, z; // variables for result 3358 const epsilon = 0.01, epsilon2 = 0.1, te = m.elements, m11 = te[0], m12 = te[4], m13 = te[8], m21 = te[1], m22 = te[5], m23 = te[9], m31 = te[2], m32 = te[6], m33 = te[10]; 3359 if (Math.abs(m12 - m21) < epsilon && Math.abs(m13 - m31) < epsilon && Math.abs(m23 - m32) < epsilon) { 3360 // singularity found 3361 // first check for identity matrix which must have +1 for all terms 3362 // in leading diagonal and zero in other terms 3363 if (Math.abs(m12 + m21) < epsilon2 && Math.abs(m13 + m31) < epsilon2 && Math.abs(m23 + m32) < epsilon2 && Math.abs(m11 + m22 + m33 - 3) < epsilon2) { 3364 // this singularity is identity matrix so angle = 0 3365 this.set(1, 0, 0, 0); 3366 return this; // zero angle, arbitrary axis 3367 } 3368 // otherwise this singularity is angle = 180 3369 angle = Math.PI; 3370 const xx = (m11 + 1) / 2; 3371 const yy = (m22 + 1) / 2; 3372 const zz = (m33 + 1) / 2; 3373 const xy = (m12 + m21) / 4; 3374 const xz = (m13 + m31) / 4; 3375 const yz = (m23 + m32) / 4; 3376 if (xx > yy && xx > zz) { 3377 // m11 is the largest diagonal term 3378 if (xx < epsilon) { 3379 x = 0; 3380 y = 0.707106781; 3381 z = 0.707106781; 3382 } else { 3383 x = Math.sqrt(xx); 3384 y = xy / x; 3385 z = xz / x; 3386 } 3387 } else if (yy > zz) { 3388 // m22 is the largest diagonal term 3389 if (yy < epsilon) { 3390 x = 0.707106781; 3391 y = 0; 3392 z = 0.707106781; 3393 } else { 3394 y = Math.sqrt(yy); 3395 x = xy / y; 3396 z = yz / y; 3397 } 3398 } else { 3399 // m33 is the largest diagonal term so base result on this 3400 if (zz < epsilon) { 3401 x = 0.707106781; 3402 y = 0.707106781; 3403 z = 0; 3404 } else { 3405 z = Math.sqrt(zz); 3406 x = xz / z; 3407 y = yz / z; 3408 } 3409 } 3410 this.set(x, y, z, angle); 3411 return this; // return 180 deg rotation 3412 } 3413 // as we have reached here there are no singularities so we can handle normally 3414 let s = Math.sqrt((m32 - m23) * (m32 - m23) + (m13 - m31) * (m13 - m31) + (m21 - m12) * (m21 - m12)); // used to normalize 3415 if (Math.abs(s) < 0.001) s = 1; 3416 // prevent divide by zero, should not happen if matrix is orthogonal and should be 3417 // caught by singularity test above, but I've left it in just in case 3418 this.x = (m32 - m23) / s; 3419 this.y = (m13 - m31) / s; 3420 this.z = (m21 - m12) / s; 3421 this.w = Math.acos((m11 + m22 + m33 - 1) / 2); 3422 return this; 3423 } 3424 /** 3425 * Sets the vector components to the position elements of the 3426 * given transformation matrix. 3427 * 3428 * @param {Matrix4} m - The 4x4 matrix. 3429 * @return {Vector4} A reference to this vector. 3430 */ setFromMatrixPosition(m) { 3431 const e = m.elements; 3432 this.x = e[12]; 3433 this.y = e[13]; 3434 this.z = e[14]; 3435 this.w = e[15]; 3436 return this; 3437 } 3438 /** 3439 * If this vector's x, y, z or w value is greater than the given vector's x, y, z or w 3440 * value, replace that value with the corresponding min value. 3441 * 3442 * @param {Vector4} v - The vector. 3443 * @return {Vector4} A reference to this vector. 3444 */ min(v) { 3445 this.x = Math.min(this.x, v.x); 3446 this.y = Math.min(this.y, v.y); 3447 this.z = Math.min(this.z, v.z); 3448 this.w = Math.min(this.w, v.w); 3449 return this; 3450 } 3451 /** 3452 * If this vector's x, y, z or w value is less than the given vector's x, y, z or w 3453 * value, replace that value with the corresponding max value. 3454 * 3455 * @param {Vector4} v - The vector. 3456 * @return {Vector4} A reference to this vector. 3457 */ max(v) { 3458 this.x = Math.max(this.x, v.x); 3459 this.y = Math.max(this.y, v.y); 3460 this.z = Math.max(this.z, v.z); 3461 this.w = Math.max(this.w, v.w); 3462 return this; 3463 } 3464 /** 3465 * If this vector's x, y, z or w value is greater than the max vector's x, y, z or w 3466 * value, it is replaced by the corresponding value. 3467 * If this vector's x, y, z or w value is less than the min vector's x, y, z or w value, 3468 * it is replaced by the corresponding value. 3469 * 3470 * @param {Vector4} min - The minimum x, y and z values. 3471 * @param {Vector4} max - The maximum x, y and z values in the desired range. 3472 * @return {Vector4} A reference to this vector. 3473 */ clamp(min, max) { 3474 // assumes min < max, componentwise 3475 this.x = clamp$1(this.x, min.x, max.x); 3476 this.y = clamp$1(this.y, min.y, max.y); 3477 this.z = clamp$1(this.z, min.z, max.z); 3478 this.w = clamp$1(this.w, min.w, max.w); 3479 return this; 3480 } 3481 /** 3482 * If this vector's x, y, z or w values are greater than the max value, they are 3483 * replaced by the max value. 3484 * If this vector's x, y, z or w values are less than the min value, they are 3485 * replaced by the min value. 3486 * 3487 * @param {number} minVal - The minimum value the components will be clamped to. 3488 * @param {number} maxVal - The maximum value the components will be clamped to. 3489 * @return {Vector4} A reference to this vector. 3490 */ clampScalar(minVal, maxVal) { 3491 this.x = clamp$1(this.x, minVal, maxVal); 3492 this.y = clamp$1(this.y, minVal, maxVal); 3493 this.z = clamp$1(this.z, minVal, maxVal); 3494 this.w = clamp$1(this.w, minVal, maxVal); 3495 return this; 3496 } 3497 /** 3498 * If this vector's length is greater than the max value, it is replaced by 3499 * the max value. 3500 * If this vector's length is less than the min value, it is replaced by the 3501 * min value. 3502 * 3503 * @param {number} min - The minimum value the vector length will be clamped to. 3504 * @param {number} max - The maximum value the vector length will be clamped to. 3505 * @return {Vector4} A reference to this vector. 3506 */ clampLength(min, max) { 3507 const length = this.length(); 3508 return this.divideScalar(length || 1).multiplyScalar(clamp$1(length, min, max)); 3509 } 3510 /** 3511 * The components of this vector are rounded down to the nearest integer value. 3512 * 3513 * @return {Vector4} A reference to this vector. 3514 */ floor() { 3515 this.x = Math.floor(this.x); 3516 this.y = Math.floor(this.y); 3517 this.z = Math.floor(this.z); 3518 this.w = Math.floor(this.w); 3519 return this; 3520 } 3521 /** 3522 * The components of this vector are rounded up to the nearest integer value. 3523 * 3524 * @return {Vector4} A reference to this vector. 3525 */ ceil() { 3526 this.x = Math.ceil(this.x); 3527 this.y = Math.ceil(this.y); 3528 this.z = Math.ceil(this.z); 3529 this.w = Math.ceil(this.w); 3530 return this; 3531 } 3532 /** 3533 * The components of this vector are rounded to the nearest integer value 3534 * 3535 * @return {Vector4} A reference to this vector. 3536 */ round() { 3537 this.x = Math.round(this.x); 3538 this.y = Math.round(this.y); 3539 this.z = Math.round(this.z); 3540 this.w = Math.round(this.w); 3541 return this; 3542 } 3543 /** 3544 * The components of this vector are rounded towards zero (up if negative, 3545 * down if positive) to an integer value. 3546 * 3547 * @return {Vector4} A reference to this vector. 3548 */ roundToZero() { 3549 this.x = Math.trunc(this.x); 3550 this.y = Math.trunc(this.y); 3551 this.z = Math.trunc(this.z); 3552 this.w = Math.trunc(this.w); 3553 return this; 3554 } 3555 /** 3556 * Inverts this vector - i.e. sets x = -x, y = -y, z = -z, w = -w. 3557 * 3558 * @return {Vector4} A reference to this vector. 3559 */ negate() { 3560 this.x = -this.x; 3561 this.y = -this.y; 3562 this.z = -this.z; 3563 this.w = -this.w; 3564 return this; 3565 } 3566 /** 3567 * Calculates the dot product of the given vector with this instance. 3568 * 3569 * @param {Vector4} v - The vector to compute the dot product with. 3570 * @return {number} The result of the dot product. 3571 */ dot(v) { 3572 return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; 3573 } 3574 /** 3575 * Computes the square of the Euclidean length (straight-line length) from 3576 * (0, 0, 0, 0) to (x, y, z, w). If you are comparing the lengths of vectors, you should 3577 * compare the length squared instead as it is slightly more efficient to calculate. 3578 * 3579 * @return {number} The square length of this vector. 3580 */ lengthSq() { 3581 return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; 3582 } 3583 /** 3584 * Computes the Euclidean length (straight-line length) from (0, 0, 0, 0) to (x, y, z, w). 3585 * 3586 * @return {number} The length of this vector. 3587 */ length() { 3588 return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); 3589 } 3590 /** 3591 * Computes the Manhattan length of this vector. 3592 * 3593 * @return {number} The length of this vector. 3594 */ manhattanLength() { 3595 return Math.abs(this.x) + Math.abs(this.y) + Math.abs(this.z) + Math.abs(this.w); 3596 } 3597 /** 3598 * Converts this vector to a unit vector - that is, sets it equal to a vector 3599 * with the same direction as this one, but with a vector length of `1`. 3600 * 3601 * @return {Vector4} A reference to this vector. 3602 */ normalize() { 3603 return this.divideScalar(this.length() || 1); 3604 } 3605 /** 3606 * Sets this vector to a vector with the same direction as this one, but 3607 * with the specified length. 3608 * 3609 * @param {number} length - The new length of this vector. 3610 * @return {Vector4} A reference to this vector. 3611 */ setLength(length) { 3612 return this.normalize().multiplyScalar(length); 3613 } 3614 /** 3615 * Linearly interpolates between the given vector and this instance, where 3616 * alpha is the percent distance along the line - alpha = 0 will be this 3617 * vector, and alpha = 1 will be the given one. 3618 * 3619 * @param {Vector4} v - The vector to interpolate towards. 3620 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. 3621 * @return {Vector4} A reference to this vector. 3622 */ lerp(v, alpha) { 3623 this.x += (v.x - this.x) * alpha; 3624 this.y += (v.y - this.y) * alpha; 3625 this.z += (v.z - this.z) * alpha; 3626 this.w += (v.w - this.w) * alpha; 3627 return this; 3628 } 3629 /** 3630 * Linearly interpolates between the given vectors, where alpha is the percent 3631 * distance along the line - alpha = 0 will be first vector, and alpha = 1 will 3632 * be the second one. The result is stored in this instance. 3633 * 3634 * @param {Vector4} v1 - The first vector. 3635 * @param {Vector4} v2 - The second vector. 3636 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. 3637 * @return {Vector4} A reference to this vector. 3638 */ lerpVectors(v1, v2, alpha) { 3639 this.x = v1.x + (v2.x - v1.x) * alpha; 3640 this.y = v1.y + (v2.y - v1.y) * alpha; 3641 this.z = v1.z + (v2.z - v1.z) * alpha; 3642 this.w = v1.w + (v2.w - v1.w) * alpha; 3643 return this; 3644 } 3645 /** 3646 * Returns `true` if this vector is equal with the given one. 3647 * 3648 * @param {Vector4} v - The vector to test for equality. 3649 * @return {boolean} Whether this vector is equal with the given one. 3650 */ equals(v) { 3651 return v.x === this.x && v.y === this.y && v.z === this.z && v.w === this.w; 3652 } 3653 /** 3654 * Sets this vector's x value to be `array[ offset ]`, y value to be `array[ offset + 1 ]`, 3655 * z value to be `array[ offset + 2 ]`, w value to be `array[ offset + 3 ]`. 3656 * 3657 * @param {Array<number>} array - An array holding the vector component values. 3658 * @param {number} [offset=0] - The offset into the array. 3659 * @return {Vector4} A reference to this vector. 3660 */ fromArray(array, offset = 0) { 3661 this.x = array[offset]; 3662 this.y = array[offset + 1]; 3663 this.z = array[offset + 2]; 3664 this.w = array[offset + 3]; 3665 return this; 3666 } 3667 /** 3668 * Writes the components of this vector to the given array. If no array is provided, 3669 * the method returns a new instance. 3670 * 3671 * @param {Array<number>} [array=[]] - The target array holding the vector components. 3672 * @param {number} [offset=0] - Index of the first element in the array. 3673 * @return {Array<number>} The vector components. 3674 */ toArray(array = [], offset = 0) { 3675 array[offset] = this.x; 3676 array[offset + 1] = this.y; 3677 array[offset + 2] = this.z; 3678 array[offset + 3] = this.w; 3679 return array; 3680 } 3681 /** 3682 * Sets the components of this vector from the given buffer attribute. 3683 * 3684 * @param {BufferAttribute} attribute - The buffer attribute holding vector data. 3685 * @param {number} index - The index into the attribute. 3686 * @return {Vector4} A reference to this vector. 3687 */ fromBufferAttribute(attribute, index) { 3688 this.x = attribute.getX(index); 3689 this.y = attribute.getY(index); 3690 this.z = attribute.getZ(index); 3691 this.w = attribute.getW(index); 3692 return this; 3693 } 3694 /** 3695 * Sets each component of this vector to a pseudo-random value between `0` and 3696 * `1`, excluding `1`. 3697 * 3698 * @return {Vector4} A reference to this vector. 3699 */ random() { 3700 this.x = Math.random(); 3701 this.y = Math.random(); 3702 this.z = Math.random(); 3703 this.w = Math.random(); 3704 return this; 3705 } 3706 *[Symbol.iterator]() { 3707 yield this.x; 3708 yield this.y; 3709 yield this.z; 3710 yield this.w; 3711 } 3712 /** 3713 * Constructs a new 4D vector. 3714 * 3715 * @param {number} [x=0] - The x value of this vector. 3716 * @param {number} [y=0] - The y value of this vector. 3717 * @param {number} [z=0] - The z value of this vector. 3718 * @param {number} [w=1] - The w value of this vector. 3719 */ constructor(x = 0, y = 0, z = 0, w = 1){ 3720 /** 3721 * This flag can be used for type testing. 3722 * 3723 * @type {boolean} 3724 * @readonly 3725 * @default true 3726 */ Vector4.prototype.isVector4 = true; 3727 /** 3728 * The x value of this vector. 3729 * 3730 * @type {number} 3731 */ this.x = x; 3732 /** 3733 * The y value of this vector. 3734 * 3735 * @type {number} 3736 */ this.y = y; 3737 /** 3738 * The z value of this vector. 3739 * 3740 * @type {number} 3741 */ this.z = z; 3742 /** 3743 * The w value of this vector. 3744 * 3745 * @type {number} 3746 */ this.w = w; 3747 } 3748 } 3749 /* 3750 In options, we can specify: 3751 * Texture parameters for an auto-generated target texture 3752 * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers 3753 */ class RenderTarget extends EventDispatcher { 3754 get texture() { 3755 return this.textures[0]; 3756 } 3757 set texture(value) { 3758 this.textures[0] = value; 3759 } 3760 set depthTexture(current) { 3761 if (this._depthTexture !== null) this._depthTexture.renderTarget = null; 3762 if (current !== null) current.renderTarget = this; 3763 this._depthTexture = current; 3764 } 3765 get depthTexture() { 3766 return this._depthTexture; 3767 } 3768 setSize(width, height, depth = 1) { 3769 if (this.width !== width || this.height !== height || this.depth !== depth) { 3770 this.width = width; 3771 this.height = height; 3772 this.depth = depth; 3773 for(let i = 0, il = this.textures.length; i < il; i++){ 3774 this.textures[i].image.width = width; 3775 this.textures[i].image.height = height; 3776 this.textures[i].image.depth = depth; 3777 } 3778 this.dispose(); 3779 } 3780 this.viewport.set(0, 0, width, height); 3781 this.scissor.set(0, 0, width, height); 3782 } 3783 clone() { 3784 return new this.constructor().copy(this); 3785 } 3786 copy(source) { 3787 this.width = source.width; 3788 this.height = source.height; 3789 this.depth = source.depth; 3790 this.scissor.copy(source.scissor); 3791 this.scissorTest = source.scissorTest; 3792 this.viewport.copy(source.viewport); 3793 this.textures.length = 0; 3794 for(let i = 0, il = source.textures.length; i < il; i++){ 3795 this.textures[i] = source.textures[i].clone(); 3796 this.textures[i].isRenderTargetTexture = true; 3797 this.textures[i].renderTarget = this; 3798 // ensure image object is not shared, see #20328 3799 const image = Object.assign({}, source.textures[i].image); 3800 this.textures[i].source = new Source(image); 3801 } 3802 this.depthBuffer = source.depthBuffer; 3803 this.stencilBuffer = source.stencilBuffer; 3804 this.resolveDepthBuffer = source.resolveDepthBuffer; 3805 this.resolveStencilBuffer = source.resolveStencilBuffer; 3806 if (source.depthTexture !== null) this.depthTexture = source.depthTexture.clone(); 3807 this.samples = source.samples; 3808 return this; 3809 } 3810 dispose() { 3811 this.dispatchEvent({ 3812 type: 'dispose' 3813 }); 3814 } 3815 constructor(width = 1, height = 1, options = {}){ 3816 super(); 3817 this.isRenderTarget = true; 3818 this.width = width; 3819 this.height = height; 3820 this.depth = 1; 3821 this.scissor = new Vector4(0, 0, width, height); 3822 this.scissorTest = false; 3823 this.viewport = new Vector4(0, 0, width, height); 3824 const image = { 3825 width: width, 3826 height: height, 3827 depth: 1 3828 }; 3829 options = Object.assign({ 3830 generateMipmaps: false, 3831 internalFormat: null, 3832 minFilter: LinearFilter, 3833 depthBuffer: true, 3834 stencilBuffer: false, 3835 resolveDepthBuffer: true, 3836 resolveStencilBuffer: true, 3837 depthTexture: null, 3838 samples: 0, 3839 count: 1 3840 }, options); 3841 const texture = new Texture$1(image, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace); 3842 texture.flipY = false; 3843 texture.generateMipmaps = options.generateMipmaps; 3844 texture.internalFormat = options.internalFormat; 3845 this.textures = []; 3846 const count = options.count; 3847 for(let i = 0; i < count; i++){ 3848 this.textures[i] = texture.clone(); 3849 this.textures[i].isRenderTargetTexture = true; 3850 this.textures[i].renderTarget = this; 3851 } 3852 this.depthBuffer = options.depthBuffer; 3853 this.stencilBuffer = options.stencilBuffer; 3854 this.resolveDepthBuffer = options.resolveDepthBuffer; 3855 this.resolveStencilBuffer = options.resolveStencilBuffer; 3856 this._depthTexture = null; 3857 this.depthTexture = options.depthTexture; 3858 this.samples = options.samples; 3859 } 3860 } 3861 class WebGLRenderTarget extends RenderTarget { 3862 constructor(width = 1, height = 1, options = {}){ 3863 super(width, height, options);
vendor: 20,961 bytes, lines 3864-4419
3864 this.isWebGLRenderTarget = true; 3865 } 3866 } 3867 class DataArrayTexture extends Texture$1 { 3868 addLayerUpdate(layerIndex) { 3869 this.layerUpdates.add(layerIndex); 3870 } 3871 clearLayerUpdates() { 3872 this.layerUpdates.clear(); 3873 } 3874 constructor(data = null, width = 1, height = 1, depth = 1){ 3875 super(null); 3876 this.isDataArrayTexture = true; 3877 this.image = { 3878 data, 3879 width, 3880 height, 3881 depth 3882 }; 3883 this.magFilter = NearestFilter; 3884 this.minFilter = NearestFilter; 3885 this.wrapR = ClampToEdgeWrapping; 3886 this.generateMipmaps = false; 3887 this.flipY = false; 3888 this.unpackAlignment = 1; 3889 this.layerUpdates = new Set(); 3890 } 3891 } 3892 class Data3DTexture extends Texture$1 { 3893 constructor(data = null, width = 1, height = 1, depth = 1){ 3894 // We're going to add .setXXX() methods for setting properties later. 3895 // Users can still set in Data3DTexture directly. 3896 // 3897 // const texture = new THREE.Data3DTexture( data, width, height, depth ); 3898 // texture.anisotropy = 16; 3899 // 3900 // See #14839 3901 super(null); 3902 this.isData3DTexture = true; 3903 this.image = { 3904 data, 3905 width, 3906 height, 3907 depth 3908 }; 3909 this.magFilter = NearestFilter; 3910 this.minFilter = NearestFilter; 3911 this.wrapR = ClampToEdgeWrapping; 3912 this.generateMipmaps = false; 3913 this.flipY = false; 3914 this.unpackAlignment = 1; 3915 } 3916 } 3917 /** 3918 * Class for representing a Quaternion. Quaternions are used in three.js to represent rotations. 3919 * 3920 * Iterating through a vector instance will yield its components `(x, y, z, w)` in 3921 * the corresponding order. 3922 * 3923 * Note that three.js expects Quaternions to be normalized. 3924 * ```js 3925 * const quaternion = new THREE.Quaternion(); 3926 * quaternion.setFromAxisAngle( new THREE.Vector3( 0, 1, 0 ), Math.PI / 2 ); 3927 * 3928 * const vector = new THREE.Vector3( 1, 0, 0 ); 3929 * vector.applyQuaternion( quaternion ); 3930 * ``` 3931 */ class Quaternion { 3932 /** 3933 * Interpolates between two quaternions via SLERP. This implementation assumes the 3934 * quaternion data are managed in flat arrays. 3935 * 3936 * @param {Array<number>} dst - The destination array. 3937 * @param {number} dstOffset - An offset into the destination array. 3938 * @param {Array<number>} src0 - The source array of the first quaternion. 3939 * @param {number} srcOffset0 - An offset into the first source array. 3940 * @param {Array<number>} src1 - The source array of the second quaternion. 3941 * @param {number} srcOffset1 - An offset into the second source array. 3942 * @param {number} t - The interpolation factor in the range `[0,1]`. 3943 * @see {@link Quaternion#slerp} 3944 */ static slerpFlat(dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t) { 3945 // fuzz-free, array-based Quaternion SLERP operation 3946 let x0 = src0[srcOffset0 + 0], y0 = src0[srcOffset0 + 1], z0 = src0[srcOffset0 + 2], w0 = src0[srcOffset0 + 3]; 3947 const x1 = src1[srcOffset1 + 0], y1 = src1[srcOffset1 + 1], z1 = src1[srcOffset1 + 2], w1 = src1[srcOffset1 + 3]; 3948 if (t === 0) { 3949 dst[dstOffset + 0] = x0; 3950 dst[dstOffset + 1] = y0; 3951 dst[dstOffset + 2] = z0; 3952 dst[dstOffset + 3] = w0; 3953 return; 3954 } 3955 if (t === 1) { 3956 dst[dstOffset + 0] = x1; 3957 dst[dstOffset + 1] = y1; 3958 dst[dstOffset + 2] = z1; 3959 dst[dstOffset + 3] = w1; 3960 return; 3961 } 3962 if (w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1) { 3963 let s = 1 - t; 3964 const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, dir = cos >= 0 ? 1 : -1, sqrSin = 1 - cos * cos; 3965 // Skip the Slerp for tiny steps to avoid numeric problems: 3966 if (sqrSin > Number.EPSILON) { 3967 const sin = Math.sqrt(sqrSin), len = Math.atan2(sin, cos * dir); 3968 s = Math.sin(s * len) / sin; 3969 t = Math.sin(t * len) / sin; 3970 } 3971 const tDir = t * dir; 3972 x0 = x0 * s + x1 * tDir; 3973 y0 = y0 * s + y1 * tDir; 3974 z0 = z0 * s + z1 * tDir; 3975 w0 = w0 * s + w1 * tDir; 3976 // Normalize in case we just did a lerp: 3977 if (s === 1 - t) { 3978 const f = 1 / Math.sqrt(x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0); 3979 x0 *= f; 3980 y0 *= f; 3981 z0 *= f; 3982 w0 *= f; 3983 } 3984 } 3985 dst[dstOffset] = x0; 3986 dst[dstOffset + 1] = y0; 3987 dst[dstOffset + 2] = z0; 3988 dst[dstOffset + 3] = w0; 3989 } 3990 /** 3991 * Multiplies two quaternions. This implementation assumes the quaternion data are managed 3992 * in flat arrays. 3993 * 3994 * @param {Array<number>} dst - The destination array. 3995 * @param {number} dstOffset - An offset into the destination array. 3996 * @param {Array<number>} src0 - The source array of the first quaternion. 3997 * @param {number} srcOffset0 - An offset into the first source array. 3998 * @param {Array<number>} src1 - The source array of the second quaternion. 3999 * @param {number} srcOffset1 - An offset into the second source array. 4000 * @return {Array<number>} The destination array. 4001 * @see {@link Quaternion#multiplyQuaternions}. 4002 */ static multiplyQuaternionsFlat(dst, dstOffset, src0, srcOffset0, src1, srcOffset1) { 4003 const x0 = src0[srcOffset0]; 4004 const y0 = src0[srcOffset0 + 1]; 4005 const z0 = src0[srcOffset0 + 2]; 4006 const w0 = src0[srcOffset0 + 3]; 4007 const x1 = src1[srcOffset1]; 4008 const y1 = src1[srcOffset1 + 1]; 4009 const z1 = src1[srcOffset1 + 2]; 4010 const w1 = src1[srcOffset1 + 3]; 4011 dst[dstOffset] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1; 4012 dst[dstOffset + 1] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1; 4013 dst[dstOffset + 2] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1; 4014 dst[dstOffset + 3] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1; 4015 return dst; 4016 } 4017 /** 4018 * The x value of this quaternion. 4019 * 4020 * @type {number} 4021 * @default 0 4022 */ get x() { 4023 return this._x; 4024 } 4025 set x(value) { 4026 this._x = value; 4027 this._onChangeCallback(); 4028 } 4029 /** 4030 * The y value of this quaternion. 4031 * 4032 * @type {number} 4033 * @default 0 4034 */ get y() { 4035 return this._y; 4036 } 4037 set y(value) { 4038 this._y = value; 4039 this._onChangeCallback(); 4040 } 4041 /** 4042 * The z value of this quaternion. 4043 * 4044 * @type {number} 4045 * @default 0 4046 */ get z() { 4047 return this._z; 4048 } 4049 set z(value) { 4050 this._z = value; 4051 this._onChangeCallback(); 4052 } 4053 /** 4054 * The w value of this quaternion. 4055 * 4056 * @type {number} 4057 * @default 1 4058 */ get w() { 4059 return this._w; 4060 } 4061 set w(value) { 4062 this._w = value; 4063 this._onChangeCallback(); 4064 } 4065 /** 4066 * Sets the quaternion components. 4067 * 4068 * @param {number} x - The x value of this quaternion. 4069 * @param {number} y - The y value of this quaternion. 4070 * @param {number} z - The z value of this quaternion. 4071 * @param {number} w - The w value of this quaternion. 4072 * @return {Quaternion} A reference to this quaternion. 4073 */ set(x, y, z, w) { 4074 this._x = x; 4075 this._y = y; 4076 this._z = z; 4077 this._w = w; 4078 this._onChangeCallback(); 4079 return this; 4080 } 4081 /** 4082 * Returns a new quaternion with copied values from this instance. 4083 * 4084 * @return {Quaternion} A clone of this instance. 4085 */ clone() { 4086 return new this.constructor(this._x, this._y, this._z, this._w); 4087 } 4088 /** 4089 * Copies the values of the given quaternion to this instance. 4090 * 4091 * @param {Quaternion} quaternion - The quaternion to copy. 4092 * @return {Quaternion} A reference to this quaternion. 4093 */ copy(quaternion) { 4094 this._x = quaternion.x; 4095 this._y = quaternion.y; 4096 this._z = quaternion.z; 4097 this._w = quaternion.w; 4098 this._onChangeCallback(); 4099 return this; 4100 } 4101 /** 4102 * Sets this quaternion from the rotation specified by the given 4103 * Euler angles. 4104 * 4105 * @param {Euler} euler - The Euler angles. 4106 * @param {boolean} [update=true] - Whether the internal `onChange` callback should be executed or not. 4107 * @return {Quaternion} A reference to this quaternion. 4108 */ setFromEuler(euler, update = true) { 4109 const x = euler._x, y = euler._y, z = euler._z, order = euler._order; 4110 // http://www.mathworks.com/matlabcentral/fileexchange/ 4111 // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ 4112 // content/SpinCalc.m 4113 const cos = Math.cos; 4114 const sin = Math.sin; 4115 const c1 = cos(x / 2); 4116 const c2 = cos(y / 2); 4117 const c3 = cos(z / 2); 4118 const s1 = sin(x / 2); 4119 const s2 = sin(y / 2); 4120 const s3 = sin(z / 2); 4121 switch(order){ 4122 case 'XYZ': 4123 this._x = s1 * c2 * c3 + c1 * s2 * s3; 4124 this._y = c1 * s2 * c3 - s1 * c2 * s3; 4125 this._z = c1 * c2 * s3 + s1 * s2 * c3; 4126 this._w = c1 * c2 * c3 - s1 * s2 * s3; 4127 break; 4128 case 'YXZ': 4129 this._x = s1 * c2 * c3 + c1 * s2 * s3; 4130 this._y = c1 * s2 * c3 - s1 * c2 * s3; 4131 this._z = c1 * c2 * s3 - s1 * s2 * c3; 4132 this._w = c1 * c2 * c3 + s1 * s2 * s3; 4133 break; 4134 case 'ZXY': 4135 this._x = s1 * c2 * c3 - c1 * s2 * s3; 4136 this._y = c1 * s2 * c3 + s1 * c2 * s3; 4137 this._z = c1 * c2 * s3 + s1 * s2 * c3; 4138 this._w = c1 * c2 * c3 - s1 * s2 * s3; 4139 break; 4140 case 'ZYX': 4141 this._x = s1 * c2 * c3 - c1 * s2 * s3; 4142 this._y = c1 * s2 * c3 + s1 * c2 * s3; 4143 this._z = c1 * c2 * s3 - s1 * s2 * c3; 4144 this._w = c1 * c2 * c3 + s1 * s2 * s3; 4145 break; 4146 case 'YZX': 4147 this._x = s1 * c2 * c3 + c1 * s2 * s3; 4148 this._y = c1 * s2 * c3 + s1 * c2 * s3; 4149 this._z = c1 * c2 * s3 - s1 * s2 * c3; 4150 this._w = c1 * c2 * c3 - s1 * s2 * s3; 4151 break; 4152 case 'XZY': 4153 this._x = s1 * c2 * c3 - c1 * s2 * s3; 4154 this._y = c1 * s2 * c3 - s1 * c2 * s3; 4155 this._z = c1 * c2 * s3 + s1 * s2 * c3; 4156 this._w = c1 * c2 * c3 + s1 * s2 * s3; 4157 break; 4158 default: 4159 console.warn('THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order); 4160 } 4161 if (update === true) this._onChangeCallback(); 4162 return this; 4163 } 4164 /** 4165 * Sets this quaternion from the given axis and angle. 4166 * 4167 * @param {Vector3} axis - The normalized axis. 4168 * @param {number} angle - The angle in radians. 4169 * @return {Quaternion} A reference to this quaternion. 4170 */ setFromAxisAngle(axis, angle) { 4171 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm 4172 const halfAngle = angle / 2, s = Math.sin(halfAngle); 4173 this._x = axis.x * s; 4174 this._y = axis.y * s; 4175 this._z = axis.z * s; 4176 this._w = Math.cos(halfAngle); 4177 this._onChangeCallback(); 4178 return this; 4179 } 4180 /** 4181 * Sets this quaternion from the given rotation matrix. 4182 * 4183 * @param {Matrix4} m - A 4x4 matrix of which the upper 3x3 of matrix is a pure rotation matrix (i.e. unscaled). 4184 * @return {Quaternion} A reference to this quaternion. 4185 */ setFromRotationMatrix(m) { 4186 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm 4187 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 4188 const te = m.elements, m11 = te[0], m12 = te[4], m13 = te[8], m21 = te[1], m22 = te[5], m23 = te[9], m31 = te[2], m32 = te[6], m33 = te[10], trace = m11 + m22 + m33; 4189 if (trace > 0) { 4190 const s = 0.5 / Math.sqrt(trace + 1.0); 4191 this._w = 0.25 / s; 4192 this._x = (m32 - m23) * s; 4193 this._y = (m13 - m31) * s; 4194 this._z = (m21 - m12) * s; 4195 } else if (m11 > m22 && m11 > m33) { 4196 const s = 2.0 * Math.sqrt(1.0 + m11 - m22 - m33); 4197 this._w = (m32 - m23) / s; 4198 this._x = 0.25 * s; 4199 this._y = (m12 + m21) / s; 4200 this._z = (m13 + m31) / s; 4201 } else if (m22 > m33) { 4202 const s = 2.0 * Math.sqrt(1.0 + m22 - m11 - m33); 4203 this._w = (m13 - m31) / s; 4204 this._x = (m12 + m21) / s; 4205 this._y = 0.25 * s; 4206 this._z = (m23 + m32) / s; 4207 } else { 4208 const s = 2.0 * Math.sqrt(1.0 + m33 - m11 - m22); 4209 this._w = (m21 - m12) / s; 4210 this._x = (m13 + m31) / s; 4211 this._y = (m23 + m32) / s; 4212 this._z = 0.25 * s; 4213 } 4214 this._onChangeCallback(); 4215 return this; 4216 } 4217 /** 4218 * Sets this quaternion to the rotation required to rotate the direction vector 4219 * `vFrom` to the direction vector `vTo`. 4220 * 4221 * @param {Vector3} vFrom - The first (normalized) direction vector. 4222 * @param {Vector3} vTo - The second (normalized) direction vector. 4223 * @return {Quaternion} A reference to this quaternion. 4224 */ setFromUnitVectors(vFrom, vTo) { 4225 // assumes direction vectors vFrom and vTo are normalized 4226 let r = vFrom.dot(vTo) + 1; 4227 if (r < Number.EPSILON) { 4228 // vFrom and vTo point in opposite directions 4229 r = 0; 4230 if (Math.abs(vFrom.x) > Math.abs(vFrom.z)) { 4231 this._x = -vFrom.y; 4232 this._y = vFrom.x; 4233 this._z = 0; 4234 this._w = r; 4235 } else { 4236 this._x = 0; 4237 this._y = -vFrom.z; 4238 this._z = vFrom.y; 4239 this._w = r; 4240 } 4241 } else { 4242 // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3 4243 this._x = vFrom.y * vTo.z - vFrom.z * vTo.y; 4244 this._y = vFrom.z * vTo.x - vFrom.x * vTo.z; 4245 this._z = vFrom.x * vTo.y - vFrom.y * vTo.x; 4246 this._w = r; 4247 } 4248 return this.normalize(); 4249 } 4250 /** 4251 * Returns the angle between this quaternion and the given one in radians. 4252 * 4253 * @param {Quaternion} q - The quaternion to compute the angle with. 4254 * @return {number} The angle in radians. 4255 */ angleTo(q) { 4256 return 2 * Math.acos(Math.abs(clamp$1(this.dot(q), -1, 1))); 4257 } 4258 /** 4259 * Rotates this quaternion by a given angular step to the given quaternion. 4260 * The method ensures that the final quaternion will not overshoot `q`. 4261 * 4262 * @param {Quaternion} q - The target quaternion. 4263 * @param {number} step - The angular step in radians. 4264 * @return {Quaternion} A reference to this quaternion. 4265 */ rotateTowards(q, step) { 4266 const angle = this.angleTo(q); 4267 if (angle === 0) return this; 4268 const t = Math.min(1, step / angle); 4269 this.slerp(q, t); 4270 return this; 4271 } 4272 /** 4273 * Sets this quaternion to the identity quaternion; that is, to the 4274 * quaternion that represents "no rotation". 4275 * 4276 * @return {Quaternion} A reference to this quaternion. 4277 */ identity() { 4278 return this.set(0, 0, 0, 1); 4279 } 4280 /** 4281 * Inverts this quaternion via {@link Quaternion#conjugate}. The 4282 * quaternion is assumed to have unit length. 4283 * 4284 * @return {Quaternion} A reference to this quaternion. 4285 */ invert() { 4286 return this.conjugate(); 4287 } 4288 /** 4289 * Returns the rotational conjugate of this quaternion. The conjugate of a 4290 * quaternion represents the same rotation in the opposite direction about 4291 * the rotational axis. 4292 * 4293 * @return {Quaternion} A reference to this quaternion. 4294 */ conjugate() { 4295 this._x *= -1; 4296 this._y *= -1; 4297 this._z *= -1; 4298 this._onChangeCallback(); 4299 return this; 4300 } 4301 /** 4302 * Calculates the dot product of this quaternion and the given one. 4303 * 4304 * @param {Quaternion} v - The quaternion to compute the dot product with. 4305 * @return {number} The result of the dot product. 4306 */ dot(v) { 4307 return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; 4308 } 4309 /** 4310 * Computes the squared Euclidean length (straight-line length) of this quaternion, 4311 * considered as a 4 dimensional vector. This can be useful if you are comparing the 4312 * lengths of two quaternions, as this is a slightly more efficient calculation than 4313 * {@link Quaternion#length}. 4314 * 4315 * @return {number} The squared Euclidean length. 4316 */ lengthSq() { 4317 return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; 4318 } 4319 /** 4320 * Computes the Euclidean length (straight-line length) of this quaternion, 4321 * considered as a 4 dimensional vector. 4322 * 4323 * @return {number} The Euclidean length. 4324 */ length() { 4325 return Math.sqrt(this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w); 4326 } 4327 /** 4328 * Normalizes this quaternion - that is, calculated the quaternion that performs 4329 * the same rotation as this one, but has a length equal to `1`. 4330 * 4331 * @return {Quaternion} A reference to this quaternion. 4332 */ normalize() { 4333 let l = this.length(); 4334 if (l === 0) { 4335 this._x = 0; 4336 this._y = 0; 4337 this._z = 0; 4338 this._w = 1; 4339 } else { 4340 l = 1 / l; 4341 this._x = this._x * l; 4342 this._y = this._y * l; 4343 this._z = this._z * l; 4344 this._w = this._w * l; 4345 } 4346 this._onChangeCallback(); 4347 return this; 4348 } 4349 /** 4350 * Multiplies this quaternion by the given one. 4351 * 4352 * @param {Quaternion} q - The quaternion. 4353 * @return {Quaternion} A reference to this quaternion. 4354 */ multiply(q) { 4355 return this.multiplyQuaternions(this, q); 4356 } 4357 /** 4358 * Pre-multiplies this quaternion by the given one. 4359 * 4360 * @param {Quaternion} q - The quaternion. 4361 * @return {Quaternion} A reference to this quaternion. 4362 */ premultiply(q) { 4363 return this.multiplyQuaternions(q, this); 4364 } 4365 /** 4366 * Multiplies the given quaternions and stores the result in this instance. 4367 * 4368 * @param {Quaternion} a - The first quaternion. 4369 * @param {Quaternion} b - The second quaternion. 4370 * @return {Quaternion} A reference to this quaternion. 4371 */ multiplyQuaternions(a, b) { 4372 // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm 4373 const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; 4374 const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; 4375 this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; 4376 this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; 4377 this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; 4378 this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; 4379 this._onChangeCallback(); 4380 return this; 4381 } 4382 /** 4383 * Performs a spherical linear interpolation between quaternions. 4384 * 4385 * @param {Quaternion} qb - The target quaternion. 4386 * @param {number} t - The interpolation factor in the closed interval `[0, 1]`. 4387 * @return {Quaternion} A reference to this quaternion. 4388 */ slerp(qb, t) { 4389 if (t === 0) return this; 4390 if (t === 1) return this.copy(qb); 4391 const x = this._x, y = this._y, z = this._z, w = this._w; 4392 // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ 4393 let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; 4394 if (cosHalfTheta < 0) { 4395 this._w = -qb._w; 4396 this._x = -qb._x; 4397 this._y = -qb._y; 4398 this._z = -qb._z; 4399 cosHalfTheta = -cosHalfTheta; 4400 } else { 4401 this.copy(qb); 4402 } 4403 if (cosHalfTheta >= 1.0) { 4404 this._w = w; 4405 this._x = x; 4406 this._y = y; 4407 this._z = z; 4408 return this; 4409 } 4410 const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; 4411 if (sqrSinHalfTheta <= Number.EPSILON) { 4412 const s = 1 - t; 4413 this._w = s * w + t * this._w; 4414 this._x = s * x + t * this._x; 4415 this._y = s * y + t * this._y; 4416 this._z = s * z + t * this._z; 4417 this.normalize(); // normalize calls _onChangeCallback() 4418 return this; 4419 }
vendor: 5,430 bytes, lines 4420-4556
4420 const sinHalfTheta = Math.sqrt(sqrSinHalfTheta); 4421 const halfTheta = Math.atan2(sinHalfTheta, cosHalfTheta); 4422 const ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta, ratioB = Math.sin(t * halfTheta) / sinHalfTheta; 4423 this._w = w * ratioA + this._w * ratioB; 4424 this._x = x * ratioA + this._x * ratioB; 4425 this._y = y * ratioA + this._y * ratioB; 4426 this._z = z * ratioA + this._z * ratioB; 4427 this._onChangeCallback(); 4428 return this; 4429 } 4430 /** 4431 * Performs a spherical linear interpolation between the given quaternions 4432 * and stores the result in this quaternion. 4433 * 4434 * @param {Quaternion} qa - The source quaternion. 4435 * @param {Quaternion} qb - The target quaternion. 4436 * @param {number} t - The interpolation factor in the closed interval `[0, 1]`. 4437 * @return {Quaternion} A reference to this quaternion. 4438 */ slerpQuaternions(qa, qb, t) { 4439 return this.copy(qa).slerp(qb, t); 4440 } 4441 /** 4442 * Sets this quaternion to a uniformly random, normalized quaternion. 4443 * 4444 * @return {Quaternion} A reference to this quaternion. 4445 */ random() { 4446 // Ken Shoemake 4447 // Uniform random rotations 4448 // D. Kirk, editor, Graphics Gems III, pages 124-132. Academic Press, New York, 1992. 4449 const theta1 = 2 * Math.PI * Math.random(); 4450 const theta2 = 2 * Math.PI * Math.random(); 4451 const x0 = Math.random(); 4452 const r1 = Math.sqrt(1 - x0); 4453 const r2 = Math.sqrt(x0); 4454 return this.set(r1 * Math.sin(theta1), r1 * Math.cos(theta1), r2 * Math.sin(theta2), r2 * Math.cos(theta2)); 4455 } 4456 /** 4457 * Returns `true` if this quaternion is equal with the given one. 4458 * 4459 * @param {Quaternion} quaternion - The quaternion to test for equality. 4460 * @return {boolean} Whether this quaternion is equal with the given one. 4461 */ equals(quaternion) { 4462 return quaternion._x === this._x && quaternion._y === this._y && quaternion._z === this._z && quaternion._w === this._w; 4463 } 4464 /** 4465 * Sets this quaternion's components from the given array. 4466 * 4467 * @param {Array<number>} array - An array holding the quaternion component values. 4468 * @param {number} [offset=0] - The offset into the array. 4469 * @return {Quaternion} A reference to this quaternion. 4470 */ fromArray(array, offset = 0) { 4471 this._x = array[offset]; 4472 this._y = array[offset + 1]; 4473 this._z = array[offset + 2]; 4474 this._w = array[offset + 3]; 4475 this._onChangeCallback(); 4476 return this; 4477 } 4478 /** 4479 * Writes the components of this quaternion to the given array. If no array is provided, 4480 * the method returns a new instance. 4481 * 4482 * @param {Array<number>} [array=[]] - The target array holding the quaternion components. 4483 * @param {number} [offset=0] - Index of the first element in the array. 4484 * @return {Array<number>} The quaternion components. 4485 */ toArray(array = [], offset = 0) { 4486 array[offset] = this._x; 4487 array[offset + 1] = this._y; 4488 array[offset + 2] = this._z; 4489 array[offset + 3] = this._w; 4490 return array; 4491 } 4492 /** 4493 * Sets the components of this quaternion from the given buffer attribute. 4494 * 4495 * @param {BufferAttribute} attribute - The buffer attribute holding quaternion data. 4496 * @param {number} index - The index into the attribute. 4497 * @return {Quaternion} A reference to this quaternion. 4498 */ fromBufferAttribute(attribute, index) { 4499 this._x = attribute.getX(index); 4500 this._y = attribute.getY(index); 4501 this._z = attribute.getZ(index); 4502 this._w = attribute.getW(index); 4503 this._onChangeCallback(); 4504 return this; 4505 } 4506 /** 4507 * This methods defines the serialization result of this class. Returns the 4508 * numerical elements of this quaternion in an array of format `[x, y, z, w]`. 4509 * 4510 * @return {Array<number>} The serialized quaternion. 4511 */ toJSON() { 4512 return this.toArray(); 4513 } 4514 _onChange(callback) { 4515 this._onChangeCallback = callback; 4516 return this; 4517 } 4518 _onChangeCallback() {} 4519 *[Symbol.iterator]() { 4520 yield this._x; 4521 yield this._y; 4522 yield this._z; 4523 yield this._w; 4524 } 4525 /** 4526 * Constructs a new quaternion. 4527 * 4528 * @param {number} [x=0] - The x value of this quaternion. 4529 * @param {number} [y=0] - The y value of this quaternion. 4530 * @param {number} [z=0] - The z value of this quaternion. 4531 * @param {number} [w=1] - The w value of this quaternion. 4532 */ constructor(x = 0, y = 0, z = 0, w = 1){ 4533 /** 4534 * This flag can be used for type testing. 4535 * 4536 * @type {boolean} 4537 * @readonly 4538 * @default true 4539 */ this.isQuaternion = true; 4540 this._x = x; 4541 this._y = y; 4542 this._z = z; 4543 this._w = w; 4544 } 4545 } 4546 /** 4547 * Class representing a 3D vector. A 3D vector is an ordered triplet of numbers 4548 * (labeled x, y and z), which can be used to represent a number of things, such as: 4549 * 4550 * - A point in 3D space. 4551 * - A direction and length in 3D space. In three.js the length will 4552 * always be the Euclidean distance(straight-line distance) from `(0, 0, 0)` to `(x, y, z)` 4553 * and the direction is also measured from `(0, 0, 0)` towards `(x, y, z)`. 4554 * - Any arbitrary ordered triplet of numbers. 4555 * 4556 * There are other things a 3D vector can be used to represent, such as
vendor: 23,989 bytes, lines 4557-5245
4557 * momentum vectors and so on, however these are the most 4558 * common uses in three.js. 4559 * 4560 * Iterating through a vector instance will yield its components `(x, y, z)` in 4561 * the corresponding order. 4562 * ```js 4563 * const a = new THREE.Vector3( 0, 1, 0 ); 4564 * 4565 * //no arguments; will be initialised to (0, 0, 0) 4566 * const b = new THREE.Vector3( ); 4567 * 4568 * const d = a.distanceTo( b ); 4569 * ``` 4570 */ class Vector3 { 4571 /** 4572 * Sets the vector components. 4573 * 4574 * @param {number} x - The value of the x component. 4575 * @param {number} y - The value of the y component. 4576 * @param {number} z - The value of the z component. 4577 * @return {Vector3} A reference to this vector. 4578 */ set(x, y, z) { 4579 if (z === undefined) z = this.z; // sprite.scale.set(x,y) 4580 this.x = x; 4581 this.y = y; 4582 this.z = z; 4583 return this; 4584 } 4585 /** 4586 * Sets the vector components to the same value. 4587 * 4588 * @param {number} scalar - The value to set for all vector components. 4589 * @return {Vector3} A reference to this vector. 4590 */ setScalar(scalar) { 4591 this.x = scalar; 4592 this.y = scalar; 4593 this.z = scalar; 4594 return this; 4595 } 4596 /** 4597 * Sets the vector's x component to the given value 4598 * 4599 * @param {number} x - The value to set. 4600 * @return {Vector3} A reference to this vector. 4601 */ setX(x) { 4602 this.x = x; 4603 return this; 4604 } 4605 /** 4606 * Sets the vector's y component to the given value 4607 * 4608 * @param {number} y - The value to set. 4609 * @return {Vector3} A reference to this vector. 4610 */ setY(y) { 4611 this.y = y; 4612 return this; 4613 } 4614 /** 4615 * Sets the vector's z component to the given value 4616 * 4617 * @param {number} z - The value to set. 4618 * @return {Vector3} A reference to this vector. 4619 */ setZ(z) { 4620 this.z = z; 4621 return this; 4622 } 4623 /** 4624 * Allows to set a vector component with an index. 4625 * 4626 * @param {number} index - The component index. `0` equals to x, `1` equals to y, `2` equals to z. 4627 * @param {number} value - The value to set. 4628 * @return {Vector3} A reference to this vector. 4629 */ setComponent(index, value) { 4630 switch(index){ 4631 case 0: 4632 this.x = value; 4633 break; 4634 case 1: 4635 this.y = value; 4636 break; 4637 case 2: 4638 this.z = value; 4639 break; 4640 default: 4641 throw new Error('index is out of range: ' + index); 4642 } 4643 return this; 4644 } 4645 /** 4646 * Returns the value of the vector component which matches the given index. 4647 * 4648 * @param {number} index - The component index. `0` equals to x, `1` equals to y, `2` equals to z. 4649 * @return {number} A vector component value. 4650 */ getComponent(index) { 4651 switch(index){ 4652 case 0: 4653 return this.x; 4654 case 1: 4655 return this.y; 4656 case 2: 4657 return this.z; 4658 default: 4659 throw new Error('index is out of range: ' + index); 4660 } 4661 } 4662 /** 4663 * Returns a new vector with copied values from this instance. 4664 * 4665 * @return {Vector3} A clone of this instance. 4666 */ clone() { 4667 return new this.constructor(this.x, this.y, this.z); 4668 } 4669 /** 4670 * Copies the values of the given vector to this instance. 4671 * 4672 * @param {Vector3} v - The vector to copy. 4673 * @return {Vector3} A reference to this vector. 4674 */ copy(v) { 4675 this.x = v.x; 4676 this.y = v.y; 4677 this.z = v.z; 4678 return this; 4679 } 4680 /** 4681 * Adds the given vector to this instance. 4682 * 4683 * @param {Vector3} v - The vector to add. 4684 * @return {Vector3} A reference to this vector. 4685 */ add(v) { 4686 this.x += v.x; 4687 this.y += v.y; 4688 this.z += v.z; 4689 return this; 4690 } 4691 /** 4692 * Adds the given scalar value to all components of this instance. 4693 * 4694 * @param {number} s - The scalar to add. 4695 * @return {Vector3} A reference to this vector. 4696 */ addScalar(s) { 4697 this.x += s; 4698 this.y += s; 4699 this.z += s; 4700 return this; 4701 } 4702 /** 4703 * Adds the given vectors and stores the result in this instance. 4704 * 4705 * @param {Vector3} a - The first vector. 4706 * @param {Vector3} b - The second vector. 4707 * @return {Vector3} A reference to this vector. 4708 */ addVectors(a, b) { 4709 this.x = a.x + b.x; 4710 this.y = a.y + b.y; 4711 this.z = a.z + b.z; 4712 return this; 4713 } 4714 /** 4715 * Adds the given vector scaled by the given factor to this instance. 4716 * 4717 * @param {Vector3|Vector4} v - The vector. 4718 * @param {number} s - The factor that scales `v`. 4719 * @return {Vector3} A reference to this vector. 4720 */ addScaledVector(v, s) { 4721 this.x += v.x * s; 4722 this.y += v.y * s; 4723 this.z += v.z * s; 4724 return this; 4725 } 4726 /** 4727 * Subtracts the given vector from this instance. 4728 * 4729 * @param {Vector3} v - The vector to subtract. 4730 * @return {Vector3} A reference to this vector. 4731 */ sub(v) { 4732 this.x -= v.x; 4733 this.y -= v.y; 4734 this.z -= v.z; 4735 return this; 4736 } 4737 /** 4738 * Subtracts the given scalar value from all components of this instance. 4739 * 4740 * @param {number} s - The scalar to subtract. 4741 * @return {Vector3} A reference to this vector. 4742 */ subScalar(s) { 4743 this.x -= s; 4744 this.y -= s; 4745 this.z -= s; 4746 return this; 4747 } 4748 /** 4749 * Subtracts the given vectors and stores the result in this instance. 4750 * 4751 * @param {Vector3} a - The first vector. 4752 * @param {Vector3} b - The second vector. 4753 * @return {Vector3} A reference to this vector. 4754 */ subVectors(a, b) { 4755 this.x = a.x - b.x; 4756 this.y = a.y - b.y; 4757 this.z = a.z - b.z; 4758 return this; 4759 } 4760 /** 4761 * Multiplies the given vector with this instance. 4762 * 4763 * @param {Vector3} v - The vector to multiply. 4764 * @return {Vector3} A reference to this vector. 4765 */ multiply(v) { 4766 this.x *= v.x; 4767 this.y *= v.y; 4768 this.z *= v.z; 4769 return this; 4770 } 4771 /** 4772 * Multiplies the given scalar value with all components of this instance. 4773 * 4774 * @param {number} scalar - The scalar to multiply. 4775 * @return {Vector3} A reference to this vector. 4776 */ multiplyScalar(scalar) { 4777 this.x *= scalar; 4778 this.y *= scalar; 4779 this.z *= scalar; 4780 return this; 4781 } 4782 /** 4783 * Multiplies the given vectors and stores the result in this instance. 4784 * 4785 * @param {Vector3} a - The first vector. 4786 * @param {Vector3} b - The second vector. 4787 * @return {Vector3} A reference to this vector. 4788 */ multiplyVectors(a, b) { 4789 this.x = a.x * b.x; 4790 this.y = a.y * b.y; 4791 this.z = a.z * b.z; 4792 return this; 4793 } 4794 /** 4795 * Applies the given Euler rotation to this vector. 4796 * 4797 * @param {Euler} euler - The Euler angles. 4798 * @return {Vector3} A reference to this vector. 4799 */ applyEuler(euler) { 4800 return this.applyQuaternion(_quaternion$4.setFromEuler(euler)); 4801 } 4802 /** 4803 * Applies a rotation specified by an axis and an angle to this vector. 4804 * 4805 * @param {Vector3} axis - A normalized vector representing the rotation axis. 4806 * @param {number} angle - The angle in radians. 4807 * @return {Vector3} A reference to this vector. 4808 */ applyAxisAngle(axis, angle) { 4809 return this.applyQuaternion(_quaternion$4.setFromAxisAngle(axis, angle)); 4810 } 4811 /** 4812 * Multiplies this vector with the given 3x3 matrix. 4813 * 4814 * @param {Matrix3} m - The 3x3 matrix. 4815 * @return {Vector3} A reference to this vector. 4816 */ applyMatrix3(m) { 4817 const x = this.x, y = this.y, z = this.z; 4818 const e = m.elements; 4819 this.x = e[0] * x + e[3] * y + e[6] * z; 4820 this.y = e[1] * x + e[4] * y + e[7] * z; 4821 this.z = e[2] * x + e[5] * y + e[8] * z; 4822 return this; 4823 } 4824 /** 4825 * Multiplies this vector by the given normal matrix and normalizes 4826 * the result. 4827 * 4828 * @param {Matrix3} m - The normal matrix. 4829 * @return {Vector3} A reference to this vector. 4830 */ applyNormalMatrix(m) { 4831 return this.applyMatrix3(m).normalize(); 4832 } 4833 /** 4834 * Multiplies this vector (with an implicit 1 in the 4th dimension) by m, and 4835 * divides by perspective. 4836 * 4837 * @param {Matrix4} m - The matrix to apply. 4838 * @return {Vector3} A reference to this vector. 4839 */ applyMatrix4(m) { 4840 const x = this.x, y = this.y, z = this.z; 4841 const e = m.elements; 4842 const w = 1 / (e[3] * x + e[7] * y + e[11] * z + e[15]); 4843 this.x = (e[0] * x + e[4] * y + e[8] * z + e[12]) * w; 4844 this.y = (e[1] * x + e[5] * y + e[9] * z + e[13]) * w; 4845 this.z = (e[2] * x + e[6] * y + e[10] * z + e[14]) * w; 4846 return this; 4847 } 4848 /** 4849 * Applies the given Quaternion to this vector. 4850 * 4851 * @param {Quaternion} q - The Quaternion. 4852 * @return {Vector3} A reference to this vector. 4853 */ applyQuaternion(q) { 4854 // quaternion q is assumed to have unit length 4855 const vx = this.x, vy = this.y, vz = this.z; 4856 const qx = q.x, qy = q.y, qz = q.z, qw = q.w; 4857 // t = 2 * cross( q.xyz, v ); 4858 const tx = 2 * (qy * vz - qz * vy); 4859 const ty = 2 * (qz * vx - qx * vz); 4860 const tz = 2 * (qx * vy - qy * vx); 4861 // v + q.w * t + cross( q.xyz, t ); 4862 this.x = vx + qw * tx + qy * tz - qz * ty; 4863 this.y = vy + qw * ty + qz * tx - qx * tz; 4864 this.z = vz + qw * tz + qx * ty - qy * tx; 4865 return this; 4866 } 4867 /** 4868 * Projects this vector from world space into the camera's normalized 4869 * device coordinate (NDC) space. 4870 * 4871 * @param {Camera} camera - The camera. 4872 * @return {Vector3} A reference to this vector. 4873 */ project(camera) { 4874 return this.applyMatrix4(camera.matrixWorldInverse).applyMatrix4(camera.projectionMatrix); 4875 } 4876 /** 4877 * Unprojects this vector from the camera's normalized device coordinate (NDC) 4878 * space into world space. 4879 * 4880 * @param {Camera} camera - The camera. 4881 * @return {Vector3} A reference to this vector. 4882 */ unproject(camera) { 4883 return this.applyMatrix4(camera.projectionMatrixInverse).applyMatrix4(camera.matrixWorld); 4884 } 4885 /** 4886 * Transforms the direction of this vector by a matrix (the upper left 3 x 3 4887 * subset of the given 4x4 matrix and then normalizes the result. 4888 * 4889 * @param {Matrix4} m - The matrix. 4890 * @return {Vector3} A reference to this vector. 4891 */ transformDirection(m) { 4892 // input: THREE.Matrix4 affine matrix 4893 // vector interpreted as a direction 4894 const x = this.x, y = this.y, z = this.z; 4895 const e = m.elements; 4896 this.x = e[0] * x + e[4] * y + e[8] * z; 4897 this.y = e[1] * x + e[5] * y + e[9] * z; 4898 this.z = e[2] * x + e[6] * y + e[10] * z; 4899 return this.normalize(); 4900 } 4901 /** 4902 * Divides this instance by the given vector. 4903 * 4904 * @param {Vector3} v - The vector to divide. 4905 * @return {Vector3} A reference to this vector. 4906 */ divide(v) { 4907 this.x /= v.x; 4908 this.y /= v.y; 4909 this.z /= v.z; 4910 return this; 4911 } 4912 /** 4913 * Divides this vector by the given scalar. 4914 * 4915 * @param {number} scalar - The scalar to divide. 4916 * @return {Vector3} A reference to this vector. 4917 */ divideScalar(scalar) { 4918 return this.multiplyScalar(1 / scalar); 4919 } 4920 /** 4921 * If this vector's x, y or z value is greater than the given vector's x, y or z 4922 * value, replace that value with the corresponding min value. 4923 * 4924 * @param {Vector3} v - The vector. 4925 * @return {Vector3} A reference to this vector. 4926 */ min(v) { 4927 this.x = Math.min(this.x, v.x); 4928 this.y = Math.min(this.y, v.y); 4929 this.z = Math.min(this.z, v.z); 4930 return this; 4931 } 4932 /** 4933 * If this vector's x, y or z value is less than the given vector's x, y or z 4934 * value, replace that value with the corresponding max value. 4935 * 4936 * @param {Vector3} v - The vector. 4937 * @return {Vector3} A reference to this vector. 4938 */ max(v) { 4939 this.x = Math.max(this.x, v.x); 4940 this.y = Math.max(this.y, v.y); 4941 this.z = Math.max(this.z, v.z); 4942 return this; 4943 } 4944 /** 4945 * If this vector's x, y or z value is greater than the max vector's x, y or z 4946 * value, it is replaced by the corresponding value. 4947 * If this vector's x, y or z value is less than the min vector's x, y or z value, 4948 * it is replaced by the corresponding value. 4949 * 4950 * @param {Vector3} min - The minimum x, y and z values. 4951 * @param {Vector3} max - The maximum x, y and z values in the desired range. 4952 * @return {Vector3} A reference to this vector. 4953 */ clamp(min, max) { 4954 // assumes min < max, componentwise 4955 this.x = clamp$1(this.x, min.x, max.x); 4956 this.y = clamp$1(this.y, min.y, max.y); 4957 this.z = clamp$1(this.z, min.z, max.z); 4958 return this; 4959 } 4960 /** 4961 * If this vector's x, y or z values are greater than the max value, they are 4962 * replaced by the max value. 4963 * If this vector's x, y or z values are less than the min value, they are 4964 * replaced by the min value. 4965 * 4966 * @param {number} minVal - The minimum value the components will be clamped to. 4967 * @param {number} maxVal - The maximum value the components will be clamped to. 4968 * @return {Vector3} A reference to this vector. 4969 */ clampScalar(minVal, maxVal) { 4970 this.x = clamp$1(this.x, minVal, maxVal); 4971 this.y = clamp$1(this.y, minVal, maxVal); 4972 this.z = clamp$1(this.z, minVal, maxVal); 4973 return this; 4974 } 4975 /** 4976 * If this vector's length is greater than the max value, it is replaced by 4977 * the max value. 4978 * If this vector's length is less than the min value, it is replaced by the 4979 * min value. 4980 * 4981 * @param {number} min - The minimum value the vector length will be clamped to. 4982 * @param {number} max - The maximum value the vector length will be clamped to. 4983 * @return {Vector3} A reference to this vector. 4984 */ clampLength(min, max) { 4985 const length = this.length(); 4986 return this.divideScalar(length || 1).multiplyScalar(clamp$1(length, min, max)); 4987 } 4988 /** 4989 * The components of this vector are rounded down to the nearest integer value. 4990 * 4991 * @return {Vector3} A reference to this vector. 4992 */ floor() { 4993 this.x = Math.floor(this.x); 4994 this.y = Math.floor(this.y); 4995 this.z = Math.floor(this.z); 4996 return this; 4997 } 4998 /** 4999 * The components of this vector are rounded up to the nearest integer value. 5000 * 5001 * @return {Vector3} A reference to this vector. 5002 */ ceil() { 5003 this.x = Math.ceil(this.x); 5004 this.y = Math.ceil(this.y); 5005 this.z = Math.ceil(this.z); 5006 return this; 5007 } 5008 /** 5009 * The components of this vector are rounded to the nearest integer value 5010 * 5011 * @return {Vector3} A reference to this vector. 5012 */ round() { 5013 this.x = Math.round(this.x); 5014 this.y = Math.round(this.y); 5015 this.z = Math.round(this.z); 5016 return this; 5017 } 5018 /** 5019 * The components of this vector are rounded towards zero (up if negative, 5020 * down if positive) to an integer value. 5021 * 5022 * @return {Vector3} A reference to this vector. 5023 */ roundToZero() { 5024 this.x = Math.trunc(this.x); 5025 this.y = Math.trunc(this.y); 5026 this.z = Math.trunc(this.z); 5027 return this; 5028 } 5029 /** 5030 * Inverts this vector - i.e. sets x = -x, y = -y and z = -z. 5031 * 5032 * @return {Vector3} A reference to this vector. 5033 */ negate() { 5034 this.x = -this.x; 5035 this.y = -this.y; 5036 this.z = -this.z; 5037 return this; 5038 } 5039 /** 5040 * Calculates the dot product of the given vector with this instance. 5041 * 5042 * @param {Vector3} v - The vector to compute the dot product with. 5043 * @return {number} The result of the dot product. 5044 */ dot(v) { 5045 return this.x * v.x + this.y * v.y + this.z * v.z; 5046 } 5047 // TODO lengthSquared? 5048 /** 5049 * Computes the square of the Euclidean length (straight-line length) from 5050 * (0, 0, 0) to (x, y, z). If you are comparing the lengths of vectors, you should 5051 * compare the length squared instead as it is slightly more efficient to calculate. 5052 * 5053 * @return {number} The square length of this vector. 5054 */ lengthSq() { 5055 return this.x * this.x + this.y * this.y + this.z * this.z; 5056 } 5057 /** 5058 * Computes the Euclidean length (straight-line length) from (0, 0, 0) to (x, y, z). 5059 * 5060 * @return {number} The length of this vector. 5061 */ length() { 5062 return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); 5063 } 5064 /** 5065 * Computes the Manhattan length of this vector. 5066 * 5067 * @return {number} The length of this vector. 5068 */ manhattanLength() { 5069 return Math.abs(this.x) + Math.abs(this.y) + Math.abs(this.z); 5070 } 5071 /** 5072 * Converts this vector to a unit vector - that is, sets it equal to a vector 5073 * with the same direction as this one, but with a vector length of `1`. 5074 * 5075 * @return {Vector3} A reference to this vector. 5076 */ normalize() { 5077 return this.divideScalar(this.length() || 1); 5078 } 5079 /** 5080 * Sets this vector to a vector with the same direction as this one, but 5081 * with the specified length. 5082 * 5083 * @param {number} length - The new length of this vector. 5084 * @return {Vector3} A reference to this vector. 5085 */ setLength(length) { 5086 return this.normalize().multiplyScalar(length); 5087 } 5088 /** 5089 * Linearly interpolates between the given vector and this instance, where 5090 * alpha is the percent distance along the line - alpha = 0 will be this 5091 * vector, and alpha = 1 will be the given one. 5092 * 5093 * @param {Vector3} v - The vector to interpolate towards. 5094 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. 5095 * @return {Vector3} A reference to this vector. 5096 */ lerp(v, alpha) { 5097 this.x += (v.x - this.x) * alpha; 5098 this.y += (v.y - this.y) * alpha; 5099 this.z += (v.z - this.z) * alpha; 5100 return this; 5101 } 5102 /** 5103 * Linearly interpolates between the given vectors, where alpha is the percent 5104 * distance along the line - alpha = 0 will be first vector, and alpha = 1 will 5105 * be the second one. The result is stored in this instance. 5106 * 5107 * @param {Vector3} v1 - The first vector. 5108 * @param {Vector3} v2 - The second vector. 5109 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. 5110 * @return {Vector3} A reference to this vector. 5111 */ lerpVectors(v1, v2, alpha) { 5112 this.x = v1.x + (v2.x - v1.x) * alpha; 5113 this.y = v1.y + (v2.y - v1.y) * alpha; 5114 this.z = v1.z + (v2.z - v1.z) * alpha; 5115 return this; 5116 } 5117 /** 5118 * Calculates the cross product of the given vector with this instance. 5119 * 5120 * @param {Vector3} v - The vector to compute the cross product with. 5121 * @return {Vector3} The result of the cross product. 5122 */ cross(v) { 5123 return this.crossVectors(this, v); 5124 } 5125 /** 5126 * Calculates the cross product of the given vectors and stores the result 5127 * in this instance. 5128 * 5129 * @param {Vector3} a - The first vector. 5130 * @param {Vector3} b - The second vector. 5131 * @return {Vector3} A reference to this vector. 5132 */ crossVectors(a, b) { 5133 const ax = a.x, ay = a.y, az = a.z; 5134 const bx = b.x, by = b.y, bz = b.z; 5135 this.x = ay * bz - az * by; 5136 this.y = az * bx - ax * bz; 5137 this.z = ax * by - ay * bx; 5138 return this; 5139 } 5140 /** 5141 * Projects this vector onto the given one. 5142 * 5143 * @param {Vector3} v - The vector to project to. 5144 * @return {Vector3} A reference to this vector. 5145 */ projectOnVector(v) { 5146 const denominator = v.lengthSq(); 5147 if (denominator === 0) return this.set(0, 0, 0); 5148 const scalar = v.dot(this) / denominator; 5149 return this.copy(v).multiplyScalar(scalar); 5150 } 5151 /** 5152 * Projects this vector onto a plane by subtracting this 5153 * vector projected onto the plane's normal from this vector. 5154 * 5155 * @param {Vector3} planeNormal - The plane normal. 5156 * @return {Vector3} A reference to this vector. 5157 */ projectOnPlane(planeNormal) { 5158 _vector$c.copy(this).projectOnVector(planeNormal); 5159 return this.sub(_vector$c); 5160 } 5161 /** 5162 * Reflects this vector off a plane orthogonal to the given normal vector. 5163 * 5164 * @param {Vector3} normal - The (normalized) normal vector. 5165 * @return {Vector3} A reference to this vector. 5166 */ reflect(normal) { 5167 return this.sub(_vector$c.copy(normal).multiplyScalar(2 * this.dot(normal))); 5168 } 5169 /** 5170 * Returns the angle between the given vector and this instance in radians. 5171 * 5172 * @param {Vector3} v - The vector to compute the angle with. 5173 * @return {number} The angle in radians. 5174 */ angleTo(v) { 5175 const denominator = Math.sqrt(this.lengthSq() * v.lengthSq()); 5176 if (denominator === 0) return Math.PI / 2; 5177 const theta = this.dot(v) / denominator; 5178 // clamp, to handle numerical problems 5179 return Math.acos(clamp$1(theta, -1, 1)); 5180 } 5181 /** 5182 * Computes the distance from the given vector to this instance. 5183 * 5184 * @param {Vector3} v - The vector to compute the distance to. 5185 * @return {number} The distance. 5186 */ distanceTo(v) { 5187 return Math.sqrt(this.distanceToSquared(v)); 5188 } 5189 /** 5190 * Computes the squared distance from the given vector to this instance. 5191 * If you are just comparing the distance with another distance, you should compare 5192 * the distance squared instead as it is slightly more efficient to calculate. 5193 * 5194 * @param {Vector3} v - The vector to compute the squared distance to. 5195 * @return {number} The squared distance. 5196 */ distanceToSquared(v) { 5197 const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; 5198 return dx * dx + dy * dy + dz * dz; 5199 } 5200 /** 5201 * Computes the Manhattan distance from the given vector to this instance. 5202 * 5203 * @param {Vector3} v - The vector to compute the Manhattan distance to. 5204 * @return {number} The Manhattan distance. 5205 */ manhattanDistanceTo(v) { 5206 return Math.abs(this.x - v.x) + Math.abs(this.y - v.y) + Math.abs(this.z - v.z); 5207 } 5208 /** 5209 * Sets the vector components from the given spherical coordinates. 5210 * 5211 * @param {Spherical} s - The spherical coordinates. 5212 * @return {Vector3} A reference to this vector. 5213 */ setFromSpherical(s) { 5214 return this.setFromSphericalCoords(s.radius, s.phi, s.theta); 5215 } 5216 /** 5217 * Sets the vector components from the given spherical coordinates. 5218 * 5219 * @param {number} radius - The radius. 5220 * @param {number} phi - The phi angle in radians. 5221 * @param {number} theta - The theta angle in radians. 5222 * @return {Vector3} A reference to this vector. 5223 */ setFromSphericalCoords(radius, phi, theta) { 5224 const sinPhiRadius = Math.sin(phi) * radius; 5225 this.x = sinPhiRadius * Math.sin(theta); 5226 this.y = Math.cos(phi) * radius; 5227 this.z = sinPhiRadius * Math.cos(theta); 5228 return this; 5229 } 5230 /** 5231 * Sets the vector components from the given cylindrical coordinates. 5232 * 5233 * @param {Cylindrical} c - The cylindrical coordinates. 5234 * @return {Vector3} A reference to this vector. 5235 */ setFromCylindrical(c) { 5236 return this.setFromCylindricalCoords(c.radius, c.theta, c.y); 5237 } 5238 /** 5239 * Sets the vector components from the given cylindrical coordinates. 5240 * 5241 * @param {number} radius - The radius. 5242 * @param {number} theta - The theta angle in radians. 5243 * @param {number} y - The y value. 5244 * @return {Vector3} A reference to this vector. 5245 */ setFromCylindricalCoords(radius, theta, y) {
vendor: 10,316 bytes, lines 5246-5543
5246 this.x = radius * Math.sin(theta); 5247 this.y = y; 5248 this.z = radius * Math.cos(theta); 5249 return this; 5250 } 5251 /** 5252 * Sets the vector components to the position elements of the 5253 * given transformation matrix. 5254 * 5255 * @param {Matrix4} m - The 4x4 matrix. 5256 * @return {Vector3} A reference to this vector. 5257 */ setFromMatrixPosition(m) { 5258 const e = m.elements; 5259 this.x = e[12]; 5260 this.y = e[13]; 5261 this.z = e[14]; 5262 return this; 5263 } 5264 /** 5265 * Sets the vector components to the scale elements of the 5266 * given transformation matrix. 5267 * 5268 * @param {Matrix4} m - The 4x4 matrix. 5269 * @return {Vector3} A reference to this vector. 5270 */ setFromMatrixScale(m) { 5271 const sx = this.setFromMatrixColumn(m, 0).length(); 5272 const sy = this.setFromMatrixColumn(m, 1).length(); 5273 const sz = this.setFromMatrixColumn(m, 2).length(); 5274 this.x = sx; 5275 this.y = sy; 5276 this.z = sz; 5277 return this; 5278 } 5279 /** 5280 * Sets the vector components from the specified matrix column. 5281 * 5282 * @param {Matrix4} m - The 4x4 matrix. 5283 * @param {number} index - The column index. 5284 * @return {Vector3} A reference to this vector. 5285 */ setFromMatrixColumn(m, index) { 5286 return this.fromArray(m.elements, index * 4); 5287 } 5288 /** 5289 * Sets the vector components from the specified matrix column. 5290 * 5291 * @param {Matrix3} m - The 3x3 matrix. 5292 * @param {number} index - The column index. 5293 * @return {Vector3} A reference to this vector. 5294 */ setFromMatrix3Column(m, index) { 5295 return this.fromArray(m.elements, index * 3); 5296 } 5297 /** 5298 * Sets the vector components from the given Euler angles. 5299 * 5300 * @param {Euler} e - The Euler angles to set. 5301 * @return {Vector3} A reference to this vector. 5302 */ setFromEuler(e) { 5303 this.x = e._x; 5304 this.y = e._y; 5305 this.z = e._z; 5306 return this; 5307 } 5308 /** 5309 * Sets the vector components from the RGB components of the 5310 * given color. 5311 * 5312 * @param {Color} c - The color to set. 5313 * @return {Vector3} A reference to this vector. 5314 */ setFromColor(c) { 5315 this.x = c.r; 5316 this.y = c.g; 5317 this.z = c.b; 5318 return this; 5319 } 5320 /** 5321 * Returns `true` if this vector is equal with the given one. 5322 * 5323 * @param {Vector3} v - The vector to test for equality. 5324 * @return {boolean} Whether this vector is equal with the given one. 5325 */ equals(v) { 5326 return v.x === this.x && v.y === this.y && v.z === this.z; 5327 } 5328 /** 5329 * Sets this vector's x value to be `array[ offset ]`, y value to be `array[ offset + 1 ]` 5330 * and z value to be `array[ offset + 2 ]`. 5331 * 5332 * @param {Array<number>} array - An array holding the vector component values. 5333 * @param {number} [offset=0] - The offset into the array. 5334 * @return {Vector3} A reference to this vector. 5335 */ fromArray(array, offset = 0) { 5336 this.x = array[offset]; 5337 this.y = array[offset + 1]; 5338 this.z = array[offset + 2]; 5339 return this; 5340 } 5341 /** 5342 * Writes the components of this vector to the given array. If no array is provided, 5343 * the method returns a new instance. 5344 * 5345 * @param {Array<number>} [array=[]] - The target array holding the vector components. 5346 * @param {number} [offset=0] - Index of the first element in the array. 5347 * @return {Array<number>} The vector components. 5348 */ toArray(array = [], offset = 0) { 5349 array[offset] = this.x; 5350 array[offset + 1] = this.y; 5351 array[offset + 2] = this.z; 5352 return array; 5353 } 5354 /** 5355 * Sets the components of this vector from the given buffer attribute. 5356 * 5357 * @param {BufferAttribute} attribute - The buffer attribute holding vector data. 5358 * @param {number} index - The index into the attribute. 5359 * @return {Vector3} A reference to this vector. 5360 */ fromBufferAttribute(attribute, index) { 5361 this.x = attribute.getX(index); 5362 this.y = attribute.getY(index); 5363 this.z = attribute.getZ(index); 5364 return this; 5365 } 5366 /** 5367 * Sets each component of this vector to a pseudo-random value between `0` and 5368 * `1`, excluding `1`. 5369 * 5370 * @return {Vector3} A reference to this vector. 5371 */ random() { 5372 this.x = Math.random(); 5373 this.y = Math.random(); 5374 this.z = Math.random(); 5375 return this; 5376 } 5377 /** 5378 * Sets this vector to a uniformly random point on a unit sphere. 5379 * 5380 * @return {Vector3} A reference to this vector. 5381 */ randomDirection() { 5382 // https://mathworld.wolfram.com/SpherePointPicking.html 5383 const theta = Math.random() * Math.PI * 2; 5384 const u = Math.random() * 2 - 1; 5385 const c = Math.sqrt(1 - u * u); 5386 this.x = c * Math.cos(theta); 5387 this.y = u; 5388 this.z = c * Math.sin(theta); 5389 return this; 5390 } 5391 *[Symbol.iterator]() { 5392 yield this.x; 5393 yield this.y; 5394 yield this.z; 5395 } 5396 /** 5397 * Constructs a new 3D vector. 5398 * 5399 * @param {number} [x=0] - The x value of this vector. 5400 * @param {number} [y=0] - The y value of this vector. 5401 * @param {number} [z=0] - The z value of this vector. 5402 */ constructor(x = 0, y = 0, z = 0){ 5403 /** 5404 * This flag can be used for type testing. 5405 * 5406 * @type {boolean} 5407 * @readonly 5408 * @default true 5409 */ Vector3.prototype.isVector3 = true; 5410 /** 5411 * The x value of this vector. 5412 * 5413 * @type {number} 5414 */ this.x = x; 5415 /** 5416 * The y value of this vector. 5417 * 5418 * @type {number} 5419 */ this.y = y; 5420 /** 5421 * The z value of this vector. 5422 * 5423 * @type {number} 5424 */ this.z = z; 5425 } 5426 } 5427 const _vector$c = /*@__PURE__*/ new Vector3(); 5428 const _quaternion$4 = /*@__PURE__*/ new Quaternion(); 5429 /** 5430 * Represents an axis-aligned bounding box (AABB) in 3D space. 5431 */ class Box3 { 5432 /** 5433 * Sets the lower and upper boundaries of this box. 5434 * Please note that this method only copies the values from the given objects. 5435 * 5436 * @param {Vector3} min - The lower boundary of the box. 5437 * @param {Vector3} max - The upper boundary of the box. 5438 * @return {Box3} A reference to this bounding box. 5439 */ set(min, max) { 5440 this.min.copy(min); 5441 this.max.copy(max); 5442 return this; 5443 } 5444 /** 5445 * Sets the upper and lower bounds of this box so it encloses the position data 5446 * in the given array. 5447 * 5448 * @param {Array<number>} array - An array holding 3D position data. 5449 * @return {Box3} A reference to this bounding box. 5450 */ setFromArray(array) { 5451 this.makeEmpty(); 5452 for(let i = 0, il = array.length; i < il; i += 3){ 5453 this.expandByPoint(_vector$b.fromArray(array, i)); 5454 } 5455 return this; 5456 } 5457 /** 5458 * Sets the upper and lower bounds of this box so it encloses the position data 5459 * in the given buffer attribute. 5460 * 5461 * @param {BufferAttribute} attribute - A buffer attribute holding 3D position data. 5462 * @return {Box3} A reference to this bounding box. 5463 */ setFromBufferAttribute(attribute) { 5464 this.makeEmpty(); 5465 for(let i = 0, il = attribute.count; i < il; i++){ 5466 this.expandByPoint(_vector$b.fromBufferAttribute(attribute, i)); 5467 } 5468 return this; 5469 } 5470 /** 5471 * Sets the upper and lower bounds of this box so it encloses the position data 5472 * in the given array. 5473 * 5474 * @param {Array<Vector3>} points - An array holding 3D position data as instances of {@link Vector3}. 5475 * @return {Box3} A reference to this bounding box. 5476 */ setFromPoints(points) { 5477 this.makeEmpty(); 5478 for(let i = 0, il = points.length; i < il; i++){ 5479 this.expandByPoint(points[i]); 5480 } 5481 return this; 5482 } 5483 /** 5484 * Centers this box on the given center vector and sets this box's width, height and 5485 * depth to the given size values. 5486 * 5487 * @param {Vector3} center - The center of the box. 5488 * @param {Vector3} size - The x, y and z dimensions of the box. 5489 * @return {Box3} A reference to this bounding box. 5490 */ setFromCenterAndSize(center, size) { 5491 const halfSize = _vector$b.copy(size).multiplyScalar(0.5); 5492 this.min.copy(center).sub(halfSize); 5493 this.max.copy(center).add(halfSize); 5494 return this; 5495 } 5496 /** 5497 * Computes the world-axis-aligned bounding box for the given 3D object 5498 * (including its children), accounting for the object's, and children's, 5499 * world transforms. The function may result in a larger box than strictly necessary. 5500 * 5501 * @param {Object3D} object - The 3D object to compute the bounding box for. 5502 * @param {boolean} [precise=false] - If set to `true`, the method computes the smallest 5503 * world-axis-aligned bounding box at the expense of more computation. 5504 * @return {Box3} A reference to this bounding box. 5505 */ setFromObject(object, precise = false) { 5506 this.makeEmpty(); 5507 return this.expandByObject(object, precise); 5508 } 5509 /** 5510 * Returns a new box with copied values from this instance. 5511 * 5512 * @return {Box3} A clone of this instance. 5513 */ clone() { 5514 return new this.constructor().copy(this); 5515 } 5516 /** 5517 * Copies the values of the given box to this instance. 5518 * 5519 * @param {Box3} box - The box to copy. 5520 * @return {Box3} A reference to this bounding box. 5521 */ copy(box) { 5522 this.min.copy(box.min); 5523 this.max.copy(box.max); 5524 return this; 5525 } 5526 /** 5527 * Makes this box empty which means in encloses a zero space in 3D. 5528 * 5529 * @return {Box3} A reference to this bounding box. 5530 */ makeEmpty() { 5531 this.min.x = this.min.y = this.min.z = +Infinity; 5532 this.max.x = this.max.y = this.max.z = -Infinity; 5533 return this; 5534 } 5535 /** 5536 * Returns true if this box includes zero points within its bounds. 5537 * Note that a box with equal lower and upper bounds still includes one 5538 * point, the one both bounds share. 5539 * 5540 * @return {boolean} Whether this box is empty or not. 5541 */ isEmpty() { 5542 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes 5543 return this.max.x < this.min.x || this.max.y < this.min.y || this.max.z < this.min.z;
vendor: 4,397 bytes, lines 5544-5638
5544 } 5545 /** 5546 * Returns the center point of this box. 5547 * 5548 * @param {Vector3} target - The target vector that is used to store the method's result. 5549 * @return {Vector3} The center point. 5550 */ getCenter(target) { 5551 return this.isEmpty() ? target.set(0, 0, 0) : target.addVectors(this.min, this.max).multiplyScalar(0.5); 5552 } 5553 /** 5554 * Returns the dimensions of this box. 5555 * 5556 * @param {Vector3} target - The target vector that is used to store the method's result. 5557 * @return {Vector3} The size. 5558 */ getSize(target) { 5559 return this.isEmpty() ? target.set(0, 0, 0) : target.subVectors(this.max, this.min); 5560 } 5561 /** 5562 * Expands the boundaries of this box to include the given point. 5563 * 5564 * @param {Vector3} point - The point that should be included by the bounding box. 5565 * @return {Box3} A reference to this bounding box. 5566 */ expandByPoint(point) { 5567 this.min.min(point); 5568 this.max.max(point); 5569 return this; 5570 } 5571 /** 5572 * Expands this box equilaterally by the given vector. The width of this 5573 * box will be expanded by the x component of the vector in both 5574 * directions. The height of this box will be expanded by the y component of 5575 * the vector in both directions. The depth of this box will be 5576 * expanded by the z component of the vector in both directions. 5577 * 5578 * @param {Vector3} vector - The vector that should expand the bounding box. 5579 * @return {Box3} A reference to this bounding box. 5580 */ expandByVector(vector) { 5581 this.min.sub(vector); 5582 this.max.add(vector); 5583 return this; 5584 } 5585 /** 5586 * Expands each dimension of the box by the given scalar. If negative, the 5587 * dimensions of the box will be contracted. 5588 * 5589 * @param {number} scalar - The scalar value that should expand the bounding box. 5590 * @return {Box3} A reference to this bounding box. 5591 */ expandByScalar(scalar) { 5592 this.min.addScalar(-scalar); 5593 this.max.addScalar(scalar); 5594 return this; 5595 } 5596 /** 5597 * Expands the boundaries of this box to include the given 3D object and 5598 * its children, accounting for the object's, and children's, world 5599 * transforms. The function may result in a larger box than strictly 5600 * necessary (unless the precise parameter is set to true). 5601 * 5602 * @param {Object3D} object - The 3D object that should expand the bounding box. 5603 * @param {boolean} precise - If set to `true`, the method expands the bounding box 5604 * as little as necessary at the expense of more computation. 5605 * @return {Box3} A reference to this bounding box. 5606 */ expandByObject(object, precise = false) { 5607 // Computes the world-axis-aligned bounding box of an object (including its children), 5608 // accounting for both the object's, and children's, world transforms 5609 object.updateWorldMatrix(false, false); 5610 const geometry = object.geometry; 5611 if (geometry !== undefined) { 5612 const positionAttribute = geometry.getAttribute('position'); 5613 // precise AABB computation based on vertex data requires at least a position attribute. 5614 // instancing isn't supported so far and uses the normal (conservative) code path. 5615 if (precise === true && positionAttribute !== undefined && object.isInstancedMesh !== true) { 5616 for(let i = 0, l = positionAttribute.count; i < l; i++){ 5617 if (object.isMesh === true) { 5618 object.getVertexPosition(i, _vector$b); 5619 } else { 5620 _vector$b.fromBufferAttribute(positionAttribute, i); 5621 } 5622 _vector$b.applyMatrix4(object.matrixWorld); 5623 this.expandByPoint(_vector$b); 5624 } 5625 } else { 5626 if (object.boundingBox !== undefined) { 5627 // object-level bounding box 5628 if (object.boundingBox === null) { 5629 object.computeBoundingBox(); 5630 } 5631 _box$4.copy(object.boundingBox); 5632 } else { 5633 // geometry-level bounding box 5634 if (geometry.boundingBox === null) { 5635 geometry.computeBoundingBox(); 5636 } 5637 _box$4.copy(geometry.boundingBox); 5638 }
vendor: 42,855 bytes, lines 5639-6694
5639 _box$4.applyMatrix4(object.matrixWorld); 5640 this.union(_box$4); 5641 } 5642 } 5643 const children = object.children; 5644 for(let i = 0, l = children.length; i < l; i++){ 5645 this.expandByObject(children[i], precise); 5646 } 5647 return this; 5648 } 5649 /** 5650 * Returns `true` if the given point lies within or on the boundaries of this box. 5651 * 5652 * @param {Vector3} point - The point to test. 5653 * @return {boolean} Whether the bounding box contains the given point or not. 5654 */ containsPoint(point) { 5655 return point.x >= this.min.x && point.x <= this.max.x && point.y >= this.min.y && point.y <= this.max.y && point.z >= this.min.z && point.z <= this.max.z; 5656 } 5657 /** 5658 * Returns `true` if this bounding box includes the entirety of the given bounding box. 5659 * If this box and the given one are identical, this function also returns `true`. 5660 * 5661 * @param {Box3} box - The bounding box to test. 5662 * @return {boolean} Whether the bounding box contains the given bounding box or not. 5663 */ containsBox(box) { 5664 return this.min.x <= box.min.x && box.max.x <= this.max.x && this.min.y <= box.min.y && box.max.y <= this.max.y && this.min.z <= box.min.z && box.max.z <= this.max.z; 5665 } 5666 /** 5667 * Returns a point as a proportion of this box's width, height and depth. 5668 * 5669 * @param {Vector3} point - A point in 3D space. 5670 * @param {Vector3} target - The target vector that is used to store the method's result. 5671 * @return {Vector3} A point as a proportion of this box's width, height and depth. 5672 */ getParameter(point, target) { 5673 // This can potentially have a divide by zero if the box 5674 // has a size dimension of 0. 5675 return target.set((point.x - this.min.x) / (this.max.x - this.min.x), (point.y - this.min.y) / (this.max.y - this.min.y), (point.z - this.min.z) / (this.max.z - this.min.z)); 5676 } 5677 /** 5678 * Returns `true` if the given bounding box intersects with this bounding box. 5679 * 5680 * @param {Box3} box - The bounding box to test. 5681 * @return {boolean} Whether the given bounding box intersects with this bounding box. 5682 */ intersectsBox(box) { 5683 // using 6 splitting planes to rule out intersections. 5684 return box.max.x >= this.min.x && box.min.x <= this.max.x && box.max.y >= this.min.y && box.min.y <= this.max.y && box.max.z >= this.min.z && box.min.z <= this.max.z; 5685 } 5686 /** 5687 * Returns `true` if the given bounding sphere intersects with this bounding box. 5688 * 5689 * @param {Sphere} sphere - The bounding sphere to test. 5690 * @return {boolean} Whether the given bounding sphere intersects with this bounding box. 5691 */ intersectsSphere(sphere) { 5692 // Find the point on the AABB closest to the sphere center. 5693 this.clampPoint(sphere.center, _vector$b); 5694 // If that point is inside the sphere, the AABB and sphere intersect. 5695 return _vector$b.distanceToSquared(sphere.center) <= sphere.radius * sphere.radius; 5696 } 5697 /** 5698 * Returns `true` if the given plane intersects with this bounding box. 5699 * 5700 * @param {Plane} plane - The plane to test. 5701 * @return {boolean} Whether the given plane intersects with this bounding box. 5702 */ intersectsPlane(plane) { 5703 // We compute the minimum and maximum dot product values. If those values 5704 // are on the same side (back or front) of the plane, then there is no intersection. 5705 let min, max; 5706 if (plane.normal.x > 0) { 5707 min = plane.normal.x * this.min.x; 5708 max = plane.normal.x * this.max.x; 5709 } else { 5710 min = plane.normal.x * this.max.x; 5711 max = plane.normal.x * this.min.x; 5712 } 5713 if (plane.normal.y > 0) { 5714 min += plane.normal.y * this.min.y; 5715 max += plane.normal.y * this.max.y; 5716 } else { 5717 min += plane.normal.y * this.max.y; 5718 max += plane.normal.y * this.min.y; 5719 } 5720 if (plane.normal.z > 0) { 5721 min += plane.normal.z * this.min.z; 5722 max += plane.normal.z * this.max.z; 5723 } else { 5724 min += plane.normal.z * this.max.z; 5725 max += plane.normal.z * this.min.z; 5726 } 5727 return min <= -plane.constant && max >= -plane.constant; 5728 } 5729 /** 5730 * Returns `true` if the given triangle intersects with this bounding box. 5731 * 5732 * @param {Triangle} triangle - The triangle to test. 5733 * @return {boolean} Whether the given triangle intersects with this bounding box. 5734 */ intersectsTriangle(triangle) { 5735 if (this.isEmpty()) { 5736 return false; 5737 } 5738 // compute box center and extents 5739 this.getCenter(_center); 5740 _extents.subVectors(this.max, _center); 5741 // translate triangle to aabb origin 5742 _v0$2.subVectors(triangle.a, _center); 5743 _v1$7.subVectors(triangle.b, _center); 5744 _v2$4.subVectors(triangle.c, _center); 5745 // compute edge vectors for triangle 5746 _f0.subVectors(_v1$7, _v0$2); 5747 _f1.subVectors(_v2$4, _v1$7); 5748 _f2.subVectors(_v0$2, _v2$4); 5749 // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb 5750 // 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 5751 // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned) 5752 let axes = [ 5753 0, 5754 -_f0.z, 5755 _f0.y, 5756 0, 5757 -_f1.z, 5758 _f1.y, 5759 0, 5760 -_f2.z, 5761 _f2.y, 5762 _f0.z, 5763 0, 5764 -_f0.x, 5765 _f1.z, 5766 0, 5767 -_f1.x, 5768 _f2.z, 5769 0, 5770 -_f2.x, 5771 -_f0.y, 5772 _f0.x, 5773 0, 5774 -_f1.y, 5775 _f1.x, 5776 0, 5777 -_f2.y, 5778 _f2.x, 5779 0 5780 ]; 5781 if (!satForAxes(axes, _v0$2, _v1$7, _v2$4, _extents)) { 5782 return false; 5783 } 5784 // test 3 face normals from the aabb 5785 axes = [ 5786 1, 5787 0, 5788 0, 5789 0, 5790 1, 5791 0, 5792 0, 5793 0, 5794 1 5795 ]; 5796 if (!satForAxes(axes, _v0$2, _v1$7, _v2$4, _extents)) { 5797 return false; 5798 } 5799 // finally testing the face normal of the triangle 5800 // use already existing triangle edge vectors here 5801 _triangleNormal.crossVectors(_f0, _f1); 5802 axes = [ 5803 _triangleNormal.x, 5804 _triangleNormal.y, 5805 _triangleNormal.z 5806 ]; 5807 return satForAxes(axes, _v0$2, _v1$7, _v2$4, _extents); 5808 } 5809 /** 5810 * Clamps the given point within the bounds of this box. 5811 * 5812 * @param {Vector3} point - The point to clamp. 5813 * @param {Vector3} target - The target vector that is used to store the method's result. 5814 * @return {Vector3} The clamped point. 5815 */ clampPoint(point, target) { 5816 return target.copy(point).clamp(this.min, this.max); 5817 } 5818 /** 5819 * Returns the euclidean distance from any edge of this box to the specified point. If 5820 * the given point lies inside of this box, the distance will be `0`. 5821 * 5822 * @param {Vector3} point - The point to compute the distance to. 5823 * @return {number} The euclidean distance. 5824 */ distanceToPoint(point) { 5825 return this.clampPoint(point, _vector$b).distanceTo(point); 5826 } 5827 /** 5828 * Returns a bounding sphere that encloses this bounding box. 5829 * 5830 * @param {Sphere} target - The target sphere that is used to store the method's result. 5831 * @return {Sphere} The bounding sphere that encloses this bounding box. 5832 */ getBoundingSphere(target) { 5833 if (this.isEmpty()) { 5834 target.makeEmpty(); 5835 } else { 5836 this.getCenter(target.center); 5837 target.radius = this.getSize(_vector$b).length() * 0.5; 5838 } 5839 return target; 5840 } 5841 /** 5842 * Computes the intersection of this bounding box and the given one, setting the upper 5843 * bound of this box to the lesser of the two boxes' upper bounds and the 5844 * lower bound of this box to the greater of the two boxes' lower bounds. If 5845 * there's no overlap, makes this box empty. 5846 * 5847 * @param {Box3} box - The bounding box to intersect with. 5848 * @return {Box3} A reference to this bounding box. 5849 */ intersect(box) { 5850 this.min.max(box.min); 5851 this.max.min(box.max); 5852 // 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. 5853 if (this.isEmpty()) this.makeEmpty(); 5854 return this; 5855 } 5856 /** 5857 * Computes the union of this box and another and the given one, setting the upper 5858 * bound of this box to the greater of the two boxes' upper bounds and the 5859 * lower bound of this box to the lesser of the two boxes' lower bounds. 5860 * 5861 * @param {Box3} box - The bounding box that will be unioned with this instance. 5862 * @return {Box3} A reference to this bounding box. 5863 */ union(box) { 5864 this.min.min(box.min); 5865 this.max.max(box.max); 5866 return this; 5867 } 5868 /** 5869 * Transforms this bounding box by the given 4x4 transformation matrix. 5870 * 5871 * @param {Matrix4} matrix - The transformation matrix. 5872 * @return {Box3} A reference to this bounding box. 5873 */ applyMatrix4(matrix) { 5874 // transform of empty box is an empty box. 5875 if (this.isEmpty()) return this; 5876 // NOTE: I am using a binary pattern to specify all 2^3 combinations below 5877 _points[0].set(this.min.x, this.min.y, this.min.z).applyMatrix4(matrix); // 000 5878 _points[1].set(this.min.x, this.min.y, this.max.z).applyMatrix4(matrix); // 001 5879 _points[2].set(this.min.x, this.max.y, this.min.z).applyMatrix4(matrix); // 010 5880 _points[3].set(this.min.x, this.max.y, this.max.z).applyMatrix4(matrix); // 011 5881 _points[4].set(this.max.x, this.min.y, this.min.z).applyMatrix4(matrix); // 100 5882 _points[5].set(this.max.x, this.min.y, this.max.z).applyMatrix4(matrix); // 101 5883 _points[6].set(this.max.x, this.max.y, this.min.z).applyMatrix4(matrix); // 110 5884 _points[7].set(this.max.x, this.max.y, this.max.z).applyMatrix4(matrix); // 111 5885 this.setFromPoints(_points); 5886 return this; 5887 } 5888 /** 5889 * Adds the given offset to both the upper and lower bounds of this bounding box, 5890 * effectively moving it in 3D space. 5891 * 5892 * @param {Vector3} offset - The offset that should be used to translate the bounding box. 5893 * @return {Box3} A reference to this bounding box. 5894 */ translate(offset) { 5895 this.min.add(offset); 5896 this.max.add(offset); 5897 return this; 5898 } 5899 /** 5900 * Returns `true` if this bounding box is equal with the given one. 5901 * 5902 * @param {Box3} box - The box to test for equality. 5903 * @return {boolean} Whether this bounding box is equal with the given one. 5904 */ equals(box) { 5905 return box.min.equals(this.min) && box.max.equals(this.max); 5906 } 5907 /** 5908 * Constructs a new bounding box. 5909 * 5910 * @param {Vector3} [min=(Infinity,Infinity,Infinity)] - A vector representing the lower boundary of the box. 5911 * @param {Vector3} [max=(-Infinity,-Infinity,-Infinity)] - A vector representing the upper boundary of the box. 5912 */ constructor(min = new Vector3(+Infinity, +Infinity, +Infinity), max = new Vector3(-Infinity, -Infinity, -Infinity)){ 5913 /** 5914 * This flag can be used for type testing. 5915 * 5916 * @type {boolean} 5917 * @readonly 5918 * @default true 5919 */ this.isBox3 = true; 5920 /** 5921 * The lower boundary of the box. 5922 * 5923 * @type {Vector3} 5924 */ this.min = min; 5925 /** 5926 * The upper boundary of the box. 5927 * 5928 * @type {Vector3} 5929 */ this.max = max; 5930 } 5931 } 5932 const _points = [ 5933 /*@__PURE__*/ new Vector3(), 5934 /*@__PURE__*/ new Vector3(), 5935 /*@__PURE__*/ new Vector3(), 5936 /*@__PURE__*/ new Vector3(), 5937 /*@__PURE__*/ new Vector3(), 5938 /*@__PURE__*/ new Vector3(), 5939 /*@__PURE__*/ new Vector3(), 5940 /*@__PURE__*/ new Vector3() 5941 ]; 5942 const _vector$b = /*@__PURE__*/ new Vector3(); 5943 const _box$4 = /*@__PURE__*/ new Box3(); 5944 // triangle centered vertices 5945 const _v0$2 = /*@__PURE__*/ new Vector3(); 5946 const _v1$7 = /*@__PURE__*/ new Vector3(); 5947 const _v2$4 = /*@__PURE__*/ new Vector3(); 5948 // triangle edge vectors 5949 const _f0 = /*@__PURE__*/ new Vector3(); 5950 const _f1 = /*@__PURE__*/ new Vector3(); 5951 const _f2 = /*@__PURE__*/ new Vector3(); 5952 const _center = /*@__PURE__*/ new Vector3(); 5953 const _extents = /*@__PURE__*/ new Vector3(); 5954 const _triangleNormal = /*@__PURE__*/ new Vector3(); 5955 const _testAxis = /*@__PURE__*/ new Vector3(); 5956 function satForAxes(axes, v0, v1, v2, extents) { 5957 for(let i = 0, j = axes.length - 3; i <= j; i += 3){ 5958 _testAxis.fromArray(axes, i); 5959 // project the aabb onto the separating axis 5960 const r = extents.x * Math.abs(_testAxis.x) + extents.y * Math.abs(_testAxis.y) + extents.z * Math.abs(_testAxis.z); 5961 // project all 3 vertices of the triangle onto the separating axis 5962 const p0 = v0.dot(_testAxis); 5963 const p1 = v1.dot(_testAxis); 5964 const p2 = v2.dot(_testAxis); 5965 // actual test, basically see if either of the most extreme of the triangle points intersects r 5966 if (Math.max(-Math.max(p0, p1, p2), Math.min(p0, p1, p2)) > r) { 5967 // points of the projected triangle are outside the projected half-length of the aabb 5968 // the axis is separating and we can exit 5969 return false; 5970 } 5971 } 5972 return true; 5973 } 5974 const _box$3 = /*@__PURE__*/ new Box3(); 5975 const _v1$6 = /*@__PURE__*/ new Vector3(); 5976 const _v2$3 = /*@__PURE__*/ new Vector3(); 5977 /** 5978 * An analytical 3D sphere defined by a center and radius. This class is mainly 5979 * used as a Bounding Sphere for 3D objects. 5980 */ class Sphere { 5981 /** 5982 * Sets the sphere's components by copying the given values. 5983 * 5984 * @param {Vector3} center - The center. 5985 * @param {number} radius - The radius. 5986 * @return {Sphere} A reference to this sphere. 5987 */ set(center, radius) { 5988 this.center.copy(center); 5989 this.radius = radius; 5990 return this; 5991 } 5992 /** 5993 * Computes the minimum bounding sphere for list of points. 5994 * If the optional center point is given, it is used as the sphere's 5995 * center. Otherwise, the center of the axis-aligned bounding box 5996 * encompassing the points is calculated. 5997 * 5998 * @param {Array<Vector3>} points - A list of points in 3D space. 5999 * @param {Vector3} [optionalCenter] - The center of the sphere. 6000 * @return {Sphere} A reference to this sphere. 6001 */ setFromPoints(points, optionalCenter) { 6002 const center = this.center; 6003 if (optionalCenter !== undefined) { 6004 center.copy(optionalCenter); 6005 } else { 6006 _box$3.setFromPoints(points).getCenter(center); 6007 } 6008 let maxRadiusSq = 0; 6009 for(let i = 0, il = points.length; i < il; i++){ 6010 maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(points[i])); 6011 } 6012 this.radius = Math.sqrt(maxRadiusSq); 6013 return this; 6014 } 6015 /** 6016 * Copies the values of the given sphere to this instance. 6017 * 6018 * @param {Sphere} sphere - The sphere to copy. 6019 * @return {Sphere} A reference to this sphere. 6020 */ copy(sphere) { 6021 this.center.copy(sphere.center); 6022 this.radius = sphere.radius; 6023 return this; 6024 } 6025 /** 6026 * Returns `true` if the sphere is empty (the radius set to a negative number). 6027 * 6028 * Spheres with a radius of `0` contain only their center point and are not 6029 * considered to be empty. 6030 * 6031 * @return {boolean} Whether this sphere is empty or not. 6032 */ isEmpty() { 6033 return this.radius < 0; 6034 } 6035 /** 6036 * Makes this sphere empty which means in encloses a zero space in 3D. 6037 * 6038 * @return {Sphere} A reference to this sphere. 6039 */ makeEmpty() { 6040 this.center.set(0, 0, 0); 6041 this.radius = -1; 6042 return this; 6043 } 6044 /** 6045 * Returns `true` if this sphere contains the given point inclusive of 6046 * the surface of the sphere. 6047 * 6048 * @param {Vector3} point - The point to check. 6049 * @return {boolean} Whether this sphere contains the given point or not. 6050 */ containsPoint(point) { 6051 return point.distanceToSquared(this.center) <= this.radius * this.radius; 6052 } 6053 /** 6054 * Returns the closest distance from the boundary of the sphere to the 6055 * given point. If the sphere contains the point, the distance will 6056 * be negative. 6057 * 6058 * @param {Vector3} point - The point to compute the distance to. 6059 * @return {number} The distance to the point. 6060 */ distanceToPoint(point) { 6061 return point.distanceTo(this.center) - this.radius; 6062 } 6063 /** 6064 * Returns `true` if this sphere intersects with the given one. 6065 * 6066 * @param {Sphere} sphere - The sphere to test. 6067 * @return {boolean} Whether this sphere intersects with the given one or not. 6068 */ intersectsSphere(sphere) { 6069 const radiusSum = this.radius + sphere.radius; 6070 return sphere.center.distanceToSquared(this.center) <= radiusSum * radiusSum; 6071 } 6072 /** 6073 * Returns `true` if this sphere intersects with the given box. 6074 * 6075 * @param {Box3} box - The box to test. 6076 * @return {boolean} Whether this sphere intersects with the given box or not. 6077 */ intersectsBox(box) { 6078 return box.intersectsSphere(this); 6079 } 6080 /** 6081 * Returns `true` if this sphere intersects with the given plane. 6082 * 6083 * @param {Plane} plane - The plane to test. 6084 * @return {boolean} Whether this sphere intersects with the given plane or not. 6085 */ intersectsPlane(plane) { 6086 return Math.abs(plane.distanceToPoint(this.center)) <= this.radius; 6087 } 6088 /** 6089 * Clamps a point within the sphere. If the point is outside the sphere, it 6090 * will clamp it to the closest point on the edge of the sphere. Points 6091 * already inside the sphere will not be affected. 6092 * 6093 * @param {Vector3} point - The plane to clamp. 6094 * @param {Vector3} target - The target vector that is used to store the method's result. 6095 * @return {Vector3} The clamped point. 6096 */ clampPoint(point, target) { 6097 const deltaLengthSq = this.center.distanceToSquared(point); 6098 target.copy(point); 6099 if (deltaLengthSq > this.radius * this.radius) { 6100 target.sub(this.center).normalize(); 6101 target.multiplyScalar(this.radius).add(this.center); 6102 } 6103 return target; 6104 } 6105 /** 6106 * Returns a bounding box that encloses this sphere. 6107 * 6108 * @param {Box3} target - The target box that is used to store the method's result. 6109 * @return {Box3} The bounding box that encloses this sphere. 6110 */ getBoundingBox(target) { 6111 if (this.isEmpty()) { 6112 // Empty sphere produces empty bounding box 6113 target.makeEmpty(); 6114 return target; 6115 } 6116 target.set(this.center, this.center); 6117 target.expandByScalar(this.radius); 6118 return target; 6119 } 6120 /** 6121 * Transforms this sphere with the given 4x4 transformation matrix. 6122 * 6123 * @param {Matrix4} matrix - The transformation matrix. 6124 * @return {Sphere} A reference to this sphere. 6125 */ applyMatrix4(matrix) { 6126 this.center.applyMatrix4(matrix); 6127 this.radius = this.radius * matrix.getMaxScaleOnAxis(); 6128 return this; 6129 } 6130 /** 6131 * Translates the sphere's center by the given offset. 6132 * 6133 * @param {Vector3} offset - The offset. 6134 * @return {Sphere} A reference to this sphere. 6135 */ translate(offset) { 6136 this.center.add(offset); 6137 return this; 6138 } 6139 /** 6140 * Expands the boundaries of this sphere to include the given point. 6141 * 6142 * @param {Vector3} point - The point to include. 6143 * @return {Sphere} A reference to this sphere. 6144 */ expandByPoint(point) { 6145 if (this.isEmpty()) { 6146 this.center.copy(point); 6147 this.radius = 0; 6148 return this; 6149 } 6150 _v1$6.subVectors(point, this.center); 6151 const lengthSq = _v1$6.lengthSq(); 6152 if (lengthSq > this.radius * this.radius) { 6153 // calculate the minimal sphere 6154 const length = Math.sqrt(lengthSq); 6155 const delta = (length - this.radius) * 0.5; 6156 this.center.addScaledVector(_v1$6, delta / length); 6157 this.radius += delta; 6158 } 6159 return this; 6160 } 6161 /** 6162 * Expands this sphere to enclose both the original sphere and the given sphere. 6163 * 6164 * @param {Sphere} sphere - The sphere to include. 6165 * @return {Sphere} A reference to this sphere. 6166 */ union(sphere) { 6167 if (sphere.isEmpty()) { 6168 return this; 6169 } 6170 if (this.isEmpty()) { 6171 this.copy(sphere); 6172 return this; 6173 } 6174 if (this.center.equals(sphere.center) === true) { 6175 this.radius = Math.max(this.radius, sphere.radius); 6176 } else { 6177 _v2$3.subVectors(sphere.center, this.center).setLength(sphere.radius); 6178 this.expandByPoint(_v1$6.copy(sphere.center).add(_v2$3)); 6179 this.expandByPoint(_v1$6.copy(sphere.center).sub(_v2$3)); 6180 } 6181 return this; 6182 } 6183 /** 6184 * Returns `true` if this sphere is equal with the given one. 6185 * 6186 * @param {Sphere} sphere - The sphere to test for equality. 6187 * @return {boolean} Whether this bounding sphere is equal with the given one. 6188 */ equals(sphere) { 6189 return sphere.center.equals(this.center) && sphere.radius === this.radius; 6190 } 6191 /** 6192 * Returns a new sphere with copied values from this instance. 6193 * 6194 * @return {Sphere} A clone of this instance. 6195 */ clone() { 6196 return new this.constructor().copy(this); 6197 } 6198 /** 6199 * Constructs a new sphere. 6200 * 6201 * @param {Vector3} [center=(0,0,0)] - The center of the sphere 6202 * @param {number} [radius=-1] - The radius of the sphere. 6203 */ constructor(center = new Vector3(), radius = -1){ 6204 /** 6205 * This flag can be used for type testing. 6206 * 6207 * @type {boolean} 6208 * @readonly 6209 * @default true 6210 */ this.isSphere = true; 6211 /** 6212 * The center of the sphere 6213 * 6214 * @type {Vector3} 6215 */ this.center = center; 6216 /** 6217 * The radius of the sphere. 6218 * 6219 * @type {number} 6220 */ this.radius = radius; 6221 } 6222 } 6223 const _vector$a = /*@__PURE__*/ new Vector3(); 6224 const _segCenter = /*@__PURE__*/ new Vector3(); 6225 const _segDir = /*@__PURE__*/ new Vector3(); 6226 const _diff = /*@__PURE__*/ new Vector3(); 6227 const _edge1 = /*@__PURE__*/ new Vector3(); 6228 const _edge2 = /*@__PURE__*/ new Vector3(); 6229 const _normal$1 = /*@__PURE__*/ new Vector3(); 6230 /** 6231 * A ray that emits from an origin in a certain direction. The class is used by 6232 * {@link Raycaster} to assist with raycasting. Raycasting is used for 6233 * mouse picking (working out what objects in the 3D space the mouse is over) 6234 * amongst other things. 6235 */ class Ray { 6236 /** 6237 * Sets the ray's components by copying the given values. 6238 * 6239 * @param {Vector3} origin - The origin. 6240 * @param {Vector3} direction - The direction. 6241 * @return {Ray} A reference to this ray. 6242 */ set(origin, direction) { 6243 this.origin.copy(origin); 6244 this.direction.copy(direction); 6245 return this; 6246 } 6247 /** 6248 * Copies the values of the given ray to this instance. 6249 * 6250 * @param {Ray} ray - The ray to copy. 6251 * @return {Ray} A reference to this ray. 6252 */ copy(ray) { 6253 this.origin.copy(ray.origin); 6254 this.direction.copy(ray.direction); 6255 return this; 6256 } 6257 /** 6258 * Returns a vector that is located at a given distance along this ray. 6259 * 6260 * @param {number} t - The distance along the ray to retrieve a position for. 6261 * @param {Vector3} target - The target vector that is used to store the method's result. 6262 * @return {Vector3} A position on the ray. 6263 */ at(t, target) { 6264 return target.copy(this.origin).addScaledVector(this.direction, t); 6265 } 6266 /** 6267 * Adjusts the direction of the ray to point at the given vector in world space. 6268 * 6269 * @param {Vector3} v - The target position. 6270 * @return {Ray} A reference to this ray. 6271 */ lookAt(v) { 6272 this.direction.copy(v).sub(this.origin).normalize(); 6273 return this; 6274 } 6275 /** 6276 * Shift the origin of this ray along its direction by the given distance. 6277 * 6278 * @param {number} t - The distance along the ray to interpolate. 6279 * @return {Ray} A reference to this ray. 6280 */ recast(t) { 6281 this.origin.copy(this.at(t, _vector$a)); 6282 return this; 6283 } 6284 /** 6285 * Returns the point along this ray that is closest to the given point. 6286 * 6287 * @param {Vector3} point - A point in 3D space to get the closet location on the ray for. 6288 * @param {Vector3} target - The target vector that is used to store the method's result. 6289 * @return {Vector3} The closest point on this ray. 6290 */ closestPointToPoint(point, target) { 6291 target.subVectors(point, this.origin); 6292 const directionDistance = target.dot(this.direction); 6293 if (directionDistance < 0) { 6294 return target.copy(this.origin); 6295 } 6296 return target.copy(this.origin).addScaledVector(this.direction, directionDistance); 6297 } 6298 /** 6299 * Returns the distance of the closest approach between this ray and the given point. 6300 * 6301 * @param {Vector3} point - A point in 3D space to compute the distance to. 6302 * @return {number} The distance. 6303 */ distanceToPoint(point) { 6304 return Math.sqrt(this.distanceSqToPoint(point)); 6305 } 6306 /** 6307 * Returns the squared distance of the closest approach between this ray and the given point. 6308 * 6309 * @param {Vector3} point - A point in 3D space to compute the distance to. 6310 * @return {number} The squared distance. 6311 */ distanceSqToPoint(point) { 6312 const directionDistance = _vector$a.subVectors(point, this.origin).dot(this.direction); 6313 // point behind the ray 6314 if (directionDistance < 0) { 6315 return this.origin.distanceToSquared(point); 6316 } 6317 _vector$a.copy(this.origin).addScaledVector(this.direction, directionDistance); 6318 return _vector$a.distanceToSquared(point); 6319 } 6320 /** 6321 * Returns the squared distance between this ray and the given line segment. 6322 * 6323 * @param {Vector3} v0 - The start point of the line segment. 6324 * @param {Vector3} v1 - The end point of the line segment. 6325 * @param {Vector3} [optionalPointOnRay] - When provided, it receives the point on this ray that is closest to the segment. 6326 * @param {Vector3} [optionalPointOnSegment] - When provided, it receives the point on the line segment that is closest to this ray. 6327 * @return {number} The squared distance. 6328 */ distanceSqToSegment(v0, v1, optionalPointOnRay, optionalPointOnSegment) { 6329 // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteDistRaySegment.h 6330 // It returns the min distance between the ray and the segment 6331 // defined by v0 and v1 6332 // It can also set two optional targets : 6333 // - The closest point on the ray 6334 // - The closest point on the segment 6335 _segCenter.copy(v0).add(v1).multiplyScalar(0.5); 6336 _segDir.copy(v1).sub(v0).normalize(); 6337 _diff.copy(this.origin).sub(_segCenter); 6338 const segExtent = v0.distanceTo(v1) * 0.5; 6339 const a01 = -this.direction.dot(_segDir); 6340 const b0 = _diff.dot(this.direction); 6341 const b1 = -_diff.dot(_segDir); 6342 const c = _diff.lengthSq(); 6343 const det = Math.abs(1 - a01 * a01); 6344 let s0, s1, sqrDist, extDet; 6345 if (det > 0) { 6346 // The ray and segment are not parallel. 6347 s0 = a01 * b1 - b0; 6348 s1 = a01 * b0 - b1; 6349 extDet = segExtent * det; 6350 if (s0 >= 0) { 6351 if (s1 >= -extDet) { 6352 if (s1 <= extDet) { 6353 // region 0 6354 // Minimum at interior points of ray and segment. 6355 const invDet = 1 / det; 6356 s0 *= invDet; 6357 s1 *= invDet; 6358 sqrDist = s0 * (s0 + a01 * s1 + 2 * b0) + s1 * (a01 * s0 + s1 + 2 * b1) + c; 6359 } else { 6360 // region 1 6361 s1 = segExtent; 6362 s0 = Math.max(0, -(a01 * s1 + b0)); 6363 sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c; 6364 } 6365 } else { 6366 // region 5 6367 s1 = -segExtent; 6368 s0 = Math.max(0, -(a01 * s1 + b0)); 6369 sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c; 6370 } 6371 } else { 6372 if (s1 <= -extDet) { 6373 // region 4 6374 s0 = Math.max(0, -(-a01 * segExtent + b0)); 6375 s1 = s0 > 0 ? -segExtent : Math.min(Math.max(-segExtent, -b1), segExtent); 6376 sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c; 6377 } else if (s1 <= extDet) { 6378 // region 3 6379 s0 = 0; 6380 s1 = Math.min(Math.max(-segExtent, -b1), segExtent); 6381 sqrDist = s1 * (s1 + 2 * b1) + c; 6382 } else { 6383 // region 2 6384 s0 = Math.max(0, -(a01 * segExtent + b0)); 6385 s1 = s0 > 0 ? segExtent : Math.min(Math.max(-segExtent, -b1), segExtent); 6386 sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c; 6387 } 6388 } 6389 } else { 6390 // Ray and segment are parallel. 6391 s1 = a01 > 0 ? -segExtent : segExtent; 6392 s0 = Math.max(0, -(a01 * s1 + b0)); 6393 sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c; 6394 } 6395 if (optionalPointOnRay) { 6396 optionalPointOnRay.copy(this.origin).addScaledVector(this.direction, s0); 6397 } 6398 if (optionalPointOnSegment) { 6399 optionalPointOnSegment.copy(_segCenter).addScaledVector(_segDir, s1); 6400 } 6401 return sqrDist; 6402 } 6403 /** 6404 * Intersects this ray with the given sphere, returning the intersection 6405 * point or `null` if there is no intersection. 6406 * 6407 * @param {Sphere} sphere - The sphere to intersect. 6408 * @param {Vector3} target - The target vector that is used to store the method's result. 6409 * @return {?Vector3} The intersection point. 6410 */ intersectSphere(sphere, target) { 6411 _vector$a.subVectors(sphere.center, this.origin); 6412 const tca = _vector$a.dot(this.direction); 6413 const d2 = _vector$a.dot(_vector$a) - tca * tca; 6414 const radius2 = sphere.radius * sphere.radius; 6415 if (d2 > radius2) return null; 6416 const thc = Math.sqrt(radius2 - d2); 6417 // t0 = first intersect point - entrance on front of sphere 6418 const t0 = tca - thc; 6419 // t1 = second intersect point - exit point on back of sphere 6420 const t1 = tca + thc; 6421 // test to see if t1 is behind the ray - if so, return null 6422 if (t1 < 0) return null; 6423 // test to see if t0 is behind the ray: 6424 // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, 6425 // in order to always return an intersect point that is in front of the ray. 6426 if (t0 < 0) return this.at(t1, target); 6427 // else t0 is in front of the ray, so return the first collision point scaled by t0 6428 return this.at(t0, target); 6429 } 6430 /** 6431 * Returns `true` if this ray intersects with the given sphere. 6432 * 6433 * @param {Sphere} sphere - The sphere to intersect. 6434 * @return {boolean} Whether this ray intersects with the given sphere or not. 6435 */ intersectsSphere(sphere) { 6436 return this.distanceSqToPoint(sphere.center) <= sphere.radius * sphere.radius; 6437 } 6438 /** 6439 * Computes the distance from the ray's origin to the given plane. Returns `null` if the ray 6440 * does not intersect with the plane. 6441 * 6442 * @param {Plane} plane - The plane to compute the distance to. 6443 * @return {?number} Whether this ray intersects with the given sphere or not. 6444 */ distanceToPlane(plane) { 6445 const denominator = plane.normal.dot(this.direction); 6446 if (denominator === 0) { 6447 // line is coplanar, return origin 6448 if (plane.distanceToPoint(this.origin) === 0) { 6449 return 0; 6450 } 6451 // Null is preferable to undefined since undefined means.... it is undefined 6452 return null; 6453 } 6454 const t = -(this.origin.dot(plane.normal) + plane.constant) / denominator; 6455 // Return if the ray never intersects the plane 6456 return t >= 0 ? t : null; 6457 } 6458 /** 6459 * Intersects this ray with the given plane, returning the intersection 6460 * point or `null` if there is no intersection. 6461 * 6462 * @param {Plane} plane - The plane to intersect. 6463 * @param {Vector3} target - The target vector that is used to store the method's result. 6464 * @return {?Vector3} The intersection point. 6465 */ intersectPlane(plane, target) { 6466 const t = this.distanceToPlane(plane); 6467 if (t === null) { 6468 return null; 6469 } 6470 return this.at(t, target); 6471 } 6472 /** 6473 * Returns `true` if this ray intersects with the given plane. 6474 * 6475 * @param {Plane} plane - The plane to intersect. 6476 * @return {boolean} Whether this ray intersects with the given plane or not. 6477 */ intersectsPlane(plane) { 6478 // check if the ray lies on the plane first 6479 const distToPoint = plane.distanceToPoint(this.origin); 6480 if (distToPoint === 0) { 6481 return true; 6482 } 6483 const denominator = plane.normal.dot(this.direction); 6484 if (denominator * distToPoint < 0) { 6485 return true; 6486 } 6487 // ray origin is behind the plane (and is pointing behind it) 6488 return false; 6489 } 6490 /** 6491 * Intersects this ray with the given bounding box, returning the intersection 6492 * point or `null` if there is no intersection. 6493 * 6494 * @param {Box3} box - The box to intersect. 6495 * @param {Vector3} target - The target vector that is used to store the method's result. 6496 * @return {?Vector3} The intersection point. 6497 */ intersectBox(box, target) { 6498 let tmin, tmax, tymin, tymax, tzmin, tzmax; 6499 const invdirx = 1 / this.direction.x, invdiry = 1 / this.direction.y, invdirz = 1 / this.direction.z; 6500 const origin = this.origin; 6501 if (invdirx >= 0) { 6502 tmin = (box.min.x - origin.x) * invdirx; 6503 tmax = (box.max.x - origin.x) * invdirx; 6504 } else { 6505 tmin = (box.max.x - origin.x) * invdirx; 6506 tmax = (box.min.x - origin.x) * invdirx; 6507 } 6508 if (invdiry >= 0) { 6509 tymin = (box.min.y - origin.y) * invdiry; 6510 tymax = (box.max.y - origin.y) * invdiry; 6511 } else { 6512 tymin = (box.max.y - origin.y) * invdiry; 6513 tymax = (box.min.y - origin.y) * invdiry; 6514 } 6515 if (tmin > tymax || tymin > tmax) return null; 6516 if (tymin > tmin || isNaN(tmin)) tmin = tymin; 6517 if (tymax < tmax || isNaN(tmax)) tmax = tymax; 6518 if (invdirz >= 0) { 6519 tzmin = (box.min.z - origin.z) * invdirz; 6520 tzmax = (box.max.z - origin.z) * invdirz; 6521 } else { 6522 tzmin = (box.max.z - origin.z) * invdirz; 6523 tzmax = (box.min.z - origin.z) * invdirz; 6524 } 6525 if (tmin > tzmax || tzmin > tmax) return null; 6526 if (tzmin > tmin || tmin !== tmin) tmin = tzmin; 6527 if (tzmax < tmax || tmax !== tmax) tmax = tzmax; 6528 //return point closest to the ray (positive side) 6529 if (tmax < 0) return null; 6530 return this.at(tmin >= 0 ? tmin : tmax, target); 6531 } 6532 /** 6533 * Returns `true` if this ray intersects with the given box. 6534 * 6535 * @param {Box3} box - The box to intersect. 6536 * @return {boolean} Whether this ray intersects with the given box or not. 6537 */ intersectsBox(box) { 6538 return this.intersectBox(box, _vector$a) !== null; 6539 } 6540 /** 6541 * Intersects this ray with the given triangle, returning the intersection 6542 * point or `null` if there is no intersection. 6543 * 6544 * @param {Vector3} a - The first vertex of the triangle. 6545 * @param {Vector3} b - The second vertex of the triangle. 6546 * @param {Vector3} c - The third vertex of the triangle. 6547 * @param {boolean} backfaceCulling - Whether to use backface culling or not. 6548 * @param {Vector3} target - The target vector that is used to store the method's result. 6549 * @return {?Vector3} The intersection point. 6550 */ intersectTriangle(a, b, c, backfaceCulling, target) { 6551 // Compute the offset origin, edges, and normal. 6552 // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h 6553 _edge1.subVectors(b, a); 6554 _edge2.subVectors(c, a); 6555 _normal$1.crossVectors(_edge1, _edge2); 6556 // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, 6557 // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by 6558 // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) 6559 // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) 6560 // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) 6561 let DdN = this.direction.dot(_normal$1); 6562 let sign; 6563 if (DdN > 0) { 6564 if (backfaceCulling) return null; 6565 sign = 1; 6566 } else if (DdN < 0) { 6567 sign = -1; 6568 DdN = -DdN; 6569 } else { 6570 return null; 6571 } 6572 _diff.subVectors(this.origin, a); 6573 const DdQxE2 = sign * this.direction.dot(_edge2.crossVectors(_diff, _edge2)); 6574 // b1 < 0, no intersection 6575 if (DdQxE2 < 0) { 6576 return null; 6577 } 6578 const DdE1xQ = sign * this.direction.dot(_edge1.cross(_diff)); 6579 // b2 < 0, no intersection 6580 if (DdE1xQ < 0) { 6581 return null; 6582 } 6583 // b1+b2 > 1, no intersection 6584 if (DdQxE2 + DdE1xQ > DdN) { 6585 return null; 6586 } 6587 // Line intersects triangle, check if ray does. 6588 const QdN = -sign * _diff.dot(_normal$1); 6589 // t < 0, no intersection 6590 if (QdN < 0) { 6591 return null; 6592 } 6593 // Ray intersects triangle. 6594 return this.at(QdN / DdN, target); 6595 } 6596 /** 6597 * Transforms this ray with the given 4x4 transformation matrix. 6598 * 6599 * @param {Matrix4} matrix4 - The transformation matrix. 6600 * @return {Ray} A reference to this ray. 6601 */ applyMatrix4(matrix4) { 6602 this.origin.applyMatrix4(matrix4); 6603 this.direction.transformDirection(matrix4); 6604 return this; 6605 } 6606 /** 6607 * Returns `true` if this ray is equal with the given one. 6608 * 6609 * @param {Ray} ray - The ray to test for equality. 6610 * @return {boolean} Whether this ray is equal with the given one. 6611 */ equals(ray) { 6612 return ray.origin.equals(this.origin) && ray.direction.equals(this.direction); 6613 } 6614 /** 6615 * Returns a new ray with copied values from this instance. 6616 * 6617 * @return {Ray} A clone of this instance. 6618 */ clone() { 6619 return new this.constructor().copy(this); 6620 } 6621 /** 6622 * Constructs a new ray. 6623 * 6624 * @param {Vector3} [origin=(0,0,0)] - The origin of the ray. 6625 * @param {Vector3} [direction=(0,0,-1)] - The (normalized) direction of the ray. 6626 */ constructor(origin = new Vector3(), direction = new Vector3(0, 0, -1)){ 6627 /** 6628 * The origin of the ray. 6629 * 6630 * @type {Vector3} 6631 */ this.origin = origin; 6632 /** 6633 * The (normalized) direction of the ray. 6634 * 6635 * @type {Vector3} 6636 */ this.direction = direction; 6637 } 6638 } 6639 /** 6640 * Represents a 4x4 matrix. 6641 * 6642 * The most common use of a 4x4 matrix in 3D computer graphics is as a transformation matrix. 6643 * For an introduction to transformation matrices as used in WebGL, check out [this tutorial]{@link https://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices} 6644 * 6645 * This allows a 3D vector representing a point in 3D space to undergo 6646 * transformations such as translation, rotation, shear, scale, reflection, 6647 * orthogonal or perspective projection and so on, by being multiplied by the 6648 * matrix. This is known as `applying` the matrix to the vector. 6649 * 6650 * A Note on Row-Major and Column-Major Ordering: 6651 * 6652 * The constructor and {@link Matrix3#set} method take arguments in 6653 * [row-major]{@link https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order} 6654 * order, while internally they are stored in the {@link Matrix3#elements} array in column-major order. 6655 * This means that calling: 6656 * ```js 6657 * const m = new THREE.Matrix4(); 6658 * m.set( 11, 12, 13, 14, 6659 * 21, 22, 23, 24, 6660 * 31, 32, 33, 34, 6661 * 41, 42, 43, 44 ); 6662 * ``` 6663 * will result in the elements array containing: 6664 * ```js 6665 * m.elements = [ 11, 21, 31, 41, 6666 * 12, 22, 32, 42, 6667 * 13, 23, 33, 43, 6668 * 14, 24, 34, 44 ]; 6669 * ``` 6670 * and internally all calculations are performed using column-major ordering. 6671 * However, as the actual ordering makes no difference mathematically and 6672 * most people are used to thinking about matrices in row-major order, the 6673 * three.js documentation shows matrices in row-major order. Just bear in 6674 * mind that if you are reading the source code, you'll have to take the 6675 * transpose of any matrices outlined here to make sense of the calculations. 6676 */ class Matrix4 { 6677 /** 6678 * Sets the elements of the matrix.The arguments are supposed to be 6679 * in row-major order. 6680 * 6681 * @param {number} [n11] - 1-1 matrix element. 6682 * @param {number} [n12] - 1-2 matrix element. 6683 * @param {number} [n13] - 1-3 matrix element. 6684 * @param {number} [n14] - 1-4 matrix element. 6685 * @param {number} [n21] - 2-1 matrix element. 6686 * @param {number} [n22] - 2-2 matrix element. 6687 * @param {number} [n23] - 2-3 matrix element. 6688 * @param {number} [n24] - 2-4 matrix element. 6689 * @param {number} [n31] - 3-1 matrix element. 6690 * @param {number} [n32] - 3-2 matrix element. 6691 * @param {number} [n33] - 3-3 matrix element. 6692 * @param {number} [n34] - 3-4 matrix element. 6693 * @param {number} [n41] - 4-1 matrix element. 6694 * @param {number}
vendor: 4,617 bytes, lines 6694-6838
6694 [n42] - 4-2 matrix element. 6695 * @param {number} [n43] - 4-3 matrix element. 6696 * @param {number} [n44] - 4-4 matrix element. 6697 * @return {Matrix4} A reference to this matrix. 6698 */ set(n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44) { 6699 const te = this.elements; 6700 te[0] = n11; 6701 te[4] = n12; 6702 te[8] = n13; 6703 te[12] = n14; 6704 te[1] = n21; 6705 te[5] = n22; 6706 te[9] = n23; 6707 te[13] = n24; 6708 te[2] = n31; 6709 te[6] = n32; 6710 te[10] = n33; 6711 te[14] = n34; 6712 te[3] = n41; 6713 te[7] = n42; 6714 te[11] = n43; 6715 te[15] = n44; 6716 return this; 6717 } 6718 /** 6719 * Sets this matrix to the 4x4 identity matrix. 6720 * 6721 * @return {Matrix4} A reference to this matrix. 6722 */ identity() { 6723 this.set(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 6724 return this; 6725 } 6726 /** 6727 * Returns a matrix with copied values from this instance. 6728 * 6729 * @return {Matrix4} A clone of this instance. 6730 */ clone() { 6731 return new Matrix4().fromArray(this.elements); 6732 } 6733 /** 6734 * Copies the values of the given matrix to this instance. 6735 * 6736 * @param {Matrix4} m - The matrix to copy. 6737 * @return {Matrix4} A reference to this matrix. 6738 */ copy(m) { 6739 const te = this.elements; 6740 const me = m.elements; 6741 te[0] = me[0]; 6742 te[1] = me[1]; 6743 te[2] = me[2]; 6744 te[3] = me[3]; 6745 te[4] = me[4]; 6746 te[5] = me[5]; 6747 te[6] = me[6]; 6748 te[7] = me[7]; 6749 te[8] = me[8]; 6750 te[9] = me[9]; 6751 te[10] = me[10]; 6752 te[11] = me[11]; 6753 te[12] = me[12]; 6754 te[13] = me[13]; 6755 te[14] = me[14]; 6756 te[15] = me[15]; 6757 return this; 6758 } 6759 /** 6760 * Copies the translation component of the given matrix 6761 * into this matrix's translation component. 6762 * 6763 * @param {Matrix4} m - The matrix to copy the translation component. 6764 * @return {Matrix4} A reference to this matrix. 6765 */ copyPosition(m) { 6766 const te = this.elements, me = m.elements; 6767 te[12] = me[12]; 6768 te[13] = me[13]; 6769 te[14] = me[14]; 6770 return this; 6771 } 6772 /** 6773 * Set the upper 3x3 elements of this matrix to the values of given 3x3 matrix. 6774 * 6775 * @param {Matrix3} m - The 3x3 matrix. 6776 * @return {Matrix4} A reference to this matrix. 6777 */ setFromMatrix3(m) { 6778 const me = m.elements; 6779 this.set(me[0], me[3], me[6], 0, me[1], me[4], me[7], 0, me[2], me[5], me[8], 0, 0, 0, 0, 1); 6780 return this; 6781 } 6782 /** 6783 * Extracts the basis of this matrix into the three axis vectors provided. 6784 * 6785 * @param {Vector3} xAxis - The basis's x axis. 6786 * @param {Vector3} yAxis - The basis's y axis. 6787 * @param {Vector3} zAxis - The basis's z axis. 6788 * @return {Matrix4} A reference to this matrix. 6789 */ extractBasis(xAxis, yAxis, zAxis) { 6790 xAxis.setFromMatrixColumn(this, 0); 6791 yAxis.setFromMatrixColumn(this, 1); 6792 zAxis.setFromMatrixColumn(this, 2); 6793 return this; 6794 } 6795 /** 6796 * Sets the given basis vectors to this matrix. 6797 * 6798 * @param {Vector3} xAxis - The basis's x axis. 6799 * @param {Vector3} yAxis - The basis's y axis. 6800 * @param {Vector3} zAxis - The basis's z axis. 6801 * @return {Matrix4} A reference to this matrix. 6802 */ makeBasis(xAxis, yAxis, zAxis) { 6803 this.set(xAxis.x, yAxis.x, zAxis.x, 0, xAxis.y, yAxis.y, zAxis.y, 0, xAxis.z, yAxis.z, zAxis.z, 0, 0, 0, 0, 1); 6804 return this; 6805 } 6806 /** 6807 * Extracts the rotation component of the given matrix 6808 * into this matrix's rotation component. 6809 * 6810 * Note: This method does not support reflection matrices. 6811 * 6812 * @param {Matrix4} m - The matrix. 6813 * @return {Matrix4} A reference to this matrix. 6814 */ extractRotation(m) { 6815 const te = this.elements; 6816 const me = m.elements; 6817 const scaleX = 1 / _v1$5.setFromMatrixColumn(m, 0).length(); 6818 const scaleY = 1 / _v1$5.setFromMatrixColumn(m, 1).length(); 6819 const scaleZ = 1 / _v1$5.setFromMatrixColumn(m, 2).length(); 6820 te[0] = me[0] * scaleX; 6821 te[1] = me[1] * scaleX; 6822 te[2] = me[2] * scaleX; 6823 te[3] = 0; 6824 te[4] = me[4] * scaleY; 6825 te[5] = me[5] * scaleY; 6826 te[6] = me[6] * scaleY; 6827 te[7] = 0; 6828 te[8] = me[8] * scaleZ; 6829 te[9] = me[9] * scaleZ; 6830 te[10] = me[10] * scaleZ; 6831 te[11] = 0; 6832 te[12] = 0; 6833 te[13] = 0; 6834 te[14] = 0; 6835 te[15] = 1; 6836 return this; 6837 } 6838 /**
6839 * Sets the rotation component (the upper left 3x3 matrix) of this matrix to 6840 * the rotation specified by the given Euler angles. The rest of 6841 * the matrix is set to the identity. Depending on the {@link Euler#order}, 6842 * there are six possible outcomes. See [this page]{@link https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix} 6843 * for a complete list. 6844 * 6845 * @param {Euler} euler - The Euler angles. 6846 * @return {Matrix4} A reference to this matrix. 6847 */ makeRotationFromEuler(euler) { 6848 const te = this.elements; 6849 const x = euler.x, y = euler.y, z = euler.z; 6850 const a = Math.cos(x), b = Math.sin(x); 6851 const c = Math.cos(y), d = Math.sin(y); 6852 const e = Math.cos(z), f = Math.sin(z); 6853 if (euler.order === 'XYZ') { 6854 const ae = a * e, af = a * f, be = b * e, bf = b * f; 6855 te[0] = c * e; 6856 te[4] = -c * f; 6857 te[8] = d; 6858 te[1] = af + be * d; 6859 te[5] = ae - bf * d; 6860 te[9] = -b * c; 6861 te[2] = bf - ae * d; 6862 te[6] = be + af * d; 6863 te[10] = a * c; 6864 } else if (euler.order === 'YXZ') { 6865 const ce = c * e, cf = c * f, de = d * e, df = d * f; 6866 te[0] = ce + df * b; 6867 te[4] = de * b - cf; 6868 te[8] = a * d; 6869 te[1] = a * f; 6870 te[5] = a * e; 6871 te[9] = -b; 6872 te[2] = cf * b - de; 6873 te[6] = df + ce * b; 6874 te[10] = a * c; 6875 } else if (euler.order === 'ZXY') { 6876 const ce = c * e, cf = c * f, de = d * e, df = d * f; 6877 te[0] = ce - df * b; 6878 te[4] = -a * f; 6879 te[8] = de + cf * b; 6880 te[1] = cf + de * b; 6881 te[5] = a * e; 6882 te[9] = df - ce * b; 6883 te[2] = -a * d; 6884 te[6] = b; 6885 te[10] = a * c; 6886 } else if (euler.order === 'ZYX') { 6887 const ae = a * e, af = a * f, be = b * e, bf = b * f; 6888 te[0] = c * e; 6889 te[4] = be * d - af; 6890 te[8] = ae * d + bf; 6891 te[1] = c * f; 6892 te[5] = bf * d + ae; 6893 te[9] = af * d - be; 6894 te[2] = -d; 6895 te[6] = b * c; 6896 te[10] = a * c; 6897 } else if (euler.order === 'YZX') { 6898 const ac = a * c, ad = a * d, bc = b * c, bd = b * d; 6899 te[0] = c * e; 6900 te[4] = bd - ac * f; 6901 te[8] = bc * f + ad; 6902 te[1] = f; 6903 te[5] = a * e; 6904 te[9] = -b * e; 6905 te[2] = -d * e; 6906 te[6] = ad * f + bc; 6907 te[10] = ac - bd * f; 6908 } else if (euler.order === 'XZY') { 6909 const ac = a * c, ad = a * d, bc = b * c, bd = b * d; 6910 te[0] = c * e; 6911 te[4] = -f; 6912 te[8] = d * e; 6913 te[1] = ac * f + bd; 6914 te[5] = a * e; 6915 te[9] = ad * f - bc; 6916 te[2] = bc * f - ad; 6917 te[6] = b * e; 6918 te[10] = bd * f + ac; 6919 } 6920 // bottom row 6921 te[3] = 0; 6922 te[7] = 0; 6923 te[11] = 0; 6924 // last column 6925 te[12] = 0; 6926 te[13] = 0; 6927 te[14] = 0; 6928 te[15] = 1; 6929 return this; 6930 } 6931 /** 6932 * Sets the rotation component of this matrix to the rotation specified by 6933 * the given Quaternion as outlined [here]{@link https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion} 6934 * The rest of the matrix is set to the identity. 6935 * 6936 * @param {Quaternion} q - The Quaternion. 6937 * @return {Matrix4} A reference to this matrix. 6938 */ makeRotationFromQuaternion(q) { 6939 return this.compose(_zero, q, _one); 6940 } 6941 /** 6942 * Sets the rotation component of the transformation matrix, looking from `eye` towards 6943 * `target`, and oriented by the up-direction. 6944 * 6945 * @param {Vector3} eye - The eye vector. 6946 * @param {Vector3} target - The target vector. 6947 * @param {Vector3} up - The up vector. 6948 * @return {Matrix4} A reference to this matrix. 6949 */ lookAt(eye, target, up) { 6950 const te = this.elements; 6951 _z.subVectors(eye, target); 6952 if (_z.lengthSq() === 0) { 6953 // eye and target are in the same position 6954 _z.z = 1; 6955 } 6956 _z.normalize(); 6957 _x.crossVectors(up, _z); 6958 if (_x.lengthSq() === 0) { 6959 // up and z are parallel 6960 if (Math.abs(up.z) === 1) { 6961 _z.x += 0.0001; 6962 } else { 6963 _z.z += 0.0001; 6964 } 6965 _z.normalize(); 6966 _x.crossVectors(up, _z); 6967 } 6968 _x.normalize(); 6969 _y.crossVectors(_z, _x); 6970 te[0] = _x.x; 6971 te[4] = _y.x; 6972 te[8] = _z.x; 6973 te[1] = _x.y; 6974 te[5] = _y.y; 6975 te[9] = _z.y; 6976 te[2] = _x.z;
vendor: 6,220 bytes, lines 6977-7130
6977 te[6] = _y.z; 6978 te[10] = _z.z; 6979 return this; 6980 } 6981 /** 6982 * Post-multiplies this matrix by the given 4x4 matrix. 6983 * 6984 * @param {Matrix4} m - The matrix to multiply with. 6985 * @return {Matrix4} A reference to this matrix. 6986 */ multiply(m) { 6987 return this.multiplyMatrices(this, m); 6988 } 6989 /** 6990 * Pre-multiplies this matrix by the given 4x4 matrix. 6991 * 6992 * @param {Matrix4} m - The matrix to multiply with. 6993 * @return {Matrix4} A reference to this matrix. 6994 */ premultiply(m) { 6995 return this.multiplyMatrices(m, this); 6996 } 6997 /** 6998 * Multiples the given 4x4 matrices and stores the result 6999 * in this matrix. 7000 * 7001 * @param {Matrix4} a - The first matrix. 7002 * @param {Matrix4} b - The second matrix. 7003 * @return {Matrix4} A reference to this matrix. 7004 */ multiplyMatrices(a, b) { 7005 const ae = a.elements; 7006 const be = b.elements; 7007 const te = this.elements; 7008 const a11 = ae[0], a12 = ae[4], a13 = ae[8], a14 = ae[12]; 7009 const a21 = ae[1], a22 = ae[5], a23 = ae[9], a24 = ae[13]; 7010 const a31 = ae[2], a32 = ae[6], a33 = ae[10], a34 = ae[14]; 7011 const a41 = ae[3], a42 = ae[7], a43 = ae[11], a44 = ae[15]; 7012 const b11 = be[0], b12 = be[4], b13 = be[8], b14 = be[12]; 7013 const b21 = be[1], b22 = be[5], b23 = be[9], b24 = be[13]; 7014 const b31 = be[2], b32 = be[6], b33 = be[10], b34 = be[14]; 7015 const b41 = be[3], b42 = be[7], b43 = be[11], b44 = be[15]; 7016 te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; 7017 te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; 7018 te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; 7019 te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; 7020 te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; 7021 te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; 7022 te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; 7023 te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; 7024 te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; 7025 te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; 7026 te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; 7027 te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; 7028 te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; 7029 te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; 7030 te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; 7031 te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; 7032 return this; 7033 } 7034 /** 7035 * Multiplies every component of the matrix by the given scalar. 7036 * 7037 * @param {number} s - The scalar. 7038 * @return {Matrix4} A reference to this matrix. 7039 */ multiplyScalar(s) { 7040 const te = this.elements; 7041 te[0] *= s; 7042 te[4] *= s; 7043 te[8] *= s; 7044 te[12] *= s; 7045 te[1] *= s; 7046 te[5] *= s; 7047 te[9] *= s; 7048 te[13] *= s; 7049 te[2] *= s; 7050 te[6] *= s; 7051 te[10] *= s; 7052 te[14] *= s; 7053 te[3] *= s; 7054 te[7] *= s; 7055 te[11] *= s; 7056 te[15] *= s; 7057 return this; 7058 } 7059 /** 7060 * Computes and returns the determinant of this matrix. 7061 * 7062 * Based on the method outlined [here]{@link http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.html}. 7063 * 7064 * @return {number} The determinant. 7065 */ determinant() { 7066 const te = this.elements; 7067 const n11 = te[0], n12 = te[4], n13 = te[8], n14 = te[12]; 7068 const n21 = te[1], n22 = te[5], n23 = te[9], n24 = te[13]; 7069 const n31 = te[2], n32 = te[6], n33 = te[10], n34 = te[14]; 7070 const n41 = te[3], n42 = te[7], n43 = te[11], n44 = te[15]; 7071 //TODO: make this more efficient 7072 return n41 * (+n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34) + n42 * (+n11 * n23 * n34 - n11 * n24 * n33 + n14 * n21 * n33 - n13 * n21 * n34 + n13 * n24 * n31 - n14 * n23 * n31) + n43 * (+n11 * n24 * n32 - n11 * n22 * n34 - n14 * n21 * n32 + n12 * n21 * n34 + n14 * n22 * n31 - n12 * n24 * n31) + n44 * (-n13 * n22 * n31 - n11 * n23 * n32 + n11 * n22 * n33 + n13 * n21 * n32 - n12 * n21 * n33 + n12 * n23 * n31); 7073 } 7074 /** 7075 * Transposes this matrix in place. 7076 * 7077 * @return {Matrix4} A reference to this matrix. 7078 */ transpose() { 7079 const te = this.elements; 7080 let tmp; 7081 tmp = te[1]; 7082 te[1] = te[4]; 7083 te[4] = tmp; 7084 tmp = te[2]; 7085 te[2] = te[8]; 7086 te[8] = tmp; 7087 tmp = te[6]; 7088 te[6] = te[9]; 7089 te[9] = tmp; 7090 tmp = te[3]; 7091 te[3] = te[12]; 7092 te[12] = tmp; 7093 tmp = te[7]; 7094 te[7] = te[13]; 7095 te[13] = tmp; 7096 tmp = te[11]; 7097 te[11] = te[14]; 7098 te[14] = tmp; 7099 return this; 7100 } 7101 /** 7102 * Sets the position component for this matrix from the given vector, 7103 * without affecting the rest of the matrix. 7104 * 7105 * @param {number|Vector3} x - The x component of the vector or alternatively the vector object. 7106 * @param {number} y - The y component of the vector. 7107 * @param {number} z - The z component of the vector. 7108 * @return {Matrix4} A reference to this matrix. 7109 */ setPosition(x, y, z) { 7110 const te = this.elements; 7111 if (x.isVector3) { 7112 te[12] = x.x; 7113 te[13] = x.y; 7114 te[14] = x.z; 7115 } else { 7116 te[12] = x; 7117 te[13] = y; 7118 te[14] = z; 7119 } 7120 return this; 7121 } 7122 /** 7123 * Inverts this matrix, using the [analytic method]{@link https://en.wikipedia.org/wiki/Invertible_matrix#Analytic_solution}. 7124 * You can not invert with a determinant of zero. If you attempt this, the method produces 7125 * a zero matrix instead. 7126 * 7127 * @return {Matrix4} A reference to this matrix. 7128 */ invert() { 7129 // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm 7130 const te = this.elements, n11 = te[0], n21 = te[1], n31 = te[2], n41 = te[3], n12 = te[4], n22 = te[5], n32 = te[6], n42 = te[7], n13 = te[8], n23 = te[9], n33 = te[10], n43 = te[11
vendor: 12,440 bytes, lines 7130-7402
7130], n14 = te[12], n24 = te[13], n34 = te[14], n44 = te[15], t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44, t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44, t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44, t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; 7131 const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; 7132 if (det === 0) return this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 7133 const detInv = 1 / det; 7134 te[0] = t11 * detInv; 7135 te[1] = (n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44) * detInv; 7136 te[2] = (n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44) * detInv; 7137 te[3] = (n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43) * detInv; 7138 te[4] = t12 * detInv; 7139 te[5] = (n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44) * detInv; 7140 te[6] = (n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44) * detInv; 7141 te[7] = (n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43) * detInv; 7142 te[8] = t13 * detInv; 7143 te[9] = (n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44) * detInv; 7144 te[10] = (n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44) * detInv; 7145 te[11] = (n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43) * detInv; 7146 te[12] = t14 * detInv; 7147 te[13] = (n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34) * detInv; 7148 te[14] = (n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34) * detInv; 7149 te[15] = (n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33) * detInv; 7150 return this; 7151 } 7152 /** 7153 * Multiplies the columns of this matrix by the given vector. 7154 * 7155 * @param {Vector3} v - The scale vector. 7156 * @return {Matrix4} A reference to this matrix. 7157 */ scale(v) { 7158 const te = this.elements; 7159 const x = v.x, y = v.y, z = v.z; 7160 te[0] *= x; 7161 te[4] *= y; 7162 te[8] *= z; 7163 te[1] *= x; 7164 te[5] *= y; 7165 te[9] *= z; 7166 te[2] *= x; 7167 te[6] *= y; 7168 te[10] *= z; 7169 te[3] *= x; 7170 te[7] *= y; 7171 te[11] *= z; 7172 return this; 7173 } 7174 /** 7175 * Gets the maximum scale value of the three axes. 7176 * 7177 * @return {number} The maximum scale. 7178 */ getMaxScaleOnAxis() { 7179 const te = this.elements; 7180 const scaleXSq = te[0] * te[0] + te[1] * te[1] + te[2] * te[2]; 7181 const scaleYSq = te[4] * te[4] + te[5] * te[5] + te[6] * te[6]; 7182 const scaleZSq = te[8] * te[8] + te[9] * te[9] + te[10] * te[10]; 7183 return Math.sqrt(Math.max(scaleXSq, scaleYSq, scaleZSq)); 7184 } 7185 /** 7186 * Sets this matrix as a translation transform from the given vector. 7187 * 7188 * @param {number|Vector3} x - The amount to translate in the X axis or alternatively a translation vector. 7189 * @param {number} y - The amount to translate in the Y axis. 7190 * @param {number} z - The amount to translate in the z axis. 7191 * @return {Matrix4} A reference to this matrix. 7192 */ makeTranslation(x, y, z) { 7193 if (x.isVector3) { 7194 this.set(1, 0, 0, x.x, 0, 1, 0, x.y, 0, 0, 1, x.z, 0, 0, 0, 1); 7195 } else { 7196 this.set(1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z, 0, 0, 0, 1); 7197 } 7198 return this; 7199 } 7200 /** 7201 * Sets this matrix as a rotational transformation around the X axis by 7202 * the given angle. 7203 * 7204 * @param {number} theta - The rotation in radians. 7205 * @return {Matrix4} A reference to this matrix. 7206 */ makeRotationX(theta) { 7207 const c = Math.cos(theta), s = Math.sin(theta); 7208 this.set(1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1); 7209 return this; 7210 } 7211 /** 7212 * Sets this matrix as a rotational transformation around the Y axis by 7213 * the given angle. 7214 * 7215 * @param {number} theta - The rotation in radians. 7216 * @return {Matrix4} A reference to this matrix. 7217 */ makeRotationY(theta) { 7218 const c = Math.cos(theta), s = Math.sin(theta); 7219 this.set(c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1); 7220 return this; 7221 } 7222 /** 7223 * Sets this matrix as a rotational transformation around the Z axis by 7224 * the given angle. 7225 * 7226 * @param {number} theta - The rotation in radians. 7227 * @return {Matrix4} A reference to this matrix. 7228 */ makeRotationZ(theta) { 7229 const c = Math.cos(theta), s = Math.sin(theta); 7230 this.set(c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); 7231 return this; 7232 } 7233 /** 7234 * Sets this matrix as a rotational transformation around the given axis by 7235 * the given angle. 7236 * 7237 * This is a somewhat controversial but mathematically sound alternative to 7238 * rotating via Quaternions. See the discussion [here]{@link https://www.gamedev.net/articles/programming/math-and-physics/do-we-really-need-quaternions-r1199}. 7239 * 7240 * @param {Vector3} axis - The normalized rotation axis. 7241 * @param {number} angle - The rotation in radians. 7242 * @return {Matrix4} A reference to this matrix. 7243 */ makeRotationAxis(axis, angle) { 7244 // Based on http://www.gamedev.net/reference/articles/article1199.asp 7245 const c = Math.cos(angle); 7246 const s = Math.sin(angle); 7247 const t = 1 - c; 7248 const x = axis.x, y = axis.y, z = axis.z; 7249 const tx = t * x, ty = t * y; 7250 this.set(tx * x + c, tx * y - s * z, tx * z + s * y, 0, tx * y + s * z, ty * y + c, ty * z - s * x, 0, tx * z - s * y, ty * z + s * x, t * z * z + c, 0, 0, 0, 0, 1); 7251 return this; 7252 } 7253 /** 7254 * Sets this matrix as a scale transformation. 7255 * 7256 * @param {number} x - The amount to scale in the X axis. 7257 * @param {number} y - The amount to scale in the Y axis. 7258 * @param {number} z - The amount to scale in the Z axis. 7259 * @return {Matrix4} A reference to this matrix. 7260 */ makeScale(x, y, z) { 7261 this.set(x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1); 7262 return this; 7263 } 7264 /** 7265 * Sets this matrix as a shear transformation. 7266 * 7267 * @param {number} xy - The amount to shear X by Y. 7268 * @param {number} xz - The amount to shear X by Z. 7269 * @param {number} yx - The amount to shear Y by X. 7270 * @param {number} yz - The amount to shear Y by Z. 7271 * @param {number} zx - The amount to shear Z by X. 7272 * @param {number} zy - The amount to shear Z by Y. 7273 * @return {Matrix4} A reference to this matrix. 7274 */ makeShear(xy, xz, yx, yz, zx, zy) { 7275 this.set(1, yx, zx, 0, xy, 1, zy, 0, xz, yz, 1, 0, 0, 0, 0, 1); 7276 return this; 7277 } 7278 /** 7279 * Sets this matrix to the transformation composed of the given position, 7280 * rotation (Quaternion) and scale. 7281 * 7282 * @param {Vector3} position - The position vector. 7283 * @param {Quaternion} quaternion - The rotation as a Quaternion. 7284 * @param {Vector3} scale - The scale vector. 7285 * @return {Matrix4} A reference to this matrix. 7286 */ compose(position, quaternion, scale) { 7287 const te = this.elements; 7288 const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w; 7289 const x2 = x + x, y2 = y + y, z2 = z + z; 7290 const xx = x * x2, xy = x * y2, xz = x * z2; 7291 const yy = y * y2, yz = y * z2, zz = z * z2; 7292 const wx = w * x2, wy = w * y2, wz = w * z2; 7293 const sx = scale.x, sy = scale.y, sz = scale.z; 7294 te[0] = (1 - (yy + zz)) * sx; 7295 te[1] = (xy + wz) * sx; 7296 te[2] = (xz - wy) * sx; 7297 te[3] = 0; 7298 te[4] = (xy - wz) * sy; 7299 te[5] = (1 - (xx + zz)) * sy; 7300 te[6] = (yz + wx) * sy; 7301 te[7] = 0; 7302 te[8] = (xz + wy) * sz; 7303 te[9] = (yz - wx) * sz; 7304 te[10] = (1 - (xx + yy)) * sz; 7305 te[11] = 0; 7306 te[12] = position.x; 7307 te[13] = position.y; 7308 te[14] = position.z; 7309 te[15] = 1; 7310 return this; 7311 } 7312 /** 7313 * Decomposes this matrix into its position, rotation and scale components 7314 * and provides the result in the given objects. 7315 * 7316 * Note: Not all matrices are decomposable in this way. For example, if an 7317 * object has a non-uniformly scaled parent, then the object's world matrix 7318 * may not be decomposable, and this method may not be appropriate. 7319 * 7320 * @param {Vector3} position - The position vector. 7321 * @param {Quaternion} quaternion - The rotation as a Quaternion. 7322 * @param {Vector3} scale - The scale vector. 7323 * @return {Matrix4} A reference to this matrix. 7324 */ decompose(position, quaternion, scale) { 7325 const te = this.elements; 7326 let sx = _v1$5.set(te[0], te[1], te[2]).length(); 7327 const sy = _v1$5.set(te[4], te[5], te[6]).length(); 7328 const sz = _v1$5.set(te[8], te[9], te[10]).length(); 7329 // if determine is negative, we need to invert one scale 7330 const det = this.determinant(); 7331 if (det < 0) sx = -sx; 7332 position.x = te[12]; 7333 position.y = te[13]; 7334 position.z = te[14]; 7335 // scale the rotation part 7336 _m1$2.copy(this); 7337 const invSX = 1 / sx; 7338 const invSY = 1 / sy; 7339 const invSZ = 1 / sz; 7340 _m1$2.elements[0] *= invSX; 7341 _m1$2.elements[1] *= invSX; 7342 _m1$2.elements[2] *= invSX; 7343 _m1$2.elements[4] *= invSY; 7344 _m1$2.elements[5] *= invSY; 7345 _m1$2.elements[6] *= invSY; 7346 _m1$2.elements[8] *= invSZ; 7347 _m1$2.elements[9] *= invSZ; 7348 _m1$2.elements[10] *= invSZ; 7349 quaternion.setFromRotationMatrix(_m1$2); 7350 scale.x = sx; 7351 scale.y = sy; 7352 scale.z = sz; 7353 return this; 7354 } 7355 /** 7356 * Creates a perspective projection matrix. This is used internally by 7357 * {@link PerspectiveCamera#updateProjectionMatrix}. 7358 7359 * @param {number} left - Left boundary of the viewing frustum at the near plane. 7360 * @param {number} right - Right boundary of the viewing frustum at the near plane. 7361 * @param {number} top - Top boundary of the viewing frustum at the near plane. 7362 * @param {number} bottom - Bottom boundary of the viewing frustum at the near plane. 7363 * @param {number} near - The distance from the camera to the near plane. 7364 * @param {number} far - The distance from the camera to the far plane. 7365 * @param {(WebGLCoordinateSystem|WebGPUCoordinateSystem)} [coordinateSystem=WebGLCoordinateSystem] - The coordinate system. 7366 * @return {Matrix4} A reference to this matrix. 7367 */ makePerspective(left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem) { 7368 const te = this.elements; 7369 const x = 2 * near / (right - left); 7370 const y = 2 * near / (top - bottom); 7371 const a = (right + left) / (right - left); 7372 const b = (top + bottom) / (top - bottom); 7373 let c, d; 7374 if (coordinateSystem === WebGLCoordinateSystem) { 7375 c = -(far + near) / (far - near); 7376 d = -2 * far * near / (far - near); 7377 } else if (coordinateSystem === WebGPUCoordinateSystem) { 7378 c = -far / (far - near); 7379 d = -far * near / (far - near); 7380 } else { 7381 throw new Error('THREE.Matrix4.makePerspective(): Invalid coordinate system: ' + coordinateSystem); 7382 } 7383 te[0] = x; 7384 te[4] = 0; 7385 te[8] = a; 7386 te[12] = 0; 7387 te[1] = 0; 7388 te[5] = y; 7389 te[9] = b; 7390 te[13] = 0; 7391 te[2] = 0; 7392 te[6] = 0; 7393 te[10] = c; 7394 te[14] = d; 7395 te[3] = 0; 7396 te[7] = 0; 7397 te[11] = -1; 7398 te[15] = 0; 7399 return this; 7400 } 7401 /** 7402 * Creates a orthographic projection matrix. This is used internally by
7403 * {@link OrthographicCamera#updateProjectionMatrix}. 7404 7405 * @param {number} left - Left boundary of the viewing frustum at the near plane. 7406 * @param {number} right - Right boundary of the viewing frustum at the near plane. 7407 * @param {number} top - Top boundary of the viewing frustum at the near plane. 7408 * @param {number} bottom - Bottom boundary of the viewing frustum at the near plane. 7409 * @param {number} near - The distance from the camera to the near plane. 7410 * @param {number} far - The distance from the camera to the far plane. 7411 * @param {(WebGLCoordinateSystem|WebGPUCoordinateSystem)} [coordinateSystem=WebGLCoordinateSystem] - The coordinate system. 7412 * @return {Matrix4} A reference to this matrix. 7413 */ makeOrthographic(left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem) { 7414 const te = this.elements; 7415 const w = 1.0 / (right - left); 7416 const h = 1.0 / (top - bottom); 7417 const p = 1.0 / (far - near); 7418 const x = (right + left) * w; 7419 const y = (top + bottom) * h; 7420 let z, zInv; 7421 if (coordinateSystem === WebGLCoordinateSystem) { 7422 z = (far + near) * p; 7423 zInv = -2 * p; 7424 } else if (coordinateSystem === WebGPUCoordinateSystem) { 7425 z = near * p; 7426 zInv = -1 * p; 7427 } else { 7428 throw new Error('THREE.Matrix4.makeOrthographic(): Invalid coordinate system: ' + coordinateSystem); 7429 } 7430 te[0] = 2 * w; 7431 te[4] = 0; 7432 te[8] = 0; 7433 te[12] = -x; 7434 te[1] = 0; 7435 te[5] = 2 * h; 7436 te[9] = 0; 7437 te[13] = -y; 7438 te[2] = 0; 7439 te[6] = 0; 7440 te[10] = zInv; 7441 te[14] = -z; 7442 te[3] = 0; 7443 te[7] = 0; 7444 te[11] = 0; 7445 te[15] = 1; 7446 return this; 7447 } 7448 /** 7449 * Returns `true` if this matrix is equal with the given one. 7450 * 7451 * @param {Matrix4} matrix - The matrix to test for equality. 7452 * @return {boolean} Whether this matrix is equal with the given one. 7453 */ equals(matrix) { 7454 const te = this.elements; 7455 const me = matrix.elements; 7456 for(let i = 0; i < 16; i++){ 7457 if (te[i] !== me[i]) return false; 7458 } 7459 return true; 7460 } 7461 /** 7462 * Sets the elements of the matrix from the given array. 7463 * 7464 * @param {Array<number>} array - The matrix elements in column-major order. 7465 * @param {number} [offset=0] - Index of the first element in the array. 7466 * @return {Matrix4} A reference to this matrix. 7467 */ fromArray(array, offset = 0) { 7468 for(let i = 0; i < 16; i++){ 7469 this.elements[i] = array[i + offset]; 7470 } 7471 return this; 7472 } 7473 /** 7474 * Writes the elements of this matrix to the given array. If no array is provided, 7475 * the method returns a new instance. 7476 * 7477 * @param {Array<number>} [array=[]] - The target array holding the matrix elements in column-major order. 7478 * @param {number} [offset=0] - Index of the first element in the array. 7479 * @return {Array<number>} The matrix elements in column-major order. 7480 */ toArray(array = [], offset = 0) { 7481 const te = this.elements; 7482 array[offset] = te[0]; 7483 array[offset + 1] = te[1]; 7484 array[offset + 2] = te[2]; 7485 array[offset + 3] = te[3]; 7486 array[offset + 4] = te[4]; 7487 array[offset + 5] = te[5]; 7488 array[offset + 6] = te[6]; 7489 array[offset + 7] = te[7]; 7490 array[offset + 8] = te[8]; 7491 array[offset + 9] = te[9]; 7492 array[offset + 10] = te[10]; 7493 array[offset + 11] = te[11]; 7494 array[offset + 12] = te[12]; 7495 array[offset + 13] = te[13]; 7496 array[offset + 14] = te[14]; 7497 array[offset + 15] = te[15]; 7498 return array; 7499 } 7500 /** 7501 * Constructs a new 4x4 matrix. The arguments are supposed to be 7502 * in row-major order. If no arguments are provided, the constructor 7503 * initializes the matrix as an identity matrix. 7504 * 7505 * @param {number} [n11] - 1-1 matrix element. 7506 * @param {number} [n12] - 1-2 matrix element. 7507 * @param {number} [n13] - 1-3 matrix element. 7508 * @param {number} [n14] - 1-4 matrix element. 7509 * @param {number} [n21] - 2-1 matrix element. 7510 * @param {number} [n22] - 2-2 matrix element. 7511 * @param {number} [n23] - 2-3 matrix element. 7512 * @param {number} [n24] - 2-4 matrix element. 7513 * @param {number} [n31] - 3-1 matrix element. 7514 * @param {number} [n32] - 3-2 matrix element. 7515 * @param {number} [n33] - 3-3 matrix element. 7516 * @param {number} [n34] - 3-4 matrix element. 7517 * @param {number} [n41] - 4-1 matrix element. 7518 * @param {number}
7518 [n42] - 4-2 matrix element. 7519 * @param {number} [n43] - 4-3 matrix element. 7520 * @param {number} [n44] - 4-4 matrix element. 7521 */ constructor(n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44){ 7522 /** 7523 * This flag can be used for type testing. 7524 * 7525 * @type {boolean} 7526 * @readonly 7527 * @default true 7528 */ Matrix4.prototype.isMatrix4 = true; 7529 /** 7530 * A column-major list of matrix values. 7531 * 7532 * @type {Array<number>} 7533 */ this.elements = [ 7534 1, 7535 0, 7536 0, 7537 0, 7538 0, 7539 1, 7540 0, 7541 0, 7542 0, 7543 0, 7544 1, 7545 0, 7546 0, 7547 0, 7548 0, 7549 1 7550 ]; 7551 if (n11 !== undefined) { 7552 this.set(n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44); 7553 } 7554 } 7555 } 7556 const _v1$5 = /*@__PURE__*/ new Vector3(); 7557 const _m1$2 = /*@__PURE__*/ new Matrix4(); 7558 const _zero = /*@__PURE__*/ new Vector3(0, 0, 0); 7559 const _one = /*@__PURE__*/ new Vector3(1, 1, 1); 7560 const _x = /*@__PURE__*/ new Vector3(); 7561 const _y = /*@__PURE__*/ new Vector3(); 7562 const _z = /*@__PURE__*/ new Vector3(); 7563 const _matrix$2 = /*@__PURE__*/ new Matrix4(); 7564 const _quaternion$3 = /*@__PURE__*/ new Quaternion(); 7565 /** 7566 * A class representing Euler angles. 7567 * 7568 * Euler angles describe a rotational transformation by rotating an object on 7569 * its various axes in specified amounts per axis, and a specified axis 7570 * order. 7571 * 7572 * Iterating through an instance will yield its components (x, y, z, 7573 * order) in the corresponding order. 7574 * 7575 * ```js 7576 * const a = new THREE.Euler( 0, 1, 1.57, 'XYZ' ); 7577 * const b = new THREE.Vector3( 1, 0, 1 ); 7578 * b.applyEuler(a); 7579 * ``` 7580 */ class Euler { 7581 /** 7582 * The angle of the x axis in radians. 7583 * 7584 * @type {number} 7585 * @default 0 7586 */ get x() { 7587 return this._x; 7588 } 7589 set x(value) { 7590 this._x = value; 7591 this._onChangeCallback(); 7592 } 7593 /** 7594 * The angle of the y axis in radians. 7595 * 7596 * @type {number} 7597 * @default 0 7598 */ get y() { 7599 return this._y; 7600 } 7601 set y(value) { 7602 this._y = value; 7603 this._onChangeCallback(); 7604 } 7605 /** 7606 * The angle of the z axis in radians. 7607 * 7608 * @type {number} 7609 * @default 0 7610 */ get z() { 7611 return this._z; 7612 } 7613 set z(value) { 7614 this._z = value; 7615 this._onChangeCallback(); 7616 } 7617 /** 7618 * A string representing the order that the rotations are applied. 7619 * 7620 * @type {string} 7621 * @default 'XYZ' 7622 */ get order() { 7623 return this._order; 7624 } 7625 set order(value) { 7626 this._order = value; 7627 this._onChangeCallback(); 7628 } 7629 /** 7630 * Sets the Euler components. 7631 * 7632 * @param {number} x - The angle of the x axis in radians. 7633 * @param {number} y - The angle of the y axis in radians. 7634 * @param {number} z - The angle of the z axis in radians. 7635 * @param {string} [order] - A string representing the order that the rotations are applied. 7636 * @return {Euler} A reference to this Euler instance. 7637 */ set(x, y, z, order = this._order) { 7638 this._x = x; 7639 this._y = y; 7640 this._z = z; 7641 this._order = order; 7642 this._onChangeCallback(); 7643 return this; 7644 } 7645 /** 7646 * Returns a new Euler instance with copied values from this instance. 7647 * 7648 * @return {Euler} A clone of this instance. 7649 */ clone() { 7650 return new this.constructor(this._x, this._y, this._z, this._order); 7651 } 7652 /** 7653 * Copies the values of the given Euler instance to this instance. 7654 * 7655 * @param {Euler} euler - The Euler instance to copy. 7656 * @return {Euler} A reference to this Euler instance. 7657 */ copy(euler) { 7658 this._x = euler._x; 7659 this._y = euler._y; 7660 this._z = euler._z; 7661 this._order = euler._order; 7662 this._onChangeCallback(); 7663 return this; 7664 } 7665 /** 7666 * Sets the angles of this Euler instance from a pure rotation matrix. 7667 * 7668 * @param {Matrix4} m - A 4x4 matrix of which the upper 3x3 of matrix is a pure rotation matrix (i.e. unscaled). 7669 * @param {string} [order] - A string representing the order that the rotations are applied. 7670 * @param {boolean}
vendor: 9,336 bytes, lines 7670-7932
7670 [update=true] - Whether the internal `onChange` callback should be executed or not. 7671 * @return {Euler} A reference to this Euler instance. 7672 */ setFromRotationMatrix(m, order = this._order, update = true) { 7673 const te = m.elements; 7674 const m11 = te[0], m12 = te[4], m13 = te[8]; 7675 const m21 = te[1], m22 = te[5], m23 = te[9]; 7676 const m31 = te[2], m32 = te[6], m33 = te[10]; 7677 switch(order){ 7678 case 'XYZ': 7679 this._y = Math.asin(clamp$1(m13, -1, 1)); 7680 if (Math.abs(m13) < 0.9999999) { 7681 this._x = Math.atan2(-m23, m33); 7682 this._z = Math.atan2(-m12, m11); 7683 } else { 7684 this._x = Math.atan2(m32, m22); 7685 this._z = 0; 7686 } 7687 break; 7688 case 'YXZ': 7689 this._x = Math.asin(-clamp$1(m23, -1, 1)); 7690 if (Math.abs(m23) < 0.9999999) { 7691 this._y = Math.atan2(m13, m33); 7692 this._z = Math.atan2(m21, m22); 7693 } else { 7694 this._y = Math.atan2(-m31, m11); 7695 this._z = 0; 7696 } 7697 break; 7698 case 'ZXY': 7699 this._x = Math.asin(clamp$1(m32, -1, 1)); 7700 if (Math.abs(m32) < 0.9999999) { 7701 this._y = Math.atan2(-m31, m33); 7702 this._z = Math.atan2(-m12, m22); 7703 } else { 7704 this._y = 0; 7705 this._z = Math.atan2(m21, m11); 7706 } 7707 break; 7708 case 'ZYX': 7709 this._y = Math.asin(-clamp$1(m31, -1, 1)); 7710 if (Math.abs(m31) < 0.9999999) { 7711 this._x = Math.atan2(m32, m33); 7712 this._z = Math.atan2(m21, m11); 7713 } else { 7714 this._x = 0; 7715 this._z = Math.atan2(-m12, m22); 7716 } 7717 break; 7718 case 'YZX': 7719 this._z = Math.asin(clamp$1(m21, -1, 1)); 7720 if (Math.abs(m21) < 0.9999999) { 7721 this._x = Math.atan2(-m23, m22); 7722 this._y = Math.atan2(-m31, m11); 7723 } else { 7724 this._x = 0; 7725 this._y = Math.atan2(m13, m33); 7726 } 7727 break; 7728 case 'XZY': 7729 this._z = Math.asin(-clamp$1(m12, -1, 1)); 7730 if (Math.abs(m12) < 0.9999999) { 7731 this._x = Math.atan2(m32, m22); 7732 this._y = Math.atan2(m13, m11); 7733 } else { 7734 this._x = Math.atan2(-m23, m33); 7735 this._y = 0; 7736 } 7737 break; 7738 default: 7739 console.warn('THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order); 7740 } 7741 this._order = order; 7742 if (update === true) this._onChangeCallback(); 7743 return this; 7744 } 7745 /** 7746 * Sets the angles of this Euler instance from a normalized quaternion. 7747 * 7748 * @param {Quaternion} q - A normalized Quaternion. 7749 * @param {string} [order] - A string representing the order that the rotations are applied. 7750 * @param {boolean} [update=true] - Whether the internal `onChange` callback should be executed or not. 7751 * @return {Euler} A reference to this Euler instance. 7752 */ setFromQuaternion(q, order, update) { 7753 _matrix$2.makeRotationFromQuaternion(q); 7754 return this.setFromRotationMatrix(_matrix$2, order, update); 7755 } 7756 /** 7757 * Sets the angles of this Euler instance from the given vector. 7758 * 7759 * @param {Vector3} v - The vector. 7760 * @param {string} [order] - A string representing the order that the rotations are applied. 7761 * @return {Euler} A reference to this Euler instance. 7762 */ setFromVector3(v, order = this._order) { 7763 return this.set(v.x, v.y, v.z, order); 7764 } 7765 /** 7766 * Resets the euler angle with a new order by creating a quaternion from this 7767 * euler angle and then setting this euler angle with the quaternion and the 7768 * new order. 7769 * 7770 * Warning: This discards revolution information. 7771 * 7772 * @param {string} [newOrder] - A string representing the new order that the rotations are applied. 7773 * @return {Euler} A reference to this Euler instance. 7774 */ reorder(newOrder) { 7775 _quaternion$3.setFromEuler(this); 7776 return this.setFromQuaternion(_quaternion$3, newOrder); 7777 } 7778 /** 7779 * Returns `true` if this Euler instance is equal with the given one. 7780 * 7781 * @param {Euler} euler - The Euler instance to test for equality. 7782 * @return {boolean} Whether this Euler instance is equal with the given one. 7783 */ equals(euler) { 7784 return euler._x === this._x && euler._y === this._y && euler._z === this._z && euler._order === this._order; 7785 } 7786 /** 7787 * Sets this Euler instance's components to values from the given array. The first three 7788 * entries of the array are assign to the x,y and z components. An optional fourth entry 7789 * defines the Euler order. 7790 * 7791 * @param {Array<number,number,number,?string>} array - An array holding the Euler component values. 7792 * @return {Euler} A reference to this Euler instance. 7793 */ fromArray(array) { 7794 this._x = array[0]; 7795 this._y = array[1]; 7796 this._z = array[2]; 7797 if (array[3] !== undefined) this._order = array[3]; 7798 this._onChangeCallback(); 7799 return this; 7800 } 7801 /** 7802 * Writes the components of this Euler instance to the given array. If no array is provided, 7803 * the method returns a new instance. 7804 * 7805 * @param {Array<number,number,number,string>} [array=[]] - The target array holding the Euler components. 7806 * @param {number} [offset=0] - Index of the first element in the array. 7807 * @return {Array<number,number,number,string>} The Euler components. 7808 */ toArray(array = [], offset = 0) { 7809 array[offset] = this._x; 7810 array[offset + 1] = this._y; 7811 array[offset + 2] = this._z; 7812 array[offset + 3] = this._order; 7813 return array; 7814 } 7815 _onChange(callback) { 7816 this._onChangeCallback = callback; 7817 return this; 7818 } 7819 _onChangeCallback() {} 7820 *[Symbol.iterator]() { 7821 yield this._x; 7822 yield this._y; 7823 yield this._z; 7824 yield this._order; 7825 } 7826 /** 7827 * Constructs a new euler instance. 7828 * 7829 * @param {number} [x=0] - The angle of the x axis in radians. 7830 * @param {number} [y=0] - The angle of the y axis in radians. 7831 * @param {number} [z=0] - The angle of the z axis in radians. 7832 * @param {string} [order=Euler.DEFAULT_ORDER] - A string representing the order that the rotations are applied. 7833 */ constructor(x = 0, y = 0, z = 0, order = Euler.DEFAULT_ORDER){ 7834 /** 7835 * This flag can be used for type testing. 7836 * 7837 * @type {boolean} 7838 * @readonly 7839 * @default true 7840 */ this.isEuler = true; 7841 this._x = x; 7842 this._y = y; 7843 this._z = z; 7844 this._order = order; 7845 } 7846 } 7847 /** 7848 * The default Euler angle order. 7849 * 7850 * @static 7851 * @type {string} 7852 * @default 'XYZ' 7853 */ Euler.DEFAULT_ORDER = 'XYZ'; 7854 class Layers { 7855 set(channel) { 7856 this.mask = (1 << channel | 0) >>> 0; 7857 } 7858 enable(channel) { 7859 this.mask |= 1 << channel | 0; 7860 } 7861 enableAll() { 7862 this.mask = 0xffffffff | 0; 7863 } 7864 toggle(channel) { 7865 this.mask ^= 1 << channel | 0; 7866 } 7867 disable(channel) { 7868 this.mask &= ~(1 << channel | 0); 7869 } 7870 disableAll() { 7871 this.mask = 0; 7872 } 7873 test(layers) { 7874 return (this.mask & layers.mask) !== 0; 7875 } 7876 isEnabled(channel) { 7877 return (this.mask & (1 << channel | 0)) !== 0; 7878 } 7879 constructor(){ 7880 this.mask = 1 | 0; 7881 } 7882 } 7883 let _object3DId = 0; 7884 const _v1$4 = /*@__PURE__*/ new Vector3(); 7885 const _q1 = /*@__PURE__*/ new Quaternion(); 7886 const _m1$1$1 = /*@__PURE__*/ new Matrix4(); 7887 const _target = /*@__PURE__*/ new Vector3(); 7888 const _position$3 = /*@__PURE__*/ new Vector3(); 7889 const _scale$2 = /*@__PURE__*/ new Vector3(); 7890 const _quaternion$2 = /*@__PURE__*/ new Quaternion(); 7891 const _xAxis = /*@__PURE__*/ new Vector3(1, 0, 0); 7892 const _yAxis = /*@__PURE__*/ new Vector3(0, 1, 0); 7893 const _zAxis = /*@__PURE__*/ new Vector3(0, 0, 1); 7894 /** 7895 * Fires when the object has been added to its parent object. 7896 * 7897 * @event Object3D#added 7898 * @type {Object} 7899 */ const _addedEvent = { 7900 type: 'added' 7901 }; 7902 /** 7903 * Fires when the object has been removed from its parent object. 7904 * 7905 * @event Object3D#removed 7906 * @type {Object} 7907 */ const _removedEvent = { 7908 type: 'removed' 7909 }; 7910 /** 7911 * Fires when a new child object has been added. 7912 * 7913 * @event Object3D#childadded 7914 * @type {Object} 7915 */ const _childaddedEvent = { 7916 type: 'childadded', 7917 child: null 7918 }; 7919 /** 7920 * Fires when a new child object has been added. 7921 * 7922 * @event Object3D#childremoved 7923 * @type {Object} 7924 */ const _childremovedEvent = { 7925 type: 'childremoved', 7926 child: null 7927 }; 7928 /** 7929 * This is the base class for most objects in three.js and provides a set of 7930 * properties and methods for manipulating objects in 3D space. 7931 * 7932 * @augments EventDispatcher
7933 */ class Object3D extends EventDispatcher { 7934 /** 7935 * A callback that is executed immediately before a 3D object is rendered to a shadow map. 7936 * 7937 * @param {Renderer|WebGLRenderer} renderer - The renderer. 7938 * @param {Object3D} object - The 3D object. 7939 * @param {Camera} camera - The camera that is used to render the scene. 7940 * @param {Camera} shadowCamera - The shadow camera. 7941 * @param {BufferGeometry} geometry - The 3D object's geometry. 7942 * @param {Material} depthMaterial - The depth material. 7943 * @param {Object} group - The geometry group data. 7944 */ onBeforeShadow() {} 7945 /** 7946 * A callback that is executed immediately after a 3D object is rendered to a shadow map. 7947 * 7948 * @param {Renderer|WebGLRenderer} renderer - The renderer. 7949 * @param {Object3D} object - The 3D object. 7950 * @param {Camera} camera - The camera that is used to render the scene. 7951 * @param {Camera} shadowCamera - The shadow camera. 7952 * @param {BufferGeometry} geometry - The 3D object's geometry. 7953 * @param {Material} depthMaterial - The depth material. 7954 * @param {Object} group - The geometry group data. 7955 */ onAfterShadow() {} 7956 /** 7957 * A callback that is executed immediately before a 3D object is rendered. 7958 * 7959 * @param {Renderer|WebGLRenderer} renderer - The renderer. 7960 * @param {Object3D} object - The 3D object. 7961 * @param {Camera} camera - The camera that is used to render the scene. 7962 * @param {BufferGeometry} geometry - The 3D object's geometry. 7963 * @param {Material} material - The 3D object's material. 7964 * @param {Object} group - The geometry group data. 7965 */ onBeforeRender() {} 7966 /** 7967 * A callback that is executed immediately after a 3D object is rendered. 7968 * 7969 * @param {Renderer|WebGLRenderer} renderer - The renderer. 7970 * @param {Object3D} object - The 3D object. 7971 * @param {Camera} camera - The camera that is used to render the scene. 7972 * @param {BufferGeometry} geometry - The 3D object's geometry. 7973 * @param {Material} material - The 3D object's material. 7974 * @param {Object} group - The geometry group data. 7975 */ onAfterRender() {} 7976 /** 7977 * Applies the given transformation matrix to the object and updates the object's position, 7978 * rotation and scale. 7979 * 7980 * @param {Matrix4} matrix - The transformation matrix. 7981 */ applyMatrix4(matrix) { 7982 if (this.matrixAutoUpdate) this.updateMatrix(); 7983 this.matrix.premultiply(matrix); 7984 this.matrix.decompose(this.position, this.quaternion, this.scale); 7985 } 7986 /** 7987 * Applies a rotation represented by given the quaternion to the 3D object. 7988 * 7989 * @param {Quaternion} q - The quaternion. 7990 * @return {Object3D} A reference to this instance. 7991 */ applyQuaternion(q) { 7992 this.quaternion.premultiply(q); 7993 return this; 7994 } 7995 /** 7996 * Sets the given rotation represented as an axis/angle couple to the 3D object. 7997 * 7998 * @param {Vector3} axis - The (normalized) axis vector. 7999 * @param {number} angle - The angle in radians. 8000 */ setRotationFromAxisAngle(axis, angle) { 8001 // assumes axis is normalized 8002 this.quaternion.setFromAxisAngle(axis, angle); 8003 } 8004 /** 8005 * Sets the given rotation represented as Euler angles to the 3D object. 8006 * 8007 * @param {Euler} euler - The Euler angles. 8008 */ setRotationFromEuler(euler) { 8009 this.quaternion.setFromEuler(euler, true); 8010 } 8011 /** 8012 * Sets the given rotation represented as rotation matrix to the 3D object. 8013 * 8014 * @param {Matrix4} m - Although a 4x4 matrix is expected, the upper 3x3 portion must be 8015 * a pure rotation matrix (i.e, unscaled). 8016 */ setRotationFromMatrix(m) { 8017 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 8018 this.quaternion.setFromRotationMatrix(m); 8019 } 8020 /** 8021 * Sets the given rotation represented as a Quaternion to the 3D object. 8022 * 8023 * @param {Quaternion} q - The Quaternion 8024 */ setRotationFromQuaternion(q) { 8025 // assumes q is normalized 8026 this.quaternion.copy(q); 8027 } 8028 /** 8029 * Rotates the 3D object along an axis in local space. 8030 * 8031 * @param {Vector3} axis - The (normalized) axis vector. 8032 * @param {number} angle - The angle in radians. 8033 * @return {Object3D} A reference to this instance. 8034 */ rotateOnAxis(axis, angle) { 8035 // rotate object on axis in object space 8036 // axis is assumed to be normalized 8037 _q1.setFromAxisAngle(axis, angle);
vendor: 4,501 bytes, lines 8038-8156
8038 this.quaternion.multiply(_q1); 8039 return this; 8040 } 8041 /** 8042 * Rotates the 3D object along an axis in world space. 8043 * 8044 * @param {Vector3} axis - The (normalized) axis vector. 8045 * @param {number} angle - The angle in radians. 8046 * @return {Object3D} A reference to this instance. 8047 */ rotateOnWorldAxis(axis, angle) { 8048 // rotate object on axis in world space 8049 // axis is assumed to be normalized 8050 // method assumes no rotated parent 8051 _q1.setFromAxisAngle(axis, angle); 8052 this.quaternion.premultiply(_q1); 8053 return this; 8054 } 8055 /** 8056 * Rotates the 3D object around its X axis in local space. 8057 * 8058 * @param {number} angle - The angle in radians. 8059 * @return {Object3D} A reference to this instance. 8060 */ rotateX(angle) { 8061 return this.rotateOnAxis(_xAxis, angle); 8062 } 8063 /** 8064 * Rotates the 3D object around its Y axis in local space. 8065 * 8066 * @param {number} angle - The angle in radians. 8067 * @return {Object3D} A reference to this instance. 8068 */ rotateY(angle) { 8069 return this.rotateOnAxis(_yAxis, angle); 8070 } 8071 /** 8072 * Rotates the 3D object around its Z axis in local space. 8073 * 8074 * @param {number} angle - The angle in radians. 8075 * @return {Object3D} A reference to this instance. 8076 */ rotateZ(angle) { 8077 return this.rotateOnAxis(_zAxis, angle); 8078 } 8079 /** 8080 * Translate the 3D object by a distance along the given axis in local space. 8081 * 8082 * @param {Vector3} axis - The (normalized) axis vector. 8083 * @param {number} distance - The distance in world units. 8084 * @return {Object3D} A reference to this instance. 8085 */ translateOnAxis(axis, distance) { 8086 // translate object by distance along axis in object space 8087 // axis is assumed to be normalized 8088 _v1$4.copy(axis).applyQuaternion(this.quaternion); 8089 this.position.add(_v1$4.multiplyScalar(distance)); 8090 return this; 8091 } 8092 /** 8093 * Translate the 3D object by a distance along its X-axis in local space. 8094 * 8095 * @param {number} distance - The distance in world units. 8096 * @return {Object3D} A reference to this instance. 8097 */ translateX(distance) { 8098 return this.translateOnAxis(_xAxis, distance); 8099 } 8100 /** 8101 * Translate the 3D object by a distance along its Y-axis in local space. 8102 * 8103 * @param {number} distance - The distance in world units. 8104 * @return {Object3D} A reference to this instance. 8105 */ translateY(distance) { 8106 return this.translateOnAxis(_yAxis, distance); 8107 } 8108 /** 8109 * Translate the 3D object by a distance along its Z-axis in local space. 8110 * 8111 * @param {number} distance - The distance in world units. 8112 * @return {Object3D} A reference to this instance. 8113 */ translateZ(distance) { 8114 return this.translateOnAxis(_zAxis, distance); 8115 } 8116 /** 8117 * Converts the given vector from this 3D object's local space to world space. 8118 * 8119 * @param {Vector3} vector - The vector to convert. 8120 * @return {Vector3} The converted vector. 8121 */ localToWorld(vector) { 8122 this.updateWorldMatrix(true, false); 8123 return vector.applyMatrix4(this.matrixWorld); 8124 } 8125 /** 8126 * Converts the given vector from this 3D object's word space to local space. 8127 * 8128 * @param {Vector3} vector - The vector to convert. 8129 * @return {Vector3} The converted vector. 8130 */ worldToLocal(vector) { 8131 this.updateWorldMatrix(true, false); 8132 return vector.applyMatrix4(_m1$1$1.copy(this.matrixWorld).invert()); 8133 } 8134 /** 8135 * Rotates the object to face a point in world space. 8136 * 8137 * This method does not support objects having non-uniformly-scaled parent(s). 8138 * 8139 * @param {number|Vector3} x - The x coordinate in world space. Alternatively, a vector representing a position in world space 8140 * @param {number} [y] - The y coordinate in world space. 8141 * @param {number} [z] - The z coordinate in world space. 8142 */ lookAt(x, y, z) { 8143 // This method does not support objects having non-uniformly-scaled parent(s) 8144 if (x.isVector3) { 8145 _target.copy(x); 8146 } else { 8147 _target.set(x, y, z); 8148 } 8149 const parent = this.parent; 8150 this.updateWorldMatrix(true, false); 8151 _position$3.setFromMatrixPosition(this.matrixWorld); 8152 if (this.isCamera || this.isLight) { 8153 _m1$1$1.lookAt(_position$3, _target, this.up); 8154 } else { 8155 _m1$1$1.lookAt(_target, _position$3, this.up); 8156 }
vendor: 6,168 bytes, lines 8157-8315
8157 this.quaternion.setFromRotationMatrix(_m1$1$1); 8158 if (parent) { 8159 _m1$1$1.extractRotation(parent.matrixWorld); 8160 _q1.setFromRotationMatrix(_m1$1$1); 8161 this.quaternion.premultiply(_q1.invert()); 8162 } 8163 } 8164 /** 8165 * Adds the given 3D object as a child to this 3D object. An arbitrary number of 8166 * objects may be added. Any current parent on an object passed in here will be 8167 * removed, since an object can have at most one parent. 8168 * 8169 * @fires Object3D#added 8170 * @fires Object3D#childadded 8171 * @param {Object3D} object - The 3D object to add. 8172 * @return {Object3D} A reference to this instance. 8173 */ add(object) { 8174 if (arguments.length > 1) { 8175 for(let i = 0; i < arguments.length; i++){ 8176 this.add(arguments[i]); 8177 } 8178 return this; 8179 } 8180 if (object === this) { 8181 console.error('THREE.Object3D.add: object can\'t be added as a child of itself.', object); 8182 return this; 8183 } 8184 if (object && object.isObject3D) { 8185 object.removeFromParent(); 8186 object.parent = this; 8187 this.children.push(object); 8188 object.dispatchEvent(_addedEvent); 8189 _childaddedEvent.child = object; 8190 this.dispatchEvent(_childaddedEvent); 8191 _childaddedEvent.child = null; 8192 } else { 8193 console.error('THREE.Object3D.add: object not an instance of THREE.Object3D.', object); 8194 } 8195 return this; 8196 } 8197 /** 8198 * Removes the given 3D object as child from this 3D object. 8199 * An arbitrary number of objects may be removed. 8200 * 8201 * @fires Object3D#removed 8202 * @fires Object3D#childremoved 8203 * @param {Object3D} object - The 3D object to remove. 8204 * @return {Object3D} A reference to this instance. 8205 */ remove(object) { 8206 if (arguments.length > 1) { 8207 for(let i = 0; i < arguments.length; i++){ 8208 this.remove(arguments[i]); 8209 } 8210 return this; 8211 } 8212 const index = this.children.indexOf(object); 8213 if (index !== -1) { 8214 object.parent = null; 8215 this.children.splice(index, 1); 8216 object.dispatchEvent(_removedEvent); 8217 _childremovedEvent.child = object; 8218 this.dispatchEvent(_childremovedEvent); 8219 _childremovedEvent.child = null; 8220 } 8221 return this; 8222 } 8223 /** 8224 * Removes this 3D object from its current parent. 8225 * 8226 * @fires Object3D#removed 8227 * @fires Object3D#childremoved 8228 * @return {Object3D} A reference to this instance. 8229 */ removeFromParent() { 8230 const parent = this.parent; 8231 if (parent !== null) { 8232 parent.remove(this); 8233 } 8234 return this; 8235 } 8236 /** 8237 * Removes all child objects. 8238 * 8239 * @fires Object3D#removed 8240 * @fires Object3D#childremoved 8241 * @return {Object3D} A reference to this instance. 8242 */ clear() { 8243 return this.remove(...this.children); 8244 } 8245 /** 8246 * Adds the given 3D object as a child of this 3D object, while maintaining the object's world 8247 * transform. This method does not support scene graphs having non-uniformly-scaled nodes(s). 8248 * 8249 * @fires Object3D#added 8250 * @fires Object3D#childadded 8251 * @param {Object3D} object - The 3D object to attach. 8252 * @return {Object3D} A reference to this instance. 8253 */ attach(object) { 8254 // adds object as a child of this, while maintaining the object's world transform 8255 // Note: This method does not support scene graphs having non-uniformly-scaled nodes(s) 8256 this.updateWorldMatrix(true, false); 8257 _m1$1$1.copy(this.matrixWorld).invert(); 8258 if (object.parent !== null) { 8259 object.parent.updateWorldMatrix(true, false); 8260 _m1$1$1.multiply(object.parent.matrixWorld); 8261 } 8262 object.applyMatrix4(_m1$1$1); 8263 object.removeFromParent(); 8264 object.parent = this; 8265 this.children.push(object); 8266 object.updateWorldMatrix(false, true); 8267 object.dispatchEvent(_addedEvent); 8268 _childaddedEvent.child = object; 8269 this.dispatchEvent(_childaddedEvent); 8270 _childaddedEvent.child = null; 8271 return this; 8272 } 8273 /** 8274 * Searches through the 3D object and its children, starting with the 3D object 8275 * itself, and returns the first with a matching ID. 8276 * 8277 * @param {number} id - The id. 8278 * @return {Object3D|undefined} The found 3D object. Returns `undefined` if no 3D object has been found. 8279 */ getObjectById(id) { 8280 return this.getObjectByProperty('id', id); 8281 } 8282 /** 8283 * Searches through the 3D object and its children, starting with the 3D object 8284 * itself, and returns the first with a matching name. 8285 * 8286 * @param {string} name - The name. 8287 * @return {Object3D|undefined} The found 3D object. Returns `undefined` if no 3D object has been found. 8288 */ getObjectByName(name) { 8289 return this.getObjectByProperty('name', name); 8290 } 8291 /** 8292 * Searches through the 3D object and its children, starting with the 3D object 8293 * itself, and returns the first with a matching property value. 8294 * 8295 * @param {string} name - The name of the property. 8296 * @param {any} value - The value. 8297 * @return {Object3D|undefined} The found 3D object. Returns `undefined` if no 3D object has been found. 8298 */ getObjectByProperty(name, value) { 8299 if (this[name] === value) return this; 8300 for(let i = 0, l = this.children.length; i < l; i++){ 8301 const child = this.children[i]; 8302 const object = child.getObjectByProperty(name, value); 8303 if (object !== undefined) { 8304 return object; 8305 } 8306 } 8307 return undefined; 8308 } 8309 /** 8310 * Searches through the 3D object and its children, starting with the 3D object 8311 * itself, and returns all 3D objects with a matching property value. 8312 * 8313 * @param {string} name - The name of the property. 8314 * @param {any} value - The value. 8315 * @param {Array<Object3D>} result - The method stores the result in this array.
vendor: 4,394 bytes, lines 8316-8422
8316 * @return {Array<Object3D>} The found 3D objects. 8317 */ getObjectsByProperty(name, value, result = []) { 8318 if (this[name] === value) result.push(this); 8319 const children = this.children; 8320 for(let i = 0, l = children.length; i < l; i++){ 8321 children[i].getObjectsByProperty(name, value, result); 8322 } 8323 return result; 8324 } 8325 /** 8326 * Returns a vector representing the position of the 3D object in world space. 8327 * 8328 * @param {Vector3} target - The target vector the result is stored to. 8329 * @return {Vector3} The 3D object's position in world space. 8330 */ getWorldPosition(target) { 8331 this.updateWorldMatrix(true, false); 8332 return target.setFromMatrixPosition(this.matrixWorld); 8333 } 8334 /** 8335 * Returns a Quaternion representing the position of the 3D object in world space. 8336 * 8337 * @param {Quaternion} target - The target Quaternion the result is stored to. 8338 * @return {Quaternion} The 3D object's rotation in world space. 8339 */ getWorldQuaternion(target) { 8340 this.updateWorldMatrix(true, false); 8341 this.matrixWorld.decompose(_position$3, target, _scale$2); 8342 return target; 8343 } 8344 /** 8345 * Returns a vector representing the scale of the 3D object in world space. 8346 * 8347 * @param {Vector3} target - The target vector the result is stored to. 8348 * @return {Vector3} The 3D object's scale in world space. 8349 */ getWorldScale(target) { 8350 this.updateWorldMatrix(true, false); 8351 this.matrixWorld.decompose(_position$3, _quaternion$2, target); 8352 return target; 8353 } 8354 /** 8355 * Returns a vector representing the ("look") direction of the 3D object in world space. 8356 * 8357 * @param {Vector3} target - The target vector the result is stored to. 8358 * @return {Vector3} The 3D object's direction in world space. 8359 */ getWorldDirection(target) { 8360 this.updateWorldMatrix(true, false); 8361 const e = this.matrixWorld.elements; 8362 return target.set(e[8], e[9], e[10]).normalize(); 8363 } 8364 /** 8365 * Abstract method to get intersections between a casted ray and this 8366 * 3D object. Renderable 3D objects such as {@link Mesh}, {@link Line} or {@link Points} 8367 * implement this method in order to use raycasting. 8368 * 8369 * @abstract 8370 * @param {Raycaster} raycaster - The raycaster. 8371 * @param {Array<Object>} intersects - An array holding the result of the method. 8372 */ raycast() {} 8373 /** 8374 * Executes the callback on this 3D object and all descendants. 8375 * 8376 * Note: Modifying the scene graph inside the callback is discouraged. 8377 * 8378 * @param {Function} callback - A callback function that allows to process the current 3D object. 8379 */ traverse(callback) { 8380 callback(this); 8381 const children = this.children; 8382 for(let i = 0, l = children.length; i < l; i++){ 8383 children[i].traverse(callback); 8384 } 8385 } 8386 /** 8387 * Like {@link Object3D#traverse}, but the callback will only be executed for visible 3D objects. 8388 * Descendants of invisible 3D objects are not traversed. 8389 * 8390 * Note: Modifying the scene graph inside the callback is discouraged. 8391 * 8392 * @param {Function} callback - A callback function that allows to process the current 3D object. 8393 */ traverseVisible(callback) { 8394 if (this.visible === false) return; 8395 callback(this); 8396 const children = this.children; 8397 for(let i = 0, l = children.length; i < l; i++){ 8398 children[i].traverseVisible(callback); 8399 } 8400 } 8401 /** 8402 * Like {@link Object3D#traverse}, but the callback will only be executed for all ancestors. 8403 * 8404 * Note: Modifying the scene graph inside the callback is discouraged. 8405 * 8406 * @param {Function} callback - A callback function that allows to process the current 3D object. 8407 */ traverseAncestors(callback) { 8408 const parent = this.parent; 8409 if (parent !== null) { 8410 callback(parent); 8411 parent.traverseAncestors(callback); 8412 } 8413 } 8414 /** 8415 * Updates the transformation matrix in local space by computing it from the current 8416 * position, rotation and scale values. 8417 */ updateMatrix() { 8418 this.matrix.compose(this.position, this.quaternion, this.scale); 8419 this.matrixWorldNeedsUpdate = true; 8420 } 8421 /** 8422 * Updates the transformation matrix in world space of this 3D objects and its desce
8422ndants. 8423 * 8424 * To ensure correct results, this method also recomputes the 3D object's transformation matrix in 8425 * local space. The computation of the local and world matrix can be controlled with the 8426 * {@link Object3D#matrixAutoUpdate} and {@link Object3D#matrixWorldAutoUpdate} flags which are both 8427 * `true` by default. Set these flags to `false` if you need more control over the update matrix process. 8428 * 8429 * @param {boolean} [force=false] - When set to `true`, a recomputation of world matrices is forced even 8430 * when {@link Object3D#matrixWorldAutoUpdate} is set to `false`. 8431 */ updateMatrixWorld(force) { 8432 if (this.matrixAutoUpdate) this.updateMatrix(); 8433 if (this.matrixWorldNeedsUpdate || force) { 8434 if (this.matrixWorldAutoUpdate === true) { 8435 if (this.parent === null) { 8436 this.matrixWorld.copy(this.matrix); 8437 } else { 8438 this.matrixWorld.multiplyMatrices(this.parent.matrixWorld, this.matrix); 8439 } 8440 } 8441 this.matrixWorldNeedsUpdate = false; 8442 force = true; 8443 } 8444 // make sure descendants are updated if required 8445 const children = this.children; 8446 for(let i = 0, l = children.length; i < l; i++){ 8447 const child = children[i]; 8448 child.updateMatrixWorld(force); 8449 } 8450 } 8451 /** 8452 * An alternative version of {@link Object3D#updateMatrixWorld} with more control over the 8453 * update of ancestor and descendant nodes. 8454 * 8455 * @param {boolean} [updateParents=false] Whether ancestor nodes should be updated or not. 8456 * @param {boolean} [updateChildren=false] Whether descendant nodes should be updated or not. 8457 */ updateWorldMatrix(updateParents, updateChildren) { 8458 const parent = this.parent; 8459 if (updateParents === true && parent !== null) { 8460 parent.updateWorldMatrix(true, false); 8461 } 8462 if (this.matrixAutoUpdate) this.updateMatrix(); 8463 if (this.matrixWorldAutoUpdate === true) { 8464 if (this.parent === null) { 8465 this.matrixWorld.copy(this.matrix); 8466 } else { 8467 this.matrixWorld.multiplyMatrices(this.parent.matrixWorld, this.matrix); 8468 } 8469 } 8470 // make sure descendants are updated 8471 if (updateChildren === true) { 8472 const children = this.children; 8473 for(let i = 0, l = children.length; i < l; i++){ 8474 const child = children[i]; 8475 child.updateWorldMatrix(false, true); 8476 } 8477 } 8478 } 8479 /** 8480 * Serializes the 3D object into JSON. 8481 * 8482 * @param {?(Object|string)} meta - An optional value holding meta information about the serialization. 8483 * @return {Object} A JSON object representing the serialized 3D object. 8484 * @see {@link ObjectLoader#parse} 8485 */ toJSON(meta) { 8486 // meta is a string when called from JSON.stringify 8487 const isRootObject = meta === undefined || typeof meta === 'string'; 8488 const output = {}; 8489 // meta is a hash used to collect geometries, materials. 8490 // not providing it implies that this is the root object 8491 // being serialized. 8492 if (isRootObject) { 8493 // initialize meta obj 8494 meta = { 8495 geometries: {}, 8496 materials: {}, 8497 textures: {}, 8498 images: {}, 8499 shapes: {}, 8500 skeletons: {}, 8501 animations: {}, 8502 nodes: {} 8503 }; 8504 output.metadata = { 8505 version: 4.6, 8506 type: 'Object', 8507 generator: 'Object3D.toJSON' 8508 }; 8509 } 8510 // standard Object3D serialization 8511 const object = {}; 8512 object.uuid = this.uuid; 8513 object.type = this.type; 8514 if (this.name !== '') object.name = this.name; 8515 if (this.castShadow === true) object.castShadow = true; 8516 if (this.receiveShadow === true) object.receiveShadow = true; 8517 if (this.visible === false) object.visible = false;
vendor: 4,179 bytes, lines 8518-8602
8518 if (this.frustumCulled === false) object.frustumCulled = false; 8519 if (this.renderOrder !== 0) object.renderOrder = this.renderOrder; 8520 if (Object.keys(this.userData).length > 0) object.userData = this.userData; 8521 object.layers = this.layers.mask; 8522 object.matrix = this.matrix.toArray(); 8523 object.up = this.up.toArray(); 8524 if (this.matrixAutoUpdate === false) object.matrixAutoUpdate = false; 8525 // object specific properties 8526 if (this.isInstancedMesh) { 8527 object.type = 'InstancedMesh'; 8528 object.count = this.count; 8529 object.instanceMatrix = this.instanceMatrix.toJSON(); 8530 if (this.instanceColor !== null) object.instanceColor = this.instanceColor.toJSON(); 8531 } 8532 if (this.isBatchedMesh) { 8533 object.type = 'BatchedMesh'; 8534 object.perObjectFrustumCulled = this.perObjectFrustumCulled; 8535 object.sortObjects = this.sortObjects; 8536 object.drawRanges = this._drawRanges; 8537 object.reservedRanges = this._reservedRanges; 8538 object.visibility = this._visibility; 8539 object.active = this._active; 8540 object.bounds = this._bounds.map((bound)=>({ 8541 boxInitialized: bound.boxInitialized, 8542 boxMin: bound.box.min.toArray(), 8543 boxMax: bound.box.max.toArray(), 8544 sphereInitialized: bound.sphereInitialized, 8545 sphereRadius: bound.sphere.radius, 8546 sphereCenter: bound.sphere.center.toArray() 8547 })); 8548 object.maxInstanceCount = this._maxInstanceCount; 8549 object.maxVertexCount = this._maxVertexCount; 8550 object.maxIndexCount = this._maxIndexCount; 8551 object.geometryInitialized = this._geometryInitialized; 8552 object.geometryCount = this._geometryCount; 8553 object.matricesTexture = this._matricesTexture.toJSON(meta); 8554 if (this._colorsTexture !== null) object.colorsTexture = this._colorsTexture.toJSON(meta); 8555 if (this.boundingSphere !== null) { 8556 object.boundingSphere = { 8557 center: object.boundingSphere.center.toArray(), 8558 radius: object.boundingSphere.radius 8559 }; 8560 } 8561 if (this.boundingBox !== null) { 8562 object.boundingBox = { 8563 min: object.boundingBox.min.toArray(), 8564 max: object.boundingBox.max.toArray() 8565 }; 8566 } 8567 } 8568 // 8569 function serialize(library, element) { 8570 if (library[element.uuid] === undefined) { 8571 library[element.uuid] = element.toJSON(meta); 8572 } 8573 return element.uuid; 8574 } 8575 if (this.isScene) { 8576 if (this.background) { 8577 if (this.background.isColor) { 8578 object.background = this.background.toJSON(); 8579 } else if (this.background.isTexture) { 8580 object.background = this.background.toJSON(meta).uuid; 8581 } 8582 } 8583 if (this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true) { 8584 object.environment = this.environment.toJSON(meta).uuid; 8585 } 8586 } else if (this.isMesh || this.isLine || this.isPoints) { 8587 object.geometry = serialize(meta.geometries, this.geometry); 8588 const parameters = this.geometry.parameters; 8589 if (parameters !== undefined && parameters.shapes !== undefined) { 8590 const shapes = parameters.shapes; 8591 if (Array.isArray(shapes)) { 8592 for(let i = 0, l = shapes.length; i < l; i++){ 8593 const shape = shapes[i]; 8594 serialize(meta.shapes, shape); 8595 } 8596 } else { 8597 serialize(meta.shapes, shapes); 8598 } 8599 } 8600 } 8601 if (this.isSkinnedMesh) { 8602 object.bindMode = this.bindMode;
vendor: 9,652 bytes, lines 8603-8875
8603 object.bindMatrix = this.bindMatrix.toArray(); 8604 if (this.skeleton !== undefined) { 8605 serialize(meta.skeletons, this.skeleton); 8606 object.skeleton = this.skeleton.uuid; 8607 } 8608 } 8609 if (this.material !== undefined) { 8610 if (Array.isArray(this.material)) { 8611 const uuids = []; 8612 for(let i = 0, l = this.material.length; i < l; i++){ 8613 uuids.push(serialize(meta.materials, this.material[i])); 8614 } 8615 object.material = uuids; 8616 } else { 8617 object.material = serialize(meta.materials, this.material); 8618 } 8619 } 8620 // 8621 if (this.children.length > 0) { 8622 object.children = []; 8623 for(let i = 0; i < this.children.length; i++){ 8624 object.children.push(this.children[i].toJSON(meta).object); 8625 } 8626 } 8627 // 8628 if (this.animations.length > 0) { 8629 object.animations = []; 8630 for(let i = 0; i < this.animations.length; i++){ 8631 const animation = this.animations[i]; 8632 object.animations.push(serialize(meta.animations, animation)); 8633 } 8634 } 8635 if (isRootObject) { 8636 const geometries = extractFromCache(meta.geometries); 8637 const materials = extractFromCache(meta.materials); 8638 const textures = extractFromCache(meta.textures); 8639 const images = extractFromCache(meta.images); 8640 const shapes = extractFromCache(meta.shapes); 8641 const skeletons = extractFromCache(meta.skeletons); 8642 const animations = extractFromCache(meta.animations); 8643 const nodes = extractFromCache(meta.nodes); 8644 if (geometries.length > 0) output.geometries = geometries; 8645 if (materials.length > 0) output.materials = materials; 8646 if (textures.length > 0) output.textures = textures; 8647 if (images.length > 0) output.images = images; 8648 if (shapes.length > 0) output.shapes = shapes; 8649 if (skeletons.length > 0) output.skeletons = skeletons; 8650 if (animations.length > 0) output.animations = animations; 8651 if (nodes.length > 0) output.nodes = nodes; 8652 } 8653 output.object = object; 8654 return output; 8655 // extract data from the cache hash 8656 // remove metadata on each item 8657 // and return as array 8658 function extractFromCache(cache) { 8659 const values = []; 8660 for(const key in cache){ 8661 const data = cache[key]; 8662 delete data.metadata; 8663 values.push(data); 8664 } 8665 return values; 8666 } 8667 } 8668 /** 8669 * Returns a new 3D object with copied values from this instance. 8670 * 8671 * @param {boolean} [recursive=true] - When set to `true`, descendants of the 3D object are also cloned. 8672 * @return {Object3D} A clone of this instance. 8673 */ clone(recursive) { 8674 return new this.constructor().copy(this, recursive); 8675 } 8676 /** 8677 * Copies the values of the given 3D object to this instance. 8678 * 8679 * @param {Object3D} source - The 3D object to copy. 8680 * @param {boolean} [recursive=true] - When set to `true`, descendants of the 3D object are cloned. 8681 * @return {Object3D} A reference to this instance. 8682 */ copy(source, recursive = true) { 8683 this.name = source.name; 8684 this.up.copy(source.up); 8685 this.position.copy(source.position); 8686 this.rotation.order = source.rotation.order; 8687 this.quaternion.copy(source.quaternion); 8688 this.scale.copy(source.scale); 8689 this.matrix.copy(source.matrix); 8690 this.matrixWorld.copy(source.matrixWorld); 8691 this.matrixAutoUpdate = source.matrixAutoUpdate; 8692 this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate; 8693 this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; 8694 this.layers.mask = source.layers.mask; 8695 this.visible = source.visible; 8696 this.castShadow = source.castShadow; 8697 this.receiveShadow = source.receiveShadow; 8698 this.frustumCulled = source.frustumCulled; 8699 this.renderOrder = source.renderOrder; 8700 this.animations = source.animations.slice(); 8701 this.userData = JSON.parse(JSON.stringify(source.userData)); 8702 if (recursive === true) { 8703 for(let i = 0; i < source.children.length; i++){ 8704 const child = source.children[i]; 8705 this.add(child.clone()); 8706 } 8707 } 8708 return this; 8709 } 8710 /** 8711 * Constructs a new 3D object. 8712 */ constructor(){ 8713 super(); 8714 /** 8715 * This flag can be used for type testing. 8716 * 8717 * @type {boolean} 8718 * @readonly 8719 * @default true 8720 */ this.isObject3D = true; 8721 /** 8722 * The ID of the 3D object. 8723 * 8724 * @name Object3D#id 8725 * @type {number} 8726 * @readonly 8727 */ Object.defineProperty(this, 'id', { 8728 value: _object3DId++ 8729 }); 8730 /** 8731 * The UUID of the 3D object. 8732 * 8733 * @type {string} 8734 * @readonly 8735 */ this.uuid = generateUUID(); 8736 /** 8737 * The name of the 3D object. 8738 * 8739 * @type {string} 8740 */ this.name = ''; 8741 /** 8742 * The type property is used for detecting the object type 8743 * in context of serialization/deserialization. 8744 * 8745 * @type {string} 8746 * @readonly 8747 */ this.type = 'Object3D'; 8748 /** 8749 * A reference to the parent object. 8750 * 8751 * @type {?Object3D} 8752 * @default null 8753 */ this.parent = null; 8754 /** 8755 * An array holding the child 3D objects of this instance. 8756 * 8757 * @type {Array<Object3D>} 8758 */ this.children = []; 8759 /** 8760 * Defines the `up` direction of the 3D object which influences 8761 * the orientation via methods like {@link Object3D#lookAt}. 8762 * 8763 * The default values for all 3D objects is defined by `Object3D.DEFAULT_UP`. 8764 * 8765 * @type {Vector3} 8766 */ this.up = Object3D.DEFAULT_UP.clone(); 8767 const position = new Vector3(); 8768 const rotation = new Euler(); 8769 const quaternion = new Quaternion(); 8770 const scale = new Vector3(1, 1, 1); 8771 function onRotationChange() { 8772 quaternion.setFromEuler(rotation, false); 8773 } 8774 function onQuaternionChange() { 8775 rotation.setFromQuaternion(quaternion, undefined, false); 8776 } 8777 rotation._onChange(onRotationChange); 8778 quaternion._onChange(onQuaternionChange); 8779 Object.defineProperties(this, { 8780 /** 8781 * Represents the object's local position. 8782 * 8783 * @name Object3D#position 8784 * @type {Vector3} 8785 * @default (0,0,0) 8786 */ position: { 8787 configurable: true, 8788 enumerable: true, 8789 value: position 8790 }, 8791 /** 8792 * Represents the object's local rotation as Euler angles, in radians. 8793 * 8794 * @name Object3D#rotation 8795 * @type {Euler} 8796 * @default (0,0,0) 8797 */ rotation: { 8798 configurable: true, 8799 enumerable: true, 8800 value: rotation 8801 }, 8802 /** 8803 * Represents the object's local rotation as Quaternions. 8804 * 8805 * @name Object3D#quaternion 8806 * @type {Quaternion} 8807 */ quaternion: { 8808 configurable: true, 8809 enumerable: true, 8810 value: quaternion 8811 }, 8812 /** 8813 * Represents the object's local scale. 8814 * 8815 * @name Object3D#scale 8816 * @type {Vector3} 8817 * @default (1,1,1) 8818 */ scale: { 8819 configurable: true, 8820 enumerable: true, 8821 value: scale 8822 }, 8823 /** 8824 * Represents the object's model-view matrix. 8825 * 8826 * @name Object3D#modelViewMatrix 8827 * @type {Matrix4} 8828 */ modelViewMatrix: { 8829 value: new Matrix4() 8830 }, 8831 /** 8832 * Represents the object's normal matrix. 8833 * 8834 * @name Object3D#normalMatrix 8835 * @type {Matrix3} 8836 */ normalMatrix: { 8837 value: new Matrix3() 8838 } 8839 }); 8840 /** 8841 * Represents the object's transformation matrix in local space. 8842 * 8843 * @type {Matrix4} 8844 */ this.matrix = new Matrix4(); 8845 /** 8846 * Represents the object's transformation matrix in world space. 8847 * If the 3D object has no parent, then it's identical to the local transformation matrix 8848 * 8849 * @type {Matrix4} 8850 */ this.matrixWorld = new Matrix4(); 8851 /** 8852 * When set to `true`, the engine automatically computes the local matrix from position, 8853 * rotation and scale every frame. 8854 * 8855 * The default values for all 3D objects is defined by `Object3D.DEFAULT_MATRIX_AUTO_UPDATE`. 8856 * 8857 * @type {boolean} 8858 * @default true 8859 */ this.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE; 8860 /** 8861 * When set to `true`, the engine automatically computes the world matrix from the current local 8862 * matrix and the object's transformation hierarchy. 8863 * 8864 * The default values for all 3D objects is defined by `Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE`. 8865 * 8866 * @type {boolean} 8867 * @default true 8868 */ this.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE; // checked by the renderer 8869 /** 8870 * When set to `true`, it calculates the world matrix in that frame and resets this property 8871 * to `false`. 8872 * 8873 * @type {boolean} 8874 * @default false 8875 */ this.matrixWorldNeedsUpdate = false;
8876 /** 8877 * The layer membership of the 3D object. The 3D object is only visible if it has 8878 * at least one layer in common with the camera in use. This property can also be 8879 * used to filter out unwanted objects in ray-intersection tests when using {@link Raycaster}. 8880 * 8881 * @type {Layers} 8882 */ this.layers = new Layers(); 8883 /** 8884 * When set to `true`, the 3D object gets rendered. 8885 * 8886 * @type {boolean} 8887 * @default true 8888 */ this.visible = true; 8889 /** 8890 * When set to `true`, the 3D object gets rendered into shadow maps. 8891 * 8892 * @type {boolean} 8893 * @default false 8894 */ this.castShadow = false; 8895 /** 8896 * When set to `true`, the 3D object is affected by shadows in the scene. 8897 * 8898 * @type {boolean} 8899 * @default false 8900 */ this.receiveShadow = false; 8901 /** 8902 * When set to `true`, the 3D object is honored by view frustum culling. 8903 * 8904 * @type {boolean} 8905 * @default true 8906 */ this.frustumCulled = true; 8907 /** 8908 * This value allows the default rendering order of scene graph objects to be 8909 * overridden although opaque and transparent objects remain sorted independently. 8910 * When this property is set for an instance of {@link Group},all descendants 8911 * objects will be sorted and rendered together. Sorting is from lowest to highest 8912 * render order. 8913 * 8914 * @type {number} 8915 * @default 0 8916 */ this.renderOrder = 0; 8917 /** 8918 * An array holding the animation clips of the 3D object. 8919 * 8920 * @type {Array<AnimationClip>} 8921 */ this.animations = []; 8922 /** 8923 * An object that can be used to store custom data about the 3D object. It 8924 * should not hold references to functions as these will not be cloned. 8925 * 8926 * @type {Object} 8927 */ this.userData = {}; 8928 } 8929 } 8930 /** 8931 * The default up direction for objects, also used as the default 8932 * position for {@link DirectionalLight} and {@link HemisphereLight}. 8933 * 8934 * @static 8935 * @type {Vector3} 8936 * @default (0,1,0) 8937 */ Object3D.DEFAULT_UP = /*@__PURE__*/ new Vector3(0, 1, 0); 8938 /** 8939 * The default setting for {@link Object3D#matrixAutoUpdate} for 8940 * newly created 3D objects. 8941 * 8942 * @static 8943 * @type {boolean} 8944 * @default true 8945 */ Object3D.DEFAULT_MATRIX_AUTO_UPDATE = true; 8946 /** 8947 * The default setting for {@link Object3D#matrixWorldAutoUpdate} for 8948 * newly created 3D objects. 8949 * 8950 * @static 8951 * @type {boolean} 8952 * @default true 8953 */ Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = true; 8954 const _v0$1 = /*@__PURE__*/ new Vector3(); 8955 const _v1$3 = /*@__PURE__*/ new Vector3(); 8956 const _v2$2 = /*@__PURE__*/ new Vector3(); 8957 const _v3$2 = /*@__PURE__*/ new Vector3(); 8958 const _vab = /*@__PURE__*/ new Vector3(); 8959 const _vac = /*@__PURE__*/ new Vector3(); 8960 const _vbc = /*@__PURE__*/ new Vector3(); 8961 const _vap = /*@__PURE__*/ new Vector3(); 8962 const _vbp = /*@__PURE__*/ new Vector3(); 8963 const _vcp = /*@__PURE__*/ new Vector3(); 8964 const _v40 = /*@__PURE__*/ new Vector4(); 8965 const _v41 = /*@__PURE__*/ new Vector4(); 8966 const _v42 = /*@__PURE__*/ new Vector4(); 8967 /** 8968 * A geometric triangle as defined by three vectors representing its three corners. 8969 */ class Triangle { 8970 /** 8971 * Computes the normal vector of a triangle. 8972 * 8973 * @param {Vector3} a - The first corner of the triangle. 8974 * @param {Vector3} b - The second corner of the triangle. 8975 * @param {Vector3} c - The third corner of the triangle. 8976 * @param {Vector3} target - The target vector that is used to store the method's result. 8977 * @return {Vector3} The triangle's normal. 8978 */ static getNormal(a, b, c, target) { 8979 target.subVectors(c, b); 8980 _v0$1.subVectors(a, b); 8981 target.cross(_v0$1); 8982 const targetLengthSq = target.lengthSq(); 8983 if (targetLengthSq > 0) { 8984 return target.multiplyScalar(1 / Math.sqrt(targetLengthSq)); 8985 } 8986 return target.set(0, 0, 0); 8987 } 8988 /** 8989 * Computes a barycentric coordinates from the given vector. 8990 * Returns `null` if the triangle is degenerate. 8991 * 8992 * @param {Vector3} point - A point in 3D space. 8993 * @param {Vector3} a - The first corner of the triangle. 8994 * @param {Vector3} b - The second corner of the triangle. 8995 * @param {Vector3} c - The third corner of the triangle. 8996 * @param {Vector3} target - The target vector that is used to store the method's result. 8997 * @return {?Vector3} The barycentric coordinates for the given point 8998 */ static getBarycoord(point, a, b, c, target) { 8999 // based on: http://www.blackpawn.com/texts/pointinpoly/default.html 9000 _v0$1.subVectors(c, a); 9001 _v1$3.subVectors(b, a); 9002 _v2$2.subVectors(point, a);
vendor: 4,454 bytes, lines 9003-9099
9003 const dot00 = _v0$1.dot(_v0$1); 9004 const dot01 = _v0$1.dot(_v1$3); 9005 const dot02 = _v0$1.dot(_v2$2); 9006 const dot11 = _v1$3.dot(_v1$3); 9007 const dot12 = _v1$3.dot(_v2$2); 9008 const denom = dot00 * dot11 - dot01 * dot01; 9009 // collinear or singular triangle 9010 if (denom === 0) { 9011 target.set(0, 0, 0); 9012 return null; 9013 } 9014 const invDenom = 1 / denom; 9015 const u = (dot11 * dot02 - dot01 * dot12) * invDenom; 9016 const v = (dot00 * dot12 - dot01 * dot02) * invDenom; 9017 // barycentric coordinates must always sum to 1 9018 return target.set(1 - u - v, v, u); 9019 } 9020 /** 9021 * Returns `true` if the given point, when projected onto the plane of the 9022 * triangle, lies within the triangle. 9023 * 9024 * @param {Vector3} point - The point in 3D space to test. 9025 * @param {Vector3} a - The first corner of the triangle. 9026 * @param {Vector3} b - The second corner of the triangle. 9027 * @param {Vector3} c - The third corner of the triangle. 9028 * @return {boolean} Whether the given point, when projected onto the plane of the 9029 * triangle, lies within the triangle or not. 9030 */ static containsPoint(point, a, b, c) { 9031 // if the triangle is degenerate then we can't contain a point 9032 if (this.getBarycoord(point, a, b, c, _v3$2) === null) { 9033 return false; 9034 } 9035 return _v3$2.x >= 0 && _v3$2.y >= 0 && _v3$2.x + _v3$2.y <= 1; 9036 } 9037 /** 9038 * Computes the value barycentrically interpolated for the given point on the 9039 * triangle. Returns `null` if the triangle is degenerate. 9040 * 9041 * @param {Vector3} point - Position of interpolated point. 9042 * @param {Vector3} p1 - The first corner of the triangle. 9043 * @param {Vector3} p2 - The second corner of the triangle. 9044 * @param {Vector3} p3 - The third corner of the triangle. 9045 * @param {Vector3} v1 - Value to interpolate of first vertex. 9046 * @param {Vector3} v2 - Value to interpolate of second vertex. 9047 * @param {Vector3} v3 - Value to interpolate of third vertex. 9048 * @param {Vector3} target - The target vector that is used to store the method's result. 9049 * @return {?Vector3} The interpolated value. 9050 */ static getInterpolation(point, p1, p2, p3, v1, v2, v3, target) { 9051 if (this.getBarycoord(point, p1, p2, p3, _v3$2) === null) { 9052 target.x = 0; 9053 target.y = 0; 9054 if ('z' in target) target.z = 0; 9055 if ('w' in target) target.w = 0; 9056 return null; 9057 } 9058 target.setScalar(0); 9059 target.addScaledVector(v1, _v3$2.x); 9060 target.addScaledVector(v2, _v3$2.y); 9061 target.addScaledVector(v3, _v3$2.z); 9062 return target; 9063 } 9064 /** 9065 * Computes the value barycentrically interpolated for the given attribute and indices. 9066 * 9067 * @param {BufferAttribute} attr - The attribute to interpolate. 9068 * @param {number} i1 - Index of first vertex. 9069 * @param {number} i2 - Index of second vertex. 9070 * @param {number} i3 - Index of third vertex. 9071 * @param {Vector3} barycoord - The barycoordinate value to use to interpolate. 9072 * @param {Vector3} target - The target vector that is used to store the method's result. 9073 * @return {Vector3} The interpolated attribute value. 9074 */ static getInterpolatedAttribute(attr, i1, i2, i3, barycoord, target) { 9075 _v40.setScalar(0); 9076 _v41.setScalar(0); 9077 _v42.setScalar(0); 9078 _v40.fromBufferAttribute(attr, i1); 9079 _v41.fromBufferAttribute(attr, i2); 9080 _v42.fromBufferAttribute(attr, i3); 9081 target.setScalar(0); 9082 target.addScaledVector(_v40, barycoord.x); 9083 target.addScaledVector(_v41, barycoord.y); 9084 target.addScaledVector(_v42, barycoord.z); 9085 return target; 9086 } 9087 /** 9088 * Returns `true` if the triangle is oriented towards the given direction. 9089 * 9090 * @param {Vector3} a - The first corner of the triangle. 9091 * @param {Vector3} b - The second corner of the triangle. 9092 * @param {Vector3} c - The third corner of the triangle. 9093 * @param {Vector3} direction - The (normalized) direction vector. 9094 * @return {boolean} Whether the triangle is oriented towards the given direction or not. 9095 */ static isFrontFacing(a, b, c, direction) { 9096 _v0$1.subVectors(c, b); 9097 _v1$3.subVectors(a, b); 9098 // strictly front facing 9099 return _v0$1.cross(_v1$3).dot(direction) < 0 ? true : false;
vendor: 6,559 bytes, lines 9100-9254
9100 } 9101 /** 9102 * Sets the triangle's vertices by copying the given values. 9103 * 9104 * @param {Vector3} a - The first corner of the triangle. 9105 * @param {Vector3} b - The second corner of the triangle. 9106 * @param {Vector3} c - The third corner of the triangle. 9107 * @return {Triangle} A reference to this triangle. 9108 */ set(a, b, c) { 9109 this.a.copy(a); 9110 this.b.copy(b); 9111 this.c.copy(c); 9112 return this; 9113 } 9114 /** 9115 * Sets the triangle's vertices by copying the given array values. 9116 * 9117 * @param {Array<Vector3>} points - An array with 3D points. 9118 * @param {number} i0 - The array index representing the first corner of the triangle. 9119 * @param {number} i1 - The array index representing the second corner of the triangle. 9120 * @param {number} i2 - The array index representing the third corner of the triangle. 9121 * @return {Triangle} A reference to this triangle. 9122 */ setFromPointsAndIndices(points, i0, i1, i2) { 9123 this.a.copy(points[i0]); 9124 this.b.copy(points[i1]); 9125 this.c.copy(points[i2]); 9126 return this; 9127 } 9128 /** 9129 * Sets the triangle's vertices by copying the given attribute values. 9130 * 9131 * @param {BufferAttribute} attribute - A buffer attribute with 3D points data. 9132 * @param {number} i0 - The attribute index representing the first corner of the triangle. 9133 * @param {number} i1 - The attribute index representing the second corner of the triangle. 9134 * @param {number} i2 - The attribute index representing the third corner of the triangle. 9135 * @return {Triangle} A reference to this triangle. 9136 */ setFromAttributeAndIndices(attribute, i0, i1, i2) { 9137 this.a.fromBufferAttribute(attribute, i0); 9138 this.b.fromBufferAttribute(attribute, i1); 9139 this.c.fromBufferAttribute(attribute, i2); 9140 return this; 9141 } 9142 /** 9143 * Returns a new triangle with copied values from this instance. 9144 * 9145 * @return {Triangle} A clone of this instance. 9146 */ clone() { 9147 return new this.constructor().copy(this); 9148 } 9149 /** 9150 * Copies the values of the given triangle to this instance. 9151 * 9152 * @param {Triangle} triangle - The triangle to copy. 9153 * @return {Triangle} A reference to this triangle. 9154 */ copy(triangle) { 9155 this.a.copy(triangle.a); 9156 this.b.copy(triangle.b); 9157 this.c.copy(triangle.c); 9158 return this; 9159 } 9160 /** 9161 * Computes the area of the triangle. 9162 * 9163 * @return {number} The triangle's area. 9164 */ getArea() { 9165 _v0$1.subVectors(this.c, this.b); 9166 _v1$3.subVectors(this.a, this.b); 9167 return _v0$1.cross(_v1$3).length() * 0.5; 9168 } 9169 /** 9170 * Computes the midpoint of the triangle. 9171 * 9172 * @param {Vector3} target - The target vector that is used to store the method's result. 9173 * @return {Vector3} The triangle's midpoint. 9174 */ getMidpoint(target) { 9175 return target.addVectors(this.a, this.b).add(this.c).multiplyScalar(1 / 3); 9176 } 9177 /** 9178 * Computes the normal of the triangle. 9179 * 9180 * @param {Vector3} target - The target vector that is used to store the method's result. 9181 * @return {Vector3} The triangle's normal. 9182 */ getNormal(target) { 9183 return Triangle.getNormal(this.a, this.b, this.c, target); 9184 } 9185 /** 9186 * Computes a plane the triangle lies within. 9187 * 9188 * @param {Plane} target - The target vector that is used to store the method's result. 9189 * @return {Plane} The plane the triangle lies within. 9190 */ getPlane(target) { 9191 return target.setFromCoplanarPoints(this.a, this.b, this.c); 9192 } 9193 /** 9194 * Computes a barycentric coordinates from the given vector. 9195 * Returns `null` if the triangle is degenerate. 9196 * 9197 * @param {Vector3} point - A point in 3D space. 9198 * @param {Vector3} target - The target vector that is used to store the method's result. 9199 * @return {?Vector3} The barycentric coordinates for the given point 9200 */ getBarycoord(point, target) { 9201 return Triangle.getBarycoord(point, this.a, this.b, this.c, target); 9202 } 9203 /** 9204 * Computes the value barycentrically interpolated for the given point on the 9205 * triangle. Returns `null` if the triangle is degenerate. 9206 * 9207 * @param {Vector3} point - Position of interpolated point. 9208 * @param {Vector3} v1 - Value to interpolate of first vertex. 9209 * @param {Vector3} v2 - Value to interpolate of second vertex. 9210 * @param {Vector3} v3 - Value to interpolate of third vertex. 9211 * @param {Vector3} target - The target vector that is used to store the method's result. 9212 * @return {?Vector3} The interpolated value. 9213 */ getInterpolation(point, v1, v2, v3, target) { 9214 return Triangle.getInterpolation(point, this.a, this.b, this.c, v1, v2, v3, target); 9215 } 9216 /** 9217 * Returns `true` if the given point, when projected onto the plane of the 9218 * triangle, lies within the triangle. 9219 * 9220 * @param {Vector3} point - The point in 3D space to test. 9221 * @return {boolean} Whether the given point, when projected onto the plane of the 9222 * triangle, lies within the triangle or not. 9223 */ containsPoint(point) { 9224 return Triangle.containsPoint(point, this.a, this.b, this.c); 9225 } 9226 /** 9227 * Returns `true` if the triangle is oriented towards the given direction. 9228 * 9229 * @param {Vector3} direction - The (normalized) direction vector. 9230 * @return {boolean} Whether the triangle is oriented towards the given direction or not. 9231 */ isFrontFacing(direction) { 9232 return Triangle.isFrontFacing(this.a, this.b, this.c, direction); 9233 } 9234 /** 9235 * Returns `true` if this triangle intersects with the given box. 9236 * 9237 * @param {Box3} box - The box to intersect. 9238 * @return {boolean} Whether this triangle intersects with the given box or not. 9239 */ intersectsBox(box) { 9240 return box.intersectsTriangle(this); 9241 } 9242 /** 9243 * Returns the closest point on the triangle to the given point. 9244 * 9245 * @param {Vector3} p - The point to compute the closest point for. 9246 * @param {Vector3} target - The target vector that is used to store the method's result. 9247 * @return {Vector3} The closest point on the triangle. 9248 */ closestPointToPoint(p, target) { 9249 const a = this.a, b = this.b, c = this.c; 9250 let v, w; 9251 // algorithm thanks to Real-Time Collision Detection by Christer Ericson, 9252 // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc., 9253 // under the accompanying license; see chapter 5.1.5 for detailed explanation. 9254 // basically, we're distinguishing which of the voronoi regi
vendor: 6,478 bytes, lines 9254-9459
9254ons of the triangle 9255 // the point lies in with the minimum amount of redundant computation. 9256 _vab.subVectors(b, a); 9257 _vac.subVectors(c, a); 9258 _vap.subVectors(p, a); 9259 const d1 = _vab.dot(_vap); 9260 const d2 = _vac.dot(_vap); 9261 if (d1 <= 0 && d2 <= 0) { 9262 // vertex region of A; barycentric coords (1, 0, 0) 9263 return target.copy(a); 9264 } 9265 _vbp.subVectors(p, b); 9266 const d3 = _vab.dot(_vbp); 9267 const d4 = _vac.dot(_vbp); 9268 if (d3 >= 0 && d4 <= d3) { 9269 // vertex region of B; barycentric coords (0, 1, 0) 9270 return target.copy(b); 9271 } 9272 const vc = d1 * d4 - d3 * d2; 9273 if (vc <= 0 && d1 >= 0 && d3 <= 0) { 9274 v = d1 / (d1 - d3); 9275 // edge region of AB; barycentric coords (1-v, v, 0) 9276 return target.copy(a).addScaledVector(_vab, v); 9277 } 9278 _vcp.subVectors(p, c); 9279 const d5 = _vab.dot(_vcp); 9280 const d6 = _vac.dot(_vcp); 9281 if (d6 >= 0 && d5 <= d6) { 9282 // vertex region of C; barycentric coords (0, 0, 1) 9283 return target.copy(c); 9284 } 9285 const vb = d5 * d2 - d1 * d6; 9286 if (vb <= 0 && d2 >= 0 && d6 <= 0) { 9287 w = d2 / (d2 - d6); 9288 // edge region of AC; barycentric coords (1-w, 0, w) 9289 return target.copy(a).addScaledVector(_vac, w); 9290 } 9291 const va = d3 * d6 - d5 * d4; 9292 if (va <= 0 && d4 - d3 >= 0 && d5 - d6 >= 0) { 9293 _vbc.subVectors(c, b); 9294 w = (d4 - d3) / (d4 - d3 + (d5 - d6)); 9295 // edge region of BC; barycentric coords (0, 1-w, w) 9296 return target.copy(b).addScaledVector(_vbc, w); // edge region of BC 9297 } 9298 // face region 9299 const denom = 1 / (va + vb + vc); 9300 // u = va * denom 9301 v = vb * denom; 9302 w = vc * denom; 9303 return target.copy(a).addScaledVector(_vab, v).addScaledVector(_vac, w); 9304 } 9305 /** 9306 * Returns `true` if this triangle is equal with the given one. 9307 * 9308 * @param {Triangle} triangle - The triangle to test for equality. 9309 * @return {boolean} Whether this triangle is equal with the given one. 9310 */ equals(triangle) { 9311 return triangle.a.equals(this.a) && triangle.b.equals(this.b) && triangle.c.equals(this.c); 9312 } 9313 /** 9314 * Constructs a new triangle. 9315 * 9316 * @param {Vector3} [a=(0,0,0)] - The first corner of the triangle. 9317 * @param {Vector3} [b=(0,0,0)] - The second corner of the triangle. 9318 * @param {Vector3} [c=(0,0,0)] - The third corner of the triangle. 9319 */ constructor(a = new Vector3(), b = new Vector3(), c = new Vector3()){ 9320 /** 9321 * The first corner of the triangle. 9322 * 9323 * @type {Vector3} 9324 */ this.a = a; 9325 /** 9326 * The second corner of the triangle. 9327 * 9328 * @type {Vector3} 9329 */ this.b = b; 9330 /** 9331 * The third corner of the triangle. 9332 * 9333 * @type {Vector3} 9334 */ this.c = c; 9335 } 9336 } 9337 const _colorKeywords = { 9338 'aliceblue': 0xF0F8FF, 9339 'antiquewhite': 0xFAEBD7, 9340 'aqua': 0x00FFFF, 9341 'aquamarine': 0x7FFFD4, 9342 'azure': 0xF0FFFF, 9343 'beige': 0xF5F5DC, 9344 'bisque': 0xFFE4C4, 9345 'black': 0x000000, 9346 'blanchedalmond': 0xFFEBCD, 9347 'blue': 0x0000FF, 9348 'blueviolet': 0x8A2BE2, 9349 'brown': 0xA52A2A, 9350 'burlywood': 0xDEB887, 9351 'cadetblue': 0x5F9EA0, 9352 'chartreuse': 0x7FFF00, 9353 'chocolate': 0xD2691E, 9354 'coral': 0xFF7F50, 9355 'cornflowerblue': 0x6495ED, 9356 'cornsilk': 0xFFF8DC, 9357 'crimson': 0xDC143C, 9358 'cyan': 0x00FFFF, 9359 'darkblue': 0x00008B, 9360 'darkcyan': 0x008B8B, 9361 'darkgoldenrod': 0xB8860B, 9362 'darkgray': 0xA9A9A9, 9363 'darkgreen': 0x006400, 9364 'darkgrey': 0xA9A9A9, 9365 'darkkhaki': 0xBDB76B, 9366 'darkmagenta': 0x8B008B, 9367 'darkolivegreen': 0x556B2F, 9368 'darkorange': 0xFF8C00, 9369 'darkorchid': 0x9932CC, 9370 'darkred': 0x8B0000, 9371 'darksalmon': 0xE9967A, 9372 'darkseagreen': 0x8FBC8F, 9373 'darkslateblue': 0x483D8B, 9374 'darkslategray': 0x2F4F4F, 9375 'darkslategrey': 0x2F4F4F, 9376 'darkturquoise': 0x00CED1, 9377 'darkviolet': 0x9400D3, 9378 'deeppink': 0xFF1493, 9379 'deepskyblue': 0x00BFFF, 9380 'dimgray': 0x696969, 9381 'dimgrey': 0x696969, 9382 'dodgerblue': 0x1E90FF, 9383 'firebrick': 0xB22222, 9384 'floralwhite': 0xFFFAF0, 9385 'forestgreen': 0x228B22, 9386 'fuchsia': 0xFF00FF, 9387 'gainsboro': 0xDCDCDC, 9388 'ghostwhite': 0xF8F8FF, 9389 'gold': 0xFFD700, 9390 'goldenrod': 0xDAA520, 9391 'gray': 0x808080, 9392 'green': 0x008000, 9393 'greenyellow': 0xADFF2F, 9394 'grey': 0x808080, 9395 'honeydew': 0xF0FFF0, 9396 'hotpink': 0xFF69B4, 9397 'indianred': 0xCD5C5C, 9398 'indigo': 0x4B0082, 9399 'ivory': 0xFFFFF0, 9400 'khaki': 0xF0E68C, 9401 'lavender': 0xE6E6FA, 9402 'lavenderblush': 0xFFF0F5, 9403 'lawngreen': 0x7CFC00, 9404 'lemonchiffon': 0xFFFACD, 9405 'lightblue': 0xADD8E6, 9406 'lightcoral': 0xF08080, 9407 'lightcyan': 0xE0FFFF, 9408 'lightgoldenrodyellow': 0xFAFAD2, 9409 'lightgray': 0xD3D3D3, 9410 'lightgreen': 0x90EE90, 9411 'lightgrey': 0xD3D3D3, 9412 'lightpink': 0xFFB6C1, 9413 'lightsalmon': 0xFFA07A, 9414 'lightseagreen': 0x20B2AA, 9415 'lightskyblue': 0x87CEFA, 9416 'lightslategray': 0x778899, 9417 'lightslategrey': 0x778899, 9418 'lightsteelblue': 0xB0C4DE, 9419 'lightyellow': 0xFFFFE0, 9420 'lime': 0x00FF00, 9421 'limegreen': 0x32CD32, 9422 'linen': 0xFAF0E6, 9423 'magenta': 0xFF00FF, 9424 'maroon': 0x800000, 9425 'mediumaquamarine': 0x66CDAA, 9426 'mediumblue': 0x0000CD, 9427 'mediumorchid': 0xBA55D3, 9428 'mediumpurple': 0x9370DB, 9429 'mediumseagreen': 0x3CB371, 9430 'mediumslateblue': 0x7B68EE, 9431 'mediumspringgreen': 0x00FA9A, 9432 'mediumturquoise': 0x48D1CC, 9433 'mediumvioletred': 0xC71585, 9434 'midnightblue': 0x191970, 9435 'mintcream': 0xF5FFFA, 9436 'mistyrose': 0xFFE4E1, 9437 'moccasin': 0xFFE4B5, 9438 'navajowhite': 0xFFDEAD, 9439 'navy': 0x000080, 9440 'oldlace': 0xFDF5E6, 9441 'olive': 0x808000, 9442 'olivedrab': 0x6B8E23, 9443 'orange': 0xFFA500, 9444 'orangered': 0xFF4500, 9445 'orchid': 0xDA70D6, 9446 'palegoldenrod': 0xEEE8AA, 9447 'palegreen': 0x98FB98, 9448 'paleturquoise': 0xAFEEEE, 9449 'palevioletred': 0xDB7093, 9450 'papayawhip': 0xFFEFD5, 9451 'peachpuff': 0xFFDAB9, 9452 'peru': 0xCD853F, 9453 'pink': 0xFFC0CB, 9454 'plum': 0xDDA0DD, 9455 'powderblue': 0xB0E0E6, 9456 'purple': 0x800080, 9457 'rebeccapurple': 0x663399, 9458 'red': 0xFF0000, 9459 'rosybrown': 0xBC8F8F,
vendor: 4,148 bytes, lines 9460-9587
9460 'royalblue': 0x4169E1, 9461 'saddlebrown': 0x8B4513, 9462 'salmon': 0xFA8072, 9463 'sandybrown': 0xF4A460, 9464 'seagreen': 0x2E8B57, 9465 'seashell': 0xFFF5EE, 9466 'sienna': 0xA0522D, 9467 'silver': 0xC0C0C0, 9468 'skyblue': 0x87CEEB, 9469 'slateblue': 0x6A5ACD, 9470 'slategray': 0x708090, 9471 'slategrey': 0x708090, 9472 'snow': 0xFFFAFA, 9473 'springgreen': 0x00FF7F, 9474 'steelblue': 0x4682B4, 9475 'tan': 0xD2B48C, 9476 'teal': 0x008080, 9477 'thistle': 0xD8BFD8, 9478 'tomato': 0xFF6347, 9479 'turquoise': 0x40E0D0, 9480 'violet': 0xEE82EE, 9481 'wheat': 0xF5DEB3, 9482 'white': 0xFFFFFF, 9483 'whitesmoke': 0xF5F5F5, 9484 'yellow': 0xFFFF00, 9485 'yellowgreen': 0x9ACD32 9486 }; 9487 const _hslA = { 9488 h: 0, 9489 s: 0, 9490 l: 0 9491 }; 9492 const _hslB = { 9493 h: 0, 9494 s: 0, 9495 l: 0 9496 }; 9497 function hue2rgb(p, q, t) { 9498 if (t < 0) t += 1; 9499 if (t > 1) t -= 1; 9500 if (t < 1 / 6) return p + (q - p) * 6 * t; 9501 if (t < 1 / 2) return q; 9502 if (t < 2 / 3) return p + (q - p) * 6 * (2 / 3 - t); 9503 return p; 9504 } 9505 /** 9506 * A Color instance is represented by RGB components in the linear <i>working 9507 * color space</i>, which defaults to `LinearSRGBColorSpace`. Inputs 9508 * conventionally using `SRGBColorSpace` (such as hexadecimals and CSS 9509 * strings) are converted to the working color space automatically. 9510 * 9511 * ```js 9512 * // converted automatically from SRGBColorSpace to LinearSRGBColorSpace 9513 * const color = new THREE.Color().setHex( 0x112233 ); 9514 * ``` 9515 * Source color spaces may be specified explicitly, to ensure correct conversions. 9516 * ```js 9517 * // assumed already LinearSRGBColorSpace; no conversion 9518 * const color = new THREE.Color().setRGB( 0.5, 0.5, 0.5 ); 9519 * 9520 * // converted explicitly from SRGBColorSpace to LinearSRGBColorSpace 9521 * const color = new THREE.Color().setRGB( 0.5, 0.5, 0.5, SRGBColorSpace ); 9522 * ``` 9523 * If THREE.ColorManagement is disabled, no conversions occur. For details, 9524 * see <i>Color management</i>. Iterating through a Color instance will yield 9525 * its components (r, g, b) in the corresponding order. A Color can be initialised 9526 * in any of the following ways: 9527 * ```js 9528 * //empty constructor - will default white 9529 * const color1 = new THREE.Color(); 9530 * 9531 * //Hexadecimal color (recommended) 9532 * const color2 = new THREE.Color( 0xff0000 ); 9533 * 9534 * //RGB string 9535 * const color3 = new THREE.Color("rgb(255, 0, 0)"); 9536 * const color4 = new THREE.Color("rgb(100%, 0%, 0%)"); 9537 * 9538 * //X11 color name - all 140 color names are supported. 9539 * //Note the lack of CamelCase in the name 9540 * const color5 = new THREE.Color( 'skyblue' ); 9541 * //HSL string 9542 * const color6 = new THREE.Color("hsl(0, 100%, 50%)"); 9543 * 9544 * //Separate RGB values between 0 and 1 9545 * const color7 = new THREE.Color( 1, 0, 0 ); 9546 * ``` 9547 */ class Color { 9548 /** 9549 * Sets the colors's components from the given values. 9550 * 9551 * @param {(number|string|Color)} [r] - The red component of the color. If `g` and `b` are 9552 * not provided, it can be hexadecimal triplet, a CSS-style string or another `Color` instance. 9553 * @param {number} [g] - The green component. 9554 * @param {number} [b] - The blue component. 9555 * @return {Color} A reference to this color. 9556 */ set(r, g, b) { 9557 if (g === undefined && b === undefined) { 9558 // r is THREE.Color, hex or string 9559 const value = r; 9560 if (value && value.isColor) { 9561 this.copy(value); 9562 } else if (typeof value === 'number') { 9563 this.setHex(value); 9564 } else if (typeof value === 'string') { 9565 this.setStyle(value); 9566 } 9567 } else { 9568 this.setRGB(r, g, b); 9569 } 9570 return this; 9571 } 9572 /** 9573 * Sets the colors's components to the given scalar value. 9574 * 9575 * @param {number} scalar - The scalar value. 9576 * @return {Color} A reference to this color. 9577 */ setScalar(scalar) { 9578 this.r = scalar; 9579 this.g = scalar; 9580 this.b = scalar; 9581 return this; 9582 } 9583 /** 9584 * Sets this color from a hexadecimal value. 9585 * 9586 * @param {number} hex - The hexadecimal value. 9587 * @param {string}
vendor: 10,233 bytes, lines 9587-9830
9587 [colorSpace=SRGBColorSpace] - The color space. 9588 * @return {Color} A reference to this color. 9589 */ setHex(hex, colorSpace = SRGBColorSpace) { 9590 hex = Math.floor(hex); 9591 this.r = (hex >> 16 & 255) / 255; 9592 this.g = (hex >> 8 & 255) / 255; 9593 this.b = (hex & 255) / 255; 9594 ColorManagement.toWorkingColorSpace(this, colorSpace); 9595 return this; 9596 } 9597 /** 9598 * Sets this color from RGB values. 9599 * 9600 * @param {number} r - Red channel value between `0.0` and `1.0`. 9601 * @param {number} g - Green channel value between `0.0` and `1.0`. 9602 * @param {number} b - Blue channel value between `0.0` and `1.0`. 9603 * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space. 9604 * @return {Color} A reference to this color. 9605 */ setRGB(r, g, b, colorSpace = ColorManagement.workingColorSpace) { 9606 this.r = r; 9607 this.g = g; 9608 this.b = b; 9609 ColorManagement.toWorkingColorSpace(this, colorSpace); 9610 return this; 9611 } 9612 /** 9613 * Sets this color from RGB values. 9614 * 9615 * @param {number} h - Hue value between `0.0` and `1.0`. 9616 * @param {number} s - Saturation value between `0.0` and `1.0`. 9617 * @param {number} l - Lightness value between `0.0` and `1.0`. 9618 * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space. 9619 * @return {Color} A reference to this color. 9620 */ setHSL(h, s, l, colorSpace = ColorManagement.workingColorSpace) { 9621 // h,s,l ranges are in 0.0 - 1.0 9622 h = euclideanModulo(h, 1); 9623 s = clamp$1(s, 0, 1); 9624 l = clamp$1(l, 0, 1); 9625 if (s === 0) { 9626 this.r = this.g = this.b = l; 9627 } else { 9628 const p = l <= 0.5 ? l * (1 + s) : l + s - l * s; 9629 const q = 2 * l - p; 9630 this.r = hue2rgb(q, p, h + 1 / 3); 9631 this.g = hue2rgb(q, p, h); 9632 this.b = hue2rgb(q, p, h - 1 / 3); 9633 } 9634 ColorManagement.toWorkingColorSpace(this, colorSpace); 9635 return this; 9636 } 9637 /** 9638 * Sets this color from a CSS-style string. For example, `rgb(250, 0,0)`, 9639 * `rgb(100%, 0%, 0%)`, `hsl(0, 100%, 50%)`, `#ff0000`, `#f00`, or `red` ( or 9640 * any [X11 color name]{@link https://en.wikipedia.org/wiki/X11_color_names#Color_name_chart} - 9641 * all 140 color names are supported). 9642 * 9643 * @param {string} style - Color as a CSS-style string. 9644 * @param {string} [colorSpace=SRGBColorSpace] - The color space. 9645 * @return {Color} A reference to this color. 9646 */ setStyle(style, colorSpace = SRGBColorSpace) { 9647 function handleAlpha(string) { 9648 if (string === undefined) return; 9649 if (parseFloat(string) < 1) { 9650 console.warn('THREE.Color: Alpha component of ' + style + ' will be ignored.'); 9651 } 9652 } 9653 let m; 9654 if (m = /^(\w+)\(([^\)]*)\)/.exec(style)) { 9655 // rgb / hsl 9656 let color; 9657 const name = m[1]; 9658 const components = m[2]; 9659 switch(name){ 9660 case 'rgb': 9661 case 'rgba': 9662 if (color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(components)) { 9663 // rgb(255,0,0) rgba(255,0,0,0.5) 9664 handleAlpha(color[4]); 9665 return this.setRGB(Math.min(255, parseInt(color[1], 10)) / 255, Math.min(255, parseInt(color[2], 10)) / 255, Math.min(255, parseInt(color[3], 10)) / 255, colorSpace); 9666 } 9667 if (color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(components)) { 9668 // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5) 9669 handleAlpha(color[4]); 9670 return this.setRGB(Math.min(100, parseInt(color[1], 10)) / 100, Math.min(100, parseInt(color[2], 10)) / 100, Math.min(100, parseInt(color[3], 10)) / 100, colorSpace); 9671 } 9672 break; 9673 case 'hsl': 9674 case 'hsla': 9675 if (color = /^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(components)) { 9676 // hsl(120,50%,50%) hsla(120,50%,50%,0.5) 9677 handleAlpha(color[4]); 9678 return this.setHSL(parseFloat(color[1]) / 360, parseFloat(color[2]) / 100, parseFloat(color[3]) / 100, colorSpace); 9679 } 9680 break; 9681 default: 9682 console.warn('THREE.Color: Unknown color model ' + style); 9683 } 9684 } else if (m = /^\#([A-Fa-f\d]+)$/.exec(style)) { 9685 // hex color 9686 const hex = m[1]; 9687 const size = hex.length; 9688 if (size === 3) { 9689 // #ff0 9690 return this.setRGB(parseInt(hex.charAt(0), 16) / 15, parseInt(hex.charAt(1), 16) / 15, parseInt(hex.charAt(2), 16) / 15, colorSpace); 9691 } else if (size === 6) { 9692 // #ff0000 9693 return this.setHex(parseInt(hex, 16), colorSpace); 9694 } else { 9695 console.warn('THREE.Color: Invalid hex color ' + style); 9696 } 9697 } else if (style && style.length > 0) { 9698 return this.setColorName(style, colorSpace); 9699 } 9700 return this; 9701 } 9702 /** 9703 * Sets this color from a color name. Faster than {@link Color#setStyle} if 9704 * you don't need the other CSS-style formats. 9705 * 9706 * For convenience, the list of names is exposed in `Color.NAMES` as a hash. 9707 * ```js 9708 * Color.NAMES.aliceblue // returns 0xF0F8FF 9709 * ``` 9710 * 9711 * @param {string} style - The color name. 9712 * @param {string} [colorSpace=SRGBColorSpace] - The color space. 9713 * @return {Color} A reference to this color. 9714 */ setColorName(style, colorSpace = SRGBColorSpace) { 9715 // color keywords 9716 const hex = _colorKeywords[style.toLowerCase()]; 9717 if (hex !== undefined) { 9718 // red 9719 this.setHex(hex, colorSpace); 9720 } else { 9721 // unknown color 9722 console.warn('THREE.Color: Unknown color ' + style); 9723 } 9724 return this; 9725 } 9726 /** 9727 * Returns a new color with copied values from this instance. 9728 * 9729 * @return {Color} A clone of this instance. 9730 */ clone() { 9731 return new this.constructor(this.r, this.g, this.b); 9732 } 9733 /** 9734 * Copies the values of the given color to this instance. 9735 * 9736 * @param {Color} color - The color to copy. 9737 * @return {Color} A reference to this color. 9738 */ copy(color) { 9739 this.r = color.r; 9740 this.g = color.g; 9741 this.b = color.b; 9742 return this; 9743 } 9744 /** 9745 * Copies the given color into this color, and then converts this color from 9746 * `SRGBColorSpace` to `LinearSRGBColorSpace`. 9747 * 9748 * @param {Color} color - The color to copy/convert. 9749 * @return {Color} A reference to this color. 9750 */ copySRGBToLinear(color) { 9751 this.r = SRGBToLinear(color.r); 9752 this.g = SRGBToLinear(color.g); 9753 this.b = SRGBToLinear(color.b); 9754 return this; 9755 } 9756 /** 9757 * Copies the given color into this color, and then converts this color from 9758 * `LinearSRGBColorSpace` to `SRGBColorSpace`. 9759 * 9760 * @param {Color} color - The color to copy/convert. 9761 * @return {Color} A reference to this color. 9762 */ copyLinearToSRGB(color) { 9763 this.r = LinearToSRGB(color.r); 9764 this.g = LinearToSRGB(color.g); 9765 this.b = LinearToSRGB(color.b); 9766 return this; 9767 } 9768 /** 9769 * Converts this color from `SRGBColorSpace` to `LinearSRGBColorSpace`. 9770 * 9771 * @return {Color} A reference to this color. 9772 */ convertSRGBToLinear() { 9773 this.copySRGBToLinear(this); 9774 return this; 9775 } 9776 /** 9777 * Converts this color from `LinearSRGBColorSpace` to `SRGBColorSpace`. 9778 * 9779 * @return {Color} A reference to this color. 9780 */ convertLinearToSRGB() { 9781 this.copyLinearToSRGB(this); 9782 return this; 9783 } 9784 /** 9785 * Returns the hexadecimal value of this color. 9786 * 9787 * @param {string} [colorSpace=SRGBColorSpace] - The color space. 9788 * @return {number} The hexadecimal value. 9789 */ getHex(colorSpace = SRGBColorSpace) { 9790 ColorManagement.fromWorkingColorSpace(_color.copy(this), colorSpace); 9791 return Math.round(clamp$1(_color.r * 255, 0, 255)) * 65536 + Math.round(clamp$1(_color.g * 255, 0, 255)) * 256 + Math.round(clamp$1(_color.b * 255, 0, 255)); 9792 } 9793 /** 9794 * Returns the hexadecimal value of this color as a string (for example, 'FFFFFF'). 9795 * 9796 * @param {string} [colorSpace=SRGBColorSpace] - The color space. 9797 * @return {string} The hexadecimal value as a string. 9798 */ getHexString(colorSpace = SRGBColorSpace) { 9799 return ('000000' + this.getHex(colorSpace).toString(16)).slice(-6); 9800 } 9801 /** 9802 * Converts the colors RGB values into the HSL format and stores them into the 9803 * given target object. 9804 * 9805 * @param {{h:0,s:0,l:0}} target - The target object that is used to store the method's result. 9806 * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space. 9807 * @return {{h:number,s:number,l:number}} The HSL representation of this color. 9808 */ getHSL(target, colorSpace = ColorManagement.workingColorSpace) { 9809 // h,s,l ranges are in 0.0 - 1.0 9810 ColorManagement.fromWorkingColorSpace(_color.copy(this), colorSpace); 9811 const r = _color.r, g = _color.g, b = _color.b; 9812 const max = Math.max(r, g, b); 9813 const min = Math.min(r, g, b); 9814 let hue, saturation; 9815 const lightness = (min + max) / 2.0; 9816 if (min === max) { 9817 hue = 0; 9818 saturation = 0; 9819 } else { 9820 const delta = max - min; 9821 saturation = lightness <= 0.5 ? delta / (max + min) : delta / (2 - max - min); 9822 switch(max){ 9823 case r: 9824 hue = (g - b) / delta + (g < b ? 6 : 0); 9825 break; 9826 case g: 9827 hue = (b - r) / delta + 2; 9828 break; 9829 case b: 9830 hue = (r - g) / delta + 4;
vendor: 6,884 bytes, lines 9831-10010
9831 break; 9832 } 9833 hue /= 6; 9834 } 9835 target.h = hue; 9836 target.s = saturation; 9837 target.l = lightness; 9838 return target; 9839 } 9840 /** 9841 * Returns the RGB values of this color and stores them into the given target object. 9842 * 9843 * @param {Color} target - The target color that is used to store the method's result. 9844 * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space. 9845 * @return {Color} The RGB representation of this color. 9846 */ getRGB(target, colorSpace = ColorManagement.workingColorSpace) { 9847 ColorManagement.fromWorkingColorSpace(_color.copy(this), colorSpace); 9848 target.r = _color.r; 9849 target.g = _color.g; 9850 target.b = _color.b; 9851 return target; 9852 } 9853 /** 9854 * Returns the value of this color as a CSS style string. Example: `rgb(255,0,0)`. 9855 * 9856 * @param {string} [colorSpace=SRGBColorSpace] - The color space. 9857 * @return {string} The CSS representation of this color. 9858 */ getStyle(colorSpace = SRGBColorSpace) { 9859 ColorManagement.fromWorkingColorSpace(_color.copy(this), colorSpace); 9860 const r = _color.r, g = _color.g, b = _color.b; 9861 if (colorSpace !== SRGBColorSpace) { 9862 // Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/). 9863 return `color(${colorSpace} ${r.toFixed(3)} ${g.toFixed(3)} ${b.toFixed(3)})`; 9864 } 9865 return `rgb(${Math.round(r * 255)},${Math.round(g * 255)},${Math.round(b * 255)})`; 9866 } 9867 /** 9868 * Adds the given HSL values to this color's values. 9869 * Internally, this converts the color's RGB values to HSL, adds HSL 9870 * and then converts the color back to RGB. 9871 * 9872 * @param {number} h - Hue value between `0.0` and `1.0`. 9873 * @param {number} s - Saturation value between `0.0` and `1.0`. 9874 * @param {number} l - Lightness value between `0.0` and `1.0`. 9875 * @return {Color} A reference to this color. 9876 */ offsetHSL(h, s, l) { 9877 this.getHSL(_hslA); 9878 return this.setHSL(_hslA.h + h, _hslA.s + s, _hslA.l + l); 9879 } 9880 /** 9881 * Adds the RGB values of the given color to the RGB values of this color. 9882 * 9883 * @param {Color} color - The color to add. 9884 * @return {Color} A reference to this color. 9885 */ add(color) { 9886 this.r += color.r; 9887 this.g += color.g; 9888 this.b += color.b; 9889 return this; 9890 } 9891 /** 9892 * Adds the RGB values of the given colors and stores the result in this instance. 9893 * 9894 * @param {Color} color1 - The first color. 9895 * @param {Color} color2 - The second color. 9896 * @return {Color} A reference to this color. 9897 */ addColors(color1, color2) { 9898 this.r = color1.r + color2.r; 9899 this.g = color1.g + color2.g; 9900 this.b = color1.b + color2.b; 9901 return this; 9902 } 9903 /** 9904 * Adds the given scalar value to the RGB values of this color. 9905 * 9906 * @param {number} s - The scalar to add. 9907 * @return {Color} A reference to this color. 9908 */ addScalar(s) { 9909 this.r += s; 9910 this.g += s; 9911 this.b += s; 9912 return this; 9913 } 9914 /** 9915 * Subtracts the RGB values of the given color from the RGB values of this color. 9916 * 9917 * @param {Color} color - The color to subtract. 9918 * @return {Color} A reference to this color. 9919 */ sub(color) { 9920 this.r = Math.max(0, this.r - color.r); 9921 this.g = Math.max(0, this.g - color.g); 9922 this.b = Math.max(0, this.b - color.b); 9923 return this; 9924 } 9925 /** 9926 * Multiplies the RGB values of the given color with the RGB values of this color. 9927 * 9928 * @param {Color} color - The color to multiply. 9929 * @return {Color} A reference to this color. 9930 */ multiply(color) { 9931 this.r *= color.r; 9932 this.g *= color.g; 9933 this.b *= color.b; 9934 return this; 9935 } 9936 /** 9937 * Multiplies the given scalar value with the RGB values of this color. 9938 * 9939 * @param {number} s - The scalar to multiply. 9940 * @return {Color} A reference to this color. 9941 */ multiplyScalar(s) { 9942 this.r *= s; 9943 this.g *= s; 9944 this.b *= s; 9945 return this; 9946 } 9947 /** 9948 * Linearly interpolates this color's RGB values toward the RGB values of the 9949 * given color. The alpha argument can be thought of as the ratio between 9950 * the two colors, where `0.0` is this color and `1.0` is the first argument. 9951 * 9952 * @param {Color} color - The color to converge on. 9953 * @param {number} alpha - The interpolation factor in the closed interval `[0,1]`. 9954 * @return {Color} A reference to this color. 9955 */ lerp(color, alpha) { 9956 this.r += (color.r - this.r) * alpha; 9957 this.g += (color.g - this.g) * alpha; 9958 this.b += (color.b - this.b) * alpha; 9959 return this; 9960 } 9961 /** 9962 * Linearly interpolates between the given colors and stores the result in this instance. 9963 * The alpha argument can be thought of as the ratio between the two colors, where `0.0` 9964 * is the first and `1.0` is the second color. 9965 * 9966 * @param {Color} color1 - The first color. 9967 * @param {Color} color2 - The second color. 9968 * @param {number} alpha - The interpolation factor in the closed interval `[0,1]`. 9969 * @return {Color} A reference to this color. 9970 */ lerpColors(color1, color2, alpha) { 9971 this.r = color1.r + (color2.r - color1.r) * alpha; 9972 this.g = color1.g + (color2.g - color1.g) * alpha; 9973 this.b = color1.b + (color2.b - color1.b) * alpha; 9974 return this; 9975 } 9976 /** 9977 * Linearly interpolates this color's HSL values toward the HSL values of the 9978 * given color. It differs from {@link Color#lerp} by not interpolating straight 9979 * from one color to the other, but instead going through all the hues in between 9980 * those two colors. The alpha argument can be thought of as the ratio between 9981 * the two colors, where 0.0 is this color and 1.0 is the first argument. 9982 * 9983 * @param {Color} color - The color to converge on. 9984 * @param {number} alpha - The interpolation factor in the closed interval `[0,1]`. 9985 * @return {Color} A reference to this color. 9986 */ lerpHSL(color, alpha) { 9987 this.getHSL(_hslA); 9988 color.getHSL(_hslB); 9989 const h = lerp$1(_hslA.h, _hslB.h, alpha); 9990 const s = lerp$1(_hslA.s, _hslB.s, alpha); 9991 const l = lerp$1(_hslA.l, _hslB.l, alpha); 9992 this.setHSL(h, s, l); 9993 return this; 9994 } 9995 /** 9996 * Sets the color's RGB components from the given 3D vector. 9997 * 9998 * @param {Vector3} v - The vector to set. 9999 * @return {Color} A reference to this color. 10000 */ setFromVector3(v) { 10001 this.r = v.x; 10002 this.g = v.y; 10003 this.b = v.z; 10004 return this; 10005 } 10006 /** 10007 * Transforms this color with the given 3x3 matrix. 10008 * 10009 * @param {Matrix3} m - The matrix. 10010 * @return {Color} A reference to this color.
vendor: 20,959 bytes, lines 10011-10437
10011 */ applyMatrix3(m) { 10012 const r = this.r, g = this.g, b = this.b; 10013 const e = m.elements; 10014 this.r = e[0] * r + e[3] * g + e[6] * b; 10015 this.g = e[1] * r + e[4] * g + e[7] * b; 10016 this.b = e[2] * r + e[5] * g + e[8] * b; 10017 return this; 10018 } 10019 /** 10020 * Returns `true` if this color is equal with the given one. 10021 * 10022 * @param {Color} c - The color to test for equality. 10023 * @return {boolean} Whether this bounding color is equal with the given one. 10024 */ equals(c) { 10025 return c.r === this.r && c.g === this.g && c.b === this.b; 10026 } 10027 /** 10028 * Sets this color's RGB components from the given array. 10029 * 10030 * @param {Array<number>} array - An array holding the RGB values. 10031 * @param {number} [offset=0] - The offset into the array. 10032 * @return {Color} A reference to this color. 10033 */ fromArray(array, offset = 0) { 10034 this.r = array[offset]; 10035 this.g = array[offset + 1]; 10036 this.b = array[offset + 2]; 10037 return this; 10038 } 10039 /** 10040 * Writes the RGB components of this color to the given array. If no array is provided, 10041 * the method returns a new instance. 10042 * 10043 * @param {Array<number>} [array=[]] - The target array holding the color components. 10044 * @param {number} [offset=0] - Index of the first element in the array. 10045 * @return {Array<number>} The color components. 10046 */ toArray(array = [], offset = 0) { 10047 array[offset] = this.r; 10048 array[offset + 1] = this.g; 10049 array[offset + 2] = this.b; 10050 return array; 10051 } 10052 /** 10053 * Sets the components of this color from the given buffer attribute. 10054 * 10055 * @param {BufferAttribute} attribute - The buffer attribute holding color data. 10056 * @param {number} index - The index into the attribute. 10057 * @return {Color} A reference to this color. 10058 */ fromBufferAttribute(attribute, index) { 10059 this.r = attribute.getX(index); 10060 this.g = attribute.getY(index); 10061 this.b = attribute.getZ(index); 10062 return this; 10063 } 10064 /** 10065 * This methods defines the serialization result of this class. Returns the color 10066 * as a hexadecimal value. 10067 * 10068 * @return {number} The hexadecimal value. 10069 */ toJSON() { 10070 return this.getHex(); 10071 } 10072 *[Symbol.iterator]() { 10073 yield this.r; 10074 yield this.g; 10075 yield this.b; 10076 } 10077 /** 10078 * Constructs a new color. 10079 * 10080 * Note that standard method of specifying color in three.js is with a hexadecimal triplet, 10081 * and that method is used throughout the rest of the documentation. 10082 * 10083 * @param {(number|string|Color)} [r] - The red component of the color. If `g` and `b` are 10084 * not provided, it can be hexadecimal triplet, a CSS-style string or another `Color` instance. 10085 * @param {number} [g] - The green component. 10086 * @param {number} [b] - The blue component. 10087 */ constructor(r, g, b){ 10088 /** 10089 * This flag can be used for type testing. 10090 * 10091 * @type {boolean} 10092 * @readonly 10093 * @default true 10094 */ this.isColor = true; 10095 /** 10096 * The red component. 10097 * 10098 * @type {number} 10099 * @default 1 10100 */ this.r = 1; 10101 /** 10102 * The green component. 10103 * 10104 * @type {number} 10105 * @default 1 10106 */ this.g = 1; 10107 /** 10108 * The blue component. 10109 * 10110 * @type {number} 10111 * @default 1 10112 */ this.b = 1; 10113 return this.set(r, g, b); 10114 } 10115 } 10116 const _color = /*@__PURE__*/ new Color(); 10117 /** 10118 * A dictionary with X11 color names. 10119 * 10120 * Note that multiple words such as Dark Orange become the string 'darkorange'. 10121 * 10122 * @static 10123 * @type {Object} 10124 */ Color.NAMES = _colorKeywords; 10125 let _materialId = 0; 10126 /** 10127 * Abstract base class for materials. 10128 * 10129 * Materials define the appearance of renderable 3D objects. 10130 * 10131 * @abstract 10132 * @augments EventDispatcher 10133 */ let Material$1 = class Material extends EventDispatcher { 10134 /** 10135 * Sets the alpha value to be used when running an alpha test. The material 10136 * will not be rendered if the opacity is lower than this value. 10137 * 10138 * @type {number} 10139 * @readonly 10140 * @default 0 10141 */ get alphaTest() { 10142 return this._alphaTest; 10143 } 10144 set alphaTest(value) { 10145 if (this._alphaTest > 0 !== value > 0) { 10146 this.version++; 10147 } 10148 this._alphaTest = value; 10149 } 10150 /** 10151 * An optional callback that is executed immediately before the material is used to render a 3D object. 10152 * 10153 * This method can only be used when rendering with {@link WebGLRenderer}. 10154 * 10155 * @param {WebGLRenderer} renderer - The renderer. 10156 * @param {Scene} scene - The scene. 10157 * @param {Camera} camera - The camera that is used to render the scene. 10158 * @param {BufferGeometry} geometry - The 3D object's geometry. 10159 * @param {Object3D} object - The 3D object. 10160 * @param {Object} group - The geometry group data. 10161 */ onBeforeRender() {} 10162 /** 10163 * An optional callback that is executed immediately before the shader 10164 * program is compiled. This function is called with the shader source code 10165 * as a parameter. Useful for the modification of built-in materials. 10166 * 10167 * This method can only be used when rendering with {@link WebGLRenderer}. The 10168 * recommended approach when customizing materials is to use `WebGPURenderer` with the new 10169 * Node Material system and [TSL]{@link https://github.com/mrdoob/three.js/wiki/Three.js-Shading-Language}. 10170 * 10171 * @param {{vertexShader:string,fragmentShader:string,uniforms:Object}} shaderobject - The object holds the uniforms and the vertex and fragment shader source. 10172 * @param {WebGLRenderer} renderer - A reference to the renderer. 10173 */ onBeforeCompile() {} 10174 /** 10175 * In case {@link Material#onBeforeCompile} is used, this callback can be used to identify 10176 * values of settings used in `onBeforeCompile()`, so three.js can reuse a cached 10177 * shader or recompile the shader for this material as needed. 10178 * 10179 * This method can only be used when rendering with {@link WebGLRenderer}. 10180 * 10181 * @return {string} The custom program cache key. 10182 */ customProgramCacheKey() { 10183 return this.onBeforeCompile.toString(); 10184 } 10185 setValues(values) { 10186 if (values === undefined) return; 10187 for(const key in values){ 10188 const newValue = values[key]; 10189 if (newValue === undefined) { 10190 console.warn(`THREE.Material: parameter '${key}' has value of undefined.`); 10191 continue; 10192 } 10193 const currentValue = this[key]; 10194 if (currentValue === undefined) { 10195 console.warn(`THREE.Material: '${key}' is not a property of THREE.${this.type}.`); 10196 continue; 10197 } 10198 if (currentValue && currentValue.isColor) { 10199 currentValue.set(newValue); 10200 } else if (currentValue && currentValue.isVector3 && newValue && newValue.isVector3) { 10201 currentValue.copy(newValue); 10202 } else { 10203 this[key] = newValue; 10204 } 10205 } 10206 } 10207 /** 10208 * Serializes the material into JSON. 10209 * 10210 * @param {?(Object|string)} meta - An optional value holding meta information about the serialization. 10211 * @return {Object} A JSON object representing the serialized material. 10212 * @see {@link ObjectLoader#parse} 10213 */ toJSON(meta) { 10214 const isRootObject = meta === undefined || typeof meta === 'string'; 10215 if (isRootObject) { 10216 meta = { 10217 textures: {}, 10218 images: {} 10219 }; 10220 } 10221 const data = { 10222 metadata: { 10223 version: 4.6, 10224 type: 'Material', 10225 generator: 'Material.toJSON' 10226 } 10227 }; 10228 // standard Material serialization 10229 data.uuid = this.uuid; 10230 data.type = this.type; 10231 if (this.name !== '') data.name = this.name; 10232 if (this.color && this.color.isColor) data.color = this.color.getHex(); 10233 if (this.roughness !== undefined) data.roughness = this.roughness; 10234 if (this.metalness !== undefined) data.metalness = this.metalness; 10235 if (this.sheen !== undefined) data.sheen = this.sheen; 10236 if (this.sheenColor && this.sheenColor.isColor) data.sheenColor = this.sheenColor.getHex(); 10237 if (this.sheenRoughness !== undefined) data.sheenRoughness = this.sheenRoughness; 10238 if (this.emissive && this.emissive.isColor) data.emissive = this.emissive.getHex(); 10239 if (this.emissiveIntensity !== undefined && this.emissiveIntensity !== 1) data.emissiveIntensity = this.emissiveIntensity; 10240 if (this.specular && this.specular.isColor) data.specular = this.specular.getHex(); 10241 if (this.specularIntensity !== undefined) data.specularIntensity = this.specularIntensity; 10242 if (this.specularColor && this.specularColor.isColor) data.specularColor = this.specularColor.getHex(); 10243 if (this.shininess !== undefined) data.shininess = this.shininess; 10244 if (this.clearcoat !== undefined) data.clearcoat = this.clearcoat; 10245 if (this.clearcoatRoughness !== undefined) data.clearcoatRoughness = this.clearcoatRoughness; 10246 if (this.clearcoatMap && this.clearcoatMap.isTexture) { 10247 data.clearcoatMap = this.clearcoatMap.toJSON(meta).uuid; 10248 } 10249 if (this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture) { 10250 data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON(meta).uuid; 10251 } 10252 if (this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture) { 10253 data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON(meta).uuid; 10254 data.clearcoatNormalScale = this.clearcoatNormalScale.toArray(); 10255 } 10256 if (this.dispersion !== undefined) data.dispersion = this.dispersion; 10257 if (this.iridescence !== undefined) data.iridescence = this.iridescence; 10258 if (this.iridescenceIOR !== undefined) data.iridescenceIOR = this.iridescenceIOR; 10259 if (this.iridescenceThicknessRange !== undefined) data.iridescenceThicknessRange = this.iridescenceThicknessRange; 10260 if (this.iridescenceMap && this.iridescenceMap.isTexture) { 10261 data.iridescenceMap = this.iridescenceMap.toJSON(meta).uuid; 10262 } 10263 if (this.iridescenceThicknessMap && this.iridescenceThicknessMap.isTexture) { 10264 data.iridescenceThicknessMap = this.iridescenceThicknessMap.toJSON(meta).uuid; 10265 } 10266 if (this.anisotropy !== undefined) data.anisotropy = this.anisotropy; 10267 if (this.anisotropyRotation !== undefined) data.anisotropyRotation = this.anisotropyRotation; 10268 if (this.anisotropyMap && this.anisotropyMap.isTexture) { 10269 data.anisotropyMap = this.anisotropyMap.toJSON(meta).uuid; 10270 } 10271 if (this.map && this.map.isTexture) data.map = this.map.toJSON(meta).uuid; 10272 if (this.matcap && this.matcap.isTexture) data.matcap = this.matcap.toJSON(meta).uuid; 10273 if (this.alphaMap && this.alphaMap.isTexture) data.alphaMap = this.alphaMap.toJSON(meta).uuid; 10274 if (this.lightMap && this.lightMap.isTexture) { 10275 data.lightMap = this.lightMap.toJSON(meta).uuid; 10276 data.lightMapIntensity = this.lightMapIntensity; 10277 } 10278 if (this.aoMap && this.aoMap.isTexture) { 10279 data.aoMap = this.aoMap.toJSON(meta).uuid; 10280 data.aoMapIntensity = this.aoMapIntensity; 10281 } 10282 if (this.bumpMap && this.bumpMap.isTexture) { 10283 data.bumpMap = this.bumpMap.toJSON(meta).uuid; 10284 data.bumpScale = this.bumpScale; 10285 } 10286 if (this.normalMap && this.normalMap.isTexture) { 10287 data.normalMap = this.normalMap.toJSON(meta).uuid; 10288 data.normalMapType = this.normalMapType; 10289 data.normalScale = this.normalScale.toArray(); 10290 } 10291 if (this.displacementMap && this.displacementMap.isTexture) { 10292 data.displacementMap = this.displacementMap.toJSON(meta).uuid; 10293 data.displacementScale = this.displacementScale; 10294 data.displacementBias = this.displacementBias; 10295 } 10296 if (this.roughnessMap && this.roughnessMap.isTexture) data.roughnessMap = this.roughnessMap.toJSON(meta).uuid; 10297 if (this.metalnessMap && this.metalnessMap.isTexture) data.metalnessMap = this.metalnessMap.toJSON(meta).uuid; 10298 if (this.emissiveMap && this.emissiveMap.isTexture) data.emissiveMap = this.emissiveMap.toJSON(meta).uuid; 10299 if (this.specularMap && this.specularMap.isTexture) data.specularMap = this.specularMap.toJSON(meta).uuid; 10300 if (this.specularIntensityMap && this.specularIntensityMap.isTexture) data.specularIntensityMap = this.specularIntensityMap.toJSON(meta).uuid; 10301 if (this.specularColorMap && this.specularColorMap.isTexture) data.specularColorMap = this.specularColorMap.toJSON(meta).uuid; 10302 if (this.envMap && this.envMap.isTexture) { 10303 data.envMap = this.envMap.toJSON(meta).uuid; 10304 if (this.combine !== undefined) data.combine = this.combine; 10305 } 10306 if (this.envMapRotation !== undefined) data.envMapRotation = this.envMapRotation.toArray(); 10307 if (this.envMapIntensity !== undefined) data.envMapIntensity = this.envMapIntensity; 10308 if (this.reflectivity !== undefined) data.reflectivity = this.reflectivity; 10309 if (this.refractionRatio !== undefined) data.refractionRatio = this.refractionRatio; 10310 if (this.gradientMap && this.gradientMap.isTexture) { 10311 data.gradientMap = this.gradientMap.toJSON(meta).uuid; 10312 } 10313 if (this.transmission !== undefined) data.transmission = this.transmission; 10314 if (this.transmissionMap && this.transmissionMap.isTexture) data.transmissionMap = this.transmissionMap.toJSON(meta).uuid; 10315 if (this.thickness !== undefined) data.thickness = this.thickness; 10316 if (this.thicknessMap && this.thicknessMap.isTexture) data.thicknessMap = this.thicknessMap.toJSON(meta).uuid; 10317 if (this.attenuationDistance !== undefined && this.attenuationDistance !== Infinity) data.attenuationDistance = this.attenuationDistance; 10318 if (this.attenuationColor !== undefined) data.attenuationColor = this.attenuationColor.getHex(); 10319 if (this.size !== undefined) data.size = this.size; 10320 if (this.shadowSide !== null) data.shadowSide = this.shadowSide; 10321 if (this.sizeAttenuation !== undefined) data.sizeAttenuation = this.sizeAttenuation; 10322 if (this.blending !== NormalBlending) data.blending = this.blending; 10323 if (this.side !== FrontSide) data.side = this.side; 10324 if (this.vertexColors === true) data.vertexColors = true; 10325 if (this.opacity < 1) data.opacity = this.opacity; 10326 if (this.transparent === true) data.transparent = true; 10327 if (this.blendSrc !== SrcAlphaFactor) data.blendSrc = this.blendSrc; 10328 if (this.blendDst !== OneMinusSrcAlphaFactor) data.blendDst = this.blendDst; 10329 if (this.blendEquation !== AddEquation) data.blendEquation = this.blendEquation; 10330 if (this.blendSrcAlpha !== null) data.blendSrcAlpha = this.blendSrcAlpha; 10331 if (this.blendDstAlpha !== null) data.blendDstAlpha = this.blendDstAlpha; 10332 if (this.blendEquationAlpha !== null) data.blendEquationAlpha = this.blendEquationAlpha; 10333 if (this.blendColor && this.blendColor.isColor) data.blendColor = this.blendColor.getHex(); 10334 if (this.blendAlpha !== 0) data.blendAlpha = this.blendAlpha; 10335 if (this.depthFunc !== LessEqualDepth) data.depthFunc = this.depthFunc; 10336 if (this.depthTest === false) data.depthTest = this.depthTest; 10337 if (this.depthWrite === false) data.depthWrite = this.depthWrite; 10338 if (this.colorWrite === false) data.colorWrite = this.colorWrite; 10339 if (this.stencilWriteMask !== 0xff) data.stencilWriteMask = this.stencilWriteMask; 10340 if (this.stencilFunc !== AlwaysStencilFunc) data.stencilFunc = this.stencilFunc; 10341 if (this.stencilRef !== 0) data.stencilRef = this.stencilRef; 10342 if (this.stencilFuncMask !== 0xff) data.stencilFuncMask = this.stencilFuncMask; 10343 if (this.stencilFail !== KeepStencilOp) data.stencilFail = this.stencilFail; 10344 if (this.stencilZFail !== KeepStencilOp) data.stencilZFail = this.stencilZFail; 10345 if (this.stencilZPass !== KeepStencilOp) data.stencilZPass = this.stencilZPass; 10346 if (this.stencilWrite === true) data.stencilWrite = this.stencilWrite; 10347 // rotation (SpriteMaterial) 10348 if (this.rotation !== undefined && this.rotation !== 0) data.rotation = this.rotation; 10349 if (this.polygonOffset === true) data.polygonOffset = true; 10350 if (this.polygonOffsetFactor !== 0) data.polygonOffsetFactor = this.polygonOffsetFactor; 10351 if (this.polygonOffsetUnits !== 0) data.polygonOffsetUnits = this.polygonOffsetUnits; 10352 if (this.linewidth !== undefined && this.linewidth !== 1) data.linewidth = this.linewidth; 10353 if (this.dashSize !== undefined) data.dashSize = this.dashSize; 10354 if (this.gapSize !== undefined) data.gapSize = this.gapSize; 10355 if (this.scale !== undefined) data.scale = this.scale; 10356 if (this.dithering === true) data.dithering = true; 10357 if (this.alphaTest > 0) data.alphaTest = this.alphaTest; 10358 if (this.alphaHash === true) data.alphaHash = true; 10359 if (this.alphaToCoverage === true) data.alphaToCoverage = true; 10360 if (this.premultipliedAlpha === true) data.premultipliedAlpha = true; 10361 if (this.forceSinglePass === true) data.forceSinglePass = true; 10362 if (this.wireframe === true) data.wireframe = true; 10363 if (this.wireframeLinewidth > 1) data.wireframeLinewidth = this.wireframeLinewidth; 10364 if (this.wireframeLinecap !== 'round') data.wireframeLinecap = this.wireframeLinecap; 10365 if (this.wireframeLinejoin !== 'round') data.wireframeLinejoin = this.wireframeLinejoin; 10366 if (this.flatShading === true) data.flatShading = true; 10367 if (this.visible === false) data.visible = false; 10368 if (this.toneMapped === false) data.toneMapped = false; 10369 if (this.fog === false) data.fog = false; 10370 if (Object.keys(this.userData).length > 0) data.userData = this.userData; 10371 // TODO: Copied from Object3D.toJSON 10372 function extractFromCache(cache) { 10373 const values = []; 10374 for(const key in cache){ 10375 const data = cache[key]; 10376 delete data.metadata; 10377 values.push(data); 10378 } 10379 return values; 10380 } 10381 if (isRootObject) { 10382 const textures = extractFromCache(meta.textures); 10383 const images = extractFromCache(meta.images); 10384 if (textures.length > 0) data.textures = textures; 10385 if (images.length > 0) data.images = images; 10386 } 10387 return data; 10388 } 10389 /** 10390 * Returns a new material with copied values from this instance. 10391 * 10392 * @return {Material} A clone of this instance. 10393 */ clone() { 10394 return new this.constructor().copy(this); 10395 } 10396 /** 10397 * Copies the values of the given material to this instance. 10398 * 10399 * @param {Material} source - The material to copy. 10400 * @return {Material} A reference to this instance. 10401 */ copy(source) { 10402 this.name = source.name; 10403 this.blending = source.blending; 10404 this.side = source.side; 10405 this.vertexColors = source.vertexColors; 10406 this.opacity = source.opacity; 10407 this.transparent = source.transparent; 10408 this.blendSrc = source.blendSrc; 10409 this.blendDst = source.blendDst; 10410 this.blendEquation = source.blendEquation; 10411 this.blendSrcAlpha = source.blendSrcAlpha; 10412 this.blendDstAlpha = source.blendDstAlpha; 10413 this.blendEquationAlpha = source.blendEquationAlpha; 10414 this.blendColor.copy(source.blendColor); 10415 this.blendAlpha = source.blendAlpha; 10416 this.depthFunc = source.depthFunc; 10417 this.depthTest = source.depthTest; 10418 this.depthWrite = source.depthWrite; 10419 this.stencilWriteMask = source.stencilWriteMask; 10420 this.stencilFunc = source.stencilFunc; 10421 this.stencilRef = source.stencilRef; 10422 this.stencilFuncMask = source.stencilFuncMask; 10423 this.stencilFail = source.stencilFail; 10424 this.stencilZFail = source.stencilZFail; 10425 this.stencilZPass = source.stencilZPass; 10426 this.stencilWrite = source.stencilWrite; 10427 const srcPlanes = source.clippingPlanes; 10428 let dstPlanes = null; 10429 if (srcPlanes !== null) { 10430 const n = srcPlanes.length; 10431 dstPlanes = new Array(n); 10432 for(let i = 0; i !== n; ++i){ 10433 dstPlanes[i] = srcPlanes[i].clone(); 10434 } 10435 } 10436 this.clippingPlanes = dstPlanes; 10437 this.clipIntersection = source.clipIntersection;
10438 this.clipShadows = source.clipShadows; 10439 this.shadowSide = source.shadowSide; 10440 this.colorWrite = source.colorWrite; 10441 this.precision = source.precision; 10442 this.polygonOffset = source.polygonOffset; 10443 this.polygonOffsetFactor = source.polygonOffsetFactor; 10444 this.polygonOffsetUnits = source.polygonOffsetUnits; 10445 this.dithering = source.dithering; 10446 this.alphaTest = source.alphaTest; 10447 this.alphaHash = source.alphaHash; 10448 this.alphaToCoverage = source.alphaToCoverage; 10449 this.premultipliedAlpha = source.premultipliedAlpha; 10450 this.forceSinglePass = source.forceSinglePass; 10451 this.visible = source.visible; 10452 this.toneMapped = source.toneMapped; 10453 this.userData = JSON.parse(JSON.stringify(source.userData)); 10454 return this; 10455 } 10456 /** 10457 * Frees the GPU-related resources allocated by this instance. Call this 10458 * method whenever this instance is no longer used in your app. 10459 * 10460 * @fires Material#dispose 10461 */ dispose() { 10462 /** 10463 * Fires when the material has been disposed of. 10464 * 10465 * @event Material#dispose 10466 * @type {Object} 10467 */ this.dispatchEvent({ 10468 type: 'dispose' 10469 }); 10470 } 10471 /** 10472 * Setting this property to `true` indicates the engine the material 10473 * needs to be recompiled. 10474 * 10475 * @type {boolean} 10476 * @default false 10477 * @param {boolean} value 10478 */ set needsUpdate(value) { 10479 if (value === true) this.version++; 10480 } 10481 onBuild() { 10482 console.warn('Material: onBuild() has been removed.'); // @deprecated, r166 10483 } 10484 /** 10485 * Constructs a new material. 10486 */ constructor(){ 10487 super(); 10488 /** 10489 * This flag can be used for type testing. 10490 * 10491 * @type {boolean} 10492 * @readonly 10493 * @default true 10494 */ this.isMaterial = true; 10495 /** 10496 * The ID of the material. 10497 * 10498 * @name Material#id 10499 * @type {number} 10500 * @readonly 10501 */ Object.defineProperty(this, 'id', { 10502 value: _materialId++ 10503 }); 10504 /** 10505 * The UUID of the material. 10506 * 10507 * @type {string} 10508 * @readonly 10509 */ this.uuid = generateUUID(); 10510 /** 10511 * The name of the material. 10512 * 10513 * @type {string} 10514 */ this.name = ''; 10515 /** 10516 * The type property is used for detecting the object type 10517 * in context of serialization/deserialization. 10518 * 10519 * @type {string} 10520 * @readonly 10521 */ this.type = 'Material'; 10522 /** 10523 * Defines the blending type of the material. 10524 * 10525 * It must be set to `CustomBlending` if custom blending properties like 10526 * {@link Material#blendSrc}, {@link Material#blendDst} or {@link Material#blendEquation} 10527 * should have any effect. 10528 * 10529 * @type {(NoBlending|NormalBlending|AdditiveBlending|SubtractiveBlending|MultiplyBlending|CustomBlending)} 10530 * @default NormalBlending 10531 */ this.blending = NormalBlending; 10532 /** 10533 * Defines which side of faces will be rendered - front, back or both. 10534 * 10535 * @type {(FrontSide|BackSide|DoubleSide)} 10536 * @default FrontSide 10537 */ this.side = FrontSide; 10538 /** 10539 * If set to `true`, vertex colors should be used. 10540 * 10541 * The engine supports RGB and RGBA vertex colors depending on whether a three (RGB) or 10542 * four (RGBA) component color buffer attribute is used. 10543 * 10544 * @type {boolean} 10545 * @default false 10546 */ this.vertexColors = false; 10547 /** 10548 * Defines how transparent the material is. 10549 * A value of `0.0` indicates fully transparent, `1.0` is fully opaque. 10550 * 10551 * If the {@link Material#transparent} is not set to `true`, 10552 * the material will remain fully opaque and this value will only affect its color. 10553 * 10554 * @type {number} 10555 * @default 1 10556 */ this.opacity = 1; 10557 /** 10558 * Defines whether this material is transparent. This has an effect on 10559 * rendering as transparent objects need special treatment and are rendered 10560 * after non-transparent objects. 10561 * 10562 * When set to true, the extent to which the material is transparent is 10563 * controlled by {@link Material#opacity}. 10564 * 10565 * @type {boolean} 10566 * @default false 10567 */ this.transparent = false;
10568 /** 10569 * Enables alpha hashed transparency, an alternative to {@link Material#transparent} or 10570 * {@link Material#alphaTest}. The material will not be rendered if opacity is lower than 10571 * a random threshold. Randomization introduces some grain or noise, but approximates alpha 10572 * blending without the associated problems of sorting. Using TAA can reduce the resulting noise. 10573 * 10574 * @type {boolean} 10575 * @default false 10576 */ this.alphaHash = false; 10577 /** 10578 * Defines the blending source factor. 10579 * 10580 * @type {(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)} 10581 * @default SrcAlphaFactor 10582 */ this.blendSrc = SrcAlphaFactor; 10583 /** 10584 * Defines the blending destination factor. 10585 * 10586 * @type {(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)} 10587 * @default OneMinusSrcAlphaFactor 10588 */ this.blendDst = OneMinusSrcAlphaFactor; 10589 /** 10590 * Defines the blending equation. 10591 * 10592 * @type {(AddEquation|SubtractEquation|ReverseSubtractEquation|MinEquation|MaxEquation)} 10593 * @default OneMinusSrcAlphaFactor 10594 */ this.blendEquation = AddEquation; 10595 /** 10596 * Defines the blending source alpha factor. 10597 * 10598 * @type {?(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)} 10599 * @default null 10600 */ this.blendSrcAlpha = null; 10601 /** 10602 * Defines the blending destination alpha factor. 10603 * 10604 * @type {?(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)} 10605 * @default null 10606 */ this.blendDstAlpha = null; 10607 /** 10608 * Defines the blending equation of the alpha channel. 10609 * 10610 * @type {(AddEquation|SubtractEquation|ReverseSubtractEquation|MinEquation|MaxEquation)} 10611 * @default OneMinusSrcAlphaFactor 10612 */ this.blendEquationAlpha = null; 10613 /** 10614 * Represents the RGB values of the constant blend color. 10615 * 10616 * This property has only an effect when using custom blending with `ConstantColor` or `OneMinusConstantColor`. 10617 * 10618 * @type {Color} 10619 * @default (0,0,0) 10620 */ this.blendColor = new Color(0, 0, 0); 10621 /** 10622 * Represents the alpha value of the constant blend color. 10623 * 10624 * This property has only an effect when using custom blending with `ConstantAlpha` or `OneMinusConstantAlpha`. 10625 * 10626 * @type {number} 10627 * @default 0 10628 */ this.blendAlpha = 0; 10629 /** 10630 * Defines the depth function. 10631 * 10632 * @type {(NeverDepth|AlwaysDepth|LessDepth|LessEqualDepth|EqualDepth|GreaterEqualDepth|GreaterDepth|NotEqualDepth)} 10633 * @default LessEqualDepth 10634 */ this.depthFunc = LessEqualDepth; 10635 /** 10636 * Whether to have depth test enabled when rendering this material. 10637 * When the depth test is disabled, the depth write will also be implicitly disabled. 10638 * 10639 * @type {boolean} 10640 * @default true 10641 */ this.depthTest = true; 10642 /** 10643 * Whether rendering this material has any effect on the depth buffer. 10644 * 10645 * When drawing 2D overlays it can be useful to disable the depth writing in 10646 * order to layer several things together without creating z-index artifacts. 10647 * 10648 * @type {boolean} 10649 * @default true 10650 */ this.depthWrite = true; 10651 /** 10652 * The bit mask to use when writing to the stencil buffer. 10653 * 10654 * @type {number} 10655 * @default 0xff 10656 */ this.stencilWriteMask = 0xff; 10657 /** 10658 * The stencil comparison function to use. 10659 * 10660 * @type {NeverStencilFunc|LessStencilFunc|EqualStencilFunc|LessEqualStencilFunc|GreaterStencilFunc|NotEqualStencilFunc|GreaterEqualStencilFunc|AlwaysStencilFunc} 10661 * @default AlwaysStencilFunc 10662 */ this.stencilFunc = AlwaysStencilFunc; 10663 /** 10664 * The value to use when performing stencil comparisons or stencil operations. 10665 * 10666 * @type {number} 10667 * @default 0 10668 */ this.stencilRef = 0; 10669 /** 10670 * The bit mask to use when comparing against the stencil buffer. 10671 * 10672 * @type {number} 10673 * @default 0xff 10674 */ this.stencilFuncMask = 0xff; 10675 /** 10676 * Which stencil operation to perform when the comparison function returns `false`. 10677 * 10678 * @type {ZeroStencilOp|KeepStencilOp|ReplaceStencilOp|IncrementStencilOp|DecrementStencilOp|IncrementWrapStencilOp|DecrementWrapStencilOp|InvertStencilOp} 10679 * @default KeepStencilOp 10680 */ this.stencilFail = KeepStencilOp; 10681 /** 10682 * Which stencil operation to perform when the comparison function returns 10683 * `true` but the depth test fails. 10684 * 10685 * @type {ZeroStencilOp|KeepStencilOp|ReplaceStencilOp|IncrementStencilOp|DecrementStencilOp|IncrementWrapStencilOp|DecrementWrapStencilOp|InvertStencilOp} 10686 * @default KeepStencilOp 10687 */ this.stencilZFail = KeepStencilOp; 10688 /** 10689 * Which stencil operation to perform when the comparison function returns 10690 * `true` and the depth test passes. 10691 * 10692 * @type {ZeroStencilOp|KeepStencilOp|ReplaceStencilOp|IncrementStencilOp|DecrementStencilOp|IncrementWrapStencilOp|DecrementWrapStencilOp|InvertStencilOp} 10693 * @default KeepStencilOp 10694 */ this.stencilZPass = KeepStencilOp; 10695 /** 10696 * Whether stencil operations are performed against the stencil buffer. In 10697 * order to perform writes or comparisons against the stencil buffer this 10698 * value must be `true`. 10699 * 10700 * @type {boolean} 10701 * @default false 10702 */ this.stencilWrite = false;
10703 /** 10704 * User-defined clipping planes specified as THREE.Plane objects in world 10705 * space. These planes apply to the objects this material is attached to. 10706 * Points in space whose signed distance to the plane is negative are clipped 10707 * (not rendered). This requires {@link WebGLRenderer#localClippingEnabled} to 10708 * be `true`. 10709 * 10710 * @type {?Array<Plane>} 10711 * @default null 10712 */ this.clippingPlanes = null; 10713 /** 10714 * Changes the behavior of clipping planes so that only their intersection is 10715 * clipped, rather than their union. 10716 * 10717 * @type {boolean} 10718 * @default false 10719 */ this.clipIntersection = false; 10720 /** 10721 * Defines whether to clip shadows according to the clipping planes specified 10722 * on this material. 10723 * 10724 * @type {boolean} 10725 * @default false 10726 */ this.clipShadows = false; 10727 /** 10728 * Defines which side of faces cast shadows. If `null`, the side casting shadows 10729 * is determined as follows: 10730 * 10731 * - When {@link Material#side} is set to `FrontSide`, the back side cast shadows. 10732 * - When {@link Material#side} is set to `BackSide`, the front side cast shadows. 10733 * - When {@link Material#side} is set to `DoubleSide`, both sides cast shadows. 10734 * 10735 * @type {?(FrontSide|BackSide|DoubleSide)} 10736 * @default null 10737 */ this.shadowSide = null; 10738 /** 10739 * Whether to render the material's color. 10740 * 10741 * This can be used in conjunction with {@link Object3D#renderOder} to create invisible 10742 * objects that occlude other objects. 10743 * 10744 * @type {boolean} 10745 * @default true 10746 */ this.colorWrite = true; 10747 /** 10748 * Override the renderer's default precision for this material. 10749 * 10750 * @type {?('highp'|'mediump'|'lowp')} 10751 * @default null 10752 */ this.precision = null; 10753 /** 10754 * Whether to use polygon offset or not. When enabled, each fragment's depth value will 10755 * be offset after it is interpolated from the depth values of the appropriate vertices. 10756 * The offset is added before the depth test is performed and before the value is written 10757 * into the depth buffer. 10758 * 10759 * Can be useful for rendering hidden-line images, for applying decals to surfaces, and for 10760 * rendering solids with highlighted edges. 10761 * 10762 * @type {boolean} 10763 * @default false 10764 */ this.polygonOffset = false; 10765 /** 10766 * Specifies a scale factor that is used to create a variable depth offset for each polygon. 10767 * 10768 * @type {number} 10769 * @default 0 10770 */ this.polygonOffsetFactor = 0; 10771 /** 10772 * Is multiplied by an implementation-specific value to create a constant depth offset. 10773 * 10774 * @type {number} 10775 * @default 0 10776 */ this.polygonOffsetUnits = 0; 10777 /** 10778 * Whether to apply dithering to the color to remove the appearance of banding. 10779 * 10780 * @type {boolean} 10781 * @default false 10782 */ this.dithering = false; 10783 /** 10784 * Whether alpha to coverage should be enabled or not. Can only be used with MSAA-enabled contexts 10785 * (meaning when the renderer was created with *antialias* parameter set to `true`). Enabling this 10786 * will smooth aliasing on clip plane edges and alphaTest-clipped edges. 10787 * 10788 * @type {boolean} 10789 * @default false 10790 */ this.alphaToCoverage = false; 10791 /** 10792 * Whether to premultiply the alpha (transparency) value. 10793 * 10794 * @type {boolean} 10795 * @default false 10796 */ this.premultipliedAlpha = false; 10797 /** 10798 * Whether double-sided, transparent objects should be rendered with a single pass or not. 10799 * 10800 * The engine renders double-sided, transparent objects with two draw calls (back faces first, 10801 * then front faces) to mitigate transparency artifacts. There are scenarios however where this 10802 * approach produces no quality gains but still doubles draw calls e.g. when rendering flat 10803 * vegetation like grass sprites. In these cases, set the `forceSinglePass` flag to `true` to 10804 * disable the two pass rendering to avoid performance issues. 10805 * 10806 * @type {boolean} 10807 * @default false 10808 */ this.forceSinglePass = false;
vendor: 19,351 bytes, lines 10809-11385
10809 /** 10810 * Defines whether 3D objects using this material are visible. 10811 * 10812 * @type {boolean} 10813 * @default true 10814 */ this.visible = true; 10815 /** 10816 * Defines whether this material is tone mapped according to the renderer's tone mapping setting. 10817 * 10818 * It is ignored when rendering to a render target or using post processing or when using 10819 * `WebGPURenderer`. In all these cases, all materials are honored by tone mapping. 10820 * 10821 * @type {boolean} 10822 * @default true 10823 */ this.toneMapped = true; 10824 /** 10825 * An object that can be used to store custom data about the Material. It 10826 * should not hold references to functions as these will not be cloned. 10827 * 10828 * @type {Object} 10829 */ this.userData = {}; 10830 /** 10831 * This starts at `0` and counts how many times {@link Material#needsUpdate} is set to `true`. 10832 * 10833 * @type {number} 10834 * @readonly 10835 * @default 0 10836 */ this.version = 0; 10837 this._alphaTest = 0; 10838 } 10839 }; 10840 class MeshBasicMaterial extends Material$1 { 10841 copy(source) { 10842 super.copy(source); 10843 this.color.copy(source.color); 10844 this.map = source.map; 10845 this.lightMap = source.lightMap; 10846 this.lightMapIntensity = source.lightMapIntensity; 10847 this.aoMap = source.aoMap; 10848 this.aoMapIntensity = source.aoMapIntensity; 10849 this.specularMap = source.specularMap; 10850 this.alphaMap = source.alphaMap; 10851 this.envMap = source.envMap; 10852 this.envMapRotation.copy(source.envMapRotation); 10853 this.combine = source.combine; 10854 this.reflectivity = source.reflectivity; 10855 this.refractionRatio = source.refractionRatio; 10856 this.wireframe = source.wireframe; 10857 this.wireframeLinewidth = source.wireframeLinewidth; 10858 this.wireframeLinecap = source.wireframeLinecap; 10859 this.wireframeLinejoin = source.wireframeLinejoin; 10860 this.fog = source.fog; 10861 return this; 10862 } 10863 constructor(parameters){ 10864 super(); 10865 this.isMeshBasicMaterial = true; 10866 this.type = 'MeshBasicMaterial'; 10867 this.color = new Color(0xffffff); // emissive 10868 this.map = null; 10869 this.lightMap = null; 10870 this.lightMapIntensity = 1.0; 10871 this.aoMap = null; 10872 this.aoMapIntensity = 1.0; 10873 this.specularMap = null; 10874 this.alphaMap = null; 10875 this.envMap = null; 10876 this.envMapRotation = new Euler(); 10877 this.combine = MultiplyOperation; 10878 this.reflectivity = 1; 10879 this.refractionRatio = 0.98; 10880 this.wireframe = false; 10881 this.wireframeLinewidth = 1; 10882 this.wireframeLinecap = 'round'; 10883 this.wireframeLinejoin = 'round'; 10884 this.fog = true; 10885 this.setValues(parameters); 10886 } 10887 } 10888 // Fast Half Float Conversions, http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf 10889 const _tables = /*@__PURE__*/ _generateTables(); 10890 function _generateTables() { 10891 // float32 to float16 helpers 10892 const buffer = new ArrayBuffer(4); 10893 const floatView = new Float32Array(buffer); 10894 const uint32View = new Uint32Array(buffer); 10895 const baseTable = new Uint32Array(512); 10896 const shiftTable = new Uint32Array(512); 10897 for(let i = 0; i < 256; ++i){ 10898 const e = i - 127; 10899 // very small number (0, -0) 10900 if (e < -27) { 10901 baseTable[i] = 0x0000; 10902 baseTable[i | 0x100] = 0x8000; 10903 shiftTable[i] = 24; 10904 shiftTable[i | 0x100] = 24; 10905 // small number (denorm) 10906 } else if (e < -14) { 10907 baseTable[i] = 0x0400 >> -e - 14; 10908 baseTable[i | 0x100] = 0x0400 >> -e - 14 | 0x8000; 10909 shiftTable[i] = -e - 1; 10910 shiftTable[i | 0x100] = -e - 1; 10911 // normal number 10912 } else if (e <= 15) { 10913 baseTable[i] = e + 15 << 10; 10914 baseTable[i | 0x100] = e + 15 << 10 | 0x8000; 10915 shiftTable[i] = 13; 10916 shiftTable[i | 0x100] = 13; 10917 // large number (Infinity, -Infinity) 10918 } else if (e < 128) { 10919 baseTable[i] = 0x7c00; 10920 baseTable[i | 0x100] = 0xfc00; 10921 shiftTable[i] = 24; 10922 shiftTable[i | 0x100] = 24; 10923 // stay (NaN, Infinity, -Infinity) 10924 } else { 10925 baseTable[i] = 0x7c00; 10926 baseTable[i | 0x100] = 0xfc00; 10927 shiftTable[i] = 13; 10928 shiftTable[i | 0x100] = 13; 10929 } 10930 } 10931 // float16 to float32 helpers 10932 const mantissaTable = new Uint32Array(2048); 10933 const exponentTable = new Uint32Array(64); 10934 const offsetTable = new Uint32Array(64); 10935 for(let i = 1; i < 1024; ++i){ 10936 let m = i << 13; // zero pad mantissa bits 10937 let e = 0; // zero exponent 10938 // normalized 10939 while((m & 0x00800000) === 0){ 10940 m <<= 1; 10941 e -= 0x00800000; // decrement exponent 10942 } 10943 m &= -8388609; // clear leading 1 bit 10944 e += 0x38800000; // adjust bias 10945 mantissaTable[i] = m | e; 10946 } 10947 for(let i = 1024; i < 2048; ++i){ 10948 mantissaTable[i] = 0x38000000 + (i - 1024 << 13); 10949 } 10950 for(let i = 1; i < 31; ++i){ 10951 exponentTable[i] = i << 23; 10952 } 10953 exponentTable[31] = 0x47800000; 10954 exponentTable[32] = 0x80000000; 10955 for(let i = 33; i < 63; ++i){ 10956 exponentTable[i] = 0x80000000 + (i - 32 << 23); 10957 } 10958 exponentTable[63] = 0xc7800000; 10959 for(let i = 1; i < 64; ++i){ 10960 if (i !== 32) { 10961 offsetTable[i] = 1024; 10962 } 10963 } 10964 return { 10965 floatView: floatView, 10966 uint32View: uint32View, 10967 baseTable: baseTable, 10968 shiftTable: shiftTable, 10969 mantissaTable: mantissaTable, 10970 exponentTable: exponentTable, 10971 offsetTable: offsetTable 10972 }; 10973 } 10974 /** 10975 * Returns a half precision floating point value (FP16) from the given single 10976 * precision floating point value (FP32). 10977 * 10978 * @param {number} val - A single precision floating point value. 10979 * @return {number} The FP16 value. 10980 */ function toHalfFloat(val) { 10981 if (Math.abs(val) > 65504) console.warn('THREE.DataUtils.toHalfFloat(): Value out of range.'); 10982 val = clamp$1(val, -65504, 65504); 10983 _tables.floatView[0] = val; 10984 const f = _tables.uint32View[0]; 10985 const e = f >> 23 & 0x1ff; 10986 return _tables.baseTable[e] + ((f & 0x007fffff) >> _tables.shiftTable[e]); 10987 } 10988 /** 10989 * Returns a single precision floating point value (FP32) from the given half 10990 * precision floating point value (FP16). 10991 * 10992 * @param {number} val - A half precision floating point value. 10993 * @return {number} The FP32 value. 10994 */ function fromHalfFloat(val) { 10995 const m = val >> 10; 10996 _tables.uint32View[0] = _tables.mantissaTable[_tables.offsetTable[m] + (val & 0x3ff)] + _tables.exponentTable[m]; 10997 return _tables.floatView[0]; 10998 } 10999 /** 11000 * A class containing utility functions for data. 11001 * 11002 * @hideconstructor 11003 */ class DataUtils { 11004 /** 11005 * Returns a half precision floating point value (FP16) from the given single 11006 * precision floating point value (FP32). 11007 * 11008 * @param {number} val - A single precision floating point value. 11009 * @return {number} The FP16 value. 11010 */ static toHalfFloat(val) { 11011 return toHalfFloat(val); 11012 } 11013 /** 11014 * Returns a single precision floating point value (FP32) from the given half 11015 * precision floating point value (FP16). 11016 * 11017 * @param {number} val - A half precision floating point value. 11018 * @return {number} The FP32 value. 11019 */ static fromHalfFloat(val) { 11020 return fromHalfFloat(val); 11021 } 11022 } 11023 const _vector$9 = /*@__PURE__*/ new Vector3(); 11024 const _vector2$1 = /*@__PURE__*/ new Vector2(); 11025 let _id$2 = 0; 11026 class BufferAttribute { 11027 onUploadCallback() {} 11028 set needsUpdate(value) { 11029 if (value === true) this.version++; 11030 } 11031 setUsage(value) { 11032 this.usage = value; 11033 return this; 11034 } 11035 addUpdateRange(start, count) { 11036 this.updateRanges.push({ 11037 start, 11038 count 11039 }); 11040 } 11041 clearUpdateRanges() { 11042 this.updateRanges.length = 0; 11043 } 11044 copy(source) { 11045 this.name = source.name; 11046 this.array = new source.array.constructor(source.array); 11047 this.itemSize = source.itemSize; 11048 this.count = source.count; 11049 this.normalized = source.normalized; 11050 this.usage = source.usage; 11051 this.gpuType = source.gpuType; 11052 return this; 11053 } 11054 copyAt(index1, attribute, index2) { 11055 index1 *= this.itemSize; 11056 index2 *= attribute.itemSize; 11057 for(let i = 0, l = this.itemSize; i < l; i++){ 11058 this.array[index1 + i] = attribute.array[index2 + i]; 11059 } 11060 return this; 11061 } 11062 copyArray(array) { 11063 this.array.set(array); 11064 return this; 11065 } 11066 applyMatrix3(m) { 11067 if (this.itemSize === 2) { 11068 for(let i = 0, l = this.count; i < l; i++){ 11069 _vector2$1.fromBufferAttribute(this, i); 11070 _vector2$1.applyMatrix3(m); 11071 this.setXY(i, _vector2$1.x, _vector2$1.y); 11072 } 11073 } else if (this.itemSize === 3) { 11074 for(let i = 0, l = this.count; i < l; i++){ 11075 _vector$9.fromBufferAttribute(this, i); 11076 _vector$9.applyMatrix3(m); 11077 this.setXYZ(i, _vector$9.x, _vector$9.y, _vector$9.z); 11078 } 11079 } 11080 return this; 11081 } 11082 applyMatrix4(m) { 11083 for(let i = 0, l = this.count; i < l; i++){ 11084 _vector$9.fromBufferAttribute(this, i); 11085 _vector$9.applyMatrix4(m); 11086 this.setXYZ(i, _vector$9.x, _vector$9.y, _vector$9.z); 11087 } 11088 return this; 11089 } 11090 applyNormalMatrix(m) { 11091 for(let i = 0, l = this.count; i < l; i++){ 11092 _vector$9.fromBufferAttribute(this, i); 11093 _vector$9.applyNormalMatrix(m); 11094 this.setXYZ(i, _vector$9.x, _vector$9.y, _vector$9.z); 11095 } 11096 return this; 11097 } 11098 transformDirection(m) { 11099 for(let i = 0, l = this.count; i < l; i++){ 11100 _vector$9.fromBufferAttribute(this, i); 11101 _vector$9.transformDirection(m); 11102 this.setXYZ(i, _vector$9.x, _vector$9.y, _vector$9.z); 11103 } 11104 return this; 11105 } 11106 set(value, offset = 0) { 11107 // Matching BufferAttribute constructor, do not normalize the array. 11108 this.array.set(value, offset); 11109 return this; 11110 } 11111 getComponent(index, component) { 11112 let value = this.array[index * this.itemSize + component]; 11113 if (this.normalized) value = denormalize(value, this.array); 11114 return value; 11115 } 11116 setComponent(index, component, value) { 11117 if (this.normalized) value = normalize(value, this.array); 11118 this.array[index * this.itemSize + component] = value; 11119 return this; 11120 } 11121 getX(index) { 11122 let x = this.array[index * this.itemSize]; 11123 if (this.normalized) x = denormalize(x, this.array); 11124 return x; 11125 } 11126 setX(index, x) { 11127 if (this.normalized) x = normalize(x, this.array); 11128 this.array[index * this.itemSize] = x; 11129 return this; 11130 } 11131 getY(index) { 11132 let y = this.array[index * this.itemSize + 1]; 11133 if (this.normalized) y = denormalize(y, this.array); 11134 return y; 11135 } 11136 setY(index, y) { 11137 if (this.normalized) y = normalize(y, this.array); 11138 this.array[index * this.itemSize + 1] = y; 11139 return this; 11140 } 11141 getZ(index) { 11142 let z = this.array[index * this.itemSize + 2]; 11143 if (this.normalized) z = denormalize(z, this.array); 11144 return z; 11145 } 11146 setZ(index, z) { 11147 if (this.normalized) z = normalize(z, this.array); 11148 this.array[index * this.itemSize + 2] = z; 11149 return this; 11150 } 11151 getW(index) { 11152 let w = this.array[index * this.itemSize + 3]; 11153 if (this.normalized) w = denormalize(w, this.array); 11154 return w; 11155 } 11156 setW(index, w) { 11157 if (this.normalized) w = normalize(w, this.array); 11158 this.array[index * this.itemSize + 3] = w; 11159 return this; 11160 } 11161 setXY(index, x, y) { 11162 index *= this.itemSize; 11163 if (this.normalized) { 11164 x = normalize(x, this.array); 11165 y = normalize(y, this.array); 11166 } 11167 this.array[index + 0] = x; 11168 this.array[index + 1] = y; 11169 return this; 11170 } 11171 setXYZ(index, x, y, z) { 11172 index *= this.itemSize; 11173 if (this.normalized) { 11174 x = normalize(x, this.array); 11175 y = normalize(y, this.array); 11176 z = normalize(z, this.array); 11177 } 11178 this.array[index + 0] = x; 11179 this.array[index + 1] = y; 11180 this.array[index + 2] = z; 11181 return this; 11182 } 11183 setXYZW(index, x, y, z, w) { 11184 index *= this.itemSize; 11185 if (this.normalized) { 11186 x = normalize(x, this.array); 11187 y = normalize(y, this.array); 11188 z = normalize(z, this.array); 11189 w = normalize(w, this.array); 11190 } 11191 this.array[index + 0] = x; 11192 this.array[index + 1] = y; 11193 this.array[index + 2] = z; 11194 this.array[index + 3] = w; 11195 return this; 11196 } 11197 onUpload(callback) { 11198 this.onUploadCallback = callback; 11199 return this; 11200 } 11201 clone() { 11202 return new this.constructor(this.array, this.itemSize).copy(this); 11203 } 11204 toJSON() { 11205 const data = { 11206 itemSize: this.itemSize, 11207 type: this.array.constructor.name, 11208 array: Array.from(this.array), 11209 normalized: this.normalized 11210 }; 11211 if (this.name !== '') data.name = this.name; 11212 if (this.usage !== StaticDrawUsage) data.usage = this.usage; 11213 return data; 11214 } 11215 constructor(array, itemSize, normalized = false){ 11216 if (Array.isArray(array)) { 11217 throw new TypeError('THREE.BufferAttribute: array should be a Typed Array.'); 11218 } 11219 this.isBufferAttribute = true; 11220 Object.defineProperty(this, 'id', { 11221 value: _id$2++ 11222 }); 11223 this.name = ''; 11224 this.array = array; 11225 this.itemSize = itemSize; 11226 this.count = array !== undefined ? array.length / itemSize : 0; 11227 this.normalized = normalized; 11228 this.usage = StaticDrawUsage; 11229 this.updateRanges = []; 11230 this.gpuType = FloatType; 11231 this.version = 0; 11232 } 11233 } 11234 class Uint16BufferAttribute extends BufferAttribute { 11235 constructor(array, itemSize, normalized){ 11236 super(new Uint16Array(array), itemSize, normalized); 11237 } 11238 } 11239 class Uint32BufferAttribute extends BufferAttribute { 11240 constructor(array, itemSize, normalized){ 11241 super(new Uint32Array(array), itemSize, normalized); 11242 } 11243 } 11244 class Float32BufferAttribute extends BufferAttribute { 11245 constructor(array, itemSize, normalized){ 11246 super(new Float32Array(array), itemSize, normalized); 11247 } 11248 } 11249 let _id$1 = 0; 11250 const _m1$3 = /*@__PURE__*/ new Matrix4(); 11251 const _obj = /*@__PURE__*/ new Object3D(); 11252 const _offset = /*@__PURE__*/ new Vector3(); 11253 const _box$2 = /*@__PURE__*/ new Box3(); 11254 const _boxMorphTargets = /*@__PURE__*/ new Box3(); 11255 const _vector$8 = /*@__PURE__*/ new Vector3(); 11256 class BufferGeometry extends EventDispatcher { 11257 getIndex() { 11258 return this.index; 11259 } 11260 setIndex(index) { 11261 if (Array.isArray(index)) { 11262 this.index = new (arrayNeedsUint32(index) ? Uint32BufferAttribute : Uint16BufferAttribute)(index, 1); 11263 } else { 11264 this.index = index; 11265 } 11266 return this; 11267 } 11268 setIndirect(indirect) { 11269 this.indirect = indirect; 11270 return this; 11271 } 11272 getIndirect() { 11273 return this.indirect; 11274 } 11275 getAttribute(name) { 11276 return this.attributes[name]; 11277 } 11278 setAttribute(name, attribute) { 11279 this.attributes[name] = attribute; 11280 return this; 11281 } 11282 deleteAttribute(name) { 11283 delete this.attributes[name]; 11284 return this; 11285 } 11286 hasAttribute(name) { 11287 return this.attributes[name] !== undefined; 11288 } 11289 addGroup(start, count, materialIndex = 0) { 11290 this.groups.push({ 11291 start: start, 11292 count: count, 11293 materialIndex: materialIndex 11294 }); 11295 } 11296 clearGroups() { 11297 this.groups = []; 11298 } 11299 setDrawRange(start, count) { 11300 this.drawRange.start = start; 11301 this.drawRange.count = count; 11302 } 11303 applyMatrix4(matrix) { 11304 const position = this.attributes.position; 11305 if (position !== undefined) { 11306 position.applyMatrix4(matrix); 11307 position.needsUpdate = true; 11308 } 11309 const normal = this.attributes.normal; 11310 if (normal !== undefined) { 11311 const normalMatrix = new Matrix3().getNormalMatrix(matrix); 11312 normal.applyNormalMatrix(normalMatrix); 11313 normal.needsUpdate = true; 11314 } 11315 const tangent = this.attributes.tangent; 11316 if (tangent !== undefined) { 11317 tangent.transformDirection(matrix); 11318 tangent.needsUpdate = true; 11319 } 11320 if (this.boundingBox !== null) { 11321 this.computeBoundingBox(); 11322 } 11323 if (this.boundingSphere !== null) { 11324 this.computeBoundingSphere(); 11325 } 11326 return this; 11327 } 11328 applyQuaternion(q) { 11329 _m1$3.makeRotationFromQuaternion(q); 11330 this.applyMatrix4(_m1$3); 11331 return this; 11332 } 11333 rotateX(angle) { 11334 // rotate geometry around world x-axis 11335 _m1$3.makeRotationX(angle); 11336 this.applyMatrix4(_m1$3); 11337 return this; 11338 } 11339 rotateY(angle) { 11340 // rotate geometry around world y-axis 11341 _m1$3.makeRotationY(angle); 11342 this.applyMatrix4(_m1$3); 11343 return this; 11344 } 11345 rotateZ(angle) { 11346 // rotate geometry around world z-axis 11347 _m1$3.makeRotationZ(angle); 11348 this.applyMatrix4(_m1$3); 11349 return this; 11350 } 11351 translate(x, y, z) { 11352 // translate geometry 11353 _m1$3.makeTranslation(x, y, z); 11354 this.applyMatrix4(_m1$3); 11355 return this; 11356 } 11357 scale(x, y, z) { 11358 // scale geometry 11359 _m1$3.makeScale(x, y, z); 11360 this.applyMatrix4(_m1$3); 11361 return this; 11362 } 11363 lookAt(vector) { 11364 _obj.lookAt(vector); 11365 _obj.updateMatrix(); 11366 this.applyMatrix4(_obj.matrix); 11367 return this; 11368 } 11369 center() { 11370 this.computeBoundingBox(); 11371 this.boundingBox.getCenter(_offset).negate(); 11372 this.translate(_offset.x, _offset.y, _offset.z); 11373 return this; 11374 } 11375 setFromPoints(points) { 11376 const positionAttribute = this.getAttribute('position'); 11377 if (positionAttribute === undefined) { 11378 const position = []; 11379 for(let i = 0, l = points.length; i < l; i++){ 11380 const point = points[i]; 11381 position.push(point.x, point.y, point.z || 0); 11382 } 11383 this.setAttribute('position', new Float32BufferAttribute(position, 3)); 11384 } else { 11385 const l = Math.min(points.length, positionAttribute.count);
vendor: 4,159 bytes, lines 11385-11464
11385 // make sure data do not exceed buffer size 11386 for(let i = 0; i < l; i++){ 11387 const point = points[i]; 11388 positionAttribute.setXYZ(i, point.x, point.y, point.z || 0); 11389 } 11390 if (points.length > positionAttribute.count) { 11391 console.warn('THREE.BufferGeometry: Buffer size too small for points data. Use .dispose() and create a new geometry.'); 11392 } 11393 positionAttribute.needsUpdate = true; 11394 } 11395 return this; 11396 } 11397 computeBoundingBox() { 11398 if (this.boundingBox === null) { 11399 this.boundingBox = new Box3(); 11400 } 11401 const position = this.attributes.position; 11402 const morphAttributesPosition = this.morphAttributes.position; 11403 if (position && position.isGLBufferAttribute) { 11404 console.error('THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box.', this); 11405 this.boundingBox.set(new Vector3(-Infinity, -Infinity, -Infinity), new Vector3(+Infinity, +Infinity, +Infinity)); 11406 return; 11407 } 11408 if (position !== undefined) { 11409 this.boundingBox.setFromBufferAttribute(position); 11410 // process morph attributes if present 11411 if (morphAttributesPosition) { 11412 for(let i = 0, il = morphAttributesPosition.length; i < il; i++){ 11413 const morphAttribute = morphAttributesPosition[i]; 11414 _box$2.setFromBufferAttribute(morphAttribute); 11415 if (this.morphTargetsRelative) { 11416 _vector$8.addVectors(this.boundingBox.min, _box$2.min); 11417 this.boundingBox.expandByPoint(_vector$8); 11418 _vector$8.addVectors(this.boundingBox.max, _box$2.max); 11419 this.boundingBox.expandByPoint(_vector$8); 11420 } else { 11421 this.boundingBox.expandByPoint(_box$2.min); 11422 this.boundingBox.expandByPoint(_box$2.max); 11423 } 11424 } 11425 } 11426 } else { 11427 this.boundingBox.makeEmpty(); 11428 } 11429 if (isNaN(this.boundingBox.min.x) || isNaN(this.boundingBox.min.y) || isNaN(this.boundingBox.min.z)) { 11430 console.error('THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this); 11431 } 11432 } 11433 computeBoundingSphere() { 11434 if (this.boundingSphere === null) { 11435 this.boundingSphere = new Sphere(); 11436 } 11437 const position = this.attributes.position; 11438 const morphAttributesPosition = this.morphAttributes.position; 11439 if (position && position.isGLBufferAttribute) { 11440 console.error('THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere.', this); 11441 this.boundingSphere.set(new Vector3(), Infinity); 11442 return; 11443 } 11444 if (position) { 11445 // first, find the center of the bounding sphere 11446 const center = this.boundingSphere.center; 11447 _box$2.setFromBufferAttribute(position); 11448 // process morph attributes if present 11449 if (morphAttributesPosition) { 11450 for(let i = 0, il = morphAttributesPosition.length; i < il; i++){ 11451 const morphAttribute = morphAttributesPosition[i]; 11452 _boxMorphTargets.setFromBufferAttribute(morphAttribute); 11453 if (this.morphTargetsRelative) { 11454 _vector$8.addVectors(_box$2.min, _boxMorphTargets.min); 11455 _box$2.expandByPoint(_vector$8); 11456 _vector$8.addVectors(_box$2.max, _boxMorphTargets.max); 11457 _box$2.expandByPoint(_vector$8); 11458 } else { 11459 _box$2.expandByPoint(_boxMorphTargets.min); 11460 _box$2.expandByPoint(_boxMorphTargets.max); 11461 } 11462 } 11463 } 11464 _box$2.getCenter(center);
vendor: 12,663 bytes, lines 11465-11737
11465 // second, try to find a boundingSphere with a radius smaller than the 11466 // boundingSphere of the boundingBox: sqrt(3) smaller in the best case 11467 let maxRadiusSq = 0; 11468 for(let i = 0, il = position.count; i < il; i++){ 11469 _vector$8.fromBufferAttribute(position, i); 11470 maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(_vector$8)); 11471 } 11472 // process morph attributes if present 11473 if (morphAttributesPosition) { 11474 for(let i = 0, il = morphAttributesPosition.length; i < il; i++){ 11475 const morphAttribute = morphAttributesPosition[i]; 11476 const morphTargetsRelative = this.morphTargetsRelative; 11477 for(let j = 0, jl = morphAttribute.count; j < jl; j++){ 11478 _vector$8.fromBufferAttribute(morphAttribute, j); 11479 if (morphTargetsRelative) { 11480 _offset.fromBufferAttribute(position, j); 11481 _vector$8.add(_offset); 11482 } 11483 maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(_vector$8)); 11484 } 11485 } 11486 } 11487 this.boundingSphere.radius = Math.sqrt(maxRadiusSq); 11488 if (isNaN(this.boundingSphere.radius)) { 11489 console.error('THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this); 11490 } 11491 } 11492 } 11493 computeTangents() { 11494 const index = this.index; 11495 const attributes = this.attributes; 11496 // based on http://www.terathon.com/code/tangent.html 11497 // (per vertex tangents) 11498 if (index === null || attributes.position === undefined || attributes.normal === undefined || attributes.uv === undefined) { 11499 console.error('THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)'); 11500 return; 11501 } 11502 const positionAttribute = attributes.position; 11503 const normalAttribute = attributes.normal; 11504 const uvAttribute = attributes.uv; 11505 if (this.hasAttribute('tangent') === false) { 11506 this.setAttribute('tangent', new BufferAttribute(new Float32Array(4 * positionAttribute.count), 4)); 11507 } 11508 const tangentAttribute = this.getAttribute('tangent'); 11509 const tan1 = [], tan2 = []; 11510 for(let i = 0; i < positionAttribute.count; i++){ 11511 tan1[i] = new Vector3(); 11512 tan2[i] = new Vector3(); 11513 } 11514 const vA = new Vector3(), vB = new Vector3(), vC = new Vector3(), uvA = new Vector2(), uvB = new Vector2(), uvC = new Vector2(), sdir = new Vector3(), tdir = new Vector3(); 11515 function handleTriangle(a, b, c) { 11516 vA.fromBufferAttribute(positionAttribute, a); 11517 vB.fromBufferAttribute(positionAttribute, b); 11518 vC.fromBufferAttribute(positionAttribute, c); 11519 uvA.fromBufferAttribute(uvAttribute, a); 11520 uvB.fromBufferAttribute(uvAttribute, b); 11521 uvC.fromBufferAttribute(uvAttribute, c); 11522 vB.sub(vA); 11523 vC.sub(vA); 11524 uvB.sub(uvA); 11525 uvC.sub(uvA); 11526 const r = 1.0 / (uvB.x * uvC.y - uvC.x * uvB.y); 11527 // silently ignore degenerate uv triangles having coincident or colinear vertices 11528 if (!isFinite(r)) return; 11529 sdir.copy(vB).multiplyScalar(uvC.y).addScaledVector(vC, -uvB.y).multiplyScalar(r); 11530 tdir.copy(vC).multiplyScalar(uvB.x).addScaledVector(vB, -uvC.x).multiplyScalar(r); 11531 tan1[a].add(sdir); 11532 tan1[b].add(sdir); 11533 tan1[c].add(sdir); 11534 tan2[a].add(tdir); 11535 tan2[b].add(tdir); 11536 tan2[c].add(tdir); 11537 } 11538 let groups = this.groups; 11539 if (groups.length === 0) { 11540 groups = [ 11541 { 11542 start: 0, 11543 count: index.count 11544 } 11545 ]; 11546 } 11547 for(let i = 0, il = groups.length; i < il; ++i){ 11548 const group = groups[i]; 11549 const start = group.start; 11550 const count = group.count; 11551 for(let j = start, jl = start + count; j < jl; j += 3){ 11552 handleTriangle(index.getX(j + 0), index.getX(j + 1), index.getX(j + 2)); 11553 } 11554 } 11555 const tmp = new Vector3(), tmp2 = new Vector3(); 11556 const n = new Vector3(), n2 = new Vector3(); 11557 function handleVertex(v) { 11558 n.fromBufferAttribute(normalAttribute, v); 11559 n2.copy(n); 11560 const t = tan1[v]; 11561 // Gram-Schmidt orthogonalize 11562 tmp.copy(t); 11563 tmp.sub(n.multiplyScalar(n.dot(t))).normalize(); 11564 // Calculate handedness 11565 tmp2.crossVectors(n2, t); 11566 const test = tmp2.dot(tan2[v]); 11567 const w = test < 0.0 ? -1 : 1.0; 11568 tangentAttribute.setXYZW(v, tmp.x, tmp.y, tmp.z, w); 11569 } 11570 for(let i = 0, il = groups.length; i < il; ++i){ 11571 const group = groups[i]; 11572 const start = group.start; 11573 const count = group.count; 11574 for(let j = start, jl = start + count; j < jl; j += 3){ 11575 handleVertex(index.getX(j + 0)); 11576 handleVertex(index.getX(j + 1)); 11577 handleVertex(index.getX(j + 2)); 11578 } 11579 } 11580 } 11581 computeVertexNormals() { 11582 const index = this.index; 11583 const positionAttribute = this.getAttribute('position'); 11584 if (positionAttribute !== undefined) { 11585 let normalAttribute = this.getAttribute('normal'); 11586 if (normalAttribute === undefined) { 11587 normalAttribute = new BufferAttribute(new Float32Array(positionAttribute.count * 3), 3); 11588 this.setAttribute('normal', normalAttribute); 11589 } else { 11590 // reset existing normals to zero 11591 for(let i = 0, il = normalAttribute.count; i < il; i++){ 11592 normalAttribute.setXYZ(i, 0, 0, 0); 11593 } 11594 } 11595 const pA = new Vector3(), pB = new Vector3(), pC = new Vector3(); 11596 const nA = new Vector3(), nB = new Vector3(), nC = new Vector3(); 11597 const cb = new Vector3(), ab = new Vector3(); 11598 // indexed elements 11599 if (index) { 11600 for(let i = 0, il = index.count; i < il; i += 3){ 11601 const vA = index.getX(i + 0); 11602 const vB = index.getX(i + 1); 11603 const vC = index.getX(i + 2); 11604 pA.fromBufferAttribute(positionAttribute, vA); 11605 pB.fromBufferAttribute(positionAttribute, vB); 11606 pC.fromBufferAttribute(positionAttribute, vC); 11607 cb.subVectors(pC, pB); 11608 ab.subVectors(pA, pB); 11609 cb.cross(ab); 11610 nA.fromBufferAttribute(normalAttribute, vA); 11611 nB.fromBufferAttribute(normalAttribute, vB); 11612 nC.fromBufferAttribute(normalAttribute, vC); 11613 nA.add(cb); 11614 nB.add(cb); 11615 nC.add(cb); 11616 normalAttribute.setXYZ(vA, nA.x, nA.y, nA.z); 11617 normalAttribute.setXYZ(vB, nB.x, nB.y, nB.z); 11618 normalAttribute.setXYZ(vC, nC.x, nC.y, nC.z); 11619 } 11620 } else { 11621 // non-indexed elements (unconnected triangle soup) 11622 for(let i = 0, il = positionAttribute.count; i < il; i += 3){ 11623 pA.fromBufferAttribute(positionAttribute, i + 0); 11624 pB.fromBufferAttribute(positionAttribute, i + 1); 11625 pC.fromBufferAttribute(positionAttribute, i + 2); 11626 cb.subVectors(pC, pB); 11627 ab.subVectors(pA, pB); 11628 cb.cross(ab); 11629 normalAttribute.setXYZ(i + 0, cb.x, cb.y, cb.z); 11630 normalAttribute.setXYZ(i + 1, cb.x, cb.y, cb.z); 11631 normalAttribute.setXYZ(i + 2, cb.x, cb.y, cb.z); 11632 } 11633 } 11634 this.normalizeNormals(); 11635 normalAttribute.needsUpdate = true; 11636 } 11637 } 11638 normalizeNormals() { 11639 const normals = this.attributes.normal; 11640 for(let i = 0, il = normals.count; i < il; i++){ 11641 _vector$8.fromBufferAttribute(normals, i); 11642 _vector$8.normalize(); 11643 normals.setXYZ(i, _vector$8.x, _vector$8.y, _vector$8.z); 11644 } 11645 } 11646 toNonIndexed() { 11647 function convertBufferAttribute(attribute, indices) { 11648 const array = attribute.array; 11649 const itemSize = attribute.itemSize; 11650 const normalized = attribute.normalized; 11651 const array2 = new array.constructor(indices.length * itemSize); 11652 let index = 0, index2 = 0; 11653 for(let i = 0, l = indices.length; i < l; i++){ 11654 if (attribute.isInterleavedBufferAttribute) { 11655 index = indices[i] * attribute.data.stride + attribute.offset; 11656 } else { 11657 index = indices[i] * itemSize; 11658 } 11659 for(let j = 0; j < itemSize; j++){ 11660 array2[index2++] = array[index++]; 11661 } 11662 } 11663 return new BufferAttribute(array2, itemSize, normalized); 11664 } 11665 // 11666 if (this.index === null) { 11667 console.warn('THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.'); 11668 return this; 11669 } 11670 const geometry2 = new BufferGeometry(); 11671 const indices = this.index.array; 11672 const attributes = this.attributes; 11673 // attributes 11674 for(const name in attributes){ 11675 const attribute = attributes[name]; 11676 const newAttribute = convertBufferAttribute(attribute, indices); 11677 geometry2.setAttribute(name, newAttribute); 11678 } 11679 // morph attributes 11680 const morphAttributes = this.morphAttributes; 11681 for(const name in morphAttributes){ 11682 const morphArray = []; 11683 const morphAttribute = morphAttributes[name]; // morphAttribute: array of Float32BufferAttributes 11684 for(let i = 0, il = morphAttribute.length; i < il; i++){ 11685 const attribute = morphAttribute[i]; 11686 const newAttribute = convertBufferAttribute(attribute, indices); 11687 morphArray.push(newAttribute); 11688 } 11689 geometry2.morphAttributes[name] = morphArray; 11690 } 11691 geometry2.morphTargetsRelative = this.morphTargetsRelative; 11692 // groups 11693 const groups = this.groups; 11694 for(let i = 0, l = groups.length; i < l; i++){ 11695 const group = groups[i]; 11696 geometry2.addGroup(group.start, group.count, group.materialIndex); 11697 } 11698 return geometry2; 11699 } 11700 toJSON() { 11701 const data = { 11702 metadata: { 11703 version: 4.6, 11704 type: 'BufferGeometry', 11705 generator: 'BufferGeometry.toJSON' 11706 } 11707 }; 11708 // standard BufferGeometry serialization 11709 data.uuid = this.uuid; 11710 data.type = this.type; 11711 if (this.name !== '') data.name = this.name; 11712 if (Object.keys(this.userData).length > 0) data.userData = this.userData; 11713 if (this.parameters !== undefined) { 11714 const parameters = this.parameters; 11715 for(const key in parameters){ 11716 if (parameters[key] !== undefined) data[key] = parameters[key]; 11717 } 11718 return data; 11719 } 11720 // for simplicity the code assumes attributes are not shared across geometries, see #15811 11721 data.data = { 11722 attributes: {} 11723 }; 11724 const index = this.index; 11725 if (index !== null) { 11726 data.data.index = { 11727 type: index.array.constructor.name, 11728 array: Array.prototype.slice.call(index.array) 11729 }; 11730 } 11731 const attributes = this.attributes; 11732 for(const key in attributes){ 11733 const attribute = attributes[key]; 11734 data.data.attributes[key] = attribute.toJSON(data.data); 11735 } 11736 const morphAttributes = {}; 11737 let hasMorphAttributes = false;
vendor: 5,811 bytes, lines 11738-11896
11738 for(const key in this.morphAttributes){ 11739 const attributeArray = this.morphAttributes[key]; 11740 const array = []; 11741 for(let i = 0, il = attributeArray.length; i < il; i++){ 11742 const attribute = attributeArray[i]; 11743 array.push(attribute.toJSON(data.data)); 11744 } 11745 if (array.length > 0) { 11746 morphAttributes[key] = array; 11747 hasMorphAttributes = true; 11748 } 11749 } 11750 if (hasMorphAttributes) { 11751 data.data.morphAttributes = morphAttributes; 11752 data.data.morphTargetsRelative = this.morphTargetsRelative; 11753 } 11754 const groups = this.groups; 11755 if (groups.length > 0) { 11756 data.data.groups = JSON.parse(JSON.stringify(groups)); 11757 } 11758 const boundingSphere = this.boundingSphere; 11759 if (boundingSphere !== null) { 11760 data.data.boundingSphere = { 11761 center: boundingSphere.center.toArray(), 11762 radius: boundingSphere.radius 11763 }; 11764 } 11765 return data; 11766 } 11767 clone() { 11768 return new this.constructor().copy(this); 11769 } 11770 copy(source) { 11771 // reset 11772 this.index = null; 11773 this.attributes = {}; 11774 this.morphAttributes = {}; 11775 this.groups = []; 11776 this.boundingBox = null; 11777 this.boundingSphere = null; 11778 // used for storing cloned, shared data 11779 const data = {}; 11780 // name 11781 this.name = source.name; 11782 // index 11783 const index = source.index; 11784 if (index !== null) { 11785 this.setIndex(index.clone(data)); 11786 } 11787 // attributes 11788 const attributes = source.attributes; 11789 for(const name in attributes){ 11790 const attribute = attributes[name]; 11791 this.setAttribute(name, attribute.clone(data)); 11792 } 11793 // morph attributes 11794 const morphAttributes = source.morphAttributes; 11795 for(const name in morphAttributes){ 11796 const array = []; 11797 const morphAttribute = morphAttributes[name]; // morphAttribute: array of Float32BufferAttributes 11798 for(let i = 0, l = morphAttribute.length; i < l; i++){ 11799 array.push(morphAttribute[i].clone(data)); 11800 } 11801 this.morphAttributes[name] = array; 11802 } 11803 this.morphTargetsRelative = source.morphTargetsRelative; 11804 // groups 11805 const groups = source.groups; 11806 for(let i = 0, l = groups.length; i < l; i++){ 11807 const group = groups[i]; 11808 this.addGroup(group.start, group.count, group.materialIndex); 11809 } 11810 // bounding box 11811 const boundingBox = source.boundingBox; 11812 if (boundingBox !== null) { 11813 this.boundingBox = boundingBox.clone(); 11814 } 11815 // bounding sphere 11816 const boundingSphere = source.boundingSphere; 11817 if (boundingSphere !== null) { 11818 this.boundingSphere = boundingSphere.clone(); 11819 } 11820 // draw range 11821 this.drawRange.start = source.drawRange.start; 11822 this.drawRange.count = source.drawRange.count; 11823 // user data 11824 this.userData = source.userData; 11825 return this; 11826 } 11827 dispose() { 11828 this.dispatchEvent({ 11829 type: 'dispose' 11830 }); 11831 } 11832 constructor(){ 11833 super(); 11834 this.isBufferGeometry = true; 11835 Object.defineProperty(this, 'id', { 11836 value: _id$1++ 11837 }); 11838 this.uuid = generateUUID(); 11839 this.name = ''; 11840 this.type = 'BufferGeometry'; 11841 this.index = null; 11842 this.indirect = null; 11843 this.attributes = {}; 11844 this.morphAttributes = {}; 11845 this.morphTargetsRelative = false; 11846 this.groups = []; 11847 this.boundingBox = null; 11848 this.boundingSphere = null; 11849 this.drawRange = { 11850 start: 0, 11851 count: Infinity 11852 }; 11853 this.userData = {}; 11854 } 11855 } 11856 const _inverseMatrix$3 = /*@__PURE__*/ new Matrix4(); 11857 const _ray$3 = /*@__PURE__*/ new Ray(); 11858 const _sphere$6 = /*@__PURE__*/ new Sphere(); 11859 const _sphereHitAt = /*@__PURE__*/ new Vector3(); 11860 const _vA$1 = /*@__PURE__*/ new Vector3(); 11861 const _vB$1 = /*@__PURE__*/ new Vector3(); 11862 const _vC$1 = /*@__PURE__*/ new Vector3(); 11863 const _tempA = /*@__PURE__*/ new Vector3(); 11864 const _morphA = /*@__PURE__*/ new Vector3(); 11865 const _intersectionPoint = /*@__PURE__*/ new Vector3(); 11866 const _intersectionPointWorld = /*@__PURE__*/ new Vector3(); 11867 /** 11868 * Class representing triangular polygon mesh based objects. 11869 * 11870 * ```js 11871 * const geometry = new THREE.BoxGeometry( 1, 1, 1 ); 11872 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); 11873 * const mesh = new THREE.Mesh( geometry, material ); 11874 * scene.add( mesh ); 11875 * ``` 11876 * 11877 * @augments Object3D 11878 */ class Mesh extends Object3D { 11879 copy(source, recursive) { 11880 super.copy(source, recursive); 11881 if (source.morphTargetInfluences !== undefined) { 11882 this.morphTargetInfluences = source.morphTargetInfluences.slice(); 11883 } 11884 if (source.morphTargetDictionary !== undefined) { 11885 this.morphTargetDictionary = Object.assign({}, source.morphTargetDictionary); 11886 } 11887 this.material = Array.isArray(source.material) ? source.material.slice() : source.material; 11888 this.geometry = source.geometry; 11889 return this; 11890 } 11891 /** 11892 * Sets the values of {@link Mesh#morphTargetDictionary} and {@link Mesh#morphTargetInfluences} 11893 * to make sure existing morph targets can influence this 3D object. 11894 */ updateMorphTargets() { 11895 const geometry = this.geometry; 11896 const morphAttributes = geometry.morphAttributes;
vendor: 28,356 bytes, lines 11897-12564
11897 const keys = Object.keys(morphAttributes); 11898 if (keys.length > 0) { 11899 const morphAttribute = morphAttributes[keys[0]]; 11900 if (morphAttribute !== undefined) { 11901 this.morphTargetInfluences = []; 11902 this.morphTargetDictionary = {}; 11903 for(let m = 0, ml = morphAttribute.length; m < ml; m++){ 11904 const name = morphAttribute[m].name || String(m); 11905 this.morphTargetInfluences.push(0); 11906 this.morphTargetDictionary[name] = m; 11907 } 11908 } 11909 } 11910 } 11911 /** 11912 * Returns the local-space position of the vertex at the given index, taking into 11913 * account the current animation state of both morph targets and skinning. 11914 * 11915 * @param {number} index - The vertex index. 11916 * @param {Vector3} target - The target object that is used to store the method's result. 11917 * @return {Vector3} The vertex position in local space. 11918 */ getVertexPosition(index, target) { 11919 const geometry = this.geometry; 11920 const position = geometry.attributes.position; 11921 const morphPosition = geometry.morphAttributes.position; 11922 const morphTargetsRelative = geometry.morphTargetsRelative; 11923 target.fromBufferAttribute(position, index); 11924 const morphInfluences = this.morphTargetInfluences; 11925 if (morphPosition && morphInfluences) { 11926 _morphA.set(0, 0, 0); 11927 for(let i = 0, il = morphPosition.length; i < il; i++){ 11928 const influence = morphInfluences[i]; 11929 const morphAttribute = morphPosition[i]; 11930 if (influence === 0) continue; 11931 _tempA.fromBufferAttribute(morphAttribute, index); 11932 if (morphTargetsRelative) { 11933 _morphA.addScaledVector(_tempA, influence); 11934 } else { 11935 _morphA.addScaledVector(_tempA.sub(target), influence); 11936 } 11937 } 11938 target.add(_morphA); 11939 } 11940 return target; 11941 } 11942 /** 11943 * Computes intersection points between a casted ray and this line. 11944 * 11945 * @param {Raycaster} raycaster - The raycaster. 11946 * @param {Array<Object>} intersects - The target array that holds the intersection points. 11947 */ raycast(raycaster, intersects) { 11948 const geometry = this.geometry; 11949 const material = this.material; 11950 const matrixWorld = this.matrixWorld; 11951 if (material === undefined) return; 11952 // test with bounding sphere in world space 11953 if (geometry.boundingSphere === null) geometry.computeBoundingSphere(); 11954 _sphere$6.copy(geometry.boundingSphere); 11955 _sphere$6.applyMatrix4(matrixWorld); 11956 // check distance from ray origin to bounding sphere 11957 _ray$3.copy(raycaster.ray).recast(raycaster.near); 11958 if (_sphere$6.containsPoint(_ray$3.origin) === false) { 11959 if (_ray$3.intersectSphere(_sphere$6, _sphereHitAt) === null) return; 11960 if (_ray$3.origin.distanceToSquared(_sphereHitAt) > (raycaster.far - raycaster.near) ** 2) return; 11961 } 11962 // convert ray to local space of mesh 11963 _inverseMatrix$3.copy(matrixWorld).invert(); 11964 _ray$3.copy(raycaster.ray).applyMatrix4(_inverseMatrix$3); 11965 // test with bounding box in local space 11966 if (geometry.boundingBox !== null) { 11967 if (_ray$3.intersectsBox(geometry.boundingBox) === false) return; 11968 } 11969 // test for intersections with geometry 11970 this._computeIntersections(raycaster, intersects, _ray$3); 11971 } 11972 _computeIntersections(raycaster, intersects, rayLocalSpace) { 11973 let intersection; 11974 const geometry = this.geometry; 11975 const material = this.material; 11976 const index = geometry.index; 11977 const position = geometry.attributes.position; 11978 const uv = geometry.attributes.uv; 11979 const uv1 = geometry.attributes.uv1; 11980 const normal = geometry.attributes.normal; 11981 const groups = geometry.groups; 11982 const drawRange = geometry.drawRange; 11983 if (index !== null) { 11984 // indexed buffer geometry 11985 if (Array.isArray(material)) { 11986 for(let i = 0, il = groups.length; i < il; i++){ 11987 const group = groups[i]; 11988 const groupMaterial = material[group.materialIndex]; 11989 const start = Math.max(group.start, drawRange.start); 11990 const end = Math.min(index.count, Math.min(group.start + group.count, drawRange.start + drawRange.count)); 11991 for(let j = start, jl = end; j < jl; j += 3){ 11992 const a = index.getX(j); 11993 const b = index.getX(j + 1); 11994 const c = index.getX(j + 2); 11995 intersection = checkGeometryIntersection(this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c); 11996 if (intersection) { 11997 intersection.faceIndex = Math.floor(j / 3); // triangle number in indexed buffer semantics 11998 intersection.face.materialIndex = group.materialIndex; 11999 intersects.push(intersection); 12000 } 12001 } 12002 } 12003 } else { 12004 const start = Math.max(0, drawRange.start); 12005 const end = Math.min(index.count, drawRange.start + drawRange.count); 12006 for(let i = start, il = end; i < il; i += 3){ 12007 const a = index.getX(i); 12008 const b = index.getX(i + 1); 12009 const c = index.getX(i + 2); 12010 intersection = checkGeometryIntersection(this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c); 12011 if (intersection) { 12012 intersection.faceIndex = Math.floor(i / 3); // triangle number in indexed buffer semantics 12013 intersects.push(intersection); 12014 } 12015 } 12016 } 12017 } else if (position !== undefined) { 12018 // non-indexed buffer geometry 12019 if (Array.isArray(material)) { 12020 for(let i = 0, il = groups.length; i < il; i++){ 12021 const group = groups[i]; 12022 const groupMaterial = material[group.materialIndex]; 12023 const start = Math.max(group.start, drawRange.start); 12024 const end = Math.min(position.count, Math.min(group.start + group.count, drawRange.start + drawRange.count)); 12025 for(let j = start, jl = end; j < jl; j += 3){ 12026 const a = j; 12027 const b = j + 1; 12028 const c = j + 2; 12029 intersection = checkGeometryIntersection(this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c); 12030 if (intersection) { 12031 intersection.faceIndex = Math.floor(j / 3); // triangle number in non-indexed buffer semantics 12032 intersection.face.materialIndex = group.materialIndex; 12033 intersects.push(intersection); 12034 } 12035 } 12036 } 12037 } else { 12038 const start = Math.max(0, drawRange.start); 12039 const end = Math.min(position.count, drawRange.start + drawRange.count); 12040 for(let i = start, il = end; i < il; i += 3){ 12041 const a = i; 12042 const b = i + 1; 12043 const c = i + 2; 12044 intersection = checkGeometryIntersection(this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c); 12045 if (intersection) { 12046 intersection.faceIndex = Math.floor(i / 3); // triangle number in non-indexed buffer semantics 12047 intersects.push(intersection); 12048 } 12049 } 12050 } 12051 } 12052 } 12053 /** 12054 * Constructs a new mesh. 12055 * 12056 * @param {BufferGeometry} [geometry] - The mesh geometry. 12057 * @param {Material|Array<Material>} [material] - The mesh material. 12058 */ constructor(geometry = new BufferGeometry(), material = new MeshBasicMaterial()){ 12059 super(); 12060 /** 12061 * This flag can be used for type testing. 12062 * 12063 * @type {boolean} 12064 * @readonly 12065 * @default true 12066 */ this.isMesh = true; 12067 this.type = 'Mesh'; 12068 /** 12069 * The mesh geometry. 12070 * 12071 * @type {BufferGeometry} 12072 */ this.geometry = geometry; 12073 /** 12074 * The mesh material. 12075 * 12076 * @type {Material|Array<Material>} 12077 * @default MeshBasicMaterial 12078 */ this.material = material; 12079 /** 12080 * A dictionary representing the morph targets in the geometry. The key is the 12081 * morph targets name, the value its attribute index. This member is `undefined` 12082 * by default and only set when morph targets are detected in the geometry. 12083 * 12084 * @type {Object<String,number>|undefined} 12085 * @default undefined 12086 */ this.morphTargetDictionary = undefined; 12087 /** 12088 * An array of weights typically in the range `[0,1]` that specify how much of the morph 12089 * is applied. This member is `undefined` by default and only set when morph targets are 12090 * detected in the geometry. 12091 * 12092 * @type {Array<number>|undefined} 12093 * @default undefined 12094 */ this.morphTargetInfluences = undefined; 12095 this.updateMorphTargets(); 12096 } 12097 } 12098 function checkIntersection$1(object, material, raycaster, ray, pA, pB, pC, point) { 12099 let intersect; 12100 if (material.side === BackSide) { 12101 intersect = ray.intersectTriangle(pC, pB, pA, true, point); 12102 } else { 12103 intersect = ray.intersectTriangle(pA, pB, pC, material.side === FrontSide, point); 12104 } 12105 if (intersect === null) return null; 12106 _intersectionPointWorld.copy(point); 12107 _intersectionPointWorld.applyMatrix4(object.matrixWorld); 12108 const distance = raycaster.ray.origin.distanceTo(_intersectionPointWorld); 12109 if (distance < raycaster.near || distance > raycaster.far) return null; 12110 return { 12111 distance: distance, 12112 point: _intersectionPointWorld.clone(), 12113 object: object 12114 }; 12115 } 12116 function checkGeometryIntersection(object, material, raycaster, ray, uv, uv1, normal, a, b, c) { 12117 object.getVertexPosition(a, _vA$1); 12118 object.getVertexPosition(b, _vB$1); 12119 object.getVertexPosition(c, _vC$1); 12120 const intersection = checkIntersection$1(object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint); 12121 if (intersection) { 12122 const barycoord = new Vector3(); 12123 Triangle.getBarycoord(_intersectionPoint, _vA$1, _vB$1, _vC$1, barycoord); 12124 if (uv) { 12125 intersection.uv = Triangle.getInterpolatedAttribute(uv, a, b, c, barycoord, new Vector2()); 12126 } 12127 if (uv1) { 12128 intersection.uv1 = Triangle.getInterpolatedAttribute(uv1, a, b, c, barycoord, new Vector2()); 12129 } 12130 if (normal) { 12131 intersection.normal = Triangle.getInterpolatedAttribute(normal, a, b, c, barycoord, new Vector3()); 12132 if (intersection.normal.dot(ray.direction) > 0) { 12133 intersection.normal.multiplyScalar(-1); 12134 } 12135 } 12136 const face = { 12137 a: a, 12138 b: b, 12139 c: c, 12140 normal: new Vector3(), 12141 materialIndex: 0 12142 }; 12143 Triangle.getNormal(_vA$1, _vB$1, _vC$1, face.normal); 12144 intersection.face = face; 12145 intersection.barycoord = barycoord; 12146 } 12147 return intersection; 12148 } 12149 /** 12150 * A geometry class for a rectangular cuboid with a given width, height, and depth. 12151 * On creation, the cuboid is centred on the origin, with each edge parallel to one 12152 * of the axes. 12153 * 12154 * ```js 12155 * const geometry = new THREE.BoxGeometry( 1, 1, 1 ); 12156 * const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); 12157 * const cube = new THREE.Mesh( geometry, material ); 12158 * scene.add( cube ); 12159 * ``` 12160 * 12161 * @augments BufferGeometry 12162 */ class BoxGeometry extends BufferGeometry { 12163 copy(source) { 12164 super.copy(source); 12165 this.parameters = Object.assign({}, source.parameters); 12166 return this; 12167 } 12168 /** 12169 * Factory method for creating an instance of this class from the given 12170 * JSON object. 12171 * 12172 * @param {Object} data - A JSON object representing the serialized geometry. 12173 * @return {BoxGeometry} A new instance. 12174 */ static fromJSON(data) { 12175 return new BoxGeometry(data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments); 12176 } 12177 /** 12178 * Constructs a new box geometry. 12179 * 12180 * @param {number} [width=1] - The width. That is, the length of the edges parallel to the X axis. 12181 * @param {number} [height=1] - The height. That is, the length of the edges parallel to the Y axis. 12182 * @param {number} [depth=1] - The depth. That is, the length of the edges parallel to the Z axis. 12183 * @param {number} [widthSegments=1] - Number of segmented rectangular faces along the width of the sides. 12184 * @param {number} [heightSegments=1] - Number of segmented rectangular faces along the height of the sides. 12185 * @param {number} [depthSegments=1] - Number of segmented rectangular faces along the depth of the sides. 12186 */ constructor(width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1){ 12187 super(); 12188 this.type = 'BoxGeometry'; 12189 /** 12190 * Holds the constructor parameters that have been 12191 * used to generate the geometry. Any modification 12192 * after instantiation does not change the geometry. 12193 * 12194 * @type {Object} 12195 */ this.parameters = { 12196 width: width, 12197 height: height, 12198 depth: depth, 12199 widthSegments: widthSegments, 12200 heightSegments: heightSegments, 12201 depthSegments: depthSegments 12202 }; 12203 const scope = this; 12204 // segments 12205 widthSegments = Math.floor(widthSegments); 12206 heightSegments = Math.floor(heightSegments); 12207 depthSegments = Math.floor(depthSegments); 12208 // buffers 12209 const indices = []; 12210 const vertices = []; 12211 const normals = []; 12212 const uvs = []; 12213 // helper variables 12214 let numberOfVertices = 0; 12215 let groupStart = 0; 12216 // build each side of the box geometry 12217 buildPlane('z', 'y', 'x', -1, -1, depth, height, width, depthSegments, heightSegments, 0); // px 12218 buildPlane('z', 'y', 'x', 1, -1, depth, height, -width, depthSegments, heightSegments, 1); // nx 12219 buildPlane('x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2); // py 12220 buildPlane('x', 'z', 'y', 1, -1, width, depth, -height, widthSegments, depthSegments, 3); // ny 12221 buildPlane('x', 'y', 'z', 1, -1, width, height, depth, widthSegments, heightSegments, 4); // pz 12222 buildPlane('x', 'y', 'z', -1, -1, width, height, -depth, widthSegments, heightSegments, 5); // nz 12223 // build geometry 12224 this.setIndex(indices); 12225 this.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 12226 this.setAttribute('normal', new Float32BufferAttribute(normals, 3)); 12227 this.setAttribute('uv', new Float32BufferAttribute(uvs, 2)); 12228 function buildPlane(u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex) { 12229 const segmentWidth = width / gridX; 12230 const segmentHeight = height / gridY; 12231 const widthHalf = width / 2; 12232 const heightHalf = height / 2; 12233 const depthHalf = depth / 2; 12234 const gridX1 = gridX + 1; 12235 const gridY1 = gridY + 1; 12236 let vertexCounter = 0; 12237 let groupCount = 0; 12238 const vector = new Vector3(); 12239 // generate vertices, normals and uvs 12240 for(let iy = 0; iy < gridY1; iy++){ 12241 const y = iy * segmentHeight - heightHalf; 12242 for(let ix = 0; ix < gridX1; ix++){ 12243 const x = ix * segmentWidth - widthHalf; 12244 // set values to correct vector component 12245 vector[u] = x * udir; 12246 vector[v] = y * vdir; 12247 vector[w] = depthHalf; 12248 // now apply vector to vertex buffer 12249 vertices.push(vector.x, vector.y, vector.z); 12250 // set values to correct vector component 12251 vector[u] = 0; 12252 vector[v] = 0; 12253 vector[w] = depth > 0 ? 1 : -1; 12254 // now apply vector to normal buffer 12255 normals.push(vector.x, vector.y, vector.z); 12256 // uvs 12257 uvs.push(ix / gridX); 12258 uvs.push(1 - iy / gridY); 12259 // counters 12260 vertexCounter += 1; 12261 } 12262 } 12263 // indices 12264 // 1. you need three indices to draw a single face 12265 // 2. a single segment consists of two faces 12266 // 3. so we need to generate six (2*3) indices per segment 12267 for(let iy = 0; iy < gridY; iy++){ 12268 for(let ix = 0; ix < gridX; ix++){ 12269 const a = numberOfVertices + ix + gridX1 * iy; 12270 const b = numberOfVertices + ix + gridX1 * (iy + 1); 12271 const c = numberOfVertices + (ix + 1) + gridX1 * (iy + 1); 12272 const d = numberOfVertices + (ix + 1) + gridX1 * iy; 12273 // faces 12274 indices.push(a, b, d); 12275 indices.push(b, c, d); 12276 // increase counter 12277 groupCount += 6; 12278 } 12279 } 12280 // add a group to the geometry. this will ensure multi material support 12281 scope.addGroup(groupStart, groupCount, materialIndex); 12282 // calculate new start value for groups 12283 groupStart += groupCount; 12284 // update total number of vertices 12285 numberOfVertices += vertexCounter; 12286 } 12287 } 12288 } 12289 /** 12290 * Uniform Utilities 12291 */ function cloneUniforms(src) { 12292 const dst = {}; 12293 for(const u in src){ 12294 dst[u] = {}; 12295 for(const p in src[u]){ 12296 const property = src[u][p]; 12297 if (property && (property.isColor || property.isMatrix3 || property.isMatrix4 || property.isVector2 || property.isVector3 || property.isVector4 || property.isTexture || property.isQuaternion)) { 12298 if (property.isRenderTargetTexture) { 12299 console.warn('UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().'); 12300 dst[u][p] = null; 12301 } else { 12302 dst[u][p] = property.clone(); 12303 } 12304 } else if (Array.isArray(property)) { 12305 dst[u][p] = property.slice(); 12306 } else { 12307 dst[u][p] = property; 12308 } 12309 } 12310 } 12311 return dst; 12312 } 12313 function mergeUniforms(uniforms) { 12314 const merged = {}; 12315 for(let u = 0; u < uniforms.length; u++){ 12316 const tmp = cloneUniforms(uniforms[u]); 12317 for(const p in tmp){ 12318 merged[p] = tmp[p]; 12319 } 12320 } 12321 return merged; 12322 } 12323 function cloneUniformsGroups(src) { 12324 const dst = []; 12325 for(let u = 0; u < src.length; u++){ 12326 dst.push(src[u].clone()); 12327 } 12328 return dst; 12329 } 12330 function getUnlitUniformColorSpace(renderer) { 12331 const currentRenderTarget = renderer.getRenderTarget(); 12332 if (currentRenderTarget === null) { 12333 // https://github.com/mrdoob/three.js/pull/23937#issuecomment-1111067398 12334 return renderer.outputColorSpace; 12335 } 12336 // https://github.com/mrdoob/three.js/issues/27868 12337 if (currentRenderTarget.isXRRenderTarget === true) { 12338 return currentRenderTarget.texture.colorSpace; 12339 } 12340 return ColorManagement.workingColorSpace; 12341 } 12342 // Legacy 12343 const UniformsUtils = { 12344 clone: cloneUniforms, 12345 merge: mergeUniforms 12346 }; 12347 var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}"; 12348 var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}"; 12349 class ShaderMaterial extends Material$1 { 12350 copy(source) { 12351 super.copy(source); 12352 this.fragmentShader = source.fragmentShader; 12353 this.vertexShader = source.vertexShader; 12354 this.uniforms = cloneUniforms(source.uniforms); 12355 this.uniformsGroups = cloneUniformsGroups(source.uniformsGroups); 12356 this.defines = Object.assign({}, source.defines); 12357 this.wireframe = source.wireframe; 12358 this.wireframeLinewidth = source.wireframeLinewidth; 12359 this.fog = source.fog; 12360 this.lights = source.lights; 12361 this.clipping = source.clipping; 12362 this.extensions = Object.assign({}, source.extensions); 12363 this.glslVersion = source.glslVersion; 12364 return this; 12365 } 12366 toJSON(meta) { 12367 const data = super.toJSON(meta); 12368 data.glslVersion = this.glslVersion; 12369 data.uniforms = {}; 12370 for(const name in this.uniforms){ 12371 const uniform = this.uniforms[name]; 12372 const value = uniform.value; 12373 if (value && value.isTexture) { 12374 data.uniforms[name] = { 12375 type: 't', 12376 value: value.toJSON(meta).uuid 12377 }; 12378 } else if (value && value.isColor) { 12379 data.uniforms[name] = { 12380 type: 'c', 12381 value: value.getHex() 12382 }; 12383 } else if (value && value.isVector2) { 12384 data.uniforms[name] = { 12385 type: 'v2', 12386 value: value.toArray() 12387 }; 12388 } else if (value && value.isVector3) { 12389 data.uniforms[name] = { 12390 type: 'v3', 12391 value: value.toArray() 12392 }; 12393 } else if (value && value.isVector4) { 12394 data.uniforms[name] = { 12395 type: 'v4', 12396 value: value.toArray() 12397 }; 12398 } else if (value && value.isMatrix3) { 12399 data.uniforms[name] = { 12400 type: 'm3', 12401 value: value.toArray() 12402 }; 12403 } else if (value && value.isMatrix4) { 12404 data.uniforms[name] = { 12405 type: 'm4', 12406 value: value.toArray() 12407 }; 12408 } else { 12409 data.uniforms[name] = { 12410 value: value 12411 }; 12412 // note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far 12413 } 12414 } 12415 if (Object.keys(this.defines).length > 0) data.defines = this.defines; 12416 data.vertexShader = this.vertexShader; 12417 data.fragmentShader = this.fragmentShader; 12418 data.lights = this.lights; 12419 data.clipping = this.clipping; 12420 const extensions = {}; 12421 for(const key in this.extensions){ 12422 if (this.extensions[key] === true) extensions[key] = true; 12423 } 12424 if (Object.keys(extensions).length > 0) data.extensions = extensions; 12425 return data; 12426 } 12427 constructor(parameters){ 12428 super(); 12429 this.isShaderMaterial = true; 12430 this.type = 'ShaderMaterial'; 12431 this.defines = {}; 12432 this.uniforms = {}; 12433 this.uniformsGroups = []; 12434 this.vertexShader = default_vertex; 12435 this.fragmentShader = default_fragment; 12436 this.linewidth = 1; 12437 this.wireframe = false; 12438 this.wireframeLinewidth = 1; 12439 this.fog = false; // set to use scene fog 12440 this.lights = false; // set to use scene lights 12441 this.clipping = false; // set to use user-defined clipping planes 12442 this.forceSinglePass = true; 12443 this.extensions = { 12444 clipCullDistance: false, 12445 multiDraw: false // set to use vertex shader multi_draw / enable gl_DrawID 12446 }; 12447 // When rendered geometry doesn't include these attributes but the material does, 12448 // use these default values in WebGL. This avoids errors when buffer data is missing. 12449 this.defaultAttributeValues = { 12450 'color': [ 12451 1, 12452 1, 12453 1 12454 ], 12455 'uv': [ 12456 0, 12457 0 12458 ], 12459 'uv1': [ 12460 0, 12461 0 12462 ] 12463 }; 12464 this.index0AttributeName = undefined; 12465 this.uniformsNeedUpdate = false; 12466 this.glslVersion = null; 12467 if (parameters !== undefined) { 12468 this.setValues(parameters); 12469 } 12470 } 12471 } 12472 /** 12473 * Abstract base class for cameras. This class should always be inherited 12474 * when you build a new camera. 12475 * 12476 * @abstract 12477 * @augments Object3D 12478 */ class Camera extends Object3D { 12479 copy(source, recursive) { 12480 super.copy(source, recursive); 12481 this.matrixWorldInverse.copy(source.matrixWorldInverse); 12482 this.projectionMatrix.copy(source.projectionMatrix); 12483 this.projectionMatrixInverse.copy(source.projectionMatrixInverse); 12484 this.coordinateSystem = source.coordinateSystem; 12485 return this; 12486 } 12487 /** 12488 * Returns a vector representing the ("look") direction of the 3D object in world space. 12489 * 12490 * This method is overwritten since cameras have a different forward vector compared to other 12491 * 3D objects. A camera looks down its local, negative z-axis by default. 12492 * 12493 * @param {Vector3} target - The target vector the result is stored to. 12494 * @return {Vector3} The 3D object's direction in world space. 12495 */ getWorldDirection(target) { 12496 return super.getWorldDirection(target).negate(); 12497 } 12498 updateMatrixWorld(force) { 12499 super.updateMatrixWorld(force); 12500 this.matrixWorldInverse.copy(this.matrixWorld).invert(); 12501 } 12502 updateWorldMatrix(updateParents, updateChildren) { 12503 super.updateWorldMatrix(updateParents, updateChildren); 12504 this.matrixWorldInverse.copy(this.matrixWorld).invert(); 12505 } 12506 clone() { 12507 return new this.constructor().copy(this); 12508 } 12509 /** 12510 * Constructs a new camera. 12511 */ constructor(){ 12512 super(); 12513 /** 12514 * This flag can be used for type testing. 12515 * 12516 * @type {boolean} 12517 * @readonly 12518 * @default true 12519 */ this.isCamera = true; 12520 this.type = 'Camera'; 12521 /** 12522 * The inverse of the camera's world matrix. 12523 * 12524 * @type {Matrix4} 12525 */ this.matrixWorldInverse = new Matrix4(); 12526 /** 12527 * The camera's projection matrix. 12528 * 12529 * @type {Matrix4} 12530 */ this.projectionMatrix = new Matrix4(); 12531 /** 12532 * The inverse of the camera's projection matrix. 12533 * 12534 * @type {Matrix4} 12535 */ this.projectionMatrixInverse = new Matrix4(); 12536 /** 12537 * The coordinate system in which the camera is used. 12538 * 12539 * @type {(WebGLCoordinateSystem|WebGPUCoordinateSystem)} 12540 */ this.coordinateSystem = WebGLCoordinateSystem; 12541 } 12542 } 12543 const _v3$1 = /*@__PURE__*/ new Vector3(); 12544 const _minTarget = /*@__PURE__*/ new Vector2(); 12545 const _maxTarget = /*@__PURE__*/ new Vector2(); 12546 /** 12547 * Camera that uses [perspective projection]{@link https://en.wikipedia.org/wiki/Perspective_(graphical)}. 12548 * 12549 * This projection mode is designed to mimic the way the human eye sees. It 12550 * is the most common projection mode used for rendering a 3D scene. 12551 * 12552 * ```js 12553 * const camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 ); 12554 * scene.add( camera ); 12555 * ``` 12556 * 12557 * @augments Camera 12558 */ class PerspectiveCamera extends Camera { 12559 copy(source, recursive) { 12560 super.copy(source, recursive); 12561 this.fov = source.fov; 12562 this.zoom = source.zoom; 12563 this.near = source.near; 12564 this.far = source.far;
vendor: 6,152 bytes, lines 12565-12709
12565 this.focus = source.focus; 12566 this.aspect = source.aspect; 12567 this.view = source.view === null ? null : Object.assign({}, source.view); 12568 this.filmGauge = source.filmGauge; 12569 this.filmOffset = source.filmOffset; 12570 return this; 12571 } 12572 /** 12573 * Sets the FOV by focal length in respect to the current {@link PerspectiveCamera#filmGauge}. 12574 * 12575 * The default film gauge is 35, so that the focal length can be specified for 12576 * a 35mm (full frame) camera. 12577 * 12578 * @param {number} focalLength - Values for focal length and film gauge must have the same unit. 12579 */ setFocalLength(focalLength) { 12580 /** see {@link http://www.bobatkins.com/photography/technical/field_of_view.html} */ const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength; 12581 this.fov = RAD2DEG * 2 * Math.atan(vExtentSlope); 12582 this.updateProjectionMatrix(); 12583 } 12584 /** 12585 * Returns the focal length from the current {@link PerspectiveCamera#fov} and 12586 * {@link PerspectiveCamera#filmGauge}. 12587 * 12588 * @return {number} The computed focal length. 12589 */ getFocalLength() { 12590 const vExtentSlope = Math.tan(DEG2RAD * 0.5 * this.fov); 12591 return 0.5 * this.getFilmHeight() / vExtentSlope; 12592 } 12593 /** 12594 * Returns the current vertical field of view angle in degrees considering {@link PerspectiveCamera#zoom}. 12595 * 12596 * @return {number} The effective FOV. 12597 */ getEffectiveFOV() { 12598 return RAD2DEG * 2 * Math.atan(Math.tan(DEG2RAD * 0.5 * this.fov) / this.zoom); 12599 } 12600 /** 12601 * Returns the width of the image on the film. If {@link PerspectiveCamera#aspect} is greater than or 12602 * equal to one (landscape format), the result equals {@link PerspectiveCamera#filmGauge}. 12603 * 12604 * @return {number} The film width. 12605 */ getFilmWidth() { 12606 // film not completely covered in portrait format (aspect < 1) 12607 return this.filmGauge * Math.min(this.aspect, 1); 12608 } 12609 /** 12610 * Returns the height of the image on the film. If {@link PerspectiveCamera#aspect} is greater than or 12611 * equal to one (landscape format), the result equals {@link PerspectiveCamera#filmGauge}. 12612 * 12613 * @return {number} The film width. 12614 */ getFilmHeight() { 12615 // film not completely covered in landscape format (aspect > 1) 12616 return this.filmGauge / Math.max(this.aspect, 1); 12617 } 12618 /** 12619 * Computes the 2D bounds of the camera's viewable rectangle at a given distance along the viewing direction. 12620 * Sets `minTarget` and `maxTarget` to the coordinates of the lower-left and upper-right corners of the view rectangle. 12621 * 12622 * @param {number} distance - The viewing distance. 12623 * @param {Vector2} minTarget - The lower-left corner of the view rectangle is written into this vector. 12624 * @param {Vector2} maxTarget - The upper-right corner of the view rectangle is written into this vector. 12625 */ getViewBounds(distance, minTarget, maxTarget) { 12626 _v3$1.set(-1, -1, 0.5).applyMatrix4(this.projectionMatrixInverse); 12627 minTarget.set(_v3$1.x, _v3$1.y).multiplyScalar(-distance / _v3$1.z); 12628 _v3$1.set(1, 1, 0.5).applyMatrix4(this.projectionMatrixInverse); 12629 maxTarget.set(_v3$1.x, _v3$1.y).multiplyScalar(-distance / _v3$1.z); 12630 } 12631 /** 12632 * Computes the width and height of the camera's viewable rectangle at a given distance along the viewing direction. 12633 * 12634 * @param {number} distance - The viewing distance. 12635 * @param {Vector2} target - The target vector that is used to store result where x is width and y is height. 12636 * @returns {Vector2} The view size. 12637 */ getViewSize(distance, target) { 12638 this.getViewBounds(distance, _minTarget, _maxTarget); 12639 return target.subVectors(_maxTarget, _minTarget); 12640 } 12641 /** 12642 * Sets an offset in a larger frustum. This is useful for multi-window or 12643 * multi-monitor/multi-machine setups. 12644 * 12645 * For example, if you have 3x2 monitors and each monitor is 1920x1080 and 12646 * the monitors are in grid like this 12647 *``` 12648 * +---+---+---+ 12649 * | A | B | C | 12650 * +---+---+---+ 12651 * | D | E | F | 12652 * +---+---+---+ 12653 *``` 12654 * then for each monitor you would call it like this: 12655 *```js 12656 * const w = 1920; 12657 * const h = 1080; 12658 * const fullWidth = w * 3; 12659 * const fullHeight = h * 2; 12660 * 12661 * // --A-- 12662 * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); 12663 * // --B-- 12664 * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); 12665 * // --C-- 12666 * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); 12667 * // --D-- 12668 * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); 12669 * // --E-- 12670 * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); 12671 * // --F-- 12672 * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); 12673 * ``` 12674 * 12675 * Note there is no reason monitors have to be the same size or in a grid. 12676 * 12677 * @param {number} fullWidth - The full width of multiview setup. 12678 * @param {number} fullHeight - The full height of multiview setup. 12679 * @param {number} x - The horizontal offset of the subcamera. 12680 * @param {number} y - The vertical offset of the subcamera. 12681 * @param {number} width - The width of subcamera. 12682 * @param {number} height - The height of subcamera. 12683 */ setViewOffset(fullWidth, fullHeight, x, y, width, height) { 12684 this.aspect = fullWidth / fullHeight; 12685 if (this.view === null) { 12686 this.view = { 12687 enabled: true, 12688 fullWidth: 1, 12689 fullHeight: 1, 12690 offsetX: 0, 12691 offsetY: 0, 12692 width: 1, 12693 height: 1 12694 }; 12695 } 12696 this.view.enabled = true; 12697 this.view.fullWidth = fullWidth; 12698 this.view.fullHeight = fullHeight; 12699 this.view.offsetX = x; 12700 this.view.offsetY = y; 12701 this.view.width = width; 12702 this.view.height = height; 12703 this.updateProjectionMatrix(); 12704 } 12705 /** 12706 * Removes the view offset from the projection matrix. 12707 */ clearViewOffset() { 12708 if (this.view !== null) { 12709 this.view.enabled = false;
vendor: 4,613 bytes, lines 12710-12841
12710 } 12711 this.updateProjectionMatrix(); 12712 } 12713 /** 12714 * Updates the camera's projection matrix. Must be called after any change of 12715 * camera properties. 12716 */ updateProjectionMatrix() { 12717 const near = this.near; 12718 let top = near * Math.tan(DEG2RAD * 0.5 * this.fov) / this.zoom; 12719 let height = 2 * top; 12720 let width = this.aspect * height; 12721 let left = -0.5 * width; 12722 const view = this.view; 12723 if (this.view !== null && this.view.enabled) { 12724 const fullWidth = view.fullWidth, fullHeight = view.fullHeight; 12725 left += view.offsetX * width / fullWidth; 12726 top -= view.offsetY * height / fullHeight; 12727 width *= view.width / fullWidth; 12728 height *= view.height / fullHeight; 12729 } 12730 const skew = this.filmOffset; 12731 if (skew !== 0) left += near * skew / this.getFilmWidth(); 12732 this.projectionMatrix.makePerspective(left, left + width, top, top - height, near, this.far, this.coordinateSystem); 12733 this.projectionMatrixInverse.copy(this.projectionMatrix).invert(); 12734 } 12735 toJSON(meta) { 12736 const data = super.toJSON(meta); 12737 data.object.fov = this.fov; 12738 data.object.zoom = this.zoom; 12739 data.object.near = this.near; 12740 data.object.far = this.far; 12741 data.object.focus = this.focus; 12742 data.object.aspect = this.aspect; 12743 if (this.view !== null) data.object.view = Object.assign({}, this.view); 12744 data.object.filmGauge = this.filmGauge; 12745 data.object.filmOffset = this.filmOffset; 12746 return data; 12747 } 12748 /** 12749 * Constructs a new perspective camera. 12750 * 12751 * @param {number} [fov=50] - The vertical field of view. 12752 * @param {number} [aspect=1] - The aspect ratio. 12753 * @param {number} [near=0.1] - The camera's near plane. 12754 * @param {number} [far=2000] - The camera's far plane. 12755 */ constructor(fov = 50, aspect = 1, near = 0.1, far = 2000){ 12756 super(); 12757 /** 12758 * This flag can be used for type testing. 12759 * 12760 * @type {boolean} 12761 * @readonly 12762 * @default true 12763 */ this.isPerspectiveCamera = true; 12764 this.type = 'PerspectiveCamera'; 12765 /** 12766 * The vertical field of view, from bottom to top of view, 12767 * in degrees. 12768 * 12769 * @type {number} 12770 * @default 50 12771 */ this.fov = fov; 12772 /** 12773 * The zoom factor of the camera. 12774 * 12775 * @type {number} 12776 * @default 1 12777 */ this.zoom = 1; 12778 /** 12779 * The camera's near plane. The valid range is greater than `0` 12780 * and less than the current value of {@link PerspectiveCamera#far}. 12781 * 12782 * Note that, unlike for the {@link OrthographicCamera}, `0` is <em>not</em> a 12783 * valid value for a perspective camera's near plane. 12784 * 12785 * @type {number} 12786 * @default 0.1 12787 */ this.near = near; 12788 /** 12789 * The camera's far plane. Must be greater than the 12790 * current value of {@link PerspectiveCamera#near}. 12791 * 12792 * @type {number} 12793 * @default 2000 12794 */ this.far = far; 12795 /** 12796 * Object distance used for stereoscopy and depth-of-field effects. This 12797 * parameter does not influence the projection matrix unless a 12798 * {@link StereoCamera} is being used. 12799 * 12800 * @type {number} 12801 * @default 10 12802 */ this.focus = 10; 12803 /** 12804 * The aspect ratio, usually the canvas width / canvas height. 12805 * 12806 * @type {number} 12807 * @default 1 12808 */ this.aspect = aspect; 12809 /** 12810 * Represents the frustum window specification. This property should not be edited 12811 * directly but via {@link PerspectiveCamera#setViewOffset} and {@link PerspectiveCamera#clearViewOffset}. 12812 * 12813 * @type {?Object} 12814 * @default null 12815 */ this.view = null; 12816 /** 12817 * Film size used for the larger axis. Default is `35` (millimeters). This 12818 * parameter does not influence the projection matrix unless {@link PerspectiveCamera#filmOffset} 12819 * is set to a nonzero value. 12820 * 12821 * @type {number} 12822 * @default 35 12823 */ this.filmGauge = 35; 12824 /** 12825 * Horizontal off-center offset in the same unit as {@link PerspectiveCamera#filmGauge}. 12826 * 12827 * @type {number} 12828 * @default 0 12829 */ this.filmOffset = 0; 12830 this.updateProjectionMatrix(); 12831 } 12832 } 12833 const fov = -90; // negative fov is not an error 12834 const aspect = 1; 12835 /** 12836 * A special type of camera that is positioned in 3D space to render its surroundings into a 12837 * cube render target. The render target can then be used as an environment map for rendering 12838 * realtime reflections in your scene. 12839 * 12840 * ```js 12841 * // Create cube render target
12842 * const cubeRenderTarget = new THREE.WebGLCubeRenderTarget( 256, { generateMipmaps: true, minFilter: THREE.LinearMipmapLinearFilter } ); 12843 * 12844 * // Create cube camera 12845 * const cubeCamera = new THREE.CubeCamera( 1, 100000, cubeRenderTarget ); 12846 * scene.add( cubeCamera ); 12847 * 12848 * // Create car 12849 * const chromeMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff, envMap: cubeRenderTarget.texture } ); 12850 * const car = new THREE.Mesh( carGeometry, chromeMaterial ); 12851 * scene.add( car ); 12852 * 12853 * // Update the render target cube 12854 * car.visible = false; 12855 * cubeCamera.position.copy( car.position ); 12856 * cubeCamera.update( renderer, scene ); 12857 * 12858 * // Render the scene 12859 * car.visible = true; 12860 * renderer.render( scene, camera ); 12861 * ``` 12862 * 12863 * @augments Object3D 12864 */ class CubeCamera extends Object3D { 12865 /** 12866 * Must be called when the coordinate system of the cube camera is changed. 12867 */ updateCoordinateSystem() { 12868 const coordinateSystem = this.coordinateSystem; 12869 const cameras = this.children.concat(); 12870 const [cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ] = cameras; 12871 for (const camera of cameras)this.remove(camera); 12872 if (coordinateSystem === WebGLCoordinateSystem) { 12873 cameraPX.up.set(0, 1, 0); 12874 cameraPX.lookAt(1, 0, 0); 12875 cameraNX.up.set(0, 1, 0); 12876 cameraNX.lookAt(-1, 0, 0); 12877 cameraPY.up.set(0, 0, -1); 12878 cameraPY.lookAt(0, 1, 0); 12879 cameraNY.up.set(0, 0, 1); 12880 cameraNY.lookAt(0, -1, 0); 12881 cameraPZ.up.set(0, 1, 0); 12882 cameraPZ.lookAt(0, 0, 1); 12883 cameraNZ.up.set(0, 1, 0); 12884 cameraNZ.lookAt(0, 0, -1); 12885 } else if (coordinateSystem === WebGPUCoordinateSystem) { 12886 cameraPX.up.set(0, -1, 0); 12887 cameraPX.lookAt(-1, 0, 0); 12888 cameraNX.up.set(0, -1, 0); 12889 cameraNX.lookAt(1, 0, 0); 12890 cameraPY.up.set(0, 0, 1); 12891 cameraPY.lookAt(0, 1, 0); 12892 cameraNY.up.set(0, 0, -1); 12893 cameraNY.lookAt(0, -1, 0); 12894 cameraPZ.up.set(0, -1, 0); 12895 cameraPZ.lookAt(0, 0, 1); 12896 cameraNZ.up.set(0, -1, 0); 12897 cameraNZ.lookAt(0, 0, -1); 12898 } else { 12899 throw new Error('THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: ' + coordinateSystem); 12900 } 12901 for (const camera of cameras){ 12902 this.add(camera); 12903 camera.updateMatrixWorld(); 12904 } 12905 } 12906 /** 12907 * Calling this method will render the given scene with the given renderer 12908 * into the cube render target of the camera. 12909 * 12910 * @param {(Renderer|WebGLRenderer)} renderer - The renderer. 12911 * @param {Scene} scene - The scene to render. 12912 */ update(renderer, scene) { 12913 if (this.parent === null) this.updateMatrixWorld(); 12914 const { renderTarget, activeMipmapLevel } = this; 12915 if (this.coordinateSystem !== renderer.coordinateSystem) { 12916 this.coordinateSystem = renderer.coordinateSystem; 12917 this.updateCoordinateSystem(); 12918 } 12919 const [cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ] = this.children; 12920 const currentRenderTarget = renderer.getRenderTarget(); 12921 const currentActiveCubeFace = renderer.getActiveCubeFace(); 12922 const currentActiveMipmapLevel = renderer.getActiveMipmapLevel(); 12923 const currentXrEnabled = renderer.xr.enabled; 12924 renderer.xr.enabled = false; 12925 const generateMipmaps = renderTarget.texture.generateMipmaps; 12926 renderTarget.texture.generateMipmaps = false; 12927 renderer.setRenderTarget(renderTarget, 0, activeMipmapLevel); 12928 renderer.render(scene, cameraPX); 12929 renderer.setRenderTarget(renderTarget, 1, activeMipmapLevel); 12930 renderer.render(scene, cameraNX); 12931 renderer.setRenderTarget(renderTarget, 2, activeMipmapLevel); 12932 renderer.render(scene, cameraPY); 12933 renderer.setRenderTarget(renderTarget, 3, activeMipmapLevel); 12934 renderer.render(scene, cameraNY); 12935 renderer.setRenderTarget(renderTarget, 4, activeMipmapLevel); 12936 renderer.render(scene, cameraPZ); 12937 // mipmaps are generated during the last call of render() 12938 // at this point, all sides of the cube render target are defined 12939 renderTarget.texture.generateMipmaps = generateMipmaps; 12940 renderer.setRenderTarget(renderTarget, 5, activeMipmapLevel); 12941 renderer.render(scene, cameraNZ); 12942 renderer.setRenderTarget(currentRenderTarget, currentActiveCubeFace, currentActiveMipmapLevel); 12943 renderer.xr.enabled = currentXrEnabled; 12944 renderTarget.texture.needsPMREMUpdate = true; 12945 } 12946 /** 12947 * Constructs a new cube camera. 12948 * 12949 * @param {number} near - The camera's near plane. 12950 * @param {number} far - The camera's far plane.
vendor: 4,586 bytes, lines 12951-13088
12951 * @param {WebGLCubeRenderTarget} renderTarget - The cube render target. 12952 */ constructor(near, far, renderTarget){ 12953 super(); 12954 this.type = 'CubeCamera'; 12955 /** 12956 * A reference to the cube render target. 12957 * 12958 * @type {WebGLCubeRenderTarget} 12959 */ this.renderTarget = renderTarget; 12960 /** 12961 * The current active coordinate system. 12962 * 12963 * @type {?(WebGLCoordinateSystem|WebGPUCoordinateSystem)} 12964 * @default null 12965 */ this.coordinateSystem = null; 12966 /** 12967 * The current active mipmap level 12968 * 12969 * @type {number} 12970 * @default 0 12971 */ this.activeMipmapLevel = 0; 12972 const cameraPX = new PerspectiveCamera(fov, aspect, near, far); 12973 cameraPX.layers = this.layers; 12974 this.add(cameraPX); 12975 const cameraNX = new PerspectiveCamera(fov, aspect, near, far); 12976 cameraNX.layers = this.layers; 12977 this.add(cameraNX); 12978 const cameraPY = new PerspectiveCamera(fov, aspect, near, far); 12979 cameraPY.layers = this.layers; 12980 this.add(cameraPY); 12981 const cameraNY = new PerspectiveCamera(fov, aspect, near, far); 12982 cameraNY.layers = this.layers; 12983 this.add(cameraNY); 12984 const cameraPZ = new PerspectiveCamera(fov, aspect, near, far); 12985 cameraPZ.layers = this.layers; 12986 this.add(cameraPZ); 12987 const cameraNZ = new PerspectiveCamera(fov, aspect, near, far); 12988 cameraNZ.layers = this.layers; 12989 this.add(cameraNZ); 12990 } 12991 } 12992 class CubeTexture extends Texture$1 { 12993 get images() { 12994 return this.image; 12995 } 12996 set images(value) { 12997 this.image = value; 12998 } 12999 constructor(images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace){ 13000 images = images !== undefined ? images : []; 13001 mapping = mapping !== undefined ? mapping : CubeReflectionMapping; 13002 super(images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace); 13003 this.isCubeTexture = true; 13004 this.flipY = false; 13005 } 13006 } 13007 class WebGLCubeRenderTarget extends WebGLRenderTarget { 13008 fromEquirectangularTexture(renderer, texture) { 13009 this.texture.type = texture.type; 13010 this.texture.colorSpace = texture.colorSpace; 13011 this.texture.generateMipmaps = texture.generateMipmaps; 13012 this.texture.minFilter = texture.minFilter; 13013 this.texture.magFilter = texture.magFilter; 13014 const shader = { 13015 uniforms: { 13016 tEquirect: { 13017 value: null 13018 } 13019 }, 13020 vertexShader: /* glsl */ ` 13021 13022 varying vec3 vWorldDirection; 13023 13024 vec3 transformDirection( in vec3 dir, in mat4 matrix ) { 13025 13026 return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); 13027 13028 } 13029 13030 void main() { 13031 13032 vWorldDirection = transformDirection( position, modelMatrix ); 13033 13034 #include <begin_vertex> 13035 #include <project_vertex> 13036 13037 } 13038 `, 13039 fragmentShader: /* glsl */ ` 13040 13041 uniform sampler2D tEquirect; 13042 13043 varying vec3 vWorldDirection; 13044 13045 #include <common> 13046 13047 void main() { 13048 13049 vec3 direction = normalize( vWorldDirection ); 13050 13051 vec2 sampleUV = equirectUv( direction ); 13052 13053 gl_FragColor = texture2D( tEquirect, sampleUV ); 13054 13055 } 13056 ` 13057 }; 13058 const geometry = new BoxGeometry(5, 5, 5); 13059 const material = new ShaderMaterial({ 13060 name: 'CubemapFromEquirect', 13061 uniforms: cloneUniforms(shader.uniforms), 13062 vertexShader: shader.vertexShader, 13063 fragmentShader: shader.fragmentShader, 13064 side: BackSide, 13065 blending: NoBlending 13066 }); 13067 material.uniforms.tEquirect.value = texture; 13068 const mesh = new Mesh(geometry, material); 13069 const currentMinFilter = texture.minFilter; 13070 // Avoid blurred poles 13071 if (texture.minFilter === LinearMipmapLinearFilter) texture.minFilter = LinearFilter; 13072 const camera = new CubeCamera(1, 10, this); 13073 camera.update(renderer, mesh); 13074 texture.minFilter = currentMinFilter; 13075 mesh.geometry.dispose(); 13076 mesh.material.dispose(); 13077 return this; 13078 } 13079 clear(renderer, color, depth, stencil) { 13080 const currentRenderTarget = renderer.getRenderTarget(); 13081 for(let i = 0; i < 6; i++){ 13082 renderer.setRenderTarget(this, i); 13083 renderer.clear(color, depth, stencil); 13084 } 13085 renderer.setRenderTarget(currentRenderTarget); 13086 } 13087 constructor(size = 1, options = {}){ 13088 super(size, size, options);
vendor: 4,708 bytes, lines 13089-13218
13089 this.isWebGLCubeRenderTarget = true; 13090 const image = { 13091 width: size, 13092 height: size, 13093 depth: 1 13094 }; 13095 const images = [ 13096 image, 13097 image, 13098 image, 13099 image, 13100 image, 13101 image 13102 ]; 13103 this.texture = new CubeTexture(images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace); 13104 // By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js) 13105 // in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words, 13106 // in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly. 13107 // three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped 13108 // and the flag isRenderTargetTexture controls this conversion. The flip is not required when using WebGLCubeRenderTarget.texture 13109 // as a cube texture (this is detected when isRenderTargetTexture is set to true for cube textures). 13110 this.texture.isRenderTargetTexture = true; 13111 this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; 13112 this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter; 13113 } 13114 } 13115 /** 13116 * This is almost identical to an {@link Object3D}. Its purpose is to 13117 * make working with groups of objects syntactically clearer. 13118 * 13119 * ```js 13120 * // Create a group and add the two cubes. 13121 * // These cubes can now be rotated / scaled etc as a group. 13122 * const group = new THREE.Group(); 13123 * 13124 * group.add( meshA ); 13125 * group.add( meshB ); 13126 * 13127 * scene.add( group ); 13128 * ``` 13129 * 13130 * @augments Object3D 13131 */ class Group extends Object3D { 13132 constructor(){ 13133 super(); 13134 /** 13135 * This flag can be used for type testing. 13136 * 13137 * @type {boolean} 13138 * @readonly 13139 * @default true 13140 */ this.isGroup = true; 13141 this.type = 'Group'; 13142 } 13143 } 13144 const _moveEvent = { 13145 type: 'move' 13146 }; 13147 class WebXRController { 13148 getHandSpace() { 13149 if (this._hand === null) { 13150 this._hand = new Group(); 13151 this._hand.matrixAutoUpdate = false; 13152 this._hand.visible = false; 13153 this._hand.joints = {}; 13154 this._hand.inputState = { 13155 pinching: false 13156 }; 13157 } 13158 return this._hand; 13159 } 13160 getTargetRaySpace() { 13161 if (this._targetRay === null) { 13162 this._targetRay = new Group(); 13163 this._targetRay.matrixAutoUpdate = false; 13164 this._targetRay.visible = false; 13165 this._targetRay.hasLinearVelocity = false; 13166 this._targetRay.linearVelocity = new Vector3(); 13167 this._targetRay.hasAngularVelocity = false; 13168 this._targetRay.angularVelocity = new Vector3(); 13169 } 13170 return this._targetRay; 13171 } 13172 getGripSpace() { 13173 if (this._grip === null) { 13174 this._grip = new Group(); 13175 this._grip.matrixAutoUpdate = false; 13176 this._grip.visible = false; 13177 this._grip.hasLinearVelocity = false; 13178 this._grip.linearVelocity = new Vector3(); 13179 this._grip.hasAngularVelocity = false; 13180 this._grip.angularVelocity = new Vector3(); 13181 } 13182 return this._grip; 13183 } 13184 dispatchEvent(event) { 13185 if (this._targetRay !== null) { 13186 this._targetRay.dispatchEvent(event); 13187 } 13188 if (this._grip !== null) { 13189 this._grip.dispatchEvent(event); 13190 } 13191 if (this._hand !== null) { 13192 this._hand.dispatchEvent(event); 13193 } 13194 return this; 13195 } 13196 connect(inputSource) { 13197 if (inputSource && inputSource.hand) { 13198 const hand = this._hand; 13199 if (hand) { 13200 for (const inputjoint of inputSource.hand.values()){ 13201 // Initialize hand with joints when connected 13202 this._getHandJoint(hand, inputjoint); 13203 } 13204 } 13205 } 13206 this.dispatchEvent({ 13207 type: 'connected', 13208 data: inputSource 13209 }); 13210 return this; 13211 } 13212 disconnect(inputSource) { 13213 this.dispatchEvent({ 13214 type: 'disconnected', 13215 data: inputSource 13216 }); 13217 if (this._targetRay !== null) { 13218 this._targetRay.visible = false;
vendor: 60,135 bytes, lines 13219-14738
13219 } 13220 if (this._grip !== null) { 13221 this._grip.visible = false; 13222 } 13223 if (this._hand !== null) { 13224 this._hand.visible = false; 13225 } 13226 return this; 13227 } 13228 update(inputSource, frame, referenceSpace) { 13229 let inputPose = null; 13230 let gripPose = null; 13231 let handPose = null; 13232 const targetRay = this._targetRay; 13233 const grip = this._grip; 13234 const hand = this._hand; 13235 if (inputSource && frame.session.visibilityState !== 'visible-blurred') { 13236 if (hand && inputSource.hand) { 13237 handPose = true; 13238 for (const inputjoint of inputSource.hand.values()){ 13239 // Update the joints groups with the XRJoint poses 13240 const jointPose = frame.getJointPose(inputjoint, referenceSpace); 13241 // The transform of this joint will be updated with the joint pose on each frame 13242 const joint = this._getHandJoint(hand, inputjoint); 13243 if (jointPose !== null) { 13244 joint.matrix.fromArray(jointPose.transform.matrix); 13245 joint.matrix.decompose(joint.position, joint.rotation, joint.scale); 13246 joint.matrixWorldNeedsUpdate = true; 13247 joint.jointRadius = jointPose.radius; 13248 } 13249 joint.visible = jointPose !== null; 13250 } 13251 // Custom events 13252 // Check pinchz 13253 const indexTip = hand.joints['index-finger-tip']; 13254 const thumbTip = hand.joints['thumb-tip']; 13255 const distance = indexTip.position.distanceTo(thumbTip.position); 13256 const distanceToPinch = 0.02; 13257 const threshold = 0.005; 13258 if (hand.inputState.pinching && distance > distanceToPinch + threshold) { 13259 hand.inputState.pinching = false; 13260 this.dispatchEvent({ 13261 type: 'pinchend', 13262 handedness: inputSource.handedness, 13263 target: this 13264 }); 13265 } else if (!hand.inputState.pinching && distance <= distanceToPinch - threshold) { 13266 hand.inputState.pinching = true; 13267 this.dispatchEvent({ 13268 type: 'pinchstart', 13269 handedness: inputSource.handedness, 13270 target: this 13271 }); 13272 } 13273 } else { 13274 if (grip !== null && inputSource.gripSpace) { 13275 gripPose = frame.getPose(inputSource.gripSpace, referenceSpace); 13276 if (gripPose !== null) { 13277 grip.matrix.fromArray(gripPose.transform.matrix); 13278 grip.matrix.decompose(grip.position, grip.rotation, grip.scale); 13279 grip.matrixWorldNeedsUpdate = true; 13280 if (gripPose.linearVelocity) { 13281 grip.hasLinearVelocity = true; 13282 grip.linearVelocity.copy(gripPose.linearVelocity); 13283 } else { 13284 grip.hasLinearVelocity = false; 13285 } 13286 if (gripPose.angularVelocity) { 13287 grip.hasAngularVelocity = true; 13288 grip.angularVelocity.copy(gripPose.angularVelocity); 13289 } else { 13290 grip.hasAngularVelocity = false; 13291 } 13292 } 13293 } 13294 } 13295 if (targetRay !== null) { 13296 inputPose = frame.getPose(inputSource.targetRaySpace, referenceSpace); 13297 // Some runtimes (namely Vive Cosmos with Vive OpenXR Runtime) have only grip space and ray space is equal to it 13298 if (inputPose === null && gripPose !== null) { 13299 inputPose = gripPose; 13300 } 13301 if (inputPose !== null) { 13302 targetRay.matrix.fromArray(inputPose.transform.matrix); 13303 targetRay.matrix.decompose(targetRay.position, targetRay.rotation, targetRay.scale); 13304 targetRay.matrixWorldNeedsUpdate = true; 13305 if (inputPose.linearVelocity) { 13306 targetRay.hasLinearVelocity = true; 13307 targetRay.linearVelocity.copy(inputPose.linearVelocity); 13308 } else { 13309 targetRay.hasLinearVelocity = false; 13310 } 13311 if (inputPose.angularVelocity) { 13312 targetRay.hasAngularVelocity = true; 13313 targetRay.angularVelocity.copy(inputPose.angularVelocity); 13314 } else { 13315 targetRay.hasAngularVelocity = false; 13316 } 13317 this.dispatchEvent(_moveEvent); 13318 } 13319 } 13320 } 13321 if (targetRay !== null) { 13322 targetRay.visible = inputPose !== null; 13323 } 13324 if (grip !== null) { 13325 grip.visible = gripPose !== null; 13326 } 13327 if (hand !== null) { 13328 hand.visible = handPose !== null; 13329 } 13330 return this; 13331 } 13332 // private method 13333 _getHandJoint(hand, inputjoint) { 13334 if (hand.joints[inputjoint.jointName] === undefined) { 13335 const joint = new Group(); 13336 joint.matrixAutoUpdate = false; 13337 joint.visible = false; 13338 hand.joints[inputjoint.jointName] = joint; 13339 hand.add(joint); 13340 } 13341 return hand.joints[inputjoint.jointName]; 13342 } 13343 constructor(){ 13344 this._targetRay = null; 13345 this._grip = null; 13346 this._hand = null; 13347 } 13348 } 13349 /** 13350 * Scenes allow you to set up what is to be rendered and where by three.js. 13351 * This is where you place 3D objects like meshes, lines or lights. 13352 * 13353 * @augments Object3D 13354 */ class Scene extends Object3D { 13355 copy(source, recursive) { 13356 super.copy(source, recursive); 13357 if (source.background !== null) this.background = source.background.clone(); 13358 if (source.environment !== null) this.environment = source.environment.clone(); 13359 if (source.fog !== null) this.fog = source.fog.clone(); 13360 this.backgroundBlurriness = source.backgroundBlurriness; 13361 this.backgroundIntensity = source.backgroundIntensity; 13362 this.backgroundRotation.copy(source.backgroundRotation); 13363 this.environmentIntensity = source.environmentIntensity; 13364 this.environmentRotation.copy(source.environmentRotation); 13365 if (source.overrideMaterial !== null) this.overrideMaterial = source.overrideMaterial.clone(); 13366 this.matrixAutoUpdate = source.matrixAutoUpdate; 13367 return this; 13368 } 13369 toJSON(meta) { 13370 const data = super.toJSON(meta); 13371 if (this.fog !== null) data.object.fog = this.fog.toJSON(); 13372 if (this.backgroundBlurriness > 0) data.object.backgroundBlurriness = this.backgroundBlurriness; 13373 if (this.backgroundIntensity !== 1) data.object.backgroundIntensity = this.backgroundIntensity; 13374 data.object.backgroundRotation = this.backgroundRotation.toArray(); 13375 if (this.environmentIntensity !== 1) data.object.environmentIntensity = this.environmentIntensity; 13376 data.object.environmentRotation = this.environmentRotation.toArray(); 13377 return data; 13378 } 13379 /** 13380 * Constructs a new scene. 13381 */ constructor(){ 13382 super(); 13383 /** 13384 * This flag can be used for type testing. 13385 * 13386 * @type {boolean} 13387 * @readonly 13388 * @default true 13389 */ this.isScene = true; 13390 this.type = 'Scene'; 13391 /** 13392 * Defines the background of the scene. Valid inputs are: 13393 * 13394 * - A color for defining a uniform colored background. 13395 * - A texture for defining a (flat) textured background. 13396 * - Cube textures or equirectangular textures for defining a skybox. 13397 * 13398 * @type {?(Color|Texture)} 13399 * @default null 13400 */ this.background = null; 13401 /** 13402 * Sets the environment map for all physical materials in the scene. However, 13403 * it's not possible to overwrite an existing texture assigned to the `envMap` 13404 * material property. 13405 * 13406 * @type {?Texture} 13407 * @default null 13408 */ this.environment = null; 13409 /** 13410 * A fog instance defining the type of fog that affects everything 13411 * rendered in the scene. 13412 * 13413 * @type {?(Fog|FogExp2)} 13414 * @default null 13415 */ this.fog = null; 13416 /** 13417 * Sets the blurriness of the background. Only influences environment maps 13418 * assigned to {@link Scene#background}. Valid input is a float between `0` 13419 * and `1`. 13420 * 13421 * @type {number} 13422 * @default 0 13423 */ this.backgroundBlurriness = 0; 13424 /** 13425 * Attenuates the color of the background. Only applies to background textures. 13426 * 13427 * @type {number} 13428 * @default 1 13429 */ this.backgroundIntensity = 1; 13430 /** 13431 * The rotation of the background in radians. Only influences environment maps 13432 * assigned to {@link Scene#background}. 13433 * 13434 * @type {Euler} 13435 * @default (0,0,0) 13436 */ this.backgroundRotation = new Euler(); 13437 /** 13438 * Attenuates the color of the environment. Only influences environment maps 13439 * assigned to {@link Scene#environment}. 13440 * 13441 * @type {number} 13442 * @default 1 13443 */ this.environmentIntensity = 1; 13444 /** 13445 * The rotation of the environment map in radians. Only influences physical materials 13446 * in the scene when {@link Scene#environment} is used. 13447 * 13448 * @type {Euler} 13449 * @default (0,0,0) 13450 */ this.environmentRotation = new Euler(); 13451 /** 13452 * Forces everything in the scene to be rendered with the defined material. 13453 * 13454 * @type {?Material} 13455 * @default null 13456 */ this.overrideMaterial = null; 13457 if (typeof __THREE_DEVTOOLS__ !== 'undefined') { 13458 __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent('observe', { 13459 detail: this 13460 })); 13461 } 13462 } 13463 } 13464 class InterleavedBuffer { 13465 onUploadCallback() {} 13466 set needsUpdate(value) { 13467 if (value === true) this.version++; 13468 } 13469 setUsage(value) { 13470 this.usage = value; 13471 return this; 13472 } 13473 addUpdateRange(start, count) { 13474 this.updateRanges.push({ 13475 start, 13476 count 13477 }); 13478 } 13479 clearUpdateRanges() { 13480 this.updateRanges.length = 0; 13481 } 13482 copy(source) { 13483 this.array = new source.array.constructor(source.array); 13484 this.count = source.count; 13485 this.stride = source.stride; 13486 this.usage = source.usage; 13487 return this; 13488 } 13489 copyAt(index1, attribute, index2) { 13490 index1 *= this.stride; 13491 index2 *= attribute.stride; 13492 for(let i = 0, l = this.stride; i < l; i++){ 13493 this.array[index1 + i] = attribute.array[index2 + i]; 13494 } 13495 return this; 13496 } 13497 set(value, offset = 0) { 13498 this.array.set(value, offset); 13499 return this; 13500 } 13501 clone(data) { 13502 if (data.arrayBuffers === undefined) { 13503 data.arrayBuffers = {}; 13504 } 13505 if (this.array.buffer._uuid === undefined) { 13506 this.array.buffer._uuid = generateUUID(); 13507 } 13508 if (data.arrayBuffers[this.array.buffer._uuid] === undefined) { 13509 data.arrayBuffers[this.array.buffer._uuid] = this.array.slice(0).buffer; 13510 } 13511 const array = new this.array.constructor(data.arrayBuffers[this.array.buffer._uuid]); 13512 const ib = new this.constructor(array, this.stride); 13513 ib.setUsage(this.usage); 13514 return ib; 13515 } 13516 onUpload(callback) { 13517 this.onUploadCallback = callback; 13518 return this; 13519 } 13520 toJSON(data) { 13521 if (data.arrayBuffers === undefined) { 13522 data.arrayBuffers = {}; 13523 } 13524 // generate UUID for array buffer if necessary 13525 if (this.array.buffer._uuid === undefined) { 13526 this.array.buffer._uuid = generateUUID(); 13527 } 13528 if (data.arrayBuffers[this.array.buffer._uuid] === undefined) { 13529 data.arrayBuffers[this.array.buffer._uuid] = Array.from(new Uint32Array(this.array.buffer)); 13530 } 13531 // 13532 return { 13533 uuid: this.uuid, 13534 buffer: this.array.buffer._uuid, 13535 type: this.array.constructor.name, 13536 stride: this.stride 13537 }; 13538 } 13539 constructor(array, stride){ 13540 this.isInterleavedBuffer = true; 13541 this.array = array; 13542 this.stride = stride; 13543 this.count = array !== undefined ? array.length / stride : 0; 13544 this.usage = StaticDrawUsage; 13545 this.updateRanges = []; 13546 this.version = 0; 13547 this.uuid = generateUUID(); 13548 } 13549 } 13550 const _vector$7 = /*@__PURE__*/ new Vector3(); 13551 class InterleavedBufferAttribute { 13552 get count() { 13553 return this.data.count; 13554 } 13555 get array() { 13556 return this.data.array; 13557 } 13558 set needsUpdate(value) { 13559 this.data.needsUpdate = value; 13560 } 13561 applyMatrix4(m) { 13562 for(let i = 0, l = this.data.count; i < l; i++){ 13563 _vector$7.fromBufferAttribute(this, i); 13564 _vector$7.applyMatrix4(m); 13565 this.setXYZ(i, _vector$7.x, _vector$7.y, _vector$7.z); 13566 } 13567 return this; 13568 } 13569 applyNormalMatrix(m) { 13570 for(let i = 0, l = this.count; i < l; i++){ 13571 _vector$7.fromBufferAttribute(this, i); 13572 _vector$7.applyNormalMatrix(m); 13573 this.setXYZ(i, _vector$7.x, _vector$7.y, _vector$7.z); 13574 } 13575 return this; 13576 } 13577 transformDirection(m) { 13578 for(let i = 0, l = this.count; i < l; i++){ 13579 _vector$7.fromBufferAttribute(this, i); 13580 _vector$7.transformDirection(m); 13581 this.setXYZ(i, _vector$7.x, _vector$7.y, _vector$7.z); 13582 } 13583 return this; 13584 } 13585 getComponent(index, component) { 13586 let value = this.array[index * this.data.stride + this.offset + component]; 13587 if (this.normalized) value = denormalize(value, this.array); 13588 return value; 13589 } 13590 setComponent(index, component, value) { 13591 if (this.normalized) value = normalize(value, this.array); 13592 this.data.array[index * this.data.stride + this.offset + component] = value; 13593 return this; 13594 } 13595 setX(index, x) { 13596 if (this.normalized) x = normalize(x, this.array); 13597 this.data.array[index * this.data.stride + this.offset] = x; 13598 return this; 13599 } 13600 setY(index, y) { 13601 if (this.normalized) y = normalize(y, this.array); 13602 this.data.array[index * this.data.stride + this.offset + 1] = y; 13603 return this; 13604 } 13605 setZ(index, z) { 13606 if (this.normalized) z = normalize(z, this.array); 13607 this.data.array[index * this.data.stride + this.offset + 2] = z; 13608 return this; 13609 } 13610 setW(index, w) { 13611 if (this.normalized) w = normalize(w, this.array); 13612 this.data.array[index * this.data.stride + this.offset + 3] = w; 13613 return this; 13614 } 13615 getX(index) { 13616 let x = this.data.array[index * this.data.stride + this.offset]; 13617 if (this.normalized) x = denormalize(x, this.array); 13618 return x; 13619 } 13620 getY(index) { 13621 let y = this.data.array[index * this.data.stride + this.offset + 1]; 13622 if (this.normalized) y = denormalize(y, this.array); 13623 return y; 13624 } 13625 getZ(index) { 13626 let z = this.data.array[index * this.data.stride + this.offset + 2]; 13627 if (this.normalized) z = denormalize(z, this.array); 13628 return z; 13629 } 13630 getW(index) { 13631 let w = this.data.array[index * this.data.stride + this.offset + 3]; 13632 if (this.normalized) w = denormalize(w, this.array); 13633 return w; 13634 } 13635 setXY(index, x, y) { 13636 index = index * this.data.stride + this.offset; 13637 if (this.normalized) { 13638 x = normalize(x, this.array); 13639 y = normalize(y, this.array); 13640 } 13641 this.data.array[index + 0] = x; 13642 this.data.array[index + 1] = y; 13643 return this; 13644 } 13645 setXYZ(index, x, y, z) { 13646 index = index * this.data.stride + this.offset; 13647 if (this.normalized) { 13648 x = normalize(x, this.array); 13649 y = normalize(y, this.array); 13650 z = normalize(z, this.array); 13651 } 13652 this.data.array[index + 0] = x; 13653 this.data.array[index + 1] = y; 13654 this.data.array[index + 2] = z; 13655 return this; 13656 } 13657 setXYZW(index, x, y, z, w) { 13658 index = index * this.data.stride + this.offset; 13659 if (this.normalized) { 13660 x = normalize(x, this.array); 13661 y = normalize(y, this.array); 13662 z = normalize(z, this.array); 13663 w = normalize(w, this.array); 13664 } 13665 this.data.array[index + 0] = x; 13666 this.data.array[index + 1] = y; 13667 this.data.array[index + 2] = z; 13668 this.data.array[index + 3] = w; 13669 return this; 13670 } 13671 clone(data) { 13672 if (data === undefined) { 13673 console.log('THREE.InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will de-interleave buffer data.'); 13674 const array = []; 13675 for(let i = 0; i < this.count; i++){ 13676 const index = i * this.data.stride + this.offset; 13677 for(let j = 0; j < this.itemSize; j++){ 13678 array.push(this.data.array[index + j]); 13679 } 13680 } 13681 return new BufferAttribute(new this.array.constructor(array), this.itemSize, this.normalized); 13682 } else { 13683 if (data.interleavedBuffers === undefined) { 13684 data.interleavedBuffers = {}; 13685 } 13686 if (data.interleavedBuffers[this.data.uuid] === undefined) { 13687 data.interleavedBuffers[this.data.uuid] = this.data.clone(data); 13688 } 13689 return new InterleavedBufferAttribute(data.interleavedBuffers[this.data.uuid], this.itemSize, this.offset, this.normalized); 13690 } 13691 } 13692 toJSON(data) { 13693 if (data === undefined) { 13694 console.log('THREE.InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will de-interleave buffer data.'); 13695 const array = []; 13696 for(let i = 0; i < this.count; i++){ 13697 const index = i * this.data.stride + this.offset; 13698 for(let j = 0; j < this.itemSize; j++){ 13699 array.push(this.data.array[index + j]); 13700 } 13701 } 13702 // de-interleave data and save it as an ordinary buffer attribute for now 13703 return { 13704 itemSize: this.itemSize, 13705 type: this.array.constructor.name, 13706 array: array, 13707 normalized: this.normalized 13708 }; 13709 } else { 13710 // save as true interleaved attribute 13711 if (data.interleavedBuffers === undefined) { 13712 data.interleavedBuffers = {}; 13713 } 13714 if (data.interleavedBuffers[this.data.uuid] === undefined) { 13715 data.interleavedBuffers[this.data.uuid] = this.data.toJSON(data); 13716 } 13717 return { 13718 isInterleavedBufferAttribute: true, 13719 itemSize: this.itemSize, 13720 data: this.data.uuid, 13721 offset: this.offset, 13722 normalized: this.normalized 13723 }; 13724 } 13725 } 13726 constructor(interleavedBuffer, itemSize, offset, normalized = false){ 13727 this.isInterleavedBufferAttribute = true; 13728 this.name = ''; 13729 this.data = interleavedBuffer; 13730 this.itemSize = itemSize; 13731 this.offset = offset; 13732 this.normalized = normalized; 13733 } 13734 } 13735 const _basePosition = /*@__PURE__*/ new Vector3(); 13736 const _skinIndex = /*@__PURE__*/ new Vector4(); 13737 const _skinWeight = /*@__PURE__*/ new Vector4(); 13738 const _vector3 = /*@__PURE__*/ new Vector3(); 13739 const _matrix4 = /*@__PURE__*/ new Matrix4(); 13740 const _vertex = /*@__PURE__*/ new Vector3(); 13741 const _sphere$5 = /*@__PURE__*/ new Sphere(); 13742 const _inverseMatrix$2 = /*@__PURE__*/ new Matrix4(); 13743 const _ray$2 = /*@__PURE__*/ new Ray(); 13744 /** 13745 * A mesh that has a {@link Skeleton} that can then be used to animate the 13746 * vertices of the geometry with skinning/skeleton animation. 13747 * 13748 * Next to a valid skeleton, the skinned mesh requires skin indices and weights 13749 * as buffer attributes in its geometry. These attribute define which bones affect a single 13750 * vertex to a certain extend. 13751 * 13752 * Typically skinned meshes are not created manually but loaders like {@link GLTFLoader} 13753 * or {@link FBXLoader } import respective models. 13754 * 13755 * @augments Mesh 13756 */ class SkinnedMesh extends Mesh { 13757 /** 13758 * Computes the bounding box of the skinned mesh, and updates {@link SkinnedMesh#boundingBox}. 13759 * The bounding box is not automatically computed by the engine; this method must be called by your app. 13760 * If the skinned mesh is animated, the bounding box should be recomputed per frame in order to reflect 13761 * the current animation state. 13762 */ computeBoundingBox() { 13763 const geometry = this.geometry; 13764 if (this.boundingBox === null) { 13765 this.boundingBox = new Box3(); 13766 } 13767 this.boundingBox.makeEmpty(); 13768 const positionAttribute = geometry.getAttribute('position'); 13769 for(let i = 0; i < positionAttribute.count; i++){ 13770 this.getVertexPosition(i, _vertex); 13771 this.boundingBox.expandByPoint(_vertex); 13772 } 13773 } 13774 /** 13775 * Computes the bounding sphere of the skinned mesh, and updates {@link SkinnedMesh#boundingSphere}. 13776 * The bounding sphere is automatically computed by the engine once when it is needed, e.g., for ray casting 13777 * and view frustum culling. If the skinned mesh is animated, the bounding sphere should be recomputed 13778 * per frame in order to reflect the current animation state. 13779 */ computeBoundingSphere() { 13780 const geometry = this.geometry; 13781 if (this.boundingSphere === null) { 13782 this.boundingSphere = new Sphere(); 13783 } 13784 this.boundingSphere.makeEmpty(); 13785 const positionAttribute = geometry.getAttribute('position'); 13786 for(let i = 0; i < positionAttribute.count; i++){ 13787 this.getVertexPosition(i, _vertex); 13788 this.boundingSphere.expandByPoint(_vertex); 13789 } 13790 } 13791 copy(source, recursive) { 13792 super.copy(source, recursive); 13793 this.bindMode = source.bindMode; 13794 this.bindMatrix.copy(source.bindMatrix); 13795 this.bindMatrixInverse.copy(source.bindMatrixInverse); 13796 this.skeleton = source.skeleton; 13797 if (source.boundingBox !== null) this.boundingBox = source.boundingBox.clone(); 13798 if (source.boundingSphere !== null) this.boundingSphere = source.boundingSphere.clone(); 13799 return this; 13800 } 13801 raycast(raycaster, intersects) { 13802 const material = this.material; 13803 const matrixWorld = this.matrixWorld; 13804 if (material === undefined) return; 13805 // test with bounding sphere in world space 13806 if (this.boundingSphere === null) this.computeBoundingSphere(); 13807 _sphere$5.copy(this.boundingSphere); 13808 _sphere$5.applyMatrix4(matrixWorld); 13809 if (raycaster.ray.intersectsSphere(_sphere$5) === false) return; 13810 // convert ray to local space of skinned mesh 13811 _inverseMatrix$2.copy(matrixWorld).invert(); 13812 _ray$2.copy(raycaster.ray).applyMatrix4(_inverseMatrix$2); 13813 // test with bounding box in local space 13814 if (this.boundingBox !== null) { 13815 if (_ray$2.intersectsBox(this.boundingBox) === false) return; 13816 } 13817 // test for intersections with geometry 13818 this._computeIntersections(raycaster, intersects, _ray$2); 13819 } 13820 getVertexPosition(index, target) { 13821 super.getVertexPosition(index, target); 13822 this.applyBoneTransform(index, target); 13823 return target; 13824 } 13825 /** 13826 * Binds the given skeleton to the skinned mesh. 13827 * 13828 * @param {Skeleton} skeleton - The skeleton to bind. 13829 * @param {Matrix4} [bindMatrix] - The bind matrix. If no bind matrix is provided, 13830 * the skinned mesh's world matrix will be used instead. 13831 */ bind(skeleton, bindMatrix) { 13832 this.skeleton = skeleton; 13833 if (bindMatrix === undefined) { 13834 this.updateMatrixWorld(true); 13835 this.skeleton.calculateInverses(); 13836 bindMatrix = this.matrixWorld; 13837 } 13838 this.bindMatrix.copy(bindMatrix); 13839 this.bindMatrixInverse.copy(bindMatrix).invert(); 13840 } 13841 /** 13842 * This method sets the skinned mesh in the rest pose). 13843 */ pose() { 13844 this.skeleton.pose(); 13845 } 13846 /** 13847 * Normalizes the skin weights which are defined as a buffer attribute 13848 * in the skinned mesh's geometry. 13849 */ normalizeSkinWeights() { 13850 const vector = new Vector4(); 13851 const skinWeight = this.geometry.attributes.skinWeight; 13852 for(let i = 0, l = skinWeight.count; i < l; i++){ 13853 vector.fromBufferAttribute(skinWeight, i); 13854 const scale = 1.0 / vector.manhattanLength(); 13855 if (scale !== Infinity) { 13856 vector.multiplyScalar(scale); 13857 } else { 13858 vector.set(1, 0, 0, 0); // do something reasonable 13859 } 13860 skinWeight.setXYZW(i, vector.x, vector.y, vector.z, vector.w); 13861 } 13862 } 13863 updateMatrixWorld(force) { 13864 super.updateMatrixWorld(force); 13865 if (this.bindMode === AttachedBindMode) { 13866 this.bindMatrixInverse.copy(this.matrixWorld).invert(); 13867 } else if (this.bindMode === DetachedBindMode) { 13868 this.bindMatrixInverse.copy(this.bindMatrix).invert(); 13869 } else { 13870 console.warn('THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode); 13871 } 13872 } 13873 /** 13874 * Applies the bone transform associated with the given index to the given 13875 * vertex position. Returns the updated vector. 13876 * 13877 * @param {number} index - The vertex index. 13878 * @param {Vector3} target - The target object that is used to store the method's result. 13879 * the skinned mesh's world matrix will be used instead. 13880 * @return {Vector3} The updated vertex position. 13881 */ applyBoneTransform(index, target) { 13882 const skeleton = this.skeleton; 13883 const geometry = this.geometry; 13884 _skinIndex.fromBufferAttribute(geometry.attributes.skinIndex, index); 13885 _skinWeight.fromBufferAttribute(geometry.attributes.skinWeight, index); 13886 _basePosition.copy(target).applyMatrix4(this.bindMatrix); 13887 target.set(0, 0, 0); 13888 for(let i = 0; i < 4; i++){ 13889 const weight = _skinWeight.getComponent(i); 13890 if (weight !== 0) { 13891 const boneIndex = _skinIndex.getComponent(i); 13892 _matrix4.multiplyMatrices(skeleton.bones[boneIndex].matrixWorld, skeleton.boneInverses[boneIndex]); 13893 target.addScaledVector(_vector3.copy(_basePosition).applyMatrix4(_matrix4), weight); 13894 } 13895 } 13896 return target.applyMatrix4(this.bindMatrixInverse); 13897 } 13898 /** 13899 * Constructs a new skinned mesh. 13900 * 13901 * @param {BufferGeometry} [geometry] - The mesh geometry. 13902 * @param {Material|Array<Material>} [material] - The mesh material. 13903 */ constructor(geometry, material){ 13904 super(geometry, material); 13905 /** 13906 * This flag can be used for type testing. 13907 * 13908 * @type {boolean} 13909 * @readonly 13910 * @default true 13911 */ this.isSkinnedMesh = true; 13912 this.type = 'SkinnedMesh'; 13913 /** 13914 * `AttachedBindMode` means the skinned mesh shares the same world space as the skeleton. 13915 * This is not true when using `DetachedBindMode` which is useful when sharing a skeleton 13916 * across multiple skinned meshes. 13917 * 13918 * @type {(AttachedBindMode|DetachedBindMode)} 13919 * @default AttachedBindMode 13920 */ this.bindMode = AttachedBindMode; 13921 /** 13922 * The base matrix that is used for the bound bone transforms. 13923 * 13924 * @type {Matrix4} 13925 */ this.bindMatrix = new Matrix4(); 13926 /** 13927 * The base matrix that is used for resetting the bound bone transforms. 13928 * 13929 * @type {Matrix4} 13930 */ this.bindMatrixInverse = new Matrix4(); 13931 /** 13932 * The bounding box of the skinned mesh. Can be computed via {@link SkinnedMesh#computeBoundingBox}. 13933 * 13934 * @type {?Box3} 13935 * @default null 13936 */ this.boundingBox = null; 13937 /** 13938 * The bounding sphere of the skinned mesh. Can be computed via {@link SkinnedMesh#computeBoundingSphere}. 13939 * 13940 * @type {?Sphere} 13941 * @default null 13942 */ this.boundingSphere = null; 13943 } 13944 } 13945 /** 13946 * A bone which is part of a {@link Skeleton}. The skeleton in turn is used by 13947 * the {@link SkinnedMesh}. 13948 * 13949 * ```js 13950 * const root = new THREE.Bone(); 13951 * const child = new THREE.Bone(); 13952 * 13953 * root.add( child ); 13954 * child.position.y = 5; 13955 * ``` 13956 * 13957 * @augments Object3D 13958 */ class Bone extends Object3D { 13959 /** 13960 * Constructs a new bone. 13961 */ constructor(){ 13962 super(); 13963 /** 13964 * This flag can be used for type testing. 13965 * 13966 * @type {boolean} 13967 * @readonly 13968 * @default true 13969 */ this.isBone = true; 13970 this.type = 'Bone'; 13971 } 13972 } 13973 class DataTexture extends Texture$1 { 13974 constructor(data = null, width = 1, height = 1, format, type, mapping, wrapS, wrapT, magFilter = NearestFilter, minFilter = NearestFilter, anisotropy, colorSpace){ 13975 super(null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace); 13976 this.isDataTexture = true; 13977 this.image = { 13978 data: data, 13979 width: width, 13980 height: height 13981 }; 13982 this.generateMipmaps = false; 13983 this.flipY = false; 13984 this.unpackAlignment = 1; 13985 } 13986 } 13987 const _offsetMatrix = /*@__PURE__*/ new Matrix4(); 13988 const _identityMatrix$1 = /*@__PURE__*/ new Matrix4(); 13989 /** 13990 * Class for representing the armatures in `three.js`. The skeleton 13991 * is defined by a hierarchy of bones. 13992 * 13993 * ```js 13994 * const bones = []; 13995 * 13996 * const shoulder = new THREE.Bone(); 13997 * const elbow = new THREE.Bone(); 13998 * const hand = new THREE.Bone(); 13999 * 14000 * shoulder.add( elbow ); 14001 * elbow.add( hand ); 14002 * 14003 * bones.push( shoulder , elbow, hand); 14004 * 14005 * shoulder.position.y = -5; 14006 * elbow.position.y = 0; 14007 * hand.position.y = 5; 14008 * 14009 * const armSkeleton = new THREE.Skeleton( bones ); 14010 * ``` 14011 */ class Skeleton { 14012 /** 14013 * Initializes the skeleton. This method gets automatically called by the constructor 14014 * but depending on how the skeleton is created it might be necessary to call this method 14015 * manually. 14016 */ init() { 14017 const bones = this.bones; 14018 const boneInverses = this.boneInverses; 14019 this.boneMatrices = new Float32Array(bones.length * 16); 14020 // calculate inverse bone matrices if necessary 14021 if (boneInverses.length === 0) { 14022 this.calculateInverses(); 14023 } else { 14024 // handle special case 14025 if (bones.length !== boneInverses.length) { 14026 console.warn('THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.'); 14027 this.boneInverses = []; 14028 for(let i = 0, il = this.bones.length; i < il; i++){ 14029 this.boneInverses.push(new Matrix4()); 14030 } 14031 } 14032 } 14033 } 14034 /** 14035 * Computes the bone inverse matrices. This method resets {@link Skeleton#boneInverses} 14036 * and fills it with new matrices. 14037 */ calculateInverses() { 14038 this.boneInverses.length = 0; 14039 for(let i = 0, il = this.bones.length; i < il; i++){ 14040 const inverse = new Matrix4(); 14041 if (this.bones[i]) { 14042 inverse.copy(this.bones[i].matrixWorld).invert(); 14043 } 14044 this.boneInverses.push(inverse); 14045 } 14046 } 14047 /** 14048 * Resets the skeleton to the base pose. 14049 */ pose() { 14050 // recover the bind-time world matrices 14051 for(let i = 0, il = this.bones.length; i < il; i++){ 14052 const bone = this.bones[i]; 14053 if (bone) { 14054 bone.matrixWorld.copy(this.boneInverses[i]).invert(); 14055 } 14056 } 14057 // compute the local matrices, positions, rotations and scales 14058 for(let i = 0, il = this.bones.length; i < il; i++){ 14059 const bone = this.bones[i]; 14060 if (bone) { 14061 if (bone.parent && bone.parent.isBone) { 14062 bone.matrix.copy(bone.parent.matrixWorld).invert(); 14063 bone.matrix.multiply(bone.matrixWorld); 14064 } else { 14065 bone.matrix.copy(bone.matrixWorld); 14066 } 14067 bone.matrix.decompose(bone.position, bone.quaternion, bone.scale); 14068 } 14069 } 14070 } 14071 /** 14072 * Resets the skeleton to the base pose. 14073 */ update() { 14074 const bones = this.bones; 14075 const boneInverses = this.boneInverses; 14076 const boneMatrices = this.boneMatrices; 14077 const boneTexture = this.boneTexture; 14078 // flatten bone matrices to array 14079 for(let i = 0, il = bones.length; i < il; i++){ 14080 // compute the offset between the current and the original transform 14081 const matrix = bones[i] ? bones[i].matrixWorld : _identityMatrix$1; 14082 _offsetMatrix.multiplyMatrices(matrix, boneInverses[i]); 14083 _offsetMatrix.toArray(boneMatrices, i * 16); 14084 } 14085 if (boneTexture !== null) { 14086 boneTexture.needsUpdate = true; 14087 } 14088 } 14089 /** 14090 * Returns a new skeleton with copied values from this instance. 14091 * 14092 * @return {Skeleton} A clone of this instance. 14093 */ clone() { 14094 return new Skeleton(this.bones, this.boneInverses); 14095 } 14096 /** 14097 * Computes a data texture for passing bone data to the vertex shader. 14098 * 14099 * @return {Skeleton} A reference of this instance. 14100 */ computeBoneTexture() { 14101 // layout (1 matrix = 4 pixels) 14102 // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) 14103 // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8) 14104 // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16) 14105 // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32) 14106 // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64) 14107 let size = Math.sqrt(this.bones.length * 4); // 4 pixels needed for 1 matrix 14108 size = Math.ceil(size / 4) * 4; 14109 size = Math.max(size, 4); 14110 const boneMatrices = new Float32Array(size * size * 4); // 4 floats per RGBA pixel 14111 boneMatrices.set(this.boneMatrices); // copy current values 14112 const boneTexture = new DataTexture(boneMatrices, size, size, RGBAFormat, FloatType); 14113 boneTexture.needsUpdate = true; 14114 this.boneMatrices = boneMatrices; 14115 this.boneTexture = boneTexture; 14116 return this; 14117 } 14118 /** 14119 * Searches through the skeleton's bone array and returns the first with a 14120 * matching name. 14121 * 14122 * @param {string} name - The name of the bone. 14123 * @return {Bone|undefined} The found bone. `undefined` if no bone has been found. 14124 */ getBoneByName(name) { 14125 for(let i = 0, il = this.bones.length; i < il; i++){ 14126 const bone = this.bones[i]; 14127 if (bone.name === name) { 14128 return bone; 14129 } 14130 } 14131 return undefined; 14132 } 14133 /** 14134 * Frees the GPU-related resources allocated by this instance. Call this 14135 * method whenever this instance is no longer used in your app. 14136 */ dispose() { 14137 if (this.boneTexture !== null) { 14138 this.boneTexture.dispose(); 14139 this.boneTexture = null; 14140 } 14141 } 14142 /** 14143 * Setups the skeleton by the given JSON and bones. 14144 * 14145 * @param {Object} json - The skeleton as serialized JSON. 14146 * @param {Array<Bone>} bones - An array of bones. 14147 * @return {Skeleton} A reference of this instance. 14148 */ fromJSON(json, bones) { 14149 this.uuid = json.uuid; 14150 for(let i = 0, l = json.bones.length; i < l; i++){ 14151 const uuid = json.bones[i]; 14152 let bone = bones[uuid]; 14153 if (bone === undefined) { 14154 console.warn('THREE.Skeleton: No bone found with UUID:', uuid); 14155 bone = new Bone(); 14156 } 14157 this.bones.push(bone); 14158 this.boneInverses.push(new Matrix4().fromArray(json.boneInverses[i])); 14159 } 14160 this.init(); 14161 return this; 14162 } 14163 /** 14164 * Serializes the skeleton into JSON. 14165 * 14166 * @return {Object} A JSON object representing the serialized skeleton. 14167 * @see {@link ObjectLoader#parse} 14168 */ toJSON() { 14169 const data = { 14170 metadata: { 14171 version: 4.6, 14172 type: 'Skeleton', 14173 generator: 'Skeleton.toJSON' 14174 }, 14175 bones: [], 14176 boneInverses: [] 14177 }; 14178 data.uuid = this.uuid; 14179 const bones = this.bones; 14180 const boneInverses = this.boneInverses; 14181 for(let i = 0, l = bones.length; i < l; i++){ 14182 const bone = bones[i]; 14183 data.bones.push(bone.uuid); 14184 const boneInverse = boneInverses[i]; 14185 data.boneInverses.push(boneInverse.toArray()); 14186 } 14187 return data; 14188 } 14189 /** 14190 * Constructs a new skeleton. 14191 * 14192 * @param {Array<Bone>} [bones] - An array of bones. 14193 * @param {Array<Matrix4>} [boneInverses] - An array of bone inverse matrices. 14194 * If not provided, these matrices will be computed automatically via {@link Skeleton#calculateInverses}. 14195 */ constructor(bones = [], boneInverses = []){ 14196 this.uuid = generateUUID(); 14197 /** 14198 * An array of bones defining the skeleton. 14199 * 14200 * @type {Array<Bone>} 14201 */ this.bones = bones.slice(0); 14202 /** 14203 * An array of bone inverse matrices. 14204 * 14205 * @type {Array<Matrix4>} 14206 */ this.boneInverses = boneInverses; 14207 /** 14208 * An array buffer holding the bone data. 14209 * Input data for {@link Skeleton#boneTexture}. 14210 * 14211 * @type {?Float32Array} 14212 * @default null 14213 */ this.boneMatrices = null; 14214 /** 14215 * A texture holding the bone data for use 14216 * in the vertex shader. 14217 * 14218 * @type {?DataTexture} 14219 * @default null 14220 */ this.boneTexture = null; 14221 this.init(); 14222 } 14223 } 14224 class InstancedBufferAttribute extends BufferAttribute { 14225 copy(source) { 14226 super.copy(source); 14227 this.meshPerAttribute = source.meshPerAttribute; 14228 return this; 14229 } 14230 toJSON() { 14231 const data = super.toJSON(); 14232 data.meshPerAttribute = this.meshPerAttribute; 14233 data.isInstancedBufferAttribute = true; 14234 return data; 14235 } 14236 constructor(array, itemSize, normalized, meshPerAttribute = 1){ 14237 super(array, itemSize, normalized); 14238 this.isInstancedBufferAttribute = true; 14239 this.meshPerAttribute = meshPerAttribute; 14240 } 14241 } 14242 const _instanceLocalMatrix = /*@__PURE__*/ new Matrix4(); 14243 const _instanceWorldMatrix = /*@__PURE__*/ new Matrix4(); 14244 const _instanceIntersects = []; 14245 const _box3 = /*@__PURE__*/ new Box3(); 14246 const _identity = /*@__PURE__*/ new Matrix4(); 14247 const _mesh$1 = /*@__PURE__*/ new Mesh(); 14248 const _sphere$4 = /*@__PURE__*/ new Sphere(); 14249 /** 14250 * A special version of a mesh with instanced rendering support. Use 14251 * this class if you have to render a large number of objects with the same 14252 * geometry and material(s) but with different world transformations. The usage 14253 * of 'InstancedMesh' will help you to reduce the number of draw calls and thus 14254 * improve the overall rendering performance in your application. 14255 * 14256 * @augments Mesh 14257 */ class InstancedMesh extends Mesh { 14258 /** 14259 * Computes the bounding box of the instanced mesh, and updates {@link InstancedMesh#boundingBox}. 14260 * The bounding box is not automatically computed by the engine; this method must be called by your app. 14261 * You may need to recompute the bounding box if an instance is transformed via {@link InstancedMesh#setMatrixAt}. 14262 */ computeBoundingBox() { 14263 const geometry = this.geometry; 14264 const count = this.count; 14265 if (this.boundingBox === null) { 14266 this.boundingBox = new Box3(); 14267 } 14268 if (geometry.boundingBox === null) { 14269 geometry.computeBoundingBox(); 14270 } 14271 this.boundingBox.makeEmpty(); 14272 for(let i = 0; i < count; i++){ 14273 this.getMatrixAt(i, _instanceLocalMatrix); 14274 _box3.copy(geometry.boundingBox).applyMatrix4(_instanceLocalMatrix); 14275 this.boundingBox.union(_box3); 14276 } 14277 } 14278 /** 14279 * Computes the bounding sphere of the instanced mesh, and updates {@link InstancedMesh#boundingSphere} 14280 * The engine automatically computes the bounding sphere when it is needed, e.g., for ray casting or view frustum culling. 14281 * You may need to recompute the bounding sphere if an instance is transformed via {@link InstancedMesh#setMatrixAt}. 14282 */ computeBoundingSphere() { 14283 const geometry = this.geometry; 14284 const count = this.count; 14285 if (this.boundingSphere === null) { 14286 this.boundingSphere = new Sphere(); 14287 } 14288 if (geometry.boundingSphere === null) { 14289 geometry.computeBoundingSphere(); 14290 } 14291 this.boundingSphere.makeEmpty(); 14292 for(let i = 0; i < count; i++){ 14293 this.getMatrixAt(i, _instanceLocalMatrix); 14294 _sphere$4.copy(geometry.boundingSphere).applyMatrix4(_instanceLocalMatrix); 14295 this.boundingSphere.union(_sphere$4); 14296 } 14297 } 14298 copy(source, recursive) { 14299 super.copy(source, recursive); 14300 this.instanceMatrix.copy(source.instanceMatrix); 14301 if (source.morphTexture !== null) this.morphTexture = source.morphTexture.clone(); 14302 if (source.instanceColor !== null) this.instanceColor = source.instanceColor.clone(); 14303 this.count = source.count; 14304 if (source.boundingBox !== null) this.boundingBox = source.boundingBox.clone(); 14305 if (source.boundingSphere !== null) this.boundingSphere = source.boundingSphere.clone(); 14306 return this; 14307 } 14308 /** 14309 * Gets the color of the defined instance. 14310 * 14311 * @param {number} index - The instance index. 14312 * @param {Color} color - The target object that is used to store the method's result. 14313 */ getColorAt(index, color) { 14314 color.fromArray(this.instanceColor.array, index * 3); 14315 } 14316 /** 14317 * Gets the local transformation matrix of the defined instance. 14318 * 14319 * @param {number} index - The instance index. 14320 * @param {Matrix4} matrix - The target object that is used to store the method's result. 14321 */ getMatrixAt(index, matrix) { 14322 matrix.fromArray(this.instanceMatrix.array, index * 16); 14323 } 14324 /** 14325 * Gets the morph target weights of the defined instance. 14326 * 14327 * @param {number} index - The instance index. 14328 * @param {Mesh} object - The target object that is used to store the method's result. 14329 */ getMorphAt(index, object) { 14330 const objectInfluences = object.morphTargetInfluences; 14331 const array = this.morphTexture.source.data.data; 14332 const len = objectInfluences.length + 1; // All influences + the baseInfluenceSum 14333 const dataIndex = index * len + 1; // Skip the baseInfluenceSum at the beginning 14334 for(let i = 0; i < objectInfluences.length; i++){ 14335 objectInfluences[i] = array[dataIndex + i]; 14336 } 14337 } 14338 raycast(raycaster, intersects) { 14339 const matrixWorld = this.matrixWorld; 14340 const raycastTimes = this.count; 14341 _mesh$1.geometry = this.geometry; 14342 _mesh$1.material = this.material; 14343 if (_mesh$1.material === undefined) return; 14344 // test with bounding sphere first 14345 if (this.boundingSphere === null) this.computeBoundingSphere(); 14346 _sphere$4.copy(this.boundingSphere); 14347 _sphere$4.applyMatrix4(matrixWorld); 14348 if (raycaster.ray.intersectsSphere(_sphere$4) === false) return; 14349 // now test each instance 14350 for(let instanceId = 0; instanceId < raycastTimes; instanceId++){ 14351 // calculate the world matrix for each instance 14352 this.getMatrixAt(instanceId, _instanceLocalMatrix); 14353 _instanceWorldMatrix.multiplyMatrices(matrixWorld, _instanceLocalMatrix); 14354 // the mesh represents this single instance 14355 _mesh$1.matrixWorld = _instanceWorldMatrix; 14356 _mesh$1.raycast(raycaster, _instanceIntersects); 14357 // process the result of raycast 14358 for(let i = 0, l = _instanceIntersects.length; i < l; i++){ 14359 const intersect = _instanceIntersects[i]; 14360 intersect.instanceId = instanceId; 14361 intersect.object = this; 14362 intersects.push(intersect); 14363 } 14364 _instanceIntersects.length = 0; 14365 } 14366 } 14367 /** 14368 * Sets the given color to the defined instance. Make sure you set the `needsUpdate` flag of 14369 * {@link InstancedMesh#instanceColor} to `true` after updating all the colors. 14370 * 14371 * @param {number} index - The instance index. 14372 * @param {Color} color - The instance color. 14373 */ setColorAt(index, color) { 14374 if (this.instanceColor === null) { 14375 this.instanceColor = new InstancedBufferAttribute(new Float32Array(this.instanceMatrix.count * 3).fill(1), 3); 14376 } 14377 color.toArray(this.instanceColor.array, index * 3); 14378 } 14379 /** 14380 * Sets the given local transformation matrix to the defined instance. Make sure you set the `needsUpdate` flag of 14381 * {@link InstancedMesh#instanceMatrix} to `true` after updating all the colors. 14382 * 14383 * @param {number} index - The instance index. 14384 * @param {Matrix4} matrix - The the local transformation. 14385 */ setMatrixAt(index, matrix) { 14386 matrix.toArray(this.instanceMatrix.array, index * 16); 14387 } 14388 /** 14389 * Sets the morph target weights to the defined instance. Make sure you set the `needsUpdate` flag of 14390 * {@link InstancedMesh#morphTexture} to `true` after updating all the influences. 14391 * 14392 * @param {number} index - The instance index. 14393 * @param {Mesh} object - A mesh which `morphTargetInfluences` property containing the morph target weights 14394 * of a single instance. 14395 */ setMorphAt(index, object) { 14396 const objectInfluences = object.morphTargetInfluences; 14397 const len = objectInfluences.length + 1; // morphBaseInfluence + all influences 14398 if (this.morphTexture === null) { 14399 this.morphTexture = new DataTexture(new Float32Array(len * this.count), len, this.count, RedFormat, FloatType); 14400 } 14401 const array = this.morphTexture.source.data.data; 14402 let morphInfluencesSum = 0; 14403 for(let i = 0; i < objectInfluences.length; i++){ 14404 morphInfluencesSum += objectInfluences[i]; 14405 } 14406 const morphBaseInfluence = this.geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum; 14407 const dataIndex = len * index; 14408 array[dataIndex] = morphBaseInfluence; 14409 array.set(objectInfluences, dataIndex + 1); 14410 } 14411 updateMorphTargets() {} 14412 /** 14413 * Frees the GPU-related resources allocated by this instance. Call this 14414 * method whenever this instance is no longer used in your app. 14415 */ dispose() { 14416 this.dispatchEvent({ 14417 type: 'dispose' 14418 }); 14419 if (this.morphTexture !== null) { 14420 this.morphTexture.dispose(); 14421 this.morphTexture = null; 14422 } 14423 } 14424 /** 14425 * Constructs a new instanced mesh. 14426 * 14427 * @param {BufferGeometry} [geometry] - The mesh geometry. 14428 * @param {Material|Array<Material>} [material] - The mesh material. 14429 * @param {number} count - The number of instances. 14430 */ constructor(geometry, material, count){ 14431 super(geometry, material); 14432 /** 14433 * This flag can be used for type testing. 14434 * 14435 * @type {boolean} 14436 * @readonly 14437 * @default true 14438 */ this.isInstancedMesh = true; 14439 /** 14440 * Represents the local transformation of all instances. You have to set its 14441 * {@link BufferAttribute#needsUpdate} flag to true if you modify instanced data 14442 * via {@link InstancedMesh#setMatrixAt}. 14443 * 14444 * @type {InstancedBufferAttribute} 14445 */ this.instanceMatrix = new InstancedBufferAttribute(new Float32Array(count * 16), 16); 14446 /** 14447 * Represents the color of all instances. You have to set its 14448 * {@link BufferAttribute#needsUpdate} flag to true if you modify instanced data 14449 * via {@link InstancedMesh#setColorAt}. 14450 * 14451 * @type {?InstancedBufferAttribute} 14452 * @default null 14453 */ this.instanceColor = null; 14454 /** 14455 * Represents the morph target weights of all instances. You have to set its 14456 * {@link Texture#needsUpdate} flag to true if you modify instanced data 14457 * via {@link InstancedMesh#setMorphAt}. 14458 * 14459 * @type {?InstancedBufferAttribute} 14460 * @default null 14461 */ this.morphTexture = null; 14462 /** 14463 * The number of instances. 14464 * 14465 * @type {number} 14466 */ this.count = count; 14467 /** 14468 * The bounding box of the instanced mesh. Can be computed via {@link InstancedMesh#computeBoundingBox}. 14469 * 14470 * @type {?Box3} 14471 * @default null 14472 */ this.boundingBox = null; 14473 /** 14474 * The bounding sphere of the instanced mesh. Can be computed via {@link InstancedMesh#computeBoundingSphere}. 14475 * 14476 * @type {?Sphere} 14477 * @default null 14478 */ this.boundingSphere = null; 14479 for(let i = 0; i < count; i++){ 14480 this.setMatrixAt(i, _identity); 14481 } 14482 } 14483 } 14484 const _vector1 = /*@__PURE__*/ new Vector3(); 14485 const _vector2 = /*@__PURE__*/ new Vector3(); 14486 const _normalMatrix = /*@__PURE__*/ new Matrix3(); 14487 /** 14488 * A two dimensional surface that extends infinitely in 3D space, represented 14489 * in [Hessian normal form]{@link http://mathworld.wolfram.com/HessianNormalForm.html} 14490 * by a unit length normal vector and a constant. 14491 */ class Plane { 14492 /** 14493 * Sets the plane components by copying the given values. 14494 * 14495 * @param {Vector3} normal - The normal. 14496 * @param {number} constant - The constant. 14497 * @return {Plane} A reference to this plane. 14498 */ set(normal, constant) { 14499 this.normal.copy(normal); 14500 this.constant = constant; 14501 return this; 14502 } 14503 /** 14504 * Sets the plane components by defining `x`, `y`, `z` as the 14505 * plane normal and `w` as the constant. 14506 * 14507 * @param {number} x - The value for the normal's x component. 14508 * @param {number} y - The value for the normal's y component. 14509 * @param {number} z - The value for the normal's z component. 14510 * @param {number} w - The constant value. 14511 * @return {Plane} A reference to this plane. 14512 */ setComponents(x, y, z, w) { 14513 this.normal.set(x, y, z); 14514 this.constant = w; 14515 return this; 14516 } 14517 /** 14518 * Sets the plane from the given normal and coplanar point (that is a point 14519 * that lies onto the plane). 14520 * 14521 * @param {Vector3} normal - The normal. 14522 * @param {Vector3} point - A coplanar point. 14523 * @return {Plane} A reference to this plane. 14524 */ setFromNormalAndCoplanarPoint(normal, point) { 14525 this.normal.copy(normal); 14526 this.constant = -point.dot(this.normal); 14527 return this; 14528 } 14529 /** 14530 * Sets the plane from three coplanar points. The winding order is 14531 * assumed to be counter-clockwise, and determines the direction of 14532 * the plane normal. 14533 * 14534 * @param {Vector3} a - The first coplanar point. 14535 * @param {Vector3} b - The second coplanar point. 14536 * @param {Vector3} c - The third coplanar point. 14537 * @return {Plane} A reference to this plane. 14538 */ setFromCoplanarPoints(a, b, c) { 14539 const normal = _vector1.subVectors(c, b).cross(_vector2.subVectors(a, b)).normalize(); 14540 // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? 14541 this.setFromNormalAndCoplanarPoint(normal, a); 14542 return this; 14543 } 14544 /** 14545 * Copies the values of the given plane to this instance. 14546 * 14547 * @param {Plane} plane - The plane to copy. 14548 * @return {Plane} A reference to this plane. 14549 */ copy(plane) { 14550 this.normal.copy(plane.normal); 14551 this.constant = plane.constant; 14552 return this; 14553 } 14554 /** 14555 * Normalizes the plane normal and adjusts the constant accordingly. 14556 * 14557 * @return {Plane} A reference to this plane. 14558 */ normalize() { 14559 // Note: will lead to a divide by zero if the plane is invalid. 14560 const inverseNormalLength = 1.0 / this.normal.length(); 14561 this.normal.multiplyScalar(inverseNormalLength); 14562 this.constant *= inverseNormalLength; 14563 return this; 14564 } 14565 /** 14566 * Negates both the plane normal and the constant. 14567 * 14568 * @return {Plane} A reference to this plane. 14569 */ negate() { 14570 this.constant *= -1; 14571 this.normal.negate(); 14572 return this; 14573 } 14574 /** 14575 * Returns the signed distance from the given point to this plane. 14576 * 14577 * @param {Vector3} point - The point to compute the distance for. 14578 * @return {number} The signed distance. 14579 */ distanceToPoint(point) { 14580 return this.normal.dot(point) + this.constant; 14581 } 14582 /** 14583 * Returns the signed distance from the given sphere to this plane. 14584 * 14585 * @param {Sphere} sphere - The sphere to compute the distance for. 14586 * @return {number} The signed distance. 14587 */ distanceToSphere(sphere) { 14588 return this.distanceToPoint(sphere.center) - sphere.radius; 14589 } 14590 /** 14591 * Projects a the given point onto the plane. 14592 * 14593 * @param {Vector3} point - The point to project. 14594 * @param {Vector3} target - The target vector that is used to store the method's result. 14595 * @return {Vector3} The projected point on the plane. 14596 */ projectPoint(point, target) { 14597 return target.copy(point).addScaledVector(this.normal, -this.distanceToPoint(point)); 14598 } 14599 /** 14600 * Returns the intersection point of the passed line and the plane. Returns 14601 * `null` if the line does not intersect. Returns the line's starting point if 14602 * the line is coplanar with the plane. 14603 * 14604 * @param {Line3} line - The line to compute the intersection for. 14605 * @param {Vector3} target - The target vector that is used to store the method's result. 14606 * @return {?Vector3} The intersection point. 14607 */ intersectLine(line, target) { 14608 const direction = line.delta(_vector1); 14609 const denominator = this.normal.dot(direction); 14610 if (denominator === 0) { 14611 // line is coplanar, return origin 14612 if (this.distanceToPoint(line.start) === 0) { 14613 return target.copy(line.start); 14614 } 14615 // Unsure if this is the correct method to handle this case. 14616 return null; 14617 } 14618 const t = -(line.start.dot(this.normal) + this.constant) / denominator; 14619 if (t < 0 || t > 1) { 14620 return null; 14621 } 14622 return target.copy(line.start).addScaledVector(direction, t); 14623 } 14624 /** 14625 * Returns `true` if the given line segment intersects with (passes through) the plane. 14626 * 14627 * @param {Line3} line - The line to test. 14628 * @return {boolean} Whether the given line segment intersects with the plane or not. 14629 */ intersectsLine(line) { 14630 // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. 14631 const startSign = this.distanceToPoint(line.start); 14632 const endSign = this.distanceToPoint(line.end); 14633 return startSign < 0 && endSign > 0 || endSign < 0 && startSign > 0; 14634 } 14635 /** 14636 * Returns `true` if the given bounding box intersects with the plane. 14637 * 14638 * @param {Box3} box - The bounding box to test. 14639 * @return {boolean} Whether the given bounding box intersects with the plane or not. 14640 */ intersectsBox(box) { 14641 return box.intersectsPlane(this); 14642 } 14643 /** 14644 * Returns `true` if the given bounding sphere intersects with the plane. 14645 * 14646 * @param {Sphere} sphere - The bounding sphere to test. 14647 * @return {boolean} Whether the given bounding sphere intersects with the plane or not. 14648 */ intersectsSphere(sphere) { 14649 return sphere.intersectsPlane(this); 14650 } 14651 /** 14652 * Returns a coplanar vector to the plane, by calculating the 14653 * projection of the normal at the origin onto the plane. 14654 * 14655 * @param {Vector3} target - The target vector that is used to store the method's result. 14656 * @return {Vector3} The coplanar point. 14657 */ coplanarPoint(target) { 14658 return target.copy(this.normal).multiplyScalar(-this.constant); 14659 } 14660 /** 14661 * Apply a 4x4 matrix to the plane. The matrix must be an affine, homogeneous transform. 14662 * 14663 * The optional normal matrix can be pre-computed like so: 14664 * ```js 14665 * const optionalNormalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); 14666 * ``` 14667 * 14668 * @param {Matrix4} matrix - The transformation matrix. 14669 * @param {Matrix4} [optionalNormalMatrix] - A pre-computed normal matrix. 14670 * @return {Plane} A reference to this plane. 14671 */ applyMatrix4(matrix, optionalNormalMatrix) { 14672 const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix(matrix); 14673 const referencePoint = this.coplanarPoint(_vector1).applyMatrix4(matrix); 14674 const normal = this.normal.applyMatrix3(normalMatrix).normalize(); 14675 this.constant = -referencePoint.dot(normal); 14676 return this; 14677 } 14678 /** 14679 * Translates the plane by the distance defined by the given offset vector. 14680 * Note that this only affects the plane constant and will not affect the normal vector. 14681 * 14682 * @param {Vector3} offset - The offset vector. 14683 * @return {Plane} A reference to this plane. 14684 */ translate(offset) { 14685 this.constant -= offset.dot(this.normal); 14686 return this; 14687 } 14688 /** 14689 * Returns `true` if this plane is equal with the given one. 14690 * 14691 * @param {Plane} plane - The plane to test for equality. 14692 * @return {boolean} Whether this plane is equal with the given one. 14693 */ equals(plane) { 14694 return plane.normal.equals(this.normal) && plane.constant === this.constant; 14695 } 14696 /** 14697 * Returns a new plane with copied values from this instance. 14698 * 14699 * @return {Plane} A clone of this instance. 14700 */ clone() { 14701 return new this.constructor().copy(this); 14702 } 14703 /** 14704 * Constructs a new plane. 14705 * 14706 * @param {Vector3} [normal=(1,0,0)] - A unit length vector defining the normal of the plane. 14707 * @param {number} [constant=0] - The signed distance from the origin to the plane. 14708 */ constructor(normal = new Vector3(1, 0, 0), constant = 0){ 14709 /** 14710 * This flag can be used for type testing. 14711 * 14712 * @type {boolean} 14713 * @readonly 14714 * @default true 14715 */ this.isPlane = true; 14716 /** 14717 * A unit length vector defining the normal of the plane. 14718 * 14719 * @type {Vector3} 14720 */ this.normal = normal; 14721 /** 14722 * The signed distance from the origin to the plane. 14723 * 14724 * @type {number} 14725 * @default 0 14726 */ this.constant = constant; 14727 } 14728 } 14729 const _sphere$3 = /*@__PURE__*/ new Sphere(); 14730 const _vector$6 = /*@__PURE__*/ new Vector3(); 14731 /** 14732 * Frustums are used to determine what is inside the camera's field of view. 14733 * They help speed up the rendering process - objects which lie outside a camera's 14734 * frustum can safely be excluded from rendering. 14735 * 14736 * This class is mainly intended for use internally by a renderer. 14737 */ class Frustum { 14738 /**
vendor: 4,611 bytes, lines 14739-14835
14739 * Sets the frustum planes by copying the given planes. 14740 * 14741 * @param {Plane} [p0] - The first plane that encloses the frustum. 14742 * @param {Plane} [p1] - The second plane that encloses the frustum. 14743 * @param {Plane} [p2] - The third plane that encloses the frustum. 14744 * @param {Plane} [p3] - The fourth plane that encloses the frustum. 14745 * @param {Plane} [p4] - The fifth plane that encloses the frustum. 14746 * @param {Plane} [p5] - The sixth plane that encloses the frustum. 14747 * @return {Frustum} A reference to this frustum. 14748 */ set(p0, p1, p2, p3, p4, p5) { 14749 const planes = this.planes; 14750 planes[0].copy(p0); 14751 planes[1].copy(p1); 14752 planes[2].copy(p2); 14753 planes[3].copy(p3); 14754 planes[4].copy(p4); 14755 planes[5].copy(p5); 14756 return this; 14757 } 14758 /** 14759 * Copies the values of the given frustum to this instance. 14760 * 14761 * @param {Frustum} frustum - The frustum to copy. 14762 * @return {Frustum} A reference to this frustum. 14763 */ copy(frustum) { 14764 const planes = this.planes; 14765 for(let i = 0; i < 6; i++){ 14766 planes[i].copy(frustum.planes[i]); 14767 } 14768 return this; 14769 } 14770 /** 14771 * Sets the frustum planes from the given projection matrix. 14772 * 14773 * @param {Matrix4} m - The projection matrix. 14774 * @param {(WebGLCoordinateSystem|WebGPUCoordinateSystem)} coordinateSystem - The coordinate system. 14775 * @return {Frustum} A reference to this frustum. 14776 */ setFromProjectionMatrix(m, coordinateSystem = WebGLCoordinateSystem) { 14777 const planes = this.planes; 14778 const me = m.elements; 14779 const me0 = me[0], me1 = me[1], me2 = me[2], me3 = me[3]; 14780 const me4 = me[4], me5 = me[5], me6 = me[6], me7 = me[7]; 14781 const me8 = me[8], me9 = me[9], me10 = me[10], me11 = me[11]; 14782 const me12 = me[12], me13 = me[13], me14 = me[14], me15 = me[15]; 14783 planes[0].setComponents(me3 - me0, me7 - me4, me11 - me8, me15 - me12).normalize(); 14784 planes[1].setComponents(me3 + me0, me7 + me4, me11 + me8, me15 + me12).normalize(); 14785 planes[2].setComponents(me3 + me1, me7 + me5, me11 + me9, me15 + me13).normalize(); 14786 planes[3].setComponents(me3 - me1, me7 - me5, me11 - me9, me15 - me13).normalize(); 14787 planes[4].setComponents(me3 - me2, me7 - me6, me11 - me10, me15 - me14).normalize(); 14788 if (coordinateSystem === WebGLCoordinateSystem) { 14789 planes[5].setComponents(me3 + me2, me7 + me6, me11 + me10, me15 + me14).normalize(); 14790 } else if (coordinateSystem === WebGPUCoordinateSystem) { 14791 planes[5].setComponents(me2, me6, me10, me14).normalize(); 14792 } else { 14793 throw new Error('THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: ' + coordinateSystem); 14794 } 14795 return this; 14796 } 14797 /** 14798 * Returns `true` if the 3D object's bounding sphere is intersecting this frustum. 14799 * 14800 * Note that the 3D object must have a geometry so that the bounding sphere can be calculated. 14801 * 14802 * @param {Object3D} object - The 3D object to test. 14803 * @return {boolean} Whether the 3D object's bounding sphere is intersecting this frustum or not. 14804 */ intersectsObject(object) { 14805 if (object.boundingSphere !== undefined) { 14806 if (object.boundingSphere === null) object.computeBoundingSphere(); 14807 _sphere$3.copy(object.boundingSphere).applyMatrix4(object.matrixWorld); 14808 } else { 14809 const geometry = object.geometry; 14810 if (geometry.boundingSphere === null) geometry.computeBoundingSphere(); 14811 _sphere$3.copy(geometry.boundingSphere).applyMatrix4(object.matrixWorld); 14812 } 14813 return this.intersectsSphere(_sphere$3); 14814 } 14815 /** 14816 * Returns `true` if the given sprite is intersecting this frustum. 14817 * 14818 * @param {Sprite} sprite - The sprite to test. 14819 * @return {boolean} Whether the sprite is intersecting this frustum or not. 14820 */ intersectsSprite(sprite) { 14821 _sphere$3.center.set(0, 0, 0); 14822 _sphere$3.radius = 0.7071067811865476; 14823 _sphere$3.applyMatrix4(sprite.matrixWorld); 14824 return this.intersectsSphere(_sphere$3); 14825 } 14826 /** 14827 * Returns `true` if the given bounding sphere is intersecting this frustum. 14828 * 14829 * @param {Sphere} sphere - The bounding sphere to test. 14830 * @return {boolean} Whether the bounding sphere is intersecting this frustum or not. 14831 */ intersectsSphere(sphere) { 14832 const planes = this.planes; 14833 const center = sphere.center; 14834 const negRadius = -sphere.radius; 14835 for(let i = 0; i < 6; i++){
vendor: 21,668 bytes, lines 14836-15382
14836 const distance = planes[i].distanceToPoint(center); 14837 if (distance < negRadius) { 14838 return false; 14839 } 14840 } 14841 return true; 14842 } 14843 /** 14844 * Returns `true` if the given bounding box is intersecting this frustum. 14845 * 14846 * @param {Box3} box - The bounding box to test. 14847 * @return {boolean} Whether the bounding box is intersecting this frustum or not. 14848 */ intersectsBox(box) { 14849 const planes = this.planes; 14850 for(let i = 0; i < 6; i++){ 14851 const plane = planes[i]; 14852 // corner at max distance 14853 _vector$6.x = plane.normal.x > 0 ? box.max.x : box.min.x; 14854 _vector$6.y = plane.normal.y > 0 ? box.max.y : box.min.y; 14855 _vector$6.z = plane.normal.z > 0 ? box.max.z : box.min.z; 14856 if (plane.distanceToPoint(_vector$6) < 0) { 14857 return false; 14858 } 14859 } 14860 return true; 14861 } 14862 /** 14863 * Returns `true` if the given point lies within the frustum. 14864 * 14865 * @param {Vector3} point - The point to test. 14866 * @return {boolean} Whether the point lies within this frustum or not. 14867 */ containsPoint(point) { 14868 const planes = this.planes; 14869 for(let i = 0; i < 6; i++){ 14870 if (planes[i].distanceToPoint(point) < 0) { 14871 return false; 14872 } 14873 } 14874 return true; 14875 } 14876 /** 14877 * Returns a new frustum with copied values from this instance. 14878 * 14879 * @return {Frustum} A clone of this instance. 14880 */ clone() { 14881 return new this.constructor().copy(this); 14882 } 14883 /** 14884 * Constructs a new frustum. 14885 * 14886 * @param {Plane} [p0] - The first plane that encloses the frustum. 14887 * @param {Plane} [p1] - The second plane that encloses the frustum. 14888 * @param {Plane} [p2] - The third plane that encloses the frustum. 14889 * @param {Plane} [p3] - The fourth plane that encloses the frustum. 14890 * @param {Plane} [p4] - The fifth plane that encloses the frustum. 14891 * @param {Plane} [p5] - The sixth plane that encloses the frustum. 14892 */ constructor(p0 = new Plane(), p1 = new Plane(), p2 = new Plane(), p3 = new Plane(), p4 = new Plane(), p5 = new Plane()){ 14893 /** 14894 * This array holds the planes that enclose the frustum. 14895 * 14896 * @type {Array<Plane>} 14897 */ this.planes = [ 14898 p0, 14899 p1, 14900 p2, 14901 p3, 14902 p4, 14903 p5 14904 ]; 14905 } 14906 } 14907 class LineBasicMaterial extends Material$1 { 14908 copy(source) { 14909 super.copy(source); 14910 this.color.copy(source.color); 14911 this.map = source.map; 14912 this.linewidth = source.linewidth; 14913 this.linecap = source.linecap; 14914 this.linejoin = source.linejoin; 14915 this.fog = source.fog; 14916 return this; 14917 } 14918 constructor(parameters){ 14919 super(); 14920 this.isLineBasicMaterial = true; 14921 this.type = 'LineBasicMaterial'; 14922 this.color = new Color(0xffffff); 14923 this.map = null; 14924 this.linewidth = 1; 14925 this.linecap = 'round'; 14926 this.linejoin = 'round'; 14927 this.fog = true; 14928 this.setValues(parameters); 14929 } 14930 } 14931 const _vStart = /*@__PURE__*/ new Vector3(); 14932 const _vEnd = /*@__PURE__*/ new Vector3(); 14933 const _inverseMatrix$1 = /*@__PURE__*/ new Matrix4(); 14934 const _ray$1 = /*@__PURE__*/ new Ray(); 14935 const _sphere$1 = /*@__PURE__*/ new Sphere(); 14936 const _intersectPointOnRay = /*@__PURE__*/ new Vector3(); 14937 const _intersectPointOnSegment = /*@__PURE__*/ new Vector3(); 14938 /** 14939 * A continuous line. The line are rendered by connecting consecutive 14940 * vertices with straight lines. 14941 * 14942 * ```js 14943 * const material = new THREE.LineBasicMaterial( { color: 0x0000ff } ); 14944 * 14945 * const points = []; 14946 * points.push( new THREE.Vector3( - 10, 0, 0 ) ); 14947 * points.push( new THREE.Vector3( 0, 10, 0 ) ); 14948 * points.push( new THREE.Vector3( 10, 0, 0 ) ); 14949 * 14950 * const geometry = new THREE.BufferGeometry().setFromPoints( points ); 14951 * 14952 * const line = new THREE.Line( geometry, material ); 14953 * scene.add( line ); 14954 * ``` 14955 * 14956 * @augments Object3D 14957 */ class Line extends Object3D { 14958 copy(source, recursive) { 14959 super.copy(source, recursive); 14960 this.material = Array.isArray(source.material) ? source.material.slice() : source.material; 14961 this.geometry = source.geometry; 14962 return this; 14963 } 14964 /** 14965 * Computes an array of distance values which are necessary for rendering dashed lines. 14966 * For each vertex in the geometry, the method calculates the cumulative length from the 14967 * current point to the very beginning of the line. 14968 * 14969 * @return {Line} A reference to this line. 14970 */ computeLineDistances() { 14971 const geometry = this.geometry; 14972 // we assume non-indexed geometry 14973 if (geometry.index === null) { 14974 const positionAttribute = geometry.attributes.position; 14975 const lineDistances = [ 14976 0 14977 ]; 14978 for(let i = 1, l = positionAttribute.count; i < l; i++){ 14979 _vStart.fromBufferAttribute(positionAttribute, i - 1); 14980 _vEnd.fromBufferAttribute(positionAttribute, i); 14981 lineDistances[i] = lineDistances[i - 1]; 14982 lineDistances[i] += _vStart.distanceTo(_vEnd); 14983 } 14984 geometry.setAttribute('lineDistance', new Float32BufferAttribute(lineDistances, 1)); 14985 } else { 14986 console.warn('THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.'); 14987 } 14988 return this; 14989 } 14990 /** 14991 * Computes intersection points between a casted ray and this line. 14992 * 14993 * @param {Raycaster} raycaster - The raycaster. 14994 * @param {Array<Object>} intersects - The target array that holds the intersection points. 14995 */ raycast(raycaster, intersects) { 14996 const geometry = this.geometry; 14997 const matrixWorld = this.matrixWorld; 14998 const threshold = raycaster.params.Line.threshold; 14999 const drawRange = geometry.drawRange; 15000 // Checking boundingSphere distance to ray 15001 if (geometry.boundingSphere === null) geometry.computeBoundingSphere(); 15002 _sphere$1.copy(geometry.boundingSphere); 15003 _sphere$1.applyMatrix4(matrixWorld); 15004 _sphere$1.radius += threshold; 15005 if (raycaster.ray.intersectsSphere(_sphere$1) === false) return; 15006 // 15007 _inverseMatrix$1.copy(matrixWorld).invert(); 15008 _ray$1.copy(raycaster.ray).applyMatrix4(_inverseMatrix$1); 15009 const localThreshold = threshold / ((this.scale.x + this.scale.y + this.scale.z) / 3); 15010 const localThresholdSq = localThreshold * localThreshold; 15011 const step = this.isLineSegments ? 2 : 1; 15012 const index = geometry.index; 15013 const attributes = geometry.attributes; 15014 const positionAttribute = attributes.position; 15015 if (index !== null) { 15016 const start = Math.max(0, drawRange.start); 15017 const end = Math.min(index.count, drawRange.start + drawRange.count); 15018 for(let i = start, l = end - 1; i < l; i += step){ 15019 const a = index.getX(i); 15020 const b = index.getX(i + 1); 15021 const intersect = checkIntersection(this, raycaster, _ray$1, localThresholdSq, a, b, i); 15022 if (intersect) { 15023 intersects.push(intersect); 15024 } 15025 } 15026 if (this.isLineLoop) { 15027 const a = index.getX(end - 1); 15028 const b = index.getX(start); 15029 const intersect = checkIntersection(this, raycaster, _ray$1, localThresholdSq, a, b, end - 1); 15030 if (intersect) { 15031 intersects.push(intersect); 15032 } 15033 } 15034 } else { 15035 const start = Math.max(0, drawRange.start); 15036 const end = Math.min(positionAttribute.count, drawRange.start + drawRange.count); 15037 for(let i = start, l = end - 1; i < l; i += step){ 15038 const intersect = checkIntersection(this, raycaster, _ray$1, localThresholdSq, i, i + 1, i); 15039 if (intersect) { 15040 intersects.push(intersect); 15041 } 15042 } 15043 if (this.isLineLoop) { 15044 const intersect = checkIntersection(this, raycaster, _ray$1, localThresholdSq, end - 1, start, end - 1); 15045 if (intersect) { 15046 intersects.push(intersect); 15047 } 15048 } 15049 } 15050 } 15051 /** 15052 * Sets the values of {@link Line#morphTargetDictionary} and {@link Line#morphTargetInfluences} 15053 * to make sure existing morph targets can influence this 3D object. 15054 */ updateMorphTargets() { 15055 const geometry = this.geometry; 15056 const morphAttributes = geometry.morphAttributes; 15057 const keys = Object.keys(morphAttributes); 15058 if (keys.length > 0) { 15059 const morphAttribute = morphAttributes[keys[0]]; 15060 if (morphAttribute !== undefined) { 15061 this.morphTargetInfluences = []; 15062 this.morphTargetDictionary = {}; 15063 for(let m = 0, ml = morphAttribute.length; m < ml; m++){ 15064 const name = morphAttribute[m].name || String(m); 15065 this.morphTargetInfluences.push(0); 15066 this.morphTargetDictionary[name] = m; 15067 } 15068 } 15069 } 15070 } 15071 /** 15072 * Constructs a new line. 15073 * 15074 * @param {BufferGeometry} [geometry] - The line geometry. 15075 * @param {Material|Array<Material>} [material] - The line material. 15076 */ constructor(geometry = new BufferGeometry(), material = new LineBasicMaterial()){ 15077 super(); 15078 /** 15079 * This flag can be used for type testing. 15080 * 15081 * @type {boolean} 15082 * @readonly 15083 * @default true 15084 */ this.isLine = true; 15085 this.type = 'Line'; 15086 /** 15087 * The line geometry. 15088 * 15089 * @type {BufferGeometry} 15090 */ this.geometry = geometry; 15091 /** 15092 * The line material. 15093 * 15094 * @type {Material|Array<Material>} 15095 * @default LineBasicMaterial 15096 */ this.material = material; 15097 /** 15098 * A dictionary representing the morph targets in the geometry. The key is the 15099 * morph targets name, the value its attribute index. This member is `undefined` 15100 * by default and only set when morph targets are detected in the geometry. 15101 * 15102 * @type {Object<String,number>|undefined} 15103 * @default undefined 15104 */ this.morphTargetDictionary = undefined; 15105 /** 15106 * An array of weights typically in the range `[0,1]` that specify how much of the morph 15107 * is applied. This member is `undefined` by default and only set when morph targets are 15108 * detected in the geometry. 15109 * 15110 * @type {Array<number>|undefined} 15111 * @default undefined 15112 */ this.morphTargetInfluences = undefined; 15113 this.updateMorphTargets(); 15114 } 15115 } 15116 function checkIntersection(object, raycaster, ray, thresholdSq, a, b, i) { 15117 const positionAttribute = object.geometry.attributes.position; 15118 _vStart.fromBufferAttribute(positionAttribute, a); 15119 _vEnd.fromBufferAttribute(positionAttribute, b); 15120 const distSq = ray.distanceSqToSegment(_vStart, _vEnd, _intersectPointOnRay, _intersectPointOnSegment); 15121 if (distSq > thresholdSq) return; 15122 _intersectPointOnRay.applyMatrix4(object.matrixWorld); // Move back to world space for distance calculation 15123 const distance = raycaster.ray.origin.distanceTo(_intersectPointOnRay); 15124 if (distance < raycaster.near || distance > raycaster.far) return; 15125 return { 15126 distance: distance, 15127 // What do we want? intersection point on the ray or on the segment?? 15128 // point: raycaster.ray.at( distance ), 15129 point: _intersectPointOnSegment.clone().applyMatrix4(object.matrixWorld), 15130 index: i, 15131 face: null, 15132 faceIndex: null, 15133 barycoord: null, 15134 object: object 15135 }; 15136 } 15137 const _start = /*@__PURE__*/ new Vector3(); 15138 const _end = /*@__PURE__*/ new Vector3(); 15139 /** 15140 * A series of lines drawn between pairs of vertices. 15141 * 15142 * @augments Line 15143 */ class LineSegments extends Line { 15144 computeLineDistances() { 15145 const geometry = this.geometry; 15146 // we assume non-indexed geometry 15147 if (geometry.index === null) { 15148 const positionAttribute = geometry.attributes.position; 15149 const lineDistances = []; 15150 for(let i = 0, l = positionAttribute.count; i < l; i += 2){ 15151 _start.fromBufferAttribute(positionAttribute, i); 15152 _end.fromBufferAttribute(positionAttribute, i + 1); 15153 lineDistances[i] = i === 0 ? 0 : lineDistances[i - 1]; 15154 lineDistances[i + 1] = lineDistances[i] + _start.distanceTo(_end); 15155 } 15156 geometry.setAttribute('lineDistance', new Float32BufferAttribute(lineDistances, 1)); 15157 } else { 15158 console.warn('THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.'); 15159 } 15160 return this; 15161 } 15162 /** 15163 * Constructs a new line segments. 15164 * 15165 * @param {BufferGeometry} [geometry] - The line geometry. 15166 * @param {Material|Array<Material>} [material] - The line material. 15167 */ constructor(geometry, material){ 15168 super(geometry, material); 15169 /** 15170 * This flag can be used for type testing. 15171 * 15172 * @type {boolean} 15173 * @readonly 15174 * @default true 15175 */ this.isLineSegments = true; 15176 this.type = 'LineSegments'; 15177 } 15178 } 15179 /** 15180 * A continuous line. This is nearly the same as {@link Line} the only difference 15181 * is that the last vertex is connected with the first vertex in order to close 15182 * the line to form a loop. 15183 * 15184 * @augments Line 15185 */ class LineLoop extends Line { 15186 /** 15187 * Constructs a new line loop. 15188 * 15189 * @param {BufferGeometry} [geometry] - The line geometry. 15190 * @param {Material|Array<Material>} [material] - The line material. 15191 */ constructor(geometry, material){ 15192 super(geometry, material); 15193 /** 15194 * This flag can be used for type testing. 15195 * 15196 * @type {boolean} 15197 * @readonly 15198 * @default true 15199 */ this.isLineLoop = true; 15200 this.type = 'LineLoop'; 15201 } 15202 } 15203 class PointsMaterial extends Material$1 { 15204 copy(source) { 15205 super.copy(source); 15206 this.color.copy(source.color); 15207 this.map = source.map; 15208 this.alphaMap = source.alphaMap; 15209 this.size = source.size; 15210 this.sizeAttenuation = source.sizeAttenuation; 15211 this.fog = source.fog; 15212 return this; 15213 } 15214 constructor(parameters){ 15215 super(); 15216 this.isPointsMaterial = true; 15217 this.type = 'PointsMaterial'; 15218 this.color = new Color(0xffffff); 15219 this.map = null; 15220 this.alphaMap = null; 15221 this.size = 1; 15222 this.sizeAttenuation = true; 15223 this.fog = true; 15224 this.setValues(parameters); 15225 } 15226 } 15227 const _inverseMatrix = /*@__PURE__*/ new Matrix4(); 15228 const _ray = /*@__PURE__*/ new Ray(); 15229 const _sphere = /*@__PURE__*/ new Sphere(); 15230 const _position$2 = /*@__PURE__*/ new Vector3(); 15231 /** 15232 * A class for displaying points or point clouds. 15233 * 15234 * @augments Object3D 15235 */ class Points extends Object3D { 15236 copy(source, recursive) { 15237 super.copy(source, recursive); 15238 this.material = Array.isArray(source.material) ? source.material.slice() : source.material; 15239 this.geometry = source.geometry; 15240 return this; 15241 } 15242 /** 15243 * Computes intersection points between a casted ray and this point cloud. 15244 * 15245 * @param {Raycaster} raycaster - The raycaster. 15246 * @param {Array<Object>} intersects - The target array that holds the intersection points. 15247 */ raycast(raycaster, intersects) { 15248 const geometry = this.geometry; 15249 const matrixWorld = this.matrixWorld; 15250 const threshold = raycaster.params.Points.threshold; 15251 const drawRange = geometry.drawRange; 15252 // Checking boundingSphere distance to ray 15253 if (geometry.boundingSphere === null) geometry.computeBoundingSphere(); 15254 _sphere.copy(geometry.boundingSphere); 15255 _sphere.applyMatrix4(matrixWorld); 15256 _sphere.radius += threshold; 15257 if (raycaster.ray.intersectsSphere(_sphere) === false) return; 15258 // 15259 _inverseMatrix.copy(matrixWorld).invert(); 15260 _ray.copy(raycaster.ray).applyMatrix4(_inverseMatrix); 15261 const localThreshold = threshold / ((this.scale.x + this.scale.y + this.scale.z) / 3); 15262 const localThresholdSq = localThreshold * localThreshold; 15263 const index = geometry.index; 15264 const attributes = geometry.attributes; 15265 const positionAttribute = attributes.position; 15266 if (index !== null) { 15267 const start = Math.max(0, drawRange.start); 15268 const end = Math.min(index.count, drawRange.start + drawRange.count); 15269 for(let i = start, il = end; i < il; i++){ 15270 const a = index.getX(i); 15271 _position$2.fromBufferAttribute(positionAttribute, a); 15272 testPoint(_position$2, a, localThresholdSq, matrixWorld, raycaster, intersects, this); 15273 } 15274 } else { 15275 const start = Math.max(0, drawRange.start); 15276 const end = Math.min(positionAttribute.count, drawRange.start + drawRange.count); 15277 for(let i = start, l = end; i < l; i++){ 15278 _position$2.fromBufferAttribute(positionAttribute, i); 15279 testPoint(_position$2, i, localThresholdSq, matrixWorld, raycaster, intersects, this); 15280 } 15281 } 15282 } 15283 /** 15284 * Sets the values of {@link Points#morphTargetDictionary} and {@link Points#morphTargetInfluences} 15285 * to make sure existing morph targets can influence this 3D object. 15286 */ updateMorphTargets() { 15287 const geometry = this.geometry; 15288 const morphAttributes = geometry.morphAttributes; 15289 const keys = Object.keys(morphAttributes); 15290 if (keys.length > 0) { 15291 const morphAttribute = morphAttributes[keys[0]]; 15292 if (morphAttribute !== undefined) { 15293 this.morphTargetInfluences = []; 15294 this.morphTargetDictionary = {}; 15295 for(let m = 0, ml = morphAttribute.length; m < ml; m++){ 15296 const name = morphAttribute[m].name || String(m); 15297 this.morphTargetInfluences.push(0); 15298 this.morphTargetDictionary[name] = m; 15299 } 15300 } 15301 } 15302 } 15303 /** 15304 * Constructs a new point cloud. 15305 * 15306 * @param {BufferGeometry} [geometry] - The points geometry. 15307 * @param {Material|Array<Material>} [material] - The points material. 15308 */ constructor(geometry = new BufferGeometry(), material = new PointsMaterial()){ 15309 super(); 15310 /** 15311 * This flag can be used for type testing. 15312 * 15313 * @type {boolean} 15314 * @readonly 15315 * @default true 15316 */ this.isPoints = true; 15317 this.type = 'Points'; 15318 /** 15319 * The points geometry. 15320 * 15321 * @type {BufferGeometry} 15322 */ this.geometry = geometry; 15323 /** 15324 * The line material. 15325 * 15326 * @type {Material|Array<Material>} 15327 * @default PointsMaterial 15328 */ this.material = material; 15329 /** 15330 * A dictionary representing the morph targets in the geometry. The key is the 15331 * morph targets name, the value its attribute index. This member is `undefined` 15332 * by default and only set when morph targets are detected in the geometry. 15333 * 15334 * @type {Object<String,number>|undefined} 15335 * @default undefined 15336 */ this.morphTargetDictionary = undefined; 15337 /** 15338 * An array of weights typically in the range `[0,1]` that specify how much of the morph 15339 * is applied. This member is `undefined` by default and only set when morph targets are 15340 * detected in the geometry. 15341 * 15342 * @type {Array<number>|undefined} 15343 * @default undefined 15344 */ this.morphTargetInfluences = undefined; 15345 this.updateMorphTargets(); 15346 } 15347 } 15348 function testPoint(point, index, localThresholdSq, matrixWorld, raycaster, intersects, object) { 15349 const rayPointDistanceSq = _ray.distanceSqToPoint(point); 15350 if (rayPointDistanceSq < localThresholdSq) { 15351 const intersectPoint = new Vector3(); 15352 _ray.closestPointToPoint(point, intersectPoint); 15353 intersectPoint.applyMatrix4(matrixWorld); 15354 const distance = raycaster.ray.origin.distanceTo(intersectPoint); 15355 if (distance < raycaster.near || distance > raycaster.far) return; 15356 intersects.push({ 15357 distance: distance, 15358 distanceToRay: Math.sqrt(rayPointDistanceSq), 15359 point: intersectPoint, 15360 index: index, 15361 face: null, 15362 faceIndex: null, 15363 barycoord: null, 15364 object: object 15365 }); 15366 } 15367 } 15368 class VideoTexture extends Texture$1 { 15369 clone() { 15370 return new this.constructor(this.image).copy(this); 15371 } 15372 update() { 15373 const video = this.image; 15374 const hasVideoFrameCallback = 'requestVideoFrameCallback' in video; 15375 if (hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA) { 15376 this.needsUpdate = true; 15377 } 15378 } 15379 constructor(video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy){ 15380 super(video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy); 15381 this.isVideoTexture = true; 15382 this.minFilter = minFilter !== undefined ? minFilter : LinearFilter;
15383 this.magFilter = magFilter !== undefined ? magFilter : LinearFilter; 15384 this.generateMipmaps = false; 15385 const scope = this; 15386 function updateVideo() { 15387 scope.needsUpdate = true; 15388 video.requestVideoFrameCallback(updateVideo); 15389 } 15390 if ('requestVideoFrameCallback' in video) { 15391 video.requestVideoFrameCallback(updateVideo); 15392 } 15393 } 15394 } 15395 class CompressedTexture extends Texture$1 { 15396 constructor(mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, colorSpace){ 15397 super(null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace); 15398 this.isCompressedTexture = true; 15399 this.image = { 15400 width: width, 15401 height: height 15402 }; 15403 this.mipmaps = mipmaps; 15404 // no flipping for cube textures 15405 // (also flipping doesn't work for compressed textures ) 15406 this.flipY = false; 15407 // can't generate mipmaps for compressed textures 15408 // mips must be embedded in DDS files 15409 this.generateMipmaps = false; 15410 } 15411 } 15412 class CompressedArrayTexture extends CompressedTexture { 15413 addLayerUpdate(layerIndex) { 15414 this.layerUpdates.add(layerIndex); 15415 } 15416 clearLayerUpdates() { 15417 this.layerUpdates.clear(); 15418 } 15419 constructor(mipmaps, width, height, depth, format, type){ 15420 super(mipmaps, width, height, format, type); 15421 this.isCompressedArrayTexture = true; 15422 this.image.depth = depth; 15423 this.wrapR = ClampToEdgeWrapping; 15424 this.layerUpdates = new Set(); 15425 } 15426 } 15427 class CompressedCubeTexture extends CompressedTexture { 15428 constructor(images, format, type){ 15429 super(undefined, images[0].width, images[0].height, format, type, CubeReflectionMapping); 15430 this.isCompressedCubeTexture = true; 15431 this.isCubeTexture = true; 15432 this.image = images; 15433 } 15434 } 15435 class CanvasTexture extends Texture$1 { 15436 constructor(canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy){ 15437 super(canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy); 15438 this.isCanvasTexture = true; 15439 this.needsUpdate = true; 15440 } 15441 } 15442 class DepthTexture extends Texture$1 { 15443 copy(source) { 15444 super.copy(source); 15445 this.source = new Source(Object.assign({}, source.image)); // see #30540 15446 this.compareFunction = source.compareFunction; 15447 return this; 15448 } 15449 toJSON(meta) { 15450 const data = super.toJSON(meta); 15451 if (this.compareFunction !== null) data.compareFunction = this.compareFunction; 15452 return data; 15453 } 15454 constructor(width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format = DepthFormat){ 15455 if (format !== DepthFormat && format !== DepthStencilFormat) { 15456 throw new Error('DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat'); 15457 } 15458 if (type === undefined && format === DepthFormat) type = UnsignedIntType; 15459 if (type === undefined && format === DepthStencilFormat) type = UnsignedInt248Type; 15460 super(null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy); 15461 this.isDepthTexture = true; 15462 this.image = { 15463 width: width, 15464 height: height 15465 }; 15466 this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; 15467 this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; 15468 this.flipY = false; 15469 this.generateMipmaps = false; 15470 this.compareFunction = null; 15471 } 15472 } 15473 /** 15474 * A geometry class for representing a plane. 15475 * 15476 * ```js 15477 * const geometry = new THREE.PlaneGeometry( 1, 1 ); 15478 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00, side: THREE.DoubleSide } ); 15479 * const plane = new THREE.Mesh( geometry, material ); 15480 * scene.add( plane ); 15481 * ``` 15482 * 15483 * @augments BufferGeometry 15484 */ class PlaneGeometry extends BufferGeometry { 15485 copy(source) { 15486 super.copy(source); 15487 this.parameters = Object.assign({}, source.parameters); 15488 return this; 15489 } 15490 /** 15491 * Factory method for creating an instance of this class from the given 15492 * JSON object. 15493 * 15494 * @param {Object} data - A JSON object representing the serialized geometry. 15495 * @return {PlaneGeometry} A new instance. 15496 */ static fromJSON(data) { 15497 return new PlaneGeometry(data.width, data.height, data.widthSegments, data.heightSegments); 15498 } 15499 /** 15500 * Constructs a new plane geometry. 15501 * 15502 * @param {number} [width=1] - The width along the X axis. 15503 * @param {number} [height=1] - The height along the Y axis 15504 * @param {number} [widthSegments=1] - The number of segments along the X axis. 15505 * @param {number} [heightSegments=1] - The number of segments along the Y axis. 15506 */ constructor(width = 1, height = 1, widthSegments = 1, heightSegments = 1){ 15507 super(); 15508 this.type = 'PlaneGeometry'; 15509 /** 15510 * Holds the constructor parameters that have been 15511 * used to generate the geometry. Any modification 15512 * after instantiation does not change the geometry. 15513 * 15514 * @type {Object} 15515 */ this.parameters = { 15516 width: width, 15517 height: height, 15518 widthSegments: widthSegments, 15519 heightSegments: heightSegments 15520 }; 15521 const width_half = width / 2; 15522 const height_half = height / 2;
vendor: 15,458 bytes, lines 15523-15923
15523 const gridX = Math.floor(widthSegments); 15524 const gridY = Math.floor(heightSegments); 15525 const gridX1 = gridX + 1; 15526 const gridY1 = gridY + 1; 15527 const segment_width = width / gridX; 15528 const segment_height = height / gridY; 15529 // 15530 const indices = []; 15531 const vertices = []; 15532 const normals = []; 15533 const uvs = []; 15534 for(let iy = 0; iy < gridY1; iy++){ 15535 const y = iy * segment_height - height_half; 15536 for(let ix = 0; ix < gridX1; ix++){ 15537 const x = ix * segment_width - width_half; 15538 vertices.push(x, -y, 0); 15539 normals.push(0, 0, 1); 15540 uvs.push(ix / gridX); 15541 uvs.push(1 - iy / gridY); 15542 } 15543 } 15544 for(let iy = 0; iy < gridY; iy++){ 15545 for(let ix = 0; ix < gridX; ix++){ 15546 const a = ix + gridX1 * iy; 15547 const b = ix + gridX1 * (iy + 1); 15548 const c = ix + 1 + gridX1 * (iy + 1); 15549 const d = ix + 1 + gridX1 * iy; 15550 indices.push(a, b, d); 15551 indices.push(b, c, d); 15552 } 15553 } 15554 this.setIndex(indices); 15555 this.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 15556 this.setAttribute('normal', new Float32BufferAttribute(normals, 3)); 15557 this.setAttribute('uv', new Float32BufferAttribute(uvs, 2)); 15558 } 15559 } 15560 /** 15561 * A class for generating a sphere geometry. 15562 * 15563 * ```js 15564 * const geometry = new THREE.SphereGeometry( 15, 32, 16 ); 15565 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); 15566 * const sphere = new THREE.Mesh( geometry, material ); 15567 * scene.add( sphere ); 15568 * ``` 15569 * 15570 * @augments BufferGeometry 15571 */ class SphereGeometry extends BufferGeometry { 15572 copy(source) { 15573 super.copy(source); 15574 this.parameters = Object.assign({}, source.parameters); 15575 return this; 15576 } 15577 /** 15578 * Factory method for creating an instance of this class from the given 15579 * JSON object. 15580 * 15581 * @param {Object} data - A JSON object representing the serialized geometry. 15582 * @return {SphereGeometry} A new instance. 15583 */ static fromJSON(data) { 15584 return new SphereGeometry(data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength); 15585 } 15586 /** 15587 * Constructs a new sphere geometry. 15588 * 15589 * @param {number} [radius=1] - The sphere radius. 15590 * @param {number} [widthSegments=32] - The number of horizontal segments. Minimum value is `3`. 15591 * @param {number} [heightSegments=16] - The number of vertical segments. Minimum value is `2`. 15592 * @param {number} [phiStart=0] - The horizontal starting angle in radians. 15593 * @param {number} [phiLength=Math.PI*2] - The horizontal sweep angle size. 15594 * @param {number} [thetaStart=0] - The vertical starting angle in radians. 15595 * @param {number} [thetaLength=Math.PI] - The vertical sweep angle size. 15596 */ constructor(radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI){ 15597 super(); 15598 this.type = 'SphereGeometry'; 15599 /** 15600 * Holds the constructor parameters that have been 15601 * used to generate the geometry. Any modification 15602 * after instantiation does not change the geometry. 15603 * 15604 * @type {Object} 15605 */ this.parameters = { 15606 radius: radius, 15607 widthSegments: widthSegments, 15608 heightSegments: heightSegments, 15609 phiStart: phiStart, 15610 phiLength: phiLength, 15611 thetaStart: thetaStart, 15612 thetaLength: thetaLength 15613 }; 15614 widthSegments = Math.max(3, Math.floor(widthSegments)); 15615 heightSegments = Math.max(2, Math.floor(heightSegments)); 15616 const thetaEnd = Math.min(thetaStart + thetaLength, Math.PI); 15617 let index = 0; 15618 const grid = []; 15619 const vertex = new Vector3(); 15620 const normal = new Vector3(); 15621 // buffers 15622 const indices = []; 15623 const vertices = []; 15624 const normals = []; 15625 const uvs = []; 15626 // generate vertices, normals and uvs 15627 for(let iy = 0; iy <= heightSegments; iy++){ 15628 const verticesRow = []; 15629 const v = iy / heightSegments; 15630 // special case for the poles 15631 let uOffset = 0; 15632 if (iy === 0 && thetaStart === 0) { 15633 uOffset = 0.5 / widthSegments; 15634 } else if (iy === heightSegments && thetaEnd === Math.PI) { 15635 uOffset = -0.5 / widthSegments; 15636 } 15637 for(let ix = 0; ix <= widthSegments; ix++){ 15638 const u = ix / widthSegments; 15639 // vertex 15640 vertex.x = -radius * Math.cos(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength); 15641 vertex.y = radius * Math.cos(thetaStart + v * thetaLength); 15642 vertex.z = radius * Math.sin(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength); 15643 vertices.push(vertex.x, vertex.y, vertex.z); 15644 // normal 15645 normal.copy(vertex).normalize(); 15646 normals.push(normal.x, normal.y, normal.z); 15647 // uv 15648 uvs.push(u + uOffset, 1 - v); 15649 verticesRow.push(index++); 15650 } 15651 grid.push(verticesRow); 15652 } 15653 // indices 15654 for(let iy = 0; iy < heightSegments; iy++){ 15655 for(let ix = 0; ix < widthSegments; ix++){ 15656 const a = grid[iy][ix + 1]; 15657 const b = grid[iy][ix]; 15658 const c = grid[iy + 1][ix]; 15659 const d = grid[iy + 1][ix + 1]; 15660 if (iy !== 0 || thetaStart > 0) indices.push(a, b, d); 15661 if (iy !== heightSegments - 1 || thetaEnd < Math.PI) indices.push(b, c, d); 15662 } 15663 } 15664 // build geometry 15665 this.setIndex(indices); 15666 this.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 15667 this.setAttribute('normal', new Float32BufferAttribute(normals, 3)); 15668 this.setAttribute('uv', new Float32BufferAttribute(uvs, 2)); 15669 } 15670 } 15671 class MeshStandardMaterial extends Material$1 { 15672 copy(source) { 15673 super.copy(source); 15674 this.defines = { 15675 'STANDARD': '' 15676 }; 15677 this.color.copy(source.color); 15678 this.roughness = source.roughness; 15679 this.metalness = source.metalness; 15680 this.map = source.map; 15681 this.lightMap = source.lightMap; 15682 this.lightMapIntensity = source.lightMapIntensity; 15683 this.aoMap = source.aoMap; 15684 this.aoMapIntensity = source.aoMapIntensity; 15685 this.emissive.copy(source.emissive); 15686 this.emissiveMap = source.emissiveMap; 15687 this.emissiveIntensity = source.emissiveIntensity; 15688 this.bumpMap = source.bumpMap; 15689 this.bumpScale = source.bumpScale; 15690 this.normalMap = source.normalMap; 15691 this.normalMapType = source.normalMapType; 15692 this.normalScale.copy(source.normalScale); 15693 this.displacementMap = source.displacementMap; 15694 this.displacementScale = source.displacementScale; 15695 this.displacementBias = source.displacementBias; 15696 this.roughnessMap = source.roughnessMap; 15697 this.metalnessMap = source.metalnessMap; 15698 this.alphaMap = source.alphaMap; 15699 this.envMap = source.envMap; 15700 this.envMapRotation.copy(source.envMapRotation); 15701 this.envMapIntensity = source.envMapIntensity; 15702 this.wireframe = source.wireframe; 15703 this.wireframeLinewidth = source.wireframeLinewidth; 15704 this.wireframeLinecap = source.wireframeLinecap; 15705 this.wireframeLinejoin = source.wireframeLinejoin; 15706 this.flatShading = source.flatShading; 15707 this.fog = source.fog; 15708 return this; 15709 } 15710 constructor(parameters){ 15711 super(); 15712 this.isMeshStandardMaterial = true; 15713 this.type = 'MeshStandardMaterial'; 15714 this.defines = { 15715 'STANDARD': '' 15716 }; 15717 this.color = new Color(0xffffff); // diffuse 15718 this.roughness = 1.0; 15719 this.metalness = 0.0; 15720 this.map = null; 15721 this.lightMap = null; 15722 this.lightMapIntensity = 1.0; 15723 this.aoMap = null; 15724 this.aoMapIntensity = 1.0; 15725 this.emissive = new Color(0x000000); 15726 this.emissiveIntensity = 1.0; 15727 this.emissiveMap = null; 15728 this.bumpMap = null; 15729 this.bumpScale = 1; 15730 this.normalMap = null; 15731 this.normalMapType = TangentSpaceNormalMap; 15732 this.normalScale = new Vector2(1, 1); 15733 this.displacementMap = null; 15734 this.displacementScale = 1; 15735 this.displacementBias = 0; 15736 this.roughnessMap = null; 15737 this.metalnessMap = null; 15738 this.alphaMap = null; 15739 this.envMap = null; 15740 this.envMapRotation = new Euler(); 15741 this.envMapIntensity = 1.0; 15742 this.wireframe = false; 15743 this.wireframeLinewidth = 1; 15744 this.wireframeLinecap = 'round'; 15745 this.wireframeLinejoin = 'round'; 15746 this.flatShading = false; 15747 this.fog = true; 15748 this.setValues(parameters); 15749 } 15750 } 15751 class MeshPhysicalMaterial extends MeshStandardMaterial { 15752 get anisotropy() { 15753 return this._anisotropy; 15754 } 15755 set anisotropy(value) { 15756 if (this._anisotropy > 0 !== value > 0) { 15757 this.version++; 15758 } 15759 this._anisotropy = value; 15760 } 15761 get clearcoat() { 15762 return this._clearcoat; 15763 } 15764 set clearcoat(value) { 15765 if (this._clearcoat > 0 !== value > 0) { 15766 this.version++; 15767 } 15768 this._clearcoat = value; 15769 } 15770 get iridescence() { 15771 return this._iridescence; 15772 } 15773 set iridescence(value) { 15774 if (this._iridescence > 0 !== value > 0) { 15775 this.version++; 15776 } 15777 this._iridescence = value; 15778 } 15779 get dispersion() { 15780 return this._dispersion; 15781 } 15782 set dispersion(value) { 15783 if (this._dispersion > 0 !== value > 0) { 15784 this.version++; 15785 } 15786 this._dispersion = value; 15787 } 15788 get sheen() { 15789 return this._sheen; 15790 } 15791 set sheen(value) { 15792 if (this._sheen > 0 !== value > 0) { 15793 this.version++; 15794 } 15795 this._sheen = value; 15796 } 15797 get transmission() { 15798 return this._transmission; 15799 } 15800 set transmission(value) { 15801 if (this._transmission > 0 !== value > 0) { 15802 this.version++; 15803 } 15804 this._transmission = value; 15805 } 15806 copy(source) { 15807 super.copy(source); 15808 this.defines = { 15809 'STANDARD': '', 15810 'PHYSICAL': '' 15811 }; 15812 this.anisotropy = source.anisotropy; 15813 this.anisotropyRotation = source.anisotropyRotation; 15814 this.anisotropyMap = source.anisotropyMap; 15815 this.clearcoat = source.clearcoat; 15816 this.clearcoatMap = source.clearcoatMap; 15817 this.clearcoatRoughness = source.clearcoatRoughness; 15818 this.clearcoatRoughnessMap = source.clearcoatRoughnessMap; 15819 this.clearcoatNormalMap = source.clearcoatNormalMap; 15820 this.clearcoatNormalScale.copy(source.clearcoatNormalScale); 15821 this.dispersion = source.dispersion; 15822 this.ior = source.ior; 15823 this.iridescence = source.iridescence; 15824 this.iridescenceMap = source.iridescenceMap; 15825 this.iridescenceIOR = source.iridescenceIOR; 15826 this.iridescenceThicknessRange = [ 15827 ...source.iridescenceThicknessRange 15828 ]; 15829 this.iridescenceThicknessMap = source.iridescenceThicknessMap; 15830 this.sheen = source.sheen; 15831 this.sheenColor.copy(source.sheenColor); 15832 this.sheenColorMap = source.sheenColorMap; 15833 this.sheenRoughness = source.sheenRoughness; 15834 this.sheenRoughnessMap = source.sheenRoughnessMap; 15835 this.transmission = source.transmission; 15836 this.transmissionMap = source.transmissionMap; 15837 this.thickness = source.thickness; 15838 this.thicknessMap = source.thicknessMap; 15839 this.attenuationDistance = source.attenuationDistance; 15840 this.attenuationColor.copy(source.attenuationColor); 15841 this.specularIntensity = source.specularIntensity; 15842 this.specularIntensityMap = source.specularIntensityMap; 15843 this.specularColor.copy(source.specularColor); 15844 this.specularColorMap = source.specularColorMap; 15845 return this; 15846 } 15847 constructor(parameters){ 15848 super(); 15849 this.isMeshPhysicalMaterial = true; 15850 this.defines = { 15851 'STANDARD': '', 15852 'PHYSICAL': '' 15853 }; 15854 this.type = 'MeshPhysicalMaterial'; 15855 this.anisotropyRotation = 0; 15856 this.anisotropyMap = null; 15857 this.clearcoatMap = null; 15858 this.clearcoatRoughness = 0.0; 15859 this.clearcoatRoughnessMap = null; 15860 this.clearcoatNormalScale = new Vector2(1, 1); 15861 this.clearcoatNormalMap = null; 15862 this.ior = 1.5; 15863 Object.defineProperty(this, 'reflectivity', { 15864 get: function() { 15865 return clamp$1(2.5 * (this.ior - 1) / (this.ior + 1), 0, 1); 15866 }, 15867 set: function(reflectivity) { 15868 this.ior = (1 + 0.4 * reflectivity) / (1 - 0.4 * reflectivity); 15869 } 15870 }); 15871 this.iridescenceMap = null; 15872 this.iridescenceIOR = 1.3; 15873 this.iridescenceThicknessRange = [ 15874 100, 15875 400 15876 ]; 15877 this.iridescenceThicknessMap = null; 15878 this.sheenColor = new Color(0x000000); 15879 this.sheenColorMap = null; 15880 this.sheenRoughness = 1.0; 15881 this.sheenRoughnessMap = null; 15882 this.transmissionMap = null; 15883 this.thickness = 0; 15884 this.thicknessMap = null; 15885 this.attenuationDistance = Infinity; 15886 this.attenuationColor = new Color(1, 1, 1); 15887 this.specularIntensity = 1.0; 15888 this.specularIntensityMap = null; 15889 this.specularColor = new Color(1, 1, 1); 15890 this.specularColorMap = null; 15891 this._anisotropy = 0; 15892 this._clearcoat = 0; 15893 this._dispersion = 0; 15894 this._iridescence = 0; 15895 this._sheen = 0.0; 15896 this._transmission = 0; 15897 this.setValues(parameters); 15898 } 15899 } 15900 class MeshDepthMaterial extends Material$1 { 15901 copy(source) { 15902 super.copy(source); 15903 this.depthPacking = source.depthPacking; 15904 this.map = source.map; 15905 this.alphaMap = source.alphaMap; 15906 this.displacementMap = source.displacementMap; 15907 this.displacementScale = source.displacementScale; 15908 this.displacementBias = source.displacementBias; 15909 this.wireframe = source.wireframe; 15910 this.wireframeLinewidth = source.wireframeLinewidth; 15911 return this; 15912 } 15913 constructor(parameters){ 15914 super(); 15915 this.isMeshDepthMaterial = true; 15916 this.type = 'MeshDepthMaterial'; 15917 this.depthPacking = BasicDepthPacking; 15918 this.map = null; 15919 this.alphaMap = null; 15920 this.displacementMap = null; 15921 this.displacementScale = 1; 15922 this.displacementBias = 0; 15923 this.wireframe = false;
15924 this.wireframeLinewidth = 1; 15925 this.setValues(parameters); 15926 } 15927 } 15928 class MeshDistanceMaterial extends Material$1 { 15929 copy(source) { 15930 super.copy(source); 15931 this.map = source.map; 15932 this.alphaMap = source.alphaMap; 15933 this.displacementMap = source.displacementMap; 15934 this.displacementScale = source.displacementScale; 15935 this.displacementBias = source.displacementBias; 15936 return this; 15937 } 15938 constructor(parameters){ 15939 super(); 15940 this.isMeshDistanceMaterial = true; 15941 this.type = 'MeshDistanceMaterial'; 15942 this.map = null; 15943 this.alphaMap = null; 15944 this.displacementMap = null; 15945 this.displacementScale = 1; 15946 this.displacementBias = 0; 15947 this.setValues(parameters); 15948 } 15949 } 15950 // converts an array to a specific type 15951 function convertArray(array, type, forceClone) { 15952 if (!array || // let 'undefined' and 'null' pass 15953 !forceClone && array.constructor === type) return array; 15954 if (typeof type.BYTES_PER_ELEMENT === 'number') { 15955 return new type(array); // create typed array 15956 } 15957 return Array.prototype.slice.call(array); // create Array 15958 } 15959 function isTypedArray(object) { 15960 return ArrayBuffer.isView(object) && !(object instanceof DataView); 15961 } 15962 // returns an array by which times and values can be sorted 15963 function getKeyframeOrder(times) { 15964 function compareTime(i, j) { 15965 return times[i] - times[j]; 15966 } 15967 const n = times.length; 15968 const result = new Array(n);
vendor: 80,912 bytes, lines 15969-18066
15969 for(let i = 0; i !== n; ++i)result[i] = i; 15970 result.sort(compareTime); 15971 return result; 15972 } 15973 // uses the array previously returned by 'getKeyframeOrder' to sort data 15974 function sortedArray(values, stride, order) { 15975 const nValues = values.length; 15976 const result = new values.constructor(nValues); 15977 for(let i = 0, dstOffset = 0; dstOffset !== nValues; ++i){ 15978 const srcOffset = order[i] * stride; 15979 for(let j = 0; j !== stride; ++j){ 15980 result[dstOffset++] = values[srcOffset + j]; 15981 } 15982 } 15983 return result; 15984 } 15985 // function for parsing AOS keyframe formats 15986 function flattenJSON(jsonKeys, times, values, valuePropertyName) { 15987 let i = 1, key = jsonKeys[0]; 15988 while(key !== undefined && key[valuePropertyName] === undefined){ 15989 key = jsonKeys[i++]; 15990 } 15991 if (key === undefined) return; // no data 15992 let value = key[valuePropertyName]; 15993 if (value === undefined) return; // no data 15994 if (Array.isArray(value)) { 15995 do { 15996 value = key[valuePropertyName]; 15997 if (value !== undefined) { 15998 times.push(key.time); 15999 values.push(...value); // push all elements 16000 } 16001 key = jsonKeys[i++]; 16002 }while (key !== undefined) 16003 } else if (value.toArray !== undefined) { 16004 // ...assume THREE.Math-ish 16005 do { 16006 value = key[valuePropertyName]; 16007 if (value !== undefined) { 16008 times.push(key.time); 16009 value.toArray(values, values.length); 16010 } 16011 key = jsonKeys[i++]; 16012 }while (key !== undefined) 16013 } else { 16014 // otherwise push as-is 16015 do { 16016 value = key[valuePropertyName]; 16017 if (value !== undefined) { 16018 times.push(key.time); 16019 values.push(value); 16020 } 16021 key = jsonKeys[i++]; 16022 }while (key !== undefined) 16023 } 16024 } 16025 /** 16026 * Abstract base class of interpolants over parametric samples. 16027 * 16028 * The parameter domain is one dimensional, typically the time or a path 16029 * along a curve defined by the data. 16030 * 16031 * The sample values can have any dimensionality and derived classes may 16032 * apply special interpretations to the data. 16033 * 16034 * This class provides the interval seek in a Template Method, deferring 16035 * the actual interpolation to derived classes. 16036 * 16037 * Time complexity is O(1) for linear access crossing at most two points 16038 * and O(log N) for random access, where N is the number of positions. 16039 * 16040 * References: {@link http://www.oodesign.com/template-method-pattern.html} 16041 * 16042 * @abstract 16043 */ class Interpolant { 16044 /** 16045 * Evaluate the interpolant at position `t`. 16046 * 16047 * @param {number} t - The interpolation factor. 16048 * @return {TypedArray} The result buffer. 16049 */ evaluate(t) { 16050 const pp = this.parameterPositions; 16051 let i1 = this._cachedIndex, t1 = pp[i1], t0 = pp[i1 - 1]; 16052 validate_interval: { 16053 seek: { 16054 let right; 16055 linear_scan: { 16056 //- See http://jsperf.com/comparison-to-undefined/3 16057 //- slower code: 16058 //- 16059 //- if ( t >= t1 || t1 === undefined ) { 16060 forward_scan: if (!(t < t1)) { 16061 for(let giveUpAt = i1 + 2;;){ 16062 if (t1 === undefined) { 16063 if (t < t0) break forward_scan; 16064 // after end 16065 i1 = pp.length; 16066 this._cachedIndex = i1; 16067 return this.copySampleValue_(i1 - 1); 16068 } 16069 if (i1 === giveUpAt) break; // this loop 16070 t0 = t1; 16071 t1 = pp[++i1]; 16072 if (t < t1) { 16073 break seek; 16074 } 16075 } 16076 // prepare binary search on the right side of the index 16077 right = pp.length; 16078 break linear_scan; 16079 } 16080 //- slower code: 16081 //- if ( t < t0 || t0 === undefined ) { 16082 if (!(t >= t0)) { 16083 // looping? 16084 const t1global = pp[1]; 16085 if (t < t1global) { 16086 i1 = 2; // + 1, using the scan for the details 16087 t0 = t1global; 16088 } 16089 // linear reverse scan 16090 for(let giveUpAt = i1 - 2;;){ 16091 if (t0 === undefined) { 16092 // before start 16093 this._cachedIndex = 0; 16094 return this.copySampleValue_(0); 16095 } 16096 if (i1 === giveUpAt) break; // this loop 16097 t1 = t0; 16098 t0 = pp[--i1 - 1]; 16099 if (t >= t0) { 16100 break seek; 16101 } 16102 } 16103 // prepare binary search on the left side of the index 16104 right = i1; 16105 i1 = 0; 16106 break linear_scan; 16107 } 16108 break validate_interval; 16109 } // linear scan 16110 // binary search 16111 while(i1 < right){ 16112 const mid = i1 + right >>> 1; 16113 if (t < pp[mid]) { 16114 right = mid; 16115 } else { 16116 i1 = mid + 1; 16117 } 16118 } 16119 t1 = pp[i1]; 16120 t0 = pp[i1 - 1]; 16121 // check boundary cases, again 16122 if (t0 === undefined) { 16123 this._cachedIndex = 0; 16124 return this.copySampleValue_(0); 16125 } 16126 if (t1 === undefined) { 16127 i1 = pp.length; 16128 this._cachedIndex = i1; 16129 return this.copySampleValue_(i1 - 1); 16130 } 16131 } // seek 16132 this._cachedIndex = i1; 16133 this.intervalChanged_(i1, t0, t1); 16134 } // validate_interval 16135 return this.interpolate_(i1, t0, t, t1); 16136 } 16137 /** 16138 * Returns the interpolation settings. 16139 * 16140 * @return {Object} The interpolation settings. 16141 */ getSettings_() { 16142 return this.settings || this.DefaultSettings_; 16143 } 16144 /** 16145 * Copies a sample value to the result buffer. 16146 * 16147 * @param {number} index - An index into the sample value buffer. 16148 * @return {TypedArray} The result buffer. 16149 */ copySampleValue_(index) { 16150 // copies a sample value to the result buffer 16151 const result = this.resultBuffer, values = this.sampleValues, stride = this.valueSize, offset = index * stride; 16152 for(let i = 0; i !== stride; ++i){ 16153 result[i] = values[offset + i]; 16154 } 16155 return result; 16156 } 16157 /** 16158 * Copies a sample value to the result buffer. 16159 * 16160 * @abstract 16161 * @param {number} i1 - An index into the sample value buffer. 16162 * @param {number} t0 - The previous interpolation factor. 16163 * @param {number} t - The current interpolation factor. 16164 * @param {number} t1 - The next interpolation factor. 16165 * @return {TypedArray} The result buffer. 16166 */ interpolate_() { 16167 throw new Error('call to abstract method'); 16168 // implementations shall return this.resultBuffer 16169 } 16170 /** 16171 * Optional method that is executed when the interval has changed. 16172 * 16173 * @param {number} i1 - An index into the sample value buffer. 16174 * @param {number} t0 - The previous interpolation factor. 16175 * @param {number} t - The current interpolation factor. 16176 */ intervalChanged_() { 16177 // empty 16178 } 16179 /** 16180 * Constructs a new interpolant. 16181 * 16182 * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors. 16183 * @param {TypedArray} sampleValues - The sample values. 16184 * @param {number} sampleSize - The sample size 16185 * @param {TypedArray} [resultBuffer] - The result buffer. 16186 */ constructor(parameterPositions, sampleValues, sampleSize, resultBuffer){ 16187 /** 16188 * The parameter positions. 16189 * 16190 * @type {TypedArray} 16191 */ this.parameterPositions = parameterPositions; 16192 /** 16193 * A cache index. 16194 * 16195 * @private 16196 * @type {number} 16197 * @default 0 16198 */ this._cachedIndex = 0; 16199 /** 16200 * The result buffer. 16201 * 16202 * @type {TypedArray} 16203 */ this.resultBuffer = resultBuffer !== undefined ? resultBuffer : new sampleValues.constructor(sampleSize); 16204 /** 16205 * The sample values. 16206 * 16207 * @type {TypedArray} 16208 */ this.sampleValues = sampleValues; 16209 /** 16210 * The value size. 16211 * 16212 * @type {TypedArray} 16213 */ this.valueSize = sampleSize; 16214 /** 16215 * The interpolation settings. 16216 * 16217 * @type {?Object} 16218 * @default null 16219 */ this.settings = null; 16220 /** 16221 * The default settings object. 16222 * 16223 * @type {Object} 16224 */ this.DefaultSettings_ = {}; 16225 } 16226 } 16227 /** 16228 * Fast and simple cubic spline interpolant. 16229 * 16230 * It was derived from a Hermitian construction setting the first derivative 16231 * at each sample position to the linear slope between neighboring positions 16232 * over their parameter interval. 16233 * 16234 * @augments Interpolant 16235 */ class CubicInterpolant extends Interpolant { 16236 intervalChanged_(i1, t0, t1) { 16237 const pp = this.parameterPositions; 16238 let iPrev = i1 - 2, iNext = i1 + 1, tPrev = pp[iPrev], tNext = pp[iNext]; 16239 if (tPrev === undefined) { 16240 switch(this.getSettings_().endingStart){ 16241 case ZeroSlopeEnding: 16242 // f'(t0) = 0 16243 iPrev = i1; 16244 tPrev = 2 * t0 - t1; 16245 break; 16246 case WrapAroundEnding: 16247 // use the other end of the curve 16248 iPrev = pp.length - 2; 16249 tPrev = t0 + pp[iPrev] - pp[iPrev + 1]; 16250 break; 16251 default: 16252 // f''(t0) = 0 a.k.a. Natural Spline 16253 iPrev = i1; 16254 tPrev = t1; 16255 } 16256 } 16257 if (tNext === undefined) { 16258 switch(this.getSettings_().endingEnd){ 16259 case ZeroSlopeEnding: 16260 // f'(tN) = 0 16261 iNext = i1; 16262 tNext = 2 * t1 - t0; 16263 break; 16264 case WrapAroundEnding: 16265 // use the other end of the curve 16266 iNext = 1; 16267 tNext = t1 + pp[1] - pp[0]; 16268 break; 16269 default: 16270 // f''(tN) = 0, a.k.a. Natural Spline 16271 iNext = i1 - 1; 16272 tNext = t0; 16273 } 16274 } 16275 const halfDt = (t1 - t0) * 0.5, stride = this.valueSize; 16276 this._weightPrev = halfDt / (t0 - tPrev); 16277 this._weightNext = halfDt / (tNext - t1); 16278 this._offsetPrev = iPrev * stride; 16279 this._offsetNext = iNext * stride; 16280 } 16281 interpolate_(i1, t0, t, t1) { 16282 const result = this.resultBuffer, values = this.sampleValues, stride = this.valueSize, o1 = i1 * stride, o0 = o1 - stride, oP = this._offsetPrev, oN = this._offsetNext, wP = this._weightPrev, wN = this._weightNext, p = (t - t0) / (t1 - t0), pp = p * p, ppp = pp * p; 16283 // evaluate polynomials 16284 const sP = -wP * ppp + 2 * wP * pp - wP * p; 16285 const s0 = (1 + wP) * ppp + (-1.5 - 2 * wP) * pp + (-0.5 + wP) * p + 1; 16286 const s1 = (-1 - wN) * ppp + (1.5 + wN) * pp + 0.5 * p; 16287 const sN = wN * ppp - wN * pp; 16288 // combine data linearly 16289 for(let i = 0; i !== stride; ++i){ 16290 result[i] = sP * values[oP + i] + s0 * values[o0 + i] + s1 * values[o1 + i] + sN * values[oN + i]; 16291 } 16292 return result; 16293 } 16294 /** 16295 * Constructs a new cubic interpolant. 16296 * 16297 * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors. 16298 * @param {TypedArray} sampleValues - The sample values. 16299 * @param {number} sampleSize - The sample size 16300 * @param {TypedArray} [resultBuffer] - The result buffer. 16301 */ constructor(parameterPositions, sampleValues, sampleSize, resultBuffer){ 16302 super(parameterPositions, sampleValues, sampleSize, resultBuffer); 16303 this._weightPrev = -0; 16304 this._offsetPrev = -0; 16305 this._weightNext = -0; 16306 this._offsetNext = -0; 16307 this.DefaultSettings_ = { 16308 endingStart: ZeroCurvatureEnding, 16309 endingEnd: ZeroCurvatureEnding 16310 }; 16311 } 16312 } 16313 /** 16314 * A basic linear interpolant. 16315 * 16316 * @augments Interpolant 16317 */ class LinearInterpolant extends Interpolant { 16318 interpolate_(i1, t0, t, t1) { 16319 const result = this.resultBuffer, values = this.sampleValues, stride = this.valueSize, offset1 = i1 * stride, offset0 = offset1 - stride, weight1 = (t - t0) / (t1 - t0), weight0 = 1 - weight1; 16320 for(let i = 0; i !== stride; ++i){ 16321 result[i] = values[offset0 + i] * weight0 + values[offset1 + i] * weight1; 16322 } 16323 return result; 16324 } 16325 /** 16326 * Constructs a new linear interpolant. 16327 * 16328 * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors. 16329 * @param {TypedArray} sampleValues - The sample values. 16330 * @param {number} sampleSize - The sample size 16331 * @param {TypedArray} [resultBuffer] - The result buffer. 16332 */ constructor(parameterPositions, sampleValues, sampleSize, resultBuffer){ 16333 super(parameterPositions, sampleValues, sampleSize, resultBuffer); 16334 } 16335 } 16336 /** 16337 * Interpolant that evaluates to the sample value at the position preceding 16338 * the parameter. 16339 * 16340 * @augments Interpolant 16341 */ class DiscreteInterpolant extends Interpolant { 16342 interpolate_(i1 /*, t0, t, t1 */ ) { 16343 return this.copySampleValue_(i1 - 1); 16344 } 16345 /** 16346 * Constructs a new discrete interpolant. 16347 * 16348 * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors. 16349 * @param {TypedArray} sampleValues - The sample values. 16350 * @param {number} sampleSize - The sample size 16351 * @param {TypedArray} [resultBuffer] - The result buffer. 16352 */ constructor(parameterPositions, sampleValues, sampleSize, resultBuffer){ 16353 super(parameterPositions, sampleValues, sampleSize, resultBuffer); 16354 } 16355 } 16356 class KeyframeTrack { 16357 // Serialization (in static context, because of constructor invocation 16358 // and automatic invocation of .toJSON): 16359 static toJSON(track) { 16360 const trackType = track.constructor; 16361 let json; 16362 // derived classes can define a static toJSON method 16363 if (trackType.toJSON !== this.toJSON) { 16364 json = trackType.toJSON(track); 16365 } else { 16366 // by default, we assume the data can be serialized as-is 16367 json = { 16368 'name': track.name, 16369 'times': convertArray(track.times, Array), 16370 'values': convertArray(track.values, Array) 16371 }; 16372 const interpolation = track.getInterpolation(); 16373 if (interpolation !== track.DefaultInterpolation) { 16374 json.interpolation = interpolation; 16375 } 16376 } 16377 json.type = track.ValueTypeName; // mandatory 16378 return json; 16379 } 16380 InterpolantFactoryMethodDiscrete(result) { 16381 return new DiscreteInterpolant(this.times, this.values, this.getValueSize(), result); 16382 } 16383 InterpolantFactoryMethodLinear(result) { 16384 return new LinearInterpolant(this.times, this.values, this.getValueSize(), result); 16385 } 16386 InterpolantFactoryMethodSmooth(result) { 16387 return new CubicInterpolant(this.times, this.values, this.getValueSize(), result); 16388 } 16389 setInterpolation(interpolation) { 16390 let factoryMethod; 16391 switch(interpolation){ 16392 case InterpolateDiscrete: 16393 factoryMethod = this.InterpolantFactoryMethodDiscrete; 16394 break; 16395 case InterpolateLinear: 16396 factoryMethod = this.InterpolantFactoryMethodLinear; 16397 break; 16398 case InterpolateSmooth: 16399 factoryMethod = this.InterpolantFactoryMethodSmooth; 16400 break; 16401 } 16402 if (factoryMethod === undefined) { 16403 const message = 'unsupported interpolation for ' + this.ValueTypeName + ' keyframe track named ' + this.name; 16404 if (this.createInterpolant === undefined) { 16405 // fall back to default, unless the default itself is messed up 16406 if (interpolation !== this.DefaultInterpolation) { 16407 this.setInterpolation(this.DefaultInterpolation); 16408 } else { 16409 throw new Error(message); // fatal, in this case 16410 } 16411 } 16412 console.warn('THREE.KeyframeTrack:', message); 16413 return this; 16414 } 16415 this.createInterpolant = factoryMethod; 16416 return this; 16417 } 16418 getInterpolation() { 16419 switch(this.createInterpolant){ 16420 case this.InterpolantFactoryMethodDiscrete: 16421 return InterpolateDiscrete; 16422 case this.InterpolantFactoryMethodLinear: 16423 return InterpolateLinear; 16424 case this.InterpolantFactoryMethodSmooth: 16425 return InterpolateSmooth; 16426 } 16427 } 16428 getValueSize() { 16429 return this.values.length / this.times.length; 16430 } 16431 // move all keyframes either forwards or backwards in time 16432 shift(timeOffset) { 16433 if (timeOffset !== 0.0) { 16434 const times = this.times; 16435 for(let i = 0, n = times.length; i !== n; ++i){ 16436 times[i] += timeOffset; 16437 } 16438 } 16439 return this; 16440 } 16441 // scale all keyframe times by a factor (useful for frame <-> seconds conversions) 16442 scale(timeScale) { 16443 if (timeScale !== 1.0) { 16444 const times = this.times; 16445 for(let i = 0, n = times.length; i !== n; ++i){ 16446 times[i] *= timeScale; 16447 } 16448 } 16449 return this; 16450 } 16451 // removes keyframes before and after animation without changing any values within the range [startTime, endTime]. 16452 // IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values 16453 trim(startTime, endTime) { 16454 const times = this.times, nKeys = times.length; 16455 let from = 0, to = nKeys - 1; 16456 while(from !== nKeys && times[from] < startTime){ 16457 ++from; 16458 } 16459 while(to !== -1 && times[to] > endTime){ 16460 --to; 16461 } 16462 ++to; // inclusive -> exclusive bound 16463 if (from !== 0 || to !== nKeys) { 16464 // empty tracks are forbidden, so keep at least one keyframe 16465 if (from >= to) { 16466 to = Math.max(to, 1); 16467 from = to - 1; 16468 } 16469 const stride = this.getValueSize(); 16470 this.times = times.slice(from, to); 16471 this.values = this.values.slice(from * stride, to * stride); 16472 } 16473 return this; 16474 } 16475 // ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable 16476 validate() { 16477 let valid = true; 16478 const valueSize = this.getValueSize(); 16479 if (valueSize - Math.floor(valueSize) !== 0) { 16480 console.error('THREE.KeyframeTrack: Invalid value size in track.', this); 16481 valid = false; 16482 } 16483 const times = this.times, values = this.values, nKeys = times.length; 16484 if (nKeys === 0) { 16485 console.error('THREE.KeyframeTrack: Track is empty.', this); 16486 valid = false; 16487 } 16488 let prevTime = null; 16489 for(let i = 0; i !== nKeys; i++){ 16490 const currTime = times[i]; 16491 if (typeof currTime === 'number' && isNaN(currTime)) { 16492 console.error('THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime); 16493 valid = false; 16494 break; 16495 } 16496 if (prevTime !== null && prevTime > currTime) { 16497 console.error('THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime); 16498 valid = false; 16499 break; 16500 } 16501 prevTime = currTime; 16502 } 16503 if (values !== undefined) { 16504 if (isTypedArray(values)) { 16505 for(let i = 0, n = values.length; i !== n; ++i){ 16506 const value = values[i]; 16507 if (isNaN(value)) { 16508 console.error('THREE.KeyframeTrack: Value is not a valid number.', this, i, value); 16509 valid = false; 16510 break; 16511 } 16512 } 16513 } 16514 } 16515 return valid; 16516 } 16517 // removes equivalent sequential keys as common in morph target sequences 16518 // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) 16519 optimize() { 16520 // times or values may be shared with other tracks, so overwriting is unsafe 16521 const times = this.times.slice(), values = this.values.slice(), stride = this.getValueSize(), smoothInterpolation = this.getInterpolation() === InterpolateSmooth, lastIndex = times.length - 1; 16522 let writeIndex = 1; 16523 for(let i = 1; i < lastIndex; ++i){ 16524 let keep = false; 16525 const time = times[i]; 16526 const timeNext = times[i + 1]; 16527 // remove adjacent keyframes scheduled at the same time 16528 if (time !== timeNext && (i !== 1 || time !== times[0])) { 16529 if (!smoothInterpolation) { 16530 // remove unnecessary keyframes same as their neighbors 16531 const offset = i * stride, offsetP = offset - stride, offsetN = offset + stride; 16532 for(let j = 0; j !== stride; ++j){ 16533 const value = values[offset + j]; 16534 if (value !== values[offsetP + j] || value !== values[offsetN + j]) { 16535 keep = true; 16536 break; 16537 } 16538 } 16539 } else { 16540 keep = true; 16541 } 16542 } 16543 // in-place compaction 16544 if (keep) { 16545 if (i !== writeIndex) { 16546 times[writeIndex] = times[i]; 16547 const readOffset = i * stride, writeOffset = writeIndex * stride; 16548 for(let j = 0; j !== stride; ++j){ 16549 values[writeOffset + j] = values[readOffset + j]; 16550 } 16551 } 16552 ++writeIndex; 16553 } 16554 } 16555 // flush last keyframe (compaction looks ahead) 16556 if (lastIndex > 0) { 16557 times[writeIndex] = times[lastIndex]; 16558 for(let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++j){ 16559 values[writeOffset + j] = values[readOffset + j]; 16560 } 16561 ++writeIndex; 16562 } 16563 if (writeIndex !== times.length) { 16564 this.times = times.slice(0, writeIndex); 16565 this.values = values.slice(0, writeIndex * stride); 16566 } else { 16567 this.times = times; 16568 this.values = values; 16569 } 16570 return this; 16571 } 16572 clone() { 16573 const times = this.times.slice(); 16574 const values = this.values.slice(); 16575 const TypedKeyframeTrack = this.constructor; 16576 const track = new TypedKeyframeTrack(this.name, times, values); 16577 // Interpolant argument to constructor is not saved, so copy the factory method directly. 16578 track.createInterpolant = this.createInterpolant; 16579 return track; 16580 } 16581 constructor(name, times, values, interpolation){ 16582 if (name === undefined) throw new Error('THREE.KeyframeTrack: track name is undefined'); 16583 if (times === undefined || times.length === 0) throw new Error('THREE.KeyframeTrack: no keyframes in track named ' + name); 16584 this.name = name; 16585 this.times = convertArray(times, this.TimeBufferType); 16586 this.values = convertArray(values, this.ValueBufferType); 16587 this.setInterpolation(interpolation || this.DefaultInterpolation); 16588 } 16589 } 16590 KeyframeTrack.prototype.TimeBufferType = Float32Array; 16591 KeyframeTrack.prototype.ValueBufferType = Float32Array; 16592 KeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear; 16593 /** 16594 * A Track of Boolean keyframe values. 16595 */ class BooleanKeyframeTrack extends KeyframeTrack { 16596 // No interpolation parameter because only InterpolateDiscrete is valid. 16597 constructor(name, times, values){ 16598 super(name, times, values); 16599 } 16600 } 16601 BooleanKeyframeTrack.prototype.ValueTypeName = 'bool'; 16602 BooleanKeyframeTrack.prototype.ValueBufferType = Array; 16603 BooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; 16604 BooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; 16605 BooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; 16606 /** 16607 * A Track of keyframe values that represent color. 16608 */ class ColorKeyframeTrack extends KeyframeTrack { 16609 } 16610 ColorKeyframeTrack.prototype.ValueTypeName = 'color'; 16611 /** 16612 * A Track of numeric keyframe values. 16613 */ class NumberKeyframeTrack extends KeyframeTrack { 16614 } 16615 NumberKeyframeTrack.prototype.ValueTypeName = 'number'; 16616 /** 16617 * Spherical linear unit quaternion interpolant. 16618 * 16619 * @augments Interpolant 16620 */ class QuaternionLinearInterpolant extends Interpolant { 16621 interpolate_(i1, t0, t, t1) { 16622 const result = this.resultBuffer, values = this.sampleValues, stride = this.valueSize, alpha = (t - t0) / (t1 - t0); 16623 let offset = i1 * stride; 16624 for(let end = offset + stride; offset !== end; offset += 4){ 16625 Quaternion.slerpFlat(result, 0, values, offset - stride, values, offset, alpha); 16626 } 16627 return result; 16628 } 16629 /** 16630 * Constructs a new SLERP interpolant. 16631 * 16632 * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors. 16633 * @param {TypedArray} sampleValues - The sample values. 16634 * @param {number} sampleSize - The sample size 16635 * @param {TypedArray} [resultBuffer] - The result buffer. 16636 */ constructor(parameterPositions, sampleValues, sampleSize, resultBuffer){ 16637 super(parameterPositions, sampleValues, sampleSize, resultBuffer); 16638 } 16639 } 16640 /** 16641 * A Track of quaternion keyframe values. 16642 */ class QuaternionKeyframeTrack extends KeyframeTrack { 16643 InterpolantFactoryMethodLinear(result) { 16644 return new QuaternionLinearInterpolant(this.times, this.values, this.getValueSize(), result); 16645 } 16646 } 16647 QuaternionKeyframeTrack.prototype.ValueTypeName = 'quaternion'; 16648 // ValueBufferType is inherited 16649 // DefaultInterpolation is inherited; 16650 QuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; 16651 /** 16652 * A Track that interpolates Strings 16653 */ class StringKeyframeTrack extends KeyframeTrack { 16654 // No interpolation parameter because only InterpolateDiscrete is valid. 16655 constructor(name, times, values){ 16656 super(name, times, values); 16657 } 16658 } 16659 StringKeyframeTrack.prototype.ValueTypeName = 'string'; 16660 StringKeyframeTrack.prototype.ValueBufferType = Array; 16661 StringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; 16662 StringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; 16663 StringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; 16664 /** 16665 * A Track of vectored keyframe values. 16666 */ class VectorKeyframeTrack extends KeyframeTrack { 16667 } 16668 VectorKeyframeTrack.prototype.ValueTypeName = 'vector'; 16669 class AnimationClip { 16670 static parse(json) { 16671 const tracks = [], jsonTracks = json.tracks, frameTime = 1.0 / (json.fps || 1.0); 16672 for(let i = 0, n = jsonTracks.length; i !== n; ++i){ 16673 tracks.push(parseKeyframeTrack(jsonTracks[i]).scale(frameTime)); 16674 } 16675 const clip = new this(json.name, json.duration, tracks, json.blendMode); 16676 clip.uuid = json.uuid; 16677 return clip; 16678 } 16679 static toJSON(clip) { 16680 const tracks = [], clipTracks = clip.tracks; 16681 const json = { 16682 'name': clip.name, 16683 'duration': clip.duration, 16684 'tracks': tracks, 16685 'uuid': clip.uuid, 16686 'blendMode': clip.blendMode 16687 }; 16688 for(let i = 0, n = clipTracks.length; i !== n; ++i){ 16689 tracks.push(KeyframeTrack.toJSON(clipTracks[i])); 16690 } 16691 return json; 16692 } 16693 static CreateFromMorphTargetSequence(name, morphTargetSequence, fps, noLoop) { 16694 const numMorphTargets = morphTargetSequence.length; 16695 const tracks = []; 16696 for(let i = 0; i < numMorphTargets; i++){ 16697 let times = []; 16698 let values = []; 16699 times.push((i + numMorphTargets - 1) % numMorphTargets, i, (i + 1) % numMorphTargets); 16700 values.push(0, 1, 0); 16701 const order = getKeyframeOrder(times); 16702 times = sortedArray(times, 1, order); 16703 values = sortedArray(values, 1, order); 16704 // if there is a key at the first frame, duplicate it as the 16705 // last frame as well for perfect loop. 16706 if (!noLoop && times[0] === 0) { 16707 times.push(numMorphTargets); 16708 values.push(values[0]); 16709 } 16710 tracks.push(new NumberKeyframeTrack('.morphTargetInfluences[' + morphTargetSequence[i].name + ']', times, values).scale(1.0 / fps)); 16711 } 16712 return new this(name, -1, tracks); 16713 } 16714 static findByName(objectOrClipArray, name) { 16715 let clipArray = objectOrClipArray; 16716 if (!Array.isArray(objectOrClipArray)) { 16717 const o = objectOrClipArray; 16718 clipArray = o.geometry && o.geometry.animations || o.animations; 16719 } 16720 for(let i = 0; i < clipArray.length; i++){ 16721 if (clipArray[i].name === name) { 16722 return clipArray[i]; 16723 } 16724 } 16725 return null; 16726 } 16727 static CreateClipsFromMorphTargetSequences(morphTargets, fps, noLoop) { 16728 const animationToMorphTargets = {}; 16729 // tested with https://regex101.com/ on trick sequences 16730 // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 16731 const pattern = /^([\w-]*?)([\d]+)$/; 16732 // sort morph target names into animation groups based 16733 // patterns like Walk_001, Walk_002, Run_001, Run_002 16734 for(let i = 0, il = morphTargets.length; i < il; i++){ 16735 const morphTarget = morphTargets[i]; 16736 const parts = morphTarget.name.match(pattern); 16737 if (parts && parts.length > 1) { 16738 const name = parts[1]; 16739 let animationMorphTargets = animationToMorphTargets[name]; 16740 if (!animationMorphTargets) { 16741 animationToMorphTargets[name] = animationMorphTargets = []; 16742 } 16743 animationMorphTargets.push(morphTarget); 16744 } 16745 } 16746 const clips = []; 16747 for(const name in animationToMorphTargets){ 16748 clips.push(this.CreateFromMorphTargetSequence(name, animationToMorphTargets[name], fps, noLoop)); 16749 } 16750 return clips; 16751 } 16752 // parse the animation.hierarchy format 16753 static parseAnimation(animation, bones) { 16754 if (!animation) { 16755 console.error('THREE.AnimationClip: No animation in JSONLoader data.'); 16756 return null; 16757 } 16758 const addNonemptyTrack = function(trackType, trackName, animationKeys, propertyName, destTracks) { 16759 // only return track if there are actually keys. 16760 if (animationKeys.length !== 0) { 16761 const times = []; 16762 const values = []; 16763 flattenJSON(animationKeys, times, values, propertyName); 16764 // empty keys are filtered out, so check again 16765 if (times.length !== 0) { 16766 destTracks.push(new trackType(trackName, times, values)); 16767 } 16768 } 16769 }; 16770 const tracks = []; 16771 const clipName = animation.name || 'default'; 16772 const fps = animation.fps || 30; 16773 const blendMode = animation.blendMode; 16774 // automatic length determination in AnimationClip. 16775 let duration = animation.length || -1; 16776 const hierarchyTracks = animation.hierarchy || []; 16777 for(let h = 0; h < hierarchyTracks.length; h++){ 16778 const animationKeys = hierarchyTracks[h].keys; 16779 // skip empty tracks 16780 if (!animationKeys || animationKeys.length === 0) continue; 16781 // process morph targets 16782 if (animationKeys[0].morphTargets) { 16783 // figure out all morph targets used in this track 16784 const morphTargetNames = {}; 16785 let k; 16786 for(k = 0; k < animationKeys.length; k++){ 16787 if (animationKeys[k].morphTargets) { 16788 for(let m = 0; m < animationKeys[k].morphTargets.length; m++){ 16789 morphTargetNames[animationKeys[k].morphTargets[m]] = -1; 16790 } 16791 } 16792 } 16793 // create a track for each morph target with all zero 16794 // morphTargetInfluences except for the keys in which 16795 // the morphTarget is named. 16796 for(const morphTargetName in morphTargetNames){ 16797 const times = []; 16798 const values = []; 16799 for(let m = 0; m !== animationKeys[k].morphTargets.length; ++m){ 16800 const animationKey = animationKeys[k]; 16801 times.push(animationKey.time); 16802 values.push(animationKey.morphTarget === morphTargetName ? 1 : 0); 16803 } 16804 tracks.push(new NumberKeyframeTrack('.morphTargetInfluence[' + morphTargetName + ']', times, values)); 16805 } 16806 duration = morphTargetNames.length * fps; 16807 } else { 16808 // ...assume skeletal animation 16809 const boneName = '.bones[' + bones[h].name + ']'; 16810 addNonemptyTrack(VectorKeyframeTrack, boneName + '.position', animationKeys, 'pos', tracks); 16811 addNonemptyTrack(QuaternionKeyframeTrack, boneName + '.quaternion', animationKeys, 'rot', tracks); 16812 addNonemptyTrack(VectorKeyframeTrack, boneName + '.scale', animationKeys, 'scl', tracks); 16813 } 16814 } 16815 if (tracks.length === 0) { 16816 return null; 16817 } 16818 const clip = new this(clipName, duration, tracks, blendMode); 16819 return clip; 16820 } 16821 resetDuration() { 16822 const tracks = this.tracks; 16823 let duration = 0; 16824 for(let i = 0, n = tracks.length; i !== n; ++i){ 16825 const track = this.tracks[i]; 16826 duration = Math.max(duration, track.times[track.times.length - 1]); 16827 } 16828 this.duration = duration; 16829 return this; 16830 } 16831 trim() { 16832 for(let i = 0; i < this.tracks.length; i++){ 16833 this.tracks[i].trim(0, this.duration); 16834 } 16835 return this; 16836 } 16837 validate() { 16838 let valid = true; 16839 for(let i = 0; i < this.tracks.length; i++){ 16840 valid = valid && this.tracks[i].validate(); 16841 } 16842 return valid; 16843 } 16844 optimize() { 16845 for(let i = 0; i < this.tracks.length; i++){ 16846 this.tracks[i].optimize(); 16847 } 16848 return this; 16849 } 16850 clone() { 16851 const tracks = []; 16852 for(let i = 0; i < this.tracks.length; i++){ 16853 tracks.push(this.tracks[i].clone()); 16854 } 16855 return new this.constructor(this.name, this.duration, tracks, this.blendMode); 16856 } 16857 toJSON() { 16858 return this.constructor.toJSON(this); 16859 } 16860 constructor(name = '', duration = -1, tracks = [], blendMode = NormalAnimationBlendMode){ 16861 this.name = name; 16862 this.tracks = tracks; 16863 this.duration = duration; 16864 this.blendMode = blendMode; 16865 this.uuid = generateUUID(); 16866 // this means it should figure out its duration by scanning the tracks 16867 if (this.duration < 0) { 16868 this.resetDuration(); 16869 } 16870 } 16871 } 16872 function getTrackTypeForValueTypeName(typeName) { 16873 switch(typeName.toLowerCase()){ 16874 case 'scalar': 16875 case 'double': 16876 case 'float': 16877 case 'number': 16878 case 'integer': 16879 return NumberKeyframeTrack; 16880 case 'vector': 16881 case 'vector2': 16882 case 'vector3': 16883 case 'vector4': 16884 return VectorKeyframeTrack; 16885 case 'color': 16886 return ColorKeyframeTrack; 16887 case 'quaternion': 16888 return QuaternionKeyframeTrack; 16889 case 'bool': 16890 case 'boolean': 16891 return BooleanKeyframeTrack; 16892 case 'string': 16893 return StringKeyframeTrack; 16894 } 16895 throw new Error('THREE.KeyframeTrack: Unsupported typeName: ' + typeName); 16896 } 16897 function parseKeyframeTrack(json) { 16898 if (json.type === undefined) { 16899 throw new Error('THREE.KeyframeTrack: track type undefined, can not parse'); 16900 } 16901 const trackType = getTrackTypeForValueTypeName(json.type); 16902 if (json.times === undefined) { 16903 const times = [], values = []; 16904 flattenJSON(json.keys, times, values, 'value'); 16905 json.times = times; 16906 json.values = values; 16907 } 16908 // derived classes can define a static parse method 16909 if (trackType.parse !== undefined) { 16910 return trackType.parse(json); 16911 } else { 16912 // by default, we assume a constructor compatible with the base 16913 return new trackType(json.name, json.times, json.values, json.interpolation); 16914 } 16915 } 16916 const Cache = { 16917 enabled: false, 16918 files: {}, 16919 add: function(key, file) { 16920 if (this.enabled === false) return; 16921 // console.log( 'THREE.Cache', 'Adding key:', key ); 16922 this.files[key] = file; 16923 }, 16924 get: function(key) { 16925 if (this.enabled === false) return; 16926 // console.log( 'THREE.Cache', 'Checking key:', key ); 16927 return this.files[key]; 16928 }, 16929 remove: function(key) { 16930 delete this.files[key]; 16931 }, 16932 clear: function() { 16933 this.files = {}; 16934 } 16935 }; 16936 class LoadingManager { 16937 constructor(onLoad, onProgress, onError){ 16938 const scope = this; 16939 let isLoading = false; 16940 let itemsLoaded = 0; 16941 let itemsTotal = 0; 16942 let urlModifier = undefined; 16943 const handlers = []; 16944 // Refer to #5689 for the reason why we don't set .onStart 16945 // in the constructor 16946 this.onStart = undefined; 16947 this.onLoad = onLoad; 16948 this.onProgress = onProgress; 16949 this.onError = onError; 16950 this.itemStart = function(url) { 16951 itemsTotal++; 16952 if (isLoading === false) { 16953 if (scope.onStart !== undefined) { 16954 scope.onStart(url, itemsLoaded, itemsTotal); 16955 } 16956 } 16957 isLoading = true; 16958 }; 16959 this.itemEnd = function(url) { 16960 itemsLoaded++; 16961 if (scope.onProgress !== undefined) { 16962 scope.onProgress(url, itemsLoaded, itemsTotal); 16963 } 16964 if (itemsLoaded === itemsTotal) { 16965 isLoading = false; 16966 if (scope.onLoad !== undefined) { 16967 scope.onLoad(); 16968 } 16969 } 16970 }; 16971 this.itemError = function(url) { 16972 if (scope.onError !== undefined) { 16973 scope.onError(url); 16974 } 16975 }; 16976 this.resolveURL = function(url) { 16977 if (urlModifier) { 16978 return urlModifier(url); 16979 } 16980 return url; 16981 }; 16982 this.setURLModifier = function(transform) { 16983 urlModifier = transform; 16984 return this; 16985 }; 16986 this.addHandler = function(regex, loader) { 16987 handlers.push(regex, loader); 16988 return this; 16989 }; 16990 this.removeHandler = function(regex) { 16991 const index = handlers.indexOf(regex); 16992 if (index !== -1) { 16993 handlers.splice(index, 2); 16994 } 16995 return this; 16996 }; 16997 this.getHandler = function(file) { 16998 for(let i = 0, l = handlers.length; i < l; i += 2){ 16999 const regex = handlers[i]; 17000 const loader = handlers[i + 1]; 17001 if (regex.global) regex.lastIndex = 0; // see #17920 17002 if (regex.test(file)) { 17003 return loader; 17004 } 17005 } 17006 return null; 17007 }; 17008 } 17009 } 17010 const DefaultLoadingManager = /*@__PURE__*/ new LoadingManager(); 17011 /** 17012 * Abstract base class for loaders. 17013 * 17014 * @abstract 17015 */ class Loader { 17016 /** 17017 * This method needs to be implemented by all concrete loaders. It holds the 17018 * logic for loading assets from the backend. 17019 * 17020 * @param {string} url - The path/URL of the file to be loaded. 17021 * @param {Function} onLoad - Executed when the loading process has been finished. 17022 * @param {onProgressCallback} onProgress - Executed while the loading is in progress. 17023 * @param {onErrorCallback} onError - Executed when errors occur. 17024 */ load() {} 17025 /** 17026 * A async version of {@link Loader#load}. 17027 * 17028 * @param {string} url - The path/URL of the file to be loaded. 17029 * @param {onProgressCallback} onProgress - Executed while the loading is in progress. 17030 * @return {Promise} A Promise that resolves when the asset has been loaded. 17031 */ loadAsync(url, onProgress) { 17032 const scope = this; 17033 return new Promise(function(resolve, reject) { 17034 scope.load(url, resolve, onProgress, reject); 17035 }); 17036 } 17037 /** 17038 * This method needs to be implemented by all concrete loaders. It holds the 17039 * logic for parsing the asset into three.js entities. 17040 * 17041 * @param {any} data - The data to parse. 17042 */ parse() {} 17043 /** 17044 * Sets the `crossOrigin` String to implement CORS for loading the URL 17045 * from a different domain that allows CORS. 17046 * 17047 * @param {string} crossOrigin - The `crossOrigin` value. 17048 * @return {Loader} A reference to this instance. 17049 */ setCrossOrigin(crossOrigin) { 17050 this.crossOrigin = crossOrigin; 17051 return this; 17052 } 17053 /** 17054 * Whether the XMLHttpRequest uses credentials such as cookies, authorization 17055 * headers or TLS client certificates, see [XMLHttpRequest.withCredentials]{@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials}. 17056 * 17057 * Note: This setting has no effect if you are loading files locally or from the same domain. 17058 * 17059 * @param {boolean} value - The `withCredentials` value. 17060 * @return {Loader} A reference to this instance. 17061 */ setWithCredentials(value) { 17062 this.withCredentials = value; 17063 return this; 17064 } 17065 /** 17066 * Sets the base path for the asset. 17067 * 17068 * @param {string} path - The base path. 17069 * @return {Loader} A reference to this instance. 17070 */ setPath(path) { 17071 this.path = path; 17072 return this; 17073 } 17074 /** 17075 * Sets the base path for dependent resources like textures. 17076 * 17077 * @param {string} resourcePath - The resource path. 17078 * @return {Loader} A reference to this instance. 17079 */ setResourcePath(resourcePath) { 17080 this.resourcePath = resourcePath; 17081 return this; 17082 } 17083 /** 17084 * Sets the given request header. 17085 * 17086 * @param {Object} requestHeader - A [request header]{@link https://developer.mozilla.org/en-US/docs/Glossary/Request_header} 17087 * for configuring the HTTP request. 17088 * @return {Loader} A reference to this instance. 17089 */ setRequestHeader(requestHeader) { 17090 this.requestHeader = requestHeader; 17091 return this; 17092 } 17093 /** 17094 * Constructs a new loader. 17095 * 17096 * @param {LoadingManager} [manager] - The loading manager. 17097 */ constructor(manager){ 17098 /** 17099 * The loading manager. 17100 * 17101 * @type {LoadingManager} 17102 * @default DefaultLoadingManager 17103 */ this.manager = manager !== undefined ? manager : DefaultLoadingManager; 17104 /** 17105 * The crossOrigin string to implement CORS for loading the url from a 17106 * different domain that allows CORS. 17107 * 17108 * @type {string} 17109 * @default 'anonymous' 17110 */ this.crossOrigin = 'anonymous'; 17111 /** 17112 * Whether the XMLHttpRequest uses credentials. 17113 * 17114 * @type {boolean} 17115 * @default false 17116 */ this.withCredentials = false; 17117 /** 17118 * The base path from which the asset will be loaded. 17119 * 17120 * @type {string} 17121 */ this.path = ''; 17122 /** 17123 * The base path from which additional resources like textures will be loaded. 17124 * 17125 * @type {string} 17126 */ this.resourcePath = ''; 17127 /** 17128 * The [request header]{@link https://developer.mozilla.org/en-US/docs/Glossary/Request_header} 17129 * used in HTTP request. 17130 * 17131 * @type {Object} 17132 */ this.requestHeader = {}; 17133 } 17134 } 17135 /** 17136 * Callback for onProgress in loaders. 17137 * 17138 * 17139 * @callback onProgressCallback 17140 * @param {ProgressEvent} event - An instance of `ProgressEvent` that represents the current loading status. 17141 */ /** 17142 * Callback for onError in loaders. 17143 * 17144 * 17145 * @callback onErrorCallback 17146 * @param {Error} error - The error which occurred during the loading process. 17147 */ /** 17148 * The default material name that is used by loaders 17149 * when creating materials for loaded 3D objects. 17150 * 17151 * Note: Not all loaders might honor this setting. 17152 * 17153 * @static 17154 * @type {string} 17155 * @default '__DEFAULT' 17156 */ Loader.DEFAULT_MATERIAL_NAME = '__DEFAULT'; 17157 const loading = {}; 17158 class HttpError extends Error { 17159 constructor(message, response){ 17160 super(message); 17161 this.response = response; 17162 } 17163 } 17164 class FileLoader extends Loader { 17165 load(url, onLoad, onProgress, onError) { 17166 if (url === undefined) url = ''; 17167 if (this.path !== undefined) url = this.path + url; 17168 url = this.manager.resolveURL(url); 17169 const cached = Cache.get(url); 17170 if (cached !== undefined) { 17171 this.manager.itemStart(url); 17172 setTimeout(()=>{ 17173 if (onLoad) onLoad(cached); 17174 this.manager.itemEnd(url); 17175 }, 0); 17176 return cached; 17177 } 17178 // Check if request is duplicate 17179 if (loading[url] !== undefined) { 17180 loading[url].push({ 17181 onLoad: onLoad, 17182 onProgress: onProgress, 17183 onError: onError 17184 }); 17185 return; 17186 } 17187 // Initialise array for duplicate requests 17188 loading[url] = []; 17189 loading[url].push({ 17190 onLoad: onLoad, 17191 onProgress: onProgress, 17192 onError: onError 17193 }); 17194 // create request 17195 const req = new Request(url, { 17196 headers: new Headers(this.requestHeader), 17197 credentials: this.withCredentials ? 'include' : 'same-origin' 17198 }); 17199 // record states ( avoid data race ) 17200 const mimeType = this.mimeType; 17201 const responseType = this.responseType; 17202 // start the fetch 17203 fetch(req).then((response)=>{ 17204 if (response.status === 200 || response.status === 0) { 17205 // Some browsers return HTTP Status 0 when using non-http protocol 17206 // e.g. 'file://' or 'data://'. Handle as success. 17207 if (response.status === 0) { 17208 console.warn('THREE.FileLoader: HTTP Status 0 received.'); 17209 } 17210 // Workaround: Checking if response.body === undefined for Alipay browser #23548 17211 if (typeof ReadableStream === 'undefined' || response.body === undefined || response.body.getReader === undefined) { 17212 return response; 17213 } 17214 const callbacks = loading[url]; 17215 const reader = response.body.getReader(); 17216 // Nginx needs X-File-Size check 17217 // https://serverfault.com/questions/482875/why-does-nginx-remove-content-length-header-for-chunked-content 17218 const contentLength = response.headers.get('X-File-Size') || response.headers.get('Content-Length'); 17219 const total = contentLength ? parseInt(contentLength) : 0; 17220 const lengthComputable = total !== 0; 17221 let loaded = 0; 17222 // periodically read data into the new stream tracking while download progress 17223 const stream = new ReadableStream({ 17224 start (controller) { 17225 readData(); 17226 function readData() { 17227 reader.read().then(({ done, value })=>{ 17228 if (done) { 17229 controller.close(); 17230 } else { 17231 loaded += value.byteLength; 17232 const event = new ProgressEvent('progress', { 17233 lengthComputable, 17234 loaded, 17235 total 17236 }); 17237 for(let i = 0, il = callbacks.length; i < il; i++){ 17238 const callback = callbacks[i]; 17239 if (callback.onProgress) callback.onProgress(event); 17240 } 17241 controller.enqueue(value); 17242 readData(); 17243 } 17244 }, (e)=>{ 17245 controller.error(e); 17246 }); 17247 } 17248 } 17249 }); 17250 return new Response(stream); 17251 } else { 17252 throw new HttpError(`fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`, response); 17253 } 17254 }).then((response)=>{ 17255 switch(responseType){ 17256 case 'arraybuffer': 17257 return response.arrayBuffer(); 17258 case 'blob': 17259 return response.blob(); 17260 case 'document': 17261 return response.text().then((text)=>{ 17262 const parser = new DOMParser(); 17263 return parser.parseFromString(text, mimeType); 17264 }); 17265 case 'json': 17266 return response.json(); 17267 default: 17268 if (mimeType === undefined) { 17269 return response.text(); 17270 } else { 17271 // sniff encoding 17272 const re = /charset="?([^;"\s]*)"?/i; 17273 const exec = re.exec(mimeType); 17274 const label = exec && exec[1] ? exec[1].toLowerCase() : undefined; 17275 const decoder = new TextDecoder(label); 17276 return response.arrayBuffer().then((ab)=>decoder.decode(ab)); 17277 } 17278 } 17279 }).then((data)=>{ 17280 // Add to cache only on HTTP success, so that we do not cache 17281 // error response bodies as proper responses to requests. 17282 Cache.add(url, data); 17283 const callbacks = loading[url]; 17284 delete loading[url]; 17285 for(let i = 0, il = callbacks.length; i < il; i++){ 17286 const callback = callbacks[i]; 17287 if (callback.onLoad) callback.onLoad(data); 17288 } 17289 }).catch((err)=>{ 17290 // Abort errors and other errors are handled the same 17291 const callbacks = loading[url]; 17292 if (callbacks === undefined) { 17293 // When onLoad was called and url was deleted in `loading` 17294 this.manager.itemError(url); 17295 throw err; 17296 } 17297 delete loading[url]; 17298 for(let i = 0, il = callbacks.length; i < il; i++){ 17299 const callback = callbacks[i]; 17300 if (callback.onError) callback.onError(err); 17301 } 17302 this.manager.itemError(url); 17303 }).finally(()=>{ 17304 this.manager.itemEnd(url); 17305 }); 17306 this.manager.itemStart(url); 17307 } 17308 setResponseType(value) { 17309 this.responseType = value; 17310 return this; 17311 } 17312 setMimeType(value) { 17313 this.mimeType = value; 17314 return this; 17315 } 17316 constructor(manager){ 17317 super(manager); 17318 } 17319 } 17320 class ImageLoader extends Loader { 17321 load(url, onLoad, onProgress, onError) { 17322 if (this.path !== undefined) url = this.path + url; 17323 url = this.manager.resolveURL(url); 17324 const scope = this; 17325 const cached = Cache.get(url); 17326 if (cached !== undefined) { 17327 scope.manager.itemStart(url); 17328 setTimeout(function() { 17329 if (onLoad) onLoad(cached); 17330 scope.manager.itemEnd(url); 17331 }, 0); 17332 return cached; 17333 } 17334 const image = createElementNS('img'); 17335 function onImageLoad() { 17336 removeEventListeners(); 17337 Cache.add(url, this); 17338 if (onLoad) onLoad(this); 17339 scope.manager.itemEnd(url); 17340 } 17341 function onImageError(event) { 17342 removeEventListeners(); 17343 if (onError) onError(event); 17344 scope.manager.itemError(url); 17345 scope.manager.itemEnd(url); 17346 } 17347 function removeEventListeners() { 17348 image.removeEventListener('load', onImageLoad, false); 17349 image.removeEventListener('error', onImageError, false); 17350 } 17351 image.addEventListener('load', onImageLoad, false); 17352 image.addEventListener('error', onImageError, false); 17353 if (url.slice(0, 5) !== 'data:') { 17354 if (this.crossOrigin !== undefined) image.crossOrigin = this.crossOrigin; 17355 } 17356 scope.manager.itemStart(url); 17357 image.src = url; 17358 return image; 17359 } 17360 constructor(manager){ 17361 super(manager); 17362 } 17363 } 17364 /** 17365 * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...) 17366 * 17367 * Sub classes have to implement the parse() method which will be used in load(). 17368 */ class DataTextureLoader extends Loader { 17369 load(url, onLoad, onProgress, onError) { 17370 const scope = this; 17371 const texture = new DataTexture(); 17372 const loader = new FileLoader(this.manager); 17373 loader.setResponseType('arraybuffer'); 17374 loader.setRequestHeader(this.requestHeader); 17375 loader.setPath(this.path); 17376 loader.setWithCredentials(scope.withCredentials); 17377 loader.load(url, function(buffer) { 17378 let texData; 17379 try { 17380 texData = scope.parse(buffer); 17381 } catch (error) { 17382 if (onError !== undefined) { 17383 onError(error); 17384 } else { 17385 console.error(error); 17386 return; 17387 } 17388 } 17389 if (texData.image !== undefined) { 17390 texture.image = texData.image; 17391 } else if (texData.data !== undefined) { 17392 texture.image.width = texData.width; 17393 texture.image.height = texData.height; 17394 texture.image.data = texData.data; 17395 } 17396 texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping; 17397 texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping; 17398 texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter; 17399 texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter; 17400 texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1; 17401 if (texData.colorSpace !== undefined) { 17402 texture.colorSpace = texData.colorSpace; 17403 } 17404 if (texData.flipY !== undefined) { 17405 texture.flipY = texData.flipY; 17406 } 17407 if (texData.format !== undefined) { 17408 texture.format = texData.format; 17409 } 17410 if (texData.type !== undefined) { 17411 texture.type = texData.type; 17412 } 17413 if (texData.mipmaps !== undefined) { 17414 texture.mipmaps = texData.mipmaps; 17415 texture.minFilter = LinearMipmapLinearFilter; // presumably... 17416 } 17417 if (texData.mipmapCount === 1) { 17418 texture.minFilter = LinearFilter; 17419 } 17420 if (texData.generateMipmaps !== undefined) { 17421 texture.generateMipmaps = texData.generateMipmaps; 17422 } 17423 texture.needsUpdate = true; 17424 if (onLoad) onLoad(texture, texData); 17425 }, onProgress, onError); 17426 return texture; 17427 } 17428 constructor(manager){ 17429 super(manager); 17430 } 17431 } 17432 class TextureLoader extends Loader { 17433 load(url, onLoad, onProgress, onError) { 17434 const texture = new Texture$1(); 17435 const loader = new ImageLoader(this.manager); 17436 loader.setCrossOrigin(this.crossOrigin); 17437 loader.setPath(this.path); 17438 loader.load(url, function(image) { 17439 texture.image = image; 17440 texture.needsUpdate = true; 17441 if (onLoad !== undefined) { 17442 onLoad(texture); 17443 } 17444 }, onProgress, onError); 17445 return texture; 17446 } 17447 constructor(manager){ 17448 super(manager); 17449 } 17450 } 17451 /** 17452 * Abstract base class for lights - all other light types inherit the 17453 * properties and methods described here. 17454 * 17455 * @abstract 17456 * @augments Object3D 17457 */ class Light extends Object3D { 17458 /** 17459 * Frees the GPU-related resources allocated by this instance. Call this 17460 * method whenever this instance is no longer used in your app. 17461 */ dispose() { 17462 // Empty here in base class; some subclasses override. 17463 } 17464 copy(source, recursive) { 17465 super.copy(source, recursive); 17466 this.color.copy(source.color); 17467 this.intensity = source.intensity; 17468 return this; 17469 } 17470 toJSON(meta) { 17471 const data = super.toJSON(meta); 17472 data.object.color = this.color.getHex(); 17473 data.object.intensity = this.intensity; 17474 if (this.groundColor !== undefined) data.object.groundColor = this.groundColor.getHex(); 17475 if (this.distance !== undefined) data.object.distance = this.distance; 17476 if (this.angle !== undefined) data.object.angle = this.angle; 17477 if (this.decay !== undefined) data.object.decay = this.decay; 17478 if (this.penumbra !== undefined) data.object.penumbra = this.penumbra; 17479 if (this.shadow !== undefined) data.object.shadow = this.shadow.toJSON(); 17480 if (this.target !== undefined) data.object.target = this.target.uuid; 17481 return data; 17482 } 17483 /** 17484 * Constructs a new light. 17485 * 17486 * @param {(number|Color|string)} [color=0xffffff] - The light's color. 17487 * @param {number} [intensity=1] - The light's strength/intensity. 17488 */ constructor(color, intensity = 1){ 17489 super(); 17490 /** 17491 * This flag can be used for type testing. 17492 * 17493 * @type {boolean} 17494 * @readonly 17495 * @default true 17496 */ this.isLight = true; 17497 this.type = 'Light'; 17498 /** 17499 * The light's color. 17500 * 17501 * @type {Color} 17502 */ this.color = new Color(color); 17503 /** 17504 * The light's intensity. 17505 * 17506 * @type {number} 17507 * @default 1 17508 */ this.intensity = intensity; 17509 } 17510 } 17511 const _projScreenMatrix$1 = /*@__PURE__*/ new Matrix4(); 17512 const _lightPositionWorld$1 = /*@__PURE__*/ new Vector3(); 17513 const _lookTarget$1 = /*@__PURE__*/ new Vector3(); 17514 /** 17515 * Abstract base class for light shadow classes. These classes 17516 * represent the shadow configuration for different ligth types. 17517 * 17518 * @abstract 17519 */ class LightShadow { 17520 /** 17521 * Used internally by the renderer to get the number of viewports that need 17522 * to be rendered for this shadow. 17523 * 17524 * @return {number} The viewport count. 17525 */ getViewportCount() { 17526 return this._viewportCount; 17527 } 17528 /** 17529 * Gets the shadow cameras frustum. Used internally by the renderer to cull objects. 17530 * 17531 * @return {Frustum} The shadow camera frustum. 17532 */ getFrustum() { 17533 return this._frustum; 17534 } 17535 /** 17536 * Update the matrices for the camera and shadow, used internally by the renderer. 17537 * 17538 * @param {Light} light - The light for which the shadow is being rendered. 17539 */ updateMatrices(light) { 17540 const shadowCamera = this.camera; 17541 const shadowMatrix = this.matrix; 17542 _lightPositionWorld$1.setFromMatrixPosition(light.matrixWorld); 17543 shadowCamera.position.copy(_lightPositionWorld$1); 17544 _lookTarget$1.setFromMatrixPosition(light.target.matrixWorld); 17545 shadowCamera.lookAt(_lookTarget$1); 17546 shadowCamera.updateMatrixWorld(); 17547 _projScreenMatrix$1.multiplyMatrices(shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse); 17548 this._frustum.setFromProjectionMatrix(_projScreenMatrix$1); 17549 shadowMatrix.set(0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0); 17550 shadowMatrix.multiply(_projScreenMatrix$1); 17551 } 17552 /** 17553 * Returns a viewport definition for the given viewport index. 17554 * 17555 * @param {number} viewportIndex - The viewport index. 17556 * @return {Vector4} The viewport. 17557 */ getViewport(viewportIndex) { 17558 return this._viewports[viewportIndex]; 17559 } 17560 /** 17561 * Returns the frame extends. 17562 * 17563 * @return {Vector2} The frame extends. 17564 */ getFrameExtents() { 17565 return this._frameExtents; 17566 } 17567 /** 17568 * Frees the GPU-related resources allocated by this instance. Call this 17569 * method whenever this instance is no longer used in your app. 17570 */ dispose() { 17571 if (this.map) { 17572 this.map.dispose(); 17573 } 17574 if (this.mapPass) { 17575 this.mapPass.dispose(); 17576 } 17577 } 17578 /** 17579 * Copies the values of the given light shadow instance to this instance. 17580 * 17581 * @param {LightShadow} source - The light shadow to copy. 17582 * @return {LightShadow} A reference to this light shadow instance. 17583 */ copy(source) { 17584 this.camera = source.camera.clone(); 17585 this.intensity = source.intensity; 17586 this.bias = source.bias; 17587 this.radius = source.radius; 17588 this.mapSize.copy(source.mapSize); 17589 return this; 17590 } 17591 /** 17592 * Returns a new light shadow instance with copied values from this instance. 17593 * 17594 * @return {LightShadow} A clone of this instance. 17595 */ clone() { 17596 return new this.constructor().copy(this); 17597 } 17598 /** 17599 * Serializes the light shadow into JSON. 17600 * 17601 * @return {Object} A JSON object representing the serialized light shadow. 17602 * @see {@link ObjectLoader#parse} 17603 */ toJSON() { 17604 const object = {}; 17605 if (this.intensity !== 1) object.intensity = this.intensity; 17606 if (this.bias !== 0) object.bias = this.bias; 17607 if (this.normalBias !== 0) object.normalBias = this.normalBias; 17608 if (this.radius !== 1) object.radius = this.radius; 17609 if (this.mapSize.x !== 512 || this.mapSize.y !== 512) object.mapSize = this.mapSize.toArray(); 17610 object.camera = this.camera.toJSON(false).object; 17611 delete object.camera.matrix; 17612 return object; 17613 } 17614 /** 17615 * Constructs a new light shadow. 17616 * 17617 * @param {Camera} camera - The light's view of the world. 17618 */ constructor(camera){ 17619 /** 17620 * The light's view of the world. 17621 * 17622 * @type {Camera} 17623 */ this.camera = camera; 17624 /** 17625 * The intensity of the shadow. The default is `1`. 17626 * Valid values are in the range `[0, 1]`. 17627 * 17628 * @type {number} 17629 * @default 1 17630 */ this.intensity = 1; 17631 /** 17632 * Shadow map bias, how much to add or subtract from the normalized depth 17633 * when deciding whether a surface is in shadow. 17634 * 17635 * The default is `0`. Very tiny adjustments here (in the order of `0.0001`) 17636 * may help reduce artifacts in shadows. 17637 * 17638 * @type {number} 17639 * @default 0 17640 */ this.bias = 0; 17641 /** 17642 * Defines how much the position used to query the shadow map is offset along 17643 * the object normal. The default is `0`. Increasing this value can be used to 17644 * reduce shadow acne especially in large scenes where light shines onto 17645 * geometry at a shallow angle. The cost is that shadows may appear distorted. 17646 * 17647 * @type {number} 17648 * @default 0 17649 */ this.normalBias = 0; 17650 /** 17651 * Setting this to values greater than 1 will blur the edges of the shadow. 17652 * High values will cause unwanted banding effects in the shadows - a greater 17653 * map size will allow for a higher value to be used here before these effects 17654 * become visible. 17655 * 17656 * The property has no effect when the shadow map type is `PCFSoftShadowMap` and 17657 * and it is recommended to increase softness by decreasing the shadow map size instead. 17658 * 17659 * The property has no effect when the shadow map type is `BasicShadowMap`. 17660 * 17661 * @type {number} 17662 * @default 1 17663 */ this.radius = 1; 17664 /** 17665 * The amount of samples to use when blurring a VSM shadow map. 17666 * 17667 * @type {number} 17668 * @default 8 17669 */ this.blurSamples = 8; 17670 /** 17671 * Defines the width and height of the shadow map. Higher values give better quality 17672 * shadows at the cost of computation time. Values must be powers of two. 17673 * 17674 * @type {Vector2} 17675 * @default (512,512) 17676 */ this.mapSize = new Vector2(512, 512); 17677 /** 17678 * The depth map generated using the internal camera; a location beyond a 17679 * pixel's depth is in shadow. Computed internally during rendering. 17680 * 17681 * @type {?RenderTarget} 17682 * @default null 17683 */ this.map = null; 17684 /** 17685 * The distribution map generated using the internal camera; an occlusion is 17686 * calculated based on the distribution of depths. Computed internally during 17687 * rendering. 17688 * 17689 * @type {?RenderTarget} 17690 * @default null 17691 */ this.mapPass = null; 17692 /** 17693 * Model to shadow camera space, to compute location and depth in shadow map. 17694 * This is computed internally during rendering. 17695 * 17696 * @type {Matrix4} 17697 */ this.matrix = new Matrix4(); 17698 /** 17699 * Enables automatic updates of the light's shadow. If you do not require dynamic 17700 * lighting / shadows, you may set this to `false`. 17701 * 17702 * @type {boolean} 17703 * @default true 17704 */ this.autoUpdate = true; 17705 /** 17706 * When set to `true`, shadow maps will be updated in the next `render` call. 17707 * If you have set {@link LightShadow#autoUpdate} to `false`, you will need to 17708 * set this property to `true` and then make a render call to update the light's shadow. 17709 * 17710 * @type {boolean} 17711 * @default false 17712 */ this.needsUpdate = false; 17713 this._frustum = new Frustum(); 17714 this._frameExtents = new Vector2(1, 1); 17715 this._viewportCount = 1; 17716 this._viewports = [ 17717 new Vector4(0, 0, 1, 1) 17718 ]; 17719 } 17720 } 17721 /** 17722 * Represents the shadow configuration of directional lights. 17723 * 17724 * @augments LightShadow 17725 */ class SpotLightShadow extends LightShadow { 17726 updateMatrices(light) { 17727 const camera = this.camera; 17728 const fov = RAD2DEG * 2 * light.angle * this.focus; 17729 const aspect = this.mapSize.width / this.mapSize.height; 17730 const far = light.distance || camera.far; 17731 if (fov !== camera.fov || aspect !== camera.aspect || far !== camera.far) { 17732 camera.fov = fov; 17733 camera.aspect = aspect; 17734 camera.far = far; 17735 camera.updateProjectionMatrix(); 17736 } 17737 super.updateMatrices(light); 17738 } 17739 copy(source) { 17740 super.copy(source); 17741 this.focus = source.focus; 17742 return this; 17743 } 17744 /** 17745 * Constructs a new spot light shadow. 17746 */ constructor(){ 17747 super(new PerspectiveCamera(50, 1, 0.5, 500)); 17748 /** 17749 * This flag can be used for type testing. 17750 * 17751 * @type {boolean} 17752 * @readonly 17753 * @default true 17754 */ this.isSpotLightShadow = true; 17755 /** 17756 * Used to focus the shadow camera. The camera's field of view is set as a 17757 * percentage of the spotlight's field-of-view. Range is `[0, 1]`. 17758 * 17759 * @type {number} 17760 * @default 1 17761 */ this.focus = 1; 17762 } 17763 } 17764 /** 17765 * This light gets emitted from a single point in one direction, along a cone 17766 * that increases in size the further from the light it gets. 17767 * 17768 * This light can cast shadows - see the {@link SpotLightShadow} for details. 17769 * 17770 * ```js 17771 * // white spotlight shining from the side, modulated by a texture 17772 * const spotLight = new THREE.SpotLight( 0xffffff ); 17773 * spotLight.position.set( 100, 1000, 100 ); 17774 * spotLight.map = new THREE.TextureLoader().load( url ); 17775 * 17776 * spotLight.castShadow = true; 17777 * spotLight.shadow.mapSize.width = 1024; 17778 * spotLight.shadow.mapSize.height = 1024; 17779 * spotLight.shadow.camera.near = 500; 17780 * spotLight.shadow.camera.far = 4000; 17781 * spotLight.shadow.camera.fov = 30;s 17782 * ``` 17783 * 17784 * @augments Light 17785 */ class SpotLight extends Light { 17786 /** 17787 * The light's power. Power is the luminous power of the light measured in lumens (lm). 17788 * Changing the power will also change the light's intensity. 17789 * 17790 * @type {number} 17791 */ get power() { 17792 // compute the light's luminous power (in lumens) from its intensity (in candela) 17793 // by convention for a spotlight, luminous power (lm) = Ï * luminous intensity (cd) 17794 return this.intensity * Math.PI; 17795 } 17796 set power(power) { 17797 // set the light's intensity (in candela) from the desired luminous power (in lumens) 17798 this.intensity = power / Math.PI; 17799 } 17800 dispose() { 17801 this.shadow.dispose(); 17802 } 17803 copy(source, recursive) { 17804 super.copy(source, recursive); 17805 this.distance = source.distance; 17806 this.angle = source.angle; 17807 this.penumbra = source.penumbra; 17808 this.decay = source.decay; 17809 this.target = source.target.clone(); 17810 this.shadow = source.shadow.clone(); 17811 return this; 17812 } 17813 /** 17814 * Constructs a new spot light. 17815 * 17816 * @param {(number|Color|string)} [color=0xffffff] - The light's color. 17817 * @param {number} [intensity=1] - The light's strength/intensity measured in candela (cd). 17818 * @param {number} [distance=0] - Maximum range of the light. `0` means no limit. 17819 * @param {number} [angle=Math.PI/3] - Maximum angle of light dispersion from its direction whose upper bound is `Math.PI/2`. 17820 * @param {number} [penumbra=0] - Percent of the spotlight cone that is attenuated due to penumbra. Value range is `[0,1]`. 17821 * @param {number} [decay=2] - The amount the light dims along the distance of the light. 17822 */ constructor(color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 2){ 17823 super(color, intensity); 17824 /** 17825 * This flag can be used for type testing. 17826 * 17827 * @type {boolean} 17828 * @readonly 17829 * @default true 17830 */ this.isSpotLight = true; 17831 this.type = 'SpotLight'; 17832 this.position.copy(Object3D.DEFAULT_UP); 17833 this.updateMatrix(); 17834 /** 17835 * The spot light points from its position to the 17836 * target's position. 17837 * 17838 * For the target's position to be changed to anything other 17839 * than the default, it must be added to the scene. 17840 * 17841 * It is also possible to set the target to be another 3D object 17842 * in the scene. The light will now track the target object. 17843 * 17844 * @type {Object3D} 17845 */ this.target = new Object3D(); 17846 /** 17847 * Maximum range of the light. `0` means no limit. 17848 * 17849 * @type {number} 17850 * @default 0 17851 */ this.distance = distance; 17852 /** 17853 * Maximum angle of light dispersion from its direction whose upper bound is `Math.PI/2`. 17854 * 17855 * @type {number} 17856 * @default Math.PI/3 17857 */ this.angle = angle; 17858 /** 17859 * Percent of the spotlight cone that is attenuated due to penumbra. 17860 * Value range is `[0,1]`. 17861 * 17862 * @type {number} 17863 * @default 0 17864 */ this.penumbra = penumbra; 17865 /** 17866 * The amount the light dims along the distance of the light. In context of 17867 * physically-correct rendering the default value should not be changed. 17868 * 17869 * @type {number} 17870 * @default 2 17871 */ this.decay = decay; 17872 /** 17873 * A texture used to modulate the color of the light. The spot light 17874 * color is mixed with the RGB value of this texture, with a ratio 17875 * corresponding to its alpha value. The cookie-like masking effect is 17876 * reproduced using pixel values (0, 0, 0, 1-cookie_value). 17877 * 17878 * *Warning*: This property is disabled if {@link Object3D#castShadow} is set to `false`. 17879 * 17880 * @type {?Texture} 17881 * @default null 17882 */ this.map = null; 17883 /** 17884 * This property holds the light's shadow configuration. 17885 * 17886 * @type {SpotLightShadow} 17887 */ this.shadow = new SpotLightShadow(); 17888 } 17889 } 17890 const _projScreenMatrix = /*@__PURE__*/ new Matrix4(); 17891 const _lightPositionWorld = /*@__PURE__*/ new Vector3(); 17892 const _lookTarget = /*@__PURE__*/ new Vector3(); 17893 /** 17894 * Represents the shadow configuration of point lights. 17895 * 17896 * @augments LightShadow 17897 */ class PointLightShadow extends LightShadow { 17898 /** 17899 * Update the matrices for the camera and shadow, used internally by the renderer. 17900 * 17901 * @param {Light} light - The light for which the shadow is being rendered. 17902 * @param {number} [viewportIndex=0] - The viewport index. 17903 */ updateMatrices(light, viewportIndex = 0) { 17904 const camera = this.camera; 17905 const shadowMatrix = this.matrix; 17906 const far = light.distance || camera.far; 17907 if (far !== camera.far) { 17908 camera.far = far; 17909 camera.updateProjectionMatrix(); 17910 } 17911 _lightPositionWorld.setFromMatrixPosition(light.matrixWorld); 17912 camera.position.copy(_lightPositionWorld); 17913 _lookTarget.copy(camera.position); 17914 _lookTarget.add(this._cubeDirections[viewportIndex]); 17915 camera.up.copy(this._cubeUps[viewportIndex]); 17916 camera.lookAt(_lookTarget); 17917 camera.updateMatrixWorld(); 17918 shadowMatrix.makeTranslation(-_lightPositionWorld.x, -_lightPositionWorld.y, -_lightPositionWorld.z); 17919 _projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse); 17920 this._frustum.setFromProjectionMatrix(_projScreenMatrix); 17921 } 17922 /** 17923 * Constructs a new point light shadow. 17924 */ constructor(){ 17925 super(new PerspectiveCamera(90, 1, 0.5, 500)); 17926 /** 17927 * This flag can be used for type testing. 17928 * 17929 * @type {boolean} 17930 * @readonly 17931 * @default true 17932 */ this.isPointLightShadow = true; 17933 this._frameExtents = new Vector2(4, 2); 17934 this._viewportCount = 6; 17935 this._viewports = [ 17936 // These viewports map a cube-map onto a 2D texture with the 17937 // following orientation: 17938 // 17939 // xzXZ 17940 // y Y 17941 // 17942 // X - Positive x direction 17943 // x - Negative x direction 17944 // Y - Positive y direction 17945 // y - Negative y direction 17946 // Z - Positive z direction 17947 // z - Negative z direction 17948 // positive X 17949 new Vector4(2, 1, 1, 1), 17950 // negative X 17951 new Vector4(0, 1, 1, 1), 17952 // positive Z 17953 new Vector4(3, 1, 1, 1), 17954 // negative Z 17955 new Vector4(1, 1, 1, 1), 17956 // positive Y 17957 new Vector4(3, 0, 1, 1), 17958 // negative Y 17959 new Vector4(1, 0, 1, 1) 17960 ]; 17961 this._cubeDirections = [ 17962 new Vector3(1, 0, 0), 17963 new Vector3(-1, 0, 0), 17964 new Vector3(0, 0, 1), 17965 new Vector3(0, 0, -1), 17966 new Vector3(0, 1, 0), 17967 new Vector3(0, -1, 0) 17968 ]; 17969 this._cubeUps = [ 17970 new Vector3(0, 1, 0), 17971 new Vector3(0, 1, 0), 17972 new Vector3(0, 1, 0), 17973 new Vector3(0, 1, 0), 17974 new Vector3(0, 0, 1), 17975 new Vector3(0, 0, -1) 17976 ]; 17977 } 17978 } 17979 /** 17980 * A light that gets emitted from a single point in all directions. A common 17981 * use case for this is to replicate the light emitted from a bare 17982 * lightbulb. 17983 * 17984 * This light can cast shadows - see the {@link PointLightShadow} for details. 17985 * 17986 * ```js 17987 * const light = new THREE.PointLight( 0xff0000, 1, 100 ); 17988 * light.position.set( 50, 50, 50 ); 17989 * scene.add( light ); 17990 * ``` 17991 * 17992 * @augments Light 17993 */ class PointLight extends Light { 17994 /** 17995 * The light's power. Power is the luminous power of the light measured in lumens (lm). 17996 * Changing the power will also change the light's intensity. 17997 * 17998 * @type {number} 17999 */ get power() { 18000 // compute the light's luminous power (in lumens) from its intensity (in candela) 18001 // for an isotropic light source, luminous power (lm) = 4 Ï luminous intensity (cd) 18002 return this.intensity * 4 * Math.PI; 18003 } 18004 set power(power) { 18005 // set the light's intensity (in candela) from the desired luminous power (in lumens) 18006 this.intensity = power / (4 * Math.PI); 18007 } 18008 dispose() { 18009 this.shadow.dispose(); 18010 } 18011 copy(source, recursive) { 18012 super.copy(source, recursive); 18013 this.distance = source.distance; 18014 this.decay = source.decay; 18015 this.shadow = source.shadow.clone(); 18016 return this; 18017 } 18018 /** 18019 * Constructs a new point light. 18020 * 18021 * @param {(number|Color|string)} [color=0xffffff] - The light's color. 18022 * @param {number} [intensity=1] - The light's strength/intensity measured in candela (cd). 18023 * @param {number} [distance=0] - Maximum range of the light. `0` means no limit. 18024 * @param {number} [decay=2] - The amount the light dims along the distance of the light. 18025 */ constructor(color, intensity, distance = 0, decay = 2){ 18026 super(color, intensity); 18027 /** 18028 * This flag can be used for type testing. 18029 * 18030 * @type {boolean} 18031 * @readonly 18032 * @default true 18033 */ this.isPointLight = true; 18034 this.type = 'PointLight'; 18035 /** 18036 * When distance is zero, light will attenuate according to inverse-square 18037 * law to infinite distance. When distance is non-zero, light will attenuate 18038 * according to inverse-square law until near the distance cutoff, where it 18039 * will then attenuate quickly and smoothly to 0. Inherently, cutoffs are not 18040 * physically correct. 18041 * 18042 * @type {number} 18043 * @default 0 18044 */ this.distance = distance; 18045 /** 18046 * The amount the light dims along the distance of the light. In context of 18047 * physically-correct rendering the default value should not be changed. 18048 * 18049 * @type {number} 18050 * @default 2 18051 */ this.decay = decay; 18052 /** 18053 * This property holds the light's shadow configuration. 18054 * 18055 * @type {PointLightShadow} 18056 */ this.shadow = new PointLightShadow(); 18057 } 18058 } 18059 /** 18060 * Camera that uses [orthographic projection]{@link https://en.wikipedia.org/wiki/Orthographic_projection}. 18061 * 18062 * In this projection mode, an object's size in the rendered image stays 18063 * constant regardless of its distance from the camera. This can be useful 18064 * for rendering 2D scenes and UI elements, amongst other things. 18065 * 18066 * ```js
18067 * const camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 1, 1000 ); 18068 * scene.add( camera ); 18069 * ``` 18070 * 18071 * @augments Camera 18072 */ class OrthographicCamera extends Camera { 18073 copy(source, recursive) { 18074 super.copy(source, recursive); 18075 this.left = source.left; 18076 this.right = source.right; 18077 this.top = source.top; 18078 this.bottom = source.bottom; 18079 this.near = source.near; 18080 this.far = source.far; 18081 this.zoom = source.zoom; 18082 this.view = source.view === null ? null : Object.assign({}, source.view); 18083 return this; 18084 } 18085 /** 18086 * Sets an offset in a larger frustum. This is useful for multi-window or 18087 * multi-monitor/multi-machine setups. 18088 * 18089 * @param {number} fullWidth - The full width of multiview setup. 18090 * @param {number} fullHeight - The full height of multiview setup. 18091 * @param {number} x - The horizontal offset of the subcamera. 18092 * @param {number} y - The vertical offset of the subcamera. 18093 * @param {number} width - The width of subcamera. 18094 * @param {number} height - The height of subcamera. 18095 * @see {@link PerspectiveCamera#setViewOffset} 18096 */ setViewOffset(fullWidth, fullHeight, x, y, width, height) { 18097 if (this.view === null) { 18098 this.view = { 18099 enabled: true, 18100 fullWidth: 1, 18101 fullHeight: 1, 18102 offsetX: 0, 18103 offsetY: 0, 18104 width: 1, 18105 height: 1 18106 }; 18107 } 18108 this.view.enabled = true; 18109 this.view.fullWidth = fullWidth; 18110 this.view.fullHeight = fullHeight; 18111 this.view.offsetX = x; 18112 this.view.offsetY = y; 18113 this.view.width = width; 18114 this.view.height = height; 18115 this.updateProjectionMatrix(); 18116 } 18117 /** 18118 * Removes the view offset from the projection matrix. 18119 */ clearViewOffset() { 18120 if (this.view !== null) { 18121 this.view.enabled = false; 18122 } 18123 this.updateProjectionMatrix(); 18124 } 18125 /** 18126 * Updates the camera's projection matrix. Must be called after any change of 18127 * camera properties. 18128 */ updateProjectionMatrix() { 18129 const dx = (this.right - this.left) / (2 * this.zoom); 18130 const dy = (this.top - this.bottom) / (2 * this.zoom); 18131 const cx = (this.right + this.left) / 2; 18132 const cy = (this.top + this.bottom) / 2; 18133 let left = cx - dx; 18134 let right = cx + dx; 18135 let top = cy + dy; 18136 let bottom = cy - dy; 18137 if (this.view !== null && this.view.enabled) { 18138 const scaleW = (this.right - this.left) / this.view.fullWidth / this.zoom; 18139 const scaleH = (this.top - this.bottom) / this.view.fullHeight / this.zoom; 18140 left += scaleW * this.view.offsetX; 18141 right = left + scaleW * this.view.width; 18142 top -= scaleH * this.view.offsetY; 18143 bottom = top - scaleH * this.view.height; 18144 } 18145 this.projectionMatrix.makeOrthographic(left, right, top, bottom, this.near, this.far, this.coordinateSystem); 18146 this.projectionMatrixInverse.copy(this.projectionMatrix).invert(); 18147 } 18148 toJSON(meta) { 18149 const data = super.toJSON(meta); 18150 data.object.zoom = this.zoom; 18151 data.object.left = this.left; 18152 data.object.right = this.right; 18153 data.object.top = this.top; 18154 data.object.bottom = this.bottom; 18155 data.object.near = this.near; 18156 data.object.far = this.far; 18157 if (this.view !== null) data.object.view = Object.assign({}, this.view); 18158 return data; 18159 } 18160 /** 18161 * Constructs a new orthographic camera. 18162 * 18163 * @param {number} [left=-1] - The left plane of the camera's frustum. 18164 * @param {number} [right=1] - The right plane of the camera's frustum. 18165 * @param {number} [top=1] - The top plane of the camera's frustum. 18166 * @param {number} [bottom=-1] - The bottom plane of the camera's frustum. 18167 * @param {number} [near=0.1] - The camera's near plane. 18168 * @param {number} [far=2000] - The camera's far plane. 18169 */ constructor(left = -1, right = 1, top = 1, bottom = -1, near = 0.1, far = 2000){ 18170 super(); 18171 /** 18172 * This flag can be used for type testing. 18173 * 18174 * @type {boolean} 18175 * @readonly 18176 * @default true 18177 */ this.isOrthographicCamera = true;
vendor: 33,662 bytes, lines 18178-19038
18178 this.type = 'OrthographicCamera'; 18179 /** 18180 * The zoom factor of the camera. 18181 * 18182 * @type {number} 18183 * @default 1 18184 */ this.zoom = 1; 18185 /** 18186 * Represents the frustum window specification. This property should not be edited 18187 * directly but via {@link PerspectiveCamera#setViewOffset} and {@link PerspectiveCamera#clearViewOffset}. 18188 * 18189 * @type {?Object} 18190 * @default null 18191 */ this.view = null; 18192 /** 18193 * The left plane of the camera's frustum. 18194 * 18195 * @type {number} 18196 * @default -1 18197 */ this.left = left; 18198 /** 18199 * The right plane of the camera's frustum. 18200 * 18201 * @type {number} 18202 * @default 1 18203 */ this.right = right; 18204 /** 18205 * The top plane of the camera's frustum. 18206 * 18207 * @type {number} 18208 * @default 1 18209 */ this.top = top; 18210 /** 18211 * The bottom plane of the camera's frustum. 18212 * 18213 * @type {number} 18214 * @default -1 18215 */ this.bottom = bottom; 18216 /** 18217 * The camera's near plane. The valid range is greater than `0` 18218 * and less than the current value of {@link OrthographicCamera#far}. 18219 * 18220 * Note that, unlike for the {@link PerspectiveCamera}, `0` is a 18221 * valid value for an orthographic camera's near plane. 18222 * 18223 * @type {number} 18224 * @default 0.1 18225 */ this.near = near; 18226 /** 18227 * The camera's far plane. Must be greater than the 18228 * current value of {@link OrthographicCamera#near}. 18229 * 18230 * @type {number} 18231 * @default 2000 18232 */ this.far = far; 18233 this.updateProjectionMatrix(); 18234 } 18235 } 18236 /** 18237 * Represents the shadow configuration of directional lights. 18238 * 18239 * @augments LightShadow 18240 */ class DirectionalLightShadow extends LightShadow { 18241 /** 18242 * Constructs a new directional light shadow. 18243 */ constructor(){ 18244 super(new OrthographicCamera(-5, 5, 5, -5, 0.5, 500)); 18245 /** 18246 * This flag can be used for type testing. 18247 * 18248 * @type {boolean} 18249 * @readonly 18250 * @default true 18251 */ this.isDirectionalLightShadow = true; 18252 } 18253 } 18254 /** 18255 * A light that gets emitted in a specific direction. This light will behave 18256 * as though it is infinitely far away and the rays produced from it are all 18257 * parallel. The common use case for this is to simulate daylight; the sun is 18258 * far enough away that its position can be considered to be infinite, and 18259 * all light rays coming from it are parallel. 18260 * 18261 * A common point of confusion for directional lights is that setting the 18262 * rotation has no effect. This is because three.js's DirectionalLight is the 18263 * equivalent to what is often called a 'Target Direct Light' in other 18264 * applications. 18265 * 18266 * This means that its direction is calculated as pointing from the light's 18267 * {@link Object3D#position} to the {@link DirectionalLight#target} position 18268 * (as opposed to a 'Free Direct Light' that just has a rotation 18269 * component). 18270 * 18271 * This light can cast shadows - see the {@link DirectionalLightShadow} for details. 18272 * 18273 * ```js 18274 * // White directional light at half intensity shining from the top. 18275 * const directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 ); 18276 * scene.add( directionalLight ); 18277 * ``` 18278 * 18279 * @augments Light 18280 */ class DirectionalLight extends Light { 18281 dispose() { 18282 this.shadow.dispose(); 18283 } 18284 copy(source) { 18285 super.copy(source); 18286 this.target = source.target.clone(); 18287 this.shadow = source.shadow.clone(); 18288 return this; 18289 } 18290 /** 18291 * Constructs a new directional light. 18292 * 18293 * @param {(number|Color|string)} [color=0xffffff] - The light's color. 18294 * @param {number} [intensity=1] - The light's strength/intensity. 18295 */ constructor(color, intensity){ 18296 super(color, intensity); 18297 /** 18298 * This flag can be used for type testing. 18299 * 18300 * @type {boolean} 18301 * @readonly 18302 * @default true 18303 */ this.isDirectionalLight = true; 18304 this.type = 'DirectionalLight'; 18305 this.position.copy(Object3D.DEFAULT_UP); 18306 this.updateMatrix(); 18307 /** 18308 * The directional light points from its position to the 18309 * target's position. 18310 * 18311 * For the target's position to be changed to anything other 18312 * than the default, it must be added to the scene. 18313 * 18314 * It is also possible to set the target to be another 3D object 18315 * in the scene. The light will now track the target object. 18316 * 18317 * @type {Object3D} 18318 */ this.target = new Object3D(); 18319 /** 18320 * This property holds the light's shadow configuration. 18321 * 18322 * @type {DirectionalLightShadow} 18323 */ this.shadow = new DirectionalLightShadow(); 18324 } 18325 } 18326 /** 18327 * Represents a third-order spherical harmonics (SH). Light probes use this class 18328 * to encode lighting information. 18329 * 18330 * - Primary reference: {@link https://graphics.stanford.edu/papers/envmap/envmap.pdf} 18331 * - Secondary reference: {@link https://www.ppsloan.org/publications/StupidSH36.pdf} 18332 */ class SphericalHarmonics3 { 18333 /** 18334 * Sets the given SH coefficients to this instance by copying 18335 * the values. 18336 * 18337 * @param {Array<Vector3>} coefficients - The SH coefficients. 18338 * @return {SphericalHarmonics3} A reference to this spherical harmonics. 18339 */ set(coefficients) { 18340 for(let i = 0; i < 9; i++){ 18341 this.coefficients[i].copy(coefficients[i]); 18342 } 18343 return this; 18344 } 18345 /** 18346 * Sets all SH coefficients to `0`. 18347 * 18348 * @return {SphericalHarmonics3} A reference to this spherical harmonics. 18349 */ zero() { 18350 for(let i = 0; i < 9; i++){ 18351 this.coefficients[i].set(0, 0, 0); 18352 } 18353 return this; 18354 } 18355 /** 18356 * Returns the radiance in the direction of the given normal. 18357 * 18358 * @param {Vector3} normal - The normal vector (assumed to be unit length) 18359 * @param {Vector3} target - The target vector that is used to store the method's result. 18360 * @return {Vector3} The radiance. 18361 */ getAt(normal, target) { 18362 // normal is assumed to be unit length 18363 const x = normal.x, y = normal.y, z = normal.z; 18364 const coeff = this.coefficients; 18365 // band 0 18366 target.copy(coeff[0]).multiplyScalar(0.282095); 18367 // band 1 18368 target.addScaledVector(coeff[1], 0.488603 * y); 18369 target.addScaledVector(coeff[2], 0.488603 * z); 18370 target.addScaledVector(coeff[3], 0.488603 * x); 18371 // band 2 18372 target.addScaledVector(coeff[4], 1.092548 * (x * y)); 18373 target.addScaledVector(coeff[5], 1.092548 * (y * z)); 18374 target.addScaledVector(coeff[6], 0.315392 * (3.0 * z * z - 1.0)); 18375 target.addScaledVector(coeff[7], 1.092548 * (x * z)); 18376 target.addScaledVector(coeff[8], 0.546274 * (x * x - y * y)); 18377 return target; 18378 } 18379 /** 18380 * Returns the irradiance (radiance convolved with cosine lobe) in the 18381 * direction of the given normal. 18382 * 18383 * @param {Vector3} normal - The normal vector (assumed to be unit length) 18384 * @param {Vector3} target - The target vector that is used to store the method's result. 18385 * @return {Vector3} The irradiance. 18386 */ getIrradianceAt(normal, target) { 18387 // normal is assumed to be unit length 18388 const x = normal.x, y = normal.y, z = normal.z; 18389 const coeff = this.coefficients; 18390 // band 0 18391 target.copy(coeff[0]).multiplyScalar(0.886227); // Ï * 0.282095 18392 // band 1 18393 target.addScaledVector(coeff[1], 2.0 * 0.511664 * y); // ( 2 * Ï / 3 ) * 0.488603 18394 target.addScaledVector(coeff[2], 2.0 * 0.511664 * z); 18395 target.addScaledVector(coeff[3], 2.0 * 0.511664 * x); 18396 // band 2 18397 target.addScaledVector(coeff[4], 2.0 * 0.429043 * x * y); // ( Ï / 4 ) * 1.092548 18398 target.addScaledVector(coeff[5], 2.0 * 0.429043 * y * z); 18399 target.addScaledVector(coeff[6], 0.743125 * z * z - 0.247708); // ( Ï / 4 ) * 0.315392 * 3 18400 target.addScaledVector(coeff[7], 2.0 * 0.429043 * x * z); 18401 target.addScaledVector(coeff[8], 0.429043 * (x * x - y * y)); // ( Ï / 4 ) * 0.546274 18402 return target; 18403 } 18404 /** 18405 * Adds the given SH to this instance. 18406 * 18407 * @param {SphericalHarmonics3} sh - The SH to add. 18408 * @return {SphericalHarmonics3} A reference to this spherical harmonics. 18409 */ add(sh) { 18410 for(let i = 0; i < 9; i++){ 18411 this.coefficients[i].add(sh.coefficients[i]); 18412 } 18413 return this; 18414 } 18415 /** 18416 * A convenience method for performing {@link SphericalHarmonics3#add} and 18417 * {@link SphericalHarmonics3#scale} at once. 18418 * 18419 * @param {SphericalHarmonics3} sh - The SH to add. 18420 * @param {number} s - The scale factor. 18421 * @return {SphericalHarmonics3} A reference to this spherical harmonics. 18422 */ addScaledSH(sh, s) { 18423 for(let i = 0; i < 9; i++){ 18424 this.coefficients[i].addScaledVector(sh.coefficients[i], s); 18425 } 18426 return this; 18427 } 18428 /** 18429 * Scales this SH by the given scale factor. 18430 * 18431 * @param {number} s - The scale factor. 18432 * @return {SphericalHarmonics3} A reference to this spherical harmonics. 18433 */ scale(s) { 18434 for(let i = 0; i < 9; i++){ 18435 this.coefficients[i].multiplyScalar(s); 18436 } 18437 return this; 18438 } 18439 /** 18440 * Linear interpolates between the given SH and this instance by the given 18441 * alpha factor. 18442 * 18443 * @param {SphericalHarmonics3} sh - The SH to interpolate with. 18444 * @param {number} alpha - The alpha factor. 18445 * @return {SphericalHarmonics3} A reference to this spherical harmonics. 18446 */ lerp(sh, alpha) { 18447 for(let i = 0; i < 9; i++){ 18448 this.coefficients[i].lerp(sh.coefficients[i], alpha); 18449 } 18450 return this; 18451 } 18452 /** 18453 * Returns `true` if this spherical harmonics is equal with the given one. 18454 * 18455 * @param {SphericalHarmonics3} sh - The spherical harmonics to test for equality. 18456 * @return {boolean} Whether this spherical harmonics is equal with the given one. 18457 */ equals(sh) { 18458 for(let i = 0; i < 9; i++){ 18459 if (!this.coefficients[i].equals(sh.coefficients[i])) { 18460 return false; 18461 } 18462 } 18463 return true; 18464 } 18465 /** 18466 * Copies the values of the given spherical harmonics to this instance. 18467 * 18468 * @param {SphericalHarmonics3} sh - The spherical harmonics to copy. 18469 * @return {SphericalHarmonics3} A reference to this spherical harmonics. 18470 */ copy(sh) { 18471 return this.set(sh.coefficients); 18472 } 18473 /** 18474 * Returns a new spherical harmonics with copied values from this instance. 18475 * 18476 * @return {SphericalHarmonics3} A clone of this instance. 18477 */ clone() { 18478 return new this.constructor().copy(this); 18479 } 18480 /** 18481 * Sets the SH coefficients of this instance from the given array. 18482 * 18483 * @param {Array<number>} array - An array holding the SH coefficients. 18484 * @param {number} [offset=0] - The array offset where to start copying. 18485 * @return {SphericalHarmonics3} A clone of this instance. 18486 */ fromArray(array, offset = 0) { 18487 const coefficients = this.coefficients; 18488 for(let i = 0; i < 9; i++){ 18489 coefficients[i].fromArray(array, offset + i * 3); 18490 } 18491 return this; 18492 } 18493 /** 18494 * Returns an array with the SH coefficients, or copies them into the provided 18495 * array. The coefficients are represented as numbers. 18496 * 18497 * @param {Array<number>} [array=[]] - The target array. 18498 * @param {number} [offset=0] - The array offset where to start copying. 18499 * @return {Array<number>} An array with flat SH coefficients. 18500 */ toArray(array = [], offset = 0) { 18501 const coefficients = this.coefficients; 18502 for(let i = 0; i < 9; i++){ 18503 coefficients[i].toArray(array, offset + i * 3); 18504 } 18505 return array; 18506 } 18507 /** 18508 * Computes the SH basis for the given normal vector. 18509 * 18510 * @param {Vector3} normal - The normal. 18511 * @param {Array<number>} shBasis - The target array holding the SH basis. 18512 */ static getBasisAt(normal, shBasis) { 18513 // normal is assumed to be unit length 18514 const x = normal.x, y = normal.y, z = normal.z; 18515 // band 0 18516 shBasis[0] = 0.282095; 18517 // band 1 18518 shBasis[1] = 0.488603 * y; 18519 shBasis[2] = 0.488603 * z; 18520 shBasis[3] = 0.488603 * x; 18521 // band 2 18522 shBasis[4] = 1.092548 * x * y; 18523 shBasis[5] = 1.092548 * y * z; 18524 shBasis[6] = 0.315392 * (3 * z * z - 1); 18525 shBasis[7] = 1.092548 * x * z; 18526 shBasis[8] = 0.546274 * (x * x - y * y); 18527 } 18528 /** 18529 * Constructs a new spherical harmonics. 18530 */ constructor(){ 18531 /** 18532 * This flag can be used for type testing. 18533 * 18534 * @type {boolean} 18535 * @readonly 18536 * @default true 18537 */ this.isSphericalHarmonics3 = true; 18538 /** 18539 * An array holding the (9) SH coefficients. 18540 * 18541 * @type {Array<Vector3>} 18542 */ this.coefficients = []; 18543 for(let i = 0; i < 9; i++){ 18544 this.coefficients.push(new Vector3()); 18545 } 18546 } 18547 } 18548 /** 18549 * Light probes are an alternative way of adding light to a 3D scene. Unlike 18550 * classical light sources (e.g. directional, point or spot lights), light 18551 * probes do not emit light. Instead they store information about light 18552 * passing through 3D space. During rendering, the light that hits a 3D 18553 * object is approximated by using the data from the light probe. 18554 * 18555 * Light probes are usually created from (radiance) environment maps. The 18556 * class {@link LightProbeGenerator} can be used to create light probes from 18557 * cube textures or render targets. However, light estimation data could also 18558 * be provided in other forms e.g. by WebXR. This enables the rendering of 18559 * augmented reality content that reacts to real world lighting. 18560 * 18561 * The current probe implementation in three.js supports so-called diffuse 18562 * light probes. This type of light probe is functionally equivalent to an 18563 * irradiance environment map. 18564 * 18565 * @augments Light 18566 */ class LightProbe extends Light { 18567 copy(source) { 18568 super.copy(source); 18569 this.sh.copy(source.sh); 18570 return this; 18571 } 18572 /** 18573 * Deserializes the light prove from the given JSON. 18574 * 18575 * @param {Object} json - The JSON holding the serialized light probe. 18576 * @return {LightProbe} A reference to this light probe. 18577 */ fromJSON(json) { 18578 this.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON(); 18579 this.sh.fromArray(json.sh); 18580 return this; 18581 } 18582 toJSON(meta) { 18583 const data = super.toJSON(meta); 18584 data.object.sh = this.sh.toArray(); 18585 return data; 18586 } 18587 /** 18588 * Constructs a new light probe. 18589 * 18590 * @param {SphericalHarmonics3} sh - The spherical harmonics which represents encoded lighting information. 18591 * @param {number} [intensity=1] - The light's strength/intensity. 18592 */ constructor(sh = new SphericalHarmonics3(), intensity = 1){ 18593 super(undefined, intensity); 18594 /** 18595 * This flag can be used for type testing. 18596 * 18597 * @type {boolean} 18598 * @readonly 18599 * @default true 18600 */ this.isLightProbe = true; 18601 /** 18602 * A light probe uses spherical harmonics to encode lighting information. 18603 * 18604 * @type {SphericalHarmonics3} 18605 */ this.sh = sh; 18606 } 18607 } 18608 class LoaderUtils { 18609 static decodeText(array) { 18610 console.warn('THREE.LoaderUtils: decodeText() has been deprecated with r165 and will be removed with r175. Use TextDecoder instead.'); 18611 if (typeof TextDecoder !== 'undefined') { 18612 return new TextDecoder().decode(array); 18613 } 18614 // Avoid the String.fromCharCode.apply(null, array) shortcut, which 18615 // throws a "maximum call stack size exceeded" error for large arrays. 18616 let s = ''; 18617 for(let i = 0, il = array.length; i < il; i++){ 18618 // Implicitly assumes little-endian. 18619 s += String.fromCharCode(array[i]); 18620 } 18621 try { 18622 // merges multi-byte utf-8 characters. 18623 return decodeURIComponent(escape(s)); 18624 } catch (e) { 18625 return s; 18626 } 18627 } 18628 static extractUrlBase(url) { 18629 const index = url.lastIndexOf('/'); 18630 if (index === -1) return './'; 18631 return url.slice(0, index + 1); 18632 } 18633 static resolveURL(url, path) { 18634 // Invalid URL 18635 if (typeof url !== 'string' || url === '') return ''; 18636 // Host Relative URL 18637 if (/^https?:\/\//i.test(path) && /^\//.test(url)) { 18638 path = path.replace(/(^https?:\/\/[^\/]+).*/i, '$1'); 18639 } 18640 // Absolute URL http://,https://,// 18641 if (/^(https?:)?\/\//i.test(url)) return url; 18642 // Data URI 18643 if (/^data:.*,.*$/i.test(url)) return url; 18644 // Blob URL 18645 if (/^blob:.*$/i.test(url)) return url; 18646 // Relative URL 18647 return path + url; 18648 } 18649 } 18650 class ImageBitmapLoader extends Loader { 18651 setOptions(options) { 18652 this.options = options; 18653 return this; 18654 } 18655 load(url, onLoad, onProgress, onError) { 18656 if (url === undefined) url = ''; 18657 if (this.path !== undefined) url = this.path + url; 18658 url = this.manager.resolveURL(url); 18659 const scope = this; 18660 const cached = Cache.get(url); 18661 if (cached !== undefined) { 18662 scope.manager.itemStart(url); 18663 // If cached is a promise, wait for it to resolve 18664 if (cached.then) { 18665 cached.then((imageBitmap)=>{ 18666 if (onLoad) onLoad(imageBitmap); 18667 scope.manager.itemEnd(url); 18668 }).catch((e)=>{ 18669 if (onError) onError(e); 18670 }); 18671 return; 18672 } 18673 // If cached is not a promise (i.e., it's already an imageBitmap) 18674 setTimeout(function() { 18675 if (onLoad) onLoad(cached); 18676 scope.manager.itemEnd(url); 18677 }, 0); 18678 return cached; 18679 } 18680 const fetchOptions = {}; 18681 fetchOptions.credentials = this.crossOrigin === 'anonymous' ? 'same-origin' : 'include'; 18682 fetchOptions.headers = this.requestHeader; 18683 const promise = fetch(url, fetchOptions).then(function(res) { 18684 return res.blob(); 18685 }).then(function(blob) { 18686 return createImageBitmap(blob, Object.assign(scope.options, { 18687 colorSpaceConversion: 'none' 18688 })); 18689 }).then(function(imageBitmap) { 18690 Cache.add(url, imageBitmap); 18691 if (onLoad) onLoad(imageBitmap); 18692 scope.manager.itemEnd(url); 18693 return imageBitmap; 18694 }).catch(function(e) { 18695 if (onError) onError(e); 18696 Cache.remove(url); 18697 scope.manager.itemError(url); 18698 scope.manager.itemEnd(url); 18699 }); 18700 Cache.add(url, promise); 18701 scope.manager.itemStart(url); 18702 } 18703 constructor(manager){ 18704 super(manager); 18705 this.isImageBitmapLoader = true; 18706 if (typeof createImageBitmap === 'undefined') { 18707 console.warn('THREE.ImageBitmapLoader: createImageBitmap() not supported.'); 18708 } 18709 if (typeof fetch === 'undefined') { 18710 console.warn('THREE.ImageBitmapLoader: fetch() not supported.'); 18711 } 18712 this.options = { 18713 premultiplyAlpha: 'none' 18714 }; 18715 } 18716 } 18717 /** 18718 * This type of camera can be used in order to efficiently render a scene with a 18719 * predefined set of cameras. This is an important performance aspect for 18720 * rendering VR scenes. 18721 * 18722 * An instance of `ArrayCamera` always has an array of sub cameras. It's mandatory 18723 * to define for each sub camera the `viewport` property which determines the 18724 * part of the viewport that is rendered with this camera. 18725 * 18726 * @augments PerspectiveCamera 18727 */ class ArrayCamera extends PerspectiveCamera { 18728 /** 18729 * Constructs a new array camera. 18730 * 18731 * @param {Array<PerspectiveCamera>} [array=[]] - An array of perspective sub cameras. 18732 */ constructor(array = []){ 18733 super(); 18734 /** 18735 * This flag can be used for type testing. 18736 * 18737 * @type {boolean} 18738 * @readonly 18739 * @default true 18740 */ this.isArrayCamera = true; 18741 /** 18742 * An array of perspective sub cameras. 18743 * 18744 * @type {Array<PerspectiveCamera>} 18745 */ this.cameras = array; 18746 this.index = 0; 18747 } 18748 } 18749 class PropertyMixer { 18750 // accumulate data in the 'incoming' region into 'accu<i>' 18751 accumulate(accuIndex, weight) { 18752 // note: happily accumulating nothing when weight = 0, the caller knows 18753 // the weight and shouldn't have made the call in the first place 18754 const buffer = this.buffer, stride = this.valueSize, offset = accuIndex * stride + stride; 18755 let currentWeight = this.cumulativeWeight; 18756 if (currentWeight === 0) { 18757 // accuN := incoming * weight 18758 for(let i = 0; i !== stride; ++i){ 18759 buffer[offset + i] = buffer[i]; 18760 } 18761 currentWeight = weight; 18762 } else { 18763 // accuN := accuN + incoming * weight 18764 currentWeight += weight; 18765 const mix = weight / currentWeight; 18766 this._mixBufferRegion(buffer, offset, 0, mix, stride); 18767 } 18768 this.cumulativeWeight = currentWeight; 18769 } 18770 // accumulate data in the 'incoming' region into 'add' 18771 accumulateAdditive(weight) { 18772 const buffer = this.buffer, stride = this.valueSize, offset = stride * this._addIndex; 18773 if (this.cumulativeWeightAdditive === 0) { 18774 // add = identity 18775 this._setIdentity(); 18776 } 18777 // add := add + incoming * weight 18778 this._mixBufferRegionAdditive(buffer, offset, 0, weight, stride); 18779 this.cumulativeWeightAdditive += weight; 18780 } 18781 // apply the state of 'accu<i>' to the binding when accus differ 18782 apply(accuIndex) { 18783 const stride = this.valueSize, buffer = this.buffer, offset = accuIndex * stride + stride, weight = this.cumulativeWeight, weightAdditive = this.cumulativeWeightAdditive, binding = this.binding; 18784 this.cumulativeWeight = 0; 18785 this.cumulativeWeightAdditive = 0; 18786 if (weight < 1) { 18787 // accuN := accuN + original * ( 1 - cumulativeWeight ) 18788 const originalValueOffset = stride * this._origIndex; 18789 this._mixBufferRegion(buffer, offset, originalValueOffset, 1 - weight, stride); 18790 } 18791 if (weightAdditive > 0) { 18792 // accuN := accuN + additive accuN 18793 this._mixBufferRegionAdditive(buffer, offset, this._addIndex * stride, 1, stride); 18794 } 18795 for(let i = stride, e = stride + stride; i !== e; ++i){ 18796 if (buffer[i] !== buffer[i + stride]) { 18797 // value has changed -> update scene graph 18798 binding.setValue(buffer, offset); 18799 break; 18800 } 18801 } 18802 } 18803 // remember the state of the bound property and copy it to both accus 18804 saveOriginalState() { 18805 const binding = this.binding; 18806 const buffer = this.buffer, stride = this.valueSize, originalValueOffset = stride * this._origIndex; 18807 binding.getValue(buffer, originalValueOffset); 18808 // accu[0..1] := orig -- initially detect changes against the original 18809 for(let i = stride, e = originalValueOffset; i !== e; ++i){ 18810 buffer[i] = buffer[originalValueOffset + i % stride]; 18811 } 18812 // Add to identity for additive 18813 this._setIdentity(); 18814 this.cumulativeWeight = 0; 18815 this.cumulativeWeightAdditive = 0; 18816 } 18817 // apply the state previously taken via 'saveOriginalState' to the binding 18818 restoreOriginalState() { 18819 const originalValueOffset = this.valueSize * 3; 18820 this.binding.setValue(this.buffer, originalValueOffset); 18821 } 18822 _setAdditiveIdentityNumeric() { 18823 const startIndex = this._addIndex * this.valueSize; 18824 const endIndex = startIndex + this.valueSize; 18825 for(let i = startIndex; i < endIndex; i++){ 18826 this.buffer[i] = 0; 18827 } 18828 } 18829 _setAdditiveIdentityQuaternion() { 18830 this._setAdditiveIdentityNumeric(); 18831 this.buffer[this._addIndex * this.valueSize + 3] = 1; 18832 } 18833 _setAdditiveIdentityOther() { 18834 const startIndex = this._origIndex * this.valueSize; 18835 const targetIndex = this._addIndex * this.valueSize; 18836 for(let i = 0; i < this.valueSize; i++){ 18837 this.buffer[targetIndex + i] = this.buffer[startIndex + i]; 18838 } 18839 } 18840 // mix functions 18841 _select(buffer, dstOffset, srcOffset, t, stride) { 18842 if (t >= 0.5) { 18843 for(let i = 0; i !== stride; ++i){ 18844 buffer[dstOffset + i] = buffer[srcOffset + i]; 18845 } 18846 } 18847 } 18848 _slerp(buffer, dstOffset, srcOffset, t) { 18849 Quaternion.slerpFlat(buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t); 18850 } 18851 _slerpAdditive(buffer, dstOffset, srcOffset, t, stride) { 18852 const workOffset = this._workIndex * stride; 18853 // Store result in intermediate buffer offset 18854 Quaternion.multiplyQuaternionsFlat(buffer, workOffset, buffer, dstOffset, buffer, srcOffset); 18855 // Slerp to the intermediate result 18856 Quaternion.slerpFlat(buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t); 18857 } 18858 _lerp(buffer, dstOffset, srcOffset, t, stride) { 18859 const s = 1 - t; 18860 for(let i = 0; i !== stride; ++i){ 18861 const j = dstOffset + i; 18862 buffer[j] = buffer[j] * s + buffer[srcOffset + i] * t; 18863 } 18864 } 18865 _lerpAdditive(buffer, dstOffset, srcOffset, t, stride) { 18866 for(let i = 0; i !== stride; ++i){ 18867 const j = dstOffset + i; 18868 buffer[j] = buffer[j] + buffer[srcOffset + i] * t; 18869 } 18870 } 18871 constructor(binding, typeName, valueSize){ 18872 this.binding = binding; 18873 this.valueSize = valueSize; 18874 let mixFunction, mixFunctionAdditive, setIdentity; 18875 // buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ] 18876 // 18877 // interpolators can use .buffer as their .result 18878 // the data then goes to 'incoming' 18879 // 18880 // 'accu0' and 'accu1' are used frame-interleaved for 18881 // the cumulative result and are compared to detect 18882 // changes 18883 // 18884 // 'orig' stores the original state of the property 18885 // 18886 // 'add' is used for additive cumulative results 18887 // 18888 // 'work' is optional and is only present for quaternion types. It is used 18889 // to store intermediate quaternion multiplication results 18890 switch(typeName){ 18891 case 'quaternion': 18892 mixFunction = this._slerp; 18893 mixFunctionAdditive = this._slerpAdditive; 18894 setIdentity = this._setAdditiveIdentityQuaternion; 18895 this.buffer = new Float64Array(valueSize * 6); 18896 this._workIndex = 5; 18897 break; 18898 case 'string': 18899 case 'bool': 18900 mixFunction = this._select; 18901 // Use the regular mix function and for additive on these types, 18902 // additive is not relevant for non-numeric types 18903 mixFunctionAdditive = this._select; 18904 setIdentity = this._setAdditiveIdentityOther; 18905 this.buffer = new Array(valueSize * 5); 18906 break; 18907 default: 18908 mixFunction = this._lerp; 18909 mixFunctionAdditive = this._lerpAdditive; 18910 setIdentity = this._setAdditiveIdentityNumeric; 18911 this.buffer = new Float64Array(valueSize * 5); 18912 } 18913 this._mixBufferRegion = mixFunction; 18914 this._mixBufferRegionAdditive = mixFunctionAdditive; 18915 this._setIdentity = setIdentity; 18916 this._origIndex = 3; 18917 this._addIndex = 4; 18918 this.cumulativeWeight = 0; 18919 this.cumulativeWeightAdditive = 0; 18920 this.useCount = 0; 18921 this.referenceCount = 0; 18922 } 18923 } 18924 // Characters [].:/ are reserved for track binding syntax. 18925 const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/'; 18926 const _reservedRe = new RegExp('[' + _RESERVED_CHARS_RE + ']', 'g'); 18927 // Attempts to allow node names from any language. ES5's `\w` regexp matches 18928 // only latin characters, and the unicode \p{L} is not yet supported. So 18929 // instead, we exclude reserved characters and match everything else. 18930 const _wordChar = '[^' + _RESERVED_CHARS_RE + ']'; 18931 const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace('\\.', '') + ']'; 18932 // Parent directories, delimited by '/' or ':'. Currently unused, but must 18933 // be matched to parse the rest of the track name. 18934 const _directoryRe = /*@__PURE__*/ /((?:WC+[\/:])*)/.source.replace('WC', _wordChar); 18935 // Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'. 18936 const _nodeRe = /*@__PURE__*/ /(WCOD+)?/.source.replace('WCOD', _wordCharOrDot); 18937 // Object on target node, and accessor. May not contain reserved 18938 // characters. Accessor may contain any character except closing bracket. 18939 const _objectRe = /*@__PURE__*/ /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace('WC', _wordChar); 18940 // Property and accessor. May not contain reserved characters. Accessor may 18941 // contain any non-bracket characters. 18942 const _propertyRe = /*@__PURE__*/ /\.(WC+)(?:\[(.+)\])?/.source.replace('WC', _wordChar); 18943 const _trackRe = new RegExp('' + '^' + _directoryRe + _nodeRe + _objectRe + _propertyRe + '$'); 18944 const _supportedObjectNames = [ 18945 'material', 18946 'materials', 18947 'bones', 18948 'map' 18949 ]; 18950 class Composite { 18951 getValue(array, offset) { 18952 this.bind(); // bind all binding 18953 const firstValidIndex = this._targetGroup.nCachedObjects_, binding = this._bindings[firstValidIndex]; 18954 // and only call .getValue on the first 18955 if (binding !== undefined) binding.getValue(array, offset); 18956 } 18957 setValue(array, offset) { 18958 const bindings = this._bindings; 18959 for(let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++i){ 18960 bindings[i].setValue(array, offset); 18961 } 18962 } 18963 bind() { 18964 const bindings = this._bindings; 18965 for(let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++i){ 18966 bindings[i].bind(); 18967 } 18968 } 18969 unbind() { 18970 const bindings = this._bindings; 18971 for(let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++i){ 18972 bindings[i].unbind(); 18973 } 18974 } 18975 constructor(targetGroup, path, optionalParsedPath){ 18976 const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName(path); 18977 this._targetGroup = targetGroup; 18978 this._bindings = targetGroup.subscribe_(path, parsedPath); 18979 } 18980 } 18981 // Note: This class uses a State pattern on a per-method basis: 18982 // 'bind' sets 'this.getValue' / 'setValue' and shadows the 18983 // prototype version of these methods with one that represents 18984 // the bound state. When the property is not found, the methods 18985 // become no-ops. 18986 class PropertyBinding { 18987 static create(root, path, parsedPath) { 18988 if (!(root && root.isAnimationObjectGroup)) { 18989 return new PropertyBinding(root, path, parsedPath); 18990 } else { 18991 return new PropertyBinding.Composite(root, path, parsedPath); 18992 } 18993 } 18994 /** 18995 * Replaces spaces with underscores and removes unsupported characters from 18996 * node names, to ensure compatibility with parseTrackName(). 18997 * 18998 * @param {string} name Node name to be sanitized. 18999 * @return {string} 19000 */ static sanitizeNodeName(name) { 19001 return name.replace(/\s/g, '_').replace(_reservedRe, ''); 19002 } 19003 static parseTrackName(trackName) { 19004 const matches = _trackRe.exec(trackName); 19005 if (matches === null) { 19006 throw new Error('PropertyBinding: Cannot parse trackName: ' + trackName); 19007 } 19008 const results = { 19009 // directoryName: matches[ 1 ], // (tschw) currently unused 19010 nodeName: matches[2], 19011 objectName: matches[3], 19012 objectIndex: matches[4], 19013 propertyName: matches[5], 19014 propertyIndex: matches[6] 19015 }; 19016 const lastDot = results.nodeName && results.nodeName.lastIndexOf('.'); 19017 if (lastDot !== undefined && lastDot !== -1) { 19018 const objectName = results.nodeName.substring(lastDot + 1); 19019 // Object names must be checked against an allowlist. Otherwise, there 19020 // is no way to parse 'foo.bar.baz': 'baz' must be a property, but 19021 // 'bar' could be the objectName, or part of a nodeName (which can 19022 // include '.' characters). 19023 if (_supportedObjectNames.indexOf(objectName) !== -1) { 19024 results.nodeName = results.nodeName.substring(0, lastDot); 19025 results.objectName = objectName; 19026 } 19027 } 19028 if (results.propertyName === null || results.propertyName.length === 0) { 19029 throw new Error('PropertyBinding: can not parse propertyName from trackName: ' + trackName); 19030 } 19031 return results; 19032 } 19033 static findNode(root, nodeName) { 19034 if (nodeName === undefined || nodeName === '' || nodeName === '.' || nodeName === -1 || nodeName === root.name || nodeName === root.uuid) { 19035 return root; 19036 } 19037 // search into skeleton bones. 19038 if (root.skeleton) {
vendor: 5,406 bytes, lines 19039-19173
19039 const bone = root.skeleton.getBoneByName(nodeName); 19040 if (bone !== undefined) { 19041 return bone; 19042 } 19043 } 19044 // search into node subtree. 19045 if (root.children) { 19046 const searchNodeSubtree = function(children) { 19047 for(let i = 0; i < children.length; i++){ 19048 const childNode = children[i]; 19049 if (childNode.name === nodeName || childNode.uuid === nodeName) { 19050 return childNode; 19051 } 19052 const result = searchNodeSubtree(childNode.children); 19053 if (result) return result; 19054 } 19055 return null; 19056 }; 19057 const subTreeNode = searchNodeSubtree(root.children); 19058 if (subTreeNode) { 19059 return subTreeNode; 19060 } 19061 } 19062 return null; 19063 } 19064 // these are used to "bind" a nonexistent property 19065 _getValue_unavailable() {} 19066 _setValue_unavailable() {} 19067 // Getters 19068 _getValue_direct(buffer, offset) { 19069 buffer[offset] = this.targetObject[this.propertyName]; 19070 } 19071 _getValue_array(buffer, offset) { 19072 const source = this.resolvedProperty; 19073 for(let i = 0, n = source.length; i !== n; ++i){ 19074 buffer[offset++] = source[i]; 19075 } 19076 } 19077 _getValue_arrayElement(buffer, offset) { 19078 buffer[offset] = this.resolvedProperty[this.propertyIndex]; 19079 } 19080 _getValue_toArray(buffer, offset) { 19081 this.resolvedProperty.toArray(buffer, offset); 19082 } 19083 // Direct 19084 _setValue_direct(buffer, offset) { 19085 this.targetObject[this.propertyName] = buffer[offset]; 19086 } 19087 _setValue_direct_setNeedsUpdate(buffer, offset) { 19088 this.targetObject[this.propertyName] = buffer[offset]; 19089 this.targetObject.needsUpdate = true; 19090 } 19091 _setValue_direct_setMatrixWorldNeedsUpdate(buffer, offset) { 19092 this.targetObject[this.propertyName] = buffer[offset]; 19093 this.targetObject.matrixWorldNeedsUpdate = true; 19094 } 19095 // EntireArray 19096 _setValue_array(buffer, offset) { 19097 const dest = this.resolvedProperty; 19098 for(let i = 0, n = dest.length; i !== n; ++i){ 19099 dest[i] = buffer[offset++]; 19100 } 19101 } 19102 _setValue_array_setNeedsUpdate(buffer, offset) { 19103 const dest = this.resolvedProperty; 19104 for(let i = 0, n = dest.length; i !== n; ++i){ 19105 dest[i] = buffer[offset++]; 19106 } 19107 this.targetObject.needsUpdate = true; 19108 } 19109 _setValue_array_setMatrixWorldNeedsUpdate(buffer, offset) { 19110 const dest = this.resolvedProperty; 19111 for(let i = 0, n = dest.length; i !== n; ++i){ 19112 dest[i] = buffer[offset++]; 19113 } 19114 this.targetObject.matrixWorldNeedsUpdate = true; 19115 } 19116 // ArrayElement 19117 _setValue_arrayElement(buffer, offset) { 19118 this.resolvedProperty[this.propertyIndex] = buffer[offset]; 19119 } 19120 _setValue_arrayElement_setNeedsUpdate(buffer, offset) { 19121 this.resolvedProperty[this.propertyIndex] = buffer[offset]; 19122 this.targetObject.needsUpdate = true; 19123 } 19124 _setValue_arrayElement_setMatrixWorldNeedsUpdate(buffer, offset) { 19125 this.resolvedProperty[this.propertyIndex] = buffer[offset]; 19126 this.targetObject.matrixWorldNeedsUpdate = true; 19127 } 19128 // HasToFromArray 19129 _setValue_fromArray(buffer, offset) { 19130 this.resolvedProperty.fromArray(buffer, offset); 19131 } 19132 _setValue_fromArray_setNeedsUpdate(buffer, offset) { 19133 this.resolvedProperty.fromArray(buffer, offset); 19134 this.targetObject.needsUpdate = true; 19135 } 19136 _setValue_fromArray_setMatrixWorldNeedsUpdate(buffer, offset) { 19137 this.resolvedProperty.fromArray(buffer, offset); 19138 this.targetObject.matrixWorldNeedsUpdate = true; 19139 } 19140 _getValue_unbound(targetArray, offset) { 19141 this.bind(); 19142 this.getValue(targetArray, offset); 19143 } 19144 _setValue_unbound(sourceArray, offset) { 19145 this.bind(); 19146 this.setValue(sourceArray, offset); 19147 } 19148 // create getter / setter pair for a property in the scene graph 19149 bind() { 19150 let targetObject = this.node; 19151 const parsedPath = this.parsedPath; 19152 const objectName = parsedPath.objectName; 19153 const propertyName = parsedPath.propertyName; 19154 let propertyIndex = parsedPath.propertyIndex; 19155 if (!targetObject) { 19156 targetObject = PropertyBinding.findNode(this.rootNode, parsedPath.nodeName); 19157 this.node = targetObject; 19158 } 19159 // set fail state so we can just 'return' on error 19160 this.getValue = this._getValue_unavailable; 19161 this.setValue = this._setValue_unavailable; 19162 // ensure there is a value node 19163 if (!targetObject) { 19164 console.warn('THREE.PropertyBinding: No target node found for track: ' + this.path + '.'); 19165 return; 19166 } 19167 if (objectName) { 19168 let objectIndex = parsedPath.objectIndex; 19169 // special cases were we need to reach deeper into the hierarchy to get the face materials.... 19170 switch(objectName){ 19171 case 'materials': 19172 if (!targetObject.material) { 19173 console.error('THREE.PropertyBinding: Can not bind to material as no
vendor: 23,355 bytes, lines 19173-19726
19173de does not have a material.', this); 19174 return; 19175 } 19176 if (!targetObject.material.materials) { 19177 console.error('THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this); 19178 return; 19179 } 19180 targetObject = targetObject.material.materials; 19181 break; 19182 case 'bones': 19183 if (!targetObject.skeleton) { 19184 console.error('THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this); 19185 return; 19186 } 19187 // potential future optimization: skip this if propertyIndex is already an integer 19188 // and convert the integer string to a true integer. 19189 targetObject = targetObject.skeleton.bones; 19190 // support resolving morphTarget names into indices. 19191 for(let i = 0; i < targetObject.length; i++){ 19192 if (targetObject[i].name === objectIndex) { 19193 objectIndex = i; 19194 break; 19195 } 19196 } 19197 break; 19198 case 'map': 19199 if ('map' in targetObject) { 19200 targetObject = targetObject.map; 19201 break; 19202 } 19203 if (!targetObject.material) { 19204 console.error('THREE.PropertyBinding: Can not bind to material as node does not have a material.', this); 19205 return; 19206 } 19207 if (!targetObject.material.map) { 19208 console.error('THREE.PropertyBinding: Can not bind to material.map as node.material does not have a map.', this); 19209 return; 19210 } 19211 targetObject = targetObject.material.map; 19212 break; 19213 default: 19214 if (targetObject[objectName] === undefined) { 19215 console.error('THREE.PropertyBinding: Can not bind to objectName of node undefined.', this); 19216 return; 19217 } 19218 targetObject = targetObject[objectName]; 19219 } 19220 if (objectIndex !== undefined) { 19221 if (targetObject[objectIndex] === undefined) { 19222 console.error('THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject); 19223 return; 19224 } 19225 targetObject = targetObject[objectIndex]; 19226 } 19227 } 19228 // resolve property 19229 const nodeProperty = targetObject[propertyName]; 19230 if (nodeProperty === undefined) { 19231 const nodeName = parsedPath.nodeName; 19232 console.error('THREE.PropertyBinding: Trying to update property for track: ' + nodeName + '.' + propertyName + ' but it wasn\'t found.', targetObject); 19233 return; 19234 } 19235 // determine versioning scheme 19236 let versioning = this.Versioning.None; 19237 this.targetObject = targetObject; 19238 if (targetObject.isMaterial === true) { 19239 versioning = this.Versioning.NeedsUpdate; 19240 } else if (targetObject.isObject3D === true) { 19241 versioning = this.Versioning.MatrixWorldNeedsUpdate; 19242 } 19243 // determine how the property gets bound 19244 let bindingType = this.BindingType.Direct; 19245 if (propertyIndex !== undefined) { 19246 // access a sub element of the property array (only primitives are supported right now) 19247 if (propertyName === 'morphTargetInfluences') { 19248 // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. 19249 // support resolving morphTarget names into indices. 19250 if (!targetObject.geometry) { 19251 console.error('THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this); 19252 return; 19253 } 19254 if (!targetObject.geometry.morphAttributes) { 19255 console.error('THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this); 19256 return; 19257 } 19258 if (targetObject.morphTargetDictionary[propertyIndex] !== undefined) { 19259 propertyIndex = targetObject.morphTargetDictionary[propertyIndex]; 19260 } 19261 } 19262 bindingType = this.BindingType.ArrayElement; 19263 this.resolvedProperty = nodeProperty; 19264 this.propertyIndex = propertyIndex; 19265 } else if (nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined) { 19266 // must use copy for Object3D.Euler/Quaternion 19267 bindingType = this.BindingType.HasFromToArray; 19268 this.resolvedProperty = nodeProperty; 19269 } else if (Array.isArray(nodeProperty)) { 19270 bindingType = this.BindingType.EntireArray; 19271 this.resolvedProperty = nodeProperty; 19272 } else { 19273 this.propertyName = propertyName; 19274 } 19275 // select getter / setter 19276 this.getValue = this.GetterByBindingType[bindingType]; 19277 this.setValue = this.SetterByBindingTypeAndVersioning[bindingType][versioning]; 19278 } 19279 unbind() { 19280 this.node = null; 19281 // back to the prototype version of getValue / setValue 19282 // note: avoiding to mutate the shape of 'this' via 'delete' 19283 this.getValue = this._getValue_unbound; 19284 this.setValue = this._setValue_unbound; 19285 } 19286 constructor(rootNode, path, parsedPath){ 19287 this.path = path; 19288 this.parsedPath = parsedPath || PropertyBinding.parseTrackName(path); 19289 this.node = PropertyBinding.findNode(rootNode, this.parsedPath.nodeName); 19290 this.rootNode = rootNode; 19291 // initial state of these methods that calls 'bind' 19292 this.getValue = this._getValue_unbound; 19293 this.setValue = this._setValue_unbound; 19294 } 19295 } 19296 PropertyBinding.Composite = Composite; 19297 PropertyBinding.prototype.BindingType = { 19298 Direct: 0, 19299 EntireArray: 1, 19300 ArrayElement: 2, 19301 HasFromToArray: 3 19302 }; 19303 PropertyBinding.prototype.Versioning = { 19304 None: 0, 19305 NeedsUpdate: 1, 19306 MatrixWorldNeedsUpdate: 2 19307 }; 19308 PropertyBinding.prototype.GetterByBindingType = [ 19309 PropertyBinding.prototype._getValue_direct, 19310 PropertyBinding.prototype._getValue_array, 19311 PropertyBinding.prototype._getValue_arrayElement, 19312 PropertyBinding.prototype._getValue_toArray 19313 ]; 19314 PropertyBinding.prototype.SetterByBindingTypeAndVersioning = [ 19315 [ 19316 // Direct 19317 PropertyBinding.prototype._setValue_direct, 19318 PropertyBinding.prototype._setValue_direct_setNeedsUpdate, 19319 PropertyBinding.prototype._setValue_direct_setMatrixWorldNeedsUpdate 19320 ], 19321 [ 19322 // EntireArray 19323 PropertyBinding.prototype._setValue_array, 19324 PropertyBinding.prototype._setValue_array_setNeedsUpdate, 19325 PropertyBinding.prototype._setValue_array_setMatrixWorldNeedsUpdate 19326 ], 19327 [ 19328 // ArrayElement 19329 PropertyBinding.prototype._setValue_arrayElement, 19330 PropertyBinding.prototype._setValue_arrayElement_setNeedsUpdate, 19331 PropertyBinding.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate 19332 ], 19333 [ 19334 // HasToFromArray 19335 PropertyBinding.prototype._setValue_fromArray, 19336 PropertyBinding.prototype._setValue_fromArray_setNeedsUpdate, 19337 PropertyBinding.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate 19338 ] 19339 ]; 19340 class AnimationAction { 19341 // State & Scheduling 19342 play() { 19343 this._mixer._activateAction(this); 19344 return this; 19345 } 19346 stop() { 19347 this._mixer._deactivateAction(this); 19348 return this.reset(); 19349 } 19350 reset() { 19351 this.paused = false; 19352 this.enabled = true; 19353 this.time = 0; // restart clip 19354 this._loopCount = -1; // forget previous loops 19355 this._startTime = null; // forget scheduling 19356 return this.stopFading().stopWarping(); 19357 } 19358 isRunning() { 19359 return this.enabled && !this.paused && this.timeScale !== 0 && this._startTime === null && this._mixer._isActiveAction(this); 19360 } 19361 // return true when play has been called 19362 isScheduled() { 19363 return this._mixer._isActiveAction(this); 19364 } 19365 startAt(time) { 19366 this._startTime = time; 19367 return this; 19368 } 19369 setLoop(mode, repetitions) { 19370 this.loop = mode; 19371 this.repetitions = repetitions; 19372 return this; 19373 } 19374 // Weight 19375 // set the weight stopping any scheduled fading 19376 // although .enabled = false yields an effective weight of zero, this 19377 // method does *not* change .enabled, because it would be confusing 19378 setEffectiveWeight(weight) { 19379 this.weight = weight; 19380 // note: same logic as when updated at runtime 19381 this._effectiveWeight = this.enabled ? weight : 0; 19382 return this.stopFading(); 19383 } 19384 // return the weight considering fading and .enabled 19385 getEffectiveWeight() { 19386 return this._effectiveWeight; 19387 } 19388 fadeIn(duration) { 19389 return this._scheduleFading(duration, 0, 1); 19390 } 19391 fadeOut(duration) { 19392 return this._scheduleFading(duration, 1, 0); 19393 } 19394 crossFadeFrom(fadeOutAction, duration, warp) { 19395 fadeOutAction.fadeOut(duration); 19396 this.fadeIn(duration); 19397 if (warp) { 19398 const fadeInDuration = this._clip.duration, fadeOutDuration = fadeOutAction._clip.duration, startEndRatio = fadeOutDuration / fadeInDuration, endStartRatio = fadeInDuration / fadeOutDuration; 19399 fadeOutAction.warp(1.0, startEndRatio, duration); 19400 this.warp(endStartRatio, 1.0, duration); 19401 } 19402 return this; 19403 } 19404 crossFadeTo(fadeInAction, duration, warp) { 19405 return fadeInAction.crossFadeFrom(this, duration, warp); 19406 } 19407 stopFading() { 19408 const weightInterpolant = this._weightInterpolant; 19409 if (weightInterpolant !== null) { 19410 this._weightInterpolant = null; 19411 this._mixer._takeBackControlInterpolant(weightInterpolant); 19412 } 19413 return this; 19414 } 19415 // Time Scale Control 19416 // set the time scale stopping any scheduled warping 19417 // although .paused = true yields an effective time scale of zero, this 19418 // method does *not* change .paused, because it would be confusing 19419 setEffectiveTimeScale(timeScale) { 19420 this.timeScale = timeScale; 19421 this._effectiveTimeScale = this.paused ? 0 : timeScale; 19422 return this.stopWarping(); 19423 } 19424 // return the time scale considering warping and .paused 19425 getEffectiveTimeScale() { 19426 return this._effectiveTimeScale; 19427 } 19428 setDuration(duration) { 19429 this.timeScale = this._clip.duration / duration; 19430 return this.stopWarping(); 19431 } 19432 syncWith(action) { 19433 this.time = action.time; 19434 this.timeScale = action.timeScale; 19435 return this.stopWarping(); 19436 } 19437 halt(duration) { 19438 return this.warp(this._effectiveTimeScale, 0, duration); 19439 } 19440 warp(startTimeScale, endTimeScale, duration) { 19441 const mixer = this._mixer, now = mixer.time, timeScale = this.timeScale; 19442 let interpolant = this._timeScaleInterpolant; 19443 if (interpolant === null) { 19444 interpolant = mixer._lendControlInterpolant(); 19445 this._timeScaleInterpolant = interpolant; 19446 } 19447 const times = interpolant.parameterPositions, values = interpolant.sampleValues; 19448 times[0] = now; 19449 times[1] = now + duration; 19450 values[0] = startTimeScale / timeScale; 19451 values[1] = endTimeScale / timeScale; 19452 return this; 19453 } 19454 stopWarping() { 19455 const timeScaleInterpolant = this._timeScaleInterpolant; 19456 if (timeScaleInterpolant !== null) { 19457 this._timeScaleInterpolant = null; 19458 this._mixer._takeBackControlInterpolant(timeScaleInterpolant); 19459 } 19460 return this; 19461 } 19462 // Object Accessors 19463 getMixer() { 19464 return this._mixer; 19465 } 19466 getClip() { 19467 return this._clip; 19468 } 19469 getRoot() { 19470 return this._localRoot || this._mixer._root; 19471 } 19472 // Interna 19473 _update(time, deltaTime, timeDirection, accuIndex) { 19474 // called by the mixer 19475 if (!this.enabled) { 19476 // call ._updateWeight() to update ._effectiveWeight 19477 this._updateWeight(time); 19478 return; 19479 } 19480 const startTime = this._startTime; 19481 if (startTime !== null) { 19482 // check for scheduled start of action 19483 const timeRunning = (time - startTime) * timeDirection; 19484 if (timeRunning < 0 || timeDirection === 0) { 19485 deltaTime = 0; 19486 } else { 19487 this._startTime = null; // unschedule 19488 deltaTime = timeDirection * timeRunning; 19489 } 19490 } 19491 // apply time scale and advance time 19492 deltaTime *= this._updateTimeScale(time); 19493 const clipTime = this._updateTime(deltaTime); 19494 // note: _updateTime may disable the action resulting in 19495 // an effective weight of 0 19496 const weight = this._updateWeight(time); 19497 if (weight > 0) { 19498 const interpolants = this._interpolants; 19499 const propertyMixers = this._propertyBindings; 19500 switch(this.blendMode){ 19501 case AdditiveAnimationBlendMode: 19502 for(let j = 0, m = interpolants.length; j !== m; ++j){ 19503 interpolants[j].evaluate(clipTime); 19504 propertyMixers[j].accumulateAdditive(weight); 19505 } 19506 break; 19507 case NormalAnimationBlendMode: 19508 default: 19509 for(let j = 0, m = interpolants.length; j !== m; ++j){ 19510 interpolants[j].evaluate(clipTime); 19511 propertyMixers[j].accumulate(accuIndex, weight); 19512 } 19513 } 19514 } 19515 } 19516 _updateWeight(time) { 19517 let weight = 0; 19518 if (this.enabled) { 19519 weight = this.weight; 19520 const interpolant = this._weightInterpolant; 19521 if (interpolant !== null) { 19522 const interpolantValue = interpolant.evaluate(time)[0]; 19523 weight *= interpolantValue; 19524 if (time > interpolant.parameterPositions[1]) { 19525 this.stopFading(); 19526 if (interpolantValue === 0) { 19527 // faded out, disable 19528 this.enabled = false; 19529 } 19530 } 19531 } 19532 } 19533 this._effectiveWeight = weight; 19534 return weight; 19535 } 19536 _updateTimeScale(time) { 19537 let timeScale = 0; 19538 if (!this.paused) { 19539 timeScale = this.timeScale; 19540 const interpolant = this._timeScaleInterpolant; 19541 if (interpolant !== null) { 19542 const interpolantValue = interpolant.evaluate(time)[0]; 19543 timeScale *= interpolantValue; 19544 if (time > interpolant.parameterPositions[1]) { 19545 this.stopWarping(); 19546 if (timeScale === 0) { 19547 // motion has halted, pause 19548 this.paused = true; 19549 } else { 19550 // warp done - apply final time scale 19551 this.timeScale = timeScale; 19552 } 19553 } 19554 } 19555 } 19556 this._effectiveTimeScale = timeScale; 19557 return timeScale; 19558 } 19559 _updateTime(deltaTime) { 19560 const duration = this._clip.duration; 19561 const loop = this.loop; 19562 let time = this.time + deltaTime; 19563 let loopCount = this._loopCount; 19564 const pingPong = loop === LoopPingPong; 19565 if (deltaTime === 0) { 19566 if (loopCount === -1) return time; 19567 return pingPong && (loopCount & 1) === 1 ? duration - time : time; 19568 } 19569 if (loop === LoopOnce) { 19570 if (loopCount === -1) { 19571 // just started 19572 this._loopCount = 0; 19573 this._setEndings(true, true, false); 19574 } 19575 handle_stop: { 19576 if (time >= duration) { 19577 time = duration; 19578 } else if (time < 0) { 19579 time = 0; 19580 } else { 19581 this.time = time; 19582 break handle_stop; 19583 } 19584 if (this.clampWhenFinished) this.paused = true; 19585 else this.enabled = false; 19586 this.time = time; 19587 this._mixer.dispatchEvent({ 19588 type: 'finished', 19589 action: this, 19590 direction: deltaTime < 0 ? -1 : 1 19591 }); 19592 } 19593 } else { 19594 if (loopCount === -1) { 19595 // just started 19596 if (deltaTime >= 0) { 19597 loopCount = 0; 19598 this._setEndings(true, this.repetitions === 0, pingPong); 19599 } else { 19600 // when looping in reverse direction, the initial 19601 // transition through zero counts as a repetition, 19602 // so leave loopCount at -1 19603 this._setEndings(this.repetitions === 0, true, pingPong); 19604 } 19605 } 19606 if (time >= duration || time < 0) { 19607 // wrap around 19608 const loopDelta = Math.floor(time / duration); // signed 19609 time -= duration * loopDelta; 19610 loopCount += Math.abs(loopDelta); 19611 const pending = this.repetitions - loopCount; 19612 if (pending <= 0) { 19613 // have to stop (switch state, clamp time, fire event) 19614 if (this.clampWhenFinished) this.paused = true; 19615 else this.enabled = false; 19616 time = deltaTime > 0 ? duration : 0; 19617 this.time = time; 19618 this._mixer.dispatchEvent({ 19619 type: 'finished', 19620 action: this, 19621 direction: deltaTime > 0 ? 1 : -1 19622 }); 19623 } else { 19624 // keep running 19625 if (pending === 1) { 19626 // entering the last round 19627 const atStart = deltaTime < 0; 19628 this._setEndings(atStart, !atStart, pingPong); 19629 } else { 19630 this._setEndings(false, false, pingPong); 19631 } 19632 this._loopCount = loopCount; 19633 this.time = time; 19634 this._mixer.dispatchEvent({ 19635 type: 'loop', 19636 action: this, 19637 loopDelta: loopDelta 19638 }); 19639 } 19640 } else { 19641 this.time = time; 19642 } 19643 if (pingPong && (loopCount & 1) === 1) { 19644 // invert time for the "pong round" 19645 return duration - time; 19646 } 19647 } 19648 return time; 19649 } 19650 _setEndings(atStart, atEnd, pingPong) { 19651 const settings = this._interpolantSettings; 19652 if (pingPong) { 19653 settings.endingStart = ZeroSlopeEnding; 19654 settings.endingEnd = ZeroSlopeEnding; 19655 } else { 19656 // assuming for LoopOnce atStart == atEnd == true 19657 if (atStart) { 19658 settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding; 19659 } else { 19660 settings.endingStart = WrapAroundEnding; 19661 } 19662 if (atEnd) { 19663 settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding; 19664 } else { 19665 settings.endingEnd = WrapAroundEnding; 19666 } 19667 } 19668 } 19669 _scheduleFading(duration, weightNow, weightThen) { 19670 const mixer = this._mixer, now = mixer.time; 19671 let interpolant = this._weightInterpolant; 19672 if (interpolant === null) { 19673 interpolant = mixer._lendControlInterpolant(); 19674 this._weightInterpolant = interpolant; 19675 } 19676 const times = interpolant.parameterPositions, values = interpolant.sampleValues; 19677 times[0] = now; 19678 values[0] = weightNow; 19679 times[1] = now + duration; 19680 values[1] = weightThen; 19681 return this; 19682 } 19683 constructor(mixer, clip, localRoot = null, blendMode = clip.blendMode){ 19684 this._mixer = mixer; 19685 this._clip = clip; 19686 this._localRoot = localRoot; 19687 this.blendMode = blendMode; 19688 const tracks = clip.tracks, nTracks = tracks.length, interpolants = new Array(nTracks); 19689 const interpolantSettings = { 19690 endingStart: ZeroCurvatureEnding, 19691 endingEnd: ZeroCurvatureEnding 19692 }; 19693 for(let i = 0; i !== nTracks; ++i){ 19694 const interpolant = tracks[i].createInterpolant(null); 19695 interpolants[i] = interpolant; 19696 interpolant.settings = interpolantSettings; 19697 } 19698 this._interpolantSettings = interpolantSettings; 19699 this._interpolants = interpolants; // bound by the mixer 19700 // inside: PropertyMixer (managed by the mixer) 19701 this._propertyBindings = new Array(nTracks); 19702 this._cacheIndex = null; // for the memory manager 19703 this._byClipCacheIndex = null; // for the memory manager 19704 this._timeScaleInterpolant = null; 19705 this._weightInterpolant = null; 19706 this.loop = LoopRepeat; 19707 this._loopCount = -1; 19708 // global mixer time when the action is to be started 19709 // it's set back to 'null' upon start of the action 19710 this._startTime = null; 19711 // scaled local time of the action 19712 // gets clamped or wrapped to 0..clip.duration according to loop 19713 this.time = 0; 19714 this.timeScale = 1; 19715 this._effectiveTimeScale = 1; 19716 this.weight = 1; 19717 this._effectiveWeight = 1; 19718 this.repetitions = Infinity; // no. of repetitions when looping 19719 this.paused = false; // true -> zero effective time scale 19720 this.enabled = true; // false -> zero effective weight 19721 this.clampWhenFinished = false; // keep feeding the last frame? 19722 this.zeroSlopeAtStart = true; // for smooth interpolation w/o separate 19723 this.zeroSlopeAtEnd = true; // clips for start, loop and end 19724 } 19725 } 19726 const _controlInterpolantsResultBuffer = new Float32Array(1);
vendor: 14,413 bytes, lines 19727-20022
19727 class AnimationMixer extends EventDispatcher { 19728 _bindAction(action, prototypeAction) { 19729 const root = action._localRoot || this._root, tracks = action._clip.tracks, nTracks = tracks.length, bindings = action._propertyBindings, interpolants = action._interpolants, rootUuid = root.uuid, bindingsByRoot = this._bindingsByRootAndName; 19730 let bindingsByName = bindingsByRoot[rootUuid]; 19731 if (bindingsByName === undefined) { 19732 bindingsByName = {}; 19733 bindingsByRoot[rootUuid] = bindingsByName; 19734 } 19735 for(let i = 0; i !== nTracks; ++i){ 19736 const track = tracks[i], trackName = track.name; 19737 let binding = bindingsByName[trackName]; 19738 if (binding !== undefined) { 19739 ++binding.referenceCount; 19740 bindings[i] = binding; 19741 } else { 19742 binding = bindings[i]; 19743 if (binding !== undefined) { 19744 // existing binding, make sure the cache knows 19745 if (binding._cacheIndex === null) { 19746 ++binding.referenceCount; 19747 this._addInactiveBinding(binding, rootUuid, trackName); 19748 } 19749 continue; 19750 } 19751 const path = prototypeAction && prototypeAction._propertyBindings[i].binding.parsedPath; 19752 binding = new PropertyMixer(PropertyBinding.create(root, trackName, path), track.ValueTypeName, track.getValueSize()); 19753 ++binding.referenceCount; 19754 this._addInactiveBinding(binding, rootUuid, trackName); 19755 bindings[i] = binding; 19756 } 19757 interpolants[i].resultBuffer = binding.buffer; 19758 } 19759 } 19760 _activateAction(action) { 19761 if (!this._isActiveAction(action)) { 19762 if (action._cacheIndex === null) { 19763 // this action has been forgotten by the cache, but the user 19764 // appears to be still using it -> rebind 19765 const rootUuid = (action._localRoot || this._root).uuid, clipUuid = action._clip.uuid, actionsForClip = this._actionsByClip[clipUuid]; 19766 this._bindAction(action, actionsForClip && actionsForClip.knownActions[0]); 19767 this._addInactiveAction(action, clipUuid, rootUuid); 19768 } 19769 const bindings = action._propertyBindings; 19770 // increment reference counts / sort out state 19771 for(let i = 0, n = bindings.length; i !== n; ++i){ 19772 const binding = bindings[i]; 19773 if (binding.useCount++ === 0) { 19774 this._lendBinding(binding); 19775 binding.saveOriginalState(); 19776 } 19777 } 19778 this._lendAction(action); 19779 } 19780 } 19781 _deactivateAction(action) { 19782 if (this._isActiveAction(action)) { 19783 const bindings = action._propertyBindings; 19784 // decrement reference counts / sort out state 19785 for(let i = 0, n = bindings.length; i !== n; ++i){ 19786 const binding = bindings[i]; 19787 if (--binding.useCount === 0) { 19788 binding.restoreOriginalState(); 19789 this._takeBackBinding(binding); 19790 } 19791 } 19792 this._takeBackAction(action); 19793 } 19794 } 19795 // Memory manager 19796 _initMemoryManager() { 19797 this._actions = []; // 'nActiveActions' followed by inactive ones 19798 this._nActiveActions = 0; 19799 this._actionsByClip = {}; 19800 // inside: 19801 // { 19802 // knownActions: Array< AnimationAction > - used as prototypes 19803 // actionByRoot: AnimationAction - lookup 19804 // } 19805 this._bindings = []; // 'nActiveBindings' followed by inactive ones 19806 this._nActiveBindings = 0; 19807 this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer > 19808 this._controlInterpolants = []; // same game as above 19809 this._nActiveControlInterpolants = 0; 19810 const scope = this; 19811 this.stats = { 19812 actions: { 19813 get total () { 19814 return scope._actions.length; 19815 }, 19816 get inUse () { 19817 return scope._nActiveActions; 19818 } 19819 }, 19820 bindings: { 19821 get total () { 19822 return scope._bindings.length; 19823 }, 19824 get inUse () { 19825 return scope._nActiveBindings; 19826 } 19827 }, 19828 controlInterpolants: { 19829 get total () { 19830 return scope._controlInterpolants.length; 19831 }, 19832 get inUse () { 19833 return scope._nActiveControlInterpolants; 19834 } 19835 } 19836 }; 19837 } 19838 // Memory management for AnimationAction objects 19839 _isActiveAction(action) { 19840 const index = action._cacheIndex; 19841 return index !== null && index < this._nActiveActions; 19842 } 19843 _addInactiveAction(action, clipUuid, rootUuid) { 19844 const actions = this._actions, actionsByClip = this._actionsByClip; 19845 let actionsForClip = actionsByClip[clipUuid]; 19846 if (actionsForClip === undefined) { 19847 actionsForClip = { 19848 knownActions: [ 19849 action 19850 ], 19851 actionByRoot: {} 19852 }; 19853 action._byClipCacheIndex = 0; 19854 actionsByClip[clipUuid] = actionsForClip; 19855 } else { 19856 const knownActions = actionsForClip.knownActions; 19857 action._byClipCacheIndex = knownActions.length; 19858 knownActions.push(action); 19859 } 19860 action._cacheIndex = actions.length; 19861 actions.push(action); 19862 actionsForClip.actionByRoot[rootUuid] = action; 19863 } 19864 _removeInactiveAction(action) { 19865 const actions = this._actions, lastInactiveAction = actions[actions.length - 1], cacheIndex = action._cacheIndex; 19866 lastInactiveAction._cacheIndex = cacheIndex; 19867 actions[cacheIndex] = lastInactiveAction; 19868 actions.pop(); 19869 action._cacheIndex = null; 19870 const clipUuid = action._clip.uuid, actionsByClip = this._actionsByClip, actionsForClip = actionsByClip[clipUuid], knownActionsForClip = actionsForClip.knownActions, lastKnownAction = knownActionsForClip[knownActionsForClip.length - 1], byClipCacheIndex = action._byClipCacheIndex; 19871 lastKnownAction._byClipCacheIndex = byClipCacheIndex; 19872 knownActionsForClip[byClipCacheIndex] = lastKnownAction; 19873 knownActionsForClip.pop(); 19874 action._byClipCacheIndex = null; 19875 const actionByRoot = actionsForClip.actionByRoot, rootUuid = (action._localRoot || this._root).uuid; 19876 delete actionByRoot[rootUuid]; 19877 if (knownActionsForClip.length === 0) { 19878 delete actionsByClip[clipUuid]; 19879 } 19880 this._removeInactiveBindingsForAction(action); 19881 } 19882 _removeInactiveBindingsForAction(action) { 19883 const bindings = action._propertyBindings; 19884 for(let i = 0, n = bindings.length; i !== n; ++i){ 19885 const binding = bindings[i]; 19886 if (--binding.referenceCount === 0) { 19887 this._removeInactiveBinding(binding); 19888 } 19889 } 19890 } 19891 _lendAction(action) { 19892 // [ active actions | inactive actions ] 19893 // [ active actions >| inactive actions ] 19894 // s a 19895 // <-swap-> 19896 // a s 19897 const actions = this._actions, prevIndex = action._cacheIndex, lastActiveIndex = this._nActiveActions++, firstInactiveAction = actions[lastActiveIndex]; 19898 action._cacheIndex = lastActiveIndex; 19899 actions[lastActiveIndex] = action; 19900 firstInactiveAction._cacheIndex = prevIndex; 19901 actions[prevIndex] = firstInactiveAction; 19902 } 19903 _takeBackAction(action) { 19904 // [ active actions | inactive actions ] 19905 // [ active actions |< inactive actions ] 19906 // a s 19907 // <-swap-> 19908 // s a 19909 const actions = this._actions, prevIndex = action._cacheIndex, firstInactiveIndex = --this._nActiveActions, lastActiveAction = actions[firstInactiveIndex]; 19910 action._cacheIndex = firstInactiveIndex; 19911 actions[firstInactiveIndex] = action; 19912 lastActiveAction._cacheIndex = prevIndex; 19913 actions[prevIndex] = lastActiveAction; 19914 } 19915 // Memory management for PropertyMixer objects 19916 _addInactiveBinding(binding, rootUuid, trackName) { 19917 const bindingsByRoot = this._bindingsByRootAndName, bindings = this._bindings; 19918 let bindingByName = bindingsByRoot[rootUuid]; 19919 if (bindingByName === undefined) { 19920 bindingByName = {}; 19921 bindingsByRoot[rootUuid] = bindingByName; 19922 } 19923 bindingByName[trackName] = binding; 19924 binding._cacheIndex = bindings.length; 19925 bindings.push(binding); 19926 } 19927 _removeInactiveBinding(binding) { 19928 const bindings = this._bindings, propBinding = binding.binding, rootUuid = propBinding.rootNode.uuid, trackName = propBinding.path, bindingsByRoot = this._bindingsByRootAndName, bindingByName = bindingsByRoot[rootUuid], lastInactiveBinding = bindings[bindings.length - 1], cacheIndex = binding._cacheIndex; 19929 lastInactiveBinding._cacheIndex = cacheIndex; 19930 bindings[cacheIndex] = lastInactiveBinding; 19931 bindings.pop(); 19932 delete bindingByName[trackName]; 19933 if (Object.keys(bindingByName).length === 0) { 19934 delete bindingsByRoot[rootUuid]; 19935 } 19936 } 19937 _lendBinding(binding) { 19938 const bindings = this._bindings, prevIndex = binding._cacheIndex, lastActiveIndex = this._nActiveBindings++, firstInactiveBinding = bindings[lastActiveIndex]; 19939 binding._cacheIndex = lastActiveIndex; 19940 bindings[lastActiveIndex] = binding; 19941 firstInactiveBinding._cacheIndex = prevIndex; 19942 bindings[prevIndex] = firstInactiveBinding; 19943 } 19944 _takeBackBinding(binding) { 19945 const bindings = this._bindings, prevIndex = binding._cacheIndex, firstInactiveIndex = --this._nActiveBindings, lastActiveBinding = bindings[firstInactiveIndex]; 19946 binding._cacheIndex = firstInactiveIndex; 19947 bindings[firstInactiveIndex] = binding; 19948 lastActiveBinding._cacheIndex = prevIndex; 19949 bindings[prevIndex] = lastActiveBinding; 19950 } 19951 // Memory management of Interpolants for weight and time scale 19952 _lendControlInterpolant() { 19953 const interpolants = this._controlInterpolants, lastActiveIndex = this._nActiveControlInterpolants++; 19954 let interpolant = interpolants[lastActiveIndex]; 19955 if (interpolant === undefined) { 19956 interpolant = new LinearInterpolant(new Float32Array(2), new Float32Array(2), 1, _controlInterpolantsResultBuffer); 19957 interpolant.__cacheIndex = lastActiveIndex; 19958 interpolants[lastActiveIndex] = interpolant; 19959 } 19960 return interpolant; 19961 } 19962 _takeBackControlInterpolant(interpolant) { 19963 const interpolants = this._controlInterpolants, prevIndex = interpolant.__cacheIndex, firstInactiveIndex = --this._nActiveControlInterpolants, lastActiveInterpolant = interpolants[firstInactiveIndex]; 19964 interpolant.__cacheIndex = firstInactiveIndex; 19965 interpolants[firstInactiveIndex] = interpolant; 19966 lastActiveInterpolant.__cacheIndex = prevIndex; 19967 interpolants[prevIndex] = lastActiveInterpolant; 19968 } 19969 // return an action for a clip optionally using a custom root target 19970 // object (this method allocates a lot of dynamic memory in case a 19971 // previously unknown clip/root combination is specified) 19972 clipAction(clip, optionalRoot, blendMode) { 19973 const root = optionalRoot || this._root, rootUuid = root.uuid; 19974 let clipObject = typeof clip === 'string' ? AnimationClip.findByName(root, clip) : clip; 19975 const clipUuid = clipObject !== null ? clipObject.uuid : clip; 19976 const actionsForClip = this._actionsByClip[clipUuid]; 19977 let prototypeAction = null; 19978 if (blendMode === undefined) { 19979 if (clipObject !== null) { 19980 blendMode = clipObject.blendMode; 19981 } else { 19982 blendMode = NormalAnimationBlendMode; 19983 } 19984 } 19985 if (actionsForClip !== undefined) { 19986 const existingAction = actionsForClip.actionByRoot[rootUuid]; 19987 if (existingAction !== undefined && existingAction.blendMode === blendMode) { 19988 return existingAction; 19989 } 19990 // we know the clip, so we don't have to parse all 19991 // the bindings again but can just copy 19992 prototypeAction = actionsForClip.knownActions[0]; 19993 // also, take the clip from the prototype action 19994 if (clipObject === null) clipObject = prototypeAction._clip; 19995 } 19996 // clip must be known when specified via string 19997 if (clipObject === null) return null; 19998 // allocate all resources required to run it 19999 const newAction = new AnimationAction(this, clipObject, optionalRoot, blendMode); 20000 this._bindAction(newAction, prototypeAction); 20001 // and make the action known to the memory manager 20002 this._addInactiveAction(newAction, clipUuid, rootUuid); 20003 return newAction; 20004 } 20005 // get an existing action 20006 existingAction(clip, optionalRoot) { 20007 const root = optionalRoot || this._root, rootUuid = root.uuid, clipObject = typeof clip === 'string' ? AnimationClip.findByName(root, clip) : clip, clipUuid = clipObject ? clipObject.uuid : clip, actionsForClip = this._actionsByClip[clipUuid]; 20008 if (actionsForClip !== undefined) { 20009 return actionsForClip.actionByRoot[rootUuid] || null; 20010 } 20011 return null; 20012 } 20013 // deactivates all previously scheduled actions 20014 stopAllAction() { 20015 const actions = this._actions, nActions = this._nActiveActions; 20016 for(let i = nActions - 1; i >= 0; --i){ 20017 actions[i].stop(); 20018 } 20019 return this; 20020 } 20021 // advance the time and update apply the animation 20022 update(deltaTime) {
vendor: 9,594 bytes, lines 20023-20263
20023 deltaTime *= this.timeScale; 20024 const actions = this._actions, nActions = this._nActiveActions, time = this.time += deltaTime, timeDirection = Math.sign(deltaTime), accuIndex = this._accuIndex ^= 1; 20025 // run active actions 20026 for(let i = 0; i !== nActions; ++i){ 20027 const action = actions[i]; 20028 action._update(time, deltaTime, timeDirection, accuIndex); 20029 } 20030 // update scene graph 20031 const bindings = this._bindings, nBindings = this._nActiveBindings; 20032 for(let i = 0; i !== nBindings; ++i){ 20033 bindings[i].apply(accuIndex); 20034 } 20035 return this; 20036 } 20037 // Allows you to seek to a specific time in an animation. 20038 setTime(timeInSeconds) { 20039 this.time = 0; // Zero out time attribute for AnimationMixer object; 20040 for(let i = 0; i < this._actions.length; i++){ 20041 this._actions[i].time = 0; // Zero out time attribute for all associated AnimationAction objects. 20042 } 20043 return this.update(timeInSeconds); // Update used to set exact time. Returns "this" AnimationMixer object. 20044 } 20045 // return this mixer's root target object 20046 getRoot() { 20047 return this._root; 20048 } 20049 // free all resources specific to a particular clip 20050 uncacheClip(clip) { 20051 const actions = this._actions, clipUuid = clip.uuid, actionsByClip = this._actionsByClip, actionsForClip = actionsByClip[clipUuid]; 20052 if (actionsForClip !== undefined) { 20053 // note: just calling _removeInactiveAction would mess up the 20054 // iteration state and also require updating the state we can 20055 // just throw away 20056 const actionsToRemove = actionsForClip.knownActions; 20057 for(let i = 0, n = actionsToRemove.length; i !== n; ++i){ 20058 const action = actionsToRemove[i]; 20059 this._deactivateAction(action); 20060 const cacheIndex = action._cacheIndex, lastInactiveAction = actions[actions.length - 1]; 20061 action._cacheIndex = null; 20062 action._byClipCacheIndex = null; 20063 lastInactiveAction._cacheIndex = cacheIndex; 20064 actions[cacheIndex] = lastInactiveAction; 20065 actions.pop(); 20066 this._removeInactiveBindingsForAction(action); 20067 } 20068 delete actionsByClip[clipUuid]; 20069 } 20070 } 20071 // free all resources specific to a particular root target object 20072 uncacheRoot(root) { 20073 const rootUuid = root.uuid, actionsByClip = this._actionsByClip; 20074 for(const clipUuid in actionsByClip){ 20075 const actionByRoot = actionsByClip[clipUuid].actionByRoot, action = actionByRoot[rootUuid]; 20076 if (action !== undefined) { 20077 this._deactivateAction(action); 20078 this._removeInactiveAction(action); 20079 } 20080 } 20081 const bindingsByRoot = this._bindingsByRootAndName, bindingByName = bindingsByRoot[rootUuid]; 20082 if (bindingByName !== undefined) { 20083 for(const trackName in bindingByName){ 20084 const binding = bindingByName[trackName]; 20085 binding.restoreOriginalState(); 20086 this._removeInactiveBinding(binding); 20087 } 20088 } 20089 } 20090 // remove a targeted clip from the cache 20091 uncacheAction(clip, optionalRoot) { 20092 const action = this.existingAction(clip, optionalRoot); 20093 if (action !== null) { 20094 this._deactivateAction(action); 20095 this._removeInactiveAction(action); 20096 } 20097 } 20098 constructor(root){ 20099 super(); 20100 this._root = root; 20101 this._initMemoryManager(); 20102 this._accuIndex = 0; 20103 this.time = 0; 20104 this.timeScale = 1.0; 20105 } 20106 } 20107 const _matrix = /*@__PURE__*/ new Matrix4(); 20108 class Raycaster { 20109 set(origin, direction) { 20110 // direction is assumed to be normalized (for accurate distance calculations) 20111 this.ray.set(origin, direction); 20112 } 20113 setFromCamera(coords, camera) { 20114 if (camera.isPerspectiveCamera) { 20115 this.ray.origin.setFromMatrixPosition(camera.matrixWorld); 20116 this.ray.direction.set(coords.x, coords.y, 0.5).unproject(camera).sub(this.ray.origin).normalize(); 20117 this.camera = camera; 20118 } else if (camera.isOrthographicCamera) { 20119 this.ray.origin.set(coords.x, coords.y, (camera.near + camera.far) / (camera.near - camera.far)).unproject(camera); // set origin in plane of camera 20120 this.ray.direction.set(0, 0, -1).transformDirection(camera.matrixWorld); 20121 this.camera = camera; 20122 } else { 20123 console.error('THREE.Raycaster: Unsupported camera type: ' + camera.type); 20124 } 20125 } 20126 setFromXRController(controller) { 20127 _matrix.identity().extractRotation(controller.matrixWorld); 20128 this.ray.origin.setFromMatrixPosition(controller.matrixWorld); 20129 this.ray.direction.set(0, 0, -1).applyMatrix4(_matrix); 20130 return this; 20131 } 20132 intersectObject(object, recursive = true, intersects = []) { 20133 intersect(object, this, intersects, recursive); 20134 intersects.sort(ascSort); 20135 return intersects; 20136 } 20137 intersectObjects(objects, recursive = true, intersects = []) { 20138 for(let i = 0, l = objects.length; i < l; i++){ 20139 intersect(objects[i], this, intersects, recursive); 20140 } 20141 intersects.sort(ascSort); 20142 return intersects; 20143 } 20144 constructor(origin, direction, near = 0, far = Infinity){ 20145 this.ray = new Ray(origin, direction); 20146 // direction is assumed to be normalized (for accurate distance calculations) 20147 this.near = near; 20148 this.far = far; 20149 this.camera = null; 20150 this.layers = new Layers(); 20151 this.params = { 20152 Mesh: {}, 20153 Line: { 20154 threshold: 1 20155 }, 20156 LOD: {}, 20157 Points: { 20158 threshold: 1 20159 }, 20160 Sprite: {} 20161 }; 20162 } 20163 } 20164 function ascSort(a, b) { 20165 return a.distance - b.distance; 20166 } 20167 function intersect(object, raycaster, intersects, recursive) { 20168 let propagate = true; 20169 if (object.layers.test(raycaster.layers)) { 20170 const result = object.raycast(raycaster, intersects); 20171 if (result === false) propagate = false; 20172 } 20173 if (propagate === true && recursive === true) { 20174 const children = object.children; 20175 for(let i = 0, l = children.length; i < l; i++){ 20176 intersect(children[i], raycaster, intersects, true); 20177 } 20178 } 20179 } 20180 /** 20181 * This class can be used to represent points in 3D space as 20182 * [Spherical coordinates]{@link https://en.wikipedia.org/wiki/Spherical_coordinate_system}. 20183 */ class Spherical { 20184 /** 20185 * Sets the spherical components by copying the given values. 20186 * 20187 * @param {number} radius - The radius. 20188 * @param {number} phi - The polar angle. 20189 * @param {number} theta - The azimuthal angle. 20190 * @return {Spherical} A reference to this spherical. 20191 */ set(radius, phi, theta) { 20192 this.radius = radius; 20193 this.phi = phi; 20194 this.theta = theta; 20195 return this; 20196 } 20197 /** 20198 * Copies the values of the given spherical to this instance. 20199 * 20200 * @param {Spherical} other - The spherical to copy. 20201 * @return {Spherical} A reference to this spherical. 20202 */ copy(other) { 20203 this.radius = other.radius; 20204 this.phi = other.phi; 20205 this.theta = other.theta; 20206 return this; 20207 } 20208 /** 20209 * Restricts the polar angle [page:.phi phi] to be between `0.000001` and pi - 20210 * `0.000001`. 20211 * 20212 * @return {Spherical} A reference to this spherical. 20213 */ makeSafe() { 20214 const EPS = 0.000001; 20215 this.phi = clamp$1(this.phi, EPS, Math.PI - EPS); 20216 return this; 20217 } 20218 /** 20219 * Sets the spherical components from the given vector which is assumed to hold 20220 * Cartesian coordinates. 20221 * 20222 * @param {Vector3} v - The vector to set. 20223 * @return {Spherical} A reference to this spherical. 20224 */ setFromVector3(v) { 20225 return this.setFromCartesianCoords(v.x, v.y, v.z); 20226 } 20227 /** 20228 * Sets the spherical components from the given Cartesian coordinates. 20229 * 20230 * @param {number} x - The x value. 20231 * @param {number} y - The x value. 20232 * @param {number} z - The x value. 20233 * @return {Spherical} A reference to this spherical. 20234 */ setFromCartesianCoords(x, y, z) { 20235 this.radius = Math.sqrt(x * x + y * y + z * z); 20236 if (this.radius === 0) { 20237 this.theta = 0; 20238 this.phi = 0; 20239 } else { 20240 this.theta = Math.atan2(x, z); 20241 this.phi = Math.acos(clamp$1(y / this.radius, -1, 1)); 20242 } 20243 return this; 20244 } 20245 /** 20246 * Returns a new spherical with copied values from this instance. 20247 * 20248 * @return {Spherical} A clone of this instance. 20249 */ clone() { 20250 return new this.constructor().copy(this); 20251 } 20252 /** 20253 * Constructs a new spherical. 20254 * 20255 * @param {number} [radius=1] - The radius, or the Euclidean distance (straight-line distance) from the point to the origin. 20256 * @param {number} [phi=0] - The polar angle in radians from the y (up) axis. 20257 * @param {number} [theta=0] - The equator/azimuthal angle in radians around the y (up) axis. 20258 */ constructor(radius = 1, phi = 0, theta = 0){ 20259 /** 20260 * The radius, or the Euclidean distance (straight-line distance) from the point to the origin. 20261 * 20262 * @type {number} 20263 * @default 1
vendor: 5,283 bytes, lines 20264-20366
20264 */ this.radius = radius; 20265 /** 20266 * The polar angle in radians from the y (up) axis. 20267 * 20268 * @type {number} 20269 * @default 0 20270 */ this.phi = phi; 20271 /** 20272 * The equator/azimuthal angle in radians around the y (up) axis. 20273 * 20274 * @type {number} 20275 * @default 0 20276 */ this.theta = theta; 20277 } 20278 } 20279 /** 20280 * Determines how many bytes must be used to represent the texture. 20281 * 20282 * @param {number} width - The width of the texture. 20283 * @param {number} height - The height of the texture. 20284 * @param {number} format - The texture's format. 20285 * @param {number} type - The texture's type. 20286 * @return {number} The byte length. 20287 */ function getByteLength(width, height, format, type) { 20288 const typeByteLength = getTextureTypeByteLength(type); 20289 switch(format){ 20290 // https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml 20291 case AlphaFormat: 20292 return width * height; 20293 case LuminanceFormat: 20294 return width * height; 20295 case LuminanceAlphaFormat: 20296 return width * height * 2; 20297 case RedFormat: 20298 return width * height / typeByteLength.components * typeByteLength.byteLength; 20299 case RedIntegerFormat: 20300 return width * height / typeByteLength.components * typeByteLength.byteLength; 20301 case RGFormat: 20302 return width * height * 2 / typeByteLength.components * typeByteLength.byteLength; 20303 case RGIntegerFormat: 20304 return width * height * 2 / typeByteLength.components * typeByteLength.byteLength; 20305 case RGBFormat: 20306 return width * height * 3 / typeByteLength.components * typeByteLength.byteLength; 20307 case RGBAFormat: 20308 return width * height * 4 / typeByteLength.components * typeByteLength.byteLength; 20309 case RGBAIntegerFormat: 20310 return width * height * 4 / typeByteLength.components * typeByteLength.byteLength; 20311 // https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_s3tc_srgb/ 20312 case RGB_S3TC_DXT1_Format: 20313 case RGBA_S3TC_DXT1_Format: 20314 return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 8; 20315 case RGBA_S3TC_DXT3_Format: 20316 case RGBA_S3TC_DXT5_Format: 20317 return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 16; 20318 // https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_pvrtc/ 20319 case RGB_PVRTC_2BPPV1_Format: 20320 case RGBA_PVRTC_2BPPV1_Format: 20321 return Math.max(width, 16) * Math.max(height, 8) / 4; 20322 case RGB_PVRTC_4BPPV1_Format: 20323 case RGBA_PVRTC_4BPPV1_Format: 20324 return Math.max(width, 8) * Math.max(height, 8) / 2; 20325 // https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_etc/ 20326 case RGB_ETC1_Format: 20327 case RGB_ETC2_Format: 20328 return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 8; 20329 case RGBA_ETC2_EAC_Format: 20330 return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 16; 20331 // https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_astc/ 20332 case RGBA_ASTC_4x4_Format: 20333 return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 16; 20334 case RGBA_ASTC_5x4_Format: 20335 return Math.floor((width + 4) / 5) * Math.floor((height + 3) / 4) * 16; 20336 case RGBA_ASTC_5x5_Format: 20337 return Math.floor((width + 4) / 5) * Math.floor((height + 4) / 5) * 16; 20338 case RGBA_ASTC_6x5_Format: 20339 return Math.floor((width + 5) / 6) * Math.floor((height + 4) / 5) * 16; 20340 case RGBA_ASTC_6x6_Format: 20341 return Math.floor((width + 5) / 6) * Math.floor((height + 5) / 6) * 16; 20342 case RGBA_ASTC_8x5_Format: 20343 return Math.floor((width + 7) / 8) * Math.floor((height + 4) / 5) * 16; 20344 case RGBA_ASTC_8x6_Format: 20345 return Math.floor((width + 7) / 8) * Math.floor((height + 5) / 6) * 16; 20346 case RGBA_ASTC_8x8_Format: 20347 return Math.floor((width + 7) / 8) * Math.floor((height + 7) / 8) * 16; 20348 case RGBA_ASTC_10x5_Format: 20349 return Math.floor((width + 9) / 10) * Math.floor((height + 4) / 5) * 16; 20350 case RGBA_ASTC_10x6_Format: 20351 return Math.floor((width + 9) / 10) * Math.floor((height + 5) / 6) * 16; 20352 case RGBA_ASTC_10x8_Format: 20353 return Math.floor((width + 9) / 10) * Math.floor((height + 7) / 8) * 16; 20354 case RGBA_ASTC_10x10_Format: 20355 return Math.floor((width + 9) / 10) * Math.floor((height + 9) / 10) * 16; 20356 case RGBA_ASTC_12x10_Format: 20357 return Math.floor((width + 11) / 12) * Math.floor((height + 9) / 10) * 16; 20358 case RGBA_ASTC_12x12_Format: 20359 return Math.floor((width + 11) / 12) * Math.floor((height + 11) / 12) * 16; 20360 // https://registry.khronos.org/webgl/extensions/EXT_texture_compression_bptc/ 20361 case RGBA_BPTC_Format: 20362 case RGB_BPTC_SIGNED_Format: 20363 case RGB_BPTC_UNSIGNED_Format: 20364 return Math.ceil(width / 4) * Math.ceil(height / 4) * 16; 20365 // https://registry.khronos.org/webgl/extensions/EXT_texture_compression_rgtc/ 20366 case RED_RGTC1_Format:
vendor: 9,723 bytes, lines 20367-20586
20367 case SIGNED_RED_RGTC1_Format: 20368 return Math.ceil(width / 4) * Math.ceil(height / 4) * 8; 20369 case RED_GREEN_RGTC2_Format: 20370 case SIGNED_RED_GREEN_RGTC2_Format: 20371 return Math.ceil(width / 4) * Math.ceil(height / 4) * 16; 20372 } 20373 throw new Error(`Unable to determine texture byte length for ${format} format.`); 20374 } 20375 function getTextureTypeByteLength(type) { 20376 switch(type){ 20377 case UnsignedByteType: 20378 case ByteType: 20379 return { 20380 byteLength: 1, 20381 components: 1 20382 }; 20383 case UnsignedShortType: 20384 case ShortType: 20385 case HalfFloatType: 20386 return { 20387 byteLength: 2, 20388 components: 1 20389 }; 20390 case UnsignedShort4444Type: 20391 case UnsignedShort5551Type: 20392 return { 20393 byteLength: 2, 20394 components: 4 20395 }; 20396 case UnsignedIntType: 20397 case IntType: 20398 case FloatType: 20399 return { 20400 byteLength: 4, 20401 components: 1 20402 }; 20403 case UnsignedInt5999Type: 20404 return { 20405 byteLength: 4, 20406 components: 3 20407 }; 20408 } 20409 throw new Error(`Unknown texture type ${type}.`); 20410 } 20411 if (typeof __THREE_DEVTOOLS__ !== 'undefined') { 20412 __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent('register', { 20413 detail: { 20414 revision: REVISION 20415 } 20416 })); 20417 } 20418 if (typeof window !== 'undefined') { 20419 if (window.__THREE__) { 20420 console.warn('WARNING: Multiple instances of Three.js being imported.'); 20421 } else { 20422 window.__THREE__ = REVISION; 20423 } 20424 } 20425 20426 function WebGLAnimation() { 20427 let context = null; 20428 let isAnimating = false; 20429 let animationLoop = null; 20430 let requestId = null; 20431 function onAnimationFrame(time, frame) { 20432 animationLoop(time, frame); 20433 requestId = context.requestAnimationFrame(onAnimationFrame); 20434 } 20435 return { 20436 start: function() { 20437 if (isAnimating === true) return; 20438 if (animationLoop === null) return; 20439 requestId = context.requestAnimationFrame(onAnimationFrame); 20440 isAnimating = true; 20441 }, 20442 stop: function() { 20443 context.cancelAnimationFrame(requestId); 20444 isAnimating = false; 20445 }, 20446 setAnimationLoop: function(callback) { 20447 animationLoop = callback; 20448 }, 20449 setContext: function(value) { 20450 context = value; 20451 } 20452 }; 20453 } 20454 function WebGLAttributes(gl) { 20455 const buffers = new WeakMap(); 20456 function createBuffer(attribute, bufferType) { 20457 const array = attribute.array; 20458 const usage = attribute.usage; 20459 const size = array.byteLength; 20460 const buffer = gl.createBuffer(); 20461 gl.bindBuffer(bufferType, buffer); 20462 gl.bufferData(bufferType, array, usage); 20463 attribute.onUploadCallback(); 20464 let type; 20465 if (array instanceof Float32Array) { 20466 type = gl.FLOAT; 20467 } else if (array instanceof Uint16Array) { 20468 if (attribute.isFloat16BufferAttribute) { 20469 type = gl.HALF_FLOAT; 20470 } else { 20471 type = gl.UNSIGNED_SHORT; 20472 } 20473 } else if (array instanceof Int16Array) { 20474 type = gl.SHORT; 20475 } else if (array instanceof Uint32Array) { 20476 type = gl.UNSIGNED_INT; 20477 } else if (array instanceof Int32Array) { 20478 type = gl.INT; 20479 } else if (array instanceof Int8Array) { 20480 type = gl.BYTE; 20481 } else if (array instanceof Uint8Array) { 20482 type = gl.UNSIGNED_BYTE; 20483 } else if (array instanceof Uint8ClampedArray) { 20484 type = gl.UNSIGNED_BYTE; 20485 } else { 20486 throw new Error('THREE.WebGLAttributes: Unsupported buffer data format: ' + array); 20487 } 20488 return { 20489 buffer: buffer, 20490 type: type, 20491 bytesPerElement: array.BYTES_PER_ELEMENT, 20492 version: attribute.version, 20493 size: size 20494 }; 20495 } 20496 function updateBuffer(buffer, attribute, bufferType) { 20497 const array = attribute.array; 20498 const updateRanges = attribute.updateRanges; 20499 gl.bindBuffer(bufferType, buffer); 20500 if (updateRanges.length === 0) { 20501 // Not using update ranges 20502 gl.bufferSubData(bufferType, 0, array); 20503 } else { 20504 // Before applying update ranges, we merge any adjacent / overlapping 20505 // ranges to reduce load on `gl.bufferSubData`. Empirically, this has led 20506 // to performance improvements for applications which make heavy use of 20507 // update ranges. Likely due to GPU command overhead. 20508 // 20509 // Note that to reduce garbage collection between frames, we merge the 20510 // update ranges in-place. This is safe because this method will clear the 20511 // update ranges once updated. 20512 updateRanges.sort((a, b)=>a.start - b.start); 20513 // To merge the update ranges in-place, we work from left to right in the 20514 // existing updateRanges array, merging ranges. This may result in a final 20515 // array which is smaller than the original. This index tracks the last 20516 // index representing a merged range, any data after this index can be 20517 // trimmed once the merge algorithm is completed. 20518 let mergeIndex = 0; 20519 for(let i = 1; i < updateRanges.length; i++){ 20520 const previousRange = updateRanges[mergeIndex]; 20521 const range = updateRanges[i]; 20522 // We add one here to merge adjacent ranges. This is safe because ranges 20523 // operate over positive integers. 20524 if (range.start <= previousRange.start + previousRange.count + 1) { 20525 previousRange.count = Math.max(previousRange.count, range.start + range.count - previousRange.start); 20526 } else { 20527 ++mergeIndex; 20528 updateRanges[mergeIndex] = range; 20529 } 20530 } 20531 // Trim the array to only contain the merged ranges. 20532 updateRanges.length = mergeIndex + 1; 20533 for(let i = 0, l = updateRanges.length; i < l; i++){ 20534 const range = updateRanges[i]; 20535 gl.bufferSubData(bufferType, range.start * array.BYTES_PER_ELEMENT, array, range.start, range.count); 20536 } 20537 attribute.clearUpdateRanges(); 20538 } 20539 attribute.onUploadCallback(); 20540 } 20541 // 20542 function get(attribute) { 20543 if (attribute.isInterleavedBufferAttribute) attribute = attribute.data; 20544 return buffers.get(attribute); 20545 } 20546 function remove(attribute) { 20547 if (attribute.isInterleavedBufferAttribute) attribute = attribute.data; 20548 const data = buffers.get(attribute); 20549 if (data) { 20550 gl.deleteBuffer(data.buffer); 20551 buffers.delete(attribute); 20552 } 20553 } 20554 function update(attribute, bufferType) { 20555 if (attribute.isInterleavedBufferAttribute) attribute = attribute.data; 20556 if (attribute.isGLBufferAttribute) { 20557 const cached = buffers.get(attribute); 20558 if (!cached || cached.version < attribute.version) { 20559 buffers.set(attribute, { 20560 buffer: attribute.buffer, 20561 type: attribute.type, 20562 bytesPerElement: attribute.elementSize, 20563 version: attribute.version 20564 }); 20565 } 20566 return; 20567 } 20568 const data = buffers.get(attribute); 20569 if (data === undefined) { 20570 buffers.set(attribute, createBuffer(attribute, bufferType)); 20571 } else if (data.version < attribute.version) { 20572 if (data.size !== attribute.array.byteLength) { 20573 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.'); 20574 } 20575 updateBuffer(data.buffer, attribute, bufferType); 20576 data.version = attribute.version; 20577 } 20578 } 20579 return { 20580 get: get, 20581 remove: remove, 20582 update: update 20583 }; 20584 } 20585 var alphahash_fragment = "#ifdef USE_ALPHAHASH\n\tif ( diffuseColor.a < getAlphaHashThreshold( vPosition ) ) discard;\n#endif"; 20586 var 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
20586- ( ( 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"; 20587 var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vAlphaMapUv ).g;\n#endif"; 20588 var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; 20589 var alphatest_fragment = "#ifdef USE_ALPHATEST\n\t#ifdef ALPHA_TO_COVERAGE\n\tdiffuseColor.a = smoothstep( alphaTest, alphaTest + fwidth( diffuseColor.a ), diffuseColor.a );\n\tif ( diffuseColor.a == 0.0 ) discard;\n\t#else\n\tif ( diffuseColor.a < alphaTest ) discard;\n\t#endif\n#endif"; 20590 var alphatest_pars_fragment = "#ifdef USE_ALPHATEST\n\tuniform float alphaTest;\n#endif"; 20591 var 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( geometryNormal, geometryViewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif"; 20592 var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; 20593 var batching_pars_vertex = "#ifdef USE_BATCHING\n\t#if ! defined( GL_ANGLE_multi_draw )\n\t#define gl_DrawID _gl_DrawID\n\tuniform int _gl_DrawID;\n\t#endif\n\tuniform highp sampler2D batchingTexture;\n\tuniform highp usampler2D batchingIdTexture;\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\tfloat getIndirectIndex( const in int i ) {\n\t\tint size = textureSize( batchingIdTexture, 0 ).x;\n\t\tint x = i % size;\n\t\tint y = i / size;\n\t\treturn float( texelFetch( batchingIdTexture, ivec2( x, y ), 0 ).r );\n\t}\n#endif\n#ifdef USE_BATCHING_COLOR\n\tuniform sampler2D batchingColorTexture;\n\tvec3 getBatchingColor( const in float i ) {\n\t\tint size = textureSize( batchingColorTexture, 0 ).x;\n\t\tint j = int( i );\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\treturn texelFetch( batchingColorTexture, ivec2( x, y ), 0 ).rgb;\n\t}\n#endif"; 20594 var batching_vertex = "#ifdef USE_BATCHING\n\tmat4 batchingMatrix = getBatchingMatrix( getIndirectIndex( gl_DrawID ) );\n#endif"; 20595 var begin_vertex = "vec3 transformed = vec3( position );\n#ifdef USE_ALPHAHASH\n\tvPosition = vec3( position );\n#endif"; 20596 var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif"; 20597 var 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"; 20598 var 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 );
20598\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 );\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"; 20599 var 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"; 20600 var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#ifdef ALPHA_TO_COVERAGE\n\t\tfloat distanceToPlane, distanceGradient;\n\t\tfloat clipOpacity = 1.0;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tdistanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w;\n\t\t\tdistanceGradient = fwidth( distanceToPlane ) / 2.0;\n\t\t\tclipOpacity *= smoothstep( - distanceGradient, distanceGradient, distanceToPlane );\n\t\t\tif ( clipOpacity == 0.0 ) discard;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\t\tfloat unionClipOpacity = 1.0;\n\t\t\t#pragma unroll_loop_start\n\t\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\t\tplane = clippingPlanes[ i ];\n\t\t\t\tdistanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w;\n\t\t\t\tdistanceGradient = fwidth( distanceToPlane ) / 2.0;\n\t\t\t\tunionClipOpacity *= 1.0 - smoothstep( - distanceGradient, distanceGradient, distanceToPlane );\n\t\t\t}\n\t\t\t#pragma unroll_loop_end\n\t\t\tclipOpacity *= 1.0 - unionClipOpacity;\n\t\t#endif\n\t\tdiffuseColor.a *= clipOpacity;\n\t\tif ( diffuseColor.a == 0.0 ) discard;\n\t#else\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\t\tbool clipped = true;\n\t\t\t#pragma unroll_loop_start\n\t\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\t\tplane = clippingPlanes[ i ];\n\t\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t\t}\n\t\t\t#pragma unroll_loop_end\n\t\t\tif ( clipped ) discard;\n\t\t#endif\n\t#endif\n#endif"; 20601 var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif"; 20602 var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif"; 20603 var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif"; 20604 var color_fragment = "#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( USE_COLOR )\n\tdiffuseColor.rgb *= vColor;\n#endif"; 20605 var color_pars_fragment = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR )\n\tvarying vec3 vColor;\n#endif"; 20606 var color_pars_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR )\n\tvarying vec3 vColor;\n#endif"; 20607 var color_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_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\n#ifdef USE_BATCHING_COLOR\n\tvec3 batchingColor = getBatchingColor( getIndirectIndex( gl_DrawID ) );\n\tvColor.xyz *= batchingColor.xyz;\n#endif"; 20608 var common = "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\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}\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"; 20609 var 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"; 20610 var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = objectTangent;\n#endif\n#ifdef USE_BATCHING\n\tmat3 bm = mat3( batchingMatrix );
20610\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"; 20611 var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif"; 20612 var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias );\n#endif"; 20613 var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv );\n\t#ifdef DECODE_VIDEO_TEXTURE_EMISSIVE\n\t\temissiveColor = sRGBTransferEOTF( emissiveColor );\n\t#endif\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif"; 20614 var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif"; 20615 var colorspace_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );"; 20616 var colorspace_pars_fragment = "vec4 LinearTransferOETF( in vec4 value ) {\n\treturn value;\n}\nvec4 sRGBTransferEOTF( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a );\n}\nvec4 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}"; 20617 var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, envMapRotation * 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"; 20618 var envmap_common_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\tuniform mat3 envMapRotation;\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"; 20619 var 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"; 20620 var 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"; 20621 var envmap_vertex = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t}
20621 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"; 20622 var fog_vertex = "#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif"; 20623 var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif"; 20624 var 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"; 20625 var 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"; 20626 var gradientmap_pars_fragment = "#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn 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}"; 20627 var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; 20628 var lights_lambert_fragment = "LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularStrength = specularStrength;"; 20629 var 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"; 20630 var 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\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\tif ( cutoffDistance > 0.0 ) {\n\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t}\n\treturn distanceFalloff;\n}\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}
20630\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"; 20631 var 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, envMapRotation * 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, envMapRotation * 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"; 20632 var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;"; 20633 var 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"; 20634 var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;"; 20635 var 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
20635( 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"; 20636 var 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;
20636\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_DISPERSION\n\tmaterial.dispersion = dispersion;\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"; 20637 var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\tfloat dispersion
vendor: 15,196 bytes, line 20637
20637;\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}";
20638 var 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.shadowIntensity, 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.shadowIntensity, 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.shadowIntensity, 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"; 20639 var 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"; 20640 var 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"; 20641 var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF )\n\tgl_FragDepth = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif"; 20642 var logdepthbuf_pars_fragment = "#if defined( USE_LOGDEPTHBUF )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif"; 20643 var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif"; 20644 var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\tvFragDepth = 1.0 + gl_Position.w;\n\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n#endif"; 20645 var map_fragment = "#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vMapUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = sRGBTransferEOTF( sampledDiffuseColor );\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif"; 20646 var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif"; 20647 var 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"; 20648 var 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"; 20649 var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif"; 20650 var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"; 20651 var morphinstance_vertex = "#ifdef USE_INSTANCING_MORPH\n\tfloat morphTargetInfluences[ MORPHTARGETS_COUNT ];\n\tfloat morphTargetBaseInfluence = texelFetch( morphTexture, ivec2( 0, gl_InstanceID ), 0 ).r;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\tmorphTargetInfluences[i] = texelFetch( morphTexture, ivec2( i + 1, gl_InstanceID ), 0 ).r;\n\t}\n#endif"; 20652 var morphcolor_vertex = "#if defined( USE_MORPHCOLORS )\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"; 20653 var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\tif ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ];\n\t}\n#endif"; 20654 var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\t#ifndef USE_INSTANCING_MORPH\n\t\tuniform float morphTargetBaseInfluence;\n\t\tuniform float morphTargetInfluences[ MORPHTARGETS_COUNT ];\n\t#endif\n\tuniform sampler2DArray morphTargetsTexture;\n\tuniform ivec2 morphTargetsTextureSize;\n\tvec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) {\n\t\tint texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset;\n\t\tint y = texelIndex / morphTargetsTextureSize.x;\n\t\tint x = texelIndex - y * morphTargetsTextureSize.x;\n\t\tivec3 morphUV = ivec3( x, y, morphTargetIndex );\n\t\treturn texelFetch( morphTargetsTexture, morphUV, 0 );\n\t}\n#endif"; 20655 var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\tif ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ];\n\t}\n#endif"; 20656 var 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;"; 20657 var 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 );
20657\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif"; 20658 var 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"; 20659 var 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"; 20660 var 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"; 20661 var 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"; 20662 var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = nonPerturbedNormal;\n#endif"; 20663 var 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"; 20664 var 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"; 20665 var iridescence_pars_fragment = "#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform sampler2D iridescenceThicknessMap;\n#endif"; 20666 var 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 );"; 20667 var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;const float ShiftRight8 = 1. / 256.;\nconst float Inv255 = 1. / 255.;\nconst vec4 PackFactors = vec4( 1.0, 256.0, 256.0 * 256.0, 256.0 * 256.0 * 256.0 );\nconst vec2 UnpackFactors2 = vec2( UnpackDownscale, 1.0 / PackFactors.g );\nconst vec3 UnpackFactors3 = vec3( UnpackDownscale / PackFactors.rg, 1.0 / PackFactors.b );\nconst vec4 UnpackFactors4 = vec4( UnpackDownscale / PackFactors.rgb, 1.0 / PackFactors.a );\nvec4 packDepthToRGBA( const in float v ) {\n\tif( v <= 0.0 )\n\t\treturn vec4( 0., 0., 0., 0. );\n\tif( v >= 1.0 )\n\t\treturn vec4( 1., 1., 1., 1. );\n\tfloat vuf;\n\tfloat af = modf( v * PackFactors.a, vuf );\n\tfloat bf = modf( vuf * ShiftRight8, vuf );\n\tfloat gf = modf( vuf * ShiftRight8, vuf );\n\treturn vec4( vuf * Inv255, gf * PackUpscale, bf * PackUpscale, af );\n}\nvec3 packDepthToRGB( const in float v ) {\n\tif( v <= 0.0 )\n\t\treturn vec3( 0., 0., 0. );\n\tif( v >= 1.0 )\n\t\treturn vec3( 1., 1., 1. );\n\tfloat vuf;\n\tfloat bf = modf( v * PackFactors.b, vuf );\n\tfloat gf = modf( vuf * ShiftRight8, vuf );\n\treturn vec3( vuf * Inv255, gf * PackUpscale, bf );\n}\nvec2 packDepthToRG( const in float v ) {\n\tif( v <= 0.0 )\n\t\treturn vec2( 0., 0. );\n\tif( v >= 1.0 )\n\t\treturn vec2( 1., 1. );\n\tfloat vuf;\n\tfloat gf = modf( v * 256., vuf );\n\treturn vec2( vuf * Inv255, gf );\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors4 );\n}\nfloat unpackRGBToDepth( const in vec3 v ) {\n\treturn dot( v, UnpackFactors3 );\n}\nfloat unpackRGToDepth( const in vec2 v ) {\n\treturn v.r * UnpackFactors2.r + v.g * UnpackFactors2.g;\n}\nvec4 pack2HalfToRGBA( const in vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 25
206675.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( const in 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}"; 20668 var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif"; 20669 var 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;"; 20670 var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif"; 20671 var dithering_pars_fragment = "#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif"; 20672 var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv );\n\troughnessFactor *= texelRoughness.g;\n#endif"; 20673 var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"; 20674 var 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 shadowIntensity;\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 shadowIntensity;\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 shadowIntensity;\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 shadowIntensity, 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;
20674\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 mix( 1.0, shadow, shadowIntensity );\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 shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tfloat shadow = 1.0;\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\t\n\t\tfloat lightToPositionLength = length( lightToPosition );\n\t\tif ( lightToPositionLength - shadowCameraFar <= 0.0 && lightToPositionLength - shadowCameraNear >= 0.0 ) {\n\t\t\tfloat dp = ( lightToPositionLength - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\t\tdp += shadowBias;\n\t\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\t\tshadow = (\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t\t) * ( 1.0 / 9.0 );\n\t\t\t#else\n\t\t\t\tshadow = texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t\t#endif\n\t\t}\n\t\treturn mix( 1.0, shadow, shadowIntensity );\n\t}\n#endif";
20675 var 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 shadowIntensity;\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 shadowIntensity;\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 shadowIntensity;\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"; 20676 var 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"; 20677 var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowIntensity, 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.shadowIntensity, 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.shadowIntensity, 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}"; 20678 var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif"; 20679 var 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"; 20680 var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif"; 20681 var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif"; 20682 var 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"; 20683 var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif"; 20684 var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif"; 20685 var tonemapping_pars_fragment =
vendor: 3,668 bytes, line 20685
20685"#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 CineonToneMapping( 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 *= toneMappingExposure;\n\tcolor = LINEAR_SRGB_TO_LINEAR_REC2020 * color;\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\tcolor = clamp( color, 0.0, 1.0 );\n\treturn color;\n}\nvec3 NeutralToneMapping( vec3 color ) {\n\tconst float StartCompression = 0.8 - 0.04;\n\tconst float Desaturation = 0.15;\n\tcolor *= toneMappingExposure;\n\tfloat x = min( color.r, min( color.g, color.b ) );\n\tfloat offset = x < 0.08 ? x - 6.25 * x * x : 0.04;\n\tcolor -= offset;\n\tfloat peak = max( color.r, max( color.g, color.b ) );\n\tif ( peak < StartCompression ) return color;\n\tfloat d = 1. - StartCompression;\n\tfloat newPeak = 1. - d * d / ( peak + d - StartCompression );\n\tcolor *= newPeak / peak;\n\tfloat g = 1. - 1. / ( Desaturation * ( peak - newPeak ) + 1. );\n\treturn mix( color, vec3( newPeak ), g );\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }"
20685; 20686 var 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.dispersion, 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"; 20687 var 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 dispersion, const in float ior, const in float thickness,\n\t\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tvec4 transmittedLight;\n\t\tvec3 transmittance;\n\t\t#ifdef USE_DISPERSION\n\t\t\tfloat halfSpread = ( ior - 1.0 ) * 0.025 * dispersion;\n\t\t\tvec3 iors = vec3( ior - halfSpread, ior, ior + halfSpread );\n\t\t\tfor ( int i = 0; i < 3; i ++ ) {\n\t\t\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, iors[ i ], modelMatrix );\n\t\t\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\t\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\t\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\t\t\trefractionCoords += 1.0;\n\t\t\t\trefractionCoords /= 2.0;\n\t\t\t\tvec4 transmissionSample = getTransmissionSample( refractionCoords, roughness, iors[ i ] );\n\t\t\t\ttransmittedLight[ i ] = transmissionSample[ i ];\n\t\t\t\ttransmittedLight.a += transmissionSample.a;\n\t\t\t\ttransmittance[ i ] = diffuseColor[ i ] * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance )[ i ];\n\t\t\t}\n\t\t\ttransmittedLight.a /= 3.0;\n\t\t#else\n\t\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\t\trefractionCoords += 1.0;\n\t\t\trefractionCoords /= 2.0;\n\t\t\ttransmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\t\ttransmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\t#endif\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"; 20688 var uv_pars_fragment = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tvarying vec2 vMapUv;
20688\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"; 20689 var 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"; 20690 var 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;
20690\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"; 20691 var 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"; 20692 const 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}"; 20693 const 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}"; 20694 const 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}"; 20695 const 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;\nuniform mat3 backgroundRotation;\nvarying vec3 vWorldDirection;\n#include <cube_uv_reflection_fragment>\nvoid main() {\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 texColor = textureCube( envMap, backgroundRotation * vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 texColor = textureCubeUV( envMap, backgroundRotation * 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}"; 20696 const 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}"; 20697 const 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}"; 20698 const 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#include <morphinstance_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}"; 20699 const 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\tvec4 diffuseColor = vec4( 1.0 );\n\t#include <clipping_planes_fragment>\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#elif DEPTH_PACKING == 3202\n\t\tgl_FragColor = vec4( packDepthToRGB( fragCoordZ ), 1.0 );\n\t#elif DEPTH_PACKING == 3203\n\t\tgl_FragColor = vec4( packDepthToRG( fragCoordZ ), 0.0, 1.0 );\n\t#endif\n}"; 20700 const 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#include <morphinstance_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}"; 20701 const 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\tvec4 diffuseColor = vec4( 1.0 );\n\t#include <clipping_planes_fragment>\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}"; 20702 const 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}"; 20703 const 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}"; 20704 const 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 <morphinstance_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}"; 20705 const 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\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\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}"; 20706 const 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 <morphinstance_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}"; 20707 const 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\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\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}"; 20708 const 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 <morphinstance_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}"; 20709 const 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\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\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}"; 20710 const 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 <morphinstance_vertex>\n\t
20710#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\t#include <fog_vertex>\n\tvViewPosition = - mvPosition.xyz;\n}"; 20711 const 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\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\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}"; 20712 const 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 <morphinstance_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}"; 20713 const 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\tvec4 diffuseColor = vec4( 0.0, 0.0, 0.0, opacity );\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 ), diffuseColor.a );\n\t#ifdef OPAQUE\n\t\tgl_FragColor.a = 1.0;\n\t#endif\n}"; 20714 const 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 <morphinstance_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}"; 20715 const 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\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\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}"; 20716 const 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 <morphinstance_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}"; 20717 const fragment$5 =
vendor: 4,251 bytes, line 20717
20717"#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;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_DISPERSION\n\tuniform float dispersion;\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\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\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;\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}"
vendor: 38,957 bytes, lines 20717-21711
20717; 20718 const 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 <morphinstance_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}"; 20719 const 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\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\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}"; 20720 const 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 <morphinstance_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}"; 20721 const 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\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\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}"; 20722 const 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 <morphinstance_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}"; 20723 const 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}"; 20724 const 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[ 3 ];\n\tvec2 scale = vec2( length( modelMatrix[ 0 ].xyz ), length( modelMatrix[ 1 ].xyz ) );\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}"; 20725 const 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\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\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}"; 20726 const ShaderChunk = { 20727 alphahash_fragment: alphahash_fragment, 20728 alphahash_pars_fragment: alphahash_pars_fragment, 20729 alphamap_fragment: alphamap_fragment, 20730 alphamap_pars_fragment: alphamap_pars_fragment, 20731 alphatest_fragment: alphatest_fragment, 20732 alphatest_pars_fragment: alphatest_pars_fragment, 20733 aomap_fragment: aomap_fragment, 20734 aomap_pars_fragment: aomap_pars_fragment, 20735 batching_pars_vertex: batching_pars_vertex, 20736 batching_vertex: batching_vertex, 20737 begin_vertex: begin_vertex, 20738 beginnormal_vertex: beginnormal_vertex, 20739 bsdfs: bsdfs, 20740 iridescence_fragment: iridescence_fragment, 20741 bumpmap_pars_fragment: bumpmap_pars_fragment, 20742 clipping_planes_fragment: clipping_planes_fragment, 20743 clipping_planes_pars_fragment: clipping_planes_pars_fragment, 20744 clipping_planes_pars_vertex: clipping_planes_pars_vertex, 20745 clipping_planes_vertex: clipping_planes_vertex, 20746 color_fragment: color_fragment, 20747 color_pars_fragment: color_pars_fragment, 20748 color_pars_vertex: color_pars_vertex, 20749 color_vertex: color_vertex, 20750 common: common, 20751 cube_uv_reflection_fragment: cube_uv_reflection_fragment, 20752 defaultnormal_vertex: defaultnormal_vertex, 20753 displacementmap_pars_vertex: displacementmap_pars_vertex, 20754 displacementmap_vertex: displacementmap_vertex, 20755 emissivemap_fragment: emissivemap_fragment, 20756 emissivemap_pars_fragment: emissivemap_pars_fragment, 20757 colorspace_fragment: colorspace_fragment, 20758 colorspace_pars_fragment: colorspace_pars_fragment, 20759 envmap_fragment: envmap_fragment, 20760 envmap_common_pars_fragment: envmap_common_pars_fragment, 20761 envmap_pars_fragment: envmap_pars_fragment, 20762 envmap_pars_vertex: envmap_pars_vertex, 20763 envmap_physical_pars_fragment: envmap_physical_pars_fragment, 20764 envmap_vertex: envmap_vertex, 20765 fog_vertex: fog_vertex, 20766 fog_pars_vertex: fog_pars_vertex, 20767 fog_fragment: fog_fragment, 20768 fog_pars_fragment: fog_pars_fragment, 20769 gradientmap_pars_fragment: gradientmap_pars_fragment, 20770 lightmap_pars_fragment: lightmap_pars_fragment, 20771 lights_lambert_fragment: lights_lambert_fragment, 20772 lights_lambert_pars_fragment: lights_lambert_pars_fragment, 20773 lights_pars_begin: lights_pars_begin, 20774 lights_toon_fragment: lights_toon_fragment, 20775 lights_toon_pars_fragment: lights_toon_pars_fragment, 20776 lights_phong_fragment: lights_phong_fragment, 20777 lights_phong_pars_fragment: lights_phong_pars_fragment, 20778 lights_physical_fragment: lights_physical_fragment, 20779 lights_physical_pars_fragment: lights_physical_pars_fragment, 20780 lights_fragment_begin: lights_fragment_begin, 20781 lights_fragment_maps: lights_fragment_maps, 20782 lights_fragment_end: lights_fragment_end, 20783 logdepthbuf_fragment: logdepthbuf_fragment, 20784 logdepthbuf_pars_fragment: logdepthbuf_pars_fragment, 20785 logdepthbuf_pars_vertex: logdepthbuf_pars_vertex, 20786 logdepthbuf_vertex: logdepthbuf_vertex, 20787 map_fragment: map_fragment, 20788 map_pars_fragment: map_pars_fragment, 20789 map_particle_fragment: map_particle_fragment, 20790 map_particle_pars_fragment: map_particle_pars_fragment, 20791 metalnessmap_fragment: metalnessmap_fragment, 20792 metalnessmap_pars_fragment: metalnessmap_pars_fragment, 20793 morphinstance_vertex: morphinstance_vertex, 20794 morphcolor_vertex: morphcolor_vertex, 20795 morphnormal_vertex: morphnormal_vertex, 20796 morphtarget_pars_vertex: morphtarget_pars_vertex, 20797 morphtarget_vertex: morphtarget_vertex, 20798 normal_fragment_begin: normal_fragment_begin, 20799 normal_fragment_maps: normal_fragment_maps, 20800 normal_pars_fragment: normal_pars_fragment, 20801 normal_pars_vertex: normal_pars_vertex, 20802 normal_vertex: normal_vertex, 20803 normalmap_pars_fragment: normalmap_pars_fragment, 20804 clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin, 20805 clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps, 20806 clearcoat_pars_fragment: clearcoat_pars_fragment, 20807 iridescence_pars_fragment: iridescence_pars_fragment, 20808 opaque_fragment: opaque_fragment, 20809 packing: packing, 20810 premultiplied_alpha_fragment: premultiplied_alpha_fragment, 20811 project_vertex: project_vertex, 20812 dithering_fragment: dithering_fragment, 20813 dithering_pars_fragment: dithering_pars_fragment, 20814 roughnessmap_fragment: roughnessmap_fragment, 20815 roughnessmap_pars_fragment: roughnessmap_pars_fragment, 20816 shadowmap_pars_fragment: shadowmap_pars_fragment, 20817 shadowmap_pars_vertex: shadowmap_pars_vertex, 20818 shadowmap_vertex: shadowmap_vertex, 20819 shadowmask_pars_fragment: shadowmask_pars_fragment, 20820 skinbase_vertex: skinbase_vertex, 20821 skinning_pars_vertex: skinning_pars_vertex, 20822 skinning_vertex: skinning_vertex, 20823 skinnormal_vertex: skinnormal_vertex, 20824 specularmap_fragment: specularmap_fragment, 20825 specularmap_pars_fragment: specularmap_pars_fragment, 20826 tonemapping_fragment: tonemapping_fragment, 20827 tonemapping_pars_fragment: tonemapping_pars_fragment, 20828 transmission_fragment: transmission_fragment, 20829 transmission_pars_fragment: transmission_pars_fragment, 20830 uv_pars_fragment: uv_pars_fragment, 20831 uv_pars_vertex: uv_pars_vertex, 20832 uv_vertex: uv_vertex, 20833 worldpos_vertex: worldpos_vertex, 20834 background_vert: vertex$h, 20835 background_frag: fragment$h, 20836 backgroundCube_vert: vertex$g, 20837 backgroundCube_frag: fragment$g, 20838 cube_vert: vertex$f, 20839 cube_frag: fragment$f, 20840 depth_vert: vertex$e, 20841 depth_frag: fragment$e, 20842 distanceRGBA_vert: vertex$d, 20843 distanceRGBA_frag: fragment$d, 20844 equirect_vert: vertex$c, 20845 equirect_frag: fragment$c, 20846 linedashed_vert: vertex$b, 20847 linedashed_frag: fragment$b, 20848 meshbasic_vert: vertex$a, 20849 meshbasic_frag: fragment$a, 20850 meshlambert_vert: vertex$9, 20851 meshlambert_frag: fragment$9, 20852 meshmatcap_vert: vertex$8, 20853 meshmatcap_frag: fragment$8, 20854 meshnormal_vert: vertex$7, 20855 meshnormal_frag: fragment$7, 20856 meshphong_vert: vertex$6, 20857 meshphong_frag: fragment$6, 20858 meshphysical_vert: vertex$5, 20859 meshphysical_frag: fragment$5, 20860 meshtoon_vert: vertex$4, 20861 meshtoon_frag: fragment$4, 20862 points_vert: vertex$3, 20863 points_frag: fragment$3, 20864 shadow_vert: vertex$2, 20865 shadow_frag: fragment$2, 20866 sprite_vert: vertex$1, 20867 sprite_frag: fragment$1 20868 }; 20869 /** 20870 * Uniforms library for shared webgl shaders 20871 */ const UniformsLib = { 20872 common: { 20873 diffuse: { 20874 value: /*@__PURE__*/ new Color(0xffffff) 20875 }, 20876 opacity: { 20877 value: 1.0 20878 }, 20879 map: { 20880 value: null 20881 }, 20882 mapTransform: { 20883 value: /*@__PURE__*/ new Matrix3() 20884 }, 20885 alphaMap: { 20886 value: null 20887 }, 20888 alphaMapTransform: { 20889 value: /*@__PURE__*/ new Matrix3() 20890 }, 20891 alphaTest: { 20892 value: 0 20893 } 20894 }, 20895 specularmap: { 20896 specularMap: { 20897 value: null 20898 }, 20899 specularMapTransform: { 20900 value: /*@__PURE__*/ new Matrix3() 20901 } 20902 }, 20903 envmap: { 20904 envMap: { 20905 value: null 20906 }, 20907 envMapRotation: { 20908 value: /*@__PURE__*/ new Matrix3() 20909 }, 20910 flipEnvMap: { 20911 value: -1 20912 }, 20913 reflectivity: { 20914 value: 1.0 20915 }, 20916 ior: { 20917 value: 1.5 20918 }, 20919 refractionRatio: { 20920 value: 0.98 20921 } 20922 }, 20923 aomap: { 20924 aoMap: { 20925 value: null 20926 }, 20927 aoMapIntensity: { 20928 value: 1 20929 }, 20930 aoMapTransform: { 20931 value: /*@__PURE__*/ new Matrix3() 20932 } 20933 }, 20934 lightmap: { 20935 lightMap: { 20936 value: null 20937 }, 20938 lightMapIntensity: { 20939 value: 1 20940 }, 20941 lightMapTransform: { 20942 value: /*@__PURE__*/ new Matrix3() 20943 } 20944 }, 20945 bumpmap: { 20946 bumpMap: { 20947 value: null 20948 }, 20949 bumpMapTransform: { 20950 value: /*@__PURE__*/ new Matrix3() 20951 }, 20952 bumpScale: { 20953 value: 1 20954 } 20955 }, 20956 normalmap: { 20957 normalMap: { 20958 value: null 20959 }, 20960 normalMapTransform: { 20961 value: /*@__PURE__*/ new Matrix3() 20962 }, 20963 normalScale: { 20964 value: /*@__PURE__*/ new Vector2(1, 1) 20965 } 20966 }, 20967 displacementmap: { 20968 displacementMap: { 20969 value: null 20970 }, 20971 displacementMapTransform: { 20972 value: /*@__PURE__*/ new Matrix3() 20973 }, 20974 displacementScale: { 20975 value: 1 20976 }, 20977 displacementBias: { 20978 value: 0 20979 } 20980 }, 20981 emissivemap: { 20982 emissiveMap: { 20983 value: null 20984 }, 20985 emissiveMapTransform: { 20986 value: /*@__PURE__*/ new Matrix3() 20987 } 20988 }, 20989 metalnessmap: { 20990 metalnessMap: { 20991 value: null 20992 }, 20993 metalnessMapTransform: { 20994 value: /*@__PURE__*/ new Matrix3() 20995 } 20996 }, 20997 roughnessmap: { 20998 roughnessMap: { 20999 value: null 21000 }, 21001 roughnessMapTransform: { 21002 value: /*@__PURE__*/ new Matrix3() 21003 } 21004 }, 21005 gradientmap: { 21006 gradientMap: { 21007 value: null 21008 } 21009 }, 21010 fog: { 21011 fogDensity: { 21012 value: 0.00025 21013 }, 21014 fogNear: { 21015 value: 1 21016 }, 21017 fogFar: { 21018 value: 2000 21019 }, 21020 fogColor: { 21021 value: /*@__PURE__*/ new Color(0xffffff) 21022 } 21023 }, 21024 lights: { 21025 ambientLightColor: { 21026 value: [] 21027 }, 21028 lightProbe: { 21029 value: [] 21030 }, 21031 directionalLights: { 21032 value: [], 21033 properties: { 21034 direction: {}, 21035 color: {} 21036 } 21037 }, 21038 directionalLightShadows: { 21039 value: [], 21040 properties: { 21041 shadowIntensity: 1, 21042 shadowBias: {}, 21043 shadowNormalBias: {}, 21044 shadowRadius: {}, 21045 shadowMapSize: {} 21046 } 21047 }, 21048 directionalShadowMap: { 21049 value: [] 21050 }, 21051 directionalShadowMatrix: { 21052 value: [] 21053 }, 21054 spotLights: { 21055 value: [], 21056 properties: { 21057 color: {}, 21058 position: {}, 21059 direction: {}, 21060 distance: {}, 21061 coneCos: {}, 21062 penumbraCos: {}, 21063 decay: {} 21064 } 21065 }, 21066 spotLightShadows: { 21067 value: [], 21068 properties: { 21069 shadowIntensity: 1, 21070 shadowBias: {}, 21071 shadowNormalBias: {}, 21072 shadowRadius: {}, 21073 shadowMapSize: {} 21074 } 21075 }, 21076 spotLightMap: { 21077 value: [] 21078 }, 21079 spotShadowMap: { 21080 value: [] 21081 }, 21082 spotLightMatrix: { 21083 value: [] 21084 }, 21085 pointLights: { 21086 value: [], 21087 properties: { 21088 color: {}, 21089 position: {}, 21090 decay: {}, 21091 distance: {} 21092 } 21093 }, 21094 pointLightShadows: { 21095 value: [], 21096 properties: { 21097 shadowIntensity: 1, 21098 shadowBias: {}, 21099 shadowNormalBias: {}, 21100 shadowRadius: {}, 21101 shadowMapSize: {}, 21102 shadowCameraNear: {}, 21103 shadowCameraFar: {} 21104 } 21105 }, 21106 pointShadowMap: { 21107 value: [] 21108 }, 21109 pointShadowMatrix: { 21110 value: [] 21111 }, 21112 hemisphereLights: { 21113 value: [], 21114 properties: { 21115 direction: {}, 21116 skyColor: {}, 21117 groundColor: {} 21118 } 21119 }, 21120 // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src 21121 rectAreaLights: { 21122 value: [], 21123 properties: { 21124 color: {}, 21125 position: {}, 21126 width: {}, 21127 height: {} 21128 } 21129 }, 21130 ltc_1: { 21131 value: null 21132 }, 21133 ltc_2: { 21134 value: null 21135 } 21136 }, 21137 points: { 21138 diffuse: { 21139 value: /*@__PURE__*/ new Color(0xffffff) 21140 }, 21141 opacity: { 21142 value: 1.0 21143 }, 21144 size: { 21145 value: 1.0 21146 }, 21147 scale: { 21148 value: 1.0 21149 }, 21150 map: { 21151 value: null 21152 }, 21153 alphaMap: { 21154 value: null 21155 }, 21156 alphaMapTransform: { 21157 value: /*@__PURE__*/ new Matrix3() 21158 }, 21159 alphaTest: { 21160 value: 0 21161 }, 21162 uvTransform: { 21163 value: /*@__PURE__*/ new Matrix3() 21164 } 21165 }, 21166 sprite: { 21167 diffuse: { 21168 value: /*@__PURE__*/ new Color(0xffffff) 21169 }, 21170 opacity: { 21171 value: 1.0 21172 }, 21173 center: { 21174 value: /*@__PURE__*/ new Vector2(0.5, 0.5) 21175 }, 21176 rotation: { 21177 value: 0.0 21178 }, 21179 map: { 21180 value: null 21181 }, 21182 mapTransform: { 21183 value: /*@__PURE__*/ new Matrix3() 21184 }, 21185 alphaMap: { 21186 value: null 21187 }, 21188 alphaMapTransform: { 21189 value: /*@__PURE__*/ new Matrix3() 21190 }, 21191 alphaTest: { 21192 value: 0 21193 } 21194 } 21195 }; 21196 const ShaderLib = { 21197 basic: { 21198 uniforms: /*@__PURE__*/ mergeUniforms([ 21199 UniformsLib.common, 21200 UniformsLib.specularmap, 21201 UniformsLib.envmap, 21202 UniformsLib.aomap, 21203 UniformsLib.lightmap, 21204 UniformsLib.fog 21205 ]), 21206 vertexShader: ShaderChunk.meshbasic_vert, 21207 fragmentShader: ShaderChunk.meshbasic_frag 21208 }, 21209 lambert: { 21210 uniforms: /*@__PURE__*/ mergeUniforms([ 21211 UniformsLib.common, 21212 UniformsLib.specularmap, 21213 UniformsLib.envmap, 21214 UniformsLib.aomap, 21215 UniformsLib.lightmap, 21216 UniformsLib.emissivemap, 21217 UniformsLib.bumpmap, 21218 UniformsLib.normalmap, 21219 UniformsLib.displacementmap, 21220 UniformsLib.fog, 21221 UniformsLib.lights, 21222 { 21223 emissive: { 21224 value: /*@__PURE__*/ new Color(0x000000) 21225 } 21226 } 21227 ]), 21228 vertexShader: ShaderChunk.meshlambert_vert, 21229 fragmentShader: ShaderChunk.meshlambert_frag 21230 }, 21231 phong: { 21232 uniforms: /*@__PURE__*/ mergeUniforms([ 21233 UniformsLib.common, 21234 UniformsLib.specularmap, 21235 UniformsLib.envmap, 21236 UniformsLib.aomap, 21237 UniformsLib.lightmap, 21238 UniformsLib.emissivemap, 21239 UniformsLib.bumpmap, 21240 UniformsLib.normalmap, 21241 UniformsLib.displacementmap, 21242 UniformsLib.fog, 21243 UniformsLib.lights, 21244 { 21245 emissive: { 21246 value: /*@__PURE__*/ new Color(0x000000) 21247 }, 21248 specular: { 21249 value: /*@__PURE__*/ new Color(0x111111) 21250 }, 21251 shininess: { 21252 value: 30 21253 } 21254 } 21255 ]), 21256 vertexShader: ShaderChunk.meshphong_vert, 21257 fragmentShader: ShaderChunk.meshphong_frag 21258 }, 21259 standard: { 21260 uniforms: /*@__PURE__*/ mergeUniforms([ 21261 UniformsLib.common, 21262 UniformsLib.envmap, 21263 UniformsLib.aomap, 21264 UniformsLib.lightmap, 21265 UniformsLib.emissivemap, 21266 UniformsLib.bumpmap, 21267 UniformsLib.normalmap, 21268 UniformsLib.displacementmap, 21269 UniformsLib.roughnessmap, 21270 UniformsLib.metalnessmap, 21271 UniformsLib.fog, 21272 UniformsLib.lights, 21273 { 21274 emissive: { 21275 value: /*@__PURE__*/ new Color(0x000000) 21276 }, 21277 roughness: { 21278 value: 1.0 21279 }, 21280 metalness: { 21281 value: 0.0 21282 }, 21283 envMapIntensity: { 21284 value: 1 21285 } 21286 } 21287 ]), 21288 vertexShader: ShaderChunk.meshphysical_vert, 21289 fragmentShader: ShaderChunk.meshphysical_frag 21290 }, 21291 toon: { 21292 uniforms: /*@__PURE__*/ mergeUniforms([ 21293 UniformsLib.common, 21294 UniformsLib.aomap, 21295 UniformsLib.lightmap, 21296 UniformsLib.emissivemap, 21297 UniformsLib.bumpmap, 21298 UniformsLib.normalmap, 21299 UniformsLib.displacementmap, 21300 UniformsLib.gradientmap, 21301 UniformsLib.fog, 21302 UniformsLib.lights, 21303 { 21304 emissive: { 21305 value: /*@__PURE__*/ new Color(0x000000) 21306 } 21307 } 21308 ]), 21309 vertexShader: ShaderChunk.meshtoon_vert, 21310 fragmentShader: ShaderChunk.meshtoon_frag 21311 }, 21312 matcap: { 21313 uniforms: /*@__PURE__*/ mergeUniforms([ 21314 UniformsLib.common, 21315 UniformsLib.bumpmap, 21316 UniformsLib.normalmap, 21317 UniformsLib.displacementmap, 21318 UniformsLib.fog, 21319 { 21320 matcap: { 21321 value: null 21322 } 21323 } 21324 ]), 21325 vertexShader: ShaderChunk.meshmatcap_vert, 21326 fragmentShader: ShaderChunk.meshmatcap_frag 21327 }, 21328 points: { 21329 uniforms: /*@__PURE__*/ mergeUniforms([ 21330 UniformsLib.points, 21331 UniformsLib.fog 21332 ]), 21333 vertexShader: ShaderChunk.points_vert, 21334 fragmentShader: ShaderChunk.points_frag 21335 }, 21336 dashed: { 21337 uniforms: /*@__PURE__*/ mergeUniforms([ 21338 UniformsLib.common, 21339 UniformsLib.fog, 21340 { 21341 scale: { 21342 value: 1 21343 }, 21344 dashSize: { 21345 value: 1 21346 }, 21347 totalSize: { 21348 value: 2 21349 } 21350 } 21351 ]), 21352 vertexShader: ShaderChunk.linedashed_vert, 21353 fragmentShader: ShaderChunk.linedashed_frag 21354 }, 21355 depth: { 21356 uniforms: /*@__PURE__*/ mergeUniforms([ 21357 UniformsLib.common, 21358 UniformsLib.displacementmap 21359 ]), 21360 vertexShader: ShaderChunk.depth_vert, 21361 fragmentShader: ShaderChunk.depth_frag 21362 }, 21363 normal: { 21364 uniforms: /*@__PURE__*/ mergeUniforms([ 21365 UniformsLib.common, 21366 UniformsLib.bumpmap, 21367 UniformsLib.normalmap, 21368 UniformsLib.displacementmap, 21369 { 21370 opacity: { 21371 value: 1.0 21372 } 21373 } 21374 ]), 21375 vertexShader: ShaderChunk.meshnormal_vert, 21376 fragmentShader: ShaderChunk.meshnormal_frag 21377 }, 21378 sprite: { 21379 uniforms: /*@__PURE__*/ mergeUniforms([ 21380 UniformsLib.sprite, 21381 UniformsLib.fog 21382 ]), 21383 vertexShader: ShaderChunk.sprite_vert, 21384 fragmentShader: ShaderChunk.sprite_frag 21385 }, 21386 background: { 21387 uniforms: { 21388 uvTransform: { 21389 value: /*@__PURE__*/ new Matrix3() 21390 }, 21391 t2D: { 21392 value: null 21393 }, 21394 backgroundIntensity: { 21395 value: 1 21396 } 21397 }, 21398 vertexShader: ShaderChunk.background_vert, 21399 fragmentShader: ShaderChunk.background_frag 21400 }, 21401 backgroundCube: { 21402 uniforms: { 21403 envMap: { 21404 value: null 21405 }, 21406 flipEnvMap: { 21407 value: -1 21408 }, 21409 backgroundBlurriness: { 21410 value: 0 21411 }, 21412 backgroundIntensity: { 21413 value: 1 21414 }, 21415 backgroundRotation: { 21416 value: /*@__PURE__*/ new Matrix3() 21417 } 21418 }, 21419 vertexShader: ShaderChunk.backgroundCube_vert, 21420 fragmentShader: ShaderChunk.backgroundCube_frag 21421 }, 21422 cube: { 21423 uniforms: { 21424 tCube: { 21425 value: null 21426 }, 21427 tFlip: { 21428 value: -1 21429 }, 21430 opacity: { 21431 value: 1.0 21432 } 21433 }, 21434 vertexShader: ShaderChunk.cube_vert, 21435 fragmentShader: ShaderChunk.cube_frag 21436 }, 21437 equirect: { 21438 uniforms: { 21439 tEquirect: { 21440 value: null 21441 } 21442 }, 21443 vertexShader: ShaderChunk.equirect_vert, 21444 fragmentShader: ShaderChunk.equirect_frag 21445 }, 21446 distanceRGBA: { 21447 uniforms: /*@__PURE__*/ mergeUniforms([ 21448 UniformsLib.common, 21449 UniformsLib.displacementmap, 21450 { 21451 referencePosition: { 21452 value: /*@__PURE__*/ new Vector3() 21453 }, 21454 nearDistance: { 21455 value: 1 21456 }, 21457 farDistance: { 21458 value: 1000 21459 } 21460 } 21461 ]), 21462 vertexShader: ShaderChunk.distanceRGBA_vert, 21463 fragmentShader: ShaderChunk.distanceRGBA_frag 21464 }, 21465 shadow: { 21466 uniforms: /*@__PURE__*/ mergeUniforms([ 21467 UniformsLib.lights, 21468 UniformsLib.fog, 21469 { 21470 color: { 21471 value: /*@__PURE__*/ new Color(0x00000) 21472 }, 21473 opacity: { 21474 value: 1.0 21475 } 21476 } 21477 ]), 21478 vertexShader: ShaderChunk.shadow_vert, 21479 fragmentShader: ShaderChunk.shadow_frag 21480 } 21481 }; 21482 ShaderLib.physical = { 21483 uniforms: /*@__PURE__*/ mergeUniforms([ 21484 ShaderLib.standard.uniforms, 21485 { 21486 clearcoat: { 21487 value: 0 21488 }, 21489 clearcoatMap: { 21490 value: null 21491 }, 21492 clearcoatMapTransform: { 21493 value: /*@__PURE__*/ new Matrix3() 21494 }, 21495 clearcoatNormalMap: { 21496 value: null 21497 }, 21498 clearcoatNormalMapTransform: { 21499 value: /*@__PURE__*/ new Matrix3() 21500 }, 21501 clearcoatNormalScale: { 21502 value: /*@__PURE__*/ new Vector2(1, 1) 21503 }, 21504 clearcoatRoughness: { 21505 value: 0 21506 }, 21507 clearcoatRoughnessMap: { 21508 value: null 21509 }, 21510 clearcoatRoughnessMapTransform: { 21511 value: /*@__PURE__*/ new Matrix3() 21512 }, 21513 dispersion: { 21514 value: 0 21515 }, 21516 iridescence: { 21517 value: 0 21518 }, 21519 iridescenceMap: { 21520 value: null 21521 }, 21522 iridescenceMapTransform: { 21523 value: /*@__PURE__*/ new Matrix3() 21524 }, 21525 iridescenceIOR: { 21526 value: 1.3 21527 }, 21528 iridescenceThicknessMinimum: { 21529 value: 100 21530 }, 21531 iridescenceThicknessMaximum: { 21532 value: 400 21533 }, 21534 iridescenceThicknessMap: { 21535 value: null 21536 }, 21537 iridescenceThicknessMapTransform: { 21538 value: /*@__PURE__*/ new Matrix3() 21539 }, 21540 sheen: { 21541 value: 0 21542 }, 21543 sheenColor: { 21544 value: /*@__PURE__*/ new Color(0x000000) 21545 }, 21546 sheenColorMap: { 21547 value: null 21548 }, 21549 sheenColorMapTransform: { 21550 value: /*@__PURE__*/ new Matrix3() 21551 }, 21552 sheenRoughness: { 21553 value: 1 21554 }, 21555 sheenRoughnessMap: { 21556 value: null 21557 }, 21558 sheenRoughnessMapTransform: { 21559 value: /*@__PURE__*/ new Matrix3() 21560 }, 21561 transmission: { 21562 value: 0 21563 }, 21564 transmissionMap: { 21565 value: null 21566 }, 21567 transmissionMapTransform: { 21568 value: /*@__PURE__*/ new Matrix3() 21569 }, 21570 transmissionSamplerSize: { 21571 value: /*@__PURE__*/ new Vector2() 21572 }, 21573 transmissionSamplerMap: { 21574 value: null 21575 }, 21576 thickness: { 21577 value: 0 21578 }, 21579 thicknessMap: { 21580 value: null 21581 }, 21582 thicknessMapTransform: { 21583 value: /*@__PURE__*/ new Matrix3() 21584 }, 21585 attenuationDistance: { 21586 value: 0 21587 }, 21588 attenuationColor: { 21589 value: /*@__PURE__*/ new Color(0x000000) 21590 }, 21591 specularColor: { 21592 value: /*@__PURE__*/ new Color(1, 1, 1) 21593 }, 21594 specularColorMap: { 21595 value: null 21596 }, 21597 specularColorMapTransform: { 21598 value: /*@__PURE__*/ new Matrix3() 21599 }, 21600 specularIntensity: { 21601 value: 1 21602 }, 21603 specularIntensityMap: { 21604 value: null 21605 }, 21606 specularIntensityMapTransform: { 21607 value: /*@__PURE__*/ new Matrix3() 21608 }, 21609 anisotropyVector: { 21610 value: /*@__PURE__*/ new Vector2() 21611 }, 21612 anisotropyMap: { 21613 value: null 21614 }, 21615 anisotropyMapTransform: { 21616 value: /*@__PURE__*/ new Matrix3() 21617 } 21618 } 21619 ]), 21620 vertexShader: ShaderChunk.meshphysical_vert, 21621 fragmentShader: ShaderChunk.meshphysical_frag 21622 }; 21623 const _rgb = { 21624 r: 0, 21625 b: 0, 21626 g: 0 21627 }; 21628 const _e1$1 = /*@__PURE__*/ new Euler(); 21629 const _m1$1 = /*@__PURE__*/ new Matrix4(); 21630 function WebGLBackground(renderer, cubemaps, cubeuvmaps, state, objects, alpha, premultipliedAlpha) { 21631 const clearColor = new Color(0x000000); 21632 let clearAlpha = alpha === true ? 0 : 1; 21633 let planeMesh; 21634 let boxMesh; 21635 let currentBackground = null; 21636 let currentBackgroundVersion = 0; 21637 let currentTonemapping = null; 21638 function getBackground(scene) { 21639 let background = scene.isScene === true ? scene.background : null; 21640 if (background && background.isTexture) { 21641 const usePMREM = scene.backgroundBlurriness > 0; // use PMREM if the user wants to blur the background 21642 background = (usePMREM ? cubeuvmaps : cubemaps).get(background); 21643 } 21644 return background; 21645 } 21646 function render(scene) { 21647 let forceClear = false; 21648 const background = getBackground(scene); 21649 if (background === null) { 21650 setClear(clearColor, clearAlpha); 21651 } else if (background && background.isColor) { 21652 setClear(background, 1); 21653 forceClear = true; 21654 } 21655 const environmentBlendMode = renderer.xr.getEnvironmentBlendMode(); 21656 if (environmentBlendMode === 'additive') { 21657 state.buffers.color.setClear(0, 0, 0, 1, premultipliedAlpha); 21658 } else if (environmentBlendMode === 'alpha-blend') { 21659 state.buffers.color.setClear(0, 0, 0, 0, premultipliedAlpha); 21660 } 21661 if (renderer.autoClear || forceClear) { 21662 // buffers might not be writable which is required to ensure a correct clear 21663 state.buffers.depth.setTest(true); 21664 state.buffers.depth.setMask(true); 21665 state.buffers.color.setMask(true); 21666 renderer.clear(renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil); 21667 } 21668 } 21669 function addToRenderList(renderList, scene) { 21670 const background = getBackground(scene); 21671 if (background && (background.isCubeTexture || background.mapping === CubeUVReflectionMapping)) { 21672 if (boxMesh === undefined) { 21673 boxMesh = new Mesh(new BoxGeometry(1, 1, 1), new ShaderMaterial({ 21674 name: 'BackgroundCubeMaterial', 21675 uniforms: cloneUniforms(ShaderLib.backgroundCube.uniforms), 21676 vertexShader: ShaderLib.backgroundCube.vertexShader, 21677 fragmentShader: ShaderLib.backgroundCube.fragmentShader, 21678 side: BackSide, 21679 depthTest: false, 21680 depthWrite: false, 21681 fog: false 21682 })); 21683 boxMesh.geometry.deleteAttribute('normal'); 21684 boxMesh.geometry.deleteAttribute('uv'); 21685 boxMesh.onBeforeRender = function(renderer, scene, camera) { 21686 this.matrixWorld.copyPosition(camera.matrixWorld); 21687 }; 21688 // add "envMap" material property so the renderer can evaluate it like for built-in materials 21689 Object.defineProperty(boxMesh.material, 'envMap', { 21690 get: function() { 21691 return this.uniforms.envMap.value; 21692 } 21693 }); 21694 objects.update(boxMesh); 21695 } 21696 _e1$1.copy(scene.backgroundRotation); 21697 // accommodate left-handed frame 21698 _e1$1.x *= -1; 21699 _e1$1.y *= -1; 21700 _e1$1.z *= -1; 21701 if (background.isCubeTexture && background.isRenderTargetTexture === false) { 21702 // environment maps which are not cube render targets or PMREMs follow a different convention 21703 _e1$1.y *= -1; 21704 _e1$1.z *= -1; 21705 } 21706 boxMesh.material.uniforms.envMap.value = background; 21707 boxMesh.material.uniforms.flipEnvMap.value = background.isCubeTexture && background.isRenderTargetTexture === false ? -1 : 1; 21708 boxMesh.material.uniforms.backgroundBlurriness.value = scene.backgroundBlurriness; 21709 boxMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity; 21710 boxMesh.material.uniforms.backgroundRotation.value.setFromMatrix4(_m1$1.makeRotationFromEuler(_e1$1)); 21711 boxMesh.material.toneMapped = ColorManagement.getTransfer(background.colorSpace) !== SRGBTransfer;
vendor: 4,172 bytes, lines 21712-21802
21712 if (currentBackground !== background || currentBackgroundVersion !== background.version || currentTonemapping !== renderer.toneMapping) { 21713 boxMesh.material.needsUpdate = true; 21714 currentBackground = background; 21715 currentBackgroundVersion = background.version; 21716 currentTonemapping = renderer.toneMapping; 21717 } 21718 boxMesh.layers.enableAll(); 21719 // push to the pre-sorted opaque render list 21720 renderList.unshift(boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null); 21721 } else if (background && background.isTexture) { 21722 if (planeMesh === undefined) { 21723 planeMesh = new Mesh(new PlaneGeometry(2, 2), new ShaderMaterial({ 21724 name: 'BackgroundMaterial', 21725 uniforms: cloneUniforms(ShaderLib.background.uniforms), 21726 vertexShader: ShaderLib.background.vertexShader, 21727 fragmentShader: ShaderLib.background.fragmentShader, 21728 side: FrontSide, 21729 depthTest: false, 21730 depthWrite: false, 21731 fog: false 21732 })); 21733 planeMesh.geometry.deleteAttribute('normal'); 21734 // add "map" material property so the renderer can evaluate it like for built-in materials 21735 Object.defineProperty(planeMesh.material, 'map', { 21736 get: function() { 21737 return this.uniforms.t2D.value; 21738 } 21739 }); 21740 objects.update(planeMesh); 21741 } 21742 planeMesh.material.uniforms.t2D.value = background; 21743 planeMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity; 21744 planeMesh.material.toneMapped = ColorManagement.getTransfer(background.colorSpace) !== SRGBTransfer; 21745 if (background.matrixAutoUpdate === true) { 21746 background.updateMatrix(); 21747 } 21748 planeMesh.material.uniforms.uvTransform.value.copy(background.matrix); 21749 if (currentBackground !== background || currentBackgroundVersion !== background.version || currentTonemapping !== renderer.toneMapping) { 21750 planeMesh.material.needsUpdate = true; 21751 currentBackground = background; 21752 currentBackgroundVersion = background.version; 21753 currentTonemapping = renderer.toneMapping; 21754 } 21755 planeMesh.layers.enableAll(); 21756 // push to the pre-sorted opaque render list 21757 renderList.unshift(planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null); 21758 } 21759 } 21760 function setClear(color, alpha) { 21761 color.getRGB(_rgb, getUnlitUniformColorSpace(renderer)); 21762 state.buffers.color.setClear(_rgb.r, _rgb.g, _rgb.b, alpha, premultipliedAlpha); 21763 } 21764 function dispose() { 21765 if (boxMesh !== undefined) { 21766 boxMesh.geometry.dispose(); 21767 boxMesh.material.dispose(); 21768 boxMesh = undefined; 21769 } 21770 if (planeMesh !== undefined) { 21771 planeMesh.geometry.dispose(); 21772 planeMesh.material.dispose(); 21773 planeMesh = undefined; 21774 } 21775 } 21776 return { 21777 getClearColor: function() { 21778 return clearColor; 21779 }, 21780 setClearColor: function(color, alpha = 1) { 21781 clearColor.set(color); 21782 clearAlpha = alpha; 21783 setClear(clearColor, clearAlpha); 21784 }, 21785 getClearAlpha: function() { 21786 return clearAlpha; 21787 }, 21788 setClearAlpha: function(alpha) { 21789 clearAlpha = alpha; 21790 setClear(clearColor, clearAlpha); 21791 }, 21792 render: render, 21793 addToRenderList: addToRenderList, 21794 dispose: dispose 21795 }; 21796 } 21797 function WebGLBindingStates(gl, attributes) { 21798 const maxVertexAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS); 21799 const bindingStates = {}; 21800 const defaultState = createBindingState(null); 21801 let currentState = defaultState; 21802 let forceUpdate = false;
vendor: 19,799 bytes, lines 21803-22220
21803 function setup(object, material, program, geometry, index) { 21804 let updateBuffers = false; 21805 const state = getBindingState(geometry, program, material); 21806 if (currentState !== state) { 21807 currentState = state; 21808 bindVertexArrayObject(currentState.object); 21809 } 21810 updateBuffers = needsUpdate(object, geometry, program, index); 21811 if (updateBuffers) saveCache(object, geometry, program, index); 21812 if (index !== null) { 21813 attributes.update(index, gl.ELEMENT_ARRAY_BUFFER); 21814 } 21815 if (updateBuffers || forceUpdate) { 21816 forceUpdate = false; 21817 setupVertexAttributes(object, material, program, geometry); 21818 if (index !== null) { 21819 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, attributes.get(index).buffer); 21820 } 21821 } 21822 } 21823 function createVertexArrayObject() { 21824 return gl.createVertexArray(); 21825 } 21826 function bindVertexArrayObject(vao) { 21827 return gl.bindVertexArray(vao); 21828 } 21829 function deleteVertexArrayObject(vao) { 21830 return gl.deleteVertexArray(vao); 21831 } 21832 function getBindingState(geometry, program, material) { 21833 const wireframe = material.wireframe === true; 21834 let programMap = bindingStates[geometry.id]; 21835 if (programMap === undefined) { 21836 programMap = {}; 21837 bindingStates[geometry.id] = programMap; 21838 } 21839 let stateMap = programMap[program.id]; 21840 if (stateMap === undefined) { 21841 stateMap = {}; 21842 programMap[program.id] = stateMap; 21843 } 21844 let state = stateMap[wireframe]; 21845 if (state === undefined) { 21846 state = createBindingState(createVertexArrayObject()); 21847 stateMap[wireframe] = state; 21848 } 21849 return state; 21850 } 21851 function createBindingState(vao) { 21852 const newAttributes = []; 21853 const enabledAttributes = []; 21854 const attributeDivisors = []; 21855 for(let i = 0; i < maxVertexAttributes; i++){ 21856 newAttributes[i] = 0; 21857 enabledAttributes[i] = 0; 21858 attributeDivisors[i] = 0; 21859 } 21860 return { 21861 // for backward compatibility on non-VAO support browser 21862 geometry: null, 21863 program: null, 21864 wireframe: false, 21865 newAttributes: newAttributes, 21866 enabledAttributes: enabledAttributes, 21867 attributeDivisors: attributeDivisors, 21868 object: vao, 21869 attributes: {}, 21870 index: null 21871 }; 21872 } 21873 function needsUpdate(object, geometry, program, index) { 21874 const cachedAttributes = currentState.attributes; 21875 const geometryAttributes = geometry.attributes; 21876 let attributesNum = 0; 21877 const programAttributes = program.getAttributes(); 21878 for(const name in programAttributes){ 21879 const programAttribute = programAttributes[name]; 21880 if (programAttribute.location >= 0) { 21881 const cachedAttribute = cachedAttributes[name]; 21882 let geometryAttribute = geometryAttributes[name]; 21883 if (geometryAttribute === undefined) { 21884 if (name === 'instanceMatrix' && object.instanceMatrix) geometryAttribute = object.instanceMatrix; 21885 if (name === 'instanceColor' && object.instanceColor) geometryAttribute = object.instanceColor; 21886 } 21887 if (cachedAttribute === undefined) return true; 21888 if (cachedAttribute.attribute !== geometryAttribute) return true; 21889 if (geometryAttribute && cachedAttribute.data !== geometryAttribute.data) return true; 21890 attributesNum++; 21891 } 21892 } 21893 if (currentState.attributesNum !== attributesNum) return true; 21894 if (currentState.index !== index) return true; 21895 return false; 21896 } 21897 function saveCache(object, geometry, program, index) { 21898 const cache = {}; 21899 const attributes = geometry.attributes; 21900 let attributesNum = 0; 21901 const programAttributes = program.getAttributes(); 21902 for(const name in programAttributes){ 21903 const programAttribute = programAttributes[name]; 21904 if (programAttribute.location >= 0) { 21905 let attribute = attributes[name]; 21906 if (attribute === undefined) { 21907 if (name === 'instanceMatrix' && object.instanceMatrix) attribute = object.instanceMatrix; 21908 if (name === 'instanceColor' && object.instanceColor) attribute = object.instanceColor; 21909 } 21910 const data = {}; 21911 data.attribute = attribute; 21912 if (attribute && attribute.data) { 21913 data.data = attribute.data; 21914 } 21915 cache[name] = data; 21916 attributesNum++; 21917 } 21918 } 21919 currentState.attributes = cache; 21920 currentState.attributesNum = attributesNum; 21921 currentState.index = index; 21922 } 21923 function initAttributes() { 21924 const newAttributes = currentState.newAttributes; 21925 for(let i = 0, il = newAttributes.length; i < il; i++){ 21926 newAttributes[i] = 0; 21927 } 21928 } 21929 function enableAttribute(attribute) { 21930 enableAttributeAndDivisor(attribute, 0); 21931 } 21932 function enableAttributeAndDivisor(attribute, meshPerAttribute) { 21933 const newAttributes = currentState.newAttributes; 21934 const enabledAttributes = currentState.enabledAttributes; 21935 const attributeDivisors = currentState.attributeDivisors; 21936 newAttributes[attribute] = 1; 21937 if (enabledAttributes[attribute] === 0) { 21938 gl.enableVertexAttribArray(attribute); 21939 enabledAttributes[attribute] = 1; 21940 } 21941 if (attributeDivisors[attribute] !== meshPerAttribute) { 21942 gl.vertexAttribDivisor(attribute, meshPerAttribute); 21943 attributeDivisors[attribute] = meshPerAttribute; 21944 } 21945 } 21946 function disableUnusedAttributes() { 21947 const newAttributes = currentState.newAttributes; 21948 const enabledAttributes = currentState.enabledAttributes; 21949 for(let i = 0, il = enabledAttributes.length; i < il; i++){ 21950 if (enabledAttributes[i] !== newAttributes[i]) { 21951 gl.disableVertexAttribArray(i); 21952 enabledAttributes[i] = 0; 21953 } 21954 } 21955 } 21956 function vertexAttribPointer(index, size, type, normalized, stride, offset, integer) { 21957 if (integer === true) { 21958 gl.vertexAttribIPointer(index, size, type, stride, offset); 21959 } else { 21960 gl.vertexAttribPointer(index, size, type, normalized, stride, offset); 21961 } 21962 } 21963 function setupVertexAttributes(object, material, program, geometry) { 21964 initAttributes(); 21965 const geometryAttributes = geometry.attributes; 21966 const programAttributes = program.getAttributes(); 21967 const materialDefaultAttributeValues = material.defaultAttributeValues; 21968 for(const name in programAttributes){ 21969 const programAttribute = programAttributes[name]; 21970 if (programAttribute.location >= 0) { 21971 let geometryAttribute = geometryAttributes[name]; 21972 if (geometryAttribute === undefined) { 21973 if (name === 'instanceMatrix' && object.instanceMatrix) geometryAttribute = object.instanceMatrix; 21974 if (name === 'instanceColor' && object.instanceColor) geometryAttribute = object.instanceColor; 21975 } 21976 if (geometryAttribute !== undefined) { 21977 const normalized = geometryAttribute.normalized; 21978 const size = geometryAttribute.itemSize; 21979 const attribute = attributes.get(geometryAttribute); 21980 // TODO Attribute may not be available on context restore 21981 if (attribute === undefined) continue; 21982 const buffer = attribute.buffer; 21983 const type = attribute.type; 21984 const bytesPerElement = attribute.bytesPerElement; 21985 // check for integer attributes 21986 const integer = type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === IntType; 21987 if (geometryAttribute.isInterleavedBufferAttribute) { 21988 const data = geometryAttribute.data; 21989 const stride = data.stride; 21990 const offset = geometryAttribute.offset; 21991 if (data.isInstancedInterleavedBuffer) { 21992 for(let i = 0; i < programAttribute.locationSize; i++){ 21993 enableAttributeAndDivisor(programAttribute.location + i, data.meshPerAttribute); 21994 } 21995 if (object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined) { 21996 geometry._maxInstanceCount = data.meshPerAttribute * data.count; 21997 } 21998 } else { 21999 for(let i = 0; i < programAttribute.locationSize; i++){ 22000 enableAttribute(programAttribute.location + i); 22001 } 22002 } 22003 gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 22004 for(let i = 0; i < programAttribute.locationSize; i++){ 22005 vertexAttribPointer(programAttribute.location + i, size / programAttribute.locationSize, type, normalized, stride * bytesPerElement, (offset + size / programAttribute.locationSize * i) * bytesPerElement, integer); 22006 } 22007 } else { 22008 if (geometryAttribute.isInstancedBufferAttribute) { 22009 for(let i = 0; i < programAttribute.locationSize; i++){ 22010 enableAttributeAndDivisor(programAttribute.location + i, geometryAttribute.meshPerAttribute); 22011 } 22012 if (object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined) { 22013 geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; 22014 } 22015 } else { 22016 for(let i = 0; i < programAttribute.locationSize; i++){ 22017 enableAttribute(programAttribute.location + i); 22018 } 22019 } 22020 gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 22021 for(let i = 0; i < programAttribute.locationSize; i++){ 22022 vertexAttribPointer(programAttribute.location + i, size / programAttribute.locationSize, type, normalized, size * bytesPerElement, size / programAttribute.locationSize * i * bytesPerElement, integer); 22023 } 22024 } 22025 } else if (materialDefaultAttributeValues !== undefined) { 22026 const value = materialDefaultAttributeValues[name]; 22027 if (value !== undefined) { 22028 switch(value.length){ 22029 case 2: 22030 gl.vertexAttrib2fv(programAttribute.location, value); 22031 break; 22032 case 3: 22033 gl.vertexAttrib3fv(programAttribute.location, value); 22034 break; 22035 case 4: 22036 gl.vertexAttrib4fv(programAttribute.location, value); 22037 break; 22038 default: 22039 gl.vertexAttrib1fv(programAttribute.location, value); 22040 } 22041 } 22042 } 22043 } 22044 } 22045 disableUnusedAttributes(); 22046 } 22047 function dispose() { 22048 reset(); 22049 for(const geometryId in bindingStates){ 22050 const programMap = bindingStates[geometryId]; 22051 for(const programId in programMap){ 22052 const stateMap = programMap[programId]; 22053 for(const wireframe in stateMap){ 22054 deleteVertexArrayObject(stateMap[wireframe].object); 22055 delete stateMap[wireframe]; 22056 } 22057 delete programMap[programId]; 22058 } 22059 delete bindingStates[geometryId]; 22060 } 22061 } 22062 function releaseStatesOfGeometry(geometry) { 22063 if (bindingStates[geometry.id] === undefined) return; 22064 const programMap = bindingStates[geometry.id]; 22065 for(const programId in programMap){ 22066 const stateMap = programMap[programId]; 22067 for(const wireframe in stateMap){ 22068 deleteVertexArrayObject(stateMap[wireframe].object); 22069 delete stateMap[wireframe]; 22070 } 22071 delete programMap[programId]; 22072 } 22073 delete bindingStates[geometry.id]; 22074 } 22075 function releaseStatesOfProgram(program) { 22076 for(const geometryId in bindingStates){ 22077 const programMap = bindingStates[geometryId]; 22078 if (programMap[program.id] === undefined) continue; 22079 const stateMap = programMap[program.id]; 22080 for(const wireframe in stateMap){ 22081 deleteVertexArrayObject(stateMap[wireframe].object); 22082 delete stateMap[wireframe]; 22083 } 22084 delete programMap[program.id]; 22085 } 22086 } 22087 function reset() { 22088 resetDefaultState(); 22089 forceUpdate = true; 22090 if (currentState === defaultState) return; 22091 currentState = defaultState; 22092 bindVertexArrayObject(currentState.object); 22093 } 22094 // for backward-compatibility 22095 function resetDefaultState() { 22096 defaultState.geometry = null; 22097 defaultState.program = null; 22098 defaultState.wireframe = false; 22099 } 22100 return { 22101 setup: setup, 22102 reset: reset, 22103 resetDefaultState: resetDefaultState, 22104 dispose: dispose, 22105 releaseStatesOfGeometry: releaseStatesOfGeometry, 22106 releaseStatesOfProgram: releaseStatesOfProgram, 22107 initAttributes: initAttributes, 22108 enableAttribute: enableAttribute, 22109 disableUnusedAttributes: disableUnusedAttributes 22110 }; 22111 } 22112 function WebGLBufferRenderer(gl, extensions, info) { 22113 let mode; 22114 function setMode(value) { 22115 mode = value; 22116 } 22117 function render(start, count) { 22118 gl.drawArrays(mode, start, count); 22119 info.update(count, mode, 1); 22120 } 22121 function renderInstances(start, count, primcount) { 22122 if (primcount === 0) return; 22123 gl.drawArraysInstanced(mode, start, count, primcount); 22124 info.update(count, mode, primcount); 22125 } 22126 function renderMultiDraw(starts, counts, drawCount) { 22127 if (drawCount === 0) return; 22128 const extension = extensions.get('WEBGL_multi_draw'); 22129 extension.multiDrawArraysWEBGL(mode, starts, 0, counts, 0, drawCount); 22130 let elementCount = 0; 22131 for(let i = 0; i < drawCount; i++){ 22132 elementCount += counts[i]; 22133 } 22134 info.update(elementCount, mode, 1); 22135 } 22136 function renderMultiDrawInstances(starts, counts, drawCount, primcount) { 22137 if (drawCount === 0) return; 22138 const extension = extensions.get('WEBGL_multi_draw'); 22139 if (extension === null) { 22140 for(let i = 0; i < starts.length; i++){ 22141 renderInstances(starts[i], counts[i], primcount[i]); 22142 } 22143 } else { 22144 extension.multiDrawArraysInstancedWEBGL(mode, starts, 0, counts, 0, primcount, 0, drawCount); 22145 let elementCount = 0; 22146 for(let i = 0; i < drawCount; i++){ 22147 elementCount += counts[i] * primcount[i]; 22148 } 22149 info.update(elementCount, mode, 1); 22150 } 22151 } 22152 // 22153 this.setMode = setMode; 22154 this.render = render; 22155 this.renderInstances = renderInstances; 22156 this.renderMultiDraw = renderMultiDraw; 22157 this.renderMultiDrawInstances = renderMultiDrawInstances; 22158 } 22159 function WebGLCapabilities(gl, extensions, parameters, utils) { 22160 let maxAnisotropy; 22161 function getMaxAnisotropy() { 22162 if (maxAnisotropy !== undefined) return maxAnisotropy; 22163 if (extensions.has('EXT_texture_filter_anisotropic') === true) { 22164 const extension = extensions.get('EXT_texture_filter_anisotropic'); 22165 maxAnisotropy = gl.getParameter(extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT); 22166 } else { 22167 maxAnisotropy = 0; 22168 } 22169 return maxAnisotropy; 22170 } 22171 function textureFormatReadable(textureFormat) { 22172 if (textureFormat !== RGBAFormat && utils.convert(textureFormat) !== gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT)) { 22173 return false; 22174 } 22175 return true; 22176 } 22177 function textureTypeReadable(textureType) { 22178 const halfFloatSupportedByExt = textureType === HalfFloatType && (extensions.has('EXT_color_buffer_half_float') || extensions.has('EXT_color_buffer_float')); 22179 if (textureType !== UnsignedByteType && utils.convert(textureType) !== gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE) && // Edge and Chrome Mac < 52 (#9513) 22180 textureType !== FloatType && !halfFloatSupportedByExt) { 22181 return false; 22182 } 22183 return true; 22184 } 22185 function getMaxPrecision(precision) { 22186 if (precision === 'highp') { 22187 if (gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.HIGH_FLOAT).precision > 0 && gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT).precision > 0) { 22188 return 'highp'; 22189 } 22190 precision = 'mediump'; 22191 } 22192 if (precision === 'mediump') { 22193 if (gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.MEDIUM_FLOAT).precision > 0 && gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT).precision > 0) { 22194 return 'mediump'; 22195 } 22196 } 22197 return 'lowp'; 22198 } 22199 let precision = parameters.precision !== undefined ? parameters.precision : 'highp'; 22200 const maxPrecision = getMaxPrecision(precision); 22201 if (maxPrecision !== precision) { 22202 console.warn('THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.'); 22203 precision = maxPrecision; 22204 } 22205 const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true; 22206 const reverseDepthBuffer = parameters.reverseDepthBuffer === true && extensions.has('EXT_clip_control'); 22207 const maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS); 22208 const maxVertexTextures = gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS); 22209 const maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE); 22210 const maxCubemapSize = gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE); 22211 const maxAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS); 22212 const maxVertexUniforms = gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS); 22213 const maxVaryings = gl.getParameter(gl.MAX_VARYING_VECTORS); 22214 const maxFragmentUniforms = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS); 22215 const vertexTextures = maxVertexTextures > 0; 22216 const maxSamples = gl.getParameter(gl.MAX_SAMPLES); 22217 return { 22218 isWebGL2: true, 22219 getMaxAnisotropy: getMaxAnisotropy, 22220 getMaxPrecision: getMaxPrecision,
vendor: 1,977 bytes, lines 22221-22267
22221 textureFormatReadable: textureFormatReadable, 22222 textureTypeReadable: textureTypeReadable, 22223 precision: precision, 22224 logarithmicDepthBuffer: logarithmicDepthBuffer, 22225 reverseDepthBuffer: reverseDepthBuffer, 22226 maxTextures: maxTextures, 22227 maxVertexTextures: maxVertexTextures, 22228 maxTextureSize: maxTextureSize, 22229 maxCubemapSize: maxCubemapSize, 22230 maxAttributes: maxAttributes, 22231 maxVertexUniforms: maxVertexUniforms, 22232 maxVaryings: maxVaryings, 22233 maxFragmentUniforms: maxFragmentUniforms, 22234 vertexTextures: vertexTextures, 22235 maxSamples: maxSamples 22236 }; 22237 } 22238 function WebGLClipping(properties) { 22239 const scope = this; 22240 let globalState = null, numGlobalPlanes = 0, localClippingEnabled = false, renderingShadows = false; 22241 const plane = new Plane(), viewNormalMatrix = new Matrix3(), uniform = { 22242 value: null, 22243 needsUpdate: false 22244 }; 22245 this.uniform = uniform; 22246 this.numPlanes = 0; 22247 this.numIntersection = 0; 22248 this.init = function(planes, enableLocalClipping) { 22249 const enabled = planes.length !== 0 || enableLocalClipping || // enable state of previous frame - the clipping code has to 22250 // run another frame in order to reset the state: 22251 numGlobalPlanes !== 0 || localClippingEnabled; 22252 localClippingEnabled = enableLocalClipping; 22253 numGlobalPlanes = planes.length; 22254 return enabled; 22255 }; 22256 this.beginShadows = function() { 22257 renderingShadows = true; 22258 projectPlanes(null); 22259 }; 22260 this.endShadows = function() { 22261 renderingShadows = false; 22262 }; 22263 this.setGlobalState = function(planes, camera) { 22264 globalState = projectPlanes(planes, camera, 0); 22265 }; 22266 this.setState = function(material, camera, useCache) { 22267 const planes = material.clippingPlanes, clipIntersection = material.clipIntersection, clipShadows = material.clipSh
vendor: 4,466 bytes, lines 22267-22370
22267adows; 22268 const materialProperties = properties.get(material); 22269 if (!localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && !clipShadows) { 22270 // there's no local clipping 22271 if (renderingShadows) { 22272 // there's no global clipping 22273 projectPlanes(null); 22274 } else { 22275 resetGlobalState(); 22276 } 22277 } else { 22278 const nGlobal = renderingShadows ? 0 : numGlobalPlanes, lGlobal = nGlobal * 4; 22279 let dstArray = materialProperties.clippingState || null; 22280 uniform.value = dstArray; // ensure unique state 22281 dstArray = projectPlanes(planes, camera, lGlobal, useCache); 22282 for(let i = 0; i !== lGlobal; ++i){ 22283 dstArray[i] = globalState[i]; 22284 } 22285 materialProperties.clippingState = dstArray; 22286 this.numIntersection = clipIntersection ? this.numPlanes : 0; 22287 this.numPlanes += nGlobal; 22288 } 22289 }; 22290 function resetGlobalState() { 22291 if (uniform.value !== globalState) { 22292 uniform.value = globalState; 22293 uniform.needsUpdate = numGlobalPlanes > 0; 22294 } 22295 scope.numPlanes = numGlobalPlanes; 22296 scope.numIntersection = 0; 22297 } 22298 function projectPlanes(planes, camera, dstOffset, skipTransform) { 22299 const nPlanes = planes !== null ? planes.length : 0; 22300 let dstArray = null; 22301 if (nPlanes !== 0) { 22302 dstArray = uniform.value; 22303 if (skipTransform !== true || dstArray === null) { 22304 const flatSize = dstOffset + nPlanes * 4, viewMatrix = camera.matrixWorldInverse; 22305 viewNormalMatrix.getNormalMatrix(viewMatrix); 22306 if (dstArray === null || dstArray.length < flatSize) { 22307 dstArray = new Float32Array(flatSize); 22308 } 22309 for(let i = 0, i4 = dstOffset; i !== nPlanes; ++i, i4 += 4){ 22310 plane.copy(planes[i]).applyMatrix4(viewMatrix, viewNormalMatrix); 22311 plane.normal.toArray(dstArray, i4); 22312 dstArray[i4 + 3] = plane.constant; 22313 } 22314 } 22315 uniform.value = dstArray; 22316 uniform.needsUpdate = true; 22317 } 22318 scope.numPlanes = nPlanes; 22319 scope.numIntersection = 0; 22320 return dstArray; 22321 } 22322 } 22323 function WebGLCubeMaps(renderer) { 22324 let cubemaps = new WeakMap(); 22325 function mapTextureMapping(texture, mapping) { 22326 if (mapping === EquirectangularReflectionMapping) { 22327 texture.mapping = CubeReflectionMapping; 22328 } else if (mapping === EquirectangularRefractionMapping) { 22329 texture.mapping = CubeRefractionMapping; 22330 } 22331 return texture; 22332 } 22333 function get(texture) { 22334 if (texture && texture.isTexture) { 22335 const mapping = texture.mapping; 22336 if (mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping) { 22337 if (cubemaps.has(texture)) { 22338 const cubemap = cubemaps.get(texture).texture; 22339 return mapTextureMapping(cubemap, texture.mapping); 22340 } else { 22341 const image = texture.image; 22342 if (image && image.height > 0) { 22343 const renderTarget = new WebGLCubeRenderTarget(image.height); 22344 renderTarget.fromEquirectangularTexture(renderer, texture); 22345 cubemaps.set(texture, renderTarget); 22346 texture.addEventListener('dispose', onTextureDispose); 22347 return mapTextureMapping(renderTarget.texture, texture.mapping); 22348 } else { 22349 // image not yet ready. try the conversion next frame 22350 return null; 22351 } 22352 } 22353 } 22354 } 22355 return texture; 22356 } 22357 function onTextureDispose(event) { 22358 const texture = event.target; 22359 texture.removeEventListener('dispose', onTextureDispose); 22360 const cubemap = cubemaps.get(texture); 22361 if (cubemap !== undefined) { 22362 cubemaps.delete(texture); 22363 cubemap.dispose(); 22364 } 22365 } 22366 function dispose() { 22367 cubemaps = new WeakMap(); 22368 } 22369 return { 22370 get: get,
22371 dispose: dispose 22372 }; 22373 } 22374 const LOD_MIN = 4; 22375 // The standard deviations (radians) associated with the extra mips. These are 22376 // chosen to approximate a Trowbridge-Reitz distribution function times the 22377 // geometric shadowing function. These sigma values squared must match the 22378 // variance #defines in cube_uv_reflection_fragment.glsl.js. 22379 const EXTRA_LOD_SIGMA = [ 22380 0.125, 22381 0.215, 22382 0.35, 22383 0.446, 22384 0.526, 22385 0.582 22386 ]; 22387 // The maximum length of the blur for loop. Smaller sigmas will use fewer 22388 // samples and exit early, but not recompile the shader. 22389 const MAX_SAMPLES$1 = 20; 22390 const _flatCamera = /*@__PURE__*/ new OrthographicCamera(); 22391 const _clearColor = /*@__PURE__*/ new Color(); 22392 let _oldTarget = null; 22393 let _oldActiveCubeFace = 0; 22394 let _oldActiveMipmapLevel = 0; 22395 let _oldXrEnabled = false; 22396 // Golden Ratio 22397 const PHI = (1 + Math.sqrt(5)) / 2; 22398 const INV_PHI = 1 / PHI; 22399 // Vertices of a dodecahedron (except the opposites, which represent the 22400 // same axis), used as axis directions evenly spread on a sphere. 22401 const _axisDirections = [ 22402 /*@__PURE__*/ new Vector3(-PHI, INV_PHI, 0), 22403 /*@__PURE__*/ new Vector3(PHI, INV_PHI, 0), 22404 /*@__PURE__*/ new Vector3(-INV_PHI, 0, PHI), 22405 /*@__PURE__*/ new Vector3(INV_PHI, 0, PHI), 22406 /*@__PURE__*/ new Vector3(0, PHI, -INV_PHI), 22407 /*@__PURE__*/ new Vector3(0, PHI, INV_PHI), 22408 /*@__PURE__*/ new Vector3(-1, 1, -1), 22409 /*@__PURE__*/ new Vector3(1, 1, -1), 22410 /*@__PURE__*/ new Vector3(-1, 1, 1), 22411 /*@__PURE__*/ new Vector3(1, 1, 1) 22412 ]; 22413 const _origin = /*@__PURE__*/ new Vector3(); 22414 /** 22415 * This class generates a Prefiltered, Mipmapped Radiance Environment Map 22416 * (PMREM) from a cubeMap environment texture. This allows different levels of 22417 * blur to be quickly accessed based on material roughness. It is packed into a 22418 * special CubeUV format that allows us to perform custom interpolation so that 22419 * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap 22420 * chain, it only goes down to the LOD_MIN level (above), and then creates extra 22421 * even more filtered 'mips' at the same LOD_MIN resolution, associated with 22422 * higher roughness levels. In this way we maintain resolution to smoothly 22423 * interpolate diffuse lighting while limiting sampling computation. 22424 * 22425 * Paper: Fast, Accurate Image-Based Lighting 22426 * https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view 22427 */ class PMREMGenerator { 22428 /** 22429 * Generates a PMREM from a supplied Scene, which can be faster than using an 22430 * image if networking bandwidth is low. Optional sigma specifies a blur radius 22431 * in radians to be applied to the scene before PMREM generation. Optional near 22432 * and far planes ensure the scene is rendered in its entirety. 22433 * 22434 * @param {Scene} scene 22435 * @param {number} sigma 22436 * @param {number} near 22437 * @param {number} far 22438 * @param {Object} [options={}] 22439 * @return {WebGLRenderTarget} 22440 */ fromScene(scene, sigma = 0, near = 0.1, far = 100, options = {}) { 22441 const { size = 256, position = _origin } = options; 22442 _oldTarget = this._renderer.getRenderTarget(); 22443 _oldActiveCubeFace = this._renderer.getActiveCubeFace(); 22444 _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); 22445 _oldXrEnabled = this._renderer.xr.enabled; 22446 this._renderer.xr.enabled = false; 22447 this._setSize(size); 22448 const cubeUVRenderTarget = this._allocateTargets(); 22449 cubeUVRenderTarget.depthBuffer = true; 22450 this._sceneToCubeUV(scene, near, far, cubeUVRenderTarget, position); 22451 if (sigma > 0) { 22452 this._blur(cubeUVRenderTarget, 0, 0, sigma); 22453 } 22454 this._applyPMREM(cubeUVRenderTarget); 22455 this._cleanup(cubeUVRenderTarget); 22456 return cubeUVRenderTarget; 22457 } 22458 /** 22459 * Generates a PMREM from an equirectangular texture, which can be either LDR 22460 * or HDR. The ideal input image size is 1k (1024 x 512), 22461 * as this matches best with the 256 x 256 cubemap output. 22462 * The smallest supported equirectangular image size is 64 x 32. 22463 * 22464 * @param {Texture} equirectangular 22465 * @param {?WebGLRenderTarget} [renderTarget=null] - Optional render target. 22466 * @return {WebGLRenderTarget} 22467 */ fromEquirectangular(equirectangular, renderTarget = null) { 22468 return this._fromTexture(equirectangular, renderTarget); 22469 } 22470 /** 22471 * Generates a PMREM from an cubemap texture, which can be either LDR 22472 * or HDR. The ideal input cube size is 256 x 256, 22473 * as this matches best with the 256 x 256 cubemap output. 22474 * The smallest supported cube size is 16 x 16. 22475 * 22476 * @param {Texture} cubemap 22477 * @param {null} [renderTarget=null] - Optional render target. 22478 * @return {WebGLRenderTarget} 22479 */ fromCubemap(cubemap, renderTarget = null) { 22480 return this._fromTexture(cubemap, renderTarget); 22481 } 22482 /** 22483 * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during 22484 * your texture's network fetch for increased concurrency. 22485 */ compileCubemapShader() { 22486 if (this._cubemapMaterial === null) { 22487 this._cubemapMaterial = _getCubemapMaterial(); 22488 this._compileMaterial(this._cubemapMaterial); 22489 } 22490 } 22491 /** 22492 * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during 22493 * your texture's network fetch for increased concurrency. 22494 */ compileEquirectangularShader() { 22495 if (this._equirectMaterial === null) { 22496 this._equirectMaterial = _getEquirectMaterial(); 22497 this._compileMaterial(this._equirectMaterial); 22498 } 22499 } 22500 /** 22501 * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class, 22502 * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on 22503 * one of them will cause any others to also become unusable. 22504 */ dispose() { 22505 this._dispose(); 22506 if (this._cubemapMaterial !== null) this._cubemapMaterial.dispose(); 22507 if (this._equirectMaterial !== null) this._equirectMaterial.dispose(); 22508 } 22509 // private interface 22510 _setSize(cubeSize) { 22511 this._lodMax = Math.floor(Math.log2(cubeSize)); 22512 this._cubeSize = Math.pow(2, this._lodMax); 22513 } 22514 _dispose() { 22515 if (this._blurMaterial !== null) this._blurMaterial.dispose(); 22516 if (this._pingPongRenderTarget !== null) this._pingPongRenderTarget.dispose(); 22517 for(let i = 0; i < this._lodPlanes.length; i++){ 22518 this._lodPlanes[i].dispose(); 22519 } 22520 } 22521 _cleanup(outputTarget) { 22522 this._renderer.setRenderTarget(_oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel); 22523 this._renderer.xr.enabled = _oldXrEnabled; 22524 outputTarget.scissorTest = false;
vendor: 3,102 bytes, lines 22525-22598
22525 _setViewport(outputTarget, 0, 0, outputTarget.width, outputTarget.height); 22526 } 22527 _fromTexture(texture, renderTarget) { 22528 if (texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping) { 22529 this._setSize(texture.image.length === 0 ? 16 : texture.image[0].width || texture.image[0].image.width); 22530 } else { 22531 this._setSize(texture.image.width / 4); 22532 } 22533 _oldTarget = this._renderer.getRenderTarget(); 22534 _oldActiveCubeFace = this._renderer.getActiveCubeFace(); 22535 _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); 22536 _oldXrEnabled = this._renderer.xr.enabled; 22537 this._renderer.xr.enabled = false; 22538 const cubeUVRenderTarget = renderTarget || this._allocateTargets(); 22539 this._textureToCubeUV(texture, cubeUVRenderTarget); 22540 this._applyPMREM(cubeUVRenderTarget); 22541 this._cleanup(cubeUVRenderTarget); 22542 return cubeUVRenderTarget; 22543 } 22544 _allocateTargets() { 22545 const width = 3 * Math.max(this._cubeSize, 16 * 7); 22546 const height = 4 * this._cubeSize; 22547 const params = { 22548 magFilter: LinearFilter, 22549 minFilter: LinearFilter, 22550 generateMipmaps: false, 22551 type: HalfFloatType, 22552 format: RGBAFormat, 22553 colorSpace: LinearSRGBColorSpace, 22554 depthBuffer: false 22555 }; 22556 const cubeUVRenderTarget = _createRenderTarget(width, height, params); 22557 if (this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height) { 22558 if (this._pingPongRenderTarget !== null) { 22559 this._dispose(); 22560 } 22561 this._pingPongRenderTarget = _createRenderTarget(width, height, params); 22562 const { _lodMax } = this; 22563 ({ sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas } = _createPlanes(_lodMax)); 22564 this._blurMaterial = _getBlurShader(_lodMax, width, height); 22565 } 22566 return cubeUVRenderTarget; 22567 } 22568 _compileMaterial(material) { 22569 const tmpMesh = new Mesh(this._lodPlanes[0], material); 22570 this._renderer.compile(tmpMesh, _flatCamera); 22571 } 22572 _sceneToCubeUV(scene, near, far, cubeUVRenderTarget, position) { 22573 const fov = 90; 22574 const aspect = 1; 22575 const cubeCamera = new PerspectiveCamera(fov, aspect, near, far); 22576 const upSign = [ 22577 1, 22578 -1, 22579 1, 22580 1, 22581 1, 22582 1 22583 ]; 22584 const forwardSign = [ 22585 1, 22586 1, 22587 1, 22588 -1, 22589 -1, 22590 -1 22591 ]; 22592 const renderer = this._renderer; 22593 const originalAutoClear = renderer.autoClear; 22594 const toneMapping = renderer.toneMapping; 22595 renderer.getClearColor(_clearColor); 22596 renderer.toneMapping = NoToneMapping; 22597 renderer.autoClear = false; 22598 const backgroundMaterial = new MeshBasicMaterial({
22599 name: 'PMREM.Background', 22600 side: BackSide, 22601 depthWrite: false, 22602 depthTest: false 22603 }); 22604 const backgroundBox = new Mesh(new BoxGeometry(), backgroundMaterial); 22605 let useSolidColor = false; 22606 const background = scene.background; 22607 if (background) { 22608 if (background.isColor) { 22609 backgroundMaterial.color.copy(background); 22610 scene.background = null; 22611 useSolidColor = true; 22612 } 22613 } else { 22614 backgroundMaterial.color.copy(_clearColor); 22615 useSolidColor = true; 22616 } 22617 for(let i = 0; i < 6; i++){ 22618 const col = i % 3; 22619 if (col === 0) { 22620 cubeCamera.up.set(0, upSign[i], 0); 22621 cubeCamera.position.set(position.x, position.y, position.z); 22622 cubeCamera.lookAt(position.x + forwardSign[i], position.y, position.z); 22623 } else if (col === 1) { 22624 cubeCamera.up.set(0, 0, upSign[i]); 22625 cubeCamera.position.set(position.x, position.y, position.z); 22626 cubeCamera.lookAt(position.x, position.y + forwardSign[i], position.z); 22627 } else { 22628 cubeCamera.up.set(0, upSign[i], 0); 22629 cubeCamera.position.set(position.x, position.y, position.z); 22630 cubeCamera.lookAt(position.x, position.y, position.z + forwardSign[i]); 22631 } 22632 const size = this._cubeSize; 22633 _setViewport(cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size); 22634 renderer.setRenderTarget(cubeUVRenderTarget); 22635 if (useSolidColor) { 22636 renderer.render(backgroundBox, cubeCamera); 22637 } 22638 renderer.render(scene, cubeCamera); 22639 } 22640 backgroundBox.geometry.dispose(); 22641 backgroundBox.material.dispose(); 22642 renderer.toneMapping = toneMapping; 22643 renderer.autoClear = originalAutoClear; 22644 scene.background = background; 22645 } 22646 _textureToCubeUV(texture, cubeUVRenderTarget) { 22647 const renderer = this._renderer; 22648 const isCubeTexture = texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping; 22649 if (isCubeTexture) { 22650 if (this._cubemapMaterial === null) { 22651 this._cubemapMaterial = _getCubemapMaterial(); 22652 } 22653 this._cubemapMaterial.uniforms.flipEnvMap.value = texture.isRenderTargetTexture === false ? -1 : 1; 22654 } else { 22655 if (this._equirectMaterial === null) { 22656 this._equirectMaterial = _getEquirectMaterial(); 22657 } 22658 } 22659 const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial; 22660 const mesh = new Mesh(this._lodPlanes[0], material); 22661 const uniforms = material.uniforms; 22662 uniforms['envMap'].value = texture; 22663 const size = this._cubeSize; 22664 _setViewport(cubeUVRenderTarget, 0, 0, 3 * size, 2 * size); 22665 renderer.setRenderTarget(cubeUVRenderTarget); 22666 renderer.render(mesh, _flatCamera); 22667 } 22668 _applyPMREM(cubeUVRenderTarget) { 22669 const renderer = this._renderer; 22670 const autoClear = renderer.autoClear; 22671 renderer.autoClear = false; 22672 const n = this._lodPlanes.length; 22673 for(let i = 1; i < n; i++){ 22674 const sigma = Math.sqrt(this._sigmas[i] * this._sigmas[i] - this._sigmas[i - 1] * this._sigmas[i - 1]); 22675 const poleAxis = _axisDirections[(n - i - 1) % _axisDirections.length]; 22676 this._blur(cubeUVRenderTarget, i - 1, i, sigma, poleAxis); 22677 } 22678 renderer.autoClear = autoClear; 22679 } 22680 /** 22681 * This is a two-pass Gaussian blur for a cubemap. Normally this is done 22682 * vertically and horizontally, but this breaks down on a cube. Here we apply 22683 * the blur latitudinally (around the poles), and then longitudinally (towards 22684 * the poles) to approximate the orthogonally-separable blur. It is least 22685 * accurate at the poles, but still does a decent job. 22686 * 22687 * @param {WebGLRenderTarget} cubeUVRenderTarget 22688 * @param {number} lodIn 22689 * @param {number} lodOut 22690 * @param {number} sigma 22691 * @param {Vector3} [poleAxis] 22692 */ _blur(cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis) { 22693 const pingPongRenderTarget = this._pingPongRenderTarget; 22694 this._halfBlur(cubeUVRenderTarget, pingPongRenderTarget, lodIn, lodOut, sigma, 'latitudinal', poleAxis); 22695 this._halfBlur(pingPongRenderTarget, cubeUVRenderTarget, lodOut, lodOut, sigma, 'longitudinal', poleAxis); 22696 } 22697 _halfBlur(targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis) { 22698 const renderer = this._renderer; 22699 const blurMaterial = this._blurMaterial; 22700 if (direction !== 'latitudinal' && direction !== 'longitudinal') { 22701 console.error('blur direction must be either latitudinal or longitudinal!'); 22702 } 22703 // Number of standard deviations at which to cut off the discrete approximation. 22704 const STANDARD_DEVIATIONS = 3; 22705 const blurMesh = new Mesh(this._lodPlanes[lodOut], blurMaterial); 22706 const blurUniforms = blurMaterial.uniforms; 22707 const pixels = this._sizeLods[lodIn] - 1;
vendor: 57,040 bytes, lines 22708-24364
22708 const radiansPerPixel = isFinite(sigmaRadians) ? Math.PI / (2 * pixels) : 2 * Math.PI / (2 * MAX_SAMPLES$1 - 1); 22709 const sigmaPixels = sigmaRadians / radiansPerPixel; 22710 const samples = isFinite(sigmaRadians) ? 1 + Math.floor(STANDARD_DEVIATIONS * sigmaPixels) : MAX_SAMPLES$1; 22711 if (samples > MAX_SAMPLES$1) { 22712 console.warn(`sigmaRadians, ${sigmaRadians}, is too large and will clip, as it requested ${samples} samples when the maximum is set to ${MAX_SAMPLES$1}`); 22713 } 22714 const weights = []; 22715 let sum = 0; 22716 for(let i = 0; i < MAX_SAMPLES$1; ++i){ 22717 const x = i / sigmaPixels; 22718 const weight = Math.exp(-x * x / 2); 22719 weights.push(weight); 22720 if (i === 0) { 22721 sum += weight; 22722 } else if (i < samples) { 22723 sum += 2 * weight; 22724 } 22725 } 22726 for(let i = 0; i < weights.length; i++){ 22727 weights[i] = weights[i] / sum; 22728 } 22729 blurUniforms['envMap'].value = targetIn.texture; 22730 blurUniforms['samples'].value = samples; 22731 blurUniforms['weights'].value = weights; 22732 blurUniforms['latitudinal'].value = direction === 'latitudinal'; 22733 if (poleAxis) { 22734 blurUniforms['poleAxis'].value = poleAxis; 22735 } 22736 const { _lodMax } = this; 22737 blurUniforms['dTheta'].value = radiansPerPixel; 22738 blurUniforms['mipInt'].value = _lodMax - lodIn; 22739 const outputSize = this._sizeLods[lodOut]; 22740 const x = 3 * outputSize * (lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0); 22741 const y = 4 * (this._cubeSize - outputSize); 22742 _setViewport(targetOut, x, y, 3 * outputSize, 2 * outputSize); 22743 renderer.setRenderTarget(targetOut); 22744 renderer.render(blurMesh, _flatCamera); 22745 } 22746 constructor(renderer){ 22747 this._renderer = renderer; 22748 this._pingPongRenderTarget = null; 22749 this._lodMax = 0; 22750 this._cubeSize = 0; 22751 this._lodPlanes = []; 22752 this._sizeLods = []; 22753 this._sigmas = []; 22754 this._blurMaterial = null; 22755 this._cubemapMaterial = null; 22756 this._equirectMaterial = null; 22757 this._compileMaterial(this._blurMaterial); 22758 } 22759 } 22760 function _createPlanes(lodMax) { 22761 const lodPlanes = []; 22762 const sizeLods = []; 22763 const sigmas = []; 22764 let lod = lodMax; 22765 const totalLods = lodMax - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length; 22766 for(let i = 0; i < totalLods; i++){ 22767 const sizeLod = Math.pow(2, lod); 22768 sizeLods.push(sizeLod); 22769 let sigma = 1.0 / sizeLod; 22770 if (i > lodMax - LOD_MIN) { 22771 sigma = EXTRA_LOD_SIGMA[i - lodMax + LOD_MIN - 1]; 22772 } else if (i === 0) { 22773 sigma = 0; 22774 } 22775 sigmas.push(sigma); 22776 const texelSize = 1.0 / (sizeLod - 2); 22777 const min = -texelSize; 22778 const max = 1 + texelSize; 22779 const uv1 = [ 22780 min, 22781 min, 22782 max, 22783 min, 22784 max, 22785 max, 22786 min, 22787 min, 22788 max, 22789 max, 22790 min, 22791 max 22792 ]; 22793 const cubeFaces = 6; 22794 const vertices = 6; 22795 const positionSize = 3; 22796 const uvSize = 2; 22797 const faceIndexSize = 1; 22798 const position = new Float32Array(positionSize * vertices * cubeFaces); 22799 const uv = new Float32Array(uvSize * vertices * cubeFaces); 22800 const faceIndex = new Float32Array(faceIndexSize * vertices * cubeFaces); 22801 for(let face = 0; face < cubeFaces; face++){ 22802 const x = face % 3 * 2 / 3 - 1; 22803 const y = face > 2 ? 0 : -1; 22804 const coordinates = [ 22805 x, 22806 y, 22807 0, 22808 x + 2 / 3, 22809 y, 22810 0, 22811 x + 2 / 3, 22812 y + 1, 22813 0, 22814 x, 22815 y, 22816 0, 22817 x + 2 / 3, 22818 y + 1, 22819 0, 22820 x, 22821 y + 1, 22822 0 22823 ]; 22824 position.set(coordinates, positionSize * vertices * face); 22825 uv.set(uv1, uvSize * vertices * face); 22826 const fill = [ 22827 face, 22828 face, 22829 face, 22830 face, 22831 face, 22832 face 22833 ]; 22834 faceIndex.set(fill, faceIndexSize * vertices * face); 22835 } 22836 const planes = new BufferGeometry(); 22837 planes.setAttribute('position', new BufferAttribute(position, positionSize)); 22838 planes.setAttribute('uv', new BufferAttribute(uv, uvSize)); 22839 planes.setAttribute('faceIndex', new BufferAttribute(faceIndex, faceIndexSize)); 22840 lodPlanes.push(planes); 22841 if (lod > LOD_MIN) { 22842 lod--; 22843 } 22844 } 22845 return { 22846 lodPlanes, 22847 sizeLods, 22848 sigmas 22849 }; 22850 } 22851 function _createRenderTarget(width, height, params) { 22852 const cubeUVRenderTarget = new WebGLRenderTarget(width, height, params); 22853 cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping; 22854 cubeUVRenderTarget.texture.name = 'PMREM.cubeUv'; 22855 cubeUVRenderTarget.scissorTest = true; 22856 return cubeUVRenderTarget; 22857 } 22858 function _setViewport(target, x, y, width, height) { 22859 target.viewport.set(x, y, width, height); 22860 target.scissor.set(x, y, width, height); 22861 } 22862 function _getBlurShader(lodMax, width, height) { 22863 const weights = new Float32Array(MAX_SAMPLES$1); 22864 const poleAxis = new Vector3(0, 1, 0); 22865 const shaderMaterial = new ShaderMaterial({ 22866 name: 'SphericalGaussianBlur', 22867 defines: { 22868 'n': MAX_SAMPLES$1, 22869 'CUBEUV_TEXEL_WIDTH': 1.0 / width, 22870 'CUBEUV_TEXEL_HEIGHT': 1.0 / height, 22871 'CUBEUV_MAX_MIP': `${lodMax}.0` 22872 }, 22873 uniforms: { 22874 'envMap': { 22875 value: null 22876 }, 22877 'samples': { 22878 value: 1 22879 }, 22880 'weights': { 22881 value: weights 22882 }, 22883 'latitudinal': { 22884 value: false 22885 }, 22886 'dTheta': { 22887 value: 0 22888 }, 22889 'mipInt': { 22890 value: 0 22891 }, 22892 'poleAxis': { 22893 value: poleAxis 22894 } 22895 }, 22896 vertexShader: _getCommonVertexShader(), 22897 fragmentShader: /* glsl */ ` 22898 22899 precision mediump float; 22900 precision mediump int; 22901 22902 varying vec3 vOutputDirection; 22903 22904 uniform sampler2D envMap; 22905 uniform int samples; 22906 uniform float weights[ n ]; 22907 uniform bool latitudinal; 22908 uniform float dTheta; 22909 uniform float mipInt; 22910 uniform vec3 poleAxis; 22911 22912 #define ENVMAP_TYPE_CUBE_UV 22913 #include <cube_uv_reflection_fragment> 22914 22915 vec3 getSample( float theta, vec3 axis ) { 22916 22917 float cosTheta = cos( theta ); 22918 // Rodrigues' axis-angle rotation 22919 vec3 sampleDirection = vOutputDirection * cosTheta 22920 + cross( axis, vOutputDirection ) * sin( theta ) 22921 + axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta ); 22922 22923 return bilinearCubeUV( envMap, sampleDirection, mipInt ); 22924 22925 } 22926 22927 void main() { 22928 22929 vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection ); 22930 22931 if ( all( equal( axis, vec3( 0.0 ) ) ) ) { 22932 22933 axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x ); 22934 22935 } 22936 22937 axis = normalize( axis ); 22938 22939 gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 ); 22940 gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis ); 22941 22942 for ( int i = 1; i < n; i++ ) { 22943 22944 if ( i >= samples ) { 22945 22946 break; 22947 22948 } 22949 22950 float theta = dTheta * float( i ); 22951 gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis ); 22952 gl_FragColor.rgb += weights[ i ] * getSample( theta, axis ); 22953 22954 } 22955 22956 } 22957 `, 22958 blending: NoBlending, 22959 depthTest: false, 22960 depthWrite: false 22961 }); 22962 return shaderMaterial; 22963 } 22964 function _getEquirectMaterial() { 22965 return new ShaderMaterial({ 22966 name: 'EquirectangularToCubeUV', 22967 uniforms: { 22968 'envMap': { 22969 value: null 22970 } 22971 }, 22972 vertexShader: _getCommonVertexShader(), 22973 fragmentShader: /* glsl */ ` 22974 22975 precision mediump float; 22976 precision mediump int; 22977 22978 varying vec3 vOutputDirection; 22979 22980 uniform sampler2D envMap; 22981 22982 #include <common> 22983 22984 void main() { 22985 22986 vec3 outputDirection = normalize( vOutputDirection ); 22987 vec2 uv = equirectUv( outputDirection ); 22988 22989 gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 ); 22990 22991 } 22992 `, 22993 blending: NoBlending, 22994 depthTest: false, 22995 depthWrite: false 22996 }); 22997 } 22998 function _getCubemapMaterial() { 22999 return new ShaderMaterial({ 23000 name: 'CubemapToCubeUV', 23001 uniforms: { 23002 'envMap': { 23003 value: null 23004 }, 23005 'flipEnvMap': { 23006 value: -1 23007 } 23008 }, 23009 vertexShader: _getCommonVertexShader(), 23010 fragmentShader: /* glsl */ ` 23011 23012 precision mediump float; 23013 precision mediump int; 23014 23015 uniform float flipEnvMap; 23016 23017 varying vec3 vOutputDirection; 23018 23019 uniform samplerCube envMap; 23020 23021 void main() { 23022 23023 gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) ); 23024 23025 } 23026 `, 23027 blending: NoBlending, 23028 depthTest: false, 23029 depthWrite: false 23030 }); 23031 } 23032 function _getCommonVertexShader() { 23033 return /* glsl */ ` 23034 23035 precision mediump float; 23036 precision mediump int; 23037 23038 attribute float faceIndex; 23039 23040 varying vec3 vOutputDirection; 23041 23042 // RH coordinate system; PMREM face-indexing convention 23043 vec3 getDirection( vec2 uv, float face ) { 23044 23045 uv = 2.0 * uv - 1.0; 23046 23047 vec3 direction = vec3( uv, 1.0 ); 23048 23049 if ( face == 0.0 ) { 23050 23051 direction = direction.zyx; // ( 1, v, u ) pos x 23052 23053 } else if ( face == 1.0 ) { 23054 23055 direction = direction.xzy; 23056 direction.xz *= -1.0; // ( -u, 1, -v ) pos y 23057 23058 } else if ( face == 2.0 ) { 23059 23060 direction.x *= -1.0; // ( -u, v, 1 ) pos z 23061 23062 } else if ( face == 3.0 ) { 23063 23064 direction = direction.zyx; 23065 direction.xz *= -1.0; // ( -1, v, -u ) neg x 23066 23067 } else if ( face == 4.0 ) { 23068 23069 direction = direction.xzy; 23070 direction.xy *= -1.0; // ( -u, -1, v ) neg y 23071 23072 } else if ( face == 5.0 ) { 23073 23074 direction.z *= -1.0; // ( u, v, -1 ) neg z 23075 23076 } 23077 23078 return direction; 23079 23080 } 23081 23082 void main() { 23083 23084 vOutputDirection = getDirection( uv, faceIndex ); 23085 gl_Position = vec4( position, 1.0 ); 23086 23087 } 23088 `; 23089 } 23090 function WebGLCubeUVMaps(renderer) { 23091 let cubeUVmaps = new WeakMap(); 23092 let pmremGenerator = null; 23093 function get(texture) { 23094 if (texture && texture.isTexture) { 23095 const mapping = texture.mapping; 23096 const isEquirectMap = mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping; 23097 const isCubeMap = mapping === CubeReflectionMapping || mapping === CubeRefractionMapping; 23098 // equirect/cube map to cubeUV conversion 23099 if (isEquirectMap || isCubeMap) { 23100 let renderTarget = cubeUVmaps.get(texture); 23101 const currentPMREMVersion = renderTarget !== undefined ? renderTarget.texture.pmremVersion : 0; 23102 if (texture.isRenderTargetTexture && texture.pmremVersion !== currentPMREMVersion) { 23103 if (pmremGenerator === null) pmremGenerator = new PMREMGenerator(renderer); 23104 renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular(texture, renderTarget) : pmremGenerator.fromCubemap(texture, renderTarget); 23105 renderTarget.texture.pmremVersion = texture.pmremVersion; 23106 cubeUVmaps.set(texture, renderTarget); 23107 return renderTarget.texture; 23108 } else { 23109 if (renderTarget !== undefined) { 23110 return renderTarget.texture; 23111 } else { 23112 const image = texture.image; 23113 if (isEquirectMap && image && image.height > 0 || isCubeMap && image && isCubeTextureComplete(image)) { 23114 if (pmremGenerator === null) pmremGenerator = new PMREMGenerator(renderer); 23115 renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular(texture) : pmremGenerator.fromCubemap(texture); 23116 renderTarget.texture.pmremVersion = texture.pmremVersion; 23117 cubeUVmaps.set(texture, renderTarget); 23118 texture.addEventListener('dispose', onTextureDispose); 23119 return renderTarget.texture; 23120 } else { 23121 // image not yet ready. try the conversion next frame 23122 return null; 23123 } 23124 } 23125 } 23126 } 23127 } 23128 return texture; 23129 } 23130 function isCubeTextureComplete(image) { 23131 let count = 0; 23132 const length = 6; 23133 for(let i = 0; i < length; i++){ 23134 if (image[i] !== undefined) count++; 23135 } 23136 return count === length; 23137 } 23138 function onTextureDispose(event) { 23139 const texture = event.target; 23140 texture.removeEventListener('dispose', onTextureDispose); 23141 const cubemapUV = cubeUVmaps.get(texture); 23142 if (cubemapUV !== undefined) { 23143 cubeUVmaps.delete(texture); 23144 cubemapUV.dispose(); 23145 } 23146 } 23147 function dispose() { 23148 cubeUVmaps = new WeakMap(); 23149 if (pmremGenerator !== null) { 23150 pmremGenerator.dispose(); 23151 pmremGenerator = null; 23152 } 23153 } 23154 return { 23155 get: get, 23156 dispose: dispose 23157 }; 23158 } 23159 function WebGLExtensions(gl) { 23160 const extensions = {}; 23161 function getExtension(name) { 23162 if (extensions[name] !== undefined) { 23163 return extensions[name]; 23164 } 23165 let extension; 23166 switch(name){ 23167 case 'WEBGL_depth_texture': 23168 extension = gl.getExtension('WEBGL_depth_texture') || gl.getExtension('MOZ_WEBGL_depth_texture') || gl.getExtension('WEBKIT_WEBGL_depth_texture'); 23169 break; 23170 case 'EXT_texture_filter_anisotropic': 23171 extension = gl.getExtension('EXT_texture_filter_anisotropic') || gl.getExtension('MOZ_EXT_texture_filter_anisotropic') || gl.getExtension('WEBKIT_EXT_texture_filter_anisotropic'); 23172 break; 23173 case 'WEBGL_compressed_texture_s3tc': 23174 extension = gl.getExtension('WEBGL_compressed_texture_s3tc') || gl.getExtension('MOZ_WEBGL_compressed_texture_s3tc') || gl.getExtension('WEBKIT_WEBGL_compressed_texture_s3tc'); 23175 break; 23176 case 'WEBGL_compressed_texture_pvrtc': 23177 extension = gl.getExtension('WEBGL_compressed_texture_pvrtc') || gl.getExtension('WEBKIT_WEBGL_compressed_texture_pvrtc'); 23178 break; 23179 default: 23180 extension = gl.getExtension(name); 23181 } 23182 extensions[name] = extension; 23183 return extension; 23184 } 23185 return { 23186 has: function(name) { 23187 return getExtension(name) !== null; 23188 }, 23189 init: function() { 23190 getExtension('EXT_color_buffer_float'); 23191 getExtension('WEBGL_clip_cull_distance'); 23192 getExtension('OES_texture_float_linear'); 23193 getExtension('EXT_color_buffer_half_float'); 23194 getExtension('WEBGL_multisampled_render_to_texture'); 23195 getExtension('WEBGL_render_shared_exponent'); 23196 }, 23197 get: function(name) { 23198 const extension = getExtension(name); 23199 if (extension === null) { 23200 warnOnce('THREE.WebGLRenderer: ' + name + ' extension not supported.'); 23201 } 23202 return extension; 23203 } 23204 }; 23205 } 23206 function WebGLGeometries(gl, attributes, info, bindingStates) { 23207 const geometries = {}; 23208 const wireframeAttributes = new WeakMap(); 23209 function onGeometryDispose(event) { 23210 const geometry = event.target; 23211 if (geometry.index !== null) { 23212 attributes.remove(geometry.index); 23213 } 23214 for(const name in geometry.attributes){ 23215 attributes.remove(geometry.attributes[name]); 23216 } 23217 geometry.removeEventListener('dispose', onGeometryDispose); 23218 delete geometries[geometry.id]; 23219 const attribute = wireframeAttributes.get(geometry); 23220 if (attribute) { 23221 attributes.remove(attribute); 23222 wireframeAttributes.delete(geometry); 23223 } 23224 bindingStates.releaseStatesOfGeometry(geometry); 23225 if (geometry.isInstancedBufferGeometry === true) { 23226 delete geometry._maxInstanceCount; 23227 } 23228 // 23229 info.memory.geometries--; 23230 } 23231 function get(object, geometry) { 23232 if (geometries[geometry.id] === true) return geometry; 23233 geometry.addEventListener('dispose', onGeometryDispose); 23234 geometries[geometry.id] = true; 23235 info.memory.geometries++; 23236 return geometry; 23237 } 23238 function update(geometry) { 23239 const geometryAttributes = geometry.attributes; 23240 // Updating index buffer in VAO now. See WebGLBindingStates. 23241 for(const name in geometryAttributes){ 23242 attributes.update(geometryAttributes[name], gl.ARRAY_BUFFER); 23243 } 23244 } 23245 function updateWireframeAttribute(geometry) { 23246 const indices = []; 23247 const geometryIndex = geometry.index; 23248 const geometryPosition = geometry.attributes.position; 23249 let version = 0; 23250 if (geometryIndex !== null) { 23251 const array = geometryIndex.array; 23252 version = geometryIndex.version; 23253 for(let i = 0, l = array.length; i < l; i += 3){ 23254 const a = array[i + 0]; 23255 const b = array[i + 1]; 23256 const c = array[i + 2]; 23257 indices.push(a, b, b, c, c, a); 23258 } 23259 } else if (geometryPosition !== undefined) { 23260 const array = geometryPosition.array; 23261 version = geometryPosition.version; 23262 for(let i = 0, l = array.length / 3 - 1; i < l; i += 3){ 23263 const a = i + 0; 23264 const b = i + 1; 23265 const c = i + 2; 23266 indices.push(a, b, b, c, c, a); 23267 } 23268 } else { 23269 return; 23270 } 23271 const attribute = new (arrayNeedsUint32(indices) ? Uint32BufferAttribute : Uint16BufferAttribute)(indices, 1); 23272 attribute.version = version; 23273 // Updating index buffer in VAO now. See WebGLBindingStates 23274 // 23275 const previousAttribute = wireframeAttributes.get(geometry); 23276 if (previousAttribute) attributes.remove(previousAttribute); 23277 // 23278 wireframeAttributes.set(geometry, attribute); 23279 } 23280 function getWireframeAttribute(geometry) { 23281 const currentAttribute = wireframeAttributes.get(geometry); 23282 if (currentAttribute) { 23283 const geometryIndex = geometry.index; 23284 if (geometryIndex !== null) { 23285 // if the attribute is obsolete, create a new one 23286 if (currentAttribute.version < geometryIndex.version) { 23287 updateWireframeAttribute(geometry); 23288 } 23289 } 23290 } else { 23291 updateWireframeAttribute(geometry); 23292 } 23293 return wireframeAttributes.get(geometry); 23294 } 23295 return { 23296 get: get, 23297 update: update, 23298 getWireframeAttribute: getWireframeAttribute 23299 }; 23300 } 23301 function WebGLIndexedBufferRenderer(gl, extensions, info) { 23302 let mode; 23303 function setMode(value) { 23304 mode = value; 23305 } 23306 let type, bytesPerElement; 23307 function setIndex(value) { 23308 type = value.type; 23309 bytesPerElement = value.bytesPerElement; 23310 } 23311 function render(start, count) { 23312 gl.drawElements(mode, count, type, start * bytesPerElement); 23313 info.update(count, mode, 1); 23314 } 23315 function renderInstances(start, count, primcount) { 23316 if (primcount === 0) return; 23317 gl.drawElementsInstanced(mode, count, type, start * bytesPerElement, primcount); 23318 info.update(count, mode, primcount); 23319 } 23320 function renderMultiDraw(starts, counts, drawCount) { 23321 if (drawCount === 0) return; 23322 const extension = extensions.get('WEBGL_multi_draw'); 23323 extension.multiDrawElementsWEBGL(mode, counts, 0, type, starts, 0, drawCount); 23324 let elementCount = 0; 23325 for(let i = 0; i < drawCount; i++){ 23326 elementCount += counts[i]; 23327 } 23328 info.update(elementCount, mode, 1); 23329 } 23330 function renderMultiDrawInstances(starts, counts, drawCount, primcount) { 23331 if (drawCount === 0) return; 23332 const extension = extensions.get('WEBGL_multi_draw'); 23333 if (extension === null) { 23334 for(let i = 0; i < starts.length; i++){ 23335 renderInstances(starts[i] / bytesPerElement, counts[i], primcount[i]); 23336 } 23337 } else { 23338 extension.multiDrawElementsInstancedWEBGL(mode, counts, 0, type, starts, 0, primcount, 0, drawCount); 23339 let elementCount = 0; 23340 for(let i = 0; i < drawCount; i++){ 23341 elementCount += counts[i] * primcount[i]; 23342 } 23343 info.update(elementCount, mode, 1); 23344 } 23345 } 23346 // 23347 this.setMode = setMode; 23348 this.setIndex = setIndex; 23349 this.render = render; 23350 this.renderInstances = renderInstances; 23351 this.renderMultiDraw = renderMultiDraw; 23352 this.renderMultiDrawInstances = renderMultiDrawInstances; 23353 } 23354 function WebGLInfo(gl) { 23355 const memory = { 23356 geometries: 0, 23357 textures: 0 23358 }; 23359 const render = { 23360 frame: 0, 23361 calls: 0, 23362 triangles: 0, 23363 points: 0, 23364 lines: 0 23365 }; 23366 function update(count, mode, instanceCount) { 23367 render.calls++; 23368 switch(mode){ 23369 case gl.TRIANGLES: 23370 render.triangles += instanceCount * (count / 3); 23371 break; 23372 case gl.LINES: 23373 render.lines += instanceCount * (count / 2); 23374 break; 23375 case gl.LINE_STRIP: 23376 render.lines += instanceCount * (count - 1); 23377 break; 23378 case gl.LINE_LOOP: 23379 render.lines += instanceCount * count; 23380 break; 23381 case gl.POINTS: 23382 render.points += instanceCount * count; 23383 break; 23384 default: 23385 console.error('THREE.WebGLInfo: Unknown draw mode:', mode); 23386 break; 23387 } 23388 } 23389 function reset() { 23390 render.calls = 0; 23391 render.triangles = 0; 23392 render.points = 0; 23393 render.lines = 0; 23394 } 23395 return { 23396 memory: memory, 23397 render: render, 23398 programs: null, 23399 autoReset: true, 23400 reset: reset, 23401 update: update 23402 }; 23403 } 23404 function WebGLMorphtargets(gl, capabilities, textures) { 23405 const morphTextures = new WeakMap(); 23406 const morph = new Vector4(); 23407 function update(object, geometry, program) { 23408 const objectInfluences = object.morphTargetInfluences; 23409 // the following encodes morph targets into an array of data textures. Each layer represents a single morph target. 23410 const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; 23411 const morphTargetsCount = morphAttribute !== undefined ? morphAttribute.length : 0; 23412 let entry = morphTextures.get(geometry); 23413 if (entry === undefined || entry.count !== morphTargetsCount) { 23414 if (entry !== undefined) entry.texture.dispose(); 23415 const hasMorphPosition = geometry.morphAttributes.position !== undefined; 23416 const hasMorphNormals = geometry.morphAttributes.normal !== undefined; 23417 const hasMorphColors = geometry.morphAttributes.color !== undefined; 23418 const morphTargets = geometry.morphAttributes.position || []; 23419 const morphNormals = geometry.morphAttributes.normal || []; 23420 const morphColors = geometry.morphAttributes.color || []; 23421 let vertexDataCount = 0; 23422 if (hasMorphPosition === true) vertexDataCount = 1; 23423 if (hasMorphNormals === true) vertexDataCount = 2; 23424 if (hasMorphColors === true) vertexDataCount = 3; 23425 let width = geometry.attributes.position.count * vertexDataCount; 23426 let height = 1; 23427 if (width > capabilities.maxTextureSize) { 23428 height = Math.ceil(width / capabilities.maxTextureSize); 23429 width = capabilities.maxTextureSize; 23430 } 23431 const buffer = new Float32Array(width * height * 4 * morphTargetsCount); 23432 const texture = new DataArrayTexture(buffer, width, height, morphTargetsCount); 23433 texture.type = FloatType; 23434 texture.needsUpdate = true; 23435 // fill buffer 23436 const vertexDataStride = vertexDataCount * 4; 23437 for(let i = 0; i < morphTargetsCount; i++){ 23438 const morphTarget = morphTargets[i]; 23439 const morphNormal = morphNormals[i]; 23440 const morphColor = morphColors[i]; 23441 const offset = width * height * 4 * i; 23442 for(let j = 0; j < morphTarget.count; j++){ 23443 const stride = j * vertexDataStride; 23444 if (hasMorphPosition === true) { 23445 morph.fromBufferAttribute(morphTarget, j); 23446 buffer[offset + stride + 0] = morph.x; 23447 buffer[offset + stride + 1] = morph.y; 23448 buffer[offset + stride + 2] = morph.z; 23449 buffer[offset + stride + 3] = 0; 23450 } 23451 if (hasMorphNormals === true) { 23452 morph.fromBufferAttribute(morphNormal, j); 23453 buffer[offset + stride + 4] = morph.x; 23454 buffer[offset + stride + 5] = morph.y; 23455 buffer[offset + stride + 6] = morph.z; 23456 buffer[offset + stride + 7] = 0; 23457 } 23458 if (hasMorphColors === true) { 23459 morph.fromBufferAttribute(morphColor, j); 23460 buffer[offset + stride + 8] = morph.x; 23461 buffer[offset + stride + 9] = morph.y; 23462 buffer[offset + stride + 10] = morph.z; 23463 buffer[offset + stride + 11] = morphColor.itemSize === 4 ? morph.w : 1; 23464 } 23465 } 23466 } 23467 entry = { 23468 count: morphTargetsCount, 23469 texture: texture, 23470 size: new Vector2(width, height) 23471 }; 23472 morphTextures.set(geometry, entry); 23473 function disposeTexture() { 23474 texture.dispose(); 23475 morphTextures.delete(geometry); 23476 geometry.removeEventListener('dispose', disposeTexture); 23477 } 23478 geometry.addEventListener('dispose', disposeTexture); 23479 } 23480 // 23481 if (object.isInstancedMesh === true && object.morphTexture !== null) { 23482 program.getUniforms().setValue(gl, 'morphTexture', object.morphTexture, textures); 23483 } else { 23484 let morphInfluencesSum = 0; 23485 for(let i = 0; i < objectInfluences.length; i++){ 23486 morphInfluencesSum += objectInfluences[i]; 23487 } 23488 const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum; 23489 program.getUniforms().setValue(gl, 'morphTargetBaseInfluence', morphBaseInfluence); 23490 program.getUniforms().setValue(gl, 'morphTargetInfluences', objectInfluences); 23491 } 23492 program.getUniforms().setValue(gl, 'morphTargetsTexture', entry.texture, textures); 23493 program.getUniforms().setValue(gl, 'morphTargetsTextureSize', entry.size); 23494 } 23495 return { 23496 update: update 23497 }; 23498 } 23499 function WebGLObjects(gl, geometries, attributes, info) { 23500 let updateMap = new WeakMap(); 23501 function update(object) { 23502 const frame = info.render.frame; 23503 const geometry = object.geometry; 23504 const buffergeometry = geometries.get(object, geometry); 23505 // Update once per frame 23506 if (updateMap.get(buffergeometry) !== frame) { 23507 geometries.update(buffergeometry); 23508 updateMap.set(buffergeometry, frame); 23509 } 23510 if (object.isInstancedMesh) { 23511 if (object.hasEventListener('dispose', onInstancedMeshDispose) === false) { 23512 object.addEventListener('dispose', onInstancedMeshDispose); 23513 } 23514 if (updateMap.get(object) !== frame) { 23515 attributes.update(object.instanceMatrix, gl.ARRAY_BUFFER); 23516 if (object.instanceColor !== null) { 23517 attributes.update(object.instanceColor, gl.ARRAY_BUFFER); 23518 } 23519 updateMap.set(object, frame); 23520 } 23521 } 23522 if (object.isSkinnedMesh) { 23523 const skeleton = object.skeleton; 23524 if (updateMap.get(skeleton) !== frame) { 23525 skeleton.update(); 23526 updateMap.set(skeleton, frame); 23527 } 23528 } 23529 return buffergeometry; 23530 } 23531 function dispose() { 23532 updateMap = new WeakMap(); 23533 } 23534 function onInstancedMeshDispose(event) { 23535 const instancedMesh = event.target; 23536 instancedMesh.removeEventListener('dispose', onInstancedMeshDispose); 23537 attributes.remove(instancedMesh.instanceMatrix); 23538 if (instancedMesh.instanceColor !== null) attributes.remove(instancedMesh.instanceColor); 23539 } 23540 return { 23541 update: update, 23542 dispose: dispose 23543 }; 23544 } 23545 /** 23546 * Uniforms of a program. 23547 * Those form a tree structure with a special top-level container for the root, 23548 * which you get by calling 'new WebGLUniforms( gl, program )'. 23549 * 23550 * 23551 * Properties of inner nodes including the top-level container: 23552 * 23553 * .seq - array of nested uniforms 23554 * .map - nested uniforms by name 23555 * 23556 * 23557 * Methods of all nodes except the top-level container: 23558 * 23559 * .setValue( gl, value, [textures] ) 23560 * 23561 * uploads a uniform value(s) 23562 * the 'textures' parameter is needed for sampler uniforms 23563 * 23564 * 23565 * Static methods of the top-level container (textures factorizations): 23566 * 23567 * .upload( gl, seq, values, textures ) 23568 * 23569 * sets uniforms in 'seq' to 'values[id].value' 23570 * 23571 * .seqWithValue( seq, values ) : filteredSeq 23572 * 23573 * filters 'seq' entries with corresponding entry in values 23574 * 23575 * 23576 * Methods of the top-level container (textures factorizations): 23577 * 23578 * .setValue( gl, name, value, textures ) 23579 * 23580 * sets uniform with name 'name' to 'value' 23581 * 23582 * .setOptional( gl, obj, prop ) 23583 * 23584 * like .set for an optional property of the object 23585 * 23586 */ const emptyTexture = /*@__PURE__*/ new Texture$1(); 23587 const emptyShadowTexture = /*@__PURE__*/ new DepthTexture(1, 1); 23588 const emptyArrayTexture = /*@__PURE__*/ new DataArrayTexture(); 23589 const empty3dTexture = /*@__PURE__*/ new Data3DTexture(); 23590 const emptyCubeTexture = /*@__PURE__*/ new CubeTexture(); 23591 // --- Utilities --- 23592 // Array Caches (provide typed arrays for temporary by size) 23593 const arrayCacheF32 = []; 23594 const arrayCacheI32 = []; 23595 // Float32Array caches used for uploading Matrix uniforms 23596 const mat4array = new Float32Array(16); 23597 const mat3array = new Float32Array(9); 23598 const mat2array = new Float32Array(4); 23599 // Flattening for arrays of vectors and matrices 23600 function flatten(array, nBlocks, blockSize) { 23601 const firstElem = array[0]; 23602 if (firstElem <= 0 || firstElem > 0) return array; 23603 // unoptimized: ! isNaN( firstElem ) 23604 // see http://jacksondunstan.com/articles/983 23605 const n = nBlocks * blockSize; 23606 let r = arrayCacheF32[n]; 23607 if (r === undefined) { 23608 r = new Float32Array(n); 23609 arrayCacheF32[n] = r; 23610 } 23611 if (nBlocks !== 0) { 23612 firstElem.toArray(r, 0); 23613 for(let i = 1, offset = 0; i !== nBlocks; ++i){ 23614 offset += blockSize; 23615 array[i].toArray(r, offset); 23616 } 23617 } 23618 return r; 23619 } 23620 function arraysEqual(a, b) { 23621 if (a.length !== b.length) return false; 23622 for(let i = 0, l = a.length; i < l; i++){ 23623 if (a[i] !== b[i]) return false; 23624 } 23625 return true; 23626 } 23627 function copyArray(a, b) { 23628 for(let i = 0, l = b.length; i < l; i++){ 23629 a[i] = b[i]; 23630 } 23631 } 23632 // Texture unit allocation 23633 function allocTexUnits(textures, n) { 23634 let r = arrayCacheI32[n]; 23635 if (r === undefined) { 23636 r = new Int32Array(n); 23637 arrayCacheI32[n] = r; 23638 } 23639 for(let i = 0; i !== n; ++i){ 23640 r[i] = textures.allocateTextureUnit(); 23641 } 23642 return r; 23643 } 23644 // --- Setters --- 23645 // Note: Defining these methods externally, because they come in a bunch 23646 // and this way their names minify. 23647 // Single scalar 23648 function setValueV1f(gl, v) { 23649 const cache = this.cache; 23650 if (cache[0] === v) return; 23651 gl.uniform1f(this.addr, v); 23652 cache[0] = v; 23653 } 23654 // Single float vector (from flat array or THREE.VectorN) 23655 function setValueV2f(gl, v) { 23656 const cache = this.cache; 23657 if (v.x !== undefined) { 23658 if (cache[0] !== v.x || cache[1] !== v.y) { 23659 gl.uniform2f(this.addr, v.x, v.y); 23660 cache[0] = v.x; 23661 cache[1] = v.y; 23662 } 23663 } else { 23664 if (arraysEqual(cache, v)) return; 23665 gl.uniform2fv(this.addr, v); 23666 copyArray(cache, v); 23667 } 23668 } 23669 function setValueV3f(gl, v) { 23670 const cache = this.cache; 23671 if (v.x !== undefined) { 23672 if (cache[0] !== v.x || cache[1] !== v.y || cache[2] !== v.z) { 23673 gl.uniform3f(this.addr, v.x, v.y, v.z); 23674 cache[0] = v.x; 23675 cache[1] = v.y; 23676 cache[2] = v.z; 23677 } 23678 } else if (v.r !== undefined) { 23679 if (cache[0] !== v.r || cache[1] !== v.g || cache[2] !== v.b) { 23680 gl.uniform3f(this.addr, v.r, v.g, v.b); 23681 cache[0] = v.r; 23682 cache[1] = v.g; 23683 cache[2] = v.b; 23684 } 23685 } else { 23686 if (arraysEqual(cache, v)) return; 23687 gl.uniform3fv(this.addr, v); 23688 copyArray(cache, v); 23689 } 23690 } 23691 function setValueV4f(gl, v) { 23692 const cache = this.cache; 23693 if (v.x !== undefined) { 23694 if (cache[0] !== v.x || cache[1] !== v.y || cache[2] !== v.z || cache[3] !== v.w) { 23695 gl.uniform4f(this.addr, v.x, v.y, v.z, v.w); 23696 cache[0] = v.x; 23697 cache[1] = v.y; 23698 cache[2] = v.z; 23699 cache[3] = v.w; 23700 } 23701 } else { 23702 if (arraysEqual(cache, v)) return; 23703 gl.uniform4fv(this.addr, v); 23704 copyArray(cache, v); 23705 } 23706 } 23707 // Single matrix (from flat array or THREE.MatrixN) 23708 function setValueM2(gl, v) { 23709 const cache = this.cache; 23710 const elements = v.elements; 23711 if (elements === undefined) { 23712 if (arraysEqual(cache, v)) return; 23713 gl.uniformMatrix2fv(this.addr, false, v); 23714 copyArray(cache, v); 23715 } else { 23716 if (arraysEqual(cache, elements)) return; 23717 mat2array.set(elements); 23718 gl.uniformMatrix2fv(this.addr, false, mat2array); 23719 copyArray(cache, elements); 23720 } 23721 } 23722 function setValueM3(gl, v) { 23723 const cache = this.cache; 23724 const elements = v.elements; 23725 if (elements === undefined) { 23726 if (arraysEqual(cache, v)) return; 23727 gl.uniformMatrix3fv(this.addr, false, v); 23728 copyArray(cache, v); 23729 } else { 23730 if (arraysEqual(cache, elements)) return; 23731 mat3array.set(elements); 23732 gl.uniformMatrix3fv(this.addr, false, mat3array); 23733 copyArray(cache, elements); 23734 } 23735 } 23736 function setValueM4(gl, v) { 23737 const cache = this.cache; 23738 const elements = v.elements; 23739 if (elements === undefined) { 23740 if (arraysEqual(cache, v)) return; 23741 gl.uniformMatrix4fv(this.addr, false, v); 23742 copyArray(cache, v); 23743 } else { 23744 if (arraysEqual(cache, elements)) return; 23745 mat4array.set(elements); 23746 gl.uniformMatrix4fv(this.addr, false, mat4array); 23747 copyArray(cache, elements); 23748 } 23749 } 23750 // Single integer / boolean 23751 function setValueV1i(gl, v) { 23752 const cache = this.cache; 23753 if (cache[0] === v) return; 23754 gl.uniform1i(this.addr, v); 23755 cache[0] = v; 23756 } 23757 // Single integer / boolean vector (from flat array or THREE.VectorN) 23758 function setValueV2i(gl, v) { 23759 const cache = this.cache; 23760 if (v.x !== undefined) { 23761 if (cache[0] !== v.x || cache[1] !== v.y) { 23762 gl.uniform2i(this.addr, v.x, v.y); 23763 cache[0] = v.x; 23764 cache[1] = v.y; 23765 } 23766 } else { 23767 if (arraysEqual(cache, v)) return; 23768 gl.uniform2iv(this.addr, v); 23769 copyArray(cache, v); 23770 } 23771 } 23772 function setValueV3i(gl, v) { 23773 const cache = this.cache; 23774 if (v.x !== undefined) { 23775 if (cache[0] !== v.x || cache[1] !== v.y || cache[2] !== v.z) { 23776 gl.uniform3i(this.addr, v.x, v.y, v.z); 23777 cache[0] = v.x; 23778 cache[1] = v.y; 23779 cache[2] = v.z; 23780 } 23781 } else { 23782 if (arraysEqual(cache, v)) return; 23783 gl.uniform3iv(this.addr, v); 23784 copyArray(cache, v); 23785 } 23786 } 23787 function setValueV4i(gl, v) { 23788 const cache = this.cache; 23789 if (v.x !== undefined) { 23790 if (cache[0] !== v.x || cache[1] !== v.y || cache[2] !== v.z || cache[3] !== v.w) { 23791 gl.uniform4i(this.addr, v.x, v.y, v.z, v.w); 23792 cache[0] = v.x; 23793 cache[1] = v.y; 23794 cache[2] = v.z; 23795 cache[3] = v.w; 23796 } 23797 } else { 23798 if (arraysEqual(cache, v)) return; 23799 gl.uniform4iv(this.addr, v); 23800 copyArray(cache, v); 23801 } 23802 } 23803 // Single unsigned integer 23804 function setValueV1ui(gl, v) { 23805 const cache = this.cache; 23806 if (cache[0] === v) return; 23807 gl.uniform1ui(this.addr, v); 23808 cache[0] = v; 23809 } 23810 // Single unsigned integer vector (from flat array or THREE.VectorN) 23811 function setValueV2ui(gl, v) { 23812 const cache = this.cache; 23813 if (v.x !== undefined) { 23814 if (cache[0] !== v.x || cache[1] !== v.y) { 23815 gl.uniform2ui(this.addr, v.x, v.y); 23816 cache[0] = v.x; 23817 cache[1] = v.y; 23818 } 23819 } else { 23820 if (arraysEqual(cache, v)) return; 23821 gl.uniform2uiv(this.addr, v); 23822 copyArray(cache, v); 23823 } 23824 } 23825 function setValueV3ui(gl, v) { 23826 const cache = this.cache; 23827 if (v.x !== undefined) { 23828 if (cache[0] !== v.x || cache[1] !== v.y || cache[2] !== v.z) { 23829 gl.uniform3ui(this.addr, v.x, v.y, v.z); 23830 cache[0] = v.x; 23831 cache[1] = v.y; 23832 cache[2] = v.z; 23833 } 23834 } else { 23835 if (arraysEqual(cache, v)) return; 23836 gl.uniform3uiv(this.addr, v); 23837 copyArray(cache, v); 23838 } 23839 } 23840 function setValueV4ui(gl, v) { 23841 const cache = this.cache; 23842 if (v.x !== undefined) { 23843 if (cache[0] !== v.x || cache[1] !== v.y || cache[2] !== v.z || cache[3] !== v.w) { 23844 gl.uniform4ui(this.addr, v.x, v.y, v.z, v.w); 23845 cache[0] = v.x; 23846 cache[1] = v.y; 23847 cache[2] = v.z; 23848 cache[3] = v.w; 23849 } 23850 } else { 23851 if (arraysEqual(cache, v)) return; 23852 gl.uniform4uiv(this.addr, v); 23853 copyArray(cache, v); 23854 } 23855 } 23856 // Single texture (2D / Cube) 23857 function setValueT1(gl, v, textures) { 23858 const cache = this.cache; 23859 const unit = textures.allocateTextureUnit(); 23860 if (cache[0] !== unit) { 23861 gl.uniform1i(this.addr, unit); 23862 cache[0] = unit; 23863 } 23864 let emptyTexture2D; 23865 if (this.type === gl.SAMPLER_2D_SHADOW) { 23866 emptyShadowTexture.compareFunction = LessEqualCompare; // #28670 23867 emptyTexture2D = emptyShadowTexture; 23868 } else { 23869 emptyTexture2D = emptyTexture; 23870 } 23871 textures.setTexture2D(v || emptyTexture2D, unit); 23872 } 23873 function setValueT3D1(gl, v, textures) { 23874 const cache = this.cache; 23875 const unit = textures.allocateTextureUnit(); 23876 if (cache[0] !== unit) { 23877 gl.uniform1i(this.addr, unit); 23878 cache[0] = unit; 23879 } 23880 textures.setTexture3D(v || empty3dTexture, unit); 23881 } 23882 function setValueT6(gl, v, textures) { 23883 const cache = this.cache; 23884 const unit = textures.allocateTextureUnit(); 23885 if (cache[0] !== unit) { 23886 gl.uniform1i(this.addr, unit); 23887 cache[0] = unit; 23888 } 23889 textures.setTextureCube(v || emptyCubeTexture, unit); 23890 } 23891 function setValueT2DArray1(gl, v, textures) { 23892 const cache = this.cache; 23893 const unit = textures.allocateTextureUnit(); 23894 if (cache[0] !== unit) { 23895 gl.uniform1i(this.addr, unit); 23896 cache[0] = unit; 23897 } 23898 textures.setTexture2DArray(v || emptyArrayTexture, unit); 23899 } 23900 // Helper to pick the right setter for the singular case 23901 function getSingularSetter(type) { 23902 switch(type){ 23903 case 0x1406: 23904 return setValueV1f; // FLOAT 23905 case 0x8b50: 23906 return setValueV2f; // _VEC2 23907 case 0x8b51: 23908 return setValueV3f; // _VEC3 23909 case 0x8b52: 23910 return setValueV4f; // _VEC4 23911 case 0x8b5a: 23912 return setValueM2; // _MAT2 23913 case 0x8b5b: 23914 return setValueM3; // _MAT3 23915 case 0x8b5c: 23916 return setValueM4; // _MAT4 23917 case 0x1404: 23918 case 0x8b56: 23919 return setValueV1i; // INT, BOOL 23920 case 0x8b53: 23921 case 0x8b57: 23922 return setValueV2i; // _VEC2 23923 case 0x8b54: 23924 case 0x8b58: 23925 return setValueV3i; // _VEC3 23926 case 0x8b55: 23927 case 0x8b59: 23928 return setValueV4i; // _VEC4 23929 case 0x1405: 23930 return setValueV1ui; // UINT 23931 case 0x8dc6: 23932 return setValueV2ui; // _VEC2 23933 case 0x8dc7: 23934 return setValueV3ui; // _VEC3 23935 case 0x8dc8: 23936 return setValueV4ui; // _VEC4 23937 case 0x8b5e: 23938 case 0x8d66: 23939 case 0x8dca: 23940 case 0x8dd2: 23941 case 0x8b62: 23942 return setValueT1; 23943 case 0x8b5f: 23944 case 0x8dcb: 23945 case 0x8dd3: 23946 return setValueT3D1; 23947 case 0x8b60: 23948 case 0x8dcc: 23949 case 0x8dd4: 23950 case 0x8dc5: 23951 return setValueT6; 23952 case 0x8dc1: 23953 case 0x8dcf: 23954 case 0x8dd7: 23955 case 0x8dc4: 23956 return setValueT2DArray1; 23957 } 23958 } 23959 // Array of scalars 23960 function setValueV1fArray(gl, v) { 23961 gl.uniform1fv(this.addr, v); 23962 } 23963 // Array of vectors (from flat array or array of THREE.VectorN) 23964 function setValueV2fArray(gl, v) { 23965 const data = flatten(v, this.size, 2); 23966 gl.uniform2fv(this.addr, data); 23967 } 23968 function setValueV3fArray(gl, v) { 23969 const data = flatten(v, this.size, 3); 23970 gl.uniform3fv(this.addr, data); 23971 } 23972 function setValueV4fArray(gl, v) { 23973 const data = flatten(v, this.size, 4); 23974 gl.uniform4fv(this.addr, data); 23975 } 23976 // Array of matrices (from flat array or array of THREE.MatrixN) 23977 function setValueM2Array(gl, v) { 23978 const data = flatten(v, this.size, 4); 23979 gl.uniformMatrix2fv(this.addr, false, data); 23980 } 23981 function setValueM3Array(gl, v) { 23982 const data = flatten(v, this.size, 9); 23983 gl.uniformMatrix3fv(this.addr, false, data); 23984 } 23985 function setValueM4Array(gl, v) { 23986 const data = flatten(v, this.size, 16); 23987 gl.uniformMatrix4fv(this.addr, false, data); 23988 } 23989 // Array of integer / boolean 23990 function setValueV1iArray(gl, v) { 23991 gl.uniform1iv(this.addr, v); 23992 } 23993 // Array of integer / boolean vectors (from flat array) 23994 function setValueV2iArray(gl, v) { 23995 gl.uniform2iv(this.addr, v); 23996 } 23997 function setValueV3iArray(gl, v) { 23998 gl.uniform3iv(this.addr, v); 23999 } 24000 function setValueV4iArray(gl, v) { 24001 gl.uniform4iv(this.addr, v); 24002 } 24003 // Array of unsigned integer 24004 function setValueV1uiArray(gl, v) { 24005 gl.uniform1uiv(this.addr, v); 24006 } 24007 // Array of unsigned integer vectors (from flat array) 24008 function setValueV2uiArray(gl, v) { 24009 gl.uniform2uiv(this.addr, v); 24010 } 24011 function setValueV3uiArray(gl, v) { 24012 gl.uniform3uiv(this.addr, v); 24013 } 24014 function setValueV4uiArray(gl, v) { 24015 gl.uniform4uiv(this.addr, v); 24016 } 24017 // Array of textures (2D / 3D / Cube / 2DArray) 24018 function setValueT1Array(gl, v, textures) { 24019 const cache = this.cache; 24020 const n = v.length; 24021 const units = allocTexUnits(textures, n); 24022 if (!arraysEqual(cache, units)) { 24023 gl.uniform1iv(this.addr, units); 24024 copyArray(cache, units); 24025 } 24026 for(let i = 0; i !== n; ++i){ 24027 textures.setTexture2D(v[i] || emptyTexture, units[i]); 24028 } 24029 } 24030 function setValueT3DArray(gl, v, textures) { 24031 const cache = this.cache; 24032 const n = v.length; 24033 const units = allocTexUnits(textures, n); 24034 if (!arraysEqual(cache, units)) { 24035 gl.uniform1iv(this.addr, units); 24036 copyArray(cache, units); 24037 } 24038 for(let i = 0; i !== n; ++i){ 24039 textures.setTexture3D(v[i] || empty3dTexture, units[i]); 24040 } 24041 } 24042 function setValueT6Array(gl, v, textures) { 24043 const cache = this.cache; 24044 const n = v.length; 24045 const units = allocTexUnits(textures, n); 24046 if (!arraysEqual(cache, units)) { 24047 gl.uniform1iv(this.addr, units); 24048 copyArray(cache, units); 24049 } 24050 for(let i = 0; i !== n; ++i){ 24051 textures.setTextureCube(v[i] || emptyCubeTexture, units[i]); 24052 } 24053 } 24054 function setValueT2DArrayArray(gl, v, textures) { 24055 const cache = this.cache; 24056 const n = v.length; 24057 const units = allocTexUnits(textures, n); 24058 if (!arraysEqual(cache, units)) { 24059 gl.uniform1iv(this.addr, units); 24060 copyArray(cache, units); 24061 } 24062 for(let i = 0; i !== n; ++i){ 24063 textures.setTexture2DArray(v[i] || emptyArrayTexture, units[i]); 24064 } 24065 } 24066 // Helper to pick the right setter for a pure (bottom-level) array 24067 function getPureArraySetter(type) { 24068 switch(type){ 24069 case 0x1406: 24070 return setValueV1fArray; // FLOAT 24071 case 0x8b50: 24072 return setValueV2fArray; // _VEC2 24073 case 0x8b51: 24074 return setValueV3fArray; // _VEC3 24075 case 0x8b52: 24076 return setValueV4fArray; // _VEC4 24077 case 0x8b5a: 24078 return setValueM2Array; // _MAT2 24079 case 0x8b5b: 24080 return setValueM3Array; // _MAT3 24081 case 0x8b5c: 24082 return setValueM4Array; // _MAT4 24083 case 0x1404: 24084 case 0x8b56: 24085 return setValueV1iArray; // INT, BOOL 24086 case 0x8b53: 24087 case 0x8b57: 24088 return setValueV2iArray; // _VEC2 24089 case 0x8b54: 24090 case 0x8b58: 24091 return setValueV3iArray; // _VEC3 24092 case 0x8b55: 24093 case 0x8b59: 24094 return setValueV4iArray; // _VEC4 24095 case 0x1405: 24096 return setValueV1uiArray; // UINT 24097 case 0x8dc6: 24098 return setValueV2uiArray; // _VEC2 24099 case 0x8dc7: 24100 return setValueV3uiArray; // _VEC3 24101 case 0x8dc8: 24102 return setValueV4uiArray; // _VEC4 24103 case 0x8b5e: 24104 case 0x8d66: 24105 case 0x8dca: 24106 case 0x8dd2: 24107 case 0x8b62: 24108 return setValueT1Array; 24109 case 0x8b5f: 24110 case 0x8dcb: 24111 case 0x8dd3: 24112 return setValueT3DArray; 24113 case 0x8b60: 24114 case 0x8dcc: 24115 case 0x8dd4: 24116 case 0x8dc5: 24117 return setValueT6Array; 24118 case 0x8dc1: 24119 case 0x8dcf: 24120 case 0x8dd7: 24121 case 0x8dc4: 24122 return setValueT2DArrayArray; 24123 } 24124 } 24125 // --- Uniform Classes --- 24126 class SingleUniform { 24127 constructor(id, activeInfo, addr){ 24128 this.id = id; 24129 this.addr = addr; 24130 this.cache = []; 24131 this.type = activeInfo.type; 24132 this.setValue = getSingularSetter(activeInfo.type); 24133 // this.path = activeInfo.name; // DEBUG 24134 } 24135 } 24136 class PureArrayUniform { 24137 constructor(id, activeInfo, addr){ 24138 this.id = id; 24139 this.addr = addr; 24140 this.cache = []; 24141 this.type = activeInfo.type; 24142 this.size = activeInfo.size; 24143 this.setValue = getPureArraySetter(activeInfo.type); 24144 // this.path = activeInfo.name; // DEBUG 24145 } 24146 } 24147 class StructuredUniform { 24148 setValue(gl, value, textures) { 24149 const seq = this.seq; 24150 for(let i = 0, n = seq.length; i !== n; ++i){ 24151 const u = seq[i]; 24152 u.setValue(gl, value[u.id], textures); 24153 } 24154 } 24155 constructor(id){ 24156 this.id = id; 24157 this.seq = []; 24158 this.map = {}; 24159 } 24160 } 24161 // --- Top-level --- 24162 // Parser - builds up the property tree from the path strings 24163 const RePathPart = /(\w+)(\])?(\[|\.)?/g; 24164 // extracts 24165 // - the identifier (member name or array index) 24166 // - followed by an optional right bracket (found when array index) 24167 // - followed by an optional left bracket or dot (type of subscript) 24168 // 24169 // Note: These portions can be read in a non-overlapping fashion and 24170 // allow straightforward parsing of the hierarchy that WebGL encodes 24171 // in the uniform names. 24172 function addUniform(container, uniformObject) { 24173 container.seq.push(uniformObject); 24174 container.map[uniformObject.id] = uniformObject; 24175 } 24176 function parseUniform(activeInfo, addr, container) { 24177 const path = activeInfo.name, pathLength = path.length; 24178 // reset RegExp object, because of the early exit of a previous run 24179 RePathPart.lastIndex = 0; 24180 while(true){ 24181 const match = RePathPart.exec(path), matchEnd = RePathPart.lastIndex; 24182 let id = match[1]; 24183 const idIsIndex = match[2] === ']', subscript = match[3]; 24184 if (idIsIndex) id = id | 0; // convert to integer 24185 if (subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength) { 24186 // bare name or "pure" bottom-level array "[0]" suffix 24187 addUniform(container, subscript === undefined ? new SingleUniform(id, activeInfo, addr) : new PureArrayUniform(id, activeInfo, addr)); 24188 break; 24189 } else { 24190 // step into inner node / create it in case it doesn't exist 24191 const map = container.map; 24192 let next = map[id]; 24193 if (next === undefined) { 24194 next = new StructuredUniform(id); 24195 addUniform(container, next); 24196 } 24197 container = next; 24198 } 24199 } 24200 } 24201 // Root Container 24202 class WebGLUniforms { 24203 setValue(gl, name, value, textures) { 24204 const u = this.map[name]; 24205 if (u !== undefined) u.setValue(gl, value, textures); 24206 } 24207 setOptional(gl, object, name) { 24208 const v = object[name]; 24209 if (v !== undefined) this.setValue(gl, name, v); 24210 } 24211 static upload(gl, seq, values, textures) { 24212 for(let i = 0, n = seq.length; i !== n; ++i){ 24213 const u = seq[i], v = values[u.id]; 24214 if (v.needsUpdate !== false) { 24215 // note: always updating when .needsUpdate is undefined 24216 u.setValue(gl, v.value, textures); 24217 } 24218 } 24219 } 24220 static seqWithValue(seq, values) { 24221 const r = []; 24222 for(let i = 0, n = seq.length; i !== n; ++i){ 24223 const u = seq[i]; 24224 if (u.id in values) r.push(u); 24225 } 24226 return r; 24227 } 24228 constructor(gl, program){ 24229 this.seq = []; 24230 this.map = {}; 24231 const n = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS); 24232 for(let i = 0; i < n; ++i){ 24233 const info = gl.getActiveUniform(program, i), addr = gl.getUniformLocation(program, info.name); 24234 parseUniform(info, addr, this); 24235 } 24236 } 24237 } 24238 function WebGLShader(gl, type, string) { 24239 const shader = gl.createShader(type); 24240 gl.shaderSource(shader, string); 24241 gl.compileShader(shader); 24242 return shader; 24243 } 24244 // From https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/ 24245 const COMPLETION_STATUS_KHR = 0x91B1; 24246 let programIdCount = 0; 24247 function handleSource(string, errorLine) { 24248 const lines = string.split('\n'); 24249 const lines2 = []; 24250 const from = Math.max(errorLine - 6, 0); 24251 const to = Math.min(errorLine + 6, lines.length); 24252 for(let i = from; i < to; i++){ 24253 const line = i + 1; 24254 lines2.push(`${line === errorLine ? '>' : ' '} ${line}: ${lines[i]}`); 24255 } 24256 return lines2.join('\n'); 24257 } 24258 const _m0 = /*@__PURE__*/ new Matrix3(); 24259 function getEncodingComponents(colorSpace) { 24260 ColorManagement._getMatrix(_m0, ColorManagement.workingColorSpace, colorSpace); 24261 const encodingMatrix = `mat3( ${_m0.elements.map((v)=>v.toFixed(4))} )`; 24262 switch(ColorManagement.getTransfer(colorSpace)){ 24263 case LinearTransfer: 24264 return [ 24265 encodingMatrix, 24266 'LinearTransferOETF' 24267 ]; 24268 case SRGBTransfer: 24269 return [ 24270 encodingMatrix, 24271 'sRGBTransferOETF' 24272 ]; 24273 default: 24274 console.warn('THREE.WebGLProgram: Unsupported color space: ', colorSpace); 24275 return [ 24276 encodingMatrix, 24277 'LinearTransferOETF' 24278 ]; 24279 } 24280 } 24281 function getShaderErrors(gl, shader, type) { 24282 const status = gl.getShaderParameter(shader, gl.COMPILE_STATUS); 24283 const errors = gl.getShaderInfoLog(shader).trim(); 24284 if (status && errors === '') return ''; 24285 const errorMatches = /ERROR: 0:(\d+)/.exec(errors); 24286 if (errorMatches) { 24287 // --enable-privileged-webgl-extension 24288 // console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); 24289 const errorLine = parseInt(errorMatches[1]); 24290 return type.toUpperCase() + '\n\n' + errors + '\n\n' + handleSource(gl.getShaderSource(shader), errorLine); 24291 } else { 24292 return errors; 24293 } 24294 } 24295 function getTexelEncodingFunction(functionName, colorSpace) { 24296 const components = getEncodingComponents(colorSpace); 24297 return [ 24298 `vec4 ${functionName}( vec4 value ) {`, 24299 ` return ${components[1]}( vec4( value.rgb * ${components[0]}, value.a ) );`, 24300 '}' 24301 ].join('\n'); 24302 } 24303 function getToneMappingFunction(functionName, toneMapping) { 24304 let toneMappingName; 24305 switch(toneMapping){ 24306 case LinearToneMapping: 24307 toneMappingName = 'Linear'; 24308 break; 24309 case ReinhardToneMapping: 24310 toneMappingName = 'Reinhard'; 24311 break; 24312 case CineonToneMapping: 24313 toneMappingName = 'Cineon'; 24314 break; 24315 case ACESFilmicToneMapping: 24316 toneMappingName = 'ACESFilmic'; 24317 break; 24318 case AgXToneMapping: 24319 toneMappingName = 'AgX'; 24320 break; 24321 case NeutralToneMapping: 24322 toneMappingName = 'Neutral'; 24323 break; 24324 case CustomToneMapping: 24325 toneMappingName = 'Custom'; 24326 break; 24327 default: 24328 console.warn('THREE.WebGLProgram: Unsupported toneMapping:', toneMapping); 24329 toneMappingName = 'Linear'; 24330 } 24331 return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }'; 24332 } 24333 const _v0 = /*@__PURE__*/ new Vector3(); 24334 function getLuminanceFunction() { 24335 ColorManagement.getLuminanceCoefficients(_v0); 24336 const r = _v0.x.toFixed(4); 24337 const g = _v0.y.toFixed(4); 24338 const b = _v0.z.toFixed(4); 24339 return [ 24340 'float luminance( const in vec3 rgb ) {', 24341 ` const vec3 weights = vec3( ${r}, ${g}, ${b} );`, 24342 ' return dot( weights, rgb );', 24343 '}' 24344 ].join('\n'); 24345 } 24346 function generateVertexExtensions(parameters) { 24347 const chunks = [ 24348 parameters.extensionClipCullDistance ? '#extension GL_ANGLE_clip_cull_distance : require' : '', 24349 parameters.extensionMultiDraw ? '#extension GL_ANGLE_multi_draw : require' : '' 24350 ]; 24351 return chunks.filter(filterEmptyLine).join('\n'); 24352 } 24353 function generateDefines(defines) { 24354 const chunks = []; 24355 for(const name in defines){ 24356 const value = defines[name]; 24357 if (value === false) continue; 24358 chunks.push('#define ' + name + ' ' + value); 24359 } 24360 return chunks.join('\n'); 24361 } 24362 function fetchAttributeLocations(gl, program) { 24363 const attributes = {}; 24364 const n = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
vendor: 6,850 bytes, lines 24365-24518
24365 for(let i = 0; i < n; i++){ 24366 const info = gl.getActiveAttrib(program, i); 24367 const name = info.name; 24368 let locationSize = 1; 24369 if (info.type === gl.FLOAT_MAT2) locationSize = 2; 24370 if (info.type === gl.FLOAT_MAT3) locationSize = 3; 24371 if (info.type === gl.FLOAT_MAT4) locationSize = 4; 24372 // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i ); 24373 attributes[name] = { 24374 type: info.type, 24375 location: gl.getAttribLocation(program, name), 24376 locationSize: locationSize 24377 }; 24378 } 24379 return attributes; 24380 } 24381 function filterEmptyLine(string) { 24382 return string !== ''; 24383 } 24384 function replaceLightNums(string, parameters) { 24385 const numSpotLightCoords = parameters.numSpotLightShadows + parameters.numSpotLightMaps - parameters.numSpotLightShadowsWithMaps; 24386 return string.replace(/NUM_DIR_LIGHTS/g, parameters.numDirLights).replace(/NUM_SPOT_LIGHTS/g, parameters.numSpotLights).replace(/NUM_SPOT_LIGHT_MAPS/g, parameters.numSpotLightMaps).replace(/NUM_SPOT_LIGHT_COORDS/g, numSpotLightCoords).replace(/NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights).replace(/NUM_POINT_LIGHTS/g, parameters.numPointLights).replace(/NUM_HEMI_LIGHTS/g, parameters.numHemiLights).replace(/NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows).replace(/NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g, parameters.numSpotLightShadowsWithMaps).replace(/NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows).replace(/NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows); 24387 } 24388 function replaceClippingPlaneNums(string, parameters) { 24389 return string.replace(/NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes).replace(/UNION_CLIPPING_PLANES/g, parameters.numClippingPlanes - parameters.numClipIntersection); 24390 } 24391 // Resolve Includes 24392 const includePattern = /^[ \t]*#include +<([\w\d./]+)>/gm; 24393 function resolveIncludes(string) { 24394 return string.replace(includePattern, includeReplacer); 24395 } 24396 const shaderChunkMap = new Map(); 24397 function includeReplacer(match, include) { 24398 let string = ShaderChunk[include]; 24399 if (string === undefined) { 24400 const newInclude = shaderChunkMap.get(include); 24401 if (newInclude !== undefined) { 24402 string = ShaderChunk[newInclude]; 24403 console.warn('THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.', include, newInclude); 24404 } else { 24405 throw new Error('Can not resolve #include <' + include + '>'); 24406 } 24407 } 24408 return resolveIncludes(string); 24409 } 24410 // Unroll Loops 24411 const unrollLoopPattern = /#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g; 24412 function unrollLoops(string) { 24413 return string.replace(unrollLoopPattern, loopReplacer); 24414 } 24415 function loopReplacer(match, start, end, snippet) { 24416 let string = ''; 24417 for(let i = parseInt(start); i < parseInt(end); i++){ 24418 string += snippet.replace(/\[\s*i\s*\]/g, '[ ' + i + ' ]').replace(/UNROLLED_LOOP_INDEX/g, i); 24419 } 24420 return string; 24421 } 24422 // 24423 function generatePrecision(parameters) { 24424 let precisionstring = `precision ${parameters.precision} float; 24425 precision ${parameters.precision} int; 24426 precision ${parameters.precision} sampler2D; 24427 precision ${parameters.precision} samplerCube; 24428 precision ${parameters.precision} sampler3D; 24429 precision ${parameters.precision} sampler2DArray; 24430 precision ${parameters.precision} sampler2DShadow; 24431 precision ${parameters.precision} samplerCubeShadow; 24432 precision ${parameters.precision} sampler2DArrayShadow; 24433 precision ${parameters.precision} isampler2D; 24434 precision ${parameters.precision} isampler3D; 24435 precision ${parameters.precision} isamplerCube; 24436 precision ${parameters.precision} isampler2DArray; 24437 precision ${parameters.precision} usampler2D; 24438 precision ${parameters.precision} usampler3D; 24439 precision ${parameters.precision} usamplerCube; 24440 precision ${parameters.precision} usampler2DArray; 24441 `; 24442 if (parameters.precision === 'highp') { 24443 precisionstring += '\n#define HIGH_PRECISION'; 24444 } else if (parameters.precision === 'mediump') { 24445 precisionstring += '\n#define MEDIUM_PRECISION'; 24446 } else if (parameters.precision === 'lowp') { 24447 precisionstring += '\n#define LOW_PRECISION'; 24448 } 24449 return precisionstring; 24450 } 24451 function generateShadowMapTypeDefine(parameters) { 24452 let shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC'; 24453 if (parameters.shadowMapType === PCFShadowMap) { 24454 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF'; 24455 } else if (parameters.shadowMapType === PCFSoftShadowMap) { 24456 shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT'; 24457 } else if (parameters.shadowMapType === VSMShadowMap) { 24458 shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM'; 24459 } 24460 return shadowMapTypeDefine; 24461 } 24462 function generateEnvMapTypeDefine(parameters) { 24463 let envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; 24464 if (parameters.envMap) { 24465 switch(parameters.envMapMode){ 24466 case CubeReflectionMapping: 24467 case CubeRefractionMapping: 24468 envMapTypeDefine = 'ENVMAP_TYPE_CUBE'; 24469 break; 24470 case CubeUVReflectionMapping: 24471 envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV'; 24472 break; 24473 } 24474 } 24475 return envMapTypeDefine; 24476 } 24477 function generateEnvMapModeDefine(parameters) { 24478 let envMapModeDefine = 'ENVMAP_MODE_REFLECTION'; 24479 if (parameters.envMap) { 24480 switch(parameters.envMapMode){ 24481 case CubeRefractionMapping: 24482 envMapModeDefine = 'ENVMAP_MODE_REFRACTION'; 24483 break; 24484 } 24485 } 24486 return envMapModeDefine; 24487 } 24488 function generateEnvMapBlendingDefine(parameters) { 24489 let envMapBlendingDefine = 'ENVMAP_BLENDING_NONE'; 24490 if (parameters.envMap) { 24491 switch(parameters.combine){ 24492 case MultiplyOperation: 24493 envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY'; 24494 break; 24495 case MixOperation: 24496 envMapBlendingDefine = 'ENVMAP_BLENDING_MIX'; 24497 break; 24498 case AddOperation: 24499 envMapBlendingDefine = 'ENVMAP_BLENDING_ADD'; 24500 break; 24501 } 24502 } 24503 return envMapBlendingDefine; 24504 } 24505 function generateCubeUVSize(parameters) { 24506 const imageHeight = parameters.envMapCubeUVHeight; 24507 if (imageHeight === null) return null; 24508 const maxMip = Math.log2(imageHeight) - 2; 24509 const texelHeight = 1.0 / imageHeight; 24510 const texelWidth = 1.0 / (3 * Math.max(Math.pow(2, maxMip), 7 * 16)); 24511 return { 24512 texelWidth, 24513 texelHeight, 24514 maxMip 24515 }; 24516 } 24517 function WebGLProgram(renderer, cacheKey, parameters, bindingStates) { 24518 // TODO Send this event to Three.js DevTools
vendor: 43,794 bytes, lines 24519-25300
24519 // console.log( 'WebGLProgram', cacheKey ); 24520 const gl = renderer.getContext(); 24521 const defines = parameters.defines; 24522 let vertexShader = parameters.vertexShader; 24523 let fragmentShader = parameters.fragmentShader; 24524 const shadowMapTypeDefine = generateShadowMapTypeDefine(parameters); 24525 const envMapTypeDefine = generateEnvMapTypeDefine(parameters); 24526 const envMapModeDefine = generateEnvMapModeDefine(parameters); 24527 const envMapBlendingDefine = generateEnvMapBlendingDefine(parameters); 24528 const envMapCubeUVSize = generateCubeUVSize(parameters); 24529 const customVertexExtensions = generateVertexExtensions(parameters); 24530 const customDefines = generateDefines(defines); 24531 const program = gl.createProgram(); 24532 let prefixVertex, prefixFragment; 24533 let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : ''; 24534 if (parameters.isRawShaderMaterial) { 24535 prefixVertex = [ 24536 '#define SHADER_TYPE ' + parameters.shaderType, 24537 '#define SHADER_NAME ' + parameters.shaderName, 24538 customDefines 24539 ].filter(filterEmptyLine).join('\n'); 24540 if (prefixVertex.length > 0) { 24541 prefixVertex += '\n'; 24542 } 24543 prefixFragment = [ 24544 '#define SHADER_TYPE ' + parameters.shaderType, 24545 '#define SHADER_NAME ' + parameters.shaderName, 24546 customDefines 24547 ].filter(filterEmptyLine).join('\n'); 24548 if (prefixFragment.length > 0) { 24549 prefixFragment += '\n'; 24550 } 24551 } else { 24552 prefixVertex = [ 24553 generatePrecision(parameters), 24554 '#define SHADER_TYPE ' + parameters.shaderType, 24555 '#define SHADER_NAME ' + parameters.shaderName, 24556 customDefines, 24557 parameters.extensionClipCullDistance ? '#define USE_CLIP_DISTANCE' : '', 24558 parameters.batching ? '#define USE_BATCHING' : '', 24559 parameters.batchingColor ? '#define USE_BATCHING_COLOR' : '', 24560 parameters.instancing ? '#define USE_INSTANCING' : '', 24561 parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '', 24562 parameters.instancingMorph ? '#define USE_INSTANCING_MORPH' : '', 24563 parameters.useFog && parameters.fog ? '#define USE_FOG' : '', 24564 parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '', 24565 parameters.map ? '#define USE_MAP' : '', 24566 parameters.envMap ? '#define USE_ENVMAP' : '', 24567 parameters.envMap ? '#define ' + envMapModeDefine : '', 24568 parameters.lightMap ? '#define USE_LIGHTMAP' : '', 24569 parameters.aoMap ? '#define USE_AOMAP' : '', 24570 parameters.bumpMap ? '#define USE_BUMPMAP' : '', 24571 parameters.normalMap ? '#define USE_NORMALMAP' : '', 24572 parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '', 24573 parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '', 24574 parameters.displacementMap ? '#define USE_DISPLACEMENTMAP' : '', 24575 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', 24576 parameters.anisotropy ? '#define USE_ANISOTROPY' : '', 24577 parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '', 24578 parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', 24579 parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', 24580 parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '', 24581 parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '', 24582 parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', 24583 parameters.specularMap ? '#define USE_SPECULARMAP' : '', 24584 parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '', 24585 parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '', 24586 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', 24587 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', 24588 parameters.alphaMap ? '#define USE_ALPHAMAP' : '', 24589 parameters.alphaHash ? '#define USE_ALPHAHASH' : '', 24590 parameters.transmission ? '#define USE_TRANSMISSION' : '', 24591 parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', 24592 parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', 24593 parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '', 24594 parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '', 24595 // 24596 parameters.mapUv ? '#define MAP_UV ' + parameters.mapUv : '', 24597 parameters.alphaMapUv ? '#define ALPHAMAP_UV ' + parameters.alphaMapUv : '', 24598 parameters.lightMapUv ? '#define LIGHTMAP_UV ' + parameters.lightMapUv : '', 24599 parameters.aoMapUv ? '#define AOMAP_UV ' + parameters.aoMapUv : '', 24600 parameters.emissiveMapUv ? '#define EMISSIVEMAP_UV ' + parameters.emissiveMapUv : '', 24601 parameters.bumpMapUv ? '#define BUMPMAP_UV ' + parameters.bumpMapUv : '', 24602 parameters.normalMapUv ? '#define NORMALMAP_UV ' + parameters.normalMapUv : '', 24603 parameters.displacementMapUv ? '#define DISPLACEMENTMAP_UV ' + parameters.displacementMapUv : '', 24604 parameters.metalnessMapUv ? '#define METALNESSMAP_UV ' + parameters.metalnessMapUv : '', 24605 parameters.roughnessMapUv ? '#define ROUGHNESSMAP_UV ' + parameters.roughnessMapUv : '', 24606 parameters.anisotropyMapUv ? '#define ANISOTROPYMAP_UV ' + parameters.anisotropyMapUv : '', 24607 parameters.clearcoatMapUv ? '#define CLEARCOATMAP_UV ' + parameters.clearcoatMapUv : '', 24608 parameters.clearcoatNormalMapUv ? '#define CLEARCOAT_NORMALMAP_UV ' + parameters.clearcoatNormalMapUv : '', 24609 parameters.clearcoatRoughnessMapUv ? '#define CLEARCOAT_ROUGHNESSMAP_UV ' + parameters.clearcoatRoughnessMapUv : '', 24610 parameters.iridescenceMapUv ? '#define IRIDESCENCEMAP_UV ' + parameters.iridescenceMapUv : '', 24611 parameters.iridescenceThicknessMapUv ? '#define IRIDESCENCE_THICKNESSMAP_UV ' + parameters.iridescenceThicknessMapUv : '', 24612 parameters.sheenColorMapUv ? '#define SHEEN_COLORMAP_UV ' + parameters.sheenColorMapUv : '', 24613 parameters.sheenRoughnessMapUv ? '#define SHEEN_ROUGHNESSMAP_UV ' + parameters.sheenRoughnessMapUv : '', 24614 parameters.specularMapUv ? '#define SPECULARMAP_UV ' + parameters.specularMapUv : '', 24615 parameters.specularColorMapUv ? '#define SPECULAR_COLORMAP_UV ' + parameters.specularColorMapUv : '', 24616 parameters.specularIntensityMapUv ? '#define SPECULAR_INTENSITYMAP_UV ' + parameters.specularIntensityMapUv : '', 24617 parameters.transmissionMapUv ? '#define TRANSMISSIONMAP_UV ' + parameters.transmissionMapUv : '', 24618 parameters.thicknessMapUv ? '#define THICKNESSMAP_UV ' + parameters.thicknessMapUv : '', 24619 // 24620 parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '', 24621 parameters.vertexColors ? '#define USE_COLOR' : '', 24622 parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', 24623 parameters.vertexUv1s ? '#define USE_UV1' : '', 24624 parameters.vertexUv2s ? '#define USE_UV2' : '', 24625 parameters.vertexUv3s ? '#define USE_UV3' : '', 24626 parameters.pointsUvs ? '#define USE_POINTS_UV' : '', 24627 parameters.flatShading ? '#define FLAT_SHADED' : '', 24628 parameters.skinning ? '#define USE_SKINNING' : '', 24629 parameters.morphTargets ? '#define USE_MORPHTARGETS' : '', 24630 parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '', 24631 parameters.morphColors ? '#define USE_MORPHCOLORS' : '', 24632 parameters.morphTargetsCount > 0 ? '#define MORPHTARGETS_TEXTURE_STRIDE ' + parameters.morphTextureStride : '', 24633 parameters.morphTargetsCount > 0 ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '', 24634 parameters.doubleSided ? '#define DOUBLE_SIDED' : '', 24635 parameters.flipSided ? '#define FLIP_SIDED' : '', 24636 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', 24637 parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', 24638 parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', 24639 parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', 24640 parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', 24641 parameters.reverseDepthBuffer ? '#define USE_REVERSEDEPTHBUF' : '', 24642 'uniform mat4 modelMatrix;', 24643 'uniform mat4 modelViewMatrix;', 24644 'uniform mat4 projectionMatrix;', 24645 'uniform mat4 viewMatrix;', 24646 'uniform mat3 normalMatrix;', 24647 'uniform vec3 cameraPosition;', 24648 'uniform bool isOrthographic;', 24649 '#ifdef USE_INSTANCING', 24650 ' attribute mat4 instanceMatrix;', 24651 '#endif', 24652 '#ifdef USE_INSTANCING_COLOR', 24653 ' attribute vec3 instanceColor;', 24654 '#endif', 24655 '#ifdef USE_INSTANCING_MORPH', 24656 ' uniform sampler2D morphTexture;', 24657 '#endif', 24658 'attribute vec3 position;', 24659 'attribute vec3 normal;', 24660 'attribute vec2 uv;', 24661 '#ifdef USE_UV1', 24662 ' attribute vec2 uv1;', 24663 '#endif', 24664 '#ifdef USE_UV2', 24665 ' attribute vec2 uv2;', 24666 '#endif', 24667 '#ifdef USE_UV3', 24668 ' attribute vec2 uv3;', 24669 '#endif', 24670 '#ifdef USE_TANGENT', 24671 ' attribute vec4 tangent;', 24672 '#endif', 24673 '#if defined( USE_COLOR_ALPHA )', 24674 ' attribute vec4 color;', 24675 '#elif defined( USE_COLOR )', 24676 ' attribute vec3 color;', 24677 '#endif', 24678 '#ifdef USE_SKINNING', 24679 ' attribute vec4 skinIndex;', 24680 ' attribute vec4 skinWeight;', 24681 '#endif', 24682 '\n' 24683 ].filter(filterEmptyLine).join('\n'); 24684 prefixFragment = [ 24685 generatePrecision(parameters), 24686 '#define SHADER_TYPE ' + parameters.shaderType, 24687 '#define SHADER_NAME ' + parameters.shaderName, 24688 customDefines, 24689 parameters.useFog && parameters.fog ? '#define USE_FOG' : '', 24690 parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '', 24691 parameters.alphaToCoverage ? '#define ALPHA_TO_COVERAGE' : '', 24692 parameters.map ? '#define USE_MAP' : '', 24693 parameters.matcap ? '#define USE_MATCAP' : '', 24694 parameters.envMap ? '#define USE_ENVMAP' : '', 24695 parameters.envMap ? '#define ' + envMapTypeDefine : '', 24696 parameters.envMap ? '#define ' + envMapModeDefine : '', 24697 parameters.envMap ? '#define ' + envMapBlendingDefine : '', 24698 envMapCubeUVSize ? '#define CUBEUV_TEXEL_WIDTH ' + envMapCubeUVSize.texelWidth : '', 24699 envMapCubeUVSize ? '#define CUBEUV_TEXEL_HEIGHT ' + envMapCubeUVSize.texelHeight : '', 24700 envMapCubeUVSize ? '#define CUBEUV_MAX_MIP ' + envMapCubeUVSize.maxMip + '.0' : '', 24701 parameters.lightMap ? '#define USE_LIGHTMAP' : '', 24702 parameters.aoMap ? '#define USE_AOMAP' : '', 24703 parameters.bumpMap ? '#define USE_BUMPMAP' : '', 24704 parameters.normalMap ? '#define USE_NORMALMAP' : '', 24705 parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '', 24706 parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '', 24707 parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', 24708 parameters.anisotropy ? '#define USE_ANISOTROPY' : '', 24709 parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '', 24710 parameters.clearcoat ? '#define USE_CLEARCOAT' : '', 24711 parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', 24712 parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', 24713 parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '', 24714 parameters.dispersion ? '#define USE_DISPERSION' : '', 24715 parameters.iridescence ? '#define USE_IRIDESCENCE' : '', 24716 parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '', 24717 parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', 24718 parameters.specularMap ? '#define USE_SPECULARMAP' : '', 24719 parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '', 24720 parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '', 24721 parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', 24722 parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', 24723 parameters.alphaMap ? '#define USE_ALPHAMAP' : '', 24724 parameters.alphaTest ? '#define USE_ALPHATEST' : '', 24725 parameters.alphaHash ? '#define USE_ALPHAHASH' : '', 24726 parameters.sheen ? '#define USE_SHEEN' : '', 24727 parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '', 24728 parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '', 24729 parameters.transmission ? '#define USE_TRANSMISSION' : '', 24730 parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', 24731 parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', 24732 parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '', 24733 parameters.vertexColors || parameters.instancingColor || parameters.batchingColor ? '#define USE_COLOR' : '', 24734 parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', 24735 parameters.vertexUv1s ? '#define USE_UV1' : '', 24736 parameters.vertexUv2s ? '#define USE_UV2' : '', 24737 parameters.vertexUv3s ? '#define USE_UV3' : '', 24738 parameters.pointsUvs ? '#define USE_POINTS_UV' : '', 24739 parameters.gradientMap ? '#define USE_GRADIENTMAP' : '', 24740 parameters.flatShading ? '#define FLAT_SHADED' : '', 24741 parameters.doubleSided ? '#define DOUBLE_SIDED' : '', 24742 parameters.flipSided ? '#define FLIP_SIDED' : '', 24743 parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '', 24744 parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '', 24745 parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '', 24746 parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', 24747 parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '', 24748 parameters.decodeVideoTextureEmissive ? '#define DECODE_VIDEO_TEXTURE_EMISSIVE' : '', 24749 parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', 24750 parameters.reverseDepthBuffer ? '#define USE_REVERSEDEPTHBUF' : '', 24751 'uniform mat4 viewMatrix;', 24752 'uniform vec3 cameraPosition;', 24753 'uniform bool isOrthographic;', 24754 parameters.toneMapping !== NoToneMapping ? '#define TONE_MAPPING' : '', 24755 parameters.toneMapping !== NoToneMapping ? ShaderChunk['tonemapping_pars_fragment'] : '', 24756 parameters.toneMapping !== NoToneMapping ? getToneMappingFunction('toneMapping', parameters.toneMapping) : '', 24757 parameters.dithering ? '#define DITHERING' : '', 24758 parameters.opaque ? '#define OPAQUE' : '', 24759 ShaderChunk['colorspace_pars_fragment'], 24760 getTexelEncodingFunction('linearToOutputTexel', parameters.outputColorSpace), 24761 getLuminanceFunction(), 24762 parameters.useDepthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '', 24763 '\n' 24764 ].filter(filterEmptyLine).join('\n'); 24765 } 24766 vertexShader = resolveIncludes(vertexShader); 24767 vertexShader = replaceLightNums(vertexShader, parameters); 24768 vertexShader = replaceClippingPlaneNums(vertexShader, parameters); 24769 fragmentShader = resolveIncludes(fragmentShader); 24770 fragmentShader = replaceLightNums(fragmentShader, parameters); 24771 fragmentShader = replaceClippingPlaneNums(fragmentShader, parameters); 24772 vertexShader = unrollLoops(vertexShader); 24773 fragmentShader = unrollLoops(fragmentShader); 24774 if (parameters.isRawShaderMaterial !== true) { 24775 // GLSL 3.0 conversion for built-in materials and ShaderMaterial 24776 versionString = '#version 300 es\n'; 24777 prefixVertex = [ 24778 customVertexExtensions, 24779 '#define attribute in', 24780 '#define varying out', 24781 '#define texture2D texture' 24782 ].join('\n') + '\n' + prefixVertex; 24783 prefixFragment = [ 24784 '#define varying in', 24785 parameters.glslVersion === GLSL3 ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;', 24786 parameters.glslVersion === GLSL3 ? '' : '#define gl_FragColor pc_fragColor', 24787 '#define gl_FragDepthEXT gl_FragDepth', 24788 '#define texture2D texture', 24789 '#define textureCube texture', 24790 '#define texture2DProj textureProj', 24791 '#define texture2DLodEXT textureLod', 24792 '#define texture2DProjLodEXT textureProjLod', 24793 '#define textureCubeLodEXT textureLod', 24794 '#define texture2DGradEXT textureGrad', 24795 '#define texture2DProjGradEXT textureProjGrad', 24796 '#define textureCubeGradEXT textureGrad' 24797 ].join('\n') + '\n' + prefixFragment; 24798 } 24799 const vertexGlsl = versionString + prefixVertex + vertexShader; 24800 const fragmentGlsl = versionString + prefixFragment + fragmentShader; 24801 // console.log( '*VERTEX*', vertexGlsl ); 24802 // console.log( '*FRAGMENT*', fragmentGlsl ); 24803 const glVertexShader = WebGLShader(gl, gl.VERTEX_SHADER, vertexGlsl); 24804 const glFragmentShader = WebGLShader(gl, gl.FRAGMENT_SHADER, fragmentGlsl); 24805 gl.attachShader(program, glVertexShader); 24806 gl.attachShader(program, glFragmentShader); 24807 // Force a particular attribute to index 0. 24808 if (parameters.index0AttributeName !== undefined) { 24809 gl.bindAttribLocation(program, 0, parameters.index0AttributeName); 24810 } else if (parameters.morphTargets === true) { 24811 // programs with morphTargets displace position out of attribute 0 24812 gl.bindAttribLocation(program, 0, 'position'); 24813 } 24814 gl.linkProgram(program); 24815 function onFirstUse(self1) { 24816 // check for link errors 24817 if (renderer.debug.checkShaderErrors) { 24818 const programLog = gl.getProgramInfoLog(program).trim(); 24819 const vertexLog = gl.getShaderInfoLog(glVertexShader).trim(); 24820 const fragmentLog = gl.getShaderInfoLog(glFragmentShader).trim(); 24821 let runnable = true; 24822 let haveDiagnostics = true; 24823 if (gl.getProgramParameter(program, gl.LINK_STATUS) === false) { 24824 runnable = false; 24825 if (typeof renderer.debug.onShaderError === 'function') { 24826 renderer.debug.onShaderError(gl, program, glVertexShader, glFragmentShader); 24827 } else { 24828 // default error reporting 24829 const vertexErrors = getShaderErrors(gl, glVertexShader, 'vertex'); 24830 const fragmentErrors = getShaderErrors(gl, glFragmentShader, 'fragment'); 24831 console.error('THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' + 'VALIDATE_STATUS ' + gl.getProgramParameter(program, gl.VALIDATE_STATUS) + '\n\n' + 'Material Name: ' + self1.name + '\n' + 'Material Type: ' + self1.type + '\n\n' + 'Program Info Log: ' + programLog + '\n' + vertexErrors + '\n' + fragmentErrors); 24832 } 24833 } else if (programLog !== '') { 24834 console.warn('THREE.WebGLProgram: Program Info Log:', programLog); 24835 } else if (vertexLog === '' || fragmentLog === '') { 24836 haveDiagnostics = false; 24837 } 24838 if (haveDiagnostics) { 24839 self1.diagnostics = { 24840 runnable: runnable, 24841 programLog: programLog, 24842 vertexShader: { 24843 log: vertexLog, 24844 prefix: prefixVertex 24845 }, 24846 fragmentShader: { 24847 log: fragmentLog, 24848 prefix: prefixFragment 24849 } 24850 }; 24851 } 24852 } 24853 // Clean up 24854 // Crashes in iOS9 and iOS10. #18402 24855 // gl.detachShader( program, glVertexShader ); 24856 // gl.detachShader( program, glFragmentShader ); 24857 gl.deleteShader(glVertexShader); 24858 gl.deleteShader(glFragmentShader); 24859 cachedUniforms = new WebGLUniforms(gl, program); 24860 cachedAttributes = fetchAttributeLocations(gl, program); 24861 } 24862 // set up caching for uniform locations 24863 let cachedUniforms; 24864 this.getUniforms = function() { 24865 if (cachedUniforms === undefined) { 24866 // Populates cachedUniforms and cachedAttributes 24867 onFirstUse(this); 24868 } 24869 return cachedUniforms; 24870 }; 24871 // set up caching for attribute locations 24872 let cachedAttributes; 24873 this.getAttributes = function() { 24874 if (cachedAttributes === undefined) { 24875 // Populates cachedAttributes and cachedUniforms 24876 onFirstUse(this); 24877 } 24878 return cachedAttributes; 24879 }; 24880 // indicate when the program is ready to be used. if the KHR_parallel_shader_compile extension isn't supported, 24881 // flag the program as ready immediately. It may cause a stall when it's first used. 24882 let programReady = parameters.rendererExtensionParallelShaderCompile === false; 24883 this.isReady = function() { 24884 if (programReady === false) { 24885 programReady = gl.getProgramParameter(program, COMPLETION_STATUS_KHR); 24886 } 24887 return programReady; 24888 }; 24889 // free resource 24890 this.destroy = function() { 24891 bindingStates.releaseStatesOfProgram(this); 24892 gl.deleteProgram(program); 24893 this.program = undefined; 24894 }; 24895 // 24896 this.type = parameters.shaderType; 24897 this.name = parameters.shaderName; 24898 this.id = programIdCount++; 24899 this.cacheKey = cacheKey; 24900 this.usedTimes = 1; 24901 this.program = program; 24902 this.vertexShader = glVertexShader; 24903 this.fragmentShader = glFragmentShader; 24904 return this; 24905 } 24906 let _id = 0; 24907 class WebGLShaderCache { 24908 update(material) { 24909 const vertexShader = material.vertexShader; 24910 const fragmentShader = material.fragmentShader; 24911 const vertexShaderStage = this._getShaderStage(vertexShader); 24912 const fragmentShaderStage = this._getShaderStage(fragmentShader); 24913 const materialShaders = this._getShaderCacheForMaterial(material); 24914 if (materialShaders.has(vertexShaderStage) === false) { 24915 materialShaders.add(vertexShaderStage); 24916 vertexShaderStage.usedTimes++; 24917 } 24918 if (materialShaders.has(fragmentShaderStage) === false) { 24919 materialShaders.add(fragmentShaderStage); 24920 fragmentShaderStage.usedTimes++; 24921 } 24922 return this; 24923 } 24924 remove(material) { 24925 const materialShaders = this.materialCache.get(material); 24926 for (const shaderStage of materialShaders){ 24927 shaderStage.usedTimes--; 24928 if (shaderStage.usedTimes === 0) this.shaderCache.delete(shaderStage.code); 24929 } 24930 this.materialCache.delete(material); 24931 return this; 24932 } 24933 getVertexShaderID(material) { 24934 return this._getShaderStage(material.vertexShader).id; 24935 } 24936 getFragmentShaderID(material) { 24937 return this._getShaderStage(material.fragmentShader).id; 24938 } 24939 dispose() { 24940 this.shaderCache.clear(); 24941 this.materialCache.clear(); 24942 } 24943 _getShaderCacheForMaterial(material) { 24944 const cache = this.materialCache; 24945 let set = cache.get(material); 24946 if (set === undefined) { 24947 set = new Set(); 24948 cache.set(material, set); 24949 } 24950 return set; 24951 } 24952 _getShaderStage(code) { 24953 const cache = this.shaderCache; 24954 let stage = cache.get(code); 24955 if (stage === undefined) { 24956 stage = new WebGLShaderStage(code); 24957 cache.set(code, stage); 24958 } 24959 return stage; 24960 } 24961 constructor(){ 24962 this.shaderCache = new Map(); 24963 this.materialCache = new Map(); 24964 } 24965 } 24966 class WebGLShaderStage { 24967 constructor(code){ 24968 this.id = _id++; 24969 this.code = code; 24970 this.usedTimes = 0; 24971 } 24972 } 24973 function WebGLPrograms(renderer, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping) { 24974 const _programLayers = new Layers(); 24975 const _customShaders = new WebGLShaderCache(); 24976 const _activeChannels = new Set(); 24977 const programs = []; 24978 const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer; 24979 const SUPPORTS_VERTEX_TEXTURES = capabilities.vertexTextures; 24980 let precision = capabilities.precision; 24981 const shaderIDs = { 24982 MeshDepthMaterial: 'depth', 24983 MeshDistanceMaterial: 'distanceRGBA', 24984 MeshNormalMaterial: 'normal', 24985 MeshBasicMaterial: 'basic', 24986 MeshLambertMaterial: 'lambert', 24987 MeshPhongMaterial: 'phong', 24988 MeshToonMaterial: 'toon', 24989 MeshStandardMaterial: 'physical', 24990 MeshPhysicalMaterial: 'physical', 24991 MeshMatcapMaterial: 'matcap', 24992 LineBasicMaterial: 'basic', 24993 LineDashedMaterial: 'dashed', 24994 PointsMaterial: 'points', 24995 ShadowMaterial: 'shadow', 24996 SpriteMaterial: 'sprite' 24997 }; 24998 function getChannel(value) { 24999 _activeChannels.add(value); 25000 if (value === 0) return 'uv'; 25001 return `uv${value}`; 25002 } 25003 function getParameters(material, lights, shadows, scene, object) { 25004 const fog = scene.fog; 25005 const geometry = object.geometry; 25006 const environment = material.isMeshStandardMaterial ? scene.environment : null; 25007 const envMap = (material.isMeshStandardMaterial ? cubeuvmaps : cubemaps).get(material.envMap || environment); 25008 const envMapCubeUVHeight = !!envMap && envMap.mapping === CubeUVReflectionMapping ? envMap.image.height : null; 25009 const shaderID = shaderIDs[material.type]; 25010 // heuristics to create shader parameters according to lights in the scene 25011 // (not to blow over maxLights budget) 25012 if (material.precision !== null) { 25013 precision = capabilities.getMaxPrecision(material.precision); 25014 if (precision !== material.precision) { 25015 console.warn('THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.'); 25016 } 25017 } 25018 // 25019 const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; 25020 const morphTargetsCount = morphAttribute !== undefined ? morphAttribute.length : 0; 25021 let morphTextureStride = 0; 25022 if (geometry.morphAttributes.position !== undefined) morphTextureStride = 1; 25023 if (geometry.morphAttributes.normal !== undefined) morphTextureStride = 2; 25024 if (geometry.morphAttributes.color !== undefined) morphTextureStride = 3; 25025 // 25026 let vertexShader, fragmentShader; 25027 let customVertexShaderID, customFragmentShaderID; 25028 if (shaderID) { 25029 const shader = ShaderLib[shaderID]; 25030 vertexShader = shader.vertexShader; 25031 fragmentShader = shader.fragmentShader; 25032 } else { 25033 vertexShader = material.vertexShader; 25034 fragmentShader = material.fragmentShader; 25035 _customShaders.update(material); 25036 customVertexShaderID = _customShaders.getVertexShaderID(material); 25037 customFragmentShaderID = _customShaders.getFragmentShaderID(material); 25038 } 25039 const currentRenderTarget = renderer.getRenderTarget(); 25040 const reverseDepthBuffer = renderer.state.buffers.depth.getReversed(); 25041 const IS_INSTANCEDMESH = object.isInstancedMesh === true; 25042 const IS_BATCHEDMESH = object.isBatchedMesh === true; 25043 const HAS_MAP = !!material.map; 25044 const HAS_MATCAP = !!material.matcap; 25045 const HAS_ENVMAP = !!envMap; 25046 const HAS_AOMAP = !!material.aoMap; 25047 const HAS_LIGHTMAP = !!material.lightMap; 25048 const HAS_BUMPMAP = !!material.bumpMap; 25049 const HAS_NORMALMAP = !!material.normalMap; 25050 const HAS_DISPLACEMENTMAP = !!material.displacementMap; 25051 const HAS_EMISSIVEMAP = !!material.emissiveMap; 25052 const HAS_METALNESSMAP = !!material.metalnessMap; 25053 const HAS_ROUGHNESSMAP = !!material.roughnessMap; 25054 const HAS_ANISOTROPY = material.anisotropy > 0; 25055 const HAS_CLEARCOAT = material.clearcoat > 0; 25056 const HAS_DISPERSION = material.dispersion > 0; 25057 const HAS_IRIDESCENCE = material.iridescence > 0; 25058 const HAS_SHEEN = material.sheen > 0; 25059 const HAS_TRANSMISSION = material.transmission > 0; 25060 const HAS_ANISOTROPYMAP = HAS_ANISOTROPY && !!material.anisotropyMap; 25061 const HAS_CLEARCOATMAP = HAS_CLEARCOAT && !!material.clearcoatMap; 25062 const HAS_CLEARCOAT_NORMALMAP = HAS_CLEARCOAT && !!material.clearcoatNormalMap; 25063 const HAS_CLEARCOAT_ROUGHNESSMAP = HAS_CLEARCOAT && !!material.clearcoatRoughnessMap; 25064 const HAS_IRIDESCENCEMAP = HAS_IRIDESCENCE && !!material.iridescenceMap; 25065 const HAS_IRIDESCENCE_THICKNESSMAP = HAS_IRIDESCENCE && !!material.iridescenceThicknessMap; 25066 const HAS_SHEEN_COLORMAP = HAS_SHEEN && !!material.sheenColorMap; 25067 const HAS_SHEEN_ROUGHNESSMAP = HAS_SHEEN && !!material.sheenRoughnessMap; 25068 const HAS_SPECULARMAP = !!material.specularMap; 25069 const HAS_SPECULAR_COLORMAP = !!material.specularColorMap; 25070 const HAS_SPECULAR_INTENSITYMAP = !!material.specularIntensityMap; 25071 const HAS_TRANSMISSIONMAP = HAS_TRANSMISSION && !!material.transmissionMap; 25072 const HAS_THICKNESSMAP = HAS_TRANSMISSION && !!material.thicknessMap; 25073 const HAS_GRADIENTMAP = !!material.gradientMap; 25074 const HAS_ALPHAMAP = !!material.alphaMap; 25075 const HAS_ALPHATEST = material.alphaTest > 0; 25076 const HAS_ALPHAHASH = !!material.alphaHash; 25077 const HAS_EXTENSIONS = !!material.extensions; 25078 let toneMapping = NoToneMapping; 25079 if (material.toneMapped) { 25080 if (currentRenderTarget === null || currentRenderTarget.isXRRenderTarget === true) { 25081 toneMapping = renderer.toneMapping; 25082 } 25083 } 25084 const parameters = { 25085 shaderID: shaderID, 25086 shaderType: material.type, 25087 shaderName: material.name, 25088 vertexShader: vertexShader, 25089 fragmentShader: fragmentShader, 25090 defines: material.defines, 25091 customVertexShaderID: customVertexShaderID, 25092 customFragmentShaderID: customFragmentShaderID, 25093 isRawShaderMaterial: material.isRawShaderMaterial === true, 25094 glslVersion: material.glslVersion, 25095 precision: precision, 25096 batching: IS_BATCHEDMESH, 25097 batchingColor: IS_BATCHEDMESH && object._colorsTexture !== null, 25098 instancing: IS_INSTANCEDMESH, 25099 instancingColor: IS_INSTANCEDMESH && object.instanceColor !== null, 25100 instancingMorph: IS_INSTANCEDMESH && object.morphTexture !== null, 25101 supportsVertexTextures: SUPPORTS_VERTEX_TEXTURES, 25102 outputColorSpace: currentRenderTarget === null ? renderer.outputColorSpace : currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace, 25103 alphaToCoverage: !!material.alphaToCoverage, 25104 map: HAS_MAP, 25105 matcap: HAS_MATCAP, 25106 envMap: HAS_ENVMAP, 25107 envMapMode: HAS_ENVMAP && envMap.mapping, 25108 envMapCubeUVHeight: envMapCubeUVHeight, 25109 aoMap: HAS_AOMAP, 25110 lightMap: HAS_LIGHTMAP, 25111 bumpMap: HAS_BUMPMAP, 25112 normalMap: HAS_NORMALMAP, 25113 displacementMap: SUPPORTS_VERTEX_TEXTURES && HAS_DISPLACEMENTMAP, 25114 emissiveMap: HAS_EMISSIVEMAP, 25115 normalMapObjectSpace: HAS_NORMALMAP && material.normalMapType === ObjectSpaceNormalMap, 25116 normalMapTangentSpace: HAS_NORMALMAP && material.normalMapType === TangentSpaceNormalMap, 25117 metalnessMap: HAS_METALNESSMAP, 25118 roughnessMap: HAS_ROUGHNESSMAP, 25119 anisotropy: HAS_ANISOTROPY, 25120 anisotropyMap: HAS_ANISOTROPYMAP, 25121 clearcoat: HAS_CLEARCOAT, 25122 clearcoatMap: HAS_CLEARCOATMAP, 25123 clearcoatNormalMap: HAS_CLEARCOAT_NORMALMAP, 25124 clearcoatRoughnessMap: HAS_CLEARCOAT_ROUGHNESSMAP, 25125 dispersion: HAS_DISPERSION, 25126 iridescence: HAS_IRIDESCENCE, 25127 iridescenceMap: HAS_IRIDESCENCEMAP, 25128 iridescenceThicknessMap: HAS_IRIDESCENCE_THICKNESSMAP, 25129 sheen: HAS_SHEEN, 25130 sheenColorMap: HAS_SHEEN_COLORMAP, 25131 sheenRoughnessMap: HAS_SHEEN_ROUGHNESSMAP, 25132 specularMap: HAS_SPECULARMAP, 25133 specularColorMap: HAS_SPECULAR_COLORMAP, 25134 specularIntensityMap: HAS_SPECULAR_INTENSITYMAP, 25135 transmission: HAS_TRANSMISSION, 25136 transmissionMap: HAS_TRANSMISSIONMAP, 25137 thicknessMap: HAS_THICKNESSMAP, 25138 gradientMap: HAS_GRADIENTMAP, 25139 opaque: material.transparent === false && material.blending === NormalBlending && material.alphaToCoverage === false, 25140 alphaMap: HAS_ALPHAMAP, 25141 alphaTest: HAS_ALPHATEST, 25142 alphaHash: HAS_ALPHAHASH, 25143 combine: material.combine, 25144 // 25145 mapUv: HAS_MAP && getChannel(material.map.channel), 25146 aoMapUv: HAS_AOMAP && getChannel(material.aoMap.channel), 25147 lightMapUv: HAS_LIGHTMAP && getChannel(material.lightMap.channel), 25148 bumpMapUv: HAS_BUMPMAP && getChannel(material.bumpMap.channel), 25149 normalMapUv: HAS_NORMALMAP && getChannel(material.normalMap.channel), 25150 displacementMapUv: HAS_DISPLACEMENTMAP && getChannel(material.displacementMap.channel), 25151 emissiveMapUv: HAS_EMISSIVEMAP && getChannel(material.emissiveMap.channel), 25152 metalnessMapUv: HAS_METALNESSMAP && getChannel(material.metalnessMap.channel), 25153 roughnessMapUv: HAS_ROUGHNESSMAP && getChannel(material.roughnessMap.channel), 25154 anisotropyMapUv: HAS_ANISOTROPYMAP && getChannel(material.anisotropyMap.channel), 25155 clearcoatMapUv: HAS_CLEARCOATMAP && getChannel(material.clearcoatMap.channel), 25156 clearcoatNormalMapUv: HAS_CLEARCOAT_NORMALMAP && getChannel(material.clearcoatNormalMap.channel), 25157 clearcoatRoughnessMapUv: HAS_CLEARCOAT_ROUGHNESSMAP && getChannel(material.clearcoatRoughnessMap.channel), 25158 iridescenceMapUv: HAS_IRIDESCENCEMAP && getChannel(material.iridescenceMap.channel), 25159 iridescenceThicknessMapUv: HAS_IRIDESCENCE_THICKNESSMAP && getChannel(material.iridescenceThicknessMap.channel), 25160 sheenColorMapUv: HAS_SHEEN_COLORMAP && getChannel(material.sheenColorMap.channel), 25161 sheenRoughnessMapUv: HAS_SHEEN_ROUGHNESSMAP && getChannel(material.sheenRoughnessMap.channel), 25162 specularMapUv: HAS_SPECULARMAP && getChannel(material.specularMap.channel), 25163 specularColorMapUv: HAS_SPECULAR_COLORMAP && getChannel(material.specularColorMap.channel), 25164 specularIntensityMapUv: HAS_SPECULAR_INTENSITYMAP && getChannel(material.specularIntensityMap.channel), 25165 transmissionMapUv: HAS_TRANSMISSIONMAP && getChannel(material.transmissionMap.channel), 25166 thicknessMapUv: HAS_THICKNESSMAP && getChannel(material.thicknessMap.channel), 25167 alphaMapUv: HAS_ALPHAMAP && getChannel(material.alphaMap.channel), 25168 // 25169 vertexTangents: !!geometry.attributes.tangent && (HAS_NORMALMAP || HAS_ANISOTROPY), 25170 vertexColors: material.vertexColors, 25171 vertexAlphas: material.vertexColors === true && !!geometry.attributes.color && geometry.attributes.color.itemSize === 4, 25172 pointsUvs: object.isPoints === true && !!geometry.attributes.uv && (HAS_MAP || HAS_ALPHAMAP), 25173 fog: !!fog, 25174 useFog: material.fog === true, 25175 fogExp2: !!fog && fog.isFogExp2, 25176 flatShading: material.flatShading === true, 25177 sizeAttenuation: material.sizeAttenuation === true, 25178 logarithmicDepthBuffer: logarithmicDepthBuffer, 25179 reverseDepthBuffer: reverseDepthBuffer, 25180 skinning: object.isSkinnedMesh === true, 25181 morphTargets: geometry.morphAttributes.position !== undefined, 25182 morphNormals: geometry.morphAttributes.normal !== undefined, 25183 morphColors: geometry.morphAttributes.color !== undefined, 25184 morphTargetsCount: morphTargetsCount, 25185 morphTextureStride: morphTextureStride, 25186 numDirLights: lights.directional.length, 25187 numPointLights: lights.point.length, 25188 numSpotLights: lights.spot.length, 25189 numSpotLightMaps: lights.spotLightMap.length, 25190 numRectAreaLights: lights.rectArea.length, 25191 numHemiLights: lights.hemi.length, 25192 numDirLightShadows: lights.directionalShadowMap.length, 25193 numPointLightShadows: lights.pointShadowMap.length, 25194 numSpotLightShadows: lights.spotShadowMap.length, 25195 numSpotLightShadowsWithMaps: lights.numSpotLightShadowsWithMaps, 25196 numLightProbes: lights.numLightProbes, 25197 numClippingPlanes: clipping.numPlanes, 25198 numClipIntersection: clipping.numIntersection, 25199 dithering: material.dithering, 25200 shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0, 25201 shadowMapType: renderer.shadowMap.type, 25202 toneMapping: toneMapping, 25203 decodeVideoTexture: HAS_MAP && material.map.isVideoTexture === true && ColorManagement.getTransfer(material.map.colorSpace) === SRGBTransfer, 25204 decodeVideoTextureEmissive: HAS_EMISSIVEMAP && material.emissiveMap.isVideoTexture === true && ColorManagement.getTransfer(material.emissiveMap.colorSpace) === SRGBTransfer, 25205 premultipliedAlpha: material.premultipliedAlpha, 25206 doubleSided: material.side === DoubleSide, 25207 flipSided: material.side === BackSide, 25208 useDepthPacking: material.depthPacking >= 0, 25209 depthPacking: material.depthPacking || 0, 25210 index0AttributeName: material.index0AttributeName, 25211 extensionClipCullDistance: HAS_EXTENSIONS && material.extensions.clipCullDistance === true && extensions.has('WEBGL_clip_cull_distance'), 25212 extensionMultiDraw: (HAS_EXTENSIONS && material.extensions.multiDraw === true || IS_BATCHEDMESH) && extensions.has('WEBGL_multi_draw'), 25213 rendererExtensionParallelShaderCompile: extensions.has('KHR_parallel_shader_compile'), 25214 customProgramCacheKey: material.customProgramCacheKey() 25215 }; 25216 // the usage of getChannel() determines the active texture channels for this shader 25217 parameters.vertexUv1s = _activeChannels.has(1); 25218 parameters.vertexUv2s = _activeChannels.has(2); 25219 parameters.vertexUv3s = _activeChannels.has(3); 25220 _activeChannels.clear(); 25221 return parameters; 25222 } 25223 function getProgramCacheKey(parameters) { 25224 const array = []; 25225 if (parameters.shaderID) { 25226 array.push(parameters.shaderID); 25227 } else { 25228 array.push(parameters.customVertexShaderID); 25229 array.push(parameters.customFragmentShaderID); 25230 } 25231 if (parameters.defines !== undefined) { 25232 for(const name in parameters.defines){ 25233 array.push(name); 25234 array.push(parameters.defines[name]); 25235 } 25236 } 25237 if (parameters.isRawShaderMaterial === false) { 25238 getProgramCacheKeyParameters(array, parameters); 25239 getProgramCacheKeyBooleans(array, parameters); 25240 array.push(renderer.outputColorSpace); 25241 } 25242 array.push(parameters.customProgramCacheKey); 25243 return array.join(); 25244 } 25245 function getProgramCacheKeyParameters(array, parameters) { 25246 array.push(parameters.precision); 25247 array.push(parameters.outputColorSpace); 25248 array.push(parameters.envMapMode); 25249 array.push(parameters.envMapCubeUVHeight); 25250 array.push(parameters.mapUv); 25251 array.push(parameters.alphaMapUv); 25252 array.push(parameters.lightMapUv); 25253 array.push(parameters.aoMapUv); 25254 array.push(parameters.bumpMapUv); 25255 array.push(parameters.normalMapUv); 25256 array.push(parameters.displacementMapUv); 25257 array.push(parameters.emissiveMapUv); 25258 array.push(parameters.metalnessMapUv); 25259 array.push(parameters.roughnessMapUv); 25260 array.push(parameters.anisotropyMapUv); 25261 array.push(parameters.clearcoatMapUv); 25262 array.push(parameters.clearcoatNormalMapUv); 25263 array.push(parameters.clearcoatRoughnessMapUv); 25264 array.push(parameters.iridescenceMapUv); 25265 array.push(parameters.iridescenceThicknessMapUv); 25266 array.push(parameters.sheenColorMapUv); 25267 array.push(parameters.sheenRoughnessMapUv); 25268 array.push(parameters.specularMapUv); 25269 array.push(parameters.specularColorMapUv); 25270 array.push(parameters.specularIntensityMapUv); 25271 array.push(parameters.transmissionMapUv); 25272 array.push(parameters.thicknessMapUv); 25273 array.push(parameters.combine); 25274 array.push(parameters.fogExp2); 25275 array.push(parameters.sizeAttenuation); 25276 array.push(parameters.morphTargetsCount); 25277 array.push(parameters.morphAttributeCount); 25278 array.push(parameters.numDirLights); 25279 array.push(parameters.numPointLights); 25280 array.push(parameters.numSpotLights); 25281 array.push(parameters.numSpotLightMaps); 25282 array.push(parameters.numHemiLights); 25283 array.push(parameters.numRectAreaLights); 25284 array.push(parameters.numDirLightShadows); 25285 array.push(parameters.numPointLightShadows); 25286 array.push(parameters.numSpotLightShadows); 25287 array.push(parameters.numSpotLightShadowsWithMaps); 25288 array.push(parameters.numLightProbes); 25289 array.push(parameters.shadowMapType); 25290 array.push(parameters.toneMapping); 25291 array.push(parameters.numClippingPlanes); 25292 array.push(parameters.numClipIntersection); 25293 array.push(parameters.depthPacking); 25294 } 25295 function getProgramCacheKeyBooleans(array, parameters) { 25296 _programLayers.disableAll(); 25297 if (parameters.supportsVertexTextures) _programLayers.enable(0); 25298 if (parameters.instancing) _programLayers.enable(1); 25299 if (parameters.instancingColor) _programLayers.enable(2); 25300 if (parameters.instancingMorph) _programLayers.enable(3);
vendor: 4,588 bytes, lines 25301-25397
25301 if (parameters.matcap) _programLayers.enable(4); 25302 if (parameters.envMap) _programLayers.enable(5); 25303 if (parameters.normalMapObjectSpace) _programLayers.enable(6); 25304 if (parameters.normalMapTangentSpace) _programLayers.enable(7); 25305 if (parameters.clearcoat) _programLayers.enable(8); 25306 if (parameters.iridescence) _programLayers.enable(9); 25307 if (parameters.alphaTest) _programLayers.enable(10); 25308 if (parameters.vertexColors) _programLayers.enable(11); 25309 if (parameters.vertexAlphas) _programLayers.enable(12); 25310 if (parameters.vertexUv1s) _programLayers.enable(13); 25311 if (parameters.vertexUv2s) _programLayers.enable(14); 25312 if (parameters.vertexUv3s) _programLayers.enable(15); 25313 if (parameters.vertexTangents) _programLayers.enable(16); 25314 if (parameters.anisotropy) _programLayers.enable(17); 25315 if (parameters.alphaHash) _programLayers.enable(18); 25316 if (parameters.batching) _programLayers.enable(19); 25317 if (parameters.dispersion) _programLayers.enable(20); 25318 if (parameters.batchingColor) _programLayers.enable(21); 25319 array.push(_programLayers.mask); 25320 _programLayers.disableAll(); 25321 if (parameters.fog) _programLayers.enable(0); 25322 if (parameters.useFog) _programLayers.enable(1); 25323 if (parameters.flatShading) _programLayers.enable(2); 25324 if (parameters.logarithmicDepthBuffer) _programLayers.enable(3); 25325 if (parameters.reverseDepthBuffer) _programLayers.enable(4); 25326 if (parameters.skinning) _programLayers.enable(5); 25327 if (parameters.morphTargets) _programLayers.enable(6); 25328 if (parameters.morphNormals) _programLayers.enable(7); 25329 if (parameters.morphColors) _programLayers.enable(8); 25330 if (parameters.premultipliedAlpha) _programLayers.enable(9); 25331 if (parameters.shadowMapEnabled) _programLayers.enable(10); 25332 if (parameters.doubleSided) _programLayers.enable(11); 25333 if (parameters.flipSided) _programLayers.enable(12); 25334 if (parameters.useDepthPacking) _programLayers.enable(13); 25335 if (parameters.dithering) _programLayers.enable(14); 25336 if (parameters.transmission) _programLayers.enable(15); 25337 if (parameters.sheen) _programLayers.enable(16); 25338 if (parameters.opaque) _programLayers.enable(17); 25339 if (parameters.pointsUvs) _programLayers.enable(18); 25340 if (parameters.decodeVideoTexture) _programLayers.enable(19); 25341 if (parameters.decodeVideoTextureEmissive) _programLayers.enable(20); 25342 if (parameters.alphaToCoverage) _programLayers.enable(21); 25343 array.push(_programLayers.mask); 25344 } 25345 function getUniforms(material) { 25346 const shaderID = shaderIDs[material.type]; 25347 let uniforms; 25348 if (shaderID) { 25349 const shader = ShaderLib[shaderID]; 25350 uniforms = UniformsUtils.clone(shader.uniforms); 25351 } else { 25352 uniforms = material.uniforms; 25353 } 25354 return uniforms; 25355 } 25356 function acquireProgram(parameters, cacheKey) { 25357 let program; 25358 // Check if code has been already compiled 25359 for(let p = 0, pl = programs.length; p < pl; p++){ 25360 const preexistingProgram = programs[p]; 25361 if (preexistingProgram.cacheKey === cacheKey) { 25362 program = preexistingProgram; 25363 ++program.usedTimes; 25364 break; 25365 } 25366 } 25367 if (program === undefined) { 25368 program = new WebGLProgram(renderer, cacheKey, parameters, bindingStates); 25369 programs.push(program); 25370 } 25371 return program; 25372 } 25373 function releaseProgram(program) { 25374 if (--program.usedTimes === 0) { 25375 // Remove from unordered set 25376 const i = programs.indexOf(program); 25377 programs[i] = programs[programs.length - 1]; 25378 programs.pop(); 25379 // Free WebGL resources 25380 program.destroy(); 25381 } 25382 } 25383 function releaseShaderCache(material) { 25384 _customShaders.remove(material); 25385 } 25386 function dispose() { 25387 _customShaders.dispose(); 25388 } 25389 return { 25390 getParameters: getParameters, 25391 getProgramCacheKey: getProgramCacheKey, 25392 getUniforms: getUniforms, 25393 acquireProgram: acquireProgram, 25394 releaseProgram: releaseProgram, 25395 releaseShaderCache: releaseShaderCache, 25396 // Exposed for resource monitoring & error feedback via renderer.info: 25397 programs: programs,
vendor: 5,529 bytes, lines 25398-25566
25398 dispose: dispose 25399 }; 25400 } 25401 function WebGLProperties() { 25402 let properties = new WeakMap(); 25403 function has(object) { 25404 return properties.has(object); 25405 } 25406 function get(object) { 25407 let map = properties.get(object); 25408 if (map === undefined) { 25409 map = {}; 25410 properties.set(object, map); 25411 } 25412 return map; 25413 } 25414 function remove(object) { 25415 properties.delete(object); 25416 } 25417 function update(object, key, value) { 25418 properties.get(object)[key] = value; 25419 } 25420 function dispose() { 25421 properties = new WeakMap(); 25422 } 25423 return { 25424 has: has, 25425 get: get, 25426 remove: remove, 25427 update: update, 25428 dispose: dispose 25429 }; 25430 } 25431 function painterSortStable(a, b) { 25432 if (a.groupOrder !== b.groupOrder) { 25433 return a.groupOrder - b.groupOrder; 25434 } else if (a.renderOrder !== b.renderOrder) { 25435 return a.renderOrder - b.renderOrder; 25436 } else if (a.material.id !== b.material.id) { 25437 return a.material.id - b.material.id; 25438 } else if (a.z !== b.z) { 25439 return a.z - b.z; 25440 } else { 25441 return a.id - b.id; 25442 } 25443 } 25444 function reversePainterSortStable(a, b) { 25445 if (a.groupOrder !== b.groupOrder) { 25446 return a.groupOrder - b.groupOrder; 25447 } else if (a.renderOrder !== b.renderOrder) { 25448 return a.renderOrder - b.renderOrder; 25449 } else if (a.z !== b.z) { 25450 return b.z - a.z; 25451 } else { 25452 return a.id - b.id; 25453 } 25454 } 25455 function WebGLRenderList() { 25456 const renderItems = []; 25457 let renderItemsIndex = 0; 25458 const opaque = []; 25459 const transmissive = []; 25460 const transparent = []; 25461 function init() { 25462 renderItemsIndex = 0; 25463 opaque.length = 0; 25464 transmissive.length = 0; 25465 transparent.length = 0; 25466 } 25467 function getNextRenderItem(object, geometry, material, groupOrder, z, group) { 25468 let renderItem = renderItems[renderItemsIndex]; 25469 if (renderItem === undefined) { 25470 renderItem = { 25471 id: object.id, 25472 object: object, 25473 geometry: geometry, 25474 material: material, 25475 groupOrder: groupOrder, 25476 renderOrder: object.renderOrder, 25477 z: z, 25478 group: group 25479 }; 25480 renderItems[renderItemsIndex] = renderItem; 25481 } else { 25482 renderItem.id = object.id; 25483 renderItem.object = object; 25484 renderItem.geometry = geometry; 25485 renderItem.material = material; 25486 renderItem.groupOrder = groupOrder; 25487 renderItem.renderOrder = object.renderOrder; 25488 renderItem.z = z; 25489 renderItem.group = group; 25490 } 25491 renderItemsIndex++; 25492 return renderItem; 25493 } 25494 function push(object, geometry, material, groupOrder, z, group) { 25495 const renderItem = getNextRenderItem(object, geometry, material, groupOrder, z, group); 25496 if (material.transmission > 0.0) { 25497 transmissive.push(renderItem); 25498 } else if (material.transparent === true) { 25499 transparent.push(renderItem); 25500 } else { 25501 opaque.push(renderItem); 25502 } 25503 } 25504 function unshift(object, geometry, material, groupOrder, z, group) { 25505 const renderItem = getNextRenderItem(object, geometry, material, groupOrder, z, group); 25506 if (material.transmission > 0.0) { 25507 transmissive.unshift(renderItem); 25508 } else if (material.transparent === true) { 25509 transparent.unshift(renderItem); 25510 } else { 25511 opaque.unshift(renderItem); 25512 } 25513 } 25514 function sort(customOpaqueSort, customTransparentSort) { 25515 if (opaque.length > 1) opaque.sort(customOpaqueSort || painterSortStable); 25516 if (transmissive.length > 1) transmissive.sort(customTransparentSort || reversePainterSortStable); 25517 if (transparent.length > 1) transparent.sort(customTransparentSort || reversePainterSortStable); 25518 } 25519 function finish() { 25520 // Clear references from inactive renderItems in the list 25521 for(let i = renderItemsIndex, il = renderItems.length; i < il; i++){ 25522 const renderItem = renderItems[i]; 25523 if (renderItem.id === null) break; 25524 renderItem.id = null; 25525 renderItem.object = null; 25526 renderItem.geometry = null; 25527 renderItem.material = null; 25528 renderItem.group = null; 25529 } 25530 } 25531 return { 25532 opaque: opaque, 25533 transmissive: transmissive, 25534 transparent: transparent, 25535 init: init, 25536 push: push, 25537 unshift: unshift, 25538 finish: finish, 25539 sort: sort 25540 }; 25541 } 25542 function WebGLRenderLists() { 25543 let lists = new WeakMap(); 25544 function get(scene, renderCallDepth) { 25545 const listArray = lists.get(scene); 25546 let list; 25547 if (listArray === undefined) { 25548 list = new WebGLRenderList(); 25549 lists.set(scene, [ 25550 list 25551 ]); 25552 } else { 25553 if (renderCallDepth >= listArray.length) { 25554 list = new WebGLRenderList(); 25555 listArray.push(list); 25556 } else { 25557 list = listArray[renderCallDepth]; 25558 } 25559 } 25560 return list; 25561 } 25562 function dispose() { 25563 lists = new WeakMap(); 25564 } 25565 return { 25566 get: get,
vendor: 9,531 bytes, lines 25567-25804
25567 dispose: dispose 25568 }; 25569 } 25570 function UniformsCache() { 25571 const lights = {}; 25572 return { 25573 get: function(light) { 25574 if (lights[light.id] !== undefined) { 25575 return lights[light.id]; 25576 } 25577 let uniforms; 25578 switch(light.type){ 25579 case 'DirectionalLight': 25580 uniforms = { 25581 direction: new Vector3(), 25582 color: new Color() 25583 }; 25584 break; 25585 case 'SpotLight': 25586 uniforms = { 25587 position: new Vector3(), 25588 direction: new Vector3(), 25589 color: new Color(), 25590 distance: 0, 25591 coneCos: 0, 25592 penumbraCos: 0, 25593 decay: 0 25594 }; 25595 break; 25596 case 'PointLight': 25597 uniforms = { 25598 position: new Vector3(), 25599 color: new Color(), 25600 distance: 0, 25601 decay: 0 25602 }; 25603 break; 25604 case 'HemisphereLight': 25605 uniforms = { 25606 direction: new Vector3(), 25607 skyColor: new Color(), 25608 groundColor: new Color() 25609 }; 25610 break; 25611 case 'RectAreaLight': 25612 uniforms = { 25613 color: new Color(), 25614 position: new Vector3(), 25615 halfWidth: new Vector3(), 25616 halfHeight: new Vector3() 25617 }; 25618 break; 25619 } 25620 lights[light.id] = uniforms; 25621 return uniforms; 25622 } 25623 }; 25624 } 25625 function ShadowUniformsCache() { 25626 const lights = {}; 25627 return { 25628 get: function(light) { 25629 if (lights[light.id] !== undefined) { 25630 return lights[light.id]; 25631 } 25632 let uniforms; 25633 switch(light.type){ 25634 case 'DirectionalLight': 25635 uniforms = { 25636 shadowIntensity: 1, 25637 shadowBias: 0, 25638 shadowNormalBias: 0, 25639 shadowRadius: 1, 25640 shadowMapSize: new Vector2() 25641 }; 25642 break; 25643 case 'SpotLight': 25644 uniforms = { 25645 shadowIntensity: 1, 25646 shadowBias: 0, 25647 shadowNormalBias: 0, 25648 shadowRadius: 1, 25649 shadowMapSize: new Vector2() 25650 }; 25651 break; 25652 case 'PointLight': 25653 uniforms = { 25654 shadowIntensity: 1, 25655 shadowBias: 0, 25656 shadowNormalBias: 0, 25657 shadowRadius: 1, 25658 shadowMapSize: new Vector2(), 25659 shadowCameraNear: 1, 25660 shadowCameraFar: 1000 25661 }; 25662 break; 25663 } 25664 lights[light.id] = uniforms; 25665 return uniforms; 25666 } 25667 }; 25668 } 25669 let nextVersion = 0; 25670 function shadowCastingAndTexturingLightsFirst(lightA, lightB) { 25671 return (lightB.castShadow ? 2 : 0) - (lightA.castShadow ? 2 : 0) + (lightB.map ? 1 : 0) - (lightA.map ? 1 : 0); 25672 } 25673 function WebGLLights(extensions) { 25674 const cache = new UniformsCache(); 25675 const shadowCache = ShadowUniformsCache(); 25676 const state = { 25677 version: 0, 25678 hash: { 25679 directionalLength: -1, 25680 pointLength: -1, 25681 spotLength: -1, 25682 rectAreaLength: -1, 25683 hemiLength: -1, 25684 numDirectionalShadows: -1, 25685 numPointShadows: -1, 25686 numSpotShadows: -1, 25687 numSpotMaps: -1, 25688 numLightProbes: -1 25689 }, 25690 ambient: [ 25691 0, 25692 0, 25693 0 25694 ], 25695 probe: [], 25696 directional: [], 25697 directionalShadow: [], 25698 directionalShadowMap: [], 25699 directionalShadowMatrix: [], 25700 spot: [], 25701 spotLightMap: [], 25702 spotShadow: [], 25703 spotShadowMap: [], 25704 spotLightMatrix: [], 25705 rectArea: [], 25706 rectAreaLTC1: null, 25707 rectAreaLTC2: null, 25708 point: [], 25709 pointShadow: [], 25710 pointShadowMap: [], 25711 pointShadowMatrix: [], 25712 hemi: [], 25713 numSpotLightShadowsWithMaps: 0, 25714 numLightProbes: 0 25715 }; 25716 for(let i = 0; i < 9; i++)state.probe.push(new Vector3()); 25717 const vector3 = new Vector3(); 25718 const matrix4 = new Matrix4(); 25719 const matrix42 = new Matrix4(); 25720 function setup(lights) { 25721 let r = 0, g = 0, b = 0; 25722 for(let i = 0; i < 9; i++)state.probe[i].set(0, 0, 0); 25723 let directionalLength = 0; 25724 let pointLength = 0; 25725 let spotLength = 0; 25726 let rectAreaLength = 0; 25727 let hemiLength = 0; 25728 let numDirectionalShadows = 0; 25729 let numPointShadows = 0; 25730 let numSpotShadows = 0; 25731 let numSpotMaps = 0; 25732 let numSpotShadowsWithMaps = 0; 25733 let numLightProbes = 0; 25734 // ordering : [shadow casting + map texturing, map texturing, shadow casting, none ] 25735 lights.sort(shadowCastingAndTexturingLightsFirst); 25736 for(let i = 0, l = lights.length; i < l; i++){ 25737 const light = lights[i]; 25738 const color = light.color; 25739 const intensity = light.intensity; 25740 const distance = light.distance; 25741 const shadowMap = light.shadow && light.shadow.map ? light.shadow.map.texture : null; 25742 if (light.isAmbientLight) { 25743 r += color.r * intensity; 25744 g += color.g * intensity; 25745 b += color.b * intensity; 25746 } else if (light.isLightProbe) { 25747 for(let j = 0; j < 9; j++){ 25748 state.probe[j].addScaledVector(light.sh.coefficients[j], intensity); 25749 } 25750 numLightProbes++; 25751 } else if (light.isDirectionalLight) { 25752 const uniforms = cache.get(light); 25753 uniforms.color.copy(light.color).multiplyScalar(light.intensity); 25754 if (light.castShadow) { 25755 const shadow = light.shadow; 25756 const shadowUniforms = shadowCache.get(light); 25757 shadowUniforms.shadowIntensity = shadow.intensity; 25758 shadowUniforms.shadowBias = shadow.bias; 25759 shadowUniforms.shadowNormalBias = shadow.normalBias; 25760 shadowUniforms.shadowRadius = shadow.radius; 25761 shadowUniforms.shadowMapSize = shadow.mapSize; 25762 state.directionalShadow[directionalLength] = shadowUniforms; 25763 state.directionalShadowMap[directionalLength] = shadowMap; 25764 state.directionalShadowMatrix[directionalLength] = light.shadow.matrix; 25765 numDirectionalShadows++; 25766 } 25767 state.directional[directionalLength] = uniforms; 25768 directionalLength++; 25769 } else if (light.isSpotLight) { 25770 const uniforms = cache.get(light); 25771 uniforms.position.setFromMatrixPosition(light.matrixWorld); 25772 uniforms.color.copy(color).multiplyScalar(intensity); 25773 uniforms.distance = distance; 25774 uniforms.coneCos = Math.cos(light.angle); 25775 uniforms.penumbraCos = Math.cos(light.angle * (1 - light.penumbra)); 25776 uniforms.decay = light.decay; 25777 state.spot[spotLength] = uniforms; 25778 const shadow = light.shadow; 25779 if (light.map) { 25780 state.spotLightMap[numSpotMaps] = light.map; 25781 numSpotMaps++; 25782 // make sure the lightMatrix is up to date 25783 // TODO : do it if required only 25784 shadow.updateMatrices(light); 25785 if (light.castShadow) numSpotShadowsWithMaps++; 25786 } 25787 state.spotLightMatrix[spotLength] = shadow.matrix; 25788 if (light.castShadow) { 25789 const shadowUniforms = shadowCache.get(light); 25790 shadowUniforms.shadowIntensity = shadow.intensity; 25791 shadowUniforms.shadowBias = shadow.bias; 25792 shadowUniforms.shadowNormalBias = shadow.normalBias; 25793 shadowUniforms.shadowRadius = shadow.radius; 25794 shadowUniforms.shadowMapSize = shadow.mapSize; 25795 state.spotShadow[spotLength] = shadowUniforms; 25796 state.spotShadowMap[spotLength] = shadowMap; 25797 numSpotShadows++; 25798 } 25799 spotLength++; 25800 } else if (light.isRectAreaLight) { 25801 const uniforms = cache.get(light); 25802 uniforms.color.copy(color).multiplyScalar(intensity); 25803 uniforms.halfWidth.set(light.width * 0.5, 0.0, 0.0); 25804 uniforms.halfHeight.set(0.0, light.height * 0.5, 0.0
vendor: 4,272 bytes, lines 25804-25877
25804); 25805 state.rectArea[rectAreaLength] = uniforms; 25806 rectAreaLength++; 25807 } else if (light.isPointLight) { 25808 const uniforms = cache.get(light); 25809 uniforms.color.copy(light.color).multiplyScalar(light.intensity); 25810 uniforms.distance = light.distance; 25811 uniforms.decay = light.decay; 25812 if (light.castShadow) { 25813 const shadow = light.shadow; 25814 const shadowUniforms = shadowCache.get(light); 25815 shadowUniforms.shadowIntensity = shadow.intensity; 25816 shadowUniforms.shadowBias = shadow.bias; 25817 shadowUniforms.shadowNormalBias = shadow.normalBias; 25818 shadowUniforms.shadowRadius = shadow.radius; 25819 shadowUniforms.shadowMapSize = shadow.mapSize; 25820 shadowUniforms.shadowCameraNear = shadow.camera.near; 25821 shadowUniforms.shadowCameraFar = shadow.camera.far; 25822 state.pointShadow[pointLength] = shadowUniforms; 25823 state.pointShadowMap[pointLength] = shadowMap; 25824 state.pointShadowMatrix[pointLength] = light.shadow.matrix; 25825 numPointShadows++; 25826 } 25827 state.point[pointLength] = uniforms; 25828 pointLength++; 25829 } else if (light.isHemisphereLight) { 25830 const uniforms = cache.get(light); 25831 uniforms.skyColor.copy(light.color).multiplyScalar(intensity); 25832 uniforms.groundColor.copy(light.groundColor).multiplyScalar(intensity); 25833 state.hemi[hemiLength] = uniforms; 25834 hemiLength++; 25835 } 25836 } 25837 if (rectAreaLength > 0) { 25838 if (extensions.has('OES_texture_float_linear') === true) { 25839 state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1; 25840 state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2; 25841 } else { 25842 state.rectAreaLTC1 = UniformsLib.LTC_HALF_1; 25843 state.rectAreaLTC2 = UniformsLib.LTC_HALF_2; 25844 } 25845 } 25846 state.ambient[0] = r; 25847 state.ambient[1] = g; 25848 state.ambient[2] = b; 25849 const hash = state.hash; 25850 if (hash.directionalLength !== directionalLength || hash.pointLength !== pointLength || hash.spotLength !== spotLength || hash.rectAreaLength !== rectAreaLength || hash.hemiLength !== hemiLength || hash.numDirectionalShadows !== numDirectionalShadows || hash.numPointShadows !== numPointShadows || hash.numSpotShadows !== numSpotShadows || hash.numSpotMaps !== numSpotMaps || hash.numLightProbes !== numLightProbes) { 25851 state.directional.length = directionalLength; 25852 state.spot.length = spotLength; 25853 state.rectArea.length = rectAreaLength; 25854 state.point.length = pointLength; 25855 state.hemi.length = hemiLength; 25856 state.directionalShadow.length = numDirectionalShadows; 25857 state.directionalShadowMap.length = numDirectionalShadows; 25858 state.pointShadow.length = numPointShadows; 25859 state.pointShadowMap.length = numPointShadows; 25860 state.spotShadow.length = numSpotShadows; 25861 state.spotShadowMap.length = numSpotShadows; 25862 state.directionalShadowMatrix.length = numDirectionalShadows; 25863 state.pointShadowMatrix.length = numPointShadows; 25864 state.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps; 25865 state.spotLightMap.length = numSpotMaps; 25866 state.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps; 25867 state.numLightProbes = numLightProbes; 25868 hash.directionalLength = directionalLength; 25869 hash.pointLength = pointLength; 25870 hash.spotLength = spotLength; 25871 hash.rectAreaLength = rectAreaLength; 25872 hash.hemiLength = hemiLength; 25873 hash.numDirectionalShadows = numDirectionalShadows; 25874 hash.numPointShadows = numPointShadows; 25875 hash.numSpotShadows = numSpotShadows; 25876 hash.numSpotMaps = numSpotMaps; 25877 hash.numLightProbes = numLightProbes;
vendor: 4,372 bytes, lines 25878-25987
25878 state.version = nextVersion++; 25879 } 25880 } 25881 function setupView(lights, camera) { 25882 let directionalLength = 0; 25883 let pointLength = 0; 25884 let spotLength = 0; 25885 let rectAreaLength = 0; 25886 let hemiLength = 0; 25887 const viewMatrix = camera.matrixWorldInverse; 25888 for(let i = 0, l = lights.length; i < l; i++){ 25889 const light = lights[i]; 25890 if (light.isDirectionalLight) { 25891 const uniforms = state.directional[directionalLength]; 25892 uniforms.direction.setFromMatrixPosition(light.matrixWorld); 25893 vector3.setFromMatrixPosition(light.target.matrixWorld); 25894 uniforms.direction.sub(vector3); 25895 uniforms.direction.transformDirection(viewMatrix); 25896 directionalLength++; 25897 } else if (light.isSpotLight) { 25898 const uniforms = state.spot[spotLength]; 25899 uniforms.position.setFromMatrixPosition(light.matrixWorld); 25900 uniforms.position.applyMatrix4(viewMatrix); 25901 uniforms.direction.setFromMatrixPosition(light.matrixWorld); 25902 vector3.setFromMatrixPosition(light.target.matrixWorld); 25903 uniforms.direction.sub(vector3); 25904 uniforms.direction.transformDirection(viewMatrix); 25905 spotLength++; 25906 } else if (light.isRectAreaLight) { 25907 const uniforms = state.rectArea[rectAreaLength]; 25908 uniforms.position.setFromMatrixPosition(light.matrixWorld); 25909 uniforms.position.applyMatrix4(viewMatrix); 25910 // extract local rotation of light to derive width/height half vectors 25911 matrix42.identity(); 25912 matrix4.copy(light.matrixWorld); 25913 matrix4.premultiply(viewMatrix); 25914 matrix42.extractRotation(matrix4); 25915 uniforms.halfWidth.set(light.width * 0.5, 0.0, 0.0); 25916 uniforms.halfHeight.set(0.0, light.height * 0.5, 0.0); 25917 uniforms.halfWidth.applyMatrix4(matrix42); 25918 uniforms.halfHeight.applyMatrix4(matrix42); 25919 rectAreaLength++; 25920 } else if (light.isPointLight) { 25921 const uniforms = state.point[pointLength]; 25922 uniforms.position.setFromMatrixPosition(light.matrixWorld); 25923 uniforms.position.applyMatrix4(viewMatrix); 25924 pointLength++; 25925 } else if (light.isHemisphereLight) { 25926 const uniforms = state.hemi[hemiLength]; 25927 uniforms.direction.setFromMatrixPosition(light.matrixWorld); 25928 uniforms.direction.transformDirection(viewMatrix); 25929 hemiLength++; 25930 } 25931 } 25932 } 25933 return { 25934 setup: setup, 25935 setupView: setupView, 25936 state: state 25937 }; 25938 } 25939 function WebGLRenderState(extensions) { 25940 const lights = new WebGLLights(extensions); 25941 const lightsArray = []; 25942 const shadowsArray = []; 25943 function init(camera) { 25944 state.camera = camera; 25945 lightsArray.length = 0; 25946 shadowsArray.length = 0; 25947 } 25948 function pushLight(light) { 25949 lightsArray.push(light); 25950 } 25951 function pushShadow(shadowLight) { 25952 shadowsArray.push(shadowLight); 25953 } 25954 function setupLights() { 25955 lights.setup(lightsArray); 25956 } 25957 function setupLightsView(camera) { 25958 lights.setupView(lightsArray, camera); 25959 } 25960 const state = { 25961 lightsArray: lightsArray, 25962 shadowsArray: shadowsArray, 25963 camera: null, 25964 lights: lights, 25965 transmissionRenderTarget: {} 25966 }; 25967 return { 25968 init: init, 25969 state: state, 25970 setupLights: setupLights, 25971 setupLightsView: setupLightsView, 25972 pushLight: pushLight, 25973 pushShadow: pushShadow 25974 }; 25975 } 25976 function WebGLRenderStates(extensions) { 25977 let renderStates = new WeakMap(); 25978 function get(scene, renderCallDepth = 0) { 25979 const renderStateArray = renderStates.get(scene); 25980 let renderState; 25981 if (renderStateArray === undefined) { 25982 renderState = new WebGLRenderState(extensions); 25983 renderStates.set(scene, [ 25984 renderState 25985 ]); 25986 } else { 25987 if (renderCallDepth >
vendor: 6,279 bytes, lines 25987-26110
25987= renderStateArray.length) { 25988 renderState = new WebGLRenderState(extensions); 25989 renderStateArray.push(renderState); 25990 } else { 25991 renderState = renderStateArray[renderCallDepth]; 25992 } 25993 } 25994 return renderState; 25995 } 25996 function dispose() { 25997 renderStates = new WeakMap(); 25998 } 25999 return { 26000 get: get, 26001 dispose: dispose 26002 }; 26003 } 26004 const vertex = "void main() {\n\tgl_Position = vec4( position, 1.0 );\n}"; 26005 const fragment = "uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radius;\n#include <packing>\nvoid main() {\n\tconst float samples = float( VSM_SAMPLES );\n\tfloat mean = 0.0;\n\tfloat squared_mean = 0.0;\n\tfloat uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 );\n\tfloat uvStart = samples <= 1.0 ? 0.0 : - 1.0;\n\tfor ( float i = 0.0; i < samples; i ++ ) {\n\t\tfloat uvOffset = uvStart + i * uvStride;\n\t\t#ifdef HORIZONTAL_PASS\n\t\t\tvec2 distribution = unpackRGBATo2Half( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ) );\n\t\t\tmean += distribution.x;\n\t\t\tsquared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n\t\t#else\n\t\t\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ) );\n\t\t\tmean += depth;\n\t\t\tsquared_mean += depth * depth;\n\t\t#endif\n\t}\n\tmean = mean / samples;\n\tsquared_mean = squared_mean / samples;\n\tfloat std_dev = sqrt( squared_mean - mean * mean );\n\tgl_FragColor = pack2HalfToRGBA( vec2( mean, std_dev ) );\n}"; 26006 function WebGLShadowMap(renderer, objects, capabilities) { 26007 let _frustum = new Frustum(); 26008 const _shadowMapSize = new Vector2(), _viewportSize = new Vector2(), _viewport = new Vector4(), _depthMaterial = new MeshDepthMaterial({ 26009 depthPacking: RGBADepthPacking 26010 }), _distanceMaterial = new MeshDistanceMaterial(), _materialCache = {}, _maxTextureSize = capabilities.maxTextureSize; 26011 const shadowSide = { 26012 [FrontSide]: BackSide, 26013 [BackSide]: FrontSide, 26014 [DoubleSide]: DoubleSide 26015 }; 26016 const shadowMaterialVertical = new ShaderMaterial({ 26017 defines: { 26018 VSM_SAMPLES: 8 26019 }, 26020 uniforms: { 26021 shadow_pass: { 26022 value: null 26023 }, 26024 resolution: { 26025 value: new Vector2() 26026 }, 26027 radius: { 26028 value: 4.0 26029 } 26030 }, 26031 vertexShader: vertex, 26032 fragmentShader: fragment 26033 }); 26034 const shadowMaterialHorizontal = shadowMaterialVertical.clone(); 26035 shadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1; 26036 const fullScreenTri = new BufferGeometry(); 26037 fullScreenTri.setAttribute('position', new BufferAttribute(new Float32Array([ 26038 -1, 26039 -1, 26040 0.5, 26041 3, 26042 -1, 26043 0.5, 26044 -1, 26045 3, 26046 0.5 26047 ]), 3)); 26048 const fullScreenMesh = new Mesh(fullScreenTri, shadowMaterialVertical); 26049 const scope = this; 26050 this.enabled = false; 26051 this.autoUpdate = true; 26052 this.needsUpdate = false; 26053 this.type = PCFShadowMap; 26054 let _previousType = this.type; 26055 this.render = function(lights, scene, camera) { 26056 if (scope.enabled === false) return; 26057 if (scope.autoUpdate === false && scope.needsUpdate === false) return; 26058 if (lights.length === 0) return; 26059 const currentRenderTarget = renderer.getRenderTarget(); 26060 const activeCubeFace = renderer.getActiveCubeFace(); 26061 const activeMipmapLevel = renderer.getActiveMipmapLevel(); 26062 const _state = renderer.state; 26063 // Set GL state for depth map. 26064 _state.setBlending(NoBlending); 26065 _state.buffers.color.setClear(1, 1, 1, 1); 26066 _state.buffers.depth.setTest(true); 26067 _state.setScissorTest(false); 26068 // check for shadow map type changes 26069 const toVSM = _previousType !== VSMShadowMap && this.type === VSMShadowMap; 26070 const fromVSM = _previousType === VSMShadowMap && this.type !== VSMShadowMap; 26071 // render depth map 26072 for(let i = 0, il = lights.length; i < il; i++){ 26073 const light = lights[i]; 26074 const shadow = light.shadow; 26075 if (shadow === undefined) { 26076 console.warn('THREE.WebGLShadowMap:', light, 'has no shadow.'); 26077 continue; 26078 } 26079 if (shadow.autoUpdate === false && shadow.needsUpdate === false) continue; 26080 _shadowMapSize.copy(shadow.mapSize); 26081 const shadowFrameExtents = shadow.getFrameExtents(); 26082 _shadowMapSize.multiply(shadowFrameExtents); 26083 _viewportSize.copy(shadow.mapSize); 26084 if (_shadowMapSize.x > _maxTextureSize || _shadowMapSize.y > _maxTextureSize) { 26085 if (_shadowMapSize.x > _maxTextureSize) { 26086 _viewportSize.x = Math.floor(_maxTextureSize / shadowFrameExtents.x); 26087 _shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x; 26088 shadow.mapSize.x = _viewportSize.x; 26089 } 26090 if (_shadowMapSize.y > _maxTextureSize) { 26091 _viewportSize.y = Math.floor(_maxTextureSize / shadowFrameExtents.y); 26092 _shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y; 26093 shadow.mapSize.y = _viewportSize.y; 26094 } 26095 } 26096 if (shadow.map === null || toVSM === true || fromVSM === true) { 26097 const pars = this.type !== VSMShadowMap ? { 26098 minFilter: NearestFilter, 26099 magFilter: NearestFilter 26100 } : {}; 26101 if (shadow.map !== null) { 26102 shadow.map.dispose(); 26103 } 26104 shadow.map = new WebGLRenderTarget(_shadowMapSize.x, _shadowMapSize.y, pars); 26105 shadow.map.texture.name = light.name + '.shadowMap'; 26106 shadow.camera.updateProjectionMatrix(); 26107 } 26108 renderer.setRenderTarget(shadow.map); 26109 renderer.clear(); 26110 const viewportCount = shadow.getViewportCount();
vendor: 9,459 bytes, lines 26111-26291
26111 for(let vp = 0; vp < viewportCount; vp++){ 26112 const viewport = shadow.getViewport(vp); 26113 _viewport.set(_viewportSize.x * viewport.x, _viewportSize.y * viewport.y, _viewportSize.x * viewport.z, _viewportSize.y * viewport.w); 26114 _state.viewport(_viewport); 26115 shadow.updateMatrices(light, vp); 26116 _frustum = shadow.getFrustum(); 26117 renderObject(scene, camera, shadow.camera, light, this.type); 26118 } 26119 // do blur pass for VSM 26120 if (shadow.isPointLightShadow !== true && this.type === VSMShadowMap) { 26121 VSMPass(shadow, camera); 26122 } 26123 shadow.needsUpdate = false; 26124 } 26125 _previousType = this.type; 26126 scope.needsUpdate = false; 26127 renderer.setRenderTarget(currentRenderTarget, activeCubeFace, activeMipmapLevel); 26128 }; 26129 function VSMPass(shadow, camera) { 26130 const geometry = objects.update(fullScreenMesh); 26131 if (shadowMaterialVertical.defines.VSM_SAMPLES !== shadow.blurSamples) { 26132 shadowMaterialVertical.defines.VSM_SAMPLES = shadow.blurSamples; 26133 shadowMaterialHorizontal.defines.VSM_SAMPLES = shadow.blurSamples; 26134 shadowMaterialVertical.needsUpdate = true; 26135 shadowMaterialHorizontal.needsUpdate = true; 26136 } 26137 if (shadow.mapPass === null) { 26138 shadow.mapPass = new WebGLRenderTarget(_shadowMapSize.x, _shadowMapSize.y); 26139 } 26140 // vertical pass 26141 shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture; 26142 shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize; 26143 shadowMaterialVertical.uniforms.radius.value = shadow.radius; 26144 renderer.setRenderTarget(shadow.mapPass); 26145 renderer.clear(); 26146 renderer.renderBufferDirect(camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null); 26147 // horizontal pass 26148 shadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture; 26149 shadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize; 26150 shadowMaterialHorizontal.uniforms.radius.value = shadow.radius; 26151 renderer.setRenderTarget(shadow.map); 26152 renderer.clear(); 26153 renderer.renderBufferDirect(camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null); 26154 } 26155 function getDepthMaterial(object, material, light, type) { 26156 let result = null; 26157 const customMaterial = light.isPointLight === true ? object.customDistanceMaterial : object.customDepthMaterial; 26158 if (customMaterial !== undefined) { 26159 result = customMaterial; 26160 } else { 26161 result = light.isPointLight === true ? _distanceMaterial : _depthMaterial; 26162 if (renderer.localClippingEnabled && material.clipShadows === true && Array.isArray(material.clippingPlanes) && material.clippingPlanes.length !== 0 || material.displacementMap && material.displacementScale !== 0 || material.alphaMap && material.alphaTest > 0 || material.map && material.alphaTest > 0) { 26163 // in this case we need a unique material instance reflecting the 26164 // appropriate state 26165 const keyA = result.uuid, keyB = material.uuid; 26166 let materialsForVariant = _materialCache[keyA]; 26167 if (materialsForVariant === undefined) { 26168 materialsForVariant = {}; 26169 _materialCache[keyA] = materialsForVariant; 26170 } 26171 let cachedMaterial = materialsForVariant[keyB]; 26172 if (cachedMaterial === undefined) { 26173 cachedMaterial = result.clone(); 26174 materialsForVariant[keyB] = cachedMaterial; 26175 material.addEventListener('dispose', onMaterialDispose); 26176 } 26177 result = cachedMaterial; 26178 } 26179 } 26180 result.visible = material.visible; 26181 result.wireframe = material.wireframe; 26182 if (type === VSMShadowMap) { 26183 result.side = material.shadowSide !== null ? material.shadowSide : material.side; 26184 } else { 26185 result.side = material.shadowSide !== null ? material.shadowSide : shadowSide[material.side]; 26186 } 26187 result.alphaMap = material.alphaMap; 26188 result.alphaTest = material.alphaTest; 26189 result.map = material.map; 26190 result.clipShadows = material.clipShadows; 26191 result.clippingPlanes = material.clippingPlanes; 26192 result.clipIntersection = material.clipIntersection; 26193 result.displacementMap = material.displacementMap; 26194 result.displacementScale = material.displacementScale; 26195 result.displacementBias = material.displacementBias; 26196 result.wireframeLinewidth = material.wireframeLinewidth; 26197 result.linewidth = material.linewidth; 26198 if (light.isPointLight === true && result.isMeshDistanceMaterial === true) { 26199 const materialProperties = renderer.properties.get(result); 26200 materialProperties.light = light; 26201 } 26202 return result; 26203 } 26204 function renderObject(object, camera, shadowCamera, light, type) { 26205 if (object.visible === false) return; 26206 const visible = object.layers.test(camera.layers); 26207 if (visible && (object.isMesh || object.isLine || object.isPoints)) { 26208 if ((object.castShadow || object.receiveShadow && type === VSMShadowMap) && (!object.frustumCulled || _frustum.intersectsObject(object))) { 26209 object.modelViewMatrix.multiplyMatrices(shadowCamera.matrixWorldInverse, object.matrixWorld); 26210 const geometry = objects.update(object); 26211 const material = object.material; 26212 if (Array.isArray(material)) { 26213 const groups = geometry.groups; 26214 for(let k = 0, kl = groups.length; k < kl; k++){ 26215 const group = groups[k]; 26216 const groupMaterial = material[group.materialIndex]; 26217 if (groupMaterial && groupMaterial.visible) { 26218 const depthMaterial = getDepthMaterial(object, groupMaterial, light, type); 26219 object.onBeforeShadow(renderer, object, camera, shadowCamera, geometry, depthMaterial, group); 26220 renderer.renderBufferDirect(shadowCamera, null, geometry, depthMaterial, object, group); 26221 object.onAfterShadow(renderer, object, camera, shadowCamera, geometry, depthMaterial, group); 26222 } 26223 } 26224 } else if (material.visible) { 26225 const depthMaterial = getDepthMaterial(object, material, light, type); 26226 object.onBeforeShadow(renderer, object, camera, shadowCamera, geometry, depthMaterial, null); 26227 renderer.renderBufferDirect(shadowCamera, null, geometry, depthMaterial, object, null); 26228 object.onAfterShadow(renderer, object, camera, shadowCamera, geometry, depthMaterial, null); 26229 } 26230 } 26231 } 26232 const children = object.children; 26233 for(let i = 0, l = children.length; i < l; i++){ 26234 renderObject(children[i], camera, shadowCamera, light, type); 26235 } 26236 } 26237 function onMaterialDispose(event) { 26238 const material = event.target; 26239 material.removeEventListener('dispose', onMaterialDispose); 26240 // make sure to remove the unique distance/depth materials used for shadow map rendering 26241 for(const id in _materialCache){ 26242 const cache = _materialCache[id]; 26243 const uuid = event.target.uuid; 26244 if (uuid in cache) { 26245 const shadowMaterial = cache[uuid]; 26246 shadowMaterial.dispose(); 26247 delete cache[uuid]; 26248 } 26249 } 26250 } 26251 } 26252 const reversedFuncs = { 26253 [NeverDepth]: AlwaysDepth, 26254 [LessDepth]: GreaterDepth, 26255 [EqualDepth]: NotEqualDepth, 26256 [LessEqualDepth]: GreaterEqualDepth, 26257 [AlwaysDepth]: NeverDepth, 26258 [GreaterDepth]: LessDepth, 26259 [NotEqualDepth]: EqualDepth, 26260 [GreaterEqualDepth]: LessEqualDepth 26261 }; 26262 function WebGLState(gl, extensions) { 26263 function ColorBuffer() { 26264 let locked = false; 26265 const color = new Vector4(); 26266 let currentColorMask = null; 26267 const currentColorClear = new Vector4(0, 0, 0, 0); 26268 return { 26269 setMask: function(colorMask) { 26270 if (currentColorMask !== colorMask && !locked) { 26271 gl.colorMask(colorMask, colorMask, colorMask, colorMask); 26272 currentColorMask = colorMask; 26273 } 26274 }, 26275 setLocked: function(lock) { 26276 locked = lock; 26277 }, 26278 setClear: function(r, g, b, a, premultipliedAlpha) { 26279 if (premultipliedAlpha === true) { 26280 r *= a; 26281 g *= a; 26282 b *= a; 26283 } 26284 color.set(r, g, b, a); 26285 if (currentColorClear.equals(color) === false) { 26286 gl.clearColor(r, g, b, a); 26287 currentColorClear.copy(color); 26288 } 26289 }, 26290 reset: function() { 26291 locked = false;
vendor: 5,256 bytes, lines 26292-26423
26292 currentColorMask = null; 26293 currentColorClear.set(-1, 0, 0, 0); // set to invalid state 26294 } 26295 }; 26296 } 26297 function DepthBuffer() { 26298 let locked = false; 26299 let reversed = false; 26300 let currentDepthMask = null; 26301 let currentDepthFunc = null; 26302 let currentDepthClear = null; 26303 return { 26304 setReversed: function(value) { 26305 if (reversed !== value) { 26306 const ext = extensions.get('EXT_clip_control'); 26307 if (reversed) { 26308 ext.clipControlEXT(ext.LOWER_LEFT_EXT, ext.ZERO_TO_ONE_EXT); 26309 } else { 26310 ext.clipControlEXT(ext.LOWER_LEFT_EXT, ext.NEGATIVE_ONE_TO_ONE_EXT); 26311 } 26312 const oldDepth = currentDepthClear; 26313 currentDepthClear = null; 26314 this.setClear(oldDepth); 26315 } 26316 reversed = value; 26317 }, 26318 getReversed: function() { 26319 return reversed; 26320 }, 26321 setTest: function(depthTest) { 26322 if (depthTest) { 26323 enable(gl.DEPTH_TEST); 26324 } else { 26325 disable(gl.DEPTH_TEST); 26326 } 26327 }, 26328 setMask: function(depthMask) { 26329 if (currentDepthMask !== depthMask && !locked) { 26330 gl.depthMask(depthMask); 26331 currentDepthMask = depthMask; 26332 } 26333 }, 26334 setFunc: function(depthFunc) { 26335 if (reversed) depthFunc = reversedFuncs[depthFunc]; 26336 if (currentDepthFunc !== depthFunc) { 26337 switch(depthFunc){ 26338 case NeverDepth: 26339 gl.depthFunc(gl.NEVER); 26340 break; 26341 case AlwaysDepth: 26342 gl.depthFunc(gl.ALWAYS); 26343 break; 26344 case LessDepth: 26345 gl.depthFunc(gl.LESS); 26346 break; 26347 case LessEqualDepth: 26348 gl.depthFunc(gl.LEQUAL); 26349 break; 26350 case EqualDepth: 26351 gl.depthFunc(gl.EQUAL); 26352 break; 26353 case GreaterEqualDepth: 26354 gl.depthFunc(gl.GEQUAL); 26355 break; 26356 case GreaterDepth: 26357 gl.depthFunc(gl.GREATER); 26358 break; 26359 case NotEqualDepth: 26360 gl.depthFunc(gl.NOTEQUAL); 26361 break; 26362 default: 26363 gl.depthFunc(gl.LEQUAL); 26364 } 26365 currentDepthFunc = depthFunc; 26366 } 26367 }, 26368 setLocked: function(lock) { 26369 locked = lock; 26370 }, 26371 setClear: function(depth) { 26372 if (currentDepthClear !== depth) { 26373 if (reversed) { 26374 depth = 1 - depth; 26375 } 26376 gl.clearDepth(depth); 26377 currentDepthClear = depth; 26378 } 26379 }, 26380 reset: function() { 26381 locked = false; 26382 currentDepthMask = null; 26383 currentDepthFunc = null; 26384 currentDepthClear = null; 26385 reversed = false; 26386 } 26387 }; 26388 } 26389 function StencilBuffer() { 26390 let locked = false; 26391 let currentStencilMask = null; 26392 let currentStencilFunc = null; 26393 let currentStencilRef = null; 26394 let currentStencilFuncMask = null; 26395 let currentStencilFail = null; 26396 let currentStencilZFail = null; 26397 let currentStencilZPass = null; 26398 let currentStencilClear = null; 26399 return { 26400 setTest: function(stencilTest) { 26401 if (!locked) { 26402 if (stencilTest) { 26403 enable(gl.STENCIL_TEST); 26404 } else { 26405 disable(gl.STENCIL_TEST); 26406 } 26407 } 26408 }, 26409 setMask: function(stencilMask) { 26410 if (currentStencilMask !== stencilMask && !locked) { 26411 gl.stencilMask(stencilMask); 26412 currentStencilMask = stencilMask; 26413 } 26414 }, 26415 setFunc: function(stencilFunc, stencilRef, stencilMask) { 26416 if (currentStencilFunc !== stencilFunc || currentStencilRef !== stencilRef || currentStencilFuncMask !== stencilMask) { 26417 gl.stencilFunc(stencilFunc, stencilRef, stencilMask); 26418 currentStencilFunc = stencilFunc; 26419 currentStencilRef = stencilRef; 26420 currentStencilFuncMask = stencilMask; 26421 } 26422 }, 26423 setOp: function(stencilFail, stencilZFail, stencilZPass) {
vendor: 36,312 bytes, lines 26424-27238
26424 if (currentStencilFail !== stencilFail || currentStencilZFail !== stencilZFail || currentStencilZPass !== stencilZPass) { 26425 gl.stencilOp(stencilFail, stencilZFail, stencilZPass); 26426 currentStencilFail = stencilFail; 26427 currentStencilZFail = stencilZFail; 26428 currentStencilZPass = stencilZPass; 26429 } 26430 }, 26431 setLocked: function(lock) { 26432 locked = lock; 26433 }, 26434 setClear: function(stencil) { 26435 if (currentStencilClear !== stencil) { 26436 gl.clearStencil(stencil); 26437 currentStencilClear = stencil; 26438 } 26439 }, 26440 reset: function() { 26441 locked = false; 26442 currentStencilMask = null; 26443 currentStencilFunc = null; 26444 currentStencilRef = null; 26445 currentStencilFuncMask = null; 26446 currentStencilFail = null; 26447 currentStencilZFail = null; 26448 currentStencilZPass = null; 26449 currentStencilClear = null; 26450 } 26451 }; 26452 } 26453 // 26454 const colorBuffer = new ColorBuffer(); 26455 const depthBuffer = new DepthBuffer(); 26456 const stencilBuffer = new StencilBuffer(); 26457 const uboBindings = new WeakMap(); 26458 const uboProgramMap = new WeakMap(); 26459 let enabledCapabilities = {}; 26460 let currentBoundFramebuffers = {}; 26461 let currentDrawbuffers = new WeakMap(); 26462 let defaultDrawbuffers = []; 26463 let currentProgram = null; 26464 let currentBlendingEnabled = false; 26465 let currentBlending = null; 26466 let currentBlendEquation = null; 26467 let currentBlendSrc = null; 26468 let currentBlendDst = null; 26469 let currentBlendEquationAlpha = null; 26470 let currentBlendSrcAlpha = null; 26471 let currentBlendDstAlpha = null; 26472 let currentBlendColor = new Color(0, 0, 0); 26473 let currentBlendAlpha = 0; 26474 let currentPremultipledAlpha = false; 26475 let currentFlipSided = null; 26476 let currentCullFace = null; 26477 let currentLineWidth = null; 26478 let currentPolygonOffsetFactor = null; 26479 let currentPolygonOffsetUnits = null; 26480 const maxTextures = gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS); 26481 let lineWidthAvailable = false; 26482 let version = 0; 26483 const glVersion = gl.getParameter(gl.VERSION); 26484 if (glVersion.indexOf('WebGL') !== -1) { 26485 version = parseFloat(/^WebGL (\d)/.exec(glVersion)[1]); 26486 lineWidthAvailable = version >= 1.0; 26487 } else if (glVersion.indexOf('OpenGL ES') !== -1) { 26488 version = parseFloat(/^OpenGL ES (\d)/.exec(glVersion)[1]); 26489 lineWidthAvailable = version >= 2.0; 26490 } 26491 let currentTextureSlot = null; 26492 let currentBoundTextures = {}; 26493 const scissorParam = gl.getParameter(gl.SCISSOR_BOX); 26494 const viewportParam = gl.getParameter(gl.VIEWPORT); 26495 const currentScissor = new Vector4().fromArray(scissorParam); 26496 const currentViewport = new Vector4().fromArray(viewportParam); 26497 function createTexture(type, target, count, dimensions) { 26498 const data = new Uint8Array(4); // 4 is required to match default unpack alignment of 4. 26499 const texture = gl.createTexture(); 26500 gl.bindTexture(type, texture); 26501 gl.texParameteri(type, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 26502 gl.texParameteri(type, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 26503 for(let i = 0; i < count; i++){ 26504 if (type === gl.TEXTURE_3D || type === gl.TEXTURE_2D_ARRAY) { 26505 gl.texImage3D(target, 0, gl.RGBA, 1, 1, dimensions, 0, gl.RGBA, gl.UNSIGNED_BYTE, data); 26506 } else { 26507 gl.texImage2D(target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data); 26508 } 26509 } 26510 return texture; 26511 } 26512 const emptyTextures = {}; 26513 emptyTextures[gl.TEXTURE_2D] = createTexture(gl.TEXTURE_2D, gl.TEXTURE_2D, 1); 26514 emptyTextures[gl.TEXTURE_CUBE_MAP] = createTexture(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6); 26515 emptyTextures[gl.TEXTURE_2D_ARRAY] = createTexture(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_2D_ARRAY, 1, 1); 26516 emptyTextures[gl.TEXTURE_3D] = createTexture(gl.TEXTURE_3D, gl.TEXTURE_3D, 1, 1); 26517 // init 26518 colorBuffer.setClear(0, 0, 0, 1); 26519 depthBuffer.setClear(1); 26520 stencilBuffer.setClear(0); 26521 enable(gl.DEPTH_TEST); 26522 depthBuffer.setFunc(LessEqualDepth); 26523 setFlipSided(false); 26524 setCullFace(CullFaceBack); 26525 enable(gl.CULL_FACE); 26526 setBlending(NoBlending); 26527 // 26528 function enable(id) { 26529 if (enabledCapabilities[id] !== true) { 26530 gl.enable(id); 26531 enabledCapabilities[id] = true; 26532 } 26533 } 26534 function disable(id) { 26535 if (enabledCapabilities[id] !== false) { 26536 gl.disable(id); 26537 enabledCapabilities[id] = false; 26538 } 26539 } 26540 function bindFramebuffer(target, framebuffer) { 26541 if (currentBoundFramebuffers[target] !== framebuffer) { 26542 gl.bindFramebuffer(target, framebuffer); 26543 currentBoundFramebuffers[target] = framebuffer; 26544 // gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER 26545 if (target === gl.DRAW_FRAMEBUFFER) { 26546 currentBoundFramebuffers[gl.FRAMEBUFFER] = framebuffer; 26547 } 26548 if (target === gl.FRAMEBUFFER) { 26549 currentBoundFramebuffers[gl.DRAW_FRAMEBUFFER] = framebuffer; 26550 } 26551 return true; 26552 } 26553 return false; 26554 } 26555 function drawBuffers(renderTarget, framebuffer) { 26556 let drawBuffers = defaultDrawbuffers; 26557 let needsUpdate = false; 26558 if (renderTarget) { 26559 drawBuffers = currentDrawbuffers.get(framebuffer); 26560 if (drawBuffers === undefined) { 26561 drawBuffers = []; 26562 currentDrawbuffers.set(framebuffer, drawBuffers); 26563 } 26564 const textures = renderTarget.textures; 26565 if (drawBuffers.length !== textures.length || drawBuffers[0] !== gl.COLOR_ATTACHMENT0) { 26566 for(let i = 0, il = textures.length; i < il; i++){ 26567 drawBuffers[i] = gl.COLOR_ATTACHMENT0 + i; 26568 } 26569 drawBuffers.length = textures.length; 26570 needsUpdate = true; 26571 } 26572 } else { 26573 if (drawBuffers[0] !== gl.BACK) { 26574 drawBuffers[0] = gl.BACK; 26575 needsUpdate = true; 26576 } 26577 } 26578 if (needsUpdate) { 26579 gl.drawBuffers(drawBuffers); 26580 } 26581 } 26582 function useProgram(program) { 26583 if (currentProgram !== program) { 26584 gl.useProgram(program); 26585 currentProgram = program; 26586 return true; 26587 } 26588 return false; 26589 } 26590 const equationToGL = { 26591 [AddEquation]: gl.FUNC_ADD, 26592 [SubtractEquation]: gl.FUNC_SUBTRACT, 26593 [ReverseSubtractEquation]: gl.FUNC_REVERSE_SUBTRACT 26594 }; 26595 equationToGL[MinEquation] = gl.MIN; 26596 equationToGL[MaxEquation] = gl.MAX; 26597 const factorToGL = { 26598 [ZeroFactor]: gl.ZERO, 26599 [OneFactor]: gl.ONE, 26600 [SrcColorFactor]: gl.SRC_COLOR, 26601 [SrcAlphaFactor]: gl.SRC_ALPHA, 26602 [SrcAlphaSaturateFactor]: gl.SRC_ALPHA_SATURATE, 26603 [DstColorFactor]: gl.DST_COLOR, 26604 [DstAlphaFactor]: gl.DST_ALPHA, 26605 [OneMinusSrcColorFactor]: gl.ONE_MINUS_SRC_COLOR, 26606 [OneMinusSrcAlphaFactor]: gl.ONE_MINUS_SRC_ALPHA, 26607 [OneMinusDstColorFactor]: gl.ONE_MINUS_DST_COLOR, 26608 [OneMinusDstAlphaFactor]: gl.ONE_MINUS_DST_ALPHA, 26609 [ConstantColorFactor]: gl.CONSTANT_COLOR, 26610 [OneMinusConstantColorFactor]: gl.ONE_MINUS_CONSTANT_COLOR, 26611 [ConstantAlphaFactor]: gl.CONSTANT_ALPHA, 26612 [OneMinusConstantAlphaFactor]: gl.ONE_MINUS_CONSTANT_ALPHA 26613 }; 26614 function setBlending(blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, blendColor, blendAlpha, premultipliedAlpha) { 26615 if (blending === NoBlending) { 26616 if (currentBlendingEnabled === true) { 26617 disable(gl.BLEND); 26618 currentBlendingEnabled = false; 26619 } 26620 return; 26621 } 26622 if (currentBlendingEnabled === false) { 26623 enable(gl.BLEND); 26624 currentBlendingEnabled = true; 26625 } 26626 if (blending !== CustomBlending) { 26627 if (blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha) { 26628 if (currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation) { 26629 gl.blendEquation(gl.FUNC_ADD); 26630 currentBlendEquation = AddEquation; 26631 currentBlendEquationAlpha = AddEquation; 26632 } 26633 if (premultipliedAlpha) { 26634 switch(blending){ 26635 case NormalBlending: 26636 gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); 26637 break; 26638 case AdditiveBlending: 26639 gl.blendFunc(gl.ONE, gl.ONE); 26640 break; 26641 case SubtractiveBlending: 26642 gl.blendFuncSeparate(gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE); 26643 break; 26644 case MultiplyBlending: 26645 gl.blendFuncSeparate(gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA); 26646 break; 26647 default: 26648 console.error('THREE.WebGLState: Invalid blending: ', blending); 26649 break; 26650 } 26651 } else { 26652 switch(blending){ 26653 case NormalBlending: 26654 gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); 26655 break; 26656 case AdditiveBlending: 26657 gl.blendFunc(gl.SRC_ALPHA, gl.ONE); 26658 break; 26659 case SubtractiveBlending: 26660 gl.blendFuncSeparate(gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE); 26661 break; 26662 case MultiplyBlending: 26663 gl.blendFunc(gl.ZERO, gl.SRC_COLOR); 26664 break; 26665 default: 26666 console.error('THREE.WebGLState: Invalid blending: ', blending); 26667 break; 26668 } 26669 } 26670 currentBlendSrc = null; 26671 currentBlendDst = null; 26672 currentBlendSrcAlpha = null; 26673 currentBlendDstAlpha = null; 26674 currentBlendColor.set(0, 0, 0); 26675 currentBlendAlpha = 0; 26676 currentBlending = blending; 26677 currentPremultipledAlpha = premultipliedAlpha; 26678 } 26679 return; 26680 } 26681 // custom blending 26682 blendEquationAlpha = blendEquationAlpha || blendEquation; 26683 blendSrcAlpha = blendSrcAlpha || blendSrc; 26684 blendDstAlpha = blendDstAlpha || blendDst; 26685 if (blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha) { 26686 gl.blendEquationSeparate(equationToGL[blendEquation], equationToGL[blendEquationAlpha]); 26687 currentBlendEquation = blendEquation; 26688 currentBlendEquationAlpha = blendEquationAlpha; 26689 } 26690 if (blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha) { 26691 gl.blendFuncSeparate(factorToGL[blendSrc], factorToGL[blendDst], factorToGL[blendSrcAlpha], factorToGL[blendDstAlpha]); 26692 currentBlendSrc = blendSrc; 26693 currentBlendDst = blendDst; 26694 currentBlendSrcAlpha = blendSrcAlpha; 26695 currentBlendDstAlpha = blendDstAlpha; 26696 } 26697 if (blendColor.equals(currentBlendColor) === false || blendAlpha !== currentBlendAlpha) { 26698 gl.blendColor(blendColor.r, blendColor.g, blendColor.b, blendAlpha); 26699 currentBlendColor.copy(blendColor); 26700 currentBlendAlpha = blendAlpha; 26701 } 26702 currentBlending = blending; 26703 currentPremultipledAlpha = false; 26704 } 26705 function setMaterial(material, frontFaceCW) { 26706 material.side === DoubleSide ? disable(gl.CULL_FACE) : enable(gl.CULL_FACE); 26707 let flipSided = material.side === BackSide; 26708 if (frontFaceCW) flipSided = !flipSided; 26709 setFlipSided(flipSided); 26710 material.blending === NormalBlending && material.transparent === false ? setBlending(NoBlending) : setBlending(material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha); 26711 depthBuffer.setFunc(material.depthFunc); 26712 depthBuffer.setTest(material.depthTest); 26713 depthBuffer.setMask(material.depthWrite); 26714 colorBuffer.setMask(material.colorWrite); 26715 const stencilWrite = material.stencilWrite; 26716 stencilBuffer.setTest(stencilWrite); 26717 if (stencilWrite) { 26718 stencilBuffer.setMask(material.stencilWriteMask); 26719 stencilBuffer.setFunc(material.stencilFunc, material.stencilRef, material.stencilFuncMask); 26720 stencilBuffer.setOp(material.stencilFail, material.stencilZFail, material.stencilZPass); 26721 } 26722 setPolygonOffset(material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits); 26723 material.alphaToCoverage === true ? enable(gl.SAMPLE_ALPHA_TO_COVERAGE) : disable(gl.SAMPLE_ALPHA_TO_COVERAGE); 26724 } 26725 // 26726 function setFlipSided(flipSided) { 26727 if (currentFlipSided !== flipSided) { 26728 if (flipSided) { 26729 gl.frontFace(gl.CW); 26730 } else { 26731 gl.frontFace(gl.CCW); 26732 } 26733 currentFlipSided = flipSided; 26734 } 26735 } 26736 function setCullFace(cullFace) { 26737 if (cullFace !== CullFaceNone) { 26738 enable(gl.CULL_FACE); 26739 if (cullFace !== currentCullFace) { 26740 if (cullFace === CullFaceBack) { 26741 gl.cullFace(gl.BACK); 26742 } else if (cullFace === CullFaceFront) { 26743 gl.cullFace(gl.FRONT); 26744 } else { 26745 gl.cullFace(gl.FRONT_AND_BACK); 26746 } 26747 } 26748 } else { 26749 disable(gl.CULL_FACE); 26750 } 26751 currentCullFace = cullFace; 26752 } 26753 function setLineWidth(width) { 26754 if (width !== currentLineWidth) { 26755 if (lineWidthAvailable) gl.lineWidth(width); 26756 currentLineWidth = width; 26757 } 26758 } 26759 function setPolygonOffset(polygonOffset, factor, units) { 26760 if (polygonOffset) { 26761 enable(gl.POLYGON_OFFSET_FILL); 26762 if (currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units) { 26763 gl.polygonOffset(factor, units); 26764 currentPolygonOffsetFactor = factor; 26765 currentPolygonOffsetUnits = units; 26766 } 26767 } else { 26768 disable(gl.POLYGON_OFFSET_FILL); 26769 } 26770 } 26771 function setScissorTest(scissorTest) { 26772 if (scissorTest) { 26773 enable(gl.SCISSOR_TEST); 26774 } else { 26775 disable(gl.SCISSOR_TEST); 26776 } 26777 } 26778 // texture 26779 function activeTexture(webglSlot) { 26780 if (webglSlot === undefined) webglSlot = gl.TEXTURE0 + maxTextures - 1; 26781 if (currentTextureSlot !== webglSlot) { 26782 gl.activeTexture(webglSlot); 26783 currentTextureSlot = webglSlot; 26784 } 26785 } 26786 function bindTexture(webglType, webglTexture, webglSlot) { 26787 if (webglSlot === undefined) { 26788 if (currentTextureSlot === null) { 26789 webglSlot = gl.TEXTURE0 + maxTextures - 1; 26790 } else { 26791 webglSlot = currentTextureSlot; 26792 } 26793 } 26794 let boundTexture = currentBoundTextures[webglSlot]; 26795 if (boundTexture === undefined) { 26796 boundTexture = { 26797 type: undefined, 26798 texture: undefined 26799 }; 26800 currentBoundTextures[webglSlot] = boundTexture; 26801 } 26802 if (boundTexture.type !== webglType || boundTexture.texture !== webglTexture) { 26803 if (currentTextureSlot !== webglSlot) { 26804 gl.activeTexture(webglSlot); 26805 currentTextureSlot = webglSlot; 26806 } 26807 gl.bindTexture(webglType, webglTexture || emptyTextures[webglType]); 26808 boundTexture.type = webglType; 26809 boundTexture.texture = webglTexture; 26810 } 26811 } 26812 function unbindTexture() { 26813 const boundTexture = currentBoundTextures[currentTextureSlot]; 26814 if (boundTexture !== undefined && boundTexture.type !== undefined) { 26815 gl.bindTexture(boundTexture.type, null); 26816 boundTexture.type = undefined; 26817 boundTexture.texture = undefined; 26818 } 26819 } 26820 function compressedTexImage2D() { 26821 try { 26822 gl.compressedTexImage2D(...arguments); 26823 } catch (error) { 26824 console.error('THREE.WebGLState:', error); 26825 } 26826 } 26827 function compressedTexImage3D() { 26828 try { 26829 gl.compressedTexImage3D(...arguments); 26830 } catch (error) { 26831 console.error('THREE.WebGLState:', error); 26832 } 26833 } 26834 function texSubImage2D() { 26835 try { 26836 gl.texSubImage2D(...arguments); 26837 } catch (error) { 26838 console.error('THREE.WebGLState:', error); 26839 } 26840 } 26841 function texSubImage3D() { 26842 try { 26843 gl.texSubImage3D(...arguments); 26844 } catch (error) { 26845 console.error('THREE.WebGLState:', error); 26846 } 26847 } 26848 function compressedTexSubImage2D() { 26849 try { 26850 gl.compressedTexSubImage2D(...arguments); 26851 } catch (error) { 26852 console.error('THREE.WebGLState:', error); 26853 } 26854 } 26855 function compressedTexSubImage3D() { 26856 try { 26857 gl.compressedTexSubImage3D(...arguments); 26858 } catch (error) { 26859 console.error('THREE.WebGLState:', error); 26860 } 26861 } 26862 function texStorage2D() { 26863 try { 26864 gl.texStorage2D(...arguments); 26865 } catch (error) { 26866 console.error('THREE.WebGLState:', error); 26867 } 26868 } 26869 function texStorage3D() { 26870 try { 26871 gl.texStorage3D(...arguments); 26872 } catch (error) { 26873 console.error('THREE.WebGLState:', error); 26874 } 26875 } 26876 function texImage2D() { 26877 try { 26878 gl.texImage2D(...arguments); 26879 } catch (error) { 26880 console.error('THREE.WebGLState:', error); 26881 } 26882 } 26883 function texImage3D() { 26884 try { 26885 gl.texImage3D(...arguments); 26886 } catch (error) { 26887 console.error('THREE.WebGLState:', error); 26888 } 26889 } 26890 // 26891 function scissor(scissor) { 26892 if (currentScissor.equals(scissor) === false) { 26893 gl.scissor(scissor.x, scissor.y, scissor.z, scissor.w); 26894 currentScissor.copy(scissor); 26895 } 26896 } 26897 function viewport(viewport) { 26898 if (currentViewport.equals(viewport) === false) { 26899 gl.viewport(viewport.x, viewport.y, viewport.z, viewport.w); 26900 currentViewport.copy(viewport); 26901 } 26902 } 26903 function updateUBOMapping(uniformsGroup, program) { 26904 let mapping = uboProgramMap.get(program); 26905 if (mapping === undefined) { 26906 mapping = new WeakMap(); 26907 uboProgramMap.set(program, mapping); 26908 } 26909 let blockIndex = mapping.get(uniformsGroup); 26910 if (blockIndex === undefined) { 26911 blockIndex = gl.getUniformBlockIndex(program, uniformsGroup.name); 26912 mapping.set(uniformsGroup, blockIndex); 26913 } 26914 } 26915 function uniformBlockBinding(uniformsGroup, program) { 26916 const mapping = uboProgramMap.get(program); 26917 const blockIndex = mapping.get(uniformsGroup); 26918 if (uboBindings.get(program) !== blockIndex) { 26919 // bind shader specific block index to global block point 26920 gl.uniformBlockBinding(program, blockIndex, uniformsGroup.__bindingPointIndex); 26921 uboBindings.set(program, blockIndex); 26922 } 26923 } 26924 // 26925 function reset() { 26926 // reset state 26927 gl.disable(gl.BLEND); 26928 gl.disable(gl.CULL_FACE); 26929 gl.disable(gl.DEPTH_TEST); 26930 gl.disable(gl.POLYGON_OFFSET_FILL); 26931 gl.disable(gl.SCISSOR_TEST); 26932 gl.disable(gl.STENCIL_TEST); 26933 gl.disable(gl.SAMPLE_ALPHA_TO_COVERAGE); 26934 gl.blendEquation(gl.FUNC_ADD); 26935 gl.blendFunc(gl.ONE, gl.ZERO); 26936 gl.blendFuncSeparate(gl.ONE, gl.ZERO, gl.ONE, gl.ZERO); 26937 gl.blendColor(0, 0, 0, 0); 26938 gl.colorMask(true, true, true, true); 26939 gl.clearColor(0, 0, 0, 0); 26940 gl.depthMask(true); 26941 gl.depthFunc(gl.LESS); 26942 depthBuffer.setReversed(false); 26943 gl.clearDepth(1); 26944 gl.stencilMask(0xffffffff); 26945 gl.stencilFunc(gl.ALWAYS, 0, 0xffffffff); 26946 gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); 26947 gl.clearStencil(0); 26948 gl.cullFace(gl.BACK); 26949 gl.frontFace(gl.CCW); 26950 gl.polygonOffset(0, 0); 26951 gl.activeTexture(gl.TEXTURE0); 26952 gl.bindFramebuffer(gl.FRAMEBUFFER, null); 26953 gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null); 26954 gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null); 26955 gl.useProgram(null); 26956 gl.lineWidth(1); 26957 gl.scissor(0, 0, gl.canvas.width, gl.canvas.height); 26958 gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); 26959 // reset internals 26960 enabledCapabilities = {}; 26961 currentTextureSlot = null; 26962 currentBoundTextures = {}; 26963 currentBoundFramebuffers = {}; 26964 currentDrawbuffers = new WeakMap(); 26965 defaultDrawbuffers = []; 26966 currentProgram = null; 26967 currentBlendingEnabled = false; 26968 currentBlending = null; 26969 currentBlendEquation = null; 26970 currentBlendSrc = null; 26971 currentBlendDst = null; 26972 currentBlendEquationAlpha = null; 26973 currentBlendSrcAlpha = null; 26974 currentBlendDstAlpha = null; 26975 currentBlendColor = new Color(0, 0, 0); 26976 currentBlendAlpha = 0; 26977 currentPremultipledAlpha = false; 26978 currentFlipSided = null; 26979 currentCullFace = null; 26980 currentLineWidth = null; 26981 currentPolygonOffsetFactor = null; 26982 currentPolygonOffsetUnits = null; 26983 currentScissor.set(0, 0, gl.canvas.width, gl.canvas.height); 26984 currentViewport.set(0, 0, gl.canvas.width, gl.canvas.height); 26985 colorBuffer.reset(); 26986 depthBuffer.reset(); 26987 stencilBuffer.reset(); 26988 } 26989 return { 26990 buffers: { 26991 color: colorBuffer, 26992 depth: depthBuffer, 26993 stencil: stencilBuffer 26994 }, 26995 enable: enable, 26996 disable: disable, 26997 bindFramebuffer: bindFramebuffer, 26998 drawBuffers: drawBuffers, 26999 useProgram: useProgram, 27000 setBlending: setBlending, 27001 setMaterial: setMaterial, 27002 setFlipSided: setFlipSided, 27003 setCullFace: setCullFace, 27004 setLineWidth: setLineWidth, 27005 setPolygonOffset: setPolygonOffset, 27006 setScissorTest: setScissorTest, 27007 activeTexture: activeTexture, 27008 bindTexture: bindTexture, 27009 unbindTexture: unbindTexture, 27010 compressedTexImage2D: compressedTexImage2D, 27011 compressedTexImage3D: compressedTexImage3D, 27012 texImage2D: texImage2D, 27013 texImage3D: texImage3D, 27014 updateUBOMapping: updateUBOMapping, 27015 uniformBlockBinding: uniformBlockBinding, 27016 texStorage2D: texStorage2D, 27017 texStorage3D: texStorage3D, 27018 texSubImage2D: texSubImage2D, 27019 texSubImage3D: texSubImage3D, 27020 compressedTexSubImage2D: compressedTexSubImage2D, 27021 compressedTexSubImage3D: compressedTexSubImage3D, 27022 scissor: scissor, 27023 viewport: viewport, 27024 reset: reset 27025 }; 27026 } 27027 function WebGLTextures(_gl, extensions, state, properties, capabilities, utils, info) { 27028 const multisampledRTTExt = extensions.has('WEBGL_multisampled_render_to_texture') ? extensions.get('WEBGL_multisampled_render_to_texture') : null; 27029 const supportsInvalidateFramebuffer = typeof navigator === 'undefined' ? false : /OculusBrowser/g.test(navigator.userAgent); 27030 const _imageDimensions = new Vector2(); 27031 const _videoTextures = new WeakMap(); 27032 let _canvas; 27033 const _sources = new WeakMap(); // maps WebglTexture objects to instances of Source 27034 // cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas, 27035 // also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")! 27036 // Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d). 27037 let useOffscreenCanvas = false; 27038 try { 27039 useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined' && new OffscreenCanvas(1, 1).getContext('2d') !== null; 27040 } catch (err) { 27041 // Ignore any errors 27042 } 27043 function createCanvas(width, height) { 27044 // Use OffscreenCanvas when available. Specially needed in web workers 27045 return useOffscreenCanvas ? // eslint-disable-next-line compat/compat 27046 new OffscreenCanvas(width, height) : createElementNS('canvas'); 27047 } 27048 function resizeImage(image, needsNewCanvas, maxSize) { 27049 let scale = 1; 27050 const dimensions = getDimensions(image); 27051 // handle case if texture exceeds max size 27052 if (dimensions.width > maxSize || dimensions.height > maxSize) { 27053 scale = maxSize / Math.max(dimensions.width, dimensions.height); 27054 } 27055 // only perform resize if necessary 27056 if (scale < 1) { 27057 // only perform resize for certain image types 27058 if (typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement || typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement || typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap || typeof VideoFrame !== 'undefined' && image instanceof VideoFrame) { 27059 const width = Math.floor(scale * dimensions.width); 27060 const height = Math.floor(scale * dimensions.height); 27061 if (_canvas === undefined) _canvas = createCanvas(width, height); 27062 // cube textures can't reuse the same canvas 27063 const canvas = needsNewCanvas ? createCanvas(width, height) : _canvas; 27064 canvas.width = width; 27065 canvas.height = height; 27066 const context = canvas.getContext('2d'); 27067 context.drawImage(image, 0, 0, width, height); 27068 console.warn('THREE.WebGLRenderer: Texture has been resized from (' + dimensions.width + 'x' + dimensions.height + ') to (' + width + 'x' + height + ').'); 27069 return canvas; 27070 } else { 27071 if ('data' in image) { 27072 console.warn('THREE.WebGLRenderer: Image in DataTexture is too big (' + dimensions.width + 'x' + dimensions.height + ').'); 27073 } 27074 return image; 27075 } 27076 } 27077 return image; 27078 } 27079 function textureNeedsGenerateMipmaps(texture) { 27080 return texture.generateMipmaps; 27081 } 27082 function generateMipmap(target) { 27083 _gl.generateMipmap(target); 27084 } 27085 function getTargetType(texture) { 27086 if (texture.isWebGLCubeRenderTarget) return _gl.TEXTURE_CUBE_MAP; 27087 if (texture.isWebGL3DRenderTarget) return _gl.TEXTURE_3D; 27088 if (texture.isWebGLArrayRenderTarget || texture.isCompressedArrayTexture) return _gl.TEXTURE_2D_ARRAY; 27089 return _gl.TEXTURE_2D; 27090 } 27091 function getInternalFormat(internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false) { 27092 if (internalFormatName !== null) { 27093 if (_gl[internalFormatName] !== undefined) return _gl[internalFormatName]; 27094 console.warn('THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\''); 27095 } 27096 let internalFormat = glFormat; 27097 if (glFormat === _gl.RED) { 27098 if (glType === _gl.FLOAT) internalFormat = _gl.R32F; 27099 if (glType === _gl.HALF_FLOAT) internalFormat = _gl.R16F; 27100 if (glType === _gl.UNSIGNED_BYTE) internalFormat = _gl.R8; 27101 } 27102 if (glFormat === _gl.RED_INTEGER) { 27103 if (glType === _gl.UNSIGNED_BYTE) internalFormat = _gl.R8UI; 27104 if (glType === _gl.UNSIGNED_SHORT) internalFormat = _gl.R16UI; 27105 if (glType === _gl.UNSIGNED_INT) internalFormat = _gl.R32UI; 27106 if (glType === _gl.BYTE) internalFormat = _gl.R8I; 27107 if (glType === _gl.SHORT) internalFormat = _gl.R16I; 27108 if (glType === _gl.INT) internalFormat = _gl.R32I; 27109 } 27110 if (glFormat === _gl.RG) { 27111 if (glType === _gl.FLOAT) internalFormat = _gl.RG32F; 27112 if (glType === _gl.HALF_FLOAT) internalFormat = _gl.RG16F; 27113 if (glType === _gl.UNSIGNED_BYTE) internalFormat = _gl.RG8; 27114 } 27115 if (glFormat === _gl.RG_INTEGER) { 27116 if (glType === _gl.UNSIGNED_BYTE) internalFormat = _gl.RG8UI; 27117 if (glType === _gl.UNSIGNED_SHORT) internalFormat = _gl.RG16UI; 27118 if (glType === _gl.UNSIGNED_INT) internalFormat = _gl.RG32UI; 27119 if (glType === _gl.BYTE) internalFormat = _gl.RG8I; 27120 if (glType === _gl.SHORT) internalFormat = _gl.RG16I; 27121 if (glType === _gl.INT) internalFormat = _gl.RG32I; 27122 } 27123 if (glFormat === _gl.RGB_INTEGER) { 27124 if (glType === _gl.UNSIGNED_BYTE) internalFormat = _gl.RGB8UI; 27125 if (glType === _gl.UNSIGNED_SHORT) internalFormat = _gl.RGB16UI; 27126 if (glType === _gl.UNSIGNED_INT) internalFormat = _gl.RGB32UI; 27127 if (glType === _gl.BYTE) internalFormat = _gl.RGB8I; 27128 if (glType === _gl.SHORT) internalFormat = _gl.RGB16I; 27129 if (glType === _gl.INT) internalFormat = _gl.RGB32I; 27130 } 27131 if (glFormat === _gl.RGBA_INTEGER) { 27132 if (glType === _gl.UNSIGNED_BYTE) internalFormat = _gl.RGBA8UI; 27133 if (glType === _gl.UNSIGNED_SHORT) internalFormat = _gl.RGBA16UI; 27134 if (glType === _gl.UNSIGNED_INT) internalFormat = _gl.RGBA32UI; 27135 if (glType === _gl.BYTE) internalFormat = _gl.RGBA8I; 27136 if (glType === _gl.SHORT) internalFormat = _gl.RGBA16I; 27137 if (glType === _gl.INT) internalFormat = _gl.RGBA32I; 27138 } 27139 if (glFormat === _gl.RGB) { 27140 if (glType === _gl.UNSIGNED_INT_5_9_9_9_REV) internalFormat = _gl.RGB9_E5; 27141 } 27142 if (glFormat === _gl.RGBA) { 27143 const transfer = forceLinearTransfer ? LinearTransfer : ColorManagement.getTransfer(colorSpace); 27144 if (glType === _gl.FLOAT) internalFormat = _gl.RGBA32F; 27145 if (glType === _gl.HALF_FLOAT) internalFormat = _gl.RGBA16F; 27146 if (glType === _gl.UNSIGNED_BYTE) internalFormat = transfer === SRGBTransfer ? _gl.SRGB8_ALPHA8 : _gl.RGBA8; 27147 if (glType === _gl.UNSIGNED_SHORT_4_4_4_4) internalFormat = _gl.RGBA4; 27148 if (glType === _gl.UNSIGNED_SHORT_5_5_5_1) internalFormat = _gl.RGB5_A1; 27149 } 27150 if (internalFormat === _gl.R16F || internalFormat === _gl.R32F || internalFormat === _gl.RG16F || internalFormat === _gl.RG32F || internalFormat === _gl.RGBA16F || internalFormat === _gl.RGBA32F) { 27151 extensions.get('EXT_color_buffer_float'); 27152 } 27153 return internalFormat; 27154 } 27155 function getInternalDepthFormat(useStencil, depthType) { 27156 let glInternalFormat; 27157 if (useStencil) { 27158 if (depthType === null || depthType === UnsignedIntType || depthType === UnsignedInt248Type) { 27159 glInternalFormat = _gl.DEPTH24_STENCIL8; 27160 } else if (depthType === FloatType) { 27161 glInternalFormat = _gl.DEPTH32F_STENCIL8; 27162 } else if (depthType === UnsignedShortType) { 27163 glInternalFormat = _gl.DEPTH24_STENCIL8; 27164 console.warn('DepthTexture: 16 bit depth attachment is not supported with stencil. Using 24-bit attachment.'); 27165 } 27166 } else { 27167 if (depthType === null || depthType === UnsignedIntType || depthType === UnsignedInt248Type) { 27168 glInternalFormat = _gl.DEPTH_COMPONENT24; 27169 } else if (depthType === FloatType) { 27170 glInternalFormat = _gl.DEPTH_COMPONENT32F; 27171 } else if (depthType === UnsignedShortType) { 27172 glInternalFormat = _gl.DEPTH_COMPONENT16; 27173 } 27174 } 27175 return glInternalFormat; 27176 } 27177 function getMipLevels(texture, image) { 27178 if (textureNeedsGenerateMipmaps(texture) === true || texture.isFramebufferTexture && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter) { 27179 return Math.log2(Math.max(image.width, image.height)) + 1; 27180 } else if (texture.mipmaps !== undefined && texture.mipmaps.length > 0) { 27181 // user-defined mipmaps 27182 return texture.mipmaps.length; 27183 } else if (texture.isCompressedTexture && Array.isArray(texture.image)) { 27184 return image.mipmaps.length; 27185 } else { 27186 // texture without mipmaps (only base level) 27187 return 1; 27188 } 27189 } 27190 // 27191 function onTextureDispose(event) { 27192 const texture = event.target; 27193 texture.removeEventListener('dispose', onTextureDispose); 27194 deallocateTexture(texture); 27195 if (texture.isVideoTexture) { 27196 _videoTextures.delete(texture); 27197 } 27198 } 27199 function onRenderTargetDispose(event) { 27200 const renderTarget = event.target; 27201 renderTarget.removeEventListener('dispose', onRenderTargetDispose); 27202 deallocateRenderTarget(renderTarget); 27203 } 27204 // 27205 function deallocateTexture(texture) { 27206 const textureProperties = properties.get(texture); 27207 if (textureProperties.__webglInit === undefined) return; 27208 // check if it's necessary to remove the WebGLTexture object 27209 const source = texture.source; 27210 const webglTextures = _sources.get(source); 27211 if (webglTextures) { 27212 const webglTexture = webglTextures[textureProperties.__cacheKey]; 27213 webglTexture.usedTimes--; 27214 // the WebGLTexture object is not used anymore, remove it 27215 if (webglTexture.usedTimes === 0) { 27216 deleteTexture(texture); 27217 } 27218 // remove the weak map entry if no WebGLTexture uses the source anymore 27219 if (Object.keys(webglTextures).length === 0) { 27220 _sources.delete(source); 27221 } 27222 } 27223 properties.remove(texture); 27224 } 27225 function deleteTexture(texture) { 27226 const textureProperties = properties.get(texture); 27227 _gl.deleteTexture(textureProperties.__webglTexture); 27228 const source = texture.source; 27229 const webglTextures = _sources.get(source); 27230 delete webglTextures[textureProperties.__cacheKey]; 27231 info.memory.textures--; 27232 } 27233 function deallocateRenderTarget(renderTarget) { 27234 const renderTargetProperties = properties.get(renderTarget); 27235 if (renderTarget.depthTexture) { 27236 renderTarget.depthTexture.dispose(); 27237 properties.remove(renderTarget.depthTexture); 27238 }
vendor: 8,880 bytes, lines 27239-27396
27239 if (renderTarget.isWebGLCubeRenderTarget) { 27240 for(let i = 0; i < 6; i++){ 27241 if (Array.isArray(renderTargetProperties.__webglFramebuffer[i])) { 27242 for(let level = 0; level < renderTargetProperties.__webglFramebuffer[i].length; level++)_gl.deleteFramebuffer(renderTargetProperties.__webglFramebuffer[i][level]); 27243 } else { 27244 _gl.deleteFramebuffer(renderTargetProperties.__webglFramebuffer[i]); 27245 } 27246 if (renderTargetProperties.__webglDepthbuffer) _gl.deleteRenderbuffer(renderTargetProperties.__webglDepthbuffer[i]); 27247 } 27248 } else { 27249 if (Array.isArray(renderTargetProperties.__webglFramebuffer)) { 27250 for(let level = 0; level < renderTargetProperties.__webglFramebuffer.length; level++)_gl.deleteFramebuffer(renderTargetProperties.__webglFramebuffer[level]); 27251 } else { 27252 _gl.deleteFramebuffer(renderTargetProperties.__webglFramebuffer); 27253 } 27254 if (renderTargetProperties.__webglDepthbuffer) _gl.deleteRenderbuffer(renderTargetProperties.__webglDepthbuffer); 27255 if (renderTargetProperties.__webglMultisampledFramebuffer) _gl.deleteFramebuffer(renderTargetProperties.__webglMultisampledFramebuffer); 27256 if (renderTargetProperties.__webglColorRenderbuffer) { 27257 for(let i = 0; i < renderTargetProperties.__webglColorRenderbuffer.length; i++){ 27258 if (renderTargetProperties.__webglColorRenderbuffer[i]) _gl.deleteRenderbuffer(renderTargetProperties.__webglColorRenderbuffer[i]); 27259 } 27260 } 27261 if (renderTargetProperties.__webglDepthRenderbuffer) _gl.deleteRenderbuffer(renderTargetProperties.__webglDepthRenderbuffer); 27262 } 27263 const textures = renderTarget.textures; 27264 for(let i = 0, il = textures.length; i < il; i++){ 27265 const attachmentProperties = properties.get(textures[i]); 27266 if (attachmentProperties.__webglTexture) { 27267 _gl.deleteTexture(attachmentProperties.__webglTexture); 27268 info.memory.textures--; 27269 } 27270 properties.remove(textures[i]); 27271 } 27272 properties.remove(renderTarget); 27273 } 27274 // 27275 let textureUnits = 0; 27276 function resetTextureUnits() { 27277 textureUnits = 0; 27278 } 27279 function allocateTextureUnit() { 27280 const textureUnit = textureUnits; 27281 if (textureUnit >= capabilities.maxTextures) { 27282 console.warn('THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures); 27283 } 27284 textureUnits += 1; 27285 return textureUnit; 27286 } 27287 function getTextureCacheKey(texture) { 27288 const array = []; 27289 array.push(texture.wrapS); 27290 array.push(texture.wrapT); 27291 array.push(texture.wrapR || 0); 27292 array.push(texture.magFilter); 27293 array.push(texture.minFilter); 27294 array.push(texture.anisotropy); 27295 array.push(texture.internalFormat); 27296 array.push(texture.format); 27297 array.push(texture.type); 27298 array.push(texture.generateMipmaps); 27299 array.push(texture.premultiplyAlpha); 27300 array.push(texture.flipY); 27301 array.push(texture.unpackAlignment); 27302 array.push(texture.colorSpace); 27303 return array.join(); 27304 } 27305 // 27306 function setTexture2D(texture, slot) { 27307 const textureProperties = properties.get(texture); 27308 if (texture.isVideoTexture) updateVideoTexture(texture); 27309 if (texture.isRenderTargetTexture === false && texture.version > 0 && textureProperties.__version !== texture.version) { 27310 const image = texture.image; 27311 if (image === null) { 27312 console.warn('THREE.WebGLRenderer: Texture marked for update but no image data found.'); 27313 } else if (image.complete === false) { 27314 console.warn('THREE.WebGLRenderer: Texture marked for update but image is incomplete'); 27315 } else { 27316 uploadTexture(textureProperties, texture, slot); 27317 return; 27318 } 27319 } 27320 state.bindTexture(_gl.TEXTURE_2D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot); 27321 } 27322 function setTexture2DArray(texture, slot) { 27323 const textureProperties = properties.get(texture); 27324 if (texture.version > 0 && textureProperties.__version !== texture.version) { 27325 uploadTexture(textureProperties, texture, slot); 27326 return; 27327 } 27328 state.bindTexture(_gl.TEXTURE_2D_ARRAY, textureProperties.__webglTexture, _gl.TEXTURE0 + slot); 27329 } 27330 function setTexture3D(texture, slot) { 27331 const textureProperties = properties.get(texture); 27332 if (texture.version > 0 && textureProperties.__version !== texture.version) { 27333 uploadTexture(textureProperties, texture, slot); 27334 return; 27335 } 27336 state.bindTexture(_gl.TEXTURE_3D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot); 27337 } 27338 function setTextureCube(texture, slot) { 27339 const textureProperties = properties.get(texture); 27340 if (texture.version > 0 && textureProperties.__version !== texture.version) { 27341 uploadCubeTexture(textureProperties, texture, slot); 27342 return; 27343 } 27344 state.bindTexture(_gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot); 27345 } 27346 const wrappingToGL = { 27347 [RepeatWrapping]: _gl.REPEAT, 27348 [ClampToEdgeWrapping]: _gl.CLAMP_TO_EDGE, 27349 [MirroredRepeatWrapping]: _gl.MIRRORED_REPEAT 27350 }; 27351 const filterToGL = { 27352 [NearestFilter]: _gl.NEAREST, 27353 [NearestMipmapNearestFilter]: _gl.NEAREST_MIPMAP_NEAREST, 27354 [NearestMipmapLinearFilter]: _gl.NEAREST_MIPMAP_LINEAR, 27355 [LinearFilter]: _gl.LINEAR, 27356 [LinearMipmapNearestFilter]: _gl.LINEAR_MIPMAP_NEAREST, 27357 [LinearMipmapLinearFilter]: _gl.LINEAR_MIPMAP_LINEAR 27358 }; 27359 const compareToGL = { 27360 [NeverCompare]: _gl.NEVER, 27361 [AlwaysCompare]: _gl.ALWAYS, 27362 [LessCompare]: _gl.LESS, 27363 [LessEqualCompare]: _gl.LEQUAL, 27364 [EqualCompare]: _gl.EQUAL, 27365 [GreaterEqualCompare]: _gl.GEQUAL, 27366 [GreaterCompare]: _gl.GREATER, 27367 [NotEqualCompare]: _gl.NOTEQUAL 27368 }; 27369 function setTextureParameters(textureType, texture) { 27370 if (texture.type === FloatType && extensions.has('OES_texture_float_linear') === false && (texture.magFilter === LinearFilter || texture.magFilter === LinearMipmapNearestFilter || texture.magFilter === NearestMipmapLinearFilter || texture.magFilter === LinearMipmapLinearFilter || texture.minFilter === LinearFilter || texture.minFilter === LinearMipmapNearestFilter || texture.minFilter === NearestMipmapLinearFilter || texture.minFilter === LinearMipmapLinearFilter)) { 27371 console.warn('THREE.WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device.'); 27372 } 27373 _gl.texParameteri(textureType, _gl.TEXTURE_WRAP_S, wrappingToGL[texture.wrapS]); 27374 _gl.texParameteri(textureType, _gl.TEXTURE_WRAP_T, wrappingToGL[texture.wrapT]); 27375 if (textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY) { 27376 _gl.texParameteri(textureType, _gl.TEXTURE_WRAP_R, wrappingToGL[texture.wrapR]); 27377 } 27378 _gl.texParameteri(textureType, _gl.TEXTURE_MAG_FILTER, filterToGL[texture.magFilter]); 27379 _gl.texParameteri(textureType, _gl.TEXTURE_MIN_FILTER, filterToGL[texture.minFilter]); 27380 if (texture.compareFunction) { 27381 _gl.texParameteri(textureType, _gl.TEXTURE_COMPARE_MODE, _gl.COMPARE_REF_TO_TEXTURE); 27382 _gl.texParameteri(textureType, _gl.TEXTURE_COMPARE_FUNC, compareToGL[texture.compareFunction]); 27383 } 27384 if (extensions.has('EXT_texture_filter_anisotropic') === true) { 27385 if (texture.magFilter === NearestFilter) return; 27386 if (texture.minFilter !== NearestMipmapLinearFilter && texture.minFilter !== LinearMipmapLinearFilter) return; 27387 if (texture.type === FloatType && extensions.has('OES_texture_float_linear') === false) return; // verify extension 27388 if (texture.anisotropy > 1 || properties.get(texture).__currentAnisotropy) { 27389 const extension = extensions.get('EXT_texture_filter_anisotropic'); 27390 _gl.texParameterf(textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min(texture.anisotropy, capabilities.getMaxAnisotropy())); 27391 properties.get(texture).__currentAnisotropy = texture.anisotropy; 27392 } 27393 } 27394 } 27395 function initTexture(textureProperties, texture) { 27396 let forceUpload = false;
vendor: 32,977 bytes, lines 27397-27906
27397 if (textureProperties.__webglInit === undefined) { 27398 textureProperties.__webglInit = true; 27399 texture.addEventListener('dispose', onTextureDispose); 27400 } 27401 // create Source <-> WebGLTextures mapping if necessary 27402 const source = texture.source; 27403 let webglTextures = _sources.get(source); 27404 if (webglTextures === undefined) { 27405 webglTextures = {}; 27406 _sources.set(source, webglTextures); 27407 } 27408 // check if there is already a WebGLTexture object for the given texture parameters 27409 const textureCacheKey = getTextureCacheKey(texture); 27410 if (textureCacheKey !== textureProperties.__cacheKey) { 27411 // if not, create a new instance of WebGLTexture 27412 if (webglTextures[textureCacheKey] === undefined) { 27413 // create new entry 27414 webglTextures[textureCacheKey] = { 27415 texture: _gl.createTexture(), 27416 usedTimes: 0 27417 }; 27418 info.memory.textures++; 27419 // when a new instance of WebGLTexture was created, a texture upload is required 27420 // even if the image contents are identical 27421 forceUpload = true; 27422 } 27423 webglTextures[textureCacheKey].usedTimes++; 27424 // every time the texture cache key changes, it's necessary to check if an instance of 27425 // WebGLTexture can be deleted in order to avoid a memory leak. 27426 const webglTexture = webglTextures[textureProperties.__cacheKey]; 27427 if (webglTexture !== undefined) { 27428 webglTextures[textureProperties.__cacheKey].usedTimes--; 27429 if (webglTexture.usedTimes === 0) { 27430 deleteTexture(texture); 27431 } 27432 } 27433 // store references to cache key and WebGLTexture object 27434 textureProperties.__cacheKey = textureCacheKey; 27435 textureProperties.__webglTexture = webglTextures[textureCacheKey].texture; 27436 } 27437 return forceUpload; 27438 } 27439 function uploadTexture(textureProperties, texture, slot) { 27440 let textureType = _gl.TEXTURE_2D; 27441 if (texture.isDataArrayTexture || texture.isCompressedArrayTexture) textureType = _gl.TEXTURE_2D_ARRAY; 27442 if (texture.isData3DTexture) textureType = _gl.TEXTURE_3D; 27443 const forceUpload = initTexture(textureProperties, texture); 27444 const source = texture.source; 27445 state.bindTexture(textureType, textureProperties.__webglTexture, _gl.TEXTURE0 + slot); 27446 const sourceProperties = properties.get(source); 27447 if (source.version !== sourceProperties.__version || forceUpload === true) { 27448 state.activeTexture(_gl.TEXTURE0 + slot); 27449 const workingPrimaries = ColorManagement.getPrimaries(ColorManagement.workingColorSpace); 27450 const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries(texture.colorSpace); 27451 const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL; 27452 _gl.pixelStorei(_gl.UNPACK_FLIP_Y_WEBGL, texture.flipY); 27453 _gl.pixelStorei(_gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha); 27454 _gl.pixelStorei(_gl.UNPACK_ALIGNMENT, texture.unpackAlignment); 27455 _gl.pixelStorei(_gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion); 27456 let image = resizeImage(texture.image, false, capabilities.maxTextureSize); 27457 image = verifyColorSpace(texture, image); 27458 const glFormat = utils.convert(texture.format, texture.colorSpace); 27459 const glType = utils.convert(texture.type); 27460 let glInternalFormat = getInternalFormat(texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture); 27461 setTextureParameters(textureType, texture); 27462 let mipmap; 27463 const mipmaps = texture.mipmaps; 27464 const useTexStorage = texture.isVideoTexture !== true; 27465 const allocateMemory = sourceProperties.__version === undefined || forceUpload === true; 27466 const dataReady = source.dataReady; 27467 const levels = getMipLevels(texture, image); 27468 if (texture.isDepthTexture) { 27469 glInternalFormat = getInternalDepthFormat(texture.format === DepthStencilFormat, texture.type); 27470 // 27471 if (allocateMemory) { 27472 if (useTexStorage) { 27473 state.texStorage2D(_gl.TEXTURE_2D, 1, glInternalFormat, image.width, image.height); 27474 } else { 27475 state.texImage2D(_gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null); 27476 } 27477 } 27478 } else if (texture.isDataTexture) { 27479 // use manually created mipmaps if available 27480 // if there are no manual mipmaps 27481 // set 0 level mipmap and then use GL to generate other mipmap levels 27482 if (mipmaps.length > 0) { 27483 if (useTexStorage && allocateMemory) { 27484 state.texStorage2D(_gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[0].width, mipmaps[0].height); 27485 } 27486 for(let i = 0, il = mipmaps.length; i < il; i++){ 27487 mipmap = mipmaps[i]; 27488 if (useTexStorage) { 27489 if (dataReady) { 27490 state.texSubImage2D(_gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data); 27491 } 27492 } else { 27493 state.texImage2D(_gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data); 27494 } 27495 } 27496 texture.generateMipmaps = false; 27497 } else { 27498 if (useTexStorage) { 27499 if (allocateMemory) { 27500 state.texStorage2D(_gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height); 27501 } 27502 if (dataReady) { 27503 state.texSubImage2D(_gl.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data); 27504 } 27505 } else { 27506 state.texImage2D(_gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data); 27507 } 27508 } 27509 } else if (texture.isCompressedTexture) { 27510 if (texture.isCompressedArrayTexture) { 27511 if (useTexStorage && allocateMemory) { 27512 state.texStorage3D(_gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, mipmaps[0].width, mipmaps[0].height, image.depth); 27513 } 27514 for(let i = 0, il = mipmaps.length; i < il; i++){ 27515 mipmap = mipmaps[i]; 27516 if (texture.format !== RGBAFormat) { 27517 if (glFormat !== null) { 27518 if (useTexStorage) { 27519 if (dataReady) { 27520 if (texture.layerUpdates.size > 0) { 27521 const layerByteLength = getByteLength(mipmap.width, mipmap.height, texture.format, texture.type); 27522 for (const layerIndex of texture.layerUpdates){ 27523 const layerData = mipmap.data.subarray(layerIndex * layerByteLength / mipmap.data.BYTES_PER_ELEMENT, (layerIndex + 1) * layerByteLength / mipmap.data.BYTES_PER_ELEMENT); 27524 state.compressedTexSubImage3D(_gl.TEXTURE_2D_ARRAY, i, 0, 0, layerIndex, mipmap.width, mipmap.height, 1, glFormat, layerData); 27525 } 27526 texture.clearLayerUpdates(); 27527 } else { 27528 state.compressedTexSubImage3D(_gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data); 27529 } 27530 } 27531 } else { 27532 state.compressedTexImage3D(_gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, mipmap.data, 0, 0); 27533 } 27534 } else { 27535 console.warn('THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()'); 27536 } 27537 } else { 27538 if (useTexStorage) { 27539 if (dataReady) { 27540 state.texSubImage3D(_gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data); 27541 } 27542 } else { 27543 state.texImage3D(_gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, glFormat, glType, mipmap.data); 27544 } 27545 } 27546 } 27547 } else { 27548 if (useTexStorage && allocateMemory) { 27549 state.texStorage2D(_gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[0].width, mipmaps[0].height); 27550 } 27551 for(let i = 0, il = mipmaps.length; i < il; i++){ 27552 mipmap = mipmaps[i]; 27553 if (texture.format !== RGBAFormat) { 27554 if (glFormat !== null) { 27555 if (useTexStorage) { 27556 if (dataReady) { 27557 state.compressedTexSubImage2D(_gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data); 27558 } 27559 } else { 27560 state.compressedTexImage2D(_gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data); 27561 } 27562 } else { 27563 console.warn('THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()'); 27564 } 27565 } else { 27566 if (useTexStorage) { 27567 if (dataReady) { 27568 state.texSubImage2D(_gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data); 27569 } 27570 } else { 27571 state.texImage2D(_gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data); 27572 } 27573 } 27574 } 27575 } 27576 } else if (texture.isDataArrayTexture) { 27577 if (useTexStorage) { 27578 if (allocateMemory) { 27579 state.texStorage3D(_gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, image.width, image.height, image.depth); 27580 } 27581 if (dataReady) { 27582 if (texture.layerUpdates.size > 0) { 27583 const layerByteLength = getByteLength(image.width, image.height, texture.format, texture.type); 27584 for (const layerIndex of texture.layerUpdates){ 27585 const layerData = image.data.subarray(layerIndex * layerByteLength / image.data.BYTES_PER_ELEMENT, (layerIndex + 1) * layerByteLength / image.data.BYTES_PER_ELEMENT); 27586 state.texSubImage3D(_gl.TEXTURE_2D_ARRAY, 0, 0, 0, layerIndex, image.width, image.height, 1, glFormat, glType, layerData); 27587 } 27588 texture.clearLayerUpdates(); 27589 } else { 27590 state.texSubImage3D(_gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data); 27591 } 27592 } 27593 } else { 27594 state.texImage3D(_gl.TEXTURE_2D_ARRAY, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data); 27595 } 27596 } else if (texture.isData3DTexture) { 27597 if (useTexStorage) { 27598 if (allocateMemory) { 27599 state.texStorage3D(_gl.TEXTURE_3D, levels, glInternalFormat, image.width, image.height, image.depth); 27600 } 27601 if (dataReady) { 27602 state.texSubImage3D(_gl.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data); 27603 } 27604 } else { 27605 state.texImage3D(_gl.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data); 27606 } 27607 } else if (texture.isFramebufferTexture) { 27608 if (allocateMemory) { 27609 if (useTexStorage) { 27610 state.texStorage2D(_gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height); 27611 } else { 27612 let width = image.width, height = image.height; 27613 for(let i = 0; i < levels; i++){ 27614 state.texImage2D(_gl.TEXTURE_2D, i, glInternalFormat, width, height, 0, glFormat, glType, null); 27615 width >>= 1; 27616 height >>= 1; 27617 } 27618 } 27619 } 27620 } else { 27621 // regular Texture (image, video, canvas) 27622 // use manually created mipmaps if available 27623 // if there are no manual mipmaps 27624 // set 0 level mipmap and then use GL to generate other mipmap levels 27625 if (mipmaps.length > 0) { 27626 if (useTexStorage && allocateMemory) { 27627 const dimensions = getDimensions(mipmaps[0]); 27628 state.texStorage2D(_gl.TEXTURE_2D, levels, glInternalFormat, dimensions.width, dimensions.height); 27629 } 27630 for(let i = 0, il = mipmaps.length; i < il; i++){ 27631 mipmap = mipmaps[i]; 27632 if (useTexStorage) { 27633 if (dataReady) { 27634 state.texSubImage2D(_gl.TEXTURE_2D, i, 0, 0, glFormat, glType, mipmap); 27635 } 27636 } else { 27637 state.texImage2D(_gl.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap); 27638 } 27639 } 27640 texture.generateMipmaps = false; 27641 } else { 27642 if (useTexStorage) { 27643 if (allocateMemory) { 27644 const dimensions = getDimensions(image); 27645 state.texStorage2D(_gl.TEXTURE_2D, levels, glInternalFormat, dimensions.width, dimensions.height); 27646 } 27647 if (dataReady) { 27648 state.texSubImage2D(_gl.TEXTURE_2D, 0, 0, 0, glFormat, glType, image); 27649 } 27650 } else { 27651 state.texImage2D(_gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image); 27652 } 27653 } 27654 } 27655 if (textureNeedsGenerateMipmaps(texture)) { 27656 generateMipmap(textureType); 27657 } 27658 sourceProperties.__version = source.version; 27659 if (texture.onUpdate) texture.onUpdate(texture); 27660 } 27661 textureProperties.__version = texture.version; 27662 } 27663 function uploadCubeTexture(textureProperties, texture, slot) { 27664 if (texture.image.length !== 6) return; 27665 const forceUpload = initTexture(textureProperties, texture); 27666 const source = texture.source; 27667 state.bindTexture(_gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot); 27668 const sourceProperties = properties.get(source); 27669 if (source.version !== sourceProperties.__version || forceUpload === true) { 27670 state.activeTexture(_gl.TEXTURE0 + slot); 27671 const workingPrimaries = ColorManagement.getPrimaries(ColorManagement.workingColorSpace); 27672 const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries(texture.colorSpace); 27673 const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL; 27674 _gl.pixelStorei(_gl.UNPACK_FLIP_Y_WEBGL, texture.flipY); 27675 _gl.pixelStorei(_gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha); 27676 _gl.pixelStorei(_gl.UNPACK_ALIGNMENT, texture.unpackAlignment); 27677 _gl.pixelStorei(_gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion); 27678 const isCompressed = texture.isCompressedTexture || texture.image[0].isCompressedTexture; 27679 const isDataTexture = texture.image[0] && texture.image[0].isDataTexture; 27680 const cubeImage = []; 27681 for(let i = 0; i < 6; i++){ 27682 if (!isCompressed && !isDataTexture) { 27683 cubeImage[i] = resizeImage(texture.image[i], true, capabilities.maxCubemapSize); 27684 } else { 27685 cubeImage[i] = isDataTexture ? texture.image[i].image : texture.image[i]; 27686 } 27687 cubeImage[i] = verifyColorSpace(texture, cubeImage[i]); 27688 } 27689 const image = cubeImage[0], glFormat = utils.convert(texture.format, texture.colorSpace), glType = utils.convert(texture.type), glInternalFormat = getInternalFormat(texture.internalFormat, glFormat, glType, texture.colorSpace); 27690 const useTexStorage = texture.isVideoTexture !== true; 27691 const allocateMemory = sourceProperties.__version === undefined || forceUpload === true; 27692 const dataReady = source.dataReady; 27693 let levels = getMipLevels(texture, image); 27694 setTextureParameters(_gl.TEXTURE_CUBE_MAP, texture); 27695 let mipmaps; 27696 if (isCompressed) { 27697 if (useTexStorage && allocateMemory) { 27698 state.texStorage2D(_gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, image.width, image.height); 27699 } 27700 for(let i = 0; i < 6; i++){ 27701 mipmaps = cubeImage[i].mipmaps; 27702 for(let j = 0; j < mipmaps.length; j++){ 27703 const mipmap = mipmaps[j]; 27704 if (texture.format !== RGBAFormat) { 27705 if (glFormat !== null) { 27706 if (useTexStorage) { 27707 if (dataReady) { 27708 state.compressedTexSubImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data); 27709 } 27710 } else { 27711 state.compressedTexImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data); 27712 } 27713 } else { 27714 console.warn('THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()'); 27715 } 27716 } else { 27717 if (useTexStorage) { 27718 if (dataReady) { 27719 state.texSubImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data); 27720 } 27721 } else { 27722 state.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data); 27723 } 27724 } 27725 } 27726 } 27727 } else { 27728 mipmaps = texture.mipmaps; 27729 if (useTexStorage && allocateMemory) { 27730 // TODO: Uniformly handle mipmap definitions 27731 // Normal textures and compressed cube textures define base level + mips with their mipmap array 27732 // Uncompressed cube textures use their mipmap array only for mips (no base level) 27733 if (mipmaps.length > 0) levels++; 27734 const dimensions = getDimensions(cubeImage[0]); 27735 state.texStorage2D(_gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, dimensions.width, dimensions.height); 27736 } 27737 for(let i = 0; i < 6; i++){ 27738 if (isDataTexture) { 27739 if (useTexStorage) { 27740 if (dataReady) { 27741 state.texSubImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, cubeImage[i].width, cubeImage[i].height, glFormat, glType, cubeImage[i].data); 27742 } 27743 } else { 27744 state.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, cubeImage[i].width, cubeImage[i].height, 0, glFormat, glType, cubeImage[i].data); 27745 } 27746 for(let j = 0; j < mipmaps.length; j++){ 27747 const mipmap = mipmaps[j]; 27748 const mipmapImage = mipmap.image[i].image; 27749 if (useTexStorage) { 27750 if (dataReady) { 27751 state.texSubImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data); 27752 } 27753 } else { 27754 state.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data); 27755 } 27756 } 27757 } else { 27758 if (useTexStorage) { 27759 if (dataReady) { 27760 state.texSubImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, glFormat, glType, cubeImage[i]); 27761 } 27762 } else { 27763 state.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, glFormat, glType, cubeImage[i]); 27764 } 27765 for(let j = 0; j < mipmaps.length; j++){ 27766 const mipmap = mipmaps[j]; 27767 if (useTexStorage) { 27768 if (dataReady) { 27769 state.texSubImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, glFormat, glType, mipmap.image[i]); 27770 } 27771 } else { 27772 state.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[i]); 27773 } 27774 } 27775 } 27776 } 27777 } 27778 if (textureNeedsGenerateMipmaps(texture)) { 27779 // We assume images for cube map have the same size. 27780 generateMipmap(_gl.TEXTURE_CUBE_MAP); 27781 } 27782 sourceProperties.__version = source.version; 27783 if (texture.onUpdate) texture.onUpdate(texture); 27784 } 27785 textureProperties.__version = texture.version; 27786 } 27787 // Render targets 27788 // Setup storage for target texture and bind it to correct framebuffer 27789 function setupFrameBufferTexture(framebuffer, renderTarget, texture, attachment, textureTarget, level) { 27790 const glFormat = utils.convert(texture.format, texture.colorSpace); 27791 const glType = utils.convert(texture.type); 27792 const glInternalFormat = getInternalFormat(texture.internalFormat, glFormat, glType, texture.colorSpace); 27793 const renderTargetProperties = properties.get(renderTarget); 27794 const textureProperties = properties.get(texture); 27795 textureProperties.__renderTarget = renderTarget; 27796 if (!renderTargetProperties.__hasExternalTextures) { 27797 const width = Math.max(1, renderTarget.width >> level); 27798 const height = Math.max(1, renderTarget.height >> level); 27799 if (textureTarget === _gl.TEXTURE_3D || textureTarget === _gl.TEXTURE_2D_ARRAY) { 27800 state.texImage3D(textureTarget, level, glInternalFormat, width, height, renderTarget.depth, 0, glFormat, glType, null); 27801 } else { 27802 state.texImage2D(textureTarget, level, glInternalFormat, width, height, 0, glFormat, glType, null); 27803 } 27804 } 27805 state.bindFramebuffer(_gl.FRAMEBUFFER, framebuffer); 27806 if (useMultisampledRTT(renderTarget)) { 27807 multisampledRTTExt.framebufferTexture2DMultisampleEXT(_gl.FRAMEBUFFER, attachment, textureTarget, textureProperties.__webglTexture, 0, getRenderTargetSamples(renderTarget)); 27808 } else if (textureTarget === _gl.TEXTURE_2D || textureTarget >= _gl.TEXTURE_CUBE_MAP_POSITIVE_X && textureTarget <= _gl.TEXTURE_CUBE_MAP_NEGATIVE_Z) { 27809 _gl.framebufferTexture2D(_gl.FRAMEBUFFER, attachment, textureTarget, textureProperties.__webglTexture, level); 27810 } 27811 state.bindFramebuffer(_gl.FRAMEBUFFER, null); 27812 } 27813 // Setup storage for internal depth/stencil buffers and bind to correct framebuffer 27814 function setupRenderBufferStorage(renderbuffer, renderTarget, isMultisample) { 27815 _gl.bindRenderbuffer(_gl.RENDERBUFFER, renderbuffer); 27816 if (renderTarget.depthBuffer) { 27817 // retrieve the depth attachment types 27818 const depthTexture = renderTarget.depthTexture; 27819 const depthType = depthTexture && depthTexture.isDepthTexture ? depthTexture.type : null; 27820 const glInternalFormat = getInternalDepthFormat(renderTarget.stencilBuffer, depthType); 27821 const glAttachmentType = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT; 27822 // set up the attachment 27823 const samples = getRenderTargetSamples(renderTarget); 27824 const isUseMultisampledRTT = useMultisampledRTT(renderTarget); 27825 if (isUseMultisampledRTT) { 27826 multisampledRTTExt.renderbufferStorageMultisampleEXT(_gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height); 27827 } else if (isMultisample) { 27828 _gl.renderbufferStorageMultisample(_gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height); 27829 } else { 27830 _gl.renderbufferStorage(_gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height); 27831 } 27832 _gl.framebufferRenderbuffer(_gl.FRAMEBUFFER, glAttachmentType, _gl.RENDERBUFFER, renderbuffer); 27833 } else { 27834 const textures = renderTarget.textures; 27835 for(let i = 0; i < textures.length; i++){ 27836 const texture = textures[i]; 27837 const glFormat = utils.convert(texture.format, texture.colorSpace); 27838 const glType = utils.convert(texture.type); 27839 const glInternalFormat = getInternalFormat(texture.internalFormat, glFormat, glType, texture.colorSpace); 27840 const samples = getRenderTargetSamples(renderTarget); 27841 if (isMultisample && useMultisampledRTT(renderTarget) === false) { 27842 _gl.renderbufferStorageMultisample(_gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height); 27843 } else if (useMultisampledRTT(renderTarget)) { 27844 multisampledRTTExt.renderbufferStorageMultisampleEXT(_gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height); 27845 } else { 27846 _gl.renderbufferStorage(_gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height); 27847 } 27848 } 27849 } 27850 _gl.bindRenderbuffer(_gl.RENDERBUFFER, null); 27851 } 27852 // Setup resources for a Depth Texture for a FBO (needs an extension) 27853 function setupDepthTexture(framebuffer, renderTarget) { 27854 const isCube = renderTarget && renderTarget.isWebGLCubeRenderTarget; 27855 if (isCube) throw new Error('Depth Texture with cube render targets is not supported'); 27856 state.bindFramebuffer(_gl.FRAMEBUFFER, framebuffer); 27857 if (!(renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture)) { 27858 throw new Error('renderTarget.depthTexture must be an instance of THREE.DepthTexture'); 27859 } 27860 const textureProperties = properties.get(renderTarget.depthTexture); 27861 textureProperties.__renderTarget = renderTarget; 27862 // upload an empty depth texture with framebuffer size 27863 if (!textureProperties.__webglTexture || renderTarget.depthTexture.image.width !== renderTarget.width || renderTarget.depthTexture.image.height !== renderTarget.height) { 27864 renderTarget.depthTexture.image.width = renderTarget.width; 27865 renderTarget.depthTexture.image.height = renderTarget.height; 27866 renderTarget.depthTexture.needsUpdate = true; 27867 } 27868 setTexture2D(renderTarget.depthTexture, 0); 27869 const webglDepthTexture = textureProperties.__webglTexture; 27870 const samples = getRenderTargetSamples(renderTarget); 27871 if (renderTarget.depthTexture.format === DepthFormat) { 27872 if (useMultisampledRTT(renderTarget)) { 27873 multisampledRTTExt.framebufferTexture2DMultisampleEXT(_gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples); 27874 } else { 27875 _gl.framebufferTexture2D(_gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0); 27876 } 27877 } else if (renderTarget.depthTexture.format === DepthStencilFormat) { 27878 if (useMultisampledRTT(renderTarget)) { 27879 multisampledRTTExt.framebufferTexture2DMultisampleEXT(_gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples); 27880 } else { 27881 _gl.framebufferTexture2D(_gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0); 27882 } 27883 } else { 27884 throw new Error('Unknown depthTexture format'); 27885 } 27886 } 27887 // Setup GL resources for a non-texture depth buffer 27888 function setupDepthRenderbuffer(renderTarget) { 27889 const renderTargetProperties = properties.get(renderTarget); 27890 const isCube = renderTarget.isWebGLCubeRenderTarget === true; 27891 // if the bound depth texture has changed 27892 if (renderTargetProperties.__boundDepthTexture !== renderTarget.depthTexture) { 27893 // fire the dispose event to get rid of stored state associated with the previously bound depth buffer 27894 const depthTexture = renderTarget.depthTexture; 27895 if (renderTargetProperties.__depthDisposeCallback) { 27896 renderTargetProperties.__depthDisposeCallback(); 27897 } 27898 // set up dispose listeners to track when the currently attached buffer is implicitly unbound 27899 if (depthTexture) { 27900 const disposeEvent = ()=>{ 27901 delete renderTargetProperties.__boundDepthTexture; 27902 delete renderTargetProperties.__depthDisposeCallback; 27903 depthTexture.removeEventListener('dispose', disposeEvent); 27904 }; 27905 depthTexture.addEventListener('dispose', disposeEvent); 27906 renderTargetProperties.__depthDisposeCallback = dis
vendor: 5,662 bytes, lines 27906-28003
27906poseEvent; 27907 } 27908 renderTargetProperties.__boundDepthTexture = depthTexture; 27909 } 27910 if (renderTarget.depthTexture && !renderTargetProperties.__autoAllocateDepthBuffer) { 27911 if (isCube) throw new Error('target.depthTexture not supported in Cube render targets'); 27912 setupDepthTexture(renderTargetProperties.__webglFramebuffer, renderTarget); 27913 } else { 27914 if (isCube) { 27915 renderTargetProperties.__webglDepthbuffer = []; 27916 for(let i = 0; i < 6; i++){ 27917 state.bindFramebuffer(_gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[i]); 27918 if (renderTargetProperties.__webglDepthbuffer[i] === undefined) { 27919 renderTargetProperties.__webglDepthbuffer[i] = _gl.createRenderbuffer(); 27920 setupRenderBufferStorage(renderTargetProperties.__webglDepthbuffer[i], renderTarget, false); 27921 } else { 27922 // attach buffer if it's been created already 27923 const glAttachmentType = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT; 27924 const renderbuffer = renderTargetProperties.__webglDepthbuffer[i]; 27925 _gl.bindRenderbuffer(_gl.RENDERBUFFER, renderbuffer); 27926 _gl.framebufferRenderbuffer(_gl.FRAMEBUFFER, glAttachmentType, _gl.RENDERBUFFER, renderbuffer); 27927 } 27928 } 27929 } else { 27930 state.bindFramebuffer(_gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer); 27931 if (renderTargetProperties.__webglDepthbuffer === undefined) { 27932 renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer(); 27933 setupRenderBufferStorage(renderTargetProperties.__webglDepthbuffer, renderTarget, false); 27934 } else { 27935 // attach buffer if it's been created already 27936 const glAttachmentType = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT; 27937 const renderbuffer = renderTargetProperties.__webglDepthbuffer; 27938 _gl.bindRenderbuffer(_gl.RENDERBUFFER, renderbuffer); 27939 _gl.framebufferRenderbuffer(_gl.FRAMEBUFFER, glAttachmentType, _gl.RENDERBUFFER, renderbuffer); 27940 } 27941 } 27942 } 27943 state.bindFramebuffer(_gl.FRAMEBUFFER, null); 27944 } 27945 // rebind framebuffer with external textures 27946 function rebindTextures(renderTarget, colorTexture, depthTexture) { 27947 const renderTargetProperties = properties.get(renderTarget); 27948 if (colorTexture !== undefined) { 27949 setupFrameBufferTexture(renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, 0); 27950 } 27951 if (depthTexture !== undefined) { 27952 setupDepthRenderbuffer(renderTarget); 27953 } 27954 } 27955 // Set up GL resources for the render target 27956 function setupRenderTarget(renderTarget) { 27957 const texture = renderTarget.texture; 27958 const renderTargetProperties = properties.get(renderTarget); 27959 const textureProperties = properties.get(texture); 27960 renderTarget.addEventListener('dispose', onRenderTargetDispose); 27961 const textures = renderTarget.textures; 27962 const isCube = renderTarget.isWebGLCubeRenderTarget === true; 27963 const isMultipleRenderTargets = textures.length > 1; 27964 if (!isMultipleRenderTargets) { 27965 if (textureProperties.__webglTexture === undefined) { 27966 textureProperties.__webglTexture = _gl.createTexture(); 27967 } 27968 textureProperties.__version = texture.version; 27969 info.memory.textures++; 27970 } 27971 // Setup framebuffer 27972 if (isCube) { 27973 renderTargetProperties.__webglFramebuffer = []; 27974 for(let i = 0; i < 6; i++){ 27975 if (texture.mipmaps && texture.mipmaps.length > 0) { 27976 renderTargetProperties.__webglFramebuffer[i] = []; 27977 for(let level = 0; level < texture.mipmaps.length; level++){ 27978 renderTargetProperties.__webglFramebuffer[i][level] = _gl.createFramebuffer(); 27979 } 27980 } else { 27981 renderTargetProperties.__webglFramebuffer[i] = _gl.createFramebuffer(); 27982 } 27983 } 27984 } else { 27985 if (texture.mipmaps && texture.mipmaps.length > 0) { 27986 renderTargetProperties.__webglFramebuffer = []; 27987 for(let level = 0; level < texture.mipmaps.length; level++){ 27988 renderTargetProperties.__webglFramebuffer[level] = _gl.createFramebuffer(); 27989 } 27990 } else { 27991 renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); 27992 } 27993 if (isMultipleRenderTargets) { 27994 for(let i = 0, il = textures.length; i < il; i++){ 27995 const attachmentProperties = properties.get(textures[i]); 27996 if (attachmentProperties.__webglTexture === undefined) { 27997 attachmentProperties.__webglTexture = _gl.createTexture(); 27998 info.memory.textures++; 27999 } 28000 } 28001 } 28002 if (renderTarget.samples > 0 && useMultisampledRTT(renderTarget) === false) { 28003 renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer();
vendor: 7,582 bytes, lines 28004-28121
28004 renderTargetProperties.__webglColorRenderbuffer = []; 28005 state.bindFramebuffer(_gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer); 28006 for(let i = 0; i < textures.length; i++){ 28007 const texture = textures[i]; 28008 renderTargetProperties.__webglColorRenderbuffer[i] = _gl.createRenderbuffer(); 28009 _gl.bindRenderbuffer(_gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[i]); 28010 const glFormat = utils.convert(texture.format, texture.colorSpace); 28011 const glType = utils.convert(texture.type); 28012 const glInternalFormat = getInternalFormat(texture.internalFormat, glFormat, glType, texture.colorSpace, renderTarget.isXRRenderTarget === true); 28013 const samples = getRenderTargetSamples(renderTarget); 28014 _gl.renderbufferStorageMultisample(_gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height); 28015 _gl.framebufferRenderbuffer(_gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[i]); 28016 } 28017 _gl.bindRenderbuffer(_gl.RENDERBUFFER, null); 28018 if (renderTarget.depthBuffer) { 28019 renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer(); 28020 setupRenderBufferStorage(renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true); 28021 } 28022 state.bindFramebuffer(_gl.FRAMEBUFFER, null); 28023 } 28024 } 28025 // Setup color buffer 28026 if (isCube) { 28027 state.bindTexture(_gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture); 28028 setTextureParameters(_gl.TEXTURE_CUBE_MAP, texture); 28029 for(let i = 0; i < 6; i++){ 28030 if (texture.mipmaps && texture.mipmaps.length > 0) { 28031 for(let level = 0; level < texture.mipmaps.length; level++){ 28032 setupFrameBufferTexture(renderTargetProperties.__webglFramebuffer[i][level], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level); 28033 } 28034 } else { 28035 setupFrameBufferTexture(renderTargetProperties.__webglFramebuffer[i], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0); 28036 } 28037 } 28038 if (textureNeedsGenerateMipmaps(texture)) { 28039 generateMipmap(_gl.TEXTURE_CUBE_MAP); 28040 } 28041 state.unbindTexture(); 28042 } else if (isMultipleRenderTargets) { 28043 for(let i = 0, il = textures.length; i < il; i++){ 28044 const attachment = textures[i]; 28045 const attachmentProperties = properties.get(attachment); 28046 state.bindTexture(_gl.TEXTURE_2D, attachmentProperties.__webglTexture); 28047 setTextureParameters(_gl.TEXTURE_2D, attachment); 28048 setupFrameBufferTexture(renderTargetProperties.__webglFramebuffer, renderTarget, attachment, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, 0); 28049 if (textureNeedsGenerateMipmaps(attachment)) { 28050 generateMipmap(_gl.TEXTURE_2D); 28051 } 28052 } 28053 state.unbindTexture(); 28054 } else { 28055 let glTextureType = _gl.TEXTURE_2D; 28056 if (renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget) { 28057 glTextureType = renderTarget.isWebGL3DRenderTarget ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY; 28058 } 28059 state.bindTexture(glTextureType, textureProperties.__webglTexture); 28060 setTextureParameters(glTextureType, texture); 28061 if (texture.mipmaps && texture.mipmaps.length > 0) { 28062 for(let level = 0; level < texture.mipmaps.length; level++){ 28063 setupFrameBufferTexture(renderTargetProperties.__webglFramebuffer[level], renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, level); 28064 } 28065 } else { 28066 setupFrameBufferTexture(renderTargetProperties.__webglFramebuffer, renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, 0); 28067 } 28068 if (textureNeedsGenerateMipmaps(texture)) { 28069 generateMipmap(glTextureType); 28070 } 28071 state.unbindTexture(); 28072 } 28073 // Setup depth and stencil buffers 28074 if (renderTarget.depthBuffer) { 28075 setupDepthRenderbuffer(renderTarget); 28076 } 28077 } 28078 function updateRenderTargetMipmap(renderTarget) { 28079 const textures = renderTarget.textures; 28080 for(let i = 0, il = textures.length; i < il; i++){ 28081 const texture = textures[i]; 28082 if (textureNeedsGenerateMipmaps(texture)) { 28083 const targetType = getTargetType(renderTarget); 28084 const webglTexture = properties.get(texture).__webglTexture; 28085 state.bindTexture(targetType, webglTexture); 28086 generateMipmap(targetType); 28087 state.unbindTexture(); 28088 } 28089 } 28090 } 28091 const invalidationArrayRead = []; 28092 const invalidationArrayDraw = []; 28093 function updateMultisampleRenderTarget(renderTarget) { 28094 if (renderTarget.samples > 0) { 28095 if (useMultisampledRTT(renderTarget) === false) { 28096 const textures = renderTarget.textures; 28097 const width = renderTarget.width; 28098 const height = renderTarget.height; 28099 let mask = _gl.COLOR_BUFFER_BIT; 28100 const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT; 28101 const renderTargetProperties = properties.get(renderTarget); 28102 const isMultipleRenderTargets = textures.length > 1; 28103 // If MRT we need to remove FBO attachments 28104 if (isMultipleRenderTargets) { 28105 for(let i = 0; i < textures.length; i++){ 28106 state.bindFramebuffer(_gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer); 28107 _gl.framebufferRenderbuffer(_gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, null); 28108 state.bindFramebuffer(_gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer); 28109 _gl.framebufferTexture2D(_gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, null, 0); 28110 } 28111 } 28112 state.bindFramebuffer(_gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer); 28113 state.bindFramebuffer(_gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer); 28114 for(let i = 0; i < textures.length; i++){ 28115 if (renderTarget.resolveDepthBuffer) { 28116 if (renderTarget.depthBuffer) mask |= _gl.DEPTH_BUFFER_BIT; 28117 // resolving stencil is slow with a D3D backend. disable it for all transmission render targets (see #27799) 28118 if (renderTarget.stencilBuffer && renderTarget.resolveStencilBuffer) mask |= _gl.STENCIL_BUFFER_BIT; 28119 } 28120 if (isMultipleRenderTargets) { 28121 _gl.framebufferRenderbuffer(_gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRen
vendor: 4,605 bytes, lines 28121-28196
28121derbuffer[i]); 28122 const webglTexture = properties.get(textures[i]).__webglTexture; 28123 _gl.framebufferTexture2D(_gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, webglTexture, 0); 28124 } 28125 _gl.blitFramebuffer(0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST); 28126 if (supportsInvalidateFramebuffer === true) { 28127 invalidationArrayRead.length = 0; 28128 invalidationArrayDraw.length = 0; 28129 invalidationArrayRead.push(_gl.COLOR_ATTACHMENT0 + i); 28130 if (renderTarget.depthBuffer && renderTarget.resolveDepthBuffer === false) { 28131 invalidationArrayRead.push(depthStyle); 28132 invalidationArrayDraw.push(depthStyle); 28133 _gl.invalidateFramebuffer(_gl.DRAW_FRAMEBUFFER, invalidationArrayDraw); 28134 } 28135 _gl.invalidateFramebuffer(_gl.READ_FRAMEBUFFER, invalidationArrayRead); 28136 } 28137 } 28138 state.bindFramebuffer(_gl.READ_FRAMEBUFFER, null); 28139 state.bindFramebuffer(_gl.DRAW_FRAMEBUFFER, null); 28140 // If MRT since pre-blit we removed the FBO we need to reconstruct the attachments 28141 if (isMultipleRenderTargets) { 28142 for(let i = 0; i < textures.length; i++){ 28143 state.bindFramebuffer(_gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer); 28144 _gl.framebufferRenderbuffer(_gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[i]); 28145 const webglTexture = properties.get(textures[i]).__webglTexture; 28146 state.bindFramebuffer(_gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer); 28147 _gl.framebufferTexture2D(_gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, webglTexture, 0); 28148 } 28149 } 28150 state.bindFramebuffer(_gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer); 28151 } else { 28152 if (renderTarget.depthBuffer && renderTarget.resolveDepthBuffer === false && supportsInvalidateFramebuffer) { 28153 const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT; 28154 _gl.invalidateFramebuffer(_gl.DRAW_FRAMEBUFFER, [ 28155 depthStyle 28156 ]); 28157 } 28158 } 28159 } 28160 } 28161 function getRenderTargetSamples(renderTarget) { 28162 return Math.min(capabilities.maxSamples, renderTarget.samples); 28163 } 28164 function useMultisampledRTT(renderTarget) { 28165 const renderTargetProperties = properties.get(renderTarget); 28166 return renderTarget.samples > 0 && extensions.has('WEBGL_multisampled_render_to_texture') === true && renderTargetProperties.__useRenderToTexture !== false; 28167 } 28168 function updateVideoTexture(texture) { 28169 const frame = info.render.frame; 28170 // Check the last frame we updated the VideoTexture 28171 if (_videoTextures.get(texture) !== frame) { 28172 _videoTextures.set(texture, frame); 28173 texture.update(); 28174 } 28175 } 28176 function verifyColorSpace(texture, image) { 28177 const colorSpace = texture.colorSpace; 28178 const format = texture.format; 28179 const type = texture.type; 28180 if (texture.isCompressedTexture === true || texture.isVideoTexture === true) return image; 28181 if (colorSpace !== LinearSRGBColorSpace && colorSpace !== NoColorSpace) { 28182 // sRGB 28183 if (ColorManagement.getTransfer(colorSpace) === SRGBTransfer) { 28184 // in WebGL 2 uncompressed textures can only be sRGB encoded if they have the RGBA8 format 28185 if (format !== RGBAFormat || type !== UnsignedByteType) { 28186 console.warn('THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType.'); 28187 } 28188 } else { 28189 console.error('THREE.WebGLTextures: Unsupported texture color space:', colorSpace); 28190 } 28191 } 28192 return image; 28193 } 28194 function getDimensions(image) { 28195 if (typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement) { 28196 // if intrinsic data are not available, fallback to width/height
vendor: 14,125 bytes, lines 28197-28466
28197 _imageDimensions.width = image.naturalWidth || image.width; 28198 _imageDimensions.height = image.naturalHeight || image.height; 28199 } else if (typeof VideoFrame !== 'undefined' && image instanceof VideoFrame) { 28200 _imageDimensions.width = image.displayWidth; 28201 _imageDimensions.height = image.displayHeight; 28202 } else { 28203 _imageDimensions.width = image.width; 28204 _imageDimensions.height = image.height; 28205 } 28206 return _imageDimensions; 28207 } 28208 // 28209 this.allocateTextureUnit = allocateTextureUnit; 28210 this.resetTextureUnits = resetTextureUnits; 28211 this.setTexture2D = setTexture2D; 28212 this.setTexture2DArray = setTexture2DArray; 28213 this.setTexture3D = setTexture3D; 28214 this.setTextureCube = setTextureCube; 28215 this.rebindTextures = rebindTextures; 28216 this.setupRenderTarget = setupRenderTarget; 28217 this.updateRenderTargetMipmap = updateRenderTargetMipmap; 28218 this.updateMultisampleRenderTarget = updateMultisampleRenderTarget; 28219 this.setupDepthRenderbuffer = setupDepthRenderbuffer; 28220 this.setupFrameBufferTexture = setupFrameBufferTexture; 28221 this.useMultisampledRTT = useMultisampledRTT; 28222 } 28223 function WebGLUtils(gl, extensions) { 28224 function convert(p, colorSpace = NoColorSpace) { 28225 let extension; 28226 const transfer = ColorManagement.getTransfer(colorSpace); 28227 if (p === UnsignedByteType) return gl.UNSIGNED_BYTE; 28228 if (p === UnsignedShort4444Type) return gl.UNSIGNED_SHORT_4_4_4_4; 28229 if (p === UnsignedShort5551Type) return gl.UNSIGNED_SHORT_5_5_5_1; 28230 if (p === UnsignedInt5999Type) return gl.UNSIGNED_INT_5_9_9_9_REV; 28231 if (p === ByteType) return gl.BYTE; 28232 if (p === ShortType) return gl.SHORT; 28233 if (p === UnsignedShortType) return gl.UNSIGNED_SHORT; 28234 if (p === IntType) return gl.INT; 28235 if (p === UnsignedIntType) return gl.UNSIGNED_INT; 28236 if (p === FloatType) return gl.FLOAT; 28237 if (p === HalfFloatType) return gl.HALF_FLOAT; 28238 if (p === AlphaFormat) return gl.ALPHA; 28239 if (p === RGBFormat) return gl.RGB; 28240 if (p === RGBAFormat) return gl.RGBA; 28241 if (p === LuminanceFormat) return gl.LUMINANCE; 28242 if (p === LuminanceAlphaFormat) return gl.LUMINANCE_ALPHA; 28243 if (p === DepthFormat) return gl.DEPTH_COMPONENT; 28244 if (p === DepthStencilFormat) return gl.DEPTH_STENCIL; 28245 // WebGL2 formats. 28246 if (p === RedFormat) return gl.RED; 28247 if (p === RedIntegerFormat) return gl.RED_INTEGER; 28248 if (p === RGFormat) return gl.RG; 28249 if (p === RGIntegerFormat) return gl.RG_INTEGER; 28250 if (p === RGBAIntegerFormat) return gl.RGBA_INTEGER; 28251 // S3TC 28252 if (p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format) { 28253 if (transfer === SRGBTransfer) { 28254 extension = extensions.get('WEBGL_compressed_texture_s3tc_srgb'); 28255 if (extension !== null) { 28256 if (p === RGB_S3TC_DXT1_Format) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT; 28257 if (p === RGBA_S3TC_DXT1_Format) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; 28258 if (p === RGBA_S3TC_DXT3_Format) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; 28259 if (p === RGBA_S3TC_DXT5_Format) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; 28260 } else { 28261 return null; 28262 } 28263 } else { 28264 extension = extensions.get('WEBGL_compressed_texture_s3tc'); 28265 if (extension !== null) { 28266 if (p === RGB_S3TC_DXT1_Format) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; 28267 if (p === RGBA_S3TC_DXT1_Format) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; 28268 if (p === RGBA_S3TC_DXT3_Format) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; 28269 if (p === RGBA_S3TC_DXT5_Format) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; 28270 } else { 28271 return null; 28272 } 28273 } 28274 } 28275 // PVRTC 28276 if (p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format) { 28277 extension = extensions.get('WEBGL_compressed_texture_pvrtc'); 28278 if (extension !== null) { 28279 if (p === RGB_PVRTC_4BPPV1_Format) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; 28280 if (p === RGB_PVRTC_2BPPV1_Format) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; 28281 if (p === RGBA_PVRTC_4BPPV1_Format) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; 28282 if (p === RGBA_PVRTC_2BPPV1_Format) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; 28283 } else { 28284 return null; 28285 } 28286 } 28287 // ETC 28288 if (p === RGB_ETC1_Format || p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format) { 28289 extension = extensions.get('WEBGL_compressed_texture_etc'); 28290 if (extension !== null) { 28291 if (p === RGB_ETC1_Format || p === RGB_ETC2_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2; 28292 if (p === RGBA_ETC2_EAC_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC; 28293 } else { 28294 return null; 28295 } 28296 } 28297 // ASTC 28298 if (p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format || p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format || p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format || p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format || p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format) { 28299 extension = extensions.get('WEBGL_compressed_texture_astc'); 28300 if (extension !== null) { 28301 if (p === RGBA_ASTC_4x4_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR; 28302 if (p === RGBA_ASTC_5x4_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR; 28303 if (p === RGBA_ASTC_5x5_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR; 28304 if (p === RGBA_ASTC_6x5_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR; 28305 if (p === RGBA_ASTC_6x6_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR; 28306 if (p === RGBA_ASTC_8x5_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR; 28307 if (p === RGBA_ASTC_8x6_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR; 28308 if (p === RGBA_ASTC_8x8_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR; 28309 if (p === RGBA_ASTC_10x5_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR; 28310 if (p === RGBA_ASTC_10x6_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR; 28311 if (p === RGBA_ASTC_10x8_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR; 28312 if (p === RGBA_ASTC_10x10_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR; 28313 if (p === RGBA_ASTC_12x10_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR; 28314 if (p === RGBA_ASTC_12x12_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR; 28315 } else { 28316 return null; 28317 } 28318 } 28319 // BPTC 28320 if (p === RGBA_BPTC_Format || p === RGB_BPTC_SIGNED_Format || p === RGB_BPTC_UNSIGNED_Format) { 28321 extension = extensions.get('EXT_texture_compression_bptc'); 28322 if (extension !== null) { 28323 if (p === RGBA_BPTC_Format) return transfer === SRGBTransfer ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT; 28324 if (p === RGB_BPTC_SIGNED_Format) return extension.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT; 28325 if (p === RGB_BPTC_UNSIGNED_Format) return extension.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT; 28326 } else { 28327 return null; 28328 } 28329 } 28330 // RGTC 28331 if (p === RED_RGTC1_Format || p === SIGNED_RED_RGTC1_Format || p === RED_GREEN_RGTC2_Format || p === SIGNED_RED_GREEN_RGTC2_Format) { 28332 extension = extensions.get('EXT_texture_compression_rgtc'); 28333 if (extension !== null) { 28334 if (p === RGBA_BPTC_Format) return extension.COMPRESSED_RED_RGTC1_EXT; 28335 if (p === SIGNED_RED_RGTC1_Format) return extension.COMPRESSED_SIGNED_RED_RGTC1_EXT; 28336 if (p === RED_GREEN_RGTC2_Format) return extension.COMPRESSED_RED_GREEN_RGTC2_EXT; 28337 if (p === SIGNED_RED_GREEN_RGTC2_Format) return extension.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT; 28338 } else { 28339 return null; 28340 } 28341 } 28342 // 28343 if (p === UnsignedInt248Type) return gl.UNSIGNED_INT_24_8; 28344 // if "p" can't be resolved, assume the user defines a WebGL constant as a string (fallback/workaround for packed RGB formats) 28345 return gl[p] !== undefined ? gl[p] : null; 28346 } 28347 return { 28348 convert: convert 28349 }; 28350 } 28351 const _occlusion_vertex = ` 28352void main() { 28353 28354 gl_Position = vec4( position, 1.0 ); 28355 28356}`; 28357 const _occlusion_fragment = ` 28358uniform sampler2DArray depthColor; 28359uniform float depthWidth; 28360uniform float depthHeight; 28361 28362void main() { 28363 28364 vec2 coord = vec2( gl_FragCoord.x / depthWidth, gl_FragCoord.y / depthHeight ); 28365 28366 if ( coord.x >= 1.0 ) { 28367 28368 gl_FragDepth = texture( depthColor, vec3( coord.x - 1.0, coord.y, 1 ) ).r; 28369 28370 } else { 28371 28372 gl_FragDepth = texture( depthColor, vec3( coord.x, coord.y, 0 ) ).r; 28373 28374 } 28375 28376}`; 28377 class WebXRDepthSensing { 28378 init(renderer, depthData, renderState) { 28379 if (this.texture === null) { 28380 const texture = new Texture$1(); 28381 const texProps = renderer.properties.get(texture); 28382 texProps.__webglTexture = depthData.texture; 28383 if (depthData.depthNear !== renderState.depthNear || depthData.depthFar !== renderState.depthFar) { 28384 this.depthNear = depthData.depthNear; 28385 this.depthFar = depthData.depthFar; 28386 } 28387 this.texture = texture; 28388 } 28389 } 28390 getMesh(cameraXR) { 28391 if (this.texture !== null) { 28392 if (this.mesh === null) { 28393 const viewport = cameraXR.cameras[0].viewport; 28394 const material = new ShaderMaterial({ 28395 vertexShader: _occlusion_vertex, 28396 fragmentShader: _occlusion_fragment, 28397 uniforms: { 28398 depthColor: { 28399 value: this.texture 28400 }, 28401 depthWidth: { 28402 value: viewport.z 28403 }, 28404 depthHeight: { 28405 value: viewport.w 28406 } 28407 } 28408 }); 28409 this.mesh = new Mesh(new PlaneGeometry(20, 20), material); 28410 } 28411 } 28412 return this.mesh; 28413 } 28414 reset() { 28415 this.texture = null; 28416 this.mesh = null; 28417 } 28418 getDepthTexture() { 28419 return this.texture; 28420 } 28421 constructor(){ 28422 this.texture = null; 28423 this.mesh = null; 28424 this.depthNear = 0; 28425 this.depthFar = 0; 28426 } 28427 } 28428 class WebXRManager extends EventDispatcher { 28429 constructor(renderer, gl){ 28430 super(); 28431 const scope = this; 28432 let session = null; 28433 let framebufferScaleFactor = 1.0; 28434 let referenceSpace = null; 28435 let referenceSpaceType = 'local-floor'; 28436 // Set default foveation to maximum. 28437 let foveation = 1.0; 28438 let customReferenceSpace = null; 28439 let pose = null; 28440 let glBinding = null; 28441 let glProjLayer = null; 28442 let glBaseLayer = null; 28443 let xrFrame = null; 28444 const depthSensing = new WebXRDepthSensing(); 28445 const attributes = gl.getContextAttributes(); 28446 let initialRenderTarget = null; 28447 let newRenderTarget = null; 28448 const controllers = []; 28449 const controllerInputSources = []; 28450 const currentSize = new Vector2(); 28451 let currentPixelRatio = null; 28452 // 28453 const cameraL = new PerspectiveCamera(); 28454 cameraL.viewport = new Vector4(); 28455 const cameraR = new PerspectiveCamera(); 28456 cameraR.viewport = new Vector4(); 28457 const cameras = [ 28458 cameraL, 28459 cameraR 28460 ]; 28461 const cameraXR = new ArrayCamera(); 28462 let _currentDepthNear = null; 28463 let _currentDepthFar = null; 28464 // 28465 this.cameraAutoUpdate = true; 28466 this.enabled = false;
vendor: 4,305 bytes, lines 28467-28567
28467 this.isPresenting = false; 28468 this.getController = function(index) { 28469 let controller = controllers[index]; 28470 if (controller === undefined) { 28471 controller = new WebXRController(); 28472 controllers[index] = controller; 28473 } 28474 return controller.getTargetRaySpace(); 28475 }; 28476 this.getControllerGrip = function(index) { 28477 let controller = controllers[index]; 28478 if (controller === undefined) { 28479 controller = new WebXRController(); 28480 controllers[index] = controller; 28481 } 28482 return controller.getGripSpace(); 28483 }; 28484 this.getHand = function(index) { 28485 let controller = controllers[index]; 28486 if (controller === undefined) { 28487 controller = new WebXRController(); 28488 controllers[index] = controller; 28489 } 28490 return controller.getHandSpace(); 28491 }; 28492 // 28493 function onSessionEvent(event) { 28494 const controllerIndex = controllerInputSources.indexOf(event.inputSource); 28495 if (controllerIndex === -1) { 28496 return; 28497 } 28498 const controller = controllers[controllerIndex]; 28499 if (controller !== undefined) { 28500 controller.update(event.inputSource, event.frame, customReferenceSpace || referenceSpace); 28501 controller.dispatchEvent({ 28502 type: event.type, 28503 data: event.inputSource 28504 }); 28505 } 28506 } 28507 function onSessionEnd() { 28508 session.removeEventListener('select', onSessionEvent); 28509 session.removeEventListener('selectstart', onSessionEvent); 28510 session.removeEventListener('selectend', onSessionEvent); 28511 session.removeEventListener('squeeze', onSessionEvent); 28512 session.removeEventListener('squeezestart', onSessionEvent); 28513 session.removeEventListener('squeezeend', onSessionEvent); 28514 session.removeEventListener('end', onSessionEnd); 28515 session.removeEventListener('inputsourceschange', onInputSourcesChange); 28516 for(let i = 0; i < controllers.length; i++){ 28517 const inputSource = controllerInputSources[i]; 28518 if (inputSource === null) continue; 28519 controllerInputSources[i] = null; 28520 controllers[i].disconnect(inputSource); 28521 } 28522 _currentDepthNear = null; 28523 _currentDepthFar = null; 28524 depthSensing.reset(); 28525 // restore framebuffer/rendering state 28526 renderer.setRenderTarget(initialRenderTarget); 28527 glBaseLayer = null; 28528 glProjLayer = null; 28529 glBinding = null; 28530 session = null; 28531 newRenderTarget = null; 28532 // 28533 animation.stop(); 28534 scope.isPresenting = false; 28535 renderer.setPixelRatio(currentPixelRatio); 28536 renderer.setSize(currentSize.width, currentSize.height, false); 28537 scope.dispatchEvent({ 28538 type: 'sessionend' 28539 }); 28540 } 28541 this.setFramebufferScaleFactor = function(value) { 28542 framebufferScaleFactor = value; 28543 if (scope.isPresenting === true) { 28544 console.warn('THREE.WebXRManager: Cannot change framebuffer scale while presenting.'); 28545 } 28546 }; 28547 this.setReferenceSpaceType = function(value) { 28548 referenceSpaceType = value; 28549 if (scope.isPresenting === true) { 28550 console.warn('THREE.WebXRManager: Cannot change reference space type while presenting.'); 28551 } 28552 }; 28553 this.getReferenceSpace = function() { 28554 return customReferenceSpace || referenceSpace; 28555 }; 28556 this.setReferenceSpace = function(space) { 28557 customReferenceSpace = space; 28558 }; 28559 this.getBaseLayer = function() { 28560 return glProjLayer !== null ? glProjLayer : glBaseLayer; 28561 }; 28562 this.getBinding = function() { 28563 return glBinding; 28564 }; 28565 this.getFrame = function() { 28566 return xrFrame; 28567 };
vendor: 14,856 bytes, lines 28568-28849
28568 this.getSession = function() { 28569 return session; 28570 }; 28571 this.setSession = async function(value) { 28572 session = value; 28573 if (session !== null) { 28574 initialRenderTarget = renderer.getRenderTarget(); 28575 session.addEventListener('select', onSessionEvent); 28576 session.addEventListener('selectstart', onSessionEvent); 28577 session.addEventListener('selectend', onSessionEvent); 28578 session.addEventListener('squeeze', onSessionEvent); 28579 session.addEventListener('squeezestart', onSessionEvent); 28580 session.addEventListener('squeezeend', onSessionEvent); 28581 session.addEventListener('end', onSessionEnd); 28582 session.addEventListener('inputsourceschange', onInputSourcesChange); 28583 if (attributes.xrCompatible !== true) { 28584 await gl.makeXRCompatible(); 28585 } 28586 currentPixelRatio = renderer.getPixelRatio(); 28587 renderer.getSize(currentSize); 28588 // Check that the browser implements the necessary APIs to use an 28589 // XRProjectionLayer rather than an XRWebGLLayer 28590 const useLayers = typeof XRWebGLBinding !== 'undefined' && 'createProjectionLayer' in XRWebGLBinding.prototype; 28591 if (!useLayers) { 28592 const layerInit = { 28593 antialias: attributes.antialias, 28594 alpha: true, 28595 depth: attributes.depth, 28596 stencil: attributes.stencil, 28597 framebufferScaleFactor: framebufferScaleFactor 28598 }; 28599 glBaseLayer = new XRWebGLLayer(session, gl, layerInit); 28600 session.updateRenderState({ 28601 baseLayer: glBaseLayer 28602 }); 28603 renderer.setPixelRatio(1); 28604 renderer.setSize(glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, false); 28605 newRenderTarget = new WebGLRenderTarget(glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, { 28606 format: RGBAFormat, 28607 type: UnsignedByteType, 28608 colorSpace: renderer.outputColorSpace, 28609 stencilBuffer: attributes.stencil, 28610 resolveDepthBuffer: glBaseLayer.ignoreDepthValues === false, 28611 resolveStencilBuffer: glBaseLayer.ignoreDepthValues === false 28612 }); 28613 } else { 28614 let depthFormat = null; 28615 let depthType = null; 28616 let glDepthFormat = null; 28617 if (attributes.depth) { 28618 glDepthFormat = attributes.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24; 28619 depthFormat = attributes.stencil ? DepthStencilFormat : DepthFormat; 28620 depthType = attributes.stencil ? UnsignedInt248Type : UnsignedIntType; 28621 } 28622 const projectionlayerInit = { 28623 colorFormat: gl.RGBA8, 28624 depthFormat: glDepthFormat, 28625 scaleFactor: framebufferScaleFactor 28626 }; 28627 glBinding = new XRWebGLBinding(session, gl); 28628 glProjLayer = glBinding.createProjectionLayer(projectionlayerInit); 28629 session.updateRenderState({ 28630 layers: [ 28631 glProjLayer 28632 ] 28633 }); 28634 renderer.setPixelRatio(1); 28635 renderer.setSize(glProjLayer.textureWidth, glProjLayer.textureHeight, false); 28636 newRenderTarget = new WebGLRenderTarget(glProjLayer.textureWidth, glProjLayer.textureHeight, { 28637 format: RGBAFormat, 28638 type: UnsignedByteType, 28639 depthTexture: new DepthTexture(glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat), 28640 stencilBuffer: attributes.stencil, 28641 colorSpace: renderer.outputColorSpace, 28642 samples: attributes.antialias ? 4 : 0, 28643 resolveDepthBuffer: glProjLayer.ignoreDepthValues === false, 28644 resolveStencilBuffer: glProjLayer.ignoreDepthValues === false 28645 }); 28646 } 28647 newRenderTarget.isXRRenderTarget = true; // TODO Remove this when possible, see #23278 28648 this.setFoveation(foveation); 28649 customReferenceSpace = null; 28650 referenceSpace = await session.requestReferenceSpace(referenceSpaceType); 28651 animation.setContext(session); 28652 animation.start(); 28653 scope.isPresenting = true; 28654 scope.dispatchEvent({ 28655 type: 'sessionstart' 28656 }); 28657 } 28658 }; 28659 this.getEnvironmentBlendMode = function() { 28660 if (session !== null) { 28661 return session.environmentBlendMode; 28662 } 28663 }; 28664 this.getDepthTexture = function() { 28665 return depthSensing.getDepthTexture(); 28666 }; 28667 function onInputSourcesChange(event) { 28668 // Notify disconnected 28669 for(let i = 0; i < event.removed.length; i++){ 28670 const inputSource = event.removed[i]; 28671 const index = controllerInputSources.indexOf(inputSource); 28672 if (index >= 0) { 28673 controllerInputSources[index] = null; 28674 controllers[index].disconnect(inputSource); 28675 } 28676 } 28677 // Notify connected 28678 for(let i = 0; i < event.added.length; i++){ 28679 const inputSource = event.added[i]; 28680 let controllerIndex = controllerInputSources.indexOf(inputSource); 28681 if (controllerIndex === -1) { 28682 // Assign input source a controller that currently has no input source 28683 for(let i = 0; i < controllers.length; i++){ 28684 if (i >= controllerInputSources.length) { 28685 controllerInputSources.push(inputSource); 28686 controllerIndex = i; 28687 break; 28688 } else if (controllerInputSources[i] === null) { 28689 controllerInputSources[i] = inputSource; 28690 controllerIndex = i; 28691 break; 28692 } 28693 } 28694 // If all controllers do currently receive input we ignore new ones 28695 if (controllerIndex === -1) break; 28696 } 28697 const controller = controllers[controllerIndex]; 28698 if (controller) { 28699 controller.connect(inputSource); 28700 } 28701 } 28702 } 28703 // 28704 const cameraLPos = new Vector3(); 28705 const cameraRPos = new Vector3(); 28706 /** 28707 * Assumes 2 cameras that are parallel and share an X-axis, and that 28708 * the cameras' projection and world matrices have already been set. 28709 * And that near and far planes are identical for both cameras. 28710 * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765 28711 * 28712 * @param {ArrayCamera} camera - The camera to update. 28713 * @param {PerspectiveCamera} cameraL - The left camera. 28714 * @param {PerspectiveCamera} cameraR - The right camera. 28715 */ function setProjectionFromUnion(camera, cameraL, cameraR) { 28716 cameraLPos.setFromMatrixPosition(cameraL.matrixWorld); 28717 cameraRPos.setFromMatrixPosition(cameraR.matrixWorld); 28718 const ipd = cameraLPos.distanceTo(cameraRPos); 28719 const projL = cameraL.projectionMatrix.elements; 28720 const projR = cameraR.projectionMatrix.elements; 28721 // VR systems will have identical far and near planes, and 28722 // most likely identical top and bottom frustum extents. 28723 // Use the left camera for these values. 28724 const near = projL[14] / (projL[10] - 1); 28725 const far = projL[14] / (projL[10] + 1); 28726 const topFov = (projL[9] + 1) / projL[5]; 28727 const bottomFov = (projL[9] - 1) / projL[5]; 28728 const leftFov = (projL[8] - 1) / projL[0]; 28729 const rightFov = (projR[8] + 1) / projR[0]; 28730 const left = near * leftFov; 28731 const right = near * rightFov; 28732 // Calculate the new camera's position offset from the 28733 // left camera. xOffset should be roughly half `ipd`. 28734 const zOffset = ipd / (-leftFov + rightFov); 28735 const xOffset = zOffset * -leftFov; 28736 // TODO: Better way to apply this offset? 28737 cameraL.matrixWorld.decompose(camera.position, camera.quaternion, camera.scale); 28738 camera.translateX(xOffset); 28739 camera.translateZ(zOffset); 28740 camera.matrixWorld.compose(camera.position, camera.quaternion, camera.scale); 28741 camera.matrixWorldInverse.copy(camera.matrixWorld).invert(); 28742 // Check if the projection uses an infinite far plane. 28743 if (projL[10] === -1) { 28744 // Use the projection matrix from the left eye. 28745 // The camera offset is sufficient to include the view volumes 28746 // of both eyes (assuming symmetric projections). 28747 camera.projectionMatrix.copy(cameraL.projectionMatrix); 28748 camera.projectionMatrixInverse.copy(cameraL.projectionMatrixInverse); 28749 } else { 28750 // Find the union of the frustum values of the cameras and scale 28751 // the values so that the near plane's position does not change in world space, 28752 // although must now be relative to the new union camera. 28753 const near2 = near + zOffset; 28754 const far2 = far + zOffset; 28755 const left2 = left - xOffset; 28756 const right2 = right + (ipd - xOffset); 28757 const top2 = topFov * far / far2 * near2; 28758 const bottom2 = bottomFov * far / far2 * near2; 28759 camera.projectionMatrix.makePerspective(left2, right2, top2, bottom2, near2, far2); 28760 camera.projectionMatrixInverse.copy(camera.projectionMatrix).invert(); 28761 } 28762 } 28763 function updateCamera(camera, parent) { 28764 if (parent === null) { 28765 camera.matrixWorld.copy(camera.matrix); 28766 } else { 28767 camera.matrixWorld.multiplyMatrices(parent.matrixWorld, camera.matrix); 28768 } 28769 camera.matrixWorldInverse.copy(camera.matrixWorld).invert(); 28770 } 28771 this.updateCamera = function(camera) { 28772 if (session === null) return; 28773 let depthNear = camera.near; 28774 let depthFar = camera.far; 28775 if (depthSensing.texture !== null) { 28776 if (depthSensing.depthNear > 0) depthNear = depthSensing.depthNear; 28777 if (depthSensing.depthFar > 0) depthFar = depthSensing.depthFar; 28778 } 28779 cameraXR.near = cameraR.near = cameraL.near = depthNear; 28780 cameraXR.far = cameraR.far = cameraL.far = depthFar; 28781 if (_currentDepthNear !== cameraXR.near || _currentDepthFar !== cameraXR.far) { 28782 // Note that the new renderState won't apply until the next frame. See #18320 28783 session.updateRenderState({ 28784 depthNear: cameraXR.near, 28785 depthFar: cameraXR.far 28786 }); 28787 _currentDepthNear = cameraXR.near; 28788 _currentDepthFar = cameraXR.far; 28789 } 28790 cameraL.layers.mask = camera.layers.mask | 0b010; 28791 cameraR.layers.mask = camera.layers.mask | 0b100; 28792 cameraXR.layers.mask = cameraL.layers.mask | cameraR.layers.mask; 28793 const parent = camera.parent; 28794 const cameras = cameraXR.cameras; 28795 updateCamera(cameraXR, parent); 28796 for(let i = 0; i < cameras.length; i++){ 28797 updateCamera(cameras[i], parent); 28798 } 28799 // update projection matrix for proper view frustum culling 28800 if (cameras.length === 2) { 28801 setProjectionFromUnion(cameraXR, cameraL, cameraR); 28802 } else { 28803 // assume single camera setup (AR) 28804 cameraXR.projectionMatrix.copy(cameraL.projectionMatrix); 28805 } 28806 // update user camera and its children 28807 updateUserCamera(camera, cameraXR, parent); 28808 }; 28809 function updateUserCamera(camera, cameraXR, parent) { 28810 if (parent === null) { 28811 camera.matrix.copy(cameraXR.matrixWorld); 28812 } else { 28813 camera.matrix.copy(parent.matrixWorld); 28814 camera.matrix.invert(); 28815 camera.matrix.multiply(cameraXR.matrixWorld); 28816 } 28817 camera.matrix.decompose(camera.position, camera.quaternion, camera.scale); 28818 camera.updateMatrixWorld(true); 28819 camera.projectionMatrix.copy(cameraXR.projectionMatrix); 28820 camera.projectionMatrixInverse.copy(cameraXR.projectionMatrixInverse); 28821 if (camera.isPerspectiveCamera) { 28822 camera.fov = RAD2DEG * 2 * Math.atan(1 / camera.projectionMatrix.elements[5]); 28823 camera.zoom = 1; 28824 } 28825 } 28826 this.getCamera = function() { 28827 return cameraXR; 28828 }; 28829 this.getFoveation = function() { 28830 if (glProjLayer === null && glBaseLayer === null) { 28831 return undefined; 28832 } 28833 return foveation; 28834 }; 28835 this.setFoveation = function(value) { 28836 // 0 = no foveation = full resolution 28837 // 1 = maximum foveation = the edges render at lower resolution 28838 foveation = value; 28839 if (glProjLayer !== null) { 28840 glProjLayer.fixedFoveation = value; 28841 } 28842 if (glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined) { 28843 glBaseLayer.fixedFoveation = value; 28844 } 28845 }; 28846 this.hasDepthSensing = function() { 28847 return depthSensing.texture !== null; 28848 }; 28849 this.getDepthSensingMesh = function() {
vendor: 6,195 bytes, lines 28850-28973
28850 return depthSensing.getMesh(cameraXR); 28851 }; 28852 // Animation Loop 28853 let onAnimationFrameCallback = null; 28854 function onAnimationFrame(time, frame) { 28855 pose = frame.getViewerPose(customReferenceSpace || referenceSpace); 28856 xrFrame = frame; 28857 if (pose !== null) { 28858 const views = pose.views; 28859 if (glBaseLayer !== null) { 28860 renderer.setRenderTargetFramebuffer(newRenderTarget, glBaseLayer.framebuffer); 28861 renderer.setRenderTarget(newRenderTarget); 28862 } 28863 let cameraXRNeedsUpdate = false; 28864 // check if it's necessary to rebuild cameraXR's camera list 28865 if (views.length !== cameraXR.cameras.length) { 28866 cameraXR.cameras.length = 0; 28867 cameraXRNeedsUpdate = true; 28868 } 28869 for(let i = 0; i < views.length; i++){ 28870 const view = views[i]; 28871 let viewport = null; 28872 if (glBaseLayer !== null) { 28873 viewport = glBaseLayer.getViewport(view); 28874 } else { 28875 const glSubImage = glBinding.getViewSubImage(glProjLayer, view); 28876 viewport = glSubImage.viewport; 28877 // For side-by-side projection, we only produce a single texture for both eyes. 28878 if (i === 0) { 28879 renderer.setRenderTargetTextures(newRenderTarget, glSubImage.colorTexture, glProjLayer.ignoreDepthValues ? undefined : glSubImage.depthStencilTexture); 28880 renderer.setRenderTarget(newRenderTarget); 28881 } 28882 } 28883 let camera = cameras[i]; 28884 if (camera === undefined) { 28885 camera = new PerspectiveCamera(); 28886 camera.layers.enable(i); 28887 camera.viewport = new Vector4(); 28888 cameras[i] = camera; 28889 } 28890 camera.matrix.fromArray(view.transform.matrix); 28891 camera.matrix.decompose(camera.position, camera.quaternion, camera.scale); 28892 camera.projectionMatrix.fromArray(view.projectionMatrix); 28893 camera.projectionMatrixInverse.copy(camera.projectionMatrix).invert(); 28894 camera.viewport.set(viewport.x, viewport.y, viewport.width, viewport.height); 28895 if (i === 0) { 28896 cameraXR.matrix.copy(camera.matrix); 28897 cameraXR.matrix.decompose(cameraXR.position, cameraXR.quaternion, cameraXR.scale); 28898 } 28899 if (cameraXRNeedsUpdate === true) { 28900 cameraXR.cameras.push(camera); 28901 } 28902 } 28903 // 28904 const enabledFeatures = session.enabledFeatures; 28905 const gpuDepthSensingEnabled = enabledFeatures && enabledFeatures.includes('depth-sensing') && session.depthUsage == 'gpu-optimized'; 28906 if (gpuDepthSensingEnabled && glBinding) { 28907 const depthData = glBinding.getDepthInformation(views[0]); 28908 if (depthData && depthData.isValid && depthData.texture) { 28909 depthSensing.init(renderer, depthData, session.renderState); 28910 } 28911 } 28912 } 28913 // 28914 for(let i = 0; i < controllers.length; i++){ 28915 const inputSource = controllerInputSources[i]; 28916 const controller = controllers[i]; 28917 if (inputSource !== null && controller !== undefined) { 28918 controller.update(inputSource, frame, customReferenceSpace || referenceSpace); 28919 } 28920 } 28921 if (onAnimationFrameCallback) onAnimationFrameCallback(time, frame); 28922 if (frame.detectedPlanes) { 28923 scope.dispatchEvent({ 28924 type: 'planesdetected', 28925 data: frame 28926 }); 28927 } 28928 xrFrame = null; 28929 } 28930 const animation = new WebGLAnimation(); 28931 animation.setAnimationLoop(onAnimationFrame); 28932 this.setAnimationLoop = function(callback) { 28933 onAnimationFrameCallback = callback; 28934 }; 28935 this.dispose = function() {}; 28936 } 28937 } 28938 const _e1 = /*@__PURE__*/ new Euler(); 28939 const _m1 = /*@__PURE__*/ new Matrix4(); 28940 function WebGLMaterials(renderer, properties) { 28941 function refreshTransformUniform(map, uniform) { 28942 if (map.matrixAutoUpdate === true) { 28943 map.updateMatrix(); 28944 } 28945 uniform.value.copy(map.matrix); 28946 } 28947 function refreshFogUniforms(uniforms, fog) { 28948 fog.color.getRGB(uniforms.fogColor.value, getUnlitUniformColorSpace(renderer)); 28949 if (fog.isFog) { 28950 uniforms.fogNear.value = fog.near; 28951 uniforms.fogFar.value = fog.far; 28952 } else if (fog.isFogExp2) { 28953 uniforms.fogDensity.value = fog.density; 28954 } 28955 } 28956 function refreshMaterialUniforms(uniforms, material, pixelRatio, height, transmissionRenderTarget) { 28957 if (material.isMeshBasicMaterial) { 28958 refreshUniformsCommon(uniforms, material); 28959 } else if (material.isMeshLambertMaterial) { 28960 refreshUniformsCommon(uniforms, material); 28961 } else if (material.isMeshToonMaterial) { 28962 refreshUniformsCommon(uniforms, material); 28963 refreshUniformsToon(uniforms, material); 28964 } else if (material.isMeshPhongMaterial) { 28965 refreshUniformsCommon(uniforms, material); 28966 refreshUniformsPhong(uniforms, material); 28967 } else if (material.isMeshStandardMaterial) { 28968 refreshUniformsCommon(uniforms, material); 28969 refreshUniformsStandard(uniforms, material); 28970 if (material.isMeshPhysicalMaterial) { 28971 refreshUniformsPhysical(uniforms, material, transmissionRenderTarget); 28972 } 28973 }
vendor: 34,388 bytes, lines 28973-29695
28973 else if (material.isMeshMatcapMaterial) { 28974 refreshUniformsCommon(uniforms, material); 28975 refreshUniformsMatcap(uniforms, material); 28976 } else if (material.isMeshDepthMaterial) { 28977 refreshUniformsCommon(uniforms, material); 28978 } else if (material.isMeshDistanceMaterial) { 28979 refreshUniformsCommon(uniforms, material); 28980 refreshUniformsDistance(uniforms, material); 28981 } else if (material.isMeshNormalMaterial) { 28982 refreshUniformsCommon(uniforms, material); 28983 } else if (material.isLineBasicMaterial) { 28984 refreshUniformsLine(uniforms, material); 28985 if (material.isLineDashedMaterial) { 28986 refreshUniformsDash(uniforms, material); 28987 } 28988 } else if (material.isPointsMaterial) { 28989 refreshUniformsPoints(uniforms, material, pixelRatio, height); 28990 } else if (material.isSpriteMaterial) { 28991 refreshUniformsSprites(uniforms, material); 28992 } else if (material.isShadowMaterial) { 28993 uniforms.color.value.copy(material.color); 28994 uniforms.opacity.value = material.opacity; 28995 } else if (material.isShaderMaterial) { 28996 material.uniformsNeedUpdate = false; // #15581 28997 } 28998 } 28999 function refreshUniformsCommon(uniforms, material) { 29000 uniforms.opacity.value = material.opacity; 29001 if (material.color) { 29002 uniforms.diffuse.value.copy(material.color); 29003 } 29004 if (material.emissive) { 29005 uniforms.emissive.value.copy(material.emissive).multiplyScalar(material.emissiveIntensity); 29006 } 29007 if (material.map) { 29008 uniforms.map.value = material.map; 29009 refreshTransformUniform(material.map, uniforms.mapTransform); 29010 } 29011 if (material.alphaMap) { 29012 uniforms.alphaMap.value = material.alphaMap; 29013 refreshTransformUniform(material.alphaMap, uniforms.alphaMapTransform); 29014 } 29015 if (material.bumpMap) { 29016 uniforms.bumpMap.value = material.bumpMap; 29017 refreshTransformUniform(material.bumpMap, uniforms.bumpMapTransform); 29018 uniforms.bumpScale.value = material.bumpScale; 29019 if (material.side === BackSide) { 29020 uniforms.bumpScale.value *= -1; 29021 } 29022 } 29023 if (material.normalMap) { 29024 uniforms.normalMap.value = material.normalMap; 29025 refreshTransformUniform(material.normalMap, uniforms.normalMapTransform); 29026 uniforms.normalScale.value.copy(material.normalScale); 29027 if (material.side === BackSide) { 29028 uniforms.normalScale.value.negate(); 29029 } 29030 } 29031 if (material.displacementMap) { 29032 uniforms.displacementMap.value = material.displacementMap; 29033 refreshTransformUniform(material.displacementMap, uniforms.displacementMapTransform); 29034 uniforms.displacementScale.value = material.displacementScale; 29035 uniforms.displacementBias.value = material.displacementBias; 29036 } 29037 if (material.emissiveMap) { 29038 uniforms.emissiveMap.value = material.emissiveMap; 29039 refreshTransformUniform(material.emissiveMap, uniforms.emissiveMapTransform); 29040 } 29041 if (material.specularMap) { 29042 uniforms.specularMap.value = material.specularMap; 29043 refreshTransformUniform(material.specularMap, uniforms.specularMapTransform); 29044 } 29045 if (material.alphaTest > 0) { 29046 uniforms.alphaTest.value = material.alphaTest; 29047 } 29048 const materialProperties = properties.get(material); 29049 const envMap = materialProperties.envMap; 29050 const envMapRotation = materialProperties.envMapRotation; 29051 if (envMap) { 29052 uniforms.envMap.value = envMap; 29053 _e1.copy(envMapRotation); 29054 // accommodate left-handed frame 29055 _e1.x *= -1; 29056 _e1.y *= -1; 29057 _e1.z *= -1; 29058 if (envMap.isCubeTexture && envMap.isRenderTargetTexture === false) { 29059 // environment maps which are not cube render targets or PMREMs follow a different convention 29060 _e1.y *= -1; 29061 _e1.z *= -1; 29062 } 29063 uniforms.envMapRotation.value.setFromMatrix4(_m1.makeRotationFromEuler(_e1)); 29064 uniforms.flipEnvMap.value = envMap.isCubeTexture && envMap.isRenderTargetTexture === false ? -1 : 1; 29065 uniforms.reflectivity.value = material.reflectivity; 29066 uniforms.ior.value = material.ior; 29067 uniforms.refractionRatio.value = material.refractionRatio; 29068 } 29069 if (material.lightMap) { 29070 uniforms.lightMap.value = material.lightMap; 29071 uniforms.lightMapIntensity.value = material.lightMapIntensity; 29072 refreshTransformUniform(material.lightMap, uniforms.lightMapTransform); 29073 } 29074 if (material.aoMap) { 29075 uniforms.aoMap.value = material.aoMap; 29076 uniforms.aoMapIntensity.value = material.aoMapIntensity; 29077 refreshTransformUniform(material.aoMap, uniforms.aoMapTransform); 29078 } 29079 } 29080 function refreshUniformsLine(uniforms, material) { 29081 uniforms.diffuse.value.copy(material.color); 29082 uniforms.opacity.value = material.opacity; 29083 if (material.map) { 29084 uniforms.map.value = material.map; 29085 refreshTransformUniform(material.map, uniforms.mapTransform); 29086 } 29087 } 29088 function refreshUniformsDash(uniforms, material) { 29089 uniforms.dashSize.value = material.dashSize; 29090 uniforms.totalSize.value = material.dashSize + material.gapSize; 29091 uniforms.scale.value = material.scale; 29092 } 29093 function refreshUniformsPoints(uniforms, material, pixelRatio, height) { 29094 uniforms.diffuse.value.copy(material.color); 29095 uniforms.opacity.value = material.opacity; 29096 uniforms.size.value = material.size * pixelRatio; 29097 uniforms.scale.value = height * 0.5; 29098 if (material.map) { 29099 uniforms.map.value = material.map; 29100 refreshTransformUniform(material.map, uniforms.uvTransform); 29101 } 29102 if (material.alphaMap) { 29103 uniforms.alphaMap.value = material.alphaMap; 29104 refreshTransformUniform(material.alphaMap, uniforms.alphaMapTransform); 29105 } 29106 if (material.alphaTest > 0) { 29107 uniforms.alphaTest.value = material.alphaTest; 29108 } 29109 } 29110 function refreshUniformsSprites(uniforms, material) { 29111 uniforms.diffuse.value.copy(material.color); 29112 uniforms.opacity.value = material.opacity; 29113 uniforms.rotation.value = material.rotation; 29114 if (material.map) { 29115 uniforms.map.value = material.map; 29116 refreshTransformUniform(material.map, uniforms.mapTransform); 29117 } 29118 if (material.alphaMap) { 29119 uniforms.alphaMap.value = material.alphaMap; 29120 refreshTransformUniform(material.alphaMap, uniforms.alphaMapTransform); 29121 } 29122 if (material.alphaTest > 0) { 29123 uniforms.alphaTest.value = material.alphaTest; 29124 } 29125 } 29126 function refreshUniformsPhong(uniforms, material) { 29127 uniforms.specular.value.copy(material.specular); 29128 uniforms.shininess.value = Math.max(material.shininess, 1e-4); // to prevent pow( 0.0, 0.0 ) 29129 } 29130 function refreshUniformsToon(uniforms, material) { 29131 if (material.gradientMap) { 29132 uniforms.gradientMap.value = material.gradientMap; 29133 } 29134 } 29135 function refreshUniformsStandard(uniforms, material) { 29136 uniforms.metalness.value = material.metalness; 29137 if (material.metalnessMap) { 29138 uniforms.metalnessMap.value = material.metalnessMap; 29139 refreshTransformUniform(material.metalnessMap, uniforms.metalnessMapTransform); 29140 } 29141 uniforms.roughness.value = material.roughness; 29142 if (material.roughnessMap) { 29143 uniforms.roughnessMap.value = material.roughnessMap; 29144 refreshTransformUniform(material.roughnessMap, uniforms.roughnessMapTransform); 29145 } 29146 if (material.envMap) { 29147 //uniforms.envMap.value = material.envMap; // part of uniforms common 29148 uniforms.envMapIntensity.value = material.envMapIntensity; 29149 } 29150 } 29151 function refreshUniformsPhysical(uniforms, material, transmissionRenderTarget) { 29152 uniforms.ior.value = material.ior; // also part of uniforms common 29153 if (material.sheen > 0) { 29154 uniforms.sheenColor.value.copy(material.sheenColor).multiplyScalar(material.sheen); 29155 uniforms.sheenRoughness.value = material.sheenRoughness; 29156 if (material.sheenColorMap) { 29157 uniforms.sheenColorMap.value = material.sheenColorMap; 29158 refreshTransformUniform(material.sheenColorMap, uniforms.sheenColorMapTransform); 29159 } 29160 if (material.sheenRoughnessMap) { 29161 uniforms.sheenRoughnessMap.value = material.sheenRoughnessMap; 29162 refreshTransformUniform(material.sheenRoughnessMap, uniforms.sheenRoughnessMapTransform); 29163 } 29164 } 29165 if (material.clearcoat > 0) { 29166 uniforms.clearcoat.value = material.clearcoat; 29167 uniforms.clearcoatRoughness.value = material.clearcoatRoughness; 29168 if (material.clearcoatMap) { 29169 uniforms.clearcoatMap.value = material.clearcoatMap; 29170 refreshTransformUniform(material.clearcoatMap, uniforms.clearcoatMapTransform); 29171 } 29172 if (material.clearcoatRoughnessMap) { 29173 uniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap; 29174 refreshTransformUniform(material.clearcoatRoughnessMap, uniforms.clearcoatRoughnessMapTransform); 29175 } 29176 if (material.clearcoatNormalMap) { 29177 uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap; 29178 refreshTransformUniform(material.clearcoatNormalMap, uniforms.clearcoatNormalMapTransform); 29179 uniforms.clearcoatNormalScale.value.copy(material.clearcoatNormalScale); 29180 if (material.side === BackSide) { 29181 uniforms.clearcoatNormalScale.value.negate(); 29182 } 29183 } 29184 } 29185 if (material.dispersion > 0) { 29186 uniforms.dispersion.value = material.dispersion; 29187 } 29188 if (material.iridescence > 0) { 29189 uniforms.iridescence.value = material.iridescence; 29190 uniforms.iridescenceIOR.value = material.iridescenceIOR; 29191 uniforms.iridescenceThicknessMinimum.value = material.iridescenceThicknessRange[0]; 29192 uniforms.iridescenceThicknessMaximum.value = material.iridescenceThicknessRange[1]; 29193 if (material.iridescenceMap) { 29194 uniforms.iridescenceMap.value = material.iridescenceMap; 29195 refreshTransformUniform(material.iridescenceMap, uniforms.iridescenceMapTransform); 29196 } 29197 if (material.iridescenceThicknessMap) { 29198 uniforms.iridescenceThicknessMap.value = material.iridescenceThicknessMap; 29199 refreshTransformUniform(material.iridescenceThicknessMap, uniforms.iridescenceThicknessMapTransform); 29200 } 29201 } 29202 if (material.transmission > 0) { 29203 uniforms.transmission.value = material.transmission; 29204 uniforms.transmissionSamplerMap.value = transmissionRenderTarget.texture; 29205 uniforms.transmissionSamplerSize.value.set(transmissionRenderTarget.width, transmissionRenderTarget.height); 29206 if (material.transmissionMap) { 29207 uniforms.transmissionMap.value = material.transmissionMap; 29208 refreshTransformUniform(material.transmissionMap, uniforms.transmissionMapTransform); 29209 } 29210 uniforms.thickness.value = material.thickness; 29211 if (material.thicknessMap) { 29212 uniforms.thicknessMap.value = material.thicknessMap; 29213 refreshTransformUniform(material.thicknessMap, uniforms.thicknessMapTransform); 29214 } 29215 uniforms.attenuationDistance.value = material.attenuationDistance; 29216 uniforms.attenuationColor.value.copy(material.attenuationColor); 29217 } 29218 if (material.anisotropy > 0) { 29219 uniforms.anisotropyVector.value.set(material.anisotropy * Math.cos(material.anisotropyRotation), material.anisotropy * Math.sin(material.anisotropyRotation)); 29220 if (material.anisotropyMap) { 29221 uniforms.anisotropyMap.value = material.anisotropyMap; 29222 refreshTransformUniform(material.anisotropyMap, uniforms.anisotropyMapTransform); 29223 } 29224 } 29225 uniforms.specularIntensity.value = material.specularIntensity; 29226 uniforms.specularColor.value.copy(material.specularColor); 29227 if (material.specularColorMap) { 29228 uniforms.specularColorMap.value = material.specularColorMap; 29229 refreshTransformUniform(material.specularColorMap, uniforms.specularColorMapTransform); 29230 } 29231 if (material.specularIntensityMap) { 29232 uniforms.specularIntensityMap.value = material.specularIntensityMap; 29233 refreshTransformUniform(material.specularIntensityMap, uniforms.specularIntensityMapTransform); 29234 } 29235 } 29236 function refreshUniformsMatcap(uniforms, material) { 29237 if (material.matcap) { 29238 uniforms.matcap.value = material.matcap; 29239 } 29240 } 29241 function refreshUniformsDistance(uniforms, material) { 29242 const light = properties.get(material).light; 29243 uniforms.referencePosition.value.setFromMatrixPosition(light.matrixWorld); 29244 uniforms.nearDistance.value = light.shadow.camera.near; 29245 uniforms.farDistance.value = light.shadow.camera.far; 29246 } 29247 return { 29248 refreshFogUniforms: refreshFogUniforms, 29249 refreshMaterialUniforms: refreshMaterialUniforms 29250 }; 29251 } 29252 function WebGLUniformsGroups(gl, info, capabilities, state) { 29253 let buffers = {}; 29254 let updateList = {}; 29255 let allocatedBindingPoints = []; 29256 const maxBindingPoints = gl.getParameter(gl.MAX_UNIFORM_BUFFER_BINDINGS); // binding points are global whereas block indices are per shader program 29257 function bind(uniformsGroup, program) { 29258 const webglProgram = program.program; 29259 state.uniformBlockBinding(uniformsGroup, webglProgram); 29260 } 29261 function update(uniformsGroup, program) { 29262 let buffer = buffers[uniformsGroup.id]; 29263 if (buffer === undefined) { 29264 prepareUniformsGroup(uniformsGroup); 29265 buffer = createBuffer(uniformsGroup); 29266 buffers[uniformsGroup.id] = buffer; 29267 uniformsGroup.addEventListener('dispose', onUniformsGroupsDispose); 29268 } 29269 // ensure to update the binding points/block indices mapping for this program 29270 const webglProgram = program.program; 29271 state.updateUBOMapping(uniformsGroup, webglProgram); 29272 // update UBO once per frame 29273 const frame = info.render.frame; 29274 if (updateList[uniformsGroup.id] !== frame) { 29275 updateBufferData(uniformsGroup); 29276 updateList[uniformsGroup.id] = frame; 29277 } 29278 } 29279 function createBuffer(uniformsGroup) { 29280 // the setup of an UBO is independent of a particular shader program but global 29281 const bindingPointIndex = allocateBindingPointIndex(); 29282 uniformsGroup.__bindingPointIndex = bindingPointIndex; 29283 const buffer = gl.createBuffer(); 29284 const size = uniformsGroup.__size; 29285 const usage = uniformsGroup.usage; 29286 gl.bindBuffer(gl.UNIFORM_BUFFER, buffer); 29287 gl.bufferData(gl.UNIFORM_BUFFER, size, usage); 29288 gl.bindBuffer(gl.UNIFORM_BUFFER, null); 29289 gl.bindBufferBase(gl.UNIFORM_BUFFER, bindingPointIndex, buffer); 29290 return buffer; 29291 } 29292 function allocateBindingPointIndex() { 29293 for(let i = 0; i < maxBindingPoints; i++){ 29294 if (allocatedBindingPoints.indexOf(i) === -1) { 29295 allocatedBindingPoints.push(i); 29296 return i; 29297 } 29298 } 29299 console.error('THREE.WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached.'); 29300 return 0; 29301 } 29302 function updateBufferData(uniformsGroup) { 29303 const buffer = buffers[uniformsGroup.id]; 29304 const uniforms = uniformsGroup.uniforms; 29305 const cache = uniformsGroup.__cache; 29306 gl.bindBuffer(gl.UNIFORM_BUFFER, buffer); 29307 for(let i = 0, il = uniforms.length; i < il; i++){ 29308 const uniformArray = Array.isArray(uniforms[i]) ? uniforms[i] : [ 29309 uniforms[i] 29310 ]; 29311 for(let j = 0, jl = uniformArray.length; j < jl; j++){ 29312 const uniform = uniformArray[j]; 29313 if (hasUniformChanged(uniform, i, j, cache) === true) { 29314 const offset = uniform.__offset; 29315 const values = Array.isArray(uniform.value) ? uniform.value : [ 29316 uniform.value 29317 ]; 29318 let arrayOffset = 0; 29319 for(let k = 0; k < values.length; k++){ 29320 const value = values[k]; 29321 const info = getUniformSize(value); 29322 // TODO add integer and struct support 29323 if (typeof value === 'number' || typeof value === 'boolean') { 29324 uniform.__data[0] = value; 29325 gl.bufferSubData(gl.UNIFORM_BUFFER, offset + arrayOffset, uniform.__data); 29326 } else if (value.isMatrix3) { 29327 // manually converting 3x3 to 3x4 29328 uniform.__data[0] = value.elements[0]; 29329 uniform.__data[1] = value.elements[1]; 29330 uniform.__data[2] = value.elements[2]; 29331 uniform.__data[3] = 0; 29332 uniform.__data[4] = value.elements[3]; 29333 uniform.__data[5] = value.elements[4]; 29334 uniform.__data[6] = value.elements[5]; 29335 uniform.__data[7] = 0; 29336 uniform.__data[8] = value.elements[6]; 29337 uniform.__data[9] = value.elements[7]; 29338 uniform.__data[10] = value.elements[8]; 29339 uniform.__data[11] = 0; 29340 } else { 29341 value.toArray(uniform.__data, arrayOffset); 29342 arrayOffset += info.storage / Float32Array.BYTES_PER_ELEMENT; 29343 } 29344 } 29345 gl.bufferSubData(gl.UNIFORM_BUFFER, offset, uniform.__data); 29346 } 29347 } 29348 } 29349 gl.bindBuffer(gl.UNIFORM_BUFFER, null); 29350 } 29351 function hasUniformChanged(uniform, index, indexArray, cache) { 29352 const value = uniform.value; 29353 const indexString = index + '_' + indexArray; 29354 if (cache[indexString] === undefined) { 29355 // cache entry does not exist so far 29356 if (typeof value === 'number' || typeof value === 'boolean') { 29357 cache[indexString] = value; 29358 } else { 29359 cache[indexString] = value.clone(); 29360 } 29361 return true; 29362 } else { 29363 const cachedObject = cache[indexString]; 29364 // compare current value with cached entry 29365 if (typeof value === 'number' || typeof value === 'boolean') { 29366 if (cachedObject !== value) { 29367 cache[indexString] = value; 29368 return true; 29369 } 29370 } else { 29371 if (cachedObject.equals(value) === false) { 29372 cachedObject.copy(value); 29373 return true; 29374 } 29375 } 29376 } 29377 return false; 29378 } 29379 function prepareUniformsGroup(uniformsGroup) { 29380 // determine total buffer size according to the STD140 layout 29381 // Hint: STD140 is the only supported layout in WebGL 2 29382 const uniforms = uniformsGroup.uniforms; 29383 let offset = 0; // global buffer offset in bytes 29384 const chunkSize = 16; // size of a chunk in bytes 29385 for(let i = 0, l = uniforms.length; i < l; i++){ 29386 const uniformArray = Array.isArray(uniforms[i]) ? uniforms[i] : [ 29387 uniforms[i] 29388 ]; 29389 for(let j = 0, jl = uniformArray.length; j < jl; j++){ 29390 const uniform = uniformArray[j]; 29391 const values = Array.isArray(uniform.value) ? uniform.value : [ 29392 uniform.value 29393 ]; 29394 for(let k = 0, kl = values.length; k < kl; k++){ 29395 const value = values[k]; 29396 const info = getUniformSize(value); 29397 const chunkOffset = offset % chunkSize; // offset in the current chunk 29398 const chunkPadding = chunkOffset % info.boundary; // required padding to match boundary 29399 const chunkStart = chunkOffset + chunkPadding; // the start position in the current chunk for the data 29400 offset += chunkPadding; 29401 // Check for chunk overflow 29402 if (chunkStart !== 0 && chunkSize - chunkStart < info.storage) { 29403 // Add padding and adjust offset 29404 offset += chunkSize - chunkStart; 29405 } 29406 // the following two properties will be used for partial buffer updates 29407 uniform.__data = new Float32Array(info.storage / Float32Array.BYTES_PER_ELEMENT); 29408 uniform.__offset = offset; 29409 // Update the global offset 29410 offset += info.storage; 29411 } 29412 } 29413 } 29414 // ensure correct final padding 29415 const chunkOffset = offset % chunkSize; 29416 if (chunkOffset > 0) offset += chunkSize - chunkOffset; 29417 // 29418 uniformsGroup.__size = offset; 29419 uniformsGroup.__cache = {}; 29420 return this; 29421 } 29422 function getUniformSize(value) { 29423 const info = { 29424 boundary: 0, 29425 storage: 0 // bytes 29426 }; 29427 // determine sizes according to STD140 29428 if (typeof value === 'number' || typeof value === 'boolean') { 29429 // float/int/bool 29430 info.boundary = 4; 29431 info.storage = 4; 29432 } else if (value.isVector2) { 29433 // vec2 29434 info.boundary = 8; 29435 info.storage = 8; 29436 } else if (value.isVector3 || value.isColor) { 29437 // vec3 29438 info.boundary = 16; 29439 info.storage = 12; // evil: vec3 must start on a 16-byte boundary but it only consumes 12 bytes 29440 } else if (value.isVector4) { 29441 // vec4 29442 info.boundary = 16; 29443 info.storage = 16; 29444 } else if (value.isMatrix3) { 29445 // mat3 (in STD140 a 3x3 matrix is represented as 3x4) 29446 info.boundary = 48; 29447 info.storage = 48; 29448 } else if (value.isMatrix4) { 29449 // mat4 29450 info.boundary = 64; 29451 info.storage = 64; 29452 } else if (value.isTexture) { 29453 console.warn('THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.'); 29454 } else { 29455 console.warn('THREE.WebGLRenderer: Unsupported uniform value type.', value); 29456 } 29457 return info; 29458 } 29459 function onUniformsGroupsDispose(event) { 29460 const uniformsGroup = event.target; 29461 uniformsGroup.removeEventListener('dispose', onUniformsGroupsDispose); 29462 const index = allocatedBindingPoints.indexOf(uniformsGroup.__bindingPointIndex); 29463 allocatedBindingPoints.splice(index, 1); 29464 gl.deleteBuffer(buffers[uniformsGroup.id]); 29465 delete buffers[uniformsGroup.id]; 29466 delete updateList[uniformsGroup.id]; 29467 } 29468 function dispose() { 29469 for(const id in buffers){ 29470 gl.deleteBuffer(buffers[id]); 29471 } 29472 allocatedBindingPoints = []; 29473 buffers = {}; 29474 updateList = {}; 29475 } 29476 return { 29477 bind: bind, 29478 update: update, 29479 dispose: dispose 29480 }; 29481 } 29482 class WebGLRenderer { 29483 get coordinateSystem() { 29484 return WebGLCoordinateSystem; 29485 } 29486 get outputColorSpace() { 29487 return this._outputColorSpace; 29488 } 29489 set outputColorSpace(colorSpace) { 29490 this._outputColorSpace = colorSpace; 29491 const gl = this.getContext(); 29492 gl.drawingBufferColorspace = ColorManagement._getDrawingBufferColorSpace(colorSpace); 29493 gl.unpackColorSpace = ColorManagement._getUnpackColorSpace(); 29494 } 29495 constructor(parameters = {}){ 29496 const { canvas = createCanvasElement(), context = null, depth = true, stencil = false, alpha = false, antialias = false, premultipliedAlpha = true, preserveDrawingBuffer = false, powerPreference = 'default', failIfMajorPerformanceCaveat = false, reverseDepthBuffer = false } = parameters; 29497 this.isWebGLRenderer = true; 29498 let _alpha; 29499 if (context !== null) { 29500 if (typeof WebGLRenderingContext !== 'undefined' && context instanceof WebGLRenderingContext) { 29501 throw new Error('THREE.WebGLRenderer: WebGL 1 is not supported since r163.'); 29502 } 29503 _alpha = context.getContextAttributes().alpha; 29504 } else { 29505 _alpha = alpha; 29506 } 29507 const uintClearColor = new Uint32Array(4); 29508 const intClearColor = new Int32Array(4); 29509 let currentRenderList = null; 29510 let currentRenderState = null; 29511 // render() can be called from within a callback triggered by another render. 29512 // We track this so that the nested render call gets its list and state isolated from the parent render call. 29513 const renderListStack = []; 29514 const renderStateStack = []; 29515 // public properties 29516 this.domElement = canvas; 29517 // Debug configuration container 29518 this.debug = { 29519 /** 29520 * Enables error checking and reporting when shader programs are being compiled 29521 * @type {boolean} 29522 */ checkShaderErrors: true, 29523 /** 29524 * Callback for custom error reporting. 29525 * @type {?Function} 29526 */ onShaderError: null 29527 }; 29528 // clearing 29529 this.autoClear = true; 29530 this.autoClearColor = true; 29531 this.autoClearDepth = true; 29532 this.autoClearStencil = true; 29533 // scene graph 29534 this.sortObjects = true; 29535 // user-defined clipping 29536 this.clippingPlanes = []; 29537 this.localClippingEnabled = false; 29538 // physically based shading 29539 this._outputColorSpace = SRGBColorSpace; 29540 // tone mapping 29541 this.toneMapping = NoToneMapping; 29542 this.toneMappingExposure = 1.0; 29543 // internal properties 29544 const _this = this; 29545 let _isContextLost = false; 29546 // internal state cache 29547 let _currentActiveCubeFace = 0; 29548 let _currentActiveMipmapLevel = 0; 29549 let _currentRenderTarget = null; 29550 let _currentMaterialId = -1; 29551 let _currentCamera = null; 29552 const _currentViewport = new Vector4(); 29553 const _currentScissor = new Vector4(); 29554 let _currentScissorTest = null; 29555 const _currentClearColor = new Color(0x000000); 29556 let _currentClearAlpha = 0; 29557 // 29558 let _width = canvas.width; 29559 let _height = canvas.height; 29560 let _pixelRatio = 1; 29561 let _opaqueSort = null; 29562 let _transparentSort = null; 29563 const _viewport = new Vector4(0, 0, _width, _height); 29564 const _scissor = new Vector4(0, 0, _width, _height); 29565 let _scissorTest = false; 29566 // frustum 29567 const _frustum = new Frustum(); 29568 // clipping 29569 let _clippingEnabled = false; 29570 let _localClippingEnabled = false; 29571 // transmission render target scale 29572 this.transmissionResolutionScale = 1.0; 29573 // camera matrices cache 29574 const _currentProjectionMatrix = new Matrix4(); 29575 const _projScreenMatrix = new Matrix4(); 29576 const _vector3 = new Vector3(); 29577 const _vector4 = new Vector4(); 29578 const _emptyScene = { 29579 background: null, 29580 fog: null, 29581 environment: null, 29582 overrideMaterial: null, 29583 isScene: true 29584 }; 29585 let _renderBackground = false; 29586 function getTargetPixelRatio() { 29587 return _currentRenderTarget === null ? _pixelRatio : 1; 29588 } 29589 // initialize 29590 let _gl = context; 29591 function getContext(contextName, contextAttributes) { 29592 return canvas.getContext(contextName, contextAttributes); 29593 } 29594 try { 29595 const contextAttributes = { 29596 alpha: true, 29597 depth, 29598 stencil, 29599 antialias, 29600 premultipliedAlpha, 29601 preserveDrawingBuffer, 29602 powerPreference, 29603 failIfMajorPerformanceCaveat 29604 }; 29605 // OffscreenCanvas does not have setAttribute, see #22811 29606 if ('setAttribute' in canvas) canvas.setAttribute('data-engine', `three.js r${REVISION}`); 29607 // event listeners must be registered before WebGL context is created, see #12753 29608 canvas.addEventListener('webglcontextlost', onContextLost, false); 29609 canvas.addEventListener('webglcontextrestored', onContextRestore, false); 29610 canvas.addEventListener('webglcontextcreationerror', onContextCreationError, false); 29611 if (_gl === null) { 29612 const contextName = 'webgl2'; 29613 _gl = getContext(contextName, contextAttributes); 29614 if (_gl === null) { 29615 if (getContext(contextName)) { 29616 throw new Error('Error creating WebGL context with your selected attributes.'); 29617 } else { 29618 throw new Error('Error creating WebGL context.'); 29619 } 29620 } 29621 } 29622 } catch (error) { 29623 console.error('THREE.WebGLRenderer: ' + error.message); 29624 throw error; 29625 } 29626 let extensions, capabilities, state, info; 29627 let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects; 29628 let programCache, materials, renderLists, renderStates, clipping, shadowMap; 29629 let background, morphtargets, bufferRenderer, indexedBufferRenderer; 29630 let utils, bindingStates, uniformsGroups; 29631 function initGLContext() { 29632 extensions = new WebGLExtensions(_gl); 29633 extensions.init(); 29634 utils = new WebGLUtils(_gl, extensions); 29635 capabilities = new WebGLCapabilities(_gl, extensions, parameters, utils); 29636 state = new WebGLState(_gl, extensions); 29637 if (capabilities.reverseDepthBuffer && reverseDepthBuffer) { 29638 state.buffers.depth.setReversed(true); 29639 } 29640 info = new WebGLInfo(_gl); 29641 properties = new WebGLProperties(); 29642 textures = new WebGLTextures(_gl, extensions, state, properties, capabilities, utils, info); 29643 cubemaps = new WebGLCubeMaps(_this); 29644 cubeuvmaps = new WebGLCubeUVMaps(_this); 29645 attributes = new WebGLAttributes(_gl); 29646 bindingStates = new WebGLBindingStates(_gl, attributes); 29647 geometries = new WebGLGeometries(_gl, attributes, info, bindingStates); 29648 objects = new WebGLObjects(_gl, geometries, attributes, info); 29649 morphtargets = new WebGLMorphtargets(_gl, capabilities, textures); 29650 clipping = new WebGLClipping(properties); 29651 programCache = new WebGLPrograms(_this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping); 29652 materials = new WebGLMaterials(_this, properties); 29653 renderLists = new WebGLRenderLists(); 29654 renderStates = new WebGLRenderStates(extensions); 29655 background = new WebGLBackground(_this, cubemaps, cubeuvmaps, state, objects, _alpha, premultipliedAlpha); 29656 shadowMap = new WebGLShadowMap(_this, objects, capabilities); 29657 uniformsGroups = new WebGLUniformsGroups(_gl, info, capabilities, state); 29658 bufferRenderer = new WebGLBufferRenderer(_gl, extensions, info); 29659 indexedBufferRenderer = new WebGLIndexedBufferRenderer(_gl, extensions, info); 29660 info.programs = programCache.programs; 29661 _this.capabilities = capabilities; 29662 _this.extensions = extensions; 29663 _this.properties = properties; 29664 _this.renderLists = renderLists; 29665 _this.shadowMap = shadowMap; 29666 _this.state = state; 29667 _this.info = info; 29668 } 29669 initGLContext(); 29670 // xr 29671 const xr = new WebXRManager(_this, _gl); 29672 this.xr = xr; 29673 // API 29674 this.getContext = function() { 29675 return _gl; 29676 }; 29677 this.getContextAttributes = function() { 29678 return _gl.getContextAttributes(); 29679 }; 29680 this.forceContextLoss = function() { 29681 const extension = extensions.get('WEBGL_lose_context'); 29682 if (extension) extension.loseContext(); 29683 }; 29684 this.forceContextRestore = function() { 29685 const extension = extensions.get('WEBGL_lose_context'); 29686 if (extension) extension.restoreContext(); 29687 }; 29688 this.getPixelRatio = function() { 29689 return _pixelRatio; 29690 }; 29691 this.setPixelRatio = function(value) { 29692 if (value === undefined) return; 29693 _pixelRatio = value; 29694 this.setSize(_width, _height, false); 29695 };
vendor: 7,040 bytes, lines 29696-29857
29696 this.getSize = function(target) { 29697 return target.set(_width, _height); 29698 }; 29699 this.setSize = function(width, height, updateStyle = true) { 29700 if (xr.isPresenting) { 29701 console.warn('THREE.WebGLRenderer: Can\'t change size while VR device is presenting.'); 29702 return; 29703 } 29704 _width = width; 29705 _height = height; 29706 canvas.width = Math.floor(width * _pixelRatio); 29707 canvas.height = Math.floor(height * _pixelRatio); 29708 if (updateStyle === true) { 29709 canvas.style.width = width + 'px'; 29710 canvas.style.height = height + 'px'; 29711 } 29712 this.setViewport(0, 0, width, height); 29713 }; 29714 this.getDrawingBufferSize = function(target) { 29715 return target.set(_width * _pixelRatio, _height * _pixelRatio).floor(); 29716 }; 29717 this.setDrawingBufferSize = function(width, height, pixelRatio) { 29718 _width = width; 29719 _height = height; 29720 _pixelRatio = pixelRatio; 29721 canvas.width = Math.floor(width * pixelRatio); 29722 canvas.height = Math.floor(height * pixelRatio); 29723 this.setViewport(0, 0, width, height); 29724 }; 29725 this.getCurrentViewport = function(target) { 29726 return target.copy(_currentViewport); 29727 }; 29728 this.getViewport = function(target) { 29729 return target.copy(_viewport); 29730 }; 29731 this.setViewport = function(x, y, width, height) { 29732 if (x.isVector4) { 29733 _viewport.set(x.x, x.y, x.z, x.w); 29734 } else { 29735 _viewport.set(x, y, width, height); 29736 } 29737 state.viewport(_currentViewport.copy(_viewport).multiplyScalar(_pixelRatio).round()); 29738 }; 29739 this.getScissor = function(target) { 29740 return target.copy(_scissor); 29741 }; 29742 this.setScissor = function(x, y, width, height) { 29743 if (x.isVector4) { 29744 _scissor.set(x.x, x.y, x.z, x.w); 29745 } else { 29746 _scissor.set(x, y, width, height); 29747 } 29748 state.scissor(_currentScissor.copy(_scissor).multiplyScalar(_pixelRatio).round()); 29749 }; 29750 this.getScissorTest = function() { 29751 return _scissorTest; 29752 }; 29753 this.setScissorTest = function(boolean) { 29754 state.setScissorTest(_scissorTest = boolean); 29755 }; 29756 this.setOpaqueSort = function(method) { 29757 _opaqueSort = method; 29758 }; 29759 this.setTransparentSort = function(method) { 29760 _transparentSort = method; 29761 }; 29762 // Clearing 29763 this.getClearColor = function(target) { 29764 return target.copy(background.getClearColor()); 29765 }; 29766 this.setClearColor = function() { 29767 background.setClearColor(...arguments); 29768 }; 29769 this.getClearAlpha = function() { 29770 return background.getClearAlpha(); 29771 }; 29772 this.setClearAlpha = function() { 29773 background.setClearAlpha(...arguments); 29774 }; 29775 this.clear = function(color = true, depth = true, stencil = true) { 29776 let bits = 0; 29777 if (color) { 29778 // check if we're trying to clear an integer target 29779 let isIntegerFormat = false; 29780 if (_currentRenderTarget !== null) { 29781 const targetFormat = _currentRenderTarget.texture.format; 29782 isIntegerFormat = targetFormat === RGBAIntegerFormat || targetFormat === RGIntegerFormat || targetFormat === RedIntegerFormat; 29783 } 29784 // use the appropriate clear functions to clear the target if it's a signed 29785 // or unsigned integer target 29786 if (isIntegerFormat) { 29787 const targetType = _currentRenderTarget.texture.type; 29788 const isUnsignedType = targetType === UnsignedByteType || targetType === UnsignedIntType || targetType === UnsignedShortType || targetType === UnsignedInt248Type || targetType === UnsignedShort4444Type || targetType === UnsignedShort5551Type; 29789 const clearColor = background.getClearColor(); 29790 const a = background.getClearAlpha(); 29791 const r = clearColor.r; 29792 const g = clearColor.g; 29793 const b = clearColor.b; 29794 if (isUnsignedType) { 29795 uintClearColor[0] = r; 29796 uintClearColor[1] = g; 29797 uintClearColor[2] = b; 29798 uintClearColor[3] = a; 29799 _gl.clearBufferuiv(_gl.COLOR, 0, uintClearColor); 29800 } else { 29801 intClearColor[0] = r; 29802 intClearColor[1] = g; 29803 intClearColor[2] = b; 29804 intClearColor[3] = a; 29805 _gl.clearBufferiv(_gl.COLOR, 0, intClearColor); 29806 } 29807 } else { 29808 bits |= _gl.COLOR_BUFFER_BIT; 29809 } 29810 } 29811 if (depth) { 29812 bits |= _gl.DEPTH_BUFFER_BIT; 29813 } 29814 if (stencil) { 29815 bits |= _gl.STENCIL_BUFFER_BIT; 29816 this.state.buffers.stencil.setMask(0xffffffff); 29817 } 29818 _gl.clear(bits); 29819 }; 29820 this.clearColor = function() { 29821 this.clear(true, false, false); 29822 }; 29823 this.clearDepth = function() { 29824 this.clear(false, true, false); 29825 }; 29826 this.clearStencil = function() { 29827 this.clear(false, false, true); 29828 }; 29829 // 29830 this.dispose = function() { 29831 canvas.removeEventListener('webglcontextlost', onContextLost, false); 29832 canvas.removeEventListener('webglcontextrestored', onContextRestore, false); 29833 canvas.removeEventListener('webglcontextcreationerror', onContextCreationError, false); 29834 background.dispose(); 29835 renderLists.dispose(); 29836 renderStates.dispose(); 29837 properties.dispose(); 29838 cubemaps.dispose(); 29839 cubeuvmaps.dispose(); 29840 objects.dispose(); 29841 bindingStates.dispose(); 29842 uniformsGroups.dispose(); 29843 programCache.dispose(); 29844 xr.dispose(); 29845 xr.removeEventListener('sessionstart', onXRSessionStart); 29846 xr.removeEventListener('sessionend', onXRSessionEnd); 29847 animation.stop(); 29848 }; 29849 // Events 29850 function onContextLost(event) { 29851 event.preventDefault(); 29852 console.log('THREE.WebGLRenderer: Context Lost.'); 29853 _isContextLost = true; 29854 } 29855 function onContextRestore() { 29856 console.log('THREE.WebGLRenderer: Context Restored.'); 29857 _isContextLost = false;
vendor: 14,715 bytes, lines 29858-30143
29858 const infoAutoReset = info.autoReset; 29859 const shadowMapEnabled = shadowMap.enabled; 29860 const shadowMapAutoUpdate = shadowMap.autoUpdate; 29861 const shadowMapNeedsUpdate = shadowMap.needsUpdate; 29862 const shadowMapType = shadowMap.type; 29863 initGLContext(); 29864 info.autoReset = infoAutoReset; 29865 shadowMap.enabled = shadowMapEnabled; 29866 shadowMap.autoUpdate = shadowMapAutoUpdate; 29867 shadowMap.needsUpdate = shadowMapNeedsUpdate; 29868 shadowMap.type = shadowMapType; 29869 } 29870 function onContextCreationError(event) { 29871 console.error('THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage); 29872 } 29873 function onMaterialDispose(event) { 29874 const material = event.target; 29875 material.removeEventListener('dispose', onMaterialDispose); 29876 deallocateMaterial(material); 29877 } 29878 // Buffer deallocation 29879 function deallocateMaterial(material) { 29880 releaseMaterialProgramReferences(material); 29881 properties.remove(material); 29882 } 29883 function releaseMaterialProgramReferences(material) { 29884 const programs = properties.get(material).programs; 29885 if (programs !== undefined) { 29886 programs.forEach(function(program) { 29887 programCache.releaseProgram(program); 29888 }); 29889 if (material.isShaderMaterial) { 29890 programCache.releaseShaderCache(material); 29891 } 29892 } 29893 } 29894 // Buffer rendering 29895 this.renderBufferDirect = function(camera, scene, geometry, material, object, group) { 29896 if (scene === null) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null) 29897 const frontFaceCW = object.isMesh && object.matrixWorld.determinant() < 0; 29898 const program = setProgram(camera, scene, geometry, material, object); 29899 state.setMaterial(material, frontFaceCW); 29900 // 29901 let index = geometry.index; 29902 let rangeFactor = 1; 29903 if (material.wireframe === true) { 29904 index = geometries.getWireframeAttribute(geometry); 29905 if (index === undefined) return; 29906 rangeFactor = 2; 29907 } 29908 // 29909 const drawRange = geometry.drawRange; 29910 const position = geometry.attributes.position; 29911 let drawStart = drawRange.start * rangeFactor; 29912 let drawEnd = (drawRange.start + drawRange.count) * rangeFactor; 29913 if (group !== null) { 29914 drawStart = Math.max(drawStart, group.start * rangeFactor); 29915 drawEnd = Math.min(drawEnd, (group.start + group.count) * rangeFactor); 29916 } 29917 if (index !== null) { 29918 drawStart = Math.max(drawStart, 0); 29919 drawEnd = Math.min(drawEnd, index.count); 29920 } else if (position !== undefined && position !== null) { 29921 drawStart = Math.max(drawStart, 0); 29922 drawEnd = Math.min(drawEnd, position.count); 29923 } 29924 const drawCount = drawEnd - drawStart; 29925 if (drawCount < 0 || drawCount === Infinity) return; 29926 // 29927 bindingStates.setup(object, material, program, geometry, index); 29928 let attribute; 29929 let renderer = bufferRenderer; 29930 if (index !== null) { 29931 attribute = attributes.get(index); 29932 renderer = indexedBufferRenderer; 29933 renderer.setIndex(attribute); 29934 } 29935 // 29936 if (object.isMesh) { 29937 if (material.wireframe === true) { 29938 state.setLineWidth(material.wireframeLinewidth * getTargetPixelRatio()); 29939 renderer.setMode(_gl.LINES); 29940 } else { 29941 renderer.setMode(_gl.TRIANGLES); 29942 } 29943 } else if (object.isLine) { 29944 let lineWidth = material.linewidth; 29945 if (lineWidth === undefined) lineWidth = 1; // Not using Line*Material 29946 state.setLineWidth(lineWidth * getTargetPixelRatio()); 29947 if (object.isLineSegments) { 29948 renderer.setMode(_gl.LINES); 29949 } else if (object.isLineLoop) { 29950 renderer.setMode(_gl.LINE_LOOP); 29951 } else { 29952 renderer.setMode(_gl.LINE_STRIP); 29953 } 29954 } else if (object.isPoints) { 29955 renderer.setMode(_gl.POINTS); 29956 } else if (object.isSprite) { 29957 renderer.setMode(_gl.TRIANGLES); 29958 } 29959 if (object.isBatchedMesh) { 29960 if (object._multiDrawInstances !== null) { 29961 // @deprecated, r174 29962 warnOnce('THREE.WebGLRenderer: renderMultiDrawInstances has been deprecated and will be removed in r184. Append to renderMultiDraw arguments and use indirection.'); 29963 renderer.renderMultiDrawInstances(object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount, object._multiDrawInstances); 29964 } else { 29965 if (!extensions.get('WEBGL_multi_draw')) { 29966 const starts = object._multiDrawStarts; 29967 const counts = object._multiDrawCounts; 29968 const drawCount = object._multiDrawCount; 29969 const bytesPerElement = index ? attributes.get(index).bytesPerElement : 1; 29970 const uniforms = properties.get(material).currentProgram.getUniforms(); 29971 for(let i = 0; i < drawCount; i++){ 29972 uniforms.setValue(_gl, '_gl_DrawID', i); 29973 renderer.render(starts[i] / bytesPerElement, counts[i]); 29974 } 29975 } else { 29976 renderer.renderMultiDraw(object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount); 29977 } 29978 } 29979 } else if (object.isInstancedMesh) { 29980 renderer.renderInstances(drawStart, drawCount, object.count); 29981 } else if (geometry.isInstancedBufferGeometry) { 29982 const maxInstanceCount = geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity; 29983 const instanceCount = Math.min(geometry.instanceCount, maxInstanceCount); 29984 renderer.renderInstances(drawStart, drawCount, instanceCount); 29985 } else { 29986 renderer.render(drawStart, drawCount); 29987 } 29988 }; 29989 // Compile 29990 function prepareMaterial(material, scene, object) { 29991 if (material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false) { 29992 material.side = BackSide; 29993 material.needsUpdate = true; 29994 getProgram(material, scene, object); 29995 material.side = FrontSide; 29996 material.needsUpdate = true; 29997 getProgram(material, scene, object); 29998 material.side = DoubleSide; 29999 } else { 30000 getProgram(material, scene, object); 30001 } 30002 } 30003 this.compile = function(scene, camera, targetScene = null) { 30004 if (targetScene === null) targetScene = scene; 30005 currentRenderState = renderStates.get(targetScene); 30006 currentRenderState.init(camera); 30007 renderStateStack.push(currentRenderState); 30008 // gather lights from both the target scene and the new object that will be added to the scene. 30009 targetScene.traverseVisible(function(object) { 30010 if (object.isLight && object.layers.test(camera.layers)) { 30011 currentRenderState.pushLight(object); 30012 if (object.castShadow) { 30013 currentRenderState.pushShadow(object); 30014 } 30015 } 30016 }); 30017 if (scene !== targetScene) { 30018 scene.traverseVisible(function(object) { 30019 if (object.isLight && object.layers.test(camera.layers)) { 30020 currentRenderState.pushLight(object); 30021 if (object.castShadow) { 30022 currentRenderState.pushShadow(object); 30023 } 30024 } 30025 }); 30026 } 30027 currentRenderState.setupLights(); 30028 // Only initialize materials in the new scene, not the targetScene. 30029 const materials = new Set(); 30030 scene.traverse(function(object) { 30031 if (!(object.isMesh || object.isPoints || object.isLine || object.isSprite)) { 30032 return; 30033 } 30034 const material = object.material; 30035 if (material) { 30036 if (Array.isArray(material)) { 30037 for(let i = 0; i < material.length; i++){ 30038 const material2 = material[i]; 30039 prepareMaterial(material2, targetScene, object); 30040 materials.add(material2); 30041 } 30042 } else { 30043 prepareMaterial(material, targetScene, object); 30044 materials.add(material); 30045 } 30046 } 30047 }); 30048 currentRenderState = renderStateStack.pop(); 30049 return materials; 30050 }; 30051 // compileAsync 30052 this.compileAsync = function(scene, camera, targetScene = null) { 30053 const materials = this.compile(scene, camera, targetScene); 30054 // Wait for all the materials in the new object to indicate that they're 30055 // ready to be used before resolving the promise. 30056 return new Promise((resolve)=>{ 30057 function checkMaterialsReady() { 30058 materials.forEach(function(material) { 30059 const materialProperties = properties.get(material); 30060 const program = materialProperties.currentProgram; 30061 if (program.isReady()) { 30062 // remove any programs that report they're ready to use from the list 30063 materials.delete(material); 30064 } 30065 }); 30066 // once the list of compiling materials is empty, call the callback 30067 if (materials.size === 0) { 30068 resolve(scene); 30069 return; 30070 } 30071 // if some materials are still not ready, wait a bit and check again 30072 setTimeout(checkMaterialsReady, 10); 30073 } 30074 if (extensions.get('KHR_parallel_shader_compile') !== null) { 30075 // If we can check the compilation status of the materials without 30076 // blocking then do so right away. 30077 checkMaterialsReady(); 30078 } else { 30079 // Otherwise start by waiting a bit to give the materials we just 30080 // initialized a chance to finish. 30081 setTimeout(checkMaterialsReady, 10); 30082 } 30083 }); 30084 }; 30085 // Animation Loop 30086 let onAnimationFrameCallback = null; 30087 function onAnimationFrame(time) { 30088 if (onAnimationFrameCallback) onAnimationFrameCallback(time); 30089 } 30090 function onXRSessionStart() { 30091 animation.stop(); 30092 } 30093 function onXRSessionEnd() { 30094 animation.start(); 30095 } 30096 const animation = new WebGLAnimation(); 30097 animation.setAnimationLoop(onAnimationFrame); 30098 if (typeof self !== 'undefined') animation.setContext(self); 30099 this.setAnimationLoop = function(callback) { 30100 onAnimationFrameCallback = callback; 30101 xr.setAnimationLoop(callback); 30102 callback === null ? animation.stop() : animation.start(); 30103 }; 30104 xr.addEventListener('sessionstart', onXRSessionStart); 30105 xr.addEventListener('sessionend', onXRSessionEnd); 30106 // Rendering 30107 this.render = function(scene, camera) { 30108 if (camera !== undefined && camera.isCamera !== true) { 30109 console.error('THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.'); 30110 return; 30111 } 30112 if (_isContextLost === true) return; 30113 // update scene graph 30114 if (scene.matrixWorldAutoUpdate === true) scene.updateMatrixWorld(); 30115 // update camera matrices and frustum 30116 if (camera.parent === null && camera.matrixWorldAutoUpdate === true) camera.updateMatrixWorld(); 30117 if (xr.enabled === true && xr.isPresenting === true) { 30118 if (xr.cameraAutoUpdate === true) xr.updateCamera(camera); 30119 camera = xr.getCamera(); // use XR camera for rendering 30120 } 30121 // 30122 if (scene.isScene === true) scene.onBeforeRender(_this, scene, camera, _currentRenderTarget); 30123 currentRenderState = renderStates.get(scene, renderStateStack.length); 30124 currentRenderState.init(camera); 30125 renderStateStack.push(currentRenderState); 30126 _projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse); 30127 _frustum.setFromProjectionMatrix(_projScreenMatrix); 30128 _localClippingEnabled = this.localClippingEnabled; 30129 _clippingEnabled = clipping.init(this.clippingPlanes, _localClippingEnabled); 30130 currentRenderList = renderLists.get(scene, renderListStack.length); 30131 currentRenderList.init(); 30132 renderListStack.push(currentRenderList); 30133 if (xr.enabled === true && xr.isPresenting === true) { 30134 const depthSensingMesh = _this.xr.getDepthSensingMesh(); 30135 if (depthSensingMesh !== null) { 30136 projectObject(depthSensingMesh, camera, -Infinity, _this.sortObjects); 30137 } 30138 } 30139 projectObject(scene, camera, 0, _this.sortObjects); 30140 currentRenderList.finish(); 30141 if (_this.sortObjects === true) { 30142 currentRenderList.sort(_opaqueSort, _transparentSort); 30143 }
vendor: 5,344 bytes, lines 30144-30240
30144 _renderBackground = xr.enabled === false || xr.isPresenting === false || xr.hasDepthSensing() === false; 30145 if (_renderBackground) { 30146 background.addToRenderList(currentRenderList, scene); 30147 } 30148 // 30149 this.info.render.frame++; 30150 if (_clippingEnabled === true) clipping.beginShadows(); 30151 const shadowsArray = currentRenderState.state.shadowsArray; 30152 shadowMap.render(shadowsArray, scene, camera); 30153 if (_clippingEnabled === true) clipping.endShadows(); 30154 // 30155 if (this.info.autoReset === true) this.info.reset(); 30156 // render scene 30157 const opaqueObjects = currentRenderList.opaque; 30158 const transmissiveObjects = currentRenderList.transmissive; 30159 currentRenderState.setupLights(); 30160 if (camera.isArrayCamera) { 30161 const cameras = camera.cameras; 30162 if (transmissiveObjects.length > 0) { 30163 for(let i = 0, l = cameras.length; i < l; i++){ 30164 const camera2 = cameras[i]; 30165 renderTransmissionPass(opaqueObjects, transmissiveObjects, scene, camera2); 30166 } 30167 } 30168 if (_renderBackground) background.render(scene); 30169 for(let i = 0, l = cameras.length; i < l; i++){ 30170 const camera2 = cameras[i]; 30171 renderScene(currentRenderList, scene, camera2, camera2.viewport); 30172 } 30173 } else { 30174 if (transmissiveObjects.length > 0) renderTransmissionPass(opaqueObjects, transmissiveObjects, scene, camera); 30175 if (_renderBackground) background.render(scene); 30176 renderScene(currentRenderList, scene, camera); 30177 } 30178 // 30179 if (_currentRenderTarget !== null && _currentActiveMipmapLevel === 0) { 30180 // resolve multisample renderbuffers to a single-sample texture if necessary 30181 textures.updateMultisampleRenderTarget(_currentRenderTarget); 30182 // Generate mipmap if we're using any kind of mipmap filtering 30183 textures.updateRenderTargetMipmap(_currentRenderTarget); 30184 } 30185 // 30186 if (scene.isScene === true) scene.onAfterRender(_this, scene, camera); 30187 // _gl.finish(); 30188 bindingStates.resetDefaultState(); 30189 _currentMaterialId = -1; 30190 _currentCamera = null; 30191 renderStateStack.pop(); 30192 if (renderStateStack.length > 0) { 30193 currentRenderState = renderStateStack[renderStateStack.length - 1]; 30194 if (_clippingEnabled === true) clipping.setGlobalState(_this.clippingPlanes, currentRenderState.state.camera); 30195 } else { 30196 currentRenderState = null; 30197 } 30198 renderListStack.pop(); 30199 if (renderListStack.length > 0) { 30200 currentRenderList = renderListStack[renderListStack.length - 1]; 30201 } else { 30202 currentRenderList = null; 30203 } 30204 }; 30205 function projectObject(object, camera, groupOrder, sortObjects) { 30206 if (object.visible === false) return; 30207 const visible = object.layers.test(camera.layers); 30208 if (visible) { 30209 if (object.isGroup) { 30210 groupOrder = object.renderOrder; 30211 } else if (object.isLOD) { 30212 if (object.autoUpdate === true) object.update(camera); 30213 } else if (object.isLight) { 30214 currentRenderState.pushLight(object); 30215 if (object.castShadow) { 30216 currentRenderState.pushShadow(object); 30217 } 30218 } else if (object.isSprite) { 30219 if (!object.frustumCulled || _frustum.intersectsSprite(object)) { 30220 if (sortObjects) { 30221 _vector4.setFromMatrixPosition(object.matrixWorld).applyMatrix4(_projScreenMatrix); 30222 } 30223 const geometry = objects.update(object); 30224 const material = object.material; 30225 if (material.visible) { 30226 currentRenderList.push(object, geometry, material, groupOrder, _vector4.z, null); 30227 } 30228 } 30229 } else if (object.isMesh || object.isLine || object.isPoints) { 30230 if (!object.frustumCulled || _frustum.intersectsObject(object)) { 30231 const geometry = objects.update(object); 30232 const material = object.material; 30233 if (sortObjects) { 30234 if (object.boundingSphere !== undefined) { 30235 if (object.boundingSphere === null) object.computeBoundingSphere(); 30236 _vector4.copy(object.boundingSphere.center); 30237 } else { 30238 if (geometry.boundingSphere === null) geometry.computeBoundingSphere(); 30239 _vector4.copy(geometry.boundingSphere.center); 30240 }
30241 _vector4.applyMatrix4(object.matrixWorld).applyMatrix4(_projScreenMatrix); 30242 } 30243 if (Array.isArray(material)) { 30244 const groups = geometry.groups; 30245 for(let i = 0, l = groups.length; i < l; i++){ 30246 const group = groups[i]; 30247 const groupMaterial = material[group.materialIndex]; 30248 if (groupMaterial && groupMaterial.visible) { 30249 currentRenderList.push(object, geometry, groupMaterial, groupOrder, _vector4.z, group); 30250 } 30251 } 30252 } else if (material.visible) { 30253 currentRenderList.push(object, geometry, material, groupOrder, _vector4.z, null); 30254 } 30255 } 30256 } 30257 } 30258 const children = object.children; 30259 for(let i = 0, l = children.length; i < l; i++){ 30260 projectObject(children[i], camera, groupOrder, sortObjects); 30261 } 30262 }
vendor: 27,326 bytes, lines 30263-30677
30263 function renderScene(currentRenderList, scene, camera, viewport) { 30264 const opaqueObjects = currentRenderList.opaque; 30265 const transmissiveObjects = currentRenderList.transmissive; 30266 const transparentObjects = currentRenderList.transparent; 30267 currentRenderState.setupLightsView(camera); 30268 if (_clippingEnabled === true) clipping.setGlobalState(_this.clippingPlanes, camera); 30269 if (viewport) state.viewport(_currentViewport.copy(viewport)); 30270 if (opaqueObjects.length > 0) renderObjects(opaqueObjects, scene, camera); 30271 if (transmissiveObjects.length > 0) renderObjects(transmissiveObjects, scene, camera); 30272 if (transparentObjects.length > 0) renderObjects(transparentObjects, scene, camera); 30273 // Ensure depth buffer writing is enabled so it can be cleared on next render 30274 state.buffers.depth.setTest(true); 30275 state.buffers.depth.setMask(true); 30276 state.buffers.color.setMask(true); 30277 state.setPolygonOffset(false); 30278 } 30279 function renderTransmissionPass(opaqueObjects, transmissiveObjects, scene, camera) { 30280 const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; 30281 if (overrideMaterial !== null) { 30282 return; 30283 } 30284 if (currentRenderState.state.transmissionRenderTarget[camera.id] === undefined) { 30285 currentRenderState.state.transmissionRenderTarget[camera.id] = new WebGLRenderTarget(1, 1, { 30286 generateMipmaps: true, 30287 type: extensions.has('EXT_color_buffer_half_float') || extensions.has('EXT_color_buffer_float') ? HalfFloatType : UnsignedByteType, 30288 minFilter: LinearMipmapLinearFilter, 30289 samples: 4, 30290 stencilBuffer: stencil, 30291 resolveDepthBuffer: false, 30292 resolveStencilBuffer: false, 30293 colorSpace: ColorManagement.workingColorSpace 30294 }); 30295 // debug 30296 /* 30297 const geometry = new PlaneGeometry(); 30298 const material = new MeshBasicMaterial( { map: _transmissionRenderTarget.texture } ); 30299 30300 const mesh = new Mesh( geometry, material ); 30301 scene.add( mesh ); 30302 */ } 30303 const transmissionRenderTarget = currentRenderState.state.transmissionRenderTarget[camera.id]; 30304 const activeViewport = camera.viewport || _currentViewport; 30305 transmissionRenderTarget.setSize(activeViewport.z * _this.transmissionResolutionScale, activeViewport.w * _this.transmissionResolutionScale); 30306 // 30307 const currentRenderTarget = _this.getRenderTarget(); 30308 _this.setRenderTarget(transmissionRenderTarget); 30309 _this.getClearColor(_currentClearColor); 30310 _currentClearAlpha = _this.getClearAlpha(); 30311 if (_currentClearAlpha < 1) _this.setClearColor(0xffffff, 0.5); 30312 _this.clear(); 30313 if (_renderBackground) background.render(scene); 30314 // Turn off the features which can affect the frag color for opaque objects pass. 30315 // Otherwise they are applied twice in opaque objects pass and transmission objects pass. 30316 const currentToneMapping = _this.toneMapping; 30317 _this.toneMapping = NoToneMapping; 30318 // Remove viewport from camera to avoid nested render calls resetting viewport to it (e.g Reflector). 30319 // Transmission render pass requires viewport to match the transmissionRenderTarget. 30320 const currentCameraViewport = camera.viewport; 30321 if (camera.viewport !== undefined) camera.viewport = undefined; 30322 currentRenderState.setupLightsView(camera); 30323 if (_clippingEnabled === true) clipping.setGlobalState(_this.clippingPlanes, camera); 30324 renderObjects(opaqueObjects, scene, camera); 30325 textures.updateMultisampleRenderTarget(transmissionRenderTarget); 30326 textures.updateRenderTargetMipmap(transmissionRenderTarget); 30327 if (extensions.has('WEBGL_multisampled_render_to_texture') === false) { 30328 let renderTargetNeedsUpdate = false; 30329 for(let i = 0, l = transmissiveObjects.length; i < l; i++){ 30330 const renderItem = transmissiveObjects[i]; 30331 const object = renderItem.object; 30332 const geometry = renderItem.geometry; 30333 const material = renderItem.material; 30334 const group = renderItem.group; 30335 if (material.side === DoubleSide && object.layers.test(camera.layers)) { 30336 const currentSide = material.side; 30337 material.side = BackSide; 30338 material.needsUpdate = true; 30339 renderObject(object, scene, camera, geometry, material, group); 30340 material.side = currentSide; 30341 material.needsUpdate = true; 30342 renderTargetNeedsUpdate = true; 30343 } 30344 } 30345 if (renderTargetNeedsUpdate === true) { 30346 textures.updateMultisampleRenderTarget(transmissionRenderTarget); 30347 textures.updateRenderTargetMipmap(transmissionRenderTarget); 30348 } 30349 } 30350 _this.setRenderTarget(currentRenderTarget); 30351 _this.setClearColor(_currentClearColor, _currentClearAlpha); 30352 if (currentCameraViewport !== undefined) camera.viewport = currentCameraViewport; 30353 _this.toneMapping = currentToneMapping; 30354 } 30355 function renderObjects(renderList, scene, camera) { 30356 const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; 30357 for(let i = 0, l = renderList.length; i < l; i++){ 30358 const renderItem = renderList[i]; 30359 const object = renderItem.object; 30360 const geometry = renderItem.geometry; 30361 const material = overrideMaterial === null ? renderItem.material : overrideMaterial; 30362 const group = renderItem.group; 30363 if (object.layers.test(camera.layers)) { 30364 renderObject(object, scene, camera, geometry, material, group); 30365 } 30366 } 30367 } 30368 function renderObject(object, scene, camera, geometry, material, group) { 30369 object.onBeforeRender(_this, scene, camera, geometry, material, group); 30370 object.modelViewMatrix.multiplyMatrices(camera.matrixWorldInverse, object.matrixWorld); 30371 object.normalMatrix.getNormalMatrix(object.modelViewMatrix); 30372 material.onBeforeRender(_this, scene, camera, geometry, object, group); 30373 if (material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false) { 30374 material.side = BackSide; 30375 material.needsUpdate = true; 30376 _this.renderBufferDirect(camera, scene, geometry, material, object, group); 30377 material.side = FrontSide; 30378 material.needsUpdate = true; 30379 _this.renderBufferDirect(camera, scene, geometry, material, object, group); 30380 material.side = DoubleSide; 30381 } else { 30382 _this.renderBufferDirect(camera, scene, geometry, material, object, group); 30383 } 30384 object.onAfterRender(_this, scene, camera, geometry, material, group); 30385 } 30386 function getProgram(material, scene, object) { 30387 if (scene.isScene !== true) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... 30388 const materialProperties = properties.get(material); 30389 const lights = currentRenderState.state.lights; 30390 const shadowsArray = currentRenderState.state.shadowsArray; 30391 const lightsStateVersion = lights.state.version; 30392 const parameters = programCache.getParameters(material, lights.state, shadowsArray, scene, object); 30393 const programCacheKey = programCache.getProgramCacheKey(parameters); 30394 let programs = materialProperties.programs; 30395 // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change 30396 materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null; 30397 materialProperties.fog = scene.fog; 30398 materialProperties.envMap = (material.isMeshStandardMaterial ? cubeuvmaps : cubemaps).get(material.envMap || materialProperties.environment); 30399 materialProperties.envMapRotation = materialProperties.environment !== null && material.envMap === null ? scene.environmentRotation : material.envMapRotation; 30400 if (programs === undefined) { 30401 // new material 30402 material.addEventListener('dispose', onMaterialDispose); 30403 programs = new Map(); 30404 materialProperties.programs = programs; 30405 } 30406 let program = programs.get(programCacheKey); 30407 if (program !== undefined) { 30408 // early out if program and light state is identical 30409 if (materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion) { 30410 updateCommonMaterialProperties(material, parameters); 30411 return program; 30412 } 30413 } else { 30414 parameters.uniforms = programCache.getUniforms(material); 30415 material.onBeforeCompile(parameters, _this); 30416 program = programCache.acquireProgram(parameters, programCacheKey); 30417 programs.set(programCacheKey, program); 30418 materialProperties.uniforms = parameters.uniforms; 30419 } 30420 const uniforms = materialProperties.uniforms; 30421 if (!material.isShaderMaterial && !material.isRawShaderMaterial || material.clipping === true) { 30422 uniforms.clippingPlanes = clipping.uniform; 30423 } 30424 updateCommonMaterialProperties(material, parameters); 30425 // store the light setup it was created for 30426 materialProperties.needsLights = materialNeedsLights(material); 30427 materialProperties.lightsStateVersion = lightsStateVersion; 30428 if (materialProperties.needsLights) { 30429 // wire up the material to this renderer's lighting state 30430 uniforms.ambientLightColor.value = lights.state.ambient; 30431 uniforms.lightProbe.value = lights.state.probe; 30432 uniforms.directionalLights.value = lights.state.directional; 30433 uniforms.directionalLightShadows.value = lights.state.directionalShadow; 30434 uniforms.spotLights.value = lights.state.spot; 30435 uniforms.spotLightShadows.value = lights.state.spotShadow; 30436 uniforms.rectAreaLights.value = lights.state.rectArea; 30437 uniforms.ltc_1.value = lights.state.rectAreaLTC1; 30438 uniforms.ltc_2.value = lights.state.rectAreaLTC2; 30439 uniforms.pointLights.value = lights.state.point; 30440 uniforms.pointLightShadows.value = lights.state.pointShadow; 30441 uniforms.hemisphereLights.value = lights.state.hemi; 30442 uniforms.directionalShadowMap.value = lights.state.directionalShadowMap; 30443 uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix; 30444 uniforms.spotShadowMap.value = lights.state.spotShadowMap; 30445 uniforms.spotLightMatrix.value = lights.state.spotLightMatrix; 30446 uniforms.spotLightMap.value = lights.state.spotLightMap; 30447 uniforms.pointShadowMap.value = lights.state.pointShadowMap; 30448 uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix; 30449 // TODO (abelnation): add area lights shadow info to uniforms 30450 } 30451 materialProperties.currentProgram = program; 30452 materialProperties.uniformsList = null; 30453 return program; 30454 } 30455 function getUniformList(materialProperties) { 30456 if (materialProperties.uniformsList === null) { 30457 const progUniforms = materialProperties.currentProgram.getUniforms(); 30458 materialProperties.uniformsList = WebGLUniforms.seqWithValue(progUniforms.seq, materialProperties.uniforms); 30459 } 30460 return materialProperties.uniformsList; 30461 } 30462 function updateCommonMaterialProperties(material, parameters) { 30463 const materialProperties = properties.get(material); 30464 materialProperties.outputColorSpace = parameters.outputColorSpace; 30465 materialProperties.batching = parameters.batching; 30466 materialProperties.batchingColor = parameters.batchingColor; 30467 materialProperties.instancing = parameters.instancing; 30468 materialProperties.instancingColor = parameters.instancingColor; 30469 materialProperties.instancingMorph = parameters.instancingMorph; 30470 materialProperties.skinning = parameters.skinning; 30471 materialProperties.morphTargets = parameters.morphTargets; 30472 materialProperties.morphNormals = parameters.morphNormals; 30473 materialProperties.morphColors = parameters.morphColors; 30474 materialProperties.morphTargetsCount = parameters.morphTargetsCount; 30475 materialProperties.numClippingPlanes = parameters.numClippingPlanes; 30476 materialProperties.numIntersection = parameters.numClipIntersection; 30477 materialProperties.vertexAlphas = parameters.vertexAlphas; 30478 materialProperties.vertexTangents = parameters.vertexTangents; 30479 materialProperties.toneMapping = parameters.toneMapping; 30480 } 30481 function setProgram(camera, scene, geometry, material, object) { 30482 if (scene.isScene !== true) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... 30483 textures.resetTextureUnits(); 30484 const fog = scene.fog; 30485 const environment = material.isMeshStandardMaterial ? scene.environment : null; 30486 const colorSpace = _currentRenderTarget === null ? _this.outputColorSpace : _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace; 30487 const envMap = (material.isMeshStandardMaterial ? cubeuvmaps : cubemaps).get(material.envMap || environment); 30488 const vertexAlphas = material.vertexColors === true && !!geometry.attributes.color && geometry.attributes.color.itemSize === 4; 30489 const vertexTangents = !!geometry.attributes.tangent && (!!material.normalMap || material.anisotropy > 0); 30490 const morphTargets = !!geometry.morphAttributes.position; 30491 const morphNormals = !!geometry.morphAttributes.normal; 30492 const morphColors = !!geometry.morphAttributes.color; 30493 let toneMapping = NoToneMapping; 30494 if (material.toneMapped) { 30495 if (_currentRenderTarget === null || _currentRenderTarget.isXRRenderTarget === true) { 30496 toneMapping = _this.toneMapping; 30497 } 30498 } 30499 const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; 30500 const morphTargetsCount = morphAttribute !== undefined ? morphAttribute.length : 0; 30501 const materialProperties = properties.get(material); 30502 const lights = currentRenderState.state.lights; 30503 if (_clippingEnabled === true) { 30504 if (_localClippingEnabled === true || camera !== _currentCamera) { 30505 const useCache = camera === _currentCamera && material.id === _currentMaterialId; 30506 // we might want to call this function with some ClippingGroup 30507 // object instead of the material, once it becomes feasible 30508 // (#8465, #8379) 30509 clipping.setState(material, camera, useCache); 30510 } 30511 } 30512 // 30513 let needsProgramChange = false; 30514 if (material.version === materialProperties.__version) { 30515 if (materialProperties.needsLights && materialProperties.lightsStateVersion !== lights.state.version) { 30516 needsProgramChange = true; 30517 } else if (materialProperties.outputColorSpace !== colorSpace) { 30518 needsProgramChange = true; 30519 } else if (object.isBatchedMesh && materialProperties.batching === false) { 30520 needsProgramChange = true; 30521 } else if (!object.isBatchedMesh && materialProperties.batching === true) { 30522 needsProgramChange = true; 30523 } else if (object.isBatchedMesh && materialProperties.batchingColor === true && object.colorTexture === null) { 30524 needsProgramChange = true; 30525 } else if (object.isBatchedMesh && materialProperties.batchingColor === false && object.colorTexture !== null) { 30526 needsProgramChange = true; 30527 } else if (object.isInstancedMesh && materialProperties.instancing === false) { 30528 needsProgramChange = true; 30529 } else if (!object.isInstancedMesh && materialProperties.instancing === true) { 30530 needsProgramChange = true; 30531 } else if (object.isSkinnedMesh && materialProperties.skinning === false) { 30532 needsProgramChange = true; 30533 } else if (!object.isSkinnedMesh && materialProperties.skinning === true) { 30534 needsProgramChange = true; 30535 } else if (object.isInstancedMesh && materialProperties.instancingColor === true && object.instanceColor === null) { 30536 needsProgramChange = true; 30537 } else if (object.isInstancedMesh && materialProperties.instancingColor === false && object.instanceColor !== null) { 30538 needsProgramChange = true; 30539 } else if (object.isInstancedMesh && materialProperties.instancingMorph === true && object.morphTexture === null) { 30540 needsProgramChange = true; 30541 } else if (object.isInstancedMesh && materialProperties.instancingMorph === false && object.morphTexture !== null) { 30542 needsProgramChange = true; 30543 } else if (materialProperties.envMap !== envMap) { 30544 needsProgramChange = true; 30545 } else if (material.fog === true && materialProperties.fog !== fog) { 30546 needsProgramChange = true; 30547 } else if (materialProperties.numClippingPlanes !== undefined && (materialProperties.numClippingPlanes !== clipping.numPlanes || materialProperties.numIntersection !== clipping.numIntersection)) { 30548 needsProgramChange = true; 30549 } else if (materialProperties.vertexAlphas !== vertexAlphas) { 30550 needsProgramChange = true; 30551 } else if (materialProperties.vertexTangents !== vertexTangents) { 30552 needsProgramChange = true; 30553 } else if (materialProperties.morphTargets !== morphTargets) { 30554 needsProgramChange = true; 30555 } else if (materialProperties.morphNormals !== morphNormals) { 30556 needsProgramChange = true; 30557 } else if (materialProperties.morphColors !== morphColors) { 30558 needsProgramChange = true; 30559 } else if (materialProperties.toneMapping !== toneMapping) { 30560 needsProgramChange = true; 30561 } else if (materialProperties.morphTargetsCount !== morphTargetsCount) { 30562 needsProgramChange = true; 30563 } 30564 } else { 30565 needsProgramChange = true; 30566 materialProperties.__version = material.version; 30567 } 30568 // 30569 let program = materialProperties.currentProgram; 30570 if (needsProgramChange === true) { 30571 program = getProgram(material, scene, object); 30572 } 30573 let refreshProgram = false; 30574 let refreshMaterial = false; 30575 let refreshLights = false; 30576 const p_uniforms = program.getUniforms(), m_uniforms = materialProperties.uniforms; 30577 if (state.useProgram(program.program)) { 30578 refreshProgram = true; 30579 refreshMaterial = true; 30580 refreshLights = true; 30581 } 30582 if (material.id !== _currentMaterialId) { 30583 _currentMaterialId = material.id; 30584 refreshMaterial = true; 30585 } 30586 if (refreshProgram || _currentCamera !== camera) { 30587 // common camera uniforms 30588 const reverseDepthBuffer = state.buffers.depth.getReversed(); 30589 if (reverseDepthBuffer) { 30590 _currentProjectionMatrix.copy(camera.projectionMatrix); 30591 toNormalizedProjectionMatrix(_currentProjectionMatrix); 30592 toReversedProjectionMatrix(_currentProjectionMatrix); 30593 p_uniforms.setValue(_gl, 'projectionMatrix', _currentProjectionMatrix); 30594 } else { 30595 p_uniforms.setValue(_gl, 'projectionMatrix', camera.projectionMatrix); 30596 } 30597 p_uniforms.setValue(_gl, 'viewMatrix', camera.matrixWorldInverse); 30598 const uCamPos = p_uniforms.map.cameraPosition; 30599 if (uCamPos !== undefined) { 30600 uCamPos.setValue(_gl, _vector3.setFromMatrixPosition(camera.matrixWorld)); 30601 } 30602 if (capabilities.logarithmicDepthBuffer) { 30603 p_uniforms.setValue(_gl, 'logDepthBufFC', 2.0 / (Math.log(camera.far + 1.0) / Math.LN2)); 30604 } 30605 // consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067 30606 if (material.isMeshPhongMaterial || material.isMeshToonMaterial || material.isMeshLambertMaterial || material.isMeshBasicMaterial || material.isMeshStandardMaterial || material.isShaderMaterial) { 30607 p_uniforms.setValue(_gl, 'isOrthographic', camera.isOrthographicCamera === true); 30608 } 30609 if (_currentCamera !== camera) { 30610 _currentCamera = camera; 30611 // lighting uniforms depend on the camera so enforce an update 30612 // now, in case this material supports lights - or later, when 30613 // the next material that does gets activated: 30614 refreshMaterial = true; // set to true on material change 30615 refreshLights = true; // remains set until update done 30616 } 30617 } 30618 // skinning and morph target uniforms must be set even if material didn't change 30619 // auto-setting of texture unit for bone and morph texture must go before other textures 30620 // otherwise textures used for skinning and morphing can take over texture units reserved for other material textures 30621 if (object.isSkinnedMesh) { 30622 p_uniforms.setOptional(_gl, object, 'bindMatrix'); 30623 p_uniforms.setOptional(_gl, object, 'bindMatrixInverse'); 30624 const skeleton = object.skeleton; 30625 if (skeleton) { 30626 if (skeleton.boneTexture === null) skeleton.computeBoneTexture(); 30627 p_uniforms.setValue(_gl, 'boneTexture', skeleton.boneTexture, textures); 30628 } 30629 } 30630 if (object.isBatchedMesh) { 30631 p_uniforms.setOptional(_gl, object, 'batchingTexture'); 30632 p_uniforms.setValue(_gl, 'batchingTexture', object._matricesTexture, textures); 30633 p_uniforms.setOptional(_gl, object, 'batchingIdTexture'); 30634 p_uniforms.setValue(_gl, 'batchingIdTexture', object._indirectTexture, textures); 30635 p_uniforms.setOptional(_gl, object, 'batchingColorTexture'); 30636 if (object._colorsTexture !== null) { 30637 p_uniforms.setValue(_gl, 'batchingColorTexture', object._colorsTexture, textures); 30638 } 30639 } 30640 const morphAttributes = geometry.morphAttributes; 30641 if (morphAttributes.position !== undefined || morphAttributes.normal !== undefined || morphAttributes.color !== undefined) { 30642 morphtargets.update(object, geometry, program); 30643 } 30644 if (refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow) { 30645 materialProperties.receiveShadow = object.receiveShadow; 30646 p_uniforms.setValue(_gl, 'receiveShadow', object.receiveShadow); 30647 } 30648 // https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512 30649 if (material.isMeshGouraudMaterial && material.envMap !== null) { 30650 m_uniforms.envMap.value = envMap; 30651 m_uniforms.flipEnvMap.value = envMap.isCubeTexture && envMap.isRenderTargetTexture === false ? -1 : 1; 30652 } 30653 if (material.isMeshStandardMaterial && material.envMap === null && scene.environment !== null) { 30654 m_uniforms.envMapIntensity.value = scene.environmentIntensity; 30655 } 30656 if (refreshMaterial) { 30657 p_uniforms.setValue(_gl, 'toneMappingExposure', _this.toneMappingExposure); 30658 if (materialProperties.needsLights) { 30659 // the current material requires lighting info 30660 // note: all lighting uniforms are always set correctly 30661 // they simply reference the renderer's state for their 30662 // values 30663 // 30664 // use the current material's .needsUpdate flags to set 30665 // the GL state when required 30666 markUniformsLightsNeedsUpdate(m_uniforms, refreshLights); 30667 } 30668 // refresh uniforms common to several materials 30669 if (fog && material.fog === true) { 30670 materials.refreshFogUniforms(m_uniforms, fog); 30671 } 30672 materials.refreshMaterialUniforms(m_uniforms, material, _pixelRatio, _height, currentRenderState.state.transmissionRenderTarget[camera.id]); 30673 WebGLUniforms.upload(_gl, getUniformList(materialProperties), m_uniforms, textures); 30674 } 30675 if (material.isShaderMaterial && material.uniformsNeedUpdate === true) { 30676 WebGLUniforms.upload(_gl, getUniformList(materialProperties), m_uniforms, textures); 30677 material.uniformsNeedUpdate = false;
vendor: 4,126 bytes, lines 30678-30749
30678 } 30679 if (material.isSpriteMaterial) { 30680 p_uniforms.setValue(_gl, 'center', object.center); 30681 } 30682 // common matrices 30683 p_uniforms.setValue(_gl, 'modelViewMatrix', object.modelViewMatrix); 30684 p_uniforms.setValue(_gl, 'normalMatrix', object.normalMatrix); 30685 p_uniforms.setValue(_gl, 'modelMatrix', object.matrixWorld); 30686 // UBOs 30687 if (material.isShaderMaterial || material.isRawShaderMaterial) { 30688 const groups = material.uniformsGroups; 30689 for(let i = 0, l = groups.length; i < l; i++){ 30690 const group = groups[i]; 30691 uniformsGroups.update(group, program); 30692 uniformsGroups.bind(group, program); 30693 } 30694 } 30695 return program; 30696 } 30697 // If uniforms are marked as clean, they don't need to be loaded to the GPU. 30698 function markUniformsLightsNeedsUpdate(uniforms, value) { 30699 uniforms.ambientLightColor.needsUpdate = value; 30700 uniforms.lightProbe.needsUpdate = value; 30701 uniforms.directionalLights.needsUpdate = value; 30702 uniforms.directionalLightShadows.needsUpdate = value; 30703 uniforms.pointLights.needsUpdate = value; 30704 uniforms.pointLightShadows.needsUpdate = value; 30705 uniforms.spotLights.needsUpdate = value; 30706 uniforms.spotLightShadows.needsUpdate = value; 30707 uniforms.rectAreaLights.needsUpdate = value; 30708 uniforms.hemisphereLights.needsUpdate = value; 30709 } 30710 function materialNeedsLights(material) { 30711 return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial || material.isMeshStandardMaterial || material.isShadowMaterial || material.isShaderMaterial && material.lights === true; 30712 } 30713 this.getActiveCubeFace = function() { 30714 return _currentActiveCubeFace; 30715 }; 30716 this.getActiveMipmapLevel = function() { 30717 return _currentActiveMipmapLevel; 30718 }; 30719 this.getRenderTarget = function() { 30720 return _currentRenderTarget; 30721 }; 30722 this.setRenderTargetTextures = function(renderTarget, colorTexture, depthTexture) { 30723 properties.get(renderTarget.texture).__webglTexture = colorTexture; 30724 properties.get(renderTarget.depthTexture).__webglTexture = depthTexture; 30725 const renderTargetProperties = properties.get(renderTarget); 30726 renderTargetProperties.__hasExternalTextures = true; 30727 renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined; 30728 if (!renderTargetProperties.__autoAllocateDepthBuffer) { 30729 // The multisample_render_to_texture extension doesn't work properly if there 30730 // are midframe flushes and an external depth buffer. Disable use of the extension. 30731 if (extensions.has('WEBGL_multisampled_render_to_texture') === true) { 30732 console.warn('THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided'); 30733 renderTargetProperties.__useRenderToTexture = false; 30734 } 30735 } 30736 }; 30737 this.setRenderTargetFramebuffer = function(renderTarget, defaultFramebuffer) { 30738 const renderTargetProperties = properties.get(renderTarget); 30739 renderTargetProperties.__webglFramebuffer = defaultFramebuffer; 30740 renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined; 30741 }; 30742 const _scratchFrameBuffer = _gl.createFramebuffer(); 30743 this.setRenderTarget = function(renderTarget, activeCubeFace = 0, activeMipmapLevel = 0) { 30744 _currentRenderTarget = renderTarget; 30745 _currentActiveCubeFace = activeCubeFace; 30746 _currentActiveMipmapLevel = activeMipmapLevel; 30747 let useDefaultFramebuffer = true; 30748 let framebuffer = null; 30749 let isCube = false;
vendor: 14,373 bytes, lines 30750-30977
30750 let isRenderTarget3D = false; 30751 if (renderTarget) { 30752 const renderTargetProperties = properties.get(renderTarget); 30753 if (renderTargetProperties.__useDefaultFramebuffer !== undefined) { 30754 // We need to make sure to rebind the framebuffer. 30755 state.bindFramebuffer(_gl.FRAMEBUFFER, null); 30756 useDefaultFramebuffer = false; 30757 } else if (renderTargetProperties.__webglFramebuffer === undefined) { 30758 textures.setupRenderTarget(renderTarget); 30759 } else if (renderTargetProperties.__hasExternalTextures) { 30760 // Color and depth texture must be rebound in order for the swapchain to update. 30761 textures.rebindTextures(renderTarget, properties.get(renderTarget.texture).__webglTexture, properties.get(renderTarget.depthTexture).__webglTexture); 30762 } else if (renderTarget.depthBuffer) { 30763 // check if the depth texture is already bound to the frame buffer and that it's been initialized 30764 const depthTexture = renderTarget.depthTexture; 30765 if (renderTargetProperties.__boundDepthTexture !== depthTexture) { 30766 // check if the depth texture is compatible 30767 if (depthTexture !== null && properties.has(depthTexture) && (renderTarget.width !== depthTexture.image.width || renderTarget.height !== depthTexture.image.height)) { 30768 throw new Error('WebGLRenderTarget: Attached DepthTexture is initialized to the incorrect size.'); 30769 } 30770 // Swap the depth buffer to the currently attached one 30771 textures.setupDepthRenderbuffer(renderTarget); 30772 } 30773 } 30774 const texture = renderTarget.texture; 30775 if (texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture) { 30776 isRenderTarget3D = true; 30777 } 30778 const __webglFramebuffer = properties.get(renderTarget).__webglFramebuffer; 30779 if (renderTarget.isWebGLCubeRenderTarget) { 30780 if (Array.isArray(__webglFramebuffer[activeCubeFace])) { 30781 framebuffer = __webglFramebuffer[activeCubeFace][activeMipmapLevel]; 30782 } else { 30783 framebuffer = __webglFramebuffer[activeCubeFace]; 30784 } 30785 isCube = true; 30786 } else if (renderTarget.samples > 0 && textures.useMultisampledRTT(renderTarget) === false) { 30787 framebuffer = properties.get(renderTarget).__webglMultisampledFramebuffer; 30788 } else { 30789 if (Array.isArray(__webglFramebuffer)) { 30790 framebuffer = __webglFramebuffer[activeMipmapLevel]; 30791 } else { 30792 framebuffer = __webglFramebuffer; 30793 } 30794 } 30795 _currentViewport.copy(renderTarget.viewport); 30796 _currentScissor.copy(renderTarget.scissor); 30797 _currentScissorTest = renderTarget.scissorTest; 30798 } else { 30799 _currentViewport.copy(_viewport).multiplyScalar(_pixelRatio).floor(); 30800 _currentScissor.copy(_scissor).multiplyScalar(_pixelRatio).floor(); 30801 _currentScissorTest = _scissorTest; 30802 } 30803 // Use a scratch frame buffer if rendering to a mip level to avoid depth buffers 30804 // being bound that are different sizes. 30805 if (activeMipmapLevel !== 0) { 30806 framebuffer = _scratchFrameBuffer; 30807 } 30808 const framebufferBound = state.bindFramebuffer(_gl.FRAMEBUFFER, framebuffer); 30809 if (framebufferBound && useDefaultFramebuffer) { 30810 state.drawBuffers(renderTarget, framebuffer); 30811 } 30812 state.viewport(_currentViewport); 30813 state.scissor(_currentScissor); 30814 state.setScissorTest(_currentScissorTest); 30815 if (isCube) { 30816 const textureProperties = properties.get(renderTarget.texture); 30817 _gl.framebufferTexture2D(_gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel); 30818 } else if (isRenderTarget3D) { 30819 const textureProperties = properties.get(renderTarget.texture); 30820 const layer = activeCubeFace; 30821 _gl.framebufferTextureLayer(_gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel, layer); 30822 } else if (renderTarget !== null && activeMipmapLevel !== 0) { 30823 // Only bind the frame buffer if we are using a scratch frame buffer to render to a mipmap. 30824 // If we rebind the texture when using a multi sample buffer then an error about inconsistent samples will be thrown. 30825 const textureProperties = properties.get(renderTarget.texture); 30826 _gl.framebufferTexture2D(_gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, textureProperties.__webglTexture, activeMipmapLevel); 30827 } 30828 _currentMaterialId = -1; // reset current material to ensure correct uniform bindings 30829 }; 30830 this.readRenderTargetPixels = function(renderTarget, x, y, width, height, buffer, activeCubeFaceIndex) { 30831 if (!(renderTarget && renderTarget.isWebGLRenderTarget)) { 30832 console.error('THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.'); 30833 return; 30834 } 30835 let framebuffer = properties.get(renderTarget).__webglFramebuffer; 30836 if (renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined) { 30837 framebuffer = framebuffer[activeCubeFaceIndex]; 30838 } 30839 if (framebuffer) { 30840 state.bindFramebuffer(_gl.FRAMEBUFFER, framebuffer); 30841 try { 30842 const texture = renderTarget.texture; 30843 const textureFormat = texture.format; 30844 const textureType = texture.type; 30845 if (!capabilities.textureFormatReadable(textureFormat)) { 30846 console.error('THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.'); 30847 return; 30848 } 30849 if (!capabilities.textureTypeReadable(textureType)) { 30850 console.error('THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.'); 30851 return; 30852 } 30853 // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) 30854 if (x >= 0 && x <= renderTarget.width - width && y >= 0 && y <= renderTarget.height - height) { 30855 _gl.readPixels(x, y, width, height, utils.convert(textureFormat), utils.convert(textureType), buffer); 30856 } 30857 } finally{ 30858 // restore framebuffer of current render target if necessary 30859 const framebuffer = _currentRenderTarget !== null ? properties.get(_currentRenderTarget).__webglFramebuffer : null; 30860 state.bindFramebuffer(_gl.FRAMEBUFFER, framebuffer); 30861 } 30862 } 30863 }; 30864 this.readRenderTargetPixelsAsync = async function(renderTarget, x, y, width, height, buffer, activeCubeFaceIndex) { 30865 if (!(renderTarget && renderTarget.isWebGLRenderTarget)) { 30866 throw new Error('THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.'); 30867 } 30868 let framebuffer = properties.get(renderTarget).__webglFramebuffer; 30869 if (renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined) { 30870 framebuffer = framebuffer[activeCubeFaceIndex]; 30871 } 30872 if (framebuffer) { 30873 const texture = renderTarget.texture; 30874 const textureFormat = texture.format; 30875 const textureType = texture.type; 30876 if (!capabilities.textureFormatReadable(textureFormat)) { 30877 throw new Error('THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.'); 30878 } 30879 if (!capabilities.textureTypeReadable(textureType)) { 30880 throw new Error('THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.'); 30881 } 30882 // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) 30883 if (x >= 0 && x <= renderTarget.width - width && y >= 0 && y <= renderTarget.height - height) { 30884 // set the active frame buffer to the one we want to read 30885 state.bindFramebuffer(_gl.FRAMEBUFFER, framebuffer); 30886 const glBuffer = _gl.createBuffer(); 30887 _gl.bindBuffer(_gl.PIXEL_PACK_BUFFER, glBuffer); 30888 _gl.bufferData(_gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ); 30889 _gl.readPixels(x, y, width, height, utils.convert(textureFormat), utils.convert(textureType), 0); 30890 // reset the frame buffer to the currently set buffer before waiting 30891 const currFramebuffer = _currentRenderTarget !== null ? properties.get(_currentRenderTarget).__webglFramebuffer : null; 30892 state.bindFramebuffer(_gl.FRAMEBUFFER, currFramebuffer); 30893 // check if the commands have finished every 8 ms 30894 const sync = _gl.fenceSync(_gl.SYNC_GPU_COMMANDS_COMPLETE, 0); 30895 _gl.flush(); 30896 await probeAsync(_gl, sync, 4); 30897 // read the data and delete the buffer 30898 _gl.bindBuffer(_gl.PIXEL_PACK_BUFFER, glBuffer); 30899 _gl.getBufferSubData(_gl.PIXEL_PACK_BUFFER, 0, buffer); 30900 _gl.deleteBuffer(glBuffer); 30901 _gl.deleteSync(sync); 30902 return buffer; 30903 } else { 30904 throw new Error('THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.'); 30905 } 30906 } 30907 }; 30908 this.copyFramebufferToTexture = function(texture, position = null, level = 0) { 30909 // support previous signature with position first 30910 if (texture.isTexture !== true) { 30911 // @deprecated, r165 30912 warnOnce('WebGLRenderer: copyFramebufferToTexture function signature has changed.'); 30913 position = arguments[0] || null; 30914 texture = arguments[1]; 30915 } 30916 const levelScale = Math.pow(2, -level); 30917 const width = Math.floor(texture.image.width * levelScale); 30918 const height = Math.floor(texture.image.height * levelScale); 30919 const x = position !== null ? position.x : 0; 30920 const y = position !== null ? position.y : 0; 30921 textures.setTexture2D(texture, 0); 30922 _gl.copyTexSubImage2D(_gl.TEXTURE_2D, level, 0, 0, x, y, width, height); 30923 state.unbindTexture(); 30924 }; 30925 const _srcFramebuffer = _gl.createFramebuffer(); 30926 const _dstFramebuffer = _gl.createFramebuffer(); 30927 this.copyTextureToTexture = function(srcTexture, dstTexture, srcRegion = null, dstPosition = null, srcLevel = 0, dstLevel = null) { 30928 // support previous signature with dstPosition first 30929 if (srcTexture.isTexture !== true) { 30930 // @deprecated, r165 30931 warnOnce('WebGLRenderer: copyTextureToTexture function signature has changed.'); 30932 dstPosition = arguments[0] || null; 30933 srcTexture = arguments[1]; 30934 dstTexture = arguments[2]; 30935 dstLevel = arguments[3] || 0; 30936 srcRegion = null; 30937 } 30938 // support the previous signature with just a single dst mipmap level 30939 if (dstLevel === null) { 30940 if (srcLevel !== 0) { 30941 // @deprecated, r171 30942 warnOnce('WebGLRenderer: copyTextureToTexture function signature has changed to support src and dst mipmap levels.'); 30943 dstLevel = srcLevel; 30944 srcLevel = 0; 30945 } else { 30946 dstLevel = 0; 30947 } 30948 } 30949 // gather the necessary dimensions to copy 30950 let width, height, depth, minX, minY, minZ; 30951 let dstX, dstY, dstZ; 30952 const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[dstLevel] : srcTexture.image; 30953 if (srcRegion !== null) { 30954 width = srcRegion.max.x - srcRegion.min.x; 30955 height = srcRegion.max.y - srcRegion.min.y; 30956 depth = srcRegion.isBox3 ? srcRegion.max.z - srcRegion.min.z : 1; 30957 minX = srcRegion.min.x; 30958 minY = srcRegion.min.y; 30959 minZ = srcRegion.isBox3 ? srcRegion.min.z : 0; 30960 } else { 30961 const levelScale = Math.pow(2, -srcLevel); 30962 width = Math.floor(image.width * levelScale); 30963 height = Math.floor(image.height * levelScale); 30964 if (srcTexture.isDataArrayTexture) { 30965 depth = image.depth; 30966 } else if (srcTexture.isData3DTexture) { 30967 depth = Math.floor(image.depth * levelScale); 30968 } else { 30969 depth = 1; 30970 } 30971 minX = 0; 30972 minY = 0; 30973 minZ = 0; 30974 } 30975 if (dstPosition !== null) { 30976 dstX = dstPosition.x; 30977 dstY = dstPosition.y;
vendor: 9,913 bytes, lines 30978-31142
30978 dstZ = dstPosition.z; 30979 } else { 30980 dstX = 0; 30981 dstY = 0; 30982 dstZ = 0; 30983 } 30984 // Set up the destination target 30985 const glFormat = utils.convert(dstTexture.format); 30986 const glType = utils.convert(dstTexture.type); 30987 let glTarget; 30988 if (dstTexture.isData3DTexture) { 30989 textures.setTexture3D(dstTexture, 0); 30990 glTarget = _gl.TEXTURE_3D; 30991 } else if (dstTexture.isDataArrayTexture || dstTexture.isCompressedArrayTexture) { 30992 textures.setTexture2DArray(dstTexture, 0); 30993 glTarget = _gl.TEXTURE_2D_ARRAY; 30994 } else { 30995 textures.setTexture2D(dstTexture, 0); 30996 glTarget = _gl.TEXTURE_2D; 30997 } 30998 _gl.pixelStorei(_gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY); 30999 _gl.pixelStorei(_gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha); 31000 _gl.pixelStorei(_gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment); 31001 // used for copying data from cpu 31002 const currentUnpackRowLen = _gl.getParameter(_gl.UNPACK_ROW_LENGTH); 31003 const currentUnpackImageHeight = _gl.getParameter(_gl.UNPACK_IMAGE_HEIGHT); 31004 const currentUnpackSkipPixels = _gl.getParameter(_gl.UNPACK_SKIP_PIXELS); 31005 const currentUnpackSkipRows = _gl.getParameter(_gl.UNPACK_SKIP_ROWS); 31006 const currentUnpackSkipImages = _gl.getParameter(_gl.UNPACK_SKIP_IMAGES); 31007 _gl.pixelStorei(_gl.UNPACK_ROW_LENGTH, image.width); 31008 _gl.pixelStorei(_gl.UNPACK_IMAGE_HEIGHT, image.height); 31009 _gl.pixelStorei(_gl.UNPACK_SKIP_PIXELS, minX); 31010 _gl.pixelStorei(_gl.UNPACK_SKIP_ROWS, minY); 31011 _gl.pixelStorei(_gl.UNPACK_SKIP_IMAGES, minZ); 31012 // set up the src texture 31013 const isSrc3D = srcTexture.isDataArrayTexture || srcTexture.isData3DTexture; 31014 const isDst3D = dstTexture.isDataArrayTexture || dstTexture.isData3DTexture; 31015 if (srcTexture.isDepthTexture) { 31016 const srcTextureProperties = properties.get(srcTexture); 31017 const dstTextureProperties = properties.get(dstTexture); 31018 const srcRenderTargetProperties = properties.get(srcTextureProperties.__renderTarget); 31019 const dstRenderTargetProperties = properties.get(dstTextureProperties.__renderTarget); 31020 state.bindFramebuffer(_gl.READ_FRAMEBUFFER, srcRenderTargetProperties.__webglFramebuffer); 31021 state.bindFramebuffer(_gl.DRAW_FRAMEBUFFER, dstRenderTargetProperties.__webglFramebuffer); 31022 for(let i = 0; i < depth; i++){ 31023 // if the source or destination are a 3d target then a layer needs to be bound 31024 if (isSrc3D) { 31025 _gl.framebufferTextureLayer(_gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, properties.get(srcTexture).__webglTexture, srcLevel, minZ + i); 31026 _gl.framebufferTextureLayer(_gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, properties.get(dstTexture).__webglTexture, dstLevel, dstZ + i); 31027 } 31028 _gl.blitFramebuffer(minX, minY, width, height, dstX, dstY, width, height, _gl.DEPTH_BUFFER_BIT, _gl.NEAREST); 31029 } 31030 state.bindFramebuffer(_gl.READ_FRAMEBUFFER, null); 31031 state.bindFramebuffer(_gl.DRAW_FRAMEBUFFER, null); 31032 } else if (srcLevel !== 0 || srcTexture.isRenderTargetTexture || properties.has(srcTexture)) { 31033 // get the appropriate frame buffers 31034 const srcTextureProperties = properties.get(srcTexture); 31035 const dstTextureProperties = properties.get(dstTexture); 31036 // bind the frame buffer targets 31037 state.bindFramebuffer(_gl.READ_FRAMEBUFFER, _srcFramebuffer); 31038 state.bindFramebuffer(_gl.DRAW_FRAMEBUFFER, _dstFramebuffer); 31039 for(let i = 0; i < depth; i++){ 31040 // assign the correct layers and mip maps to the frame buffers 31041 if (isSrc3D) { 31042 _gl.framebufferTextureLayer(_gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, srcTextureProperties.__webglTexture, srcLevel, minZ + i); 31043 } else { 31044 _gl.framebufferTexture2D(_gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, srcTextureProperties.__webglTexture, srcLevel); 31045 } 31046 if (isDst3D) { 31047 _gl.framebufferTextureLayer(_gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, dstTextureProperties.__webglTexture, dstLevel, dstZ + i); 31048 } else { 31049 _gl.framebufferTexture2D(_gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, dstTextureProperties.__webglTexture, dstLevel); 31050 } 31051 // copy the data using the fastest function that can achieve the copy 31052 if (srcLevel !== 0) { 31053 _gl.blitFramebuffer(minX, minY, width, height, dstX, dstY, width, height, _gl.COLOR_BUFFER_BIT, _gl.NEAREST); 31054 } else if (isDst3D) { 31055 _gl.copyTexSubImage3D(glTarget, dstLevel, dstX, dstY, dstZ + i, minX, minY, width, height); 31056 } else { 31057 _gl.copyTexSubImage2D(glTarget, dstLevel, dstX, dstY, minX, minY, width, height); 31058 } 31059 } 31060 // unbind read, draw buffers 31061 state.bindFramebuffer(_gl.READ_FRAMEBUFFER, null); 31062 state.bindFramebuffer(_gl.DRAW_FRAMEBUFFER, null); 31063 } else { 31064 if (isDst3D) { 31065 // copy data into the 3d texture 31066 if (srcTexture.isDataTexture || srcTexture.isData3DTexture) { 31067 _gl.texSubImage3D(glTarget, dstLevel, dstX, dstY, dstZ, width, height, depth, glFormat, glType, image.data); 31068 } else if (dstTexture.isCompressedArrayTexture) { 31069 _gl.compressedTexSubImage3D(glTarget, dstLevel, dstX, dstY, dstZ, width, height, depth, glFormat, image.data); 31070 } else { 31071 _gl.texSubImage3D(glTarget, dstLevel, dstX, dstY, dstZ, width, height, depth, glFormat, glType, image); 31072 } 31073 } else { 31074 // copy data into the 2d texture 31075 if (srcTexture.isDataTexture) { 31076 _gl.texSubImage2D(_gl.TEXTURE_2D, dstLevel, dstX, dstY, width, height, glFormat, glType, image.data); 31077 } else if (srcTexture.isCompressedTexture) { 31078 _gl.compressedTexSubImage2D(_gl.TEXTURE_2D, dstLevel, dstX, dstY, image.width, image.height, glFormat, image.data); 31079 } else { 31080 _gl.texSubImage2D(_gl.TEXTURE_2D, dstLevel, dstX, dstY, width, height, glFormat, glType, image); 31081 } 31082 } 31083 } 31084 // reset values 31085 _gl.pixelStorei(_gl.UNPACK_ROW_LENGTH, currentUnpackRowLen); 31086 _gl.pixelStorei(_gl.UNPACK_IMAGE_HEIGHT, currentUnpackImageHeight); 31087 _gl.pixelStorei(_gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels); 31088 _gl.pixelStorei(_gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows); 31089 _gl.pixelStorei(_gl.UNPACK_SKIP_IMAGES, currentUnpackSkipImages); 31090 // Generate mipmaps only when copying level 0 31091 if (dstLevel === 0 && dstTexture.generateMipmaps) { 31092 _gl.generateMipmap(glTarget); 31093 } 31094 state.unbindTexture(); 31095 }; 31096 this.copyTextureToTexture3D = function(srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0) { 31097 // support previous signature with source box first 31098 if (srcTexture.isTexture !== true) { 31099 // @deprecated, r165 31100 warnOnce('WebGLRenderer: copyTextureToTexture3D function signature has changed.'); 31101 srcRegion = arguments[0] || null; 31102 dstPosition = arguments[1] || null; 31103 srcTexture = arguments[2]; 31104 dstTexture = arguments[3]; 31105 level = arguments[4] || 0; 31106 } 31107 // @deprecated, r170 31108 warnOnce('WebGLRenderer: copyTextureToTexture3D function has been deprecated. Use "copyTextureToTexture" instead.'); 31109 return this.copyTextureToTexture(srcTexture, dstTexture, srcRegion, dstPosition, level); 31110 }; 31111 this.initRenderTarget = function(target) { 31112 if (properties.get(target).__webglFramebuffer === undefined) { 31113 textures.setupRenderTarget(target); 31114 } 31115 }; 31116 this.initTexture = function(texture) { 31117 if (texture.isCubeTexture) { 31118 textures.setTextureCube(texture, 0); 31119 } else if (texture.isData3DTexture) { 31120 textures.setTexture3D(texture, 0); 31121 } else if (texture.isDataArrayTexture || texture.isCompressedArrayTexture) { 31122 textures.setTexture2DArray(texture, 0); 31123 } else { 31124 textures.setTexture2D(texture, 0); 31125 } 31126 state.unbindTexture(); 31127 }; 31128 this.resetState = function() { 31129 _currentActiveCubeFace = 0; 31130 _currentActiveMipmapLevel = 0; 31131 _currentRenderTarget = null; 31132 state.reset(); 31133 bindingStates.reset(); 31134 }; 31135 if (typeof __THREE_DEVTOOLS__ !== 'undefined') { 31136 __THREE_DEVTOOLS__.dispatchEvent(new CustomEvent('observe', { 31137 detail: this 31138 })); 31139 } 31140 } 31141 } 31142
vendor: 11,446 bytes, lines 31143-31409
31143 /** 31144 * @license 31145 * Copyright 2017 Google LLC 31146 * SPDX-License-Identifier: BSD-3-Clause 31147 */ var _t; 31148 const t$1 = globalThis, i$2 = t$1.trustedTypes, s = i$2 ? i$2.createPolicy("lit-html", { 31149 createHTML: (t)=>t 31150 }) : void 0, e = "$lit$", h = `lit$${Math.random().toFixed(9).slice(2)}$`, o = "?" + h, n$1 = `<${o}>`, r$1 = document, l = ()=>r$1.createComment(""), c$1 = (t)=>null === t || "object" != typeof t && "function" != typeof t, a$1 = Array.isArray, u$1 = (t)=>a$1(t) || "function" == typeof t?.[Symbol.iterator], d = "[ \t\n\f\r]", f = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g, v = /-->/g, _ = />/g, m = RegExp(`>|${d}(?:([^\\s"'>=/]+)(${d}*=${d}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`, "g"), p = /'/g, g$2 = /"/g, $ = /^(?:script|style|textarea|title)$/i, y = (t)=>(i, ...s)=>({ 31151 _$litType$: t, 31152 strings: i, 31153 values: s 31154 }), x$1 = y(1), T$1 = Symbol.for("lit-noChange"), E = Symbol.for("lit-nothing"), A$1 = new WeakMap, C$2 = r$1.createTreeWalker(r$1, 129); 31155 function P(t, i) { 31156 if (!a$1(t) || !t.hasOwnProperty("raw")) throw Error("invalid template strings array"); 31157 return void 0 !== s ? s.createHTML(i) : i; 31158 } 31159 const V = (t, i)=>{ 31160 const s = t.length - 1, o = []; 31161 let r, l = 2 === i ? "<svg>" : 3 === i ? "<math>" : "", c = f; 31162 for(let i = 0; i < s; i++){ 31163 const s = t[i]; 31164 let a, u, d = -1, y = 0; 31165 for(; y < s.length && (c.lastIndex = y, u = c.exec(s), null !== u);)y = c.lastIndex, c === f ? "!--" === u[1] ? c = v : void 0 !== u[1] ? c = _ : void 0 !== u[2] ? ($.test(u[2]) && (r = RegExp("</" + u[2], "g")), c = m) : void 0 !== u[3] && (c = m) : c === m ? ">" === u[0] ? (c = r ?? f, d = -1) : void 0 === u[1] ? d = -2 : (d = c.lastIndex - u[2].length, a = u[1], c = void 0 === u[3] ? m : '"' === u[3] ? g$2 : p) : c === g$2 || c === p ? c = m : c === v || c === _ ? c = f : (c = m, r = void 0); 31166 const x = c === m && t[i + 1].startsWith("/>") ? " " : ""; 31167 l += c === f ? s + n$1 : d >= 0 ? (o.push(a), s.slice(0, d) + e + s.slice(d) + h + x) : s + h + (-2 === d ? i : x); 31168 } 31169 return [ 31170 P(t, l + (t[s] || "<?>") + (2 === i ? "</svg>" : 3 === i ? "</math>" : "")), 31171 o 31172 ]; 31173 }; 31174 class N { 31175 static createElement(t, i) { 31176 const s = r$1.createElement("template"); 31177 return s.innerHTML = t, s; 31178 } 31179 constructor({ strings: t, _$litType$: s }, n){ 31180 let r; 31181 this.parts = []; 31182 let c = 0, a = 0; 31183 const u = t.length - 1, d = this.parts, [f, v] = V(t, s); 31184 if (this.el = N.createElement(f, n), C$2.currentNode = this.el.content, 2 === s || 3 === s) { 31185 const t = this.el.content.firstChild; 31186 t.replaceWith(...t.childNodes); 31187 } 31188 for(; null !== (r = C$2.nextNode()) && d.length < u;){ 31189 if (1 === r.nodeType) { 31190 if (r.hasAttributes()) for (const t of r.getAttributeNames())if (t.endsWith(e)) { 31191 const i = v[a++], s = r.getAttribute(t).split(h), e = /([.?@])?(.*)/.exec(i); 31192 d.push({ 31193 type: 1, 31194 index: c, 31195 name: e[2], 31196 strings: s, 31197 ctor: "." === e[1] ? H : "?" === e[1] ? I$1 : "@" === e[1] ? L : k 31198 }), r.removeAttribute(t); 31199 } else t.startsWith(h) && (d.push({ 31200 type: 6, 31201 index: c 31202 }), r.removeAttribute(t)); 31203 if ($.test(r.tagName)) { 31204 const t = r.textContent.split(h), s = t.length - 1; 31205 if (s > 0) { 31206 r.textContent = i$2 ? i$2.emptyScript : ""; 31207 for(let i = 0; i < s; i++)r.append(t[i], l()), C$2.nextNode(), d.push({ 31208 type: 2, 31209 index: ++c 31210 }); 31211 r.append(t[s], l()); 31212 } 31213 } 31214 } else if (8 === r.nodeType) if (r.data === o) d.push({ 31215 type: 2, 31216 index: c 31217 }); 31218 else { 31219 let t = -1; 31220 for(; -1 !== (t = r.data.indexOf(h, t + 1));)d.push({ 31221 type: 7, 31222 index: c 31223 }), t += h.length - 1; 31224 } 31225 c++; 31226 } 31227 } 31228 } 31229 function S(t, i, s = t, e) { 31230 var _s; 31231 if (i === T$1) return i; 31232 let h = void 0 !== e ? s._$Co?.[e] : s._$Cl; 31233 const o = c$1(i) ? void 0 : i._$litDirective$; 31234 return h?.constructor !== o && (h?._$AO?.(false), void 0 === o ? h = void 0 : (h = new o(t), h._$AT(t, s, e)), void 0 !== e ? ((_s = s)._$Co ?? (_s._$Co = []))[e] = h : s._$Cl = h), void 0 !== h && (i = S(t, h._$AS(t, i.values), h, e)), i; 31235 } 31236 class M { 31237 get parentNode() { 31238 return this._$AM.parentNode; 31239 } 31240 get _$AU() { 31241 return this._$AM._$AU; 31242 } 31243 u(t) { 31244 const { el: { content: i }, parts: s } = this._$AD, e = (t?.creationScope ?? r$1).importNode(i, true); 31245 C$2.currentNode = e; 31246 let h = C$2.nextNode(), o = 0, n = 0, l = s[0]; 31247 for(; void 0 !== l;){ 31248 if (o === l.index) { 31249 let i; 31250 2 === l.type ? i = new R$1(h, h.nextSibling, this, t) : 1 === l.type ? i = new l.ctor(h, l.name, l.strings, this, t) : 6 === l.type && (i = new z(h, this, t)), this._$AV.push(i), l = s[++n]; 31251 } 31252 o !== l?.index && (h = C$2.nextNode(), o++); 31253 } 31254 return C$2.currentNode = r$1, e; 31255 } 31256 p(t) { 31257 let i = 0; 31258 for (const s of this._$AV) void 0 !== s && (void 0 !== s.strings ? (s._$AI(t, s, i), i += s.strings.length - 2) : s._$AI(t[i])), i++; 31259 } 31260 constructor(t, i){ 31261 this._$AV = [], this._$AN = void 0, this._$AD = t, this._$AM = i; 31262 } 31263 } 31264 let R$1 = class R { 31265 get _$AU() { 31266 return this._$AM?._$AU ?? this._$Cv; 31267 } 31268 get parentNode() { 31269 let t = this._$AA.parentNode; 31270 const i = this._$AM; 31271 return void 0 !== i && 11 === t?.nodeType && (t = i.parentNode), t; 31272 } 31273 get startNode() { 31274 return this._$AA; 31275 } 31276 get endNode() { 31277 return this._$AB; 31278 } 31279 _$AI(t, i = this) { 31280 t = S(this, t, i), c$1(t) ? t === E || null == t || "" === t ? (this._$AH !== E && this._$AR(), this._$AH = E) : t !== this._$AH && t !== T$1 && this._(t) : void 0 !== t._$litType$ ? this.$(t) : void 0 !== t.nodeType ? this.T(t) : u$1(t) ? this.k(t) : this._(t); 31281 } 31282 O(t) { 31283 return this._$AA.parentNode.insertBefore(t, this._$AB); 31284 } 31285 T(t) { 31286 this._$AH !== t && (this._$AR(), this._$AH = this.O(t)); 31287 } 31288 _(t) { 31289 this._$AH !== E && c$1(this._$AH) ? this._$AA.nextSibling.data = t : this.T(r$1.createTextNode(t)), this._$AH = t; 31290 } 31291 $(t) { 31292 const { values: i, _$litType$: s } = t, e = "number" == typeof s ? this._$AC(t) : (void 0 === s.el && (s.el = N.createElement(P(s.h, s.h[0]), this.options)), s); 31293 if (this._$AH?._$AD === e) this._$AH.p(i); 31294 else { 31295 const t = new M(e, this), s = t.u(this.options); 31296 t.p(i), this.T(s), this._$AH = t; 31297 } 31298 } 31299 _$AC(t) { 31300 let i = A$1.get(t.strings); 31301 return void 0 === i && A$1.set(t.strings, i = new N(t)), i; 31302 } 31303 k(t) { 31304 a$1(this._$AH) || (this._$AH = [], this._$AR()); 31305 const i = this._$AH; 31306 let s, e = 0; 31307 for (const h of t)e === i.length ? i.push(s = new R(this.O(l()), this.O(l()), this, this.options)) : s = i[e], s._$AI(h), e++; 31308 e < i.length && (this._$AR(s && s._$AB.nextSibling, e), i.length = e); 31309 } 31310 _$AR(t = this._$AA.nextSibling, i) { 31311 for(this._$AP?.(false, true, i); t && t !== this._$AB;){ 31312 const i = t.nextSibling; 31313 t.remove(), t = i; 31314 } 31315 } 31316 setConnected(t) { 31317 void 0 === this._$AM && (this._$Cv = t, this._$AP?.(t)); 31318 } 31319 constructor(t, i, s, e){ 31320 this.type = 2, this._$AH = E, this._$AN = void 0, this._$AA = t, this._$AB = i, this._$AM = s, this.options = e, this._$Cv = e?.isConnected ?? true; 31321 } 31322 }; 31323 class k { 31324 get tagName() { 31325 return this.element.tagName; 31326 } 31327 get _$AU() { 31328 return this._$AM._$AU; 31329 } 31330 _$AI(t, i = this, s, e) { 31331 const h = this.strings; 31332 let o = false; 31333 if (void 0 === h) t = S(this, t, i, 0), o = !c$1(t) || t !== this._$AH && t !== T$1, o && (this._$AH = t); 31334 else { 31335 const e = t; 31336 let n, r; 31337 for(t = h[0], n = 0; n < h.length - 1; n++)r = S(this, e[s + n], i, n), r === T$1 && (r = this._$AH[n]), o || (o = !c$1(r) || r !== this._$AH[n]), r === E ? t = E : t !== E && (t += (r ?? "") + h[n + 1]), this._$AH[n] = r; 31338 } 31339 o && !e && this.j(t); 31340 } 31341 j(t) { 31342 t === E ? this.element.removeAttribute(this.name) : this.element.setAttribute(this.name, t ?? ""); 31343 } 31344 constructor(t, i, s, e, h){ 31345 this.type = 1, this._$AH = E, this._$AN = void 0, this.element = t, this.name = i, this._$AM = e, this.options = h, s.length > 2 || "" !== s[0] || "" !== s[1] ? (this._$AH = Array(s.length - 1).fill(new String), this.strings = s) : this._$AH = E; 31346 } 31347 } 31348 class H extends k { 31349 j(t) { 31350 this.element[this.name] = t === E ? void 0 : t; 31351 } 31352 constructor(){ 31353 super(...arguments), this.type = 3; 31354 } 31355 } 31356 let I$1 = class I extends k { 31357 j(t) { 31358 this.element.toggleAttribute(this.name, !!t && t !== E); 31359 } 31360 constructor(){ 31361 super(...arguments), this.type = 4; 31362 } 31363 }; 31364 class L extends k { 31365 _$AI(t, i = this) { 31366 if ((t = S(this, t, i, 0) ?? E) === T$1) return; 31367 const s = this._$AH, e = t === E && s !== E || t.capture !== s.capture || t.once !== s.once || t.passive !== s.passive, h = t !== E && (s === E || e); 31368 e && this.element.removeEventListener(this.name, this, s), h && this.element.addEventListener(this.name, this, t), this._$AH = t; 31369 } 31370 handleEvent(t) { 31371 "function" == typeof this._$AH ? this._$AH.call(this.options?.host ?? this.element, t) : this._$AH.handleEvent(t); 31372 } 31373 constructor(t, i, s, e, h){ 31374 super(t, i, s, e, h), this.type = 5; 31375 } 31376 } 31377 class z { 31378 get _$AU() { 31379 return this._$AM._$AU; 31380 } 31381 _$AI(t) { 31382 S(this, t); 31383 } 31384 constructor(t, i, s){ 31385 this.element = t, this.type = 6, this._$AN = void 0, this._$AM = i, this.options = s; 31386 } 31387 } 31388 const j = t$1.litHtmlPolyfillSupport; 31389 j?.(N, R$1), ((_t = t$1).litHtmlVersions ?? (_t.litHtmlVersions = [])).push("3.2.1"); 31390 const B$1 = (t, i, s)=>{ 31391 const e = s?.renderBefore ?? i; 31392 let h = e._$litPart$; 31393 if (void 0 === h) { 31394 const t = s?.renderBefore ?? null; 31395 e._$litPart$ = h = new R$1(i.insertBefore(l(), t), t, void 0, s ?? {}); 31396 } 31397 return h._$AI(t), h; 31398 }; 31399 31400 var _globalThis; 31401 /** 31402 * @license 31403 * Copyright 2017 Google LLC 31404 * SPDX-License-Identifier: BSD-3-Clause 31405 */ class r extends b$1 { 31406 createRenderRoot() { 31407 var _this_renderOptions; 31408 const t = super.createRenderRoot(); 31409 return (_this_renderOptions = this.renderOptions).renderBefore ?? (_this_renderOptions.renderBefore = t.firstChild), t;
vendor: 4,398 bytes, lines 31410-31467
31410 } 31411 update(t) { 31412 const s = this.render(); 31413 this.hasUpdated || (this.renderOptions.isConnected = this.isConnected), super.update(t), this._$Do = B$1(s, this.renderRoot, this.renderOptions); 31414 } 31415 connectedCallback() { 31416 super.connectedCallback(), this._$Do?.setConnected(true); 31417 } 31418 disconnectedCallback() { 31419 super.disconnectedCallback(), this._$Do?.setConnected(false); 31420 } 31421 render() { 31422 return T$1; 31423 } 31424 constructor(){ 31425 super(...arguments), this.renderOptions = { 31426 host: this 31427 }, this._$Do = void 0; 31428 } 31429 } 31430 r._$litElement$ = true, r["finalized"] = true, globalThis.litElementHydrateSupport?.({ 31431 LitElement: r 31432 }); 31433 const i$1 = globalThis.litElementPolyfillSupport; 31434 i$1?.({ 31435 LitElement: r 31436 }); 31437 ((_globalThis = globalThis).litElementVersions ?? (_globalThis.litElementVersions = [])).push("4.1.1"); 31438 31439 const HAS_WEBXR_DEVICE_API = navigator.xr != null && self.XRSession != null && navigator.xr.isSessionSupported != null; 31440 const HAS_WEBXR_HIT_TEST_API = HAS_WEBXR_DEVICE_API && self.XRSession.prototype.requestHitTestSource != null; 31441 const HAS_RESIZE_OBSERVER = self.ResizeObserver != null; 31442 const HAS_INTERSECTION_OBSERVER = self.IntersectionObserver != null; 31443 const IS_WEBXR_AR_CANDIDATE = HAS_WEBXR_HIT_TEST_API; 31444 (()=>{ 31445 const userAgent = navigator.userAgent || navigator.vendor || self.opera; 31446 let check = false; 31447 if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(userAgent) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(userAgent.substr(0, 4))) { 31448 check = true; 31449 } 31450 return check; 31451 })(); 31452 const IS_ANDROID = /android/i.test(navigator.userAgent); 31453 const IS_IOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !self.MSStream || navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1; 31454 const IS_FIREFOX = /firefox/i.test(navigator.userAgent); 31455 const IS_OCULUS = /OculusBrowser/.test(navigator.userAgent); 31456 const IS_SCENEVIEWER_CANDIDATE = IS_ANDROID && !IS_FIREFOX && !IS_OCULUS; 31457 const IS_WKWEBVIEW = Boolean(window.webkit && window.webkit.messageHandlers); 31458 const IS_AR_QUICKLOOK_CANDIDATE = (()=>{ 31459 if (IS_IOS) { 31460 if (!IS_WKWEBVIEW) { 31461 const tempAnchor = document.createElement('a'); 31462 return Boolean(tempAnchor.relList && tempAnchor.relList.supports && tempAnchor.relList.supports('ar')); 31463 } else { 31464 return Boolean(/CriOS\/|EdgiOS\/|FxiOS\/|GSA\/|DuckDuckGo\//.test(navigator.userAgent)); 31465 } 31466 } else { 31467 return false;
vendor: 4,727 bytes, lines 31468-31577
31468 } 31469 })(); 31470 31471 const deserializeUrl = (url)=>!!url && url !== 'null' ? toFullUrl(url) : null; 31472 const assertIsArCandidate = ()=>{ 31473 if (IS_WEBXR_AR_CANDIDATE) { 31474 return; 31475 } 31476 const missingApis = []; 31477 if (!HAS_WEBXR_DEVICE_API) { 31478 missingApis.push('WebXR Device API'); 31479 } 31480 if (!HAS_WEBXR_HIT_TEST_API) { 31481 missingApis.push('WebXR Hit Test API'); 31482 } 31483 throw new Error(`The following APIs are required for AR, but are missing in this browser: ${missingApis.join(', ')}`); 31484 }; 31485 const toFullUrl = (partialUrl)=>{ 31486 const url = new URL(partialUrl, window.location.toString()); 31487 return url.toString(); 31488 }; 31489 const throttle = (fn, ms)=>{ 31490 let timer = null; 31491 const throttled = (...args)=>{ 31492 if (timer != null) { 31493 return; 31494 } 31495 fn(...args); 31496 timer = self.setTimeout(()=>timer = null, ms); 31497 }; 31498 throttled.flush = ()=>{ 31499 if (timer != null) { 31500 self.clearTimeout(timer); 31501 timer = null; 31502 } 31503 }; 31504 return throttled; 31505 }; 31506 const debounce = (fn, ms)=>{ 31507 let timer = null; 31508 return (...args)=>{ 31509 if (timer != null) { 31510 self.clearTimeout(timer); 31511 } 31512 timer = self.setTimeout(()=>{ 31513 timer = null; 31514 fn(...args); 31515 }, ms); 31516 }; 31517 }; 31518 const clamp = (value, lowerLimit, upperLimit)=>Math.max(lowerLimit, Math.min(upperLimit, value)); 31519 const isDebugMode = (()=>{ 31520 const debugQueryParameterName = 'model-viewer-debug-mode'; 31521 const debugQueryParameter = new RegExp(`[?&]${debugQueryParameterName}(&|$)`); 31522 return ()=>self.ModelViewerElement && self.ModelViewerElement.debugMode || self.location && self.location.search && self.location.search.match(debugQueryParameter); 31523 })(); 31524 const timePasses = (ms = 0)=>new Promise((resolve)=>setTimeout(resolve, ms)); 31525 const waitForEvent = (target, eventName, predicate = null)=>new Promise((resolve)=>{ 31526 function handler(event) { 31527 if (!predicate || predicate(event)) { 31528 resolve(event); 31529 target.removeEventListener(eventName, handler); 31530 } 31531 } 31532 target.addEventListener(eventName, handler); 31533 }); 31534 31535 var __decorate$7 = undefined && undefined.__decorate || function(decorators, target, key, desc) { 31536 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 31537 for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 31538 return c > 3 && r && Object.defineProperty(target, key, r), r; 31539 }; 31540 const BASE_OPACITY = 0.5; 31541 const DEFAULT_SHADOW_INTENSITY = 0.0; 31542 const DEFAULT_SHADOW_SOFTNESS = 1.0; 31543 const DEFAULT_EXPOSURE = 1.0; 31544 const $currentEnvironmentMap = Symbol('currentEnvironmentMap'); 31545 const $currentBackground = Symbol('currentBackground'); 31546 const $updateEnvironment = Symbol('updateEnvironment'); 31547 const $cancelEnvironmentUpdate = Symbol('cancelEnvironmentUpdate'); 31548 const EnvironmentMixin = (ModelViewerElement)=>{ 31549 var _a, _b, _c; 31550 class EnvironmentModelViewerElement extends ModelViewerElement { 31551 updated(changedProperties) { 31552 super.updated(changedProperties); 31553 if (changedProperties.has('shadowIntensity')) { 31554 this[$scene].setShadowIntensity(this.shadowIntensity * BASE_OPACITY); 31555 this[$needsRender](); 31556 } 31557 if (changedProperties.has('shadowSoftness')) { 31558 this[$scene].setShadowSoftness(this.shadowSoftness); 31559 this[$needsRender](); 31560 } 31561 if (changedProperties.has('exposure')) { 31562 this[$scene].exposure = this.exposure; 31563 this[$needsRender](); 31564 } 31565 if (changedProperties.has('toneMapping')) { 31566 this[$scene].toneMapping = this.toneMapping === 'aces' ? ACESFilmicToneMapping : this.toneMapping === 'agx' ? AgXToneMapping : this.toneMapping === 'reinhard' ? ReinhardToneMapping : this.toneMapping === 'cineon' ? CineonToneMapping : this.toneMapping === 'linear' ? LinearToneMapping : this.toneMapping === 'none' ? NoToneMapping : NeutralToneMapping; 31567 this[$needsRender](); 31568 } 31569 if ((changedProperties.has('environmentImage') || changedProperties.has('skyboxImage')) && this[$shouldAttemptPreload]()) { 31570 this[$updateEnvironment](); 31571 } 31572 if (changedProperties.has('skyboxHeight')) { 31573 this[$scene].setGroundedSkybox(); 31574 this[$needsRender](); 31575 } 31576 } 31577 hasBakedShadow() {
vendor: 4,358 bytes, lines 31578-31685
31578 return this[$scene].bakedShadows.size > 0; 31579 } 31580 async [(_a = $currentEnvironmentMap, _b = $currentBackground, _c = $cancelEnvironmentUpdate, $updateEnvironment)]() { 31581 const { skyboxImage, environmentImage } = this; 31582 if (this[$cancelEnvironmentUpdate] != null) { 31583 this[$cancelEnvironmentUpdate](); 31584 this[$cancelEnvironmentUpdate] = null; 31585 } 31586 const { textureUtils } = this[$renderer]; 31587 if (textureUtils == null) { 31588 return; 31589 } 31590 const updateEnvProgress = this[$progressTracker].beginActivity('environment-update'); 31591 try { 31592 const { environmentMap, skybox } = await textureUtils.generateEnvironmentMapAndSkybox(deserializeUrl(skyboxImage), environmentImage, (progress)=>updateEnvProgress(clamp(progress, 0, 1)), this.withCredentials); 31593 if (this[$currentEnvironmentMap] !== environmentMap) { 31594 this[$currentEnvironmentMap] = environmentMap; 31595 this.dispatchEvent(new CustomEvent('environment-change')); 31596 } 31597 if (skybox != null) { 31598 this[$currentBackground] = skybox.name === environmentMap.name ? environmentMap : skybox; 31599 } else { 31600 this[$currentBackground] = null; 31601 } 31602 this[$scene].setEnvironmentAndSkybox(this[$currentEnvironmentMap], this[$currentBackground]); 31603 } catch (errorOrPromise) { 31604 if (errorOrPromise instanceof Error) { 31605 this[$scene].setEnvironmentAndSkybox(null, null); 31606 throw errorOrPromise; 31607 } 31608 } finally{ 31609 updateEnvProgress(1.0); 31610 } 31611 } 31612 constructor(){ 31613 super(...arguments); 31614 this.environmentImage = null; 31615 this.skyboxImage = null; 31616 this.shadowIntensity = DEFAULT_SHADOW_INTENSITY; 31617 this.shadowSoftness = DEFAULT_SHADOW_SOFTNESS; 31618 this.exposure = DEFAULT_EXPOSURE; 31619 this.toneMapping = 'auto'; 31620 this.skyboxHeight = '0'; 31621 this[_a] = null; 31622 this[_b] = null; 31623 this[_c] = null; 31624 } 31625 } 31626 __decorate$7([ 31627 n$2({ 31628 type: String, 31629 attribute: 'environment-image' 31630 }) 31631 ], EnvironmentModelViewerElement.prototype, "environmentImage", void 0); 31632 __decorate$7([ 31633 n$2({ 31634 type: String, 31635 attribute: 'skybox-image' 31636 }) 31637 ], EnvironmentModelViewerElement.prototype, "skyboxImage", void 0); 31638 __decorate$7([ 31639 n$2({ 31640 type: Number, 31641 attribute: 'shadow-intensity' 31642 }) 31643 ], EnvironmentModelViewerElement.prototype, "shadowIntensity", void 0); 31644 __decorate$7([ 31645 n$2({ 31646 type: Number, 31647 attribute: 'shadow-softness' 31648 }) 31649 ], EnvironmentModelViewerElement.prototype, "shadowSoftness", void 0); 31650 __decorate$7([ 31651 n$2({ 31652 type: Number 31653 }) 31654 ], EnvironmentModelViewerElement.prototype, "exposure", void 0); 31655 __decorate$7([ 31656 n$2({ 31657 type: String, 31658 attribute: 'tone-mapping' 31659 }) 31660 ], EnvironmentModelViewerElement.prototype, "toneMapping", void 0); 31661 __decorate$7([ 31662 n$2({ 31663 type: String, 31664 attribute: 'skybox-height' 31665 }) 31666 ], EnvironmentModelViewerElement.prototype, "skyboxHeight", void 0); 31667 return EnvironmentModelViewerElement; 31668 }; 31669 31670 var CloseIcon = x$1` 31671<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24" fill="#000000"> 31672 <!-- NOTE(cdata): This SVG filter is a stop-gap until we can implement 31673 support for dynamic re-coloring of UI components --> 31674 <defs> 31675 <filter id="drop-shadow" x="-100%" y="-100%" width="300%" height="300%"> 31676 <feGaussianBlur in="SourceAlpha" stdDeviation="1"/> 31677 <feOffset dx="0" dy="0" result="offsetblur"/> 31678 <feFlood flood-color="#000000"/> 31679 <feComposite in2="offsetblur" operator="in"/> 31680 <feMerge> 31681 <feMergeNode/> 31682 <feMergeNode in="SourceGraphic"/> 31683 </feMerge> 31684 </filter> 31685 </defs>
31686 <path filter="url(#drop-shadow)" d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/> 31687 <path d="M0 0h24v24H0z" fill="none"/> 31688</svg>`; 31689 31690 var ControlsPrompt = x$1` 31691<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="25" height="36"> 31692 <defs> 31693 <path id="A" d="M.001.232h24.997V36H.001z" /> 31694 </defs> 31695 <g transform="translate(-11 -4)" fill="none" fill-rule="evenodd"> 31696 <path fill-opacity="0" fill="#fff" d="M0 0h44v44H0z" /> 31697 <g transform="translate(11 3)"> 31698 <path d="M8.733 11.165c.04-1.108.766-2.027 1.743-2.307a2.54 2.54 0 0 1 .628-.089c.16 0 .314.017.463.044 1.088.2 1.9 1.092 1.9 2.16v8.88h1.26c2.943-1.39 5-4.45 5-8.025a9.01 9.01 0 0 0-1.9-5.56l-.43-.5c-.765-.838-1.683-1.522-2.712-2-1.057-.49-2.226-.77-3.46-.77s-2.4.278-3.46.77c-1.03.478-1.947 1.162-2.71 2l-.43.5a9.01 9.01 0 0 0-1.9 5.56 9.04 9.04 0 0 0 .094 1.305c.03.21.088.41.13.617l.136.624c.083.286.196.56.305.832l.124.333a8.78 8.78 0 0 0 .509.953l.065.122a8.69 8.69 0 0 0 3.521 3.191l1.11.537v-9.178z" fill-opacity=".5" fill="#e4e4e4" /> 31699 <path d="M22.94 26.218l-2.76 7.74c-.172.485-.676.8-1.253.8H12.24c-1.606 0-3.092-.68-3.98-1.82-1.592-2.048-3.647-3.822-6.11-5.27-.095-.055-.15-.137-.152-.23-.004-.1.046-.196.193-.297.56-.393 1.234-.6 1.926-.6a3.43 3.43 0 0 1 .691.069l4.922.994V10.972c0-.663.615-1.203 1.37-1.203s1.373.54 1.373 1.203v9.882h2.953c.273 0 .533.073.757.21l6.257 3.874c.027.017.045.042.07.06.41.296.586.77.426 1.22M4.1 16.614c-.024-.04-.042-.083-.065-.122a8.69 8.69 0 0 1-.509-.953c-.048-.107-.08-.223-.124-.333l-.305-.832c-.058-.202-.09-.416-.136-.624l-.13-.617a9.03 9.03 0 0 1-.094-1.305c0-2.107.714-4.04 1.9-5.56l.43-.5c.764-.84 1.682-1.523 2.71-2 1.058-.49 2.226-.77 3.46-.77s2.402.28 3.46.77c1.03.477 1.947 1.16 2.712 2l.428.5a9 9 0 0 1 1.901 5.559c0 3.577-2.056 6.636-5 8.026h-1.26v-8.882c0-1.067-.822-1.96-1.9-2.16-.15-.028-.304-.044-.463-.044-.22 0-.427.037-.628.09-.977.28-1.703 1.198-1.743 2.306v9.178l-1.11-.537C6.18 19.098 4.96 18 4.1 16.614M22.97 24.09l-6.256-3.874c-.102-.063-.218-.098-.33-.144 2.683-1.8 4.354-4.855 4.354-8.243 0-.486-.037-.964-.104-1.43a9.97 9.97 0 0 0-1.57-4.128l-.295-.408-.066-.092a10.05 10.05 0 0 0-.949-1.078c-.342-.334-.708-.643-1.094-.922-1.155-.834-2.492-1.412-3.94-1.65l-.732-.088-.748-.03a9.29 9.29 0 0 0-1.482.119c-1.447.238-2.786.816-3.94 1.65a9.33 9.33 0 0 0-.813.686 9.59 9.59 0 0 0-.845.877l-.385.437-.36.5-.288.468-.418.778-.04.09c-.593 1.28-.93 2.71-.93 4.222 0 3.832 2.182 7.342 5.56 8.938l1.437.68v4.946L5 25.64a4.44 4.44 0 0 0-.888-.086c-.017 0-.034.003-.05.003-.252.004-.503.033-.75.08a5.08 5.08 0 0 0-.237.056c-.193.046-.382.107-.568.18-.075.03-.15.057-.225.1-.25.114-.494.244-.723.405a1.31 1.31 0 0 0-.566 1.122 1.28 1.28 0 0 0 .645 1.051C4 29.925 5.96 31.614 7.473 33.563a5.06 5.06 0 0 0 .434.491c1.086 1.082 2.656 1.713 4.326 1.715h6.697c.748-.001 1.43-.333 1.858-.872.142-.18.256-.38.336-.602l2.757-7.74c.094-.26.13-.53.112-.794s-.088-.52-.203-.76a2.19 2.19 0 0 0-.821-.91" fill-opacity=".6" fill="#000" /> 31700 <path d="M22.444 24.94l-6.257-3.874a1.45 1.45 0 0 0-.757-.211h-2.953v-9.88c0-.663-.616-1.203-1.373-1.203s-1.37.54-1.37 1.203v16.643l-4.922-.994a3.44 3.44 0 0 0-.692-.069 3.35 3.35 0 0 0-1.925.598c-.147.102-.198.198-.194.298.004.094.058.176.153.23 2.462 1.448 4.517 3.22 6.11 5.27.887 1.14 2.373 1.82 3.98 1.82h6.686c.577 0 1.08-.326 1.253-.8l2.76-7.74c.16-.448-.017-.923-.426-1.22-.025-.02-.043-.043-.07-.06z" fill="#fff" /> 31701 <g transform="translate(0 .769)"> 31702 <mask id="B" fill="#fff"> 31703 <use xlink:href="#A" /> 31704 </mask> 31705 <path d="M23.993 24.992a1.96 1.96 0 0 1-.111.794l-2.758 7.74c-.08.22-.194.423-.336.602-.427.54-1.11.87-1.857.872h-6.698c-1.67-.002-3.24-.633-4.326-1.715-.154-.154-.3-.318-.434-.49C5.96 30.846 4 29.157 1.646 27.773c-.385-.225-.626-.618-.645-1.05a1.31 1.31 0 0 1 .566-1.122 4.56 4.56 0 0 1 .723-.405l.225-.1a4.3 4.3 0 0 1 .568-.18l.237-.056c.248-.046.5-.075.75-.08.018 0 .034-.003.05-.003.303-.001.597.027.89.086l3.722.752V20.68l-1.436-.68c-3.377-1.596-5.56-5.106-5.56-8.938 0-1.51.336-2.94.93-4.222.015-.03.025-.06.
3170504-.09.127-.267.268-.525.418-.778.093-.16.186-.316.288-.468.063-.095.133-.186.2-.277L3.773 5c.118-.155.26-.29.385-.437.266-.3.544-.604.845-.877a9.33 9.33 0 0 1 .813-.686C6.97 2.167 8.31 1.59 9.757 1.35a9.27 9.27 0 0 1 1.481-.119 8.82 8.82 0 0 1 .748.031c.247.02.49.05.733.088 1.448.238 2.786.816 3.94 1.65.387.28.752.588 1.094.922a9.94 9.94 0 0 1 .949 1.078l.066.092c.102.133.203.268.295.408a9.97 9.97 0 0 1 1.571 4.128c.066.467.103.945.103 1.43 0 3.388-1.67 6.453-4.353 8.243.11.046.227.08.33.144l6.256 3.874c.37.23.645.55.82.9.115.24.185.498.203.76m.697-1.195c-.265-.55-.677-1.007-1.194-1.326l-5.323-3.297c2.255-2.037 3.564-4.97 3.564-8.114 0-2.19-.637-4.304-1.84-6.114-.126-.188-.26-.37-.4-.552-.645-.848-1.402-1.6-2.252-2.204C15.472.91 13.393.232 11.238.232A10.21 10.21 0 0 0 5.23 2.19c-.848.614-1.606 1.356-2.253 2.205-.136.18-.272.363-.398.55C1.374 6.756.737 8.87.737 11.06c0 4.218 2.407 8.08 6.133 9.842l.863.41v3.092l-2.525-.51c-.356-.07-.717-.106-1.076-.106a5.45 5.45 0 0 0-3.14.996c-.653.46-1.022 1.202-.99 1.983a2.28 2.28 0 0 0 1.138 1.872c2.24 1.318 4.106 2.923 5.543 4.772 1.26 1.62 3.333 2.59 5.55 2.592h6.698c1.42-.001 2.68-.86 3.134-2.138l2.76-7.74c.272-.757.224-1.584-.134-2.325" fill-opacity=".05" fill="#000" mask="url(#B)" /> 31706 </g> 31707 </g> 31708 </g> 31709</svg>`; 31710 31711 var ARGlyph = x$1` 31712<svg version="1.1" id="view_x5F_in_x5F_AR_x5F_icon" 31713 xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px" height="24px" 31714 viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve"> 31715<rect id="Bounding_Box" x="0" y="0" fill="none" width="24" height="24"/> 31716<g id="Art_layer"> 31717 <path d="M3,4c0-0.55,0.45-1,1-1h2V1H4C2.35,1,1,2.35,1,4v2h2V4z"/> 31718 <path d="M20,3c0.55,0,1,0.45,1,1v2h2V4c0-1.65-1.35-3-3-3h-2v2H20z"/> 31719 <path d="M4,21c-0.55,0-1-0.45-1-1v-2H1v2c0,1.65,1.35,3,3,3h2v-2H4z"/> 31720 <path d="M20,21c0.55,0,1-0.45,1-1v-2h2v2c0,1.65-1.35,3-3,3h-2v-2H20z"/> 31721 <g> 31722 <path d="M18.25,7.6l-5.5-3.18c-0.46-0.27-1.04-0.27-1.5,0L5.75,7.6C5.29,7.87,5,8.36,5,8.9v6.35c0,0.54,0.29,1.03,0.75,1.3 31723 l5.5,3.18c0.46,0.27,1.04,0.27,1.5,0l5.5-3.18c0.46-0.27,0.75-0.76,0.75-1.3V8.9C19,8.36,18.71,7.87,18.25,7.6z M7,14.96v-4.62 31724 l4,2.32v4.61L7,14.96z M12,10.93L8,8.61l4-2.31l4,2.31L12,10.93z M13,17.27v-4.61l4-2.32v4.62L13,17.27z"/> 31725 </g> 31726</g> 31727</svg>`; 31728 31729 const templateResult = x$1` 31730<style> 31731:host { 31732 display: block; 31733 position: relative; 31734 contain: strict; 31735 width: 300px; 31736 height: 150px; 31737} 31738 31739.container { 31740 position: relative; 31741 overflow: hidden; 31742} 31743 31744.userInput { 31745 width: 100%; 31746 height: 100%; 31747 display: none; 31748 position: relative; 31749 outline-offset: -1px; 31750 outline-width: 1px; 31751} 31752 31753canvas { 31754 position: absolute; 31755 display: none; 31756 pointer-events: none; 31757 /* NOTE(cdata): Chrome 76 and below apparently have a bug 31758 * that causes our canvas not to display pixels unless it is 31759 * on its own render layer 31760 * @see https://github.com/google/model-viewer/pull/755#issuecomment-536597893 31761 */ 31762 transform: translateZ(0); 31763} 31764 31765.show { 31766 display: block; 31767} 31768 31769/* Adapted from HTML5 Boilerplate 31770 * 31771 * @see https://github.com/h5bp/html5-boilerplate/blob/ceb4620c78fc82e13534fc44202a3f168754873f/dist/css/main.css#L122-L133 */ 31772.screen-reader-only { 31773 border: 0; 31774 left: 0; 31775 top: 0; 31776 clip: rect(0, 0, 0, 0); 31777 height: 1px; 31778 margin: -1px; 31779 overflow: hidden; 31780 padding: 0; 31781 position: absolute; 31782 white-space: nowrap; 31783 width: 1px; 31784 pointer-events: none; 31785} 31786 31787.slot { 31788 position: absolute; 31789 pointer-events: none; 31790 top: 0; 31791 left: 0; 31792 width: 100%; 31793 height: 100%; 31794} 31795 31796.slot > * { 31797 pointer-events: initial; 31798} 31799 31800.annotation-wrapper ::slotted(*) { 31801 opacity: var(--max-hotspot-opacity, 1); 31802 transition: opacity 0.3s; 31803} 31804 31805.pointer-tumbling .annotation-wrapper ::slotted(*) { 31806 pointer-events: none; 31807} 31808 31809.annotation-wrapper ::slotted(*) { 31810 pointer-events: initial; 31811} 31812 31813.annotation-wrapper.hide ::slotted(*) { 31814 opacity: var(--min-hotspot-opacity, 0.25); 31815} 31816 31817.slot.poster { 31818 display: none; 31819 background-color: inherit; 31820} 31821 31822.slot.poster.show { 31823 display: inherit; 31824} 31825 31826.slot.poster > * { 31827 pointer-events: initial; 31828} 31829 31830.slot.poster:not(.show) > * { 31831 pointer-events: none; 31832} 31833 31834#default-poster { 31835 width: 100%; 31836 height: 100%; 31837 /* The default poster is a <button> so we need to set display 31838 * to prevent it from being affected by text-align: */ 31839 display: block; 31840 position: absolute; 31841 border: none; 31842 padding: 0; 31843 background-size: contain; 31844 background-repeat: no-repeat; 31845 background-position: center; 31846 background-color: #fff0; 31847} 31848 31849#default-progress-bar { 31850 display: block; 31851 position: relative; 31852 width: 100%; 31853 height: 100%; 31854 pointer-events: none; 31855 overflow: hidden; 31856} 31857 31858#default-progress-bar > .bar { 31859 position: absolute; 31860 top: 0; 31861 left: 0; 31862 width: 100%; 31863 height: var(--progress-bar-height, 5px); 31864 background-color: var(--progress-bar-color, rgba(0, 0, 0, 0.4)); 31865 transition: transform 0.09s; 31866 transform-origin: top left; 31867 transform: scaleX(0); 31868 overflow: hidden; 31869} 31870 31871#default-progress-bar > .bar.hide { 31872 transition: opacity 0.3s 1s; 31873 opacity: 0; 31874} 31875 31876.centered { 31877 align-items: center; 31878 justify-content: center; 31879} 31880 31881.cover { 31882 position: absolute; 31883 top: 0; 31884 left: 0; 31885 width: 100%; 31886 height: 100%; 31887 pointer-events: none; 31888} 31889 31890.slot.interaction-prompt { 31891 display: var(--interaction-prompt-display, flex); 31892 overflow: hidden; 31893 opacity: 0; 31894 will-change: opacity; 31895 transition: opacity 0.3s; 31896} 31897 31898.slot.interaction-prompt.visible { 31899 opacity: 1; 31900} 31901 31902.animated-container { 31903 will-change: transform, opacity; 31904 opacity: 0; 31905 transition: opacity 0.3s; 31906} 31907 31908.slot.interaction-prompt > * { 31909 pointer-events: none; 31910} 31911 31912.slot.ar-button { 31913 -moz-user-select: none; 31914 -webkit-tap-highlight-color: transparent; 31915 user-select: none; 31916 31917 display: var(--ar-button-display, block); 31918} 31919 31920.slot.ar-button:not(.enabled) { 31921 display: none; 31922} 31923 31924.fab { 31925 display: flex; 31926 align-items: center; 31927 justify-content: center; 31928 box-sizing: border-box; 31929 width: 40px; 31930 height: 40px; 31931 cursor: pointer; 31932 background-color: #fff; 31933 box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.15); 31934 border-radius: 100px; 31935} 31936 31937.fab > * { 31938 opacity: 0.87; 31939} 31940 31941#default-ar-button { 31942 position: absolute; 31943 bottom: 16px; 31944 right: 16px; 31945 transform: scale(var(--ar-button-scale, 1)); 31946 transform-origin: bottom right; 31947} 31948 31949.slot.pan-target { 31950 display: block; 31951 position: absolute; 31952 width: 0; 31953 height: 0; 31954 left: 50%; 31955 top: 50%; 31956 transform: translate3d(-50%, -50%, 0); 31957 background-color: transparent; 31958 opacity: 0; 31959 transition: opacity 0.3s; 31960} 31961 31962#default-pan-target { 31963 width: 6px; 31964 height: 6px; 31965 border-radius: 6px; 31966 border: 1px solid white; 31967 box-shadow: 0px 0px 2px 1px rgba(0, 0, 0, 0.8); 31968} 31969 31970.slot.default { 31971 pointer-events: none; 31972} 31973 31974.slot.progress-bar { 31975 pointer-events: none; 31976} 31977 31978.slot.exit-webxr-ar-button { 31979 pointer-events: none; 31980} 31981 31982.slot.exit-webxr-ar-button:not(.enabled) { 31983 display: none; 31984} 31985 31986#default-exit-webxr-ar-button { 31987 display: flex; 31988 align-items: center; 31989 justify-content: center; 31990 position: absolute; 31991 top: env(safe-area-inset-top, 16px); 31992 right: 16px; 31993 width: 40px; 31994 height: 40px; 31995 box-sizing: border-box; 31996} 31997 31998#default-exit-webxr-ar-button > svg { 31999 fill: #fff; 32000} 32001</style> 32002<div class="container"> 32003 <div class="userInput" tabindex="0" role="img" 32004 aria-label="3D model"> 32005 <div class="slot canvas"> 32006 <slot name="canvas"> 32007 <canvas></canvas> 32008 </slot> 32009 </div> 32010 32011 </div> 32012 32013 <!-- NOTE(cdata): We need to wrap slots because browsers without ShadowDOM 32014 will have their <slot> elements removed by ShadyCSS --> 32015 <div class="slot poster"> 32016 <slot name="poster"> 32017 <button type="button" id="default-poster" aria-hidden="true" aria-label="Loading 3D model"></button> 32018 </slot> 32019 </div> 32020 32021 <div class="slot ar-button"> 32022 <slot name="ar-button"> 32023 <a id="default-ar-button" part="default-ar-button" class="fab" 32024 tabindex="2" 32025 role="button" 32026 href="javascript:void(0);" 32027 aria-label="View in your space"> 32028 ${ARGlyph} 32029 </a> 32030 </slot> 32031 </div> 32032 32033 <div class="slot pan-target"> 32034 <slot name="pan-target"> 32035 <div id="default-pan-target"> 32036 </div> 32037 </slot> 32038 </div> 32039 32040 <div class="slot interaction-prompt cover centered"> 32041 <div id="prompt" class="animated-container"> 32042 <slot name="interaction-prompt" aria-hidden="true"> 32043 ${ControlsPrompt} 32044 </slot> 32045 </div> 32046 </div> 32047 32048 <div id="finger0" class="animated-container cover"> 32049 <slot name="finger0" aria-hidden="true"> 32050 </slot> 32051 </div> 32052 <div id="finger1" class="animated-container cover"> 32053 <slot name="finger1" aria-hidden="true"> 32054 </slot> 32055 </div> 32056 32057 <div class="slot default"> 32058 <slot></slot> 32059 32060 <div class="slot progress-bar"> 32061 <slot name="progress-bar"> 32062 <div id="default-progress-bar" aria-hidden="true"> 32063 <div class="bar" part="default-progress-bar"></div> 32064 </div> 32065 </slot> 32066 </div> 32067 32068 <div class="slot exit-webxr-ar-button"> 32069 <slot name="exit-webxr-ar-button"> 32070 <a id="default-exit-webxr-ar-button" part="default-exit-webxr-ar-button" 32071 tabindex="3" 32072 aria-label="Exit AR" 32073 aria-hidden="true"> 32074 ${CloseIcon} 32075 </a> 32076 </slot> 32077 </div> 32078 </div> 32079</div> 32080<div class="screen-reader-only" role="region" aria-label="Live announcements"> 32081 <span id="status" role="status"></span> 32082</div>`; 32083 const makeTemplate = (shadowRoot)=>{ 32084 B$1(templateResult, shadowRoot); 32085 }; 32086 32087 // This file is part of meshoptimizer library and is distributed under the terms of MIT License. 32088 // Copyright (C) 2016-2022, by Arseny Kapoulkine ([email protected]) 32089 var MeshoptDecoder = function() { 32090 // Built with clang version 14.0.4 32091 // Built from meshoptimizer 0.18 32092 var wasm_base = "b9H79Tebbbe8Fv9Gbb9Gvuuuuueu9Giuuub9Geueu9Giuuueuikqbeeedddillviebeoweuec:q;iekr;leDo9TW9T9VV95dbH9F9F939H79T9F9J9H229F9Jt9VV7bb8A9TW79O9V9Wt9F9KW9J9V9KW9wWVtW949c919M9MWVbeY9TW79O9V9Wt9F9KW9J9V9KW69U9KW949c919M9MWVbdE9TW79O9V9Wt9F9KW9J9V9KW69U9KW949tWG91W9U9JWbiL9TW79O9V9Wt9F9KW9J9V9KWS9P2tWV9p9JtblK9TW79O9V9Wt9F9KW9J9V9KWS9P2tWV9r919HtbvL9TW79O9V9Wt9F9KW9J9V9KWS9P2tWVT949Wbol79IV9Rbrq:P8Yqdbk;3sezu8Jjjjjbcj;eb9Rgv8Kjjjjbc9:hodnadcefal0mbcuhoaiRbbc:Ge9hmbavaialfgrad9Radz1jjjbhwcj;abad9UhoaicefhldnadTmbaoc;WFbGgocjdaocjd6EhDcbhqinaqae9pmeaDaeaq9RaqaDfae6Egkcsfgocl4cifcd4hxdndndndnaoc9WGgmTmbcbhPcehsawcjdfhzalhHinaraH9Rax6midnaraHaxfgl9RcK6mbczhoinawcj;cbfaogifgoc9WfhOdndndndndnaHaic9WfgAco4fRbbaAci4coG4ciGPlbedibkaO9cb83ibaOcwf9cb83ibxikaOalRblalRbbgAco4gCaCciSgCE86bbaocGfalclfaCfgORbbaAcl4ciGgCaCciSgCE86bbaocVfaOaCfgORbbaAcd4ciGgCaCciSgCE86bbaoc7faOaCfgORbbaAciGgAaAciSgAE86bbaoctfaOaAfgARbbalRbegOco4gCaCciSgCE86bbaoc91faAaCfgARbbaOcl4ciGgCaCciSgCE86bbaoc4faAaCfgARbbaOcd4ciGgCaCciSgCE86bbaoc93faAaCfgARbbaOciGgOaOciSgOE86bbaoc94faAaOfgARbbalRbdgOco4gCaCciSgCE86bbaoc95faAaCfgARbbaOcl4ciGgCaCciSgCE86bbaoc96faAaCfgARbbaOcd4ciGgCaCciSgCE86bbaoc97faAaCfgARbbaOciGgOaOciSgOE86bbaoc98faAaOfgORbbalRbiglco4gAaAciSgAE86bbaoc99faOaAfgORbbalcl4ciGgAaAciSgAE86bbaoc9:faOaAfgORbbalcd4ciGgAaAciSgAE86bbaocufaOaAfgoRbbalciGglalciSglE86bbaoalfhlxdkaOalRbwalRbbgAcl4gCaCcsSgCE86bbaocGfalcwfaCfgORbbaAcsGgAaAcsSgAE86bbaocVfaOaAfgORbbalRbegAcl4gCaCcsSgCE86bbaoc7faOaCfgORbbaAcsGgAaAcsSgAE86bbaoctfaOaAfgORbbalRbdgAcl4gCaCcsSgCE86bbaoc91faOaCfgORbbaAcsGgAaAcsSgAE86bbaoc4faOaAfgORbbalRbigAcl4gCaCcsSgCE86bbaoc93faOaCfgORbbaAcsGgAaAcsSgAE86bbaoc94faOaAfgORbbalRblgAcl4gCaCcsSgCE86bbaoc95faOaCfgORbbaAcsGgAaAcsSgAE86bbaoc96faOaAfgORbbalRbvgAcl4gCaCcsSgCE86bbaoc97faOaCfgORbbaAcsGgAaAcsSgAE86bbaoc98faOaAfgORbbalRbogAcl4gCaCcsSgCE86bbaoc99faOaCfgORbbaAcsGgAaAcsSgAE86bbaoc9:faOaAfgORbbalRbrglcl4gAaAcsSgAE86bbaocufaOaAfgoRbbalcsGglalcsSglE86bbaoalfhlxekaOal8Pbb83bbaOcwfalcwf8Pbb83bbalczfhlkdnaiam9pmbaiczfhoaral9RcL0mekkaiam6mialTmidnakTmbawaPfRbbhOcbhoazhiinaiawcj;cbfaofRbbgAce4cbaAceG9R7aOfgO86bbaiadfhiaocefgoak9hmbkkazcefhzaPcefgPad6hsalhHaPad9hmexvkkcbhlasceGmdxikalaxad2fhCdnakTmbcbhHcehsawcjdfhminaral9Rax6mialTmdalaxfhlawaHfRbbhOcbhoamhiinaiawcj;cbfaofRbbgAce4cbaAceG9R7aOfgO86bbaiadfhiaocefgoak9hmbkamcefhmaHcefgHad6hsaHad9hmbkaChlxikcbhocehsinaral9Rax6mdalTmealaxfhlaocefgoad6hsadao9hmbkaChlxdkcbhlasceGTmekc9:hoxikabaqad2fawcjdfakad2z1jjjb8Aawawcjdfakcufad2fadz1jjjb8Aakaqfhqalmbkc9:hoxekcbc99aral9Radcaadca0ESEhokavcj;ebf8Kjjjjbaok;yzeHu8Jjjjjbc;ae9Rgv8Kjjjjbc9:hodnaeci9UgrcHfal0mbcuhoaiRbbgwc;WeGc;Ge9hmbawcsGgDce0mbavc;abfcFecjez:jjjjb8AavcUf9cu83ibavc8Wf9cu83ibavcyf9cu83ibavcaf9cu83ibavcKf9cu83ibavczf9cu83ibav9cu83iwav9cu83ibaialfc9WfhqaicefgwarfhodnaeTmbcmcsaDceSEhkcbhxcbhmcbhDcbhicbhlindnaoaq9nmbc9:hoxikdndnawRbbgrc;Ve0mbavc;abfalarcl4cu7fcsGcitfgPydlhsaPydbhzdnarcsGgPak9pmbavaiarcu7fcsGcdtfydbaxaPEhraPThPdndnadcd9hmbabaDcetfgHaz87ebaHcdfas87ebaHclfar87ebxekabaDcdtfgHazBdbaHclfasBdbaHcwfarBdbkaxaPfhxavc;abfalcitfgHarBdbaHasBdlavaicdtfarBdbavc;abfalcefcsGglcitfgHazBdbaHarBdlaiaPfhialcefhlxdkdndnaPcsSmbamaPfaPc987fcefhmxekaocefhrao8SbbgPcFeGhHdndnaPcu9mmbarhoxekaocvfhoaHcFbGhHcrhPdninar8SbbgOcFbGaPtaHVhHaOcu9kmearcefhraPcrfgPc8J9hmbxdkkarcefhokaHce4cbaHceG9R7amfhmkdndnadcd9hmbabaDcetfgraz87ebarcdfas87ebarclfam87ebxekabaDcdtfgrazBdbarclfasBdbarcwfamBdbkavc;abfalcitfgramBdbarasBdlavaicdtfamBdbavc;abfalcefcsGglcitfgrazBdbaramBdlaicefhialcefhlxekdnarcpe0mbaxcefgOavaiaqarcsGfRbbgPcl49RcsGcdtfydbaPcz6gHEhravaiaP9RcsGcdtfydbaOaHfgsaPcsGgOEhPaOThOdndnadcd9hmbabaDcetfgzax87ebazcdfar87ebazclfaP87ebxekabaDcdtfgzaxBdbazclfarBdbazcwfaPBdbkavaicdtfaxBdbavc;abfalcitfgzarBdbazaxBdlavaicefgicsGcdtfarBdbavc;abfalcefcsGcitfgzaPBdbazarBdlavaiaHfcsGgicdtfaPBdbavc;abfalcdfcsGglcitfgraxBdbaraPBdlalcefhlaiaOfhiasaOfhxxekaxcbaoRbbgzEgAarc;:eSgrfhsazcsGhCazcl4hXdndnazcs0mbascefhOxekashOavaiaX9RcsGcdtfydbhskdndnaCmbaOcefhxxekaOhxavaiaz9RcsGcdtfydbhOkdndnarTmbaocefhrxekaocdfhrao8SbegHcFeGhPdnaHcu9kmbaocofhAaPcFbGhPcrhodninar8SbbgHcFbGaotaPVhPaHcu9kmearcefhraocrfgoc8J9hmbkaAhrxekarcefhrkaPce4cbaPceG9R7amfgmhAkdndnaXcsSmbarhPxekarcefhPar8SbbgocFeGhHdnaocu9kmbarcvfhsaHcFbGhHcrhodninaP8SbbgrcFbGaotaHVhHarcu9kmeaPcefhPaocrfgoc8J9hmbkashPxekaPcefhPkaHce4cbaHceG9R7amfgmhskdndnaCcsSmbaPhoxekaPcefhoaP8SbbgrcFeGhHdnarcu9kmbaPcvfhOaHcFbGhHcrhrdninao8SbbgPcFbGartaHVhHaPcu9kmeaocefhoarcrfgrc8J9hmbkaOhoxekaocefhokaHce4cbaHceG9R7amfgmhOkdndnadcd9hmbabaDcetfgraA87ebarc
32092dfas87ebarclfaO87ebxekabaDcdtfgraABdbarclfasBdbarcwfaOBdbkavc;abfalcitfgrasBdbaraABdlavaicdtfaABdbavc;abfalcefcsGcitfgraOBdbarasBdlavaicefgicsGcdtfasBdbavc;abfalcdfcsGcitfgraABdbaraOBdlavaiazcz6aXcsSVfgicsGcdtfaOBdbaiaCTaCcsSVfhialcifhlkawcefhwalcsGhlaicsGhiaDcifgDae6mbkkcbc99aoaqSEhokavc;aef8Kjjjjbaok:llevu8Jjjjjbcz9Rhvc9:hodnaecvfal0mbcuhoaiRbbc;:eGc;qe9hmbav9cb83iwaicefhraialfc98fhwdnaeTmbdnadcdSmbcbhDindnaraw6mbc9:skarcefhoar8SbbglcFeGhidndnalcu9mmbaohrxekarcvfhraicFbGhicrhldninao8SbbgdcFbGaltaiVhiadcu9kmeaocefhoalcrfglc8J9hmbxdkkaocefhrkabaDcdtfaicd4cbaice4ceG9R7avcwfaiceGcdtVgoydbfglBdbaoalBdbaDcefgDae9hmbxdkkcbhDindnaraw6mbc9:skarcefhoar8SbbglcFeGhidndnalcu9mmbaohrxekarcvfhraicFbGhicrhldninao8SbbgdcFbGaltaiVhiadcu9kmeaocefhoalcrfglc8J9hmbxdkkaocefhrkabaDcetfaicd4cbaice4ceG9R7avcwfaiceGcdtVgoydbfgl87ebaoalBdbaDcefgDae9hmbkkcbc99arawSEhokaok:Lvoeue99dud99eud99dndnadcl9hmbaeTmeindndnabcdfgd8Sbb:Yab8Sbbgi:Ygl:l:tabcefgv8Sbbgo:Ygr:l:tgwJbb;:9cawawNJbbbbawawJbbbb9GgDEgq:mgkaqaicb9iEalMgwawNakaqaocb9iEarMgqaqNMM:r:vglNJbbbZJbbb:;aDEMgr:lJbbb9p9DTmbar:Ohixekcjjjj94hikadai86bbdndnaqalNJbbbZJbbb:;aqJbbbb9GEMgq:lJbbb9p9DTmbaq:Ohdxekcjjjj94hdkavad86bbdndnawalNJbbbZJbbb:;awJbbbb9GEMgw:lJbbb9p9DTmbaw:Ohdxekcjjjj94hdkabad86bbabclfhbaecufgembxdkkaeTmbindndnabclfgd8Ueb:Yab8Uebgi:Ygl:l:tabcdfgv8Uebgo:Ygr:l:tgwJb;:FSawawNJbbbbawawJbbbb9GgDEgq:mgkaqaicb9iEalMgwawNakaqaocb9iEarMgqaqNMM:r:vglNJbbbZJbbb:;aDEMgr:lJbbb9p9DTmbar:Ohixekcjjjj94hikadai87ebdndnaqalNJbbbZJbbb:;aqJbbbb9GEMgq:lJbbb9p9DTmbaq:Ohdxekcjjjj94hdkavad87ebdndnawalNJbbbZJbbb:;awJbbbb9GEMgw:lJbbb9p9DTmbaw:Ohdxekcjjjj94hdkabad87ebabcwfhbaecufgembkkk;siliui99iue99dnaeTmbcbhiabhlindndnJ;Zl81Zalcof8UebgvciV:Y:vgoal8Ueb:YNgrJb;:FSNJbbbZJbbb:;arJbbbb9GEMgw:lJbbb9p9DTmbaw:OhDxekcjjjj94hDkalclf8Uebhqalcdf8UebhkabavcefciGaiVcetfaD87ebdndnaoak:YNgwJb;:FSNJbbbZJbbb:;awJbbbb9GEMgx:lJbbb9p9DTmbax:Ohkxekcjjjj94hkkabavcdfciGaiVcetfak87ebdndnaoaq:YNgoJb;:FSNJbbbZJbbb:;aoJbbbb9GEMgx:lJbbb9p9DTmbax:Ohqxekcjjjj94hqkabavcufciGaiVcetfaq87ebdndnJbbjZararN:tawawN:taoaoN:tgrJbbbbarJbbbb9GE:rJb;:FSNJbbbZMgr:lJbbb9p9DTmbar:Ohqxekcjjjj94hqkabavciGaiVcetfaq87ebalcwfhlaiclfhiaecufgembkkk9mbdnadcd4ae2geTmbinababydbgdcwtcw91:Yadce91cjjj;8ifcjjj98G::NUdbabclfhbaecufgembkkk9teiucbcbydj1jjbgeabcifc98GfgbBdj1jjbdndnabZbcztgd9nmbcuhiabad9RcFFifcz4nbcuSmekaehikaik;LeeeudndnaeabVciGTmbabhixekdndnadcz9pmbabhixekabhiinaiaeydbBdbaiclfaeclfydbBdbaicwfaecwfydbBdbaicxfaecxfydbBdbaiczfhiaeczfheadc9Wfgdcs0mbkkadcl6mbinaiaeydbBdbaeclfheaiclfhiadc98fgdci0mbkkdnadTmbinaiaeRbb86bbaicefhiaecefheadcufgdmbkkabk;aeedudndnabciGTmbabhixekaecFeGc:b:c:ew2hldndnadcz9pmbabhixekabhiinaialBdbaicxfalBdbaicwfalBdbaiclfalBdbaiczfhiadc9Wfgdcs0mbkkadcl6mbinaialBdbaiclfhiadc98fgdci0mbkkdnadTmbinaiae86bbaicefhiadcufgdmbkkabkkkebcjwklz9Kbb"; 32093 var wasm_simd =
vendor: 12,055 bytes, line 32093
32093"b9H79TebbbeKl9Gbb9Gvuuuuueu9Giuuub9Geueuikqbbebeedddilve9Weeeviebeoweuec:q;Aekr;leDo9TW9T9VV95dbH9F9F939H79T9F9J9H229F9Jt9VV7bb8A9TW79O9V9Wt9F9KW9J9V9KW9wWVtW949c919M9MWVbdY9TW79O9V9Wt9F9KW9J9V9KW69U9KW949c919M9MWVblE9TW79O9V9Wt9F9KW9J9V9KW69U9KW949tWG91W9U9JWbvL9TW79O9V9Wt9F9KW9J9V9KWS9P2tWV9p9JtboK9TW79O9V9Wt9F9KW9J9V9KWS9P2tWV9r919HtbrL9TW79O9V9Wt9F9KW9J9V9KWS9P2tWVT949Wbwl79IV9RbDq;t9tqlbzik9:evu8Jjjjjbcz9Rhbcbheincbhdcbhiinabcwfadfaicjuaead4ceGglE86bbaialfhiadcefgdcw9hmbkaec:q:yjjbfai86bbaecitc:q1jjbfab8Piw83ibaecefgecjd9hmbkk;h8JlHud97euo978Jjjjjbcj;kb9Rgv8Kjjjjbc9:hodnadcefal0mbcuhoaiRbbc:Ge9hmbavaialfgrad9Rad;8qbbcj;abad9UhoaicefhldnadTmbaoc;WFbGgocjdaocjd6EhwcbhDinaDae9pmeawaeaD9RaDawfae6Egqcsfgoc9WGgkci2hxakcethmaocl4cifcd4hPabaDad2fhscbhzdnincehHalhOcbhAdninaraO9RaP6miavcj;cbfaAak2fhCaOaPfhlcbhidnakc;ab6mbaral9Rc;Gb6mbcbhoinaCaofhidndndndndnaOaoco4fRbbgXciGPlbedibkaipxbbbbbbbbbbbbbbbbpklbxikaialpbblalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLgQcdp:meaQpmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9ogLpxiiiiiiiiiiiiiiiip8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibaKc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spklbalclfaYpQbfaKc:q:yjjbfRbbfhlxdkaialpbbwalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLpxssssssssssssssssp9ogLpxssssssssssssssssp8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibaKc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spklbalcwfaYpQbfaKc:q:yjjbfRbbfhlxekaialpbbbpklbalczfhlkdndndndndnaXcd4ciGPlbedibkaipxbbbbbbbbbbbbbbbbpklzxikaialpbblalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLgQcdp:meaQpmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9ogLpxiiiiiiiiiiiiiiiip8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibaKc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spklzalclfaYpQbfaKc:q:yjjbfRbbfhlxdkaialpbbwalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLpxssssssssssssssssp9ogLpxssssssssssssssssp8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibaKc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spklzalcwfaYpQbfaKc:q:yjjbfRbbfhlxekaialpbbbpklzalczfhlkdndndndndnaXcl4ciGPlbedibkaipxbbbbbbbbbbbbbbbbpklaxikaialpbblalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLgQcdp:meaQpmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9ogLpxiiiiiiiiiiiiiiiip8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibaKc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spklaalclfaYpQbfaKc:q:yjjbfRbbfhlxdkaialpbbwalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLpxssssssssssssssssp9ogLpxssssssssssssssssp8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibaKc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spklaalcwfaYpQbfaKc:q:yjjbfRbbfhlxekaialpbbbpklaalczfhlkdndndndndnaXco4Plbedibkaipxbbbbbbbbbbbbbbbbpkl8WxikaialpbblalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLgQcdp:meaQpmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9ogLpxiiiiiiiiiiiiiiiip8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgXcitc:q1jjbfpbibaXc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgXcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spkl8WalclfaYpQbfaXc:q:yjjbfRbbfhlxdkaialpbbwalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLpxssssssssssssssssp9ogLpxssssssssssssssssp8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgXcitc:q1jjbfpbibaXc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgXcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spkl8WalcwfaYpQbfaXc:q:yjjbfRbbfhlxekaialpbbbpkl8Walczfhlkaoc;abfhiaocjefak0meaihoaral9Rc;Fb0mbkkdndnaiak9pmbaici4hoinaral9RcK6mdaCaifhXdndndndndnaOaico4fRbbaocoG4ciGPlbedibkaXpxbbbbbbbbbbbbbbbbpklbxikaXalpbblalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLgQcdp:meaQpmbzeHdOiAlCvXoQrLpxiiiiiiiiiiiiiiiip9ogLpxiiiiiiiiiiiiiiiip8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibaKc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spklbalclfaYpQbfaKc:q:yjjbfRbbfhlxdkaXalpbbwalpbbbgQclp:meaQpmbzeHdOiAlCvXoQrLpxssssssssssssssssp9ogLpxssssssssssssssssp8JgQp5b9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibaKc:q:yjjbfpbbbgYaYpmbbbbbbbbbbbbbbbbaQp5e9cjF;8;4;W;G;ab9:9cU1:NgKcitc:q1jjbfpbibp9UpmbedilvorzHOACXQLpPaLaQp9spklbalcwfaYpQbfaKc:q:yjjbfRbbfhlxekaXalpbbbpklbalczfhlkaocdfhoaiczfgiak6mbkkalTmbaAci6hHalhOaAcefgohAaoclSmdxekkcbhlaHceGmdkdnakTmbavcjdfazfhiavazfpbdbhYcbhXinaiavcj;cbfaXfgopblbgLcep9TaLpxeeeeeeeeeeeeeeeegQp9op9Hp9rgLaoakfpblbg8Acep9Ta8AaQp9op9Hp9rg8ApmbzeHdOiAlCvXoQrLgEaoamfpblbg3cep9Ta3aQp9op9Hp9rg3aoaxfpblbg5cep9Ta5aQp9op9Hp9rg5pmbzeHdOiAlCvXoQrLg8EpmbezHdiOAlvCXorQLgQaQpmbedibedibedibediaYp9UgYp9AdbbaiadfgoaYaQaQpmlvorlvorlvorlvorp9UgYp9AdbbaoadfgoaYaQaQpmwDqkwDqkwDqkwDqkp9UgYp9AdbbaoadfgoaYaQaQpmxmPsxmPsxmPsxmPsp9UgYp9AdbbaoadfgoaYaEa8EpmwDKYqk8AExm35Ps8E8FgQaQpmbedibedibedibedip9UgYp9AdbbaoadfgoaYaQaQpmlvorlvorlvorlvorp9UgYp9AdbbaoadfgoaYaQaQpmwDqkwDqkwDqkwDqkp9UgYp9AdbbaoadfgoaYaQaQpmxmPsxmPsxmPsxmPsp9UgYp9AdbbaoadfgoaYaLa8ApmwKDYq8AkEx3m5P8Es8FgLa3a5pmwKDYq8AkEx3m5P8Es8Fg8ApmbezHdiOAlvCXorQLgQaQpmbedibedibedibedip9UgYp9AdbbaoadfgoaYaQaQpmlvorlvorlvorlvorp9UgYp9AdbbaoadfgoaYaQaQpmwDqkwDqkwDqkwDqkp9UgYp9AdbbaoadfgoaYaQaQpmxmPsxmPsxmPsxmPsp9UgYp9AdbbaoadfgoaYaLa8ApmwDKYqk8AExm35Ps8E8FgQaQpmbedibedibedibedip9UgYp9AdbbaoadfgoaYaQaQpmlvorlvorlvorlvorp9UgYp9AdbbaoadfgoaYaQaQpmwDqkwDqkwDqkwDqkp9UgYp9AdbbaoadfgoaYaQaQpmxmPsxmPsxmPsxmPsp9UgYp9AdbbaoadfhiaXczfgXak6mbkkazclfgzad6mbkasavcjdfaqad2;8qbbavavcjdfaqcufad2fad;8qbbaqaDfhDc9:hoalmexikkc9:hoxekcbc99aral9Radcaadca0ESEhokavcj;kbf8Kjjjjbaokwbz:bjjjbk;uzeHu8Jjjjjbc;ae9Rgv8Kjjjjbc9:hodnaeci9UgrcHfal0mbcuhoaiRbbgwc;WeGc;Ge9hmbawcsGgDce0mbavc;abfcFecje;8kbavcUf9cu83ibavc8Wf9cu83ibavcyf9cu83ibavcaf9cu83ibavcKf9cu83ibavczf9cu83ibav9cu83iwav9cu83ibaialfc9WfhqaicefgwarfhodnaeTmbcmcsaDceSEhkcbhxcbhmcbhDcbhicbhlindnaoaq9nmbc9:hoxikdndnawRbbgrc;Ve0mbavc;abfalarcl4cu7fcsGcitfgPydlhsaPydbhzdnarcsGgPak9pmbavaiarcu7fcsGcdtfydbaxaPEhraPThPdndnadcd9hmbabaDcetfgHaz87ebaHcdfas87ebaHclfar87ebxekabaDcdtfgHazBdbaHclfasBdbaHcwfarBdbkaxaPfhxavc;abfalcitfgHarBdbaHasBdlavaicdtfarBdbavc;abfalcefcsGglcitfgHazBdbaHarBdlaiaPfhialcefhlxdkdndnaPcsSmbamaPfaPc987fcefhmxekaocefhrao8SbbgPcFeGhHdndnaPcu9mmbarhoxekaocvfhoaHcFbGhHcrhPdninar8SbbgOcFbGaPtaHVhHaOcu9kmearcefhraPcrfgPc8J9hmbxdkkarcefhokaHce4cbaHceG9R7amfhmkdndnadcd9hmbabaDcetfgraz87ebarcdfas87ebarclfam87ebxekabaDcdtfgrazBdbarclfasBdbarcwfamBdbkavc;abfalcitfgramBdbarasBdlavaicdtfamBdbavc;abfalcefcsGglcitfgrazBdbaramBdlaicefhialcefhlxekdnarcpe0mbaxcefgOavaiaqarcsGfRbbgPcl49RcsGcdtfydbaPcz6gHEhravaiaP9RcsGcdtfydbaOaHfgsaPcsGgOEhPaOThOdndnadcd9hmbabaDcetfgzax87ebazcdfar87ebazclfaP87ebxekabaDcdtfgzaxBdbazclfarBdbazcwfaPBdbkavaicdtfaxBdbavc;abfalcitfgzarBdbazaxBdlavaicefgicsGcdtfarBdbavc;abfalcefcsGcitfgzaPBdbazarBdlavaiaHfcsGgicdtfaPBdbavc;abfalcdfcsGglcitfgraxBdbaraPBdlalcefhlaiaOfhiasaOfhxxekaxcbaoRbbgzEgAarc;:eSgrfhsazcsGhCazcl4hXdndnazcs0mbascefhOxekashOavaiaX9RcsGcdtfydbhskdndnaCmbaOcefhxxekaOhxavaiaz9RcsGcdtfydbhOkdndnarTmbaocefhrxekaocdfhrao8SbegHcFeGhPdnaHcu9kmbaocofhAaPcFbGhPcrhodninar8SbbgHcFbGaotaPVhPaHcu9kmearcefhraocrfgoc8J9hmbkaAhrxekarcefhrkaPce4cbaPceG9R7amfgmhAkdndnaXcsSmbarhPxekarcefhPar8SbbgocFeGhHdnaocu9kmbarcvfhsaHcFbGhHcrhodninaP8SbbgrcFbGaotaHVhHarcu9kmeaPcefhPaocrfgoc8J9hmbkashPxekaPcefhPkaHce4cbaHceG9R7amfgmhskdndnaCcsSmbaPhoxekaPcefhoaP8SbbgrcFeGhHdnarcu9kmbaPcvfhOaHcFbGhHcrhrdninao8SbbgPcFbGartaHVhHaPcu9kmeaocefhoarcrfgrc8J9hmbkaOhoxekaocefhokaHce4cbaHceG9R7amfgmhOkdndnadcd9hmbabaDcetfgraA87ebarcdfas87ebarclfaO87ebxekabaDcdtfgraABdbarclfasBdbarcwfaOBdbkavc;abfalcitfgrasBdbaraABdlavaicdtfaABdbavc;abfalcefcsGcitfgraOBdbarasBdlavaicefgicsGcdtfasBdbavc;abfalcdfcsGcitfgraABdbaraOBdlavaiazcz6aXcsSVfgicsGcdtfaOBdbaiaCTaCcsSVfhialcifhlkawcefhwalcsGhlaicsGhiaDcifgDae6mbkkcbc99aoaqSEhokavc;aef8Kjjjjbaok:llevu8Jjjjjbcz9Rhvc9:hodnaecvfal0mbcuhoaiRbbc;:eGc;qe9hmbav9cb83iwaicefhraialfc98fhwdnaeTmbdnadcdSmbcbhDindnaraw6mbc9:skarcefhoar8SbbglcFeGhidndnalcu9mmbaohrxekarcvfhraicFbGhicrhldninao8SbbgdcFbGaltaiVhiadcu9kmeaocefhoalcrfglc8J9hmbxdkkaocefhrkabaDcdtfaicd4cbaice4ceG9R7avcwfaiceGcdtVgoydbfglBdbaoalBdbaDcefgDae9hmbxdkkcbhDindnaraw6mbc9:skarcefhoar8SbbglcFeGhidndnalcu9mmbaohrxekarcvfhraicFbGhicrhldninao8SbbgdcFbGaltaiVhiadcu9kmeaocefhoalcrfglc8J9hmbxdkkaocefhrkabaDcetfaicd4cbaice4ceG9R7avcwfaiceGcdtVgoydbfgl87ebaoalBdbaDcefgDae9hmbkkcbc99arawSEhokaok:EPliuo97eue978Jjjjjbca9Rhidndnadcl9hmbdnaec98GglTmbcbhvabhdinadadpbbbgocKp:RecKp:Sep;6egraocwp:RecKp:Sep;6earp;Geaoczp:RecKp:Sep;6egwp;Gep;Kep;LegDpxbbbbbbbbbbbbbbbbp:2egqarpxbbbjbbbjbbbjbbbjgkp9op9rp;Kegrpxbb;:9cbb;:9cbb;:9cbb;:9cararp;MeaDaDp;Meawaqawakp9op9rp;Kegrarp;Mep;Kep;Kep;Jep;Negwp;Mepxbbn0bbn0bbn0bbn0gqp;KepxFbbbFbbbFbbbFbbbp9oaopxbbbFbbbFbbbFbbbFp9op9qarawp;Meaqp;Kecwp:RepxbFbbbFbbbFbbbFbbp9op9qaDawp;Meaqp;Keczp:RepxbbFbbbFbbbFbbbFbp9op9qpkbbadczfhdavclfgval6mbkkalae9pmeaiaeciGgvcdtgdVcbczad9R;8kbaiabalcdtfglad;8qbbdnavTmbaiaipblbgocKp:RecKp:Sep;6egraocwp:RecKp:Sep;6earp;Geaoczp:RecKp:Sep;6egwp;Gep;Kep;LegDpxbbbbbbbbbbbbbbbbp:2egqarpxbbbjbbbjbbbjbbbjgkp9op9rp;Kegrpxbb;:9cbb;:9cbb;:9cbb;:9cararp;MeaDaDp;Meawaqawakp9op9rp;Kegrarp;Mep;Kep;Kep;Jep;Negwp;Mepxbbn0bbn0bbn0bbn0gqp;KepxFbbbFbbbFbbbFbbbp9oaopxbbbFbbbFbbbFbbbFp9op9qarawp;Meaqp;Kecwp:RepxbFbbbFbbbFbbbFbbp9op9qaDawp;Meaqp;Keczp:RepxbbFbbbFbbbFbbbFbp9op9qpklbkalaiad;8qbbskdnaec98GgxTmbcbhvabhdinadczfglalpbbbgopxbbbbbbFFbbbbbbFFgkp9oadpbbbgDaopmlvorxmPsCXQL358E8FpxFubbFubbFubbFubbp9op;6eaDaopmbediwDqkzHOAKY8AEgoczp:Sep;6egrp;Geaoczp:Reczp:Sep;6egwp;Gep;Kep;Legopxb;:FSb;:FSb;:FSb;:FSawaopxbbbbbbbbbbbbbbbbp:2egqawpxbbbjbbbjbbbjbbbjgmp9op9rp;Kegwawp;Meaoaop;Mearaqaramp9op9rp;Kegoaop;Mep;Kep;Kep;Jep;Negrp;Mepxbbn0bbn0bbn0bbn0gqp;Keczp:Reawarp;Meaqp;KepxFFbbFFbbFFbbFFbbp9op9qgwaoarp;Meaqp;KepxFFbbFFbbFFbbFFbbp9ogopmwDKYqk8AExm35Ps8E8Fp9qpkbbadaDakp9oawaopmbezHdiOAlvCXorQLp9qpkbbadcafhdavclfgvax6mbkkaxae9pmbaiaeciGgvcitgdfcbcaad9R;8kbaiabaxcitfglad;8qbbdnavTmbaiaipblzgopxbbbbbbFFbbbbbbFFgkp9oaipblbgDaopmlvorxmPsCXQL358E8FpxFubbFubbFubbFubbp9op;6eaDaopmbediwDqkzHOAKY8AEgoczp:Sep;6egrp;Geaoczp:Reczp:Sep;6egwp;Gep;Kep;Legopxb;:FSb;:FSb;:FSb;:FSawaopxbbbbbbbbbbbbbbbbp:2egqawpxbbbjbbbjbbbjbbbjgmp9op9rp;Kegwawp;Meaoaop;Mearaqaramp9op9rp;Kegoaop;Mep;Kep;Kep;Jep;Negrp;Mepxbbn0bbn0bbn0bbn0gqp;Keczp:Reawarp;Meaqp;KepxFFbbFFbbFFbbFFbbp9op9qgwaoarp;Meaqp;KepxFFbbFFbbFFbbFFbbp9ogopmwDKYqk8AExm35Ps8E8Fp9qpklzaiaDakp9oawaopmbezHdiOAlvCXorQLp9qpklbkalaiad;8qbbkk;4wllue97euv978Jjjjjbc8W9Rhidnaec98GglTmbcbhvabhoinaiaopbbbgraoczfgwpbbbgDpmlvorxmPsCXQL358E8Fgqczp:Segkclp:RepklbaopxbbjZbbjZbbjZbbjZpx;Zl81Z;Zl81Z;Zl81Z;Zl81Zakpxibbbibbbibbbibbbp9qp;6ep;NegkaraDpmbediwDqkzHOAKY8AEgrczp:Reczp:Sep;6ep;MegDaDp;Meakarczp:Sep;6ep;Megxaxp;Meakaqczp:Reczp:Sep;6ep;Megqaqp;Mep;Kep;Kep;Lepxbbbbbbbbbbbbbbbbp:4ep;Jepxb;:FSb;:FSb;:FSb;:FSgkp;Mepxbbn0bbn0bbn0bbn0grp;KepxFFbbFFbbFFbbFFbbgmp9oaxakp;Mearp;Keczp:Rep9qgxaqakp;Mearp;Keczp:ReaDakp;Mearp;Keamp9op9qgkpmbezHdiOAlvCXorQLgrp5baipblbpEb:T:j83ibaocwfarp5eaipblbpEe:T:j83ibawaxakpmwDKYqk8AExm35Ps8E8Fgkp5baipblbpEd:T:j83ibaocKfakp5eaipblbpEi:T:j83ibaocafhoavclfgval6mbkkdnalae9pmbaiaeciGgvcitgofcbcaao9R;8kbaiabalcitfgwao;8qbbdnavTmbaiaipblbgraipblzgDpmlvorxmPsCXQL358E8Fgqczp:Segkclp:RepklaaipxbbjZbbjZbbjZbbjZpx;Zl81Z;Zl81Z;Zl81Z;Zl81Zakpxibbbibbbibbbibbbp9qp;6ep;NegkaraDpmbediwDqkzHOAKY8AEgrczp:Reczp:Sep;6ep;MegDaDp;Meakarczp:Sep;6ep;Megxaxp;Meakaqczp:Reczp:Sep;6ep;Megqaqp;Mep;Kep;Kep;Lepxbbbbbbbbbbbbbbbbp:4ep;Jepxb;:FSb;:FSb;:FSb;:FSgkp;Mepxbbn0bbn0bbn0bbn0grp;KepxFFbbFFbbFFbbFFbbgmp9oaxakp;Mearp;Keczp:Rep9qgxaqakp;Mearp;Keczp:ReaDakp;Mearp;Keamp9op9qgkpmbezHdiOAlvCXorQLgrp5baipblapEb:T:j83ibaiarp5eaipblapEe:T:j83iwaiaxakpmwDKYqk8AExm35Ps8E8Fgkp5baipblapEd:T:j83izaiakp5eaipblapEi:T:j83iKkawaiao;8qbbkk:Pddiue978Jjjjjbc;ab9Rhidnadcd4ae2glc98GgvTmbcbhdabheinaeaepbbbgocwp:Recwp:Sep;6eaocep:SepxbbjZbbjZbbjZbbjZp:UepxbbjFbbjFbbjFbbjFp9op;Mepkbbaeczfheadclfgdav6mbkkdnaval9pmbaialciGgdcdtgeVcbc;abae9R;8kbaiabavcdtfgvae;8qbbdnadTmbaiaipblbgocwp:Recwp:Sep;6eaocep:SepxbbjZbbjZbbjZbbjZp:UepxbbjFbbjFbbjFbbjFp9op;Mepklbkavaiae;8qbbkk9teiucbcbydj1jjbgeabcifc98GfgbBdj1jjbdndnabZbcztgd9nmbcuhiabad9RcFFifcz4nbcuSmekaehikaikkkebcjwklz9Tbb"
32093; 32094 var detector = new Uint8Array([ 32095 0, 32096 97, 32097 115, 32098 109, 32099 1, 32100 0, 32101 0, 32102 0, 32103 1, 32104 4, 32105 1, 32106 96, 32107 0, 32108 0, 32109 3, 32110 3, 32111 2, 32112 0, 32113 0, 32114 5, 32115 3, 32116 1, 32117 0, 32118 1, 32119 12, 32120 1, 32121 0, 32122 10, 32123 22, 32124 2, 32125 12, 32126 0, 32127 65, 32128 0, 32129 65, 32130 0, 32131 65, 32132 0, 32133 252, 32134 10, 32135 0, 32136 0, 32137 11, 32138 7, 32139 0, 32140 65, 32141 0, 32142 253, 32143 15, 32144 26, 32145 11 32146 ]); 32147 var wasmpack = new Uint8Array([ 32148 32, 32149 0, 32150 65, 32151 2, 32152 1, 32153 106, 32154 34, 32155 33, 32156 3, 32157 128, 32158 11, 32159 4, 32160 13, 32161 64, 32162 6, 32163 253, 32164 10, 32165 7, 32166 15, 32167 116,
vendor: 31,980 bytes, lines 32168-32955
32168 127, 32169 5, 32170 8, 32171 12, 32172 40, 32173 16, 32174 19, 32175 54, 32176 20, 32177 9, 32178 27, 32179 255, 32180 113, 32181 17, 32182 42, 32183 67, 32184 24, 32185 23, 32186 146, 32187 148, 32188 18, 32189 14, 32190 22, 32191 45, 32192 70, 32193 69, 32194 56, 32195 114, 32196 101, 32197 21, 32198 25, 32199 63, 32200 75, 32201 136, 32202 108, 32203 28, 32204 118, 32205 29, 32206 73, 32207 115 32208 ]); 32209 if (typeof WebAssembly !== 'object') { 32210 return { 32211 supported: false 32212 }; 32213 } 32214 var wasm = WebAssembly.validate(detector) ? wasm_simd : wasm_base; 32215 var instance; 32216 var ready = WebAssembly.instantiate(unpack(wasm), {}).then(function(result) { 32217 instance = result.instance; 32218 instance.exports.__wasm_call_ctors(); 32219 }); 32220 function unpack(data) { 32221 var result = new Uint8Array(data.length); 32222 for(var i = 0; i < data.length; ++i){ 32223 var ch = data.charCodeAt(i); 32224 result[i] = ch > 96 ? ch - 97 : ch > 64 ? ch - 39 : ch + 4; 32225 } 32226 var write = 0; 32227 for(var i = 0; i < data.length; ++i){ 32228 result[write++] = result[i] < 60 ? wasmpack[result[i]] : (result[i] - 60) * 64 + result[++i]; 32229 } 32230 return result.buffer.slice(0, write); 32231 } 32232 function decode(fun, target, count, size, source, filter) { 32233 var sbrk = instance.exports.sbrk; 32234 var count4 = count + 3 & -4; 32235 var tp = sbrk(count4 * size); 32236 var sp = sbrk(source.length); 32237 var heap = new Uint8Array(instance.exports.memory.buffer); 32238 heap.set(source, sp); 32239 var res = fun(tp, count, size, sp, source.length); 32240 if (res == 0 && filter) { 32241 filter(tp, count4, size); 32242 } 32243 target.set(heap.subarray(tp, tp + count * size)); 32244 sbrk(tp - sbrk(0)); 32245 if (res != 0) { 32246 throw new Error("Malformed buffer data: " + res); 32247 } 32248 } 32249 var filters = { 32250 NONE: "", 32251 OCTAHEDRAL: "meshopt_decodeFilterOct", 32252 QUATERNION: "meshopt_decodeFilterQuat", 32253 EXPONENTIAL: "meshopt_decodeFilterExp" 32254 }; 32255 var decoders = { 32256 ATTRIBUTES: "meshopt_decodeVertexBuffer", 32257 TRIANGLES: "meshopt_decodeIndexBuffer", 32258 INDICES: "meshopt_decodeIndexSequence" 32259 }; 32260 var workers = []; 32261 var requestId = 0; 32262 function createWorker(url) { 32263 var worker = { 32264 object: new Worker(url), 32265 pending: 0, 32266 requests: {} 32267 }; 32268 worker.object.onmessage = function(event) { 32269 var data = event.data; 32270 worker.pending -= data.count; 32271 worker.requests[data.id][data.action](data.value); 32272 delete worker.requests[data.id]; 32273 }; 32274 return worker; 32275 } 32276 function initWorkers(count) { 32277 var source = "var instance; var ready = WebAssembly.instantiate(new Uint8Array([" + new Uint8Array(unpack(wasm)) + "]), {})" + ".then(function(result) { instance = result.instance; instance.exports.__wasm_call_ctors(); });" + "self.onmessage = workerProcess;" + decode.toString() + workerProcess.toString(); 32278 var blob = new Blob([ 32279 source 32280 ], { 32281 type: 'text/javascript' 32282 }); 32283 var url = URL.createObjectURL(blob); 32284 for(var i = 0; i < count; ++i){ 32285 workers[i] = createWorker(url); 32286 } 32287 URL.revokeObjectURL(url); 32288 } 32289 function decodeWorker(count, size, source, mode, filter) { 32290 var worker = workers[0]; 32291 for(var i = 1; i < workers.length; ++i){ 32292 if (workers[i].pending < worker.pending) { 32293 worker = workers[i]; 32294 } 32295 } 32296 return new Promise(function(resolve, reject) { 32297 var data = new Uint8Array(source); 32298 var id = requestId++; 32299 worker.pending += count; 32300 worker.requests[id] = { 32301 resolve: resolve, 32302 reject: reject 32303 }; 32304 worker.object.postMessage({ 32305 id: id, 32306 count: count, 32307 size: size, 32308 source: data, 32309 mode: mode, 32310 filter: filter 32311 }, [ 32312 data.buffer 32313 ]); 32314 }); 32315 } 32316 function workerProcess(event) { 32317 ready.then(function() { 32318 var data = event.data; 32319 try { 32320 var target = new Uint8Array(data.count * data.size); 32321 decode(instance.exports[data.mode], target, data.count, data.size, data.source, instance.exports[data.filter]); 32322 self.postMessage({ 32323 id: data.id, 32324 count: data.count, 32325 action: "resolve", 32326 value: target 32327 }, [ 32328 target.buffer 32329 ]); 32330 } catch (error) { 32331 self.postMessage({ 32332 id: data.id, 32333 count: data.count, 32334 action: "reject", 32335 value: error 32336 }); 32337 } 32338 }); 32339 } 32340 return { 32341 ready: ready, 32342 supported: true, 32343 useWorkers: function(count) { 32344 initWorkers(count); 32345 }, 32346 decodeVertexBuffer: function(target, count, size, source, filter) { 32347 decode(instance.exports.meshopt_decodeVertexBuffer, target, count, size, source, instance.exports[filters[filter]]); 32348 }, 32349 decodeIndexBuffer: function(target, count, size, source) { 32350 decode(instance.exports.meshopt_decodeIndexBuffer, target, count, size, source); 32351 }, 32352 decodeIndexSequence: function(target, count, size, source) { 32353 decode(instance.exports.meshopt_decodeIndexSequence, target, count, size, source); 32354 }, 32355 decodeGltfBuffer: function(target, count, size, source, mode, filter) { 32356 decode(instance.exports[decoders[mode]], target, count, size, source, instance.exports[filters[filter]]); 32357 }, 32358 decodeGltfBufferAsync: function(count, size, source, mode, filter) { 32359 if (workers.length > 0) { 32360 return decodeWorker(count, size, source, decoders[mode], filters[filter]); 32361 } 32362 return ready.then(function() { 32363 var target = new Uint8Array(count * size); 32364 decode(instance.exports[decoders[mode]], target, count, size, source, instance.exports[filters[filter]]); 32365 return target; 32366 }); 32367 } 32368 }; 32369 }(); 32370 32371 const _taskCache$1 = new WeakMap(); 32372 class DRACOLoader extends Loader { 32373 setDecoderPath(path) { 32374 this.decoderPath = path; 32375 return this; 32376 } 32377 setDecoderConfig(config) { 32378 this.decoderConfig = config; 32379 return this; 32380 } 32381 setWorkerLimit(workerLimit) { 32382 this.workerLimit = workerLimit; 32383 return this; 32384 } 32385 load(url, onLoad, onProgress, onError) { 32386 const loader = new FileLoader(this.manager); 32387 loader.setPath(this.path); 32388 loader.setResponseType('arraybuffer'); 32389 loader.setRequestHeader(this.requestHeader); 32390 loader.setWithCredentials(this.withCredentials); 32391 loader.load(url, (buffer)=>{ 32392 this.parse(buffer, onLoad, onError); 32393 }, onProgress, onError); 32394 } 32395 parse(buffer, onLoad, onError = ()=>{}) { 32396 this.decodeDracoFile(buffer, onLoad, null, null, SRGBColorSpace, onError).catch(onError); 32397 } 32398 decodeDracoFile(buffer, callback, attributeIDs, attributeTypes, vertexColorSpace = LinearSRGBColorSpace, onError = ()=>{}) { 32399 const taskConfig = { 32400 attributeIDs: attributeIDs || this.defaultAttributeIDs, 32401 attributeTypes: attributeTypes || this.defaultAttributeTypes, 32402 useUniqueIDs: !!attributeIDs, 32403 vertexColorSpace: vertexColorSpace 32404 }; 32405 return this.decodeGeometry(buffer, taskConfig).then(callback).catch(onError); 32406 } 32407 decodeGeometry(buffer, taskConfig) { 32408 const taskKey = JSON.stringify(taskConfig); 32409 // Check for an existing task using this buffer. A transferred buffer cannot be transferred 32410 // again from this thread. 32411 if (_taskCache$1.has(buffer)) { 32412 const cachedTask = _taskCache$1.get(buffer); 32413 if (cachedTask.key === taskKey) { 32414 return cachedTask.promise; 32415 } else if (buffer.byteLength === 0) { 32416 // Technically, it would be possible to wait for the previous task to complete, 32417 // transfer the buffer back, and decode again with the second configuration. That 32418 // is complex, and I don't know of any reason to decode a Draco buffer twice in 32419 // different ways, so this is left unimplemented. 32420 throw new Error('THREE.DRACOLoader: Unable to re-decode a buffer with different ' + 'settings. Buffer has already been transferred.'); 32421 } 32422 } 32423 // 32424 let worker; 32425 const taskID = this.workerNextTaskID++; 32426 const taskCost = buffer.byteLength; 32427 // Obtain a worker and assign a task, and construct a geometry instance 32428 // when the task completes. 32429 const geometryPending = this._getWorker(taskID, taskCost).then((_worker)=>{ 32430 worker = _worker; 32431 return new Promise((resolve, reject)=>{ 32432 worker._callbacks[taskID] = { 32433 resolve, 32434 reject 32435 }; 32436 worker.postMessage({ 32437 type: 'decode', 32438 id: taskID, 32439 taskConfig, 32440 buffer 32441 }, [ 32442 buffer 32443 ]); 32444 // this.debug(); 32445 }); 32446 }).then((message)=>this._createGeometry(message.geometry)); 32447 // Remove task from the task list. 32448 // Note: replaced '.finally()' with '.catch().then()' block - iOS 11 support (#19416) 32449 geometryPending.catch(()=>true).then(()=>{ 32450 if (worker && taskID) { 32451 this._releaseTask(worker, taskID); 32452 // this.debug(); 32453 } 32454 }); 32455 // Cache the task result. 32456 _taskCache$1.set(buffer, { 32457 key: taskKey, 32458 promise: geometryPending 32459 }); 32460 return geometryPending; 32461 } 32462 _createGeometry(geometryData) { 32463 const geometry = new BufferGeometry(); 32464 if (geometryData.index) { 32465 geometry.setIndex(new BufferAttribute(geometryData.index.array, 1)); 32466 } 32467 for(let i = 0; i < geometryData.attributes.length; i++){ 32468 const result = geometryData.attributes[i]; 32469 const name = result.name; 32470 const array = result.array; 32471 const itemSize = result.itemSize; 32472 const attribute = new BufferAttribute(array, itemSize); 32473 if (name === 'color') { 32474 this._assignVertexColorSpace(attribute, result.vertexColorSpace); 32475 attribute.normalized = array instanceof Float32Array === false; 32476 } 32477 geometry.setAttribute(name, attribute); 32478 } 32479 return geometry; 32480 } 32481 _assignVertexColorSpace(attribute, inputColorSpace) { 32482 // While .drc files do not specify colorspace, the only 'official' tooling 32483 // is PLY and OBJ converters, which use sRGB. We'll assume sRGB when a .drc 32484 // file is passed into .load() or .parse(). GLTFLoader uses internal APIs 32485 // to decode geometry, and vertex colors are already Linear-sRGB in there. 32486 if (inputColorSpace !== SRGBColorSpace) return; 32487 const _color = new Color(); 32488 for(let i = 0, il = attribute.count; i < il; i++){ 32489 _color.fromBufferAttribute(attribute, i); 32490 ColorManagement.toWorkingColorSpace(_color, SRGBColorSpace); 32491 attribute.setXYZ(i, _color.r, _color.g, _color.b); 32492 } 32493 } 32494 _loadLibrary(url, responseType) { 32495 const loader = new FileLoader(this.manager); 32496 loader.setPath(this.decoderPath); 32497 loader.setResponseType(responseType); 32498 loader.setWithCredentials(this.withCredentials); 32499 return new Promise((resolve, reject)=>{ 32500 loader.load(url, resolve, undefined, reject); 32501 }); 32502 } 32503 preload() { 32504 this._initDecoder(); 32505 return this; 32506 } 32507 _initDecoder() { 32508 if (this.decoderPending) return this.decoderPending; 32509 const useJS = typeof WebAssembly !== 'object' || this.decoderConfig.type === 'js'; 32510 const librariesPending = []; 32511 if (useJS) { 32512 librariesPending.push(this._loadLibrary('draco_decoder.js', 'text')); 32513 } else { 32514 librariesPending.push(this._loadLibrary('draco_wasm_wrapper.js', 'text')); 32515 librariesPending.push(this._loadLibrary('draco_decoder.wasm', 'arraybuffer')); 32516 } 32517 this.decoderPending = Promise.all(librariesPending).then((libraries)=>{ 32518 const jsContent = libraries[0]; 32519 if (!useJS) { 32520 this.decoderConfig.wasmBinary = libraries[1]; 32521 } 32522 const fn = DRACOWorker.toString(); 32523 const body = [ 32524 '/* draco decoder */', 32525 jsContent, 32526 '', 32527 '/* worker */', 32528 fn.substring(fn.indexOf('{') + 1, fn.lastIndexOf('}')) 32529 ].join('\n'); 32530 this.workerSourceURL = URL.createObjectURL(new Blob([ 32531 body 32532 ])); 32533 }); 32534 return this.decoderPending; 32535 } 32536 _getWorker(taskID, taskCost) { 32537 return this._initDecoder().then(()=>{ 32538 if (this.workerPool.length < this.workerLimit) { 32539 const worker = new Worker(this.workerSourceURL); 32540 worker._callbacks = {}; 32541 worker._taskCosts = {}; 32542 worker._taskLoad = 0; 32543 worker.postMessage({ 32544 type: 'init', 32545 decoderConfig: this.decoderConfig 32546 }); 32547 worker.onmessage = function(e) { 32548 const message = e.data; 32549 switch(message.type){ 32550 case 'decode': 32551 worker._callbacks[message.id].resolve(message); 32552 break; 32553 case 'error': 32554 worker._callbacks[message.id].reject(message); 32555 break; 32556 default: 32557 console.error('THREE.DRACOLoader: Unexpected message, "' + message.type + '"'); 32558 } 32559 }; 32560 this.workerPool.push(worker); 32561 } else { 32562 this.workerPool.sort(function(a, b) { 32563 return a._taskLoad > b._taskLoad ? -1 : 1; 32564 }); 32565 } 32566 const worker = this.workerPool[this.workerPool.length - 1]; 32567 worker._taskCosts[taskID] = taskCost; 32568 worker._taskLoad += taskCost; 32569 return worker; 32570 }); 32571 } 32572 _releaseTask(worker, taskID) { 32573 worker._taskLoad -= worker._taskCosts[taskID]; 32574 delete worker._callbacks[taskID]; 32575 delete worker._taskCosts[taskID]; 32576 } 32577 debug() { 32578 console.log('Task load: ', this.workerPool.map((worker)=>worker._taskLoad)); 32579 } 32580 dispose() { 32581 for(let i = 0; i < this.workerPool.length; ++i){ 32582 this.workerPool[i].terminate(); 32583 } 32584 this.workerPool.length = 0; 32585 if (this.workerSourceURL !== '') { 32586 URL.revokeObjectURL(this.workerSourceURL); 32587 } 32588 return this; 32589 } 32590 constructor(manager){ 32591 super(manager); 32592 this.decoderPath = ''; 32593 this.decoderConfig = {}; 32594 this.decoderBinary = null; 32595 this.decoderPending = null; 32596 this.workerLimit = 4; 32597 this.workerPool = []; 32598 this.workerNextTaskID = 1; 32599 this.workerSourceURL = ''; 32600 this.defaultAttributeIDs = { 32601 position: 'POSITION', 32602 normal: 'NORMAL', 32603 color: 'COLOR', 32604 uv: 'TEX_COORD' 32605 }; 32606 this.defaultAttributeTypes = { 32607 position: 'Float32Array', 32608 normal: 'Float32Array', 32609 color: 'Float32Array', 32610 uv: 'Float32Array' 32611 }; 32612 } 32613 } 32614 /* WEB WORKER */ function DRACOWorker() { 32615 let decoderConfig; 32616 let decoderPending; 32617 onmessage = function(e) { 32618 const message = e.data; 32619 switch(message.type){ 32620 case 'init': 32621 decoderConfig = message.decoderConfig; 32622 decoderPending = new Promise(function(resolve /*, reject*/ ) { 32623 decoderConfig.onModuleLoaded = function(draco) { 32624 // Module is Promise-like. Wrap before resolving to avoid loop. 32625 resolve({ 32626 draco: draco 32627 }); 32628 }; 32629 DracoDecoderModule(decoderConfig); // eslint-disable-line no-undef 32630 }); 32631 break; 32632 case 'decode': 32633 const buffer = message.buffer; 32634 const taskConfig = message.taskConfig; 32635 decoderPending.then((module)=>{ 32636 const draco = module.draco; 32637 const decoder = new draco.Decoder(); 32638 try { 32639 const geometry = decodeGeometry(draco, decoder, new Int8Array(buffer), taskConfig); 32640 const buffers = geometry.attributes.map((attr)=>attr.array.buffer); 32641 if (geometry.index) buffers.push(geometry.index.array.buffer); 32642 self.postMessage({ 32643 type: 'decode', 32644 id: message.id, 32645 geometry 32646 }, buffers); 32647 } catch (error) { 32648 console.error(error); 32649 self.postMessage({ 32650 type: 'error', 32651 id: message.id, 32652 error: error.message 32653 }); 32654 } finally{ 32655 draco.destroy(decoder); 32656 } 32657 }); 32658 break; 32659 } 32660 }; 32661 function decodeGeometry(draco, decoder, array, taskConfig) { 32662 const attributeIDs = taskConfig.attributeIDs; 32663 const attributeTypes = taskConfig.attributeTypes; 32664 let dracoGeometry; 32665 let decodingStatus; 32666 const geometryType = decoder.GetEncodedGeometryType(array); 32667 if (geometryType === draco.TRIANGULAR_MESH) { 32668 dracoGeometry = new draco.Mesh(); 32669 decodingStatus = decoder.DecodeArrayToMesh(array, array.byteLength, dracoGeometry); 32670 } else if (geometryType === draco.POINT_CLOUD) { 32671 dracoGeometry = new draco.PointCloud(); 32672 decodingStatus = decoder.DecodeArrayToPointCloud(array, array.byteLength, dracoGeometry); 32673 } else { 32674 throw new Error('THREE.DRACOLoader: Unexpected geometry type.'); 32675 } 32676 if (!decodingStatus.ok() || dracoGeometry.ptr === 0) { 32677 throw new Error('THREE.DRACOLoader: Decoding failed: ' + decodingStatus.error_msg()); 32678 } 32679 const geometry = { 32680 index: null, 32681 attributes: [] 32682 }; 32683 // Gather all vertex attributes. 32684 for(const attributeName in attributeIDs){ 32685 const attributeType = self[attributeTypes[attributeName]]; 32686 let attribute; 32687 let attributeID; 32688 // A Draco file may be created with default vertex attributes, whose attribute IDs 32689 // are mapped 1:1 from their semantic name (POSITION, NORMAL, ...). Alternatively, 32690 // a Draco file may contain a custom set of attributes, identified by known unique 32691 // IDs. glTF files always do the latter, and `.drc` files typically do the former. 32692 if (taskConfig.useUniqueIDs) { 32693 attributeID = attributeIDs[attributeName]; 32694 attribute = decoder.GetAttributeByUniqueId(dracoGeometry, attributeID); 32695 } else { 32696 attributeID = decoder.GetAttributeId(dracoGeometry, draco[attributeIDs[attributeName]]); 32697 if (attributeID === -1) continue; 32698 attribute = decoder.GetAttribute(dracoGeometry, attributeID); 32699 } 32700 const attributeResult = decodeAttribute(draco, decoder, dracoGeometry, attributeName, attributeType, attribute); 32701 if (attributeName === 'color') { 32702 attributeResult.vertexColorSpace = taskConfig.vertexColorSpace; 32703 } 32704 geometry.attributes.push(attributeResult); 32705 } 32706 // Add index. 32707 if (geometryType === draco.TRIANGULAR_MESH) { 32708 geometry.index = decodeIndex(draco, decoder, dracoGeometry); 32709 } 32710 draco.destroy(dracoGeometry); 32711 return geometry; 32712 } 32713 function decodeIndex(draco, decoder, dracoGeometry) { 32714 const numFaces = dracoGeometry.num_faces(); 32715 const numIndices = numFaces * 3; 32716 const byteLength = numIndices * 4; 32717 const ptr = draco._malloc(byteLength); 32718 decoder.GetTrianglesUInt32Array(dracoGeometry, byteLength, ptr); 32719 const index = new Uint32Array(draco.HEAPF32.buffer, ptr, numIndices).slice(); 32720 draco._free(ptr); 32721 return { 32722 array: index, 32723 itemSize: 1 32724 }; 32725 } 32726 function decodeAttribute(draco, decoder, dracoGeometry, attributeName, attributeType, attribute) { 32727 const numComponents = attribute.num_components(); 32728 const numPoints = dracoGeometry.num_points(); 32729 const numValues = numPoints * numComponents; 32730 const byteLength = numValues * attributeType.BYTES_PER_ELEMENT; 32731 const dataType = getDracoDataType(draco, attributeType); 32732 const ptr = draco._malloc(byteLength); 32733 decoder.GetAttributeDataArrayForAllPoints(dracoGeometry, attribute, dataType, byteLength, ptr); 32734 const array = new attributeType(draco.HEAPF32.buffer, ptr, numValues).slice(); 32735 draco._free(ptr); 32736 return { 32737 name: attributeName, 32738 array: array, 32739 itemSize: numComponents 32740 }; 32741 } 32742 function getDracoDataType(draco, attributeType) { 32743 switch(attributeType){ 32744 case Float32Array: 32745 return draco.DT_FLOAT32; 32746 case Int8Array: 32747 return draco.DT_INT8; 32748 case Int16Array: 32749 return draco.DT_INT16; 32750 case Int32Array: 32751 return draco.DT_INT32; 32752 case Uint8Array: 32753 return draco.DT_UINT8; 32754 case Uint16Array: 32755 return draco.DT_UINT16; 32756 case Uint32Array: 32757 return draco.DT_UINT32; 32758 } 32759 } 32760 } 32761 32762 /** 32763 * @param {BufferGeometry} geometry 32764 * @param {number} drawMode 32765 * @return {BufferGeometry} 32766 */ function toTrianglesDrawMode(geometry, drawMode) { 32767 if (drawMode === TrianglesDrawMode) { 32768 console.warn('THREE.BufferGeometryUtils.toTrianglesDrawMode(): Geometry already defined as triangles.'); 32769 return geometry; 32770 } 32771 if (drawMode === TriangleFanDrawMode || drawMode === TriangleStripDrawMode) { 32772 let index = geometry.getIndex(); 32773 // generate index if not present 32774 if (index === null) { 32775 const indices = []; 32776 const position = geometry.getAttribute('position'); 32777 if (position !== undefined) { 32778 for(let i = 0; i < position.count; i++){ 32779 indices.push(i); 32780 } 32781 geometry.setIndex(indices); 32782 index = geometry.getIndex(); 32783 } else { 32784 console.error('THREE.BufferGeometryUtils.toTrianglesDrawMode(): Undefined position attribute. Processing not possible.'); 32785 return geometry; 32786 } 32787 } 32788 // 32789 const numberOfTriangles = index.count - 2; 32790 const newIndices = []; 32791 if (drawMode === TriangleFanDrawMode) { 32792 // gl.TRIANGLE_FAN 32793 for(let i = 1; i <= numberOfTriangles; i++){ 32794 newIndices.push(index.getX(0)); 32795 newIndices.push(index.getX(i)); 32796 newIndices.push(index.getX(i + 1)); 32797 } 32798 } else { 32799 // gl.TRIANGLE_STRIP 32800 for(let i = 0; i < numberOfTriangles; i++){ 32801 if (i % 2 === 0) { 32802 newIndices.push(index.getX(i)); 32803 newIndices.push(index.getX(i + 1)); 32804 newIndices.push(index.getX(i + 2)); 32805 } else { 32806 newIndices.push(index.getX(i + 2)); 32807 newIndices.push(index.getX(i + 1)); 32808 newIndices.push(index.getX(i)); 32809 } 32810 } 32811 } 32812 if (newIndices.length / 3 !== numberOfTriangles) { 32813 console.error('THREE.BufferGeometryUtils.toTrianglesDrawMode(): Unable to generate correct amount of triangles.'); 32814 } 32815 // build final geometry 32816 const newGeometry = geometry.clone(); 32817 newGeometry.setIndex(newIndices); 32818 newGeometry.clearGroups(); 32819 return newGeometry; 32820 } else { 32821 console.error('THREE.BufferGeometryUtils.toTrianglesDrawMode(): Unknown draw mode:', drawMode); 32822 return geometry; 32823 } 32824 } 32825 32826 class GLTFLoader extends Loader { 32827 load(url, onLoad, onProgress, onError) { 32828 const scope = this; 32829 let resourcePath; 32830 if (this.resourcePath !== '') { 32831 resourcePath = this.resourcePath; 32832 } else if (this.path !== '') { 32833 // If a base path is set, resources will be relative paths from that plus the relative path of the gltf file 32834 // Example path = 'https://my-cnd-server.com/', url = 'assets/models/model.gltf' 32835 // resourcePath = 'https://my-cnd-server.com/assets/models/' 32836 // referenced resource 'model.bin' will be loaded from 'https://my-cnd-server.com/assets/models/model.bin' 32837 // referenced resource '../textures/texture.png' will be loaded from 'https://my-cnd-server.com/assets/textures/texture.png' 32838 const relativeUrl = LoaderUtils.extractUrlBase(url); 32839 resourcePath = LoaderUtils.resolveURL(relativeUrl, this.path); 32840 } else { 32841 resourcePath = LoaderUtils.extractUrlBase(url); 32842 } 32843 // Tells the LoadingManager to track an extra item, which resolves after 32844 // the model is fully loaded. This means the count of items loaded will 32845 // be incorrect, but ensures manager.onLoad() does not fire early. 32846 this.manager.itemStart(url); 32847 const _onError = function(e) { 32848 if (onError) { 32849 onError(e); 32850 } else { 32851 console.error(e); 32852 } 32853 scope.manager.itemError(url); 32854 scope.manager.itemEnd(url); 32855 }; 32856 const loader = new FileLoader(this.manager); 32857 loader.setPath(this.path); 32858 loader.setResponseType('arraybuffer'); 32859 loader.setRequestHeader(this.requestHeader); 32860 loader.setWithCredentials(this.withCredentials); 32861 loader.load(url, function(data) { 32862 try { 32863 scope.parse(data, resourcePath, function(gltf) { 32864 onLoad(gltf); 32865 scope.manager.itemEnd(url); 32866 }, _onError); 32867 } catch (e) { 32868 _onError(e); 32869 } 32870 }, onProgress, _onError); 32871 } 32872 setDRACOLoader(dracoLoader) { 32873 this.dracoLoader = dracoLoader; 32874 return this; 32875 } 32876 setKTX2Loader(ktx2Loader) { 32877 this.ktx2Loader = ktx2Loader; 32878 return this; 32879 } 32880 setMeshoptDecoder(meshoptDecoder) { 32881 this.meshoptDecoder = meshoptDecoder; 32882 return this; 32883 } 32884 register(callback) { 32885 if (this.pluginCallbacks.indexOf(callback) === -1) { 32886 this.pluginCallbacks.push(callback); 32887 } 32888 return this; 32889 } 32890 unregister(callback) { 32891 if (this.pluginCallbacks.indexOf(callback) !== -1) { 32892 this.pluginCallbacks.splice(this.pluginCallbacks.indexOf(callback), 1); 32893 } 32894 return this; 32895 } 32896 parse(data, path, onLoad, onError) { 32897 let json; 32898 const extensions = {}; 32899 const plugins = {}; 32900 const textDecoder = new TextDecoder(); 32901 if (typeof data === 'string') { 32902 json = JSON.parse(data); 32903 } else if (data instanceof ArrayBuffer) { 32904 const magic = textDecoder.decode(new Uint8Array(data, 0, 4)); 32905 if (magic === BINARY_EXTENSION_HEADER_MAGIC) { 32906 try { 32907 extensions[EXTENSIONS.KHR_BINARY_GLTF] = new GLTFBinaryExtension(data); 32908 } catch (error) { 32909 if (onError) onError(error); 32910 return; 32911 } 32912 json = JSON.parse(extensions[EXTENSIONS.KHR_BINARY_GLTF].content); 32913 } else { 32914 json = JSON.parse(textDecoder.decode(data)); 32915 } 32916 } else { 32917 json = data; 32918 } 32919 if (json.asset === undefined || json.asset.version[0] < 2) { 32920 if (onError) onError(new Error('THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported.')); 32921 return; 32922 } 32923 const parser = new GLTFParser(json, { 32924 path: path || this.resourcePath || '', 32925 crossOrigin: this.crossOrigin, 32926 requestHeader: this.requestHeader, 32927 manager: this.manager, 32928 ktx2Loader: this.ktx2Loader, 32929 meshoptDecoder: this.meshoptDecoder 32930 }); 32931 parser.fileLoader.setRequestHeader(this.requestHeader); 32932 for(let i = 0; i < this.pluginCallbacks.length; i++){ 32933 const plugin = this.pluginCallbacks[i](parser); 32934 if (!plugin.name) console.error('THREE.GLTFLoader: Invalid plugin found: missing name'); 32935 plugins[plugin.name] = plugin; 32936 // Workaround to avoid determining as unknown extension 32937 // in addUnknownExtensionsToUserData(). 32938 // Remove this workaround if we move all the existing 32939 // extension handlers to plugin system 32940 extensions[plugin.name] = true; 32941 } 32942 if (json.extensionsUsed) { 32943 for(let i = 0; i < json.extensionsUsed.length; ++i){ 32944 const extensionName = json.extensionsUsed[i]; 32945 const extensionsRequired = json.extensionsRequired || []; 32946 switch(extensionName){ 32947 case EXTENSIONS.KHR_MATERIALS_UNLIT: 32948 extensions[extensionName] = new GLTFMaterialsUnlitExtension$1(); 32949 break; 32950 case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION: 32951 extensions[extensionName] = new GLTFDracoMeshCompressionExtension(json, this.dracoLoader); 32952 break; 32953 case EXTENSIONS.KHR_TEXTURE_TRANSFORM: 32954 extensions[extensionName] = new GLTFTextureTransformExtension(); 32955 break;
vendor: 2,009 bytes, lines 32956-33006
32956 case EXTENSIONS.KHR_MESH_QUANTIZATION: 32957 extensions[extensionName] = new GLTFMeshQuantizationExtension(); 32958 break; 32959 default: 32960 if (extensionsRequired.indexOf(extensionName) >= 0 && plugins[extensionName] === undefined) { 32961 console.warn('THREE.GLTFLoader: Unknown extension "' + extensionName + '".'); 32962 } 32963 } 32964 } 32965 } 32966 parser.setExtensions(extensions); 32967 parser.setPlugins(plugins); 32968 parser.parse(onLoad, onError); 32969 } 32970 parseAsync(data, path) { 32971 const scope = this; 32972 return new Promise(function(resolve, reject) { 32973 scope.parse(data, path, resolve, reject); 32974 }); 32975 } 32976 constructor(manager){ 32977 super(manager); 32978 this.dracoLoader = null; 32979 this.ktx2Loader = null; 32980 this.meshoptDecoder = null; 32981 this.pluginCallbacks = []; 32982 this.register(function(parser) { 32983 return new GLTFMaterialsClearcoatExtension$1(parser); 32984 }); 32985 this.register(function(parser) { 32986 return new GLTFMaterialsDispersionExtension$1(parser); 32987 }); 32988 this.register(function(parser) { 32989 return new GLTFTextureBasisUExtension(parser); 32990 }); 32991 this.register(function(parser) { 32992 return new GLTFTextureWebPExtension(parser); 32993 }); 32994 this.register(function(parser) { 32995 return new GLTFTextureAVIFExtension(parser); 32996 }); 32997 this.register(function(parser) { 32998 return new GLTFMaterialsSheenExtension$1(parser); 32999 }); 33000 this.register(function(parser) { 33001 return new GLTFMaterialsTransmissionExtension$1(parser); 33002 }); 33003 this.register(function(parser) { 33004 return new GLTFMaterialsVolumeExtension$1(parser); 33005 }); 33006 this.register(function(parser) {
vendor: 20,079 bytes, lines 33007-33452
33007 return new GLTFMaterialsIorExtension$1(parser); 33008 }); 33009 this.register(function(parser) { 33010 return new GLTFMaterialsEmissiveStrengthExtension$1(parser); 33011 }); 33012 this.register(function(parser) { 33013 return new GLTFMaterialsSpecularExtension$1(parser); 33014 }); 33015 this.register(function(parser) { 33016 return new GLTFMaterialsIridescenceExtension$1(parser); 33017 }); 33018 this.register(function(parser) { 33019 return new GLTFMaterialsAnisotropyExtension$1(parser); 33020 }); 33021 this.register(function(parser) { 33022 return new GLTFMaterialsBumpExtension$1(parser); 33023 }); 33024 this.register(function(parser) { 33025 return new GLTFLightsExtension(parser); 33026 }); 33027 this.register(function(parser) { 33028 return new GLTFMeshoptCompression(parser); 33029 }); 33030 this.register(function(parser) { 33031 return new GLTFMeshGpuInstancing$1(parser); 33032 }); 33033 } 33034 } 33035 /* GLTFREGISTRY */ function GLTFRegistry() { 33036 let objects = {}; 33037 return { 33038 get: function(key) { 33039 return objects[key]; 33040 }, 33041 add: function(key, object) { 33042 objects[key] = object; 33043 }, 33044 remove: function(key) { 33045 delete objects[key]; 33046 }, 33047 removeAll: function() { 33048 objects = {}; 33049 } 33050 }; 33051 } 33052 /*********************************/ /********** EXTENSIONS ***********/ /*********************************/ const EXTENSIONS = { 33053 KHR_BINARY_GLTF: 'KHR_binary_glTF', 33054 KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression', 33055 KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual', 33056 KHR_MATERIALS_CLEARCOAT: 'KHR_materials_clearcoat', 33057 KHR_MATERIALS_DISPERSION: 'KHR_materials_dispersion', 33058 KHR_MATERIALS_IOR: 'KHR_materials_ior', 33059 KHR_MATERIALS_SHEEN: 'KHR_materials_sheen', 33060 KHR_MATERIALS_SPECULAR: 'KHR_materials_specular', 33061 KHR_MATERIALS_TRANSMISSION: 'KHR_materials_transmission', 33062 KHR_MATERIALS_IRIDESCENCE: 'KHR_materials_iridescence', 33063 KHR_MATERIALS_ANISOTROPY: 'KHR_materials_anisotropy', 33064 KHR_MATERIALS_UNLIT: 'KHR_materials_unlit', 33065 KHR_MATERIALS_VOLUME: 'KHR_materials_volume', 33066 KHR_TEXTURE_BASISU: 'KHR_texture_basisu', 33067 KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform', 33068 KHR_MESH_QUANTIZATION: 'KHR_mesh_quantization', 33069 KHR_MATERIALS_EMISSIVE_STRENGTH: 'KHR_materials_emissive_strength', 33070 EXT_MATERIALS_BUMP: 'EXT_materials_bump', 33071 EXT_TEXTURE_WEBP: 'EXT_texture_webp', 33072 EXT_TEXTURE_AVIF: 'EXT_texture_avif', 33073 EXT_MESHOPT_COMPRESSION: 'EXT_meshopt_compression', 33074 EXT_MESH_GPU_INSTANCING: 'EXT_mesh_gpu_instancing' 33075 }; 33076 /** 33077 * Punctual Lights Extension 33078 * 33079 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual 33080 */ class GLTFLightsExtension { 33081 _markDefs() { 33082 const parser = this.parser; 33083 const nodeDefs = this.parser.json.nodes || []; 33084 for(let nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex++){ 33085 const nodeDef = nodeDefs[nodeIndex]; 33086 if (nodeDef.extensions && nodeDef.extensions[this.name] && nodeDef.extensions[this.name].light !== undefined) { 33087 parser._addNodeRef(this.cache, nodeDef.extensions[this.name].light); 33088 } 33089 } 33090 } 33091 _loadLight(lightIndex) { 33092 const parser = this.parser; 33093 const cacheKey = 'light:' + lightIndex; 33094 let dependency = parser.cache.get(cacheKey); 33095 if (dependency) return dependency; 33096 const json = parser.json; 33097 const extensions = json.extensions && json.extensions[this.name] || {}; 33098 const lightDefs = extensions.lights || []; 33099 const lightDef = lightDefs[lightIndex]; 33100 let lightNode; 33101 const color = new Color(0xffffff); 33102 if (lightDef.color !== undefined) color.setRGB(lightDef.color[0], lightDef.color[1], lightDef.color[2], LinearSRGBColorSpace); 33103 const range = lightDef.range !== undefined ? lightDef.range : 0; 33104 switch(lightDef.type){ 33105 case 'directional': 33106 lightNode = new DirectionalLight(color); 33107 lightNode.target.position.set(0, 0, -1); 33108 lightNode.add(lightNode.target); 33109 break; 33110 case 'point': 33111 lightNode = new PointLight(color); 33112 lightNode.distance = range; 33113 break; 33114 case 'spot': 33115 lightNode = new SpotLight(color); 33116 lightNode.distance = range; 33117 // Handle spotlight properties. 33118 lightDef.spot = lightDef.spot || {}; 33119 lightDef.spot.innerConeAngle = lightDef.spot.innerConeAngle !== undefined ? lightDef.spot.innerConeAngle : 0; 33120 lightDef.spot.outerConeAngle = lightDef.spot.outerConeAngle !== undefined ? lightDef.spot.outerConeAngle : Math.PI / 4.0; 33121 lightNode.angle = lightDef.spot.outerConeAngle; 33122 lightNode.penumbra = 1.0 - lightDef.spot.innerConeAngle / lightDef.spot.outerConeAngle; 33123 lightNode.target.position.set(0, 0, -1); 33124 lightNode.add(lightNode.target); 33125 break; 33126 default: 33127 throw new Error('THREE.GLTFLoader: Unexpected light type: ' + lightDef.type); 33128 } 33129 // Some lights (e.g. spot) default to a position other than the origin. Reset the position 33130 // here, because node-level parsing will only override position if explicitly specified. 33131 lightNode.position.set(0, 0, 0); 33132 assignExtrasToUserData(lightNode, lightDef); 33133 if (lightDef.intensity !== undefined) lightNode.intensity = lightDef.intensity; 33134 lightNode.name = parser.createUniqueName(lightDef.name || 'light_' + lightIndex); 33135 dependency = Promise.resolve(lightNode); 33136 parser.cache.add(cacheKey, dependency); 33137 return dependency; 33138 } 33139 getDependency(type, index) { 33140 if (type !== 'light') return; 33141 return this._loadLight(index); 33142 } 33143 createNodeAttachment(nodeIndex) { 33144 const self1 = this; 33145 const parser = this.parser; 33146 const json = parser.json; 33147 const nodeDef = json.nodes[nodeIndex]; 33148 const lightDef = nodeDef.extensions && nodeDef.extensions[this.name] || {}; 33149 const lightIndex = lightDef.light; 33150 if (lightIndex === undefined) return null; 33151 return this._loadLight(lightIndex).then(function(light) { 33152 return parser._getNodeRef(self1.cache, lightIndex, light); 33153 }); 33154 } 33155 constructor(parser){ 33156 this.parser = parser; 33157 this.name = EXTENSIONS.KHR_LIGHTS_PUNCTUAL; 33158 // Object3D instance caches 33159 this.cache = { 33160 refs: {}, 33161 uses: {} 33162 }; 33163 } 33164 } 33165 /** 33166 * Unlit Materials Extension 33167 * 33168 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit 33169 */ let GLTFMaterialsUnlitExtension$1 = class GLTFMaterialsUnlitExtension { 33170 getMaterialType() { 33171 return MeshBasicMaterial; 33172 } 33173 extendParams(materialParams, materialDef, parser) { 33174 const pending = []; 33175 materialParams.color = new Color(1.0, 1.0, 1.0); 33176 materialParams.opacity = 1.0; 33177 const metallicRoughness = materialDef.pbrMetallicRoughness; 33178 if (metallicRoughness) { 33179 if (Array.isArray(metallicRoughness.baseColorFactor)) { 33180 const array = metallicRoughness.baseColorFactor; 33181 materialParams.color.setRGB(array[0], array[1], array[2], LinearSRGBColorSpace); 33182 materialParams.opacity = array[3]; 33183 } 33184 if (metallicRoughness.baseColorTexture !== undefined) { 33185 pending.push(parser.assignTexture(materialParams, 'map', metallicRoughness.baseColorTexture, SRGBColorSpace)); 33186 } 33187 } 33188 return Promise.all(pending); 33189 } 33190 constructor(){ 33191 this.name = EXTENSIONS.KHR_MATERIALS_UNLIT; 33192 } 33193 }; 33194 /** 33195 * Materials Emissive Strength Extension 33196 * 33197 * Specification: https://github.com/KhronosGroup/glTF/blob/5768b3ce0ef32bc39cdf1bef10b948586635ead3/extensions/2.0/Khronos/KHR_materials_emissive_strength/README.md 33198 */ let GLTFMaterialsEmissiveStrengthExtension$1 = class GLTFMaterialsEmissiveStrengthExtension { 33199 extendMaterialParams(materialIndex, materialParams) { 33200 const parser = this.parser; 33201 const materialDef = parser.json.materials[materialIndex]; 33202 if (!materialDef.extensions || !materialDef.extensions[this.name]) { 33203 return Promise.resolve(); 33204 } 33205 const emissiveStrength = materialDef.extensions[this.name].emissiveStrength; 33206 if (emissiveStrength !== undefined) { 33207 materialParams.emissiveIntensity = emissiveStrength; 33208 } 33209 return Promise.resolve(); 33210 } 33211 constructor(parser){ 33212 this.parser = parser; 33213 this.name = EXTENSIONS.KHR_MATERIALS_EMISSIVE_STRENGTH; 33214 } 33215 }; 33216 /** 33217 * Clearcoat Materials Extension 33218 * 33219 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_clearcoat 33220 */ let GLTFMaterialsClearcoatExtension$1 = class GLTFMaterialsClearcoatExtension { 33221 getMaterialType(materialIndex) { 33222 const parser = this.parser; 33223 const materialDef = parser.json.materials[materialIndex]; 33224 if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; 33225 return MeshPhysicalMaterial; 33226 } 33227 extendMaterialParams(materialIndex, materialParams) { 33228 const parser = this.parser; 33229 const materialDef = parser.json.materials[materialIndex]; 33230 if (!materialDef.extensions || !materialDef.extensions[this.name]) { 33231 return Promise.resolve(); 33232 } 33233 const pending = []; 33234 const extension = materialDef.extensions[this.name]; 33235 if (extension.clearcoatFactor !== undefined) { 33236 materialParams.clearcoat = extension.clearcoatFactor; 33237 } 33238 if (extension.clearcoatTexture !== undefined) { 33239 pending.push(parser.assignTexture(materialParams, 'clearcoatMap', extension.clearcoatTexture)); 33240 } 33241 if (extension.clearcoatRoughnessFactor !== undefined) { 33242 materialParams.clearcoatRoughness = extension.clearcoatRoughnessFactor; 33243 } 33244 if (extension.clearcoatRoughnessTexture !== undefined) { 33245 pending.push(parser.assignTexture(materialParams, 'clearcoatRoughnessMap', extension.clearcoatRoughnessTexture)); 33246 } 33247 if (extension.clearcoatNormalTexture !== undefined) { 33248 pending.push(parser.assignTexture(materialParams, 'clearcoatNormalMap', extension.clearcoatNormalTexture)); 33249 if (extension.clearcoatNormalTexture.scale !== undefined) { 33250 const scale = extension.clearcoatNormalTexture.scale; 33251 materialParams.clearcoatNormalScale = new Vector2(scale, scale); 33252 } 33253 } 33254 return Promise.all(pending); 33255 } 33256 constructor(parser){ 33257 this.parser = parser; 33258 this.name = EXTENSIONS.KHR_MATERIALS_CLEARCOAT; 33259 } 33260 }; 33261 /** 33262 * Materials dispersion Extension 33263 * 33264 * Specification: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_dispersion 33265 */ let GLTFMaterialsDispersionExtension$1 = class GLTFMaterialsDispersionExtension { 33266 getMaterialType(materialIndex) { 33267 const parser = this.parser; 33268 const materialDef = parser.json.materials[materialIndex]; 33269 if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; 33270 return MeshPhysicalMaterial; 33271 } 33272 extendMaterialParams(materialIndex, materialParams) { 33273 const parser = this.parser; 33274 const materialDef = parser.json.materials[materialIndex]; 33275 if (!materialDef.extensions || !materialDef.extensions[this.name]) { 33276 return Promise.resolve(); 33277 } 33278 const extension = materialDef.extensions[this.name]; 33279 materialParams.dispersion = extension.dispersion !== undefined ? extension.dispersion : 0; 33280 return Promise.resolve(); 33281 } 33282 constructor(parser){ 33283 this.parser = parser; 33284 this.name = EXTENSIONS.KHR_MATERIALS_DISPERSION; 33285 } 33286 }; 33287 /** 33288 * Iridescence Materials Extension 33289 * 33290 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_iridescence 33291 */ let GLTFMaterialsIridescenceExtension$1 = class GLTFMaterialsIridescenceExtension { 33292 getMaterialType(materialIndex) { 33293 const parser = this.parser; 33294 const materialDef = parser.json.materials[materialIndex]; 33295 if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; 33296 return MeshPhysicalMaterial; 33297 } 33298 extendMaterialParams(materialIndex, materialParams) { 33299 const parser = this.parser; 33300 const materialDef = parser.json.materials[materialIndex]; 33301 if (!materialDef.extensions || !materialDef.extensions[this.name]) { 33302 return Promise.resolve(); 33303 } 33304 const pending = []; 33305 const extension = materialDef.extensions[this.name]; 33306 if (extension.iridescenceFactor !== undefined) { 33307 materialParams.iridescence = extension.iridescenceFactor; 33308 } 33309 if (extension.iridescenceTexture !== undefined) { 33310 pending.push(parser.assignTexture(materialParams, 'iridescenceMap', extension.iridescenceTexture)); 33311 } 33312 if (extension.iridescenceIor !== undefined) { 33313 materialParams.iridescenceIOR = extension.iridescenceIor; 33314 } 33315 if (materialParams.iridescenceThicknessRange === undefined) { 33316 materialParams.iridescenceThicknessRange = [ 33317 100, 33318 400 33319 ]; 33320 } 33321 if (extension.iridescenceThicknessMinimum !== undefined) { 33322 materialParams.iridescenceThicknessRange[0] = extension.iridescenceThicknessMinimum; 33323 } 33324 if (extension.iridescenceThicknessMaximum !== undefined) { 33325 materialParams.iridescenceThicknessRange[1] = extension.iridescenceThicknessMaximum; 33326 } 33327 if (extension.iridescenceThicknessTexture !== undefined) { 33328 pending.push(parser.assignTexture(materialParams, 'iridescenceThicknessMap', extension.iridescenceThicknessTexture)); 33329 } 33330 return Promise.all(pending); 33331 } 33332 constructor(parser){ 33333 this.parser = parser; 33334 this.name = EXTENSIONS.KHR_MATERIALS_IRIDESCENCE; 33335 } 33336 }; 33337 /** 33338 * Sheen Materials Extension 33339 * 33340 * Specification: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_sheen 33341 */ let GLTFMaterialsSheenExtension$1 = class GLTFMaterialsSheenExtension { 33342 getMaterialType(materialIndex) { 33343 const parser = this.parser; 33344 const materialDef = parser.json.materials[materialIndex]; 33345 if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; 33346 return MeshPhysicalMaterial; 33347 } 33348 extendMaterialParams(materialIndex, materialParams) { 33349 const parser = this.parser; 33350 const materialDef = parser.json.materials[materialIndex]; 33351 if (!materialDef.extensions || !materialDef.extensions[this.name]) { 33352 return Promise.resolve(); 33353 } 33354 const pending = []; 33355 materialParams.sheenColor = new Color(0, 0, 0); 33356 materialParams.sheenRoughness = 0; 33357 materialParams.sheen = 1; 33358 const extension = materialDef.extensions[this.name]; 33359 if (extension.sheenColorFactor !== undefined) { 33360 const colorFactor = extension.sheenColorFactor; 33361 materialParams.sheenColor.setRGB(colorFactor[0], colorFactor[1], colorFactor[2], LinearSRGBColorSpace); 33362 } 33363 if (extension.sheenRoughnessFactor !== undefined) { 33364 materialParams.sheenRoughness = extension.sheenRoughnessFactor; 33365 } 33366 if (extension.sheenColorTexture !== undefined) { 33367 pending.push(parser.assignTexture(materialParams, 'sheenColorMap', extension.sheenColorTexture, SRGBColorSpace)); 33368 } 33369 if (extension.sheenRoughnessTexture !== undefined) { 33370 pending.push(parser.assignTexture(materialParams, 'sheenRoughnessMap', extension.sheenRoughnessTexture)); 33371 } 33372 return Promise.all(pending); 33373 } 33374 constructor(parser){ 33375 this.parser = parser; 33376 this.name = EXTENSIONS.KHR_MATERIALS_SHEEN; 33377 } 33378 }; 33379 /** 33380 * Transmission Materials Extension 33381 * 33382 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_transmission 33383 * Draft: https://github.com/KhronosGroup/glTF/pull/1698 33384 */ let GLTFMaterialsTransmissionExtension$1 = class GLTFMaterialsTransmissionExtension { 33385 getMaterialType(materialIndex) { 33386 const parser = this.parser; 33387 const materialDef = parser.json.materials[materialIndex]; 33388 if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; 33389 return MeshPhysicalMaterial; 33390 } 33391 extendMaterialParams(materialIndex, materialParams) { 33392 const parser = this.parser; 33393 const materialDef = parser.json.materials[materialIndex]; 33394 if (!materialDef.extensions || !materialDef.extensions[this.name]) { 33395 return Promise.resolve(); 33396 } 33397 const pending = []; 33398 const extension = materialDef.extensions[this.name]; 33399 if (extension.transmissionFactor !== undefined) { 33400 materialParams.transmission = extension.transmissionFactor; 33401 } 33402 if (extension.transmissionTexture !== undefined) { 33403 pending.push(parser.assignTexture(materialParams, 'transmissionMap', extension.transmissionTexture)); 33404 } 33405 return Promise.all(pending); 33406 } 33407 constructor(parser){ 33408 this.parser = parser; 33409 this.name = EXTENSIONS.KHR_MATERIALS_TRANSMISSION; 33410 } 33411 }; 33412 /** 33413 * Materials Volume Extension 33414 * 33415 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_volume 33416 */ let GLTFMaterialsVolumeExtension$1 = class GLTFMaterialsVolumeExtension { 33417 getMaterialType(materialIndex) { 33418 const parser = this.parser; 33419 const materialDef = parser.json.materials[materialIndex]; 33420 if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; 33421 return MeshPhysicalMaterial; 33422 } 33423 extendMaterialParams(materialIndex, materialParams) { 33424 const parser = this.parser; 33425 const materialDef = parser.json.materials[materialIndex]; 33426 if (!materialDef.extensions || !materialDef.extensions[this.name]) { 33427 return Promise.resolve(); 33428 } 33429 const pending = []; 33430 const extension = materialDef.extensions[this.name]; 33431 materialParams.thickness = extension.thicknessFactor !== undefined ? extension.thicknessFactor : 0; 33432 if (extension.thicknessTexture !== undefined) { 33433 pending.push(parser.assignTexture(materialParams, 'thicknessMap', extension.thicknessTexture)); 33434 } 33435 materialParams.attenuationDistance = extension.attenuationDistance || Infinity; 33436 const colorArray = extension.attenuationColor || [ 33437 1, 33438 1, 33439 1 33440 ]; 33441 materialParams.attenuationColor = new Color().setRGB(colorArray[0], colorArray[1], colorArray[2], LinearSRGBColorSpace); 33442 return Promise.all(pending); 33443 } 33444 constructor(parser){ 33445 this.parser = parser; 33446 this.name = EXTENSIONS.KHR_MATERIALS_VOLUME; 33447 } 33448 }; 33449 /** 33450 * Materials ior Extension 33451 * 33452 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_ior
33453 */ let GLTFMaterialsIorExtension$1 = class GLTFMaterialsIorExtension { 33454 getMaterialType(materialIndex) { 33455 const parser = this.parser; 33456 const materialDef = parser.json.materials[materialIndex]; 33457 if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; 33458 return MeshPhysicalMaterial; 33459 } 33460 extendMaterialParams(materialIndex, materialParams) { 33461 const parser = this.parser; 33462 const materialDef = parser.json.materials[materialIndex]; 33463 if (!materialDef.extensions || !materialDef.extensions[this.name]) { 33464 return Promise.resolve(); 33465 } 33466 const extension = materialDef.extensions[this.name]; 33467 materialParams.ior = extension.ior !== undefined ? extension.ior : 1.5; 33468 return Promise.resolve(); 33469 } 33470 constructor(parser){ 33471 this.parser = parser; 33472 this.name = EXTENSIONS.KHR_MATERIALS_IOR; 33473 } 33474 }; 33475 /** 33476 * Materials specular Extension 33477 * 33478 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_specular 33479 */ let GLTFMaterialsSpecularExtension$1 = class GLTFMaterialsSpecularExtension { 33480 getMaterialType(materialIndex) { 33481 const parser = this.parser; 33482 const materialDef = parser.json.materials[materialIndex]; 33483 if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; 33484 return MeshPhysicalMaterial; 33485 } 33486 extendMaterialParams(materialIndex, materialParams) { 33487 const parser = this.parser; 33488 const materialDef = parser.json.materials[materialIndex]; 33489 if (!materialDef.extensions || !materialDef.extensions[this.name]) { 33490 return Promise.resolve(); 33491 } 33492 const pending = []; 33493 const extension = materialDef.extensions[this.name]; 33494 materialParams.specularIntensity = extension.specularFactor !== undefined ? extension.specularFactor : 1.0; 33495 if (extension.specularTexture !== undefined) { 33496 pending.push(parser.assignTexture(materialParams, 'specularIntensityMap', extension.specularTexture)); 33497 } 33498 const colorArray = extension.specularColorFactor || [ 33499 1, 33500 1, 33501 1 33502 ]; 33503 materialParams.specularColor = new Color().setRGB(colorArray[0], colorArray[1], colorArray[2], LinearSRGBColorSpace); 33504 if (extension.specularColorTexture !== undefined) { 33505 pending.push(parser.assignTexture(materialParams, 'specularColorMap', extension.specularColorTexture, SRGBColorSpace)); 33506 } 33507 return Promise.all(pending); 33508 } 33509 constructor(parser){ 33510 this.parser = parser; 33511 this.name = EXTENSIONS.KHR_MATERIALS_SPECULAR; 33512 } 33513 }; 33514 /** 33515 * Materials bump Extension 33516 * 33517 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/EXT_materials_bump 33518 */ let GLTFMaterialsBumpExtension$1 = class GLTFMaterialsBumpExtension { 33519 getMaterialType(materialIndex) { 33520 const parser = this.parser; 33521 const materialDef = parser.json.materials[materialIndex]; 33522 if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; 33523 return MeshPhysicalMaterial; 33524 } 33525 extendMaterialParams(materialIndex, materialParams) { 33526 const parser = this.parser; 33527 const materialDef = parser.json.materials[materialIndex]; 33528 if (!materialDef.extensions || !materialDef.extensions[this.name]) { 33529 return Promise.resolve(); 33530 } 33531 const pending = []; 33532 const extension = materialDef.extensions[this.name]; 33533 materialParams.bumpScale = extension.bumpFactor !== undefined ? extension.bumpFactor : 1.0; 33534 if (extension.bumpTexture !== undefined) { 33535 pending.push(parser.assignTexture(materialParams, 'bumpMap', extension.bumpTexture)); 33536 } 33537 return Promise.all(pending); 33538 } 33539 constructor(parser){ 33540 this.parser = parser; 33541 this.name = EXTENSIONS.EXT_MATERIALS_BUMP; 33542 } 33543 }; 33544 /** 33545 * Materials anisotropy Extension 33546 * 33547 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_anisotropy 33548 */ let GLTFMaterialsAnisotropyExtension$1 = class GLTFMaterialsAnisotropyExtension { 33549 getMaterialType(materialIndex) { 33550 const parser = this.parser; 33551 const materialDef = parser.json.materials[materialIndex]; 33552 if (!materialDef.extensions || !materialDef.extensions[this.name]) return null; 33553 return MeshPhysicalMaterial; 33554 } 33555 extendMaterialParams(materialIndex, materialParams) { 33556 const parser = this.parser; 33557 const materialDef = parser.json.materials[materialIndex]; 33558 if (!materialDef.extensions || !materialDef.extensions[this.name]) { 33559 return Promise.resolve(); 33560 } 33561 const pending = []; 33562 const extension = materialDef.extensions[this.name]; 33563 if (extension.anisotropyStrength !== undefined) { 33564 materialParams.anisotropy = extension.anisotropyStrength; 33565 } 33566 if (extension.anisotropyRotation !== undefined) { 33567 materialParams.anisotropyRotation = extension.anisotropyRotation; 33568 } 33569 if (extension.anisotropyTexture !== undefined) { 33570 pending.push(parser.assignTexture(materialParams, 'anisotropyMap', extension.anisotropyTexture)); 33571 } 33572 return Promise.all(pending); 33573 } 33574 constructor(parser){ 33575 this.parser = parser; 33576 this.name = EXTENSIONS.KHR_MATERIALS_ANISOTROPY; 33577 } 33578 }; 33579 /** 33580 * BasisU Texture Extension 33581 * 33582 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_texture_basisu 33583 */ class GLTFTextureBasisUExtension { 33584 loadTexture(textureIndex) { 33585 const parser = this.parser; 33586 const json = parser.json; 33587 const textureDef = json.textures[textureIndex]; 33588 if (!textureDef.extensions || !textureDef.extensions[this.name]) { 33589 return null; 33590 } 33591 const extension = textureDef.extensions[this.name]; 33592 const loader = parser.options.ktx2Loader; 33593 if (!loader) { 33594 if (json.extensionsRequired && json.extensionsRequired.indexOf(this.name) >= 0) { 33595 throw new Error('THREE.GLTFLoader: setKTX2Loader must be called before loading KTX2 textures'); 33596 } else { 33597 // Assumes that the extension is optional and that a fallback texture is present 33598 return null; 33599 } 33600 } 33601 return parser.loadTextureImage(textureIndex, extension.source, loader); 33602 } 33603 constructor(parser){ 33604 this.parser = parser; 33605 this.name = EXTENSIONS.KHR_TEXTURE_BASISU; 33606 } 33607 } 33608 /** 33609 * WebP Texture Extension 33610 * 33611 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_texture_webp 33612 */ class GLTFTextureWebPExtension { 33613 loadTexture(textureIndex) { 33614 const name = this.name; 33615 const parser = this.parser; 33616 const json = parser.json; 33617 const textureDef = json.textures[textureIndex]; 33618 if (!textureDef.extensions || !textureDef.extensions[name]) { 33619 return null; 33620 } 33621 const extension = textureDef.extensions[name]; 33622 const source = json.images[extension.source]; 33623 let loader = parser.textureLoader; 33624 if (source.uri) { 33625 const handler = parser.options.manager.getHandler(source.uri); 33626 if (handler !== null) loader = handler; 33627 } 33628 return this.detectSupport().then(function(isSupported) { 33629 if (isSupported) return parser.loadTextureImage(textureIndex, extension.source, loader); 33630 if (json.extensionsRequired && json.extensionsRequired.indexOf(name) >= 0) { 33631 throw new Error('THREE.GLTFLoader: WebP required by asset but unsupported.'); 33632 } 33633 // Fall back to PNG or JPEG. 33634 return parser.loadTexture(textureIndex); 33635 }); 33636 } 33637 detectSupport() { 33638 if (!this.isSupported) { 33639 this.isSupported = new Promise(function(resolve) { 33640 const image = new Image(); 33641 // Lossy test image. Support for lossy images doesn't guarantee support for all 33642 // WebP images, unfortunately. 33643 image.src = 'data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA'; 33644 image.onload = image.onerror = function() { 33645 resolve(image.height === 1); 33646 }; 33647 }); 33648 } 33649 return this.isSupported; 33650 } 33651 constructor(parser){ 33652 this.parser = parser; 33653 this.name = EXTENSIONS.EXT_TEXTURE_WEBP; 33654 this.isSupported = null; 33655 } 33656 } 33657 /** 33658 * AVIF Texture Extension 33659 * 33660 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_texture_avif 33661 */ class GLTFTextureAVIFExtension { 33662 loadTexture(textureIndex) { 33663 const name = this.name; 33664 const parser = this.parser; 33665 const json = parser.json; 33666 const textureDef = json.textures[textureIndex]; 33667 if (!textureDef.extensions || !textureDef.extensions[name]) { 33668 return null; 33669 } 33670 const extension = textureDef.extensions[name]; 33671 const source = json.images[extension.source]; 33672 let loader = parser.textureLoader; 33673 if (source.uri) { 33674 const handler = parser.options.manager.getHandler(source.uri); 33675 if (handler !== null) loader = handler; 33676 } 33677 return this.detectSupport().then(function(isSupported) { 33678 if (isSupported) return parser.loadTextureImage(textureIndex, extension.source, loader); 33679 if (json.extensionsRequired && json.extensionsRequired.indexOf(name) >= 0) { 33680 throw new Error('THREE.GLTFLoader: AVIF required by asset but unsupported.'); 33681 } 33682 // Fall back to PNG or JPEG. 33683 return parser.loadTexture(textureIndex); 33684 }); 33685 } 33686 detectSupport() { 33687 if (!this.isSupported) { 33688 this.isSupported = new Promise(function(resolve) { 33689 const image = new Image(); 33690 // Lossy test image. 33691 image.src = 'data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAABcAAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAEAAAABAAAAEHBpeGkAAAAAAwgICAAAAAxhdj
vendor: 4,621 bytes, lines 33691-33791
33691FDgQAMAAAAABNjb2xybmNseAACAAIABoAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAAB9tZGF0EgAKCBgABogQEDQgMgkQAAAAB8dSLfI='; 33692 image.onload = image.onerror = function() { 33693 resolve(image.height === 1); 33694 }; 33695 }); 33696 } 33697 return this.isSupported; 33698 } 33699 constructor(parser){ 33700 this.parser = parser; 33701 this.name = EXTENSIONS.EXT_TEXTURE_AVIF; 33702 this.isSupported = null; 33703 } 33704 } 33705 /** 33706 * meshopt BufferView Compression Extension 33707 * 33708 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_meshopt_compression 33709 */ class GLTFMeshoptCompression { 33710 loadBufferView(index) { 33711 const json = this.parser.json; 33712 const bufferView = json.bufferViews[index]; 33713 if (bufferView.extensions && bufferView.extensions[this.name]) { 33714 const extensionDef = bufferView.extensions[this.name]; 33715 const buffer = this.parser.getDependency('buffer', extensionDef.buffer); 33716 const decoder = this.parser.options.meshoptDecoder; 33717 if (!decoder || !decoder.supported) { 33718 if (json.extensionsRequired && json.extensionsRequired.indexOf(this.name) >= 0) { 33719 throw new Error('THREE.GLTFLoader: setMeshoptDecoder must be called before loading compressed files'); 33720 } else { 33721 // Assumes that the extension is optional and that fallback buffer data is present 33722 return null; 33723 } 33724 } 33725 return buffer.then(function(res) { 33726 const byteOffset = extensionDef.byteOffset || 0; 33727 const byteLength = extensionDef.byteLength || 0; 33728 const count = extensionDef.count; 33729 const stride = extensionDef.byteStride; 33730 const source = new Uint8Array(res, byteOffset, byteLength); 33731 if (decoder.decodeGltfBufferAsync) { 33732 return decoder.decodeGltfBufferAsync(count, stride, source, extensionDef.mode, extensionDef.filter).then(function(res) { 33733 return res.buffer; 33734 }); 33735 } else { 33736 // Support for MeshoptDecoder 0.18 or earlier, without decodeGltfBufferAsync 33737 return decoder.ready.then(function() { 33738 const result = new ArrayBuffer(count * stride); 33739 decoder.decodeGltfBuffer(new Uint8Array(result), count, stride, source, extensionDef.mode, extensionDef.filter); 33740 return result; 33741 }); 33742 } 33743 }); 33744 } else { 33745 return null; 33746 } 33747 } 33748 constructor(parser){ 33749 this.name = EXTENSIONS.EXT_MESHOPT_COMPRESSION; 33750 this.parser = parser; 33751 } 33752 } 33753 /** 33754 * GPU Instancing Extension 33755 * 33756 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_mesh_gpu_instancing 33757 * 33758 */ let GLTFMeshGpuInstancing$1 = class GLTFMeshGpuInstancing { 33759 createNodeMesh(nodeIndex) { 33760 const json = this.parser.json; 33761 const nodeDef = json.nodes[nodeIndex]; 33762 if (!nodeDef.extensions || !nodeDef.extensions[this.name] || nodeDef.mesh === undefined) { 33763 return null; 33764 } 33765 const meshDef = json.meshes[nodeDef.mesh]; 33766 // No Points or Lines + Instancing support yet 33767 for (const primitive of meshDef.primitives){ 33768 if (primitive.mode !== WEBGL_CONSTANTS$1.TRIANGLES && primitive.mode !== WEBGL_CONSTANTS$1.TRIANGLE_STRIP && primitive.mode !== WEBGL_CONSTANTS$1.TRIANGLE_FAN && primitive.mode !== undefined) { 33769 return null; 33770 } 33771 } 33772 const extensionDef = nodeDef.extensions[this.name]; 33773 const attributesDef = extensionDef.attributes; 33774 // @TODO: Can we support InstancedMesh + SkinnedMesh? 33775 const pending = []; 33776 const attributes = {}; 33777 for(const key in attributesDef){ 33778 pending.push(this.parser.getDependency('accessor', attributesDef[key]).then((accessor)=>{ 33779 attributes[key] = accessor; 33780 return attributes[key]; 33781 })); 33782 } 33783 if (pending.length < 1) { 33784 return null; 33785 } 33786 pending.push(this.parser.createNodeMesh(nodeIndex)); 33787 return Promise.all(pending).then((results)=>{ 33788 const nodeObject = results.pop(); 33789 const meshes = nodeObject.isGroup ? nodeObject.children : [ 33790 nodeObject 33791 ];
vendor: 13,399 bytes, lines 33792-34112
33792 const count = results[0].count; // All attribute counts should be same 33793 const instancedMeshes = []; 33794 for (const mesh of meshes){ 33795 // Temporal variables 33796 const m = new Matrix4(); 33797 const p = new Vector3(); 33798 const q = new Quaternion(); 33799 const s = new Vector3(1, 1, 1); 33800 const instancedMesh = new InstancedMesh(mesh.geometry, mesh.material, count); 33801 for(let i = 0; i < count; i++){ 33802 if (attributes.TRANSLATION) { 33803 p.fromBufferAttribute(attributes.TRANSLATION, i); 33804 } 33805 if (attributes.ROTATION) { 33806 q.fromBufferAttribute(attributes.ROTATION, i); 33807 } 33808 if (attributes.SCALE) { 33809 s.fromBufferAttribute(attributes.SCALE, i); 33810 } 33811 instancedMesh.setMatrixAt(i, m.compose(p, q, s)); 33812 } 33813 // Add instance attributes to the geometry, excluding TRS. 33814 for(const attributeName in attributes){ 33815 if (attributeName === '_COLOR_0') { 33816 const attr = attributes[attributeName]; 33817 instancedMesh.instanceColor = new InstancedBufferAttribute(attr.array, attr.itemSize, attr.normalized); 33818 } else if (attributeName !== 'TRANSLATION' && attributeName !== 'ROTATION' && attributeName !== 'SCALE') { 33819 mesh.geometry.setAttribute(attributeName, attributes[attributeName]); 33820 } 33821 } 33822 // Just in case 33823 Object3D.prototype.copy.call(instancedMesh, mesh); 33824 this.parser.assignFinalMaterial(instancedMesh); 33825 instancedMeshes.push(instancedMesh); 33826 } 33827 if (nodeObject.isGroup) { 33828 nodeObject.clear(); 33829 nodeObject.add(...instancedMeshes); 33830 return nodeObject; 33831 } 33832 return instancedMeshes[0]; 33833 }); 33834 } 33835 constructor(parser){ 33836 this.name = EXTENSIONS.EXT_MESH_GPU_INSTANCING; 33837 this.parser = parser; 33838 } 33839 }; 33840 /* BINARY EXTENSION */ const BINARY_EXTENSION_HEADER_MAGIC = 'glTF'; 33841 const BINARY_EXTENSION_HEADER_LENGTH = 12; 33842 const BINARY_EXTENSION_CHUNK_TYPES = { 33843 JSON: 0x4E4F534A, 33844 BIN: 0x004E4942 33845 }; 33846 class GLTFBinaryExtension { 33847 constructor(data){ 33848 this.name = EXTENSIONS.KHR_BINARY_GLTF; 33849 this.content = null; 33850 this.body = null; 33851 const headerView = new DataView(data, 0, BINARY_EXTENSION_HEADER_LENGTH); 33852 const textDecoder = new TextDecoder(); 33853 this.header = { 33854 magic: textDecoder.decode(new Uint8Array(data.slice(0, 4))), 33855 version: headerView.getUint32(4, true), 33856 length: headerView.getUint32(8, true) 33857 }; 33858 if (this.header.magic !== BINARY_EXTENSION_HEADER_MAGIC) { 33859 throw new Error('THREE.GLTFLoader: Unsupported glTF-Binary header.'); 33860 } else if (this.header.version < 2.0) { 33861 throw new Error('THREE.GLTFLoader: Legacy binary file detected.'); 33862 } 33863 const chunkContentsLength = this.header.length - BINARY_EXTENSION_HEADER_LENGTH; 33864 const chunkView = new DataView(data, BINARY_EXTENSION_HEADER_LENGTH); 33865 let chunkIndex = 0; 33866 while(chunkIndex < chunkContentsLength){ 33867 const chunkLength = chunkView.getUint32(chunkIndex, true); 33868 chunkIndex += 4; 33869 const chunkType = chunkView.getUint32(chunkIndex, true); 33870 chunkIndex += 4; 33871 if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON) { 33872 const contentArray = new Uint8Array(data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength); 33873 this.content = textDecoder.decode(contentArray); 33874 } else if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN) { 33875 const byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex; 33876 this.body = data.slice(byteOffset, byteOffset + chunkLength); 33877 } 33878 // Clients must ignore chunks with unknown types. 33879 chunkIndex += chunkLength; 33880 } 33881 if (this.content === null) { 33882 throw new Error('THREE.GLTFLoader: JSON content not found.'); 33883 } 33884 } 33885 } 33886 /** 33887 * DRACO Mesh Compression Extension 33888 * 33889 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression 33890 */ class GLTFDracoMeshCompressionExtension { 33891 decodePrimitive(primitive, parser) { 33892 const json = this.json; 33893 const dracoLoader = this.dracoLoader; 33894 const bufferViewIndex = primitive.extensions[this.name].bufferView; 33895 const gltfAttributeMap = primitive.extensions[this.name].attributes; 33896 const threeAttributeMap = {}; 33897 const attributeNormalizedMap = {}; 33898 const attributeTypeMap = {}; 33899 for(const attributeName in gltfAttributeMap){ 33900 const threeAttributeName = ATTRIBUTES[attributeName] || attributeName.toLowerCase(); 33901 threeAttributeMap[threeAttributeName] = gltfAttributeMap[attributeName]; 33902 } 33903 for(const attributeName in primitive.attributes){ 33904 const threeAttributeName = ATTRIBUTES[attributeName] || attributeName.toLowerCase(); 33905 if (gltfAttributeMap[attributeName] !== undefined) { 33906 const accessorDef = json.accessors[primitive.attributes[attributeName]]; 33907 const componentType = WEBGL_COMPONENT_TYPES[accessorDef.componentType]; 33908 attributeTypeMap[threeAttributeName] = componentType.name; 33909 attributeNormalizedMap[threeAttributeName] = accessorDef.normalized === true; 33910 } 33911 } 33912 return parser.getDependency('bufferView', bufferViewIndex).then(function(bufferView) { 33913 return new Promise(function(resolve, reject) { 33914 dracoLoader.decodeDracoFile(bufferView, function(geometry) { 33915 for(const attributeName in geometry.attributes){ 33916 const attribute = geometry.attributes[attributeName]; 33917 const normalized = attributeNormalizedMap[attributeName]; 33918 if (normalized !== undefined) attribute.normalized = normalized; 33919 } 33920 resolve(geometry); 33921 }, threeAttributeMap, attributeTypeMap, LinearSRGBColorSpace, reject); 33922 }); 33923 }); 33924 } 33925 constructor(json, dracoLoader){ 33926 if (!dracoLoader) { 33927 throw new Error('THREE.GLTFLoader: No DRACOLoader instance provided.'); 33928 } 33929 this.name = EXTENSIONS.KHR_DRACO_MESH_COMPRESSION; 33930 this.json = json; 33931 this.dracoLoader = dracoLoader; 33932 this.dracoLoader.preload(); 33933 } 33934 } 33935 /** 33936 * Texture Transform Extension 33937 * 33938 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_texture_transform 33939 */ class GLTFTextureTransformExtension { 33940 extendTexture(texture, transform) { 33941 if ((transform.texCoord === undefined || transform.texCoord === texture.channel) && transform.offset === undefined && transform.rotation === undefined && transform.scale === undefined) { 33942 // See https://github.com/mrdoob/three.js/issues/21819. 33943 return texture; 33944 } 33945 texture = texture.clone(); 33946 if (transform.texCoord !== undefined) { 33947 texture.channel = transform.texCoord; 33948 } 33949 if (transform.offset !== undefined) { 33950 texture.offset.fromArray(transform.offset); 33951 } 33952 if (transform.rotation !== undefined) { 33953 texture.rotation = transform.rotation; 33954 } 33955 if (transform.scale !== undefined) { 33956 texture.repeat.fromArray(transform.scale); 33957 } 33958 texture.needsUpdate = true; 33959 return texture; 33960 } 33961 constructor(){ 33962 this.name = EXTENSIONS.KHR_TEXTURE_TRANSFORM; 33963 } 33964 } 33965 /** 33966 * Mesh Quantization Extension 33967 * 33968 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization 33969 */ class GLTFMeshQuantizationExtension { 33970 constructor(){ 33971 this.name = EXTENSIONS.KHR_MESH_QUANTIZATION; 33972 } 33973 } 33974 /*********************************/ /********** INTERPOLATION ********/ /*********************************/ // Spline Interpolation 33975 // Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#appendix-c-spline-interpolation 33976 class GLTFCubicSplineInterpolant extends Interpolant { 33977 copySampleValue_(index) { 33978 // Copies a sample value to the result buffer. See description of glTF 33979 // CUBICSPLINE values layout in interpolate_() function below. 33980 const result = this.resultBuffer, values = this.sampleValues, valueSize = this.valueSize, offset = index * valueSize * 3 + valueSize; 33981 for(let i = 0; i !== valueSize; i++){ 33982 result[i] = values[offset + i]; 33983 } 33984 return result; 33985 } 33986 interpolate_(i1, t0, t, t1) { 33987 const result = this.resultBuffer; 33988 const values = this.sampleValues; 33989 const stride = this.valueSize; 33990 const stride2 = stride * 2; 33991 const stride3 = stride * 3; 33992 const td = t1 - t0; 33993 const p = (t - t0) / td; 33994 const pp = p * p; 33995 const ppp = pp * p; 33996 const offset1 = i1 * stride3; 33997 const offset0 = offset1 - stride3; 33998 const s2 = -2 * ppp + 3 * pp; 33999 const s3 = ppp - pp; 34000 const s0 = 1 - s2; 34001 const s1 = s3 - pp + p; 34002 // Layout of keyframe output values for CUBICSPLINE animations: 34003 // [ inTangent_1, splineVertex_1, outTangent_1, inTangent_2, splineVertex_2, ... ] 34004 for(let i = 0; i !== stride; i++){ 34005 const p0 = values[offset0 + i + stride]; // splineVertex_k 34006 const m0 = values[offset0 + i + stride2] * td; // outTangent_k * (t_k+1 - t_k) 34007 const p1 = values[offset1 + i + stride]; // splineVertex_k+1 34008 const m1 = values[offset1 + i] * td; // inTangent_k+1 * (t_k+1 - t_k) 34009 result[i] = s0 * p0 + s1 * m0 + s2 * p1 + s3 * m1; 34010 } 34011 return result; 34012 } 34013 constructor(parameterPositions, sampleValues, sampleSize, resultBuffer){ 34014 super(parameterPositions, sampleValues, sampleSize, resultBuffer); 34015 } 34016 } 34017 const _q = new Quaternion(); 34018 class GLTFCubicSplineQuaternionInterpolant extends GLTFCubicSplineInterpolant { 34019 interpolate_(i1, t0, t, t1) { 34020 const result = super.interpolate_(i1, t0, t, t1); 34021 _q.fromArray(result).normalize().toArray(result); 34022 return result; 34023 } 34024 } 34025 /*********************************/ /********** INTERNALS ************/ /*********************************/ /* CONSTANTS */ const WEBGL_CONSTANTS$1 = { 34026 POINTS: 0, 34027 LINES: 1, 34028 LINE_LOOP: 2, 34029 LINE_STRIP: 3, 34030 TRIANGLES: 4, 34031 TRIANGLE_STRIP: 5, 34032 TRIANGLE_FAN: 6}; 34033 const WEBGL_COMPONENT_TYPES = { 34034 5120: Int8Array, 34035 5121: Uint8Array, 34036 5122: Int16Array, 34037 5123: Uint16Array, 34038 5125: Uint32Array, 34039 5126: Float32Array 34040 }; 34041 const WEBGL_FILTERS = { 34042 9728: NearestFilter, 34043 9729: LinearFilter, 34044 9984: NearestMipmapNearestFilter, 34045 9985: LinearMipmapNearestFilter, 34046 9986: NearestMipmapLinearFilter, 34047 9987: LinearMipmapLinearFilter 34048 }; 34049 const WEBGL_WRAPPINGS = { 34050 33071: ClampToEdgeWrapping, 34051 33648: MirroredRepeatWrapping, 34052 10497: RepeatWrapping 34053 }; 34054 const WEBGL_TYPE_SIZES = { 34055 'SCALAR': 1, 34056 'VEC2': 2, 34057 'VEC3': 3, 34058 'VEC4': 4, 34059 'MAT2': 4, 34060 'MAT3': 9, 34061 'MAT4': 16 34062 }; 34063 const ATTRIBUTES = { 34064 POSITION: 'position', 34065 NORMAL: 'normal', 34066 TANGENT: 'tangent', 34067 TEXCOORD_0: 'uv', 34068 TEXCOORD_1: 'uv1', 34069 TEXCOORD_2: 'uv2', 34070 TEXCOORD_3: 'uv3', 34071 COLOR_0: 'color', 34072 WEIGHTS_0: 'skinWeight', 34073 JOINTS_0: 'skinIndex' 34074 }; 34075 const PATH_PROPERTIES$1 = { 34076 scale: 'scale', 34077 translation: 'position', 34078 rotation: 'quaternion', 34079 weights: 'morphTargetInfluences' 34080 }; 34081 const INTERPOLATION = { 34082 CUBICSPLINE: undefined, 34083 // keyframe track will be initialized with a default interpolation type, then modified. 34084 LINEAR: InterpolateLinear, 34085 STEP: InterpolateDiscrete 34086 }; 34087 const ALPHA_MODES = { 34088 OPAQUE: 'OPAQUE', 34089 MASK: 'MASK', 34090 BLEND: 'BLEND' 34091 }; 34092 /** 34093 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#default-material 34094 * 34095 * @param {Object<string, Material>} cache 34096 * @return {Material} 34097 */ function createDefaultMaterial(cache) { 34098 if (cache['DefaultMaterial'] === undefined) { 34099 cache['DefaultMaterial'] = new MeshStandardMaterial({ 34100 color: 0xFFFFFF, 34101 emissive: 0x000000, 34102 metalness: 1, 34103 roughness: 1, 34104 transparent: false, 34105 depthTest: true, 34106 side: FrontSide 34107 }); 34108 } 34109 return cache['DefaultMaterial']; 34110 } 34111 function addUnknownExtensionsToUserData(knownExtensions, object, objectDef) { 34112 // Add unknown glTF extensions to an object's userData.
vendor: 5,010 bytes, lines 34113-34223
34113 for(const name in objectDef.extensions){ 34114 if (knownExtensions[name] === undefined) { 34115 object.userData.gltfExtensions = object.userData.gltfExtensions || {}; 34116 object.userData.gltfExtensions[name] = objectDef.extensions[name]; 34117 } 34118 } 34119 } 34120 /** 34121 * @param {Object3D|Material|BufferGeometry} object 34122 * @param {GLTF.definition} gltfDef 34123 */ function assignExtrasToUserData(object, gltfDef) { 34124 if (gltfDef.extras !== undefined) { 34125 if (typeof gltfDef.extras === 'object') { 34126 Object.assign(object.userData, gltfDef.extras); 34127 } else { 34128 console.warn('THREE.GLTFLoader: Ignoring primitive type .extras, ' + gltfDef.extras); 34129 } 34130 } 34131 } 34132 /** 34133 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets 34134 * 34135 * @param {BufferGeometry} geometry 34136 * @param {Array<GLTF.Target>} targets 34137 * @param {GLTFParser} parser 34138 * @return {Promise<BufferGeometry>} 34139 */ function addMorphTargets(geometry, targets, parser) { 34140 let hasMorphPosition = false; 34141 let hasMorphNormal = false; 34142 let hasMorphColor = false; 34143 for(let i = 0, il = targets.length; i < il; i++){ 34144 const target = targets[i]; 34145 if (target.POSITION !== undefined) hasMorphPosition = true; 34146 if (target.NORMAL !== undefined) hasMorphNormal = true; 34147 if (target.COLOR_0 !== undefined) hasMorphColor = true; 34148 if (hasMorphPosition && hasMorphNormal && hasMorphColor) break; 34149 } 34150 if (!hasMorphPosition && !hasMorphNormal && !hasMorphColor) return Promise.resolve(geometry); 34151 const pendingPositionAccessors = []; 34152 const pendingNormalAccessors = []; 34153 const pendingColorAccessors = []; 34154 for(let i = 0, il = targets.length; i < il; i++){ 34155 const target = targets[i]; 34156 if (hasMorphPosition) { 34157 const pendingAccessor = target.POSITION !== undefined ? parser.getDependency('accessor', target.POSITION) : geometry.attributes.position; 34158 pendingPositionAccessors.push(pendingAccessor); 34159 } 34160 if (hasMorphNormal) { 34161 const pendingAccessor = target.NORMAL !== undefined ? parser.getDependency('accessor', target.NORMAL) : geometry.attributes.normal; 34162 pendingNormalAccessors.push(pendingAccessor); 34163 } 34164 if (hasMorphColor) { 34165 const pendingAccessor = target.COLOR_0 !== undefined ? parser.getDependency('accessor', target.COLOR_0) : geometry.attributes.color; 34166 pendingColorAccessors.push(pendingAccessor); 34167 } 34168 } 34169 return Promise.all([ 34170 Promise.all(pendingPositionAccessors), 34171 Promise.all(pendingNormalAccessors), 34172 Promise.all(pendingColorAccessors) 34173 ]).then(function(accessors) { 34174 const morphPositions = accessors[0]; 34175 const morphNormals = accessors[1]; 34176 const morphColors = accessors[2]; 34177 if (hasMorphPosition) geometry.morphAttributes.position = morphPositions; 34178 if (hasMorphNormal) geometry.morphAttributes.normal = morphNormals; 34179 if (hasMorphColor) geometry.morphAttributes.color = morphColors; 34180 geometry.morphTargetsRelative = true; 34181 return geometry; 34182 }); 34183 } 34184 /** 34185 * @param {Mesh} mesh 34186 * @param {GLTF.Mesh} meshDef 34187 */ function updateMorphTargets(mesh, meshDef) { 34188 mesh.updateMorphTargets(); 34189 if (meshDef.weights !== undefined) { 34190 for(let i = 0, il = meshDef.weights.length; i < il; i++){ 34191 mesh.morphTargetInfluences[i] = meshDef.weights[i]; 34192 } 34193 } 34194 // .extras has user-defined data, so check that .extras.targetNames is an array. 34195 if (meshDef.extras && Array.isArray(meshDef.extras.targetNames)) { 34196 const targetNames = meshDef.extras.targetNames; 34197 if (mesh.morphTargetInfluences.length === targetNames.length) { 34198 mesh.morphTargetDictionary = {}; 34199 for(let i = 0, il = targetNames.length; i < il; i++){ 34200 mesh.morphTargetDictionary[targetNames[i]] = i; 34201 } 34202 } else { 34203 console.warn('THREE.GLTFLoader: Invalid extras.targetNames length. Ignoring names.'); 34204 } 34205 } 34206 } 34207 function createPrimitiveKey(primitiveDef) { 34208 let geometryKey; 34209 const dracoExtension = primitiveDef.extensions && primitiveDef.extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION]; 34210 if (dracoExtension) { 34211 geometryKey = 'draco:' + dracoExtension.bufferView + ':' + dracoExtension.indices + ':' + createAttributesKey(dracoExtension.attributes); 34212 } else { 34213 geometryKey = primitiveDef.indices + ':' + createAttributesKey(primitiveDef.attributes) + ':' + primitiveDef.mode; 34214 } 34215 if (primitiveDef.targets !== undefined) { 34216 for(let i = 0, il = primitiveDef.targets.length; i < il; i++){ 34217 geometryKey += ':' + createAttributesKey(primitiveDef.targets[i]); 34218 } 34219 } 34220 return geometryKey; 34221 } 34222 function createAttributesKey(attributes) { 34223 let attributesKey = '';
vendor: 15,606 bytes, lines 34224-34565
34224 const keys = Object.keys(attributes).sort(); 34225 for(let i = 0, il = keys.length; i < il; i++){ 34226 attributesKey += keys[i] + ':' + attributes[keys[i]] + ';'; 34227 } 34228 return attributesKey; 34229 } 34230 function getNormalizedComponentScale(constructor) { 34231 // Reference: 34232 // https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization#encoding-quantized-data 34233 switch(constructor){ 34234 case Int8Array: 34235 return 1 / 127; 34236 case Uint8Array: 34237 return 1 / 255; 34238 case Int16Array: 34239 return 1 / 32767; 34240 case Uint16Array: 34241 return 1 / 65535; 34242 default: 34243 throw new Error('THREE.GLTFLoader: Unsupported normalized accessor component type.'); 34244 } 34245 } 34246 function getImageURIMimeType(uri) { 34247 if (uri.search(/\.jpe?g($|\?)/i) > 0 || uri.search(/^data\:image\/jpeg/) === 0) return 'image/jpeg'; 34248 if (uri.search(/\.webp($|\?)/i) > 0 || uri.search(/^data\:image\/webp/) === 0) return 'image/webp'; 34249 if (uri.search(/\.ktx2($|\?)/i) > 0 || uri.search(/^data\:image\/ktx2/) === 0) return 'image/ktx2'; 34250 return 'image/png'; 34251 } 34252 const _identityMatrix = new Matrix4(); 34253 /* GLTF PARSER */ class GLTFParser { 34254 setExtensions(extensions) { 34255 this.extensions = extensions; 34256 } 34257 setPlugins(plugins) { 34258 this.plugins = plugins; 34259 } 34260 parse(onLoad, onError) { 34261 const parser = this; 34262 const json = this.json; 34263 const extensions = this.extensions; 34264 // Clear the loader cache 34265 this.cache.removeAll(); 34266 this.nodeCache = {}; 34267 // Mark the special nodes/meshes in json for efficient parse 34268 this._invokeAll(function(ext) { 34269 return ext._markDefs && ext._markDefs(); 34270 }); 34271 Promise.all(this._invokeAll(function(ext) { 34272 return ext.beforeRoot && ext.beforeRoot(); 34273 })).then(function() { 34274 return Promise.all([ 34275 parser.getDependencies('scene'), 34276 parser.getDependencies('animation'), 34277 parser.getDependencies('camera') 34278 ]); 34279 }).then(function(dependencies) { 34280 const result = { 34281 scene: dependencies[0][json.scene || 0], 34282 scenes: dependencies[0], 34283 animations: dependencies[1], 34284 cameras: dependencies[2], 34285 asset: json.asset, 34286 parser: parser, 34287 userData: {} 34288 }; 34289 addUnknownExtensionsToUserData(extensions, result, json); 34290 assignExtrasToUserData(result, json); 34291 return Promise.all(parser._invokeAll(function(ext) { 34292 return ext.afterRoot && ext.afterRoot(result); 34293 })).then(function() { 34294 for (const scene of result.scenes){ 34295 scene.updateMatrixWorld(); 34296 } 34297 onLoad(result); 34298 }); 34299 }).catch(onError); 34300 } 34301 /** 34302 * Marks the special nodes/meshes in json for efficient parse. 34303 */ _markDefs() { 34304 const nodeDefs = this.json.nodes || []; 34305 const skinDefs = this.json.skins || []; 34306 const meshDefs = this.json.meshes || []; 34307 // Nothing in the node definition indicates whether it is a Bone or an 34308 // Object3D. Use the skins' joint references to mark bones. 34309 for(let skinIndex = 0, skinLength = skinDefs.length; skinIndex < skinLength; skinIndex++){ 34310 const joints = skinDefs[skinIndex].joints; 34311 for(let i = 0, il = joints.length; i < il; i++){ 34312 nodeDefs[joints[i]].isBone = true; 34313 } 34314 } 34315 // Iterate over all nodes, marking references to shared resources, 34316 // as well as skeleton joints. 34317 for(let nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex++){ 34318 const nodeDef = nodeDefs[nodeIndex]; 34319 if (nodeDef.mesh !== undefined) { 34320 this._addNodeRef(this.meshCache, nodeDef.mesh); 34321 // Nothing in the mesh definition indicates whether it is 34322 // a SkinnedMesh or Mesh. Use the node's mesh reference 34323 // to mark SkinnedMesh if node has skin. 34324 if (nodeDef.skin !== undefined) { 34325 meshDefs[nodeDef.mesh].isSkinnedMesh = true; 34326 } 34327 } 34328 if (nodeDef.camera !== undefined) { 34329 this._addNodeRef(this.cameraCache, nodeDef.camera); 34330 } 34331 } 34332 } 34333 /** 34334 * Counts references to shared node / Object3D resources. These resources 34335 * can be reused, or "instantiated", at multiple nodes in the scene 34336 * hierarchy. Mesh, Camera, and Light instances are instantiated and must 34337 * be marked. Non-scenegraph resources (like Materials, Geometries, and 34338 * Textures) can be reused directly and are not marked here. 34339 * 34340 * Example: CesiumMilkTruck sample model reuses "Wheel" meshes. 34341 * 34342 * @param {Object} cache 34343 * @param {Object3D} index 34344 */ _addNodeRef(cache, index) { 34345 if (index === undefined) return; 34346 if (cache.refs[index] === undefined) { 34347 cache.refs[index] = cache.uses[index] = 0; 34348 } 34349 cache.refs[index]++; 34350 } 34351 /** 34352 * Returns a reference to a shared resource, cloning it if necessary. 34353 * 34354 * @param {Object} cache 34355 * @param {number} index 34356 * @param {Object} object 34357 * @return {Object} 34358 */ _getNodeRef(cache, index, object) { 34359 if (cache.refs[index] <= 1) return object; 34360 const ref = object.clone(); 34361 // Propagates mappings to the cloned object, prevents mappings on the 34362 // original object from being lost. 34363 const updateMappings = (original, clone)=>{ 34364 const mappings = this.associations.get(original); 34365 if (mappings != null) { 34366 this.associations.set(clone, mappings); 34367 } 34368 for (const [i, child] of original.children.entries()){ 34369 updateMappings(child, clone.children[i]); 34370 } 34371 }; 34372 updateMappings(object, ref); 34373 ref.name += '_instance_' + cache.uses[index]++; 34374 return ref; 34375 } 34376 _invokeOne(func) { 34377 const extensions = Object.values(this.plugins); 34378 extensions.push(this); 34379 for(let i = 0; i < extensions.length; i++){ 34380 const result = func(extensions[i]); 34381 if (result) return result; 34382 } 34383 return null; 34384 } 34385 _invokeAll(func) { 34386 const extensions = Object.values(this.plugins); 34387 extensions.unshift(this); 34388 const pending = []; 34389 for(let i = 0; i < extensions.length; i++){ 34390 const result = func(extensions[i]); 34391 if (result) pending.push(result); 34392 } 34393 return pending; 34394 } 34395 /** 34396 * Requests the specified dependency asynchronously, with caching. 34397 * @param {string} type 34398 * @param {number} index 34399 * @return {Promise<Object3D|Material|THREE.Texture|AnimationClip|ArrayBuffer|Object>} 34400 */ getDependency(type, index) { 34401 const cacheKey = type + ':' + index; 34402 let dependency = this.cache.get(cacheKey); 34403 if (!dependency) { 34404 switch(type){ 34405 case 'scene': 34406 dependency = this.loadScene(index); 34407 break; 34408 case 'node': 34409 dependency = this._invokeOne(function(ext) { 34410 return ext.loadNode && ext.loadNode(index); 34411 }); 34412 break; 34413 case 'mesh': 34414 dependency = this._invokeOne(function(ext) { 34415 return ext.loadMesh && ext.loadMesh(index); 34416 }); 34417 break; 34418 case 'accessor': 34419 dependency = this.loadAccessor(index); 34420 break; 34421 case 'bufferView': 34422 dependency = this._invokeOne(function(ext) { 34423 return ext.loadBufferView && ext.loadBufferView(index); 34424 }); 34425 break; 34426 case 'buffer': 34427 dependency = this.loadBuffer(index); 34428 break; 34429 case 'material': 34430 dependency = this._invokeOne(function(ext) { 34431 return ext.loadMaterial && ext.loadMaterial(index); 34432 }); 34433 break; 34434 case 'texture': 34435 dependency = this._invokeOne(function(ext) { 34436 return ext.loadTexture && ext.loadTexture(index); 34437 }); 34438 break; 34439 case 'skin': 34440 dependency = this.loadSkin(index); 34441 break; 34442 case 'animation': 34443 dependency = this._invokeOne(function(ext) { 34444 return ext.loadAnimation && ext.loadAnimation(index); 34445 }); 34446 break; 34447 case 'camera': 34448 dependency = this.loadCamera(index); 34449 break; 34450 default: 34451 dependency = this._invokeOne(function(ext) { 34452 return ext != this && ext.getDependency && ext.getDependency(type, index); 34453 }); 34454 if (!dependency) { 34455 throw new Error('Unknown type: ' + type); 34456 } 34457 break; 34458 } 34459 this.cache.add(cacheKey, dependency); 34460 } 34461 return dependency; 34462 } 34463 /** 34464 * Requests all dependencies of the specified type asynchronously, with caching. 34465 * @param {string} type 34466 * @return {Promise<Array<Object>>} 34467 */ getDependencies(type) { 34468 let dependencies = this.cache.get(type); 34469 if (!dependencies) { 34470 const parser = this; 34471 const defs = this.json[type + (type === 'mesh' ? 'es' : 's')] || []; 34472 dependencies = Promise.all(defs.map(function(def, index) { 34473 return parser.getDependency(type, index); 34474 })); 34475 this.cache.add(type, dependencies); 34476 } 34477 return dependencies; 34478 } 34479 /** 34480 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views 34481 * @param {number} bufferIndex 34482 * @return {Promise<ArrayBuffer>} 34483 */ loadBuffer(bufferIndex) { 34484 const bufferDef = this.json.buffers[bufferIndex]; 34485 const loader = this.fileLoader; 34486 if (bufferDef.type && bufferDef.type !== 'arraybuffer') { 34487 throw new Error('THREE.GLTFLoader: ' + bufferDef.type + ' buffer type is not supported.'); 34488 } 34489 // If present, GLB container is required to be the first buffer. 34490 if (bufferDef.uri === undefined && bufferIndex === 0) { 34491 return Promise.resolve(this.extensions[EXTENSIONS.KHR_BINARY_GLTF].body); 34492 } 34493 const options = this.options; 34494 return new Promise(function(resolve, reject) { 34495 loader.load(LoaderUtils.resolveURL(bufferDef.uri, options.path), resolve, undefined, function() { 34496 reject(new Error('THREE.GLTFLoader: Failed to load buffer "' + bufferDef.uri + '".')); 34497 }); 34498 }); 34499 } 34500 /** 34501 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views 34502 * @param {number} bufferViewIndex 34503 * @return {Promise<ArrayBuffer>} 34504 */ loadBufferView(bufferViewIndex) { 34505 const bufferViewDef = this.json.bufferViews[bufferViewIndex]; 34506 return this.getDependency('buffer', bufferViewDef.buffer).then(function(buffer) { 34507 const byteLength = bufferViewDef.byteLength || 0; 34508 const byteOffset = bufferViewDef.byteOffset || 0; 34509 return buffer.slice(byteOffset, byteOffset + byteLength); 34510 }); 34511 } 34512 /** 34513 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#accessors 34514 * @param {number} accessorIndex 34515 * @return {Promise<BufferAttribute|InterleavedBufferAttribute>} 34516 */ loadAccessor(accessorIndex) { 34517 const parser = this; 34518 const json = this.json; 34519 const accessorDef = this.json.accessors[accessorIndex]; 34520 if (accessorDef.bufferView === undefined && accessorDef.sparse === undefined) { 34521 const itemSize = WEBGL_TYPE_SIZES[accessorDef.type]; 34522 const TypedArray = WEBGL_COMPONENT_TYPES[accessorDef.componentType]; 34523 const normalized = accessorDef.normalized === true; 34524 const array = new TypedArray(accessorDef.count * itemSize); 34525 return Promise.resolve(new BufferAttribute(array, itemSize, normalized)); 34526 } 34527 const pendingBufferViews = []; 34528 if (accessorDef.bufferView !== undefined) { 34529 pendingBufferViews.push(this.getDependency('bufferView', accessorDef.bufferView)); 34530 } else { 34531 pendingBufferViews.push(null); 34532 } 34533 if (accessorDef.sparse !== undefined) { 34534 pendingBufferViews.push(this.getDependency('bufferView', accessorDef.sparse.indices.bufferView)); 34535 pendingBufferViews.push(this.getDependency('bufferView', accessorDef.sparse.values.bufferView)); 34536 } 34537 return Promise.all(pendingBufferViews).then(function(bufferViews) { 34538 const bufferView = bufferViews[0]; 34539 const itemSize = WEBGL_TYPE_SIZES[accessorDef.type]; 34540 const TypedArray = WEBGL_COMPONENT_TYPES[accessorDef.componentType]; 34541 // For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12. 34542 const elementBytes = TypedArray.BYTES_PER_ELEMENT; 34543 const itemBytes = elementBytes * itemSize; 34544 const byteOffset = accessorDef.byteOffset || 0; 34545 const byteStride = accessorDef.bufferView !== undefined ? json.bufferViews[accessorDef.bufferView].byteStride : undefined; 34546 const normalized = accessorDef.normalized === true; 34547 let array, bufferAttribute; 34548 // The buffer is not interleaved if the stride is the item size in bytes. 34549 if (byteStride && byteStride !== itemBytes) { 34550 // Each "slice" of the buffer, as defined by 'count' elements of 'byteStride' bytes, gets its own InterleavedBuffer 34551 // This makes sure that IBA.count reflects accessor.count properly 34552 const ibSlice = Math.floor(byteOffset / byteStride); 34553 const ibCacheKey = 'InterleavedBuffer:' + accessorDef.bufferView + ':' + accessorDef.componentType + ':' + ibSlice + ':' + accessorDef.count; 34554 let ib = parser.cache.get(ibCacheKey); 34555 if (!ib) { 34556 array = new TypedArray(bufferView, ibSlice * byteStride, accessorDef.count * byteStride / elementBytes); 34557 // Integer parameters to IB/IBA are in array elements, not bytes. 34558 ib = new InterleavedBuffer(array, byteStride / elementBytes); 34559 parser.cache.add(ibCacheKey, ib); 34560 } 34561 bufferAttribute = new InterleavedBufferAttribute(ib, itemSize, byteOffset % byteStride / elementBytes, normalized); 34562 } else { 34563 if (bufferView === null) { 34564 array = new TypedArray(accessorDef.count * itemSize); 34565 } else {
vendor: 12,524 bytes, lines 34566-34807
34566 array = new TypedArray(bufferView, byteOffset, accessorDef.count * itemSize); 34567 } 34568 bufferAttribute = new BufferAttribute(array, itemSize, normalized); 34569 } 34570 // https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#sparse-accessors 34571 if (accessorDef.sparse !== undefined) { 34572 const itemSizeIndices = WEBGL_TYPE_SIZES.SCALAR; 34573 const TypedArrayIndices = WEBGL_COMPONENT_TYPES[accessorDef.sparse.indices.componentType]; 34574 const byteOffsetIndices = accessorDef.sparse.indices.byteOffset || 0; 34575 const byteOffsetValues = accessorDef.sparse.values.byteOffset || 0; 34576 const sparseIndices = new TypedArrayIndices(bufferViews[1], byteOffsetIndices, accessorDef.sparse.count * itemSizeIndices); 34577 const sparseValues = new TypedArray(bufferViews[2], byteOffsetValues, accessorDef.sparse.count * itemSize); 34578 if (bufferView !== null) { 34579 // Avoid modifying the original ArrayBuffer, if the bufferView wasn't initialized with zeroes. 34580 bufferAttribute = new BufferAttribute(bufferAttribute.array.slice(), bufferAttribute.itemSize, bufferAttribute.normalized); 34581 } 34582 // Ignore normalized since we copy from sparse 34583 bufferAttribute.normalized = false; 34584 for(let i = 0, il = sparseIndices.length; i < il; i++){ 34585 const index = sparseIndices[i]; 34586 bufferAttribute.setX(index, sparseValues[i * itemSize]); 34587 if (itemSize >= 2) bufferAttribute.setY(index, sparseValues[i * itemSize + 1]); 34588 if (itemSize >= 3) bufferAttribute.setZ(index, sparseValues[i * itemSize + 2]); 34589 if (itemSize >= 4) bufferAttribute.setW(index, sparseValues[i * itemSize + 3]); 34590 if (itemSize >= 5) throw new Error('THREE.GLTFLoader: Unsupported itemSize in sparse BufferAttribute.'); 34591 } 34592 bufferAttribute.normalized = normalized; 34593 } 34594 return bufferAttribute; 34595 }); 34596 } 34597 /** 34598 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#textures 34599 * @param {number} textureIndex 34600 * @return {Promise<THREE.Texture|null>} 34601 */ loadTexture(textureIndex) { 34602 const json = this.json; 34603 const options = this.options; 34604 const textureDef = json.textures[textureIndex]; 34605 const sourceIndex = textureDef.source; 34606 const sourceDef = json.images[sourceIndex]; 34607 let loader = this.textureLoader; 34608 if (sourceDef.uri) { 34609 const handler = options.manager.getHandler(sourceDef.uri); 34610 if (handler !== null) loader = handler; 34611 } 34612 return this.loadTextureImage(textureIndex, sourceIndex, loader); 34613 } 34614 loadTextureImage(textureIndex, sourceIndex, loader) { 34615 const parser = this; 34616 const json = this.json; 34617 const textureDef = json.textures[textureIndex]; 34618 const sourceDef = json.images[sourceIndex]; 34619 const cacheKey = (sourceDef.uri || sourceDef.bufferView) + ':' + textureDef.sampler; 34620 if (this.textureCache[cacheKey]) { 34621 // See https://github.com/mrdoob/three.js/issues/21559. 34622 return this.textureCache[cacheKey]; 34623 } 34624 const promise = this.loadImageSource(sourceIndex, loader).then(function(texture) { 34625 texture.flipY = false; 34626 texture.name = textureDef.name || sourceDef.name || ''; 34627 if (texture.name === '' && typeof sourceDef.uri === 'string' && sourceDef.uri.startsWith('data:image/') === false) { 34628 texture.name = sourceDef.uri; 34629 } 34630 const samplers = json.samplers || {}; 34631 const sampler = samplers[textureDef.sampler] || {}; 34632 texture.magFilter = WEBGL_FILTERS[sampler.magFilter] || LinearFilter; 34633 texture.minFilter = WEBGL_FILTERS[sampler.minFilter] || LinearMipmapLinearFilter; 34634 texture.wrapS = WEBGL_WRAPPINGS[sampler.wrapS] || RepeatWrapping; 34635 texture.wrapT = WEBGL_WRAPPINGS[sampler.wrapT] || RepeatWrapping; 34636 texture.generateMipmaps = !texture.isCompressedTexture && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter; 34637 parser.associations.set(texture, { 34638 textures: textureIndex 34639 }); 34640 return texture; 34641 }).catch(function() { 34642 return null; 34643 }); 34644 this.textureCache[cacheKey] = promise; 34645 return promise; 34646 } 34647 loadImageSource(sourceIndex, loader) { 34648 const parser = this; 34649 const json = this.json; 34650 const options = this.options; 34651 if (this.sourceCache[sourceIndex] !== undefined) { 34652 return this.sourceCache[sourceIndex].then((texture)=>texture.clone()); 34653 } 34654 const sourceDef = json.images[sourceIndex]; 34655 const URL = self.URL || self.webkitURL; 34656 let sourceURI = sourceDef.uri || ''; 34657 let isObjectURL = false; 34658 if (sourceDef.bufferView !== undefined) { 34659 // Load binary image data from bufferView, if provided. 34660 sourceURI = parser.getDependency('bufferView', sourceDef.bufferView).then(function(bufferView) { 34661 isObjectURL = true; 34662 const blob = new Blob([ 34663 bufferView 34664 ], { 34665 type: sourceDef.mimeType 34666 }); 34667 sourceURI = URL.createObjectURL(blob); 34668 return sourceURI; 34669 }); 34670 } else if (sourceDef.uri === undefined) { 34671 throw new Error('THREE.GLTFLoader: Image ' + sourceIndex + ' is missing URI and bufferView'); 34672 } 34673 const promise = Promise.resolve(sourceURI).then(function(sourceURI) { 34674 return new Promise(function(resolve, reject) { 34675 let onLoad = resolve; 34676 if (loader.isImageBitmapLoader === true) { 34677 onLoad = function(imageBitmap) { 34678 const texture = new Texture$1(imageBitmap); 34679 texture.needsUpdate = true; 34680 resolve(texture); 34681 }; 34682 } 34683 loader.load(LoaderUtils.resolveURL(sourceURI, options.path), onLoad, undefined, reject); 34684 }); 34685 }).then(function(texture) { 34686 // Clean up resources and configure Texture. 34687 if (isObjectURL === true) { 34688 URL.revokeObjectURL(sourceURI); 34689 } 34690 assignExtrasToUserData(texture, sourceDef); 34691 texture.userData.mimeType = sourceDef.mimeType || getImageURIMimeType(sourceDef.uri); 34692 return texture; 34693 }).catch(function(error) { 34694 console.error('THREE.GLTFLoader: Couldn\'t load texture', sourceURI); 34695 throw error; 34696 }); 34697 this.sourceCache[sourceIndex] = promise; 34698 return promise; 34699 } 34700 /** 34701 * Asynchronously assigns a texture to the given material parameters. 34702 * 34703 * @param {Object} materialParams 34704 * @param {string} mapName 34705 * @param {Object} mapDef 34706 * @param {string} colorSpace 34707 * @return {Promise<Texture>} 34708 */ assignTexture(materialParams, mapName, mapDef, colorSpace) { 34709 const parser = this; 34710 return this.getDependency('texture', mapDef.index).then(function(texture) { 34711 if (!texture) return null; 34712 if (mapDef.texCoord !== undefined && mapDef.texCoord > 0) { 34713 texture = texture.clone(); 34714 texture.channel = mapDef.texCoord; 34715 } 34716 if (parser.extensions[EXTENSIONS.KHR_TEXTURE_TRANSFORM]) { 34717 const transform = mapDef.extensions !== undefined ? mapDef.extensions[EXTENSIONS.KHR_TEXTURE_TRANSFORM] : undefined; 34718 if (transform) { 34719 const gltfReference = parser.associations.get(texture); 34720 texture = parser.extensions[EXTENSIONS.KHR_TEXTURE_TRANSFORM].extendTexture(texture, transform); 34721 parser.associations.set(texture, gltfReference); 34722 } 34723 } 34724 if (colorSpace !== undefined) { 34725 texture.colorSpace = colorSpace; 34726 } 34727 materialParams[mapName] = texture; 34728 return texture; 34729 }); 34730 } 34731 /** 34732 * Assigns final material to a Mesh, Line, or Points instance. The instance 34733 * already has a material (generated from the glTF material options alone) 34734 * but reuse of the same glTF material may require multiple threejs materials 34735 * to accommodate different primitive types, defines, etc. New materials will 34736 * be created if necessary, and reused from a cache. 34737 * @param {Object3D} mesh Mesh, Line, or Points instance. 34738 */ assignFinalMaterial(mesh) { 34739 const geometry = mesh.geometry; 34740 let material = mesh.material; 34741 const useDerivativeTangents = geometry.attributes.tangent === undefined; 34742 const useVertexColors = geometry.attributes.color !== undefined; 34743 const useFlatShading = geometry.attributes.normal === undefined; 34744 if (mesh.isPoints) { 34745 const cacheKey = 'PointsMaterial:' + material.uuid; 34746 let pointsMaterial = this.cache.get(cacheKey); 34747 if (!pointsMaterial) { 34748 pointsMaterial = new PointsMaterial(); 34749 Material$1.prototype.copy.call(pointsMaterial, material); 34750 pointsMaterial.color.copy(material.color); 34751 pointsMaterial.map = material.map; 34752 pointsMaterial.sizeAttenuation = false; // glTF spec says points should be 1px 34753 this.cache.add(cacheKey, pointsMaterial); 34754 } 34755 material = pointsMaterial; 34756 } else if (mesh.isLine) { 34757 const cacheKey = 'LineBasicMaterial:' + material.uuid; 34758 let lineMaterial = this.cache.get(cacheKey); 34759 if (!lineMaterial) { 34760 lineMaterial = new LineBasicMaterial(); 34761 Material$1.prototype.copy.call(lineMaterial, material); 34762 lineMaterial.color.copy(material.color); 34763 lineMaterial.map = material.map; 34764 this.cache.add(cacheKey, lineMaterial); 34765 } 34766 material = lineMaterial; 34767 } 34768 // Clone the material if it will be modified 34769 if (useDerivativeTangents || useVertexColors || useFlatShading) { 34770 let cacheKey = 'ClonedMaterial:' + material.uuid + ':'; 34771 if (useDerivativeTangents) cacheKey += 'derivative-tangents:'; 34772 if (useVertexColors) cacheKey += 'vertex-colors:'; 34773 if (useFlatShading) cacheKey += 'flat-shading:'; 34774 let cachedMaterial = this.cache.get(cacheKey); 34775 if (!cachedMaterial) { 34776 cachedMaterial = material.clone(); 34777 if (useVertexColors) cachedMaterial.vertexColors = true; 34778 if (useFlatShading) cachedMaterial.flatShading = true; 34779 if (useDerivativeTangents) { 34780 // https://github.com/mrdoob/three.js/issues/11438#issuecomment-507003995 34781 if (cachedMaterial.normalScale) cachedMaterial.normalScale.y *= -1; 34782 if (cachedMaterial.clearcoatNormalScale) cachedMaterial.clearcoatNormalScale.y *= -1; 34783 } 34784 this.cache.add(cacheKey, cachedMaterial); 34785 this.associations.set(cachedMaterial, this.associations.get(material)); 34786 } 34787 material = cachedMaterial; 34788 } 34789 mesh.material = material; 34790 } 34791 getMaterialType() { 34792 return MeshStandardMaterial; 34793 } 34794 /** 34795 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials 34796 * @param {number} materialIndex 34797 * @return {Promise<Material>} 34798 */ loadMaterial(materialIndex) { 34799 const parser = this; 34800 const json = this.json; 34801 const extensions = this.extensions; 34802 const materialDef = json.materials[materialIndex]; 34803 let materialType; 34804 const materialParams = {}; 34805 const materialExtensions = materialDef.extensions || {}; 34806 const pending = []; 34807 if (materialExtensions[EXTENSIONS.KHR_MATERIALS_UNLIT]) {
vendor: 12,157 bytes, lines 34808-35035
34808 const kmuExtension = extensions[EXTENSIONS.KHR_MATERIALS_UNLIT]; 34809 materialType = kmuExtension.getMaterialType(); 34810 pending.push(kmuExtension.extendParams(materialParams, materialDef, parser)); 34811 } else { 34812 // Specification: 34813 // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material 34814 const metallicRoughness = materialDef.pbrMetallicRoughness || {}; 34815 materialParams.color = new Color(1.0, 1.0, 1.0); 34816 materialParams.opacity = 1.0; 34817 if (Array.isArray(metallicRoughness.baseColorFactor)) { 34818 const array = metallicRoughness.baseColorFactor; 34819 materialParams.color.setRGB(array[0], array[1], array[2], LinearSRGBColorSpace); 34820 materialParams.opacity = array[3]; 34821 } 34822 if (metallicRoughness.baseColorTexture !== undefined) { 34823 pending.push(parser.assignTexture(materialParams, 'map', metallicRoughness.baseColorTexture, SRGBColorSpace)); 34824 } 34825 materialParams.metalness = metallicRoughness.metallicFactor !== undefined ? metallicRoughness.metallicFactor : 1.0; 34826 materialParams.roughness = metallicRoughness.roughnessFactor !== undefined ? metallicRoughness.roughnessFactor : 1.0; 34827 if (metallicRoughness.metallicRoughnessTexture !== undefined) { 34828 pending.push(parser.assignTexture(materialParams, 'metalnessMap', metallicRoughness.metallicRoughnessTexture)); 34829 pending.push(parser.assignTexture(materialParams, 'roughnessMap', metallicRoughness.metallicRoughnessTexture)); 34830 } 34831 materialType = this._invokeOne(function(ext) { 34832 return ext.getMaterialType && ext.getMaterialType(materialIndex); 34833 }); 34834 pending.push(Promise.all(this._invokeAll(function(ext) { 34835 return ext.extendMaterialParams && ext.extendMaterialParams(materialIndex, materialParams); 34836 }))); 34837 } 34838 if (materialDef.doubleSided === true) { 34839 materialParams.side = DoubleSide; 34840 } 34841 const alphaMode = materialDef.alphaMode || ALPHA_MODES.OPAQUE; 34842 if (alphaMode === ALPHA_MODES.BLEND) { 34843 materialParams.transparent = true; 34844 // See: https://github.com/mrdoob/three.js/issues/17706 34845 materialParams.depthWrite = false; 34846 } else { 34847 materialParams.transparent = false; 34848 if (alphaMode === ALPHA_MODES.MASK) { 34849 materialParams.alphaTest = materialDef.alphaCutoff !== undefined ? materialDef.alphaCutoff : 0.5; 34850 } 34851 } 34852 if (materialDef.normalTexture !== undefined && materialType !== MeshBasicMaterial) { 34853 pending.push(parser.assignTexture(materialParams, 'normalMap', materialDef.normalTexture)); 34854 materialParams.normalScale = new Vector2(1, 1); 34855 if (materialDef.normalTexture.scale !== undefined) { 34856 const scale = materialDef.normalTexture.scale; 34857 materialParams.normalScale.set(scale, scale); 34858 } 34859 } 34860 if (materialDef.occlusionTexture !== undefined && materialType !== MeshBasicMaterial) { 34861 pending.push(parser.assignTexture(materialParams, 'aoMap', materialDef.occlusionTexture)); 34862 if (materialDef.occlusionTexture.strength !== undefined) { 34863 materialParams.aoMapIntensity = materialDef.occlusionTexture.strength; 34864 } 34865 } 34866 if (materialDef.emissiveFactor !== undefined && materialType !== MeshBasicMaterial) { 34867 const emissiveFactor = materialDef.emissiveFactor; 34868 materialParams.emissive = new Color().setRGB(emissiveFactor[0], emissiveFactor[1], emissiveFactor[2], LinearSRGBColorSpace); 34869 } 34870 if (materialDef.emissiveTexture !== undefined && materialType !== MeshBasicMaterial) { 34871 pending.push(parser.assignTexture(materialParams, 'emissiveMap', materialDef.emissiveTexture, SRGBColorSpace)); 34872 } 34873 return Promise.all(pending).then(function() { 34874 const material = new materialType(materialParams); 34875 if (materialDef.name) material.name = materialDef.name; 34876 assignExtrasToUserData(material, materialDef); 34877 parser.associations.set(material, { 34878 materials: materialIndex 34879 }); 34880 if (materialDef.extensions) addUnknownExtensionsToUserData(extensions, material, materialDef); 34881 return material; 34882 }); 34883 } 34884 /** 34885 * When Object3D instances are targeted by animation, they need unique names. 34886 * 34887 * @param {string} originalName 34888 * @return {string} 34889 */ createUniqueName(originalName) { 34890 const sanitizedName = PropertyBinding.sanitizeNodeName(originalName || ''); 34891 if (sanitizedName in this.nodeNamesUsed) { 34892 return sanitizedName + '_' + ++this.nodeNamesUsed[sanitizedName]; 34893 } else { 34894 this.nodeNamesUsed[sanitizedName] = 0; 34895 return sanitizedName; 34896 } 34897 } 34898 /** 34899 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#geometry 34900 * 34901 * Creates BufferGeometries from primitives. 34902 * 34903 * @param {Array<GLTF.Primitive>} primitives 34904 * @return {Promise<Array<BufferGeometry>>} 34905 */ loadGeometries(primitives) { 34906 const parser = this; 34907 const extensions = this.extensions; 34908 const cache = this.primitiveCache; 34909 function createDracoPrimitive(primitive) { 34910 return extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION].decodePrimitive(primitive, parser).then(function(geometry) { 34911 return addPrimitiveAttributes(geometry, primitive, parser); 34912 }); 34913 } 34914 const pending = []; 34915 for(let i = 0, il = primitives.length; i < il; i++){ 34916 const primitive = primitives[i]; 34917 const cacheKey = createPrimitiveKey(primitive); 34918 // See if we've already created this geometry 34919 const cached = cache[cacheKey]; 34920 if (cached) { 34921 // Use the cached geometry if it exists 34922 pending.push(cached.promise); 34923 } else { 34924 let geometryPromise; 34925 if (primitive.extensions && primitive.extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION]) { 34926 // Use DRACO geometry if available 34927 geometryPromise = createDracoPrimitive(primitive); 34928 } else { 34929 // Otherwise create a new geometry 34930 geometryPromise = addPrimitiveAttributes(new BufferGeometry(), primitive, parser); 34931 } 34932 // Cache this geometry 34933 cache[cacheKey] = { 34934 primitive: primitive, 34935 promise: geometryPromise 34936 }; 34937 pending.push(geometryPromise); 34938 } 34939 } 34940 return Promise.all(pending); 34941 } 34942 /** 34943 * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#meshes 34944 * @param {number} meshIndex 34945 * @return {Promise<Group|Mesh|SkinnedMesh>} 34946 */ loadMesh(meshIndex) { 34947 const parser = this; 34948 const json = this.json; 34949 const extensions = this.extensions; 34950 const meshDef = json.meshes[meshIndex]; 34951 const primitives = meshDef.primitives; 34952 const pending = []; 34953 for(let i = 0, il = primitives.length; i < il; i++){ 34954 const material = primitives[i].material === undefined ? createDefaultMaterial(this.cache) : this.getDependency('material', primitives[i].material); 34955 pending.push(material); 34956 } 34957 pending.push(parser.loadGeometries(primitives)); 34958 return Promise.all(pending).then(function(results) { 34959 const materials = results.slice(0, results.length - 1); 34960 const geometries = results[results.length - 1]; 34961 const meshes = []; 34962 for(let i = 0, il = geometries.length; i < il; i++){ 34963 const geometry = geometries[i]; 34964 const primitive = primitives[i]; 34965 // 1. create Mesh 34966 let mesh; 34967 const material = materials[i]; 34968 if (primitive.mode === WEBGL_CONSTANTS$1.TRIANGLES || primitive.mode === WEBGL_CONSTANTS$1.TRIANGLE_STRIP || primitive.mode === WEBGL_CONSTANTS$1.TRIANGLE_FAN || primitive.mode === undefined) { 34969 // .isSkinnedMesh isn't in glTF spec. See ._markDefs() 34970 mesh = meshDef.isSkinnedMesh === true ? new SkinnedMesh(geometry, material) : new Mesh(geometry, material); 34971 if (mesh.isSkinnedMesh === true) { 34972 // normalize skin weights to fix malformed assets (see #15319) 34973 mesh.normalizeSkinWeights(); 34974 } 34975 if (primitive.mode === WEBGL_CONSTANTS$1.TRIANGLE_STRIP) { 34976 mesh.geometry = toTrianglesDrawMode(mesh.geometry, TriangleStripDrawMode); 34977 } else if (primitive.mode === WEBGL_CONSTANTS$1.TRIANGLE_FAN) { 34978 mesh.geometry = toTrianglesDrawMode(mesh.geometry, TriangleFanDrawMode); 34979 } 34980 } else if (primitive.mode === WEBGL_CONSTANTS$1.LINES) { 34981 mesh = new LineSegments(geometry, material); 34982 } else if (primitive.mode === WEBGL_CONSTANTS$1.LINE_STRIP) { 34983 mesh = new Line(geometry, material); 34984 } else if (primitive.mode === WEBGL_CONSTANTS$1.LINE_LOOP) { 34985 mesh = new LineLoop(geometry, material); 34986 } else if (primitive.mode === WEBGL_CONSTANTS$1.POINTS) { 34987 mesh = new Points(geometry, material); 34988 } else { 34989 throw new Error('THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode); 34990 } 34991 if (Object.keys(mesh.geometry.morphAttributes).length > 0) { 34992 updateMorphTargets(mesh, meshDef); 34993 } 34994 mesh.name = parser.createUniqueName(meshDef.name || 'mesh_' + meshIndex); 34995 assignExtrasToUserData(mesh, meshDef); 34996 if (primitive.extensions) addUnknownExtensionsToUserData(extensions, mesh, primitive); 34997 parser.assignFinalMaterial(mesh); 34998 meshes.push(mesh); 34999 } 35000 for(let i = 0, il = meshes.length; i < il; i++){ 35001 parser.associations.set(meshes[i], { 35002 meshes: meshIndex, 35003 primitives: i 35004 }); 35005 } 35006 if (meshes.length === 1) { 35007 if (meshDef.extensions) addUnknownExtensionsToUserData(extensions, meshes[0], meshDef); 35008 return meshes[0]; 35009 } 35010 const group = new Group(); 35011 if (meshDef.extensions) addUnknownExtensionsToUserData(extensions, group, meshDef); 35012 parser.associations.set(group, { 35013 meshes: meshIndex 35014 }); 35015 for(let i = 0, il = meshes.length; i < il; i++){ 35016 group.add(meshes[i]); 35017 } 35018 return group; 35019 }); 35020 } 35021 /** 35022 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#cameras 35023 * @param {number} cameraIndex 35024 * @return {Promise<THREE.Camera>} 35025 */ loadCamera(cameraIndex) { 35026 let camera; 35027 const cameraDef = this.json.cameras[cameraIndex]; 35028 const params = cameraDef[cameraDef.type]; 35029 if (!params) { 35030 console.warn('THREE.GLTFLoader: Missing camera parameters.'); 35031 return; 35032 } 35033 if (cameraDef.type === 'perspective') { 35034 camera = new PerspectiveCamera(MathUtils.radToDeg(params.yfov), params.aspectRatio || 1, params.znear || 1, params.zfar || 2e6); 35035 } else if (cameraDef.type === 'orthographic') {
vendor: 4,195 bytes, lines 35036-35122
35036 camera = new OrthographicCamera(-params.xmag, params.xmag, params.ymag, -params.ymag, params.znear, params.zfar); 35037 } 35038 if (cameraDef.name) camera.name = this.createUniqueName(cameraDef.name); 35039 assignExtrasToUserData(camera, cameraDef); 35040 return Promise.resolve(camera); 35041 } 35042 /** 35043 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins 35044 * @param {number} skinIndex 35045 * @return {Promise<Skeleton>} 35046 */ loadSkin(skinIndex) { 35047 const skinDef = this.json.skins[skinIndex]; 35048 const pending = []; 35049 for(let i = 0, il = skinDef.joints.length; i < il; i++){ 35050 pending.push(this._loadNodeShallow(skinDef.joints[i])); 35051 } 35052 if (skinDef.inverseBindMatrices !== undefined) { 35053 pending.push(this.getDependency('accessor', skinDef.inverseBindMatrices)); 35054 } else { 35055 pending.push(null); 35056 } 35057 return Promise.all(pending).then(function(results) { 35058 const inverseBindMatrices = results.pop(); 35059 const jointNodes = results; 35060 // Note that bones (joint nodes) may or may not be in the 35061 // scene graph at this time. 35062 const bones = []; 35063 const boneInverses = []; 35064 for(let i = 0, il = jointNodes.length; i < il; i++){ 35065 const jointNode = jointNodes[i]; 35066 if (jointNode) { 35067 bones.push(jointNode); 35068 const mat = new Matrix4(); 35069 if (inverseBindMatrices !== null) { 35070 mat.fromArray(inverseBindMatrices.array, i * 16); 35071 } 35072 boneInverses.push(mat); 35073 } else { 35074 console.warn('THREE.GLTFLoader: Joint "%s" could not be found.', skinDef.joints[i]); 35075 } 35076 } 35077 return new Skeleton(bones, boneInverses); 35078 }); 35079 } 35080 /** 35081 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations 35082 * @param {number} animationIndex 35083 * @return {Promise<AnimationClip>} 35084 */ loadAnimation(animationIndex) { 35085 const json = this.json; 35086 const parser = this; 35087 const animationDef = json.animations[animationIndex]; 35088 const animationName = animationDef.name ? animationDef.name : 'animation_' + animationIndex; 35089 const pendingNodes = []; 35090 const pendingInputAccessors = []; 35091 const pendingOutputAccessors = []; 35092 const pendingSamplers = []; 35093 const pendingTargets = []; 35094 for(let i = 0, il = animationDef.channels.length; i < il; i++){ 35095 const channel = animationDef.channels[i]; 35096 const sampler = animationDef.samplers[channel.sampler]; 35097 const target = channel.target; 35098 const name = target.node; 35099 const input = animationDef.parameters !== undefined ? animationDef.parameters[sampler.input] : sampler.input; 35100 const output = animationDef.parameters !== undefined ? animationDef.parameters[sampler.output] : sampler.output; 35101 if (target.node === undefined) continue; 35102 pendingNodes.push(this.getDependency('node', name)); 35103 pendingInputAccessors.push(this.getDependency('accessor', input)); 35104 pendingOutputAccessors.push(this.getDependency('accessor', output)); 35105 pendingSamplers.push(sampler); 35106 pendingTargets.push(target); 35107 } 35108 return Promise.all([ 35109 Promise.all(pendingNodes), 35110 Promise.all(pendingInputAccessors), 35111 Promise.all(pendingOutputAccessors), 35112 Promise.all(pendingSamplers), 35113 Promise.all(pendingTargets) 35114 ]).then(function(dependencies) { 35115 const nodes = dependencies[0]; 35116 const inputAccessors = dependencies[1]; 35117 const outputAccessors = dependencies[2]; 35118 const samplers = dependencies[3]; 35119 const targets = dependencies[4]; 35120 const tracks = []; 35121 for(let i = 0, il = nodes.length; i < il; i++){ 35122 const node = nodes[i];
vendor: 4,599 bytes, lines 35123-35225
35123 const inputAccessor = inputAccessors[i]; 35124 const outputAccessor = outputAccessors[i]; 35125 const sampler = samplers[i]; 35126 const target = targets[i]; 35127 if (node === undefined) continue; 35128 if (node.updateMatrix) { 35129 node.updateMatrix(); 35130 } 35131 const createdTracks = parser._createAnimationTracks(node, inputAccessor, outputAccessor, sampler, target); 35132 if (createdTracks) { 35133 for(let k = 0; k < createdTracks.length; k++){ 35134 tracks.push(createdTracks[k]); 35135 } 35136 } 35137 } 35138 return new AnimationClip(animationName, undefined, tracks); 35139 }); 35140 } 35141 createNodeMesh(nodeIndex) { 35142 const json = this.json; 35143 const parser = this; 35144 const nodeDef = json.nodes[nodeIndex]; 35145 if (nodeDef.mesh === undefined) return null; 35146 return parser.getDependency('mesh', nodeDef.mesh).then(function(mesh) { 35147 const node = parser._getNodeRef(parser.meshCache, nodeDef.mesh, mesh); 35148 // if weights are provided on the node, override weights on the mesh. 35149 if (nodeDef.weights !== undefined) { 35150 node.traverse(function(o) { 35151 if (!o.isMesh) return; 35152 for(let i = 0, il = nodeDef.weights.length; i < il; i++){ 35153 o.morphTargetInfluences[i] = nodeDef.weights[i]; 35154 } 35155 }); 35156 } 35157 return node; 35158 }); 35159 } 35160 /** 35161 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#nodes-and-hierarchy 35162 * @param {number} nodeIndex 35163 * @return {Promise<Object3D>} 35164 */ loadNode(nodeIndex) { 35165 const json = this.json; 35166 const parser = this; 35167 const nodeDef = json.nodes[nodeIndex]; 35168 const nodePending = parser._loadNodeShallow(nodeIndex); 35169 const childPending = []; 35170 const childrenDef = nodeDef.children || []; 35171 for(let i = 0, il = childrenDef.length; i < il; i++){ 35172 childPending.push(parser.getDependency('node', childrenDef[i])); 35173 } 35174 const skeletonPending = nodeDef.skin === undefined ? Promise.resolve(null) : parser.getDependency('skin', nodeDef.skin); 35175 return Promise.all([ 35176 nodePending, 35177 Promise.all(childPending), 35178 skeletonPending 35179 ]).then(function(results) { 35180 const node = results[0]; 35181 const children = results[1]; 35182 const skeleton = results[2]; 35183 if (skeleton !== null) { 35184 // This full traverse should be fine because 35185 // child glTF nodes have not been added to this node yet. 35186 node.traverse(function(mesh) { 35187 if (!mesh.isSkinnedMesh) return; 35188 mesh.bind(skeleton, _identityMatrix); 35189 }); 35190 } 35191 for(let i = 0, il = children.length; i < il; i++){ 35192 node.add(children[i]); 35193 } 35194 return node; 35195 }); 35196 } 35197 // ._loadNodeShallow() parses a single node. 35198 // skin and child nodes are created and added in .loadNode() (no '_' prefix). 35199 _loadNodeShallow(nodeIndex) { 35200 const json = this.json; 35201 const extensions = this.extensions; 35202 const parser = this; 35203 // This method is called from .loadNode() and .loadSkin(). 35204 // Cache a node to avoid duplication. 35205 if (this.nodeCache[nodeIndex] !== undefined) { 35206 return this.nodeCache[nodeIndex]; 35207 } 35208 const nodeDef = json.nodes[nodeIndex]; 35209 // reserve node's name before its dependencies, so the root has the intended name. 35210 const nodeName = nodeDef.name ? parser.createUniqueName(nodeDef.name) : ''; 35211 const pending = []; 35212 const meshPromise = parser._invokeOne(function(ext) { 35213 return ext.createNodeMesh && ext.createNodeMesh(nodeIndex); 35214 }); 35215 if (meshPromise) { 35216 pending.push(meshPromise); 35217 } 35218 if (nodeDef.camera !== undefined) { 35219 pending.push(parser.getDependency('camera', nodeDef.camera).then(function(camera) { 35220 return parser._getNodeRef(parser.cameraCache, nodeDef.camera, camera); 35221 })); 35222 } 35223 parser._invokeAll(function(ext) { 35224 return ext.createNodeAttachment && ext.createNodeAttachment(nodeIndex); 35225 }
vendor: 5,641 bytes, lines 35225-35356
35225).forEach(function(promise) { 35226 pending.push(promise); 35227 }); 35228 this.nodeCache[nodeIndex] = Promise.all(pending).then(function(objects) { 35229 let node; 35230 // .isBone isn't in glTF spec. See ._markDefs 35231 if (nodeDef.isBone === true) { 35232 node = new Bone(); 35233 } else if (objects.length > 1) { 35234 node = new Group(); 35235 } else if (objects.length === 1) { 35236 node = objects[0]; 35237 } else { 35238 node = new Object3D(); 35239 } 35240 if (node !== objects[0]) { 35241 for(let i = 0, il = objects.length; i < il; i++){ 35242 node.add(objects[i]); 35243 } 35244 } 35245 if (nodeDef.name) { 35246 node.userData.name = nodeDef.name; 35247 node.name = nodeName; 35248 } 35249 assignExtrasToUserData(node, nodeDef); 35250 if (nodeDef.extensions) addUnknownExtensionsToUserData(extensions, node, nodeDef); 35251 if (nodeDef.matrix !== undefined) { 35252 const matrix = new Matrix4(); 35253 matrix.fromArray(nodeDef.matrix); 35254 node.applyMatrix4(matrix); 35255 } else { 35256 if (nodeDef.translation !== undefined) { 35257 node.position.fromArray(nodeDef.translation); 35258 } 35259 if (nodeDef.rotation !== undefined) { 35260 node.quaternion.fromArray(nodeDef.rotation); 35261 } 35262 if (nodeDef.scale !== undefined) { 35263 node.scale.fromArray(nodeDef.scale); 35264 } 35265 } 35266 if (!parser.associations.has(node)) { 35267 parser.associations.set(node, {}); 35268 } 35269 parser.associations.get(node).nodes = nodeIndex; 35270 return node; 35271 }); 35272 return this.nodeCache[nodeIndex]; 35273 } 35274 /** 35275 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#scenes 35276 * @param {number} sceneIndex 35277 * @return {Promise<Group>} 35278 */ loadScene(sceneIndex) { 35279 const extensions = this.extensions; 35280 const sceneDef = this.json.scenes[sceneIndex]; 35281 const parser = this; 35282 // Loader returns Group, not Scene. 35283 // See: https://github.com/mrdoob/three.js/issues/18342#issuecomment-578981172 35284 const scene = new Group(); 35285 if (sceneDef.name) scene.name = parser.createUniqueName(sceneDef.name); 35286 assignExtrasToUserData(scene, sceneDef); 35287 if (sceneDef.extensions) addUnknownExtensionsToUserData(extensions, scene, sceneDef); 35288 const nodeIds = sceneDef.nodes || []; 35289 const pending = []; 35290 for(let i = 0, il = nodeIds.length; i < il; i++){ 35291 pending.push(parser.getDependency('node', nodeIds[i])); 35292 } 35293 return Promise.all(pending).then(function(nodes) { 35294 for(let i = 0, il = nodes.length; i < il; i++){ 35295 scene.add(nodes[i]); 35296 } 35297 // Removes dangling associations, associations that reference a node that 35298 // didn't make it into the scene. 35299 const reduceAssociations = (node)=>{ 35300 const reducedAssociations = new Map(); 35301 for (const [key, value] of parser.associations){ 35302 if (key instanceof Material$1 || key instanceof Texture$1) { 35303 reducedAssociations.set(key, value); 35304 } 35305 } 35306 node.traverse((node)=>{ 35307 const mappings = parser.associations.get(node); 35308 if (mappings != null) { 35309 reducedAssociations.set(node, mappings); 35310 } 35311 }); 35312 return reducedAssociations; 35313 }; 35314 parser.associations = reduceAssociations(scene); 35315 return scene; 35316 }); 35317 } 35318 _createAnimationTracks(node, inputAccessor, outputAccessor, sampler, target) { 35319 const tracks = []; 35320 const targetName = node.name ? node.name : node.uuid; 35321 const targetNames = []; 35322 if (PATH_PROPERTIES$1[target.path] === PATH_PROPERTIES$1.weights) { 35323 node.traverse(function(object) { 35324 if (object.morphTargetInfluences) { 35325 targetNames.push(object.name ? object.name : object.uuid); 35326 } 35327 }); 35328 } else { 35329 targetNames.push(targetName); 35330 } 35331 let TypedKeyframeTrack; 35332 switch(PATH_PROPERTIES$1[target.path]){ 35333 case PATH_PROPERTIES$1.weights: 35334 TypedKeyframeTrack = NumberKeyframeTrack; 35335 break; 35336 case PATH_PROPERTIES$1.rotation: 35337 TypedKeyframeTrack = QuaternionKeyframeTrack; 35338 break; 35339 case PATH_PROPERTIES$1.position: 35340 case PATH_PROPERTIES$1.scale: 35341 TypedKeyframeTrack = VectorKeyframeTrack; 35342 break; 35343 default: 35344 switch(outputAccessor.itemSize){ 35345 case 1: 35346 TypedKeyframeTrack = NumberKeyframeTrack; 35347 break; 35348 case 2: 35349 case 3: 35350 default: 35351 TypedKeyframeTrack = VectorKeyframeTrack; 35352 break; 35353 } 35354 break; 35355 } 35356 const interpolation = sampler.interpolation !== undefined ? INTERPOLATION[sampler.interpolation] : InterpolateLinear;
vendor: 15,206 bytes, lines 35357-35706
35357 const outputArray = this._getArrayFromAccessor(outputAccessor); 35358 for(let j = 0, jl = targetNames.length; j < jl; j++){ 35359 const track = new TypedKeyframeTrack(targetNames[j] + '.' + PATH_PROPERTIES$1[target.path], inputAccessor.array, outputArray, interpolation); 35360 // Override interpolation with custom factory method. 35361 if (sampler.interpolation === 'CUBICSPLINE') { 35362 this._createCubicSplineTrackInterpolant(track); 35363 } 35364 tracks.push(track); 35365 } 35366 return tracks; 35367 } 35368 _getArrayFromAccessor(accessor) { 35369 let outputArray = accessor.array; 35370 if (accessor.normalized) { 35371 const scale = getNormalizedComponentScale(outputArray.constructor); 35372 const scaled = new Float32Array(outputArray.length); 35373 for(let j = 0, jl = outputArray.length; j < jl; j++){ 35374 scaled[j] = outputArray[j] * scale; 35375 } 35376 outputArray = scaled; 35377 } 35378 return outputArray; 35379 } 35380 _createCubicSplineTrackInterpolant(track) { 35381 track.createInterpolant = function InterpolantFactoryMethodGLTFCubicSpline(result) { 35382 // A CUBICSPLINE keyframe in glTF has three output values for each input value, 35383 // representing inTangent, splineVertex, and outTangent. As a result, track.getValueSize() 35384 // must be divided by three to get the interpolant's sampleSize argument. 35385 const interpolantType = this instanceof QuaternionKeyframeTrack ? GLTFCubicSplineQuaternionInterpolant : GLTFCubicSplineInterpolant; 35386 return new interpolantType(this.times, this.values, this.getValueSize() / 3, result); 35387 }; 35388 // Mark as CUBICSPLINE. `track.getInterpolation()` doesn't support custom interpolants. 35389 track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline = true; 35390 } 35391 constructor(json = {}, options = {}){ 35392 this.json = json; 35393 this.extensions = {}; 35394 this.plugins = {}; 35395 this.options = options; 35396 // loader object cache 35397 this.cache = new GLTFRegistry(); 35398 // associations between Three.js objects and glTF elements 35399 this.associations = new Map(); 35400 // BufferGeometry caching 35401 this.primitiveCache = {}; 35402 // Node cache 35403 this.nodeCache = {}; 35404 // Object3D instance caches 35405 this.meshCache = { 35406 refs: {}, 35407 uses: {} 35408 }; 35409 this.cameraCache = { 35410 refs: {}, 35411 uses: {} 35412 }; 35413 this.lightCache = { 35414 refs: {}, 35415 uses: {} 35416 }; 35417 this.sourceCache = {}; 35418 this.textureCache = {}; 35419 // Track node names, to ensure no duplicates 35420 this.nodeNamesUsed = {}; 35421 // Use an ImageBitmapLoader if imageBitmaps are supported. Moves much of the 35422 // expensive work of uploading a texture to the GPU off the main thread. 35423 let isSafari = false; 35424 let safariVersion = -1; 35425 let isFirefox = false; 35426 let firefoxVersion = -1; 35427 if (typeof navigator !== 'undefined') { 35428 const userAgent = navigator.userAgent; 35429 isSafari = /^((?!chrome|android).)*safari/i.test(userAgent) === true; 35430 const safariMatch = userAgent.match(/Version\/(\d+)/); 35431 safariVersion = isSafari && safariMatch ? parseInt(safariMatch[1], 10) : -1; 35432 isFirefox = userAgent.indexOf('Firefox') > -1; 35433 firefoxVersion = isFirefox ? userAgent.match(/Firefox\/([0-9]+)\./)[1] : -1; 35434 } 35435 if (typeof createImageBitmap === 'undefined' || isSafari && safariVersion < 17 || isFirefox && firefoxVersion < 98) { 35436 this.textureLoader = new TextureLoader(this.options.manager); 35437 } else { 35438 this.textureLoader = new ImageBitmapLoader(this.options.manager); 35439 } 35440 this.textureLoader.setCrossOrigin(this.options.crossOrigin); 35441 this.textureLoader.setRequestHeader(this.options.requestHeader); 35442 this.fileLoader = new FileLoader(this.options.manager); 35443 this.fileLoader.setResponseType('arraybuffer'); 35444 if (this.options.crossOrigin === 'use-credentials') { 35445 this.fileLoader.setWithCredentials(true); 35446 } 35447 } 35448 } 35449 /** 35450 * @param {BufferGeometry} geometry 35451 * @param {GLTF.Primitive} primitiveDef 35452 * @param {GLTFParser} parser 35453 */ function computeBounds(geometry, primitiveDef, parser) { 35454 const attributes = primitiveDef.attributes; 35455 const box = new Box3(); 35456 if (attributes.POSITION !== undefined) { 35457 const accessor = parser.json.accessors[attributes.POSITION]; 35458 const min = accessor.min; 35459 const max = accessor.max; 35460 // glTF requires 'min' and 'max', but VRM (which extends glTF) currently ignores that requirement. 35461 if (min !== undefined && max !== undefined) { 35462 box.set(new Vector3(min[0], min[1], min[2]), new Vector3(max[0], max[1], max[2])); 35463 if (accessor.normalized) { 35464 const boxScale = getNormalizedComponentScale(WEBGL_COMPONENT_TYPES[accessor.componentType]); 35465 box.min.multiplyScalar(boxScale); 35466 box.max.multiplyScalar(boxScale); 35467 } 35468 } else { 35469 console.warn('THREE.GLTFLoader: Missing min/max properties for accessor POSITION.'); 35470 return; 35471 } 35472 } else { 35473 return; 35474 } 35475 const targets = primitiveDef.targets; 35476 if (targets !== undefined) { 35477 const maxDisplacement = new Vector3(); 35478 const vector = new Vector3(); 35479 for(let i = 0, il = targets.length; i < il; i++){ 35480 const target = targets[i]; 35481 if (target.POSITION !== undefined) { 35482 const accessor = parser.json.accessors[target.POSITION]; 35483 const min = accessor.min; 35484 const max = accessor.max; 35485 // glTF requires 'min' and 'max', but VRM (which extends glTF) currently ignores that requirement. 35486 if (min !== undefined && max !== undefined) { 35487 // we need to get max of absolute components because target weight is [-1,1] 35488 vector.setX(Math.max(Math.abs(min[0]), Math.abs(max[0]))); 35489 vector.setY(Math.max(Math.abs(min[1]), Math.abs(max[1]))); 35490 vector.setZ(Math.max(Math.abs(min[2]), Math.abs(max[2]))); 35491 if (accessor.normalized) { 35492 const boxScale = getNormalizedComponentScale(WEBGL_COMPONENT_TYPES[accessor.componentType]); 35493 vector.multiplyScalar(boxScale); 35494 } 35495 // Note: this assumes that the sum of all weights is at most 1. This isn't quite correct - it's more conservative 35496 // to assume that each target can have a max weight of 1. However, for some use cases - notably, when morph targets 35497 // are used to implement key-frame animations and as such only two are active at a time - this results in very large 35498 // boxes. So for now we make a box that's sometimes a touch too small but is hopefully mostly of reasonable size. 35499 maxDisplacement.max(vector); 35500 } else { 35501 console.warn('THREE.GLTFLoader: Missing min/max properties for accessor POSITION.'); 35502 } 35503 } 35504 } 35505 // As per comment above this box isn't conservative, but has a reasonable size for a very large number of morph targets. 35506 box.expandByVector(maxDisplacement); 35507 } 35508 geometry.boundingBox = box; 35509 const sphere = new Sphere(); 35510 box.getCenter(sphere.center); 35511 sphere.radius = box.min.distanceTo(box.max) / 2; 35512 geometry.boundingSphere = sphere; 35513 } 35514 /** 35515 * @param {BufferGeometry} geometry 35516 * @param {GLTF.Primitive} primitiveDef 35517 * @param {GLTFParser} parser 35518 * @return {Promise<BufferGeometry>} 35519 */ function addPrimitiveAttributes(geometry, primitiveDef, parser) { 35520 const attributes = primitiveDef.attributes; 35521 const pending = []; 35522 function assignAttributeAccessor(accessorIndex, attributeName) { 35523 return parser.getDependency('accessor', accessorIndex).then(function(accessor) { 35524 geometry.setAttribute(attributeName, accessor); 35525 }); 35526 } 35527 for(const gltfAttributeName in attributes){ 35528 const threeAttributeName = ATTRIBUTES[gltfAttributeName] || gltfAttributeName.toLowerCase(); 35529 // Skip attributes already provided by e.g. Draco extension. 35530 if (threeAttributeName in geometry.attributes) continue; 35531 pending.push(assignAttributeAccessor(attributes[gltfAttributeName], threeAttributeName)); 35532 } 35533 if (primitiveDef.indices !== undefined && !geometry.index) { 35534 const accessor = parser.getDependency('accessor', primitiveDef.indices).then(function(accessor) { 35535 geometry.setIndex(accessor); 35536 }); 35537 pending.push(accessor); 35538 } 35539 if (ColorManagement.workingColorSpace !== LinearSRGBColorSpace && 'COLOR_0' in attributes) { 35540 console.warn(`THREE.GLTFLoader: Converting vertex colors from "srgb-linear" to "${ColorManagement.workingColorSpace}" not supported.`); 35541 } 35542 assignExtrasToUserData(geometry, primitiveDef); 35543 computeBounds(geometry, primitiveDef, parser); 35544 return Promise.all(pending).then(function() { 35545 return primitiveDef.targets !== undefined ? addMorphTargets(geometry, primitiveDef.targets, parser) : geometry; 35546 }); 35547 } 35548 35549 /** 35550 * @author Deepkolos / https://github.com/deepkolos 35551 */ class WorkerPool { 35552 _initWorker(workerId) { 35553 if (!this.workers[workerId]) { 35554 const worker = this.workerCreator(); 35555 worker.addEventListener('message', this._onMessage.bind(this, workerId)); 35556 this.workers[workerId] = worker; 35557 } 35558 } 35559 _getIdleWorker() { 35560 for(let i = 0; i < this.pool; i++)if (!(this.workerStatus & 1 << i)) return i; 35561 return -1; 35562 } 35563 _onMessage(workerId, msg) { 35564 const resolve = this.workersResolve[workerId]; 35565 resolve && resolve(msg); 35566 if (this.queue.length) { 35567 const { resolve, msg, transfer } = this.queue.shift(); 35568 this.workersResolve[workerId] = resolve; 35569 this.workers[workerId].postMessage(msg, transfer); 35570 } else { 35571 this.workerStatus ^= 1 << workerId; 35572 } 35573 } 35574 setWorkerCreator(workerCreator) { 35575 this.workerCreator = workerCreator; 35576 } 35577 setWorkerLimit(pool) { 35578 this.pool = pool; 35579 } 35580 postMessage(msg, transfer) { 35581 return new Promise((resolve)=>{ 35582 const workerId = this._getIdleWorker(); 35583 if (workerId !== -1) { 35584 this._initWorker(workerId); 35585 this.workerStatus |= 1 << workerId; 35586 this.workersResolve[workerId] = resolve; 35587 this.workers[workerId].postMessage(msg, transfer); 35588 } else { 35589 this.queue.push({ 35590 resolve, 35591 msg, 35592 transfer 35593 }); 35594 } 35595 }); 35596 } 35597 dispose() { 35598 this.workers.forEach((worker)=>worker.terminate()); 35599 this.workersResolve.length = 0; 35600 this.workers.length = 0; 35601 this.queue.length = 0; 35602 this.workerStatus = 0; 35603 } 35604 constructor(pool = 4){ 35605 this.pool = pool; 35606 this.queue = []; 35607 this.workers = []; 35608 this.workersResolve = []; 35609 this.workerStatus = 0; 35610 } 35611 } 35612 35613 const t = 0, n = 2, g$1 = 1, u = 2, T = 0, C$1 = 1, R = 10, it = 0, ct = 9, yt = 15, xt = 16, wt = 22, Ft = 37, Ct = 43, te$1 = 76, ae = 83, ge = 97, ue = 100, we = 103, Ae = 109, In = 165, Sn = 166, pi = 1000066e3; 35614 class Ii { 35615 constructor(){ 35616 this.vkFormat = 0, this.typeSize = 1, this.pixelWidth = 0, this.pixelHeight = 0, this.pixelDepth = 0, this.layerCount = 0, this.faceCount = 1, this.supercompressionScheme = 0, this.levels = [], this.dataFormatDescriptor = [ 35617 { 35618 vendorId: 0, 35619 descriptorType: 0, 35620 descriptorBlockSize: 0, 35621 versionNumber: 2, 35622 colorModel: 0, 35623 colorPrimaries: 1, 35624 transferFunction: 2, 35625 flags: 0, 35626 texelBlockDimension: [ 35627 0, 35628 0, 35629 0, 35630 0 35631 ], 35632 bytesPlane: [ 35633 0, 35634 0, 35635 0, 35636 0, 35637 0, 35638 0, 35639 0, 35640 0 35641 ], 35642 samples: [] 35643 } 35644 ], this.keyValue = {}, this.globalData = null; 35645 } 35646 } 35647 class Si { 35648 _nextUint8() { 35649 const t = this._dataView.getUint8(this._offset); 35650 return this._offset += 1, t; 35651 } 35652 _nextUint16() { 35653 const t = this._dataView.getUint16(this._offset, this._littleEndian); 35654 return this._offset += 2, t; 35655 } 35656 _nextUint32() { 35657 const t = this._dataView.getUint32(this._offset, this._littleEndian); 35658 return this._offset += 4, t; 35659 } 35660 _nextUint64() { 35661 const t = this._dataView.getUint32(this._offset, this._littleEndian) + 2 ** 32 * this._dataView.getUint32(this._offset + 4, this._littleEndian); 35662 return this._offset += 8, t; 35663 } 35664 _nextInt32() { 35665 const t = this._dataView.getInt32(this._offset, this._littleEndian); 35666 return this._offset += 4, t; 35667 } 35668 _nextUint8Array(t) { 35669 const e = new Uint8Array(this._dataView.buffer, this._dataView.byteOffset + this._offset, t); 35670 return this._offset += t, e; 35671 } 35672 _skip(t) { 35673 return this._offset += t, this; 35674 } 35675 _scan(t, e) { 35676 void 0 === e && (e = 0); 35677 const n = this._offset; 35678 let i = 0; 35679 for(; this._dataView.getUint8(this._offset) !== e && i < t;)i++, this._offset++; 35680 return i < t && this._offset++, new Uint8Array(this._dataView.buffer, this._dataView.byteOffset + n, i); 35681 } 35682 constructor(t, e, n, i){ 35683 this._dataView = void 0, this._littleEndian = void 0, this._offset = void 0, this._dataView = new DataView(t.buffer, t.byteOffset + e, n), this._littleEndian = i, this._offset = 0; 35684 } 35685 } 35686 const Oi = [ 35687 171, 35688 75, 35689 84, 35690 88, 35691 32, 35692 50, 35693 48, 35694 187, 35695 13, 35696 10, 35697 26, 35698 10 35699 ]; 35700 function Ti(t) { 35701 return (new TextDecoder).decode(t); 35702 } 35703 function Pi(t) { 35704 const e = new Uint8Array(t.buffer, t.byteOffset, Oi.length); 35705 if (e[0] !== Oi[0] || e[1] !== Oi[1] || e[2] !== Oi[2] || e[3] !== Oi[3] || e[4] !== Oi[4] || e[5] !== Oi[5] || e[6] !== Oi[6] || e[7] !== Oi[7] || e[8] !== Oi[8] || e[9] !== Oi[9] || e[10] !== Oi[10] || e[11] !== Oi[11]) throw new Error("Missing KTX 2.0 identifier."); 35706 const n = new Ii, i = 17 * Uint32Array.BYTES_PER_ELEMENT, s = new Si(t, Oi.length, i, true);
vendor: 4,191 bytes, lines 35707-35804
35707 n.vkFormat = s._nextUint32(), n.typeSize = s._nextUint32(), n.pixelWidth = s._nextUint32(), n.pixelHeight = s._nextUint32(), n.pixelDepth = s._nextUint32(), n.layerCount = s._nextUint32(), n.faceCount = s._nextUint32(); 35708 const a = s._nextUint32(); 35709 n.supercompressionScheme = s._nextUint32(); 35710 const r = s._nextUint32(), o = s._nextUint32(), l = s._nextUint32(), f = s._nextUint32(), h = s._nextUint64(), U = s._nextUint64(), c = new Si(t, Oi.length + i, 3 * a * 8, true); 35711 for(let e = 0; e < a; e++)n.levels.push({ 35712 levelData: new Uint8Array(t.buffer, t.byteOffset + c._nextUint64(), c._nextUint64()), 35713 uncompressedByteLength: c._nextUint64() 35714 }); 35715 const _ = new Si(t, r, o, true), p = { 35716 vendorId: _._skip(4)._nextUint16(), 35717 descriptorType: _._nextUint16(), 35718 versionNumber: _._nextUint16(), 35719 descriptorBlockSize: _._nextUint16(), 35720 colorModel: _._nextUint8(), 35721 colorPrimaries: _._nextUint8(), 35722 transferFunction: _._nextUint8(), 35723 flags: _._nextUint8(), 35724 texelBlockDimension: [ 35725 _._nextUint8(), 35726 _._nextUint8(), 35727 _._nextUint8(), 35728 _._nextUint8() 35729 ], 35730 bytesPlane: [ 35731 _._nextUint8(), 35732 _._nextUint8(), 35733 _._nextUint8(), 35734 _._nextUint8(), 35735 _._nextUint8(), 35736 _._nextUint8(), 35737 _._nextUint8(), 35738 _._nextUint8() 35739 ], 35740 samples: [] 35741 }, g = (p.descriptorBlockSize / 4 - 6) / 4; 35742 for(let t = 0; t < g; t++){ 35743 const e = { 35744 bitOffset: _._nextUint16(), 35745 bitLength: _._nextUint8(), 35746 channelType: _._nextUint8(), 35747 samplePosition: [ 35748 _._nextUint8(), 35749 _._nextUint8(), 35750 _._nextUint8(), 35751 _._nextUint8() 35752 ], 35753 sampleLower: -Infinity, 35754 sampleUpper: Infinity 35755 }; 35756 64 & e.channelType ? (e.sampleLower = _._nextInt32(), e.sampleUpper = _._nextInt32()) : (e.sampleLower = _._nextUint32(), e.sampleUpper = _._nextUint32()), p.samples[t] = e; 35757 } 35758 n.dataFormatDescriptor.length = 0, n.dataFormatDescriptor.push(p); 35759 const y = new Si(t, l, f, true); 35760 for(; y._offset < f;){ 35761 const t = y._nextUint32(), e = y._scan(t), i = Ti(e); 35762 if (n.keyValue[i] = y._nextUint8Array(t - e.byteLength - 1), i.match(/^ktx/i)) { 35763 const t = Ti(n.keyValue[i]); 35764 n.keyValue[i] = t.substring(0, t.lastIndexOf("\0")); 35765 } 35766 y._skip(t % 4 ? 4 - t % 4 : 0); 35767 } 35768 if (U <= 0) return n; 35769 const x = new Si(t, h, U, true), u = x._nextUint16(), b = x._nextUint16(), d = x._nextUint32(), w = x._nextUint32(), m = x._nextUint32(), D = x._nextUint32(), B = []; 35770 for(let t = 0; t < a; t++)B.push({ 35771 imageFlags: x._nextUint32(), 35772 rgbSliceByteOffset: x._nextUint32(), 35773 rgbSliceByteLength: x._nextUint32(), 35774 alphaSliceByteOffset: x._nextUint32(), 35775 alphaSliceByteLength: x._nextUint32() 35776 }); 35777 const L = h + x._offset, v = L + d, A = v + w, k = A + m, V = new Uint8Array(t.buffer, t.byteOffset + L, d), I = new Uint8Array(t.buffer, t.byteOffset + v, w), S = new Uint8Array(t.buffer, t.byteOffset + A, m), F = new Uint8Array(t.buffer, t.byteOffset + k, D); 35778 return n.globalData = { 35779 endpointCount: u, 35780 selectorCount: b, 35781 imageDescs: B, 35782 endpointsData: V, 35783 selectorsData: I, 35784 tablesData: S, 35785 extendedData: F 35786 }, n; 35787 } 35788 35789 let A, I, B; 35790 const g = { 35791 env: { 35792 emscripten_notify_memory_growth: function(A) { 35793 B = new Uint8Array(I.exports.memory.buffer); 35794 } 35795 } 35796 }; 35797 class Q { 35798 init() { 35799 return A || (A = "undefined" != typeof fetch ? fetch("data:application/wasm;base64," + C).then((A)=>A.arrayBuffer()).then((A)=>WebAssembly.instantiate(A, g)).then(this._init) : WebAssembly.instantiate(Buffer.from(C, "base64"), g).then(this._init), A); 35800 } 35801 _init(A) { 35802 I = A.instance, g.env.emscripten_notify_memory_growth(0); 35803 } 35804 decode(A, g = 0) {
35805 if (!I) throw new Error("ZSTDDecoder: Await .init() before decoding."); 35806 const Q = A.byteLength, C = I.exports.malloc(Q); 35807 B.set(A, C), g = g || Number(I.exports.ZSTD_findDecompressedSize(C, Q)); 35808 const E = I.exports.malloc(g), i = I.exports.ZSTD_decompress(E, g, C, Q), D = B.slice(E, E + i); 35809 return I.exports.free(C), I.exports.free(E), D; 35810 } 35811 } 35812 const C =
vendor: 38,978 bytes, line 35812
35812"AGFzbQEAAAABpQEVYAF/AX9gAn9/AGADf39/AX9gBX9/f39/AX9gAX8AYAJ/fwF/YAR/f39/AX9gA39/fwBgBn9/f39/fwF/YAd/f39/f39/AX9gAn9/AX5gAn5+AX5gAABgBX9/f39/AGAGf39/f39/AGAIf39/f39/f38AYAl/f39/f39/f38AYAABf2AIf39/f39/f38Bf2ANf39/f39/f39/f39/fwF/YAF/AX4CJwEDZW52H2Vtc2NyaXB0ZW5fbm90aWZ5X21lbW9yeV9ncm93dGgABANpaAEFAAAFAgEFCwACAQABAgIFBQcAAwABDgsBAQcAEhMHAAUBDAQEAAANBwQCAgYCBAgDAwMDBgEACQkHBgICAAYGAgQUBwYGAwIGAAMCAQgBBwUGCgoEEQAEBAEIAwgDBQgDEA8IAAcABAUBcAECAgUEAQCAAgYJAX8BQaCgwAILB2AHBm1lbW9yeQIABm1hbGxvYwAoBGZyZWUAJgxaU1REX2lzRXJyb3IAaBlaU1REX2ZpbmREZWNvbXByZXNzZWRTaXplAFQPWlNURF9kZWNvbXByZXNzAEoGX3N0YXJ0ACQJBwEAQQELASQKussBaA8AIAAgACgCBCABajYCBAsZACAAKAIAIAAoAgRBH3F0QQAgAWtBH3F2CwgAIABBiH9LC34BBH9BAyEBIAAoAgQiA0EgTQRAIAAoAggiASAAKAIQTwRAIAAQDQ8LIAAoAgwiAiABRgRAQQFBAiADQSBJGw8LIAAgASABIAJrIANBA3YiBCABIARrIAJJIgEbIgJrIgQ2AgggACADIAJBA3RrNgIEIAAgBCgAADYCAAsgAQsUAQF/IAAgARACIQIgACABEAEgAgv3AQECfyACRQRAIABCADcCACAAQQA2AhAgAEIANwIIQbh/DwsgACABNgIMIAAgAUEEajYCECACQQRPBEAgACABIAJqIgFBfGoiAzYCCCAAIAMoAAA2AgAgAUF/ai0AACIBBEAgAEEIIAEQFGs2AgQgAg8LIABBADYCBEF/DwsgACABNgIIIAAgAS0AACIDNgIAIAJBfmoiBEEBTQRAIARBAWtFBEAgACABLQACQRB0IANyIgM2AgALIAAgAS0AAUEIdCADajYCAAsgASACakF/ai0AACIBRQRAIABBADYCBEFsDwsgAEEoIAEQFCACQQN0ams2AgQgAgsWACAAIAEpAAA3AAAgACABKQAINwAICy8BAX8gAUECdEGgHWooAgAgACgCAEEgIAEgACgCBGprQR9xdnEhAiAAIAEQASACCyEAIAFCz9bTvtLHq9lCfiAAfEIfiUKHla+vmLbem55/fgsdAQF/IAAoAgggACgCDEYEfyAAKAIEQSBGBUEACwuCBAEDfyACQYDAAE8EQCAAIAEgAhBnIAAPCyAAIAJqIQMCQCAAIAFzQQNxRQRAAkAgAkEBSARAIAAhAgwBCyAAQQNxRQRAIAAhAgwBCyAAIQIDQCACIAEtAAA6AAAgAUEBaiEBIAJBAWoiAiADTw0BIAJBA3ENAAsLAkAgA0F8cSIEQcAASQ0AIAIgBEFAaiIFSw0AA0AgAiABKAIANgIAIAIgASgCBDYCBCACIAEoAgg2AgggAiABKAIMNgIMIAIgASgCEDYCECACIAEoAhQ2AhQgAiABKAIYNgIYIAIgASgCHDYCHCACIAEoAiA2AiAgAiABKAIkNgIkIAIgASgCKDYCKCACIAEoAiw2AiwgAiABKAIwNgIwIAIgASgCNDYCNCACIAEoAjg2AjggAiABKAI8NgI8IAFBQGshASACQUBrIgIgBU0NAAsLIAIgBE8NAQNAIAIgASgCADYCACABQQRqIQEgAkEEaiICIARJDQALDAELIANBBEkEQCAAIQIMAQsgA0F8aiIEIABJBEAgACECDAELIAAhAgNAIAIgAS0AADoAACACIAEtAAE6AAEgAiABLQACOgACIAIgAS0AAzoAAyABQQRqIQEgAkEEaiICIARNDQALCyACIANJBEADQCACIAEtAAA6AAAgAUEBaiEBIAJBAWoiAiADRw0ACwsgAAsMACAAIAEpAAA3AAALQQECfyAAKAIIIgEgACgCEEkEQEEDDwsgACAAKAIEIgJBB3E2AgQgACABIAJBA3ZrIgE2AgggACABKAAANgIAQQALDAAgACABKAIANgAAC/cCAQJ/AkAgACABRg0AAkAgASACaiAASwRAIAAgAmoiBCABSw0BCyAAIAEgAhALDwsgACABc0EDcSEDAkACQCAAIAFJBEAgAwRAIAAhAwwDCyAAQQNxRQRAIAAhAwwCCyAAIQMDQCACRQ0EIAMgAS0AADoAACABQQFqIQEgAkF/aiECIANBAWoiA0EDcQ0ACwwBCwJAIAMNACAEQQNxBEADQCACRQ0FIAAgAkF/aiICaiIDIAEgAmotAAA6AAAgA0EDcQ0ACwsgAkEDTQ0AA0AgACACQXxqIgJqIAEgAmooAgA2AgAgAkEDSw0ACwsgAkUNAgNAIAAgAkF/aiICaiABIAJqLQAAOgAAIAINAAsMAgsgAkEDTQ0AIAIhBANAIAMgASgCADYCACABQQRqIQEgA0EEaiEDIARBfGoiBEEDSw0ACyACQQNxIQILIAJFDQADQCADIAEtAAA6AAAgA0EBaiEDIAFBAWohASACQX9qIgINAAsLIAAL8wICAn8BfgJAIAJFDQAgACACaiIDQX9qIAE6AAAgACABOgAAIAJBA0kNACADQX5qIAE6AAAgACABOgABIANBfWogAToAACAAIAE6AAIgAkEHSQ0AIANBfGogAToAACAAIAE6AAMgAkEJSQ0AIABBACAAa0EDcSIEaiIDIAFB/wFxQYGChAhsIgE2AgAgAyACIARrQXxxIgRqIgJBfGogATYCACAEQQlJDQAgAyABNgIIIAMgATYCBCACQXhqIAE2AgAgAkF0aiABNgIAIARBGUkNACADIAE2AhggAyABNgIUIAMgATYCECADIAE2AgwgAkFwaiABNgIAIAJBbGogATYCACACQWhqIAE2AgAgAkFkaiABNgIAIAQgA0EEcUEYciIEayICQSBJDQAgAa0iBUIghiAFhCEFIAMgBGohAQNAIAEgBTcDGCABIAU3AxAgASAFNwMIIAEgBTcDACABQSBqIQEgAkFgaiICQR9LDQALCyAACy8BAn8gACgCBCAAKAIAQQJ0aiICLQACIQMgACACLwEAIAEgAi0AAxAIajYCACADCy8BAn8gACgCBCAAKAIAQQJ0aiICLQACIQMgACACLwEAIAEgAi0AAxAFajYCACADCx8AIAAgASACKAIEEAg2AgAgARAEGiAAIAJBCGo2AgQLCAAgAGdBH3MLugUBDX8jAEEQayIKJAACfyAEQQNNBEAgCkEANgIMIApBDGogAyAEEAsaIAAgASACIApBDGpBBBAVIgBBbCAAEAMbIAAgACAESxsMAQsgAEEAIAEoAgBBAXRBAmoQECENQVQgAygAACIGQQ9xIgBBCksNABogAiAAQQVqNgIAIAMgBGoiAkF8aiEMIAJBeWohDiACQXtqIRAgAEEGaiELQQQhBSAGQQR2IQRBICAAdCIAQQFyIQkgASgCACEPQQAhAiADIQYCQANAIAlBAkggAiAPS3JFBEAgAiEHAkAgCARAA0AgBEH//wNxQf//A0YEQCAHQRhqIQcgBiAQSQR/IAZBAmoiBigAACAFdgUgBUEQaiEFIARBEHYLIQQMAQsLA0AgBEEDcSIIQQNGBEAgBUECaiEFIARBAnYhBCAHQQNqIQcMAQsLIAcgCGoiByAPSw0EIAVBAmohBQNAIAIgB0kEQCANIAJBAXRqQQA7AQAgAkEBaiECDAELCyAGIA5LQQAgBiAFQQN1aiIHIAxLG0UEQCAHKAAAIAVBB3EiBXYhBAwCCyAEQQJ2IQQLIAYhBwsCfyALQX9qIAQgAEF/anEiBiAAQQF0QX9qIgggCWsiEUkNABogBCAIcSIEQQAgESAEIABIG2shBiALCyEIIA0gAkEBdGogBkF/aiIEOwEAIAlBASAGayAEIAZBAUgbayEJA0AgCSAASARAIABBAXUhACALQX9qIQsMAQsLAn8gByAOS0EAIAcgBSAIaiIFQQN1aiIGIAxLG0UEQCAFQQdxDAELIAUgDCIGIAdrQQN0awshBSACQQFqIQIgBEUhCCAGKAAAIAVBH3F2IQQMAQsLQWwgCUEBRyAFQSBKcg0BGiABIAJBf2o2AgAgBiAFQQdqQQN1aiADawwBC0FQCyEAIApBEGokACAACwkAQQFBBSAAGwsMACAAIAEoAAA2AAALqgMBCn8jAEHwAGsiCiQAIAJBAWohDiAAQQhqIQtBgIAEIAVBf2p0QRB1IQxBACECQQEhBkEBIAV0IglBf2oiDyEIA0AgAiAORkUEQAJAIAEgAkEBdCINai8BACIHQf//A0YEQCALIAhBA3RqIAI2AgQgCEF/aiEIQQEhBwwBCyAGQQAgDCAHQRB0QRB1ShshBgsgCiANaiAHOwEAIAJBAWohAgwBCwsgACAFNgIEIAAgBjYCACAJQQN2IAlBAXZqQQNqIQxBACEAQQAhBkEAIQIDQCAGIA5GBEADQAJAIAAgCUYNACAKIAsgAEEDdGoiASgCBCIGQQF0aiICIAIvAQAiAkEBajsBACABIAUgAhAUayIIOgADIAEgAiAIQf8BcXQgCWs7AQAgASAEIAZBAnQiAmooAgA6AAIgASACIANqKAIANgIEIABBAWohAAwBCwsFIAEgBkEBdGouAQAhDUEAIQcDQCAHIA1ORQRAIAsgAkEDdGogBjYCBANAIAIgDGogD3EiAiAISw0ACyAHQQFqIQcMAQsLIAZBAWohBgwBCwsgCkHwAGokAAsjAEIAIAEQCSAAhUKHla+vmLbem55/fkLj3MqV/M7y9YV/fAsQACAAQn43AwggACABNgIACyQBAX8gAARAIAEoAgQiAgRAIAEoAgggACACEQEADwsgABAmCwsfACAAIAEgAi8BABAINgIAIAEQBBogACACQQRqNgIEC0oBAX9BoCAoAgAiASAAaiIAQX9MBEBBiCBBMDYCAEF/DwsCQCAAPwBBEHRNDQAgABBmDQBBiCBBMDYCAEF/DwtBoCAgADYCACABC9cBAQh/Qbp/IQoCQCACKAIEIgggAigCACIJaiIOIAEgAGtLDQBBbCEKIAkgBCADKAIAIgtrSw0AIAAgCWoiBCACKAIIIgxrIQ0gACABQWBqIg8gCyAJQQAQKSADIAkgC2o2AgACQAJAIAwgBCAFa00EQCANIQUMAQsgDCAEIAZrSw0CIAcgDSAFayIAaiIBIAhqIAdNBEAgBCABIAgQDxoMAgsgBCABQQAgAGsQDyEBIAIgACAIaiIINgIEIAEgAGshBAsgBCAPIAUgCEEBECkLIA4hCgsgCgubAgEBfyMAQYABayINJAAgDSADNgJ8AkAgAkEDSwRAQX8hCQwBCwJAAkACQAJAIAJBAWsOAwADAgELIAZFBEBBuH8hCQwEC0FsIQkgBS0AACICIANLDQMgACAHIAJBAnQiAmooAgAgAiAIaigCABA7IAEgADYCAEEBIQkMAwsgASAJNgIAQQAhCQwCCyAKRQRAQWwhCQwCC0EAIQkgC0UgDEEZSHINAUEIIAR0QQhqIQBBACECA0AgAiAATw0CIAJBQGshAgwAAAsAC0FsIQkgDSANQfwAaiANQfgAaiAFIAYQFSICEAMNACANKAJ4IgMgBEsNACAAIA0gDSgCfCAHIAggAxAYIAEgADYCACACIQkLIA1BgAFqJAAgCQsLACAAIAEgAhALGgsQACAALwAAIAAtAAJBEHRyCy8AAn9BuH8gAUEISQ0AGkFyIAAoAAQiAEF3Sw0AGkG4fyAAQQhqIgAgACABSxsLCwkAIAAgATsAAAsDAAELigYBBX8gACAAKAIAIgVBfnE2AgBBACAAIAVBAXZqQYQgKAIAIgQgAEYbIQECQAJAIAAoAgQiAkUNACACKAIAIgNBAXENACACQQhqIgUgA0EBdkF4aiIDQQggA0EISxtnQR9zQQJ0QYAfaiIDKAIARgRAIAMgAigCDDYCAAsgAigCCCIDBEAgAyACKAIMNgIECyACKAIMIgMEQCADIAIoAgg2AgALIAIgAigCACAAKAIAQX5xajYCAEGEICEAAkACQCABRQ0AIAEgAjYCBCABKAIAIgNBAXENASADQQF2QXhqIgNBCCADQQhLG2dBH3NBAnRBgB9qIgMoAgAgAUEIakYEQCADIAEoAgw2AgALIAEoAggiAwRAIAMgASgCDDYCBAsgASgCDCIDBEAgAyABKAIINgIAQYQgKAIAIQQLIAIgAigCACABKAIAQX5xajYCACABIARGDQAgASABKAIAQQF2akEEaiEACyAAIAI2AgALIAIoAgBBAXZBeGoiAEEIIABBCEsbZ0Efc0ECdEGAH2oiASgCACEAIAEgBTYCACACIAA2AgwgAkEANgIIIABFDQEgACAFNgIADwsCQCABRQ0AIAEoAgAiAkEBcQ0AIAJBAXZBeGoiAkEIIAJBCEsbZ0Efc0ECdEGAH2oiAigCACABQQhqRgRAIAIgASgCDDYCAAsgASgCCCICBEAgAiABKAIMNgIECyABKAIMIgIEQCACIAEoAgg2AgBBhCAoAgAhBAsgACAAKAIAIAEoAgBBfnFqIgI2AgACQCABIARHBEAgASABKAIAQQF2aiAANgIEIAAoAgAhAgwBC0GEICAANgIACyACQQF2QXhqIgFBCCABQQhLG2dBH3NBAnRBgB9qIgIoAgAhASACIABBCGoiAjYCACAAIAE2AgwgAEEANgIIIAFFDQEgASACNgIADwsgBUEBdkF4aiIBQQggAUEISxtnQR9zQQJ0QYAfaiICKAIAIQEgAiAAQQhqIgI2AgAgACABNgIMIABBADYCCCABRQ0AIAEgAjYCAAsLDgAgAARAIABBeGoQJQsLgAIBA38CQCAAQQ9qQXhxQYQgKAIAKAIAQQF2ayICEB1Bf0YNAAJAQYQgKAIAIgAoAgAiAUEBcQ0AIAFBAXZBeGoiAUEIIAFBCEsbZ0Efc0ECdEGAH2oiASgCACAAQQhqRgRAIAEgACgCDDYCAAsgACgCCCIBBEAgASAAKAIMNgIECyAAKAIMIgFFDQAgASAAKAIINgIAC0EBIQEgACAAKAIAIAJBAXRqIgI2AgAgAkEBcQ0AIAJBAXZBeGoiAkEIIAJBCEsbZ0Efc0ECdEGAH2oiAygCACECIAMgAEEIaiIDNgIAIAAgAjYCDCAAQQA2AgggAkUNACACIAM2AgALIAELtwIBA38CQAJAIABBASAAGyICEDgiAA0AAkACQEGEICgCACIARQ0AIAAoAgAiA0EBcQ0AIAAgA0EBcjYCACADQQF2QXhqIgFBCCABQQhLG2dBH3NBAnRBgB9qIgEoAgAgAEEIakYEQCABIAAoAgw2AgALIAAoAggiAQRAIAEgACgCDDYCBAsgACgCDCIBBEAgASAAKAIINgIACyACECchAkEAIQFBhCAoAgAhACACDQEgACAAKAIAQX5xNgIAQQAPCyACQQ9qQXhxIgMQHSICQX9GDQIgAkEHakF4cSIAIAJHBEAgACACaxAdQX9GDQMLAkBBhCAoAgAiAUUEQEGAICAANgIADAELIAAgATYCBAtBhCAgADYCACAAIANBAXRBAXI2AgAMAQsgAEUNAQsgAEEIaiEBCyABC7kDAQJ/IAAgA2ohBQJAIANBB0wEQANAIAAgBU8NAiAAIAItAAA6AAAgAEEBaiEAIAJBAWohAgwAAAsACyAEQQFGBEACQCAAIAJrIgZBB00EQCAAIAItAAA6AAAgACACLQABOgABIAAgAi0AAjoAAiAAIAItAAM6AAMgAEEEaiACIAZBAnQiBkHAHmooAgBqIgIQFyACIAZB4B5qKAIAayECDAELIAAgAhAMCyACQQhqIQIgAEEIaiEACwJAAkACQAJAIAUgAU0EQCAAIANqIQEgBEEBRyAAIAJrQQ9Kcg0BA0AgACACEAwgAkEIaiECIABBCGoiACABSQ0ACwwFCyAAIAFLBEAgACEBDAQLIARBAUcgACACa0EPSnINASAAIQMgAiEEA0AgAyAEEAwgBEEIaiEEIANBCGoiAyABSQ0ACwwCCwNAIAAgAhAHIAJBEGohAiAAQRBqIgAgAUkNAAsMAwsgACEDIAIhBANAIAMgBBAHIARBEGohBCADQRBqIgMgAUkNAAsLIAIgASAAa2ohAgsDQCABIAVPDQEgASACLQAAOgAAIAFBAWohASACQQFqIQIMAAALAAsLQQECfyAAIAAoArjgASIDNgLE4AEgACgCvOABIQQgACABNgK84AEgACABIAJqNgK44AEgACABIAQgA2tqNgLA4AELpgEBAX8gACAAKALs4QEQFjYCyOABIABCADcD+OABIABCADcDuOABIABBwOABakIANwMAIABBqNAAaiIBQYyAgOAANgIAIABBADYCmOIBIABCADcDiOEBIABCAzcDgOEBIABBrNABakHgEikCADcCACAAQbTQAWpB6BIoAgA2AgAgACABNgIMIAAgAEGYIGo2AgggACAAQaAwajYCBCAAIABBEGo2AgALYQEBf0G4fyEDAkAgAUEDSQ0AIAIgABAhIgFBA3YiADYCCCACIAFBAXE2AgQgAiABQQF2QQNxIgM2AgACQCADQX9qIgFBAksNAAJAIAFBAWsOAgEAAgtBbA8LIAAhAwsgAwsMACAAIAEgAkEAEC4LiAQCA38CfiADEBYhBCAAQQBBKBAQIQAgBCACSwRAIAQPCyABRQRAQX8PCwJAAkAgA0EBRg0AIAEoAAAiBkGo6r5pRg0AQXYhAyAGQXBxQdDUtMIBRw0BQQghAyACQQhJDQEgAEEAQSgQECEAIAEoAAQhASAAQQE2AhQgACABrTcDAEEADwsgASACIAMQLyIDIAJLDQAgACADNgIYQXIhAyABIARqIgVBf2otAAAiAkEIcQ0AIAJBIHEiBkUEQEFwIQMgBS0AACIFQacBSw0BIAVBB3GtQgEgBUEDdkEKaq2GIgdCA4h+IAd8IQggBEEBaiEECyACQQZ2IQMgAkECdiEFAkAgAkEDcUF/aiICQQJLBEBBACECDAELAkACQAJAIAJBAWsOAgECAAsgASAEai0AACECIARBAWohBAwCCyABIARqLwAAIQIgBEECaiEEDAELIAEgBGooAAAhAiAEQQRqIQQLIAVBAXEhBQJ+AkACQAJAIANBf2oiA0ECTQRAIANBAWsOAgIDAQtCfyAGRQ0DGiABIARqMQAADAMLIAEgBGovAACtQoACfAwCCyABIARqKAAArQwBCyABIARqKQAACyEHIAAgBTYCICAAIAI2AhwgACAHNwMAQQAhAyAAQQA2AhQgACAHIAggBhsiBzcDCCAAIAdCgIAIIAdCgIAIVBs+AhALIAMLWwEBf0G4fyEDIAIQFiICIAFNBH8gACACakF/ai0AACIAQQNxQQJ0QaAeaigCACACaiAAQQZ2IgFBAnRBsB5qKAIAaiAAQSBxIgBFaiABRSAAQQV2cWoFQbh/CwsdACAAKAKQ4gEQWiAAQQA2AqDiASAAQgA3A5DiAQu1AwEFfyMAQZACayIKJABBuH8hBgJAIAVFDQAgBCwAACIIQf8BcSEHAkAgCEF/TARAIAdBgn9qQQF2IgggBU8NAkFsIQYgB0GBf2oiBUGAAk8NAiAEQQFqIQdBACEGA0AgBiAFTwRAIAUhBiAIIQcMAwUgACAGaiAHIAZBAXZqIgQtAABBBHY6AAAgACAGQQFyaiAELQAAQQ9xOgAAIAZBAmohBgwBCwAACwALIAcgBU8NASAAIARBAWogByAKEFMiBhADDQELIAYhBEEAIQYgAUEAQTQQECEJQQAhBQNAIAQgBkcEQCAAIAZqIggtAAAiAUELSwRAQWwhBgwDBSAJIAFBAnRqIgEgASgCAEEBajYCACAGQQFqIQZBASAILQAAdEEBdSAFaiEFDAILAAsLQWwhBiAFRQ0AIAUQFEEBaiIBQQxLDQAgAyABNgIAQQFBASABdCAFayIDEBQiAXQgA0cNACAAIARqIAFBAWoiADoAACAJIABBAnRqIgAgACgCAEEBajYCACAJKAIEIgBBAkkgAEEBcXINACACIARBAWo2AgAgB0EBaiEGCyAKQZACaiQAIAYLxhEBDH8jAEHwAGsiBSQAQWwhCwJAIANBCkkNACACLwAAIQogAi8AAiEJIAIvAAQhByAFQQhqIAQQDgJAIAMgByAJIApqakEGaiIMSQ0AIAUtAAohCCAFQdgAaiACQQZqIgIgChAGIgsQAw0BIAVBQGsgAiAKaiICIAkQBiILEAMNASAFQShqIAIgCWoiAiAHEAYiCxADDQEgBUEQaiACIAdqIAMgDGsQBiILEAMNASAAIAFqIg9BfWohECAEQQRqIQZBASELIAAgAUEDakECdiIDaiIMIANqIgIgA2oiDiEDIAIhBCAMIQcDQCALIAMgEElxBEAgACAGIAVB2ABqIAgQAkECdGoiCS8BADsAACAFQdgAaiAJLQACEAEgCS0AAyELIAcgBiAFQUBrIAgQAkECdGoiCS8BADsAACAFQUBrIAktAAIQASAJLQADIQogBCAGIAVBKGogCBACQQJ0aiIJLwEAOwAAIAVBKGogCS0AAhABIAktAAMhCSADIAYgBUEQaiAIEAJBAnRqIg0vAQA7AAAgBUEQaiANLQACEAEgDS0AAyENIAAgC2oiCyAGIAVB2ABqIAgQAkECdGoiAC8BADsAACAFQdgAaiAALQACEAEgAC0AAyEAIAcgCmoiCiAGIAVBQGsgCBACQQJ0aiIHLwEAOwAAIAVBQGsgBy0AAhABIActAAMhByAEIAlqIgkgBiAFQShqIAgQAkECdGoiBC8BADsAACAFQShqIAQtAAIQASAELQADIQQgAyANaiIDIAYgBUEQaiAIEAJBAnRqIg0vAQA7AAAgBUEQaiANLQACEAEgACALaiEAIAcgCmohByAEIAlqIQQgAyANLQADaiEDIAVB2ABqEA0gBUFAaxANciAFQShqEA1yIAVBEGoQDXJFIQsMAQsLIAQgDksgByACS3INAEFsIQsgACAMSw0BIAxBfWohCQNAQQAgACAJSSAFQdgAahAEGwRAIAAgBiAFQdgAaiAIEAJBAnRqIgovAQA7AAAgBUHYAGogCi0AAhABIAAgCi0AA2oiACAGIAVB2ABqIAgQAkECdGoiCi8BADsAACAFQdgAaiAKLQACEAEgACAKLQADaiEADAEFIAxBfmohCgNAIAVB2ABqEAQgACAKS3JFBEAgACAGIAVB2ABqIAgQAkECdGoiCS8BADsAACAFQdgAaiAJLQACEAEgACAJLQADaiEADAELCwNAIAAgCk0EQCAAIAYgBUHYAGogCBACQQJ0aiIJLwEAOwAAIAVB2ABqIAktAAIQASAAIAktAANqIQAMAQsLAkAgACAMTw0AIAAgBiAFQdgAaiAIEAIiAEECdGoiDC0AADoAACAMLQADQQFGBEAgBUHYAGogDC0AAhABDAELIAUoAlxBH0sNACAFQdgAaiAGIABBAnRqLQACEAEgBSgCXEEhSQ0AIAVBIDYCXAsgAkF9aiEMA0BBACAHIAxJIAVBQGsQBBsEQCAHIAYgBUFAayAIEAJBAnRqIgAvAQA7AAAgBUFAayAALQACEAEgByAALQADaiIAIAYgBUFAayAIEAJBAnRqIgcvAQA7AAAgBUFAayAHLQACEAEgACAHLQADaiEHDAEFIAJBfmohDANAIAVBQGsQBCAHIAxLckUEQCAHIAYgBUFAayAIEAJBAnRqIgAvAQA7AAAgBUFAayAALQACEAEgByAALQADaiEHDAELCwNAIAcgDE0EQCAHIAYgBUFAayAIEAJBAnRqIgAvAQA7AAAgBUFAayAALQACEAEgByAALQADaiEHDAELCwJAIAcgAk8NACAHIAYgBUFAayAIEAIiAEECdGoiAi0AADoAACACLQADQQFGBEAgBUFAayACLQACEAEMAQsgBSgCREEfSw0AIAVBQGsgBiAAQQJ0ai0AAhABIAUoAkRBIUkNACAFQSA2AkQLIA5BfWohAgNAQQAgBCACSSAFQShqEAQbBEAgBCAGIAVBKGogCBACQQJ0aiIALwEAOwAAIAVBKGogAC0AAhABIAQgAC0AA2oiACAGIAVBKGogCBACQQJ0aiIELwEAOwAAIAVBKGogBC0AAhABIAAgBC0AA2ohBAwBBSAOQX5qIQIDQCAFQShqEAQgBCACS3JFBEAgBCAGIAVBKGogCBACQQJ0aiIALwEAOwAAIAVBKGogAC0AAhABIAQgAC0AA2ohBAwBCwsDQCAEIAJNBEAgBCAGIAVBKGogCBACQQJ0aiIALwEAOwAAIAVBKGogAC0AAhABIAQgAC0AA2ohBAwBCwsCQCAEIA5PDQAgBCAGIAVBKGogCBACIgBBAnRqIgItAAA6AAAgAi0AA0EBRgRAIAVBKGogAi0AAhABDAELIAUoAixBH0sNACAFQShqIAYgAEECdGotAAIQASAFKAIsQSFJDQAgBUEgNgIsCwNAQQAgAyAQSSAFQRBqEAQbBEAgAyAGIAVBEGogCBACQQJ0aiIALwEAOwAAIAVBEGogAC0AAhABIAMgAC0AA2oiACAGIAVBEGogCBACQQJ0aiICLwEAOwAAIAVBEGogAi0AAhABIAAgAi0AA2ohAwwBBSAPQX5qIQIDQCAFQRBqEAQgAyACS3JFBEAgAyAGIAVBEGogCBACQQJ0aiIALwEAOwAAIAVBEGogAC0AAhABIAMgAC0AA2ohAwwBCwsDQCADIAJNBEAgAyAGIAVBEGogCBACQQJ0aiIALwEAOwAAIAVBEGogAC0AAhABIAMgAC0AA2ohAwwBCwsCQCADIA9PDQAgAyAGIAVBEGogCBACIgBBAnRqIgItAAA6AAAgAi0AA0EBRgRAIAVBEGogAi0AAhABDAELIAUoAhRBH0sNACAFQRBqIAYgAEECdGotAAIQASAFKAIUQSFJDQAgBUEgNgIUCyABQWwgBUHYAGoQCiAFQUBrEApxIAVBKGoQCnEgBUEQahAKcRshCwwJCwAACwALAAALAAsAAAsACwAACwALQWwhCwsgBUHwAGokACALC7UEAQ5/IwBBEGsiBiQAIAZBBGogABAOQVQhBQJAIARB3AtJDQAgBi0ABCEHIANB8ARqQQBB7AAQECEIIAdBDEsNACADQdwJaiIJIAggBkEIaiAGQQxqIAEgAhAxIhAQA0UEQCAGKAIMIgQgB0sNASADQdwFaiEPIANBpAVqIREgAEEEaiESIANBqAVqIQEgBCEFA0AgBSICQX9qIQUgCCACQQJ0aigCAEUNAAsgAkEBaiEOQQEhBQNAIAUgDk9FBEAgCCAFQQJ0IgtqKAIAIQwgASALaiAKNgIAIAVBAWohBSAKIAxqIQoMAQsLIAEgCjYCAEEAIQUgBigCCCELA0AgBSALRkUEQCABIAUgCWotAAAiDEECdGoiDSANKAIAIg1BAWo2AgAgDyANQQF0aiINIAw6AAEgDSAFOgAAIAVBAWohBQwBCwtBACEBIANBADYCqAUgBEF/cyAHaiEJQQEhBQNAIAUgDk9FBEAgCCAFQQJ0IgtqKAIAIQwgAyALaiABNgIAIAwgBSAJanQgAWohASAFQQFqIQUMAQsLIAcgBEEBaiIBIAJrIgRrQQFqIQgDQEEBIQUgBCAIT0UEQANAIAUgDk9FBEAgBUECdCIJIAMgBEE0bGpqIAMgCWooAgAgBHY2AgAgBUEBaiEFDAELCyAEQQFqIQQMAQsLIBIgByAPIAogESADIAIgARBkIAZBAToABSAGIAc6AAYgACAGKAIENgIACyAQIQULIAZBEGokACAFC8ENAQt/IwBB8ABrIgUkAEFsIQkCQCADQQpJDQAgAi8AACEKIAIvAAIhDCACLwAEIQYgBUEIaiAEEA4CQCADIAYgCiAMampBBmoiDUkNACAFLQAKIQcgBUHYAGogAkEGaiICIAoQBiIJEAMNASAFQUBrIAIgCmoiAiAMEAYiCRADDQEgBUEoaiACIAxqIgIgBhAGIgkQAw0BIAVBEGogAiAGaiADIA1rEAYiCRADDQEgACABaiIOQX1qIQ8gBEEEaiEGQQEhCSAAIAFBA2pBAnYiAmoiCiACaiIMIAJqIg0hAyAMIQQgCiECA0AgCSADIA9JcQRAIAYgBUHYAGogBxACQQF0aiIILQAAIQsgBUHYAGogCC0AARABIAAgCzoAACAGIAVBQGsgBxACQQF0aiIILQAAIQsgBUFAayAILQABEAEgAiALOgAAIAYgBUEoaiAHEAJBAXRqIggtAAAhCyAFQShqIAgtAAEQASAEIAs6AAAgBiAFQRBqIAcQAkEBdGoiCC0AACELIAVBEGogCC0AARABIAMgCzoAACAGIAVB2ABqIAcQAkEBdGoiCC0AACELIAVB2ABqIAgtAAEQASAAIAs6AAEgBiAFQUBrIAcQAkEBdGoiCC0AACELIAVBQGsgCC0AARABIAIgCzoAASAGIAVBKGogBxACQQF0aiIILQAAIQsgBUEoaiAILQABEAEgBCALOgABIAYgBUEQaiAHEAJBAXRqIggtAAAhCyAFQRBqIAgtAAEQASADIAs6AAEgA0ECaiEDIARBAmohBCACQQJqIQIgAEECaiEAIAkgBUHYAGoQDUVxIAVBQGsQDUVxIAVBKGoQDUVxIAVBEGoQDUVxIQkMAQsLIAQgDUsgAiAMS3INAEFsIQkgACAKSw0BIApBfWohCQNAIAVB2ABqEAQgACAJT3JFBEAgBiAFQdgAaiAHEAJBAXRqIggtAAAhCyAFQdgAaiAILQABEAEgACALOgAAIAYgBUHYAGogBxACQQF0aiIILQAAIQsgBUHYAGogCC0AARABIAAgCzoAASAAQQJqIQAMAQsLA0AgBUHYAGoQBCAAIApPckUEQCAGIAVB2ABqIAcQAkEBdGoiCS0AACEIIAVB2ABqIAktAAEQASAAIAg6AAAgAEEBaiEADAELCwNAIAAgCkkEQCAGIAVB2ABqIAcQAkEBdGoiCS0AACEIIAVB2ABqIAktAAEQASAAIAg6AAAgAEEBaiEADAELCyAMQX1qIQADQCAFQUBrEAQgAiAAT3JFBEAgBiAFQUBrIAcQAkEBdGoiCi0AACEJIAVBQGsgCi0AARABIAIgCToAACAGIAVBQGsgBxACQQF0aiIKLQAAIQkgBUFAayAKLQABEAEgAiAJOgABIAJBAmohAgwBCwsDQCAFQUBrEAQgAiAMT3JFBEAgBiAFQUBrIAcQAkEBdGoiAC0AACEKIAVBQGsgAC0AARABIAIgCjoAACACQQFqIQIMAQsLA0AgAiAMSQRAIAYgBUFAayAHEAJBAXRqIgAtAAAhCiAFQUBrIAAtAAEQASACIAo6AAAgAkEBaiECDAELCyANQX1qIQADQCAFQShqEAQgBCAAT3JFBEAgBiAFQShqIAcQAkEBdGoiAi0AACEKIAVBKGogAi0AARABIAQgCjoAACAGIAVBKGogBxACQQF0aiICLQAAIQogBUEoaiACLQABEAEgBCAKOgABIARBAmohBAwBCwsDQCAFQShqEAQgBCANT3JFBEAgBiAFQShqIAcQAkEBdGoiAC0AACECIAVBKGogAC0AARABIAQgAjoAACAEQQFqIQQMAQsLA0AgBCANSQRAIAYgBUEoaiAHEAJBAXRqIgAtAAAhAiAFQShqIAAtAAEQASAEIAI6AAAgBEEBaiEEDAELCwNAIAVBEGoQBCADIA9PckUEQCAGIAVBEGogBxACQQF0aiIALQAAIQIgBUEQaiAALQABEAEgAyACOgAAIAYgBUEQaiAHEAJBAXRqIgAtAAAhAiAFQRBqIAAtAAEQASADIAI6AAEgA0ECaiEDDAELCwNAIAVBEGoQBCADIA5PckUEQCAGIAVBEGogBxACQQF0aiIALQAAIQIgBUEQaiAALQABEAEgAyACOgAAIANBAWohAwwBCwsDQCADIA5JBEAgBiAFQRBqIAcQAkEBdGoiAC0AACECIAVBEGogAC0AARABIAMgAjoAACADQQFqIQMMAQsLIAFBbCAFQdgAahAKIAVBQGsQCnEgBUEoahAKcSAFQRBqEApxGyEJDAELQWwhCQsgBUHwAGokACAJC8oCAQR/IwBBIGsiBSQAIAUgBBAOIAUtAAIhByAFQQhqIAIgAxAGIgIQA0UEQCAEQQRqIQIgACABaiIDQX1qIQQDQCAFQQhqEAQgACAET3JFBEAgAiAFQQhqIAcQAkEBdGoiBi0AACEIIAVBCGogBi0AARABIAAgCDoAACACIAVBCGogBxACQQF0aiIGLQAAIQggBUEIaiAGLQABEAEgACAIOgABIABBAmohAAwBCwsDQCAFQQhqEAQgACADT3JFBEAgAiAFQQhqIAcQAkEBdGoiBC0AACEGIAVBCGogBC0AARABIAAgBjoAACAAQQFqIQAMAQsLA0AgACADT0UEQCACIAVBCGogBxACQQF0aiIELQAAIQYgBUEIaiAELQABEAEgACAGOgAAIABBAWohAAwBCwsgAUFsIAVBCGoQChshAgsgBUEgaiQAIAILtgMBCX8jAEEQayIGJAAgBkEANgIMIAZBADYCCEFUIQQCQAJAIANBQGsiDCADIAZBCGogBkEMaiABIAIQMSICEAMNACAGQQRqIAAQDiAGKAIMIgcgBi0ABEEBaksNASAAQQRqIQogBkEAOgAFIAYgBzoABiAAIAYoAgQ2AgAgB0EBaiEJQQEhBANAIAQgCUkEQCADIARBAnRqIgEoAgAhACABIAU2AgAgACAEQX9qdCAFaiEFIARBAWohBAwBCwsgB0EBaiEHQQAhBSAGKAIIIQkDQCAFIAlGDQEgAyAFIAxqLQAAIgRBAnRqIgBBASAEdEEBdSILIAAoAgAiAWoiADYCACAHIARrIQhBACEEAkAgC0EDTQRAA0AgBCALRg0CIAogASAEakEBdGoiACAIOgABIAAgBToAACAEQQFqIQQMAAALAAsDQCABIABPDQEgCiABQQF0aiIEIAg6AAEgBCAFOgAAIAQgCDoAAyAEIAU6AAIgBCAIOgAFIAQgBToABCAEIAg6AAcgBCAFOgAGIAFBBGohAQwAAAsACyAFQQFqIQUMAAALAAsgAiEECyAGQRBqJAAgBAutAQECfwJAQYQgKAIAIABHIAAoAgBBAXYiAyABa0F4aiICQXhxQQhHcgR/IAIFIAMQJ0UNASACQQhqC0EQSQ0AIAAgACgCACICQQFxIAAgAWpBD2pBeHEiASAAa0EBdHI2AgAgASAANgIEIAEgASgCAEEBcSAAIAJBAXZqIAFrIgJBAXRyNgIAQYQgIAEgAkH/////B3FqQQRqQYQgKAIAIABGGyABNgIAIAEQJQsLygIBBX8CQAJAAkAgAEEIIABBCEsbZ0EfcyAAaUEBR2oiAUEESSAAIAF2cg0AIAFBAnRB/B5qKAIAIgJFDQADQCACQXhqIgMoAgBBAXZBeGoiBSAATwRAIAIgBUEIIAVBCEsbZ0Efc0ECdEGAH2oiASgCAEYEQCABIAIoAgQ2AgALDAMLIARBHksNASAEQQFqIQQgAigCBCICDQALC0EAIQMgAUEgTw0BA0AgAUECdEGAH2ooAgAiAkUEQCABQR5LIQIgAUEBaiEBIAJFDQEMAwsLIAIgAkF4aiIDKAIAQQF2QXhqIgFBCCABQQhLG2dBH3NBAnRBgB9qIgEoAgBGBEAgASACKAIENgIACwsgAigCACIBBEAgASACKAIENgIECyACKAIEIgEEQCABIAIoAgA2AgALIAMgAygCAEEBcjYCACADIAAQNwsgAwvhCwINfwV+IwBB8ABrIgckACAHIAAoAvDhASIINgJcIAEgAmohDSAIIAAoAoDiAWohDwJAAkAgBUUEQCABIQQMAQsgACgCxOABIRAgACgCwOABIREgACgCvOABIQ4gAEEBNgKM4QFBACEIA0AgCEEDRwRAIAcgCEECdCICaiAAIAJqQazQAWooAgA2AkQgCEEBaiEIDAELC0FsIQwgB0EYaiADIAQQBhADDQEgB0EsaiAHQRhqIAAoAgAQEyAHQTRqIAdBGGogACgCCBATIAdBPGogB0EYaiAAKAIEEBMgDUFgaiESIAEhBEEAIQwDQCAHKAIwIAcoAixBA3RqKQIAIhRCEIinQf8BcSEIIAcoAkAgBygCPEEDdGopAgAiFUIQiKdB/wFxIQsgBygCOCAHKAI0QQN0aikCACIWQiCIpyEJIBVCIIghFyAUQiCIpyECAkAgFkIQiKdB/wFxIgNBAk8EQAJAIAZFIANBGUlyRQRAIAkgB0EYaiADQSAgBygCHGsiCiAKIANLGyIKEAUgAyAKayIDdGohCSAHQRhqEAQaIANFDQEgB0EYaiADEAUgCWohCQwBCyAHQRhqIAMQBSAJaiEJIAdBGGoQBBoLIAcpAkQhGCAHIAk2AkQgByAYNwNIDAELAkAgA0UEQCACBEAgBygCRCEJDAMLIAcoAkghCQwBCwJAAkAgB0EYakEBEAUgCSACRWpqIgNBA0YEQCAHKAJEQX9qIgMgA0VqIQkMAQsgA0ECdCAHaigCRCIJIAlFaiEJIANBAUYNAQsgByAHKAJINgJMCwsgByAHKAJENgJIIAcgCTYCRAsgF6chAyALBEAgB0EYaiALEAUgA2ohAwsgCCALakEUTwRAIAdBGGoQBBoLIAgEQCAHQRhqIAgQBSACaiECCyAHQRhqEAQaIAcgB0EYaiAUQhiIp0H/AXEQCCAUp0H//wNxajYCLCAHIAdBGGogFUIYiKdB/wFxEAggFadB//8DcWo2AjwgB0EYahAEGiAHIAdBGGogFkIYiKdB/wFxEAggFqdB//8DcWo2AjQgByACNgJgIAcoAlwhCiAHIAk2AmggByADNgJkAkACQAJAIAQgAiADaiILaiASSw0AIAIgCmoiEyAPSw0AIA0gBGsgC0Egak8NAQsgByAHKQNoNwMQIAcgBykDYDcDCCAEIA0gB0EIaiAHQdwAaiAPIA4gESAQEB4hCwwBCyACIARqIQggBCAKEAcgAkERTwRAIARBEGohAgNAIAIgCkEQaiIKEAcgAkEQaiICIAhJDQALCyAIIAlrIQIgByATNgJcIAkgCCAOa0sEQCAJIAggEWtLBEBBbCELDAILIBAgAiAOayICaiIKIANqIBBNBEAgCCAKIAMQDxoMAgsgCCAKQQAgAmsQDyEIIAcgAiADaiIDNgJkIAggAmshCCAOIQILIAlBEE8EQCADIAhqIQMDQCAIIAIQByACQRBqIQIgCEEQaiIIIANJDQALDAELAkAgCUEHTQRAIAggAi0AADoAACAIIAItAAE6AAEgCCACLQACOgACIAggAi0AAzoAAyAIQQRqIAIgCUECdCIDQcAeaigCAGoiAhAXIAIgA0HgHmooAgBrIQIgBygCZCEDDAELIAggAhAMCyADQQlJDQAgAyAIaiEDIAhBCGoiCCACQQhqIgJrQQ9MBEADQCAIIAIQDCACQQhqIQIgCEEIaiIIIANJDQAMAgALAAsDQCAIIAIQByACQRBqIQIgCEEQaiIIIANJDQALCyAHQRhqEAQaIAsgDCALEAMiAhshDCAEIAQgC2ogAhshBCAFQX9qIgUNAAsgDBADDQFBbCEMIAdBGGoQBEECSQ0BQQAhCANAIAhBA0cEQCAAIAhBAnQiAmpBrNABaiACIAdqKAJENgIAIAhBAWohCAwBCwsgBygCXCEIC0G6fyEMIA8gCGsiACANIARrSw0AIAQEfyAEIAggABALIABqBUEACyABayEMCyAHQfAAaiQAIAwLkRcCFn8FfiMAQdABayIHJAAgByAAKALw4QEiCDYCvAEgASACaiESIAggACgCgOIBaiETAkACQCAFRQRAIAEhAwwBCyAAKALE4AEhESAAKALA4AEhFSAAKAK84AEhDyAAQQE2AozhAUEAIQgDQCAIQQNHBEAgByAIQQJ0IgJqIAAgAmpBrNABaigCADYCVCAIQQFqIQgMAQsLIAcgETYCZCAHIA82AmAgByABIA9rNgJoQWwhECAHQShqIAMgBBAGEAMNASAFQQQgBUEESBshFyAHQTxqIAdBKGogACgCABATIAdBxABqIAdBKGogACgCCBATIAdBzABqIAdBKGogACgCBBATQQAhBCAHQeAAaiEMIAdB5ABqIQoDQCAHQShqEARBAksgBCAXTnJFBEAgBygCQCAHKAI8QQN0aikCACIdQhCIp0H/AXEhCyAHKAJQIAcoAkxBA3RqKQIAIh5CEIinQf8BcSEJIAcoAkggBygCREEDdGopAgAiH0IgiKchCCAeQiCIISAgHUIgiKchAgJAIB9CEIinQf8BcSIDQQJPBEACQCAGRSADQRlJckUEQCAIIAdBKGogA0EgIAcoAixrIg0gDSADSxsiDRAFIAMgDWsiA3RqIQggB0EoahAEGiADRQ0BIAdBKGogAxAFIAhqIQgMAQsgB0EoaiADEAUgCGohCCAHQShqEAQaCyAHKQJUISEgByAINgJUIAcgITcDWAwBCwJAIANFBEAgAgRAIAcoAlQhCAwDCyAHKAJYIQgMAQsCQAJAIAdBKGpBARAFIAggAkVqaiIDQQNGBEAgBygCVEF/aiIDIANFaiEIDAELIANBAnQgB2ooAlQiCCAIRWohCCADQQFGDQELIAcgBygCWDYCXAsLIAcgBygCVDYCWCAHIAg2AlQLICCnIQMgCQRAIAdBKGogCRAFIANqIQMLIAkgC2pBFE8EQCAHQShqEAQaCyALBEAgB0EoaiALEAUgAmohAgsgB0EoahAEGiAHIAcoAmggAmoiCSADajYCaCAKIAwgCCAJSxsoAgAhDSAHIAdBKGogHUIYiKdB/wFxEAggHadB//8DcWo2AjwgByAHQShqIB5CGIinQf8BcRAIIB6nQf//A3FqNgJMIAdBKGoQBBogB0EoaiAfQhiIp0H/AXEQCCEOIAdB8ABqIARBBHRqIgsgCSANaiAIazYCDCALIAg2AgggCyADNgIEIAsgAjYCACAHIA4gH6dB//8DcWo2AkQgBEEBaiEEDAELCyAEIBdIDQEgEkFgaiEYIAdB4ABqIRogB0HkAGohGyABIQMDQCAHQShqEARBAksgBCAFTnJFBEAgBygCQCAHKAI8QQN0aikCACIdQhCIp0H/AXEhCyAHKAJQIAcoAkxBA3RqKQIAIh5CEIinQf8BcSEIIAcoAkggBygCREEDdGopAgAiH0IgiKchCSAeQiCIISAgHUIgiKchDAJAIB9CEIinQf8BcSICQQJPBEACQCAGRSACQRlJckUEQCAJIAdBKGogAkEgIAcoAixrIgogCiACSxsiChAFIAIgCmsiAnRqIQkgB0EoahAEGiACRQ0BIAdBKGogAhAFIAlqIQkMAQsgB0EoaiACEAUgCWohCSAHQShqEAQaCyAHKQJUISEgByAJNgJUIAcgITcDWAwBCwJAIAJFBEAgDARAIAcoAlQhCQwDCyAHKAJYIQkMAQsCQAJAIAdBKGpBARAFIAkgDEVqaiICQQNGBEAgBygCVEF/aiICIAJFaiEJDAELIAJBAnQgB2ooAlQiCSAJRWohCSACQQFGDQELIAcgBygCWDYCXAsLIAcgBygCVDYCWCAHIAk2AlQLICCnIRQgCARAIAdBKGogCBAFIBRqIRQLIAggC2pBFE8EQCAHQShqEAQaCyALBEAgB0EoaiALEAUgDGohDAsgB0EoahAEGiAHIAcoAmggDGoiGSAUajYCaCAbIBogCSAZSxsoAgAhHCAHIAdBKGogHUIYiKdB/wFxEAggHadB//8DcWo2AjwgByAHQShqIB5CGIinQf8BcRAIIB6nQf//A3FqNgJMIAdBKGoQBBogByAHQShqIB9CGIinQf8BcRAIIB+nQf//A3FqNgJEIAcgB0HwAGogBEEDcUEEdGoiDSkDCCIdNwPIASAHIA0pAwAiHjcDwAECQAJAAkAgBygCvAEiDiAepyICaiIWIBNLDQAgAyAHKALEASIKIAJqIgtqIBhLDQAgEiADayALQSBqTw0BCyAHIAcpA8gBNwMQIAcgBykDwAE3AwggAyASIAdBCGogB0G8AWogEyAPIBUgERAeIQsMAQsgAiADaiEIIAMgDhAHIAJBEU8EQCADQRBqIQIDQCACIA5BEGoiDhAHIAJBEGoiAiAISQ0ACwsgCCAdpyIOayECIAcgFjYCvAEgDiAIIA9rSwRAIA4gCCAVa0sEQEFsIQsMAgsgESACIA9rIgJqIhYgCmogEU0EQCAIIBYgChAPGgwCCyAIIBZBACACaxAPIQggByACIApqIgo2AsQBIAggAmshCCAPIQILIA5BEE8EQCAIIApqIQoDQCAIIAIQByACQRBqIQIgCEEQaiIIIApJDQALDAELAkAgDkEHTQRAIAggAi0AADoAACAIIAItAAE6AAEgCCACLQACOgACIAggAi0AAzoAAyAIQQRqIAIgDkECdCIKQcAeaigCAGoiAhAXIAIgCkHgHmooAgBrIQIgBygCxAEhCgwBCyAIIAIQDAsgCkEJSQ0AIAggCmohCiAIQQhqIgggAkEIaiICa0EPTARAA0AgCCACEAwgAkEIaiECIAhBCGoiCCAKSQ0ADAIACwALA0AgCCACEAcgAkEQaiECIAhBEGoiCCAKSQ0ACwsgCxADBEAgCyEQDAQFIA0gDDYCACANIBkgHGogCWs2AgwgDSAJNgIIIA0gFDYCBCAEQQFqIQQgAyALaiEDDAILAAsLIAQgBUgNASAEIBdrIQtBACEEA0AgCyAFSARAIAcgB0HwAGogC0EDcUEEdGoiAikDCCIdNwPIASAHIAIpAwAiHjcDwAECQAJAAkAgBygCvAEiDCAepyICaiIKIBNLDQAgAyAHKALEASIJIAJqIhBqIBhLDQAgEiADayAQQSBqTw0BCyAHIAcpA8gBNwMgIAcgBykDwAE3AxggAyASIAdBGGogB0G8AWogEyAPIBUgERAeIRAMAQsgAiADaiEIIAMgDBAHIAJBEU8EQCADQRBqIQIDQCACIAxBEGoiDBAHIAJBEGoiAiAISQ0ACwsgCCAdpyIGayECIAcgCjYCvAEgBiAIIA9rSwRAIAYgCCAVa0sEQEFsIRAMAgsgESACIA9rIgJqIgwgCWogEU0EQCAIIAwgCRAPGgwCCyAIIAxBACACaxAPIQggByACIAlqIgk2AsQBIAggAmshCCAPIQILIAZBEE8EQCAIIAlqIQYDQCAIIAIQByACQRBqIQIgCEEQaiIIIAZJDQALDAELAkAgBkEHTQRAIAggAi0AADoAACAIIAItAAE6AAEgCCACLQACOgACIAggAi0AAzoAAyAIQQRqIAIgBkECdCIGQcAeaigCAGoiAhAXIAIgBkHgHmooAgBrIQIgBygCxAEhCQwBCyAIIAIQDAsgCUEJSQ0AIAggCWohBiAIQQhqIgggAkEIaiICa0EPTARAA0AgCCACEAwgAkEIaiECIAhBCGoiCCAGSQ0ADAIACwALA0AgCCACEAcgAkEQaiECIAhBEGoiCCAGSQ0ACwsgEBADDQMgC0EBaiELIAMgEGohAwwBCwsDQCAEQQNHBEAgACAEQQJ0IgJqQazQAWogAiAHaigCVDYCACAEQQFqIQQMAQsLIAcoArwBIQgLQbp/IRAgEyAIayIAIBIgA2tLDQAgAwR/IAMgCCAAEAsgAGoFQQALIAFrIRALIAdB0AFqJAAgEAslACAAQgA3AgAgAEEAOwEIIABBADoACyAAIAE2AgwgACACOgAKC7QFAQN/IwBBMGsiBCQAIABB/wFqIgVBfWohBgJAIAMvAQIEQCAEQRhqIAEgAhAGIgIQAw0BIARBEGogBEEYaiADEBwgBEEIaiAEQRhqIAMQHCAAIQMDQAJAIARBGGoQBCADIAZPckUEQCADIARBEGogBEEYahASOgAAIAMgBEEIaiAEQRhqEBI6AAEgBEEYahAERQ0BIANBAmohAwsgBUF+aiEFAn8DQEG6fyECIAMiASAFSw0FIAEgBEEQaiAEQRhqEBI6AAAgAUEBaiEDIARBGGoQBEEDRgRAQQIhAiAEQQhqDAILIAMgBUsNBSABIARBCGogBEEYahASOgABIAFBAmohA0EDIQIgBEEYahAEQQNHDQALIARBEGoLIQUgAyAFIARBGGoQEjoAACABIAJqIABrIQIMAwsgAyAEQRBqIARBGGoQEjoAAiADIARBCGogBEEYahASOgADIANBBGohAwwAAAsACyAEQRhqIAEgAhAGIgIQAw0AIARBEGogBEEYaiADEBwgBEEIaiAEQRhqIAMQHCAAIQMDQAJAIARBGGoQBCADIAZPckUEQCADIARBEGogBEEYahAROgAAIAMgBEEIaiAEQRhqEBE6AAEgBEEYahAERQ0BIANBAmohAwsgBUF+aiEFAn8DQEG6fyECIAMiASAFSw0EIAEgBEEQaiAEQRhqEBE6AAAgAUEBaiEDIARBGGoQBEEDRgRAQQIhAiAEQQhqDAILIAMgBUsNBCABIARBCGogBEEYahAROgABIAFBAmohA0EDIQIgBEEYahAEQQNHDQALIARBEGoLIQUgAyAFIARBGGoQEToAACABIAJqIABrIQIMAgsgAyAEQRBqIARBGGoQEToAAiADIARBCGogBEEYahAROgADIANBBGohAwwAAAsACyAEQTBqJAAgAgtpAQF/An8CQAJAIAJBB00NACABKAAAQbfIwuF+Rw0AIAAgASgABDYCmOIBQWIgAEEQaiABIAIQPiIDEAMNAhogAEKBgICAEDcDiOEBIAAgASADaiACIANrECoMAQsgACABIAIQKgtBAAsLrQMBBn8jAEGAAWsiAyQAQWIhCAJAIAJBCUkNACAAQZjQAGogAUEIaiIEIAJBeGogAEGY0AAQMyIFEAMiBg0AIANBHzYCfCADIANB/ABqIANB+ABqIAQgBCAFaiAGGyIEIAEgAmoiAiAEaxAVIgUQAw0AIAMoAnwiBkEfSw0AIAMoAngiB0EJTw0AIABBiCBqIAMgBkGAC0GADCAHEBggA0E0NgJ8IAMgA0H8AGogA0H4AGogBCAFaiIEIAIgBGsQFSIFEAMNACADKAJ8IgZBNEsNACADKAJ4IgdBCk8NACAAQZAwaiADIAZBgA1B4A4gBxAYIANBIzYCfCADIANB/ABqIANB+ABqIAQgBWoiBCACIARrEBUiBRADDQAgAygCfCIGQSNLDQAgAygCeCIHQQpPDQAgACADIAZBwBBB0BEgBxAYIAQgBWoiBEEMaiIFIAJLDQAgAiAFayEFQQAhAgNAIAJBA0cEQCAEKAAAIgZBf2ogBU8NAiAAIAJBAnRqQZzQAWogBjYCACACQQFqIQIgBEEEaiEEDAELCyAEIAFrIQgLIANBgAFqJAAgCAtGAQN/IABBCGohAyAAKAIEIQJBACEAA0AgACACdkUEQCABIAMgAEEDdGotAAJBFktqIQEgAEEBaiEADAELCyABQQggAmt0C4YDAQV/Qbh/IQcCQCADRQ0AIAItAAAiBEUEQCABQQA2AgBBAUG4fyADQQFGGw8LAn8gAkEBaiIFIARBGHRBGHUiBkF/Sg0AGiAGQX9GBEAgA0EDSA0CIAUvAABBgP4BaiEEIAJBA2oMAQsgA0ECSA0BIAItAAEgBEEIdHJBgIB+aiEEIAJBAmoLIQUgASAENgIAIAVBAWoiASACIANqIgNLDQBBbCEHIABBEGogACAFLQAAIgVBBnZBI0EJIAEgAyABa0HAEEHQEUHwEiAAKAKM4QEgACgCnOIBIAQQHyIGEAMiCA0AIABBmCBqIABBCGogBUEEdkEDcUEfQQggASABIAZqIAgbIgEgAyABa0GAC0GADEGAFyAAKAKM4QEgACgCnOIBIAQQHyIGEAMiCA0AIABBoDBqIABBBGogBUECdkEDcUE0QQkgASABIAZqIAgbIgEgAyABa0GADUHgDkGQGSAAKAKM4QEgACgCnOIBIAQQHyIAEAMNACAAIAFqIAJrIQcLIAcLrQMBCn8jAEGABGsiCCQAAn9BUiACQf8BSw0AGkFUIANBDEsNABogAkEBaiELIABBBGohCUGAgAQgA0F/anRBEHUhCkEAIQJBASEEQQEgA3QiB0F/aiIMIQUDQCACIAtGRQRAAkAgASACQQF0Ig1qLwEAIgZB//8DRgRAIAkgBUECdGogAjoAAiAFQX9qIQVBASEGDAELIARBACAKIAZBEHRBEHVKGyEECyAIIA1qIAY7AQAgAkEBaiECDAELCyAAIAQ7AQIgACADOwEAIAdBA3YgB0EBdmpBA2ohBkEAIQRBACECA0AgBCALRkUEQCABIARBAXRqLgEAIQpBACEAA0AgACAKTkUEQCAJIAJBAnRqIAQ6AAIDQCACIAZqIAxxIgIgBUsNAAsgAEEBaiEADAELCyAEQQFqIQQMAQsLQX8gAg0AGkEAIQIDfyACIAdGBH9BAAUgCCAJIAJBAnRqIgAtAAJBAXRqIgEgAS8BACIBQQFqOwEAIAAgAyABEBRrIgU6AAMgACABIAVB/wFxdCAHazsBACACQQFqIQIMAQsLCyEFIAhBgARqJAAgBQvjBgEIf0FsIQcCQCACQQNJDQACQAJAAkACQCABLQAAIgNBA3EiCUEBaw4DAwEAAgsgACgCiOEBDQBBYg8LIAJBBUkNAkEDIQYgASgAACEFAn8CQAJAIANBAnZBA3EiCEF+aiIEQQFNBEAgBEEBaw0BDAILIAVBDnZB/wdxIQQgBUEEdkH/B3EhAyAIRQwCCyAFQRJ2IQRBBCEGIAVBBHZB//8AcSEDQQAMAQsgBUEEdkH//w9xIgNBgIAISw0DIAEtAARBCnQgBUEWdnIhBEEFIQZBAAshBSAEIAZqIgogAksNAgJAIANBgQZJDQAgACgCnOIBRQ0AQQAhAgNAIAJBg4ABSw0BIAJBQGshAgwAAAsACwJ/IAlBA0YEQCABIAZqIQEgAEHw4gFqIQIgACgCDCEGIAUEQCACIAMgASAEIAYQXwwCCyACIAMgASAEIAYQXQwBCyAAQbjQAWohAiABIAZqIQEgAEHw4gFqIQYgAEGo0ABqIQggBQRAIAggBiADIAEgBCACEF4MAQsgCCAGIAMgASAEIAIQXAsQAw0CIAAgAzYCgOIBIABBATYCiOEBIAAgAEHw4gFqNgLw4QEgCUECRgRAIAAgAEGo0ABqNgIMCyAAIANqIgBBiOMBakIANwAAIABBgOMBakIANwAAIABB+OIBakIANwAAIABB8OIBakIANwAAIAoPCwJ/AkACQAJAIANBAnZBA3FBf2oiBEECSw0AIARBAWsOAgACAQtBASEEIANBA3YMAgtBAiEEIAEvAABBBHYMAQtBAyEEIAEQIUEEdgsiAyAEaiIFQSBqIAJLBEAgBSACSw0CIABB8OIBaiABIARqIAMQCyEBIAAgAzYCgOIBIAAgATYC8OEBIAEgA2oiAEIANwAYIABCADcAECAAQgA3AAggAEIANwAAIAUPCyAAIAM2AoDiASAAIAEgBGo2AvDhASAFDwsCfwJAAkACQCADQQJ2QQNxQX9qIgRBAksNACAEQQFrDgIAAgELQQEhByADQQN2DAILQQIhByABLwAAQQR2DAELIAJBBEkgARAhIgJBj4CAAUtyDQFBAyEHIAJBBHYLIQIgAEHw4gFqIAEgB2otAAAgAkEgahAQIQEgACACNgKA4gEgACABNgLw4QEgB0EBaiEHCyAHC0sAIABC+erQ0OfJoeThADcDICAAQgA3AxggAELP1tO+0ser2UI3AxAgAELW64Lu6v2J9eAANwMIIABCADcDACAAQShqQQBBKBAQGgviAgICfwV+IABBKGoiASAAKAJIaiECAn4gACkDACIDQiBaBEAgACkDECIEQgeJIAApAwgiBUIBiXwgACkDGCIGQgyJfCAAKQMgIgdCEol8IAUQGSAEEBkgBhAZIAcQGQwBCyAAKQMYQsXP2bLx5brqJ3wLIAN8IQMDQCABQQhqIgAgAk0EQEIAIAEpAAAQCSADhUIbiUKHla+vmLbem55/fkLj3MqV/M7y9YV/fCEDIAAhAQwBCwsCQCABQQRqIgAgAksEQCABIQAMAQsgASgAAK1Ch5Wvr5i23puef34gA4VCF4lCz9bTvtLHq9lCfkL5893xmfaZqxZ8IQMLA0AgACACSQRAIAAxAABCxc/ZsvHluuonfiADhUILiUKHla+vmLbem55/fiEDIABBAWohAAwBCwsgA0IhiCADhULP1tO+0ser2UJ+IgNCHYggA4VC+fPd8Zn2masWfiIDQiCIIAOFC+8CAgJ/BH4gACAAKQMAIAKtfDcDAAJAAkAgACgCSCIDIAJqIgRBH00EQCABRQ0BIAAgA2pBKGogASACECAgACgCSCACaiEEDAELIAEgAmohAgJ/IAMEQCAAQShqIgQgA2ogAUEgIANrECAgACAAKQMIIAQpAAAQCTcDCCAAIAApAxAgACkAMBAJNwMQIAAgACkDGCAAKQA4EAk3AxggACAAKQMgIABBQGspAAAQCTcDICAAKAJIIQMgAEEANgJIIAEgA2tBIGohAQsgAUEgaiACTQsEQCACQWBqIQMgACkDICEFIAApAxghBiAAKQMQIQcgACkDCCEIA0AgCCABKQAAEAkhCCAHIAEpAAgQCSEHIAYgASkAEBAJIQYgBSABKQAYEAkhBSABQSBqIgEgA00NAAsgACAFNwMgIAAgBjcDGCAAIAc3AxAgACAINwMICyABIAJPDQEgAEEoaiABIAIgAWsiBBAgCyAAIAQ2AkgLCy8BAX8gAEUEQEG2f0EAIAMbDwtBun8hBCADIAFNBH8gACACIAMQEBogAwVBun8LCy8BAX8gAEUEQEG2f0EAIAMbDwtBun8hBCADIAFNBH8gACACIAMQCxogAwVBun8LC6gCAQZ/IwBBEGsiByQAIABB2OABaikDAEKAgIAQViEIQbh/IQUCQCAEQf//B0sNACAAIAMgBBBCIgUQAyIGDQAgACgCnOIBIQkgACAHQQxqIAMgAyAFaiAGGyIKIARBACAFIAYbayIGEEAiAxADBEAgAyEFDAELIAcoAgwhBCABRQRAQbp/IQUgBEEASg0BCyAGIANrIQUgAyAKaiEDAkAgCQRAIABBADYCnOIBDAELAkACQAJAIARBBUgNACAAQdjgAWopAwBCgICACFgNAAwBCyAAQQA2ApziAQwBCyAAKAIIED8hBiAAQQA2ApziASAGQRRPDQELIAAgASACIAMgBSAEIAgQOSEFDAELIAAgASACIAMgBSAEIAgQOiEFCyAHQRBqJAAgBQtnACAAQdDgAWogASACIAAoAuzhARAuIgEQAwRAIAEPC0G4fyECAkAgAQ0AIABB7OABaigCACIBBEBBYCECIAAoApjiASABRw0BC0EAIQIgAEHw4AFqKAIARQ0AIABBkOEBahBDCyACCycBAX8QVyIERQRAQUAPCyAEIAAgASACIAMgBBBLEE8hACAEEFYgAAs/AQF/AkACQAJAIAAoAqDiAUEBaiIBQQJLDQAgAUEBaw4CAAECCyAAEDBBAA8LIABBADYCoOIBCyAAKAKU4gELvAMCB38BfiMAQRBrIgkkAEG4fyEGAkAgBCgCACIIQQVBCSAAKALs4QEiBRtJDQAgAygCACIHQQFBBSAFGyAFEC8iBRADBEAgBSEGDAELIAggBUEDakkNACAAIAcgBRBJIgYQAw0AIAEgAmohCiAAQZDhAWohCyAIIAVrIQIgBSAHaiEHIAEhBQNAIAcgAiAJECwiBhADDQEgAkF9aiICIAZJBEBBuH8hBgwCCyAJKAIAIghBAksEQEFsIQYMAgsgB0EDaiEHAn8CQAJAAkAgCEEBaw4CAgABCyAAIAUgCiAFayAHIAYQSAwCCyAFIAogBWsgByAGEEcMAQsgBSAKIAVrIActAAAgCSgCCBBGCyIIEAMEQCAIIQYMAgsgACgC8OABBEAgCyAFIAgQRQsgAiAGayECIAYgB2ohByAFIAhqIQUgCSgCBEUNAAsgACkD0OABIgxCf1IEQEFsIQYgDCAFIAFrrFINAQsgACgC8OABBEBBaiEGIAJBBEkNASALEEQhDCAHKAAAIAynRw0BIAdBBGohByACQXxqIQILIAMgBzYCACAEIAI2AgAgBSABayEGCyAJQRBqJAAgBgsuACAAECsCf0EAQQAQAw0AGiABRSACRXJFBEBBYiAAIAEgAhA9EAMNARoLQQALCzcAIAEEQCAAIAAoAsTgASABKAIEIAEoAghqRzYCnOIBCyAAECtBABADIAFFckUEQCAAIAEQWwsL0QIBB38jAEEQayIGJAAgBiAENgIIIAYgAzYCDCAFBEAgBSgCBCEKIAUoAgghCQsgASEIAkACQANAIAAoAuzhARAWIQsCQANAIAQgC0kNASADKAAAQXBxQdDUtMIBRgRAIAMgBBAiIgcQAw0EIAQgB2shBCADIAdqIQMMAQsLIAYgAzYCDCAGIAQ2AggCQCAFBEAgACAFEE5BACEHQQAQA0UNAQwFCyAAIAogCRBNIgcQAw0ECyAAIAgQUCAMQQFHQQAgACAIIAIgBkEMaiAGQQhqEEwiByIDa0EAIAMQAxtBCkdyRQRAQbh/IQcMBAsgBxADDQMgAiAHayECIAcgCGohCEEBIQwgBigCDCEDIAYoAgghBAwBCwsgBiADNgIMIAYgBDYCCEG4fyEHIAQNASAIIAFrIQcMAQsgBiADNgIMIAYgBDYCCAsgBkEQaiQAIAcLRgECfyABIAAoArjgASICRwRAIAAgAjYCxOABIAAgATYCuOABIAAoArzgASEDIAAgATYCvOABIAAgASADIAJrajYCwOABCwutAgIEfwF+IwBBQGoiBCQAAkACQCACQQhJDQAgASgAAEFwcUHQ1LTCAUcNACABIAIQIiEBIABCADcDCCAAQQA2AgQgACABNgIADAELIARBGGogASACEC0iAxADBEAgACADEBoMAQsgAwRAIABBuH8QGgwBCyACIAQoAjAiA2shAiABIANqIQMDQAJAIAAgAyACIARBCGoQLCIFEAMEfyAFBSACIAVBA2oiBU8NAUG4fwsQGgwCCyAGQQFqIQYgAiAFayECIAMgBWohAyAEKAIMRQ0ACyAEKAI4BEAgAkEDTQRAIABBuH8QGgwCCyADQQRqIQMLIAQoAighAiAEKQMYIQcgAEEANgIEIAAgAyABazYCACAAIAIgBmytIAcgB0J/URs3AwgLIARBQGskAAslAQF/IwBBEGsiAiQAIAIgACABEFEgAigCACEAIAJBEGokACAAC30BBH8jAEGQBGsiBCQAIARB/wE2AggCQCAEQRBqIARBCGogBEEMaiABIAIQFSIGEAMEQCAGIQUMAQtBVCEFIAQoAgwiB0EGSw0AIAMgBEEQaiAEKAIIIAcQQSIFEAMNACAAIAEgBmogAiAGayADEDwhBQsgBEGQBGokACAFC4cBAgJ/An5BABAWIQMCQANAIAEgA08EQAJAIAAoAABBcHFB0NS0wgFGBEAgACABECIiAhADRQ0BQn4PCyAAIAEQVSIEQn1WDQMgBCAFfCIFIARUIQJCfiEEIAINAyAAIAEQUiICEAMNAwsgASACayEBIAAgAmohAAwBCwtCfiAFIAEbIQQLIAQLPwIBfwF+IwBBMGsiAiQAAn5CfiACQQhqIAAgARAtDQAaQgAgAigCHEEBRg0AGiACKQMICyEDIAJBMGokACADC40BAQJ/IwBBMGsiASQAAkAgAEUNACAAKAKI4gENACABIABB/OEBaigCADYCKCABIAApAvThATcDICAAEDAgACgCqOIBIQIgASABKAIoNgIYIAEgASkDIDcDECACIAFBEGoQGyAAQQA2AqjiASABIAEoAig2AgggASABKQMgNwMAIAAgARAbCyABQTBqJAALKgECfyMAQRBrIgAkACAAQQA2AgggAEIANwMAIAAQWCEBIABBEGokACABC4cBAQN/IwBBEGsiAiQAAkAgACgCAEUgACgCBEVzDQAgAiAAKAIINgIIIAIgACkCADcDAAJ/IAIoAgAiAQRAIAIoAghBqOMJIAERBQAMAQtBqOMJECgLIgFFDQAgASAAKQIANwL04QEgAUH84QFqIAAoAgg2AgAgARBZIAEhAwsgAkEQaiQAIAMLywEBAn8jAEEgayIBJAAgAEGBgIDAADYCtOIBIABBADYCiOIBIABBADYC7OEBIABCADcDkOIBIABBADYCpOMJIABBADYC3OIBIABCADcCzOIBIABBADYCvOIBIABBADYCxOABIABCADcCnOIBIABBpOIBakIANwIAIABBrOIBakEANgIAIAFCADcCECABQgA3AhggASABKQMYNwMIIAEgASkDEDcDACABKAIIQQh2QQFxIQIgAEEANgLg4gEgACACNgKM4gEgAUEgaiQAC3YBA38jAEEwayIBJAAgAARAIAEgAEHE0AFqIgIoAgA2AiggASAAKQK80AE3AyAgACgCACEDIAEgAigCADYCGCABIAApArzQATcDECADIAFBEGoQGyABIAEoAig2AgggASABKQMgNwMAIAAgARAbCyABQTBqJAALzAEBAX8gACABKAK00AE2ApjiASAAIAEoAgQiAjYCwOABIAAgAjYCvOABIAAgAiABKAIIaiICNgK44AEgACACNgLE4AEgASgCuNABBEAgAEKBgICAEDcDiOEBIAAgAUGk0ABqNgIMIAAgAUGUIGo2AgggACABQZwwajYCBCAAIAFBDGo2AgAgAEGs0AFqIAFBqNABaigCADYCACAAQbDQAWogAUGs0AFqKAIANgIAIABBtNABaiABQbDQAWooAgA2AgAPCyAAQgA3A4jhAQs7ACACRQRAQbp/DwsgBEUEQEFsDwsgAiAEEGAEQCAAIAEgAiADIAQgBRBhDwsgACABIAIgAyAEIAUQZQtGAQF/IwBBEGsiBSQAIAVBCGogBBAOAn8gBS0ACQRAIAAgASACIAMgBBAyDAELIAAgASACIAMgBBA0CyEAIAVBEGokACAACzQAIAAgAyAEIAUQNiIFEAMEQCAFDwsgBSAESQR/IAEgAiADIAVqIAQgBWsgABA1BUG4fwsLRgEBfyMAQRBrIgUkACAFQQhqIAQQDgJ/IAUtAAkEQCAAIAEgAiADIAQQYgwBCyAAIAEgAiADIAQQNQshACAFQRBqJAAgAAtZAQF/QQ8hAiABIABJBEAgAUEEdCAAbiECCyAAQQh2IgEgAkEYbCIAQYwIaigCAGwgAEGICGooAgBqIgJBA3YgAmogAEGACGooAgAgAEGECGooAgAgAWxqSQs3ACAAIAMgBCAFQYAQEDMiBRADBEAgBQ8LIAUgBEkEfyABIAIgAyAFaiAEIAVrIAAQMgVBuH8LC78DAQN/IwBBIGsiBSQAIAVBCGogAiADEAYiAhADRQRAIAAgAWoiB0F9aiEGIAUgBBAOIARBBGohAiAFLQACIQMDQEEAIAAgBkkgBUEIahAEGwRAIAAgAiAFQQhqIAMQAkECdGoiBC8BADsAACAFQQhqIAQtAAIQASAAIAQtAANqIgQgAiAFQQhqIAMQAkECdGoiAC8BADsAACAFQQhqIAAtAAIQASAEIAAtAANqIQAMAQUgB0F+aiEEA0AgBUEIahAEIAAgBEtyRQRAIAAgAiAFQQhqIAMQAkECdGoiBi8BADsAACAFQQhqIAYtAAIQASAAIAYtAANqIQAMAQsLA0AgACAES0UEQCAAIAIgBUEIaiADEAJBAnRqIgYvAQA7AAAgBUEIaiAGLQACEAEgACAGLQADaiEADAELCwJAIAAgB08NACAAIAIgBUEIaiADEAIiA0ECdGoiAC0AADoAACAALQADQQFGBEAgBUEIaiAALQACEAEMAQsgBSgCDEEfSw0AIAVBCGogAiADQQJ0ai0AAhABIAUoAgxBIUkNACAFQSA2AgwLIAFBbCAFQQhqEAobIQILCwsgBUEgaiQAIAILkgIBBH8jAEFAaiIJJAAgCSADQTQQCyEDAkAgBEECSA0AIAMgBEECdGooAgAhCSADQTxqIAgQIyADQQE6AD8gAyACOgA+QQAhBCADKAI8IQoDQCAEIAlGDQEgACAEQQJ0aiAKNgEAIARBAWohBAwAAAsAC0EAIQkDQCAGIAlGRQRAIAMgBSAJQQF0aiIKLQABIgtBAnRqIgwoAgAhBCADQTxqIAotAABBCHQgCGpB//8DcRAjIANBAjoAPyADIAcgC2siCiACajoAPiAEQQEgASAKa3RqIQogAygCPCELA0AgACAEQQJ0aiALNgEAIARBAWoiBCAKSQ0ACyAMIAo2AgAgCUEBaiEJDAELCyADQUBrJAALowIBCX8jAEHQAGsiCSQAIAlBEGogBUE0EAsaIAcgBmshDyAHIAFrIRADQAJAIAMgCkcEQEEBIAEgByACIApBAXRqIgYtAAEiDGsiCGsiC3QhDSAGLQAAIQ4gCUEQaiAMQQJ0aiIMKAIAIQYgCyAPTwRAIAAgBkECdGogCyAIIAUgCEE0bGogCCAQaiIIQQEgCEEBShsiCCACIAQgCEECdGooAgAiCEEBdGogAyAIayAHIA4QYyAGIA1qIQgMAgsgCUEMaiAOECMgCUEBOgAPIAkgCDoADiAGIA1qIQggCSgCDCELA0AgBiAITw0CIAAgBkECdGogCzYBACAGQQFqIQYMAAALAAsgCUHQAGokAA8LIAwgCDYCACAKQQFqIQoMAAALAAs0ACAAIAMgBCAFEDYiBRADBEAgBQ8LIAUgBEkEfyABIAIgAyAFaiAEIAVrIAAQNAVBuH8LCyMAIAA/AEEQdGtB//8DakEQdkAAQX9GBEBBAA8LQQAQAEEBCzsBAX8gAgRAA0AgACABIAJBgCAgAkGAIEkbIgMQCyEAIAFBgCBqIQEgAEGAIGohACACIANrIgINAAsLCwYAIAAQAwsLqBUJAEGICAsNAQAAAAEAAAACAAAAAgBBoAgLswYBAAAAAQAAAAIAAAACAAAAJgAAAIIAAAAhBQAASgAAAGcIAAAmAAAAwAEAAIAAAABJBQAASgAAAL4IAAApAAAALAIAAIAAAABJBQAASgAAAL4IAAAvAAAAygIAAIAAAACKBQAASgAAAIQJAAA1AAAAcwMAAIAAAACdBQAASgAAAKAJAAA9AAAAgQMAAIAAAADrBQAASwAAAD4KAABEAAAAngMAAIAAAABNBgAASwAAAKoKAABLAAAAswMAAIAAAADBBgAATQAAAB8NAABNAAAAUwQAAIAAAAAjCAAAUQAAAKYPAABUAAAAmQQAAIAAAABLCQAAVwAAALESAABYAAAA2gQAAIAAAABvCQAAXQAAACMUAABUAAAARQUAAIAAAABUCgAAagAAAIwUAABqAAAArwUAAIAAAAB2CQAAfAAAAE4QAAB8AAAA0gIAAIAAAABjBwAAkQAAAJAHAACSAAAAAAAAAAEAAAABAAAABQAAAA0AAAAdAAAAPQAAAH0AAAD9AAAA/QEAAP0DAAD9BwAA/Q8AAP0fAAD9PwAA/X8AAP3/AAD9/wEA/f8DAP3/BwD9/w8A/f8fAP3/PwD9/38A/f//AP3//wH9//8D/f//B/3//w/9//8f/f//P/3//38AAAAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABcAAAAYAAAAGQAAABoAAAAbAAAAHAAAAB0AAAAeAAAAHwAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAKAAAACwAAAAwAAAANAAAADgAAAA8AAAAQAAAAEQAAABIAAAATAAAAFAAAABUAAAAWAAAAFwAAABgAAAAZAAAAGgAAABsAAAAcAAAAHQAAAB4AAAAfAAAAIAAAACEAAAAiAAAAIwAAACUAAAAnAAAAKQAAACsAAAAvAAAAMwAAADsAAABDAAAAUwAAAGMAAACDAAAAAwEAAAMCAAADBAAAAwgAAAMQAAADIAAAA0AAAAOAAAADAAEAQeAPC1EBAAAAAQAAAAEAAAABAAAAAgAAAAIAAAADAAAAAwAAAAQAAAAEAAAABQAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAAOAAAADwAAABAAQcQQC4sBAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAABIAAAAUAAAAFgAAABgAAAAcAAAAIAAAACgAAAAwAAAAQAAAAIAAAAAAAQAAAAIAAAAEAAAACAAAABAAAAAgAAAAQAAAAIAAAAAAAQBBkBIL5gQBAAAAAQAAAAEAAAABAAAAAgAAAAIAAAADAAAAAwAAAAQAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsAAAAMAAAADQAAAA4AAAAPAAAAEAAAAAEAAAAEAAAACAAAAAAAAAABAAEBBgAAAAAAAAQAAAAAEAAABAAAAAAgAAAFAQAAAAAAAAUDAAAAAAAABQQAAAAAAAAFBgAAAAAAAAUHAAAAAAAABQkAAAAAAAAFCgAAAAAAAAUMAAAAAAAABg4AAAAAAAEFEAAAAAAAAQUUAAAAAAABBRYAAAAAAAIFHAAAAAAAAwUgAAAAAAAEBTAAAAAgAAYFQAAAAAAABwWAAAAAAAAIBgABAAAAAAoGAAQAAAAADAYAEAAAIAAABAAAAAAAAAAEAQAAAAAAAAUCAAAAIAAABQQAAAAAAAAFBQAAACAAAAUHAAAAAAAABQgAAAAgAAAFCgAAAAAAAAULAAAAAAAABg0AAAAgAAEFEAAAAAAAAQUSAAAAIAABBRYAAAAAAAIFGAAAACAAAwUgAAAAAAADBSgAAAAAAAYEQAAAABAABgRAAAAAIAAHBYAAAAAAAAkGAAIAAAAACwYACAAAMAAABAAAAAAQAAAEAQAAACAAAAUCAAAAIAAABQMAAAAgAAAFBQAAACAAAAUGAAAAIAAABQgAAAAgAAAFCQAAACAAAAULAAAAIAAABQwAAAAAAAAGDwAAACAAAQUSAAAAIAABBRQAAAAgAAIFGAAAACAAAgUcAAAAIAADBSgAAAAgAAQFMAAAAAAAEAYAAAEAAAAPBgCAAAAAAA4GAEAAAAAADQYAIABBgBcLhwIBAAEBBQAAAAAAAAUAAAAAAAAGBD0AAAAAAAkF/QEAAAAADwX9fwAAAAAVBf3/HwAAAAMFBQAAAAAABwR9AAAAAAAMBf0PAAAAABIF/f8DAAAAFwX9/38AAAAFBR0AAAAAAAgE/QAAAAAADgX9PwAAAAAUBf3/DwAAAAIFAQAAABAABwR9AAAAAAALBf0HAAAAABEF/f8BAAAAFgX9/z8AAAAEBQ0AAAAQAAgE/QAAAAAADQX9HwAAAAATBf3/BwAAAAEFAQAAABAABgQ9AAAAAAAKBf0DAAAAABAF/f8AAAAAHAX9//8PAAAbBf3//wcAABoF/f//AwAAGQX9//8BAAAYBf3//wBBkBkLhgQBAAEBBgAAAAAAAAYDAAAAAAAABAQAAAAgAAAFBQAAAAAAAAUGAAAAAAAABQgAAAAAAAAFCQAAAAAAAAULAAAAAAAABg0AAAAAAAAGEAAAAAAAAAYTAAAAAAAABhYAAAAAAAAGGQAAAAAAAAYcAAAAAAAABh8AAAAAAAAGIgAAAAAAAQYlAAAAAAABBikAAAAAAAIGLwAAAAAAAwY7AAAAAAAEBlMAAAAAAAcGgwAAAAAACQYDAgAAEAAABAQAAAAAAAAEBQAAACAAAAUGAAAAAAAABQcAAAAgAAAFCQAAAAAAAAUKAAAAAAAABgwAAAAAAAAGDwAAAAAAAAYSAAAAAAAABhUAAAAAAAAGGAAAAAAAAAYbAAAAAAAABh4AAAAAAAAGIQAAAAAAAQYjAAAAAAABBicAAAAAAAIGKwAAAAAAAwYzAAAAAAAEBkMAAAAAAAUGYwAAAAAACAYDAQAAIAAABAQAAAAwAAAEBAAAABAAAAQFAAAAIAAABQcAAAAgAAAFCAAAACAAAAUKAAAAIAAABQsAAAAAAAAGDgAAAAAAAAYRAAAAAAAABhQAAAAAAAAGFwAAAAAAAAYaAAAAAAAABh0AAAAAAAAGIAAAAAAAEAYDAAEAAAAPBgOAAAAAAA4GA0AAAAAADQYDIAAAAAAMBgMQAAAAAAsGAwgAAAAACgYDBABBpB0L2QEBAAAAAwAAAAcAAAAPAAAAHwAAAD8AAAB/AAAA/wAAAP8BAAD/AwAA/wcAAP8PAAD/HwAA/z8AAP9/AAD//wAA//8BAP//AwD//wcA//8PAP//HwD//z8A//9/AP///wD///8B////A////wf///8P////H////z////9/AAAAAAEAAAACAAAABAAAAAAAAAACAAAABAAAAAgAAAAAAAAAAQAAAAIAAAABAAAABAAAAAQAAAAEAAAABAAAAAgAAAAIAAAACAAAAAcAAAAIAAAACQAAAAoAAAALAEGgIAsDwBBQ"
vendor: 18,012 bytes, lines 35812-36220
35812; 35813 35814 const DisplayP3ColorSpace = 'display-p3'; 35815 const LinearDisplayP3ColorSpace = 'display-p3-linear'; 35816 35817 const _taskCache = new WeakMap(); 35818 let _activeLoaders = 0; 35819 let _zstd; 35820 class KTX2Loader extends Loader { 35821 setTranscoderPath(path) { 35822 this.transcoderPath = path; 35823 return this; 35824 } 35825 setWorkerLimit(num) { 35826 this.workerPool.setWorkerLimit(num); 35827 return this; 35828 } 35829 async detectSupportAsync(renderer) { 35830 this.workerConfig = { 35831 astcSupported: await renderer.hasFeatureAsync('texture-compression-astc'), 35832 astcHDRSupported: false, 35833 etc1Supported: await renderer.hasFeatureAsync('texture-compression-etc1'), 35834 etc2Supported: await renderer.hasFeatureAsync('texture-compression-etc2'), 35835 dxtSupported: await renderer.hasFeatureAsync('texture-compression-bc'), 35836 bptcSupported: await renderer.hasFeatureAsync('texture-compression-bptc'), 35837 pvrtcSupported: await renderer.hasFeatureAsync('texture-compression-pvrtc') 35838 }; 35839 return this; 35840 } 35841 detectSupport(renderer) { 35842 if (renderer.isWebGPURenderer === true) { 35843 this.workerConfig = { 35844 astcSupported: renderer.hasFeature('texture-compression-astc'), 35845 astcHDRSupported: false, 35846 etc1Supported: renderer.hasFeature('texture-compression-etc1'), 35847 etc2Supported: renderer.hasFeature('texture-compression-etc2'), 35848 dxtSupported: renderer.hasFeature('texture-compression-bc'), 35849 bptcSupported: renderer.hasFeature('texture-compression-bptc'), 35850 pvrtcSupported: renderer.hasFeature('texture-compression-pvrtc') 35851 }; 35852 } else { 35853 this.workerConfig = { 35854 astcSupported: renderer.extensions.has('WEBGL_compressed_texture_astc'), 35855 astcHDRSupported: renderer.extensions.has('WEBGL_compressed_texture_astc') && renderer.extensions.get('WEBGL_compressed_texture_astc').getSupportedProfiles().includes('hdr'), 35856 etc1Supported: renderer.extensions.has('WEBGL_compressed_texture_etc1'), 35857 etc2Supported: renderer.extensions.has('WEBGL_compressed_texture_etc'), 35858 dxtSupported: renderer.extensions.has('WEBGL_compressed_texture_s3tc'), 35859 bptcSupported: renderer.extensions.has('EXT_texture_compression_bptc'), 35860 pvrtcSupported: renderer.extensions.has('WEBGL_compressed_texture_pvrtc') || renderer.extensions.has('WEBKIT_WEBGL_compressed_texture_pvrtc') 35861 }; 35862 } 35863 return this; 35864 } 35865 init() { 35866 if (!this.transcoderPending) { 35867 // Load transcoder wrapper. 35868 const jsLoader = new FileLoader(this.manager); 35869 jsLoader.setPath(this.transcoderPath); 35870 jsLoader.setWithCredentials(this.withCredentials); 35871 const jsContent = jsLoader.loadAsync('basis_transcoder.js'); 35872 // Load transcoder WASM binary. 35873 const binaryLoader = new FileLoader(this.manager); 35874 binaryLoader.setPath(this.transcoderPath); 35875 binaryLoader.setResponseType('arraybuffer'); 35876 binaryLoader.setWithCredentials(this.withCredentials); 35877 const binaryContent = binaryLoader.loadAsync('basis_transcoder.wasm'); 35878 this.transcoderPending = Promise.all([ 35879 jsContent, 35880 binaryContent 35881 ]).then(([jsContent, binaryContent])=>{ 35882 const fn = KTX2Loader.BasisWorker.toString(); 35883 const body = [ 35884 '/* constants */', 35885 'let _EngineFormat = ' + JSON.stringify(KTX2Loader.EngineFormat), 35886 'let _EngineType = ' + JSON.stringify(KTX2Loader.EngineType), 35887 'let _TranscoderFormat = ' + JSON.stringify(KTX2Loader.TranscoderFormat), 35888 'let _BasisFormat = ' + JSON.stringify(KTX2Loader.BasisFormat), 35889 '/* basis_transcoder.js */', 35890 jsContent, 35891 '/* worker */', 35892 fn.substring(fn.indexOf('{') + 1, fn.lastIndexOf('}')) 35893 ].join('\n'); 35894 this.workerSourceURL = URL.createObjectURL(new Blob([ 35895 body 35896 ])); 35897 this.transcoderBinary = binaryContent; 35898 this.workerPool.setWorkerCreator(()=>{ 35899 const worker = new Worker(this.workerSourceURL); 35900 const transcoderBinary = this.transcoderBinary.slice(0); 35901 worker.postMessage({ 35902 type: 'init', 35903 config: this.workerConfig, 35904 transcoderBinary 35905 }, [ 35906 transcoderBinary 35907 ]); 35908 return worker; 35909 }); 35910 }); 35911 if (_activeLoaders > 0) { 35912 // Each instance loads a transcoder and allocates workers, increasing network and memory cost. 35913 console.warn('THREE.KTX2Loader: Multiple active KTX2 loaders may cause performance issues.' + ' Use a single KTX2Loader instance, or call .dispose() on old instances.'); 35914 } 35915 _activeLoaders++; 35916 } 35917 return this.transcoderPending; 35918 } 35919 load(url, onLoad, onProgress, onError) { 35920 if (this.workerConfig === null) { 35921 throw new Error('THREE.KTX2Loader: Missing initialization with `.detectSupport( renderer )`.'); 35922 } 35923 const loader = new FileLoader(this.manager); 35924 loader.setResponseType('arraybuffer'); 35925 loader.setWithCredentials(this.withCredentials); 35926 loader.load(url, (buffer)=>{ 35927 this.parse(buffer, onLoad, onError); 35928 }, onProgress, onError); 35929 } 35930 parse(buffer, onLoad, onError) { 35931 if (this.workerConfig === null) { 35932 throw new Error('THREE.KTX2Loader: Missing initialization with `.detectSupport( renderer )`.'); 35933 } 35934 // Check for an existing task using this buffer. A transferred buffer cannot be transferred 35935 // again from this thread. 35936 if (_taskCache.has(buffer)) { 35937 const cachedTask = _taskCache.get(buffer); 35938 return cachedTask.promise.then(onLoad).catch(onError); 35939 } 35940 this._createTexture(buffer).then((texture)=>onLoad ? onLoad(texture) : null).catch(onError); 35941 } 35942 _createTextureFrom(transcodeResult, container) { 35943 const { type: messageType, error, data: { faces, width, height, format, type, dfdFlags } } = transcodeResult; 35944 if (messageType === 'error') return Promise.reject(error); 35945 let texture; 35946 if (container.faceCount === 6) { 35947 texture = new CompressedCubeTexture(faces, format, type); 35948 } else { 35949 const mipmaps = faces[0].mipmaps; 35950 texture = container.layerCount > 1 ? new CompressedArrayTexture(mipmaps, width, height, container.layerCount, format, type) : new CompressedTexture(mipmaps, width, height, format, type); 35951 } 35952 texture.minFilter = faces[0].mipmaps.length === 1 ? LinearFilter : LinearMipmapLinearFilter; 35953 texture.magFilter = LinearFilter; 35954 texture.generateMipmaps = false; 35955 texture.needsUpdate = true; 35956 texture.colorSpace = parseColorSpace(container); 35957 texture.premultiplyAlpha = !!(dfdFlags & g$1); 35958 return texture; 35959 } 35960 /** 35961 * @param {ArrayBuffer} buffer 35962 * @param {?Object} config 35963 * @return {Promise<CompressedTexture|CompressedArrayTexture|DataTexture|Data3DTexture>} 35964 */ async _createTexture(buffer, config = {}) { 35965 const container = Pi(new Uint8Array(buffer)); 35966 // Basis UASTC HDR is a subset of ASTC, which can be transcoded efficiently 35967 // to BC6H. To detect whether a KTX2 file uses Basis UASTC HDR, or default 35968 // ASTC, inspect the DFD color model. 35969 // 35970 // Source: https://github.com/BinomialLLC/basis_universal/issues/381 35971 const isBasisHDR = container.vkFormat === pi && container.dataFormatDescriptor[0].colorModel === 0xA7; 35972 // If the device supports ASTC, Basis UASTC HDR requires no transcoder. 35973 const needsTranscoder = container.vkFormat === it || isBasisHDR && !this.workerConfig.astcHDRSupported; 35974 if (!needsTranscoder) { 35975 return createRawTexture(container); 35976 } 35977 // 35978 const taskConfig = config; 35979 const texturePending = this.init().then(()=>{ 35980 return this.workerPool.postMessage({ 35981 type: 'transcode', 35982 buffer, 35983 taskConfig: taskConfig 35984 }, [ 35985 buffer 35986 ]); 35987 }).then((e)=>this._createTextureFrom(e.data, container)); 35988 // Cache the task result. 35989 _taskCache.set(buffer, { 35990 promise: texturePending 35991 }); 35992 return texturePending; 35993 } 35994 dispose() { 35995 this.workerPool.dispose(); 35996 if (this.workerSourceURL) URL.revokeObjectURL(this.workerSourceURL); 35997 _activeLoaders--; 35998 return this; 35999 } 36000 constructor(manager){ 36001 super(manager); 36002 this.transcoderPath = ''; 36003 this.transcoderBinary = null; 36004 this.transcoderPending = null; 36005 this.workerPool = new WorkerPool(); 36006 this.workerSourceURL = ''; 36007 this.workerConfig = null; 36008 if (typeof MSC_TRANSCODER !== 'undefined') { 36009 console.warn('THREE.KTX2Loader: Please update to latest "basis_transcoder".' + ' "msc_basis_transcoder" is no longer supported in three.js r125+.'); 36010 } 36011 } 36012 } 36013 /* CONSTANTS */ KTX2Loader.BasisFormat = { 36014 ETC1S: 0, 36015 UASTC: 1, 36016 UASTC_HDR: 2 36017 }; 36018 // Source: https://github.com/BinomialLLC/basis_universal/blob/master/webgl/texture_test/index.html 36019 KTX2Loader.TranscoderFormat = { 36020 ETC1: 0, 36021 ETC2: 1, 36022 BC1: 2, 36023 BC3: 3, 36024 BC4: 4, 36025 BC5: 5, 36026 BC7_M6_OPAQUE_ONLY: 6, 36027 BC7_M5: 7, 36028 PVRTC1_4_RGB: 8, 36029 PVRTC1_4_RGBA: 9, 36030 ASTC_4x4: 10, 36031 ATC_RGB: 11, 36032 ATC_RGBA_INTERPOLATED_ALPHA: 12, 36033 RGBA32: 13, 36034 RGB565: 14, 36035 BGR565: 15, 36036 RGBA4444: 16, 36037 BC6H: 22, 36038 RGB_HALF: 24, 36039 RGBA_HALF: 25 36040 }; 36041 KTX2Loader.EngineFormat = { 36042 RGBAFormat: RGBAFormat, 36043 RGBA_ASTC_4x4_Format: RGBA_ASTC_4x4_Format, 36044 RGB_BPTC_UNSIGNED_Format: RGB_BPTC_UNSIGNED_Format, 36045 RGBA_BPTC_Format: RGBA_BPTC_Format, 36046 RGBA_ETC2_EAC_Format: RGBA_ETC2_EAC_Format, 36047 RGBA_PVRTC_4BPPV1_Format: RGBA_PVRTC_4BPPV1_Format, 36048 RGBA_S3TC_DXT5_Format: RGBA_S3TC_DXT5_Format, 36049 RGB_ETC1_Format: RGB_ETC1_Format, 36050 RGB_ETC2_Format: RGB_ETC2_Format, 36051 RGB_PVRTC_4BPPV1_Format: RGB_PVRTC_4BPPV1_Format, 36052 RGBA_S3TC_DXT1_Format: RGBA_S3TC_DXT1_Format 36053 }; 36054 KTX2Loader.EngineType = { 36055 UnsignedByteType: UnsignedByteType, 36056 HalfFloatType: HalfFloatType, 36057 FloatType: FloatType 36058 }; 36059 /* WEB WORKER */ KTX2Loader.BasisWorker = function() { 36060 let config; 36061 let transcoderPending; 36062 let BasisModule; 36063 const EngineFormat = _EngineFormat; // eslint-disable-line no-undef 36064 const EngineType = _EngineType; // eslint-disable-line no-undef 36065 const TranscoderFormat = _TranscoderFormat; // eslint-disable-line no-undef 36066 const BasisFormat = _BasisFormat; // eslint-disable-line no-undef 36067 self.addEventListener('message', function(e) { 36068 const message = e.data; 36069 switch(message.type){ 36070 case 'init': 36071 config = message.config; 36072 init(message.transcoderBinary); 36073 break; 36074 case 'transcode': 36075 transcoderPending.then(()=>{ 36076 try { 36077 const { faces, buffers, width, height, hasAlpha, format, type, dfdFlags } = transcode(message.buffer); 36078 self.postMessage({ 36079 type: 'transcode', 36080 id: message.id, 36081 data: { 36082 faces, 36083 width, 36084 height, 36085 hasAlpha, 36086 format, 36087 type, 36088 dfdFlags 36089 } 36090 }, buffers); 36091 } catch (error) { 36092 console.error(error); 36093 self.postMessage({ 36094 type: 'error', 36095 id: message.id, 36096 error: error.message 36097 }); 36098 } 36099 }); 36100 break; 36101 } 36102 }); 36103 function init(wasmBinary) { 36104 transcoderPending = new Promise((resolve)=>{ 36105 BasisModule = { 36106 wasmBinary, 36107 onRuntimeInitialized: resolve 36108 }; 36109 BASIS(BasisModule); // eslint-disable-line no-undef 36110 }).then(()=>{ 36111 BasisModule.initializeBasis(); 36112 if (BasisModule.KTX2File === undefined) { 36113 console.warn('THREE.KTX2Loader: Please update Basis Universal transcoder.'); 36114 } 36115 }); 36116 } 36117 function transcode(buffer) { 36118 const ktx2File = new BasisModule.KTX2File(new Uint8Array(buffer)); 36119 function cleanup() { 36120 ktx2File.close(); 36121 ktx2File.delete(); 36122 } 36123 if (!ktx2File.isValid()) { 36124 cleanup(); 36125 throw new Error('THREE.KTX2Loader: Invalid or unsupported .ktx2 file'); 36126 } 36127 let basisFormat; 36128 if (ktx2File.isUASTC()) { 36129 basisFormat = BasisFormat.UASTC; 36130 } else if (ktx2File.isETC1S()) { 36131 basisFormat = BasisFormat.ETC1S; 36132 } else if (ktx2File.isHDR()) { 36133 basisFormat = BasisFormat.UASTC_HDR; 36134 } else { 36135 throw new Error('THREE.KTX2Loader: Unknown Basis encoding'); 36136 } 36137 const width = ktx2File.getWidth(); 36138 const height = ktx2File.getHeight(); 36139 const layerCount = ktx2File.getLayers() || 1; 36140 const levelCount = ktx2File.getLevels(); 36141 const faceCount = ktx2File.getFaces(); 36142 const hasAlpha = ktx2File.getHasAlpha(); 36143 const dfdFlags = ktx2File.getDFDFlags(); 36144 const { transcoderFormat, engineFormat, engineType } = getTranscoderFormat(basisFormat, width, height, hasAlpha); 36145 if (!width || !height || !levelCount) { 36146 cleanup(); 36147 throw new Error('THREE.KTX2Loader: Invalid texture'); 36148 } 36149 if (!ktx2File.startTranscoding()) { 36150 cleanup(); 36151 throw new Error('THREE.KTX2Loader: .startTranscoding failed'); 36152 } 36153 const faces = []; 36154 const buffers = []; 36155 for(let face = 0; face < faceCount; face++){ 36156 const mipmaps = []; 36157 for(let mip = 0; mip < levelCount; mip++){ 36158 const layerMips = []; 36159 let mipWidth, mipHeight; 36160 for(let layer = 0; layer < layerCount; layer++){ 36161 const levelInfo = ktx2File.getImageLevelInfo(mip, layer, face); 36162 if (face === 0 && mip === 0 && layer === 0 && (levelInfo.origWidth % 4 !== 0 || levelInfo.origHeight % 4 !== 0)) { 36163 console.warn('THREE.KTX2Loader: ETC1S and UASTC textures should use multiple-of-four dimensions.'); 36164 } 36165 if (levelCount > 1) { 36166 mipWidth = levelInfo.origWidth; 36167 mipHeight = levelInfo.origHeight; 36168 } else { 36169 // Handles non-multiple-of-four dimensions in textures without mipmaps. Textures with 36170 // mipmaps must use multiple-of-four dimensions, for some texture formats and APIs. 36171 // See mrdoob/three.js#25908. 36172 mipWidth = levelInfo.width; 36173 mipHeight = levelInfo.height; 36174 } 36175 let dst = new Uint8Array(ktx2File.getImageTranscodedSizeInBytes(mip, layer, 0, transcoderFormat)); 36176 const status = ktx2File.transcodeImage(dst, mip, layer, face, transcoderFormat, 0, -1, -1); 36177 if (engineType === EngineType.HalfFloatType) { 36178 dst = new Uint16Array(dst.buffer, dst.byteOffset, dst.byteLength / Uint16Array.BYTES_PER_ELEMENT); 36179 } 36180 if (!status) { 36181 cleanup(); 36182 throw new Error('THREE.KTX2Loader: .transcodeImage failed.'); 36183 } 36184 layerMips.push(dst); 36185 } 36186 const mipData = concat(layerMips); 36187 mipmaps.push({ 36188 data: mipData, 36189 width: mipWidth, 36190 height: mipHeight 36191 }); 36192 buffers.push(mipData.buffer); 36193 } 36194 faces.push({ 36195 mipmaps, 36196 width, 36197 height, 36198 format: engineFormat, 36199 type: engineType 36200 }); 36201 } 36202 cleanup(); 36203 return { 36204 faces, 36205 buffers, 36206 width, 36207 height, 36208 hasAlpha, 36209 dfdFlags, 36210 format: engineFormat, 36211 type: engineType 36212 }; 36213 } 36214 // 36215 // Optimal choice of a transcoder target format depends on the Basis format (ETC1S, UASTC, or 36216 // UASTC HDR), device capabilities, and texture dimensions. The list below ranks the formats 36217 // separately for each format. Currently, priority is assigned based on: 36218 // 36219 // high quality > low quality > uncompressed 36220 //
vendor: 5,465 bytes, lines 36221-36400
36221 // Prioritization may be revisited, or exposed for configuration, in the future. 36222 // 36223 // Reference: https://github.com/KhronosGroup/3D-Formats-Guidelines/blob/main/KTXDeveloperGuide.md 36224 const FORMAT_OPTIONS = [ 36225 { 36226 if: 'astcSupported', 36227 basisFormat: [ 36228 BasisFormat.UASTC 36229 ], 36230 transcoderFormat: [ 36231 TranscoderFormat.ASTC_4x4, 36232 TranscoderFormat.ASTC_4x4 36233 ], 36234 engineFormat: [ 36235 EngineFormat.RGBA_ASTC_4x4_Format, 36236 EngineFormat.RGBA_ASTC_4x4_Format 36237 ], 36238 engineType: [ 36239 EngineType.UnsignedByteType 36240 ], 36241 priorityETC1S: Infinity, 36242 priorityUASTC: 1, 36243 needsPowerOfTwo: false 36244 }, 36245 { 36246 if: 'bptcSupported', 36247 basisFormat: [ 36248 BasisFormat.ETC1S, 36249 BasisFormat.UASTC 36250 ], 36251 transcoderFormat: [ 36252 TranscoderFormat.BC7_M5, 36253 TranscoderFormat.BC7_M5 36254 ], 36255 engineFormat: [ 36256 EngineFormat.RGBA_BPTC_Format, 36257 EngineFormat.RGBA_BPTC_Format 36258 ], 36259 engineType: [ 36260 EngineType.UnsignedByteType 36261 ], 36262 priorityETC1S: 3, 36263 priorityUASTC: 2, 36264 needsPowerOfTwo: false 36265 }, 36266 { 36267 if: 'dxtSupported', 36268 basisFormat: [ 36269 BasisFormat.ETC1S, 36270 BasisFormat.UASTC 36271 ], 36272 transcoderFormat: [ 36273 TranscoderFormat.BC1, 36274 TranscoderFormat.BC3 36275 ], 36276 engineFormat: [ 36277 EngineFormat.RGBA_S3TC_DXT1_Format, 36278 EngineFormat.RGBA_S3TC_DXT5_Format 36279 ], 36280 engineType: [ 36281 EngineType.UnsignedByteType 36282 ], 36283 priorityETC1S: 4, 36284 priorityUASTC: 5, 36285 needsPowerOfTwo: false 36286 }, 36287 { 36288 if: 'etc2Supported', 36289 basisFormat: [ 36290 BasisFormat.ETC1S, 36291 BasisFormat.UASTC 36292 ], 36293 transcoderFormat: [ 36294 TranscoderFormat.ETC1, 36295 TranscoderFormat.ETC2 36296 ], 36297 engineFormat: [ 36298 EngineFormat.RGB_ETC2_Format, 36299 EngineFormat.RGBA_ETC2_EAC_Format 36300 ], 36301 engineType: [ 36302 EngineType.UnsignedByteType 36303 ], 36304 priorityETC1S: 1, 36305 priorityUASTC: 3, 36306 needsPowerOfTwo: false 36307 }, 36308 { 36309 if: 'etc1Supported', 36310 basisFormat: [ 36311 BasisFormat.ETC1S, 36312 BasisFormat.UASTC 36313 ], 36314 transcoderFormat: [ 36315 TranscoderFormat.ETC1 36316 ], 36317 engineFormat: [ 36318 EngineFormat.RGB_ETC1_Format 36319 ], 36320 engineType: [ 36321 EngineType.UnsignedByteType 36322 ], 36323 priorityETC1S: 2, 36324 priorityUASTC: 4, 36325 needsPowerOfTwo: false 36326 }, 36327 { 36328 if: 'pvrtcSupported', 36329 basisFormat: [ 36330 BasisFormat.ETC1S, 36331 BasisFormat.UASTC 36332 ], 36333 transcoderFormat: [ 36334 TranscoderFormat.PVRTC1_4_RGB, 36335 TranscoderFormat.PVRTC1_4_RGBA 36336 ], 36337 engineFormat: [ 36338 EngineFormat.RGB_PVRTC_4BPPV1_Format, 36339 EngineFormat.RGBA_PVRTC_4BPPV1_Format 36340 ], 36341 engineType: [ 36342 EngineType.UnsignedByteType 36343 ], 36344 priorityETC1S: 5, 36345 priorityUASTC: 6, 36346 needsPowerOfTwo: true 36347 }, 36348 { 36349 if: 'bptcSupported', 36350 basisFormat: [ 36351 BasisFormat.UASTC_HDR 36352 ], 36353 transcoderFormat: [ 36354 TranscoderFormat.BC6H 36355 ], 36356 engineFormat: [ 36357 EngineFormat.RGB_BPTC_UNSIGNED_Format 36358 ], 36359 engineType: [ 36360 EngineType.HalfFloatType 36361 ], 36362 priorityHDR: 1, 36363 needsPowerOfTwo: false 36364 }, 36365 // Uncompressed fallbacks. 36366 { 36367 basisFormat: [ 36368 BasisFormat.ETC1S, 36369 BasisFormat.UASTC 36370 ], 36371 transcoderFormat: [ 36372 TranscoderFormat.RGBA32, 36373 TranscoderFormat.RGBA32 36374 ], 36375 engineFormat: [ 36376 EngineFormat.RGBAFormat, 36377 EngineFormat.RGBAFormat 36378 ], 36379 engineType: [ 36380 EngineType.UnsignedByteType, 36381 EngineType.UnsignedByteType 36382 ], 36383 priorityETC1S: 100, 36384 priorityUASTC: 100, 36385 needsPowerOfTwo: false 36386 }, 36387 { 36388 basisFormat: [ 36389 BasisFormat.UASTC_HDR 36390 ], 36391 transcoderFormat: [ 36392 TranscoderFormat.RGBA_HALF 36393 ], 36394 engineFormat: [ 36395 EngineFormat.RGBAFormat 36396 ], 36397 engineType: [ 36398 EngineType.HalfFloatType 36399 ], 36400 priorityHDR: 100,
vendor: 30,567 bytes, lines 36401-37225
36401 needsPowerOfTwo: false 36402 } 36403 ]; 36404 const OPTIONS = { 36405 // TODO: For ETC1S we intentionally sort by _UASTC_ priority, preserving 36406 // a historical accident shown to avoid performance pitfalls for Linux with 36407 // Firefox & AMD GPU (RadeonSI). Further work needed. 36408 // See https://github.com/mrdoob/three.js/pull/29730. 36409 [BasisFormat.ETC1S]: FORMAT_OPTIONS.filter((opt)=>opt.basisFormat.includes(BasisFormat.ETC1S)).sort((a, b)=>a.priorityUASTC - b.priorityUASTC), 36410 [BasisFormat.UASTC]: FORMAT_OPTIONS.filter((opt)=>opt.basisFormat.includes(BasisFormat.UASTC)).sort((a, b)=>a.priorityUASTC - b.priorityUASTC), 36411 [BasisFormat.UASTC_HDR]: FORMAT_OPTIONS.filter((opt)=>opt.basisFormat.includes(BasisFormat.UASTC_HDR)).sort((a, b)=>a.priorityHDR - b.priorityHDR) 36412 }; 36413 function getTranscoderFormat(basisFormat, width, height, hasAlpha) { 36414 const options = OPTIONS[basisFormat]; 36415 for(let i = 0; i < options.length; i++){ 36416 const opt = options[i]; 36417 if (opt.if && !config[opt.if]) continue; 36418 if (!opt.basisFormat.includes(basisFormat)) continue; 36419 if (hasAlpha && opt.transcoderFormat.length < 2) continue; 36420 if (opt.needsPowerOfTwo && !(isPowerOfTwo(width) && isPowerOfTwo(height))) continue; 36421 const transcoderFormat = opt.transcoderFormat[hasAlpha ? 1 : 0]; 36422 const engineFormat = opt.engineFormat[hasAlpha ? 1 : 0]; 36423 const engineType = opt.engineType[0]; 36424 return { 36425 transcoderFormat, 36426 engineFormat, 36427 engineType 36428 }; 36429 } 36430 throw new Error('THREE.KTX2Loader: Failed to identify transcoding target.'); 36431 } 36432 function isPowerOfTwo(value) { 36433 if (value <= 2) return true; 36434 return (value & value - 1) === 0 && value !== 0; 36435 } 36436 /** 36437 * Concatenates N byte arrays. 36438 * 36439 * @param {Uint8Array[]} arrays 36440 * @return {Uint8Array} 36441 */ function concat(arrays) { 36442 if (arrays.length === 1) return arrays[0]; 36443 let totalByteLength = 0; 36444 for(let i = 0; i < arrays.length; i++){ 36445 const array = arrays[i]; 36446 totalByteLength += array.byteLength; 36447 } 36448 const result = new Uint8Array(totalByteLength); 36449 let byteOffset = 0; 36450 for(let i = 0; i < arrays.length; i++){ 36451 const array = arrays[i]; 36452 result.set(array, byteOffset); 36453 byteOffset += array.byteLength; 36454 } 36455 return result; 36456 } 36457 }; 36458 // Parsing for non-Basis textures. These textures may have supercompression 36459 // like Zstd, but they do not require transcoding. 36460 const UNCOMPRESSED_FORMATS = new Set([ 36461 RGBAFormat, 36462 RGFormat, 36463 RedFormat 36464 ]); 36465 const FORMAT_MAP = { 36466 [Ae]: RGBAFormat, 36467 [ge]: RGBAFormat, 36468 [Ft]: RGBAFormat, 36469 [Ct]: RGBAFormat, 36470 [we]: RGFormat, 36471 [ae]: RGFormat, 36472 [xt]: RGFormat, 36473 [wt]: RGFormat, 36474 [ue]: RedFormat, 36475 [te$1]: RedFormat, 36476 [yt]: RedFormat, 36477 [ct]: RedFormat, 36478 [pi]: RGBA_ASTC_4x4_Format, 36479 [Sn]: RGBA_ASTC_6x6_Format, 36480 [In]: RGBA_ASTC_6x6_Format 36481 }; 36482 const TYPE_MAP = { 36483 [Ae]: FloatType, 36484 [ge]: HalfFloatType, 36485 [Ft]: UnsignedByteType, 36486 [Ct]: UnsignedByteType, 36487 [we]: FloatType, 36488 [ae]: HalfFloatType, 36489 [xt]: UnsignedByteType, 36490 [wt]: UnsignedByteType, 36491 [ue]: FloatType, 36492 [te$1]: HalfFloatType, 36493 [yt]: UnsignedByteType, 36494 [ct]: UnsignedByteType, 36495 [pi]: HalfFloatType, 36496 [Sn]: UnsignedByteType, 36497 [In]: UnsignedByteType 36498 }; 36499 async function createRawTexture(container) { 36500 const { vkFormat } = container; 36501 if (FORMAT_MAP[vkFormat] === undefined) { 36502 throw new Error('THREE.KTX2Loader: Unsupported vkFormat.'); 36503 } 36504 // 36505 let zstd; 36506 if (container.supercompressionScheme === n) { 36507 if (!_zstd) { 36508 _zstd = new Promise(async (resolve)=>{ 36509 const zstd = new Q(); 36510 await zstd.init(); 36511 resolve(zstd); 36512 }); 36513 } 36514 zstd = await _zstd; 36515 } 36516 // 36517 const mipmaps = []; 36518 for(let levelIndex = 0; levelIndex < container.levels.length; levelIndex++){ 36519 const levelWidth = Math.max(1, container.pixelWidth >> levelIndex); 36520 const levelHeight = Math.max(1, container.pixelHeight >> levelIndex); 36521 const levelDepth = container.pixelDepth ? Math.max(1, container.pixelDepth >> levelIndex) : 0; 36522 const level = container.levels[levelIndex]; 36523 let levelData; 36524 if (container.supercompressionScheme === t) { 36525 levelData = level.levelData; 36526 } else if (container.supercompressionScheme === n) { 36527 levelData = zstd.decode(level.levelData, level.uncompressedByteLength); 36528 } else { 36529 throw new Error('THREE.KTX2Loader: Unsupported supercompressionScheme.'); 36530 } 36531 let data; 36532 if (TYPE_MAP[vkFormat] === FloatType) { 36533 data = new Float32Array(levelData.buffer, levelData.byteOffset, levelData.byteLength / Float32Array.BYTES_PER_ELEMENT); 36534 } else if (TYPE_MAP[vkFormat] === HalfFloatType) { 36535 data = new Uint16Array(levelData.buffer, levelData.byteOffset, levelData.byteLength / Uint16Array.BYTES_PER_ELEMENT); 36536 } else { 36537 data = levelData; 36538 } 36539 mipmaps.push({ 36540 data: data, 36541 width: levelWidth, 36542 height: levelHeight, 36543 depth: levelDepth 36544 }); 36545 } 36546 let texture; 36547 if (UNCOMPRESSED_FORMATS.has(FORMAT_MAP[vkFormat])) { 36548 texture = container.pixelDepth === 0 ? new DataTexture(mipmaps[0].data, container.pixelWidth, container.pixelHeight) : new Data3DTexture(mipmaps[0].data, container.pixelWidth, container.pixelHeight, container.pixelDepth); 36549 } else { 36550 if (container.pixelDepth > 0) throw new Error('THREE.KTX2Loader: Unsupported pixelDepth.'); 36551 texture = new CompressedTexture(mipmaps, container.pixelWidth, container.pixelHeight); 36552 texture.minFilter = mipmaps.length === 1 ? LinearFilter : LinearMipmapLinearFilter; 36553 texture.magFilter = LinearFilter; 36554 } 36555 texture.mipmaps = mipmaps; 36556 texture.type = TYPE_MAP[vkFormat]; 36557 texture.format = FORMAT_MAP[vkFormat]; 36558 texture.colorSpace = parseColorSpace(container); 36559 texture.needsUpdate = true; 36560 // 36561 return Promise.resolve(texture); 36562 } 36563 function parseColorSpace(container) { 36564 const dfd = container.dataFormatDescriptor[0]; 36565 if (dfd.colorPrimaries === C$1) { 36566 return dfd.transferFunction === u ? SRGBColorSpace : LinearSRGBColorSpace; 36567 } else if (dfd.colorPrimaries === R) { 36568 return dfd.transferFunction === u ? DisplayP3ColorSpace : LinearDisplayP3ColorSpace; 36569 } else if (dfd.colorPrimaries === T) { 36570 return NoColorSpace; 36571 } else { 36572 console.warn(`THREE.KTX2Loader: Unsupported color primaries, "${dfd.colorPrimaries}"`); 36573 return NoColorSpace; 36574 } 36575 } 36576 36577 var _a$9, _b$9; 36578 const $retainerCount = Symbol('retainerCount'); 36579 const $recentlyUsed = Symbol('recentlyUsed'); 36580 const $evict = Symbol('evict'); 36581 const $evictionThreshold = Symbol('evictionThreshold'); 36582 const $cache = Symbol('cache'); 36583 class CacheEvictionPolicy { 36584 set evictionThreshold(value) { 36585 this[$evictionThreshold] = value; 36586 this[$evict](); 36587 } 36588 get evictionThreshold() { 36589 return this[$evictionThreshold]; 36590 } 36591 get cache() { 36592 return this[$cache]; 36593 } 36594 retainerCount(key) { 36595 return this[$retainerCount].get(key) || 0; 36596 } 36597 reset() { 36598 this[$retainerCount].clear(); 36599 this[$recentlyUsed] = []; 36600 } 36601 retain(key) { 36602 if (!this[$retainerCount].has(key)) { 36603 this[$retainerCount].set(key, 0); 36604 } 36605 this[$retainerCount].set(key, this[$retainerCount].get(key) + 1); 36606 const recentlyUsedIndex = this[$recentlyUsed].indexOf(key); 36607 if (recentlyUsedIndex !== -1) { 36608 this[$recentlyUsed].splice(recentlyUsedIndex, 1); 36609 } 36610 this[$recentlyUsed].unshift(key); 36611 this[$evict](); 36612 } 36613 release(key) { 36614 if (this[$retainerCount].has(key)) { 36615 this[$retainerCount].set(key, Math.max(this[$retainerCount].get(key) - 1, 0)); 36616 } 36617 this[$evict](); 36618 } 36619 [(_a$9 = $retainerCount, _b$9 = $recentlyUsed, $evict)]() { 36620 if (this[$recentlyUsed].length < this[$evictionThreshold]) { 36621 return; 36622 } 36623 for(let i = this[$recentlyUsed].length - 1; i >= this[$evictionThreshold]; --i){ 36624 const key = this[$recentlyUsed][i]; 36625 const retainerCount = this[$retainerCount].get(key); 36626 if (retainerCount === 0) { 36627 this[$cache].delete(key); 36628 this[$recentlyUsed].splice(i, 1); 36629 } 36630 } 36631 } 36632 constructor(cache, evictionThreshold = 5){ 36633 this[_a$9] = new Map(); 36634 this[_b$9] = []; 36635 this[$cache] = cache; 36636 this[$evictionThreshold] = evictionThreshold; 36637 } 36638 } 36639 36640 const ensureUniqueNames = (variantNames)=>{ 36641 const uniqueNames = []; 36642 const knownNames = new Set(); 36643 for (const name of variantNames){ 36644 let uniqueName = name; 36645 let suffix = 0; 36646 while(knownNames.has(uniqueName)){ 36647 uniqueName = name + '.' + ++suffix; 36648 } 36649 knownNames.add(uniqueName); 36650 uniqueNames.push(uniqueName); 36651 } 36652 return uniqueNames; 36653 }; 36654 const mappingsArrayToTable = (extensionDef)=>{ 36655 const table = new Map(); 36656 for (const mapping of extensionDef.mappings){ 36657 for (const variant of mapping.variants){ 36658 table.set(variant, { 36659 material: null, 36660 gltfMaterialIndex: mapping.material 36661 }); 36662 } 36663 } 36664 return table; 36665 }; 36666 class GLTFMaterialsVariantsExtension { 36667 afterRoot(gltf) { 36668 const parser = this.parser; 36669 const json = parser.json; 36670 if (json.extensions === undefined || json.extensions[this.name] === undefined) { 36671 return null; 36672 } 36673 const extensionDef = json.extensions[this.name]; 36674 const variantsDef = extensionDef.variants || []; 36675 const variants = ensureUniqueNames(variantsDef.map((v)=>v.name)); 36676 for (const scene of gltf.scenes){ 36677 scene.traverse((object)=>{ 36678 const mesh = object; 36679 if (!mesh.material) { 36680 return; 36681 } 36682 const association = parser.associations.get(mesh); 36683 if (association == null || association.meshes == null || association.primitives == null) { 36684 return; 36685 } 36686 const meshDef = json.meshes[association.meshes]; 36687 const primitivesDef = meshDef.primitives; 36688 const primitiveDef = primitivesDef[association.primitives]; 36689 const extensionsDef = primitiveDef.extensions; 36690 if (!extensionsDef || !extensionsDef[this.name]) { 36691 return; 36692 } 36693 mesh.userData.variantMaterials = mappingsArrayToTable(extensionsDef[this.name]); 36694 }); 36695 } 36696 gltf.userData.variants = variants; 36697 return Promise.resolve(); 36698 } 36699 constructor(parser){ 36700 this.parser = parser; 36701 this.name = 'KHR_materials_variants'; 36702 } 36703 } 36704 36705 var _a$8, _b$8; 36706 Texture$1.DEFAULT_ANISOTROPY = 4; 36707 const loadWithLoader = (url, loader, progressCallback = ()=>{})=>{ 36708 const onProgress = (event)=>{ 36709 const fraction = event.loaded / event.total; 36710 progressCallback(Math.max(0, Math.min(1, isFinite(fraction) ? fraction : 1))); 36711 }; 36712 return new Promise((resolve, reject)=>{ 36713 loader.load(url, resolve, onProgress, reject); 36714 }); 36715 }; 36716 const fetchScript = (src)=>{ 36717 return new Promise((resolve, reject)=>{ 36718 const script = document.createElement('script'); 36719 document.body.appendChild(script); 36720 script.onload = resolve; 36721 script.onerror = reject; 36722 script.async = true; 36723 script.src = src; 36724 }); 36725 }; 36726 const cache = new Map(); 36727 const preloaded = new Map(); 36728 let dracoDecoderLocation; 36729 const dracoLoader = new DRACOLoader(); 36730 let ktx2TranscoderLocation; 36731 const ktx2Loader = new KTX2Loader(); 36732 let meshoptDecoderLocation; 36733 let meshoptDecoder; 36734 const $loader = Symbol('loader'); 36735 const $evictionPolicy = Symbol('evictionPolicy'); 36736 const $GLTFInstance = Symbol('GLTFInstance'); 36737 class CachingGLTFLoader extends EventDispatcher { 36738 static setDRACODecoderLocation(url) { 36739 dracoDecoderLocation = url; 36740 dracoLoader.setDecoderPath(url); 36741 } 36742 static getDRACODecoderLocation() { 36743 return dracoDecoderLocation; 36744 } 36745 static setKTX2TranscoderLocation(url) { 36746 ktx2TranscoderLocation = url; 36747 ktx2Loader.setTranscoderPath(url); 36748 } 36749 static getKTX2TranscoderLocation() { 36750 return ktx2TranscoderLocation; 36751 } 36752 static setMeshoptDecoderLocation(url) { 36753 if (meshoptDecoderLocation !== url) { 36754 meshoptDecoderLocation = url; 36755 meshoptDecoder = fetchScript(url).then(()=>MeshoptDecoder.ready).then(()=>MeshoptDecoder); 36756 } 36757 } 36758 static getMeshoptDecoderLocation() { 36759 return meshoptDecoderLocation; 36760 } 36761 static initializeKTX2Loader(renderer) { 36762 ktx2Loader.detectSupport(renderer); 36763 } 36764 static get cache() { 36765 return cache; 36766 } 36767 static clearCache() { 36768 cache.forEach((_value, url)=>{ 36769 this.delete(url); 36770 }); 36771 this[$evictionPolicy].reset(); 36772 } 36773 static has(url) { 36774 return cache.has(url); 36775 } 36776 static async delete(url) { 36777 if (!this.has(url)) { 36778 return; 36779 } 36780 const gltfLoads = cache.get(url); 36781 preloaded.delete(url); 36782 cache.delete(url); 36783 const gltf = await gltfLoads; 36784 gltf.dispose(); 36785 } 36786 static hasFinishedLoading(url) { 36787 return !!preloaded.get(url); 36788 } 36789 get [(_a$8 = $evictionPolicy, _b$8 = $loader, $evictionPolicy)]() { 36790 return this.constructor[$evictionPolicy]; 36791 } 36792 async preload(url, element, progressCallback = ()=>{}) { 36793 this[$loader].setWithCredentials(element.withCredentials); 36794 this.dispatchEvent({ 36795 type: 'preload', 36796 element: element, 36797 src: url 36798 }); 36799 if (!cache.has(url)) { 36800 if (meshoptDecoder != null) { 36801 this[$loader].setMeshoptDecoder(await meshoptDecoder); 36802 } 36803 const rawGLTFLoads = loadWithLoader(url, this[$loader], (progress)=>{ 36804 progressCallback(progress * 0.8); 36805 }); 36806 const GLTFInstance = this[$GLTFInstance]; 36807 const gltfInstanceLoads = rawGLTFLoads.then((rawGLTF)=>{ 36808 return GLTFInstance.prepare(rawGLTF); 36809 }).then((preparedGLTF)=>{ 36810 progressCallback(0.9); 36811 return new GLTFInstance(preparedGLTF); 36812 }).catch((reason)=>{ 36813 console.error(reason); 36814 return new GLTFInstance(); 36815 }); 36816 cache.set(url, gltfInstanceLoads); 36817 } 36818 await cache.get(url); 36819 preloaded.set(url, true); 36820 if (progressCallback) { 36821 progressCallback(1.0); 36822 } 36823 } 36824 async load(url, element, progressCallback = ()=>{}) { 36825 await this.preload(url, element, progressCallback); 36826 const gltf = await cache.get(url); 36827 const clone = await gltf.clone(); 36828 this[$evictionPolicy].retain(url); 36829 clone.dispose = ()=>{ 36830 this[$evictionPolicy].release(url); 36831 }; 36832 return clone; 36833 } 36834 constructor(GLTFInstance){ 36835 super(); 36836 this[_b$8] = new GLTFLoader().register((parser)=>new GLTFMaterialsVariantsExtension(parser)); 36837 this[$GLTFInstance] = GLTFInstance; 36838 this[$loader].setDRACOLoader(dracoLoader); 36839 this[$loader].setKTX2Loader(ktx2Loader); 36840 } 36841 } 36842 CachingGLTFLoader[_a$8] = new CacheEvictionPolicy(CachingGLTFLoader); 36843 36844 class CSS2DObject extends Object3D { 36845 copy(source, recursive) { 36846 super.copy(source, recursive); 36847 this.element = source.element.cloneNode(true); 36848 this.center = source.center; 36849 return this; 36850 } 36851 constructor(element = document.createElement('div')){ 36852 super(); 36853 this.isCSS2DObject = true; 36854 this.element = element; 36855 this.element.style.position = 'absolute'; 36856 this.element.style.userSelect = 'none'; 36857 this.element.setAttribute('draggable', false); 36858 this.center = new Vector2(0.5, 0.5); // ( 0, 0 ) is the lower left; ( 1, 1 ) is the top right 36859 this.addEventListener('removed', function() { 36860 this.traverse(function(object) { 36861 if (object.element instanceof object.element.ownerDocument.defaultView.Element && object.element.parentNode !== null) { 36862 object.element.remove(); 36863 } 36864 }); 36865 }); 36866 } 36867 } 36868 // 36869 const _vector = new Vector3(); 36870 const _viewMatrix = new Matrix4(); 36871 const _viewProjectionMatrix = new Matrix4(); 36872 const _a$7 = new Vector3(); 36873 const _b$7 = new Vector3(); 36874 class CSS2DRenderer { 36875 constructor(parameters = {}){ 36876 const _this = this; 36877 let _width, _height; 36878 let _widthHalf, _heightHalf; 36879 const cache = { 36880 objects: new WeakMap() 36881 }; 36882 const domElement = parameters.element !== undefined ? parameters.element : document.createElement('div'); 36883 domElement.style.overflow = 'hidden'; 36884 this.domElement = domElement; 36885 this.getSize = function() { 36886 return { 36887 width: _width, 36888 height: _height 36889 }; 36890 }; 36891 this.render = function(scene, camera) { 36892 if (scene.matrixWorldAutoUpdate === true) scene.updateMatrixWorld(); 36893 if (camera.parent === null && camera.matrixWorldAutoUpdate === true) camera.updateMatrixWorld(); 36894 _viewMatrix.copy(camera.matrixWorldInverse); 36895 _viewProjectionMatrix.multiplyMatrices(camera.projectionMatrix, _viewMatrix); 36896 renderObject(scene, scene, camera); 36897 zOrder(scene); 36898 }; 36899 this.setSize = function(width, height) { 36900 _width = width; 36901 _height = height; 36902 _widthHalf = _width / 2; 36903 _heightHalf = _height / 2; 36904 domElement.style.width = width + 'px'; 36905 domElement.style.height = height + 'px'; 36906 }; 36907 function hideObject(object) { 36908 if (object.isCSS2DObject) object.element.style.display = 'none'; 36909 for(let i = 0, l = object.children.length; i < l; i++){ 36910 hideObject(object.children[i]); 36911 } 36912 } 36913 function renderObject(object, scene, camera) { 36914 if (object.visible === false) { 36915 hideObject(object); 36916 return; 36917 } 36918 if (object.isCSS2DObject) { 36919 _vector.setFromMatrixPosition(object.matrixWorld); 36920 _vector.applyMatrix4(_viewProjectionMatrix); 36921 const visible = _vector.z >= -1 && _vector.z <= 1 && object.layers.test(camera.layers) === true; 36922 const element = object.element; 36923 element.style.display = visible === true ? '' : 'none'; 36924 if (visible === true) { 36925 object.onBeforeRender(_this, scene, camera); 36926 element.style.transform = 'translate(' + -100 * object.center.x + '%,' + -100 * object.center.y + '%)' + 'translate(' + (_vector.x * _widthHalf + _widthHalf) + 'px,' + (-_vector.y * _heightHalf + _heightHalf) + 'px)'; 36927 if (element.parentNode !== domElement) { 36928 domElement.appendChild(element); 36929 } 36930 object.onAfterRender(_this, scene, camera); 36931 } 36932 const objectData = { 36933 distanceToCameraSquared: getDistanceToSquared(camera, object) 36934 }; 36935 cache.objects.set(object, objectData); 36936 } 36937 for(let i = 0, l = object.children.length; i < l; i++){ 36938 renderObject(object.children[i], scene, camera); 36939 } 36940 } 36941 function getDistanceToSquared(object1, object2) { 36942 _a$7.setFromMatrixPosition(object1.matrixWorld); 36943 _b$7.setFromMatrixPosition(object2.matrixWorld); 36944 return _a$7.distanceToSquared(_b$7); 36945 } 36946 function filterAndFlatten(scene) { 36947 const result = []; 36948 scene.traverseVisible(function(object) { 36949 if (object.isCSS2DObject) result.push(object); 36950 }); 36951 return result; 36952 } 36953 function zOrder(scene) { 36954 const sorted = filterAndFlatten(scene).sort(function(a, b) { 36955 if (a.renderOrder !== b.renderOrder) { 36956 return b.renderOrder - a.renderOrder; 36957 } 36958 const distanceA = cache.objects.get(a).distanceToCameraSquared; 36959 const distanceB = cache.objects.get(b).distanceToCameraSquared; 36960 return distanceA - distanceB; 36961 }); 36962 const zMax = sorted.length; 36963 for(let i = 0, l = sorted.length; i < l; i++){ 36964 sorted[i].element.style.zIndex = zMax - i; 36965 } 36966 } 36967 } 36968 } 36969 36970 function reduceVertices(object, func, initialValue) { 36971 let value = initialValue; 36972 const vertex = new Vector3(); 36973 object.updateWorldMatrix(true, true); 36974 object.traverseVisible((child)=>{ 36975 const { geometry } = child; 36976 if (geometry !== undefined) { 36977 const { position } = geometry.attributes; 36978 if (position !== undefined) { 36979 for(let i = 0, l = position.count; i < l; i++){ 36980 if (child.isMesh) { 36981 child.getVertexPosition(i, vertex); 36982 } else { 36983 vertex.fromBufferAttribute(position, i); 36984 } 36985 if (!child.isSkinnedMesh) { 36986 vertex.applyMatrix4(child.matrixWorld); 36987 } 36988 value = func(value, vertex); 36989 } 36990 } 36991 } 36992 }); 36993 return value; 36994 } 36995 36996 /** 36997 * The KHR_mesh_quantization extension allows these extra attribute component types 36998 * 36999 * @see https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_mesh_quantization/README.md#extending-mesh-attributes 37000 */ const KHR_mesh_quantization_ExtraAttrTypes = { 37001 POSITION: [ 37002 'byte', 37003 'byte normalized', 37004 'unsigned byte', 37005 'unsigned byte normalized', 37006 'short', 37007 'short normalized', 37008 'unsigned short', 37009 'unsigned short normalized' 37010 ], 37011 NORMAL: [ 37012 'byte normalized', 37013 'short normalized' 37014 ], 37015 TANGENT: [ 37016 'byte normalized', 37017 'short normalized' 37018 ], 37019 TEXCOORD: [ 37020 'byte', 37021 'byte normalized', 37022 'unsigned byte', 37023 'short', 37024 'short normalized', 37025 'unsigned short' 37026 ] 37027 }; 37028 class GLTFExporter { 37029 register(callback) { 37030 if (this.pluginCallbacks.indexOf(callback) === -1) { 37031 this.pluginCallbacks.push(callback); 37032 } 37033 return this; 37034 } 37035 unregister(callback) { 37036 if (this.pluginCallbacks.indexOf(callback) !== -1) { 37037 this.pluginCallbacks.splice(this.pluginCallbacks.indexOf(callback), 1); 37038 } 37039 return this; 37040 } 37041 setTextureUtils(utils) { 37042 this.textureUtils = utils; 37043 return this; 37044 } 37045 /** 37046 * Parse scenes and generate GLTF output 37047 * 37048 * @param {Scene|Array<Scene>} input Scene or Array of THREE.Scenes 37049 * @param {Function} onDone Callback on completed 37050 * @param {Function} onError Callback on errors 37051 * @param {Object} options options 37052 */ parse(input, onDone, onError, options) { 37053 const writer = new GLTFWriter(); 37054 const plugins = []; 37055 for(let i = 0, il = this.pluginCallbacks.length; i < il; i++){ 37056 plugins.push(this.pluginCallbacks[i](writer)); 37057 } 37058 writer.setPlugins(plugins); 37059 writer.setTextureUtils(this.textureUtils); 37060 writer.writeAsync(input, onDone, options).catch(onError); 37061 } 37062 parseAsync(input, options) { 37063 const scope = this; 37064 return new Promise(function(resolve, reject) { 37065 scope.parse(input, resolve, reject, options); 37066 }); 37067 } 37068 constructor(){ 37069 this.textureUtils = null; 37070 this.pluginCallbacks = []; 37071 this.register(function(writer) { 37072 return new GLTFLightExtension(writer); 37073 }); 37074 this.register(function(writer) { 37075 return new GLTFMaterialsUnlitExtension(writer); 37076 }); 37077 this.register(function(writer) { 37078 return new GLTFMaterialsTransmissionExtension(writer); 37079 }); 37080 this.register(function(writer) { 37081 return new GLTFMaterialsVolumeExtension(writer); 37082 }); 37083 this.register(function(writer) { 37084 return new GLTFMaterialsIorExtension(writer); 37085 }); 37086 this.register(function(writer) { 37087 return new GLTFMaterialsSpecularExtension(writer); 37088 }); 37089 this.register(function(writer) { 37090 return new GLTFMaterialsClearcoatExtension(writer); 37091 }); 37092 this.register(function(writer) { 37093 return new GLTFMaterialsDispersionExtension(writer); 37094 }); 37095 this.register(function(writer) { 37096 return new GLTFMaterialsIridescenceExtension(writer); 37097 }); 37098 this.register(function(writer) { 37099 return new GLTFMaterialsSheenExtension(writer); 37100 }); 37101 this.register(function(writer) { 37102 return new GLTFMaterialsAnisotropyExtension(writer); 37103 }); 37104 this.register(function(writer) { 37105 return new GLTFMaterialsEmissiveStrengthExtension(writer); 37106 }); 37107 this.register(function(writer) { 37108 return new GLTFMaterialsBumpExtension(writer); 37109 }); 37110 this.register(function(writer) { 37111 return new GLTFMeshGpuInstancing(writer); 37112 }); 37113 } 37114 } 37115 //------------------------------------------------------------------------------ 37116 // Constants 37117 //------------------------------------------------------------------------------ 37118 const WEBGL_CONSTANTS = { 37119 POINTS: 0x0000, 37120 LINES: 0x0001, 37121 LINE_LOOP: 0x0002, 37122 LINE_STRIP: 0x0003, 37123 TRIANGLES: 0x0004, 37124 BYTE: 0x1400, 37125 UNSIGNED_BYTE: 0x1401, 37126 SHORT: 0x1402, 37127 UNSIGNED_SHORT: 0x1403, 37128 INT: 0x1404, 37129 UNSIGNED_INT: 0x1405, 37130 FLOAT: 0x1406, 37131 ARRAY_BUFFER: 0x8892, 37132 ELEMENT_ARRAY_BUFFER: 0x8893, 37133 NEAREST: 0x2600, 37134 LINEAR: 0x2601, 37135 NEAREST_MIPMAP_NEAREST: 0x2700, 37136 LINEAR_MIPMAP_NEAREST: 0x2701, 37137 NEAREST_MIPMAP_LINEAR: 0x2702, 37138 LINEAR_MIPMAP_LINEAR: 0x2703, 37139 CLAMP_TO_EDGE: 33071, 37140 MIRRORED_REPEAT: 33648, 37141 REPEAT: 10497 37142 }; 37143 const KHR_MESH_QUANTIZATION = 'KHR_mesh_quantization'; 37144 const THREE_TO_WEBGL = {}; 37145 THREE_TO_WEBGL[NearestFilter] = WEBGL_CONSTANTS.NEAREST; 37146 THREE_TO_WEBGL[NearestMipmapNearestFilter] = WEBGL_CONSTANTS.NEAREST_MIPMAP_NEAREST; 37147 THREE_TO_WEBGL[NearestMipmapLinearFilter] = WEBGL_CONSTANTS.NEAREST_MIPMAP_LINEAR; 37148 THREE_TO_WEBGL[LinearFilter] = WEBGL_CONSTANTS.LINEAR; 37149 THREE_TO_WEBGL[LinearMipmapNearestFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_NEAREST; 37150 THREE_TO_WEBGL[LinearMipmapLinearFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_LINEAR; 37151 THREE_TO_WEBGL[ClampToEdgeWrapping] = WEBGL_CONSTANTS.CLAMP_TO_EDGE; 37152 THREE_TO_WEBGL[RepeatWrapping] = WEBGL_CONSTANTS.REPEAT; 37153 THREE_TO_WEBGL[MirroredRepeatWrapping] = WEBGL_CONSTANTS.MIRRORED_REPEAT; 37154 const PATH_PROPERTIES = { 37155 scale: 'scale', 37156 position: 'translation', 37157 quaternion: 'rotation', 37158 morphTargetInfluences: 'weights' 37159 }; 37160 const DEFAULT_SPECULAR_COLOR = new Color(); 37161 // GLB constants 37162 // https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#glb-file-format-specification 37163 const GLB_HEADER_BYTES = 12; 37164 const GLB_HEADER_MAGIC = 0x46546C67; 37165 const GLB_VERSION = 2; 37166 const GLB_CHUNK_PREFIX_BYTES = 8; 37167 const GLB_CHUNK_TYPE_JSON = 0x4E4F534A; 37168 const GLB_CHUNK_TYPE_BIN = 0x004E4942; 37169 //------------------------------------------------------------------------------ 37170 // Utility functions 37171 //------------------------------------------------------------------------------ 37172 /** 37173 * Compare two arrays 37174 * @param {Array} array1 Array 1 to compare 37175 * @param {Array} array2 Array 2 to compare 37176 * @return {boolean} Returns true if both arrays are equal 37177 */ function equalArray(array1, array2) { 37178 return array1.length === array2.length && array1.every(function(element, index) { 37179 return element === array2[index]; 37180 }); 37181 } 37182 /** 37183 * Converts a string to an ArrayBuffer. 37184 * @param {string} text 37185 * @return {ArrayBuffer} 37186 */ function stringToArrayBuffer(text) { 37187 return new TextEncoder().encode(text).buffer; 37188 } 37189 /** 37190 * Is identity matrix 37191 * 37192 * @param {Matrix4} matrix 37193 * @returns {boolean} Returns true, if parameter is identity matrix 37194 */ function isIdentityMatrix(matrix) { 37195 return equalArray(matrix.elements, [ 37196 1, 37197 0, 37198 0, 37199 0, 37200 0, 37201 1, 37202 0, 37203 0, 37204 0, 37205 0, 37206 1, 37207 0, 37208 0, 37209 0, 37210 0, 37211 1 37212 ]); 37213 } 37214 /** 37215 * Get the min and max vectors from the given attribute 37216 * 37217 * @param {BufferAttribute} attribute Attribute to find the min/max in range from start to start + count 37218 * @param {number} start Start index 37219 * @param {number} count Range to cover 37220 * @return {Object} Object containing the `min` and `max` values (As an array of attribute.itemSize components) 37221 */ function getMinMax(attribute, start, count) { 37222 const output = { 37223 min: new Array(attribute.itemSize).fill(Number.POSITIVE_INFINITY), 37224 max: new Array(attribute.itemSize).fill(Number.NEGATIVE_INFINITY) 37225 };
vendor: 10,845 bytes, lines 37226-37485
37226 for(let i = start; i < start + count; i++){ 37227 for(let a = 0; a < attribute.itemSize; a++){ 37228 let value; 37229 if (attribute.itemSize > 4) { 37230 // no support for interleaved data for itemSize > 4 37231 value = attribute.array[i * attribute.itemSize + a]; 37232 } else { 37233 if (a === 0) value = attribute.getX(i); 37234 else if (a === 1) value = attribute.getY(i); 37235 else if (a === 2) value = attribute.getZ(i); 37236 else if (a === 3) value = attribute.getW(i); 37237 if (attribute.normalized === true) { 37238 value = MathUtils.normalize(value, attribute.array); 37239 } 37240 } 37241 output.min[a] = Math.min(output.min[a], value); 37242 output.max[a] = Math.max(output.max[a], value); 37243 } 37244 } 37245 return output; 37246 } 37247 /** 37248 * Get the required size + padding for a buffer, rounded to the next 4-byte boundary. 37249 * https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment 37250 * 37251 * @param {number} bufferSize The size the original buffer. Should be an integer. 37252 * @returns {number} new buffer size with required padding as an integer. 37253 * 37254 */ function getPaddedBufferSize(bufferSize) { 37255 return Math.ceil(bufferSize / 4) * 4; 37256 } 37257 /** 37258 * Returns a buffer aligned to 4-byte boundary. 37259 * 37260 * @param {ArrayBuffer} arrayBuffer Buffer to pad 37261 * @param {number} [paddingByte=0] Should be an integer 37262 * @returns {ArrayBuffer} The same buffer if it's already aligned to 4-byte boundary or a new buffer 37263 */ function getPaddedArrayBuffer(arrayBuffer, paddingByte = 0) { 37264 const paddedLength = getPaddedBufferSize(arrayBuffer.byteLength); 37265 if (paddedLength !== arrayBuffer.byteLength) { 37266 const array = new Uint8Array(paddedLength); 37267 array.set(new Uint8Array(arrayBuffer)); 37268 if (paddingByte !== 0) { 37269 for(let i = arrayBuffer.byteLength; i < paddedLength; i++){ 37270 array[i] = paddingByte; 37271 } 37272 } 37273 return array.buffer; 37274 } 37275 return arrayBuffer; 37276 } 37277 function getCanvas() { 37278 if (typeof document === 'undefined' && typeof OffscreenCanvas !== 'undefined') { 37279 return new OffscreenCanvas(1, 1); 37280 } 37281 return document.createElement('canvas'); 37282 } 37283 function getToBlobPromise(canvas, mimeType) { 37284 if (canvas.toBlob !== undefined) { 37285 return new Promise((resolve)=>canvas.toBlob(resolve, mimeType)); 37286 } 37287 let quality; 37288 // Blink's implementation of convertToBlob seems to default to a quality level of 100% 37289 // Use the Blink default quality levels of toBlob instead so that file sizes are comparable. 37290 if (mimeType === 'image/jpeg') { 37291 quality = 0.92; 37292 } else if (mimeType === 'image/webp') { 37293 quality = 0.8; 37294 } 37295 return canvas.convertToBlob({ 37296 type: mimeType, 37297 quality: quality 37298 }); 37299 } 37300 /** 37301 * Writer 37302 */ class GLTFWriter { 37303 setPlugins(plugins) { 37304 this.plugins = plugins; 37305 } 37306 setTextureUtils(utils) { 37307 this.textureUtils = utils; 37308 } 37309 /** 37310 * Parse scenes and generate GLTF output 37311 * 37312 * @param {Scene|Array<Scene>} input Scene or Array of THREE.Scenes 37313 * @param {Function} onDone Callback on completed 37314 * @param {Object} options options 37315 */ async writeAsync(input, onDone, options = {}) { 37316 this.options = Object.assign({ 37317 // default options 37318 binary: false, 37319 trs: false, 37320 onlyVisible: true, 37321 maxTextureSize: Infinity, 37322 animations: [], 37323 includeCustomExtensions: false 37324 }, options); 37325 if (this.options.animations.length > 0) { 37326 // Only TRS properties, and not matrices, may be targeted by animation. 37327 this.options.trs = true; 37328 } 37329 await this.processInputAsync(input); 37330 await Promise.all(this.pending); 37331 const writer = this; 37332 const buffers = writer.buffers; 37333 const json = writer.json; 37334 options = writer.options; 37335 const extensionsUsed = writer.extensionsUsed; 37336 const extensionsRequired = writer.extensionsRequired; 37337 // Merge buffers. 37338 const blob = new Blob(buffers, { 37339 type: 'application/octet-stream' 37340 }); 37341 // Declare extensions. 37342 const extensionsUsedList = Object.keys(extensionsUsed); 37343 const extensionsRequiredList = Object.keys(extensionsRequired); 37344 if (extensionsUsedList.length > 0) json.extensionsUsed = extensionsUsedList; 37345 if (extensionsRequiredList.length > 0) json.extensionsRequired = extensionsRequiredList; 37346 // Update bytelength of the single buffer. 37347 if (json.buffers && json.buffers.length > 0) json.buffers[0].byteLength = blob.size; 37348 if (options.binary === true) { 37349 // https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#glb-file-format-specification 37350 const reader = new FileReader(); 37351 reader.readAsArrayBuffer(blob); 37352 reader.onloadend = function() { 37353 // Binary chunk. 37354 const binaryChunk = getPaddedArrayBuffer(reader.result); 37355 const binaryChunkPrefix = new DataView(new ArrayBuffer(GLB_CHUNK_PREFIX_BYTES)); 37356 binaryChunkPrefix.setUint32(0, binaryChunk.byteLength, true); 37357 binaryChunkPrefix.setUint32(4, GLB_CHUNK_TYPE_BIN, true); 37358 // JSON chunk. 37359 const jsonChunk = getPaddedArrayBuffer(stringToArrayBuffer(JSON.stringify(json)), 0x20); 37360 const jsonChunkPrefix = new DataView(new ArrayBuffer(GLB_CHUNK_PREFIX_BYTES)); 37361 jsonChunkPrefix.setUint32(0, jsonChunk.byteLength, true); 37362 jsonChunkPrefix.setUint32(4, GLB_CHUNK_TYPE_JSON, true); 37363 // GLB header. 37364 const header = new ArrayBuffer(GLB_HEADER_BYTES); 37365 const headerView = new DataView(header); 37366 headerView.setUint32(0, GLB_HEADER_MAGIC, true); 37367 headerView.setUint32(4, GLB_VERSION, true); 37368 const totalByteLength = GLB_HEADER_BYTES + jsonChunkPrefix.byteLength + jsonChunk.byteLength + binaryChunkPrefix.byteLength + binaryChunk.byteLength; 37369 headerView.setUint32(8, totalByteLength, true); 37370 const glbBlob = new Blob([ 37371 header, 37372 jsonChunkPrefix, 37373 jsonChunk, 37374 binaryChunkPrefix, 37375 binaryChunk 37376 ], { 37377 type: 'application/octet-stream' 37378 }); 37379 const glbReader = new FileReader(); 37380 glbReader.readAsArrayBuffer(glbBlob); 37381 glbReader.onloadend = function() { 37382 onDone(glbReader.result); 37383 }; 37384 }; 37385 } else { 37386 if (json.buffers && json.buffers.length > 0) { 37387 const reader = new FileReader(); 37388 reader.readAsDataURL(blob); 37389 reader.onloadend = function() { 37390 const base64data = reader.result; 37391 json.buffers[0].uri = base64data; 37392 onDone(json); 37393 }; 37394 } else { 37395 onDone(json); 37396 } 37397 } 37398 } 37399 /** 37400 * Serializes a userData. 37401 * 37402 * @param {THREE.Object3D|THREE.Material} object 37403 * @param {Object} objectDef 37404 */ serializeUserData(object, objectDef) { 37405 if (Object.keys(object.userData).length === 0) return; 37406 const options = this.options; 37407 const extensionsUsed = this.extensionsUsed; 37408 try { 37409 const json = JSON.parse(JSON.stringify(object.userData)); 37410 if (options.includeCustomExtensions && json.gltfExtensions) { 37411 if (objectDef.extensions === undefined) objectDef.extensions = {}; 37412 for(const extensionName in json.gltfExtensions){ 37413 objectDef.extensions[extensionName] = json.gltfExtensions[extensionName]; 37414 extensionsUsed[extensionName] = true; 37415 } 37416 delete json.gltfExtensions; 37417 } 37418 if (Object.keys(json).length > 0) objectDef.extras = json; 37419 } catch (error) { 37420 console.warn('THREE.GLTFExporter: userData of \'' + object.name + '\' ' + 'won\'t be serialized because of JSON.stringify error - ' + error.message); 37421 } 37422 } 37423 /** 37424 * Returns ids for buffer attributes. 37425 * 37426 * @param {Object} attribute 37427 * @param {boolean} [isRelativeCopy=false] 37428 * @return {number} An integer 37429 */ getUID(attribute, isRelativeCopy = false) { 37430 if (this.uids.has(attribute) === false) { 37431 const uids = new Map(); 37432 uids.set(true, this.uid++); 37433 uids.set(false, this.uid++); 37434 this.uids.set(attribute, uids); 37435 } 37436 const uids = this.uids.get(attribute); 37437 return uids.get(isRelativeCopy); 37438 } 37439 /** 37440 * Checks if normal attribute values are normalized. 37441 * 37442 * @param {BufferAttribute} normal 37443 * @returns {boolean} 37444 */ isNormalizedNormalAttribute(normal) { 37445 const cache = this.cache; 37446 if (cache.attributesNormalized.has(normal)) return false; 37447 const v = new Vector3(); 37448 for(let i = 0, il = normal.count; i < il; i++){ 37449 // 0.0005 is from glTF-validator 37450 if (Math.abs(v.fromBufferAttribute(normal, i).length() - 1.0) > 0.0005) return false; 37451 } 37452 return true; 37453 } 37454 /** 37455 * Creates normalized normal buffer attribute. 37456 * 37457 * @param {BufferAttribute} normal 37458 * @returns {BufferAttribute} 37459 * 37460 */ createNormalizedNormalAttribute(normal) { 37461 const cache = this.cache; 37462 if (cache.attributesNormalized.has(normal)) return cache.attributesNormalized.get(normal); 37463 const attribute = normal.clone(); 37464 const v = new Vector3(); 37465 for(let i = 0, il = attribute.count; i < il; i++){ 37466 v.fromBufferAttribute(attribute, i); 37467 if (v.x === 0 && v.y === 0 && v.z === 0) { 37468 // if values can't be normalized set (1, 0, 0) 37469 v.setX(1.0); 37470 } else { 37471 v.normalize(); 37472 } 37473 attribute.setXYZ(i, v.x, v.y, v.z); 37474 } 37475 cache.attributesNormalized.set(normal, attribute); 37476 return attribute; 37477 } 37478 /** 37479 * Applies a texture transform, if present, to the map definition. Requires 37480 * the KHR_texture_transform extension. 37481 * 37482 * @param {Object} mapDef 37483 * @param {THREE.Texture} texture 37484 */ applyTextureTransform(mapDef, texture) { 37485 let didTransform = false;
vendor: 17,489 bytes, lines 37486-37860
37486 const transformDef = {}; 37487 if (texture.offset.x !== 0 || texture.offset.y !== 0) { 37488 transformDef.offset = texture.offset.toArray(); 37489 didTransform = true; 37490 } 37491 if (texture.rotation !== 0) { 37492 transformDef.rotation = texture.rotation; 37493 didTransform = true; 37494 } 37495 if (texture.repeat.x !== 1 || texture.repeat.y !== 1) { 37496 transformDef.scale = texture.repeat.toArray(); 37497 didTransform = true; 37498 } 37499 if (didTransform) { 37500 mapDef.extensions = mapDef.extensions || {}; 37501 mapDef.extensions['KHR_texture_transform'] = transformDef; 37502 this.extensionsUsed['KHR_texture_transform'] = true; 37503 } 37504 } 37505 async buildMetalRoughTextureAsync(metalnessMap, roughnessMap) { 37506 if (metalnessMap === roughnessMap) return metalnessMap; 37507 function getEncodingConversion(map) { 37508 if (map.colorSpace === SRGBColorSpace) { 37509 return function SRGBToLinear(c) { 37510 return c < 0.04045 ? c * 0.0773993808 : Math.pow(c * 0.9478672986 + 0.0521327014, 2.4); 37511 }; 37512 } 37513 return function LinearToLinear(c) { 37514 return c; 37515 }; 37516 } 37517 if (metalnessMap instanceof CompressedTexture) { 37518 metalnessMap = await this.decompressTextureAsync(metalnessMap); 37519 } 37520 if (roughnessMap instanceof CompressedTexture) { 37521 roughnessMap = await this.decompressTextureAsync(roughnessMap); 37522 } 37523 const metalness = metalnessMap ? metalnessMap.image : null; 37524 const roughness = roughnessMap ? roughnessMap.image : null; 37525 const width = Math.max(metalness ? metalness.width : 0, roughness ? roughness.width : 0); 37526 const height = Math.max(metalness ? metalness.height : 0, roughness ? roughness.height : 0); 37527 const canvas = getCanvas(); 37528 canvas.width = width; 37529 canvas.height = height; 37530 const context = canvas.getContext('2d', { 37531 willReadFrequently: true 37532 }); 37533 context.fillStyle = '#00ffff'; 37534 context.fillRect(0, 0, width, height); 37535 const composite = context.getImageData(0, 0, width, height); 37536 if (metalness) { 37537 context.drawImage(metalness, 0, 0, width, height); 37538 const convert = getEncodingConversion(metalnessMap); 37539 const data = context.getImageData(0, 0, width, height).data; 37540 for(let i = 2; i < data.length; i += 4){ 37541 composite.data[i] = convert(data[i] / 256) * 256; 37542 } 37543 } 37544 if (roughness) { 37545 context.drawImage(roughness, 0, 0, width, height); 37546 const convert = getEncodingConversion(roughnessMap); 37547 const data = context.getImageData(0, 0, width, height).data; 37548 for(let i = 1; i < data.length; i += 4){ 37549 composite.data[i] = convert(data[i] / 256) * 256; 37550 } 37551 } 37552 context.putImageData(composite, 0, 0); 37553 // 37554 const reference = metalnessMap || roughnessMap; 37555 const texture = reference.clone(); 37556 texture.source = new Source(canvas); 37557 texture.colorSpace = NoColorSpace; 37558 texture.channel = (metalnessMap || roughnessMap).channel; 37559 if (metalnessMap && roughnessMap && metalnessMap.channel !== roughnessMap.channel) { 37560 console.warn('THREE.GLTFExporter: UV channels for metalnessMap and roughnessMap textures must match.'); 37561 } 37562 console.warn('THREE.GLTFExporter: Merged metalnessMap and roughnessMap textures.'); 37563 return texture; 37564 } 37565 async decompressTextureAsync(texture, maxTextureSize = Infinity) { 37566 if (this.textureUtils === null) { 37567 throw new Error('THREE.GLTFExporter: setTextureUtils() must be called to process compressed textures.'); 37568 } 37569 return await this.textureUtils.decompress(texture, maxTextureSize); 37570 } 37571 /** 37572 * Process a buffer to append to the default one. 37573 * @param {ArrayBuffer} buffer 37574 * @return {0} 37575 */ processBuffer(buffer) { 37576 const json = this.json; 37577 const buffers = this.buffers; 37578 if (!json.buffers) json.buffers = [ 37579 { 37580 byteLength: 0 37581 } 37582 ]; 37583 // All buffers are merged before export. 37584 buffers.push(buffer); 37585 return 0; 37586 } 37587 /** 37588 * Process and generate a BufferView 37589 * @param {BufferAttribute} attribute 37590 * @param {number} componentType 37591 * @param {number} start 37592 * @param {number} count 37593 * @param {?number} target Target usage of the BufferView 37594 * @return {Object} 37595 */ processBufferView(attribute, componentType, start, count, target) { 37596 const json = this.json; 37597 if (!json.bufferViews) json.bufferViews = []; 37598 // Create a new dataview and dump the attribute's array into it 37599 let componentSize; 37600 switch(componentType){ 37601 case WEBGL_CONSTANTS.BYTE: 37602 case WEBGL_CONSTANTS.UNSIGNED_BYTE: 37603 componentSize = 1; 37604 break; 37605 case WEBGL_CONSTANTS.SHORT: 37606 case WEBGL_CONSTANTS.UNSIGNED_SHORT: 37607 componentSize = 2; 37608 break; 37609 default: 37610 componentSize = 4; 37611 } 37612 let byteStride = attribute.itemSize * componentSize; 37613 if (target === WEBGL_CONSTANTS.ARRAY_BUFFER) { 37614 // Each element of a vertex attribute MUST be aligned to 4-byte boundaries 37615 // inside a bufferView 37616 byteStride = Math.ceil(byteStride / 4) * 4; 37617 } 37618 const byteLength = getPaddedBufferSize(count * byteStride); 37619 const dataView = new DataView(new ArrayBuffer(byteLength)); 37620 let offset = 0; 37621 for(let i = start; i < start + count; i++){ 37622 for(let a = 0; a < attribute.itemSize; a++){ 37623 let value; 37624 if (attribute.itemSize > 4) { 37625 // no support for interleaved data for itemSize > 4 37626 value = attribute.array[i * attribute.itemSize + a]; 37627 } else { 37628 if (a === 0) value = attribute.getX(i); 37629 else if (a === 1) value = attribute.getY(i); 37630 else if (a === 2) value = attribute.getZ(i); 37631 else if (a === 3) value = attribute.getW(i); 37632 if (attribute.normalized === true) { 37633 value = MathUtils.normalize(value, attribute.array); 37634 } 37635 } 37636 if (componentType === WEBGL_CONSTANTS.FLOAT) { 37637 dataView.setFloat32(offset, value, true); 37638 } else if (componentType === WEBGL_CONSTANTS.INT) { 37639 dataView.setInt32(offset, value, true); 37640 } else if (componentType === WEBGL_CONSTANTS.UNSIGNED_INT) { 37641 dataView.setUint32(offset, value, true); 37642 } else if (componentType === WEBGL_CONSTANTS.SHORT) { 37643 dataView.setInt16(offset, value, true); 37644 } else if (componentType === WEBGL_CONSTANTS.UNSIGNED_SHORT) { 37645 dataView.setUint16(offset, value, true); 37646 } else if (componentType === WEBGL_CONSTANTS.BYTE) { 37647 dataView.setInt8(offset, value); 37648 } else if (componentType === WEBGL_CONSTANTS.UNSIGNED_BYTE) { 37649 dataView.setUint8(offset, value); 37650 } 37651 offset += componentSize; 37652 } 37653 if (offset % byteStride !== 0) { 37654 offset += byteStride - offset % byteStride; 37655 } 37656 } 37657 const bufferViewDef = { 37658 buffer: this.processBuffer(dataView.buffer), 37659 byteOffset: this.byteOffset, 37660 byteLength: byteLength 37661 }; 37662 if (target !== undefined) bufferViewDef.target = target; 37663 if (target === WEBGL_CONSTANTS.ARRAY_BUFFER) { 37664 // Only define byteStride for vertex attributes. 37665 bufferViewDef.byteStride = byteStride; 37666 } 37667 this.byteOffset += byteLength; 37668 json.bufferViews.push(bufferViewDef); 37669 // @TODO Merge bufferViews where possible. 37670 const output = { 37671 id: json.bufferViews.length - 1, 37672 byteLength: 0 37673 }; 37674 return output; 37675 } 37676 /** 37677 * Process and generate a BufferView from an image Blob. 37678 * @param {Blob} blob 37679 * @return {Promise<number>} An integer 37680 */ processBufferViewImage(blob) { 37681 const writer = this; 37682 const json = writer.json; 37683 if (!json.bufferViews) json.bufferViews = []; 37684 return new Promise(function(resolve) { 37685 const reader = new FileReader(); 37686 reader.readAsArrayBuffer(blob); 37687 reader.onloadend = function() { 37688 const buffer = getPaddedArrayBuffer(reader.result); 37689 const bufferViewDef = { 37690 buffer: writer.processBuffer(buffer), 37691 byteOffset: writer.byteOffset, 37692 byteLength: buffer.byteLength 37693 }; 37694 writer.byteOffset += buffer.byteLength; 37695 resolve(json.bufferViews.push(bufferViewDef) - 1); 37696 }; 37697 }); 37698 } 37699 /** 37700 * Process attribute to generate an accessor 37701 * @param {BufferAttribute} attribute Attribute to process 37702 * @param {?BufferGeometry} geometry Geometry used for truncated draw range 37703 * @param {number} [start=0] 37704 * @param {number} [count=Infinity] 37705 * @return {?number} Index of the processed accessor on the "accessors" array 37706 */ processAccessor(attribute, geometry, start, count) { 37707 const json = this.json; 37708 const types = { 37709 1: 'SCALAR', 37710 2: 'VEC2', 37711 3: 'VEC3', 37712 4: 'VEC4', 37713 9: 'MAT3', 37714 16: 'MAT4' 37715 }; 37716 let componentType; 37717 // Detect the component type of the attribute array 37718 if (attribute.array.constructor === Float32Array) { 37719 componentType = WEBGL_CONSTANTS.FLOAT; 37720 } else if (attribute.array.constructor === Int32Array) { 37721 componentType = WEBGL_CONSTANTS.INT; 37722 } else if (attribute.array.constructor === Uint32Array) { 37723 componentType = WEBGL_CONSTANTS.UNSIGNED_INT; 37724 } else if (attribute.array.constructor === Int16Array) { 37725 componentType = WEBGL_CONSTANTS.SHORT; 37726 } else if (attribute.array.constructor === Uint16Array) { 37727 componentType = WEBGL_CONSTANTS.UNSIGNED_SHORT; 37728 } else if (attribute.array.constructor === Int8Array) { 37729 componentType = WEBGL_CONSTANTS.BYTE; 37730 } else if (attribute.array.constructor === Uint8Array) { 37731 componentType = WEBGL_CONSTANTS.UNSIGNED_BYTE; 37732 } else { 37733 throw new Error('THREE.GLTFExporter: Unsupported bufferAttribute component type: ' + attribute.array.constructor.name); 37734 } 37735 if (start === undefined) start = 0; 37736 if (count === undefined || count === Infinity) count = attribute.count; 37737 // Skip creating an accessor if the attribute doesn't have data to export 37738 if (count === 0) return null; 37739 const minMax = getMinMax(attribute, start, count); 37740 let bufferViewTarget; 37741 // If geometry isn't provided, don't infer the target usage of the bufferView. For 37742 // animation samplers, target must not be set. 37743 if (geometry !== undefined) { 37744 bufferViewTarget = attribute === geometry.index ? WEBGL_CONSTANTS.ELEMENT_ARRAY_BUFFER : WEBGL_CONSTANTS.ARRAY_BUFFER; 37745 } 37746 const bufferView = this.processBufferView(attribute, componentType, start, count, bufferViewTarget); 37747 const accessorDef = { 37748 bufferView: bufferView.id, 37749 byteOffset: bufferView.byteOffset, 37750 componentType: componentType, 37751 count: count, 37752 max: minMax.max, 37753 min: minMax.min, 37754 type: types[attribute.itemSize] 37755 }; 37756 if (attribute.normalized === true) accessorDef.normalized = true; 37757 if (!json.accessors) json.accessors = []; 37758 return json.accessors.push(accessorDef) - 1; 37759 } 37760 /** 37761 * Process image 37762 * @param {Image} image to process 37763 * @param {number} format Identifier of the format (RGBAFormat) 37764 * @param {boolean} flipY before writing out the image 37765 * @param {string} mimeType export format 37766 * @return {number} Index of the processed texture in the "images" array 37767 */ processImage(image, format, flipY, mimeType = 'image/png') { 37768 if (image !== null) { 37769 const writer = this; 37770 const cache = writer.cache; 37771 const json = writer.json; 37772 const options = writer.options; 37773 const pending = writer.pending; 37774 if (!cache.images.has(image)) cache.images.set(image, {}); 37775 const cachedImages = cache.images.get(image); 37776 const key = mimeType + ':flipY/' + flipY.toString(); 37777 if (cachedImages[key] !== undefined) return cachedImages[key]; 37778 if (!json.images) json.images = []; 37779 const imageDef = { 37780 mimeType: mimeType 37781 }; 37782 const canvas = getCanvas(); 37783 canvas.width = Math.min(image.width, options.maxTextureSize); 37784 canvas.height = Math.min(image.height, options.maxTextureSize); 37785 const ctx = canvas.getContext('2d', { 37786 willReadFrequently: true 37787 }); 37788 if (flipY === true) { 37789 ctx.translate(0, canvas.height); 37790 ctx.scale(1, -1); 37791 } 37792 if (image.data !== undefined) { 37793 if (format !== RGBAFormat) { 37794 console.error('GLTFExporter: Only RGBAFormat is supported.', format); 37795 } 37796 if (image.width > options.maxTextureSize || image.height > options.maxTextureSize) { 37797 console.warn('GLTFExporter: Image size is bigger than maxTextureSize', image); 37798 } 37799 const data = new Uint8ClampedArray(image.height * image.width * 4); 37800 for(let i = 0; i < data.length; i += 4){ 37801 data[i + 0] = image.data[i + 0]; 37802 data[i + 1] = image.data[i + 1]; 37803 data[i + 2] = image.data[i + 2]; 37804 data[i + 3] = image.data[i + 3]; 37805 } 37806 ctx.putImageData(new ImageData(data, image.width, image.height), 0, 0); 37807 } else { 37808 if (typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement || typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement || typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap || typeof OffscreenCanvas !== 'undefined' && image instanceof OffscreenCanvas) { 37809 ctx.drawImage(image, 0, 0, canvas.width, canvas.height); 37810 } else { 37811 throw new Error('THREE.GLTFExporter: Invalid image type. Use HTMLImageElement, HTMLCanvasElement, ImageBitmap or OffscreenCanvas.'); 37812 } 37813 } 37814 if (options.binary === true) { 37815 pending.push(getToBlobPromise(canvas, mimeType).then((blob)=>writer.processBufferViewImage(blob)).then((bufferViewIndex)=>{ 37816 imageDef.bufferView = bufferViewIndex; 37817 })); 37818 } else { 37819 if (canvas.toDataURL !== undefined) { 37820 imageDef.uri = canvas.toDataURL(mimeType); 37821 } else { 37822 pending.push(getToBlobPromise(canvas, mimeType).then((blob)=>new FileReader().readAsDataURL(blob)).then((dataURL)=>{ 37823 imageDef.uri = dataURL; 37824 })); 37825 } 37826 } 37827 const index = json.images.push(imageDef) - 1; 37828 cachedImages[key] = index; 37829 return index; 37830 } else { 37831 throw new Error('THREE.GLTFExporter: No valid image data found. Unable to process texture.'); 37832 } 37833 } 37834 /** 37835 * Process sampler 37836 * @param {Texture} map Texture to process 37837 * @return {number} Index of the processed texture in the "samplers" array 37838 */ processSampler(map) { 37839 const json = this.json; 37840 if (!json.samplers) json.samplers = []; 37841 const samplerDef = { 37842 magFilter: THREE_TO_WEBGL[map.magFilter], 37843 minFilter: THREE_TO_WEBGL[map.minFilter], 37844 wrapS: THREE_TO_WEBGL[map.wrapS], 37845 wrapT: THREE_TO_WEBGL[map.wrapT] 37846 }; 37847 return json.samplers.push(samplerDef) - 1; 37848 } 37849 /** 37850 * Process texture 37851 * @param {Texture} map Map to process 37852 * @return {Promise<number>} Index of the processed texture in the "textures" array 37853 */ async processTextureAsync(map) { 37854 const writer = this; 37855 const options = writer.options; 37856 const cache = this.cache; 37857 const json = this.json; 37858 if (cache.textures.has(map)) return cache.textures.get(map); 37859 if (!json.textures) json.textures = []; 37860 // make non-readable textures (e.g. CompressedTexture) readable by blitting them into a
vendor: 5,024 bytes, lines 37860-37967
37860new texture 37861 if (map instanceof CompressedTexture) { 37862 map = await this.decompressTextureAsync(map, options.maxTextureSize); 37863 } 37864 let mimeType = map.userData.mimeType; 37865 if (mimeType === 'image/webp') mimeType = 'image/png'; 37866 const textureDef = { 37867 sampler: this.processSampler(map), 37868 source: this.processImage(map.image, map.format, map.flipY, mimeType) 37869 }; 37870 if (map.name) textureDef.name = map.name; 37871 await this._invokeAllAsync(async function(ext) { 37872 ext.writeTexture && await ext.writeTexture(map, textureDef); 37873 }); 37874 const index = json.textures.push(textureDef) - 1; 37875 cache.textures.set(map, index); 37876 return index; 37877 } 37878 /** 37879 * Process material 37880 * @param {THREE.Material} material Material to process 37881 * @return {Promise<number|null>} Index of the processed material in the "materials" array 37882 */ async processMaterialAsync(material) { 37883 const cache = this.cache; 37884 const json = this.json; 37885 if (cache.materials.has(material)) return cache.materials.get(material); 37886 if (material.isShaderMaterial) { 37887 console.warn('GLTFExporter: THREE.ShaderMaterial not supported.'); 37888 return null; 37889 } 37890 if (!json.materials) json.materials = []; 37891 // @QUESTION Should we avoid including any attribute that has the default value? 37892 const materialDef = { 37893 pbrMetallicRoughness: {} 37894 }; 37895 if (material.isMeshStandardMaterial !== true && material.isMeshBasicMaterial !== true) { 37896 console.warn('GLTFExporter: Use MeshStandardMaterial or MeshBasicMaterial for best results.'); 37897 } 37898 // pbrMetallicRoughness.baseColorFactor 37899 const color = material.color.toArray().concat([ 37900 material.opacity 37901 ]); 37902 if (!equalArray(color, [ 37903 1, 37904 1, 37905 1, 37906 1 37907 ])) { 37908 materialDef.pbrMetallicRoughness.baseColorFactor = color; 37909 } 37910 if (material.isMeshStandardMaterial) { 37911 materialDef.pbrMetallicRoughness.metallicFactor = material.metalness; 37912 materialDef.pbrMetallicRoughness.roughnessFactor = material.roughness; 37913 } else { 37914 materialDef.pbrMetallicRoughness.metallicFactor = 0; 37915 materialDef.pbrMetallicRoughness.roughnessFactor = 1; 37916 } 37917 // pbrMetallicRoughness.metallicRoughnessTexture 37918 if (material.metalnessMap || material.roughnessMap) { 37919 const metalRoughTexture = await this.buildMetalRoughTextureAsync(material.metalnessMap, material.roughnessMap); 37920 const metalRoughMapDef = { 37921 index: await this.processTextureAsync(metalRoughTexture), 37922 texCoord: metalRoughTexture.channel 37923 }; 37924 this.applyTextureTransform(metalRoughMapDef, metalRoughTexture); 37925 materialDef.pbrMetallicRoughness.metallicRoughnessTexture = metalRoughMapDef; 37926 } 37927 // pbrMetallicRoughness.baseColorTexture 37928 if (material.map) { 37929 const baseColorMapDef = { 37930 index: await this.processTextureAsync(material.map), 37931 texCoord: material.map.channel 37932 }; 37933 this.applyTextureTransform(baseColorMapDef, material.map); 37934 materialDef.pbrMetallicRoughness.baseColorTexture = baseColorMapDef; 37935 } 37936 if (material.emissive) { 37937 const emissive = material.emissive; 37938 const maxEmissiveComponent = Math.max(emissive.r, emissive.g, emissive.b); 37939 if (maxEmissiveComponent > 0) { 37940 materialDef.emissiveFactor = material.emissive.toArray(); 37941 } 37942 // emissiveTexture 37943 if (material.emissiveMap) { 37944 const emissiveMapDef = { 37945 index: await this.processTextureAsync(material.emissiveMap), 37946 texCoord: material.emissiveMap.channel 37947 }; 37948 this.applyTextureTransform(emissiveMapDef, material.emissiveMap); 37949 materialDef.emissiveTexture = emissiveMapDef; 37950 } 37951 } 37952 // normalTexture 37953 if (material.normalMap) { 37954 const normalMapDef = { 37955 index: await this.processTextureAsync(material.normalMap), 37956 texCoord: material.normalMap.channel 37957 }; 37958 if (material.normalScale && material.normalScale.x !== 1) { 37959 // glTF normal scale is univariate. Ignore `y`, which may be flipped. 37960 // Context: https://github.com/mrdoob/three.js/issues/11438#issuecomment-507003995 37961 normalMapDef.scale = material.normalScale.x; 37962 } 37963 this.applyTextureTransform(normalMapDef, material.normalMap); 37964 materialDef.normalTexture = normalMapDef; 37965 } 37966 // occlusionTexture 37967 if (material.aoMap) {
vendor: 4,402 bytes, lines 37968-38062
37968 const occlusionMapDef = { 37969 index: await this.processTextureAsync(material.aoMap), 37970 texCoord: material.aoMap.channel 37971 }; 37972 if (material.aoMapIntensity !== 1.0) { 37973 occlusionMapDef.strength = material.aoMapIntensity; 37974 } 37975 this.applyTextureTransform(occlusionMapDef, material.aoMap); 37976 materialDef.occlusionTexture = occlusionMapDef; 37977 } 37978 // alphaMode 37979 if (material.transparent) { 37980 materialDef.alphaMode = 'BLEND'; 37981 } else { 37982 if (material.alphaTest > 0.0) { 37983 materialDef.alphaMode = 'MASK'; 37984 materialDef.alphaCutoff = material.alphaTest; 37985 } 37986 } 37987 // doubleSided 37988 if (material.side === DoubleSide) materialDef.doubleSided = true; 37989 if (material.name !== '') materialDef.name = material.name; 37990 this.serializeUserData(material, materialDef); 37991 await this._invokeAllAsync(async function(ext) { 37992 ext.writeMaterialAsync && await ext.writeMaterialAsync(material, materialDef); 37993 }); 37994 const index = json.materials.push(materialDef) - 1; 37995 cache.materials.set(material, index); 37996 return index; 37997 } 37998 /** 37999 * Process mesh 38000 * @param {THREE.Mesh} mesh Mesh to process 38001 * @return {Promise<number|null>} Index of the processed mesh in the "meshes" array 38002 */ async processMeshAsync(mesh) { 38003 const cache = this.cache; 38004 const json = this.json; 38005 const meshCacheKeyParts = [ 38006 mesh.geometry.uuid 38007 ]; 38008 if (Array.isArray(mesh.material)) { 38009 for(let i = 0, l = mesh.material.length; i < l; i++){ 38010 meshCacheKeyParts.push(mesh.material[i].uuid); 38011 } 38012 } else { 38013 meshCacheKeyParts.push(mesh.material.uuid); 38014 } 38015 const meshCacheKey = meshCacheKeyParts.join(':'); 38016 if (cache.meshes.has(meshCacheKey)) return cache.meshes.get(meshCacheKey); 38017 const geometry = mesh.geometry; 38018 let mode; 38019 // Use the correct mode 38020 if (mesh.isLineSegments) { 38021 mode = WEBGL_CONSTANTS.LINES; 38022 } else if (mesh.isLineLoop) { 38023 mode = WEBGL_CONSTANTS.LINE_LOOP; 38024 } else if (mesh.isLine) { 38025 mode = WEBGL_CONSTANTS.LINE_STRIP; 38026 } else if (mesh.isPoints) { 38027 mode = WEBGL_CONSTANTS.POINTS; 38028 } else { 38029 mode = mesh.material.wireframe ? WEBGL_CONSTANTS.LINES : WEBGL_CONSTANTS.TRIANGLES; 38030 } 38031 const meshDef = {}; 38032 const attributes = {}; 38033 const primitives = []; 38034 const targets = []; 38035 // Conversion between attributes names in threejs and gltf spec 38036 const nameConversion = { 38037 uv: 'TEXCOORD_0', 38038 uv1: 'TEXCOORD_1', 38039 uv2: 'TEXCOORD_2', 38040 uv3: 'TEXCOORD_3', 38041 color: 'COLOR_0', 38042 skinWeight: 'WEIGHTS_0', 38043 skinIndex: 'JOINTS_0' 38044 }; 38045 const originalNormal = geometry.getAttribute('normal'); 38046 if (originalNormal !== undefined && !this.isNormalizedNormalAttribute(originalNormal)) { 38047 console.warn('THREE.GLTFExporter: Creating normalized normal attribute from the non-normalized one.'); 38048 geometry.setAttribute('normal', this.createNormalizedNormalAttribute(originalNormal)); 38049 } 38050 // @QUESTION Detect if .vertexColors = true? 38051 // For every attribute create an accessor 38052 let modifiedAttribute = null; 38053 for(let attributeName in geometry.attributes){ 38054 // Ignore morph target attributes, which are exported later. 38055 if (attributeName.slice(0, 5) === 'morph') continue; 38056 const attribute = geometry.attributes[attributeName]; 38057 attributeName = nameConversion[attributeName] || attributeName.toUpperCase(); 38058 // Prefix all geometry attributes except the ones specifically 38059 // listed in the spec; non-spec attributes are considered custom. 38060 const validVertexAttributes = /^(POSITION|NORMAL|TANGENT|TEXCOORD_\d+|COLOR_\d+|JOINTS_\d+|WEIGHTS_\d+)$/; 38061 if (!validVertexAttributes.test(attributeName)) attributeName = '_' + attributeName; 38062 if (cache.attributes.has(this.getUID(attribute))) {
vendor: 10,387 bytes, lines 38063-38268
38063 attributes[attributeName] = cache.attributes.get(this.getUID(attribute)); 38064 continue; 38065 } 38066 // Enforce glTF vertex attribute requirements: 38067 // - JOINTS_0 must be UNSIGNED_BYTE or UNSIGNED_SHORT 38068 // - Only custom attributes may be INT or UNSIGNED_INT 38069 modifiedAttribute = null; 38070 const array = attribute.array; 38071 if (attributeName === 'JOINTS_0' && !(array instanceof Uint16Array) && !(array instanceof Uint8Array)) { 38072 console.warn('GLTFExporter: Attribute "skinIndex" converted to type UNSIGNED_SHORT.'); 38073 modifiedAttribute = new BufferAttribute(new Uint16Array(array), attribute.itemSize, attribute.normalized); 38074 } else if ((array instanceof Uint32Array || array instanceof Int32Array) && !attributeName.startsWith('_')) { 38075 console.warn(`GLTFExporter: Attribute "${attributeName}" converted to type FLOAT.`); 38076 modifiedAttribute = GLTFExporter.Utils.toFloat32BufferAttribute(attribute); 38077 } 38078 const accessor = this.processAccessor(modifiedAttribute || attribute, geometry); 38079 if (accessor !== null) { 38080 if (!attributeName.startsWith('_')) { 38081 this.detectMeshQuantization(attributeName, attribute); 38082 } 38083 attributes[attributeName] = accessor; 38084 cache.attributes.set(this.getUID(attribute), accessor); 38085 } 38086 } 38087 if (originalNormal !== undefined) geometry.setAttribute('normal', originalNormal); 38088 // Skip if no exportable attributes found 38089 if (Object.keys(attributes).length === 0) return null; 38090 // Morph targets 38091 if (mesh.morphTargetInfluences !== undefined && mesh.morphTargetInfluences.length > 0) { 38092 const weights = []; 38093 const targetNames = []; 38094 const reverseDictionary = {}; 38095 if (mesh.morphTargetDictionary !== undefined) { 38096 for(const key in mesh.morphTargetDictionary){ 38097 reverseDictionary[mesh.morphTargetDictionary[key]] = key; 38098 } 38099 } 38100 for(let i = 0; i < mesh.morphTargetInfluences.length; ++i){ 38101 const target = {}; 38102 let warned = false; 38103 for(const attributeName in geometry.morphAttributes){ 38104 // glTF 2.0 morph supports only POSITION/NORMAL/TANGENT. 38105 // Three.js doesn't support TANGENT yet. 38106 if (attributeName !== 'position' && attributeName !== 'normal') { 38107 if (!warned) { 38108 console.warn('GLTFExporter: Only POSITION and NORMAL morph are supported.'); 38109 warned = true; 38110 } 38111 continue; 38112 } 38113 const attribute = geometry.morphAttributes[attributeName][i]; 38114 const gltfAttributeName = attributeName.toUpperCase(); 38115 // Three.js morph attribute has absolute values while the one of glTF has relative values. 38116 // 38117 // glTF 2.0 Specification: 38118 // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#morph-targets 38119 const baseAttribute = geometry.attributes[attributeName]; 38120 if (cache.attributes.has(this.getUID(attribute, true))) { 38121 target[gltfAttributeName] = cache.attributes.get(this.getUID(attribute, true)); 38122 continue; 38123 } 38124 // Clones attribute not to override 38125 const relativeAttribute = attribute.clone(); 38126 if (!geometry.morphTargetsRelative) { 38127 for(let j = 0, jl = attribute.count; j < jl; j++){ 38128 for(let a = 0; a < attribute.itemSize; a++){ 38129 if (a === 0) relativeAttribute.setX(j, attribute.getX(j) - baseAttribute.getX(j)); 38130 if (a === 1) relativeAttribute.setY(j, attribute.getY(j) - baseAttribute.getY(j)); 38131 if (a === 2) relativeAttribute.setZ(j, attribute.getZ(j) - baseAttribute.getZ(j)); 38132 if (a === 3) relativeAttribute.setW(j, attribute.getW(j) - baseAttribute.getW(j)); 38133 } 38134 } 38135 } 38136 target[gltfAttributeName] = this.processAccessor(relativeAttribute, geometry); 38137 cache.attributes.set(this.getUID(baseAttribute, true), target[gltfAttributeName]); 38138 } 38139 targets.push(target); 38140 weights.push(mesh.morphTargetInfluences[i]); 38141 if (mesh.morphTargetDictionary !== undefined) targetNames.push(reverseDictionary[i]); 38142 } 38143 meshDef.weights = weights; 38144 if (targetNames.length > 0) { 38145 meshDef.extras = {}; 38146 meshDef.extras.targetNames = targetNames; 38147 } 38148 } 38149 const isMultiMaterial = Array.isArray(mesh.material); 38150 if (isMultiMaterial && geometry.groups.length === 0) return null; 38151 let didForceIndices = false; 38152 if (isMultiMaterial && geometry.index === null) { 38153 const indices = []; 38154 for(let i = 0, il = geometry.attributes.position.count; i < il; i++){ 38155 indices[i] = i; 38156 } 38157 geometry.setIndex(indices); 38158 didForceIndices = true; 38159 } 38160 const materials = isMultiMaterial ? mesh.material : [ 38161 mesh.material 38162 ]; 38163 const groups = isMultiMaterial ? geometry.groups : [ 38164 { 38165 materialIndex: 0, 38166 start: undefined, 38167 count: undefined 38168 } 38169 ]; 38170 for(let i = 0, il = groups.length; i < il; i++){ 38171 const primitive = { 38172 mode: mode, 38173 attributes: attributes 38174 }; 38175 this.serializeUserData(geometry, primitive); 38176 if (targets.length > 0) primitive.targets = targets; 38177 if (geometry.index !== null) { 38178 let cacheKey = this.getUID(geometry.index); 38179 if (groups[i].start !== undefined || groups[i].count !== undefined) { 38180 cacheKey += ':' + groups[i].start + ':' + groups[i].count; 38181 } 38182 if (cache.attributes.has(cacheKey)) { 38183 primitive.indices = cache.attributes.get(cacheKey); 38184 } else { 38185 primitive.indices = this.processAccessor(geometry.index, geometry, groups[i].start, groups[i].count); 38186 cache.attributes.set(cacheKey, primitive.indices); 38187 } 38188 if (primitive.indices === null) delete primitive.indices; 38189 } 38190 const material = await this.processMaterialAsync(materials[groups[i].materialIndex]); 38191 if (material !== null) primitive.material = material; 38192 primitives.push(primitive); 38193 } 38194 if (didForceIndices === true) { 38195 geometry.setIndex(null); 38196 } 38197 meshDef.primitives = primitives; 38198 if (!json.meshes) json.meshes = []; 38199 await this._invokeAllAsync(function(ext) { 38200 ext.writeMesh && ext.writeMesh(mesh, meshDef); 38201 }); 38202 const index = json.meshes.push(meshDef) - 1; 38203 cache.meshes.set(meshCacheKey, index); 38204 return index; 38205 } 38206 /** 38207 * If a vertex attribute with a 38208 * [non-standard data type](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#meshes-overview) 38209 * is used, it is checked whether it is a valid data type according to the 38210 * [KHR_mesh_quantization](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_mesh_quantization/README.md) 38211 * extension. 38212 * In this case the extension is automatically added to the list of used extensions. 38213 * 38214 * @param {string} attributeName 38215 * @param {THREE.BufferAttribute} attribute 38216 */ detectMeshQuantization(attributeName, attribute) { 38217 if (this.extensionsUsed[KHR_MESH_QUANTIZATION]) return; 38218 let attrType = undefined; 38219 switch(attribute.array.constructor){ 38220 case Int8Array: 38221 attrType = 'byte'; 38222 break; 38223 case Uint8Array: 38224 attrType = 'unsigned byte'; 38225 break; 38226 case Int16Array: 38227 attrType = 'short'; 38228 break; 38229 case Uint16Array: 38230 attrType = 'unsigned short'; 38231 break; 38232 default: 38233 return; 38234 } 38235 if (attribute.normalized) attrType += ' normalized'; 38236 const attrNamePrefix = attributeName.split('_', 1)[0]; 38237 if (KHR_mesh_quantization_ExtraAttrTypes[attrNamePrefix] && KHR_mesh_quantization_ExtraAttrTypes[attrNamePrefix].includes(attrType)) { 38238 this.extensionsUsed[KHR_MESH_QUANTIZATION] = true; 38239 this.extensionsRequired[KHR_MESH_QUANTIZATION] = true; 38240 } 38241 } 38242 /** 38243 * Process camera 38244 * @param {THREE.Camera} camera Camera to process 38245 * @return {number} Index of the processed mesh in the "camera" array 38246 */ processCamera(camera) { 38247 const json = this.json; 38248 if (!json.cameras) json.cameras = []; 38249 const isOrtho = camera.isOrthographicCamera; 38250 const cameraDef = { 38251 type: isOrtho ? 'orthographic' : 'perspective' 38252 }; 38253 if (isOrtho) { 38254 cameraDef.orthographic = { 38255 xmag: camera.right * 2, 38256 ymag: camera.top * 2, 38257 zfar: camera.far <= 0 ? 0.001 : camera.far, 38258 znear: camera.near < 0 ? 0 : camera.near 38259 }; 38260 } else { 38261 cameraDef.perspective = { 38262 aspectRatio: camera.aspect, 38263 yfov: MathUtils.degToRad(camera.fov), 38264 zfar: camera.far <= 0 ? 0.001 : camera.far, 38265 znear: camera.near < 0 ? 0 : camera.near 38266 }; 38267 } 38268 // Question: Is saving "type" as name intentional?
vendor: 16,384 bytes, lines 38269-38659
38269 if (camera.name !== '') cameraDef.name = camera.type; 38270 return json.cameras.push(cameraDef) - 1; 38271 } 38272 /** 38273 * Creates glTF animation entry from AnimationClip object. 38274 * 38275 * Status: 38276 * - Only properties listed in PATH_PROPERTIES may be animated. 38277 * 38278 * @param {THREE.AnimationClip} clip 38279 * @param {THREE.Object3D} root 38280 * @return {number|null} 38281 */ processAnimation(clip, root) { 38282 const json = this.json; 38283 const nodeMap = this.nodeMap; 38284 if (!json.animations) json.animations = []; 38285 clip = GLTFExporter.Utils.mergeMorphTargetTracks(clip.clone(), root); 38286 const tracks = clip.tracks; 38287 const channels = []; 38288 const samplers = []; 38289 for(let i = 0; i < tracks.length; ++i){ 38290 const track = tracks[i]; 38291 const trackBinding = PropertyBinding.parseTrackName(track.name); 38292 let trackNode = PropertyBinding.findNode(root, trackBinding.nodeName); 38293 const trackProperty = PATH_PROPERTIES[trackBinding.propertyName]; 38294 if (trackBinding.objectName === 'bones') { 38295 if (trackNode.isSkinnedMesh === true) { 38296 trackNode = trackNode.skeleton.getBoneByName(trackBinding.objectIndex); 38297 } else { 38298 trackNode = undefined; 38299 } 38300 } 38301 if (!trackNode || !trackProperty) { 38302 console.warn('THREE.GLTFExporter: Could not export animation track "%s".', track.name); 38303 continue; 38304 } 38305 const inputItemSize = 1; 38306 let outputItemSize = track.values.length / track.times.length; 38307 if (trackProperty === PATH_PROPERTIES.morphTargetInfluences) { 38308 outputItemSize /= trackNode.morphTargetInfluences.length; 38309 } 38310 let interpolation; 38311 // @TODO export CubicInterpolant(InterpolateSmooth) as CUBICSPLINE 38312 // Detecting glTF cubic spline interpolant by checking factory method's special property 38313 // GLTFCubicSplineInterpolant is a custom interpolant and track doesn't return 38314 // valid value from .getInterpolation(). 38315 if (track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline === true) { 38316 interpolation = 'CUBICSPLINE'; 38317 // itemSize of CUBICSPLINE keyframe is 9 38318 // (VEC3 * 3: inTangent, splineVertex, and outTangent) 38319 // but needs to be stored as VEC3 so dividing by 3 here. 38320 outputItemSize /= 3; 38321 } else if (track.getInterpolation() === InterpolateDiscrete) { 38322 interpolation = 'STEP'; 38323 } else { 38324 interpolation = 'LINEAR'; 38325 } 38326 samplers.push({ 38327 input: this.processAccessor(new BufferAttribute(track.times, inputItemSize)), 38328 output: this.processAccessor(new BufferAttribute(track.values, outputItemSize)), 38329 interpolation: interpolation 38330 }); 38331 channels.push({ 38332 sampler: samplers.length - 1, 38333 target: { 38334 node: nodeMap.get(trackNode), 38335 path: trackProperty 38336 } 38337 }); 38338 } 38339 json.animations.push({ 38340 name: clip.name || 'clip_' + json.animations.length, 38341 samplers: samplers, 38342 channels: channels 38343 }); 38344 return json.animations.length - 1; 38345 } 38346 /** 38347 * @param {THREE.Object3D} object 38348 * @return {number|null} 38349 */ processSkin(object) { 38350 const json = this.json; 38351 const nodeMap = this.nodeMap; 38352 const node = json.nodes[nodeMap.get(object)]; 38353 const skeleton = object.skeleton; 38354 if (skeleton === undefined) return null; 38355 const rootJoint = object.skeleton.bones[0]; 38356 if (rootJoint === undefined) return null; 38357 const joints = []; 38358 const inverseBindMatrices = new Float32Array(skeleton.bones.length * 16); 38359 const temporaryBoneInverse = new Matrix4(); 38360 for(let i = 0; i < skeleton.bones.length; ++i){ 38361 joints.push(nodeMap.get(skeleton.bones[i])); 38362 temporaryBoneInverse.copy(skeleton.boneInverses[i]); 38363 temporaryBoneInverse.multiply(object.bindMatrix).toArray(inverseBindMatrices, i * 16); 38364 } 38365 if (json.skins === undefined) json.skins = []; 38366 json.skins.push({ 38367 inverseBindMatrices: this.processAccessor(new BufferAttribute(inverseBindMatrices, 16)), 38368 joints: joints, 38369 skeleton: nodeMap.get(rootJoint) 38370 }); 38371 const skinIndex = node.skin = json.skins.length - 1; 38372 return skinIndex; 38373 } 38374 /** 38375 * Process Object3D node 38376 * @param {THREE.Object3D} object Object3D to processNodeAsync 38377 * @return {Promise<number>} Index of the node in the nodes list 38378 */ async processNodeAsync(object) { 38379 const json = this.json; 38380 const options = this.options; 38381 const nodeMap = this.nodeMap; 38382 if (!json.nodes) json.nodes = []; 38383 const nodeDef = {}; 38384 if (options.trs) { 38385 const rotation = object.quaternion.toArray(); 38386 const position = object.position.toArray(); 38387 const scale = object.scale.toArray(); 38388 if (!equalArray(rotation, [ 38389 0, 38390 0, 38391 0, 38392 1 38393 ])) { 38394 nodeDef.rotation = rotation; 38395 } 38396 if (!equalArray(position, [ 38397 0, 38398 0, 38399 0 38400 ])) { 38401 nodeDef.translation = position; 38402 } 38403 if (!equalArray(scale, [ 38404 1, 38405 1, 38406 1 38407 ])) { 38408 nodeDef.scale = scale; 38409 } 38410 } else { 38411 if (object.matrixAutoUpdate) { 38412 object.updateMatrix(); 38413 } 38414 if (isIdentityMatrix(object.matrix) === false) { 38415 nodeDef.matrix = object.matrix.elements; 38416 } 38417 } 38418 // We don't export empty strings name because it represents no-name in Three.js. 38419 if (object.name !== '') nodeDef.name = String(object.name); 38420 this.serializeUserData(object, nodeDef); 38421 if (object.isMesh || object.isLine || object.isPoints) { 38422 const meshIndex = await this.processMeshAsync(object); 38423 if (meshIndex !== null) nodeDef.mesh = meshIndex; 38424 } else if (object.isCamera) { 38425 nodeDef.camera = this.processCamera(object); 38426 } 38427 if (object.isSkinnedMesh) this.skins.push(object); 38428 if (object.children.length > 0) { 38429 const children = []; 38430 for(let i = 0, l = object.children.length; i < l; i++){ 38431 const child = object.children[i]; 38432 if (child.visible || options.onlyVisible === false) { 38433 const nodeIndex = await this.processNodeAsync(child); 38434 if (nodeIndex !== null) children.push(nodeIndex); 38435 } 38436 } 38437 if (children.length > 0) nodeDef.children = children; 38438 } 38439 await this._invokeAllAsync(function(ext) { 38440 ext.writeNode && ext.writeNode(object, nodeDef); 38441 }); 38442 const nodeIndex = json.nodes.push(nodeDef) - 1; 38443 nodeMap.set(object, nodeIndex); 38444 return nodeIndex; 38445 } 38446 /** 38447 * Process Scene 38448 * @param {Scene} scene Scene to process 38449 */ async processSceneAsync(scene) { 38450 const json = this.json; 38451 const options = this.options; 38452 if (!json.scenes) { 38453 json.scenes = []; 38454 json.scene = 0; 38455 } 38456 const sceneDef = {}; 38457 if (scene.name !== '') sceneDef.name = scene.name; 38458 json.scenes.push(sceneDef); 38459 const nodes = []; 38460 for(let i = 0, l = scene.children.length; i < l; i++){ 38461 const child = scene.children[i]; 38462 if (child.visible || options.onlyVisible === false) { 38463 const nodeIndex = await this.processNodeAsync(child); 38464 if (nodeIndex !== null) nodes.push(nodeIndex); 38465 } 38466 } 38467 if (nodes.length > 0) sceneDef.nodes = nodes; 38468 this.serializeUserData(scene, sceneDef); 38469 } 38470 /** 38471 * Creates a Scene to hold a list of objects and parse it 38472 * @param {Array<THREE.Object3D>} objects List of objects to process 38473 */ async processObjectsAsync(objects) { 38474 const scene = new Scene(); 38475 scene.name = 'AuxScene'; 38476 for(let i = 0; i < objects.length; i++){ 38477 // We push directly to children instead of calling `add` to prevent 38478 // modify the .parent and break its original scene and hierarchy 38479 scene.children.push(objects[i]); 38480 } 38481 await this.processSceneAsync(scene); 38482 } 38483 /** 38484 * @param {THREE.Object3D|Array<THREE.Object3D>} input 38485 */ async processInputAsync(input) { 38486 const options = this.options; 38487 input = input instanceof Array ? input : [ 38488 input 38489 ]; 38490 await this._invokeAllAsync(function(ext) { 38491 ext.beforeParse && ext.beforeParse(input); 38492 }); 38493 const objectsWithoutScene = []; 38494 for(let i = 0; i < input.length; i++){ 38495 if (input[i] instanceof Scene) { 38496 await this.processSceneAsync(input[i]); 38497 } else { 38498 objectsWithoutScene.push(input[i]); 38499 } 38500 } 38501 if (objectsWithoutScene.length > 0) { 38502 await this.processObjectsAsync(objectsWithoutScene); 38503 } 38504 for(let i = 0; i < this.skins.length; ++i){ 38505 this.processSkin(this.skins[i]); 38506 } 38507 for(let i = 0; i < options.animations.length; ++i){ 38508 this.processAnimation(options.animations[i], input[0]); 38509 } 38510 await this._invokeAllAsync(function(ext) { 38511 ext.afterParse && ext.afterParse(input); 38512 }); 38513 } 38514 async _invokeAllAsync(func) { 38515 for(let i = 0, il = this.plugins.length; i < il; i++){ 38516 await func(this.plugins[i]); 38517 } 38518 } 38519 constructor(){ 38520 this.plugins = []; 38521 this.options = {}; 38522 this.pending = []; 38523 this.buffers = []; 38524 this.byteOffset = 0; 38525 this.buffers = []; 38526 this.nodeMap = new Map(); 38527 this.skins = []; 38528 this.extensionsUsed = {}; 38529 this.extensionsRequired = {}; 38530 this.uids = new Map(); 38531 this.uid = 0; 38532 this.json = { 38533 asset: { 38534 version: '2.0', 38535 generator: 'THREE.GLTFExporter r' + REVISION 38536 } 38537 }; 38538 this.cache = { 38539 meshes: new Map(), 38540 attributes: new Map(), 38541 attributesNormalized: new Map(), 38542 materials: new Map(), 38543 textures: new Map(), 38544 images: new Map() 38545 }; 38546 this.textureUtils = null; 38547 } 38548 } 38549 /** 38550 * Punctual Lights Extension 38551 * 38552 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual 38553 */ class GLTFLightExtension { 38554 writeNode(light, nodeDef) { 38555 if (!light.isLight) return; 38556 if (!light.isDirectionalLight && !light.isPointLight && !light.isSpotLight) { 38557 console.warn('THREE.GLTFExporter: Only directional, point, and spot lights are supported.', light); 38558 return; 38559 } 38560 const writer = this.writer; 38561 const json = writer.json; 38562 const extensionsUsed = writer.extensionsUsed; 38563 const lightDef = {}; 38564 if (light.name) lightDef.name = light.name; 38565 lightDef.color = light.color.toArray(); 38566 lightDef.intensity = light.intensity; 38567 if (light.isDirectionalLight) { 38568 lightDef.type = 'directional'; 38569 } else if (light.isPointLight) { 38570 lightDef.type = 'point'; 38571 if (light.distance > 0) lightDef.range = light.distance; 38572 } else if (light.isSpotLight) { 38573 lightDef.type = 'spot'; 38574 if (light.distance > 0) lightDef.range = light.distance; 38575 lightDef.spot = {}; 38576 lightDef.spot.innerConeAngle = (1.0 - light.penumbra) * light.angle; 38577 lightDef.spot.outerConeAngle = light.angle; 38578 } 38579 if (light.decay !== undefined && light.decay !== 2) { 38580 console.warn('THREE.GLTFExporter: Light decay may be lost. glTF is physically-based, ' + 'and expects light.decay=2.'); 38581 } 38582 if (light.target && (light.target.parent !== light || light.target.position.x !== 0 || light.target.position.y !== 0 || light.target.position.z !== -1)) { 38583 console.warn('THREE.GLTFExporter: Light direction may be lost. For best results, ' + 'make light.target a child of the light with position 0,0,-1.'); 38584 } 38585 if (!extensionsUsed[this.name]) { 38586 json.extensions = json.extensions || {}; 38587 json.extensions[this.name] = { 38588 lights: [] 38589 }; 38590 extensionsUsed[this.name] = true; 38591 } 38592 const lights = json.extensions[this.name].lights; 38593 lights.push(lightDef); 38594 nodeDef.extensions = nodeDef.extensions || {}; 38595 nodeDef.extensions[this.name] = { 38596 light: lights.length - 1 38597 }; 38598 } 38599 constructor(writer){ 38600 this.writer = writer; 38601 this.name = 'KHR_lights_punctual'; 38602 } 38603 } 38604 /** 38605 * Unlit Materials Extension 38606 * 38607 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_unlit 38608 */ class GLTFMaterialsUnlitExtension { 38609 async writeMaterialAsync(material, materialDef) { 38610 if (!material.isMeshBasicMaterial) return; 38611 const writer = this.writer; 38612 const extensionsUsed = writer.extensionsUsed; 38613 materialDef.extensions = materialDef.extensions || {}; 38614 materialDef.extensions[this.name] = {}; 38615 extensionsUsed[this.name] = true; 38616 materialDef.pbrMetallicRoughness.metallicFactor = 0.0; 38617 materialDef.pbrMetallicRoughness.roughnessFactor = 0.9; 38618 } 38619 constructor(writer){ 38620 this.writer = writer; 38621 this.name = 'KHR_materials_unlit'; 38622 } 38623 } 38624 /** 38625 * Clearcoat Materials Extension 38626 * 38627 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_clearcoat 38628 */ class GLTFMaterialsClearcoatExtension { 38629 async writeMaterialAsync(material, materialDef) { 38630 if (!material.isMeshPhysicalMaterial || material.clearcoat === 0) return; 38631 const writer = this.writer; 38632 const extensionsUsed = writer.extensionsUsed; 38633 const extensionDef = {}; 38634 extensionDef.clearcoatFactor = material.clearcoat; 38635 if (material.clearcoatMap) { 38636 const clearcoatMapDef = { 38637 index: await writer.processTextureAsync(material.clearcoatMap), 38638 texCoord: material.clearcoatMap.channel 38639 }; 38640 writer.applyTextureTransform(clearcoatMapDef, material.clearcoatMap); 38641 extensionDef.clearcoatTexture = clearcoatMapDef; 38642 } 38643 extensionDef.clearcoatRoughnessFactor = material.clearcoatRoughness; 38644 if (material.clearcoatRoughnessMap) { 38645 const clearcoatRoughnessMapDef = { 38646 index: await writer.processTextureAsync(material.clearcoatRoughnessMap), 38647 texCoord: material.clearcoatRoughnessMap.channel 38648 }; 38649 writer.applyTextureTransform(clearcoatRoughnessMapDef, material.clearcoatRoughnessMap); 38650 extensionDef.clearcoatRoughnessTexture = clearcoatRoughnessMapDef; 38651 } 38652 if (material.clearcoatNormalMap) { 38653 const clearcoatNormalMapDef = { 38654 index: await writer.processTextureAsync(material.clearcoatNormalMap), 38655 texCoord: material.clearcoatNormalMap.channel 38656 }; 38657 if (material.clearcoatNormalScale.x !== 1) clearcoatNormalMapDef.scale = material.clearcoatNormalScale.x; 38658 writer.applyTextureTransform(clearcoatNormalMapDef, material.clearcoatNormalMap); 38659 extensionDef.cl
vendor: 10,643 bytes, lines 38659-38893
38659earcoatNormalTexture = clearcoatNormalMapDef; 38660 } 38661 materialDef.extensions = materialDef.extensions || {}; 38662 materialDef.extensions[this.name] = extensionDef; 38663 extensionsUsed[this.name] = true; 38664 } 38665 constructor(writer){ 38666 this.writer = writer; 38667 this.name = 'KHR_materials_clearcoat'; 38668 } 38669 } 38670 /** 38671 * Materials dispersion Extension 38672 * 38673 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_dispersion 38674 */ class GLTFMaterialsDispersionExtension { 38675 async writeMaterialAsync(material, materialDef) { 38676 if (!material.isMeshPhysicalMaterial || material.dispersion === 0) return; 38677 const writer = this.writer; 38678 const extensionsUsed = writer.extensionsUsed; 38679 const extensionDef = {}; 38680 extensionDef.dispersion = material.dispersion; 38681 materialDef.extensions = materialDef.extensions || {}; 38682 materialDef.extensions[this.name] = extensionDef; 38683 extensionsUsed[this.name] = true; 38684 } 38685 constructor(writer){ 38686 this.writer = writer; 38687 this.name = 'KHR_materials_dispersion'; 38688 } 38689 } 38690 /** 38691 * Iridescence Materials Extension 38692 * 38693 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_iridescence 38694 */ class GLTFMaterialsIridescenceExtension { 38695 async writeMaterialAsync(material, materialDef) { 38696 if (!material.isMeshPhysicalMaterial || material.iridescence === 0) return; 38697 const writer = this.writer; 38698 const extensionsUsed = writer.extensionsUsed; 38699 const extensionDef = {}; 38700 extensionDef.iridescenceFactor = material.iridescence; 38701 if (material.iridescenceMap) { 38702 const iridescenceMapDef = { 38703 index: await writer.processTextureAsync(material.iridescenceMap), 38704 texCoord: material.iridescenceMap.channel 38705 }; 38706 writer.applyTextureTransform(iridescenceMapDef, material.iridescenceMap); 38707 extensionDef.iridescenceTexture = iridescenceMapDef; 38708 } 38709 extensionDef.iridescenceIor = material.iridescenceIOR; 38710 extensionDef.iridescenceThicknessMinimum = material.iridescenceThicknessRange[0]; 38711 extensionDef.iridescenceThicknessMaximum = material.iridescenceThicknessRange[1]; 38712 if (material.iridescenceThicknessMap) { 38713 const iridescenceThicknessMapDef = { 38714 index: await writer.processTextureAsync(material.iridescenceThicknessMap), 38715 texCoord: material.iridescenceThicknessMap.channel 38716 }; 38717 writer.applyTextureTransform(iridescenceThicknessMapDef, material.iridescenceThicknessMap); 38718 extensionDef.iridescenceThicknessTexture = iridescenceThicknessMapDef; 38719 } 38720 materialDef.extensions = materialDef.extensions || {}; 38721 materialDef.extensions[this.name] = extensionDef; 38722 extensionsUsed[this.name] = true; 38723 } 38724 constructor(writer){ 38725 this.writer = writer; 38726 this.name = 'KHR_materials_iridescence'; 38727 } 38728 } 38729 /** 38730 * Transmission Materials Extension 38731 * 38732 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_transmission 38733 */ class GLTFMaterialsTransmissionExtension { 38734 async writeMaterialAsync(material, materialDef) { 38735 if (!material.isMeshPhysicalMaterial || material.transmission === 0) return; 38736 const writer = this.writer; 38737 const extensionsUsed = writer.extensionsUsed; 38738 const extensionDef = {}; 38739 extensionDef.transmissionFactor = material.transmission; 38740 if (material.transmissionMap) { 38741 const transmissionMapDef = { 38742 index: await writer.processTextureAsync(material.transmissionMap), 38743 texCoord: material.transmissionMap.channel 38744 }; 38745 writer.applyTextureTransform(transmissionMapDef, material.transmissionMap); 38746 extensionDef.transmissionTexture = transmissionMapDef; 38747 } 38748 materialDef.extensions = materialDef.extensions || {}; 38749 materialDef.extensions[this.name] = extensionDef; 38750 extensionsUsed[this.name] = true; 38751 } 38752 constructor(writer){ 38753 this.writer = writer; 38754 this.name = 'KHR_materials_transmission'; 38755 } 38756 } 38757 /** 38758 * Materials Volume Extension 38759 * 38760 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_volume 38761 */ class GLTFMaterialsVolumeExtension { 38762 async writeMaterialAsync(material, materialDef) { 38763 if (!material.isMeshPhysicalMaterial || material.transmission === 0) return; 38764 const writer = this.writer; 38765 const extensionsUsed = writer.extensionsUsed; 38766 const extensionDef = {}; 38767 extensionDef.thicknessFactor = material.thickness; 38768 if (material.thicknessMap) { 38769 const thicknessMapDef = { 38770 index: await writer.processTextureAsync(material.thicknessMap), 38771 texCoord: material.thicknessMap.channel 38772 }; 38773 writer.applyTextureTransform(thicknessMapDef, material.thicknessMap); 38774 extensionDef.thicknessTexture = thicknessMapDef; 38775 } 38776 if (material.attenuationDistance !== Infinity) { 38777 extensionDef.attenuationDistance = material.attenuationDistance; 38778 } 38779 extensionDef.attenuationColor = material.attenuationColor.toArray(); 38780 materialDef.extensions = materialDef.extensions || {}; 38781 materialDef.extensions[this.name] = extensionDef; 38782 extensionsUsed[this.name] = true; 38783 } 38784 constructor(writer){ 38785 this.writer = writer; 38786 this.name = 'KHR_materials_volume'; 38787 } 38788 } 38789 /** 38790 * Materials ior Extension 38791 * 38792 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_ior 38793 */ class GLTFMaterialsIorExtension { 38794 async writeMaterialAsync(material, materialDef) { 38795 if (!material.isMeshPhysicalMaterial || material.ior === 1.5) return; 38796 const writer = this.writer; 38797 const extensionsUsed = writer.extensionsUsed; 38798 const extensionDef = {}; 38799 extensionDef.ior = material.ior; 38800 materialDef.extensions = materialDef.extensions || {}; 38801 materialDef.extensions[this.name] = extensionDef; 38802 extensionsUsed[this.name] = true; 38803 } 38804 constructor(writer){ 38805 this.writer = writer; 38806 this.name = 'KHR_materials_ior'; 38807 } 38808 } 38809 /** 38810 * Materials specular Extension 38811 * 38812 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_specular 38813 */ class GLTFMaterialsSpecularExtension { 38814 async writeMaterialAsync(material, materialDef) { 38815 if (!material.isMeshPhysicalMaterial || material.specularIntensity === 1.0 && material.specularColor.equals(DEFAULT_SPECULAR_COLOR) && !material.specularIntensityMap && !material.specularColorMap) return; 38816 const writer = this.writer; 38817 const extensionsUsed = writer.extensionsUsed; 38818 const extensionDef = {}; 38819 if (material.specularIntensityMap) { 38820 const specularIntensityMapDef = { 38821 index: await writer.processTextureAsync(material.specularIntensityMap), 38822 texCoord: material.specularIntensityMap.channel 38823 }; 38824 writer.applyTextureTransform(specularIntensityMapDef, material.specularIntensityMap); 38825 extensionDef.specularTexture = specularIntensityMapDef; 38826 } 38827 if (material.specularColorMap) { 38828 const specularColorMapDef = { 38829 index: await writer.processTextureAsync(material.specularColorMap), 38830 texCoord: material.specularColorMap.channel 38831 }; 38832 writer.applyTextureTransform(specularColorMapDef, material.specularColorMap); 38833 extensionDef.specularColorTexture = specularColorMapDef; 38834 } 38835 extensionDef.specularFactor = material.specularIntensity; 38836 extensionDef.specularColorFactor = material.specularColor.toArray(); 38837 materialDef.extensions = materialDef.extensions || {}; 38838 materialDef.extensions[this.name] = extensionDef; 38839 extensionsUsed[this.name] = true; 38840 } 38841 constructor(writer){ 38842 this.writer = writer; 38843 this.name = 'KHR_materials_specular'; 38844 } 38845 } 38846 /** 38847 * Sheen Materials Extension 38848 * 38849 * Specification: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_sheen 38850 */ class GLTFMaterialsSheenExtension { 38851 async writeMaterialAsync(material, materialDef) { 38852 if (!material.isMeshPhysicalMaterial || material.sheen == 0.0) return; 38853 const writer = this.writer; 38854 const extensionsUsed = writer.extensionsUsed; 38855 const extensionDef = {}; 38856 if (material.sheenRoughnessMap) { 38857 const sheenRoughnessMapDef = { 38858 index: await writer.processTextureAsync(material.sheenRoughnessMap), 38859 texCoord: material.sheenRoughnessMap.channel 38860 }; 38861 writer.applyTextureTransform(sheenRoughnessMapDef, material.sheenRoughnessMap); 38862 extensionDef.sheenRoughnessTexture = sheenRoughnessMapDef; 38863 } 38864 if (material.sheenColorMap) { 38865 const sheenColorMapDef = { 38866 index: await writer.processTextureAsync(material.sheenColorMap), 38867 texCoord: material.sheenColorMap.channel 38868 }; 38869 writer.applyTextureTransform(sheenColorMapDef, material.sheenColorMap); 38870 extensionDef.sheenColorTexture = sheenColorMapDef; 38871 } 38872 extensionDef.sheenRoughnessFactor = material.sheenRoughness; 38873 extensionDef.sheenColorFactor = material.sheenColor.toArray(); 38874 materialDef.extensions = materialDef.extensions || {}; 38875 materialDef.extensions[this.name] = extensionDef; 38876 extensionsUsed[this.name] = true; 38877 } 38878 constructor(writer){ 38879 this.writer = writer; 38880 this.name = 'KHR_materials_sheen'; 38881 } 38882 } 38883 /** 38884 * Anisotropy Materials Extension 38885 * 38886 * Specification: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_anisotropy 38887 */ class GLTFMaterialsAnisotropyExtension { 38888 async writeMaterialAsync(material, materialDef) { 38889 if (!material.isMeshPhysicalMaterial || material.anisotropy == 0.0) return; 38890 const writer = this.writer; 38891 const extensionsUsed = writer.extensionsUsed; 38892 const extensionDef = {}; 38893 if (material.anisotropyMap) {
vendor: 19,972 bytes, lines 38894-39316
38894 const anisotropyMapDef = { 38895 index: await writer.processTextureAsync(material.anisotropyMap) 38896 }; 38897 writer.applyTextureTransform(anisotropyMapDef, material.anisotropyMap); 38898 extensionDef.anisotropyTexture = anisotropyMapDef; 38899 } 38900 extensionDef.anisotropyStrength = material.anisotropy; 38901 extensionDef.anisotropyRotation = material.anisotropyRotation; 38902 materialDef.extensions = materialDef.extensions || {}; 38903 materialDef.extensions[this.name] = extensionDef; 38904 extensionsUsed[this.name] = true; 38905 } 38906 constructor(writer){ 38907 this.writer = writer; 38908 this.name = 'KHR_materials_anisotropy'; 38909 } 38910 } 38911 /** 38912 * Materials Emissive Strength Extension 38913 * 38914 * Specification: https://github.com/KhronosGroup/glTF/blob/5768b3ce0ef32bc39cdf1bef10b948586635ead3/extensions/2.0/Khronos/KHR_materials_emissive_strength/README.md 38915 */ class GLTFMaterialsEmissiveStrengthExtension { 38916 async writeMaterialAsync(material, materialDef) { 38917 if (!material.isMeshStandardMaterial || material.emissiveIntensity === 1.0) return; 38918 const writer = this.writer; 38919 const extensionsUsed = writer.extensionsUsed; 38920 const extensionDef = {}; 38921 extensionDef.emissiveStrength = material.emissiveIntensity; 38922 materialDef.extensions = materialDef.extensions || {}; 38923 materialDef.extensions[this.name] = extensionDef; 38924 extensionsUsed[this.name] = true; 38925 } 38926 constructor(writer){ 38927 this.writer = writer; 38928 this.name = 'KHR_materials_emissive_strength'; 38929 } 38930 } 38931 /** 38932 * Materials bump Extension 38933 * 38934 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/EXT_materials_bump 38935 */ class GLTFMaterialsBumpExtension { 38936 async writeMaterialAsync(material, materialDef) { 38937 if (!material.isMeshStandardMaterial || material.bumpScale === 1 && !material.bumpMap) return; 38938 const writer = this.writer; 38939 const extensionsUsed = writer.extensionsUsed; 38940 const extensionDef = {}; 38941 if (material.bumpMap) { 38942 const bumpMapDef = { 38943 index: await writer.processTextureAsync(material.bumpMap), 38944 texCoord: material.bumpMap.channel 38945 }; 38946 writer.applyTextureTransform(bumpMapDef, material.bumpMap); 38947 extensionDef.bumpTexture = bumpMapDef; 38948 } 38949 extensionDef.bumpFactor = material.bumpScale; 38950 materialDef.extensions = materialDef.extensions || {}; 38951 materialDef.extensions[this.name] = extensionDef; 38952 extensionsUsed[this.name] = true; 38953 } 38954 constructor(writer){ 38955 this.writer = writer; 38956 this.name = 'EXT_materials_bump'; 38957 } 38958 } 38959 /** 38960 * GPU Instancing Extension 38961 * 38962 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_mesh_gpu_instancing 38963 */ class GLTFMeshGpuInstancing { 38964 writeNode(object, nodeDef) { 38965 if (!object.isInstancedMesh) return; 38966 const writer = this.writer; 38967 const mesh = object; 38968 const translationAttr = new Float32Array(mesh.count * 3); 38969 const rotationAttr = new Float32Array(mesh.count * 4); 38970 const scaleAttr = new Float32Array(mesh.count * 3); 38971 const matrix = new Matrix4(); 38972 const position = new Vector3(); 38973 const quaternion = new Quaternion(); 38974 const scale = new Vector3(); 38975 for(let i = 0; i < mesh.count; i++){ 38976 mesh.getMatrixAt(i, matrix); 38977 matrix.decompose(position, quaternion, scale); 38978 position.toArray(translationAttr, i * 3); 38979 quaternion.toArray(rotationAttr, i * 4); 38980 scale.toArray(scaleAttr, i * 3); 38981 } 38982 const attributes = { 38983 TRANSLATION: writer.processAccessor(new BufferAttribute(translationAttr, 3)), 38984 ROTATION: writer.processAccessor(new BufferAttribute(rotationAttr, 4)), 38985 SCALE: writer.processAccessor(new BufferAttribute(scaleAttr, 3)) 38986 }; 38987 if (mesh.instanceColor) attributes._COLOR_0 = writer.processAccessor(mesh.instanceColor); 38988 nodeDef.extensions = nodeDef.extensions || {}; 38989 nodeDef.extensions[this.name] = { 38990 attributes 38991 }; 38992 writer.extensionsUsed[this.name] = true; 38993 writer.extensionsRequired[this.name] = true; 38994 } 38995 constructor(writer){ 38996 this.writer = writer; 38997 this.name = 'EXT_mesh_gpu_instancing'; 38998 } 38999 } 39000 /** 39001 * Static utility functions 39002 */ GLTFExporter.Utils = { 39003 insertKeyframe: function(track, time) { 39004 const tolerance = 0.001; // 1ms 39005 const valueSize = track.getValueSize(); 39006 const times = new track.TimeBufferType(track.times.length + 1); 39007 const values = new track.ValueBufferType(track.values.length + valueSize); 39008 const interpolant = track.createInterpolant(new track.ValueBufferType(valueSize)); 39009 let index; 39010 if (track.times.length === 0) { 39011 times[0] = time; 39012 for(let i = 0; i < valueSize; i++){ 39013 values[i] = 0; 39014 } 39015 index = 0; 39016 } else if (time < track.times[0]) { 39017 if (Math.abs(track.times[0] - time) < tolerance) return 0; 39018 times[0] = time; 39019 times.set(track.times, 1); 39020 values.set(interpolant.evaluate(time), 0); 39021 values.set(track.values, valueSize); 39022 index = 0; 39023 } else if (time > track.times[track.times.length - 1]) { 39024 if (Math.abs(track.times[track.times.length - 1] - time) < tolerance) { 39025 return track.times.length - 1; 39026 } 39027 times[times.length - 1] = time; 39028 times.set(track.times, 0); 39029 values.set(track.values, 0); 39030 values.set(interpolant.evaluate(time), track.values.length); 39031 index = times.length - 1; 39032 } else { 39033 for(let i = 0; i < track.times.length; i++){ 39034 if (Math.abs(track.times[i] - time) < tolerance) return i; 39035 if (track.times[i] < time && track.times[i + 1] > time) { 39036 times.set(track.times.slice(0, i + 1), 0); 39037 times[i + 1] = time; 39038 times.set(track.times.slice(i + 1), i + 2); 39039 values.set(track.values.slice(0, (i + 1) * valueSize), 0); 39040 values.set(interpolant.evaluate(time), (i + 1) * valueSize); 39041 values.set(track.values.slice((i + 1) * valueSize), (i + 2) * valueSize); 39042 index = i + 1; 39043 break; 39044 } 39045 } 39046 } 39047 track.times = times; 39048 track.values = values; 39049 return index; 39050 }, 39051 mergeMorphTargetTracks: function(clip, root) { 39052 const tracks = []; 39053 const mergedTracks = {}; 39054 const sourceTracks = clip.tracks; 39055 for(let i = 0; i < sourceTracks.length; ++i){ 39056 let sourceTrack = sourceTracks[i]; 39057 const sourceTrackBinding = PropertyBinding.parseTrackName(sourceTrack.name); 39058 const sourceTrackNode = PropertyBinding.findNode(root, sourceTrackBinding.nodeName); 39059 if (sourceTrackBinding.propertyName !== 'morphTargetInfluences' || sourceTrackBinding.propertyIndex === undefined) { 39060 // Tracks that don't affect morph targets, or that affect all morph targets together, can be left as-is. 39061 tracks.push(sourceTrack); 39062 continue; 39063 } 39064 if (sourceTrack.createInterpolant !== sourceTrack.InterpolantFactoryMethodDiscrete && sourceTrack.createInterpolant !== sourceTrack.InterpolantFactoryMethodLinear) { 39065 if (sourceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline) { 39066 // This should never happen, because glTF morph target animations 39067 // affect all targets already. 39068 throw new Error('THREE.GLTFExporter: Cannot merge tracks with glTF CUBICSPLINE interpolation.'); 39069 } 39070 console.warn('THREE.GLTFExporter: Morph target interpolation mode not yet supported. Using LINEAR instead.'); 39071 sourceTrack = sourceTrack.clone(); 39072 sourceTrack.setInterpolation(InterpolateLinear); 39073 } 39074 const targetCount = sourceTrackNode.morphTargetInfluences.length; 39075 const targetIndex = sourceTrackNode.morphTargetDictionary[sourceTrackBinding.propertyIndex]; 39076 if (targetIndex === undefined) { 39077 throw new Error('THREE.GLTFExporter: Morph target name not found: ' + sourceTrackBinding.propertyIndex); 39078 } 39079 let mergedTrack; 39080 // If this is the first time we've seen this object, create a new 39081 // track to store merged keyframe data for each morph target. 39082 if (mergedTracks[sourceTrackNode.uuid] === undefined) { 39083 mergedTrack = sourceTrack.clone(); 39084 const values = new mergedTrack.ValueBufferType(targetCount * mergedTrack.times.length); 39085 for(let j = 0; j < mergedTrack.times.length; j++){ 39086 values[j * targetCount + targetIndex] = mergedTrack.values[j]; 39087 } 39088 // We need to take into consideration the intended target node 39089 // of our original un-merged morphTarget animation. 39090 mergedTrack.name = (sourceTrackBinding.nodeName || '') + '.morphTargetInfluences'; 39091 mergedTrack.values = values; 39092 mergedTracks[sourceTrackNode.uuid] = mergedTrack; 39093 tracks.push(mergedTrack); 39094 continue; 39095 } 39096 const sourceInterpolant = sourceTrack.createInterpolant(new sourceTrack.ValueBufferType(1)); 39097 mergedTrack = mergedTracks[sourceTrackNode.uuid]; 39098 // For every existing keyframe of the merged track, write a (possibly 39099 // interpolated) value from the source track. 39100 for(let j = 0; j < mergedTrack.times.length; j++){ 39101 mergedTrack.values[j * targetCount + targetIndex] = sourceInterpolant.evaluate(mergedTrack.times[j]); 39102 } 39103 // For every existing keyframe of the source track, write a (possibly 39104 // new) keyframe to the merged track. Values from the previous loop may 39105 // be written again, but keyframes are de-duplicated. 39106 for(let j = 0; j < sourceTrack.times.length; j++){ 39107 const keyframeIndex = this.insertKeyframe(mergedTrack, sourceTrack.times[j]); 39108 mergedTrack.values[keyframeIndex * targetCount + targetIndex] = sourceTrack.values[j]; 39109 } 39110 } 39111 clip.tracks = tracks; 39112 return clip; 39113 }, 39114 toFloat32BufferAttribute: function(srcAttribute) { 39115 const dstAttribute = new BufferAttribute(new Float32Array(srcAttribute.count * srcAttribute.itemSize), srcAttribute.itemSize, false); 39116 if (!srcAttribute.normalized && !srcAttribute.isInterleavedBufferAttribute) { 39117 dstAttribute.array.set(srcAttribute.array); 39118 return dstAttribute; 39119 } 39120 for(let i = 0, il = srcAttribute.count; i < il; i++){ 39121 for(let j = 0; j < srcAttribute.itemSize; j++){ 39122 dstAttribute.setComponent(i, j, srcAttribute.getComponent(i, j)); 39123 } 39124 } 39125 return dstAttribute; 39126 } 39127 }; 39128 39129 const compatibleObject = (object)=>{ 39130 return object.material !== undefined && 39131 object.userData && 39132 object.userData.variantMaterials && 39133 !!Array.from(object.userData.variantMaterials.values()).filter((m)=>compatibleMaterial(m.material)); 39134 }; 39135 const compatibleMaterial = (material)=>{ 39136 return material && material.isMaterial && !Array.isArray(material); 39137 }; 39138 class GLTFExporterMaterialsVariantsExtension { 39139 beforeParse(objects) { 39140 const variantNameSet = new Set(); 39141 const addVariantNames = (o)=>{ 39142 if (!compatibleObject(o)) { 39143 return; 39144 } 39145 const variantMaterials = o.userData.variantMaterials; 39146 const variantDataMap = o.userData.variantData; 39147 for (const [variantName, variantData] of variantDataMap){ 39148 const variantMaterial = variantMaterials.get(variantData.index); 39149 if (variantMaterial && compatibleMaterial(variantMaterial.material)) { 39150 variantNameSet.add(variantName); 39151 } 39152 } 39153 }; 39154 if (Array.isArray(objects)) { 39155 for (const object of objects){ 39156 object.traverse(addVariantNames); 39157 } 39158 } else { 39159 objects.traverse(addVariantNames); 39160 } 39161 variantNameSet.forEach((name)=>this.variantNames.push(name)); 39162 } 39163 async writeMesh(mesh, meshDef) { 39164 if (!compatibleObject(mesh)) { 39165 return; 39166 } 39167 const userData = mesh.userData; 39168 const variantMaterials = userData.variantMaterials; 39169 const variantDataMap = userData.variantData; 39170 const mappingTable = new Map(); 39171 const reIndexedVariants = new Map(); 39172 const variants = Array.from(variantDataMap.values()).sort((a, b)=>{ 39173 return a.index - b.index; 39174 }); 39175 for (const [i, variantData] of variants.entries()){ 39176 reIndexedVariants.set(variantData.index, i); 39177 } 39178 for (const variantData of variantDataMap.values()){ 39179 const variantInstance = variantMaterials.get(variantData.index); 39180 if (!variantInstance || !compatibleMaterial(variantInstance.material)) { 39181 continue; 39182 } 39183 const materialIndex = await this.writer.processMaterialAsync(variantInstance.material); 39184 if (!mappingTable.has(materialIndex)) { 39185 mappingTable.set(materialIndex, { 39186 material: materialIndex, 39187 variants: [] 39188 }); 39189 } 39190 mappingTable.get(materialIndex).variants.push(reIndexedVariants.get(variantData.index)); 39191 } 39192 const mappingsDef = Array.from(mappingTable.values()).map((m)=>{ 39193 return m.variants.sort((a, b)=>a - b) && m; 39194 }).sort((a, b)=>a.material - b.material); 39195 if (mappingsDef.length === 0) { 39196 return; 39197 } 39198 const originalMaterialIndex = compatibleMaterial(userData.originalMaterial) ? await this.writer.processMaterialAsync(userData.originalMaterial) : -1; 39199 for (const primitiveDef of meshDef.primitives){ 39200 if (originalMaterialIndex >= 0) { 39201 primitiveDef.material = originalMaterialIndex; 39202 } 39203 primitiveDef.extensions = primitiveDef.extensions || {}; 39204 primitiveDef.extensions[this.name] = { 39205 mappings: mappingsDef 39206 }; 39207 } 39208 } 39209 afterParse() { 39210 if (this.variantNames.length === 0) { 39211 return; 39212 } 39213 const root = this.writer.json; 39214 root.extensions = root.extensions || {}; 39215 const variantsDef = this.variantNames.map((n)=>{ 39216 return { 39217 name: n 39218 }; 39219 }); 39220 root.extensions[this.name] = { 39221 variants: variantsDef 39222 }; 39223 this.writer.extensionsUsed[this.name] = true; 39224 } 39225 constructor(writer){ 39226 this.writer = writer; 39227 this.name = 'KHR_materials_variants'; 39228 this.variantNames = []; 39229 } 39230 } 39231 39232 class SessionLightProbe { 39233 updateReflection() { 39234 const textureProperties = this.renderer.properties.get(this.xrLight.environment); 39235 if (textureProperties) { 39236 const cubeMap = this.xrWebGLBinding.getReflectionCubeMap(this.lightProbe); 39237 if (cubeMap) { 39238 textureProperties.__webglTexture = cubeMap; 39239 this.xrLight.environment.needsPMREMUpdate = true; 39240 } 39241 } 39242 } 39243 onXRFrame(time, xrFrame) { 39244 // If either this object or the XREstimatedLight has been destroyed, stop 39245 // running the frame loop. 39246 if (!this.xrLight) { 39247 return; 39248 } 39249 const session = xrFrame.session; 39250 session.requestAnimationFrame(this.frameCallback); 39251 const lightEstimate = xrFrame.getLightEstimate(this.lightProbe); 39252 if (lightEstimate) { 39253 // We can copy the estimate's spherical harmonics array directly into the light probe. 39254 this.xrLight.lightProbe.sh.fromArray(lightEstimate.sphericalHarmonicsCoefficients); 39255 this.xrLight.lightProbe.intensity = 1.0; 39256 // For the directional light we have to normalize the color and set the scalar as the 39257 // intensity, since WebXR can return color values that exceed 1.0. 39258 const intensityScalar = Math.max(1.0, Math.max(lightEstimate.primaryLightIntensity.x, Math.max(lightEstimate.primaryLightIntensity.y, lightEstimate.primaryLightIntensity.z))); 39259 this.xrLight.directionalLight.color.setRGB(lightEstimate.primaryLightIntensity.x / intensityScalar, lightEstimate.primaryLightIntensity.y / intensityScalar, lightEstimate.primaryLightIntensity.z / intensityScalar); 39260 this.xrLight.directionalLight.intensity = intensityScalar; 39261 this.xrLight.directionalLight.position.copy(lightEstimate.primaryLightDirection); 39262 if (this.estimationStartCallback) { 39263 this.estimationStartCallback(); 39264 this.estimationStartCallback = null; 39265 } 39266 } 39267 } 39268 dispose() { 39269 this.xrLight = null; 39270 this.renderer = null; 39271 this.lightProbe = null; 39272 this.xrWebGLBinding = null; 39273 } 39274 constructor(xrLight, renderer, lightProbe, environmentEstimation, estimationStartCallback){ 39275 this.xrLight = xrLight; 39276 this.renderer = renderer; 39277 this.lightProbe = lightProbe; 39278 this.xrWebGLBinding = null; 39279 this.estimationStartCallback = estimationStartCallback; 39280 this.frameCallback = this.onXRFrame.bind(this); 39281 const session = renderer.xr.getSession(); 39282 // If the XRWebGLBinding class is available then we can also query an 39283 // estimated reflection cube map. 39284 if (environmentEstimation && 'XRWebGLBinding' in window) { 39285 // This is the simplest way I know of to initialize a WebGL cubemap in Three. 39286 const cubeRenderTarget = new WebGLCubeRenderTarget(16); 39287 xrLight.environment = cubeRenderTarget.texture; 39288 const gl = renderer.getContext(); 39289 // Ensure that we have any extensions needed to use the preferred cube map format. 39290 switch(session.preferredReflectionFormat){ 39291 case 'srgba8': 39292 gl.getExtension('EXT_sRGB'); 39293 break; 39294 case 'rgba16f': 39295 gl.getExtension('OES_texture_half_float'); 39296 break; 39297 } 39298 this.xrWebGLBinding = new XRWebGLBinding(session, gl); 39299 this.lightProbe.addEventListener('reflectionchange', ()=>{ 39300 this.updateReflection(); 39301 }); 39302 } 39303 // Start monitoring the XR animation frame loop to look for lighting 39304 // estimation changes. 39305 session.requestAnimationFrame(this.frameCallback); 39306 } 39307 } 39308 class XREstimatedLight extends Group { 39309 constructor(renderer, environmentEstimation = true){ 39310 super(); 39311 this.lightProbe = new LightProbe(); 39312 this.lightProbe.intensity = 0; 39313 this.add(this.lightProbe); 39314 this.directionalLight = new DirectionalLight(); 39315 this.directionalLight.intensity = 0; 39316 this.add(this.directionalLight);
vendor: 4,443 bytes, lines 39317-39422
39317 // Will be set to a cube map in the SessionLightProbe if environment estimation is 39318 // available and requested. 39319 this.environment = null; 39320 let sessionLightProbe = null; 39321 let estimationStarted = false; 39322 renderer.xr.addEventListener('sessionstart', ()=>{ 39323 const session = renderer.xr.getSession(); 39324 if ('requestLightProbe' in session) { 39325 session.requestLightProbe({ 39326 reflectionFormat: session.preferredReflectionFormat 39327 }).then((probe)=>{ 39328 sessionLightProbe = new SessionLightProbe(this, renderer, probe, environmentEstimation, ()=>{ 39329 estimationStarted = true; 39330 // Fired to indicate that the estimated lighting values are now being updated. 39331 this.dispatchEvent({ 39332 type: 'estimationstart' 39333 }); 39334 }); 39335 }); 39336 } 39337 }); 39338 renderer.xr.addEventListener('sessionend', ()=>{ 39339 if (sessionLightProbe) { 39340 sessionLightProbe.dispose(); 39341 sessionLightProbe = null; 39342 } 39343 if (estimationStarted) { 39344 // Fired to indicate that the estimated lighting values are no longer being updated. 39345 this.dispatchEvent({ 39346 type: 'estimationend' 39347 }); 39348 } 39349 }); 39350 // Done inline to provide access to sessionLightProbe. 39351 this.dispose = ()=>{ 39352 if (sessionLightProbe) { 39353 sessionLightProbe.dispose(); 39354 sessionLightProbe = null; 39355 } 39356 this.remove(this.lightProbe); 39357 this.lightProbe = null; 39358 this.remove(this.directionalLight); 39359 this.directionalLight = null; 39360 this.environment = null; 39361 }; 39362 } 39363 } 39364 39365 const SETTLING_TIME = 10000; 39366 const MIN_DECAY_MILLISECONDS = 0.001; 39367 const DECAY_MILLISECONDS = 50; 39368 class Damper { 39369 setDecayTime(decayMilliseconds) { 39370 this.naturalFrequency = 1 / Math.max(MIN_DECAY_MILLISECONDS, decayMilliseconds); 39371 } 39372 update(x, xGoal, timeStepMilliseconds, xNormalization) { 39373 const nilSpeed = 0.0002 * this.naturalFrequency; 39374 if (x == null || xNormalization === 0) { 39375 return xGoal; 39376 } 39377 if (x === xGoal && this.velocity === 0) { 39378 return xGoal; 39379 } 39380 if (timeStepMilliseconds < 0) { 39381 return x; 39382 } 39383 const deltaX = x - xGoal; 39384 const intermediateVelocity = this.velocity + this.naturalFrequency * deltaX; 39385 const intermediateX = deltaX + timeStepMilliseconds * intermediateVelocity; 39386 const decay = Math.exp(-this.naturalFrequency * timeStepMilliseconds); 39387 const newVelocity = (intermediateVelocity - this.naturalFrequency * intermediateX) * decay; 39388 const acceleration = -this.naturalFrequency * (newVelocity + intermediateVelocity * decay); 39389 if (Math.abs(newVelocity) < nilSpeed * Math.abs(xNormalization) && acceleration * deltaX >= 0) { 39390 this.velocity = 0; 39391 return xGoal; 39392 } else { 39393 this.velocity = newVelocity; 39394 return xGoal + intermediateX * decay; 39395 } 39396 } 39397 constructor(decayMilliseconds = DECAY_MILLISECONDS){ 39398 this.velocity = 0; 39399 this.naturalFrequency = 0; 39400 this.setDecayTime(decayMilliseconds); 39401 } 39402 } 39403 39404 const RADIUS = 0.2; 39405 const LINE_WIDTH = 0.03; 39406 const MAX_OPACITY = 0.75; 39407 const SEGMENTS = 12; 39408 const DELTA_PHI = Math.PI / (2 * SEGMENTS); 39409 const vector2$1 = new Vector2(); 39410 const addCorner = (vertices, cornerX, cornerY)=>{ 39411 let phi = cornerX > 0 ? cornerY > 0 ? 0 : -Math.PI / 2 : cornerY > 0 ? Math.PI / 2 : Math.PI; 39412 for(let i = 0; i <= SEGMENTS; ++i){ 39413 vertices.push(cornerX + (RADIUS - LINE_WIDTH) * Math.cos(phi), cornerY + (RADIUS - LINE_WIDTH) * Math.sin(phi), 0, cornerX + RADIUS * Math.cos(phi), cornerY + RADIUS * Math.sin(phi), 0); 39414 phi += DELTA_PHI; 39415 } 39416 }; 39417 class PlacementBox extends Mesh { 39418 getHit(scene, screenX, screenY) { 39419 vector2$1.set(screenX, -screenY); 39420 this.hitPlane.visible = true; 39421 const hitResult = scene.positionAndNormalFromPoint(vector2$1, this.hitPlane); 39422 this.hitPlane.visible = false;
39423 return hitResult == null ? null : hitResult.position; 39424 } 39425 getExpandedHit(scene, screenX, screenY) { 39426 this.hitPlane.scale.set(1000, 1000, 1000); 39427 this.hitPlane.updateMatrixWorld(); 39428 const hitResult = this.getHit(scene, screenX, screenY); 39429 this.hitPlane.scale.set(1, 1, 1); 39430 return hitResult; 39431 } 39432 controllerIntersection(scene, controller) { 39433 this.hitBox.visible = true; 39434 const hitResult = scene.hitFromController(controller, this.hitBox); 39435 this.hitBox.visible = false; 39436 return hitResult; 39437 } 39438 set offsetHeight(offset) { 39439 offset -= 0.001; 39440 if (this.side === 'back') { 39441 this.position.z = this.shadowHeight + offset; 39442 } else { 39443 this.position.y = this.shadowHeight + offset; 39444 } 39445 } 39446 get offsetHeight() { 39447 if (this.side === 'back') { 39448 return this.position.z - this.shadowHeight; 39449 } else { 39450 return this.position.y - this.shadowHeight; 39451 } 39452 } 39453 set show(visible) { 39454 this.goalOpacity = visible ? MAX_OPACITY : 0; 39455 } 39456 updateOpacity(delta) { 39457 const material = this.material; 39458 material.opacity = this.opacityDamper.update(material.opacity, this.goalOpacity, delta, 1); 39459 this.visible = material.opacity > 0; 39460 } 39461 dispose() { 39462 const { geometry, material } = this.hitPlane; 39463 geometry.dispose(); 39464 material.dispose(); 39465 this.hitBox.geometry.dispose(); 39466 this.hitBox.material.dispose(); 39467 this.geometry.dispose(); 39468 this.material.dispose(); 39469 this.hitBox.removeFromParent(); 39470 this.removeFromParent(); 39471 } 39472 constructor(scene, side){ 39473 const geometry = new BufferGeometry(); 39474 const triangles = []; 39475 const vertices = []; 39476 const { size, boundingBox } = scene; 39477 const x = size.x / 2; 39478 const y = (side === 'back' ? size.y : size.z) / 2; 39479 addCorner(vertices, x, y); 39480 addCorner(vertices, -x, y); 39481 addCorner(vertices, -x, -y); 39482 addCorner(vertices, x, -y); 39483 const numVertices = vertices.length / 3; 39484 for(let i = 0; i < numVertices - 2; i += 2){ 39485 triangles.push(i, i + 1, i + 3, i, i + 3, i + 2); 39486 } 39487 const i = numVertices - 2; 39488 triangles.push(i, i + 1, 1, i, 1, 0); 39489 geometry.setAttribute('position', new Float32BufferAttribute(vertices, 3)); 39490 geometry.setIndex(triangles); 39491 super(geometry); 39492 this.side = side; 39493 const material = this.material; 39494 material.side = DoubleSide; 39495 material.transparent = true; 39496 material.opacity = 0; 39497 this.goalOpacity = 0; 39498 this.opacityDamper = new Damper(); 39499 this.hitPlane = new Mesh(new PlaneGeometry(2 * (x + RADIUS), 2 * (y + RADIUS))); 39500 this.hitPlane.visible = false; 39501 this.hitPlane.material.side = DoubleSide; 39502 this.add(this.hitPlane); 39503 this.hitBox = new Mesh(new BoxGeometry(size.x + 2 * RADIUS, size.y + RADIUS, size.z + 2 * RADIUS)); 39504 this.hitBox.visible = false; 39505 this.hitBox.material.side = DoubleSide; 39506 this.add(this.hitBox); 39507 boundingBox.getCenter(this.position); 39508 switch(side){ 39509 case 'bottom': 39510 this.rotateX(-Math.PI / 2); 39511 this.shadowHeight = boundingBox.min.y; 39512 this.position.y = this.shadowHeight; 39513 break; 39514 case 'back': 39515 this.shadowHeight = boundingBox.min.z; 39516 this.position.z = this.shadowHeight; 39517 } 39518 scene.target.add(this); 39519 this.hitBox.position.y = (size.y + RADIUS) / 2 + boundingBox.min.y; 39520 scene.target.add(this.hitBox); 39521 this.offsetHeight = 0; 39522 } 39523 } 39524 39525 const numberNode = (value, unit)=>({ 39526 type: 'number', 39527 number: value, 39528 unit 39529 }); 39530 const parseExpressions = (()=>{ 39531 const cache = {}; 39532 const MAX_PARSE_ITERATIONS = 1000; 39533 return (inputString)=>{ 39534 const cacheKey = inputString; 39535 if (cacheKey in cache) { 39536 return cache[cacheKey]; 39537 } 39538 const expressions = []; 39539 let parseIterations = 0; 39540 while(inputString){ 39541 if (++parseIterations > MAX_PARSE_ITERATIONS) { 39542 inputString = ''; 39543 break; 39544 } 39545 const expressionParseResult = parseExpression(inputString); 39546 const expression = expressionParseResult.nodes[0]; 39547 if (expression == null || expression.terms.length === 0) { 39548 break; 39549 } 39550 expressions.push(expression); 39551 inputString = expressionParseResult.remainingInput; 39552 } 39553 return cache[cacheKey] = expressions; 39554 }; 39555 })(); 39556 const parseExpression = (()=>{ 39557 const IS_IDENT_RE = /^(\-\-|[a-z\u0240-\uffff])/i;
vendor: 24,025 bytes, lines 39558-40223
39558 const IS_OPERATOR_RE = /^([\*\+\/]|[\-]\s)/i; 39559 const IS_EXPRESSION_END_RE = /^[\),]/; 39560 const FUNCTION_ARGUMENTS_FIRST_TOKEN = '('; 39561 const HEX_FIRST_TOKEN = '#'; 39562 return (inputString)=>{ 39563 const terms = []; 39564 while(inputString.length){ 39565 inputString = inputString.trim(); 39566 if (IS_EXPRESSION_END_RE.test(inputString)) { 39567 break; 39568 } else if (inputString[0] === FUNCTION_ARGUMENTS_FIRST_TOKEN) { 39569 const { nodes, remainingInput } = parseFunctionArguments(inputString); 39570 inputString = remainingInput; 39571 terms.push({ 39572 type: 'function', 39573 name: { 39574 type: 'ident', 39575 value: 'calc' 39576 }, 39577 arguments: nodes 39578 }); 39579 } else if (IS_IDENT_RE.test(inputString)) { 39580 const identParseResult = parseIdent(inputString); 39581 const identNode = identParseResult.nodes[0]; 39582 inputString = identParseResult.remainingInput; 39583 if (inputString[0] === FUNCTION_ARGUMENTS_FIRST_TOKEN) { 39584 const { nodes, remainingInput } = parseFunctionArguments(inputString); 39585 terms.push({ 39586 type: 'function', 39587 name: identNode, 39588 arguments: nodes 39589 }); 39590 inputString = remainingInput; 39591 } else { 39592 terms.push(identNode); 39593 } 39594 } else if (IS_OPERATOR_RE.test(inputString)) { 39595 terms.push({ 39596 type: 'operator', 39597 value: inputString[0] 39598 }); 39599 inputString = inputString.slice(1); 39600 } else { 39601 const { nodes, remainingInput } = inputString[0] === HEX_FIRST_TOKEN ? parseHex(inputString) : parseNumber(inputString); 39602 if (nodes.length === 0) { 39603 break; 39604 } 39605 terms.push(nodes[0]); 39606 inputString = remainingInput; 39607 } 39608 } 39609 return { 39610 nodes: [ 39611 { 39612 type: 'expression', 39613 terms 39614 } 39615 ], 39616 remainingInput: inputString 39617 }; 39618 }; 39619 })(); 39620 const parseIdent = (()=>{ 39621 const NOT_IDENT_RE = /[^a-z0-9_\-\u0240-\uffff]/i; 39622 return (inputString)=>{ 39623 const match = inputString.match(NOT_IDENT_RE); 39624 const ident = match == null ? inputString : inputString.substr(0, match.index); 39625 const remainingInput = match == null ? '' : inputString.substr(match.index); 39626 return { 39627 nodes: [ 39628 { 39629 type: 'ident', 39630 value: ident 39631 } 39632 ], 39633 remainingInput 39634 }; 39635 }; 39636 })(); 39637 const parseNumber = (()=>{ 39638 const VALUE_RE = /[\+\-]?(\d+[\.]\d+|\d+|[\.]\d+)([eE][\+\-]?\d+)?/; 39639 const UNIT_RE = /^[a-z%]+/i; 39640 const ALLOWED_UNITS = /^(m|mm|cm|rad|deg|[%])$/; 39641 return (inputString)=>{ 39642 const valueMatch = inputString.match(VALUE_RE); 39643 const value = valueMatch == null ? '0' : valueMatch[0]; 39644 inputString = value == null ? inputString : inputString.slice(value.length); 39645 const unitMatch = inputString.match(UNIT_RE); 39646 let unit = unitMatch != null && unitMatch[0] !== '' ? unitMatch[0] : null; 39647 const remainingInput = unitMatch == null ? inputString : inputString.slice(unit.length); 39648 if (unit != null && !ALLOWED_UNITS.test(unit)) { 39649 unit = null; 39650 } 39651 return { 39652 nodes: [ 39653 { 39654 type: 'number', 39655 number: parseFloat(value) || 0, 39656 unit: unit 39657 } 39658 ], 39659 remainingInput 39660 }; 39661 }; 39662 })(); 39663 const parseHex = (()=>{ 39664 const HEX_RE = /^[a-f0-9]*/i; 39665 return (inputString)=>{ 39666 inputString = inputString.slice(1).trim(); 39667 const hexMatch = inputString.match(HEX_RE); 39668 const nodes = hexMatch == null ? [] : [ 39669 { 39670 type: 'hex', 39671 value: hexMatch[0] 39672 } 39673 ]; 39674 return { 39675 nodes, 39676 remainingInput: hexMatch == null ? inputString : inputString.slice(hexMatch[0].length) 39677 }; 39678 }; 39679 })(); 39680 const parseFunctionArguments = (inputString)=>{ 39681 const expressionNodes = []; 39682 inputString = inputString.slice(1).trim(); 39683 while(inputString.length){ 39684 const expressionParseResult = parseExpression(inputString); 39685 expressionNodes.push(expressionParseResult.nodes[0]); 39686 inputString = expressionParseResult.remainingInput.trim(); 39687 if (inputString[0] === ',') { 39688 inputString = inputString.slice(1).trim(); 39689 } else if (inputString[0] === ')') { 39690 inputString = inputString.slice(1); 39691 break; 39692 } 39693 } 39694 return { 39695 nodes: expressionNodes, 39696 remainingInput: inputString 39697 }; 39698 }; 39699 const $visitedTypes = Symbol('visitedTypes'); 39700 class ASTWalker { 39701 walk(ast, callback) { 39702 const remaining = ast.slice(); 39703 while(remaining.length){ 39704 const next = remaining.shift(); 39705 if (this[$visitedTypes].indexOf(next.type) > -1) { 39706 callback(next); 39707 } 39708 switch(next.type){ 39709 case 'expression': 39710 remaining.unshift(...next.terms); 39711 break; 39712 case 'function': 39713 remaining.unshift(next.name, ...next.arguments); 39714 break; 39715 } 39716 } 39717 } 39718 constructor(visitedTypes){ 39719 this[$visitedTypes] = visitedTypes; 39720 } 39721 } 39722 const ZERO = Object.freeze({ 39723 type: 'number', 39724 number: 0, 39725 unit: null 39726 }); 39727 39728 const degreesToRadians = (numberNode, fallbackRadianValue = 0)=>{ 39729 let { number, unit } = numberNode; 39730 if (!isFinite(number)) { 39731 number = fallbackRadianValue; 39732 unit = 'rad'; 39733 } else if (numberNode.unit === 'rad' || numberNode.unit == null) { 39734 return numberNode; 39735 } 39736 const valueIsDegrees = unit === 'deg' && number != null; 39737 const value = valueIsDegrees ? number : 0; 39738 const radians = value * Math.PI / 180; 39739 return { 39740 type: 'number', 39741 number: radians, 39742 unit: 'rad' 39743 }; 39744 }; 39745 const lengthToBaseMeters = (numberNode, fallbackMeterValue = 0)=>{ 39746 let { number, unit } = numberNode; 39747 if (!isFinite(number)) { 39748 number = fallbackMeterValue; 39749 unit = 'm'; 39750 } else if (numberNode.unit === 'm') { 39751 return numberNode; 39752 } 39753 let scale; 39754 switch(unit){ 39755 default: 39756 scale = 1; 39757 break; 39758 case 'cm': 39759 scale = 1 / 100; 39760 break; 39761 case 'mm': 39762 scale = 1 / 1000; 39763 break; 39764 } 39765 const value = scale * number; 39766 return { 39767 type: 'number', 39768 number: value, 39769 unit: 'm' 39770 }; 39771 }; 39772 const normalizeUnit = (()=>{ 39773 const identity = (node)=>node; 39774 const unitNormalizers = { 39775 'rad': identity, 39776 'deg': degreesToRadians, 39777 'm': identity, 39778 'mm': lengthToBaseMeters, 39779 'cm': lengthToBaseMeters 39780 }; 39781 return (node, fallback = ZERO)=>{ 39782 if (!isFinite(node.number)) { 39783 node.number = fallback.number; 39784 node.unit = fallback.unit; 39785 } 39786 const { unit } = node; 39787 if (unit == null) { 39788 return node; 39789 } 39790 const normalize = unitNormalizers[unit]; 39791 if (normalize == null) { 39792 return fallback; 39793 } 39794 return normalize(node); 39795 }; 39796 })(); 39797 39798 var _a$6, _b$6, _c$4; 39799 const $evaluate = Symbol('evaluate'); 39800 const $lastValue = Symbol('lastValue'); 39801 class Evaluator { 39802 static evaluatableFor(node, basis = ZERO) { 39803 if (node instanceof Evaluator) { 39804 return node; 39805 } 39806 if (node.type === 'number') { 39807 if (node.unit === '%') { 39808 return new PercentageEvaluator(node, basis); 39809 } 39810 return node; 39811 } 39812 switch(node.name.value){ 39813 case 'calc': 39814 return new CalcEvaluator(node, basis); 39815 case 'env': 39816 return new EnvEvaluator(node); 39817 } 39818 return ZERO; 39819 } 39820 static evaluate(evaluatable) { 39821 if (evaluatable instanceof Evaluator) { 39822 return evaluatable.evaluate(); 39823 } 39824 return evaluatable; 39825 } 39826 static isConstant(evaluatable) { 39827 if (evaluatable instanceof Evaluator) { 39828 return evaluatable.isConstant; 39829 } 39830 return true; 39831 } 39832 static applyIntrinsics(evaluated, intrinsics) { 39833 const { basis, keywords } = intrinsics; 39834 const { auto } = keywords; 39835 return basis.map((basisNode, index)=>{ 39836 const autoSubstituteNode = auto[index] == null ? basisNode : auto[index]; 39837 let evaluatedNode = evaluated[index] ? evaluated[index] : autoSubstituteNode; 39838 if (evaluatedNode.type === 'ident') { 39839 const keyword = evaluatedNode.value; 39840 if (keyword in keywords) { 39841 evaluatedNode = keywords[keyword][index]; 39842 } 39843 } 39844 if (evaluatedNode == null || evaluatedNode.type === 'ident') { 39845 evaluatedNode = autoSubstituteNode; 39846 } 39847 if (evaluatedNode.unit === '%') { 39848 return numberNode(evaluatedNode.number / 100 * basisNode.number, basisNode.unit); 39849 } 39850 evaluatedNode = normalizeUnit(evaluatedNode, basisNode); 39851 if (evaluatedNode.unit !== basisNode.unit) { 39852 return basisNode; 39853 } 39854 return evaluatedNode; 39855 }); 39856 } 39857 get isConstant() { 39858 return false; 39859 } 39860 evaluate() { 39861 if (!this.isConstant || this[$lastValue] == null) { 39862 this[$lastValue] = this[$evaluate](); 39863 } 39864 return this[$lastValue]; 39865 } 39866 constructor(){ 39867 this[_a$6] = null; 39868 } 39869 } 39870 _a$6 = $lastValue; 39871 const $percentage = Symbol('percentage'); 39872 const $basis = Symbol('basis'); 39873 class PercentageEvaluator extends Evaluator { 39874 get isConstant() { 39875 return true; 39876 } 39877 [$evaluate]() { 39878 return numberNode(this[$percentage].number / 100 * this[$basis].number, this[$basis].unit); 39879 } 39880 constructor(percentage, basis){ 39881 super(); 39882 this[$percentage] = percentage; 39883 this[$basis] = basis; 39884 } 39885 } 39886 const $identNode = Symbol('identNode'); 39887 class EnvEvaluator extends Evaluator { 39888 get isConstant() { 39889 return false; 39890 } 39891 [(_b$6 = $identNode, $evaluate)]() { 39892 if (this[$identNode] != null) { 39893 switch(this[$identNode].value){ 39894 case 'window-scroll-y': 39895 const verticalScrollPosition = window.pageYOffset; 39896 const verticalScrollMax = Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight); 39897 const scrollY = verticalScrollPosition / (verticalScrollMax - window.innerHeight) || 0; 39898 return { 39899 type: 'number', 39900 number: scrollY, 39901 unit: null 39902 }; 39903 } 39904 } 39905 return ZERO; 39906 } 39907 constructor(envFunction){ 39908 super(); 39909 this[_b$6] = null; 39910 const identNode = envFunction.arguments.length ? envFunction.arguments[0].terms[0] : null; 39911 if (identNode != null && identNode.type === 'ident') { 39912 this[$identNode] = identNode; 39913 } 39914 } 39915 } 39916 const IS_MULTIPLICATION_RE = /[\*\/]/; 39917 const $evaluator = Symbol('evaluator'); 39918 class CalcEvaluator extends Evaluator { 39919 get isConstant() { 39920 return this[$evaluator] == null || Evaluator.isConstant(this[$evaluator]); 39921 } 39922 [(_c$4 = $evaluator, $evaluate)]() { 39923 return this[$evaluator] != null ? Evaluator.evaluate(this[$evaluator]) : ZERO; 39924 } 39925 constructor(calcFunction, basis = ZERO){ 39926 super(); 39927 this[_c$4] = null; 39928 if (calcFunction.arguments.length !== 1) { 39929 return; 39930 } 39931 const terms = calcFunction.arguments[0].terms.slice(); 39932 const secondOrderTerms = []; 39933 while(terms.length){ 39934 const term = terms.shift(); 39935 if (secondOrderTerms.length > 0) { 39936 const previousTerm = secondOrderTerms[secondOrderTerms.length - 1]; 39937 if (previousTerm.type === 'operator' && IS_MULTIPLICATION_RE.test(previousTerm.value)) { 39938 const operator = secondOrderTerms.pop(); 39939 const leftValue = secondOrderTerms.pop(); 39940 if (leftValue == null) { 39941 return; 39942 } 39943 secondOrderTerms.push(new OperatorEvaluator(operator, Evaluator.evaluatableFor(leftValue, basis), Evaluator.evaluatableFor(term, basis))); 39944 continue; 39945 } 39946 } 39947 secondOrderTerms.push(term.type === 'operator' ? term : Evaluator.evaluatableFor(term, basis)); 39948 } 39949 while(secondOrderTerms.length > 2){ 39950 const [left, operator, right] = secondOrderTerms.splice(0, 3); 39951 if (operator.type !== 'operator') { 39952 return; 39953 } 39954 secondOrderTerms.unshift(new OperatorEvaluator(operator, Evaluator.evaluatableFor(left, basis), Evaluator.evaluatableFor(right, basis))); 39955 } 39956 if (secondOrderTerms.length === 1) { 39957 this[$evaluator] = secondOrderTerms[0]; 39958 } 39959 } 39960 } 39961 const $operator = Symbol('operator'); 39962 const $left = Symbol('left'); 39963 const $right = Symbol('right'); 39964 class OperatorEvaluator extends Evaluator { 39965 get isConstant() { 39966 return Evaluator.isConstant(this[$left]) && Evaluator.isConstant(this[$right]); 39967 } 39968 [$evaluate]() { 39969 const leftNode = normalizeUnit(Evaluator.evaluate(this[$left])); 39970 const rightNode = normalizeUnit(Evaluator.evaluate(this[$right])); 39971 const { number: leftValue, unit: leftUnit } = leftNode; 39972 const { number: rightValue, unit: rightUnit } = rightNode; 39973 if (rightUnit != null && leftUnit != null && rightUnit != leftUnit) { 39974 return ZERO; 39975 } 39976 const unit = leftUnit || rightUnit; 39977 let value; 39978 switch(this[$operator].value){ 39979 case '+': 39980 value = leftValue + rightValue; 39981 break; 39982 case '-': 39983 value = leftValue - rightValue; 39984 break; 39985 case '/': 39986 value = leftValue / rightValue; 39987 break; 39988 case '*': 39989 value = leftValue * rightValue; 39990 break; 39991 default: 39992 return ZERO; 39993 } 39994 return { 39995 type: 'number', 39996 number: value, 39997 unit 39998 }; 39999 } 40000 constructor(operator, left, right){ 40001 super(); 40002 this[$operator] = operator; 40003 this[$left] = left; 40004 this[$right] = right; 40005 } 40006 } 40007 const $evaluatables = Symbol('evaluatables'); 40008 const $intrinsics = Symbol('intrinsics'); 40009 class StyleEvaluator extends Evaluator { 40010 get isConstant() { 40011 for (const evaluatable of this[$evaluatables]){ 40012 if (!Evaluator.isConstant(evaluatable)) { 40013 return false; 40014 } 40015 } 40016 return true; 40017 } 40018 [$evaluate]() { 40019 const evaluated = this[$evaluatables].map((evaluatable)=>Evaluator.evaluate(evaluatable)); 40020 return Evaluator.applyIntrinsics(evaluated, this[$intrinsics]).map((numberNode)=>numberNode.number); 40021 } 40022 constructor(expressions, intrinsics){ 40023 super(); 40024 this[$intrinsics] = intrinsics; 40025 const firstExpression = expressions[0]; 40026 const terms = firstExpression != null ? firstExpression.terms : []; 40027 this[$evaluatables] = intrinsics.basis.map((basisNode, index)=>{ 40028 const term = terms[index]; 40029 if (term == null) { 40030 return { 40031 type: 'ident', 40032 value: 'auto' 40033 }; 40034 } 40035 if (term.type === 'ident') { 40036 return term; 40037 } 40038 return Evaluator.evaluatableFor(term, basisNode); 40039 }); 40040 } 40041 } 40042 40043 var _a$5, _b$5, _c$3, _d$2; 40044 const $instances = Symbol('instances'); 40045 const $activateListener = Symbol('activateListener'); 40046 const $deactivateListener = Symbol('deactivateListener'); 40047 const $notifyInstances = Symbol('notifyInstances'); 40048 const $notify = Symbol('notify'); 40049 const $scrollCallback = Symbol('callback'); 40050 class ScrollObserver { 40051 static [$notifyInstances]() { 40052 for (const instance of ScrollObserver[$instances]){ 40053 instance[$notify](); 40054 } 40055 } 40056 static [(_a$5 = $instances, $activateListener)]() { 40057 window.addEventListener('scroll', this[$notifyInstances], { 40058 passive: true 40059 }); 40060 } 40061 static [$deactivateListener]() { 40062 window.removeEventListener('scroll', this[$notifyInstances]); 40063 } 40064 observe() { 40065 if (ScrollObserver[$instances].size === 0) { 40066 ScrollObserver[$activateListener](); 40067 } 40068 ScrollObserver[$instances].add(this); 40069 } 40070 disconnect() { 40071 ScrollObserver[$instances].delete(this); 40072 if (ScrollObserver[$instances].size === 0) { 40073 ScrollObserver[$deactivateListener](); 40074 } 40075 } 40076 [$notify]() { 40077 this[$scrollCallback](); 40078 } 40079 constructor(callback){ 40080 this[$scrollCallback] = callback; 40081 } 40082 } 40083 ScrollObserver[_a$5] = new Set(); 40084 const $computeStyleCallback = Symbol('computeStyleCallback'); 40085 const $astWalker = Symbol('astWalker'); 40086 const $dependencies = Symbol('dependencies'); 40087 const $onScroll = Symbol('onScroll'); 40088 class StyleEffector { 40089 observeEffectsFor(ast) { 40090 const newDependencies = {}; 40091 const oldDependencies = this[$dependencies]; 40092 this[$astWalker].walk(ast, (functionNode)=>{ 40093 const { name } = functionNode; 40094 const firstArgument = functionNode.arguments[0]; 40095 const firstTerm = firstArgument.terms[0]; 40096 if (name.value !== 'env' || firstTerm == null || firstTerm.type !== 'ident') { 40097 return; 40098 } 40099 switch(firstTerm.value){ 40100 case 'window-scroll-y': 40101 if (newDependencies['window-scroll'] == null) { 40102 const observer = 'window-scroll' in oldDependencies ? oldDependencies['window-scroll'] : new ScrollObserver(this[$onScroll]); 40103 observer.observe(); 40104 delete oldDependencies['window-scroll']; 40105 newDependencies['window-scroll'] = observer; 40106 } 40107 break; 40108 } 40109 }); 40110 for(const environmentState in oldDependencies){ 40111 const observer = oldDependencies[environmentState]; 40112 observer.disconnect(); 40113 } 40114 this[$dependencies] = newDependencies; 40115 } 40116 dispose() { 40117 for(const environmentState in this[$dependencies]){ 40118 const observer = this[$dependencies][environmentState]; 40119 observer.disconnect(); 40120 } 40121 } 40122 constructor(callback){ 40123 this[_b$5] = {}; 40124 this[_c$3] = new ASTWalker([ 40125 'function' 40126 ]); 40127 this[_d$2] = ()=>{ 40128 this[$computeStyleCallback]({ 40129 relatedState: 'window-scroll' 40130 }); 40131 }; 40132 this[$computeStyleCallback] = callback; 40133 } 40134 } 40135 _b$5 = $dependencies, _c$3 = $astWalker, _d$2 = $onScroll; 40136 40137 const style = (config)=>{ 40138 const observeEffects = config.observeEffects || false; 40139 const getIntrinsics = config.intrinsics instanceof Function ? config.intrinsics : ()=>config.intrinsics; 40140 return (proto, propertyName)=>{ 40141 const originalUpdated = proto.updated; 40142 const originalConnectedCallback = proto.connectedCallback; 40143 const originalDisconnectedCallback = proto.disconnectedCallback; 40144 const $styleEffector = Symbol(`${propertyName}StyleEffector`); 40145 const $styleEvaluator = Symbol(`${propertyName}StyleEvaluator`); 40146 const $updateEvaluator = Symbol(`${propertyName}UpdateEvaluator`); 40147 const $evaluateAndSync = Symbol(`${propertyName}EvaluateAndSync`); 40148 Object.defineProperties(proto, { 40149 [$styleEffector]: { 40150 value: null, 40151 writable: true 40152 }, 40153 [$styleEvaluator]: { 40154 value: null, 40155 writable: true 40156 }, 40157 [$updateEvaluator]: { 40158 value: function() { 40159 const ast = parseExpressions(this[propertyName]); 40160 this[$styleEvaluator] = new StyleEvaluator(ast, getIntrinsics(this)); 40161 if (this[$styleEffector] == null && observeEffects) { 40162 this[$styleEffector] = new StyleEffector(()=>this[$evaluateAndSync]()); 40163 } 40164 if (this[$styleEffector] != null) { 40165 this[$styleEffector].observeEffectsFor(ast); 40166 } 40167 } 40168 }, 40169 [$evaluateAndSync]: { 40170 value: function() { 40171 if (this[$styleEvaluator] == null) { 40172 return; 40173 } 40174 const result = this[$styleEvaluator].evaluate(); 40175 this[config.updateHandler](result); 40176 } 40177 }, 40178 updated: { 40179 value: function(changedProperties) { 40180 if (changedProperties.has(propertyName)) { 40181 this[$updateEvaluator](); 40182 this[$evaluateAndSync](); 40183 } 40184 originalUpdated.call(this, changedProperties); 40185 } 40186 }, 40187 connectedCallback: { 40188 value: function() { 40189 originalConnectedCallback.call(this); 40190 this.requestUpdate(propertyName, this[propertyName]); 40191 } 40192 }, 40193 disconnectedCallback: { 40194 value: function() { 40195 originalDisconnectedCallback.call(this); 40196 if (this[$styleEffector] != null) { 40197 this[$styleEffector].dispose(); 40198 this[$styleEffector] = null; 40199 } 40200 } 40201 } 40202 }); 40203 }; 40204 }; 40205 40206 const easeInOutQuad = (t)=>t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t; 40207 const interpolate = (start, end, ease = easeInOutQuad)=>(time)=>start + (end - start) * ease(time); 40208 const sequence = (tracks, weights)=>{ 40209 const cumulativeSum = (sum)=>(value)=>sum += value; 40210 const times = weights.map(cumulativeSum(0)); 40211 return (time)=>{ 40212 time = clamp(time, 0, 1); 40213 time *= times[times.length - 1]; 40214 const i = times.findIndex((val)=>val >= time); 40215 const start = i < 1 ? 0 : times[i - 1]; 40216 const end = times[i]; 40217 return tracks[i]((time - start) / (end - start)); 40218 }; 40219 }; 40220 const timeline = (path)=>{ 40221 const tracks = []; 40222 const weights = []; 40223 let lastValue = path.initialValue;
vendor: 6,810 bytes, lines 40224-40453
40224 for(let i = 0; i < path.keyframes.length; ++i){ 40225 const keyframe = path.keyframes[i]; 40226 const { value, frames } = keyframe; 40227 const ease = keyframe.ease || easeInOutQuad; 40228 const track = interpolate(lastValue, value, ease); 40229 tracks.push(track); 40230 weights.push(frames); 40231 lastValue = value; 40232 } 40233 return sequence(tracks, weights); 40234 }; 40235 40236 var __decorate$6 = undefined && undefined.__decorate || function(decorators, target, key, desc) { 40237 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 40238 for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 40239 return c > 3 && r && Object.defineProperty(target, key, r), r; 40240 }; 40241 const PROMPT_ANIMATION_TIME = 5000; 40242 const wiggle = timeline({ 40243 initialValue: 0, 40244 keyframes: [ 40245 { 40246 frames: 5, 40247 value: -1 40248 }, 40249 { 40250 frames: 1, 40251 value: -1 40252 }, 40253 { 40254 frames: 8, 40255 value: 1 40256 }, 40257 { 40258 frames: 1, 40259 value: 1 40260 }, 40261 { 40262 frames: 5, 40263 value: 0 40264 }, 40265 { 40266 frames: 18, 40267 value: 0 40268 } 40269 ] 40270 }); 40271 const fade = timeline({ 40272 initialValue: 0, 40273 keyframes: [ 40274 { 40275 frames: 1, 40276 value: 1 40277 }, 40278 { 40279 frames: 5, 40280 value: 1 40281 }, 40282 { 40283 frames: 1, 40284 value: 0 40285 }, 40286 { 40287 frames: 6, 40288 value: 0 40289 } 40290 ] 40291 }); 40292 const DEFAULT_FOV_DEG = 30; 40293 const DEFAULT_MIN_FOV_DEG = 12; 40294 const DEFAULT_CAMERA_ORBIT = '0deg 75deg 105%'; 40295 const DEFAULT_CAMERA_TARGET = 'auto auto auto'; 40296 const DEFAULT_FIELD_OF_VIEW = 'auto'; 40297 const MINIMUM_RADIUS_RATIO = 2.2; 40298 const AZIMUTHAL_QUADRANT_LABELS = [ 40299 'front', 40300 'right', 40301 'back', 40302 'left' 40303 ]; 40304 const POLAR_TRIENT_LABELS = [ 40305 'upper-', 40306 '', 40307 'lower-' 40308 ]; 40309 const DEFAULT_INTERACTION_PROMPT_THRESHOLD = 3000; 40310 const INTERACTION_PROMPT = '. Use mouse, touch or arrow keys to move.'; 40311 const InteractionPromptStrategy = { 40312 AUTO: 'auto'}; 40313 const InteractionPromptStyle = { 40314 BASIC: 'basic', 40315 WIGGLE: 'wiggle' 40316 }; 40317 const TouchAction = { 40318 NONE: 'none' 40319 }; 40320 const fieldOfViewIntrinsics = ()=>{ 40321 return { 40322 basis: [ 40323 degreesToRadians(numberNode(DEFAULT_FOV_DEG, 'deg')) 40324 ], 40325 keywords: { 40326 auto: [ 40327 null 40328 ] 40329 } 40330 }; 40331 }; 40332 const minFieldOfViewIntrinsics = ()=>{ 40333 return { 40334 basis: [ 40335 degreesToRadians(numberNode(DEFAULT_MIN_FOV_DEG, 'deg')) 40336 ], 40337 keywords: { 40338 auto: [ 40339 null 40340 ] 40341 } 40342 }; 40343 }; 40344 const cameraOrbitIntrinsics = (()=>{ 40345 const defaultTerms = parseExpressions(DEFAULT_CAMERA_ORBIT)[0].terms; 40346 const theta = normalizeUnit(defaultTerms[0]); 40347 const phi = normalizeUnit(defaultTerms[1]); 40348 return (element)=>{ 40349 const radius = element[$scene].idealCameraDistance(); 40350 return { 40351 basis: [ 40352 theta, 40353 phi, 40354 numberNode(radius, 'm') 40355 ], 40356 keywords: { 40357 auto: [ 40358 null, 40359 null, 40360 numberNode(105, '%') 40361 ] 40362 } 40363 }; 40364 }; 40365 })(); 40366 const minCameraOrbitIntrinsics = (element)=>{ 40367 const radius = MINIMUM_RADIUS_RATIO * element[$scene].boundingSphere.radius; 40368 return { 40369 basis: [ 40370 numberNode(-Infinity, 'rad'), 40371 numberNode(0, 'rad'), 40372 numberNode(radius, 'm') 40373 ], 40374 keywords: { 40375 auto: [ 40376 null, 40377 null, 40378 null 40379 ] 40380 } 40381 }; 40382 }; 40383 const maxCameraOrbitIntrinsics = (element)=>{ 40384 const orbitIntrinsics = cameraOrbitIntrinsics(element); 40385 const evaluator = new StyleEvaluator([], orbitIntrinsics); 40386 const defaultRadius = evaluator.evaluate()[2]; 40387 return { 40388 basis: [ 40389 numberNode(Infinity, 'rad'), 40390 numberNode(Math.PI, 'rad'), 40391 numberNode(defaultRadius, 'm') 40392 ], 40393 keywords: { 40394 auto: [ 40395 null, 40396 null, 40397 null 40398 ] 40399 } 40400 }; 40401 }; 40402 const cameraTargetIntrinsics = (element)=>{ 40403 const center = element[$scene].boundingBox.getCenter(new Vector3()); 40404 return { 40405 basis: [ 40406 numberNode(center.x, 'm'), 40407 numberNode(center.y, 'm'), 40408 numberNode(center.z, 'm') 40409 ], 40410 keywords: { 40411 auto: [ 40412 null, 40413 null, 40414 null 40415 ] 40416 } 40417 }; 40418 }; 40419 const HALF_PI = Math.PI / 2.0; 40420 const THIRD_PI = Math.PI / 3.0; 40421 const QUARTER_PI = HALF_PI / 2.0; 40422 const TAU = 2.0 * Math.PI; 40423 const $controls = Symbol('controls'); 40424 const $panElement = Symbol('panElement'); 40425 const $promptElement = Symbol('promptElement'); 40426 const $promptAnimatedContainer = Symbol('promptAnimatedContainer'); 40427 const $fingerAnimatedContainers = Symbol('fingerAnimatedContainers'); 40428 const $deferInteractionPrompt = Symbol('deferInteractionPrompt'); 40429 const $updateAria = Symbol('updateAria'); 40430 const $a11y = Symbol('a11y'); 40431 const $updateA11y = Symbol('updateA11y'); 40432 const $updateCameraForRadius = Symbol('updateCameraForRadius'); 40433 const $cancelPrompts = Symbol('cancelPrompts'); 40434 const $onChange = Symbol('onChange'); 40435 const $onPointerChange = Symbol('onPointerChange'); 40436 const $waitingToPromptUser = Symbol('waitingToPromptUser'); 40437 const $userHasInteracted = Symbol('userHasInteracted'); 40438 const $promptElementVisibleTime = Symbol('promptElementVisibleTime'); 40439 const $lastPromptOffset = Symbol('lastPromptOffset'); 40440 const $cancellationSource = Symbol('cancellationSource'); 40441 const $lastSpherical = Symbol('lastSpherical'); 40442 const $jumpCamera = Symbol('jumpCamera'); 40443 const $initialized = Symbol('initialized'); 40444 const $maintainThetaPhi = Symbol('maintainThetaPhi'); 40445 const $syncCameraOrbit = Symbol('syncCameraOrbit'); 40446 const $syncFieldOfView = Symbol('syncFieldOfView'); 40447 const $syncCameraTarget = Symbol('syncCameraTarget'); 40448 const $syncMinCameraOrbit = Symbol('syncMinCameraOrbit'); 40449 const $syncMaxCameraOrbit = Symbol('syncMaxCameraOrbit'); 40450 const $syncMinFieldOfView = Symbol('syncMinFieldOfView'); 40451 const $syncMaxFieldOfView = Symbol('syncMaxFieldOfView'); 40452 const ControlsMixin = (ModelViewerElement)=>{ 40453 var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
vendor: 20,162 bytes, lines 40454-40885
40454 class ControlsModelViewerElement extends ModelViewerElement { 40455 get inputSensitivity() { 40456 return this[$controls].inputSensitivity; 40457 } 40458 set inputSensitivity(value) { 40459 this[$controls].inputSensitivity = value; 40460 } 40461 getCameraOrbit() { 40462 const { theta, phi, radius } = this[$lastSpherical]; 40463 return { 40464 theta, 40465 phi, 40466 radius, 40467 toString () { 40468 return `${this.theta}rad ${this.phi}rad ${this.radius}m`; 40469 } 40470 }; 40471 } 40472 getCameraTarget() { 40473 return toVector3D(this[$renderer].isPresenting ? this[$renderer].arRenderer.target : this[$scene].getDynamicTarget()); 40474 } 40475 getFieldOfView() { 40476 return this[$controls].getFieldOfView(); 40477 } 40478 getMinimumFieldOfView() { 40479 return this[$controls].options.minimumFieldOfView; 40480 } 40481 getMaximumFieldOfView() { 40482 return this[$controls].options.maximumFieldOfView; 40483 } 40484 getIdealAspect() { 40485 return this[$scene].idealAspect; 40486 } 40487 jumpCameraToGoal() { 40488 this[$jumpCamera] = true; 40489 this.requestUpdate($jumpCamera, false); 40490 } 40491 resetInteractionPrompt() { 40492 this[$lastPromptOffset] = 0; 40493 this[$promptElementVisibleTime] = Infinity; 40494 this[$userHasInteracted] = false; 40495 this[$waitingToPromptUser] = this.interactionPrompt === InteractionPromptStrategy.AUTO && this.cameraControls; 40496 } 40497 zoom(keyPresses) { 40498 const event = new WheelEvent('wheel', { 40499 deltaY: -30 * keyPresses 40500 }); 40501 this[$userInputElement].dispatchEvent(event); 40502 } 40503 connectedCallback() { 40504 super.connectedCallback(); 40505 this[$controls].addEventListener('user-interaction', this[$cancelPrompts]); 40506 this[$controls].addEventListener('pointer-change-start', this[$onPointerChange]); 40507 this[$controls].addEventListener('pointer-change-end', this[$onPointerChange]); 40508 } 40509 disconnectedCallback() { 40510 super.disconnectedCallback(); 40511 this[$controls].removeEventListener('user-interaction', this[$cancelPrompts]); 40512 this[$controls].removeEventListener('pointer-change-start', this[$onPointerChange]); 40513 this[$controls].removeEventListener('pointer-change-end', this[$onPointerChange]); 40514 } 40515 updated(changedProperties) { 40516 super.updated(changedProperties); 40517 const controls = this[$controls]; 40518 const scene = this[$scene]; 40519 if (changedProperties.has('cameraControls')) { 40520 if (this.cameraControls) { 40521 controls.enableInteraction(); 40522 if (this.interactionPrompt === InteractionPromptStrategy.AUTO) { 40523 this[$waitingToPromptUser] = true; 40524 } 40525 } else { 40526 controls.disableInteraction(); 40527 this[$deferInteractionPrompt](); 40528 } 40529 this[$userInputElement].setAttribute('aria-label', this[$ariaLabel]); 40530 } 40531 if (changedProperties.has('disableZoom')) { 40532 controls.disableZoom = this.disableZoom; 40533 } 40534 if (changedProperties.has('disablePan')) { 40535 controls.enablePan = !this.disablePan; 40536 } 40537 if (changedProperties.has('disableTap')) { 40538 controls.enableTap = !this.disableTap; 40539 } 40540 if (changedProperties.has('interactionPrompt') || changedProperties.has('cameraControls') || changedProperties.has('src')) { 40541 if (this.interactionPrompt === InteractionPromptStrategy.AUTO && this.cameraControls && !this[$userHasInteracted]) { 40542 this[$waitingToPromptUser] = true; 40543 } else { 40544 this[$deferInteractionPrompt](); 40545 } 40546 } 40547 if (changedProperties.has('interactionPromptStyle')) { 40548 this[$promptAnimatedContainer].style.opacity = this.interactionPromptStyle == InteractionPromptStyle.BASIC ? '1' : '0'; 40549 } 40550 if (changedProperties.has('touchAction')) { 40551 const touchAction = this.touchAction; 40552 controls.applyOptions({ 40553 touchAction 40554 }); 40555 controls.updateTouchActionStyle(); 40556 } 40557 if (changedProperties.has('orbitSensitivity')) { 40558 controls.orbitSensitivity = this.orbitSensitivity; 40559 } 40560 if (changedProperties.has('zoomSensitivity')) { 40561 controls.zoomSensitivity = this.zoomSensitivity; 40562 } 40563 if (changedProperties.has('panSensitivity')) { 40564 controls.panSensitivity = this.panSensitivity; 40565 } 40566 if (changedProperties.has('interpolationDecay')) { 40567 controls.setDamperDecayTime(this.interpolationDecay); 40568 scene.setTargetDamperDecayTime(this.interpolationDecay); 40569 } 40570 if (changedProperties.has('a11y')) { 40571 this[$updateA11y](); 40572 } 40573 if (this[$jumpCamera] === true) { 40574 Promise.resolve().then(()=>{ 40575 controls.jumpToGoal(); 40576 scene.jumpToGoal(); 40577 this[$onChange](); 40578 this[$jumpCamera] = false; 40579 }); 40580 } 40581 } 40582 async updateFraming() { 40583 const scene = this[$scene]; 40584 const oldFramedFoV = scene.adjustedFoV(scene.framedFoVDeg); 40585 await scene.updateFraming(); 40586 const newFramedFoV = scene.adjustedFoV(scene.framedFoVDeg); 40587 const zoom = this[$controls].getFieldOfView() / oldFramedFoV; 40588 this[$controls].setFieldOfView(newFramedFoV * zoom); 40589 this[$maintainThetaPhi] = true; 40590 this.requestUpdate('maxFieldOfView'); 40591 this.requestUpdate('fieldOfView'); 40592 this.requestUpdate('minCameraOrbit'); 40593 this.requestUpdate('maxCameraOrbit'); 40594 this.requestUpdate('cameraOrbit'); 40595 await this.updateComplete; 40596 } 40597 interact(duration, finger0, finger1) { 40598 const inputElement = this[$userInputElement]; 40599 const fingerElements = this[$fingerAnimatedContainers]; 40600 if (fingerElements[0].style.opacity === '1') { 40601 console.warn('interact() failed because an existing interaction is running.'); 40602 return; 40603 } 40604 const xy = new Array(); 40605 xy.push({ 40606 x: timeline(finger0.x), 40607 y: timeline(finger0.y) 40608 }); 40609 const positions = [ 40610 { 40611 x: xy[0].x(0), 40612 y: xy[0].y(0) 40613 } 40614 ]; 40615 if (finger1 != null) { 40616 xy.push({ 40617 x: timeline(finger1.x), 40618 y: timeline(finger1.y) 40619 }); 40620 positions.push({ 40621 x: xy[1].x(0), 40622 y: xy[1].y(0) 40623 }); 40624 } 40625 let startTime = performance.now(); 40626 const { width, height } = this[$scene]; 40627 const rect = this.getBoundingClientRect(); 40628 const dispatchTouches = (type)=>{ 40629 for (const [i, position] of positions.entries()){ 40630 const { style } = fingerElements[i]; 40631 style.transform = `translateX(${width * position.x}px) translateY(${height * position.y}px)`; 40632 if (type === 'pointerdown') { 40633 style.opacity = '1'; 40634 } else if (type === 'pointerup') { 40635 style.opacity = '0'; 40636 } 40637 const init = { 40638 pointerId: i - 5678, 40639 pointerType: 'touch', 40640 target: inputElement, 40641 clientX: width * position.x + rect.x, 40642 clientY: height * position.y + rect.y, 40643 altKey: true 40644 }; 40645 inputElement.dispatchEvent(new PointerEvent(type, init)); 40646 } 40647 }; 40648 const moveTouches = ()=>{ 40649 const changeSource = this[$cancellationSource]; 40650 if (changeSource !== ChangeSource.AUTOMATIC || !inputElement.isConnected) { 40651 for (const fingerElement of this[$fingerAnimatedContainers]){ 40652 fingerElement.style.opacity = '0'; 40653 } 40654 dispatchTouches('pointercancel'); 40655 this.dispatchEvent(new CustomEvent('interact-stopped', { 40656 detail: { 40657 source: changeSource 40658 } 40659 })); 40660 document.removeEventListener('visibilitychange', onVisibilityChange); 40661 return; 40662 } 40663 const time = Math.min(1, (performance.now() - startTime) / duration); 40664 for (const [i, position] of positions.entries()){ 40665 position.x = xy[i].x(time); 40666 position.y = xy[i].y(time); 40667 } 40668 dispatchTouches('pointermove'); 40669 if (time < 1) { 40670 requestAnimationFrame(moveTouches); 40671 } else { 40672 dispatchTouches('pointerup'); 40673 this.dispatchEvent(new CustomEvent('interact-stopped', { 40674 detail: { 40675 source: ChangeSource.AUTOMATIC 40676 } 40677 })); 40678 document.removeEventListener('visibilitychange', onVisibilityChange); 40679 } 40680 }; 40681 const onVisibilityChange = ()=>{ 40682 let elapsed = 0; 40683 if (document.visibilityState === 'hidden') { 40684 elapsed = performance.now() - startTime; 40685 } else { 40686 startTime = performance.now() - elapsed; 40687 } 40688 }; 40689 document.addEventListener('visibilitychange', onVisibilityChange); 40690 dispatchTouches('pointerdown'); 40691 this[$cancellationSource] = ChangeSource.AUTOMATIC; 40692 requestAnimationFrame(moveTouches); 40693 } 40694 [(_a = $promptElement, _b = $promptAnimatedContainer, _c = $fingerAnimatedContainers, _d = $panElement, _e = $lastPromptOffset, _f = $promptElementVisibleTime, _g = $userHasInteracted, _h = $waitingToPromptUser, _j = $cancellationSource, _k = $controls, _l = $lastSpherical, _m = $jumpCamera, _o = $initialized, _p = $maintainThetaPhi, _q = $a11y, $syncFieldOfView)](style) { 40695 const controls = this[$controls]; 40696 const scene = this[$scene]; 40697 scene.framedFoVDeg = style[0] * 180 / Math.PI; 40698 controls.changeSource = ChangeSource.NONE; 40699 controls.setFieldOfView(scene.adjustedFoV(scene.framedFoVDeg)); 40700 this[$cancelPrompts](); 40701 } 40702 [$syncCameraOrbit](style) { 40703 const controls = this[$controls]; 40704 if (this[$maintainThetaPhi]) { 40705 const { theta, phi } = this.getCameraOrbit(); 40706 style[0] = theta; 40707 style[1] = phi; 40708 this[$maintainThetaPhi] = false; 40709 } 40710 controls.changeSource = ChangeSource.NONE; 40711 controls.setOrbit(style[0], style[1], style[2]); 40712 this[$cancelPrompts](); 40713 } 40714 [$syncMinCameraOrbit](style) { 40715 this[$controls].applyOptions({ 40716 minimumAzimuthalAngle: style[0], 40717 minimumPolarAngle: style[1], 40718 minimumRadius: style[2] 40719 }); 40720 this.jumpCameraToGoal(); 40721 } 40722 [$syncMaxCameraOrbit](style) { 40723 this[$controls].applyOptions({ 40724 maximumAzimuthalAngle: style[0], 40725 maximumPolarAngle: style[1], 40726 maximumRadius: style[2] 40727 }); 40728 this[$updateCameraForRadius](style[2]); 40729 this.jumpCameraToGoal(); 40730 } 40731 [$syncMinFieldOfView](style) { 40732 this[$controls].applyOptions({ 40733 minimumFieldOfView: style[0] * 180 / Math.PI 40734 }); 40735 this.jumpCameraToGoal(); 40736 } 40737 [$syncMaxFieldOfView](style) { 40738 const fov = this[$scene].adjustedFoV(style[0] * 180 / Math.PI); 40739 this[$controls].applyOptions({ 40740 maximumFieldOfView: fov 40741 }); 40742 this.jumpCameraToGoal(); 40743 } 40744 [$syncCameraTarget](style) { 40745 const [x, y, z] = style; 40746 if (!this[$renderer].arRenderer.isPresenting) { 40747 this[$scene].setTarget(x, y, z); 40748 } 40749 this[$controls].changeSource = ChangeSource.NONE; 40750 this[$renderer].arRenderer.updateTarget(); 40751 this[$cancelPrompts](); 40752 } 40753 [$tick](time, delta) { 40754 super[$tick](time, delta); 40755 if (this[$renderer].isPresenting || !this[$getModelIsVisible]()) { 40756 return; 40757 } 40758 const controls = this[$controls]; 40759 const scene = this[$scene]; 40760 const now = performance.now(); 40761 if (this[$waitingToPromptUser]) { 40762 if (this.loaded && now > this[$loadedTime] + this.interactionPromptThreshold) { 40763 this[$waitingToPromptUser] = false; 40764 this[$promptElementVisibleTime] = now; 40765 this[$promptElement].classList.add('visible'); 40766 } 40767 } 40768 if (isFinite(this[$promptElementVisibleTime]) && this.interactionPromptStyle === InteractionPromptStyle.WIGGLE) { 40769 const animationTime = (now - this[$promptElementVisibleTime]) / PROMPT_ANIMATION_TIME % 1; 40770 const offset = wiggle(animationTime); 40771 const opacity = fade(animationTime); 40772 this[$promptAnimatedContainer].style.opacity = `${opacity}`; 40773 if (offset !== this[$lastPromptOffset]) { 40774 const xOffset = offset * scene.width * 0.05; 40775 const deltaTheta = (offset - this[$lastPromptOffset]) * Math.PI / 16; 40776 this[$promptAnimatedContainer].style.transform = `translateX(${xOffset}px)`; 40777 controls.changeSource = ChangeSource.AUTOMATIC; 40778 controls.adjustOrbit(deltaTheta, 0, 0); 40779 this[$lastPromptOffset] = offset; 40780 } 40781 } 40782 const cameraMoved = controls.update(time, delta); 40783 const targetMoved = scene.updateTarget(delta); 40784 if (cameraMoved || targetMoved) { 40785 this[$onChange](); 40786 } 40787 } 40788 [$deferInteractionPrompt]() { 40789 this[$waitingToPromptUser] = false; 40790 this[$promptElement].classList.remove('visible'); 40791 this[$promptElementVisibleTime] = Infinity; 40792 } 40793 [$updateCameraForRadius](radius) { 40794 const maximumRadius = Math.max(this[$scene].farRadius(), radius); 40795 const near = 0; 40796 const far = Math.abs(2 * maximumRadius); 40797 this[$controls].updateNearFar(near, far); 40798 } 40799 [$updateAria]() { 40800 const { theta, phi } = this[$controls].getCameraSpherical(this[$lastSpherical]); 40801 const azimuthalQuadrant = (4 + Math.floor((theta % TAU + QUARTER_PI) / HALF_PI)) % 4; 40802 const polarTrient = Math.floor(phi / THIRD_PI); 40803 const azimuthalQuadrantLabel = AZIMUTHAL_QUADRANT_LABELS[azimuthalQuadrant]; 40804 const polarTrientLabel = POLAR_TRIENT_LABELS[polarTrient]; 40805 const position = `${polarTrientLabel}${azimuthalQuadrantLabel}`; 40806 const key = position; 40807 if (key in this[$a11y]) { 40808 this[$updateStatus](this[$a11y][key]); 40809 } else { 40810 this[$updateStatus](`View from stage ${position}`); 40811 } 40812 } 40813 get [$ariaLabel]() { 40814 let interactionPrompt = INTERACTION_PROMPT; 40815 if ('interaction-prompt' in this[$a11y]) { 40816 interactionPrompt = `. ${this[$a11y]['interaction-prompt']}`; 40817 } 40818 return super[$ariaLabel].replace(/\.$/, '') + (this.cameraControls ? interactionPrompt : ''); 40819 } 40820 async [$onResize](event) { 40821 const controls = this[$controls]; 40822 const scene = this[$scene]; 40823 const oldFramedFoV = scene.adjustedFoV(scene.framedFoVDeg); 40824 super[$onResize](event); 40825 const fovRatio = scene.adjustedFoV(scene.framedFoVDeg) / oldFramedFoV; 40826 const fov = controls.getFieldOfView() * (isFinite(fovRatio) ? fovRatio : 1); 40827 controls.updateAspect(this[$scene].aspect); 40828 this.requestUpdate('maxFieldOfView', this.maxFieldOfView); 40829 await this.updateComplete; 40830 this[$controls].setFieldOfView(fov); 40831 this.jumpCameraToGoal(); 40832 } 40833 [$onModelLoad]() { 40834 super[$onModelLoad](); 40835 if (this[$initialized]) { 40836 this[$maintainThetaPhi] = true; 40837 } else { 40838 this[$initialized] = true; 40839 } 40840 this.requestUpdate('maxFieldOfView', this.maxFieldOfView); 40841 this.requestUpdate('fieldOfView', this.fieldOfView); 40842 this.requestUpdate('minCameraOrbit', this.minCameraOrbit); 40843 this.requestUpdate('maxCameraOrbit', this.maxCameraOrbit); 40844 this.requestUpdate('cameraOrbit', this.cameraOrbit); 40845 this.requestUpdate('cameraTarget', this.cameraTarget); 40846 this.jumpCameraToGoal(); 40847 } 40848 [(_r = $cancelPrompts, _s = $onChange, _t = $onPointerChange, $updateA11y)]() { 40849 if (typeof this.a11y === 'string') { 40850 if (this.a11y.startsWith('{')) { 40851 try { 40852 this[$a11y] = JSON.parse(this.a11y); 40853 } catch (error) { 40854 console.warn('Error parsing a11y JSON:', error); 40855 } 40856 } else if (this.a11y.length > 0) { 40857 console.warn('Error not supported format, should be a JSON string:', this.a11y); 40858 } else { 40859 this[$a11y] = {}; 40860 } 40861 } else if (typeof this.a11y === 'object' && this.a11y != null) { 40862 this[$a11y] = Object.assign({}, this.a11y); 40863 } else { 40864 this[$a11y] = {}; 40865 } 40866 this[$userInputElement].setAttribute('aria-label', this[$ariaLabel]); 40867 } 40868 constructor(){ 40869 super(...arguments); 40870 this.cameraControls = false; 40871 this.cameraOrbit = DEFAULT_CAMERA_ORBIT; 40872 this.cameraTarget = DEFAULT_CAMERA_TARGET; 40873 this.fieldOfView = DEFAULT_FIELD_OF_VIEW; 40874 this.minCameraOrbit = 'auto'; 40875 this.maxCameraOrbit = 'auto'; 40876 this.minFieldOfView = 'auto'; 40877 this.maxFieldOfView = 'auto'; 40878 this.interactionPromptThreshold = DEFAULT_INTERACTION_PROMPT_THRESHOLD; 40879 this.interactionPrompt = InteractionPromptStrategy.AUTO; 40880 this.interactionPromptStyle = InteractionPromptStyle.WIGGLE; 40881 this.orbitSensitivity = 1; 40882 this.zoomSensitivity = 1; 40883 this.panSensitivity = 1; 40884 this.touchAction = TouchAction.NONE; 40885 this.disableZoom = false;
vendor: 7,563 bytes, lines 40886-41112
40886 this.disablePan = false; 40887 this.disableTap = false; 40888 this.interpolationDecay = DECAY_MILLISECONDS; 40889 this.a11y = null; 40890 this[_a] = this.shadowRoot.querySelector('.interaction-prompt'); 40891 this[_b] = this.shadowRoot.querySelector('#prompt'); 40892 this[_c] = [ 40893 this.shadowRoot.querySelector('#finger0'), 40894 this.shadowRoot.querySelector('#finger1') 40895 ]; 40896 this[_d] = this.shadowRoot.querySelector('.pan-target'); 40897 this[_e] = 0; 40898 this[_f] = Infinity; 40899 this[_g] = false; 40900 this[_h] = false; 40901 this[_j] = ChangeSource.AUTOMATIC; 40902 this[_k] = new SmoothControls(this[$scene].camera, this[$userInputElement], this[$scene]); 40903 this[_l] = new Spherical(); 40904 this[_m] = false; 40905 this[_o] = false; 40906 this[_p] = false; 40907 this[_q] = {}; 40908 this[_r] = ()=>{ 40909 const source = this[$controls].changeSource; 40910 this[$cancellationSource] = source; 40911 if (source === ChangeSource.USER_INTERACTION) { 40912 this[$userHasInteracted] = true; 40913 this[$deferInteractionPrompt](); 40914 } 40915 }; 40916 this[_s] = ()=>{ 40917 this[$updateAria](); 40918 this[$needsRender](); 40919 const source = this[$controls].changeSource; 40920 this.dispatchEvent(new CustomEvent('camera-change', { 40921 detail: { 40922 source 40923 } 40924 })); 40925 }; 40926 this[_t] = (event)=>{ 40927 this[$container].classList.toggle('pointer-tumbling', event.type === 'pointer-change-start'); 40928 }; 40929 } 40930 } 40931 __decorate$6([ 40932 n$2({ 40933 type: Boolean, 40934 attribute: 'camera-controls' 40935 }) 40936 ], ControlsModelViewerElement.prototype, "cameraControls", void 0); 40937 __decorate$6([ 40938 style({ 40939 intrinsics: cameraOrbitIntrinsics, 40940 observeEffects: true, 40941 updateHandler: $syncCameraOrbit 40942 }), 40943 n$2({ 40944 type: String, 40945 attribute: 'camera-orbit', 40946 hasChanged: ()=>true 40947 }) 40948 ], ControlsModelViewerElement.prototype, "cameraOrbit", void 0); 40949 __decorate$6([ 40950 style({ 40951 intrinsics: cameraTargetIntrinsics, 40952 observeEffects: true, 40953 updateHandler: $syncCameraTarget 40954 }), 40955 n$2({ 40956 type: String, 40957 attribute: 'camera-target', 40958 hasChanged: ()=>true 40959 }) 40960 ], ControlsModelViewerElement.prototype, "cameraTarget", void 0); 40961 __decorate$6([ 40962 style({ 40963 intrinsics: fieldOfViewIntrinsics, 40964 observeEffects: true, 40965 updateHandler: $syncFieldOfView 40966 }), 40967 n$2({ 40968 type: String, 40969 attribute: 'field-of-view', 40970 hasChanged: ()=>true 40971 }) 40972 ], ControlsModelViewerElement.prototype, "fieldOfView", void 0); 40973 __decorate$6([ 40974 style({ 40975 intrinsics: minCameraOrbitIntrinsics, 40976 updateHandler: $syncMinCameraOrbit 40977 }), 40978 n$2({ 40979 type: String, 40980 attribute: 'min-camera-orbit', 40981 hasChanged: ()=>true 40982 }) 40983 ], ControlsModelViewerElement.prototype, "minCameraOrbit", void 0); 40984 __decorate$6([ 40985 style({ 40986 intrinsics: maxCameraOrbitIntrinsics, 40987 updateHandler: $syncMaxCameraOrbit 40988 }), 40989 n$2({ 40990 type: String, 40991 attribute: 'max-camera-orbit', 40992 hasChanged: ()=>true 40993 }) 40994 ], ControlsModelViewerElement.prototype, "maxCameraOrbit", void 0); 40995 __decorate$6([ 40996 style({ 40997 intrinsics: minFieldOfViewIntrinsics, 40998 updateHandler: $syncMinFieldOfView 40999 }), 41000 n$2({ 41001 type: String, 41002 attribute: 'min-field-of-view', 41003 hasChanged: ()=>true 41004 }) 41005 ], ControlsModelViewerElement.prototype, "minFieldOfView", void 0); 41006 __decorate$6([ 41007 style({ 41008 intrinsics: fieldOfViewIntrinsics, 41009 updateHandler: $syncMaxFieldOfView 41010 }), 41011 n$2({ 41012 type: String, 41013 attribute: 'max-field-of-view', 41014 hasChanged: ()=>true 41015 }) 41016 ], ControlsModelViewerElement.prototype, "maxFieldOfView", void 0); 41017 __decorate$6([ 41018 n$2({ 41019 type: Number, 41020 attribute: 'interaction-prompt-threshold' 41021 }) 41022 ], ControlsModelViewerElement.prototype, "interactionPromptThreshold", void 0); 41023 __decorate$6([ 41024 n$2({ 41025 type: String, 41026 attribute: 'interaction-prompt' 41027 }) 41028 ], ControlsModelViewerElement.prototype, "interactionPrompt", void 0); 41029 __decorate$6([ 41030 n$2({ 41031 type: String, 41032 attribute: 'interaction-prompt-style' 41033 }) 41034 ], ControlsModelViewerElement.prototype, "interactionPromptStyle", void 0); 41035 __decorate$6([ 41036 n$2({ 41037 type: Number, 41038 attribute: 'orbit-sensitivity' 41039 }) 41040 ], ControlsModelViewerElement.prototype, "orbitSensitivity", void 0); 41041 __decorate$6([ 41042 n$2({ 41043 type: Number, 41044 attribute: 'zoom-sensitivity' 41045 }) 41046 ], ControlsModelViewerElement.prototype, "zoomSensitivity", void 0); 41047 __decorate$6([ 41048 n$2({ 41049 type: Number, 41050 attribute: 'pan-sensitivity' 41051 }) 41052 ], ControlsModelViewerElement.prototype, "panSensitivity", void 0); 41053 __decorate$6([ 41054 n$2({ 41055 type: String, 41056 attribute: 'touch-action' 41057 }) 41058 ], ControlsModelViewerElement.prototype, "touchAction", void 0); 41059 __decorate$6([ 41060 n$2({ 41061 type: Boolean, 41062 attribute: 'disable-zoom' 41063 }) 41064 ], ControlsModelViewerElement.prototype, "disableZoom", void 0); 41065 __decorate$6([ 41066 n$2({ 41067 type: Boolean, 41068 attribute: 'disable-pan' 41069 }) 41070 ], ControlsModelViewerElement.prototype, "disablePan", void 0); 41071 __decorate$6([ 41072 n$2({ 41073 type: Boolean, 41074 attribute: 'disable-tap' 41075 }) 41076 ], ControlsModelViewerElement.prototype, "disableTap", void 0); 41077 __decorate$6([ 41078 n$2({ 41079 type: Number, 41080 attribute: 'interpolation-decay' 41081 }) 41082 ], ControlsModelViewerElement.prototype, "interpolationDecay", void 0); 41083 __decorate$6([ 41084 n$2() 41085 ], ControlsModelViewerElement.prototype, "a11y", void 0); 41086 return ControlsModelViewerElement; 41087 }; 41088 41089 const PAN_SENSITIVITY = 0.018; 41090 const TAP_DISTANCE = 2; 41091 const TAP_MS = 300; 41092 const vector2 = new Vector2(); 41093 const vector3$2 = new Vector3(); 41094 const DEFAULT_OPTIONS = Object.freeze({ 41095 minimumRadius: 0, 41096 maximumRadius: Infinity, 41097 minimumPolarAngle: 0, 41098 maximumPolarAngle: Math.PI, 41099 minimumAzimuthalAngle: -Infinity, 41100 maximumAzimuthalAngle: Infinity, 41101 minimumFieldOfView: 10, 41102 maximumFieldOfView: 45, 41103 touchAction: 'none' 41104 }); 41105 const KEYBOARD_ORBIT_INCREMENT = Math.PI / 8; 41106 const ZOOM_SENSITIVITY = 0.04; 41107 const PAN_KEY_INCREMENT = 10; 41108 const ChangeSource = { 41109 USER_INTERACTION: 'user-interaction', 41110 NONE: 'none', 41111 AUTOMATIC: 'automatic' 41112 };
vendor: 9,631 bytes, lines 41113-41317
41113 class SmoothControls extends EventDispatcher { 41114 get interactionEnabled() { 41115 return this._interactionEnabled; 41116 } 41117 enableInteraction() { 41118 if (this._interactionEnabled === false) { 41119 const { element } = this; 41120 element.addEventListener('pointerdown', this.onPointerDown); 41121 element.addEventListener('pointercancel', this.onPointerUp); 41122 if (!this._disableZoom) { 41123 element.addEventListener('wheel', this.onWheel); 41124 } 41125 element.addEventListener('keydown', this.onKeyDown); 41126 element.addEventListener('touchmove', ()=>{}, { 41127 passive: false 41128 }); 41129 element.addEventListener('contextmenu', this.onContext); 41130 this.element.style.cursor = 'grab'; 41131 this._interactionEnabled = true; 41132 this.updateTouchActionStyle(); 41133 } 41134 } 41135 disableInteraction() { 41136 if (this._interactionEnabled === true) { 41137 const { element } = this; 41138 element.removeEventListener('pointerdown', this.onPointerDown); 41139 element.removeEventListener('pointermove', this.onPointerMove); 41140 element.removeEventListener('pointerup', this.onPointerUp); 41141 element.removeEventListener('pointercancel', this.onPointerUp); 41142 element.removeEventListener('wheel', this.onWheel); 41143 element.removeEventListener('keydown', this.onKeyDown); 41144 element.removeEventListener('contextmenu', this.onContext); 41145 element.style.cursor = ''; 41146 this.touchMode = null; 41147 this._interactionEnabled = false; 41148 this.updateTouchActionStyle(); 41149 } 41150 } 41151 get options() { 41152 return this._options; 41153 } 41154 set disableZoom(disable) { 41155 if (this._disableZoom != disable) { 41156 this._disableZoom = disable; 41157 if (disable === true) { 41158 this.element.removeEventListener('wheel', this.onWheel); 41159 } else { 41160 this.element.addEventListener('wheel', this.onWheel); 41161 } 41162 this.updateTouchActionStyle(); 41163 } 41164 } 41165 getCameraSpherical(target = new Spherical()) { 41166 return target.copy(this.spherical); 41167 } 41168 getFieldOfView() { 41169 return this.camera.fov; 41170 } 41171 applyOptions(_options) { 41172 Object.assign(this._options, _options); 41173 this.setOrbit(); 41174 this.setFieldOfView(Math.exp(this.goalLogFov)); 41175 } 41176 updateNearFar(nearPlane, farPlane) { 41177 this.camera.far = farPlane === 0 ? 2 : farPlane; 41178 this.camera.near = Math.max(nearPlane, this.camera.far / 1000); 41179 this.camera.updateProjectionMatrix(); 41180 } 41181 updateAspect(aspect) { 41182 this.camera.aspect = aspect; 41183 this.camera.updateProjectionMatrix(); 41184 } 41185 setOrbit(goalTheta = this.goalSpherical.theta, goalPhi = this.goalSpherical.phi, goalRadius = this.goalSpherical.radius) { 41186 const { minimumAzimuthalAngle, maximumAzimuthalAngle, minimumPolarAngle, maximumPolarAngle, minimumRadius, maximumRadius } = this._options; 41187 const { theta, phi, radius } = this.goalSpherical; 41188 const nextTheta = clamp(goalTheta, minimumAzimuthalAngle, maximumAzimuthalAngle); 41189 if (!isFinite(minimumAzimuthalAngle) && !isFinite(maximumAzimuthalAngle)) { 41190 this.spherical.theta = this.wrapAngle(this.spherical.theta - nextTheta) + nextTheta; 41191 } 41192 const nextPhi = clamp(goalPhi, minimumPolarAngle, maximumPolarAngle); 41193 const nextRadius = clamp(goalRadius, minimumRadius, maximumRadius); 41194 if (nextTheta === theta && nextPhi === phi && nextRadius === radius) { 41195 return false; 41196 } 41197 if (!isFinite(nextTheta) || !isFinite(nextPhi) || !isFinite(nextRadius)) { 41198 return false; 41199 } 41200 this.goalSpherical.theta = nextTheta; 41201 this.goalSpherical.phi = nextPhi; 41202 this.goalSpherical.radius = nextRadius; 41203 this.goalSpherical.makeSafe(); 41204 return true; 41205 } 41206 setRadius(radius) { 41207 this.goalSpherical.radius = radius; 41208 this.setOrbit(); 41209 } 41210 setFieldOfView(fov) { 41211 const { minimumFieldOfView, maximumFieldOfView } = this._options; 41212 fov = clamp(fov, minimumFieldOfView, maximumFieldOfView); 41213 this.goalLogFov = Math.log(fov); 41214 } 41215 setDamperDecayTime(decayMilliseconds) { 41216 this.thetaDamper.setDecayTime(decayMilliseconds); 41217 this.phiDamper.setDecayTime(decayMilliseconds); 41218 this.radiusDamper.setDecayTime(decayMilliseconds); 41219 this.fovDamper.setDecayTime(decayMilliseconds); 41220 } 41221 adjustOrbit(deltaTheta, deltaPhi, deltaZoom) { 41222 const { theta, phi, radius } = this.goalSpherical; 41223 const { minimumRadius, maximumRadius, minimumFieldOfView, maximumFieldOfView } = this._options; 41224 const dTheta = this.spherical.theta - theta; 41225 const dThetaLimit = Math.PI - 0.001; 41226 const goalTheta = theta - clamp(deltaTheta, -dThetaLimit - dTheta, dThetaLimit - dTheta); 41227 const goalPhi = phi - deltaPhi; 41228 const deltaRatio = deltaZoom === 0 ? 0 : ((deltaZoom > 0 ? maximumRadius : minimumRadius) - radius) / (Math.log(deltaZoom > 0 ? maximumFieldOfView : minimumFieldOfView) - this.goalLogFov); 41229 const goalRadius = radius + deltaZoom * (isFinite(deltaRatio) ? deltaRatio : (maximumRadius - minimumRadius) * 2); 41230 this.setOrbit(goalTheta, goalPhi, goalRadius); 41231 if (deltaZoom !== 0) { 41232 const goalLogFov = this.goalLogFov + deltaZoom; 41233 this.setFieldOfView(Math.exp(goalLogFov)); 41234 } 41235 } 41236 jumpToGoal() { 41237 this.update(0, SETTLING_TIME); 41238 } 41239 update(_time, delta) { 41240 if (this.isStationary()) { 41241 return false; 41242 } 41243 const { maximumPolarAngle, maximumRadius } = this._options; 41244 const dTheta = this.spherical.theta - this.goalSpherical.theta; 41245 if (Math.abs(dTheta) > Math.PI && !isFinite(this._options.minimumAzimuthalAngle) && !isFinite(this._options.maximumAzimuthalAngle)) { 41246 this.spherical.theta -= Math.sign(dTheta) * 2 * Math.PI; 41247 } 41248 this.spherical.theta = this.thetaDamper.update(this.spherical.theta, this.goalSpherical.theta, delta, Math.PI); 41249 this.spherical.phi = this.phiDamper.update(this.spherical.phi, this.goalSpherical.phi, delta, maximumPolarAngle); 41250 this.spherical.radius = this.radiusDamper.update(this.spherical.radius, this.goalSpherical.radius, delta, maximumRadius); 41251 this.logFov = this.fovDamper.update(this.logFov, this.goalLogFov, delta, 1); 41252 this.moveCamera(); 41253 return true; 41254 } 41255 updateTouchActionStyle() { 41256 const { style } = this.element; 41257 if (this._interactionEnabled) { 41258 const { touchAction } = this._options; 41259 if (this._disableZoom && touchAction !== 'none') { 41260 style.touchAction = 'manipulation'; 41261 } else { 41262 style.touchAction = touchAction; 41263 } 41264 } else { 41265 style.touchAction = ''; 41266 } 41267 } 41268 isStationary() { 41269 return this.goalSpherical.theta === this.spherical.theta && this.goalSpherical.phi === this.spherical.phi && this.goalSpherical.radius === this.spherical.radius && this.goalLogFov === this.logFov; 41270 } 41271 moveCamera() { 41272 this.spherical.makeSafe(); 41273 this.camera.position.setFromSpherical(this.spherical); 41274 this.camera.setRotationFromEuler(new Euler(this.spherical.phi - Math.PI / 2, this.spherical.theta, 0, 'YXZ')); 41275 if (this.camera.fov !== Math.exp(this.logFov)) { 41276 this.camera.fov = Math.exp(this.logFov); 41277 this.camera.updateProjectionMatrix(); 41278 } 41279 } 41280 userAdjustOrbit(deltaTheta, deltaPhi, deltaZoom) { 41281 this.adjustOrbit(deltaTheta * this.orbitSensitivity * this.inputSensitivity, deltaPhi * this.orbitSensitivity * this.inputSensitivity, deltaZoom * this.inputSensitivity); 41282 } 41283 wrapAngle(radians) { 41284 const normalized = (radians + Math.PI) / (2 * Math.PI); 41285 const wrapped = normalized - Math.floor(normalized); 41286 return wrapped * 2 * Math.PI - Math.PI; 41287 } 41288 pixelLengthToSphericalAngle(pixelLength) { 41289 return 2 * Math.PI * pixelLength / this.scene.height; 41290 } 41291 twoTouchDistance(touchOne, touchTwo) { 41292 const { clientX: xOne, clientY: yOne } = touchOne; 41293 const { clientX: xTwo, clientY: yTwo } = touchTwo; 41294 const xDelta = xTwo - xOne; 41295 const yDelta = yTwo - yOne; 41296 return Math.sqrt(xDelta * xDelta + yDelta * yDelta); 41297 } 41298 handleSinglePointerMove(dx, dy) { 41299 const deltaTheta = this.pixelLengthToSphericalAngle(dx); 41300 const deltaPhi = this.pixelLengthToSphericalAngle(dy); 41301 if (this.isUserPointing === false) { 41302 this.isUserPointing = true; 41303 this.dispatchEvent({ 41304 type: 'pointer-change-start' 41305 }); 41306 } 41307 this.userAdjustOrbit(deltaTheta, deltaPhi, 0); 41308 } 41309 initializePan() { 41310 const { theta, phi } = this.spherical; 41311 const psi = theta - this.scene.yaw; 41312 this.panPerPixel = PAN_SENSITIVITY * this.panSensitivity / this.scene.height; 41313 this.panProjection.set(-Math.cos(psi), -Math.cos(phi) * Math.sin(psi), 0, 0, Math.sin(phi), 0, Math.sin(psi), -Math.cos(phi) * Math.cos(psi), 0); 41314 } 41315 movePan(dx, dy) { 41316 const { scene } = this; 41317 const dxy = vector3$2.set(dx, dy, 0).multiplyScalar(this.inputSensitivity);
vendor: 5,343 bytes, lines 41318-41448
41318 const metersPerPixel = this.spherical.radius * Math.exp(this.logFov) * this.panPerPixel; 41319 dxy.multiplyScalar(metersPerPixel); 41320 const target = scene.getTarget(); 41321 target.add(dxy.applyMatrix3(this.panProjection)); 41322 scene.boundingSphere.clampPoint(target, target); 41323 scene.setTarget(target.x, target.y, target.z); 41324 } 41325 recenter(pointer) { 41326 if (performance.now() > this.startTime + TAP_MS || Math.abs(pointer.clientX - this.startPointerPosition.clientX) > TAP_DISTANCE || Math.abs(pointer.clientY - this.startPointerPosition.clientY) > TAP_DISTANCE) { 41327 return; 41328 } 41329 const { scene } = this; 41330 const hit = scene.positionAndNormalFromPoint(scene.getNDC(pointer.clientX, pointer.clientY)); 41331 if (hit == null) { 41332 const { cameraTarget } = scene.element; 41333 scene.element.cameraTarget = ''; 41334 scene.element.cameraTarget = cameraTarget; 41335 this.userAdjustOrbit(0, 0, 1); 41336 } else { 41337 scene.target.worldToLocal(hit.position); 41338 scene.setTarget(hit.position.x, hit.position.y, hit.position.z); 41339 } 41340 } 41341 resetRadius() { 41342 const { scene } = this; 41343 const hit = scene.positionAndNormalFromPoint(vector2.set(0, 0)); 41344 if (hit == null) { 41345 return; 41346 } 41347 scene.target.worldToLocal(hit.position); 41348 const goalTarget = scene.getTarget(); 41349 const { theta, phi } = this.spherical; 41350 const psi = theta - scene.yaw; 41351 const n = vector3$2.set(Math.sin(phi) * Math.sin(psi), Math.cos(phi), Math.sin(phi) * Math.cos(psi)); 41352 const dr = n.dot(hit.position.sub(goalTarget)); 41353 goalTarget.add(n.multiplyScalar(dr)); 41354 scene.setTarget(goalTarget.x, goalTarget.y, goalTarget.z); 41355 this.setOrbit(undefined, undefined, this.goalSpherical.radius - dr); 41356 } 41357 onTouchChange(event) { 41358 if (this.pointers.length === 1) { 41359 this.touchMode = this.touchModeRotate; 41360 } else { 41361 if (this._disableZoom) { 41362 this.touchMode = null; 41363 this.element.removeEventListener('touchmove', this.disableScroll); 41364 return; 41365 } 41366 this.touchMode = this.touchDecided && this.touchMode === null ? null : this.touchModeZoom; 41367 this.touchDecided = true; 41368 this.element.addEventListener('touchmove', this.disableScroll, { 41369 passive: false 41370 }); 41371 this.lastSeparation = this.twoTouchDistance(this.pointers[0], this.pointers[1]); 41372 if (this.enablePan && this.touchMode != null) { 41373 this.initializePan(); 41374 if (!event.altKey) { 41375 this.scene.element[$panElement].style.opacity = 1; 41376 } 41377 } 41378 } 41379 } 41380 onMouseDown(event) { 41381 this.panPerPixel = 0; 41382 if (this.enablePan && (event.button === 2 || event.ctrlKey || event.metaKey || event.shiftKey)) { 41383 this.initializePan(); 41384 this.scene.element[$panElement].style.opacity = 1; 41385 } 41386 this.element.style.cursor = 'grabbing'; 41387 } 41388 orbitZoomKeyCodeHandler(event) { 41389 let relevantKey = true; 41390 switch(event.key){ 41391 case 'PageUp': 41392 this.userAdjustOrbit(0, 0, ZOOM_SENSITIVITY * this.zoomSensitivity); 41393 break; 41394 case 'PageDown': 41395 this.userAdjustOrbit(0, 0, -1 * ZOOM_SENSITIVITY * this.zoomSensitivity); 41396 break; 41397 case 'ArrowUp': 41398 this.userAdjustOrbit(0, -KEYBOARD_ORBIT_INCREMENT, 0); 41399 break; 41400 case 'ArrowDown': 41401 this.userAdjustOrbit(0, KEYBOARD_ORBIT_INCREMENT, 0); 41402 break; 41403 case 'ArrowLeft': 41404 this.userAdjustOrbit(-KEYBOARD_ORBIT_INCREMENT, 0, 0); 41405 break; 41406 case 'ArrowRight': 41407 this.userAdjustOrbit(KEYBOARD_ORBIT_INCREMENT, 0, 0); 41408 break; 41409 default: 41410 relevantKey = false; 41411 break; 41412 } 41413 return relevantKey; 41414 } 41415 panKeyCodeHandler(event) { 41416 this.initializePan(); 41417 let relevantKey = true; 41418 switch(event.key){ 41419 case 'ArrowUp': 41420 this.movePan(0, -1 * PAN_KEY_INCREMENT); 41421 break; 41422 case 'ArrowDown': 41423 this.movePan(0, PAN_KEY_INCREMENT); 41424 break; 41425 case 'ArrowLeft': 41426 this.movePan(-1 * PAN_KEY_INCREMENT, 0); 41427 break; 41428 case 'ArrowRight': 41429 this.movePan(PAN_KEY_INCREMENT, 0); 41430 break; 41431 default: 41432 relevantKey = false; 41433 break; 41434 } 41435 return relevantKey; 41436 } 41437 constructor(camera, element, scene){ 41438 super(); 41439 this.camera = camera; 41440 this.element = element; 41441 this.scene = scene; 41442 this.orbitSensitivity = 1; 41443 this.zoomSensitivity = 1; 41444 this.panSensitivity = 1; 41445 this.inputSensitivity = 1; 41446 this.changeSource = ChangeSource.NONE; 41447 this._interactionEnabled = false; 41448 this._disableZoom = false;
vendor: 11,686 bytes, lines 41449-41737
41449 this.isUserPointing = false; 41450 this.enablePan = true; 41451 this.enableTap = true; 41452 this.panProjection = new Matrix3(); 41453 this.panPerPixel = 0; 41454 this.spherical = new Spherical(); 41455 this.goalSpherical = new Spherical(); 41456 this.thetaDamper = new Damper(); 41457 this.phiDamper = new Damper(); 41458 this.radiusDamper = new Damper(); 41459 this.logFov = Math.log(DEFAULT_OPTIONS.maximumFieldOfView); 41460 this.goalLogFov = this.logFov; 41461 this.fovDamper = new Damper(); 41462 this.touchMode = null; 41463 this.pointers = []; 41464 this.startTime = 0; 41465 this.startPointerPosition = { 41466 clientX: 0, 41467 clientY: 0 41468 }; 41469 this.lastSeparation = 0; 41470 this.touchDecided = false; 41471 this.onContext = (event)=>{ 41472 if (this.enablePan) { 41473 event.preventDefault(); 41474 } else { 41475 for (const pointer of this.pointers){ 41476 this.onPointerUp(new PointerEvent('pointercancel', Object.assign(Object.assign({}, this.startPointerPosition), { 41477 pointerId: pointer.id 41478 }))); 41479 } 41480 } 41481 }; 41482 this.touchModeZoom = (dx, dy)=>{ 41483 if (!this._disableZoom) { 41484 const touchDistance = this.twoTouchDistance(this.pointers[0], this.pointers[1]); 41485 const deltaZoom = ZOOM_SENSITIVITY * this.zoomSensitivity * (this.lastSeparation - touchDistance) * 50 / this.scene.height; 41486 this.lastSeparation = touchDistance; 41487 this.userAdjustOrbit(0, 0, deltaZoom); 41488 } 41489 if (this.panPerPixel > 0) { 41490 this.movePan(dx, dy); 41491 } 41492 }; 41493 this.disableScroll = (event)=>{ 41494 event.preventDefault(); 41495 }; 41496 this.touchModeRotate = (dx, dy)=>{ 41497 const { touchAction } = this._options; 41498 if (!this.touchDecided && touchAction !== 'none') { 41499 this.touchDecided = true; 41500 const dxMag = Math.abs(dx); 41501 const dyMag = Math.abs(dy); 41502 if (this.changeSource === ChangeSource.USER_INTERACTION && (touchAction === 'pan-y' && dyMag > dxMag || touchAction === 'pan-x' && dxMag > dyMag)) { 41503 this.touchMode = null; 41504 return; 41505 } else { 41506 this.element.addEventListener('touchmove', this.disableScroll, { 41507 passive: false 41508 }); 41509 } 41510 } 41511 this.handleSinglePointerMove(dx, dy); 41512 }; 41513 this.onPointerDown = (event)=>{ 41514 if (this.pointers.length > 2) { 41515 return; 41516 } 41517 const { element } = this; 41518 if (this.pointers.length === 0) { 41519 element.addEventListener('pointermove', this.onPointerMove); 41520 element.addEventListener('pointerup', this.onPointerUp); 41521 this.touchMode = null; 41522 this.touchDecided = false; 41523 this.startPointerPosition.clientX = event.clientX; 41524 this.startPointerPosition.clientY = event.clientY; 41525 this.startTime = performance.now(); 41526 } 41527 try { 41528 element.setPointerCapture(event.pointerId); 41529 } catch (_a) {} 41530 this.pointers.push({ 41531 clientX: event.clientX, 41532 clientY: event.clientY, 41533 id: event.pointerId 41534 }); 41535 this.isUserPointing = false; 41536 if (event.pointerType === 'touch') { 41537 this.changeSource = event.altKey ? ChangeSource.AUTOMATIC : ChangeSource.USER_INTERACTION; 41538 this.onTouchChange(event); 41539 } else { 41540 this.changeSource = ChangeSource.USER_INTERACTION; 41541 this.onMouseDown(event); 41542 } 41543 if (this.changeSource === ChangeSource.USER_INTERACTION) { 41544 this.dispatchEvent({ 41545 type: 'user-interaction' 41546 }); 41547 } 41548 }; 41549 this.onPointerMove = (event)=>{ 41550 const pointer = this.pointers.find((pointer)=>pointer.id === event.pointerId); 41551 if (pointer == null) { 41552 return; 41553 } 41554 if (event.pointerType === 'mouse' && event.buttons === 0) { 41555 this.onPointerUp(event); 41556 return; 41557 } 41558 const numTouches = this.pointers.length; 41559 const dx = (event.clientX - pointer.clientX) / numTouches; 41560 const dy = (event.clientY - pointer.clientY) / numTouches; 41561 if (dx === 0 && dy === 0) { 41562 return; 41563 } 41564 pointer.clientX = event.clientX; 41565 pointer.clientY = event.clientY; 41566 if (event.pointerType === 'touch') { 41567 this.changeSource = event.altKey ? ChangeSource.AUTOMATIC : ChangeSource.USER_INTERACTION; 41568 if (this.touchMode !== null) { 41569 this.touchMode(dx, dy); 41570 } 41571 } else { 41572 this.changeSource = ChangeSource.USER_INTERACTION; 41573 if (this.panPerPixel > 0) { 41574 this.movePan(dx, dy); 41575 } else { 41576 this.handleSinglePointerMove(dx, dy); 41577 } 41578 } 41579 }; 41580 this.onPointerUp = (event)=>{ 41581 const { element } = this; 41582 const index = this.pointers.findIndex((pointer)=>pointer.id === event.pointerId); 41583 if (index !== -1) { 41584 this.pointers.splice(index, 1); 41585 } 41586 if (this.panPerPixel > 0 && !event.altKey) { 41587 this.resetRadius(); 41588 } 41589 if (this.pointers.length === 0) { 41590 element.removeEventListener('pointermove', this.onPointerMove); 41591 element.removeEventListener('pointerup', this.onPointerUp); 41592 element.removeEventListener('touchmove', this.disableScroll); 41593 if (this.enablePan && this.enableTap) { 41594 this.recenter(event); 41595 } 41596 } else if (this.touchMode !== null) { 41597 this.onTouchChange(event); 41598 } 41599 this.scene.element[$panElement].style.opacity = 0; 41600 element.style.cursor = 'grab'; 41601 this.panPerPixel = 0; 41602 if (this.isUserPointing) { 41603 this.dispatchEvent({ 41604 type: 'pointer-change-end' 41605 }); 41606 } 41607 }; 41608 this.onWheel = (event)=>{ 41609 this.changeSource = ChangeSource.USER_INTERACTION; 41610 const deltaZoom = event.deltaY * (event.deltaMode == 1 ? 18 : 1) * ZOOM_SENSITIVITY * this.zoomSensitivity / 30; 41611 this.userAdjustOrbit(0, 0, deltaZoom); 41612 event.preventDefault(); 41613 this.dispatchEvent({ 41614 type: 'user-interaction' 41615 }); 41616 }; 41617 this.onKeyDown = (event)=>{ 41618 const { changeSource } = this; 41619 this.changeSource = ChangeSource.USER_INTERACTION; 41620 const relevantKey = event.shiftKey && this.enablePan ? this.panKeyCodeHandler(event) : this.orbitZoomKeyCodeHandler(event); 41621 if (relevantKey) { 41622 event.preventDefault(); 41623 this.dispatchEvent({ 41624 type: 'user-interaction' 41625 }); 41626 } else { 41627 this.changeSource = changeSource; 41628 } 41629 }; 41630 this._options = Object.assign({}, DEFAULT_OPTIONS); 41631 this.setOrbit(0, Math.PI / 2, 1); 41632 this.setFieldOfView(100); 41633 this.jumpToGoal(); 41634 } 41635 } 41636 41637 const INIT_FRAMES = 30; 41638 const AR_SHADOW_INTENSITY = 0.8; 41639 const ROTATION_RATE = 1.5; 41640 const HIT_ANGLE_DEG = 20; 41641 const SCALE_SNAP = 0.2; 41642 const MIN_VIEWPORT_SCALE = 0.25; 41643 const MAX_DISTANCE = 10; 41644 const DECAY = 150; 41645 const MAX_LINE_LENGTH = 5; 41646 const BOX_SIZE = 0.1; 41647 const ARStatus = { 41648 NOT_PRESENTING: 'not-presenting', 41649 SESSION_STARTED: 'session-started', 41650 OBJECT_PLACED: 'object-placed', 41651 FAILED: 'failed' 41652 }; 41653 const ARTracking = { 41654 TRACKING: 'tracking', 41655 NOT_TRACKING: 'not-tracking' 41656 }; 41657 const vector3$1 = new Vector3(); 41658 const quaternion = new Quaternion(); 41659 const matrix4 = new Matrix4(); 41660 const hitPosition = new Vector3(); 41661 const camera = new PerspectiveCamera(45, 1, 0.1, 100); 41662 const lineGeometry = new BufferGeometry().setFromPoints([ 41663 new Vector3(0, 0, 0), 41664 new Vector3(0, 0, -1) 41665 ]); 41666 const boxGeometry = new BoxGeometry(); 41667 class ARRenderer extends EventDispatcher { 41668 async resolveARSession() { 41669 assertIsArCandidate(); 41670 const session = await navigator.xr.requestSession('immersive-ar', { 41671 requiredFeatures: [], 41672 optionalFeatures: [ 41673 'hit-test', 41674 'dom-overlay', 41675 'light-estimation' 41676 ], 41677 domOverlay: this.overlay ? { 41678 root: this.overlay 41679 } : undefined 41680 }); 41681 this.threeRenderer.xr.setReferenceSpaceType('local'); 41682 await this.threeRenderer.xr.setSession(session); 41683 this.threeRenderer.xr.cameraAutoUpdate = false; 41684 return session; 41685 } 41686 get presentedScene() { 41687 return this._presentedScene; 41688 } 41689 async supportsPresentation() { 41690 try { 41691 assertIsArCandidate(); 41692 return await navigator.xr.isSessionSupported('immersive-ar'); 41693 } catch (error) { 41694 console.warn('Request to present in WebXR denied:'); 41695 console.warn(error); 41696 console.warn('Falling back to next ar-mode'); 41697 return false; 41698 } 41699 } 41700 async present(scene, environmentEstimation = false) { 41701 if (this.isPresenting) { 41702 console.warn('Cannot present while a model is already presenting'); 41703 } 41704 let waitForAnimationFrame = new Promise((resolve, _reject)=>{ 41705 requestAnimationFrame(()=>resolve()); 41706 }); 41707 scene.setHotspotsVisibility(false); 41708 scene.queueRender(); 41709 await waitForAnimationFrame; 41710 this._presentedScene = scene; 41711 this.overlay = scene.element.shadowRoot.querySelector('div.default'); 41712 if (environmentEstimation === true) { 41713 this.xrLight = new XREstimatedLight(this.threeRenderer); 41714 this.xrLight.addEventListener('estimationstart', ()=>{ 41715 if (!this.isPresenting || this.xrLight == null) { 41716 return; 41717 } 41718 const scene = this.presentedScene; 41719 scene.add(this.xrLight); 41720 scene.environment = this.xrLight.environment; 41721 }); 41722 } 41723 const currentSession = await this.resolveARSession(); 41724 currentSession.addEventListener('end', ()=>{ 41725 this.postSessionCleanup(); 41726 }, { 41727 once: true 41728 }); 41729 const exitButton = scene.element.shadowRoot.querySelector('.slot.exit-webxr-ar-button'); 41730 exitButton.classList.add('enabled'); 41731 exitButton.addEventListener('click', this.onExitWebXRButtonContainerClick); 41732 this.exitWebXRButtonContainer = exitButton; 41733 const viewerRefSpace = await currentSession.requestReferenceSpace('viewer'); 41734 this.xrMode = currentSession.interactionMode; 41735 this.tracking = true; 41736 this.frames = 0; 41737 this.initialized = false;
41738 this.turntableRotation = scene.yaw; 41739 this.goalYaw = scene.yaw; 41740 this.goalScale = 1; 41741 scene.setBackground(null); 41742 this.oldShadowIntensity = scene.shadowIntensity; 41743 scene.setShadowIntensity(0.01); 41744 this.oldTarget.copy(scene.getTarget()); 41745 scene.element.addEventListener('load', this.onUpdateScene); 41746 const radians = HIT_ANGLE_DEG * Math.PI / 180; 41747 const ray = this.placeOnWall === true ? undefined : new XRRay(new DOMPoint(0, 0, 0), { 41748 x: 0, 41749 y: -Math.sin(radians), 41750 z: -Math.cos(radians) 41751 }); 41752 currentSession.requestHitTestSource({ 41753 space: viewerRefSpace, 41754 offsetRay: ray 41755 }).then((hitTestSource)=>{ 41756 this.initialHitSource = hitTestSource; 41757 }); 41758 if (this.xrMode !== 'screen-space') { 41759 this.setupControllers(); 41760 this.xDamper.setDecayTime(DECAY); 41761 this.yDamper.setDecayTime(DECAY); 41762 this.zDamper.setDecayTime(DECAY); 41763 this.yawDamper.setDecayTime(DECAY); 41764 this.pitchDamper.setDecayTime(DECAY); 41765 this.rollDamper.setDecayTime(DECAY); 41766 } 41767 this.currentSession = currentSession; 41768 this.placementBox = new PlacementBox(scene, this.placeOnWall ? 'back' : 'bottom'); 41769 this.placementComplete = false; 41770 this.lastTick = performance.now(); 41771 this.dispatchEvent({ 41772 type: 'status', 41773 status: ARStatus.SESSION_STARTED 41774 }); 41775 } 41776 setupControllers() { 41777 this.controller1 = this.threeRenderer.xr.getController(0); 41778 this.controller1.addEventListener('selectstart', this.onControllerSelectStart); 41779 this.controller1.addEventListener('selectend', this.onControllerSelectEnd); 41780 this.controller2 = this.threeRenderer.xr.getController(1); 41781 this.controller2.addEventListener('selectstart', this.onControllerSelectStart); 41782 this.controller2.addEventListener('selectend', this.onControllerSelectEnd); 41783 const scene = this.presentedScene; 41784 scene.add(this.controller1); 41785 scene.add(this.controller2); 41786 if (!this.controller1.userData.line) { 41787 const line = new Line(lineGeometry); 41788 line.name = 'line'; 41789 line.scale.z = MAX_LINE_LENGTH; 41790 this.controller1.userData.turning = false; 41791 this.controller1.userData.line = line; 41792 this.controller1.add(line); 41793 this.controller2.userData.turning = false; 41794 const line2 = line.clone(); 41795 this.controller2.userData.line = line2; 41796 this.controller2.add(line2); 41797 this.scaleLine.name = 'scale line'; 41798 this.scaleLine.visible = false; 41799 this.controller1.add(this.scaleLine); 41800 const { size } = scene; 41801 const scale = BOX_SIZE / Math.max(size.x, size.y, size.z); 41802 const box = new Mesh(boxGeometry); 41803 box.name = 'box'; 41804 box.scale.copy(size).multiplyScalar(scale); 41805 box.visible = false; 41806 this.controller1.userData.box = box; 41807 scene.add(box); 41808 const box2 = box.clone(); 41809 this.controller2.userData.box = box2; 41810 scene.add(box2); 41811 } 41812 } 41813 hover(controller) { 41814 if (this.xrMode === 'screen-space' || this.selectedController == controller) { 41815 return false; 41816 } 41817 const scene = this.presentedScene; 41818 const intersection = this.placementBox.controllerIntersection(scene, controller); 41819 controller.userData.box.visible = (intersection == null || controller.userData.turning) && !this.isTwoFingering; 41820 controller.userData.line.scale.z = intersection == null ? MAX_LINE_LENGTH : intersection.distance; 41821 return intersection != null; 41822 } 41823 controllerSeparation() { 41824 return this.controller1.position.distanceTo(this.controller2.position); 41825 } 41826 async stopPresenting() { 41827 if (!this.isPresenting) { 41828 return; 41829 } 41830 const cleanupPromise = new Promise((resolve)=>{ 41831 this.resolveCleanup = resolve; 41832 }); 41833 try { 41834 await this.currentSession.end(); 41835 await cleanupPromise; 41836 } catch (error) { 41837 console.warn('Error while trying to end WebXR AR session'); 41838 console.warn(error); 41839 this.postSessionCleanup(); 41840 } 41841 } 41842 get isPresenting() { 41843 return this.presentedScene != null; 41844 } 41845 get target() { 41846 return this.oldTarget; 41847 } 41848 updateTarget() { 41849 const scene = this.presentedScene; 41850 if (scene != null) { 41851 const target = scene.getTarget(); 41852 this.oldTarget.copy(target); 41853 if (this.placeOnWall) { 41854 target.z = scene.boundingBox.min.z; 41855 } else { 41856 target.y = scene.boundingBox.min.y; 41857 } 41858 scene.setTarget(target.x, target.y, target.z); 41859 } 41860 } 41861 postSessionCleanup() { 41862 const session = this.currentSession; 41863 if (session != null) { 41864 session.removeEventListener('selectstart', this.onSelectStart); 41865 session.removeEventListener('selectend', this.onSelectEnd); 41866 this.currentSession = null; 41867 } 41868 const scene = this.presentedScene; 41869 this._presentedScene = null; 41870 if (scene != null) { 41871 const { element } = scene;
vendor: 9,769 bytes, lines 41872-42102
41872 if (this.xrLight != null) { 41873 scene.remove(this.xrLight); 41874 this.xrLight.dispose(); 41875 this.xrLight = null; 41876 } 41877 scene.add(scene.pivot); 41878 scene.pivot.quaternion.set(0, 0, 0, 1); 41879 scene.pivot.position.set(0, 0, 0); 41880 scene.pivot.scale.set(1, 1, 1); 41881 scene.setShadowOffset(0); 41882 const yaw = this.turntableRotation; 41883 if (yaw != null) { 41884 scene.yaw = yaw; 41885 } 41886 const intensity = this.oldShadowIntensity; 41887 if (intensity != null) { 41888 scene.setShadowIntensity(intensity); 41889 } 41890 scene.setEnvironmentAndSkybox(element[$currentEnvironmentMap], element[$currentBackground]); 41891 const point = this.oldTarget; 41892 scene.setTarget(point.x, point.y, point.z); 41893 scene.xrCamera = null; 41894 scene.element.removeEventListener('load', this.onUpdateScene); 41895 scene.orientHotspots(0); 41896 const { width, height } = element.getBoundingClientRect(); 41897 scene.setSize(width, height); 41898 requestAnimationFrame(()=>{ 41899 scene.element.dispatchEvent(new CustomEvent('camera-change', { 41900 detail: { 41901 source: ChangeSource.NONE 41902 } 41903 })); 41904 }); 41905 } 41906 this.renderer.height = 0; 41907 const exitButton = this.exitWebXRButtonContainer; 41908 if (exitButton != null) { 41909 exitButton.classList.remove('enabled'); 41910 exitButton.removeEventListener('click', this.onExitWebXRButtonContainerClick); 41911 this.exitWebXRButtonContainer = null; 41912 } 41913 const hitSource = this.transientHitTestSource; 41914 if (hitSource != null) { 41915 hitSource.cancel(); 41916 this.transientHitTestSource = null; 41917 } 41918 const hitSourceInitial = this.initialHitSource; 41919 if (hitSourceInitial != null) { 41920 hitSourceInitial.cancel(); 41921 this.initialHitSource = null; 41922 } 41923 if (this.placementBox != null) { 41924 this.placementBox.dispose(); 41925 this.placementBox = null; 41926 } 41927 if (this.xrMode !== 'screen-space') { 41928 if (this.controller1 != null) { 41929 this.controller1.userData.turning = false; 41930 this.controller1.userData.box.visible = false; 41931 this.controller1.userData.line.visible = true; 41932 this.controller1.removeEventListener('selectstart', this.onControllerSelectStart); 41933 this.controller1.removeEventListener('selectend', this.onControllerSelectEnd); 41934 this.controller1.removeFromParent(); 41935 this.controller1 = null; 41936 } 41937 if (this.controller2 != null) { 41938 this.controller2.userData.turning = false; 41939 this.controller2.userData.box.visible = false; 41940 this.controller2.userData.line.visible = true; 41941 this.controller2.removeEventListener('selectstart', this.onControllerSelectStart); 41942 this.controller2.removeEventListener('selectend', this.onControllerSelectEnd); 41943 this.controller2.removeFromParent(); 41944 this.controller2 = null; 41945 } 41946 this.selectedController = null; 41947 this.scaleLine.visible = false; 41948 } 41949 this.isTranslating = false; 41950 this.isRotating = false; 41951 this.isTwoFingering = false; 41952 this.lastTick = null; 41953 this.turntableRotation = null; 41954 this.oldShadowIntensity = null; 41955 this.frame = null; 41956 this.inputSource = null; 41957 this.overlay = null; 41958 if (this.resolveCleanup != null) { 41959 this.resolveCleanup(); 41960 } 41961 this.dispatchEvent({ 41962 type: 'status', 41963 status: ARStatus.NOT_PRESENTING 41964 }); 41965 } 41966 updateView(view) { 41967 const scene = this.presentedScene; 41968 const xr = this.threeRenderer.xr; 41969 xr.updateCamera(camera); 41970 scene.xrCamera = xr.getCamera(); 41971 const { elements } = scene.getCamera().matrixWorld; 41972 scene.orientHotspots(Math.atan2(elements[1], elements[5])); 41973 if (!this.initialized) { 41974 this.placeInitially(); 41975 this.initialized = true; 41976 } 41977 if (view.requestViewportScale && view.recommendedViewportScale) { 41978 const scale = view.recommendedViewportScale; 41979 view.requestViewportScale(Math.max(scale, MIN_VIEWPORT_SCALE)); 41980 } 41981 const layer = xr.getBaseLayer(); 41982 if (layer != null) { 41983 const viewport = layer instanceof XRWebGLLayer ? layer.getViewport(view) : xr.getBinding().getViewSubImage(layer, view).viewport; 41984 this.threeRenderer.setViewport(viewport.x, viewport.y, viewport.width, viewport.height); 41985 } 41986 } 41987 placeInitially() { 41988 const scene = this.presentedScene; 41989 const { pivot, element } = scene; 41990 const { position } = pivot; 41991 const xrCamera = scene.getCamera(); 41992 const { width, height } = this.overlay.getBoundingClientRect(); 41993 scene.setSize(width, height); 41994 xrCamera.projectionMatrixInverse.copy(xrCamera.projectionMatrix).invert(); 41995 const { theta } = element.getCameraOrbit(); 41996 const cameraDirection = xrCamera.getWorldDirection(vector3$1); 41997 scene.yaw = Math.atan2(-cameraDirection.x, -cameraDirection.z) - theta; 41998 this.goalYaw = scene.yaw; 41999 const radius = Math.max(1, 2 * scene.boundingSphere.radius); 42000 position.copy(xrCamera.position).add(cameraDirection.multiplyScalar(radius)); 42001 this.updateTarget(); 42002 const target = scene.getTarget(); 42003 position.add(target).sub(this.oldTarget); 42004 this.goalPosition.copy(position); 42005 scene.setHotspotsVisibility(true); 42006 if (this.xrMode === 'screen-space') { 42007 const { session } = this.frame; 42008 session.addEventListener('selectstart', this.onSelectStart); 42009 session.addEventListener('selectend', this.onSelectEnd); 42010 session.requestHitTestSourceForTransientInput({ 42011 profile: 'generic-touchscreen' 42012 }).then((hitTestSource)=>{ 42013 this.transientHitTestSource = hitTestSource; 42014 }); 42015 } 42016 } 42017 getTouchLocation() { 42018 const { axes } = this.inputSource.gamepad; 42019 let location = this.placementBox.getExpandedHit(this.presentedScene, axes[0], axes[1]); 42020 if (location != null) { 42021 vector3$1.copy(location).sub(this.presentedScene.getCamera().position); 42022 if (vector3$1.length() > MAX_DISTANCE) return null; 42023 } 42024 return location; 42025 } 42026 getHitPoint(hitResult) { 42027 const refSpace = this.threeRenderer.xr.getReferenceSpace(); 42028 const pose = hitResult.getPose(refSpace); 42029 if (pose == null) { 42030 return null; 42031 } 42032 const hitMatrix = matrix4.fromArray(pose.transform.matrix); 42033 if (this.placeOnWall === true) { 42034 this.goalYaw = Math.atan2(hitMatrix.elements[4], hitMatrix.elements[6]); 42035 } 42036 return hitMatrix.elements[5] > 0.75 !== this.placeOnWall ? hitPosition.setFromMatrixPosition(hitMatrix) : null; 42037 } 42038 moveToFloor(frame) { 42039 const hitSource = this.initialHitSource; 42040 if (hitSource == null) { 42041 return; 42042 } 42043 const hitTestResults = frame.getHitTestResults(hitSource); 42044 if (hitTestResults.length == 0) { 42045 return; 42046 } 42047 const hit = hitTestResults[0]; 42048 const hitPoint = this.getHitPoint(hit); 42049 if (hitPoint == null) { 42050 return; 42051 } 42052 this.placementBox.show = true; 42053 if (!this.isTranslating) { 42054 if (this.placeOnWall) { 42055 this.goalPosition.copy(hitPoint); 42056 } else { 42057 this.goalPosition.y = hitPoint.y; 42058 } 42059 } 42060 hitSource.cancel(); 42061 this.initialHitSource = null; 42062 this.dispatchEvent({ 42063 type: 'status', 42064 status: ARStatus.OBJECT_PLACED 42065 }); 42066 } 42067 fingerPolar(fingers) { 42068 const fingerOne = fingers[0].inputSource.gamepad.axes; 42069 const fingerTwo = fingers[1].inputSource.gamepad.axes; 42070 const deltaX = fingerTwo[0] - fingerOne[0]; 42071 const deltaY = fingerTwo[1] - fingerOne[1]; 42072 const angle = Math.atan2(deltaY, deltaX); 42073 let deltaYaw = this.lastAngle - angle; 42074 if (deltaYaw > Math.PI) { 42075 deltaYaw -= 2 * Math.PI; 42076 } else if (deltaYaw < -Math.PI) { 42077 deltaYaw += 2 * Math.PI; 42078 } 42079 this.lastAngle = angle; 42080 return { 42081 separation: Math.sqrt(deltaX * deltaX + deltaY * deltaY), 42082 deltaYaw: deltaYaw 42083 }; 42084 } 42085 setScale(separation) { 42086 const scale = separation / this.firstRatio; 42087 this.goalScale = Math.abs(scale - 1) < SCALE_SNAP ? 1 : scale; 42088 } 42089 processInput(frame) { 42090 const hitSource = this.transientHitTestSource; 42091 if (hitSource == null) { 42092 return; 42093 } 42094 if (!this.isTranslating && !this.isTwoFingering && !this.isRotating) { 42095 return; 42096 } 42097 const fingers = frame.getHitTestResultsForTransientInput(hitSource); 42098 const scene = this.presentedScene; 42099 const scale = scene.pivot.scale.x; 42100 if (this.isTwoFingering) { 42101 if (fingers.length < 2) { 42102 this.isTwoFingering = false;
42103 } else { 42104 const { separation, deltaYaw } = this.fingerPolar(fingers); 42105 if (this.placeOnWall === false) { 42106 this.goalYaw += deltaYaw; 42107 } 42108 if (scene.canScale) { 42109 this.setScale(separation); 42110 } 42111 } 42112 return; 42113 } else if (fingers.length === 2) { 42114 this.isTranslating = false; 42115 this.isRotating = false; 42116 this.isTwoFingering = true; 42117 const { separation } = this.fingerPolar(fingers); 42118 this.firstRatio = separation / scale; 42119 return; 42120 } 42121 if (this.isRotating) { 42122 const angle = this.inputSource.gamepad.axes[0] * ROTATION_RATE; 42123 this.goalYaw += angle - this.lastAngle; 42124 this.lastAngle = angle; 42125 } else if (this.isTranslating) { 42126 fingers.forEach((finger)=>{ 42127 if (finger.inputSource !== this.inputSource) { 42128 return; 42129 } 42130 let hit = null; 42131 if (finger.results.length > 0) { 42132 hit = this.getHitPoint(finger.results[0]); 42133 } 42134 if (hit == null) { 42135 hit = this.getTouchLocation(); 42136 } 42137 if (hit == null) { 42138 return; 42139 } 42140 this.goalPosition.sub(this.lastDragPosition); 42141 if (this.placeOnWall === false) { 42142 const offset = hit.y - this.lastDragPosition.y; 42143 if (offset < 0) { 42144 this.placementBox.offsetHeight = offset / scale; 42145 this.presentedScene.setShadowOffset(offset); 42146 const cameraPosition = vector3$1.copy(scene.getCamera().position); 42147 const alpha = -offset / (cameraPosition.y - hit.y); 42148 cameraPosition.multiplyScalar(alpha); 42149 hit.multiplyScalar(1 - alpha).add(cameraPosition); 42150 } 42151 } 42152 this.goalPosition.add(hit); 42153 this.lastDragPosition.copy(hit); 42154 }); 42155 } 42156 } 42157 moveScene(delta) { 42158 const scene = this.presentedScene; 42159 const { pivot } = scene; 42160 const box = this.placementBox; 42161 box.updateOpacity(delta); 42162 if (this.controller1) { 42163 if (this.controller1.userData.turning) { 42164 pivot.quaternion.copy(this.controller1.quaternion).multiply(this.relativeOrientation); 42165 if (this.selectedController && this.selectedController === this.controller2) { 42166 pivot.quaternion.premultiply(quaternion.copy(this.controller2.quaternion).invert()); 42167 } 42168 } 42169 this.controller1.userData.box.position.copy(this.controller1.position); 42170 pivot.getWorldQuaternion(this.controller1.userData.box.quaternion); 42171 } 42172 if (this.controller2) { 42173 if (this.controller2.userData.turning) { 42174 pivot.quaternion.copy(this.controller2.quaternion).multiply(this.relativeOrientation); 42175 if (this.selectedController && this.selectedController === this.controller1) { 42176 pivot.quaternion.premultiply(quaternion.copy(this.controller1.quaternion).invert()); 42177 } 42178 } 42179 this.controller2.userData.box.position.copy(this.controller2.position); 42180 pivot.getWorldQuaternion(this.controller2.userData.box.quaternion); 42181 } 42182 if (this.controller1 && this.controller2 && this.isTwoFingering) { 42183 const dist = this.controllerSeparation(); 42184 this.setScale(dist); 42185 this.scaleLine.scale.z = -dist; 42186 this.scaleLine.lookAt(this.controller2.position); 42187 } 42188 const oldScale = scene.pivot.scale.x; 42189 if (this.goalScale !== oldScale) { 42190 const newScale = this.scaleDamper.update(oldScale, this.goalScale, delta, 1); 42191 scene.pivot.scale.set(newScale, newScale, newScale); 42192 }
42193 if (pivot.parent !== scene) { 42194 return; 42195 } 42196 const { position } = pivot; 42197 const boundingRadius = scene.boundingSphere.radius; 42198 const goal = this.goalPosition; 42199 let source = ChangeSource.NONE; 42200 if (!goal.equals(position)) { 42201 source = ChangeSource.USER_INTERACTION; 42202 let { x, y, z } = position; 42203 x = this.xDamper.update(x, goal.x, delta, boundingRadius); 42204 y = this.yDamper.update(y, goal.y, delta, boundingRadius); 42205 z = this.zDamper.update(z, goal.z, delta, boundingRadius); 42206 position.set(x, y, z); 42207 if (this.xrMode === 'screen-space' && !this.isTranslating) { 42208 const offset = goal.y - y; 42209 if (this.placementComplete && this.placeOnWall === false) { 42210 box.offsetHeight = offset / scene.pivot.scale.x; 42211 scene.setShadowOffset(offset); 42212 } else if (offset === 0) { 42213 this.placementComplete = true; 42214 box.show = false; 42215 scene.setShadowIntensity(AR_SHADOW_INTENSITY); 42216 } 42217 } 42218 if (this.xrMode !== 'screen-space' && goal.equals(position)) { 42219 scene.setShadowIntensity(AR_SHADOW_INTENSITY); 42220 } 42221 } 42222 scene.updateTarget(delta); 42223 quaternion.setFromAxisAngle(vector3$1.set(0, 1, 0), this.goalYaw); 42224 const angle = scene.pivot.quaternion.angleTo(quaternion); 42225 const angleStep = angle - this.yawDamper.update(angle, 0, delta, Math.PI); 42226 scene.pivot.quaternion.rotateTowards(quaternion, angleStep); 42227 scene.element.dispatchEvent(new CustomEvent('camera-change', { 42228 detail: { 42229 source 42230 } 42231 })); 42232 } 42233 onWebXRFrame(time, frame) { 42234 if (this.xrMode !== 'screen-space') { 42235 const over1 = this.hover(this.controller1); 42236 const over2 = this.hover(this.controller2); 42237 this.placementBox.show = (over1 || over2) && !this.isTwoFingering; 42238 } 42239 this.frame = frame; 42240 ++this.frames; 42241 const refSpace = this.threeRenderer.xr.getReferenceSpace(); 42242 const pose = frame.getViewerPose(refSpace); 42243 if (pose == null && this.tracking === true && this.frames > INIT_FRAMES) { 42244 this.tracking = false; 42245 this.dispatchEvent({ 42246 type: 'tracking', 42247 status: ARTracking.NOT_TRACKING 42248 }); 42249 } 42250 const scene = this.presentedScene; 42251 if (pose == null || scene == null || !scene.element.loaded) { 42252 this.threeRenderer.clear(); 42253 return; 42254 } 42255 if (this.tracking === false) { 42256 this.tracking = true; 42257 this.dispatchEvent({ 42258 type: 'tracking', 42259 status: ARTracking.TRACKING 42260 }); 42261 } 42262 let isFirstView = true; 42263 for (const view of pose.views){ 42264 this.updateView(view); 42265 if (isFirstView) { 42266 this.moveToFloor(frame); 42267 this.processInput(frame); 42268 const delta = time - this.lastTick; 42269 this.moveScene(delta); 42270 this.renderer.preRender(scene, time, delta); 42271 this.lastTick = time; 42272 scene.renderShadow(this.threeRenderer); 42273 } 42274 this.threeRenderer.render(scene, scene.getCamera()); 42275 isFirstView = false; 42276 } 42277 } 42278 constructor(renderer){ 42279 super(); 42280 this.renderer = renderer; 42281 this.currentSession = null; 42282 this.placeOnWall = false; 42283 this.placementBox = null; 42284 this.lastTick = null; 42285 this.turntableRotation = null; 42286 this.oldShadowIntensity = null; 42287 this.frame = null; 42288 this.initialHitSource = null; 42289 this.transientHitTestSource = null; 42290 this.inputSource = null; 42291 this._presentedScene = null; 42292 this.resolveCleanup = null; 42293 this.exitWebXRButtonContainer = null;
42294 this.overlay = null; 42295 this.xrLight = null; 42296 this.xrMode = null; 42297 this.controller1 = null; 42298 this.controller2 = null; 42299 this.selectedController = null; 42300 this.tracking = true; 42301 this.frames = 0; 42302 this.initialized = false; 42303 this.oldTarget = new Vector3(); 42304 this.placementComplete = false; 42305 this.isTranslating = false; 42306 this.isRotating = false; 42307 this.isTwoFingering = false; 42308 this.lastDragPosition = new Vector3(); 42309 this.relativeOrientation = new Quaternion(); 42310 this.scaleLine = new Line(lineGeometry); 42311 this.firstRatio = 0; 42312 this.lastAngle = 0; 42313 this.goalPosition = new Vector3(); 42314 this.goalYaw = 0; 42315 this.goalScale = 1; 42316 this.xDamper = new Damper(); 42317 this.yDamper = new Damper(); 42318 this.zDamper = new Damper(); 42319 this.yawDamper = new Damper(); 42320 this.pitchDamper = new Damper(); 42321 this.rollDamper = new Damper(); 42322 this.scaleDamper = new Damper(); 42323 this.onExitWebXRButtonContainerClick = ()=>this.stopPresenting(); 42324 this.onControllerSelectStart = (event)=>{ 42325 const scene = this.presentedScene; 42326 const controller = event.target; 42327 if (this.placementBox.controllerIntersection(scene, controller) != null) { 42328 if (this.selectedController != null) { 42329 this.selectedController.userData.line.visible = false; 42330 if (scene.canScale) { 42331 this.isTwoFingering = true; 42332 this.firstRatio = this.controllerSeparation() / scene.pivot.scale.x; 42333 this.scaleLine.visible = true; 42334 } 42335 } 42336 controller.attach(scene.pivot); 42337 this.selectedController = controller; 42338 scene.setShadowIntensity(0.01); 42339 } else { 42340 const otherController = controller === this.controller1 ? this.controller2 : this.controller1; 42341 this.relativeOrientation.copy(controller.quaternion).invert().multiply(scene.pivot.getWorldQuaternion(quaternion)); 42342 otherController.userData.turning = false; 42343 controller.userData.turning = true; 42344 controller.userData.line.visible = false; 42345 } 42346 }; 42347 this.onControllerSelectEnd = (event)=>{ 42348 const controller = event.target; 42349 controller.userData.turning = false; 42350 controller.userData.line.visible = true; 42351 this.isTwoFingering = false; 42352 this.scaleLine.visible = false; 42353 if (this.selectedController != null && this.selectedController != controller) { 42354 return; 42355 } 42356 const scene = this.presentedScene; 42357 scene.attach(scene.pivot); 42358 this.selectedController = null; 42359 this.goalYaw = Math.atan2(scene.pivot.matrix.elements[8], scene.pivot.matrix.elements[10]); 42360 this.goalPosition.x = scene.pivot.position.x; 42361 this.goalPosition.z = scene.pivot.position.z; 42362 }; 42363 this.onUpdateScene = ()=>{ 42364 if (this.placementBox != null && this.isPresenting) { 42365 this.placementBox.dispose(); 42366 this.placementBox = new PlacementBox(this.presentedScene, this.placeOnWall ? 'back' : 'bottom'); 42367 } 42368 }; 42369 this.onSelectStart = (event)=>{ 42370 const hitSource = this.transientHitTestSource; 42371 if (hitSource == null) { 42372 return; 42373 } 42374 const fingers = this.frame.getHitTestResultsForTransientInput(hitSource); 42375 const scene = this.presentedScene; 42376 const box = this.placementBox; 42377 if (fingers.length === 1) { 42378 this.inputSource = event.inputSource; 42379 const { axes } = this.inputSource.gamepad; 42380 const hitPosition = box.getHit(this.presentedScene, axes[0], axes[1]); 42381 box.show = true; 42382 if (hitPosition != null) { 42383 this.isTranslating = true; 42384 this.lastDragPosition.copy(hitPosition); 42385 } else if (this.placeOnWall === false) { 42386 this.isRotating = true; 42387 this.lastAngle = axes[0] * ROTATION_RATE; 42388 } 42389 } else if (fingers.length === 2) { 42390 box.show = true; 42391 this.isTwoFingering = true; 42392 const { separation } = this.fingerPolar(fingers); 42393 this.firstRatio = separation / scene.pivot.scale.x; 42394 } 42395 }; 42396 this.onSelectEnd = ()=>{ 42397 this.isTranslating = false;
vendor: 5,060 bytes, lines 42398-42549
42398 this.isRotating = false; 42399 this.isTwoFingering = false; 42400 this.inputSource = null; 42401 this.goalPosition.y += this.placementBox.offsetHeight * this.presentedScene.scale.x; 42402 this.placementBox.show = false; 42403 }; 42404 this.threeRenderer = renderer.threeRenderer; 42405 this.threeRenderer.xr.enabled = true; 42406 } 42407 } 42408 42409 function clone(source) { 42410 const sourceLookup = new Map(); 42411 const cloneLookup = new Map(); 42412 const clone = source.clone(); 42413 parallelTraverse(source, clone, function(sourceNode, clonedNode) { 42414 sourceLookup.set(clonedNode, sourceNode); 42415 cloneLookup.set(sourceNode, clonedNode); 42416 }); 42417 clone.traverse(function(node) { 42418 if (!node.isSkinnedMesh) return; 42419 const clonedMesh = node; 42420 const sourceMesh = sourceLookup.get(node); 42421 const sourceBones = sourceMesh.skeleton.bones; 42422 clonedMesh.skeleton = sourceMesh.skeleton.clone(); 42423 clonedMesh.bindMatrix.copy(sourceMesh.bindMatrix); 42424 clonedMesh.skeleton.bones = sourceBones.map(function(bone) { 42425 return cloneLookup.get(bone); 42426 }); 42427 clonedMesh.bind(clonedMesh.skeleton, clonedMesh.bindMatrix); 42428 }); 42429 return clone; 42430 } 42431 function parallelTraverse(a, b, callback) { 42432 callback(a, b); 42433 for(let i = 0; i < a.children.length; i++){ 42434 parallelTraverse(a.children[i], b.children[i], callback); 42435 } 42436 } 42437 42438 const $prepared = Symbol('prepared'); 42439 const $prepare = Symbol('prepare'); 42440 const $preparedGLTF = Symbol('preparedGLTF'); 42441 const $clone = Symbol('clone'); 42442 class GLTFInstance { 42443 static prepare(source) { 42444 if (source.scene == null) { 42445 throw new Error('Model does not have a scene'); 42446 } 42447 if (source[$prepared]) { 42448 return source; 42449 } 42450 const prepared = this[$prepare](source); 42451 prepared[$prepared] = true; 42452 return prepared; 42453 } 42454 static [$prepare](source) { 42455 const { scene } = source; 42456 const scenes = [ 42457 scene 42458 ]; 42459 return Object.assign(Object.assign({}, source), { 42460 scene, 42461 scenes 42462 }); 42463 } 42464 get parser() { 42465 return this[$preparedGLTF].parser; 42466 } 42467 get animations() { 42468 return this[$preparedGLTF].animations; 42469 } 42470 get scene() { 42471 return this[$preparedGLTF].scene; 42472 } 42473 get scenes() { 42474 return this[$preparedGLTF].scenes; 42475 } 42476 get cameras() { 42477 return this[$preparedGLTF].cameras; 42478 } 42479 get asset() { 42480 return this[$preparedGLTF].asset; 42481 } 42482 get userData() { 42483 return this[$preparedGLTF].userData; 42484 } 42485 clone() { 42486 const GLTFInstanceConstructor = this.constructor; 42487 const clonedGLTF = this[$clone](); 42488 return new GLTFInstanceConstructor(clonedGLTF); 42489 } 42490 dispose() { 42491 this.scenes.forEach((scene)=>{ 42492 scene.traverse((object)=>{ 42493 const mesh = object; 42494 if (!mesh.material) { 42495 return; 42496 } 42497 const materials = Array.isArray(mesh.material) ? mesh.material : [ 42498 mesh.material 42499 ]; 42500 materials.forEach((material)=>{ 42501 for(const propertyName in material){ 42502 const texture = material[propertyName]; 42503 if (texture instanceof Texture$1) { 42504 const image = texture.source.data; 42505 if (image.close != null) { 42506 image.close(); 42507 } 42508 texture.dispose(); 42509 } 42510 } 42511 material.dispose(); 42512 }); 42513 mesh.geometry.dispose(); 42514 }); 42515 }); 42516 } 42517 [$clone]() { 42518 const source = this[$preparedGLTF]; 42519 const scene = clone(this.scene); 42520 cloneVariantMaterials(scene, this.scene); 42521 const scenes = [ 42522 scene 42523 ]; 42524 const userData = source.userData ? Object.assign({}, source.userData) : {}; 42525 return Object.assign(Object.assign({}, source), { 42526 scene, 42527 scenes, 42528 userData 42529 }); 42530 } 42531 constructor(preparedGLTF){ 42532 this[$preparedGLTF] = preparedGLTF; 42533 } 42534 } 42535 const cloneVariantMaterials = (dst, src)=>{ 42536 traversePair(dst, src, (dst, src)=>{ 42537 if (src.userData.variantMaterials !== undefined) { 42538 dst.userData.variantMaterials = new Map(src.userData.variantMaterials); 42539 } 42540 if (src.userData.variantData !== undefined) { 42541 dst.userData.variantData = src.userData.variantData; 42542 } 42543 if (src.userData.originalMaterial !== undefined) { 42544 dst.userData.originalMaterial = src.userData.originalMaterial; 42545 } 42546 }); 42547 }; 42548 const traversePair = (obj1, obj2, callback)=>{ 42549 callback(obj1, obj2);
vendor: 5,410 bytes, lines 42550-42663
42550 for(let i = 0; i < obj1.children.length; i++){ 42551 traversePair(obj1.children[i], obj2.children[i], callback); 42552 } 42553 }; 42554 42555 const $threeGLTF = Symbol('threeGLTF'); 42556 const $gltf = Symbol('gltf'); 42557 const $gltfElementMap = Symbol('gltfElementMap'); 42558 const $threeObjectMap = Symbol('threeObjectMap'); 42559 const $parallelTraverseThreeScene = Symbol('parallelTraverseThreeScene'); 42560 const $correlateOriginalThreeGLTF = Symbol('correlateOriginalThreeGLTF'); 42561 const $correlateCloneThreeGLTF = Symbol('correlateCloneThreeGLTF'); 42562 class CorrelatedSceneGraph { 42563 static from(threeGLTF, upstreamCorrelatedSceneGraph) { 42564 if (upstreamCorrelatedSceneGraph != null) { 42565 return this[$correlateCloneThreeGLTF](threeGLTF, upstreamCorrelatedSceneGraph); 42566 } else { 42567 return this[$correlateOriginalThreeGLTF](threeGLTF); 42568 } 42569 } 42570 static [$correlateOriginalThreeGLTF](threeGLTF) { 42571 const gltf = threeGLTF.parser.json; 42572 const associations = threeGLTF.parser.associations; 42573 const gltfElementMap = new Map(); 42574 const defaultMaterial = { 42575 name: 'Default' 42576 }; 42577 const defaultReference = { 42578 index: -1 42579 }; 42580 for (const threeMaterial of associations.keys()){ 42581 if (threeMaterial instanceof Material$1 && associations.get(threeMaterial) == null) { 42582 if (defaultReference.index < 0) { 42583 if (gltf.materials == null) { 42584 gltf.materials = []; 42585 } 42586 defaultReference.index = gltf.materials.length; 42587 gltf.materials.push(defaultMaterial); 42588 } 42589 threeMaterial.name = defaultMaterial.name; 42590 associations.set(threeMaterial, { 42591 materials: defaultReference.index 42592 }); 42593 } 42594 } 42595 for (const [threeObject, gltfMappings] of associations){ 42596 if (gltfMappings) { 42597 threeObject.userData = threeObject.userData || {}; 42598 threeObject.userData.associations = gltfMappings; 42599 } 42600 for(const mapping in gltfMappings){ 42601 if (mapping != null && mapping !== 'primitives') { 42602 const type = mapping; 42603 const elementArray = gltf[type] || []; 42604 const gltfElement = elementArray[gltfMappings[type]]; 42605 if (gltfElement == null) { 42606 continue; 42607 } 42608 let threeObjects = gltfElementMap.get(gltfElement); 42609 if (threeObjects == null) { 42610 threeObjects = new Set(); 42611 gltfElementMap.set(gltfElement, threeObjects); 42612 } 42613 threeObjects.add(threeObject); 42614 } 42615 } 42616 } 42617 return new CorrelatedSceneGraph(threeGLTF, gltf, associations, gltfElementMap); 42618 } 42619 static [$correlateCloneThreeGLTF](cloneThreeGLTF, upstreamCorrelatedSceneGraph) { 42620 const originalThreeGLTF = upstreamCorrelatedSceneGraph.threeGLTF; 42621 const originalGLTF = upstreamCorrelatedSceneGraph.gltf; 42622 const cloneGLTF = JSON.parse(JSON.stringify(originalGLTF)); 42623 const cloneThreeObjectMap = new Map(); 42624 const cloneGLTFElementMap = new Map(); 42625 for(let i = 0; i < originalThreeGLTF.scenes.length; i++){ 42626 this[$parallelTraverseThreeScene](originalThreeGLTF.scenes[i], cloneThreeGLTF.scenes[i], (object, cloneObject)=>{ 42627 const elementReference = upstreamCorrelatedSceneGraph.threeObjectMap.get(object); 42628 if (elementReference == null) { 42629 return; 42630 } 42631 for(const mapping in elementReference){ 42632 if (mapping != null && mapping !== 'primitives') { 42633 const type = mapping; 42634 const index = elementReference[type]; 42635 const cloneElement = cloneGLTF[type][index]; 42636 const mappings = cloneThreeObjectMap.get(cloneObject) || {}; 42637 mappings[type] = index; 42638 cloneThreeObjectMap.set(cloneObject, mappings); 42639 const cloneObjects = cloneGLTFElementMap.get(cloneElement) || new Set(); 42640 cloneObjects.add(cloneObject); 42641 cloneGLTFElementMap.set(cloneElement, cloneObjects); 42642 } 42643 } 42644 }); 42645 } 42646 return new CorrelatedSceneGraph(cloneThreeGLTF, cloneGLTF, cloneThreeObjectMap, cloneGLTFElementMap); 42647 } 42648 static [$parallelTraverseThreeScene](sceneOne, sceneTwo, callback) { 42649 const traverse = (a, b)=>{ 42650 callback(a, b); 42651 if (a.isObject3D) { 42652 const meshA = a; 42653 const meshB = b; 42654 if (meshA.material) { 42655 if (Array.isArray(meshA.material)) { 42656 for(let i = 0; i < meshA.material.length; ++i){ 42657 callback(meshA.material[i], meshB.material[i]); 42658 } 42659 } else { 42660 callback(meshA.material, meshB.material); 42661 } 42662 } 42663 for(let i = 0;
vendor: 6,066 bytes, lines 42663-42833
42663 i < a.children.length; ++i){ 42664 traverse(a.children[i], b.children[i]); 42665 } 42666 } 42667 }; 42668 traverse(sceneOne, sceneTwo); 42669 } 42670 get threeGLTF() { 42671 return this[$threeGLTF]; 42672 } 42673 get gltf() { 42674 return this[$gltf]; 42675 } 42676 get gltfElementMap() { 42677 return this[$gltfElementMap]; 42678 } 42679 get threeObjectMap() { 42680 return this[$threeObjectMap]; 42681 } 42682 constructor(threeGLTF, gltf, threeObjectMap, gltfElementMap){ 42683 this[$threeGLTF] = threeGLTF; 42684 this[$gltf] = gltf; 42685 this[$gltfElementMap] = gltfElementMap; 42686 this[$threeObjectMap] = threeObjectMap; 42687 } 42688 } 42689 42690 const $correlatedSceneGraph = Symbol('correlatedSceneGraph'); 42691 class ModelViewerGLTFInstance extends GLTFInstance { 42692 static [$prepare](source) { 42693 const prepared = super[$prepare](source); 42694 if (prepared[$correlatedSceneGraph] == null) { 42695 prepared[$correlatedSceneGraph] = CorrelatedSceneGraph.from(prepared); 42696 } 42697 const { scene } = prepared; 42698 const nullSphere = new Sphere(undefined, Infinity); 42699 scene.traverse((node)=>{ 42700 node.renderOrder = 1000; 42701 node.frustumCulled = false; 42702 if (!node.name) { 42703 node.name = node.uuid; 42704 } 42705 const mesh = node; 42706 if (mesh.material) { 42707 const { geometry } = mesh; 42708 mesh.castShadow = true; 42709 if (mesh.isSkinnedMesh) { 42710 geometry.boundingSphere = nullSphere; 42711 geometry.boundingBox = null; 42712 } 42713 const material = mesh.material; 42714 if (material.isMeshBasicMaterial === true) { 42715 material.toneMapped = false; 42716 } 42717 material.shadowSide = FrontSide; 42718 if (material.aoMap) { 42719 const { gltf, threeObjectMap } = prepared[$correlatedSceneGraph]; 42720 const gltfRef = threeObjectMap.get(material); 42721 if (gltf.materials != null && gltfRef != null && gltfRef.materials != null) { 42722 const gltfMaterial = gltf.materials[gltfRef.materials]; 42723 if (gltfMaterial.occlusionTexture && gltfMaterial.occlusionTexture.texCoord === 0 && geometry.attributes.uv != null) { 42724 geometry.setAttribute('uv2', geometry.attributes.uv); 42725 } 42726 } 42727 } 42728 } 42729 }); 42730 return prepared; 42731 } 42732 get correlatedSceneGraph() { 42733 return this[$preparedGLTF][$correlatedSceneGraph]; 42734 } 42735 [$clone]() { 42736 const clone = super[$clone](); 42737 const sourceUUIDToClonedMaterial = new Map(); 42738 clone.scene.traverse((node)=>{ 42739 const mesh = node; 42740 if (mesh.material) { 42741 const material = mesh.material; 42742 if (material != null) { 42743 if (sourceUUIDToClonedMaterial.has(material.uuid)) { 42744 mesh.material = sourceUUIDToClonedMaterial.get(material.uuid); 42745 return; 42746 } 42747 mesh.material = material.clone(); 42748 sourceUUIDToClonedMaterial.set(material.uuid, mesh.material); 42749 } 42750 } 42751 const light = node; 42752 if (light.target !== undefined) { 42753 light.add(light.target); 42754 } 42755 }); 42756 clone[$correlatedSceneGraph] = CorrelatedSceneGraph.from(clone, this.correlatedSceneGraph); 42757 return clone; 42758 } 42759 } 42760 42761 const getBufferForType = (type, width, height)=>{ 42762 let out; 42763 switch(type){ 42764 case UnsignedByteType: 42765 out = new Uint8ClampedArray(width * height * 4); 42766 break; 42767 case HalfFloatType: 42768 out = new Uint16Array(width * height * 4); 42769 break; 42770 case UnsignedIntType: 42771 out = new Uint32Array(width * height * 4); 42772 break; 42773 case ByteType: 42774 out = new Int8Array(width * height * 4); 42775 break; 42776 case ShortType: 42777 out = new Int16Array(width * height * 4); 42778 break; 42779 case IntType: 42780 out = new Int32Array(width * height * 4); 42781 break; 42782 case FloatType: 42783 out = new Float32Array(width * height * 4); 42784 break; 42785 default: 42786 throw new Error('Unsupported data type'); 42787 } 42788 return out; 42789 }; 42790 let _canReadPixelsResult; 42791 /** 42792 * Test if this browser implementation can correctly read pixels from the specified 42793 * Render target type. 42794 * 42795 * Runs only once 42796 * 42797 * @param type 42798 * @param renderer 42799 * @param camera 42800 * @param renderTargetOptions 42801 * @returns 42802 */ const canReadPixels = (type, renderer, camera, renderTargetOptions)=>{ 42803 if (_canReadPixelsResult !== undefined) return _canReadPixelsResult; 42804 const testRT = new WebGLRenderTarget(1, 1, renderTargetOptions); 42805 renderer.setRenderTarget(testRT); 42806 const mesh = new Mesh(new PlaneGeometry(), new MeshBasicMaterial({ 42807 color: 0xffffff 42808 })); 42809 renderer.render(mesh, camera); 42810 renderer.setRenderTarget(null); 42811 const out = getBufferForType(type, testRT.width, testRT.height); 42812 renderer.readRenderTargetPixels(testRT, 0, 0, testRT.width, testRT.height, out); 42813 testRT.dispose(); 42814 mesh.geometry.dispose(); 42815 mesh.material.dispose(); 42816 _canReadPixelsResult = out[0] !== 0; 42817 return _canReadPixelsResult; 42818 }; 42819 /** 42820 * Utility class used for rendering a texture with a material 42821 * 42822 * @category Core 42823 * @group Core 42824 */ class QuadRenderer { 42825 /** 42826 * Instantiates a temporary renderer 42827 * 42828 * @returns 42829 */ static instantiateRenderer() { 42830 const renderer = new WebGLRenderer(); 42831 renderer.setSize(128, 128); 42832 // renderer.outputColorSpace = SRGBColorSpace 42833 // renderer.toneMapping = LinearToneMapping
42834 // renderer.debug.checkShaderErrors = false 42835 // this._rendererIsDisposable = true 42836 return renderer; 42837 } 42838 /** 42839 * Obtains a Buffer containing the rendered texture. 42840 * 42841 * @throws Error if the browser cannot read pixels from this RenderTarget type. 42842 * @returns a TypedArray containing RGBA values from this renderer 42843 */ toArray() { 42844 if (!this._supportsReadPixels) throw new Error('Can\'t read pixels in this browser'); 42845 const out = getBufferForType(this._type, this._width, this._height); 42846 this._renderer.readRenderTargetPixels(this._renderTarget, 0, 0, this._width, this._height, out); 42847 return out; 42848 } 42849 /** 42850 * Performs a readPixel operation in the renderTarget 42851 * and returns a DataTexture containing the read data 42852 * 42853 * @param options options 42854 * @returns 42855 */ toDataTexture(options) { 42856 const returnValue = new DataTexture(// fixed values 42857 this.toArray(), this.width, this.height, RGBAFormat, this._type, // user values 42858 (options === null || options === void 0 ? void 0 : options.mapping) || UVMapping, (options === null || options === void 0 ? void 0 : options.wrapS) || ClampToEdgeWrapping, (options === null || options === void 0 ? void 0 : options.wrapT) || ClampToEdgeWrapping, (options === null || options === void 0 ? void 0 : options.magFilter) || LinearFilter, (options === null || options === void 0 ? void 0 : options.minFilter) || LinearFilter, (options === null || options === void 0 ? void 0 : options.anisotropy) || 1, // fixed value 42859 LinearSRGBColorSpace); 42860 // set this afterwards, we can't set it in constructor 42861 returnValue.generateMipmaps = (options === null || options === void 0 ? void 0 : options.generateMipmaps) !== undefined ? options === null || options === void 0 ? void 0 : options.generateMipmaps : false; 42862 return returnValue; 42863 } 42864 /** 42865 * If using a disposable renderer, it will dispose it. 42866 */ disposeOnDemandRenderer() { 42867 this._renderer.setRenderTarget(null); 42868 if (this._rendererIsDisposable) { 42869 this._renderer.dispose(); 42870 this._renderer.forceContextLoss(); 42871 } 42872 } 42873 /** 42874 * Will dispose of **all** assets used by this renderer. 42875 * 42876 *
42877 * @param disposeRenderTarget will dispose of the renderTarget which will not be usable later 42878 * set this to true if you passed the `renderTarget.texture` to a `PMREMGenerator` 42879 * or are otherwise done with it. 42880 * 42881 * @example 42882 * ```js 42883 * const loader = new HDRJPGLoader(renderer) 42884 * const result = await loader.loadAsync('gainmap.jpeg') 42885 * const mesh = new Mesh(geometry, new MeshBasicMaterial({ map: result.renderTarget.texture }) ) 42886 * // DO NOT dispose the renderTarget here, 42887 * // it is used directly in the material 42888 * result.dispose() 42889 * ``` 42890 * 42891 * @example 42892 * ```js 42893 * const loader = new HDRJPGLoader(renderer) 42894 * const pmremGenerator = new PMREMGenerator( renderer ); 42895 * const result = await loader.loadAsync('gainmap.jpeg') 42896 * const envMap = pmremGenerator.fromEquirectangular(result.renderTarget.texture) 42897 * const mesh = new Mesh(geometry, new MeshStandardMaterial({ envMap }) ) 42898 * // renderTarget can be disposed here 42899 * // because it was used to generate a PMREM texture 42900 * result.dispose(true) 42901 * ``` 42902 */ dispose(disposeRenderTarget) { 42903 this.disposeOnDemandRenderer(); 42904 if (disposeRenderTarget) { 42905 this.renderTarget.dispose(); 42906 } 42907 // dispose shader material texture uniforms 42908 if (this.material instanceof ShaderMaterial) { 42909 Object.values(this.material.uniforms).forEach((v)=>{ 42910 if (v.value instanceof Texture$1) v.value.dispose(); 42911 }); 42912 } 42913 // dispose other material properties 42914 Object.values(this.material).forEach((value)=>{ 42915 if (value instanceof Texture$1) value.dispose(); 42916 }); 42917 this.material.dispose(); 42918 this._quad.geometry.dispose(); 42919 } 42920 /** 42921 * Width of the texture 42922 */ get width() { 42923 return this._width; 42924 } 42925 set width(value) { 42926 this._width = value; 42927 this._renderTarget.setSize(this._width, this._height); 42928 } 42929 /** 42930 * Height of the texture 42931 */ get height() { 42932 return this._height; 42933 } 42934 set height(value) { 42935 this._height = value; 42936 this._renderTarget.setSize(this._width, this._height); 42937 } 42938 /** 42939 * The renderer used 42940 */ get renderer() { 42941 return this._renderer; 42942 } 42943 /** 42944 * The `WebGLRenderTarget` used. 42945 */ get renderTarget() { 42946 return this._renderTarget; 42947 } 42948 set renderTarget(value) { 42949 this._renderTarget = value; 42950 this._width = value.width; 42951 this._height = value.height; 42952 // this._type = value.texture.type 42953 } 42954 /** 42955 * The `Material` used. 42956 */ get material() { 42957 return this._material; 42958 } 42959 /** 42960 * 42961 */ get type() { 42962 return this._type; 42963 } 42964 get colorSpace() { 42965 return this._colorSpace; 42966 } 42967 /** 42968 * Constructs a new QuadRenderer 42969 * 42970 * @param options Parameters for this QuadRenderer 42971 */ constructor(options){ 42972 var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r; 42973 this._rendererIsDisposable = false; 42974 this._supportsReadPixels = true; 42975 /** 42976 * Renders the input texture using the specified material 42977 */ this.render = ()=>{ 42978 this._renderer.setRenderTarget(this._renderTarget); 42979 try { 42980 this._renderer.render(this._scene, this._camera); 42981 } catch (e) { 42982 this._renderer.setRenderTarget(null); 42983 throw e; 42984 } 42985 this._renderer.setRenderTarget(null); 42986 }; 42987 this._width = options.width; 42988 this._height = options.height; 42989 this._type = options.type; 42990 this._colorSpace = options.colorSpace; 42991 const rtOptions = { 42992 // fixed options 42993 format: RGBAFormat, 42994 depthBuffer: false, 42995 stencilBuffer: false, 42996 // user options 42997 type: this._type, 42998 colorSpace: this._colorSpace, 42999 anisotropy: ((_a = options.renderTargetOptions) === null || _a === void 0 ? void 0 : _a.anisotropy) !== undefined ? (_b = options.renderTargetOptions) === null || _b === void 0 ? void 0 : _b.anisotropy : 1, 43000 generateMipmaps: ((_c = options.renderTargetOptions) === null || _c === void 0 ? void 0 : _c.generateMipmaps) !== undefined ? (_d = options.renderTargetOptions) === null || _d === void 0 ? void 0 : _d.generateMipmaps : false, 43001 magFilter: ((_e = options.renderTargetOptions) === null || _e === void 0 ? void 0 : _e.magFilter) !== undefined ? (_f = options.renderTargetOptions) === null || _f === void 0 ? void 0 : _f.magFilter : LinearFilter, 43002 minFilter: ((_g = options.renderTargetOptions) === null || _g === void 0 ? void 0 : _g.minFilter) !== undefined ? (_h = options.renderTargetOptions) === null || _h === void 0 ? void 0 : _h.minFilter : LinearFilter, 43003 samples: ((_j = options.renderTargetOptions) === null || _j === void 0 ? void 0 : _j.samples) !== undefined ? (_k = options.renderTargetOptions) === null || _k === void 0 ? void 0 : _k.samples : undefined, 43004 wrapS: ((_l = options.renderTargetOptions) === null || _l === void 0 ? void 0 : _l.wrapS) !== undefined ? (_m = options.renderTargetOptions) === null || _m === void 0 ? void 0 : _m.wrapS : ClampToEdgeWrapping,
vendor: 15,142 bytes, lines 43005-43364
43005 wrapT: ((_o = options.renderTargetOptions) === null || _o === void 0 ? void 0 : _o.wrapT) !== undefined ? (_p = options.renderTargetOptions) === null || _p === void 0 ? void 0 : _p.wrapT : ClampToEdgeWrapping 43006 }; 43007 this._material = options.material; 43008 if (options.renderer) { 43009 this._renderer = options.renderer; 43010 } else { 43011 this._renderer = QuadRenderer.instantiateRenderer(); 43012 this._rendererIsDisposable = true; 43013 } 43014 this._scene = new Scene(); 43015 this._camera = new OrthographicCamera(); 43016 this._camera.position.set(0, 0, 10); 43017 this._camera.left = -0.5; 43018 this._camera.right = 0.5; 43019 this._camera.top = 0.5; 43020 this._camera.bottom = -0.5; 43021 this._camera.updateProjectionMatrix(); 43022 if (!canReadPixels(this._type, this._renderer, this._camera, rtOptions)) { 43023 let alternativeType; 43024 switch(this._type){ 43025 case HalfFloatType: 43026 alternativeType = this._renderer.extensions.has('EXT_color_buffer_float') ? FloatType : undefined; 43027 break; 43028 } 43029 if (alternativeType !== undefined) { 43030 console.warn(`This browser does not support reading pixels from ${this._type} RenderTargets, switching to ${FloatType}`); 43031 this._type = alternativeType; 43032 } else { 43033 this._supportsReadPixels = false; 43034 console.warn('This browser dos not support toArray or toDataTexture, calls to those methods will result in an error thrown'); 43035 } 43036 } 43037 this._quad = new Mesh(new PlaneGeometry(), this._material); 43038 this._quad.geometry.computeBoundingBox(); 43039 this._scene.add(this._quad); 43040 this._renderTarget = new WebGLRenderTarget(this.width, this.height, rtOptions); 43041 this._renderTarget.texture.mapping = ((_q = options.renderTargetOptions) === null || _q === void 0 ? void 0 : _q.mapping) !== undefined ? (_r = options.renderTargetOptions) === null || _r === void 0 ? void 0 : _r.mapping : UVMapping; 43042 } 43043 } 43044 43045 const vertexShader = /* glsl */ ` 43046varying vec2 vUv; 43047 43048void main() { 43049 vUv = uv; 43050 gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 43051} 43052`; 43053 const fragmentShader = /* glsl */ ` 43054// min half float value 43055#define HALF_FLOAT_MIN vec3( -65504, -65504, -65504 ) 43056// max half float value 43057#define HALF_FLOAT_MAX vec3( 65504, 65504, 65504 ) 43058 43059uniform sampler2D sdr; 43060uniform sampler2D gainMap; 43061uniform vec3 gamma; 43062uniform vec3 offsetHdr; 43063uniform vec3 offsetSdr; 43064uniform vec3 gainMapMin; 43065uniform vec3 gainMapMax; 43066uniform float weightFactor; 43067 43068varying vec2 vUv; 43069 43070void main() { 43071 vec3 rgb = texture2D( sdr, vUv ).rgb; 43072 vec3 recovery = texture2D( gainMap, vUv ).rgb; 43073 vec3 logRecovery = pow( recovery, gamma ); 43074 vec3 logBoost = gainMapMin * ( 1.0 - logRecovery ) + gainMapMax * logRecovery; 43075 vec3 hdrColor = (rgb + offsetSdr) * exp2( logBoost * weightFactor ) - offsetHdr; 43076 vec3 clampedHdrColor = max( HALF_FLOAT_MIN, min( HALF_FLOAT_MAX, hdrColor )); 43077 gl_FragColor = vec4( clampedHdrColor , 1.0 ); 43078} 43079`; 43080 /** 43081 * A Material which is able to decode the Gainmap into a full HDR Representation 43082 * 43083 * @category Materials 43084 * @group Materials 43085 */ class GainMapDecoderMaterial extends ShaderMaterial { 43086 get sdr() { 43087 return this.uniforms.sdr.value; 43088 } 43089 set sdr(value) { 43090 this.uniforms.sdr.value = value; 43091 } 43092 get gainMap() { 43093 return this.uniforms.gainMap.value; 43094 } 43095 set gainMap(value) { 43096 this.uniforms.gainMap.value = value; 43097 } 43098 /** 43099 * @see {@link GainMapMetadata.offsetHdr} 43100 */ get offsetHdr() { 43101 return this.uniforms.offsetHdr.value.toArray(); 43102 } 43103 set offsetHdr(value) { 43104 this.uniforms.offsetHdr.value.fromArray(value); 43105 } 43106 /** 43107 * @see {@link GainMapMetadata.offsetSdr} 43108 */ get offsetSdr() { 43109 return this.uniforms.offsetSdr.value.toArray(); 43110 } 43111 set offsetSdr(value) { 43112 this.uniforms.offsetSdr.value.fromArray(value); 43113 } 43114 /** 43115 * @see {@link GainMapMetadata.gainMapMin} 43116 */ get gainMapMin() { 43117 return this.uniforms.gainMapMin.value.toArray(); 43118 } 43119 set gainMapMin(value) { 43120 this.uniforms.gainMapMin.value.fromArray(value); 43121 } 43122 /** 43123 * @see {@link GainMapMetadata.gainMapMax} 43124 */ get gainMapMax() { 43125 return this.uniforms.gainMapMax.value.toArray(); 43126 } 43127 set gainMapMax(value) { 43128 this.uniforms.gainMapMax.value.fromArray(value); 43129 } 43130 /** 43131 * @see {@link GainMapMetadata.gamma} 43132 */ get gamma() { 43133 const g = this.uniforms.gamma.value; 43134 return [ 43135 1 / g.x, 43136 1 / g.y, 43137 1 / g.z 43138 ]; 43139 } 43140 set gamma(value) { 43141 const g = this.uniforms.gamma.value; 43142 g.x = 1.0 / value[0]; 43143 g.y = 1.0 / value[1]; 43144 g.z = 1.0 / value[2]; 43145 } 43146 /** 43147 * @see {@link GainMapMetadata.hdrCapacityMin} 43148 * @remarks Logarithmic space 43149 */ get hdrCapacityMin() { 43150 return this._hdrCapacityMin; 43151 } 43152 set hdrCapacityMin(value) { 43153 this._hdrCapacityMin = value; 43154 this.calculateWeight(); 43155 } 43156 /** 43157 * @see {@link GainMapMetadata.hdrCapacityMin} 43158 * @remarks Logarithmic space 43159 */ get hdrCapacityMax() { 43160 return this._hdrCapacityMax; 43161 } 43162 set hdrCapacityMax(value) { 43163 this._hdrCapacityMax = value; 43164 this.calculateWeight(); 43165 } 43166 /** 43167 * @see {@link GainmapDecodingParameters.maxDisplayBoost} 43168 * @remarks Non Logarithmic space 43169 */ get maxDisplayBoost() { 43170 return this._maxDisplayBoost; 43171 } 43172 set maxDisplayBoost(value) { 43173 this._maxDisplayBoost = Math.max(1, Math.min(65504, value)); 43174 this.calculateWeight(); 43175 } 43176 calculateWeight() { 43177 const val = (Math.log2(this._maxDisplayBoost) - this._hdrCapacityMin) / (this._hdrCapacityMax - this._hdrCapacityMin); 43178 this.uniforms.weightFactor.value = Math.max(0, Math.min(1, val)); 43179 } 43180 /** 43181 * 43182 * @param params 43183 */ constructor({ gamma, offsetHdr, offsetSdr, gainMapMin, gainMapMax, maxDisplayBoost, hdrCapacityMin, hdrCapacityMax, sdr, gainMap }){ 43184 super({ 43185 name: 'GainMapDecoderMaterial', 43186 vertexShader, 43187 fragmentShader, 43188 uniforms: { 43189 sdr: { 43190 value: sdr 43191 }, 43192 gainMap: { 43193 value: gainMap 43194 }, 43195 gamma: { 43196 value: new Vector3(1.0 / gamma[0], 1.0 / gamma[1], 1.0 / gamma[2]) 43197 }, 43198 offsetHdr: { 43199 value: new Vector3().fromArray(offsetHdr) 43200 }, 43201 offsetSdr: { 43202 value: new Vector3().fromArray(offsetSdr) 43203 }, 43204 gainMapMin: { 43205 value: new Vector3().fromArray(gainMapMin) 43206 }, 43207 gainMapMax: { 43208 value: new Vector3().fromArray(gainMapMax) 43209 }, 43210 weightFactor: { 43211 value: (Math.log2(maxDisplayBoost) - hdrCapacityMin) / (hdrCapacityMax - hdrCapacityMin) 43212 } 43213 }, 43214 blending: NoBlending, 43215 depthTest: false, 43216 depthWrite: false 43217 }); 43218 this._maxDisplayBoost = maxDisplayBoost; 43219 this._hdrCapacityMin = hdrCapacityMin; 43220 this._hdrCapacityMax = hdrCapacityMax; 43221 this.needsUpdate = true; 43222 this.uniformsNeedUpdate = true; 43223 } 43224 } 43225 class GainMapNotFoundError extends Error { 43226 } 43227 class XMPMetadataNotFoundError extends Error { 43228 } 43229 const getXMLValue = (xml, tag, defaultValue)=>{ 43230 // Check for attribute format first: tag="value" 43231 const attributeMatch = new RegExp(`${tag}="([^"]*)"`, 'i').exec(xml); 43232 if (attributeMatch) return attributeMatch[1]; 43233 // Check for tag format: <tag>value</tag> or <tag><rdf:li>value</rdf:li>...</tag> 43234 const tagMatch = new RegExp(`<${tag}[^>]*>([\\s\\S]*?)</${tag}>`, 'i').exec(xml); 43235 if (tagMatch) { 43236 // Check if it contains rdf:li elements 43237 const liValues = tagMatch[1].match(/<rdf:li>([^<]*)<\/rdf:li>/g); 43238 if (liValues && liValues.length === 3) { 43239 return liValues.map((v)=>v.replace(/<\/?rdf:li>/g, '')); 43240 } 43241 return tagMatch[1].trim(); 43242 } 43243 if (defaultValue !== undefined) return defaultValue; 43244 throw new Error(`Can't find ${tag} in gainmap metadata`); 43245 }; 43246 const extractXMP = (input)=>{ 43247 let str; 43248 // support node test environment 43249 if (typeof TextDecoder !== 'undefined') str = new TextDecoder().decode(input); 43250 else str = input.toString(); 43251 let start = str.indexOf('<x:xmpmeta'); 43252 while(start !== -1){ 43253 const end = str.indexOf('x:xmpmeta>', start); 43254 const xmpBlock = str.slice(start, end + 10); 43255 try { 43256 const gainMapMin = getXMLValue(xmpBlock, 'hdrgm:GainMapMin', '0'); 43257 const gainMapMax = getXMLValue(xmpBlock, 'hdrgm:GainMapMax'); 43258 const gamma = getXMLValue(xmpBlock, 'hdrgm:Gamma', '1'); 43259 const offsetSDR = getXMLValue(xmpBlock, 'hdrgm:OffsetSDR', '0.015625'); 43260 const offsetHDR = getXMLValue(xmpBlock, 'hdrgm:OffsetHDR', '0.015625'); 43261 // These are always attributes, so we can use a simpler regex 43262 const hdrCapacityMinMatch = /hdrgm:HDRCapacityMin="([^"]*)"/.exec(xmpBlock); 43263 const hdrCapacityMin = hdrCapacityMinMatch ? hdrCapacityMinMatch[1] : '0'; 43264 const hdrCapacityMaxMatch = /hdrgm:HDRCapacityMax="([^"]*)"/.exec(xmpBlock); 43265 if (!hdrCapacityMaxMatch) throw new Error('Incomplete gainmap metadata'); 43266 const hdrCapacityMax = hdrCapacityMaxMatch[1]; 43267 return { 43268 gainMapMin: Array.isArray(gainMapMin) ? gainMapMin.map((v)=>parseFloat(v)) : [ 43269 parseFloat(gainMapMin), 43270 parseFloat(gainMapMin), 43271 parseFloat(gainMapMin) 43272 ], 43273 gainMapMax: Array.isArray(gainMapMax) ? gainMapMax.map((v)=>parseFloat(v)) : [ 43274 parseFloat(gainMapMax), 43275 parseFloat(gainMapMax), 43276 parseFloat(gainMapMax) 43277 ], 43278 gamma: Array.isArray(gamma) ? gamma.map((v)=>parseFloat(v)) : [ 43279 parseFloat(gamma), 43280 parseFloat(gamma), 43281 parseFloat(gamma) 43282 ], 43283 offsetSdr: Array.isArray(offsetSDR) ? offsetSDR.map((v)=>parseFloat(v)) : [ 43284 parseFloat(offsetSDR), 43285 parseFloat(offsetSDR), 43286 parseFloat(offsetSDR) 43287 ], 43288 offsetHdr: Array.isArray(offsetHDR) ? offsetHDR.map((v)=>parseFloat(v)) : [ 43289 parseFloat(offsetHDR), 43290 parseFloat(offsetHDR), 43291 parseFloat(offsetHDR) 43292 ], 43293 hdrCapacityMin: parseFloat(hdrCapacityMin), 43294 hdrCapacityMax: parseFloat(hdrCapacityMax) 43295 }; 43296 } catch (e) { 43297 // Continue searching for another xmpmeta block if this one fails 43298 } 43299 start = str.indexOf('<x:xmpmeta', end); 43300 } 43301 }; 43302 /** 43303 * MPF Extractor (Multi Picture Format Extractor) 43304 * By Henrik S Nilsson 2019 43305 * 43306 * Extracts images stored in images based on the MPF format (found here: https://www.cipa.jp/e/std/std-sec.html 43307 * under "CIPA DC-007-Translation-2021 Multi-Picture Format" 43308 * 43309 * Overly commented, and without intention of being complete or production ready. 43310 * Created to extract depth maps from iPhone images, and to learn about image metadata. 43311 * Kudos to: Phil Harvey (exiftool), Jaume Sanchez (android-lens-blur-depth-extractor) 43312 */ class MPFExtractor { 43313 extract(imageArrayBuffer) { 43314 return new Promise((resolve, reject)=>{ 43315 const debug = this.options.debug; 43316 const dataView = new DataView(imageArrayBuffer.buffer); 43317 // If you're executing this line on a big endian machine, it'll be reversed. 43318 // bigEnd further down though, refers to the endianness of the image itself. 43319 if (dataView.getUint16(0) !== 0xffd8) { 43320 reject(new Error('Not a valid jpeg')); 43321 return; 43322 } 43323 const length = dataView.byteLength; 43324 let offset = 2; 43325 let loops = 0; 43326 let marker; // APP# marker 43327 while(offset < length){ 43328 if (++loops > 250) { 43329 reject(new Error(`Found no marker after ${loops} loops ðµ`)); 43330 return; 43331 } 43332 if (dataView.getUint8(offset) !== 0xff) { 43333 reject(new Error(`Not a valid marker at offset 0x${offset.toString(16)}, found: 0x${dataView.getUint8(offset).toString(16)}`)); 43334 return; 43335 } 43336 marker = dataView.getUint8(offset + 1); 43337 if (debug) console.log(`Marker: ${marker.toString(16)}`); 43338 if (marker === 0xe2) { 43339 if (debug) console.log('Found APP2 marker (0xffe2)'); 43340 // Works for iPhone 8 Plus, X, and XSMax. Or any photos of MPF format. 43341 // Great way to visualize image information in html is using Exiftool. E.g.: 43342 // ./exiftool.exe -htmldump -wantTrailer photo.jpg > photo.html 43343 const formatPt = offset + 4; 43344 /* 43345 * Structure of the MP Format Identifier 43346 * 43347 * Offset Addr. | Code (Hex) | Description 43348 * +00 ff Marker Prefix <-- offset 43349 * +01 e2 APP2 43350 * +02 #n APP2 Field Length 43351 * +03 #n APP2 Field Length 43352 * +04 4d 'M' <-- formatPt 43353 * +05 50 'P' 43354 * +06 46 'F' 43355 * +07 00 NULL 43356 * <-- tiffOffset 43357 */ if (dataView.getUint32(formatPt) === 0x4d504600) { 43358 // Found MPF tag, so we start dig out sub images 43359 const tiffOffset = formatPt + 4; 43360 let bigEnd; // Endianness from TIFF header 43361 // Test for TIFF validity and endianness 43362 // 0x4949 and 0x4D4D ('II' and 'MM') marks Little Endian and Big Endian 43363 if (dataView.getUint16(tiffOffset) === 0x4949) { 43364 bigEnd = false;
vendor: 4,099 bytes, lines 43365-43422
43365 } else if (dataView.getUint16(tiffOffset) === 0x4d4d) { 43366 bigEnd = true; 43367 } else { 43368 reject(new Error('No valid endianness marker found in TIFF header')); 43369 return; 43370 } 43371 if (dataView.getUint16(tiffOffset + 2, !bigEnd) !== 0x002a) { 43372 reject(new Error('Not valid TIFF data! (no 0x002A marker)')); 43373 return; 43374 } 43375 // 32 bit number stating the offset from the start of the 8 Byte MP Header 43376 // to MP Index IFD Least possible value is thus 8 (means 0 offset) 43377 const firstIFDOffset = dataView.getUint32(tiffOffset + 4, !bigEnd); 43378 if (firstIFDOffset < 0x00000008) { 43379 reject(new Error('Not valid TIFF data! (First offset less than 8)')); 43380 return; 43381 } 43382 // Move ahead to MP Index IFD 43383 // Assume we're at the first IFD, so firstIFDOffset points to 43384 // MP Index IFD and not MP Attributes IFD. (If we try extract from a sub image, 43385 // we fail silently here due to this assumption) 43386 // Count (2 Byte) | MP Index Fields a.k.a. MP Entries (count * 12 Byte) | Offset of Next IFD (4 Byte) 43387 const dirStart = tiffOffset + firstIFDOffset; // Start of IFD (Image File Directory) 43388 const count = dataView.getUint16(dirStart, !bigEnd); // Count of MPEntries (2 Byte) 43389 // Extract info from MPEntries (starting after Count) 43390 const entriesStart = dirStart + 2; 43391 let numberOfImages = 0; 43392 for(let i = entriesStart; i < entriesStart + 12 * count; i += 12){ 43393 // Each entry is 12 Bytes long 43394 // Check MP Index IFD tags, here we only take tag 0xb001 = Number of images 43395 if (dataView.getUint16(i, !bigEnd) === 0xb001) { 43396 // stored in Last 4 bytes of its 12 Byte entry. 43397 numberOfImages = dataView.getUint32(i + 8, !bigEnd); 43398 } 43399 } 43400 const nextIFDOffsetLen = 4; // 4 Byte offset field that appears after MP Index IFD tags 43401 const MPImageListValPt = dirStart + 2 + count * 12 + nextIFDOffsetLen; 43402 const images = []; 43403 for(let i = MPImageListValPt; i < MPImageListValPt + numberOfImages * 16; i += 16){ 43404 const image = { 43405 MPType: dataView.getUint32(i, !bigEnd), 43406 size: dataView.getUint32(i + 4, !bigEnd), 43407 // This offset is specified relative to the address of the MP Endian 43408 // field in the MP Header, unless the image is a First Individual Image, 43409 // in which case the value of the offset shall be NULL (0x00000000). 43410 dataOffset: dataView.getUint32(i + 8, !bigEnd), 43411 dependantImages: dataView.getUint32(i + 12, !bigEnd), 43412 start: -1, 43413 end: -1, 43414 isFII: false 43415 }; 43416 if (!image.dataOffset) { 43417 // dataOffset is 0x00000000 for First Individual Image 43418 image.start = 0; 43419 image.isFII = true; 43420 } else { 43421 image.start = tiffOffset + image.dataOffset; 43422 image.isFII = false;
vendor: 4,205 bytes, lines 43423-43533
43423 } 43424 image.end = image.start + image.size; 43425 images.push(image); 43426 } 43427 if (this.options.extractNonFII && images.length) { 43428 const bufferBlob = new Blob([ 43429 dataView 43430 ]); 43431 const imgs = []; 43432 for (const image of images){ 43433 if (image.isFII && !this.options.extractFII) { 43434 continue; // Skip FII 43435 } 43436 const imageBlob = bufferBlob.slice(image.start, image.end + 1, 'image/jpeg'); 43437 // we don't need this 43438 // const imageUrl = URL.createObjectURL(imageBlob) 43439 // image.img = document.createElement('img') 43440 // image.img.src = imageUrl 43441 imgs.push(imageBlob); 43442 } 43443 resolve(imgs); 43444 } 43445 } 43446 } 43447 offset += 2 + dataView.getUint16(offset + 2); 43448 } 43449 }); 43450 } 43451 constructor(options){ 43452 this.options = { 43453 debug: options && options.debug !== undefined ? options.debug : false, 43454 extractFII: options && options.extractFII !== undefined ? options.extractFII : true, 43455 extractNonFII: options && options.extractNonFII !== undefined ? options.extractNonFII : true 43456 }; 43457 } 43458 } 43459 /** 43460 * Extracts XMP Metadata and the gain map recovery image 43461 * from a single JPEG file. 43462 * 43463 * @category Decoding Functions 43464 * @group Decoding Functions 43465 * @param jpegFile an `Uint8Array` containing and encoded JPEG file 43466 * @returns an sdr `Uint8Array` compressed in JPEG, a gainMap `Uint8Array` compressed in JPEG and the XMP parsed XMP metadata 43467 * @throws Error if XMP Metadata is not found 43468 * @throws Error if Gain map image is not found 43469 * @example 43470 * import { FileLoader } from 'three' 43471 * import { extractGainmapFromJPEG } from '@monogrid/gainmap-js' 43472 * 43473 * const jpegFile = await new FileLoader() 43474 * .setResponseType('arraybuffer') 43475 * .loadAsync('image.jpg') 43476 * 43477 * const { sdr, gainMap, metadata } = extractGainmapFromJPEG(jpegFile) 43478 */ const extractGainmapFromJPEG = async (jpegFile)=>{ 43479 const metadata = extractXMP(jpegFile); 43480 if (!metadata) throw new XMPMetadataNotFoundError('Gain map XMP metadata not found'); 43481 const mpfExtractor = new MPFExtractor({ 43482 extractFII: true, 43483 extractNonFII: true 43484 }); 43485 const images = await mpfExtractor.extract(jpegFile); 43486 if (images.length !== 2) throw new GainMapNotFoundError('Gain map recovery image not found'); 43487 return { 43488 sdr: new Uint8Array(await images[0].arrayBuffer()), 43489 gainMap: new Uint8Array(await images[1].arrayBuffer()), 43490 metadata 43491 }; 43492 }; 43493 /** 43494 * private function, async get image from blob 43495 * 43496 * @param blob 43497 * @returns 43498 */ const getHTMLImageFromBlob = (blob)=>{ 43499 return new Promise((resolve, reject)=>{ 43500 const img = document.createElement('img'); 43501 img.onload = ()=>{ 43502 resolve(img); 43503 }; 43504 img.onerror = (e)=>{ 43505 reject(e); 43506 }; 43507 img.src = URL.createObjectURL(blob); 43508 }); 43509 }; 43510 class LoaderBase extends Loader { 43511 /** 43512 * Specify the renderer to use when rendering the gain map 43513 * 43514 * @param renderer 43515 * @returns 43516 */ setRenderer(renderer) { 43517 this._renderer = renderer; 43518 return this; 43519 } 43520 /** 43521 * Specify the renderTarget options to use when rendering the gain map 43522 * 43523 * @param options 43524 * @returns 43525 */ setRenderTargetOptions(options) { 43526 this._renderTargetOptions = options; 43527 return this; 43528 } 43529 /** 43530 * @private 43531 * @returns 43532 */ prepareQuadRenderer() { 43533 if (!this._renderer) console.warn('WARNING: An existing WebGL Renderer was not passed to this Loa
43533der constructor or in setRenderer, the result of this Loader will need to be converted to a Data Texture with toDataTexture() before you can use it in your renderer.'); 43534 // temporary values 43535 const material = new GainMapDecoderMaterial({ 43536 gainMapMax: [ 43537 1, 43538 1, 43539 1 43540 ], 43541 gainMapMin: [ 43542 0, 43543 0, 43544 0 43545 ], 43546 gamma: [ 43547 1, 43548 1, 43549 1 43550 ], 43551 offsetHdr: [ 43552 1, 43553 1, 43554 1 43555 ], 43556 offsetSdr: [ 43557 1, 43558 1, 43559 1 43560 ], 43561 hdrCapacityMax: 1, 43562 hdrCapacityMin: 0, 43563 maxDisplayBoost: 1, 43564 gainMap: new Texture$1(), 43565 sdr: new Texture$1() 43566 }); 43567 return new QuadRenderer({ 43568 width: 16, 43569 height: 16, 43570 type: HalfFloatType, 43571 colorSpace: LinearSRGBColorSpace, 43572 material, 43573 renderer: this._renderer, 43574 renderTargetOptions: this._renderTargetOptions 43575 }); 43576 } 43577 /** 43578 * @private 43579 * @param quadRenderer 43580 * @param metadata 43581 * @param sdrBuffer 43582 * @param gainMapBuffer 43583 */ async render(quadRenderer, metadata, sdrBuffer, gainMapBuffer) { 43584 // this is optional, will render a black gain-map if not present 43585 const gainMapBlob = gainMapBuffer ? new Blob([ 43586 gainMapBuffer 43587 ], { 43588 type: 'image/jpeg' 43589 }) : undefined; 43590 const sdrBlob = new Blob([ 43591 sdrBuffer 43592 ], { 43593 type: 'image/jpeg' 43594 }); 43595 let sdrImage; 43596 let gainMapImage; 43597 let needsFlip = false; 43598 if (typeof createImageBitmap === 'undefined') { 43599 const res = await Promise.all([ 43600 gainMapBlob ? getHTMLImageFromBlob(gainMapBlob) : Promise.resolve(undefined), 43601 getHTMLImageFromBlob(sdrBlob) 43602 ]); 43603 gainMapImage = res[0]; 43604 sdrImage = res[1]; 43605 needsFlip = true; 43606 } else { 43607 const res = await Promise.all([ 43608 gainMapBlob ? createImageBitmap(gainMapBlob, { 43609 imageOrientation: 'flipY' 43610 }) : Promise.resolve(undefined), 43611 createImageBitmap(sdrBlob, { 43612 imageOrientation: 'flipY' 43613 }) 43614 ]); 43615 gainMapImage = res[0]; 43616 sdrImage = res[1]; 43617 } 43618 const gainMap = new Texture$1(gainMapImage || new ImageData(2, 2), UVMapping, ClampToEdgeWrapping, ClampToEdgeWrapping, LinearFilter, LinearMipMapLinearFilter, RGBAFormat, UnsignedByteType, 1, LinearSRGBColorSpace); 43619 gainMap.flipY = needsFlip; 43620 gainMap.needsUpdate = true; 43621 const sdr = new Texture$1(sdrImage, UVMapping, ClampToEdgeWrapping, ClampToEdgeWrapping, LinearFilter, LinearMipMapLinearFilter, RGBAFormat, UnsignedByteType, 1, SRGBColorSpace); 43622 sdr.flipY = needsFlip; 43623 sdr.needsUpdate = true; 43624 quadRenderer.width = sdrImage.width; 43625 quadRenderer.height = sdrImage.height; 43626 quadRenderer.material.gainMap = gainMap; 43627 quadRenderer.material.sdr = sdr; 43628 quadRenderer.material.gainMapMin = metadata.gainMapMin; 43629 quadRenderer.material.gainMapMax = metadata.gainMapMax; 43630 quadRenderer.material.offsetHdr = metadata.offsetHdr; 43631 quadRenderer.material.offsetSdr = metadata.offsetSdr; 43632 quadRenderer.material.gamma = metadata.gamma; 43633 quadRenderer.material.hdrCapacityMin = metadata.hdrCapacityMin; 43634 quadRenderer.material.hdrCapacityMax = metadata.hdrCapacityMax; 43635 quadRenderer.material.maxDisplayBoost = Math.pow(2, metadata.hdrCapacityMax); 43636 quadRenderer.material.needsUpdate = true; 43637 quadRenderer.render(); 43638 } 43639 /** 43640 * 43641 * @param renderer 43642 * @param manager 43643 */ constructor(renderer, manager){ 43644 super(manager); 43645 if (renderer) this._renderer = renderer; 43646 this._internalLoadingManager = new LoadingManager(); 43647 } 43648 } 43649 /** 43650 * A Three.js Loader for a JPEG with embedded gainmap metadata. 43651 * 43652 * @category Loaders 43653 * @group Loaders 43654 * 43655 * @example 43656 * import { HDRJPGLoader } from '@monogrid/gainmap-js' 43657 * import { 43658 * EquirectangularReflectionMapping, 43659 * LinearFilter, 43660 * Mesh, 43661 * MeshBasicMaterial, 43662 * PerspectiveCamera, 43663 * PlaneGeometry, 43664 * Scene, 43665 * WebGLRenderer 43666 * } from 'three' 43667 * 43668 * const renderer = new WebGLRenderer() 43669 * 43670 * const loader = new HDRJPGLoader(renderer) 43671 * 43672 * const result = await loader.loadAsync('gainmap.jpeg') 43673 * // `result` can be used to populate a Texture 43674 * 43675 * const scene = new Scene() 43676 * const mesh = new Mesh( 43677 * new PlaneGeometry(), 43678 * new MeshBasicMaterial({ map: result.renderTarget.texture }) 43679 * ) 43680 * scene.add(mesh) 43681 * renderer.render(scene, new PerspectiveCamera()) 43682 * 43683 * // Starting from three.js r159 43684 * // `result.renderTarget.texture` can 43685 * // also be used as Equirectangular scene background 43686 * // 43687 * // it was previously needed to convert it 43688 * // to a DataTexture with `result.toDataTexture()` 43689 * scene.background = result.renderTarget.texture 43690 * scene.background.mapping = EquirectangularReflectionMapping 43691 * 43692 * // result must be manually disposed 43693 * // when you are done using it 43694 * result.dispose() 43695 * 43696 */ class HDRJPGLoader extends LoaderBase { 43697 /** 43698 * Loads a JPEG containing gain map metadata
vendor: 6,231 bytes, lines 43699-43826
43699 * Renders a normal SDR image if gainmap data is not found 43700 * 43701 * @param url An array in the form of [sdr.jpg, gainmap.jpg, metadata.json] 43702 * @param onLoad Load complete callback, will receive the result 43703 * @param onProgress Progress callback, will receive a {@link ProgressEvent} 43704 * @param onError Error callback 43705 * @returns 43706 */ load(url, onLoad, onProgress, onError) { 43707 const quadRenderer = this.prepareQuadRenderer(); 43708 const loader = new FileLoader(this._internalLoadingManager); 43709 loader.setResponseType('arraybuffer'); 43710 loader.setRequestHeader(this.requestHeader); 43711 loader.setPath(this.path); 43712 loader.setWithCredentials(this.withCredentials); 43713 this.manager.itemStart(url); 43714 loader.load(url, async (jpeg)=>{ 43715 /* istanbul ignore if 43716 this condition exists only because of three.js types + strict mode 43717 */ if (typeof jpeg === 'string') throw new Error('Invalid buffer, received [string], was expecting [ArrayBuffer]'); 43718 const jpegBuffer = new Uint8Array(jpeg); 43719 let sdrJPEG; 43720 let gainMapJPEG; 43721 let metadata; 43722 try { 43723 const extractionResult = await extractGainmapFromJPEG(jpegBuffer); 43724 // gain map is successfully reconstructed 43725 sdrJPEG = extractionResult.sdr; 43726 gainMapJPEG = extractionResult.gainMap; 43727 metadata = extractionResult.metadata; 43728 } catch (e) { 43729 // render the SDR version if this is not a gainmap 43730 if (e instanceof XMPMetadataNotFoundError || e instanceof GainMapNotFoundError) { 43731 console.warn(`Failure to reconstruct an HDR image from ${url}: Gain map metadata not found in the file, HDRJPGLoader will render the SDR jpeg`); 43732 metadata = { 43733 gainMapMin: [ 43734 0, 43735 0, 43736 0 43737 ], 43738 gainMapMax: [ 43739 1, 43740 1, 43741 1 43742 ], 43743 gamma: [ 43744 1, 43745 1, 43746 1 43747 ], 43748 hdrCapacityMin: 0, 43749 hdrCapacityMax: 1, 43750 offsetHdr: [ 43751 0, 43752 0, 43753 0 43754 ], 43755 offsetSdr: [ 43756 0, 43757 0, 43758 0 43759 ] 43760 }; 43761 sdrJPEG = jpegBuffer; 43762 } else { 43763 throw e; 43764 } 43765 } 43766 // solves #16 43767 try { 43768 await this.render(quadRenderer, metadata, sdrJPEG, gainMapJPEG); 43769 } catch (error) { 43770 this.manager.itemError(url); 43771 if (typeof onError === 'function') onError(error); 43772 quadRenderer.disposeOnDemandRenderer(); 43773 return; 43774 } 43775 if (typeof onLoad === 'function') onLoad(quadRenderer); 43776 this.manager.itemEnd(url); 43777 quadRenderer.disposeOnDemandRenderer(); 43778 }, onProgress, (error)=>{ 43779 this.manager.itemError(url); 43780 if (typeof onError === 'function') onError(error); 43781 }); 43782 return quadRenderer; 43783 } 43784 } 43785 43786 // https://github.com/mrdoob/three.js/issues/5552 43787 // http://en.wikipedia.org/wiki/RGBE_image_format 43788 class RGBELoader extends DataTextureLoader { 43789 // adapted from http://www.graphics.cornell.edu/~bjw/rgbe.html 43790 parse(buffer) { 43791 const /* default error routine. change this to change error handling */ rgbe_read_error = 1, rgbe_write_error = 2, rgbe_format_error = 3, rgbe_memory_error = 4, rgbe_error = function(rgbe_error_code, msg) { 43792 switch(rgbe_error_code){ 43793 case rgbe_read_error: 43794 throw new Error('THREE.RGBELoader: Read Error: ' + (msg || '')); 43795 case rgbe_write_error: 43796 throw new Error('THREE.RGBELoader: Write Error: ' + (msg || '')); 43797 case rgbe_format_error: 43798 throw new Error('THREE.RGBELoader: Bad File Format: ' + (msg || '')); 43799 default: 43800 case rgbe_memory_error: 43801 throw new Error('THREE.RGBELoader: Memory Error: ' + (msg || '')); 43802 } 43803 }, /* offsets to red, green, and blue components in a data (float) pixel */ //RGBE_DATA_RED = 0, 43804 //RGBE_DATA_GREEN = 1, 43805 //RGBE_DATA_BLUE = 2, 43806 /* number of floats per pixel, use 4 since stored in rgba image format */ //RGBE_DATA_SIZE = 4, 43807 /* flags indicating which fields in an rgbe_header_info are valid */ RGBE_VALID_PROGRAMTYPE = 1, RGBE_VALID_FORMAT = 2, RGBE_VALID_DIMENSIONS = 4, NEWLINE = '\n', fgets = function(buffer, lineLimit, consume) { 43808 const chunkSize = 128; 43809 lineLimit = !lineLimit ? 1024 : lineLimit; 43810 let p = buffer.pos, i = -1, len = 0, s = '', chunk = String.fromCharCode.apply(null, new Uint16Array(buffer.subarray(p, p + chunkSize))); 43811 while(0 > (i = chunk.indexOf(NEWLINE)) && len < lineLimit && p < buffer.byteLength){ 43812 s += chunk; 43813 len += chunk.length; 43814 p += chunkSize; 43815 chunk += String.fromCharCode.apply(null, new Uint16Array(buffer.subarray(p, p + chunkSize))); 43816 } 43817 if (-1 < i) { 43818 /*for (i=l-1; i>=0; i--) { 43819 byteCode = m.charCodeAt(i); 43820 if (byteCode > 0x7f && byteCode <= 0x7ff) byteLen++; 43821 else if (byteCode > 0x7ff && byteCode <= 0xffff) byteLen += 2; 43822 if (byteCode >= 0xDC00 && byteCode <= 0xDFFF) i--; //trail surrogate 43823 }*/ buffer.pos += len + i + 1; 43824 return s + chunk.slice(0, i); 43825 } 43826 return false;
vendor: 6,994 bytes, lines 43827-43956
43827 }, /* minimal header reading. modify if you want to parse more information */ RGBE_ReadHeader = function(buffer) { 43828 // regexes to parse header info fields 43829 const magic_token_re = /^#\?(\S+)/, gamma_re = /^\s*GAMMA\s*=\s*(\d+(\.\d+)?)\s*$/, exposure_re = /^\s*EXPOSURE\s*=\s*(\d+(\.\d+)?)\s*$/, format_re = /^\s*FORMAT=(\S+)\s*$/, dimensions_re = /^\s*\-Y\s+(\d+)\s+\+X\s+(\d+)\s*$/, // RGBE format header struct 43830 header = { 43831 valid: 0, 43832 /* indicate which fields are valid */ string: '', 43833 /* the actual header string */ comments: '', 43834 /* comments found in header */ programtype: 'RGBE', 43835 /* listed at beginning of file to identify it after "#?". defaults to "RGBE" */ format: '', 43836 /* RGBE format, default 32-bit_rle_rgbe */ gamma: 1.0, 43837 /* image has already been gamma corrected with given gamma. defaults to 1.0 (no correction) */ exposure: 1.0, 43838 /* a value of 1.0 in an image corresponds to <exposure> watts/steradian/m^2. defaults to 1.0 */ width: 0, 43839 height: 0 /* image dimensions, width/height */ 43840 }; 43841 let line, match; 43842 if (buffer.pos >= buffer.byteLength || !(line = fgets(buffer))) { 43843 rgbe_error(rgbe_read_error, 'no header found'); 43844 } 43845 /* if you want to require the magic token then uncomment the next line */ if (!(match = line.match(magic_token_re))) { 43846 rgbe_error(rgbe_format_error, 'bad initial token'); 43847 } 43848 header.valid |= RGBE_VALID_PROGRAMTYPE; 43849 header.programtype = match[1]; 43850 header.string += line + '\n'; 43851 while(true){ 43852 line = fgets(buffer); 43853 if (false === line) break; 43854 header.string += line + '\n'; 43855 if ('#' === line.charAt(0)) { 43856 header.comments += line + '\n'; 43857 continue; // comment line 43858 } 43859 if (match = line.match(gamma_re)) { 43860 header.gamma = parseFloat(match[1]); 43861 } 43862 if (match = line.match(exposure_re)) { 43863 header.exposure = parseFloat(match[1]); 43864 } 43865 if (match = line.match(format_re)) { 43866 header.valid |= RGBE_VALID_FORMAT; 43867 header.format = match[1]; //'32-bit_rle_rgbe'; 43868 } 43869 if (match = line.match(dimensions_re)) { 43870 header.valid |= RGBE_VALID_DIMENSIONS; 43871 header.height = parseInt(match[1], 10); 43872 header.width = parseInt(match[2], 10); 43873 } 43874 if (header.valid & RGBE_VALID_FORMAT && header.valid & RGBE_VALID_DIMENSIONS) break; 43875 } 43876 if (!(header.valid & RGBE_VALID_FORMAT)) { 43877 rgbe_error(rgbe_format_error, 'missing format specifier'); 43878 } 43879 if (!(header.valid & RGBE_VALID_DIMENSIONS)) { 43880 rgbe_error(rgbe_format_error, 'missing image size specifier'); 43881 } 43882 return header; 43883 }, RGBE_ReadPixels_RLE = function(buffer, w, h) { 43884 const scanline_width = w; 43885 if (scanline_width < 8 || scanline_width > 0x7fff || // this file is not run length encoded 43886 2 !== buffer[0] || 2 !== buffer[1] || buffer[2] & 0x80) { 43887 // return the flat buffer 43888 return new Uint8Array(buffer); 43889 } 43890 if (scanline_width !== (buffer[2] << 8 | buffer[3])) { 43891 rgbe_error(rgbe_format_error, 'wrong scanline width'); 43892 } 43893 const data_rgba = new Uint8Array(4 * w * h); 43894 if (!data_rgba.length) { 43895 rgbe_error(rgbe_memory_error, 'unable to allocate buffer space'); 43896 } 43897 let offset = 0, pos = 0; 43898 const ptr_end = 4 * scanline_width; 43899 const rgbeStart = new Uint8Array(4); 43900 const scanline_buffer = new Uint8Array(ptr_end); 43901 let num_scanlines = h; 43902 // read in each successive scanline 43903 while(num_scanlines > 0 && pos < buffer.byteLength){ 43904 if (pos + 4 > buffer.byteLength) { 43905 rgbe_error(rgbe_read_error); 43906 } 43907 rgbeStart[0] = buffer[pos++]; 43908 rgbeStart[1] = buffer[pos++]; 43909 rgbeStart[2] = buffer[pos++]; 43910 rgbeStart[3] = buffer[pos++]; 43911 if (2 != rgbeStart[0] || 2 != rgbeStart[1] || (rgbeStart[2] << 8 | rgbeStart[3]) != scanline_width) { 43912 rgbe_error(rgbe_format_error, 'bad rgbe scanline format'); 43913 } 43914 // read each of the four channels for the scanline into the buffer 43915 // first red, then green, then blue, then exponent 43916 let ptr = 0, count; 43917 while(ptr < ptr_end && pos < buffer.byteLength){ 43918 count = buffer[pos++]; 43919 const isEncodedRun = count > 128; 43920 if (isEncodedRun) count -= 128; 43921 if (0 === count || ptr + count > ptr_end) { 43922 rgbe_error(rgbe_format_error, 'bad scanline data'); 43923 } 43924 if (isEncodedRun) { 43925 // a (encoded) run of the same value 43926 const byteValue = buffer[pos++]; 43927 for(let i = 0; i < count; i++){ 43928 scanline_buffer[ptr++] = byteValue; 43929 } 43930 //ptr += count; 43931 } else { 43932 // a literal-run 43933 scanline_buffer.set(buffer.subarray(pos, pos + count), ptr); 43934 ptr += count; 43935 pos += count; 43936 } 43937 } 43938 // now convert data from buffer into rgba 43939 // first red, then green, then blue, then exponent (alpha) 43940 const l = scanline_width; //scanline_buffer.byteLength; 43941 for(let i = 0; i < l; i++){ 43942 let off = 0; 43943 data_rgba[offset] = scanline_buffer[i + off]; 43944 off += scanline_width; //1; 43945 data_rgba[offset + 1] = scanline_buffer[i + off]; 43946 off += scanline_width; //1; 43947 data_rgba[offset + 2] = scanline_buffer[i + off]; 43948 off += scanline_width; //1; 43949 data_rgba[offset + 3] = scanline_buffer[i + off]; 43950 offset += 4; 43951 } 43952 num_scanlines--; 43953 } 43954 return data_rgba; 43955 }; 43956 const RGBEByteToRGBFloat = function(sourceArray, sourceOffset, destArray, destOff
vendor: 14,181 bytes, lines 43956-44493
43956set) { 43957 const e = sourceArray[sourceOffset + 3]; 43958 const scale = Math.pow(2.0, e - 128.0) / 255.0; 43959 destArray[destOffset + 0] = sourceArray[sourceOffset + 0] * scale; 43960 destArray[destOffset + 1] = sourceArray[sourceOffset + 1] * scale; 43961 destArray[destOffset + 2] = sourceArray[sourceOffset + 2] * scale; 43962 destArray[destOffset + 3] = 1; 43963 }; 43964 const RGBEByteToRGBHalf = function(sourceArray, sourceOffset, destArray, destOffset) { 43965 const e = sourceArray[sourceOffset + 3]; 43966 const scale = Math.pow(2.0, e - 128.0) / 255.0; 43967 // clamping to 65504, the maximum representable value in float16 43968 destArray[destOffset + 0] = DataUtils.toHalfFloat(Math.min(sourceArray[sourceOffset + 0] * scale, 65504)); 43969 destArray[destOffset + 1] = DataUtils.toHalfFloat(Math.min(sourceArray[sourceOffset + 1] * scale, 65504)); 43970 destArray[destOffset + 2] = DataUtils.toHalfFloat(Math.min(sourceArray[sourceOffset + 2] * scale, 65504)); 43971 destArray[destOffset + 3] = DataUtils.toHalfFloat(1); 43972 }; 43973 const byteArray = new Uint8Array(buffer); 43974 byteArray.pos = 0; 43975 const rgbe_header_info = RGBE_ReadHeader(byteArray); 43976 const w = rgbe_header_info.width, h = rgbe_header_info.height, image_rgba_data = RGBE_ReadPixels_RLE(byteArray.subarray(byteArray.pos), w, h); 43977 let data, type; 43978 let numElements; 43979 switch(this.type){ 43980 case FloatType: 43981 numElements = image_rgba_data.length / 4; 43982 const floatArray = new Float32Array(numElements * 4); 43983 for(let j = 0; j < numElements; j++){ 43984 RGBEByteToRGBFloat(image_rgba_data, j * 4, floatArray, j * 4); 43985 } 43986 data = floatArray; 43987 type = FloatType; 43988 break; 43989 case HalfFloatType: 43990 numElements = image_rgba_data.length / 4; 43991 const halfArray = new Uint16Array(numElements * 4); 43992 for(let j = 0; j < numElements; j++){ 43993 RGBEByteToRGBHalf(image_rgba_data, j * 4, halfArray, j * 4); 43994 } 43995 data = halfArray; 43996 type = HalfFloatType; 43997 break; 43998 default: 43999 throw new Error('THREE.RGBELoader: Unsupported type: ' + this.type); 44000 } 44001 return { 44002 width: w, 44003 height: h, 44004 data: data, 44005 header: rgbe_header_info.string, 44006 gamma: rgbe_header_info.gamma, 44007 exposure: rgbe_header_info.exposure, 44008 type: type 44009 }; 44010 } 44011 setDataType(value) { 44012 this.type = value; 44013 return this; 44014 } 44015 load(url, onLoad, onProgress, onError) { 44016 function onLoadCallback(texture, texData) { 44017 switch(texture.type){ 44018 case FloatType: 44019 case HalfFloatType: 44020 texture.colorSpace = LinearSRGBColorSpace; 44021 texture.minFilter = LinearFilter; 44022 texture.magFilter = LinearFilter; 44023 texture.generateMipmaps = false; 44024 texture.flipY = true; 44025 break; 44026 } 44027 if (onLoad) onLoad(texture, texData); 44028 } 44029 return super.load(url, onLoadCallback, onProgress, onError); 44030 } 44031 constructor(manager){ 44032 super(manager); 44033 this.type = HalfFloatType; 44034 } 44035 } 44036 44037 const legacy = { 44038 topLight: { 44039 intensity: 500, 44040 position: [ 44041 0.418, 44042 16.199, 44043 0.300 44044 ] 44045 }, 44046 room: { 44047 position: [ 44048 -0.757, 44049 13.219, 44050 0.717 44051 ], 44052 scale: [ 44053 31.713, 44054 28.305, 44055 28.591 44056 ] 44057 }, 44058 boxes: [ 44059 { 44060 position: [ 44061 -10.906, 44062 2.009, 44063 1.846 44064 ], 44065 rotation: -0.195, 44066 scale: [ 44067 2.328, 44068 7.905, 44069 4.651 44070 ] 44071 }, 44072 { 44073 position: [ 44074 -5.607, 44075 -0.754, 44076 -0.758 44077 ], 44078 rotation: 0.994, 44079 scale: [ 44080 1.970, 44081 1.534, 44082 3.955 44083 ] 44084 }, 44085 { 44086 position: [ 44087 6.167, 44088 0.857, 44089 7.803 44090 ], 44091 rotation: 0.561, 44092 scale: [ 44093 3.927, 44094 6.285, 44095 3.687 44096 ] 44097 }, 44098 { 44099 position: [ 44100 -2.017, 44101 0.018, 44102 6.124 44103 ], 44104 rotation: 0.333, 44105 scale: [ 44106 2.002, 44107 4.566, 44108 2.064 44109 ] 44110 }, 44111 { 44112 position: [ 44113 2.291, 44114 -0.756, 44115 -2.621 44116 ], 44117 rotation: -0.286, 44118 scale: [ 44119 1.546, 44120 1.552, 44121 1.496 44122 ] 44123 }, 44124 { 44125 position: [ 44126 -2.193, 44127 -0.369, 44128 -5.547 44129 ], 44130 rotation: 0.516, 44131 scale: [ 44132 3.875, 44133 3.487, 44134 2.986 44135 ] 44136 } 44137 ], 44138 lights: [ 44139 { 44140 intensity: 50, 44141 position: [ 44142 -16.116, 44143 14.37, 44144 8.208 44145 ], 44146 scale: [ 44147 0.1, 44148 2.428, 44149 2.739 44150 ] 44151 }, 44152 { 44153 intensity: 50, 44154 position: [ 44155 -16.109, 44156 18.021, 44157 -8.207 44158 ], 44159 scale: [ 44160 0.1, 44161 2.425, 44162 2.751 44163 ] 44164 }, 44165 { 44166 intensity: 17, 44167 position: [ 44168 14.904, 44169 12.198, 44170 -1.832 44171 ], 44172 scale: [ 44173 0.15, 44174 4.265, 44175 6.331 44176 ] 44177 }, 44178 { 44179 intensity: 43, 44180 position: [ 44181 -0.462, 44182 8.89, 44183 14.520 44184 ], 44185 scale: [ 44186 4.38, 44187 5.441, 44188 0.088 44189 ] 44190 }, 44191 { 44192 intensity: 20, 44193 position: [ 44194 3.235, 44195 11.486, 44196 -12.541 44197 ], 44198 scale: [ 44199 2.5, 44200 2.0, 44201 0.1 44202 ] 44203 }, 44204 { 44205 intensity: 100, 44206 position: [ 44207 0.0, 44208 20.0, 44209 0.0 44210 ], 44211 scale: [ 44212 1.0, 44213 0.1, 44214 1.0 44215 ] 44216 } 44217 ] 44218 }; 44219 const neutral = { 44220 topLight: { 44221 intensity: 400, 44222 position: [ 44223 0.5, 44224 14.0, 44225 0.5 44226 ] 44227 }, 44228 room: { 44229 position: [ 44230 0.0, 44231 13.2, 44232 0.0 44233 ], 44234 scale: [ 44235 31.5, 44236 28.5, 44237 31.5 44238 ] 44239 }, 44240 boxes: [ 44241 { 44242 position: [ 44243 -10.906, 44244 -1, 44245 1.846 44246 ], 44247 rotation: -0.195, 44248 scale: [ 44249 2.328, 44250 7.905, 44251 4.651 44252 ] 44253 }, 44254 { 44255 position: [ 44256 -5.607, 44257 -0.754, 44258 -0.758 44259 ], 44260 rotation: 0.994, 44261 scale: [ 44262 1.970, 44263 1.534, 44264 3.955 44265 ] 44266 }, 44267 { 44268 position: [ 44269 6.167, 44270 -0.16, 44271 7.803 44272 ], 44273 rotation: 0.561, 44274 scale: [ 44275 3.927, 44276 6.285, 44277 3.687 44278 ] 44279 }, 44280 { 44281 position: [ 44282 -2.017, 44283 0.018, 44284 6.124 44285 ], 44286 rotation: 0.333, 44287 scale: [ 44288 2.002, 44289 4.566, 44290 2.064 44291 ] 44292 }, 44293 { 44294 position: [ 44295 2.291, 44296 -0.756, 44297 -2.621 44298 ], 44299 rotation: -0.286, 44300 scale: [ 44301 1.546, 44302 1.552, 44303 1.496 44304 ] 44305 }, 44306 { 44307 position: [ 44308 -2.193, 44309 -0.369, 44310 -5.547 44311 ], 44312 rotation: 0.516, 44313 scale: [ 44314 3.875, 44315 3.487, 44316 2.986 44317 ] 44318 } 44319 ], 44320 lights: [ 44321 { 44322 intensity: 80, 44323 position: [ 44324 -14, 44325 10.0, 44326 8.0 44327 ], 44328 scale: [ 44329 0.1, 44330 2.5, 44331 2.5 44332 ] 44333 }, 44334 { 44335 intensity: 80, 44336 position: [ 44337 -14, 44338 14.0, 44339 -4 44340 ], 44341 scale: [ 44342 0.1, 44343 2.5, 44344 2.5 44345 ] 44346 }, 44347 { 44348 intensity: 23, 44349 position: [ 44350 14.0, 44351 12.0, 44352 0.0 44353 ], 44354 scale: [ 44355 0.1, 44356 5.0, 44357 5.0 44358 ] 44359 }, 44360 { 44361 intensity: 16, 44362 position: [ 44363 0.0, 44364 9.0, 44365 14.0 44366 ], 44367 scale: [ 44368 5.0, 44369 5.0, 44370 0.1 44371 ] 44372 }, 44373 { 44374 intensity: 80, 44375 position: [ 44376 7.0, 44377 8.0, 44378 -14 44379 ], 44380 scale: [ 44381 2.5, 44382 2.5, 44383 0.1 44384 ] 44385 }, 44386 { 44387 intensity: 80, 44388 position: [ 44389 -7, 44390 16.0, 44391 -14 44392 ], 44393 scale: [ 44394 2.5, 44395 2.5, 44396 0.1 44397 ] 44398 }, 44399 { 44400 intensity: 1, 44401 position: [ 44402 0.0, 44403 20.0, 44404 0.0 44405 ], 44406 scale: [ 44407 0.1, 44408 0.1, 44409 0.1 44410 ] 44411 } 44412 ] 44413 }; 44414 class EnvironmentScene extends Scene { 44415 createAreaLightMaterial(intensity) { 44416 const material = new MeshBasicMaterial(); 44417 material.color.setScalar(intensity); 44418 return material; 44419 } 44420 constructor(name){ 44421 super(); 44422 this.position.y = -3.5; 44423 const geometry = new BoxGeometry(); 44424 geometry.deleteAttribute('uv'); 44425 const roomMaterial = new MeshStandardMaterial({ 44426 metalness: 0, 44427 side: BackSide 44428 }); 44429 const boxMaterial = new MeshStandardMaterial({ 44430 metalness: 0 44431 }); 44432 const data = name == 'legacy' ? legacy : neutral; 44433 const mainLight = new PointLight(0xffffff, data.topLight.intensity, 28, 2); 44434 mainLight.position.set(...data.topLight.position); 44435 this.add(mainLight); 44436 const room = new Mesh(geometry, roomMaterial); 44437 room.position.set(...data.room.position); 44438 room.scale.set(...data.room.scale); 44439 this.add(room); 44440 for (const box of data.boxes){ 44441 const box1 = new Mesh(geometry, boxMaterial); 44442 box1.position.set(...box.position); 44443 box1.rotation.set(0, box.rotation, 0); 44444 box1.scale.set(...box.scale); 44445 this.add(box1); 44446 } 44447 for (const light of data.lights){ 44448 const light1 = new Mesh(geometry, this.createAreaLightMaterial(light.intensity)); 44449 light1.position.set(...light.position); 44450 light1.scale.set(...light.scale); 44451 this.add(light1); 44452 } 44453 } 44454 } 44455 44456 const GENERATED_SIGMA = 0.04; 44457 const MAX_SAMPLES = 20; 44458 const HDR_FILE_RE = /\.hdr(\.js)?$/; 44459 class TextureUtils { 44460 ldrLoader(withCredentials) { 44461 if (this._ldrLoader == null) { 44462 this._ldrLoader = new TextureLoader(); 44463 } 44464 this._ldrLoader.setWithCredentials(withCredentials); 44465 return this._ldrLoader; 44466 } 44467 imageLoader(withCredentials) { 44468 if (this._imageLoader == null) { 44469 this._imageLoader = new HDRJPGLoader(this.threeRenderer); 44470 } 44471 this._imageLoader.setWithCredentials(withCredentials); 44472 return this._imageLoader; 44473 } 44474 hdrLoader(withCredentials) { 44475 if (this._hdrLoader == null) { 44476 this._hdrLoader = new RGBELoader(); 44477 this._hdrLoader.setDataType(HalfFloatType); 44478 } 44479 this._hdrLoader.setWithCredentials(withCredentials); 44480 return this._hdrLoader; 44481 } 44482 async getLottieLoader(withCredentials) { 44483 if (this._lottieLoader == null) { 44484 const { LottieLoader } = await import( this.lottieLoaderUrl); 44485 this._lottieLoader = new LottieLoader(); 44486 } 44487 this._lottieLoader.setWithCredentials(withCredentials); 44488 return this._lottieLoader; 44489 } 44490 async loadImage(url, withCredentials) { 44491 const texture = await new Promise((resolve, reject)=>this.ldrLoader(withCredentials).load(url, resolve, ()=>{}, reject)); 44492 texture.name = url; 44493 texture.flipY = false;
vendor: 5,594 bytes, lines 44494-44618
44494 return texture; 44495 } 44496 async loadLottie(url, quality, withCredentials) { 44497 const loader = await this.getLottieLoader(withCredentials); 44498 loader.setQuality(quality); 44499 const texture = await new Promise((resolve, reject)=>loader.load(url, resolve, ()=>{}, reject)); 44500 texture.name = url; 44501 return texture; 44502 } 44503 async loadEquirect(url, withCredentials = false, progressCallback = ()=>{}) { 44504 try { 44505 const isHDR = HDR_FILE_RE.test(url); 44506 const loader = isHDR ? this.hdrLoader(withCredentials) : this.imageLoader(withCredentials); 44507 const texture = await new Promise((resolve, reject)=>loader.load(url, (result)=>{ 44508 const { renderTarget } = result; 44509 if (renderTarget != null) { 44510 const { texture } = renderTarget; 44511 result.dispose(false); 44512 resolve(texture); 44513 } else { 44514 resolve(result); 44515 } 44516 }, (event)=>{ 44517 progressCallback(event.loaded / event.total * 0.9); 44518 }, reject)); 44519 progressCallback(1.0); 44520 texture.name = url; 44521 texture.mapping = EquirectangularReflectionMapping; 44522 if (!isHDR) { 44523 texture.colorSpace = SRGBColorSpace; 44524 } 44525 return texture; 44526 } finally{ 44527 if (progressCallback) { 44528 progressCallback(1); 44529 } 44530 } 44531 } 44532 async generateEnvironmentMapAndSkybox(skyboxUrl = null, environmentMapUrl = null, progressCallback = ()=>{}, withCredentials = false) { 44533 const useAltEnvironment = environmentMapUrl !== 'legacy'; 44534 if (environmentMapUrl === 'legacy' || environmentMapUrl === 'neutral') { 44535 environmentMapUrl = null; 44536 } 44537 environmentMapUrl = deserializeUrl(environmentMapUrl); 44538 let skyboxLoads = Promise.resolve(null); 44539 let environmentMapLoads; 44540 if (!!skyboxUrl) { 44541 skyboxLoads = this.loadEquirectFromUrl(skyboxUrl, withCredentials, progressCallback); 44542 } 44543 if (!!environmentMapUrl) { 44544 environmentMapLoads = this.loadEquirectFromUrl(environmentMapUrl, withCredentials, progressCallback); 44545 } else if (!!skyboxUrl) { 44546 environmentMapLoads = this.loadEquirectFromUrl(skyboxUrl, withCredentials, progressCallback); 44547 } else { 44548 environmentMapLoads = useAltEnvironment ? this.loadGeneratedEnvironmentMapAlt() : this.loadGeneratedEnvironmentMap(); 44549 } 44550 const [environmentMap, skybox] = await Promise.all([ 44551 environmentMapLoads, 44552 skyboxLoads 44553 ]); 44554 if (environmentMap == null) { 44555 throw new Error('Failed to load environment map.'); 44556 } 44557 return { 44558 environmentMap, 44559 skybox 44560 }; 44561 } 44562 async loadEquirectFromUrl(url, withCredentials, progressCallback) { 44563 if (!this.skyboxCache.has(url)) { 44564 const skyboxMapLoads = this.loadEquirect(url, withCredentials, progressCallback); 44565 this.skyboxCache.set(url, skyboxMapLoads); 44566 } 44567 return this.skyboxCache.get(url); 44568 } 44569 async GenerateEnvironmentMap(scene, name) { 44570 await timePasses(); 44571 const renderer = this.threeRenderer; 44572 const cubeTarget = new WebGLCubeRenderTarget(256, { 44573 generateMipmaps: false, 44574 type: HalfFloatType, 44575 format: RGBAFormat, 44576 colorSpace: LinearSRGBColorSpace, 44577 depthBuffer: true 44578 }); 44579 const cubeCamera = new CubeCamera(0.1, 100, cubeTarget); 44580 const generatedEnvironmentMap = cubeCamera.renderTarget.texture; 44581 generatedEnvironmentMap.name = name; 44582 const outputColorSpace = renderer.outputColorSpace; 44583 const toneMapping = renderer.toneMapping; 44584 renderer.toneMapping = NoToneMapping; 44585 renderer.outputColorSpace = LinearSRGBColorSpace; 44586 cubeCamera.update(renderer, scene); 44587 this.blurCubemap(cubeTarget, GENERATED_SIGMA); 44588 renderer.toneMapping = toneMapping; 44589 renderer.outputColorSpace = outputColorSpace; 44590 return generatedEnvironmentMap; 44591 } 44592 async loadGeneratedEnvironmentMap() { 44593 if (this.generatedEnvironmentMap == null) { 44594 this.generatedEnvironmentMap = this.GenerateEnvironmentMap(new EnvironmentScene('legacy'), 'legacy'); 44595 } 44596 return this.generatedEnvironmentMap; 44597 } 44598 async loadGeneratedEnvironmentMapAlt() { 44599 if (this.generatedEnvironmentMapAlt == null) { 44600 this.generatedEnvironmentMapAlt = this.GenerateEnvironmentMap(new EnvironmentScene('neutral'), 'neutral'); 44601 } 44602 return this.generatedEnvironmentMapAlt; 44603 } 44604 blurCubemap(cubeTarget, sigma) { 44605 if (this.blurMaterial == null) { 44606 this.blurMaterial = this.getBlurShader(MAX_SAMPLES); 44607 const box = new BoxGeometry(); 44608 const blurMesh = new Mesh(box, this.blurMaterial); 44609 this.blurScene = new Scene(); 44610 this.blurScene.add(blurMesh); 44611 } 44612 const tempTarget = cubeTarget.clone(); 44613 this.halfblur(cubeTarget, tempTarget, sigma, 'latitudinal'); 44614 this.halfblur(tempTarget, cubeTarget, sigma, 'longitudinal'); 44615 } 44616 halfblur(targetIn, targetOut, sigmaRadians, direction) { 44617 const STANDARD_DEVIATIONS = 3; 44618 const pixels = targetIn.width;
vendor: 53,934 bytes, lines 44619-46114
44619 const radiansPerPixel = isFinite(sigmaRadians) ? Math.PI / (2 * pixels) : 2 * Math.PI / (2 * MAX_SAMPLES - 1); 44620 const sigmaPixels = sigmaRadians / radiansPerPixel; 44621 const samples = isFinite(sigmaRadians) ? 1 + Math.floor(STANDARD_DEVIATIONS * sigmaPixels) : MAX_SAMPLES; 44622 if (samples > MAX_SAMPLES) { 44623 console.warn(`sigmaRadians, ${sigmaRadians}, is too large and will clip, as it requested ${samples} samples when the maximum is set to ${MAX_SAMPLES}`); 44624 } 44625 const weights = []; 44626 let sum = 0; 44627 for(let i = 0; i < MAX_SAMPLES; ++i){ 44628 const x = i / sigmaPixels; 44629 const weight = Math.exp(-x * x / 2); 44630 weights.push(weight); 44631 if (i == 0) { 44632 sum += weight; 44633 } else if (i < samples) { 44634 sum += 2 * weight; 44635 } 44636 } 44637 for(let i = 0; i < weights.length; i++){ 44638 weights[i] = weights[i] / sum; 44639 } 44640 const blurUniforms = this.blurMaterial.uniforms; 44641 blurUniforms['envMap'].value = targetIn.texture; 44642 blurUniforms['samples'].value = samples; 44643 blurUniforms['weights'].value = weights; 44644 blurUniforms['latitudinal'].value = direction === 'latitudinal'; 44645 blurUniforms['dTheta'].value = radiansPerPixel; 44646 const cubeCamera = new CubeCamera(0.1, 100, targetOut); 44647 cubeCamera.update(this.threeRenderer, this.blurScene); 44648 } 44649 getBlurShader(maxSamples) { 44650 const weights = new Float32Array(maxSamples); 44651 const poleAxis = new Vector3(0, 1, 0); 44652 const shaderMaterial = new ShaderMaterial({ 44653 name: 'SphericalGaussianBlur', 44654 defines: { 44655 'n': maxSamples 44656 }, 44657 uniforms: { 44658 'envMap': { 44659 value: null 44660 }, 44661 'samples': { 44662 value: 1 44663 }, 44664 'weights': { 44665 value: weights 44666 }, 44667 'latitudinal': { 44668 value: false 44669 }, 44670 'dTheta': { 44671 value: 0 44672 }, 44673 'poleAxis': { 44674 value: poleAxis 44675 } 44676 }, 44677 vertexShader: ` 44678 44679 varying vec3 vOutputDirection; 44680 44681 void main() { 44682 44683 vOutputDirection = vec3( position ); 44684 gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); 44685 44686 } 44687 `, 44688 fragmentShader: ` 44689 varying vec3 vOutputDirection; 44690 44691 uniform samplerCube envMap; 44692 uniform int samples; 44693 uniform float weights[ n ]; 44694 uniform bool latitudinal; 44695 uniform float dTheta; 44696 uniform vec3 poleAxis; 44697 44698 vec3 getSample( float theta, vec3 axis ) { 44699 44700 float cosTheta = cos( theta ); 44701 // Rodrigues' axis-angle rotation 44702 vec3 sampleDirection = vOutputDirection * cosTheta 44703 + cross( axis, vOutputDirection ) * sin( theta ) 44704 + axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta ); 44705 44706 return vec3( textureCube( envMap, sampleDirection ) ); 44707 44708 } 44709 44710 void main() { 44711 44712 vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection ); 44713 44714 if ( all( equal( axis, vec3( 0.0 ) ) ) ) { 44715 44716 axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x ); 44717 44718 } 44719 44720 axis = normalize( axis ); 44721 44722 gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 ); 44723 gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis ); 44724 44725 for ( int i = 1; i < n; i++ ) { 44726 44727 if ( i >= samples ) { 44728 44729 break; 44730 44731 } 44732 44733 float theta = dTheta * float( i ); 44734 gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis ); 44735 gl_FragColor.rgb += weights[ i ] * getSample( theta, axis ); 44736 44737 } 44738 } 44739 `, 44740 blending: NoBlending, 44741 depthTest: false, 44742 depthWrite: false, 44743 side: BackSide 44744 }); 44745 return shaderMaterial; 44746 } 44747 async dispose() { 44748 for (const [, promise] of this.skyboxCache){ 44749 const skybox = await promise; 44750 skybox.dispose(); 44751 } 44752 if (this.generatedEnvironmentMap != null) { 44753 (await this.generatedEnvironmentMap).dispose(); 44754 this.generatedEnvironmentMap = null; 44755 } 44756 if (this.generatedEnvironmentMapAlt != null) { 44757 (await this.generatedEnvironmentMapAlt).dispose(); 44758 this.generatedEnvironmentMapAlt = null; 44759 } 44760 if (this.blurMaterial != null) { 44761 this.blurMaterial.dispose(); 44762 } 44763 } 44764 constructor(threeRenderer){ 44765 this.threeRenderer = threeRenderer; 44766 this.lottieLoaderUrl = ''; 44767 this._ldrLoader = null; 44768 this._imageLoader = null; 44769 this._hdrLoader = null; 44770 this._lottieLoader = null; 44771 this.generatedEnvironmentMap = null; 44772 this.generatedEnvironmentMapAlt = null; 44773 this.skyboxCache = new Map(); 44774 this.blurMaterial = null; 44775 this.blurScene = null; 44776 } 44777 } 44778 44779 const DURATION_DECAY = 0.2; 44780 const LOW_FRAME_DURATION_MS = 40; 44781 const HIGH_FRAME_DURATION_MS = 60; 44782 const MAX_AVG_CHANGE_MS = 5; 44783 const SCALE_STEPS = [ 44784 1, 44785 0.79, 44786 0.62, 44787 0.5, 44788 0.4, 44789 0.31, 44790 0.25 44791 ]; 44792 const DEFAULT_LAST_STEP = 3; 44793 const DEFAULT_POWER_PREFERENCE = 'high-performance'; 44794 const COMMERCE_EXPOSURE = 1.3; 44795 class Renderer extends EventDispatcher { 44796 static get singleton() { 44797 if (!this._singleton) { 44798 this._singleton = new Renderer({ 44799 powerPreference: (self.ModelViewerElement || {}).powerPreference || DEFAULT_POWER_PREFERENCE, 44800 debug: isDebugMode() 44801 }); 44802 } 44803 return this._singleton; 44804 } 44805 static resetSingleton() { 44806 const elements = this._singleton.dispose(); 44807 for (const element of elements){ 44808 element.disconnectedCallback(); 44809 } 44810 this._singleton = new Renderer({ 44811 powerPreference: (self.ModelViewerElement || {}).powerPreference || DEFAULT_POWER_PREFERENCE, 44812 debug: isDebugMode() 44813 }); 44814 for (const element of elements){ 44815 element.connectedCallback(); 44816 } 44817 } 44818 get canRender() { 44819 return this.threeRenderer != null; 44820 } 44821 get scaleFactor() { 44822 return SCALE_STEPS[this.scaleStep]; 44823 } 44824 set minScale(scale) { 44825 let i = 1; 44826 while(i < SCALE_STEPS.length){ 44827 if (SCALE_STEPS[i] < scale) { 44828 break; 44829 } 44830 ++i; 44831 } 44832 this.lastStep = i - 1; 44833 } 44834 registerScene(scene) { 44835 this.scenes.add(scene); 44836 scene.forceRescale(); 44837 const size = new Vector2(); 44838 this.threeRenderer.getSize(size); 44839 scene.canvas.width = size.x; 44840 scene.canvas.height = size.y; 44841 if (this.canRender && this.scenes.size > 0) { 44842 this.threeRenderer.setAnimationLoop((time, frame)=>this.render(time, frame)); 44843 } 44844 } 44845 unregisterScene(scene) { 44846 this.scenes.delete(scene); 44847 if (this.canvas3D.parentElement === scene.canvas.parentElement) { 44848 scene.canvas.parentElement.removeChild(this.canvas3D); 44849 } 44850 if (this.canRender && this.scenes.size === 0) { 44851 this.threeRenderer.setAnimationLoop(null); 44852 } 44853 } 44854 displayCanvas(scene) { 44855 return scene.element.modelIsVisible && !this.multipleScenesVisible ? this.canvas3D : scene.element[$canvas]; 44856 } 44857 countVisibleScenes() { 44858 const { canvas3D } = this; 44859 let visibleScenes = 0; 44860 let canvas3DScene = null; 44861 for (const scene of this.scenes){ 44862 const { element } = scene; 44863 if (element.modelIsVisible && scene.externalRenderer == null) { 44864 ++visibleScenes; 44865 } 44866 if (canvas3D.parentElement === scene.canvas.parentElement) { 44867 canvas3DScene = scene; 44868 } 44869 } 44870 const multipleScenesVisible = visibleScenes > 1; 44871 if (canvas3DScene != null) { 44872 const newlyMultiple = multipleScenesVisible && !this.multipleScenesVisible; 44873 const disappearing = !canvas3DScene.element.modelIsVisible; 44874 if (newlyMultiple || disappearing) { 44875 const { width, height } = this.sceneSize(canvas3DScene); 44876 this.copyPixels(canvas3DScene, width, height); 44877 canvas3D.parentElement.removeChild(canvas3D); 44878 } 44879 } 44880 this.multipleScenesVisible = multipleScenesVisible; 44881 } 44882 updateRendererSize() { 44883 var _a; 44884 const dpr = window.devicePixelRatio; 44885 if (dpr !== this.dpr) { 44886 for (const scene of this.scenes){ 44887 const { element } = scene; 44888 element[$updateSize](element.getBoundingClientRect()); 44889 } 44890 } 44891 let width = 0; 44892 let height = 0; 44893 for (const scene of this.scenes){ 44894 width = Math.max(width, scene.width); 44895 height = Math.max(height, scene.height); 44896 } 44897 if (width === this.width && height === this.height && dpr === this.dpr) { 44898 return; 44899 } 44900 this.width = width; 44901 this.height = height; 44902 this.dpr = dpr; 44903 width = Math.ceil(width * dpr); 44904 height = Math.ceil(height * dpr); 44905 if (this.canRender) { 44906 this.threeRenderer.setSize(width, height, false); 44907 } 44908 for (const scene of this.scenes){ 44909 const { canvas } = scene; 44910 canvas.width = width; 44911 canvas.height = height; 44912 scene.forceRescale(); 44913 (_a = scene.effectRenderer) === null || _a === void 0 ? void 0 : _a.setSize(width, height); 44914 } 44915 } 44916 updateRendererScale(delta) { 44917 const scaleStep = this.scaleStep; 44918 this.avgFrameDuration += clamp(DURATION_DECAY * (delta - this.avgFrameDuration), -5, MAX_AVG_CHANGE_MS); 44919 if (this.avgFrameDuration > HIGH_FRAME_DURATION_MS) { 44920 ++this.scaleStep; 44921 } else if (this.avgFrameDuration < LOW_FRAME_DURATION_MS && this.scaleStep > 0) { 44922 --this.scaleStep; 44923 } 44924 this.scaleStep = Math.min(this.scaleStep, this.lastStep); 44925 if (scaleStep !== this.scaleStep) { 44926 this.avgFrameDuration = (HIGH_FRAME_DURATION_MS + LOW_FRAME_DURATION_MS) / 2; 44927 } 44928 } 44929 shouldRender(scene) { 44930 if (!scene.shouldRender()) { 44931 if (scene.scaleStep != 0) { 44932 scene.scaleStep = 0; 44933 this.rescaleCanvas(scene); 44934 } else { 44935 return false; 44936 } 44937 } else if (scene.scaleStep != this.scaleStep) { 44938 scene.scaleStep = this.scaleStep; 44939 this.rescaleCanvas(scene); 44940 } 44941 return true; 44942 } 44943 rescaleCanvas(scene) { 44944 const scale = SCALE_STEPS[scene.scaleStep]; 44945 const width = Math.ceil(this.width / scale); 44946 const height = Math.ceil(this.height / scale); 44947 const { style } = scene.canvas; 44948 style.width = `${width}px`; 44949 style.height = `${height}px`; 44950 this.canvas3D.style.width = `${width}px`; 44951 this.canvas3D.style.height = `${height}px`; 44952 const renderedDpr = this.dpr * scale; 44953 const reason = scale < 1 ? 'GPU throttling' : this.dpr !== window.devicePixelRatio ? 'No meta viewport tag' : ''; 44954 scene.element.dispatchEvent(new CustomEvent('render-scale', { 44955 detail: { 44956 reportedDpr: window.devicePixelRatio, 44957 renderedDpr: renderedDpr, 44958 minimumDpr: this.dpr * SCALE_STEPS[this.lastStep], 44959 pixelWidth: Math.ceil(scene.width * renderedDpr), 44960 pixelHeight: Math.ceil(scene.height * renderedDpr), 44961 reason: reason 44962 } 44963 })); 44964 } 44965 sceneSize(scene) { 44966 const { dpr } = this; 44967 const scaleFactor = SCALE_STEPS[scene.scaleStep]; 44968 const width = Math.min(Math.ceil(scene.width * scaleFactor * dpr), this.canvas3D.width); 44969 const height = Math.min(Math.ceil(scene.height * scaleFactor * dpr), this.canvas3D.height); 44970 return { 44971 width, 44972 height 44973 }; 44974 } 44975 copyPixels(scene, width, height) { 44976 const context2D = scene.context; 44977 if (context2D == null) { 44978 console.log('could not acquire 2d context'); 44979 return; 44980 } 44981 context2D.clearRect(0, 0, width, height); 44982 context2D.drawImage(this.canvas3D, 0, 0, width, height, 0, 0, width, height); 44983 scene.canvas.classList.add('show'); 44984 } 44985 orderedScenes() { 44986 const scenes = []; 44987 for (const visible of [ 44988 false, 44989 true 44990 ]){ 44991 for (const scene of this.scenes){ 44992 if (scene.element.modelIsVisible === visible) { 44993 scenes.push(scene); 44994 } 44995 } 44996 } 44997 return scenes; 44998 } 44999 get isPresenting() { 45000 return this.arRenderer.isPresenting; 45001 } 45002 preRender(scene, t, delta) { 45003 const { element, exposure, toneMapping } = scene; 45004 element[$tick](t, delta); 45005 const exposureIsNumber = typeof exposure === 'number' && !Number.isNaN(exposure); 45006 const env = element.environmentImage; 45007 const sky = element.skyboxImage; 45008 const compensateExposure = toneMapping === NeutralToneMapping && (env === 'neutral' || env === 'legacy' || !env && !sky); 45009 this.threeRenderer.toneMappingExposure = (exposureIsNumber ? exposure : 1.0) * (compensateExposure ? COMMERCE_EXPOSURE : 1.0); 45010 } 45011 render(t, frame) { 45012 if (frame != null) { 45013 this.arRenderer.onWebXRFrame(t, frame); 45014 return; 45015 } 45016 const delta = t - this.lastTick; 45017 this.lastTick = t; 45018 if (!this.canRender || this.isPresenting) { 45019 return; 45020 } 45021 this.countVisibleScenes(); 45022 this.updateRendererSize(); 45023 if (this.renderedLastFrame) { 45024 this.updateRendererScale(delta); 45025 this.renderedLastFrame = false; 45026 } 45027 const { canvas3D } = this; 45028 for (const scene of this.orderedScenes()){ 45029 const { element } = scene; 45030 if (!element.loaded || !element.modelIsVisible && scene.renderCount > 0) { 45031 continue; 45032 } 45033 this.preRender(scene, t, delta); 45034 if (!this.shouldRender(scene)) { 45035 continue; 45036 } 45037 if (scene.externalRenderer != null) { 45038 const camera = scene.getCamera(); 45039 camera.updateMatrix(); 45040 const { matrix, projectionMatrix } = camera; 45041 const viewMatrix = matrix.elements.slice(); 45042 const target = scene.getTarget(); 45043 viewMatrix[12] += target.x; 45044 viewMatrix[13] += target.y; 45045 viewMatrix[14] += target.z; 45046 scene.externalRenderer.render({ 45047 viewMatrix: viewMatrix, 45048 projectionMatrix: projectionMatrix.elements 45049 }); 45050 continue; 45051 } 45052 if (!element.modelIsVisible && !this.multipleScenesVisible) { 45053 for (const visibleScene of this.scenes){ 45054 if (visibleScene.element.modelIsVisible) { 45055 visibleScene.queueRender(); 45056 } 45057 } 45058 } 45059 const { width, height } = this.sceneSize(scene); 45060 scene.renderShadow(this.threeRenderer); 45061 this.threeRenderer.setRenderTarget(null); 45062 this.threeRenderer.setViewport(0, Math.ceil(this.height * this.dpr) - height, width, height); 45063 if (scene.effectRenderer != null) { 45064 scene.effectRenderer.render(delta); 45065 } else { 45066 this.threeRenderer.autoClear = true; 45067 this.threeRenderer.toneMapping = scene.toneMapping; 45068 this.threeRenderer.render(scene, scene.camera); 45069 } 45070 if (this.multipleScenesVisible || !scene.element.modelIsVisible && scene.renderCount === 0) { 45071 this.copyPixels(scene, width, height); 45072 } else if (canvas3D.parentElement !== scene.canvas.parentElement) { 45073 scene.canvas.parentElement.appendChild(canvas3D); 45074 scene.canvas.classList.remove('show'); 45075 } 45076 scene.hasRendered(); 45077 ++scene.renderCount; 45078 this.renderedLastFrame = true; 45079 } 45080 } 45081 dispose() { 45082 if (this.textureUtils != null) { 45083 this.textureUtils.dispose(); 45084 } 45085 if (this.threeRenderer != null) { 45086 this.threeRenderer.dispose(); 45087 } 45088 this.textureUtils = null; 45089 this.threeRenderer = null; 45090 const elements = []; 45091 for (const scene of this.scenes){ 45092 elements.push(scene.element); 45093 } 45094 this.canvas3D.removeEventListener('webglcontextlost', this.onWebGLContextLost); 45095 this.canvas3D.removeEventListener('webglcontextrestored', this.onWebGLContextRestored); 45096 return elements; 45097 } 45098 constructor(options){ 45099 super(); 45100 this.loader = new CachingGLTFLoader(ModelViewerGLTFInstance); 45101 this.width = 0; 45102 this.height = 0; 45103 this.dpr = 1; 45104 this.scenes = new Set(); 45105 this.multipleScenesVisible = false; 45106 this.lastTick = performance.now(); 45107 this.renderedLastFrame = false; 45108 this.scaleStep = 0; 45109 this.lastStep = DEFAULT_LAST_STEP; 45110 this.avgFrameDuration = (HIGH_FRAME_DURATION_MS + LOW_FRAME_DURATION_MS) / 2; 45111 this.onWebGLContextLost = (event)=>{ 45112 this.dispatchEvent({ 45113 type: 'contextlost', 45114 sourceEvent: event 45115 }); 45116 }; 45117 this.onWebGLContextRestored = ()=>{ 45118 var _a; 45119 (_a = this.textureUtils) === null || _a === void 0 ? void 0 : _a.dispose(); 45120 this.textureUtils = new TextureUtils(this.threeRenderer); 45121 for (const scene of this.scenes){ 45122 scene.element[$updateEnvironment](); 45123 } 45124 }; 45125 this.dpr = window.devicePixelRatio; 45126 this.canvas3D = document.createElement('canvas'); 45127 this.canvas3D.id = 'webgl-canvas'; 45128 this.canvas3D.classList.add('show'); 45129 try { 45130 this.threeRenderer = new WebGLRenderer({ 45131 canvas: this.canvas3D, 45132 alpha: true, 45133 antialias: true, 45134 powerPreference: options.powerPreference, 45135 preserveDrawingBuffer: true 45136 }); 45137 this.threeRenderer.autoClear = true; 45138 this.threeRenderer.setPixelRatio(1); 45139 this.threeRenderer.debug = { 45140 checkShaderErrors: !!options.debug, 45141 onShaderError: null 45142 }; 45143 this.threeRenderer.toneMapping = NeutralToneMapping; 45144 } catch (error) { 45145 console.warn(error); 45146 } 45147 this.arRenderer = new ARRenderer(this); 45148 this.textureUtils = this.canRender ? new TextureUtils(this.threeRenderer) : null; 45149 CachingGLTFLoader.initializeKTX2Loader(this.threeRenderer); 45150 this.canvas3D.addEventListener('webglcontextlost', this.onWebGLContextLost); 45151 this.canvas3D.addEventListener('webglcontextrestored', this.onWebGLContextRestored); 45152 this.updateRendererSize(); 45153 } 45154 } 45155 45156 const $correlatedObjects = Symbol('correlatedObjects'); 45157 const $onUpdate$1 = Symbol('onUpdate'); 45158 class ThreeDOMElement { 45159 constructor(onUpdate, correlatedObjects){ 45160 this[$onUpdate$1] = onUpdate; 45161 this[$correlatedObjects] = correlatedObjects; 45162 } 45163 } 45164 45165 const quadMaterial = new MeshBasicMaterial(); 45166 const quad = new PlaneGeometry(2, 2); 45167 let adhocNum = 0; 45168 const $threeTexture$2 = Symbol('threeTexture'); 45169 const $threeTextures$1 = Symbol('threeTextures'); 45170 let Image$1 = class Image extends ThreeDOMElement { 45171 get [$threeTexture$2]() { 45172 var _a; 45173 return (_a = this[$correlatedObjects]) === null || _a === void 0 ? void 0 : _a.values().next().value; 45174 } 45175 get [$threeTextures$1]() { 45176 return this[$correlatedObjects]; 45177 } 45178 get name() { 45179 return this[$threeTexture$2].image.name || ''; 45180 } 45181 get uri() { 45182 return this[$threeTexture$2].image.src; 45183 } 45184 get bufferView() { 45185 return this[$threeTexture$2].image.bufferView; 45186 } 45187 get element() { 45188 const texture = this[$threeTexture$2]; 45189 if (texture && (texture.isCanvasTexture || texture.isVideoTexture)) { 45190 return texture.image; 45191 } 45192 return; 45193 } 45194 get animation() { 45195 const texture = this[$threeTexture$2]; 45196 if (texture && texture.isCanvasTexture && texture.animation) { 45197 return texture.animation; 45198 } 45199 return; 45200 } 45201 get type() { 45202 return this.uri != null ? 'external' : 'embedded'; 45203 } 45204 set name(name) { 45205 for (const texture of this[$threeTextures$1]){ 45206 texture.image.name = name; 45207 } 45208 } 45209 update() { 45210 const texture = this[$threeTexture$2]; 45211 if (texture && texture.isCanvasTexture && !texture.animation) { 45212 this[$threeTexture$2].needsUpdate = true; 45213 this[$onUpdate$1](); 45214 } 45215 } 45216 async createThumbnail(width, height) { 45217 const scene = new Scene(); 45218 quadMaterial.map = this[$threeTexture$2]; 45219 const mesh = new Mesh(quad, quadMaterial); 45220 scene.add(mesh); 45221 const camera = new OrthographicCamera(-1, 1, 1, -1, 0, 1); 45222 const { threeRenderer } = Renderer.singleton; 45223 const renderTarget = new WebGLRenderTarget(width, height); 45224 threeRenderer.setRenderTarget(renderTarget); 45225 threeRenderer.render(scene, camera); 45226 threeRenderer.setRenderTarget(null); 45227 const buffer = new Uint8Array(width * height * 4); 45228 threeRenderer.readRenderTargetPixels(renderTarget, 0, 0, width, height, buffer); 45229 blobCanvas.width = width; 45230 blobCanvas.height = height; 45231 const blobContext = blobCanvas.getContext('2d'); 45232 const imageData = blobContext.createImageData(width, height); 45233 imageData.data.set(buffer); 45234 blobContext.putImageData(imageData, 0, 0); 45235 return new Promise(async (resolve, reject)=>{ 45236 blobCanvas.toBlob((blob)=>{ 45237 if (!blob) { 45238 return reject('Failed to capture thumbnail.'); 45239 } 45240 resolve(URL.createObjectURL(blob)); 45241 }, 'image/png'); 45242 }); 45243 } 45244 constructor(onUpdate, texture){ 45245 super(onUpdate, new Set(texture ? [ 45246 texture 45247 ] : [])); 45248 if (!this[$threeTexture$2].image.src) { 45249 this[$threeTexture$2].image.src = texture.name ? texture.name : 'adhoc_image' + adhocNum++; 45250 } 45251 if (!this[$threeTexture$2].image.name) { 45252 this[$threeTexture$2].image.name = texture && texture.image && texture.image.src ? texture.image.src.split('/').pop() : 'adhoc_image'; 45253 } 45254 } 45255 }; 45256 45257 var Filter; 45258 (function(Filter) { 45259 Filter[Filter["Nearest"] = 9728] = "Nearest"; 45260 Filter[Filter["Linear"] = 9729] = "Linear"; 45261 Filter[Filter["NearestMipmapNearest"] = 9984] = "NearestMipmapNearest"; 45262 Filter[Filter["LinearMipmapNearest"] = 9985] = "LinearMipmapNearest"; 45263 Filter[Filter["NearestMipmapLinear"] = 9986] = "NearestMipmapLinear"; 45264 Filter[Filter["LinearMipmapLinear"] = 9987] = "LinearMipmapLinear"; 45265 })(Filter || (Filter = {})); 45266 var Wrap; 45267 (function(Wrap) { 45268 Wrap[Wrap["ClampToEdge"] = 33071] = "ClampToEdge"; 45269 Wrap[Wrap["MirroredRepeat"] = 33648] = "MirroredRepeat"; 45270 Wrap[Wrap["Repeat"] = 10497] = "Repeat"; 45271 })(Wrap || (Wrap = {})); 45272 45273 const wrapModeToWrapping = new Map([ 45274 [ 45275 Wrap.Repeat, 45276 RepeatWrapping 45277 ], 45278 [ 45279 Wrap.ClampToEdge, 45280 ClampToEdgeWrapping 45281 ], 45282 [ 45283 Wrap.MirroredRepeat, 45284 MirroredRepeatWrapping 45285 ] 45286 ]); 45287 const wrappingToWrapMode = new Map([ 45288 [ 45289 RepeatWrapping, 45290 Wrap.Repeat 45291 ], 45292 [ 45293 ClampToEdgeWrapping, 45294 Wrap.ClampToEdge 45295 ], 45296 [ 45297 MirroredRepeatWrapping, 45298 Wrap.MirroredRepeat 45299 ] 45300 ]); 45301 const minFilterToMinification = new Map([ 45302 [ 45303 Filter.Nearest, 45304 NearestFilter 45305 ], 45306 [ 45307 Filter.Linear, 45308 LinearFilter 45309 ], 45310 [ 45311 Filter.NearestMipmapNearest, 45312 NearestMipmapNearestFilter 45313 ], 45314 [ 45315 Filter.LinearMipmapNearest, 45316 LinearMipmapNearestFilter 45317 ], 45318 [ 45319 Filter.NearestMipmapLinear, 45320 NearestMipmapLinearFilter 45321 ], 45322 [ 45323 Filter.LinearMipmapLinear, 45324 LinearMipmapLinearFilter 45325 ] 45326 ]); 45327 const minificationToMinFilter = new Map([ 45328 [ 45329 NearestFilter, 45330 Filter.Nearest 45331 ], 45332 [ 45333 LinearFilter, 45334 Filter.Linear 45335 ], 45336 [ 45337 NearestMipmapNearestFilter, 45338 Filter.NearestMipmapNearest 45339 ], 45340 [ 45341 LinearMipmapNearestFilter, 45342 Filter.LinearMipmapNearest 45343 ], 45344 [ 45345 NearestMipmapLinearFilter, 45346 Filter.NearestMipmapLinear 45347 ], 45348 [ 45349 LinearMipmapLinearFilter, 45350 Filter.LinearMipmapLinear 45351 ] 45352 ]); 45353 const magFilterToMagnification = new Map([ 45354 [ 45355 Filter.Nearest, 45356 NearestFilter 45357 ], 45358 [ 45359 Filter.Linear, 45360 LinearFilter 45361 ] 45362 ]); 45363 const magnificationToMagFilter = new Map([ 45364 [ 45365 NearestFilter, 45366 Filter.Nearest 45367 ], 45368 [ 45369 LinearFilter, 45370 Filter.Linear 45371 ] 45372 ]); 45373 const isMinFilter = (()=>{ 45374 return (value)=>minificationToMinFilter.has(value); 45375 })(); 45376 const isMagFilter = (()=>{ 45377 return (value)=>magnificationToMagFilter.has(value); 45378 })(); 45379 const isWrapping = (()=>{ 45380 return (value)=>wrappingToWrapMode.has(value); 45381 })(); 45382 const isValidSamplerValue = (property, value)=>{ 45383 switch(property){ 45384 case 'minFilter': 45385 return isMinFilter(value); 45386 case 'magFilter': 45387 return isMagFilter(value); 45388 case 'wrapS': 45389 case 'wrapT': 45390 return isWrapping(value); 45391 case 'rotation': 45392 case 'repeat': 45393 case 'offset': 45394 return true; 45395 default: 45396 throw new Error(`Cannot configure property "${property}" on Sampler`); 45397 } 45398 }; 45399 const $threeTexture$1 = Symbol('threeTexture'); 45400 const $threeTextures = Symbol('threeTextures'); 45401 const $setProperty = Symbol('setProperty'); 45402 class Sampler extends ThreeDOMElement { 45403 get [$threeTexture$1]() { 45404 var _a; 45405 return (_a = this[$correlatedObjects]) === null || _a === void 0 ? void 0 : _a.values().next().value; 45406 } 45407 get [$threeTextures]() { 45408 return this[$correlatedObjects]; 45409 } 45410 get name() { 45411 return this[$threeTexture$1].name || ''; 45412 } 45413 get minFilter() { 45414 return minificationToMinFilter.get(this[$threeTexture$1].minFilter); 45415 } 45416 get magFilter() { 45417 return magnificationToMagFilter.get(this[$threeTexture$1].magFilter); 45418 } 45419 get wrapS() { 45420 return wrappingToWrapMode.get(this[$threeTexture$1].wrapS); 45421 } 45422 get wrapT() { 45423 return wrappingToWrapMode.get(this[$threeTexture$1].wrapT); 45424 } 45425 get rotation() { 45426 return this[$threeTexture$1].rotation; 45427 } 45428 get scale() { 45429 return toVector2D(this[$threeTexture$1].repeat); 45430 } 45431 get offset() { 45432 return toVector2D(this[$threeTexture$1].offset); 45433 } 45434 setMinFilter(filter) { 45435 this[$setProperty]('minFilter', minFilterToMinification.get(filter)); 45436 } 45437 setMagFilter(filter) { 45438 this[$setProperty]('magFilter', magFilterToMagnification.get(filter)); 45439 } 45440 setWrapS(mode) { 45441 this[$setProperty]('wrapS', wrapModeToWrapping.get(mode)); 45442 } 45443 setWrapT(mode) { 45444 this[$setProperty]('wrapT', wrapModeToWrapping.get(mode)); 45445 } 45446 setRotation(rotation) { 45447 if (rotation == null) { 45448 rotation = 0; 45449 } 45450 this[$setProperty]('rotation', rotation); 45451 } 45452 setScale(scale) { 45453 if (scale == null) { 45454 scale = { 45455 u: 1, 45456 v: 1 45457 }; 45458 } 45459 this[$setProperty]('repeat', new Vector2(scale.u, scale.v)); 45460 } 45461 setOffset(offset) { 45462 if (offset == null) { 45463 offset = { 45464 u: 0, 45465 v: 0 45466 }; 45467 } 45468 this[$setProperty]('offset', new Vector2(offset.u, offset.v)); 45469 } 45470 [$setProperty](property, value) { 45471 if (isValidSamplerValue(property, value)) { 45472 for (const texture of this[$threeTextures]){ 45473 texture[property] = value; 45474 texture.needsUpdate = true; 45475 } 45476 } 45477 this[$onUpdate$1](); 45478 } 45479 constructor(onUpdate, texture){ 45480 super(onUpdate, new Set(texture ? [ 45481 texture 45482 ] : [])); 45483 } 45484 } 45485 45486 const $image = Symbol('image'); 45487 const $sampler = Symbol('sampler'); 45488 const $threeTexture = Symbol('threeTexture'); 45489 class Texture extends ThreeDOMElement { 45490 get [$threeTexture]() { 45491 var _a; 45492 return (_a = this[$correlatedObjects]) === null || _a === void 0 ? void 0 : _a.values().next().value; 45493 } 45494 get name() { 45495 return this[$threeTexture].name || ''; 45496 } 45497 set name(name) { 45498 for (const texture of this[$correlatedObjects]){ 45499 texture.name = name; 45500 } 45501 } 45502 get sampler() { 45503 return this[$sampler]; 45504 } 45505 get source() { 45506 return this[$image]; 45507 } 45508 constructor(onUpdate, threeTexture){ 45509 super(onUpdate, new Set(threeTexture ? [ 45510 threeTexture 45511 ] : [])); 45512 this[$sampler] = new Sampler(onUpdate, threeTexture); 45513 this[$image] = new Image$1(onUpdate, threeTexture); 45514 } 45515 } 45516 45517 var _a$4, _b$4, _c$2; 45518 const $texture = Symbol('texture'); 45519 const $transform = Symbol('transform'); 45520 const $materials$1 = Symbol('materials'); 45521 const $usage = Symbol('usage'); 45522 const $onUpdate = Symbol('onUpdate'); 45523 const $activeVideo = Symbol('activeVideo'); 45524 var TextureUsage; 45525 (function(TextureUsage) { 45526 TextureUsage[TextureUsage["Base"] = 0] = "Base"; 45527 TextureUsage[TextureUsage["MetallicRoughness"] = 1] = "MetallicRoughness"; 45528 TextureUsage[TextureUsage["Normal"] = 2] = "Normal"; 45529 TextureUsage[TextureUsage["Occlusion"] = 3] = "Occlusion"; 45530 TextureUsage[TextureUsage["Emissive"] = 4] = "Emissive"; 45531 TextureUsage[TextureUsage["Clearcoat"] = 5] = "Clearcoat"; 45532 TextureUsage[TextureUsage["ClearcoatRoughness"] = 6] = "ClearcoatRoughness"; 45533 TextureUsage[TextureUsage["ClearcoatNormal"] = 7] = "ClearcoatNormal"; 45534 TextureUsage[TextureUsage["SheenColor"] = 8] = "SheenColor"; 45535 TextureUsage[TextureUsage["SheenRoughness"] = 9] = "SheenRoughness"; 45536 TextureUsage[TextureUsage["Transmission"] = 10] = "Transmission"; 45537 TextureUsage[TextureUsage["Thickness"] = 11] = "Thickness"; 45538 TextureUsage[TextureUsage["Specular"] = 12] = "Specular"; 45539 TextureUsage[TextureUsage["SpecularColor"] = 13] = "SpecularColor"; 45540 TextureUsage[TextureUsage["Iridescence"] = 14] = "Iridescence"; 45541 TextureUsage[TextureUsage["IridescenceThickness"] = 15] = "IridescenceThickness"; 45542 TextureUsage[TextureUsage["Anisotropy"] = 16] = "Anisotropy"; 45543 })(TextureUsage || (TextureUsage = {})); 45544 class TextureInfo { 45545 get texture() { 45546 return this[$texture]; 45547 } 45548 setTexture(texture) { 45549 var _d, _e; 45550 const threeTexture = texture != null ? texture.source[$threeTexture$2] : null; 45551 const oldTexture = (_d = this[$texture]) === null || _d === void 0 ? void 0 : _d.source[$threeTexture$2]; 45552 if (oldTexture != null && oldTexture.isVideoTexture) { 45553 this[$activeVideo] = false; 45554 } else if ((_e = this[$texture]) === null || _e === void 0 ? void 0 : _e.source.animation) { 45555 this[$texture].source.animation.removeEventListener('enterFrame', this[$onUpdate]); 45556 } 45557 this[$texture] = texture; 45558 if (threeTexture != null && threeTexture.isVideoTexture) { 45559 const element = threeTexture.image; 45560 this[$activeVideo] = true; 45561 if (element.requestVideoFrameCallback != null) { 45562 const update = ()=>{ 45563 if (!this[$activeVideo]) { 45564 return; 45565 } 45566 this[$onUpdate](); 45567 element.requestVideoFrameCallback(update); 45568 }; 45569 element.requestVideoFrameCallback(update); 45570 } else { 45571 const update = ()=>{ 45572 if (!this[$activeVideo]) { 45573 return; 45574 } 45575 this[$onUpdate](); 45576 requestAnimationFrame(update); 45577 }; 45578 requestAnimationFrame(update); 45579 } 45580 } else if ((texture === null || texture === void 0 ? void 0 : texture.source.animation) != null) { 45581 texture.source.animation.addEventListener('enterFrame', this[$onUpdate]); 45582 } 45583 let colorSpace = SRGBColorSpace; 45584 if (this[$materials$1]) { 45585 for (const material of this[$materials$1]){ 45586 switch(this[$usage]){ 45587 case TextureUsage.Base: 45588 material.map = threeTexture; 45589 break; 45590 case TextureUsage.MetallicRoughness: 45591 colorSpace = LinearSRGBColorSpace; 45592 material.metalnessMap = threeTexture; 45593 material.roughnessMap = threeTexture; 45594 break; 45595 case TextureUsage.Normal: 45596 colorSpace = LinearSRGBColorSpace; 45597 material.normalMap = threeTexture; 45598 break; 45599 case TextureUsage.Occlusion: 45600 colorSpace = LinearSRGBColorSpace; 45601 material.aoMap = threeTexture; 45602 break; 45603 case TextureUsage.Emissive: 45604 material.emissiveMap = threeTexture; 45605 break; 45606 case TextureUsage.Clearcoat: 45607 material.clearcoatMap = threeTexture; 45608 break; 45609 case TextureUsage.ClearcoatRoughness: 45610 material.clearcoatRoughnessMap = threeTexture; 45611 break; 45612 case TextureUsage.ClearcoatNormal: 45613 material.clearcoatNormalMap = threeTexture; 45614 break; 45615 case TextureUsage.SheenColor: 45616 material.sheenColorMap = threeTexture; 45617 break; 45618 case TextureUsage.SheenRoughness: 45619 material.sheenRoughnessMap = threeTexture; 45620 break; 45621 case TextureUsage.Transmission: 45622 material.transmissionMap = threeTexture; 45623 break; 45624 case TextureUsage.Thickness: 45625 material.thicknessMap = threeTexture; 45626 break; 45627 case TextureUsage.Specular: 45628 material.specularIntensityMap = threeTexture; 45629 break; 45630 case TextureUsage.SpecularColor: 45631 material.specularColorMap = threeTexture; 45632 break; 45633 case TextureUsage.Iridescence: 45634 material.iridescenceMap = threeTexture; 45635 break; 45636 case TextureUsage.IridescenceThickness: 45637 material.iridescenceThicknessMap = threeTexture; 45638 break; 45639 case TextureUsage.Anisotropy: 45640 material.anisotropyMap = threeTexture; 45641 break; 45642 } 45643 material.needsUpdate = true; 45644 } 45645 } 45646 if (threeTexture) { 45647 threeTexture.colorSpace = colorSpace; 45648 threeTexture.rotation = this[$transform].rotation; 45649 threeTexture.repeat = this[$transform].scale; 45650 threeTexture.offset = this[$transform].offset; 45651 } 45652 this[$onUpdate](); 45653 } 45654 constructor(onUpdate, usage, threeTexture, material){ 45655 this[_a$4] = null; 45656 this[_b$4] = { 45657 rotation: 0, 45658 scale: new Vector2(1, 1), 45659 offset: new Vector2(0, 0) 45660 }; 45661 this[_c$2] = false; 45662 if (threeTexture) { 45663 this[$transform].rotation = threeTexture.rotation; 45664 this[$transform].scale.copy(threeTexture.repeat); 45665 this[$transform].offset.copy(threeTexture.offset); 45666 this[$texture] = new Texture(onUpdate, threeTexture); 45667 } 45668 this[$onUpdate] = onUpdate; 45669 this[$materials$1] = material; 45670 this[$usage] = usage; 45671 } 45672 } 45673 _a$4 = $texture, _b$4 = $transform, _c$2 = $activeVideo; 45674 45675 const $threeMaterial = Symbol('threeMaterial'); 45676 const $threeMaterials = Symbol('threeMaterials'); 45677 const $baseColorTexture = Symbol('baseColorTexture'); 45678 const $metallicRoughnessTexture = Symbol('metallicRoughnessTexture'); 45679 class PBRMetallicRoughness extends ThreeDOMElement { 45680 get [$threeMaterials]() { 45681 return this[$correlatedObjects]; 45682 } 45683 get [$threeMaterial]() { 45684 var _a; 45685 return (_a = this[$correlatedObjects]) === null || _a === void 0 ? void 0 : _a.values().next().value; 45686 } 45687 get baseColorFactor() { 45688 const rgba = [ 45689 0, 45690 0, 45691 0, 45692 this[$threeMaterial].opacity 45693 ]; 45694 this[$threeMaterial].color.toArray(rgba); 45695 return rgba; 45696 } 45697 get metallicFactor() { 45698 return this[$threeMaterial].metalness; 45699 } 45700 get roughnessFactor() { 45701 return this[$threeMaterial].roughness; 45702 } 45703 get baseColorTexture() { 45704 return this[$baseColorTexture]; 45705 } 45706 get metallicRoughnessTexture() { 45707 return this[$metallicRoughnessTexture]; 45708 } 45709 setBaseColorFactor(rgba) { 45710 const color = new Color(); 45711 if (rgba instanceof Array) { 45712 color.fromArray(rgba); 45713 } else { 45714 color.set(rgba); 45715 } 45716 for (const material of this[$threeMaterials]){ 45717 material.color.set(color); 45718 if (rgba instanceof Array && rgba.length > 3) { 45719 material.opacity = rgba[3]; 45720 } else { 45721 rgba = [ 45722 0, 45723 0, 45724 0, 45725 material.opacity 45726 ]; 45727 color.toArray(rgba); 45728 } 45729 } 45730 this[$onUpdate$1](); 45731 } 45732 setMetallicFactor(value) { 45733 for (const material of this[$threeMaterials]){ 45734 material.metalness = value; 45735 } 45736 this[$onUpdate$1](); 45737 } 45738 setRoughnessFactor(value) { 45739 for (const material of this[$threeMaterials]){ 45740 material.roughness = value; 45741 } 45742 this[$onUpdate$1](); 45743 } 45744 constructor(onUpdate, correlatedMaterials){ 45745 super(onUpdate, correlatedMaterials); 45746 const { map, metalnessMap } = correlatedMaterials.values().next().value; 45747 this[$baseColorTexture] = new TextureInfo(onUpdate, TextureUsage.Base, map, correlatedMaterials); 45748 this[$metallicRoughnessTexture] = new TextureInfo(onUpdate, TextureUsage.MetallicRoughness, metalnessMap, correlatedMaterials); 45749 } 45750 } 45751 45752 var _a$3, _b$3; 45753 const $pbrMetallicRoughness = Symbol('pbrMetallicRoughness'); 45754 const $normalTexture = Symbol('normalTexture'); 45755 const $occlusionTexture = Symbol('occlusionTexture'); 45756 const $emissiveTexture = Symbol('emissiveTexture'); 45757 const $backingThreeMaterial = Symbol('backingThreeMaterial'); 45758 const $applyAlphaCutoff = Symbol('applyAlphaCutoff'); 45759 const $getAlphaMode = Symbol('getAlphaMode'); 45760 const $lazyLoadGLTFInfo = Symbol('lazyLoadGLTFInfo'); 45761 const $initialize = Symbol('initialize'); 45762 const $getLoadedMaterial = Symbol('getLoadedMaterial'); 45763 const $ensureMaterialIsLoaded = Symbol('ensureMaterialIsLoaded'); 45764 const $gltfIndex = Symbol('gltfIndex'); 45765 const $setActive = Symbol('setActive'); 45766 const $variantIndices = Symbol('variantIndices'); 45767 const $isActive = Symbol('isActive'); 45768 const $modelVariants = Symbol('modelVariants'); 45769 const $name = Symbol('name'); 45770 const $pbrTextures = Symbol('pbrTextures'); 45771 class Material extends ThreeDOMElement { 45772 get [(_a$3 = $variantIndices, _b$3 = $pbrTextures, $backingThreeMaterial)]() { 45773 return this[$correlatedObjects].values().next().value; 45774 } 45775 [$initialize]() { 45776 const onUpdate = this[$onUpdate$1]; 45777 const correlatedMaterials = this[$correlatedObjects]; 45778 this[$pbrMetallicRoughness] = new PBRMetallicRoughness(onUpdate, correlatedMaterials); 45779 const { normalMap, aoMap, emissiveMap } = correlatedMaterials.values().next().value; 45780 this[$normalTexture] = new TextureInfo(onUpdate, TextureUsage.Normal, normalMap, correlatedMaterials); 45781 this[$occlusionTexture] = new TextureInfo(onUpdate, TextureUsage.Occlusion, aoMap, correlatedMaterials); 45782 this[$emissiveTexture] = new TextureInfo(onUpdate, TextureUsage.Emissive, emissiveMap, correlatedMaterials); 45783 const createTextureInfo = (usage)=>{ 45784 this[$pbrTextures].set(usage, new TextureInfo(onUpdate, usage, null, correlatedMaterials)); 45785 }; 45786 createTextureInfo(TextureUsage.Clearcoat); 45787 createTextureInfo(TextureUsage.ClearcoatRoughness); 45788 createTextureInfo(TextureUsage.ClearcoatNormal); 45789 createTextureInfo(TextureUsage.SheenColor); 45790 createTextureInfo(TextureUsage.SheenRoughness); 45791 createTextureInfo(TextureUsage.Transmission); 45792 createTextureInfo(TextureUsage.Thickness); 45793 createTextureInfo(TextureUsage.Specular); 45794 createTextureInfo(TextureUsage.SpecularColor); 45795 createTextureInfo(TextureUsage.Iridescence); 45796 createTextureInfo(TextureUsage.IridescenceThickness); 45797 createTextureInfo(TextureUsage.Anisotropy); 45798 } 45799 async [$getLoadedMaterial]() { 45800 if (this[$lazyLoadGLTFInfo] != null) { 45801 const material = await this[$lazyLoadGLTFInfo].doLazyLoad(); 45802 this[$initialize](); 45803 this[$lazyLoadGLTFInfo] = undefined; 45804 this.ensureLoaded = async ()=>{}; 45805 return material; 45806 } 45807 return null; 45808 } 45809 colorFromRgb(rgb) { 45810 const color = new Color(); 45811 if (rgb instanceof Array) { 45812 color.fromArray(rgb); 45813 } else { 45814 color.set(rgb); 45815 } 45816 return color; 45817 } 45818 [$ensureMaterialIsLoaded]() { 45819 if (this[$lazyLoadGLTFInfo] == null) { 45820 return; 45821 } 45822 throw new Error(`Material "${this.name}" has not been loaded, call 'await 45823 myMaterial.ensureLoaded()' before using an unloaded material.`); 45824 } 45825 async ensureLoaded() { 45826 await this[$getLoadedMaterial](); 45827 } 45828 get isLoaded() { 45829 return this[$lazyLoadGLTFInfo] == null; 45830 } 45831 get isActive() { 45832 return this[$isActive]; 45833 } 45834 [$setActive](isActive) { 45835 this[$isActive] = isActive; 45836 } 45837 get name() { 45838 return this[$name] || ''; 45839 } 45840 set name(name) { 45841 this[$name] = name; 45842 if (this[$correlatedObjects] != null) { 45843 for (const threeMaterial of this[$correlatedObjects]){ 45844 threeMaterial.name = name; 45845 } 45846 } 45847 } 45848 get pbrMetallicRoughness() { 45849 this[$ensureMaterialIsLoaded](); 45850 return this[$pbrMetallicRoughness]; 45851 } 45852 get normalTexture() { 45853 this[$ensureMaterialIsLoaded](); 45854 return this[$normalTexture]; 45855 } 45856 get occlusionTexture() { 45857 this[$ensureMaterialIsLoaded](); 45858 return this[$occlusionTexture]; 45859 } 45860 get emissiveTexture() { 45861 this[$ensureMaterialIsLoaded](); 45862 return this[$emissiveTexture]; 45863 } 45864 get emissiveFactor() { 45865 this[$ensureMaterialIsLoaded](); 45866 return this[$backingThreeMaterial].emissive.toArray(); 45867 } 45868 get index() { 45869 return this[$gltfIndex]; 45870 } 45871 hasVariant(name) { 45872 const variantData = this[$modelVariants].get(name); 45873 return variantData != null && this[$variantIndices].has(variantData.index); 45874 } 45875 setEmissiveFactor(rgb) { 45876 this[$ensureMaterialIsLoaded](); 45877 const color = this.colorFromRgb(rgb); 45878 for (const material of this[$correlatedObjects]){ 45879 material.emissive.set(color); 45880 } 45881 this[$onUpdate$1](); 45882 } 45883 [$getAlphaMode]() { 45884 if (this[$backingThreeMaterial].transparent) { 45885 return 'BLEND'; 45886 } else { 45887 if (this[$backingThreeMaterial].alphaTest > 0.0) { 45888 return 'MASK'; 45889 } 45890 } 45891 return 'OPAQUE'; 45892 } 45893 [$applyAlphaCutoff]() { 45894 this[$ensureMaterialIsLoaded](); 45895 for (const material of this[$correlatedObjects]){ 45896 if (this[$getAlphaMode]() === 'MASK') { 45897 if (material.alphaTest == undefined) { 45898 material.alphaTest = 0.5; 45899 } 45900 } else { 45901 material.alphaTest = undefined; 45902 } 45903 material.needsUpdate = true; 45904 } 45905 } 45906 setAlphaCutoff(cutoff) { 45907 this[$ensureMaterialIsLoaded](); 45908 for (const material of this[$correlatedObjects]){ 45909 material.alphaTest = cutoff; 45910 material.needsUpdate = true; 45911 } 45912 this[$applyAlphaCutoff](); 45913 this[$onUpdate$1](); 45914 } 45915 getAlphaCutoff() { 45916 this[$ensureMaterialIsLoaded](); 45917 return this[$backingThreeMaterial].alphaTest; 45918 } 45919 setDoubleSided(doubleSided) { 45920 this[$ensureMaterialIsLoaded](); 45921 for (const material of this[$correlatedObjects]){ 45922 material.side = doubleSided ? DoubleSide : FrontSide; 45923 material.needsUpdate = true; 45924 } 45925 this[$onUpdate$1](); 45926 } 45927 getDoubleSided() { 45928 this[$ensureMaterialIsLoaded](); 45929 return this[$backingThreeMaterial].side == DoubleSide; 45930 } 45931 setAlphaMode(alphaMode) { 45932 this[$ensureMaterialIsLoaded](); 45933 const enableTransparency = (material, enabled)=>{ 45934 material.transparent = enabled; 45935 material.depthWrite = !enabled; 45936 }; 45937 for (const material of this[$correlatedObjects]){ 45938 enableTransparency(material, alphaMode === 'BLEND'); 45939 if (alphaMode === 'MASK') { 45940 material.alphaTest = 0.5; 45941 } else { 45942 material.alphaTest = undefined; 45943 } 45944 material.needsUpdate = true; 45945 } 45946 this[$onUpdate$1](); 45947 } 45948 getAlphaMode() { 45949 this[$ensureMaterialIsLoaded](); 45950 return this[$getAlphaMode](); 45951 } 45952 get emissiveStrength() { 45953 this[$ensureMaterialIsLoaded](); 45954 return this[$backingThreeMaterial].emissiveIntensity; 45955 } 45956 setEmissiveStrength(emissiveStrength) { 45957 this[$ensureMaterialIsLoaded](); 45958 for (const material of this[$correlatedObjects]){ 45959 material.emissiveIntensity = emissiveStrength; 45960 } 45961 this[$onUpdate$1](); 45962 } 45963 get clearcoatFactor() { 45964 this[$ensureMaterialIsLoaded](); 45965 return this[$backingThreeMaterial].clearcoat; 45966 } 45967 get clearcoatRoughnessFactor() { 45968 this[$ensureMaterialIsLoaded](); 45969 return this[$backingThreeMaterial].clearcoatRoughness; 45970 } 45971 get clearcoatTexture() { 45972 this[$ensureMaterialIsLoaded](); 45973 return this[$pbrTextures].get(TextureUsage.Clearcoat); 45974 } 45975 get clearcoatRoughnessTexture() { 45976 this[$ensureMaterialIsLoaded](); 45977 return this[$pbrTextures].get(TextureUsage.ClearcoatRoughness); 45978 } 45979 get clearcoatNormalTexture() { 45980 this[$ensureMaterialIsLoaded](); 45981 return this[$pbrTextures].get(TextureUsage.ClearcoatNormal); 45982 } 45983 get clearcoatNormalScale() { 45984 this[$ensureMaterialIsLoaded](); 45985 return this[$backingThreeMaterial].clearcoatNormalScale.x; 45986 } 45987 setClearcoatFactor(clearcoatFactor) { 45988 this[$ensureMaterialIsLoaded](); 45989 for (const material of this[$correlatedObjects]){ 45990 material.clearcoat = clearcoatFactor; 45991 } 45992 this[$onUpdate$1](); 45993 } 45994 setClearcoatRoughnessFactor(clearcoatRoughnessFactor) { 45995 this[$ensureMaterialIsLoaded](); 45996 for (const material of this[$correlatedObjects]){ 45997 material.clearcoatRoughness = clearcoatRoughnessFactor; 45998 } 45999 this[$onUpdate$1](); 46000 } 46001 setClearcoatNormalScale(clearcoatNormalScale) { 46002 this[$ensureMaterialIsLoaded](); 46003 for (const material of this[$correlatedObjects]){ 46004 material.clearcoatNormalScale = new Vector2(clearcoatNormalScale, clearcoatNormalScale); 46005 } 46006 this[$onUpdate$1](); 46007 } 46008 get ior() { 46009 this[$ensureMaterialIsLoaded](); 46010 return this[$backingThreeMaterial].ior; 46011 } 46012 setIor(ior) { 46013 this[$ensureMaterialIsLoaded](); 46014 for (const material of this[$correlatedObjects]){ 46015 material.ior = ior; 46016 } 46017 this[$onUpdate$1](); 46018 } 46019 get sheenColorFactor() { 46020 this[$ensureMaterialIsLoaded](); 46021 return this[$backingThreeMaterial].sheenColor.toArray(); 46022 } 46023 get sheenColorTexture() { 46024 this[$ensureMaterialIsLoaded](); 46025 return this[$pbrTextures].get(TextureUsage.SheenColor); 46026 } 46027 get sheenRoughnessFactor() { 46028 this[$ensureMaterialIsLoaded](); 46029 return this[$backingThreeMaterial].sheenRoughness; 46030 } 46031 get sheenRoughnessTexture() { 46032 this[$ensureMaterialIsLoaded](); 46033 return this[$pbrTextures].get(TextureUsage.SheenRoughness); 46034 } 46035 setSheenColorFactor(rgb) { 46036 this[$ensureMaterialIsLoaded](); 46037 const color = this.colorFromRgb(rgb); 46038 for (const material of this[$correlatedObjects]){ 46039 material.sheenColor.set(color); 46040 material.sheen = 1; 46041 } 46042 this[$onUpdate$1](); 46043 } 46044 setSheenRoughnessFactor(roughness) { 46045 this[$ensureMaterialIsLoaded](); 46046 for (const material of this[$correlatedObjects]){ 46047 material.sheenRoughness = roughness; 46048 material.sheen = 1; 46049 } 46050 this[$onUpdate$1](); 46051 } 46052 get transmissionFactor() { 46053 this[$ensureMaterialIsLoaded](); 46054 return this[$backingThreeMaterial].transmission; 46055 } 46056 get transmissionTexture() { 46057 this[$ensureMaterialIsLoaded](); 46058 return this[$pbrTextures].get(TextureUsage.Transmission); 46059 } 46060 setTransmissionFactor(transmission) { 46061 this[$ensureMaterialIsLoaded](); 46062 for (const material of this[$correlatedObjects]){ 46063 material.transmission = transmission; 46064 } 46065 this[$onUpdate$1](); 46066 } 46067 get thicknessFactor() { 46068 this[$ensureMaterialIsLoaded](); 46069 return this[$backingThreeMaterial].thickness; 46070 } 46071 get thicknessTexture() { 46072 this[$ensureMaterialIsLoaded](); 46073 return this[$pbrTextures].get(TextureUsage.Thickness); 46074 } 46075 get attenuationDistance() { 46076 this[$ensureMaterialIsLoaded](); 46077 return this[$backingThreeMaterial].attenuationDistance; 46078 } 46079 get attenuationColor() { 46080 this[$ensureMaterialIsLoaded](); 46081 return this[$backingThreeMaterial].attenuationColor.toArray(); 46082 } 46083 setThicknessFactor(thickness) { 46084 this[$ensureMaterialIsLoaded](); 46085 for (const material of this[$correlatedObjects]){ 46086 material.thickness = thickness; 46087 } 46088 this[$onUpdate$1](); 46089 } 46090 setAttenuationDistance(attenuationDistance) { 46091 this[$ensureMaterialIsLoaded](); 46092 for (const material of this[$correlatedObjects]){ 46093 material.attenuationDistance = attenuationDistance; 46094 } 46095 this[$onUpdate$1](); 46096 } 46097 setAttenuationColor(rgb) { 46098 this[$ensureMaterialIsLoaded](); 46099 const color = this.colorFromRgb(rgb); 46100 for (const material of this[$correlatedObjects]){ 46101 material.attenuationColor.set(color); 46102 } 46103 this[$onUpdate$1](); 46104 } 46105 get specularFactor() { 46106 this[$ensureMaterialIsLoaded](); 46107 return this[$backingThreeMaterial].specularIntensity; 46108 } 46109 get specularTexture() { 46110 this[$ensureMaterialIsLoaded](); 46111 return this[$pbrTextures].get(TextureUsage.Specular); 46112 } 46113 get specularColorFactor() { 46114 this[$ensureMaterialI
vendor: 18,141 bytes, lines 46114-46566
46114sLoaded](); 46115 return this[$backingThreeMaterial].specularColor.toArray(); 46116 } 46117 get specularColorTexture() { 46118 this[$ensureMaterialIsLoaded](); 46119 return this[$pbrTextures].get(TextureUsage.SheenColor); 46120 } 46121 setSpecularFactor(specularFactor) { 46122 this[$ensureMaterialIsLoaded](); 46123 for (const material of this[$correlatedObjects]){ 46124 material.specularIntensity = specularFactor; 46125 } 46126 this[$onUpdate$1](); 46127 } 46128 setSpecularColorFactor(rgb) { 46129 this[$ensureMaterialIsLoaded](); 46130 const color = this.colorFromRgb(rgb); 46131 for (const material of this[$correlatedObjects]){ 46132 material.specularColor.set(color); 46133 } 46134 this[$onUpdate$1](); 46135 } 46136 get iridescenceFactor() { 46137 this[$ensureMaterialIsLoaded](); 46138 return this[$backingThreeMaterial].iridescence; 46139 } 46140 get iridescenceTexture() { 46141 this[$ensureMaterialIsLoaded](); 46142 return this[$pbrTextures].get(TextureUsage.Iridescence); 46143 } 46144 get iridescenceIor() { 46145 this[$ensureMaterialIsLoaded](); 46146 return this[$backingThreeMaterial].iridescenceIOR; 46147 } 46148 get iridescenceThicknessMinimum() { 46149 this[$ensureMaterialIsLoaded](); 46150 return this[$backingThreeMaterial].iridescenceThicknessRange[0]; 46151 } 46152 get iridescenceThicknessMaximum() { 46153 this[$ensureMaterialIsLoaded](); 46154 return this[$backingThreeMaterial].iridescenceThicknessRange[1]; 46155 } 46156 get iridescenceThicknessTexture() { 46157 this[$ensureMaterialIsLoaded](); 46158 return this[$pbrTextures].get(TextureUsage.IridescenceThickness); 46159 } 46160 setIridescenceFactor(iridescence) { 46161 this[$ensureMaterialIsLoaded](); 46162 for (const material of this[$correlatedObjects]){ 46163 material.iridescence = iridescence; 46164 } 46165 this[$onUpdate$1](); 46166 } 46167 setIridescenceIor(ior) { 46168 this[$ensureMaterialIsLoaded](); 46169 for (const material of this[$correlatedObjects]){ 46170 material.iridescenceIOR = ior; 46171 } 46172 this[$onUpdate$1](); 46173 } 46174 setIridescenceThicknessMinimum(thicknessMin) { 46175 this[$ensureMaterialIsLoaded](); 46176 for (const material of this[$correlatedObjects]){ 46177 material.iridescenceThicknessRange[0] = thicknessMin; 46178 } 46179 this[$onUpdate$1](); 46180 } 46181 setIridescenceThicknessMaximum(thicknessMax) { 46182 this[$ensureMaterialIsLoaded](); 46183 for (const material of this[$correlatedObjects]){ 46184 material.iridescenceThicknessRange[1] = thicknessMax; 46185 } 46186 this[$onUpdate$1](); 46187 } 46188 get anisotropyStrength() { 46189 this[$ensureMaterialIsLoaded](); 46190 return this[$backingThreeMaterial].anisotropy; 46191 } 46192 get anisotropyRotation() { 46193 this[$ensureMaterialIsLoaded](); 46194 return this[$backingThreeMaterial].anisotropyRotation; 46195 } 46196 get anisotropyTexture() { 46197 this[$ensureMaterialIsLoaded](); 46198 return this[$pbrTextures].get(TextureUsage.Anisotropy); 46199 } 46200 setAnisotropyStrength(strength) { 46201 this[$ensureMaterialIsLoaded](); 46202 for (const material of this[$correlatedObjects]){ 46203 material.anisotropy = strength; 46204 } 46205 this[$onUpdate$1](); 46206 } 46207 setAnisotropyRotation(rotation) { 46208 this[$ensureMaterialIsLoaded](); 46209 for (const material of this[$correlatedObjects]){ 46210 material.anisotropyRotation = rotation; 46211 } 46212 this[$onUpdate$1](); 46213 } 46214 constructor(onUpdate, gltfIndex, isActive, modelVariants, correlatedMaterials, name, lazyLoadInfo = undefined){ 46215 super(onUpdate, correlatedMaterials); 46216 this[_a$3] = new Set(); 46217 this[_b$3] = new Map(); 46218 this[$gltfIndex] = gltfIndex; 46219 this[$isActive] = isActive; 46220 this[$modelVariants] = modelVariants; 46221 this[$name] = name; 46222 if (lazyLoadInfo == null) { 46223 this[$initialize](); 46224 } else { 46225 this[$lazyLoadGLTFInfo] = lazyLoadInfo; 46226 } 46227 } 46228 } 46229 46230 let Node$1 = class Node { 46231 constructor(name){ 46232 this.name = ''; 46233 this.children = new Array(); 46234 this.name = name; 46235 } 46236 }; 46237 class PrimitiveNode extends Node$1 { 46238 async setActiveMaterial(material) { 46239 const mvMaterial = this.materials.get(material); 46240 if (material !== this.activeMaterialIdx) { 46241 const backingMaterials = mvMaterial[$correlatedObjects]; 46242 const baseMaterial = await mvMaterial[$getLoadedMaterial](); 46243 if (baseMaterial != null) { 46244 this.mesh.material = baseMaterial; 46245 } else { 46246 this.mesh.material = backingMaterials.values().next().value; 46247 } 46248 this.parser.assignFinalMaterial(this.mesh); 46249 backingMaterials.add(this.mesh.material); 46250 this.activeMaterialIdx = material; 46251 } 46252 return this.mesh.material; 46253 } 46254 getActiveMaterial() { 46255 return this.materials.get(this.activeMaterialIdx); 46256 } 46257 getMaterial(index) { 46258 return this.materials.get(index); 46259 } 46260 async enableVariant(name) { 46261 if (name == null) { 46262 return this.setActiveMaterial(this.initialMaterialIdx); 46263 } 46264 if (this.variantToMaterialMap != null && this.modelVariants.has(name)) { 46265 const modelVariants = this.modelVariants.get(name); 46266 return this.enableVariantHelper(modelVariants.index); 46267 } 46268 return null; 46269 } 46270 async enableVariantHelper(index) { 46271 if (this.variantToMaterialMap != null && index != null) { 46272 const material = this.variantToMaterialMap.get(index); 46273 if (material != null) { 46274 return this.setActiveMaterial(material.index); 46275 } 46276 } 46277 return null; 46278 } 46279 async instantiateVariants() { 46280 if (this.variantToMaterialMap == null) { 46281 return; 46282 } 46283 for (const index of this.variantToMaterialMap.keys()){ 46284 const variantMaterial = this.mesh.userData.variantMaterials.get(index); 46285 if (variantMaterial.material != null) { 46286 continue; 46287 } 46288 const threeMaterial = await this.enableVariantHelper(index); 46289 if (threeMaterial != null) { 46290 variantMaterial.material = threeMaterial; 46291 } 46292 } 46293 } 46294 get variantInfo() { 46295 return this.variantToMaterialMap; 46296 } 46297 addVariant(materialVariant, variantName) { 46298 if (!this.ensureVariantIsUnused(variantName)) { 46299 return false; 46300 } 46301 if (!this.modelVariants.has(variantName)) { 46302 this.modelVariants.set(variantName, { 46303 name: variantName, 46304 index: this.modelVariants.size 46305 }); 46306 } 46307 const modelVariantData = this.modelVariants.get(variantName); 46308 const variantIndex = modelVariantData.index; 46309 materialVariant[$variantIndices].add(variantIndex); 46310 this.variantToMaterialMap.set(variantIndex, materialVariant); 46311 this.materials.set(materialVariant.index, materialVariant); 46312 this.updateVariantUserData(variantIndex, materialVariant); 46313 return true; 46314 } 46315 deleteVariant(variantIndex) { 46316 if (this.variantInfo.has(variantIndex)) { 46317 this.variantInfo.delete(variantIndex); 46318 const userDataMap = this.mesh.userData.variantMaterials; 46319 if (userDataMap != null) { 46320 userDataMap.delete(variantIndex); 46321 } 46322 } 46323 } 46324 updateVariantUserData(variantIndex, materialVariant) { 46325 materialVariant[$variantIndices].add(variantIndex); 46326 this.mesh.userData.variantData = this.modelVariants; 46327 this.mesh.userData.variantMaterials = this.mesh.userData.variantMaterials || new Map(); 46328 const map = this.mesh.userData.variantMaterials; 46329 map.set(variantIndex, { 46330 material: materialVariant[$correlatedObjects].values().next().value, 46331 gltfMaterialIndex: materialVariant.index 46332 }); 46333 } 46334 ensureVariantIsUnused(variantName) { 46335 const modelVariants = this.modelVariants.get(variantName); 46336 if (modelVariants != null && this.variantInfo.has(modelVariants.index)) { 46337 console.warn(`Primitive cannot add variant '${variantName}' for this material, it already exists.`); 46338 return false; 46339 } 46340 return true; 46341 } 46342 constructor(mesh, mvMaterials, modelVariants, correlatedSceneGraph){ 46343 super(mesh.name); 46344 this.materials = new Map(); 46345 this.variantToMaterialMap = new Map(); 46346 this.initialMaterialIdx = 0; 46347 this.activeMaterialIdx = 0; 46348 this.mesh = mesh; 46349 const { gltf, threeGLTF, threeObjectMap } = correlatedSceneGraph; 46350 this.parser = threeGLTF.parser; 46351 this.modelVariants = modelVariants; 46352 this.mesh.userData.variantData = modelVariants; 46353 const materialMappings = threeObjectMap.get(mesh.material); 46354 if (materialMappings.materials != null) { 46355 this.initialMaterialIdx = this.activeMaterialIdx = materialMappings.materials; 46356 } else { 46357 console.error(`Primitive (${mesh.name}) missing initial material reference.`); 46358 } 46359 const associations = mesh.userData.associations || {}; 46360 if (associations.meshes == null) { 46361 console.error('Mesh is missing primitive index association'); 46362 return; 46363 } 46364 const meshElementArray = gltf['meshes'] || []; 46365 const gltfPrimitives = meshElementArray[associations.meshes].primitives || []; 46366 const gltfPrimitive = gltfPrimitives[associations.primitives]; 46367 if (gltfPrimitive == null) { 46368 console.error('Mesh primitive definition is missing.'); 46369 return; 46370 } 46371 if (gltfPrimitive.material != null) { 46372 this.materials.set(gltfPrimitive.material, mvMaterials[gltfPrimitive.material]); 46373 } else { 46374 const defaultIdx = mvMaterials.findIndex((mat)=>{ 46375 return mat.name === 'Default'; 46376 }); 46377 if (defaultIdx >= 0) { 46378 this.materials.set(defaultIdx, mvMaterials[defaultIdx]); 46379 } else { 46380 console.warn('gltfPrimitive has no material!'); 46381 } 46382 } 46383 if (gltfPrimitive.extensions && gltfPrimitive.extensions['KHR_materials_variants']) { 46384 const variantsExtension = gltfPrimitive.extensions['KHR_materials_variants']; 46385 const extensions = threeGLTF.parser.json.extensions; 46386 const variantNames = extensions['KHR_materials_variants'].variants; 46387 for (const mapping of variantsExtension.mappings){ 46388 const mvMaterial = mvMaterials[mapping.material]; 46389 this.materials.set(mapping.material, mvMaterial); 46390 for (const variant of mapping.variants){ 46391 const { name } = variantNames[variant]; 46392 this.variantToMaterialMap.set(variant, mvMaterial); 46393 mvMaterial[$variantIndices].add(variant); 46394 if (!modelVariants.has(name)) { 46395 modelVariants.set(name, { 46396 name, 46397 index: variant 46398 }); 46399 } 46400 } 46401 } 46402 } 46403 } 46404 } 46405 46406 var _a$2, _b$2, _c$1, _d$1, _e$1, _f$1; 46407 const $materials = Symbol('materials'); 46408 const $hierarchy = Symbol('hierarchy'); 46409 const $roots = Symbol('roots'); 46410 const $primitivesList = Symbol('primitives'); 46411 const $prepareVariantsForExport = Symbol('prepareVariantsForExport'); 46412 const $switchVariant = Symbol('switchVariant'); 46413 const $materialFromPoint = Symbol('materialFromPoint'); 46414 const $nodeFromPoint = Symbol('nodeFromPoint'); 46415 const $nodeFromIndex = Symbol('nodeFromIndex'); 46416 const $variantData = Symbol('variantData'); 46417 const $availableVariants = Symbol('availableVariants'); 46418 const $modelOnUpdate = Symbol('modelOnUpdate'); 46419 const $cloneMaterial = Symbol('cloneMaterial'); 46420 class LazyLoader { 46421 constructor(gltf, gltfElementMap, mapKey, doLazyLoad){ 46422 this.gltf = gltf; 46423 this.gltfElementMap = gltfElementMap; 46424 this.mapKey = mapKey; 46425 this.doLazyLoad = doLazyLoad; 46426 } 46427 } 46428 class Model { 46429 get materials() { 46430 return this[$materials]; 46431 } 46432 [(_a$2 = $materials, _b$2 = $hierarchy, _c$1 = $roots, _d$1 = $primitivesList, _e$1 = $modelOnUpdate, _f$1 = $variantData, $availableVariants)]() { 46433 const variants = Array.from(this[$variantData].values()); 46434 variants.sort((a, b)=>{ 46435 return a.index - b.index; 46436 }); 46437 return variants.map((data)=>{ 46438 return data.name; 46439 }); 46440 } 46441 getMaterialByName(name) { 46442 const matches = this[$materials].filter((material)=>{ 46443 return material.name === name; 46444 }); 46445 if (matches.length > 0) { 46446 return matches[0]; 46447 } 46448 return null; 46449 } 46450 [$nodeFromIndex](mesh, primitive) { 46451 const found = this[$hierarchy].find((node)=>{ 46452 if (node instanceof PrimitiveNode) { 46453 const { meshes, primitives } = node.mesh.userData.associations; 46454 if (meshes == mesh && primitives == primitive) { 46455 return true; 46456 } 46457 } 46458 return false; 46459 }); 46460 return found == null ? null : found; 46461 } 46462 [$nodeFromPoint](hit) { 46463 return this[$hierarchy].find((node)=>{ 46464 if (node instanceof PrimitiveNode) { 46465 const primitive = node; 46466 if (primitive.mesh === hit.object) { 46467 return true; 46468 } 46469 } 46470 return false; 46471 }); 46472 } 46473 [$materialFromPoint](hit) { 46474 return this[$nodeFromPoint](hit).getActiveMaterial(); 46475 } 46476 async [$switchVariant](variantName) { 46477 for (const primitive of this[$primitivesList]){ 46478 await primitive.enableVariant(variantName); 46479 } 46480 for (const material of this.materials){ 46481 material[$setActive](false); 46482 } 46483 for (const primitive of this[$primitivesList]){ 46484 this.materials[primitive.getActiveMaterial().index][$setActive](true); 46485 } 46486 } 46487 async [$prepareVariantsForExport]() { 46488 const promises = new Array(); 46489 for (const primitive of this[$primitivesList]){ 46490 promises.push(primitive.instantiateVariants()); 46491 } 46492 await Promise.all(promises); 46493 } 46494 [$cloneMaterial](index, newMaterialName) { 46495 const material = this.materials[index]; 46496 if (!material.isLoaded) { 46497 console.error(`Cloning an unloaded material, 46498 call 'material.ensureLoaded() before cloning the material.`); 46499 } 46500 const threeMaterialSet = material[$correlatedObjects]; 46501 const clonedSet = new Set(); 46502 for (const [i, threeMaterial] of threeMaterialSet.entries()){ 46503 const clone = threeMaterial.clone(); 46504 clone.name = newMaterialName + (threeMaterialSet.size > 1 ? '_inst' + i : ''); 46505 clonedSet.add(clone); 46506 } 46507 const clonedMaterial = new Material(this[$modelOnUpdate], this[$materials].length, false, this[$variantData], clonedSet, newMaterialName); 46508 this[$materials].push(clonedMaterial); 46509 return clonedMaterial; 46510 } 46511 createMaterialInstanceForVariant(originalMaterialIndex, newMaterialName, variantName, activateVariant = true) { 46512 let variantMaterialInstance = null; 46513 for (const primitive of this[$primitivesList]){ 46514 const variantData = this[$variantData].get(variantName); 46515 if (variantData != null && primitive.variantInfo.has(variantData.index)) { 46516 continue; 46517 } 46518 if (primitive.getMaterial(originalMaterialIndex) == null) { 46519 continue; 46520 } 46521 if (!this.hasVariant(variantName)) { 46522 this.createVariant(variantName); 46523 } 46524 if (variantMaterialInstance == null) { 46525 variantMaterialInstance = this[$cloneMaterial](originalMaterialIndex, newMaterialName); 46526 } 46527 primitive.addVariant(variantMaterialInstance, variantName); 46528 } 46529 if (activateVariant && variantMaterialInstance != null) { 46530 variantMaterialInstance[$setActive](true); 46531 this.materials[originalMaterialIndex][$setActive](false); 46532 for (const primitive of this[$primitivesList]){ 46533 primitive.enableVariant(variantName); 46534 } 46535 } 46536 return variantMaterialInstance; 46537 } 46538 createVariant(variantName) { 46539 if (!this[$variantData].has(variantName)) { 46540 this[$variantData].set(variantName, { 46541 name: variantName, 46542 index: this[$variantData].size 46543 }); 46544 } else { 46545 console.warn(`Variant '${variantName}'' already exists`); 46546 } 46547 } 46548 hasVariant(variantName) { 46549 return this[$variantData].has(variantName); 46550 } 46551 setMaterialToVariant(materialIndex, targetVariantName) { 46552 if (this[$availableVariants]().find((name)=>name === targetVariantName) == null) { 46553 console.warn(`Can't add material to '${targetVariantName}', the variant does not exist.'`); 46554 return; 46555 } 46556 if (materialIndex < 0 || materialIndex >= this.materials.length) { 46557 console.error(`setMaterialToVariant(): materialIndex is out of bounds.`); 46558 return; 46559 } 46560 for (const primitive of this[$primitivesList]){ 46561 const material = primitive.getMaterial(materialIndex); 46562 if (material != null) { 46563 primitive.addVariant(material, targetVariantName); 46564 } 46565 } 46566 }
vendor: 15,708 bytes, lines 46567-46965
46567 updateVariantName(currentName, newName) { 46568 const variantData = this[$variantData].get(currentName); 46569 if (variantData == null) { 46570 return; 46571 } 46572 variantData.name = newName; 46573 this[$variantData].set(newName, variantData); 46574 this[$variantData].delete(currentName); 46575 } 46576 deleteVariant(variantName) { 46577 const variant = this[$variantData].get(variantName); 46578 if (variant == null) { 46579 return; 46580 } 46581 for (const material of this.materials){ 46582 if (material.hasVariant(variantName)) { 46583 material[$variantIndices].delete(variant.index); 46584 } 46585 } 46586 for (const primitive of this[$primitivesList]){ 46587 primitive.deleteVariant(variant.index); 46588 } 46589 this[$variantData].delete(variantName); 46590 } 46591 constructor(correlatedSceneGraph, onUpdate = ()=>{}){ 46592 this[_a$2] = new Array(); 46593 this[_b$2] = new Array(); 46594 this[_c$1] = new Array(); 46595 this[_d$1] = new Array(); 46596 this[_e$1] = ()=>{}; 46597 this[_f$1] = new Map(); 46598 this[$modelOnUpdate] = onUpdate; 46599 const { gltf, threeGLTF, gltfElementMap } = correlatedSceneGraph; 46600 for (const [i, material] of gltf.materials.entries()){ 46601 const correlatedMaterial = gltfElementMap.get(material); 46602 if (correlatedMaterial != null) { 46603 this[$materials].push(new Material(onUpdate, i, true, this[$variantData], correlatedMaterial, material.name)); 46604 } else { 46605 const elementArray = gltf['materials'] || []; 46606 const gltfMaterialDef = elementArray[i]; 46607 const threeMaterialSet = new Set(); 46608 gltfElementMap.set(gltfMaterialDef, threeMaterialSet); 46609 const materialLoadCallback = async ()=>{ 46610 const threeMaterial = await threeGLTF.parser.getDependency('material', i); 46611 threeMaterialSet.add(threeMaterial); 46612 return threeMaterial; 46613 }; 46614 this[$materials].push(new Material(onUpdate, i, false, this[$variantData], threeMaterialSet, material.name, new LazyLoader(gltf, gltfElementMap, gltfMaterialDef, materialLoadCallback))); 46615 } 46616 } 46617 const parentMap = new Map(); 46618 const nodeStack = new Array(); 46619 for (const object of threeGLTF.scene.children){ 46620 nodeStack.push(object); 46621 } 46622 while(nodeStack.length > 0){ 46623 const object = nodeStack.pop(); 46624 let node = null; 46625 if (object instanceof Mesh) { 46626 node = new PrimitiveNode(object, this.materials, this[$variantData], correlatedSceneGraph); 46627 this[$primitivesList].push(node); 46628 } else { 46629 node = new Node$1(object.name); 46630 } 46631 const parent = parentMap.get(object); 46632 if (parent != null) { 46633 parent.children.push(node); 46634 } else { 46635 this[$roots].push(node); 46636 } 46637 this[$hierarchy].push(node); 46638 for (const child of object.children){ 46639 nodeStack.push(child); 46640 parentMap.set(object, node); 46641 } 46642 } 46643 } 46644 } 46645 46646 var __decorate$5 = undefined && undefined.__decorate || function(decorators, target, key, desc) { 46647 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 46648 for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 46649 return c > 3 && r && Object.defineProperty(target, key, r), r; 46650 }; 46651 const $currentGLTF = Symbol('currentGLTF'); 46652 const $originalGltfJson = Symbol('originalGltfJson'); 46653 const $model = Symbol('model'); 46654 const $getOnUpdateMethod = Symbol('getOnUpdateMethod'); 46655 const $buildTexture = Symbol('buildTexture'); 46656 const SceneGraphMixin = (ModelViewerElement)=>{ 46657 var _a, _b, _c; 46658 class SceneGraphModelViewerElement extends ModelViewerElement { 46659 get model() { 46660 return this[$model]; 46661 } 46662 get availableVariants() { 46663 return this.model ? this.model[$availableVariants]() : []; 46664 } 46665 get originalGltfJson() { 46666 return this[$originalGltfJson]; 46667 } 46668 [(_a = $model, _b = $currentGLTF, _c = $originalGltfJson, $getOnUpdateMethod)]() { 46669 return ()=>{ 46670 this[$needsRender](); 46671 }; 46672 } 46673 [$buildTexture](texture) { 46674 texture.colorSpace = SRGBColorSpace; 46675 texture.wrapS = RepeatWrapping; 46676 texture.wrapT = RepeatWrapping; 46677 return new Texture(this[$getOnUpdateMethod](), texture); 46678 } 46679 async createTexture(uri, type = 'image/png') { 46680 const { textureUtils } = this[$renderer]; 46681 const texture = await textureUtils.loadImage(uri, this.withCredentials); 46682 texture.userData.mimeType = type; 46683 return this[$buildTexture](texture); 46684 } 46685 async createLottieTexture(uri, quality = 1) { 46686 const { textureUtils } = this[$renderer]; 46687 const texture = await textureUtils.loadLottie(uri, quality, this.withCredentials); 46688 return this[$buildTexture](texture); 46689 } 46690 createVideoTexture(uri) { 46691 const video = document.createElement('video'); 46692 video.crossOrigin = this.withCredentials ? 'use-credentials' : 'anonymous'; 46693 video.src = uri; 46694 video.muted = true; 46695 video.playsInline = true; 46696 video.loop = true; 46697 video.play(); 46698 const texture = new VideoTexture(video); 46699 return this[$buildTexture](texture); 46700 } 46701 createCanvasTexture() { 46702 const canvas = document.createElement('canvas'); 46703 const texture = new CanvasTexture(canvas); 46704 return this[$buildTexture](texture); 46705 } 46706 async updated(changedProperties) { 46707 super.updated(changedProperties); 46708 if (changedProperties.has('variantName')) { 46709 const updateVariantProgress = this[$progressTracker].beginActivity('variant-update'); 46710 updateVariantProgress(0.1); 46711 const model = this[$model]; 46712 const { variantName } = this; 46713 if (model != null) { 46714 await model[$switchVariant](variantName); 46715 this[$needsRender](); 46716 this.dispatchEvent(new CustomEvent('variant-applied')); 46717 } 46718 updateVariantProgress(1.0); 46719 } 46720 if (changedProperties.has('orientation') || changedProperties.has('scale')) { 46721 if (!this.loaded) { 46722 return; 46723 } 46724 const scene = this[$scene]; 46725 scene.applyTransform(); 46726 scene.updateBoundingBox(); 46727 scene.updateShadow(); 46728 this[$renderer].arRenderer.onUpdateScene(); 46729 this[$needsRender](); 46730 } 46731 } 46732 [$onModelLoad]() { 46733 super[$onModelLoad](); 46734 const { currentGLTF } = this[$scene]; 46735 if (currentGLTF != null) { 46736 const { correlatedSceneGraph } = currentGLTF; 46737 if (correlatedSceneGraph != null && currentGLTF !== this[$currentGLTF]) { 46738 this[$model] = new Model(correlatedSceneGraph, this[$getOnUpdateMethod]()); 46739 this[$originalGltfJson] = JSON.parse(JSON.stringify(correlatedSceneGraph.gltf)); 46740 } 46741 if ('variants' in currentGLTF.userData) { 46742 this.requestUpdate('variantName'); 46743 } 46744 } 46745 this[$currentGLTF] = currentGLTF; 46746 } 46747 async exportScene(options) { 46748 const scene = this[$scene]; 46749 return new Promise(async (resolve, reject)=>{ 46750 const opts = { 46751 binary: true, 46752 onlyVisible: true, 46753 maxTextureSize: Infinity, 46754 includeCustomExtensions: false, 46755 forceIndices: false 46756 }; 46757 Object.assign(opts, options); 46758 opts.animations = scene.animations; 46759 opts.truncateDrawRange = true; 46760 const shadow = scene.shadow; 46761 let visible = false; 46762 if (shadow != null) { 46763 visible = shadow.visible; 46764 shadow.visible = false; 46765 } 46766 await this[$model][$prepareVariantsForExport](); 46767 const exporter = new GLTFExporter().register((writer)=>new GLTFExporterMaterialsVariantsExtension(writer)); 46768 exporter.parse(scene.model, (gltf)=>{ 46769 return resolve(new Blob([ 46770 opts.binary ? gltf : JSON.stringify(gltf) 46771 ], { 46772 type: opts.binary ? 'application/octet-stream' : 'application/json' 46773 })); 46774 }, ()=>{ 46775 return reject('glTF export failed'); 46776 }, opts); 46777 if (shadow != null) { 46778 shadow.visible = visible; 46779 } 46780 }); 46781 } 46782 materialFromPoint(pixelX, pixelY) { 46783 const model = this[$model]; 46784 if (model == null) { 46785 return null; 46786 } 46787 const scene = this[$scene]; 46788 const ndcCoords = scene.getNDC(pixelX, pixelY); 46789 const hit = scene.hitFromPoint(ndcCoords); 46790 if (hit == null || hit.face == null) { 46791 return null; 46792 } 46793 return model[$materialFromPoint](hit); 46794 } 46795 constructor(){ 46796 super(...arguments); 46797 this[_a] = undefined; 46798 this[_b] = null; 46799 this[_c] = null; 46800 this.variantName = null; 46801 this.orientation = '0 0 0'; 46802 this.scale = '1 1 1'; 46803 } 46804 } 46805 __decorate$5([ 46806 n$2({ 46807 type: String, 46808 attribute: 'variant-name' 46809 }) 46810 ], SceneGraphModelViewerElement.prototype, "variantName", void 0); 46811 __decorate$5([ 46812 n$2({ 46813 type: String, 46814 attribute: 'orientation' 46815 }) 46816 ], SceneGraphModelViewerElement.prototype, "orientation", void 0); 46817 __decorate$5([ 46818 n$2({ 46819 type: String, 46820 attribute: 'scale' 46821 }) 46822 ], SceneGraphModelViewerElement.prototype, "scale", void 0); 46823 return SceneGraphModelViewerElement; 46824 }; 46825 46826 class GroundedSkybox extends Mesh { 46827 get map() { 46828 return this.material.map; 46829 } 46830 set map(skybox) { 46831 this.material.map = skybox; 46832 } 46833 isUsable() { 46834 return this.height > 0 && this.radius > 0 && this.geometry != null && this.map != null; 46835 } 46836 updateGeometry(height = this.height, radius = this.radius, resolution = 128) { 46837 if (height != this.height || radius != this.radius || resolution != this.resolution) { 46838 this.height = height; 46839 this.radius = radius; 46840 this.resolution = resolution; 46841 if (height > 0 && radius > 0) { 46842 this.geometry.dispose(); 46843 this.geometry = makeGeometry(height, radius, resolution); 46844 } 46845 } 46846 } 46847 constructor(){ 46848 super(undefined, new MeshBasicMaterial({ 46849 depthWrite: false 46850 })); 46851 this.height = 0; 46852 this.radius = 0; 46853 this.resolution = 0; 46854 this.userData.noHit = true; 46855 } 46856 } 46857 function makeGeometry(height, radius, resolution) { 46858 const geometry = new SphereGeometry(radius, 2 * resolution, resolution); 46859 geometry.scale(1, 1, -1); 46860 const pos = geometry.getAttribute('position'); 46861 const tmp = new Vector3(); 46862 for(let i = 0; i < pos.count; ++i){ 46863 tmp.fromBufferAttribute(pos, i); 46864 if (tmp.y < 0) { 46865 const y1 = -height * 3 / 2; 46866 const f = tmp.y < y1 ? -height / tmp.y : 1 - tmp.y * tmp.y / (3 * y1 * y1); 46867 tmp.multiplyScalar(f); 46868 tmp.toArray(pos.array, 3 * i); 46869 } 46870 } 46871 pos.needsUpdate = true; 46872 return geometry; 46873 } 46874 46875 const a = new Vector3(); 46876 const b = new Vector3(); 46877 const c = new Vector3(); 46878 const mat = new Matrix3(); 46879 const triangle = new Triangle(); 46880 const quat = new Quaternion(); 46881 class Hotspot extends CSS2DObject { 46882 get facingCamera() { 46883 return !this.element.classList.contains('hide'); 46884 } 46885 show() { 46886 if (!this.facingCamera || !this.initialized) { 46887 this.updateVisibility(true); 46888 } 46889 } 46890 hide() { 46891 if (this.facingCamera || !this.initialized) { 46892 this.updateVisibility(false); 46893 } 46894 } 46895 increment() { 46896 this.referenceCount++; 46897 } 46898 decrement() { 46899 if (this.referenceCount > 0) { 46900 --this.referenceCount; 46901 } 46902 return this.referenceCount === 0; 46903 } 46904 updatePosition(position) { 46905 if (position == null) return; 46906 const positionNodes = parseExpressions(position)[0].terms; 46907 for(let i = 0; i < 3; ++i){ 46908 this.position.setComponent(i, normalizeUnit(positionNodes[i]).number); 46909 } 46910 this.updateMatrixWorld(); 46911 } 46912 updateNormal(normal) { 46913 if (normal == null) return; 46914 const normalNodes = parseExpressions(normal)[0].terms; 46915 for(let i = 0; i < 3; ++i){ 46916 this.normal.setComponent(i, normalNodes[i].number); 46917 } 46918 } 46919 updateSurface() { 46920 const { mesh, tri, bary } = this; 46921 if (mesh == null || tri == null || bary == null) { 46922 return; 46923 } 46924 mesh.getVertexPosition(tri.x, a); 46925 mesh.getVertexPosition(tri.y, b); 46926 mesh.getVertexPosition(tri.z, c); 46927 a.toArray(mat.elements, 0); 46928 b.toArray(mat.elements, 3); 46929 c.toArray(mat.elements, 6); 46930 this.position.copy(bary).applyMatrix3(mat); 46931 const target = this.parent; 46932 target.worldToLocal(mesh.localToWorld(this.position)); 46933 triangle.set(a, b, c); 46934 triangle.getNormal(this.normal).transformDirection(mesh.matrixWorld); 46935 const pivot = target.parent; 46936 quat.setFromAxisAngle(a.set(0, 1, 0), -pivot.rotation.y); 46937 this.normal.applyQuaternion(quat); 46938 } 46939 orient(radians) { 46940 this.pivot.style.transform = `rotate(${radians}rad)`; 46941 } 46942 updateVisibility(show) { 46943 this.element.classList.toggle('hide', !show); 46944 this.slot.assignedNodes().forEach((node)=>{ 46945 if (node.nodeType !== Node.ELEMENT_NODE) { 46946 return; 46947 } 46948 const element = node; 46949 const visibilityAttribute = element.dataset.visibilityAttribute; 46950 if (visibilityAttribute != null) { 46951 const attributeName = `data-${visibilityAttribute}`; 46952 element.toggleAttribute(attributeName, show); 46953 } 46954 element.dispatchEvent(new CustomEvent('hotspot-visibility', { 46955 detail: { 46956 visible: show 46957 } 46958 })); 46959 }); 46960 this.initialized = true; 46961 } 46962 constructor(config){ 46963 super(document.createElement('div')); 46964 this.normal = new Vector3(0, 1, 0); 46965 this.initialized = false;
vendor: 4,404 bytes, lines 46966-47107
46966 this.referenceCount = 1; 46967 this.pivot = document.createElement('div'); 46968 this.slot = document.createElement('slot'); 46969 this.element.classList.add('annotation-wrapper'); 46970 this.slot.name = config.name; 46971 this.element.appendChild(this.pivot); 46972 this.pivot.appendChild(this.slot); 46973 this.updatePosition(config.position); 46974 this.updateNormal(config.normal); 46975 this.surface = config.surface; 46976 } 46977 } 46978 46979 /** 46980 * Two pass Gaussian blur filter (horizontal and vertical blur shaders) 46981 * - see http://www.cake23.de/traveling-wavefronts-lit-up.html 46982 * 46983 * - 9 samples per pass 46984 * - standard deviation 2.7 46985 * - "h" and "v" parameters should be set to "1 / width" and "1 / height" 46986 */ const HorizontalBlurShader = { 46987 name: 'HorizontalBlurShader', 46988 uniforms: { 46989 'tDiffuse': { 46990 value: null 46991 }, 46992 'h': { 46993 value: 1.0 / 512.0 46994 } 46995 }, 46996 vertexShader: /* glsl */ ` 46997 46998 varying vec2 vUv; 46999 47000 void main() { 47001 47002 vUv = uv; 47003 gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); 47004 47005 }`, 47006 fragmentShader: /* glsl */ ` 47007 47008 uniform sampler2D tDiffuse; 47009 uniform float h; 47010 47011 varying vec2 vUv; 47012 47013 void main() { 47014 47015 vec4 sum = vec4( 0.0 ); 47016 47017 sum += texture2D( tDiffuse, vec2( vUv.x - 4.0 * h, vUv.y ) ) * 0.051; 47018 sum += texture2D( tDiffuse, vec2( vUv.x - 3.0 * h, vUv.y ) ) * 0.0918; 47019 sum += texture2D( tDiffuse, vec2( vUv.x - 2.0 * h, vUv.y ) ) * 0.12245; 47020 sum += texture2D( tDiffuse, vec2( vUv.x - 1.0 * h, vUv.y ) ) * 0.1531; 47021 sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y ) ) * 0.1633; 47022 sum += texture2D( tDiffuse, vec2( vUv.x + 1.0 * h, vUv.y ) ) * 0.1531; 47023 sum += texture2D( tDiffuse, vec2( vUv.x + 2.0 * h, vUv.y ) ) * 0.12245; 47024 sum += texture2D( tDiffuse, vec2( vUv.x + 3.0 * h, vUv.y ) ) * 0.0918; 47025 sum += texture2D( tDiffuse, vec2( vUv.x + 4.0 * h, vUv.y ) ) * 0.051; 47026 47027 gl_FragColor = sum; 47028 47029 }` 47030 }; 47031 47032 /** 47033 * Two pass Gaussian blur filter (horizontal and vertical blur shaders) 47034 * - see http://www.cake23.de/traveling-wavefronts-lit-up.html 47035 * 47036 * - 9 samples per pass 47037 * - standard deviation 2.7 47038 * - "h" and "v" parameters should be set to "1 / width" and "1 / height" 47039 */ const VerticalBlurShader = { 47040 name: 'VerticalBlurShader', 47041 uniforms: { 47042 'tDiffuse': { 47043 value: null 47044 }, 47045 'v': { 47046 value: 1.0 / 512.0 47047 } 47048 }, 47049 vertexShader: /* glsl */ ` 47050 47051 varying vec2 vUv; 47052 47053 void main() { 47054 47055 vUv = uv; 47056 gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); 47057 47058 }`, 47059 fragmentShader: /* glsl */ ` 47060 47061 uniform sampler2D tDiffuse; 47062 uniform float v; 47063 47064 varying vec2 vUv; 47065 47066 void main() { 47067 47068 vec4 sum = vec4( 0.0 ); 47069 47070 sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 4.0 * v ) ) * 0.051; 47071 sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 3.0 * v ) ) * 0.0918; 47072 sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 2.0 * v ) ) * 0.12245; 47073 sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y - 1.0 * v ) ) * 0.1531; 47074 sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y ) ) * 0.1633; 47075 sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 1.0 * v ) ) * 0.1531; 47076 sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 2.0 * v ) ) * 0.12245; 47077 sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 3.0 * v ) ) * 0.0918; 47078 sum += texture2D( tDiffuse, vec2( vUv.x, vUv.y + 4.0 * v ) ) * 0.051; 47079 47080 gl_FragColor = sum; 47081 47082 }` 47083 }; 47084 47085 /** 47086 * Returns a value linearly interpolated from two known points based on the given interval - 47087 * `t = 0` will return `x` and `t = 1` will return `y`. 47088 * 47089 * @param {number} x - The start point 47090 * @param {number} y - The end point. 47091 * @param {number} t - The interpolation factor in the closed interval `[0, 1]`. 47092 * @return {number} The interpolated value. 47093 */ function lerp(x, y, t) { 47094 return (1 - t) * x + t * y; 47095 } 47096 47097 const LOG_MAX_RESOLUTION = 9; 47098 const LOG_MIN_RESOLUTION = 6; 47099 const ANIMATION_SCALING = 2; 47100 const DEFAULT_HARD_INTENSITY = 0.3; 47101 class Shadow extends Object3D { 47102 setScene(scene, softness, side) { 47103 const { boundingBox, size, rotation, position } = this; 47104 this.isAnimated = scene.animationNames.length > 0; 47105 this.boundingBox.copy(scene.boundingBox); 47106 this.size.copy(scene.size); 47107 this.maxDimension = Math.max(size.x, size.y, size.z) * (this.isAnimated ? ANIMATION_
vendor: 10,021 bytes, lines 47107-47372
47107SCALING : 1); 47108 this.boundingBox.getCenter(position); 47109 if (side === 'back') { 47110 const { min, max } = boundingBox; 47111 [min.y, min.z] = [ 47112 min.z, 47113 min.y 47114 ]; 47115 [max.y, max.z] = [ 47116 max.z, 47117 max.y 47118 ]; 47119 [size.y, size.z] = [ 47120 size.z, 47121 size.y 47122 ]; 47123 rotation.x = Math.PI / 2; 47124 rotation.y = Math.PI; 47125 } else { 47126 rotation.x = 0; 47127 rotation.y = 0; 47128 } 47129 if (this.isAnimated) { 47130 const minY = boundingBox.min.y; 47131 const maxY = boundingBox.max.y; 47132 size.y = this.maxDimension; 47133 boundingBox.expandByVector(size.subScalar(this.maxDimension).multiplyScalar(-0.5)); 47134 boundingBox.min.y = minY; 47135 boundingBox.max.y = maxY; 47136 size.set(this.maxDimension, maxY - minY, this.maxDimension); 47137 } 47138 if (side === 'bottom') { 47139 position.y = boundingBox.min.y; 47140 } else { 47141 position.z = boundingBox.min.y; 47142 } 47143 this.setSoftness(softness); 47144 } 47145 setSoftness(softness) { 47146 this.softness = softness; 47147 const { size, camera } = this; 47148 const scaleY = this.isAnimated ? ANIMATION_SCALING : 1; 47149 const resolution = scaleY * Math.pow(2, LOG_MAX_RESOLUTION - softness * (LOG_MAX_RESOLUTION - LOG_MIN_RESOLUTION)); 47150 this.setMapSize(resolution); 47151 const softFar = size.y / 2; 47152 const hardFar = size.y * scaleY; 47153 camera.near = 0; 47154 camera.far = lerp(hardFar, softFar, softness); 47155 this.depthMaterial.opacity = 1.0 / softness; 47156 camera.updateProjectionMatrix(); 47157 this.setIntensity(this.intensity); 47158 this.setOffset(0); 47159 } 47160 setMapSize(maxMapSize) { 47161 const { size } = this; 47162 if (this.isAnimated) { 47163 maxMapSize *= ANIMATION_SCALING; 47164 } 47165 const baseWidth = Math.floor(size.x > size.z ? maxMapSize : maxMapSize * size.x / size.z); 47166 const baseHeight = Math.floor(size.x > size.z ? maxMapSize * size.z / size.x : maxMapSize); 47167 const TAP_WIDTH = 10; 47168 const width = TAP_WIDTH + baseWidth; 47169 const height = TAP_WIDTH + baseHeight; 47170 if (this.renderTarget != null && (this.renderTarget.width !== width || this.renderTarget.height !== height)) { 47171 this.renderTarget.dispose(); 47172 this.renderTarget = null; 47173 this.renderTargetBlur.dispose(); 47174 this.renderTargetBlur = null; 47175 } 47176 if (this.renderTarget == null) { 47177 const params = { 47178 format: RGBAFormat 47179 }; 47180 this.renderTarget = new WebGLRenderTarget(width, height, params); 47181 this.renderTargetBlur = new WebGLRenderTarget(width, height, params); 47182 this.floor.material.map = this.renderTarget.texture; 47183 } 47184 this.camera.scale.set(size.x * (1 + TAP_WIDTH / baseWidth), size.z * (1 + TAP_WIDTH / baseHeight), 1); 47185 this.needsUpdate = true; 47186 } 47187 setIntensity(intensity) { 47188 this.intensity = intensity; 47189 if (intensity > 0) { 47190 this.visible = true; 47191 this.floor.visible = true; 47192 this.floor.material.opacity = intensity * lerp(DEFAULT_HARD_INTENSITY, 1, this.softness * this.softness); 47193 } else { 47194 this.visible = false; 47195 this.floor.visible = false; 47196 } 47197 } 47198 getIntensity() { 47199 return this.intensity; 47200 } 47201 setOffset(offset) { 47202 this.floor.position.z = -offset + this.gap(); 47203 } 47204 gap() { 47205 return 0.001 * this.maxDimension; 47206 } 47207 render(renderer, scene) { 47208 scene.overrideMaterial = this.depthMaterial; 47209 const initialClearAlpha = renderer.getClearAlpha(); 47210 renderer.setClearAlpha(0); 47211 this.floor.visible = false; 47212 const xrEnabled = renderer.xr.enabled; 47213 renderer.xr.enabled = false; 47214 const oldRenderTarget = renderer.getRenderTarget(); 47215 renderer.setRenderTarget(this.renderTarget); 47216 renderer.render(scene, this.camera); 47217 scene.overrideMaterial = null; 47218 this.floor.visible = true; 47219 this.blurShadow(renderer); 47220 renderer.xr.enabled = xrEnabled; 47221 renderer.setRenderTarget(oldRenderTarget); 47222 renderer.setClearAlpha(initialClearAlpha); 47223 } 47224 blurShadow(renderer) { 47225 const { camera, horizontalBlurMaterial, verticalBlurMaterial, renderTarget, renderTargetBlur, blurPlane } = this; 47226 blurPlane.visible = true; 47227 blurPlane.material = horizontalBlurMaterial; 47228 horizontalBlurMaterial.uniforms.h.value = 1 / this.renderTarget.width; 47229 horizontalBlurMaterial.uniforms.tDiffuse.value = this.renderTarget.texture; 47230 renderer.setRenderTarget(renderTargetBlur); 47231 renderer.render(blurPlane, camera); 47232 blurPlane.material = verticalBlurMaterial; 47233 verticalBlurMaterial.uniforms.v.value = 1 / this.renderTarget.height; 47234 verticalBlurMaterial.uniforms.tDiffuse.value = this.renderTargetBlur.texture; 47235 renderer.setRenderTarget(renderTarget); 47236 renderer.render(blurPlane, camera); 47237 blurPlane.visible = false; 47238 } 47239 dispose() { 47240 if (this.renderTarget != null) { 47241 this.renderTarget.dispose(); 47242 } 47243 if (this.renderTargetBlur != null) { 47244 this.renderTargetBlur.dispose(); 47245 } 47246 this.depthMaterial.dispose(); 47247 this.horizontalBlurMaterial.dispose(); 47248 this.verticalBlurMaterial.dispose(); 47249 this.floor.material.dispose(); 47250 this.floor.geometry.dispose(); 47251 this.blurPlane.geometry.dispose(); 47252 this.removeFromParent(); 47253 } 47254 constructor(scene, softness, side){ 47255 super(); 47256 this.camera = new OrthographicCamera(); 47257 this.renderTarget = null; 47258 this.renderTargetBlur = null; 47259 this.depthMaterial = new MeshDepthMaterial(); 47260 this.horizontalBlurMaterial = new ShaderMaterial(HorizontalBlurShader); 47261 this.verticalBlurMaterial = new ShaderMaterial(VerticalBlurShader); 47262 this.intensity = 0; 47263 this.softness = 1; 47264 this.boundingBox = new Box3; 47265 this.size = new Vector3; 47266 this.maxDimension = 0; 47267 this.isAnimated = false; 47268 this.needsUpdate = false; 47269 const { camera } = this; 47270 camera.rotation.x = Math.PI / 2; 47271 camera.left = -0.5; 47272 camera.right = 0.5; 47273 camera.bottom = -0.5; 47274 camera.top = 0.5; 47275 this.add(camera); 47276 const plane = new PlaneGeometry(); 47277 const shadowMaterial = new MeshBasicMaterial({ 47278 opacity: 1, 47279 transparent: true, 47280 side: BackSide 47281 }); 47282 this.floor = new Mesh(plane, shadowMaterial); 47283 this.floor.userData.noHit = true; 47284 camera.add(this.floor); 47285 this.blurPlane = new Mesh(plane); 47286 this.blurPlane.visible = false; 47287 camera.add(this.blurPlane); 47288 scene.target.add(this); 47289 this.depthMaterial.onBeforeCompile = function(shader) { 47290 shader.fragmentShader = shader.fragmentShader.replace('gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );', 'gl_FragColor = vec4( vec3( 0.0 ), ( 1.0 - fragCoordZ ) * opacity );'); 47291 }; 47292 this.depthMaterial.side = DoubleSide; 47293 this.horizontalBlurMaterial.depthTest = false; 47294 this.verticalBlurMaterial.depthTest = false; 47295 this.setScene(scene, softness, side); 47296 } 47297 } 47298 47299 const GROUNDED_SKYBOX_SIZE = 10; 47300 const MIN_SHADOW_RATIO = 100; 47301 const view = new Vector3(); 47302 const target = new Vector3(); 47303 const normalWorld = new Vector3(); 47304 const raycaster = new Raycaster(); 47305 const vector3 = new Vector3(); 47306 const ndc = new Vector2(); 47307 class ModelScene extends Scene { 47308 get context() { 47309 return this.canvas.getContext('2d'); 47310 } 47311 getCamera() { 47312 return this.xrCamera != null ? this.xrCamera : this.camera; 47313 } 47314 queueRender() { 47315 this.isDirty = true; 47316 } 47317 shouldRender() { 47318 return this.isDirty; 47319 } 47320 hasRendered() { 47321 this.isDirty = false; 47322 } 47323 forceRescale() { 47324 this.scaleStep = -1; 47325 this.queueRender(); 47326 } 47327 async setObject(model) { 47328 this.reset(); 47329 this._model = model; 47330 this.target.add(model); 47331 await this.setupScene(); 47332 } 47333 async setSource(url, progressCallback = ()=>{}) { 47334 if (!url || url === this.url) { 47335 progressCallback(1); 47336 return; 47337 } 47338 this.reset(); 47339 this.url = url; 47340 if (this.externalRenderer != null) { 47341 const framingInfo = await this.externalRenderer.load(progressCallback); 47342 this.boundingSphere.radius = framingInfo.framedRadius; 47343 this.idealAspect = framingInfo.fieldOfViewAspect; 47344 return; 47345 } 47346 if (this.cancelPendingSourceChange != null) { 47347 this.cancelPendingSourceChange(); 47348 this.cancelPendingSourceChange = null; 47349 } 47350 let gltf; 47351 try { 47352 gltf = await new Promise(async (resolve, reject)=>{ 47353 this.cancelPendingSourceChange = ()=>reject(); 47354 try { 47355 const result = await this.element[$renderer].loader.load(url, this.element, progressCallback); 47356 resolve(result); 47357 } catch (error) { 47358 reject(error); 47359 } 47360 }); 47361 } catch (error) { 47362 if (error == null) { 47363 return; 47364 } 47365 throw error; 47366 } 47367 this.cancelPendingSourceChange = null; 47368 this.reset(); 47369 this.url = url; 47370 this._currentGLTF = gltf; 47371 if (gltf != null) { 47372 this._model = gltf.scene;
47373 this.target.add(gltf.scene); 47374 } 47375 const { animations } = gltf; 47376 const animationsByName = new Map(); 47377 const animationNames = []; 47378 for (const animation of animations){ 47379 animationsByName.set(animation.name, animation); 47380 animationNames.push(animation.name); 47381 } 47382 this.animations = animations; 47383 this.animationsByName = animationsByName; 47384 this.animationNames = animationNames; 47385 await this.setupScene(); 47386 } 47387 async setupScene() { 47388 this.applyTransform(); 47389 this.updateBoundingBox(); 47390 await this.updateFraming(); 47391 this.updateShadow(); 47392 this.setShadowIntensity(this.shadowIntensity); 47393 this.setGroundedSkybox(); 47394 } 47395 reset() { 47396 this.url = null; 47397 this.renderCount = 0; 47398 this.queueRender(); 47399 if (this.shadow != null) { 47400 this.shadow.setIntensity(0); 47401 } 47402 this.bakedShadows.clear(); 47403 const { _model } = this; 47404 if (_model != null) { 47405 _model.removeFromParent(); 47406 this._model = null; 47407 } 47408 const gltf = this._currentGLTF; 47409 if (gltf != null) { 47410 gltf.dispose(); 47411 this._currentGLTF = null; 47412 } 47413 if (this.currentAnimationAction != null) { 47414 this.currentAnimationAction.stop(); 47415 this.currentAnimationAction = null; 47416 } 47417 this.mixer.stopAllAction(); 47418 this.mixer.uncacheRoot(this); 47419 } 47420 dispose() { 47421 this.reset(); 47422 if (this.shadow != null) { 47423 this.shadow.dispose(); 47424 this.shadow = null; 47425 } 47426 this.element[$currentGLTF] = null; 47427 this.element[$originalGltfJson] = null; 47428 this.element[$model] = null; 47429 } 47430 get currentGLTF() { 47431 return this._currentGLTF; 47432 } 47433 setSize(width, height) { 47434 if (this.width === width && this.height === height) { 47435 return; 47436 } 47437 this.width = Math.max(width, 1); 47438 this.height = Math.max(height, 1); 47439 this.annotationRenderer.setSize(width, height); 47440 this.aspect = this.width / this.height; 47441 if (this.externalRenderer != null) { 47442 const dpr = window.devicePixelRatio; 47443 this.externalRenderer.resize(width * dpr, height * dpr); 47444 } 47445 this.queueRender(); 47446 } 47447 markBakedShadow(mesh) { 47448 mesh.userData.noHit = true; 47449 this.bakedShadows.add(mesh); 47450 } 47451 unmarkBakedShadow(mesh) { 47452 mesh.userData.noHit = false; 47453 mesh.visible = true; 47454 this.bakedShadows.delete(mesh); 47455 this.boundingBox.expandByObject(mesh); 47456 } 47457 findBakedShadows(group) { 47458 const boundingBox = new Box3(); 47459 group.traverse((object)=>{ 47460 const mesh = object; 47461 if (!mesh.material) { 47462 return; 47463 } 47464 const material = mesh.material; 47465 if (!material.transparent) { 47466 return; 47467 } 47468 boundingBox.setFromObject(mesh); 47469 const size = boundingBox.getSize(vector3); 47470 const minDim = Math.min(size.x, size.y, size.z); 47471 const maxDim = Math.max(size.x, size.y, size.z); 47472 if (maxDim < MIN_SHADOW_RATIO * minDim) { 47473 return; 47474 } 47475 this.markBakedShadow(mesh); 47476 }); 47477 } 47478 checkBakedShadows() { 47479 const { min, max } = this.boundingBox; 47480 const shadowBox = new Box3(); 47481 this.boundingBox.getSize(this.size); 47482 for (const mesh of this.bakedShadows){ 47483 shadowBox.setFromObject(mesh); 47484 if (shadowBox.min.y < min.y + this.size.y / MIN_SHADOW_RATIO && shadowBox.min.x <= min.x && shadowBox.max.x >= max.x && shadowBox.min.z <= min.z && shadowBox.max.z >= max.z) { 47485 continue; 47486 } 47487 if (shadowBox.min.z < min.z + this.size.z / MIN_SHADOW_RATIO && shadowBox.min.x <= min.x && shadowBox.max.x >= max.x && shadowBox.min.y <= min.y && shadowBox.max.y >= max.y) { 47488 continue; 47489 } 47490 this.unmarkBakedShadow(mesh); 47491 } 47492 } 47493 applyTransform() { 47494 const { model } = this; 47495 if (model == null) { 47496 return; 47497 } 47498 const orientation = parseExpressions(this.element.orientation)[0].terms; 47499 const roll = normalizeUnit(orientation[0]).number; 47500 const pitch = normalizeUnit(orientation[1]).number; 47501 const yaw = normalizeUnit(orientation[2]).number; 47502 model.quaternion.setFromEuler(new Euler(pitch, yaw, roll, 'YXZ')); 47503 const scale = parseExpressions(this.element.scale)[0].terms; 47504 model.scale.set(scale[0].number, scale[1].number, scale[2].number); 47505 } 47506 updateBoundingBox() { 47507 const { model } = this; 47508 if (model == null) { 47509 return; 47510 } 47511 this.target.remove(model); 47512 this.findBakedShadows(model); 47513 const bound = (box, vertex)=>{ 47514 return box.expandByPoint(vertex); 47515 }; 47516 this.setBakedShadowVisibility(false); 47517 this.boundingBox = reduceVertices(model, bound, new Box3()); 47518 if (this.boundingBox.isEmpty()) { 47519 this.setBakedShadowVisibility(true);
47520 this.bakedShadows.forEach((mesh)=>this.unmarkBakedShadow(mesh)); 47521 this.boundingBox = reduceVertices(model, bound, new Box3()); 47522 } 47523 this.checkBakedShadows(); 47524 this.setBakedShadowVisibility(); 47525 this.boundingBox.getSize(this.size); 47526 this.target.add(model); 47527 } 47528 async updateFraming() { 47529 const { model } = this; 47530 if (model == null) { 47531 return; 47532 } 47533 this.target.remove(model); 47534 this.setBakedShadowVisibility(false); 47535 const { center } = this.boundingSphere; 47536 this.element.requestUpdate('cameraTarget'); 47537 await this.element.updateComplete; 47538 center.copy(this.getTarget()); 47539 const radiusSquared = (value, vertex)=>{ 47540 return Math.max(value, center.distanceToSquared(vertex)); 47541 }; 47542 this.boundingSphere.radius = Math.sqrt(reduceVertices(model, radiusSquared, 0)); 47543 const horizontalTanFov = (value, vertex)=>{ 47544 vertex.sub(center); 47545 const radiusXZ = Math.sqrt(vertex.x * vertex.x + vertex.z * vertex.z); 47546 return Math.max(value, radiusXZ / (this.idealCameraDistance() - Math.abs(vertex.y))); 47547 }; 47548 this.idealAspect = reduceVertices(model, horizontalTanFov, 0) / Math.tan(this.framedFoVDeg / 2 * Math.PI / 180); 47549 this.setBakedShadowVisibility(); 47550 this.target.add(model); 47551 } 47552 setBakedShadowVisibility(visible = this.shadowIntensity <= 0) { 47553 for (const shadow of this.bakedShadows){ 47554 shadow.visible = visible; 47555 } 47556 } 47557 idealCameraDistance() { 47558 const halfFovRad = this.framedFoVDeg / 2 * Math.PI / 180; 47559 return this.boundingSphere.radius / Math.sin(halfFovRad); 47560 } 47561 adjustedFoV(fovDeg) { 47562 const vertical = Math.tan(fovDeg / 2 * Math.PI / 180) * Math.max(1, this.idealAspect / this.aspect); 47563 return 2 * Math.atan(vertical) * 180 / Math.PI; 47564 } 47565 getNDC(clientX, clientY) { 47566 if (this.xrCamera != null) { 47567 ndc.set(clientX / window.screen.width, clientY / window.screen.height); 47568 } else { 47569 const rect = this.element.getBoundingClientRect(); 47570 ndc.set((clientX - rect.x) / this.width, (clientY - rect.y
47570) / this.height); 47571 } 47572 ndc.multiplyScalar(2).subScalar(1); 47573 ndc.y *= -1; 47574 return ndc; 47575 } 47576 getSize() { 47577 return { 47578 width: this.width, 47579 height: this.height 47580 }; 47581 } 47582 setEnvironmentAndSkybox(environment, skybox) { 47583 if (this.element[$renderer].arRenderer.presentedScene === this) { 47584 return; 47585 } 47586 this.environment = environment; 47587 this.setBackground(skybox); 47588 this.queueRender(); 47589 } 47590 setBackground(skybox) { 47591 this.groundedSkybox.map = skybox; 47592 if (this.groundedSkybox.isUsable()) { 47593 this.target.add(this.groundedSkybox); 47594 this.background = null; 47595 } else { 47596 this.target.remove(this.groundedSkybox); 47597 this.background = skybox; 47598 } 47599 } 47600 farRadius() { 47601 return this.boundingSphere.radius * (this.groundedSkybox.parent != null ? GROUNDED_SKYBOX_SIZE : 1); 47602 } 47603 setGroundedSkybox() { 47604 const heightNode = parseExpressions(this.element.skyboxHeight)[0].terms[0]; 47605 const height = normalizeUnit(heightNode).number; 47606 const radius = GROUNDED_SKYBOX_SIZE * this.boundingSphere.radius; 47607 this.groundedSkybox.updateGeometry(height, radius); 47608 this.groundedSkybox.position.y = height - (this.shadow ? 2 * this.shadow.gap() : 0); 47609 this.setBackground(this.groundedSkybox.map); 47610 } 47611 setTarget(modelX, modelY, modelZ) { 47612 this.goalTarget.set(-modelX, -modelY, -modelZ); 47613 } 47614 setTargetDamperDecayTime(decayMilliseconds) { 47615 this.targetDamperX.setDecayTime(decayMilliseconds); 47616 this.targetDamperY.setDecayTime(decayMilliseconds); 47617 this.targetDamperZ.setDecayTime(decayMilliseconds); 47618 } 47619 getTarget() { 47620 return this.goalTarget.clone().multiplyScalar(-1); 47621 } 47622 getDynamicTarget() { 47623 return this.target.position.clone().multiplyScalar(-1); 47624 } 47625 jumpToGoal() { 47626 this.updateTarget(SETTLING_TIME); 47627 } 47628 updateTarget(delta) { 47629 const goal = this.goalTarget; 47630 const target = this.target.position; 47631 if (!goal.equals(target)) { 47632 const normalization = this.boundingSphere.radius / 10; 47633 let { x, y, z } = target; 47634 x = this.targetDamperX.update(x, goal.x, delta, normalization); 47635 y = this.targetDamperY.update(y, goal.y, delta, normalization); 47636 z = this.targetDamperZ.update(z, goal.z, delta, normalization); 47637 this.groundedSkybox.position.x = -x; 47638 this.groundedSkybox.position.z = -z; 47639 this.target.position.set(x, y, z); 47640 this.target.updateMatrixWorld(); 47641 this.queueRender(); 47642 return true; 47643 } else { 47644 return false; 47645 } 47646 } 47647 pointTowards(worldX, worldZ) { 47648 const { x, z } = this.position; 47649 this.yaw = Math.atan2(worldX - x, worldZ - z); 47650 } 47651 get model() { 47652 return this._model; 47653 } 47654 set yaw(radiansY) { 47655 this.pivot.rotation.y = radiansY; 47656 this.groundedSkybox.rotation.y = -radiansY; 47657 this.queueRender(); 47658 } 47659 get yaw() { 47660 return this.pivot.rotation.y; 47661 } 47662 set animationTime(value) { 47663 this.mixer.setTime(value); 47664 this.queueShadowRender(); 47665 } 47666 get animationTime() { 47667 if (this.currentAnimationAction != null) { 47668 const loopCount = Math.max(this.currentAnimationAction._loopCount, 0); 47669 if (this.currentAnimationAction.loop === LoopPingPong && (loopCount & 1) === 1) { 47670 return this.duration - this.currentAnimationAction.time; 47671 } else { 47672 return this.currentAnimationAction.time; 47673 } 47674 } 47675 return 0; 47676 } 47677 set animationTimeScale(value) { 47678 this.mixer.timeScale = value; 47679 } 47680 get animationTimeScale() { 47681 return this.mixer.timeScale; 47682 } 47683 get duration() { 47684 if (this.currentAnimationAction != null && this.currentAnimationAction.getClip()) { 47685 return this.currentAnimationAction.getClip().duration; 47686 } 47687 return 0; 47688 } 47689 get hasActiveAnimation() { 47690 return this.currentAnimationAction != null; 47691 } 47692 playAnimation(name = null, crossfadeTime = 0, loopMode = LoopRepeat, repetitionCount = Infinity) { 47693 if (this._currentGLTF == null) { 47694 return; 47695 } 47696 const { animations } = this; 47697 if (animations == null || animations.length === 0) { 47698 return; 47699 } 47700 let animationClip = null; 47701 if (name != null) { 47702 animationClip = this.animationsByName.get(name); 47703 if (animationClip == null) { 47704 const parsedAnimationIndex = parseInt(name); 47705 if (!isNaN(parsedAnimationIndex) && parsedAnimationIndex >= 0 && parsedAnimationIndex < animations.length) { 47706 animationClip = animations[parsedAnimationIndex]; 47707 } 47708 } 47709 } 47710 if (animationClip == null) { 47711 animationClip = animations[0]; 47712 } 47713 try { 47714 const { currentAnimationAction: lastAnimationAction } = this; 47715 const action = this.mixer.clipAction(animationClip, this); 47716 if (action.timeScale != this.element.timeScale) { 47717 action.timeScale = this.element.timeScale; 47718 } 47719 this.currentAnimationAction = action; 47720 if (this.element.paused) { 47721 this.mixer.stopAllAction(); 47722 } else { 47723 action.paused = false;
47724 if (lastAnimationAction != null && action !== lastAnimationAction) { 47725 action.crossFadeFrom(lastAnimationAction, crossfadeTime, false); 47726 } else if (this.animationTimeScale > 0 && this.animationTime == this.duration) { 47727 this.animationTime = 0; 47728 } 47729 } 47730 action.setLoop(loopMode, repetitionCount); 47731 action.enabled = true; 47732 action.clampWhenFinished = true; 47733 action.play(); 47734 } catch (error) { 47735 console.error(error); 47736 } 47737 } 47738 appendAnimation(name = '', loopMode = LoopRepeat, repetitionCount = Infinity, weight = 1, timeScale = 1, fade = false, warp = false, relativeWarp = true, time = null, needsToStop = false) { 47739 if (this._currentGLTF == null || name === this.element.animationName) { 47740 return; 47741 } 47742 const { animations } = this; 47743 if (animations == null || animations.length === 0) { 47744 return; 47745 } 47746 let animationClip = null; 47747 const defaultFade = 1.25; 47748 if (name) { 47749 animationClip = this.animationsByName.get(name); 47750 } 47751 if (animationClip == null) { 47752 return; 47753 } 47754 if (typeof repetitionCount === 'string') { 47755 if (!isNaN(repetitionCount)) { 47756 repetitionCount = Math.max(parseInt(repetitionCount), 1); 47757 } else { 47758 repetitionCount = Infinity; 47759 console.warn('Invalid repetitionCount value, repetitionCount is set to Infinity'); 47760 } 47761 } else if (typeof repetitionCount === 'number' && repetitionCount < 1) { 47762 repetitionCount = 1; 47763 } 47764 if (repetitionCount === 1 && loopMode !== LoopOnce) { 47765 loopMode = LoopOnce; 47766 } 47767 if (typeof weight === 'string') { 47768 if (!isNaN(weight)) { 47769 weight = parseFloat(weight); 47770 } else { 47771 weight = 1; 47772 console.warn('Invalid weight value, weight is set to 1'); 47773 } 47774 } 47775 if (typeof timeScale === 'string') { 47776 if (!isNaN(timeScale)) { 47777 timeScale = parseFloat(timeScale); 47778 } else { 47779 timeScale = 1; 47780 console.warn('Invalid timeScale value, timeScale is set to 1'); 47781 } 47782 } 47783 if (typeof fade === 'string') { 47784 if (fade.toLowerCase().trim() === 'true') { 47785 fade = true; 47786 } else if (fade.toLowerCase().trim() === 'false') { 47787 fade = false;
47788 } else if (!isNaN(fade)) { 47789 fade = parseFloat(fade); 47790 } else { 47791 fade = false; 47792 console.warn('Invalid fade value, fade is set to false'); 47793 } 47794 } 47795 if (typeof warp === 'string') { 47796 if (warp.toLowerCase().trim() === 'true') { 47797 warp = true; 47798 } else if (warp.toLowerCase().trim() === 'false') { 47799 warp = false; 47800 } else if (!isNaN(warp)) { 47801 warp = parseFloat(warp); 47802 } else { 47803 warp = false; 47804 console.warn('Invalid warp value, warp is set to false'); 47805 } 47806 } 47807 if (typeof time === 'string') { 47808 if (!isNaN(time)) { 47809 time = parseFloat(time); 47810 } 47811 } 47812 try { 47813 const action = this.mixer.existingAction(animationClip) || this.mixer.clipAction(animationClip, this); 47814 const currentTimeScale = action.timeScale; 47815 if (needsToStop && this.appendedAnimations.includes(name)) { 47816 if (!this.markedAnimations.map((e)=>e.name).includes(name)) { 47817 this.markedAnimations.push({ 47818 name, 47819 loopMode, 47820 repetitionCount 47821 }); 47822 } 47823 } 47824 if (typeof time === 'number') { 47825 action.time = Math.min(Math.max(time, 0), animationClip.duration); 47826 } 47827 if (typeof fade === 'boolean' && fade) { 47828 action.fadeIn(defaultFade); 47829 } else if (typeof fade === 'number') { 47830 action.fadeIn(Math.max(fade, 0)); 47831 } else { 47832 if (weight >= 0) { 47833 action.weight = Math.min(Math.max(weight, 0), 1); 47834 } 47835 } 47836 if (typeof warp === 'boolean' && warp) { 47837 action.warp(relativeWarp ? currentTimeScale : 0, timeScale, defaultFade); 47838 } else if (typeof warp === 'number') { 47839 action.warp(relativeWarp ? currentTimeScale : 0, timeScale, Math.max(warp, 0)); 47840 } else { 47841 action.timeScale = timeScale; 47842 } 47843 if (!action.isRunning()) { 47844 if (action.time == animationClip.duration) { 47845 action.stop(); 47846 } 47847 action.setLoop(loopMode, repetitionCount); 47848 action.paused = false; 47849 action.enabled = true; 47850 action.clampWhenFinished = true; 47851 action.play(); 47852 } 47853 if (!this.appendedAnimations.includes(name)) { 47854 this.element[$scene].appendedAnimations.push(name); 47855 } 47856 } catch (error) { 47857 console.error(error); 47858 } 47859 } 47860 detachAnimation(name = '', fade = true) { 47861 if (this._currentGLTF == null || name === this.element.animationName) { 47862 return; 47863 } 47864 const { animations } = this; 47865 if (animations == null || animations.length === 0) { 47866 return; 47867 } 47868 let animationClip = null; 47869 const defaultFade = 1.5; 47870 if (name) { 47871 animationClip = this.animationsByName.get(name); 47872 } 47873 if (animationClip == null) { 47874 return; 47875 } 47876 if (typeof fade === 'string') { 47877 if (fade.toLowerCase().trim() === 'true') { 47878 fade = true; 47879 } else if (fade.toLowerCase().trim() === 'false') { 47880 fade = false;
47881 } else if (!isNaN(fade)) { 47882 fade = parseFloat(fade); 47883 } else { 47884 fade = true; 47885 console.warn('Invalid fade value, fade is set to true'); 47886 } 47887 } 47888 try { 47889 const action = this.mixer.existingAction(animationClip) || this.mixer.clipAction(animationClip, this); 47890 if (typeof fade === 'boolean' && fade) { 47891 action.fadeOut(defaultFade); 47892 } else if (typeof fade === 'number') { 47893 action.fadeOut(Math.max(fade, 0)); 47894 } else { 47895 action.stop(); 47896 } 47897 const result = this.element[$scene].appendedAnimations.filter((i)=>i !== name); 47898 this.element[$scene].appendedAnimations = result; 47899 } catch (error) { 47900 console.error(error); 47901 } 47902 } 47903 updateAnimationLoop(name = '', loopMode = LoopRepeat, repetitionCount = Infinity) { 47904 if (this._currentGLTF == null || name === this.element.animationName) { 47905 return; 47906 } 47907 const { animations } = this; 47908 if (animations == null || animations.length === 0) { 47909 return; 47910 } 47911 let animationClip = null; 47912 if (name) { 47913 animationClip = this.animationsByName.get(name); 47914 } 47915 if (animationClip == null) { 47916 return; 47917 } 47918 try { 47919 const action = this.mixer.existingAction(animationClip) || this.mixer.clipAction(animationClip, this); 47920 action.stop(); 47921 action.setLoop(loopMode, repetitionCount); 47922 action.play(); 47923 } catch (error) { 47924 console.error(error); 47925 } 47926 } 47927 stopAnimation() { 47928 this.currentAnimationAction = null; 47929 this.mixer.stopAllAction(); 47930 } 47931 updateAnimation(step) { 47932 this.mixer.update(step); 47933 this.queueShadowRender(); 47934 } 47935 subscribeMixerEvent(event, callback) { 47936 this.mixer.addEventListener(event, callback); 47937 } 47938 updateShadow() { 47939 const shadow = this.shadow; 47940 if (shadow != null) { 47941 const side = this.element.arPlacement === 'wall' ? 'back' : 'bottom'; 47942 shadow.setScene(this, this.shadowSoftness, side); 47943 shadow.needsUpdate = true; 47944 } 47945 } 47946 renderShadow(renderer) { 47947 const shadow = this.shadow; 47948 if (shadow != null && shadow.needsUpdate == true) { 47949 shadow.render(renderer, this); 47950 shadow.needsUpdate = false; 47951 } 47952 } 47953 queueShadowRender() { 47954 if (this.shadow != null) { 47955 this.shadow.needsUpdate = true; 47956 } 47957 } 47958 setShadowIntensity(shadowIntensity) { 47959 this.shadowIntensity = shadowIntensity; 47960 if (this._currentGLTF == null) { 47961 return; 47962 } 47963 this.setBakedShadowVisibility(); 47964 if (shadowIntensity <= 0 && this.shadow == null) { 47965 return; 47966 } 47967 if (this.shadow == null) { 47968 const side = this.element.arPlacement === 'wall' ? 'back' : 'bottom'; 47969 this.shadow = new Shadow(this, this.shadowSoftness, side); 47970 } 47971 this.shadow.setIntensity(shadowIntensity); 47972 } 47973 setShadowSoftness(softness) { 47974 this.shadowSoftness = softness; 47975 const shadow = this.shadow; 47976 if (shadow != null) { 47977 shadow.setSoftness(softness); 47978 } 47979 } 47980 setShadowOffset(offset) { 47981 const shadow = this.shadow; 47982 if (shadow != null) { 47983 shadow.setOffset(offset); 47984 } 47985 } 47986 getHit(object = this) { 47987 const hits = raycaster.intersectObject(object, true); 47988 return hits.find((hit)=>hit.object.visible && !hit.object.userData.noHit); 47989 } 47990 hitFromController(controller, object = this) { 47991 raycaster.setFromXRController(controller); 47992 return this.getHit(object); 47993 } 47994 hitFromPoint(ndcPosition, object = this) { 47995 raycaster.setFromCamera(ndcPosition, this.getCamera()); 47996 return this.getHit(object); 47997 } 47998 positionAndNormalFromPoint(ndcPosition, object = this) { 47999 var _a; 48000 const hit = this.hitFromPoint(ndcPosition, object); 48001 if (hit == null) { 48002 return null; 48003 } 48004 const position = hit.point; 48005 const normal = hit.face != null ? hit.face.normal.clone().applyNormalMatrix(new Matrix3().getNormalMatrix(hit.object.matrixWorld)) : raycaster.ray.direction.clone().multiplyScalar(-1); 48006 const uv = (_a = hit.uv) !== null && _a !== void 0 ? _a : null; 48007 return { 48008 position, 48009 normal, 48010 uv 48011 }; 48012 } 48013 surfaceFromPoint(ndcPosition, object = this) { 48014 const model = this.element.model; 48015 if (model == null) { 48016 return null; 48017 } 48018 const hit = this.hitFromPoint(ndcPosition, object); 48019 if (hit == null || hit.face == null) { 48020 return null; 48021 }
vendor: 9,449 bytes, lines 48022-48263
48022 const node = model[$nodeFromPoint](hit); 48023 const { meshes, primitives } = node.mesh.userData.associations; 48024 const va = new Vector3(); 48025 const vb = new Vector3(); 48026 const vc = new Vector3(); 48027 const { a, b, c } = hit.face; 48028 const mesh = hit.object; 48029 mesh.getVertexPosition(a, va); 48030 mesh.getVertexPosition(b, vb); 48031 mesh.getVertexPosition(c, vc); 48032 const tri = new Triangle(va, vb, vc); 48033 const uvw = new Vector3(); 48034 tri.getBarycoord(mesh.worldToLocal(hit.point), uvw); 48035 return `${meshes} ${primitives} ${a} ${b} ${c} ${uvw.x.toFixed(3)} ${uvw.y.toFixed(3)} ${uvw.z.toFixed(3)}`; 48036 } 48037 addHotspot(hotspot) { 48038 this.target.add(hotspot); 48039 this.annotationRenderer.domElement.appendChild(hotspot.element); 48040 this.updateSurfaceHotspot(hotspot); 48041 } 48042 removeHotspot(hotspot) { 48043 this.target.remove(hotspot); 48044 } 48045 forHotspots(func) { 48046 const { children } = this.target; 48047 for(let i = 0, l = children.length; i < l; i++){ 48048 const hotspot = children[i]; 48049 if (hotspot instanceof Hotspot) { 48050 func(hotspot); 48051 } 48052 } 48053 } 48054 updateSurfaceHotspot(hotspot) { 48055 if (hotspot.surface == null || this.element.model == null) { 48056 return; 48057 } 48058 const nodes = parseExpressions(hotspot.surface)[0].terms; 48059 if (nodes.length != 8) { 48060 console.warn(hotspot.surface + ' does not have exactly 8 numbers.'); 48061 return; 48062 } 48063 const primitiveNode = this.element.model[$nodeFromIndex](nodes[0].number, nodes[1].number); 48064 if (primitiveNode == null) { 48065 console.warn(hotspot.surface + ' does not match a node/primitive in this glTF! Skipping this hotspot.'); 48066 return; 48067 } 48068 const numVert = primitiveNode.mesh.geometry.attributes.position.count; 48069 const tri = new Vector3(nodes[2].number, nodes[3].number, nodes[4].number); 48070 if (tri.x >= numVert || tri.y >= numVert || tri.z >= numVert) { 48071 console.warn(hotspot.surface + ' vertex indices out of range in this glTF! Skipping this hotspot.'); 48072 return; 48073 } 48074 const bary = new Vector3(nodes[5].number, nodes[6].number, nodes[7].number); 48075 hotspot.mesh = primitiveNode.mesh; 48076 hotspot.tri = tri; 48077 hotspot.bary = bary; 48078 hotspot.updateSurface(); 48079 } 48080 animateSurfaceHotspots() { 48081 if (this.element.paused) { 48082 return; 48083 } 48084 this.forHotspots((hotspot)=>{ 48085 hotspot.updateSurface(); 48086 }); 48087 } 48088 updateHotspotsVisibility(viewerPosition) { 48089 this.forHotspots((hotspot)=>{ 48090 view.copy(viewerPosition); 48091 target.setFromMatrixPosition(hotspot.matrixWorld); 48092 view.sub(target); 48093 normalWorld.copy(hotspot.normal).transformDirection(this.target.matrixWorld); 48094 if (view.dot(normalWorld) < 0) { 48095 hotspot.hide(); 48096 } else { 48097 hotspot.show(); 48098 } 48099 }); 48100 } 48101 orientHotspots(radians) { 48102 this.forHotspots((hotspot)=>{ 48103 hotspot.orient(radians); 48104 }); 48105 } 48106 setHotspotsVisibility(visible) { 48107 this.forHotspots((hotspot)=>{ 48108 hotspot.visible = visible; 48109 }); 48110 } 48111 updateSchema(src) { 48112 var _a; 48113 const { schemaElement, element } = this; 48114 const { alt, poster, iosSrc } = element; 48115 if (src != null) { 48116 const encoding = [ 48117 { 48118 '@type': 'MediaObject', 48119 contentUrl: src, 48120 encodingFormat: ((_a = src.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'gltf' ? 'model/gltf+json' : 'model/gltf-binary' 48121 } 48122 ]; 48123 if (iosSrc) { 48124 encoding.push({ 48125 '@type': 'MediaObject', 48126 contentUrl: iosSrc, 48127 encodingFormat: 'model/vnd.usdz+zip' 48128 }); 48129 } 48130 const structuredData = { 48131 '@context': 'http://schema.org/', 48132 '@type': '3DModel', 48133 image: poster !== null && poster !== void 0 ? poster : undefined, 48134 name: alt !== null && alt !== void 0 ? alt : undefined, 48135 encoding 48136 }; 48137 schemaElement.textContent = JSON.stringify(structuredData); 48138 document.head.appendChild(schemaElement); 48139 } else if (schemaElement.parentElement != null) { 48140 schemaElement.parentElement.removeChild(schemaElement); 48141 } 48142 } 48143 constructor({ canvas, element, width, height }){ 48144 super(); 48145 this.annotationRenderer = new CSS2DRenderer(); 48146 this.effectRenderer = null; 48147 this.schemaElement = document.createElement('script'); 48148 this.width = 1; 48149 this.height = 1; 48150 this.aspect = 1; 48151 this.scaleStep = 0; 48152 this.renderCount = 0; 48153 this.externalRenderer = null; 48154 this.appendedAnimations = []; 48155 this.markedAnimations = []; 48156 this.camera = new PerspectiveCamera(45, 1, 0.1, 100); 48157 this.xrCamera = null; 48158 this.url = null; 48159 this.pivot = new Object3D(); 48160 this.target = new Object3D(); 48161 this.animationNames = []; 48162 this.boundingBox = new Box3(); 48163 this.boundingSphere = new Sphere(); 48164 this.size = new Vector3(); 48165 this.idealAspect = 0; 48166 this.framedFoVDeg = 0; 48167 this.shadow = null; 48168 this.shadowIntensity = 0; 48169 this.shadowSoftness = 1; 48170 this.bakedShadows = new Set(); 48171 this.exposure = 1; 48172 this.toneMapping = NeutralToneMapping; 48173 this.canScale = true; 48174 this.isDirty = false; 48175 this.goalTarget = new Vector3(); 48176 this.targetDamperX = new Damper(); 48177 this.targetDamperY = new Damper(); 48178 this.targetDamperZ = new Damper(); 48179 this._currentGLTF = null; 48180 this._model = null; 48181 this.cancelPendingSourceChange = null; 48182 this.animationsByName = new Map(); 48183 this.currentAnimationAction = null; 48184 this.groundedSkybox = new GroundedSkybox(); 48185 this.name = 'ModelScene'; 48186 this.element = element; 48187 this.canvas = canvas; 48188 this.camera = new PerspectiveCamera(45, 1, 0.1, 100); 48189 this.camera.name = 'MainCamera'; 48190 this.add(this.pivot); 48191 this.pivot.name = 'Pivot'; 48192 this.pivot.add(this.target); 48193 this.setSize(width, height); 48194 this.target.name = 'Target'; 48195 this.mixer = new AnimationMixer(this.target); 48196 const { domElement } = this.annotationRenderer; 48197 const { style } = domElement; 48198 style.display = 'none'; 48199 style.pointerEvents = 'none'; 48200 style.position = 'absolute'; 48201 style.top = '0'; 48202 this.element.shadowRoot.querySelector('.default').appendChild(domElement); 48203 this.schemaElement.setAttribute('type', 'application/ld+json'); 48204 } 48205 } 48206 48207 class ProgressTracker extends EventTarget { 48208 get ongoingActivityCount() { 48209 return this.ongoingActivities.size; 48210 } 48211 beginActivity(reason) { 48212 const activity = { 48213 progress: 0, 48214 completed: false 48215 }; 48216 this.ongoingActivities.add(activity); 48217 if (this.ongoingActivityCount === 1) { 48218 this.announceTotalProgress(activity, 0, reason); 48219 } 48220 return (progress)=>{ 48221 let nextProgress; 48222 nextProgress = Math.max(clamp(progress, 0, 1), activity.progress); 48223 if (nextProgress !== activity.progress) { 48224 this.announceTotalProgress(activity, nextProgress, reason); 48225 } 48226 return activity.progress; 48227 }; 48228 } 48229 announceTotalProgress(updatedActivity, nextProgress, reason) { 48230 let progressLeft = 0; 48231 let completedActivities = 0; 48232 if (nextProgress == 1.0) updatedActivity.completed = true; 48233 for (const activity of this.ongoingActivities){ 48234 const { progress } = activity; 48235 progressLeft += 1.0 - progress; 48236 if (activity.completed) { 48237 completedActivities++; 48238 } 48239 } 48240 const lastProgress = updatedActivity.progress; 48241 updatedActivity.progress = nextProgress; 48242 this.totalProgress += (nextProgress - lastProgress) * (1.0 - this.totalProgress) / progressLeft; 48243 const totalProgress = completedActivities === this.ongoingActivityCount ? 1.0 : this.totalProgress; 48244 this.dispatchEvent(new CustomEvent('progress', { 48245 detail: { 48246 totalProgress, 48247 reason 48248 } 48249 })); 48250 if (completedActivities === this.ongoingActivityCount) { 48251 this.totalProgress = 0.0; 48252 this.ongoingActivities.clear(); 48253 } 48254 } 48255 constructor(){ 48256 super(...arguments); 48257 this.ongoingActivities = new Set(); 48258 this.totalProgress = 0; 48259 } 48260 } 48261 48262 var __decorate$4 = undefined && undefined.__decorate || function(decorators, target, key, desc) { 48263 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
vendor: 10,572 bytes, lines 48264-48533
48264 for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 48265 return c > 3 && r && Object.defineProperty(target, key, r), r; 48266 }; 48267 var _a$1, _b$1, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o; 48268 const CLEAR_MODEL_TIMEOUT_MS = 10; 48269 const FALLBACK_SIZE_UPDATE_THRESHOLD_MS = 50; 48270 const ANNOUNCE_MODEL_VISIBILITY_DEBOUNCE_THRESHOLD = 0; 48271 const UNSIZED_MEDIA_WIDTH = 300; 48272 const UNSIZED_MEDIA_HEIGHT = 150; 48273 const blobCanvas = document.createElement('canvas'); 48274 const $fallbackResizeHandler = Symbol('fallbackResizeHandler'); 48275 const $defaultAriaLabel = Symbol('defaultAriaLabel'); 48276 const $resizeObserver = Symbol('resizeObserver'); 48277 const $clearModelTimeout = Symbol('clearModelTimeout'); 48278 const $onContextLost = Symbol('onContextLost'); 48279 const $loaded = Symbol('loaded'); 48280 const $status = Symbol('status'); 48281 const $onFocus = Symbol('onFocus'); 48282 const $onBlur = Symbol('onBlur'); 48283 const $updateSize = Symbol('updateSize'); 48284 const $intersectionObserver = Symbol('intersectionObserver'); 48285 const $isElementInViewport = Symbol('isElementInViewport'); 48286 const $announceModelVisibility = Symbol('announceModelVisibility'); 48287 const $ariaLabel = Symbol('ariaLabel'); 48288 const $altDefaulted = Symbol('altDefaulted'); 48289 const $statusElement = Symbol('statusElement'); 48290 const $updateStatus = Symbol('updateStatus'); 48291 const $loadedTime = Symbol('loadedTime'); 48292 const $updateSource = Symbol('updateSource'); 48293 const $markLoaded = Symbol('markLoaded'); 48294 const $container = Symbol('container'); 48295 const $userInputElement = Symbol('input'); 48296 const $canvas = Symbol('canvas'); 48297 const $scene = Symbol('scene'); 48298 const $needsRender = Symbol('needsRender'); 48299 const $tick = Symbol('tick'); 48300 const $onModelLoad = Symbol('onModelLoad'); 48301 const $onResize = Symbol('onResize'); 48302 const $renderer = Symbol('renderer'); 48303 const $progressTracker = Symbol('progressTracker'); 48304 const $getLoaded = Symbol('getLoaded'); 48305 const $getModelIsVisible = Symbol('getModelIsVisible'); 48306 const $shouldAttemptPreload = Symbol('shouldAttemptPreload'); 48307 const toVector3D = (v)=>{ 48308 return { 48309 x: v.x, 48310 y: v.y, 48311 z: v.z, 48312 toString () { 48313 return `${this.x}m ${this.y}m ${this.z}m`; 48314 } 48315 }; 48316 }; 48317 const toVector2D = (v)=>{ 48318 return { 48319 u: v.x, 48320 v: v.y, 48321 toString () { 48322 return `${this.u} ${this.v}`; 48323 } 48324 }; 48325 }; 48326 class ModelViewerElementBase extends b$1 { 48327 static get is() { 48328 return 'model-viewer'; 48329 } 48330 static set modelCacheSize(value) { 48331 CachingGLTFLoader[$evictionPolicy].evictionThreshold = value; 48332 } 48333 static get modelCacheSize() { 48334 return CachingGLTFLoader[$evictionPolicy].evictionThreshold; 48335 } 48336 static set minimumRenderScale(value) { 48337 if (value > 1) { 48338 console.warn('<model-viewer> minimumRenderScale has been clamped to a maximum value of 1.'); 48339 } 48340 if (value <= 0) { 48341 console.warn('<model-viewer> minimumRenderScale has been clamped to a minimum value of 0.25.'); 48342 } 48343 Renderer.singleton.minScale = value; 48344 } 48345 static get minimumRenderScale() { 48346 return Renderer.singleton.minScale; 48347 } 48348 get loaded() { 48349 return this[$getLoaded](); 48350 } 48351 get [(_a$1 = $isElementInViewport, _b$1 = $loaded, _c = $loadedTime, _d = $status, _e = $clearModelTimeout, _f = $fallbackResizeHandler, _g = $announceModelVisibility, _h = $resizeObserver, _j = $intersectionObserver, _k = $progressTracker, $renderer)]() { 48352 return Renderer.singleton; 48353 } 48354 get modelIsVisible() { 48355 return this[$getModelIsVisible](); 48356 } 48357 connectedCallback() { 48358 super.connectedCallback && super.connectedCallback(); 48359 if (HAS_RESIZE_OBSERVER) { 48360 this[$resizeObserver].observe(this); 48361 } else { 48362 self.addEventListener('resize', this[$fallbackResizeHandler]); 48363 } 48364 if (HAS_INTERSECTION_OBSERVER) { 48365 this[$intersectionObserver].observe(this); 48366 } 48367 this.addEventListener('focus', this[$onFocus]); 48368 this.addEventListener('blur', this[$onBlur]); 48369 const renderer = this[$renderer]; 48370 renderer.addEventListener('contextlost', this[$onContextLost]); 48371 renderer.registerScene(this[$scene]); 48372 if (this[$clearModelTimeout] != null) { 48373 self.clearTimeout(this[$clearModelTimeout]); 48374 this[$clearModelTimeout] = null; 48375 this.requestUpdate('src', null); 48376 } 48377 } 48378 disconnectedCallback() { 48379 super.disconnectedCallback && super.disconnectedCallback(); 48380 if (HAS_RESIZE_OBSERVER) { 48381 this[$resizeObserver].unobserve(this); 48382 } else { 48383 self.removeEventListener('resize', this[$fallbackResizeHandler]); 48384 } 48385 if (HAS_INTERSECTION_OBSERVER) { 48386 this[$intersectionObserver].unobserve(this); 48387 } 48388 this.removeEventListener('focus', this[$onFocus]); 48389 this.removeEventListener('blur', this[$onBlur]); 48390 const renderer = this[$renderer]; 48391 renderer.removeEventListener('contextlost', this[$onContextLost]); 48392 renderer.unregisterScene(this[$scene]); 48393 this[$clearModelTimeout] = self.setTimeout(()=>{ 48394 this[$scene].dispose(); 48395 this[$clearModelTimeout] = null; 48396 }, CLEAR_MODEL_TIMEOUT_MS); 48397 } 48398 updated(changedProperties) { 48399 super.updated(changedProperties); 48400 if (changedProperties.has('src')) { 48401 if (this.src == null) { 48402 this[$loaded] = false; 48403 this[$loadedTime] = 0; 48404 this[$scene].reset(); 48405 } else if (this.src !== this[$scene].url) { 48406 this[$loaded] = false; 48407 this[$loadedTime] = 0; 48408 this[$updateSource](); 48409 } 48410 } 48411 if (changedProperties.has('alt')) { 48412 this[$userInputElement].setAttribute('aria-label', this[$ariaLabel]); 48413 } 48414 if (changedProperties.has('generateSchema')) { 48415 if (this.generateSchema) { 48416 this[$scene].updateSchema(this.src); 48417 } else { 48418 this[$scene].updateSchema(null); 48419 } 48420 } 48421 } 48422 toDataURL(type, encoderOptions) { 48423 return this[$renderer].displayCanvas(this[$scene]).toDataURL(type, encoderOptions); 48424 } 48425 async toBlob(options) { 48426 const mimeType = options ? options.mimeType : undefined; 48427 const qualityArgument = options ? options.qualityArgument : undefined; 48428 const useIdealAspect = options ? options.idealAspect : undefined; 48429 const { width, height, idealAspect, aspect } = this[$scene]; 48430 const { dpr, scaleFactor } = this[$renderer]; 48431 let outputWidth = width * scaleFactor * dpr; 48432 let outputHeight = height * scaleFactor * dpr; 48433 let offsetX = 0; 48434 let offsetY = 0; 48435 if (useIdealAspect === true) { 48436 if (idealAspect > aspect) { 48437 const oldHeight = outputHeight; 48438 outputHeight = Math.round(outputWidth / idealAspect); 48439 offsetY = (oldHeight - outputHeight) / 2; 48440 } else { 48441 const oldWidth = outputWidth; 48442 outputWidth = Math.round(outputHeight * idealAspect); 48443 offsetX = (oldWidth - outputWidth) / 2; 48444 } 48445 } 48446 blobCanvas.width = outputWidth; 48447 blobCanvas.height = outputHeight; 48448 try { 48449 return new Promise(async (resolve, reject)=>{ 48450 blobCanvas.getContext('2d').drawImage(this[$renderer].displayCanvas(this[$scene]), offsetX, offsetY, outputWidth, outputHeight, 0, 0, outputWidth, outputHeight); 48451 blobCanvas.toBlob((blob)=>{ 48452 if (!blob) { 48453 return reject(new Error('Unable to retrieve canvas blob')); 48454 } 48455 resolve(blob); 48456 }, mimeType, qualityArgument); 48457 }); 48458 } finally{ 48459 this[$updateSize]({ 48460 width, 48461 height 48462 }); 48463 } 48464 } 48465 registerEffectComposer(effectComposer) { 48466 effectComposer.setRenderer(this[$renderer].threeRenderer); 48467 effectComposer.setMainCamera(this[$scene].getCamera()); 48468 effectComposer.setMainScene(this[$scene]); 48469 this[$scene].effectRenderer = effectComposer; 48470 } 48471 unregisterEffectComposer() { 48472 this[$scene].effectRenderer = null; 48473 } 48474 registerRenderer(renderer) { 48475 this[$scene].externalRenderer = renderer; 48476 } 48477 unregisterRenderer() { 48478 this[$scene].externalRenderer = null; 48479 } 48480 get [$ariaLabel]() { 48481 return this[$altDefaulted]; 48482 } 48483 get [$altDefaulted]() { 48484 return this.alt == null || this.alt === 'null' ? this[$defaultAriaLabel] : this.alt; 48485 } 48486 [$getLoaded]() { 48487 return this[$loaded]; 48488 } 48489 [$getModelIsVisible]() { 48490 return this.loaded && this[$isElementInViewport]; 48491 } 48492 [$shouldAttemptPreload]() { 48493 return !!this.src && this[$isElementInViewport]; 48494 } 48495 [$updateSize]({ width, height }) { 48496 if (width === 0 || height === 0) { 48497 return; 48498 } 48499 this[$container].style.width = `${width}px`; 48500 this[$container].style.height = `${height}px`; 48501 this[$onResize]({ 48502 width, 48503 height 48504 }); 48505 } 48506 [$tick](time, delta) { 48507 var _p; 48508 (_p = this[$scene].effectRenderer) === null || _p === void 0 ? void 0 : _p.beforeRender(time, delta); 48509 } 48510 [$markLoaded]() { 48511 if (this[$loaded]) { 48512 return; 48513 } 48514 this[$loaded] = true; 48515 this[$loadedTime] = performance.now(); 48516 } 48517 [$needsRender]() { 48518 this[$scene].queueRender(); 48519 } 48520 [$onModelLoad]() {} 48521 [$updateStatus](status) { 48522 this[$status] = status; 48523 const rootNode = this.getRootNode(); 48524 if (rootNode != null && rootNode.activeElement === this && this[$statusElement].textContent != status) { 48525 this[$statusElement].textContent = status; 48526 } 48527 } 48528 [(_l = $onFocus, _m = $onBlur, $onResize)](e) { 48529 this[$scene].setSize(e.width, e.height); 48530 } 48531 async [(_o = $onContextLost, $updateSource)]() { 48532 const scene = this[$scene]; 48533 if (this.loaded || !this[$shouldAttemptPreload]() || this.src === sce
48533ne.url) { 48534 return; 48535 } 48536 if (this.generateSchema) { 48537 scene.updateSchema(this.src); 48538 } 48539 this[$updateStatus]('Loading'); 48540 scene.stopAnimation(); 48541 const updateSourceProgress = this[$progressTracker].beginActivity('model-load'); 48542 const source = this.src; 48543 try { 48544 const srcUpdated = scene.setSource(source, (progress)=>updateSourceProgress(clamp(progress, 0, 1) * 0.95)); 48545 const envUpdated = this[$updateEnvironment](); 48546 await Promise.all([ 48547 srcUpdated, 48548 envUpdated 48549 ]); 48550 this[$markLoaded](); 48551 this[$onModelLoad](); 48552 this.updateComplete.then(()=>{ 48553 this.dispatchEvent(new CustomEvent('before-render')); 48554 }); 48555 await new Promise((resolve)=>{ 48556 requestAnimationFrame(()=>{ 48557 requestAnimationFrame(()=>{ 48558 this.dispatchEvent(new CustomEvent('load', { 48559 detail: { 48560 url: source 48561 } 48562 })); 48563 resolve(); 48564 }); 48565 }); 48566 }); 48567 } catch (error) { 48568 this.dispatchEvent(new CustomEvent('error', { 48569 detail: { 48570 type: 'loadfailure', 48571 sourceError: error 48572 } 48573 })); 48574 } finally{ 48575 updateSourceProgress(1.0); 48576 } 48577 } 48578 constructor(){ 48579 super(); 48580 this.alt = null; 48581 this.src = null; 48582 this.withCredentials = false; 48583 this.generateSchema = false; 48584 this[_a$1] = false; 48585 this[_b$1] = false; 48586 this[_c] = 0; 48587 this[_d] = ''; 48588 this[_e] = null; 48589 this[_f] = debounce(()=>{ 48590 const boundingRect = this.getBoundingClientRect(); 48591 this[$updateSize](boundingRect); 48592 }, FALLBACK_SIZE_UPDATE_THRESHOLD_MS); 48593 this[_g] = debounce((oldVisibility)=>{ 48594 const newVisibility = this.modelIsVisible; 48595 if (newVisibility !== oldVisibility) { 48596 this.dispatchEvent(new CustomEvent('model-visibility', { 48597 detail: { 48598 visible: newVisibility 48599 } 48600 })); 48601 } 48602 }, ANNOUNCE_MODEL_VISIBILITY_DEBOUNCE_THRESHOLD); 48603 this[_h] = null; 48604 this[_j] = null; 48605 this[_k] = new ProgressTracker(); 48606 this[_l] = ()=>{ 48607 this[$statusElement].textContent = this[$status]; 48608 }; 48609 this[_m] = ()=>{ 48610 this[$statusElement].textContent = ''; 48611 }; 48612 this[_o] = (event)=>{ 48613 this.dispatchEvent(new CustomEvent('error', { 48614 detail: { 48615 type: 'webglcontextlost', 48616 sourceError: event.sourceEvent 48617 } 48618 })); 48619 }; 48620 this.attachShadow({ 48621 mode: 'open' 48622 }); 48623 const shadowRoot = this.shadowRoot; 48624 makeTemplate(shadowRoot); 48625 this[$container] = shadowRoot.querySelector('.container'); 48626 this[$userInputElement] = shadowRoot.querySelector('.userInput'); 48627 this[$canvas] = shadowRoot.querySelector('canvas'); 48628 this[$statusElement] = shadowRoot.querySelector('#status');
vendor: 4,779 bytes, lines 48629-48772
48629 this[$defaultAriaLabel] = this[$userInputElement].getAttribute('aria-label'); 48630 let width, height; 48631 if (this.isConnected) { 48632 const rect = this.getBoundingClientRect(); 48633 width = rect.width; 48634 height = rect.height; 48635 } else { 48636 width = UNSIZED_MEDIA_WIDTH; 48637 height = UNSIZED_MEDIA_HEIGHT; 48638 } 48639 this[$scene] = new ModelScene({ 48640 canvas: this[$canvas], 48641 element: this, 48642 width, 48643 height 48644 }); 48645 Promise.resolve().then(()=>{ 48646 this[$updateSize](this.getBoundingClientRect()); 48647 }); 48648 if (HAS_RESIZE_OBSERVER) { 48649 this[$resizeObserver] = new ResizeObserver((entries)=>{ 48650 if (this[$renderer].isPresenting) { 48651 return; 48652 } 48653 for (let entry of entries){ 48654 if (entry.target === this) { 48655 this[$updateSize](entry.contentRect); 48656 } 48657 } 48658 }); 48659 } 48660 if (HAS_INTERSECTION_OBSERVER) { 48661 this[$intersectionObserver] = new IntersectionObserver((entries)=>{ 48662 for (let entry of entries){ 48663 if (entry.target === this) { 48664 const oldVisibility = this.modelIsVisible; 48665 this[$isElementInViewport] = entry.isIntersecting; 48666 this[$announceModelVisibility](oldVisibility); 48667 if (this[$isElementInViewport] && !this.loaded) { 48668 this[$updateSource](); 48669 } 48670 } 48671 } 48672 }, { 48673 root: null, 48674 rootMargin: '0px', 48675 threshold: 0.00001 48676 }); 48677 } else { 48678 this[$isElementInViewport] = true; 48679 } 48680 } 48681 } 48682 __decorate$4([ 48683 n$2({ 48684 type: String 48685 }) 48686 ], ModelViewerElementBase.prototype, "alt", void 0); 48687 __decorate$4([ 48688 n$2({ 48689 type: String 48690 }) 48691 ], ModelViewerElementBase.prototype, "src", void 0); 48692 __decorate$4([ 48693 n$2({ 48694 type: Boolean, 48695 attribute: 'with-credentials' 48696 }) 48697 ], ModelViewerElementBase.prototype, "withCredentials", void 0); 48698 __decorate$4([ 48699 n$2({ 48700 type: Boolean, 48701 attribute: 'generate-schema' 48702 }) 48703 ], ModelViewerElementBase.prototype, "generateSchema", void 0); 48704 48705 var __decorate$3 = undefined && undefined.__decorate || function(decorators, target, key, desc) { 48706 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 48707 for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 48708 return c > 3 && r && Object.defineProperty(target, key, r), r; 48709 }; 48710 const MILLISECONDS_PER_SECOND = 1000.0; 48711 const $changeAnimation = Symbol('changeAnimation'); 48712 const $appendAnimation = Symbol('appendAnimation'); 48713 const $detachAnimation = Symbol('detachAnimation'); 48714 const $paused = Symbol('paused'); 48715 const DEFAULT_PLAY_OPTIONS = { 48716 repetitions: Infinity, 48717 pingpong: false 48718 }; 48719 const DEFAULT_APPEND_OPTIONS = { 48720 pingpong: false, 48721 repetitions: null, 48722 weight: 1, 48723 timeScale: 1, 48724 fade: false, 48725 warp: false, 48726 relativeWarp: true, 48727 time: null 48728 }; 48729 const DEFAULT_DETACH_OPTIONS = { 48730 fade: true 48731 }; 48732 const AnimationMixin = (ModelViewerElement)=>{ 48733 var _a; 48734 class AnimationModelViewerElement extends ModelViewerElement { 48735 get availableAnimations() { 48736 if (this.loaded) { 48737 return this[$scene].animationNames; 48738 } 48739 return []; 48740 } 48741 get duration() { 48742 return this[$scene].duration; 48743 } 48744 get paused() { 48745 return this[$paused]; 48746 } 48747 get currentTime() { 48748 return this[$scene].animationTime; 48749 } 48750 get appendedAnimations() { 48751 return this[$scene].appendedAnimations; 48752 } 48753 set currentTime(value) { 48754 this[$scene].animationTime = value; 48755 this[$needsRender](); 48756 } 48757 get timeScale() { 48758 return this[$scene].animationTimeScale; 48759 } 48760 set timeScale(value) { 48761 this[$scene].animationTimeScale = value; 48762 } 48763 pause() { 48764 if (this[$paused]) { 48765 return; 48766 } 48767 this[$paused] = true; 48768 this.dispatchEvent(new CustomEvent('pause')); 48769 } 48770 play(options) { 48771 if (this.availableAnimations.length > 0) { 48772 this[$paused] = false;
vendor: 4,213 bytes, lines 48773-48859
48773 this[$changeAnimation](options); 48774 this.dispatchEvent(new CustomEvent('play')); 48775 } 48776 } 48777 appendAnimation(animationName, options) { 48778 if (this.availableAnimations.length > 0) { 48779 this[$paused] = false; 48780 this[$appendAnimation](animationName, options); 48781 this.dispatchEvent(new CustomEvent('append-animation')); 48782 } 48783 } 48784 detachAnimation(animationName, options) { 48785 if (this.availableAnimations.length > 0) { 48786 this[$paused] = false; 48787 this[$detachAnimation](animationName, options); 48788 this.dispatchEvent(new CustomEvent('detach-animation')); 48789 } 48790 } 48791 [(_a = $paused, $onModelLoad)]() { 48792 super[$onModelLoad](); 48793 this[$paused] = true; 48794 if (this.animationName != null) { 48795 this[$changeAnimation](); 48796 } 48797 if (this.autoplay) { 48798 this.play(); 48799 } 48800 } 48801 [$tick](_time, delta) { 48802 super[$tick](_time, delta); 48803 if (this[$paused] || !this[$getModelIsVisible]() && !this[$renderer].isPresenting) { 48804 return; 48805 } 48806 this[$scene].updateAnimation(delta / MILLISECONDS_PER_SECOND); 48807 this[$needsRender](); 48808 } 48809 updated(changedProperties) { 48810 super.updated(changedProperties); 48811 if (changedProperties.has('autoplay') && this.autoplay) { 48812 this.play(); 48813 } 48814 if (changedProperties.has('animationName')) { 48815 this[$changeAnimation](); 48816 } 48817 } 48818 [$changeAnimation](options = DEFAULT_PLAY_OPTIONS) { 48819 var _b; 48820 const repetitions = (_b = options.repetitions) !== null && _b !== void 0 ? _b : Infinity; 48821 const mode = options.pingpong ? LoopPingPong : repetitions === 1 ? LoopOnce : LoopRepeat; 48822 this[$scene].playAnimation(this.animationName, this.animationCrossfadeDuration / MILLISECONDS_PER_SECOND, mode, repetitions); 48823 if (this[$paused]) { 48824 this[$scene].updateAnimation(0); 48825 this[$needsRender](); 48826 } 48827 } 48828 [$appendAnimation](animationName = '', options = DEFAULT_APPEND_OPTIONS) { 48829 var _b; 48830 const repetitions = (_b = options.repetitions) !== null && _b !== void 0 ? _b : Infinity; 48831 const mode = options.pingpong ? LoopPingPong : repetitions === 1 ? LoopOnce : LoopRepeat; 48832 const needsToStop = !!options.repetitions || 'pingpong' in options; 48833 this[$scene].appendAnimation(animationName ? animationName : this.animationName, mode, repetitions, options.weight, options.timeScale, options.fade, options.warp, options.relativeWarp, options.time, needsToStop); 48834 if (this[$paused]) { 48835 this[$scene].updateAnimation(0); 48836 this[$needsRender](); 48837 } 48838 } 48839 [$detachAnimation](animationName = '', options = DEFAULT_DETACH_OPTIONS) { 48840 this[$scene].detachAnimation(animationName ? animationName : this.animationName, options.fade); 48841 if (this[$paused]) { 48842 this[$scene].updateAnimation(0); 48843 this[$needsRender](); 48844 } 48845 } 48846 constructor(...args){ 48847 super(args); 48848 this.autoplay = false; 48849 this.animationName = undefined; 48850 this.animationCrossfadeDuration = 300; 48851 this[_a] = true; 48852 this[$scene].subscribeMixerEvent('loop', (e)=>{ 48853 const count = e.action._loopCount; 48854 const name = e.action._clip.name; 48855 const uuid = e.action._clip.uuid; 48856 const targetAnimation = this[$scene].markedAnimations.find((e)=>e.name === name); 48857 if (targetAnimation) { 48858 this[$scene].updateAnimationLoop(targetAnimation.name, targetAnimation.loopMode, targetAnimation.repetitionCount); 48859 const filtredArr = this[$scene].markedAnimations.filter((e)=>
vendor: 4,599 bytes, lines 48859-48977
48859e.name !== name); 48860 this[$scene].markedAnimations = filtredArr; 48861 } 48862 this.dispatchEvent(new CustomEvent('loop', { 48863 detail: { 48864 count, 48865 name, 48866 uuid 48867 } 48868 })); 48869 }); 48870 this[$scene].subscribeMixerEvent('finished', (e)=>{ 48871 if (!this[$scene].appendedAnimations.includes(e.action._clip.name)) { 48872 this[$paused] = true; 48873 } else { 48874 const filterdList = this[$scene].appendedAnimations.filter((i)=>i !== e.action._clip.name); 48875 this[$scene].appendedAnimations = filterdList; 48876 } 48877 this.dispatchEvent(new CustomEvent('finished')); 48878 }); 48879 } 48880 } 48881 __decorate$3([ 48882 n$2({ 48883 type: Boolean 48884 }) 48885 ], AnimationModelViewerElement.prototype, "autoplay", void 0); 48886 __decorate$3([ 48887 n$2({ 48888 type: String, 48889 attribute: 'animation-name' 48890 }) 48891 ], AnimationModelViewerElement.prototype, "animationName", void 0); 48892 __decorate$3([ 48893 n$2({ 48894 type: Number, 48895 attribute: 'animation-crossfade-duration' 48896 }) 48897 ], AnimationModelViewerElement.prototype, "animationCrossfadeDuration", void 0); 48898 return AnimationModelViewerElement; 48899 }; 48900 48901 const $hotspotMap = Symbol('hotspotMap'); 48902 const $mutationCallback = Symbol('mutationCallback'); 48903 const $observer = Symbol('observer'); 48904 const $addHotspot = Symbol('addHotspot'); 48905 const $removeHotspot = Symbol('removeHotspot'); 48906 const worldToModel = new Matrix4(); 48907 const AnnotationMixin = (ModelViewerElement)=>{ 48908 var _a, _b, _c; 48909 class AnnotationModelViewerElement extends ModelViewerElement { 48910 connectedCallback() { 48911 super.connectedCallback(); 48912 for(let i = 0; i < this.children.length; ++i){ 48913 this[$addHotspot](this.children[i]); 48914 } 48915 const { ShadyDOM } = self; 48916 if (ShadyDOM == null) { 48917 this[$observer].observe(this, { 48918 childList: true 48919 }); 48920 } else { 48921 this[$observer] = ShadyDOM.observeChildren(this, this[$mutationCallback]); 48922 } 48923 } 48924 disconnectedCallback() { 48925 super.disconnectedCallback(); 48926 const { ShadyDOM } = self; 48927 if (ShadyDOM == null) { 48928 this[$observer].disconnect(); 48929 } else { 48930 ShadyDOM.unobserveChildren(this[$observer]); 48931 } 48932 } 48933 [(_a = $hotspotMap, _b = $mutationCallback, _c = $observer, $onModelLoad)]() { 48934 super[$onModelLoad](); 48935 const scene = this[$scene]; 48936 scene.forHotspots((hotspot)=>{ 48937 scene.updateSurfaceHotspot(hotspot); 48938 }); 48939 } 48940 [$tick](time, delta) { 48941 super[$tick](time, delta); 48942 const scene = this[$scene]; 48943 const { annotationRenderer } = scene; 48944 const camera = scene.getCamera(); 48945 if (scene.shouldRender()) { 48946 scene.animateSurfaceHotspots(); 48947 scene.updateHotspotsVisibility(camera.position); 48948 annotationRenderer.domElement.style.display = ''; 48949 annotationRenderer.render(scene, camera); 48950 } 48951 } 48952 updateHotspot(config) { 48953 const hotspot = this[$hotspotMap].get(config.name); 48954 if (hotspot == null) { 48955 return; 48956 } 48957 hotspot.updatePosition(config.position); 48958 hotspot.updateNormal(config.normal); 48959 hotspot.surface = config.surface; 48960 this[$scene].updateSurfaceHotspot(hotspot); 48961 this[$needsRender](); 48962 } 48963 queryHotspot(name) { 48964 const hotspot = this[$hotspotMap].get(name); 48965 if (hotspot == null) { 48966 return null; 48967 } 48968 const position = toVector3D(hotspot.position); 48969 const normal = toVector3D(hotspot.normal); 48970 const facingCamera = hotspot.facingCamera; 48971 const scene = this[$scene]; 48972 const camera = scene.getCamera(); 48973 const vector = new Vector3(); 48974 vector.setFromMatrixPosition(hotspot.matrixWorld); 48975 vector.project(camera); 48976 const widthHalf = scene.width / 2; 48977 const heightHalf = scene.height / 2;
vendor: 4,034 bytes, lines 48978-49079
48978 vector.x = vector.x * widthHalf + widthHalf; 48979 vector.y = -(vector.y * heightHalf) + heightHalf; 48980 const canvasPosition = toVector3D(new Vector3(vector.x, vector.y, vector.z)); 48981 if (!Number.isFinite(canvasPosition.x) || !Number.isFinite(canvasPosition.y)) { 48982 return null; 48983 } 48984 return { 48985 position, 48986 normal, 48987 canvasPosition, 48988 facingCamera 48989 }; 48990 } 48991 positionAndNormalFromPoint(pixelX, pixelY) { 48992 const scene = this[$scene]; 48993 const ndcPosition = scene.getNDC(pixelX, pixelY); 48994 const hit = scene.positionAndNormalFromPoint(ndcPosition); 48995 if (hit == null) { 48996 return null; 48997 } 48998 worldToModel.copy(scene.target.matrixWorld).invert(); 48999 const position = toVector3D(hit.position.applyMatrix4(worldToModel)); 49000 const normal = toVector3D(hit.normal.transformDirection(worldToModel)); 49001 let uv = null; 49002 if (hit.uv != null) { 49003 uv = toVector2D(hit.uv); 49004 } 49005 return { 49006 position: position, 49007 normal: normal, 49008 uv: uv 49009 }; 49010 } 49011 surfaceFromPoint(pixelX, pixelY) { 49012 const scene = this[$scene]; 49013 const ndcPosition = scene.getNDC(pixelX, pixelY); 49014 return scene.surfaceFromPoint(ndcPosition); 49015 } 49016 [$addHotspot](node) { 49017 if (!(node instanceof HTMLElement && node.slot.indexOf('hotspot') === 0)) { 49018 return; 49019 } 49020 let hotspot = this[$hotspotMap].get(node.slot); 49021 if (hotspot != null) { 49022 hotspot.increment(); 49023 } else { 49024 hotspot = new Hotspot({ 49025 name: node.slot, 49026 position: node.dataset.position, 49027 normal: node.dataset.normal, 49028 surface: node.dataset.surface 49029 }); 49030 this[$hotspotMap].set(node.slot, hotspot); 49031 this[$scene].addHotspot(hotspot); 49032 } 49033 this[$scene].queueRender(); 49034 } 49035 [$removeHotspot](node) { 49036 if (!(node instanceof HTMLElement)) { 49037 return; 49038 } 49039 const hotspot = this[$hotspotMap].get(node.slot); 49040 if (!hotspot) { 49041 return; 49042 } 49043 if (hotspot.decrement()) { 49044 this[$scene].removeHotspot(hotspot); 49045 this[$hotspotMap].delete(node.slot); 49046 } 49047 this[$scene].queueRender(); 49048 } 49049 constructor(){ 49050 super(...arguments); 49051 this[_a] = new Map(); 49052 this[_b] = (mutations)=>{ 49053 mutations.forEach((mutation)=>{ 49054 if (!(mutation instanceof MutationRecord) || mutation.type === 'childList') { 49055 mutation.addedNodes.forEach((node)=>{ 49056 this[$addHotspot](node); 49057 }); 49058 mutation.removedNodes.forEach((node)=>{ 49059 this[$removeHotspot](node); 49060 }); 49061 this[$needsRender](); 49062 } 49063 }); 49064 }; 49065 this[_c] = new MutationObserver(this[$mutationCallback]); 49066 } 49067 } 49068 return AnnotationModelViewerElement; 49069 }; 49070 49071 /*! 49072 fflate - fast JavaScript compression/decompression 49073 <https://101arrowz.github.io/fflate> 49074 Licensed under MIT. https://github.com/101arrowz/fflate/blob/master/LICENSE 49075 version 0.8.2 49076 */ // DEFLATE is a complex format; to read this code, you should probably check the RFC first: 49077 // https://tools.ietf.org/html/rfc1951 49078 // You may also wish to take a look at the guide I made about this program: 49079 // https://gist.github.com/101arrowz/253f31eb5abc3d9275ab943003ffecad
vendor: 5,986 bytes, lines 49080-49326
49080 // Some of the following code is similar to that of UZIP.js: 49081 // https://github.com/photopea/UZIP.js 49082 // However, the vast majority of the codebase has diverged from UZIP.js to increase performance and reduce bundle size. 49083 // Sometimes 0 will appear where -1 would be more appropriate. This is because using a uint 49084 // is better for memory in most engines (I *think*). 49085 // aliases for shorter compressed code (most minifers don't do this) 49086 var u8 = Uint8Array, u16 = Uint16Array, i32 = Int32Array; 49087 // fixed length extra bits 49088 var fleb = new u8([ 49089 0, 49090 0, 49091 0, 49092 0, 49093 0, 49094 0, 49095 0, 49096 0, 49097 1, 49098 1, 49099 1, 49100 1, 49101 2, 49102 2, 49103 2, 49104 2, 49105 3, 49106 3, 49107 3, 49108 3, 49109 4, 49110 4, 49111 4, 49112 4, 49113 5, 49114 5, 49115 5, 49116 5, 49117 0, 49118 /* unused */ 0, 49119 0, 49120 /* impossible */ 0 49121 ]); 49122 // fixed distance extra bits 49123 var fdeb = new u8([ 49124 0, 49125 0, 49126 0, 49127 0, 49128 1, 49129 1, 49130 2, 49131 2, 49132 3, 49133 3, 49134 4, 49135 4, 49136 5, 49137 5, 49138 6, 49139 6, 49140 7, 49141 7, 49142 8, 49143 8, 49144 9, 49145 9, 49146 10, 49147 10, 49148 11, 49149 11, 49150 12, 49151 12, 49152 13, 49153 13, 49154 /* unused */ 0, 49155 0 49156 ]); 49157 // code length index map 49158 var clim = new u8([ 49159 16, 49160 17, 49161 18, 49162 0, 49163 8, 49164 7, 49165 9, 49166 6, 49167 10, 49168 5, 49169 11, 49170 4, 49171 12, 49172 3, 49173 13, 49174 2, 49175 14, 49176 1, 49177 15 49178 ]); 49179 // get base, reverse index map from extra bits 49180 var freb = function(eb, start) { 49181 var b = new u16(31); 49182 for(var i = 0; i < 31; ++i){ 49183 b[i] = start += 1 << eb[i - 1]; 49184 } 49185 // numbers here are at max 18 bits 49186 var r = new i32(b[30]); 49187 for(var i = 1; i < 30; ++i){ 49188 for(var j = b[i]; j < b[i + 1]; ++j){ 49189 r[j] = j - b[i] << 5 | i; 49190 } 49191 } 49192 return { 49193 b: b, 49194 r: r 49195 }; 49196 }; 49197 var _a = freb(fleb, 2), fl = _a.b, revfl = _a.r; 49198 // we can ignore the fact that the other numbers are wrong; they never happen anyway 49199 fl[28] = 258, revfl[258] = 28; 49200 var _b = freb(fdeb, 0), revfd = _b.r; 49201 // map of value to reverse (assuming 16 bits) 49202 var rev = new u16(32768); 49203 for(var i = 0; i < 32768; ++i){ 49204 // reverse table algorithm from SO 49205 var x = (i & 0xAAAA) >> 1 | (i & 0x5555) << 1; 49206 x = (x & 0xCCCC) >> 2 | (x & 0x3333) << 2; 49207 x = (x & 0xF0F0) >> 4 | (x & 0x0F0F) << 4; 49208 rev[i] = ((x & 0xFF00) >> 8 | (x & 0x00FF) << 8) >> 1; 49209 } 49210 // create huffman tree from u8 "map": index -> code length for code index 49211 // mb (max bits) must be at most 15 49212 // TODO: optimize/split up? 49213 var hMap = function(cd, mb, r) { 49214 var s = cd.length; 49215 // index 49216 var i = 0; 49217 // u16 "map": index -> # of codes with bit length = index 49218 var l = new u16(mb); 49219 // length of cd must be 288 (total # of codes) 49220 for(; i < s; ++i){ 49221 if (cd[i]) ++l[cd[i] - 1]; 49222 } 49223 // u16 "map": index -> minimum code for bit length = index 49224 var le = new u16(mb); 49225 for(i = 1; i < mb; ++i){ 49226 le[i] = le[i - 1] + l[i - 1] << 1; 49227 } 49228 var co; 49229 if (r) { 49230 // u16 "map": index -> number of actual bits, symbol for code 49231 co = new u16(1 << mb); 49232 // bits to remove for reverser 49233 var rvb = 15 - mb; 49234 for(i = 0; i < s; ++i){ 49235 // ignore 0 lengths 49236 if (cd[i]) { 49237 // num encoding both symbol and bits read 49238 var sv = i << 4 | cd[i]; 49239 // free bits 49240 var r_1 = mb - cd[i]; 49241 // start value 49242 var v = le[cd[i] - 1]++ << r_1; 49243 // m is end value 49244 for(var m = v | (1 << r_1) - 1; v <= m; ++v){ 49245 // every 16 bit value starting with the code yields the same result 49246 co[rev[v] >> rvb] = sv; 49247 } 49248 } 49249 } 49250 } else { 49251 co = new u16(s); 49252 for(i = 0; i < s; ++i){ 49253 if (cd[i]) { 49254 co[i] = rev[le[cd[i] - 1]++] >> 15 - cd[i]; 49255 } 49256 } 49257 } 49258 return co; 49259 }; 49260 // fixed length tree 49261 var flt = new u8(288); 49262 for(var i = 0; i < 144; ++i)flt[i] = 8; 49263 for(var i = 144; i < 256; ++i)flt[i] = 9; 49264 for(var i = 256; i < 280; ++i)flt[i] = 7; 49265 for(var i = 280; i < 288; ++i)flt[i] = 8; 49266 // fixed distance tree 49267 var fdt = new u8(32); 49268 for(var i = 0; i < 32; ++i)fdt[i] = 5; 49269 // fixed length map 49270 var flm = /*#__PURE__*/ hMap(flt, 9, 0); 49271 // fixed distance map 49272 var fdm = /*#__PURE__*/ hMap(fdt, 5, 0); 49273 // get end of byte 49274 var shft = function(p) { 49275 return (p + 7) / 8 | 0; 49276 }; 49277 // typed array slice - allows garbage collector to free original reference, 49278 // while being more compatible than .slice 49279 var slc = function(v, s, e) { 49280 if (e == null || e > v.length) e = v.length; 49281 // can't use .constructor in case user-supplied 49282 return new u8(v.subarray(s, e)); 49283 }; 49284 // error codes 49285 var ec = [ 49286 'unexpected EOF', 49287 'invalid block type', 49288 'invalid length/literal', 49289 'invalid distance', 49290 'stream finished', 49291 'no stream handler', 49292 , 49293 'no callback', 49294 'invalid UTF-8 data', 49295 'extra field too long', 49296 'date not in range 1980-2099', 49297 'filename too long', 49298 'stream finishing', 49299 'invalid zip data' 49300 ]; 49301 var err = function(ind, msg, nt) { 49302 var e = new Error(msg || ec[ind]); 49303 e.code = ind; 49304 if (Error.captureStackTrace) Error.captureStackTrace(e, err); 49305 if (!nt) throw e; 49306 return e; 49307 }; 49308 // starting at p, write the minimum number of bits that can hold v to d 49309 var wbits = function(d, p, v) { 49310 v <<= p & 7; 49311 var o = p / 8 | 0; 49312 d[o] |= v; 49313 d[o + 1] |= v >> 8; 49314 }; 49315 // starting at p, write the minimum number of bits (>8) that can hold v to d 49316 var wbits16 = function(d, p, v) { 49317 v <<= p & 7; 49318 var o = p / 8 | 0; 49319 d[o] |= v; 49320 d[o + 1] |= v >> 8; 49321 d[o + 2] |= v >> 16; 49322 }; 49323 // creates code lengths from a frequency table 49324 var hTree = function(d, mb) { 49325 // Need extra info to make a tree 49326 var t = [];
vendor: 10,065 bytes, lines 49327-49613
49327 for(var i = 0; i < d.length; ++i){ 49328 if (d[i]) t.push({ 49329 s: i, 49330 f: d[i] 49331 }); 49332 } 49333 var s = t.length; 49334 var t2 = t.slice(); 49335 if (!s) return { 49336 t: et, 49337 l: 0 49338 }; 49339 if (s == 1) { 49340 var v = new u8(t[0].s + 1); 49341 v[t[0].s] = 1; 49342 return { 49343 t: v, 49344 l: 1 49345 }; 49346 } 49347 t.sort(function(a, b) { 49348 return a.f - b.f; 49349 }); 49350 // after i2 reaches last ind, will be stopped 49351 // freq must be greater than largest possible number of symbols 49352 t.push({ 49353 s: -1, 49354 f: 25001 49355 }); 49356 var l = t[0], r = t[1], i0 = 0, i1 = 1, i2 = 2; 49357 t[0] = { 49358 s: -1, 49359 f: l.f + r.f, 49360 l: l, 49361 r: r 49362 }; 49363 // efficient algorithm from UZIP.js 49364 // i0 is lookbehind, i2 is lookahead - after processing two low-freq 49365 // symbols that combined have high freq, will start processing i2 (high-freq, 49366 // non-composite) symbols instead 49367 // see https://reddit.com/r/photopea/comments/ikekht/uzipjs_questions/ 49368 while(i1 != s - 1){ 49369 l = t[t[i0].f < t[i2].f ? i0++ : i2++]; 49370 r = t[i0 != i1 && t[i0].f < t[i2].f ? i0++ : i2++]; 49371 t[i1++] = { 49372 s: -1, 49373 f: l.f + r.f, 49374 l: l, 49375 r: r 49376 }; 49377 } 49378 var maxSym = t2[0].s; 49379 for(var i = 1; i < s; ++i){ 49380 if (t2[i].s > maxSym) maxSym = t2[i].s; 49381 } 49382 // code lengths 49383 var tr = new u16(maxSym + 1); 49384 // max bits in tree 49385 var mbt = ln(t[i1 - 1], tr, 0); 49386 if (mbt > mb) { 49387 // more algorithms from UZIP.js 49388 // TODO: find out how this code works (debt) 49389 // ind debt 49390 var i = 0, dt = 0; 49391 // left cost 49392 var lft = mbt - mb, cst = 1 << lft; 49393 t2.sort(function(a, b) { 49394 return tr[b.s] - tr[a.s] || a.f - b.f; 49395 }); 49396 for(; i < s; ++i){ 49397 var i2_1 = t2[i].s; 49398 if (tr[i2_1] > mb) { 49399 dt += cst - (1 << mbt - tr[i2_1]); 49400 tr[i2_1] = mb; 49401 } else break; 49402 } 49403 dt >>= lft; 49404 while(dt > 0){ 49405 var i2_2 = t2[i].s; 49406 if (tr[i2_2] < mb) dt -= 1 << mb - tr[i2_2]++ - 1; 49407 else ++i; 49408 } 49409 for(; i >= 0 && dt; --i){ 49410 var i2_3 = t2[i].s; 49411 if (tr[i2_3] == mb) { 49412 --tr[i2_3]; 49413 ++dt; 49414 } 49415 } 49416 mbt = mb; 49417 } 49418 return { 49419 t: new u8(tr), 49420 l: mbt 49421 }; 49422 }; 49423 // get the max length and assign length codes 49424 var ln = function(n, l, d) { 49425 return n.s == -1 ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1)) : l[n.s] = d; 49426 }; 49427 // length codes generation 49428 var lc = function(c) { 49429 var s = c.length; 49430 // Note that the semicolon was intentional 49431 while(s && !c[--s]); 49432 var cl = new u16(++s); 49433 // ind num streak 49434 var cli = 0, cln = c[0], cls = 1; 49435 var w = function(v) { 49436 cl[cli++] = v; 49437 }; 49438 for(var i = 1; i <= s; ++i){ 49439 if (c[i] == cln && i != s) ++cls; 49440 else { 49441 if (!cln && cls > 2) { 49442 for(; cls > 138; cls -= 138)w(32754); 49443 if (cls > 2) { 49444 w(cls > 10 ? cls - 11 << 5 | 28690 : cls - 3 << 5 | 12305); 49445 cls = 0; 49446 } 49447 } else if (cls > 3) { 49448 w(cln), --cls; 49449 for(; cls > 6; cls -= 6)w(8304); 49450 if (cls > 2) w(cls - 3 << 5 | 8208), cls = 0; 49451 } 49452 while(cls--)w(cln); 49453 cls = 1; 49454 cln = c[i]; 49455 } 49456 } 49457 return { 49458 c: cl.subarray(0, cli), 49459 n: s 49460 }; 49461 }; 49462 // calculate the length of output from tree, code lengths 49463 var clen = function(cf, cl) { 49464 var l = 0; 49465 for(var i = 0; i < cl.length; ++i)l += cf[i] * cl[i]; 49466 return l; 49467 }; 49468 // writes a fixed block 49469 // returns the new bit pos 49470 var wfblk = function(out, pos, dat) { 49471 // no need to write 00 as type: TypedArray defaults to 0 49472 var s = dat.length; 49473 var o = shft(pos + 2); 49474 out[o] = s & 255; 49475 out[o + 1] = s >> 8; 49476 out[o + 2] = out[o] ^ 255; 49477 out[o + 3] = out[o + 1] ^ 255; 49478 for(var i = 0; i < s; ++i)out[o + i + 4] = dat[i]; 49479 return (o + 4 + s) * 8; 49480 }; 49481 // writes a block 49482 var wblk = function(dat, out, final, syms, lf, df, eb, li, bs, bl, p) { 49483 wbits(out, p++, final); 49484 ++lf[256]; 49485 var _a = hTree(lf, 15), dlt = _a.t, mlb = _a.l; 49486 var _b = hTree(df, 15), ddt = _b.t, mdb = _b.l; 49487 var _c = lc(dlt), lclt = _c.c, nlc = _c.n; 49488 var _d = lc(ddt), lcdt = _d.c, ndc = _d.n; 49489 var lcfreq = new u16(19); 49490 for(var i = 0; i < lclt.length; ++i)++lcfreq[lclt[i] & 31]; 49491 for(var i = 0; i < lcdt.length; ++i)++lcfreq[lcdt[i] & 31]; 49492 var _e = hTree(lcfreq, 7), lct = _e.t, mlcb = _e.l; 49493 var nlcc = 19; 49494 for(; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc); 49495 var flen = bl + 5 << 3; 49496 var ftlen = clen(lf, flt) + clen(df, fdt) + eb; 49497 var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + 2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18]; 49498 if (bs >= 0 && flen <= ftlen && flen <= dtlen) return wfblk(out, p, dat.subarray(bs, bs + bl)); 49499 var lm, ll, dm, dl; 49500 wbits(out, p, 1 + (dtlen < ftlen)), p += 2; 49501 if (dtlen < ftlen) { 49502 lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt; 49503 var llm = hMap(lct, mlcb, 0); 49504 wbits(out, p, nlc - 257); 49505 wbits(out, p + 5, ndc - 1); 49506 wbits(out, p + 10, nlcc - 4); 49507 p += 14; 49508 for(var i = 0; i < nlcc; ++i)wbits(out, p + 3 * i, lct[clim[i]]); 49509 p += 3 * nlcc; 49510 var lcts = [ 49511 lclt, 49512 lcdt 49513 ]; 49514 for(var it = 0; it < 2; ++it){ 49515 var clct = lcts[it]; 49516 for(var i = 0; i < clct.length; ++i){ 49517 var len = clct[i] & 31; 49518 wbits(out, p, llm[len]), p += lct[len]; 49519 if (len > 15) wbits(out, p, clct[i] >> 5 & 127), p += clct[i] >> 12; 49520 } 49521 } 49522 } else { 49523 lm = flm, ll = flt, dm = fdm, dl = fdt; 49524 } 49525 for(var i = 0; i < li; ++i){ 49526 var sym = syms[i]; 49527 if (sym > 255) { 49528 var len = sym >> 18 & 31; 49529 wbits16(out, p, lm[len + 257]), p += ll[len + 257]; 49530 if (len > 7) wbits(out, p, sym >> 23 & 31), p += fleb[len]; 49531 var dst = sym & 31; 49532 wbits16(out, p, dm[dst]), p += dl[dst]; 49533 if (dst > 3) wbits16(out, p, sym >> 5 & 8191), p += fdeb[dst]; 49534 } else { 49535 wbits16(out, p, lm[sym]), p += ll[sym]; 49536 } 49537 } 49538 wbits16(out, p, lm[256]); 49539 return p + ll[256]; 49540 }; 49541 // deflate options (nice << 13) | chain 49542 var deo = /*#__PURE__*/ new i32([ 49543 65540, 49544 131080, 49545 131088, 49546 131104, 49547 262176, 49548 1048704, 49549 1048832, 49550 2114560, 49551 2117632 49552 ]); 49553 // empty 49554 var et = /*#__PURE__*/ new u8(0); 49555 // compresses data into a raw DEFLATE buffer 49556 var dflt = function(dat, lvl, plvl, pre, post, st) { 49557 var s = st.z || dat.length; 49558 var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7000)) + post); 49559 // writing to this writes to the output buffer 49560 var w = o.subarray(pre, o.length - post); 49561 var lst = st.l; 49562 var pos = (st.r || 0) & 7; 49563 if (lvl) { 49564 if (pos) w[0] = st.r >> 3; 49565 var opt = deo[lvl - 1]; 49566 var n = opt >> 13, c = opt & 8191; 49567 var msk_1 = (1 << plvl) - 1; 49568 // prev 2-byte val map curr 2-byte val map 49569 var prev = st.p || new u16(32768), head = st.h || new u16(msk_1 + 1); 49570 var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1; 49571 var hsh = function(i) { 49572 return (dat[i] ^ dat[i + 1] << bs1_1 ^ dat[i + 2] << bs2_1) & msk_1; 49573 }; 49574 // 24576 is an arbitrary number of maximum symbols per block 49575 // 424 buffer for last block 49576 var syms = new i32(25000); 49577 // length/literal freq distance freq 49578 var lf = new u16(288), df = new u16(32); 49579 // l/lcnt exbits index l/lind waitdx blkpos 49580 var lc_1 = 0, eb = 0, i = st.i || 0, li = 0, wi = st.w || 0, bs = 0; 49581 for(; i + 2 < s; ++i){ 49582 // hash value 49583 var hv = hsh(i); 49584 // index mod 32768 previous index mod 49585 var imod = i & 32767, pimod = head[hv]; 49586 prev[imod] = pimod; 49587 head[hv] = imod; 49588 // We always should modify head and prev, but only add symbols if 49589 // this data is not yet processed ("wait" for wait index) 49590 if (wi <= i) { 49591 // bytes remaining 49592 var rem = s - i; 49593 if ((lc_1 > 7000 || li > 24576) && (rem > 423 || !lst)) { 49594 pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i - bs, pos); 49595 li = lc_1 = eb = 0, bs = i; 49596 for(var j = 0; j < 286; ++j)lf[j] = 0; 49597 for(var j = 0; j < 30; ++j)df[j] = 0; 49598 } 49599 // len dist chain 49600 var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767; 49601 if (rem > 2 && hv == hsh(i - dif)) { 49602 var maxn = Math.min(n, rem) - 1; 49603 var maxd = Math.min(32767, i); 49604 // max possible length 49605 // not capped at dif because decompressors implement "rolling" index population 49606 var ml = Math.min(258, rem); 49607 while(dif <= maxd && --ch_1 && imod != pimod){ 49608 if (dat[i + l] == dat[i + l - dif]) { 49609 var nl = 0; 49610 for(; nl < ml && dat[i + nl] == dat[i + nl - dif]; ++nl); 49611 if (nl > l) { 49612 l = nl, d = dif; 49613 // break out early when we reach "nice"
vendor: 16,127 bytes, lines 49613-50072
49613(we are satisfied enough) 49614 if (nl > maxn) break; 49615 // now, find the rarest 2-byte sequence within this 49616 // length of literals and search for that instead. 49617 // Much faster than just using the start 49618 var mmd = Math.min(dif, nl - 2); 49619 var md = 0; 49620 for(var j = 0; j < mmd; ++j){ 49621 var ti = i - dif + j & 32767; 49622 var pti = prev[ti]; 49623 var cd = ti - pti & 32767; 49624 if (cd > md) md = cd, pimod = ti; 49625 } 49626 } 49627 } 49628 // check the previous match 49629 imod = pimod, pimod = prev[imod]; 49630 dif += imod - pimod & 32767; 49631 } 49632 } 49633 // d will be nonzero only when a match was found 49634 if (d) { 49635 // store both dist and len data in one int32 49636 // Make sure this is recognized as a len/dist with 28th bit (2^28) 49637 syms[li++] = 268435456 | revfl[l] << 18 | revfd[d]; 49638 var lin = revfl[l] & 31, din = revfd[d] & 31; 49639 eb += fleb[lin] + fdeb[din]; 49640 ++lf[257 + lin]; 49641 ++df[din]; 49642 wi = i + l; 49643 ++lc_1; 49644 } else { 49645 syms[li++] = dat[i]; 49646 ++lf[dat[i]]; 49647 } 49648 } 49649 } 49650 for(i = Math.max(i, wi); i < s; ++i){ 49651 syms[li++] = dat[i]; 49652 ++lf[dat[i]]; 49653 } 49654 pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i - bs, pos); 49655 if (!lst) { 49656 st.r = pos & 7 | w[pos / 8 | 0] << 3; 49657 // shft(pos) now 1 less if pos & 7 != 0 49658 pos -= 7; 49659 st.h = head, st.p = prev, st.i = i, st.w = wi; 49660 } 49661 } else { 49662 for(var i = st.w || 0; i < s + lst; i += 65535){ 49663 // end 49664 var e = i + 65535; 49665 if (e >= s) { 49666 // write final block 49667 w[pos / 8 | 0] = lst; 49668 e = s; 49669 } 49670 pos = wfblk(w, pos + 1, dat.subarray(i, e)); 49671 } 49672 st.i = s; 49673 } 49674 return slc(o, 0, pre + shft(pos) + post); 49675 }; 49676 // CRC32 table 49677 var crct = /*#__PURE__*/ function() { 49678 var t = new Int32Array(256); 49679 for(var i = 0; i < 256; ++i){ 49680 var c = i, k = 9; 49681 while(--k)c = (c & 1 && -306674912) ^ c >>> 1; 49682 t[i] = c; 49683 } 49684 return t; 49685 }(); 49686 // CRC32 49687 var crc = function() { 49688 var c = -1; 49689 return { 49690 p: function(d) { 49691 // closures have awful performance 49692 var cr = c; 49693 for(var i = 0; i < d.length; ++i)cr = crct[cr & 255 ^ d[i]] ^ cr >>> 8; 49694 c = cr; 49695 }, 49696 d: function() { 49697 return ~c; 49698 } 49699 }; 49700 }; 49701 // deflate with opts 49702 var dopt = function(dat, opt, pre, post, st) { 49703 if (!st) { 49704 st = { 49705 l: 1 49706 }; 49707 if (opt.dictionary) { 49708 var dict = opt.dictionary.subarray(-32768); 49709 var newDat = new u8(dict.length + dat.length); 49710 newDat.set(dict); 49711 newDat.set(dat, dict.length); 49712 dat = newDat; 49713 st.w = dict.length; 49714 } 49715 } 49716 return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? st.l ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 20 : 12 + opt.mem, pre, post, st); 49717 }; 49718 // Walmart object spread 49719 var mrg = function(a, b) { 49720 var o = {}; 49721 for(var k in a)o[k] = a[k]; 49722 for(var k in b)o[k] = b[k]; 49723 return o; 49724 }; 49725 // write bytes 49726 var wbytes = function(d, b, v) { 49727 for(; v; ++b)d[b] = v, v >>>= 8; 49728 }; 49729 /** 49730 * Compresses data with DEFLATE without any wrapper 49731 * @param data The data to compress 49732 * @param opts The compression options 49733 * @returns The deflated version of the data 49734 */ function deflateSync(data, opts) { 49735 return dopt(data, opts || {}, 0, 0); 49736 } 49737 // flatten a directory structure 49738 var fltn = function(d, p, t, o) { 49739 for(var k in d){ 49740 var val = d[k], n = p + k, op = o; 49741 if (Array.isArray(val)) op = mrg(o, val[1]), val = val[0]; 49742 if (val instanceof u8) t[n] = [ 49743 val, 49744 op 49745 ]; 49746 else { 49747 t[n += '/'] = [ 49748 new u8(0), 49749 op 49750 ]; 49751 fltn(val, n, t, o); 49752 } 49753 } 49754 }; 49755 // text encoder 49756 var te = typeof TextEncoder != 'undefined' && /*#__PURE__*/ new TextEncoder(); 49757 // text decoder 49758 var td = typeof TextDecoder != 'undefined' && /*#__PURE__*/ new TextDecoder(); 49759 // text decoder stream 49760 var tds = 0; 49761 try { 49762 td.decode(et, { 49763 stream: true 49764 }); 49765 tds = 1; 49766 } catch (e) {} 49767 /** 49768 * Converts a string into a Uint8Array for use with compression/decompression methods 49769 * @param str The string to encode 49770 * @param latin1 Whether or not to interpret the data as Latin-1. This should 49771 * not need to be true unless decoding a binary string. 49772 * @returns The string encoded in UTF-8/Latin-1 binary 49773 */ function strToU8(str, latin1) { 49774 var i; 49775 if (te) return te.encode(str); 49776 var l = str.length; 49777 var ar = new u8(str.length + (str.length >> 1)); 49778 var ai = 0; 49779 var w = function(v) { 49780 ar[ai++] = v; 49781 }; 49782 for(var i = 0; i < l; ++i){ 49783 if (ai + 5 > ar.length) { 49784 var n = new u8(ai + 8 + (l - i << 1)); 49785 n.set(ar); 49786 ar = n; 49787 } 49788 var c = str.charCodeAt(i); 49789 if (c < 128 || latin1) w(c); 49790 else if (c < 2048) w(192 | c >> 6), w(128 | c & 63); 49791 else if (c > 55295 && c < 57344) c = 65536 + (c & 1023 << 10) | str.charCodeAt(++i) & 1023, w(240 | c >> 18), w(128 | c >> 12 & 63), w(128 | c >> 6 & 63), w(128 | c & 63); 49792 else w(224 | c >> 12), w(128 | c >> 6 & 63), w(128 | c & 63); 49793 } 49794 return slc(ar, 0, ai); 49795 } 49796 // extra field length 49797 var exfl = function(ex) { 49798 var le = 0; 49799 if (ex) { 49800 for(var k in ex){ 49801 var l = ex[k].length; 49802 if (l > 65535) err(9); 49803 le += l + 4; 49804 } 49805 } 49806 return le; 49807 }; 49808 // write zip header 49809 var wzh = function(d, b, f, fn, u, c, ce, co) { 49810 var fl = fn.length, ex = f.extra, col = co && co.length; 49811 var exl = exfl(ex); 49812 wbytes(d, b, ce != null ? 0x2014B50 : 0x4034B50), b += 4; 49813 if (ce != null) d[b++] = 20, d[b++] = f.os; 49814 d[b] = 20, b += 2; // spec compliance? what's that? 49815 d[b++] = f.flag << 1 | (c < 0 && 8), d[b++] = u && 8; 49816 d[b++] = f.compression & 255, d[b++] = f.compression >> 8; 49817 var dt = new Date(f.mtime == null ? Date.now() : f.mtime), y = dt.getFullYear() - 1980; 49818 if (y < 0 || y > 119) err(10); 49819 wbytes(d, b, y << 25 | dt.getMonth() + 1 << 21 | dt.getDate() << 16 | dt.getHours() << 11 | dt.getMinutes() << 5 | dt.getSeconds() >> 1), b += 4; 49820 if (c != -1) { 49821 wbytes(d, b, f.crc); 49822 wbytes(d, b + 4, c < 0 ? -c - 2 : c); 49823 wbytes(d, b + 8, f.size); 49824 } 49825 wbytes(d, b + 12, fl); 49826 wbytes(d, b + 14, exl), b += 16; 49827 if (ce != null) { 49828 wbytes(d, b, col); 49829 wbytes(d, b + 6, f.attrs); 49830 wbytes(d, b + 10, ce), b += 14; 49831 } 49832 d.set(fn, b); 49833 b += fl; 49834 if (exl) { 49835 for(var k in ex){ 49836 var exf = ex[k], l = exf.length; 49837 wbytes(d, b, +k); 49838 wbytes(d, b + 2, l); 49839 d.set(exf, b + 4), b += 4 + l; 49840 } 49841 } 49842 if (col) d.set(co, b), b += col; 49843 return b; 49844 }; 49845 // write zip footer (end of central directory) 49846 var wzf = function(o, b, c, d, e) { 49847 wbytes(o, b, 0x6054B50); // skip disk 49848 wbytes(o, b + 8, c); 49849 wbytes(o, b + 10, c); 49850 wbytes(o, b + 12, d); 49851 wbytes(o, b + 16, e); 49852 }; 49853 /** 49854 * Synchronously creates a ZIP file. Prefer using `zip` for better performance 49855 * with more than one file. 49856 * @param data The directory structure for the ZIP archive 49857 * @param opts The main options, merged with per-file options 49858 * @returns The generated ZIP archive 49859 */ function zipSync(data, opts) { 49860 if (!opts) opts = {}; 49861 var r = {}; 49862 var files = []; 49863 fltn(data, '', r, opts); 49864 var o = 0; 49865 var tot = 0; 49866 for(var fn in r){ 49867 var _a = r[fn], file = _a[0], p = _a[1]; 49868 var compression = p.level == 0 ? 0 : 8; 49869 var f = strToU8(fn), s = f.length; 49870 var com = p.comment, m = com && strToU8(com), ms = m && m.length; 49871 var exl = exfl(p.extra); 49872 if (s > 65535) err(11); 49873 var d = compression ? deflateSync(file, p) : file, l = d.length; 49874 var c = crc(); 49875 c.p(file); 49876 files.push(mrg(p, { 49877 size: file.length, 49878 crc: c.d(), 49879 c: d, 49880 f: f, 49881 m: m, 49882 u: s != fn.length || m && com.length != ms, 49883 o: o, 49884 compression: compression 49885 })); 49886 o += 30 + s + exl + l; 49887 tot += 76 + 2 * (s + exl) + (ms || 0) + l; 49888 } 49889 var out = new u8(tot + 22), oe = o, cdl = tot - o; 49890 for(var i = 0; i < files.length; ++i){ 49891 var f = files[i]; 49892 wzh(out, f.o, f, f.f, f.u, f.c.length); 49893 var badd = 30 + f.f.length + exfl(f.extra); 49894 out.set(f.c, f.o + badd); 49895 wzh(out, o, f, f.f, f.u, f.c.length, f.o, f.m), o += 16 + badd + (f.m ? f.m.length : 0); 49896 } 49897 wzf(out, o, files.length, cdl, oe); 49898 return out; 49899 } 49900 49901 class USDZExporter { 49902 setTextureUtils(utils) { 49903 this.textureUtils = utils; 49904 } 49905 parse(scene, onDone, onError, options) { 49906 this.parseAsync(scene, options).then(onDone).catch(onError); 49907 } 49908 async parseAsync(scene, options = {}) { 49909 options = Object.assign({ 49910 ar: { 49911 anchoring: { 49912 type: 'plane' 49913 }, 49914 planeAnchoring: { 49915 alignment: 'horizontal' 49916 } 49917 }, 49918 includeAnchoringProperties: true, 49919 quickLookCompatible: false, 49920 maxTextureSize: 1024 49921 }, options); 49922 const files = {}; 49923 const modelFileName = 'model.usda'; 49924 // model file should be first in USDZ archive so we init it here 49925 files[modelFileName] = null; 49926 let output = buildHeader(); 49927 output += buildSceneStart(options); 49928 const materials = {}; 49929 const textures = {}; 49930 scene.traverseVisible((object)=>{ 49931 if (object.isMesh) { 49932 const geometry = object.geometry; 49933 const material = object.material; 49934 if (material.isMeshStandardMaterial) { 49935 const geometryFileName = 'geometries/Geometry_' + geometry.id + '.usda'; 49936 if (!(geometryFileName in files)) { 49937 const meshObject = buildMeshObject(geometry); 49938 files[geometryFileName] = buildUSDFileAsString(meshObject); 49939 } 49940 if (!(material.uuid in materials)) { 49941 materials[material.uuid] = material; 49942 } 49943 output += buildXform(object, geometry, material); 49944 } else { 49945 console.warn('THREE.USDZExporter: Unsupported material type (USDZ only supports MeshStandardMaterial)', object); 49946 } 49947 } else if (object.isCamera) { 49948 output += buildCamera(object); 49949 } 49950 }); 49951 output += buildSceneEnd(); 49952 output += buildMaterials(materials, textures, options.quickLookCompatible); 49953 files[modelFileName] = strToU8(output); 49954 output = null; 49955 for(const id in textures){ 49956 let texture = textures[id]; 49957 if (texture.isCompressedTexture === true) { 49958 if (this.textureUtils === null) { 49959 throw new Error('THREE.USDZExporter: setTextureUtils() must be called to process compressed textures.'); 49960 } else { 49961 texture = await this.textureUtils.decompress(texture); 49962 } 49963 } 49964 const canvas = imageToCanvas(texture.image, texture.flipY, options.maxTextureSize); 49965 const blob = await new Promise((resolve)=>canvas.toBlob(resolve, 'image/png', 1)); 49966 files[`textures/Texture_${id}.png`] = new Uint8Array(await blob.arrayBuffer()); 49967 } 49968 // 64 byte alignment 49969 // https://github.com/101arrowz/fflate/issues/39#issuecomment-777263109 49970 let offset = 0; 49971 for(const filename in files){ 49972 const file = files[filename]; 49973 const headerSize = 34 + filename.length; 49974 offset += headerSize; 49975 const offsetMod64 = offset & 63; 49976 if (offsetMod64 !== 4) { 49977 const padLength = 64 - offsetMod64; 49978 const padding = new Uint8Array(padLength); 49979 files[filename] = [ 49980 file, 49981 { 49982 extra: { 49983 12345: padding 49984 } 49985 } 49986 ]; 49987 } 49988 offset = file.length; 49989 } 49990 return zipSync(files, { 49991 level: 0 49992 }); 49993 } 49994 constructor(){ 49995 this.textureUtils = null; 49996 } 49997 } 49998 function imageToCanvas(image, flipY, maxTextureSize) { 49999 if (typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement || typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement || typeof OffscreenCanvas !== 'undefined' && image instanceof OffscreenCanvas || typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap) { 50000 const scale = maxTextureSize / Math.max(image.width, image.height); 50001 const canvas = document.createElement('canvas'); 50002 canvas.width = image.width * Math.min(1, scale); 50003 canvas.height = image.height * Math.min(1, scale); 50004 const context = canvas.getContext('2d'); 50005 // TODO: We should be able to do this in the UsdTransform2d? 50006 if (flipY === true) { 50007 context.translate(0, canvas.height); 50008 context.scale(1, -1); 50009 } 50010 context.drawImage(image, 0, 0, canvas.width, canvas.height); 50011 return canvas; 50012 } else { 50013 throw new Error('THREE.USDZExporter: No valid image data found. Unable to process texture.'); 50014 } 50015 } 50016 // 50017 const PRECISION = 7; 50018 function buildHeader() { 50019 return `#usda 1.0 50020( 50021 customLayerData = { 50022 string creator = "Three.js USDZExporter" 50023 } 50024 defaultPrim = "Root" 50025 metersPerUnit = 1 50026 upAxis = "Y" 50027) 50028 50029`; 50030 } 50031 function buildSceneStart(options) { 50032 const alignment = options.includeAnchoringProperties === true ? ` 50033 token preliminary:anchoring:type = "${options.ar.anchoring.type}" 50034 token preliminary:planeAnchoring:alignment = "${options.ar.planeAnchoring.alignment}" 50035 ` : ''; 50036 return `def Xform "Root" 50037{ 50038 def Scope "Scenes" ( 50039 kind = "sceneLibrary" 50040 ) 50041 { 50042 def Xform "Scene" ( 50043 customData = { 50044 bool preliminary_collidesWithEnvironment = 0 50045 string sceneName = "Scene" 50046 } 50047 sceneName = "Scene" 50048 ) 50049 {${alignment} 50050`; 50051 } 50052 function buildSceneEnd() { 50053 return ` 50054 } 50055 } 50056} 50057 50058`; 50059 } 50060 function buildUSDFileAsString(dataToInsert) { 50061 let output = buildHeader(); 50062 output += dataToInsert; 50063 return strToU8(output); 50064 } 50065 // Xform 50066 function buildXform(object, geometry, material) { 50067 const name = 'Object_' + object.id; 50068 const transform = buildMatrix(object.matrixWorld); 50069 if (object.matrixWorld.determinant() < 0) { 50070 console.warn('THREE.USDZExporter: USDZ does not support negative scales', object); 50071 } 50072 return `def Xform "${name}" (
50073 prepend references = @./geometries/Geometry_${geometry.id}.usda@</Geometry> 50074 prepend apiSchemas = ["MaterialBindingAPI"] 50075) 50076{ 50077 matrix4d xformOp:transform = ${transform} 50078 uniform token[] xformOpOrder = ["xformOp:transform"] 50079 50080 rel material:binding = </Materials/Material_${material.id}> 50081} 50082 50083`; 50084 } 50085 function buildMatrix(matrix) { 50086 const array = matrix.elements; 50087 return `( ${buildMatrixRow(array, 0)}, ${buildMatrixRow(array, 4)}, ${buildMatrixRow(array, 8)}, ${buildMatrixRow(array, 12)} )`; 50088 } 50089 function buildMatrixRow(array, offset) { 50090 return `(${array[offset + 0]}, ${array[offset + 1]}, ${array[offset + 2]}, ${array[offset + 3]})`; 50091 } 50092 // Mesh 50093 function buildMeshObject(geometry) { 50094 const mesh = buildMesh(geometry); 50095 return ` 50096def "Geometry" 50097{ 50098${mesh} 50099} 50100`; 50101 } 50102 function buildMesh(geometry) { 50103 const name = 'Geometry'; 50104 const attributes = geometry.attributes; 50105 const count = attributes.position.count; 50106 return ` 50107 def Mesh "${name}" 50108 { 50109 int[] faceVertexCounts = [${buildMeshVertexCount(geometry)}] 50110 int[] faceVertexIndices = [${buildMeshVertexIndices(geometry)}] 50111 normal3f[] normals = [${buildVector3Array(attributes.normal, count)}] ( 50112 interpolation = "vertex" 50113 ) 50114 point3f[] points = [${buildVector3Array(attributes.position, count)}
50114] 50115${buildPrimvars(attributes)} 50116 uniform token subdivisionScheme = "none" 50117 } 50118`; 50119 } 50120 function buildMeshVertexCount(geometry) { 50121 const count = geometry.index !== null ? geometry.index.count : geometry.attributes.position.count; 50122 return Array(count / 3).fill(3).join(', '); 50123 } 50124 function buildMeshVertexIndices(geometry) { 50125 const index = geometry.index; 50126 const array = []; 50127 if (index !== null) { 50128 for(let i = 0; i < index.count; i++){ 50129 array.push(index.getX(i)); 50130 } 50131 } else { 50132 const length = geometry.attributes.position.count; 50133 for(let i = 0; i < length; i++){ 50134 array.push(i); 50135 } 50136 } 50137 return array.join(', '); 50138 } 50139 function buildVector3Array(attribute, count) { 50140 if (attribute === undefined) { 50141 console.warn('USDZExporter: Normals missing.'); 50142 return Array(count).fill('(0, 0, 0)').join(', '); 50143 } 50144 const array = []; 50145 for(let i = 0; i < attribute.count; i++){ 50146 const x = attribute.getX(i); 50147 const y = attribute.getY(i); 50148 const z = attribute.getZ(i); 50149 array.push(`(${x.toPrecision(PRECISION)}, ${y.toPrecision(PRECISION)}, ${z.toPrecision(PRECISION)})`); 50150 } 50151 return array.join(', '); 50152 } 50153 function buildVector2Array(attribute) { 50154 const array = []; 50155 for(let i = 0; i < attribute.count; i++){ 50156 const x = attribute.getX(i); 50157 const y = attribute.getY(i); 50158 array.push(`(${x.toPrecision(PRECISION)}, ${1 - y.toPrecision(PRECISION)})`); 50159 } 50160 return array.join(', '); 50161 } 50162 function buildPrimvars(attributes) { 50163 let string = ''; 50164 for(let i = 0; i < 4; i++){ 50165 const id = i > 0 ? i : ''; 50166 const attribute = attributes['uv' + id]; 50167 if (attribute !== undefined) { 50168 string += ` 50169 texCoord2f[] primvars:st${id} = [${buildVector2Array(attribute)}] ( 50170 interpolation = "vertex" 50171 )`; 50172 } 50173 } 50174 // vertex colors 50175 const colorAttribute = attributes.color; 50176 if (colorAttribute !== undefined) { 50177 const count = colorAttribute.count; 50178 string += ` 50179 color3f[] primvars:displayColor = [${buildVector3Array(colorAttribute, count)}] ( 50180 interpolation = "vertex" 50181 )`; 50182 } 50183 return string; 50184 } 50185 // Materials 50186 function buildMaterials(materials, textures, quickLookCompatible = false) { 50187 const array = []; 50188 for(const uuid in materials){ 50189 const material = materials[uuid]; 50190 array.push(buildMaterial(material, textures, quickLookCompatible)); 50191 } 50192 return `def "Materials" 50193{ 50194${array.join('')} 50195} 50196 50197`; 50198 } 50199 function buildMaterial(material, textures, quickLookCompatible = false) { 50200 // https://graphics.pixar.com/usd/docs/UsdPreviewSurface-Proposal.html 50201 const pad = ' '; 50202 const inputs = []; 50203 const samplers = []; 50204 function buildTexture(texture, mapType, color) { 50205 const id = texture.source.id + '_' + texture.flipY; 50206 textures[id] = texture; 50207 const uv = texture.channel > 0 ? 'st' + texture.channel : 'st'; 50208 const WRAPPINGS = { 50209 1000: 'repeat', 50210 1001: 'clamp', 50211 1002: 'mirror' // MirroredRepeatWrapping 50212 }; 50213 const repeat = texture.repeat.clone(); 50214 const offset = texture.offset.clone(); 50215 const rotation = texture.rotation; 50216 // rotation is around the wrong point. after rotation we need to shift offset again so that we're rotating around the right spot 50217 const xRotationOffset = Math.sin(rotation); 50218 const yRotationOffset = Math.cos(rotation); 50219 // texture coordinates start in the opposite corner, need to correct 50220 offset.y = 1 - offset.y - repeat.y; 50221 // turns out QuickLook is buggy and interprets texture repeat inverted/applies operations in a different order. 50222 // Apple Feedback: FB10036297 and FB11442287 50223 if (quickLookCompatible) { 50224 // This is NOT correct yet in QuickLook, but comes close for a range of models. 50225 // It becomes more incorrect the bigger the offset is 50226 offset.x = offset.x / repeat.x; 50227 offset.y = offset.y / repeat.y; 50228 offset.x += xRotationOffset / repeat.x; 50229 offset.y += yRotationOffset - 1; 50230 } else { 50231 // results match glTF results exactly. verified correct in usdview. 50232 offset.x += xRotationOffset * repeat.x; 50233 offset.y += (1 - yRotationOffset) * repeat.y; 50234 } 50235 return ` 50236 def Shader "PrimvarReader_${mapType}" 50237 { 50238 uniform token info:id = "UsdPrimvarReader_float2" 50239 float2 inputs:fallback = (0.0, 0.0)
50240 token inputs:varname = "${uv}" 50241 float2 outputs:result 50242 } 50243 50244 def Shader "Transform2d_${mapType}" 50245 { 50246 uniform token info:id = "UsdTransform2d" 50247 token inputs:in.connect = </Materials/Material_${material.id}/PrimvarReader_${mapType}.outputs:result> 50248 float inputs:rotation = ${(rotation * (180 / Math.PI)).toFixed(PRECISION)} 50249 float2 inputs:scale = ${buildVector2(repeat)} 50250 float2 inputs:translation = ${buildVector2(offset)} 50251 float2 outputs:result 50252 } 50253 50254 def Shader "Texture_${texture.id}_${mapType}" 50255 { 50256 uniform token info:id = "UsdUVTexture" 50257 asset inputs:file = @textures/Texture_${id}.png@ 50258 float2 inputs:st.connect = </Materials/Material_${material.id}/Transform2d_${mapType}.outputs:result> 50259 ${color !== undefined ? 'float4 inputs:scale = ' + buildColor4(color) : ''} 50260 token inputs:sourceColorSpace = "${texture.colorSpace === NoColorSpace ? 'raw' : 'sRGB'}" 50261 token inputs:wrapS = "${WRAPPINGS[texture.wrapS]}" 50262 token inputs:wrapT = "${WRAPPINGS[texture.wrapT]}" 50263 float outputs:r 50264 float outputs:g 50265 float outputs:b 50266 float3 outputs:rgb 50267 ${material.transparent || material.alphaTest > 0.0 ? 'float outputs:a' : ''} 50268 }`; 50269 } 50270 if (material.side === DoubleSide) { 50271 console.warn('THREE.USDZExporter: USDZ does not support double sided materials', material); 50272 } 50273 if (material.map !== null) { 50274 inputs.push(`${pad}color3f inputs:diffuseColor.connect = </Materials/Material_${material.id}/Texture_${material.map.id}_diffuse.outputs:rgb>`); 50275 if (material.transparent) { 50276 inputs.push(`${pad}float inputs:opacity.connect = </Materials/Material_${material.id}/Texture_${material.map.id}_diffuse.outputs:a>`); 50277 } else if (material.alphaTest > 0.0) { 50278 inputs.push(`${pad}float inputs:opacity.connect = </Materials/Material_${material.id}/Texture_${material.map.id}_diffuse.outputs:a>`); 50279 inputs.push(`${pad}float inputs:opacityThreshold = ${material.alphaTest}`); 50280 } 50281 samplers.push(buildTexture(material.map, 'diffuse', material.color)); 50282 } else { 50283 inputs.push(`${pad}color3f inputs:diffuseColor = ${buildColor(material.color)}`); 50284 } 50285 if (material.emissiveMap !== null) { 50286 inputs.push(`${pad}color3f inputs:emissiveColor.connect = </Materials/Material_${material.id}/Texture_${material.emissiveMap.id}_emissive.outputs:rgb>`); 50287 samplers.push(buildTexture(material.emissiveMap, 'emissive', new Color(material.emissive.r * material.emissiveIntensity, material.emissive.g * material.emissiveIntensity, material.emissive.b * material.emissiveIntensity))); 50288 } else if (material.emissive.getHex() > 0) { 50289 inputs.push(`${pad}color3f inputs:emissiveColor = ${buildColor(material.emissive)}`); 50290 } 50291 if (material.normalMap !== null) { 50292 inputs.push(`${pad}normal3f inputs:normal.connect = </Materials/Material_${material.id}/Texture_${material.normalMap.id}_normal.outputs:rgb>`); 50293 samplers.push(buildTexture(material.normalMap, 'normal')); 50294 } 50295 if (material.aoMap !== null) { 50296 inputs.push(`${pad}float inputs:occlusion.connect = </Materials/Material_${material.id}/Texture_${material.aoMap.id}_occlusion.outputs:r>`); 50297 samplers.push(buildTexture(material.aoMap, 'occlusion', new Color(material.aoMapIntensity, material.aoMapIntensity, material.aoMapIntensity))); 50298 } 50299 if (material.roughnessMap !== null) { 50300 inputs.push(`${pad}float inputs:roughness.connect = </Materials/Material_${material.id}/Texture_${material.roughnessMap.id}_roughness.outputs:g>`); 50301 samplers.push(buildTexture(material.roughnessMap, 'roughness', new Color(material.roughness, material.roughness, material.roughness))); 50302 } else { 50303 inputs.push(`${pad}float inputs:roughness = ${material.roughness}`); 50304 } 50305 if (material.metalnessMap !== null) { 50306 inputs.push(`${pad}float inputs:metallic.connect = </Materials/Material_${material.id}/Texture_${material.metalnessMap.id}_metallic.outputs:b>`); 50307 samplers.push(buildTexture(material.metalnessMap, 'metallic', new Color(material.metalness, material.metalness, material.metalness))); 50308 } else { 50309 inputs.push(`${pad}float inputs:metallic = ${material.metalness}`); 50310 } 50311 if (material.alphaMap !== null) { 50312 inputs.push(`${pad}
50312float inputs:opacity.connect = </Materials/Material_${material.id}/Texture_${material.alphaMap.id}_opacity.outputs:r>`); 50313 inputs.push(`${pad}float inputs:opacityThreshold = 0.0001`); 50314 samplers.push(buildTexture(material.alphaMap, 'opacity')); 50315 } else { 50316 inputs.push(`${pad}float inputs:opacity = ${material.opacity}`); 50317 } 50318 if (material.isMeshPhysicalMaterial) { 50319 if (material.clearcoatMap !== null) { 50320 inputs.push(`${pad}float inputs:clearcoat.connect = </Materials/Material_${material.id}/Texture_${material.clearcoatMap.id}_clearcoat.outputs:r>`); 50321 samplers.push(buildTexture(material.clearcoatMap, 'clearcoat', new Color(material.clearcoat, material.clearcoat, material.clearcoat))); 50322 } else { 50323 inputs.push(`${pad}float inputs:clearcoat = ${material.clearcoat}`); 50324 } 50325 if (material.clearcoatRoughnessMap !== null) { 50326 inputs.push(`${pad}float inputs:clearcoatRoughness.connect = </Materials/Material_${material.id}/Texture_${material.clearcoatRoughnessMap.id}_clearcoatRoughness.outputs:g>`); 50327 samplers.push(buildTexture(material.clearcoatRoughnessMap, 'clearcoatRoughness', new Color(material.clearcoatRoughness, material.clearcoatRoughness, material.clearcoatRoughness))); 50328 } else { 50329 inputs.push(`${pad}float inputs:clearcoatRoughness = ${material.clearcoatRoughness}`); 50330 } 50331 inputs.push(`${pad}float inputs:ior = ${material.ior}`); 50332 } 50333 return ` 50334 def Material "Material_${material.id}" 50335 { 50336 def Shader "PreviewSurface" 50337 { 50338 uniform token info:id = "UsdPreviewSurface" 50339${inputs.join('\n')} 50340 int inputs:useSpecularWorkflow = 0 50341 token outputs:surface 50342 } 50343 50344 token outputs:surface.connect = </Materials/Material_${material.id}/PreviewSurface.outputs:surface> 50345 50346${samplers.join('\n')} 50347 50348 } 50349`; 50350 } 50351 function buildColor(color) { 50352 return `(${color.r}, ${color.g}, ${color.b})`; 50353 } 50354 function buildColor4(color) { 50355 return `(${color.r}, ${color.g}, ${color.b}, 1.0)`; 50356 } 50357 function buildVector2(vector) { 50358 return `(${vector.x}, ${vector.y})`; 50359 } 50360 function buildCamera(camera) { 50361 const name = camera.name ? camera.name : 'Camera_' + camera.id; 50362 const transform = buildMatrix(camera.matrixWorld); 50363 if (camera.matrixWorld.determinant() < 0) { 50364 console.warn('THREE.USDZExporter: USDZ does not support negative scales', camera); 50365 } 50366 if (camera.isOrthographicCamera) { 50367 return `def Camera "${name}" 50368 { 50369 matrix4d xformOp:transform = ${transform} 50370 uniform token[] xformOpOrder = ["xformOp:transform"] 50371 50372 float2 clippingRange = (${camera.near.toPrecision(PRECISION)}, ${camera.far.toPrecision(PRECISION)}) 50373 float horizontalAperture = ${((Math.abs(camera.left) + Math.abs(camera.right)) * 10).toPrecision(PRECISION)} 50374 float verticalAperture = ${((Math.abs(camera.top) + Math.abs(camera.bottom)) * 10).toPrecision(PRECISION)} 50375 token projection = "orthographic" 50376 } 50377 50378 `; 50379 } else { 50380 return `def Camera "${name}" 50381 { 50382 matrix4d xformOp:transform = ${transform} 50383 uniform token[] xformOpOrder = ["xformOp:transform"] 50384 50385 float2 clippingRange = (${camera.near.toPrecision(PRECISION)}, ${camera.far.toPrecision(PRECISION)}) 50386 float focalLength = ${camera.getFocalLength().toPrecision(PRECISION)} 50387 float focusDistance = ${camera.focus.toPrecision(PRECISION)} 50388 float horizontalAperture = ${camera.getFilmWidth().toPrecision(PRECISION)} 50389 token projection = "perspective" 50390 float verticalAperture = ${camera.getFilmHeight().toPrecision(PRECISION)} 50391 } 50392 50393 `; 50394 } 50395 } 50396 50397 const enumerationDeserializer = (allowedNames)=>(valueString)=>{ 50398 try { 50399 const expressions = parseExpressions(valueString); 50400 const names = (expressions.length ? expressions[0].terms : []).filter((valueNode)=>valueNode && valueNode.type === 'ident').map((valueNode)=>valueNode.value).filter((name)=>allowedNames.indexOf(name) > -1); 50401 return new Set(names); 50402 } catch (_error) {} 50403 return new Set(); 50404 }; 50405 50406 var __decorate$2 = undefined && undefined.__decorate || function(decorators, target, key, desc) { 50407 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
vendor: 11,770 bytes, lines 50408-50653
50408 for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 50409 return c > 3 && r && Object.defineProperty(target, key, r), r; 50410 }; 50411 let isWebXRBlocked = false; 50412 let isSceneViewerBlocked = false; 50413 const noArViewerSigil = '#model-viewer-no-ar-fallback'; 50414 const deserializeARModes = enumerationDeserializer([ 50415 'quick-look', 50416 'scene-viewer', 50417 'webxr', 50418 'none' 50419 ]); 50420 const DEFAULT_AR_MODES = 'webxr scene-viewer quick-look'; 50421 const ARMode = { 50422 QUICK_LOOK: 'quick-look', 50423 SCENE_VIEWER: 'scene-viewer', 50424 WEBXR: 'webxr', 50425 NONE: 'none' 50426 }; 50427 const $arButtonContainer = Symbol('arButtonContainer'); 50428 const $enterARWithWebXR = Symbol('enterARWithWebXR'); 50429 const $openSceneViewer = Symbol('openSceneViewer'); 50430 const $openIOSARQuickLook = Symbol('openIOSARQuickLook'); 50431 const $canActivateAR = Symbol('canActivateAR'); 50432 const $arMode = Symbol('arMode'); 50433 const $arModes = Symbol('arModes'); 50434 const $arAnchor = Symbol('arAnchor'); 50435 const $preload = Symbol('preload'); 50436 const $onARButtonContainerClick = Symbol('onARButtonContainerClick'); 50437 const $onARStatus = Symbol('onARStatus'); 50438 const $onARTracking = Symbol('onARTracking'); 50439 const $onARTap = Symbol('onARTap'); 50440 const $selectARMode = Symbol('selectARMode'); 50441 const $triggerLoad = Symbol('triggerLoad'); 50442 const ARMixin = (ModelViewerElement)=>{ 50443 var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; 50444 class ARModelViewerElement extends ModelViewerElement { 50445 get canActivateAR() { 50446 return this[$arMode] !== ARMode.NONE; 50447 } 50448 connectedCallback() { 50449 super.connectedCallback(); 50450 this[$renderer].arRenderer.addEventListener('status', this[$onARStatus]); 50451 this.setAttribute('ar-status', ARStatus.NOT_PRESENTING); 50452 this[$renderer].arRenderer.addEventListener('tracking', this[$onARTracking]); 50453 this[$arAnchor].addEventListener('message', this[$onARTap]); 50454 } 50455 disconnectedCallback() { 50456 super.disconnectedCallback(); 50457 this[$renderer].arRenderer.removeEventListener('status', this[$onARStatus]); 50458 this[$renderer].arRenderer.removeEventListener('tracking', this[$onARTracking]); 50459 this[$arAnchor].removeEventListener('message', this[$onARTap]); 50460 } 50461 update(changedProperties) { 50462 super.update(changedProperties); 50463 if (changedProperties.has('arScale')) { 50464 this[$scene].canScale = this.arScale !== 'fixed'; 50465 } 50466 if (changedProperties.has('arPlacement')) { 50467 this[$scene].updateShadow(); 50468 this[$needsRender](); 50469 } 50470 if (changedProperties.has('arModes')) { 50471 this[$arModes] = deserializeARModes(this.arModes); 50472 } 50473 if (changedProperties.has('ar') || changedProperties.has('arModes') || changedProperties.has('src') || changedProperties.has('iosSrc') || changedProperties.has('arUsdzMaxTextureSize')) { 50474 this[$selectARMode](); 50475 } 50476 } 50477 async activateAR() { 50478 switch(this[$arMode]){ 50479 case ARMode.QUICK_LOOK: 50480 await this[$openIOSARQuickLook](); 50481 break; 50482 case ARMode.WEBXR: 50483 await this[$enterARWithWebXR](); 50484 break; 50485 case ARMode.SCENE_VIEWER: 50486 this[$openSceneViewer](); 50487 break; 50488 default: 50489 console.warn('No AR Mode can be activated. This is probably due to missing \ 50490configuration or device capabilities'); 50491 break; 50492 } 50493 } 50494 async [(_a = $canActivateAR, _b = $arButtonContainer, _c = $arAnchor, _d = $arModes, _e = $arMode, _f = $preload, _g = $onARButtonContainerClick, _h = $onARStatus, _j = $onARTracking, _k = $onARTap, $selectARMode)]() { 50495 var _l; 50496 let arMode = ARMode.NONE; 50497 if (this.ar) { 50498 if (this.src != null) { 50499 for (const value of this[$arModes]){ 50500 if (value === 'webxr' && IS_WEBXR_AR_CANDIDATE && !isWebXRBlocked && await this[$renderer].arRenderer.supportsPresentation()) { 50501 arMode = ARMode.WEBXR; 50502 break; 50503 } 50504 if (value === 'scene-viewer' && !isSceneViewerBlocked && (IS_SCENEVIEWER_CANDIDATE || navigator.userAgentData && navigator.userAgentData.getHighEntropyValues && ((_l = (await navigator.userAgentData.getHighEntropyValues([ 50505 'formFactor' 50506 ])).formFactor) === null || _l === void 0 ? void 0 : _l.includes('XR')))) { 50507 arMode = ARMode.SCENE_VIEWER; 50508 break; 50509 } 50510 if (value === 'quick-look' && IS_AR_QUICKLOOK_CANDIDATE) { 50511 arMode = ARMode.QUICK_LOOK; 50512 break; 50513 } 50514 } 50515 } 50516 if (arMode === ARMode.NONE && this.iosSrc != null && IS_AR_QUICKLOOK_CANDIDATE) { 50517 arMode = ARMode.QUICK_LOOK; 50518 } 50519 } 50520 if (arMode !== ARMode.NONE) { 50521 this[$arButtonContainer].classList.add('enabled'); 50522 this[$arButtonContainer].addEventListener('click', this[$onARButtonContainerClick]); 50523 } else if (this[$arButtonContainer].classList.contains('enabled')) { 50524 this[$arButtonContainer].removeEventListener('click', this[$onARButtonContainerClick]); 50525 this[$arButtonContainer].classList.remove('enabled'); 50526 const status = ARStatus.FAILED; 50527 this.setAttribute('ar-status', status); 50528 this.dispatchEvent(new CustomEvent('ar-status', { 50529 detail: { 50530 status 50531 } 50532 })); 50533 } 50534 this[$arMode] = arMode; 50535 } 50536 async [$enterARWithWebXR]() { 50537 console.log('Attempting to present in AR with WebXR...'); 50538 await this[$triggerLoad](); 50539 try { 50540 this[$arButtonContainer].removeEventListener('click', this[$onARButtonContainerClick]); 50541 const { arRenderer } = this[$renderer]; 50542 arRenderer.placeOnWall = this.arPlacement === 'wall'; 50543 await arRenderer.present(this[$scene], this.xrEnvironment); 50544 } catch (error) { 50545 console.warn('Error while trying to present in AR with WebXR'); 50546 console.error(error); 50547 await this[$renderer].arRenderer.stopPresenting(); 50548 isWebXRBlocked = true; 50549 console.warn('Falling back to next ar-mode'); 50550 await this[$selectARMode](); 50551 this.activateAR(); 50552 } finally{ 50553 this[$selectARMode](); 50554 } 50555 } 50556 async [$triggerLoad]() { 50557 if (!this.loaded) { 50558 this[$preload] = true; 50559 this[$updateSource](); 50560 await waitForEvent(this, 'load'); 50561 this[$preload] = false; 50562 } 50563 } 50564 [$shouldAttemptPreload]() { 50565 return super[$shouldAttemptPreload]() || this[$preload]; 50566 } 50567 [$openSceneViewer]() { 50568 const location = self.location.toString(); 50569 const locationUrl = new URL(location); 50570 const modelUrl = new URL(this.src, location); 50571 if (modelUrl.hash) modelUrl.hash = ''; 50572 const params = new URLSearchParams(modelUrl.search); 50573 locationUrl.hash = noArViewerSigil; 50574 params.set('mode', 'ar_preferred'); 50575 if (!params.has('disable_occlusion')) { 50576 params.set('disable_occlusion', 'true'); 50577 } 50578 if (this.arScale === 'fixed') { 50579 params.set('resizable', 'false'); 50580 } 50581 if (this.arPlacement === 'wall') { 50582 params.set('enable_vertical_placement', 'true'); 50583 } 50584 if (params.has('sound')) { 50585 const soundUrl = new URL(params.get('sound'), location); 50586 params.set('sound', soundUrl.toString()); 50587 } 50588 if (params.has('link')) { 50589 const linkUrl = new URL(params.get('link'), location); 50590 params.set('link', linkUrl.toString()); 50591 } 50592 const intent = `intent://arvr.google.com/scene-viewer/1.2?${params.toString() + '&file=' + encodeURIComponent(modelUrl.toString())}#Intent;scheme=https;package=com.google.android.googlequicksearchbox;action=android.intent.action.VIEW;S.browser_fallback_url=${encodeURIComponent(locationUrl.toString())};end;`; 50593 const undoHashChange = ()=>{ 50594 if (self.location.hash === noArViewerSigil) { 50595 isSceneViewerBlocked = true; 50596 self.history.back(); 50597 console.warn('Error while trying to present in AR with Scene Viewer'); 50598 console.warn('Falling back to next ar-mode'); 50599 this[$selectARMode](); 50600 } 50601 }; 50602 self.addEventListener('hashchange', undoHashChange, { 50603 once: true 50604 }); 50605 this[$arAnchor].setAttribute('href', intent); 50606 console.log('Attempting to present in AR with Scene Viewer...'); 50607 this[$arAnchor].click(); 50608 } 50609 async [$openIOSARQuickLook]() { 50610 const generateUsdz = !this.iosSrc; 50611 this[$arButtonContainer].classList.remove('enabled'); 50612 const objectURL = generateUsdz ? await this.prepareUSDZ() : this.iosSrc; 50613 const modelUrl = new URL(objectURL, self.location.toString()); 50614 if (generateUsdz) { 50615 const location = self.location.toString(); 50616 const locationUrl = new URL(location); 50617 const srcUrl = new URL(this.src, locationUrl); 50618 if (srcUrl.hash) { 50619 modelUrl.hash = srcUrl.hash; 50620 } 50621 } 50622 if (this.arScale === 'fixed') { 50623 if (modelUrl.hash) { 50624 modelUrl.hash += '&'; 50625 } 50626 modelUrl.hash += 'allowsContentScaling=0'; 50627 } 50628 const anchor = this[$arAnchor]; 50629 anchor.setAttribute('rel', 'ar'); 50630 const img = document.createElement('img'); 50631 anchor.appendChild(img); 50632 anchor.setAttribute('href', modelUrl.toString()); 50633 if (generateUsdz) { 50634 anchor.setAttribute('download', 'model.usdz'); 50635 } 50636 anchor.style.display = 'none'; 50637 if (!anchor.isConnected) this.shadowRoot.appendChild(anchor); 50638 console.log('Attempting to present in AR with Quick Look...'); 50639 anchor.click(); 50640 anchor.removeChild(img); 50641 if (generateUsdz) { 50642 URL.revokeObjectURL(objectURL); 50643 } 50644 this[$arButtonContainer].classList.add('enabled'); 50645 } 50646 async prepareUSDZ() { 50647 const updateSourceProgress = this[$progressTracker].beginActivity('usdz-conversion'); 50648 await this[$triggerLoad](); 50649 const { model, shadow, target } = this[$scene]; 50650 if (model == null) { 50651 return ''; 50652 } 50653 let visible = false;
vendor: 9,616 bytes, lines 50654-50880
50654 if (shadow != null) { 50655 visible = shadow.visible; 50656 shadow.visible = false; 50657 } 50658 updateSourceProgress(0.2); 50659 const exporter = new USDZExporter(); 50660 target.remove(model); 50661 model.position.copy(target.position); 50662 model.updateWorldMatrix(false, true); 50663 const arraybuffer = await exporter.parseAsync(model, { 50664 maxTextureSize: isNaN(this.arUsdzMaxTextureSize) ? Infinity : Math.max(parseInt(this.arUsdzMaxTextureSize), 16) 50665 }); 50666 model.position.set(0, 0, 0); 50667 target.add(model); 50668 const blob = new Blob([ 50669 arraybuffer 50670 ], { 50671 type: 'model/vnd.usdz+zip' 50672 }); 50673 const url = URL.createObjectURL(blob); 50674 updateSourceProgress(1); 50675 if (shadow != null) { 50676 shadow.visible = visible; 50677 } 50678 return url; 50679 } 50680 constructor(){ 50681 super(...arguments); 50682 this.ar = false; 50683 this.arScale = 'auto'; 50684 this.arUsdzMaxTextureSize = 'auto'; 50685 this.arPlacement = 'floor'; 50686 this.arModes = DEFAULT_AR_MODES; 50687 this.iosSrc = null; 50688 this.xrEnvironment = false; 50689 this[_a] = false; 50690 this[_b] = this.shadowRoot.querySelector('.ar-button'); 50691 this[_c] = document.createElement('a'); 50692 this[_d] = new Set(); 50693 this[_e] = ARMode.NONE; 50694 this[_f] = false; 50695 this[_g] = (event)=>{ 50696 event.preventDefault(); 50697 this.activateAR(); 50698 }; 50699 this[_h] = ({ status })=>{ 50700 if (status === ARStatus.NOT_PRESENTING || this[$renderer].arRenderer.presentedScene === this[$scene]) { 50701 this.setAttribute('ar-status', status); 50702 this.dispatchEvent(new CustomEvent('ar-status', { 50703 detail: { 50704 status 50705 } 50706 })); 50707 if (status === ARStatus.NOT_PRESENTING) { 50708 this.removeAttribute('ar-tracking'); 50709 } else if (status === ARStatus.SESSION_STARTED) { 50710 this.setAttribute('ar-tracking', ARTracking.TRACKING); 50711 } 50712 } 50713 }; 50714 this[_j] = ({ status })=>{ 50715 this.setAttribute('ar-tracking', status); 50716 this.dispatchEvent(new CustomEvent('ar-tracking', { 50717 detail: { 50718 status 50719 } 50720 })); 50721 }; 50722 this[_k] = (event)=>{ 50723 if (event.data == '_apple_ar_quicklook_button_tapped') { 50724 this.dispatchEvent(new CustomEvent('quick-look-button-tapped')); 50725 } 50726 }; 50727 } 50728 } 50729 __decorate$2([ 50730 n$2({ 50731 type: Boolean, 50732 attribute: 'ar' 50733 }) 50734 ], ARModelViewerElement.prototype, "ar", void 0); 50735 __decorate$2([ 50736 n$2({ 50737 type: String, 50738 attribute: 'ar-scale' 50739 }) 50740 ], ARModelViewerElement.prototype, "arScale", void 0); 50741 __decorate$2([ 50742 n$2({ 50743 type: String, 50744 attribute: 'ar-usdz-max-texture-size' 50745 }) 50746 ], ARModelViewerElement.prototype, "arUsdzMaxTextureSize", void 0); 50747 __decorate$2([ 50748 n$2({ 50749 type: String, 50750 attribute: 'ar-placement' 50751 }) 50752 ], ARModelViewerElement.prototype, "arPlacement", void 0); 50753 __decorate$2([ 50754 n$2({ 50755 type: String, 50756 attribute: 'ar-modes' 50757 }) 50758 ], ARModelViewerElement.prototype, "arModes", void 0); 50759 __decorate$2([ 50760 n$2({ 50761 type: String, 50762 attribute: 'ios-src' 50763 }) 50764 ], ARModelViewerElement.prototype, "iosSrc", void 0); 50765 __decorate$2([ 50766 n$2({ 50767 type: Boolean, 50768 attribute: 'xr-environment' 50769 }) 50770 ], ARModelViewerElement.prototype, "xrEnvironment", void 0); 50771 return ARModelViewerElement; 50772 }; 50773 50774 var __decorate$1 = undefined && undefined.__decorate || function(decorators, target, key, desc) { 50775 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 50776 for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 50777 return c > 3 && r && Object.defineProperty(target, key, r), r; 50778 }; 50779 const PROGRESS_BAR_UPDATE_THRESHOLD = 100; 50780 const DEFAULT_DRACO_DECODER_LOCATION = (window.explorexrPluginUrl || '/wp-content/plugins/explorexr/') + 'assets/vendor/draco/'; 50781 const DEFAULT_KTX2_TRANSCODER_LOCATION = (window.explorexrPluginUrl || '/wp-content/plugins/explorexr/') + 'assets/vendor/basis-universal/'; 50782 const DEFAULT_LOTTIE_LOADER_LOCATION = (window.explorexrPluginUrl || '/wp-content/plugins/explorexr/') + 'assets/vendor/three/LottieLoader.js'; 50783 const RevealStrategy = { 50784 AUTO: 'auto'}; 50785 const LoadingStrategy = { 50786 AUTO: 'auto', 50787 EAGER: 'eager' 50788 }; 50789 const $defaultProgressBarElement = Symbol('defaultProgressBarElement'); 50790 const $posterContainerElement = Symbol('posterContainerElement'); 50791 const $defaultPosterElement = Symbol('defaultPosterElement'); 50792 const $shouldDismissPoster = Symbol('shouldDismissPoster'); 50793 const $hidePoster = Symbol('hidePoster'); 50794 const $modelIsRevealed = Symbol('modelIsRevealed'); 50795 const $updateProgressBar = Symbol('updateProgressBar'); 50796 const $ariaLabelCallToAction = Symbol('ariaLabelCallToAction'); 50797 const $onProgress = Symbol('onProgress'); 50798 const LoadingMixin = (ModelViewerElement)=>{ 50799 var _a, _b, _c, _d, _e, _f, _g, _h; 50800 class LoadingModelViewerElement extends ModelViewerElement { 50801 static set dracoDecoderLocation(value) { 50802 CachingGLTFLoader.setDRACODecoderLocation(value); 50803 } 50804 static get dracoDecoderLocation() { 50805 return CachingGLTFLoader.getDRACODecoderLocation(); 50806 } 50807 static set ktx2TranscoderLocation(value) { 50808 CachingGLTFLoader.setKTX2TranscoderLocation(value); 50809 } 50810 static get ktx2TranscoderLocation() { 50811 return CachingGLTFLoader.getKTX2TranscoderLocation(); 50812 } 50813 static set meshoptDecoderLocation(value) { 50814 CachingGLTFLoader.setMeshoptDecoderLocation(value); 50815 } 50816 static get meshoptDecoderLocation() { 50817 return CachingGLTFLoader.getMeshoptDecoderLocation(); 50818 } 50819 static set lottieLoaderLocation(value) { 50820 Renderer.singleton.textureUtils.lottieLoaderUrl = value; 50821 } 50822 static get lottieLoaderLocation() { 50823 return Renderer.singleton.textureUtils.lottieLoaderUrl; 50824 } 50825 static mapURLs(callback) { 50826 Renderer.singleton.loader[$loader].manager.setURLModifier(callback); 50827 } 50828 dismissPoster() { 50829 if (this.loaded) { 50830 this[$hidePoster](); 50831 } else { 50832 this[$shouldDismissPoster] = true; 50833 this[$updateSource](); 50834 } 50835 } 50836 showPoster() { 50837 const posterContainerElement = this[$posterContainerElement]; 50838 if (posterContainerElement.classList.contains('show')) { 50839 return; 50840 } 50841 posterContainerElement.classList.add('show'); 50842 this[$userInputElement].classList.remove('show'); 50843 const defaultPosterElement = this[$defaultPosterElement]; 50844 defaultPosterElement.removeAttribute('tabindex'); 50845 defaultPosterElement.removeAttribute('aria-hidden'); 50846 const oldVisibility = this.modelIsVisible; 50847 this[$modelIsRevealed] = false; 50848 this[$announceModelVisibility](oldVisibility); 50849 } 50850 getDimensions() { 50851 return toVector3D(this[$scene].size); 50852 } 50853 getBoundingBoxCenter() { 50854 return toVector3D(this[$scene].boundingBox.getCenter(new Vector3())); 50855 } 50856 connectedCallback() { 50857 super.connectedCallback(); 50858 if (!this.loaded) { 50859 this.showPoster(); 50860 } 50861 this[$progressTracker].addEventListener('progress', this[$onProgress]); 50862 } 50863 disconnectedCallback() { 50864 super.disconnectedCallback(); 50865 this[$progressTracker].removeEventListener('progress', this[$onProgress]); 50866 } 50867 async updated(changedProperties) { 50868 super.updated(changedProperties); 50869 if (changedProperties.has('poster') && this.poster != null) { 50870 this[$defaultPosterElement].style.backgroundImage = `url(${this.poster})`; 50871 } 50872 if (changedProperties.has('alt')) { 50873 this[$defaultPosterElement].setAttribute('aria-label', this[$altDefaulted]); 50874 } 50875 if (changedProperties.has('reveal') || changedProperties.has('loading')) { 50876 this[$updateSource](); 50877 } 50878 } 50879 [(_a = $modelIsRevealed, _b = $shouldDismissPoster, _c = $posterContainerElement, _d = $defaultPosterElement, _e = $defaultProgressBarElement, _f = $ariaLabelCallToAction, _g = $updateProgressBar, _h = $onProgress, $shouldAttemptPreload)]() { 50880 return !!this.src && (this[$shouldDismissPoster] || this.loading === LoadingStrategy.EAGE
vendor: 8,863 bytes, lines 50880-51086
50880R || this.reveal === RevealStrategy.AUTO && this[$isElementInViewport]); 50881 } 50882 [$hidePoster]() { 50883 this[$shouldDismissPoster] = false; 50884 const posterContainerElement = this[$posterContainerElement]; 50885 if (!posterContainerElement.classList.contains('show')) { 50886 return; 50887 } 50888 posterContainerElement.classList.remove('show'); 50889 this[$userInputElement].classList.add('show'); 50890 const oldVisibility = this.modelIsVisible; 50891 this[$modelIsRevealed] = true; 50892 this[$announceModelVisibility](oldVisibility); 50893 const root = this.getRootNode(); 50894 if (root && root.activeElement === this) { 50895 this[$userInputElement].focus(); 50896 } 50897 const defaultPosterElement = this[$defaultPosterElement]; 50898 defaultPosterElement.setAttribute('aria-hidden', 'true'); 50899 defaultPosterElement.tabIndex = -1; 50900 this.dispatchEvent(new CustomEvent('poster-dismissed')); 50901 } 50902 [$getModelIsVisible]() { 50903 return super[$getModelIsVisible]() && this[$modelIsRevealed]; 50904 } 50905 constructor(...args){ 50906 super(...args); 50907 this.poster = null; 50908 this.reveal = RevealStrategy.AUTO; 50909 this.loading = LoadingStrategy.AUTO; 50910 this[_a] = false; 50911 this[_b] = false; 50912 this[_c] = this.shadowRoot.querySelector('.slot.poster'); 50913 this[_d] = this.shadowRoot.querySelector('#default-poster'); 50914 this[_e] = this.shadowRoot.querySelector('#default-progress-bar > .bar'); 50915 this[_f] = this[$defaultPosterElement].getAttribute('aria-label'); 50916 this[_g] = throttle((progress)=>{ 50917 const parentNode = this[$defaultProgressBarElement].parentNode; 50918 requestAnimationFrame(()=>{ 50919 this[$defaultProgressBarElement].style.transform = `scaleX(${progress})`; 50920 if (progress === 0) { 50921 parentNode.removeChild(this[$defaultProgressBarElement]); 50922 parentNode.appendChild(this[$defaultProgressBarElement]); 50923 } 50924 this[$defaultProgressBarElement].classList.toggle('hide', progress === 1.0); 50925 }); 50926 }, PROGRESS_BAR_UPDATE_THRESHOLD); 50927 this[_h] = (event)=>{ 50928 const progress = event.detail.totalProgress; 50929 const reason = event.detail.reason; 50930 if (progress === 1.0) { 50931 this[$updateProgressBar].flush(); 50932 if (this.loaded && (this[$shouldDismissPoster] || this.reveal === RevealStrategy.AUTO)) { 50933 this[$hidePoster](); 50934 } 50935 } 50936 this[$updateProgressBar](progress); 50937 this.dispatchEvent(new CustomEvent('progress', { 50938 detail: { 50939 totalProgress: progress, 50940 reason 50941 } 50942 })); 50943 }; 50944 const ModelViewerElement = self.ModelViewerElement || {}; 50945 const dracoDecoderLocation = ModelViewerElement.dracoDecoderLocation || DEFAULT_DRACO_DECODER_LOCATION; 50946 CachingGLTFLoader.setDRACODecoderLocation(dracoDecoderLocation); 50947 const ktx2TranscoderLocation = ModelViewerElement.ktx2TranscoderLocation || DEFAULT_KTX2_TRANSCODER_LOCATION; 50948 CachingGLTFLoader.setKTX2TranscoderLocation(ktx2TranscoderLocation); 50949 if (ModelViewerElement.meshoptDecoderLocation) { 50950 CachingGLTFLoader.setMeshoptDecoderLocation(ModelViewerElement.meshoptDecoderLocation); 50951 } 50952 const lottieLoaderLocation = ModelViewerElement.lottieLoaderLocation || DEFAULT_LOTTIE_LOADER_LOCATION; 50953 Renderer.singleton.textureUtils.lottieLoaderUrl = lottieLoaderLocation; 50954 } 50955 } 50956 __decorate$1([ 50957 n$2({ 50958 type: String 50959 }) 50960 ], LoadingModelViewerElement.prototype, "poster", void 0); 50961 __decorate$1([ 50962 n$2({ 50963 type: String 50964 }) 50965 ], LoadingModelViewerElement.prototype, "reveal", void 0); 50966 __decorate$1([ 50967 n$2({ 50968 type: String 50969 }) 50970 ], LoadingModelViewerElement.prototype, "loading", void 0); 50971 return LoadingModelViewerElement; 50972 }; 50973 50974 var __decorate = undefined && undefined.__decorate || function(decorators, target, key, desc) { 50975 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 50976 for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 50977 return c > 3 && r && Object.defineProperty(target, key, r), r; 50978 }; 50979 const DEFAULT_ROTATION_SPEED = Math.PI / 32; 50980 const AUTO_ROTATE_DELAY_DEFAULT = 3000; 50981 const rotationRateIntrinsics = { 50982 basis: [ 50983 degreesToRadians(numberNode(DEFAULT_ROTATION_SPEED, 'rad')) 50984 ], 50985 keywords: { 50986 auto: [ 50987 null 50988 ] 50989 } 50990 }; 50991 const $autoRotateStartTime = Symbol('autoRotateStartTime'); 50992 const $radiansPerSecond = Symbol('radiansPerSecond'); 50993 const $syncRotationRate = Symbol('syncRotationRate'); 50994 const $onCameraChange = Symbol('onCameraChange'); 50995 const StagingMixin = (ModelViewerElement)=>{ 50996 var _a, _b, _c; 50997 class StagingModelViewerElement extends ModelViewerElement { 50998 connectedCallback() { 50999 super.connectedCallback(); 51000 this.addEventListener('camera-change', this[$onCameraChange]); 51001 this[$autoRotateStartTime] = performance.now(); 51002 } 51003 disconnectedCallback() { 51004 super.disconnectedCallback(); 51005 this.removeEventListener('camera-change', this[$onCameraChange]); 51006 this[$autoRotateStartTime] = performance.now(); 51007 } 51008 updated(changedProperties) { 51009 super.updated(changedProperties); 51010 if (changedProperties.has('autoRotate')) { 51011 this[$autoRotateStartTime] = performance.now(); 51012 } 51013 } 51014 [(_a = $autoRotateStartTime, _b = $radiansPerSecond, $syncRotationRate)](style) { 51015 this[$radiansPerSecond] = style[0]; 51016 } 51017 [$tick](time, delta) { 51018 super[$tick](time, delta); 51019 if (!this.autoRotate || !this[$getModelIsVisible]() || this[$renderer].isPresenting) { 51020 return; 51021 } 51022 const rotationDelta = Math.min(delta, time - this[$autoRotateStartTime] - this.autoRotateDelay); 51023 if (rotationDelta > 0) { 51024 this[$scene].yaw = this.turntableRotation + this[$radiansPerSecond] * rotationDelta * 0.001; 51025 } 51026 } 51027 get turntableRotation() { 51028 return this[$scene].yaw; 51029 } 51030 resetTurntableRotation(theta = 0) { 51031 this[$scene].yaw = theta; 51032 } 51033 constructor(){ 51034 super(...arguments); 51035 this.autoRotate = false; 51036 this.autoRotateDelay = AUTO_ROTATE_DELAY_DEFAULT; 51037 this.rotationPerSecond = 'auto'; 51038 this[_a] = performance.now(); 51039 this[_b] = 0; 51040 this[_c] = (event)=>{ 51041 if (!this.autoRotate) { 51042 return; 51043 } 51044 if (event.detail.source === 'user-interaction') { 51045 this[$autoRotateStartTime] = performance.now(); 51046 } 51047 }; 51048 } 51049 } 51050 _c = $onCameraChange; 51051 __decorate([ 51052 n$2({ 51053 type: Boolean, 51054 attribute: 'auto-rotate' 51055 }) 51056 ], StagingModelViewerElement.prototype, "autoRotate", void 0); 51057 __decorate([ 51058 n$2({ 51059 type: Number, 51060 attribute: 'auto-rotate-delay' 51061 }) 51062 ], StagingModelViewerElement.prototype, "autoRotateDelay", void 0); 51063 __decorate([ 51064 style({ 51065 intrinsics: rotationRateIntrinsics, 51066 updateHandler: $syncRotationRate 51067 }), 51068 n$2({ 51069 type: String, 51070 attribute: 'rotation-per-second' 51071 }) 51072 ], StagingModelViewerElement.prototype, "rotationPerSecond", void 0); 51073 return StagingModelViewerElement; 51074 }; 51075 51076 const ModelViewerElement = AnnotationMixin(SceneGraphMixin(StagingMixin(EnvironmentMixin(ControlsMixin(ARMixin(LoadingMixin(AnimationMixin(ModelViewerElementBase)))))))); 51077 customElements.define('model-viewer', ModelViewerElement); 51078 51079 exports.CanvasTexture = CanvasTexture; 51080 exports.FileLoader = FileLoader; 51081 exports.Loader = Loader; 51082 exports.ModelViewerElement = ModelViewerElement; 51083 exports.NearestFilter = NearestFilter; 51084 51085})); 51086//# sourceMappingURL=model-viewer-umd.js.map
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.