1/** 2 * Prepares safe url 3 * @param string str url to prepare 4 * @returns string prepared URL 5 */ 6const globe_ut_prepareURL = function (str) { 7 8 if (typeof str !== "string") { 9 return str; 10 } 11 12 // parse html entities 13 str = str.replace(/&/gi, '&'); 14 str.replace(/&#(\d+);/g, function (match, dec) { 15 return String.fromCharCode(dec); 16 }); 17 18 // check if allowed url 19 var url, protocols; 20 try { 21 url = new URL(str); 22 } catch (_) { 23 url = false; 24 } 25 26 // check if valid url. If string it might be a anchor or relative path, so keep going 27 if (url) { 28 // acepted protocols 29 protocols = [null, "http:", "https:", "mailto:", "tel:"]; 30 if (!protocols.includes(url.protocol)) { 31 console.log('URL protocol not allowed'); 32 return ''; 33 } 34 } 35 36 return str; 37 38}; 39 40/** Prepare data to be used. Set defaults and other operations */ 41const globe_ut_prepareData = function ( data ) { 42 43 if ( ! data.hasOwnProperty( 'dotLabels' ) || ! data.dotLabels ) { 44 data['dotlabels'] = []; 45 } 46 if ( ! data.hasOwnProperty( 'points' ) || ! data.points ) { 47 data['points'] = []; 48 } 49 50 // set preview defaults 51 let defaults = { 52 'showGraticules': false, 53 'backgroundColor': 'transparent', 54 'atmosphere': { 55 'enabled': false, 56 'atmosphereColor': null, 57 'atmosphereAltitude': null 58 }, 59 'globeImage': 'earth-day.jpg' 60 }; 61 62 // merge data with defaults 63 if ( Object.keys(data).length === 0 || data.emptyPreview ) { 64 Object.assign(data, defaults); 65 } 66 67 // set point of view 68 data.pointOfView = { 69 lat: 0, 70 lng: 0, 71 altitude: 1.5 72 }; 73 74 if ( ! data.centerCoordinates ) { 75 data.centerCoordinates = { 76 latitude: 0, 77 lat: 0, 78 longitude: 0, 79 lng: 0 80 }; 81 } 82 if (data.centerCoordinates) { 83 let altitude = typeof data.altitudeOptions !== 'undefined' ? data.altitudeOptions.altitude : data.altitude; 84 data.pointOfView.lat = globe_ut_float(data.centerCoordinates.latitude); 85 data.pointOfView.lng = globe_ut_float(data.centerCoordinates.longitude); 86 const floatAltitude = globe_ut_float(altitude); 87 data.pointOfView.altitude = (altitude !== '' && typeof altitude !== 'undefined') ? floatAltitude : 1.7; 88 } 89 90 return data; 91}; 92 93const globe_ut_prepareProData = function ( data ) { 94 95 if ( ! data.hasOwnProperty( 'arcLines' ) || ! data.arcLines ) { 96 data['arcLines'] = []; 97 } 98 if ( ! data.hasOwnProperty( 'regions' ) || ! data.arcLines ) { 99 data['regions'] = []; 100 } 101 if ( ! data.hasOwnProperty( 'html' ) || ! data.html ) { 102 data['html'] = []; 103 } 104 105 return data; 106}; 107 108 109const globe_ut_setupData = function ( data, dataTypes ) { 110 111 data.centerCoordinates.lat = parseFloat( data.centerCoordinates.lat ); 112 data.centerCoordinates.lng = parseFloat( data.centerCoordinates.lng ); 113 114 for (const key in dataTypes) { 115 let defaults = dataTypes[key]; 116 if ( data[key] && Array.isArray( data[key] ) ) { 117 data[key].map(function (entry) { 118 // add defaults data type 119 if ( typeof entry.useCustom === "undefined" || 120 ( typeof entry.useCustom !== "undefined" && ! globe_ut_bool( entry.useCustom ) ) ) { 121 Object.assign(entry, data[defaults]); 122 } 123 124 if(Array.isArray(entry.action)){ 125 entry.action = entry.action[0]; 126 } 127 128 // if it's using default action 129 if ( data[defaults] && entry.action && entry.action === 'default') { 130 entry.action = data[defaults]['action']; 131 } 132 }); 133 } 134 } 135}; 136 137/** 138 * Prepare viewport and globe 139 * @param DOM element container 140 * @param object data 141 * @param Globe Object thisGlobe 142 */ 143const globe_ut_prepareViewport = function ( container, data ) { 144 var aspRatioContainer = container.closest(".itt_globe_aspect_ratio"); 145 146 // container size adjustment 147 // if mobile 148 if (window.innerWidth <= 780 && typeof data.paddingTop !== 'undefined' && data.paddingTop !== '') { 149 aspRatioContainer.style.paddingTop = String(data.paddingTopMobile) + '%'; 150 } else { 151 aspRatioContainer.style.paddingTop = String(data.paddingTop) + '%'; 152 } 153}; 154 155/** 156 * Returns float, even if not a number 157 * @param {string} string to get float from 158 * @returns int float number 159 */ 160const globe_ut_float = function (string) { 161 var float = parseFloat(string); 162 if (isNaN(float)) { 163 return 0; 164 } 165 return float; 166}; 167 168/** 169 * Returns boolean value of a string or number 170 * @param {*} string 171 * @returns boolen 172 */ 173const globe_ut_bool = function (string) {
174 var bool = Number(string) === 0 || string === "false" || typeof string === "undefined" ? false : true; 175 return bool; 176}; 177 178const globe_ut_prepare_coordinates = function( type, marker ){ 179 180 if( typeof marker.coordinates !== 'undefined' && marker.coordinates[type] ){ 181 return parseFloat( marker.coordinates[type] ); 182 } 183 184 if( typeof marker[type] !== 'undefined' ){ 185 return parseFloat( marker[type] ); 186 } 187 return false; 188}; 189 190/** 191 * Sanitizes HTML string using a whitelist approach to prevent XSS. 192 * Allows basic formatting tags but removes unsafe tags and attributes. 193 * @param {string} htmlString 194 * @returns {string} Safe HTML string 195 */ 196const globe_ut_sanitize = function(htmlString) { 197 if (!htmlString || typeof htmlString !== 'string') { 198 return ''; 199 } 200 201 // Create a detached element to parse HTML 202 const parser = new DOMParser(); 203 const doc = parser.parseFromString(htmlString, 'text/html'); 204 const body = doc.body; 205 206 // Allowed tags 207 const allowedTags = [ 208 'DIV', 'SPAN', 'B', 'STRONG', 'I', 'EM', 'U', 'P', 'BR', 'UL', 'OL', 'LI', 'IMG', 'A', 209 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'TABLE', 'THEAD', 'TBODY', 'TR', 'TD', 'TH', 'BLOCKQUOTE', 'BODY' 210 ]; 211 212 // Allowed attributes 213 const allowedAttributes = [ 214 'id', 'class', 'title', 'src', 'alt', 'href', 'target', 'width', 'height', 'rel' 215 ]; 216 217 // Recursive sanitization function 218 function sanitizeNode(node) { 219 const children = Array.from(node.childNodes); 220 for (const child of children) { 221 sanitizeNode(child); 222 } 223 224 // Remove disallowed tags 225 if (node.nodeType === 1) { // Element node 226 if (!allowedTags.includes(node.tagName)) { 227 // Replace with text content if it's not script/style, otherwise remove entirely 228 if (['SCRIPT', 'STYLE', 'IFRAME', 'OBJECT', 'EMBED', 'LINK', 'META'].includes(node.tagName)) { 229 node.remove(); 230 } else { 231 // Unwrap safe text content for other unknown tags 232 while (node.firstChild) { 233 node.parentNode.insertBefore(node.firstChild, node); 234 } 235 node.remove(); 236 } 237 } else { 238 // Sanitize attributes 239 const attributes = Array.from(node.attributes); 240 for (const attr of attributes) { 241 // Remove attributes not in whitelist 242 if (!allowedAttributes.includes(attr.name.toLowerCase())) { 243 node.removeAttribute(attr.name); 244 continue; 245 } 246 247 // Special checks 248 // Block javascript: protocols in href and src 249 if (['href', 'src'].includes(attr.name.toLowerCase())) { 250 // Remove control characters (00-31 and 127) before checking to prevent bypasses 251 const val = attr.value.replace(/[\x00-\x1F\x7F]+/g, '').trim().toLowerCase(); 252 if ( val.startsWith('javascript:') || val.startsWith('vbscript:') || (val.startsWith('data:') && !val.startsWith('data:image/')) ) { 253 node.removeAttribute(attr.name); 254 } 255 } 256 // Block event handlers (on*) just in case they slipped through whitelist (though not in allowedAttributes) 257 if (attr.name.toLowerCase().startsWith('on')) { 258 node.removeAttribute(attr.name); 259 } 260 // Prevent tabnabbing 261 if (node.tagName === 'A' && node.getAttribute('target') === '_blank') { 262 node.setAttribute('rel', 'noopener noreferrer'); 263 } 264 } 265 } 266 } 267 } 268 269 sanitizeNode(body); 270 return body.innerHTML; 271}; 272 273/** Setup tooltip for element */ 274function setupTooltip( element, template ) { 275 276 let tooltip = element.tooltipContent ?? ''; 277 if( typeof template !== 'undefined' && template !== '{tooltipContent}' && template.length > 0 ){ 278 279 tooltip = template.replace(/\{([^}]+)\}/g, function(match, key) { 280 // Split the key by dot notation 281 const keys = key.split('.'); 282 let value = element; 283 284 // Traverse the object using the keys 285 for (let i = 0; i < keys.length; i++) { 286 value = value ? value[keys[i]] : undefined; 287 } 288 289 // If the value is undefined, replace it with an empty string or handle as necessary 290 return value !== undefined ? String(value) : ''; 291 }); 292 } 293 294 // Sanitize the final result to ensure both template and values are safe 295 tooltip = globe_ut_sanitize(tooltip); 296 297 if ( tooltip !== '') { 298 tooltip = '<div class="itt_globe_' + element.globe_id + ' itt_globe_tooltip">' + tooltip + '</div>'; 299 } 300 return tooltip; 301} 302 303/** Setup click events for element */ 304function setupClickEvent$1( thisGlobe, GlobeData, element ) { 305 306 let layerDataTypes = { 307 'arcLines': 'arcLineDefaults', 308 'points': 'pointDefaults', 309 'dotLabels': 'labelDefaults', 310 'regions': 'regionDefaults', 311 'html': 'htmlDefaults', 312 }; 313 314 if(element.type === 'flag' || element.type === 'marker' || element.type === 'cylinder' || element.type === 'pin'){ 315 element.type = 'points'; 316 } 317
318 if(element.type === 'regions' && element.properties){ 319 element = { ...element.properties }; 320 } 321 322 if (new URLSearchParams(window.location.search).has('debug')) { 323 console.debug(element); 324 } 325 326 // if we arrive here and it's still set as default, we need to set it to the default action for that layer 327 if( element.action === 'default' ){ 328 element.action = GlobeData[layerDataTypes[element.type]].action; 329 } 330 331 if (element.action === "none") { 332 // do nothing 333 return; 334 } 335 336 const clickAction = element.action; 337 if (clickAction && typeof window.ittGlobes.clickActions[clickAction] === 'function') { 338 window.ittGlobes.clickActions[clickAction]( thisGlobe, GlobeData, element ); 339 } 340 if ( ittGlobeData.isAdmin ) { 341 return; 342 } 343 344 // check urls 345 if (element.action === "open_url" || element.action === "open_url_new") { 346 element.content = globe_ut_prepareURL(element.content); 347 } 348 // open new url 349 if (element.action === "open_url" && element.content !== "") { 350 document.location = element.content; 351 } else if (element.action === "open_url_new" && element.content !== "") { 352 window.open(element.content); 353 } 354} 355 356/** Setup hover events for element */ 357function setupHoverEvent$1(thisGlobe, element, prevElement, type) { 358 359 let GlobeData = thisGlobe.meta; 360 361 if (type === 'regions') { 362 363 //pause/resume animation 364 if ( 365 typeof GlobeData.rotate !== 'undefined' && 366 globe_ut_bool(GlobeData.rotate.enabled) 367 ) { 368 // Pause auto-rotation when hovering over a region, resume when not hovering 369 thisGlobe.controls().autoRotate = !element; 370 } 371 372 373 thisGlobe.polygonCapColor(function (region) { 374 // when hovering the globe itself, element doesn't exist or doesn't have properties 375 if ( 376 typeof element === 'undefined' || 377 (element && typeof element.properties === 'undefined' && typeof element.originalId === 'undefined') 378 ) { 379 // Return original color when hovering over empty space or invalid element 380 return region.properties.color 381 ? region.properties.color 382 : GlobeData.regionDefaults.inactive; 383 } 384 // change hover color if being hovered or part of same group 385 else if (region === element) { 386 // Apply hover color to the specific region being hovered 387 return region.properties.hover; 388 } 389 // Handle case where element itself contains properties (like originalId) 390 else if ( 391 element && 392 element.originalId && 393 Array.isArray(element.originalId) && 394 region.properties.originalId && 395 Array.isArray(region.properties.originalId) && 396 element.originalId.some(id => region.properties.originalId.includes(id)) 397 ) { 398 console.log('triggered case where element itself contains properties (like originalId)'); 399 // Apply hover color to regions that match the element's originalId 400 return element.hover || region.properties.hover; 401 } 402 // Handle case where element has properties but we're checking against region properties 403 else if ( 404 region.properties.originalId && 405 element && 406 element.properties && 407 element.properties.id && 408 region.properties.originalId.includes(element.properties.id) 409 ) { 410 // Apply hover color to regions that share the same original ID (grouped regions) 411 return region.properties.hover; 412 } else if ( 413 region.properties.originalId && 414 element && 415 element.properties && 416 Array.isArray(element.properties.id) && 417 element.properties.id.includes(region.properties.id) 418 ) { 419 // Apply hover color to regions that are part of an array of IDs (multi-selection) 420 return region.properties.hover; 421 } 422 // we actually don't need the previous I think, we can reset the value for the rest of the entries 423 // Return original color for all other regions (not being hovered or grouped) 424 return region.properties.color 425 ? region.properties.color 426 : GlobeData.regionDefaults.inactive; 427 }); 428 } 429 430 else if (type === 'pin' || type === 'marker') { 431 if (element) { 432 // Convert hex color to integer 433 const hoverColor = parseInt(element.hover.replace('#', '0x'), 16); 434 parseInt(element.color.replace('#', '0x'), 16); 435 436 let threeObj = element.__threeObjObject ? element.__threeObjObject : element.__threeObj; 437 438 if (type === 'pin' ) {
439 threeObj.children[0].children.forEach((element) => { 440 element.material.color.setHex(hoverColor); 441 }); 442 } else if (type === 'marker') { 443 threeObj.children[0].material.color.setHex(hoverColor); 444 } 445 } 446 447 if (prevElement && prevElement !== element) { 448 const originalColor = parseInt(prevElement.color.replace('#', '0x'), 16); 449 let threeObj = prevElement.__threeObjObject ? prevElement.__threeObjObject : prevElement.__threeObj; 450 451 if (type === 'pin') { 452 threeObj.children[0].children.forEach((element) => { 453 element.material.color.setHex(originalColor); 454 }); 455 } else if (type === 'marker' && prevElement.type === 'marker') { 456 threeObj.children[0].material.color.setHex(originalColor); 457 } 458 } 459 460 461 //pause/resume animation 462 if ( 463 typeof GlobeData.rotate !== 'undefined' && 464 globe_ut_bool(GlobeData.rotate.enabled) 465 ) { 466 thisGlobe.controls().autoRotate = !element; 467 } 468 469 } 470 471 else { // for default points and labels 472 thisGlobe.labelColor(function (el) { 473 return element && el.id === element.id ? el.hover : el.color; 474 }); 475 476 thisGlobe.pointColor(function (el) { 477 return element && el.id === element.id ? el.hover : el.color; 478 }); 479 480 //pause/resume animation 481 if ( 482 typeof GlobeData.rotate !== 'undefined' && 483 globe_ut_bool(GlobeData.rotate.enabled) 484 ) { 485 thisGlobe.controls().autoRotate = !element; 486 } 487 } 488 489 return thisGlobe; 490} 491 492/** Add Points Layer to Globe */ 493function addPointsLayer(thisGlobe, GlobeData) { 494 thisGlobe.pointsData( GlobeData.points ) 495 .pointLat(p => globe_ut_prepare_coordinates('latitude', p) ) 496 .pointLng(p => globe_ut_prepare_coordinates('longitude', p) ) 497 .pointRadius(p => p.radius / 10) 498 .pointAltitude(p => p.altitude / 100) 499 .pointColor(p => p.color) 500 .pointResolution(20); 501 502 // tooltip 503 thisGlobe.pointLabel(function (label) { 504 505 let pointsTooltipTemplate = GlobeData.tooltipTemplate ?? '{tooltipContent}'; 506 if( GlobeData.pointsTooltipTemplate ){ 507 pointsTooltipTemplate = GlobeData.pointsTooltipTemplate; 508 } 509 return setupTooltip(label, pointsTooltipTemplate ); 510 511 }); 512 513 // click events 514 thisGlobe.onPointClick(function ( element ) { 515 setupClickEvent$1( thisGlobe, GlobeData, element ); 516 }); 517 518 // hover events 519 thisGlobe.onPointHover(function (label) { 520 setupHoverEvent$1( thisGlobe, label, 'point' ); 521 }); 522 523 // click events 524 thisGlobe.onObjectClick(function ( element ) { 525 setupClickEvent$1( thisGlobe, GlobeData, element ); 526 }); 527} 528 529/** Add Labels Layer to Globe */ 530function addLabelsLayer( thisGlobe, GlobeData ) { 531 532 thisGlobe.labelsData( GlobeData.dotLabels ) 533 .labelLat(l => globe_ut_prepare_coordinates('latitude', l)) 534 .labelLng(l => globe_ut_prepare_coordinates('longitude', l)) 535 .labelText(l => l.title ? (l.title.trim() ? l.title : '_') : '_') 536 .labelAltitude(l => l.altitude / 100) 537 .labelSize(l => l.size / 10) 538 .labelColor(l => l.color) 539 .labelResolution(20) 540 .labelIncludeDot(l => globe_ut_bool(l.includeDot)) 541 .labelDotRadius(l => l.radius / 10) 542 .labelDotOrientation(l => l.dotOrientation); 543 544 // font 545 if (GlobeData.labelFont && GlobeData.labelFont !== 'default') { 546 547 let url = ittGlobeData.assetsUrl + 'fonts/' + GlobeData.labelFont + '.json'; 548 549 fetch(url) 550 .then(res => res.json()) 551 .then( labelfont => { thisGlobe.labelTypeFace(labelfont); } ) 552 .catch(error => { 553 console.error('Fetch error:', error); 554 }); 555 } 556 557 // tooltip 558 thisGlobe.labelLabel(function (label) { 559 560 let dotLabelsTooltipTemplate = GlobeData.tooltipTemplate ?? '{tooltipContent}'; 561 if( GlobeData.dotLabelsTooltipTemplate ){ 562 dotLabelsTooltipTemplate = GlobeData.dotLabelsTooltipTemplate; 563 } 564 return setupTooltip(label, dotLabelsTooltipTemplate ); 565 }); 566 567 // click events 568 thisGlobe.onLabelClick(function (label, event, coordinates) { 569 setupClickEvent$1( thisGlobe, GlobeData, label ); 570 }); 571 572 // hover events 573 thisGlobe.onLabelHover(function (label) { 574 setupHoverEvent$1( thisGlobe, label, 'label' ); 575 }); 576} 577 578/** Setup click events for element */ 579function setupResizeEvent( thisGlobe, container, data ) { 580 581 var aspRatioContainer = container.closest(".itt_globe_aspect_ratio"); 582 583 window.addEventListener('resize', function () { 584 if (window.innerWidth <= 780 && typeof data.paddingTop !== 'undefined' && data.paddingTop !== '') { 585 aspRatioContainer.style.paddingTop = String(data.paddingTopMobile) + '%'; 586 } else { 587 aspRatioContainer.style.paddingTop = String(data.paddingTop) + '%'; 588 } 589 590 // Here should go the code to rebuild globe with new size in a more performant way 591 // check for size changes, etc.. 592 if (thisGlobe.width() !== container.offsetWidth) { 593 thisGlobe 594 .width(container.offsetWidth) 595 .height(container.offsetHeight); 596 } 597 }); 598} 599 600/** 601 * Controls globe interactions 602 * @param {*} thisGlobe 603 * @param {*} data 604 */ 605function setupInteractions( thisGlobe, data ) { 606 // interactions 607 if( typeof data.interactions !== 'undefined' ) { 608 thisGlobe.controls().enableZoom = globe_ut_bool( data.interactions.zoom ); 609 thisGlobe.controls().enablePan = globe_ut_bool( data.interactions.pan ); 610 thisGlobe.controls().enableRotate = globe_ut_bool( data.interactions.pan ); 611 } 612 613 if( typeof data.interactions === 'undefined' || globe_ut_bool( data.interactions.zoom ) ) { 614 615 let lastClickTime = 0; 616 const doubleClickDelay = 300; // milliseconds 617 618 thisGlobe.onGlobeClick(function(coordinates, event) { 619 620 const currentTime = new Date().getTime(); 621 const timeDiff = currentTime - lastClickTime; 622 623 if (timeDiff < doubleClickDelay) { 624 // Double click detected - zoom in
625 let zoomTo = thisGlobe.pointOfView(); 626 zoomTo.altitude = zoomTo.altitude * 0.6; 627 zoomTo.lat = coordinates.lat; 628 zoomTo.lng = coordinates.lng; 629 thisGlobe.pointOfView(zoomTo, 800); 630 } 631 632 lastClickTime = currentTime; 633 }); 634 } 635} 636 637let ittGlobes$1 = { 638 'globes': [], 639 'globesIndex': {}, 640 'clickActions': {}, 641}; 642 643window.ittGlobes = ittGlobes$1; 644 645function addArcLines(globe, data) { 646 // Create GeoJSON features from arc lines 647 const features = data.arcLines.map((line, index) => { 648 // Line properties have already been processed, so use them directly 649 const lineProps = line; 650 // Get the layer ID and globe ID 651 let layerId = line._layerId ? line._layerId : line.globe_id; 652 let globeId = line.globe_id; 653 654 // If no layer ID is set, try to find the layer this line belongs to 655 if (!layerId && data.layers) { 656 const matchingLayer = data.layers.find(layer => 657 layer.arcLines && layer.arcLines.some(l => l === line) 658 ); 659 if (matchingLayer) { 660 layerId = matchingLayer.id; 661 globeId = matchingLayer.globe_id; 662 } 663 } 664 665 // If still no globe ID, use the base map ID 666 if (!globeId) { 667 globeId = data.id; 668 } 669 670 let feature = { 671 type: 'Feature', 672 id: index, 673 properties: { 674 stroke: lineProps.stroke || '#000000', 675 strokeWidth: parseInt(lineProps.strokeWidth || 5, 10), 676 globe_id: globeId, 677 layer_id: layerId, 678 isActive: true 679 }, 680 geometry: { 681 type: 'LineString', 682 coordinates: line.line.map(point => [ 683 point.coordinates.longitude, 684 point.coordinates.latitude 685 ]) 686 } 687 }; 688 689 return feature; 690 }); 691 692 // Add source 693 globe.addSource('lines', { 694 type: 'geojson', 695 data: { 696 type: 'FeatureCollection', 697 features: features 698 } 699 }); 700 701 // Get all layers and find the last region border layer 702 const styleLayers = globe.getStyle().layers; 703 const borderLayerIndices = styleLayers 704 .map((layer, index) => layer.id.endsWith('-borders') ? index : -1) 705 .filter(index => index !== -1); 706 707 // If we found any border layers, add lines after the last one 708 // If no border layers found, add at the very end 709 const lastBorderIndex = borderLayerIndices.length > 0 710 ? Math.max(...borderLayerIndices) 711 : styleLayers.length - 1; 712 713 styleLayers[Math.min(lastBorderIndex + 1, styleLayers.length - 1)].id; 714 715 // Add layer with high z-index to ensure it's on top 716 globe.addLayer({ 717 id: 'lines', 718 type: 'line', 719 source: 'lines', 720 layout: { 721 'line-join': 'round', 722 'line-cap': 'round' 723 }, 724 paint: { 725 'line-color': ['get', 'stroke'], 726 'line-width': ['get', 'strokeWidth'], 727 'line-opacity': [ 728 'case', 729 ['boolean', ['feature-state', 'visible'], false], 730 1, 731 0 732 ] 733 } 734 }); // if provided, it will Insert the layer beneath the first symbol layer. 735 // so by not passing the second parameter, it places on top. 736 737 // Set initial feature states for lines 738 features.forEach(feature => { 739 740 if (feature.id !== undefined) { 741 // Check if we have a default layer set and keepBase is disabled 742 const hasDefaultLayer = data.liveFilter?.enabled === '1' && data.liveFilter?.default; 743 const keepBaseDisabled = data.liveFilter?.keepBase !== '1'; 744 const defaultGlobeId = data.liveFilter?.default; 745 const featureGlobeId = feature.properties.globe_id; 746 747 // Determine initial visibility - FIXED: Don't hide lines by default 748 let shouldBeVisible = true; 749 750 if (hasDefaultLayer && keepBaseDisabled) { 751 // If we have a default layer and keepBase is disabled, 752 // only show lines that match the default layer's globe ID 753 shouldBeVisible = String(featureGlobeId) === String(defaultGlobeId); 754 } 755 // REMOVED: else if (keepBaseDisabled) { shouldBeVisible = false; } 756 // This was causing lines to be hidden by default when keepBase was disabled 757 758 globe.setFeatureState( 759 { source: 'lines', id: feature.id }, 760 { 761 visible: shouldBeVisible, 762 hover: false 763 } 764 ); 765 766 } 767 }); 768} 769 770// Handle resize events to prevent rendering artifacts 771function setupResizeListener(globe) { 772 const handleResize = () => { 773 globe.resize(); 774 }; 775 776 // Use ResizeObserver to detect container size changes 777 const container = globe.getContainer(); 778 const resizeObserver = new ResizeObserver(() => { 779 handleResize(); 780 }); 781 782 if (container) { 783 resizeObserver.observe(container); 784 } 785 786 window.addEventListener('resize', handleResize); 787 788 // Return cleanup function 789 return () => { 790 if (container) { 791 resizeObserver.unobserve(container); 792 } 793 resizeObserver.disconnect(); 794 window.removeEventListener('resize', handleResize); 795 }; 796} 797// Add methods to the globe object for programmatic control 798 799// Method to trigger click events programmatically 800function setupClickEvent(globe, globeData, element) { 801
802 // If element exists, call the imported setupClickEvent function 803 if (element) { 804 // Directly call the setupClickEvent function that's imported from click.js 805 setupClickEvent$1(globe, globeData, element); 806 } 807} 808// Method to trigger hover events programmatically 809function setupHoverEvent(globe, element, prevElement, type) { 810 811 // Handle hover event based on element type 812 if (!element) return; 813 814 const zoomLevel = element.zoomLevel || 4; 815 const animationDuration = 1500; 816 // Normalize type - use element.type if provided, or fallback to the passed type 817 const elementType = element.type || type || 'point'; 818 819 // Check if it's a marker (points, objects, dotLabels, html) 820 if (elementType !== 'regions' && element._marker) { 821 // For markers, trigger mouseenter event on the marker element 822 const markerElement = element._marker.getElement(); 823 824 // Remove hover from previous element if provided 825 if (prevElement && prevElement._marker) { 826 const prevMarkerElement = prevElement._marker.getElement(); 827 const mouseLeaveEvent = new MouseEvent('mouseleave'); 828 prevMarkerElement.dispatchEvent(mouseLeaveEvent); 829 } 830 831 // Trigger hover on current element 832 const mouseEnterEvent = new MouseEvent('mouseenter'); 833 markerElement.dispatchEvent(mouseEnterEvent); 834 835 // Show popup with tooltip content if available 836 if (element.tooltipContent || 837 (elementType === 'point' && (globe.meta.pointsTooltipTemplate || globe.meta.tooltipTemplate)) || 838 (elementType === 'dotLabel' && (globe.meta.dotLabelsTooltipTemplate || globe.meta.tooltipTemplate))) { 839 840 const coordinates = element.coordinates ? 841 [element.coordinates.longitude, element.coordinates.latitude] : 842 [element.longitude || element.lng || 0, element.latitude || element.lat || 0]; 843 844 // Process tooltip content using the same method as in the hover handler 845 let template = ''; 846 switch(elementType) { 847 case 'point': 848 case 'marker': 849 template = globe.meta.pointsTooltipTemplate || globe.meta.tooltipTemplate; 850 break; 851 case 'dotLabel': 852 template = globe.meta.dotLabelsTooltipTemplate || globe.meta.tooltipTemplate; 853 break; 854 case 'htmlMarker': 855 template = globe.meta.htmlTooltipTemplate || globe.meta.tooltipTemplate; 856 break; 857 default: 858 template = globe.meta.tooltipTemplate; 859 } 860 861 let processedContent = element.tooltipContent || ''; 862 if (template) { 863 processedContent = template; 864 // Replace all placeholders with their values 865 Object.keys(element).forEach(key => { 866 const placeholder = `{${key}}`; 867 const value = element[key] || ''; 868 processedContent = processedContent.replace(new RegExp(placeholder, 'g'), value); 869 }); 870 } 871 872 globe.popup.setLngLat(coordinates) 873 .setHTML(processedContent) 874 .addTo(globe); 875 } 876 } 877 // Check if it's a region 878 else if (elementType === 'regions' && globe.getSource('regions')) { 879 // Handle region - it could have an ID as array or string
880 const regionId = Array.isArray(element.id) ? element.id[0] : element.id; 881 882 if (!regionId) { 883 return; 884 } 885 886 // If not a known region, proceed with feature-based calculation 887 const regionFeatures = globe.querySourceFeatures('regions', { 888 filter: ['==', ['get', 'id'], regionId] 889 }); 890 891 if (regionFeatures.length > 0) { 892 // Create a bounds object to encompass ALL parts of the region 893 const bounds = new maplibregl.LngLatBounds(); 894 let hasValidCoords = false; 895 896 try { 897 // Process all features that match this region ID 898 regionFeatures.forEach(feature => { 899 if (feature.geometry.type === 'Polygon') { 900 // For polygons, process all rings (first is outer, rest are holes) 901 feature.geometry.coordinates.forEach((ring, ringIndex) => { 902 // Only process outer ring (index 0) for bounds 903 if (ringIndex === 0) { 904 ring.forEach(coord => { 905 if (Array.isArray(coord) && coord.length >= 2) { 906 bounds.extend(coord); 907 hasValidCoords = true; 908 } 909 }); 910 } 911 }); 912 } 913 else if (feature.geometry.type === 'MultiPolygon') { 914 // For multi-polygons, process each polygon's outer ring 915 feature.geometry.coordinates.forEach(polygon => {
916 if (Array.isArray(polygon) && polygon.length > 0) { 917 // Get the outer ring of this polygon (index 0) 918 const outerRing = polygon[0]; 919 if (Array.isArray(outerRing)) { 920 outerRing.forEach(coord => { 921 if (Array.isArray(coord) && coord.length >= 2) { 922 bounds.extend(coord); 923 hasValidCoords = true; 924 } 925 }); 926 } 927 } 928 }); 929 } 930 }); 931 932 if (hasValidCoords) { 933 // Fit the map to the bounds of the entire region 934 globe.fitBounds(bounds, { 935 padding: {top: 10, bottom: 10, left: 10, right: 10}, // More flexible padding 936 duration: animationDuration, 937 maxZoom: zoomLevel 938 }); 939 } else { 940 throw new Error('No valid coordinates found in any region geometry'); 941 } 942 } catch (error) { 943 // Silently handle error 944 } 945 } 946 } 947} 948 949// Add filter interaction logic for maplibre maps 950const setupMaplibreFilters = () => { 951 const filterContainers = document.querySelectorAll( 952 '.itt_globe_filter_menu_container[data-library="maplibre"] .itt_globe_filter_menu, .itt_globe_filter_menu_container[data-library="maplibre"] .itt_globe_toggle_menu' 953 ); 954 document.querySelectorAll( 955 '.itt_globe_filter_menu_container[data-library="maplibre"] .itt_globe_filter_dropdown' 956 ); 957 958 // Menu & toggle 959 if (filterContainers.length > 0) { 960 filterContainers.forEach((container) => { 961 const type = container.classList.contains('itt_globe_filter_menu') 962 ? 'filter' 963 : 'toggle'; 964 const containerId = container.getAttribute('data-globe-id'); 965 const globe = ittGlobes.globesIndex[containerId]; 966 const globeData = globe.meta; 967 const filterItems = container.querySelectorAll('.itt_globe_filter_item'); 968 969 // Function to handle filter click 970 const handleFilterClick = function() { 971 const globeId = parseInt(this.getAttribute('data-globe-id')); 972 // Get the data from the globe's meta property 973 const globeData = globe.meta; 974 975 // Handle active class based on filter type 976 if (type === 'filter') { 977 // Remove active class from all items in the same container 978 filterItems.forEach(otherItem => { 979 otherItem.classList.remove('itt_globe_filter_item_active'); 980 }); 981 // Add active class to clicked item 982 this.classList.add('itt_globe_filter_item_active'); 983 } else if (type === 'toggle') { 984 // Toggle the active class 985 this.classList.toggle('itt_globe_filter_item_active'); 986 } 987 988 // Process base data 989 processEntries(globe, globeId, globeData, type, true); 990 991 // Process layer data 992 if (globeData.layers && Array.isArray(globeData.layers)) { 993 globeData.layers.forEach(layer => { 994 processEntries( globe, globeId, layer, type, false); 995 }); 996 } 997 }; 998 999 // Add click event listeners to filter items 1000 filterItems.forEach((item) => { 1001 item.addEventListener('click', handleFilterClick); 1002 }); 1003 1004 // Check for default filter and trigger it if needed 1005 if (globeData.liveFilter?.enabled === '1' && globeData.liveFilter?.default) { 1006 const defaultGlobeId = globeData.liveFilter.default; 1007 const defaultFilterItem = Array.from(filterItems).find(item => 1008 item.getAttribute('data-globe-id') === defaultGlobeId 1009 ); 1010 1011 if (defaultFilterItem) { 1012 // Create and dispatch a click event 1013 const clickEvent = new MouseEvent('click', { 1014 bubbles: true, 1015 cancelable: true, 1016 view: window 1017 }); 1018 defaultFilterItem.dispatchEvent(clickEvent); 1019 } 1020 } 1021 }); 1022 } 1023}; 1024 1025 1026 1027// Function to process entries from a data object 1028const processEntries = ( globe, globeId, data, type, isBaseData = false) => { 1029 if (!data) return; 1030 // Get all entries from the globe that match the globeId 1031 const matchingEntries = []; 1032 const keepBaseValue = data.liveFilter && data.liveFilter.keepBase ? data.liveFilter.keepBase : '0'; 1033 1034 /** 1035 * Determines if an entry should be visible based on various conditions: 1036 * 1. Base map entries with matching keepBase ID 1037 * 2. Base map filter selection (globeId matches base map ID) 1038 * 3. Filter/toggle type and active state 1039 * 1040 * @param {Object} entry - The entry to check visibility for 1041 * @returns {boolean} - Whether the entry should be visible 1042 */ 1043 const shouldBeVisible = (entry) => { 1044 1045 // If this is the base map filter (globeId matches base map ID), show all entries 1046 if (globeId === parseInt(data.id)) { 1047 return true; 1048 } 1049 1050 if ( globe.meta.id === globeId ) { 1051 return true; 1052 } 1053 1054 // If keepBase is set and this is a base map region, keep it visible 1055 if (keepBaseValue === '1' && entry.globe_id === parseInt(data.id)) { 1056 return true; 1057 } 1058
1059 // For filter type, show only matching entries 1060 if (type === 'filter') { 1061 const isVisible = entry.globe_id === globeId; 1062 return isVisible; 1063 } 1064 // For toggle type, show based on active state 1065 // simplified this, but maybe its too simplistic 1066 return entry.globe_id === globeId; 1067 }; 1068 1069 // Check points 1070 if (data.points) { 1071 const matchingPoints = data.points.filter(point => point.globe_id === globeId); 1072 matchingEntries.push(...matchingPoints); 1073 // Show/hide markers 1074 data.points.forEach(point => { 1075 if (point._marker) { 1076 point._marker.getElement().style.display = shouldBeVisible(point) ? 'block' : 'none'; 1077 } 1078 }); 1079 } 1080 1081 // Check objects 1082 if (data.objects) { 1083 const matchingObjects = data.objects.filter(object => object.globe_id === globeId); 1084 matchingEntries.push(...matchingObjects); 1085 // Show/hide markers 1086 data.objects.forEach(object => { 1087 if (object._marker) { 1088 object._marker.getElement().style.display = shouldBeVisible(object) ? 'block' : 'none'; 1089 } 1090 }); 1091 } 1092 1093 // Check dotLabels 1094 if (data.dotLabels) { 1095 const matchingDotLabels = data.dotLabels.filter(label => label.globe_id === globeId); 1096 matchingEntries.push(...matchingDotLabels); 1097 // Show/hide markers
1098 data.dotLabels.forEach(label => { 1099 if (label._marker) { 1100 label._marker.getElement().style.display = shouldBeVisible(label) ? 'block' : 'none'; 1101 } 1102 }); 1103 } 1104 1105 // Check html markers 1106 if (data.html) { 1107 const matchingHtml = data.html.filter(html => html.globe_id === globeId); 1108 matchingEntries.push(...matchingHtml); 1109 // Show/hide markers 1110 data.html.forEach(html => { 1111 if (html._marker) { 1112 html._marker.getElement().style.display = shouldBeVisible(html) ? 'block' : 'none'; 1113 } 1114 }); 1115 } 1116 1117 // Check regions 1118 if (data.regions) { 1119 const matchingRegions = data.regions.filter(region => region.globe_id === globeId); 1120 matchingEntries.push(...matchingRegions); 1121 1122 // Show/hide regions using feature state for all region sources 1123 const regionSources = globe.getStyle().sources; 1124 Object.keys(regionSources).forEach(sourceId => { 1125 if (sourceId.startsWith('regions')) { 1126 const features = globe.querySourceFeatures(sourceId); 1127 features.forEach(feature => { 1128 if (feature.id !== undefined) { 1129 const isActive = shouldBeVisible(feature.properties); 1130 1131 try { 1132 globe.setFeatureState( 1133 { source: sourceId, id: feature.id }, 1134 { 1135 visible: isActive, 1136 hover: false 1137 } 1138 ); 1139 1140 } catch (error) { 1141 console.error('Error setting feature state:', error); 1142 } 1143 } 1144 }); 1145 } 1146 }); 1147 } 1148 1149 // Check arcLines 1150 if (data.arcLines) { 1151 1152 const matchingArcLines = data.arcLines.filter(line => line.globe_id === globeId); 1153 matchingEntries.push(...matchingArcLines); 1154 1155 // Show/hide lines using feature state 1156 if (globe.getSource('lines')) { 1157 const features = globe.querySourceFeatures('lines'); 1158 1159 1160 features.forEach(feature => { 1161 if (feature.id !== undefined) { 1162 const isActive = shouldBeVisible(feature.properties); 1163 1164 1165 try { 1166 globe.setFeatureState( 1167 { source: 'lines', id: feature.id }, 1168 { 1169 visible: isActive, 1170 hover: false 1171 } 1172 ); 1173 1174 } catch (error) { 1175 console.error('Error setting line feature state:', error); 1176 } 1177 } 1178 }); 1179 } 1180 } 1181 1182 return matchingEntries; 1183}; 1184 1185// Helper function to get coordinates from an object, [ longitude, latitude ] 1186const getCoordinates = (obj) => { 1187 // Try different possible coordinate property names 1188 if (obj.coordinates?.longitude !== undefined && obj.coordinates?.latitude !== undefined) { 1189 return [obj.coordinates.longitude, obj.coordinates.latitude]; 1190 } 1191 if (obj.coordinates?.long !== undefined && obj.coordinates?.lat !== undefined) { 1192 return [obj.coordinates.long, obj.coordinates.lat]; 1193 } 1194 if (obj.longitude !== undefined && obj.latitude !== undefined) { 1195 return [obj.longitude, obj.latitude]; 1196 } 1197 if (obj.long !== undefined && obj.lat !== undefined) { 1198 return [obj.long, obj.lat]; 1199 } 1200 if (obj.lng !== undefined && obj.lat !== undefined) { 1201 return [obj.lng, obj.lat]; 1202 } 1203 console.warn('Could not find valid coordinates in object:', obj); 1204 return [0, 0]; // Fallback to [0,0] if no valid coordinates found 1205}; 1206 1207const isAdmin = typeof ittGlobeData !== 'undefined' && ittGlobeData.isAdmin === true; 1208 1209// Function to check if a specific select element already has an option with a specific value 1210const hasOption = function(selectElement, valueToCheck) { 1211 // Get all options of the select element 1212 const options = selectElement.options; 1213 if ( options === undefined ){ 1214 return false; 1215 } 1216 1217 // Loop through all options 1218 for (let i = 0; i < options.length; i++) { 1219 // Check if the value of the current option matches the value we are checking for 1220 if (options[i].value === valueToCheck) { 1221 // If a match is found, return true 1222 return true; 1223 } 1224 } 1225 1226 // If no match is found, return false 1227 return false; 1228}; 1229 1230 1231 1232/** 1233 * Truncate to 3 decimal places 1234 */ 1235const truncateTo3Decimals = function(number) { 1236 const truncated = Math.trunc(number * 1000) / 1000; 1237 return truncated.toFixed(3); 1238}; 1239 1240 1241 1242const getGeojsonUrlVal = function(){ 1243 let geojsonUrlSelect = document.getElementsByName( 'globe_info[regionCustomSourceURL]' ); 1244 1245 if ( typeof geojsonUrlSelect === 'undefined' || geojsonUrlSelect.length == 0 ) { 1246 return; 1247 } 1248 1249 geojsonUrlSelect = geojsonUrlSelect[0]; 1250 if ( typeof geojsonUrlSelect === 'undefined' ) { 1251 return; 1252 } 1253 1254 return geojsonUrlSelect.value; 1255}; 1256 1257const getGeojsonVal = function(){ 1258 let geojsonSelect = document.getElementsByName( 'globe_info[regionSource]' ); 1259 if ( typeof geojsonSelect === 'undefined' || geojsonSelect.length == 0 ) { 1260 return; 1261 } 1262 1263 geojsonSelect = geojsonSelect[0]; 1264 if ( typeof geojsonSelect === 'undefined' ) { 1265 return; 1266 } 1267 1268 return geojsonSelect.value; 1269}; 1270 1271 1272 1273const updatePreviewUI = ( dataset, element ) => { 1274 1275 // prevent unnecessary DOM queries and logic from running when the preview UI is not present. 1276 const previewContainer = document.querySelector('#itt_globe_preview_data_clicked'); 1277 if ( ! previewContainer ) { 1278 return; 1279 } 1280 // ripple click 1281 // TODO ripple click 1282 let addNewButton = previewContainer.querySelector('.itt_globe_preview_action_add_new'); 1283 1284 // if is inactive , show add new button 1285 if( dataset.isActive === false ){ 1286 if ( ! addNewButton) { 1287 return; 1288 } 1289 // remove any previous dataset keys used by this feature 1290 Object.keys( dataset ).forEach(key => { 1291 delete addNewButton.dataset[key]; 1292 }); 1293 1294 // set previous 1295 addNewButton.dataset.prevlatitude = addNewButton.dataset.latitude; 1296 addNewButton.dataset.prevlongitude = addNewButton.dataset.longitude; 1297 1298 // add to the dropdown
1299 if( ! hasOption( addNewButton, element.post_type ) ){ 1300 let newOption = new Option( element.type, element.post_type ); 1301 addNewButton.add( newOption, undefined ); 1302 } 1303 let editButton = previewContainer.querySelector('.itt_globe_preview_action_edit'); 1304 if ( editButton ) { 1305 editButton.style.display = "none"; 1306 } 1307 1308 // set dataset values to carry on to add new url 1309 1310 // set new coordinates 1311 addNewButton.dataset.latitude = truncateTo3Decimals( element.coordinates.latitude ); 1312 addNewButton.dataset.longitude = truncateTo3Decimals( element.coordinates.longitude ); 1313 1314 1315 // set new values (ensure strings) 1316 Object.entries( dataset ).forEach(([key, val]) => { 1317 addNewButton.dataset[key] = (val === null || typeof val === 'undefined') ? '' : String(val); 1318 }); 1319 1320 addNewButton.style.display = "inline-block"; 1321 let title = previewContainer.querySelector('.itt_globe_preview_title'); 1322 if ( title ) { 1323 title.textContent = 'Clicked ' + element.text + ' : ' + element.title; 1324 } 1325 } 1326 if( dataset.isActive === true ){ 1327 // edit stuff 1328 if ( ( 1329 element.post_type === 'itt_globe_point' || 1330 element.post_type === 'itt_globe_dotlabel' || 1331 element.post_type === 'itt_globe_region' || 1332 element.post_type === 'itt_globe_html' 1333 ) || 1334 typeof element.post_id !== 'undefined' ){ 1335 1336 if ( addNewButton ) { 1337 addNewButton.style.display = "none"; 1338 } 1339 // show edit button 1340 let editButton = previewContainer.querySelector('.itt_globe_preview_action_edit'); 1341 if ( editButton ) { 1342 editButton.dataset.id = element.post_id ? element.post_id : element.id; 1343 editButton.dataset.post_type = element.post_type; 1344 editButton.style.display = "inline-block"; 1345 } 1346 } 1347 1348 let title = previewContainer.querySelector('.itt_globe_preview_title'); 1349 if ( title ) { 1350 title.textContent = 'Clicked ' + element.text + ' : ' + element.title; 1351 } 1352 } 1353 1354 // common update info 1355 let clicked = previewContainer.querySelector('.inside .itt_globe_preview_data'); 1356 if ( ! clicked ) { 1357 return; 1358 } 1359 let clickedTemplate = 1360 '<div class="coordinate-block lat-block">' + 1361 '<div class="coordinate-label info--unselectable ">Lat: </div>' + 1362 '<div class="coordinate-value">' + truncateTo3Decimals(element.coordinates.latitude) + '</div>' + 1363 '</div>' + 1364 '<div class="coordinate-block lng-block">' + 1365 '<div class="coordinate-label info--unselectable">Lng: </div>' + 1366 '<div class="coordinate-value">' + truncateTo3Decimals(element.coordinates.longitude) + '</div>' + 1367 '</div>'; 1368 clicked.innerHTML = clickedTemplate; 1369}; 1370 1371// Function to process tooltip template 1372 const processTooltipTemplate = (template, properties = {}) => { 1373 // If no template, return tooltipContent or empty string 1374 if (!template) return properties.tooltipContent || ''; 1375 1376 let processedContent = template; 1377 1378 // Replace all placeholders with their values 1379 Object.keys(properties).forEach(key => { 1380 const placeholder = `{${key}}`; 1381 const value = properties[key] || ''; 1382 processedContent = processedContent.replace(new RegExp(placeholder, 'g'), value); 1383 }); 1384 1385 return processedContent; 1386 }; 1387 1388 // Function to get the appropriate template 1389 const getTooltipTemplate = (type, properties = {}, data ) => { 1390 // Check for specific template first 1391 let template = ''; 1392 switch(type) { 1393 case 'point': 1394 template = data.pointsTooltipTemplate || data.tooltipTemplate; 1395 break; 1396 case 'region': 1397 template = data.regionsTooltipTemplate || data.tooltipTemplate; 1398 break; 1399 case 'dotLabel': 1400 template = data.dotLabelsTooltipTemplate || data.tooltipTemplate; 1401 break; 1402 default: 1403 template = data.tooltipTemplate; 1404 } 1405 1406 // If we have a template, process it regardless of tooltipContent 1407 if (template) { 1408 return processTooltipTemplate(template, properties); 1409 } 1410 1411 // If no template, return tooltipContent or empty string 1412 return properties.tooltipContent || ''; 1413 }; 1414 1415 1416 // Function to apply tooltip styles 1417 const applyTooltipStyles = (popupElement, globeId, data ) => { 1418 if (!data.tooltip) return; 1419 1420 const tooltipSettings = data.tooltip; 1421 const className = `itt-tooltip-${globeId}`; 1422 1423 // Create style element if it doesn't exist 1424 let styleElement = document.getElementById(`itt-tooltip-styles-${globeId}`); 1425 if (!styleElement) { 1426 styleElement = document.createElement('style'); 1427 styleElement.globeId = `itt-tooltip-styles-${globeId}`; 1428 document.head.appendChild(styleElement); 1429 } 1430 1431 // Generate CSS 1432 const css = ` 1433 .maplibregl-popup.${className} { 1434 background: none; 1435 padding: 0; 1436 box-shadow: none; 1437 border: none; 1438 pointer-events: none; 1439 } 1440 1441 .maplibregl-popup.${className} .maplibregl-popup-content { 1442 pointer-events: none; 1443 min-width: 40px; 1444 background-color: ${tooltipSettings.backgroundColor}; 1445 font-family: ${tooltipSettings.fontFamily}; 1446 font-weight: ${tooltipSettings.font['font-weight']}; 1447 font-style: ${tooltipSettings.font['font-style']}; 1448 text-align: ${tooltipSettings.font['text-align']}; 1449 font-size: ${tooltipSettings.font['font-size']}${tooltipSettings.font.unit}; 1450 color: ${tooltipSettings.font.color}; 1451 border-radius: ${tooltipSettings.cornerRadius}px; 1452 border: ${tooltipSettings.border.all}px ${tooltipSettings.border.style} ${tooltipSettings.border.color}; 1453 padding: ${tooltipSettings.padding.top}${tooltipSettings.padding.unit} ${tooltipSettings.padding.right}${tooltipSettings.padding.unit} ${tooltipSettings.padding.bottom}${tooltipSettings.padding.unit} ${tooltipSettings.padding.left}${tooltipSettings.padding.unit}; 1454 max-width: ${tooltipSettings.maxWidth}px; 1455 margin: 0; 1456 position: relative; 1457 } 1458 1459 1460 1461 .maplibregl-popup.${className} .maplibregl-popup-tip { 1462 display: none; 1463 } 1464 `; 1465 1466 // Update styles 1467 styleElement.textContent = css; 1468 1469 // Apply class to popup 1470 popupElement.classList.add(className); 1471 }; 1472 1473 1474const addTooltipStylesToPopup = function( globe, globeId, data ) { 1475 1476 // Apply styles when popup is added to the map 1477 globe.popup.on('open', () => { 1478 const popupElement = globe.popup.getElement(); 1479 applyTooltipStyles(popupElement, globeId, data ); 1480 }); 1481}; 1482 1483// Function to calculate optimal anchor position for tooltip 1484const calculateOptimalAnchor = ( globe, coordinates, markerElement) => { 1485 // Get the marker's position in the viewport 1486 const markerRect = markerElement.getBoundingClientRect(); 1487 const mapRect = globe.getContainer().getBoundingClientRect(); 1488 1489 // Calculate distances to viewport edges 1490 const distanceToTop = markerRect.top - mapRect.top; 1491 mapRect.bottom - markerRect.bottom; 1492 const distanceToLeft = markerRect.left - mapRect.left; 1493 const distanceToRight = mapRect.right - markerRect.right; 1494 1495 // Determine vertical anchor 1496 let verticalAnchor = 'bottom'; 1497 if (distanceToTop < 100) { // If less than 100px from top 1498 verticalAnchor = 'top'; 1499 } 1500
1501 // Determine horizontal anchor 1502 let horizontalAnchor = 'center'; 1503 if (distanceToLeft < 100) { // If less than 100px from left 1504 horizontalAnchor = 'left'; 1505 } else if (distanceToRight < 100) { // If less than 100px from right 1506 horizontalAnchor = 'right'; 1507 } 1508 1509 return `${verticalAnchor}-${horizontalAnchor}`; 1510}; 1511 1512// Helper function to get point property with fallback to defaults 1513const getPointProperty = ( point, propertyName, data ) => { 1514 // Special case for type property 1515 if (propertyName === 'type') { 1516 return point.type; 1517 } 1518 1519 // If point has custom settings enabled, return the point's property 1520 if (globe_ut_bool(point.useCustom)) { 1521 return point[propertyName]; 1522 } 1523 1524 // If point has a layer ID, use that layer's defaults 1525 if (point._layerId && data.layers) { 1526 const layer = data.layers.find(l => l.id === point._layerId || l.id === `layer_${point._layerId}`); 1527 if (layer) { 1528 // Get the appropriate defaults based on point type 1529 let layerDefaults; 1530 switch (point.type) { 1531 case 'dotLabel': 1532 layerDefaults = layer.labelDefaults; 1533 break; 1534 case 'htmlMarker': 1535 layerDefaults = layer.htmlDefaults; 1536 break; 1537 case 'objects': 1538 layerDefaults = layer.pointDefaults; 1539 break; 1540 default: 1541 layerDefaults = layer.pointDefaults; 1542 } 1543 if (layerDefaults && layerDefaults[propertyName] !== undefined) { 1544 return layerDefaults[propertyName]; 1545 } 1546 } 1547 } 1548 1549 // Fallback to base map defaults 1550 let defaults; 1551 switch (point.type) { 1552 case 'dotLabel': 1553 defaults = data.labelDefaults; 1554 break; 1555 case 'htmlMarker': 1556 defaults = data.htmlDefaults; 1557 break; 1558 case 'objects': 1559 defaults = data.pointDefaults; 1560 break; 1561 default: 1562 defaults = data.pointDefaults; 1563 } 1564 1565 return defaults[propertyName]; 1566}; 1567const addMarkers = function( globe, data ) { 1568 // Process base data first (without layer ID) 1569 if (data.points && data.points.length > 0) { 1570 data.points.forEach(point => { 1571 const coordinates = getCoordinates(point); 1572 const marker = createMarker$1(point, data ) 1573 .setLngLat(coordinates) 1574 .addTo(globe); 1575 1576 // Store marker reference 1577 point._marker = marker; 1578 1579 // Add click event listener 1580 marker.getElement().addEventListener('click', () => { 1581 setupClickEvent$1(globe, data, point); 1582 1583 // update ui 1584 point.post_type = 'itt_globe_point'; 1585 if ( isAdmin ) { 1586 updateUIforMarker( point, coordinates ); 1587 } 1588 }); 1589 1590 // Check for either tooltipContent or template 1591 if (point.tooltipContent || data.pointsTooltipTemplate || data.tooltipTemplate) { 1592 handleMarkerHover( 1593 globe, 1594 data, 1595 marker, 1596 point.tooltipContent, 1597 coordinates, 1598 'point', 1599 point 1600 ); 1601 } 1602 1603 }); 1604 } 1605 1606 // Add markers from objects array 1607 if (data.objects && data.objects.length > 0) { 1608 data.objects.forEach(object => { 1609 const coordinates = getCoordinates(object); 1610 const marker = createMarker$1(object, data ) 1611 .setLngLat(coordinates) 1612 .addTo(globe); 1613 1614 // Store marker reference 1615 object._marker = marker; 1616 1617 // Add click event listener 1618 marker.getElement().addEventListener('click', () => { 1619 setupClickEvent$1(globe, data, object); 1620 1621 object.post_type = 'itt_globe_point'; 1622 if ( isAdmin ) { 1623 updateUIforMarker( object, coordinates ); 1624 } 1625 }); 1626 1627 // Check for either tooltipContent or template 1628 if (object.tooltipContent || data.pointsTooltipTemplate || data.tooltipTemplate) { 1629 handleMarkerHover( 1630 globe, 1631 data, 1632 marker, 1633 object.tooltipContent, 1634 coordinates, 1635 'point', 1636 object 1637 ); 1638 } 1639 }); 1640 } 1641 1642 // Add dot labels from dotLabels array 1643 if (data.dotLabels && data.dotLabels.length > 0) {
1644 data.dotLabels.forEach(dotlabel => { 1645 dotlabel.type = 'dotLabel'; 1646 const coordinates = getCoordinates(dotlabel); 1647 const marker = createMarker$1(dotlabel, data ) 1648 .setLngLat(coordinates) 1649 .addTo(globe); 1650 1651 // Store marker reference 1652 dotlabel._marker = marker; 1653 1654 // Add click event listener 1655 marker.getElement().addEventListener('click', () => { 1656 1657 setupClickEvent$1(globe, data, dotlabel); 1658 1659 dotlabel.post_type = 'itt_globe_dotlabel'; 1660 if ( isAdmin ) { 1661 updateUIforMarker( dotlabel, coordinates ); 1662 } 1663 }); 1664 1665 // Check for either tooltipContent or template 1666 if (dotlabel.tooltipContent || data.dotLabelsTooltipTemplate || data.tooltipTemplate) { 1667 handleMarkerHover( 1668 globe, 1669 data, 1670 marker, 1671 dotlabel.tooltipContent, 1672 coordinates, 1673 'dotLabel', 1674 dotlabel 1675 ); 1676 } 1677 }); 1678 } 1679 1680 // add html labels from htmlLabels array 1681 if (data.html && data.html.length > 0) { 1682 data.html.forEach(htmlMarker => { 1683 htmlMarker.type = 'htmlMarker'; 1684 const coordinates = getCoordinates(htmlMarker); 1685 const marker = createMarker$1(htmlMarker, data ) 1686 .setLngLat(coordinates) 1687 .addTo(globe); 1688 1689 // Store marker reference 1690 htmlMarker._marker = marker; 1691 1692 // Add click event listener 1693 marker.getElement().addEventListener('click', () => { 1694 setupClickEvent$1(globe, data, htmlMarker); 1695 1696 htmlMarker.post_type = 'itt_globe_html'; 1697 if ( isAdmin ) { 1698 updateUIforMarker( htmlMarker, coordinates ); 1699 } 1700 }); 1701 1702 // Check for either tooltipContent or template 1703 if (htmlMarker.tooltipContent || data.pointsTooltipTemplate || data.tooltipTemplate) { 1704 handleMarkerHover( 1705 globe, 1706 data, 1707 marker, 1708 htmlMarker.tooltipContent, 1709 coordinates, 1710 'point', 1711 htmlMarker 1712 ); 1713 } 1714 }); 1715 } 1716 1717}; 1718// Helper function to handle marker hover 1719const handleMarkerHover = ( globe, data, marker, content, coordinates, type, originalProperties) => { 1720 const element = marker.getElement(); 1721 1722 // Show popup on hover 1723 element.addEventListener('mouseenter', (e) => { 1724 e.stopPropagation(); 1725 1726 // Close any existing popup 1727 if (globe.popup.isOpen()) { 1728 globe.popup.remove(); 1729 } 1730 1731 // Check if marker is effectively hidden 1732 const opacity = window.getComputedStyle(element).opacity; 1733 if (parseFloat(opacity) === 0) { 1734 return; // Skip showing tooltip 1735 } 1736 1737 // Calculate optimal anchor position 1738 const anchor = calculateOptimalAnchor( globe, coordinates, element); 1739 1740 // Calculate offset based on anchor position 1741 let offset = [0, 0]; 1742 if (anchor.startsWith('top')) { 1743 offset[1] = 10; // Offset below marker 1744 } else { 1745 offset[1] = -10; // Offset above marker 1746 } 1747 1748 // Adjust horizontal offset based on anchor 1749 if (anchor.endsWith('left')) { 1750 offset[0] = 10; 1751 } else if (anchor.endsWith('right')) { 1752 offset[0] = -10; 1753 } 1754 1755 // Show new popup with calculated offset
1756 const processedContent = getTooltipTemplate(type, originalProperties, data ); 1757 globe.popup.setLngLat(coordinates) 1758 .setOffset(offset) 1759 .setHTML(processedContent) 1760 .addTo(globe); 1761 }); 1762 1763 element.addEventListener('mouseleave', () => { 1764 globe.popup.remove(); 1765 }); 1766 1767 // Hide popup when mouse leaves the map 1768 globe.getCanvas().addEventListener('mouseleave', () => { 1769 globe.popup.remove(); 1770 }); 1771}; 1772 1773 1774// Add markers from points and objects arrays 1775const createMarker$1 = ( point, data ) => { 1776 let markerElement; 1777 const type = getPointProperty(point, 'type', data ); 1778 const color = getPointProperty(point, 'color', data); 1779 const hover = getPointProperty(point, 'hover', data); 1780 const radius = getPointProperty(point, 'radius', data); 1781 const image = getPointProperty(point, 'image', data); 1782 1783 switch(type) { 1784 case 'htmlMarker': 1785 let template = getPointProperty(point,'htmlTemplate', data ); 1786 1787 // now replace all {placeholders} with the point properties 1788 Object.keys(point).forEach(key => { 1789 template = template.replace(`{${key}}`, point[key]); 1790 }); 1791 1792 markerElement = document.createElement('div'); 1793 markerElement.className = 'custom-marker html-marker'; 1794 markerElement.innerHTML = template || ''; 1795 markerElement.style.color = color; 1796 markerElement.style.fontSize = point.size + 'px'; 1797 markerElement.style.transition = 'color 0.3s ease'; 1798 1799 markerElement.addEventListener('mouseenter', () => { 1800 markerElement.style.color = hover; 1801 }); 1802 markerElement.addEventListener('mouseleave', () => { 1803 markerElement.style.color = color; 1804 }); 1805 break; 1806 1807 case 'cylinder': 1808 markerElement = document.createElement('div'); 1809 markerElement.className = 'custom-marker cylinder-marker'; 1810 markerElement.style.width = radius + 'px'; 1811 markerElement.style.height = radius + 'px'; 1812 markerElement.style.backgroundColor = color; 1813 markerElement.style.border = '1px solid #e0e0e0'; 1814 markerElement.style.borderRadius = '50%'; 1815 markerElement.style.transition = 'background-color 0.3s ease'; 1816 1817 markerElement.addEventListener('mouseenter', () => { 1818 markerElement.style.backgroundColor = hover; 1819 }); 1820 markerElement.addEventListener('mouseleave', () => { 1821 markerElement.style.backgroundColor = color; 1822 }); 1823 break; 1824 1825 case 'pin': 1826 markerElement = document.createElement('div'); 1827 markerElement.className = 'custom-marker pin-marker'; 1828 markerElement.style.filter = 'drop-shadow(0 2px 4px rgba(0,0,0,0.2))'; 1829 1830 const pinHead = document.createElement('div'); 1831 pinHead.className = 'pin-head'; 1832 pinHead.style.width = radius + 'px'; 1833 pinHead.style.height = radius + 'px'; 1834 pinHead.style.backgroundColor = color; 1835 pinHead.style.borderRadius = '50%'; 1836 pinHead.style.boxShadow = 'inset -2px -2px 4px rgba(0,0,0,0.2)'; 1837 1838 const pinLine = document.createElement('div'); 1839 pinLine.className = 'pin-line'; 1840 pinLine.style.width = '6px'; // Wider at the bottom 1841 pinLine.style.height = (radius * 0.5 + (point.altitude * 2)) + 'px'; 1842 pinLine.style.background = `linear-gradient(to right, ${color} 0%, ${color} 50%, transparent 100%)`; 1843 pinLine.style.marginLeft = 'auto'; 1844 pinLine.style.marginRight = 'auto'; 1845 pinLine.style.clipPath = 'polygon(0 0, 100% 0, 50% 100%)'; 1846 pinLine.style.transformOrigin = 'top center'; 1847 pinLine.style.transform = 'scaleY(1)'; 1848 pinLine.style.boxShadow = '0 1px 2px rgba(0,0,0,0.1)'; 1849 1850 markerElement.appendChild(pinHead); 1851 markerElement.appendChild(pinLine); 1852 1853 // Add hover color change and tooltip to the entire marker 1854 markerElement.addEventListener('mouseenter', () => { 1855 pinHead.style.backgroundColor = hover; 1856 pinLine.style.background = `linear-gradient(to right, ${hover} 0%, ${hover} 50%, transparent 100%)`; 1857 }); 1858 markerElement.addEventListener('mouseleave', () => { 1859 pinHead.style.backgroundColor = color; 1860 pinLine.style.background = `linear-gradient(to right, ${color} 0%, ${color} 50%, transparent 100%)`; 1861 }); 1862 1863 // Return the marker with the element 1864 return new maplibregl.Marker({ 1865 element: markerElement, 1866 opacityWhenCovered: 0, 1867 anchor: 'bottom' 1868 }); 1869 1870 case 'dotLabel': 1871 markerElement = document.createElement('div'); 1872 markerElement.className = 'custom-marker dot-label-marker'; 1873 1874 const label = document.createElement('div'); 1875 label.className = 'dot-label-text'; 1876 label.textContent = point.title; 1877 label.style.color = color; 1878 label.style.fontSize = point.size + 'px'; 1879 label.style.textAlign = 'center'; 1880 1881 if (globe_ut_bool(point.includeDot)) { 1882 const dot = document.createElement('div'); 1883 dot.className = 'dot-label-dot';
1884 dot.style.width = radius + 'px'; 1885 dot.style.height = radius + 'px'; 1886 dot.style.backgroundColor = color; 1887 dot.style.borderRadius = '50%'; 1888 1889 // Handle dot orientation (which is actually the label side) 1890 const orientation = point.dotOrientation || 'above'; 1891 const orientationString = Array.isArray(orientation) ? orientation[0] : orientation; 1892 1893 switch(orientationString.toLowerCase()) { 1894 case 'bottom': 1895 dot.style.margin = '0 auto 5px auto'; 1896 markerElement.appendChild(dot); 1897 markerElement.appendChild(label); 1898 break; 1899 case 'top': 1900 dot.style.margin = '5px auto 0 auto'; 1901 markerElement.appendChild(label); 1902 markerElement.appendChild(dot); 1903 break; 1904 case 'right': 1905 markerElement.style.display = 'flex'; 1906 markerElement.style.alignItems = 'center'; 1907 markerElement.style.flexDirection = 'row'; 1908 dot.style.margin = '0 5px 0 0'; 1909 markerElement.appendChild(dot); 1910 markerElement.appendChild(label); 1911 break; 1912 default: // default to above 1913 dot.style.margin = '0 auto 5px auto'; 1914 markerElement.appendChild(dot); 1915 markerElement.appendChild(label); 1916 } 1917 } else { 1918 markerElement.appendChild(label); 1919 } 1920 1921 markerElement.addEventListener('mouseenter', () => { 1922 if (globe_ut_bool(point.includeDot)) { 1923 markerElement.querySelector('.dot-label-dot').style.backgroundColor = hover; 1924 } 1925 label.style.color = hover; 1926 }); 1927 1928 markerElement.addEventListener('mouseleave', () => { 1929 if (globe_ut_bool(point.includeDot)) { 1930 markerElement.querySelector('.dot-label-dot').style.backgroundColor = color; 1931 } 1932 label.style.color = color; 1933 }); 1934 break; 1935 1936 case 'image': 1937 if (image?.url) { 1938 markerElement = document.createElement('div'); 1939 markerElement.className = 'custom-marker image-marker'; 1940 const img = document.createElement('img'); 1941 img.src = image.url; 1942 img.style.width = radius + 'px'; 1943 img.style.height = 'auto'; 1944 markerElement.appendChild(img); 1945 } 1946 break; 1947 1948 case 'flag': 1949 markerElement = document.createElement('div'); 1950 markerElement.className = 'custom-marker flag-marker'; 1951 1952 // Create flag pole 1953 const flagPole = document.createElement('div'); 1954 flagPole.className = 'flag-pole'; 1955 flagPole.style.width = '2px'; 1956 // Calculate pole height based on altitude, with a minimum height 1957 const baseHeight = radius * 0.5; 1958 const altitude = point.altitude || 0; 1959 const scaledHeight = baseHeight + (altitude * 2); // Scale factor of 2 for better visibility 1960 flagPole.style.height = Math.max(baseHeight, scaledHeight) + 'px'; 1961 flagPole.style.backgroundColor = '#666'; 1962 flagPole.style.position = 'absolute'; 1963 flagPole.style.left = '0'; 1964 flagPole.style.bottom = '0'; 1965 flagPole.style.zIndex = '1'; 1966 1967 // Create flag container 1968 const flagContainer = document.createElement('div'); 1969 flagContainer.className = 'flag-container'; 1970 flagContainer.style.width = (radius * 1.5) + 'px'; 1971 flagContainer.style.height = radius + 'px'; 1972 flagContainer.style.position = 'absolute'; 1973 flagContainer.style.left = '2px'; 1974 flagContainer.style.bottom = (Math.max(baseHeight, scaledHeight) - radius) + 'px'; // Align with top of pole 1975 flagContainer.style.overflow = 'hidden'; 1976 flagContainer.style.zIndex = '2'; 1977 1978 if (image?.url) { 1979 // If image is provided, use it as the flag 1980 const flagImage = document.createElement('img'); 1981 flagImage.src = image.url; 1982 flagImage.style.width = '100%'; 1983 flagImage.style.height = '100%'; 1984 flagImage.style.objectFit = 'cover'; 1985 flagContainer.appendChild(flagImage); 1986 } else { 1987 // If no image, use a colored rectangle 1988 const flagColor = document.createElement('div'); 1989 flagColor.style.width = '100%'; 1990 flagColor.style.height = '100%'; 1991 flagColor.style.backgroundColor = color; 1992 flagContainer.appendChild(flagColor); 1993 } 1994 1995 markerElement.appendChild(flagPole); 1996 markerElement.appendChild(flagContainer); 1997 1998 return new maplibregl.Marker({ 1999 element: markerElement, 2000 anchor: 'bottom', 2001 offset: [-2, 0], // Offset to align with pole base 2002 rotationAlignment: 'map', 2003 pitchAlignment: 'map', 2004 opacityWhenCovered: 0, 2005 }); 2006 2007 case 'marker': 2008 default: 2009 // Use default MapLibre marker with custom color
2010 const defaultMarker = new maplibregl.Marker({ 2011 color: color, 2012 scale: radius / 30, 2013 rotationAlignment: 'map', 2014 pitchAlignment: 'map', 2015 opacityWhenCovered: 0, 2016 }); 2017 2018 // Add hover color change 2019 const defaultMarkerElement = defaultMarker.getElement(); 2020 defaultMarkerElement.addEventListener('mouseenter', () => { 2021 defaultMarkerElement.querySelector('path').style.fill = hover; 2022 }); 2023 defaultMarkerElement.addEventListener('mouseleave', () => { 2024 defaultMarkerElement.querySelector('path').style.fill = color; 2025 }); 2026 2027 return defaultMarker; 2028 } 2029 2030 // Return custom marker if element was created 2031 if (markerElement) { 2032 return new maplibregl.Marker({ 2033 element: markerElement, 2034 anchor: type === 'pin' ? 'center' : 'center', 2035 rotationAlignment: 'map', 2036 pitchAlignment: 'map', 2037 opacityWhenCovered: 0, 2038 }); 2039 } 2040 2041 // Fallback to default marker 2042 return new maplibregl.Marker({ 2043 color: color, 2044 scale: radius / 30, 2045 rotationAlignment: 'map', 2046 pitchAlignment: 'map', 2047 opacityWhenCovered: 0, 2048 }); 2049}; 2050 2051 2052 2053const updateUIforMarker = ( marker, coordinates ) => { 2054 coordinates.latitude = truncateTo3Decimals( coordinates[1] ); 2055 coordinates.longitude = truncateTo3Decimals( coordinates[0] ); 2056 2057 marker.coordinates = coordinates; 2058 2059 2060 // if clicked empty region, set title 2061 if( typeof marker.title === 'undefined' ){ 2062 marker.title = marker.name || marker.id; 2063 } 2064 2065 let preview = {}; 2066 preview.clickedDataset = { 2067 marker_id : marker.id || marker.id, 2068 title : marker.name, 2069 isActive: true 2070 }; 2071 2072 preview.clickedElement = Object.assign({}, marker ); 2073 preview.clickedElement.text = 'Marker'; 2074 preview.clickedElement.type = 'Marker'; 2075 preview.clickedElement.post_type = marker.post_type; 2076 2077 2078 updatePreviewUI( preview.clickedDataset, preview.clickedElement ); 2079}; 2080 2081// Add filter interaction logic for maplibre maps 2082const setupMaplibreLayers = (globe, data ) => { 2083 data.layers.forEach((layer, index) => { 2084 // Use layer.id if available, otherwise generate one 2085 const layerId = layer.id || `layer_${index}`; 2086 2087 processLayer( globe, data, layer, layerId); 2088 }); 2089}; 2090 2091 2092// Function to process a single layer's data 2093 2094// todo add extra param to calls 2095const processLayer = (globe, data, layerData, layerId) => { 2096 // Process points 2097 if (layerData.points && layerData.points.length > 0) { 2098 layerData.points.forEach((point, index) => { 2099 // Add layer ID to the point 2100 point._layerId = layerId; 2101 2102 // Inherit defaults from layer if not specified 2103 if (!point.useCustom) { 2104 // Update the original object instead of creating a new one 2105 Object.assign(point, { 2106 ...layerData.pointDefaults, 2107 color: point.color || layerData.pointDefaults?.color, 2108 hover: point.hover || layerData.pointDefaults?.hover 2109 }); 2110 } 2111 2112 const coordinates = getCoordinates(point); 2113 const marker = createMarker$1(point, data ) 2114 .setLngLat(coordinates) 2115 .addTo(globe); 2116 2117 // Store marker reference - this will now work correctly 2118 point._marker = marker; 2119 2120 // Add click event listener 2121 marker.getElement().addEventListener('click', () => { 2122 // Ensure we have all necessary data for the click event 2123 const clickData = { 2124 ...point, 2125 action: point.action || layerData.action || data.action, 2126 actionTarget: point.actionTarget || layerData.actionTarget || data.actionTarget, 2127 actionValue: point.actionValue || layerData.actionValue || data.actionValue, 2128 globe_id: point.globe_id || layerData.globe_id || data.id 2129 }; 2130 globe.setupClickEvent(globe, data, clickData); 2131 }); 2132 2133 // Add hover effects if needed 2134 if (point.tooltipContent || data.pointsTooltipTemplate || data.tooltipTemplate) { 2135 handleMarkerHover( 2136 globe, 2137 data, 2138 marker, 2139 point.tooltipContent, 2140 coordinates, 2141 'point', 2142 point 2143 ); 2144 } 2145 }); 2146 } 2147 2148 // Process objects 2149 if (layerData.objects && layerData.objects.length > 0) { 2150 layerData.objects.forEach(object => { 2151 // Add layer ID to the object 2152 object._layerId = layerId; 2153 // Inherit defaults from layer if not specified 2154 if (!globe_ut_bool(object.useCustom)) { 2155 Object.assign(object, { 2156 ...layerData.pointDefaults, 2157 color: object.color || layerData.pointDefaults?.color, 2158 hover: object.hover || layerData.pointDefaults?.hover 2159 }); 2160 } 2161 const coordinates = getCoordinates(object); 2162 const marker = createMarker$1(object, data ) 2163 .setLngLat(coordinates) 2164 .addTo(globe); 2165 2166 // Store marker reference 2167 object._marker = marker; 2168 2169 // Add click event listener 2170 marker.getElement().addEventListener('click', () => { 2171 // Ensure we have all necessary data for the click event 2172 const clickData = { 2173 ...object, 2174 action: object.action || layerData.action || data.action, 2175 actionTarget: object.actionTarget || layerData.actionTarget || data.actionTarget, 2176 actionValue: object.actionValue || layerData.actionValue || data.actionValue, 2177 globe_id: object.globe_id || layerData.globe_id || data.id 2178 }; 2179 globe.setupClickEvent(globe, data, clickData); 2180 }); 2181 2182 // Add hover effects if needed 2183 if (object.tooltipContent || data.pointsTooltipTemplate || data.tooltipTemplate) { 2184 handleMarkerHover( 2185 globe, 2186 data, 2187 marker, 2188 object.tooltipContent, 2189 coordinates, 2190 'point', 2191 object 2192 ); 2193 } 2194 }); 2195 } 2196 2197 // Process dot labels 2198 if (layerData.dotLabels && layerData.dotLabels.length > 0) {
2199 layerData.dotLabels.forEach(label => { 2200 // Add layer ID to the label 2201 label._layerId = layerId; 2202 label.type = 'dotLabel'; 2203 // Inherit defaults from layer if not specified 2204 if (!globe_ut_bool(label.useCustom)) { 2205 Object.assign(label, { 2206 ...layerData.labelDefaults, 2207 color: label.color || layerData.labelDefaults?.color, 2208 hover: label.hover || layerData.labelDefaults?.hover 2209 }); 2210 } 2211 const coordinates = getCoordinates(label); 2212 const marker = createMarker$1(label, data ) 2213 .setLngLat(coordinates) 2214 .addTo(globe); 2215 2216 // Store marker reference 2217 label._marker = marker; 2218 2219 // Add click event listener 2220 marker.getElement().addEventListener('click', () => { 2221 // Ensure we have all necessary data for the click event 2222 const clickData = { 2223 ...label, 2224 action: label.action || layerData.action || data.action, 2225 actionTarget: label.actionTarget || layerData.actionTarget || data.actionTarget, 2226 actionValue: label.actionValue || layerData.actionValue || data.actionValue, 2227 globe_id: label.globe_id || layerData.globe_id || data.id 2228 }; 2229 globe.setupClickEvent(globe, data, clickData); 2230 }); 2231 2232 // Add hover effects if needed 2233 if (label.tooltipContent || data.dotLabelsTooltipTemplate || data.tooltipTemplate) { 2234 handleMarkerHover( 2235 globe, 2236 data, 2237 marker, 2238 label.tooltipContent, 2239 coordinates, 2240 'dotLabel', 2241 label 2242 ); 2243 } 2244 }); 2245 } 2246 2247 // Process HTML markers 2248 if (layerData.html && layerData.html.length > 0) { 2249 layerData.html.forEach(htmlMarker => { 2250 // Add layer ID to the HTML marker 2251 htmlMarker._layerId = layerId; 2252 htmlMarker.type = 'htmlMarker'; 2253 // Inherit defaults from layer if not specified 2254 if (!globe_ut_bool(htmlMarker.useCustom)) { 2255 Object.assign(htmlMarker, { 2256 ...layerData.htmlDefaults, 2257 color: htmlMarker.color || layerData.htmlDefaults?.color, 2258 hover: htmlMarker.hover || layerData.htmlDefaults?.hover 2259 }); 2260 } 2261 const coordinates = getCoordinates(htmlMarker); 2262 const marker = createMarker$1(htmlMarker, data ) 2263 .setLngLat(coordinates) 2264 .addTo(globe); 2265 2266 // Store marker reference 2267 htmlMarker._marker = marker; 2268 2269 // Add click event listener 2270 marker.getElement().addEventListener('click', () => { 2271 // Ensure we have all necessary data for the click event 2272 const clickData = { 2273 ...htmlMarker, 2274 action: htmlMarker.action || layerData.action || data.action, 2275 actionTarget: htmlMarker.actionTarget || layerData.actionTarget || data.actionTarget, 2276 actionValue: htmlMarker.actionValue || layerData.actionValue || data.actionValue, 2277 globe_id: htmlMarker.globe_id || layerData.globe_id || data.id 2278 }; 2279 globe.setupClickEvent(globe, data, clickData); 2280 }); 2281 2282 // Add hover effects if needed 2283 if (htmlMarker.tooltipContent || data.pointsTooltipTemplate || data.tooltipTemplate) { 2284 handleMarkerHover( 2285 globe, 2286 data, 2287 marker, 2288 htmlMarker.tooltipContent, 2289 coordinates, 2290 'point', 2291 htmlMarker 2292 ); 2293 } 2294 }); 2295 } 2296 2297 // Process regions 2298 if (layerData.regions && layerData.regions.length > 0) { 2299 // Add regions to the main regions array with layer ID 2300 2301 layerData.regions.forEach(region => { 2302 region._layerId = layerId; 2303 // Inherit defaults from layer if not specified 2304 if (!globe_ut_bool(region.useCustom)) { 2305 Object.assign(region, { 2306 ...layerData.regionDefaults, 2307 color: region.color || layerData.regionDefaults?.color, 2308 hover: region.hover || layerData.regionDefaults?.hover 2309 }); 2310 } 2311 // Add to the main data.regions array 2312 if (!data.regions) data.regions = []; 2313 data.regions.push(region); 2314 }); 2315 } 2316 2317 // Process lines 2318 if (layerData.arcLines && layerData.arcLines.length > 0) { 2319 // Add lines to the main arcLines array with layer ID 2320 layerData.arcLines.forEach(line => { 2321 line._layerId = layerId; 2322 2323 // Add to the main data.arcLines array 2324 if (!data.arcLines) data.arcLines = []; 2325 data.arcLines.push(line); 2326 }); 2327 } 2328}; 2329 2330const getRegionProperty = (region, propertyName, data, fallback ) => { 2331 if (globe_ut_bool(region.useCustom)) { 2332 return region[propertyName]; 2333 } 2334 // If region has a layer ID, use that layer's defaults 2335 if (region.sourceId && data.layers) { 2336 const layer = data.layers.find(l => l.id === region.sourceId); 2337 if (layer && layer.regionDefaults) { 2338 return layer.regionDefaults[propertyName]; 2339 } 2340 } 2341 // Fallback to base map defaults 2342 return data.regionDefaults?.[propertyName] || fallback; 2343}; 2344 2345const normalizeRegion = (region, data ) => ({ 2346 ...region, 2347 color: getRegionProperty(region, 'color', data, '#c9c9c9'), 2348 hover: getRegionProperty(region, 'hover', data, '#a0a0a0'), 2349 strokeColor: getRegionProperty(region, 'strokeColor', data, '#f0f
23490f0'), 2350 tooltipContent: region.tooltipContent 2351}); 2352 2353const isDictEmpty = (obj) => { 2354 for (let key in obj) { 2355 if (obj.hasOwnProperty(key)) { 2356 return false; 2357 } 2358 } 2359 return true; 2360}; 2361 2362const findFeature = (regionFeatures, regionIdOrList, lookupId ) => { 2363 // Try direct lookup 2364 2365 if (Array.isArray(regionIdOrList)) { 2366 return regionIdOrList.map(element => 2367 findFeature(regionFeatures, element, lookupId) 2368 ); 2369 } 2370 let feature = regionFeatures[regionIdOrList]; 2371 if (feature) return feature; 2372 2373 // Search by dynamic property 2374 return Object.values(regionFeatures).find(f => 2375 f.properties?.[lookupId] === regionIdOrList 2376 ) || null; 2377}; 2378 2379const pointOfView = (globe, data, element, transitionMs ) => { 2380 if (!element) return; 2381 2382 // Define zoom level and animation options 2383 const zoomLevel = element.zoomLevel || 4; 2384 const animationDuration = 1500; 2385 2386 // For markers (points, objects, dotLabels, html) 2387 if (element.coordinates || element.longitude || element.lat) { 2388 const coordinates = element.coordinates ? 2389 [element.coordinates.longitude, element.coordinates.latitude] : 2390 [element.longitude || element.lng || 0, element.latitude || element.lat || 0]; 2391 2392 // Fly to the coordinates 2393 globe.flyTo({ 2394 center: coordinates, 2395 //zoom: zoomLevel, // where does this come from 2396 duration: animationDuration, 2397 essential: true 2398 }); 2399 } 2400 // For regions 2401 else if (element.type === 'regions' && globe.getSource('regions')) { 2402 // Handle region ID that might be an array and might be in different locations 2403 // First check element.id (original format) 2404 let regionIdOrList; 2405 2406 if (element.id) { 2407 regionIdOrList = element.id; 2408 } 2409 // Then check element.properties.id (format from some event handlers) 2410 else if (element.properties && element.properties.id) { 2411 regionIdOrList = element.properties.id; 2412 } 2413 if (!regionIdOrList) { 2414 return; 2415 } 2416 let regionFirstId = regionIdOrList; 2417 if( Array.isArray( regionIdOrList ) ) { 2418 regionFirstId = regionIdOrList[0]; 2419 } 2420 2421 2422 // Define known region centers for common regions 2423 const knownRegionCenters = { 2424 'asia': { center: [100, 30], zoom: 2.5 }, 2425 'africa': { center: [20, 0], zoom: 2.5 }, 2426 'europe': { center: [15, 50], zoom: 3 }, 2427 'northAmerica': { center: [-100, 40], zoom: 2.5 }, 2428 'southAmerica': { center: [-60, -20], zoom: 2.5 }, 2429 'australia': { center: [135, -25], zoom: 3 }, 2430 'antarctica': { center: [0, -90], zoom: 2 }, 2431 'oceania': { center: [150, -10], zoom: 3 } 2432 }; 2433 2434 // Check if this is a known region - normalize the ID for comparison 2435 const normalizedId = regionFirstId.toLowerCase().replace(/\s+/g, '-'); 2436 2437 // If it's a known region, use predefined center and zoom 2438 if (knownRegionCenters[normalizedId]) { 2439 const regionConfig = knownRegionCenters[normalizedId]; 2440 2441 globe.flyTo({ 2442 center: regionConfig.center, 2443 zoom: regionConfig.zoom || (zoomLevel - 1), // Use predefined zoom or default 2444 duration: animationDuration, 2445 essential: true 2446 }); 2447 return; 2448 } 2449 2450 let lookupId = 'id'; 2451 const isRegionOtherSourceEnabled = data.regionsDataSource?.enabled || false; 2452 if ( isRegionOtherSourceEnabled != 0 ) { 2453 lookupId = data.regionsDataSource?.json_id || 'id'; 2454 } 2455 2456 setTimeout(() => { 2457 // Wait a bit for tiles to load 2458 const allRegionFeatures = globe.allRegionsLookup; 2459 if ( isDictEmpty( allRegionFeatures ) ) { 2460 console.debug('the Lookup is empty' ); 2461 return; 2462 } 2463 2464 const availableRegions = findFeature( allRegionFeatures, regionIdOrList, lookupId ); 2465 if ( ! availableRegions ) { 2466 console.error('No Region found with ID:', regionIdOrList ); 2467 return; 2468 } 2469 2470 // Create a bounds object to encompass ALL parts of the region 2471 const bounds = new maplibregl.LngLatBounds(); 2472 let hasValidCoords = false; 2473 2474 try { 2475 // Process all features that match this region ID 2476 // for each availableRegion find the bounds: 2477 availableRegions.forEach( feature => { 2478 2479 if (feature.geometry.type === 'Polygon') { 2480 // For polygons, process all rings (first is outer, rest are holes) 2481 feature.geometry.coordinates.forEach((ring, ringIndex) => { 2482 // Only process outer ring (index 0) for bounds 2483 if (ringIndex === 0) { 2484 ring.forEach(coord => { 2485 if (Array.isArray(coord) && coord.length >= 2) { 2486 bounds.extend(coord); 2487 hasValidCoords = true; 2488 } 2489 }); 2490 } 2491 }); 2492 } 2493 else if (feature.geometry.type === 'MultiPolygon') { 2494 // For multi-polygons, process each polygon's outer ring
2495 feature.geometry.coordinates.forEach(polygon => { 2496 if (Array.isArray(polygon) && polygon.length > 0) { 2497 // Get the outer ring of this polygon (index 0) 2498 const outerRing = polygon[0]; 2499 if (Array.isArray(outerRing)) { 2500 outerRing.forEach(coord => { 2501 if (Array.isArray(coord) && coord.length >= 2) { 2502 bounds.extend(coord); 2503 hasValidCoords = true; 2504 } 2505 }); 2506 } 2507 } 2508 }); 2509 } 2510 }); 2511 2512 if (hasValidCoords) { 2513 2514 // Fit the map to the bounds of the entire region 2515 globe.fitBounds(bounds, { 2516 padding: {top: 10, bottom: 10, left: 10, right: 10}, // More flexible padding 2517 duration: animationDuration, 2518 maxZoom: zoomLevel 2519 }); 2520 } else { 2521 throw new Error('No valid coordinates found in any region geometry'); 2522 } 2523 } catch (error) { 2524 console.error('Error fitting region to view:', error); 2525 } 2526 }, 100); 2527 } 2528}; 2529 2530// Add hover effects for regions 2531let hoveredRegionId = null; 2532let hoveredSourceId = null; 2533 2534/** 2535 * Adds geojson regions layer 2536 * @param {*} globe 2537 * @param {*} data 2538 */ 2539 2540const addRegions = async function( globe, data, regionDataLookup = {} ) { 2541 2542 let allRegions = Object.create(null); 2543 // Get keepBase value from data.liveFilter at the start of the function 2544 data.liveFilter && data.liveFilter.keepBase ? data.liveFilter.keepBase : '0'; 2545 2546 2547 // Process base map regions if enabled 2548 if (data.regionSource !== 'disabled' && data.regionSource && data.regions) { 2549 let fullpath; 2550 if (data.regionSource !== 'custom') { 2551 let geojson_source = data.regionSource; 2552 if (!geojson_source.includes('.geojson') && !geojson_source.includes('.json')) { 2553 geojson_source += '.json'; 2554 } 2555 fullpath = ittGlobeData.assetsUrl + 'geojson/' + geojson_source; 2556 } else { 2557 fullpath = data.regionCustomSourceURL; 2558 } 2559 2560 const baseGeoJSONData = await loadGeoJSONData(fullpath); 2561 if (baseGeoJSONData) { 2562 // Get keepBase value from the filter container 2563 const baseRegions = await processRegionsData(globe, data, baseGeoJSONData, regionDataLookup, 'regions' ); 2564 allRegions = { ...allRegions, ...baseRegions }; 2565 } 2566 } 2567 2568 // Process regions from layers independently 2569 if (data.layers && Array.isArray(data.layers)) { 2570 2571 let layerRegions = {}; 2572 for (const layer of data.layers) { 2573 if (layer.regions && layer.regions.length > 0 && layer.regionSource) { 2574 let layerFullpath; 2575 if (layer.regionSource !== 'custom') { 2576 let layerGeojsonSource = layer.regionSource; 2577 if (!layerGeojsonSource.includes('.geojson') && !layerGeojsonSource.includes('.json')) { 2578 layerGeojsonSource += '.json'; 2579 } 2580 layerFullpath = ittGlobeData.assetsUrl + 'geojson/' + layerGeojsonSource; 2581 } else { 2582 layerFullpath = layer.regionCustomSourceURL; 2583 } 2584 2585 const layerGeoJSONData = await loadGeoJSONData(layerFullpath); 2586 if (layerGeoJSONData) { 2587 const sourceId = `regions-${layer.id || layer.name || Math.random().toString(36).substr(2, 9)}`; 2588 const layerRegionsDict = prepareDataRegions( layer, sourceId ) || {}; 2589 // Create a context object with layer regions to ensure correct active IDs calculation 2590 // Merge layer properties to respect layer-specific settings 2591 // Force onlyActiveRegions to true to accumulate active regions without obscuring underlying layers with inactive ones 2592 const layerData = { 2593 ...data, 2594 ...layer, 2595 onlyActiveRegions: true 2596 }; 2597 2598 layerRegions = await processRegionsData( globe, layerData, layerGeoJSONData, layerRegionsDict, sourceId ); 2599 allRegions = { ...allRegions, ...layerRegions }; 2600 } 2601 } 2602 } 2603 } 2604 2605 2606 // Add hover and click events to all region elements ( libremap calls it layers ) 2607 const regionElements = globe.getStyle().layers 2608 .filter(layer => layer.id.endsWith('-fills')) 2609 .map(layer => layer.id); 2610 2611 regionElements.forEach(layerId => { 2612 globe.on('mousemove', layerId, createGlobeHandler(mapLibreHandleHoverEvent, globe, data )); 2613 globe.on('mouseleave', layerId, () => { 2614 if (hoveredRegionId && hoveredSourceId) { 2615 globe.setFeatureState( 2616 { source: hoveredSourceId, id: hoveredRegionId }, 2617 { hover: false } 2618 ); 2619 } 2620 hoveredRegionId = null; 2621 hoveredSourceId = null; 2622 globe.popup.remove(); 2623 }); 2624 globe.on('click', layerId, createGlobeHandler(mapLibreHandleRegionClick, globe, data )); 2625 }); 2626 2627 return allRegions; 2628}; 2629 2630 2631// Function to load and process GeoJSON data 2632const loadGeoJSONData = async (sourceUrl) => { 2633 try { 2634 const response = await fetch(sourceUrl); 2635 return await response.json(); 2636 } catch (error) { 2637 console.error('Error loading GeoJSON:', error); 2638 return null; 2639 } 2640}; 2641 2642const createGlobeHandler = (handler, globe, data ) => { 2643 return (e) => handler(globe, data, e ); 2644}; 2645const mapLibreHandleRegionClick = (globe, data, e ) => { 2646 2647 if (e.originalEvent.target.classList.contains('maplibregl-marker') 2648 || e.originalEvent.target.classList.contains('itt_globe_html') 2649 || e.originalEvent.target.classList.contains('itt_globe_dot_label') 2650 || e.originalEvent.target.classList.contains('itt_globe_point') 2651 || e.originalEvent.target.classList.contains('pin-head') 2652 || e.originalEvent.target.classList.contains('dot-label-dot') 2653 || e.originalEvent.target.classList.contains('dot-label-marker') 2654 || e.originalEvent.target.classList.contains('itt_globe_line') 2655 || e.originalEvent.target.classList.contains('itt_globe_html_marker') 2656 || e.originalEvent.target.tagName.toLowerCase() === 'img' 2657 || e.originalEvent.target.tagName.toLowerCase() === 'path') { 2658 2659 return // Click target was a marker so do nothing⦠2660 } 2661 // update 2662 if (e && e.features && e.features.length > 0) { 2663 const region = e.features[0]; 2664 setupClickEvent$1(globe, data, region.properties); 2665 // update the prview UI 2666 if ( isAdmin ) { 2667 updateUIforRegion( e.features[0], e.lngLat ); 2668 } 2669 2670 } 2671}; 2672 2673 2674const updateUIforRegion = ( region, coordinates ) => { 2675 coordinates.latitude = truncateTo3Decimals( coordinates.lat ); 2676 coordinates.longitude = truncateTo3Decimals( coordinates.lng ); 2677
2678 region.properties.coordinates = coordinates; 2679 2680 2681 // if clicked empty region, set title 2682 if( typeof region.properties.title === 'undefined' ){ 2683 region.properties.title = region.properties.name || region.id; 2684 } 2685 let preview = {}; 2686 preview.clickedDataset = { 2687 region_id : region.properties.id || region.id, 2688 title : region.properties.name, 2689 geojson : getGeojsonVal(), 2690 geojsonURL : getGeojsonUrlVal(), 2691 isActive: region.properties.isActive == 1 || region.properties.isActive === true 2692 }; 2693 2694 preview.clickedElement = Object.assign({}, region.properties); 2695 preview.clickedElement.text = 'in a location in Region'; 2696 preview.clickedElement.type = 'Region'; 2697 preview.clickedElement.post_type = 'itt_globe_region'; 2698 2699 2700 updatePreviewUI( preview.clickedDataset, preview.clickedElement ); 2701}; 2702 2703 2704// Add hover effects for all region layers 2705const mapLibreHandleHoverEvent = (globe, data, e) => { 2706 2707 if ( e.features.length > 0) { 2708 const region = e.features[0]; 2709 const regionId = region.id; 2710 const isActive = region.properties.isActive; 2711 const sourceId = region.properties.sourceId; 2712 2713 // Get the current feature state to check visibility 2714 const featureState = globe.getFeatureState({ source: sourceId, id: regionId }); 2715 const isVisible = featureState && featureState.visible; 2716 2717 // Only proceed if the region is active and visible 2718 if (isActive && isVisible) { 2719 if (hoveredRegionId !== regionId || hoveredSourceId !== sourceId) { 2720 // Clear previous hover state if it exists 2721 if (hoveredRegionId && hoveredSourceId) { 2722 globe.setFeatureState( 2723 { source: hoveredSourceId, id: hoveredRegionId }, 2724 { hover: false } 2725 ); 2726 } 2727 2728 // Set new hover state 2729 hoveredRegionId = regionId; 2730 hoveredSourceId = sourceId; 2731 globe.setFeatureState( 2732 { source: sourceId, id: hoveredRegionId }, 2733 { hover: true } 2734 ); 2735 2736 // Show tooltip if available and not hovering a marker 2737 if (region.properties.tooltipContent) { 2738 const processedContent = getTooltipTemplate('region', region.properties, data ); 2739 globe.popup.setLngLat(e.lngLat) 2740 .setHTML(processedContent) 2741 .addTo(globe); 2742 } 2743 } 2744 } else { 2745 // If region is not visible or not active, ensure hover state is cleared 2746 if (hoveredRegionId === regionId && hoveredSourceId === sourceId) { 2747 globe.setFeatureState( 2748 { source: sourceId, id: regionId }, 2749 { hover: false } 2750 ); 2751 hoveredRegionId = null; 2752 hoveredSourceId = null; 2753 globe.popup.remove(); 2754 } 2755 } 2756 } 2757}; 2758 2759const prepareDataRegions = function ( data, sourceId ){ 2760 // foreach data. 2761 if (!data.regions || data.regions.length === 0) { 2762 return; 2763 } 2764 const selectedRegionsIndividually = data.regions.reduce((acc, region) => { 2765 2766 // save original id, to use for grouped hover 2767 region.originalId = region.id; 2768 2769 // Destructure the region to get all properties except ids 2770 const { id, ...regionProps } = region; 2771 if ( ! id ) { 2772 return acc; 2773 } 2774 2775 // Convert string id to array if needed 2776 if (typeof id === 'string') { 2777 id = id.includes(',') ? id.split(',').map(i => i.trim()) : [id]; 2778 } 2779 2780 // Create new objects with all region properties and the individual id 2781 const idsWithProps = id.map(id => ( 2782 { 2783 ...regionProps, 2784 id: id, 2785 sourceId: sourceId, // Store the source ID in properties 2786 })); 2787 return acc.concat(idsWithProps); 2788 }, []); 2789 2790 2791 // Convert the selection of regions array to a dictionary for quick lookup 2792 2793 const regionsDict = selectedRegionsIndividually.reduce((acc, region) => { 2794 const ids = Array.isArray(region.id) ? region.id : [region.id]; 2795 const normalized = normalizeRegion(region, data); 2796 2797 ids.forEach(id => { 2798 if (!id) { 2799 console.warn('Region missing ID:', region); 2800 return; 2801 } 2802 acc[String(id)] = normalized; 2803 }); 2804 2805 // Optional: also store by title (for country name lookup) 2806 if (region.title) { 2807 acc[region.title] = normalized; 2808 } 2809 // Store by name as well (if different from title) 2810 if (region.name) { 2811 acc[region.name] = normalized; 2812 } 2813 return acc; 2814 }, Object.create(null)); // use null prototype for faster lookups 2815 2816 return regionsDict; 2817}; 2818 2819 2820// Function to process regions data 2821const processRegionsData = (globe, data, geojsonData, regionDataLookup, sourceId ) => { 2822 2823 const allRegions = []; 2824 if ( ! geojsonData) { 2825 return allRegions; 2826 } 2827 2828 // todo: maybe replace with this regionDataLookup 2829 let activeRegionIds = []; 2830 2831 if ( data.regions?.length ) { 2832 activeRegionIds = data.regions.flatMap(region => Array.isArray(region.id) ? region.id : [region.id]); 2833 } 2834 // Only filter features if onlyActiveRegions is true 2835 const shouldFilterRegions = globe_ut_bool(data.onlyActiveRegions); 2836 2837 if (shouldFilterRegions) { 2838 geojsonData.features = geojsonData.features.filter(feature => { 2839 return activeRegionIds.includes(feature.properties.id); 2840 }); 2841 } 2842 const keepBaseValue = data.liveFilter && data.liveFilter.keepBase ? data.liveFilter.keepBase : '0'; 2843 2844 2845 const lookupjsonid = data.regionsDataSource?.json_id || 'id'; 2846 2847 const features = geojsonData.features.map( (feature, index ) => { 2848 const originalId = feature.properties.id; 2849 const regionId = String(originalId); 2850 2851 const regionData = regionDataLookup[regionId] || {}; 2852 const isActive = activeRegionIds.includes(regionId); 2853 2854 let search_term = originalId; 2855 const isRegionOtherSourceEnabled = data.regionsDataSource?.enabled || false; 2856 if ( isRegionOtherSourceEnabled != 0 ) { 2857 search_term = regionData?.[lookupjsonid]; 2858 } 2859 2860 // Create a new feature with integer ID and original ID in properties 2861 return { 2862 ...feature, 2863 id: index, // Assign unique integer ID 2864 properties: { 2865 ...regionData, 2866 ...feature.properties, 2867 originalId: originalId, // Store original ID in properties 2868 id: originalId, // Keep original ID in properties for compatibility 2869 searchTerm: search_term, 2870 isActive: isActive, 2871 sourceId: sourceId, // Store the source ID in properties 2872 globe_id: regionData.globe_id || data.id // Ensure globe_id is set 2873 } 2874 }; 2875 }); 2876 2877 // Add source ( all the data ) 2878 globe.addSource(sourceId, { 2879 type: 'geojson', 2880 data: { 2881 ...geojsonData, 2882 features: features 2883 } 2884 }); 2885 2886 // Also create dict for lookups 2887 const featuresDict = features.reduce((acc, feature) => { 2888 const id = String(feature.properties.originalId); 2889 acc[id] = feature; 2890 2891 if (feature.properties.name) { 2892 acc[feature.properties.name] = feature; 2893 } 2894 2895 return acc; 2896 }, Object.create(null)); 2897 2898 const hasRegions = Object.keys(regionDataLookup || {}).length > 0; 2899 2900 const hoverMatch = hasRegions ? [ 2901 'match', 2902 ['get', 'id'], 2903 ...Object.entries(regionDataLookup).map(([id, props]) => [id, props.hover]).flat(), 2904 data.regionDefaults.hover || '#a0a0a0' 2905 ] 2906 : data.regionDefaults.hover || '#a0a0a0'; 2907 2908 const activeMatch = hasRegions ? [ 2909 'match', 2910 ['get', 'id'], 2911 ...Object.entries(regionDataLookup).map(([id, props]) => [id, props.color]).flat(), 2912 data.regionDefaults.inactive || '#c9c9c9' 2913 ] 2914 : data.regionDefaults.inactive || '#c9c9c9'; 2915 2916 const regionsStrokeColor = data.regionDefaults?.strokeColor || '#f0f0f0'; 2917 const strokeMatch = hasRegions ? [ 2918 'match', 2919 ['get', 'id'], 2920 ...Object.entries(regionDataLookup).map(([id, props]) => [ 2921 id, 2922 props.strokeColor ?? ( regionsStrokeColor ) 2923 ]).flat(), 2924 regionsStrokeColor 2925 ] 2926 : regionsStrokeColor; 2927 2928 // Add regions style layer for Fill 2929 globe.addLayer({ 2930 id: `${sourceId}-fills`, 2931 type: 'fill', 2932 source: sourceId, 2933 paint: { 2934 'fill-color': [ 2935 'case', 2936 ['all', 2937 ['boolean', ['feature-state', 'hover'], false], 2938 ['get', 'isActive'] 2939 ], 2940 hoverMatch, 2941 ['get', 'isActive'], 2942 activeMatch, 2943 data.regionDefaults.inactive || '#c9c9c9' 2944 ], 2945 'fill-opacity': [ 2946 'case', 2947 ['boolean', ['feature-state', 'visible'], false], 2948 0.9, 2949 0 2950 ] 2951 } 2952 }); 2953 2954 // Add regions style layer for borders 2955 globe.addLayer({ 2956 id: `${sourceId}-borders`, 2957 type: 'line', 2958 source: sourceId, 2959 paint: { 2960 'line-color': [ 2961 'case', 2962 ['get', 'isActive'], 2963 strokeMatch, 2964 data.regionDefaults.strokeColor || '#f0f0f0' 2965 ], 2966 'line-width': 0.5, 2967 'line-opacity': [ 2968 'case', 2969 ['boolean', ['feature-state', 'visible'], false], 2970 0.9, 2971 0 2972 ] 2973 } 2974 }); 2975 2976 2977 // Wait for the source to be loaded before setting feature states 2978 globe.on('sourcedata', (e) => {
2979 if (e.sourceId === sourceId && globe.isSourceLoaded(sourceId)) { 2980 2981 // Check if live filter is enabled and has a default value 2982 const hasLiveFilter = globe_ut_bool(data.liveFilter?.enabled); 2983 const defaultGlobeId = data.liveFilter?.default; 2984 2985 2986 const shouldFilterRegions = globe_ut_bool(data.onlyActiveRegions); 2987 features.forEach(feature => { 2988 if (feature.id !== undefined) { 2989 const isActive = feature.properties.isActive; 2990 const featureGlobeId = feature.properties.globe_id; 2991 2992 // Determine initial visibility based on live filter settings 2993 let shouldBeVisible = isActive || !shouldFilterRegions; 2994 2995 if (hasLiveFilter && defaultGlobeId) { 2996 2997 // Convert IDs to strings for comparison to avoid type mismatches 2998 const defaultGlobeIdStr = String(defaultGlobeId); 2999 const baseMapIdStr = String(data.id); 3000 const featureGlobeIdStr = String(featureGlobeId); 3001 3002 // If keepBase is enabled and this is a base map region, always show it 3003 if (keepBaseValue === '1' && featureGlobeIdStr === baseMapIdStr) { 3004 shouldBeVisible = isActive; 3005 } 3006 // If default is base map, show all active regions 3007 else if (defaultGlobeIdStr === baseMapIdStr) { 3008 shouldBeVisible = isActive; 3009 } 3010 // If default is this layer's globe_id, show this layer's regions 3011 else if (defaultGlobeIdStr === featureGlobeIdStr) { 3012 shouldBeVisible = isActive; 3013 } 3014 // If default is a different layer, hide this layer's regions unless it's base map with keepBase 3015 else { 3016 shouldBeVisible = keepBaseValue === '1' && featureGlobeIdStr === baseMapIdStr; 3017 } 3018 } 3019 3020 3021 try { 3022 // Set both visible and hover states 3023 globe.setFeatureState( 3024 { source: sourceId, id: feature.id }, 3025 { 3026 visible: shouldBeVisible, 3027 hover: false 3028 } 3029 ); 3030 3031 } catch (error) { 3032 console.error('Error setting feature state:', error); 3033 } 3034 } 3035 }); 3036 } 3037 }); 3038 return featuresDict; 3039}; 3040 3041const maybeRotateGlobe = function ( globe, data ) { 3042 // Add auto rotation if enabled 3043 if (globe_ut_bool(data.rotate?.enabled)) { 3044 let rotationSpeed = data.rotate?.speed ? parseFloat(data.rotate.speed)/4 : 1.5; 3045 let isRotating = true; 3046 let animationFrameId; 3047 3048 // Start a rotation animation around the globe (panning along equator) 3049 const rotateCamera = () => { 3050 if (isRotating) { 3051 const currentCenter = globe.getCenter(); 3052 globe.setCenter([currentCenter.lng + rotationSpeed, currentCenter.lat], { 3053 duration: 0, 3054 easing: t => t 3055 }); 3056 animationFrameId = requestAnimationFrame(rotateCamera); 3057 } 3058 }; 3059 3060 const stopRotation = () => { 3061 isRotating = false; 3062 if (animationFrameId) { 3063 cancelAnimationFrame(animationFrameId); 3064 } 3065 }; 3066 3067 const startRotation = () => { 3068 isRotating = true; 3069 rotateCamera(); 3070 }; 3071 3072 // Start initial rotation 3073 rotateCamera(); 3074 3075 // Stop rotation on map hover 3076 globe.getCanvas().addEventListener('mouseenter', stopRotation); 3077 3078 // Resume rotation when mouse leaves the map 3079 globe.getCanvas().addEventListener('mouseleave', startRotation); 3080 3081 // Add hover handlers to all markers 3082 const addMarkerHoverHandlers = (marker) => { 3083 const element = marker.getElement(); 3084 element.addEventListener('mouseenter', stopRotation); 3085 element.addEventListener('mouseleave', startRotation); 3086 }; 3087 3088 // Add hover handlers to existing markers 3089 if (data.points) { 3090 data.points.forEach(point => addMarkerHoverHandlers(point._marker)); 3091 } 3092 if (data.objects) { 3093 data.objects.forEach(object => addMarkerHoverHandlers(object._marker)); 3094 } 3095 if (data.dotLabels) {
3096 data.dotLabels.forEach(label => addMarkerHoverHandlers(label._marker)); 3097 } 3098 if (data.html) { 3099 data.html.forEach(html => addMarkerHoverHandlers(html._marker)); 3100 } 3101 } 3102}; 3103 3104const styles = {}; 3105 3106 styles['default'] = { 3107 version: 8, 3108 sources: { 3109 satellite: { 3110 type: 'raster', 3111 tiles: ['https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}'], 3112 tileSize: 256, 3113 attribution: 'Esri World Imagery' 3114 } 3115 }, 3116 layers: [ 3117 { 3118 id: 'satellite-layer', 3119 type: 'raster', 3120 source: 'satellite', 3121 minzoom: 0, 3122 maxzoom: 22 3123 } 3124 ] 3125 }; 3126 styles['terrain'] = { 3127 version: 8, 3128 sources: { 3129 opentopo: { 3130 type: 'raster', 3131 tiles: ['https://a.tile.opentopomap.org/{z}/{x}/{y}.png'], 3132 tileSize: 256 3133 } 3134 }, 3135 layers: [ 3136 { 3137 id: 'opentopo-tiles', 3138 type: 'raster', 3139 source: 'opentopo' 3140 } 3141 ] 3142 }; 3143 3144 styles['light'] = { 3145 version: 8, 3146 sources: { 3147 carto: { 3148 type: 'raster', 3149 tiles: ['https://a.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png'], 3150 tileSize: 256 3151 } 3152 }, 3153 layers: [ 3154 { 3155 id: 'carto-tiles', 3156 type: 'raster', 3157 source: 'carto' 3158 } 3159 ] 3160 }; 3161 3162 styles['dark'] = { 3163 version: 8, 3164 sources: { 3165 carto: { 3166 type: 'raster', 3167 tiles: ['https://a.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png'], 3168 tileSize: 256 3169 } 3170 }, 3171 layers: [ 3172 { 3173 id: 'carto-tiles', 3174 type: 'raster', 3175 source: 'carto' 3176 } 3177 ] 3178 }; 3179 3180 3181 3182 styles['osm'] = { 3183 version: 8, 3184 sources: { 3185 osm: { 3186 type: 'raster', 3187 tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'], 3188 tileSize: 256 3189 } 3190 }, 3191 layers: [ 3192 { 3193 id: 'osm-tiles', 3194 type: 'raster', 3195 source: 'osm' 3196 } 3197 ] 3198 }; 3199 3200var create_maplibre = function ( id, data ) { 3201 3202 //data types - normal 3203 let dataTypes = { 3204 'points': 'pointDefaults', 3205 'dotLabels': 'labelDefaults', 3206 'html': 'htmlDefaults', 3207 'objects': 'pointDefaults', 3208 'regions': 'regionDefaults', 3209 'arcLines': 'arcLineDefaults', 3210 }; 3211 3212 let container = document.getElementById( 'itt_globe_' + id ); 3213 3214 globe_ut_prepareData( data ); 3215 globe_ut_setupData( data, dataTypes ); 3216 globe_ut_prepareViewport( container, data ); 3217 3218 // Store the data in our data store 3219 ({ 3220 base: { 3221 points: data.points || [], 3222 objects: data.objects || [], 3223 dotLabels: data.dotLabels || [], 3224 html: data.html || [], 3225 regions: data.regions || [], 3226 arcLines: data.arcLines || [] 3227 }, 3228 layers: data.layers || [], 3229 baseMapId: data.id // Store the base map ID for reference 3230 }); 3231 3232 // if there are layers, process the layers data also 3233 if(data.layers){ 3234 for(let layer of data.layers){ 3235 globe_ut_setupData(layer, dataTypes); 3236 } 3237 } 3238 3239 // Initialize a new MapLibre GL map instance with the specified configuration. 3240 // - `container`: The HTML element ID where the map will be rendered, prefixed with 'itt_globe_' and the given `id`. 3241 // - `style`: The map style to use, determined by the `maplibreStyle` property in the `data` object. 3242 // - `center`: The initial geographical center of the map, using longitude and latitude from `data.centerCoordinates`. 3243 // - `zoom`: The initial zoom level, defaulting to 2 if not specified in `data.zoomOptions`. 3244 // - `minZoom`: The minimum zoom level allowed, defaulting to 0, ensuring it's not negative. 3245 // - `maxZoom`: The maximum zoom level allowed, defaulting to 22, ensuring it doesn't exceed 22. 3246 // - `maplibreLogo`: Set to false to hide the MapLibre logo. 3247 // - `dragPan`: Enables or disables panning interaction based on `data.interactions.pan`. 3248 // - `scrollZoom`: Enables or disables zooming interaction based on `data.interactions.zoom`. 3249 // - `preserveDrawingBuffer`: Set to false, meaning the drawing buffer is not preserved. 3250 // - `renderWorldCopies`: Set to true to render multiple copies of the world map. 3251 const thisGlobe = new maplibregl.Map({ 3252 container: 'itt_globe_' + id, 3253 style: styles[data.maplibreStyle], 3254 center: [data.centerCoordinates.longitude, data.centerCoordinates.latitude], 3255 zoom: (typeof data.zoomOptions?.initialZoom !== 'undefined' && data.zoomOptions.initialZoom !== '') ? parseFloat(data.zoomOptions.initialZoom) : 2, 3256 minZoom: data.zoomOptions?.minZoom ? Math.max(0, parseFloat(data.zoomOptions.minZoom)) : 0, 3257 maxZoom: data.zoomOptions?.maxZoom ? Math.min(22, parseFloat(data.zoomOptions.maxZoom)) : 22, 3258 maplibreLogo: false, 3259 dragPan: globe_ut_bool(data.interactions?.pan), 3260 scrollZoom: globe_ut_bool(data.interactions?.zoom), 3261 renderWorldCopies: true 3262 }); 3263 3264 // Attach the wrapper - pre-bind globe and data
3265 thisGlobe.pointOfView = (pov, transitionMs) => { 3266 return pointOfView(thisGlobe, data, pov); 3267 }; 3268 3269 // Create a single popup for all markers 3270 new maplibregl.Popup({ 3271 offset: [0, -25], // Increased vertical offset 3272 closeButton: false, 3273 closeOnClick: true 3274 }); 3275 3276 // to make it publically accessible 3277 thisGlobe.meta = data; 3278 3279 // Add screenshot capability 3280 thisGlobe.takeScreenshot = () => { 3281 return new Promise((resolve) => { 3282 thisGlobe.once("render", () => { 3283 resolve(thisGlobe.getCanvas().toDataURL()); 3284 }); 3285 /* trigger render */ 3286 thisGlobe.setBearing(thisGlobe.getBearing()); 3287 }); 3288 }; 3289 3290 // add object to be public 3291 ittGlobes$1.globes.push(thisGlobe); 3292 ittGlobes$1.globesIndex[id] = thisGlobe; 3293 3294 3295 // events 3296 thisGlobe.setupClickEvent = setupClickEvent; 3297 thisGlobe.setupHoverEvent = setupHoverEvent; 3298 3299 maybeRotateGlobe( thisGlobe, data ); 3300 3301 thisGlobe.on('style.load', () => { 3302 thisGlobe.setProjection({ 3303 type: 'globe' 3304 }); 3305 }); 3306 3307 thisGlobe.on('load', async () => { 3308 // Store popup reference for reuse 3309 thisGlobe.popup = new maplibregl.Popup({ 3310 offset: [0, -25], 3311 closeButton: false, 3312 closeOnClick: true 3313 }); 3314 addTooltipStylesToPopup( thisGlobe, id, data ); 3315 3316 // setup settings 3317 // use later to empty memory used 3318 setupResizeListener(thisGlobe); 3319 3320 // Setup elements 3321 await addMarkers( thisGlobe, data ); 3322 3323 // region Lookups 3324 const dataRegions = await prepareDataRegions( data, 'base' ); 3325 const allRegions = await addRegions( thisGlobe, data, dataRegions ); 3326 thisGlobe.allRegionsLookup = allRegions; 3327 3328 if (data.arcLines && data.arcLines.length > 0) { 3329 addArcLines( thisGlobe, data ); 3330 } 3331 3332 // Only add navigation controls if zoom is enabled 3333 if (globe_ut_bool(data.interactions?.zoom)) { 3334 thisGlobe.addControl(new maplibregl.NavigationControl()); 3335 } 3336 3337 3338 // Initialize filters after map is fully loaded 3339 setupMaplibreFilters(); 3340 // Process layers if they exist 3341 if (data.layers && Array.isArray(data.layers)) { 3342 setupMaplibreLayers( thisGlobe, data ); 3343 } 3344 // Trigger admin globe ready event if admin 3345 if (ittGlobeData.isAdmin) { 3346 const event = new Event("adminProGlobeReady"); 3347 document.dispatchEvent(event); 3348 } 3349 }); 3350 3351 return thisGlobe; 3352}; 3353 3354function setupZoomEvent(globe) { 3355 3356 let GlobeData = globe.meta; 3357 3358 globe.onZoom(function(coordinates) { 3359 if (GlobeData.altitudeOptions) { 3360 // Clamp altitude between min and max values if values are set 3361 const minAlt = parseFloat(GlobeData.altitudeOptions.minAltitude); 3362 const maxAlt = parseFloat(GlobeData.altitudeOptions.maxAltitude); 3363 3364 if (!isNaN(minAlt) && minAlt !== 0 && coordinates.altitude < minAlt) { 3365 globe.pointOfView({ 3366 ...coordinates, 3367 altitude: minAlt 3368 }); 3369 } 3370 else if (!isNaN(maxAlt) && maxAlt !== 0 && coordinates.altitude > maxAlt) { 3371 globe.pointOfView({ 3372 ...coordinates, 3373 altitude: maxAlt 3374 }); 3375 } 3376 } 3377 }); 3378} 3379 3380/** initialize globe */ 3381ittGlobes$1.init = function () { 3382 3383 // code was running twice, so we check if it's already inited 3384 if ( typeof window.ittGlobes !== 'undefined' && typeof window.ittGlobes.inited !== 'undefined' ) { 3385 return; 3386 } 3387 3388 // check for globe container created by the shortcode 3389 let globe_render_container = document.getElementsByClassName( 'js-itt-globe-render' ); 3390 for (const globe_container of globe_render_container) { 3391 if ( ! globe_container.dataset.hasOwnProperty('globe_id') ) { 3392 continue; 3393 } 3394 let globe_id = 0; 3395 try { 3396 globe_id = parseInt( JSON.parse(globe_container.dataset.globe_id ) ); 3397 } catch (e) { 3398 continue; 3399 } 3400 3401 if ( ittGlobes$1.globesIndex[ globe_id ] !== undefined ) { 3402 continue; 3403 } 3404 3405 if ( ! globe_container.dataset.hasOwnProperty( 'globe_meta' ) ) { 3406 continue; 3407 } 3408 3409 let globe_meta = {}; 3410 try { 3411 globe_meta = JSON.parse( globe_container.dataset.globe_meta ); 3412 } catch (e) { 3413 globe_meta = {}; 3414 } 3415 3416 if ( globe_meta.library === 'maplibre' ) { 3417 // return early if Maplibre Library didn't load properly 3418 if (typeof maplibregl === 'undefined') { 3419 console.error('Maplibre lib not loaded properly'); 3420 return; 3421 } 3422 3423 // Store reference to map 3424 ittGlobes$1.globesIndex[globe_id] = create_maplibre( globe_id, globe_meta ); 3425 3426 // we only set inited to true if library is maplibre, otherwise, it seems the globe needs to rerun to populate objects? 3427 ittGlobes$1.inited = true; 3428 } 3429 if ( globe_meta.library === 'globegl' || typeof globe_meta.library === 'undefined' ) { 3430 // return early if Globe.gl Library didn't load properly 3431 if (typeof Globe === 'undefined') { 3432 console.error('Globe lib not loaded properly'); 3433 return; 3434 } 3435 3436 create_globe( globe_id, globe_meta ); 3437 } 3438 3439 3440 } 3441}; 3442 3443var create_globe = function ( id, data ) { 3444 3445 //data types - normal 3446 let dataTypes = { 3447 'points': 'pointDefaults', 3448 'dotLabels': 'labelDefaults', 3449 }; 3450 let container = document.getElementById( 'itt_globe_' + id ); 3451 3452 globe_ut_prepareData( data ); 3453 globe_ut_setupData( data, dataTypes ); 3454 globe_ut_prepareViewport( container, data ); 3455 3456 let configOptions = { 3457 rendererConfig: { antialias: true, alpha: true }, 3458 waitForGlobeReady: true, 3459 animateIn: typeof data.animateIn !== 'undefined' ? globe_ut_bool( data.animateIn ) : true, 3460 }; 3461 3462 let thisGlobe = Globe( configOptions ) 3463 (document.getElementById( 'itt_globe_' + id )); 3464 3465 // to make it publically accessible 3466 thisGlobe.meta = data; 3467 3468 // background colour 3469 if (data.backgroundColor === 'transparent') { 3470 data.backgroundColor = 'rgba(0,0,0,0)'; 3471 } 3472 3473 // globe visuals 3474 if ( data.globeImage !== null && data.globeImage !== '' && data.globeImage !== 'earth-hollow' && data.globeImage !== 'noImage' && data.globeImage !== 'customImage' ) { 3475 thisGlobe.globeImageUrl( ittGlobeData.imagesUrl + data.globeImage ); 3476 } 3477 3478 thisGlobe.backgroundColor(data.backgroundColor) 3479 .width(container.offsetWidth) 3480 .height(container.offsetHeight) 3481 .showGraticules( globe_ut_bool( data.showGraticules) && ! globe_ut_bool( data.graticules?.useLargeLinesGraticules ) ) 3482 .showAtmosphere( globe_ut_bool(data.atmosphere.enabled)) 3483 .atmosphereColor(data.atmosphere.atmosphereColor) 3484 .atmosphereAltitude(data.atmosphere.atmosphereAltitude)
3485 .pointOfView(data.pointOfView); 3486 3487 setupInteractions( thisGlobe, data ); 3488 setupResizeEvent( thisGlobe, container, data ); 3489 setupZoomEvent( thisGlobe ); 3490 // if admin 3491 if ( ittGlobeData.isAdmin ) { 3492 3493 const existingOnGlobeReady = thisGlobe.onGlobeReady(); 3494 thisGlobe.onGlobeReady(function () { 3495 if (existingOnGlobeReady) { 3496 existingOnGlobeReady(); 3497 } 3498 const event = new Event("adminGlobeReady"); 3499 document.dispatchEvent(event); 3500 }); 3501 } 3502 // setup points 3503 if ( data.points ) { 3504 addPointsLayer( thisGlobe, data ); 3505 } 3506 3507 // setup label points 3508 if ( data.dotLabels ) { 3509 addLabelsLayer( thisGlobe, data ); 3510 } 3511 3512 // add click event function to be accesible globally 3513 thisGlobe.setupClickEvent = setupClickEvent$1; 3514 thisGlobe.setupHoverEvent = setupHoverEvent$1; 3515 3516 // add object to be public 3517 ittGlobes$1.globes.push( thisGlobe ); 3518 ittGlobes$1.globesIndex[ id ] = thisGlobe; 3519 3520 // altitude options 3521 if ( data.altitudeOptions ) { 3522 thisGlobe.altitudeOptions = data.altitudeOptions; 3523 } 3524}; 3525 3526ittGlobes$1.init(); 3527 3528window.ittGlobes = ittGlobes$1; 3529 3530/** Add Arcs Layer to Globe - Pro */ 3531function addArcsLayer( thisGlobe, data ) { 3532 3533 const segmented_lines = processLinesArray(data.arcLines); 3534 3535 thisGlobe.arcsData( segmented_lines ) 3536 .arcStartLat(p => p.line[0].coordinates.latitude) 3537 .arcStartLng(p => p.line[0].coordinates.longitude) 3538 .arcEndLat(p => p.line[1].coordinates.latitude) 3539 .arcEndLng(p => p.line[1].coordinates.longitude) 3540 .arcColor( p => p.stroke ) 3541 .arcStroke( p => p.strokeWidth ) 3542 .arcDashLength( p => p.dashLength / 100 ) 3543 .arcDashGap( p => p.dashGap / 100 ) 3544 .arcDashAnimateTime( p => p.animate * 1000 ) 3545 .arcAltitude(function (p) { 3546 if (isNaN(p.altitude) || p.altitude.trim() === '') { 3547 return null; 3548 } 3549 return p.altitude / 100; 3550 }); 3551} 3552 3553function processLinesArray(lines) { 3554 const segmented_lines = []; 3555 3556 lines.forEach(entry => { 3557 const line_points = entry.line; 3558 3559 if ( line_points.length <= 2) { 3560 segmented_lines.push(entry); 3561 return; 3562 } 3563 // create copy for all properties 3564 const arc_data = { ...entry }; 3565 3566 // replace the coordinates with a single line 3567 for (let i = 1; i < line_points.length; i++) { 3568 const new_arc_data = { ...arc_data }; 3569 new_arc_data.line = [line_points[i - 1], line_points[i]]; 3570 segmented_lines.push( new_arc_data ); 3571 } 3572 }); 3573 3574 return segmented_lines; 3575} 3576 3577/** 3578 * @license 3579 * Copyright 2010-2025 Three.js Authors 3580 * SPDX-License-Identifier: MIT 3581 */ 3582const REVISION = '175'; 3583 3584/** 3585 * Only front faces are rendered. 3586 * 3587 * @type {number} 3588 * @constant 3589 */ 3590const FrontSide = 0; 3591 3592/** 3593 * Only back faces are rendered. 3594 * 3595 * @type {number} 3596 * @constant 3597 */ 3598const BackSide = 1; 3599 3600/** 3601 * Both front and back faces are rendered. 3602 * 3603 * @type {number} 3604 * @constant 3605 */ 3606const DoubleSide = 2; 3607 3608/** 3609 * The default blending. 3610 * 3611 * @type {number} 3612 * @constant 3613 */ 3614const NormalBlending = 1; 3615 3616/** 3617 * A `source + destination` blending equation. 3618 * 3619 * @type {number} 3620 * @constant 3621 */ 3622const AddEquation = 100; 3623 3624/** 3625 * Multiplies all colors by the source alpha value. 3626 * 3627 * @type {number} 3628 * @constant 3629 */ 3630const SrcAlphaFactor = 204; 3631 3632/** 3633 * Multiplies all colors by 1 minus the source alpha value. 3634 * 3635 * @type {number} 3636 * @constant 3637 */ 3638const OneMinusSrcAlphaFactor = 205; 3639 3640/** 3641 * Pass if the incoming value is less than or equal to the depth buffer value. 3642 * 3643 * @type {number} 3644 * @constant 3645 */ 3646const LessEqualDepth = 3; 3647 3648/** 3649 * Multiplies the environment map color with the surface color. 3650 * 3651 * @type {number} 3652 * @constant 3653 */ 3654const MultiplyOperation = 0; 3655 3656/** 3657 * Maps textures using the geometry's UV coordinates. 3658 * 3659 * @type {number} 3660 * @constant 3661 */ 3662const UVMapping = 300; 3663 3664/** 3665 * The texture will simply repeat to infinity. 3666 * 3667 * @type {number} 3668 * @constant 3669 */ 3670const RepeatWrapping = 1000; 3671 3672/** 3673 * The last pixel of the texture stretches to the edge of the mesh. 3674 * 3675 * @type {number} 3676 * @constant 3677 */ 3678const ClampToEdgeWrapping = 1001; 3679 3680/** 3681 * The texture will repeats to infinity, mirroring on each repeat. 3682 * 3683 * @type {number} 3684 * @constant 3685 */ 3686const MirroredRepeatWrapping = 1002; 3687 3688/** 3689 * Returns the weighted average of the four texture elements that are closest to the specified 3690 * texture coordinates, and can include items wrapped or repeated from other parts of a texture, 3691 * depending on the values of `wrapS` and `wrapT`, and on the exact mapping. 3692 * 3693 * @type {number} 3694 * @constant 3695 */ 3696const LinearFilter = 1006; 3697 3698/** 3699 * Chooses the two mipmaps that most closely match the size of the pixel being textured and uses 3700 * the `LinearFilter` criterion to produce a texture value from each mipmap. The final texture value 3701 * is a weighted average of those two values. 3702 * 3703 * @type {number} 3704 * @constant 3705 */ 3706const LinearMipmapLinearFilter = 1008; 3707 3708/** 3709 * An unsigned byte data type for textures. 3710 * 3711 * @type {number} 3712 * @constant 3713 */ 3714const UnsignedByteType = 1009; 3715 3716/** 3717 * A float data type for textures. 3718 * 3719 * @type {number} 3720 * @constant 3721 */ 3722const FloatType = 1015; 3723 3724/** 3725 * Reads the red, green, blue and alpha components. 3726 * 3727 * @type {number} 3728 * @constant 3729 */ 3730const RGBAFormat = 1023; 3731 3732/** 3733 * Normal information is relative to the underlying surface. 3734 * 3735 * @type {number} 3736 * @constant 3737 */ 3738const TangentSpaceNormalMap = 0; 3739 3740// Color space string identifiers, matching CSS Color Module Level 4 and WebGPU n
vendor: 4,339 bytes, lines 3740-3947
3740ames where available. 3741 3742/** 3743 * No color space. 3744 * 3745 * @type {string} 3746 * @constant 3747 */ 3748const NoColorSpace = ''; 3749 3750/** 3751 * sRGB color space. 3752 * 3753 * @type {string} 3754 * @constant 3755 */ 3756const SRGBColorSpace = 'srgb'; 3757 3758/** 3759 * sRGB-linear color space. 3760 * 3761 * @type {string} 3762 * @constant 3763 */ 3764const LinearSRGBColorSpace = 'srgb-linear'; 3765 3766/** 3767 * Linear transfer function. 3768 * 3769 * @type {string} 3770 * @constant 3771 */ 3772const LinearTransfer = 'linear'; 3773 3774/** 3775 * sRGB transfer function. 3776 * 3777 * @type {string} 3778 * @constant 3779 */ 3780const SRGBTransfer = 'srgb'; 3781 3782/** 3783 * Keeps the current value. 3784 * 3785 * @type {number} 3786 * @constant 3787 */ 3788const KeepStencilOp = 7680; 3789 3790/** 3791 * Will always return true. 3792 * 3793 * @type {number} 3794 * @constant 3795 */ 3796const AlwaysStencilFunc = 519; 3797 3798/** 3799 * The contents are intended to be specified once by the application, and used many 3800 * times as the source for drawing and image specification commands. 3801 * 3802 * @type {number} 3803 * @constant 3804 */ 3805const StaticDrawUsage = 35044; 3806 3807/** 3808 * WebGL coordinate system. 3809 * 3810 * @type {number} 3811 * @constant 3812 */ 3813const WebGLCoordinateSystem = 2000; 3814 3815/** 3816 * WebGPU coordinate system. 3817 * 3818 * @type {number} 3819 * @constant 3820 */ 3821const WebGPUCoordinateSystem = 2001; 3822 3823/** 3824 * This type represents mouse buttons and interaction types in context of controls. 3825 * 3826 * @typedef {Object} ConstantsMouse 3827 * @property {number} MIDDLE - The left mouse button. 3828 * @property {number} LEFT - The middle mouse button. 3829 * @property {number} RIGHT - The right mouse button. 3830 * @property {number} ROTATE - A rotate interaction. 3831 * @property {number} DOLLY - A dolly interaction. 3832 * @property {number} PAN - A pan interaction. 3833 **/ 3834 3835/** 3836 * This type represents touch interaction types in context of controls. 3837 * 3838 * @typedef {Object} ConstantsTouch 3839 * @property {number} ROTATE - A rotate interaction. 3840 * @property {number} PAN - A pan interaction. 3841 * @property {number} DOLLY_PAN - The dolly-pan interaction. 3842 * @property {number} DOLLY_ROTATE - A dolly-rotate interaction. 3843 **/ 3844 3845/** 3846 * This type represents the different timestamp query types. 3847 * 3848 * @typedef {Object} ConstantsTimestampQuery 3849 * @property {string} COMPUTE - A `compute` timestamp query. 3850 * @property {string} RENDER - A `render` timestamp query. 3851 **/ 3852 3853/** 3854 * This modules allows to dispatch event objects on custom JavaScript objects. 3855 * 3856 * Main repository: [eventdispatcher.js]{@link https://github.com/mrdoob/eventdispatcher.js/} 3857 * 3858 * Code Example: 3859 * ```js 3860 * class Car extends EventDispatcher { 3861 * start() { 3862 * this.dispatchEvent( { type: 'start', message: 'vroom vroom!' } ); 3863 * } 3864 *}; 3865 * 3866 * // Using events with the custom object 3867 * const car = new Car(); 3868 * car.addEventListener( 'start', function ( event ) { 3869 * alert( event.message ); 3870 * } ); 3871 * 3872 * car.start(); 3873 * ``` 3874 */ 3875class EventDispatcher { 3876 3877 /** 3878 * Adds the given event listener to the given event type. 3879 * 3880 * @param {string} type - The type of event to listen to. 3881 * @param {Function} listener - The function that gets called when the event is fired. 3882 */ 3883 addEventListener( type, listener ) { 3884 3885 if ( this._listeners === undefined ) this._listeners = {}; 3886 3887 const listeners = this._listeners; 3888 3889 if ( listeners[ type ] === undefined ) { 3890 3891 listeners[ type ] = []; 3892 3893 } 3894 3895 if ( listeners[ type ].indexOf( listener ) === -1 ) { 3896 3897 listeners[ type ].push( listener ); 3898 3899 } 3900 3901 } 3902 3903 /** 3904 * Returns `true` if the given event listener has been added to the given event type. 3905 * 3906 * @param {string} type - The type of event. 3907 * @param {Function} listener - The listener to check. 3908 * @return {boolean} Whether the given event listener has been added to the given event type. 3909 */ 3910 hasEventListener( type, listener ) { 3911 3912 const listeners = this._listeners; 3913 3914 if ( listeners === undefined ) return false; 3915 3916 return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== -1; 3917 3918 } 3919 3920 /** 3921 * Removes the given event listener from the given event type. 3922 * 3923 * @param {string} type - The type of event. 3924 * @param {Function} listener - The listener to remove. 3925 */ 3926 removeEventListener( type, listener ) { 3927 3928 const listeners = this._listeners; 3929 3930 if ( listeners === undefined ) return; 3931 3932 const listenerArray = listeners[ type ]; 3933 3934 if ( listenerArray !== undefined ) { 3935 3936 const index = listenerArray.indexOf( listener ); 3937 3938 if ( index !== -1 ) { 3939 3940 listenerArray.splice( index, 1 ); 3941 3942 } 3943 3944 } 3945 3946 } 3947
vendor: 12,364 bytes, lines 3948-4361
3948 /** 3949 * Dispatches an event object. 3950 * 3951 * @param {Object} event - The event that gets fired. 3952 */ 3953 dispatchEvent( event ) { 3954 3955 const listeners = this._listeners; 3956 3957 if ( listeners === undefined ) return; 3958 3959 const listenerArray = listeners[ event.type ]; 3960 3961 if ( listenerArray !== undefined ) { 3962 3963 event.target = this; 3964 3965 // Make a copy, in case listeners are removed while iterating. 3966 const array = listenerArray.slice( 0 ); 3967 3968 for ( let i = 0, l = array.length; i < l; i ++ ) { 3969 3970 array[ i ].call( this, event ); 3971 3972 } 3973 3974 event.target = null; 3975 3976 } 3977 3978 } 3979 3980} 3981 3982const _lut = [ '00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '0a', '0b', '0c', '0d', '0e', '0f', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '1a', '1b', '1c', '1d', '1e', '1f', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '2a', '2b', '2c', '2d', '2e', '2f', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '3a', '3b', '3c', '3d', '3e', '3f', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '4a', '4b', '4c', '4d', '4e', '4f', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '5a', '5b', '5c', '5d', '5e', '5f', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '6a', '6b', '6c', '6d', '6e', '6f', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '7a', '7b', '7c', '7d', '7e', '7f', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '8a', '8b', '8c', '8d', '8e', '8f', '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', '9a', '9b', '9c', '9d', '9e', '9f', 'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'a9', 'aa', 'ab', 'ac', 'ad', 'ae', 'af', 'b0', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'b9', 'ba', 'bb', 'bc', 'bd', 'be', 'bf', 'c0', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'ca', 'cb', 'cc', 'cd', 'ce', 'cf', 'd0', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9', 'da', 'db', 'dc', 'dd', 'de', 'df', 'e0', 'e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7', 'e8', 'e9', 'ea', 'eb', 'ec', 'ed', 'ee', 'ef', 'f0', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'fa', 'fb', 'fc', 'fd', 'fe', 'ff' ]; 3983 3984let _seed = 1234567; 3985 3986 3987const DEG2RAD = Math.PI / 180; 3988const RAD2DEG = 180 / Math.PI; 3989 3990/** 3991 * Generate a [UUID]{@link https://en.wikipedia.org/wiki/Universally_unique_identifier} 3992 * (universally unique identifier). 3993 * 3994 * @return {string} The UUID. 3995 */ 3996function generateUUID() { 3997 3998 // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 3999 4000 const d0 = Math.random() * 0xffffffff | 0; 4001 const d1 = Math.random() * 0xffffffff | 0; 4002 const d2 = Math.random() * 0xffffffff | 0; 4003 const d3 = Math.random() * 0xffffffff | 0; 4004 const uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' + 4005 _lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' + 4006 _lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] + 4007 _lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ]; 4008 4009 // .toLowerCase() here flattens concatenated strings to save heap memory space. 4010 return uuid.toLowerCase(); 4011 4012} 4013 4014/** 4015 * Clamps the given value between min and max. 4016 * 4017 * @param {number} value - The value to clamp. 4018 * @param {number} min - The min value. 4019 * @param {number} max - The max value. 4020 * @return {number} The clamped value. 4021 */ 4022function clamp( value, min, max ) { 4023 4024 return Math.max( min, Math.min( max, value ) ); 4025 4026} 4027 4028/** 4029 * Computes the Euclidean modulo of the given parameters that 4030 * is `( ( n % m ) + m ) % m`. 4031 * 4032 * @param {number} n - The first parameter. 4033 * @param {number} m - The second parameter. 4034 * @return {number} The Euclidean modulo. 4035 */ 4036function euclideanModulo( n, m ) { 4037 4038 // https://en.wikipedia.org/wiki/Modulo_operation 4039 4040 return ( ( n % m ) + m ) % m; 4041 4042} 4043 4044/** 4045 * Performs a linear mapping from range `<a1, a2>` to range `<b1, b2>` 4046 * for the given value. 4047 * 4048 * @param {number} x - The value to be mapped. 4049 * @param {number} a1 - Minimum value for range A. 4050 * @param {number} a2 - Maximum value for range A. 4051 * @param {number} b1 - Minimum value for range B. 4052 * @param {number} b2 - Maximum value for range B. 4053 * @return {number} The mapped value. 4054 */ 4055function mapLinear( x, a1, a2, b1, b2 ) { 4056 4057 return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); 4058 4059} 4060 4061/** 4062 * Returns the percentage in the closed interval `[0, 1]` of the given value 4063 * between the start and end point. 4064 * 4065 * @param {number} x - The start point 4066 * @param {number} y - The end point. 4067 * @param {number} value - A value between start and end. 4068 * @return {number} The interpolation factor. 4069 */ 4070function inverseLerp( x, y, value ) { 4071 4072 // https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/ 4073 4074 if ( x !== y ) { 4075 4076 return ( value - x ) / ( y - x ); 4077 4078 } else { 4079 4080 return 0; 4081 4082 } 4083 4084} 4085 4086/** 4087 * Returns a value linearly interpolated from two known points based on the given interval - 4088 * `t = 0` will return `x` and `t = 1` will return `y`. 4089 * 4090 * @param {number} x - The start point 4091 * @param {number} y - The end point. 4092 * @param {number} t - The interpolation factor in the closed interval `[0, 1]`. 4093 * @return {number} The interpolated value. 4094 */ 4095function lerp( x, y, t ) { 4096 4097 return ( 1 - t ) * x + t * y; 4098 4099} 4100 4101/** 4102 * Smoothly interpolate a number from `x` to `y` in a spring-like manner using a delta 4103 * time to maintain frame rate independent movement. For details, see 4104 * [Frame rate independent damping using lerp]{@link http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/}. 4105 * 4106 * @param {number} x - The current point. 4107 * @param {number} y - The target point. 4108 * @param {number} lambda - A higher lambda value will make the movement more sudden, 4109 * and a lower value will make the movement more gradual. 4110 * @param {number} dt - Delta time in seconds. 4111 * @return {number} The interpolated value. 4112 */ 4113function damp( x, y, lambda, dt ) { 4114 4115 return lerp( x, y, 1 - Math.exp( - lambda * dt ) ); 4116 4117} 4118 4119/** 4120 * Returns a value that alternates between `0` and the given `length` parameter. 4121 * 4122 * @param {number} x - The value to pingpong. 4123 * @param {number} [length=1] - The positive value the function will pingpong to. 4124 * @return {number} The alternated value. 4125 */ 4126function pingpong( x, length = 1 ) { 4127 4128 // https://www.desmos.com/calculator/vcsjnyz7x4 4129 4130 return length - Math.abs( euclideanModulo( x, length * 2 ) - length ); 4131 4132} 4133 4134/** 4135 * Returns a value in the range `[0,1]` that represents the percentage that `x` has 4136 * moved between `min` and `max`, but smoothed or slowed down the closer `x` is to 4137 * the `min` and `max`. 4138 * 4139 * See [Smoothstep]{@link http://en.wikipedia.org/wiki/Smoothstep} for more details. 4140 * 4141 * @param {number} x - The value to evaluate based on its position between min and max. 4142 * @param {number} min - The min value. Any x value below min will be `0`. 4143 * @param {number} max - The max value. Any x value above max will be `1`. 4144 * @return {number} The alternated value. 4145 */ 4146function smoothstep( x, min, max ) { 4147 4148 if ( x <= min ) return 0; 4149 if ( x >= max ) return 1; 4150 4151 x = ( x - min ) / ( max - min ); 4152 4153 return x * x * ( 3 - 2 * x ); 4154 4155} 4156 4157/** 4158 * A [variation on smoothstep]{@link https://en.wikipedia.org/wiki/Smoothstep#Variations} 4159 * that has zero 1st and 2nd order derivatives at x=0 and x=1. 4160 * 4161 * @param {number} x - The value to evaluate based on its position between min and max. 4162 * @param {number} min - The min value. Any x value below min will be `0`. 4163 * @param {number} max - The max value. Any x value above max will be `1`. 4164 * @return {number} The alternated value. 4165 */ 4166function smootherstep( x, min, max ) { 4167 4168 if ( x <= min ) return 0; 4169 if ( x >= max ) return 1; 4170 4171 x = ( x - min ) / ( max - min ); 4172 4173 return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); 4174 4175} 4176 4177/** 4178 * Returns a random integer from `<low, high>` interval. 4179 * 4180 * @param {number} low - The lower value boundary. 4181 * @param {number} high - The upper value boundary 4182 * @return {number} A random integer. 4183 */ 4184function randInt( low, high ) { 4185 4186 return low + Math.floor( Math.random() * ( high - low + 1 ) ); 4187 4188} 4189 4190/** 4191 * Returns a random float from `<low, high>` interval. 4192 * 4193 * @param {number} low - The lower value boundary. 4194 * @param {number} high - The upper value boundary 4195 * @return {number} A random float. 4196 */ 4197function randFloat( low, high ) { 4198 4199 return low + Math.random() * ( high - low ); 4200 4201} 4202 4203/** 4204 * Returns a random integer from `<-range/2, range/2>` interval. 4205 * 4206 * @param {number} range - Defines the value range. 4207 * @return {number} A random float. 4208 */ 4209function randFloatSpread( range ) { 4210 4211 return range * ( 0.5 - Math.random() ); 4212 4213} 4214 4215/** 4216 * Returns a deterministic pseudo-random float in the interval `[0, 1]`. 4217 * 4218 * @param {number} [s] - The integer seed. 4219 * @return {number} A random float. 4220 */ 4221function seededRandom( s ) { 4222 4223 if ( s !== undefined ) _seed = s; 4224 4225 // Mulberry32 generator 4226 4227 let t = _seed += 0x6D2B79F5; 4228 4229 t = Math.imul( t ^ t >>> 15, t | 1 ); 4230 4231 t ^= t + Math.imul( t ^ t >>> 7, t | 61 ); 4232 4233 return ( ( t ^ t >>> 14 ) >>> 0 ) / 4294967296; 4234 4235} 4236 4237/** 4238 * Converts degrees to radians. 4239 * 4240 * @param {number} degrees - A value in degrees. 4241 * @return {number} The converted value in radians. 4242 */ 4243function degToRad( degrees ) { 4244 4245 return degrees * DEG2RAD; 4246 4247} 4248 4249/** 4250 * Converts radians to degrees. 4251 * 4252 * @param {number} radians - A value in radians. 4253 * @return {number} The converted value in degrees. 4254 */ 4255function radToDeg( radians ) { 4256 4257 return radians * RAD2DEG; 4258 4259} 4260 4261/** 4262 * Returns `true` if the given number is a power of two. 4263 * 4264 * @param {number} value - The value to check. 4265 * @return {boolean} Whether the given number is a power of two or not. 4266 */ 4267function isPowerOfTwo( value ) { 4268 4269 return ( value & ( value - 1 ) ) === 0 && value !== 0; 4270 4271} 4272 4273/** 4274 * Returns the smallest power of two that is greater than or equal to the given number. 4275 * 4276 * @param {number} value - The value to find a POT for. 4277 * @return {number} The smallest power of two that is greater than or equal to the given number. 4278 */ 4279function ceilPowerOfTwo( value ) { 4280 4281 return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) ); 4282 4283} 4284 4285/** 4286 * Returns the largest power of two that is less than or equal to the given number. 4287 * 4288 * @param {number} value - The value to find a POT for. 4289 * @return {number} The largest power of two that is less than or equal to the given number. 4290 */ 4291function floorPowerOfTwo( value ) { 4292 4293 return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) ); 4294 4295} 4296 4297/** 4298 * Sets the given quaternion from the [Intrinsic Proper Euler Angles]{@link https://en.wikipedia.org/wiki/Euler_angles} 4299 * defined by the given angles and order. 4300 * 4301 * Rotations are applied to the axes in the order specified by order: 4302 * rotation by angle `a` is applied first, then by angle `b`, then by angle `c`. 4303 * 4304 * @param {Quaternion} q - The quaternion to set. 4305 * @param {number} a - The rotation applied to the first axis, in radians. 4306 * @param {number} b - The rotation applied to the second axis, in radians. 4307 * @param {number} c - The rotation applied to the third axis, in radians. 4308 * @param {('XYX'|'XZX'|'YXY'|'YZY'|'ZXZ'|'ZYZ')} order - A string specifying the axes order. 4309 */ 4310function setQuaternionFromProperEuler( q, a, b, c, order ) { 4311 4312 const cos = Math.cos; 4313 const sin = Math.sin; 4314 4315 const c2 = cos( b / 2 ); 4316 const s2 = sin( b / 2 ); 4317 4318 const c13 = cos( ( a + c ) / 2 ); 4319 const s13 = sin( ( a + c ) / 2 ); 4320 4321 const c1_3 = cos( ( a - c ) / 2 ); 4322 const s1_3 = sin( ( a - c ) / 2 ); 4323 4324 const c3_1 = cos( ( c - a ) / 2 ); 4325 const s3_1 = sin( ( c - a ) / 2 ); 4326 4327 switch ( order ) { 4328 4329 case 'XYX': 4330 q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 ); 4331 break; 4332 4333 case 'YZY': 4334 q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 ); 4335 break; 4336 4337 case 'ZXZ': 4338 q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 ); 4339 break; 4340 4341 case 'XZX': 4342 q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 ); 4343 break; 4344 4345 case 'YXY': 4346 q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 ); 4347 break; 4348 4349 case 'ZYZ': 4350 q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 ); 4351 break; 4352 4353 default: 4354 console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order ); 4355 4356 } 4357 4358} 4359 4360/** 4361 * Denormalizes the given value according to the given typed array.
4362 * 4363 * @param {number} value - The value to denormalize. 4364 * @param {TypedArray} array - The typed array that defines the data type of the value. 4365 * @return {number} The denormalize (float) value in the range `[0,1]`. 4366 */ 4367function denormalize( value, array ) { 4368 4369 switch ( array.constructor ) { 4370 4371 case Float32Array: 4372 4373 return value; 4374 4375 case Uint32Array: 4376 4377 return value / 4294967295.0; 4378 4379 case Uint16Array: 4380 4381 return value / 65535.0; 4382 4383 case Uint8Array: 4384 4385 return value / 255.0; 4386 4387 case Int32Array: 4388 4389 return Math.max( value / 2147483647.0, -1 ); 4390 4391 case Int16Array: 4392 4393 return Math.max( value / 32767.0, -1 ); 4394 4395 case Int8Array: 4396 4397 return Math.max( value / 127.0, -1 ); 4398 4399 default: 4400 4401 throw new Error( 'Invalid component type.' ); 4402 4403 } 4404 4405} 4406 4407/** 4408 * Normalizes the given value according to the given typed array. 4409 * 4410 * @param {number} value - The float value in the range `[0,1]` to normalize. 4411 * @param {TypedArray} array - The typed array that defines the data type of the value. 4412 * @return {number} The normalize value. 4413 */ 4414function normalize( value, array ) { 4415 4416 switch ( array.constructor ) { 4417 4418 case Float32Array: 4419 4420 return value; 4421 4422 case Uint32Array: 4423 4424 return Math.round( value * 4294967295.0 ); 4425 4426 case Uint16Array: 4427 4428 return Math.round( value * 65535.0 ); 4429 4430 case Uint8Array: 4431 4432 return Math.round( value * 255.0 ); 4433 4434 case Int32Array: 4435 4436 return Math.round( value * 2147483647.0 ); 4437 4438 case Int16Array: 4439 4440 return Math.round( value * 32767.0 ); 4441 4442 case Int8Array: 4443 4444 return Math.round( value * 127.0 ); 4445 4446 default: 4447 4448 throw new Error( 'Invalid component type.' ); 4449 4450 } 4451 4452} 4453 4454/** 4455 * @class 4456 * @classdesc A collection of math utility functions. 4457 * @hideconstructor 4458 */ 4459const MathUtils = { 4460 DEG2RAD: DEG2RAD, 4461 RAD2DEG: RAD2DEG, 4462 /** 4463 * Generate a [UUID]{@link https://en.wikipedia.org/wiki/Universally_unique_identifier} 4464 * (universally unique identifier). 4465 * 4466 * @static 4467 * @method 4468 * @return {string} The UUID. 4469 */ 4470 generateUUID: generateUUID, 4471 /** 4472 * Clamps the given value between min and max. 4473 * 4474 * @static 4475 * @method 4476 * @param {number} value - The value to clamp. 4477 * @param {number} min - The min value. 4478 * @param {number} max - The max value. 4479 * @return {number} The clamped value. 4480 */ 4481 clamp: clamp, 4482 /** 4483 * Computes the Euclidean modulo of the given parameters that 4484 * is `( ( n % m ) + m ) % m`. 4485 * 4486 * @static 4487 * @method 4488 * @param {number} n - The first parameter. 4489 * @param {number} m - The second parameter. 4490 * @return {number} The Euclidean modulo. 4491 */ 4492 euclideanModulo: euclideanModulo, 4493 /** 4494 * Performs a linear mapping from range `<a1, a2>` to range `<b1, b2>` 4495 * for the given value. 4496 * 4497 * @static 4498 * @method 4499 * @param {number} x - The value to be mapped. 4500 * @param {number} a1 - Minimum value for range A. 4501 * @param {number} a2 - Maximum value for range A. 4502 * @param {number} b1 - Minimum value for range B. 4503 * @param {number} b2 - Maximum value for range B. 4504 * @return {number} The mapped value. 4505 */ 4506 mapLinear: mapLinear, 4507 /** 4508 * Returns the percentage in the closed interval `[0, 1]` of the given value 4509 * between the start and end point. 4510 * 4511 * @static 4512 * @method 4513 * @param {number} x - The start point 4514 * @param {number} y - The end point. 4515 * @param {number} value - A value between start and end. 4516 * @return {number} The interpolation factor. 4517 */ 4518 inverseLerp: inverseLerp, 4519 /** 4520 * Returns a value linearly interpolated from two known points based on the given interval - 4521 * `t = 0` will return `x` and `t = 1` will return `y`. 4522 * 4523 * @static 4524 * @method 4525 * @param {number} x - The start point 4526 * @param {number} y - The end point. 4527 * @param {number} t - The interpolation factor in the closed interval `[0, 1]`. 4528 * @return {number} The interpolated value. 4529 */ 4530 lerp: lerp, 4531 /** 4532 * Smoothly interpolate a number from `x` to `y` in a spring-like manner using a delta 4533 * time to maintain frame rate independent movement. For details, see 4534 * [Frame rate independent damping using lerp]{@link http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/}. 4535 * 4536 * @static 4537 * @method 4538 * @param {number} x - The current point. 4539 * @param {number} y - The target point. 4540 * @param {number} lambda - A higher lambda value will make the movement more sudden, 4541 * and a lower value will make the movement more gradual. 4542 * @param {number} dt - Delta time in seconds. 4543 * @return {number} The interpolated value. 4544 */ 4545 damp: damp, 4546 /** 4547 * Returns a value that alternates between `0` and the given `length` parameter. 4548 * 4549 * @static 4550 * @method 4551 * @param {number} x - The value to pingpong. 4552 * @param {number} [length=1] - The positive value the function will pingpong to. 4553 * @return {number} The alternated value. 4554 */ 4555 pingpong: pingpong, 4556 /** 4557 * Returns a value in the range `[0,1]` that represents the percentage that `x` has 4558 * moved between `min` and `max`, but smoothed or slowed down the closer `x` is to 4559 * the `min` and `max`. 4560 * 4561 * See [Smoothstep]{@link http://en.wikipedia.org/wiki/Smoothstep} for more details. 4562 * 4563 * @static 4564 * @method 4565 * @param {number} x - The value to evaluate based on its position between min and max. 4566 * @param {number} min - The min value. Any x value below min will be `0`. 4567 * @param {number} max - The max value. Any x value above max will be `1`. 4568 * @return {number} The alternated value. 4569 */ 4570 smoothstep: smoothstep, 4571 /** 4572 * A [variation on smoothstep]{@link https://en.wikipedia.org/wiki/Smoothstep#Variations} 4573 * that has zero 1st and 2nd order derivatives at x=0 and x=1. 4574 * 4575 * @static 4576 * @method 4577 * @param {number} x - The value to evaluate based on its position between min and max. 4578 * @param {number} min - The min value. Any x value below min will be `0`. 4579 * @param {number} max - The max value. Any x value above max will be `1`. 4580 * @return {number} The alternated value. 4581 */ 4582 smootherstep: smootherstep, 4583 /** 4584 * Returns a random integer from `<low, high>` interval. 4585 * 4586 * @static 4587 * @method 4588 * @param {number} low - The lower value boundary. 4589 * @param {number} high - The upper value boundary 4590 * @return {number} A random integer. 4591 */ 4592 randInt: randInt, 4593 /** 4594 * Returns a random float from `<low, high>` interval. 4595 * 4596 * @static 4597 * @method 4598 * @param {number} low - The lower value boundary. 4599 * @param {number} high - The upper value boundary 4600 * @return {number} A random float. 4601 */ 4602 randFloat: randFloat, 4603 /** 4604 * Returns a random integer from `<-range/2, range/2>` interval. 4605 * 4606 * @static 4607 * @method 4608 * @param {number} range - Defines the value range. 4609 * @return {number} A random float. 4610 */ 4611 randFloatSpread: randFloatSpread, 4612 /** 4613 * Returns a deterministic pseudo-random float in the interval `[0, 1]`. 4614 * 4615 * @static 4616 * @method 4617 * @param {number} [s] - The integer seed. 4618 * @return {number} A random float. 4619 */ 4620 seededRandom: seededRandom, 4621 /** 4622 * Converts degrees to radians. 4623 * 4624 * @static 4625 * @method 4626 * @param {number} degrees - A value in degrees. 4627 * @return {number} The converted value in radians. 4628 */ 4629 degToRad: degToRad, 4630 /** 4631 * Converts radians to degrees. 4632 * 4633 * @static 4634 * @method 4635 * @param {number} radians - A value in radians. 4636 * @return {number} The converted value in degrees. 4637 */ 4638 radToDeg: radToDeg, 4639 /** 4640 * Returns `true` if the given number is a power of two. 4641 * 4642 * @static 4643 * @method 4644 * @param {number} value - The value to check. 4645 * @return {boolean} Whether the given number is a power of two or not. 4646 */ 4647 isPowerOfTwo: isPowerOfTwo, 4648 /** 4649 * Returns the smallest power of two that is greater than or equal to the given number. 4650 * 4651 * @static 4652 * @method 4653 * @param {number} value - The value to find a POT for. 4654 * @return {number} The smallest power of two that is greater than or equal to the given number. 4655 */ 4656 ceilPowerOfTwo: ceilPowerOfTwo, 4657 /** 4658 * Returns the largest power of two that is less than or equal to the given number. 4659 * 4660 * @static 4661 * @method 4662 * @param {number} value - The value to find a POT for. 4663 * @return {number} The largest power of two that is less than or equal to the given number. 4664 */ 4665 floorPowerOfTwo: floorPowerOfTwo, 4666 /** 4667 * Sets the given quaternion from the [Intrinsic Proper Euler Angles]{@link https://en.wikipedia.org/wiki/Euler_angles}
vendor: 4,973 bytes, lines 4667-4895
4667 4668 * defined by the given angles and order. 4669 * 4670 * Rotations are applied to the axes in the order specified by order: 4671 * rotation by angle `a` is applied first, then by angle `b`, then by angle `c`. 4672 * 4673 * @static 4674 * @method 4675 * @param {Quaternion} q - The quaternion to set. 4676 * @param {number} a - The rotation applied to the first axis, in radians. 4677 * @param {number} b - The rotation applied to the second axis, in radians. 4678 * @param {number} c - The rotation applied to the third axis, in radians. 4679 * @param {('XYX'|'XZX'|'YXY'|'YZY'|'ZXZ'|'ZYZ')} order - A string specifying the axes order. 4680 */ 4681 setQuaternionFromProperEuler: setQuaternionFromProperEuler, 4682 /** 4683 * Normalizes the given value according to the given typed array. 4684 * 4685 * @static 4686 * @method 4687 * @param {number} value - The float value in the range `[0,1]` to normalize. 4688 * @param {TypedArray} array - The typed array that defines the data type of the value. 4689 * @return {number} The normalize value. 4690 */ 4691 normalize: normalize, 4692 /** 4693 * Denormalizes the given value according to the given typed array. 4694 * 4695 * @static 4696 * @method 4697 * @param {number} value - The value to denormalize. 4698 * @param {TypedArray} array - The typed array that defines the data type of the value. 4699 * @return {number} The denormalize (float) value in the range `[0,1]`. 4700 */ 4701 denormalize: denormalize 4702}; 4703 4704/** 4705 * Class representing a 2D vector. A 2D vector is an ordered pair of numbers 4706 * (labeled x and y), which can be used to represent a number of things, such as: 4707 * 4708 * - A point in 2D space (i.e. a position on a plane). 4709 * - A direction and length across a plane. In three.js the length will 4710 * always be the Euclidean distance(straight-line distance) from `(0, 0)` to `(x, y)` 4711 * and the direction is also measured from `(0, 0)` towards `(x, y)`. 4712 * - Any arbitrary ordered pair of numbers. 4713 * 4714 * There are other things a 2D vector can be used to represent, such as 4715 * momentum vectors, complex numbers and so on, however these are the most 4716 * common uses in three.js. 4717 * 4718 * Iterating through a vector instance will yield its components `(x, y)` in 4719 * the corresponding order. 4720 * ```js 4721 * const a = new THREE.Vector2( 0, 1 ); 4722 * 4723 * //no arguments; will be initialised to (0, 0) 4724 * const b = new THREE.Vector2( ); 4725 * 4726 * const d = a.distanceTo( b ); 4727 * ``` 4728 */ 4729class Vector2 { 4730 4731 /** 4732 * Constructs a new 2D vector. 4733 * 4734 * @param {number} [x=0] - The x value of this vector. 4735 * @param {number} [y=0] - The y value of this vector. 4736 */ 4737 constructor( x = 0, y = 0 ) { 4738 4739 /** 4740 * This flag can be used for type testing. 4741 * 4742 * @type {boolean} 4743 * @readonly 4744 * @default true 4745 */ 4746 Vector2.prototype.isVector2 = true; 4747 4748 /** 4749 * The x value of this vector. 4750 * 4751 * @type {number} 4752 */ 4753 this.x = x; 4754 4755 /** 4756 * The y value of this vector. 4757 * 4758 * @type {number} 4759 */ 4760 this.y = y; 4761 4762 } 4763 4764 /** 4765 * Alias for {@link Vector2#x}. 4766 * 4767 * @type {number} 4768 */ 4769 get width() { 4770 4771 return this.x; 4772 4773 } 4774 4775 set width( value ) { 4776 4777 this.x = value; 4778 4779 } 4780 4781 /** 4782 * Alias for {@link Vector2#y}. 4783 * 4784 * @type {number} 4785 */ 4786 get height() { 4787 4788 return this.y; 4789 4790 } 4791 4792 set height( value ) { 4793 4794 this.y = value; 4795 4796 } 4797 4798 /** 4799 * Sets the vector components. 4800 * 4801 * @param {number} x - The value of the x component. 4802 * @param {number} y - The value of the y component. 4803 * @return {Vector2} A reference to this vector. 4804 */ 4805 set( x, y ) { 4806 4807 this.x = x; 4808 this.y = y; 4809 4810 return this; 4811 4812 } 4813 4814 /** 4815 * Sets the vector components to the same value. 4816 * 4817 * @param {number} scalar - The value to set for all vector components. 4818 * @return {Vector2} A reference to this vector. 4819 */ 4820 setScalar( scalar ) { 4821 4822 this.x = scalar; 4823 this.y = scalar; 4824 4825 return this; 4826 4827 } 4828 4829 /** 4830 * Sets the vector's x component to the given value 4831 * 4832 * @param {number} x - The value to set. 4833 * @return {Vector2} A reference to this vector. 4834 */ 4835 setX( x ) { 4836 4837 this.x = x; 4838 4839 return this; 4840 4841 } 4842 4843 /** 4844 * Sets the vector's y component to the given value 4845 * 4846 * @param {number} y - The value to set. 4847 * @return {Vector2} A reference to this vector. 4848 */ 4849 setY( y ) { 4850 4851 this.y = y; 4852 4853 return this; 4854 4855 } 4856 4857 /** 4858 * Allows to set a vector component with an index. 4859 * 4860 * @param {number} index - The component index. `0` equals to x, `1` equals to y. 4861 * @param {number} value - The value to set. 4862 * @return {Vector2} A reference to this vector. 4863 */ 4864 setComponent( index, value ) { 4865 4866 switch ( index ) { 4867 4868 case 0: this.x = value; break; 4869 case 1: this.y = value; break; 4870 default: throw new Error( 'index is out of range: ' + index ); 4871 4872 } 4873 4874 return this; 4875 4876 } 4877 4878 /** 4879 * Returns the value of the vector component which matches the given index. 4880 * 4881 * @param {number} index - The component index. `0` equals to x, `1` equals to y. 4882 * @return {number} A vector component value. 4883 */ 4884 getComponent( index ) { 4885 4886 switch ( index ) { 4887 4888 case 0: return this.x; 4889 case 1: return this.y; 4890 default: throw new Error( 'index is out of range: ' + index ); 4891 4892 } 4893 4894 } 4895
vendor: 14,580 bytes, lines 4896-5568
4896 /** 4897 * Returns a new vector with copied values from this instance. 4898 * 4899 * @return {Vector2} A clone of this instance. 4900 */ 4901 clone() { 4902 4903 return new this.constructor( this.x, this.y ); 4904 4905 } 4906 4907 /** 4908 * Copies the values of the given vector to this instance. 4909 * 4910 * @param {Vector2} v - The vector to copy. 4911 * @return {Vector2} A reference to this vector. 4912 */ 4913 copy( v ) { 4914 4915 this.x = v.x; 4916 this.y = v.y; 4917 4918 return this; 4919 4920 } 4921 4922 /** 4923 * Adds the given vector to this instance. 4924 * 4925 * @param {Vector2} v - The vector to add. 4926 * @return {Vector2} A reference to this vector. 4927 */ 4928 add( v ) { 4929 4930 this.x += v.x; 4931 this.y += v.y; 4932 4933 return this; 4934 4935 } 4936 4937 /** 4938 * Adds the given scalar value to all components of this instance. 4939 * 4940 * @param {number} s - The scalar to add. 4941 * @return {Vector2} A reference to this vector. 4942 */ 4943 addScalar( s ) { 4944 4945 this.x += s; 4946 this.y += s; 4947 4948 return this; 4949 4950 } 4951 4952 /** 4953 * Adds the given vectors and stores the result in this instance. 4954 * 4955 * @param {Vector2} a - The first vector. 4956 * @param {Vector2} b - The second vector. 4957 * @return {Vector2} A reference to this vector. 4958 */ 4959 addVectors( a, b ) { 4960 4961 this.x = a.x + b.x; 4962 this.y = a.y + b.y; 4963 4964 return this; 4965 4966 } 4967 4968 /** 4969 * Adds the given vector scaled by the given factor to this instance. 4970 * 4971 * @param {Vector2} v - The vector. 4972 * @param {number} s - The factor that scales `v`. 4973 * @return {Vector2} A reference to this vector. 4974 */ 4975 addScaledVector( v, s ) { 4976 4977 this.x += v.x * s; 4978 this.y += v.y * s; 4979 4980 return this; 4981 4982 } 4983 4984 /** 4985 * Subtracts the given vector from this instance. 4986 * 4987 * @param {Vector2} v - The vector to subtract. 4988 * @return {Vector2} A reference to this vector. 4989 */ 4990 sub( v ) { 4991 4992 this.x -= v.x; 4993 this.y -= v.y; 4994 4995 return this; 4996 4997 } 4998 4999 /** 5000 * Subtracts the given scalar value from all components of this instance. 5001 * 5002 * @param {number} s - The scalar to subtract. 5003 * @return {Vector2} A reference to this vector. 5004 */ 5005 subScalar( s ) { 5006 5007 this.x -= s; 5008 this.y -= s; 5009 5010 return this; 5011 5012 } 5013 5014 /** 5015 * Subtracts the given vectors and stores the result in this instance. 5016 * 5017 * @param {Vector2} a - The first vector. 5018 * @param {Vector2} b - The second vector. 5019 * @return {Vector2} A reference to this vector. 5020 */ 5021 subVectors( a, b ) { 5022 5023 this.x = a.x - b.x; 5024 this.y = a.y - b.y; 5025 5026 return this; 5027 5028 } 5029 5030 /** 5031 * Multiplies the given vector with this instance. 5032 * 5033 * @param {Vector2} v - The vector to multiply. 5034 * @return {Vector2} A reference to this vector. 5035 */ 5036 multiply( v ) { 5037 5038 this.x *= v.x; 5039 this.y *= v.y; 5040 5041 return this; 5042 5043 } 5044 5045 /** 5046 * Multiplies the given scalar value with all components of this instance. 5047 * 5048 * @param {number} scalar - The scalar to multiply. 5049 * @return {Vector2} A reference to this vector. 5050 */ 5051 multiplyScalar( scalar ) { 5052 5053 this.x *= scalar; 5054 this.y *= scalar; 5055 5056 return this; 5057 5058 } 5059 5060 /** 5061 * Divides this instance by the given vector. 5062 * 5063 * @param {Vector2} v - The vector to divide. 5064 * @return {Vector2} A reference to this vector. 5065 */ 5066 divide( v ) { 5067 5068 this.x /= v.x; 5069 this.y /= v.y; 5070 5071 return this; 5072 5073 } 5074 5075 /** 5076 * Divides this vector by the given scalar. 5077 * 5078 * @param {number} scalar - The scalar to divide. 5079 * @return {Vector2} A reference to this vector. 5080 */ 5081 divideScalar( scalar ) { 5082 5083 return this.multiplyScalar( 1 / scalar ); 5084 5085 } 5086 5087 /** 5088 * Multiplies this vector (with an implicit 1 as the 3rd component) by 5089 * the given 3x3 matrix. 5090 * 5091 * @param {Matrix3} m - The matrix to apply. 5092 * @return {Vector2} A reference to this vector. 5093 */ 5094 applyMatrix3( m ) { 5095 5096 const x = this.x, y = this.y; 5097 const e = m.elements; 5098 5099 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ]; 5100 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ]; 5101 5102 return this; 5103 5104 } 5105 5106 /** 5107 * If this vector's x or y value is greater than the given vector's x or y 5108 * value, replace that value with the corresponding min value. 5109 * 5110 * @param {Vector2} v - The vector. 5111 * @return {Vector2} A reference to this vector. 5112 */ 5113 min( v ) { 5114 5115 this.x = Math.min( this.x, v.x ); 5116 this.y = Math.min( this.y, v.y ); 5117 5118 return this; 5119 5120 } 5121 5122 /** 5123 * If this vector's x or y value is less than the given vector's x or y 5124 * value, replace that value with the corresponding max value. 5125 * 5126 * @param {Vector2} v - The vector. 5127 * @return {Vector2} A reference to this vector. 5128 */ 5129 max( v ) { 5130 5131 this.x = Math.max( this.x, v.x ); 5132 this.y = Math.max( this.y, v.y ); 5133 5134 return this; 5135 5136 } 5137 5138 /** 5139 * If this vector's x or y value is greater than the max vector's x or y 5140 * value, it is replaced by the corresponding value. 5141 * If this vector's x or y value is less than the min vector's x or y value, 5142 * it is replaced by the corresponding value. 5143 * 5144 * @param {Vector2} min - The minimum x and y values. 5145 * @param {Vector2} max - The maximum x and y values in the desired range. 5146 * @return {Vector2} A reference to this vector. 5147 */ 5148 clamp( min, max ) { 5149 5150 // assumes min < max, componentwise 5151 5152 this.x = clamp( this.x, min.x, max.x ); 5153 this.y = clamp( this.y, min.y, max.y ); 5154 5155 return this; 5156 5157 } 5158 5159 /** 5160 * If this vector's x or y values are greater than the max value, they are 5161 * replaced by the max value. 5162 * If this vector's x or y values are less than the min value, they are 5163 * replaced by the min value. 5164 * 5165 * @param {number} minVal - The minimum value the components will be clamped to. 5166 * @param {number} maxVal - The maximum value the components will be clamped to. 5167 * @return {Vector2} A reference to this vector. 5168 */ 5169 clampScalar( minVal, maxVal ) { 5170 5171 this.x = clamp( this.x, minVal, maxVal ); 5172 this.y = clamp( this.y, minVal, maxVal ); 5173 5174 return this; 5175 5176 } 5177 5178 /** 5179 * If this vector's length is greater than the max value, it is replaced by 5180 * the max value. 5181 * If this vector's length is less than the min value, it is replaced by the 5182 * min value. 5183 * 5184 * @param {number} min - The minimum value the vector length will be clamped to. 5185 * @param {number} max - The maximum value the vector length will be clamped to. 5186 * @return {Vector2} A reference to this vector. 5187 */ 5188 clampLength( min, max ) { 5189 5190 const length = this.length(); 5191 5192 return this.divideScalar( length || 1 ).multiplyScalar( clamp( length, min, max ) ); 5193 5194 } 5195 5196 /** 5197 * The components of this vector are rounded down to the nearest integer value. 5198 * 5199 * @return {Vector2} A reference to this vector. 5200 */ 5201 floor() { 5202 5203 this.x = Math.floor( this.x ); 5204 this.y = Math.floor( this.y ); 5205 5206 return this; 5207 5208 } 5209 5210 /** 5211 * The components of this vector are rounded up to the nearest integer value. 5212 * 5213 * @return {Vector2} A reference to this vector. 5214 */ 5215 ceil() { 5216 5217 this.x = Math.ceil( this.x ); 5218 this.y = Math.ceil( this.y ); 5219 5220 return this; 5221 5222 } 5223 5224 /** 5225 * The components of this vector are rounded to the nearest integer value 5226 * 5227 * @return {Vector2} A reference to this vector. 5228 */ 5229 round() { 5230 5231 this.x = Math.round( this.x ); 5232 this.y = Math.round( this.y ); 5233 5234 return this; 5235 5236 } 5237 5238 /** 5239 * The components of this vector are rounded towards zero (up if negative, 5240 * down if positive) to an integer value. 5241 * 5242 * @return {Vector2} A reference to this vector. 5243 */ 5244 roundToZero() { 5245 5246 this.x = Math.trunc( this.x ); 5247 this.y = Math.trunc( this.y ); 5248 5249 return this; 5250 5251 } 5252 5253 /** 5254 * Inverts this vector - i.e. sets x = -x and y = -y. 5255 * 5256 * @return {Vector2} A reference to this vector. 5257 */ 5258 negate() { 5259 5260 this.x = - this.x; 5261 this.y = - this.y; 5262 5263 return this; 5264 5265 } 5266 5267 /** 5268 * Calculates the dot product of the given vector with this instance. 5269 * 5270 * @param {Vector2} v - The vector to compute the dot product with. 5271 * @return {number} The result of the dot product. 5272 */ 5273 dot( v ) { 5274 5275 return this.x * v.x + this.y * v.y; 5276 5277 } 5278 5279 /** 5280 * Calculates the cross product of the given vector with this instance. 5281 * 5282 * @param {Vector2} v - The vector to compute the cross product with. 5283 * @return {number} The result of the cross product. 5284 */ 5285 cross( v ) { 5286 5287 return this.x * v.y - this.y * v.x; 5288 5289 } 5290 5291 /** 5292 * Computes the square of the Euclidean length (straight-line length) from 5293 * (0, 0) to (x, y). If you are comparing the lengths of vectors, you should 5294 * compare the length squared instead as it is slightly more efficient to calculate. 5295 * 5296 * @return {number} The square length of this vector. 5297 */ 5298 lengthSq() { 5299 5300 return this.x * this.x + this.y * this.y; 5301 5302 } 5303 5304 /** 5305 * Computes the Euclidean length (straight-line length) from (0, 0) to (x, y). 5306 * 5307 * @return {number} The length of this vector. 5308 */ 5309 length() { 5310 5311 return Math.sqrt( this.x * this.x + this.y * this.y ); 5312 5313 } 5314 5315 /** 5316 * Computes the Manhattan length of this vector. 5317 * 5318 * @return {number} The length of this vector. 5319 */ 5320 manhattanLength() { 5321 5322 return Math.abs( this.x ) + Math.abs( this.y ); 5323 5324 } 5325 5326 /** 5327 * Converts this vector to a unit vector - that is, sets it equal to a vector 5328 * with the same direction as this one, but with a vector length of `1`. 5329 * 5330 * @return {Vector2} A reference to this vector. 5331 */ 5332 normalize() { 5333 5334 return this.divideScalar( this.length() || 1 ); 5335 5336 } 5337 5338 /** 5339 * Computes the angle in radians of this vector with respect to the positive x-axis. 5340 * 5341 * @return {number} The angle in radians. 5342 */ 5343 angle() { 5344 5345 const angle = Math.atan2( - this.y, - this.x ) + Math.PI; 5346 5347 return angle; 5348 5349 } 5350 5351 /** 5352 * Returns the angle between the given vector and this instance in radians. 5353 * 5354 * @param {Vector2} v - The vector to compute the angle with. 5355 * @return {number} The angle in radians. 5356 */ 5357 angleTo( v ) { 5358 5359 const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); 5360 5361 if ( denominator === 0 ) return Math.PI / 2; 5362 5363 const theta = this.dot( v ) / denominator; 5364 5365 // clamp, to handle numerical problems 5366 5367 return Math.acos( clamp( theta, -1, 1 ) ); 5368 5369 } 5370 5371 /** 5372 * Computes the distance from the given vector to this instance. 5373 * 5374 * @param {Vector2} v - The vector to compute the distance to. 5375 * @return {number} The distance. 5376 */ 5377 distanceTo( v ) { 5378 5379 return Math.sqrt( this.distanceToSquared( v ) ); 5380 5381 } 5382 5383 /** 5384 * Computes the squared distance from the given vector to this instance. 5385 * If you are just comparing the distance with another distance, you should compare 5386 * the distance squared instead as it is slightly more efficient to calculate. 5387 * 5388 * @param {Vector2} v - The vector to compute the squared distance to. 5389 * @return {number} The squared distance. 5390 */ 5391 distanceToSquared( v ) { 5392 5393 const dx = this.x - v.x, dy = this.y - v.y; 5394 return dx * dx + dy * dy; 5395 5396 } 5397 5398 /** 5399 * Computes the Manhattan distance from the given vector to this instance. 5400 * 5401 * @param {Vector2} v - The vector to compute the Manhattan distance to. 5402 * @return {number} The Manhattan distance. 5403 */ 5404 manhattanDistanceTo( v ) { 5405 5406 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ); 5407 5408 } 5409 5410 /** 5411 * Sets this vector to a vector with the same direction as this one, but 5412 * with the specified length. 5413 * 5414 * @param {number} length - The new length of this vector. 5415 * @return {Vector2} A reference to this vector. 5416 */ 5417 setLength( length ) { 5418 5419 return this.normalize().multiplyScalar( length ); 5420 5421 } 5422 5423 /** 5424 * Linearly interpolates between the given vector and this instance, where 5425 * alpha is the percent distance along the line - alpha = 0 will be this 5426 * vector, and alpha = 1 will be the given one. 5427 * 5428 * @param {Vector2} v - The vector to interpolate towards. 5429 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. 5430 * @return {Vector2} A reference to this vector. 5431 */ 5432 lerp( v, alpha ) { 5433 5434 this.x += ( v.x - this.x ) * alpha; 5435 this.y += ( v.y - this.y ) * alpha; 5436 5437 return this; 5438 5439 } 5440 5441 /** 5442 * Linearly interpolates between the given vectors, where alpha is the percent 5443 * distance along the line - alpha = 0 will be first vector, and alpha = 1 will 5444 * be the second one. The result is stored in this instance. 5445 * 5446 * @param {Vector2} v1 - The first vector. 5447 * @param {Vector2} v2 - The second vector. 5448 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. 5449 * @return {Vector2} A reference to this vector. 5450 */ 5451 lerpVectors( v1, v2, alpha ) { 5452 5453 this.x = v1.x + ( v2.x - v1.x ) * alpha; 5454 this.y = v1.y + ( v2.y - v1.y ) * alpha; 5455 5456 return this; 5457 5458 } 5459 5460 /** 5461 * Returns `true` if this vector is equal with the given one. 5462 * 5463 * @param {Vector2} v - The vector to test for equality. 5464 * @return {boolean} Whether this vector is equal with the given one. 5465 */ 5466 equals( v ) { 5467 5468 return ( ( v.x === this.x ) && ( v.y === this.y ) ); 5469 5470 } 5471 5472 /** 5473 * Sets this vector's x value to be `array[ offset ]` and y 5474 * value to be `array[ offset + 1 ]`. 5475 * 5476 * @param {Array<number>} array - An array holding the vector component values. 5477 * @param {number} [offset=0] - The offset into the array. 5478 * @return {Vector2} A reference to this vector. 5479 */ 5480 fromArray( array, offset = 0 ) { 5481 5482 this.x = array[ offset ]; 5483 this.y = array[ offset + 1 ]; 5484 5485 return this; 5486 5487 } 5488 5489 /** 5490 * Writes the components of this vector to the given array. If no array is provided, 5491 * the method returns a new instance. 5492 * 5493 * @param {Array<number>} [array=[]] - The target array holding the vector components. 5494 * @param {number} [offset=0] - Index of the first element in the array. 5495 * @return {Array<number>} The vector components. 5496 */ 5497 toArray( array = [], offset = 0 ) { 5498 5499 array[ offset ] = this.x; 5500 array[ offset + 1 ] = this.y; 5501 5502 return array; 5503 5504 } 5505 5506 /** 5507 * Sets the components of this vector from the given buffer attribute. 5508 * 5509 * @param {BufferAttribute} attribute - The buffer attribute holding vector data. 5510 * @param {number} index - The index into the attribute. 5511 * @return {Vector2} A reference to this vector. 5512 */ 5513 fromBufferAttribute( attribute, index ) { 5514 5515 this.x = attribute.getX( index ); 5516 this.y = attribute.getY( index ); 5517 5518 return this; 5519 5520 } 5521 5522 /** 5523 * Rotates this vector around the given center by the given angle. 5524 * 5525 * @param {Vector2} center - The point around which to rotate. 5526 * @param {number} angle - The angle to rotate, in radians. 5527 * @return {Vector2} A reference to this vector. 5528 */ 5529 rotateAround( center, angle ) { 5530 5531 const c = Math.cos( angle ), s = Math.sin( angle ); 5532 5533 const x = this.x - center.x; 5534 const y = this.y - center.y; 5535 5536 this.x = x * c - y * s + center.x; 5537 this.y = x * s + y * c + center.y; 5538 5539 return this; 5540 5541 } 5542 5543 /** 5544 * Sets each component of this vector to a pseudo-random value between `0` and 5545 * `1`, excluding `1`. 5546 * 5547 * @return {Vector2} A reference to this vector. 5548 */ 5549 random() { 5550 5551 this.x = Math.random(); 5552 this.y = Math.random(); 5553 5554 return this; 5555 5556 } 5557 5558 *[ Symbol.iterator ]() { 5559 5560 yield this.x; 5561 yield this.y; 5562 5563 } 5564 5565} 5566 5567/** 5568 *
5568Represents a 3x3 matrix. 5569 * 5570 * A Note on Row-Major and Column-Major Ordering: 5571 * 5572 * The constructor and {@link Matrix3#set} method take arguments in 5573 * [row-major]{@link https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order} 5574 * order, while internally they are stored in the {@link Matrix3#elements} array in column-major order. 5575 * This means that calling: 5576 * ```js 5577 * const m = new THREE.Matrix(); 5578 * m.set( 11, 12, 13, 5579 * 21, 22, 23, 5580 * 31, 32, 33 ); 5581 * ``` 5582 * will result in the elements array containing: 5583 * ```js 5584 * m.elements = [ 11, 21, 31, 5585 * 12, 22, 32, 5586 * 13, 23, 33 ]; 5587 * ``` 5588 * and internally all calculations are performed using column-major ordering. 5589 * However, as the actual ordering makes no difference mathematically and 5590 * most people are used to thinking about matrices in row-major order, the 5591 * three.js documentation shows matrices in row-major order. Just bear in 5592 * mind that if you are reading the source code, you'll have to take the 5593 * transpose of any matrices outlined here to make sense of the calculations. 5594 */ 5595class Matrix3 { 5596 5597 /** 5598 * Constructs a new 3x3 matrix. The arguments are supposed to be 5599 * in row-major order. If no arguments are provided, the constructor 5600 * initializes the matrix as an identity matrix. 5601 * 5602 * @param {number} [n11] - 1-1 matrix element. 5603 * @param {number} [n12] - 1-2 matrix element. 5604 * @param {number} [n13] - 1-3 matrix element. 5605 * @param {number} [n21] - 2-1 matrix element. 5606 * @param {number} [n22] - 2-2 matrix element. 5607 * @param {number} [n23] - 2-3 matrix element. 5608 * @param {number} [n31] - 3-1 matrix element. 5609 * @param {number} [n32] - 3-2 matrix element. 5610 * @param {number} [n33] - 3-3 matrix element. 5611 */ 5612 constructor( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { 5613 5614 /** 5615 * This flag can be used for type testing. 5616 * 5617 * @type {boolean} 5618 * @readonly 5619 * @default true 5620 */ 5621 Matrix3.prototype.isMatrix3 = true; 5622 5623 /** 5624 * A column-major list of matrix values. 5625 * 5626 * @type {Array<number>} 5627 */ 5628 this.elements = [ 5629 5630 1, 0, 0, 5631 0, 1, 0, 5632 0, 0, 1 5633 5634 ]; 5635 5636 if ( n11 !== undefined ) { 5637 5638 this.set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ); 5639 5640 } 5641 5642 } 5643 5644 /** 5645 * Sets the elements of the matrix.The arguments are supposed to be 5646 * in row-major order. 5647 * 5648 * @param {number} [n11] - 1-1 matrix element. 5649 * @param {number} [n12] - 1-2 matrix element. 5650 * @param {number} [n13] - 1-3 matrix element. 5651 * @param {number} [n21] - 2-1 matrix element. 5652 * @param {number} [n22] - 2-2 matrix element. 5653 * @param {number} [n23] - 2-3 matrix element. 5654 * @param {number} [n31] - 3-1 matrix element. 5655 * @param {number} [n32] - 3-2 matrix element. 5656 * @param {number} [n33] - 3-3 matrix element. 5657 * @return {Matrix3} A reference to this matrix. 5658 */ 5659 set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { 5660 5661 const te = this.elements; 5662 5663 te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31; 5664 te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32; 5665 te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33; 5666 5667 return this; 5668 5669 } 5670
vendor: 3,926 bytes, lines 5671-5847
5671 /** 5672 * Sets this matrix to the 3x3 identity matrix. 5673 * 5674 * @return {Matrix3} A reference to this matrix. 5675 */ 5676 identity() { 5677 5678 this.set( 5679 5680 1, 0, 0, 5681 0, 1, 0, 5682 0, 0, 1 5683 5684 ); 5685 5686 return this; 5687 5688 } 5689 5690 /** 5691 * Copies the values of the given matrix to this instance. 5692 * 5693 * @param {Matrix3} m - The matrix to copy. 5694 * @return {Matrix3} A reference to this matrix. 5695 */ 5696 copy( m ) { 5697 5698 const te = this.elements; 5699 const me = m.elements; 5700 5701 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; 5702 te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; 5703 te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ]; 5704 5705 return this; 5706 5707 } 5708 5709 /** 5710 * Extracts the basis of this matrix into the three axis vectors provided. 5711 * 5712 * @param {Vector3} xAxis - The basis's x axis. 5713 * @param {Vector3} yAxis - The basis's y axis. 5714 * @param {Vector3} zAxis - The basis's z axis. 5715 * @return {Matrix3} A reference to this matrix. 5716 */ 5717 extractBasis( xAxis, yAxis, zAxis ) { 5718 5719 xAxis.setFromMatrix3Column( this, 0 ); 5720 yAxis.setFromMatrix3Column( this, 1 ); 5721 zAxis.setFromMatrix3Column( this, 2 ); 5722 5723 return this; 5724 5725 } 5726 5727 /** 5728 * Set this matrix to the upper 3x3 matrix of the given 4x4 matrix. 5729 * 5730 * @param {Matrix4} m - The 4x4 matrix. 5731 * @return {Matrix3} A reference to this matrix. 5732 */ 5733 setFromMatrix4( m ) { 5734 5735 const me = m.elements; 5736 5737 this.set( 5738 5739 me[ 0 ], me[ 4 ], me[ 8 ], 5740 me[ 1 ], me[ 5 ], me[ 9 ], 5741 me[ 2 ], me[ 6 ], me[ 10 ] 5742 5743 ); 5744 5745 return this; 5746 5747 } 5748 5749 /** 5750 * Post-multiplies this matrix by the given 3x3 matrix. 5751 * 5752 * @param {Matrix3} m - The matrix to multiply with. 5753 * @return {Matrix3} A reference to this matrix. 5754 */ 5755 multiply( m ) { 5756 5757 return this.multiplyMatrices( this, m ); 5758 5759 } 5760 5761 /** 5762 * Pre-multiplies this matrix by the given 3x3 matrix. 5763 * 5764 * @param {Matrix3} m - The matrix to multiply with. 5765 * @return {Matrix3} A reference to this matrix. 5766 */ 5767 premultiply( m ) { 5768 5769 return this.multiplyMatrices( m, this ); 5770 5771 } 5772 5773 /** 5774 * Multiples the given 3x3 matrices and stores the result 5775 * in this matrix. 5776 * 5777 * @param {Matrix3} a - The first matrix. 5778 * @param {Matrix3} b - The second matrix. 5779 * @return {Matrix3} A reference to this matrix. 5780 */ 5781 multiplyMatrices( a, b ) { 5782 5783 const ae = a.elements; 5784 const be = b.elements; 5785 const te = this.elements; 5786 5787 const a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ]; 5788 const a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ]; 5789 const a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ]; 5790 5791 const b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ]; 5792 const b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ]; 5793 const b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ]; 5794 5795 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31; 5796 te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32; 5797 te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33; 5798 5799 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31; 5800 te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32; 5801 te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33; 5802 5803 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31; 5804 te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32; 5805 te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33; 5806 5807 return this; 5808 5809 } 5810 5811 /** 5812 * Multiplies every component of the matrix by the given scalar. 5813 * 5814 * @param {number} s - The scalar. 5815 * @return {Matrix3} A reference to this matrix. 5816 */ 5817 multiplyScalar( s ) { 5818 5819 const te = this.elements; 5820 5821 te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s; 5822 te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s; 5823 te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s; 5824 5825 return this; 5826 5827 } 5828 5829 /** 5830 * Computes and returns the determinant of this matrix. 5831 * 5832 * @return {number} The determinant. 5833 */ 5834 determinant() { 5835 5836 const te = this.elements; 5837 5838 const a = te[ 0 ], b = te[ 1 ], c = te[ 2 ], 5839 d = te[ 3 ], e = te[ 4 ], f = te[ 5 ], 5840 g = te[ 6 ], h = te[ 7 ], i = te[ 8 ]; 5841 5842 return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g; 5843 5844 } 5845 5846 /** 5847 * Inverts this matrix, using the [analytic method]{@link https://en.wikipedia.org/wiki/Invertible_matrix#Analytic_solution}
vendor: 6,837 bytes, lines 5847-6178
5847. 5848 * You can not invert with a determinant of zero. If you attempt this, the method produces 5849 * a zero matrix instead. 5850 * 5851 * @return {Matrix3} A reference to this matrix. 5852 */ 5853 invert() { 5854 5855 const te = this.elements, 5856 5857 n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], 5858 n12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ], 5859 n13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ], 5860 5861 t11 = n33 * n22 - n32 * n23, 5862 t12 = n32 * n13 - n33 * n12, 5863 t13 = n23 * n12 - n22 * n13, 5864 5865 det = n11 * t11 + n21 * t12 + n31 * t13; 5866 5867 if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 ); 5868 5869 const detInv = 1 / det; 5870 5871 te[ 0 ] = t11 * detInv; 5872 te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv; 5873 te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv; 5874 5875 te[ 3 ] = t12 * detInv; 5876 te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv; 5877 te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv; 5878 5879 te[ 6 ] = t13 * detInv; 5880 te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv; 5881 te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv; 5882 5883 return this; 5884 5885 } 5886 5887 /** 5888 * Transposes this matrix in place. 5889 * 5890 * @return {Matrix3} A reference to this matrix. 5891 */ 5892 transpose() { 5893 5894 let tmp; 5895 const m = this.elements; 5896 5897 tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp; 5898 tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp; 5899 tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp; 5900 5901 return this; 5902 5903 } 5904 5905 /** 5906 * Computes the normal matrix which is the inverse transpose of the upper 5907 * left 3x3 portion of the given 4x4 matrix. 5908 * 5909 * @param {Matrix4} matrix4 - The 4x4 matrix. 5910 * @return {Matrix3} A reference to this matrix. 5911 */ 5912 getNormalMatrix( matrix4 ) { 5913 5914 return this.setFromMatrix4( matrix4 ).invert().transpose(); 5915 5916 } 5917 5918 /** 5919 * Transposes this matrix into the supplied array, and returns itself unchanged. 5920 * 5921 * @param {Array<number>} r - An array to store the transposed matrix elements. 5922 * @return {Matrix3} A reference to this matrix. 5923 */ 5924 transposeIntoArray( r ) { 5925 5926 const m = this.elements; 5927 5928 r[ 0 ] = m[ 0 ]; 5929 r[ 1 ] = m[ 3 ]; 5930 r[ 2 ] = m[ 6 ]; 5931 r[ 3 ] = m[ 1 ]; 5932 r[ 4 ] = m[ 4 ]; 5933 r[ 5 ] = m[ 7 ]; 5934 r[ 6 ] = m[ 2 ]; 5935 r[ 7 ] = m[ 5 ]; 5936 r[ 8 ] = m[ 8 ]; 5937 5938 return this; 5939 5940 } 5941 5942 /** 5943 * Sets the UV transform matrix from offset, repeat, rotation, and center. 5944 * 5945 * @param {number} tx - Offset x. 5946 * @param {number} ty - Offset y. 5947 * @param {number} sx - Repeat x. 5948 * @param {number} sy - Repeat y. 5949 * @param {number} rotation - Rotation, in radians. Positive values rotate counterclockwise. 5950 * @param {number} cx - Center x of rotation. 5951 * @param {number} cy - Center y of rotation 5952 * @return {Matrix3} A reference to this matrix. 5953 */ 5954 setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) { 5955 5956 const c = Math.cos( rotation ); 5957 const s = Math.sin( rotation ); 5958 5959 this.set( 5960 sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx, 5961 - sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty, 5962 0, 0, 1 5963 ); 5964 5965 return this; 5966 5967 } 5968 5969 /** 5970 * Scales this matrix with the given scalar values. 5971 * 5972 * @param {number} sx - The amount to scale in the X axis. 5973 * @param {number} sy - The amount to scale in the Y axis. 5974 * @return {Matrix3} A reference to this matrix. 5975 */ 5976 scale( sx, sy ) { 5977 5978 this.premultiply( _m3.makeScale( sx, sy ) ); 5979 5980 return this; 5981 5982 } 5983 5984 /** 5985 * Rotates this matrix by the given angle. 5986 * 5987 * @param {number} theta - The rotation in radians. 5988 * @return {Matrix3} A reference to this matrix. 5989 */ 5990 rotate( theta ) { 5991 5992 this.premultiply( _m3.makeRotation( - theta ) ); 5993 5994 return this; 5995 5996 } 5997 5998 /** 5999 * Translates this matrix by the given scalar values. 6000 * 6001 * @param {number} tx - The amount to translate in the X axis. 6002 * @param {number} ty - The amount to translate in the Y axis. 6003 * @return {Matrix3} A reference to this matrix. 6004 */ 6005 translate( tx, ty ) { 6006 6007 this.premultiply( _m3.makeTranslation( tx, ty ) ); 6008 6009 return this; 6010 6011 } 6012 6013 // for 2D Transforms 6014 6015 /** 6016 * Sets this matrix as a 2D translation transform. 6017 * 6018 * @param {number|Vector2} x - The amount to translate in the X axis or alternatively a translation vector. 6019 * @param {number} y - The amount to translate in the Y axis. 6020 * @return {Matrix3} A reference to this matrix. 6021 */ 6022 makeTranslation( x, y ) { 6023 6024 if ( x.isVector2 ) { 6025 6026 this.set( 6027 6028 1, 0, x.x, 6029 0, 1, x.y, 6030 0, 0, 1 6031 6032 ); 6033 6034 } else { 6035 6036 this.set( 6037 6038 1, 0, x, 6039 0, 1, y, 6040 0, 0, 1 6041 6042 ); 6043 6044 } 6045 6046 return this; 6047 6048 } 6049 6050 /** 6051 * Sets this matrix as a 2D rotational transformation. 6052 * 6053 * @param {number} theta - The rotation in radians. 6054 * @return {Matrix3} A reference to this matrix. 6055 */ 6056 makeRotation( theta ) { 6057 6058 // counterclockwise 6059 6060 const c = Math.cos( theta ); 6061 const s = Math.sin( theta ); 6062 6063 this.set( 6064 6065 c, - s, 0, 6066 s, c, 0, 6067 0, 0, 1 6068 6069 ); 6070 6071 return this; 6072 6073 } 6074 6075 /** 6076 * Sets this matrix as a 2D scale transform. 6077 * 6078 * @param {number} x - The amount to scale in the X axis. 6079 * @param {number} y - The amount to scale in the Y axis. 6080 * @return {Matrix3} A reference to this matrix. 6081 */ 6082 makeScale( x, y ) { 6083 6084 this.set( 6085 6086 x, 0, 0, 6087 0, y, 0, 6088 0, 0, 1 6089 6090 ); 6091 6092 return this; 6093 6094 } 6095 6096 /** 6097 * Returns `true` if this matrix is equal with the given one. 6098 * 6099 * @param {Matrix3} matrix - The matrix to test for equality. 6100 * @return {boolean} Whether this matrix is equal with the given one. 6101 */ 6102 equals( matrix ) { 6103 6104 const te = this.elements; 6105 const me = matrix.elements; 6106 6107 for ( let i = 0; i < 9; i ++ ) { 6108 6109 if ( te[ i ] !== me[ i ] ) return false; 6110 6111 } 6112 6113 return true; 6114 6115 } 6116 6117 /** 6118 * Sets the elements of the matrix from the given array. 6119 * 6120 * @param {Array<number>} array - The matrix elements in column-major order. 6121 * @param {number} [offset=0] - Index of the first element in the array. 6122 * @return {Matrix3} A reference to this matrix. 6123 */ 6124 fromArray( array, offset = 0 ) { 6125 6126 for ( let i = 0; i < 9; i ++ ) { 6127 6128 this.elements[ i ] = array[ i + offset ]; 6129 6130 } 6131 6132 return this; 6133 6134 } 6135 6136 /** 6137 * Writes the elements of this matrix to the given array. If no array is provided, 6138 * the method returns a new instance. 6139 * 6140 * @param {Array<number>} [array=[]] - The target array holding the matrix elements in column-major order. 6141 * @param {number} [offset=0] - Index of the first element in the array. 6142 * @return {Array<number>} The matrix elements in column-major order. 6143 */ 6144 toArray( array = [], offset = 0 ) { 6145 6146 const te = this.elements; 6147 6148 array[ offset ] = te[ 0 ]; 6149 array[ offset + 1 ] = te[ 1 ]; 6150 array[ offset + 2 ] = te[ 2 ]; 6151 6152 array[ offset + 3 ] = te[ 3 ]; 6153 array[ offset + 4 ] = te[ 4 ]; 6154 array[ offset + 5 ] = te[ 5 ]; 6155 6156 array[ offset + 6 ] = te[ 6 ]; 6157 array[ offset + 7 ] = te[ 7 ]; 6158 array[ offset + 8 ] = te[ 8 ]; 6159 6160 return array; 6161 6162 } 6163 6164 /** 6165 * Returns a matrix with copied values from this instance. 6166 * 6167 * @return {Matrix3} A clone of this instance. 6168 */ 6169 clone() { 6170 6171 return new this.constructor().fromArray( this.elements ); 6172 6173 } 6174 6175} 6176 6177const _m3 = /*@__PURE__*/ new Matrix3(); 6178
vendor: 4,073 bytes, lines 6179-6347
6179function arrayNeedsUint32( array ) { 6180 6181 // assumes larger values usually on last 6182 6183 for ( let i = array.length - 1; i >= 0; -- i ) { 6184 6185 if ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565 6186 6187 } 6188 6189 return false; 6190 6191} 6192 6193function createElementNS( name ) { 6194 6195 return document.createElementNS( 'http://www.w3.org/1999/xhtml', name ); 6196 6197} 6198 6199const LINEAR_REC709_TO_XYZ = /*@__PURE__*/ new Matrix3().set( 6200 0.4123908, 0.3575843, 0.1804808, 6201 0.2126390, 0.7151687, 0.0721923, 6202 0.0193308, 0.1191948, 0.9505322 6203); 6204 6205const XYZ_TO_LINEAR_REC709 = /*@__PURE__*/ new Matrix3().set( 6206 3.2409699, -1.5373832, -0.4986108, 6207 -0.9692436, 1.8759675, 0.0415551, 6208 0.0556301, -0.203977, 1.0569715 6209); 6210 6211function createColorManagement() { 6212 6213 const ColorManagement = { 6214 6215 enabled: true, 6216 6217 workingColorSpace: LinearSRGBColorSpace, 6218 6219 /** 6220 * Implementations of supported color spaces. 6221 * 6222 * Required: 6223 * - primaries: chromaticity coordinates [ rx ry gx gy bx by ] 6224 * - whitePoint: reference white [ x y ] 6225 * - transfer: transfer function (pre-defined) 6226 * - toXYZ: Matrix3 RGB to XYZ transform 6227 * - fromXYZ: Matrix3 XYZ to RGB transform 6228 * - luminanceCoefficients: RGB luminance coefficients 6229 * 6230 * Optional: 6231 * - outputColorSpaceConfig: { drawingBufferColorSpace: ColorSpace } 6232 * - workingColorSpaceConfig: { unpackColorSpace: ColorSpace } 6233 * 6234 * Reference: 6235 * - https://www.russellcottrell.com/photo/matrixCalculator.htm 6236 */ 6237 spaces: {}, 6238 6239 convert: function ( color, sourceColorSpace, targetColorSpace ) { 6240 6241 if ( this.enabled === false || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) { 6242 6243 return color; 6244 6245 } 6246 6247 if ( this.spaces[ sourceColorSpace ].transfer === SRGBTransfer ) { 6248 6249 color.r = SRGBToLinear( color.r ); 6250 color.g = SRGBToLinear( color.g ); 6251 color.b = SRGBToLinear( color.b ); 6252 6253 } 6254 6255 if ( this.spaces[ sourceColorSpace ].primaries !== this.spaces[ targetColorSpace ].primaries ) { 6256 6257 color.applyMatrix3( this.spaces[ sourceColorSpace ].toXYZ ); 6258 color.applyMatrix3( this.spaces[ targetColorSpace ].fromXYZ ); 6259 6260 } 6261 6262 if ( this.spaces[ targetColorSpace ].transfer === SRGBTransfer ) { 6263 6264 color.r = LinearToSRGB( color.r ); 6265 color.g = LinearToSRGB( color.g ); 6266 color.b = LinearToSRGB( color.b ); 6267 6268 } 6269 6270 return color; 6271 6272 }, 6273 6274 fromWorkingColorSpace: function ( color, targetColorSpace ) { 6275 6276 return this.convert( color, this.workingColorSpace, targetColorSpace ); 6277 6278 }, 6279 6280 toWorkingColorSpace: function ( color, sourceColorSpace ) { 6281 6282 return this.convert( color, sourceColorSpace, this.workingColorSpace ); 6283 6284 }, 6285 6286 getPrimaries: function ( colorSpace ) { 6287 6288 return this.spaces[ colorSpace ].primaries; 6289 6290 }, 6291 6292 getTransfer: function ( colorSpace ) { 6293 6294 if ( colorSpace === NoColorSpace ) return LinearTransfer; 6295 6296 return this.spaces[ colorSpace ].transfer; 6297 6298 }, 6299 6300 getLuminanceCoefficients: function ( target, colorSpace = this.workingColorSpace ) { 6301 6302 return target.fromArray( this.spaces[ colorSpace ].luminanceCoefficients ); 6303 6304 }, 6305 6306 define: function ( colorSpaces ) { 6307 6308 Object.assign( this.spaces, colorSpaces ); 6309 6310 }, 6311 6312 // Internal APIs 6313 6314 _getMatrix: function ( targetMatrix, sourceColorSpace, targetColorSpace ) { 6315 6316 return targetMatrix 6317 .copy( this.spaces[ sourceColorSpace ].toXYZ ) 6318 .multiply( this.spaces[ targetColorSpace ].fromXYZ ); 6319 6320 }, 6321 6322 _getDrawingBufferColorSpace: function ( colorSpace ) { 6323 6324 return this.spaces[ colorSpace ].outputColorSpaceConfig.drawingBufferColorSpace; 6325 6326 }, 6327 6328 _getUnpackColorSpace: function ( colorSpace = this.workingColorSpace ) { 6329 6330 return this.spaces[ colorSpace ].workingColorSpaceConfig.unpackColorSpace; 6331 6332 } 6333 6334 }; 6335 6336 /****************************************************************************** 6337 * sRGB definitions 6338 */ 6339 6340 const REC709_PRIMARIES = [ 0.640, 0.330, 0.300, 0.600, 0.150, 0.060 ]; 6341 const REC709_LUMINANCE_COEFFICIENTS = [ 0.2126, 0.7152, 0.0722 ]; 6342 const D65 = [ 0.3127, 0.3290 ]; 6343 6344 ColorManagement.define( { 6345 6346 [ LinearSRGBColorSpace ]: { 6347 primaries: REC709_PRIMARIES,
vendor: 5,188 bytes, lines 6348-6591
6348 whitePoint: D65, 6349 transfer: LinearTransfer, 6350 toXYZ: LINEAR_REC709_TO_XYZ, 6351 fromXYZ: XYZ_TO_LINEAR_REC709, 6352 luminanceCoefficients: REC709_LUMINANCE_COEFFICIENTS, 6353 workingColorSpaceConfig: { unpackColorSpace: SRGBColorSpace }, 6354 outputColorSpaceConfig: { drawingBufferColorSpace: SRGBColorSpace } 6355 }, 6356 6357 [ SRGBColorSpace ]: { 6358 primaries: REC709_PRIMARIES, 6359 whitePoint: D65, 6360 transfer: SRGBTransfer, 6361 toXYZ: LINEAR_REC709_TO_XYZ, 6362 fromXYZ: XYZ_TO_LINEAR_REC709, 6363 luminanceCoefficients: REC709_LUMINANCE_COEFFICIENTS, 6364 outputColorSpaceConfig: { drawingBufferColorSpace: SRGBColorSpace } 6365 }, 6366 6367 } ); 6368 6369 return ColorManagement; 6370 6371} 6372 6373const ColorManagement = /*@__PURE__*/ createColorManagement(); 6374 6375function SRGBToLinear( c ) { 6376 6377 return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 ); 6378 6379} 6380 6381function LinearToSRGB( c ) { 6382 6383 return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055; 6384 6385} 6386 6387let _canvas; 6388 6389/** 6390 * A class containing utility functions for images. 6391 * 6392 * @hideconstructor 6393 */ 6394class ImageUtils { 6395 6396 /** 6397 * Returns a data URI containing a representation of the given image. 6398 * 6399 * @param {(HTMLImageElement|HTMLCanvasElement)} image - The image object. 6400 * @param {string} [type='image/png'] - Indicates the image format. 6401 * @return {string} The data URI. 6402 */ 6403 static getDataURL( image, type = 'image/png' ) { 6404 6405 if ( /^data:/i.test( image.src ) ) { 6406 6407 return image.src; 6408 6409 } 6410 6411 if ( typeof HTMLCanvasElement === 'undefined' ) { 6412 6413 return image.src; 6414 6415 } 6416 6417 let canvas; 6418 6419 if ( image instanceof HTMLCanvasElement ) { 6420 6421 canvas = image; 6422 6423 } else { 6424 6425 if ( _canvas === undefined ) _canvas = createElementNS( 'canvas' ); 6426 6427 _canvas.width = image.width; 6428 _canvas.height = image.height; 6429 6430 const context = _canvas.getContext( '2d' ); 6431 6432 if ( image instanceof ImageData ) { 6433 6434 context.putImageData( image, 0, 0 ); 6435 6436 } else { 6437 6438 context.drawImage( image, 0, 0, image.width, image.height ); 6439 6440 } 6441 6442 canvas = _canvas; 6443 6444 } 6445 6446 return canvas.toDataURL( type ); 6447 6448 } 6449 6450 /** 6451 * Converts the given sRGB image data to linear color space. 6452 * 6453 * @param {(HTMLImageElement|HTMLCanvasElement|ImageBitmap|Object)} image - The image object. 6454 * @return {HTMLCanvasElement|Object} The converted image. 6455 */ 6456 static sRGBToLinear( image ) { 6457 6458 if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || 6459 ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || 6460 ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { 6461 6462 const canvas = createElementNS( 'canvas' ); 6463 6464 canvas.width = image.width; 6465 canvas.height = image.height; 6466 6467 const context = canvas.getContext( '2d' ); 6468 context.drawImage( image, 0, 0, image.width, image.height ); 6469 6470 const imageData = context.getImageData( 0, 0, image.width, image.height ); 6471 const data = imageData.data; 6472 6473 for ( let i = 0; i < data.length; i ++ ) { 6474 6475 data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255; 6476 6477 } 6478 6479 context.putImageData( imageData, 0, 0 ); 6480 6481 return canvas; 6482 6483 } else if ( image.data ) { 6484 6485 const data = image.data.slice( 0 ); 6486 6487 for ( let i = 0; i < data.length; i ++ ) { 6488 6489 if ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) { 6490 6491 data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 ); 6492 6493 } else { 6494 6495 // assuming float 6496 6497 data[ i ] = SRGBToLinear( data[ i ] ); 6498 6499 } 6500 6501 } 6502 6503 return { 6504 data: data, 6505 width: image.width, 6506 height: image.height 6507 }; 6508 6509 } else { 6510 6511 console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' ); 6512 return image; 6513 6514 } 6515 6516 } 6517 6518} 6519 6520let _sourceId = 0; 6521 6522/** 6523 * Represents the data source of a texture. 6524 * 6525 * The main purpose of this class is to decouple the data definition from the texture 6526 * definition so the same data can be used with multiple texture instances. 6527 */ 6528class Source { 6529 6530 /** 6531 * Constructs a new video texture. 6532 * 6533 * @param {any} [data=null] - The data definition of a texture. 6534 */ 6535 constructor( data = null ) { 6536 6537 /** 6538 * This flag can be used for type testing. 6539 * 6540 * @type {boolean} 6541 * @readonly 6542 * @default true 6543 */ 6544 this.isSource = true; 6545 6546 /** 6547 * The ID of the source. 6548 * 6549 * @name Source#id 6550 * @type {number} 6551 * @readonly 6552 */ 6553 Object.defineProperty( this, 'id', { value: _sourceId ++ } ); 6554 6555 /** 6556 * The UUID of the source. 6557 * 6558 * @type {string} 6559 * @readonly 6560 */ 6561 this.uuid = generateUUID(); 6562 6563 /** 6564 * The data definition of a texture. 6565 * 6566 * @type {any} 6567 */ 6568 this.data = data; 6569 6570 /** 6571 * This property is only relevant when {@link Source#needsUpdate} is set to `true` and 6572 * provides more control on how texture data should be processed. When `dataReady` is set 6573 * to `false`, the engine performs the memory allocation (if necessary) but does not transfer 6574 * the data into the GPU memory. 6575 * 6576 * @type {boolean} 6577 * @default true 6578 */ 6579 this.dataReady = true; 6580 6581 /** 6582 * This starts at `0` and counts how many times {@link Source#needsUpdate} is set to `true`. 6583 * 6584 * @type {number} 6585 * @readonly 6586 * @default 0 6587 */ 6588 this.version = 0; 6589 6590 } 6591
vendor: 5,044 bytes, lines 6592-6811
6592 /** 6593 * When the property is set to `true`, the engine allocates the memory 6594 * for the texture (if necessary) and triggers the actual texture upload 6595 * to the GPU next time the source is used. 6596 * 6597 * @type {boolean} 6598 * @default false 6599 * @param {boolean} value 6600 */ 6601 set needsUpdate( value ) { 6602 6603 if ( value === true ) this.version ++; 6604 6605 } 6606 6607 /** 6608 * Serializes the source into JSON. 6609 * 6610 * @param {?(Object|string)} meta - An optional value holding meta information about the serialization. 6611 * @return {Object} A JSON object representing the serialized source. 6612 * @see {@link ObjectLoader#parse} 6613 */ 6614 toJSON( meta ) { 6615 6616 const isRootObject = ( meta === undefined || typeof meta === 'string' ); 6617 6618 if ( ! isRootObject && meta.images[ this.uuid ] !== undefined ) { 6619 6620 return meta.images[ this.uuid ]; 6621 6622 } 6623 6624 const output = { 6625 uuid: this.uuid, 6626 url: '' 6627 }; 6628 6629 const data = this.data; 6630 6631 if ( data !== null ) { 6632 6633 let url; 6634 6635 if ( Array.isArray( data ) ) { 6636 6637 // cube texture 6638 6639 url = []; 6640 6641 for ( let i = 0, l = data.length; i < l; i ++ ) { 6642 6643 if ( data[ i ].isDataTexture ) { 6644 6645 url.push( serializeImage( data[ i ].image ) ); 6646 6647 } else { 6648 6649 url.push( serializeImage( data[ i ] ) ); 6650 6651 } 6652 6653 } 6654 6655 } else { 6656 6657 // texture 6658 6659 url = serializeImage( data ); 6660 6661 } 6662 6663 output.url = url; 6664 6665 } 6666 6667 if ( ! isRootObject ) { 6668 6669 meta.images[ this.uuid ] = output; 6670 6671 } 6672 6673 return output; 6674 6675 } 6676 6677} 6678 6679function serializeImage( image ) { 6680 6681 if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || 6682 ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || 6683 ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { 6684 6685 // default images 6686 6687 return ImageUtils.getDataURL( image ); 6688 6689 } else { 6690 6691 if ( image.data ) { 6692 6693 // images of DataTexture 6694 6695 return { 6696 data: Array.from( image.data ), 6697 width: image.width, 6698 height: image.height, 6699 type: image.data.constructor.name 6700 }; 6701 6702 } else { 6703 6704 console.warn( 'THREE.Texture: Unable to serialize Texture.' ); 6705 return {}; 6706 6707 } 6708 6709 } 6710 6711} 6712 6713let _textureId = 0; 6714 6715/** 6716 * Base class for all textures. 6717 * 6718 * Note: After the initial use of a texture, its dimensions, format, and type 6719 * cannot be changed. Instead, call {@link Texture#dispose} on the texture and instantiate a new one. 6720 * 6721 * @augments EventDispatcher 6722 */ 6723class Texture extends EventDispatcher { 6724 6725 /** 6726 * Constructs a new texture. 6727 * 6728 * @param {?Object} [image=Texture.DEFAULT_IMAGE] - The image holding the texture data. 6729 * @param {number} [mapping=Texture.DEFAULT_MAPPING] - The texture mapping. 6730 * @param {number} [wrapS=ClampToEdgeWrapping] - The wrapS value. 6731 * @param {number} [wrapT=ClampToEdgeWrapping] - The wrapT value. 6732 * @param {number} [magFilter=LinearFilter] - The mag filter value. 6733 * @param {number} [minFilter=LinearMipmapLinearFilter] - The min filter value. 6734 * @param {number} [format=RGBAFormat] - The texture format. 6735 * @param {number} [type=UnsignedByteType] - The texture type. 6736 * @param {number} [anisotropy=Texture.DEFAULT_ANISOTROPY] - The anisotropy value. 6737 * @param {string} [colorSpace=NoColorSpace] - The color space. 6738 */ 6739 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 ) { 6740 6741 super(); 6742 6743 /** 6744 * This flag can be used for type testing. 6745 * 6746 * @type {boolean} 6747 * @readonly 6748 * @default true 6749 */ 6750 this.isTexture = true; 6751 6752 /** 6753 * The ID of the texture. 6754 * 6755 * @name Texture#id 6756 * @type {number} 6757 * @readonly 6758 */ 6759 Object.defineProperty( this, 'id', { value: _textureId ++ } ); 6760 6761 /** 6762 * The UUID of the material. 6763 * 6764 * @type {string} 6765 * @readonly 6766 */ 6767 this.uuid = generateUUID(); 6768 6769 /** 6770 * The name of the material. 6771 * 6772 * @type {string} 6773 */ 6774 this.name = ''; 6775 6776 /** 6777 * The data definition of a texture. A reference to the data source can be 6778 * shared across textures. This is often useful in context of spritesheets 6779 * where multiple textures render the same data but with different texture 6780 * transformations. 6781 * 6782 * @type {Source} 6783 */ 6784 this.source = new Source( image ); 6785 6786 /** 6787 * An array holding user-defined mipmaps. 6788 * 6789 * @type {Array<Object>} 6790 */ 6791 this.mipmaps = []; 6792 6793 /** 6794 * How the texture is applied to the object. The value `UVMapping` 6795 * is the default, where texture or uv coordinates are used to apply the map. 6796 * 6797 * @type {(UVMapping|CubeReflectionMapping|CubeRefractionMapping|EquirectangularReflectionMapping|EquirectangularRefractionMapping|CubeUVReflectionMapping)} 6798 * @default UVMapping 6799 */ 6800 this.mapping = mapping; 6801 6802 /** 6803 * Lets you select the uv attribute to map the texture to. `0` for `uv`, 6804 * `1` for `uv1`, `2` for `uv2` and `3` for `uv3`. 6805 * 6806 * @type {number} 6807 * @default 0 6808 */ 6809 this.channel = 0; 6810 6811 /**
6812 * This defines how the texture is wrapped horizontally and corresponds to 6813 * *U* in UV mapping. 6814 * 6815 * @type {(RepeatWrapping|ClampToEdgeWrapping|MirroredRepeatWrapping)} 6816 * @default ClampToEdgeWrapping 6817 */ 6818 this.wrapS = wrapS; 6819 6820 /** 6821 * This defines how the texture is wrapped horizontally and corresponds to 6822 * *V* in UV mapping. 6823 * 6824 * @type {(RepeatWrapping|ClampToEdgeWrapping|MirroredRepeatWrapping)} 6825 * @default ClampToEdgeWrapping 6826 */ 6827 this.wrapT = wrapT; 6828 6829 /** 6830 * How the texture is sampled when a texel covers more than one pixel. 6831 * 6832 * @type {(NearestFilter|NearestMipmapNearestFilter|NearestMipmapLinearFilter|LinearFilter|LinearMipmapNearestFilter|LinearMipmapLinearFilter)} 6833 * @default LinearFilter 6834 */ 6835 this.magFilter = magFilter; 6836 6837 /** 6838 * How the texture is sampled when a texel covers less than one pixel. 6839 * 6840 * @type {(NearestFilter|NearestMipmapNearestFilter|NearestMipmapLinearFilter|LinearFilter|LinearMipmapNearestFilter|LinearMipmapLinearFilter)} 6841 * @default LinearMipmapLinearFilter 6842 */ 6843 this.minFilter = minFilter; 6844 6845 /** 6846 * The number of samples taken along the axis through the pixel that has the 6847 * highest density of texels. By default, this value is `1`. A higher value 6848 * gives a less blurry result than a basic mipmap, at the cost of more 6849 * texture samples being used. 6850 * 6851 * @type {number} 6852 * @default 0 6853 */ 6854 this.anisotropy = anisotropy; 6855 6856 /** 6857 * The format of the texture. 6858 * 6859 * @type {number} 6860 * @default RGBAFormat 6861 */ 6862 this.format = format; 6863 6864 /** 6865 * The default internal format is derived from {@link Texture#format} and {@link Texture#type} and 6866 * defines how the texture data is going to be stored on the GPU. 6867 * 6868 * This property allows to overwrite the default format. 6869 * 6870 * @type {?string} 6871 * @default null 6872 */ 6873 this.internalFormat = null; 6874 6875 /** 6876 * The data type of the texture. 6877 * 6878 * @type {number} 6879 * @default UnsignedByteType 6880 */ 6881 this.type = type; 6882 6883 /** 6884 * How much a single repetition of the texture is offset from the beginning, 6885 * in each direction U and V. Typical range is `0.0` to `1.0`. 6886 * 6887 * @type {Vector2} 6888 * @default (0,0) 6889 */ 6890 this.offset = new Vector2( 0, 0 ); 6891 6892 /** 6893 * How many times the texture is repeated across the surface, in each 6894 * direction U and V. If repeat is set greater than `1` in either direction, 6895 * the corresponding wrap parameter should also be set to `RepeatWrapping` 6896 * or `MirroredRepeatWrapping` to achieve the desired tiling effect. 6897 * 6898 * @type {Vector2} 6899 * @default (1,1) 6900 */ 6901 this.repeat = new Vector2( 1, 1 ); 6902 6903 /** 6904 * The point around which rotation occurs. A value of `(0.5, 0.5)` corresponds 6905 * to the center of the texture. Default is `(0, 0)`, the lower left. 6906 * 6907 * @type {Vector2} 6908 * @default (0,0) 6909 */ 6910 this.center = new Vector2( 0, 0 ); 6911 6912 /** 6913 * How much the texture is rotated around the center point, in radians. 6914 * Positive values are counter-clockwise. 6915 * 6916 * @type {number} 6917 * @default 0 6918 */ 6919 this.rotation = 0; 6920 6921 /** 6922 * Whether to update the texture's uv-transformation {@link Texture#matrix} 6923 * from the properties {@link Texture#offset}, {@link Texture#repeat}, 6924 * {@link Texture#rotation}, and {@link Texture#center}. 6925 * 6926 * Set this to `false` if you are specifying the uv-transform matrix directly. 6927 * 6928 * @type {boolean} 6929 * @default true 6930 */ 6931 this.matrixAutoUpdate = true; 6932 6933 /** 6934 * The uv-transformation matrix of the texture. 6935 * 6936 * @type {Matrix3} 6937 */ 6938 this.matrix = new Matrix3(); 6939 6940 /** 6941 * Whether to generate mipmaps (if possible) for a texture. 6942 * 6943 * Set this to `false` if you are creating mipmaps manually. 6944 * 6945 * @type {boolean} 6946 * @default true 6947 */ 6948 this.generateMipmaps = true; 6949 6950 /** 6951 * If set to `true`, the alpha channel, if present, is multiplied into the 6952 * color channels when the texture is uploaded to the GPU. 6953 * 6954 * Note that this property has no effect when using `ImageBitmap`. You need to 6955 * configure premultiply alpha on bitmap creation instead. 6956 * 6957 * @type {boolean} 6958 * @default false 6959 */ 6960 this.premultiplyAlpha = false;
6961 6962 /** 6963 * If set to `true`, the texture is flipped along the vertical axis when 6964 * uploaded to the GPU. 6965 * 6966 * Note that this property has no effect when using `ImageBitmap`. You need to 6967 * configure the flip on bitmap creation instead. 6968 * 6969 * @type {boolean} 6970 * @default true 6971 */ 6972 this.flipY = true; 6973 6974 /** 6975 * Specifies the alignment requirements for the start of each pixel row in memory. 6976 * The allowable values are `1` (byte-alignment), `2` (rows aligned to even-numbered bytes), 6977 * `4` (word-alignment), and `8` (rows start on double-word boundaries). 6978 * 6979 * @type {number} 6980 * @default 4 6981 */ 6982 this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) 6983 6984 /** 6985 * Textures containing color data should be annotated with `SRGBColorSpace` or `LinearSRGBColorSpace`. 6986 * 6987 * @type {string} 6988 * @default NoColorSpace 6989 */ 6990 this.colorSpace = colorSpace; 6991 6992 /** 6993 * An object that can be used to store custom data about the texture. It 6994 * should not hold references to functions as these will not be cloned. 6995 * 6996 * @type {Object} 6997 */ 6998 this.userData = {}; 6999 7000 /** 7001 * This starts at `0` and counts how many times {@link Texture#needsUpdate} is set to `true`. 7002 * 7003 * @type {number} 7004 * @readonly 7005 * @default 0 7006 */ 7007 this.version = 0; 7008 7009 /** 7010 * A callback function, called when the texture is updated (e.g., when 7011 * {@link Texture#needsUpdate} has been set to true and then the texture is used). 7012 * 7013 * @type {?Function} 7014 * @default null 7015 */ 7016 this.onUpdate = null; 7017 7018 /** 7019 * An optional back reference to the textures render target. 7020 * 7021 * @type {?(RenderTarget|WebGLRenderTarget)} 7022 * @default null 7023 */ 7024 this.renderTarget = null; 7025 7026 /** 7027 * Indicates whether a texture belongs to a render target or not. 7028 * 7029 * @type {boolean} 7030 * @readonly 7031 * @default false 7032 */ 7033 this.isRenderTargetTexture = false; 7034 7035 /** 7036 * Indicates whether this texture should be processed by `PMREMGenerator` or not 7037 * (only relevant for render target textures). 7038 * 7039 * @type {number} 7040 * @readonly 7041 * @default 0 7042 */ 7043 this.pmremVersion = 0; 7044 7045 } 7046 7047 /** 7048 * The image object holding the texture data. 7049 * 7050 * @type {?Object} 7051 */ 7052 get image() { 7053 7054 return this.source.data; 7055 7056 } 7057 7058 set image( value = null ) { 7059 7060 this.source.data = value; 7061 7062 } 7063 7064 /** 7065 * Updates the texture transformation matrix from the from the properties {@link Texture#offset}, 7066 * {@link Texture#repeat}, {@link Texture#rotation}, and {@link Texture#center}. 7067 */ 7068 updateMatrix() { 7069 7070 this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y ); 7071 7072 } 7073 7074 /** 7075 * Returns a new texture with copied values from this instance. 7076 * 7077 * @return {Texture} A clone of this instance. 7078 */ 7079 clone() { 7080 7081 return new this.constructor().copy( this ); 7082 7083 } 7084 7085 /** 7086 * Copies the values of the given texture to this instance. 7087 * 7088 * @param {Texture} source - The texture to copy. 7089 * @return {Texture} A reference to this instance. 7090 */ 7091 copy( source ) { 7092 7093 this.name = source.name; 7094 7095 this.source = source.source; 7096 this.mipmaps = source.mipmaps.slice( 0 ); 7097 7098 this.mapping = source.mapping; 7099 this.channel = source.channel; 7100 7101 this.wrapS = source.wrapS; 7102 this.wrapT = source.wrapT; 7103 7104 this.magFilter = source.magFilter; 7105 this.minFilter = source.minFilter; 7106 7107 this.anisotropy = source.anisotropy; 7108 7109 this.format = source.format; 7110 this.internalFormat = source.internalFormat; 7111 this.type = source.type; 7112 7113 this.offset.copy( source.offset ); 7114 this.repeat.copy( source.repeat ); 7115 this.center.copy( source.center ); 7116 this.rotation = source.rotation; 7117 7118 this.matrixAutoUpdate = source.matrixAutoUpdate; 7119 this.matrix.copy( source.matrix ); 7120 7121 this.generateMipmaps = source.generateMipmaps; 7122 this.premultiplyAlpha = source.premultiplyAlpha; 7123 this.flipY = source.flipY; 7124 this.unpackAlignment = source.unpackAlignment; 7125 this.colorSpace = source.colorSpace; 7126 7127 this.renderTarget = source.renderTarget; 7128 this.isRenderTargetTexture = source.isRenderTargetTexture; 7129 7130 this.userData = JSON.parse( JSON.stringify( source.userData ) ); 7131 7132 this.needsUpdate = true; 7133 7134 return this; 7135 7136 } 7137
vendor: 4,108 bytes, lines 7138-7376
7138 /** 7139 * Serializes the texture into JSON. 7140 * 7141 * @param {?(Object|string)} meta - An optional value holding meta information about the serialization. 7142 * @return {Object} A JSON object representing the serialized texture. 7143 * @see {@link ObjectLoader#parse} 7144 */ 7145 toJSON( meta ) { 7146 7147 const isRootObject = ( meta === undefined || typeof meta === 'string' ); 7148 7149 if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) { 7150 7151 return meta.textures[ this.uuid ]; 7152 7153 } 7154 7155 const output = { 7156 7157 metadata: { 7158 version: 4.6, 7159 type: 'Texture', 7160 generator: 'Texture.toJSON' 7161 }, 7162 7163 uuid: this.uuid, 7164 name: this.name, 7165 7166 image: this.source.toJSON( meta ).uuid, 7167 7168 mapping: this.mapping, 7169 channel: this.channel, 7170 7171 repeat: [ this.repeat.x, this.repeat.y ], 7172 offset: [ this.offset.x, this.offset.y ], 7173 center: [ this.center.x, this.center.y ], 7174 rotation: this.rotation, 7175 7176 wrap: [ this.wrapS, this.wrapT ], 7177 7178 format: this.format, 7179 internalFormat: this.internalFormat, 7180 type: this.type, 7181 colorSpace: this.colorSpace, 7182 7183 minFilter: this.minFilter, 7184 magFilter: this.magFilter, 7185 anisotropy: this.anisotropy, 7186 7187 flipY: this.flipY, 7188 7189 generateMipmaps: this.generateMipmaps, 7190 premultiplyAlpha: this.premultiplyAlpha, 7191 unpackAlignment: this.unpackAlignment 7192 7193 }; 7194 7195 if ( Object.keys( this.userData ).length > 0 ) output.userData = this.userData; 7196 7197 if ( ! isRootObject ) { 7198 7199 meta.textures[ this.uuid ] = output; 7200 7201 } 7202 7203 return output; 7204 7205 } 7206 7207 /** 7208 * Frees the GPU-related resources allocated by this instance. Call this 7209 * method whenever this instance is no longer used in your app. 7210 * 7211 * @fires Texture#dispose 7212 */ 7213 dispose() { 7214 7215 /** 7216 * Fires when the texture has been disposed of. 7217 * 7218 * @event Texture#dispose 7219 * @type {Object} 7220 */ 7221 this.dispatchEvent( { type: 'dispose' } ); 7222 7223 } 7224 7225 /** 7226 * Transforms the given uv vector with the textures uv transformation matrix. 7227 * 7228 * @param {Vector2} uv - The uv vector. 7229 * @return {Vector2} The transformed uv vector. 7230 */ 7231 transformUv( uv ) { 7232 7233 if ( this.mapping !== UVMapping ) return uv; 7234 7235 uv.applyMatrix3( this.matrix ); 7236 7237 if ( uv.x < 0 || uv.x > 1 ) { 7238 7239 switch ( this.wrapS ) { 7240 7241 case RepeatWrapping: 7242 7243 uv.x = uv.x - Math.floor( uv.x ); 7244 break; 7245 7246 case ClampToEdgeWrapping: 7247 7248 uv.x = uv.x < 0 ? 0 : 1; 7249 break; 7250 7251 case MirroredRepeatWrapping: 7252 7253 if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { 7254 7255 uv.x = Math.ceil( uv.x ) - uv.x; 7256 7257 } else { 7258 7259 uv.x = uv.x - Math.floor( uv.x ); 7260 7261 } 7262 7263 break; 7264 7265 } 7266 7267 } 7268 7269 if ( uv.y < 0 || uv.y > 1 ) { 7270 7271 switch ( this.wrapT ) { 7272 7273 case RepeatWrapping: 7274 7275 uv.y = uv.y - Math.floor( uv.y ); 7276 break; 7277 7278 case ClampToEdgeWrapping: 7279 7280 uv.y = uv.y < 0 ? 0 : 1; 7281 break; 7282 7283 case MirroredRepeatWrapping: 7284 7285 if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { 7286 7287 uv.y = Math.ceil( uv.y ) - uv.y; 7288 7289 } else { 7290 7291 uv.y = uv.y - Math.floor( uv.y ); 7292 7293 } 7294 7295 break; 7296 7297 } 7298 7299 } 7300 7301 if ( this.flipY ) { 7302 7303 uv.y = 1 - uv.y; 7304 7305 } 7306 7307 return uv; 7308 7309 } 7310 7311 /** 7312 * Setting this property to `true` indicates the engine the texture 7313 * must be updated in the next render. This triggers a texture upload 7314 * to the GPU and ensures correct texture parameter configuration. 7315 * 7316 * @type {boolean} 7317 * @default false 7318 * @param {boolean} value 7319 */ 7320 set needsUpdate( value ) { 7321 7322 if ( value === true ) { 7323 7324 this.version ++; 7325 this.source.needsUpdate = true; 7326 7327 } 7328 7329 } 7330 7331 /** 7332 * Setting this property to `true` indicates the engine the PMREM 7333 * must be regenerated. 7334 * 7335 * @type {boolean} 7336 * @default false 7337 * @param {boolean} value 7338 */ 7339 set needsPMREMUpdate( value ) { 7340 7341 if ( value === true ) { 7342 7343 this.pmremVersion ++; 7344 7345 } 7346 7347 } 7348 7349} 7350 7351/** 7352 * The default image for all textures. 7353 * 7354 * @static 7355 * @type {?Image} 7356 * @default null 7357 */ 7358Texture.DEFAULT_IMAGE = null; 7359 7360/** 7361 * The default mapping for all textures. 7362 * 7363 * @static 7364 * @type {number} 7365 * @default UVMapping 7366 */ 7367Texture.DEFAULT_MAPPING = UVMapping; 7368 7369/** 7370 * The default anisotropy value for all textures. 7371 * 7372 * @static 7373 * @type {number} 7374 * @default 1 7375 */ 7376Texture
vendor: 14,502 bytes, lines 7376-8100
7376.DEFAULT_ANISOTROPY = 1; 7377 7378/** 7379 * Class representing a 4D vector. A 4D vector is an ordered quadruplet of numbers 7380 * (labeled x, y, z and w), which can be used to represent a number of things, such as: 7381 * 7382 * - A point in 4D space. 7383 * - A direction and length in 4D space. In three.js the length will 7384 * always be the Euclidean distance(straight-line distance) from `(0, 0, 0, 0)` to `(x, y, z, w)` 7385 * and the direction is also measured from `(0, 0, 0, 0)` towards `(x, y, z, w)`. 7386 * - Any arbitrary ordered quadruplet of numbers. 7387 * 7388 * There are other things a 4D vector can be used to represent, however these 7389 * are the most common uses in *three.js*. 7390 * 7391 * Iterating through a vector instance will yield its components `(x, y, z, w)` in 7392 * the corresponding order. 7393 * ```js 7394 * const a = new THREE.Vector4( 0, 1, 0, 0 ); 7395 * 7396 * //no arguments; will be initialised to (0, 0, 0, 1) 7397 * const b = new THREE.Vector4( ); 7398 * 7399 * const d = a.dot( b ); 7400 * ``` 7401 */ 7402class Vector4 { 7403 7404 /** 7405 * Constructs a new 4D vector. 7406 * 7407 * @param {number} [x=0] - The x value of this vector. 7408 * @param {number} [y=0] - The y value of this vector. 7409 * @param {number} [z=0] - The z value of this vector. 7410 * @param {number} [w=1] - The w value of this vector. 7411 */ 7412 constructor( x = 0, y = 0, z = 0, w = 1 ) { 7413 7414 /** 7415 * This flag can be used for type testing. 7416 * 7417 * @type {boolean} 7418 * @readonly 7419 * @default true 7420 */ 7421 Vector4.prototype.isVector4 = true; 7422 7423 /** 7424 * The x value of this vector. 7425 * 7426 * @type {number} 7427 */ 7428 this.x = x; 7429 7430 /** 7431 * The y value of this vector. 7432 * 7433 * @type {number} 7434 */ 7435 this.y = y; 7436 7437 /** 7438 * The z value of this vector. 7439 * 7440 * @type {number} 7441 */ 7442 this.z = z; 7443 7444 /** 7445 * The w value of this vector. 7446 * 7447 * @type {number} 7448 */ 7449 this.w = w; 7450 7451 } 7452 7453 /** 7454 * Alias for {@link Vector4#z}. 7455 * 7456 * @type {number} 7457 */ 7458 get width() { 7459 7460 return this.z; 7461 7462 } 7463 7464 set width( value ) { 7465 7466 this.z = value; 7467 7468 } 7469 7470 /** 7471 * Alias for {@link Vector4#w}. 7472 * 7473 * @type {number} 7474 */ 7475 get height() { 7476 7477 return this.w; 7478 7479 } 7480 7481 set height( value ) { 7482 7483 this.w = value; 7484 7485 } 7486 7487 /** 7488 * Sets the vector components. 7489 * 7490 * @param {number} x - The value of the x component. 7491 * @param {number} y - The value of the y component. 7492 * @param {number} z - The value of the z component. 7493 * @param {number} w - The value of the w component. 7494 * @return {Vector4} A reference to this vector. 7495 */ 7496 set( x, y, z, w ) { 7497 7498 this.x = x; 7499 this.y = y; 7500 this.z = z; 7501 this.w = w; 7502 7503 return this; 7504 7505 } 7506 7507 /** 7508 * Sets the vector components to the same value. 7509 * 7510 * @param {number} scalar - The value to set for all vector components. 7511 * @return {Vector4} A reference to this vector. 7512 */ 7513 setScalar( scalar ) { 7514 7515 this.x = scalar; 7516 this.y = scalar; 7517 this.z = scalar; 7518 this.w = scalar; 7519 7520 return this; 7521 7522 } 7523 7524 /** 7525 * Sets the vector's x component to the given value 7526 * 7527 * @param {number} x - The value to set. 7528 * @return {Vector4} A reference to this vector. 7529 */ 7530 setX( x ) { 7531 7532 this.x = x; 7533 7534 return this; 7535 7536 } 7537 7538 /** 7539 * Sets the vector's y component to the given value 7540 * 7541 * @param {number} y - The value to set. 7542 * @return {Vector4} A reference to this vector. 7543 */ 7544 setY( y ) { 7545 7546 this.y = y; 7547 7548 return this; 7549 7550 } 7551 7552 /** 7553 * Sets the vector's z component to the given value 7554 * 7555 * @param {number} z - The value to set. 7556 * @return {Vector4} A reference to this vector. 7557 */ 7558 setZ( z ) { 7559 7560 this.z = z; 7561 7562 return this; 7563 7564 } 7565 7566 /** 7567 * Sets the vector's w component to the given value 7568 * 7569 * @param {number} w - The value to set. 7570 * @return {Vector4} A reference to this vector. 7571 */ 7572 setW( w ) { 7573 7574 this.w = w; 7575 7576 return this; 7577 7578 } 7579 7580 /** 7581 * Allows to set a vector component with an index. 7582 * 7583 * @param {number} index - The component index. `0` equals to x, `1` equals to y, 7584 * `2` equals to z, `3` equals to w. 7585 * @param {number} value - The value to set. 7586 * @return {Vector4} A reference to this vector. 7587 */ 7588 setComponent( index, value ) { 7589 7590 switch ( index ) { 7591 7592 case 0: this.x = value; break; 7593 case 1: this.y = value; break; 7594 case 2: this.z = value; break; 7595 case 3: this.w = value; break; 7596 default: throw new Error( 'index is out of range: ' + index ); 7597 7598 } 7599 7600 return this; 7601 7602 } 7603 7604 /** 7605 * Returns the value of the vector component which matches the given index. 7606 * 7607 * @param {number} index - The component index. `0` equals to x, `1` equals to y, 7608 * `2` equals to z, `3` equals to w. 7609 * @return {number} A vector component value. 7610 */ 7611 getComponent( index ) { 7612 7613 switch ( index ) { 7614 7615 case 0: return this.x; 7616 case 1: return this.y; 7617 case 2: return this.z; 7618 case 3: return this.w; 7619 default: throw new Error( 'index is out of range: ' + index ); 7620 7621 } 7622 7623 } 7624 7625 /** 7626 * Returns a new vector with copied values from this instance. 7627 * 7628 * @return {Vector4} A clone of this instance. 7629 */ 7630 clone() { 7631 7632 return new this.constructor( this.x, this.y, this.z, this.w ); 7633 7634 } 7635 7636 /** 7637 * Copies the values of the given vector to this instance. 7638 * 7639 * @param {Vector3|Vector4} v - The vector to copy. 7640 * @return {Vector4} A reference to this vector. 7641 */ 7642 copy( v ) { 7643 7644 this.x = v.x; 7645 this.y = v.y; 7646 this.z = v.z; 7647 this.w = ( v.w !== undefined ) ? v.w : 1; 7648 7649 return this; 7650 7651 } 7652 7653 /** 7654 * Adds the given vector to this instance. 7655 * 7656 * @param {Vector4} v - The vector to add. 7657 * @return {Vector4} A reference to this vector. 7658 */ 7659 add( v ) { 7660 7661 this.x += v.x; 7662 this.y += v.y; 7663 this.z += v.z; 7664 this.w += v.w; 7665 7666 return this; 7667 7668 } 7669 7670 /** 7671 * Adds the given scalar value to all components of this instance. 7672 * 7673 * @param {number} s - The scalar to add. 7674 * @return {Vector4} A reference to this vector. 7675 */ 7676 addScalar( s ) { 7677 7678 this.x += s; 7679 this.y += s; 7680 this.z += s; 7681 this.w += s; 7682 7683 return this; 7684 7685 } 7686 7687 /** 7688 * Adds the given vectors and stores the result in this instance. 7689 * 7690 * @param {Vector4} a - The first vector. 7691 * @param {Vector4} b - The second vector. 7692 * @return {Vector4} A reference to this vector. 7693 */ 7694 addVectors( a, b ) { 7695 7696 this.x = a.x + b.x; 7697 this.y = a.y + b.y; 7698 this.z = a.z + b.z; 7699 this.w = a.w + b.w; 7700 7701 return this; 7702 7703 } 7704 7705 /** 7706 * Adds the given vector scaled by the given factor to this instance. 7707 * 7708 * @param {Vector4} v - The vector. 7709 * @param {number} s - The factor that scales `v`. 7710 * @return {Vector4} A reference to this vector. 7711 */ 7712 addScaledVector( v, s ) { 7713 7714 this.x += v.x * s; 7715 this.y += v.y * s; 7716 this.z += v.z * s; 7717 this.w += v.w * s; 7718 7719 return this; 7720 7721 } 7722 7723 /** 7724 * Subtracts the given vector from this instance. 7725 * 7726 * @param {Vector4} v - The vector to subtract. 7727 * @return {Vector4} A reference to this vector. 7728 */ 7729 sub( v ) { 7730 7731 this.x -= v.x; 7732 this.y -= v.y; 7733 this.z -= v.z; 7734 this.w -= v.w; 7735 7736 return this; 7737 7738 } 7739 7740 /** 7741 * Subtracts the given scalar value from all components of this instance. 7742 * 7743 * @param {number} s - The scalar to subtract. 7744 * @return {Vector4} A reference to this vector. 7745 */ 7746 subScalar( s ) { 7747 7748 this.x -= s; 7749 this.y -= s; 7750 this.z -= s; 7751 this.w -= s; 7752 7753 return this; 7754 7755 } 7756 7757 /** 7758 * Subtracts the given vectors and stores the result in this instance. 7759 * 7760 * @param {Vector4} a - The first vector. 7761 * @param {Vector4} b - The second vector. 7762 * @return {Vector4} A reference to this vector. 7763 */ 7764 subVectors( a, b ) { 7765 7766 this.x = a.x - b.x; 7767 this.y = a.y - b.y; 7768 this.z = a.z - b.z; 7769 this.w = a.w - b.w; 7770 7771 return this; 7772 7773 } 7774 7775 /** 7776 * Multiplies the given vector with this instance. 7777 * 7778 * @param {Vector4} v - The vector to multiply. 7779 * @return {Vector4} A reference to this vector. 7780 */ 7781 multiply( v ) { 7782 7783 this.x *= v.x; 7784 this.y *= v.y; 7785 this.z *= v.z; 7786 this.w *= v.w; 7787 7788 return this; 7789 7790 } 7791 7792 /** 7793 * Multiplies the given scalar value with all components of this instance. 7794 * 7795 * @param {number} scalar - The scalar to multiply. 7796 * @return {Vector4} A reference to this vector. 7797 */ 7798 multiplyScalar( scalar ) { 7799 7800 this.x *= scalar; 7801 this.y *= scalar; 7802 this.z *= scalar; 7803 this.w *= scalar; 7804 7805 return this; 7806 7807 } 7808 7809 /** 7810 * Multiplies this vector with the given 4x4 matrix. 7811 * 7812 * @param {Matrix4} m - The 4x4 matrix. 7813 * @return {Vector4} A reference to this vector. 7814 */ 7815 applyMatrix4( m ) { 7816 7817 const x = this.x, y = this.y, z = this.z, w = this.w; 7818 const e = m.elements; 7819 7820 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w; 7821 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w; 7822 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w; 7823 this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w; 7824 7825 return this; 7826 7827 } 7828 7829 /** 7830 * Divides this instance by the given vector. 7831 * 7832 * @param {Vector4} v - The vector to divide. 7833 * @return {Vector4} A reference to this vector. 7834 */ 7835 divide( v ) { 7836 7837 this.x /= v.x; 7838 this.y /= v.y; 7839 this.z /= v.z; 7840 this.w /= v.w; 7841 7842 return this; 7843 7844 } 7845 7846 /** 7847 * Divides this vector by the given scalar. 7848 * 7849 * @param {number} scalar - The scalar to divide. 7850 * @return {Vector4} A reference to this vector. 7851 */ 7852 divideScalar( scalar ) { 7853 7854 return this.multiplyScalar( 1 / scalar ); 7855 7856 } 7857 7858 /** 7859 * Sets the x, y and z components of this 7860 * vector to the quaternion's axis and w to the angle. 7861 * 7862 * @param {Quaternion} q - The Quaternion to set. 7863 * @return {Vector4} A reference to this vector. 7864 */ 7865 setAxisAngleFromQuaternion( q ) { 7866 7867 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm 7868 7869 // q is assumed to be normalized 7870 7871 this.w = 2 * Math.acos( q.w ); 7872 7873 const s = Math.sqrt( 1 - q.w * q.w ); 7874 7875 if ( s < 0.0001 ) { 7876 7877 this.x = 1; 7878 this.y = 0; 7879 this.z = 0; 7880 7881 } else { 7882 7883 this.x = q.x / s; 7884 this.y = q.y / s; 7885 this.z = q.z / s; 7886 7887 } 7888 7889 return this; 7890 7891 } 7892 7893 /** 7894 * Sets the x, y and z components of this 7895 * vector to the axis of rotation and w to the angle. 7896 * 7897 * @param {Matrix4} m - A 4x4 matrix of which the upper left 3x3 matrix is a pure rotation matrix. 7898 * @return {Vector4} A reference to this vector. 7899 */ 7900 setAxisAngleFromRotationMatrix( m ) { 7901 7902 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm 7903 7904 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 7905 7906 let angle, x, y, z; // variables for result 7907 const epsilon = 0.01, // margin to allow for rounding errors 7908 epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees 7909 7910 te = m.elements, 7911 7912 m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], 7913 m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], 7914 m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; 7915 7916 if ( ( Math.abs( m12 - m21 ) < epsilon ) && 7917 ( Math.abs( m13 - m31 ) < epsilon ) && 7918 ( Math.abs( m23 - m32 ) < epsilon ) ) { 7919 7920 // singularity found 7921 // first check for identity matrix which must have +1 for all terms 7922 // in leading diagonal and zero in other terms 7923 7924 if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && 7925 ( Math.abs( m13 + m31 ) < epsilon2 ) && 7926 ( Math.abs( m23 + m32 ) < epsilon2 ) && 7927 ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { 7928 7929 // this singularity is identity matrix so angle = 0 7930 7931 this.set( 1, 0, 0, 0 ); 7932 7933 return this; // zero angle, arbitrary axis 7934 7935 } 7936 7937 // otherwise this singularity is angle = 180 7938 7939 angle = Math.PI; 7940 7941 const xx = ( m11 + 1 ) / 2; 7942 const yy = ( m22 + 1 ) / 2; 7943 const zz = ( m33 + 1 ) / 2; 7944 const xy = ( m12 + m21 ) / 4; 7945 const xz = ( m13 + m31 ) / 4; 7946 const yz = ( m23 + m32 ) / 4; 7947 7948 if ( ( xx > yy ) && ( xx > zz ) ) { 7949 7950 // m11 is the largest diagonal term 7951 7952 if ( xx < epsilon ) { 7953 7954 x = 0; 7955 y = 0.707106781; 7956 z = 0.707106781; 7957 7958 } else { 7959 7960 x = Math.sqrt( xx ); 7961 y = xy / x; 7962 z = xz / x; 7963 7964 } 7965 7966 } else if ( yy > zz ) { 7967 7968 // m22 is the largest diagonal term 7969 7970 if ( yy < epsilon ) { 7971 7972 x = 0.707106781; 7973 y = 0; 7974 z = 0.707106781; 7975 7976 } else { 7977 7978 y = Math.sqrt( yy ); 7979 x = xy / y; 7980 z = yz / y; 7981 7982 } 7983 7984 } else { 7985 7986 // m33 is the largest diagonal term so base result on this 7987 7988 if ( zz < epsilon ) { 7989 7990 x = 0.707106781; 7991 y = 0.707106781; 7992 z = 0; 7993 7994 } else { 7995 7996 z = Math.sqrt( zz ); 7997 x = xz / z; 7998 y = yz / z; 7999 8000 } 8001 8002 } 8003 8004 this.set( x, y, z, angle ); 8005 8006 return this; // return 180 deg rotation 8007 8008 } 8009 8010 // as we have reached here there are no singularities so we can handle normally 8011 8012 let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + 8013 ( m13 - m31 ) * ( m13 - m31 ) + 8014 ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize 8015 8016 if ( Math.abs( s ) < 0.001 ) s = 1; 8017 8018 // prevent divide by zero, should not happen if matrix is orthogonal and should be 8019 // caught by singularity test above, but I've left it in just in case 8020 8021 this.x = ( m32 - m23 ) / s; 8022 this.y = ( m13 - m31 ) / s; 8023 this.z = ( m21 - m12 ) / s; 8024 this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); 8025 8026 return this; 8027 8028 } 8029 8030 /** 8031 * Sets the vector components to the position elements of the 8032 * given transformation matrix. 8033 * 8034 * @param {Matrix4} m - The 4x4 matrix. 8035 * @return {Vector4} A reference to this vector. 8036 */ 8037 setFromMatrixPosition( m ) { 8038 8039 const e = m.elements; 8040 8041 this.x = e[ 12 ]; 8042 this.y = e[ 13 ]; 8043 this.z = e[ 14 ]; 8044 this.w = e[ 15 ]; 8045 8046 return this; 8047 8048 } 8049 8050 /** 8051 * If this vector's x, y, z or w value is greater than the given vector's x, y, z or w 8052 * value, replace that value with the corresponding min value. 8053 * 8054 * @param {Vector4} v - The vector. 8055 * @return {Vector4} A reference to this vector. 8056 */ 8057 min( v ) { 8058 8059 this.x = Math.min( this.x, v.x ); 8060 this.y = Math.min( this.y, v.y ); 8061 this.z = Math.min( this.z, v.z ); 8062 this.w = Math.min( this.w, v.w ); 8063 8064 return this; 8065 8066 } 8067 8068 /** 8069 * If this vector's x, y, z or w value is less than the given vector's x, y, z or w 8070 * value, replace that value with the corresponding max value. 8071 * 8072 * @param {Vector4} v - The vector. 8073 * @return {Vector4} A reference to this vector. 8074 */ 8075 max( v ) { 8076 8077 this.x = Math.max( this.x, v.x ); 8078 this.y = Math.max( this.y, v.y ); 8079 this.z = Math.max( this.z, v.z ); 8080 this.w = Math.max( this.w, v.w ); 8081 8082 return this; 8083 8084 } 8085 8086 /** 8087 * If this vector's x, y, z or w value is greater than the max vector's x, y, z or w 8088 * value, it is replaced by the corresponding value. 8089 * If this vector's x, y, z or w value is less than the min vector's x, y, z or w value, 8090 * it is replaced by the corresponding value. 8091 * 8092 * @param {Vector4} min - The minimum x, y and z values. 8093 * @param {Vector4} max - The maximum x, y and z values in the desired range. 8094 * @return {Vector4} A reference to this vector. 8095 */ 8096 clamp( min, max ) { 8097 8098 // assumes min < max, componentwise 8099 8100 this.x = clamp
8100( this.x, min.x, max.x ); 8101 this.y = clamp( this.y, min.y, max.y ); 8102 this.z = clamp( this.z, min.z, max.z ); 8103 this.w = clamp( this.w, min.w, max.w ); 8104 8105 return this; 8106 8107 } 8108
vendor: 8,421 bytes, lines 8109-8443
8109 /** 8110 * If this vector's x, y, z or w values are greater than the max value, they are 8111 * replaced by the max value. 8112 * If this vector's x, y, z or w values are less than the min value, they are 8113 * replaced by the min value. 8114 * 8115 * @param {number} minVal - The minimum value the components will be clamped to. 8116 * @param {number} maxVal - The maximum value the components will be clamped to. 8117 * @return {Vector4} A reference to this vector. 8118 */ 8119 clampScalar( minVal, maxVal ) { 8120 8121 this.x = clamp( this.x, minVal, maxVal ); 8122 this.y = clamp( this.y, minVal, maxVal ); 8123 this.z = clamp( this.z, minVal, maxVal ); 8124 this.w = clamp( this.w, minVal, maxVal ); 8125 8126 return this; 8127 8128 } 8129 8130 /** 8131 * If this vector's length is greater than the max value, it is replaced by 8132 * the max value. 8133 * If this vector's length is less than the min value, it is replaced by the 8134 * min value. 8135 * 8136 * @param {number} min - The minimum value the vector length will be clamped to. 8137 * @param {number} max - The maximum value the vector length will be clamped to. 8138 * @return {Vector4} A reference to this vector. 8139 */ 8140 clampLength( min, max ) { 8141 8142 const length = this.length(); 8143 8144 return this.divideScalar( length || 1 ).multiplyScalar( clamp( length, min, max ) ); 8145 8146 } 8147 8148 /** 8149 * The components of this vector are rounded down to the nearest integer value. 8150 * 8151 * @return {Vector4} A reference to this vector. 8152 */ 8153 floor() { 8154 8155 this.x = Math.floor( this.x ); 8156 this.y = Math.floor( this.y ); 8157 this.z = Math.floor( this.z ); 8158 this.w = Math.floor( this.w ); 8159 8160 return this; 8161 8162 } 8163 8164 /** 8165 * The components of this vector are rounded up to the nearest integer value. 8166 * 8167 * @return {Vector4} A reference to this vector. 8168 */ 8169 ceil() { 8170 8171 this.x = Math.ceil( this.x ); 8172 this.y = Math.ceil( this.y ); 8173 this.z = Math.ceil( this.z ); 8174 this.w = Math.ceil( this.w ); 8175 8176 return this; 8177 8178 } 8179 8180 /** 8181 * The components of this vector are rounded to the nearest integer value 8182 * 8183 * @return {Vector4} A reference to this vector. 8184 */ 8185 round() { 8186 8187 this.x = Math.round( this.x ); 8188 this.y = Math.round( this.y ); 8189 this.z = Math.round( this.z ); 8190 this.w = Math.round( this.w ); 8191 8192 return this; 8193 8194 } 8195 8196 /** 8197 * The components of this vector are rounded towards zero (up if negative, 8198 * down if positive) to an integer value. 8199 * 8200 * @return {Vector4} A reference to this vector. 8201 */ 8202 roundToZero() { 8203 8204 this.x = Math.trunc( this.x ); 8205 this.y = Math.trunc( this.y ); 8206 this.z = Math.trunc( this.z ); 8207 this.w = Math.trunc( this.w ); 8208 8209 return this; 8210 8211 } 8212 8213 /** 8214 * Inverts this vector - i.e. sets x = -x, y = -y, z = -z, w = -w. 8215 * 8216 * @return {Vector4} A reference to this vector. 8217 */ 8218 negate() { 8219 8220 this.x = - this.x; 8221 this.y = - this.y; 8222 this.z = - this.z; 8223 this.w = - this.w; 8224 8225 return this; 8226 8227 } 8228 8229 /** 8230 * Calculates the dot product of the given vector with this instance. 8231 * 8232 * @param {Vector4} v - The vector to compute the dot product with. 8233 * @return {number} The result of the dot product. 8234 */ 8235 dot( v ) { 8236 8237 return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; 8238 8239 } 8240 8241 /** 8242 * Computes the square of the Euclidean length (straight-line length) from 8243 * (0, 0, 0, 0) to (x, y, z, w). If you are comparing the lengths of vectors, you should 8244 * compare the length squared instead as it is slightly more efficient to calculate. 8245 * 8246 * @return {number} The square length of this vector. 8247 */ 8248 lengthSq() { 8249 8250 return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; 8251 8252 } 8253 8254 /** 8255 * Computes the Euclidean length (straight-line length) from (0, 0, 0, 0) to (x, y, z, w). 8256 * 8257 * @return {number} The length of this vector. 8258 */ 8259 length() { 8260 8261 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); 8262 8263 } 8264 8265 /** 8266 * Computes the Manhattan length of this vector. 8267 * 8268 * @return {number} The length of this vector. 8269 */ 8270 manhattanLength() { 8271 8272 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); 8273 8274 } 8275 8276 /** 8277 * Converts this vector to a unit vector - that is, sets it equal to a vector 8278 * with the same direction as this one, but with a vector length of `1`. 8279 * 8280 * @return {Vector4} A reference to this vector. 8281 */ 8282 normalize() { 8283 8284 return this.divideScalar( this.length() || 1 ); 8285 8286 } 8287 8288 /** 8289 * Sets this vector to a vector with the same direction as this one, but 8290 * with the specified length. 8291 * 8292 * @param {number} length - The new length of this vector. 8293 * @return {Vector4} A reference to this vector. 8294 */ 8295 setLength( length ) { 8296 8297 return this.normalize().multiplyScalar( length ); 8298 8299 } 8300 8301 /** 8302 * Linearly interpolates between the given vector and this instance, where 8303 * alpha is the percent distance along the line - alpha = 0 will be this 8304 * vector, and alpha = 1 will be the given one. 8305 * 8306 * @param {Vector4} v - The vector to interpolate towards. 8307 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. 8308 * @return {Vector4} A reference to this vector. 8309 */ 8310 lerp( v, alpha ) { 8311 8312 this.x += ( v.x - this.x ) * alpha; 8313 this.y += ( v.y - this.y ) * alpha; 8314 this.z += ( v.z - this.z ) * alpha; 8315 this.w += ( v.w - this.w ) * alpha; 8316 8317 return this; 8318 8319 } 8320 8321 /** 8322 * Linearly interpolates between the given vectors, where alpha is the percent 8323 * distance along the line - alpha = 0 will be first vector, and alpha = 1 will 8324 * be the second one. The result is stored in this instance. 8325 * 8326 * @param {Vector4} v1 - The first vector. 8327 * @param {Vector4} v2 - The second vector. 8328 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. 8329 * @return {Vector4} A reference to this vector. 8330 */ 8331 lerpVectors( v1, v2, alpha ) { 8332 8333 this.x = v1.x + ( v2.x - v1.x ) * alpha; 8334 this.y = v1.y + ( v2.y - v1.y ) * alpha; 8335 this.z = v1.z + ( v2.z - v1.z ) * alpha; 8336 this.w = v1.w + ( v2.w - v1.w ) * alpha; 8337 8338 return this; 8339 8340 } 8341 8342 /** 8343 * Returns `true` if this vector is equal with the given one. 8344 * 8345 * @param {Vector4} v - The vector to test for equality. 8346 * @return {boolean} Whether this vector is equal with the given one. 8347 */ 8348 equals( v ) { 8349 8350 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); 8351 8352 } 8353 8354 /** 8355 * Sets this vector's x value to be `array[ offset ]`, y value to be `array[ offset + 1 ]`, 8356 * z value to be `array[ offset + 2 ]`, w value to be `array[ offset + 3 ]`. 8357 * 8358 * @param {Array<number>} array - An array holding the vector component values. 8359 * @param {number} [offset=0] - The offset into the array. 8360 * @return {Vector4} A reference to this vector. 8361 */ 8362 fromArray( array, offset = 0 ) { 8363 8364 this.x = array[ offset ]; 8365 this.y = array[ offset + 1 ]; 8366 this.z = array[ offset + 2 ]; 8367 this.w = array[ offset + 3 ]; 8368 8369 return this; 8370 8371 } 8372 8373 /** 8374 * Writes the components of this vector to the given array. If no array is provided, 8375 * the method returns a new instance. 8376 * 8377 * @param {Array<number>} [array=[]] - The target array holding the vector components. 8378 * @param {number} [offset=0] - Index of the first element in the array. 8379 * @return {Array<number>} The vector components. 8380 */ 8381 toArray( array = [], offset = 0 ) { 8382 8383 array[ offset ] = this.x; 8384 array[ offset + 1 ] = this.y; 8385 array[ offset + 2 ] = this.z; 8386 array[ offset + 3 ] = this.w; 8387 8388 return array; 8389 8390 } 8391 8392 /** 8393 * Sets the components of this vector from the given buffer attribute. 8394 * 8395 * @param {BufferAttribute} attribute - The buffer attribute holding vector data. 8396 * @param {number} index - The index into the attribute. 8397 * @return {Vector4} A reference to this vector. 8398 */ 8399 fromBufferAttribute( attribute, index ) { 8400 8401 this.x = attribute.getX( index ); 8402 this.y = attribute.getY( index ); 8403 this.z = attribute.getZ( index ); 8404 this.w = attribute.getW( index ); 8405 8406 return this; 8407 8408 } 8409 8410 /** 8411 * Sets each component of this vector to a pseudo-random value between `0` and 8412 * `1`, excluding `1`. 8413 * 8414 * @return {Vector4} A reference to this vector. 8415 */ 8416 random() { 8417 8418 this.x = Math.random(); 8419 this.y = Math.random(); 8420 this.z = Math.random(); 8421 this.w = Math.random(); 8422 8423 return this; 8424 8425 } 8426 8427 *[ Symbol.iterator ]() { 8428 8429 yield this.x; 8430 yield this.y; 8431 yield this.z; 8432 yield this.w; 8433 8434 } 8435 8436} 8437 8438/** 8439 * Class for representing a Quaternion. Quaternions are used in three.js to represent rotations. 8440 * 8441 * Iterating through a vector instance will yield its components `(x, y, z, w)` in 8442 * the corresponding order. 8443 *
vendor: 17,834 bytes, lines 8444-9225
8444 * Note that three.js expects Quaternions to be normalized. 8445 * ```js 8446 * const quaternion = new THREE.Quaternion(); 8447 * quaternion.setFromAxisAngle( new THREE.Vector3( 0, 1, 0 ), Math.PI / 2 ); 8448 * 8449 * const vector = new THREE.Vector3( 1, 0, 0 ); 8450 * vector.applyQuaternion( quaternion ); 8451 * ``` 8452 */ 8453class Quaternion { 8454 8455 /** 8456 * Constructs a new quaternion. 8457 * 8458 * @param {number} [x=0] - The x value of this quaternion. 8459 * @param {number} [y=0] - The y value of this quaternion. 8460 * @param {number} [z=0] - The z value of this quaternion. 8461 * @param {number} [w=1] - The w value of this quaternion. 8462 */ 8463 constructor( x = 0, y = 0, z = 0, w = 1 ) { 8464 8465 /** 8466 * This flag can be used for type testing. 8467 * 8468 * @type {boolean} 8469 * @readonly 8470 * @default true 8471 */ 8472 this.isQuaternion = true; 8473 8474 this._x = x; 8475 this._y = y; 8476 this._z = z; 8477 this._w = w; 8478 8479 } 8480 8481 /** 8482 * Interpolates between two quaternions via SLERP. This implementation assumes the 8483 * quaternion data are managed in flat arrays. 8484 * 8485 * @param {Array<number>} dst - The destination array. 8486 * @param {number} dstOffset - An offset into the destination array. 8487 * @param {Array<number>} src0 - The source array of the first quaternion. 8488 * @param {number} srcOffset0 - An offset into the first source array. 8489 * @param {Array<number>} src1 - The source array of the second quaternion. 8490 * @param {number} srcOffset1 - An offset into the second source array. 8491 * @param {number} t - The interpolation factor in the range `[0,1]`. 8492 * @see {@link Quaternion#slerp} 8493 */ 8494 static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { 8495 8496 // fuzz-free, array-based Quaternion SLERP operation 8497 8498 let x0 = src0[ srcOffset0 + 0 ], 8499 y0 = src0[ srcOffset0 + 1 ], 8500 z0 = src0[ srcOffset0 + 2 ], 8501 w0 = src0[ srcOffset0 + 3 ]; 8502 8503 const x1 = src1[ srcOffset1 + 0 ], 8504 y1 = src1[ srcOffset1 + 1 ], 8505 z1 = src1[ srcOffset1 + 2 ], 8506 w1 = src1[ srcOffset1 + 3 ]; 8507 8508 if ( t === 0 ) { 8509 8510 dst[ dstOffset + 0 ] = x0; 8511 dst[ dstOffset + 1 ] = y0; 8512 dst[ dstOffset + 2 ] = z0; 8513 dst[ dstOffset + 3 ] = w0; 8514 return; 8515 8516 } 8517 8518 if ( t === 1 ) { 8519 8520 dst[ dstOffset + 0 ] = x1; 8521 dst[ dstOffset + 1 ] = y1; 8522 dst[ dstOffset + 2 ] = z1; 8523 dst[ dstOffset + 3 ] = w1; 8524 return; 8525 8526 } 8527 8528 if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { 8529 8530 let s = 1 - t; 8531 const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, 8532 dir = ( cos >= 0 ? 1 : -1 ), 8533 sqrSin = 1 - cos * cos; 8534 8535 // Skip the Slerp for tiny steps to avoid numeric problems: 8536 if ( sqrSin > Number.EPSILON ) { 8537 8538 const sin = Math.sqrt( sqrSin ), 8539 len = Math.atan2( sin, cos * dir ); 8540 8541 s = Math.sin( s * len ) / sin; 8542 t = Math.sin( t * len ) / sin; 8543 8544 } 8545 8546 const tDir = t * dir; 8547 8548 x0 = x0 * s + x1 * tDir; 8549 y0 = y0 * s + y1 * tDir; 8550 z0 = z0 * s + z1 * tDir; 8551 w0 = w0 * s + w1 * tDir; 8552 8553 // Normalize in case we just did a lerp: 8554 if ( s === 1 - t ) { 8555 8556 const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); 8557 8558 x0 *= f; 8559 y0 *= f; 8560 z0 *= f; 8561 w0 *= f; 8562 8563 } 8564 8565 } 8566 8567 dst[ dstOffset ] = x0; 8568 dst[ dstOffset + 1 ] = y0; 8569 dst[ dstOffset + 2 ] = z0; 8570 dst[ dstOffset + 3 ] = w0; 8571 8572 } 8573 8574 /** 8575 * Multiplies two quaternions. This implementation assumes the quaternion data are managed 8576 * in flat arrays. 8577 * 8578 * @param {Array<number>} dst - The destination array. 8579 * @param {number} dstOffset - An offset into the destination array. 8580 * @param {Array<number>} src0 - The source array of the first quaternion. 8581 * @param {number} srcOffset0 - An offset into the first source array. 8582 * @param {Array<number>} src1 - The source array of the second quaternion. 8583 * @param {number} srcOffset1 - An offset into the second source array. 8584 * @return {Array<number>} The destination array. 8585 * @see {@link Quaternion#multiplyQuaternions}. 8586 */ 8587 static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) { 8588 8589 const x0 = src0[ srcOffset0 ]; 8590 const y0 = src0[ srcOffset0 + 1 ]; 8591 const z0 = src0[ srcOffset0 + 2 ]; 8592 const w0 = src0[ srcOffset0 + 3 ]; 8593 8594 const x1 = src1[ srcOffset1 ]; 8595 const y1 = src1[ srcOffset1 + 1 ]; 8596 const z1 = src1[ srcOffset1 + 2 ]; 8597 const w1 = src1[ srcOffset1 + 3 ]; 8598 8599 dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1; 8600 dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1; 8601 dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1; 8602 dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1; 8603 8604 return dst; 8605 8606 } 8607 8608 /** 8609 * The x value of this quaternion. 8610 * 8611 * @type {number} 8612 * @default 0 8613 */ 8614 get x() { 8615 8616 return this._x; 8617 8618 } 8619 8620 set x( value ) { 8621 8622 this._x = value; 8623 this._onChangeCallback(); 8624 8625 } 8626 8627 /** 8628 * The y value of this quaternion. 8629 * 8630 * @type {number} 8631 * @default 0 8632 */ 8633 get y() { 8634 8635 return this._y; 8636 8637 } 8638 8639 set y( value ) { 8640 8641 this._y = value; 8642 this._onChangeCallback(); 8643 8644 } 8645 8646 /** 8647 * The z value of this quaternion. 8648 * 8649 * @type {number} 8650 * @default 0 8651 */ 8652 get z() { 8653 8654 return this._z; 8655 8656 } 8657 8658 set z( value ) { 8659 8660 this._z = value; 8661 this._onChangeCallback(); 8662 8663 } 8664 8665 /** 8666 * The w value of this quaternion. 8667 * 8668 * @type {number} 8669 * @default 1 8670 */ 8671 get w() { 8672 8673 return this._w; 8674 8675 } 8676 8677 set w( value ) { 8678 8679 this._w = value; 8680 this._onChangeCallback(); 8681 8682 } 8683 8684 /** 8685 * Sets the quaternion components. 8686 * 8687 * @param {number} x - The x value of this quaternion. 8688 * @param {number} y - The y value of this quaternion. 8689 * @param {number} z - The z value of this quaternion. 8690 * @param {number} w - The w value of this quaternion. 8691 * @return {Quaternion} A reference to this quaternion. 8692 */ 8693 set( x, y, z, w ) { 8694 8695 this._x = x; 8696 this._y = y; 8697 this._z = z; 8698 this._w = w; 8699 8700 this._onChangeCallback(); 8701 8702 return this; 8703 8704 } 8705 8706 /** 8707 * Returns a new quaternion with copied values from this instance. 8708 * 8709 * @return {Quaternion} A clone of this instance. 8710 */ 8711 clone() { 8712 8713 return new this.constructor( this._x, this._y, this._z, this._w ); 8714 8715 } 8716 8717 /** 8718 * Copies the values of the given quaternion to this instance. 8719 * 8720 * @param {Quaternion} quaternion - The quaternion to copy. 8721 * @return {Quaternion} A reference to this quaternion. 8722 */ 8723 copy( quaternion ) { 8724 8725 this._x = quaternion.x; 8726 this._y = quaternion.y; 8727 this._z = quaternion.z; 8728 this._w = quaternion.w; 8729 8730 this._onChangeCallback(); 8731 8732 return this; 8733 8734 } 8735 8736 /** 8737 * Sets this quaternion from the rotation specified by the given 8738 * Euler angles. 8739 * 8740 * @param {Euler} euler - The Euler angles. 8741 * @param {boolean} [update=true] - Whether the internal `onChange` callback should be executed or not. 8742 * @return {Quaternion} A reference to this quaternion. 8743 */ 8744 setFromEuler( euler, update = true ) { 8745 8746 const x = euler._x, y = euler._y, z = euler._z, order = euler._order; 8747 8748 // http://www.mathworks.com/matlabcentral/fileexchange/ 8749 // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ 8750 // content/SpinCalc.m 8751 8752 const cos = Math.cos; 8753 const sin = Math.sin; 8754 8755 const c1 = cos( x / 2 ); 8756 const c2 = cos( y / 2 ); 8757 const c3 = cos( z / 2 ); 8758 8759 const s1 = sin( x / 2 ); 8760 const s2 = sin( y / 2 ); 8761 const s3 = sin( z / 2 ); 8762 8763 switch ( order ) { 8764 8765 case 'XYZ': 8766 this._x = s1 * c2 * c3 + c1 * s2 * s3; 8767 this._y = c1 * s2 * c3 - s1 * c2 * s3; 8768 this._z = c1 * c2 * s3 + s1 * s2 * c3; 8769 this._w = c1 * c2 * c3 - s1 * s2 * s3; 8770 break; 8771 8772 case 'YXZ': 8773 this._x = s1 * c2 * c3 + c1 * s2 * s3; 8774 this._y = c1 * s2 * c3 - s1 * c2 * s3; 8775 this._z = c1 * c2 * s3 - s1 * s2 * c3; 8776 this._w = c1 * c2 * c3 + s1 * s2 * s3; 8777 break; 8778 8779 case 'ZXY': 8780 this._x = s1 * c2 * c3 - c1 * s2 * s3; 8781 this._y = c1 * s2 * c3 + s1 * c2 * s3; 8782 this._z = c1 * c2 * s3 + s1 * s2 * c3; 8783 this._w = c1 * c2 * c3 - s1 * s2 * s3; 8784 break; 8785 8786 case 'ZYX': 8787 this._x = s1 * c2 * c3 - c1 * s2 * s3; 8788 this._y = c1 * s2 * c3 + s1 * c2 * s3; 8789 this._z = c1 * c2 * s3 - s1 * s2 * c3; 8790 this._w = c1 * c2 * c3 + s1 * s2 * s3; 8791 break; 8792 8793 case 'YZX': 8794 this._x = s1 * c2 * c3 + c1 * s2 * s3; 8795 this._y = c1 * s2 * c3 + s1 * c2 * s3; 8796 this._z = c1 * c2 * s3 - s1 * s2 * c3; 8797 this._w = c1 * c2 * c3 - s1 * s2 * s3; 8798 break; 8799 8800 case 'XZY': 8801 this._x = s1 * c2 * c3 - c1 * s2 * s3; 8802 this._y = c1 * s2 * c3 - s1 * c2 * s3; 8803 this._z = c1 * c2 * s3 + s1 * s2 * c3; 8804 this._w = c1 * c2 * c3 + s1 * s2 * s3; 8805 break; 8806 8807 default: 8808 console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order ); 8809 8810 } 8811 8812 if ( update === true ) this._onChangeCallback(); 8813 8814 return this; 8815 8816 } 8817 8818 /** 8819 * Sets this quaternion from the given axis and angle. 8820 * 8821 * @param {Vector3} axis - The normalized axis. 8822 * @param {number} angle - The angle in radians. 8823 * @return {Quaternion} A reference to this quaternion. 8824 */ 8825 setFromAxisAngle( axis, angle ) { 8826 8827 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm 8828 8829 const halfAngle = angle / 2, s = Math.sin( halfAngle ); 8830 8831 this._x = axis.x * s; 8832 this._y = axis.y * s; 8833 this._z = axis.z * s; 8834 this._w = Math.cos( halfAngle ); 8835 8836 this._onChangeCallback(); 8837 8838 return this; 8839 8840 } 8841 8842 /** 8843 * Sets this quaternion from the given rotation matrix. 8844 * 8845 * @param {Matrix4} m - A 4x4 matrix of which the upper 3x3 of matrix is a pure rotation matrix (i.e. unscaled). 8846 * @return {Quaternion} A reference to this quaternion. 8847 */ 8848 setFromRotationMatrix( m ) { 8849 8850 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm 8851 8852 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 8853 8854 const te = m.elements, 8855 8856 m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], 8857 m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], 8858 m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], 8859 8860 trace = m11 + m22 + m33; 8861 8862 if ( trace > 0 ) { 8863 8864 const s = 0.5 / Math.sqrt( trace + 1.0 ); 8865 8866 this._w = 0.25 / s; 8867 this._x = ( m32 - m23 ) * s; 8868 this._y = ( m13 - m31 ) * s; 8869 this._z = ( m21 - m12 ) * s; 8870 8871 } else if ( m11 > m22 && m11 > m33 ) { 8872 8873 const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); 8874 8875 this._w = ( m32 - m23 ) / s; 8876 this._x = 0.25 * s; 8877 this._y = ( m12 + m21 ) / s; 8878 this._z = ( m13 + m31 ) / s; 8879 8880 } else if ( m22 > m33 ) { 8881 8882 const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); 8883 8884 this._w = ( m13 - m31 ) / s; 8885 this._x = ( m12 + m21 ) / s; 8886 this._y = 0.25 * s; 8887 this._z = ( m23 + m32 ) / s; 8888 8889 } else { 8890 8891 const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); 8892 8893 this._w = ( m21 - m12 ) / s; 8894 this._x = ( m13 + m31 ) / s; 8895 this._y = ( m23 + m32 ) / s; 8896 this._z = 0.25 * s; 8897 8898 } 8899 8900 this._onChangeCallback(); 8901 8902 return this; 8903 8904 } 8905 8906 /** 8907 * Sets this quaternion to the rotation required to rotate the direction vector 8908 * `vFrom` to the direction vector `vTo`. 8909 * 8910 * @param {Vector3} vFrom - The first (normalized) direction vector. 8911 * @param {Vector3} vTo - The second (normalized) direction vector. 8912 * @return {Quaternion} A reference to this quaternion. 8913 */ 8914 setFromUnitVectors( vFrom, vTo ) { 8915 8916 // assumes direction vectors vFrom and vTo are normalized 8917 8918 let r = vFrom.dot( vTo ) + 1; 8919 8920 if ( r < Number.EPSILON ) { 8921 8922 // vFrom and vTo point in opposite directions 8923 8924 r = 0; 8925 8926 if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { 8927 8928 this._x = - vFrom.y; 8929 this._y = vFrom.x; 8930 this._z = 0; 8931 this._w = r; 8932 8933 } else { 8934 8935 this._x = 0; 8936 this._y = - vFrom.z; 8937 this._z = vFrom.y; 8938 this._w = r; 8939 8940 } 8941 8942 } else { 8943 8944 // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3 8945 8946 this._x = vFrom.y * vTo.z - vFrom.z * vTo.y; 8947 this._y = vFrom.z * vTo.x - vFrom.x * vTo.z; 8948 this._z = vFrom.x * vTo.y - vFrom.y * vTo.x; 8949 this._w = r; 8950 8951 } 8952 8953 return this.normalize(); 8954 8955 } 8956 8957 /** 8958 * Returns the angle between this quaternion and the given one in radians. 8959 * 8960 * @param {Quaternion} q - The quaternion to compute the angle with. 8961 * @return {number} The angle in radians. 8962 */ 8963 angleTo( q ) { 8964 8965 return 2 * Math.acos( Math.abs( clamp( this.dot( q ), -1, 1 ) ) ); 8966 8967 } 8968 8969 /** 8970 * Rotates this quaternion by a given angular step to the given quaternion. 8971 * The method ensures that the final quaternion will not overshoot `q`. 8972 * 8973 * @param {Quaternion} q - The target quaternion. 8974 * @param {number} step - The angular step in radians. 8975 * @return {Quaternion} A reference to this quaternion. 8976 */ 8977 rotateTowards( q, step ) { 8978 8979 const angle = this.angleTo( q ); 8980 8981 if ( angle === 0 ) return this; 8982 8983 const t = Math.min( 1, step / angle ); 8984 8985 this.slerp( q, t ); 8986 8987 return this; 8988 8989 } 8990 8991 /** 8992 * Sets this quaternion to the identity quaternion; that is, to the 8993 * quaternion that represents "no rotation". 8994 * 8995 * @return {Quaternion} A reference to this quaternion. 8996 */ 8997 identity() { 8998 8999 return this.set( 0, 0, 0, 1 ); 9000 9001 } 9002 9003 /** 9004 * Inverts this quaternion via {@link Quaternion#conjugate}. The 9005 * quaternion is assumed to have unit length. 9006 * 9007 * @return {Quaternion} A reference to this quaternion. 9008 */ 9009 invert() { 9010 9011 return this.conjugate(); 9012 9013 } 9014 9015 /** 9016 * Returns the rotational conjugate of this quaternion. The conjugate of a 9017 * quaternion represents the same rotation in the opposite direction about 9018 * the rotational axis. 9019 * 9020 * @return {Quaternion} A reference to this quaternion. 9021 */ 9022 conjugate() { 9023 9024 this._x *= -1; 9025 this._y *= -1; 9026 this._z *= -1; 9027 9028 this._onChangeCallback(); 9029 9030 return this; 9031 9032 } 9033 9034 /** 9035 * Calculates the dot product of this quaternion and the given one. 9036 * 9037 * @param {Quaternion} v - The quaternion to compute the dot product with. 9038 * @return {number} The result of the dot product. 9039 */ 9040 dot( v ) { 9041 9042 return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; 9043 9044 } 9045 9046 /** 9047 * Computes the squared Euclidean length (straight-line length) of this quaternion, 9048 * considered as a 4 dimensional vector. This can be useful if you are comparing the 9049 * lengths of two quaternions, as this is a slightly more efficient calculation than 9050 * {@link Quaternion#length}. 9051 * 9052 * @return {number} The squared Euclidean length. 9053 */ 9054 lengthSq() { 9055 9056 return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; 9057 9058 } 9059 9060 /** 9061 * Computes the Euclidean length (straight-line length) of this quaternion, 9062 * considered as a 4 dimensional vector. 9063 * 9064 * @return {number} The Euclidean length. 9065 */ 9066 length() { 9067 9068 return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); 9069 9070 } 9071 9072 /** 9073 * Normalizes this quaternion - that is, calculated the quaternion that performs 9074 * the same rotation as this one, but has a length equal to `1`. 9075 * 9076 * @return {Quaternion} A reference to this quaternion. 9077 */ 9078 normalize() { 9079 9080 let l = this.length(); 9081 9082 if ( l === 0 ) { 9083 9084 this._x = 0; 9085 this._y = 0; 9086 this._z = 0; 9087 this._w = 1; 9088 9089 } else { 9090 9091 l = 1 / l; 9092 9093 this._x = this._x * l; 9094 this._y = this._y * l; 9095 this._z = this._z * l; 9096 this._w = this._w * l; 9097 9098 } 9099 9100 this._onChangeCallback(); 9101 9102 return this; 9103 9104 } 9105 9106 /** 9107 * Multiplies this quaternion by the given one. 9108 * 9109 * @param {Quaternion} q - The quaternion. 9110 * @return {Quaternion} A reference to this quaternion. 9111 */ 9112 multiply( q ) { 9113 9114 return this.multiplyQuaternions( this, q ); 9115 9116 } 9117 9118 /** 9119 * Pre-multiplies this quaternion by the given one. 9120 * 9121 * @param {Quaternion} q - The quaternion. 9122 * @return {Quaternion} A reference to this quaternion. 9123 */ 9124 premultiply( q ) { 9125 9126 return this.multiplyQuaternions( q, this ); 9127 9128 } 9129 9130 /** 9131 * Multiplies the given quaternions and stores the result in this instance. 9132 * 9133 * @param {Quaternion} a - The first quaternion. 9134 * @param {Quaternion} b - The second quaternion. 9135 * @return {Quaternion} A reference to this quaternion. 9136 */ 9137 multiplyQuaternions( a, b ) { 9138 9139 // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm 9140 9141 const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; 9142 const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; 9143 9144 this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; 9145 this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; 9146 this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; 9147 this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; 9148 9149 this._onChangeCallback(); 9150 9151 return this; 9152 9153 } 9154 9155 /** 9156 * Performs a spherical linear interpolation between quaternions. 9157 * 9158 * @param {Quaternion} qb - The target quaternion. 9159 * @param {number} t - The interpolation factor in the closed interval `[0, 1]`. 9160 * @return {Quaternion} A reference to this quaternion. 9161 */ 9162 slerp( qb, t ) { 9163 9164 if ( t === 0 ) return this; 9165 if ( t === 1 ) return this.copy( qb ); 9166 9167 const x = this._x, y = this._y, z = this._z, w = this._w; 9168 9169 // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ 9170 9171 let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; 9172 9173 if ( cosHalfTheta < 0 ) { 9174 9175 this._w = - qb._w; 9176 this._x = - qb._x; 9177 this._y = - qb._y; 9178 this._z = - qb._z; 9179 9180 cosHalfTheta = - cosHalfTheta; 9181 9182 } else { 9183 9184 this.copy( qb ); 9185 9186 } 9187 9188 if ( cosHalfTheta >= 1.0 ) { 9189 9190 this._w = w; 9191 this._x = x; 9192 this._y = y; 9193 this._z = z; 9194 9195 return this; 9196 9197 } 9198 9199 const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; 9200 9201 if ( sqrSinHalfTheta <= Number.EPSILON ) { 9202 9203 const s = 1 - t; 9204 this._w = s * w + t * this._w; 9205 this._x = s * x + t * this._x; 9206 this._y = s * y + t * this._y; 9207 this._z = s * z + t * this._z; 9208 9209 this.normalize(); // normalize calls _onChangeCallback() 9210 9211 return this; 9212 9213 } 9214 9215 const sinHalfTheta = Math.sqrt( sqrSinHalfTheta ); 9216 const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); 9217 const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, 9218 ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; 9219 9220 this._w = ( w * ratioA + this._w * ratioB ); 9221 this._x = ( x * ratioA + this._x * ratioB ); 9222 this._y = ( y * ratioA + this._y * ratioB ); 9223 this._z = ( z * ratioA + this._z * ratioB ); 9224 9225 this._onChangeCallback();
vendor: 4,515 bytes, lines 9225-9404
9225 9226 9227 return this; 9228 9229 } 9230 9231 /** 9232 * Performs a spherical linear interpolation between the given quaternions 9233 * and stores the result in this quaternion. 9234 * 9235 * @param {Quaternion} qa - The source quaternion. 9236 * @param {Quaternion} qb - The target quaternion. 9237 * @param {number} t - The interpolation factor in the closed interval `[0, 1]`. 9238 * @return {Quaternion} A reference to this quaternion. 9239 */ 9240 slerpQuaternions( qa, qb, t ) { 9241 9242 return this.copy( qa ).slerp( qb, t ); 9243 9244 } 9245 9246 /** 9247 * Sets this quaternion to a uniformly random, normalized quaternion. 9248 * 9249 * @return {Quaternion} A reference to this quaternion. 9250 */ 9251 random() { 9252 9253 // Ken Shoemake 9254 // Uniform random rotations 9255 // D. Kirk, editor, Graphics Gems III, pages 124-132. Academic Press, New York, 1992. 9256 9257 const theta1 = 2 * Math.PI * Math.random(); 9258 const theta2 = 2 * Math.PI * Math.random(); 9259 9260 const x0 = Math.random(); 9261 const r1 = Math.sqrt( 1 - x0 ); 9262 const r2 = Math.sqrt( x0 ); 9263 9264 return this.set( 9265 r1 * Math.sin( theta1 ), 9266 r1 * Math.cos( theta1 ), 9267 r2 * Math.sin( theta2 ), 9268 r2 * Math.cos( theta2 ), 9269 ); 9270 9271 } 9272 9273 /** 9274 * Returns `true` if this quaternion is equal with the given one. 9275 * 9276 * @param {Quaternion} quaternion - The quaternion to test for equality. 9277 * @return {boolean} Whether this quaternion is equal with the given one. 9278 */ 9279 equals( quaternion ) { 9280 9281 return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); 9282 9283 } 9284 9285 /** 9286 * Sets this quaternion's components from the given array. 9287 * 9288 * @param {Array<number>} array - An array holding the quaternion component values. 9289 * @param {number} [offset=0] - The offset into the array. 9290 * @return {Quaternion} A reference to this quaternion. 9291 */ 9292 fromArray( array, offset = 0 ) { 9293 9294 this._x = array[ offset ]; 9295 this._y = array[ offset + 1 ]; 9296 this._z = array[ offset + 2 ]; 9297 this._w = array[ offset + 3 ]; 9298 9299 this._onChangeCallback(); 9300 9301 return this; 9302 9303 } 9304 9305 /** 9306 * Writes the components of this quaternion to the given array. If no array is provided, 9307 * the method returns a new instance. 9308 * 9309 * @param {Array<number>} [array=[]] - The target array holding the quaternion components. 9310 * @param {number} [offset=0] - Index of the first element in the array. 9311 * @return {Array<number>} The quaternion components. 9312 */ 9313 toArray( array = [], offset = 0 ) { 9314 9315 array[ offset ] = this._x; 9316 array[ offset + 1 ] = this._y; 9317 array[ offset + 2 ] = this._z; 9318 array[ offset + 3 ] = this._w; 9319 9320 return array; 9321 9322 } 9323 9324 /** 9325 * Sets the components of this quaternion from the given buffer attribute. 9326 * 9327 * @param {BufferAttribute} attribute - The buffer attribute holding quaternion data. 9328 * @param {number} index - The index into the attribute. 9329 * @return {Quaternion} A reference to this quaternion. 9330 */ 9331 fromBufferAttribute( attribute, index ) { 9332 9333 this._x = attribute.getX( index ); 9334 this._y = attribute.getY( index ); 9335 this._z = attribute.getZ( index ); 9336 this._w = attribute.getW( index ); 9337 9338 this._onChangeCallback(); 9339 9340 return this; 9341 9342 } 9343 9344 /** 9345 * This methods defines the serialization result of this class. Returns the 9346 * numerical elements of this quaternion in an array of format `[x, y, z, w]`. 9347 * 9348 * @return {Array<number>} The serialized quaternion. 9349 */ 9350 toJSON() { 9351 9352 return this.toArray(); 9353 9354 } 9355 9356 _onChange( callback ) { 9357 9358 this._onChangeCallback = callback; 9359 9360 return this; 9361 9362 } 9363 9364 _onChangeCallback() {} 9365 9366 *[ Symbol.iterator ]() { 9367 9368 yield this._x; 9369 yield this._y; 9370 yield this._z; 9371 yield this._w; 9372 9373 } 9374 9375} 9376 9377/** 9378 * Class representing a 3D vector. A 3D vector is an ordered triplet of numbers 9379 * (labeled x, y and z), which can be used to represent a number of things, such as: 9380 * 9381 * - A point in 3D space. 9382 * - A direction and length in 3D space. In three.js the length will 9383 * always be the Euclidean distance(straight-line distance) from `(0, 0, 0)` to `(x, y, z)` 9384 * and the direction is also measured from `(0, 0, 0)` towards `(x, y, z)`. 9385 * - Any arbitrary ordered triplet of numbers. 9386 * 9387 * There are other things a 3D vector can be used to represent, such as 9388 * momentum vectors and so on, however these are the most 9389 * common uses in three.js. 9390 * 9391 * Iterating through a vector instance will yield its components `(x, y, z)` in 9392 * the corresponding order. 9393 * ```js 9394 * const a = new THREE.Vector3( 0, 1, 0 ); 9395 * 9396 * //no arguments; will be initialised to (0, 0, 0) 9397 * const b = new THREE.Vector3( ); 9398 * 9399 * const d = a.distanceTo( b ); 9400 * ``` 9401 */ 9402class Vector3 { 9403 9404
vendor: 3,883 bytes, lines 9404-9622
9404/** 9405 * Constructs a new 3D vector. 9406 * 9407 * @param {number} [x=0] - The x value of this vector. 9408 * @param {number} [y=0] - The y value of this vector. 9409 * @param {number} [z=0] - The z value of this vector. 9410 */ 9411 constructor( x = 0, y = 0, z = 0 ) { 9412 9413 /** 9414 * This flag can be used for type testing. 9415 * 9416 * @type {boolean} 9417 * @readonly 9418 * @default true 9419 */ 9420 Vector3.prototype.isVector3 = true; 9421 9422 /** 9423 * The x value of this vector. 9424 * 9425 * @type {number} 9426 */ 9427 this.x = x; 9428 9429 /** 9430 * The y value of this vector. 9431 * 9432 * @type {number} 9433 */ 9434 this.y = y; 9435 9436 /** 9437 * The z value of this vector. 9438 * 9439 * @type {number} 9440 */ 9441 this.z = z; 9442 9443 } 9444 9445 /** 9446 * Sets the vector components. 9447 * 9448 * @param {number} x - The value of the x component. 9449 * @param {number} y - The value of the y component. 9450 * @param {number} z - The value of the z component. 9451 * @return {Vector3} A reference to this vector. 9452 */ 9453 set( x, y, z ) { 9454 9455 if ( z === undefined ) z = this.z; // sprite.scale.set(x,y) 9456 9457 this.x = x; 9458 this.y = y; 9459 this.z = z; 9460 9461 return this; 9462 9463 } 9464 9465 /** 9466 * Sets the vector components to the same value. 9467 * 9468 * @param {number} scalar - The value to set for all vector components. 9469 * @return {Vector3} A reference to this vector. 9470 */ 9471 setScalar( scalar ) { 9472 9473 this.x = scalar; 9474 this.y = scalar; 9475 this.z = scalar; 9476 9477 return this; 9478 9479 } 9480 9481 /** 9482 * Sets the vector's x component to the given value 9483 * 9484 * @param {number} x - The value to set. 9485 * @return {Vector3} A reference to this vector. 9486 */ 9487 setX( x ) { 9488 9489 this.x = x; 9490 9491 return this; 9492 9493 } 9494 9495 /** 9496 * Sets the vector's y component to the given value 9497 * 9498 * @param {number} y - The value to set. 9499 * @return {Vector3} A reference to this vector. 9500 */ 9501 setY( y ) { 9502 9503 this.y = y; 9504 9505 return this; 9506 9507 } 9508 9509 /** 9510 * Sets the vector's z component to the given value 9511 * 9512 * @param {number} z - The value to set. 9513 * @return {Vector3} A reference to this vector. 9514 */ 9515 setZ( z ) { 9516 9517 this.z = z; 9518 9519 return this; 9520 9521 } 9522 9523 /** 9524 * Allows to set a vector component with an index. 9525 * 9526 * @param {number} index - The component index. `0` equals to x, `1` equals to y, `2` equals to z. 9527 * @param {number} value - The value to set. 9528 * @return {Vector3} A reference to this vector. 9529 */ 9530 setComponent( index, value ) { 9531 9532 switch ( index ) { 9533 9534 case 0: this.x = value; break; 9535 case 1: this.y = value; break; 9536 case 2: this.z = value; break; 9537 default: throw new Error( 'index is out of range: ' + index ); 9538 9539 } 9540 9541 return this; 9542 9543 } 9544 9545 /** 9546 * Returns the value of the vector component which matches the given index. 9547 * 9548 * @param {number} index - The component index. `0` equals to x, `1` equals to y, `2` equals to z. 9549 * @return {number} A vector component value. 9550 */ 9551 getComponent( index ) { 9552 9553 switch ( index ) { 9554 9555 case 0: return this.x; 9556 case 1: return this.y; 9557 case 2: return this.z; 9558 default: throw new Error( 'index is out of range: ' + index ); 9559 9560 } 9561 9562 } 9563 9564 /** 9565 * Returns a new vector with copied values from this instance. 9566 * 9567 * @return {Vector3} A clone of this instance. 9568 */ 9569 clone() { 9570 9571 return new this.constructor( this.x, this.y, this.z ); 9572 9573 } 9574 9575 /** 9576 * Copies the values of the given vector to this instance. 9577 * 9578 * @param {Vector3} v - The vector to copy. 9579 * @return {Vector3} A reference to this vector. 9580 */ 9581 copy( v ) { 9582 9583 this.x = v.x; 9584 this.y = v.y; 9585 this.z = v.z; 9586 9587 return this; 9588 9589 } 9590 9591 /** 9592 * Adds the given vector to this instance. 9593 * 9594 * @param {Vector3} v - The vector to add. 9595 * @return {Vector3} A reference to this vector. 9596 */ 9597 add( v ) { 9598 9599 this.x += v.x; 9600 this.y += v.y; 9601 this.z += v.z; 9602 9603 return this; 9604 9605 } 9606 9607 /** 9608 * Adds the given scalar value to all components of this instance. 9609 * 9610 * @param {number} s - The scalar to add. 9611 * @return {Vector3} A reference to this vector. 9612 */ 9613 addScalar( s ) { 9614 9615 this.x += s; 9616 this.y += s; 9617 this.z += s; 9618 9619 return this; 9620 9621 } 9622
vendor: 11,109 bytes, lines 9623-10120
9623 /** 9624 * Adds the given vectors and stores the result in this instance. 9625 * 9626 * @param {Vector3} a - The first vector. 9627 * @param {Vector3} b - The second vector. 9628 * @return {Vector3} A reference to this vector. 9629 */ 9630 addVectors( a, b ) { 9631 9632 this.x = a.x + b.x; 9633 this.y = a.y + b.y; 9634 this.z = a.z + b.z; 9635 9636 return this; 9637 9638 } 9639 9640 /** 9641 * Adds the given vector scaled by the given factor to this instance. 9642 * 9643 * @param {Vector3|Vector4} v - The vector. 9644 * @param {number} s - The factor that scales `v`. 9645 * @return {Vector3} A reference to this vector. 9646 */ 9647 addScaledVector( v, s ) { 9648 9649 this.x += v.x * s; 9650 this.y += v.y * s; 9651 this.z += v.z * s; 9652 9653 return this; 9654 9655 } 9656 9657 /** 9658 * Subtracts the given vector from this instance. 9659 * 9660 * @param {Vector3} v - The vector to subtract. 9661 * @return {Vector3} A reference to this vector. 9662 */ 9663 sub( v ) { 9664 9665 this.x -= v.x; 9666 this.y -= v.y; 9667 this.z -= v.z; 9668 9669 return this; 9670 9671 } 9672 9673 /** 9674 * Subtracts the given scalar value from all components of this instance. 9675 * 9676 * @param {number} s - The scalar to subtract. 9677 * @return {Vector3} A reference to this vector. 9678 */ 9679 subScalar( s ) { 9680 9681 this.x -= s; 9682 this.y -= s; 9683 this.z -= s; 9684 9685 return this; 9686 9687 } 9688 9689 /** 9690 * Subtracts the given vectors and stores the result in this instance. 9691 * 9692 * @param {Vector3} a - The first vector. 9693 * @param {Vector3} b - The second vector. 9694 * @return {Vector3} A reference to this vector. 9695 */ 9696 subVectors( a, b ) { 9697 9698 this.x = a.x - b.x; 9699 this.y = a.y - b.y; 9700 this.z = a.z - b.z; 9701 9702 return this; 9703 9704 } 9705 9706 /** 9707 * Multiplies the given vector with this instance. 9708 * 9709 * @param {Vector3} v - The vector to multiply. 9710 * @return {Vector3} A reference to this vector. 9711 */ 9712 multiply( v ) { 9713 9714 this.x *= v.x; 9715 this.y *= v.y; 9716 this.z *= v.z; 9717 9718 return this; 9719 9720 } 9721 9722 /** 9723 * Multiplies the given scalar value with all components of this instance. 9724 * 9725 * @param {number} scalar - The scalar to multiply. 9726 * @return {Vector3} A reference to this vector. 9727 */ 9728 multiplyScalar( scalar ) { 9729 9730 this.x *= scalar; 9731 this.y *= scalar; 9732 this.z *= scalar; 9733 9734 return this; 9735 9736 } 9737 9738 /** 9739 * Multiplies the given vectors and stores the result in this instance. 9740 * 9741 * @param {Vector3} a - The first vector. 9742 * @param {Vector3} b - The second vector. 9743 * @return {Vector3} A reference to this vector. 9744 */ 9745 multiplyVectors( a, b ) { 9746 9747 this.x = a.x * b.x; 9748 this.y = a.y * b.y; 9749 this.z = a.z * b.z; 9750 9751 return this; 9752 9753 } 9754 9755 /** 9756 * Applies the given Euler rotation to this vector. 9757 * 9758 * @param {Euler} euler - The Euler angles. 9759 * @return {Vector3} A reference to this vector. 9760 */ 9761 applyEuler( euler ) { 9762 9763 return this.applyQuaternion( _quaternion$4.setFromEuler( euler ) ); 9764 9765 } 9766 9767 /** 9768 * Applies a rotation specified by an axis and an angle to this vector. 9769 * 9770 * @param {Vector3} axis - A normalized vector representing the rotation axis. 9771 * @param {number} angle - The angle in radians. 9772 * @return {Vector3} A reference to this vector. 9773 */ 9774 applyAxisAngle( axis, angle ) { 9775 9776 return this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) ); 9777 9778 } 9779 9780 /** 9781 * Multiplies this vector with the given 3x3 matrix. 9782 * 9783 * @param {Matrix3} m - The 3x3 matrix. 9784 * @return {Vector3} A reference to this vector. 9785 */ 9786 applyMatrix3( m ) { 9787 9788 const x = this.x, y = this.y, z = this.z; 9789 const e = m.elements; 9790 9791 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z; 9792 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z; 9793 this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z; 9794 9795 return this; 9796 9797 } 9798 9799 /** 9800 * Multiplies this vector by the given normal matrix and normalizes 9801 * the result. 9802 * 9803 * @param {Matrix3} m - The normal matrix. 9804 * @return {Vector3} A reference to this vector. 9805 */ 9806 applyNormalMatrix( m ) { 9807 9808 return this.applyMatrix3( m ).normalize(); 9809 9810 } 9811 9812 /** 9813 * Multiplies this vector (with an implicit 1 in the 4th dimension) by m, and 9814 * divides by perspective. 9815 * 9816 * @param {Matrix4} m - The matrix to apply. 9817 * @return {Vector3} A reference to this vector. 9818 */ 9819 applyMatrix4( m ) { 9820 9821 const x = this.x, y = this.y, z = this.z; 9822 const e = m.elements; 9823 9824 const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); 9825 9826 this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w; 9827 this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w; 9828 this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w; 9829 9830 return this; 9831 9832 } 9833 9834 /** 9835 * Applies the given Quaternion to this vector. 9836 * 9837 * @param {Quaternion} q - The Quaternion. 9838 * @return {Vector3} A reference to this vector. 9839 */ 9840 applyQuaternion( q ) { 9841 9842 // quaternion q is assumed to have unit length 9843 9844 const vx = this.x, vy = this.y, vz = this.z; 9845 const qx = q.x, qy = q.y, qz = q.z, qw = q.w; 9846 9847 // t = 2 * cross( q.xyz, v ); 9848 const tx = 2 * ( qy * vz - qz * vy ); 9849 const ty = 2 * ( qz * vx - qx * vz ); 9850 const tz = 2 * ( qx * vy - qy * vx ); 9851 9852 // v + q.w * t + cross( q.xyz, t ); 9853 this.x = vx + qw * tx + qy * tz - qz * ty; 9854 this.y = vy + qw * ty + qz * tx - qx * tz; 9855 this.z = vz + qw * tz + qx * ty - qy * tx; 9856 9857 return this; 9858 9859 } 9860 9861 /** 9862 * Projects this vector from world space into the camera's normalized 9863 * device coordinate (NDC) space. 9864 * 9865 * @param {Camera} camera - The camera. 9866 * @return {Vector3} A reference to this vector. 9867 */ 9868 project( camera ) { 9869 9870 return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix ); 9871 9872 } 9873 9874 /** 9875 * Unprojects this vector from the camera's normalized device coordinate (NDC) 9876 * space into world space. 9877 * 9878 * @param {Camera} camera - The camera. 9879 * @return {Vector3} A reference to this vector. 9880 */ 9881 unproject( camera ) { 9882 9883 return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld ); 9884 9885 } 9886 9887 /** 9888 * Transforms the direction of this vector by a matrix (the upper left 3 x 3 9889 * subset of the given 4x4 matrix and then normalizes the result. 9890 * 9891 * @param {Matrix4} m - The matrix. 9892 * @return {Vector3} A reference to this vector. 9893 */ 9894 transformDirection( m ) { 9895 9896 // input: THREE.Matrix4 affine matrix 9897 // vector interpreted as a direction 9898 9899 const x = this.x, y = this.y, z = this.z; 9900 const e = m.elements; 9901 9902 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z; 9903 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z; 9904 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z; 9905 9906 return this.normalize(); 9907 9908 } 9909 9910 /** 9911 * Divides this instance by the given vector. 9912 * 9913 * @param {Vector3} v - The vector to divide. 9914 * @return {Vector3} A reference to this vector. 9915 */ 9916 divide( v ) { 9917 9918 this.x /= v.x; 9919 this.y /= v.y; 9920 this.z /= v.z; 9921 9922 return this; 9923 9924 } 9925 9926 /** 9927 * Divides this vector by the given scalar. 9928 * 9929 * @param {number} scalar - The scalar to divide. 9930 * @return {Vector3} A reference to this vector. 9931 */ 9932 divideScalar( scalar ) { 9933 9934 return this.multiplyScalar( 1 / scalar ); 9935 9936 } 9937 9938 /** 9939 * If this vector's x, y or z value is greater than the given vector's x, y or z 9940 * value, replace that value with the corresponding min value. 9941 * 9942 * @param {Vector3} v - The vector. 9943 * @return {Vector3} A reference to this vector. 9944 */ 9945 min( v ) { 9946 9947 this.x = Math.min( this.x, v.x ); 9948 this.y = Math.min( this.y, v.y ); 9949 this.z = Math.min( this.z, v.z ); 9950 9951 return this; 9952 9953 } 9954 9955 /** 9956 * If this vector's x, y or z value is less than the given vector's x, y or z 9957 * value, replace that value with the corresponding max value. 9958 * 9959 * @param {Vector3} v - The vector. 9960 * @return {Vector3} A reference to this vector. 9961 */ 9962 max( v ) { 9963 9964 this.x = Math.max( this.x, v.x ); 9965 this.y = Math.max( this.y, v.y ); 9966 this.z = Math.max( this.z, v.z ); 9967 9968 return this; 9969 9970 } 9971 9972 /** 9973 * If this vector's x, y or z value is greater than the max vector's x, y or z 9974 * value, it is replaced by the corresponding value. 9975 * If this vector's x, y or z value is less than the min vector's x, y or z value, 9976 * it is replaced by the corresponding value. 9977 * 9978 * @param {Vector3} min - The minimum x, y and z values. 9979 * @param {Vector3} max - The maximum x, y and z values in the desired range. 9980 * @return {Vector3} A reference to this vector. 9981 */ 9982 clamp( min, max ) { 9983 9984 // assumes min < max, componentwise 9985 9986 this.x = clamp( this.x, min.x, max.x ); 9987 this.y = clamp( this.y, min.y, max.y ); 9988 this.z = clamp( this.z, min.z, max.z ); 9989 9990 return this; 9991 9992 } 9993 9994 /** 9995 * If this vector's x, y or z values are greater than the max value, they are 9996 * replaced by the max value. 9997 * If this vector's x, y or z values are less than the min value, they are 9998 * replaced by the min value. 9999 * 10000 * @param {number} minVal - The minimum value the components will be clamped to. 10001 * @param {number} maxVal - The maximum value the components will be clamped to. 10002 * @return {Vector3} A reference to this vector. 10003 */ 10004 clampScalar( minVal, maxVal ) { 10005 10006 this.x = clamp( this.x, minVal, maxVal ); 10007 this.y = clamp( this.y, minVal, maxVal ); 10008 this.z = clamp( this.z, minVal, maxVal ); 10009 10010 return this; 10011 10012 } 10013 10014 /** 10015 * If this vector's length is greater than the max value, it is replaced by 10016 * the max value. 10017 * If this vector's length is less than the min value, it is replaced by the 10018 * min value. 10019 * 10020 * @param {number} min - The minimum value the vector length will be clamped to. 10021 * @param {number} max - The maximum value the vector length will be clamped to. 10022 * @return {Vector3} A reference to this vector. 10023 */ 10024 clampLength( min, max ) { 10025 10026 const length = this.length(); 10027 10028 return this.divideScalar( length || 1 ).multiplyScalar( clamp( length, min, max ) ); 10029 10030 } 10031 10032 /** 10033 * The components of this vector are rounded down to the nearest integer value. 10034 * 10035 * @return {Vector3} A reference to this vector. 10036 */ 10037 floor() { 10038 10039 this.x = Math.floor( this.x ); 10040 this.y = Math.floor( this.y ); 10041 this.z = Math.floor( this.z ); 10042 10043 return this; 10044 10045 } 10046 10047 /** 10048 * The components of this vector are rounded up to the nearest integer value. 10049 * 10050 * @return {Vector3} A reference to this vector. 10051 */ 10052 ceil() { 10053 10054 this.x = Math.ceil( this.x ); 10055 this.y = Math.ceil( this.y ); 10056 this.z = Math.ceil( this.z ); 10057 10058 return this; 10059 10060 } 10061 10062 /** 10063 * The components of this vector are rounded to the nearest integer value 10064 * 10065 * @return {Vector3} A reference to this vector. 10066 */ 10067 round() { 10068 10069 this.x = Math.round( this.x ); 10070 this.y = Math.round( this.y ); 10071 this.z = Math.round( this.z ); 10072 10073 return this; 10074 10075 } 10076 10077 /** 10078 * The components of this vector are rounded towards zero (up if negative, 10079 * down if positive) to an integer value. 10080 * 10081 * @return {Vector3} A reference to this vector. 10082 */ 10083 roundToZero() { 10084 10085 this.x = Math.trunc( this.x ); 10086 this.y = Math.trunc( this.y ); 10087 this.z = Math.trunc( this.z ); 10088 10089 return this; 10090 10091 } 10092 10093 /** 10094 * Inverts this vector - i.e. sets x = -x, y = -y and z = -z. 10095 * 10096 * @return {Vector3} A reference to this vector. 10097 */ 10098 negate() { 10099 10100 this.x = - this.x; 10101 this.y = - this.y; 10102 this.z = - this.z; 10103 10104 return this; 10105 10106 } 10107 10108 /** 10109 * Calculates the dot product of the given vector with this instance. 10110 * 10111 * @param {Vector3} v - The vector to compute the dot product with. 10112 * @return {number} The result of the dot product. 10113 */ 10114 dot( v ) { 10115 10116 return this.x * v.x + this.y * v.y + this.z * v.z; 10117 10118 } 10119 10120 // TODO lengthSquared?
vendor: 12,137 bytes, lines 10120-10632
10120 10121 10122 /** 10123 * Computes the square of the Euclidean length (straight-line length) from 10124 * (0, 0, 0) to (x, y, z). If you are comparing the lengths of vectors, you should 10125 * compare the length squared instead as it is slightly more efficient to calculate. 10126 * 10127 * @return {number} The square length of this vector. 10128 */ 10129 lengthSq() { 10130 10131 return this.x * this.x + this.y * this.y + this.z * this.z; 10132 10133 } 10134 10135 /** 10136 * Computes the Euclidean length (straight-line length) from (0, 0, 0) to (x, y, z). 10137 * 10138 * @return {number} The length of this vector. 10139 */ 10140 length() { 10141 10142 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); 10143 10144 } 10145 10146 /** 10147 * Computes the Manhattan length of this vector. 10148 * 10149 * @return {number} The length of this vector. 10150 */ 10151 manhattanLength() { 10152 10153 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); 10154 10155 } 10156 10157 /** 10158 * Converts this vector to a unit vector - that is, sets it equal to a vector 10159 * with the same direction as this one, but with a vector length of `1`. 10160 * 10161 * @return {Vector3} A reference to this vector. 10162 */ 10163 normalize() { 10164 10165 return this.divideScalar( this.length() || 1 ); 10166 10167 } 10168 10169 /** 10170 * Sets this vector to a vector with the same direction as this one, but 10171 * with the specified length. 10172 * 10173 * @param {number} length - The new length of this vector. 10174 * @return {Vector3} A reference to this vector. 10175 */ 10176 setLength( length ) { 10177 10178 return this.normalize().multiplyScalar( length ); 10179 10180 } 10181 10182 /** 10183 * Linearly interpolates between the given vector and this instance, where 10184 * alpha is the percent distance along the line - alpha = 0 will be this 10185 * vector, and alpha = 1 will be the given one. 10186 * 10187 * @param {Vector3} v - The vector to interpolate towards. 10188 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. 10189 * @return {Vector3} A reference to this vector. 10190 */ 10191 lerp( v, alpha ) { 10192 10193 this.x += ( v.x - this.x ) * alpha; 10194 this.y += ( v.y - this.y ) * alpha; 10195 this.z += ( v.z - this.z ) * alpha; 10196 10197 return this; 10198 10199 } 10200 10201 /** 10202 * Linearly interpolates between the given vectors, where alpha is the percent 10203 * distance along the line - alpha = 0 will be first vector, and alpha = 1 will 10204 * be the second one. The result is stored in this instance. 10205 * 10206 * @param {Vector3} v1 - The first vector. 10207 * @param {Vector3} v2 - The second vector. 10208 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. 10209 * @return {Vector3} A reference to this vector. 10210 */ 10211 lerpVectors( v1, v2, alpha ) { 10212 10213 this.x = v1.x + ( v2.x - v1.x ) * alpha; 10214 this.y = v1.y + ( v2.y - v1.y ) * alpha; 10215 this.z = v1.z + ( v2.z - v1.z ) * alpha; 10216 10217 return this; 10218 10219 } 10220 10221 /** 10222 * Calculates the cross product of the given vector with this instance. 10223 * 10224 * @param {Vector3} v - The vector to compute the cross product with. 10225 * @return {Vector3} The result of the cross product. 10226 */ 10227 cross( v ) { 10228 10229 return this.crossVectors( this, v ); 10230 10231 } 10232 10233 /** 10234 * Calculates the cross product of the given vectors and stores the result 10235 * in this instance. 10236 * 10237 * @param {Vector3} a - The first vector. 10238 * @param {Vector3} b - The second vector. 10239 * @return {Vector3} A reference to this vector. 10240 */ 10241 crossVectors( a, b ) { 10242 10243 const ax = a.x, ay = a.y, az = a.z; 10244 const bx = b.x, by = b.y, bz = b.z; 10245 10246 this.x = ay * bz - az * by; 10247 this.y = az * bx - ax * bz; 10248 this.z = ax * by - ay * bx; 10249 10250 return this; 10251 10252 } 10253 10254 /** 10255 * Projects this vector onto the given one. 10256 * 10257 * @param {Vector3} v - The vector to project to. 10258 * @return {Vector3} A reference to this vector. 10259 */ 10260 projectOnVector( v ) { 10261 10262 const denominator = v.lengthSq(); 10263 10264 if ( denominator === 0 ) return this.set( 0, 0, 0 ); 10265 10266 const scalar = v.dot( this ) / denominator; 10267 10268 return this.copy( v ).multiplyScalar( scalar ); 10269 10270 } 10271 10272 /** 10273 * Projects this vector onto a plane by subtracting this 10274 * vector projected onto the plane's normal from this vector. 10275 * 10276 * @param {Vector3} planeNormal - The plane normal. 10277 * @return {Vector3} A reference to this vector. 10278 */ 10279 projectOnPlane( planeNormal ) { 10280 10281 _vector$c.copy( this ).projectOnVector( planeNormal ); 10282 10283 return this.sub( _vector$c ); 10284 10285 } 10286 10287 /** 10288 * Reflects this vector off a plane orthogonal to the given normal vector. 10289 * 10290 * @param {Vector3} normal - The (normalized) normal vector. 10291 * @return {Vector3} A reference to this vector. 10292 */ 10293 reflect( normal ) { 10294 10295 return this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); 10296 10297 } 10298 /** 10299 * Returns the angle between the given vector and this instance in radians. 10300 * 10301 * @param {Vector3} v - The vector to compute the angle with. 10302 * @return {number} The angle in radians. 10303 */ 10304 angleTo( v ) { 10305 10306 const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); 10307 10308 if ( denominator === 0 ) return Math.PI / 2; 10309 10310 const theta = this.dot( v ) / denominator; 10311 10312 // clamp, to handle numerical problems 10313 10314 return Math.acos( clamp( theta, -1, 1 ) ); 10315 10316 } 10317 10318 /** 10319 * Computes the distance from the given vector to this instance. 10320 * 10321 * @param {Vector3} v - The vector to compute the distance to. 10322 * @return {number} The distance. 10323 */ 10324 distanceTo( v ) { 10325 10326 return Math.sqrt( this.distanceToSquared( v ) ); 10327 10328 } 10329 10330 /** 10331 * Computes the squared distance from the given vector to this instance. 10332 * If you are just comparing the distance with another distance, you should compare 10333 * the distance squared instead as it is slightly more efficient to calculate. 10334 * 10335 * @param {Vector3} v - The vector to compute the squared distance to. 10336 * @return {number} The squared distance. 10337 */ 10338 distanceToSquared( v ) { 10339 10340 const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; 10341 10342 return dx * dx + dy * dy + dz * dz; 10343 10344 } 10345 10346 /** 10347 * Computes the Manhattan distance from the given vector to this instance. 10348 * 10349 * @param {Vector3} v - The vector to compute the Manhattan distance to. 10350 * @return {number} The Manhattan distance. 10351 */ 10352 manhattanDistanceTo( v ) { 10353 10354 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); 10355 10356 } 10357 10358 /** 10359 * Sets the vector components from the given spherical coordinates. 10360 * 10361 * @param {Spherical} s - The spherical coordinates. 10362 * @return {Vector3} A reference to this vector. 10363 */ 10364 setFromSpherical( s ) { 10365 10366 return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); 10367 10368 } 10369 10370 /** 10371 * Sets the vector components from the given spherical coordinates. 10372 * 10373 * @param {number} radius - The radius. 10374 * @param {number} phi - The phi angle in radians. 10375 * @param {number} theta - The theta angle in radians. 10376 * @return {Vector3} A reference to this vector. 10377 */ 10378 setFromSphericalCoords( radius, phi, theta ) { 10379 10380 const sinPhiRadius = Math.sin( phi ) * radius; 10381 10382 this.x = sinPhiRadius * Math.sin( theta ); 10383 this.y = Math.cos( phi ) * radius; 10384 this.z = sinPhiRadius * Math.cos( theta ); 10385 10386 return this; 10387 10388 } 10389 10390 /** 10391 * Sets the vector components from the given cylindrical coordinates. 10392 * 10393 * @param {Cylindrical} c - The cylindrical coordinates. 10394 * @return {Vector3} A reference to this vector. 10395 */ 10396 setFromCylindrical( c ) { 10397 10398 return this.setFromCylindricalCoords( c.radius, c.theta, c.y ); 10399 10400 } 10401 10402 /** 10403 * Sets the vector components from the given cylindrical coordinates. 10404 * 10405 * @param {number} radius - The radius. 10406 * @param {number} theta - The theta angle in radians. 10407 * @param {number} y - The y value. 10408 * @return {Vector3} A reference to this vector. 10409 */ 10410 setFromCylindricalCoords( radius, theta, y ) { 10411 10412 this.x = radius * Math.sin( theta ); 10413 this.y = y; 10414 this.z = radius * Math.cos( theta ); 10415 10416 return this; 10417 10418 } 10419 10420 /** 10421 * Sets the vector components to the position elements of the 10422 * given transformation matrix. 10423 * 10424 * @param {Matrix4} m - The 4x4 matrix. 10425 * @return {Vector3} A reference to this vector. 10426 */ 10427 setFromMatrixPosition( m ) { 10428 10429 const e = m.elements; 10430 10431 this.x = e[ 12 ]; 10432 this.y = e[ 13 ]; 10433 this.z = e[ 14 ]; 10434 10435 return this; 10436 10437 } 10438 10439 /** 10440 * Sets the vector components to the scale elements of the 10441 * given transformation matrix. 10442 * 10443 * @param {Matrix4} m - The 4x4 matrix. 10444 * @return {Vector3} A reference to this vector. 10445 */ 10446 setFromMatrixScale( m ) { 10447 10448 const sx = this.setFromMatrixColumn( m, 0 ).length(); 10449 const sy = this.setFromMatrixColumn( m, 1 ).length(); 10450 const sz = this.setFromMatrixColumn( m, 2 ).length(); 10451 10452 this.x = sx; 10453 this.y = sy; 10454 this.z = sz; 10455 10456 return this; 10457 10458 } 10459 10460 /** 10461 * Sets the vector components from the specified matrix column. 10462 * 10463 * @param {Matrix4} m - The 4x4 matrix. 10464 * @param {number} index - The column index. 10465 * @return {Vector3} A reference to this vector. 10466 */ 10467 setFromMatrixColumn( m, index ) { 10468 10469 return this.fromArray( m.elements, index * 4 ); 10470 10471 } 10472 10473 /** 10474 * Sets the vector components from the specified matrix column. 10475 * 10476 * @param {Matrix3} m - The 3x3 matrix. 10477 * @param {number} index - The column index. 10478 * @return {Vector3} A reference to this vector. 10479 */ 10480 setFromMatrix3Column( m, index ) { 10481 10482 return this.fromArray( m.elements, index * 3 ); 10483 10484 } 10485 10486 /** 10487 * Sets the vector components from the given Euler angles. 10488 * 10489 * @param {Euler} e - The Euler angles to set. 10490 * @return {Vector3} A reference to this vector. 10491 */ 10492 setFromEuler( e ) { 10493 10494 this.x = e._x; 10495 this.y = e._y; 10496 this.z = e._z; 10497 10498 return this; 10499 10500 } 10501 10502 /** 10503 * Sets the vector components from the RGB components of the 10504 * given color. 10505 * 10506 * @param {Color} c - The color to set. 10507 * @return {Vector3} A reference to this vector. 10508 */ 10509 setFromColor( c ) { 10510 10511 this.x = c.r; 10512 this.y = c.g; 10513 this.z = c.b; 10514 10515 return this; 10516 10517 } 10518 10519 /** 10520 * Returns `true` if this vector is equal with the given one. 10521 * 10522 * @param {Vector3} v - The vector to test for equality. 10523 * @return {boolean} Whether this vector is equal with the given one. 10524 */ 10525 equals( v ) { 10526 10527 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); 10528 10529 } 10530 10531 /** 10532 * Sets this vector's x value to be `array[ offset ]`, y value to be `array[ offset + 1 ]` 10533 * and z value to be `array[ offset + 2 ]`. 10534 * 10535 * @param {Array<number>} array - An array holding the vector component values. 10536 * @param {number} [offset=0] - The offset into the array. 10537 * @return {Vector3} A reference to this vector. 10538 */ 10539 fromArray( array, offset = 0 ) { 10540 10541 this.x = array[ offset ]; 10542 this.y = array[ offset + 1 ]; 10543 this.z = array[ offset + 2 ]; 10544 10545 return this; 10546 10547 } 10548 10549 /** 10550 * Writes the components of this vector to the given array. If no array is provided, 10551 * the method returns a new instance. 10552 * 10553 * @param {Array<number>} [array=[]] - The target array holding the vector components. 10554 * @param {number} [offset=0] - Index of the first element in the array. 10555 * @return {Array<number>} The vector components. 10556 */ 10557 toArray( array = [], offset = 0 ) { 10558 10559 array[ offset ] = this.x; 10560 array[ offset + 1 ] = this.y; 10561 array[ offset + 2 ] = this.z; 10562 10563 return array; 10564 10565 } 10566 10567 /** 10568 * Sets the components of this vector from the given buffer attribute. 10569 * 10570 * @param {BufferAttribute} attribute - The buffer attribute holding vector data. 10571 * @param {number} index - The index into the attribute. 10572 * @return {Vector3} A reference to this vector. 10573 */ 10574 fromBufferAttribute( attribute, index ) { 10575 10576 this.x = attribute.getX( index ); 10577 this.y = attribute.getY( index ); 10578 this.z = attribute.getZ( index ); 10579 10580 return this; 10581 10582 } 10583 10584 /** 10585 * Sets each component of this vector to a pseudo-random value between `0` and 10586 * `1`, excluding `1`. 10587 * 10588 * @return {Vector3} A reference to this vector. 10589 */ 10590 random() { 10591 10592 this.x = Math.random(); 10593 this.y = Math.random(); 10594 this.z = Math.random(); 10595 10596 return this; 10597 10598 } 10599 10600 /** 10601 * Sets this vector to a uniformly random point on a unit sphere. 10602 * 10603 * @return {Vector3} A reference to this vector. 10604 */ 10605 randomDirection() { 10606 10607 // https://mathworld.wolfram.com/SpherePointPicking.html 10608 10609 const theta = Math.random() * Math.PI * 2; 10610 const u = Math.random() * 2 - 1; 10611 const c = Math.sqrt( 1 - u * u ); 10612 10613 this.x = c * Math.cos( theta ); 10614 this.y = u; 10615 this.z = c * Math.sin( theta ); 10616 10617 return this; 10618 10619 } 10620 10621 *[ Symbol.iterator ]() { 10622 10623 yield this.x; 10624 yield this.y; 10625 yield this.z; 10626 10627 } 10628 10629} 10630 10631const _vector$c = /*@__PURE__*/ new Vector3(); 10632const _quaternion$
vendor: 15,977 bytes, lines 10632-11254
106324 = /*@__PURE__*/ new Quaternion(); 10633 10634/** 10635 * Represents an axis-aligned bounding box (AABB) in 3D space. 10636 */ 10637class Box3 { 10638 10639 /** 10640 * Constructs a new bounding box. 10641 * 10642 * @param {Vector3} [min=(Infinity,Infinity,Infinity)] - A vector representing the lower boundary of the box. 10643 * @param {Vector3} [max=(-Infinity,-Infinity,-Infinity)] - A vector representing the upper boundary of the box. 10644 */ 10645 constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) { 10646 10647 /** 10648 * This flag can be used for type testing. 10649 * 10650 * @type {boolean} 10651 * @readonly 10652 * @default true 10653 */ 10654 this.isBox3 = true; 10655 10656 /** 10657 * The lower boundary of the box. 10658 * 10659 * @type {Vector3} 10660 */ 10661 this.min = min; 10662 10663 /** 10664 * The upper boundary of the box. 10665 * 10666 * @type {Vector3} 10667 */ 10668 this.max = max; 10669 10670 } 10671 10672 /** 10673 * Sets the lower and upper boundaries of this box. 10674 * Please note that this method only copies the values from the given objects. 10675 * 10676 * @param {Vector3} min - The lower boundary of the box. 10677 * @param {Vector3} max - The upper boundary of the box. 10678 * @return {Box3} A reference to this bounding box. 10679 */ 10680 set( min, max ) { 10681 10682 this.min.copy( min ); 10683 this.max.copy( max ); 10684 10685 return this; 10686 10687 } 10688 10689 /** 10690 * Sets the upper and lower bounds of this box so it encloses the position data 10691 * in the given array. 10692 * 10693 * @param {Array<number>} array - An array holding 3D position data. 10694 * @return {Box3} A reference to this bounding box. 10695 */ 10696 setFromArray( array ) { 10697 10698 this.makeEmpty(); 10699 10700 for ( let i = 0, il = array.length; i < il; i += 3 ) { 10701 10702 this.expandByPoint( _vector$b.fromArray( array, i ) ); 10703 10704 } 10705 10706 return this; 10707 10708 } 10709 10710 /** 10711 * Sets the upper and lower bounds of this box so it encloses the position data 10712 * in the given buffer attribute. 10713 * 10714 * @param {BufferAttribute} attribute - A buffer attribute holding 3D position data. 10715 * @return {Box3} A reference to this bounding box. 10716 */ 10717 setFromBufferAttribute( attribute ) { 10718 10719 this.makeEmpty(); 10720 10721 for ( let i = 0, il = attribute.count; i < il; i ++ ) { 10722 10723 this.expandByPoint( _vector$b.fromBufferAttribute( attribute, i ) ); 10724 10725 } 10726 10727 return this; 10728 10729 } 10730 10731 /** 10732 * Sets the upper and lower bounds of this box so it encloses the position data 10733 * in the given array. 10734 * 10735 * @param {Array<Vector3>} points - An array holding 3D position data as instances of {@link Vector3}. 10736 * @return {Box3} A reference to this bounding box. 10737 */ 10738 setFromPoints( points ) { 10739 10740 this.makeEmpty(); 10741 10742 for ( let i = 0, il = points.length; i < il; i ++ ) { 10743 10744 this.expandByPoint( points[ i ] ); 10745 10746 } 10747 10748 return this; 10749 10750 } 10751 10752 /** 10753 * Centers this box on the given center vector and sets this box's width, height and 10754 * depth to the given size values. 10755 * 10756 * @param {Vector3} center - The center of the box. 10757 * @param {Vector3} size - The x, y and z dimensions of the box. 10758 * @return {Box3} A reference to this bounding box. 10759 */ 10760 setFromCenterAndSize( center, size ) { 10761 10762 const halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 ); 10763 10764 this.min.copy( center ).sub( halfSize ); 10765 this.max.copy( center ).add( halfSize ); 10766 10767 return this; 10768 10769 } 10770 10771 /** 10772 * Computes the world-axis-aligned bounding box for the given 3D object 10773 * (including its children), accounting for the object's, and children's, 10774 * world transforms. The function may result in a larger box than strictly necessary. 10775 * 10776 * @param {Object3D} object - The 3D object to compute the bounding box for. 10777 * @param {boolean} [precise=false] - If set to `true`, the method computes the smallest 10778 * world-axis-aligned bounding box at the expense of more computation. 10779 * @return {Box3} A reference to this bounding box. 10780 */ 10781 setFromObject( object, precise = false ) { 10782 10783 this.makeEmpty(); 10784 10785 return this.expandByObject( object, precise ); 10786 10787 } 10788 10789 /** 10790 * Returns a new box with copied values from this instance. 10791 * 10792 * @return {Box3} A clone of this instance. 10793 */ 10794 clone() { 10795 10796 return new this.constructor().copy( this ); 10797 10798 } 10799 10800 /** 10801 * Copies the values of the given box to this instance. 10802 * 10803 * @param {Box3} box - The box to copy. 10804 * @return {Box3} A reference to this bounding box. 10805 */ 10806 copy( box ) { 10807 10808 this.min.copy( box.min ); 10809 this.max.copy( box.max ); 10810 10811 return this; 10812 10813 } 10814 10815 /** 10816 * Makes this box empty which means in encloses a zero space in 3D. 10817 * 10818 * @return {Box3} A reference to this bounding box. 10819 */ 10820 makeEmpty() { 10821 10822 this.min.x = this.min.y = this.min.z = + Infinity; 10823 this.max.x = this.max.y = this.max.z = - Infinity; 10824 10825 return this; 10826 10827 } 10828 10829 /** 10830 * Returns true if this box includes zero points within its bounds. 10831 * Note that a box with equal lower and upper bounds still includes one 10832 * point, the one both bounds share. 10833 * 10834 * @return {boolean} Whether this box is empty or not. 10835 */ 10836 isEmpty() { 10837 10838 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes 10839 10840 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); 10841 10842 } 10843 10844 /** 10845 * Returns the center point of this box. 10846 * 10847 * @param {Vector3} target - The target vector that is used to store the method's result. 10848 * @return {Vector3} The center point. 10849 */ 10850 getCenter( target ) { 10851 10852 return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); 10853 10854 } 10855 10856 /** 10857 * Returns the dimensions of this box. 10858 * 10859 * @param {Vector3} target - The target vector that is used to store the method's result. 10860 * @return {Vector3} The size. 10861 */ 10862 getSize( target ) { 10863 10864 return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min ); 10865 10866 } 10867 10868 /** 10869 * Expands the boundaries of this box to include the given point. 10870 * 10871 * @param {Vector3} point - The point that should be included by the bounding box. 10872 * @return {Box3} A reference to this bounding box. 10873 */ 10874 expandByPoint( point ) { 10875 10876 this.min.min( point ); 10877 this.max.max( point ); 10878 10879 return this; 10880 10881 } 10882 10883 /** 10884 * Expands this box equilaterally by the given vector. The width of this 10885 * box will be expanded by the x component of the vector in both 10886 * directions. The height of this box will be expanded by the y component of 10887 * the vector in both directions. The depth of this box will be 10888 * expanded by the z component of the vector in both directions. 10889 * 10890 * @param {Vector3} vector - The vector that should expand the bounding box. 10891 * @return {Box3} A reference to this bounding box. 10892 */ 10893 expandByVector( vector ) { 10894 10895 this.min.sub( vector ); 10896 this.max.add( vector ); 10897 10898 return this; 10899 10900 } 10901 10902 /** 10903 * Expands each dimension of the box by the given scalar. If negative, the 10904 * dimensions of the box will be contracted. 10905 * 10906 * @param {number} scalar - The scalar value that should expand the bounding box. 10907 * @return {Box3} A reference to this bounding box. 10908 */ 10909 expandByScalar( scalar ) { 10910 10911 this.min.addScalar( - scalar ); 10912 this.max.addScalar( scalar ); 10913 10914 return this; 10915 10916 } 10917 10918 /** 10919 * Expands the boundaries of this box to include the given 3D object and 10920 * its children, accounting for the object's, and children's, world 10921 * transforms. The function may result in a larger box than strictly 10922 * necessary (unless the precise parameter is set to true). 10923 * 10924 * @param {Object3D} object - The 3D object that should expand the bounding box. 10925 * @param {boolean} precise - If set to `true`, the method expands the bounding box 10926 * as little as necessary at the expense of more computation. 10927 * @return {Box3} A reference to this bounding box. 10928 */ 10929 expandByObject( object, precise = false ) { 10930 10931 // Computes the world-axis-aligned bounding box of an object (including its children), 10932 // accounting for both the object's, and children's, world transforms 10933 10934 object.updateWorldMatrix( false, false ); 10935 10936 const geometry = object.geometry; 10937 10938 if ( geometry !== undefined ) { 10939 10940 const positionAttribute = geometry.getAttribute( 'position' ); 10941 10942 // precise AABB computation based on vertex data requires at least a position attribute. 10943 // instancing isn't supported so far and uses the normal (conservative) code path. 10944 10945 if ( precise === true && positionAttribute !== undefined && object.isInstancedMesh !== true ) { 10946 10947 for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) { 10948 10949 if ( object.isMesh === true ) { 10950 10951 object.getVertexPosition( i, _vector$b ); 10952 10953 } else { 10954 10955 _vector$b.fromBufferAttribute( positionAttribute, i ); 10956 10957 } 10958 10959 _vector$b.applyMatrix4( object.matrixWorld ); 10960 this.expandByPoint( _vector$b ); 10961 10962 } 10963 10964 } else { 10965 10966 if ( object.boundingBox !== undefined ) { 10967 10968 // object-level bounding box 10969 10970 if ( object.boundingBox === null ) { 10971 10972 object.computeBoundingBox(); 10973 10974 } 10975 10976 _box$4.copy( object.boundingBox ); 10977 10978 10979 } else { 10980 10981 // geometry-level bounding box 10982 10983 if ( geometry.boundingBox === null ) { 10984 10985 geometry.computeBoundingBox(); 10986 10987 } 10988 10989 _box$4.copy( geometry.boundingBox ); 10990 10991 } 10992 10993 _box$4.applyMatrix4( object.matrixWorld ); 10994 10995 this.union( _box$4 ); 10996 10997 } 10998 10999 } 11000 11001 const children = object.children; 11002 11003 for ( let i = 0, l = children.length; i < l; i ++ ) { 11004 11005 this.expandByObject( children[ i ], precise ); 11006 11007 } 11008 11009 return this; 11010 11011 } 11012 11013 /** 11014 * Returns `true` if the given point lies within or on the boundaries of this box. 11015 * 11016 * @param {Vector3} point - The point to test. 11017 * @return {boolean} Whether the bounding box contains the given point or not. 11018 */ 11019 containsPoint( point ) { 11020 11021 return point.x >= this.min.x && point.x <= this.max.x && 11022 point.y >= this.min.y && point.y <= this.max.y && 11023 point.z >= this.min.z && point.z <= this.max.z; 11024 11025 } 11026 11027 /** 11028 * Returns `true` if this bounding box includes the entirety of the given bounding box. 11029 * If this box and the given one are identical, this function also returns `true`. 11030 * 11031 * @param {Box3} box - The bounding box to test. 11032 * @return {boolean} Whether the bounding box contains the given bounding box or not. 11033 */ 11034 containsBox( box ) { 11035 11036 return this.min.x <= box.min.x && box.max.x <= this.max.x && 11037 this.min.y <= box.min.y && box.max.y <= this.max.y && 11038 this.min.z <= box.min.z && box.max.z <= this.max.z; 11039 11040 } 11041 11042 /** 11043 * Returns a point as a proportion of this box's width, height and depth. 11044 * 11045 * @param {Vector3} point - A point in 3D space. 11046 * @param {Vector3} target - The target vector that is used to store the method's result. 11047 * @return {Vector3} A point as a proportion of this box's width, height and depth. 11048 */ 11049 getParameter( point, target ) { 11050 11051 // This can potentially have a divide by zero if the box 11052 // has a size dimension of 0. 11053 11054 return target.set( 11055 ( point.x - this.min.x ) / ( this.max.x - this.min.x ), 11056 ( point.y - this.min.y ) / ( this.max.y - this.min.y ), 11057 ( point.z - this.min.z ) / ( this.max.z - this.min.z ) 11058 ); 11059 11060 } 11061 11062 /** 11063 * Returns `true` if the given bounding box intersects with this bounding box. 11064 * 11065 * @param {Box3} box - The bounding box to test. 11066 * @return {boolean} Whether the given bounding box intersects with this bounding box. 11067 */ 11068 intersectsBox( box ) { 11069 11070 // using 6 splitting planes to rule out intersections. 11071 return box.max.x >= this.min.x && box.min.x <= this.max.x && 11072 box.max.y >= this.min.y && box.min.y <= this.max.y && 11073 box.max.z >= this.min.z && box.min.z <= this.max.z; 11074 11075 } 11076 11077 /** 11078 * Returns `true` if the given bounding sphere intersects with this bounding box. 11079 * 11080 * @param {Sphere} sphere - The bounding sphere to test. 11081 * @return {boolean} Whether the given bounding sphere intersects with this bounding box. 11082 */ 11083 intersectsSphere( sphere ) { 11084 11085 // Find the point on the AABB closest to the sphere center. 11086 this.clampPoint( sphere.center, _vector$b ); 11087 11088 // If that point is inside the sphere, the AABB and sphere intersect. 11089 return _vector$b.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius ); 11090 11091 } 11092 11093 /** 11094 * Returns `true` if the given plane intersects with this bounding box. 11095 * 11096 * @param {Plane} plane - The plane to test. 11097 * @return {boolean} Whether the given plane intersects with this bounding box. 11098 */ 11099 intersectsPlane( plane ) { 11100 11101 // We compute the minimum and maximum dot product values. If those values 11102 // are on the same side (back or front) of the plane, then there is no intersection. 11103 11104 let min, max; 11105 11106 if ( plane.normal.x > 0 ) { 11107 11108 min = plane.normal.x * this.min.x; 11109 max = plane.normal.x * this.max.x; 11110 11111 } else { 11112 11113 min = plane.normal.x * this.max.x; 11114 max = plane.normal.x * this.min.x; 11115 11116 } 11117 11118 if ( plane.normal.y > 0 ) { 11119 11120 min += plane.normal.y * this.min.y; 11121 max += plane.normal.y * this.max.y; 11122 11123 } else { 11124 11125 min += plane.normal.y * this.max.y; 11126 max += plane.normal.y * this.min.y; 11127 11128 } 11129 11130 if ( plane.normal.z > 0 ) { 11131 11132 min += plane.normal.z * this.min.z; 11133 max += plane.normal.z * this.max.z; 11134 11135 } else { 11136 11137 min += plane.normal.z * this.max.z; 11138 max += plane.normal.z * this.min.z; 11139 11140 } 11141 11142 return ( min <= - plane.constant && max >= - plane.constant ); 11143 11144 } 11145 11146 /** 11147 * Returns `true` if the given triangle intersects with this bounding box. 11148 * 11149 * @param {Triangle} triangle - The triangle to test. 11150 * @return {boolean} Whether the given triangle intersects with this bounding box. 11151 */ 11152 intersectsTriangle( triangle ) { 11153 11154 if ( this.isEmpty() ) { 11155 11156 return false; 11157 11158 } 11159 11160 // compute box center and extents 11161 this.getCenter( _center ); 11162 _extents.subVectors( this.max, _center ); 11163 11164 // translate triangle to aabb origin 11165 _v0$2.subVectors( triangle.a, _center ); 11166 _v1$7.subVectors( triangle.b, _center ); 11167 _v2$4.subVectors( triangle.c, _center ); 11168 11169 // compute edge vectors for triangle 11170 _f0.subVectors( _v1$7, _v0$2 ); 11171 _f1.subVectors( _v2$4, _v1$7 ); 11172 _f2.subVectors( _v0$2, _v2$4 ); 11173 11174 // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb 11175 // 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 11176 // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned) 11177 let axes = [ 11178 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y, 11179 _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x, 11180 - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0 11181 ]; 11182 if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { 11183 11184 return false; 11185 11186 } 11187 11188 // test 3 face normals from the aabb 11189 axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]; 11190 if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { 11191 11192 return false; 11193 11194 } 11195 11196 // finally testing the face normal of the triangle 11197 // use already existing triangle edge vectors here 11198 _triangleNormal.crossVectors( _f0, _f1 ); 11199 axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ]; 11200 11201 return satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ); 11202 11203 } 11204 11205 /** 11206 * Clamps the given point within the bounds of this box. 11207 * 11208 * @param {Vector3} point - The point to clamp. 11209 * @param {Vector3} target - The target vector that is used to store the method's result. 11210 * @return {Vector3} The clamped point. 11211 */ 11212 clampPoint( point, target ) { 11213 11214 return target.copy( point ).clamp( this.min, this.max ); 11215 11216 } 11217 11218 /** 11219 * Returns the euclidean distance from any edge of this box to the specified point. If 11220 * the given point lies inside of this box, the distance will be `0`. 11221 * 11222 * @param {Vector3} point - The point to compute the distance to. 11223 * @return {number} The euclidean distance. 11224 */ 11225 distanceToPoint( point ) { 11226 11227 return this.clampPoint( point, _vector$b ).distanceTo( point ); 11228 11229 } 11230 11231 /** 11232 * Returns a bounding sphere that encloses this bounding box. 11233 * 11234 * @param {Sphere} target - The target sphere that is used to store the method's result. 11235 * @return {Sphere} The bounding sphere that encloses this bounding box. 11236 */ 11237 getBoundingSphere( target ) { 11238 11239 if ( this.isEmpty() ) { 11240 11241 target.makeEmpty(); 11242 11243 } else { 11244 11245 this.getCenter( target.center ); 11246 11247 target.radius = this.getSize( _vector$b ).length() * 0.5; 11248 11249 } 11250 11251 return target; 11252 11253 } 11254
vendor: 8,977 bytes, lines 11255-11600
11255 /** 11256 * Computes the intersection of this bounding box and the given one, setting the upper 11257 * bound of this box to the lesser of the two boxes' upper bounds and the 11258 * lower bound of this box to the greater of the two boxes' lower bounds. If 11259 * there's no overlap, makes this box empty. 11260 * 11261 * @param {Box3} box - The bounding box to intersect with. 11262 * @return {Box3} A reference to this bounding box. 11263 */ 11264 intersect( box ) { 11265 11266 this.min.max( box.min ); 11267 this.max.min( box.max ); 11268 11269 // 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. 11270 if ( this.isEmpty() ) this.makeEmpty(); 11271 11272 return this; 11273 11274 } 11275 11276 /** 11277 * Computes the union of this box and another and the given one, setting the upper 11278 * bound of this box to the greater of the two boxes' upper bounds and the 11279 * lower bound of this box to the lesser of the two boxes' lower bounds. 11280 * 11281 * @param {Box3} box - The bounding box that will be unioned with this instance. 11282 * @return {Box3} A reference to this bounding box. 11283 */ 11284 union( box ) { 11285 11286 this.min.min( box.min ); 11287 this.max.max( box.max ); 11288 11289 return this; 11290 11291 } 11292 11293 /** 11294 * Transforms this bounding box by the given 4x4 transformation matrix. 11295 * 11296 * @param {Matrix4} matrix - The transformation matrix. 11297 * @return {Box3} A reference to this bounding box. 11298 */ 11299 applyMatrix4( matrix ) { 11300 11301 // transform of empty box is an empty box. 11302 if ( this.isEmpty() ) return this; 11303 11304 // NOTE: I am using a binary pattern to specify all 2^3 combinations below 11305 _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 11306 _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 11307 _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 11308 _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 11309 _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 11310 _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 11311 _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 11312 _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 11313 11314 this.setFromPoints( _points ); 11315 11316 return this; 11317 11318 } 11319 11320 /** 11321 * Adds the given offset to both the upper and lower bounds of this bounding box, 11322 * effectively moving it in 3D space. 11323 * 11324 * @param {Vector3} offset - The offset that should be used to translate the bounding box. 11325 * @return {Box3} A reference to this bounding box. 11326 */ 11327 translate( offset ) { 11328 11329 this.min.add( offset ); 11330 this.max.add( offset ); 11331 11332 return this; 11333 11334 } 11335 11336 /** 11337 * Returns `true` if this bounding box is equal with the given one. 11338 * 11339 * @param {Box3} box - The box to test for equality. 11340 * @return {boolean} Whether this bounding box is equal with the given one. 11341 */ 11342 equals( box ) { 11343 11344 return box.min.equals( this.min ) && box.max.equals( this.max ); 11345 11346 } 11347 11348} 11349 11350const _points = [ 11351 /*@__PURE__*/ new Vector3(), 11352 /*@__PURE__*/ new Vector3(), 11353 /*@__PURE__*/ new Vector3(), 11354 /*@__PURE__*/ new Vector3(), 11355 /*@__PURE__*/ new Vector3(), 11356 /*@__PURE__*/ new Vector3(), 11357 /*@__PURE__*/ new Vector3(), 11358 /*@__PURE__*/ new Vector3() 11359]; 11360 11361const _vector$b = /*@__PURE__*/ new Vector3(); 11362 11363const _box$4 = /*@__PURE__*/ new Box3(); 11364 11365// triangle centered vertices 11366 11367const _v0$2 = /*@__PURE__*/ new Vector3(); 11368const _v1$7 = /*@__PURE__*/ new Vector3(); 11369const _v2$4 = /*@__PURE__*/ new Vector3(); 11370 11371// triangle edge vectors 11372 11373const _f0 = /*@__PURE__*/ new Vector3(); 11374const _f1 = /*@__PURE__*/ new Vector3(); 11375const _f2 = /*@__PURE__*/ new Vector3(); 11376 11377const _center = /*@__PURE__*/ new Vector3(); 11378const _extents = /*@__PURE__*/ new Vector3(); 11379const _triangleNormal = /*@__PURE__*/ new Vector3(); 11380const _testAxis = /*@__PURE__*/ new Vector3(); 11381 11382function satForAxes( axes, v0, v1, v2, extents ) { 11383 11384 for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) { 11385 11386 _testAxis.fromArray( axes, i ); 11387 // project the aabb onto the separating axis 11388 const r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z ); 11389 // project all 3 vertices of the triangle onto the separating axis 11390 const p0 = v0.dot( _testAxis ); 11391 const p1 = v1.dot( _testAxis ); 11392 const p2 = v2.dot( _testAxis ); 11393 // actual test, basically see if either of the most extreme of the triangle points intersects r 11394 if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) { 11395 11396 // points of the projected triangle are outside the projected half-length of the aabb 11397 // the axis is separating and we can exit 11398 return false; 11399 11400 } 11401 11402 } 11403 11404 return true; 11405 11406} 11407 11408const _box$3 = /*@__PURE__*/ new Box3(); 11409const _v1$6 = /*@__PURE__*/ new Vector3(); 11410const _v2$3 = /*@__PURE__*/ new Vector3(); 11411 11412/** 11413 * An analytical 3D sphere defined by a center and radius. This class is mainly 11414 * used as a Bounding Sphere for 3D objects. 11415 */ 11416class Sphere { 11417 11418 /** 11419 * Constructs a new sphere. 11420 * 11421 * @param {Vector3} [center=(0,0,0)] - The center of the sphere 11422 * @param {number} [radius=-1] - The radius of the sphere. 11423 */ 11424 constructor( center = new Vector3(), radius = -1 ) { 11425 11426 /** 11427 * This flag can be used for type testing. 11428 * 11429 * @type {boolean} 11430 * @readonly 11431 * @default true 11432 */ 11433 this.isSphere = true; 11434 11435 /** 11436 * The center of the sphere 11437 * 11438 * @type {Vector3} 11439 */ 11440 this.center = center; 11441 11442 /** 11443 * The radius of the sphere. 11444 * 11445 * @type {number} 11446 */ 11447 this.radius = radius; 11448 11449 } 11450 11451 /** 11452 * Sets the sphere's components by copying the given values. 11453 * 11454 * @param {Vector3} center - The center. 11455 * @param {number} radius - The radius. 11456 * @return {Sphere} A reference to this sphere. 11457 */ 11458 set( center, radius ) { 11459 11460 this.center.copy( center ); 11461 this.radius = radius; 11462 11463 return this; 11464 11465 } 11466 11467 /** 11468 * Computes the minimum bounding sphere for list of points. 11469 * If the optional center point is given, it is used as the sphere's 11470 * center. Otherwise, the center of the axis-aligned bounding box 11471 * encompassing the points is calculated. 11472 * 11473 * @param {Array<Vector3>} points - A list of points in 3D space. 11474 * @param {Vector3} [optionalCenter] - The center of the sphere. 11475 * @return {Sphere} A reference to this sphere. 11476 */ 11477 setFromPoints( points, optionalCenter ) { 11478 11479 const center = this.center; 11480 11481 if ( optionalCenter !== undefined ) { 11482 11483 center.copy( optionalCenter ); 11484 11485 } else { 11486 11487 _box$3.setFromPoints( points ).getCenter( center ); 11488 11489 } 11490 11491 let maxRadiusSq = 0; 11492 11493 for ( let i = 0, il = points.length; i < il; i ++ ) { 11494 11495 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); 11496 11497 } 11498 11499 this.radius = Math.sqrt( maxRadiusSq ); 11500 11501 return this; 11502 11503 } 11504 11505 /** 11506 * Copies the values of the given sphere to this instance. 11507 * 11508 * @param {Sphere} sphere - The sphere to copy. 11509 * @return {Sphere} A reference to this sphere. 11510 */ 11511 copy( sphere ) { 11512 11513 this.center.copy( sphere.center ); 11514 this.radius = sphere.radius; 11515 11516 return this; 11517 11518 } 11519 11520 /** 11521 * Returns `true` if the sphere is empty (the radius set to a negative number). 11522 * 11523 * Spheres with a radius of `0` contain only their center point and are not 11524 * considered to be empty. 11525 * 11526 * @return {boolean} Whether this sphere is empty or not. 11527 */ 11528 isEmpty() { 11529 11530 return ( this.radius < 0 ); 11531 11532 } 11533 11534 /** 11535 * Makes this sphere empty which means in encloses a zero space in 3D. 11536 * 11537 * @return {Sphere} A reference to this sphere. 11538 */ 11539 makeEmpty() { 11540 11541 this.center.set( 0, 0, 0 ); 11542 this.radius = -1; 11543 11544 return this; 11545 11546 } 11547 11548 /** 11549 * Returns `true` if this sphere contains the given point inclusive of 11550 * the surface of the sphere. 11551 * 11552 * @param {Vector3} point - The point to check. 11553 * @return {boolean} Whether this sphere contains the given point or not. 11554 */ 11555 containsPoint( point ) { 11556 11557 return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); 11558 11559 } 11560 11561 /** 11562 * Returns the closest distance from the boundary of the sphere to the 11563 * given point. If the sphere contains the point, the distance will 11564 * be negative. 11565 * 11566 * @param {Vector3} point - The point to compute the distance to. 11567 * @return {number} The distance to the point. 11568 */ 11569 distanceToPoint( point ) { 11570 11571 return ( point.distanceTo( this.center ) - this.radius ); 11572 11573 } 11574 11575 /** 11576 * Returns `true` if this sphere intersects with the given one. 11577 * 11578 * @param {Sphere} sphere - The sphere to test. 11579 * @return {boolean} Whether this sphere intersects with the given one or not. 11580 */ 11581 intersectsSphere( sphere ) { 11582 11583 const radiusSum = this.radius + sphere.radius; 11584 11585 return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); 11586 11587 } 11588 11589 /** 11590 * Returns `true` if this sphere intersects with the given box. 11591 * 11592 * @param {Box3} box - The box to test. 11593 * @return {boolean} Whether this sphere intersects with the given box or not. 11594 */ 11595 intersectsBox( box ) { 11596 11597 return box.intersectsSphere( this ); 11598 11599 } 11600
vendor: 9,314 bytes, lines 11601-11991
11601 /** 11602 * Returns `true` if this sphere intersects with the given plane. 11603 * 11604 * @param {Plane} plane - The plane to test. 11605 * @return {boolean} Whether this sphere intersects with the given plane or not. 11606 */ 11607 intersectsPlane( plane ) { 11608 11609 return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; 11610 11611 } 11612 11613 /** 11614 * Clamps a point within the sphere. If the point is outside the sphere, it 11615 * will clamp it to the closest point on the edge of the sphere. Points 11616 * already inside the sphere will not be affected. 11617 * 11618 * @param {Vector3} point - The plane to clamp. 11619 * @param {Vector3} target - The target vector that is used to store the method's result. 11620 * @return {Vector3} The clamped point. 11621 */ 11622 clampPoint( point, target ) { 11623 11624 const deltaLengthSq = this.center.distanceToSquared( point ); 11625 11626 target.copy( point ); 11627 11628 if ( deltaLengthSq > ( this.radius * this.radius ) ) { 11629 11630 target.sub( this.center ).normalize(); 11631 target.multiplyScalar( this.radius ).add( this.center ); 11632 11633 } 11634 11635 return target; 11636 11637 } 11638 11639 /** 11640 * Returns a bounding box that encloses this sphere. 11641 * 11642 * @param {Box3} target - The target box that is used to store the method's result. 11643 * @return {Box3} The bounding box that encloses this sphere. 11644 */ 11645 getBoundingBox( target ) { 11646 11647 if ( this.isEmpty() ) { 11648 11649 // Empty sphere produces empty bounding box 11650 target.makeEmpty(); 11651 return target; 11652 11653 } 11654 11655 target.set( this.center, this.center ); 11656 target.expandByScalar( this.radius ); 11657 11658 return target; 11659 11660 } 11661 11662 /** 11663 * Transforms this sphere with the given 4x4 transformation matrix. 11664 * 11665 * @param {Matrix4} matrix - The transformation matrix. 11666 * @return {Sphere} A reference to this sphere. 11667 */ 11668 applyMatrix4( matrix ) { 11669 11670 this.center.applyMatrix4( matrix ); 11671 this.radius = this.radius * matrix.getMaxScaleOnAxis(); 11672 11673 return this; 11674 11675 } 11676 11677 /** 11678 * Translates the sphere's center by the given offset. 11679 * 11680 * @param {Vector3} offset - The offset. 11681 * @return {Sphere} A reference to this sphere. 11682 */ 11683 translate( offset ) { 11684 11685 this.center.add( offset ); 11686 11687 return this; 11688 11689 } 11690 11691 /** 11692 * Expands the boundaries of this sphere to include the given point. 11693 * 11694 * @param {Vector3} point - The point to include. 11695 * @return {Sphere} A reference to this sphere. 11696 */ 11697 expandByPoint( point ) { 11698 11699 if ( this.isEmpty() ) { 11700 11701 this.center.copy( point ); 11702 11703 this.radius = 0; 11704 11705 return this; 11706 11707 } 11708 11709 _v1$6.subVectors( point, this.center ); 11710 11711 const lengthSq = _v1$6.lengthSq(); 11712 11713 if ( lengthSq > ( this.radius * this.radius ) ) { 11714 11715 // calculate the minimal sphere 11716 11717 const length = Math.sqrt( lengthSq ); 11718 11719 const delta = ( length - this.radius ) * 0.5; 11720 11721 this.center.addScaledVector( _v1$6, delta / length ); 11722 11723 this.radius += delta; 11724 11725 } 11726 11727 return this; 11728 11729 } 11730 11731 /** 11732 * Expands this sphere to enclose both the original sphere and the given sphere. 11733 * 11734 * @param {Sphere} sphere - The sphere to include. 11735 * @return {Sphere} A reference to this sphere. 11736 */ 11737 union( sphere ) { 11738 11739 if ( sphere.isEmpty() ) { 11740 11741 return this; 11742 11743 } 11744 11745 if ( this.isEmpty() ) { 11746 11747 this.copy( sphere ); 11748 11749 return this; 11750 11751 } 11752 11753 if ( this.center.equals( sphere.center ) === true ) { 11754 11755 this.radius = Math.max( this.radius, sphere.radius ); 11756 11757 } else { 11758 11759 _v2$3.subVectors( sphere.center, this.center ).setLength( sphere.radius ); 11760 11761 this.expandByPoint( _v1$6.copy( sphere.center ).add( _v2$3 ) ); 11762 11763 this.expandByPoint( _v1$6.copy( sphere.center ).sub( _v2$3 ) ); 11764 11765 } 11766 11767 return this; 11768 11769 } 11770 11771 /** 11772 * Returns `true` if this sphere is equal with the given one. 11773 * 11774 * @param {Sphere} sphere - The sphere to test for equality. 11775 * @return {boolean} Whether this bounding sphere is equal with the given one. 11776 */ 11777 equals( sphere ) { 11778 11779 return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); 11780 11781 } 11782 11783 /** 11784 * Returns a new sphere with copied values from this instance. 11785 * 11786 * @return {Sphere} A clone of this instance. 11787 */ 11788 clone() { 11789 11790 return new this.constructor().copy( this ); 11791 11792 } 11793 11794} 11795 11796const _vector$a = /*@__PURE__*/ new Vector3(); 11797const _segCenter = /*@__PURE__*/ new Vector3(); 11798const _segDir = /*@__PURE__*/ new Vector3(); 11799const _diff = /*@__PURE__*/ new Vector3(); 11800 11801const _edge1 = /*@__PURE__*/ new Vector3(); 11802const _edge2 = /*@__PURE__*/ new Vector3(); 11803const _normal$1 = /*@__PURE__*/ new Vector3(); 11804 11805/** 11806 * A ray that emits from an origin in a certain direction. The class is used by 11807 * {@link Raycaster} to assist with raycasting. Raycasting is used for 11808 * mouse picking (working out what objects in the 3D space the mouse is over) 11809 * amongst other things. 11810 */ 11811class Ray { 11812 11813 /** 11814 * Constructs a new ray. 11815 * 11816 * @param {Vector3} [origin=(0,0,0)] - The origin of the ray. 11817 * @param {Vector3} [direction=(0,0,-1)] - The (normalized) direction of the ray. 11818 */ 11819 constructor( origin = new Vector3(), direction = new Vector3( 0, 0, -1 ) ) { 11820 11821 /** 11822 * The origin of the ray. 11823 * 11824 * @type {Vector3} 11825 */ 11826 this.origin = origin; 11827 11828 /** 11829 * The (normalized) direction of the ray. 11830 * 11831 * @type {Vector3} 11832 */ 11833 this.direction = direction; 11834 11835 } 11836 11837 /** 11838 * Sets the ray's components by copying the given values. 11839 * 11840 * @param {Vector3} origin - The origin. 11841 * @param {Vector3} direction - The direction. 11842 * @return {Ray} A reference to this ray. 11843 */ 11844 set( origin, direction ) { 11845 11846 this.origin.copy( origin ); 11847 this.direction.copy( direction ); 11848 11849 return this; 11850 11851 } 11852 11853 /** 11854 * Copies the values of the given ray to this instance. 11855 * 11856 * @param {Ray} ray - The ray to copy. 11857 * @return {Ray} A reference to this ray. 11858 */ 11859 copy( ray ) { 11860 11861 this.origin.copy( ray.origin ); 11862 this.direction.copy( ray.direction ); 11863 11864 return this; 11865 11866 } 11867 11868 /** 11869 * Returns a vector that is located at a given distance along this ray. 11870 * 11871 * @param {number} t - The distance along the ray to retrieve a position for. 11872 * @param {Vector3} target - The target vector that is used to store the method's result. 11873 * @return {Vector3} A position on the ray. 11874 */ 11875 at( t, target ) { 11876 11877 return target.copy( this.origin ).addScaledVector( this.direction, t ); 11878 11879 } 11880 11881 /** 11882 * Adjusts the direction of the ray to point at the given vector in world space. 11883 * 11884 * @param {Vector3} v - The target position. 11885 * @return {Ray} A reference to this ray. 11886 */ 11887 lookAt( v ) { 11888 11889 this.direction.copy( v ).sub( this.origin ).normalize(); 11890 11891 return this; 11892 11893 } 11894 11895 /** 11896 * Shift the origin of this ray along its direction by the given distance. 11897 * 11898 * @param {number} t - The distance along the ray to interpolate. 11899 * @return {Ray} A reference to this ray. 11900 */ 11901 recast( t ) { 11902 11903 this.origin.copy( this.at( t, _vector$a ) ); 11904 11905 return this; 11906 11907 } 11908 11909 /** 11910 * Returns the point along this ray that is closest to the given point. 11911 * 11912 * @param {Vector3} point - A point in 3D space to get the closet location on the ray for. 11913 * @param {Vector3} target - The target vector that is used to store the method's result. 11914 * @return {Vector3} The closest point on this ray. 11915 */ 11916 closestPointToPoint( point, target ) { 11917 11918 target.subVectors( point, this.origin ); 11919 11920 const directionDistance = target.dot( this.direction ); 11921 11922 if ( directionDistance < 0 ) { 11923 11924 return target.copy( this.origin ); 11925 11926 } 11927 11928 return target.copy( this.origin ).addScaledVector( this.direction, directionDistance ); 11929 11930 } 11931 11932 /** 11933 * Returns the distance of the closest approach between this ray and the given point. 11934 * 11935 * @param {Vector3} point - A point in 3D space to compute the distance to. 11936 * @return {number} The distance. 11937 */ 11938 distanceToPoint( point ) { 11939 11940 return Math.sqrt( this.distanceSqToPoint( point ) ); 11941 11942 } 11943 11944 /** 11945 * Returns the squared distance of the closest approach between this ray and the given point. 11946 * 11947 * @param {Vector3} point - A point in 3D space to compute the distance to. 11948 * @return {number} The squared distance. 11949 */ 11950 distanceSqToPoint( point ) { 11951 11952 const directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction ); 11953 11954 // point behind the ray 11955 11956 if ( directionDistance < 0 ) { 11957 11958 return this.origin.distanceToSquared( point ); 11959 11960 } 11961 11962 _vector$a.copy( this.origin ).addScaledVector( this.direction, directionDistance ); 11963 11964 return _vector$a.distanceToSquared( point ); 11965 11966 } 11967 11968 /** 11969 * Returns the squared distance between this ray and the given line segment. 11970 * 11971 * @param {Vector3} v0 - The start point of the line segment. 11972 * @param {Vector3} v1 - The end point of the line segment. 11973 * @param {Vector3} [optionalPointOnRay] - When provided, it receives the point on this ray that is closest to the segment. 11974 * @param {Vector3} [optionalPointOnSegment] - When provided, it receives the point on the line segment that is closest to this ray. 11975 * @return {number} The squared distance. 11976 */ 11977 distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { 11978 11979 // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteDistRaySegment.h 11980 // It returns the min distance between the ray and the segment 11981 // defined by v0 and v1 11982 // It can also set two optional targets : 11983 // - The closest point on the ray 11984 // - The closest point on the segment 11985 11986 _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); 11987 _segDir.copy( v1 ).sub( v0 ).normalize(); 11988 _diff.copy( this.origin ).sub( _segCenter ); 11989 11990 const segExtent = v0.distanceTo( v1 ) * 0.5; 11991 const a01 = - this.direction.dot( _segDir );
vendor: 4,520 bytes, lines 11992-12179
11992 const b0 = _diff.dot( this.direction ); 11993 const b1 = - _diff.dot( _segDir ); 11994 const c = _diff.lengthSq(); 11995 const det = Math.abs( 1 - a01 * a01 ); 11996 let s0, s1, sqrDist, extDet; 11997 11998 if ( det > 0 ) { 11999 12000 // The ray and segment are not parallel. 12001 12002 s0 = a01 * b1 - b0; 12003 s1 = a01 * b0 - b1; 12004 extDet = segExtent * det; 12005 12006 if ( s0 >= 0 ) { 12007 12008 if ( s1 >= - extDet ) { 12009 12010 if ( s1 <= extDet ) { 12011 12012 // region 0 12013 // Minimum at interior points of ray and segment. 12014 12015 const invDet = 1 / det; 12016 s0 *= invDet; 12017 s1 *= invDet; 12018 sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; 12019 12020 } else { 12021 12022 // region 1 12023 12024 s1 = segExtent; 12025 s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); 12026 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 12027 12028 } 12029 12030 } else { 12031 12032 // region 5 12033 12034 s1 = - segExtent; 12035 s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); 12036 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 12037 12038 } 12039 12040 } else { 12041 12042 if ( s1 <= - extDet ) { 12043 12044 // region 4 12045 12046 s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); 12047 s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); 12048 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 12049 12050 } else if ( s1 <= extDet ) { 12051 12052 // region 3 12053 12054 s0 = 0; 12055 s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); 12056 sqrDist = s1 * ( s1 + 2 * b1 ) + c; 12057 12058 } else { 12059 12060 // region 2 12061 12062 s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); 12063 s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); 12064 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 12065 12066 } 12067 12068 } 12069 12070 } else { 12071 12072 // Ray and segment are parallel. 12073 12074 s1 = ( a01 > 0 ) ? - segExtent : segExtent; 12075 s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); 12076 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 12077 12078 } 12079 12080 if ( optionalPointOnRay ) { 12081 12082 optionalPointOnRay.copy( this.origin ).addScaledVector( this.direction, s0 ); 12083 12084 } 12085 12086 if ( optionalPointOnSegment ) { 12087 12088 optionalPointOnSegment.copy( _segCenter ).addScaledVector( _segDir, s1 ); 12089 12090 } 12091 12092 return sqrDist; 12093 12094 } 12095 12096 /** 12097 * Intersects this ray with the given sphere, returning the intersection 12098 * point or `null` if there is no intersection. 12099 * 12100 * @param {Sphere} sphere - The sphere to intersect. 12101 * @param {Vector3} target - The target vector that is used to store the method's result. 12102 * @return {?Vector3} The intersection point. 12103 */ 12104 intersectSphere( sphere, target ) { 12105 12106 _vector$a.subVectors( sphere.center, this.origin ); 12107 const tca = _vector$a.dot( this.direction ); 12108 const d2 = _vector$a.dot( _vector$a ) - tca * tca; 12109 const radius2 = sphere.radius * sphere.radius; 12110 12111 if ( d2 > radius2 ) return null; 12112 12113 const thc = Math.sqrt( radius2 - d2 ); 12114 12115 // t0 = first intersect point - entrance on front of sphere 12116 const t0 = tca - thc; 12117 12118 // t1 = second intersect point - exit point on back of sphere 12119 const t1 = tca + thc; 12120 12121 // test to see if t1 is behind the ray - if so, return null 12122 if ( t1 < 0 ) return null; 12123 12124 // test to see if t0 is behind the ray: 12125 // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, 12126 // in order to always return an intersect point that is in front of the ray. 12127 if ( t0 < 0 ) return this.at( t1, target ); 12128 12129 // else t0 is in front of the ray, so return the first collision point scaled by t0 12130 return this.at( t0, target ); 12131 12132 } 12133 12134 /** 12135 * Returns `true` if this ray intersects with the given sphere. 12136 * 12137 * @param {Sphere} sphere - The sphere to intersect. 12138 * @return {boolean} Whether this ray intersects with the given sphere or not. 12139 */ 12140 intersectsSphere( sphere ) { 12141 12142 return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius ); 12143 12144 } 12145 12146 /** 12147 * Computes the distance from the ray's origin to the given plane. Returns `null` if the ray 12148 * does not intersect with the plane. 12149 * 12150 * @param {Plane} plane - The plane to compute the distance to. 12151 * @return {?number} Whether this ray intersects with the given sphere or not. 12152 */ 12153 distanceToPlane( plane ) { 12154 12155 const denominator = plane.normal.dot( this.direction ); 12156 12157 if ( denominator === 0 ) { 12158 12159 // line is coplanar, return origin 12160 if ( plane.distanceToPoint( this.origin ) === 0 ) { 12161 12162 return 0; 12163 12164 } 12165 12166 // Null is preferable to undefined since undefined means.... it is undefined 12167 12168 return null; 12169 12170 } 12171 12172 const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; 12173 12174 // Return if the ray never intersects the plane 12175 12176 return t >= 0 ? t : null; 12177 12178 } 12179
vendor: 4,941 bytes, lines 12180-12391
12180 /** 12181 * Intersects this ray with the given plane, returning the intersection 12182 * point or `null` if there is no intersection. 12183 * 12184 * @param {Plane} plane - The plane to intersect. 12185 * @param {Vector3} target - The target vector that is used to store the method's result. 12186 * @return {?Vector3} The intersection point. 12187 */ 12188 intersectPlane( plane, target ) { 12189 12190 const t = this.distanceToPlane( plane ); 12191 12192 if ( t === null ) { 12193 12194 return null; 12195 12196 } 12197 12198 return this.at( t, target ); 12199 12200 } 12201 12202 /** 12203 * Returns `true` if this ray intersects with the given plane. 12204 * 12205 * @param {Plane} plane - The plane to intersect. 12206 * @return {boolean} Whether this ray intersects with the given plane or not. 12207 */ 12208 intersectsPlane( plane ) { 12209 12210 // check if the ray lies on the plane first 12211 12212 const distToPoint = plane.distanceToPoint( this.origin ); 12213 12214 if ( distToPoint === 0 ) { 12215 12216 return true; 12217 12218 } 12219 12220 const denominator = plane.normal.dot( this.direction ); 12221 12222 if ( denominator * distToPoint < 0 ) { 12223 12224 return true; 12225 12226 } 12227 12228 // ray origin is behind the plane (and is pointing behind it) 12229 12230 return false; 12231 12232 } 12233 12234 /** 12235 * Intersects this ray with the given bounding box, returning the intersection 12236 * point or `null` if there is no intersection. 12237 * 12238 * @param {Box3} box - The box to intersect. 12239 * @param {Vector3} target - The target vector that is used to store the method's result. 12240 * @return {?Vector3} The intersection point. 12241 */ 12242 intersectBox( box, target ) { 12243 12244 let tmin, tmax, tymin, tymax, tzmin, tzmax; 12245 12246 const invdirx = 1 / this.direction.x, 12247 invdiry = 1 / this.direction.y, 12248 invdirz = 1 / this.direction.z; 12249 12250 const origin = this.origin; 12251 12252 if ( invdirx >= 0 ) { 12253 12254 tmin = ( box.min.x - origin.x ) * invdirx; 12255 tmax = ( box.max.x - origin.x ) * invdirx; 12256 12257 } else { 12258 12259 tmin = ( box.max.x - origin.x ) * invdirx; 12260 tmax = ( box.min.x - origin.x ) * invdirx; 12261 12262 } 12263 12264 if ( invdiry >= 0 ) { 12265 12266 tymin = ( box.min.y - origin.y ) * invdiry; 12267 tymax = ( box.max.y - origin.y ) * invdiry; 12268 12269 } else { 12270 12271 tymin = ( box.max.y - origin.y ) * invdiry; 12272 tymax = ( box.min.y - origin.y ) * invdiry; 12273 12274 } 12275 12276 if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; 12277 12278 if ( tymin > tmin || isNaN( tmin ) ) tmin = tymin; 12279 12280 if ( tymax < tmax || isNaN( tmax ) ) tmax = tymax; 12281 12282 if ( invdirz >= 0 ) { 12283 12284 tzmin = ( box.min.z - origin.z ) * invdirz; 12285 tzmax = ( box.max.z - origin.z ) * invdirz; 12286 12287 } else { 12288 12289 tzmin = ( box.max.z - origin.z ) * invdirz; 12290 tzmax = ( box.min.z - origin.z ) * invdirz; 12291 12292 } 12293 12294 if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; 12295 12296 if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; 12297 12298 if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; 12299 12300 //return point closest to the ray (positive side) 12301 12302 if ( tmax < 0 ) return null; 12303 12304 return this.at( tmin >= 0 ? tmin : tmax, target ); 12305 12306 } 12307 12308 /** 12309 * Returns `true` if this ray intersects with the given box. 12310 * 12311 * @param {Box3} box - The box to intersect. 12312 * @return {boolean} Whether this ray intersects with the given box or not. 12313 */ 12314 intersectsBox( box ) { 12315 12316 return this.intersectBox( box, _vector$a ) !== null; 12317 12318 } 12319 12320 /** 12321 * Intersects this ray with the given triangle, returning the intersection 12322 * point or `null` if there is no intersection. 12323 * 12324 * @param {Vector3} a - The first vertex of the triangle. 12325 * @param {Vector3} b - The second vertex of the triangle. 12326 * @param {Vector3} c - The third vertex of the triangle. 12327 * @param {boolean} backfaceCulling - Whether to use backface culling or not. 12328 * @param {Vector3} target - The target vector that is used to store the method's result. 12329 * @return {?Vector3} The intersection point. 12330 */ 12331 intersectTriangle( a, b, c, backfaceCulling, target ) { 12332 12333 // Compute the offset origin, edges, and normal. 12334 12335 // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h 12336 12337 _edge1.subVectors( b, a ); 12338 _edge2.subVectors( c, a ); 12339 _normal$1.crossVectors( _edge1, _edge2 ); 12340 12341 // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, 12342 // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by 12343 // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) 12344 // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) 12345 // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) 12346 let DdN = this.direction.dot( _normal$1 ); 12347 let sign; 12348 12349 if ( DdN > 0 ) { 12350 12351 if ( backfaceCulling ) return null; 12352 sign = 1; 12353 12354 } else if ( DdN < 0 ) { 12355 12356 sign = -1; 12357 DdN = - DdN; 12358 12359 } else { 12360 12361 return null; 12362 12363 } 12364 12365 _diff.subVectors( this.origin, a ); 12366 const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) ); 12367 12368 // b1 < 0, no intersection 12369 if ( DdQxE2 < 0 ) { 12370 12371 return null; 12372 12373 } 12374 12375 const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) ); 12376 12377 // b2 < 0, no intersection 12378 if ( DdE1xQ < 0 ) { 12379 12380 return null; 12381 12382 } 12383 12384 // b1+b2 > 1, no intersection 12385 if ( DdQxE2 + DdE1xQ > DdN ) { 12386 12387 return null; 12388 12389 } 12390 12391 // Line intersects triangle, check if ray does.
vendor: 4,310 bytes, lines 12392-12540
12392 const QdN = - sign * _diff.dot( _normal$1 ); 12393 12394 // t < 0, no intersection 12395 if ( QdN < 0 ) { 12396 12397 return null; 12398 12399 } 12400 12401 // Ray intersects triangle. 12402 return this.at( QdN / DdN, target ); 12403 12404 } 12405 12406 /** 12407 * Transforms this ray with the given 4x4 transformation matrix. 12408 * 12409 * @param {Matrix4} matrix4 - The transformation matrix. 12410 * @return {Ray} A reference to this ray. 12411 */ 12412 applyMatrix4( matrix4 ) { 12413 12414 this.origin.applyMatrix4( matrix4 ); 12415 this.direction.transformDirection( matrix4 ); 12416 12417 return this; 12418 12419 } 12420 12421 /** 12422 * Returns `true` if this ray is equal with the given one. 12423 * 12424 * @param {Ray} ray - The ray to test for equality. 12425 * @return {boolean} Whether this ray is equal with the given one. 12426 */ 12427 equals( ray ) { 12428 12429 return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); 12430 12431 } 12432 12433 /** 12434 * Returns a new ray with copied values from this instance. 12435 * 12436 * @return {Ray} A clone of this instance. 12437 */ 12438 clone() { 12439 12440 return new this.constructor().copy( this ); 12441 12442 } 12443 12444} 12445 12446/** 12447 * Represents a 4x4 matrix. 12448 * 12449 * The most common use of a 4x4 matrix in 3D computer graphics is as a transformation matrix. 12450 * 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} 12451 * 12452 * This allows a 3D vector representing a point in 3D space to undergo 12453 * transformations such as translation, rotation, shear, scale, reflection, 12454 * orthogonal or perspective projection and so on, by being multiplied by the 12455 * matrix. This is known as `applying` the matrix to the vector. 12456 * 12457 * A Note on Row-Major and Column-Major Ordering: 12458 * 12459 * The constructor and {@link Matrix3#set} method take arguments in 12460 * [row-major]{@link https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order} 12461 * order, while internally they are stored in the {@link Matrix3#elements} array in column-major order. 12462 * This means that calling: 12463 * ```js 12464 * const m = new THREE.Matrix4(); 12465 * m.set( 11, 12, 13, 14, 12466 * 21, 22, 23, 24, 12467 * 31, 32, 33, 34, 12468 * 41, 42, 43, 44 ); 12469 * ``` 12470 * will result in the elements array containing: 12471 * ```js 12472 * m.elements = [ 11, 21, 31, 41, 12473 * 12, 22, 32, 42, 12474 * 13, 23, 33, 43, 12475 * 14, 24, 34, 44 ]; 12476 * ``` 12477 * and internally all calculations are performed using column-major ordering. 12478 * However, as the actual ordering makes no difference mathematically and 12479 * most people are used to thinking about matrices in row-major order, the 12480 * three.js documentation shows matrices in row-major order. Just bear in 12481 * mind that if you are reading the source code, you'll have to take the 12482 * transpose of any matrices outlined here to make sense of the calculations. 12483 */ 12484class Matrix4 { 12485 12486 /** 12487 * Constructs a new 4x4 matrix. The arguments are supposed to be 12488 * in row-major order. If no arguments are provided, the constructor 12489 * initializes the matrix as an identity matrix. 12490 * 12491 * @param {number} [n11] - 1-1 matrix element. 12492 * @param {number} [n12] - 1-2 matrix element. 12493 * @param {number} [n13] - 1-3 matrix element. 12494 * @param {number} [n14] - 1-4 matrix element. 12495 * @param {number} [n21] - 2-1 matrix element. 12496 * @param {number} [n22] - 2-2 matrix element. 12497 * @param {number} [n23] - 2-3 matrix element. 12498 * @param {number} [n24] - 2-4 matrix element. 12499 * @param {number} [n31] - 3-1 matrix element. 12500 * @param {number} [n32] - 3-2 matrix element. 12501 * @param {number} [n33] - 3-3 matrix element. 12502 * @param {number} [n34] - 3-4 matrix element. 12503 * @param {number} [n41] - 4-1 matrix element. 12504 * @param {number} [n42] - 4-2 matrix element. 12505 * @param {number} [n43] - 4-3 matrix element. 12506 * @param {number} [n44] - 4-4 matrix element. 12507 */ 12508 constructor( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { 12509 12510 /** 12511 * This flag can be used for type testing. 12512 * 12513 * @type {boolean} 12514 * @readonly 12515 * @default true 12516 */ 12517 Matrix4.prototype.isMatrix4 = true; 12518 12519 /** 12520 * A column-major list of matrix values. 12521 * 12522 * @type {Array<number>} 12523 */ 12524 this.elements = [ 12525 12526 1, 0, 0, 0, 12527 0, 1, 0, 0, 12528 0, 0, 1, 0, 12529 0, 0, 0, 1 12530 12531 ]; 12532 12533 if ( n11 !== undefined ) { 12534 12535 this.set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ); 12536 12537 } 12538 12539 } 12540
vendor: 9,117 bytes, lines 12541-12951
12541 /** 12542 * Sets the elements of the matrix.The arguments are supposed to be 12543 * in row-major order. 12544 * 12545 * @param {number} [n11] - 1-1 matrix element. 12546 * @param {number} [n12] - 1-2 matrix element. 12547 * @param {number} [n13] - 1-3 matrix element. 12548 * @param {number} [n14] - 1-4 matrix element. 12549 * @param {number} [n21] - 2-1 matrix element. 12550 * @param {number} [n22] - 2-2 matrix element. 12551 * @param {number} [n23] - 2-3 matrix element. 12552 * @param {number} [n24] - 2-4 matrix element. 12553 * @param {number} [n31] - 3-1 matrix element. 12554 * @param {number} [n32] - 3-2 matrix element. 12555 * @param {number} [n33] - 3-3 matrix element. 12556 * @param {number} [n34] - 3-4 matrix element. 12557 * @param {number} [n41] - 4-1 matrix element. 12558 * @param {number} [n42] - 4-2 matrix element. 12559 * @param {number} [n43] - 4-3 matrix element. 12560 * @param {number} [n44] - 4-4 matrix element. 12561 * @return {Matrix4} A reference to this matrix. 12562 */ 12563 set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { 12564 12565 const te = this.elements; 12566 12567 te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; 12568 te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; 12569 te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; 12570 te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; 12571 12572 return this; 12573 12574 } 12575 12576 /** 12577 * Sets this matrix to the 4x4 identity matrix. 12578 * 12579 * @return {Matrix4} A reference to this matrix. 12580 */ 12581 identity() { 12582 12583 this.set( 12584 12585 1, 0, 0, 0, 12586 0, 1, 0, 0, 12587 0, 0, 1, 0, 12588 0, 0, 0, 1 12589 12590 ); 12591 12592 return this; 12593 12594 } 12595 12596 /** 12597 * Returns a matrix with copied values from this instance. 12598 * 12599 * @return {Matrix4} A clone of this instance. 12600 */ 12601 clone() { 12602 12603 return new Matrix4().fromArray( this.elements ); 12604 12605 } 12606 12607 /** 12608 * Copies the values of the given matrix to this instance. 12609 * 12610 * @param {Matrix4} m - The matrix to copy. 12611 * @return {Matrix4} A reference to this matrix. 12612 */ 12613 copy( m ) { 12614 12615 const te = this.elements; 12616 const me = m.elements; 12617 12618 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ]; 12619 te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; 12620 te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ]; 12621 te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ]; 12622 12623 return this; 12624 12625 } 12626 12627 /** 12628 * Copies the translation component of the given matrix 12629 * into this matrix's translation component. 12630 * 12631 * @param {Matrix4} m - The matrix to copy the translation component. 12632 * @return {Matrix4} A reference to this matrix. 12633 */ 12634 copyPosition( m ) { 12635 12636 const te = this.elements, me = m.elements; 12637 12638 te[ 12 ] = me[ 12 ]; 12639 te[ 13 ] = me[ 13 ]; 12640 te[ 14 ] = me[ 14 ]; 12641 12642 return this; 12643 12644 } 12645 12646 /** 12647 * Set the upper 3x3 elements of this matrix to the values of given 3x3 matrix. 12648 * 12649 * @param {Matrix3} m - The 3x3 matrix. 12650 * @return {Matrix4} A reference to this matrix. 12651 */ 12652 setFromMatrix3( m ) { 12653 12654 const me = m.elements; 12655 12656 this.set( 12657 12658 me[ 0 ], me[ 3 ], me[ 6 ], 0, 12659 me[ 1 ], me[ 4 ], me[ 7 ], 0, 12660 me[ 2 ], me[ 5 ], me[ 8 ], 0, 12661 0, 0, 0, 1 12662 12663 ); 12664 12665 return this; 12666 12667 } 12668 12669 /** 12670 * Extracts the basis of this matrix into the three axis vectors provided. 12671 * 12672 * @param {Vector3} xAxis - The basis's x axis. 12673 * @param {Vector3} yAxis - The basis's y axis. 12674 * @param {Vector3} zAxis - The basis's z axis. 12675 * @return {Matrix4} A reference to this matrix. 12676 */ 12677 extractBasis( xAxis, yAxis, zAxis ) { 12678 12679 xAxis.setFromMatrixColumn( this, 0 ); 12680 yAxis.setFromMatrixColumn( this, 1 ); 12681 zAxis.setFromMatrixColumn( this, 2 ); 12682 12683 return this; 12684 12685 } 12686 12687 /** 12688 * Sets the given basis vectors to this matrix. 12689 * 12690 * @param {Vector3} xAxis - The basis's x axis. 12691 * @param {Vector3} yAxis - The basis's y axis. 12692 * @param {Vector3} zAxis - The basis's z axis. 12693 * @return {Matrix4} A reference to this matrix. 12694 */ 12695 makeBasis( xAxis, yAxis, zAxis ) { 12696 12697 this.set( 12698 xAxis.x, yAxis.x, zAxis.x, 0, 12699 xAxis.y, yAxis.y, zAxis.y, 0, 12700 xAxis.z, yAxis.z, zAxis.z, 0, 12701 0, 0, 0, 1 12702 ); 12703 12704 return this; 12705 12706 } 12707 12708 /** 12709 * Extracts the rotation component of the given matrix 12710 * into this matrix's rotation component. 12711 * 12712 * Note: This method does not support reflection matrices. 12713 * 12714 * @param {Matrix4} m - The matrix. 12715 * @return {Matrix4} A reference to this matrix. 12716 */ 12717 extractRotation( m ) { 12718 12719 const te = this.elements; 12720 const me = m.elements; 12721 12722 const scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length(); 12723 const scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length(); 12724 const scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length(); 12725 12726 te[ 0 ] = me[ 0 ] * scaleX; 12727 te[ 1 ] = me[ 1 ] * scaleX; 12728 te[ 2 ] = me[ 2 ] * scaleX; 12729 te[ 3 ] = 0; 12730 12731 te[ 4 ] = me[ 4 ] * scaleY; 12732 te[ 5 ] = me[ 5 ] * scaleY; 12733 te[ 6 ] = me[ 6 ] * scaleY; 12734 te[ 7 ] = 0; 12735 12736 te[ 8 ] = me[ 8 ] * scaleZ; 12737 te[ 9 ] = me[ 9 ] * scaleZ; 12738 te[ 10 ] = me[ 10 ] * scaleZ; 12739 te[ 11 ] = 0; 12740 12741 te[ 12 ] = 0; 12742 te[ 13 ] = 0; 12743 te[ 14 ] = 0; 12744 te[ 15 ] = 1; 12745 12746 return this; 12747 12748 } 12749 12750 /** 12751 * Sets the rotation component (the upper left 3x3 matrix) of this matrix to 12752 * the rotation specified by the given Euler angles. The rest of 12753 * the matrix is set to the identity. Depending on the {@link Euler#order}, 12754 * there are six possible outcomes. See [this page]{@link https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix} 12755 * for a complete list. 12756 * 12757 * @param {Euler} euler - The Euler angles. 12758 * @return {Matrix4} A reference to this matrix. 12759 */ 12760 makeRotationFromEuler( euler ) { 12761 12762 const te = this.elements; 12763 12764 const x = euler.x, y = euler.y, z = euler.z; 12765 const a = Math.cos( x ), b = Math.sin( x ); 12766 const c = Math.cos( y ), d = Math.sin( y ); 12767 const e = Math.cos( z ), f = Math.sin( z ); 12768 12769 if ( euler.order === 'XYZ' ) { 12770 12771 const ae = a * e, af = a * f, be = b * e, bf = b * f; 12772 12773 te[ 0 ] = c * e; 12774 te[ 4 ] = - c * f; 12775 te[ 8 ] = d; 12776 12777 te[ 1 ] = af + be * d; 12778 te[ 5 ] = ae - bf * d; 12779 te[ 9 ] = - b * c; 12780 12781 te[ 2 ] = bf - ae * d; 12782 te[ 6 ] = be + af * d; 12783 te[ 10 ] = a * c; 12784 12785 } else if ( euler.order === 'YXZ' ) { 12786 12787 const ce = c * e, cf = c * f, de = d * e, df = d * f; 12788 12789 te[ 0 ] = ce + df * b; 12790 te[ 4 ] = de * b - cf; 12791 te[ 8 ] = a * d; 12792 12793 te[ 1 ] = a * f; 12794 te[ 5 ] = a * e; 12795 te[ 9 ] = - b; 12796 12797 te[ 2 ] = cf * b - de; 12798 te[ 6 ] = df + ce * b; 12799 te[ 10 ] = a * c; 12800 12801 } else if ( euler.order === 'ZXY' ) { 12802 12803 const ce = c * e, cf = c * f, de = d * e, df = d * f; 12804 12805 te[ 0 ] = ce - df * b; 12806 te[ 4 ] = - a * f; 12807 te[ 8 ] = de + cf * b; 12808 12809 te[ 1 ] = cf + de * b; 12810 te[ 5 ] = a * e; 12811 te[ 9 ] = df - ce * b; 12812 12813 te[ 2 ] = - a * d; 12814 te[ 6 ] = b; 12815 te[ 10 ] = a * c; 12816 12817 } else if ( euler.order === 'ZYX' ) { 12818 12819 const ae = a * e, af = a * f, be = b * e, bf = b * f; 12820 12821 te[ 0 ] = c * e; 12822 te[ 4 ] = be * d - af; 12823 te[ 8 ] = ae * d + bf; 12824 12825 te[ 1 ] = c * f; 12826 te[ 5 ] = bf * d + ae; 12827 te[ 9 ] = af * d - be; 12828 12829 te[ 2 ] = - d; 12830 te[ 6 ] = b * c; 12831 te[ 10 ] = a * c; 12832 12833 } else if ( euler.order === 'YZX' ) { 12834 12835 const ac = a * c, ad = a * d, bc = b * c, bd = b * d; 12836 12837 te[ 0 ] = c * e; 12838 te[ 4 ] = bd - ac * f; 12839 te[ 8 ] = bc * f + ad; 12840 12841 te[ 1 ] = f; 12842 te[ 5 ] = a * e; 12843 te[ 9 ] = - b * e; 12844 12845 te[ 2 ] = - d * e; 12846 te[ 6 ] = ad * f + bc; 12847 te[ 10 ] = ac - bd * f; 12848 12849 } else if ( euler.order === 'XZY' ) { 12850 12851 const ac = a * c, ad = a * d, bc = b * c, bd = b * d; 12852 12853 te[ 0 ] = c * e; 12854 te[ 4 ] = - f; 12855 te[ 8 ] = d * e; 12856 12857 te[ 1 ] = ac * f + bd; 12858 te[ 5 ] = a * e; 12859 te[ 9 ] = ad * f - bc; 12860 12861 te[ 2 ] = bc * f - ad; 12862 te[ 6 ] = b * e; 12863 te[ 10 ] = bd * f + ac; 12864 12865 } 12866 12867 // bottom row 12868 te[ 3 ] = 0; 12869 te[ 7 ] = 0; 12870 te[ 11 ] = 0; 12871 12872 // last column 12873 te[ 12 ] = 0; 12874 te[ 13 ] = 0; 12875 te[ 14 ] = 0; 12876 te[ 15 ] = 1; 12877 12878 return this; 12879 12880 } 12881 12882 /** 12883 * Sets the rotation component of this matrix to the rotation specified by 12884 * the given Quaternion as outlined [here]{@link https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion} 12885 * The rest of the matrix is set to the identity. 12886 * 12887 * @param {Quaternion} q - The Quaternion. 12888 * @return {Matrix4} A reference to this matrix. 12889 */ 12890 makeRotationFromQuaternion( q ) { 12891 12892 return this.compose( _zero, q, _one ); 12893 12894 } 12895 12896 /** 12897 * Sets the rotation component of the transformation matrix, looking from `eye` towards 12898 * `target`, and oriented by the up-direction. 12899 * 12900 * @param {Vector3} eye - The eye vector. 12901 * @param {Vector3} target - The target vector. 12902 * @param {Vector3} up - The up vector. 12903 * @return {Matrix4} A reference to this matrix. 12904 */ 12905 lookAt( eye, target, up ) { 12906 12907 const te = this.elements; 12908 12909 _z.subVectors( eye, target ); 12910 12911 if ( _z.lengthSq() === 0 ) { 12912 12913 // eye and target are in the same position 12914 12915 _z.z = 1; 12916 12917 } 12918 12919 _z.normalize(); 12920 _x.crossVectors( up, _z ); 12921 12922 if ( _x.lengthSq() === 0 ) { 12923 12924 // up and z are parallel 12925 12926 if ( Math.abs( up.z ) === 1 ) { 12927 12928 _z.x += 0.0001; 12929 12930 } else { 12931 12932 _z.z += 0.0001; 12933 12934 } 12935 12936 _z.normalize(); 12937 _x.crossVectors( up, _z ); 12938 12939 } 12940 12941 _x.normalize(); 12942 _y.crossVectors( _z, _x ); 12943 12944 te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x; 12945 te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y; 12946 te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z; 12947 12948 return this; 12949 12950 } 12951
vendor: 4,574 bytes, lines 12952-13120
12952 /** 12953 * Post-multiplies this matrix by the given 4x4 matrix. 12954 * 12955 * @param {Matrix4} m - The matrix to multiply with. 12956 * @return {Matrix4} A reference to this matrix. 12957 */ 12958 multiply( m ) { 12959 12960 return this.multiplyMatrices( this, m ); 12961 12962 } 12963 12964 /** 12965 * Pre-multiplies this matrix by the given 4x4 matrix. 12966 * 12967 * @param {Matrix4} m - The matrix to multiply with. 12968 * @return {Matrix4} A reference to this matrix. 12969 */ 12970 premultiply( m ) { 12971 12972 return this.multiplyMatrices( m, this ); 12973 12974 } 12975 12976 /** 12977 * Multiples the given 4x4 matrices and stores the result 12978 * in this matrix. 12979 * 12980 * @param {Matrix4} a - The first matrix. 12981 * @param {Matrix4} b - The second matrix. 12982 * @return {Matrix4} A reference to this matrix. 12983 */ 12984 multiplyMatrices( a, b ) { 12985 12986 const ae = a.elements; 12987 const be = b.elements; 12988 const te = this.elements; 12989 12990 const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; 12991 const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; 12992 const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; 12993 const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; 12994 12995 const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; 12996 const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; 12997 const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; 12998 const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; 12999 13000 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; 13001 te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; 13002 te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; 13003 te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; 13004 13005 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; 13006 te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; 13007 te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; 13008 te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; 13009 13010 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; 13011 te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; 13012 te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; 13013 te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; 13014 13015 te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; 13016 te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; 13017 te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; 13018 te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; 13019 13020 return this; 13021 13022 } 13023 13024 /** 13025 * Multiplies every component of the matrix by the given scalar. 13026 * 13027 * @param {number} s - The scalar. 13028 * @return {Matrix4} A reference to this matrix. 13029 */ 13030 multiplyScalar( s ) { 13031 13032 const te = this.elements; 13033 13034 te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s; 13035 te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s; 13036 te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s; 13037 te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s; 13038 13039 return this; 13040 13041 } 13042 13043 /** 13044 * Computes and returns the determinant of this matrix. 13045 * 13046 * Based on the method outlined [here]{@link http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.html}. 13047 * 13048 * @return {number} The determinant. 13049 */ 13050 determinant() { 13051 13052 const te = this.elements; 13053 13054 const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; 13055 const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; 13056 const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; 13057 const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; 13058 13059 //TODO: make this more efficient 13060 13061 return ( 13062 n41 * ( 13063 + n14 * n23 * n32 13064 - n13 * n24 * n32 13065 - n14 * n22 * n33 13066 + n12 * n24 * n33 13067 + n13 * n22 * n34 13068 - n12 * n23 * n34 13069 ) + 13070 n42 * ( 13071 + n11 * n23 * n34 13072 - n11 * n24 * n33 13073 + n14 * n21 * n33 13074 - n13 * n21 * n34 13075 + n13 * n24 * n31 13076 - n14 * n23 * n31 13077 ) + 13078 n43 * ( 13079 + n11 * n24 * n32 13080 - n11 * n22 * n34 13081 - n14 * n21 * n32 13082 + n12 * n21 * n34 13083 + n14 * n22 * n31 13084 - n12 * n24 * n31 13085 ) + 13086 n44 * ( 13087 - n13 * n22 * n31 13088 - n11 * n23 * n32 13089 + n11 * n22 * n33 13090 + n13 * n21 * n32 13091 - n12 * n21 * n33 13092 + n12 * n23 * n31 13093 ) 13094 13095 ); 13096 13097 } 13098 13099 /** 13100 * Transposes this matrix in place. 13101 * 13102 * @return {Matrix4} A reference to this matrix. 13103 */ 13104 transpose() { 13105 13106 const te = this.elements; 13107 let tmp; 13108 13109 tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp; 13110 tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp; 13111 tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp; 13112 13113 tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp; 13114 tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp; 13115 tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp; 13116 13117 return this; 13118 13119 } 13120
vendor: 4,133 bytes, lines 13121-13223
13121 /** 13122 * Sets the position component for this matrix from the given vector, 13123 * without affecting the rest of the matrix. 13124 * 13125 * @param {number|Vector3} x - The x component of the vector or alternatively the vector object. 13126 * @param {number} y - The y component of the vector. 13127 * @param {number} z - The z component of the vector. 13128 * @return {Matrix4} A reference to this matrix. 13129 */ 13130 setPosition( x, y, z ) { 13131 13132 const te = this.elements; 13133 13134 if ( x.isVector3 ) { 13135 13136 te[ 12 ] = x.x; 13137 te[ 13 ] = x.y; 13138 te[ 14 ] = x.z; 13139 13140 } else { 13141 13142 te[ 12 ] = x; 13143 te[ 13 ] = y; 13144 te[ 14 ] = z; 13145 13146 } 13147 13148 return this; 13149 13150 } 13151 13152 /** 13153 * Inverts this matrix, using the [analytic method]{@link https://en.wikipedia.org/wiki/Invertible_matrix#Analytic_solution}. 13154 * You can not invert with a determinant of zero. If you attempt this, the method produces 13155 * a zero matrix instead. 13156 * 13157 * @return {Matrix4} A reference to this matrix. 13158 */ 13159 invert() { 13160 13161 // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm 13162 const te = this.elements, 13163 13164 n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ], 13165 n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ], 13166 n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ], 13167 n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ], 13168 13169 t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44, 13170 t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44, 13171 t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44, 13172 t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; 13173 13174 const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; 13175 13176 if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); 13177 13178 const detInv = 1 / det; 13179 13180 te[ 0 ] = t11 * detInv; 13181 te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv; 13182 te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv; 13183 te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv; 13184 13185 te[ 4 ] = t12 * detInv; 13186 te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv; 13187 te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv; 13188 te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv; 13189 13190 te[ 8 ] = t13 * detInv; 13191 te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv; 13192 te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv; 13193 te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv; 13194 13195 te[ 12 ] = t14 * detInv; 13196 te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv; 13197 te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv; 13198 te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv; 13199 13200 return this; 13201 13202 } 13203 13204 /** 13205 * Multiplies the columns of this matrix by the given vector. 13206 * 13207 * @param {Vector3} v - The scale vector. 13208 * @return {Matrix4} A reference to this matrix. 13209 */ 13210 scale( v ) { 13211 13212 const te = this.elements; 13213 const x = v.x, y = v.y, z = v.z; 13214 13215 te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; 13216 te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; 13217 te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; 13218 te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; 13219 13220 return this; 13221 13222 } 13223
vendor: 4,266 bytes, lines 13224-13433
13224 /** 13225 * Gets the maximum scale value of the three axes. 13226 * 13227 * @return {number} The maximum scale. 13228 */ 13229 getMaxScaleOnAxis() { 13230 13231 const te = this.elements; 13232 13233 const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; 13234 const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; 13235 const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; 13236 13237 return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); 13238 13239 } 13240 13241 /** 13242 * Sets this matrix as a translation transform from the given vector. 13243 * 13244 * @param {number|Vector3} x - The amount to translate in the X axis or alternatively a translation vector. 13245 * @param {number} y - The amount to translate in the Y axis. 13246 * @param {number} z - The amount to translate in the z axis. 13247 * @return {Matrix4} A reference to this matrix. 13248 */ 13249 makeTranslation( x, y, z ) { 13250 13251 if ( x.isVector3 ) { 13252 13253 this.set( 13254 13255 1, 0, 0, x.x, 13256 0, 1, 0, x.y, 13257 0, 0, 1, x.z, 13258 0, 0, 0, 1 13259 13260 ); 13261 13262 } else { 13263 13264 this.set( 13265 13266 1, 0, 0, x, 13267 0, 1, 0, y, 13268 0, 0, 1, z, 13269 0, 0, 0, 1 13270 13271 ); 13272 13273 } 13274 13275 return this; 13276 13277 } 13278 13279 /** 13280 * Sets this matrix as a rotational transformation around the X axis by 13281 * the given angle. 13282 * 13283 * @param {number} theta - The rotation in radians. 13284 * @return {Matrix4} A reference to this matrix. 13285 */ 13286 makeRotationX( theta ) { 13287 13288 const c = Math.cos( theta ), s = Math.sin( theta ); 13289 13290 this.set( 13291 13292 1, 0, 0, 0, 13293 0, c, - s, 0, 13294 0, s, c, 0, 13295 0, 0, 0, 1 13296 13297 ); 13298 13299 return this; 13300 13301 } 13302 13303 /** 13304 * Sets this matrix as a rotational transformation around the Y axis by 13305 * the given angle. 13306 * 13307 * @param {number} theta - The rotation in radians. 13308 * @return {Matrix4} A reference to this matrix. 13309 */ 13310 makeRotationY( theta ) { 13311 13312 const c = Math.cos( theta ), s = Math.sin( theta ); 13313 13314 this.set( 13315 13316 c, 0, s, 0, 13317 0, 1, 0, 0, 13318 - s, 0, c, 0, 13319 0, 0, 0, 1 13320 13321 ); 13322 13323 return this; 13324 13325 } 13326 13327 /** 13328 * Sets this matrix as a rotational transformation around the Z axis by 13329 * the given angle. 13330 * 13331 * @param {number} theta - The rotation in radians. 13332 * @return {Matrix4} A reference to this matrix. 13333 */ 13334 makeRotationZ( theta ) { 13335 13336 const c = Math.cos( theta ), s = Math.sin( theta ); 13337 13338 this.set( 13339 13340 c, - s, 0, 0, 13341 s, c, 0, 0, 13342 0, 0, 1, 0, 13343 0, 0, 0, 1 13344 13345 ); 13346 13347 return this; 13348 13349 } 13350 13351 /** 13352 * Sets this matrix as a rotational transformation around the given axis by 13353 * the given angle. 13354 * 13355 * This is a somewhat controversial but mathematically sound alternative to 13356 * rotating via Quaternions. See the discussion [here]{@link https://www.gamedev.net/articles/programming/math-and-physics/do-we-really-need-quaternions-r1199}. 13357 * 13358 * @param {Vector3} axis - The normalized rotation axis. 13359 * @param {number} angle - The rotation in radians. 13360 * @return {Matrix4} A reference to this matrix. 13361 */ 13362 makeRotationAxis( axis, angle ) { 13363 13364 // Based on http://www.gamedev.net/reference/articles/article1199.asp 13365 13366 const c = Math.cos( angle ); 13367 const s = Math.sin( angle ); 13368 const t = 1 - c; 13369 const x = axis.x, y = axis.y, z = axis.z; 13370 const tx = t * x, ty = t * y; 13371 13372 this.set( 13373 13374 tx * x + c, tx * y - s * z, tx * z + s * y, 0, 13375 tx * y + s * z, ty * y + c, ty * z - s * x, 0, 13376 tx * z - s * y, ty * z + s * x, t * z * z + c, 0, 13377 0, 0, 0, 1 13378 13379 ); 13380 13381 return this; 13382 13383 } 13384 13385 /** 13386 * Sets this matrix as a scale transformation. 13387 * 13388 * @param {number} x - The amount to scale in the X axis. 13389 * @param {number} y - The amount to scale in the Y axis. 13390 * @param {number} z - The amount to scale in the Z axis. 13391 * @return {Matrix4} A reference to this matrix. 13392 */ 13393 makeScale( x, y, z ) { 13394 13395 this.set( 13396 13397 x, 0, 0, 0, 13398 0, y, 0, 0, 13399 0, 0, z, 0, 13400 0, 0, 0, 1 13401 13402 ); 13403 13404 return this; 13405 13406 } 13407 13408 /** 13409 * Sets this matrix as a shear transformation. 13410 * 13411 * @param {number} xy - The amount to shear X by Y. 13412 * @param {number} xz - The amount to shear X by Z. 13413 * @param {number} yx - The amount to shear Y by X. 13414 * @param {number} yz - The amount to shear Y by Z. 13415 * @param {number} zx - The amount to shear Z by X. 13416 * @param {number} zy - The amount to shear Z by Y. 13417 * @return {Matrix4} A reference to this matrix. 13418 */ 13419 makeShear( xy, xz, yx, yz, zx, zy ) { 13420 13421 this.set( 13422 13423 1, yx, zx, 0, 13424 xy, 1, zy, 0, 13425 xz, yz, 1, 0, 13426 0, 0, 0, 1 13427 13428 ); 13429 13430 return this; 13431 13432 } 13433
vendor: 14,176 bytes, lines 13434-14035
13434 /** 13435 * Sets this matrix to the transformation composed of the given position, 13436 * rotation (Quaternion) and scale. 13437 * 13438 * @param {Vector3} position - The position vector. 13439 * @param {Quaternion} quaternion - The rotation as a Quaternion. 13440 * @param {Vector3} scale - The scale vector. 13441 * @return {Matrix4} A reference to this matrix. 13442 */ 13443 compose( position, quaternion, scale ) { 13444 13445 const te = this.elements; 13446 13447 const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w; 13448 const x2 = x + x, y2 = y + y, z2 = z + z; 13449 const xx = x * x2, xy = x * y2, xz = x * z2; 13450 const yy = y * y2, yz = y * z2, zz = z * z2; 13451 const wx = w * x2, wy = w * y2, wz = w * z2; 13452 13453 const sx = scale.x, sy = scale.y, sz = scale.z; 13454 13455 te[ 0 ] = ( 1 - ( yy + zz ) ) * sx; 13456 te[ 1 ] = ( xy + wz ) * sx; 13457 te[ 2 ] = ( xz - wy ) * sx; 13458 te[ 3 ] = 0; 13459 13460 te[ 4 ] = ( xy - wz ) * sy; 13461 te[ 5 ] = ( 1 - ( xx + zz ) ) * sy; 13462 te[ 6 ] = ( yz + wx ) * sy; 13463 te[ 7 ] = 0; 13464 13465 te[ 8 ] = ( xz + wy ) * sz; 13466 te[ 9 ] = ( yz - wx ) * sz; 13467 te[ 10 ] = ( 1 - ( xx + yy ) ) * sz; 13468 te[ 11 ] = 0; 13469 13470 te[ 12 ] = position.x; 13471 te[ 13 ] = position.y; 13472 te[ 14 ] = position.z; 13473 te[ 15 ] = 1; 13474 13475 return this; 13476 13477 } 13478 13479 /** 13480 * Decomposes this matrix into its position, rotation and scale components 13481 * and provides the result in the given objects. 13482 * 13483 * Note: Not all matrices are decomposable in this way. For example, if an 13484 * object has a non-uniformly scaled parent, then the object's world matrix 13485 * may not be decomposable, and this method may not be appropriate. 13486 * 13487 * @param {Vector3} position - The position vector. 13488 * @param {Quaternion} quaternion - The rotation as a Quaternion. 13489 * @param {Vector3} scale - The scale vector. 13490 * @return {Matrix4} A reference to this matrix. 13491 */ 13492 decompose( position, quaternion, scale ) { 13493 13494 const te = this.elements; 13495 13496 let sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); 13497 const sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); 13498 const sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); 13499 13500 // if determine is negative, we need to invert one scale 13501 const det = this.determinant(); 13502 if ( det < 0 ) sx = - sx; 13503 13504 position.x = te[ 12 ]; 13505 position.y = te[ 13 ]; 13506 position.z = te[ 14 ]; 13507 13508 // scale the rotation part 13509 _m1$2.copy( this ); 13510 13511 const invSX = 1 / sx; 13512 const invSY = 1 / sy; 13513 const invSZ = 1 / sz; 13514 13515 _m1$2.elements[ 0 ] *= invSX; 13516 _m1$2.elements[ 1 ] *= invSX; 13517 _m1$2.elements[ 2 ] *= invSX; 13518 13519 _m1$2.elements[ 4 ] *= invSY; 13520 _m1$2.elements[ 5 ] *= invSY; 13521 _m1$2.elements[ 6 ] *= invSY; 13522 13523 _m1$2.elements[ 8 ] *= invSZ; 13524 _m1$2.elements[ 9 ] *= invSZ; 13525 _m1$2.elements[ 10 ] *= invSZ; 13526 13527 quaternion.setFromRotationMatrix( _m1$2 ); 13528 13529 scale.x = sx; 13530 scale.y = sy; 13531 scale.z = sz; 13532 13533 return this; 13534 13535 } 13536 13537 /** 13538 * Creates a perspective projection matrix. This is used internally by 13539 * {@link PerspectiveCamera#updateProjectionMatrix}. 13540 13541 * @param {number} left - Left boundary of the viewing frustum at the near plane. 13542 * @param {number} right - Right boundary of the viewing frustum at the near plane. 13543 * @param {number} top - Top boundary of the viewing frustum at the near plane. 13544 * @param {number} bottom - Bottom boundary of the viewing frustum at the near plane. 13545 * @param {number} near - The distance from the camera to the near plane. 13546 * @param {number} far - The distance from the camera to the far plane. 13547 * @param {(WebGLCoordinateSystem|WebGPUCoordinateSystem)} [coordinateSystem=WebGLCoordinateSystem] - The coordinate system. 13548 * @return {Matrix4} A reference to this matrix. 13549 */ 13550 makePerspective( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) { 13551 13552 const te = this.elements; 13553 const x = 2 * near / ( right - left ); 13554 const y = 2 * near / ( top - bottom ); 13555 13556 const a = ( right + left ) / ( right - left ); 13557 const b = ( top + bottom ) / ( top - bottom ); 13558 13559 let c, d; 13560 13561 if ( coordinateSystem === WebGLCoordinateSystem ) { 13562 13563 c = - ( far + near ) / ( far - near ); 13564 d = ( -2 * far * near ) / ( far - near ); 13565 13566 } else if ( coordinateSystem === WebGPUCoordinateSystem ) { 13567 13568 c = - far / ( far - near ); 13569 d = ( - far * near ) / ( far - near ); 13570 13571 } else { 13572 13573 throw new Error( 'THREE.Matrix4.makePerspective(): Invalid coordinate system: ' + coordinateSystem ); 13574 13575 } 13576 13577 te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; 13578 te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; 13579 te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; 13580 te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = -1; te[ 15 ] = 0; 13581 13582 return this; 13583 13584 } 13585 13586 /** 13587 * Creates a orthographic projection matrix. This is used internally by 13588 * {@link OrthographicCamera#updateProjectionMatrix}. 13589 13590 * @param {number} left - Left boundary of the viewing frustum at the near plane. 13591 * @param {number} right - Right boundary of the viewing frustum at the near plane. 13592 * @param {number} top - Top boundary of the viewing frustum at the near plane. 13593 * @param {number} bottom - Bottom boundary of the viewing frustum at the near plane. 13594 * @param {number} near - The distance from the camera to the near plane. 13595 * @param {number} far - The distance from the camera to the far plane. 13596 * @param {(WebGLCoordinateSystem|WebGPUCoordinateSystem)} [coordinateSystem=WebGLCoordinateSystem] - The coordinate system. 13597 * @return {Matrix4} A reference to this matrix. 13598 */ 13599 makeOrthographic( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) { 13600 13601 const te = this.elements; 13602 const w = 1.0 / ( right - left ); 13603 const h = 1.0 / ( top - bottom ); 13604 const p = 1.0 / ( far - near ); 13605 13606 const x = ( right + left ) * w; 13607 const y = ( top + bottom ) * h; 13608 13609 let z, zInv; 13610 13611 if ( coordinateSystem === WebGLCoordinateSystem ) { 13612 13613 z = ( far + near ) * p; 13614 zInv = -2 * p; 13615 13616 } else if ( coordinateSystem === WebGPUCoordinateSystem ) { 13617 13618 z = near * p; 13619 zInv = -1 * p; 13620 13621 } else { 13622 13623 throw new Error( 'THREE.Matrix4.makeOrthographic(): Invalid coordinate system: ' + coordinateSystem ); 13624 13625 } 13626 13627 te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x; 13628 te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y; 13629 te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = zInv; te[ 14 ] = - z; 13630 te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; 13631 13632 return this; 13633 13634 } 13635 13636 /** 13637 * Returns `true` if this matrix is equal with the given one. 13638 * 13639 * @param {Matrix4} matrix - The matrix to test for equality. 13640 * @return {boolean} Whether this matrix is equal with the given one. 13641 */ 13642 equals( matrix ) { 13643 13644 const te = this.elements; 13645 const me = matrix.elements; 13646 13647 for ( let i = 0; i < 16; i ++ ) { 13648 13649 if ( te[ i ] !== me[ i ] ) return false; 13650 13651 } 13652 13653 return true; 13654 13655 } 13656 13657 /** 13658 * Sets the elements of the matrix from the given array. 13659 * 13660 * @param {Array<number>} array - The matrix elements in column-major order. 13661 * @param {number} [offset=0] - Index of the first element in the array. 13662 * @return {Matrix4} A reference to this matrix. 13663 */ 13664 fromArray( array, offset = 0 ) { 13665 13666 for ( let i = 0; i < 16; i ++ ) { 13667 13668 this.elements[ i ] = array[ i + offset ]; 13669 13670 } 13671 13672 return this; 13673 13674 } 13675 13676 /** 13677 * Writes the elements of this matrix to the given array. If no array is provided, 13678 * the method returns a new instance. 13679 * 13680 * @param {Array<number>} [array=[]] - The target array holding the matrix elements in column-major order. 13681 * @param {number} [offset=0] - Index of the first element in the array. 13682 * @return {Array<number>} The matrix elements in column-major order. 13683 */ 13684 toArray( array = [], offset = 0 ) { 13685 13686 const te = this.elements; 13687 13688 array[ offset ] = te[ 0 ]; 13689 array[ offset + 1 ] = te[ 1 ]; 13690 array[ offset + 2 ] = te[ 2 ]; 13691 array[ offset + 3 ] = te[ 3 ]; 13692 13693 array[ offset + 4 ] = te[ 4 ]; 13694 array[ offset + 5 ] = te[ 5 ]; 13695 array[ offset + 6 ] = te[ 6 ]; 13696 array[ offset + 7 ] = te[ 7 ]; 13697 13698 array[ offset + 8 ] = te[ 8 ]; 13699 array[ offset + 9 ] = te[ 9 ]; 13700 array[ offset + 10 ] = te[ 10 ]; 13701 array[ offset + 11 ] = te[ 11 ]; 13702 13703 array[ offset + 12 ] = te[ 12 ]; 13704 array[ offset + 13 ] = te[ 13 ]; 13705 array[ offset + 14 ] = te[ 14 ]; 13706 array[ offset + 15 ] = te[ 15 ]; 13707 13708 return array; 13709 13710 } 13711 13712} 13713 13714const _v1$5 = /*@__PURE__*/ new Vector3(); 13715const _m1$2 = /*@__PURE__*/ new Matrix4(); 13716const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 ); 13717const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 ); 13718const _x = /*@__PURE__*/ new Vector3(); 13719const _y = /*@__PURE__*/ new Vector3(); 13720const _z = /*@__PURE__*/ new Vector3(); 13721 13722const _matrix$2 = /*@__PURE__*/ new Matrix4(); 13723const _quaternion$3 = /*@__PURE__*/ new Quaternion(); 13724 13725/** 13726 * A class representing Euler angles. 13727 * 13728 * Euler angles describe a rotational transformation by rotating an object on 13729 * its various axes in specified amounts per axis, and a specified axis 13730 * order. 13731 * 13732 * Iterating through an instance will yield its components (x, y, z, 13733 * order) in the corresponding order. 13734 * 13735 * ```js 13736 * const a = new THREE.Euler( 0, 1, 1.57, 'XYZ' ); 13737 * const b = new THREE.Vector3( 1, 0, 1 ); 13738 * b.applyEuler(a); 13739 * ``` 13740 */ 13741class Euler { 13742 13743 /** 13744 * Constructs a new euler instance. 13745 * 13746 * @param {number} [x=0] - The angle of the x axis in radians. 13747 * @param {number} [y=0] - The angle of the y axis in radians. 13748 * @param {number} [z=0] - The angle of the z axis in radians. 13749 * @param {string} [order=Euler.DEFAULT_ORDER] - A string representing the order that the rotations are applied. 13750 */ 13751 constructor( x = 0, y = 0, z = 0, order = Euler.DEFAULT_ORDER ) { 13752 13753 /** 13754 * This flag can be used for type testing. 13755 * 13756 * @type {boolean} 13757 * @readonly 13758 * @default true 13759 */ 13760 this.isEuler = true; 13761 13762 this._x = x; 13763 this._y = y; 13764 this._z = z; 13765 this._order = order; 13766 13767 } 13768 13769 /** 13770 * The angle of the x axis in radians. 13771 * 13772 * @type {number} 13773 * @default 0 13774 */ 13775 get x() { 13776 13777 return this._x; 13778 13779 } 13780 13781 set x( value ) { 13782 13783 this._x = value; 13784 this._onChangeCallback(); 13785 13786 } 13787 13788 /** 13789 * The angle of the y axis in radians. 13790 * 13791 * @type {number} 13792 * @default 0 13793 */ 13794 get y() { 13795 13796 return this._y; 13797 13798 } 13799 13800 set y( value ) { 13801 13802 this._y = value; 13803 this._onChangeCallback(); 13804 13805 } 13806 13807 /** 13808 * The angle of the z axis in radians. 13809 * 13810 * @type {number} 13811 * @default 0 13812 */ 13813 get z() { 13814 13815 return this._z; 13816 13817 } 13818 13819 set z( value ) { 13820 13821 this._z = value; 13822 this._onChangeCallback(); 13823 13824 } 13825 13826 /** 13827 * A string representing the order that the rotations are applied. 13828 * 13829 * @type {string} 13830 * @default 'XYZ' 13831 */ 13832 get order() { 13833 13834 return this._order; 13835 13836 } 13837 13838 set order( value ) { 13839 13840 this._order = value; 13841 this._onChangeCallback(); 13842 13843 } 13844 13845 /** 13846 * Sets the Euler components. 13847 * 13848 * @param {number} x - The angle of the x axis in radians. 13849 * @param {number} y - The angle of the y axis in radians. 13850 * @param {number} z - The angle of the z axis in radians. 13851 * @param {string} [order] - A string representing the order that the rotations are applied. 13852 * @return {Euler} A reference to this Euler instance. 13853 */ 13854 set( x, y, z, order = this._order ) { 13855 13856 this._x = x; 13857 this._y = y; 13858 this._z = z; 13859 this._order = order; 13860 13861 this._onChangeCallback(); 13862 13863 return this; 13864 13865 } 13866 13867 /** 13868 * Returns a new Euler instance with copied values from this instance. 13869 * 13870 * @return {Euler} A clone of this instance. 13871 */ 13872 clone() { 13873 13874 return new this.constructor( this._x, this._y, this._z, this._order ); 13875 13876 } 13877 13878 /** 13879 * Copies the values of the given Euler instance to this instance. 13880 * 13881 * @param {Euler} euler - The Euler instance to copy. 13882 * @return {Euler} A reference to this Euler instance. 13883 */ 13884 copy( euler ) { 13885 13886 this._x = euler._x; 13887 this._y = euler._y; 13888 this._z = euler._z; 13889 this._order = euler._order; 13890 13891 this._onChangeCallback(); 13892 13893 return this; 13894 13895 } 13896 13897 /** 13898 * Sets the angles of this Euler instance from a pure rotation matrix. 13899 * 13900 * @param {Matrix4} m - A 4x4 matrix of which the upper 3x3 of matrix is a pure rotation matrix (i.e. unscaled). 13901 * @param {string} [order] - A string representing the order that the rotations are applied. 13902 * @param {boolean} [update=true] - Whether the internal `onChange` callback should be executed or not. 13903 * @return {Euler} A reference to this Euler instance. 13904 */ 13905 setFromRotationMatrix( m, order = this._order, update = true ) { 13906 13907 const te = m.elements; 13908 const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ]; 13909 const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ]; 13910 const m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; 13911 13912 switch ( order ) { 13913 13914 case 'XYZ': 13915 13916 this._y = Math.asin( clamp( m13, -1, 1 ) ); 13917 13918 if ( Math.abs( m13 ) < 0.9999999 ) { 13919 13920 this._x = Math.atan2( - m23, m33 ); 13921 this._z = Math.atan2( - m12, m11 ); 13922 13923 } else { 13924 13925 this._x = Math.atan2( m32, m22 ); 13926 this._z = 0; 13927 13928 } 13929 13930 break; 13931 13932 case 'YXZ': 13933 13934 this._x = Math.asin( - clamp( m23, -1, 1 ) ); 13935 13936 if ( Math.abs( m23 ) < 0.9999999 ) { 13937 13938 this._y = Math.atan2( m13, m33 ); 13939 this._z = Math.atan2( m21, m22 ); 13940 13941 } else { 13942 13943 this._y = Math.atan2( - m31, m11 ); 13944 this._z = 0; 13945 13946 } 13947 13948 break; 13949 13950 case 'ZXY': 13951 13952 this._x = Math.asin( clamp( m32, -1, 1 ) ); 13953 13954 if ( Math.abs( m32 ) < 0.9999999 ) { 13955 13956 this._y = Math.atan2( - m31, m33 ); 13957 this._z = Math.atan2( - m12, m22 ); 13958 13959 } else { 13960 13961 this._y = 0; 13962 this._z = Math.atan2( m21, m11 ); 13963 13964 } 13965 13966 break; 13967 13968 case 'ZYX': 13969 13970 this._y = Math.asin( - clamp( m31, -1, 1 ) ); 13971 13972 if ( Math.abs( m31 ) < 0.9999999 ) { 13973 13974 this._x = Math.atan2( m32, m33 ); 13975 this._z = Math.atan2( m21, m11 ); 13976 13977 } else { 13978 13979 this._x = 0; 13980 this._z = Math.atan2( - m12, m22 ); 13981 13982 } 13983 13984 break; 13985 13986 case 'YZX': 13987 13988 this._z = Math.asin( clamp( m21, -1, 1 ) ); 13989 13990 if ( Math.abs( m21 ) < 0.9999999 ) { 13991 13992 this._x = Math.atan2( - m23, m22 ); 13993 this._y = Math.atan2( - m31, m11 ); 13994 13995 } else { 13996 13997 this._x = 0; 13998 this._y = Math.atan2( m13, m33 ); 13999 14000 } 14001 14002 break; 14003 14004 case 'XZY': 14005 14006 this._z = Math.asin( - clamp( m12, -1, 1 ) ); 14007 14008 if ( Math.abs( m12 ) < 0.9999999 ) { 14009 14010 this._x = Math.atan2( m32, m22 ); 14011 this._y = Math.atan2( m13, m11 ); 14012 14013 } else { 14014 14015 this._x = Math.atan2( - m23, m33 ); 14016 this._y = 0; 14017 14018 } 14019 14020 break; 14021 14022 default: 14023 14024 console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order ); 14025 14026 } 14027 14028 this._order = order; 14029 14030 if ( update === true ) this._onChangeCallback(); 14031 14032 return this; 14033 14034 } 14035
vendor: 11,401 bytes, lines 14036-14545
14036 /** 14037 * Sets the angles of this Euler instance from a normalized quaternion. 14038 * 14039 * @param {Quaternion} q - A normalized Quaternion. 14040 * @param {string} [order] - A string representing the order that the rotations are applied. 14041 * @param {boolean} [update=true] - Whether the internal `onChange` callback should be executed or not. 14042 * @return {Euler} A reference to this Euler instance. 14043 */ 14044 setFromQuaternion( q, order, update ) { 14045 14046 _matrix$2.makeRotationFromQuaternion( q ); 14047 14048 return this.setFromRotationMatrix( _matrix$2, order, update ); 14049 14050 } 14051 14052 /** 14053 * Sets the angles of this Euler instance from the given vector. 14054 * 14055 * @param {Vector3} v - The vector. 14056 * @param {string} [order] - A string representing the order that the rotations are applied. 14057 * @return {Euler} A reference to this Euler instance. 14058 */ 14059 setFromVector3( v, order = this._order ) { 14060 14061 return this.set( v.x, v.y, v.z, order ); 14062 14063 } 14064 14065 /** 14066 * Resets the euler angle with a new order by creating a quaternion from this 14067 * euler angle and then setting this euler angle with the quaternion and the 14068 * new order. 14069 * 14070 * Warning: This discards revolution information. 14071 * 14072 * @param {string} [newOrder] - A string representing the new order that the rotations are applied. 14073 * @return {Euler} A reference to this Euler instance. 14074 */ 14075 reorder( newOrder ) { 14076 14077 _quaternion$3.setFromEuler( this ); 14078 14079 return this.setFromQuaternion( _quaternion$3, newOrder ); 14080 14081 } 14082 14083 /** 14084 * Returns `true` if this Euler instance is equal with the given one. 14085 * 14086 * @param {Euler} euler - The Euler instance to test for equality. 14087 * @return {boolean} Whether this Euler instance is equal with the given one. 14088 */ 14089 equals( euler ) { 14090 14091 return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); 14092 14093 } 14094 14095 /** 14096 * Sets this Euler instance's components to values from the given array. The first three 14097 * entries of the array are assign to the x,y and z components. An optional fourth entry 14098 * defines the Euler order. 14099 * 14100 * @param {Array<number,number,number,?string>} array - An array holding the Euler component values. 14101 * @return {Euler} A reference to this Euler instance. 14102 */ 14103 fromArray( array ) { 14104 14105 this._x = array[ 0 ]; 14106 this._y = array[ 1 ]; 14107 this._z = array[ 2 ]; 14108 if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; 14109 14110 this._onChangeCallback(); 14111 14112 return this; 14113 14114 } 14115 14116 /** 14117 * Writes the components of this Euler instance to the given array. If no array is provided, 14118 * the method returns a new instance. 14119 * 14120 * @param {Array<number,number,number,string>} [array=[]] - The target array holding the Euler components. 14121 * @param {number} [offset=0] - Index of the first element in the array. 14122 * @return {Array<number,number,number,string>} The Euler components. 14123 */ 14124 toArray( array = [], offset = 0 ) { 14125 14126 array[ offset ] = this._x; 14127 array[ offset + 1 ] = this._y; 14128 array[ offset + 2 ] = this._z; 14129 array[ offset + 3 ] = this._order; 14130 14131 return array; 14132 14133 } 14134 14135 _onChange( callback ) { 14136 14137 this._onChangeCallback = callback; 14138 14139 return this; 14140 14141 } 14142 14143 _onChangeCallback() {} 14144 14145 *[ Symbol.iterator ]() { 14146 14147 yield this._x; 14148 yield this._y; 14149 yield this._z; 14150 yield this._order; 14151 14152 } 14153 14154} 14155 14156/** 14157 * The default Euler angle order. 14158 * 14159 * @static 14160 * @type {string} 14161 * @default 'XYZ' 14162 */ 14163Euler.DEFAULT_ORDER = 'XYZ'; 14164 14165/** 14166 * A layers object assigns an 3D object to 1 or more of 32 14167 * layers numbered `0` to `31` - internally the layers are stored as a 14168 * bit mask], and by default all 3D objects are a member of layer `0`. 14169 * 14170 * This can be used to control visibility - an object must share a layer with 14171 * a camera to be visible when that camera's view is 14172 * rendered. 14173 * 14174 * All classes that inherit from {@link Object3D} have an `layers` property which 14175 * is an instance of this class. 14176 */ 14177class Layers { 14178 14179 /** 14180 * Constructs a new layers instance, with membership 14181 * initially set to layer `0`. 14182 */ 14183 constructor() { 14184 14185 /** 14186 * A bit mask storing which of the 32 layers this layers object is currently 14187 * a member of. 14188 * 14189 * @type {number} 14190 */ 14191 this.mask = 1 | 0; 14192 14193 } 14194 14195 /** 14196 * Sets membership to the given layer, and remove membership all other layers. 14197 * 14198 * @param {number} layer - The layer to set. 14199 */ 14200 set( layer ) { 14201 14202 this.mask = ( 1 << layer | 0 ) >>> 0; 14203 14204 } 14205 14206 /** 14207 * Adds membership of the given layer. 14208 * 14209 * @param {number} layer - The layer to enable. 14210 */ 14211 enable( layer ) { 14212 14213 this.mask |= 1 << layer | 0; 14214 14215 } 14216 14217 /** 14218 * Adds membership to all layers. 14219 */ 14220 enableAll() { 14221 14222 this.mask = 0xffffffff | 0; 14223 14224 } 14225 14226 /** 14227 * Toggles the membership of the given layer. 14228 * 14229 * @param {number} layer - The layer to toggle. 14230 */ 14231 toggle( layer ) { 14232 14233 this.mask ^= 1 << layer | 0; 14234 14235 } 14236 14237 /** 14238 * Removes membership of the given layer. 14239 * 14240 * @param {number} layer - The layer to enable. 14241 */ 14242 disable( layer ) { 14243 14244 this.mask &= ~ ( 1 << layer | 0 ); 14245 14246 } 14247 14248 /** 14249 * Removes the membership from all layers. 14250 */ 14251 disableAll() { 14252 14253 this.mask = 0; 14254 14255 } 14256 14257 /** 14258 * Returns `true` if this and the given layers object have at least one 14259 * layer in common. 14260 * 14261 * @param {Layers} layers - The layers to test. 14262 * @return {boolean } Whether this and the given layers object have at least one layer in common or not. 14263 */ 14264 test( layers ) { 14265 14266 return ( this.mask & layers.mask ) !== 0; 14267 14268 } 14269 14270 /** 14271 * Returns `true` if the given layer is enabled. 14272 * 14273 * @param {number} layer - The layer to test. 14274 * @return {boolean } Whether the given layer is enabled or not. 14275 */ 14276 isEnabled( layer ) { 14277 14278 return ( this.mask & ( 1 << layer | 0 ) ) !== 0; 14279 14280 } 14281 14282} 14283 14284let _object3DId = 0; 14285 14286const _v1$4 = /*@__PURE__*/ new Vector3(); 14287const _q1 = /*@__PURE__*/ new Quaternion(); 14288const _m1$1 = /*@__PURE__*/ new Matrix4(); 14289const _target = /*@__PURE__*/ new Vector3(); 14290 14291const _position$3 = /*@__PURE__*/ new Vector3(); 14292const _scale$2 = /*@__PURE__*/ new Vector3(); 14293const _quaternion$2 = /*@__PURE__*/ new Quaternion(); 14294 14295const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 ); 14296const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 ); 14297const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 ); 14298 14299/** 14300 * Fires when the object has been added to its parent object. 14301 * 14302 * @event Object3D#added 14303 * @type {Object} 14304 */ 14305const _addedEvent = { type: 'added' }; 14306 14307/** 14308 * Fires when the object has been removed from its parent object. 14309 * 14310 * @event Object3D#removed 14311 * @type {Object} 14312 */ 14313const _removedEvent = { type: 'removed' }; 14314 14315/** 14316 * Fires when a new child object has been added. 14317 * 14318 * @event Object3D#childadded 14319 * @type {Object} 14320 */ 14321const _childaddedEvent = { type: 'childadded', child: null }; 14322 14323/** 14324 * Fires when a new child object has been added. 14325 * 14326 * @event Object3D#childremoved 14327 * @type {Object} 14328 */ 14329const _childremovedEvent = { type: 'childremoved', child: null }; 14330 14331/** 14332 * This is the base class for most objects in three.js and provides a set of 14333 * properties and methods for manipulating objects in 3D space. 14334 * 14335 * @augments EventDispatcher 14336 */ 14337class Object3D extends EventDispatcher { 14338 14339 /** 14340 * Constructs a new 3D object. 14341 */ 14342 constructor() { 14343 14344 super(); 14345 14346 /** 14347 * This flag can be used for type testing. 14348 * 14349 * @type {boolean} 14350 * @readonly 14351 * @default true 14352 */ 14353 this.isObject3D = true; 14354 14355 /** 14356 * The ID of the 3D object. 14357 * 14358 * @name Object3D#id 14359 * @type {number} 14360 * @readonly 14361 */ 14362 Object.defineProperty( this, 'id', { value: _object3DId ++ } ); 14363 14364 /** 14365 * The UUID of the 3D object. 14366 * 14367 * @type {string} 14368 * @readonly 14369 */ 14370 this.uuid = generateUUID(); 14371 14372 /** 14373 * The name of the 3D object. 14374 * 14375 * @type {string} 14376 */ 14377 this.name = ''; 14378 14379 /** 14380 * The type property is used for detecting the object type 14381 * in context of serialization/deserialization. 14382 * 14383 * @type {string} 14384 * @readonly 14385 */ 14386 this.type = 'Object3D'; 14387 14388 /** 14389 * A reference to the parent object. 14390 * 14391 * @type {?Object3D} 14392 * @default null 14393 */ 14394 this.parent = null; 14395 14396 /** 14397 * An array holding the child 3D objects of this instance. 14398 * 14399 * @type {Array<Object3D>} 14400 */ 14401 this.children = []; 14402 14403 /** 14404 * Defines the `up` direction of the 3D object which influences 14405 * the orientation via methods like {@link Object3D#lookAt}. 14406 * 14407 * The default values for all 3D objects is defined by `Object3D.DEFAULT_UP`. 14408 * 14409 * @type {Vector3} 14410 */ 14411 this.up = Object3D.DEFAULT_UP.clone(); 14412 14413 const position = new Vector3(); 14414 const rotation = new Euler(); 14415 const quaternion = new Quaternion(); 14416 const scale = new Vector3( 1, 1, 1 ); 14417 14418 function onRotationChange() { 14419 14420 quaternion.setFromEuler( rotation, false ); 14421 14422 } 14423 14424 function onQuaternionChange() { 14425 14426 rotation.setFromQuaternion( quaternion, undefined, false ); 14427 14428 } 14429 14430 rotation._onChange( onRotationChange ); 14431 quaternion._onChange( onQuaternionChange ); 14432 14433 Object.defineProperties( this, { 14434 /** 14435 * Represents the object's local position. 14436 * 14437 * @name Object3D#position 14438 * @type {Vector3} 14439 * @default (0,0,0) 14440 */ 14441 position: { 14442 configurable: true, 14443 enumerable: true, 14444 value: position 14445 }, 14446 /** 14447 * Represents the object's local rotation as Euler angles, in radians. 14448 * 14449 * @name Object3D#rotation 14450 * @type {Euler} 14451 * @default (0,0,0) 14452 */ 14453 rotation: { 14454 configurable: true, 14455 enumerable: true, 14456 value: rotation 14457 }, 14458 /** 14459 * Represents the object's local rotation as Quaternions. 14460 * 14461 * @name Object3D#quaternion 14462 * @type {Quaternion} 14463 */ 14464 quaternion: { 14465 configurable: true, 14466 enumerable: true, 14467 value: quaternion 14468 }, 14469 /** 14470 * Represents the object's local scale. 14471 * 14472 * @name Object3D#scale 14473 * @type {Vector3} 14474 * @default (1,1,1) 14475 */ 14476 scale: { 14477 configurable: true, 14478 enumerable: true, 14479 value: scale 14480 }, 14481 /** 14482 * Represents the object's model-view matrix. 14483 * 14484 * @name Object3D#modelViewMatrix 14485 * @type {Matrix4} 14486 */ 14487 modelViewMatrix: { 14488 value: new Matrix4() 14489 }, 14490 /** 14491 * Represents the object's normal matrix. 14492 * 14493 * @name Object3D#normalMatrix 14494 * @type {Matrix3} 14495 */ 14496 normalMatrix: { 14497 value: new Matrix3() 14498 } 14499 } ); 14500 14501 /** 14502 * Represents the object's transformation matrix in local space. 14503 * 14504 * @type {Matrix4} 14505 */ 14506 this.matrix = new Matrix4(); 14507 14508 /** 14509 * Represents the object's transformation matrix in world space. 14510 * If the 3D object has no parent, then it's identical to the local transformation matrix 14511 * 14512 * @type {Matrix4} 14513 */ 14514 this.matrixWorld = new Matrix4(); 14515 14516 /** 14517 * When set to `true`, the engine automatically computes the local matrix from position, 14518 * rotation and scale every frame. 14519 * 14520 * The default values for all 3D objects is defined by `Object3D.DEFAULT_MATRIX_AUTO_UPDATE`. 14521 * 14522 * @type {boolean} 14523 * @default true 14524 */ 14525 this.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE; 14526 14527 /** 14528 * When set to `true`, the engine automatically computes the world matrix from the current local 14529 * matrix and the object's transformation hierarchy. 14530 * 14531 * The default values for all 3D objects is defined by `Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE`. 14532 * 14533 * @type {boolean} 14534 * @default true 14535 */ 14536 this.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE; // checked by the renderer 14537 14538 /** 14539 * When set to `true`, it calculates the world matrix in that frame and resets this property 14540 * to `false`. 14541 * 14542 * @type {boolean} 14543 * @default false 14544 */ 14545 this.matrixWorldNeedsUpdate = false;
14546 14547 /** 14548 * The layer membership of the 3D object. The 3D object is only visible if it has 14549 * at least one layer in common with the camera in use. This property can also be 14550 * used to filter out unwanted objects in ray-intersection tests when using {@link Raycaster}. 14551 * 14552 * @type {Layers} 14553 */ 14554 this.layers = new Layers(); 14555 14556 /** 14557 * When set to `true`, the 3D object gets rendered. 14558 * 14559 * @type {boolean} 14560 * @default true 14561 */ 14562 this.visible = true; 14563 14564 /** 14565 * When set to `true`, the 3D object gets rendered into shadow maps. 14566 * 14567 * @type {boolean} 14568 * @default false 14569 */ 14570 this.castShadow = false; 14571 14572 /** 14573 * When set to `true`, the 3D object is affected by shadows in the scene. 14574 * 14575 * @type {boolean} 14576 * @default false 14577 */ 14578 this.receiveShadow = false; 14579 14580 /** 14581 * When set to `true`, the 3D object is honored by view frustum culling. 14582 * 14583 * @type {boolean} 14584 * @default true 14585 */ 14586 this.frustumCulled = true; 14587 14588 /** 14589 * This value allows the default rendering order of scene graph objects to be 14590 * overridden although opaque and transparent objects remain sorted independently. 14591 * When this property is set for an instance of {@link Group},all descendants 14592 * objects will be sorted and rendered together. Sorting is from lowest to highest 14593 * render order. 14594 * 14595 * @type {number} 14596 * @default 0 14597 */ 14598 this.renderOrder = 0; 14599 14600 /** 14601 * An array holding the animation clips of the 3D object. 14602 * 14603 * @type {Array<AnimationClip>} 14604 */ 14605 this.animations = []; 14606 14607 /** 14608 * Custom depth material to be used when rendering to the depth map. Can only be used 14609 * in context of meshes. When shadow-casting with a {@link DirectionalLight} or {@link SpotLight}, 14610 * if you are modifying vertex positions in the vertex shader you must specify a custom depth 14611 * material for proper shadows. 14612 * 14613 * Only relevant in context of {@link WebGLRenderer}. 14614 * 14615 * @type {(Material|undefined)} 14616 * @default undefined 14617 */ 14618 this.customDepthMaterial = undefined; 14619 14620 /** 14621 * Same as {@link Object3D#customDepthMaterial}, but used with {@link PointLight}. 14622 * 14623 * Only relevant in context of {@link WebGLRenderer}. 14624 * 14625 * @type {(Material|undefined)} 14626 * @default undefined 14627 */ 14628 this.customDistanceMaterial = undefined; 14629 14630 /** 14631 * An object that can be used to store custom data about the 3D object. It 14632 * should not hold references to functions as these will not be cloned. 14633 * 14634 * @type {Object} 14635 */ 14636 this.userData = {}; 14637 14638 } 14639 14640 /** 14641 * A callback that is executed immediately before a 3D object is rendered to a shadow map. 14642 * 14643 * @param {Renderer|WebGLRenderer} renderer - The renderer. 14644 * @param {Object3D} object - The 3D object. 14645 * @param {Camera} camera - The camera that is used to render the scene. 14646 * @param {Camera} shadowCamera - The shadow camera. 14647 * @param {BufferGeometry} geometry - The 3D object's geometry. 14648 * @param {Material} depthMaterial - The depth material. 14649 * @param {Object} group - The geometry group data. 14650 */ 14651 onBeforeShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {} 14652 14653 /** 14654 * A callback that is executed immediately after a 3D object is rendered to a shadow map. 14655 * 14656 * @param {Renderer|WebGLRenderer} renderer - The renderer. 14657 * @param {Object3D} object - The 3D object. 14658 * @param {Camera} camera - The camera that is used to render the scene. 14659 * @param {Camera} shadowCamera - The shadow camera. 14660 * @param {BufferGeometry} geometry - The 3D object's geometry. 14661 * @param {Material} depthMaterial - The depth material. 14662 * @param {Object} group - The geometry group data. 14663 */ 14664 onAfterShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {} 14665 14666 /** 14667 * A callback that is executed immediately before a 3D object is rendered. 14668 * 14669 * @param {Renderer|WebGLRenderer} renderer - The renderer. 14670 * @param {Object3D} object - The 3D object. 14671 * @param {Camera} camera - The camera that is used to render the scene. 14672 * @param {BufferGeometry} geometry - The 3D object's geometry. 14673 * @param {Material} material - The 3D object's material. 14674 * @param {Object} group - The geometry group data. 14675 */ 14676 onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {} 14677 14678 /** 14679 * A callback that is executed immediately after a 3D object is rendered. 14680 *
14681 * @param {Renderer|WebGLRenderer} renderer - The renderer. 14682 * @param {Object3D} object - The 3D object. 14683 * @param {Camera} camera - The camera that is used to render the scene. 14684 * @param {BufferGeometry} geometry - The 3D object's geometry. 14685 * @param {Material} material - The 3D object's material. 14686 * @param {Object} group - The geometry group data. 14687 */ 14688 onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {} 14689 14690 /** 14691 * Applies the given transformation matrix to the object and updates the object's position, 14692 * rotation and scale. 14693 * 14694 * @param {Matrix4} matrix - The transformation matrix. 14695 */ 14696 applyMatrix4( matrix ) { 14697 14698 if ( this.matrixAutoUpdate ) this.updateMatrix(); 14699 14700 this.matrix.premultiply( matrix ); 14701 14702 this.matrix.decompose( this.position, this.quaternion, this.scale ); 14703 14704 } 14705 14706 /** 14707 * Applies a rotation represented by given the quaternion to the 3D object. 14708 * 14709 * @param {Quaternion} q - The quaternion. 14710 * @return {Object3D} A reference to this instance. 14711 */ 14712 applyQuaternion( q ) { 14713 14714 this.quaternion.premultiply( q ); 14715 14716 return this; 14717 14718 } 14719 14720 /** 14721 * Sets the given rotation represented as an axis/angle couple to the 3D object. 14722 * 14723 * @param {Vector3} axis - The (normalized) axis vector. 14724 * @param {number} angle - The angle in radians. 14725 */ 14726 setRotationFromAxisAngle( axis, angle ) { 14727 14728 // assumes axis is normalized 14729 14730 this.quaternion.setFromAxisAngle( axis, angle ); 14731 14732 } 14733 14734 /** 14735 * Sets the given rotation represented as Euler angles to the 3D object. 14736 * 14737 * @param {Euler} euler - The Euler angles. 14738 */ 14739 setRotationFromEuler( euler ) { 14740 14741 this.quaternion.setFromEuler( euler, true ); 14742 14743 } 14744 14745 /** 14746 * Sets the given rotation represented as rotation matrix to the 3D object. 14747 * 14748 * @param {Matrix4} m - Although a 4x4 matrix is expected, the upper 3x3 portion must be 14749 * a pure rotation matrix (i.e, unscaled). 14750 */ 14751 setRotationFromMatrix( m ) { 14752 14753 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 14754 14755 this.quaternion.setFromRotationMatrix( m ); 14756 14757 } 14758 14759 /** 14760 * Sets the given rotation represented as a Quaternion to the 3D object. 14761 * 14762 * @param {Quaternion} q - The Quaternion 14763 */ 14764 setRotationFromQuaternion( q ) { 14765 14766 // assumes q is normalized 14767 14768 this.quaternion.copy( q ); 14769 14770 } 14771 14772 /** 14773 * Rotates the 3D object along an axis in local space. 14774 * 14775 * @param {Vector3} axis - The (normalized) axis vector. 14776 * @param {number} angle - The angle in radians. 14777 * @return {Object3D} A reference to this instance. 14778 */ 14779 rotateOnAxis( axis, angle ) { 14780 14781 // rotate object on axis in object space 14782 // axis is assumed to be normalized 14783 14784 _q1.setFromAxisAngle( axis, angle ); 14785 14786 this.quaternion.multiply( _q1 ); 14787 14788 return this; 14789 14790 } 14791 14792 /** 14793 * Rotates the 3D object along an axis in world space. 14794 * 14795 * @param {Vector3} axis - The (normalized) axis vector. 14796 * @param {number} angle - The angle in radians. 14797 * @return {Object3D} A reference to this instance. 14798 */ 14799 rotateOnWorldAxis( axis, angle ) { 14800 14801 // rotate object on axis in world space 14802 // axis is assumed to be normalized 14803 // method assumes no rotated parent 14804 14805 _q1.setFromAxisAngle( axis, angle ); 14806 14807 this.quaternion.premultiply( _q1 ); 14808 14809 return this; 14810 14811 } 14812 14813 /** 14814 * Rotates the 3D object around its X axis in local space. 14815 * 14816 * @param {number} angle - The angle in radians. 14817 * @return {Object3D} A reference to this instance. 14818 */ 14819 rotateX( angle ) { 14820 14821 return this.rotateOnAxis( _xAxis, angle ); 14822 14823 } 14824 14825 /** 14826 * Rotates the 3D object around its Y axis in local space. 14827 * 14828 * @param {number} angle - The angle in radians. 14829 * @return {Object3D} A reference to this instance. 14830 */ 14831 rotateY( angle ) { 14832 14833 return this.rotateOnAxis( _yAxis, angle ); 14834 14835 } 14836 14837 /** 14838 * Rotates the 3D object around its Z axis in local space. 14839 * 14840 * @param {number} angle - The angle in radians. 14841 * @return {Object3D} A reference to this instance. 14842 */ 14843 rotateZ( angle ) { 14844 14845 return this.rotateOnAxis( _zAxis, angle ); 14846 14847 } 14848 14849 /** 14850 * Translate the 3D object by a distance along the given axis in local space. 14851 * 14852 * @param {Vector3} axis - The (normalized) axis vector. 14853 * @param {number} distance - The distance in world units. 14854 * @return {Object3D} A reference to this instance. 14855 */ 14856 translateOnAxis( axis, distance ) { 14857 14858 // translate object by distance along axis in object space 14859 // axis is assumed to be normalized 14860 14861 _v1$4.copy( axis ).applyQuaternion( this.quaternion ); 14862 14863 this.position.add( _v1$4.multiplyScalar( distance ) ); 14864 14865 return this; 14866 14867 } 14868
vendor: 4,524 bytes, lines 14869-15078
14869 /** 14870 * Translate the 3D object by a distance along its X-axis in local space. 14871 * 14872 * @param {number} distance - The distance in world units. 14873 * @return {Object3D} A reference to this instance. 14874 */ 14875 translateX( distance ) { 14876 14877 return this.translateOnAxis( _xAxis, distance ); 14878 14879 } 14880 14881 /** 14882 * Translate the 3D object by a distance along its Y-axis in local space. 14883 * 14884 * @param {number} distance - The distance in world units. 14885 * @return {Object3D} A reference to this instance. 14886 */ 14887 translateY( distance ) { 14888 14889 return this.translateOnAxis( _yAxis, distance ); 14890 14891 } 14892 14893 /** 14894 * Translate the 3D object by a distance along its Z-axis in local space. 14895 * 14896 * @param {number} distance - The distance in world units. 14897 * @return {Object3D} A reference to this instance. 14898 */ 14899 translateZ( distance ) { 14900 14901 return this.translateOnAxis( _zAxis, distance ); 14902 14903 } 14904 14905 /** 14906 * Converts the given vector from this 3D object's local space to world space. 14907 * 14908 * @param {Vector3} vector - The vector to convert. 14909 * @return {Vector3} The converted vector. 14910 */ 14911 localToWorld( vector ) { 14912 14913 this.updateWorldMatrix( true, false ); 14914 14915 return vector.applyMatrix4( this.matrixWorld ); 14916 14917 } 14918 14919 /** 14920 * Converts the given vector from this 3D object's word space to local space. 14921 * 14922 * @param {Vector3} vector - The vector to convert. 14923 * @return {Vector3} The converted vector. 14924 */ 14925 worldToLocal( vector ) { 14926 14927 this.updateWorldMatrix( true, false ); 14928 14929 return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() ); 14930 14931 } 14932 14933 /** 14934 * Rotates the object to face a point in world space. 14935 * 14936 * This method does not support objects having non-uniformly-scaled parent(s). 14937 * 14938 * @param {number|Vector3} x - The x coordinate in world space. Alternatively, a vector representing a position in world space 14939 * @param {number} [y] - The y coordinate in world space. 14940 * @param {number} [z] - The z coordinate in world space. 14941 */ 14942 lookAt( x, y, z ) { 14943 14944 // This method does not support objects having non-uniformly-scaled parent(s) 14945 14946 if ( x.isVector3 ) { 14947 14948 _target.copy( x ); 14949 14950 } else { 14951 14952 _target.set( x, y, z ); 14953 14954 } 14955 14956 const parent = this.parent; 14957 14958 this.updateWorldMatrix( true, false ); 14959 14960 _position$3.setFromMatrixPosition( this.matrixWorld ); 14961 14962 if ( this.isCamera || this.isLight ) { 14963 14964 _m1$1.lookAt( _position$3, _target, this.up ); 14965 14966 } else { 14967 14968 _m1$1.lookAt( _target, _position$3, this.up ); 14969 14970 } 14971 14972 this.quaternion.setFromRotationMatrix( _m1$1 ); 14973 14974 if ( parent ) { 14975 14976 _m1$1.extractRotation( parent.matrixWorld ); 14977 _q1.setFromRotationMatrix( _m1$1 ); 14978 this.quaternion.premultiply( _q1.invert() ); 14979 14980 } 14981 14982 } 14983 14984 /** 14985 * Adds the given 3D object as a child to this 3D object. An arbitrary number of 14986 * objects may be added. Any current parent on an object passed in here will be 14987 * removed, since an object can have at most one parent. 14988 * 14989 * @fires Object3D#added 14990 * @fires Object3D#childadded 14991 * @param {Object3D} object - The 3D object to add. 14992 * @return {Object3D} A reference to this instance. 14993 */ 14994 add( object ) { 14995 14996 if ( arguments.length > 1 ) { 14997 14998 for ( let i = 0; i < arguments.length; i ++ ) { 14999 15000 this.add( arguments[ i ] ); 15001 15002 } 15003 15004 return this; 15005 15006 } 15007 15008 if ( object === this ) { 15009 15010 console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object ); 15011 return this; 15012 15013 } 15014 15015 if ( object && object.isObject3D ) { 15016 15017 object.removeFromParent(); 15018 object.parent = this; 15019 this.children.push( object ); 15020 15021 object.dispatchEvent( _addedEvent ); 15022 15023 _childaddedEvent.child = object; 15024 this.dispatchEvent( _childaddedEvent ); 15025 _childaddedEvent.child = null; 15026 15027 } else { 15028 15029 console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object ); 15030 15031 } 15032 15033 return this; 15034 15035 } 15036 15037 /** 15038 * Removes the given 3D object as child from this 3D object. 15039 * An arbitrary number of objects may be removed. 15040 * 15041 * @fires Object3D#removed 15042 * @fires Object3D#childremoved 15043 * @param {Object3D} object - The 3D object to remove. 15044 * @return {Object3D} A reference to this instance. 15045 */ 15046 remove( object ) { 15047 15048 if ( arguments.length > 1 ) { 15049 15050 for ( let i = 0; i < arguments.length; i ++ ) { 15051 15052 this.remove( arguments[ i ] ); 15053 15054 } 15055 15056 return this; 15057 15058 } 15059 15060 const index = this.children.indexOf( object ); 15061 15062 if ( index !== -1 ) { 15063 15064 object.parent = null; 15065 this.children.splice( index, 1 ); 15066 15067 object.dispatchEvent( _removedEvent ); 15068 15069 _childremovedEvent.child = object; 15070 this.dispatchEvent( _childremovedEvent ); 15071 _childremovedEvent.child = null; 15072 15073 } 15074 15075 return this; 15076 15077 } 15078
vendor: 8,613 bytes, lines 15079-15420
15079 /** 15080 * Removes this 3D object from its current parent. 15081 * 15082 * @fires Object3D#removed 15083 * @fires Object3D#childremoved 15084 * @return {Object3D} A reference to this instance. 15085 */ 15086 removeFromParent() { 15087 15088 const parent = this.parent; 15089 15090 if ( parent !== null ) { 15091 15092 parent.remove( this ); 15093 15094 } 15095 15096 return this; 15097 15098 } 15099 15100 /** 15101 * Removes all child objects. 15102 * 15103 * @fires Object3D#removed 15104 * @fires Object3D#childremoved 15105 * @return {Object3D} A reference to this instance. 15106 */ 15107 clear() { 15108 15109 return this.remove( ... this.children ); 15110 15111 } 15112 15113 /** 15114 * Adds the given 3D object as a child of this 3D object, while maintaining the object's world 15115 * transform. This method does not support scene graphs having non-uniformly-scaled nodes(s). 15116 * 15117 * @fires Object3D#added 15118 * @fires Object3D#childadded 15119 * @param {Object3D} object - The 3D object to attach. 15120 * @return {Object3D} A reference to this instance. 15121 */ 15122 attach( object ) { 15123 15124 // adds object as a child of this, while maintaining the object's world transform 15125 15126 // Note: This method does not support scene graphs having non-uniformly-scaled nodes(s) 15127 15128 this.updateWorldMatrix( true, false ); 15129 15130 _m1$1.copy( this.matrixWorld ).invert(); 15131 15132 if ( object.parent !== null ) { 15133 15134 object.parent.updateWorldMatrix( true, false ); 15135 15136 _m1$1.multiply( object.parent.matrixWorld ); 15137 15138 } 15139 15140 object.applyMatrix4( _m1$1 ); 15141 15142 object.removeFromParent(); 15143 object.parent = this; 15144 this.children.push( object ); 15145 15146 object.updateWorldMatrix( false, true ); 15147 15148 object.dispatchEvent( _addedEvent ); 15149 15150 _childaddedEvent.child = object; 15151 this.dispatchEvent( _childaddedEvent ); 15152 _childaddedEvent.child = null; 15153 15154 return this; 15155 15156 } 15157 15158 /** 15159 * Searches through the 3D object and its children, starting with the 3D object 15160 * itself, and returns the first with a matching ID. 15161 * 15162 * @param {number} id - The id. 15163 * @return {Object3D|undefined} The found 3D object. Returns `undefined` if no 3D object has been found. 15164 */ 15165 getObjectById( id ) { 15166 15167 return this.getObjectByProperty( 'id', id ); 15168 15169 } 15170 15171 /** 15172 * Searches through the 3D object and its children, starting with the 3D object 15173 * itself, and returns the first with a matching name. 15174 * 15175 * @param {string} name - The name. 15176 * @return {Object3D|undefined} The found 3D object. Returns `undefined` if no 3D object has been found. 15177 */ 15178 getObjectByName( name ) { 15179 15180 return this.getObjectByProperty( 'name', name ); 15181 15182 } 15183 15184 /** 15185 * Searches through the 3D object and its children, starting with the 3D object 15186 * itself, and returns the first with a matching property value. 15187 * 15188 * @param {string} name - The name of the property. 15189 * @param {any} value - The value. 15190 * @return {Object3D|undefined} The found 3D object. Returns `undefined` if no 3D object has been found. 15191 */ 15192 getObjectByProperty( name, value ) { 15193 15194 if ( this[ name ] === value ) return this; 15195 15196 for ( let i = 0, l = this.children.length; i < l; i ++ ) { 15197 15198 const child = this.children[ i ]; 15199 const object = child.getObjectByProperty( name, value ); 15200 15201 if ( object !== undefined ) { 15202 15203 return object; 15204 15205 } 15206 15207 } 15208 15209 return undefined; 15210 15211 } 15212 15213 /** 15214 * Searches through the 3D object and its children, starting with the 3D object 15215 * itself, and returns all 3D objects with a matching property value. 15216 * 15217 * @param {string} name - The name of the property. 15218 * @param {any} value - The value. 15219 * @param {Array<Object3D>} result - The method stores the result in this array. 15220 * @return {Array<Object3D>} The found 3D objects. 15221 */ 15222 getObjectsByProperty( name, value, result = [] ) { 15223 15224 if ( this[ name ] === value ) result.push( this ); 15225 15226 const children = this.children; 15227 15228 for ( let i = 0, l = children.length; i < l; i ++ ) { 15229 15230 children[ i ].getObjectsByProperty( name, value, result ); 15231 15232 } 15233 15234 return result; 15235 15236 } 15237 15238 /** 15239 * Returns a vector representing the position of the 3D object in world space. 15240 * 15241 * @param {Vector3} target - The target vector the result is stored to. 15242 * @return {Vector3} The 3D object's position in world space. 15243 */ 15244 getWorldPosition( target ) { 15245 15246 this.updateWorldMatrix( true, false ); 15247 15248 return target.setFromMatrixPosition( this.matrixWorld ); 15249 15250 } 15251 15252 /** 15253 * Returns a Quaternion representing the position of the 3D object in world space. 15254 * 15255 * @param {Quaternion} target - The target Quaternion the result is stored to. 15256 * @return {Quaternion} The 3D object's rotation in world space. 15257 */ 15258 getWorldQuaternion( target ) { 15259 15260 this.updateWorldMatrix( true, false ); 15261 15262 this.matrixWorld.decompose( _position$3, target, _scale$2 ); 15263 15264 return target; 15265 15266 } 15267 15268 /** 15269 * Returns a vector representing the scale of the 3D object in world space. 15270 * 15271 * @param {Vector3} target - The target vector the result is stored to. 15272 * @return {Vector3} The 3D object's scale in world space. 15273 */ 15274 getWorldScale( target ) { 15275 15276 this.updateWorldMatrix( true, false ); 15277 15278 this.matrixWorld.decompose( _position$3, _quaternion$2, target ); 15279 15280 return target; 15281 15282 } 15283 15284 /** 15285 * Returns a vector representing the ("look") direction of the 3D object in world space. 15286 * 15287 * @param {Vector3} target - The target vector the result is stored to. 15288 * @return {Vector3} The 3D object's direction in world space. 15289 */ 15290 getWorldDirection( target ) { 15291 15292 this.updateWorldMatrix( true, false ); 15293 15294 const e = this.matrixWorld.elements; 15295 15296 return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize(); 15297 15298 } 15299 15300 /** 15301 * Abstract method to get intersections between a casted ray and this 15302 * 3D object. Renderable 3D objects such as {@link Mesh}, {@link Line} or {@link Points} 15303 * implement this method in order to use raycasting. 15304 * 15305 * @abstract 15306 * @param {Raycaster} raycaster - The raycaster. 15307 * @param {Array<Object>} intersects - An array holding the result of the method. 15308 */ 15309 raycast( /* raycaster, intersects */ ) {} 15310 15311 /** 15312 * Executes the callback on this 3D object and all descendants. 15313 * 15314 * Note: Modifying the scene graph inside the callback is discouraged. 15315 * 15316 * @param {Function} callback - A callback function that allows to process the current 3D object. 15317 */ 15318 traverse( callback ) { 15319 15320 callback( this ); 15321 15322 const children = this.children; 15323 15324 for ( let i = 0, l = children.length; i < l; i ++ ) { 15325 15326 children[ i ].traverse( callback ); 15327 15328 } 15329 15330 } 15331 15332 /** 15333 * Like {@link Object3D#traverse}, but the callback will only be executed for visible 3D objects. 15334 * Descendants of invisible 3D objects are not traversed. 15335 * 15336 * Note: Modifying the scene graph inside the callback is discouraged. 15337 * 15338 * @param {Function} callback - A callback function that allows to process the current 3D object. 15339 */ 15340 traverseVisible( callback ) { 15341 15342 if ( this.visible === false ) return; 15343 15344 callback( this ); 15345 15346 const children = this.children; 15347 15348 for ( let i = 0, l = children.length; i < l; i ++ ) { 15349 15350 children[ i ].traverseVisible( callback ); 15351 15352 } 15353 15354 } 15355 15356 /** 15357 * Like {@link Object3D#traverse}, but the callback will only be executed for all ancestors. 15358 * 15359 * Note: Modifying the scene graph inside the callback is discouraged. 15360 * 15361 * @param {Function} callback - A callback function that allows to process the current 3D object. 15362 */ 15363 traverseAncestors( callback ) { 15364 15365 const parent = this.parent; 15366 15367 if ( parent !== null ) { 15368 15369 callback( parent ); 15370 15371 parent.traverseAncestors( callback ); 15372 15373 } 15374 15375 } 15376 15377 /** 15378 * Updates the transformation matrix in local space by computing it from the current 15379 * position, rotation and scale values. 15380 */ 15381 updateMatrix() { 15382 15383 this.matrix.compose( this.position, this.quaternion, this.scale ); 15384 15385 this.matrixWorldNeedsUpdate = true; 15386 15387 } 15388 15389 /** 15390 * Updates the transformation matrix in world space of this 3D objects and its descendants. 15391 * 15392 * To ensure correct results, this method also recomputes the 3D object's transformation matrix in 15393 * local space. The computation of the local and world matrix can be controlled with the 15394 * {@link Object3D#matrixAutoUpdate} and {@link Object3D#matrixWorldAutoUpdate} flags which are both 15395 * `true` by default. Set these flags to `false` if you need more control over the update matrix process. 15396 * 15397 * @param {boolean} [force=false] - When set to `true`, a recomputation of world matrices is forced even 15398 * when {@link Object3D#matrixWorldAutoUpdate} is set to `false`. 15399 */ 15400 updateMatrixWorld( force ) { 15401 15402 if ( this.matrixAutoUpdate ) this.updateMatrix(); 15403 15404 if ( this.matrixWorldNeedsUpdate || force ) { 15405 15406 if ( this.matrixWorldAutoUpdate === true ) { 15407 15408 if ( this.parent === null ) { 15409 15410 this.matrixWorld.copy( this.matrix ); 15411 15412 } else { 15413 15414 this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); 15415 15416 } 15417 15418 } 15419 15420 this.matrixWorldNeedsUpdate = false;
vendor: 11,871 bytes, lines 15421-15943
15421 15422 force = true; 15423 15424 } 15425 15426 // make sure descendants are updated if required 15427 15428 const children = this.children; 15429 15430 for ( let i = 0, l = children.length; i < l; i ++ ) { 15431 15432 const child = children[ i ]; 15433 15434 child.updateMatrixWorld( force ); 15435 15436 } 15437 15438 } 15439 15440 /** 15441 * An alternative version of {@link Object3D#updateMatrixWorld} with more control over the 15442 * update of ancestor and descendant nodes. 15443 * 15444 * @param {boolean} [updateParents=false] Whether ancestor nodes should be updated or not. 15445 * @param {boolean} [updateChildren=false] Whether descendant nodes should be updated or not. 15446 */ 15447 updateWorldMatrix( updateParents, updateChildren ) { 15448 15449 const parent = this.parent; 15450 15451 if ( updateParents === true && parent !== null ) { 15452 15453 parent.updateWorldMatrix( true, false ); 15454 15455 } 15456 15457 if ( this.matrixAutoUpdate ) this.updateMatrix(); 15458 15459 if ( this.matrixWorldAutoUpdate === true ) { 15460 15461 if ( this.parent === null ) { 15462 15463 this.matrixWorld.copy( this.matrix ); 15464 15465 } else { 15466 15467 this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); 15468 15469 } 15470 15471 } 15472 15473 // make sure descendants are updated 15474 15475 if ( updateChildren === true ) { 15476 15477 const children = this.children; 15478 15479 for ( let i = 0, l = children.length; i < l; i ++ ) { 15480 15481 const child = children[ i ]; 15482 15483 child.updateWorldMatrix( false, true ); 15484 15485 } 15486 15487 } 15488 15489 } 15490 15491 /** 15492 * Serializes the 3D object into JSON. 15493 * 15494 * @param {?(Object|string)} meta - An optional value holding meta information about the serialization. 15495 * @return {Object} A JSON object representing the serialized 3D object. 15496 * @see {@link ObjectLoader#parse} 15497 */ 15498 toJSON( meta ) { 15499 15500 // meta is a string when called from JSON.stringify 15501 const isRootObject = ( meta === undefined || typeof meta === 'string' ); 15502 15503 const output = {}; 15504 15505 // meta is a hash used to collect geometries, materials. 15506 // not providing it implies that this is the root object 15507 // being serialized. 15508 if ( isRootObject ) { 15509 15510 // initialize meta obj 15511 meta = { 15512 geometries: {}, 15513 materials: {}, 15514 textures: {}, 15515 images: {}, 15516 shapes: {}, 15517 skeletons: {}, 15518 animations: {}, 15519 nodes: {} 15520 }; 15521 15522 output.metadata = { 15523 version: 4.6, 15524 type: 'Object', 15525 generator: 'Object3D.toJSON' 15526 }; 15527 15528 } 15529 15530 // standard Object3D serialization 15531 15532 const object = {}; 15533 15534 object.uuid = this.uuid; 15535 object.type = this.type; 15536 15537 if ( this.name !== '' ) object.name = this.name; 15538 if ( this.castShadow === true ) object.castShadow = true; 15539 if ( this.receiveShadow === true ) object.receiveShadow = true; 15540 if ( this.visible === false ) object.visible = false; 15541 if ( this.frustumCulled === false ) object.frustumCulled = false; 15542 if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder; 15543 if ( Object.keys( this.userData ).length > 0 ) object.userData = this.userData; 15544 15545 object.layers = this.layers.mask; 15546 object.matrix = this.matrix.toArray(); 15547 object.up = this.up.toArray(); 15548 15549 if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false; 15550 15551 // object specific properties 15552 15553 if ( this.isInstancedMesh ) { 15554 15555 object.type = 'InstancedMesh'; 15556 object.count = this.count; 15557 object.instanceMatrix = this.instanceMatrix.toJSON(); 15558 if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON(); 15559 15560 } 15561 15562 if ( this.isBatchedMesh ) { 15563 15564 object.type = 'BatchedMesh'; 15565 object.perObjectFrustumCulled = this.perObjectFrustumCulled; 15566 object.sortObjects = this.sortObjects; 15567 15568 object.drawRanges = this._drawRanges; 15569 object.reservedRanges = this._reservedRanges; 15570 15571 object.visibility = this._visibility; 15572 object.active = this._active; 15573 object.bounds = this._bounds.map( bound => ( { 15574 boxInitialized: bound.boxInitialized, 15575 boxMin: bound.box.min.toArray(), 15576 boxMax: bound.box.max.toArray(), 15577 15578 sphereInitialized: bound.sphereInitialized, 15579 sphereRadius: bound.sphere.radius, 15580 sphereCenter: bound.sphere.center.toArray() 15581 } ) ); 15582 15583 object.maxInstanceCount = this._maxInstanceCount; 15584 object.maxVertexCount = this._maxVertexCount; 15585 object.maxIndexCount = this._maxIndexCount; 15586 15587 object.geometryInitialized = this._geometryInitialized; 15588 object.geometryCount = this._geometryCount; 15589 15590 object.matricesTexture = this._matricesTexture.toJSON( meta ); 15591 15592 if ( this._colorsTexture !== null ) object.colorsTexture = this._colorsTexture.toJSON( meta ); 15593 15594 if ( this.boundingSphere !== null ) { 15595 15596 object.boundingSphere = { 15597 center: object.boundingSphere.center.toArray(), 15598 radius: object.boundingSphere.radius 15599 }; 15600 15601 } 15602 15603 if ( this.boundingBox !== null ) { 15604 15605 object.boundingBox = { 15606 min: object.boundingBox.min.toArray(), 15607 max: object.boundingBox.max.toArray() 15608 }; 15609 15610 } 15611 15612 } 15613 15614 // 15615 15616 function serialize( library, element ) { 15617 15618 if ( library[ element.uuid ] === undefined ) { 15619 15620 library[ element.uuid ] = element.toJSON( meta ); 15621 15622 } 15623 15624 return element.uuid; 15625 15626 } 15627 15628 if ( this.isScene ) { 15629 15630 if ( this.background ) { 15631 15632 if ( this.background.isColor ) { 15633 15634 object.background = this.background.toJSON(); 15635 15636 } else if ( this.background.isTexture ) { 15637 15638 object.background = this.background.toJSON( meta ).uuid; 15639 15640 } 15641 15642 } 15643 15644 if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) { 15645 15646 object.environment = this.environment.toJSON( meta ).uuid; 15647 15648 } 15649 15650 } else if ( this.isMesh || this.isLine || this.isPoints ) { 15651 15652 object.geometry = serialize( meta.geometries, this.geometry ); 15653 15654 const parameters = this.geometry.parameters; 15655 15656 if ( parameters !== undefined && parameters.shapes !== undefined ) { 15657 15658 const shapes = parameters.shapes; 15659 15660 if ( Array.isArray( shapes ) ) { 15661 15662 for ( let i = 0, l = shapes.length; i < l; i ++ ) { 15663 15664 const shape = shapes[ i ]; 15665 15666 serialize( meta.shapes, shape ); 15667 15668 } 15669 15670 } else { 15671 15672 serialize( meta.shapes, shapes ); 15673 15674 } 15675 15676 } 15677 15678 } 15679 15680 if ( this.isSkinnedMesh ) { 15681 15682 object.bindMode = this.bindMode; 15683 object.bindMatrix = this.bindMatrix.toArray(); 15684 15685 if ( this.skeleton !== undefined ) { 15686 15687 serialize( meta.skeletons, this.skeleton ); 15688 15689 object.skeleton = this.skeleton.uuid; 15690 15691 } 15692 15693 } 15694 15695 if ( this.material !== undefined ) { 15696 15697 if ( Array.isArray( this.material ) ) { 15698 15699 const uuids = []; 15700 15701 for ( let i = 0, l = this.material.length; i < l; i ++ ) { 15702 15703 uuids.push( serialize( meta.materials, this.material[ i ] ) ); 15704 15705 } 15706 15707 object.material = uuids; 15708 15709 } else { 15710 15711 object.material = serialize( meta.materials, this.material ); 15712 15713 } 15714 15715 } 15716 15717 // 15718 15719 if ( this.children.length > 0 ) { 15720 15721 object.children = []; 15722 15723 for ( let i = 0; i < this.children.length; i ++ ) { 15724 15725 object.children.push( this.children[ i ].toJSON( meta ).object ); 15726 15727 } 15728 15729 } 15730 15731 // 15732 15733 if ( this.animations.length > 0 ) { 15734 15735 object.animations = []; 15736 15737 for ( let i = 0; i < this.animations.length; i ++ ) { 15738 15739 const animation = this.animations[ i ]; 15740 15741 object.animations.push( serialize( meta.animations, animation ) ); 15742 15743 } 15744 15745 } 15746 15747 if ( isRootObject ) { 15748 15749 const geometries = extractFromCache( meta.geometries ); 15750 const materials = extractFromCache( meta.materials ); 15751 const textures = extractFromCache( meta.textures ); 15752 const images = extractFromCache( meta.images ); 15753 const shapes = extractFromCache( meta.shapes ); 15754 const skeletons = extractFromCache( meta.skeletons ); 15755 const animations = extractFromCache( meta.animations ); 15756 const nodes = extractFromCache( meta.nodes ); 15757 15758 if ( geometries.length > 0 ) output.geometries = geometries; 15759 if ( materials.length > 0 ) output.materials = materials; 15760 if ( textures.length > 0 ) output.textures = textures; 15761 if ( images.length > 0 ) output.images = images; 15762 if ( shapes.length > 0 ) output.shapes = shapes; 15763 if ( skeletons.length > 0 ) output.skeletons = skeletons; 15764 if ( animations.length > 0 ) output.animations = animations; 15765 if ( nodes.length > 0 ) output.nodes = nodes; 15766 15767 } 15768 15769 output.object = object; 15770 15771 return output; 15772 15773 // extract data from the cache hash 15774 // remove metadata on each item 15775 // and return as array 15776 function extractFromCache( cache ) { 15777 15778 const values = []; 15779 for ( const key in cache ) { 15780 15781 const data = cache[ key ]; 15782 delete data.metadata; 15783 values.push( data ); 15784 15785 } 15786 15787 return values; 15788 15789 } 15790 15791 } 15792 15793 /** 15794 * Returns a new 3D object with copied values from this instance. 15795 * 15796 * @param {boolean} [recursive=true] - When set to `true`, descendants of the 3D object are also cloned. 15797 * @return {Object3D} A clone of this instance. 15798 */ 15799 clone( recursive ) { 15800 15801 return new this.constructor().copy( this, recursive ); 15802 15803 } 15804 15805 /** 15806 * Copies the values of the given 3D object to this instance. 15807 * 15808 * @param {Object3D} source - The 3D object to copy. 15809 * @param {boolean} [recursive=true] - When set to `true`, descendants of the 3D object are cloned. 15810 * @return {Object3D} A reference to this instance. 15811 */ 15812 copy( source, recursive = true ) { 15813 15814 this.name = source.name; 15815 15816 this.up.copy( source.up ); 15817 15818 this.position.copy( source.position ); 15819 this.rotation.order = source.rotation.order; 15820 this.quaternion.copy( source.quaternion ); 15821 this.scale.copy( source.scale ); 15822 15823 this.matrix.copy( source.matrix ); 15824 this.matrixWorld.copy( source.matrixWorld ); 15825 15826 this.matrixAutoUpdate = source.matrixAutoUpdate; 15827 15828 this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate; 15829 this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; 15830 15831 this.layers.mask = source.layers.mask; 15832 this.visible = source.visible; 15833 15834 this.castShadow = source.castShadow; 15835 this.receiveShadow = source.receiveShadow; 15836 15837 this.frustumCulled = source.frustumCulled; 15838 this.renderOrder = source.renderOrder; 15839 15840 this.animations = source.animations.slice(); 15841 15842 this.userData = JSON.parse( JSON.stringify( source.userData ) ); 15843 15844 if ( recursive === true ) { 15845 15846 for ( let i = 0; i < source.children.length; i ++ ) { 15847 15848 const child = source.children[ i ]; 15849 this.add( child.clone() ); 15850 15851 } 15852 15853 } 15854 15855 return this; 15856 15857 } 15858 15859} 15860 15861/** 15862 * The default up direction for objects, also used as the default 15863 * position for {@link DirectionalLight} and {@link HemisphereLight}. 15864 * 15865 * @static 15866 * @type {Vector3} 15867 * @default (0,1,0) 15868 */ 15869Object3D.DEFAULT_UP = /*@__PURE__*/ new Vector3( 0, 1, 0 ); 15870 15871/** 15872 * The default setting for {@link Object3D#matrixAutoUpdate} for 15873 * newly created 3D objects. 15874 * 15875 * @static 15876 * @type {boolean} 15877 * @default true 15878 */ 15879Object3D.DEFAULT_MATRIX_AUTO_UPDATE = true; 15880 15881/** 15882 * The default setting for {@link Object3D#matrixWorldAutoUpdate} for 15883 * newly created 3D objects. 15884 * 15885 * @static 15886 * @type {boolean} 15887 * @default true 15888 */ 15889Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = true; 15890 15891const _v0$1 = /*@__PURE__*/ new Vector3(); 15892const _v1$3 = /*@__PURE__*/ new Vector3(); 15893const _v2$2 = /*@__PURE__*/ new Vector3(); 15894const _v3$2 = /*@__PURE__*/ new Vector3(); 15895 15896const _vab = /*@__PURE__*/ new Vector3(); 15897const _vac = /*@__PURE__*/ new Vector3(); 15898const _vbc = /*@__PURE__*/ new Vector3(); 15899const _vap = /*@__PURE__*/ new Vector3(); 15900const _vbp = /*@__PURE__*/ new Vector3(); 15901const _vcp = /*@__PURE__*/ new Vector3(); 15902 15903const _v40 = /*@__PURE__*/ new Vector4(); 15904const _v41 = /*@__PURE__*/ new Vector4(); 15905const _v42 = /*@__PURE__*/ new Vector4(); 15906 15907/** 15908 * A geometric triangle as defined by three vectors representing its three corners. 15909 */ 15910class Triangle { 15911 15912 /** 15913 * Constructs a new triangle. 15914 * 15915 * @param {Vector3} [a=(0,0,0)] - The first corner of the triangle. 15916 * @param {Vector3} [b=(0,0,0)] - The second corner of the triangle. 15917 * @param {Vector3} [c=(0,0,0)] - The third corner of the triangle. 15918 */ 15919 constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) { 15920 15921 /** 15922 * The first corner of the triangle. 15923 * 15924 * @type {Vector3} 15925 */ 15926 this.a = a; 15927 15928 /** 15929 * The second corner of the triangle. 15930 * 15931 * @type {Vector3} 15932 */ 15933 this.b = b; 15934 15935 /** 15936 * The third corner of the triangle. 15937 * 15938 * @type {Vector3} 15939 */ 15940 this.c = c; 15941 15942 } 15943
vendor: 4,935 bytes, lines 15944-16102
15944 /** 15945 * Computes the normal vector of a triangle. 15946 * 15947 * @param {Vector3} a - The first corner of the triangle. 15948 * @param {Vector3} b - The second corner of the triangle. 15949 * @param {Vector3} c - The third corner of the triangle. 15950 * @param {Vector3} target - The target vector that is used to store the method's result. 15951 * @return {Vector3} The triangle's normal. 15952 */ 15953 static getNormal( a, b, c, target ) { 15954 15955 target.subVectors( c, b ); 15956 _v0$1.subVectors( a, b ); 15957 target.cross( _v0$1 ); 15958 15959 const targetLengthSq = target.lengthSq(); 15960 if ( targetLengthSq > 0 ) { 15961 15962 return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) ); 15963 15964 } 15965 15966 return target.set( 0, 0, 0 ); 15967 15968 } 15969 15970 /** 15971 * Computes a barycentric coordinates from the given vector. 15972 * Returns `null` if the triangle is degenerate. 15973 * 15974 * @param {Vector3} point - A point in 3D space. 15975 * @param {Vector3} a - The first corner of the triangle. 15976 * @param {Vector3} b - The second corner of the triangle. 15977 * @param {Vector3} c - The third corner of the triangle. 15978 * @param {Vector3} target - The target vector that is used to store the method's result. 15979 * @return {?Vector3} The barycentric coordinates for the given point 15980 */ 15981 static getBarycoord( point, a, b, c, target ) { 15982 15983 // based on: http://www.blackpawn.com/texts/pointinpoly/default.html 15984 15985 _v0$1.subVectors( c, a ); 15986 _v1$3.subVectors( b, a ); 15987 _v2$2.subVectors( point, a ); 15988 15989 const dot00 = _v0$1.dot( _v0$1 ); 15990 const dot01 = _v0$1.dot( _v1$3 ); 15991 const dot02 = _v0$1.dot( _v2$2 ); 15992 const dot11 = _v1$3.dot( _v1$3 ); 15993 const dot12 = _v1$3.dot( _v2$2 ); 15994 15995 const denom = ( dot00 * dot11 - dot01 * dot01 ); 15996 15997 // collinear or singular triangle 15998 if ( denom === 0 ) { 15999 16000 target.set( 0, 0, 0 ); 16001 return null; 16002 16003 } 16004 16005 const invDenom = 1 / denom; 16006 const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; 16007 const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; 16008 16009 // barycentric coordinates must always sum to 1 16010 return target.set( 1 - u - v, v, u ); 16011 16012 } 16013 16014 /** 16015 * Returns `true` if the given point, when projected onto the plane of the 16016 * triangle, lies within the triangle. 16017 * 16018 * @param {Vector3} point - The point in 3D space to test. 16019 * @param {Vector3} a - The first corner of the triangle. 16020 * @param {Vector3} b - The second corner of the triangle. 16021 * @param {Vector3} c - The third corner of the triangle. 16022 * @return {boolean} Whether the given point, when projected onto the plane of the 16023 * triangle, lies within the triangle or not. 16024 */ 16025 static containsPoint( point, a, b, c ) { 16026 16027 // if the triangle is degenerate then we can't contain a point 16028 if ( this.getBarycoord( point, a, b, c, _v3$2 ) === null ) { 16029 16030 return false; 16031 16032 } 16033 16034 return ( _v3$2.x >= 0 ) && ( _v3$2.y >= 0 ) && ( ( _v3$2.x + _v3$2.y ) <= 1 ); 16035 16036 } 16037 16038 /** 16039 * Computes the value barycentrically interpolated for the given point on the 16040 * triangle. Returns `null` if the triangle is degenerate. 16041 * 16042 * @param {Vector3} point - Position of interpolated point. 16043 * @param {Vector3} p1 - The first corner of the triangle. 16044 * @param {Vector3} p2 - The second corner of the triangle. 16045 * @param {Vector3} p3 - The third corner of the triangle. 16046 * @param {Vector3} v1 - Value to interpolate of first vertex. 16047 * @param {Vector3} v2 - Value to interpolate of second vertex. 16048 * @param {Vector3} v3 - Value to interpolate of third vertex. 16049 * @param {Vector3} target - The target vector that is used to store the method's result. 16050 * @return {?Vector3} The interpolated value. 16051 */ 16052 static getInterpolation( point, p1, p2, p3, v1, v2, v3, target ) { 16053 16054 if ( this.getBarycoord( point, p1, p2, p3, _v3$2 ) === null ) { 16055 16056 target.x = 0; 16057 target.y = 0; 16058 if ( 'z' in target ) target.z = 0; 16059 if ( 'w' in target ) target.w = 0; 16060 return null; 16061 16062 } 16063 16064 target.setScalar( 0 ); 16065 target.addScaledVector( v1, _v3$2.x ); 16066 target.addScaledVector( v2, _v3$2.y ); 16067 target.addScaledVector( v3, _v3$2.z ); 16068 16069 return target; 16070 16071 } 16072 16073 /** 16074 * Computes the value barycentrically interpolated for the given attribute and indices. 16075 * 16076 * @param {BufferAttribute} attr - The attribute to interpolate. 16077 * @param {number} i1 - Index of first vertex. 16078 * @param {number} i2 - Index of second vertex. 16079 * @param {number} i3 - Index of third vertex. 16080 * @param {Vector3} barycoord - The barycoordinate value to use to interpolate. 16081 * @param {Vector3} target - The target vector that is used to store the method's result. 16082 * @return {Vector3} The interpolated attribute value. 16083 */ 16084 static getInterpolatedAttribute( attr, i1, i2, i3, barycoord, target ) { 16085 16086 _v40.setScalar( 0 ); 16087 _v41.setScalar( 0 ); 16088 _v42.setScalar( 0 ); 16089 16090 _v40.fromBufferAttribute( attr, i1 ); 16091 _v41.fromBufferAttribute( attr, i2 ); 16092 _v42.fromBufferAttribute( attr, i3 ); 16093 16094 target.setScalar( 0 ); 16095 target.addScaledVector( _v40, barycoord.x ); 16096 target.addScaledVector( _v41, barycoord.y ); 16097 target.addScaledVector( _v42, barycoord.z ); 16098 16099 return target; 16100 16101 } 16102
vendor: 3,100 bytes, lines 16103-16215
16103 /** 16104 * Returns `true` if the triangle is oriented towards the given direction. 16105 * 16106 * @param {Vector3} a - The first corner of the triangle. 16107 * @param {Vector3} b - The second corner of the triangle. 16108 * @param {Vector3} c - The third corner of the triangle. 16109 * @param {Vector3} direction - The (normalized) direction vector. 16110 * @return {boolean} Whether the triangle is oriented towards the given direction or not. 16111 */ 16112 static isFrontFacing( a, b, c, direction ) { 16113 16114 _v0$1.subVectors( c, b ); 16115 _v1$3.subVectors( a, b ); 16116 16117 // strictly front facing 16118 return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false; 16119 16120 } 16121 16122 /** 16123 * Sets the triangle's vertices by copying the given values. 16124 * 16125 * @param {Vector3} a - The first corner of the triangle. 16126 * @param {Vector3} b - The second corner of the triangle. 16127 * @param {Vector3} c - The third corner of the triangle. 16128 * @return {Triangle} A reference to this triangle. 16129 */ 16130 set( a, b, c ) { 16131 16132 this.a.copy( a ); 16133 this.b.copy( b ); 16134 this.c.copy( c ); 16135 16136 return this; 16137 16138 } 16139 16140 /** 16141 * Sets the triangle's vertices by copying the given array values. 16142 * 16143 * @param {Array<Vector3>} points - An array with 3D points. 16144 * @param {number} i0 - The array index representing the first corner of the triangle. 16145 * @param {number} i1 - The array index representing the second corner of the triangle. 16146 * @param {number} i2 - The array index representing the third corner of the triangle. 16147 * @return {Triangle} A reference to this triangle. 16148 */ 16149 setFromPointsAndIndices( points, i0, i1, i2 ) { 16150 16151 this.a.copy( points[ i0 ] ); 16152 this.b.copy( points[ i1 ] ); 16153 this.c.copy( points[ i2 ] ); 16154 16155 return this; 16156 16157 } 16158 16159 /** 16160 * Sets the triangle's vertices by copying the given attribute values. 16161 * 16162 * @param {BufferAttribute} attribute - A buffer attribute with 3D points data. 16163 * @param {number} i0 - The attribute index representing the first corner of the triangle. 16164 * @param {number} i1 - The attribute index representing the second corner of the triangle. 16165 * @param {number} i2 - The attribute index representing the third corner of the triangle. 16166 * @return {Triangle} A reference to this triangle. 16167 */ 16168 setFromAttributeAndIndices( attribute, i0, i1, i2 ) { 16169 16170 this.a.fromBufferAttribute( attribute, i0 ); 16171 this.b.fromBufferAttribute( attribute, i1 ); 16172 this.c.fromBufferAttribute( attribute, i2 ); 16173 16174 return this; 16175 16176 } 16177 16178 /** 16179 * Returns a new triangle with copied values from this instance. 16180 * 16181 * @return {Triangle} A clone of this instance. 16182 */ 16183 clone() { 16184 16185 return new this.constructor().copy( this ); 16186 16187 } 16188 16189 /** 16190 * Copies the values of the given triangle to this instance. 16191 * 16192 * @param {Triangle} triangle - The triangle to copy. 16193 * @return {Triangle} A reference to this triangle. 16194 */ 16195 copy( triangle ) { 16196 16197 this.a.copy( triangle.a ); 16198 this.b.copy( triangle.b ); 16199 this.c.copy( triangle.c ); 16200 16201 return this; 16202 16203 } 16204 16205 /** 16206 * Computes the area of the triangle. 16207 * 16208 * @return {number} The triangle's area. 16209 */ 16210 getArea() { 16211 16212 _v0$1.subVectors( this.c, this.b ); 16213 _v1$3.subVectors( this.a, this.b ); 16214 16215 return _v0$1.cross( _v1$3
vendor: 5,857 bytes, lines 16215-16425
16215 ).length() * 0.5; 16216 16217 } 16218 16219 /** 16220 * Computes the midpoint of the triangle. 16221 * 16222 * @param {Vector3} target - The target vector that is used to store the method's result. 16223 * @return {Vector3} The triangle's midpoint. 16224 */ 16225 getMidpoint( target ) { 16226 16227 return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); 16228 16229 } 16230 16231 /** 16232 * Computes the normal of the triangle. 16233 * 16234 * @param {Vector3} target - The target vector that is used to store the method's result. 16235 * @return {Vector3} The triangle's normal. 16236 */ 16237 getNormal( target ) { 16238 16239 return Triangle.getNormal( this.a, this.b, this.c, target ); 16240 16241 } 16242 16243 /** 16244 * Computes a plane the triangle lies within. 16245 * 16246 * @param {Plane} target - The target vector that is used to store the method's result. 16247 * @return {Plane} The plane the triangle lies within. 16248 */ 16249 getPlane( target ) { 16250 16251 return target.setFromCoplanarPoints( this.a, this.b, this.c ); 16252 16253 } 16254 16255 /** 16256 * Computes a barycentric coordinates from the given vector. 16257 * Returns `null` if the triangle is degenerate. 16258 * 16259 * @param {Vector3} point - A point in 3D space. 16260 * @param {Vector3} target - The target vector that is used to store the method's result. 16261 * @return {?Vector3} The barycentric coordinates for the given point 16262 */ 16263 getBarycoord( point, target ) { 16264 16265 return Triangle.getBarycoord( point, this.a, this.b, this.c, target ); 16266 16267 } 16268 16269 /** 16270 * Computes the value barycentrically interpolated for the given point on the 16271 * triangle. Returns `null` if the triangle is degenerate. 16272 * 16273 * @param {Vector3} point - Position of interpolated point. 16274 * @param {Vector3} v1 - Value to interpolate of first vertex. 16275 * @param {Vector3} v2 - Value to interpolate of second vertex. 16276 * @param {Vector3} v3 - Value to interpolate of third vertex. 16277 * @param {Vector3} target - The target vector that is used to store the method's result. 16278 * @return {?Vector3} The interpolated value. 16279 */ 16280 getInterpolation( point, v1, v2, v3, target ) { 16281 16282 return Triangle.getInterpolation( point, this.a, this.b, this.c, v1, v2, v3, target ); 16283 16284 } 16285 16286 /** 16287 * Returns `true` if the given point, when projected onto the plane of the 16288 * triangle, lies within the triangle. 16289 * 16290 * @param {Vector3} point - The point in 3D space to test. 16291 * @return {boolean} Whether the given point, when projected onto the plane of the 16292 * triangle, lies within the triangle or not. 16293 */ 16294 containsPoint( point ) { 16295 16296 return Triangle.containsPoint( point, this.a, this.b, this.c ); 16297 16298 } 16299 16300 /** 16301 * Returns `true` if the triangle is oriented towards the given direction. 16302 * 16303 * @param {Vector3} direction - The (normalized) direction vector. 16304 * @return {boolean} Whether the triangle is oriented towards the given direction or not. 16305 */ 16306 isFrontFacing( direction ) { 16307 16308 return Triangle.isFrontFacing( this.a, this.b, this.c, direction ); 16309 16310 } 16311 16312 /** 16313 * Returns `true` if this triangle intersects with the given box. 16314 * 16315 * @param {Box3} box - The box to intersect. 16316 * @return {boolean} Whether this triangle intersects with the given box or not. 16317 */ 16318 intersectsBox( box ) { 16319 16320 return box.intersectsTriangle( this ); 16321 16322 } 16323 16324 /** 16325 * Returns the closest point on the triangle to the given point. 16326 * 16327 * @param {Vector3} p - The point to compute the closest point for. 16328 * @param {Vector3} target - The target vector that is used to store the method's result. 16329 * @return {Vector3} The closest point on the triangle. 16330 */ 16331 closestPointToPoint( p, target ) { 16332 16333 const a = this.a, b = this.b, c = this.c; 16334 let v, w; 16335 16336 // algorithm thanks to Real-Time Collision Detection by Christer Ericson, 16337 // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc., 16338 // under the accompanying license; see chapter 5.1.5 for detailed explanation. 16339 // basically, we're distinguishing which of the voronoi regions of the triangle 16340 // the point lies in with the minimum amount of redundant computation. 16341 16342 _vab.subVectors( b, a ); 16343 _vac.subVectors( c, a ); 16344 _vap.subVectors( p, a ); 16345 const d1 = _vab.dot( _vap ); 16346 const d2 = _vac.dot( _vap ); 16347 if ( d1 <= 0 && d2 <= 0 ) { 16348 16349 // vertex region of A; barycentric coords (1, 0, 0) 16350 return target.copy( a ); 16351 16352 } 16353 16354 _vbp.subVectors( p, b ); 16355 const d3 = _vab.dot( _vbp ); 16356 const d4 = _vac.dot( _vbp ); 16357 if ( d3 >= 0 && d4 <= d3 ) { 16358 16359 // vertex region of B; barycentric coords (0, 1, 0) 16360 return target.copy( b ); 16361 16362 } 16363 16364 const vc = d1 * d4 - d3 * d2; 16365 if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) { 16366 16367 v = d1 / ( d1 - d3 ); 16368 // edge region of AB; barycentric coords (1-v, v, 0) 16369 return target.copy( a ).addScaledVector( _vab, v ); 16370 16371 } 16372 16373 _vcp.subVectors( p, c ); 16374 const d5 = _vab.dot( _vcp ); 16375 const d6 = _vac.dot( _vcp ); 16376 if ( d6 >= 0 && d5 <= d6 ) { 16377 16378 // vertex region of C; barycentric coords (0, 0, 1) 16379 return target.copy( c ); 16380 16381 } 16382 16383 const vb = d5 * d2 - d1 * d6; 16384 if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) { 16385 16386 w = d2 / ( d2 - d6 ); 16387 // edge region of AC; barycentric coords (1-w, 0, w) 16388 return target.copy( a ).addScaledVector( _vac, w ); 16389 16390 } 16391 16392 const va = d3 * d6 - d5 * d4; 16393 if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) { 16394 16395 _vbc.subVectors( c, b ); 16396 w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) ); 16397 // edge region of BC; barycentric coords (0, 1-w, w) 16398 return target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC 16399 16400 } 16401 16402 // face region 16403 const denom = 1 / ( va + vb + vc ); 16404 // u = va * denom 16405 v = vb * denom; 16406 w = vc * denom; 16407 16408 return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w ); 16409 16410 } 16411 16412 /** 16413 * Returns `true` if this triangle is equal with the given one. 16414 * 16415 * @param {Triangle} triangle - The triangle to test for equality. 16416 * @return {boolean} Whether this triangle is equal with the given one. 16417 */ 16418 equals( triangle ) { 16419 16420 return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); 16421 16422 } 16423 16424} 16425
vendor: 9,866 bytes, lines 16426-16703
16426const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, 16427 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, 16428 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, 16429 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, 16430 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, 16431 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, 16432 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, 16433 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, 16434 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, 16435 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, 16436 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, 16437 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, 16438 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, 16439 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, 16440 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, 16441 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, 16442 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, 16443 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, 16444 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, 16445 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, 16446 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, 16447 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, 16448 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, 16449 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; 16450 16451const _hslA = { h: 0, s: 0, l: 0 }; 16452const _hslB = { h: 0, s: 0, l: 0 }; 16453 16454function hue2rgb( p, q, t ) { 16455 16456 if ( t < 0 ) t += 1; 16457 if ( t > 1 ) t -= 1; 16458 if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; 16459 if ( t < 1 / 2 ) return q; 16460 if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); 16461 return p; 16462 16463} 16464 16465/** 16466 * A Color instance is represented by RGB components in the linear <i>working 16467 * color space</i>, which defaults to `LinearSRGBColorSpace`. Inputs 16468 * conventionally using `SRGBColorSpace` (such as hexadecimals and CSS 16469 * strings) are converted to the working color space automatically. 16470 * 16471 * ```js 16472 * // converted automatically from SRGBColorSpace to LinearSRGBColorSpace 16473 * const color = new THREE.Color().setHex( 0x112233 ); 16474 * ``` 16475 * Source color spaces may be specified explicitly, to ensure correct conversions. 16476 * ```js 16477 * // assumed already LinearSRGBColorSpace; no conversion 16478 * const color = new THREE.Color().setRGB( 0.5, 0.5, 0.5 ); 16479 * 16480 * // converted explicitly from SRGBColorSpace to LinearSRGBColorSpace 16481 * const color = new THREE.Color().setRGB( 0.5, 0.5, 0.5, SRGBColorSpace ); 16482 * ``` 16483 * If THREE.ColorManagement is disabled, no conversions occur. For details, 16484 * see <i>Color management</i>. Iterating through a Color instance will yield 16485 * its components (r, g, b) in the corresponding order. A Color can be initialised 16486 * in any of the following ways: 16487 * ```js 16488 * //empty constructor - will default white 16489 * const color1 = new THREE.Color(); 16490 * 16491 * //Hexadecimal color (recommended) 16492 * const color2 = new THREE.Color( 0xff0000 ); 16493 * 16494 * //RGB string 16495 * const color3 = new THREE.Color("rgb(255, 0, 0)"); 16496 * const color4 = new THREE.Color("rgb(100%, 0%, 0%)"); 16497 * 16498 * //X11 color name - all 140 color names are supported. 16499 * //Note the lack of CamelCase in the name 16500 * const color5 = new THREE.Color( 'skyblue' ); 16501 * //HSL string 16502 * const color6 = new THREE.Color("hsl(0, 100%, 50%)"); 16503 * 16504 * //Separate RGB values between 0 and 1 16505 * const color7 = new THREE.Color( 1, 0, 0 ); 16506 * ``` 16507 */ 16508class Color { 16509 16510 /** 16511 * Constructs a new color. 16512 * 16513 * Note that standard method of specifying color in three.js is with a hexadecimal triplet, 16514 * and that method is used throughout the rest of the documentation. 16515 * 16516 * @param {(number|string|Color)} [r] - The red component of the color. If `g` and `b` are 16517 * not provided, it can be hexadecimal triplet, a CSS-style string or another `Color` instance. 16518 * @param {number} [g] - The green component. 16519 * @param {number} [b] - The blue component. 16520 */ 16521 constructor( r, g, b ) { 16522 16523 /** 16524 * This flag can be used for type testing. 16525 * 16526 * @type {boolean} 16527 * @readonly 16528 * @default true 16529 */ 16530 this.isColor = true; 16531 16532 /** 16533 * The red component. 16534 * 16535 * @type {number} 16536 * @default 1 16537 */ 16538 this.r = 1; 16539 16540 /** 16541 * The green component. 16542 * 16543 * @type {number} 16544 * @default 1 16545 */ 16546 this.g = 1; 16547 16548 /** 16549 * The blue component. 16550 * 16551 * @type {number} 16552 * @default 1 16553 */ 16554 this.b = 1; 16555 16556 return this.set( r, g, b ); 16557 16558 } 16559 16560 /** 16561 * Sets the colors's components from the given values. 16562 * 16563 * @param {(number|string|Color)} [r] - The red component of the color. If `g` and `b` are 16564 * not provided, it can be hexadecimal triplet, a CSS-style string or another `Color` instance. 16565 * @param {number} [g] - The green component. 16566 * @param {number} [b] - The blue component. 16567 * @return {Color} A reference to this color. 16568 */ 16569 set( r, g, b ) { 16570 16571 if ( g === undefined && b === undefined ) { 16572 16573 // r is THREE.Color, hex or string 16574 16575 const value = r; 16576 16577 if ( value && value.isColor ) { 16578 16579 this.copy( value ); 16580 16581 } else if ( typeof value === 'number' ) { 16582 16583 this.setHex( value ); 16584 16585 } else if ( typeof value === 'string' ) { 16586 16587 this.setStyle( value ); 16588 16589 } 16590 16591 } else { 16592 16593 this.setRGB( r, g, b ); 16594 16595 } 16596 16597 return this; 16598 16599 } 16600 16601 /** 16602 * Sets the colors's components to the given scalar value. 16603 * 16604 * @param {number} scalar - The scalar value. 16605 * @return {Color} A reference to this color. 16606 */ 16607 setScalar( scalar ) { 16608 16609 this.r = scalar; 16610 this.g = scalar; 16611 this.b = scalar; 16612 16613 return this; 16614 16615 } 16616 16617 /** 16618 * Sets this color from a hexadecimal value. 16619 * 16620 * @param {number} hex - The hexadecimal value. 16621 * @param {string} [colorSpace=SRGBColorSpace] - The color space. 16622 * @return {Color} A reference to this color. 16623 */ 16624 setHex( hex, colorSpace = SRGBColorSpace ) { 16625 16626 hex = Math.floor( hex ); 16627 16628 this.r = ( hex >> 16 & 255 ) / 255; 16629 this.g = ( hex >> 8 & 255 ) / 255; 16630 this.b = ( hex & 255 ) / 255; 16631 16632 ColorManagement.toWorkingColorSpace( this, colorSpace ); 16633 16634 return this; 16635 16636 } 16637 16638 /** 16639 * Sets this color from RGB values. 16640 * 16641 * @param {number} r - Red channel value between `0.0` and `1.0`. 16642 * @param {number} g - Green channel value between `0.0` and `1.0`. 16643 * @param {number} b - Blue channel value between `0.0` and `1.0`. 16644 * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space. 16645 * @return {Color} A reference to this color. 16646 */ 16647 setRGB( r, g, b, colorSpace = ColorManagement.workingColorSpace ) { 16648 16649 this.r = r; 16650 this.g = g; 16651 this.b = b; 16652 16653 ColorManagement.toWorkingColorSpace( this, colorSpace ); 16654 16655 return this; 16656 16657 } 16658 16659 /** 16660 * Sets this color from RGB values. 16661 * 16662 * @param {number} h - Hue value between `0.0` and `1.0`. 16663 * @param {number} s - Saturation value between `0.0` and `1.0`. 16664 * @param {number} l - Lightness value between `0.0` and `1.0`. 16665 * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space. 16666 * @return {Color} A reference to this color. 16667 */ 16668 setHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) { 16669 16670 // h,s,l ranges are in 0.0 - 1.0 16671 h = euclideanModulo( h, 1 ); 16672 s = clamp( s, 0, 1 ); 16673 l = clamp( l, 0, 1 ); 16674 16675 if ( s === 0 ) { 16676 16677 this.r = this.g = this.b = l; 16678 16679 } else { 16680 16681 const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); 16682 const q = ( 2 * l ) - p; 16683 16684 this.r = hue2rgb( q, p, h + 1 / 3 ); 16685 this.g = hue2rgb( q, p, h ); 16686 this.b = hue2rgb( q, p, h - 1 / 3 ); 16687 16688 } 16689 16690 ColorManagement.toWorkingColorSpace( this, colorSpace ); 16691 16692 return this; 16693 16694 } 16695 16696 /** 16697 * Sets this color from a CSS-style string. For example, `rgb(250, 0,0)`, 16698 * `rgb(100%, 0%, 0%)`, `hsl(0, 100%, 50%)`, `#ff0000`, `#f00`, or `red` ( or 16699 * any [X11 color name]{@link https://en.wikipedia.org/wiki/X11_color_names#Color_name_chart} - 16700 * all 140 color names are supported). 16701 * 16702 * @param {string} style - Color as a CSS-style string. 16703 * @param {string}
vendor: 4,222 bytes, lines 16703-16909
16703 [colorSpace=SRGBColorSpace] - The color space. 16704 * @return {Color} A reference to this color. 16705 */ 16706 setStyle( style, colorSpace = SRGBColorSpace ) { 16707 16708 function handleAlpha( string ) { 16709 16710 if ( string === undefined ) return; 16711 16712 if ( parseFloat( string ) < 1 ) { 16713 16714 console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); 16715 16716 } 16717 16718 } 16719 16720 16721 let m; 16722 16723 if ( m = /^(\w+)\(([^\)]*)\)/.exec( style ) ) { 16724 16725 // rgb / hsl 16726 16727 let color; 16728 const name = m[ 1 ]; 16729 const components = m[ 2 ]; 16730 16731 switch ( name ) { 16732 16733 case 'rgb': 16734 case 'rgba': 16735 16736 if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { 16737 16738 // rgb(255,0,0) rgba(255,0,0,0.5) 16739 16740 handleAlpha( color[ 4 ] ); 16741 16742 return this.setRGB( 16743 Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255, 16744 Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255, 16745 Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255, 16746 colorSpace 16747 ); 16748 16749 } 16750 16751 if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { 16752 16753 // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5) 16754 16755 handleAlpha( color[ 4 ] ); 16756 16757 return this.setRGB( 16758 Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100, 16759 Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100, 16760 Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100, 16761 colorSpace 16762 ); 16763 16764 } 16765 16766 break; 16767 16768 case 'hsl': 16769 case 'hsla': 16770 16771 if ( color = /^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { 16772 16773 // hsl(120,50%,50%) hsla(120,50%,50%,0.5) 16774 16775 handleAlpha( color[ 4 ] ); 16776 16777 return this.setHSL( 16778 parseFloat( color[ 1 ] ) / 360, 16779 parseFloat( color[ 2 ] ) / 100, 16780 parseFloat( color[ 3 ] ) / 100, 16781 colorSpace 16782 ); 16783 16784 } 16785 16786 break; 16787 16788 default: 16789 16790 console.warn( 'THREE.Color: Unknown color model ' + style ); 16791 16792 } 16793 16794 } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) { 16795 16796 // hex color 16797 16798 const hex = m[ 1 ]; 16799 const size = hex.length; 16800 16801 if ( size === 3 ) { 16802 16803 // #ff0 16804 return this.setRGB( 16805 parseInt( hex.charAt( 0 ), 16 ) / 15, 16806 parseInt( hex.charAt( 1 ), 16 ) / 15, 16807 parseInt( hex.charAt( 2 ), 16 ) / 15, 16808 colorSpace 16809 ); 16810 16811 } else if ( size === 6 ) { 16812 16813 // #ff0000 16814 return this.setHex( parseInt( hex, 16 ), colorSpace ); 16815 16816 } else { 16817 16818 console.warn( 'THREE.Color: Invalid hex color ' + style ); 16819 16820 } 16821 16822 } else if ( style && style.length > 0 ) { 16823 16824 return this.setColorName( style, colorSpace ); 16825 16826 } 16827 16828 return this; 16829 16830 } 16831 16832 /** 16833 * Sets this color from a color name. Faster than {@link Color#setStyle} if 16834 * you don't need the other CSS-style formats. 16835 * 16836 * For convenience, the list of names is exposed in `Color.NAMES` as a hash. 16837 * ```js 16838 * Color.NAMES.aliceblue // returns 0xF0F8FF 16839 * ``` 16840 * 16841 * @param {string} style - The color name. 16842 * @param {string} [colorSpace=SRGBColorSpace] - The color space. 16843 * @return {Color} A reference to this color. 16844 */ 16845 setColorName( style, colorSpace = SRGBColorSpace ) { 16846 16847 // color keywords 16848 const hex = _colorKeywords[ style.toLowerCase() ]; 16849 16850 if ( hex !== undefined ) { 16851 16852 // red 16853 this.setHex( hex, colorSpace ); 16854 16855 } else { 16856 16857 // unknown color 16858 console.warn( 'THREE.Color: Unknown color ' + style ); 16859 16860 } 16861 16862 return this; 16863 16864 } 16865 16866 /** 16867 * Returns a new color with copied values from this instance. 16868 * 16869 * @return {Color} A clone of this instance. 16870 */ 16871 clone() { 16872 16873 return new this.constructor( this.r, this.g, this.b ); 16874 16875 } 16876 16877 /** 16878 * Copies the values of the given color to this instance. 16879 * 16880 * @param {Color} color - The color to copy. 16881 * @return {Color} A reference to this color. 16882 */ 16883 copy( color ) { 16884 16885 this.r = color.r; 16886 this.g = color.g; 16887 this.b = color.b; 16888 16889 return this; 16890 16891 } 16892 16893 /** 16894 * Copies the given color into this color, and then converts this color from 16895 * `SRGBColorSpace` to `LinearSRGBColorSpace`. 16896 * 16897 * @param {Color} color - The color to copy/convert. 16898 * @return {Color} A reference to this color. 16899 */ 16900 copySRGBToLinear( color ) { 16901 16902 this.r = SRGBToLinear( color.r ); 16903 this.g = SRGBToLinear( color.g ); 16904 this.b = SRGBToLinear( color.b ); 16905 16906 return this; 16907 16908 } 16909
vendor: 11,584 bytes, lines 16910-17385
16910 /** 16911 * Copies the given color into this color, and then converts this color from 16912 * `LinearSRGBColorSpace` to `SRGBColorSpace`. 16913 * 16914 * @param {Color} color - The color to copy/convert. 16915 * @return {Color} A reference to this color. 16916 */ 16917 copyLinearToSRGB( color ) { 16918 16919 this.r = LinearToSRGB( color.r ); 16920 this.g = LinearToSRGB( color.g ); 16921 this.b = LinearToSRGB( color.b ); 16922 16923 return this; 16924 16925 } 16926 16927 /** 16928 * Converts this color from `SRGBColorSpace` to `LinearSRGBColorSpace`. 16929 * 16930 * @return {Color} A reference to this color. 16931 */ 16932 convertSRGBToLinear() { 16933 16934 this.copySRGBToLinear( this ); 16935 16936 return this; 16937 16938 } 16939 16940 /** 16941 * Converts this color from `LinearSRGBColorSpace` to `SRGBColorSpace`. 16942 * 16943 * @return {Color} A reference to this color. 16944 */ 16945 convertLinearToSRGB() { 16946 16947 this.copyLinearToSRGB( this ); 16948 16949 return this; 16950 16951 } 16952 16953 /** 16954 * Returns the hexadecimal value of this color. 16955 * 16956 * @param {string} [colorSpace=SRGBColorSpace] - The color space. 16957 * @return {number} The hexadecimal value. 16958 */ 16959 getHex( colorSpace = SRGBColorSpace ) { 16960 16961 ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); 16962 16963 return Math.round( clamp( _color.r * 255, 0, 255 ) ) * 65536 + Math.round( clamp( _color.g * 255, 0, 255 ) ) * 256 + Math.round( clamp( _color.b * 255, 0, 255 ) ); 16964 16965 } 16966 16967 /** 16968 * Returns the hexadecimal value of this color as a string (for example, 'FFFFFF'). 16969 * 16970 * @param {string} [colorSpace=SRGBColorSpace] - The color space. 16971 * @return {string} The hexadecimal value as a string. 16972 */ 16973 getHexString( colorSpace = SRGBColorSpace ) { 16974 16975 return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( -6 ); 16976 16977 } 16978 16979 /** 16980 * Converts the colors RGB values into the HSL format and stores them into the 16981 * given target object. 16982 * 16983 * @param {{h:number,s:number,l:number}} target - The target object that is used to store the method's result. 16984 * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space. 16985 * @return {{h:number,s:number,l:number}} The HSL representation of this color. 16986 */ 16987 getHSL( target, colorSpace = ColorManagement.workingColorSpace ) { 16988 16989 // h,s,l ranges are in 0.0 - 1.0 16990 16991 ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); 16992 16993 const r = _color.r, g = _color.g, b = _color.b; 16994 16995 const max = Math.max( r, g, b ); 16996 const min = Math.min( r, g, b ); 16997 16998 let hue, saturation; 16999 const lightness = ( min + max ) / 2.0; 17000 17001 if ( min === max ) { 17002 17003 hue = 0; 17004 saturation = 0; 17005 17006 } else { 17007 17008 const delta = max - min; 17009 17010 saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); 17011 17012 switch ( max ) { 17013 17014 case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; 17015 case g: hue = ( b - r ) / delta + 2; break; 17016 case b: hue = ( r - g ) / delta + 4; break; 17017 17018 } 17019 17020 hue /= 6; 17021 17022 } 17023 17024 target.h = hue; 17025 target.s = saturation; 17026 target.l = lightness; 17027 17028 return target; 17029 17030 } 17031 17032 /** 17033 * Returns the RGB values of this color and stores them into the given target object. 17034 * 17035 * @param {Color} target - The target color that is used to store the method's result. 17036 * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space. 17037 * @return {Color} The RGB representation of this color. 17038 */ 17039 getRGB( target, colorSpace = ColorManagement.workingColorSpace ) { 17040 17041 ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); 17042 17043 target.r = _color.r; 17044 target.g = _color.g; 17045 target.b = _color.b; 17046 17047 return target; 17048 17049 } 17050 17051 /** 17052 * Returns the value of this color as a CSS style string. Example: `rgb(255,0,0)`. 17053 * 17054 * @param {string} [colorSpace=SRGBColorSpace] - The color space. 17055 * @return {string} The CSS representation of this color. 17056 */ 17057 getStyle( colorSpace = SRGBColorSpace ) { 17058 17059 ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); 17060 17061 const r = _color.r, g = _color.g, b = _color.b; 17062 17063 if ( colorSpace !== SRGBColorSpace ) { 17064 17065 // Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/). 17066 return `color(${ colorSpace } ${ r.toFixed( 3 ) } ${ g.toFixed( 3 ) } ${ b.toFixed( 3 ) })`; 17067 17068 } 17069 17070 return `rgb(${ Math.round( r * 255 ) },${ Math.round( g * 255 ) },${ Math.round( b * 255 ) })`; 17071 17072 } 17073 17074 /** 17075 * Adds the given HSL values to this color's values. 17076 * Internally, this converts the color's RGB values to HSL, adds HSL 17077 * and then converts the color back to RGB. 17078 * 17079 * @param {number} h - Hue value between `0.0` and `1.0`. 17080 * @param {number} s - Saturation value between `0.0` and `1.0`. 17081 * @param {number} l - Lightness value between `0.0` and `1.0`. 17082 * @return {Color} A reference to this color. 17083 */ 17084 offsetHSL( h, s, l ) { 17085 17086 this.getHSL( _hslA ); 17087 17088 return this.setHSL( _hslA.h + h, _hslA.s + s, _hslA.l + l ); 17089 17090 } 17091 17092 /** 17093 * Adds the RGB values of the given color to the RGB values of this color. 17094 * 17095 * @param {Color} color - The color to add. 17096 * @return {Color} A reference to this color. 17097 */ 17098 add( color ) { 17099 17100 this.r += color.r; 17101 this.g += color.g; 17102 this.b += color.b; 17103 17104 return this; 17105 17106 } 17107 17108 /** 17109 * Adds the RGB values of the given colors and stores the result in this instance. 17110 * 17111 * @param {Color} color1 - The first color. 17112 * @param {Color} color2 - The second color. 17113 * @return {Color} A reference to this color. 17114 */ 17115 addColors( color1, color2 ) { 17116 17117 this.r = color1.r + color2.r; 17118 this.g = color1.g + color2.g; 17119 this.b = color1.b + color2.b; 17120 17121 return this; 17122 17123 } 17124 17125 /** 17126 * Adds the given scalar value to the RGB values of this color. 17127 * 17128 * @param {number} s - The scalar to add. 17129 * @return {Color} A reference to this color. 17130 */ 17131 addScalar( s ) { 17132 17133 this.r += s; 17134 this.g += s; 17135 this.b += s; 17136 17137 return this; 17138 17139 } 17140 17141 /** 17142 * Subtracts the RGB values of the given color from the RGB values of this color. 17143 * 17144 * @param {Color} color - The color to subtract. 17145 * @return {Color} A reference to this color. 17146 */ 17147 sub( color ) { 17148 17149 this.r = Math.max( 0, this.r - color.r ); 17150 this.g = Math.max( 0, this.g - color.g ); 17151 this.b = Math.max( 0, this.b - color.b ); 17152 17153 return this; 17154 17155 } 17156 17157 /** 17158 * Multiplies the RGB values of the given color with the RGB values of this color. 17159 * 17160 * @param {Color} color - The color to multiply. 17161 * @return {Color} A reference to this color. 17162 */ 17163 multiply( color ) { 17164 17165 this.r *= color.r; 17166 this.g *= color.g; 17167 this.b *= color.b; 17168 17169 return this; 17170 17171 } 17172 17173 /** 17174 * Multiplies the given scalar value with the RGB values of this color. 17175 * 17176 * @param {number} s - The scalar to multiply. 17177 * @return {Color} A reference to this color. 17178 */ 17179 multiplyScalar( s ) { 17180 17181 this.r *= s; 17182 this.g *= s; 17183 this.b *= s; 17184 17185 return this; 17186 17187 } 17188 17189 /** 17190 * Linearly interpolates this color's RGB values toward the RGB values of the 17191 * given color. The alpha argument can be thought of as the ratio between 17192 * the two colors, where `0.0` is this color and `1.0` is the first argument. 17193 * 17194 * @param {Color} color - The color to converge on. 17195 * @param {number} alpha - The interpolation factor in the closed interval `[0,1]`. 17196 * @return {Color} A reference to this color. 17197 */ 17198 lerp( color, alpha ) { 17199 17200 this.r += ( color.r - this.r ) * alpha; 17201 this.g += ( color.g - this.g ) * alpha; 17202 this.b += ( color.b - this.b ) * alpha; 17203 17204 return this; 17205 17206 } 17207 17208 /** 17209 * Linearly interpolates between the given colors and stores the result in this instance. 17210 * The alpha argument can be thought of as the ratio between the two colors, where `0.0` 17211 * is the first and `1.0` is the second color. 17212 * 17213 * @param {Color} color1 - The first color. 17214 * @param {Color} color2 - The second color. 17215 * @param {number} alpha - The interpolation factor in the closed interval `[0,1]`. 17216 * @return {Color} A reference to this color. 17217 */ 17218 lerpColors( color1, color2, alpha ) { 17219 17220 this.r = color1.r + ( color2.r - color1.r ) * alpha; 17221 this.g = color1.g + ( color2.g - color1.g ) * alpha; 17222 this.b = color1.b + ( color2.b - color1.b ) * alpha; 17223 17224 return this; 17225 17226 } 17227 17228 /** 17229 * Linearly interpolates this color's HSL values toward the HSL values of the 17230 * given color. It differs from {@link Color#lerp} by not interpolating straight 17231 * from one color to the other, but instead going through all the hues in between 17232 * those two colors. The alpha argument can be thought of as the ratio between 17233 * the two colors, where 0.0 is this color and 1.0 is the first argument. 17234 * 17235 * @param {Color} color - The color to converge on. 17236 * @param {number} alpha - The interpolation factor in the closed interval `[0,1]`. 17237 * @return {Color} A reference to this color. 17238 */ 17239 lerpHSL( color, alpha ) { 17240 17241 this.getHSL( _hslA ); 17242 color.getHSL( _hslB ); 17243 17244 const h = lerp( _hslA.h, _hslB.h, alpha ); 17245 const s = lerp( _hslA.s, _hslB.s, alpha ); 17246 const l = lerp( _hslA.l, _hslB.l, alpha ); 17247 17248 this.setHSL( h, s, l ); 17249 17250 return this; 17251 17252 } 17253 17254 /** 17255 * Sets the color's RGB components from the given 3D vector. 17256 * 17257 * @param {Vector3} v - The vector to set. 17258 * @return {Color} A reference to this color. 17259 */ 17260 setFromVector3( v ) { 17261 17262 this.r = v.x; 17263 this.g = v.y; 17264 this.b = v.z; 17265 17266 return this; 17267 17268 } 17269 17270 /** 17271 * Transforms this color with the given 3x3 matrix. 17272 * 17273 * @param {Matrix3} m - The matrix. 17274 * @return {Color} A reference to this color. 17275 */ 17276 applyMatrix3( m ) { 17277 17278 const r = this.r, g = this.g, b = this.b; 17279 const e = m.elements; 17280 17281 this.r = e[ 0 ] * r + e[ 3 ] * g + e[ 6 ] * b; 17282 this.g = e[ 1 ] * r + e[ 4 ] * g + e[ 7 ] * b; 17283 this.b = e[ 2 ] * r + e[ 5 ] * g + e[ 8 ] * b; 17284 17285 return this; 17286 17287 } 17288 17289 /** 17290 * Returns `true` if this color is equal with the given one. 17291 * 17292 * @param {Color} c - The color to test for equality. 17293 * @return {boolean} Whether this bounding color is equal with the given one. 17294 */ 17295 equals( c ) { 17296 17297 return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); 17298 17299 } 17300 17301 /** 17302 * Sets this color's RGB components from the given array. 17303 * 17304 * @param {Array<number>} array - An array holding the RGB values. 17305 * @param {number} [offset=0] - The offset into the array. 17306 * @return {Color} A reference to this color. 17307 */ 17308 fromArray( array, offset = 0 ) { 17309 17310 this.r = array[ offset ]; 17311 this.g = array[ offset + 1 ]; 17312 this.b = array[ offset + 2 ]; 17313 17314 return this; 17315 17316 } 17317 17318 /** 17319 * Writes the RGB components of this color to the given array. If no array is provided, 17320 * the method returns a new instance. 17321 * 17322 * @param {Array<number>} [array=[]] - The target array holding the color components. 17323 * @param {number} [offset=0] - Index of the first element in the array. 17324 * @return {Array<number>} The color components. 17325 */ 17326 toArray( array = [], offset = 0 ) { 17327 17328 array[ offset ] = this.r; 17329 array[ offset + 1 ] = this.g; 17330 array[ offset + 2 ] = this.b; 17331 17332 return array; 17333 17334 } 17335 17336 /** 17337 * Sets the components of this color from the given buffer attribute. 17338 * 17339 * @param {BufferAttribute} attribute - The buffer attribute holding color data. 17340 * @param {number} index - The index into the attribute. 17341 * @return {Color} A reference to this color. 17342 */ 17343 fromBufferAttribute( attribute, index ) { 17344 17345 this.r = attribute.getX( index ); 17346 this.g = attribute.getY( index ); 17347 this.b = attribute.getZ( index ); 17348 17349 return this; 17350 17351 } 17352 17353 /** 17354 * This methods defines the serialization result of this class. Returns the color 17355 * as a hexadecimal value. 17356 * 17357 * @return {number} The hexadecimal value. 17358 */ 17359 toJSON() { 17360 17361 return this.getHex(); 17362 17363 } 17364 17365 *[ Symbol.iterator ]() { 17366 17367 yield this.r; 17368 yield this.g; 17369 yield this.b; 17370 17371 } 17372 17373} 17374 17375const _color = /*@__PURE__*/ new Color(); 17376 17377/** 17378 * A dictionary with X11 color names. 17379 * 17380 * Note that multiple words such as Dark Orange become the string 'darkorange'. 17381 * 17382 * @static 17383 * @type {Object} 17384 */ 17385Color.NAMES = _colorKeywords;
vendor: 15,189 bytes, lines 17385-17906
17385 17386 17387let _materialId = 0; 17388 17389/** 17390 * Abstract base class for materials. 17391 * 17392 * Materials define the appearance of renderable 3D objects. 17393 * 17394 * @abstract 17395 * @augments EventDispatcher 17396 */ 17397class Material extends EventDispatcher { 17398 17399 /** 17400 * Constructs a new material. 17401 */ 17402 constructor() { 17403 17404 super(); 17405 17406 /** 17407 * This flag can be used for type testing. 17408 * 17409 * @type {boolean} 17410 * @readonly 17411 * @default true 17412 */ 17413 this.isMaterial = true; 17414 17415 /** 17416 * The ID of the material. 17417 * 17418 * @name Material#id 17419 * @type {number} 17420 * @readonly 17421 */ 17422 Object.defineProperty( this, 'id', { value: _materialId ++ } ); 17423 17424 /** 17425 * The UUID of the material. 17426 * 17427 * @type {string} 17428 * @readonly 17429 */ 17430 this.uuid = generateUUID(); 17431 17432 /** 17433 * The name of the material. 17434 * 17435 * @type {string} 17436 */ 17437 this.name = ''; 17438 17439 /** 17440 * The type property is used for detecting the object type 17441 * in context of serialization/deserialization. 17442 * 17443 * @type {string} 17444 * @readonly 17445 */ 17446 this.type = 'Material'; 17447 17448 /** 17449 * Defines the blending type of the material. 17450 * 17451 * It must be set to `CustomBlending` if custom blending properties like 17452 * {@link Material#blendSrc}, {@link Material#blendDst} or {@link Material#blendEquation} 17453 * should have any effect. 17454 * 17455 * @type {(NoBlending|NormalBlending|AdditiveBlending|SubtractiveBlending|MultiplyBlending|CustomBlending)} 17456 * @default NormalBlending 17457 */ 17458 this.blending = NormalBlending; 17459 17460 /** 17461 * Defines which side of faces will be rendered - front, back or both. 17462 * 17463 * @type {(FrontSide|BackSide|DoubleSide)} 17464 * @default FrontSide 17465 */ 17466 this.side = FrontSide; 17467 17468 /** 17469 * If set to `true`, vertex colors should be used. 17470 * 17471 * The engine supports RGB and RGBA vertex colors depending on whether a three (RGB) or 17472 * four (RGBA) component color buffer attribute is used. 17473 * 17474 * @type {boolean} 17475 * @default false 17476 */ 17477 this.vertexColors = false; 17478 17479 /** 17480 * Defines how transparent the material is. 17481 * A value of `0.0` indicates fully transparent, `1.0` is fully opaque. 17482 * 17483 * If the {@link Material#transparent} is not set to `true`, 17484 * the material will remain fully opaque and this value will only affect its color. 17485 * 17486 * @type {number} 17487 * @default 1 17488 */ 17489 this.opacity = 1; 17490 17491 /** 17492 * Defines whether this material is transparent. This has an effect on 17493 * rendering as transparent objects need special treatment and are rendered 17494 * after non-transparent objects. 17495 * 17496 * When set to true, the extent to which the material is transparent is 17497 * controlled by {@link Material#opacity}. 17498 * 17499 * @type {boolean} 17500 * @default false 17501 */ 17502 this.transparent = false; 17503 17504 /** 17505 * Enables alpha hashed transparency, an alternative to {@link Material#transparent} or 17506 * {@link Material#alphaTest}. The material will not be rendered if opacity is lower than 17507 * a random threshold. Randomization introduces some grain or noise, but approximates alpha 17508 * blending without the associated problems of sorting. Using TAA can reduce the resulting noise. 17509 * 17510 * @type {boolean} 17511 * @default false 17512 */ 17513 this.alphaHash = false; 17514 17515 /** 17516 * Defines the blending source factor. 17517 * 17518 * @type {(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)} 17519 * @default SrcAlphaFactor 17520 */ 17521 this.blendSrc = SrcAlphaFactor; 17522 17523 /** 17524 * Defines the blending destination factor. 17525 * 17526 * @type {(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)} 17527 * @default OneMinusSrcAlphaFactor 17528 */ 17529 this.blendDst = OneMinusSrcAlphaFactor; 17530 17531 /** 17532 * Defines the blending equation. 17533 * 17534 * @type {(AddEquation|SubtractEquation|ReverseSubtractEquation|MinEquation|MaxEquation)} 17535 * @default AddEquation 17536 */ 17537 this.blendEquation = AddEquation; 17538 17539 /** 17540 * Defines the blending source alpha factor. 17541 * 17542 * @type {?(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)} 17543 * @default null 17544 */ 17545 this.blendSrcAlpha = null; 17546 17547 /** 17548 * Defines the blending destination alpha factor. 17549 * 17550 * @type {?(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)} 17551 * @default null 17552 */ 17553 this.blendDstAlpha = null; 17554 17555 /** 17556 * Defines the blending equation of the alpha channel. 17557 * 17558 * @type {?(AddEquation|SubtractEquation|ReverseSubtractEquation|MinEquation|MaxEquation)} 17559 * @default null 17560 */ 17561 this.blendEquationAlpha = null; 17562 17563 /** 17564 * Represents the RGB values of the constant blend color. 17565 * 17566 * This property has only an effect when using custom blending with `ConstantColor` or `OneMinusConstantColor`. 17567 * 17568 * @type {Color} 17569 * @default (0,0,0) 17570 */ 17571 this.blendColor = new Color( 0, 0, 0 ); 17572 17573 /** 17574 * Represents the alpha value of the constant blend color. 17575 * 17576 * This property has only an effect when using custom blending with `ConstantAlpha` or `OneMinusConstantAlpha`. 17577 * 17578 * @type {number} 17579 * @default 0 17580 */ 17581 this.blendAlpha = 0; 17582 17583 /** 17584 * Defines the depth function. 17585 * 17586 * @type {(NeverDepth|AlwaysDepth|LessDepth|LessEqualDepth|EqualDepth|GreaterEqualDepth|GreaterDepth|NotEqualDepth)} 17587 * @default LessEqualDepth 17588 */ 17589 this.depthFunc = LessEqualDepth; 17590 17591 /** 17592 * Whether to have depth test enabled when rendering this material. 17593 * When the depth test is disabled, the depth write will also be implicitly disabled. 17594 * 17595 * @type {boolean} 17596 * @default true 17597 */ 17598 this.depthTest = true; 17599 17600 /** 17601 * Whether rendering this material has any effect on the depth buffer. 17602 * 17603 * When drawing 2D overlays it can be useful to disable the depth writing in 17604 * order to layer several things together without creating z-index artifacts. 17605 * 17606 * @type {boolean} 17607 * @default true 17608 */ 17609 this.depthWrite = true; 17610 17611 /** 17612 * The bit mask to use when writing to the stencil buffer. 17613 * 17614 * @type {number} 17615 * @default 0xff 17616 */ 17617 this.stencilWriteMask = 0xff; 17618 17619 /** 17620 * The stencil comparison function to use. 17621 * 17622 * @type {NeverStencilFunc|LessStencilFunc|EqualStencilFunc|LessEqualStencilFunc|GreaterStencilFunc|NotEqualStencilFunc|GreaterEqualStencilFunc|AlwaysStencilFunc} 17623 * @default AlwaysStencilFunc 17624 */ 17625 this.stencilFunc = AlwaysStencilFunc; 17626 17627 /** 17628 * The value to use when performing stencil comparisons or stencil operations. 17629 * 17630 * @type {number} 17631 * @default 0 17632 */ 17633 this.stencilRef = 0; 17634 17635 /** 17636 * The bit mask to use when comparing against the stencil buffer. 17637 * 17638 * @type {number} 17639 * @default 0xff 17640 */ 17641 this.stencilFuncMask = 0xff; 17642 17643 /** 17644 * Which stencil operation to perform when the comparison function returns `false`. 17645 * 17646 * @type {ZeroStencilOp|KeepStencilOp|ReplaceStencilOp|IncrementStencilOp|DecrementStencilOp|IncrementWrapStencilOp|DecrementWrapStencilOp|InvertStencilOp} 17647 * @default KeepStencilOp 17648 */ 17649 this.stencilFail = KeepStencilOp; 17650 17651 /** 17652 * Which stencil operation to perform when the comparison function returns 17653 * `true` but the depth test fails. 17654 * 17655 * @type {ZeroStencilOp|KeepStencilOp|ReplaceStencilOp|IncrementStencilOp|DecrementStencilOp|IncrementWrapStencilOp|DecrementWrapStencilOp|InvertStencilOp} 17656 * @default KeepStencilOp 17657 */ 17658 this.stencilZFail = KeepStencilOp; 17659 17660 /** 17661 * Which stencil operation to perform when the comparison function returns 17662 * `true` and the depth test passes. 17663 * 17664 * @type {ZeroStencilOp|KeepStencilOp|ReplaceStencilOp|IncrementStencilOp|DecrementStencilOp|IncrementWrapStencilOp|DecrementWrapStencilOp|InvertStencilOp} 17665 * @default KeepStencilOp 17666 */ 17667 this.stencilZPass = KeepStencilOp; 17668 17669 /** 17670 * Whether stencil operations are performed against the stencil buffer. In 17671 * order to perform writes or comparisons against the stencil buffer this 17672 * value must be `true`. 17673 * 17674 * @type {boolean} 17675 * @default false 17676 */ 17677 this.stencilWrite = false; 17678 17679 /** 17680 * User-defined clipping planes specified as THREE.Plane objects in world 17681 * space. These planes apply to the objects this material is attached to. 17682 * Points in space whose signed distance to the plane is negative are clipped 17683 * (not rendered). This requires {@link WebGLRenderer#localClippingEnabled} to 17684 * be `true`. 17685 * 17686 * @type {?Array<Plane>} 17687 * @default null 17688 */ 17689 this.clippingPlanes = null; 17690 17691 /** 17692 * Changes the behavior of clipping planes so that only their intersection is 17693 * clipped, rather than their union. 17694 * 17695 * @type {boolean} 17696 * @default false 17697 */ 17698 this.clipIntersection = false; 17699 17700 /** 17701 * Defines whether to clip shadows according to the clipping planes specified 17702 * on this material. 17703 * 17704 * @type {boolean} 17705 * @default false 17706 */ 17707 this.clipShadows = false; 17708 17709 /** 17710 * Defines which side of faces cast shadows. If `null`, the side casting shadows 17711 * is determined as follows: 17712 * 17713 * - When {@link Material#side} is set to `FrontSide`, the back side cast shadows. 17714 * - When {@link Material#side} is set to `BackSide`, the front side cast shadows. 17715 * - When {@link Material#side} is set to `DoubleSide`, both sides cast shadows. 17716 * 17717 * @type {?(FrontSide|BackSide|DoubleSide)} 17718 * @default null 17719 */ 17720 this.shadowSide = null; 17721 17722 /** 17723 * Whether to render the material's color. 17724 * 17725 * This can be used in conjunction with {@link Object3D#renderOder} to create invisible 17726 * objects that occlude other objects. 17727 * 17728 * @type {boolean} 17729 * @default true 17730 */ 17731 this.colorWrite = true; 17732 17733 /** 17734 * Override the renderer's default precision for this material. 17735 * 17736 * @type {?('highp'|'mediump'|'lowp')} 17737 * @default null 17738 */ 17739 this.precision = null; 17740 17741 /** 17742 * Whether to use polygon offset or not. When enabled, each fragment's depth value will 17743 * be offset after it is interpolated from the depth values of the appropriate vertices. 17744 * The offset is added before the depth test is performed and before the value is written 17745 * into the depth buffer. 17746 * 17747 * Can be useful for rendering hidden-line images, for applying decals to surfaces, and for 17748 * rendering solids with highlighted edges. 17749 * 17750 * @type {boolean} 17751 * @default false 17752 */ 17753 this.polygonOffset = false; 17754 17755 /** 17756 * Specifies a scale factor that is used to create a variable depth offset for each polygon. 17757 * 17758 * @type {number} 17759 * @default 0 17760 */ 17761 this.polygonOffsetFactor = 0; 17762 17763 /** 17764 * Is multiplied by an implementation-specific value to create a constant depth offset. 17765 * 17766 * @type {number} 17767 * @default 0 17768 */ 17769 this.polygonOffsetUnits = 0; 17770 17771 /** 17772 * Whether to apply dithering to the color to remove the appearance of banding. 17773 * 17774 * @type {boolean} 17775 * @default false 17776 */ 17777 this.dithering = false; 17778 17779 /** 17780 * Whether alpha to coverage should be enabled or not. Can only be used with MSAA-enabled contexts 17781 * (meaning when the renderer was created with *antialias* parameter set to `true`). Enabling this 17782 * will smooth aliasing on clip plane edges and alphaTest-clipped edges. 17783 * 17784 * @type {boolean} 17785 * @default false 17786 */ 17787 this.alphaToCoverage = false; 17788 17789 /** 17790 * Whether to premultiply the alpha (transparency) value. 17791 * 17792 * @type {boolean} 17793 * @default false 17794 */ 17795 this.premultipliedAlpha = false; 17796 17797 /** 17798 * Whether double-sided, transparent objects should be rendered with a single pass or not. 17799 * 17800 * The engine renders double-sided, transparent objects with two draw calls (back faces first, 17801 * then front faces) to mitigate transparency artifacts. There are scenarios however where this 17802 * approach produces no quality gains but still doubles draw calls e.g. when rendering flat 17803 * vegetation like grass sprites. In these cases, set the `forceSinglePass` flag to `true` to 17804 * disable the two pass rendering to avoid performance issues. 17805 * 17806 * @type {boolean} 17807 * @default false 17808 */ 17809 this.forceSinglePass = false; 17810 17811 /** 17812 * Whether it's possible to override the material with {@link Scene#overrideMaterial} or not. 17813 * 17814 * @type {boolean} 17815 * @default true 17816 */ 17817 this.allowOverride = true; 17818 17819 /** 17820 * Defines whether 3D objects using this material are visible. 17821 * 17822 * @type {boolean} 17823 * @default true 17824 */ 17825 this.visible = true; 17826 17827 /** 17828 * Defines whether this material is tone mapped according to the renderer's tone mapping setting. 17829 * 17830 * It is ignored when rendering to a render target or using post processing or when using 17831 * `WebGPURenderer`. In all these cases, all materials are honored by tone mapping. 17832 * 17833 * @type {boolean} 17834 * @default true 17835 */ 17836 this.toneMapped = true; 17837 17838 /** 17839 * An object that can be used to store custom data about the Material. It 17840 * should not hold references to functions as these will not be cloned. 17841 * 17842 * @type {Object} 17843 */ 17844 this.userData = {}; 17845 17846 /** 17847 * This starts at `0` and counts how many times {@link Material#needsUpdate} is set to `true`. 17848 * 17849 * @type {number} 17850 * @readonly 17851 * @default 0 17852 */ 17853 this.version = 0; 17854 17855 this._alphaTest = 0; 17856 17857 } 17858 17859 /** 17860 * Sets the alpha value to be used when running an alpha test. The material 17861 * will not be rendered if the opacity is lower than this value. 17862 * 17863 * @type {number} 17864 * @readonly 17865 * @default 0 17866 */ 17867 get alphaTest() { 17868 17869 return this._alphaTest; 17870 17871 } 17872 17873 set alphaTest( value ) { 17874 17875 if ( this._alphaTest > 0 !== value > 0 ) { 17876 17877 this.version ++; 17878 17879 } 17880 17881 this._alphaTest = value; 17882 17883 } 17884 17885 /** 17886 * An optional callback that is executed immediately before the material is used to render a 3D object. 17887 * 17888 * This method can only be used when rendering with {@link WebGLRenderer}. 17889 * 17890 * @param {WebGLRenderer} renderer - The renderer. 17891 * @param {Scene} scene - The scene. 17892 * @param {Camera} camera - The camera that is used to render the scene. 17893 * @param {BufferGeometry} geometry - The 3D object's geometry. 17894 * @param {Object3D} object - The 3D object. 17895 * @param {Object} group - The geometry group data. 17896 */ 17897 onBeforeRender( /* renderer, scene, camera, geometry, object, group */ ) {} 17898 17899 /** 17900 * An optional callback that is executed immediately before the shader 17901 * program is compiled. This function is called with the shader source code 17902 * as a parameter. Useful for the modification of built-in materials. 17903 * 17904 * This method can only be used when rendering with {@link WebGLRenderer}. The 17905 * recommended approach when customizing materials is to use `WebGPURenderer` with the new 17906 * Node Material system and [TSL]
vendor: 10,207 bytes, lines 17906-18178
17906{@link https://github.com/mrdoob/three.js/wiki/Three.js-Shading-Language}. 17907 * 17908 * @param {{vertexShader:string,fragmentShader:string,uniforms:Object}} shaderobject - The object holds the uniforms and the vertex and fragment shader source. 17909 * @param {WebGLRenderer} renderer - A reference to the renderer. 17910 */ 17911 onBeforeCompile( /* shaderobject, renderer */ ) {} 17912 17913 /** 17914 * In case {@link Material#onBeforeCompile} is used, this callback can be used to identify 17915 * values of settings used in `onBeforeCompile()`, so three.js can reuse a cached 17916 * shader or recompile the shader for this material as needed. 17917 * 17918 * This method can only be used when rendering with {@link WebGLRenderer}. 17919 * 17920 * @return {string} The custom program cache key. 17921 */ 17922 customProgramCacheKey() { 17923 17924 return this.onBeforeCompile.toString(); 17925 17926 } 17927 17928 /** 17929 * This method can be used to set default values from parameter objects. 17930 * It is a generic implementation so it can be used with different types 17931 * of materials. 17932 * 17933 * @param {Object} [values] - The material values to set. 17934 */ 17935 setValues( values ) { 17936 17937 if ( values === undefined ) return; 17938 17939 for ( const key in values ) { 17940 17941 const newValue = values[ key ]; 17942 17943 if ( newValue === undefined ) { 17944 17945 console.warn( `THREE.Material: parameter '${ key }' has value of undefined.` ); 17946 continue; 17947 17948 } 17949 17950 const currentValue = this[ key ]; 17951 17952 if ( currentValue === undefined ) { 17953 17954 console.warn( `THREE.Material: '${ key }' is not a property of THREE.${ this.type }.` ); 17955 continue; 17956 17957 } 17958 17959 if ( currentValue && currentValue.isColor ) { 17960 17961 currentValue.set( newValue ); 17962 17963 } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) { 17964 17965 currentValue.copy( newValue ); 17966 17967 } else { 17968 17969 this[ key ] = newValue; 17970 17971 } 17972 17973 } 17974 17975 } 17976 17977 /** 17978 * Serializes the material into JSON. 17979 * 17980 * @param {?(Object|string)} meta - An optional value holding meta information about the serialization. 17981 * @return {Object} A JSON object representing the serialized material. 17982 * @see {@link ObjectLoader#parse} 17983 */ 17984 toJSON( meta ) { 17985 17986 const isRootObject = ( meta === undefined || typeof meta === 'string' ); 17987 17988 if ( isRootObject ) { 17989 17990 meta = { 17991 textures: {}, 17992 images: {} 17993 }; 17994 17995 } 17996 17997 const data = { 17998 metadata: { 17999 version: 4.6, 18000 type: 'Material', 18001 generator: 'Material.toJSON' 18002 } 18003 }; 18004 18005 // standard Material serialization 18006 data.uuid = this.uuid; 18007 data.type = this.type; 18008 18009 if ( this.name !== '' ) data.name = this.name; 18010 18011 if ( this.color && this.color.isColor ) data.color = this.color.getHex(); 18012 18013 if ( this.roughness !== undefined ) data.roughness = this.roughness; 18014 if ( this.metalness !== undefined ) data.metalness = this.metalness; 18015 18016 if ( this.sheen !== undefined ) data.sheen = this.sheen; 18017 if ( this.sheenColor && this.sheenColor.isColor ) data.sheenColor = this.sheenColor.getHex(); 18018 if ( this.sheenRoughness !== undefined ) data.sheenRoughness = this.sheenRoughness; 18019 if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex(); 18020 if ( this.emissiveIntensity !== undefined && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity; 18021 18022 if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex(); 18023 if ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity; 18024 if ( this.specularColor && this.specularColor.isColor ) data.specularColor = this.specularColor.getHex(); 18025 if ( this.shininess !== undefined ) data.shininess = this.shininess; 18026 if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat; 18027 if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness; 18028 18029 if ( this.clearcoatMap && this.clearcoatMap.isTexture ) { 18030 18031 data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid; 18032 18033 } 18034 18035 if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) { 18036 18037 data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid; 18038 18039 } 18040 18041 if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) { 18042 18043 data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid; 18044 data.clearcoatNormalScale = this.clearcoatNormalScale.toArray(); 18045 18046 } 18047 18048 if ( this.dispersion !== undefined ) data.dispersion = this.dispersion; 18049 18050 if ( this.iridescence !== undefined ) data.iridescence = this.iridescence; 18051 if ( this.iridescenceIOR !== undefined ) data.iridescenceIOR = this.iridescenceIOR; 18052 if ( this.iridescenceThicknessRange !== undefined ) data.iridescenceThicknessRange = this.iridescenceThicknessRange; 18053 18054 if ( this.iridescenceMap && this.iridescenceMap.isTexture ) { 18055 18056 data.iridescenceMap = this.iridescenceMap.toJSON( meta ).uuid; 18057 18058 } 18059 18060 if ( this.iridescenceThicknessMap && this.iridescenceThicknessMap.isTexture ) { 18061 18062 data.iridescenceThicknessMap = this.iridescenceThicknessMap.toJSON( meta ).uuid; 18063 18064 } 18065 18066 if ( this.anisotropy !== undefined ) data.anisotropy = this.anisotropy; 18067 if ( this.anisotropyRotation !== undefined ) data.anisotropyRotation = this.anisotropyRotation; 18068 18069 if ( this.anisotropyMap && this.anisotropyMap.isTexture ) { 18070 18071 data.anisotropyMap = this.anisotropyMap.toJSON( meta ).uuid; 18072 18073 } 18074 18075 if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid; 18076 if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid; 18077 if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid; 18078 18079 if ( this.lightMap && this.lightMap.isTexture ) { 18080 18081 data.lightMap = this.lightMap.toJSON( meta ).uuid; 18082 data.lightMapIntensity = this.lightMapIntensity; 18083 18084 } 18085 18086 if ( this.aoMap && this.aoMap.isTexture ) { 18087 18088 data.aoMap = this.aoMap.toJSON( meta ).uuid; 18089 data.aoMapIntensity = this.aoMapIntensity; 18090 18091 } 18092 18093 if ( this.bumpMap && this.bumpMap.isTexture ) { 18094 18095 data.bumpMap = this.bumpMap.toJSON( meta ).uuid; 18096 data.bumpScale = this.bumpScale; 18097 18098 } 18099 18100 if ( this.normalMap && this.normalMap.isTexture ) { 18101 18102 data.normalMap = this.normalMap.toJSON( meta ).uuid; 18103 data.normalMapType = this.normalMapType; 18104 data.normalScale = this.normalScale.toArray(); 18105 18106 } 18107 18108 if ( this.displacementMap && this.displacementMap.isTexture ) { 18109 18110 data.displacementMap = this.displacementMap.toJSON( meta ).uuid; 18111 data.displacementScale = this.displacementScale; 18112 data.displacementBias = this.displacementBias; 18113 18114 } 18115 18116 if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid; 18117 if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid; 18118 18119 if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid; 18120 if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid; 18121 if ( this.specularIntensityMap && this.specularIntensityMap.isTexture ) data.specularIntensityMap = this.specularIntensityMap.toJSON( meta ).uuid; 18122 if ( this.specularColorMap && this.specularColorMap.isTexture ) data.specularColorMap = this.specularColorMap.toJSON( meta ).uuid; 18123 18124 if ( this.envMap && this.envMap.isTexture ) { 18125 18126 data.envMap = this.envMap.toJSON( meta ).uuid; 18127 18128 if ( this.combine !== undefined ) data.combine = this.combine; 18129 18130 } 18131 18132 if ( this.envMapRotation !== undefined ) data.envMapRotation = this.envMapRotation.toArray(); 18133 if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity; 18134 if ( this.reflectivity !== undefined ) data.reflectivity = this.reflectivity; 18135 if ( this.refractionRatio !== undefined ) data.refractionRatio = this.refractionRatio; 18136 18137 if ( this.gradientMap && this.gradientMap.isTexture ) { 18138 18139 data.gradientMap = this.gradientMap.toJSON( meta ).uuid; 18140 18141 } 18142 18143 if ( this.transmission !== undefined ) data.transmission = this.transmission; 18144 if ( this.transmissionMap && this.transmissionMap.isTexture ) data.transmissionMap = this.transmissionMap.toJSON( meta ).uuid; 18145 if ( this.thickness !== undefined ) data.thickness = this.thickness; 18146 if ( this.thicknessMap && this.thicknessMap.isTexture ) data.thicknessMap = this.thicknessMap.toJSON( meta ).uuid; 18147 if ( this.attenuationDistance !== undefined && this.attenuationDistance !== Infinity ) data.attenuationDistance = this.attenuationDistance; 18148 if ( this.attenuationColor !== undefined ) data.attenuationColor = this.attenuationColor.getHex(); 18149 18150 if ( this.size !== undefined ) data.size = this.size; 18151 if ( this.shadowSide !== null ) data.shadowSide = this.shadowSide; 18152 if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation; 18153 18154 if ( this.blending !== NormalBlending ) data.blending = this.blending; 18155 if ( this.side !== FrontSide ) data.side = this.side; 18156 if ( this.vertexColors === true ) data.vertexColors = true; 18157 18158 if ( this.opacity < 1 ) data.opacity = this.opacity; 18159 if ( this.transparent === true ) data.transparent = true; 18160 18161 if ( this.blendSrc !== SrcAlphaFactor ) data.blendSrc = this.blendSrc; 18162 if ( this.blendDst !== OneMinusSrcAlphaFactor ) data.blendDst = this.blendDst; 18163 if ( this.blendEquation !== AddEquation ) data.blendEquation = this.blendEquation; 18164 if ( this.blendSrcAlpha !== null ) data.blendSrcAlpha = this.blendSrcAlpha; 18165 if ( this.blendDstAlpha !== null ) data.blendDstAlpha = this.blendDstAlpha; 18166 if ( this.blendEquationAlpha !== null ) data.blendEquationAlpha = this.blendEquationAlpha; 18167 if ( this.blendColor && this.blendColor.isColor ) data.blendColor = this.blendColor.getHex(); 18168 if ( this.blendAlpha !== 0 ) data.blendAlpha = this.blendAlpha; 18169 18170 if ( this.depthFunc !== LessEqualDepth ) data.depthFunc = this.depthFunc; 18171 if ( this.depthTest === false ) data.depthTest = this.depthTest; 18172 if ( this.depthWrite === false ) data.depthWrite = this.depthWrite; 18173 if ( this.colorWrite === false ) data.colorWrite = this.colorWrite; 18174 18175 if ( this.stencilWriteMask !== 0xff ) data.stencilWriteMask = this.stencilWriteMask; 18176 if ( this.stencilFunc !== AlwaysStencilFunc ) data.stencilFunc = this.stencilFunc; 18177 if ( this.stencilRef !== 0 ) data.stencilRef = this.stencilRef; 18178 if ( this.stencilFuncMask !== 0xff ) data.stencilFuncMask = this.stencilFuncMask;
vendor: 4,271 bytes, lines 18179-18318
18179 if ( this.stencilFail !== KeepStencilOp ) data.stencilFail = this.stencilFail; 18180 if ( this.stencilZFail !== KeepStencilOp ) data.stencilZFail = this.stencilZFail; 18181 if ( this.stencilZPass !== KeepStencilOp ) data.stencilZPass = this.stencilZPass; 18182 if ( this.stencilWrite === true ) data.stencilWrite = this.stencilWrite; 18183 18184 // rotation (SpriteMaterial) 18185 if ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation; 18186 18187 if ( this.polygonOffset === true ) data.polygonOffset = true; 18188 if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor; 18189 if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits; 18190 18191 if ( this.linewidth !== undefined && this.linewidth !== 1 ) data.linewidth = this.linewidth; 18192 if ( this.dashSize !== undefined ) data.dashSize = this.dashSize; 18193 if ( this.gapSize !== undefined ) data.gapSize = this.gapSize; 18194 if ( this.scale !== undefined ) data.scale = this.scale; 18195 18196 if ( this.dithering === true ) data.dithering = true; 18197 18198 if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; 18199 if ( this.alphaHash === true ) data.alphaHash = true; 18200 if ( this.alphaToCoverage === true ) data.alphaToCoverage = true; 18201 if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = true; 18202 if ( this.forceSinglePass === true ) data.forceSinglePass = true; 18203 18204 if ( this.wireframe === true ) data.wireframe = true; 18205 if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth; 18206 if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap; 18207 if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin; 18208 18209 if ( this.flatShading === true ) data.flatShading = true; 18210 18211 if ( this.visible === false ) data.visible = false; 18212 18213 if ( this.toneMapped === false ) data.toneMapped = false; 18214 18215 if ( this.fog === false ) data.fog = false; 18216 18217 if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData; 18218 18219 // TODO: Copied from Object3D.toJSON 18220 18221 function extractFromCache( cache ) { 18222 18223 const values = []; 18224 18225 for ( const key in cache ) { 18226 18227 const data = cache[ key ]; 18228 delete data.metadata; 18229 values.push( data ); 18230 18231 } 18232 18233 return values; 18234 18235 } 18236 18237 if ( isRootObject ) { 18238 18239 const textures = extractFromCache( meta.textures ); 18240 const images = extractFromCache( meta.images ); 18241 18242 if ( textures.length > 0 ) data.textures = textures; 18243 if ( images.length > 0 ) data.images = images; 18244 18245 } 18246 18247 return data; 18248 18249 } 18250 18251 /** 18252 * Returns a new material with copied values from this instance. 18253 * 18254 * @return {Material} A clone of this instance. 18255 */ 18256 clone() { 18257 18258 return new this.constructor().copy( this ); 18259 18260 } 18261 18262 /** 18263 * Copies the values of the given material to this instance. 18264 * 18265 * @param {Material} source - The material to copy. 18266 * @return {Material} A reference to this instance. 18267 */ 18268 copy( source ) { 18269 18270 this.name = source.name; 18271 18272 this.blending = source.blending; 18273 this.side = source.side; 18274 this.vertexColors = source.vertexColors; 18275 18276 this.opacity = source.opacity; 18277 this.transparent = source.transparent; 18278 18279 this.blendSrc = source.blendSrc; 18280 this.blendDst = source.blendDst; 18281 this.blendEquation = source.blendEquation; 18282 this.blendSrcAlpha = source.blendSrcAlpha; 18283 this.blendDstAlpha = source.blendDstAlpha; 18284 this.blendEquationAlpha = source.blendEquationAlpha; 18285 this.blendColor.copy( source.blendColor ); 18286 this.blendAlpha = source.blendAlpha; 18287 18288 this.depthFunc = source.depthFunc; 18289 this.depthTest = source.depthTest; 18290 this.depthWrite = source.depthWrite; 18291 18292 this.stencilWriteMask = source.stencilWriteMask; 18293 this.stencilFunc = source.stencilFunc; 18294 this.stencilRef = source.stencilRef; 18295 this.stencilFuncMask = source.stencilFuncMask; 18296 this.stencilFail = source.stencilFail; 18297 this.stencilZFail = source.stencilZFail; 18298 this.stencilZPass = source.stencilZPass; 18299 this.stencilWrite = source.stencilWrite; 18300 18301 const srcPlanes = source.clippingPlanes; 18302 let dstPlanes = null; 18303 18304 if ( srcPlanes !== null ) { 18305 18306 const n = srcPlanes.length; 18307 dstPlanes = new Array( n ); 18308 18309 for ( let i = 0; i !== n; ++ i ) { 18310 18311 dstPlanes[ i ] = srcPlanes[ i ].clone(); 18312 18313 } 18314 18315 } 18316 18317 this.clippingPlanes = dstPlanes; 18318 this.clipIntersection = source.clipIntersection;
18319 this.clipShadows = source.clipShadows; 18320 18321 this.shadowSide = source.shadowSide; 18322 18323 this.colorWrite = source.colorWrite; 18324 18325 this.precision = source.precision; 18326 18327 this.polygonOffset = source.polygonOffset; 18328 this.polygonOffsetFactor = source.polygonOffsetFactor; 18329 this.polygonOffsetUnits = source.polygonOffsetUnits; 18330 18331 this.dithering = source.dithering; 18332 18333 this.alphaTest = source.alphaTest; 18334 this.alphaHash = source.alphaHash; 18335 this.alphaToCoverage = source.alphaToCoverage; 18336 this.premultipliedAlpha = source.premultipliedAlpha; 18337 this.forceSinglePass = source.forceSinglePass; 18338 18339 this.visible = source.visible; 18340 18341 this.toneMapped = source.toneMapped; 18342 18343 this.userData = JSON.parse( JSON.stringify( source.userData ) ); 18344 18345 return this; 18346 18347 } 18348 18349 /** 18350 * Frees the GPU-related resources allocated by this instance. Call this 18351 * method whenever this instance is no longer used in your app. 18352 * 18353 * @fires Material#dispose 18354 */ 18355 dispose() { 18356 18357 /** 18358 * Fires when the material has been disposed of. 18359 * 18360 * @event Material#dispose 18361 * @type {Object} 18362 */ 18363 this.dispatchEvent( { type: 'dispose' } ); 18364 18365 } 18366 18367 /** 18368 * Setting this property to `true` indicates the engine the material 18369 * needs to be recompiled. 18370 * 18371 * @type {boolean} 18372 * @default false 18373 * @param {boolean} value 18374 */ 18375 set needsUpdate( value ) { 18376 18377 if ( value === true ) this.version ++; 18378 18379 } 18380 18381 onBuild( /* shaderobject, renderer */ ) { 18382 18383 console.warn( 'Material: onBuild() has been removed.' ); // @deprecated, r166 18384 18385 } 18386 18387} 18388 18389/** 18390 * A material for drawing geometries in a simple shaded (flat or wireframe) way. 18391 * 18392 * This material is not affected by lights. 18393 * 18394 * @augments Material 18395 */ 18396class MeshBasicMaterial extends Material { 18397 18398 /** 18399 * Constructs a new mesh basic material. 18400 * 18401 * @param {Object} [parameters] - An object with one or more properties 18402 * defining the material's appearance. Any property of the material 18403 * (including any property from inherited materials) can be passed 18404 * in here. Color values can be passed any type of value accepted 18405 * by {@link Color#set}. 18406 */ 18407 constructor( parameters ) { 18408 18409 super(); 18410 18411 /** 18412 * This flag can be used for type testing. 18413 * 18414 * @type {boolean} 18415 * @readonly 18416 * @default true 18417 */ 18418 this.isMeshBasicMaterial = true; 18419 18420 this.type = 'MeshBasicMaterial'; 18421 18422 /** 18423 * Color of the material. 18424 * 18425 * @type {Color} 18426 * @default (1,1,1) 18427 */ 18428 this.color = new Color( 0xffffff ); // emissive 18429 18430 /** 18431 * The color map. May optionally include an alpha channel, typically combined 18432 * with {@link Material#transparent} or {@link Material#alphaTest}. The texture map 18433 * color is modulated by the diffuse `color`. 18434 * 18435 * @type {?Texture} 18436 * @default null 18437 */ 18438 this.map = null; 18439 18440 /** 18441 * The light map. Requires a second set of UVs. 18442 * 18443 * @type {?Texture} 18444 * @default null 18445 */ 18446 this.lightMap = null; 18447 18448 /** 18449 * Intensity of the baked light. 18450 * 18451 * @type {number} 18452 * @default 1 18453 */ 18454 this.lightMapIntensity = 1.0; 18455 18456 /** 18457 * The red channel of this texture is used as the ambient occlusion map. 18458 * Requires a second set of UVs. 18459 * 18460 * @type {?Texture} 18461 * @default null 18462 */ 18463 this.aoMap = null; 18464 18465 /** 18466 * Intensity of the ambient occlusion effect. Range is `[0,1]`, where `0` 18467 * disables ambient occlusion. Where intensity is `1` and the AO map's 18468 * red channel is also `1`, ambient light is fully occluded on a surface. 18469 * 18470 * @type {number} 18471 * @default 1 18472 */ 18473 this.aoMapIntensity = 1.0; 18474 18475 /** 18476 * Specular map used by the material. 18477 * 18478 * @type {?Texture} 18479 * @default null 18480 */ 18481 this.specularMap = null; 18482 18483 /** 18484 * The alpha map is a grayscale texture that controls the opacity across the 18485 * surface (black: fully transparent; white: fully opaque). 18486 * 18487 * Only the color of the texture is used, ignoring the alpha channel if one 18488 * exists. For RGB and RGBA textures, the renderer will use the green channel 18489 * when sampling this texture due to the extra bit of precision provided for 18490 * green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and 18491 * luminance/alpha textures will also still work as expected. 18492 * 18493 * @type {?Texture} 18494 * @default null 18495 */ 18496 this.alphaMap = null; 18497 18498 /** 18499 * The environment map. 18500 * 18501 * @type {?Texture} 18502 * @default null 18503 */ 18504 this.envMap = null; 18505 18506 /** 18507 * The rotation of the environment map in radians. 18508 * 18509 * @type {Euler} 18510 * @default (0,0,0) 18511 */ 18512 this.envMapRotation = new Euler(); 18513 18514 /** 18515 * How to combine the result of the surface's color with the environment map, if any. 18516 * 18517 * When set to `MixOperation`, the {@link MeshBasicMaterial#reflectivity} is used to 18518 * blend between the two colors. 18519 * 18520 * @type {(MultiplyOperation|MixOperation|AddOperation)} 18521 * @default MultiplyOperation 18522 */ 18523 this.combine = MultiplyOperation; 18524 18525 /** 18526 * How much the environment map affects the surface. 18527 * The valid range is between `0` (no reflections) and `1` (full reflections). 18528 * 18529 * @type {number} 18530 * @default 1 18531 */ 18532 this.reflectivity = 1; 18533 18534 /** 18535 * The index of refraction (IOR) of air (approximately 1) divided by the 18536 * index of refraction of the material. It is used with environment mapping 18537 * modes {@link CubeRefractionMapping} and {@link EquirectangularRefractionMapping}. 18538 * The refraction ratio should not exceed `1`. 18539 * 18540 * @type {number} 18541 * @default 0.98 18542 */ 18543 this.refractionRatio = 0.98; 18544 18545 /** 18546 * Renders the geometry as a wireframe. 18547 * 18548 * @type {boolean} 18549 * @default false 18550 */ 18551 this.wireframe = false;
vendor: 5,003 bytes, lines 18552-18737
18552 18553 /** 18554 * Controls the thickness of the wireframe. 18555 * 18556 * Can only be used with {@link SVGRenderer}. 18557 * 18558 * @type {number} 18559 * @default 1 18560 */ 18561 this.wireframeLinewidth = 1; 18562 18563 /** 18564 * Defines appearance of wireframe ends. 18565 * 18566 * Can only be used with {@link SVGRenderer}. 18567 * 18568 * @type {('round'|'bevel'|'miter')} 18569 * @default 'round' 18570 */ 18571 this.wireframeLinecap = 'round'; 18572 18573 /** 18574 * Defines appearance of wireframe joints. 18575 * 18576 * Can only be used with {@link SVGRenderer}. 18577 * 18578 * @type {('round'|'bevel'|'miter')} 18579 * @default 'round' 18580 */ 18581 this.wireframeLinejoin = 'round'; 18582 18583 /** 18584 * Whether the material is affected by fog or not. 18585 * 18586 * @type {boolean} 18587 * @default true 18588 */ 18589 this.fog = true; 18590 18591 this.setValues( parameters ); 18592 18593 } 18594 18595 copy( source ) { 18596 18597 super.copy( source ); 18598 18599 this.color.copy( source.color ); 18600 18601 this.map = source.map; 18602 18603 this.lightMap = source.lightMap; 18604 this.lightMapIntensity = source.lightMapIntensity; 18605 18606 this.aoMap = source.aoMap; 18607 this.aoMapIntensity = source.aoMapIntensity; 18608 18609 this.specularMap = source.specularMap; 18610 18611 this.alphaMap = source.alphaMap; 18612 18613 this.envMap = source.envMap; 18614 this.envMapRotation.copy( source.envMapRotation ); 18615 this.combine = source.combine; 18616 this.reflectivity = source.reflectivity; 18617 this.refractionRatio = source.refractionRatio; 18618 18619 this.wireframe = source.wireframe; 18620 this.wireframeLinewidth = source.wireframeLinewidth; 18621 this.wireframeLinecap = source.wireframeLinecap; 18622 this.wireframeLinejoin = source.wireframeLinejoin; 18623 18624 this.fog = source.fog; 18625 18626 return this; 18627 18628 } 18629 18630} 18631 18632const _vector$9 = /*@__PURE__*/ new Vector3(); 18633const _vector2$1 = /*@__PURE__*/ new Vector2(); 18634 18635let _id$2 = 0; 18636 18637/** 18638 * This class stores data for an attribute (such as vertex positions, face 18639 * indices, normals, colors, UVs, and any custom attributes ) associated with 18640 * a geometry, which allows for more efficient passing of data to the GPU. 18641 * 18642 * When working with vector-like data, the `fromBufferAttribute( attribute, index )` 18643 * helper methods on vector and color class might be helpful. E.g. {@link Vector3#fromBufferAttribute}. 18644 */ 18645class BufferAttribute { 18646 18647 /** 18648 * Constructs a new buffer attribute. 18649 * 18650 * @param {TypedArray} array - The array holding the attribute data. 18651 * @param {number} itemSize - The item size. 18652 * @param {boolean} [normalized=false] - Whether the data are normalized or not. 18653 */ 18654 constructor( array, itemSize, normalized = false ) { 18655 18656 if ( Array.isArray( array ) ) { 18657 18658 throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); 18659 18660 } 18661 18662 /** 18663 * This flag can be used for type testing. 18664 * 18665 * @type {boolean} 18666 * @readonly 18667 * @default true 18668 */ 18669 this.isBufferAttribute = true; 18670 18671 /** 18672 * The ID of the buffer attribute. 18673 * 18674 * @name BufferAttribute#id 18675 * @type {number} 18676 * @readonly 18677 */ 18678 Object.defineProperty( this, 'id', { value: _id$2 ++ } ); 18679 18680 /** 18681 * The name of the buffer attribute. 18682 * 18683 * @type {string} 18684 */ 18685 this.name = ''; 18686 18687 /** 18688 * The array holding the attribute data. It should have `itemSize * numVertices` 18689 * elements, where `numVertices` is the number of vertices in the associated geometry. 18690 * 18691 * @type {TypedArray} 18692 */ 18693 this.array = array; 18694 18695 /** 18696 * The number of values of the array that should be associated with a particular vertex. 18697 * For instance, if this attribute is storing a 3-component vector (such as a position, 18698 * normal, or color), then the value should be `3`. 18699 * 18700 * @type {number} 18701 */ 18702 this.itemSize = itemSize; 18703 18704 /** 18705 * Represents the number of items this buffer attribute stores. It is internally computed 18706 * by dividing the `array` length by the `itemSize`. 18707 * 18708 * @type {number} 18709 * @readonly 18710 */ 18711 this.count = array !== undefined ? array.length / itemSize : 0; 18712 18713 /** 18714 * Applies to integer data only. Indicates how the underlying data in the buffer maps to 18715 * the values in the GLSL code. For instance, if `array` is an instance of `UInt16Array`, 18716 * and `normalized` is `true`, the values `0 -+65535` in the array data will be mapped to 18717 * `0.0f - +1.0f` in the GLSL attribute. If `normalized` is `false`, the values will be converted 18718 * to floats unmodified, i.e. `65535` becomes `65535.0f`. 18719 * 18720 * @type {boolean} 18721 */ 18722 this.normalized = normalized; 18723 18724 /** 18725 * Defines the intended usage pattern of the data store for optimization purposes. 18726 * 18727 * Note: After the initial use of a buffer, its usage cannot be changed. Instead, 18728 * instantiate a new one and set the desired usage before the next render. 18729 * 18730 * @type {(StaticDrawUsage|DynamicDrawUsage|StreamDrawUsage|StaticReadUsage|DynamicReadUsage|StreamReadUsage|StaticCopyUsage|DynamicCopyUsage|StreamCopyUsage)} 18731 * @default StaticDrawUsage 18732 */ 18733 this.usage = StaticDrawUsage; 18734 18735 /** 18736 * This can be used to only update some components of stored vectors (for example, just the 18737 * component related to color). Use the `addUpdateRange()` function to add ranges to this array.
vendor: 8,896 bytes, lines 18738-19133
18738 * 18739 * @type {Array<Object>} 18740 */ 18741 this.updateRanges = []; 18742 18743 /** 18744 * Configures the bound GPU type for use in shaders. 18745 * 18746 * Note: this only has an effect for integer arrays and is not configurable for float arrays. 18747 * For lower precision float types, use `Float16BufferAttribute`. 18748 * 18749 * @type {(FloatType|IntType)} 18750 * @default FloatType 18751 */ 18752 this.gpuType = FloatType; 18753 18754 /** 18755 * A version number, incremented every time the `needsUpdate` is set to `true`. 18756 * 18757 * @type {number} 18758 */ 18759 this.version = 0; 18760 18761 } 18762 18763 /** 18764 * A callback function that is executed after the renderer has transferred the attribute 18765 * array data to the GPU. 18766 */ 18767 onUploadCallback() {} 18768 18769 /** 18770 * Flag to indicate that this attribute has changed and should be re-sent to 18771 * the GPU. Set this to `true` when you modify the value of the array. 18772 * 18773 * @type {number} 18774 * @default false 18775 * @param {boolean} value 18776 */ 18777 set needsUpdate( value ) { 18778 18779 if ( value === true ) this.version ++; 18780 18781 } 18782 18783 /** 18784 * Sets the usage of this buffer attribute. 18785 * 18786 * @param {(StaticDrawUsage|DynamicDrawUsage|StreamDrawUsage|StaticReadUsage|DynamicReadUsage|StreamReadUsage|StaticCopyUsage|DynamicCopyUsage|StreamCopyUsage)} value - The usage to set. 18787 * @return {BufferAttribute} A reference to this buffer attribute. 18788 */ 18789 setUsage( value ) { 18790 18791 this.usage = value; 18792 18793 return this; 18794 18795 } 18796 18797 /** 18798 * Adds a range of data in the data array to be updated on the GPU. 18799 * 18800 * @param {number} start - Position at which to start update. 18801 * @param {number} count - The number of components to update. 18802 */ 18803 addUpdateRange( start, count ) { 18804 18805 this.updateRanges.push( { start, count } ); 18806 18807 } 18808 18809 /** 18810 * Clears the update ranges. 18811 */ 18812 clearUpdateRanges() { 18813 18814 this.updateRanges.length = 0; 18815 18816 } 18817 18818 /** 18819 * Copies the values of the given buffer attribute to this instance. 18820 * 18821 * @param {BufferAttribute} source - The buffer attribute to copy. 18822 * @return {BufferAttribute} A reference to this instance. 18823 */ 18824 copy( source ) { 18825 18826 this.name = source.name; 18827 this.array = new source.array.constructor( source.array ); 18828 this.itemSize = source.itemSize; 18829 this.count = source.count; 18830 this.normalized = source.normalized; 18831 18832 this.usage = source.usage; 18833 this.gpuType = source.gpuType; 18834 18835 return this; 18836 18837 } 18838 18839 /** 18840 * Copies a vector from the given buffer attribute to this one. The start 18841 * and destination position in the attribute buffers are represented by the 18842 * given indices. 18843 * 18844 * @param {number} index1 - The destination index into this buffer attribute. 18845 * @param {BufferAttribute} attribute - The buffer attribute to copy from. 18846 * @param {number} index2 - The source index into the given buffer attribute. 18847 * @return {BufferAttribute} A reference to this instance. 18848 */ 18849 copyAt( index1, attribute, index2 ) { 18850 18851 index1 *= this.itemSize; 18852 index2 *= attribute.itemSize; 18853 18854 for ( let i = 0, l = this.itemSize; i < l; i ++ ) { 18855 18856 this.array[ index1 + i ] = attribute.array[ index2 + i ]; 18857 18858 } 18859 18860 return this; 18861 18862 } 18863 18864 /** 18865 * Copies the given array data into this buffer attribute. 18866 * 18867 * @param {(TypedArray|Array)} array - The array to copy. 18868 * @return {BufferAttribute} A reference to this instance. 18869 */ 18870 copyArray( array ) { 18871 18872 this.array.set( array ); 18873 18874 return this; 18875 18876 } 18877 18878 /** 18879 * Applies the given 3x3 matrix to the given attribute. Works with 18880 * item size `2` and `3`. 18881 * 18882 * @param {Matrix3} m - The matrix to apply. 18883 * @return {BufferAttribute} A reference to this instance. 18884 */ 18885 applyMatrix3( m ) { 18886 18887 if ( this.itemSize === 2 ) { 18888 18889 for ( let i = 0, l = this.count; i < l; i ++ ) { 18890 18891 _vector2$1.fromBufferAttribute( this, i ); 18892 _vector2$1.applyMatrix3( m ); 18893 18894 this.setXY( i, _vector2$1.x, _vector2$1.y ); 18895 18896 } 18897 18898 } else if ( this.itemSize === 3 ) { 18899 18900 for ( let i = 0, l = this.count; i < l; i ++ ) { 18901 18902 _vector$9.fromBufferAttribute( this, i ); 18903 _vector$9.applyMatrix3( m ); 18904 18905 this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); 18906 18907 } 18908 18909 } 18910 18911 return this; 18912 18913 } 18914 18915 /** 18916 * Applies the given 4x4 matrix to the given attribute. Only works with 18917 * item size `3`. 18918 * 18919 * @param {Matrix4} m - The matrix to apply. 18920 * @return {BufferAttribute} A reference to this instance. 18921 */ 18922 applyMatrix4( m ) { 18923 18924 for ( let i = 0, l = this.count; i < l; i ++ ) { 18925 18926 _vector$9.fromBufferAttribute( this, i ); 18927 18928 _vector$9.applyMatrix4( m ); 18929 18930 this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); 18931 18932 } 18933 18934 return this; 18935 18936 } 18937 18938 /** 18939 * Applies the given 3x3 normal matrix to the given attribute. Only works with 18940 * item size `3`. 18941 * 18942 * @param {Matrix3} m - The normal matrix to apply. 18943 * @return {BufferAttribute} A reference to this instance. 18944 */ 18945 applyNormalMatrix( m ) { 18946 18947 for ( let i = 0, l = this.count; i < l; i ++ ) { 18948 18949 _vector$9.fromBufferAttribute( this, i ); 18950 18951 _vector$9.applyNormalMatrix( m ); 18952 18953 this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); 18954 18955 } 18956 18957 return this; 18958 18959 } 18960 18961 /** 18962 * Applies the given 4x4 matrix to the given attribute. Only works with 18963 * item size `3` and with direction vectors. 18964 * 18965 * @param {Matrix4} m - The matrix to apply. 18966 * @return {BufferAttribute} A reference to this instance. 18967 */ 18968 transformDirection( m ) { 18969 18970 for ( let i = 0, l = this.count; i < l; i ++ ) { 18971 18972 _vector$9.fromBufferAttribute( this, i ); 18973 18974 _vector$9.transformDirection( m ); 18975 18976 this.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); 18977 18978 } 18979 18980 return this; 18981 18982 } 18983 18984 /** 18985 * Sets the given array data in the buffer attribute. 18986 * 18987 * @param {(TypedArray|Array)} value - The array data to set. 18988 * @param {number} [offset=0] - The offset in this buffer attribute's array. 18989 * @return {BufferAttribute} A reference to this instance. 18990 */ 18991 set( value, offset = 0 ) { 18992 18993 // Matching BufferAttribute constructor, do not normalize the array. 18994 this.array.set( value, offset ); 18995 18996 return this; 18997 18998 } 18999 19000 /** 19001 * Returns the given component of the vector at the given index. 19002 * 19003 * @param {number} index - The index into the buffer attribute. 19004 * @param {number} component - The component index. 19005 * @return {number} The returned value. 19006 */ 19007 getComponent( index, component ) { 19008 19009 let value = this.array[ index * this.itemSize + component ]; 19010 19011 if ( this.normalized ) value = denormalize( value, this.array ); 19012 19013 return value; 19014 19015 } 19016 19017 /** 19018 * Sets the given value to the given component of the vector at the given index. 19019 * 19020 * @param {number} index - The index into the buffer attribute. 19021 * @param {number} component - The component index. 19022 * @param {number} value - The value to set. 19023 * @return {BufferAttribute} A reference to this instance. 19024 */ 19025 setComponent( index, component, value ) { 19026 19027 if ( this.normalized ) value = normalize( value, this.array ); 19028 19029 this.array[ index * this.itemSize + component ] = value; 19030 19031 return this; 19032 19033 } 19034 19035 /** 19036 * Returns the x component of the vector at the given index. 19037 * 19038 * @param {number} index - The index into the buffer attribute. 19039 * @return {number} The x component. 19040 */ 19041 getX( index ) { 19042 19043 let x = this.array[ index * this.itemSize ]; 19044 19045 if ( this.normalized ) x = denormalize( x, this.array ); 19046 19047 return x; 19048 19049 } 19050 19051 /** 19052 * Sets the x component of the vector at the given index. 19053 * 19054 * @param {number} index - The index into the buffer attribute. 19055 * @param {number} x - The value to set. 19056 * @return {BufferAttribute} A reference to this instance. 19057 */ 19058 setX( index, x ) { 19059 19060 if ( this.normalized ) x = normalize( x, this.array ); 19061 19062 this.array[ index * this.itemSize ] = x; 19063 19064 return this; 19065 19066 } 19067 19068 /** 19069 * Returns the y component of the vector at the given index. 19070 * 19071 * @param {number} index - The index into the buffer attribute. 19072 * @return {number} The y component. 19073 */ 19074 getY( index ) { 19075 19076 let y = this.array[ index * this.itemSize + 1 ]; 19077 19078 if ( this.normalized ) y = denormalize( y, this.array ); 19079 19080 return y; 19081 19082 } 19083 19084 /** 19085 * Sets the y component of the vector at the given index. 19086 * 19087 * @param {number} index - The index into the buffer attribute. 19088 * @param {number} y - The value to set. 19089 * @return {BufferAttribute} A reference to this instance. 19090 */ 19091 setY( index, y ) { 19092 19093 if ( this.normalized ) y = normalize( y, this.array ); 19094 19095 this.array[ index * this.itemSize + 1 ] = y; 19096 19097 return this; 19098 19099 } 19100 19101 /** 19102 * Returns the z component of the vector at the given index. 19103 * 19104 * @param {number} index - The index into the buffer attribute. 19105 * @return {number} The z component. 19106 */ 19107 getZ( index ) { 19108 19109 let z = this.array[ index * this.itemSize + 2 ]; 19110 19111 if ( this.normalized ) z = denormalize( z, this.array ); 19112 19113 return z; 19114 19115 } 19116 19117 /** 19118 * Sets the z component of the vector at the given index. 19119 * 19120 * @param {number} index - The index into the buffer attribute. 19121 * @param {number} z - The value to set. 19122 * @return {BufferAttribute} A reference to this instance. 19123 */ 19124 setZ( index, z ) { 19125 19126 if ( this.normalized ) z = normalize( z, this.array ); 19127 19128 this.array[ index * this.itemSize + 2 ] = z; 19129 19130 return this; 19131 19132 } 19133
vendor: 5,998 bytes, lines 19134-19380
19134 /** 19135 * Returns the w component of the vector at the given index. 19136 * 19137 * @param {number} index - The index into the buffer attribute. 19138 * @return {number} The w component. 19139 */ 19140 getW( index ) { 19141 19142 let w = this.array[ index * this.itemSize + 3 ]; 19143 19144 if ( this.normalized ) w = denormalize( w, this.array ); 19145 19146 return w; 19147 19148 } 19149 19150 /** 19151 * Sets the w component of the vector at the given index. 19152 * 19153 * @param {number} index - The index into the buffer attribute. 19154 * @param {number} w - The value to set. 19155 * @return {BufferAttribute} A reference to this instance. 19156 */ 19157 setW( index, w ) { 19158 19159 if ( this.normalized ) w = normalize( w, this.array ); 19160 19161 this.array[ index * this.itemSize + 3 ] = w; 19162 19163 return this; 19164 19165 } 19166 19167 /** 19168 * Sets the x and y component of the vector at the given index. 19169 * 19170 * @param {number} index - The index into the buffer attribute. 19171 * @param {number} x - The value for the x component to set. 19172 * @param {number} y - The value for the y component to set. 19173 * @return {BufferAttribute} A reference to this instance. 19174 */ 19175 setXY( index, x, y ) { 19176 19177 index *= this.itemSize; 19178 19179 if ( this.normalized ) { 19180 19181 x = normalize( x, this.array ); 19182 y = normalize( y, this.array ); 19183 19184 } 19185 19186 this.array[ index + 0 ] = x; 19187 this.array[ index + 1 ] = y; 19188 19189 return this; 19190 19191 } 19192 19193 /** 19194 * Sets the x, y and z component of the vector at the given index. 19195 * 19196 * @param {number} index - The index into the buffer attribute. 19197 * @param {number} x - The value for the x component to set. 19198 * @param {number} y - The value for the y component to set. 19199 * @param {number} z - The value for the z component to set. 19200 * @return {BufferAttribute} A reference to this instance. 19201 */ 19202 setXYZ( index, x, y, z ) { 19203 19204 index *= this.itemSize; 19205 19206 if ( this.normalized ) { 19207 19208 x = normalize( x, this.array ); 19209 y = normalize( y, this.array ); 19210 z = normalize( z, this.array ); 19211 19212 } 19213 19214 this.array[ index + 0 ] = x; 19215 this.array[ index + 1 ] = y; 19216 this.array[ index + 2 ] = z; 19217 19218 return this; 19219 19220 } 19221 19222 /** 19223 * Sets the x, y, z and w component of the vector at the given index. 19224 * 19225 * @param {number} index - The index into the buffer attribute. 19226 * @param {number} x - The value for the x component to set. 19227 * @param {number} y - The value for the y component to set. 19228 * @param {number} z - The value for the z component to set. 19229 * @param {number} w - The value for the w component to set. 19230 * @return {BufferAttribute} A reference to this instance. 19231 */ 19232 setXYZW( index, x, y, z, w ) { 19233 19234 index *= this.itemSize; 19235 19236 if ( this.normalized ) { 19237 19238 x = normalize( x, this.array ); 19239 y = normalize( y, this.array ); 19240 z = normalize( z, this.array ); 19241 w = normalize( w, this.array ); 19242 19243 } 19244 19245 this.array[ index + 0 ] = x; 19246 this.array[ index + 1 ] = y; 19247 this.array[ index + 2 ] = z; 19248 this.array[ index + 3 ] = w; 19249 19250 return this; 19251 19252 } 19253 19254 /** 19255 * Sets the given callback function that is executed after the Renderer has transferred 19256 * the attribute array data to the GPU. Can be used to perform clean-up operations after 19257 * the upload when attribute data are not needed anymore on the CPU side. 19258 * 19259 * @param {Function} callback - The `onUpload()` callback. 19260 * @return {BufferAttribute} A reference to this instance. 19261 */ 19262 onUpload( callback ) { 19263 19264 this.onUploadCallback = callback; 19265 19266 return this; 19267 19268 } 19269 19270 /** 19271 * Returns a new buffer attribute with copied values from this instance. 19272 * 19273 * @return {BufferAttribute} A clone of this instance. 19274 */ 19275 clone() { 19276 19277 return new this.constructor( this.array, this.itemSize ).copy( this ); 19278 19279 } 19280 19281 /** 19282 * Serializes the buffer attribute into JSON. 19283 * 19284 * @return {Object} A JSON object representing the serialized buffer attribute. 19285 */ 19286 toJSON() { 19287 19288 const data = { 19289 itemSize: this.itemSize, 19290 type: this.array.constructor.name, 19291 array: Array.from( this.array ), 19292 normalized: this.normalized 19293 }; 19294 19295 if ( this.name !== '' ) data.name = this.name; 19296 if ( this.usage !== StaticDrawUsage ) data.usage = this.usage; 19297 19298 return data; 19299 19300 } 19301 19302} 19303 19304/** 19305 * Convenient class that can be used when creating a `UInt16` buffer attribute with 19306 * a plain `Array` instance. 19307 * 19308 * @augments BufferAttribute 19309 */ 19310class Uint16BufferAttribute extends BufferAttribute { 19311 19312 /** 19313 * Constructs a new buffer attribute. 19314 * 19315 * @param {(Array<number>|Uint16Array)} array - The array holding the attribute data. 19316 * @param {number} itemSize - The item size. 19317 * @param {boolean} [normalized=false] - Whether the data are normalized or not. 19318 */ 19319 constructor( array, itemSize, normalized ) { 19320 19321 super( new Uint16Array( array ), itemSize, normalized ); 19322 19323 } 19324 19325} 19326 19327/** 19328 * Convenient class that can be used when creating a `UInt32` buffer attribute with 19329 * a plain `Array` instance. 19330 * 19331 * @augments BufferAttribute 19332 */ 19333class Uint32BufferAttribute extends BufferAttribute { 19334 19335 /** 19336 * Constructs a new buffer attribute. 19337 * 19338 * @param {(Array<number>|Uint32Array)} array - The array holding the attribute data. 19339 * @param {number} itemSize - The item size. 19340 * @param {boolean} [normalized=false] - Whether the data are normalized or not. 19341 */ 19342 constructor( array, itemSize, normalized ) { 19343 19344 super( new Uint32Array( array ), itemSize, normalized ); 19345 19346 } 19347 19348} 19349 19350/** 19351 * Convenient class that can be used when creating a `Float32` buffer attribute with 19352 * a plain `Array` instance. 19353 * 19354 * @augments BufferAttribute 19355 */ 19356class Float32BufferAttribute extends BufferAttribute { 19357 19358 /** 19359 * Constructs a new buffer attribute. 19360 * 19361 * @param {(Array<number>|Float32Array)} array - The array holding the attribute data. 19362 * @param {number} itemSize - The item size. 19363 * @param {boolean} [normalized=false] - Whether the data are normalized or not. 19364 */ 19365 constructor( array, itemSize, normalized ) { 19366 19367 super( new Float32Array( array ), itemSize, normalized ); 19368 19369 } 19370 19371} 19372 19373let _id$1 = 0; 19374 19375const _m1 = /*@__PURE__*/ new Matrix4(); 19376const _obj = /*@__PURE__*/ new Object3D(); 19377const _offset = /*@__PURE__*/ new Vector3(); 19378const _box$2 = /*@__PURE__*/ new Box3(); 19379const _boxMorphTargets = /*@__PURE__*/ new Box3(); 19380const _vector$8
vendor: 2,454 bytes, lines 19380-19475
19380 = /*@__PURE__*/ new Vector3(); 19381 19382/** 19383 * A representation of mesh, line, or point geometry. Includes vertex 19384 * positions, face indices, normals, colors, UVs, and custom attributes 19385 * within buffers, reducing the cost of passing all this data to the GPU. 19386 * 19387 * ```js 19388 * const geometry = new THREE.BufferGeometry(); 19389 * // create a simple square shape. We duplicate the top left and bottom right 19390 * // vertices because each vertex needs to appear once per triangle. 19391 * const vertices = new Float32Array( [ 19392 * -1.0, -1.0, 1.0, // v0 19393 * 1.0, -1.0, 1.0, // v1 19394 * 1.0, 1.0, 1.0, // v2 19395 * 19396 * 1.0, 1.0, 1.0, // v3 19397 * -1.0, 1.0, 1.0, // v4 19398 * -1.0, -1.0, 1.0 // v5 19399 * ] ); 19400 * // itemSize = 3 because there are 3 values (components) per vertex 19401 * geometry.setAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); 19402 * const material = new THREE.MeshBasicMaterial( { color: 0xff0000 } ); 19403 * const mesh = new THREE.Mesh( geometry, material ); 19404 * ``` 19405 * 19406 * @augments EventDispatcher 19407 */ 19408class BufferGeometry extends EventDispatcher { 19409 19410 /** 19411 * Constructs a new geometry. 19412 */ 19413 constructor() { 19414 19415 super(); 19416 19417 /** 19418 * This flag can be used for type testing. 19419 * 19420 * @type {boolean} 19421 * @readonly 19422 * @default true 19423 */ 19424 this.isBufferGeometry = true; 19425 19426 /** 19427 * The ID of the geometry. 19428 * 19429 * @name BufferGeometry#id 19430 * @type {number} 19431 * @readonly 19432 */ 19433 Object.defineProperty( this, 'id', { value: _id$1 ++ } ); 19434 19435 /** 19436 * The UUID of the geometry. 19437 * 19438 * @type {string} 19439 * @readonly 19440 */ 19441 this.uuid = generateUUID(); 19442 19443 /** 19444 * The name of the geometry. 19445 * 19446 * @type {string} 19447 */ 19448 this.name = ''; 19449 this.type = 'BufferGeometry'; 19450 19451 /** 19452 * Allows for vertices to be re-used across multiple triangles; this is 19453 * called using "indexed triangles". Each triangle is associated with the 19454 * indices of three vertices. This attribute therefore stores the index of 19455 * each vertex for each triangular face. If this attribute is not set, the 19456 * renderer assumes that each three contiguous positions represent a single triangle. 19457 * 19458 * @type {?BufferAttribute} 19459 * @default null 19460 */ 19461 this.index = null; 19462 19463 /** 19464 * A (storage) buffer attribute which was generated with a compute shader and 19465 * now defines indirect draw calls. 19466 * 19467 * Can only be used with {@link WebGPURenderer} and a WebGPU backend. 19468 * 19469 * @type {?BufferAttribute} 19470 * @default null 19471 */ 19472 this.indirect = null; 19473 19474 /** 19475 * Th
19475is dictionary has as id the name of the attribute to be set and as value 19476 * the buffer attribute to set it to. Rather than accessing this property directly, 19477 * use `setAttribute()` and `getAttribute()` to access attributes of this geometry. 19478 * 19479 * @type {Object<string,(BufferAttribute|InterleavedBufferAttribute)>} 19480 */ 19481 this.attributes = {}; 19482 19483 /** 19484 * This dictionary holds the morph targets of the geometry. 19485 * 19486 * Note: Once the geometry has been rendered, the morph attribute data cannot 19487 * be changed. You will have to call `dispose()?, and create a new geometry instance. 19488 * 19489 * @type {Object} 19490 */ 19491 this.morphAttributes = {}; 19492 19493 /** 19494 * Used to control the morph target behavior; when set to `true`, the morph 19495 * target data is treated as relative offsets, rather than as absolute 19496 * positions/normals. 19497 * 19498 * @type {boolean} 19499 * @default false 19500 */ 19501 this.morphTargetsRelative = false; 19502 19503 /** 19504 * Split the geometry into groups, each of which will be rendered in a 19505 * separate draw call. This allows an array of materials to be used with the geometry. 19506 * 19507 * Use `addGroup()` and `clearGroups()` to edit groups, rather than modifying this array directly. 19508 * 19509 * Every vertex and index must belong to exactly one group â groups must not share vertices or 19510 * indices, and must not leave vertices or indices unused. 19511 * 19512 * @type {Array<Object>} 19513 */ 19514 this.groups = []; 19515 19516 /** 19517 * Bounding box for the geometry which can be calculated with `computeBoundingBox()`. 19518 * 19519 * @type {Box3} 19520 * @default null 19521 */ 19522 this.boundingBox = null; 19523 19524 /** 19525 * Bounding sphere for the geometry which can be calculated with `computeBoundingSphere()`. 19526 * 19527 * @type {Sphere} 19528 * @default null 19529 */ 19530 this.boundingSphere = null; 19531 19532 /** 19533 * Determines the part of the geometry to render. This should not be set directly, 19534 * instead use `setDrawRange()`. 19535 * 19536 * @type {{start:number,count:number}} 19537 */ 19538 this.drawRange = { start: 0, count: Infinity }; 19539 19540 /** 19541 * An object that can be used to store custom data about the geometry. 19542 * It should not hold references to functions as these will not be cloned. 19543 * 19544 * @type {Object} 19545 */ 19546 this.userData = {}; 19547 19548 } 19549 19550 /** 19551 * Returns the index of this geometry. 19552 * 19553 * @return {?BufferAttribute} The index. Returns `null` if no index is defined. 19554 */ 19555 getIndex() { 19556 19557 return this.index; 19558 19559 } 19560 19561 /** 19562 * Sets the given index to this geometry. 19563 * 19564 * @param {Array<number>|BufferAttribute} index - The index to set. 19565 * @return {BufferGeometry} A reference to this instance. 19566 */ 19567 setIndex( index ) { 19568 19569 if ( Array.isArray( index ) ) { 19570 19571 this.index = new ( arrayNeedsUint32( index ) ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 ); 19572 19573 } else { 19574 19575 this.index = index; 19576 19577 } 19578 19579 return this; 19580 19581 } 19582 19583 /** 19584 * Sets the given indirect attribute to this geometry. 19585 * 19586 * @param {BufferAttribute} indirect - The attribute holding indirect draw calls. 19587 * @return {BufferGeometry} A reference to this instance. 19588 */ 19589 setIndirect( indirect ) { 19590 19591 this.indirect = indirec
vendor: 3,681 bytes, lines 19591-19769
19591t; 19592 19593 return this; 19594 19595 } 19596 19597 /** 19598 * Returns the indirect attribute of this geometry. 19599 * 19600 * @return {?BufferAttribute} The indirect attribute. Returns `null` if no indirect attribute is defined. 19601 */ 19602 getIndirect() { 19603 19604 return this.indirect; 19605 19606 } 19607 19608 /** 19609 * Returns the buffer attribute for the given name. 19610 * 19611 * @param {string} name - The attribute name. 19612 * @return {BufferAttribute|InterleavedBufferAttribute|undefined} The buffer attribute. 19613 * Returns `undefined` if not attribute has been found. 19614 */ 19615 getAttribute( name ) { 19616 19617 return this.attributes[ name ]; 19618 19619 } 19620 19621 /** 19622 * Sets the given attribute for the given name. 19623 * 19624 * @param {string} name - The attribute name. 19625 * @param {BufferAttribute|InterleavedBufferAttribute} attribute - The attribute to set. 19626 * @return {BufferGeometry} A reference to this instance. 19627 */ 19628 setAttribute( name, attribute ) { 19629 19630 this.attributes[ name ] = attribute; 19631 19632 return this; 19633 19634 } 19635 19636 /** 19637 * Deletes the attribute for the given name. 19638 * 19639 * @param {string} name - The attribute name to delete. 19640 * @return {BufferGeometry} A reference to this instance. 19641 */ 19642 deleteAttribute( name ) { 19643 19644 delete this.attributes[ name ]; 19645 19646 return this; 19647 19648 } 19649 19650 /** 19651 * Returns `true` if this geometry has an attribute for the given name. 19652 * 19653 * @param {string} name - The attribute name. 19654 * @return {boolean} Whether this geometry has an attribute for the given name or not. 19655 */ 19656 hasAttribute( name ) { 19657 19658 return this.attributes[ name ] !== undefined; 19659 19660 } 19661 19662 /** 19663 * Adds a group to this geometry. 19664 * 19665 * @param {number} start - The first element in this draw call. That is the first 19666 * vertex for non-indexed geometry, otherwise the first triangle index. 19667 * @param {number} count - Specifies how many vertices (or indices) are part of this group. 19668 * @param {number} [materialIndex=0] - The material array index to use. 19669 */ 19670 addGroup( start, count, materialIndex = 0 ) { 19671 19672 this.groups.push( { 19673 19674 start: start, 19675 count: count, 19676 materialIndex: materialIndex 19677 19678 } ); 19679 19680 } 19681 19682 /** 19683 * Clears all groups. 19684 */ 19685 clearGroups() { 19686 19687 this.groups = []; 19688 19689 } 19690 19691 /** 19692 * Sets the draw range for this geometry. 19693 * 19694 * @param {number} start - The first vertex for non-indexed geometry, otherwise the first triangle index. 19695 * @param {number} count - For non-indexed BufferGeometry, `count` is the number of vertices to render. 19696 * For indexed BufferGeometry, `count` is the number of indices to render. 19697 */ 19698 setDrawRange( start, count ) { 19699 19700 this.drawRange.start = start; 19701 this.drawRange.count = count; 19702 19703 } 19704 19705 /** 19706 * Applies the given 4x4 transformation matrix to the geometry. 19707 * 19708 * @param {Matrix4} matrix - The matrix to apply. 19709 * @return {BufferGeometry} A reference to this instance. 19710 */ 19711 applyMatrix4( matrix ) { 19712 19713 const position = this.attributes.position; 19714 19715 if ( position !== undefined ) { 19716 19717 position.applyMatrix4( matrix ); 19718 19719 position.needsUpdate = true; 19720 19721 } 19722 19723 const normal = this.attributes.normal; 19724 19725 if ( normal !== undefined ) { 19726 19727 const normalMatrix = new Matrix3().getNormalMatrix( matrix ); 19728 19729 normal.applyNormalMatrix( normalMatrix ); 19730 19731 normal.needsUpdate = true; 19732 19733 } 19734 19735 const tangent = this.attributes.tangent; 19736 19737 if ( tangent !== undefined ) { 19738 19739 tangent.transformDirection( matrix ); 19740 19741 tangent.needsUpdate = true; 19742 19743 } 19744 19745 if ( this.boundingBox !== null ) { 19746 19747 this.computeBoundingBox(); 19748 19749 } 19750 19751 if ( this.boundingSphere !== null ) { 19752 19753 this.computeBoundingSphere(); 19754 19755 } 19756 19757 return this; 19758 19759 } 19760 19761 /** 19762 * Applies the rotation represented by the Quaternion to the geometry. 19763 * 19764 * @param {Quaternion} q - The Quaternion to apply. 19765 * @return {BufferGeometry} A reference to this instance. 19766 */ 19767 applyQuaternion( q ) { 19768 19769 _m1
19769.makeRotationFromQuaternion( q ); 19770 19771 this.applyMatrix4( _m1 ); 19772 19773 return this; 19774 19775 } 19776 19777 /** 19778 * Rotates the geometry about the X axis. This is typically done as a one time 19779 * operation, and not during a loop. Use {@link Object3D#rotation} for typical 19780 * real-time mesh rotation. 19781 * 19782 * @param {number} angle - The angle in radians. 19783 * @return {BufferGeometry} A reference to this instance. 19784 */ 19785 rotateX( angle ) { 19786 19787 // rotate geometry around world x-axis 19788 19789 _m1.makeRotationX( angle ); 19790 19791 this.applyMatrix4( _m1 ); 19792 19793 return this; 19794 19795 } 19796 19797 /** 19798 * Rotates the geometry about the Y axis. This is typically done as a one time 19799 * operation, and not during a loop. Use {@link Object3D#rotation} for typical 19800 * real-time mesh rotation. 19801 * 19802 * @param {number} angle - The angle in radians. 19803 * @return {BufferGeometry} A reference to this instance. 19804 */ 19805 rotateY( angle ) { 19806 19807 // rotate geometry around world y-axis 19808 19809 _m1.makeRotationY( angle ); 19810 19811 this.applyMatrix4( _m1 ); 19812 19813 return this; 19814 19815 } 19816 19817 /** 19818 * Rotates the geometry about the Z axis. This is typically done as a one time 19819 * operation, and not during a loop. Use {@link Object3D#rotation} for typical 19820 * real-time mesh rotation. 19821 * 19822 * @param {number} angle - The angle in radians. 19823 * @return {BufferGeometry} A reference to this instance. 19824 */ 19825 rotateZ( angle ) { 19826 19827 // rotate geometry around world z-axis 19828 19829 _m1.makeRotationZ( angle ); 19830 19831 this.applyMatrix4( _m1 ); 19832 19833 return this; 19834 19835 } 19836 19837 /** 19838 * Translates the geometry. This is typically done as a one time 19839 * operation, and not during a loop. Use {@link Object3D#position} for typical 19840 * real-time mesh rotation. 19841 * 19842 * @param {number} x - The x offset. 19843 * @param {number} y - The y offset. 19844 * @param {number} z - The z offset. 19845 * @return {BufferGeometry} A reference to this instance. 19846 */ 19847 translate( x, y, z ) { 19848 19849 // translate geometry 19850 19851 _m1.makeTranslation( x, y, z ); 19852 19853 this.applyMatrix4( _m1 ); 19854 19855 return this; 19856 19857 } 19858 19859 /** 19860 * Scales the geometry. This is typically done as a one time 19861 * operation, and not during a loop. Use {@link Object3D#scale} for typical 19862 * real-time mesh rotation. 19863 * 19864 * @param {number} x - The x scale. 19865 * @param {number} y - The y scale. 19866 * @param {number} z - The z scale. 19867 * @return {BufferGeometry} A reference to this instance. 19868 */ 19869 scale( x, y, z ) { 19870 19871 // scale geometry 19872 19873 _m1.makeScale( x, y, z ); 19874 19875 this.applyMatrix4( _m1 ); 19876 19877 return this; 19878 19879 } 19880 19881 /** 19882 * Rotates the geometry to face a point in 3D space. This is typically done as a one time 19883 * operation, and not during a loop. Use {@link Object3D#lookAt} for typical 19884 * real-time mesh rotation. 19885 * 19886 * @param {Vector3} vector - The target point. 19887 * @return {BufferGeometry} A reference to this instance. 19888 */ 19889 lookAt( vector ) { 19890 19891 _obj.lookAt( vector ); 19892 19893 _obj.updateMatrix(); 19894 19895 this.applyMatrix4( _obj.matrix ); 19896 19897 return this; 19898 19899 } 19900 19901 /** 19902 * Center the geometry based on its bounding box. 19903 * 19904 * @return {BufferGeometry} A reference to this instance. 19905 */ 19906 center() { 19907 19908 this.computeBoundingBox(); 19909 19910 this.boundingBox.getCenter( _offset ).negate(); 19911 19912 this.translate( _offset.x, _offset.y, _offset.z ); 19913 19914 return this; 19915 19916 } 19917
vendor: 5,043 bytes, lines 19918-20109
19918 /** 19919 * Defines a geometry by creating a `position` attribute based on the given array of points. The array 19920 * can hold 2D or 3D vectors. When using two-dimensional data, the `z` coordinate for all vertices is 19921 * set to `0`. 19922 * 19923 * If the method is used with an existing `position` attribute, the vertex data are overwritten with the 19924 * data from the array. The length of the array must match the vertex count. 19925 * 19926 * @param {Array<Vector2>|Array<Vector3>} points - The points. 19927 * @return {BufferGeometry} A reference to this instance. 19928 */ 19929 setFromPoints( points ) { 19930 19931 const positionAttribute = this.getAttribute( 'position' ); 19932 19933 if ( positionAttribute === undefined ) { 19934 19935 const position = []; 19936 19937 for ( let i = 0, l = points.length; i < l; i ++ ) { 19938 19939 const point = points[ i ]; 19940 position.push( point.x, point.y, point.z || 0 ); 19941 19942 } 19943 19944 this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) ); 19945 19946 } else { 19947 19948 const l = Math.min( points.length, positionAttribute.count ); // make sure data do not exceed buffer size 19949 19950 for ( let i = 0; i < l; i ++ ) { 19951 19952 const point = points[ i ]; 19953 positionAttribute.setXYZ( i, point.x, point.y, point.z || 0 ); 19954 19955 } 19956 19957 if ( points.length > positionAttribute.count ) { 19958 19959 console.warn( 'THREE.BufferGeometry: Buffer size too small for points data. Use .dispose() and create a new geometry.' ); 19960 19961 } 19962 19963 positionAttribute.needsUpdate = true; 19964 19965 } 19966 19967 return this; 19968 19969 } 19970 19971 /** 19972 * Computes the bounding box of the geometry, and updates the `boundingBox` member. 19973 * The bounding box is not computed by the engine; it must be computed by your app. 19974 * You may need to recompute the bounding box if the geometry vertices are modified. 19975 */ 19976 computeBoundingBox() { 19977 19978 if ( this.boundingBox === null ) { 19979 19980 this.boundingBox = new Box3(); 19981 19982 } 19983 19984 const position = this.attributes.position; 19985 const morphAttributesPosition = this.morphAttributes.position; 19986 19987 if ( position && position.isGLBufferAttribute ) { 19988 19989 console.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box.', this ); 19990 19991 this.boundingBox.set( 19992 new Vector3( - Infinity, - Infinity, - Infinity ), 19993 new Vector3( + Infinity, + Infinity, + Infinity ) 19994 ); 19995 19996 return; 19997 19998 } 19999 20000 if ( position !== undefined ) { 20001 20002 this.boundingBox.setFromBufferAttribute( position ); 20003 20004 // process morph attributes if present 20005 20006 if ( morphAttributesPosition ) { 20007 20008 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { 20009 20010 const morphAttribute = morphAttributesPosition[ i ]; 20011 _box$2.setFromBufferAttribute( morphAttribute ); 20012 20013 if ( this.morphTargetsRelative ) { 20014 20015 _vector$8.addVectors( this.boundingBox.min, _box$2.min ); 20016 this.boundingBox.expandByPoint( _vector$8 ); 20017 20018 _vector$8.addVectors( this.boundingBox.max, _box$2.max ); 20019 this.boundingBox.expandByPoint( _vector$8 ); 20020 20021 } else { 20022 20023 this.boundingBox.expandByPoint( _box$2.min ); 20024 this.boundingBox.expandByPoint( _box$2.max ); 20025 20026 } 20027 20028 } 20029 20030 } 20031 20032 } else { 20033 20034 this.boundingBox.makeEmpty(); 20035 20036 } 20037 20038 if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { 20039 20040 console.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this ); 20041 20042 } 20043 20044 } 20045 20046 /** 20047 * Computes the bounding sphere of the geometry, and updates the `boundingSphere` member. 20048 * The engine automatically computes the bounding sphere when it is needed, e.g., for ray casting or view frustum culling. 20049 * You may need to recompute the bounding sphere if the geometry vertices are modified. 20050 */ 20051 computeBoundingSphere() { 20052 20053 if ( this.boundingSphere === null ) { 20054 20055 this.boundingSphere = new Sphere(); 20056 20057 } 20058 20059 const position = this.attributes.position; 20060 const morphAttributesPosition = this.morphAttributes.position; 20061 20062 if ( position && position.isGLBufferAttribute ) { 20063 20064 console.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere.', this ); 20065 20066 this.boundingSphere.set( new Vector3(), Infinity ); 20067 20068 return; 20069 20070 } 20071 20072 if ( position ) { 20073 20074 // first, find the center of the bounding sphere 20075 20076 const center = this.boundingSphere.center; 20077 20078 _box$2.setFromBufferAttribute( position ); 20079 20080 // process morph attributes if present 20081 20082 if ( morphAttributesPosition ) { 20083 20084 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { 20085 20086 const morphAttribute = morphAttributesPosition[ i ]; 20087 _boxMorphTargets.setFromBufferAttribute( morphAttribute ); 20088 20089 if ( this.morphTargetsRelative ) { 20090 20091 _vector$8.addVectors( _box$2.min, _boxMorphTargets.min ); 20092 _box$2.expandByPoint( _vector$8 ); 20093 20094 _vector$8.addVectors( _box$2.max, _boxMorphTargets.max ); 20095 _box$2.expandByPoint( _vector$8 ); 20096 20097 } else { 20098 20099 _box$2.expandByPoint( _boxMorphTargets.min ); 20100 _box$2.expandByPoint( _boxMorphTargets.max ); 20101 20102 } 20103 20104 } 20105 20106 } 20107 20108 _box$2.getCenter( center ); 20109
vendor: 5,099 bytes, lines 20110-20328
20110 // second, try to find a boundingSphere with a radius smaller than the 20111 // boundingSphere of the boundingBox: sqrt(3) smaller in the best case 20112 20113 let maxRadiusSq = 0; 20114 20115 for ( let i = 0, il = position.count; i < il; i ++ ) { 20116 20117 _vector$8.fromBufferAttribute( position, i ); 20118 20119 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) ); 20120 20121 } 20122 20123 // process morph attributes if present 20124 20125 if ( morphAttributesPosition ) { 20126 20127 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { 20128 20129 const morphAttribute = morphAttributesPosition[ i ]; 20130 const morphTargetsRelative = this.morphTargetsRelative; 20131 20132 for ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) { 20133 20134 _vector$8.fromBufferAttribute( morphAttribute, j ); 20135 20136 if ( morphTargetsRelative ) { 20137 20138 _offset.fromBufferAttribute( position, j ); 20139 _vector$8.add( _offset ); 20140 20141 } 20142 20143 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) ); 20144 20145 } 20146 20147 } 20148 20149 } 20150 20151 this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); 20152 20153 if ( isNaN( this.boundingSphere.radius ) ) { 20154 20155 console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); 20156 20157 } 20158 20159 } 20160 20161 } 20162 20163 /** 20164 * Calculates and adds a tangent attribute to this geometry. 20165 * 20166 * The computation is only supported for indexed geometries and if position, normal, and uv attributes 20167 * are defined. When using a tangent space normal map, prefer the MikkTSpace algorithm provided by 20168 * {@link BufferGeometryUtils#computeMikkTSpaceTangents} instead. 20169 */ 20170 computeTangents() { 20171 20172 const index = this.index; 20173 const attributes = this.attributes; 20174 20175 // based on http://www.terathon.com/code/tangent.html 20176 // (per vertex tangents) 20177 20178 if ( index === null || 20179 attributes.position === undefined || 20180 attributes.normal === undefined || 20181 attributes.uv === undefined ) { 20182 20183 console.error( 'THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' ); 20184 return; 20185 20186 } 20187 20188 const positionAttribute = attributes.position; 20189 const normalAttribute = attributes.normal; 20190 const uvAttribute = attributes.uv; 20191 20192 if ( this.hasAttribute( 'tangent' ) === false ) { 20193 20194 this.setAttribute( 'tangent', new BufferAttribute( new Float32Array( 4 * positionAttribute.count ), 4 ) ); 20195 20196 } 20197 20198 const tangentAttribute = this.getAttribute( 'tangent' ); 20199 20200 const tan1 = [], tan2 = []; 20201 20202 for ( let i = 0; i < positionAttribute.count; i ++ ) { 20203 20204 tan1[ i ] = new Vector3(); 20205 tan2[ i ] = new Vector3(); 20206 20207 } 20208 20209 const vA = new Vector3(), 20210 vB = new Vector3(), 20211 vC = new Vector3(), 20212 20213 uvA = new Vector2(), 20214 uvB = new Vector2(), 20215 uvC = new Vector2(), 20216 20217 sdir = new Vector3(), 20218 tdir = new Vector3(); 20219 20220 function handleTriangle( a, b, c ) { 20221 20222 vA.fromBufferAttribute( positionAttribute, a ); 20223 vB.fromBufferAttribute( positionAttribute, b ); 20224 vC.fromBufferAttribute( positionAttribute, c ); 20225 20226 uvA.fromBufferAttribute( uvAttribute, a ); 20227 uvB.fromBufferAttribute( uvAttribute, b ); 20228 uvC.fromBufferAttribute( uvAttribute, c ); 20229 20230 vB.sub( vA ); 20231 vC.sub( vA ); 20232 20233 uvB.sub( uvA ); 20234 uvC.sub( uvA ); 20235 20236 const r = 1.0 / ( uvB.x * uvC.y - uvC.x * uvB.y ); 20237 20238 // silently ignore degenerate uv triangles having coincident or colinear vertices 20239 20240 if ( ! isFinite( r ) ) return; 20241 20242 sdir.copy( vB ).multiplyScalar( uvC.y ).addScaledVector( vC, - uvB.y ).multiplyScalar( r ); 20243 tdir.copy( vC ).multiplyScalar( uvB.x ).addScaledVector( vB, - uvC.x ).multiplyScalar( r ); 20244 20245 tan1[ a ].add( sdir ); 20246 tan1[ b ].add( sdir ); 20247 tan1[ c ].add( sdir ); 20248 20249 tan2[ a ].add( tdir ); 20250 tan2[ b ].add( tdir ); 20251 tan2[ c ].add( tdir ); 20252 20253 } 20254 20255 let groups = this.groups; 20256 20257 if ( groups.length === 0 ) { 20258 20259 groups = [ { 20260 start: 0, 20261 count: index.count 20262 } ]; 20263 20264 } 20265 20266 for ( let i = 0, il = groups.length; i < il; ++ i ) { 20267 20268 const group = groups[ i ]; 20269 20270 const start = group.start; 20271 const count = group.count; 20272 20273 for ( let j = start, jl = start + count; j < jl; j += 3 ) { 20274 20275 handleTriangle( 20276 index.getX( j + 0 ), 20277 index.getX( j + 1 ), 20278 index.getX( j + 2 ) 20279 ); 20280 20281 } 20282 20283 } 20284 20285 const tmp = new Vector3(), tmp2 = new Vector3(); 20286 const n = new Vector3(), n2 = new Vector3(); 20287 20288 function handleVertex( v ) { 20289 20290 n.fromBufferAttribute( normalAttribute, v ); 20291 n2.copy( n ); 20292 20293 const t = tan1[ v ]; 20294 20295 // Gram-Schmidt orthogonalize 20296 20297 tmp.copy( t ); 20298 tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); 20299 20300 // Calculate handedness 20301 20302 tmp2.crossVectors( n2, t ); 20303 const test = tmp2.dot( tan2[ v ] ); 20304 const w = ( test < 0.0 ) ? -1 : 1.0; 20305 20306 tangentAttribute.setXYZW( v, tmp.x, tmp.y, tmp.z, w ); 20307 20308 } 20309 20310 for ( let i = 0, il = groups.length; i < il; ++ i ) { 20311 20312 const group = groups[ i ]; 20313 20314 const start = group.start; 20315 const count = group.count; 20316 20317 for ( let j = start, jl = start + count; j < jl; j += 3 ) { 20318 20319 handleVertex( index.getX( j + 0 ) ); 20320 handleVertex( index.getX( j + 1 ) ); 20321 handleVertex( index.getX( j + 2 ) ); 20322 20323 } 20324 20325 } 20326 20327 } 20328
vendor: 4,020 bytes, lines 20329-20493
20329 /** 20330 * Computes vertex normals for the given vertex data. For indexed geometries, the method sets 20331 * each vertex normal to be the average of the face normals of the faces that share that vertex. 20332 * For non-indexed geometries, vertices are not shared, and the method sets each vertex normal 20333 * to be the same as the face normal. 20334 */ 20335 computeVertexNormals() { 20336 20337 const index = this.index; 20338 const positionAttribute = this.getAttribute( 'position' ); 20339 20340 if ( positionAttribute !== undefined ) { 20341 20342 let normalAttribute = this.getAttribute( 'normal' ); 20343 20344 if ( normalAttribute === undefined ) { 20345 20346 normalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 ); 20347 this.setAttribute( 'normal', normalAttribute ); 20348 20349 } else { 20350 20351 // reset existing normals to zero 20352 20353 for ( let i = 0, il = normalAttribute.count; i < il; i ++ ) { 20354 20355 normalAttribute.setXYZ( i, 0, 0, 0 ); 20356 20357 } 20358 20359 } 20360 20361 const pA = new Vector3(), pB = new Vector3(), pC = new Vector3(); 20362 const nA = new Vector3(), nB = new Vector3(), nC = new Vector3(); 20363 const cb = new Vector3(), ab = new Vector3(); 20364 20365 // indexed elements 20366 20367 if ( index ) { 20368 20369 for ( let i = 0, il = index.count; i < il; i += 3 ) { 20370 20371 const vA = index.getX( i + 0 ); 20372 const vB = index.getX( i + 1 ); 20373 const vC = index.getX( i + 2 ); 20374 20375 pA.fromBufferAttribute( positionAttribute, vA ); 20376 pB.fromBufferAttribute( positionAttribute, vB ); 20377 pC.fromBufferAttribute( positionAttribute, vC ); 20378 20379 cb.subVectors( pC, pB ); 20380 ab.subVectors( pA, pB ); 20381 cb.cross( ab ); 20382 20383 nA.fromBufferAttribute( normalAttribute, vA ); 20384 nB.fromBufferAttribute( normalAttribute, vB ); 20385 nC.fromBufferAttribute( normalAttribute, vC ); 20386 20387 nA.add( cb ); 20388 nB.add( cb ); 20389 nC.add( cb ); 20390 20391 normalAttribute.setXYZ( vA, nA.x, nA.y, nA.z ); 20392 normalAttribute.setXYZ( vB, nB.x, nB.y, nB.z ); 20393 normalAttribute.setXYZ( vC, nC.x, nC.y, nC.z ); 20394 20395 } 20396 20397 } else { 20398 20399 // non-indexed elements (unconnected triangle soup) 20400 20401 for ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) { 20402 20403 pA.fromBufferAttribute( positionAttribute, i + 0 ); 20404 pB.fromBufferAttribute( positionAttribute, i + 1 ); 20405 pC.fromBufferAttribute( positionAttribute, i + 2 ); 20406 20407 cb.subVectors( pC, pB ); 20408 ab.subVectors( pA, pB ); 20409 cb.cross( ab ); 20410 20411 normalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z ); 20412 normalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z ); 20413 normalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z ); 20414 20415 } 20416 20417 } 20418 20419 this.normalizeNormals(); 20420 20421 normalAttribute.needsUpdate = true; 20422 20423 } 20424 20425 } 20426 20427 /** 20428 * Ensures every normal vector in a geometry will have a magnitude of `1`. This will 20429 * correct lighting on the geometry surfaces. 20430 */ 20431 normalizeNormals() { 20432 20433 const normals = this.attributes.normal; 20434 20435 for ( let i = 0, il = normals.count; i < il; i ++ ) { 20436 20437 _vector$8.fromBufferAttribute( normals, i ); 20438 20439 _vector$8.normalize(); 20440 20441 normals.setXYZ( i, _vector$8.x, _vector$8.y, _vector$8.z ); 20442 20443 } 20444 20445 } 20446 20447 /** 20448 * Return a new non-index version of this indexed geometry. If the geometry 20449 * is already non-indexed, the method is a NOOP. 20450 * 20451 * @return {BufferGeometry} The non-indexed version of this indexed geometry. 20452 */ 20453 toNonIndexed() { 20454 20455 function convertBufferAttribute( attribute, indices ) { 20456 20457 const array = attribute.array; 20458 const itemSize = attribute.itemSize; 20459 const normalized = attribute.normalized; 20460 20461 const array2 = new array.constructor( indices.length * itemSize ); 20462 20463 let index = 0, index2 = 0; 20464 20465 for ( let i = 0, l = indices.length; i < l; i ++ ) { 20466 20467 if ( attribute.isInterleavedBufferAttribute ) { 20468 20469 index = indices[ i ] * attribute.data.stride + attribute.offset; 20470 20471 } else { 20472 20473 index = indices[ i ] * itemSize; 20474 20475 } 20476 20477 for ( let j = 0; j < itemSize; j ++ ) { 20478 20479 array2[ index2 ++ ] = array[ index ++ ]; 20480 20481 } 20482 20483 } 20484 20485 return new BufferAttribute( array2, itemSize, normalized ); 20486 20487 } 20488 20489 // 20490 20491 if ( this.index === null ) { 20492 20493 console.warn( 'THREE.
vendor: 1,446 bytes, lines 20493-20564
20493BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' ); 20494 return this; 20495 20496 } 20497 20498 const geometry2 = new BufferGeometry(); 20499 20500 const indices = this.index.array; 20501 const attributes = this.attributes; 20502 20503 // attributes 20504 20505 for ( const name in attributes ) { 20506 20507 const attribute = attributes[ name ]; 20508 20509 const newAttribute = convertBufferAttribute( attribute, indices ); 20510 20511 geometry2.setAttribute( name, newAttribute ); 20512 20513 } 20514 20515 // morph attributes 20516 20517 const morphAttributes = this.morphAttributes; 20518 20519 for ( const name in morphAttributes ) { 20520 20521 const morphArray = []; 20522 const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes 20523 20524 for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) { 20525 20526 const attribute = morphAttribute[ i ]; 20527 20528 const newAttribute = convertBufferAttribute( attribute, indices ); 20529 20530 morphArray.push( newAttribute ); 20531 20532 } 20533 20534 geometry2.morphAttributes[ name ] = morphArray; 20535 20536 } 20537 20538 geometry2.morphTargetsRelative = this.morphTargetsRelative; 20539 20540 // groups 20541 20542 const groups = this.groups; 20543 20544 for ( let i = 0, l = groups.length; i < l; i ++ ) { 20545 20546 const group = groups[ i ]; 20547 geometry2.addGroup( group.start, group.count, group.materialIndex ); 20548 20549 } 20550 20551 return geometry2; 20552 20553 } 20554 20555 /** 20556 * Serializes the geometry into JSON. 20557 * 20558 * @return {Object} A JSON object representing the serialized geometry. 20559 */ 20560 toJSON() { 20561 20562 const data = { 20563 metadata: { 20564 version: 4.
vendor: 2,295 bytes, lines 20564-20687
205646, 20565 type: 'BufferGeometry', 20566 generator: 'BufferGeometry.toJSON' 20567 } 20568 }; 20569 20570 // standard BufferGeometry serialization 20571 20572 data.uuid = this.uuid; 20573 data.type = this.type; 20574 if ( this.name !== '' ) data.name = this.name; 20575 if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData; 20576 20577 if ( this.parameters !== undefined ) { 20578 20579 const parameters = this.parameters; 20580 20581 for ( const key in parameters ) { 20582 20583 if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; 20584 20585 } 20586 20587 return data; 20588 20589 } 20590 20591 // for simplicity the code assumes attributes are not shared across geometries, see #15811 20592 20593 data.data = { attributes: {} }; 20594 20595 const index = this.index; 20596 20597 if ( index !== null ) { 20598 20599 data.data.index = { 20600 type: index.array.constructor.name, 20601 array: Array.prototype.slice.call( index.array ) 20602 }; 20603 20604 } 20605 20606 const attributes = this.attributes; 20607 20608 for ( const key in attributes ) { 20609 20610 const attribute = attributes[ key ]; 20611 20612 data.data.attributes[ key ] = attribute.toJSON( data.data ); 20613 20614 } 20615 20616 const morphAttributes = {}; 20617 let hasMorphAttributes = false; 20618 20619 for ( const key in this.morphAttributes ) { 20620 20621 const attributeArray = this.morphAttributes[ key ]; 20622 20623 const array = []; 20624 20625 for ( let i = 0, il = attributeArray.length; i < il; i ++ ) { 20626 20627 const attribute = attributeArray[ i ]; 20628 20629 array.push( attribute.toJSON( data.data ) ); 20630 20631 } 20632 20633 if ( array.length > 0 ) { 20634 20635 morphAttributes[ key ] = array; 20636 20637 hasMorphAttributes = true; 20638 20639 } 20640 20641 } 20642 20643 if ( hasMorphAttributes ) { 20644 20645 data.data.morphAttributes = morphAttributes; 20646 data.data.morphTargetsRelative = this.morphTargetsRelative; 20647 20648 } 20649 20650 const groups = this.groups; 20651 20652 if ( groups.length > 0 ) { 20653 20654 data.data.groups = JSON.parse( JSON.stringify( groups ) ); 20655 20656 } 20657 20658 const boundingSphere = this.boundingSphere; 20659 20660 if ( boundingSphere !== null ) { 20661 20662 data.data.boundingSphere = { 20663 center: boundingSphere.center.toArray(), 20664 radius: boundingSphere.radius 20665 }; 20666 20667 } 20668 20669 return data; 20670 20671 } 20672 20673 /** 20674 * Returns a new geometry with copied values from this instance. 20675 * 20676 * @return {BufferGeometry} A clone of this instance. 20677 */ 20678 clone() { 20679 20680 return new this.constructor().copy( this ); 20681 20682 } 20683 20684 /** 20685 * Copies the values of the given geometry to this instance. 20686 * 20687 * @param {BufferGeometry}
vendor: 4,893 bytes, lines 20687-20920
20687 source - The geometry to copy. 20688 * @return {BufferGeometry} A reference to this instance. 20689 */ 20690 copy( source ) { 20691 20692 // reset 20693 20694 this.index = null; 20695 this.attributes = {}; 20696 this.morphAttributes = {}; 20697 this.groups = []; 20698 this.boundingBox = null; 20699 this.boundingSphere = null; 20700 20701 // used for storing cloned, shared data 20702 20703 const data = {}; 20704 20705 // name 20706 20707 this.name = source.name; 20708 20709 // index 20710 20711 const index = source.index; 20712 20713 if ( index !== null ) { 20714 20715 this.setIndex( index.clone() ); 20716 20717 } 20718 20719 // attributes 20720 20721 const attributes = source.attributes; 20722 20723 for ( const name in attributes ) { 20724 20725 const attribute = attributes[ name ]; 20726 this.setAttribute( name, attribute.clone( data ) ); 20727 20728 } 20729 20730 // morph attributes 20731 20732 const morphAttributes = source.morphAttributes; 20733 20734 for ( const name in morphAttributes ) { 20735 20736 const array = []; 20737 const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes 20738 20739 for ( let i = 0, l = morphAttribute.length; i < l; i ++ ) { 20740 20741 array.push( morphAttribute[ i ].clone( data ) ); 20742 20743 } 20744 20745 this.morphAttributes[ name ] = array; 20746 20747 } 20748 20749 this.morphTargetsRelative = source.morphTargetsRelative; 20750 20751 // groups 20752 20753 const groups = source.groups; 20754 20755 for ( let i = 0, l = groups.length; i < l; i ++ ) { 20756 20757 const group = groups[ i ]; 20758 this.addGroup( group.start, group.count, group.materialIndex ); 20759 20760 } 20761 20762 // bounding box 20763 20764 const boundingBox = source.boundingBox; 20765 20766 if ( boundingBox !== null ) { 20767 20768 this.boundingBox = boundingBox.clone(); 20769 20770 } 20771 20772 // bounding sphere 20773 20774 const boundingSphere = source.boundingSphere; 20775 20776 if ( boundingSphere !== null ) { 20777 20778 this.boundingSphere = boundingSphere.clone(); 20779 20780 } 20781 20782 // draw range 20783 20784 this.drawRange.start = source.drawRange.start; 20785 this.drawRange.count = source.drawRange.count; 20786 20787 // user data 20788 20789 this.userData = source.userData; 20790 20791 return this; 20792 20793 } 20794 20795 /** 20796 * Frees the GPU-related resources allocated by this instance. Call this 20797 * method whenever this instance is no longer used in your app. 20798 * 20799 * @fires BufferGeometry#dispose 20800 */ 20801 dispose() { 20802 20803 this.dispatchEvent( { type: 'dispose' } ); 20804 20805 } 20806 20807} 20808 20809const _inverseMatrix$3 = /*@__PURE__*/ new Matrix4(); 20810const _ray$3 = /*@__PURE__*/ new Ray(); 20811const _sphere$6 = /*@__PURE__*/ new Sphere(); 20812const _sphereHitAt = /*@__PURE__*/ new Vector3(); 20813 20814const _vA$1 = /*@__PURE__*/ new Vector3(); 20815const _vB$1 = /*@__PURE__*/ new Vector3(); 20816const _vC$1 = /*@__PURE__*/ new Vector3(); 20817 20818const _tempA = /*@__PURE__*/ new Vector3(); 20819const _morphA = /*@__PURE__*/ new Vector3(); 20820 20821const _intersectionPoint = /*@__PURE__*/ new Vector3(); 20822const _intersectionPointWorld = /*@__PURE__*/ new Vector3(); 20823 20824/** 20825 * Class representing triangular polygon mesh based objects. 20826 * 20827 * ```js 20828 * const geometry = new THREE.BoxGeometry( 1, 1, 1 ); 20829 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); 20830 * const mesh = new THREE.Mesh( geometry, material ); 20831 * scene.add( mesh ); 20832 * ``` 20833 * 20834 * @augments Object3D 20835 */ 20836class Mesh extends Object3D { 20837 20838 /** 20839 * Constructs a new mesh. 20840 * 20841 * @param {BufferGeometry} [geometry] - The mesh geometry. 20842 * @param {Material|Array<Material>} [material] - The mesh material. 20843 */ 20844 constructor( geometry = new BufferGeometry(), material = new MeshBasicMaterial() ) { 20845 20846 super(); 20847 20848 /** 20849 * This flag can be used for type testing. 20850 * 20851 * @type {boolean} 20852 * @readonly 20853 * @default true 20854 */ 20855 this.isMesh = true; 20856 20857 this.type = 'Mesh'; 20858 20859 /** 20860 * The mesh geometry. 20861 * 20862 * @type {BufferGeometry} 20863 */ 20864 this.geometry = geometry; 20865 20866 /** 20867 * The mesh material. 20868 * 20869 * @type {Material|Array<Material>} 20870 * @default MeshBasicMaterial 20871 */ 20872 this.material = material; 20873 20874 /** 20875 * A dictionary representing the morph targets in the geometry. The key is the 20876 * morph targets name, the value its attribute index. This member is `undefined` 20877 * by default and only set when morph targets are detected in the geometry. 20878 * 20879 * @type {Object<String,number>|undefined} 20880 * @default undefined 20881 */ 20882 this.morphTargetDictionary = undefined; 20883 20884 /** 20885 * An array of weights typically in the range `[0,1]` that specify how much of the morph 20886 * is applied. This member is `undefined` by default and only set when morph targets are 20887 * detected in the geometry. 20888 * 20889 * @type {Array<number>|undefined} 20890 * @default undefined 20891 */ 20892 this.morphTargetInfluences = undefined; 20893 20894 this.updateMorphTargets(); 20895 20896 } 20897 20898 copy( source, recursive ) { 20899 20900 super.copy( source, recursive ); 20901 20902 if ( source.morphTargetInfluences !== undefined ) { 20903 20904 this.morphTargetInfluences = source.morphTargetInfluences.slice(); 20905 20906 } 20907 20908 if ( source.morphTargetDictionary !== undefined ) { 20909 20910 this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary ); 20911 20912 } 20913 20914 this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; 20915 this.geometry = source.geometry; 20916 20917 return this; 20918 20919 } 20920
vendor: 8,498 bytes, lines 20921-21254
20921 /** 20922 * Sets the values of {@link Mesh#morphTargetDictionary} and {@link Mesh#morphTargetInfluences} 20923 * to make sure existing morph targets can influence this 3D object. 20924 */ 20925 updateMorphTargets() { 20926 20927 const geometry = this.geometry; 20928 20929 const morphAttributes = geometry.morphAttributes; 20930 const keys = Object.keys( morphAttributes ); 20931 20932 if ( keys.length > 0 ) { 20933 20934 const morphAttribute = morphAttributes[ keys[ 0 ] ]; 20935 20936 if ( morphAttribute !== undefined ) { 20937 20938 this.morphTargetInfluences = []; 20939 this.morphTargetDictionary = {}; 20940 20941 for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { 20942 20943 const name = morphAttribute[ m ].name || String( m ); 20944 20945 this.morphTargetInfluences.push( 0 ); 20946 this.morphTargetDictionary[ name ] = m; 20947 20948 } 20949 20950 } 20951 20952 } 20953 20954 } 20955 20956 /** 20957 * Returns the local-space position of the vertex at the given index, taking into 20958 * account the current animation state of both morph targets and skinning. 20959 * 20960 * @param {number} index - The vertex index. 20961 * @param {Vector3} target - The target object that is used to store the method's result. 20962 * @return {Vector3} The vertex position in local space. 20963 */ 20964 getVertexPosition( index, target ) { 20965 20966 const geometry = this.geometry; 20967 const position = geometry.attributes.position; 20968 const morphPosition = geometry.morphAttributes.position; 20969 const morphTargetsRelative = geometry.morphTargetsRelative; 20970 20971 target.fromBufferAttribute( position, index ); 20972 20973 const morphInfluences = this.morphTargetInfluences; 20974 20975 if ( morphPosition && morphInfluences ) { 20976 20977 _morphA.set( 0, 0, 0 ); 20978 20979 for ( let i = 0, il = morphPosition.length; i < il; i ++ ) { 20980 20981 const influence = morphInfluences[ i ]; 20982 const morphAttribute = morphPosition[ i ]; 20983 20984 if ( influence === 0 ) continue; 20985 20986 _tempA.fromBufferAttribute( morphAttribute, index ); 20987 20988 if ( morphTargetsRelative ) { 20989 20990 _morphA.addScaledVector( _tempA, influence ); 20991 20992 } else { 20993 20994 _morphA.addScaledVector( _tempA.sub( target ), influence ); 20995 20996 } 20997 20998 } 20999 21000 target.add( _morphA ); 21001 21002 } 21003 21004 return target; 21005 21006 } 21007 21008 /** 21009 * Computes intersection points between a casted ray and this line. 21010 * 21011 * @param {Raycaster} raycaster - The raycaster. 21012 * @param {Array<Object>} intersects - The target array that holds the intersection points. 21013 */ 21014 raycast( raycaster, intersects ) { 21015 21016 const geometry = this.geometry; 21017 const material = this.material; 21018 const matrixWorld = this.matrixWorld; 21019 21020 if ( material === undefined ) return; 21021 21022 // test with bounding sphere in world space 21023 21024 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); 21025 21026 _sphere$6.copy( geometry.boundingSphere ); 21027 _sphere$6.applyMatrix4( matrixWorld ); 21028 21029 // check distance from ray origin to bounding sphere 21030 21031 _ray$3.copy( raycaster.ray ).recast( raycaster.near ); 21032 21033 if ( _sphere$6.containsPoint( _ray$3.origin ) === false ) { 21034 21035 if ( _ray$3.intersectSphere( _sphere$6, _sphereHitAt ) === null ) return; 21036 21037 if ( _ray$3.origin.distanceToSquared( _sphereHitAt ) > ( raycaster.far - raycaster.near ) ** 2 ) return; 21038 21039 } 21040 21041 // convert ray to local space of mesh 21042 21043 _inverseMatrix$3.copy( matrixWorld ).invert(); 21044 _ray$3.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$3 ); 21045 21046 // test with bounding box in local space 21047 21048 if ( geometry.boundingBox !== null ) { 21049 21050 if ( _ray$3.intersectsBox( geometry.boundingBox ) === false ) return; 21051 21052 } 21053 21054 // test for intersections with geometry 21055 21056 this._computeIntersections( raycaster, intersects, _ray$3 ); 21057 21058 } 21059 21060 _computeIntersections( raycaster, intersects, rayLocalSpace ) { 21061 21062 let intersection; 21063 21064 const geometry = this.geometry; 21065 const material = this.material; 21066 21067 const index = geometry.index; 21068 const position = geometry.attributes.position; 21069 const uv = geometry.attributes.uv; 21070 const uv1 = geometry.attributes.uv1; 21071 const normal = geometry.attributes.normal; 21072 const groups = geometry.groups; 21073 const drawRange = geometry.drawRange; 21074 21075 if ( index !== null ) { 21076 21077 // indexed buffer geometry 21078 21079 if ( Array.isArray( material ) ) { 21080 21081 for ( let i = 0, il = groups.length; i < il; i ++ ) { 21082 21083 const group = groups[ i ]; 21084 const groupMaterial = material[ group.materialIndex ]; 21085 21086 const start = Math.max( group.start, drawRange.start ); 21087 const end = Math.min( index.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) ); 21088 21089 for ( let j = start, jl = end; j < jl; j += 3 ) { 21090 21091 const a = index.getX( j ); 21092 const b = index.getX( j + 1 ); 21093 const c = index.getX( j + 2 ); 21094 21095 intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); 21096 21097 if ( intersection ) { 21098 21099 intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics 21100 intersection.face.materialIndex = group.materialIndex; 21101 intersects.push( intersection ); 21102 21103 } 21104 21105 } 21106 21107 } 21108 21109 } else { 21110 21111 const start = Math.max( 0, drawRange.start ); 21112 const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); 21113 21114 for ( let i = start, il = end; i < il; i += 3 ) { 21115 21116 const a = index.getX( i ); 21117 const b = index.getX( i + 1 ); 21118 const c = index.getX( i + 2 ); 21119 21120 intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); 21121 21122 if ( intersection ) { 21123 21124 intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics 21125 intersects.push( intersection ); 21126 21127 } 21128 21129 } 21130 21131 } 21132 21133 } else if ( position !== undefined ) { 21134 21135 // non-indexed buffer geometry 21136 21137 if ( Array.isArray( material ) ) { 21138 21139 for ( let i = 0, il = groups.length; i < il; i ++ ) { 21140 21141 const group = groups[ i ]; 21142 const groupMaterial = material[ group.materialIndex ]; 21143 21144 const start = Math.max( group.start, drawRange.start ); 21145 const end = Math.min( position.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) ); 21146 21147 for ( let j = start, jl = end; j < jl; j += 3 ) { 21148 21149 const a = j; 21150 const b = j + 1; 21151 const c = j + 2; 21152 21153 intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); 21154 21155 if ( intersection ) { 21156 21157 intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics 21158 intersection.face.materialIndex = group.materialIndex; 21159 intersects.push( intersection ); 21160 21161 } 21162 21163 } 21164 21165 } 21166 21167 } else { 21168 21169 const start = Math.max( 0, drawRange.start ); 21170 const end = Math.min( position.count, ( drawRange.start + drawRange.count ) ); 21171 21172 for ( let i = start, il = end; i < il; i += 3 ) { 21173 21174 const a = i; 21175 const b = i + 1; 21176 const c = i + 2; 21177 21178 intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); 21179 21180 if ( intersection ) { 21181 21182 intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics 21183 intersects.push( intersection ); 21184 21185 } 21186 21187 } 21188 21189 } 21190 21191 } 21192 21193 } 21194 21195} 21196 21197function checkIntersection$1( object, material, raycaster, ray, pA, pB, pC, point ) { 21198 21199 let intersect; 21200 21201 if ( material.side === BackSide ) { 21202 21203 intersect = ray.intersectTriangle( pC, pB, pA, true, point ); 21204 21205 } else { 21206 21207 intersect = ray.intersectTriangle( pA, pB, pC, ( material.side === FrontSide ), point ); 21208 21209 } 21210 21211 if ( intersect === null ) return null; 21212 21213 _intersectionPointWorld.copy( point ); 21214 _intersectionPointWorld.applyMatrix4( object.matrixWorld ); 21215 21216 const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld ); 21217 21218 if ( distance < raycaster.near || distance > raycaster.far ) return null; 21219 21220 return { 21221 distance: distance, 21222 point: _intersectionPointWorld.clone(), 21223 object: object 21224 }; 21225 21226} 21227 21228function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, normal, a, b, c ) { 21229 21230 object.getVertexPosition( a, _vA$1 ); 21231 object.getVertexPosition( b, _vB$1 ); 21232 object.getVertexPosition( c, _vC$1 ); 21233 21234 const intersection = checkIntersection$1( object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint ); 21235 21236 if ( intersection ) { 21237 21238 const barycoord = new Vector3(); 21239 Triangle.getBarycoord( _intersectionPoint, _vA$1, _vB$1, _vC$1, barycoord ); 21240 21241 if ( uv ) { 21242 21243 intersection.uv = Triangle.getInterpolatedAttribute( uv, a, b, c, barycoord, new Vector2() ); 21244 21245 } 21246 21247 if ( uv1 ) { 21248 21249 intersection.uv1 = Triangle.getInterpolatedAttribute( uv1, a, b, c, barycoord, new Vector2() ); 21250 21251 } 21252 21253 if ( normal ) { 21254
vendor: 4,211 bytes, lines 21255-21434
21255 intersection.normal = Triangle.getInterpolatedAttribute( normal, a, b, c, barycoord, new Vector3() ); 21256 21257 if ( intersection.normal.dot( ray.direction ) > 0 ) { 21258 21259 intersection.normal.multiplyScalar( -1 ); 21260 21261 } 21262 21263 } 21264 21265 const face = { 21266 a: a, 21267 b: b, 21268 c: c, 21269 normal: new Vector3(), 21270 materialIndex: 0 21271 }; 21272 21273 Triangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal ); 21274 21275 intersection.face = face; 21276 intersection.barycoord = barycoord; 21277 21278 } 21279 21280 return intersection; 21281 21282} 21283 21284// Uniform Utilities 21285 21286function cloneUniforms( src ) { 21287 21288 const dst = {}; 21289 21290 for ( const u in src ) { 21291 21292 dst[ u ] = {}; 21293 21294 for ( const p in src[ u ] ) { 21295 21296 const property = src[ u ][ p ]; 21297 21298 if ( property && ( property.isColor || 21299 property.isMatrix3 || property.isMatrix4 || 21300 property.isVector2 || property.isVector3 || property.isVector4 || 21301 property.isTexture || property.isQuaternion ) ) { 21302 21303 if ( property.isRenderTargetTexture ) { 21304 21305 console.warn( 'UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().' ); 21306 dst[ u ][ p ] = null; 21307 21308 } else { 21309 21310 dst[ u ][ p ] = property.clone(); 21311 21312 } 21313 21314 } else if ( Array.isArray( property ) ) { 21315 21316 dst[ u ][ p ] = property.slice(); 21317 21318 } else { 21319 21320 dst[ u ][ p ] = property; 21321 21322 } 21323 21324 } 21325 21326 } 21327 21328 return dst; 21329 21330} 21331 21332function mergeUniforms( uniforms ) { 21333 21334 const merged = {}; 21335 21336 for ( let u = 0; u < uniforms.length; u ++ ) { 21337 21338 const tmp = cloneUniforms( uniforms[ u ] ); 21339 21340 for ( const p in tmp ) { 21341 21342 merged[ p ] = tmp[ p ]; 21343 21344 } 21345 21346 } 21347 21348 return merged; 21349 21350} 21351 21352function cloneUniformsGroups( src ) { 21353 21354 const dst = []; 21355 21356 for ( let u = 0; u < src.length; u ++ ) { 21357 21358 dst.push( src[ u ].clone() ); 21359 21360 } 21361 21362 return dst; 21363 21364} 21365 21366// Legacy 21367 21368const UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms }; 21369 21370var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}"; 21371 21372var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}"; 21373 21374/** 21375 * A material rendered with custom shaders. A shader is a small program written in GLSL. 21376 * that runs on the GPU. You may want to use a custom shader if you need to implement an 21377 * effect not included with any of the built-in materials. 21378 * 21379 * There are the following notes to bear in mind when using a `ShaderMaterial`: 21380 * 21381 * - `ShaderMaterial` can only be used with {@link WebGLRenderer}. 21382 * - Built in attributes and uniforms are passed to the shaders along with your code. If 21383 * you don't want that, use {@link RawShaderMaterial} instead. 21384 * - You can use the directive `#pragma unroll_loop_start` and `#pragma unroll_loop_end` 21385 * in order to unroll a `for` loop in GLSL by the shader preprocessor. The directive has 21386 * to be placed right above the loop. The loop formatting has to correspond to a defined standard. 21387 * - The loop has to be [normalized]{@link https://en.wikipedia.org/wiki/Normalized_loop}. 21388 * - The loop variable has to be *i*. 21389 * - The value `UNROLLED_LOOP_INDEX` will be replaced with the explicitly 21390 * value of *i* for the given iteration and can be used in preprocessor 21391 * statements. 21392 * 21393 * ```js 21394 * const material = new THREE.ShaderMaterial( { 21395 * uniforms: { 21396 * time: { value: 1.0 }, 21397 * resolution: { value: new THREE.Vector2() } 21398 * }, 21399 * vertexShader: document.getElementById( 'vertexShader' ).textContent, 21400 * fragmentShader: document.getElementById( 'fragmentShader' ).textContent 21401 * } ); 21402 * ``` 21403 * 21404 * @augments Material 21405 */ 21406class ShaderMaterial extends Material { 21407 21408 /** 21409 * Constructs a new shader material. 21410 * 21411 * @param {Object} [parameters] - An object with one or more properties 21412 * defining the material's appearance. Any property of the material 21413 * (including any property from inherited materials) can be passed 21414 * in here. Color values can be passed any type of value accepted 21415 * by {@link Color#set}. 21416 */ 21417 constructor( parameters ) { 21418 21419 super(); 21420 21421 /** 21422 * This flag can be used for type testing. 21423 * 21424 * @type {boolean} 21425 * @readonly 21426 * @default true 21427 */ 21428 this.isShaderMaterial = true; 21429 21430 this.type = 'ShaderMaterial'; 21431 21432 /** 21433 * Defines custom constants using `#define` directives within the GLSL code 21434 * for both the vertex shader and the fragment shader;
21434 each key/value pair 21435 * yields another directive. 21436 * ```js 21437 * defines: { 21438 * FOO: 15, 21439 * BAR: true 21440 * } 21441 * ``` 21442 * Yields the lines: 21443 * ``` 21444 * #define FOO 15 21445 * #define BAR true 21446 * ``` 21447 * 21448 * @type {Object} 21449 */ 21450 this.defines = {}; 21451 21452 /** 21453 * An object of the form: 21454 * ```js 21455 * { 21456 * "uniform1": { value: 1.0 }, 21457 * "uniform2": { value: 2 } 21458 * } 21459 * ``` 21460 * specifying the uniforms to be passed to the shader code; keys are uniform 21461 * names, values are definitions of the form 21462 * ``` 21463 * { 21464 * value: 1.0 21465 * } 21466 * ``` 21467 * where `value` is the value of the uniform. Names must match the name of 21468 * the uniform, as defined in the GLSL code. Note that uniforms are refreshed 21469 * on every frame, so updating the value of the uniform will immediately 21470 * update the value available to the GLSL code. 21471 * 21472 * @type {Object} 21473 */ 21474 this.uniforms = {}; 21475 21476 /** 21477 * An array holding uniforms groups for configuring UBOs. 21478 * 21479 * @type {Array<UniformsGroup>} 21480 */ 21481 this.uniformsGroups = []; 21482 21483 /** 21484 * Vertex shader GLSL code. This is the actual code for the shader. 21485 * 21486 * @type {string} 21487 */ 21488 this.vertexShader = default_vertex; 21489 21490 /** 21491 * Fragment shader GLSL code. This is the actual code for the shader. 21492 * 21493 * @type {string} 21494 */ 21495 this.fragmentShader = default_fragment; 21496 21497 /** 21498 * Controls line thickness or lines. 21499 * 21500 * WebGL and WebGPU ignore this setting and always render line primitives with a 21501 * width of one pixel. 21502 * 21503 * @type {number} 21504 * @default 1 21505 */ 21506 this.linewidth = 1; 21507 21508 /** 21509 * Renders the geometry as a wireframe. 21510 * 21511 * @type {boolean} 21512 * @default false 21513 */ 21514 this.wireframe = false; 21515 21516 /** 21517 * Controls the thickness of the wireframe. 21518 * 21519 * WebGL and WebGPU ignore this property and always render 21520 * 1 pixel wide lines. 21521 * 21522 * @type {number} 21523 * @default 1 21524 */ 21525 this.wireframeLinewidth = 1; 21526 21527 /** 21528 * Define whether the material color is affected by global fog settings; `true` 21529 * to pass fog uniforms to the shader. 21530 * 21531 * @type {boolean} 21532 * @default false 21533 */ 21534 this.fog = false; 21535 21536 /** 21537 * Defines whether this material uses lighting; `true` to pass uniform data 21538 * related to lighting to this shader. 21539 * 21540 * @type {boolean} 21541 * @default false 21542 */ 21543 this.lights = false; 21544 21545 /** 21546 * Defines whether this material supports clipping; `true` to let the renderer 21547 * pass the clippingPlanes uniform. 21548 * 21549 * @type {boolean} 21550 * @default false 21551 */ 21552 this.clipping = false; 21553 21554 /** 21555 * Overwritten and set to `true` by default. 21556 * 21557 * @type {boolean} 21558 * @default true 21559 */ 21560 this.forceSinglePass = true; 21561 21562 /** 21563 * This object allows to enable certain WebGL 2 extensions. 21564 * 21565 * - clipCullDistance: set to `true` to use vertex shader clipping 21566 * - multiDraw: set to `true` to use vertex shader multi_draw / enable gl_DrawID 21567 * 21568 * @type {{clipCullDistance:false,multiDraw:false}} 21569 */ 21570 this.extensions = { 21571 clipCullDistance: false, // set to use vertex shader clipping 21572 multiDraw: false // set to use vertex shader multi_draw / enable gl_DrawID 21573 }; 21574 21575 /** 21576 * When the rendered geometry doesn't include these attributes but the 21577 * material does, these default values will be passed to the shaders. This 21578 * avoids errors when buffer data is missing. 21579 * 21580 * - color: [ 1, 1, 1 ] 21581 * - uv: [ 0, 0 ] 21582 * - uv1: [ 0, 0 ] 21583 * 21584 * @type {Object} 21585 */ 21586 this.defaultAttributeValues = { 21587 'color': [ 1, 1, 1 ], 21588 'uv': [ 0, 0 ], 21589 'uv1': [ 0, 0 ] 21590 }; 21591 21592 /** 21593 * If set, this calls [gl.bindAttribLocation]{@link https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/bindAttribLocation} 21594 * to bind a generic vertex index to an attribute variable. 21595 * 21596 * @type {string|undefined} 21597 * @default undefined 21598 */ 21599 this.index0AttributeName = undefined; 21600 21601 /** 21602 * Can be used to force a uniform update while changing uniforms in 21603 * {@link Object3D#onBeforeRender}. 21604 * 21605 * @type {boolean} 21606 * @default false 21607 */ 21608 this.uniformsNeedUpdate = false; 21609 21610 /** 21611 * Defines the GLSL version of custom shader code. 21612 * 21613 * @type {?(GLSL1|GLSL3)} 21614 * @default null 21615 */ 21616 this.glslVersion = null; 21617 21618 if ( parameters !== undefined ) { 21619 21620 this.setValues( parameters ); 21621 21622 } 21623 21624 } 21625 21626 copy( source ) { 21627 21628 super.copy( source ); 21629 21630 this.fragmentShader = source.fragmentShader; 21631 this.vertexShader = source.vertexShader; 21632 21633 this.uniforms = cloneUniforms( source.uniforms ); 21634 this.uniformsGroups = cloneUniformsGroups( source.uniformsGroups ); 21635 21636 this.defines = Object.assign( {}, source.defines ); 21637 21638 this.wireframe = source.wireframe; 21639 this.wireframeLinewidth = source.wireframeLinewidth; 21640
vendor: 8,379 bytes, lines 21641-22017
21641 this.fog = source.fog; 21642 this.lights = source.lights; 21643 this.clipping = source.clipping; 21644 21645 this.extensions = Object.assign( {}, source.extensions ); 21646 21647 this.glslVersion = source.glslVersion; 21648 21649 return this; 21650 21651 } 21652 21653 toJSON( meta ) { 21654 21655 const data = super.toJSON( meta ); 21656 21657 data.glslVersion = this.glslVersion; 21658 data.uniforms = {}; 21659 21660 for ( const name in this.uniforms ) { 21661 21662 const uniform = this.uniforms[ name ]; 21663 const value = uniform.value; 21664 21665 if ( value && value.isTexture ) { 21666 21667 data.uniforms[ name ] = { 21668 type: 't', 21669 value: value.toJSON( meta ).uuid 21670 }; 21671 21672 } else if ( value && value.isColor ) { 21673 21674 data.uniforms[ name ] = { 21675 type: 'c', 21676 value: value.getHex() 21677 }; 21678 21679 } else if ( value && value.isVector2 ) { 21680 21681 data.uniforms[ name ] = { 21682 type: 'v2', 21683 value: value.toArray() 21684 }; 21685 21686 } else if ( value && value.isVector3 ) { 21687 21688 data.uniforms[ name ] = { 21689 type: 'v3', 21690 value: value.toArray() 21691 }; 21692 21693 } else if ( value && value.isVector4 ) { 21694 21695 data.uniforms[ name ] = { 21696 type: 'v4', 21697 value: value.toArray() 21698 }; 21699 21700 } else if ( value && value.isMatrix3 ) { 21701 21702 data.uniforms[ name ] = { 21703 type: 'm3', 21704 value: value.toArray() 21705 }; 21706 21707 } else if ( value && value.isMatrix4 ) { 21708 21709 data.uniforms[ name ] = { 21710 type: 'm4', 21711 value: value.toArray() 21712 }; 21713 21714 } else { 21715 21716 data.uniforms[ name ] = { 21717 value: value 21718 }; 21719 21720 // note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far 21721 21722 } 21723 21724 } 21725 21726 if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines; 21727 21728 data.vertexShader = this.vertexShader; 21729 data.fragmentShader = this.fragmentShader; 21730 21731 data.lights = this.lights; 21732 data.clipping = this.clipping; 21733 21734 const extensions = {}; 21735 21736 for ( const key in this.extensions ) { 21737 21738 if ( this.extensions[ key ] === true ) extensions[ key ] = true; 21739 21740 } 21741 21742 if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions; 21743 21744 return data; 21745 21746 } 21747 21748} 21749 21750/** 21751 * This is almost identical to an {@link Object3D}. Its purpose is to 21752 * make working with groups of objects syntactically clearer. 21753 * 21754 * ```js 21755 * // Create a group and add the two cubes. 21756 * // These cubes can now be rotated / scaled etc as a group. 21757 * const group = new THREE.Group(); 21758 * 21759 * group.add( meshA ); 21760 * group.add( meshB ); 21761 * 21762 * scene.add( group ); 21763 * ``` 21764 * 21765 * @augments Object3D 21766 */ 21767class Group extends Object3D { 21768 21769 constructor() { 21770 21771 super(); 21772 21773 /** 21774 * This flag can be used for type testing. 21775 * 21776 * @type {boolean} 21777 * @readonly 21778 * @default true 21779 */ 21780 this.isGroup = true; 21781 21782 this.type = 'Group'; 21783 21784 } 21785 21786} 21787 21788/** 21789 * "Interleaved" means that multiple attributes, possibly of different types, 21790 * (e.g., position, normal, uv, color) are packed into a single array buffer. 21791 * 21792 * An introduction into interleaved arrays can be found here: [Interleaved array basics]{@link https://blog.tojicode.com/2011/05/interleaved-array-basics.html} 21793 */ 21794class InterleavedBuffer { 21795 21796 /** 21797 * Constructs a new interleaved buffer. 21798 * 21799 * @param {TypedArray} array - A typed array with a shared buffer storing attribute data. 21800 * @param {number} stride - The number of typed-array elements per vertex. 21801 */ 21802 constructor( array, stride ) { 21803 21804 /** 21805 * This flag can be used for type testing. 21806 * 21807 * @type {boolean} 21808 * @readonly 21809 * @default true 21810 */ 21811 this.isInterleavedBuffer = true; 21812 21813 /** 21814 * A typed array with a shared buffer storing attribute data. 21815 * 21816 * @type {TypedArray} 21817 */ 21818 this.array = array; 21819 21820 /** 21821 * The number of typed-array elements per vertex. 21822 * 21823 * @type {number} 21824 */ 21825 this.stride = stride; 21826 21827 /** 21828 * The total number of elements in the array 21829 * 21830 * @type {number} 21831 * @readonly 21832 */ 21833 this.count = array !== undefined ? array.length / stride : 0; 21834 21835 /** 21836 * Defines the intended usage pattern of the data store for optimization purposes. 21837 * 21838 * Note: After the initial use of a buffer, its usage cannot be changed. Instead, 21839 * instantiate a new one and set the desired usage before the next render. 21840 * 21841 * @type {(StaticDrawUsage|DynamicDrawUsage|StreamDrawUsage|StaticReadUsage|DynamicReadUsage|StreamReadUsage|StaticCopyUsage|DynamicCopyUsage|StreamCopyUsage)} 21842 * @default StaticDrawUsage 21843 */ 21844 this.usage = StaticDrawUsage; 21845 21846 /** 21847 * This can be used to only update some components of stored vectors (for example, just the 21848 * component related to color). Use the `addUpdateRange()` function to add ranges to this array. 21849 * 21850 * @type {Array<Object>} 21851 */ 21852 this.updateRanges = []; 21853 21854 /** 21855 * A version number, incremented every time the `needsUpdate` is set to `true`. 21856 * 21857 * @type {number} 21858 */ 21859 this.version = 0; 21860 21861 /** 21862 * The UUID of the interleaved buffer. 21863 * 21864 * @type {string} 21865 * @readonly 21866 */ 21867 this.uuid = generateUUID(); 21868 21869 } 21870 21871 /** 21872 * A callback function that is executed after the renderer has transferred the attribute array 21873 * data to the GPU. 21874 */ 21875 onUploadCallback() {} 21876 21877 /** 21878 * Flag to indicate that this attribute has changed and should be re-sent to 21879 * the GPU. Set this to `true` when you modify the value of the array. 21880 * 21881 * @type {number} 21882 * @default false 21883 * @param {boolean} value 21884 */ 21885 set needsUpdate( value ) { 21886 21887 if ( value === true ) this.version ++; 21888 21889 } 21890 21891 /** 21892 * Sets the usage of this interleaved buffer. 21893 * 21894 * @param {(StaticDrawUsage|DynamicDrawUsage|StreamDrawUsage|StaticReadUsage|DynamicReadUsage|StreamReadUsage|StaticCopyUsage|DynamicCopyUsage|StreamCopyUsage)} value - The usage to set. 21895 * @return {InterleavedBuffer} A reference to this interleaved buffer. 21896 */ 21897 setUsage( value ) { 21898 21899 this.usage = value; 21900 21901 return this; 21902 21903 } 21904 21905 /** 21906 * Adds a range of data in the data array to be updated on the GPU. 21907 * 21908 * @param {number} start - Position at which to start update. 21909 * @param {number} count - The number of components to update. 21910 */ 21911 addUpdateRange( start, count ) { 21912 21913 this.updateRanges.push( { start, count } ); 21914 21915 } 21916 21917 /** 21918 * Clears the update ranges. 21919 */ 21920 clearUpdateRanges() { 21921 21922 this.updateRanges.length = 0; 21923 21924 } 21925 21926 /** 21927 * Copies the values of the given interleaved buffer to this instance. 21928 * 21929 * @param {InterleavedBuffer} source - The interleaved buffer to copy. 21930 * @return {InterleavedBuffer} A reference to this instance. 21931 */ 21932 copy( source ) { 21933 21934 this.array = new source.array.constructor( source.array ); 21935 this.count = source.count; 21936 this.stride = source.stride; 21937 this.usage = source.usage; 21938 21939 return this; 21940 21941 } 21942 21943 /** 21944 * Copies a vector from the given interleaved buffer to this one. The start 21945 * and destination position in the attribute buffers are represented by the 21946 * given indices. 21947 * 21948 * @param {number} index1 - The destination index into this interleaved buffer. 21949 * @param {InterleavedBuffer} interleavedBuffer - The interleaved buffer to copy from. 21950 * @param {number} index2 - The source index into the given interleaved buffer. 21951 * @return {InterleavedBuffer} A reference to this instance. 21952 */ 21953 copyAt( index1, interleavedBuffer, index2 ) { 21954 21955 index1 *= this.stride; 21956 index2 *= interleavedBuffer.stride; 21957 21958 for ( let i = 0, l = this.stride; i < l; i ++ ) { 21959 21960 this.array[ index1 + i ] = interleavedBuffer.array[ index2 + i ]; 21961 21962 } 21963 21964 return this; 21965 21966 } 21967 21968 /** 21969 * Sets the given array data in the interleaved buffer. 21970 * 21971 * @param {(TypedArray|Array)} value - The array data to set. 21972 * @param {number} [offset=0] - The offset in this interleaved buffer's array. 21973 * @return {InterleavedBuffer} A reference to this instance. 21974 */ 21975 set( value, offset = 0 ) { 21976 21977 this.array.set( value, offset ); 21978 21979 return this; 21980 21981 } 21982 21983 /** 21984 * Returns a new interleaved buffer with copied values from this instance. 21985 * 21986 * @param {Object} [data] - An object with shared array buffers that allows to retain shared structures. 21987 * @return {InterleavedBuffer} A clone of this instance. 21988 */ 21989 clone( data ) { 21990 21991 if ( data.arrayBuffers === undefined ) { 21992 21993 data.arrayBuffers = {}; 21994 21995 } 21996 21997 if ( this.array.buffer._uuid === undefined ) { 21998 21999 this.array.buffer._uuid = generateUUID(); 22000 22001 } 22002 22003 if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) { 22004 22005 data.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer; 22006 22007 } 22008 22009 const array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] ); 22010 22011 const ib = new this.constructor( array, this.stride ); 22012 ib.setUsage( this.usage ); 22013 22014 return ib; 22015 22016 } 22017
vendor: 2,927 bytes, lines 22018-22151
22018 /** 22019 * Sets the given callback function that is executed after the Renderer has transferred 22020 * the array data to the GPU. Can be used to perform clean-up operations after 22021 * the upload when data are not needed anymore on the CPU side. 22022 * 22023 * @param {Function} callback - The `onUpload()` callback. 22024 * @return {InterleavedBuffer} A reference to this instance. 22025 */ 22026 onUpload( callback ) { 22027 22028 this.onUploadCallback = callback; 22029 22030 return this; 22031 22032 } 22033 22034 /** 22035 * Serializes the interleaved buffer into JSON. 22036 * 22037 * @param {Object} [data] - An optional value holding meta information about the serialization. 22038 * @return {Object} A JSON object representing the serialized interleaved buffer. 22039 */ 22040 toJSON( data ) { 22041 22042 if ( data.arrayBuffers === undefined ) { 22043 22044 data.arrayBuffers = {}; 22045 22046 } 22047 22048 // generate UUID for array buffer if necessary 22049 22050 if ( this.array.buffer._uuid === undefined ) { 22051 22052 this.array.buffer._uuid = generateUUID(); 22053 22054 } 22055 22056 if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) { 22057 22058 data.arrayBuffers[ this.array.buffer._uuid ] = Array.from( new Uint32Array( this.array.buffer ) ); 22059 22060 } 22061 22062 // 22063 22064 return { 22065 uuid: this.uuid, 22066 buffer: this.array.buffer._uuid, 22067 type: this.array.constructor.name, 22068 stride: this.stride 22069 }; 22070 22071 } 22072 22073} 22074 22075const _vector$7 = /*@__PURE__*/ new Vector3(); 22076 22077/** 22078 * An alternative version of a buffer attribute with interleaved data. Interleaved 22079 * attributes share a common interleaved data storage ({@link InterleavedBuffer}) and refer with 22080 * different offsets into the buffer. 22081 */ 22082class InterleavedBufferAttribute { 22083 22084 /** 22085 * Constructs a new interleaved buffer attribute. 22086 * 22087 * @param {InterleavedBuffer} interleavedBuffer - The buffer holding the interleaved data. 22088 * @param {number} itemSize - The item size. 22089 * @param {number} offset - The attribute offset into the buffer. 22090 * @param {boolean} [normalized=false] - Whether the data are normalized or not. 22091 */ 22092 constructor( interleavedBuffer, itemSize, offset, normalized = false ) { 22093 22094 /** 22095 * This flag can be used for type testing. 22096 * 22097 * @type {boolean} 22098 * @readonly 22099 * @default true 22100 */ 22101 this.isInterleavedBufferAttribute = true; 22102 22103 /** 22104 * The name of the buffer attribute. 22105 * 22106 * @type {string} 22107 */ 22108 this.name = ''; 22109 22110 /** 22111 * The buffer holding the interleaved data. 22112 * 22113 * @type {InterleavedBuffer} 22114 */ 22115 this.data = interleavedBuffer; 22116 22117 /** 22118 * The item size, see {@link BufferAttribute#itemSize}. 22119 * 22120 * @type {number} 22121 */ 22122 this.itemSize = itemSize; 22123 22124 /** 22125 * The attribute offset into the buffer. 22126 * 22127 * @type {number} 22128 */ 22129 this.offset = offset; 22130 22131 /** 22132 * Whether the data are normalized or not, see {@link BufferAttribute#normalized} 22133 * 22134 * @type {InterleavedBuffer} 22135 */ 22136 this.normalized = normalized; 22137 22138 } 22139 22140 /** 22141 * The item count of this buffer attribute. 22142 * 22143 * @type {number} 22144 * @readonly 22145 */ 22146 get count() { 22147 22148 return this.data.count; 22149 22150 } 22151
vendor: 4,140 bytes, lines 22152-22331
22152 /** 22153 * The array holding the interleaved buffer attribute data. 22154 * 22155 * @type {TypedArray} 22156 */ 22157 get array() { 22158 22159 return this.data.array; 22160 22161 } 22162 22163 /** 22164 * Flag to indicate that this attribute has changed and should be re-sent to 22165 * the GPU. Set this to `true` when you modify the value of the array. 22166 * 22167 * @type {number} 22168 * @default false 22169 * @param {boolean} value 22170 */ 22171 set needsUpdate( value ) { 22172 22173 this.data.needsUpdate = value; 22174 22175 } 22176 22177 /** 22178 * Applies the given 4x4 matrix to the given attribute. Only works with 22179 * item size `3`. 22180 * 22181 * @param {Matrix4} m - The matrix to apply. 22182 * @return {InterleavedBufferAttribute} A reference to this instance. 22183 */ 22184 applyMatrix4( m ) { 22185 22186 for ( let i = 0, l = this.data.count; i < l; i ++ ) { 22187 22188 _vector$7.fromBufferAttribute( this, i ); 22189 22190 _vector$7.applyMatrix4( m ); 22191 22192 this.setXYZ( i, _vector$7.x, _vector$7.y, _vector$7.z ); 22193 22194 } 22195 22196 return this; 22197 22198 } 22199 22200 /** 22201 * Applies the given 3x3 normal matrix to the given attribute. Only works with 22202 * item size `3`. 22203 * 22204 * @param {Matrix3} m - The normal matrix to apply. 22205 * @return {InterleavedBufferAttribute} A reference to this instance. 22206 */ 22207 applyNormalMatrix( m ) { 22208 22209 for ( let i = 0, l = this.count; i < l; i ++ ) { 22210 22211 _vector$7.fromBufferAttribute( this, i ); 22212 22213 _vector$7.applyNormalMatrix( m ); 22214 22215 this.setXYZ( i, _vector$7.x, _vector$7.y, _vector$7.z ); 22216 22217 } 22218 22219 return this; 22220 22221 } 22222 22223 /** 22224 * Applies the given 4x4 matrix to the given attribute. Only works with 22225 * item size `3` and with direction vectors. 22226 * 22227 * @param {Matrix4} m - The matrix to apply. 22228 * @return {InterleavedBufferAttribute} A reference to this instance. 22229 */ 22230 transformDirection( m ) { 22231 22232 for ( let i = 0, l = this.count; i < l; i ++ ) { 22233 22234 _vector$7.fromBufferAttribute( this, i ); 22235 22236 _vector$7.transformDirection( m ); 22237 22238 this.setXYZ( i, _vector$7.x, _vector$7.y, _vector$7.z ); 22239 22240 } 22241 22242 return this; 22243 22244 } 22245 22246 /** 22247 * Returns the given component of the vector at the given index. 22248 * 22249 * @param {number} index - The index into the buffer attribute. 22250 * @param {number} component - The component index. 22251 * @return {number} The returned value. 22252 */ 22253 getComponent( index, component ) { 22254 22255 let value = this.array[ index * this.data.stride + this.offset + component ]; 22256 22257 if ( this.normalized ) value = denormalize( value, this.array ); 22258 22259 return value; 22260 22261 } 22262 22263 /** 22264 * Sets the given value to the given component of the vector at the given index. 22265 * 22266 * @param {number} index - The index into the buffer attribute. 22267 * @param {number} component - The component index. 22268 * @param {number} value - The value to set. 22269 * @return {InterleavedBufferAttribute} A reference to this instance. 22270 */ 22271 setComponent( index, component, value ) { 22272 22273 if ( this.normalized ) value = normalize( value, this.array ); 22274 22275 this.data.array[ index * this.data.stride + this.offset + component ] = value; 22276 22277 return this; 22278 22279 } 22280 22281 /** 22282 * Sets the x component of the vector at the given index. 22283 * 22284 * @param {number} index - The index into the buffer attribute. 22285 * @param {number} x - The value to set. 22286 * @return {InterleavedBufferAttribute} A reference to this instance. 22287 */ 22288 setX( index, x ) { 22289 22290 if ( this.normalized ) x = normalize( x, this.array ); 22291 22292 this.data.array[ index * this.data.stride + this.offset ] = x; 22293 22294 return this; 22295 22296 } 22297 22298 /** 22299 * Sets the y component of the vector at the given index. 22300 * 22301 * @param {number} index - The index into the buffer attribute. 22302 * @param {number} y - The value to set. 22303 * @return {InterleavedBufferAttribute} A reference to this instance. 22304 */ 22305 setY( index, y ) { 22306 22307 if ( this.normalized ) y = normalize( y, this.array ); 22308 22309 this.data.array[ index * this.data.stride + this.offset + 1 ] = y; 22310 22311 return this; 22312 22313 } 22314 22315 /** 22316 * Sets the z component of the vector at the given index. 22317 * 22318 * @param {number} index - The index into the buffer attribute. 22319 * @param {number} z - The value to set. 22320 * @return {InterleavedBufferAttribute} A reference to this instance. 22321 */ 22322 setZ( index, z ) { 22323 22324 if ( this.normalized ) z = normalize( z, this.array ); 22325 22326 this.data.array[ index * this.data.stride + this.offset + 2 ] = z; 22327 22328 return this; 22329 22330 } 22331
vendor: 5,375 bytes, lines 22332-22549
22332 /** 22333 * Sets the w component of the vector at the given index. 22334 * 22335 * @param {number} index - The index into the buffer attribute. 22336 * @param {number} w - The value to set. 22337 * @return {InterleavedBufferAttribute} A reference to this instance. 22338 */ 22339 setW( index, w ) { 22340 22341 if ( this.normalized ) w = normalize( w, this.array ); 22342 22343 this.data.array[ index * this.data.stride + this.offset + 3 ] = w; 22344 22345 return this; 22346 22347 } 22348 22349 /** 22350 * Returns the x component of the vector at the given index. 22351 * 22352 * @param {number} index - The index into the buffer attribute. 22353 * @return {number} The x component. 22354 */ 22355 getX( index ) { 22356 22357 let x = this.data.array[ index * this.data.stride + this.offset ]; 22358 22359 if ( this.normalized ) x = denormalize( x, this.array ); 22360 22361 return x; 22362 22363 } 22364 22365 /** 22366 * Returns the y component of the vector at the given index. 22367 * 22368 * @param {number} index - The index into the buffer attribute. 22369 * @return {number} The y component. 22370 */ 22371 getY( index ) { 22372 22373 let y = this.data.array[ index * this.data.stride + this.offset + 1 ]; 22374 22375 if ( this.normalized ) y = denormalize( y, this.array ); 22376 22377 return y; 22378 22379 } 22380 22381 /** 22382 * Returns the z component of the vector at the given index. 22383 * 22384 * @param {number} index - The index into the buffer attribute. 22385 * @return {number} The z component. 22386 */ 22387 getZ( index ) { 22388 22389 let z = this.data.array[ index * this.data.stride + this.offset + 2 ]; 22390 22391 if ( this.normalized ) z = denormalize( z, this.array ); 22392 22393 return z; 22394 22395 } 22396 22397 /** 22398 * Returns the w component of the vector at the given index. 22399 * 22400 * @param {number} index - The index into the buffer attribute. 22401 * @return {number} The w component. 22402 */ 22403 getW( index ) { 22404 22405 let w = this.data.array[ index * this.data.stride + this.offset + 3 ]; 22406 22407 if ( this.normalized ) w = denormalize( w, this.array ); 22408 22409 return w; 22410 22411 } 22412 22413 /** 22414 * Sets the x and y component of the vector at the given index. 22415 * 22416 * @param {number} index - The index into the buffer attribute. 22417 * @param {number} x - The value for the x component to set. 22418 * @param {number} y - The value for the y component to set. 22419 * @return {InterleavedBufferAttribute} A reference to this instance. 22420 */ 22421 setXY( index, x, y ) { 22422 22423 index = index * this.data.stride + this.offset; 22424 22425 if ( this.normalized ) { 22426 22427 x = normalize( x, this.array ); 22428 y = normalize( y, this.array ); 22429 22430 } 22431 22432 this.data.array[ index + 0 ] = x; 22433 this.data.array[ index + 1 ] = y; 22434 22435 return this; 22436 22437 } 22438 22439 /** 22440 * Sets the x, y and z component of the vector at the given index. 22441 * 22442 * @param {number} index - The index into the buffer attribute. 22443 * @param {number} x - The value for the x component to set. 22444 * @param {number} y - The value for the y component to set. 22445 * @param {number} z - The value for the z component to set. 22446 * @return {InterleavedBufferAttribute} A reference to this instance. 22447 */ 22448 setXYZ( index, x, y, z ) { 22449 22450 index = index * this.data.stride + this.offset; 22451 22452 if ( this.normalized ) { 22453 22454 x = normalize( x, this.array ); 22455 y = normalize( y, this.array ); 22456 z = normalize( z, this.array ); 22457 22458 } 22459 22460 this.data.array[ index + 0 ] = x; 22461 this.data.array[ index + 1 ] = y; 22462 this.data.array[ index + 2 ] = z; 22463 22464 return this; 22465 22466 } 22467 22468 /** 22469 * Sets the x, y, z and w component of the vector at the given index. 22470 * 22471 * @param {number} index - The index into the buffer attribute. 22472 * @param {number} x - The value for the x component to set. 22473 * @param {number} y - The value for the y component to set. 22474 * @param {number} z - The value for the z component to set. 22475 * @param {number} w - The value for the w component to set. 22476 * @return {InterleavedBufferAttribute} A reference to this instance. 22477 */ 22478 setXYZW( index, x, y, z, w ) { 22479 22480 index = index * this.data.stride + this.offset; 22481 22482 if ( this.normalized ) { 22483 22484 x = normalize( x, this.array ); 22485 y = normalize( y, this.array ); 22486 z = normalize( z, this.array ); 22487 w = normalize( w, this.array ); 22488 22489 } 22490 22491 this.data.array[ index + 0 ] = x; 22492 this.data.array[ index + 1 ] = y; 22493 this.data.array[ index + 2 ] = z; 22494 this.data.array[ index + 3 ] = w; 22495 22496 return this; 22497 22498 } 22499 22500 /** 22501 * Returns a new buffer attribute with copied values from this instance. 22502 * 22503 * If no parameter is provided, cloning an interleaved buffer attribute will de-interleave buffer data. 22504 * 22505 * @param {Object} [data] - An object with interleaved buffers that allows to retain the interleaved property. 22506 * @return {BufferAttribute|InterleavedBufferAttribute} A clone of this instance. 22507 */ 22508 clone( data ) { 22509 22510 if ( data === undefined ) { 22511 22512 console.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will de-interleave buffer data.' ); 22513 22514 const array = []; 22515 22516 for ( let i = 0; i < this.count; i ++ ) { 22517 22518 const index = i * this.data.stride + this.offset; 22519 22520 for ( let j = 0; j < this.itemSize; j ++ ) { 22521 22522 array.push( this.data.array[ index + j ] ); 22523 22524 } 22525 22526 } 22527 22528 return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized ); 22529 22530 } else { 22531 22532 if ( data.interleavedBuffers === undefined ) { 22533 22534 data.interleavedBuffers = {}; 22535 22536 } 22537 22538 if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { 22539 22540 data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data ); 22541 22542 } 22543 22544 return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized ); 22545 22546 } 22547 22548 } 22549
vendor: 6,327 bytes, lines 22550-22837
22550 /** 22551 * Serializes the buffer attribute into JSON. 22552 * 22553 * If no parameter is provided, cloning an interleaved buffer attribute will de-interleave buffer data. 22554 * 22555 * @param {Object} [data] - An optional value holding meta information about the serialization. 22556 * @return {Object} A JSON object representing the serialized buffer attribute. 22557 */ 22558 toJSON( data ) { 22559 22560 if ( data === undefined ) { 22561 22562 console.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will de-interleave buffer data.' ); 22563 22564 const array = []; 22565 22566 for ( let i = 0; i < this.count; i ++ ) { 22567 22568 const index = i * this.data.stride + this.offset; 22569 22570 for ( let j = 0; j < this.itemSize; j ++ ) { 22571 22572 array.push( this.data.array[ index + j ] ); 22573 22574 } 22575 22576 } 22577 22578 // de-interleave data and save it as an ordinary buffer attribute for now 22579 22580 return { 22581 itemSize: this.itemSize, 22582 type: this.array.constructor.name, 22583 array: array, 22584 normalized: this.normalized 22585 }; 22586 22587 } else { 22588 22589 // save as true interleaved attribute 22590 22591 if ( data.interleavedBuffers === undefined ) { 22592 22593 data.interleavedBuffers = {}; 22594 22595 } 22596 22597 if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { 22598 22599 data.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data ); 22600 22601 } 22602 22603 return { 22604 isInterleavedBufferAttribute: true, 22605 itemSize: this.itemSize, 22606 data: this.data.uuid, 22607 offset: this.offset, 22608 normalized: this.normalized 22609 }; 22610 22611 } 22612 22613 } 22614 22615} 22616 22617/** 22618 * A material for rendering line primitives. 22619 * 22620 * Materials define the appearance of renderable 3D objects. 22621 * 22622 * ```js 22623 * const material = new THREE.LineBasicMaterial( { color: 0xffffff } ); 22624 * ``` 22625 * 22626 * @augments Material 22627 */ 22628class LineBasicMaterial extends Material { 22629 22630 /** 22631 * Constructs a new line basic material. 22632 * 22633 * @param {Object} [parameters] - An object with one or more properties 22634 * defining the material's appearance. Any property of the material 22635 * (including any property from inherited materials) can be passed 22636 * in here. Color values can be passed any type of value accepted 22637 * by {@link Color#set}. 22638 */ 22639 constructor( parameters ) { 22640 22641 super(); 22642 22643 /** 22644 * This flag can be used for type testing. 22645 * 22646 * @type {boolean} 22647 * @readonly 22648 * @default true 22649 */ 22650 this.isLineBasicMaterial = true; 22651 22652 this.type = 'LineBasicMaterial'; 22653 22654 /** 22655 * Color of the material. 22656 * 22657 * @type {Color} 22658 * @default (1,1,1) 22659 */ 22660 this.color = new Color( 0xffffff ); 22661 22662 /** 22663 * Sets the color of the lines using data from a texture. The texture map 22664 * color is modulated by the diffuse `color`. 22665 * 22666 * @type {?Texture} 22667 * @default null 22668 */ 22669 this.map = null; 22670 22671 /** 22672 * Controls line thickness or lines. 22673 * 22674 * Can only be used with {@link SVGRenderer}. WebGL and WebGPU 22675 * ignore this setting and always render line primitives with a 22676 * width of one pixel. 22677 * 22678 * @type {number} 22679 * @default 1 22680 */ 22681 this.linewidth = 1; 22682 22683 /** 22684 * Defines appearance of line ends. 22685 * 22686 * Can only be used with {@link SVGRenderer}. 22687 * 22688 * @type {('butt'|'round'|'square')} 22689 * @default 'round' 22690 */ 22691 this.linecap = 'round'; 22692 22693 /** 22694 * Defines appearance of line joints. 22695 * 22696 * Can only be used with {@link SVGRenderer}. 22697 * 22698 * @type {('round'|'bevel'|'miter')} 22699 * @default 'round' 22700 */ 22701 this.linejoin = 'round'; 22702 22703 /** 22704 * Whether the material is affected by fog or not. 22705 * 22706 * @type {boolean} 22707 * @default true 22708 */ 22709 this.fog = true; 22710 22711 this.setValues( parameters ); 22712 22713 } 22714 22715 copy( source ) { 22716 22717 super.copy( source ); 22718 22719 this.color.copy( source.color ); 22720 22721 this.map = source.map; 22722 22723 this.linewidth = source.linewidth; 22724 this.linecap = source.linecap; 22725 this.linejoin = source.linejoin; 22726 22727 this.fog = source.fog; 22728 22729 return this; 22730 22731 } 22732 22733} 22734 22735const _vStart = /*@__PURE__*/ new Vector3(); 22736const _vEnd = /*@__PURE__*/ new Vector3(); 22737 22738const _inverseMatrix$1 = /*@__PURE__*/ new Matrix4(); 22739const _ray$1 = /*@__PURE__*/ new Ray(); 22740const _sphere$1 = /*@__PURE__*/ new Sphere(); 22741 22742const _intersectPointOnRay = /*@__PURE__*/ new Vector3(); 22743const _intersectPointOnSegment = /*@__PURE__*/ new Vector3(); 22744 22745/** 22746 * A continuous line. The line are rendered by connecting consecutive 22747 * vertices with straight lines. 22748 * 22749 * ```js 22750 * const material = new THREE.LineBasicMaterial( { color: 0x0000ff } ); 22751 * 22752 * const points = []; 22753 * points.push( new THREE.Vector3( - 10, 0, 0 ) ); 22754 * points.push( new THREE.Vector3( 0, 10, 0 ) ); 22755 * points.push( new THREE.Vector3( 10, 0, 0 ) ); 22756 * 22757 * const geometry = new THREE.BufferGeometry().setFromPoints( points ); 22758 * 22759 * const line = new THREE.Line( geometry, material ); 22760 * scene.add( line ); 22761 * ``` 22762 * 22763 * @augments Object3D 22764 */ 22765class Line extends Object3D { 22766 22767 /** 22768 * Constructs a new line. 22769 * 22770 * @param {BufferGeometry} [geometry] - The line geometry. 22771 * @param {Material|Array<Material>} [material] - The line material. 22772 */ 22773 constructor( geometry = new BufferGeometry(), material = new LineBasicMaterial() ) { 22774 22775 super(); 22776 22777 /** 22778 * This flag can be used for type testing. 22779 * 22780 * @type {boolean} 22781 * @readonly 22782 * @default true 22783 */ 22784 this.isLine = true; 22785 22786 this.type = 'Line'; 22787 22788 /** 22789 * The line geometry. 22790 * 22791 * @type {BufferGeometry} 22792 */ 22793 this.geometry = geometry; 22794 22795 /** 22796 * The line material. 22797 * 22798 * @type {Material|Array<Material>} 22799 * @default LineBasicMaterial 22800 */ 22801 this.material = material; 22802 22803 /** 22804 * A dictionary representing the morph targets in the geometry. The key is the 22805 * morph targets name, the value its attribute index. This member is `undefined` 22806 * by default and only set when morph targets are detected in the geometry. 22807 * 22808 * @type {Object<String,number>|undefined} 22809 * @default undefined 22810 */ 22811 this.morphTargetDictionary = undefined; 22812 22813 /** 22814 * An array of weights typically in the range `[0,1]` that specify how much of the morph 22815 * is applied. This member is `undefined` by default and only set when morph targets are 22816 * detected in the geometry. 22817 * 22818 * @type {Array<number>|undefined} 22819 * @default undefined 22820 */ 22821 this.morphTargetInfluences = undefined; 22822 22823 this.updateMorphTargets(); 22824 22825 } 22826 22827 copy( source, recursive ) { 22828 22829 super.copy( source, recursive ); 22830 22831 this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; 22832 this.geometry = source.geometry; 22833 22834 return this; 22835 22836 } 22837
vendor: 6,280 bytes, lines 22838-23092
22838 /** 22839 * Computes an array of distance values which are necessary for rendering dashed lines. 22840 * For each vertex in the geometry, the method calculates the cumulative length from the 22841 * current point to the very beginning of the line. 22842 * 22843 * @return {Line} A reference to this line. 22844 */ 22845 computeLineDistances() { 22846 22847 const geometry = this.geometry; 22848 22849 // we assume non-indexed geometry 22850 22851 if ( geometry.index === null ) { 22852 22853 const positionAttribute = geometry.attributes.position; 22854 const lineDistances = [ 0 ]; 22855 22856 for ( let i = 1, l = positionAttribute.count; i < l; i ++ ) { 22857 22858 _vStart.fromBufferAttribute( positionAttribute, i - 1 ); 22859 _vEnd.fromBufferAttribute( positionAttribute, i ); 22860 22861 lineDistances[ i ] = lineDistances[ i - 1 ]; 22862 lineDistances[ i ] += _vStart.distanceTo( _vEnd ); 22863 22864 } 22865 22866 geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); 22867 22868 } else { 22869 22870 console.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); 22871 22872 } 22873 22874 return this; 22875 22876 } 22877 22878 /** 22879 * Computes intersection points between a casted ray and this line. 22880 * 22881 * @param {Raycaster} raycaster - The raycaster. 22882 * @param {Array<Object>} intersects - The target array that holds the intersection points. 22883 */ 22884 raycast( raycaster, intersects ) { 22885 22886 const geometry = this.geometry; 22887 const matrixWorld = this.matrixWorld; 22888 const threshold = raycaster.params.Line.threshold; 22889 const drawRange = geometry.drawRange; 22890 22891 // Checking boundingSphere distance to ray 22892 22893 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); 22894 22895 _sphere$1.copy( geometry.boundingSphere ); 22896 _sphere$1.applyMatrix4( matrixWorld ); 22897 _sphere$1.radius += threshold; 22898 22899 if ( raycaster.ray.intersectsSphere( _sphere$1 ) === false ) return; 22900 22901 // 22902 22903 _inverseMatrix$1.copy( matrixWorld ).invert(); 22904 _ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 ); 22905 22906 const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); 22907 const localThresholdSq = localThreshold * localThreshold; 22908 22909 const step = this.isLineSegments ? 2 : 1; 22910 22911 const index = geometry.index; 22912 const attributes = geometry.attributes; 22913 const positionAttribute = attributes.position; 22914 22915 if ( index !== null ) { 22916 22917 const start = Math.max( 0, drawRange.start ); 22918 const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); 22919 22920 for ( let i = start, l = end - 1; i < l; i += step ) { 22921 22922 const a = index.getX( i ); 22923 const b = index.getX( i + 1 ); 22924 22925 const intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, a, b, i ); 22926 22927 if ( intersect ) { 22928 22929 intersects.push( intersect ); 22930 22931 } 22932 22933 } 22934 22935 if ( this.isLineLoop ) { 22936 22937 const a = index.getX( end - 1 ); 22938 const b = index.getX( start ); 22939 22940 const intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, a, b, end - 1 ); 22941 22942 if ( intersect ) { 22943 22944 intersects.push( intersect ); 22945 22946 } 22947 22948 } 22949 22950 } else { 22951 22952 const start = Math.max( 0, drawRange.start ); 22953 const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) ); 22954 22955 for ( let i = start, l = end - 1; i < l; i += step ) { 22956 22957 const intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, i, i + 1, i ); 22958 22959 if ( intersect ) { 22960 22961 intersects.push( intersect ); 22962 22963 } 22964 22965 } 22966 22967 if ( this.isLineLoop ) { 22968 22969 const intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, end - 1, start, end - 1 ); 22970 22971 if ( intersect ) { 22972 22973 intersects.push( intersect ); 22974 22975 } 22976 22977 } 22978 22979 } 22980 22981 } 22982 22983 /** 22984 * Sets the values of {@link Line#morphTargetDictionary} and {@link Line#morphTargetInfluences} 22985 * to make sure existing morph targets can influence this 3D object. 22986 */ 22987 updateMorphTargets() { 22988 22989 const geometry = this.geometry; 22990 22991 const morphAttributes = geometry.morphAttributes; 22992 const keys = Object.keys( morphAttributes ); 22993 22994 if ( keys.length > 0 ) { 22995 22996 const morphAttribute = morphAttributes[ keys[ 0 ] ]; 22997 22998 if ( morphAttribute !== undefined ) { 22999 23000 this.morphTargetInfluences = []; 23001 this.morphTargetDictionary = {}; 23002 23003 for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { 23004 23005 const name = morphAttribute[ m ].name || String( m ); 23006 23007 this.morphTargetInfluences.push( 0 ); 23008 this.morphTargetDictionary[ name ] = m; 23009 23010 } 23011 23012 } 23013 23014 } 23015 23016 } 23017 23018} 23019 23020function checkIntersection( object, raycaster, ray, thresholdSq, a, b, i ) { 23021 23022 const positionAttribute = object.geometry.attributes.position; 23023 23024 _vStart.fromBufferAttribute( positionAttribute, a ); 23025 _vEnd.fromBufferAttribute( positionAttribute, b ); 23026 23027 const distSq = ray.distanceSqToSegment( _vStart, _vEnd, _intersectPointOnRay, _intersectPointOnSegment ); 23028 23029 if ( distSq > thresholdSq ) return; 23030 23031 _intersectPointOnRay.applyMatrix4( object.matrixWorld ); // Move back to world space for distance calculation 23032 23033 const distance = raycaster.ray.origin.distanceTo( _intersectPointOnRay ); 23034 23035 if ( distance < raycaster.near || distance > raycaster.far ) return; 23036 23037 return { 23038 23039 distance: distance, 23040 // What do we want? intersection point on the ray or on the segment?? 23041 // point: raycaster.ray.at( distance ), 23042 point: _intersectPointOnSegment.clone().applyMatrix4( object.matrixWorld ), 23043 index: i, 23044 face: null, 23045 faceIndex: null, 23046 barycoord: null, 23047 object: object 23048 23049 }; 23050 23051} 23052 23053/** 23054 * An abstract base class for creating an analytic curve object that contains methods 23055 * for interpolation. 23056 * 23057 * @abstract 23058 */ 23059class Curve { 23060 23061 /** 23062 * Constructs a new curve. 23063 */ 23064 constructor() { 23065 23066 /** 23067 * The type property is used for detecting the object type 23068 * in context of serialization/deserialization. 23069 * 23070 * @type {string} 23071 * @readonly 23072 */ 23073 this.type = 'Curve'; 23074 23075 /** 23076 * This value determines the amount of divisions when calculating the 23077 * cumulative segment lengths of a curve via {@link Curve#getLengths}. To ensure 23078 * precision when using methods like {@link Curve#getSpacedPoints}, it is 23079 * recommended to increase the value of this property if the curve is very large. 23080 * 23081 * @type {number} 23082 * @default 200 23083 */ 23084 this.arcLengthDivisions = 200; 23085 23086 /** 23087 * Must be set to `true` if the curve parameters have changed. 23088 * 23089 * @type {boolean} 23090 * @default false 23091 */ 23092 this.needsUpdate = false;
23093 23094 /** 23095 * An internal cache that holds precomputed curve length values. 23096 * 23097 * @private 23098 * @type {?Array<number>} 23099 * @default null 23100 */ 23101 this.cacheArcLengths = null; 23102 23103 } 23104 23105 /** 23106 * This method returns a vector in 2D or 3D space (depending on the curve definition) 23107 * for the given interpolation factor. 23108 * 23109 * @abstract 23110 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 23111 * @param {(Vector2|Vector3)} [optionalTarget] - The optional target vector the result is written to. 23112 * @return {(Vector2|Vector3)} The position on the curve. It can be a 2D or 3D vector depending on the curve definition. 23113 */ 23114 getPoint( /* t, optionalTarget */ ) { 23115 23116 console.warn( 'THREE.
vendor: 10,031 bytes, lines 23116-23533
23116Curve: .getPoint() not implemented.' ); 23117 23118 } 23119 23120 /** 23121 * This method returns a vector in 2D or 3D space (depending on the curve definition) 23122 * for the given interpolation factor. Unlike {@link Curve#getPoint}, this method honors the length 23123 * of the curve which equidistant samples. 23124 * 23125 * @param {number} u - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 23126 * @param {(Vector2|Vector3)} [optionalTarget] - The optional target vector the result is written to. 23127 * @return {(Vector2|Vector3)} The position on the curve. It can be a 2D or 3D vector depending on the curve definition. 23128 */ 23129 getPointAt( u, optionalTarget ) { 23130 23131 const t = this.getUtoTmapping( u ); 23132 return this.getPoint( t, optionalTarget ); 23133 23134 } 23135 23136 /** 23137 * This method samples the curve via {@link Curve#getPoint} and returns an array of points representing 23138 * the curve shape. 23139 * 23140 * @param {number} [divisions=5] - The number of divisions. 23141 * @return {Array<(Vector2|Vector3)>} An array holding the sampled curve values. The number of points is `divisions + 1`. 23142 */ 23143 getPoints( divisions = 5 ) { 23144 23145 const points = []; 23146 23147 for ( let d = 0; d <= divisions; d ++ ) { 23148 23149 points.push( this.getPoint( d / divisions ) ); 23150 23151 } 23152 23153 return points; 23154 23155 } 23156 23157 // Get sequence of points using getPointAt( u ) 23158 23159 /** 23160 * This method samples the curve via {@link Curve#getPointAt} and returns an array of points representing 23161 * the curve shape. Unlike {@link Curve#getPoints}, this method returns equi-spaced points across the entire 23162 * curve. 23163 * 23164 * @param {number} [divisions=5] - The number of divisions. 23165 * @return {Array<(Vector2|Vector3)>} An array holding the sampled curve values. The number of points is `divisions + 1`. 23166 */ 23167 getSpacedPoints( divisions = 5 ) { 23168 23169 const points = []; 23170 23171 for ( let d = 0; d <= divisions; d ++ ) { 23172 23173 points.push( this.getPointAt( d / divisions ) ); 23174 23175 } 23176 23177 return points; 23178 23179 } 23180 23181 /** 23182 * Returns the total arc length of the curve. 23183 * 23184 * @return {number} The length of the curve. 23185 */ 23186 getLength() { 23187 23188 const lengths = this.getLengths(); 23189 return lengths[ lengths.length - 1 ]; 23190 23191 } 23192 23193 /** 23194 * Returns an array of cumulative segment lengths of the curve. 23195 * 23196 * @param {number} [divisions=this.arcLengthDivisions] - The number of divisions. 23197 * @return {Array<number>} An array holding the cumulative segment lengths. 23198 */ 23199 getLengths( divisions = this.arcLengthDivisions ) { 23200 23201 if ( this.cacheArcLengths && 23202 ( this.cacheArcLengths.length === divisions + 1 ) && 23203 ! this.needsUpdate ) { 23204 23205 return this.cacheArcLengths; 23206 23207 } 23208 23209 this.needsUpdate = false; 23210 23211 const cache = []; 23212 let current, last = this.getPoint( 0 ); 23213 let sum = 0; 23214 23215 cache.push( 0 ); 23216 23217 for ( let p = 1; p <= divisions; p ++ ) { 23218 23219 current = this.getPoint( p / divisions ); 23220 sum += current.distanceTo( last ); 23221 cache.push( sum ); 23222 last = current; 23223 23224 } 23225 23226 this.cacheArcLengths = cache; 23227 23228 return cache; // { sums: cache, sum: sum }; Sum is in the last element. 23229 23230 } 23231 23232 /** 23233 * Update the cumulative segment distance cache. The method must be called 23234 * every time curve parameters are changed. If an updated curve is part of a 23235 * composed curve like {@link CurvePath}, this method must be called on the 23236 * composed curve, too. 23237 */ 23238 updateArcLengths() { 23239 23240 this.needsUpdate = true; 23241 this.getLengths(); 23242 23243 } 23244 23245 /** 23246 * Given an interpolation factor in the range `[0,1]`, this method returns an updated 23247 * interpolation factor in the same range that can be ued to sample equidistant points 23248 * from a curve. 23249 * 23250 * @param {number} u - The interpolation factor. 23251 * @param {?number} distance - An optional distance on the curve. 23252 * @return {number} The updated interpolation factor. 23253 */ 23254 getUtoTmapping( u, distance = null ) { 23255 23256 const arcLengths = this.getLengths(); 23257 23258 let i = 0; 23259 const il = arcLengths.length; 23260 23261 let targetArcLength; // The targeted u distance value to get 23262 23263 if ( distance ) { 23264 23265 targetArcLength = distance; 23266 23267 } else { 23268 23269 targetArcLength = u * arcLengths[ il - 1 ]; 23270 23271 } 23272 23273 // binary search for the index with largest value smaller than target u distance 23274 23275 let low = 0, high = il - 1, comparison; 23276 23277 while ( low <= high ) { 23278 23279 i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats 23280 23281 comparison = arcLengths[ i ] - targetArcLength; 23282 23283 if ( comparison < 0 ) { 23284 23285 low = i + 1; 23286 23287 } else if ( comparison > 0 ) { 23288 23289 high = i - 1; 23290 23291 } else { 23292 23293 high = i; 23294 break; 23295 23296 // DONE 23297 23298 } 23299 23300 } 23301 23302 i = high; 23303 23304 if ( arcLengths[ i ] === targetArcLength ) { 23305 23306 return i / ( il - 1 ); 23307 23308 } 23309 23310 // we could get finer grain at lengths, or use simple interpolation between two points 23311 23312 const lengthBefore = arcLengths[ i ]; 23313 const lengthAfter = arcLengths[ i + 1 ]; 23314 23315 const segmentLength = lengthAfter - lengthBefore; 23316 23317 // determine where we are between the 'before' and 'after' points 23318 23319 const segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; 23320 23321 // add that fractional amount to t 23322 23323 const t = ( i + segmentFraction ) / ( il - 1 ); 23324 23325 return t; 23326 23327 } 23328 23329 /** 23330 * Returns a unit vector tangent for the given interpolation factor. 23331 * If the derived curve does not implement its tangent derivation, 23332 * two points a small delta apart will be used to find its gradient 23333 * which seems to give a reasonable approximation. 23334 * 23335 * @param {number} t - The interpolation factor. 23336 * @param {(Vector2|Vector3)} [optionalTarget] - The optional target vector the result is written to. 23337 * @return {(Vector2|Vector3)} The tangent vector. 23338 */ 23339 getTangent( t, optionalTarget ) { 23340 23341 const delta = 0.0001; 23342 let t1 = t - delta; 23343 let t2 = t + delta; 23344 23345 // Capping in case of danger 23346 23347 if ( t1 < 0 ) t1 = 0; 23348 if ( t2 > 1 ) t2 = 1; 23349 23350 const pt1 = this.getPoint( t1 ); 23351 const pt2 = this.getPoint( t2 ); 23352 23353 const tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() ); 23354 23355 tangent.copy( pt2 ).sub( pt1 ).normalize(); 23356 23357 return tangent; 23358 23359 } 23360 23361 /** 23362 * Same as {@link Curve#getTangent} but with equidistant samples. 23363 * 23364 * @param {number} u - The interpolation factor. 23365 * @param {(Vector2|Vector3)} [optionalTarget] - The optional target vector the result is written to. 23366 * @return {(Vector2|Vector3)} The tangent vector. 23367 * @see {@link Curve#getPointAt} 23368 */ 23369 getTangentAt( u, optionalTarget ) { 23370 23371 const t = this.getUtoTmapping( u ); 23372 return this.getTangent( t, optionalTarget ); 23373 23374 } 23375 23376 /** 23377 * Generates the Frenet Frames. Requires a curve definition in 3D space. Used 23378 * in geometries like {@link TubeGeometry} or {@link ExtrudeGeometry}. 23379 * 23380 * @param {number} segments - The number of segments. 23381 * @param {boolean} [closed=false] - Whether the curve is closed or not. 23382 * @return {{tangents: Array<Vector3>, normals: Array<Vector3>, binormals: Array<Vector3>}} The Frenet Frames. 23383 */ 23384 computeFrenetFrames( segments, closed = false ) { 23385 23386 // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf 23387 23388 const normal = new Vector3(); 23389 23390 const tangents = []; 23391 const normals = []; 23392 const binormals = []; 23393 23394 const vec = new Vector3(); 23395 const mat = new Matrix4(); 23396 23397 // compute the tangent vectors for each segment on the curve 23398 23399 for ( let i = 0; i <= segments; i ++ ) { 23400 23401 const u = i / segments; 23402 23403 tangents[ i ] = this.getTangentAt( u, new Vector3() ); 23404 23405 } 23406 23407 // select an initial normal vector perpendicular to the first tangent vector, 23408 // and in the direction of the minimum tangent xyz component 23409 23410 normals[ 0 ] = new Vector3(); 23411 binormals[ 0 ] = new Vector3(); 23412 let min = Number.MAX_VALUE; 23413 const tx = Math.abs( tangents[ 0 ].x ); 23414 const ty = Math.abs( tangents[ 0 ].y ); 23415 const tz = Math.abs( tangents[ 0 ].z ); 23416 23417 if ( tx <= min ) { 23418 23419 min = tx; 23420 normal.set( 1, 0, 0 ); 23421 23422 } 23423 23424 if ( ty <= min ) { 23425 23426 min = ty; 23427 normal.set( 0, 1, 0 ); 23428 23429 } 23430 23431 if ( tz <= min ) { 23432 23433 normal.set( 0, 0, 1 ); 23434 23435 } 23436 23437 vec.crossVectors( tangents[ 0 ], normal ).normalize(); 23438 23439 normals[ 0 ].crossVectors( tangents[ 0 ], vec ); 23440 binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); 23441 23442 23443 // compute the slowly-varying normal and binormal vectors for each segment on the curve 23444 23445 for ( let i = 1; i <= segments; i ++ ) { 23446 23447 normals[ i ] = normals[ i - 1 ].clone(); 23448 23449 binormals[ i ] = binormals[ i - 1 ].clone(); 23450 23451 vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); 23452 23453 if ( vec.length() > Number.EPSILON ) { 23454 23455 vec.normalize(); 23456 23457 const theta = Math.acos( clamp( tangents[ i - 1 ].dot( tangents[ i ] ), -1, 1 ) ); // clamp for floating pt errors 23458 23459 normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); 23460 23461 } 23462 23463 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); 23464 23465 } 23466 23467 // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same 23468 23469 if ( closed === true ) { 23470 23471 let theta = Math.acos( clamp( normals[ 0 ].dot( normals[ segments ] ), -1, 1 ) ); 23472 theta /= segments; 23473 23474 if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { 23475 23476 theta = - theta; 23477 23478 } 23479 23480 for ( let i = 1; i <= segments; i ++ ) { 23481 23482 // twist a little... 23483 normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); 23484 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); 23485 23486 } 23487 23488 } 23489 23490 return { 23491 tangents: tangents, 23492 normals: normals, 23493 binormals: binormals 23494 }; 23495 23496 } 23497 23498 /** 23499 * Returns a new curve with copied values from this instance. 23500 * 23501 * @return {Curve} A clone of this instance. 23502 */ 23503 clone() { 23504 23505 return new this.constructor().copy( this ); 23506 23507 } 23508 23509 /** 23510 * Copies the values of the given curve to this instance. 23511 * 23512 * @param {Curve} source - The curve to copy. 23513 * @return {Curve} A reference to this curve. 23514 */ 23515 copy( source ) { 23516 23517 this.arcLengthDivisions = source.arcLengthDivisions; 23518 23519 return this; 23520 23521 } 23522 23523 /** 23524 * Serializes the curve into JSON. 23525 * 23526 * @return {Object} A JSON object representing the serialized curve. 23527 * @see {@link ObjectLoader#parse} 23528 */ 23529 toJSON() { 23530 23531 const data = { 23532 metadata: { 23533 version: 4.
235336
vendor: 14,056 bytes, lines 23533-24174
23533, 23534 type: 'Curve', 23535 generator: 'Curve.toJSON' 23536 } 23537 }; 23538 23539 data.arcLengthDivisions = this.arcLengthDivisions; 23540 data.type = this.type; 23541 23542 return data; 23543 23544 } 23545 23546 /** 23547 * Deserializes the curve from the given JSON. 23548 * 23549 * @param {Object} json - The JSON holding the serialized curve. 23550 * @return {Curve} A reference to this curve. 23551 */ 23552 fromJSON( json ) { 23553 23554 this.arcLengthDivisions = json.arcLengthDivisions; 23555 23556 return this; 23557 23558 } 23559 23560} 23561 23562/** 23563 * A curve representing an ellipse. 23564 * 23565 * ```js 23566 * const curve = new THREE.EllipseCurve( 23567 * 0, 0, 23568 * 10, 10, 23569 * 0, 2 * Math.PI, 23570 * false, 23571 * 0 23572 * ); 23573 * 23574 * const points = curve.getPoints( 50 ); 23575 * const geometry = new THREE.BufferGeometry().setFromPoints( points ); 23576 * 23577 * const material = new THREE.LineBasicMaterial( { color: 0xff0000 } ); 23578 * 23579 * // Create the final object to add to the scene 23580 * const ellipse = new THREE.Line( geometry, material ); 23581 * ``` 23582 * 23583 * @augments Curve 23584 */ 23585class EllipseCurve extends Curve { 23586 23587 /** 23588 * Constructs a new ellipse curve. 23589 * 23590 * @param {number} [aX=0] - The X center of the ellipse. 23591 * @param {number} [aY=0] - The Y center of the ellipse. 23592 * @param {number} [xRadius=1] - The radius of the ellipse in the x direction. 23593 * @param {number} [yRadius=1] - The radius of the ellipse in the y direction. 23594 * @param {number} [aStartAngle=0] - The start angle of the curve in radians starting from the positive X axis. 23595 * @param {number} [aEndAngle=Math.PI*2] - The end angle of the curve in radians starting from the positive X axis. 23596 * @param {boolean} [aClockwise=false] - Whether the ellipse is drawn clockwise or not. 23597 * @param {number} [aRotation=0] - The rotation angle of the ellipse in radians, counterclockwise from the positive X axis. 23598 */ 23599 constructor( aX = 0, aY = 0, xRadius = 1, yRadius = 1, aStartAngle = 0, aEndAngle = Math.PI * 2, aClockwise = false, aRotation = 0 ) { 23600 23601 super(); 23602 23603 /** 23604 * This flag can be used for type testing. 23605 * 23606 * @type {boolean} 23607 * @readonly 23608 * @default true 23609 */ 23610 this.isEllipseCurve = true; 23611 23612 this.type = 'EllipseCurve'; 23613 23614 /** 23615 * The X center of the ellipse. 23616 * 23617 * @type {number} 23618 * @default 0 23619 */ 23620 this.aX = aX; 23621 23622 /** 23623 * The Y center of the ellipse. 23624 * 23625 * @type {number} 23626 * @default 0 23627 */ 23628 this.aY = aY; 23629 23630 /** 23631 * The radius of the ellipse in the x direction. 23632 * Setting the this value equal to the {@link EllipseCurve#yRadius} will result in a circle. 23633 * 23634 * @type {number} 23635 * @default 1 23636 */ 23637 this.xRadius = xRadius; 23638 23639 /** 23640 * The radius of the ellipse in the y direction. 23641 * Setting the this value equal to the {@link EllipseCurve#xRadius} will result in a circle. 23642 * 23643 * @type {number} 23644 * @default 1 23645 */ 23646 this.yRadius = yRadius; 23647 23648 /** 23649 * The start angle of the curve in radians starting from the positive X axis. 23650 * 23651 * @type {number} 23652 * @default 0 23653 */ 23654 this.aStartAngle = aStartAngle; 23655 23656 /** 23657 * The end angle of the curve in radians starting from the positive X axis. 23658 * 23659 * @type {number} 23660 * @default Math.PI*2 23661 */ 23662 this.aEndAngle = aEndAngle; 23663 23664 /** 23665 * Whether the ellipse is drawn clockwise or not. 23666 * 23667 * @type {boolean} 23668 * @default false 23669 */ 23670 this.aClockwise = aClockwise; 23671 23672 /** 23673 * The rotation angle of the ellipse in radians, counterclockwise from the positive X axis. 23674 * 23675 * @type {number} 23676 * @default 0 23677 */ 23678 this.aRotation = aRotation; 23679 23680 } 23681 23682 /** 23683 * Returns a point on the curve. 23684 * 23685 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 23686 * @param {Vector2} [optionalTarget] - The optional target vector the result is written to. 23687 * @return {Vector2} The position on the curve. 23688 */ 23689 getPoint( t, optionalTarget = new Vector2() ) { 23690 23691 const point = optionalTarget; 23692 23693 const twoPi = Math.PI * 2; 23694 let deltaAngle = this.aEndAngle - this.aStartAngle; 23695 const samePoints = Math.abs( deltaAngle ) < Number.EPSILON; 23696 23697 // ensures that deltaAngle is 0 .. 2 PI 23698 while ( deltaAngle < 0 ) deltaAngle += twoPi; 23699 while ( deltaAngle > twoPi ) deltaAngle -= twoPi; 23700 23701 if ( deltaAngle < Number.EPSILON ) { 23702 23703 if ( samePoints ) { 23704 23705 deltaAngle = 0; 23706 23707 } else { 23708 23709 deltaAngle = twoPi; 23710 23711 } 23712 23713 } 23714 23715 if ( this.aClockwise === true && ! samePoints ) { 23716 23717 if ( deltaAngle === twoPi ) { 23718 23719 deltaAngle = - twoPi; 23720 23721 } else { 23722 23723 deltaAngle = deltaAngle - twoPi; 23724 23725 } 23726 23727 } 23728 23729 const angle = this.aStartAngle + t * deltaAngle; 23730 let x = this.aX + this.xRadius * Math.cos( angle ); 23731 let y = this.aY + this.yRadius * Math.sin( angle ); 23732 23733 if ( this.aRotation !== 0 ) { 23734 23735 const cos = Math.cos( this.aRotation ); 23736 const sin = Math.sin( this.aRotation ); 23737 23738 const tx = x - this.aX; 23739 const ty = y - this.aY; 23740 23741 // Rotate the point about the center of the ellipse. 23742 x = tx * cos - ty * sin + this.aX; 23743 y = tx * sin + ty * cos + this.aY; 23744 23745 } 23746 23747 return point.set( x, y ); 23748 23749 } 23750 23751 copy( source ) { 23752 23753 super.copy( source ); 23754 23755 this.aX = source.aX; 23756 this.aY = source.aY; 23757 23758 this.xRadius = source.xRadius; 23759 this.yRadius = source.yRadius; 23760 23761 this.aStartAngle = source.aStartAngle; 23762 this.aEndAngle = source.aEndAngle; 23763 23764 this.aClockwise = source.aClockwise; 23765 23766 this.aRotation = source.aRotation; 23767 23768 return this; 23769 23770 } 23771 23772 toJSON() { 23773 23774 const data = super.toJSON(); 23775 23776 data.aX = this.aX; 23777 data.aY = this.aY; 23778 23779 data.xRadius = this.xRadius; 23780 data.yRadius = this.yRadius; 23781 23782 data.aStartAngle = this.aStartAngle; 23783 data.aEndAngle = this.aEndAngle; 23784 23785 data.aClockwise = this.aClockwise; 23786 23787 data.aRotation = this.aRotation; 23788 23789 return data; 23790 23791 } 23792 23793 fromJSON( json ) { 23794 23795 super.fromJSON( json ); 23796 23797 this.aX = json.aX; 23798 this.aY = json.aY; 23799 23800 this.xRadius = json.xRadius; 23801 this.yRadius = json.yRadius; 23802 23803 this.aStartAngle = json.aStartAngle; 23804 this.aEndAngle = json.aEndAngle; 23805 23806 this.aClockwise = json.aClockwise; 23807 23808 this.aRotation = json.aRotation; 23809 23810 return this; 23811 23812 } 23813 23814} 23815 23816/** 23817 * A curve representing an arc. 23818 * 23819 * @augments EllipseCurve 23820 */ 23821class ArcCurve extends EllipseCurve { 23822 23823 /** 23824 * Constructs a new arc curve. 23825 * 23826 * @param {number} [aX=0] - The X center of the ellipse. 23827 * @param {number} [aY=0] - The Y center of the ellipse. 23828 * @param {number} [aRadius=1] - The radius of the ellipse in the x direction. 23829 * @param {number} [aStartAngle=0] - The start angle of the curve in radians starting from the positive X axis. 23830 * @param {number} [aEndAngle=Math.PI*2] - The end angle of the curve in radians starting from the positive X axis. 23831 * @param {boolean} [aClockwise=false] - Whether the ellipse is drawn clockwise or not. 23832 */ 23833 constructor( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { 23834 23835 super( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); 23836 23837 /** 23838 * This flag can be used for type testing. 23839 * 23840 * @type {boolean} 23841 * @readonly 23842 * @default true 23843 */ 23844 this.isArcCurve = true; 23845 23846 this.type = 'ArcCurve'; 23847 23848 } 23849 23850} 23851 23852function CubicPoly() { 23853 23854 /** 23855 * Centripetal CatmullRom Curve - which is useful for avoiding 23856 * cusps and self-intersections in non-uniform catmull rom curves. 23857 * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf 23858 * 23859 * curve.type accepts centripetal(default), chordal and catmullrom 23860 * curve.tension is used for catmullrom which defaults to 0.5 23861 */ 23862 23863 /* 23864 Based on an optimized c++ solution in 23865 - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/ 23866 - http://ideone.com/NoEbVM 23867 23868 This CubicPoly class could be used for reusing some variables and calculations, 23869 but for three.js curve use, it could be possible inlined and flatten into a single function call 23870 which can be placed in CurveUtils. 23871 */ 23872 23873 let c0 = 0, c1 = 0, c2 = 0, c3 = 0; 23874 23875 /* 23876 * Compute coefficients for a cubic polynomial 23877 * p(s) = c0 + c1*s + c2*s^2 + c3*s^3 23878 * such that 23879 * p(0) = x0, p(1) = x1 23880 * and 23881 * p'(0) = t0, p'(1) = t1. 23882 */ 23883 function init( x0, x1, t0, t1 ) { 23884 23885 c0 = x0; 23886 c1 = t0; 23887 c2 = -3 * x0 + 3 * x1 - 2 * t0 - t1; 23888 c3 = 2 * x0 - 2 * x1 + t0 + t1; 23889 23890 } 23891 23892 return { 23893 23894 initCatmullRom: function ( x0, x1, x2, x3, tension ) { 23895 23896 init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); 23897 23898 }, 23899 23900 initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) { 23901 23902 // compute tangents when parameterized in [t1,t2] 23903 let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; 23904 let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2; 23905 23906 // rescale tangents for parametrization in [0,1] 23907 t1 *= dt1; 23908 t2 *= dt1; 23909 23910 init( x1, x2, t1, t2 ); 23911 23912 }, 23913 23914 calc: function ( t ) { 23915 23916 const t2 = t * t; 23917 const t3 = t2 * t; 23918 return c0 + c1 * t + c2 * t2 + c3 * t3; 23919 23920 } 23921 23922 }; 23923 23924} 23925 23926// 23927 23928const tmp = /*@__PURE__*/ new Vector3(); 23929const px = /*@__PURE__*/ new CubicPoly(); 23930const py = /*@__PURE__*/ new CubicPoly(); 23931const pz = /*@__PURE__*/ new CubicPoly(); 23932 23933/** 23934 * A curve representing a Catmull-Rom spline. 23935 * 23936 * ```js 23937 * //Create a closed wavey loop 23938 * const curve = new THREE.CatmullRomCurve3( [ 23939 * new THREE.Vector3( -10, 0, 10 ), 23940 * new THREE.Vector3( -5, 5, 5 ), 23941 * new THREE.Vector3( 0, 0, 0 ), 23942 * new THREE.Vector3( 5, -5, 5 ), 23943 * new THREE.Vector3( 10, 0, 10 ) 23944 * ] ); 23945 * 23946 * const points = curve.getPoints( 50 ); 23947 * const geometry = new THREE.BufferGeometry().setFromPoints( points ); 23948 * 23949 * const material = new THREE.LineBasicMaterial( { color: 0xff0000 } ); 23950 * 23951 * // Create the final object to add to the scene 23952 * const curveObject = new THREE.Line( geometry, material ); 23953 * ``` 23954 * 23955 * @augments Curve 23956 */ 23957class CatmullRomCurve3 extends Curve { 23958 23959 /** 23960 * Constructs a new Catmull-Rom curve. 23961 * 23962 * @param {Array<Vector3>} [points] - An array of 3D points defining the curve. 23963 * @param {boolean} [closed=false] - Whether the curve is closed or not. 23964 * @param {('centripetal'|'chordal'|'catmullrom')} [curveType='centripetal'] - The curve type. 23965 * @param {number} [tension=0.5] - Tension of the curve. 23966 */ 23967 constructor( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) { 23968 23969 super(); 23970 23971 /** 23972 * This flag can be used for type testing. 23973 * 23974 * @type {boolean} 23975 * @readonly 23976 * @default true 23977 */ 23978 this.isCatmullRomCurve3 = true; 23979 23980 this.type = 'CatmullRomCurve3'; 23981 23982 /** 23983 * An array of 3D points defining the curve. 23984 * 23985 * @type {Array<Vector3>} 23986 */ 23987 this.points = points; 23988 23989 /** 23990 * Whether the curve is closed or not. 23991 * 23992 * @type {boolean} 23993 * @default false 23994 */ 23995 this.closed = closed; 23996 23997 /** 23998 * The curve type. 23999 * 24000 * @type {('centripetal'|'chordal'|'catmullrom')} 24001 * @default 'centripetal' 24002 */ 24003 this.curveType = curveType; 24004 24005 /** 24006 * Tension of the curve. 24007 * 24008 * @type {number} 24009 * @default 0.5 24010 */ 24011 this.tension = tension; 24012 24013 } 24014 24015 /** 24016 * Returns a point on the curve. 24017 * 24018 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 24019 * @param {Vector3} [optionalTarget] - The optional target vector the result is written to. 24020 * @return {Vector3} The position on the curve. 24021 */ 24022 getPoint( t, optionalTarget = new Vector3() ) { 24023 24024 const point = optionalTarget; 24025 24026 const points = this.points; 24027 const l = points.length; 24028 24029 const p = ( l - ( this.closed ? 0 : 1 ) ) * t; 24030 let intPoint = Math.floor( p ); 24031 let weight = p - intPoint; 24032 24033 if ( this.closed ) { 24034 24035 intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l; 24036 24037 } else if ( weight === 0 && intPoint === l - 1 ) { 24038 24039 intPoint = l - 2; 24040 weight = 1; 24041 24042 } 24043 24044 let p0, p3; // 4 points (p1 & p2 defined below) 24045 24046 if ( this.closed || intPoint > 0 ) { 24047 24048 p0 = points[ ( intPoint - 1 ) % l ]; 24049 24050 } else { 24051 24052 // extrapolate first point 24053 tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); 24054 p0 = tmp; 24055 24056 } 24057 24058 const p1 = points[ intPoint % l ]; 24059 const p2 = points[ ( intPoint + 1 ) % l ]; 24060 24061 if ( this.closed || intPoint + 2 < l ) { 24062 24063 p3 = points[ ( intPoint + 2 ) % l ]; 24064 24065 } else { 24066 24067 // extrapolate last point 24068 tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] ); 24069 p3 = tmp; 24070 24071 } 24072 24073 if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) { 24074 24075 // init Centripetal / Chordal Catmull-Rom 24076 const pow = this.curveType === 'chordal' ? 0.5 : 0.25; 24077 let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); 24078 let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); 24079 let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); 24080 24081 // safety check for repeated points 24082 if ( dt1 < 1e-4 ) dt1 = 1.0; 24083 if ( dt0 < 1e-4 ) dt0 = dt1; 24084 if ( dt2 < 1e-4 ) dt2 = dt1; 24085 24086 px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 ); 24087 py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 ); 24088 pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 ); 24089 24090 } else if ( this.curveType === 'catmullrom' ) { 24091 24092 px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension ); 24093 py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension ); 24094 pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension ); 24095 24096 } 24097 24098 point.set( 24099 px.calc( weight ), 24100 py.calc( weight ), 24101 pz.calc( weight ) 24102 ); 24103 24104 return point; 24105 24106 } 24107 24108 copy( source ) { 24109 24110 super.copy( source ); 24111 24112 this.points = []; 24113 24114 for ( let i = 0, l = source.points.length; i < l; i ++ ) { 24115 24116 const point = source.points[ i ]; 24117 24118 this.points.push( point.clone() ); 24119 24120 } 24121 24122 this.closed = source.closed; 24123 this.curveType = source.curveType; 24124 this.tension = source.tension; 24125 24126 return this; 24127 24128 } 24129 24130 toJSON() { 24131 24132 const data = super.toJSON(); 24133 24134 data.points = []; 24135 24136 for ( let i = 0, l = this.points.length; i < l; i ++ ) { 24137 24138 const point = this.points[ i ]; 24139 data.points.push( point.toArray() ); 24140 24141 } 24142 24143 data.closed = this.closed; 24144 data.curveType = this.curveType; 24145 data.tension = this.tension; 24146 24147 return data; 24148 24149 } 24150 24151 fromJSON( json ) { 24152 24153 super.fromJSON( json ); 24154 24155 this.points = []; 24156 24157 for ( let i = 0, l = json.points.length; i < l; i ++ ) { 24158 24159 const point = json.points[ i ]; 24160 this.points.push( new Vector3().fromArray( point ) ); 24161 24162 } 24163 24164 this.closed = json.closed; 24165 this.curveType = json.curveType; 24166 this.tension = json.tension; 24167 24168 return this; 24169 24170 } 24171 24172} 24173 24174/
24174/ Bezier Curves formulas obtained from: https://en.wikipedia.org/wiki/B%C3%A9zier_curve
vendor: 28,440 bytes, lines 24174-25660
24174 24175 24176/** 24177 * Computes a point on a Catmull-Rom spline. 24178 * 24179 * @param {number} t - The interpolation factor. 24180 * @param {number} p0 - The first control point. 24181 * @param {number} p1 - The second control point. 24182 * @param {number} p2 - The third control point. 24183 * @param {number} p3 - The fourth control point. 24184 * @return {number} The calculated point on a Catmull-Rom spline. 24185 */ 24186function CatmullRom( t, p0, p1, p2, p3 ) { 24187 24188 const v0 = ( p2 - p0 ) * 0.5; 24189 const v1 = ( p3 - p1 ) * 0.5; 24190 const t2 = t * t; 24191 const t3 = t * t2; 24192 return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( -3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; 24193 24194} 24195 24196// 24197 24198function QuadraticBezierP0( t, p ) { 24199 24200 const k = 1 - t; 24201 return k * k * p; 24202 24203} 24204 24205function QuadraticBezierP1( t, p ) { 24206 24207 return 2 * ( 1 - t ) * t * p; 24208 24209} 24210 24211function QuadraticBezierP2( t, p ) { 24212 24213 return t * t * p; 24214 24215} 24216 24217/** 24218 * Computes a point on a Quadratic Bezier curve. 24219 * 24220 * @param {number} t - The interpolation factor. 24221 * @param {number} p0 - The first control point. 24222 * @param {number} p1 - The second control point. 24223 * @param {number} p2 - The third control point. 24224 * @return {number} The calculated point on a Quadratic Bezier curve. 24225 */ 24226function QuadraticBezier( t, p0, p1, p2 ) { 24227 24228 return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + 24229 QuadraticBezierP2( t, p2 ); 24230 24231} 24232 24233// 24234 24235function CubicBezierP0( t, p ) { 24236 24237 const k = 1 - t; 24238 return k * k * k * p; 24239 24240} 24241 24242function CubicBezierP1( t, p ) { 24243 24244 const k = 1 - t; 24245 return 3 * k * k * t * p; 24246 24247} 24248 24249function CubicBezierP2( t, p ) { 24250 24251 return 3 * ( 1 - t ) * t * t * p; 24252 24253} 24254 24255function CubicBezierP3( t, p ) { 24256 24257 return t * t * t * p; 24258 24259} 24260 24261/** 24262 * Computes a point on a Cubic Bezier curve. 24263 * 24264 * @param {number} t - The interpolation factor. 24265 * @param {number} p0 - The first control point. 24266 * @param {number} p1 - The second control point. 24267 * @param {number} p2 - The third control point. 24268 * @param {number} p3 - The fourth control point. 24269 * @return {number} The calculated point on a Cubic Bezier curve. 24270 */ 24271function CubicBezier( t, p0, p1, p2, p3 ) { 24272 24273 return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + 24274 CubicBezierP3( t, p3 ); 24275 24276} 24277 24278/** 24279 * A curve representing a 2D Cubic Bezier curve. 24280 * 24281 * ```js 24282 * const curve = new THREE.CubicBezierCurve( 24283 * new THREE.Vector2( - 0, 0 ), 24284 * new THREE.Vector2( - 5, 15 ), 24285 * new THREE.Vector2( 20, 15 ), 24286 * new THREE.Vector2( 10, 0 ) 24287 * ); 24288 * 24289 * const points = curve.getPoints( 50 ); 24290 * const geometry = new THREE.BufferGeometry().setFromPoints( points ); 24291 * 24292 * const material = new THREE.LineBasicMaterial( { color: 0xff0000 } ); 24293 * 24294 * // Create the final object to add to the scene 24295 * const curveObject = new THREE.Line( geometry, material ); 24296 * ``` 24297 * 24298 * @augments Curve 24299 */ 24300class CubicBezierCurve extends Curve { 24301 24302 /** 24303 * Constructs a new Cubic Bezier curve. 24304 * 24305 * @param {Vector2} [v0] - The start point. 24306 * @param {Vector2} [v1] - The first control point. 24307 * @param {Vector2} [v2] - The second control point. 24308 * @param {Vector2} [v3] - The end point. 24309 */ 24310 constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) { 24311 24312 super(); 24313 24314 /** 24315 * This flag can be used for type testing. 24316 * 24317 * @type {boolean} 24318 * @readonly 24319 * @default true 24320 */ 24321 this.isCubicBezierCurve = true; 24322 24323 this.type = 'CubicBezierCurve'; 24324 24325 /** 24326 * The start point. 24327 * 24328 * @type {Vector2} 24329 */ 24330 this.v0 = v0; 24331 24332 /** 24333 * The first control point. 24334 * 24335 * @type {Vector2} 24336 */ 24337 this.v1 = v1; 24338 24339 /** 24340 * The second control point. 24341 * 24342 * @type {Vector2} 24343 */ 24344 this.v2 = v2; 24345 24346 /** 24347 * The end point. 24348 * 24349 * @type {Vector2} 24350 */ 24351 this.v3 = v3; 24352 24353 } 24354 24355 /** 24356 * Returns a point on the curve. 24357 * 24358 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 24359 * @param {Vector2} [optionalTarget] - The optional target vector the result is written to. 24360 * @return {Vector2} The position on the curve. 24361 */ 24362 getPoint( t, optionalTarget = new Vector2() ) { 24363 24364 const point = optionalTarget; 24365 24366 const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; 24367 24368 point.set( 24369 CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), 24370 CubicBezier( t, v0.y, v1.y, v2.y, v3.y ) 24371 ); 24372 24373 return point; 24374 24375 } 24376 24377 copy( source ) { 24378 24379 super.copy( source ); 24380 24381 this.v0.copy( source.v0 ); 24382 this.v1.copy( source.v1 ); 24383 this.v2.copy( source.v2 ); 24384 this.v3.copy( source.v3 ); 24385 24386 return this; 24387 24388 } 24389 24390 toJSON() { 24391 24392 const data = super.toJSON(); 24393 24394 data.v0 = this.v0.toArray(); 24395 data.v1 = this.v1.toArray(); 24396 data.v2 = this.v2.toArray(); 24397 data.v3 = this.v3.toArray(); 24398 24399 return data; 24400 24401 } 24402 24403 fromJSON( json ) { 24404 24405 super.fromJSON( json ); 24406 24407 this.v0.fromArray( json.v0 ); 24408 this.v1.fromArray( json.v1 ); 24409 this.v2.fromArray( json.v2 ); 24410 this.v3.fromArray( json.v3 ); 24411 24412 return this; 24413 24414 } 24415 24416} 24417 24418/** 24419 * A curve representing a 3D Cubic Bezier curve. 24420 * 24421 * @augments Curve 24422 */ 24423class CubicBezierCurve3 extends Curve { 24424 24425 /** 24426 * Constructs a new Cubic Bezier curve. 24427 * 24428 * @param {Vector3} [v0] - The start point. 24429 * @param {Vector3} [v1] - The first control point. 24430 * @param {Vector3} [v2] - The second control point. 24431 * @param {Vector3} [v3] - The end point. 24432 */ 24433 constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) { 24434 24435 super(); 24436 24437 /** 24438 * This flag can be used for type testing. 24439 * 24440 * @type {boolean} 24441 * @readonly 24442 * @default true 24443 */ 24444 this.isCubicBezierCurve3 = true; 24445 24446 this.type = 'CubicBezierCurve3'; 24447 24448 /** 24449 * The start point. 24450 * 24451 * @type {Vector3} 24452 */ 24453 this.v0 = v0; 24454 24455 /** 24456 * The first control point. 24457 * 24458 * @type {Vector3} 24459 */ 24460 this.v1 = v1; 24461 24462 /** 24463 * The second control point. 24464 * 24465 * @type {Vector3} 24466 */ 24467 this.v2 = v2; 24468 24469 /** 24470 * The end point. 24471 * 24472 * @type {Vector3} 24473 */ 24474 this.v3 = v3; 24475 24476 } 24477 24478 /** 24479 * Returns a point on the curve. 24480 * 24481 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 24482 * @param {Vector3} [optionalTarget] - The optional target vector the result is written to. 24483 * @return {Vector3} The position on the curve. 24484 */ 24485 getPoint( t, optionalTarget = new Vector3() ) { 24486 24487 const point = optionalTarget; 24488 24489 const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; 24490 24491 point.set( 24492 CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), 24493 CubicBezier( t, v0.y, v1.y, v2.y, v3.y ), 24494 CubicBezier( t, v0.z, v1.z, v2.z, v3.z ) 24495 ); 24496 24497 return point; 24498 24499 } 24500 24501 copy( source ) { 24502 24503 super.copy( source ); 24504 24505 this.v0.copy( source.v0 ); 24506 this.v1.copy( source.v1 ); 24507 this.v2.copy( source.v2 ); 24508 this.v3.copy( source.v3 ); 24509 24510 return this; 24511 24512 } 24513 24514 toJSON() { 24515 24516 const data = super.toJSON(); 24517 24518 data.v0 = this.v0.toArray(); 24519 data.v1 = this.v1.toArray(); 24520 data.v2 = this.v2.toArray(); 24521 data.v3 = this.v3.toArray(); 24522 24523 return data; 24524 24525 } 24526 24527 fromJSON( json ) { 24528 24529 super.fromJSON( json ); 24530 24531 this.v0.fromArray( json.v0 ); 24532 this.v1.fromArray( json.v1 ); 24533 this.v2.fromArray( json.v2 ); 24534 this.v3.fromArray( json.v3 ); 24535 24536 return this; 24537 24538 } 24539 24540} 24541 24542/** 24543 * A curve representing a 2D line segment. 24544 * 24545 * @augments Curve 24546 */ 24547class LineCurve extends Curve { 24548 24549 /** 24550 * Constructs a new line curve. 24551 * 24552 * @param {Vector2} [v1] - The start point. 24553 * @param {Vector2} [v2] - The end point. 24554 */ 24555 constructor( v1 = new Vector2(), v2 = new Vector2() ) { 24556 24557 super(); 24558 24559 /** 24560 * This flag can be used for type testing. 24561 * 24562 * @type {boolean} 24563 * @readonly 24564 * @default true 24565 */ 24566 this.isLineCurve = true; 24567 24568 this.type = 'LineCurve'; 24569 24570 /** 24571 * The start point. 24572 * 24573 * @type {Vector2} 24574 */ 24575 this.v1 = v1; 24576 24577 /** 24578 * The end point. 24579 * 24580 * @type {Vector2} 24581 */ 24582 this.v2 = v2; 24583 24584 } 24585 24586 /** 24587 * Returns a point on the line. 24588 * 24589 * @param {number} t - A interpolation factor representing a position on the line. Must be in the range `[0,1]`. 24590 * @param {Vector2} [optionalTarget] - The optional target vector the result is written to. 24591 * @return {Vector2} The position on the line. 24592 */ 24593 getPoint( t, optionalTarget = new Vector2() ) { 24594 24595 const point = optionalTarget; 24596 24597 if ( t === 1 ) { 24598 24599 point.copy( this.v2 ); 24600 24601 } else { 24602 24603 point.copy( this.v2 ).sub( this.v1 ); 24604 point.multiplyScalar( t ).add( this.v1 ); 24605 24606 } 24607 24608 return point; 24609 24610 } 24611 24612 // Line curve is linear, so we can overwrite default getPointAt 24613 getPointAt( u, optionalTarget ) { 24614 24615 return this.getPoint( u, optionalTarget ); 24616 24617 } 24618 24619 getTangent( t, optionalTarget = new Vector2() ) { 24620 24621 return optionalTarget.subVectors( this.v2, this.v1 ).normalize(); 24622 24623 } 24624 24625 getTangentAt( u, optionalTarget ) { 24626 24627 return this.getTangent( u, optionalTarget ); 24628 24629 } 24630 24631 copy( source ) { 24632 24633 super.copy( source ); 24634 24635 this.v1.copy( source.v1 ); 24636 this.v2.copy( source.v2 ); 24637 24638 return this; 24639 24640 } 24641 24642 toJSON() { 24643 24644 const data = super.toJSON(); 24645 24646 data.v1 = this.v1.toArray(); 24647 data.v2 = this.v2.toArray(); 24648 24649 return data; 24650 24651 } 24652 24653 fromJSON( json ) { 24654 24655 super.fromJSON( json ); 24656 24657 this.v1.fromArray( json.v1 ); 24658 this.v2.fromArray( json.v2 ); 24659 24660 return this; 24661 24662 } 24663 24664} 24665 24666/** 24667 * A curve representing a 3D line segment. 24668 * 24669 * @augments Curve 24670 */ 24671class LineCurve3 extends Curve { 24672 24673 /** 24674 * Constructs a new line curve. 24675 * 24676 * @param {Vector3} [v1] - The start point. 24677 * @param {Vector3} [v2] - The end point. 24678 */ 24679 constructor( v1 = new Vector3(), v2 = new Vector3() ) { 24680 24681 super(); 24682 24683 /** 24684 * This flag can be used for type testing. 24685 * 24686 * @type {boolean} 24687 * @readonly 24688 * @default true 24689 */ 24690 this.isLineCurve3 = true; 24691 24692 this.type = 'LineCurve3'; 24693 24694 /** 24695 * The start point. 24696 * 24697 * @type {Vector3} 24698 */ 24699 this.v1 = v1; 24700 24701 /** 24702 * The end point. 24703 * 24704 * @type {Vector2} 24705 */ 24706 this.v2 = v2; 24707 24708 } 24709 24710 /** 24711 * Returns a point on the line. 24712 * 24713 * @param {number} t - A interpolation factor representing a position on the line. Must be in the range `[0,1]`. 24714 * @param {Vector3} [optionalTarget] - The optional target vector the result is written to. 24715 * @return {Vector3} The position on the line. 24716 */ 24717 getPoint( t, optionalTarget = new Vector3() ) { 24718 24719 const point = optionalTarget; 24720 24721 if ( t === 1 ) { 24722 24723 point.copy( this.v2 ); 24724 24725 } else { 24726 24727 point.copy( this.v2 ).sub( this.v1 ); 24728 point.multiplyScalar( t ).add( this.v1 ); 24729 24730 } 24731 24732 return point; 24733 24734 } 24735 24736 // Line curve is linear, so we can overwrite default getPointAt 24737 getPointAt( u, optionalTarget ) { 24738 24739 return this.getPoint( u, optionalTarget ); 24740 24741 } 24742 24743 getTangent( t, optionalTarget = new Vector3() ) { 24744 24745 return optionalTarget.subVectors( this.v2, this.v1 ).normalize(); 24746 24747 } 24748 24749 getTangentAt( u, optionalTarget ) { 24750 24751 return this.getTangent( u, optionalTarget ); 24752 24753 } 24754 24755 copy( source ) { 24756 24757 super.copy( source ); 24758 24759 this.v1.copy( source.v1 ); 24760 this.v2.copy( source.v2 ); 24761 24762 return this; 24763 24764 } 24765 24766 toJSON() { 24767 24768 const data = super.toJSON(); 24769 24770 data.v1 = this.v1.toArray(); 24771 data.v2 = this.v2.toArray(); 24772 24773 return data; 24774 24775 } 24776 24777 fromJSON( json ) { 24778 24779 super.fromJSON( json ); 24780 24781 this.v1.fromArray( json.v1 ); 24782 this.v2.fromArray( json.v2 ); 24783 24784 return this; 24785 24786 } 24787 24788} 24789 24790/** 24791 * A curve representing a 2D Quadratic Bezier curve. 24792 * 24793 * ```js 24794 * const curve = new THREE.QuadraticBezierCurve( 24795 * new THREE.Vector2( - 10, 0 ), 24796 * new THREE.Vector2( 20, 15 ), 24797 * new THREE.Vector2( 10, 0 ) 24798 * ) 24799 * 24800 * const points = curve.getPoints( 50 ); 24801 * const geometry = new THREE.BufferGeometry().setFromPoints( points ); 24802 * 24803 * const material = new THREE.LineBasicMaterial( { color: 0xff0000 } ); 24804 * 24805 * // Create the final object to add to the scene 24806 * const curveObject = new THREE.Line( geometry, material ); 24807 * ``` 24808 * 24809 * @augments Curve 24810 */ 24811class QuadraticBezierCurve extends Curve { 24812 24813 /** 24814 * Constructs a new Quadratic Bezier curve. 24815 * 24816 * @param {Vector2} [v0] - The start point. 24817 * @param {Vector2} [v1] - The control point. 24818 * @param {Vector2} [v2] - The end point. 24819 */ 24820 constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) { 24821 24822 super(); 24823 24824 /** 24825 * This flag can be used for type testing. 24826 * 24827 * @type {boolean} 24828 * @readonly 24829 * @default true 24830 */ 24831 this.isQuadraticBezierCurve = true; 24832 24833 this.type = 'QuadraticBezierCurve'; 24834 24835 /** 24836 * The start point. 24837 * 24838 * @type {Vector2} 24839 */ 24840 this.v0 = v0; 24841 24842 /** 24843 * The control point. 24844 * 24845 * @type {Vector2} 24846 */ 24847 this.v1 = v1; 24848 24849 /** 24850 * The end point. 24851 * 24852 * @type {Vector2} 24853 */ 24854 this.v2 = v2; 24855 24856 } 24857 24858 /** 24859 * Returns a point on the curve. 24860 * 24861 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 24862 * @param {Vector2} [optionalTarget] - The optional target vector the result is written to. 24863 * @return {Vector2} The position on the curve. 24864 */ 24865 getPoint( t, optionalTarget = new Vector2() ) { 24866 24867 const point = optionalTarget; 24868 24869 const v0 = this.v0, v1 = this.v1, v2 = this.v2; 24870 24871 point.set( 24872 QuadraticBezier( t, v0.x, v1.x, v2.x ), 24873 QuadraticBezier( t, v0.y, v1.y, v2.y ) 24874 ); 24875 24876 return point; 24877 24878 } 24879 24880 copy( source ) { 24881 24882 super.copy( source ); 24883 24884 this.v0.copy( source.v0 ); 24885 this.v1.copy( source.v1 ); 24886 this.v2.copy( source.v2 ); 24887 24888 return this; 24889 24890 } 24891 24892 toJSON() { 24893 24894 const data = super.toJSON(); 24895 24896 data.v0 = this.v0.toArray(); 24897 data.v1 = this.v1.toArray(); 24898 data.v2 = this.v2.toArray(); 24899 24900 return data; 24901 24902 } 24903 24904 fromJSON( json ) { 24905 24906 super.fromJSON( json ); 24907 24908 this.v0.fromArray( json.v0 ); 24909 this.v1.fromArray( json.v1 ); 24910 this.v2.fromArray( json.v2 ); 24911 24912 return this; 24913 24914 } 24915 24916} 24917 24918/** 24919 * A curve representing a 3D Quadratic Bezier curve. 24920 * 24921 * @augments Curve 24922 */ 24923class QuadraticBezierCurve3 extends Curve { 24924 24925 /** 24926 * Constructs a new Quadratic Bezier curve. 24927 * 24928 * @param {Vector3} [v0] - The start point. 24929 * @param {Vector3} [v1] - The control point. 24930 * @param {Vector3} [v2] - The end point. 24931 */ 24932 constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) { 24933 24934 super(); 24935 24936 /** 24937 * This flag can be used for type testing. 24938 * 24939 * @type {boolean} 24940 * @readonly 24941 * @default true 24942 */ 24943 this.isQuadraticBezierCurve3 = true; 24944 24945 this.type = 'QuadraticBezierCurve3'; 24946 24947 /** 24948 * The start point. 24949 * 24950 * @type {Vector3} 24951 */ 24952 this.v0 = v0; 24953 24954 /** 24955 * The control point. 24956 * 24957 * @type {Vector3} 24958 */ 24959 this.v1 = v1; 24960 24961 /** 24962 * The end point. 24963 * 24964 * @type {Vector3} 24965 */ 24966 this.v2 = v2; 24967 24968 } 24969 24970 /** 24971 * Returns a point on the curve. 24972 * 24973 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 24974 * @param {Vector3} [optionalTarget] - The optional target vector the result is written to. 24975 * @return {Vector3} The position on the curve. 24976 */ 24977 getPoint( t, optionalTarget = new Vector3() ) { 24978 24979 const point = optionalTarget; 24980 24981 const v0 = this.v0, v1 = this.v1, v2 = this.v2; 24982 24983 point.set( 24984 QuadraticBezier( t, v0.x, v1.x, v2.x ), 24985 QuadraticBezier( t, v0.y, v1.y, v2.y ), 24986 QuadraticBezier( t, v0.z, v1.z, v2.z ) 24987 ); 24988 24989 return point; 24990 24991 } 24992 24993 copy( source ) { 24994 24995 super.copy( source ); 24996 24997 this.v0.copy( source.v0 ); 24998 this.v1.copy( source.v1 ); 24999 this.v2.copy( source.v2 ); 25000 25001 return this; 25002 25003 } 25004 25005 toJSON() { 25006 25007 const data = super.toJSON(); 25008 25009 data.v0 = this.v0.toArray(); 25010 data.v1 = this.v1.toArray(); 25011 data.v2 = this.v2.toArray(); 25012 25013 return data; 25014 25015 } 25016 25017 fromJSON( json ) { 25018 25019 super.fromJSON( json ); 25020 25021 this.v0.fromArray( json.v0 ); 25022 this.v1.fromArray( json.v1 ); 25023 this.v2.fromArray( json.v2 ); 25024 25025 return this; 25026 25027 } 25028 25029} 25030 25031/** 25032 * A curve representing a 2D spline curve. 25033 * 25034 * ```js 25035 * // Create a sine-like wave 25036 * const curve = new THREE.SplineCurve( [ 25037 * new THREE.Vector2( -10, 0 ), 25038 * new THREE.Vector2( -5, 5 ), 25039 * new THREE.Vector2( 0, 0 ), 25040 * new THREE.Vector2( 5, -5 ), 25041 * new THREE.Vector2( 10, 0 ) 25042 * ] ); 25043 * 25044 * const points = curve.getPoints( 50 ); 25045 * const geometry = new THREE.BufferGeometry().setFromPoints( points ); 25046 * 25047 * const material = new THREE.LineBasicMaterial( { color: 0xff0000 } ); 25048 * 25049 * // Create the final object to add to the scene 25050 * const splineObject = new THREE.Line( geometry, material ); 25051 * ``` 25052 * 25053 * @augments Curve 25054 */ 25055class SplineCurve extends Curve { 25056 25057 /** 25058 * Constructs a new 2D spline curve. 25059 * 25060 * @param {Array<Vector2>} [points] - An array of 2D points defining the curve. 25061 */ 25062 constructor( points = [] ) { 25063 25064 super(); 25065 25066 /** 25067 * This flag can be used for type testing. 25068 * 25069 * @type {boolean} 25070 * @readonly 25071 * @default true 25072 */ 25073 this.isSplineCurve = true; 25074 25075 this.type = 'SplineCurve'; 25076 25077 /** 25078 * An array of 2D points defining the curve. 25079 * 25080 * @type {Array<Vector2>} 25081 */ 25082 this.points = points; 25083 25084 } 25085 25086 /** 25087 * Returns a point on the curve. 25088 * 25089 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 25090 * @param {Vector2} [optionalTarget] - The optional target vector the result is written to. 25091 * @return {Vector2} The position on the curve. 25092 */ 25093 getPoint( t, optionalTarget = new Vector2() ) { 25094 25095 const point = optionalTarget; 25096 25097 const points = this.points; 25098 const p = ( points.length - 1 ) * t; 25099 25100 const intPoint = Math.floor( p ); 25101 const weight = p - intPoint; 25102 25103 const p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; 25104 const p1 = points[ intPoint ]; 25105 const p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; 25106 const p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; 25107 25108 point.set( 25109 CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ), 25110 CatmullRom( weight, p0.y, p1.y, p2.y, p3.y ) 25111 ); 25112 25113 return point; 25114 25115 } 25116 25117 copy( source ) { 25118 25119 super.copy( source ); 25120 25121 this.points = []; 25122 25123 for ( let i = 0, l = source.points.length; i < l; i ++ ) { 25124 25125 const point = source.points[ i ]; 25126 25127 this.points.push( point.clone() ); 25128 25129 } 25130 25131 return this; 25132 25133 } 25134 25135 toJSON() { 25136 25137 const data = super.toJSON(); 25138 25139 data.points = []; 25140 25141 for ( let i = 0, l = this.points.length; i < l; i ++ ) { 25142 25143 const point = this.points[ i ]; 25144 data.points.push( point.toArray() ); 25145 25146 } 25147 25148 return data; 25149 25150 } 25151 25152 fromJSON( json ) { 25153 25154 super.fromJSON( json ); 25155 25156 this.points = []; 25157 25158 for ( let i = 0, l = json.points.length; i < l; i ++ ) { 25159 25160 const point = json.points[ i ]; 25161 this.points.push( new Vector2().fromArray( point ) ); 25162 25163 } 25164 25165 return this; 25166 25167 } 25168 25169} 25170 25171var Curves = /*#__PURE__*/Object.freeze({ 25172 __proto__: null, 25173 ArcCurve: ArcCurve, 25174 CatmullRomCurve3: CatmullRomCurve3, 25175 CubicBezierCurve: CubicBezierCurve, 25176 CubicBezierCurve3: CubicBezierCurve3, 25177 EllipseCurve: EllipseCurve, 25178 LineCurve: LineCurve, 25179 LineCurve3: LineCurve3, 25180 QuadraticBezierCurve: QuadraticBezierCurve, 25181 QuadraticBezierCurve3: QuadraticBezierCurve3, 25182 SplineCurve: SplineCurve 25183}); 25184 25185/** 25186 * A base class extending {@link Curve}. `CurvePath` is simply an 25187 * array of connected curves, but retains the API of a curve. 25188 * 25189 * @augments Curve 25190 */ 25191class CurvePath extends Curve { 25192 25193 /** 25194 * Constructs a new curve path. 25195 */ 25196 constructor() { 25197 25198 super(); 25199 25200 this.type = 'CurvePath'; 25201 25202 /** 25203 * An array of curves defining the 25204 * path. 25205 * 25206 * @type {Array<Curve>} 25207 */ 25208 this.curves = []; 25209 25210 /** 25211 * Whether the path should automatically be closed 25212 * by a line curve. 25213 * 25214 * @type {boolean} 25215 * @default false 25216 */ 25217 this.autoClose = false; 25218 25219 } 25220 25221 /** 25222 * Adds a curve to this curve path. 25223 * 25224 * @param {Curve} curve - The curve to add. 25225 */ 25226 add( curve ) { 25227 25228 this.curves.push( curve ); 25229 25230 } 25231 25232 /** 25233 * Adds a line curve to close the path. 25234 * 25235 * @return {CurvePath} A reference to this curve path. 25236 */ 25237 closePath() { 25238 25239 // Add a line curve if start and end of lines are not connected 25240 const startPoint = this.curves[ 0 ].getPoint( 0 ); 25241 const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 ); 25242 25243 if ( ! startPoint.equals( endPoint ) ) { 25244 25245 const lineType = ( startPoint.isVector2 === true ) ? 'LineCurve' : 'LineCurve3'; 25246 this.curves.push( new Curves[ lineType ]( endPoint, startPoint ) ); 25247 25248 } 25249 25250 return this; 25251 25252 } 25253 25254 /** 25255 * This method returns a vector in 2D or 3D space (depending on the curve definitions) 25256 * for the given interpolation factor. 25257 * 25258 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 25259 * @param {(Vector2|Vector3)} [optionalTarget] - The optional target vector the result is written to. 25260 * @return {?(Vector2|Vector3)} The position on the curve. It can be a 2D or 3D vector depending on the curve definition. 25261 */ 25262 getPoint( t, optionalTarget ) { 25263 25264 // To get accurate point with reference to 25265 // entire path distance at time t, 25266 // following has to be done: 25267 25268 // 1. Length of each sub path have to be known 25269 // 2. Locate and identify type of curve 25270 // 3. Get t for the curve 25271 // 4. Return curve.getPointAt(t') 25272 25273 const d = t * this.getLength(); 25274 const curveLengths = this.getCurveLengths(); 25275 let i = 0; 25276 25277 // To think about boundaries points. 25278 25279 while ( i < curveLengths.length ) { 25280 25281 if ( curveLengths[ i ] >= d ) { 25282 25283 const diff = curveLengths[ i ] - d; 25284 const curve = this.curves[ i ]; 25285 25286 const segmentLength = curve.getLength(); 25287 const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; 25288 25289 return curve.getPointAt( u, optionalTarget ); 25290 25291 } 25292 25293 i ++; 25294 25295 } 25296 25297 return null; 25298 25299 // loop where sum != 0, sum > d , sum+1 <d 25300 25301 } 25302 25303 getLength() { 25304 25305 // We cannot use the default THREE.Curve getPoint() with getLength() because in 25306 // THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath 25307 // getPoint() depends on getLength 25308 25309 const lens = this.getCurveLengths(); 25310 return lens[ lens.length - 1 ]; 25311 25312 } 25313 25314 updateArcLengths() { 25315 25316 // cacheLengths must be recalculated. 25317 25318 this.needsUpdate = true; 25319 this.cacheLengths = null; 25320 this.getCurveLengths(); 25321 25322 } 25323 25324 /** 25325 * Returns list of cumulative curve lengths of the defined curves. 25326 * 25327 * @return {Array<number>} The curve lengths. 25328 */ 25329 getCurveLengths() { 25330 25331 // Compute lengths and cache them 25332 // We cannot overwrite getLengths() because UtoT mapping uses it. 25333 // We use cache values if curves and cache array are same length 25334 25335 if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) { 25336 25337 return this.cacheLengths; 25338 25339 } 25340 25341 // Get length of sub-curve 25342 // Push sums into cached array 25343 25344 const lengths = []; 25345 let sums = 0; 25346 25347 for ( let i = 0, l = this.curves.length; i < l; i ++ ) { 25348 25349 sums += this.curves[ i ].getLength(); 25350 lengths.push( sums ); 25351 25352 } 25353 25354 this.cacheLengths = lengths; 25355 25356 return lengths; 25357 25358 } 25359 25360 getSpacedPoints( divisions = 40 ) { 25361 25362 const points = []; 25363 25364 for ( let i = 0; i <= divisions; i ++ ) { 25365 25366 points.push( this.getPoint( i / divisions ) ); 25367 25368 } 25369 25370 if ( this.autoClose ) { 25371 25372 points.push( points[ 0 ] ); 25373 25374 } 25375 25376 return points; 25377 25378 } 25379 25380 getPoints( divisions = 12 ) { 25381 25382 const points = []; 25383 let last; 25384 25385 for ( let i = 0, curves = this.curves; i < curves.length; i ++ ) { 25386 25387 const curve = curves[ i ]; 25388 const resolution = curve.isEllipseCurve ? divisions * 2 25389 : ( curve.isLineCurve || curve.isLineCurve3 ) ? 1 25390 : curve.isSplineCurve ? divisions * curve.points.length 25391 : divisions; 25392 25393 const pts = curve.getPoints( resolution ); 25394 25395 for ( let j = 0; j < pts.length; j ++ ) { 25396 25397 const point = pts[ j ]; 25398 25399 if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates 25400 25401 points.push( point ); 25402 last = point; 25403 25404 } 25405 25406 } 25407 25408 if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) { 25409 25410 points.push( points[ 0 ] ); 25411 25412 } 25413 25414 return points; 25415 25416 } 25417 25418 copy( source ) { 25419 25420 super.copy( source ); 25421 25422 this.curves = []; 25423 25424 for ( let i = 0, l = source.curves.length; i < l; i ++ ) { 25425 25426 const curve = source.curves[ i ]; 25427 25428 this.curves.push( curve.clone() ); 25429 25430 } 25431 25432 this.autoClose = source.autoClose; 25433 25434 return this; 25435 25436 } 25437 25438 toJSON() { 25439 25440 const data = super.toJSON(); 25441 25442 data.autoClose = this.autoClose; 25443 data.curves = []; 25444 25445 for ( let i = 0, l = this.curves.length; i < l; i ++ ) { 25446 25447 const curve = this.curves[ i ]; 25448 data.curves.push( curve.toJSON() ); 25449 25450 } 25451 25452 return data; 25453 25454 } 25455 25456 fromJSON( json ) { 25457 25458 super.fromJSON( json ); 25459 25460 this.autoClose = json.autoClose; 25461 this.curves = []; 25462 25463 for ( let i = 0, l = json.curves.length; i < l; i ++ ) { 25464 25465 const curve = json.curves[ i ]; 25466 this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) ); 25467 25468 } 25469 25470 return this; 25471 25472 } 25473 25474} 25475 25476/** 25477 * A 2D path representation. The class provides methods for creating paths 25478 * and contours of 2D shapes similar to the 2D Canvas API. 25479 * 25480 * ```js 25481 * const path = new THREE.Path(); 25482 * 25483 * path.lineTo( 0, 0.8 ); 25484 * path.quadraticCurveTo( 0, 1, 0.2, 1 ); 25485 * path.lineTo( 1, 1 ); 25486 * 25487 * const points = path.getPoints(); 25488 * 25489 * const geometry = new THREE.BufferGeometry().setFromPoints( points ); 25490 * const material = new THREE.LineBasicMaterial( { color: 0xffffff } ); 25491 * 25492 * const line = new THREE.Line( geometry, material ); 25493 * scene.add( line ); 25494 * ``` 25495 * 25496 * @augments CurvePath 25497 */ 25498class Path extends CurvePath { 25499 25500 /** 25501 * Constructs a new path. 25502 * 25503 * @param {Array<Vector2>} [points] - An array of 2D points defining the path. 25504 */ 25505 constructor( points ) { 25506 25507 super(); 25508 25509 this.type = 'Path'; 25510 25511 /** 25512 * The current offset of the path. Any new curve added will start here. 25513 * 25514 * @type {Vector2} 25515 */ 25516 this.currentPoint = new Vector2(); 25517 25518 if ( points ) { 25519 25520 this.setFromPoints( points ); 25521 25522 } 25523 25524 } 25525 25526 /** 25527 * Creates a path from the given list of points. The points are added 25528 * to the path as instances of {@link LineCurve}. 25529 * 25530 * @param {Array<Vector2>} points - An array of 2D points. 25531 * @return {Path} A reference to this path. 25532 */ 25533 setFromPoints( points ) { 25534 25535 this.moveTo( points[ 0 ].x, points[ 0 ].y ); 25536 25537 for ( let i = 1, l = points.length; i < l; i ++ ) { 25538 25539 this.lineTo( points[ i ].x, points[ i ].y ); 25540 25541 } 25542 25543 return this; 25544 25545 } 25546 25547 /** 25548 * Moves {@link Path#currentPoint} to the given point. 25549 * 25550 * @param {number} x - The x coordinate. 25551 * @param {number} y - The y coordinate. 25552 * @return {Path} A reference to this path. 25553 */ 25554 moveTo( x, y ) { 25555 25556 this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? 25557 25558 return this; 25559 25560 } 25561 25562 /** 25563 * Adds an instance of {@link LineCurve} to the path by connecting 25564 * the current point with the given one. 25565 * 25566 * @param {number} x - The x coordinate of the end point. 25567 * @param {number} y - The y coordinate of the end point. 25568 * @return {Path} A reference to this path. 25569 */ 25570 lineTo( x, y ) { 25571 25572 const curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); 25573 this.curves.push( curve ); 25574 25575 this.currentPoint.set( x, y ); 25576 25577 return this; 25578 25579 } 25580 25581 /** 25582 * Adds an instance of {@link QuadraticBezierCurve} to the path by connecting 25583 * the current point with the given one. 25584 * 25585 * @param {number} aCPx - The x coordinate of the control point. 25586 * @param {number} aCPy - The y coordinate of the control point. 25587 * @param {number} aX - The x coordinate of the end point. 25588 * @param {number} aY - The y coordinate of the end point. 25589 * @return {Path} A reference to this path. 25590 */ 25591 quadraticCurveTo( aCPx, aCPy, aX, aY ) { 25592 25593 const curve = new QuadraticBezierCurve( 25594 this.currentPoint.clone(), 25595 new Vector2( aCPx, aCPy ), 25596 new Vector2( aX, aY ) 25597 ); 25598 25599 this.curves.push( curve ); 25600 25601 this.currentPoint.set( aX, aY ); 25602 25603 return this; 25604 25605 } 25606 25607 /** 25608 * Adds an instance of {@link CubicBezierCurve} to the path by connecting 25609 * the current point with the given one. 25610 * 25611 * @param {number} aCP1x - The x coordinate of the first control point. 25612 * @param {number} aCP1y - The y coordinate of the first control point. 25613 * @param {number} aCP2x - The x coordinate of the second control point. 25614 * @param {number} aCP2y - The y coordinate of the second control point. 25615 * @param {number} aX - The x coordinate of the end point. 25616 * @param {number} aY - The y coordinate of the end point. 25617 * @return {Path} A reference to this path. 25618 */ 25619 bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { 25620 25621 const curve = new CubicBezierCurve( 25622 this.currentPoint.clone(), 25623 new Vector2( aCP1x, aCP1y ), 25624 new Vector2( aCP2x, aCP2y ), 25625 new Vector2( aX, aY ) 25626 ); 25627 25628 this.curves.push( curve ); 25629 25630 this.currentPoint.set( aX, aY ); 25631 25632 return this; 25633 25634 } 25635 25636 /** 25637 * Adds an instance of {@link SplineCurve} to the path by connecting 25638 * the current point with the given list of points. 25639 * 25640 * @param {Array<Vector2>} pts - An array of points in 2D space. 25641 * @return {Path} A reference to this path. 25642 */ 25643 splineThru( pts ) { 25644 25645 const npts = [ this.currentPoint.clone() ].concat( pts ); 25646 25647 const curve = new SplineCurve( npts ); 25648 this.curves.push( curve ); 25649 25650 this.currentPoint.copy( pts[ pts.length - 1 ] ); 25651 25652 return this; 25653 25654 } 25655 25656 /** 25657 * Adds an arc as an instance of {@link EllipseCurve} to the path, positioned relative 25658 * to the current point. 25659 * 25660 * @param {number}
25660aX - The x coordinate of the center of the arc offsetted from the previous curve. 25661 * @param {number} aY - The y coordinate of the center of the arc offsetted from the previous curve. 25662 * @param {number} aRadius - The radius of the arc. 25663 * @param {number} aStartAngle - The start angle in radians. 25664 * @param {number} aEndAngle - The end angle in radians. 25665 * @param {boolean} [aClockwise=false] - Whether to sweep the arc clockwise or not. 25666 * @return {Path} A reference to this path. 25667 */ 25668 arc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { 25669 25670 const x0 = this.currentPoint.x; 25671 const y0 = this.currentPoint.y; 25672 25673 this.absarc( aX + x0, aY + y0, aRadius, 25674 aStartAngle, aEndAngle, aClockwise ); 25675 25676 return this; 25677 25678 } 25679
vendor: 31,426 bytes, lines 25680-26835
25680 /** 25681 * Adds an absolutely positioned arc as an instance of {@link EllipseCurve} to the path. 25682 * 25683 * @param {number} aX - The x coordinate of the center of the arc. 25684 * @param {number} aY - The y coordinate of the center of the arc. 25685 * @param {number} aRadius - The radius of the arc. 25686 * @param {number} aStartAngle - The start angle in radians. 25687 * @param {number} aEndAngle - The end angle in radians. 25688 * @param {boolean} [aClockwise=false] - Whether to sweep the arc clockwise or not. 25689 * @return {Path} A reference to this path. 25690 */ 25691 absarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { 25692 25693 this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); 25694 25695 return this; 25696 25697 } 25698 25699 /** 25700 * Adds an ellipse as an instance of {@link EllipseCurve} to the path, positioned relative 25701 * to the current point 25702 * 25703 * @param {number} aX - The x coordinate of the center of the ellipse offsetted from the previous curve. 25704 * @param {number} aY - The y coordinate of the center of the ellipse offsetted from the previous curve. 25705 * @param {number} xRadius - The radius of the ellipse in the x axis. 25706 * @param {number} yRadius - The radius of the ellipse in the y axis. 25707 * @param {number} aStartAngle - The start angle in radians. 25708 * @param {number} aEndAngle - The end angle in radians. 25709 * @param {boolean} [aClockwise=false] - Whether to sweep the ellipse clockwise or not. 25710 * @param {number} [aRotation=0] - The rotation angle of the ellipse in radians, counterclockwise from the positive X axis. 25711 * @return {Path} A reference to this path. 25712 */ 25713 ellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { 25714 25715 const x0 = this.currentPoint.x; 25716 const y0 = this.currentPoint.y; 25717 25718 this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); 25719 25720 return this; 25721 25722 } 25723 25724 /** 25725 * Adds an absolutely positioned ellipse as an instance of {@link EllipseCurve} to the path. 25726 * 25727 * @param {number} aX - The x coordinate of the absolute center of the ellipse. 25728 * @param {number} aY - The y coordinate of the absolute center of the ellipse. 25729 * @param {number} xRadius - The radius of the ellipse in the x axis. 25730 * @param {number} yRadius - The radius of the ellipse in the y axis. 25731 * @param {number} aStartAngle - The start angle in radians. 25732 * @param {number} aEndAngle - The end angle in radians. 25733 * @param {boolean} [aClockwise=false] - Whether to sweep the ellipse clockwise or not. 25734 * @param {number} [aRotation=0] - The rotation angle of the ellipse in radians, counterclockwise from the positive X axis. 25735 * @return {Path} A reference to this path. 25736 */ 25737 absellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { 25738 25739 const curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); 25740 25741 if ( this.curves.length > 0 ) { 25742 25743 // if a previous curve is present, attempt to join 25744 const firstPoint = curve.getPoint( 0 ); 25745 25746 if ( ! firstPoint.equals( this.currentPoint ) ) { 25747 25748 this.lineTo( firstPoint.x, firstPoint.y ); 25749 25750 } 25751 25752 } 25753 25754 this.curves.push( curve ); 25755 25756 const lastPoint = curve.getPoint( 1 ); 25757 this.currentPoint.copy( lastPoint ); 25758 25759 return this; 25760 25761 } 25762 25763 copy( source ) { 25764 25765 super.copy( source ); 25766 25767 this.currentPoint.copy( source.currentPoint ); 25768 25769 return this; 25770 25771 } 25772 25773 toJSON() { 25774 25775 const data = super.toJSON(); 25776 25777 data.currentPoint = this.currentPoint.toArray(); 25778 25779 return data; 25780 25781 } 25782 25783 fromJSON( json ) { 25784 25785 super.fromJSON( json ); 25786 25787 this.currentPoint.fromArray( json.currentPoint ); 25788 25789 return this; 25790 25791 } 25792 25793} 25794 25795/** 25796 * A geometry class for representing a cylinder. 25797 * 25798 * ```js 25799 * const geometry = new THREE.CylinderGeometry( 5, 5, 20, 32 ); 25800 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); 25801 * const cylinder = new THREE.Mesh( geometry, material ); 25802 * scene.add( cylinder ); 25803 * ``` 25804 * 25805 * @augments BufferGeometry 25806 */ 25807class CylinderGeometry extends BufferGeometry { 25808 25809 /** 25810 * Constructs a new cylinder geometry. 25811 * 25812 * @param {number} [radiusTop=1] - Radius of the cylinder at the top. 25813 * @param {number} [radiusBottom=1] - Radius of the cylinder at the bottom. 25814 * @param {number} [height=1] - Height of the cylinder. 25815 * @param {number} [radialSegments=32] - Number of segmented faces around the circumference of the cylinder. 25816 * @param {number} [heightSegments=1] - Number of rows of faces along the height of the cylinder. 25817 * @param {boolean} [openEnded=false] - Whether the base of the cylinder is open or capped. 25818 * @param {number} [thetaStart=0] - Start angle for first segment, in radians. 25819 * @param {number} [thetaLength=Math.PI*2] - The central angle, often called theta, of the circular sector, in radians. 25820 * The default value results in a complete cylinder. 25821 */ 25822 constructor( radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) { 25823 25824 super(); 25825 25826 this.type = 'CylinderGeometry'; 25827 25828 /** 25829 * Holds the constructor parameters that have been 25830 * used to generate the geometry. Any modification 25831 * after instantiation does not change the geometry. 25832 * 25833 * @type {Object} 25834 */ 25835 this.parameters = { 25836 radiusTop: radiusTop, 25837 radiusBottom: radiusBottom, 25838 height: height, 25839 radialSegments: radialSegments, 25840 heightSegments: heightSegments, 25841 openEnded: openEnded, 25842 thetaStart: thetaStart, 25843 thetaLength: thetaLength 25844 }; 25845 25846 const scope = this; 25847 25848 radialSegments = Math.floor( radialSegments ); 25849 heightSegments = Math.floor( heightSegments ); 25850 25851 // buffers 25852 25853 const indices = []; 25854 const vertices = []; 25855 const normals = []; 25856 const uvs = []; 25857 25858 // helper variables 25859 25860 let index = 0; 25861 const indexArray = []; 25862 const halfHeight = height / 2; 25863 let groupStart = 0; 25864 25865 // generate geometry 25866 25867 generateTorso(); 25868 25869 if ( openEnded === false ) { 25870 25871 if ( radiusTop > 0 ) generateCap( true ); 25872 if ( radiusBottom > 0 ) generateCap( false ); 25873 25874 } 25875 25876 // build geometry 25877 25878 this.setIndex( indices ); 25879 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 25880 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 25881 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 25882 25883 function generateTorso() { 25884 25885 const normal = new Vector3(); 25886 const vertex = new Vector3(); 25887 25888 let groupCount = 0; 25889 25890 // this will be used to calculate the normal 25891 const slope = ( radiusBottom - radiusTop ) / height; 25892 25893 // generate vertices, normals and uvs 25894 25895 for ( let y = 0; y <= heightSegments; y ++ ) { 25896 25897 const indexRow = []; 25898 25899 const v = y / heightSegments; 25900 25901 // calculate the radius of the current row 25902 25903 const radius = v * ( radiusBottom - radiusTop ) + radiusTop; 25904 25905 for ( let x = 0; x <= radialSegments; x ++ ) { 25906 25907 const u = x / radialSegments; 25908 25909 const theta = u * thetaLength + thetaStart; 25910 25911 const sinTheta = Math.sin( theta ); 25912 const cosTheta = Math.cos( theta ); 25913 25914 // vertex 25915 25916 vertex.x = radius * sinTheta; 25917 vertex.y = - v * height + halfHeight; 25918 vertex.z = radius * cosTheta; 25919 vertices.push( vertex.x, vertex.y, vertex.z ); 25920 25921 // normal 25922 25923 normal.set( sinTheta, slope, cosTheta ).normalize(); 25924 normals.push( normal.x, normal.y, normal.z ); 25925 25926 // uv 25927 25928 uvs.push( u, 1 - v ); 25929 25930 // save index of vertex in respective row 25931 25932 indexRow.push( index ++ ); 25933 25934 } 25935 25936 // now save vertices of the row in our index array 25937 25938 indexArray.push( indexRow ); 25939 25940 } 25941 25942 // generate indices 25943 25944 for ( let x = 0; x < radialSegments; x ++ ) { 25945 25946 for ( let y = 0; y < heightSegments; y ++ ) { 25947 25948 // we use the index array to access the correct indices 25949 25950 const a = indexArray[ y ][ x ]; 25951 const b = indexArray[ y + 1 ][ x ]; 25952 const c = indexArray[ y + 1 ][ x + 1 ]; 25953 const d = indexArray[ y ][ x + 1 ]; 25954 25955 // faces 25956 25957 if ( radiusTop > 0 || y !== 0 ) { 25958 25959 indices.push( a, b, d ); 25960 groupCount += 3; 25961 25962 } 25963 25964 if ( radiusBottom > 0 || y !== heightSegments - 1 ) { 25965 25966 indices.push( b, c, d ); 25967 groupCount += 3; 25968 25969 } 25970 25971 } 25972 25973 } 25974 25975 // add a group to the geometry. this will ensure multi material support 25976 25977 scope.addGroup( groupStart, groupCount, 0 ); 25978 25979 // calculate new start value for groups 25980 25981 groupStart += groupCount; 25982 25983 } 25984 25985 function generateCap( top ) { 25986 25987 // save the index of the first center vertex 25988 const centerIndexStart = index; 25989 25990 const uv = new Vector2(); 25991 const vertex = new Vector3(); 25992 25993 let groupCount = 0; 25994 25995 const radius = ( top === true ) ? radiusTop : radiusBottom; 25996 const sign = ( top === true ) ? 1 : -1; 25997 25998 // first we generate the center vertex data of the cap. 25999 // because the geometry needs one set of uvs per face, 26000 // we must generate a center vertex per face/segment 26001 26002 for ( let x = 1; x <= radialSegments; x ++ ) { 26003 26004 // vertex 26005 26006 vertices.push( 0, halfHeight * sign, 0 ); 26007 26008 // normal 26009 26010 normals.push( 0, sign, 0 ); 26011 26012 // uv 26013 26014 uvs.push( 0.5, 0.5 ); 26015 26016 // increase index 26017 26018 index ++; 26019 26020 } 26021 26022 // save the index of the last center vertex 26023 const centerIndexEnd = index; 26024 26025 // now we generate the surrounding vertices, normals and uvs 26026 26027 for ( let x = 0; x <= radialSegments; x ++ ) { 26028 26029 const u = x / radialSegments; 26030 const theta = u * thetaLength + thetaStart; 26031 26032 const cosTheta = Math.cos( theta ); 26033 const sinTheta = Math.sin( theta ); 26034 26035 // vertex 26036 26037 vertex.x = radius * sinTheta; 26038 vertex.y = halfHeight * sign; 26039 vertex.z = radius * cosTheta; 26040 vertices.push( vertex.x, vertex.y, vertex.z ); 26041 26042 // normal 26043 26044 normals.push( 0, sign, 0 ); 26045 26046 // uv 26047 26048 uv.x = ( cosTheta * 0.5 ) + 0.5; 26049 uv.y = ( sinTheta * 0.5 * sign ) + 0.5; 26050 uvs.push( uv.x, uv.y ); 26051 26052 // increase index 26053 26054 index ++; 26055 26056 } 26057 26058 // generate indices 26059 26060 for ( let x = 0; x < radialSegments; x ++ ) { 26061 26062 const c = centerIndexStart + x; 26063 const i = centerIndexEnd + x; 26064 26065 if ( top === true ) { 26066 26067 // face top 26068 26069 indices.push( i, i + 1, c ); 26070 26071 } else { 26072 26073 // face bottom 26074 26075 indices.push( i + 1, i, c ); 26076 26077 } 26078 26079 groupCount += 3; 26080 26081 } 26082 26083 // add a group to the geometry. this will ensure multi material support 26084 26085 scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 ); 26086 26087 // calculate new start value for groups 26088 26089 groupStart += groupCount; 26090 26091 } 26092 26093 } 26094 26095 copy( source ) { 26096 26097 super.copy( source ); 26098 26099 this.parameters = Object.assign( {}, source.parameters ); 26100 26101 return this; 26102 26103 } 26104 26105 /** 26106 * Factory method for creating an instance of this class from the given 26107 * JSON object. 26108 * 26109 * @param {Object} data - A JSON object representing the serialized geometry. 26110 * @return {CylinderGeometry} A new instance. 26111 */ 26112 static fromJSON( data ) { 26113 26114 return new CylinderGeometry( data.radiusTop, data.radiusBottom, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ); 26115 26116 } 26117 26118} 26119 26120/** 26121 * A geometry class for representing a cone. 26122 * 26123 * ```js 26124 * const geometry = new THREE.ConeGeometry( 5, 20, 32 ); 26125 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); 26126 * const cone = new THREE.Mesh(geometry, material ); 26127 * scene.add( cone ); 26128 * ``` 26129 * 26130 * @augments CylinderGeometry 26131 */ 26132class ConeGeometry extends CylinderGeometry { 26133 26134 /** 26135 * Constructs a new cone geometry. 26136 * 26137 * @param {number} [radius=1] - Radius of the cone base. 26138 * @param {number} [height=1] - Height of the cone. 26139 * @param {number} [radialSegments=32] - Number of segmented faces around the circumference of the cone. 26140 * @param {number} [heightSegments=1] - Number of rows of faces along the height of the cone. 26141 * @param {boolean} [openEnded=false] - Whether the base of the cone is open or capped. 26142 * @param {number} [thetaStart=0] - Start angle for first segment, in radians. 26143 * @param {number} [thetaLength=Math.PI*2] - The central angle, often called theta, of the circular sector, in radians. 26144 * The default value results in a complete cone. 26145 */ 26146 constructor( radius = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) { 26147 26148 super( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); 26149 26150 this.type = 'ConeGeometry'; 26151 26152 /** 26153 * Holds the constructor parameters that have been 26154 * used to generate the geometry. Any modification 26155 * after instantiation does not change the geometry. 26156 * 26157 * @type {Object} 26158 */ 26159 this.parameters = { 26160 radius: radius, 26161 height: height, 26162 radialSegments: radialSegments, 26163 heightSegments: heightSegments, 26164 openEnded: openEnded, 26165 thetaStart: thetaStart, 26166 thetaLength: thetaLength 26167 }; 26168 26169 } 26170 26171 /** 26172 * Factory method for creating an instance of this class from the given 26173 * JSON object. 26174 * 26175 * @param {Object} data - A JSON object representing the serialized geometry. 26176 * @return {ConeGeometry} A new instance. 26177 */ 26178 static fromJSON( data ) { 26179 26180 return new ConeGeometry( data.radius, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ); 26181 26182 } 26183 26184} 26185 26186/** 26187 * Defines an arbitrary 2d shape plane using paths with optional holes. It 26188 * can be used with {@link ExtrudeGeometry}, {@link ShapeGeometry}, to get 26189 * points, or to get triangulated faces. 26190 * 26191 * ```js 26192 * const heartShape = new THREE.Shape(); 26193 * 26194 * heartShape.moveTo( 25, 25 ); 26195 * heartShape.bezierCurveTo( 25, 25, 20, 0, 0, 0 ); 26196 * heartShape.bezierCurveTo( - 30, 0, - 30, 35, - 30, 35 ); 26197 * heartShape.bezierCurveTo( - 30, 55, - 10, 77, 25, 95 ); 26198 * heartShape.bezierCurveTo( 60, 77, 80, 55, 80, 35 ); 26199 * heartShape.bezierCurveTo( 80, 35, 80, 0, 50, 0 ); 26200 * heartShape.bezierCurveTo( 35, 0, 25, 25, 25, 25 ); 26201 * 26202 * const extrudeSettings = { 26203 * depth: 8, 26204 * bevelEnabled: true, 26205 * bevelSegments: 2, 26206 * steps: 2, 26207 * bevelSize: 1, 26208 * bevelThickness: 1 26209 * }; 26210 * 26211 * const geometry = new THREE.ExtrudeGeometry( heartShape, extrudeSettings ); 26212 * const mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial() ); 26213 * ``` 26214 * 26215 * @augments Path 26216 */ 26217class Shape extends Path { 26218 26219 /** 26220 * Constructs a new shape. 26221 * 26222 * @param {Array<Vector2>} [points] - An array of 2D points defining the shape. 26223 */ 26224 constructor( points ) { 26225 26226 super( points ); 26227 26228 /** 26229 * The UUID of the shape. 26230 * 26231 * @type {string} 26232 * @readonly 26233 */ 26234 this.uuid = generateUUID(); 26235 26236 this.type = 'Shape'; 26237 26238 /** 26239 * Defines the holes in the shape. Hole definitions must use the 26240 * opposite winding order (CW/CCW) than the outer shape. 26241 * 26242 * @type {Array<Path>} 26243 * @readonly 26244 */ 26245 this.holes = []; 26246 26247 } 26248 26249 /** 26250 * Returns an array representing each contour of the holes 26251 * as a list of 2D points. 26252 * 26253 * @param {number} divisions - The fineness of the result. 26254 * @return {Array<Array<Vector2>>} The holes as a series of 2D points. 26255 */ 26256 getPointsHoles( divisions ) { 26257 26258 const holesPts = []; 26259 26260 for ( let i = 0, l = this.holes.length; i < l; i ++ ) { 26261 26262 holesPts[ i ] = this.holes[ i ].getPoints( divisions ); 26263 26264 } 26265 26266 return holesPts; 26267 26268 } 26269 26270 // get points of shape and holes (keypoints based on segments parameter) 26271 26272 /** 26273 * Returns an object that holds contour data for the shape and its holes as 26274 * arrays of 2D points. 26275 * 26276 * @param {number} divisions - The fineness of the result. 26277 * @return {{shape:Array<Vector2>,holes:Array<Array<Vector2>>}} An object with contour data. 26278 */ 26279 extractPoints( divisions ) { 26280 26281 return { 26282 26283 shape: this.getPoints( divisions ), 26284 holes: this.getPointsHoles( divisions ) 26285 26286 }; 26287 26288 } 26289 26290 copy( source ) { 26291 26292 super.copy( source ); 26293 26294 this.holes = []; 26295 26296 for ( let i = 0, l = source.holes.length; i < l; i ++ ) { 26297 26298 const hole = source.holes[ i ]; 26299 26300 this.holes.push( hole.clone() ); 26301 26302 } 26303 26304 return this; 26305 26306 } 26307 26308 toJSON() { 26309 26310 const data = super.toJSON(); 26311 26312 data.uuid = this.uuid; 26313 data.holes = []; 26314 26315 for ( let i = 0, l = this.holes.length; i < l; i ++ ) { 26316 26317 const hole = this.holes[ i ]; 26318 data.holes.push( hole.toJSON() ); 26319 26320 } 26321 26322 return data; 26323 26324 } 26325 26326 fromJSON( json ) { 26327 26328 super.fromJSON( json ); 26329 26330 this.uuid = json.uuid; 26331 this.holes = []; 26332 26333 for ( let i = 0, l = json.holes.length; i < l; i ++ ) { 26334 26335 const hole = json.holes[ i ]; 26336 this.holes.push( new Path().fromJSON( hole ) ); 26337 26338 } 26339 26340 return this; 26341 26342 } 26343 26344} 26345 26346/* eslint-disable */ 26347// copy of mapbox/earcut version 3.0.1 26348// https://github.com/mapbox/earcut/tree/v3.0.1 26349 26350function earcut(data, holeIndices, dim = 2) { 26351 26352 const hasHoles = holeIndices && holeIndices.length; 26353 const outerLen = hasHoles ? holeIndices[0] * dim : data.length; 26354 let outerNode = linkedList(data, 0, outerLen, dim, true); 26355 const triangles = []; 26356 26357 if (!outerNode || outerNode.next === outerNode.prev) return triangles; 26358 26359 let minX, minY, invSize; 26360 26361 if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim); 26362 26363 // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox 26364 if (data.length > 80 * dim) { 26365 minX = Infinity; 26366 minY = Infinity; 26367 let maxX = -Infinity; 26368 let maxY = -Infinity; 26369 26370 for (let i = dim; i < outerLen; i += dim) { 26371 const x = data[i]; 26372 const y = data[i + 1]; 26373 if (x < minX) minX = x; 26374 if (y < minY) minY = y; 26375 if (x > maxX) maxX = x; 26376 if (y > maxY) maxY = y; 26377 } 26378 26379 // minX, minY and invSize are later used to transform coords into integers for z-order calculation 26380 invSize = Math.max(maxX - minX, maxY - minY); 26381 invSize = invSize !== 0 ? 32767 / invSize : 0; 26382 } 26383 26384 earcutLinked(outerNode, triangles, dim, minX, minY, invSize, 0); 26385 26386 return triangles; 26387} 26388 26389// create a circular doubly linked list from polygon points in the specified winding order 26390function linkedList(data, start, end, dim, clockwise) { 26391 let last; 26392 26393 if (clockwise === (signedArea(data, start, end, dim) > 0)) { 26394 for (let i = start; i < end; i += dim) last = insertNode(i / dim | 0, data[i], data[i + 1], last); 26395 } else { 26396 for (let i = end - dim; i >= start; i -= dim) last = insertNode(i / dim | 0, data[i], data[i + 1], last); 26397 } 26398 26399 if (last && equals(last, last.next)) { 26400 removeNode(last); 26401 last = last.next; 26402 } 26403 26404 return last; 26405} 26406 26407// eliminate colinear or duplicate points 26408function filterPoints(start, end) { 26409 if (!start) return start; 26410 if (!end) end = start; 26411 26412 let p = start, 26413 again; 26414 do { 26415 again = false; 26416 26417 if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) { 26418 removeNode(p); 26419 p = end = p.prev; 26420 if (p === p.next) break; 26421 again = true; 26422 26423 } else { 26424 p = p.next; 26425 } 26426 } while (again || p !== end); 26427 26428 return end; 26429} 26430 26431// main ear slicing loop which triangulates a polygon (given as a linked list) 26432function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) { 26433 if (!ear) return; 26434 26435 // interlink polygon nodes in z-order 26436 if (!pass && invSize) indexCurve(ear, minX, minY, invSize); 26437 26438 let stop = ear; 26439 26440 // iterate through ears, slicing them one by one 26441 while (ear.prev !== ear.next) { 26442 const prev = ear.prev; 26443 const next = ear.next; 26444 26445 if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) { 26446 triangles.push(prev.i, ear.i, next.i); // cut off the triangle 26447 26448 removeNode(ear); 26449 26450 // skipping the next vertex leads to less sliver triangles 26451 ear = next.next; 26452 stop = next.next; 26453 26454 continue; 26455 } 26456 26457 ear = next; 26458 26459 // if we looped through the whole remaining polygon and can't find any more ears 26460 if (ear === stop) { 26461 // try filtering points and slicing again 26462 if (!pass) { 26463 earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1); 26464 26465 // if this didn't work, try curing all small self-intersections locally 26466 } else if (pass === 1) { 26467 ear = cureLocalIntersections(filterPoints(ear), triangles); 26468 earcutLinked(ear, triangles, dim, minX, minY, invSize, 2); 26469 26470 // as a last resort, try splitting the remaining polygon into two 26471 } else if (pass === 2) { 26472 splitEarcut(ear, triangles, dim, minX, minY, invSize); 26473 } 26474 26475 break; 26476 } 26477 } 26478} 26479 26480// check whether a polygon node forms a valid ear with adjacent nodes 26481function isEar(ear) { 26482 const a = ear.prev, 26483 b = ear, 26484 c = ear.next; 26485 26486 if (area(a, b, c) >= 0) return false; // reflex, can't be an ear 26487 26488 // now make sure we don't have other points inside the potential ear 26489 const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y; 26490 26491 // triangle bbox 26492 const x0 = Math.min(ax, bx, cx), 26493 y0 = Math.min(ay, by, cy), 26494 x1 = Math.max(ax, bx, cx), 26495 y1 = Math.max(ay, by, cy); 26496 26497 let p = c.next; 26498 while (p !== a) { 26499 if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && 26500 pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) && 26501 area(p.prev, p, p.next) >= 0) return false; 26502 p = p.next; 26503 } 26504 26505 return true; 26506} 26507 26508function isEarHashed(ear, minX, minY, invSize) { 26509 const a = ear.prev, 26510 b = ear, 26511 c = ear.next; 26512 26513 if (area(a, b, c) >= 0) return false; // reflex, can't be an ear 26514 26515 const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y; 26516 26517 // triangle bbox 26518 const x0 = Math.min(ax, bx, cx), 26519 y0 = Math.min(ay, by, cy), 26520 x1 = Math.max(ax, bx, cx), 26521 y1 = Math.max(ay, by, cy); 26522 26523 // z-order range for the current triangle bbox; 26524 const minZ = zOrder(x0, y0, minX, minY, invSize), 26525 maxZ = zOrder(x1, y1, minX, minY, invSize); 26526 26527 let p = ear.prevZ, 26528 n = ear.nextZ; 26529 26530 // look for points inside the triangle in both directions 26531 while (p && p.z >= minZ && n && n.z <= maxZ) { 26532 if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && 26533 pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false; 26534 p = p.prevZ; 26535 26536 if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && 26537 pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false; 26538 n = n.nextZ; 26539 } 26540 26541 // look for remaining points in decreasing z-order 26542 while (p && p.z >= minZ) { 26543 if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && 26544 pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false; 26545 p = p.prevZ; 26546 } 26547 26548 // look for remaining points in increasing z-order 26549 while (n && n.z <= maxZ) { 26550 if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && 26551 pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false; 26552 n = n.nextZ; 26553 } 26554 26555 return true; 26556} 26557 26558// go through all polygon nodes and cure small local self-intersections 26559function cureLocalIntersections(start, triangles) { 26560 let p = start; 26561 do { 26562 const a = p.prev, 26563 b = p.next.next; 26564 26565 if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) { 26566 26567 triangles.push(a.i, p.i, b.i); 26568 26569 // remove two nodes involved 26570 removeNode(p); 26571 removeNode(p.next); 26572 26573 p = start = b; 26574 } 26575 p = p.next; 26576 } while (p !== start); 26577 26578 return filterPoints(p); 26579} 26580 26581// try splitting polygon into two and triangulate them independently 26582function splitEarcut(start, triangles, dim, minX, minY, invSize) { 26583 // look for a valid diagonal that divides the polygon into two 26584 let a = start; 26585 do { 26586 let b = a.next.next; 26587 while (b !== a.prev) { 26588 if (a.i !== b.i && isValidDiagonal(a, b)) { 26589 // split the polygon in two by the diagonal 26590 let c = splitPolygon(a, b); 26591 26592 // filter colinear points around the cuts 26593 a = filterPoints(a, a.next); 26594 c = filterPoints(c, c.next); 26595 26596 // run earcut on each half 26597 earcutLinked(a, triangles, dim, minX, minY, invSize, 0); 26598 earcutLinked(c, triangles, dim, minX, minY, invSize, 0); 26599 return; 26600 } 26601 b = b.next; 26602 } 26603 a = a.next; 26604 } while (a !== start); 26605} 26606 26607// link every hole into the outer loop, producing a single-ring polygon without holes 26608function eliminateHoles(data, holeIndices, outerNode, dim) { 26609 const queue = []; 26610 26611 for (let i = 0, len = holeIndices.length; i < len; i++) { 26612 const start = holeIndices[i] * dim; 26613 const end = i < len - 1 ? holeIndices[i + 1] * dim : data.length; 26614 const list = linkedList(data, start, end, dim, false); 26615 if (list === list.next) list.steiner = true; 26616 queue.push(getLeftmost(list)); 26617 } 26618 26619 queue.sort(compareXYSlope); 26620 26621 // process holes from left to right 26622 for (let i = 0; i < queue.length; i++) { 26623 outerNode = eliminateHole(queue[i], outerNode); 26624 } 26625 26626 return outerNode; 26627} 26628 26629function compareXYSlope(a, b) { 26630 let result = a.x - b.x; 26631 // when the left-most point of 2 holes meet at a vertex, sort the holes counterclockwise so that when we find 26632 // the bridge to the outer shell is always the point that they meet at. 26633 if (result === 0) { 26634 result = a.y - b.y; 26635 if (result === 0) { 26636 const aSlope = (a.next.y - a.y) / (a.next.x - a.x); 26637 const bSlope = (b.next.y - b.y) / (b.next.x - b.x); 26638 result = aSlope - bSlope; 26639 } 26640 } 26641 return result; 26642} 26643 26644// find a bridge between vertices that connects hole with an outer ring and and link it 26645function eliminateHole(hole, outerNode) { 26646 const bridge = findHoleBridge(hole, outerNode); 26647 if (!bridge) { 26648 return outerNode; 26649 } 26650 26651 const bridgeReverse = splitPolygon(bridge, hole); 26652 26653 // filter collinear points around the cuts 26654 filterPoints(bridgeReverse, bridgeReverse.next); 26655 return filterPoints(bridge, bridge.next); 26656} 26657 26658// David Eberly's algorithm for finding a bridge between hole and outer polygon 26659function findHoleBridge(hole, outerNode) { 26660 let p = outerNode; 26661 const hx = hole.x; 26662 const hy = hole.y; 26663 let qx = -Infinity; 26664 let m; 26665 26666 // find a segment intersected by a ray from the hole's leftmost point to the left; 26667 // segment's endpoint with lesser x will be potential connection point 26668 // unless they intersect at a vertex, then choose the vertex 26669 if (equals(hole, p)) return p; 26670 do { 26671 if (equals(hole, p.next)) return p.next; 26672 else if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) { 26673 const x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y); 26674 if (x <= hx && x > qx) { 26675 qx = x; 26676 m = p.x < p.next.x ? p : p.next; 26677 if (x === hx) return m; // hole touches outer segment; pick leftmost endpoint 26678 } 26679 } 26680 p = p.next; 26681 } while (p !== outerNode); 26682 26683 if (!m) return null; 26684 26685 // look for points inside the triangle of hole point, segment intersection and endpoint; 26686 // if there are no points found, we have a valid connection; 26687 // otherwise choose the point of the minimum angle with the ray as connection point 26688 26689 const stop = m; 26690 const mx = m.x; 26691 const my = m.y; 26692 let tanMin = Infinity; 26693 26694 p = m; 26695 26696 do { 26697 if (hx >= p.x && p.x >= mx && hx !== p.x && 26698 pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) { 26699 26700 const tan = Math.abs(hy - p.y) / (hx - p.x); // tangential 26701 26702 if (locallyInside(p, hole) && 26703 (tan < tanMin || (tan === tanMin && (p.x > m.x || (p.x === m.x && sectorContainsSector(m, p)))))) { 26704 m = p; 26705 tanMin = tan; 26706 } 26707 } 26708 26709 p = p.next; 26710 } while (p !== stop); 26711 26712 return m; 26713} 26714 26715// whether sector in vertex m contains sector in vertex p in the same coordinates 26716function sectorContainsSector(m, p) { 26717 return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0; 26718} 26719 26720// interlink polygon nodes in z-order 26721function indexCurve(start, minX, minY, invSize) { 26722 let p = start; 26723 do { 26724 if (p.z === 0) p.z = zOrder(p.x, p.y, minX, minY, invSize); 26725 p.prevZ = p.prev; 26726 p.nextZ = p.next; 26727 p = p.next; 26728 } while (p !== start); 26729 26730 p.prevZ.nextZ = null; 26731 p.prevZ = null; 26732 26733 sortLinked(p); 26734} 26735 26736// Simon Tatham's linked list merge sort algorithm 26737// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html 26738function sortLinked(list) { 26739 let numMerges; 26740 let inSize = 1; 26741 26742 do { 26743 let p = list; 26744 let e; 26745 list = null; 26746 let tail = null; 26747 numMerges = 0; 26748 26749 while (p) { 26750 numMerges++; 26751 let q = p; 26752 let pSize = 0; 26753 for (let i = 0; i < inSize; i++) { 26754 pSize++; 26755 q = q.nextZ; 26756 if (!q) break; 26757 } 26758 let qSize = inSize; 26759 26760 while (pSize > 0 || (qSize > 0 && q)) { 26761 26762 if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) { 26763 e = p; 26764 p = p.nextZ; 26765 pSize--; 26766 } else { 26767 e = q; 26768 q = q.nextZ; 26769 qSize--; 26770 } 26771 26772 if (tail) tail.nextZ = e; 26773 else list = e; 26774 26775 e.prevZ = tail; 26776 tail = e; 26777 } 26778 26779 p = q; 26780 } 26781 26782 tail.nextZ = null; 26783 inSize *= 2; 26784 26785 } while (numMerges > 1); 26786 26787 return list; 26788} 26789 26790// z-order of a point given coords and inverse of the longer side of data bbox 26791function zOrder(x, y, minX, minY, invSize) { 26792 // coords are transformed into non-negative 15-bit integer range 26793 x = (x - minX) * invSize | 0; 26794 y = (y - minY) * invSize | 0; 26795 26796 x = (x | (x << 8)) & 0x00FF00FF; 26797 x = (x | (x << 4)) & 0x0F0F0F0F; 26798 x = (x | (x << 2)) & 0x33333333; 26799 x = (x | (x << 1)) & 0x55555555; 26800 26801 y = (y | (y << 8)) & 0x00FF00FF; 26802 y = (y | (y << 4)) & 0x0F0F0F0F; 26803 y = (y | (y << 2)) & 0x33333333; 26804 y = (y | (y << 1)) & 0x55555555; 26805 26806 return x | (y << 1); 26807} 26808 26809// find the leftmost node of a polygon ring 26810function getLeftmost(start) { 26811 let p = start, 26812 leftmost = start; 26813 do { 26814 if (p.x < leftmost.x || (p.x === leftmost.x && p.y < leftmost.y)) leftmost = p; 26815 p = p.next; 26816 } while (p !== start); 26817 26818 return leftmost; 26819} 26820 26821// check if a point lies within a convex triangle 26822function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) { 26823 return (cx - px) * (ay - py) >= (ax - px) * (cy - py) && 26824 (ax - px) * (by - py) >= (bx - px) * (ay - py) && 26825 (bx - px) * (cy - py) >= (cx - px) * (by - py); 26826} 26827 26828// check if a point lies within a convex triangle but false if its equal to the first point of the triangle 26829function pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, px, py) { 26830 return !(ax === px && ay === py) && pointInTriangle(ax, ay, bx, by, cx, cy, px, py); 26831} 26832 26833// check if a diagonal between two polygon nodes is valid (lies in polygon interior) 26834function isValidDiagonal(a, b) { 26835 return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && // dones
vendor: 4,345 bytes, lines 26835-26981
26835't intersect other edges 26836 (locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible 26837 (area(a.prev, a, b.prev) || area(a, b.prev, b)) || // does not create opposite-facing sectors 26838 equals(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0); // special zero-length case 26839} 26840 26841// signed area of a triangle 26842function area(p, q, r) { 26843 return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y); 26844} 26845 26846// check if two points are equal 26847function equals(p1, p2) { 26848 return p1.x === p2.x && p1.y === p2.y; 26849} 26850 26851// check if two segments intersect 26852function intersects(p1, q1, p2, q2) { 26853 const o1 = sign(area(p1, q1, p2)); 26854 const o2 = sign(area(p1, q1, q2)); 26855 const o3 = sign(area(p2, q2, p1)); 26856 const o4 = sign(area(p2, q2, q1)); 26857 26858 if (o1 !== o2 && o3 !== o4) return true; // general case 26859 26860 if (o1 === 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1 26861 if (o2 === 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1 26862 if (o3 === 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2 26863 if (o4 === 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2 26864 26865 return false; 26866} 26867 26868// for collinear points p, q, r, check if point q lies on segment pr 26869function onSegment(p, q, r) { 26870 return q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y); 26871} 26872 26873function sign(num) { 26874 return num > 0 ? 1 : num < 0 ? -1 : 0; 26875} 26876 26877// check if a polygon diagonal intersects any polygon segments 26878function intersectsPolygon(a, b) { 26879 let p = a; 26880 do { 26881 if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && 26882 intersects(p, p.next, a, b)) return true; 26883 p = p.next; 26884 } while (p !== a); 26885 26886 return false; 26887} 26888 26889// check if a polygon diagonal is locally inside the polygon 26890function locallyInside(a, b) { 26891 return area(a.prev, a, a.next) < 0 ? 26892 area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 : 26893 area(a, b, a.prev) < 0 || area(a, a.next, b) < 0; 26894} 26895 26896// check if the middle point of a polygon diagonal is inside the polygon 26897function middleInside(a, b) { 26898 let p = a; 26899 let inside = false; 26900 const px = (a.x + b.x) / 2; 26901 const py = (a.y + b.y) / 2; 26902 do { 26903 if (((p.y > py) !== (p.next.y > py)) && p.next.y !== p.y && 26904 (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x)) 26905 inside = !inside; 26906 p = p.next; 26907 } while (p !== a); 26908 26909 return inside; 26910} 26911 26912// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two; 26913// if one belongs to the outer ring and another to a hole, it merges it into a single ring 26914function splitPolygon(a, b) { 26915 const a2 = createNode(a.i, a.x, a.y), 26916 b2 = createNode(b.i, b.x, b.y), 26917 an = a.next, 26918 bp = b.prev; 26919 26920 a.next = b; 26921 b.prev = a; 26922 26923 a2.next = an; 26924 an.prev = a2; 26925 26926 b2.next = a2; 26927 a2.prev = b2; 26928 26929 bp.next = b2; 26930 b2.prev = bp; 26931 26932 return b2; 26933} 26934 26935// create a node and optionally link it with previous one (in a circular doubly linked list) 26936function insertNode(i, x, y, last) { 26937 const p = createNode(i, x, y); 26938 26939 if (!last) { 26940 p.prev = p; 26941 p.next = p; 26942 26943 } else { 26944 p.next = last.next; 26945 p.prev = last; 26946 last.next.prev = p; 26947 last.next = p; 26948 } 26949 return p; 26950} 26951 26952function removeNode(p) { 26953 p.next.prev = p.prev; 26954 p.prev.next = p.next; 26955 26956 if (p.prevZ) p.prevZ.nextZ = p.nextZ; 26957 if (p.nextZ) p.nextZ.prevZ = p.prevZ; 26958} 26959 26960function createNode(i, x, y) { 26961 return { 26962 i, // vertex index in coordinates array 26963 x, y, // vertex coordinates 26964 prev: null, // previous and next vertex nodes in a polygon ring 26965 next: null, 26966 z: 0, // z-order curve value 26967 prevZ: null, // previous and next nodes in z-order 26968 nextZ: null, 26969 steiner: false // indicates whether this is a steiner point 26970 }; 26971} 26972 26973function signedArea(data, start, end, dim) { 26974 let sum = 0; 26975 for (let i = start, j = end - dim; i < end; i += dim) { 26976 sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]); 26977 j = i; 26978 } 26979 return sum; 26980} 26981
vendor: 25,005 bytes, lines 26982-28082
26982class Earcut { 26983 26984 /** 26985 * Triangulates the given shape definition by returning an array of triangles. 26986 * 26987 * @param {Array<number>} data - An array with 2D points. 26988 * @param {Array<number>} holeIndices - An array with indices defining holes. 26989 * @param {number} [dim=2] - The number of coordinates per vertex in the input array. 26990 * @return {Array<number>} An array representing the triangulated faces. Each face is defined by three consecutive numbers 26991 * representing vertex indices. 26992 */ 26993 static triangulate( data, holeIndices, dim = 2 ) { 26994 26995 return earcut( data, holeIndices, dim ); 26996 26997 } 26998 26999} 27000 27001/** 27002 * A class containing utility functions for shapes. 27003 * 27004 * @hideconstructor 27005 */ 27006class ShapeUtils { 27007 27008 /** 27009 * Calculate area of a ( 2D ) contour polygon. 27010 * 27011 * @param {Array<Vector2>} contour - An array of 2D points. 27012 * @return {number} The area. 27013 */ 27014 static area( contour ) { 27015 27016 const n = contour.length; 27017 let a = 0.0; 27018 27019 for ( let p = n - 1, q = 0; q < n; p = q ++ ) { 27020 27021 a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; 27022 27023 } 27024 27025 return a * 0.5; 27026 27027 } 27028 27029 /** 27030 * Returns `true` if the given contour uses a clockwise winding order. 27031 * 27032 * @param {Array<Vector2>} pts - An array of 2D points defining a polygon. 27033 * @return {boolean} Whether the given contour uses a clockwise winding order or not. 27034 */ 27035 static isClockWise( pts ) { 27036 27037 return ShapeUtils.area( pts ) < 0; 27038 27039 } 27040 27041 /** 27042 * Triangulates the given shape definition. 27043 * 27044 * @param {Array<Vector2>} contour - An array of 2D points defining the contour. 27045 * @param {Array<Array<Vector2>>} holes - An array that holds arrays of 2D points defining the holes. 27046 * @return {Array<Array<number>>} An array that holds for each face definition an array with three indices. 27047 */ 27048 static triangulateShape( contour, holes ) { 27049 27050 const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ] 27051 const holeIndices = []; // array of hole indices 27052 const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ] 27053 27054 removeDupEndPts( contour ); 27055 addContour( vertices, contour ); 27056 27057 // 27058 27059 let holeIndex = contour.length; 27060 27061 holes.forEach( removeDupEndPts ); 27062 27063 for ( let i = 0; i < holes.length; i ++ ) { 27064 27065 holeIndices.push( holeIndex ); 27066 holeIndex += holes[ i ].length; 27067 addContour( vertices, holes[ i ] ); 27068 27069 } 27070 27071 // 27072 27073 const triangles = Earcut.triangulate( vertices, holeIndices ); 27074 27075 // 27076 27077 for ( let i = 0; i < triangles.length; i += 3 ) { 27078 27079 faces.push( triangles.slice( i, i + 3 ) ); 27080 27081 } 27082 27083 return faces; 27084 27085 } 27086 27087} 27088 27089function removeDupEndPts( points ) { 27090 27091 const l = points.length; 27092 27093 if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) { 27094 27095 points.pop(); 27096 27097 } 27098 27099} 27100 27101function addContour( vertices, contour ) { 27102 27103 for ( let i = 0; i < contour.length; i ++ ) { 27104 27105 vertices.push( contour[ i ].x ); 27106 vertices.push( contour[ i ].y ); 27107 27108 } 27109 27110} 27111 27112/** 27113 * Creates extruded geometry from a path shape. 27114 * 27115 * ```js 27116 * const length = 12, width = 8; 27117 * 27118 * const shape = new THREE.Shape(); 27119 * shape.moveTo( 0,0 ); 27120 * shape.lineTo( 0, width ); 27121 * shape.lineTo( length, width ); 27122 * shape.lineTo( length, 0 ); 27123 * shape.lineTo( 0, 0 ); 27124 * 27125 * const geometry = new THREE.ExtrudeGeometry( shape ); 27126 * const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); 27127 * const mesh = new THREE.Mesh( geometry, material ) ; 27128 * scene.add( mesh ); 27129 * ``` 27130 * 27131 * @augments BufferGeometry 27132 */ 27133class ExtrudeGeometry extends BufferGeometry { 27134 27135 /** 27136 * Constructs a new extrude geometry. 27137 * 27138 * @param {Shape|Array<Shape>} [shapes] - A shape or an array of shapes. 27139 * @param {ExtrudeGeometry~Options} [options] - The extrude settings. 27140 */ 27141 constructor( shapes = new Shape( [ new Vector2( 0.5, 0.5 ), new Vector2( -0.5, 0.5 ), new Vector2( -0.5, -0.5 ), new Vector2( 0.5, -0.5 ) ] ), options = {} ) { 27142 27143 super(); 27144 27145 this.type = 'ExtrudeGeometry'; 27146 27147 /** 27148 * Holds the constructor parameters that have been 27149 * used to generate the geometry. Any modification 27150 * after instantiation does not change the geometry. 27151 * 27152 * @type {Object} 27153 */ 27154 this.parameters = { 27155 shapes: shapes, 27156 options: options 27157 }; 27158 27159 shapes = Array.isArray( shapes ) ? shapes : [ shapes ]; 27160 27161 const scope = this; 27162 27163 const verticesArray = []; 27164 const uvArray = []; 27165 27166 for ( let i = 0, l = shapes.length; i < l; i ++ ) { 27167 27168 const shape = shapes[ i ]; 27169 addShape( shape ); 27170 27171 } 27172 27173 // build geometry 27174 27175 this.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) ); 27176 this.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) ); 27177 27178 this.computeVertexNormals(); 27179 27180 // functions 27181 27182 function addShape( shape ) { 27183 27184 const placeholder = []; 27185 27186 // options 27187 27188 const curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; 27189 const steps = options.steps !== undefined ? options.steps : 1; 27190 const depth = options.depth !== undefined ? options.depth : 1; 27191 27192 let bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; 27193 let bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 0.2; 27194 let bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 0.1; 27195 let bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0; 27196 let bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; 27197 27198 const extrudePath = options.extrudePath; 27199 27200 const uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator; 27201 27202 // 27203 27204 let extrudePts, extrudeByPath = false; 27205 let splineTube, binormal, normal, position2; 27206 27207 if ( extrudePath ) { 27208 27209 extrudePts = extrudePath.getSpacedPoints( steps ); 27210 27211 extrudeByPath = true; 27212 bevelEnabled = false; // bevels not supported for path extrusion 27213 27214 // SETUP TNB variables 27215 27216 // TODO1 - have a .isClosed in spline? 27217 27218 splineTube = extrudePath.computeFrenetFrames( steps, false ); 27219 27220 // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); 27221 27222 binormal = new Vector3(); 27223 normal = new Vector3(); 27224 position2 = new Vector3(); 27225 27226 } 27227 27228 // Safeguards if bevels are not enabled 27229 27230 if ( ! bevelEnabled ) { 27231 27232 bevelSegments = 0; 27233 bevelThickness = 0; 27234 bevelSize = 0; 27235 bevelOffset = 0; 27236 27237 } 27238 27239 // Variables initialization 27240 27241 const shapePoints = shape.extractPoints( curveSegments ); 27242 27243 let vertices = shapePoints.shape; 27244 const holes = shapePoints.holes; 27245 27246 const reverse = ! ShapeUtils.isClockWise( vertices ); 27247 27248 if ( reverse ) { 27249 27250 vertices = vertices.reverse(); 27251 27252 // Maybe we should also check if holes are in the opposite direction, just to be safe ... 27253 27254 for ( let h = 0, hl = holes.length; h < hl; h ++ ) { 27255 27256 const ahole = holes[ h ]; 27257 27258 if ( ShapeUtils.isClockWise( ahole ) ) { 27259 27260 holes[ h ] = ahole.reverse(); 27261 27262 } 27263 27264 } 27265 27266 } 27267 27268 /**Merges index-adjacent points that are within a threshold distance of each other. Array is modified in-place. Threshold distance is empirical, and scaled based on the magnitude of point coordinates. 27269 * @param {Array<Vector2>} points 27270 */ 27271 function mergeOverlappingPoints( points ) { 27272 27273 const THRESHOLD = 1e-10; 27274 const THRESHOLD_SQ = THRESHOLD * THRESHOLD; 27275 let prevPos = points[ 0 ]; 27276 for ( let i = 1; i <= points.length; i ++ ) { 27277 27278 const currentIndex = i % points.length; 27279 const currentPos = points[ currentIndex ]; 27280 const dx = currentPos.x - prevPos.x; 27281 const dy = currentPos.y - prevPos.y; 27282 const distSq = dx * dx + dy * dy; 27283 27284 const scalingFactorSqrt = Math.max( 27285 Math.abs( currentPos.x ), 27286 Math.abs( currentPos.y ), 27287 Math.abs( prevPos.x ), 27288 Math.abs( prevPos.y ) 27289 ); 27290 const thesholdSqScaled = THRESHOLD_SQ * scalingFactorSqrt * scalingFactorSqrt; 27291 if ( distSq <= thesholdSqScaled ) { 27292 27293 points.splice( currentIndex, 1 ); 27294 i --; 27295 continue; 27296 27297 } 27298 27299 prevPos = currentPos; 27300 27301 } 27302 27303 } 27304 27305 mergeOverlappingPoints( vertices ); 27306 holes.forEach( mergeOverlappingPoints ); 27307 27308 const numHoles = holes.length; 27309 27310 /* Vertices */ 27311 27312 const contour = vertices; // vertices has all points but contour has only points of circumference 27313 27314 for ( let h = 0; h < numHoles; h ++ ) { 27315 27316 const ahole = holes[ h ]; 27317 27318 vertices = vertices.concat( ahole ); 27319 27320 } 27321 27322 27323 function scalePt2( pt, vec, size ) { 27324 27325 if ( ! vec ) console.error( 'THREE.ExtrudeGeometry: vec does not exist' ); 27326 27327 return pt.clone().addScaledVector( vec, size ); 27328 27329 } 27330 27331 const vlen = vertices.length; 27332 27333 27334 // Find directions for point movement 27335 27336 27337 function getBevelVec( inPt, inPrev, inNext ) { 27338 27339 // computes for inPt the corresponding point inPt' on a new contour 27340 // shifted by 1 unit (length of normalized vector) to the left 27341 // if we walk along contour clockwise, this new contour is outside the old one 27342 // 27343 // inPt' is the intersection of the two lines parallel to the two 27344 // adjacent edges of inPt at a distance of 1 unit on the left side. 27345 27346 let v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt 27347 27348 // good reading for geometry algorithms (here: line-line intersection) 27349 // http://geomalgorithms.com/a05-_intersect-1.html 27350 27351 const v_prev_x = inPt.x - inPrev.x, 27352 v_prev_y = inPt.y - inPrev.y; 27353 const v_next_x = inNext.x - inPt.x, 27354 v_next_y = inNext.y - inPt.y; 27355 27356 const v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); 27357 27358 // check for collinear edges 27359 const collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); 27360 27361 if ( Math.abs( collinear0 ) > Number.EPSILON ) { 27362 27363 // not collinear 27364 27365 // length of vectors for normalizing 27366 27367 const v_prev_len = Math.sqrt( v_prev_lensq ); 27368 const v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y ); 27369 27370 // shift adjacent points by unit vectors to the left 27371 27372 const ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); 27373 const ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); 27374 27375 const ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); 27376 const ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); 27377 27378 // scaling factor for v_prev to intersection point 27379 27380 const sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - 27381 ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / 27382 ( v_prev_x * v_next_y - v_prev_y * v_next_x ); 27383 27384 // vector from inPt to intersection point 27385 27386 v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); 27387 v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); 27388 27389 // Don't normalize!, otherwise sharp corners become ugly 27390 // but prevent crazy spikes 27391 const v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ); 27392 if ( v_trans_lensq <= 2 ) { 27393 27394 return new Vector2( v_trans_x, v_trans_y ); 27395 27396 } else { 27397 27398 shrink_by = Math.sqrt( v_trans_lensq / 2 ); 27399 27400 } 27401 27402 } else { 27403 27404 // handle special case of collinear edges 27405 27406 let direction_eq = false; // assumes: opposite 27407 27408 if ( v_prev_x > Number.EPSILON ) { 27409 27410 if ( v_next_x > Number.EPSILON ) { 27411 27412 direction_eq = true; 27413 27414 } 27415 27416 } else { 27417 27418 if ( v_prev_x < - Number.EPSILON ) { 27419 27420 if ( v_next_x < - Number.EPSILON ) { 27421 27422 direction_eq = true; 27423 27424 } 27425 27426 } else { 27427 27428 if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) { 27429 27430 direction_eq = true; 27431 27432 } 27433 27434 } 27435 27436 } 27437 27438 if ( direction_eq ) { 27439 27440 // console.log("Warning: lines are a straight sequence"); 27441 v_trans_x = - v_prev_y; 27442 v_trans_y = v_prev_x; 27443 shrink_by = Math.sqrt( v_prev_lensq ); 27444 27445 } else { 27446 27447 // console.log("Warning: lines are a straight spike"); 27448 v_trans_x = v_prev_x; 27449 v_trans_y = v_prev_y; 27450 shrink_by = Math.sqrt( v_prev_lensq / 2 ); 27451 27452 } 27453 27454 } 27455 27456 return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); 27457 27458 } 27459 27460 27461 const contourMovements = []; 27462 27463 for ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { 27464 27465 if ( j === il ) j = 0; 27466 if ( k === il ) k = 0; 27467 27468 // (j)---(i)---(k) 27469 // console.log('i,j,k', i, j , k) 27470 27471 contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); 27472 27473 } 27474 27475 const holesMovements = []; 27476 let oneHoleMovements, verticesMovements = contourMovements.concat(); 27477 27478 for ( let h = 0, hl = numHoles; h < hl; h ++ ) { 27479 27480 const ahole = holes[ h ]; 27481 27482 oneHoleMovements = []; 27483 27484 for ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { 27485 27486 if ( j === il ) j = 0; 27487 if ( k === il ) k = 0; 27488 27489 // (j)---(i)---(k) 27490 oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); 27491 27492 } 27493 27494 holesMovements.push( oneHoleMovements ); 27495 verticesMovements = verticesMovements.concat( oneHoleMovements ); 27496 27497 } 27498 27499 const contractedContourVertices = []; 27500 const expandedHoleVertices = []; 27501 27502 // Loop bevelSegments, 1 for the front, 1 for the back 27503 27504 for ( let b = 0; b < bevelSegments; b ++ ) { 27505 27506 //for ( b = bevelSegments; b > 0; b -- ) { 27507 27508 const t = b / bevelSegments; 27509 const z = bevelThickness * Math.cos( t * Math.PI / 2 ); 27510 const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset; 27511 27512 // contract shape 27513 27514 for ( let i = 0, il = contour.length; i < il; i ++ ) { 27515 27516 const vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); 27517 27518 v( vert.x, vert.y, - z ); 27519 if ( t == 0 ) contractedContourVertices.push( vert ); 27520 27521 } 27522 27523 // expand holes 27524 27525 for ( let h = 0, hl = numHoles; h < hl; h ++ ) { 27526 27527 const ahole = holes[ h ]; 27528 oneHoleMovements = holesMovements[ h ]; 27529 const oneHoleVertices = []; 27530 for ( let i = 0, il = ahole.length; i < il; i ++ ) { 27531 27532 const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); 27533 27534 v( vert.x, vert.y, - z ); 27535 if ( t == 0 ) oneHoleVertices.push( vert ); 27536 27537 } 27538 27539 if ( t == 0 ) expandedHoleVertices.push( oneHoleVertices ); 27540 27541 } 27542 27543 } 27544 27545 const faces = ShapeUtils.triangulateShape( contractedContourVertices, expandedHoleVertices ); 27546 27547 const flen = faces.length; 27548 27549 const bs = bevelSize + bevelOffset; 27550 27551 // Back facing vertices 27552 27553 for ( let i = 0; i < vlen; i ++ ) { 27554 27555 const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; 27556 27557 if ( ! extrudeByPath ) { 27558 27559 v( vert.x, vert.y, 0 ); 27560 27561 } else { 27562 27563 // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); 27564 27565 normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x ); 27566 binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y ); 27567 27568 position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal ); 27569 27570 v( position2.x, position2.y, position2.z ); 27571 27572 } 27573 27574 } 27575 27576 // Add stepped vertices... 27577 // Including front facing vertices 27578 27579 for ( let s = 1; s <= steps; s ++ ) { 27580 27581 for ( let i = 0; i < vlen; i ++ ) { 27582 27583 const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; 27584 27585 if ( ! extrudeByPath ) { 27586 27587 v( vert.x, vert.y, depth / steps * s ); 27588 27589 } else { 27590 27591 // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); 27592 27593 normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x ); 27594 binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y ); 27595 27596 position2.copy( extrudePts[ s ] ).add( normal ).add( binormal ); 27597 27598 v( position2.x, position2.y, position2.z ); 27599 27600 } 27601 27602 } 27603 27604 } 27605 27606 27607 // Add bevel segments planes 27608 27609 //for ( b = 1; b <= bevelSegments; b ++ ) { 27610 for ( let b = bevelSegments - 1; b >= 0; b -- ) { 27611 27612 const t = b / bevelSegments; 27613 const z = bevelThickness * Math.cos( t * Math.PI / 2 ); 27614 const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset; 27615 27616 // contract shape 27617 27618 for ( let i = 0, il = contour.length; i < il; i ++ ) { 27619 27620 const vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); 27621 v( vert.x, vert.y, depth + z ); 27622 27623 } 27624 27625 // expand holes 27626 27627 for ( let h = 0, hl = holes.length; h < hl; h ++ ) { 27628 27629 const ahole = holes[ h ]; 27630 oneHoleMovements = holesMovements[ h ]; 27631 27632 for ( let i = 0, il = ahole.length; i < il; i ++ ) { 27633 27634 const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); 27635 27636 if ( ! extrudeByPath ) { 27637 27638 v( vert.x, vert.y, depth + z ); 27639 27640 } else { 27641 27642 v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); 27643 27644 } 27645 27646 } 27647 27648 } 27649 27650 } 27651 27652 /* Faces */ 27653 27654 // Top and bottom faces 27655 27656 buildLidFaces(); 27657 27658 // Sides faces 27659 27660 buildSideFaces(); 27661 27662 27663 ///// Internal functions 27664 27665 function buildLidFaces() { 27666 27667 const start = verticesArray.length / 3; 27668 27669 if ( bevelEnabled ) { 27670 27671 let layer = 0; // steps + 1 27672 let offset = vlen * layer; 27673 27674 // Bottom faces 27675 27676 for ( let i = 0; i < flen; i ++ ) { 27677 27678 const face = faces[ i ]; 27679 f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); 27680 27681 } 27682 27683 layer = steps + bevelSegments * 2; 27684 offset = vlen * layer; 27685 27686 // Top faces 27687 27688 for ( let i = 0; i < flen; i ++ ) { 27689 27690 const face = faces[ i ]; 27691 f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset ); 27692 27693 } 27694 27695 } else { 27696 27697 // Bottom faces 27698 27699 for ( let i = 0; i < flen; i ++ ) { 27700 27701 const face = faces[ i ]; 27702 f3( face[ 2 ], face[ 1 ], face[ 0 ] ); 27703 27704 } 27705 27706 // Top faces 27707 27708 for ( let i = 0; i < flen; i ++ ) { 27709 27710 const face = faces[ i ]; 27711 f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps ); 27712 27713 } 27714 27715 } 27716 27717 scope.addGroup( start, verticesArray.length / 3 - start, 0 ); 27718 27719 } 27720 27721 // Create faces for the z-sides of the shape 27722 27723 function buildSideFaces() { 27724 27725 const start = verticesArray.length / 3; 27726 let layeroffset = 0; 27727 sidewalls( contour, layeroffset ); 27728 layeroffset += contour.length; 27729 27730 for ( let h = 0, hl = holes.length; h < hl; h ++ ) { 27731 27732 const ahole = holes[ h ]; 27733 sidewalls( ahole, layeroffset ); 27734 27735 //, true 27736 layeroffset += ahole.length; 27737 27738 } 27739 27740 27741 scope.addGroup( start, verticesArray.length / 3 - start, 1 ); 27742 27743 27744 } 27745 27746 function sidewalls( contour, layeroffset ) { 27747 27748 let i = contour.length; 27749 27750 while ( -- i >= 0 ) { 27751 27752 const j = i; 27753 let k = i - 1; 27754 if ( k < 0 ) k = contour.length - 1; 27755 27756 //console.log('b', i,j, i-1, k,vertices.length); 27757 27758 for ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) { 27759 27760 const slen1 = vlen * s; 27761 const slen2 = vlen * ( s + 1 ); 27762 27763 const a = layeroffset + j + slen1, 27764 b = layeroffset + k + slen1, 27765 c = layeroffset + k + slen2, 27766 d = layeroffset + j + slen2; 27767 27768 f4( a, b, c, d ); 27769 27770 } 27771 27772 } 27773 27774 } 27775 27776 function v( x, y, z ) { 27777 27778 placeholder.push( x ); 27779 placeholder.push( y ); 27780 placeholder.push( z ); 27781 27782 } 27783 27784 27785 function f3( a, b, c ) { 27786 27787 addVertex( a ); 27788 addVertex( b ); 27789 addVertex( c ); 27790 27791 const nextIndex = verticesArray.length / 3; 27792 const uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); 27793 27794 addUV( uvs[ 0 ] ); 27795 addUV( uvs[ 1 ] ); 27796 addUV( uvs[ 2 ] ); 27797 27798 } 27799 27800 function f4( a, b, c, d ) { 27801 27802 addVertex( a ); 27803 addVertex( b ); 27804 addVertex( d ); 27805 27806 addVertex( b ); 27807 addVertex( c ); 27808 addVertex( d ); 27809 27810 27811 const nextIndex = verticesArray.length / 3; 27812 const uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); 27813 27814 addUV( uvs[ 0 ] ); 27815 addUV( uvs[ 1 ] ); 27816 addUV( uvs[ 3 ] ); 27817 27818 addUV( uvs[ 1 ] ); 27819 addUV( uvs[ 2 ] ); 27820 addUV( uvs[ 3 ] ); 27821 27822 } 27823 27824 function addVertex( index ) { 27825 27826 verticesArray.push( placeholder[ index * 3 + 0 ] ); 27827 verticesArray.push( placeholder[ index * 3 + 1 ] ); 27828 verticesArray.push( placeholder[ index * 3 + 2 ] ); 27829 27830 } 27831 27832 27833 function addUV( vector2 ) { 27834 27835 uvArray.push( vector2.x ); 27836 uvArray.push( vector2.y ); 27837 27838 } 27839 27840 } 27841 27842 } 27843 27844 copy( source ) { 27845 27846 super.copy( source ); 27847 27848 this.parameters = Object.assign( {}, source.parameters ); 27849 27850 return this; 27851 27852 } 27853 27854 toJSON() { 27855 27856 const data = super.toJSON(); 27857 27858 const shapes = this.parameters.shapes; 27859 const options = this.parameters.options; 27860 27861 return toJSON$1( shapes, options, data ); 27862 27863 } 27864 27865 /** 27866 * Factory method for creating an instance of this class from the given 27867 * JSON object. 27868 * 27869 * @param {Object} data - A JSON object representing the serialized geometry. 27870 * @param {Array<Shape>} shapes - An array of shapes. 27871 * @return {ExtrudeGeometry} A new instance. 27872 */ 27873 static fromJSON( data, shapes ) { 27874 27875 const geometryShapes = []; 27876 27877 for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) { 27878 27879 const shape = shapes[ data.shapes[ j ] ]; 27880 27881 geometryShapes.push( shape ); 27882 27883 } 27884 27885 const extrudePath = data.options.extrudePath; 27886 27887 if ( extrudePath !== undefined ) { 27888 27889 data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath ); 27890 27891 } 27892 27893 return new ExtrudeGeometry( geometryShapes, data.options ); 27894 27895 } 27896 27897} 27898 27899const WorldUVGenerator = { 27900 27901 generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) { 27902 27903 const a_x = vertices[ indexA * 3 ]; 27904 const a_y = vertices[ indexA * 3 + 1 ]; 27905 const b_x = vertices[ indexB * 3 ]; 27906 const b_y = vertices[ indexB * 3 + 1 ]; 27907 const c_x = vertices[ indexC * 3 ]; 27908 const c_y = vertices[ indexC * 3 + 1 ]; 27909 27910 return [ 27911 new Vector2( a_x, a_y ), 27912 new Vector2( b_x, b_y ), 27913 new Vector2( c_x, c_y ) 27914 ]; 27915 27916 }, 27917 27918 generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) { 27919 27920 const a_x = vertices[ indexA * 3 ]; 27921 const a_y = vertices[ indexA * 3 + 1 ]; 27922 const a_z = vertices[ indexA * 3 + 2 ]; 27923 const b_x = vertices[ indexB * 3 ]; 27924 const b_y = vertices[ indexB * 3 + 1 ]; 27925 const b_z = vertices[ indexB * 3 + 2 ]; 27926 const c_x = vertices[ indexC * 3 ]; 27927 const c_y = vertices[ indexC * 3 + 1 ]; 27928 const c_z = vertices[ indexC * 3 + 2 ]; 27929 const d_x = vertices[ indexD * 3 ]; 27930 const d_y = vertices[ indexD * 3 + 1 ]; 27931 const d_z = vertices[ indexD * 3 + 2 ]; 27932 27933 if ( Math.abs( a_y - b_y ) < Math.abs( a_x - b_x ) ) { 27934 27935 return [ 27936 new Vector2( a_x, 1 - a_z ), 27937 new Vector2( b_x, 1 - b_z ), 27938 new Vector2( c_x, 1 - c_z ), 27939 new Vector2( d_x, 1 - d_z ) 27940 ]; 27941 27942 } else { 27943 27944 return [ 27945 new Vector2( a_y, 1 - a_z ), 27946 new Vector2( b_y, 1 - b_z ), 27947 new Vector2( c_y, 1 - c_z ), 27948 new Vector2( d_y, 1 - d_z ) 27949 ]; 27950 27951 } 27952 27953 } 27954 27955}; 27956 27957function toJSON$1( shapes, options, data ) { 27958 27959 data.shapes = []; 27960 27961 if ( Array.isArray( shapes ) ) { 27962 27963 for ( let i = 0, l = shapes.length; i < l; i ++ ) { 27964 27965 const shape = shapes[ i ]; 27966 27967 data.shapes.push( shape.uuid ); 27968 27969 } 27970 27971 } else { 27972 27973 data.shapes.push( shapes.uuid ); 27974 27975 } 27976 27977 data.options = Object.assign( {}, options ); 27978 27979 if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON(); 27980 27981 return data; 27982 27983} 27984 27985/** 27986 * A geometry class for representing a plane. 27987 * 27988 * ```js 27989 * const geometry = new THREE.PlaneGeometry( 1, 1 ); 27990 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00, side: THREE.DoubleSide } ); 27991 * const plane = new THREE.Mesh( geometry, material ); 27992 * scene.add( plane ); 27993 * ``` 27994 * 27995 * @augments BufferGeometry 27996 */ 27997class PlaneGeometry extends BufferGeometry { 27998 27999 /** 28000 * Constructs a new plane geometry. 28001 * 28002 * @param {number} [width=1] - The width along the X axis. 28003 * @param {number} [height=1] - The height along the Y axis 28004 * @param {number} [widthSegments=1] - The number of segments along the X axis. 28005 * @param {number} [heightSegments=1] - The number of segments along the Y axis. 28006 */ 28007 constructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) { 28008 28009 super(); 28010 28011 this.type = 'PlaneGeometry'; 28012 28013 /** 28014 * Holds the constructor parameters that have been 28015 * used to generate the geometry. Any modification 28016 * after instantiation does not change the geometry. 28017 * 28018 * @type {Object} 28019 */ 28020 this.parameters = { 28021 width: width, 28022 height: height, 28023 widthSegments: widthSegments, 28024 heightSegments: heightSegments 28025 }; 28026 28027 const width_half = width / 2; 28028 const height_half = height / 2; 28029 28030 const gridX = Math.floor( widthSegments ); 28031 const gridY = Math.floor( heightSegments ); 28032 28033 const gridX1 = gridX + 1; 28034 const gridY1 = gridY + 1; 28035 28036 const segment_width = width / gridX; 28037 const segment_height = height / gridY; 28038 28039 // 28040 28041 const indices = []; 28042 const vertices = []; 28043 const normals = []; 28044 const uvs = []; 28045 28046 for ( let iy = 0; iy < gridY1; iy ++ ) { 28047 28048 const y = iy * segment_height - height_half; 28049 28050 for ( let ix = 0; ix < gridX1; ix ++ ) { 28051 28052 const x = ix * segment_width - width_half; 28053 28054 vertices.push( x, - y, 0 ); 28055 28056 normals.push( 0, 0, 1 ); 28057 28058 uvs.push( ix / gridX ); 28059 uvs.push( 1 - ( iy / gridY ) ); 28060 28061 } 28062 28063 } 28064 28065 for ( let iy = 0; iy < gridY; iy ++ ) { 28066 28067 for ( let ix = 0; ix < gridX; ix ++ ) { 28068 28069 const a = ix + gridX1 * iy; 28070 const b = ix + gridX1 * ( iy + 1 ); 28071 const c = ( ix + 1 ) + gridX1 * ( iy + 1 ); 28072 const d = ( ix + 1 ) + gridX1 * iy; 28073 28074 indices.push( a, b, d ); 28075 indices.push( b, c, d ); 28076 28077 } 28078 28079 } 28080 28081 this.setIndex( indices ); 28082 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
vendor: 4,215 bytes, lines 28083-28251
28083 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 28084 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 28085 28086 } 28087 28088 copy( source ) { 28089 28090 super.copy( source ); 28091 28092 this.parameters = Object.assign( {}, source.parameters ); 28093 28094 return this; 28095 28096 } 28097 28098 /** 28099 * Factory method for creating an instance of this class from the given 28100 * JSON object. 28101 * 28102 * @param {Object} data - A JSON object representing the serialized geometry. 28103 * @return {PlaneGeometry} A new instance. 28104 */ 28105 static fromJSON( data ) { 28106 28107 return new PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments ); 28108 28109 } 28110 28111} 28112 28113/** 28114 * A class for generating a sphere geometry. 28115 * 28116 * ```js 28117 * const geometry = new THREE.SphereGeometry( 15, 32, 16 ); 28118 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); 28119 * const sphere = new THREE.Mesh( geometry, material ); 28120 * scene.add( sphere ); 28121 * ``` 28122 * 28123 * @augments BufferGeometry 28124 */ 28125class SphereGeometry extends BufferGeometry { 28126 28127 /** 28128 * Constructs a new sphere geometry. 28129 * 28130 * @param {number} [radius=1] - The sphere radius. 28131 * @param {number} [widthSegments=32] - The number of horizontal segments. Minimum value is `3`. 28132 * @param {number} [heightSegments=16] - The number of vertical segments. Minimum value is `2`. 28133 * @param {number} [phiStart=0] - The horizontal starting angle in radians. 28134 * @param {number} [phiLength=Math.PI*2] - The horizontal sweep angle size. 28135 * @param {number} [thetaStart=0] - The vertical starting angle in radians. 28136 * @param {number} [thetaLength=Math.PI] - The vertical sweep angle size. 28137 */ 28138 constructor( radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) { 28139 28140 super(); 28141 28142 this.type = 'SphereGeometry'; 28143 28144 /** 28145 * Holds the constructor parameters that have been 28146 * used to generate the geometry. Any modification 28147 * after instantiation does not change the geometry. 28148 * 28149 * @type {Object} 28150 */ 28151 this.parameters = { 28152 radius: radius, 28153 widthSegments: widthSegments, 28154 heightSegments: heightSegments, 28155 phiStart: phiStart, 28156 phiLength: phiLength, 28157 thetaStart: thetaStart, 28158 thetaLength: thetaLength 28159 }; 28160 28161 widthSegments = Math.max( 3, Math.floor( widthSegments ) ); 28162 heightSegments = Math.max( 2, Math.floor( heightSegments ) ); 28163 28164 const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI ); 28165 28166 let index = 0; 28167 const grid = []; 28168 28169 const vertex = new Vector3(); 28170 const normal = new Vector3(); 28171 28172 // buffers 28173 28174 const indices = []; 28175 const vertices = []; 28176 const normals = []; 28177 const uvs = []; 28178 28179 // generate vertices, normals and uvs 28180 28181 for ( let iy = 0; iy <= heightSegments; iy ++ ) { 28182 28183 const verticesRow = []; 28184 28185 const v = iy / heightSegments; 28186 28187 // special case for the poles 28188 28189 let uOffset = 0; 28190 28191 if ( iy === 0 && thetaStart === 0 ) { 28192 28193 uOffset = 0.5 / widthSegments; 28194 28195 } else if ( iy === heightSegments && thetaEnd === Math.PI ) { 28196 28197 uOffset = -0.5 / widthSegments; 28198 28199 } 28200 28201 for ( let ix = 0; ix <= widthSegments; ix ++ ) { 28202 28203 const u = ix / widthSegments; 28204 28205 // vertex 28206 28207 vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); 28208 vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); 28209 vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); 28210 28211 vertices.push( vertex.x, vertex.y, vertex.z ); 28212 28213 // normal 28214 28215 normal.copy( vertex ).normalize(); 28216 normals.push( normal.x, normal.y, normal.z ); 28217 28218 // uv 28219 28220 uvs.push( u + uOffset, 1 - v ); 28221 28222 verticesRow.push( index ++ ); 28223 28224 } 28225 28226 grid.push( verticesRow ); 28227 28228 } 28229 28230 // indices 28231 28232 for ( let iy = 0; iy < heightSegments; iy ++ ) { 28233 28234 for ( let ix = 0; ix < widthSegments; ix ++ ) { 28235 28236 const a = grid[ iy ][ ix + 1 ]; 28237 const b = grid[ iy ][ ix ]; 28238 const c = grid[ iy + 1 ][ ix ]; 28239 const d = grid[ iy + 1 ][ ix + 1 ]; 28240 28241 if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d ); 28242 if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d ); 28243 28244 } 28245 28246 } 28247 28248 // build geometry 28249 28250 this.setIndex( indices ); 28251 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
vendor: 4,237 bytes, lines 28252-28443
28252 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 28253 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 28254 28255 } 28256 28257 copy( source ) { 28258 28259 super.copy( source ); 28260 28261 this.parameters = Object.assign( {}, source.parameters ); 28262 28263 return this; 28264 28265 } 28266 28267 /** 28268 * Factory method for creating an instance of this class from the given 28269 * JSON object. 28270 * 28271 * @param {Object} data - A JSON object representing the serialized geometry. 28272 * @return {SphereGeometry} A new instance. 28273 */ 28274 static fromJSON( data ) { 28275 28276 return new SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength ); 28277 28278 } 28279 28280} 28281 28282/** 28283 * Can be used as a helper object to visualize a geometry as a wireframe. 28284 * 28285 * ```js 28286 * const geometry = new THREE.SphereGeometry(); 28287 * 28288 * const wireframe = new THREE.WireframeGeometry( geometry ); 28289 * 28290 * const line = new THREE.LineSegments( wireframe ); 28291 * line.material.depthWrite = false; 28292 * line.material.opacity = 0.25; 28293 * line.material.transparent = true; 28294 * 28295 * scene.add( line ); 28296 * ``` 28297 * 28298 * Note: It is not yet possible to serialize/deserialize instances of this class. 28299 * 28300 * @augments BufferGeometry 28301 */ 28302class WireframeGeometry extends BufferGeometry { 28303 28304 /** 28305 * Constructs a new wireframe geometry. 28306 * 28307 * @param {?BufferGeometry} [geometry=null] - The geometry. 28308 */ 28309 constructor( geometry = null ) { 28310 28311 super(); 28312 28313 this.type = 'WireframeGeometry'; 28314 28315 /** 28316 * Holds the constructor parameters that have been 28317 * used to generate the geometry. Any modification 28318 * after instantiation does not change the geometry. 28319 * 28320 * @type {Object} 28321 */ 28322 this.parameters = { 28323 geometry: geometry 28324 }; 28325 28326 if ( geometry !== null ) { 28327 28328 // buffer 28329 28330 const vertices = []; 28331 const edges = new Set(); 28332 28333 // helper variables 28334 28335 const start = new Vector3(); 28336 const end = new Vector3(); 28337 28338 if ( geometry.index !== null ) { 28339 28340 // indexed BufferGeometry 28341 28342 const position = geometry.attributes.position; 28343 const indices = geometry.index; 28344 let groups = geometry.groups; 28345 28346 if ( groups.length === 0 ) { 28347 28348 groups = [ { start: 0, count: indices.count, materialIndex: 0 } ]; 28349 28350 } 28351 28352 // create a data structure that contains all edges without duplicates 28353 28354 for ( let o = 0, ol = groups.length; o < ol; ++ o ) { 28355 28356 const group = groups[ o ]; 28357 28358 const groupStart = group.start; 28359 const groupCount = group.count; 28360 28361 for ( let i = groupStart, l = ( groupStart + groupCount ); i < l; i += 3 ) { 28362 28363 for ( let j = 0; j < 3; j ++ ) { 28364 28365 const index1 = indices.getX( i + j ); 28366 const index2 = indices.getX( i + ( j + 1 ) % 3 ); 28367 28368 start.fromBufferAttribute( position, index1 ); 28369 end.fromBufferAttribute( position, index2 ); 28370 28371 if ( isUniqueEdge( start, end, edges ) === true ) { 28372 28373 vertices.push( start.x, start.y, start.z ); 28374 vertices.push( end.x, end.y, end.z ); 28375 28376 } 28377 28378 } 28379 28380 } 28381 28382 } 28383 28384 } else { 28385 28386 // non-indexed BufferGeometry 28387 28388 const position = geometry.attributes.position; 28389 28390 for ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) { 28391 28392 for ( let j = 0; j < 3; j ++ ) { 28393 28394 // three edges per triangle, an edge is represented as (index1, index2) 28395 // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0) 28396 28397 const index1 = 3 * i + j; 28398 const index2 = 3 * i + ( ( j + 1 ) % 3 ); 28399 28400 start.fromBufferAttribute( position, index1 ); 28401 end.fromBufferAttribute( position, index2 ); 28402 28403 if ( isUniqueEdge( start, end, edges ) === true ) { 28404 28405 vertices.push( start.x, start.y, start.z ); 28406 vertices.push( end.x, end.y, end.z ); 28407 28408 } 28409 28410 } 28411 28412 } 28413 28414 } 28415 28416 // build geometry 28417 28418 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 28419 28420 } 28421 28422 } 28423 28424 copy( source ) { 28425 28426 super.copy( source ); 28427 28428 this.parameters = Object.assign( {}, source.parameters ); 28429 28430 return this; 28431 28432 } 28433 28434} 28435 28436function isUniqueEdge( start, end, edges ) { 28437 28438 const hash1 = `${start.x},${start.y},${start.z}-${end.x},${end.y},${end.z}`; 28439 const hash2 = `${end.x},${end.y},${end.z}-${start.x},${start.y},${start.z}`; // coincident edge 28440 28441 if ( edges.has( hash1 ) === true || edges.has( hash2 ) === true ) { 28442 28443 return false;
28444 28445 } else { 28446 28447 edges.add( hash1 ); 28448 edges.add( hash2 ); 28449 return true; 28450 28451 } 28452 28453} 28454 28455/** 28456 * A material for shiny surfaces with specular highlights. 28457 * 28458 * The material uses a non-physically based [Blinn-Phong]{@link https://en.wikipedia.org/wiki/Blinn-Phong_shading_model} 28459 * model for calculating reflectance. Unlike the Lambertian model used in the 28460 * {@link MeshLambertMaterial} this can simulate shiny surfaces with specular 28461 * highlights (such as varnished wood). `MeshPhongMaterial` uses per-fragment shading. 28462 * 28463 * Performance will generally be greater when using this material over the 28464 * {@link MeshStandardMaterial} or {@link MeshPhysicalMaterial}, at the cost of 28465 * some graphical accuracy. 28466 * 28467 * @augments Material 28468 */ 28469class MeshPhongMaterial extends Material { 28470 28471 /** 28472 * Constructs a new mesh phong material. 28473 * 28474 * @param {Object} [parameters] - An object with one or more properties 28475 * defining the material's appearance. Any property of the material 28476 * (including any property from inherited materials) can be passed 28477 * in here. Color values can be passed any type of value accepted 28478 * by {@link Color#set}. 28479 */ 28480 constructor( parameters ) { 28481 28482 super(); 28483 28484 /** 28485 * This flag can be used for type testing. 28486 * 28487 * @type {boolean} 28488 * @readonly 28489 * @default true 28490 */ 28491 this.isMeshPhongMaterial = true; 28492 28493 this.type = 'MeshPhongMaterial'; 28494 28495 /** 28496 * Color of the material. 28497 * 28498 * @type {Color} 28499 * @default (1,1,1) 28500 */ 28501 this.color = new Color( 0xffffff ); // diffuse 28502 28503 /** 28504 * Specular color of the material. The default color is set to `0x111111` (very dark grey) 28505 * 28506 * This defines how shiny the material is and the color of its shine. 28507 * 28508 * @type {Color} 28509 */ 28510 this.specular = new Color( 0x111111 ); 28511 28512 /** 28513 * How shiny the specular highlight is; a higher value gives a sharper highlight. 28514 * 28515 * @type {number} 28516 * @default 30 28517 */ 28518 this.shininess = 30; 28519 28520 /** 28521 * The color map. May optionally include an alpha channel, typically combined 28522 * with {@link Material#transparent} or {@link Material#alphaTest}. The texture map 28523 * color is modulated by the diffuse `color`. 28524 * 28525 * @type {?Texture} 28526 * @default null 28527 */ 28528 this.map = null; 28529 28530 /** 28531 * The light map. Requires a second set of UVs. 28532 * 28533 * @type {?Texture} 28534 * @default null 28535 */ 28536 this.lightMap = null; 28537 28538 /** 28539 * Intensity of the baked light. 28540 * 28541 * @type {number} 28542 * @default 1 28543 */ 28544 this.lightMapIntensity = 1.0; 28545 28546 /** 28547 * The red channel of this texture is used as the ambient occlusion map. 28548 * Requires a second set of UVs. 28549 * 28550 * @type {?Texture} 28551 * @default null 28552 */ 28553 this.aoMap = null; 28554 28555 /** 28556 * Intensity of the ambient occlusion effect. Range is `[0,1]`, where `0` 28557 * disables ambient occlusion. Where intensity is `1` and the AO map's 28558 * red channel is also `1`, ambient light is fully occluded on a surface. 28559 * 28560 * @type {number} 28561 * @default 1 28562 */ 28563 this.aoMapIntensity = 1.0; 28564 28565 /** 28566 * Emissive (light) color of the material, essentially a solid color 28567 * unaffected by other lighting. 28568 * 28569 * @type {Color} 28570 * @default (0,0,0) 28571 */ 28572 this.emissive = new Color( 0x000000 ); 28573 28574 /** 28575 * Intensity of the emissive light. Modulates the emissive color. 28576 * 28577 * @type {number} 28578 * @default 1 28579 */ 28580 this.emissiveIntensity = 1.0; 28581 28582 /** 28583 * Set emissive (glow) map. The emissive map color is modulated by the 28584 * emissive color and the emissive intensity. If you have an emissive map, 28585 * be sure to set the emissive color to something other than black. 28586 * 28587 * @type {?Texture} 28588 * @default null 28589 */ 28590 this.emissiveMap = null; 28591 28592 /** 28593 * The texture to create a bump map. The black and white values map to the 28594 * perceived depth in relation to the lights. Bump doesn't actually affect 28595 * the geometry of the object, only the lighting. If a normal map is defined 28596 * this will be ignored. 28597 * 28598 * @type {?Texture} 28599 * @default null 28600 */ 28601 this.bumpMap = null; 28602 28603 /** 28604 * How much the bump map affects the material. Typical range is `[0,1]`. 28605 * 28606 * @type {number} 28607 * @default 1 28608 */ 28609 this.bumpScale = 1; 28610 28611 /** 28612 * The texture to create a normal map. The RGB values affect the surface 28613 * normal for each pixel fragment and change the way the color is lit. Normal
28614 * maps do not change the actual shape of the surface, only the lighting. In 28615 * case the material has a normal map authored using the left handed 28616 * convention, the `y` component of `normalScale` should be negated to compensate 28617 * for the different handedness. 28618 * 28619 * @type {?Texture} 28620 * @default null 28621 */ 28622 this.normalMap = null; 28623 28624 /** 28625 * The type of normal map. 28626 * 28627 * @type {(TangentSpaceNormalMap|ObjectSpaceNormalMap)} 28628 * @default TangentSpaceNormalMap 28629 */ 28630 this.normalMapType = TangentSpaceNormalMap; 28631 28632 /** 28633 * How much the normal map affects the material. Typical value range is `[0,1]`. 28634 * 28635 * @type {Vector2} 28636 * @default (1,1) 28637 */ 28638 this.normalScale = new Vector2( 1, 1 ); 28639 28640 /** 28641 * The displacement map affects the position of the mesh's vertices. Unlike 28642 * other maps which only affect the light and shade of the material the 28643 * displaced vertices can cast shadows, block other objects, and otherwise 28644 * act as real geometry. The displacement texture is an image where the value 28645 * of each pixel (white being the highest) is mapped against, and 28646 * repositions, the vertices of the mesh. 28647 * 28648 * @type {?Texture} 28649 * @default null 28650 */ 28651 this.displacementMap = null; 28652 28653 /** 28654 * How much the displacement map affects the mesh (where black is no 28655 * displacement, and white is maximum displacement). Without a displacement 28656 * map set, this value is not applied. 28657 * 28658 * @type {number} 28659 * @default 0 28660 */ 28661 this.displacementScale = 1; 28662 28663 /** 28664 * The offset of the displacement map's values on the mesh's vertices. 28665 * The bias is added to the scaled sample of the displacement map. 28666 * Without a displacement map set, this value is not applied. 28667 * 28668 * @type {number} 28669 * @default 0 28670 */ 28671 this.displacementBias = 0; 28672 28673 /** 28674 * The specular map value affects both how much the specular surface 28675 * highlight contributes and how much of the environment map affects the 28676 * surface. 28677 * 28678 * @type {?Texture} 28679 * @default null 28680 */ 28681 this.specularMap = null; 28682 28683 /** 28684 * The alpha map is a grayscale texture that controls the opacity across the 28685 * surface (black: fully transparent; white: fully opaque). 28686 * 28687 * Only the color of the texture is used, ignoring the alpha channel if one 28688 * exists. For RGB and RGBA textures, the renderer will use the green channel 28689 * when sampling this texture due to the extra bit of precision provided for 28690 * green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and 28691 * luminance/alpha textures will also still work as expected. 28692 * 28693 * @type {?Texture} 28694 * @default null 28695 */ 28696 this.alphaMap = null; 28697 28698 /** 28699 * The environment map. 28700 * 28701 * @type {?Texture} 28702 * @default null 28703 */ 28704 this.envMap = null; 28705 28706 /** 28707 * The rotation of the environment map in radians. 28708 * 28709 * @type {Euler} 28710 * @default (0,0,0) 28711 */ 28712 this.envMapRotation = new Euler(); 28713 28714 /** 28715 * How to combine the result of the surface's color with the environment map, if any. 28716 * 28717 * When set to `MixOperation`, the {@link MeshBasicMaterial#reflectivity} is used to 28718 * blend between the two colors. 28719 * 28720 * @type {(MultiplyOperation|MixOperation|AddOperation)} 28721 * @default MultiplyOperation 28722 */ 28723 this.combine = MultiplyOperation; 28724 28725 /** 28726 * How much the environment map affects the surface. 28727 * The valid range is between `0` (no reflections) and `1` (full reflections). 28728 * 28729 * @type {number} 28730 * @default 1 28731 */ 28732 this.reflectivity = 1; 28733 28734 /** 28735 * The index of refraction (IOR) of air (approximately 1) divided by the 28736 * index of refraction of the material. It is used with environment mapping 28737 * modes {@link CubeRefractionMapping} and {@link EquirectangularRefractionMapping}. 28738 * The refraction ratio should not exceed `1`. 28739 * 28740 * @type {number} 28741 * @default 0.98 28742 */ 28743 this.refractionRatio = 0.98; 28744 28745 /** 28746 * Renders the geometry as a wireframe. 28747 * 28748 * @type {boolean} 28749 * @default false 28750 */ 28751 this.wireframe = false; 28752 28753 /** 28754 * Controls the thickness of the wireframe. 28755 * 28756 * Can only be used with {@link SVGRenderer}. 28757 * 28758 * @type {number} 28759 * @default 1 28760 */ 28761 this.wireframeLinewidth = 1; 28762 28763 /** 28764 * Defines appearance of wireframe ends. 28765 * 28766 * Can only be used with {@link SVGRenderer}. 28767 * 28768 * @type {('round'|'bevel'|'miter')} 28769 * @default 'round' 28770 */ 28771 this.wireframeLinecap = 'round'; 28772 28773 /** 28774 * Defines appearance of wireframe joints. 28775 * 28776 * Can only be used with {@link SVGRenderer}. 28777 * 28778 * @type {('round'|'bevel'|'miter')} 28779 * @default 'round' 28780 */ 28781 this.wireframeLinejoin = 'round'; 28782 28783 /** 28784 * Whether the material is rendered with flat shading or not. 28785 * 28786 * @type {boolean} 28787 * @default false 28788 */ 28789 this.flatShading = false;
28790 28791 /** 28792 * Whether the material is affected by fog or not. 28793 * 28794 * @type {boolean} 28795 * @default true 28796 */ 28797 this.fog = true; 28798 28799 this.setValues( parameters ); 28800 28801 } 28802 28803 copy( source ) { 28804 28805 super.copy( source ); 28806 28807 this.color.copy( source.color ); 28808 this.specular.copy( source.specular ); 28809 this.shininess = source.shininess; 28810 28811 this.map = source.map; 28812 28813 this.lightMap = source.lightMap; 28814 this.lightMapIntensity = source.lightMapIntensity; 28815 28816 this.aoMap = source.aoMap; 28817 this.aoMapIntensity = source.aoMapIntensity; 28818 28819 this.emissive.copy( source.emissive ); 28820 this.emissiveMap = source.emissiveMap; 28821 this.emissiveIntensity = source.emissiveIntensity; 28822 28823 this.bumpMap = source.bumpMap; 28824 this.bumpScale = source.bumpScale; 28825 28826 this.normalMap = source.normalMap; 28827 this.normalMapType = source.normalMapType; 28828 this.normalScale.copy( source.normalScale ); 28829 28830 this.displacementMap = source.displacementMap; 28831 this.displacementScale = source.displacementScale; 28832 this.displacementBias = source.displacementBias; 28833 28834 this.specularMap = source.specularMap; 28835 28836 this.alphaMap = source.alphaMap; 28837 28838 this.envMap = source.envMap; 28839 this.envMapRotation.copy( source.envMapRotation ); 28840 this.combine = source.combine; 28841 this.reflectivity = source.reflectivity; 28842 this.refractionRatio = source.refractionRatio; 28843 28844 this.wireframe = source.wireframe; 28845 this.wireframeLinewidth = source.wireframeLinewidth; 28846 this.wireframeLinecap = source.wireframeLinecap; 28847 this.wireframeLinejoin = source.wireframeLinejoin; 28848 28849 this.flatShading = source.flatShading; 28850 28851 this.fog = source.fog; 28852 28853 return this; 28854 28855 } 28856 28857} 28858 28859/** 28860 * A material for non-shiny surfaces, without specular highlights. 28861 * 28862 * The material uses a non-physically based [Lambertian]{@link https://en.wikipedia.org/wiki/Lambertian_reflectance} 28863 * model for calculating reflectance. This can simulate some surfaces (such 28864 * as untreated wood or stone) well, but cannot simulate shiny surfaces with 28865 * specular highlights (such as varnished wood). `MeshLambertMaterial` uses per-fragment 28866 * shading. 28867 * 28868 * Due to the simplicity of the reflectance and illumination models, 28869 * performance will be greater when using this material over the 28870 * {@link MeshPhongMaterial}, {@link MeshStandardMaterial} or 28871 * {@link MeshPhysicalMaterial}, at the cost of some graphical accuracy. 28872 * 28873 * @augments Material 28874 */ 28875class MeshLambertMaterial extends Material { 28876 28877 /** 28878 * Constructs a new mesh lambert material. 28879 * 28880 * @param {Object} [parameters] - An object with one or more properties 28881 * defining the material's appearance. Any property of the material 28882 * (including any property from inherited materials) can be passed 28883 * in here. Color values can be passed any type of value accepted 28884 * by {@link Color#set}. 28885 */ 28886 constructor( parameters ) { 28887 28888 super(); 28889 28890 /** 28891 * This flag can be used for type testing. 28892 * 28893 * @type {boolean} 28894 * @readonly 28895 * @default true 28896 */ 28897 this.isMeshLambertMaterial = true; 28898 28899 this.type = 'MeshLambertMaterial'; 28900 28901 /** 28902 * Color of the material. 28903 * 28904 * @type {Color} 28905 * @default (1,1,1) 28906 */ 28907 this.color = new Color( 0xffffff ); // diffuse 28908 28909 /** 28910 * The color map. May optionally include an alpha channel, typically combined 28911 * with {@link Material#transparent} or {@link Material#alphaTest}. The texture map 28912 * color is modulated by the diffuse `color`. 28913 * 28914 * @type {?Texture} 28915 * @default null 28916 */ 28917 this.map = null; 28918 28919 /** 28920 * The light map. Requires a second set of UVs. 28921 * 28922 * @type {?Texture} 28923 * @default null 28924 */ 28925 this.lightMap = null; 28926 28927 /** 28928 * Intensity of the baked light. 28929 * 28930 * @type {number} 28931 * @default 1 28932 */ 28933 this.lightMapIntensity = 1.0; 28934 28935 /** 28936 * The red channel of this texture is used as the ambient occlusion map. 28937 * Requires a second set of UVs. 28938 * 28939 * @type {?Texture} 28940 * @default null 28941 */ 28942 this.aoMap = null; 28943 28944 /** 28945 * Intensity of the ambient occlusion effect. Range is `[0,1]`, where `0` 28946 * disables ambient occlusion. Where intensity is `1` and the AO map's 28947 * red channel is also `1`, ambient light is fully occluded on a surface. 28948 * 28949 * @type {number} 28950 * @default 1 28951 */ 28952 this.aoMapIntensity = 1.0; 28953 28954 /** 28955 * Emissive (light) color of the material, essentially a solid color 28956 * unaffected by other lighting. 28957 * 28958 * @type {Color} 28959 * @default (0,0,0) 28960 */ 28961 this.emissive = new Color( 0x000000 ); 28962 28963 /** 28964 * Intensity of the emissive light. Modulates the emissive color. 28965 * 28966 * @type {number} 28967 * @default 1 28968 */ 28969 this.emissiveIntensity = 1.0; 28970 28971 /** 28972 * Set emissive (glow) map. The emissive map color is modulated by the 28973 * emissive color and the emissive intensity. If you have an emissive map, 28974 * be sure to set the emissive color to something other than black. 28975 * 28976 * @type {?Texture} 28977 * @default null 28978 */ 28979 this.emissiveMap = null; 28980 28981 /** 28982 * The texture to create a bump map. The black and white values map to the 28983 * perceived depth in relation to the lights. Bump doesn't actually affect 28984 * the geometry of the object, only the lighting. If a normal map is defined 28985 * this will be ignored. 28986 * 28987 * @type {?Texture} 28988 * @default null 28989 */ 28990 this.bumpMap = null; 28991 28992 /** 28993 * How much the bump map affects the material. Typical range is `[0,1]`. 28994 * 28995 * @type {number} 28996 * @default 1 28997 */ 28998 this.bumpScale = 1; 28999 29000 /** 29001 * The texture to create a normal map. The RGB values affect the surface 29002 * normal for each pixel fragment and change the way the color is lit. Normal
29003 * maps do not change the actual shape of the surface, only the lighting. In 29004 * case the material has a normal map authored using the left handed 29005 * convention, the `y` component of `normalScale` should be negated to compensate 29006 * for the different handedness. 29007 * 29008 * @type {?Texture} 29009 * @default null 29010 */ 29011 this.normalMap = null; 29012 29013 /** 29014 * The type of normal map. 29015 * 29016 * @type {(TangentSpaceNormalMap|ObjectSpaceNormalMap)} 29017 * @default TangentSpaceNormalMap 29018 */ 29019 this.normalMapType = TangentSpaceNormalMap; 29020 29021 /** 29022 * How much the normal map affects the material. Typical value range is `[0,1]`. 29023 * 29024 * @type {Vector2} 29025 * @default (1,1) 29026 */ 29027 this.normalScale = new Vector2( 1, 1 ); 29028 29029 /** 29030 * The displacement map affects the position of the mesh's vertices. Unlike 29031 * other maps which only affect the light and shade of the material the 29032 * displaced vertices can cast shadows, block other objects, and otherwise 29033 * act as real geometry. The displacement texture is an image where the value 29034 * of each pixel (white being the highest) is mapped against, and 29035 * repositions, the vertices of the mesh. 29036 * 29037 * @type {?Texture} 29038 * @default null 29039 */ 29040 this.displacementMap = null; 29041 29042 /** 29043 * How much the displacement map affects the mesh (where black is no 29044 * displacement, and white is maximum displacement). Without a displacement 29045 * map set, this value is not applied. 29046 * 29047 * @type {number} 29048 * @default 0 29049 */ 29050 this.displacementScale = 1; 29051 29052 /** 29053 * The offset of the displacement map's values on the mesh's vertices. 29054 * The bias is added to the scaled sample of the displacement map. 29055 * Without a displacement map set, this value is not applied. 29056 * 29057 * @type {number} 29058 * @default 0 29059 */ 29060 this.displacementBias = 0; 29061 29062 /** 29063 * Specular map used by the material. 29064 * 29065 * @type {?Texture} 29066 * @default null 29067 */ 29068 this.specularMap = null; 29069 29070 /** 29071 * The alpha map is a grayscale texture that controls the opacity across the 29072 * surface (black: fully transparent; white: fully opaque). 29073 * 29074 * Only the color of the texture is used, ignoring the alpha channel if one 29075 * exists. For RGB and RGBA textures, the renderer will use the green channel 29076 * when sampling this texture due to the extra bit of precision provided for 29077 * green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and 29078 * luminance/alpha textures will also still work as expected. 29079 * 29080 * @type {?Texture} 29081 * @default null 29082 */ 29083 this.alphaMap = null; 29084 29085 /** 29086 * The environment map. 29087 * 29088 * @type {?Texture} 29089 * @default null 29090 */ 29091 this.envMap = null; 29092 29093 /** 29094 * The rotation of the environment map in radians. 29095 * 29096 * @type {Euler} 29097 * @default (0,0,0) 29098 */ 29099 this.envMapRotation = new Euler(); 29100 29101 /** 29102 * How to combine the result of the surface's color with the environment map, if any. 29103 * 29104 * When set to `MixOperation`, the {@link MeshBasicMaterial#reflectivity} is used to 29105 * blend between the two colors. 29106 * 29107 * @type {(MultiplyOperation|MixOperation|AddOperation)} 29108 * @default MultiplyOperation 29109 */ 29110 this.combine = MultiplyOperation; 29111 29112 /** 29113 * How much the environment map affects the surface. 29114 * The valid range is between `0` (no reflections) and `1` (full reflections). 29115 * 29116 * @type {number} 29117 * @default 1 29118 */ 29119 this.reflectivity = 1; 29120 29121 /** 29122 * The index of refraction (IOR) of air (approximately 1) divided by the 29123 * index of refraction of the material. It is used with environment mapping 29124 * modes {@link CubeRefractionMapping} and {@link EquirectangularRefractionMapping}. 29125 * The refraction ratio should not exceed `1`. 29126 * 29127 * @type {number} 29128 * @default 0.98 29129 */ 29130 this.refractionRatio = 0.98; 29131 29132 /** 29133 * Renders the geometry as a wireframe. 29134 * 29135 * @type {boolean} 29136 * @default false 29137 */ 29138 this.wireframe = false; 29139 29140 /** 29141 * Controls the thickness of the wireframe. 29142 * 29143 * Can only be used with {@link SVGRenderer}. 29144 * 29145 * @type {number} 29146 * @default 1 29147 */ 29148 this.wireframeLinewidth = 1; 29149 29150 /** 29151 * Defines appearance of wireframe ends. 29152 * 29153 * Can only be used with {@link SVGRenderer}. 29154 * 29155 * @type {('round'|'bevel'|'miter')} 29156 * @default 'round' 29157 */ 29158 this.wireframeLinecap = 'round'; 29159 29160 /** 29161 * Defines appearance of wireframe joints. 29162 * 29163 * Can only be used with {@link SVGRenderer}. 29164 * 29165 * @type {('round'|'bevel'|'miter')} 29166 * @default 'round' 29167 */ 29168 this.wireframeLinejoin = 'round'; 29169 29170 /** 29171 * Whether the material is rendered with flat shading or not. 29172 * 29173 * @type {boolean} 29174 * @default false 29175 */ 29176 this.flatShading = false;
vendor: 4,123 bytes, lines 29177-29359
29177 29178 /** 29179 * Whether the material is affected by fog or not. 29180 * 29181 * @type {boolean} 29182 * @default true 29183 */ 29184 this.fog = true; 29185 29186 this.setValues( parameters ); 29187 29188 } 29189 29190 copy( source ) { 29191 29192 super.copy( source ); 29193 29194 this.color.copy( source.color ); 29195 29196 this.map = source.map; 29197 29198 this.lightMap = source.lightMap; 29199 this.lightMapIntensity = source.lightMapIntensity; 29200 29201 this.aoMap = source.aoMap; 29202 this.aoMapIntensity = source.aoMapIntensity; 29203 29204 this.emissive.copy( source.emissive ); 29205 this.emissiveMap = source.emissiveMap; 29206 this.emissiveIntensity = source.emissiveIntensity; 29207 29208 this.bumpMap = source.bumpMap; 29209 this.bumpScale = source.bumpScale; 29210 29211 this.normalMap = source.normalMap; 29212 this.normalMapType = source.normalMapType; 29213 this.normalScale.copy( source.normalScale ); 29214 29215 this.displacementMap = source.displacementMap; 29216 this.displacementScale = source.displacementScale; 29217 this.displacementBias = source.displacementBias; 29218 29219 this.specularMap = source.specularMap; 29220 29221 this.alphaMap = source.alphaMap; 29222 29223 this.envMap = source.envMap; 29224 this.envMapRotation.copy( source.envMapRotation ); 29225 this.combine = source.combine; 29226 this.reflectivity = source.reflectivity; 29227 this.refractionRatio = source.refractionRatio; 29228 29229 this.wireframe = source.wireframe; 29230 this.wireframeLinewidth = source.wireframeLinewidth; 29231 this.wireframeLinecap = source.wireframeLinecap; 29232 this.wireframeLinejoin = source.wireframeLinejoin; 29233 29234 this.flatShading = source.flatShading; 29235 29236 this.fog = source.fog; 29237 29238 return this; 29239 29240 } 29241 29242} 29243 29244/** 29245 * @class 29246 * @classdesc A simple caching system, used internally by {@link FileLoader}. 29247 * To enable caching across all loaders that use {@link FileLoader}, add `THREE.Cache.enabled = true.` once in your app. 29248 * @hideconstructor 29249 */ 29250const Cache = { 29251 29252 /** 29253 * Whether caching is enabled or not. 29254 * 29255 * @static 29256 * @type {boolean} 29257 * @default false 29258 */ 29259 enabled: false, 29260 29261 /** 29262 * A dictionary that holds cached files. 29263 * 29264 * @static 29265 * @type {Object<string,Object>} 29266 */ 29267 files: {}, 29268 29269 /** 29270 * Adds a cache entry with a key to reference the file. If this key already 29271 * holds a file, it is overwritten. 29272 * 29273 * @static 29274 * @param {string} key - The key to reference the cached file. 29275 * @param {Object} file - The file to be cached. 29276 */ 29277 add: function ( key, file ) { 29278 29279 if ( this.enabled === false ) return; 29280 29281 // console.log( 'THREE.Cache', 'Adding key:', key ); 29282 29283 this.files[ key ] = file; 29284 29285 }, 29286 29287 /** 29288 * Gets the cached value for the given key. 29289 * 29290 * @static 29291 * @param {string} key - The key to reference the cached file. 29292 * @return {Object|undefined} The cached file. If the key does not exist `undefined` is returned. 29293 */ 29294 get: function ( key ) { 29295 29296 if ( this.enabled === false ) return; 29297 29298 // console.log( 'THREE.Cache', 'Checking key:', key ); 29299 29300 return this.files[ key ]; 29301 29302 }, 29303 29304 /** 29305 * Removes the cached file associated with the given key. 29306 * 29307 * @static 29308 * @param {string} key - The key to reference the cached file. 29309 */ 29310 remove: function ( key ) { 29311 29312 delete this.files[ key ]; 29313 29314 }, 29315 29316 /** 29317 * Remove all values from the cache. 29318 * 29319 * @static 29320 */ 29321 clear: function () { 29322 29323 this.files = {}; 29324 29325 } 29326 29327}; 29328 29329/** 29330 * Handles and keeps track of loaded and pending data. A default global 29331 * instance of this class is created and used by loaders if not supplied 29332 * manually. 29333 * 29334 * In general that should be sufficient, however there are times when it can 29335 * be useful to have separate loaders - for example if you want to show 29336 * separate loading bars for objects and textures. 29337 * 29338 * ```js 29339 * const manager = new THREE.LoadingManager(); 29340 * manager.onLoad = () => console.log( 'Loading complete!' ); 29341 * 29342 * const loader1 = new OBJLoader( manager ); 29343 * const loader2 = new ColladaLoader( manager ); 29344 * ``` 29345 */ 29346class LoadingManager { 29347 29348 /** 29349 * Constructs a new loading manager. 29350 * 29351 * @param {Function} [onLoad] - Executes when all items have been loaded. 29352 * @param {Function} [onProgress] - Executes when single items have been loaded. 29353 * @param {Function} [onError] - Executes when an error occurs. 29354 */ 29355 constructor( onLoad, onProgress, onError ) { 29356 29357 const scope = this; 29358 29359 let isLoading = false;
vendor: 6,083 bytes, lines 29360-29649
29360 let itemsLoaded = 0; 29361 let itemsTotal = 0; 29362 let urlModifier = undefined; 29363 const handlers = []; 29364 29365 // Refer to #5689 for the reason why we don't set .onStart 29366 // in the constructor 29367 29368 /** 29369 * Executes when an item starts loading. 29370 * 29371 * @type {Function|undefined} 29372 * @default undefined 29373 */ 29374 this.onStart = undefined; 29375 29376 /** 29377 * Executes when all items have been loaded. 29378 * 29379 * @type {Function|undefined} 29380 * @default undefined 29381 */ 29382 this.onLoad = onLoad; 29383 29384 /** 29385 * Executes when single items have been loaded. 29386 * 29387 * @type {Function|undefined} 29388 * @default undefined 29389 */ 29390 this.onProgress = onProgress; 29391 29392 /** 29393 * Executes when an error occurs. 29394 * 29395 * @type {Function|undefined} 29396 * @default undefined 29397 */ 29398 this.onError = onError; 29399 29400 /** 29401 * This should be called by any loader using the manager when the loader 29402 * starts loading an item. 29403 * 29404 * @param {string} url - The URL to load. 29405 */ 29406 this.itemStart = function ( url ) { 29407 29408 itemsTotal ++; 29409 29410 if ( isLoading === false ) { 29411 29412 if ( scope.onStart !== undefined ) { 29413 29414 scope.onStart( url, itemsLoaded, itemsTotal ); 29415 29416 } 29417 29418 } 29419 29420 isLoading = true; 29421 29422 }; 29423 29424 /** 29425 * This should be called by any loader using the manager when the loader 29426 * ended loading an item. 29427 * 29428 * @param {string} url - The URL of the loaded item. 29429 */ 29430 this.itemEnd = function ( url ) { 29431 29432 itemsLoaded ++; 29433 29434 if ( scope.onProgress !== undefined ) { 29435 29436 scope.onProgress( url, itemsLoaded, itemsTotal ); 29437 29438 } 29439 29440 if ( itemsLoaded === itemsTotal ) { 29441 29442 isLoading = false; 29443 29444 if ( scope.onLoad !== undefined ) { 29445 29446 scope.onLoad(); 29447 29448 } 29449 29450 } 29451 29452 }; 29453 29454 /** 29455 * This should be called by any loader using the manager when the loader 29456 * encounters an error when loading an item. 29457 * 29458 * @param {string} url - The URL of the item that produces an error. 29459 */ 29460 this.itemError = function ( url ) { 29461 29462 if ( scope.onError !== undefined ) { 29463 29464 scope.onError( url ); 29465 29466 } 29467 29468 }; 29469 29470 /** 29471 * Given a URL, uses the URL modifier callback (if any) and returns a 29472 * resolved URL. If no URL modifier is set, returns the original URL. 29473 * 29474 * @param {string} url - The URL to load. 29475 * @return {string} The resolved URL. 29476 */ 29477 this.resolveURL = function ( url ) { 29478 29479 if ( urlModifier ) { 29480 29481 return urlModifier( url ); 29482 29483 } 29484 29485 return url; 29486 29487 }; 29488 29489 /** 29490 * If provided, the callback will be passed each resource URL before a 29491 * request is sent. The callback may return the original URL, or a new URL to 29492 * override loading behavior. This behavior can be used to load assets from 29493 * .ZIP files, drag-and-drop APIs, and Data URIs. 29494 * 29495 * ```js 29496 * const blobs = {'fish.gltf': blob1, 'diffuse.png': blob2, 'normal.png': blob3}; 29497 * 29498 * const manager = new THREE.LoadingManager(); 29499 * 29500 * // Initialize loading manager with URL callback. 29501 * const objectURLs = []; 29502 * manager.setURLModifier( ( url ) => { 29503 * 29504 * url = URL.createObjectURL( blobs[ url ] ); 29505 * objectURLs.push( url ); 29506 * return url; 29507 * 29508 * } ); 29509 * 29510 * // Load as usual, then revoke the blob URLs. 29511 * const loader = new GLTFLoader( manager ); 29512 * loader.load( 'fish.gltf', (gltf) => { 29513 * 29514 * scene.add( gltf.scene ); 29515 * objectURLs.forEach( ( url ) => URL.revokeObjectURL( url ) ); 29516 * 29517 * } ); 29518 * ``` 29519 * 29520 * @param {function(string):string} transform - URL modifier callback. Called with an URL and must return a resolved URL. 29521 * @return {LoadingManager} A reference to this loading manager. 29522 */ 29523 this.setURLModifier = function ( transform ) { 29524 29525 urlModifier = transform; 29526 29527 return this; 29528 29529 }; 29530 29531 /** 29532 * Registers a loader with the given regular expression. Can be used to 29533 * define what loader should be used in order to load specific files. A 29534 * typical use case is to overwrite the default loader for textures. 29535 * 29536 * ```js 29537 * // add handler for TGA textures 29538 * manager.addHandler( /\.tga$/i, new TGALoader() ); 29539 * ``` 29540 * 29541 * @param {string} regex - A regular expression. 29542 * @param {Loader} loader - A loader that should handle matched cases. 29543 * @return {LoadingManager} A reference to this loading manager. 29544 */ 29545 this.addHandler = function ( regex, loader ) { 29546 29547 handlers.push( regex, loader ); 29548 29549 return this; 29550 29551 }; 29552 29553 /** 29554 * Removes the loader for the given regular expression. 29555 * 29556 * @param {string} regex - A regular expression. 29557 * @return {LoadingManager} A reference to this loading manager. 29558 */ 29559 this.removeHandler = function ( regex ) { 29560 29561 const index = handlers.indexOf( regex ); 29562 29563 if ( index !== -1 ) { 29564 29565 handlers.splice( index, 2 ); 29566 29567 } 29568 29569 return this; 29570 29571 }; 29572 29573 /** 29574 * Can be used to retrieve the registered loader for the given file path. 29575 * 29576 * @param {string} file - The file path. 29577 * @return {?Loader} The registered loader. Returns `null` if no loader was found. 29578 */ 29579 this.getHandler = function ( file ) { 29580 29581 for ( let i = 0, l = handlers.length; i < l; i += 2 ) { 29582 29583 const regex = handlers[ i ]; 29584 const loader = handlers[ i + 1 ]; 29585 29586 if ( regex.global ) regex.lastIndex = 0; // see #17920 29587 29588 if ( regex.test( file ) ) { 29589 29590 return loader; 29591 29592 } 29593 29594 } 29595 29596 return null; 29597 29598 }; 29599 29600 } 29601 29602} 29603 29604/** 29605 * The global default loading manager. 29606 * 29607 * @constant 29608 * @type {LoadingManager} 29609 */ 29610const DefaultLoadingManager = /*@__PURE__*/ new LoadingManager(); 29611 29612/** 29613 * Abstract base class for loaders. 29614 * 29615 * @abstract 29616 */ 29617class Loader { 29618 29619 /** 29620 * Constructs a new loader. 29621 * 29622 * @param {LoadingManager} [manager] - The loading manager. 29623 */ 29624 constructor( manager ) { 29625 29626 /** 29627 * The loading manager. 29628 * 29629 * @type {LoadingManager} 29630 * @default DefaultLoadingManager 29631 */ 29632 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; 29633 29634 /** 29635 * The crossOrigin string to implement CORS for loading the url from a 29636 * different domain that allows CORS. 29637 * 29638 * @type {string} 29639 * @default 'anonymous' 29640 */ 29641 this.crossOrigin = 'anonymous'; 29642 29643 /** 29644 * Whether the XMLHttpRequest uses credentials. 29645 * 29646 * @type {boolean} 29647 * @default false 29648 */ 29649 this.withCredentials = false;
29650 29651 /** 29652 * The base path from which the asset will be loaded. 29653 * 29654 * @type {string} 29655 */ 29656 this.path = ''; 29657 29658 /** 29659 * The base path from which additional resources like textures will be loaded. 29660 * 29661 * @type {string} 29662 */ 29663 this.resourcePath = ''; 29664 29665 /** 29666 * The [request header]{@link https://developer.mozilla.org/en-US/docs/Glossary/Request_header} 29667 * used in HTTP request. 29668 * 29669 * @type {Object<string, any>} 29670 */ 29671 this.requestHeader = {}; 29672 29673 } 29674 29675 /** 29676 * This method needs to be implemented by all concrete loaders. It holds the 29677 * logic for loading assets from the backend. 29678 * 29679 * @param {string} url - The path/URL of the file to be loaded. 29680 * @param {Function} onLoad - Executed when the loading process has been finished. 29681 * @param {onProgressCallback} [onProgress] - Executed while the loading is in progress. 29682 * @param {onErrorCallback} [onError] - Executed when errors occur. 29683 */ 29684 load( /* url, onLoad, onProgress, onError */ ) {} 29685 29686 /** 29687 * A async version of {@link Loader#load}. 29688 * 29689 * @param {string} url - The path/URL of the file to be loaded. 29690 * @param {onProgressCallback} [onProgress] - Executed while the loading is in progress. 29691 * @return {Promise} A Promise that resolves when the asset has been loaded. 29692 */ 29693 loadAsync( url, onProgress ) { 29694 29695 const scope = this; 29696 29697 return new Promise( function ( resolve, reject ) { 29698 29699 scope.load( url, resolve, onProgress, reject ); 29700 29701 } ); 29702 29703 } 29704 29705 /** 29706 * This method needs to be implemented by all concrete loaders. It holds the 29707 * logic for parsing the asset into three.js entities. 29708 * 29709 * @param {any} data - The data to parse. 29710 */ 29711 parse( /* data */ ) {} 29712 29713 /** 29714 * Sets the `crossOrigin` String to implement CORS for loading the URL 29715 * from a different domain that allows CORS. 29716 * 29717 * @param {string} crossOrigin - The `crossOrigin` value. 29718 * @return {Loader} A reference to this instance. 29719 */ 29720 setCrossOrigin( crossOrigin ) { 29721 29722 this.crossOrigin = crossOrigin; 29723 return this; 29724 29725 } 29726 29727 /** 29728 * Whether the XMLHttpRequest uses credentials such as cookies, authorization 29729 * headers or TLS client certificates, see [XMLHttpRequest.withCredentials]{@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials}. 29730 * 29731 * Note: This setting has no effect if you are loading files locally or from the same domain. 29732 * 29733 * @param {boolean} value - The `withCredentials` value. 29734 * @return {Loader} A reference to this instance. 29735 */ 29736 setWithCredentials( value ) { 29737 29738 this.withCredentials = value; 29739 return this; 29740 29741 } 29742 29743 /** 29744 * Sets the base path for the asset. 29745 * 29746 * @param {string} path - The base path. 29747 * @return {Loader} A reference to this instance. 29748 */ 29749 setPath( path ) { 29750 29751 this.path = path; 29752 return this; 29753 29754 } 29755 29756 /** 29757 * Sets the base path for dependent resources like textures. 29758 * 29759 * @param {string} resourcePath - The resource path. 29760 * @return {Loader} A reference to this instance. 29761 */
29762 setResourcePath( resourcePath ) { 29763 29764 this.resourcePath = resourcePath; 29765 return this; 29766 29767 } 29768 29769 /** 29770 * Sets the given request header. 29771 * 29772 * @param {Object} requestHeader - A [request header]{@link https://developer.mozilla.org/en-US/docs/Glossary/Request_header} 29773 * for configuring the HTTP request. 29774 * @return {Loader} A reference to this instance. 29775 */ 29776 setRequestHeader( requestHeader ) { 29777 29778 this.requestHeader = requestHeader; 29779 return this; 29780 29781 } 29782 29783} 29784 29785/** 29786 * Callback for onProgress in loaders. 29787 * 29788 * @callback onProgressCallback 29789 * @param {ProgressEvent} event - An instance of `ProgressEvent` that represents the current loading status. 29790 */ 29791 29792/** 29793 * Callback for onError in loaders. 29794 * 29795 * @callback onErrorCallback 29796 * @param {Error} error - The error which occurred during the loading process. 29797 */ 29798 29799/** 29800 * The default material name that is used by loaders 29801 * when creating materials for loaded 3D objects. 29802 * 29803 * Note: Not all loaders might honor this setting. 29804 * 29805 * @static 29806 * @type {string} 29807 * @default '__DEFAULT' 29808 */ 29809Loader.DEFAULT_MATERIAL_NAME = '__DEFAULT'; 29810 29811/** 29812 * A loader for loading images. The class loads images with the HTML `Image` API. 29813 * 29814 * ```js 29815 * const loader = new THREE.ImageLoader(); 29816 * const image = await loader.loadAsync( 'image.png' ); 29817 * ``` 29818 * Please note that `ImageLoader` has dropped support for progress 29819 * events in `r84`. For an `ImageLoader` that supports progress events, see 29820 * [this thread]{@link https://github.com/mrdoob/three.js/issues/10439#issuecomment-275785639}. 29821 * 29822 * @augments Loader 29823 */ 29824class ImageLoader extends Loader { 29825 29826 /** 29827 * Constructs a new image loader. 29828 * 29829 * @param {LoadingManager} [manager] - The loading manager. 29830 */ 29831 constructor( manager ) { 29832 29833 super( manager ); 29834 29835 } 29836 29837 /** 29838 * Starts loading from the given URL and passes the loaded image 29839 * to the `onLoad()` callback. The method also returns a new `Image` object which can 29840 * directly be used for texture creation. If you do it this way, the texture 29841 * may pop up in your scene once the respective loading process is finished. 29842 * 29843 * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI. 29844 * @param {function(Image)} onLoad - Executed when the loading process has been finished. 29845 * @param {onProgressCallback} onProgress - Unsupported in this loader. 29846 * @param {onErrorCallback} onError - Executed when errors occur. 29847 * @return {Image} The image. 29848 */ 29849 load( url, onLoad, onProgress, onError ) { 29850 29851 if ( this.path !== undefined ) url = this.path + url; 29852 29853 url = this.manager.resolveURL( url ); 29854 29855 const scope = this; 29856 29857 const cached = Cache.get( url ); 29858 29859 if ( cached !== undefined ) { 29860 29861 scope.manager.itemStart( url ); 29862 29863 setTimeout( function () { 29864 29865 if ( onLoad ) onLoad( cached ); 29866 29867 scope.manager.itemEnd( url ); 29868 29869 }, 0 ); 29870 29871 return cached; 29872 29873 } 29874 29875 const image = createElementNS( 'img' ); 29876 29877 function onImageLoad() { 29878 29879 removeEventListeners(); 29880 29881 Cache.add( url, this ); 29882 29883 if ( onLoad ) onLoad( this ); 29884 29885 scope.manager.itemEnd( url ); 29886 29887 } 29888 29889 function onImageError( event ) { 29890 29891 removeEventListeners(); 29892 29893 if ( onError ) onError( event ); 29894 29895 scope.manager.itemError( url ); 29896 scope.manager.itemEnd( url ); 29897 29898 } 29899 29900 function removeEventListeners() { 29901 29902 image.removeEventListener( 'load', onImageLoad, false ); 29903 image.removeEventListener( 'error', onImageError, false ); 29904 29905 } 29906 29907 image.addEventListener( 'load', onImageLoad, false ); 29908 image.addEventListener( 'error', onImageError, false ); 29909 29910 if ( url.slice( 0, 5 ) !== 'data:' ) { 29911 29912 if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; 29913 29914 } 29915 29916 scope.manager.itemStart( url ); 29917 29918 image.src = url; 29919 29920 return image; 29921 29922 } 29923 29924} 29925 29926/** 29927 * Class for loading textures. Images are internally 29928 * loaded via {@link ImageLoader}. 29929 * 29930 * ```js 29931 * const loader = new THREE.TextureLoader(); 29932 * const texture = await loader.loadAsync( 'textures/land_ocean_ice_cloud_2048.jpg' ); 29933 * 29934 * const material = new THREE.MeshBasicMaterial( { map:texture } ); 29935 * ``` 29936 * Please note that `TextureLoader` has dropped support for progress 29937 * events in `r84`. For a `TextureLoader` that supports progress events, see 29938 * [this thread]{@link https://github.com/mrdoob/three.js/issues/10439#
vendor: 9,961 bytes, lines 29938-30357
29938issuecomment-293260145}. 29939 * 29940 * @augments Loader 29941 */ 29942class TextureLoader extends Loader { 29943 29944 /** 29945 * Constructs a new texture loader. 29946 * 29947 * @param {LoadingManager} [manager] - The loading manager. 29948 */ 29949 constructor( manager ) { 29950 29951 super( manager ); 29952 29953 } 29954 29955 /** 29956 * Starts loading from the given URL and pass the fully loaded texture 29957 * to the `onLoad()` callback. The method also returns a new texture object which can 29958 * directly be used for material creation. If you do it this way, the texture 29959 * may pop up in your scene once the respective loading process is finished. 29960 * 29961 * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI. 29962 * @param {function(Texture)} onLoad - Executed when the loading process has been finished. 29963 * @param {onProgressCallback} onProgress - Unsupported in this loader. 29964 * @param {onErrorCallback} onError - Executed when errors occur. 29965 * @return {Texture} The texture. 29966 */ 29967 load( url, onLoad, onProgress, onError ) { 29968 29969 const texture = new Texture(); 29970 29971 const loader = new ImageLoader( this.manager ); 29972 loader.setCrossOrigin( this.crossOrigin ); 29973 loader.setPath( this.path ); 29974 29975 loader.load( url, function ( image ) { 29976 29977 texture.image = image; 29978 texture.needsUpdate = true; 29979 29980 if ( onLoad !== undefined ) { 29981 29982 onLoad( texture ); 29983 29984 } 29985 29986 }, onProgress, onError ); 29987 29988 return texture; 29989 29990 } 29991 29992} 29993 29994/** 29995 * An instanced version of a geometry. 29996 */ 29997class InstancedBufferGeometry extends BufferGeometry { 29998 29999 /** 30000 * Constructs a new instanced buffer geometry. 30001 */ 30002 constructor() { 30003 30004 super(); 30005 30006 /** 30007 * This flag can be used for type testing. 30008 * 30009 * @type {boolean} 30010 * @readonly 30011 * @default true 30012 */ 30013 this.isInstancedBufferGeometry = true; 30014 30015 this.type = 'InstancedBufferGeometry'; 30016 30017 /** 30018 * The instance count. 30019 * 30020 * @type {number} 30021 * @default Infinity 30022 */ 30023 this.instanceCount = Infinity; 30024 30025 } 30026 30027 copy( source ) { 30028 30029 super.copy( source ); 30030 30031 this.instanceCount = source.instanceCount; 30032 30033 return this; 30034 30035 } 30036 30037 toJSON() { 30038 30039 const data = super.toJSON(); 30040 30041 data.instanceCount = this.instanceCount; 30042 30043 data.isInstancedBufferGeometry = true; 30044 30045 return data; 30046 30047 } 30048 30049} 30050 30051/** 30052 * An instanced version of an interleaved buffer. 30053 * 30054 * @augments InterleavedBuffer 30055 */ 30056class InstancedInterleavedBuffer extends InterleavedBuffer { 30057 30058 /** 30059 * Constructs a new instanced interleaved buffer. 30060 * 30061 * @param {TypedArray} array - A typed array with a shared buffer storing attribute data. 30062 * @param {number} stride - The number of typed-array elements per vertex. 30063 * @param {number} [meshPerAttribute=1] - Defines how often a value of this interleaved buffer should be repeated. 30064 */ 30065 constructor( array, stride, meshPerAttribute = 1 ) { 30066 30067 super( array, stride ); 30068 30069 /** 30070 * This flag can be used for type testing. 30071 * 30072 * @type {boolean} 30073 * @readonly 30074 * @default true 30075 */ 30076 this.isInstancedInterleavedBuffer = true; 30077 30078 /** 30079 * Defines how often a value of this buffer attribute should be repeated, 30080 * see {@link InstancedBufferAttribute#meshPerAttribute}. 30081 * 30082 * @type {number} 30083 * @default 1 30084 */ 30085 this.meshPerAttribute = meshPerAttribute; 30086 30087 } 30088 30089 copy( source ) { 30090 30091 super.copy( source ); 30092 30093 this.meshPerAttribute = source.meshPerAttribute; 30094 30095 return this; 30096 30097 } 30098 30099 clone( data ) { 30100 30101 const ib = super.clone( data ); 30102 30103 ib.meshPerAttribute = this.meshPerAttribute; 30104 30105 return ib; 30106 30107 } 30108 30109 toJSON( data ) { 30110 30111 const json = super.toJSON( data ); 30112 30113 json.isInstancedInterleavedBuffer = true; 30114 json.meshPerAttribute = this.meshPerAttribute; 30115 30116 return json; 30117 30118 } 30119 30120} 30121 30122const _startP = /*@__PURE__*/ new Vector3(); 30123const _startEnd = /*@__PURE__*/ new Vector3(); 30124 30125/** 30126 * An analytical line segment in 3D space represented by a start and end point. 30127 */ 30128class Line3 { 30129 30130 /** 30131 * Constructs a new line segment. 30132 * 30133 * @param {Vector3} [start=(0,0,0)] - Start of the line segment. 30134 * @param {Vector3} [end=(0,0,0)] - End of the line segment. 30135 */ 30136 constructor( start = new Vector3(), end = new Vector3() ) { 30137 30138 /** 30139 * Start of the line segment. 30140 * 30141 * @type {Vector3} 30142 */ 30143 this.start = start; 30144 30145 /** 30146 * End of the line segment. 30147 * 30148 * @type {Vector3} 30149 */ 30150 this.end = end; 30151 30152 } 30153 30154 /** 30155 * Sets the start and end values by copying the given vectors. 30156 * 30157 * @param {Vector3} start - The start point. 30158 * @param {Vector3} end - The end point. 30159 * @return {Line3} A reference to this line segment. 30160 */ 30161 set( start, end ) { 30162 30163 this.start.copy( start ); 30164 this.end.copy( end ); 30165 30166 return this; 30167 30168 } 30169 30170 /** 30171 * Copies the values of the given line segment to this instance. 30172 * 30173 * @param {Line3} line - The line segment to copy. 30174 * @return {Line3} A reference to this line segment. 30175 */ 30176 copy( line ) { 30177 30178 this.start.copy( line.start ); 30179 this.end.copy( line.end ); 30180 30181 return this; 30182 30183 } 30184 30185 /** 30186 * Returns the center of the line segment. 30187 * 30188 * @param {Vector3} target - The target vector that is used to store the method's result. 30189 * @return {Vector3} The center point. 30190 */ 30191 getCenter( target ) { 30192 30193 return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); 30194 30195 } 30196 30197 /** 30198 * Returns the delta vector of the line segment's start and end point. 30199 * 30200 * @param {Vector3} target - The target vector that is used to store the method's result. 30201 * @return {Vector3} The delta vector. 30202 */ 30203 delta( target ) { 30204 30205 return target.subVectors( this.end, this.start ); 30206 30207 } 30208 30209 /** 30210 * Returns the squared Euclidean distance between the line' start and end point. 30211 * 30212 * @return {number} The squared Euclidean distance. 30213 */ 30214 distanceSq() { 30215 30216 return this.start.distanceToSquared( this.end ); 30217 30218 } 30219 30220 /** 30221 * Returns the Euclidean distance between the line' start and end point. 30222 * 30223 * @return {number} The Euclidean distance. 30224 */ 30225 distance() { 30226 30227 return this.start.distanceTo( this.end ); 30228 30229 } 30230 30231 /** 30232 * Returns a vector at a certain position along the line segment. 30233 * 30234 * @param {number} t - A value between `[0,1]` to represent a position along the line segment. 30235 * @param {Vector3} target - The target vector that is used to store the method's result. 30236 * @return {Vector3} The delta vector. 30237 */ 30238 at( t, target ) { 30239 30240 return this.delta( target ).multiplyScalar( t ).add( this.start ); 30241 30242 } 30243 30244 /** 30245 * Returns a point parameter based on the closest point as projected on the line segment. 30246 * 30247 * @param {Vector3} point - The point for which to return a point parameter. 30248 * @param {boolean} clampToLine - Whether to clamp the result to the range `[0,1]` or not. 30249 * @return {number} The point parameter. 30250 */ 30251 closestPointToPointParameter( point, clampToLine ) { 30252 30253 _startP.subVectors( point, this.start ); 30254 _startEnd.subVectors( this.end, this.start ); 30255 30256 const startEnd2 = _startEnd.dot( _startEnd ); 30257 const startEnd_startP = _startEnd.dot( _startP ); 30258 30259 let t = startEnd_startP / startEnd2; 30260 30261 if ( clampToLine ) { 30262 30263 t = clamp( t, 0, 1 ); 30264 30265 } 30266 30267 return t; 30268 30269 } 30270 30271 /** 30272 * Returns the closets point on the line for a given point. 30273 * 30274 * @param {Vector3} point - The point to compute the closest point on the line for. 30275 * @param {boolean} clampToLine - Whether to clamp the result to the range `[0,1]` or not. 30276 * @param {Vector3} target - The target vector that is used to store the method's result. 30277 * @return {Vector3} The closest point on the line. 30278 */ 30279 closestPointToPoint( point, clampToLine, target ) { 30280 30281 const t = this.closestPointToPointParameter( point, clampToLine ); 30282 30283 return this.delta( target ).multiplyScalar( t ).add( this.start ); 30284 30285 } 30286 30287 /** 30288 * Applies a 4x4 transformation matrix to this line segment. 30289 * 30290 * @param {Matrix4} matrix - The transformation matrix. 30291 * @return {Line3} A reference to this line segment. 30292 */ 30293 applyMatrix4( matrix ) { 30294 30295 this.start.applyMatrix4( matrix ); 30296 this.end.applyMatrix4( matrix ); 30297 30298 return this; 30299 30300 } 30301 30302 /** 30303 * Returns `true` if this line segment is equal with the given one. 30304 * 30305 * @param {Line3} line - The line segment to test for equality. 30306 * @return {boolean} Whether this line segment is equal with the given one. 30307 */ 30308 equals( line ) { 30309 30310 return line.start.equals( this.start ) && line.end.equals( this.end ); 30311 30312 } 30313 30314 /** 30315 * Returns a new line segment with copied values from this instance. 30316 * 30317 * @return {Line3} A clone of this instance. 30318 */ 30319 clone() { 30320 30321 return new this.constructor().copy( this ); 30322 30323 } 30324 30325} 30326 30327if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { 30328 30329 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: { 30330 revision: REVISION, 30331 } } ) ); 30332 30333} 30334 30335if ( typeof window !== 'undefined' ) { 30336 30337 if ( window.__THREE__ ) { 30338 30339 console.warn( 'WARNING: Multiple instances of Three.js being imported.' ); 30340 30341 } else { 30342 30343 window.__THREE__ = REVISION; 30344 30345 } 30346 30347} 30348 30349/** 30350 * @license 30351 * Copyright 2010-2025 Three.js Authors 30352 * SPDX-License-Identifier: MIT 30353 */ 30354 30355var alphahash_fragment = "#ifdef USE_ALPHAHASH\n\tif ( diffuseColor.a < getAlphaHashThreshold( vPosition ) ) discard;\n#endif"; 30356 30357var 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
30357- ( ( 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"; 30358 30359var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vAlphaMapUv ).g;\n#endif"; 30360 30361var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; 30362 30363var 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"; 30364 30365var alphatest_pars_fragment = "#ifdef USE_ALPHATEST\n\tuniform float alphaTest;\n#endif"; 30366 30367var 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"; 30368 30369var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; 30370 30371var 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"; 30372 30373var batching_vertex = "#ifdef USE_BATCHING\n\tmat4 batchingMatrix = getBatchingMatrix( getIndirectIndex( gl_DrawID ) );\n#endif"; 30374 30375var begin_vertex = "vec3 transformed = vec3( position );\n#ifdef USE_ALPHAHASH\n\tvPosition = vec3( position );\n#endif"; 30376 30377var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif"; 30378 30379var 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"; 30380 30381var 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 );
30381\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"; 30382 30383var 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"; 30384 30385var 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"; 30386 30387var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif"; 30388 30389var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif"; 30390 30391var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif"; 30392 30393var color_fragment = "#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( USE_COLOR )\n\tdiffuseColor.rgb *= vColor;\n#endif"; 30394 30395var color_pars_fragment = "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_COLOR )\n\tvarying vec3 vColor;\n#endif"; 30396 30397var 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"; 30398 30399var 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"; 30400 30401var 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"; 30402 30403var 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"; 30404 30405var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = objectTangent;\n#endif\n#ifdef USE_BATCHING\n\tmat3 bm = mat3( batchingMatrix );
30405\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"; 30406 30407var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif"; 30408 30409var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias );\n#endif"; 30410 30411var 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"; 30412 30413var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif"; 30414 30415var colorspace_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );"; 30416 30417var 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}"; 30418 30419var 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"; 30420 30421var 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
vendor: 6,748 bytes, lines 30421-30445
30421\n#endif"; 30422 30423var 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"; 30424 30425var 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"; 30426 30427var 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} 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"; 30428 30429var fog_vertex = "#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif"; 30430 30431var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif"; 30432 30433var 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"; 30434 30435var 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"; 30436 30437var 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}"; 30438 30439var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; 30440 30441var lights_lambert_fragment = "LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularStrength = specularStrength;"; 30442 30443var 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"; 30444 30445var 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}
vendor: 8,222 bytes, lines 30445-30457
30445\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"; 30446 30447var 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"; 30448 30449var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;"; 30450 30451var 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"; 30452 30453var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;"; 30454 30455var 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( 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"; 30456 30457var 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;\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_
30457DISPERSION\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"; 30458 30459var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\tfloat dispersion
vendor: 16,747 bytes, lines 30459-30461
30459;\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}"; 30460 30461var 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.shadow
30461Intensity, 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"; 30462 30463var 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"; 30464 30465var 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"; 30466 30467var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF )\n\tgl_FragDepth = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif"; 30468 30469var logdepthbuf_pars_fragment = "#if defined( USE_LOGDEPTHBUF )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif"; 30470 30471var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif"; 30472 30473var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF
vendor: 10,573 bytes, lines 30473-30519
30473\n\tvFragDepth = 1.0 + gl_Position.w;\n\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n#endif"; 30474 30475var 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"; 30476 30477var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif"; 30478 30479var 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"; 30480 30481var 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"; 30482 30483var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif"; 30484 30485var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"; 30486 30487var 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"; 30488 30489var 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"; 30490 30491var 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"; 30492 30493var 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"; 30494 30495var 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"; 30496 30497var 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;"; 30498 30499var 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 );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif"; 30500 30501var 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"; 30502 30503var 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"; 30504 30505var 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"; 30506 30507var 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"; 30508 30509var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = nonPerturbedNormal;\n#endif"; 30510 30511var 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"; 30512 30513var 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"; 30514 30515var iridescence_pars_fragment = "#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform sampler2D iridescenceThicknessMap;\n#endif"; 30516 30517var 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 );"; 30518 30519var 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 * 255.0 ), v.y, fract( v.y * 255.0 ) );\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );\n}\nvec2 unpackRGBATo2Half( 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\t
30519return 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}"; 30520 30521var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif"; 30522 30523var 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;"; 30524 30525var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif"; 30526 30527var 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"; 30528 30529var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv );\n\troughnessFactor *= texelRoughness.g;\n#endif"; 30530 30531var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"; 30532 30533var 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;
30533\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"; 30534
30535var 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"; 30536 30537var 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"; 30538 30539var 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}"; 30540 30541var 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"; 30542 30543var 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"; 30544 30545var 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"; 30546 30547var 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"; 30548 30549var 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"; 30550 30551var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif"; 30552 30553var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif"; 30554 30555var tonemapping_pars_fragment =
vendor: 3,668 bytes, line 30555
30555"#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; }"
30555; 30556 30557var 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
vendor: 15,291 bytes, lines 30557-30575
30557, 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"; 30558 30559var 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"; 30560 30561var uv_pars_fragment = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tvarying vec2 vMapUv;\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"; 30562 30563var 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"; 30564 30565var 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;\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"; 30566 30567var 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"; 30568 30569const 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}"; 30570 30571const 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}"; 30572 30573const 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}"; 30574 30575const 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
30575flipEnvMap;\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}"; 30576 30577const 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}"; 30578 30579const 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}"; 30580 30581const 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}"; 30582 30583const 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}"; 30584 30585const 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}"; 30586 30587const 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}"; 30588 30589const 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}"; 30590 30591const 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}"; 30592 30593const 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}"; 30594 30595const 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}"; 30596 30597const 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}"; 30598 30599const 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}"; 30600 30601const 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}"; 30602 30603const 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}"; 30604 30605const 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#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}"; 30606 30607const 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;
30607\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}"; 30608 30609const 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}"; 30610 30611const 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}"; 30612 30613const 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}"; 30614 30615const 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}"; 30616 30617const 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}"; 30618 30619const fragment$5 =
vendor: 4,251 bytes, line 30619
30619"#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: 20,917 bytes, lines 30619-31135
30619; 30620 30621const 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}"; 30622 30623const 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}"; 30624 30625const 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}"; 30626 30627const 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}"; 30628 30629const 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}"; 30630 30631const 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}"; 30632 30633const 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}"; 30634 30635const 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}"; 30636 30637const ShaderChunk = { 30638 alphahash_fragment: alphahash_fragment, 30639 alphahash_pars_fragment: alphahash_pars_fragment, 30640 alphamap_fragment: alphamap_fragment, 30641 alphamap_pars_fragment: alphamap_pars_fragment, 30642 alphatest_fragment: alphatest_fragment, 30643 alphatest_pars_fragment: alphatest_pars_fragment, 30644 aomap_fragment: aomap_fragment, 30645 aomap_pars_fragment: aomap_pars_fragment, 30646 batching_pars_vertex: batching_pars_vertex, 30647 batching_vertex: batching_vertex, 30648 begin_vertex: begin_vertex, 30649 beginnormal_vertex: beginnormal_vertex, 30650 bsdfs: bsdfs, 30651 iridescence_fragment: iridescence_fragment, 30652 bumpmap_pars_fragment: bumpmap_pars_fragment, 30653 clipping_planes_fragment: clipping_planes_fragment, 30654 clipping_planes_pars_fragment: clipping_planes_pars_fragment, 30655 clipping_planes_pars_vertex: clipping_planes_pars_vertex, 30656 clipping_planes_vertex: clipping_planes_vertex, 30657 color_fragment: color_fragment, 30658 color_pars_fragment: color_pars_fragment, 30659 color_pars_vertex: color_pars_vertex, 30660 color_vertex: color_vertex, 30661 common: common, 30662 cube_uv_reflection_fragment: cube_uv_reflection_fragment, 30663 defaultnormal_vertex: defaultnormal_vertex, 30664 displacementmap_pars_vertex: displacementmap_pars_vertex, 30665 displacementmap_vertex: displacementmap_vertex, 30666 emissivemap_fragment: emissivemap_fragment, 30667 emissivemap_pars_fragment: emissivemap_pars_fragment, 30668 colorspace_fragment: colorspace_fragment, 30669 colorspace_pars_fragment: colorspace_pars_fragment, 30670 envmap_fragment: envmap_fragment, 30671 envmap_common_pars_fragment: envmap_common_pars_fragment, 30672 envmap_pars_fragment: envmap_pars_fragment, 30673 envmap_pars_vertex: envmap_pars_vertex, 30674 envmap_physical_pars_fragment: envmap_physical_pars_fragment, 30675 envmap_vertex: envmap_vertex, 30676 fog_vertex: fog_vertex, 30677 fog_pars_vertex: fog_pars_vertex, 30678 fog_fragment: fog_fragment, 30679 fog_pars_fragment: fog_pars_fragment, 30680 gradientmap_pars_fragment: gradientmap_pars_fragment, 30681 lightmap_pars_fragment: lightmap_pars_fragment, 30682 lights_lambert_fragment: lights_lambert_fragment, 30683 lights_lambert_pars_fragment: lights_lambert_pars_fragment, 30684 lights_pars_begin: lights_pars_begin, 30685 lights_toon_fragment: lights_toon_fragment, 30686 lights_toon_pars_fragment: lights_toon_pars_fragment, 30687 lights_phong_fragment: lights_phong_fragment, 30688 lights_phong_pars_fragment: lights_phong_pars_fragment, 30689 lights_physical_fragment: lights_physical_fragment, 30690 lights_physical_pars_fragment: lights_physical_pars_fragment, 30691 lights_fragment_begin: lights_fragment_begin, 30692 lights_fragment_maps: lights_fragment_maps, 30693 lights_fragment_end: lights_fragment_end, 30694 logdepthbuf_fragment: logdepthbuf_fragment, 30695 logdepthbuf_pars_fragment: logdepthbuf_pars_fragment, 30696 logdepthbuf_pars_vertex: logdepthbuf_pars_vertex, 30697 logdepthbuf_vertex: logdepthbuf_vertex, 30698 map_fragment: map_fragment, 30699 map_pars_fragment: map_pars_fragment, 30700 map_particle_fragment: map_particle_fragment, 30701 map_particle_pars_fragment: map_particle_pars_fragment, 30702 metalnessmap_fragment: metalnessmap_fragment, 30703 metalnessmap_pars_fragment: metalnessmap_pars_fragment, 30704 morphinstance_vertex: morphinstance_vertex, 30705 morphcolor_vertex: morphcolor_vertex, 30706 morphnormal_vertex: morphnormal_vertex, 30707 morphtarget_pars_vertex: morphtarget_pars_vertex, 30708 morphtarget_vertex: morphtarget_vertex, 30709 normal_fragment_begin: normal_fragment_begin, 30710 normal_fragment_maps: normal_fragment_maps, 30711 normal_pars_fragment: normal_pars_fragment, 30712 normal_pars_vertex: normal_pars_vertex, 30713 normal_vertex: normal_vertex, 30714 normalmap_pars_fragment: normalmap_pars_fragment, 30715 clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin, 30716 clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps, 30717 clearcoat_pars_fragment: clearcoat_pars_fragment, 30718 iridescence_pars_fragment: iridescence_pars_fragment, 30719 opaque_fragment: opaque_fragment, 30720 packing: packing, 30721 premultiplied_alpha_fragment: premultiplied_alpha_fragment, 30722 project_vertex: project_vertex, 30723 dithering_fragment: dithering_fragment, 30724 dithering_pars_fragment: dithering_pars_fragment, 30725 roughnessmap_fragment: roughnessmap_fragment, 30726 roughnessmap_pars_fragment: roughnessmap_pars_fragment, 30727 shadowmap_pars_fragment: shadowmap_pars_fragment, 30728 shadowmap_pars_vertex: shadowmap_pars_vertex, 30729 shadowmap_vertex: shadowmap_vertex, 30730 shadowmask_pars_fragment: shadowmask_pars_fragment, 30731 skinbase_vertex: skinbase_vertex, 30732 skinning_pars_vertex: skinning_pars_vertex, 30733 skinning_vertex: skinning_vertex, 30734 skinnormal_vertex: skinnormal_vertex, 30735 specularmap_fragment: specularmap_fragment, 30736 specularmap_pars_fragment: specularmap_pars_fragment, 30737 tonemapping_fragment: tonemapping_fragment, 30738 tonemapping_pars_fragment: tonemapping_pars_fragment, 30739 transmission_fragment: transmission_fragment, 30740 transmission_pars_fragment: transmission_pars_fragment, 30741 uv_pars_fragment: uv_pars_fragment, 30742 uv_pars_vertex: uv_pars_vertex, 30743 uv_vertex: uv_vertex, 30744 worldpos_vertex: worldpos_vertex, 30745 30746 background_vert: vertex$h, 30747 background_frag: fragment$h, 30748 backgroundCube_vert: vertex$g, 30749 backgroundCube_frag: fragment$g, 30750 cube_vert: vertex$f, 30751 cube_frag: fragment$f, 30752 depth_vert: vertex$e, 30753 depth_frag: fragment$e, 30754 distanceRGBA_vert: vertex$d, 30755 distanceRGBA_frag: fragment$d, 30756 equirect_vert: vertex$c, 30757 equirect_frag: fragment$c, 30758 linedashed_vert: vertex$b, 30759 linedashed_frag: fragment$b, 30760 meshbasic_vert: vertex$a, 30761 meshbasic_frag: fragment$a, 30762 meshlambert_vert: vertex$9, 30763 meshlambert_frag: fragment$9, 30764 meshmatcap_vert: vertex$8, 30765 meshmatcap_frag: fragment$8, 30766 meshnormal_vert: vertex$7, 30767 meshnormal_frag: fragment$7, 30768 meshphong_vert: vertex$6, 30769 meshphong_frag: fragment$6, 30770 meshphysical_vert: vertex$5, 30771 meshphysical_frag: fragment$5, 30772 meshtoon_vert: vertex$4, 30773 meshtoon_frag: fragment$4, 30774 points_vert: vertex$3, 30775 points_frag: fragment$3, 30776 shadow_vert: vertex$2, 30777 shadow_frag: fragment$2, 30778 sprite_vert: vertex$1, 30779 sprite_frag: fragment$1 30780}; 30781 30782// Uniforms library for shared webgl shaders 30783const UniformsLib = { 30784 30785 common: { 30786 30787 diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, 30788 opacity: { value: 1.0 }, 30789 30790 map: { value: null }, 30791 mapTransform: { value: /*@__PURE__*/ new Matrix3() }, 30792 30793 alphaMap: { value: null }, 30794 alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 30795 30796 alphaTest: { value: 0 } 30797 30798 }, 30799 30800 specularmap: { 30801 30802 specularMap: { value: null }, 30803 specularMapTransform: { value: /*@__PURE__*/ new Matrix3() } 30804 30805 }, 30806 30807 envmap: { 30808 30809 envMap: { value: null }, 30810 envMapRotation: { value: /*@__PURE__*/ new Matrix3() }, 30811 flipEnvMap: { value: -1 }, 30812 reflectivity: { value: 1.0 }, // basic, lambert, phong 30813 ior: { value: 1.5 }, // physical 30814 refractionRatio: { value: 0.98 }, // basic, lambert, phong 30815 30816 }, 30817 30818 aomap: { 30819 30820 aoMap: { value: null }, 30821 aoMapIntensity: { value: 1 }, 30822 aoMapTransform: { value: /*@__PURE__*/ new Matrix3() } 30823 30824 }, 30825 30826 lightmap: { 30827 30828 lightMap: { value: null }, 30829 lightMapIntensity: { value: 1 }, 30830 lightMapTransform: { value: /*@__PURE__*/ new Matrix3() } 30831 30832 }, 30833 30834 bumpmap: { 30835 30836 bumpMap: { value: null }, 30837 bumpMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 30838 bumpScale: { value: 1 } 30839 30840 }, 30841 30842 normalmap: { 30843 30844 normalMap: { value: null }, 30845 normalMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 30846 normalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) } 30847 30848 }, 30849 30850 displacementmap: { 30851 30852 displacementMap: { value: null }, 30853 displacementMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 30854 displacementScale: { value: 1 }, 30855 displacementBias: { value: 0 } 30856 30857 }, 30858 30859 emissivemap: { 30860 30861 emissiveMap: { value: null }, 30862 emissiveMapTransform: { value: /*@__PURE__*/ new Matrix3() } 30863 30864 }, 30865 30866 metalnessmap: { 30867 30868 metalnessMap: { value: null }, 30869 metalnessMapTransform: { value: /*@__PURE__*/ new Matrix3() } 30870 30871 }, 30872 30873 roughnessmap: { 30874 30875 roughnessMap: { value: null }, 30876 roughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() } 30877 30878 }, 30879 30880 gradientmap: { 30881 30882 gradientMap: { value: null } 30883 30884 }, 30885 30886 fog: { 30887 30888 fogDensity: { value: 0.00025 }, 30889 fogNear: { value: 1 }, 30890 fogFar: { value: 2000 }, 30891 fogColor: { value: /*@__PURE__*/ new Color( 0xffffff ) } 30892 30893 }, 30894 30895 lights: { 30896 30897 ambientLightColor: { value: [] }, 30898 30899 lightProbe: { value: [] }, 30900 30901 directionalLights: { value: [], properties: { 30902 direction: {}, 30903 color: {} 30904 } }, 30905 30906 directionalLightShadows: { value: [], properties: { 30907 shadowIntensity: 1, 30908 shadowBias: {}, 30909 shadowNormalBias: {}, 30910 shadowRadius: {}, 30911 shadowMapSize: {} 30912 } }, 30913 30914 directionalShadowMap: { value: [] }, 30915 directionalShadowMatrix: { value: [] }, 30916 30917 spotLights: { value: [], properties: { 30918 color: {}, 30919 position: {}, 30920 direction: {}, 30921 distance: {}, 30922 coneCos: {}, 30923 penumbraCos: {}, 30924 decay: {} 30925 } }, 30926 30927 spotLightShadows: { value: [], properties: { 30928 shadowIntensity: 1, 30929 shadowBias: {}, 30930 shadowNormalBias: {}, 30931 shadowRadius: {}, 30932 shadowMapSize: {} 30933 } }, 30934 30935 spotLightMap: { value: [] }, 30936 spotShadowMap: { value: [] }, 30937 spotLightMatrix: { value: [] }, 30938 30939 pointLights: { value: [], properties: { 30940 color: {}, 30941 position: {}, 30942 decay: {}, 30943 distance: {} 30944 } }, 30945 30946 pointLightShadows: { value: [], properties: { 30947 shadowIntensity: 1, 30948 shadowBias: {}, 30949 shadowNormalBias: {}, 30950 shadowRadius: {}, 30951 shadowMapSize: {}, 30952 shadowCameraNear: {}, 30953 shadowCameraFar: {} 30954 } }, 30955 30956 pointShadowMap: { value: [] }, 30957 pointShadowMatrix: { value: [] }, 30958 30959 hemisphereLights: { value: [], properties: { 30960 direction: {}, 30961 skyColor: {}, 30962 groundColor: {} 30963 } }, 30964 30965 // TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src 30966 rectAreaLights: { value: [], properties: { 30967 color: {}, 30968 position: {}, 30969 width: {}, 30970 height: {} 30971 } }, 30972 30973 ltc_1: { value: null }, 30974 ltc_2: { value: null } 30975 30976 }, 30977 30978 points: { 30979 30980 diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, 30981 opacity: { value: 1.0 }, 30982 size: { value: 1.0 }, 30983 scale: { value: 1.0 }, 30984 map: { value: null }, 30985 alphaMap: { value: null }, 30986 alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 30987 alphaTest: { value: 0 }, 30988 uvTransform: { value: /*@__PURE__*/ new Matrix3() } 30989 30990 }, 30991 30992 sprite: { 30993 30994 diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, 30995 opacity: { value: 1.0 }, 30996 center: { value: /*@__PURE__*/ new Vector2( 0.5, 0.5 ) }, 30997 rotation: { value: 0.0 }, 30998 map: { value: null }, 30999 mapTransform: { value: /*@__PURE__*/ new Matrix3() }, 31000 alphaMap: { value: null }, 31001 alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 31002 alphaTest: { value: 0 } 31003 31004 } 31005 31006}; 31007 31008const ShaderLib = { 31009 31010 basic: { 31011 31012 uniforms: /*@__PURE__*/ mergeUniforms( [ 31013 UniformsLib.common, 31014 UniformsLib.specularmap, 31015 UniformsLib.envmap, 31016 UniformsLib.aomap, 31017 UniformsLib.lightmap, 31018 UniformsLib.fog 31019 ] ), 31020 31021 vertexShader: ShaderChunk.meshbasic_vert, 31022 fragmentShader: ShaderChunk.meshbasic_frag 31023 31024 }, 31025 31026 lambert: { 31027 31028 uniforms: /*@__PURE__*/ mergeUniforms( [ 31029 UniformsLib.common, 31030 UniformsLib.specularmap, 31031 UniformsLib.envmap, 31032 UniformsLib.aomap, 31033 UniformsLib.lightmap, 31034 UniformsLib.emissivemap, 31035 UniformsLib.bumpmap, 31036 UniformsLib.normalmap, 31037 UniformsLib.displacementmap, 31038 UniformsLib.fog, 31039 UniformsLib.lights, 31040 { 31041 emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) } 31042 } 31043 ] ), 31044 31045 vertexShader: ShaderChunk.meshlambert_vert, 31046 fragmentShader: ShaderChunk.meshlambert_frag 31047 31048 }, 31049 31050 phong: { 31051 31052 uniforms: /*@__PURE__*/ mergeUniforms( [ 31053 UniformsLib.common, 31054 UniformsLib.specularmap, 31055 UniformsLib.envmap, 31056 UniformsLib.aomap, 31057 UniformsLib.lightmap, 31058 UniformsLib.emissivemap, 31059 UniformsLib.bumpmap, 31060 UniformsLib.normalmap, 31061 UniformsLib.displacementmap, 31062 UniformsLib.fog, 31063 UniformsLib.lights, 31064 { 31065 emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }, 31066 specular: { value: /*@__PURE__*/ new Color( 0x111111 ) }, 31067 shininess: { value: 30 } 31068 } 31069 ] ), 31070 31071 vertexShader: ShaderChunk.meshphong_vert, 31072 fragmentShader: ShaderChunk.meshphong_frag 31073 31074 }, 31075 31076 standard: { 31077 31078 uniforms: /*@__PURE__*/ mergeUniforms( [ 31079 UniformsLib.common, 31080 UniformsLib.envmap, 31081 UniformsLib.aomap, 31082 UniformsLib.lightmap, 31083 UniformsLib.emissivemap, 31084 UniformsLib.bumpmap, 31085 UniformsLib.normalmap, 31086 UniformsLib.displacementmap, 31087 UniformsLib.roughnessmap, 31088 UniformsLib.metalnessmap, 31089 UniformsLib.fog, 31090 UniformsLib.lights, 31091 { 31092 emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }, 31093 roughness: { value: 1.0 }, 31094 metalness: { value: 0.0 }, 31095 envMapIntensity: { value: 1 } 31096 } 31097 ] ), 31098 31099 vertexShader: ShaderChunk.meshphysical_vert, 31100 fragmentShader: ShaderChunk.meshphysical_frag 31101 31102 }, 31103 31104 toon: { 31105 31106 uniforms: /*@__PURE__*/ mergeUniforms( [ 31107 UniformsLib.common, 31108 UniformsLib.aomap, 31109 UniformsLib.lightmap, 31110 UniformsLib.emissivemap, 31111 UniformsLib.bumpmap, 31112 UniformsLib.normalmap, 31113 UniformsLib.displacementmap, 31114 UniformsLib.gradientmap, 31115 UniformsLib.fog, 31116 UniformsLib.lights, 31117 { 31118 emissive: { value: /*@__PURE__*/ new Color( 0x000000 ) } 31119 } 31120 ] ), 31121 31122 vertexShader: ShaderChunk.meshtoon_vert, 31123 fragmentShader: ShaderChunk.meshtoon_frag 31124 31125 }, 31126 31127 matcap: { 31128 31129 uniforms: /*@__PURE__*/ mergeUniforms( [ 31130 UniformsLib.common, 31131 UniformsLib.bumpmap, 31132 UniformsLib.normalmap, 31133 UniformsLib.displacementmap, 31134 UniformsLib.fog, 31135 {
vendor: 6,435 bytes, lines 31136-31399
31136 matcap: { value: null } 31137 } 31138 ] ), 31139 31140 vertexShader: ShaderChunk.meshmatcap_vert, 31141 fragmentShader: ShaderChunk.meshmatcap_frag 31142 31143 }, 31144 31145 points: { 31146 31147 uniforms: /*@__PURE__*/ mergeUniforms( [ 31148 UniformsLib.points, 31149 UniformsLib.fog 31150 ] ), 31151 31152 vertexShader: ShaderChunk.points_vert, 31153 fragmentShader: ShaderChunk.points_frag 31154 31155 }, 31156 31157 dashed: { 31158 31159 uniforms: /*@__PURE__*/ mergeUniforms( [ 31160 UniformsLib.common, 31161 UniformsLib.fog, 31162 { 31163 scale: { value: 1 }, 31164 dashSize: { value: 1 }, 31165 totalSize: { value: 2 } 31166 } 31167 ] ), 31168 31169 vertexShader: ShaderChunk.linedashed_vert, 31170 fragmentShader: ShaderChunk.linedashed_frag 31171 31172 }, 31173 31174 depth: { 31175 31176 uniforms: /*@__PURE__*/ mergeUniforms( [ 31177 UniformsLib.common, 31178 UniformsLib.displacementmap 31179 ] ), 31180 31181 vertexShader: ShaderChunk.depth_vert, 31182 fragmentShader: ShaderChunk.depth_frag 31183 31184 }, 31185 31186 normal: { 31187 31188 uniforms: /*@__PURE__*/ mergeUniforms( [ 31189 UniformsLib.common, 31190 UniformsLib.bumpmap, 31191 UniformsLib.normalmap, 31192 UniformsLib.displacementmap, 31193 { 31194 opacity: { value: 1.0 } 31195 } 31196 ] ), 31197 31198 vertexShader: ShaderChunk.meshnormal_vert, 31199 fragmentShader: ShaderChunk.meshnormal_frag 31200 31201 }, 31202 31203 sprite: { 31204 31205 uniforms: /*@__PURE__*/ mergeUniforms( [ 31206 UniformsLib.sprite, 31207 UniformsLib.fog 31208 ] ), 31209 31210 vertexShader: ShaderChunk.sprite_vert, 31211 fragmentShader: ShaderChunk.sprite_frag 31212 31213 }, 31214 31215 background: { 31216 31217 uniforms: { 31218 uvTransform: { value: /*@__PURE__*/ new Matrix3() }, 31219 t2D: { value: null }, 31220 backgroundIntensity: { value: 1 } 31221 }, 31222 31223 vertexShader: ShaderChunk.background_vert, 31224 fragmentShader: ShaderChunk.background_frag 31225 31226 }, 31227 31228 backgroundCube: { 31229 31230 uniforms: { 31231 envMap: { value: null }, 31232 flipEnvMap: { value: -1 }, 31233 backgroundBlurriness: { value: 0 }, 31234 backgroundIntensity: { value: 1 }, 31235 backgroundRotation: { value: /*@__PURE__*/ new Matrix3() } 31236 }, 31237 31238 vertexShader: ShaderChunk.backgroundCube_vert, 31239 fragmentShader: ShaderChunk.backgroundCube_frag 31240 31241 }, 31242 31243 cube: { 31244 31245 uniforms: { 31246 tCube: { value: null }, 31247 tFlip: { value: -1 }, 31248 opacity: { value: 1.0 } 31249 }, 31250 31251 vertexShader: ShaderChunk.cube_vert, 31252 fragmentShader: ShaderChunk.cube_frag 31253 31254 }, 31255 31256 equirect: { 31257 31258 uniforms: { 31259 tEquirect: { value: null }, 31260 }, 31261 31262 vertexShader: ShaderChunk.equirect_vert, 31263 fragmentShader: ShaderChunk.equirect_frag 31264 31265 }, 31266 31267 distanceRGBA: { 31268 31269 uniforms: /*@__PURE__*/ mergeUniforms( [ 31270 UniformsLib.common, 31271 UniformsLib.displacementmap, 31272 { 31273 referencePosition: { value: /*@__PURE__*/ new Vector3() }, 31274 nearDistance: { value: 1 }, 31275 farDistance: { value: 1000 } 31276 } 31277 ] ), 31278 31279 vertexShader: ShaderChunk.distanceRGBA_vert, 31280 fragmentShader: ShaderChunk.distanceRGBA_frag 31281 31282 }, 31283 31284 shadow: { 31285 31286 uniforms: /*@__PURE__*/ mergeUniforms( [ 31287 UniformsLib.lights, 31288 UniformsLib.fog, 31289 { 31290 color: { value: /*@__PURE__*/ new Color( 0x00000 ) }, 31291 opacity: { value: 1.0 } 31292 }, 31293 ] ), 31294 31295 vertexShader: ShaderChunk.shadow_vert, 31296 fragmentShader: ShaderChunk.shadow_frag 31297 31298 } 31299 31300}; 31301 31302ShaderLib.physical = { 31303 31304 uniforms: /*@__PURE__*/ mergeUniforms( [ 31305 ShaderLib.standard.uniforms, 31306 { 31307 clearcoat: { value: 0 }, 31308 clearcoatMap: { value: null }, 31309 clearcoatMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 31310 clearcoatNormalMap: { value: null }, 31311 clearcoatNormalMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 31312 clearcoatNormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) }, 31313 clearcoatRoughness: { value: 0 }, 31314 clearcoatRoughnessMap: { value: null }, 31315 clearcoatRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 31316 dispersion: { value: 0 }, 31317 iridescence: { value: 0 }, 31318 iridescenceMap: { value: null }, 31319 iridescenceMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 31320 iridescenceIOR: { value: 1.3 }, 31321 iridescenceThicknessMinimum: { value: 100 }, 31322 iridescenceThicknessMaximum: { value: 400 }, 31323 iridescenceThicknessMap: { value: null }, 31324 iridescenceThicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 31325 sheen: { value: 0 }, 31326 sheenColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, 31327 sheenColorMap: { value: null }, 31328 sheenColorMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 31329 sheenRoughness: { value: 1 }, 31330 sheenRoughnessMap: { value: null }, 31331 sheenRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 31332 transmission: { value: 0 }, 31333 transmissionMap: { value: null }, 31334 transmissionMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 31335 transmissionSamplerSize: { value: /*@__PURE__*/ new Vector2() }, 31336 transmissionSamplerMap: { value: null }, 31337 thickness: { value: 0 }, 31338 thicknessMap: { value: null }, 31339 thicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 31340 attenuationDistance: { value: 0 }, 31341 attenuationColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, 31342 specularColor: { value: /*@__PURE__*/ new Color( 1, 1, 1 ) }, 31343 specularColorMap: { value: null }, 31344 specularColorMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 31345 specularIntensity: { value: 1 }, 31346 specularIntensityMap: { value: null }, 31347 specularIntensityMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 31348 anisotropyVector: { value: /*@__PURE__*/ new Vector2() }, 31349 anisotropyMap: { value: null }, 31350 anisotropyMapTransform: { value: /*@__PURE__*/ new Matrix3() }, 31351 } 31352 ] ), 31353 31354 vertexShader: ShaderChunk.meshphysical_vert, 31355 fragmentShader: ShaderChunk.meshphysical_frag 31356 31357}; 31358 31359const _box$1 = new Box3(); 31360const _vector = new Vector3(); 31361 31362/** 31363 * A series of vertex pairs, forming line segments. 31364 * 31365 * This is used in {@link LineSegments2} to describe the shape. 31366 * 31367 * @augments InstancedBufferGeometry 31368 * @three_import import { LineSegmentsGeometry } from 'three/addons/lines/LineSegmentsGeometry.js'; 31369 */ 31370class LineSegmentsGeometry extends InstancedBufferGeometry { 31371 31372 /** 31373 * Constructs a new line segments geometry. 31374 */ 31375 constructor() { 31376 31377 super(); 31378 31379 /** 31380 * This flag can be used for type testing. 31381 * 31382 * @type {boolean} 31383 * @readonly 31384 * @default true 31385 */ 31386 this.isLineSegmentsGeometry = true; 31387 31388 this.type = 'LineSegmentsGeometry'; 31389 31390 const positions = [ - 1, 2, 0, 1, 2, 0, - 1, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 0, - 1, - 1, 0, 1, - 1, 0 ]; 31391 const uvs = [ - 1, 2, 1, 2, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 2, 1, - 2 ]; 31392 const index = [ 0, 2, 1, 2, 3, 1, 2, 4, 3, 4, 5, 3, 4, 6, 5, 6, 7, 5 ]; 31393 31394 this.setIndex( index ); 31395 this.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); 31396 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 31397 31398 } 31399
vendor: 6,346 bytes, lines 31400-31681
31400 /** 31401 * Applies the given 4x4 transformation matrix to the geometry. 31402 * 31403 * @param {Matrix4} matrix - The matrix to apply. 31404 * @return {LineSegmentsGeometry} A reference to this instance. 31405 */ 31406 applyMatrix4( matrix ) { 31407 31408 const start = this.attributes.instanceStart; 31409 const end = this.attributes.instanceEnd; 31410 31411 if ( start !== undefined ) { 31412 31413 start.applyMatrix4( matrix ); 31414 31415 end.applyMatrix4( matrix ); 31416 31417 start.needsUpdate = true; 31418 31419 } 31420 31421 if ( this.boundingBox !== null ) { 31422 31423 this.computeBoundingBox(); 31424 31425 } 31426 31427 if ( this.boundingSphere !== null ) { 31428 31429 this.computeBoundingSphere(); 31430 31431 } 31432 31433 return this; 31434 31435 } 31436 31437 /** 31438 * Sets the given line positions for this geometry. The length must be a multiple of six since 31439 * each line segment is defined by a start end vertex in the pattern `(xyz xyz)`. 31440 * 31441 * @param {Float32Array|Array<number>} array - The position data to set. 31442 * @return {LineSegmentsGeometry} A reference to this geometry. 31443 */ 31444 setPositions( array ) { 31445 31446 let lineSegments; 31447 31448 if ( array instanceof Float32Array ) { 31449 31450 lineSegments = array; 31451 31452 } else if ( Array.isArray( array ) ) { 31453 31454 lineSegments = new Float32Array( array ); 31455 31456 } 31457 31458 const instanceBuffer = new InstancedInterleavedBuffer( lineSegments, 6, 1 ); // xyz, xyz 31459 31460 this.setAttribute( 'instanceStart', new InterleavedBufferAttribute( instanceBuffer, 3, 0 ) ); // xyz 31461 this.setAttribute( 'instanceEnd', new InterleavedBufferAttribute( instanceBuffer, 3, 3 ) ); // xyz 31462 31463 this.instanceCount = this.attributes.instanceStart.count; 31464 31465 // 31466 31467 this.computeBoundingBox(); 31468 this.computeBoundingSphere(); 31469 31470 return this; 31471 31472 } 31473 31474 /** 31475 * Sets the given line colors for this geometry. The length must be a multiple of six since 31476 * each line segment is defined by a start end color in the pattern `(rgb rgb)`. 31477 * 31478 * @param {Float32Array|Array<number>} array - The position data to set. 31479 * @return {LineSegmentsGeometry} A reference to this geometry. 31480 */ 31481 setColors( array ) { 31482 31483 let colors; 31484 31485 if ( array instanceof Float32Array ) { 31486 31487 colors = array; 31488 31489 } else if ( Array.isArray( array ) ) { 31490 31491 colors = new Float32Array( array ); 31492 31493 } 31494 31495 const instanceColorBuffer = new InstancedInterleavedBuffer( colors, 6, 1 ); // rgb, rgb 31496 31497 this.setAttribute( 'instanceColorStart', new InterleavedBufferAttribute( instanceColorBuffer, 3, 0 ) ); // rgb 31498 this.setAttribute( 'instanceColorEnd', new InterleavedBufferAttribute( instanceColorBuffer, 3, 3 ) ); // rgb 31499 31500 return this; 31501 31502 } 31503 31504 /** 31505 * Setups this line segments geometry from the given wireframe geometry. 31506 * 31507 * @param {WireframeGeometry} geometry - The geometry that should be used as a data source for this geometry. 31508 * @return {LineSegmentsGeometry} A reference to this geometry. 31509 */ 31510 fromWireframeGeometry( geometry ) { 31511 31512 this.setPositions( geometry.attributes.position.array ); 31513 31514 return this; 31515 31516 } 31517 31518 /** 31519 * Setups this line segments geometry from the given edges geometry. 31520 * 31521 * @param {EdgesGeometry} geometry - The geometry that should be used as a data source for this geometry. 31522 * @return {LineSegmentsGeometry} A reference to this geometry. 31523 */ 31524 fromEdgesGeometry( geometry ) { 31525 31526 this.setPositions( geometry.attributes.position.array ); 31527 31528 return this; 31529 31530 } 31531 31532 /** 31533 * Setups this line segments geometry from the given mesh. 31534 * 31535 * @param {Mesh} mesh - The mesh geometry that should be used as a data source for this geometry. 31536 * @return {LineSegmentsGeometry} A reference to this geometry. 31537 */ 31538 fromMesh( mesh ) { 31539 31540 this.fromWireframeGeometry( new WireframeGeometry( mesh.geometry ) ); 31541 31542 // set colors, maybe 31543 31544 return this; 31545 31546 } 31547 31548 /** 31549 * Setups this line segments geometry from the given line segments. 31550 * 31551 * @param {LineSegments} lineSegments - The line segments that should be used as a data source for this geometry. 31552 * Assumes the source geometry is not using indices. 31553 * @return {LineSegmentsGeometry} A reference to this geometry. 31554 */ 31555 fromLineSegments( lineSegments ) { 31556 31557 const geometry = lineSegments.geometry; 31558 31559 this.setPositions( geometry.attributes.position.array ); // assumes non-indexed 31560 31561 // set colors, maybe 31562 31563 return this; 31564 31565 } 31566 31567 computeBoundingBox() { 31568 31569 if ( this.boundingBox === null ) { 31570 31571 this.boundingBox = new Box3(); 31572 31573 } 31574 31575 const start = this.attributes.instanceStart; 31576 const end = this.attributes.instanceEnd; 31577 31578 if ( start !== undefined && end !== undefined ) { 31579 31580 this.boundingBox.setFromBufferAttribute( start ); 31581 31582 _box$1.setFromBufferAttribute( end ); 31583 31584 this.boundingBox.union( _box$1 ); 31585 31586 } 31587 31588 } 31589 31590 computeBoundingSphere() { 31591 31592 if ( this.boundingSphere === null ) { 31593 31594 this.boundingSphere = new Sphere(); 31595 31596 } 31597 31598 if ( this.boundingBox === null ) { 31599 31600 this.computeBoundingBox(); 31601 31602 } 31603 31604 const start = this.attributes.instanceStart; 31605 const end = this.attributes.instanceEnd; 31606 31607 if ( start !== undefined && end !== undefined ) { 31608 31609 const center = this.boundingSphere.center; 31610 31611 this.boundingBox.getCenter( center ); 31612 31613 let maxRadiusSq = 0; 31614 31615 for ( let i = 0, il = start.count; i < il; i ++ ) { 31616 31617 _vector.fromBufferAttribute( start, i ); 31618 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector ) ); 31619 31620 _vector.fromBufferAttribute( end, i ); 31621 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector ) ); 31622 31623 } 31624 31625 this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); 31626 31627 if ( isNaN( this.boundingSphere.radius ) ) { 31628 31629 console.error( 'THREE.LineSegmentsGeometry.computeBoundingSphere(): Computed radius is NaN. The instanced position data is likely to have NaN values.', this ); 31630 31631 } 31632 31633 } 31634 31635 } 31636 31637 toJSON() { 31638 31639 // todo 31640 31641 } 31642 31643} 31644 31645UniformsLib.line = { 31646 31647 worldUnits: { value: 1 }, 31648 linewidth: { value: 1 }, 31649 resolution: { value: new Vector2( 1, 1 ) }, 31650 dashOffset: { value: 0 }, 31651 dashScale: { value: 1 }, 31652 dashSize: { value: 1 }, 31653 gapSize: { value: 1 } // todo FIX - maybe change to totalSize 31654 31655}; 31656 31657ShaderLib[ 'line' ] = { 31658 31659 uniforms: UniformsUtils.merge( [ 31660 UniformsLib.common, 31661 UniformsLib.fog, 31662 UniformsLib.line 31663 ] ), 31664 31665 vertexShader: 31666 /* glsl */` 31667 #include <common> 31668 #include <color_pars_vertex> 31669 #include <fog_pars_vertex> 31670 #include <logdepthbuf_pars_vertex> 31671 #include <clipping_planes_pars_vertex> 31672 31673 uniform float linewidth; 31674 uniform vec2 resolution; 31675 31676 attribute vec3 instanceStart; 31677 attribute vec3 instanceEnd; 31678 31679 attribute vec3 instanceColorStart; 31680 attribute vec3 instanceColorEnd; 31681
31682 #ifdef WORLD_UNITS 31683 31684 varying vec4 worldPos; 31685 varying vec3 worldStart; 31686 varying vec3 worldEnd; 31687 31688 #ifdef USE_DASH 31689 31690 varying vec2 vUv; 31691 31692 #endif 31693 31694 #else 31695 31696 varying vec2 vUv; 31697 31698 #endif 31699 31700 #ifdef USE_DASH 31701 31702 uniform float dashScale; 31703 attribute float instanceDistanceStart; 31704 attribute float instanceDistanceEnd; 31705 varying float vLineDistance; 31706 31707 #endif 31708 31709 void trimSegment( const in vec4 start, inout vec4 end ) { 31710 31711 // trim end segment so it terminates between the camera plane and the near plane 31712 31713 // conservative estimate of the near plane 31714 float a = projectionMatrix[ 2 ][ 2 ]; // 3nd entry in 3th column 31715 float b = projectionMatrix[ 3 ][ 2 ]; // 3nd entry in 4th column 31716 float nearEstimate = - 0.5 * b / a; 31717 31718 float alpha = ( nearEstimate - start.z ) / ( end.z - start.z ); 31719 31720 end.xyz = mix( start.xyz, end.xyz, alpha ); 31721 31722 } 31723 31724 void main() { 31725 31726 #ifdef USE_COLOR 31727 31728 vColor.xyz = ( position.y < 0.5 ) ? instanceColorStart : instanceColorEnd; 31729 31730 #endif 31731 31732 #ifdef USE_DASH 31733 31734 vLineDistance = ( position.y < 0.5 ) ? dashScale * instanceDistanceStart : dashScale * instanceDistanceEnd; 31735 vUv = uv; 31736 31737 #endif 31738 31739 float aspect = resolution.x / resolution.y; 31740 31741 // camera space 31742 vec4 start = modelViewMatrix * vec4( instanceStart, 1.0 ); 31743 vec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 ); 31744 31745 #ifdef WORLD_UNITS 31746 31747 worldStart = start.xyz; 31748 worldEnd = end.xyz; 31749 31750 #else 31751 31752 vUv = uv; 31753 31754 #endif 31755 31756 // special case for perspective projection, and segments that terminate either in, or behind, the camera plane 31757 // clearly the gpu firmware has a way of addressing this issue when projecting into ndc space 31758 // but we need to perform ndc-space calculations in the shader, so we must address this issue directly 31759 // perhaps there is a more elegant solution -- WestLangley 31760 31761 bool perspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 ); // 4th entry in the 3rd column 31762 31763 if ( perspective ) { 31764 31765 if ( start.z < 0.0 && end.z >= 0.0 ) { 31766 31767 trimSegment( start, end ); 31768 31769 } else if ( end.z < 0.0 && start.z >= 0.0 ) { 31770 31771 trimSegment( end, start ); 31772 31773 } 31774 31775 } 31776 31777 // clip space 31778 vec4 clipStart = projectionMatrix * start; 31779 vec4 clipEnd = projectionMatrix * end; 31780 31781 // ndc space 31782 vec3 ndcStart = clipStart.xyz / clipStart.w; 31783 vec3 ndcEnd = clipEnd.xyz / clipEnd.w; 31784 31785 // direction 31786 vec2 dir = ndcEnd.xy - ndcStart.xy; 31787 31788 // account for clip-space aspect ratio 31789 dir.x *= aspect; 31790 dir = normalize( dir ); 31791 31792 #ifdef WORLD_UNITS 31793 31794 vec3 worldDir = normalize( end.xyz - start.xyz ); 31795 vec3 tmpFwd = normalize( mix( start.xyz, end.xyz, 0.5 ) ); 31796 vec3 worldUp = normalize( cross( worldDir, tmpFwd ) ); 31797 vec3 worldFwd = cross( worldDir, worldUp ); 31798 worldPos = position.y < 0.5 ? start: end; 31799 31800 // height offset 31801 float hw = linewidth * 0.5; 31802 worldPos.xyz += position.x < 0.0 ? hw * worldUp : - hw * worldUp; 31803 31804 // don't extend the line if we're rendering dashes because we 31805 // won't be rendering the endcaps 31806 #ifndef USE_DASH 31807 31808 // cap extension 31809 worldPos.xyz += position.y < 0.5 ? - hw * worldDir : hw * worldDir; 31810 31811 // add width to the box 31812 worldPos.xyz += worldFwd * hw; 31813 31814 // endcaps 31815 if ( position.y > 1.0 || position.y < 0.0 ) { 31816 31817 worldPos.xyz -= worldFwd * 2.0 * hw; 31818 31819 } 31820 31821 #endif 31822 31823 // project the worldpos 31824 vec4 clip = projectionMatrix * worldPos; 31825 31826 // shift the depth of the projected points so the line 31827 // segments overlap neatly 31828 vec3 clipPose = ( position.y < 0.5 ) ? ndcStart : ndcEnd; 31829 clip.z = clipPose.z * clip.w; 31830 31831 #else 31832 31833 vec2 offset = vec2( dir.y, - dir.x ); 31834 // undo aspect ratio adjustment 31835 dir.x /= aspect; 31836 offset.x /= aspect; 31837 31838 // sign flip 31839 if ( position.x < 0.0 ) offset *= - 1.0; 31840 31841 // endcaps 31842 if ( position.y < 0.0 ) { 31843 31844 offset += - dir; 31845 31846 } else if ( position.y > 1.0 ) { 31847 31848 offset += dir; 31849 31850 } 31851 31852 // adjust for linewidth 31853 offset *= linewidth; 31854 31855 // adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ... 31856 offset /= resolution.y; 31857 31858 // select end 31859 vec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd; 31860 31861 // back to clip space 31862 offset *= clip.w; 31863 31864 clip.xy += offset; 31865 31866 #endif 31867 31868 gl_Position = clip; 31869 31870 vec4 mvPosition = ( position.y < 0.5 ) ? start : end; // this is an approximation 31871 31872 #include <logdepthbuf_vertex> 31873 #include <clipping_planes_vertex> 31874 #include <fog_vertex> 31875 31876 } 31877 `, 31878 31879 fragmentShader: 31880 /* glsl */` 31881 uniform vec3 diffuse; 31882 uniform float opacity; 31883 uniform float linewidth; 31884 31885 #ifdef USE_DASH 31886 31887 uniform float dashOffset; 31888 uniform float dashSize; 31889 uniform float gapSize; 31890 31891 #endif 31892 31893 varying float vLineDistance; 31894 31895 #ifdef WORLD_UNITS 31896 31897 varying vec4 worldPos; 31898 varying vec3 worldStart; 31899 varying vec3 worldEnd; 31900 31901 #ifdef USE_DASH 31902 31903 varying vec2 vUv; 31904 31905 #endif 31906 31907 #else 31908 31909 varying vec2 vUv; 31910 31911 #endif 31912 31913 #include <common> 31914 #include <color_pars_fragment> 31915 #include <fog_pars_fragment> 31916 #include <logdepthbuf_pars_fragment> 31917 #include <clipping_planes_pars_fragment> 31918 31919 vec2 closestLineToLine(vec3 p1, vec3 p2, vec3 p3, vec3 p4) { 31920 31921 float mua; 31922 float mub; 31923 31924 vec3 p13 = p1 - p3; 31925 vec3 p43 = p4 - p3; 31926 31927 vec3 p21 = p2 - p1; 31928 31929 float d1343 = dot( p13, p43 );
31930 float d4321 = dot( p43, p21 ); 31931 float d1321 = dot( p13, p21 ); 31932 float d4343 = dot( p43, p43 ); 31933 float d2121 = dot( p21, p21 ); 31934 31935 float denom = d2121 * d4343 - d4321 * d4321; 31936 31937 float numer = d1343 * d4321 - d1321 * d4343; 31938 31939 mua = numer / denom; 31940 mua = clamp( mua, 0.0, 1.0 ); 31941 mub = ( d1343 + d4321 * ( mua ) ) / d4343; 31942 mub = clamp( mub, 0.0, 1.0 ); 31943 31944 return vec2( mua, mub ); 31945 31946 } 31947 31948 void main() { 31949 31950 float alpha = opacity; 31951 vec4 diffuseColor = vec4( diffuse, alpha ); 31952 31953 #include <clipping_planes_fragment> 31954 31955 #ifdef USE_DASH 31956 31957 if ( vUv.y < - 1.0 || vUv.y > 1.0 ) discard; // discard endcaps 31958 31959 if ( mod( vLineDistance + dashOffset, dashSize + gapSize ) > dashSize ) discard; // todo - FIX 31960 31961 #endif 31962 31963 #ifdef WORLD_UNITS 31964 31965 // Find the closest points on the view ray and the line segment 31966 vec3 rayEnd = normalize( worldPos.xyz ) * 1e5; 31967 vec3 lineDir = worldEnd - worldStart; 31968 vec2 params = closestLineToLine( worldStart, worldEnd, vec3( 0.0, 0.0, 0.0 ), rayEnd ); 31969 31970 vec3 p1 = worldStart + lineDir * params.x; 31971 vec3 p2 = rayEnd * params.y; 31972 vec3 delta = p1 - p2; 31973 float len = length( delta ); 31974 float norm = len / linewidth; 31975 31976 #ifndef USE_DASH 31977 31978 #ifdef USE_ALPHA_TO_COVERAGE 31979 31980 float dnorm = fwidth( norm ); 31981 alpha = 1.0 - smoothstep( 0.5 - dnorm, 0.5 + dnorm, norm ); 31982 31983 #else 31984 31985 if ( norm > 0.5 ) { 31986 31987 discard; 31988 31989 } 31990 31991 #endif 31992 31993 #endif 31994 31995 #else 31996 31997 #ifdef USE_ALPHA_TO_COVERAGE 31998 31999 // artifacts appear on some hardware if a derivative is taken within a conditional 32000 float a = vUv.x; 32001 float b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0; 32002 float len2 = a * a + b * b; 32003 float dlen = fwidth( len2 ); 32004 32005 if ( abs( vUv.y ) > 1.0 ) { 32006 32007 alpha = 1.0 - smoothstep( 1.0 - dlen, 1.0 + dlen, len2 ); 32008 32009 } 32010 32011 #else 32012 32013 if ( abs( vUv.y ) > 1.0 ) { 32014 32015 float a = vUv.x; 32016 float b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0; 32017 float len2 = a * a + b * b; 32018 32019 if ( len2 > 1.0 ) discard; 32020 32021 } 32022 32023 #endif 32024 32025 #endif 32026 32027 #include <logdepthbuf_fragment> 32028 #include <color_fragment> 32029 32030 gl_FragColor = vec4( diffuseColor.rgb, alpha ); 32031 32032 #include <tonemapping_fragment> 32033 #include <colorspace_fragment> 32034 #include <fog_fragment> 32035 #include <premultiplied_alpha_fragment> 32036 32037 } 32038 ` 32039}; 32040 32041/** 32042 * A material for drawing wireframe-style geometries. 32043 * 32044 * Unlike {@link LineBasicMaterial}, it supports arbitrary line widths and allows using world units 32045 * instead of screen space units. This material is used with {@link LineSegments2} and {@link Line2}. 32046 * 32047 * This module can only be used with {@link WebGLRenderer}. When using {@link WebGPURenderer}, 32048 * use {@link Line2NodeMaterial}. 32049 * 32050 * @augments ShaderMaterial 32051 * @three_import import { LineMaterial } from 'three/addons/lines/LineMaterial.js'; 32052 */ 32053class LineMaterial extends ShaderMaterial { 32054 32055 /** 32056 * Constructs a new line segments geometry. 32057 * 32058 * @param {Object} [parameters] - An object with one or more properties 32059 * defining the material's appearance. Any property of the material 32060 * (including any property from inherited materials) can be passed 32061 * in here. Color values can be passed any type of value accepted 32062 * by {@link Color#set}. 32063 */ 32064 constructor( parameters ) { 32065 32066 super( { 32067 32068 type: 'LineMaterial', 32069 uniforms: UniformsUtils.clone( ShaderLib[ 'line' ].uniforms ), 32070 32071 vertexShader: ShaderLib[ 'line' ].vertexShader, 32072 fragmentShader: ShaderLib[ 'line' ].fragmentShader, 32073 32074 clipping: true // required for clipping support 32075 32076 } ); 32077 32078 /** 32079 * This flag can be used for type testing. 32080 * 32081 * @type {boolean} 32082 * @readonly 32083 * @default true 32084 */ 32085 this.isLineMaterial = true; 32086 32087 this.setValues( parameters ); 32088 32089 } 32090 32091 /** 32092 * The material's color. 32093 * 32094 * @type {Color} 32095 * @default (1,1,1) 32096 */ 32097 get color() { 32098 32099 return this.uniforms.diffuse.value; 32100 32101 } 32102 32103 set color( value ) { 32104 32105 this.uniforms.diffuse.value = value; 32106 32107 } 32108 32109 /** 32110 * Whether the material's sizes (width, dash gaps) are in world units. 32111 * 32112 * @type {boolean} 32113 * @default false 32114 */ 32115 get worldUnits() { 32116 32117 return 'WORLD_UNITS' in this.defines; 32118 32119 } 32120 32121 set worldUnits( value ) { 32122 32123 if ( value === true ) { 32124 32125 this.defines.WORLD_UNITS = ''; 32126 32127 } else { 32128 32129 delete this.defines.WORLD_UNITS; 32130 32131 } 32132 32133 } 32134
vendor: 11,241 bytes, lines 32135-32628
32135 /** 32136 * Controls line thickness in CSS pixel units when `worldUnits` is `false` (default), 32137 * or in world units when `worldUnits` is `true`. 32138 * 32139 * @type {number} 32140 * @default 1 32141 */ 32142 get linewidth() { 32143 32144 return this.uniforms.linewidth.value; 32145 32146 } 32147 32148 set linewidth( value ) { 32149 32150 if ( ! this.uniforms.linewidth ) return; 32151 this.uniforms.linewidth.value = value; 32152 32153 } 32154 32155 /** 32156 * Whether the line is dashed, or solid. 32157 * 32158 * @type {boolean} 32159 * @default false 32160 */ 32161 get dashed() { 32162 32163 return 'USE_DASH' in this.defines; 32164 32165 } 32166 32167 set dashed( value ) { 32168 32169 if ( ( value === true ) !== this.dashed ) { 32170 32171 this.needsUpdate = true; 32172 32173 } 32174 32175 if ( value === true ) { 32176 32177 this.defines.USE_DASH = ''; 32178 32179 } else { 32180 32181 delete this.defines.USE_DASH; 32182 32183 } 32184 32185 } 32186 32187 /** 32188 * The scale of the dashes and gaps. 32189 * 32190 * @type {number} 32191 * @default 1 32192 */ 32193 get dashScale() { 32194 32195 return this.uniforms.dashScale.value; 32196 32197 } 32198 32199 set dashScale( value ) { 32200 32201 this.uniforms.dashScale.value = value; 32202 32203 } 32204 32205 /** 32206 * The size of the dash. 32207 * 32208 * @type {number} 32209 * @default 1 32210 */ 32211 get dashSize() { 32212 32213 return this.uniforms.dashSize.value; 32214 32215 } 32216 32217 set dashSize( value ) { 32218 32219 this.uniforms.dashSize.value = value; 32220 32221 } 32222 32223 /** 32224 * Where in the dash cycle the dash starts. 32225 * 32226 * @type {number} 32227 * @default 0 32228 */ 32229 get dashOffset() { 32230 32231 return this.uniforms.dashOffset.value; 32232 32233 } 32234 32235 set dashOffset( value ) { 32236 32237 this.uniforms.dashOffset.value = value; 32238 32239 } 32240 32241 /** 32242 * The size of the gap. 32243 * 32244 * @type {number} 32245 * @default 0 32246 */ 32247 get gapSize() { 32248 32249 return this.uniforms.gapSize.value; 32250 32251 } 32252 32253 set gapSize( value ) { 32254 32255 this.uniforms.gapSize.value = value; 32256 32257 } 32258 32259 /** 32260 * The opacity. 32261 * 32262 * @type {number} 32263 * @default 1 32264 */ 32265 get opacity() { 32266 32267 return this.uniforms.opacity.value; 32268 32269 } 32270 32271 set opacity( value ) { 32272 32273 if ( ! this.uniforms ) return; 32274 this.uniforms.opacity.value = value; 32275 32276 } 32277 32278 /** 32279 * The size of the viewport, in screen pixels. This must be kept updated to make 32280 * screen-space rendering accurate.The `LineSegments2.onBeforeRender` callback 32281 * performs the update for visible objects. 32282 * 32283 * @type {Vector2} 32284 */ 32285 get resolution() { 32286 32287 return this.uniforms.resolution.value; 32288 32289 } 32290 32291 set resolution( value ) { 32292 32293 this.uniforms.resolution.value.copy( value ); 32294 32295 } 32296 32297 /** 32298 * Whether to use alphaToCoverage or not. When enabled, this can improve the 32299 * anti-aliasing of line edges when using MSAA. 32300 * 32301 * @type {boolean} 32302 */ 32303 get alphaToCoverage() { 32304 32305 return 'USE_ALPHA_TO_COVERAGE' in this.defines; 32306 32307 } 32308 32309 set alphaToCoverage( value ) { 32310 32311 if ( ! this.defines ) return; 32312 32313 if ( ( value === true ) !== this.alphaToCoverage ) { 32314 32315 this.needsUpdate = true; 32316 32317 } 32318 32319 if ( value === true ) { 32320 32321 this.defines.USE_ALPHA_TO_COVERAGE = ''; 32322 32323 } else { 32324 32325 delete this.defines.USE_ALPHA_TO_COVERAGE; 32326 32327 } 32328 32329 } 32330 32331} 32332 32333const _viewport = new Vector4(); 32334 32335const _start = new Vector3(); 32336const _end = new Vector3(); 32337 32338const _start4 = new Vector4(); 32339const _end4 = new Vector4(); 32340 32341const _ssOrigin = new Vector4(); 32342const _ssOrigin3 = new Vector3(); 32343const _mvMatrix = new Matrix4(); 32344const _line = new Line3(); 32345const _closestPoint = new Vector3(); 32346 32347const _box = new Box3(); 32348const _sphere = new Sphere(); 32349const _clipToWorldVector = new Vector4(); 32350 32351let _ray, _lineWidth; 32352 32353// Returns the margin required to expand by in world space given the distance from the camera, 32354// line width, resolution, and camera projection 32355function getWorldSpaceHalfWidth( camera, distance, resolution ) { 32356 32357 // transform into clip space, adjust the x and y values by the pixel width offset, then 32358 // transform back into world space to get world offset. Note clip space is [-1, 1] so full 32359 // width does not need to be halved. 32360 _clipToWorldVector.set( 0, 0, - distance, 1.0 ).applyMatrix4( camera.projectionMatrix ); 32361 _clipToWorldVector.multiplyScalar( 1.0 / _clipToWorldVector.w ); 32362 _clipToWorldVector.x = _lineWidth / resolution.width; 32363 _clipToWorldVector.y = _lineWidth / resolution.height; 32364 _clipToWorldVector.applyMatrix4( camera.projectionMatrixInverse ); 32365 _clipToWorldVector.multiplyScalar( 1.0 / _clipToWorldVector.w ); 32366 32367 return Math.abs( Math.max( _clipToWorldVector.x, _clipToWorldVector.y ) ); 32368 32369} 32370 32371function raycastWorldUnits( lineSegments, intersects ) { 32372 32373 const matrixWorld = lineSegments.matrixWorld; 32374 const geometry = lineSegments.geometry; 32375 const instanceStart = geometry.attributes.instanceStart; 32376 const instanceEnd = geometry.attributes.instanceEnd; 32377 const segmentCount = Math.min( geometry.instanceCount, instanceStart.count ); 32378 32379 for ( let i = 0, l = segmentCount; i < l; i ++ ) { 32380 32381 _line.start.fromBufferAttribute( instanceStart, i ); 32382 _line.end.fromBufferAttribute( instanceEnd, i ); 32383 32384 _line.applyMatrix4( matrixWorld ); 32385 32386 const pointOnLine = new Vector3(); 32387 const point = new Vector3(); 32388 32389 _ray.distanceSqToSegment( _line.start, _line.end, point, pointOnLine ); 32390 const isInside = point.distanceTo( pointOnLine ) < _lineWidth * 0.5; 32391 32392 if ( isInside ) { 32393 32394 intersects.push( { 32395 point, 32396 pointOnLine, 32397 distance: _ray.origin.distanceTo( point ), 32398 object: lineSegments, 32399 face: null, 32400 faceIndex: i, 32401 uv: null, 32402 uv1: null, 32403 } ); 32404 32405 } 32406 32407 } 32408 32409} 32410 32411function raycastScreenSpace( lineSegments, camera, intersects ) { 32412 32413 const projectionMatrix = camera.projectionMatrix; 32414 const material = lineSegments.material; 32415 const resolution = material.resolution; 32416 const matrixWorld = lineSegments.matrixWorld; 32417 32418 const geometry = lineSegments.geometry; 32419 const instanceStart = geometry.attributes.instanceStart; 32420 const instanceEnd = geometry.attributes.instanceEnd; 32421 const segmentCount = Math.min( geometry.instanceCount, instanceStart.count ); 32422 32423 const near = - camera.near; 32424 32425 // 32426 32427 // pick a point 1 unit out along the ray to avoid the ray origin 32428 // sitting at the camera origin which will cause "w" to be 0 when 32429 // applying the projection matrix. 32430 _ray.at( 1, _ssOrigin ); 32431 32432 // ndc space [ - 1.0, 1.0 ] 32433 _ssOrigin.w = 1; 32434 _ssOrigin.applyMatrix4( camera.matrixWorldInverse ); 32435 _ssOrigin.applyMatrix4( projectionMatrix ); 32436 _ssOrigin.multiplyScalar( 1 / _ssOrigin.w ); 32437 32438 // screen space 32439 _ssOrigin.x *= resolution.x / 2; 32440 _ssOrigin.y *= resolution.y / 2; 32441 _ssOrigin.z = 0; 32442 32443 _ssOrigin3.copy( _ssOrigin ); 32444 32445 _mvMatrix.multiplyMatrices( camera.matrixWorldInverse, matrixWorld ); 32446 32447 for ( let i = 0, l = segmentCount; i < l; i ++ ) { 32448 32449 _start4.fromBufferAttribute( instanceStart, i ); 32450 _end4.fromBufferAttribute( instanceEnd, i ); 32451 32452 _start4.w = 1; 32453 _end4.w = 1; 32454 32455 // camera space 32456 _start4.applyMatrix4( _mvMatrix ); 32457 _end4.applyMatrix4( _mvMatrix ); 32458 32459 // skip the segment if it's entirely behind the camera 32460 const isBehindCameraNear = _start4.z > near && _end4.z > near; 32461 if ( isBehindCameraNear ) { 32462 32463 continue; 32464 32465 } 32466 32467 // trim the segment if it extends behind camera near 32468 if ( _start4.z > near ) { 32469 32470 const deltaDist = _start4.z - _end4.z; 32471 const t = ( _start4.z - near ) / deltaDist; 32472 _start4.lerp( _end4, t ); 32473 32474 } else if ( _end4.z > near ) { 32475 32476 const deltaDist = _end4.z - _start4.z; 32477 const t = ( _end4.z - near ) / deltaDist; 32478 _end4.lerp( _start4, t ); 32479 32480 } 32481 32482 // clip space 32483 _start4.applyMatrix4( projectionMatrix ); 32484 _end4.applyMatrix4( projectionMatrix ); 32485 32486 // ndc space [ - 1.0, 1.0 ] 32487 _start4.multiplyScalar( 1 / _start4.w ); 32488 _end4.multiplyScalar( 1 / _end4.w ); 32489 32490 // screen space 32491 _start4.x *= resolution.x / 2; 32492 _start4.y *= resolution.y / 2; 32493 32494 _end4.x *= resolution.x / 2; 32495 _end4.y *= resolution.y / 2; 32496 32497 // create 2d segment 32498 _line.start.copy( _start4 ); 32499 _line.start.z = 0; 32500 32501 _line.end.copy( _end4 ); 32502 _line.end.z = 0; 32503 32504 // get closest point on ray to segment 32505 const param = _line.closestPointToPointParameter( _ssOrigin3, true ); 32506 _line.at( param, _closestPoint ); 32507 32508 // check if the intersection point is within clip space 32509 const zPos = MathUtils.lerp( _start4.z, _end4.z, param ); 32510 const isInClipSpace = zPos >= - 1 && zPos <= 1; 32511 32512 const isInside = _ssOrigin3.distanceTo( _closestPoint ) < _lineWidth * 0.5; 32513 32514 if ( isInClipSpace && isInside ) { 32515 32516 _line.start.fromBufferAttribute( instanceStart, i ); 32517 _line.end.fromBufferAttribute( instanceEnd, i ); 32518 32519 _line.start.applyMatrix4( matrixWorld ); 32520 _line.end.applyMatrix4( matrixWorld ); 32521 32522 const pointOnLine = new Vector3(); 32523 const point = new Vector3(); 32524 32525 _ray.distanceSqToSegment( _line.start, _line.end, point, pointOnLine ); 32526 32527 intersects.push( { 32528 point: point, 32529 pointOnLine: pointOnLine, 32530 distance: _ray.origin.distanceTo( point ), 32531 object: lineSegments, 32532 face: null, 32533 faceIndex: i, 32534 uv: null, 32535 uv1: null, 32536 } ); 32537 32538 } 32539 32540 } 32541 32542} 32543 32544/** 32545 * A series of lines drawn between pairs of vertices. 32546 * 32547 * This adds functionality beyond {@link LineSegments}, like arbitrary line width and changing width 32548 * to be in world units. {@link Line2} extends this object, forming a polyline instead of individual 32549 * segments. 32550 * 32551 * This module can only be used with {@link WebGLRenderer}. When using {@link WebGPURenderer}, 32552 * import the class from `lines/webgpu/LineSegments2.js`. 32553 * 32554 * ```js 32555 * const geometry = new LineSegmentsGeometry(); 32556 * geometry.setPositions( positions ); 32557 * geometry.setColors( colors ); 32558 * 32559 * const material = new LineMaterial( { linewidth: 5, vertexColors: true } }; 32560 * 32561 * const lineSegments = new LineSegments2( geometry, material ); 32562 * scene.add( lineSegments ); 32563 * ``` 32564 * 32565 * @augments Mesh 32566 * @three_import import { LineSegments2 } from 'three/addons/lines/LineSegments2.js'; 32567 */ 32568class LineSegments2 extends Mesh { 32569 32570 /** 32571 * Constructs a new wide line. 32572 * 32573 * @param {LineSegmentsGeometry} [geometry] - The line geometry. 32574 * @param {LineMaterial} [material] - The line material. 32575 */ 32576 constructor( geometry = new LineSegmentsGeometry(), material = new LineMaterial( { color: Math.random() * 0xffffff } ) ) { 32577 32578 super( geometry, material ); 32579 32580 /** 32581 * This flag can be used for type testing. 32582 * 32583 * @type {boolean} 32584 * @readonly 32585 * @default true 32586 */ 32587 this.isLineSegments2 = true; 32588 32589 this.type = 'LineSegments2'; 32590 32591 } 32592 32593 /** 32594 * Computes an array of distance values which are necessary for rendering dashed lines. 32595 * For each vertex in the geometry, the method calculates the cumulative length from the 32596 * current point to the very beginning of the line. 32597 * 32598 * @return {LineSegments2} A reference to this instance. 32599 */ 32600 computeLineDistances() { 32601 32602 // for backwards-compatibility, but could be a method of LineSegmentsGeometry... 32603 32604 const geometry = this.geometry; 32605 32606 const instanceStart = geometry.attributes.instanceStart; 32607 const instanceEnd = geometry.attributes.instanceEnd; 32608 const lineDistances = new Float32Array( 2 * instanceStart.count ); 32609 32610 for ( let i = 0, j = 0, l = instanceStart.count; i < l; i ++, j += 2 ) { 32611 32612 _start.fromBufferAttribute( instanceStart, i ); 32613 _end.fromBufferAttribute( instanceEnd, i ); 32614 32615 lineDistances[ j ] = ( j === 0 ) ? 0 : lineDistances[ j - 1 ]; 32616 lineDistances[ j + 1 ] = lineDistances[ j ] + _start.distanceTo( _end ); 32617 32618 } 32619 32620 const instanceDistanceBuffer = new InstancedInterleavedBuffer( lineDistances, 2, 1 ); // d0, d1 32621 32622 geometry.setAttribute( 'instanceDistanceStart', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 0 ) ); // d0 32623 geometry.setAttribute( 'instanceDistanceEnd', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 1 ) ); // d1 32624 32625 return this; 32626 32627 } 32628
32629 /** 32630 * Computes intersection points between a casted ray and this instance. 32631 * 32632 * @param {Raycaster} raycaster - The raycaster. 32633 * @param {Array<Object>} intersects - The target array that holds the intersection points. 32634 */ 32635 raycast( raycaster, intersects ) { 32636 32637 const worldUnits = this.material.worldUnits; 32638 const camera = raycaster.camera; 32639 32640 if ( camera === null && ! worldUnits ) { 32641 32642 console.error( 'LineSegments2: "Raycaster.camera" needs to be set in order to raycast against LineSegments2 while worldUnits is set to false.' ); 32643 32644 } 32645 32646 const threshold = ( raycaster.params.Line2 !== undefined ) ? raycaster.params.Line2.threshold || 0 : 0; 32647 32648 _ray = raycaster.ray; 32649 32650 const matrixWorld = this.matrixWorld; 32651 const geometry = this.geometry; 32652 const material = this.material; 32653 32654 _lineWidth = material.linewidth + threshold; 32655 32656 // check if we intersect the sphere bounds 32657 if ( geometry.boundingSphere === null ) { 32658 32659 geometry.computeBoundingSphere(); 32660 32661 } 32662 32663 _sphere.copy( geometry.boundingSphere ).applyMatrix4( matrixWorld ); 32664 32665 // increase the sphere bounds by the worst case line screen space width 32666 let sphereMargin; 32667 if ( worldUnits ) { 32668 32669 sphereMargin = _lineWidth * 0.5; 32670 32671 } else { 32672 32673 const distanceToSphere = Math.max( camera.near, _sphere.distanceToPoint( _ray.origin ) ); 32674 sphereMargin = getWorldSpaceHalfWidth( camera, distanceToSphere, material.resolution ); 32675 32676 } 32677 32678 _sphere.radius += sphereMargin; 32679 32680 if ( _ray.intersectsSphere( _sphere ) === false ) { 32681 32682 return; 32683 32684 } 32685 32686 // check if we intersect the box bounds 32687 if ( geometry.boundingBox === null ) { 32688 32689 geometry.computeBoundingBox(); 32690 32691 } 32692 32693 _box.copy( geometry.boundingBox ).applyMatrix4( matrixWorld ); 32694 32695 // increase the box bounds by the worst case line width 32696 let boxMargin; 32697 if ( worldUnits ) { 32698 32699 boxMargin = _lineWidth * 0.5; 32700 32701 } else { 32702 32703 const distanceToBox = Math.max( camera.near, _box.distanceToPoint( _ray.origin ) ); 32704 boxMargin = getWorldSpaceHalfWidth( camera, distanceToBox, material.resolution ); 32705 32706 } 32707 32708 _box.expandByScalar( boxMargin ); 32709 32710 if ( _ray.intersectsBox( _box ) === false ) { 32711 32712 return; 32713 32714 } 32715 32716 if ( worldUnits ) { 32717 32718 raycastWorldUnits( this, intersects ); 32719 32720 } else { 32721 32722 raycastScreenSpace( this, camera, intersects ); 32723 32724 } 32725 32726 } 32727 32728 onBeforeRender( renderer ) { 32729 32730 const uniforms = this.material.uniforms; 32731 32732 if ( uniforms && uniforms.resolution ) { 32733 32734 renderer.getViewport( _viewport ); 32735 this.material.uniforms.resolution.value.set( _viewport.z, _viewport.w ); 32736 32737 } 32738 32739 } 32740 32741} 32742 32743function lonLatToVector3(lon, lat, radius, altitude ) { 32744 let new_radius = radius + altitude; 32745 const phi = (90 - lat) * (Math.PI / 180); 32746 const theta = (lon + 180) * (Math.PI / 180); 32747 return new Vector3( 32748 -new_radius * Math.sin(phi) * Math.cos(theta), 32749 new_radius * Math.cos(phi), 32750 new_radius * Math.sin(phi) * Math.sin(theta) 32751 ); 32752} 32753 32754/** 32755 * Creates positions for graticule lines 32756 * 32757 * @param {*} radius 32758 * @param {*} lonStep 32759 * @param {*} latStep 32760 * @returns 32761 */ 32762 32763function createGraticulePositions( radius, lonStep = 10, latStep = 10, altitude = 0.0 ) { 32764 const positions = []; 32765 32766 // Longitude lines 32767 for (let lon = -180; lon <= 180; lon += lonStep) { 32768 for (let lat = -90; lat < 90; lat += 1) { 32769 const v1 = lonLatToVector3(lon, lat, radius, altitude ); 32770 const v2 = lonLatToVector3(lon, lat + 1, radius, altitude ); 32771 positions.push(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z); 32772 } 32773 } 32774 32775 // Latitude lines 32776 for (let lat = -90; lat <= 90; lat += latStep) { 32777 for (let lon = -180; lon < 180; lon += 1) { 32778 const v1 = lonLatToVector3(lon, lat, radius, altitude ); 32779 const v2 = lonLatToVector3(lon + 1, lat, radius, altitude ); 32780 positions.push(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z); 32781 } 32782 } 32783 return positions; 32784} 32785 32786/** 32787 * Creates a graticule geometry using LineSegmentsGeometry 32788 * @param {*} radius - Radius of the globe 32789 * @param {*} lonStep - Longitude step in degrees 32790 * @param {*} latStep - Latitude step in degrees 32791 * @param {*} altitude - Altitude above the globe surface 32792 * @returns {LineSegmentsGeometry} - Geometry for graticule lines 32793 */ 32794 32795function createGraticuleGeometry( radius, lonStep = 10, latStep = 10, altitude = 0.0 ) { 32796 const positions = createGraticulePositions( radius, lonStep, latStep, altitude ); // Earth radius in km, adjust as needed 32797 32798 const lineGeometry = new LineSegmentsGeometry(); 32799 lineGeometry.setPositions(positions); 32800 32801 return lineGeometry; 32802} 32803 32804/** 32805 * Creates a graticule object with LineSegments2 and LineMaterial 32806 * @param {*} lineGeometry - Geometry for the graticule lines 32807 * @param {*}
32807 linewidth - Width of the lines 32808 * @param {*} opacity - Opacity of the lines 32809 * @param {*} color - Color of the lines 32810 * @returns {LineSegments2} - Graticule object 32811 */ 32812function createGraticuleObject( lineGeometry, linewidth, opacity, color ) { 32813 // Use THREE.js to create your graticule lines 32814 32815 // Create a LineMaterial for the graticule lines 32816 // it allows line width to be set, as opposed to LineBasicMaterial with width of 1 32817 const lineMaterial = new LineMaterial({ 32818 color: color, 32819 linewidth: linewidth, // In world units, not pixels! 32820 transparent: true, 32821 opacity: opacity, 32822 }); 32823 // linesegments2 is a 3D object that can handle more details 32824 const lineGraticule = new LineSegments2( lineGeometry, lineMaterial ); 32825 lineGraticule.computeLineDistances(); 32826 32827 // Optionally tag it for future reference 32828 lineGraticule.userData.isGraticule = true; 32829 32830 // disable raycasting so it doesn't trigger library click events (prevents crash) 32831 lineGraticule.raycast = () => {}; 32832 32833 return lineGraticule; 32834} 32835 32836/** 32837 * Sets custom graticule lines on the globe 32838 * This function checks if the graticule lines are enabled and creates them if they are not 32839 * @param {Object} thisGlobe - The globe instance where the graticule will be set 32840 * @param {Object} data - The data object containing graticule settings 32841 * @returns {void} 32842 */ 32843 32844function setCustomGraticule( thisGlobe, data ) { 32845 32846 // runs on globe ready 32847 if ( !thisGlobe || !thisGlobe.scene ) { 32848 console.warn( 'Globe or scene not available' ); 32849 return; 32850 } 32851 32852 // if no data or graticules are not enabled, return 32853 if ( ! data || !globe_ut_bool( data.showGraticules ) || !globe_ut_bool( data.graticules ) ) { 32854 return; 32855 } 32856 const scene = thisGlobe.scene(); 32857 if ( ! Array.isArray( scene?.children ) || scene.children.length === 0 ) { 32858 console.warn('Scene or scene.children not available'); 32859 return; 32860 } 32861 32862 let top_group = scene.children.find( obj => obj?.type === 'Group' ); 32863 if ( ! Array.isArray( top_group?.children ) ) { 32864 top_group = new Group(); 32865 top_group.name = 'topGroup'; 32866 scene.add( top_group ); 32867 } 32868 32869 let middle_group = top_group.children.find( obj => obj && obj.type === 'Group' ); 32870 if ( ! Array.isArray( middle_group?.children ) ) { 32871 middle_group = new Group(); 32872 middle_group.name = 'middle_group'; 32873 top_group.add( middle_group ); 32874 } 32875 32876 let graticule; 32877 32878 // if graticule already exists, and is render is set to simple 32879 if ( ! globe_ut_bool( data.graticules.useLargeLinesGraticules ) ) { 32880 graticule = middle_group.children.find(obj => obj && obj.type === 'LineSegments' && obj.material?.transparent); 32881 32882 if ( graticule && globe_ut_bool( data.graticules ) ) { 32883 // color 32884 if ( typeof data.graticules.color !== 'undefined') { 32885 graticule.material.color.set(data.graticules.color); 32886 } 32887 32888 // opacity 32889 if ( typeof data.graticules.opacity !== 'undefined') { 32890 graticule.material.opacity = parseFloat(data.graticules.opacity); 32891 } 32892 graticule.userData.isGraticule = true; // Tag for future access 32893 } 32894 } 32895 32896 // if render is set to 3D, create new graticule with LineSegmentsGeometry 32897 if ( ! graticule && globe_ut_bool( data.graticules.useLargeLinesGraticules ) ) { 32898 let graticule3D = middle_group.children.find( 32899 obj => obj?.userData?.is3DGraticule 32900 ); 32901 32902 const globe_radius = thisGlobe.getGlobeRadius(); 32903 32904 const graticuleSettings = data.graticules || {}; 32905 const altitude = parseFloat(graticuleSettings.altitude ?? 0); 32906 const color = graticuleSettings.color ?? 'lightgrey'; 32907 const thickness = parseFloat(graticuleSettings.thickness ?? 1); 32908 const opacity = parseFloat(graticuleSettings.opacity ?? 0.5); 32909 32910 const graticule_geometry = createGraticuleGeometry( globe_radius, 10, 10, altitude ); 32911 32912 // if graticule3D already exists, update it 32913 if ( graticule3D ) { 32914 // Update geometry 32915 graticule3D.geometry.dispose(); 32916 graticule3D.geometry = graticule_geometry; 32917 // Update material 32918 graticule3D.material.color.set(color); 32919 graticule3D.material.linewidth = thickness; 32920 graticule3D.material.opacity = opacity; 32921 graticule3D.material.needsUpdate = true; 32922 return; 32923 } 32924 32925 // create new graticule if it does not exist 32926 graticule = createGraticuleObject( graticule_geometry, thickness, opacity, color ); 32927 graticule.userData.isGraticule = true; // Tag for future access 32928 graticule.userData.is3DGraticule = true; // Tag for future access 32929 // Add to the group 32930 middle_group.add(graticule); 32931 32932 } 32933 32934} 32935 32936/** Add Points Layer to Globe */ 32937function addHTMLElementsLayer ( thisGlobe, GlobeData ) { 32938 32939 thisGlobe.htmlElementsData( GlobeData.html ) 32940 .htmlLat(p => globe_ut_prepare_coordinates('latitude', p) ) 32941 .htmlLng(p => globe_ut_prepare_coordinates('longitude', p) ) 32942 .htmlAltitude(0.01) // there was no benefit in using the altitude from the backend 32943 .htmlElement(p => { 32944 32945 let html = p.html ? p.html : buildHtml(p, GlobeData); 32946 32947 const el = document.createElement('div'); 32948 el.innerHTML = html; 32949 el.classList.add('itt_globe_html_element'); 32950 el.style['pointer-events'] = 'auto'; 32951 el.onclick = function() { 32952 setupClickEvent$1(thisGlobe, GlobeData, p); 32953 }; 32954 return el; 32955 }); 32956} 32957 32958function buildHtml(p, GlobeData) { 32959 let template = GlobeData.htmlDefaults?.htmlTemplate || ''; 32960 32961 if (!template || typeof template !== 'string' ) { 32962 // Provide a fallback or handle the missing template 32963 template = ''; // example fallback 32964 } 32965 // replace placeholders with values from p 32966 template = template.replace(/\{([^}]+)\}/g, (match, key) => { 32967 // Handle dot notation by splitting on dots 32968 const keys = key.split('.'); 32969 let value = p; 32970 32971 // Traverse the object/array following the dot notation 32972 for (const k of keys) { 32973 if (value === undefined || value === null) return match; 32974 value = value[k]; 32975 } 32976 32977 return value !== undefined ? value : match; 32978 }); 32979 32980 return template; 32981} 32982 32983/**
32984 * Adds geojson regions layer 32985 * @param {*} thisGlobe 32986 * @param {*} GlobeData 32987 */ 32988const addRegionLayer = function( thisGlobe, GlobeData ) { 32989 32990 // in case it's a hollow globe, we don't want to see the side color 32991 let sideColor = 'rgba(100, 100, 100, 0.05)'; 32992 if( GlobeData.globeImage === 'earth-hollow'){ 32993 sideColor = 'rgba(100, 100, 100, 0)'; 32994 } 32995 32996 if ( GlobeData.regionDefaults === undefined ) { 32997 GlobeData.regionDefaults = {}; 32998 } 32999 33000 let defaultStrokeColor = GlobeData.regionDefaults.strokeColor ?? '#f0f0f0'; 33001 33002 return new Promise((resolve) => { 33003 thisGlobe.polygonAltitude( r => r.properties.altitude ?? 0.005 ) 33004 .lineHoverPrecision(0) 33005 .polygonCapColor(r => r.properties.color ? r.properties.color : GlobeData.regionDefaults.inactive) 33006 .polygonSideColor(() => sideColor) 33007 .polygonStrokeColor(r => r.properties.strokeColor || defaultStrokeColor) 33008 .polygonCapCurvatureResolution(5) 33009 .polygonsTransitionDuration(300); 33010 33011 thisGlobe.regionLayers = {}; 33012 thisGlobe.originalPolygonsData = []; 33013 33014 // tooltip 33015 thisGlobe.polygonLabel(function (region) { 33016 33017 // if region was not added manually and option to only display on active region is enabled, skip 33018 let onlyActive = globe_ut_bool(GlobeData.tooltipOnlyActive); 33019 if( onlyActive && typeof region.properties.originalId === 'undefined' ){ 33020 return; 33021 } 33022 // set tooltip template 33023 let regionsTooltipTemplate = GlobeData.tooltipTemplate ?? '{tooltipContent}'; 33024 if( GlobeData.regionsTooltipTemplate ){ 33025 regionsTooltipTemplate = GlobeData.regionsTooltipTemplate; 33026 } 33027 33028 return setupTooltip(region.properties, regionsTooltipTemplate); 33029 }); 33030 33031 // click events 33032 thisGlobe.onPolygonClick(function (region) { 33033 setupClickEvent$1(thisGlobe, GlobeData, region.properties); 33034 }); 33035 33036 // hover events 33037 thisGlobe.onPolygonHover(function (current, previous) { 33038 setupHoverEvent$1( thisGlobe, current, previous, 'regions' ); 33039 }); 33040 33041 33042 if ( (!GlobeData.regions || GlobeData.regions.length === 0) && globe_ut_bool(GlobeData.onlyActiveRegions) ) { 33043 resolve(); 33044 return; 33045 } 33046 33047 // fetch regions 33048 (async () => { 33049 const regions = await prepareRegions(thisGlobe, GlobeData); 33050 thisGlobe.polygonsData(regions); 33051 thisGlobe.originalPolygonsData = regions; 33052 33053 resolve(); 33054 })(); 33055 }); 33056}; 33057 33058const prepareRegions = async function( thisGlobe, GlobeData, alt
33058itudeMultiplier ){ 33059 33060 // if it already exists, return it, otherwise fetch it 33061 if (thisGlobe.regionLayers && thisGlobe.regionLayers[GlobeData.id]) { 33062 return thisGlobe.regionLayers[GlobeData.id]; 33063 } 33064 33065 altitudeMultiplier = altitudeMultiplier ?? 0; 33066 33067 let geojson_source = GlobeData.regionSource; 33068 if ( geojson_source === 'disabled' || geojson_source === undefined ){ 33069 return; 33070 } 33071 if ( GlobeData.regions === undefined ){ 33072 return; 33073 } 33074 33075 let fullpath; 33076 if( geojson_source !== 'custom' ){ 33077 if ( ! geojson_source.includes('.geojson') && ! geojson_source.includes('.json') ) { 33078 geojson_source += '.json'; 33079 } 33080 fullpath = ittGlobeData.assetsUrl + 'geojson/' + geojson_source; 33081 } else { 33082 fullpath = GlobeData.regionCustomSourceURL; 33083 } 33084 33085 const selectedRegionsIndividually = GlobeData.regions.reduce((acc, region) => { 33086 33087 // save original id, to use for grouped hover 33088 region.originalId = region.id; 33089 33090 // Destructure the region to get all properties except ids 33091 const { id, ...regionProps } = region; 33092 if ( ! id ) { 33093 return acc; 33094 } 33095 33096 // Convert string id to array if needed 33097 if (typeof id === 'string') { 33098 id = id.includes(',') ? id.split(',').map(i => i.trim()) : [id]; 33099 } 33100 33101 // Create new objects with all region properties and the individual id 33102 const idsWithProps = id.map(id => ({ ...regionProps, id })); 33103 return acc.concat(idsWithProps); 33104 }, []); 33105 33106 // Convert the selection of regions array to a dictionary for quick lookup 33107 const regionsDict = selectedRegionsIndividually.reduce((acc, item) => { 33108 // Add both id and name as keys if available 33109 acc[item.id] = item; // id from the regions object 33110 if (item.title) { // title or name for country 33111 acc[item.title] = item; // Store the title (e.g., "Algeria") 33112 } 33113 return acc; 33114 }, {}); 33115 33116 return fetch(fullpath) 33117 .then(res => res.json()) 33118 .then(regionsAvailable => { 33119 // Enrich the GeoJSON data with each regions data 33120 regionsAvailable.features.forEach(feature => { 33121 33122 // Sanitize all string properties found in the geojson to prevent XSS 33123 Object.keys(feature.properties).forEach(key => { 33124 if (typeof feature.properties[key] === 'string') { 33125 feature.properties[key] = globe_ut_sanitize(feature.properties[key]); 33126 } 33127 }); 33128 33129 const regionId = feature.id; 33130 const regionName = feature.properties.name; 33131 33132 // Try to find the matching region data by id or name 33133 const regionData = regionsDict[regionId] || regionsDict[regionName]; 33134 33135 if (regionData) { 33136 feature.properties = { 33137 ...feature.properties, 33138 ...regionData 33139 }; 33140 } 33141 // Add globe_id to feature properties 33142 feature.properties.globe_id = GlobeData.id; 33143 33144 if (thisGlobe.liveFilter && thisGlobe.liveFilter.allLabel && thisGlobe.liveFilter.allLabel.trim() !== '') { 33145 feature.properties.altitude = 0.005 + ( 0.0025 * altitudeMultiplier ); 33146 } 33147 33148 }); 33149 33150 let features = regionsAvailable.features; 33151 33152 // save total of available features 33153 thisGlobe.totalAvailableRegions = features.length; 33154 // get total of active regions 33155 thisGlobe.totalActiveRegions = features.filter(feature => feature.properties.originalId).length; 33156 33157 // Filter to only active regions if setting enabled 33158 if (globe_ut_bool(GlobeData.onlyActiveRegions)) { 33159 features = features.filter(feature => feature.properties.originalId); 33160 } 33161 33162 thisGlobe.regionLayers[GlobeData.id] = features; 33163 return features; 33164 }); 33165}; 33166 33167/** Add Marker Objects Layer to Globe 33168 * It will inherit the same properties as the points layer 33169*/ 33170function addObjectsLayer ( thisGlobe, GlobeData ) { 33171 33172 // use in images if needed 33173 thisGlobe.textureLoader = new TextureLoader(); 33174 33175 thisGlobe.objectsData( GlobeData.objects ) 33176 .objectLat(p => globe_ut_prepare_coordinates('latitude', p) ) 33177 .objectLng(p => globe_ut_prepare_coordinates('longitude', p) ) 33178 .objectAltitude(p => 0); 33179 // object shape 33180 thisGlobe.objectThreeObject(function(d) { 33181 if (d.type === 'pin') { 33182 return createPin(d, thisGlobe); 33183 } 33184 if (d.type === 'marker') { 33185 return createMarker(d); 33186 } 33187 if (d.type === 'image') { 33188 return createImage(d, thisGlobe); 33189 } 33190 if (d.type === 'flag') { 33191 if(d.image?.url){ 33192 return createFlagImage(d, thisGlobe); 33193 } 33194 else { 33195 return createFlag(d, thisGlobe); 33196 } 33197 } 33198 return null; 33199 }); 33200 33201 // tooltip 33202 thisGlobe.objectLabel(function (label) { 33203 33204 let pointsTooltipTemplate = GlobeData.tooltipTemplate ?? '{tooltipContent}'; 33205 if( GlobeData.pointsTooltipTemplate ){ 33206 pointsTooltipTemplate = GlobeData.pointsTooltipTemplate; 33207 } 33208 return setupTooltip(label, pointsTooltipTemplate ); 33209 33210 }); 33211 33212 // click events 33213 thisGlobe.onObjectClick(function ( element ) { 33214 setupClickEvent$1( thisGlobe, GlobeData, element ); 33215 }); 33216 33217 // hover events 33218 thisGlobe.onObjectHover(function (object, prevObject) {
33219 let type = object && object.type ? object.type : prevObject.type; 33220 setupHoverEvent$1(thisGlobe, object, prevObject, type ); 33221 }); 33222} 33223 33224function createFlag(d, thisGlobe) { 33225 const flagGroup = new Group(); 33226 let globeRadius = thisGlobe.getGlobeRadius(); 33227 let size = d.radius * 0.5; 33228 let height = size * (3/5); 33229 // Set minimum altitude without dividing by globe radius 33230 let minAltitude = height + 1; 33231 let altitude = Math.max(d.altitude, minAltitude); 33232 let altitudeInUnits = parseFloat((altitude * globeRadius).toFixed(2)) * 0.01; 33233 let poleRadius = size * 0.025; 33234 let animate = d.animate ? globe_ut_bool(d.animate) : true; 33235 let width = size; 33236 let flagMaterial; 33237 let flagPole = createFlagPole(d, thisGlobe); 33238 33239 flagGroup.add(flagPole); 33240 33241 flagMaterial = new MeshLambertMaterial({ 33242 color: d.color, 33243 side: DoubleSide 33244 }); 33245 33246 const geometry = new PlaneGeometry(width, height, width, height); 33247 const flagMesh = new Mesh(geometry, flagMaterial); 33248 33249 // Position flag mesh with bottom edge at the top of the pole 33250 flagMesh.position.set(width/2 + poleRadius, altitudeInUnits - height/2, 0); 33251 33252 const animateFunction = () => { 33253 // Get the position attribute 33254 const positions = flagMesh.geometry.getAttribute('position'); 33255 33256 for (let y = 0; y <= height; y++) { 33257 for (let x = 0; x <= width; x++) { 33258 const index = x + y * (width + 1); 33259 // Create wave effect by combining sine waves 33260 const waveX = Math.sin(x * 0.5 - Date.now() * 0.003) * 0.5; 33261 const waveY = Math.sin(y * 0.3 - Date.now() * 0.004) * 0.3; 33262 const wave = waveX + waveY; 33263 // Increase amplitude towards flag edge 33264 const amplitude = (x / width) * 2; 33265 positions.array[index * 3 + 2] = wave * amplitude; 33266 } 33267 } 33268 33269 // Mark the positions as needing an update 33270 positions.needsUpdate = true; 33271 requestAnimationFrame(animateFunction); 33272 }; 33273 33274 if(animate){ 33275 animateFunction(); 33276 } 33277 33278 flagGroup.add(flagMesh); 33279 33280 // Rotate entire flag group to be perpendicular to globe surface 33281 flagGroup.rotation.x = Math.PI / 2; 33282 return flagGroup; 33283} 33284 33285function createFlagImage(d, thisGlobe) { 33286 const flagGroup = new Group(); 33287 let globeRadius = thisGlobe.getGlobeRadius(); 33288 let size = d.radius * 0.5; 33289 let height = size * (3/5); 33290 // Set minimum altitude without dividing by globe radius 33291 let minAltitude = height + 1; 33292 let altitude = Math.max(d.altitude, minAltitude); 33293 let altitudeInUnits = parseFloat((altitude * globeRadius).toFixed(2)) * 0.01; 33294 let poleRadius = size * 0.025; 33295 let animate = d.animate ? globe_ut_bool(d.animate) : true; 33296 let width = size; 33297 let flagMaterial; 33298 let flagPole = createFlagPole(d, thisGlobe); 33299 33300 flagGroup.add(flagPole); 33301 33302 flagMaterial = new MeshBasicMaterial({ 33303 map: thisGlobe.textureLoader.load(d.image.url), 33304 side: DoubleSide, 33305 transparent: true 33306 }); 33307 33308 const geometry = new PlaneGeometry(width, height, width, height); 33309 const flagMesh = new Mesh(geometry, flagMaterial); 33310 33311 // Position flag mesh with bottom edge at the top of the pole 33312 flagMesh.position.set(width/2 + poleRadius, altitudeInUnits - height/2, 0); 33313 33314 // Update geometry and position once image loads 33315 const img = new Image(); 33316 img.onload = function() {
33317 const aspectRatio = img.height / img.width; 33318 const adjustedHeight = width * aspectRatio; 33319 33320 // Update geometry with correct dimensions 33321 flagMesh.geometry = new PlaneGeometry(width, adjustedHeight, width, adjustedHeight); 33322 33323 // Update position to account for new height, keeping bottom edge at top of pole 33324 flagMesh.position.set(width/2 + poleRadius, altitudeInUnits - adjustedHeight/2, 0); 33325 }; 33326 img.src = d.image.url; 33327 33328 const animateFunction = () => { 33329 // Get the position attribute 33330 const positions = flagMesh.geometry.getAttribute('position'); 33331 33332 for (let y = 0; y <= height; y++) { 33333 for (let x = 0; x <= width; x++) { 33334 const index = x + y * (width + 1); 33335 // Create wave effect by combining sine waves 33336 const waveX = Math.sin(x * 0.5 - Date.now() * 0.003) * 0.5; 33337 const waveY = Math.sin(y * 0.3 - Date.now() * 0.004) * 0.3; 33338 const wave = waveX + waveY; 33339 // Increase amplitude towards flag edge 33340 const amplitude = (x / width) * 2; 33341 positions.array[index * 3 + 2] = wave * amplitude; 33342 } 33343 } 33344 33345 // Mark the positions as needing an update 33346 positions.needsUpdate = true; 33347 requestAnimationFrame(animateFunction); 33348 }; 33349 33350 if(animate){ 33351 animateFunction(); 33352 } 33353 33354 flagGroup.add(flagMesh); 33355 33356 // Rotate entire flag group to be perpendicular to globe surface 33357 flagGroup.rotation.x = Math.PI / 2; 33358 return flagGroup; 33359} 33360 33361function createFlagPole(d, thisGlobe) { 33362 let globeRadius = thisGlobe.getGlobeRadius(); 33363 let size = d.radius * 0.5; 33364 let height = size * (3/5); 33365 // Use the same minimum altitude calculation as the flag 33366 let minAltitude = height + 1; 33367 let altitude = Math.max(d.altitude, minAltitude); 33368 let altitudeInUnits = parseFloat((altitude * globeRadius).toFixed(2)) * 0.01; 33369 let poleRadius = size * 0.025; 33370 33371 let geometry = new CylinderGeometry(poleRadius, poleRadius, altitudeInUnits, 16, 1); 33372 let material = new MeshPhongMaterial({ 33373 color: d.color, 33374 specular: "#999999", 33375 shininess: 30 33376 }); 33377 const pole = new Mesh(geometry, material); 33378 33379 // Position the pole so its base is at the surface and it extends upward 33380 pole.position.set(0, altitudeInUnits/2, 0); 33381 33382 return pole; 33383} 33384 33385/** Create a 3d image object */ 33386function createImage(d, thisGlobe) { 33387 33388 const textureLoader = thisGlobe.textureLoader; 33389 const group = new Group(); 33390 let size = d.radius; 33391 33392 // currently not being used, could be a future feature 33393 let includeLine = d.includeLine ? globe_ut_bool(d.includeLine) : false; 33394 let animate = d.animate ? globe_ut_bool(d.animate) : false; 33395 33396 // Get globe width and altitude in units 33397 const globeRadius = thisGlobe.getGlobeRadius(); 33398 const altitudeInUnits = parseFloat((d.altitude * globeRadius).toFixed(2)) * 0.01; 33399 33400 // Create a plane geometry for the image 33401 // Load the image and calculate its aspect ratio 33402 const img = new Image(); 33403 img.onload = function() {
33404 const aspectRatio = img.height / img.width; 33405 const width = size; 33406 const height = width * aspectRatio; 33407 33408 // Update plane geometry with calculated dimensions 33409 const planeGeometry = new PlaneGeometry(width, height); 33410 imagePlane.geometry = planeGeometry; 33411 33412 // Ensure the plane is centered 33413 if(d.imageOrientation === 'horizontal'){ 33414 imagePlane.position.set(0, 0, altitudeInUnits); 33415 } else { 33416 imagePlane.position.set(0, 0, altitudeInUnits + height / 2); 33417 } 33418 33419 }; 33420 33421 img.src = d.image.url; 33422 33423 const planeGeometry = new PlaneGeometry(size, size); 33424 33425 // Load the texture from the image URL 33426 const texture = textureLoader.load(d.image.url); 33427 const planeMaterial = new MeshBasicMaterial({ 33428 map: texture, 33429 transparent: true, 33430 side: DoubleSide 33431 }); 33432 33433 const imagePlane = new Mesh(planeGeometry, planeMaterial); 33434 33435 // Position the image plane 33436 imagePlane.position.set(0, 0, altitudeInUnits); 33437 33438 let orientation = new Vector3(0, -1, altitudeInUnits); 33439 if(d.imageOrientation === 'horizontal'){ 33440 orientation = new Vector3(0, 0, 0); 33441 } 33442 33443 // Rotate the image plane to face outward or vertical from the globe 33444 imagePlane.lookAt(orientation); 33445 33446 group.add(imagePlane); 33447 33448 // Create a line from the surface to the image 33449 // currently not being used, could be a future feature 33450 if (altitudeInUnits > 1 && includeLine) { 33451 const lineGeometry = new BufferGeometry().setFromPoints([ 33452 new Vector3(0, 0, 0), // Start from the globe surface 33453 new Vector3(0, 0, altitudeInUnits) // End at the image 33454 ]); 33455 33456 const lineMaterial = new LineBasicMaterial({ color: d.color }); 33457 const line = new Line(lineGeometry, lineMaterial); 33458 group.add(line); 33459 } 33460 33461 // Add animation for vertical orientation 33462 // currently not being used, could be a future feature 33463 if (animate) { 33464 const animate = () => { 33465 imagePlane.rotation.y += 0.05; // Adjust rotation speed as needed 33466 requestAnimationFrame(animate); 33467 }; 33468 animate(); 33469 } 33470 33471 return group; 33472 33473} 33474 33475/** Create a 3d marker object */ 33476function createMarker(d, thisGlobe) { 33477 // Create the outer shape of the pin 33478 const outerShape = new Shape(); 33479 outerShape.moveTo(0, 0); 33480 outerShape.bezierCurveTo(0, 0.8, 0.8, 1.6, 1.6, 1.6); 33481 outerShape.bezierCurveTo(2.4, 1.6, 3.2, 0.8, 3.2, 0); 33482 outerShape.bezierCurveTo(3.2, -0.8, 2.4, -2.4, 1.6, -4); 33483 outerShape.bezierCurveTo(0.8, -2.4, 0, -0.8, 0, 0); 33484 33485 // Create the inner shape for the hole with a bigger radius and moved down 33486 const innerShape = new Path(); 33487 innerShape.moveTo(1.6, 0.6); 33488 innerShape.absarc(1.6, 0.6, 0.9, 0, Math.PI * 2, false); 33489 33490 outerShape.holes.push(innerShape); 33491 33492 // Create extrusion settings 33493 const extrudeSettings = { 33494 steps: 2, 33495 depth: 0.4, 33496 bevelEnabled: true, 33497 bevelThickness: 0.2, 33498 bevelSize: 0.1, 33499 bevelSegments: 1 33500 }; 33501 33502 // Create geometry 33503 const geometry = new ExtrudeGeometry(outerShape, extrudeSettings); 33504 33505 // Center the geometry so that its local origin (0, 0, 0) is in the middle 33506 geometry.center(); 33507 33508 // Create material 33509 const material = new MeshPhongMaterial({ 33510 color: d.color, 33511 shininess: 100 33512 }); 33513 33514 // Create mesh 33515 const pinMesh = new Mesh(geometry, material); 33516 33517 // Rotate the pin to face the globe 33518 pinMesh.lookAt(new Vector3(0, 0, 0)); 33519 pinMesh.rotateX(Math.PI / 2); 33520 33521 // Scale the pin 33522 const scale = d.radius * 0.1; // Reduced scale to make pins smaller 33523 pinMesh.scale.set(scale, scale, scale); 33524 33525 // Move the pin up/away from the globe 33526 const offset = scale * 3 + d.altitude * 0.1; // Adjust this value to fine-tune the offset 33527 pinMesh.position.set(0, 0, offset); 33528 33529 // Add animation for vertical orientation 33530 if (d.animate) { 33531 const animate = () => { 33532 pinMesh.rotation.y += 0.05; // Adjust rotation speed as needed 33533 requestAnimationFrame(animate); 33534 }; 33535 animate(); 33536 } 33537 33538 return pinMesh; 33539} 33540 33541 33542/** Create a pin object */ 33543function createPin(d, thisGlobe) { 33544 33545 const group = new Group(); 33546 33547 // radius will originally be 20 for example. 33548 // altitude will originally be 10 for example. 33549 let AdjustedRadius = parseFloat((d.radius * 0.2).toFixed(2)); 33550 let AdjustedAltitude = parseFloat((d.altitude / 100 ).toFixed(2)); 33551 // Get globe radius and altitude in units 33552 const globeRadius = thisGlobe.getGlobeRadius(); 33553 const altitudeInUnits = parseFloat((AdjustedAltitude * globeRadius).toFixed(2)); 33554 // Sphere for the round part 33555 const sphereGeometry = new SphereGeometry(AdjustedRadius, 32, 32); 33556 const sphereMaterial = new MeshLambertMaterial({ color: d.color }); 33557 const sphere = new Mesh(sphereGeometry, sphereMaterial); 33558 33559 // Position the sphere so that it sits above the cone 33560 sphere.position.set(0, 0, altitudeInUnits); // Adjusted position based on cone's rotation 33561 33562 group.add(sphere); 33563 33564 // Cone for the pointer 33565 const coneHeight = Math.max(0, parseInt(altitudeInUnits)); 33566 if(coneHeight > 0){ 33567 const coneGeometry = new ConeGeometry(AdjustedRadius/4, coneHeight, 32); 33568 const coneMaterial = new MeshLambertMaterial({ color: d.color }); 33569 const cone = new Mesh(coneGeometry, coneMaterial); 33570 33571 cone.position.set(0, 0, coneHeight/2); 33572 cone.rotation.y = -Math.PI / 2; // Keep the rotation around Y 33573 cone.rotation.x = -Math.PI / 2; // Keep the rotation around X 33574 33575 group.add(cone); 33576 } 33577 return group; 33578} 33579 33580/** 33581 * Adds Auto Rotate and its speed controls 33582 * @param {*} thisGlobe 33583 * @param {*} data 33584 */ 33585function addAutoRotate( thisGlobe, data ) { 33586 if (typeof data.rotate !== 'undefined' && globe_ut_bool(data.rotate.enabled)) { 33587 thisGlobe.controls().autoRotate = true; 33588 thisGlobe.controls().autoRotateSpeed = data.rotate.speed; 33589 } 33590} 33591 33592/** 33593 * Handles click actions to display content 33594 */ 33595function displayContent( thisGlobe, GlobeData, data, position, scroll ) { 33596 33597 // we could try to use thisGlobe to rotate the globe to the clicked coordinates 33598 // and we could use position to target specific container, if multiple displayContent were selected 33599 33600 var contentContainer = document.getElementById('itt_globe_content_' + position + '_' + GlobeData.id ); 33601 33602 if ( contentContainer === undefined || contentContainer === null ) { 33603 return; 33604 } 33605 var thisContent = data.content ? data.content : ''; 33606 33607 contentContainer.innerHTML = thisContent; 33608 33609 if (scroll) { 33610 var originalTop = Math.floor(contentContainer.getBoundingClientRect().top - 100); 33611 window.scrollBy({ 33612 top: originalTop, 33613 left: 0, 33614 behavior: 'smooth', 33615 }); 33616 } 33617 33618} 33619 33620function contentBelowScroll( thisGlobe, GlobeData, data ) { 33621 displayContent( thisGlobe, GlobeData, data, 'below', true ); 33622} 33623 33624function contentBelow( thisGlobe, GlobeData, data ) { 33625 displayContent( thisGlobe, GlobeData, data, 'below', false ); 33626} 33627 33628function contentAbove( thisGlobe, GlobeData, data ) { 33629 displayContent( thisGlobe, GlobeData, data, 'above', false ); 33630} 33631 33632function contentRight( thisGlobe, GlobeData, data ) { 33633 displayContent( thisGlobe, GlobeData, data, 'right', false ); 33634} 33635 33636function contentLeft( thisGlobe, GlobeData, data ) { 33637 displayContent( thisGlobe, GlobeData, data, 'left', false ); 33638} 33639 33640function contentLighbox( thisGlobe, GlobeData, data ) { 33641 openLightbox( thisGlobe, GlobeData, data, 'inline' ); 33642} 33643 33644function iframeLightbox( thisGlobe, GlobeData, data ) { 33645 openLightbox( thisGlobe, GlobeData, data, 'iframe' ); 33646} 33647 33648function openLightbox( thisGlobe, GlobeData, data, type ) { 33649 //function (id, data, type) { 33650 var elements = [], 33651 width = window.innerWidth < 900 ? '90%' : '60%', 33652 opts = {}; 33653 33654 if (type === 'inline') { 33655 elements.push({ 33656 content: data.content, 33657 type: type, 33658 width: width, 33659 height: 'auto', 33660 }); 33661 } else if (type === 'iframe') { 33662 elements.push({ 33663 href: data.content, 33664 type: 'external', 33665 width: width, 33666 height: parseInt(window.innerHeight * 0.8), 33667 }); 33668 } 33669 33670 opts = { 33671 touchNavigation: false, 33672 draggable: false, 33673 keyboardNavigation: false, 33674 loopAtEnd: false, 33675 loop: false, 33676 zoomable: false, 33677 elements: elements, 33678 closeButton: true, 33679 closeOnOutsideClick: true, 33680 }; 33681 33682 // fix for lightbox closing on bigger touch devices 33683 /* 33684 if (window.innerWidth > 768 && functionToCheckifTouchScreenDevice()) { 33685 opts.closeOnOutsideClick = false;
33686 } 33687 */ 33688 33689 // let's make it global for better debugging, just in case 33690 ittGlobes.lightbox = GLightbox(opts); 33691 33692 if (data.content !== '' && ittGlobes.lightbox) { 33693 ittGlobes.lightbox.open(); 33694 ittGlobes.lightboxIsRunning = true; 33695 } else { 33696 console.debug('Empty Action Content or Incorrect Request - Lightbox not triggered'); 33697 } 33698 33699 ittGlobes.lightbox.on('close', function () { 33700 console.debug('lightbox closed, we might need to reset stuff'); 33701 ittGlobes.lightboxIsRunning = false; 33702 }); 33703 33704 // add custom close button to solve issues on touch devices 33705 ittGlobes.lightbox.on('open', function () { 33706 console.debug('Open event not working?'); 33707 /* 33708 let close = document.querySelector('.ginner-container .gslide-media .ittglobe_close'); 33709 if (!close) { 33710 close = document.createElement('span'); 33711 close.classList.add('ittglobe_close'); 33712 close.innerHTML = 'XXXâ³'; 33713 let containers = document.querySelectorAll('.ginner-container .gslide-media'); 33714 containers.forEach(function (el) { 33715 let clone = close.cloneNode(true); 33716 clone.addEventListener('click', function () { 33717 lightbox.close(); 33718 }); 33719 33720 el.prepend(clone); 33721 }); 33722 } 33723 */ 33724 }); 33725} 33726 33727ittGlobes$1.clickActions.DisplayContentBelow = contentBelow; 33728ittGlobes$1.clickActions.DisplayContentBelowScroll = contentBelowScroll; 33729ittGlobes$1.clickActions.DisplayContentAbove = contentAbove; 33730ittGlobes$1.clickActions.DisplayContentRight = contentRight; 33731ittGlobes$1.clickActions.DisplayContentLeft = contentLeft; 33732ittGlobes$1.clickActions.DisplayContentLightbox = contentLighbox; 33733ittGlobes$1.clickActions.DisplayIframeLightbox = iframeLightbox; 33734 33735/** initialize globe */ 33736ittGlobes$1.pro = function () { 33737 33738 // check for globe container created by the shortcode 33739 let globe_render_container = document.getElementsByClassName( 'js-itt-globe-render' ); 33740 for (const globe_container of globe_render_container) { 33741 if ( ! globe_container.dataset.hasOwnProperty('globe_id') ) { 33742 continue; 33743 } 33744 let globe_id = 0; 33745 try { 33746 globe_id = parseInt( JSON.parse(globe_container.dataset.globe_id ) ); 33747 } catch (e) { 33748 continue; 33749 } 33750 33751 if ( ! globe_container.dataset.hasOwnProperty( 'globe_meta' ) ) { 33752 continue; 33753 } 33754 33755 let globe_meta = {}; 33756 try { 33757 globe_meta = JSON.parse( globe_container.dataset.globe_meta ); 33758 } catch (e) { 33759 globe_meta = {}; 33760 } 33761 33762 if ( globe_meta.library === 'maplibre' ) { 33763 return; 33764 } 33765 33766 extend_globe( globe_id, globe_meta ); 33767 } 33768}; 33769 33770var extend_globe = function ( id, data ) { 33771 //data types - normal 33772 let dataTypes = { 33773 'arcLines': 'arcLineDefaults', 33774 'regions': 'regionDefaults', 33775 'html': 'htmlDefaults', 33776 'objects': 'pointDefaults', 33777 }; 33778 33779 globe_ut_prepareData( data ); 33780 globe_ut_prepareProData( data ); 33781 globe_ut_setupData( data, dataTypes ); 33782 33783 let thisGlobe = ittGlobes$1.globesIndex[ id ]; 33784 33785 if ( data.globeImage === 'earth-hollow' ) { 33786 thisGlobe.showGlobe(false).showAtmosphere(false); 33787 } 33788 33789 if( data.globeImage === 'noImage' ){ 33790 // return compatible color object 33791 let globeColor = typeof data.globeColor !== 'undefined' ? data.globeColor : '#064273'; 33792 thisGlobe.globeMaterial().color.set( globeColor ); 33793 } 33794 33795 if ( data.globeImage === 'customImage' ) { 33796 let globeCustomImage = typeof data.customImage !== 'undefined' ? data.customImage.url : false; 33797 thisGlobe.globeImageUrl( globeCustomImage ); 33798 } 33799 33800 addAutoRotate( thisGlobe, data ); 33801 addArcsLayer( thisGlobe, data ); 33802 addHTMLElementsLayer( thisGlobe, data ); 33803 33804 // if there's a live filter, add that info to the main globe 33805 if( data.layers && Array.isArray(data.layers) && data.liveFilter && data.liveFilter.enabled === "1" ){ 33806 thisGlobe.liveFilter = data.liveFilter; 33807 } 33808 33809 // setup marker objects 33810 if ( data.objects ) { 33811 addObjectsLayer( thisGlobe, data ); 33812 } 33813 33814 // overlay layers for Regions, async 33815 // Wait for the addRegionLayer async operation to complete 33816 (async () => { 33817 await Promise.resolve(addRegionLayer(thisGlobe, data)); 33818 33819 // Now that addRegionLayer is complete, we can proceed with the overlay layers 33820 if (data.layers && Array.isArray(data.layers)) { 33821 let altitudeMultiplier = 1; 33822 for (let layer of data.layers) { 33823 if (layer.regions && Array.isArray(layer.regions)) { 33824 33825 globe_ut_setupData( layer, {'regions': 'regionDefaults'} ); 33826 33827 // fetch regions 33828 const existingRegions = thisGlobe.originalPolygonsData || []; 33829 const layerData = { ...layer, onlyActiveRegions: true }; 33830 const preparedLayerRegions = await prepareRegions(thisGlobe, layerData, alt
33830itudeMultiplier) || []; 33831 const mergedRegions = [...existingRegions, ...preparedLayerRegions]; 33832 33833 altitudeMultiplier++; 33834 33835 thisGlobe.originalPolygonsData = mergedRegions; 33836 33837 if (data.liveFilter && data.liveFilter.enabled === "1" && parseInt(data.liveFilter.default) !== parseInt(id)) { 33838 if (parseInt(data.liveFilter.default) === parseInt(layer.id)) { 33839 // we need to keep base, so merge base also 33840 if (data.liveFilter.keepBase === "1") { 33841 let baseAndLayerRegions = [...thisGlobe.basePolygonsData, ...preparedLayerRegions]; 33842 thisGlobe.polygonsData(baseAndLayerRegions); 33843 } else { 33844 thisGlobe.polygonsData(layer.regions); 33845 } 33846 } 33847 } else { 33848 thisGlobe.polygonsData(mergedRegions); 33849 } 33850 } 33851 } 33852 } 33853 })(); 33854 33855 // overlay layers for dotLabels, points, object markers and arcs 33856 if( data.layers && Array.isArray( data.layers ) ){ 33857 // Initialize arrays for data collection 33858 thisGlobe.originalPointsData = thisGlobe.pointsData(); 33859 thisGlobe.originalLabelsData = thisGlobe.labelsData(); 33860 thisGlobe.originalArcsData = thisGlobe.arcsData(); 33861 thisGlobe.originalHtmlData = thisGlobe.htmlElementsData(); 33862 thisGlobe.originalObjectsData = thisGlobe.objectsData(); 33863 33864 // store original base map data, if needed 33865 thisGlobe.basePointsData = thisGlobe.pointsData(); 33866 thisGlobe.baseLabelsData = thisGlobe.labelsData(); 33867 thisGlobe.baseArcsData = thisGlobe.arcsData(); 33868 thisGlobe.baseHtmlData = thisGlobe.htmlElementsData(); 33869 thisGlobe.baseObjectsData = thisGlobe.objectsData(); 33870 33871 for( let layer of data.layers ){ 33872 33873 let layerDataTypes = { 33874 'arcLines': 'arcLineDefaults', 33875 'points': 'pointDefaults', 33876 'objects': 'pointDefaults', 33877 'dotLabels': 'labelDefaults', 33878 'html': 'htmlDefaults', 33879 'pins': 'pointDefaults' 33880 }; 33881 33882 globe_ut_setupData( layer, layerDataTypes ); 33883 // points 33884 if (layer.points && Array.isArray(layer.points)) { 33885 33886 const existingPoints = thisGlobe.originalPointsData; 33887 const mergedPoints = [...existingPoints, ...layer.points]; 33888 33889 thisGlobe.originalPointsData = mergedPoints; 33890 33891 if( data.liveFilter && data.liveFilter.enabled === "1" && parseInt( data.liveFilter.default ) !== parseInt( id ) ){ 33892 if( parseInt( data.liveFilter.default ) === parseInt( layer.id ) ){ 33893 thisGlobe.pointsData(layer.points); 33894 // we need to keep base, so merge base also 33895 if( data.liveFilter.keepBase === "1" ){ 33896 let baseAndLayerPoints = [...thisGlobe.basePointsData, ...layer.points]; 33897 thisGlobe.pointsData( baseAndLayerPoints ); 33898 } 33899 } 33900 } else { 33901 thisGlobe.pointsData(mergedPoints); 33902 } 33903 } 33904 33905 // html 33906 if (layer.html && Array.isArray(layer.html)) { 33907 const existingHtml = thisGlobe.originalHtmlData; 33908 const mergedHtml = [...existingHtml, ...layer.html]; 33909 33910 thisGlobe.originalHtmlData = mergedHtml; 33911 33912 if( data.liveFilter && data.liveFilter.enabled === "1" && parseInt( data.liveFilter.default ) !== parseInt( id ) ){ 33913 if( parseInt( data.liveFilter.default ) === parseInt( layer.id ) ){ 33914 thisGlobe.htmlElementsData(layer.html); 33915 } 33916 } else { 33917 thisGlobe.htmlElementsData(mergedHtml); 33918 } 33919 } 33920 // objects 33921 if (layer.objects && Array.isArray(layer.objects)) { 33922 33923 const existingObjects = thisGlobe.originalObjectsData; 33924 const mergedObjects = [...existingObjects, ...layer.objects]; 33925 33926 thisGlobe.originalObjectsData = mergedObjects; 33927 33928 if( data.liveFilter && data.liveFilter.enabled === "1" && parseInt( data.liveFilter.default ) !== parseInt( id ) ){ 33929 if( parseInt( data.liveFilter.default ) === parseInt( layer.id ) ){ 33930 thisGlobe.objectsData(layer.objects); 33931 // we need to keep base, so merge base also 33932 if( data.liveFilter.keepBase === "1" ){ 33933 let baseAndLayerObjects = [...thisGlobe.baseObjectsData, ...layer.objects]; 33934 thisGlobe.objectsData( baseAndLayerObjects ); 33935 } 33936 } 33937 } else { 33938 thisGlobe.objectsData(mergedObjects); 33939 } 33940 } 33941 33942 // dot labels 33943 if (layer.dotLabels && Array.isArray(layer.dotLabels)) { 33944 const existingLabels = thisGlobe.originalLabelsData; 33945 const mergedLabels = [...existingLabels, ...layer.dotLabels]; 33946 33947 thisGlobe.originalLabelsData = mergedLabels; 33948 33949 if( data.liveFilter && data.liveFilter.enabled === "1" && parseInt( data.liveFilter.default ) !== parseInt( id ) ){ 33950 if( parseInt( data.liveFilter.default ) === parseInt( layer.id ) ){ 33951 thisGlobe.labelsData(layer.dotLabels); 33952 // we need to keep base, so merge base also 33953 if( data.liveFilter.keepBase === "1" ){ 33954 let baseAndLayerDotLabels = [...thisGlobe.baseLabelsData, ...layer.dotLabels]; 33955 thisGlobe.labelsData( baseAndLayerDotLabels ); 33956 } 33957 } 33958 } else { 33959 thisGlobe.labelsData(mergedLabels); 33960 } 33961 } 33962 33963 // arcs 33964 if (layer.arcLines && Array.isArray(layer.arcLines)) { 33965 const existingArcs = thisGlobe.originalArcsData; 33966 const mergedArcs = [...existingArcs, ...layer.arcLines]; 33967 33968 thisGlobe.originalArcsData = mergedArcs; 33969 33970 if( data.liveFilter && data.liveFilter.enabled === "1" && parseInt( data.liveFilter.default ) !== parseInt( id ) ){ 33971 if( parseInt( data.liveFilter.default ) === parseInt( layer.id ) ){ 33972 thisGlobe.arcsData(layer.arcLines); 33973 // we need to keep base, so merge base also 33974 if( data.liveFilter.keepBase === "1" ){ 33975 let baseAndLayerArcs = [...thisGlobe.baseArcsData, ...layer.arcLines]; 33976 thisGlobe.arcsData( baseAndLayerArcs ); 33977 } 33978 } 33979 } else { 33980 thisGlobe.arcsData(mergedArcs); 33981 } 33982 } 33983 33984 // regions are done async 33985 } 33986 } 33987 33988 const existingOnGlobeReady = thisGlobe.onGlobeReady(); 33989 thisGlobe.onGlobeReady(function () { 33990 if ( existingOnGlobeReady ) { 33991 existingOnGlobeReady(); 33992 } 33993 setCustomGraticule( thisGlobe, data ); 33994 33995 // only admin hook 33996 if ( ittGlobeData.isAdmin ) { 33997 document.dispatchEvent(new Event("adminProGlobeReady")); 33998 } 33999 }); 34000 34001 34002 // to make it publically accessible 34003 thisGlobe.meta = data; 34004}; 34005 34006ittGlobes$1.pro();
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.