1/** 2 * @license 3 * Copyright 2010-2026 Three.js Authors 4 * SPDX-License-Identifier: MIT 5 */ 6const REVISION = '184'; 7 8/** 9 * Represents mouse buttons and interaction types in context of controls. 10 * 11 * @type {ConstantsMouse} 12 * @constant 13 */ 14const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 }; 15 16/** 17 * Represents touch interaction types in context of controls. 18 * 19 * @type {ConstantsTouch} 20 * @constant 21 */ 22const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 }; 23 24/** 25 * Disables face culling. 26 * 27 * @type {number} 28 * @constant 29 */ 30const CullFaceNone = 0; 31 32/** 33 * Culls back faces. 34 * 35 * @type {number} 36 * @constant 37 */ 38const CullFaceBack = 1; 39 40/** 41 * Culls front faces. 42 * 43 * @type {number} 44 * @constant 45 */ 46const CullFaceFront = 2; 47 48/** 49 * Culls both front and back faces. 50 * 51 * @type {number} 52 * @constant 53 */ 54const CullFaceFrontBack = 3; 55 56/** 57 * Gives unfiltered shadow maps - fastest, but lowest quality. 58 * 59 * @type {number} 60 * @constant 61 */ 62const BasicShadowMap = 0; 63 64/** 65 * Filters shadow maps using the Percentage-Closer Filtering (PCF) algorithm. 66 * 67 * @type {number} 68 * @constant 69 */ 70const PCFShadowMap = 1; 71 72/** 73 * Filters shadow maps using the Percentage-Closer Filtering (PCF) algorithm with 74 * better soft shadows especially when using low-resolution shadow maps. 75 * 76 * @type {number} 77 * @constant
vendor: 28,453 bytes, lines 77-1718
77 78 */ 79const PCFSoftShadowMap = 2; 80 81/** 82 * Filters shadow maps using the Variance Shadow Map (VSM) algorithm. 83 * When using VSMShadowMap all shadow receivers will also cast shadows. 84 * 85 * @type {number} 86 * @constant 87 */ 88const VSMShadowMap = 3; 89 90/** 91 * Only front faces are rendered. 92 * 93 * @type {number} 94 * @constant 95 */ 96const FrontSide = 0; 97 98/** 99 * Only back faces are rendered. 100 * 101 * @type {number} 102 * @constant 103 */ 104const BackSide = 1; 105 106/** 107 * Both front and back faces are rendered. 108 * 109 * @type {number} 110 * @constant 111 */ 112const DoubleSide = 2; 113 114/** 115 * No blending is performed which effectively disables 116 * alpha transparency. 117 * 118 * @type {number} 119 * @constant 120 */ 121const NoBlending = 0; 122 123/** 124 * The default blending. 125 * 126 * @type {number} 127 * @constant 128 */ 129const NormalBlending = 1; 130 131/** 132 * Represents additive blending. 133 * 134 * @type {number} 135 * @constant 136 */ 137const AdditiveBlending = 2; 138 139/** 140 * Represents subtractive blending. 141 * 142 * @type {number} 143 * @constant 144 */ 145const SubtractiveBlending = 3; 146 147/** 148 * Represents multiply blending. 149 * 150 * @type {number} 151 * @constant 152 */ 153const MultiplyBlending = 4; 154 155/** 156 * Represents custom blending. 157 * 158 * @type {number} 159 * @constant 160 */ 161const CustomBlending = 5; 162 163/** 164 * Represents material blending. 165 * 166 * @type {number} 167 * @constant 168 */ 169const MaterialBlending = 6; 170 171/** 172 * A `source + destination` blending equation. 173 * 174 * @type {number} 175 * @constant 176 */ 177const AddEquation = 100; 178 179/** 180 * A `source - destination` blending equation. 181 * 182 * @type {number} 183 * @constant 184 */ 185const SubtractEquation = 101; 186 187/** 188 * A `destination - source` blending equation. 189 * 190 * @type {number} 191 * @constant 192 */ 193const ReverseSubtractEquation = 102; 194 195/** 196 * A blend equation that uses the minimum of source and destination. 197 * 198 * @type {number} 199 * @constant 200 */ 201const MinEquation = 103; 202 203/** 204 * A blend equation that uses the maximum of source and destination. 205 * 206 * @type {number} 207 * @constant 208 */ 209const MaxEquation = 104; 210 211/** 212 * Multiplies all colors by `0`. 213 * 214 * @type {number} 215 * @constant 216 */ 217const ZeroFactor = 200; 218 219/** 220 * Multiplies all colors by `1`. 221 * 222 * @type {number} 223 * @constant 224 */ 225const OneFactor = 201; 226 227/** 228 * Multiplies all colors by the source colors. 229 * 230 * @type {number} 231 * @constant 232 */ 233const SrcColorFactor = 202; 234 235/** 236 * Multiplies all colors by `1` minus each source color. 237 * 238 * @type {number} 239 * @constant 240 */ 241const OneMinusSrcColorFactor = 203; 242 243/** 244 * Multiplies all colors by the source alpha value. 245 * 246 * @type {number} 247 * @constant 248 */ 249const SrcAlphaFactor = 204; 250 251/** 252 * Multiplies all colors by 1 minus the source alpha value. 253 * 254 * @type {number} 255 * @constant 256 */ 257const OneMinusSrcAlphaFactor = 205; 258 259/** 260 * Multiplies all colors by the destination alpha value. 261 * 262 * @type {number} 263 * @constant 264 */ 265const DstAlphaFactor = 206; 266 267/** 268 * Multiplies all colors by `1` minus the destination alpha value. 269 * 270 * @type {number} 271 * @constant 272 */ 273const OneMinusDstAlphaFactor = 207; 274 275/** 276 * Multiplies all colors by the destination color. 277 * 278 * @type {number} 279 * @constant 280 */ 281const DstColorFactor = 208; 282 283/** 284 * Multiplies all colors by `1` minus each destination color. 285 * 286 * @type {number} 287 * @constant 288 */ 289const OneMinusDstColorFactor = 209; 290 291/** 292 * Multiplies the RGB colors by the smaller of either the source alpha 293 * value or the value of `1` minus the destination alpha value. The alpha 294 * value is multiplied by `1`. 295 * 296 * @type {number} 297 * @constant 298 */ 299const SrcAlphaSaturateFactor = 210; 300 301/** 302 * Multiplies all colors by a constant color. 303 * 304 * @type {number} 305 * @constant 306 */ 307const ConstantColorFactor = 211; 308 309/** 310 * Multiplies all colors by `1` minus a constant color. 311 * 312 * @type {number} 313 * @constant 314 */ 315const OneMinusConstantColorFactor = 212; 316 317/** 318 * Multiplies all colors by a constant alpha value. 319 * 320 * @type {number} 321 * @constant 322 */ 323const ConstantAlphaFactor = 213; 324 325/** 326 * Multiplies all colors by 1 minus a constant alpha value. 327 * 328 * @type {number} 329 * @constant 330 */ 331const OneMinusConstantAlphaFactor = 214; 332 333/** 334 * Never pass. 335 * 336 * @type {number} 337 * @constant 338 */ 339const NeverDepth = 0; 340 341/** 342 * Always pass. 343 * 344 * @type {number} 345 * @constant 346 */ 347const AlwaysDepth = 1; 348 349/** 350 * Pass if the incoming value is less than the depth buffer value. 351 * 352 * @type {number} 353 * @constant 354 */ 355const LessDepth = 2; 356 357/** 358 * Pass if the incoming value is less than or equal to the depth buffer value. 359 * 360 * @type {number} 361 * @constant 362 */ 363const LessEqualDepth = 3; 364 365/** 366 * Pass if the incoming value equals the depth buffer value. 367 * 368 * @type {number} 369 * @constant 370 */ 371const EqualDepth = 4; 372 373/** 374 * Pass if the incoming value is greater than or equal to the depth buffer value. 375 * 376 * @type {number} 377 * @constant 378 */ 379const GreaterEqualDepth = 5; 380 381/** 382 * Pass if the incoming value is greater than the depth buffer value. 383 * 384 * @type {number} 385 * @constant 386 */ 387const GreaterDepth = 6; 388 389/** 390 * Pass if the incoming value is not equal to the depth buffer value. 391 * 392 * @type {number} 393 * @constant 394 */ 395const NotEqualDepth = 7; 396 397/** 398 * Multiplies the environment map color with the surface color. 399 * 400 * @type {number} 401 * @constant 402 */ 403const MultiplyOperation = 0; 404 405/** 406 * Uses reflectivity to blend between the two colors. 407 * 408 * @type {number} 409 * @constant 410 */ 411const MixOperation = 1; 412 413/** 414 * Adds the two colors. 415 * 416 * @type {number} 417 * @constant 418 */ 419const AddOperation = 2; 420 421/** 422 * No tone mapping is applied. 423 * 424 * @type {number} 425 * @constant 426 */ 427const NoToneMapping = 0; 428 429/** 430 * Linear tone mapping. 431 * 432 * @type {number} 433 * @constant 434 */ 435const LinearToneMapping = 1; 436 437/** 438 * Reinhard tone mapping. 439 * 440 * @type {number} 441 * @constant 442 */ 443const ReinhardToneMapping = 2; 444 445/** 446 * Cineon tone mapping. 447 * 448 * @type {number} 449 * @constant 450 */ 451const CineonToneMapping = 3; 452 453/** 454 * ACES Filmic tone mapping. 455 * 456 * @type {number} 457 * @constant 458 */ 459const ACESFilmicToneMapping = 4; 460 461/** 462 * Custom tone mapping. 463 * 464 * Expects a custom implementation by modifying shader code of the material's fragment shader. 465 * 466 * @type {number} 467 * @constant 468 */ 469const CustomToneMapping = 5; 470 471/** 472 * AgX tone mapping. 473 * 474 * @type {number} 475 * @constant 476 */ 477const AgXToneMapping = 6; 478 479/** 480 * Neutral tone mapping. 481 * 482 * Implementation based on the Khronos 3D Commerce Group standard tone mapping. 483 * 484 * @type {number} 485 * @constant 486 */ 487const NeutralToneMapping = 7; 488 489/** 490 * The skinned mesh shares the same world space as the skeleton. 491 * 492 * @type {string} 493 * @constant 494 */ 495const AttachedBindMode = 'attached'; 496 497/** 498 * The skinned mesh does not share the same world space as the skeleton. 499 * This is useful when a skeleton is shared across multiple skinned meshes. 500 * 501 * @type {string} 502 * @constant 503 */ 504const DetachedBindMode = 'detached'; 505 506/** 507 * Maps textures using the geometry's UV coordinates. 508 * 509 * @type {number} 510 * @constant 511 */ 512const UVMapping = 300; 513 514/** 515 * Reflection mapping for cube textures. 516 * 517 * @type {number} 518 * @constant 519 */ 520const CubeReflectionMapping = 301; 521 522/** 523 * Refraction mapping for cube textures. 524 * 525 * @type {number} 526 * @constant 527 */ 528const CubeRefractionMapping = 302; 529 530/** 531 * Reflection mapping for equirectangular textures. 532 * 533 * @type {number} 534 * @constant 535 */ 536const EquirectangularReflectionMapping = 303; 537 538/** 539 * Refraction mapping for equirectangular textures. 540 * 541 * @type {number} 542 * @constant 543 */ 544const EquirectangularRefractionMapping = 304; 545 546/** 547 * Reflection mapping for PMREM textures. 548 * 549 * @type {number} 550 * @constant 551 */ 552const CubeUVReflectionMapping = 306; 553 554/** 555 * The texture will simply repeat to infinity. 556 * 557 * @type {number} 558 * @constant 559 */ 560const RepeatWrapping = 1000; 561 562/** 563 * The last pixel of the texture stretches to the edge of the mesh. 564 * 565 * @type {number} 566 * @constant 567 */ 568const ClampToEdgeWrapping = 1001; 569 570/** 571 * The texture will repeats to infinity, mirroring on each repeat. 572 * 573 * @type {number} 574 * @constant 575 */ 576const MirroredRepeatWrapping = 1002; 577 578/** 579 * Returns the value of the texture element that is nearest (in Manhattan distance) 580 * to the specified texture coordinates. 581 * 582 * @type {number} 583 * @constant 584 */ 585const NearestFilter = 1003; 586 587/** 588 * Chooses the mipmap that most closely matches the size of the pixel being textured 589 * and uses the `NearestFilter` criterion (the texel nearest to the center of the pixel) 590 * to produce a texture value. 591 * 592 * @type {number} 593 * @constant 594 */ 595const NearestMipmapNearestFilter = 1004; 596const NearestMipMapNearestFilter = 1004; // legacy 597 598/** 599 * Chooses the two mipmaps that most closely match the size of the pixel being textured and 600 * uses the `NearestFilter` criterion to produce a texture value from each mipmap. 601 * The final texture value is a weighted average of those two values. 602 * 603 * @type {number} 604 * @constant 605 */ 606const NearestMipmapLinearFilter = 1005; 607const NearestMipMapLinearFilter = 1005; // legacy 608 609/** 610 * Returns the weighted average of the four texture elements that are closest to the specified 611 * texture coordinates, and can include items wrapped or repeated from other parts of a texture, 612 * depending on the values of `wrapS` and `wrapT`, and on the exact mapping. 613 * 614 * @type {number} 615 * @constant 616 */ 617const LinearFilter = 1006; 618 619/** 620 * Chooses the mipmap that most closely matches the size of the pixel being textured and uses 621 * the `LinearFilter` criterion (a weighted average of the four texels that are closest to the 622 * center of the pixel) to produce a texture value. 623 * 624 * @type {number} 625 * @constant 626 */ 627const LinearMipmapNearestFilter = 1007; 628const LinearMipMapNearestFilter = 1007; // legacy 629 630/** 631 * Chooses the two mipmaps that most closely match the size of the pixel being textured and uses 632 * the `LinearFilter` criterion to produce a texture value from each mipmap. The final texture value 633 * is a weighted average of those two values. 634 * 635 * @type {number} 636 * @constant 637 */ 638const LinearMipmapLinearFilter = 1008; 639const LinearMipMapLinearFilter = 1008; // legacy 640 641/** 642 * An unsigned byte data type for textures. 643 * 644 * @type {number} 645 * @constant 646 */ 647const UnsignedByteType = 1009; 648 649/** 650 * A byte data type for textures. 651 * 652 * @type {number} 653 * @constant 654 */ 655const ByteType = 1010; 656 657/** 658 * A short data type for textures. 659 * 660 * @type {number} 661 * @constant 662 */ 663const ShortType = 1011; 664 665/** 666 * An unsigned short data type for textures. 667 * 668 * @type {number} 669 * @constant 670 */ 671const UnsignedShortType = 1012; 672 673/** 674 * An int data type for textures. 675 * 676 * @type {number} 677 * @constant 678 */ 679const IntType = 1013; 680 681/** 682 * An unsigned int data type for textures. 683 * 684 * @type {number} 685 * @constant 686 */ 687const UnsignedIntType = 1014; 688 689/** 690 * A float data type for textures. 691 * 692 * @type {number} 693 * @constant 694 */ 695const FloatType = 1015; 696 697/** 698 * A half float data type for textures. 699 * 700 * @type {number} 701 * @constant 702 */ 703const HalfFloatType = 1016; 704 705/** 706 * An unsigned short 4_4_4_4 (packed) data type for textures. 707 * 708 * @type {number} 709 * @constant 710 */ 711const UnsignedShort4444Type = 1017; 712 713/** 714 * An unsigned short 5_5_5_1 (packed) data type for textures. 715 * 716 * @type {number} 717 * @constant 718 */ 719const UnsignedShort5551Type = 1018; 720 721/** 722 * An unsigned int 24_8 data type for textures. 723 * 724 * @type {number} 725 * @constant 726 */ 727const UnsignedInt248Type = 1020; 728 729/** 730 * An unsigned int 5_9_9_9 (packed) data type for textures. 731 * 732 * @type {number} 733 * @constant 734 */ 735const UnsignedInt5999Type = 35902; 736 737/** 738 * An unsigned int 10_11_11 (packed) data type for textures. 739 * 740 * @type {number} 741 * @constant 742 */ 743const UnsignedInt101111Type = 35899; 744 745/** 746 * Discards the red, green and blue components and reads just the alpha component. 747 * 748 * @type {number} 749 * @constant 750 */ 751const AlphaFormat = 1021; 752 753/** 754 * Discards the alpha component and reads the red, green and blue component. 755 * 756 * @type {number} 757 * @constant 758 */ 759const RGBFormat = 1022; 760 761/** 762 * Reads the red, green, blue and alpha components. 763 * 764 * @type {number} 765 * @constant 766 */ 767const RGBAFormat = 1023; 768 769/** 770 * Reads each element as a single depth value, converts it to floating point, and clamps to the range `[0,1]`. 771 * 772 * @type {number} 773 * @constant 774 */ 775const DepthFormat = 1026; 776 777/** 778 * Reads each element is a pair of depth and stencil values. The depth component of the pair is interpreted as 779 * in `DepthFormat`. The stencil component is interpreted based on the depth + stencil internal format. 780 * 781 * @type {number} 782 * @constant 783 */ 784const DepthStencilFormat = 1027; 785 786/** 787 * Discards the green, blue and alpha components and reads just the red component. 788 * 789 * @type {number} 790 * @constant 791 */ 792const RedFormat = 1028; 793 794/** 795 * Discards the green, blue and alpha components and reads just the red component. The texels are read as integers instead of floating point. 796 * 797 * @type {number} 798 * @constant 799 */ 800const RedIntegerFormat = 1029; 801 802/** 803 * Discards the alpha, and blue components and reads the red, and green components. 804 * 805 * @type {number} 806 * @constant 807 */ 808const RGFormat = 1030; 809 810/** 811 * Discards the alpha, and blue components and reads the red, and green components. The texels are read as integers instead of floating point. 812 * 813 * @type {number} 814 * @constant 815 */ 816const RGIntegerFormat = 1031; 817 818/** 819 * Discards the alpha component and reads the red, green and blue component. The texels are read as integers instead of floating point. 820 * 821 * @type {number} 822 * @constant 823 */ 824const RGBIntegerFormat = 1032; 825 826/** 827 * Reads the red, green, blue and alpha components. The texels are read as integers instead of floating point. 828 * 829 * @type {number} 830 * @constant 831 */ 832const RGBAIntegerFormat = 1033; 833 834/** 835 * A DXT1-compressed image in an RGB image format. 836 * 837 * @type {number} 838 * @constant 839 */ 840const RGB_S3TC_DXT1_Format = 33776; 841 842/** 843 * A DXT1-compressed image in an RGB image format with a simple on/off alpha value. 844 * 845 * @type {number} 846 * @constant 847 */ 848const RGBA_S3TC_DXT1_Format = 33777; 849 850/** 851 * A DXT3-compressed image in an RGBA image format. Compared to a 32-bit RGBA texture, it offers 4:1 compression. 852 * 853 * @type {number} 854 * @constant 855 */ 856const RGBA_S3TC_DXT3_Format = 33778; 857 858/** 859 * A DXT5-compressed image in an RGBA image format. It also provides a 4:1 compression, but differs to the DXT3 860 * compression in how the alpha compression is done. 861 * 862 * @type {number} 863 * @constant 864 */ 865const RGBA_S3TC_DXT5_Format = 33779; 866 867/** 868 * PVRTC RGB compression in 4-bit mode. One block for each 4Ã4 pixels. 869 * 870 * @type {number} 871 * @constant 872 */ 873const RGB_PVRTC_4BPPV1_Format = 35840; 874 875/** 876 * PVRTC RGB compression in 2-bit mode. One block for each 8Ã4 pixels. 877 * 878 * @type {number} 879 * @constant 880 */ 881const RGB_PVRTC_2BPPV1_Format = 35841; 882 883/** 884 * PVRTC RGBA compression in 4-bit mode. One block for each 4Ã4 pixels. 885 * 886 * @type {number} 887 * @constant 888 */ 889const RGBA_PVRTC_4BPPV1_Format = 35842; 890 891/** 892 * PVRTC RGBA compression in 2-bit mode. One block for each 8Ã4 pixels. 893 * 894 * @type {number} 895 * @constant 896 */ 897const RGBA_PVRTC_2BPPV1_Format = 35843; 898 899/** 900 * ETC1 RGB format. 901 * 902 * @type {number} 903 * @constant 904 */ 905const RGB_ETC1_Format = 36196; 906 907/** 908 * ETC2 RGB format. 909 * 910 * @type {number} 911 * @constant 912 */ 913const RGB_ETC2_Format = 37492; 914 915/** 916 * ETC2 RGBA format. 917 * 918 * @type {number} 919 * @constant 920 */ 921const RGBA_ETC2_EAC_Format = 37496; 922 923/** 924 * EAC R11 UNORM format. 925 * 926 * @type {number} 927 * @constant 928 */ 929const R11_EAC_Format = 37488; // 0x9270 930 931/** 932 * EAC R11 SNORM format. 933 * 934 * @type {number} 935 * @constant 936 */ 937const SIGNED_R11_EAC_Format = 37489; // 0x9271 938 939/** 940 * EAC RG11 UNORM format. 941 * 942 * @type {number} 943 * @constant 944 */ 945const RG11_EAC_Format = 37490; // 0x9272 946 947/** 948 * EAC RG11 SNORM format. 949 * 950 * @type {number} 951 * @constant 952 */ 953const SIGNED_RG11_EAC_Format = 37491; // 0x9273 954 955/** 956 * ASTC RGBA 4x4 format. 957 * 958 * @type {number} 959 * @constant 960 */ 961const RGBA_ASTC_4x4_Format = 37808; 962 963/** 964 * ASTC RGBA 5x4 format. 965 * 966 * @type {number} 967 * @constant 968 */ 969const RGBA_ASTC_5x4_Format = 37809; 970 971/** 972 * ASTC RGBA 5x5 format. 973 * 974 * @type {number} 975 * @constant 976 */ 977const RGBA_ASTC_5x5_Format = 37810; 978 979/** 980 * ASTC RGBA 6x5 format. 981 * 982 * @type {number} 983 * @constant 984 */ 985const RGBA_ASTC_6x5_Format = 37811; 986 987/** 988 * ASTC RGBA 6x6 format. 989 * 990 * @type {number} 991 * @constant 992 */ 993const RGBA_ASTC_6x6_Format = 37812; 994 995/** 996 * ASTC RGBA 8x5 format. 997 * 998 * @type {number} 999 * @constant 1000 */ 1001const RGBA_ASTC_8x5_Format = 37813; 1002 1003/** 1004 * ASTC RGBA 8x6 format. 1005 * 1006 * @type {number} 1007 * @constant 1008 */ 1009const RGBA_ASTC_8x6_Format = 37814; 1010 1011/** 1012 * ASTC RGBA 8x8 format. 1013 * 1014 * @type {number} 1015 * @constant 1016 */ 1017const RGBA_ASTC_8x8_Format = 37815; 1018 1019/** 1020 * ASTC RGBA 10x5 format. 1021 * 1022 * @type {number} 1023 * @constant 1024 */ 1025const RGBA_ASTC_10x5_Format = 37816; 1026 1027/** 1028 * ASTC RGBA 10x6 format. 1029 * 1030 * @type {number} 1031 * @constant 1032 */ 1033const RGBA_ASTC_10x6_Format = 37817; 1034 1035/** 1036 * ASTC RGBA 10x8 format. 1037 * 1038 * @type {number} 1039 * @constant 1040 */ 1041const RGBA_ASTC_10x8_Format = 37818; 1042 1043/** 1044 * ASTC RGBA 10x10 format. 1045 * 1046 * @type {number} 1047 * @constant 1048 */ 1049const RGBA_ASTC_10x10_Format = 37819; 1050 1051/** 1052 * ASTC RGBA 12x10 format. 1053 * 1054 * @type {number} 1055 * @constant 1056 */ 1057const RGBA_ASTC_12x10_Format = 37820; 1058 1059/** 1060 * ASTC RGBA 12x12 format. 1061 * 1062 * @type {number} 1063 * @constant 1064 */ 1065const RGBA_ASTC_12x12_Format = 37821; 1066 1067/** 1068 * BPTC RGBA format. 1069 * 1070 * @type {number} 1071 * @constant 1072 */ 1073const RGBA_BPTC_Format = 36492; 1074 1075/** 1076 * BPTC Signed RGB format. 1077 * 1078 * @type {number} 1079 * @constant 1080 */ 1081const RGB_BPTC_SIGNED_Format = 36494; 1082 1083/** 1084 * BPTC Unsigned RGB format. 1085 * 1086 * @type {number} 1087 * @constant 1088 */ 1089const RGB_BPTC_UNSIGNED_Format = 36495; 1090 1091/** 1092 * RGTC1 Red format. 1093 * 1094 * @type {number} 1095 * @constant 1096 */ 1097const RED_RGTC1_Format = 36283; 1098 1099/** 1100 * RGTC1 Signed Red format. 1101 * 1102 * @type {number} 1103 * @constant 1104 */ 1105const SIGNED_RED_RGTC1_Format = 36284; 1106 1107/** 1108 * RGTC2 Red Green format. 1109 * 1110 * @type {number} 1111 * @constant 1112 */ 1113const RED_GREEN_RGTC2_Format = 36285; 1114 1115/** 1116 * RGTC2 Signed Red Green format. 1117 * 1118 * @type {number} 1119 * @constant 1120 */ 1121const SIGNED_RED_GREEN_RGTC2_Format = 36286; 1122 1123/** 1124 * Animations are played once. 1125 * 1126 * @type {number} 1127 * @constant 1128 */ 1129const LoopOnce = 2200; 1130 1131/** 1132 * Animations are played with a chosen number of repetitions, each time jumping from 1133 * the end of the clip directly to its beginning. 1134 * 1135 * @type {number} 1136 * @constant 1137 */ 1138const LoopRepeat = 2201; 1139 1140/** 1141 * Animations are played with a chosen number of repetitions, alternately playing forward 1142 * and backward. 1143 * 1144 * @type {number} 1145 * @constant 1146 */ 1147const LoopPingPong = 2202; 1148 1149/** 1150 * Discrete interpolation mode for keyframe tracks. 1151 * 1152 * @type {number} 1153 * @constant 1154 */ 1155const InterpolateDiscrete = 2300; 1156 1157/** 1158 * Linear interpolation mode for keyframe tracks. 1159 * 1160 * @type {number} 1161 * @constant 1162 */ 1163const InterpolateLinear = 2301; 1164 1165/** 1166 * Smooth interpolation mode for keyframe tracks. 1167 * 1168 * @type {number} 1169 * @constant 1170 */ 1171const InterpolateSmooth = 2302; 1172 1173/** 1174 * Bezier interpolation mode for keyframe tracks. 1175 * 1176 * Uses cubic Bezier curves with explicit 2D control points. 1177 * Requires tangent data to be set on the track. 1178 * 1179 * @type {number} 1180 * @constant 1181 */ 1182const InterpolateBezier = 2303; 1183 1184/** 1185 * Zero curvature ending for animations. 1186 * 1187 * @type {number} 1188 * @constant 1189 */ 1190const ZeroCurvatureEnding = 2400; 1191 1192/** 1193 * Zero slope ending for animations. 1194 * 1195 * @type {number} 1196 * @constant 1197 */ 1198const ZeroSlopeEnding = 2401; 1199 1200/** 1201 * Wrap around ending for animations. 1202 * 1203 * @type {number} 1204 * @constant 1205 */ 1206const WrapAroundEnding = 2402; 1207 1208/** 1209 * Default animation blend mode. 1210 * 1211 * @type {number} 1212 * @constant 1213 */ 1214const NormalAnimationBlendMode = 2500; 1215 1216/** 1217 * Additive animation blend mode. Can be used to layer motions on top of 1218 * each other to build complex performances from smaller re-usable assets. 1219 * 1220 * @type {number} 1221 * @constant 1222 */ 1223const AdditiveAnimationBlendMode = 2501; 1224 1225/** 1226 * For every three vertices draw a single triangle. 1227 * 1228 * @type {number} 1229 * @constant 1230 */ 1231const TrianglesDrawMode = 0; 1232 1233/** 1234 * For each vertex draw a triangle from the last three vertices. 1235 * 1236 * @type {number} 1237 * @constant 1238 */ 1239const TriangleStripDrawMode = 1; 1240 1241/** 1242 * For each vertex draw a triangle from the first vertex and the last two vertices. 1243 * 1244 * @type {number} 1245 * @constant 1246 */ 1247const TriangleFanDrawMode = 2; 1248 1249/** 1250 * The depth value is inverted (1.0 - z) for visualization purposes. 1251 * 1252 * @type {number} 1253 * @constant 1254 */ 1255const BasicDepthPacking = 3200; 1256 1257/** 1258 * The depth value is packed into 32 bit RGBA. 1259 * 1260 * @type {number} 1261 * @constant 1262 */ 1263const RGBADepthPacking = 3201; 1264 1265/** 1266 * The depth value is packed into 24 bit RGB. 1267 * 1268 * @type {number} 1269 * @constant 1270 */ 1271const RGBDepthPacking = 3202; 1272 1273/** 1274 * The depth value is packed into 16 bit RG. 1275 * 1276 * @type {number} 1277 * @constant 1278 */ 1279const RGDepthPacking = 3203; 1280 1281/** 1282 * Normal information is relative to the underlying surface. 1283 * 1284 * @type {number} 1285 * @constant 1286 */ 1287const TangentSpaceNormalMap = 0; 1288 1289/** 1290 * Normal information is relative to the object orientation. 1291 * 1292 * @type {number} 1293 * @constant 1294 */ 1295const ObjectSpaceNormalMap = 1; 1296 1297// Color space string identifiers, matching CSS Color Module Level 4 and WebGPU names where available. 1298 1299/** 1300 * No color space. 1301 * 1302 * @type {string} 1303 * @constant 1304 */ 1305const NoColorSpace = ''; 1306 1307/** 1308 * sRGB color space. 1309 * 1310 * @type {string} 1311 * @constant 1312 */ 1313const SRGBColorSpace = 'srgb'; 1314 1315/** 1316 * sRGB-linear color space. 1317 * 1318 * @type {string} 1319 * @constant 1320 */ 1321const LinearSRGBColorSpace = 'srgb-linear'; 1322 1323/** 1324 * Linear transfer function. 1325 * 1326 * @type {string} 1327 * @constant 1328 */ 1329const LinearTransfer = 'linear'; 1330 1331/** 1332 * sRGB transfer function. 1333 * 1334 * @type {string} 1335 * @constant 1336 */ 1337const SRGBTransfer = 'srgb'; 1338 1339/** 1340 * No normal map packing. 1341 * 1342 * @type {string} 1343 * @constant 1344 */ 1345const NoNormalPacking = ''; 1346 1347/** 1348 * Normal RG packing. 1349 * 1350 * @type {string} 1351 * @constant 1352 */ 1353const NormalRGPacking = 'rg'; 1354 1355/** 1356 * Normal GA packing. 1357 * 1358 * @type {string} 1359 * @constant 1360 */ 1361const NormalGAPacking = 'ga'; 1362 1363/** 1364 * Sets the stencil buffer value to `0`. 1365 * 1366 * @type {number} 1367 * @constant 1368 */ 1369const ZeroStencilOp = 0; 1370 1371/** 1372 * Keeps the current value. 1373 * 1374 * @type {number} 1375 * @constant 1376 */ 1377const KeepStencilOp = 7680; 1378 1379/** 1380 * Sets the stencil buffer value to the specified reference value. 1381 * 1382 * @type {number} 1383 * @constant 1384 */ 1385const ReplaceStencilOp = 7681; 1386 1387/** 1388 * Increments the current stencil buffer value. Clamps to the maximum representable unsigned value. 1389 * 1390 * @type {number} 1391 * @constant 1392 */ 1393const IncrementStencilOp = 7682; 1394 1395/** 1396 * Decrements the current stencil buffer value. Clamps to `0`. 1397 * 1398 * @type {number} 1399 * @constant 1400 */ 1401const DecrementStencilOp = 7683; 1402 1403/** 1404 * Increments the current stencil buffer value. Wraps stencil buffer value to zero when incrementing 1405 * the maximum representable unsigned value. 1406 * 1407 * @type {number} 1408 * @constant 1409 */ 1410const IncrementWrapStencilOp = 34055; 1411 1412/** 1413 * Decrements the current stencil buffer value. Wraps stencil buffer value to the maximum representable 1414 * unsigned value when decrementing a stencil buffer value of `0`. 1415 * 1416 * @type {number} 1417 * @constant 1418 */ 1419const DecrementWrapStencilOp = 34056; 1420 1421/** 1422 * Inverts the current stencil buffer value bitwise. 1423 * 1424 * @type {number} 1425 * @constant 1426 */ 1427const InvertStencilOp = 5386; 1428 1429/** 1430 * Will never return true. 1431 * 1432 * @type {number} 1433 * @constant 1434 */ 1435const NeverStencilFunc = 512; 1436 1437/** 1438 * Will return true if the stencil reference value is less than the current stencil value. 1439 * 1440 * @type {number} 1441 * @constant 1442 */ 1443const LessStencilFunc = 513; 1444 1445/** 1446 * Will return true if the stencil reference value is equal to the current stencil value. 1447 * 1448 * @type {number} 1449 * @constant 1450 */ 1451const EqualStencilFunc = 514; 1452 1453/** 1454 * Will return true if the stencil reference value is less than or equal to the current stencil value. 1455 * 1456 * @type {number} 1457 * @constant 1458 */ 1459const LessEqualStencilFunc = 515; 1460 1461/** 1462 * Will return true if the stencil reference value is greater than the current stencil value. 1463 * 1464 * @type {number} 1465 * @constant 1466 */ 1467const GreaterStencilFunc = 516; 1468 1469/** 1470 * Will return true if the stencil reference value is not equal to the current stencil value. 1471 * 1472 * @type {number} 1473 * @constant 1474 */ 1475const NotEqualStencilFunc = 517; 1476 1477/** 1478 * Will return true if the stencil reference value is greater than or equal to the current stencil value. 1479 * 1480 * @type {number} 1481 * @constant 1482 */ 1483const GreaterEqualStencilFunc = 518; 1484 1485/** 1486 * Will always return true. 1487 * 1488 * @type {number} 1489 * @constant 1490 */ 1491const AlwaysStencilFunc = 519; 1492 1493/** 1494 * Never pass. 1495 * 1496 * @type {number} 1497 * @constant 1498 */ 1499const NeverCompare = 512; 1500 1501/** 1502 * Pass if the incoming value is less than the texture value. 1503 * 1504 * @type {number} 1505 * @constant 1506 */ 1507const LessCompare = 513; 1508 1509/** 1510 * Pass if the incoming value equals the texture value. 1511 * 1512 * @type {number} 1513 * @constant 1514 */ 1515const EqualCompare = 514; 1516 1517/** 1518 * Pass if the incoming value is less than or equal to the texture value. 1519 * 1520 * @type {number} 1521 * @constant 1522 */ 1523const LessEqualCompare = 515; 1524 1525/** 1526 * Pass if the incoming value is greater than the texture value. 1527 * 1528 * @type {number} 1529 * @constant 1530 */ 1531const GreaterCompare = 516; 1532 1533/** 1534 * Pass if the incoming value is not equal to the texture value. 1535 * 1536 * @type {number} 1537 * @constant 1538 */ 1539const NotEqualCompare = 517; 1540 1541/** 1542 * Pass if the incoming value is greater than or equal to the texture value. 1543 * 1544 * @type {number} 1545 * @constant 1546 */ 1547const GreaterEqualCompare = 518; 1548 1549/** 1550 * Always pass. 1551 * 1552 * @type {number} 1553 * @constant 1554 */ 1555const AlwaysCompare = 519; 1556 1557/** 1558 * The contents are intended to be specified once by the application, and used many 1559 * times as the source for drawing and image specification commands. 1560 * 1561 * @type {number} 1562 * @constant 1563 */ 1564const StaticDrawUsage = 35044; 1565 1566/** 1567 * The contents are intended to be respecified repeatedly by the application, and 1568 * used many times as the source for drawing and image specification commands. 1569 * 1570 * @type {number} 1571 * @constant 1572 */ 1573const DynamicDrawUsage = 35048; 1574 1575/** 1576 * The contents are intended to be specified once by the application, and used at most 1577 * a few times as the source for drawing and image specification commands. 1578 * 1579 * @type {number} 1580 * @constant 1581 */ 1582const StreamDrawUsage = 35040; 1583 1584/** 1585 * The contents are intended to be specified once by reading data from the 3D API, and queried 1586 * many times by the application. 1587 * 1588 * @type {number} 1589 * @constant 1590 */ 1591const StaticReadUsage = 35045; 1592 1593/** 1594 * The contents are intended to be respecified repeatedly by reading data from the 3D API, and queried 1595 * many times by the application. 1596 * 1597 * @type {number} 1598 * @constant 1599 */ 1600const DynamicReadUsage = 35049; 1601 1602/** 1603 * The contents are intended to be specified once by reading data from the 3D API, and queried at most 1604 * a few times by the application 1605 * 1606 * @type {number} 1607 * @constant 1608 */ 1609const StreamReadUsage = 35041; 1610 1611/** 1612 * The contents are intended to be specified once by reading data from the 3D API, and used many times as 1613 * the source for WebGL drawing and image specification commands. 1614 * 1615 * @type {number} 1616 * @constant 1617 */ 1618const StaticCopyUsage = 35046; 1619 1620/** 1621 * The contents are intended to be respecified repeatedly by reading data from the 3D API, and used many times 1622 * as the source for WebGL drawing and image specification commands. 1623 * 1624 * @type {number} 1625 * @constant 1626 */ 1627const DynamicCopyUsage = 35050; 1628 1629/** 1630 * The contents are intended to be specified once by reading data from the 3D API, and used at most a few times 1631 * as the source for WebGL drawing and image specification commands. 1632 * 1633 * @type {number} 1634 * @constant 1635 */ 1636const StreamCopyUsage = 35042; 1637 1638/** 1639 * GLSL 1 shader code. 1640 * 1641 * @type {string} 1642 * @constant 1643 */ 1644const GLSL1 = '100'; 1645 1646/** 1647 * GLSL 3 shader code. 1648 * 1649 * @type {string} 1650 * @constant 1651 */ 1652const GLSL3 = '300 es'; 1653 1654/** 1655 * WebGL coordinate system. 1656 * 1657 * @type {number} 1658 * @constant 1659 */ 1660const WebGLCoordinateSystem = 2000; 1661 1662/** 1663 * WebGPU coordinate system. 1664 * 1665 * @type {number} 1666 * @constant 1667 */ 1668const WebGPUCoordinateSystem = 2001; 1669 1670/** 1671 * Represents the different timestamp query types. 1672 * 1673 * @type {ConstantsTimestampQuery} 1674 * @constant 1675 */ 1676const TimestampQuery = { 1677 COMPUTE: 'compute', 1678 RENDER: 'render' 1679}; 1680 1681/** 1682 * Represents mouse buttons and interaction types in context of controls. 1683 * 1684 * @type {ConstantsInterpolationSamplingType} 1685 * @constant 1686 */ 1687const InterpolationSamplingType = { 1688 PERSPECTIVE: 'perspective', 1689 LINEAR: 'linear', 1690 FLAT: 'flat' 1691}; 1692 1693/** 1694 * Represents the different interpolation sampling modes. 1695 * 1696 * @type {ConstantsInterpolationSamplingMode} 1697 * @constant 1698 */ 1699const InterpolationSamplingMode = { 1700 NORMAL: 'normal', 1701 CENTROID: 'centroid', 1702 SAMPLE: 'sample', 1703 FIRST: 'first', 1704 EITHER: 'either' 1705}; 1706 1707/** 1708 * Compatibility flags for features that may not be supported across all platforms. 1709 * 1710 * @type {Object} 1711 * @constant 1712 */ 1713const Compatibility = { 1714 TEXTURE_COMPARE: 'depthTextureCompare' 1715}; 1716 1717/** 1718 *
1718This type represents mouse buttons and interaction types in context of controls. 1719 * 1720 * @typedef {Object} ConstantsMouse 1721 * @property {number} MIDDLE - The left mouse button. 1722 * @property {number} LEFT - The middle mouse button. 1723 * @property {number} RIGHT - The right mouse button. 1724 * @property {number} ROTATE - A rotate interaction. 1725 * @property {number} DOLLY - A dolly interaction. 1726 * @property {number} PAN - A pan interaction. 1727 **/ 1728 1729/** 1730 * This type represents touch interaction types in context of controls. 1731 * 1732 * @typedef {Object} ConstantsTouch 1733 * @property {number} ROTATE - A rotate interaction. 1734 * @property {number} PAN - A pan interaction. 1735 * @property {number} DOLLY_PAN - The dolly-pan interaction. 1736 * @property {number} DOLLY_ROTATE - A dolly-rotate interaction. 1737 **/ 1738 1739/** 1740 * This type represents the different timestamp query types. 1741 * 1742 * @typedef {Object} ConstantsTimestampQuery 1743 * @property {string} COMPUTE - A `compute` timestamp query. 1744 * @property {string} RENDER - A `render` timestamp query. 1745 **/ 1746 1747/** 1748 * Represents the different interpolation sampling types. 1749 * 1750 * @typedef {Object} ConstantsInterpolationSamplingType 1751 * @property {string} PERSPECTIVE - Perspective-correct interpolation. 1752 * @property {string} LINEAR - Linear interpolation. 1753 * @property {string} FLAT - Flat interpolation. 1754 */ 1755 1756/** 1757 * Represents the different interpolation sampling modes. 1758 * 1759 * @typedef {Object} ConstantsInterpolationSamplingMode 1760 * @property {string} NORMAL - Normal sampling mode. 1761 * @property {string} CENTROID - Centroid sampling mode. 1762 * @property {string} SAMPLE - Sample-specific sampling mode. 1763 * @property {string} FIRST - Flat interpolation using the first vertex. 1764 * @property {string} EITHER - Flat interpolation using either vertex
vendor: 21,397 bytes, lines 1764-2561
1764. 1765 */ 1766 1767/** 1768 * Checks if an array contains values that require Uint32 representation. 1769 * 1770 * This function determines whether the array contains any values >= 65535, 1771 * which would require a Uint32Array rather than a Uint16Array for proper storage. 1772 * The function iterates from the end of the array, assuming larger values are 1773 * typically located at the end. 1774 * 1775 * @private 1776 * @param {Array<number>} array - The array to check. 1777 * @return {boolean} True if the array contains values >= 65535, false otherwise. 1778 */ 1779function arrayNeedsUint32( array ) { 1780 1781 // assumes larger values usually on last 1782 1783 for ( let i = array.length - 1; i >= 0; -- i ) { 1784 1785 if ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565 1786 1787 } 1788 1789 return false; 1790 1791} 1792 1793/** 1794 * Map of typed array constructor names to their constructors. 1795 * This mapping enables dynamic creation of typed arrays based on string type names. 1796 * 1797 * @private 1798 * @constant 1799 * @type {Object<string, TypedArrayConstructor>} 1800 */ 1801const TYPED_ARRAYS = { 1802 Int8Array: Int8Array, 1803 Uint8Array: Uint8Array, 1804 Uint8ClampedArray: Uint8ClampedArray, 1805 Int16Array: Int16Array, 1806 Uint16Array: Uint16Array, 1807 Int32Array: Int32Array, 1808 Uint32Array: Uint32Array, 1809 Float32Array: Float32Array, 1810 Float64Array: Float64Array 1811}; 1812 1813/** 1814 * Creates a typed array of the specified type from the given buffer. 1815 * 1816 * @private 1817 * @param {string} type - The name of the typed array type (e.g., 'Float32Array', 'Uint16Array'). 1818 * @param {ArrayBuffer} buffer - The buffer to create the typed array from. 1819 * @return {TypedArray} A new typed array of the specified type. 1820 */ 1821function getTypedArray( type, buffer ) { 1822 1823 return new TYPED_ARRAYS[ type ]( buffer ); 1824 1825} 1826 1827/** 1828 * Returns `true` if the given object is a typed array. 1829 * 1830 * @param {any} array - The object to check. 1831 * @return {boolean} Whether the given object is a typed array. 1832 */ 1833function isTypedArray( array ) { 1834 1835 return ArrayBuffer.isView( array ) && ! ( array instanceof DataView ); 1836 1837} 1838 1839/** 1840 * Creates an XHTML element with the specified tag name. 1841 * 1842 * This function uses the XHTML namespace to create DOM elements, 1843 * ensuring proper element creation in XML-based contexts. 1844 * 1845 * @private 1846 * @param {string} name - The tag name of the element to create (e.g., 'canvas', 'div'). 1847 * @return {HTMLElement} The created XHTML element. 1848 */ 1849function createElementNS( name ) { 1850 1851 return document.createElementNS( 'http://www.w3.org/1999/xhtml', name ); 1852 1853} 1854 1855/** 1856 * Creates a canvas element configured for block display. 1857 * 1858 * This is a convenience function that creates a canvas element with 1859 * display style set to 'block', which is commonly used in three.js 1860 * rendering contexts to avoid inline element spacing issues. 1861 * 1862 * @return {HTMLCanvasElement} A canvas element with display set to 'block'. 1863 */ 1864function createCanvasElement() { 1865 1866 const canvas = createElementNS( 'canvas' ); 1867 canvas.style.display = 'block'; 1868 return canvas; 1869 1870} 1871 1872/** 1873 * Internal cache for tracking warning messages to prevent duplicate warnings. 1874 * 1875 * @private 1876 * @type {Object<string, boolean>} 1877 */ 1878const _cache = {}; 1879 1880/** 1881 * Custom console function handler for intercepting log, warn, and error calls. 1882 * 1883 * @private 1884 * @type {Function|null} 1885 */ 1886let _setConsoleFunction = null; 1887 1888/** 1889 * Sets a custom function to handle console output. 1890 * 1891 * This allows external code to intercept and handle console.log, console.warn, 1892 * and console.error calls made by three.js, which is useful for custom logging, 1893 * testing, or debugging workflows. 1894 * 1895 * @param {Function} fn - The function to handle console output. Should accept 1896 * (type, message, ...params) where type is 'log', 'warn', or 'error'. 1897 */ 1898function setConsoleFunction( fn ) { 1899 1900 _setConsoleFunction = fn; 1901 1902} 1903 1904/** 1905 * Gets the currently set custom console function. 1906 * 1907 * @return {Function|null} The custom console function, or null if not set. 1908 */ 1909function getConsoleFunction() { 1910 1911 return _setConsoleFunction; 1912 1913} 1914 1915/** 1916 * Logs an informational message with the 'THREE.' prefix. 1917 * 1918 * If a custom console function is set via setConsoleFunction(), it will be used 1919 * instead of the native console.log. The first parameter is treated as the 1920 * method name and is automatically prefixed with 'THREE.'. 1921 * 1922 * @param {...any} params - The message components. The first param is used as 1923 * the method name and prefixed with 'THREE.'. 1924 */ 1925function log( ...params ) { 1926 1927 const message = 'THREE.' + params.shift(); 1928 1929 if ( _setConsoleFunction ) { 1930 1931 _setConsoleFunction( 'log', message, ...params ); 1932 1933 } else { 1934 1935 console.log( message, ...params ); 1936 1937 } 1938 1939} 1940 1941/** 1942 * Enhances log/warn/error messages related to TSL. 1943 * 1944 * @param {Array<any>} params - The original message parameters. 1945 * @returns {Array<any>} The filtered and enhanced message parameters. 1946 */ 1947function enhanceLogMessage( params ) { 1948 1949 const message = params[ 0 ]; 1950 1951 if ( typeof message === 'string' && message.startsWith( 'TSL:' ) ) { 1952 1953 const stackTrace = params[ 1 ]; 1954 1955 if ( stackTrace && stackTrace.isStackTrace ) { 1956 1957 params[ 0 ] += ' ' + stackTrace.getLocation(); 1958 1959 } else { 1960 1961 params[ 1 ] = 'Stack trace not available. Enable "THREE.Node.captureStackTrace" to capture stack traces.'; 1962 1963 } 1964 1965 } 1966 1967 return params; 1968 1969} 1970 1971/** 1972 * Logs a warning message with the 'THREE.' prefix. 1973 * 1974 * If a custom console function is set via setConsoleFunction(), it will be used 1975 * instead of the native console.warn. The first parameter is treated as the 1976 * method name and is automatically prefixed with 'THREE.'. 1977 * 1978 * @param {...any} params - The message components. The first param is used as 1979 * the method name and prefixed with 'THREE.'. 1980 */ 1981function warn( ...params ) { 1982 1983 params = enhanceLogMessage( params ); 1984 1985 const message = 'THREE.' + params.shift(); 1986 1987 if ( _setConsoleFunction ) { 1988 1989 _setConsoleFunction( 'warn', message, ...params ); 1990 1991 } else { 1992 1993 const stackTrace = params[ 0 ]; 1994 1995 if ( stackTrace && stackTrace.isStackTrace ) { 1996 1997 console.warn( stackTrace.getError( message ) ); 1998 1999 } else { 2000 2001 console.warn( message, ...params ); 2002 2003 } 2004 2005 } 2006 2007} 2008 2009/** 2010 * Logs an error message with the 'THREE.' prefix. 2011 * 2012 * If a custom console function is set via setConsoleFunction(), it will be used 2013 * instead of the native console.error. The first parameter is treated as the 2014 * method name and is automatically prefixed with 'THREE.'. 2015 * 2016 * @param {...any} params - The message components. The first param is used as 2017 * the method name and prefixed with 'THREE.'. 2018 */ 2019function error( ...params ) { 2020 2021 params = enhanceLogMessage( params ); 2022 2023 const message = 'THREE.' + params.shift(); 2024 2025 if ( _setConsoleFunction ) { 2026 2027 _setConsoleFunction( 'error', message, ...params ); 2028 2029 } else { 2030 2031 const stackTrace = params[ 0 ]; 2032 2033 if ( stackTrace && stackTrace.isStackTrace ) { 2034 2035 console.error( stackTrace.getError( message ) ); 2036 2037 } else { 2038 2039 console.error( message, ...params ); 2040 2041 } 2042 2043 } 2044 2045} 2046 2047/** 2048 * Logs a warning message only once, preventing duplicate warnings. 2049 * 2050 * This function maintains an internal cache of warning messages and will only 2051 * output each unique warning message once. Useful for warnings that may be 2052 * triggered repeatedly but should only be shown to the user once. 2053 * 2054 * @param {...any} params - The warning message components. 2055 */ 2056function warnOnce( ...params ) { 2057 2058 const message = params.join( ' ' ); 2059 2060 if ( message in _cache ) return; 2061 2062 _cache[ message ] = true; 2063 2064 warn( ...params ); 2065 2066} 2067 2068/** 2069 * Yields execution to the main thread to allow rendering and other tasks. 2070 * Uses scheduler.yield() when available (Chrome 115+), falls back to requestAnimationFrame. 2071 * 2072 * @return {Promise<void>} 2073 */ 2074function yieldToMain() { 2075 2076 if ( typeof self !== 'undefined' && typeof self.scheduler !== 'undefined' && typeof self.scheduler.yield !== 'undefined' ) { 2077 2078 return self.scheduler.yield(); 2079 2080 } 2081 2082 return new Promise( resolve => { 2083 2084 requestAnimationFrame( resolve ); 2085 2086 } ); 2087 2088} 2089 2090/** 2091 * Asynchronously probes for WebGL sync object completion. 2092 * 2093 * This function creates a promise that resolves when the WebGL sync object 2094 * signals completion or rejects if the sync operation fails. It uses polling 2095 * at the specified interval to check the sync status without blocking the 2096 * main thread. This is useful for GPU-CPU synchronization in WebGL contexts. 2097 * 2098 * @private 2099 * @param {WebGL2RenderingContext} gl - The WebGL rendering context. 2100 * @param {WebGLSync} sync - The WebGL sync object to wait for. 2101 * @param {number} interval - The polling interval in milliseconds. 2102 * @return {Promise<void>} A promise that resolves when the sync completes or rejects if it fails. 2103 */ 2104function probeAsync( gl, sync, interval ) { 2105 2106 return new Promise( function ( resolve, reject ) { 2107 2108 function probe() { 2109 2110 switch ( gl.clientWaitSync( sync, gl.SYNC_FLUSH_COMMANDS_BIT, 0 ) ) { 2111 2112 case gl.WAIT_FAILED: 2113 reject(); 2114 break; 2115 2116 case gl.TIMEOUT_EXPIRED: 2117 setTimeout( probe, interval ); 2118 break; 2119 2120 default: 2121 resolve(); 2122 2123 } 2124 2125 } 2126 2127 setTimeout( probe, interval ); 2128 2129 } ); 2130 2131} 2132 2133/** 2134 * Used to select the correct depth functions 2135 * when reversed depth buffer is used. 2136 * 2137 * @private 2138 * @type {Object} 2139 */ 2140const ReversedDepthFuncs = { 2141 [ NeverDepth ]: AlwaysDepth, 2142 [ LessDepth ]: GreaterDepth, 2143 [ EqualDepth ]: NotEqualDepth, 2144 [ LessEqualDepth ]: GreaterEqualDepth, 2145 2146 [ AlwaysDepth ]: NeverDepth, 2147 [ GreaterDepth ]: LessDepth, 2148 [ NotEqualDepth ]: EqualDepth, 2149 [ GreaterEqualDepth ]: LessEqualDepth, 2150}; 2151 2152/** 2153 * This modules allows to dispatch event objects on custom JavaScript objects. 2154 * 2155 * Main repository: [eventdispatcher.js](https://github.com/mrdoob/eventdispatcher.js/) 2156 * 2157 * Code Example: 2158 * ```js 2159 * class Car extends EventDispatcher { 2160 * start() { 2161 * this.dispatchEvent( { type: 'start', message: 'vroom vroom!' } ); 2162 * } 2163 *}; 2164 * 2165 * // Using events with the custom object 2166 * const car = new Car(); 2167 * car.addEventListener( 'start', function ( event ) { 2168 * alert( event.message ); 2169 * } ); 2170 * 2171 * car.start(); 2172 * ``` 2173 */ 2174class EventDispatcher { 2175 2176 /** 2177 * Adds the given event listener to the given event type. 2178 * 2179 * @param {string} type - The type of event to listen to. 2180 * @param {Function} listener - The function that gets called when the event is fired. 2181 */ 2182 addEventListener( type, listener ) { 2183 2184 if ( this._listeners === undefined ) this._listeners = {}; 2185 2186 const listeners = this._listeners; 2187 2188 if ( listeners[ type ] === undefined ) { 2189 2190 listeners[ type ] = []; 2191 2192 } 2193 2194 if ( listeners[ type ].indexOf( listener ) === -1 ) { 2195 2196 listeners[ type ].push( listener ); 2197 2198 } 2199 2200 } 2201 2202 /** 2203 * Returns `true` if the given event listener has been added to the given event type. 2204 * 2205 * @param {string} type - The type of event. 2206 * @param {Function} listener - The listener to check. 2207 * @return {boolean} Whether the given event listener has been added to the given event type. 2208 */ 2209 hasEventListener( type, listener ) { 2210 2211 const listeners = this._listeners; 2212 2213 if ( listeners === undefined ) return false; 2214 2215 return listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== -1; 2216 2217 } 2218 2219 /** 2220 * Removes the given event listener from the given event type. 2221 * 2222 * @param {string} type - The type of event. 2223 * @param {Function} listener - The listener to remove. 2224 */ 2225 removeEventListener( type, listener ) { 2226 2227 const listeners = this._listeners; 2228 2229 if ( listeners === undefined ) return; 2230 2231 const listenerArray = listeners[ type ]; 2232 2233 if ( listenerArray !== undefined ) { 2234 2235 const index = listenerArray.indexOf( listener ); 2236 2237 if ( index !== -1 ) { 2238 2239 listenerArray.splice( index, 1 ); 2240 2241 } 2242 2243 } 2244 2245 } 2246 2247 /** 2248 * Dispatches an event object. 2249 * 2250 * @param {Object} event - The event that gets fired. 2251 */ 2252 dispatchEvent( event ) { 2253 2254 const listeners = this._listeners; 2255 2256 if ( listeners === undefined ) return; 2257 2258 const listenerArray = listeners[ event.type ]; 2259 2260 if ( listenerArray !== undefined ) { 2261 2262 event.target = this; 2263 2264 // Make a copy, in case listeners are removed while iterating. 2265 const array = listenerArray.slice( 0 ); 2266 2267 for ( let i = 0, l = array.length; i < l; i ++ ) { 2268 2269 array[ i ].call( this, event ); 2270 2271 } 2272 2273 event.target = null; 2274 2275 } 2276 2277 } 2278 2279} 2280 2281const _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' ]; 2282 2283let _seed = 1234567; 2284 2285 2286const DEG2RAD = Math.PI / 180; 2287const RAD2DEG = 180 / Math.PI; 2288 2289/** 2290 * Generate a [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier) 2291 * (universally unique identifier). 2292 * 2293 * @return {string} The UUID. 2294 */ 2295function generateUUID() { 2296 2297 // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136 2298 2299 const d0 = Math.random() * 0xffffffff | 0; 2300 const d1 = Math.random() * 0xffffffff | 0; 2301 const d2 = Math.random() * 0xffffffff | 0; 2302 const d3 = Math.random() * 0xffffffff | 0; 2303 const uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' + 2304 _lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' + 2305 _lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] + 2306 _lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ]; 2307 2308 // .toLowerCase() here flattens concatenated strings to save heap memory space. 2309 return uuid.toLowerCase(); 2310 2311} 2312 2313/** 2314 * Clamps the given value between min and max. 2315 * 2316 * @param {number} value - The value to clamp. 2317 * @param {number} min - The min value. 2318 * @param {number} max - The max value. 2319 * @return {number} The clamped value. 2320 */ 2321function clamp( value, min, max ) { 2322 2323 return Math.max( min, Math.min( max, value ) ); 2324 2325} 2326 2327/** 2328 * Computes the Euclidean modulo of the given parameters that 2329 * is `( ( n % m ) + m ) % m`. 2330 * 2331 * @param {number} n - The first parameter. 2332 * @param {number} m - The second parameter. 2333 * @return {number} The Euclidean modulo. 2334 */ 2335function euclideanModulo( n, m ) { 2336 2337 // https://en.wikipedia.org/wiki/Modulo_operation 2338 2339 return ( ( n % m ) + m ) % m; 2340 2341} 2342 2343/** 2344 * Performs a linear mapping from range `<a1, a2>` to range `<b1, b2>` 2345 * for the given value. `a2` must be greater than `a1`. 2346 * 2347 * @param {number} x - The value to be mapped. 2348 * @param {number} a1 - Minimum value for range A. 2349 * @param {number} a2 - Maximum value for range A. 2350 * @param {number} b1 - Minimum value for range B. 2351 * @param {number} b2 - Maximum value for range B. 2352 * @return {number} The mapped value. 2353 */ 2354function mapLinear( x, a1, a2, b1, b2 ) { 2355 2356 return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); 2357 2358} 2359 2360/** 2361 * Returns the percentage in the closed interval `[0, 1]` of the given value 2362 * between the start and end point. 2363 * 2364 * @param {number} x - The start point 2365 * @param {number} y - The end point. 2366 * @param {number} value - A value between start and end. 2367 * @return {number} The interpolation factor. 2368 */ 2369function inverseLerp( x, y, value ) { 2370 2371 // https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/ 2372 2373 if ( x !== y ) { 2374 2375 return ( value - x ) / ( y - x ); 2376 2377 } else { 2378 2379 return 0; 2380 2381 } 2382 2383} 2384 2385/** 2386 * Returns a value linearly interpolated from two known points based on the given interval - 2387 * `t = 0` will return `x` and `t = 1` will return `y`. 2388 * 2389 * @param {number} x - The start point 2390 * @param {number} y - The end point. 2391 * @param {number} t - The interpolation factor in the closed interval `[0, 1]`. 2392 * @return {number} The interpolated value. 2393 */ 2394function lerp( x, y, t ) { 2395 2396 return ( 1 - t ) * x + t * y; 2397 2398} 2399 2400/** 2401 * Smoothly interpolate a number from `x` to `y` in a spring-like manner using a delta 2402 * time to maintain frame rate independent movement. For details, see 2403 * [Frame rate independent damping using lerp](http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/). 2404 * 2405 * @param {number} x - The current point. 2406 * @param {number} y - The target point. 2407 * @param {number} lambda - A higher lambda value will make the movement more sudden, 2408 * and a lower value will make the movement more gradual. 2409 * @param {number} dt - Delta time in seconds. 2410 * @return {number} The interpolated value. 2411 */ 2412function damp( x, y, lambda, dt ) { 2413 2414 return lerp( x, y, 1 - Math.exp( - lambda * dt ) ); 2415 2416} 2417 2418/** 2419 * Returns a value that alternates between `0` and the given `length` parameter. 2420 * 2421 * @param {number} x - The value to pingpong. 2422 * @param {number} [length=1] - The positive value the function will pingpong to. 2423 * @return {number} The alternated value. 2424 */ 2425function pingpong( x, length = 1 ) { 2426 2427 // https://www.desmos.com/calculator/vcsjnyz7x4 2428 2429 return length - Math.abs( euclideanModulo( x, length * 2 ) - length ); 2430 2431} 2432 2433/** 2434 * Returns a value in the range `[0,1]` that represents the percentage that `x` has 2435 * moved between `min` and `max`, but smoothed or slowed down the closer `x` is to 2436 * the `min` and `max`. 2437 * 2438 * See [Smoothstep](http://en.wikipedia.org/wiki/Smoothstep) for more details. 2439 * 2440 * @param {number} x - The value to evaluate based on its position between `min` and `max`. 2441 * @param {number} min - The min value. Any `x` value below `min` will be `0`. `min` must be lower than `max`. 2442 * @param {number} max - The max value. Any `x` value above `max` will be `1`. `max` must be greater than `min`. 2443 * @return {number} The alternated value. 2444 */ 2445function smoothstep( x, min, max ) { 2446 2447 if ( x <= min ) return 0; 2448 if ( x >= max ) return 1; 2449 2450 x = ( x - min ) / ( max - min ); 2451 2452 return x * x * ( 3 - 2 * x ); 2453 2454} 2455 2456/** 2457 * A [variation on smoothstep](https://en.wikipedia.org/wiki/Smoothstep#Variations) 2458 * that has zero 1st and 2nd order derivatives at `x=0` and `x=1`. 2459 * 2460 * @param {number} x - The value to evaluate based on its position between `min` and `max`. 2461 * @param {number} min - The min value. Any `x` value below `min` will be `0`. `min` must be lower than `max`. 2462 * @param {number} max - The max value. Any `x` value above `max` will be `1`. `max` must be greater than `min`. 2463 * @return {number} The alternated value. 2464 */ 2465function smootherstep( x, min, max ) { 2466 2467 if ( x <= min ) return 0; 2468 if ( x >= max ) return 1; 2469 2470 x = ( x - min ) / ( max - min ); 2471 2472 return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); 2473 2474} 2475 2476/** 2477 * Returns a random integer from `<low, high>` interval. 2478 * 2479 * @param {number} low - The lower value boundary. 2480 * @param {number} high - The upper value boundary 2481 * @return {number} A random integer. 2482 */ 2483function randInt( low, high ) { 2484 2485 return low + Math.floor( Math.random() * ( high - low + 1 ) ); 2486 2487} 2488 2489/** 2490 * Returns a random float from `<low, high>` interval. 2491 * 2492 * @param {number} low - The lower value boundary. 2493 * @param {number} high - The upper value boundary 2494 * @return {number} A random float. 2495 */ 2496function randFloat( low, high ) { 2497 2498 return low + Math.random() * ( high - low ); 2499 2500} 2501 2502/** 2503 * Returns a random integer from `<-range/2, range/2>` interval. 2504 * 2505 * @param {number} range - Defines the value range. 2506 * @return {number} A random float. 2507 */ 2508function randFloatSpread( range ) { 2509 2510 return range * ( 0.5 - Math.random() ); 2511 2512} 2513 2514/** 2515 * Returns a deterministic pseudo-random float in the interval `[0, 1]`. 2516 * 2517 * @param {number} [s] - The integer seed. 2518 * @return {number} A random float. 2519 */ 2520function seededRandom( s ) { 2521 2522 if ( s !== undefined ) _seed = s; 2523 2524 // Mulberry32 generator 2525 2526 let t = _seed += 0x6D2B79F5; 2527 2528 t = Math.imul( t ^ t >>> 15, t | 1 ); 2529 2530 t ^= t + Math.imul( t ^ t >>> 7, t | 61 ); 2531 2532 return ( ( t ^ t >>> 14 ) >>> 0 ) / 4294967296; 2533 2534} 2535 2536/** 2537 * Converts degrees to radians. 2538 * 2539 * @param {number} degrees - A value in degrees. 2540 * @return {number} The converted value in radians. 2541 */ 2542function degToRad( degrees ) { 2543 2544 return degrees * DEG2RAD; 2545 2546} 2547 2548/** 2549 * Converts radians to degrees. 2550 * 2551 * @param {number} radians - A value in radians. 2552 * @return {number} The converted value in degrees. 2553 */ 2554function radToDeg( radians ) { 2555 2556 return radians * RAD2DEG; 2557 2558} 2559 2560/** 2561 * Returns `true` if the given
2561number is a power of two. 2562 * 2563 * @param {number} value - The value to check. 2564 * @return {boolean} Whether the given number is a power of two or not. 2565 */ 2566function isPowerOfTwo( value ) { 2567 2568 return ( value & ( value - 1 ) ) === 0 && value !== 0; 2569 2570} 2571 2572/** 2573 * Returns the smallest power of two that is greater than or equal to the given number. 2574 * 2575 * @param {number} value - The value to find a POT for. Must be greater than `0`. 2576 * @return {number} The smallest power of two that is greater than or equal to the given number. 2577 */ 2578function ceilPowerOfTwo( value ) { 2579 2580 return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) ); 2581 2582} 2583 2584/** 2585 * Returns the largest power of two that is less than or equal to the given number. 2586 * 2587 * @param {number} value - The value to find a POT for. Must be greater than `0`. 2588 * @return {number} The largest power of two that is less than or equal to the given number. 2589 */ 2590function floorPowerOfTwo( value ) { 2591 2592 return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) ); 2593 2594} 2595 2596/** 2597 * Sets the given quaternion from the [Intrinsic Proper Euler Angles](https://en.wikipedia.org/wiki/Euler_angles) 2598 * defined by the given angles and order. 2599 * 2600 * Rotations are applied to the axes in the order specified by order: 2601 * rotation by angle `a` is applied first, then by angle `b`, then by angle `c`. 2602 * 2603 * @param {Quaternion} q - The quaternion to set. 2604 * @param {number} a - The rotation applied to the first axis, in radians. 2605 * @param {number} b - The rotation applied to the second axis, in radians. 2606 * @param {number} c - The rotation applied to the third axis, in radians. 2607 * @param {('XYX'|'XZX'|'YXY'|'YZY'|'ZXZ'|'ZYZ')} order - A string specifying the axes order. 2608 */ 2609function setQuaternionFromProperEuler( q, a, b, c, order ) { 2610 2611 const cos = Math.cos; 2612 const sin = Math.sin; 2613 2614 const c2 = cos( b / 2 ); 2615 const s2 = sin( b / 2 ); 2616 2617 const c13 = cos( ( a + c ) / 2 ); 2618 const s13 = sin( ( a + c ) / 2 ); 2619 2620 const c1_3 = cos( ( a - c ) / 2 ); 2621 const s1_3 = sin( ( a - c ) / 2 ); 2622 2623 const c3_1 = cos( ( c - a ) / 2 ); 2624 const s3_1 = sin( ( c - a ) / 2 ); 2625 2626 switch ( order ) { 2627 2628 case 'XYX': 2629 q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 ); 2630 break; 2631 2632 case 'YZY': 2633 q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 ); 2634 break; 2635 2636 case 'ZXZ': 2637 q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 ); 2638 break; 2639 2640 case 'XZX': 2641 q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 ); 2642 break; 2643 2644 case 'YXY': 2645 q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 ); 2646 break; 2647 2648 case 'ZYZ': 2649 q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 ); 2650 break; 2651 2652 default: 2653 warn( 'MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order ); 2654 2655 } 2656 2657} 2658 2659/** 2660 * Denormalizes the given value according to the given typed array.
2661 * 2662 * @param {number} value - The value to denormalize. 2663 * @param {TypedArray} array - The typed array that defines the data type of the value. 2664 * @return {number} The denormalize (float) value in the range `[0,1]`. 2665 */ 2666function denormalize( value, array ) { 2667 2668 switch ( array.constructor ) { 2669 2670 case Float32Array: 2671 2672 return value; 2673 2674 case Uint32Array: 2675 2676 return value / 4294967295.0; 2677 2678 case Uint16Array: 2679 2680 return value / 65535.0; 2681 2682 case Uint8Array: 2683 2684 return value / 255.0; 2685 2686 case Int32Array: 2687 2688 return Math.max( value / 2147483647.0, -1 ); 2689 2690 case Int16Array: 2691 2692 return Math.max( value / 32767.0, -1 ); 2693 2694 case Int8Array: 2695 2696 return Math.max( value / 127.0, -1 ); 2697 2698 default: 2699 2700 throw new Error( 'Invalid component type.' ); 2701 2702 } 2703 2704} 2705 2706/** 2707 * Normalizes the given value according to the given typed array. 2708 * 2709 * @param {number} value - The float value in the range `[0,1]` to normalize. 2710 * @param {TypedArray} array - The typed array that defines the data type of the value. 2711 * @return {number} The normalize value. 2712 */ 2713function normalize( value, array ) { 2714 2715 switch ( array.constructor ) { 2716 2717 case Float32Array: 2718 2719 return value; 2720 2721 case Uint32Array: 2722 2723 return Math.round( value * 4294967295.0 ); 2724 2725 case Uint16Array: 2726 2727 return Math.round( value * 65535.0 ); 2728 2729 case Uint8Array: 2730 2731 return Math.round( value * 255.0 ); 2732 2733 case Int32Array: 2734 2735 return Math.round( value * 2147483647.0 ); 2736 2737 case Int16Array: 2738 2739 return Math.round( value * 32767.0 ); 2740 2741 case Int8Array: 2742 2743 return Math.round( value * 127.0 ); 2744 2745 default: 2746 2747 throw new Error( 'Invalid component type.' ); 2748 2749 } 2750 2751} 2752 2753/** 2754 * @class 2755 * @classdesc A collection of math utility functions. 2756 * @hideconstructor 2757 */ 2758const MathUtils = { 2759 DEG2RAD: DEG2RAD, 2760 RAD2DEG: RAD2DEG, 2761 /** 2762 * Generate a [UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier) 2763 * (universally unique identifier). 2764 * 2765 * @static 2766 * @method 2767 * @return {string} The UUID. 2768 */ 2769 generateUUID: generateUUID, 2770 /** 2771 * Clamps the given value between min and max. 2772 * 2773 * @static 2774 * @method 2775 * @param {number} value - The value to clamp. 2776 * @param {number} min - The min value. 2777 * @param {number} max - The max value. 2778 * @return {number} The clamped value. 2779 */ 2780 clamp: clamp, 2781 /** 2782 * Computes the Euclidean modulo of the given parameters that 2783 * is `( ( n % m ) + m ) % m`. 2784 * 2785 * @static 2786 * @method 2787 * @param {number} n - The first parameter. 2788 * @param {number} m - The second parameter. 2789 * @return {number} The Euclidean modulo. 2790 */ 2791 euclideanModulo: euclideanModulo, 2792 /** 2793 * Performs a linear mapping from range `<a1, a2>` to range `<b1, b2>` 2794 * for the given value. 2795 * 2796 * @static 2797 * @method 2798 * @param {number} x - The value to be mapped. 2799 * @param {number} a1 - Minimum value for range A. 2800 * @param {number} a2 - Maximum value for range A. 2801 * @param {number} b1 - Minimum value for range B. 2802 * @param {number} b2 - Maximum value for range B. 2803 * @return {number} The mapped value. 2804 */ 2805 mapLinear: mapLinear, 2806 /** 2807 * Returns the percentage in the closed interval `[0, 1]` of the given value 2808 * between the start and end point. 2809 * 2810 * @static 2811 * @method 2812 * @param {number} x - The start point 2813 * @param {number} y - The end point. 2814 * @param {number} value - A value between start and end. 2815 * @return {number} The interpolation factor. 2816 */ 2817 inverseLerp: inverseLerp, 2818 /** 2819 * Returns a value linearly interpolated from two known points based on the given interval - 2820 * `t = 0` will return `x` and `t = 1` will return `y`. 2821 * 2822 * @static 2823 * @method 2824 * @param {number} x - The start point 2825 * @param {number} y - The end point. 2826 * @param {number} t - The interpolation factor in the closed interval `[0, 1]`. 2827 * @return {number} The interpolated value. 2828 */ 2829 lerp: lerp, 2830 /** 2831 * Smoothly interpolate a number from `x` to `y` in a spring-like manner using a delta 2832 * time to maintain frame rate independent movement. For details, see 2833 * [Frame rate independent damping using lerp](http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/). 2834 * 2835 * @static 2836 * @method 2837 * @param {number} x - The current point. 2838 * @param {number} y - The target point. 2839 * @param {number} lambda - A higher lambda value will make the movement more sudden, 2840 * and a lower value will make the movement more gradual. 2841 * @param {number} dt - Delta time in seconds. 2842 * @return {number} The interpolated value. 2843 */ 2844 damp: damp, 2845 /** 2846 * Returns a value that alternates between `0` and the given `length` parameter. 2847 * 2848 * @static 2849 * @method 2850 * @param {number} x - The value to pingpong. 2851 * @param {number} [length=1] - The positive value the function will pingpong to. 2852 * @return {number} The alternated value. 2853 */ 2854 pingpong: pingpong, 2855 /** 2856 * Returns a value in the range `[0,1]` that represents the percentage that `x` has 2857 * moved between `min` and `max`, but smoothed or slowed down the closer `x` is to 2858 * the `min` and `max`. 2859 * 2860 * See [Smoothstep](http://en.wikipedia.org/wiki/Smoothstep) for more details. 2861 * 2862 * @static 2863 * @method 2864 * @param {number} x - The value to evaluate based on its position between min and max. 2865 * @param {number} min - The min value. Any x value below min will be `0`. 2866 * @param {number} max - The max value. Any x value above max will be `1`. 2867 * @return {number} The alternated value. 2868 */ 2869 smoothstep: smoothstep, 2870 /** 2871 * A [variation on smoothstep](https://en.wikipedia.org/wiki/Smoothstep#Variations) 2872 * that has zero 1st and 2nd order derivatives at x=0 and x=1. 2873 * 2874 * @static 2875 * @method 2876 * @param {number} x - The value to evaluate based on its position between min and max. 2877 * @param {number} min - The min value. Any x value below min will be `0`. 2878 * @param {number} max - The max value. Any x value above max will be `1`. 2879 * @return {number} The alternated value. 2880 */ 2881 smootherstep: smootherstep, 2882 /** 2883 * Returns a random integer from `<low, high>` interval. 2884 * 2885 * @static 2886 * @method 2887 * @param {number} low - The lower value boundary. 2888 * @param {number} high - The upper value boundary 2889 * @return {number} A random integer. 2890 */ 2891 randInt: randInt, 2892 /** 2893 * Returns a random float from `<low, high>` interval. 2894 * 2895 * @static 2896 * @method 2897 * @param {number} low - The lower value boundary. 2898 * @param {number} high - The upper value boundary 2899 * @return {number} A random float. 2900 */ 2901 randFloat: randFloat, 2902 /** 2903 * Returns a random integer from `<-range/2, range/2>` interval. 2904 * 2905 * @static 2906 * @method 2907 * @param {number} range - Defines the value range. 2908 * @return {number} A random float. 2909 */ 2910 randFloatSpread: randFloatSpread, 2911 /** 2912 * Returns a deterministic pseudo-random float in the interval `[0, 1]`. 2913 * 2914 * @static 2915 * @method 2916 * @param {number} [s] - The integer seed. 2917 * @return {number} A random float. 2918 */ 2919 seededRandom: seededRandom, 2920 /** 2921 * Converts degrees to radians. 2922 * 2923 * @static 2924 * @method 2925 * @param {number} degrees - A value in degrees. 2926 * @return {number} The converted value in radians. 2927 */ 2928 degToRad: degToRad, 2929 /** 2930 * Converts radians to degrees. 2931 * 2932 * @static 2933 * @method 2934 * @param {number} radians - A value in radians. 2935 * @return {number} The converted value in degrees. 2936 */ 2937 radToDeg: radToDeg, 2938 /** 2939 * Returns `true` if the given number is a power of two. 2940 * 2941 * @static 2942 * @method 2943 * @param {number} value - The value to check. 2944 * @return {boolean} Whether the given number is a power of two or not. 2945 */ 2946 isPowerOfTwo: isPowerOfTwo, 2947 /** 2948 * Returns the smallest power of two that is greater than or equal to the given number. 2949 * 2950 * @static 2951 * @method 2952 * @param {number} value - The value to find a POT for. 2953 * @return {number} The smallest power of two that is greater than or equal to the given number. 2954 */ 2955 ceilPowerOfTwo: ceilPowerOfTwo, 2956 /** 2957 * Returns the largest power of two that is less than or equal to the given number. 2958 * 2959 * @static 2960 * @method 2961 * @param {number} value - The value to find a POT for. 2962 * @return {number} The largest power of two that is less than or equal to the given number. 2963 */ 2964 floorPowerOfTwo: floorPowerOfTwo, 2965 /** 2966 * Sets the given quaternion from the [Intrinsic Proper Euler Angles](https://en.wikipedia.org/wiki/Euler_angles) 2967 * defined by the given angles and order. 2968 * 2969 * Rotations are applied to the axes in the order specified by order: 2970 * rotation by angle `a` is applied first, then by angle `b`, then by angle `c`. 2971 * 2972 * @static 2973 * @method 2974 * @param {Quaternion} q - The quaternion to set. 2975 * @param {number} a - The rotation applied to the first axis, in radians. 2976 * @param {number} b - The rotation applied to the second axis, in radians. 2977 * @param {number} c - The rotation applied to the third axis, in radians. 2978 * @param {('XYX'|'XZX'|'YXY'|'YZY'|'ZXZ'|'ZYZ')} order - A string specifying the axes order. 2979 */ 2980 setQuaternionFromProperEuler: setQuaternionFromProperEuler, 2981 /** 2982 * Normalizes the given value according to the given typed array.
2983 * 2984 * @static 2985 * @method 2986 * @param {number} value - The float value in the range `[0,1]` to normalize. 2987 * @param {TypedArray} array - The typed array that defines the data type of the value. 2988 * @return {number} The normalize value. 2989 */ 2990 normalize: normalize, 2991 /** 2992 * Denormalizes the given value according to the given typed array. 2993 * 2994 * @static 2995 * @method 2996 * @param {number} value - The value to denormalize. 2997 * @param {TypedArray} array - The typed array that defines the data type of the value. 2998 * @return {number} The denormalize (float) value in the range `[0,1]`. 2999 */ 3000 denormalize: denormalize 3001}; 3002 3003/** 3004 * Class representing a 2D vector. A 2D vector is an ordered pair of numbers 3005 * (labeled x and y), which can be used to represent a number of things, such as: 3006 * 3007 * - A point in 2D space (i.e. a position on a plane). 3008 * - A direction and length across a plane. In three.js the length will 3009 * always be the Euclidean distance(straight-line distance) from `(0, 0)` to `(x, y)` 3010 * and the direction is also measured from `(0, 0)` towards `(x, y)`. 3011 * - Any arbitrary ordered pair of numbers. 3012 * 3013 * There are other things a 2D vector can be used to represent, such as 3014 * momentum vectors, complex numbers and so on, however these are the most 3015 * common uses in three.js. 3016 * 3017 * Iterating through a vector instance will yield its components `(x, y)` in 3018 * the corresponding order. 3019 * ```js 3020 * const a = new THREE.Vector2( 0, 1 ); 3021 * 3022 * //no arguments; will be initialised to (0, 0) 3023 * const b = new THREE.Vector2( ); 3024 * 3025 * const d = a.distanceTo( b ); 3026 * ``` 3027 */ 3028class Vector2 { 3029 3030 static { 3031 3032 /** 3033 * This flag can be used for type testing. 3034 * 3035 * @type {boolean} 3036 * @readonly 3037 * @default true 3038 */ 3039 Vector2.prototype.isVector2 = true; 3040 3041 } 3042 3043 /** 3044 * Constructs a new 2D vector. 3045 * 3046 * @param {number} [x=0] - The x value of this vector. 3047 * @param {number} [y=0] - The y value of this vector. 3048 */ 3049 constructor( x = 0, y = 0 ) { 3050 3051 /** 3052 * The x value of this vector. 3053 * 3054 * @type {number} 3055 */ 3056 this.x = x; 3057 3058 /** 3059 * The y value of this vector. 3060 * 3061 * @type {number} 3062 */ 3063 this.y = y; 3064 3065 } 3066 3067 /** 3068 * Alias for {@link Vector2#x}. 3069 * 3070 * @type {number} 3071 */ 3072 get width() { 3073 3074 return this.x; 3075 3076 } 3077 3078 set width( value ) { 3079 3080 this.x = value; 3081 3082 } 3083 3084 /** 3085 * Alias for {@link Vector2#y}. 3086 * 3087 * @type {number} 3088 */ 3089 get height() { 3090 3091 return this.y; 3092 3093 } 3094 3095 set height( value ) { 3096 3097 this.y = value; 3098 3099 } 3100 3101 /** 3102 * Sets the vector components. 3103 * 3104 * @param {number} x - The value of the x component. 3105 * @param {number} y - The value of the y component. 3106 * @return {Vector2} A reference to this vector. 3107 */ 3108 set( x, y ) { 3109 3110 this.x = x; 3111 this.y = y; 3112 3113 return this; 3114 3115 } 3116 3117 /** 3118 * Sets the vector components to the same value. 3119 * 3120 * @param {number} scalar - The value to set for all vector components. 3121 * @return {Vector2} A reference to this vector. 3122 */ 3123 setScalar( scalar ) { 3124 3125 this.x = scalar; 3126 this.y = scalar; 3127 3128 return this; 3129 3130 } 3131 3132 /** 3133 * Sets the vector's x component to the given value 3134 * 3135 * @param {number} x - The value to set. 3136 * @return {Vector2} A reference to this vector. 3137 */ 3138 setX( x ) { 3139 3140 this.x = x; 3141 3142 return this; 3143 3144 } 3145 3146 /** 3147 * Sets the vector's y component to the given value 3148 * 3149 * @param {number} y - The value to set. 3150 * @return {Vector2} A reference to this vector. 3151 */ 3152 setY( y ) { 3153 3154 this.y = y; 3155 3156 return this; 3157 3158 } 3159 3160 /** 3161 * Allows to set a vector component with an index. 3162 * 3163 * @param {number} index - The component index. `0` equals to x, `1` equals to y. 3164 * @param {number} value - The value to set. 3165 * @return {Vector2} A reference to this vector. 3166 */ 3167 setComponent( index, value ) { 3168 3169 switch ( index ) { 3170 3171 case 0: this.x = value; break; 3172 case 1: this.y = value; break; 3173 default: throw new Error( 'index is out of range: ' + index ); 3174 3175 } 3176 3177 return this; 3178 3179 } 3180 3181 /** 3182 * Returns the value of the vector component which matches the given index. 3183 * 3184 * @param {number} index - The component index. `0` equals to x, `1` equals to y. 3185 * @return {number} A vector component value. 3186 */ 3187 getComponent( index ) { 3188 3189 switch ( index ) { 3190 3191 case 0: return this.x; 3192 case 1: return this.y; 3193 default: throw new Error( '
vendor: 17,739 bytes, lines 3193-3996
3193index is out of range: ' + index ); 3194 3195 } 3196 3197 } 3198 3199 /** 3200 * Returns a new vector with copied values from this instance. 3201 * 3202 * @return {Vector2} A clone of this instance. 3203 */ 3204 clone() { 3205 3206 return new this.constructor( this.x, this.y ); 3207 3208 } 3209 3210 /** 3211 * Copies the values of the given vector to this instance. 3212 * 3213 * @param {Vector2} v - The vector to copy. 3214 * @return {Vector2} A reference to this vector. 3215 */ 3216 copy( v ) { 3217 3218 this.x = v.x; 3219 this.y = v.y; 3220 3221 return this; 3222 3223 } 3224 3225 /** 3226 * Adds the given vector to this instance. 3227 * 3228 * @param {Vector2} v - The vector to add. 3229 * @return {Vector2} A reference to this vector. 3230 */ 3231 add( v ) { 3232 3233 this.x += v.x; 3234 this.y += v.y; 3235 3236 return this; 3237 3238 } 3239 3240 /** 3241 * Adds the given scalar value to all components of this instance. 3242 * 3243 * @param {number} s - The scalar to add. 3244 * @return {Vector2} A reference to this vector. 3245 */ 3246 addScalar( s ) { 3247 3248 this.x += s; 3249 this.y += s; 3250 3251 return this; 3252 3253 } 3254 3255 /** 3256 * Adds the given vectors and stores the result in this instance. 3257 * 3258 * @param {Vector2} a - The first vector. 3259 * @param {Vector2} b - The second vector. 3260 * @return {Vector2} A reference to this vector. 3261 */ 3262 addVectors( a, b ) { 3263 3264 this.x = a.x + b.x; 3265 this.y = a.y + b.y; 3266 3267 return this; 3268 3269 } 3270 3271 /** 3272 * Adds the given vector scaled by the given factor to this instance. 3273 * 3274 * @param {Vector2} v - The vector. 3275 * @param {number} s - The factor that scales `v`. 3276 * @return {Vector2} A reference to this vector. 3277 */ 3278 addScaledVector( v, s ) { 3279 3280 this.x += v.x * s; 3281 this.y += v.y * s; 3282 3283 return this; 3284 3285 } 3286 3287 /** 3288 * Subtracts the given vector from this instance. 3289 * 3290 * @param {Vector2} v - The vector to subtract. 3291 * @return {Vector2} A reference to this vector. 3292 */ 3293 sub( v ) { 3294 3295 this.x -= v.x; 3296 this.y -= v.y; 3297 3298 return this; 3299 3300 } 3301 3302 /** 3303 * Subtracts the given scalar value from all components of this instance. 3304 * 3305 * @param {number} s - The scalar to subtract. 3306 * @return {Vector2} A reference to this vector. 3307 */ 3308 subScalar( s ) { 3309 3310 this.x -= s; 3311 this.y -= s; 3312 3313 return this; 3314 3315 } 3316 3317 /** 3318 * Subtracts the given vectors and stores the result in this instance. 3319 * 3320 * @param {Vector2} a - The first vector. 3321 * @param {Vector2} b - The second vector. 3322 * @return {Vector2} A reference to this vector. 3323 */ 3324 subVectors( a, b ) { 3325 3326 this.x = a.x - b.x; 3327 this.y = a.y - b.y; 3328 3329 return this; 3330 3331 } 3332 3333 /** 3334 * Multiplies the given vector with this instance. 3335 * 3336 * @param {Vector2} v - The vector to multiply. 3337 * @return {Vector2} A reference to this vector. 3338 */ 3339 multiply( v ) { 3340 3341 this.x *= v.x; 3342 this.y *= v.y; 3343 3344 return this; 3345 3346 } 3347 3348 /** 3349 * Multiplies the given scalar value with all components of this instance. 3350 * 3351 * @param {number} scalar - The scalar to multiply. 3352 * @return {Vector2} A reference to this vector. 3353 */ 3354 multiplyScalar( scalar ) { 3355 3356 this.x *= scalar; 3357 this.y *= scalar; 3358 3359 return this; 3360 3361 } 3362 3363 /** 3364 * Divides this instance by the given vector. 3365 * 3366 * @param {Vector2} v - The vector to divide. 3367 * @return {Vector2} A reference to this vector. 3368 */ 3369 divide( v ) { 3370 3371 this.x /= v.x; 3372 this.y /= v.y; 3373 3374 return this; 3375 3376 } 3377 3378 /** 3379 * Divides this vector by the given scalar. 3380 * 3381 * @param {number} scalar - The scalar to divide. 3382 * @return {Vector2} A reference to this vector. 3383 */ 3384 divideScalar( scalar ) { 3385 3386 return this.multiplyScalar( 1 / scalar ); 3387 3388 } 3389 3390 /** 3391 * Multiplies this vector (with an implicit 1 as the 3rd component) by 3392 * the given 3x3 matrix. 3393 * 3394 * @param {Matrix3} m - The matrix to apply. 3395 * @return {Vector2} A reference to this vector. 3396 */ 3397 applyMatrix3( m ) { 3398 3399 const x = this.x, y = this.y; 3400 const e = m.elements; 3401 3402 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ]; 3403 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ]; 3404 3405 return this; 3406 3407 } 3408 3409 /** 3410 * If this vector's x or y value is greater than the given vector's x or y 3411 * value, replace that value with the corresponding min value. 3412 * 3413 * @param {Vector2} v - The vector. 3414 * @return {Vector2} A reference to this vector. 3415 */ 3416 min( v ) { 3417 3418 this.x = Math.min( this.x, v.x ); 3419 this.y = Math.min( this.y, v.y ); 3420 3421 return this; 3422 3423 } 3424 3425 /** 3426 * If this vector's x or y value is less than the given vector's x or y 3427 * value, replace that value with the corresponding max value. 3428 * 3429 * @param {Vector2} v - The vector. 3430 * @return {Vector2} A reference to this vector. 3431 */ 3432 max( v ) { 3433 3434 this.x = Math.max( this.x, v.x ); 3435 this.y = Math.max( this.y, v.y ); 3436 3437 return this; 3438 3439 } 3440 3441 /** 3442 * If this vector's x or y value is greater than the max vector's x or y 3443 * value, it is replaced by the corresponding value. 3444 * If this vector's x or y value is less than the min vector's x or y value, 3445 * it is replaced by the corresponding value. 3446 * 3447 * @param {Vector2} min - The minimum x and y values. 3448 * @param {Vector2} max - The maximum x and y values in the desired range. 3449 * @return {Vector2} A reference to this vector. 3450 */ 3451 clamp( min, max ) { 3452 3453 // assumes min < max, componentwise 3454 3455 this.x = clamp( this.x, min.x, max.x ); 3456 this.y = clamp( this.y, min.y, max.y ); 3457 3458 return this; 3459 3460 } 3461 3462 /** 3463 * If this vector's x or y values are greater than the max value, they are 3464 * replaced by the max value. 3465 * If this vector's x or y values are less than the min value, they are 3466 * replaced by the min value. 3467 * 3468 * @param {number} minVal - The minimum value the components will be clamped to. 3469 * @param {number} maxVal - The maximum value the components will be clamped to. 3470 * @return {Vector2} A reference to this vector. 3471 */ 3472 clampScalar( minVal, maxVal ) { 3473 3474 this.x = clamp( this.x, minVal, maxVal ); 3475 this.y = clamp( this.y, minVal, maxVal ); 3476 3477 return this; 3478 3479 } 3480 3481 /** 3482 * If this vector's length is greater than the max value, it is replaced by 3483 * the max value. 3484 * If this vector's length is less than the min value, it is replaced by the 3485 * min value. 3486 * 3487 * @param {number} min - The minimum value the vector length will be clamped to. 3488 * @param {number} max - The maximum value the vector length will be clamped to. 3489 * @return {Vector2} A reference to this vector. 3490 */ 3491 clampLength( min, max ) { 3492 3493 const length = this.length(); 3494 3495 return this.divideScalar( length || 1 ).multiplyScalar( clamp( length, min, max ) ); 3496 3497 } 3498 3499 /** 3500 * The components of this vector are rounded down to the nearest integer value. 3501 * 3502 * @return {Vector2} A reference to this vector. 3503 */ 3504 floor() { 3505 3506 this.x = Math.floor( this.x ); 3507 this.y = Math.floor( this.y ); 3508 3509 return this; 3510 3511 } 3512 3513 /** 3514 * The components of this vector are rounded up to the nearest integer value. 3515 * 3516 * @return {Vector2} A reference to this vector. 3517 */ 3518 ceil() { 3519 3520 this.x = Math.ceil( this.x ); 3521 this.y = Math.ceil( this.y ); 3522 3523 return this; 3524 3525 } 3526 3527 /** 3528 * The components of this vector are rounded to the nearest integer value 3529 * 3530 * @return {Vector2} A reference to this vector. 3531 */ 3532 round() { 3533 3534 this.x = Math.round( this.x ); 3535 this.y = Math.round( this.y ); 3536 3537 return this; 3538 3539 } 3540 3541 /** 3542 * The components of this vector are rounded towards zero (up if negative, 3543 * down if positive) to an integer value. 3544 * 3545 * @return {Vector2} A reference to this vector. 3546 */ 3547 roundToZero() { 3548 3549 this.x = Math.trunc( this.x ); 3550 this.y = Math.trunc( this.y ); 3551 3552 return this; 3553 3554 } 3555 3556 /** 3557 * Inverts this vector - i.e. sets x = -x and y = -y. 3558 * 3559 * @return {Vector2} A reference to this vector. 3560 */ 3561 negate() { 3562 3563 this.x = - this.x; 3564 this.y = - this.y; 3565 3566 return this; 3567 3568 } 3569 3570 /** 3571 * Calculates the dot product of the given vector with this instance. 3572 * 3573 * @param {Vector2} v - The vector to compute the dot product with. 3574 * @return {number} The result of the dot product. 3575 */ 3576 dot( v ) { 3577 3578 return this.x * v.x + this.y * v.y; 3579 3580 } 3581 3582 /** 3583 * Calculates the cross product of the given vector with this instance. 3584 * 3585 * @param {Vector2} v - The vector to compute the cross product with. 3586 * @return {number} The result of the cross product. 3587 */ 3588 cross( v ) { 3589 3590 return this.x * v.y - this.y * v.x; 3591 3592 } 3593 3594 /** 3595 * Computes the square of the Euclidean length (straight-line length) from 3596 * (0, 0) to (x, y). If you are comparing the lengths of vectors, you should 3597 * compare the length squared instead as it is slightly more efficient to calculate. 3598 * 3599 * @return {number} The square length of this vector. 3600 */ 3601 lengthSq() { 3602 3603 return this.x * this.x + this.y * this.y; 3604 3605 } 3606 3607 /** 3608 * Computes the Euclidean length (straight-line length) from (0, 0) to (x, y). 3609 * 3610 * @return {number} The length of this vector. 3611 */ 3612 length() { 3613 3614 return Math.sqrt( this.x * this.x + this.y * this.y ); 3615 3616 } 3617 3618 /** 3619 * Computes the Manhattan length of this vector. 3620 * 3621 * @return {number} The length of this vector. 3622 */ 3623 manhattanLength() { 3624 3625 return Math.abs( this.x ) + Math.abs( this.y ); 3626 3627 } 3628 3629 /** 3630 * Converts this vector to a unit vector - that is, sets it equal to a vector 3631 * with the same direction as this one, but with a vector length of `1`. 3632 * 3633 * @return {Vector2} A reference to this vector. 3634 */ 3635 normalize() { 3636 3637 return this.divideScalar( this.length() || 1 ); 3638 3639 } 3640 3641 /** 3642 * Computes the angle in radians of this vector with respect to the positive x-axis. 3643 * 3644 * @return {number} The angle in radians. 3645 */ 3646 angle() { 3647 3648 const angle = Math.atan2( - this.y, - this.x ) + Math.PI; 3649 3650 return angle; 3651 3652 } 3653 3654 /** 3655 * Returns the angle between the given vector and this instance in radians. 3656 * 3657 * @param {Vector2} v - The vector to compute the angle with. 3658 * @return {number} The angle in radians. 3659 */ 3660 angleTo( v ) { 3661 3662 const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); 3663 3664 if ( denominator === 0 ) return Math.PI / 2; 3665 3666 const theta = this.dot( v ) / denominator; 3667 3668 // clamp, to handle numerical problems 3669 3670 return Math.acos( clamp( theta, -1, 1 ) ); 3671 3672 } 3673 3674 /** 3675 * Computes the distance from the given vector to this instance. 3676 * 3677 * @param {Vector2} v - The vector to compute the distance to. 3678 * @return {number} The distance. 3679 */ 3680 distanceTo( v ) { 3681 3682 return Math.sqrt( this.distanceToSquared( v ) ); 3683 3684 } 3685 3686 /** 3687 * Computes the squared distance from the given vector to this instance. 3688 * If you are just comparing the distance with another distance, you should compare 3689 * the distance squared instead as it is slightly more efficient to calculate. 3690 * 3691 * @param {Vector2} v - The vector to compute the squared distance to. 3692 * @return {number} The squared distance. 3693 */ 3694 distanceToSquared( v ) { 3695 3696 const dx = this.x - v.x, dy = this.y - v.y; 3697 return dx * dx + dy * dy; 3698 3699 } 3700 3701 /** 3702 * Computes the Manhattan distance from the given vector to this instance. 3703 * 3704 * @param {Vector2} v - The vector to compute the Manhattan distance to. 3705 * @return {number} The Manhattan distance. 3706 */ 3707 manhattanDistanceTo( v ) { 3708 3709 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ); 3710 3711 } 3712 3713 /** 3714 * Sets this vector to a vector with the same direction as this one, but 3715 * with the specified length. 3716 * 3717 * @param {number} length - The new length of this vector. 3718 * @return {Vector2} A reference to this vector. 3719 */ 3720 setLength( length ) { 3721 3722 return this.normalize().multiplyScalar( length ); 3723 3724 } 3725 3726 /** 3727 * Linearly interpolates between the given vector and this instance, where 3728 * alpha is the percent distance along the line - alpha = 0 will be this 3729 * vector, and alpha = 1 will be the given one. 3730 * 3731 * @param {Vector2} v - The vector to interpolate towards. 3732 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. 3733 * @return {Vector2} A reference to this vector. 3734 */ 3735 lerp( v, alpha ) { 3736 3737 this.x += ( v.x - this.x ) * alpha; 3738 this.y += ( v.y - this.y ) * alpha; 3739 3740 return this; 3741 3742 } 3743 3744 /** 3745 * Linearly interpolates between the given vectors, where alpha is the percent 3746 * distance along the line - alpha = 0 will be first vector, and alpha = 1 will 3747 * be the second one. The result is stored in this instance. 3748 * 3749 * @param {Vector2} v1 - The first vector. 3750 * @param {Vector2} v2 - The second vector. 3751 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. 3752 * @return {Vector2} A reference to this vector. 3753 */ 3754 lerpVectors( v1, v2, alpha ) { 3755 3756 this.x = v1.x + ( v2.x - v1.x ) * alpha; 3757 this.y = v1.y + ( v2.y - v1.y ) * alpha; 3758 3759 return this; 3760 3761 } 3762 3763 /** 3764 * Returns `true` if this vector is equal with the given one. 3765 * 3766 * @param {Vector2} v - The vector to test for equality. 3767 * @return {boolean} Whether this vector is equal with the given one. 3768 */ 3769 equals( v ) { 3770 3771 return ( ( v.x === this.x ) && ( v.y === this.y ) ); 3772 3773 } 3774 3775 /** 3776 * Sets this vector's x value to be `array[ offset ]` and y 3777 * value to be `array[ offset + 1 ]`. 3778 * 3779 * @param {Array<number>} array - An array holding the vector component values. 3780 * @param {number} [offset=0] - The offset into the array. 3781 * @return {Vector2} A reference to this vector. 3782 */ 3783 fromArray( array, offset = 0 ) { 3784 3785 this.x = array[ offset ]; 3786 this.y = array[ offset + 1 ]; 3787 3788 return this; 3789 3790 } 3791 3792 /** 3793 * Writes the components of this vector to the given array. If no array is provided, 3794 * the method returns a new instance. 3795 * 3796 * @param {Array<number>} [array=[]] - The target array holding the vector components. 3797 * @param {number} [offset=0] - Index of the first element in the array. 3798 * @return {Array<number>} The vector components. 3799 */ 3800 toArray( array = [], offset = 0 ) { 3801 3802 array[ offset ] = this.x; 3803 array[ offset + 1 ] = this.y; 3804 3805 return array; 3806 3807 } 3808 3809 /** 3810 * Sets the components of this vector from the given buffer attribute. 3811 * 3812 * @param {BufferAttribute} attribute - The buffer attribute holding vector data. 3813 * @param {number} index - The index into the attribute. 3814 * @return {Vector2} A reference to this vector. 3815 */ 3816 fromBufferAttribute( attribute, index ) { 3817 3818 this.x = attribute.getX( index ); 3819 this.y = attribute.getY( index ); 3820 3821 return this; 3822 3823 } 3824 3825 /** 3826 * Rotates this vector around the given center by the given angle. 3827 * 3828 * @param {Vector2} center - The point around which to rotate. 3829 * @param {number} angle - The angle to rotate, in radians. 3830 * @return {Vector2} A reference to this vector. 3831 */ 3832 rotateAround( center, angle ) { 3833 3834 const c = Math.cos( angle ), s = Math.sin( angle ); 3835 3836 const x = this.x - center.x; 3837 const y = this.y - center.y; 3838 3839 this.x = x * c - y * s + center.x; 3840 this.y = x * s + y * c + center.y; 3841 3842 return this; 3843 3844 } 3845 3846 /** 3847 * Sets each component of this vector to a pseudo-random value between `0` and 3848 * `1`, excluding `1`. 3849 * 3850 * @return {Vector2} A reference to this vector. 3851 */ 3852 random() { 3853 3854 this.x = Math.random(); 3855 this.y = Math.random(); 3856 3857 return this; 3858 3859 } 3860 3861 *[ Symbol.iterator ]() { 3862 3863 yield this.x; 3864 yield this.y; 3865 3866 } 3867 3868} 3869 3870/** 3871 * Class for representing a Quaternion. Quaternions are used in three.js to represent rotations. 3872 * 3873 * Iterating through a vector instance will yield its components `(x, y, z, w)` in 3874 * the corresponding order. 3875 * 3876 * Note that three.js expects Quaternions to be normalized. 3877 * ```js 3878 * const quaternion = new THREE.Quaternion(); 3879 * quaternion.setFromAxisAngle( new THREE.Vector3( 0, 1, 0 ), Math.PI / 2 ); 3880 * 3881 * const vector = new THREE.Vector3( 1, 0, 0 ); 3882 * vector.applyQuaternion( quaternion ); 3883 * ``` 3884 */ 3885class Quaternion { 3886 3887 /** 3888 * Constructs a new quaternion. 3889 * 3890 * @param {number} [x=0] - The x value of this quaternion. 3891 * @param {number} [y=0] - The y value of this quaternion. 3892 * @param {number} [z=0] - The z value of this quaternion. 3893 * @param {number} [w=1] - The w value of this quaternion. 3894 */ 3895 constructor( x = 0, y = 0, z = 0, w = 1 ) { 3896 3897 /** 3898 * This flag can be used for type testing. 3899 * 3900 * @type {boolean} 3901 * @readonly 3902 * @default true 3903 */ 3904 this.isQuaternion = true; 3905 3906 this._x = x; 3907 this._y = y; 3908 this._z = z; 3909 this._w = w; 3910 3911 } 3912 3913 /** 3914 * Interpolates between two quaternions via SLERP. This implementation assumes the 3915 * quaternion data are managed in flat arrays. 3916 * 3917 * @param {Array<number>} dst - The destination array. 3918 * @param {number} dstOffset - An offset into the destination array. 3919 * @param {Array<number>} src0 - The source array of the first quaternion. 3920 * @param {number} srcOffset0 - An offset into the first source array. 3921 * @param {Array<number>} src1 - The source array of the second quaternion. 3922 * @param {number} srcOffset1 - An offset into the second source array. 3923 * @param {number} t - The interpolation factor. A value in the range `[0,1]` will interpolate. A value outside the range `[0,1]` will extrapolate. 3924 * @see {@link Quaternion#slerp} 3925 */ 3926 static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { 3927 3928 let x0 = src0[ srcOffset0 + 0 ], 3929 y0 = src0[ srcOffset0 + 1 ], 3930 z0 = src0[ srcOffset0 + 2 ], 3931 w0 = src0[ srcOffset0 + 3 ]; 3932 3933 let x1 = src1[ srcOffset1 + 0 ], 3934 y1 = src1[ srcOffset1 + 1 ], 3935 z1 = src1[ srcOffset1 + 2 ], 3936 w1 = src1[ srcOffset1 + 3 ]; 3937 3938 if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { 3939 3940 let dot = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1; 3941 3942 if ( dot < 0 ) { 3943 3944 x1 = - x1; 3945 y1 = - y1; 3946 z1 = - z1; 3947 w1 = - w1; 3948 3949 dot = - dot; 3950 3951 } 3952 3953 let s = 1 - t; 3954 3955 if ( dot < 0.9995 ) { 3956 3957 // slerp 3958 3959 const theta = Math.acos( dot ); 3960 const sin = Math.sin( theta ); 3961 3962 s = Math.sin( s * theta ) / sin; 3963 t = Math.sin( t * theta ) / sin; 3964 3965 x0 = x0 * s + x1 * t; 3966 y0 = y0 * s + y1 * t; 3967 z0 = z0 * s + z1 * t; 3968 w0 = w0 * s + w1 * t; 3969 3970 } else { 3971 3972 // for small angles, lerp then normalize 3973 3974 x0 = x0 * s + x1 * t; 3975 y0 = y0 * s + y1 * t; 3976 z0 = z0 * s + z1 * t; 3977 w0 = w0 * s + w1 * t; 3978 3979 const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); 3980 3981 x0 *= f; 3982 y0 *= f; 3983 z0 *= f; 3984 w0 *= f; 3985 3986 } 3987 3988 } 3989 3990 dst[ dstOffset ] = x0; 3991 dst[ dstOffset + 1 ] = y0; 3992 dst[ dstOffset + 2 ] = z0; 3993 dst[ dstOffset + 3 ] = w0; 3994 3995 } 3996
vendor: 14,213 bytes, lines 3997-4637
3997 /** 3998 * Multiplies two quaternions. This implementation assumes the quaternion data are managed 3999 * in flat arrays. 4000 * 4001 * @param {Array<number>} dst - The destination array. 4002 * @param {number} dstOffset - An offset into the destination array. 4003 * @param {Array<number>} src0 - The source array of the first quaternion. 4004 * @param {number} srcOffset0 - An offset into the first source array. 4005 * @param {Array<number>} src1 - The source array of the second quaternion. 4006 * @param {number} srcOffset1 - An offset into the second source array. 4007 * @return {Array<number>} The destination array. 4008 * @see {@link Quaternion#multiplyQuaternions}. 4009 */ 4010 static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) { 4011 4012 const x0 = src0[ srcOffset0 ]; 4013 const y0 = src0[ srcOffset0 + 1 ]; 4014 const z0 = src0[ srcOffset0 + 2 ]; 4015 const w0 = src0[ srcOffset0 + 3 ]; 4016 4017 const x1 = src1[ srcOffset1 ]; 4018 const y1 = src1[ srcOffset1 + 1 ]; 4019 const z1 = src1[ srcOffset1 + 2 ]; 4020 const w1 = src1[ srcOffset1 + 3 ]; 4021 4022 dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1; 4023 dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1; 4024 dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1; 4025 dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1; 4026 4027 return dst; 4028 4029 } 4030 4031 /** 4032 * The x value of this quaternion. 4033 * 4034 * @type {number} 4035 * @default 0 4036 */ 4037 get x() { 4038 4039 return this._x; 4040 4041 } 4042 4043 set x( value ) { 4044 4045 this._x = value; 4046 this._onChangeCallback(); 4047 4048 } 4049 4050 /** 4051 * The y value of this quaternion. 4052 * 4053 * @type {number} 4054 * @default 0 4055 */ 4056 get y() { 4057 4058 return this._y; 4059 4060 } 4061 4062 set y( value ) { 4063 4064 this._y = value; 4065 this._onChangeCallback(); 4066 4067 } 4068 4069 /** 4070 * The z value of this quaternion. 4071 * 4072 * @type {number} 4073 * @default 0 4074 */ 4075 get z() { 4076 4077 return this._z; 4078 4079 } 4080 4081 set z( value ) { 4082 4083 this._z = value; 4084 this._onChangeCallback(); 4085 4086 } 4087 4088 /** 4089 * The w value of this quaternion. 4090 * 4091 * @type {number} 4092 * @default 1 4093 */ 4094 get w() { 4095 4096 return this._w; 4097 4098 } 4099 4100 set w( value ) { 4101 4102 this._w = value; 4103 this._onChangeCallback(); 4104 4105 } 4106 4107 /** 4108 * Sets the quaternion components. 4109 * 4110 * @param {number} x - The x value of this quaternion. 4111 * @param {number} y - The y value of this quaternion. 4112 * @param {number} z - The z value of this quaternion. 4113 * @param {number} w - The w value of this quaternion. 4114 * @return {Quaternion} A reference to this quaternion. 4115 */ 4116 set( x, y, z, w ) { 4117 4118 this._x = x; 4119 this._y = y; 4120 this._z = z; 4121 this._w = w; 4122 4123 this._onChangeCallback(); 4124 4125 return this; 4126 4127 } 4128 4129 /** 4130 * Returns a new quaternion with copied values from this instance. 4131 * 4132 * @return {Quaternion} A clone of this instance. 4133 */ 4134 clone() { 4135 4136 return new this.constructor( this._x, this._y, this._z, this._w ); 4137 4138 } 4139 4140 /** 4141 * Copies the values of the given quaternion to this instance. 4142 * 4143 * @param {Quaternion} quaternion - The quaternion to copy. 4144 * @return {Quaternion} A reference to this quaternion. 4145 */ 4146 copy( quaternion ) { 4147 4148 this._x = quaternion.x; 4149 this._y = quaternion.y; 4150 this._z = quaternion.z; 4151 this._w = quaternion.w; 4152 4153 this._onChangeCallback(); 4154 4155 return this; 4156 4157 } 4158 4159 /** 4160 * Sets this quaternion from the rotation specified by the given 4161 * Euler angles. 4162 * 4163 * @param {Euler} euler - The Euler angles. 4164 * @param {boolean} [update=true] - Whether the internal `onChange` callback should be executed or not. 4165 * @return {Quaternion} A reference to this quaternion. 4166 */ 4167 setFromEuler( euler, update = true ) { 4168 4169 const x = euler._x, y = euler._y, z = euler._z, order = euler._order; 4170 4171 // http://www.mathworks.com/matlabcentral/fileexchange/ 4172 // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ 4173 // content/SpinCalc.m 4174 4175 const cos = Math.cos; 4176 const sin = Math.sin; 4177 4178 const c1 = cos( x / 2 ); 4179 const c2 = cos( y / 2 ); 4180 const c3 = cos( z / 2 ); 4181 4182 const s1 = sin( x / 2 ); 4183 const s2 = sin( y / 2 ); 4184 const s3 = sin( z / 2 ); 4185 4186 switch ( order ) { 4187 4188 case 'XYZ': 4189 this._x = s1 * c2 * c3 + c1 * s2 * s3; 4190 this._y = c1 * s2 * c3 - s1 * c2 * s3; 4191 this._z = c1 * c2 * s3 + s1 * s2 * c3; 4192 this._w = c1 * c2 * c3 - s1 * s2 * s3; 4193 break; 4194 4195 case 'YXZ': 4196 this._x = s1 * c2 * c3 + c1 * s2 * s3; 4197 this._y = c1 * s2 * c3 - s1 * c2 * s3; 4198 this._z = c1 * c2 * s3 - s1 * s2 * c3; 4199 this._w = c1 * c2 * c3 + s1 * s2 * s3; 4200 break; 4201 4202 case 'ZXY': 4203 this._x = s1 * c2 * c3 - c1 * s2 * s3; 4204 this._y = c1 * s2 * c3 + s1 * c2 * s3; 4205 this._z = c1 * c2 * s3 + s1 * s2 * c3; 4206 this._w = c1 * c2 * c3 - s1 * s2 * s3; 4207 break; 4208 4209 case 'ZYX': 4210 this._x = s1 * c2 * c3 - c1 * s2 * s3; 4211 this._y = c1 * s2 * c3 + s1 * c2 * s3; 4212 this._z = c1 * c2 * s3 - s1 * s2 * c3; 4213 this._w = c1 * c2 * c3 + s1 * s2 * s3; 4214 break; 4215 4216 case 'YZX': 4217 this._x = s1 * c2 * c3 + c1 * s2 * s3; 4218 this._y = c1 * s2 * c3 + s1 * c2 * s3; 4219 this._z = c1 * c2 * s3 - s1 * s2 * c3; 4220 this._w = c1 * c2 * c3 - s1 * s2 * s3; 4221 break; 4222 4223 case 'XZY': 4224 this._x = s1 * c2 * c3 - c1 * s2 * s3; 4225 this._y = c1 * s2 * c3 - s1 * c2 * s3; 4226 this._z = c1 * c2 * s3 + s1 * s2 * c3; 4227 this._w = c1 * c2 * c3 + s1 * s2 * s3; 4228 break; 4229 4230 default: 4231 warn( 'Quaternion: .setFromEuler() encountered an unknown order: ' + order ); 4232 4233 } 4234 4235 if ( update === true ) this._onChangeCallback(); 4236 4237 return this; 4238 4239 } 4240 4241 /** 4242 * Sets this quaternion from the given axis and angle. 4243 * 4244 * @param {Vector3} axis - The normalized axis. 4245 * @param {number} angle - The angle in radians. 4246 * @return {Quaternion} A reference to this quaternion. 4247 */ 4248 setFromAxisAngle( axis, angle ) { 4249 4250 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm 4251 4252 const halfAngle = angle / 2, s = Math.sin( halfAngle ); 4253 4254 this._x = axis.x * s; 4255 this._y = axis.y * s; 4256 this._z = axis.z * s; 4257 this._w = Math.cos( halfAngle ); 4258 4259 this._onChangeCallback(); 4260 4261 return this; 4262 4263 } 4264 4265 /** 4266 * Sets this quaternion from the given rotation matrix. 4267 * 4268 * @param {Matrix4} m - A 4x4 matrix of which the upper 3x3 of matrix is a pure rotation matrix (i.e. unscaled). 4269 * @return {Quaternion} A reference to this quaternion. 4270 */ 4271 setFromRotationMatrix( m ) { 4272 4273 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm 4274 4275 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 4276 4277 const te = m.elements, 4278 4279 m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], 4280 m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], 4281 m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], 4282 4283 trace = m11 + m22 + m33; 4284 4285 if ( trace > 0 ) { 4286 4287 const s = 0.5 / Math.sqrt( trace + 1.0 ); 4288 4289 this._w = 0.25 / s; 4290 this._x = ( m32 - m23 ) * s; 4291 this._y = ( m13 - m31 ) * s; 4292 this._z = ( m21 - m12 ) * s; 4293 4294 } else if ( m11 > m22 && m11 > m33 ) { 4295 4296 const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); 4297 4298 this._w = ( m32 - m23 ) / s; 4299 this._x = 0.25 * s; 4300 this._y = ( m12 + m21 ) / s; 4301 this._z = ( m13 + m31 ) / s; 4302 4303 } else if ( m22 > m33 ) { 4304 4305 const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); 4306 4307 this._w = ( m13 - m31 ) / s; 4308 this._x = ( m12 + m21 ) / s; 4309 this._y = 0.25 * s; 4310 this._z = ( m23 + m32 ) / s; 4311 4312 } else { 4313 4314 const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); 4315 4316 this._w = ( m21 - m12 ) / s; 4317 this._x = ( m13 + m31 ) / s; 4318 this._y = ( m23 + m32 ) / s; 4319 this._z = 0.25 * s; 4320 4321 } 4322 4323 this._onChangeCallback(); 4324 4325 return this; 4326 4327 } 4328 4329 /** 4330 * Sets this quaternion to the rotation required to rotate the direction vector 4331 * `vFrom` to the direction vector `vTo`. 4332 * 4333 * @param {Vector3} vFrom - The first (normalized) direction vector. 4334 * @param {Vector3} vTo - The second (normalized) direction vector. 4335 * @return {Quaternion} A reference to this quaternion. 4336 */ 4337 setFromUnitVectors( vFrom, vTo ) { 4338 4339 // assumes direction vectors vFrom and vTo are normalized 4340 4341 let r = vFrom.dot( vTo ) + 1; 4342 4343 if ( r < 1e-8 ) { // the epsilon value has been discussed in #31286 4344 4345 // vFrom and vTo point in opposite directions 4346 4347 r = 0; 4348 4349 if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { 4350 4351 this._x = - vFrom.y; 4352 this._y = vFrom.x; 4353 this._z = 0; 4354 this._w = r; 4355 4356 } else { 4357 4358 this._x = 0; 4359 this._y = - vFrom.z; 4360 this._z = vFrom.y; 4361 this._w = r; 4362 4363 } 4364 4365 } else { 4366 4367 // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3 4368 4369 this._x = vFrom.y * vTo.z - vFrom.z * vTo.y; 4370 this._y = vFrom.z * vTo.x - vFrom.x * vTo.z; 4371 this._z = vFrom.x * vTo.y - vFrom.y * vTo.x; 4372 this._w = r; 4373 4374 } 4375 4376 return this.normalize(); 4377 4378 } 4379 4380 /** 4381 * Returns the angle between this quaternion and the given one in radians. 4382 * 4383 * @param {Quaternion} q - The quaternion to compute the angle with. 4384 * @return {number} The angle in radians. 4385 */ 4386 angleTo( q ) { 4387 4388 return 2 * Math.acos( Math.abs( clamp( this.dot( q ), -1, 1 ) ) ); 4389 4390 } 4391 4392 /** 4393 * Rotates this quaternion by a given angular step to the given quaternion. 4394 * The method ensures that the final quaternion will not overshoot `q`. 4395 * 4396 * @param {Quaternion} q - The target quaternion. 4397 * @param {number} step - The angular step in radians. 4398 * @return {Quaternion} A reference to this quaternion. 4399 */ 4400 rotateTowards( q, step ) { 4401 4402 const angle = this.angleTo( q ); 4403 4404 if ( angle === 0 ) return this; 4405 4406 const t = Math.min( 1, step / angle ); 4407 4408 this.slerp( q, t ); 4409 4410 return this; 4411 4412 } 4413 4414 /** 4415 * Sets this quaternion to the identity quaternion; that is, to the 4416 * quaternion that represents "no rotation". 4417 * 4418 * @return {Quaternion} A reference to this quaternion. 4419 */ 4420 identity() { 4421 4422 return this.set( 0, 0, 0, 1 ); 4423 4424 } 4425 4426 /** 4427 * Inverts this quaternion via {@link Quaternion#conjugate}. The 4428 * quaternion is assumed to have unit length. 4429 * 4430 * @return {Quaternion} A reference to this quaternion. 4431 */ 4432 invert() { 4433 4434 return this.conjugate(); 4435 4436 } 4437 4438 /** 4439 * Returns the rotational conjugate of this quaternion. The conjugate of a 4440 * quaternion represents the same rotation in the opposite direction about 4441 * the rotational axis. 4442 * 4443 * @return {Quaternion} A reference to this quaternion. 4444 */ 4445 conjugate() { 4446 4447 this._x *= -1; 4448 this._y *= -1; 4449 this._z *= -1; 4450 4451 this._onChangeCallback(); 4452 4453 return this; 4454 4455 } 4456 4457 /** 4458 * Calculates the dot product of this quaternion and the given one. 4459 * 4460 * @param {Quaternion} v - The quaternion to compute the dot product with. 4461 * @return {number} The result of the dot product. 4462 */ 4463 dot( v ) { 4464 4465 return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; 4466 4467 } 4468 4469 /** 4470 * Computes the squared Euclidean length (straight-line length) of this quaternion, 4471 * considered as a 4 dimensional vector. This can be useful if you are comparing the 4472 * lengths of two quaternions, as this is a slightly more efficient calculation than 4473 * {@link Quaternion#length}. 4474 * 4475 * @return {number} The squared Euclidean length. 4476 */ 4477 lengthSq() { 4478 4479 return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; 4480 4481 } 4482 4483 /** 4484 * Computes the Euclidean length (straight-line length) of this quaternion, 4485 * considered as a 4 dimensional vector. 4486 * 4487 * @return {number} The Euclidean length. 4488 */ 4489 length() { 4490 4491 return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); 4492 4493 } 4494 4495 /** 4496 * Normalizes this quaternion - that is, calculated the quaternion that performs 4497 * the same rotation as this one, but has a length equal to `1`. 4498 * 4499 * @return {Quaternion} A reference to this quaternion. 4500 */ 4501 normalize() { 4502 4503 let l = this.length(); 4504 4505 if ( l === 0 ) { 4506 4507 this._x = 0; 4508 this._y = 0; 4509 this._z = 0; 4510 this._w = 1; 4511 4512 } else { 4513 4514 l = 1 / l; 4515 4516 this._x = this._x * l; 4517 this._y = this._y * l; 4518 this._z = this._z * l; 4519 this._w = this._w * l; 4520 4521 } 4522 4523 this._onChangeCallback(); 4524 4525 return this; 4526 4527 } 4528 4529 /** 4530 * Multiplies this quaternion by the given one. 4531 * 4532 * @param {Quaternion} q - The quaternion. 4533 * @return {Quaternion} A reference to this quaternion. 4534 */ 4535 multiply( q ) { 4536 4537 return this.multiplyQuaternions( this, q ); 4538 4539 } 4540 4541 /** 4542 * Pre-multiplies this quaternion by the given one. 4543 * 4544 * @param {Quaternion} q - The quaternion. 4545 * @return {Quaternion} A reference to this quaternion. 4546 */ 4547 premultiply( q ) { 4548 4549 return this.multiplyQuaternions( q, this ); 4550 4551 } 4552 4553 /** 4554 * Multiplies the given quaternions and stores the result in this instance. 4555 * 4556 * @param {Quaternion} a - The first quaternion. 4557 * @param {Quaternion} b - The second quaternion. 4558 * @return {Quaternion} A reference to this quaternion. 4559 */ 4560 multiplyQuaternions( a, b ) { 4561 4562 // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm 4563 4564 const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; 4565 const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; 4566 4567 this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; 4568 this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; 4569 this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; 4570 this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; 4571 4572 this._onChangeCallback(); 4573 4574 return this; 4575 4576 } 4577 4578 /** 4579 * Performs a spherical linear interpolation between this quaternion and the target quaternion. 4580 * 4581 * @param {Quaternion} qb - The target quaternion. 4582 * @param {number} t - The interpolation factor. A value in the range `[0,1]` will interpolate. A value outside the range `[0,1]` will extrapolate. 4583 * @return {Quaternion} A reference to this quaternion. 4584 */ 4585 slerp( qb, t ) { 4586 4587 let x = qb._x, y = qb._y, z = qb._z, w = qb._w; 4588 4589 let dot = this.dot( qb ); 4590 4591 if ( dot < 0 ) { 4592 4593 x = - x; 4594 y = - y; 4595 z = - z; 4596 w = - w; 4597 4598 dot = - dot; 4599 4600 } 4601 4602 let s = 1 - t; 4603 4604 if ( dot < 0.9995 ) { 4605 4606 // slerp 4607 4608 const theta = Math.acos( dot ); 4609 const sin = Math.sin( theta ); 4610 4611 s = Math.sin( s * theta ) / sin; 4612 t = Math.sin( t * theta ) / sin; 4613 4614 this._x = this._x * s + x * t; 4615 this._y = this._y * s + y * t; 4616 this._z = this._z * s + z * t; 4617 this._w = this._w * s + w * t; 4618 4619 this._onChangeCallback(); 4620 4621 } else { 4622 4623 // for small angles, lerp then normalize 4624 4625 this._x = this._x * s + x * t; 4626 this._y = this._y * s + y * t; 4627 this._z = this._z * s + z * t; 4628 this._w = this._w * s + w * t; 4629 4630 this.normalize(); // normalize calls _onChangeCallback() 4631 4632 } 4633 4634 return this; 4635 4636 } 4637
vendor: 6,943 bytes, lines 4638-4948
4638 /** 4639 * Performs a spherical linear interpolation between the given quaternions 4640 * and stores the result in this quaternion. 4641 * 4642 * @param {Quaternion} qa - The source quaternion. 4643 * @param {Quaternion} qb - The target quaternion. 4644 * @param {number} t - The interpolation factor in the closed interval `[0, 1]`. 4645 * @return {Quaternion} A reference to this quaternion. 4646 */ 4647 slerpQuaternions( qa, qb, t ) { 4648 4649 return this.copy( qa ).slerp( qb, t ); 4650 4651 } 4652 4653 /** 4654 * Sets this quaternion to a uniformly random, normalized quaternion. 4655 * 4656 * @return {Quaternion} A reference to this quaternion. 4657 */ 4658 random() { 4659 4660 // Ken Shoemake 4661 // Uniform random rotations 4662 // D. Kirk, editor, Graphics Gems III, pages 124-132. Academic Press, New York, 1992. 4663 4664 const theta1 = 2 * Math.PI * Math.random(); 4665 const theta2 = 2 * Math.PI * Math.random(); 4666 4667 const x0 = Math.random(); 4668 const r1 = Math.sqrt( 1 - x0 ); 4669 const r2 = Math.sqrt( x0 ); 4670 4671 return this.set( 4672 r1 * Math.sin( theta1 ), 4673 r1 * Math.cos( theta1 ), 4674 r2 * Math.sin( theta2 ), 4675 r2 * Math.cos( theta2 ), 4676 ); 4677 4678 } 4679 4680 /** 4681 * Returns `true` if this quaternion is equal with the given one. 4682 * 4683 * @param {Quaternion} quaternion - The quaternion to test for equality. 4684 * @return {boolean} Whether this quaternion is equal with the given one. 4685 */ 4686 equals( quaternion ) { 4687 4688 return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); 4689 4690 } 4691 4692 /** 4693 * Sets this quaternion's components from the given array. 4694 * 4695 * @param {Array<number>} array - An array holding the quaternion component values. 4696 * @param {number} [offset=0] - The offset into the array. 4697 * @return {Quaternion} A reference to this quaternion. 4698 */ 4699 fromArray( array, offset = 0 ) { 4700 4701 this._x = array[ offset ]; 4702 this._y = array[ offset + 1 ]; 4703 this._z = array[ offset + 2 ]; 4704 this._w = array[ offset + 3 ]; 4705 4706 this._onChangeCallback(); 4707 4708 return this; 4709 4710 } 4711 4712 /** 4713 * Writes the components of this quaternion to the given array. If no array is provided, 4714 * the method returns a new instance. 4715 * 4716 * @param {Array<number>} [array=[]] - The target array holding the quaternion components. 4717 * @param {number} [offset=0] - Index of the first element in the array. 4718 * @return {Array<number>} The quaternion components. 4719 */ 4720 toArray( array = [], offset = 0 ) { 4721 4722 array[ offset ] = this._x; 4723 array[ offset + 1 ] = this._y; 4724 array[ offset + 2 ] = this._z; 4725 array[ offset + 3 ] = this._w; 4726 4727 return array; 4728 4729 } 4730 4731 /** 4732 * Sets the components of this quaternion from the given buffer attribute. 4733 * 4734 * @param {BufferAttribute} attribute - The buffer attribute holding quaternion data. 4735 * @param {number} index - The index into the attribute. 4736 * @return {Quaternion} A reference to this quaternion. 4737 */ 4738 fromBufferAttribute( attribute, index ) { 4739 4740 this._x = attribute.getX( index ); 4741 this._y = attribute.getY( index ); 4742 this._z = attribute.getZ( index ); 4743 this._w = attribute.getW( index ); 4744 4745 this._onChangeCallback(); 4746 4747 return this; 4748 4749 } 4750 4751 /** 4752 * This methods defines the serialization result of this class. Returns the 4753 * numerical elements of this quaternion in an array of format `[x, y, z, w]`. 4754 * 4755 * @return {Array<number>} The serialized quaternion. 4756 */ 4757 toJSON() { 4758 4759 return this.toArray(); 4760 4761 } 4762 4763 _onChange( callback ) { 4764 4765 this._onChangeCallback = callback; 4766 4767 return this; 4768 4769 } 4770 4771 _onChangeCallback() {} 4772 4773 *[ Symbol.iterator ]() { 4774 4775 yield this._x; 4776 yield this._y; 4777 yield this._z; 4778 yield this._w; 4779 4780 } 4781 4782} 4783 4784/** 4785 * Class representing a 3D vector. A 3D vector is an ordered triplet of numbers 4786 * (labeled x, y and z), which can be used to represent a number of things, such as: 4787 * 4788 * - A point in 3D space. 4789 * - A direction and length in 3D space. In three.js the length will 4790 * always be the Euclidean distance(straight-line distance) from `(0, 0, 0)` to `(x, y, z)` 4791 * and the direction is also measured from `(0, 0, 0)` towards `(x, y, z)`. 4792 * - Any arbitrary ordered triplet of numbers. 4793 * 4794 * There are other things a 3D vector can be used to represent, such as 4795 * momentum vectors and so on, however these are the most 4796 * common uses in three.js. 4797 * 4798 * Iterating through a vector instance will yield its components `(x, y, z)` in 4799 * the corresponding order. 4800 * ```js 4801 * const a = new THREE.Vector3( 0, 1, 0 ); 4802 * 4803 * //no arguments; will be initialised to (0, 0, 0) 4804 * const b = new THREE.Vector3( ); 4805 * 4806 * const d = a.distanceTo( b ); 4807 * ``` 4808 */ 4809class Vector3 { 4810 4811 static { 4812 4813 /** 4814 * This flag can be used for type testing. 4815 * 4816 * @type {boolean} 4817 * @readonly 4818 * @default true 4819 */ 4820 Vector3.prototype.isVector3 = true; 4821 4822 } 4823 4824 /** 4825 * Constructs a new 3D vector. 4826 * 4827 * @param {number} [x=0] - The x value of this vector. 4828 * @param {number} [y=0] - The y value of this vector. 4829 * @param {number} [z=0] - The z value of this vector. 4830 */ 4831 constructor( x = 0, y = 0, z = 0 ) { 4832 4833 /** 4834 * The x value of this vector. 4835 * 4836 * @type {number} 4837 */ 4838 this.x = x; 4839 4840 /** 4841 * The y value of this vector. 4842 * 4843 * @type {number} 4844 */ 4845 this.y = y; 4846 4847 /** 4848 * The z value of this vector. 4849 * 4850 * @type {number} 4851 */ 4852 this.z = z; 4853 4854 } 4855 4856 /** 4857 * Sets the vector components. 4858 * 4859 * @param {number} x - The value of the x component. 4860 * @param {number} y - The value of the y component. 4861 * @param {number} z - The value of the z component. 4862 * @return {Vector3} A reference to this vector. 4863 */ 4864 set( x, y, z ) { 4865 4866 if ( z === undefined ) z = this.z; // sprite.scale.set(x,y) 4867 4868 this.x = x; 4869 this.y = y; 4870 this.z = z; 4871 4872 return this; 4873 4874 } 4875 4876 /** 4877 * Sets the vector components to the same value. 4878 * 4879 * @param {number} scalar - The value to set for all vector components. 4880 * @return {Vector3} A reference to this vector. 4881 */ 4882 setScalar( scalar ) { 4883 4884 this.x = scalar; 4885 this.y = scalar; 4886 this.z = scalar; 4887 4888 return this; 4889 4890 } 4891 4892 /** 4893 * Sets the vector's x component to the given value. 4894 * 4895 * @param {number} x - The value to set. 4896 * @return {Vector3} A reference to this vector. 4897 */ 4898 setX( x ) { 4899 4900 this.x = x; 4901 4902 return this; 4903 4904 } 4905 4906 /** 4907 * Sets the vector's y component to the given value. 4908 * 4909 * @param {number} y - The value to set. 4910 * @return {Vector3} A reference to this vector. 4911 */ 4912 setY( y ) { 4913 4914 this.y = y; 4915 4916 return this; 4917 4918 } 4919 4920 /** 4921 * Sets the vector's z component to the given value. 4922 * 4923 * @param {number} z - The value to set. 4924 * @return {Vector3} A reference to this vector. 4925 */ 4926 setZ( z ) { 4927 4928 this.z = z; 4929 4930 return this; 4931 4932 } 4933 4934 /** 4935 * Allows to set a vector component with an index. 4936 * 4937 * @param {number} index - The component index. `0` equals to x, `1` equals to y, `2` equals to z. 4938 * @param {number} value - The value to set. 4939 * @return {Vector3} A reference to this vector. 4940 */ 4941 setComponent( index, value ) { 4942 4943 switch ( index ) { 4944 4945 case 0: this.x = value; break; 4946 case 1: this.y = value; break; 4947 case 2: this.z = value; break; 4948 default: throw new Error( '
4948index is out of range: ' + index ); 4949 4950 } 4951 4952 return this; 4953 4954 } 4955 4956 /** 4957 * Returns the value of the vector component which matches the given index. 4958 * 4959 * @param {number} index - The component index. `0` equals to x, `1` equals to y, `2` equals to z. 4960 * @return {number} A vector component value. 4961 */ 4962 getComponent( index ) { 4963 4964 switch ( index ) { 4965 4966 case 0: return this.x; 4967 case 1: return this.y; 4968 case 2: return this.z; 4969 default: throw new Error( '
vendor: 6,725 bytes, lines 4969-5299
4969index is out of range: ' + index ); 4970 4971 } 4972 4973 } 4974 4975 /** 4976 * Returns a new vector with copied values from this instance. 4977 * 4978 * @return {Vector3} A clone of this instance. 4979 */ 4980 clone() { 4981 4982 return new this.constructor( this.x, this.y, this.z ); 4983 4984 } 4985 4986 /** 4987 * Copies the values of the given vector to this instance. 4988 * 4989 * @param {Vector3} v - The vector to copy. 4990 * @return {Vector3} A reference to this vector. 4991 */ 4992 copy( v ) { 4993 4994 this.x = v.x; 4995 this.y = v.y; 4996 this.z = v.z; 4997 4998 return this; 4999 5000 } 5001 5002 /** 5003 * Adds the given vector to this instance. 5004 * 5005 * @param {Vector3} v - The vector to add. 5006 * @return {Vector3} A reference to this vector. 5007 */ 5008 add( v ) { 5009 5010 this.x += v.x; 5011 this.y += v.y; 5012 this.z += v.z; 5013 5014 return this; 5015 5016 } 5017 5018 /** 5019 * Adds the given scalar value to all components of this instance. 5020 * 5021 * @param {number} s - The scalar to add. 5022 * @return {Vector3} A reference to this vector. 5023 */ 5024 addScalar( s ) { 5025 5026 this.x += s; 5027 this.y += s; 5028 this.z += s; 5029 5030 return this; 5031 5032 } 5033 5034 /** 5035 * Adds the given vectors and stores the result in this instance. 5036 * 5037 * @param {Vector3} a - The first vector. 5038 * @param {Vector3} b - The second vector. 5039 * @return {Vector3} A reference to this vector. 5040 */ 5041 addVectors( a, b ) { 5042 5043 this.x = a.x + b.x; 5044 this.y = a.y + b.y; 5045 this.z = a.z + b.z; 5046 5047 return this; 5048 5049 } 5050 5051 /** 5052 * Adds the given vector scaled by the given factor to this instance. 5053 * 5054 * @param {Vector3|Vector4} v - The vector. 5055 * @param {number} s - The factor that scales `v`. 5056 * @return {Vector3} A reference to this vector. 5057 */ 5058 addScaledVector( v, s ) { 5059 5060 this.x += v.x * s; 5061 this.y += v.y * s; 5062 this.z += v.z * s; 5063 5064 return this; 5065 5066 } 5067 5068 /** 5069 * Subtracts the given vector from this instance. 5070 * 5071 * @param {Vector3} v - The vector to subtract. 5072 * @return {Vector3} A reference to this vector. 5073 */ 5074 sub( v ) { 5075 5076 this.x -= v.x; 5077 this.y -= v.y; 5078 this.z -= v.z; 5079 5080 return this; 5081 5082 } 5083 5084 /** 5085 * Subtracts the given scalar value from all components of this instance. 5086 * 5087 * @param {number} s - The scalar to subtract. 5088 * @return {Vector3} A reference to this vector. 5089 */ 5090 subScalar( s ) { 5091 5092 this.x -= s; 5093 this.y -= s; 5094 this.z -= s; 5095 5096 return this; 5097 5098 } 5099 5100 /** 5101 * Subtracts the given vectors and stores the result in this instance. 5102 * 5103 * @param {Vector3} a - The first vector. 5104 * @param {Vector3} b - The second vector. 5105 * @return {Vector3} A reference to this vector. 5106 */ 5107 subVectors( a, b ) { 5108 5109 this.x = a.x - b.x; 5110 this.y = a.y - b.y; 5111 this.z = a.z - b.z; 5112 5113 return this; 5114 5115 } 5116 5117 /** 5118 * Multiplies the given vector with this instance. 5119 * 5120 * @param {Vector3} v - The vector to multiply. 5121 * @return {Vector3} A reference to this vector. 5122 */ 5123 multiply( v ) { 5124 5125 this.x *= v.x; 5126 this.y *= v.y; 5127 this.z *= v.z; 5128 5129 return this; 5130 5131 } 5132 5133 /** 5134 * Multiplies the given scalar value with all components of this instance. 5135 * 5136 * @param {number} scalar - The scalar to multiply. 5137 * @return {Vector3} A reference to this vector. 5138 */ 5139 multiplyScalar( scalar ) { 5140 5141 this.x *= scalar; 5142 this.y *= scalar; 5143 this.z *= scalar; 5144 5145 return this; 5146 5147 } 5148 5149 /** 5150 * Multiplies the given vectors and stores the result in this instance. 5151 * 5152 * @param {Vector3} a - The first vector. 5153 * @param {Vector3} b - The second vector. 5154 * @return {Vector3} A reference to this vector. 5155 */ 5156 multiplyVectors( a, b ) { 5157 5158 this.x = a.x * b.x; 5159 this.y = a.y * b.y; 5160 this.z = a.z * b.z; 5161 5162 return this; 5163 5164 } 5165 5166 /** 5167 * Applies the given Euler rotation to this vector. 5168 * 5169 * @param {Euler} euler - The Euler angles. 5170 * @return {Vector3} A reference to this vector. 5171 */ 5172 applyEuler( euler ) { 5173 5174 return this.applyQuaternion( _quaternion$5.setFromEuler( euler ) ); 5175 5176 } 5177 5178 /** 5179 * Applies a rotation specified by an axis and an angle to this vector. 5180 * 5181 * @param {Vector3} axis - A normalized vector representing the rotation axis. 5182 * @param {number} angle - The angle in radians. 5183 * @return {Vector3} A reference to this vector. 5184 */ 5185 applyAxisAngle( axis, angle ) { 5186 5187 return this.applyQuaternion( _quaternion$5.setFromAxisAngle( axis, angle ) ); 5188 5189 } 5190 5191 /** 5192 * Multiplies this vector with the given 3x3 matrix. 5193 * 5194 * @param {Matrix3} m - The 3x3 matrix. 5195 * @return {Vector3} A reference to this vector. 5196 */ 5197 applyMatrix3( m ) { 5198 5199 const x = this.x, y = this.y, z = this.z; 5200 const e = m.elements; 5201 5202 this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z; 5203 this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z; 5204 this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z; 5205 5206 return this; 5207 5208 } 5209 5210 /** 5211 * Multiplies this vector by the given normal matrix and normalizes 5212 * the result. 5213 * 5214 * @param {Matrix3} m - The normal matrix. 5215 * @return {Vector3} A reference to this vector. 5216 */ 5217 applyNormalMatrix( m ) { 5218 5219 return this.applyMatrix3( m ).normalize(); 5220 5221 } 5222 5223 /** 5224 * Multiplies this vector (with an implicit 1 in the 4th dimension) by m, and 5225 * divides by perspective. 5226 * 5227 * @param {Matrix4} m - The matrix to apply. 5228 * @return {Vector3} A reference to this vector. 5229 */ 5230 applyMatrix4( m ) { 5231 5232 const x = this.x, y = this.y, z = this.z; 5233 const e = m.elements; 5234 5235 const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); 5236 5237 this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w; 5238 this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w; 5239 this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w; 5240 5241 return this; 5242 5243 } 5244 5245 /** 5246 * Applies the given Quaternion to this vector. 5247 * 5248 * @param {Quaternion} q - The Quaternion. 5249 * @return {Vector3} A reference to this vector. 5250 */ 5251 applyQuaternion( q ) { 5252 5253 // quaternion q is assumed to have unit length 5254 5255 const vx = this.x, vy = this.y, vz = this.z; 5256 const qx = q.x, qy = q.y, qz = q.z, qw = q.w; 5257 5258 // t = 2 * cross( q.xyz, v ); 5259 const tx = 2 * ( qy * vz - qz * vy ); 5260 const ty = 2 * ( qz * vx - qx * vz ); 5261 const tz = 2 * ( qx * vy - qy * vx ); 5262 5263 // v + q.w * t + cross( q.xyz, t ); 5264 this.x = vx + qw * tx + qy * tz - qz * ty; 5265 this.y = vy + qw * ty + qz * tx - qx * tz; 5266 this.z = vz + qw * tz + qx * ty - qy * tx; 5267 5268 return this; 5269 5270 } 5271 5272 /** 5273 * Projects this vector from world space into the camera's normalized 5274 * device coordinate (NDC) space. 5275 * 5276 * @param {Camera} camera - The camera. 5277 * @return {Vector3} A reference to this vector. 5278 */ 5279 project( camera ) { 5280 5281 return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix ); 5282 5283 } 5284 5285 /** 5286 * Unprojects this vector from the camera's normalized device coordinate (NDC) 5287 * space into world space. 5288 * 5289 * @param {Camera} camera - The camera. 5290 * @return {Vector3} A reference to this vector. 5291 */ 5292 unproject( camera ) { 5293 5294 return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld ); 5295 5296 } 5297 5298 /** 5299 * Transforms th
5299e direction of this vector by a matrix (the upper left 3 x 3 5300 * subset of the given 4x4 matrix and then
vendor: 25,414 bytes, lines 5300-6366
5300 normalizes the result. 5301 * 5302 * @param {Matrix4} m - The matrix. 5303 * @return {Vector3} A reference to this vector. 5304 */ 5305 transformDirection( m ) { 5306 5307 // input: THREE.Matrix4 affine matrix 5308 // vector interpreted as a direction 5309 5310 const x = this.x, y = this.y, z = this.z; 5311 const e = m.elements; 5312 5313 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z; 5314 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z; 5315 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z; 5316 5317 return this.normalize(); 5318 5319 } 5320 5321 /** 5322 * Divides this instance by the given vector. 5323 * 5324 * @param {Vector3} v - The vector to divide. 5325 * @return {Vector3} A reference to this vector. 5326 */ 5327 divide( v ) { 5328 5329 this.x /= v.x; 5330 this.y /= v.y; 5331 this.z /= v.z; 5332 5333 return this; 5334 5335 } 5336 5337 /** 5338 * Divides this vector by the given scalar. 5339 * 5340 * @param {number} scalar - The scalar to divide. 5341 * @return {Vector3} A reference to this vector. 5342 */ 5343 divideScalar( scalar ) { 5344 5345 return this.multiplyScalar( 1 / scalar ); 5346 5347 } 5348 5349 /** 5350 * If this vector's x, y or z value is greater than the given vector's x, y or z 5351 * value, replace that value with the corresponding min value. 5352 * 5353 * @param {Vector3} v - The vector. 5354 * @return {Vector3} A reference to this vector. 5355 */ 5356 min( v ) { 5357 5358 this.x = Math.min( this.x, v.x ); 5359 this.y = Math.min( this.y, v.y ); 5360 this.z = Math.min( this.z, v.z ); 5361 5362 return this; 5363 5364 } 5365 5366 /** 5367 * If this vector's x, y or z value is less than the given vector's x, y or z 5368 * value, replace that value with the corresponding max value. 5369 * 5370 * @param {Vector3} v - The vector. 5371 * @return {Vector3} A reference to this vector. 5372 */ 5373 max( v ) { 5374 5375 this.x = Math.max( this.x, v.x ); 5376 this.y = Math.max( this.y, v.y ); 5377 this.z = Math.max( this.z, v.z ); 5378 5379 return this; 5380 5381 } 5382 5383 /** 5384 * If this vector's x, y or z value is greater than the max vector's x, y or z 5385 * value, it is replaced by the corresponding value. 5386 * If this vector's x, y or z value is less than the min vector's x, y or z value, 5387 * it is replaced by the corresponding value. 5388 * 5389 * @param {Vector3} min - The minimum x, y and z values. 5390 * @param {Vector3} max - The maximum x, y and z values in the desired range. 5391 * @return {Vector3} A reference to this vector. 5392 */ 5393 clamp( min, max ) { 5394 5395 // assumes min < max, componentwise 5396 5397 this.x = clamp( this.x, min.x, max.x ); 5398 this.y = clamp( this.y, min.y, max.y ); 5399 this.z = clamp( this.z, min.z, max.z ); 5400 5401 return this; 5402 5403 } 5404 5405 /** 5406 * If this vector's x, y or z values are greater than the max value, they are 5407 * replaced by the max value. 5408 * If this vector's x, y or z values are less than the min value, they are 5409 * replaced by the min value. 5410 * 5411 * @param {number} minVal - The minimum value the components will be clamped to. 5412 * @param {number} maxVal - The maximum value the components will be clamped to. 5413 * @return {Vector3} A reference to this vector. 5414 */ 5415 clampScalar( minVal, maxVal ) { 5416 5417 this.x = clamp( this.x, minVal, maxVal ); 5418 this.y = clamp( this.y, minVal, maxVal ); 5419 this.z = clamp( this.z, minVal, maxVal ); 5420 5421 return this; 5422 5423 } 5424 5425 /** 5426 * If this vector's length is greater than the max value, it is replaced by 5427 * the max value. 5428 * If this vector's length is less than the min value, it is replaced by the 5429 * min value. 5430 * 5431 * @param {number} min - The minimum value the vector length will be clamped to. 5432 * @param {number} max - The maximum value the vector length will be clamped to. 5433 * @return {Vector3} A reference to this vector. 5434 */ 5435 clampLength( min, max ) { 5436 5437 const length = this.length(); 5438 5439 return this.divideScalar( length || 1 ).multiplyScalar( clamp( length, min, max ) ); 5440 5441 } 5442 5443 /** 5444 * The components of this vector are rounded down to the nearest integer value. 5445 * 5446 * @return {Vector3} A reference to this vector. 5447 */ 5448 floor() { 5449 5450 this.x = Math.floor( this.x ); 5451 this.y = Math.floor( this.y ); 5452 this.z = Math.floor( this.z ); 5453 5454 return this; 5455 5456 } 5457 5458 /** 5459 * The components of this vector are rounded up to the nearest integer value. 5460 * 5461 * @return {Vector3} A reference to this vector. 5462 */ 5463 ceil() { 5464 5465 this.x = Math.ceil( this.x ); 5466 this.y = Math.ceil( this.y ); 5467 this.z = Math.ceil( this.z ); 5468 5469 return this; 5470 5471 } 5472 5473 /** 5474 * The components of this vector are rounded to the nearest integer value 5475 * 5476 * @return {Vector3} A reference to this vector. 5477 */ 5478 round() { 5479 5480 this.x = Math.round( this.x ); 5481 this.y = Math.round( this.y ); 5482 this.z = Math.round( this.z ); 5483 5484 return this; 5485 5486 } 5487 5488 /** 5489 * The components of this vector are rounded towards zero (up if negative, 5490 * down if positive) to an integer value. 5491 * 5492 * @return {Vector3} A reference to this vector. 5493 */ 5494 roundToZero() { 5495 5496 this.x = Math.trunc( this.x ); 5497 this.y = Math.trunc( this.y ); 5498 this.z = Math.trunc( this.z ); 5499 5500 return this; 5501 5502 } 5503 5504 /** 5505 * Inverts this vector - i.e. sets x = -x, y = -y and z = -z. 5506 * 5507 * @return {Vector3} A reference to this vector. 5508 */ 5509 negate() { 5510 5511 this.x = - this.x; 5512 this.y = - this.y; 5513 this.z = - this.z; 5514 5515 return this; 5516 5517 } 5518 5519 /** 5520 * Calculates the dot product of the given vector with this instance. 5521 * 5522 * @param {Vector3} v - The vector to compute the dot product with. 5523 * @return {number} The result of the dot product. 5524 */ 5525 dot( v ) { 5526 5527 return this.x * v.x + this.y * v.y + this.z * v.z; 5528 5529 } 5530 5531 /** 5532 * Computes the square of the Euclidean length (straight-line length) from 5533 * (0, 0, 0) to (x, y, z). If you are comparing the lengths of vectors, you should 5534 * compare the length squared instead as it is slightly more efficient to calculate. 5535 * 5536 * @return {number} The square length of this vector. 5537 */ 5538 lengthSq() { 5539 5540 return this.x * this.x + this.y * this.y + this.z * this.z; 5541 5542 } 5543 5544 /** 5545 * Computes the Euclidean length (straight-line length) from (0, 0, 0) to (x, y, z). 5546 * 5547 * @return {number} The length of this vector. 5548 */ 5549 length() { 5550 5551 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); 5552 5553 } 5554 5555 /** 5556 * Computes the Manhattan length of this vector. 5557 * 5558 * @return {number} The length of this vector. 5559 */ 5560 manhattanLength() { 5561 5562 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); 5563 5564 } 5565 5566 /** 5567 * Converts this vector to a unit vector - that is, sets it equal to a vector 5568 * with the same direction as this one, but with a vector length of `1`. 5569 * 5570 * @return {Vector3} A reference to this vector. 5571 */ 5572 normalize() { 5573 5574 return this.divideScalar( this.length() || 1 ); 5575 5576 } 5577 5578 /** 5579 * Sets this vector to a vector with the same direction as this one, but 5580 * with the specified length. 5581 * 5582 * @param {number} length - The new length of this vector. 5583 * @return {Vector3} A reference to this vector. 5584 */ 5585 setLength( length ) { 5586 5587 return this.normalize().multiplyScalar( length ); 5588 5589 } 5590 5591 /** 5592 * Linearly interpolates between the given vector and this instance, where 5593 * alpha is the percent distance along the line - alpha = 0 will be this 5594 * vector, and alpha = 1 will be the given one. 5595 * 5596 * @param {Vector3} v - The vector to interpolate towards. 5597 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. 5598 * @return {Vector3} A reference to this vector. 5599 */ 5600 lerp( v, alpha ) { 5601 5602 this.x += ( v.x - this.x ) * alpha; 5603 this.y += ( v.y - this.y ) * alpha; 5604 this.z += ( v.z - this.z ) * alpha; 5605 5606 return this; 5607 5608 } 5609 5610 /** 5611 * Linearly interpolates between the given vectors, where alpha is the percent 5612 * distance along the line - alpha = 0 will be first vector, and alpha = 1 will 5613 * be the second one. The result is stored in this instance. 5614 * 5615 * @param {Vector3} v1 - The first vector. 5616 * @param {Vector3} v2 - The second vector. 5617 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. 5618 * @return {Vector3} A reference to this vector. 5619 */ 5620 lerpVectors( v1, v2, alpha ) { 5621 5622 this.x = v1.x + ( v2.x - v1.x ) * alpha; 5623 this.y = v1.y + ( v2.y - v1.y ) * alpha; 5624 this.z = v1.z + ( v2.z - v1.z ) * alpha; 5625 5626 return this; 5627 5628 } 5629 5630 /** 5631 * Calculates the cross product of the given vector with this instance. 5632 * 5633 * @param {Vector3} v - The vector to compute the cross product with. 5634 * @return {Vector3} The result of the cross product. 5635 */ 5636 cross( v ) { 5637 5638 return this.crossVectors( this, v ); 5639 5640 } 5641 5642 /** 5643 * Calculates the cross product of the given vectors and stores the result 5644 * in this instance. 5645 * 5646 * @param {Vector3} a - The first vector. 5647 * @param {Vector3} b - The second vector. 5648 * @return {Vector3} A reference to this vector. 5649 */ 5650 crossVectors( a, b ) { 5651 5652 const ax = a.x, ay = a.y, az = a.z; 5653 const bx = b.x, by = b.y, bz = b.z; 5654 5655 this.x = ay * bz - az * by; 5656 this.y = az * bx - ax * bz; 5657 this.z = ax * by - ay * bx; 5658 5659 return this; 5660 5661 } 5662 5663 /** 5664 * Projects this vector onto the given one. 5665 * 5666 * @param {Vector3} v - The vector to project to. 5667 * @return {Vector3} A reference to this vector. 5668 */ 5669 projectOnVector( v ) { 5670 5671 const denominator = v.lengthSq(); 5672 5673 if ( denominator === 0 ) return this.set( 0, 0, 0 ); 5674 5675 const scalar = v.dot( this ) / denominator; 5676 5677 return this.copy( v ).multiplyScalar( scalar ); 5678 5679 } 5680 5681 /** 5682 * Projects this vector onto a plane by subtracting this 5683 * vector projected onto the plane's normal from this vector. 5684 * 5685 * @param {Vector3} planeNormal - The plane normal. 5686 * @return {Vector3} A reference to this vector. 5687 */ 5688 projectOnPlane( planeNormal ) { 5689 5690 _vector$c.copy( this ).projectOnVector( planeNormal ); 5691 5692 return this.sub( _vector$c ); 5693 5694 } 5695 5696 /** 5697 * Reflects this vector off a plane orthogonal to the given normal vector. 5698 * 5699 * @param {Vector3} normal - The (normalized) normal vector. 5700 * @return {Vector3} A reference to this vector. 5701 */ 5702 reflect( normal ) { 5703 5704 return this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); 5705 5706 } 5707 /** 5708 * Returns the angle between the given vector and this instance in radians. 5709 * 5710 * @param {Vector3} v - The vector to compute the angle with. 5711 * @return {number} The angle in radians. 5712 */ 5713 angleTo( v ) { 5714 5715 const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); 5716 5717 if ( denominator === 0 ) return Math.PI / 2; 5718 5719 const theta = this.dot( v ) / denominator; 5720 5721 // clamp, to handle numerical problems 5722 5723 return Math.acos( clamp( theta, -1, 1 ) ); 5724 5725 } 5726 5727 /** 5728 * Computes the distance from the given vector to this instance. 5729 * 5730 * @param {Vector3} v - The vector to compute the distance to. 5731 * @return {number} The distance. 5732 */ 5733 distanceTo( v ) { 5734 5735 return Math.sqrt( this.distanceToSquared( v ) ); 5736 5737 } 5738 5739 /** 5740 * Computes the squared distance from the given vector to this instance. 5741 * If you are just comparing the distance with another distance, you should compare 5742 * the distance squared instead as it is slightly more efficient to calculate. 5743 * 5744 * @param {Vector3} v - The vector to compute the squared distance to. 5745 * @return {number} The squared distance. 5746 */ 5747 distanceToSquared( v ) { 5748 5749 const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; 5750 5751 return dx * dx + dy * dy + dz * dz; 5752 5753 } 5754 5755 /** 5756 * Computes the Manhattan distance from the given vector to this instance. 5757 * 5758 * @param {Vector3} v - The vector to compute the Manhattan distance to. 5759 * @return {number} The Manhattan distance. 5760 */ 5761 manhattanDistanceTo( v ) { 5762 5763 return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); 5764 5765 } 5766 5767 /** 5768 * Sets the vector components from the given spherical coordinates. 5769 * 5770 * @param {Spherical} s - The spherical coordinates. 5771 * @return {Vector3} A reference to this vector. 5772 */ 5773 setFromSpherical( s ) { 5774 5775 return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); 5776 5777 } 5778 5779 /** 5780 * Sets the vector components from the given spherical coordinates. 5781 * 5782 * @param {number} radius - The radius. 5783 * @param {number} phi - The phi angle in radians. 5784 * @param {number} theta - The theta angle in radians. 5785 * @return {Vector3} A reference to this vector. 5786 */ 5787 setFromSphericalCoords( radius, phi, theta ) { 5788 5789 const sinPhiRadius = Math.sin( phi ) * radius; 5790 5791 this.x = sinPhiRadius * Math.sin( theta ); 5792 this.y = Math.cos( phi ) * radius; 5793 this.z = sinPhiRadius * Math.cos( theta ); 5794 5795 return this; 5796 5797 } 5798 5799 /** 5800 * Sets the vector components from the given cylindrical coordinates. 5801 * 5802 * @param {Cylindrical} c - The cylindrical coordinates. 5803 * @return {Vector3} A reference to this vector. 5804 */ 5805 setFromCylindrical( c ) { 5806 5807 return this.setFromCylindricalCoords( c.radius, c.theta, c.y ); 5808 5809 } 5810 5811 /** 5812 * Sets the vector components from the given cylindrical coordinates. 5813 * 5814 * @param {number} radius - The radius. 5815 * @param {number} theta - The theta angle in radians. 5816 * @param {number} y - The y value. 5817 * @return {Vector3} A reference to this vector. 5818 */ 5819 setFromCylindricalCoords( radius, theta, y ) { 5820 5821 this.x = radius * Math.sin( theta ); 5822 this.y = y; 5823 this.z = radius * Math.cos( theta ); 5824 5825 return this; 5826 5827 } 5828 5829 /** 5830 * Sets the vector components to the position elements of the 5831 * given transformation matrix. 5832 * 5833 * @param {Matrix4} m - The 4x4 matrix. 5834 * @return {Vector3} A reference to this vector. 5835 */ 5836 setFromMatrixPosition( m ) { 5837 5838 const e = m.elements; 5839 5840 this.x = e[ 12 ]; 5841 this.y = e[ 13 ]; 5842 this.z = e[ 14 ]; 5843 5844 return this; 5845 5846 } 5847 5848 /** 5849 * Sets the vector components to the scale elements of the 5850 * given transformation matrix. 5851 * 5852 * @param {Matrix4} m - The 4x4 matrix. 5853 * @return {Vector3} A reference to this vector. 5854 */ 5855 setFromMatrixScale( m ) { 5856 5857 const sx = this.setFromMatrixColumn( m, 0 ).length(); 5858 const sy = this.setFromMatrixColumn( m, 1 ).length(); 5859 const sz = this.setFromMatrixColumn( m, 2 ).length(); 5860 5861 this.x = sx; 5862 this.y = sy; 5863 this.z = sz; 5864 5865 return this; 5866 5867 } 5868 5869 /** 5870 * Sets the vector components from the specified matrix column. 5871 * 5872 * @param {Matrix4} m - The 4x4 matrix. 5873 * @param {number} index - The column index. 5874 * @return {Vector3} A reference to this vector. 5875 */ 5876 setFromMatrixColumn( m, index ) { 5877 5878 return this.fromArray( m.elements, index * 4 ); 5879 5880 } 5881 5882 /** 5883 * Sets the vector components from the specified matrix column. 5884 * 5885 * @param {Matrix3} m - The 3x3 matrix. 5886 * @param {number} index - The column index. 5887 * @return {Vector3} A reference to this vector. 5888 */ 5889 setFromMatrix3Column( m, index ) { 5890 5891 return this.fromArray( m.elements, index * 3 ); 5892 5893 } 5894 5895 /** 5896 * Sets the vector components from the given Euler angles. 5897 * 5898 * @param {Euler} e - The Euler angles to set. 5899 * @return {Vector3} A reference to this vector. 5900 */ 5901 setFromEuler( e ) { 5902 5903 this.x = e._x; 5904 this.y = e._y; 5905 this.z = e._z; 5906 5907 return this; 5908 5909 } 5910 5911 /** 5912 * Sets the vector components from the RGB components of the 5913 * given color. 5914 * 5915 * @param {Color} c - The color to set. 5916 * @return {Vector3} A reference to this vector. 5917 */ 5918 setFromColor( c ) { 5919 5920 this.x = c.r; 5921 this.y = c.g; 5922 this.z = c.b; 5923 5924 return this; 5925 5926 } 5927 5928 /** 5929 * Returns `true` if this vector is equal with the given one. 5930 * 5931 * @param {Vector3} v - The vector to test for equality. 5932 * @return {boolean} Whether this vector is equal with the given one. 5933 */ 5934 equals( v ) { 5935 5936 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); 5937 5938 } 5939 5940 /** 5941 * Sets this vector's x value to be `array[ offset ]`, y value to be `array[ offset + 1 ]` 5942 * and z value to be `array[ offset + 2 ]`. 5943 * 5944 * @param {Array<number>} array - An array holding the vector component values. 5945 * @param {number} [offset=0] - The offset into the array. 5946 * @return {Vector3} A reference to this vector. 5947 */ 5948 fromArray( array, offset = 0 ) { 5949 5950 this.x = array[ offset ]; 5951 this.y = array[ offset + 1 ]; 5952 this.z = array[ offset + 2 ]; 5953 5954 return this; 5955 5956 } 5957 5958 /** 5959 * Writes the components of this vector to the given array. If no array is provided, 5960 * the method returns a new instance. 5961 * 5962 * @param {Array<number>} [array=[]] - The target array holding the vector components. 5963 * @param {number} [offset=0] - Index of the first element in the array. 5964 * @return {Array<number>} The vector components. 5965 */ 5966 toArray( array = [], offset = 0 ) { 5967 5968 array[ offset ] = this.x; 5969 array[ offset + 1 ] = this.y; 5970 array[ offset + 2 ] = this.z; 5971 5972 return array; 5973 5974 } 5975 5976 /** 5977 * Sets the components of this vector from the given buffer attribute. 5978 * 5979 * @param {BufferAttribute} attribute - The buffer attribute holding vector data. 5980 * @param {number} index - The index into the attribute. 5981 * @return {Vector3} A reference to this vector. 5982 */ 5983 fromBufferAttribute( attribute, index ) { 5984 5985 this.x = attribute.getX( index ); 5986 this.y = attribute.getY( index ); 5987 this.z = attribute.getZ( index ); 5988 5989 return this; 5990 5991 } 5992 5993 /** 5994 * Sets each component of this vector to a pseudo-random value between `0` and 5995 * `1`, excluding `1`. 5996 * 5997 * @return {Vector3} A reference to this vector. 5998 */ 5999 random() { 6000 6001 this.x = Math.random(); 6002 this.y = Math.random(); 6003 this.z = Math.random(); 6004 6005 return this; 6006 6007 } 6008 6009 /** 6010 * Sets this vector to a uniformly random point on a unit sphere. 6011 * 6012 * @return {Vector3} A reference to this vector. 6013 */ 6014 randomDirection() { 6015 6016 // https://mathworld.wolfram.com/SpherePointPicking.html 6017 6018 const theta = Math.random() * Math.PI * 2; 6019 const u = Math.random() * 2 - 1; 6020 const c = Math.sqrt( 1 - u * u ); 6021 6022 this.x = c * Math.cos( theta ); 6023 this.y = u; 6024 this.z = c * Math.sin( theta ); 6025 6026 return this; 6027 6028 } 6029 6030 *[ Symbol.iterator ]() { 6031 6032 yield this.x; 6033 yield this.y; 6034 yield this.z; 6035 6036 } 6037 6038} 6039 6040const _vector$c = /*@__PURE__*/ new Vector3(); 6041const _quaternion$5 = /*@__PURE__*/ new Quaternion(); 6042 6043/** 6044 * Represents a 3x3 matrix. 6045 * 6046 * A Note on Row-Major and Column-Major Ordering: 6047 * 6048 * The constructor and {@link Matrix3#set} method take arguments in 6049 * [row-major](https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order) 6050 * order, while internally they are stored in the {@link Matrix3#elements} array in column-major order. 6051 * This means that calling: 6052 * ```js 6053 * const m = new THREE.Matrix(); 6054 * m.set( 11, 12, 13, 6055 * 21, 22, 23, 6056 * 31, 32, 33 ); 6057 * ``` 6058 * will result in the elements array containing: 6059 * ```js 6060 * m.elements = [ 11, 21, 31, 6061 * 12, 22, 32, 6062 * 13, 23, 33 ]; 6063 * ``` 6064 * and internally all calculations are performed using column-major ordering. 6065 * However, as the actual ordering makes no difference mathematically and 6066 * most people are used to thinking about matrices in row-major order, the 6067 * three.js documentation shows matrices in row-major order. Just bear in 6068 * mind that if you are reading the source code, you'll have to take the 6069 * transpose of any matrices outlined here to make sense of the calculations. 6070 */ 6071class Matrix3 { 6072 6073 static { 6074 6075 /** 6076 * This flag can be used for type testing. 6077 * 6078 * @type {boolean} 6079 * @readonly 6080 * @default true 6081 */ 6082 Matrix3.prototype.isMatrix3 = true; 6083 6084 } 6085 6086 /** 6087 * Constructs a new 3x3 matrix. The arguments are supposed to be 6088 * in row-major order. If no arguments are provided, the constructor 6089 * initializes the matrix as an identity matrix. 6090 * 6091 * @param {number} [n11] - 1-1 matrix element. 6092 * @param {number} [n12] - 1-2 matrix element. 6093 * @param {number} [n13] - 1-3 matrix element. 6094 * @param {number} [n21] - 2-1 matrix element. 6095 * @param {number} [n22] - 2-2 matrix element. 6096 * @param {number} [n23] - 2-3 matrix element. 6097 * @param {number} [n31] - 3-1 matrix element. 6098 * @param {number} [n32] - 3-2 matrix element. 6099 * @param {number} [n33] - 3-3 matrix element. 6100 */ 6101 constructor( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { 6102 6103 /** 6104 * A column-major list of matrix values. 6105 * 6106 * @type {Array<number>} 6107 */ 6108 this.elements = [ 6109 6110 1, 0, 0, 6111 0, 1, 0, 6112 0, 0, 1 6113 6114 ]; 6115 6116 if ( n11 !== undefined ) { 6117 6118 this.set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ); 6119 6120 } 6121 6122 } 6123 6124 /** 6125 * Sets the elements of the matrix.The arguments are supposed to be 6126 * in row-major order. 6127 * 6128 * @param {number} [n11] - 1-1 matrix element. 6129 * @param {number} [n12] - 1-2 matrix element. 6130 * @param {number} [n13] - 1-3 matrix element. 6131 * @param {number} [n21] - 2-1 matrix element. 6132 * @param {number} [n22] - 2-2 matrix element. 6133 * @param {number} [n23] - 2-3 matrix element. 6134 * @param {number} [n31] - 3-1 matrix element. 6135 * @param {number} [n32] - 3-2 matrix element. 6136 * @param {number} [n33] - 3-3 matrix element. 6137 * @return {Matrix3} A reference to this matrix. 6138 */ 6139 set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { 6140 6141 const te = this.elements; 6142 6143 te[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31; 6144 te[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32; 6145 te[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33; 6146 6147 return this; 6148 6149 } 6150 6151 /** 6152 * Sets this matrix to the 3x3 identity matrix. 6153 * 6154 * @return {Matrix3} A reference to this matrix. 6155 */ 6156 identity() { 6157 6158 this.set( 6159 6160 1, 0, 0, 6161 0, 1, 0, 6162 0, 0, 1 6163 6164 ); 6165 6166 return this; 6167 6168 } 6169 6170 /** 6171 * Copies the values of the given matrix to this instance. 6172 * 6173 * @param {Matrix3} m - The matrix to copy. 6174 * @return {Matrix3} A reference to this matrix. 6175 */ 6176 copy( m ) { 6177 6178 const te = this.elements; 6179 const me = m.elements; 6180 6181 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; 6182 te[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; 6183 te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ]; 6184 6185 return this; 6186 6187 } 6188 6189 /** 6190 * Extracts the basis of this matrix into the three axis vectors provided. 6191 * 6192 * @param {Vector3} xAxis - The basis's x axis. 6193 * @param {Vector3} yAxis - The basis's y axis. 6194 * @param {Vector3} zAxis - The basis's z axis. 6195 * @return {Matrix3} A reference to this matrix. 6196 */ 6197 extractBasis( xAxis, yAxis, zAxis ) { 6198 6199 xAxis.setFromMatrix3Column( this, 0 ); 6200 yAxis.setFromMatrix3Column( this, 1 ); 6201 zAxis.setFromMatrix3Column( this, 2 ); 6202 6203 return this; 6204 6205 } 6206 6207 /** 6208 * Set this matrix to the upper 3x3 matrix of the given 4x4 matrix. 6209 * 6210 * @param {Matrix4} m - The 4x4 matrix. 6211 * @return {Matrix3} A reference to this matrix. 6212 */ 6213 setFromMatrix4( m ) { 6214 6215 const me = m.elements; 6216 6217 this.set( 6218 6219 me[ 0 ], me[ 4 ], me[ 8 ], 6220 me[ 1 ], me[ 5 ], me[ 9 ], 6221 me[ 2 ], me[ 6 ], me[ 10 ] 6222 6223 ); 6224 6225 return this; 6226 6227 } 6228 6229 /** 6230 * Post-multiplies this matrix by the given 3x3 matrix. 6231 * 6232 * @param {Matrix3} m - The matrix to multiply with. 6233 * @return {Matrix3} A reference to this matrix. 6234 */ 6235 multiply( m ) { 6236 6237 return this.multiplyMatrices( this, m ); 6238 6239 } 6240 6241 /** 6242 * Pre-multiplies this matrix by the given 3x3 matrix. 6243 * 6244 * @param {Matrix3} m - The matrix to multiply with. 6245 * @return {Matrix3} A reference to this matrix. 6246 */ 6247 premultiply( m ) { 6248 6249 return this.multiplyMatrices( m, this ); 6250 6251 } 6252 6253 /** 6254 * Multiples the given 3x3 matrices and stores the result 6255 * in this matrix. 6256 * 6257 * @param {Matrix3} a - The first matrix. 6258 * @param {Matrix3} b - The second matrix. 6259 * @return {Matrix3} A reference to this matrix. 6260 */ 6261 multiplyMatrices( a, b ) { 6262 6263 const ae = a.elements; 6264 const be = b.elements; 6265 const te = this.elements; 6266 6267 const a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ]; 6268 const a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ]; 6269 const a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ]; 6270 6271 const b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ]; 6272 const b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ]; 6273 const b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ]; 6274 6275 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31; 6276 te[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32; 6277 te[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33; 6278 6279 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31; 6280 te[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32; 6281 te[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33; 6282 6283 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31; 6284 te[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32; 6285 te[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33; 6286 6287 return this; 6288 6289 } 6290 6291 /** 6292 * Multiplies every component of the matrix by the given scalar. 6293 * 6294 * @param {number} s - The scalar. 6295 * @return {Matrix3} A reference to this matrix. 6296 */ 6297 multiplyScalar( s ) { 6298 6299 const te = this.elements; 6300 6301 te[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s; 6302 te[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s; 6303 te[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s; 6304 6305 return this; 6306 6307 } 6308 6309 /** 6310 * Computes and returns the determinant of this matrix. 6311 * 6312 * @return {number} The determinant. 6313 */ 6314 determinant() { 6315 6316 const te = this.elements; 6317 6318 const a = te[ 0 ], b = te[ 1 ], c = te[ 2 ], 6319 d = te[ 3 ], e = te[ 4 ], f = te[ 5 ], 6320 g = te[ 6 ], h = te[ 7 ], i = te[ 8 ]; 6321 6322 return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g; 6323 6324 } 6325 6326 /** 6327 * Inverts this matrix, using the [analytic method](https://en.wikipedia.org/wiki/Invertible_matrix#Analytic_solution). 6328 * You can not invert with a determinant of zero. If you attempt this, the method produces 6329 * a zero matrix instead. 6330 * 6331 * @return {Matrix3} A reference to this matrix. 6332 */ 6333 invert() { 6334 6335 const te = this.elements, 6336 6337 n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], 6338 n12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ], 6339 n13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ], 6340 6341 t11 = n33 * n22 - n32 * n23, 6342 t12 = n32 * n13 - n33 * n12, 6343 t13 = n23 * n12 - n22 * n13, 6344 6345 det = n11 * t11 + n21 * t12 + n31 * t13; 6346 6347 if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 ); 6348 6349 const detInv = 1 / det; 6350 6351 te[ 0 ] = t11 * detInv; 6352 te[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv; 6353 te[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv; 6354 6355 te[ 3 ] = t12 * detInv; 6356 te[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv; 6357 te[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv; 6358 6359 te[ 6 ] = t13 * detInv; 6360 te[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv; 6361 te[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv; 6362 6363 return this; 6364 6365 } 6366
vendor: 16,024 bytes, lines 6367-7092
6367 /** 6368 * Transposes this matrix in place. 6369 * 6370 * @return {Matrix3} A reference to this matrix. 6371 */ 6372 transpose() { 6373 6374 let tmp; 6375 const m = this.elements; 6376 6377 tmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp; 6378 tmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp; 6379 tmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp; 6380 6381 return this; 6382 6383 } 6384 6385 /** 6386 * Computes the normal matrix which is the inverse transpose of the upper 6387 * left 3x3 portion of the given 4x4 matrix. 6388 * 6389 * @param {Matrix4} matrix4 - The 4x4 matrix. 6390 * @return {Matrix3} A reference to this matrix. 6391 */ 6392 getNormalMatrix( matrix4 ) { 6393 6394 return this.setFromMatrix4( matrix4 ).invert().transpose(); 6395 6396 } 6397 6398 /** 6399 * Transposes this matrix into the supplied array, and returns itself unchanged. 6400 * 6401 * @param {Array<number>} r - An array to store the transposed matrix elements. 6402 * @return {Matrix3} A reference to this matrix. 6403 */ 6404 transposeIntoArray( r ) { 6405 6406 const m = this.elements; 6407 6408 r[ 0 ] = m[ 0 ]; 6409 r[ 1 ] = m[ 3 ]; 6410 r[ 2 ] = m[ 6 ]; 6411 r[ 3 ] = m[ 1 ]; 6412 r[ 4 ] = m[ 4 ]; 6413 r[ 5 ] = m[ 7 ]; 6414 r[ 6 ] = m[ 2 ]; 6415 r[ 7 ] = m[ 5 ]; 6416 r[ 8 ] = m[ 8 ]; 6417 6418 return this; 6419 6420 } 6421 6422 /** 6423 * Sets the UV transform matrix from offset, repeat, rotation, and center. 6424 * 6425 * @param {number} tx - Offset x. 6426 * @param {number} ty - Offset y. 6427 * @param {number} sx - Repeat x. 6428 * @param {number} sy - Repeat y. 6429 * @param {number} rotation - Rotation, in radians. Positive values rotate counterclockwise. 6430 * @param {number} cx - Center x of rotation. 6431 * @param {number} cy - Center y of rotation 6432 * @return {Matrix3} A reference to this matrix. 6433 */ 6434 setUvTransform( tx, ty, sx, sy, rotation, cx, cy ) { 6435 6436 const c = Math.cos( rotation ); 6437 const s = Math.sin( rotation ); 6438 6439 this.set( 6440 sx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx, 6441 - sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty, 6442 0, 0, 1 6443 ); 6444 6445 return this; 6446 6447 } 6448 6449 /** 6450 * Scales this matrix with the given scalar values. 6451 * 6452 * @param {number} sx - The amount to scale in the X axis. 6453 * @param {number} sy - The amount to scale in the Y axis. 6454 * @return {Matrix3} A reference to this matrix. 6455 */ 6456 scale( sx, sy ) { 6457 6458 this.premultiply( _m3.makeScale( sx, sy ) ); 6459 6460 return this; 6461 6462 } 6463 6464 /** 6465 * Rotates this matrix by the given angle. 6466 * 6467 * @param {number} theta - The rotation in radians. 6468 * @return {Matrix3} A reference to this matrix. 6469 */ 6470 rotate( theta ) { 6471 6472 this.premultiply( _m3.makeRotation( - theta ) ); 6473 6474 return this; 6475 6476 } 6477 6478 /** 6479 * Translates this matrix by the given scalar values. 6480 * 6481 * @param {number} tx - The amount to translate in the X axis. 6482 * @param {number} ty - The amount to translate in the Y axis. 6483 * @return {Matrix3} A reference to this matrix. 6484 */ 6485 translate( tx, ty ) { 6486 6487 this.premultiply( _m3.makeTranslation( tx, ty ) ); 6488 6489 return this; 6490 6491 } 6492 6493 // for 2D Transforms 6494 6495 /** 6496 * Sets this matrix as a 2D translation transform. 6497 * 6498 * @param {number|Vector2} x - The amount to translate in the X axis or alternatively a translation vector. 6499 * @param {number} y - The amount to translate in the Y axis. 6500 * @return {Matrix3} A reference to this matrix. 6501 */ 6502 makeTranslation( x, y ) { 6503 6504 if ( x.isVector2 ) { 6505 6506 this.set( 6507 6508 1, 0, x.x, 6509 0, 1, x.y, 6510 0, 0, 1 6511 6512 ); 6513 6514 } else { 6515 6516 this.set( 6517 6518 1, 0, x, 6519 0, 1, y, 6520 0, 0, 1 6521 6522 ); 6523 6524 } 6525 6526 return this; 6527 6528 } 6529 6530 /** 6531 * Sets this matrix as a 2D rotational transformation. 6532 * 6533 * @param {number} theta - The rotation in radians. 6534 * @return {Matrix3} A reference to this matrix. 6535 */ 6536 makeRotation( theta ) { 6537 6538 // counterclockwise 6539 6540 const c = Math.cos( theta ); 6541 const s = Math.sin( theta ); 6542 6543 this.set( 6544 6545 c, - s, 0, 6546 s, c, 0, 6547 0, 0, 1 6548 6549 ); 6550 6551 return this; 6552 6553 } 6554 6555 /** 6556 * Sets this matrix as a 2D scale transform. 6557 * 6558 * @param {number} x - The amount to scale in the X axis. 6559 * @param {number} y - The amount to scale in the Y axis. 6560 * @return {Matrix3} A reference to this matrix. 6561 */ 6562 makeScale( x, y ) { 6563 6564 this.set( 6565 6566 x, 0, 0, 6567 0, y, 0, 6568 0, 0, 1 6569 6570 ); 6571 6572 return this; 6573 6574 } 6575 6576 /** 6577 * Returns `true` if this matrix is equal with the given one. 6578 * 6579 * @param {Matrix3} matrix - The matrix to test for equality. 6580 * @return {boolean} Whether this matrix is equal with the given one. 6581 */ 6582 equals( matrix ) { 6583 6584 const te = this.elements; 6585 const me = matrix.elements; 6586 6587 for ( let i = 0; i < 9; i ++ ) { 6588 6589 if ( te[ i ] !== me[ i ] ) return false; 6590 6591 } 6592 6593 return true; 6594 6595 } 6596 6597 /** 6598 * Sets the elements of the matrix from the given array. 6599 * 6600 * @param {Array<number>} array - The matrix elements in column-major order. 6601 * @param {number} [offset=0] - Index of the first element in the array. 6602 * @return {Matrix3} A reference to this matrix. 6603 */ 6604 fromArray( array, offset = 0 ) { 6605 6606 for ( let i = 0; i < 9; i ++ ) { 6607 6608 this.elements[ i ] = array[ i + offset ]; 6609 6610 } 6611 6612 return this; 6613 6614 } 6615 6616 /** 6617 * Writes the elements of this matrix to the given array. If no array is provided, 6618 * the method returns a new instance. 6619 * 6620 * @param {Array<number>} [array=[]] - The target array holding the matrix elements in column-major order. 6621 * @param {number} [offset=0] - Index of the first element in the array. 6622 * @return {Array<number>} The matrix elements in column-major order. 6623 */ 6624 toArray( array = [], offset = 0 ) { 6625 6626 const te = this.elements; 6627 6628 array[ offset ] = te[ 0 ]; 6629 array[ offset + 1 ] = te[ 1 ]; 6630 array[ offset + 2 ] = te[ 2 ]; 6631 6632 array[ offset + 3 ] = te[ 3 ]; 6633 array[ offset + 4 ] = te[ 4 ]; 6634 array[ offset + 5 ] = te[ 5 ]; 6635 6636 array[ offset + 6 ] = te[ 6 ]; 6637 array[ offset + 7 ] = te[ 7 ]; 6638 array[ offset + 8 ] = te[ 8 ]; 6639 6640 return array; 6641 6642 } 6643 6644 /** 6645 * Returns a matrix with copied values from this instance. 6646 * 6647 * @return {Matrix3} A clone of this instance. 6648 */ 6649 clone() { 6650 6651 return new this.constructor().fromArray( this.elements ); 6652 6653 } 6654 6655} 6656 6657const _m3 = /*@__PURE__*/ new Matrix3(); 6658 6659const LINEAR_REC709_TO_XYZ = /*@__PURE__*/ new Matrix3().set( 6660 0.4123908, 0.3575843, 0.1804808, 6661 0.2126390, 0.7151687, 0.0721923, 6662 0.0193308, 0.1191948, 0.9505322 6663); 6664 6665const XYZ_TO_LINEAR_REC709 = /*@__PURE__*/ new Matrix3().set( 6666 3.2409699, -1.5373832, -0.4986108, 6667 -0.9692436, 1.8759675, 0.0415551, 6668 0.0556301, -0.203977, 1.0569715 6669); 6670 6671function createColorManagement() { 6672 6673 const ColorManagement = { 6674 6675 enabled: true, 6676 6677 workingColorSpace: LinearSRGBColorSpace, 6678 6679 /** 6680 * Implementations of supported color spaces. 6681 * 6682 * Required: 6683 * - primaries: chromaticity coordinates [ rx ry gx gy bx by ] 6684 * - whitePoint: reference white [ x y ] 6685 * - transfer: transfer function (pre-defined) 6686 * - toXYZ: Matrix3 RGB to XYZ transform 6687 * - fromXYZ: Matrix3 XYZ to RGB transform 6688 * - luminanceCoefficients: RGB luminance coefficients 6689 * 6690 * Optional: 6691 * - outputColorSpaceConfig: { drawingBufferColorSpace: ColorSpace, toneMappingMode: 'extended' | 'standard' } 6692 * - workingColorSpaceConfig: { unpackColorSpace: ColorSpace } 6693 * 6694 * Reference: 6695 * - https://www.russellcottrell.com/photo/matrixCalculator.htm 6696 */ 6697 spaces: {}, 6698 6699 convert: function ( color, sourceColorSpace, targetColorSpace ) { 6700 6701 if ( this.enabled === false || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) { 6702 6703 return color; 6704 6705 } 6706 6707 if ( this.spaces[ sourceColorSpace ].transfer === SRGBTransfer ) { 6708 6709 color.r = SRGBToLinear( color.r ); 6710 color.g = SRGBToLinear( color.g ); 6711 color.b = SRGBToLinear( color.b ); 6712 6713 } 6714 6715 if ( this.spaces[ sourceColorSpace ].primaries !== this.spaces[ targetColorSpace ].primaries ) { 6716 6717 color.applyMatrix3( this.spaces[ sourceColorSpace ].toXYZ ); 6718 color.applyMatrix3( this.spaces[ targetColorSpace ].fromXYZ ); 6719 6720 } 6721 6722 if ( this.spaces[ targetColorSpace ].transfer === SRGBTransfer ) { 6723 6724 color.r = LinearToSRGB( color.r ); 6725 color.g = LinearToSRGB( color.g ); 6726 color.b = LinearToSRGB( color.b ); 6727 6728 } 6729 6730 return color; 6731 6732 }, 6733 6734 workingToColorSpace: function ( color, targetColorSpace ) { 6735 6736 return this.convert( color, this.workingColorSpace, targetColorSpace ); 6737 6738 }, 6739 6740 colorSpaceToWorking: function ( color, sourceColorSpace ) { 6741 6742 return this.convert( color, sourceColorSpace, this.workingColorSpace ); 6743 6744 }, 6745 6746 getPrimaries: function ( colorSpace ) { 6747 6748 return this.spaces[ colorSpace ].primaries; 6749 6750 }, 6751 6752 getTransfer: function ( colorSpace ) { 6753 6754 if ( colorSpace === NoColorSpace ) return LinearTransfer; 6755 6756 return this.spaces[ colorSpace ].transfer; 6757 6758 }, 6759 6760 getToneMappingMode: function ( colorSpace ) { 6761 6762 return this.spaces[ colorSpace ].outputColorSpaceConfig.toneMappingMode || 'standard'; 6763 6764 }, 6765 6766 getLuminanceCoefficients: function ( target, colorSpace = this.workingColorSpace ) { 6767 6768 return target.fromArray( this.spaces[ colorSpace ].luminanceCoefficients ); 6769 6770 }, 6771 6772 define: function ( colorSpaces ) { 6773 6774 Object.assign( this.spaces, colorSpaces ); 6775 6776 }, 6777 6778 // Internal APIs 6779 6780 _getMatrix: function ( targetMatrix, sourceColorSpace, targetColorSpace ) { 6781 6782 return targetMatrix 6783 .copy( this.spaces[ sourceColorSpace ].toXYZ ) 6784 .multiply( this.spaces[ targetColorSpace ].fromXYZ ); 6785 6786 }, 6787 6788 _getDrawingBufferColorSpace: function ( colorSpace ) { 6789 6790 return this.spaces[ colorSpace ].outputColorSpaceConfig.drawingBufferColorSpace; 6791 6792 }, 6793 6794 _getUnpackColorSpace: function ( colorSpace = this.workingColorSpace ) { 6795 6796 return this.spaces[ colorSpace ].workingColorSpaceConfig.unpackColorSpace; 6797 6798 }, 6799 6800 // Deprecated 6801 6802 fromWorkingColorSpace: function ( color, targetColorSpace ) { 6803 6804 warnOnce( 'ColorManagement: .fromWorkingColorSpace() has been renamed to .workingToColorSpace().' ); // @deprecated, r177 6805 6806 return ColorManagement.workingToColorSpace( color, targetColorSpace ); 6807 6808 }, 6809 6810 toWorkingColorSpace: function ( color, sourceColorSpace ) { 6811 6812 warnOnce( 'ColorManagement: .toWorkingColorSpace() has been renamed to .colorSpaceToWorking().' ); // @deprecated, r177 6813 6814 return ColorManagement.colorSpaceToWorking( color, sourceColorSpace ); 6815 6816 }, 6817 6818 }; 6819 6820 /****************************************************************************** 6821 * sRGB definitions 6822 */ 6823 6824 const REC709_PRIMARIES = [ 0.640, 0.330, 0.300, 0.600, 0.150, 0.060 ]; 6825 const REC709_LUMINANCE_COEFFICIENTS = [ 0.2126, 0.7152, 0.0722 ]; 6826 const D65 = [ 0.3127, 0.3290 ]; 6827 6828 ColorManagement.define( { 6829 6830 [ LinearSRGBColorSpace ]: { 6831 primaries: REC709_PRIMARIES, 6832 whitePoint: D65, 6833 transfer: LinearTransfer, 6834 toXYZ: LINEAR_REC709_TO_XYZ, 6835 fromXYZ: XYZ_TO_LINEAR_REC709, 6836 luminanceCoefficients: REC709_LUMINANCE_COEFFICIENTS, 6837 workingColorSpaceConfig: { unpackColorSpace: SRGBColorSpace }, 6838 outputColorSpaceConfig: { drawingBufferColorSpace: SRGBColorSpace } 6839 }, 6840 6841 [ SRGBColorSpace ]: { 6842 primaries: REC709_PRIMARIES, 6843 whitePoint: D65, 6844 transfer: SRGBTransfer, 6845 toXYZ: LINEAR_REC709_TO_XYZ, 6846 fromXYZ: XYZ_TO_LINEAR_REC709, 6847 luminanceCoefficients: REC709_LUMINANCE_COEFFICIENTS, 6848 outputColorSpaceConfig: { drawingBufferColorSpace: SRGBColorSpace } 6849 }, 6850 6851 } ); 6852 6853 return ColorManagement; 6854 6855} 6856 6857const ColorManagement = /*@__PURE__*/ createColorManagement(); 6858 6859function SRGBToLinear( c ) { 6860 6861 return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 ); 6862 6863} 6864 6865function LinearToSRGB( c ) { 6866 6867 return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055; 6868 6869} 6870 6871let _canvas; 6872 6873/** 6874 * A class containing utility functions for images. 6875 * 6876 * @hideconstructor 6877 */ 6878class ImageUtils { 6879 6880 /** 6881 * Returns a data URI containing a representation of the given image. 6882 * 6883 * @param {(HTMLImageElement|HTMLCanvasElement)} image - The image object. 6884 * @param {string} [type='image/png'] - Indicates the image format. 6885 * @return {string} The data URI. 6886 */ 6887 static getDataURL( image, type = 'image/png' ) { 6888 6889 if ( /^data:/i.test( image.src ) ) { 6890 6891 return image.src; 6892 6893 } 6894 6895 if ( typeof HTMLCanvasElement === 'undefined' ) { 6896 6897 return image.src; 6898 6899 } 6900 6901 let canvas; 6902 6903 if ( image instanceof HTMLCanvasElement ) { 6904 6905 canvas = image; 6906 6907 } else { 6908 6909 if ( _canvas === undefined ) _canvas = createElementNS( 'canvas' ); 6910 6911 _canvas.width = image.width; 6912 _canvas.height = image.height; 6913 6914 const context = _canvas.getContext( '2d' ); 6915 6916 if ( image instanceof ImageData ) { 6917 6918 context.putImageData( image, 0, 0 ); 6919 6920 } else { 6921 6922 context.drawImage( image, 0, 0, image.width, image.height ); 6923 6924 } 6925 6926 canvas = _canvas; 6927 6928 } 6929 6930 return canvas.toDataURL( type ); 6931 6932 } 6933 6934 /** 6935 * Converts the given sRGB image data to linear color space. 6936 * 6937 * @param {(HTMLImageElement|HTMLCanvasElement|ImageBitmap|Object)} image - The image object. 6938 * @return {HTMLCanvasElement|Object} The converted image. 6939 */ 6940 static sRGBToLinear( image ) { 6941 6942 if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || 6943 ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || 6944 ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { 6945 6946 const canvas = createElementNS( 'canvas' ); 6947 6948 canvas.width = image.width; 6949 canvas.height = image.height; 6950 6951 const context = canvas.getContext( '2d' ); 6952 context.drawImage( image, 0, 0, image.width, image.height ); 6953 6954 const imageData = context.getImageData( 0, 0, image.width, image.height ); 6955 const data = imageData.data; 6956 6957 for ( let i = 0; i < data.length; i ++ ) { 6958 6959 data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255; 6960 6961 } 6962 6963 context.putImageData( imageData, 0, 0 ); 6964 6965 return canvas; 6966 6967 } else if ( image.data ) { 6968 6969 const data = image.data.slice( 0 ); 6970 6971 for ( let i = 0; i < data.length; i ++ ) { 6972 6973 if ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) { 6974 6975 data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 ); 6976 6977 } else { 6978 6979 // assuming float 6980 6981 data[ i ] = SRGBToLinear( data[ i ] ); 6982 6983 } 6984 6985 } 6986 6987 return { 6988 data: data, 6989 width: image.width, 6990 height: image.height 6991 }; 6992 6993 } else { 6994 6995 warn( 'ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' ); 6996 return image; 6997 6998 } 6999 7000 } 7001 7002} 7003 7004let _sourceId = 0; 7005 7006/** 7007 * Represents the data source of a texture. 7008 * 7009 * The main purpose of this class is to decouple the data definition from the texture 7010 * definition so the same data can be used with multiple texture instances. 7011 */ 7012class Source { 7013 7014 /** 7015 * Constructs a new video texture. 7016 * 7017 * @param {any} [data=null] - The data definition of a texture. 7018 */ 7019 constructor( data = null ) { 7020 7021 /** 7022 * This flag can be used for type testing. 7023 * 7024 * @type {boolean} 7025 * @readonly 7026 * @default true 7027 */ 7028 this.isSource = true; 7029 7030 /** 7031 * The ID of the source. 7032 * 7033 * @name Source#id 7034 * @type {number} 7035 * @readonly 7036 */ 7037 Object.defineProperty( this, 'id', { value: _sourceId ++ } ); 7038 7039 /** 7040 * The UUID of the source. 7041 * 7042 * @type {string} 7043 * @readonly 7044 */ 7045 this.uuid = generateUUID(); 7046 7047 /** 7048 * The data definition of a texture. 7049 * 7050 * @type {any} 7051 */ 7052 this.data = data; 7053 7054 /** 7055 * This property is only relevant when {@link Source#needsUpdate} is set to `true` and 7056 * provides more control on how texture data should be processed. When `dataReady` is set 7057 * to `false`, the engine performs the memory allocation (if necessary) but does not transfer 7058 * the data into the GPU memory. 7059 * 7060 * @type {boolean} 7061 * @default true 7062 */ 7063 this.dataReady = true; 7064 7065 /** 7066 * This starts at `0` and counts how many times {@link Source#needsUpdate} is set to `true`. 7067 * 7068 * @type {number} 7069 * @readonly 7070 * @default 0 7071 */ 7072 this.version = 0; 7073 7074 } 7075 7076 /** 7077 * Returns the dimensions of the source into the given target vector. 7078 * 7079 * @param {(Vector2|Vector3)} target - The target object the result is written into. 7080 * @return {(Vector2|Vector3)} The dimensions of the source. 7081 */ 7082 getSize( target ) { 7083 7084 const data = this.data; 7085 7086 if ( ( typeof HTMLVideoElement !== 'undefined' ) && ( data instanceof HTMLVideoElement ) ) { 7087 7088 target.set( data.videoWidth, data.videoHeight, 0 ); 7089 7090 } else if ( ( typeof VideoFrame !== 'undefined' ) && ( data instanceof VideoFrame ) ) { 7091 7092 target.set( data.display
vendor: 2,595 bytes, lines 7092-7240
7092Width, data.displayHeight, 0 ); 7093 7094 } else if ( data !== null ) { 7095 7096 target.set( data.width, data.height, data.depth || 0 ); 7097 7098 } else { 7099 7100 target.set( 0, 0, 0 ); 7101 7102 } 7103 7104 return target; 7105 7106 } 7107 7108 /** 7109 * When the property is set to `true`, the engine allocates the memory 7110 * for the texture (if necessary) and triggers the actual texture upload 7111 * to the GPU next time the source is used. 7112 * 7113 * @type {boolean} 7114 * @default false 7115 * @param {boolean} value 7116 */ 7117 set needsUpdate( value ) { 7118 7119 if ( value === true ) this.version ++; 7120 7121 } 7122 7123 /** 7124 * Serializes the source into JSON. 7125 * 7126 * @param {?(Object|string)} meta - An optional value holding meta information about the serialization. 7127 * @return {Object} A JSON object representing the serialized source. 7128 * @see {@link ObjectLoader#parse} 7129 */ 7130 toJSON( meta ) { 7131 7132 const isRootObject = ( meta === undefined || typeof meta === 'string' ); 7133 7134 if ( ! isRootObject && meta.images[ this.uuid ] !== undefined ) { 7135 7136 return meta.images[ this.uuid ]; 7137 7138 } 7139 7140 const output = { 7141 uuid: this.uuid, 7142 url: '' 7143 }; 7144 7145 const data = this.data; 7146 7147 if ( data !== null ) { 7148 7149 let url; 7150 7151 if ( Array.isArray( data ) ) { 7152 7153 // cube texture 7154 7155 url = []; 7156 7157 for ( let i = 0, l = data.length; i < l; i ++ ) { 7158 7159 if ( data[ i ].isDataTexture ) { 7160 7161 url.push( serializeImage( data[ i ].image ) ); 7162 7163 } else { 7164 7165 url.push( serializeImage( data[ i ] ) ); 7166 7167 } 7168 7169 } 7170 7171 } else { 7172 7173 // texture 7174 7175 url = serializeImage( data ); 7176 7177 } 7178 7179 output.url = url; 7180 7181 } 7182 7183 if ( ! isRootObject ) { 7184 7185 meta.images[ this.uuid ] = output; 7186 7187 } 7188 7189 return output; 7190 7191 } 7192 7193} 7194 7195function serializeImage( image ) { 7196 7197 if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || 7198 ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || 7199 ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { 7200 7201 // default images 7202 7203 return ImageUtils.getDataURL( image ); 7204 7205 } else { 7206 7207 if ( image.data ) { 7208 7209 // images of DataTexture 7210 7211 return { 7212 data: Array.from( image.data ), 7213 width: image.width, 7214 height: image.height, 7215 type: image.data.constructor.name 7216 }; 7217 7218 } else { 7219 7220 warn( 'Texture: Unable to serialize Texture.' ); 7221 return {}; 7222 7223 } 7224 7225 } 7226 7227} 7228 7229let _textureId = 0; 7230 7231const _tempVec3 = /*@__PURE__*/ new Vector3(); 7232 7233/** 7234 * Base class for all textures. 7235 * 7236 * Note: After the initial use of a texture, its dimensions, format, and type 7237 * cannot be changed. Instead, call {@link Texture#dispose} on the texture and instantiate a new one. 7238 * 7239 * @augments EventDispatcher 7240 */
vendor: 6,879 bytes, lines 7241-7478
7241class Texture extends EventDispatcher { 7242 7243 /** 7244 * Constructs a new texture. 7245 * 7246 * @param {?Object} [image=Texture.DEFAULT_IMAGE] - The image holding the texture data. 7247 * @param {number} [mapping=Texture.DEFAULT_MAPPING] - The texture mapping. 7248 * @param {number} [wrapS=ClampToEdgeWrapping] - The wrapS value. 7249 * @param {number} [wrapT=ClampToEdgeWrapping] - The wrapT value. 7250 * @param {number} [magFilter=LinearFilter] - The mag filter value. 7251 * @param {number} [minFilter=LinearMipmapLinearFilter] - The min filter value. 7252 * @param {number} [format=RGBAFormat] - The texture format. 7253 * @param {number} [type=UnsignedByteType] - The texture type. 7254 * @param {number} [anisotropy=Texture.DEFAULT_ANISOTROPY] - The anisotropy value. 7255 * @param {string} [colorSpace=NoColorSpace] - The color space. 7256 */ 7257 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 ) { 7258 7259 super(); 7260 7261 /** 7262 * This flag can be used for type testing. 7263 * 7264 * @type {boolean} 7265 * @readonly 7266 * @default true 7267 */ 7268 this.isTexture = true; 7269 7270 /** 7271 * The ID of the texture. 7272 * 7273 * @name Texture#id 7274 * @type {number} 7275 * @readonly 7276 */ 7277 Object.defineProperty( this, 'id', { value: _textureId ++ } ); 7278 7279 /** 7280 * The UUID of the texture. 7281 * 7282 * @type {string} 7283 * @readonly 7284 */ 7285 this.uuid = generateUUID(); 7286 7287 /** 7288 * The name of the texture. 7289 * 7290 * @type {string} 7291 */ 7292 this.name = ''; 7293 7294 /** 7295 * The data definition of a texture. A reference to the data source can be 7296 * shared across textures. This is often useful in context of spritesheets 7297 * where multiple textures render the same data but with different texture 7298 * transformations. 7299 * 7300 * @type {Source} 7301 */ 7302 this.source = new Source( image ); 7303 7304 /** 7305 * An array holding user-defined mipmaps. 7306 * 7307 * @type {Array<Object>} 7308 */ 7309 this.mipmaps = []; 7310 7311 /** 7312 * How the texture is applied to the object. The value `UVMapping` 7313 * is the default, where texture or uv coordinates are used to apply the map. 7314 * 7315 * @type {(UVMapping|CubeReflectionMapping|CubeRefractionMapping|EquirectangularReflectionMapping|EquirectangularRefractionMapping|CubeUVReflectionMapping)} 7316 * @default UVMapping 7317 */ 7318 this.mapping = mapping; 7319 7320 /** 7321 * Lets you select the uv attribute to map the texture to. `0` for `uv`, 7322 * `1` for `uv1`, `2` for `uv2` and `3` for `uv3`. 7323 * 7324 * @type {number} 7325 * @default 0 7326 */ 7327 this.channel = 0; 7328 7329 /** 7330 * This defines how the texture is wrapped horizontally and corresponds to 7331 * *U* in UV mapping. 7332 * 7333 * @type {(RepeatWrapping|ClampToEdgeWrapping|MirroredRepeatWrapping)} 7334 * @default ClampToEdgeWrapping 7335 */ 7336 this.wrapS = wrapS; 7337 7338 /** 7339 * This defines how the texture is wrapped horizontally and corresponds to 7340 * *V* in UV mapping. 7341 * 7342 * @type {(RepeatWrapping|ClampToEdgeWrapping|MirroredRepeatWrapping)} 7343 * @default ClampToEdgeWrapping 7344 */ 7345 this.wrapT = wrapT; 7346 7347 /** 7348 * How the texture is sampled when a texel covers more than one pixel. 7349 * 7350 * @type {(NearestFilter|NearestMipmapNearestFilter|NearestMipmapLinearFilter|LinearFilter|LinearMipmapNearestFilter|LinearMipmapLinearFilter)} 7351 * @default LinearFilter 7352 */ 7353 this.magFilter = magFilter; 7354 7355 /** 7356 * How the texture is sampled when a texel covers less than one pixel. 7357 * 7358 * @type {(NearestFilter|NearestMipmapNearestFilter|NearestMipmapLinearFilter|LinearFilter|LinearMipmapNearestFilter|LinearMipmapLinearFilter)} 7359 * @default LinearMipmapLinearFilter 7360 */ 7361 this.minFilter = minFilter; 7362 7363 /** 7364 * The number of samples taken along the axis through the pixel that has the 7365 * highest density of texels. By default, this value is `1`. A higher value 7366 * gives a less blurry result than a basic mipmap, at the cost of more 7367 * texture samples being used. 7368 * 7369 * @type {number} 7370 * @default Texture.DEFAULT_ANISOTROPY 7371 */ 7372 this.anisotropy = anisotropy; 7373 7374 /** 7375 * The format of the texture. 7376 * 7377 * @type {number} 7378 * @default RGBAFormat 7379 */ 7380 this.format = format; 7381 7382 /** 7383 * The default internal format is derived from {@link Texture#format} and {@link Texture#type} and 7384 * defines how the texture data is going to be stored on the GPU. 7385 * 7386 * This property allows to overwrite the default format. 7387 * 7388 * @type {?string} 7389 * @default null 7390 */ 7391 this.internalFormat = null; 7392 7393 /** 7394 * The data type of the texture. 7395 * 7396 * @type {number} 7397 * @default UnsignedByteType 7398 */ 7399 this.type = type; 7400 7401 /** 7402 * How much a single repetition of the texture is offset from the beginning, 7403 * in each direction U and V. Typical range is `0.0` to `1.0`. 7404 * 7405 * @type {Vector2} 7406 * @default (0,0) 7407 */ 7408 this.offset = new Vector2( 0, 0 ); 7409 7410 /** 7411 * How many times the texture is repeated across the surface, in each 7412 * direction U and V. If repeat is set greater than `1` in either direction, 7413 * the corresponding wrap parameter should also be set to `RepeatWrapping` 7414 * or `MirroredRepeatWrapping` to achieve the desired tiling effect. 7415 * 7416 * @type {Vector2} 7417 * @default (1,1) 7418 */ 7419 this.repeat = new Vector2( 1, 1 ); 7420 7421 /** 7422 * The point around which rotation occurs. A value of `(0.5, 0.5)` corresponds 7423 * to the center of the texture. Default is `(0, 0)`, the lower left. 7424 * 7425 * @type {Vector2} 7426 * @default (0,0) 7427 */ 7428 this.center = new Vector2( 0, 0 ); 7429 7430 /** 7431 * How much the texture is rotated around the center point, in radians. 7432 * Positive values are counter-clockwise. 7433 * 7434 * @type {number} 7435 * @default 0 7436 */ 7437 this.rotation = 0; 7438 7439 /** 7440 * Whether to update the texture's uv-transformation {@link Texture#matrix} 7441 * from the properties {@link Texture#offset}, {@link Texture#repeat}, 7442 * {@link Texture#rotation}, and {@link Texture#center}. 7443 * 7444 * Set this to `false` if you are specifying the uv-transform matrix directly. 7445 * 7446 * @type {boolean} 7447 * @default true 7448 */ 7449 this.matrixAutoUpdate = true; 7450 7451 /** 7452 * The uv-transformation matrix of the texture. 7453 * 7454 * @type {Matrix3} 7455 */ 7456 this.matrix = new Matrix3(); 7457 7458 /** 7459 * Whether to generate mipmaps (if possible) for a texture. 7460 * 7461 * Set this to `false` if you are creating mipmaps manually. 7462 * 7463 * @type {boolean} 7464 * @default true 7465 */ 7466 this.generateMipmaps = true; 7467 7468 /** 7469 * If set to `true`, the alpha channel, if present, is multiplied into the 7470 * color channels when the texture is uploaded to the GPU. 7471 * 7472 * Note that this property has no effect when using `ImageBitmap`. You need to 7473 * configure premultiply alpha on bitmap creation instead. 7474 * 7475 * @type {boolean} 7476 * @default false 7477 */ 7478 this.premultiplyAlpha = false;
vendor: 15,080 bytes, lines 7479-8243
7479 7480 /** 7481 * If set to `true`, the texture is flipped along the vertical axis when 7482 * uploaded to the GPU. 7483 * 7484 * Note that this property has no effect when using `ImageBitmap`. You need to 7485 * configure the flip on bitmap creation instead. 7486 * 7487 * @type {boolean} 7488 * @default true 7489 */ 7490 this.flipY = true; 7491 7492 /** 7493 * Specifies the alignment requirements for the start of each pixel row in memory. 7494 * The allowable values are `1` (byte-alignment), `2` (rows aligned to even-numbered bytes), 7495 * `4` (word-alignment), and `8` (rows start on double-word boundaries). 7496 * 7497 * @type {number} 7498 * @default 4 7499 */ 7500 this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) 7501 7502 /** 7503 * Textures containing color data should be annotated with `SRGBColorSpace` or `LinearSRGBColorSpace`. 7504 * 7505 * @type {string} 7506 * @default NoColorSpace 7507 */ 7508 this.colorSpace = colorSpace; 7509 7510 /** 7511 * An object that can be used to store custom data about the texture. It 7512 * should not hold references to functions as these will not be cloned. 7513 * 7514 * @type {Object} 7515 */ 7516 this.userData = {}; 7517 7518 /** 7519 * This can be used to only update a subregion or specific rows of the texture (for example, just the 7520 * first 3 rows). Use the `addUpdateRange()` function to add ranges to this array. 7521 * 7522 * @type {Array<Object>} 7523 */ 7524 this.updateRanges = []; 7525 7526 /** 7527 * This starts at `0` and counts how many times {@link Texture#needsUpdate} is set to `true`. 7528 * 7529 * @type {number} 7530 * @readonly 7531 * @default 0 7532 */ 7533 this.version = 0; 7534 7535 /** 7536 * A callback function, called when the texture is updated (e.g., when 7537 * {@link Texture#needsUpdate} has been set to true and then the texture is used). 7538 * 7539 * @type {?Function} 7540 * @default null 7541 */ 7542 this.onUpdate = null; 7543 7544 /** 7545 * An optional back reference to the textures render target. 7546 * 7547 * @type {?(RenderTarget|WebGLRenderTarget)} 7548 * @default null 7549 */ 7550 this.renderTarget = null; 7551 7552 /** 7553 * Indicates whether a texture belongs to a render target or not. 7554 * 7555 * @type {boolean} 7556 * @readonly 7557 * @default false 7558 */ 7559 this.isRenderTargetTexture = false; 7560 7561 /** 7562 * Indicates if a texture should be handled like a texture array. 7563 * 7564 * @type {boolean} 7565 * @readonly 7566 * @default false 7567 */ 7568 this.isArrayTexture = image && image.depth && image.depth > 1 ? true : false; 7569 7570 /** 7571 * Indicates whether this texture should be processed by `PMREMGenerator` or not 7572 * (only relevant for render target textures). 7573 * 7574 * @type {number} 7575 * @readonly 7576 * @default 0 7577 */ 7578 this.pmremVersion = 0; 7579 7580 /** 7581 * Whether the texture should use one of the 16 bit integer formats which are normalized 7582 * to [0, 1] or [-1, 1] (depending on signed/unsigned) when sampled. 7583 * 7584 * @type {boolean} 7585 * @default false 7586 */ 7587 this.normalized = false; 7588 7589 } 7590 7591 /** 7592 * The width of the texture in pixels. 7593 */ 7594 get width() { 7595 7596 return this.source.getSize( _tempVec3 ).x; 7597 7598 } 7599 7600 /** 7601 * The height of the texture in pixels. 7602 */ 7603 get height() { 7604 7605 return this.source.getSize( _tempVec3 ).y; 7606 7607 } 7608 7609 /** 7610 * The depth of the texture in pixels. 7611 */ 7612 get depth() { 7613 7614 return this.source.getSize( _tempVec3 ).z; 7615 7616 } 7617 7618 /** 7619 * The image object holding the texture data. 7620 * 7621 * @type {?Object} 7622 */ 7623 get image() { 7624 7625 return this.source.data; 7626 7627 } 7628 7629 set image( value ) { 7630 7631 this.source.data = value; 7632 7633 } 7634 7635 /** 7636 * Updates the texture transformation matrix from the properties {@link Texture#offset}, 7637 * {@link Texture#repeat}, {@link Texture#rotation}, and {@link Texture#center}. 7638 */ 7639 updateMatrix() { 7640 7641 this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y ); 7642 7643 } 7644 7645 /** 7646 * Adds a range of data in the data texture to be updated on the GPU. 7647 * 7648 * @param {number} start - Position at which to start update. 7649 * @param {number} count - The number of components to update. 7650 */ 7651 addUpdateRange( start, count ) { 7652 7653 this.updateRanges.push( { start, count } ); 7654 7655 } 7656 7657 /** 7658 * Clears the update ranges. 7659 */ 7660 clearUpdateRanges() { 7661 7662 this.updateRanges.length = 0; 7663 7664 } 7665 7666 /** 7667 * Returns a new texture with copied values from this instance. 7668 * 7669 * @return {Texture} A clone of this instance. 7670 */ 7671 clone() { 7672 7673 return new this.constructor().copy( this ); 7674 7675 } 7676 7677 /** 7678 * Copies the values of the given texture to this instance. 7679 * 7680 * @param {Texture} source - The texture to copy. 7681 * @return {Texture} A reference to this instance. 7682 */ 7683 copy( source ) { 7684 7685 this.name = source.name; 7686 7687 this.source = source.source; 7688 this.mipmaps = source.mipmaps.slice( 0 ); 7689 7690 this.mapping = source.mapping; 7691 this.channel = source.channel; 7692 7693 this.wrapS = source.wrapS; 7694 this.wrapT = source.wrapT; 7695 7696 this.magFilter = source.magFilter; 7697 this.minFilter = source.minFilter; 7698 7699 this.anisotropy = source.anisotropy; 7700 7701 this.format = source.format; 7702 this.internalFormat = source.internalFormat; 7703 this.type = source.type; 7704 this.normalized = source.normalized; 7705 7706 this.offset.copy( source.offset ); 7707 this.repeat.copy( source.repeat ); 7708 this.center.copy( source.center ); 7709 this.rotation = source.rotation; 7710 7711 this.matrixAutoUpdate = source.matrixAutoUpdate; 7712 this.matrix.copy( source.matrix ); 7713 7714 this.generateMipmaps = source.generateMipmaps; 7715 this.premultiplyAlpha = source.premultiplyAlpha; 7716 this.flipY = source.flipY; 7717 this.unpackAlignment = source.unpackAlignment; 7718 this.colorSpace = source.colorSpace; 7719 7720 this.renderTarget = source.renderTarget; 7721 this.isRenderTargetTexture = source.isRenderTargetTexture; 7722 this.isArrayTexture = source.isArrayTexture; 7723 7724 this.userData = JSON.parse( JSON.stringify( source.userData ) ); 7725 7726 this.needsUpdate = true; 7727 7728 return this; 7729 7730 } 7731 7732 /** 7733 * Sets this texture's properties based on `values`. 7734 * @param {Object} values - A container with texture parameters. 7735 */ 7736 setValues( values ) { 7737 7738 for ( const key in values ) { 7739 7740 const newValue = values[ key ]; 7741 7742 if ( newValue === undefined ) { 7743 7744 warn( `Texture.setValues(): parameter '${ key }' has value of undefined.` ); 7745 continue; 7746 7747 } 7748 7749 const currentValue = this[ key ]; 7750 7751 if ( currentValue === undefined ) { 7752 7753 warn( `Texture.setValues(): property '${ key }' does not exist.` ); 7754 continue; 7755 7756 } 7757 7758 if ( ( currentValue && newValue ) && ( currentValue.isVector2 && newValue.isVector2 ) ) { 7759 7760 currentValue.copy( newValue ); 7761 7762 } else if ( ( currentValue && newValue ) && ( currentValue.isVector3 && newValue.isVector3 ) ) { 7763 7764 currentValue.copy( newValue ); 7765 7766 } else if ( ( currentValue && newValue ) && ( currentValue.isMatrix3 && newValue.isMatrix3 ) ) { 7767 7768 currentValue.copy( newValue ); 7769 7770 } else { 7771 7772 this[ key ] = newValue; 7773 7774 } 7775 7776 } 7777 7778 } 7779 7780 /** 7781 * Serializes the texture into JSON. 7782 * 7783 * @param {?(Object|string)} meta - An optional value holding meta information about the serialization. 7784 * @return {Object} A JSON object representing the serialized texture. 7785 * @see {@link ObjectLoader#parse} 7786 */ 7787 toJSON( meta ) { 7788 7789 const isRootObject = ( meta === undefined || typeof meta === 'string' ); 7790 7791 if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) { 7792 7793 return meta.textures[ this.uuid ]; 7794 7795 } 7796 7797 const output = { 7798 7799 metadata: { 7800 version: 4.7, 7801 type: 'Texture', 7802 generator: 'Texture.toJSON' 7803 }, 7804 7805 uuid: this.uuid, 7806 name: this.name, 7807 7808 image: this.source.toJSON( meta ).uuid, 7809 7810 mapping: this.mapping, 7811 channel: this.channel, 7812 7813 repeat: [ this.repeat.x, this.repeat.y ], 7814 offset: [ this.offset.x, this.offset.y ], 7815 center: [ this.center.x, this.center.y ], 7816 rotation: this.rotation, 7817 7818 wrap: [ this.wrapS, this.wrapT ], 7819 7820 format: this.format, 7821 internalFormat: this.internalFormat, 7822 type: this.type, 7823 normalized: this.normalized, 7824 colorSpace: this.colorSpace, 7825 7826 minFilter: this.minFilter, 7827 magFilter: this.magFilter, 7828 anisotropy: this.anisotropy, 7829 7830 flipY: this.flipY, 7831 7832 generateMipmaps: this.generateMipmaps, 7833 premultiplyAlpha: this.premultiplyAlpha, 7834 unpackAlignment: this.unpackAlignment 7835 7836 }; 7837 7838 if ( Object.keys( this.userData ).length > 0 ) output.userData = this.userData; 7839 7840 if ( ! isRootObject ) { 7841 7842 meta.textures[ this.uuid ] = output; 7843 7844 } 7845 7846 return output; 7847 7848 } 7849 7850 /** 7851 * Frees the GPU-related resources allocated by this instance. Call this 7852 * method whenever this instance is no longer used in your app. 7853 * 7854 * @fires Texture#dispose 7855 */ 7856 dispose() { 7857 7858 /** 7859 * Fires when the texture has been disposed of. 7860 * 7861 * @event Texture#dispose 7862 * @type {Object} 7863 */ 7864 this.dispatchEvent( { type: 'dispose' } ); 7865 7866 } 7867 7868 /** 7869 * Transforms the given uv vector with the textures uv transformation matrix. 7870 * 7871 * @param {Vector2} uv - The uv vector. 7872 * @return {Vector2} The transformed uv vector. 7873 */ 7874 transformUv( uv ) { 7875 7876 if ( this.mapping !== UVMapping ) return uv; 7877 7878 uv.applyMatrix3( this.matrix ); 7879 7880 if ( uv.x < 0 || uv.x > 1 ) { 7881 7882 switch ( this.wrapS ) { 7883 7884 case RepeatWrapping: 7885 7886 uv.x = uv.x - Math.floor( uv.x ); 7887 break; 7888 7889 case ClampToEdgeWrapping: 7890 7891 uv.x = uv.x < 0 ? 0 : 1; 7892 break; 7893 7894 case MirroredRepeatWrapping: 7895 7896 if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { 7897 7898 uv.x = Math.ceil( uv.x ) - uv.x; 7899 7900 } else { 7901 7902 uv.x = uv.x - Math.floor( uv.x ); 7903 7904 } 7905 7906 break; 7907 7908 } 7909 7910 } 7911 7912 if ( uv.y < 0 || uv.y > 1 ) { 7913 7914 switch ( this.wrapT ) { 7915 7916 case RepeatWrapping: 7917 7918 uv.y = uv.y - Math.floor( uv.y ); 7919 break; 7920 7921 case ClampToEdgeWrapping: 7922 7923 uv.y = uv.y < 0 ? 0 : 1; 7924 break; 7925 7926 case MirroredRepeatWrapping: 7927 7928 if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { 7929 7930 uv.y = Math.ceil( uv.y ) - uv.y; 7931 7932 } else { 7933 7934 uv.y = uv.y - Math.floor( uv.y ); 7935 7936 } 7937 7938 break; 7939 7940 } 7941 7942 } 7943 7944 if ( this.flipY ) { 7945 7946 uv.y = 1 - uv.y; 7947 7948 } 7949 7950 return uv; 7951 7952 } 7953 7954 /** 7955 * Setting this property to `true` indicates the engine the texture 7956 * must be updated in the next render. This triggers a texture upload 7957 * to the GPU and ensures correct texture parameter configuration. 7958 * 7959 * @type {boolean} 7960 * @default false 7961 * @param {boolean} value 7962 */ 7963 set needsUpdate( value ) { 7964 7965 if ( value === true ) { 7966 7967 this.version ++; 7968 this.source.needsUpdate = true; 7969 7970 } 7971 7972 } 7973 7974 /** 7975 * Setting this property to `true` indicates the engine the PMREM 7976 * must be regenerated. 7977 * 7978 * @type {boolean} 7979 * @default false 7980 * @param {boolean} value 7981 */ 7982 set needsPMREMUpdate( value ) { 7983 7984 if ( value === true ) { 7985 7986 this.pmremVersion ++; 7987 7988 } 7989 7990 } 7991 7992} 7993 7994/** 7995 * The default image for all textures. 7996 * 7997 * @static 7998 * @type {?Image} 7999 * @default null 8000 */ 8001Texture.DEFAULT_IMAGE = null; 8002 8003/** 8004 * The default mapping for all textures. 8005 * 8006 * @static 8007 * @type {number} 8008 * @default UVMapping 8009 */ 8010Texture.DEFAULT_MAPPING = UVMapping; 8011 8012/** 8013 * The default anisotropy value for all textures. 8014 * 8015 * @static 8016 * @type {number} 8017 * @default 1 8018 */ 8019Texture.DEFAULT_ANISOTROPY = 1; 8020 8021/** 8022 * Class representing a 4D vector. A 4D vector is an ordered quadruplet of numbers 8023 * (labeled x, y, z and w), which can be used to represent a number of things, such as: 8024 * 8025 * - A point in 4D space. 8026 * - A direction and length in 4D space. In three.js the length will 8027 * always be the Euclidean distance(straight-line distance) from `(0, 0, 0, 0)` to `(x, y, z, w)` 8028 * and the direction is also measured from `(0, 0, 0, 0)` towards `(x, y, z, w)`. 8029 * - Any arbitrary ordered quadruplet of numbers. 8030 * 8031 * There are other things a 4D vector can be used to represent, however these 8032 * are the most common uses in *three.js*. 8033 * 8034 * Iterating through a vector instance will yield its components `(x, y, z, w)` in 8035 * the corresponding order. 8036 * ```js 8037 * const a = new THREE.Vector4( 0, 1, 0, 0 ); 8038 * 8039 * //no arguments; will be initialised to (0, 0, 0, 1) 8040 * const b = new THREE.Vector4( ); 8041 * 8042 * const d = a.dot( b ); 8043 * ``` 8044 */ 8045class Vector4 { 8046 8047 static { 8048 8049 /** 8050 * This flag can be used for type testing. 8051 * 8052 * @type {boolean} 8053 * @readonly 8054 * @default true 8055 */ 8056 Vector4.prototype.isVector4 = true; 8057 8058 } 8059 8060 /** 8061 * Constructs a new 4D vector. 8062 * 8063 * @param {number} [x=0] - The x value of this vector. 8064 * @param {number} [y=0] - The y value of this vector. 8065 * @param {number} [z=0] - The z value of this vector. 8066 * @param {number} [w=1] - The w value of this vector. 8067 */ 8068 constructor( x = 0, y = 0, z = 0, w = 1 ) { 8069 8070 /** 8071 * The x value of this vector. 8072 * 8073 * @type {number} 8074 */ 8075 this.x = x; 8076 8077 /** 8078 * The y value of this vector. 8079 * 8080 * @type {number} 8081 */ 8082 this.y = y; 8083 8084 /** 8085 * The z value of this vector. 8086 * 8087 * @type {number} 8088 */ 8089 this.z = z; 8090 8091 /** 8092 * The w value of this vector. 8093 * 8094 * @type {number} 8095 */ 8096 this.w = w; 8097 8098 } 8099 8100 /** 8101 * Alias for {@link Vector4#z}. 8102 * 8103 * @type {number} 8104 */ 8105 get width() { 8106 8107 return this.z; 8108 8109 } 8110 8111 set width( value ) { 8112 8113 this.z = value; 8114 8115 } 8116 8117 /** 8118 * Alias for {@link Vector4#w}. 8119 * 8120 * @type {number} 8121 */ 8122 get height() { 8123 8124 return this.w; 8125 8126 } 8127 8128 set height( value ) { 8129 8130 this.w = value; 8131 8132 } 8133 8134 /** 8135 * Sets the vector components. 8136 * 8137 * @param {number} x - The value of the x component. 8138 * @param {number} y - The value of the y component. 8139 * @param {number} z - The value of the z component. 8140 * @param {number} w - The value of the w component. 8141 * @return {Vector4} A reference to this vector. 8142 */ 8143 set( x, y, z, w ) { 8144 8145 this.x = x; 8146 this.y = y; 8147 this.z = z; 8148 this.w = w; 8149 8150 return this; 8151 8152 } 8153 8154 /** 8155 * Sets the vector components to the same value. 8156 * 8157 * @param {number} scalar - The value to set for all vector components. 8158 * @return {Vector4} A reference to this vector. 8159 */ 8160 setScalar( scalar ) { 8161 8162 this.x = scalar; 8163 this.y = scalar; 8164 this.z = scalar; 8165 this.w = scalar; 8166 8167 return this; 8168 8169 } 8170 8171 /** 8172 * Sets the vector's x component to the given value 8173 * 8174 * @param {number} x - The value to set. 8175 * @return {Vector4} A reference to this vector. 8176 */ 8177 setX( x ) { 8178 8179 this.x = x; 8180 8181 return this; 8182 8183 } 8184 8185 /** 8186 * Sets the vector's y component to the given value 8187 * 8188 * @param {number} y - The value to set. 8189 * @return {Vector4} A reference to this vector. 8190 */ 8191 setY( y ) { 8192 8193 this.y = y; 8194 8195 return this; 8196 8197 } 8198 8199 /** 8200 * Sets the vector's z component to the given value 8201 * 8202 * @param {number} z - The value to set. 8203 * @return {Vector4} A reference to this vector. 8204 */ 8205 setZ( z ) { 8206 8207 this.z = z; 8208 8209 return this; 8210 8211 } 8212 8213 /** 8214 * Sets the vector's w component to the given value 8215 * 8216 * @param {number} w - The value to set. 8217 * @return {Vector4} A reference to this vector. 8218 */ 8219 setW( w ) { 8220 8221 this.w = w; 8222 8223 return this; 8224 8225 } 8226 8227 /** 8228 * Allows to set a vector component with an index. 8229 * 8230 * @param {number} index - The component index. `0` equals to x, `1` equals to y, 8231 * `2` equals to z, `3` equals to w. 8232 * @param {number} value - The value to set. 8233 * @return {Vector4} A reference to this vector. 8234 */ 8235 setComponent( index, value ) { 8236 8237 switch ( index ) { 8238 8239 case 0: this.x = value; break; 8240 case 1: this.y = value; break; 8241 case 2: this.z = value; break; 8242 case 3: this.w = value; break; 8243 default: throw new Error( '
vendor: 10,358 bytes, lines 8243-8747
8243index is out of range: ' + index ); 8244 8245 } 8246 8247 return this; 8248 8249 } 8250 8251 /** 8252 * Returns the value of the vector component which matches the given index. 8253 * 8254 * @param {number} index - The component index. `0` equals to x, `1` equals to y, 8255 * `2` equals to z, `3` equals to w. 8256 * @return {number} A vector component value. 8257 */ 8258 getComponent( index ) { 8259 8260 switch ( index ) { 8261 8262 case 0: return this.x; 8263 case 1: return this.y; 8264 case 2: return this.z; 8265 case 3: return this.w; 8266 default: throw new Error( 'index is out of range: ' + index ); 8267 8268 } 8269 8270 } 8271 8272 /** 8273 * Returns a new vector with copied values from this instance. 8274 * 8275 * @return {Vector4} A clone of this instance. 8276 */ 8277 clone() { 8278 8279 return new this.constructor( this.x, this.y, this.z, this.w ); 8280 8281 } 8282 8283 /** 8284 * Copies the values of the given vector to this instance. 8285 * 8286 * @param {Vector3|Vector4} v - The vector to copy. 8287 * @return {Vector4} A reference to this vector. 8288 */ 8289 copy( v ) { 8290 8291 this.x = v.x; 8292 this.y = v.y; 8293 this.z = v.z; 8294 this.w = ( v.w !== undefined ) ? v.w : 1; 8295 8296 return this; 8297 8298 } 8299 8300 /** 8301 * Adds the given vector to this instance. 8302 * 8303 * @param {Vector4} v - The vector to add. 8304 * @return {Vector4} A reference to this vector. 8305 */ 8306 add( v ) { 8307 8308 this.x += v.x; 8309 this.y += v.y; 8310 this.z += v.z; 8311 this.w += v.w; 8312 8313 return this; 8314 8315 } 8316 8317 /** 8318 * Adds the given scalar value to all components of this instance. 8319 * 8320 * @param {number} s - The scalar to add. 8321 * @return {Vector4} A reference to this vector. 8322 */ 8323 addScalar( s ) { 8324 8325 this.x += s; 8326 this.y += s; 8327 this.z += s; 8328 this.w += s; 8329 8330 return this; 8331 8332 } 8333 8334 /** 8335 * Adds the given vectors and stores the result in this instance. 8336 * 8337 * @param {Vector4} a - The first vector. 8338 * @param {Vector4} b - The second vector. 8339 * @return {Vector4} A reference to this vector. 8340 */ 8341 addVectors( a, b ) { 8342 8343 this.x = a.x + b.x; 8344 this.y = a.y + b.y; 8345 this.z = a.z + b.z; 8346 this.w = a.w + b.w; 8347 8348 return this; 8349 8350 } 8351 8352 /** 8353 * Adds the given vector scaled by the given factor to this instance. 8354 * 8355 * @param {Vector4} v - The vector. 8356 * @param {number} s - The factor that scales `v`. 8357 * @return {Vector4} A reference to this vector. 8358 */ 8359 addScaledVector( v, s ) { 8360 8361 this.x += v.x * s; 8362 this.y += v.y * s; 8363 this.z += v.z * s; 8364 this.w += v.w * s; 8365 8366 return this; 8367 8368 } 8369 8370 /** 8371 * Subtracts the given vector from this instance. 8372 * 8373 * @param {Vector4} v - The vector to subtract. 8374 * @return {Vector4} A reference to this vector. 8375 */ 8376 sub( v ) { 8377 8378 this.x -= v.x; 8379 this.y -= v.y; 8380 this.z -= v.z; 8381 this.w -= v.w; 8382 8383 return this; 8384 8385 } 8386 8387 /** 8388 * Subtracts the given scalar value from all components of this instance. 8389 * 8390 * @param {number} s - The scalar to subtract. 8391 * @return {Vector4} A reference to this vector. 8392 */ 8393 subScalar( s ) { 8394 8395 this.x -= s; 8396 this.y -= s; 8397 this.z -= s; 8398 this.w -= s; 8399 8400 return this; 8401 8402 } 8403 8404 /** 8405 * Subtracts the given vectors and stores the result in this instance. 8406 * 8407 * @param {Vector4} a - The first vector. 8408 * @param {Vector4} b - The second vector. 8409 * @return {Vector4} A reference to this vector. 8410 */ 8411 subVectors( a, b ) { 8412 8413 this.x = a.x - b.x; 8414 this.y = a.y - b.y; 8415 this.z = a.z - b.z; 8416 this.w = a.w - b.w; 8417 8418 return this; 8419 8420 } 8421 8422 /** 8423 * Multiplies the given vector with this instance. 8424 * 8425 * @param {Vector4} v - The vector to multiply. 8426 * @return {Vector4} A reference to this vector. 8427 */ 8428 multiply( v ) { 8429 8430 this.x *= v.x; 8431 this.y *= v.y; 8432 this.z *= v.z; 8433 this.w *= v.w; 8434 8435 return this; 8436 8437 } 8438 8439 /** 8440 * Multiplies the given scalar value with all components of this instance. 8441 * 8442 * @param {number} scalar - The scalar to multiply. 8443 * @return {Vector4} A reference to this vector. 8444 */ 8445 multiplyScalar( scalar ) { 8446 8447 this.x *= scalar; 8448 this.y *= scalar; 8449 this.z *= scalar; 8450 this.w *= scalar; 8451 8452 return this; 8453 8454 } 8455 8456 /** 8457 * Multiplies this vector with the given 4x4 matrix. 8458 * 8459 * @param {Matrix4} m - The 4x4 matrix. 8460 * @return {Vector4} A reference to this vector. 8461 */ 8462 applyMatrix4( m ) { 8463 8464 const x = this.x, y = this.y, z = this.z, w = this.w; 8465 const e = m.elements; 8466 8467 this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w; 8468 this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w; 8469 this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w; 8470 this.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w; 8471 8472 return this; 8473 8474 } 8475 8476 /** 8477 * Divides this instance by the given vector. 8478 * 8479 * @param {Vector4} v - The vector to divide. 8480 * @return {Vector4} A reference to this vector. 8481 */ 8482 divide( v ) { 8483 8484 this.x /= v.x; 8485 this.y /= v.y; 8486 this.z /= v.z; 8487 this.w /= v.w; 8488 8489 return this; 8490 8491 } 8492 8493 /** 8494 * Divides this vector by the given scalar. 8495 * 8496 * @param {number} scalar - The scalar to divide. 8497 * @return {Vector4} A reference to this vector. 8498 */ 8499 divideScalar( scalar ) { 8500 8501 return this.multiplyScalar( 1 / scalar ); 8502 8503 } 8504 8505 /** 8506 * Sets the x, y and z components of this 8507 * vector to the quaternion's axis and w to the angle. 8508 * 8509 * @param {Quaternion} q - The Quaternion to set. 8510 * @return {Vector4} A reference to this vector. 8511 */ 8512 setAxisAngleFromQuaternion( q ) { 8513 8514 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm 8515 8516 // q is assumed to be normalized 8517 8518 this.w = 2 * Math.acos( q.w ); 8519 8520 const s = Math.sqrt( 1 - q.w * q.w ); 8521 8522 if ( s < 0.0001 ) { 8523 8524 this.x = 1; 8525 this.y = 0; 8526 this.z = 0; 8527 8528 } else { 8529 8530 this.x = q.x / s; 8531 this.y = q.y / s; 8532 this.z = q.z / s; 8533 8534 } 8535 8536 return this; 8537 8538 } 8539 8540 /** 8541 * Sets the x, y and z components of this 8542 * vector to the axis of rotation and w to the angle. 8543 * 8544 * @param {Matrix4} m - A 4x4 matrix of which the upper left 3x3 matrix is a pure rotation matrix. 8545 * @return {Vector4} A reference to this vector. 8546 */ 8547 setAxisAngleFromRotationMatrix( m ) { 8548 8549 // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm 8550 8551 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 8552 8553 let angle, x, y, z; // variables for result 8554 const epsilon = 0.01, // margin to allow for rounding errors 8555 epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees 8556 8557 te = m.elements, 8558 8559 m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], 8560 m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], 8561 m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; 8562 8563 if ( ( Math.abs( m12 - m21 ) < epsilon ) && 8564 ( Math.abs( m13 - m31 ) < epsilon ) && 8565 ( Math.abs( m23 - m32 ) < epsilon ) ) { 8566 8567 // singularity found 8568 // first check for identity matrix which must have +1 for all terms 8569 // in leading diagonal and zero in other terms 8570 8571 if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && 8572 ( Math.abs( m13 + m31 ) < epsilon2 ) && 8573 ( Math.abs( m23 + m32 ) < epsilon2 ) && 8574 ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { 8575 8576 // this singularity is identity matrix so angle = 0 8577 8578 this.set( 1, 0, 0, 0 ); 8579 8580 return this; // zero angle, arbitrary axis 8581 8582 } 8583 8584 // otherwise this singularity is angle = 180 8585 8586 angle = Math.PI; 8587 8588 const xx = ( m11 + 1 ) / 2; 8589 const yy = ( m22 + 1 ) / 2; 8590 const zz = ( m33 + 1 ) / 2; 8591 const xy = ( m12 + m21 ) / 4; 8592 const xz = ( m13 + m31 ) / 4; 8593 const yz = ( m23 + m32 ) / 4; 8594 8595 if ( ( xx > yy ) && ( xx > zz ) ) { 8596 8597 // m11 is the largest diagonal term 8598 8599 if ( xx < epsilon ) { 8600 8601 x = 0; 8602 y = 0.707106781; 8603 z = 0.707106781; 8604 8605 } else { 8606 8607 x = Math.sqrt( xx ); 8608 y = xy / x; 8609 z = xz / x; 8610 8611 } 8612 8613 } else if ( yy > zz ) { 8614 8615 // m22 is the largest diagonal term 8616 8617 if ( yy < epsilon ) { 8618 8619 x = 0.707106781; 8620 y = 0; 8621 z = 0.707106781; 8622 8623 } else { 8624 8625 y = Math.sqrt( yy ); 8626 x = xy / y; 8627 z = yz / y; 8628 8629 } 8630 8631 } else { 8632 8633 // m33 is the largest diagonal term so base result on this 8634 8635 if ( zz < epsilon ) { 8636 8637 x = 0.707106781; 8638 y = 0.707106781; 8639 z = 0; 8640 8641 } else { 8642 8643 z = Math.sqrt( zz ); 8644 x = xz / z; 8645 y = yz / z; 8646 8647 } 8648 8649 } 8650 8651 this.set( x, y, z, angle ); 8652 8653 return this; // return 180 deg rotation 8654 8655 } 8656 8657 // as we have reached here there are no singularities so we can handle normally 8658 8659 let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + 8660 ( m13 - m31 ) * ( m13 - m31 ) + 8661 ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize 8662 8663 if ( Math.abs( s ) < 0.001 ) s = 1; 8664 8665 // prevent divide by zero, should not happen if matrix is orthogonal and should be 8666 // caught by singularity test above, but I've left it in just in case 8667 8668 this.x = ( m32 - m23 ) / s; 8669 this.y = ( m13 - m31 ) / s; 8670 this.z = ( m21 - m12 ) / s; 8671 this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); 8672 8673 return this; 8674 8675 } 8676 8677 /** 8678 * Sets the vector components to the position elements of the 8679 * given transformation matrix. 8680 * 8681 * @param {Matrix4} m - The 4x4 matrix. 8682 * @return {Vector4} A reference to this vector. 8683 */ 8684 setFromMatrixPosition( m ) { 8685 8686 const e = m.elements; 8687 8688 this.x = e[ 12 ]; 8689 this.y = e[ 13 ]; 8690 this.z = e[ 14 ]; 8691 this.w = e[ 15 ]; 8692 8693 return this; 8694 8695 } 8696 8697 /** 8698 * If this vector's x, y, z or w value is greater than the given vector's x, y, z or w 8699 * value, replace that value with the corresponding min value. 8700 * 8701 * @param {Vector4} v - The vector. 8702 * @return {Vector4} A reference to this vector. 8703 */ 8704 min( v ) { 8705 8706 this.x = Math.min( this.x, v.x ); 8707 this.y = Math.min( this.y, v.y ); 8708 this.z = Math.min( this.z, v.z ); 8709 this.w = Math.min( this.w, v.w ); 8710 8711 return this; 8712 8713 } 8714 8715 /** 8716 * If this vector's x, y, z or w value is less than the given vector's x, y, z or w 8717 * value, replace that value with the corresponding max value. 8718 * 8719 * @param {Vector4} v - The vector. 8720 * @return {Vector4} A reference to this vector. 8721 */ 8722 max( v ) { 8723 8724 this.x = Math.max( this.x, v.x ); 8725 this.y = Math.max( this.y, v.y ); 8726 this.z = Math.max( this.z, v.z ); 8727 this.w = Math.max( this.w, v.w ); 8728 8729 return this; 8730 8731 } 8732 8733 /** 8734 * If this vector's x, y, z or w value is greater than the max vector's x, y, z or w 8735 * value, it is replaced by the corresponding value. 8736 * If this vector's x, y, z or w value is less than the min vector's x, y, z or w value, 8737 * it is replaced by the corresponding value. 8738 * 8739 * @param {Vector4} min - The minimum x, y and z values. 8740 * @param {Vector4} max - The maximum x, y and z values in the desired range. 8741 * @return {Vector4} A reference to this vector. 8742 */ 8743 clamp( min, max ) { 8744 8745 // assumes min < max, componentwise 8746 8747 this.x = clamp
8747( this.x, min.x, max.x ); 8748 this.y = clamp( this.y, min.y, max.y ); 8749 this.z = clamp( this.z, min.z, max.z ); 8750 this.w = clamp( this.w, min.w, max.w ); 8751 8752 return this; 8753 8754 } 8755 8756 /** 8757 * If this vector's x, y, z or w values are greater than the max value, they are 8758 * replaced by the max value. 8759 * If this vector's x, y, z or w values are less than the min value, they are 8760 * replaced by the min value. 8761 * 8762 * @param {number} minVal - The minimum value the components will be clamped to. 8763 * @param {number} maxVal - The maximum value the components will be clamped to. 8764 * @return {Vector4} A reference to this vector. 8765 */ 8766 clampScalar( minVal, maxVal ) { 8767 8768 this.x = clamp( this.x, minVal, maxVal ); 8769 this.y = clamp( this.y, minVal, maxVal ); 8770 this.z = clamp( this.z, minVal, maxVal ); 8771 this.w = clamp( this.w, minVal, maxVal ); 8772 8773 return this; 8774 8775 } 8776 8777 /** 8778 * If this vector's length is greater than the max value, it is replaced by 8779 * the max value. 8780 * If this vector's length is less than the min value, it is replaced by the 8781 * min value. 8782 * 8783 * @param {number} min - The minimum value the vector length will be clamped to. 8784 * @param {number} max - The maximum value the vector length will be clamped to. 8785 * @return {Vector4} A reference to this vector. 8786 */ 8787 clampLength( min, max ) { 8788 8789 const length = this.length(); 8790 8791 return this.divideScalar( length || 1 ).multiplyScalar( clamp
vendor: 16,862 bytes, lines 8791-9449
8791( length, min, max ) ); 8792 8793 } 8794 8795 /** 8796 * The components of this vector are rounded down to the nearest integer value. 8797 * 8798 * @return {Vector4} A reference to this vector. 8799 */ 8800 floor() { 8801 8802 this.x = Math.floor( this.x ); 8803 this.y = Math.floor( this.y ); 8804 this.z = Math.floor( this.z ); 8805 this.w = Math.floor( this.w ); 8806 8807 return this; 8808 8809 } 8810 8811 /** 8812 * The components of this vector are rounded up to the nearest integer value. 8813 * 8814 * @return {Vector4} A reference to this vector. 8815 */ 8816 ceil() { 8817 8818 this.x = Math.ceil( this.x ); 8819 this.y = Math.ceil( this.y ); 8820 this.z = Math.ceil( this.z ); 8821 this.w = Math.ceil( this.w ); 8822 8823 return this; 8824 8825 } 8826 8827 /** 8828 * The components of this vector are rounded to the nearest integer value 8829 * 8830 * @return {Vector4} A reference to this vector. 8831 */ 8832 round() { 8833 8834 this.x = Math.round( this.x ); 8835 this.y = Math.round( this.y ); 8836 this.z = Math.round( this.z ); 8837 this.w = Math.round( this.w ); 8838 8839 return this; 8840 8841 } 8842 8843 /** 8844 * The components of this vector are rounded towards zero (up if negative, 8845 * down if positive) to an integer value. 8846 * 8847 * @return {Vector4} A reference to this vector. 8848 */ 8849 roundToZero() { 8850 8851 this.x = Math.trunc( this.x ); 8852 this.y = Math.trunc( this.y ); 8853 this.z = Math.trunc( this.z ); 8854 this.w = Math.trunc( this.w ); 8855 8856 return this; 8857 8858 } 8859 8860 /** 8861 * Inverts this vector - i.e. sets x = -x, y = -y, z = -z, w = -w. 8862 * 8863 * @return {Vector4} A reference to this vector. 8864 */ 8865 negate() { 8866 8867 this.x = - this.x; 8868 this.y = - this.y; 8869 this.z = - this.z; 8870 this.w = - this.w; 8871 8872 return this; 8873 8874 } 8875 8876 /** 8877 * Calculates the dot product of the given vector with this instance. 8878 * 8879 * @param {Vector4} v - The vector to compute the dot product with. 8880 * @return {number} The result of the dot product. 8881 */ 8882 dot( v ) { 8883 8884 return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; 8885 8886 } 8887 8888 /** 8889 * Computes the square of the Euclidean length (straight-line length) from 8890 * (0, 0, 0, 0) to (x, y, z, w). If you are comparing the lengths of vectors, you should 8891 * compare the length squared instead as it is slightly more efficient to calculate. 8892 * 8893 * @return {number} The square length of this vector. 8894 */ 8895 lengthSq() { 8896 8897 return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; 8898 8899 } 8900 8901 /** 8902 * Computes the Euclidean length (straight-line length) from (0, 0, 0, 0) to (x, y, z, w). 8903 * 8904 * @return {number} The length of this vector. 8905 */ 8906 length() { 8907 8908 return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); 8909 8910 } 8911 8912 /** 8913 * Computes the Manhattan length of this vector. 8914 * 8915 * @return {number} The length of this vector. 8916 */ 8917 manhattanLength() { 8918 8919 return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); 8920 8921 } 8922 8923 /** 8924 * Converts this vector to a unit vector - that is, sets it equal to a vector 8925 * with the same direction as this one, but with a vector length of `1`. 8926 * 8927 * @return {Vector4} A reference to this vector. 8928 */ 8929 normalize() { 8930 8931 return this.divideScalar( this.length() || 1 ); 8932 8933 } 8934 8935 /** 8936 * Sets this vector to a vector with the same direction as this one, but 8937 * with the specified length. 8938 * 8939 * @param {number} length - The new length of this vector. 8940 * @return {Vector4} A reference to this vector. 8941 */ 8942 setLength( length ) { 8943 8944 return this.normalize().multiplyScalar( length ); 8945 8946 } 8947 8948 /** 8949 * Linearly interpolates between the given vector and this instance, where 8950 * alpha is the percent distance along the line - alpha = 0 will be this 8951 * vector, and alpha = 1 will be the given one. 8952 * 8953 * @param {Vector4} v - The vector to interpolate towards. 8954 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. 8955 * @return {Vector4} A reference to this vector. 8956 */ 8957 lerp( v, alpha ) { 8958 8959 this.x += ( v.x - this.x ) * alpha; 8960 this.y += ( v.y - this.y ) * alpha; 8961 this.z += ( v.z - this.z ) * alpha; 8962 this.w += ( v.w - this.w ) * alpha; 8963 8964 return this; 8965 8966 } 8967 8968 /** 8969 * Linearly interpolates between the given vectors, where alpha is the percent 8970 * distance along the line - alpha = 0 will be first vector, and alpha = 1 will 8971 * be the second one. The result is stored in this instance. 8972 * 8973 * @param {Vector4} v1 - The first vector. 8974 * @param {Vector4} v2 - The second vector. 8975 * @param {number} alpha - The interpolation factor, typically in the closed interval `[0, 1]`. 8976 * @return {Vector4} A reference to this vector. 8977 */ 8978 lerpVectors( v1, v2, alpha ) { 8979 8980 this.x = v1.x + ( v2.x - v1.x ) * alpha; 8981 this.y = v1.y + ( v2.y - v1.y ) * alpha; 8982 this.z = v1.z + ( v2.z - v1.z ) * alpha; 8983 this.w = v1.w + ( v2.w - v1.w ) * alpha; 8984 8985 return this; 8986 8987 } 8988 8989 /** 8990 * Returns `true` if this vector is equal with the given one. 8991 * 8992 * @param {Vector4} v - The vector to test for equality. 8993 * @return {boolean} Whether this vector is equal with the given one. 8994 */ 8995 equals( v ) { 8996 8997 return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); 8998 8999 } 9000 9001 /** 9002 * Sets this vector's x value to be `array[ offset ]`, y value to be `array[ offset + 1 ]`, 9003 * z value to be `array[ offset + 2 ]`, w value to be `array[ offset + 3 ]`. 9004 * 9005 * @param {Array<number>} array - An array holding the vector component values. 9006 * @param {number} [offset=0] - The offset into the array. 9007 * @return {Vector4} A reference to this vector. 9008 */ 9009 fromArray( array, offset = 0 ) { 9010 9011 this.x = array[ offset ]; 9012 this.y = array[ offset + 1 ]; 9013 this.z = array[ offset + 2 ]; 9014 this.w = array[ offset + 3 ]; 9015 9016 return this; 9017 9018 } 9019 9020 /** 9021 * Writes the components of this vector to the given array. If no array is provided, 9022 * the method returns a new instance. 9023 * 9024 * @param {Array<number>} [array=[]] - The target array holding the vector components. 9025 * @param {number} [offset=0] - Index of the first element in the array. 9026 * @return {Array<number>} The vector components. 9027 */ 9028 toArray( array = [], offset = 0 ) { 9029 9030 array[ offset ] = this.x; 9031 array[ offset + 1 ] = this.y; 9032 array[ offset + 2 ] = this.z; 9033 array[ offset + 3 ] = this.w; 9034 9035 return array; 9036 9037 } 9038 9039 /** 9040 * Sets the components of this vector from the given buffer attribute. 9041 * 9042 * @param {BufferAttribute} attribute - The buffer attribute holding vector data. 9043 * @param {number} index - The index into the attribute. 9044 * @return {Vector4} A reference to this vector. 9045 */ 9046 fromBufferAttribute( attribute, index ) { 9047 9048 this.x = attribute.getX( index ); 9049 this.y = attribute.getY( index ); 9050 this.z = attribute.getZ( index ); 9051 this.w = attribute.getW( index ); 9052 9053 return this; 9054 9055 } 9056 9057 /** 9058 * Sets each component of this vector to a pseudo-random value between `0` and 9059 * `1`, excluding `1`. 9060 * 9061 * @return {Vector4} A reference to this vector. 9062 */ 9063 random() { 9064 9065 this.x = Math.random(); 9066 this.y = Math.random(); 9067 this.z = Math.random(); 9068 this.w = Math.random(); 9069 9070 return this; 9071 9072 } 9073 9074 *[ Symbol.iterator ]() { 9075 9076 yield this.x; 9077 yield this.y; 9078 yield this.z; 9079 yield this.w; 9080 9081 } 9082 9083} 9084 9085/** 9086 * A render target is a buffer where the video card draws pixels for a scene 9087 * that is being rendered in the background. It is used in different effects, 9088 * such as applying postprocessing to a rendered image before displaying it 9089 * on the screen. 9090 * 9091 * @augments EventDispatcher 9092 */ 9093class RenderTarget extends EventDispatcher { 9094 9095 /** 9096 * Render target options. 9097 * 9098 * @typedef {Object} RenderTarget~Options 9099 * @property {boolean} [generateMipmaps=false] - Whether to generate mipmaps or not. 9100 * @property {number} [magFilter=LinearFilter] - The mag filter. 9101 * @property {number} [minFilter=LinearFilter] - The min filter. 9102 * @property {number} [format=RGBAFormat] - The texture format. 9103 * @property {number} [type=UnsignedByteType] - The texture type. 9104 * @property {?string} [internalFormat=null] - The texture's internal format. 9105 * @property {number} [wrapS=ClampToEdgeWrapping] - The texture's uv wrapping mode. 9106 * @property {number} [wrapT=ClampToEdgeWrapping] - The texture's uv wrapping mode. 9107 * @property {number} [anisotropy=1] - The texture's anisotropy value. 9108 * @property {string} [colorSpace=NoColorSpace] - The texture's color space. 9109 * @property {boolean} [depthBuffer=true] - Whether to allocate a depth buffer or not. 9110 * @property {boolean} [stencilBuffer=false] - Whether to allocate a stencil buffer or not. 9111 * @property {boolean} [resolveDepthBuffer=true] - Whether to resolve the depth buffer or not. 9112 * @property {boolean} [resolveStencilBuffer=true] - Whether to resolve the stencil buffer or not. 9113 * @property {?Texture} [depthTexture=null] - Reference to a depth texture. 9114 * @property {number} [samples=0] - The MSAA samples count. 9115 * @property {number} [count=1] - Defines the number of color attachments . Must be at least `1`. 9116 * @property {number} [depth=1] - The texture depth. 9117 * @property {boolean} [multiview=false] - Whether this target is used for multiview rendering. 9118 */ 9119 9120 /** 9121 * Constructs a new render target. 9122 * 9123 * @param {number} [width=1] - The width of the render target. 9124 * @param {number} [height=1] - The height of the render target. 9125 * @param {RenderTarget~Options} [options] - The configuration object. 9126 */ 9127 constructor( width = 1, height = 1, options = {} ) { 9128 9129 super(); 9130 9131 options = Object.assign( { 9132 generateMipmaps: false, 9133 internalFormat: null, 9134 minFilter: LinearFilter, 9135 depthBuffer: true, 9136 stencilBuffer: false, 9137 resolveDepthBuffer: true, 9138 resolveStencilBuffer: true, 9139 depthTexture: null, 9140 samples: 0, 9141 count: 1, 9142 depth: 1, 9143 multiview: false 9144 }, options ); 9145 9146 /** 9147 * This flag can be used for type testing. 9148 * 9149 * @type {boolean} 9150 * @readonly 9151 * @default true 9152 */ 9153 this.isRenderTarget = true; 9154 9155 /** 9156 * The width of the render target. 9157 * 9158 * @type {number} 9159 * @default 1 9160 */ 9161 this.width = width; 9162 9163 /** 9164 * The height of the render target. 9165 * 9166 * @type {number} 9167 * @default 1 9168 */ 9169 this.height = height; 9170 9171 /** 9172 * The depth of the render target. 9173 * 9174 * @type {number} 9175 * @default 1 9176 */ 9177 this.depth = options.depth; 9178 9179 /** 9180 * A rectangular area inside the render target's viewport. Fragments that are 9181 * outside the area will be discarded. 9182 * 9183 * @type {Vector4} 9184 * @default (0,0,width,height) 9185 */ 9186 this.scissor = new Vector4( 0, 0, width, height ); 9187 9188 /** 9189 * Indicates whether the scissor test should be enabled when rendering into 9190 * this render target or not. 9191 * 9192 * @type {boolean} 9193 * @default false 9194 */ 9195 this.scissorTest = false; 9196 9197 /** 9198 * A rectangular area representing the render target's viewport. 9199 * 9200 * @type {Vector4} 9201 * @default (0,0,width,height) 9202 */ 9203 this.viewport = new Vector4( 0, 0, width, height ); 9204 9205 /** 9206 * An array of textures. Each color attachment is represented as a separate texture. 9207 * Has at least a single entry for the default color attachment. 9208 * 9209 * @type {Array<Texture>} 9210 */ 9211 this.textures = []; 9212 9213 const image = { width: width, height: height, depth: options.depth }; 9214 const texture = new Texture( image ); 9215 9216 const count = options.count; 9217 for ( let i = 0; i < count; i ++ ) { 9218 9219 this.textures[ i ] = texture.clone(); 9220 this.textures[ i ].isRenderTargetTexture = true; 9221 this.textures[ i ].renderTarget = this; 9222 9223 } 9224 9225 this._setTextureOptions( options ); 9226 9227 /** 9228 * Whether to allocate a depth buffer or not. 9229 * 9230 * @type {boolean} 9231 * @default true 9232 */ 9233 this.depthBuffer = options.depthBuffer; 9234 9235 /** 9236 * Whether to allocate a stencil buffer or not. 9237 * 9238 * @type {boolean} 9239 * @default false 9240 */ 9241 this.stencilBuffer = options.stencilBuffer; 9242 9243 /** 9244 * Whether to resolve the depth buffer or not. 9245 * 9246 * @type {boolean} 9247 * @default true 9248 */ 9249 this.resolveDepthBuffer = options.resolveDepthBuffer; 9250 9251 /** 9252 * Whether to resolve the stencil buffer or not. 9253 * 9254 * @type {boolean} 9255 * @default true 9256 */ 9257 this.resolveStencilBuffer = options.resolveStencilBuffer; 9258 9259 this._depthTexture = null; 9260 this.depthTexture = options.depthTexture; 9261 9262 /** 9263 * The number of MSAA samples. 9264 * 9265 * A value of `0` disables MSAA. 9266 * 9267 * @type {number} 9268 * @default 0 9269 */ 9270 this.samples = options.samples; 9271 9272 /** 9273 * Whether to this target is used in multiview rendering. 9274 * 9275 * @type {boolean} 9276 * @default false 9277 */ 9278 this.multiview = options.multiview; 9279 9280 } 9281 9282 _setTextureOptions( options = {} ) { 9283 9284 const values = { 9285 minFilter: LinearFilter, 9286 generateMipmaps: false, 9287 flipY: false, 9288 internalFormat: null 9289 }; 9290 9291 if ( options.mapping !== undefined ) values.mapping = options.mapping; 9292 if ( options.wrapS !== undefined ) values.wrapS = options.wrapS; 9293 if ( options.wrapT !== undefined ) values.wrapT = options.wrapT; 9294 if ( options.wrapR !== undefined ) values.wrapR = options.wrapR; 9295 if ( options.magFilter !== undefined ) values.magFilter = options.magFilter; 9296 if ( options.minFilter !== undefined ) values.minFilter = options.minFilter; 9297 if ( options.format !== undefined ) values.format = options.format; 9298 if ( options.type !== undefined ) values.type = options.type; 9299 if ( options.anisotropy !== undefined ) values.anisotropy = options.anisotropy; 9300 if ( options.colorSpace !== undefined ) values.colorSpace = options.colorSpace; 9301 if ( options.flipY !== undefined ) values.flipY = options.flipY; 9302 if ( options.generateMipmaps !== undefined ) values.generateMipmaps = options.generateMipmaps; 9303 if ( options.internalFormat !== undefined ) values.internalFormat = options.internalFormat; 9304 9305 for ( let i = 0; i < this.textures.length; i ++ ) { 9306 9307 const texture = this.textures[ i ]; 9308 texture.setValues( values ); 9309 9310 } 9311 9312 } 9313 9314 /** 9315 * The texture representing the default color attachment. 9316 * 9317 * @type {Texture} 9318 */ 9319 get texture() { 9320 9321 return this.textures[ 0 ]; 9322 9323 } 9324 9325 set texture( value ) { 9326 9327 this.textures[ 0 ] = value; 9328 9329 } 9330 9331 set depthTexture( current ) { 9332 9333 if ( this._depthTexture !== null ) this._depthTexture.renderTarget = null; 9334 if ( current !== null ) current.renderTarget = this; 9335 9336 this._depthTexture = current; 9337 9338 } 9339 9340 /** 9341 * Instead of saving the depth in a renderbuffer, a texture 9342 * can be used instead which is useful for further processing 9343 * e.g. in context of post-processing. 9344 * 9345 * @type {?DepthTexture} 9346 * @default null 9347 */ 9348 get depthTexture() { 9349 9350 return this._depthTexture; 9351 9352 } 9353 9354 /** 9355 * Sets the size of this render target. 9356 * 9357 * @param {number} width - The width. 9358 * @param {number} height - The height. 9359 * @param {number} [depth=1] - The depth. 9360 */ 9361 setSize( width, height, depth = 1 ) { 9362 9363 if ( this.width !== width || this.height !== height || this.depth !== depth ) { 9364 9365 this.width = width; 9366 this.height = height; 9367 this.depth = depth; 9368 9369 for ( let i = 0, il = this.textures.length; i < il; i ++ ) { 9370 9371 this.textures[ i ].image.width = width; 9372 this.textures[ i ].image.height = height; 9373 this.textures[ i ].image.depth = depth; 9374 9375 if ( this.textures[ i ].isData3DTexture !== true ) { // Fix for #31693 9376 9377 // TODO: Reconsider setting isArrayTexture flag here and in the ctor of Texture. 9378 // Maybe a method `isArrayTexture()` or just a getter could replace a flag since 9379 // both are evaluated on each call? 9380 9381 this.textures[ i ].isArrayTexture = this.textures[ i ].image.depth > 1; 9382 9383 } 9384 9385 } 9386 9387 this.dispose(); 9388 9389 } 9390 9391 this.viewport.set( 0, 0, width, height ); 9392 this.scissor.set( 0, 0, width, height ); 9393 9394 } 9395 9396 /** 9397 * Returns a new render target with copied values from this instance. 9398 * 9399 * @return {RenderTarget} A clone of this instance. 9400 */ 9401 clone() { 9402 9403 return new this.constructor().copy( this ); 9404 9405 } 9406 9407 /** 9408 * Copies the settings of the given render target. This is a structural copy so 9409 * no resources are shared between render targets after the copy. That includes 9410 * all MRT textures and the depth texture. 9411 * 9412 * @param {RenderTarget} source - The render target to copy. 9413 * @return {RenderTarget} A reference to this instance. 9414 */ 9415 copy( source ) { 9416 9417 this.width = source.width; 9418 this.height = source.height; 9419 this.depth = source.depth; 9420 9421 this.scissor.copy( source.scissor ); 9422 this.scissorTest = source.scissorTest; 9423 9424 this.viewport.copy( source.viewport ); 9425 9426 this.textures.length = 0; 9427 9428 for ( let i = 0, il = source.textures.length; i < il; i ++ ) { 9429 9430 this.textures[ i ] = source.textures[ i ].clone(); 9431 this.textures[ i ].isRenderTargetTexture = true; 9432 this.textures[ i ].renderTarget = this; 9433 9434 // ensure image object is not shared, see #20328 9435 9436 const image = Object.assign( {}, source.textures[ i ].image ); 9437 this.textures[ i ].source = new Source( image ); 9438 9439 } 9440 9441 this.depthBuffer = source.depthBuffer; 9442 this.stencilBuffer = source.stencilBuffer; 9443 9444 this.resolveDepthBuffer = source.resolveDepthBuffer; 9445 this.resolveStencilBuffer = source.resolveStencilBuffer; 9446 9447 if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone(); 9448 9449 this.samples = source.samples;
9450 this.multiview = source.multiview; 9451 9452 return this; 9453 9454 } 9455 9456 /** 9457 * Frees the GPU-related resources allocated by this instance. Call this 9458 * method whenever this instance is no longer used in your app. 9459 * 9460 * @fires RenderTarget#dispose 9461 */ 9462 dispose() { 9463 9464 this.dispatchEvent( { type: 'dispose' } ); 9465 9466 } 9467 9468} 9469 9470/** 9471 * A render target used in context of {@link WebGLRenderer}. 9472 * 9473 * @augments RenderTarget 9474 */ 9475class WebGLRenderTarget extends RenderTarget { 9476 9477 /** 9478 * Constructs a new 3D render target. 9479 * 9480 * @param {number} [width=1] - The width of the render target. 9481 * @param {number} [height=1] - The height of the render target. 9482 * @param {RenderTarget~Options} [options] - The configuration object. 9483 */ 9484 constructor( width = 1, height = 1, options = {} ) { 9485 9486 super( width, height, options ); 9487 9488 /** 9489 * This flag can be used for type testing. 9490 * 9491 * @type {boolean} 9492 * @readonly 9493 * @default true 9494 */ 9495 this.isWebGLRenderTarget = true; 9496 9497 } 9498 9499} 9500 9501/** 9502 * Creates an array of textures directly from raw buffer data. 9503 * 9504 * @augments Texture 9505 */ 9506class DataArrayTexture extends Texture { 9507 9508 /** 9509 * Constructs a new data array texture. 9510 * 9511 * @param {?TypedArray} [data=null] - The buffer data. 9512 * @param {number} [width=1] - The width of the texture. 9513 * @param {number} [height=1] - The height of the texture. 9514 * @param {number} [depth=1] - The depth of the texture. 9515 */ 9516 constructor( data = null, width = 1, height = 1, depth = 1 ) { 9517 9518 super( null ); 9519 9520 /** 9521 * This flag can be used for type testing. 9522 * 9523 * @type {boolean} 9524 * @readonly 9525 * @default true 9526 */ 9527 this.isDataArrayTexture = true; 9528 9529 /** 9530 * The image definition of a data texture. 9531 * 9532 * @type {{data:TypedArray,width:number,height:number,depth:number}} 9533 */ 9534 this.image = { data, width, height, depth }; 9535 9536 /** 9537 * How the texture is sampled when a texel covers more than one pixel. 9538 * 9539 * Overwritten and set to `NearestFilter` by default. 9540 * 9541 * @type {(NearestFilter|NearestMipmapNearestFilter|NearestMipmapLinearFilter|LinearFilter|LinearMipmapNearestFilter|LinearMipmapLinearFilter)} 9542 * @default NearestFilter 9543 */ 9544 this.magFilter = NearestFilter; 9545 9546 /** 9547 * How the texture is sampled when a texel covers less than one pixel. 9548 * 9549 * Overwritten and set to `NearestFilter` by default. 9550 * 9551 * @type {(NearestFilter|NearestMipmapNearestFilter|NearestMipmapLinearFilter|LinearFilter|LinearMipmapNearestFilter|LinearMipmapLinearFilter)} 9552 * @default NearestFilter 9553 */ 9554 this.minFilter = NearestFilter; 9555 9556 /** 9557 * This defines how the texture is wrapped in the depth and corresponds to 9558 * *W* in UVW mapping. 9559 * 9560 * @type {(RepeatWrapping|ClampToEdgeWrapping|MirroredRepeatWrapping)} 9561 * @default ClampToEdgeWrapping 9562 */ 9563 this.wrapR = ClampToEdgeWrapping; 9564 9565 /** 9566 * Whether to generate mipmaps (if possible) for a texture. 9567 * 9568 * Overwritten and set to `false` by default. 9569 * 9570 * @type {boolean} 9571 * @default false 9572 */ 9573 this.generateMipmaps = false; 9574 9575 /** 9576 * If set to `true`, the texture is flipped along the vertical axis when 9577 * uploaded to the GPU. 9578 * 9579 * Overwritten and set to `false` by default. 9580 * 9581 * @type {boolean} 9582 * @default false 9583 */ 9584 this.flipY = false; 9585 9586 /** 9587 * Specifies the alignment requirements for the start of each pixel row in memory. 9588 * 9589 * Overwritten and set to `1` by default. 9590 * 9591 * @type {boolean} 9592 * @default 1 9593 */ 9594 this.unpackAlignment = 1; 9595 9596 /** 9597 * A set of all layers which need to be updated in the texture. 9598 * 9599 * @type {Set<number>} 9600 */ 9601 this.layerUpdates = new Set(); 9602 9603 } 9604 9605 /** 9606 * Describes that a specific layer of the texture needs to be updated. 9607 * Normally when {@link Texture#needsUpdate} is set to `true`, the 9608 * entire data texture array is sent to the GPU. Marking specific 9609 * layers will only transmit subsets of all mipmaps associated with a 9610 * specific depth in the array which is often much more performant. 9611 * 9612 * @param {number} layerIndex - The layer index that should be updated. 9613 */ 9614 addLayerUpdate( layerIndex ) { 9615 9616 this.layerUpdates.add( layerIndex ); 9617 9618 } 9619
9620 /** 9621 * Resets the layer updates registry. 9622 */ 9623 clearLayerUpdates() { 9624 9625 this.layerUpdates.clear(); 9626 9627 } 9628 9629} 9630 9631/** 9632 * An array render target used in context of {@link WebGLRenderer}. 9633 * 9634 * @augments WebGLRenderTarget 9635 */ 9636class WebGLArrayRenderTarget extends WebGLRenderTarget { 9637 9638 /** 9639 * Constructs a new array render target. 9640 * 9641 * @param {number} [width=1] - The width of the render target. 9642 * @param {number} [height=1] - The height of the render target. 9643 * @param {number} [depth=1] - The height of the render target. 9644 * @param {RenderTarget~Options} [options] - The configuration object. 9645 */ 9646 constructor( width = 1, height = 1, depth = 1, options = {} ) { 9647 9648 super( width, height, options ); 9649 9650 /** 9651 * This flag can be used for type testing. 9652 * 9653 * @type {boolean} 9654 * @readonly 9655 * @default true 9656 */ 9657 this.isWebGLArrayRenderTarget = true; 9658 9659 this.depth = depth; 9660 9661 /** 9662 * Overwritten with a different texture type. 9663 * 9664 * @type {DataArrayTexture} 9665 */ 9666 this.texture = new DataArrayTexture( null, width, height, depth ); 9667 this._setTextureOptions( options ); 9668 9669 this.texture.isRenderTargetTexture = true; 9670 9671 } 9672 9673} 9674 9675/** 9676 * Creates a three-dimensional texture from raw data, with parameters to 9677 * divide it into width, height, and depth. 9678 * 9679 * @augments Texture 9680 */ 9681class Data3DTexture extends Texture { 9682 9683 /** 9684 * Constructs a new data array texture. 9685 * 9686 * @param {?TypedArray} [data=null] - The buffer data. 9687 * @param {number} [width=1] - The width of the texture. 9688 * @param {number} [height=1] - The height of the texture. 9689 * @param {number} [depth=1] - The depth of the texture. 9690 */ 9691 constructor( data = null, width = 1, height = 1, depth = 1 ) { 9692 9693 // We're going to add .setXXX() methods for setting properties later. 9694 // Users can still set in Data3DTexture directly. 9695 // 9696 // const texture = new THREE.Data3DTexture( data, width, height, depth ); 9697 // texture.anisotropy = 16; 9698 // 9699 // See #14839 9700 9701 super( null ); 9702 9703 /** 9704 * This flag can be used for type testing. 9705 * 9706 * @type {boolean} 9707 * @readonly 9708 * @default true 9709 */ 9710 this.isData3DTexture = true; 9711 9712 /** 9713 * The image definition of a data texture. 9714 * 9715 * @type {{data:TypedArray,width:number,height:number,depth:number}} 9716 */ 9717 this.image = { data, width, height, depth }; 9718 9719 /** 9720 * How the texture is sampled when a texel covers more than one pixel. 9721 * 9722 * Overwritten and set to `NearestFilter` by default. 9723 * 9724 * @type {(NearestFilter|NearestMipmapNearestFilter|NearestMipmapLinearFilter|LinearFilter|LinearMipmapNearestFilter|LinearMipmapLinearFilter)} 9725 * @default NearestFilter 9726 */ 9727 this.magFilter = NearestFilter; 9728 9729 /** 9730 * How the texture is sampled when a texel covers less than one pixel. 9731 * 9732 * Overwritten and set to `NearestFilter` by default. 9733 * 9734 * @type {(NearestFilter|NearestMipmapNearestFilter|NearestMipmapLinearFilter|LinearFilter|LinearMipmapNearestFilter|LinearMipmapLinearFilter)} 9735 * @default NearestFilter 9736 */ 9737 this.minFilter = NearestFilter; 9738 9739 /** 9740 * This defines how the texture is wrapped in the depth and corresponds to 9741 * *W* in UVW mapping. 9742 * 9743 * @type {(RepeatWrapping|ClampToEdgeWrapping|MirroredRepeatWrapping)} 9744 * @default ClampToEdgeWrapping 9745 */ 9746 this.wrapR = ClampToEdgeWrapping; 9747 9748 /** 9749 * Whether to generate mipmaps (if possible) for a texture. 9750 * 9751 * Overwritten and set to `false` by default. 9752 * 9753 * @type {boolean} 9754 * @default false 9755 */ 9756 this.generateMipmaps = false; 9757 9758 /** 9759 * If set to `true`, the texture is flipped along the vertical axis when 9760 * uploaded to the GPU. 9761 * 9762 * Overwritten and set to `false` by default. 9763 * 9764 * @type {boolean} 9765 * @default false 9766 */ 9767 this.flipY = false; 9768 9769 /** 9770 * Specifies the alignment requirements for the start of each pixel row in memory. 9771 * 9772 * Overwritten and set to `1` by default. 9773 * 9774 * @type {boolean} 9775 * @default 1 9776 */ 9777 this.unpackAlignment = 1; 9778 9779 } 9780 9781} 9782 9783/** 9784 * A 3D render target used in context of {@link WebGLRenderer}. 9785 * 9786 * @augments WebGLRenderTarget 9787 */ 9788class WebGL3DRenderTarget extends WebGLRenderTarget { 9789 9790 /** 9791 * Constructs a new 3D render target. 9792 * 9793 * @param {number} [width=1] - The width of the render target. 9794 * @param {number} [height=1] - The height of the render target. 9795 * @param {number} [depth=1] - The height of the render target.
9796 * @param {RenderTarget~Options} [options] - The configuration object. 9797 */ 9798 constructor( width = 1, height = 1, depth = 1, options = {} ) { 9799 9800 super( width, height, options ); 9801 9802 /** 9803 * This flag can be used for type testing. 9804 * 9805 * @type {boolean} 9806 * @readonly 9807 * @default true 9808 */ 9809 this.isWebGL3DRenderTarget = true; 9810 9811 this.depth = depth; 9812 9813 /** 9814 * Overwritten with a different texture type. 9815 * 9816 * @type {Data3DTexture} 9817 */ 9818 this.texture = new Data3DTexture( null, width, height, depth ); 9819 this._setTextureOptions( options ); 9820 9821 this.texture.isRenderTargetTexture = true; 9822 9823 } 9824 9825} 9826 9827/** 9828 * Represents a 4x4 matrix. 9829 * 9830 * The most common use of a 4x4 matrix in 3D computer graphics is as a transformation matrix. 9831 * For an introduction to transformation matrices as used in WebGL, check out [this tutorial](https://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices) 9832 * 9833 * This allows a 3D vector representing a point in 3D space to undergo 9834 * transformations such as translation, rotation, shear, scale, reflection, 9835 * orthogonal or perspective projection and so on, by being multiplied by the 9836 * matrix. This is known as `applying` the matrix to the vector. 9837 * 9838 * A Note on Row-Major and Column-Major Ordering: 9839 * 9840 * The constructor and {@link Matrix3#set} method take arguments in 9841 * [row-major](https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order) 9842 * order, while internally they are stored in the {@link Matrix3#elements} array in column-major order. 9843 * This means that calling: 9844 * ```js 9845 * const m = new THREE.Matrix4(); 9846 * m.set( 11, 12, 13, 14, 9847 * 21, 22, 23, 24, 9848 * 31, 32, 33, 34, 9849 * 41, 42, 43, 44 ); 9850 * ``` 9851 * will result in the elements array containing: 9852 * ```js 9853 * m.elements = [ 11, 21, 31, 41, 9854 * 12, 22, 32, 42, 9855 * 13, 23, 33, 43, 9856 * 14, 24, 34, 44 ]; 9857 * ``` 9858 * and internally all calculations are performed using column-major ordering. 9859 * However, as the actual ordering makes no difference mathematically and 9860 * most people are used to thinking about matrices in row-major order, the 9861 * three.js documentation shows matrices in row-major order. Just bear in 9862 * mind that if you are reading the source code, you'll have to take the 9863 * transpose of any matrices outlined here to make sense of the calculations. 9864 */ 9865class Matrix4 { 9866 9867 static { 9868 9869 /** 9870 * This flag can be used for type testing. 9871 * 9872 * @type {boolean} 9873 * @readonly 9874 * @default true 9875 */ 9876 Matrix4.prototype.isMatrix4 = true; 9877 9878 } 9879 9880 /** 9881 * Constructs a new 4x4 matrix. The arguments are supposed to be 9882 * in row-major order. If no arguments are provided, the constructor 9883 * initializes the matrix as an identity matrix. 9884 * 9885 * @param {number} [n11] - 1-1 matrix element. 9886 * @param {number} [n12] - 1-2 matrix element. 9887 * @param {number} [n13] - 1-3 matrix element. 9888 * @param {number} [n14] - 1-4 matrix element. 9889 * @param {number} [n21] - 2-1 matrix element. 9890 * @param {number} [n22] - 2-2 matrix element. 9891 * @param {number} [n23] - 2-3 matrix element. 9892 * @param {number} [n24] - 2-4 matrix element. 9893 * @param {number} [n31] - 3-1 matrix element. 9894 * @param {number} [n32] - 3-2 matrix element. 9895 * @param {number} [n33] - 3-3 matrix element. 9896 * @param {number} [n34] - 3-4 matrix element. 9897 * @param {number} [n41] - 4-1 matrix element. 9898 * @param {number} [n42] - 4-2 matrix element. 9899 * @param {number} [n43] - 4-3 matrix element. 9900 * @param {number} [n44] - 4-4 matrix element. 9901 */ 9902 constructor( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
vendor: 31,611 bytes, lines 9902-11183
9902 9903 9904 /** 9905 * A column-major list of matrix values. 9906 * 9907 * @type {Array<number>} 9908 */ 9909 this.elements = [ 9910 9911 1, 0, 0, 0, 9912 0, 1, 0, 0, 9913 0, 0, 1, 0, 9914 0, 0, 0, 1 9915 9916 ]; 9917 9918 if ( n11 !== undefined ) { 9919 9920 this.set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ); 9921 9922 } 9923 9924 } 9925 9926 /** 9927 * Sets the elements of the matrix.The arguments are supposed to be 9928 * in row-major order. 9929 * 9930 * @param {number} [n11] - 1-1 matrix element. 9931 * @param {number} [n12] - 1-2 matrix element. 9932 * @param {number} [n13] - 1-3 matrix element. 9933 * @param {number} [n14] - 1-4 matrix element. 9934 * @param {number} [n21] - 2-1 matrix element. 9935 * @param {number} [n22] - 2-2 matrix element. 9936 * @param {number} [n23] - 2-3 matrix element. 9937 * @param {number} [n24] - 2-4 matrix element. 9938 * @param {number} [n31] - 3-1 matrix element. 9939 * @param {number} [n32] - 3-2 matrix element. 9940 * @param {number} [n33] - 3-3 matrix element. 9941 * @param {number} [n34] - 3-4 matrix element. 9942 * @param {number} [n41] - 4-1 matrix element. 9943 * @param {number} [n42] - 4-2 matrix element. 9944 * @param {number} [n43] - 4-3 matrix element. 9945 * @param {number} [n44] - 4-4 matrix element. 9946 * @return {Matrix4} A reference to this matrix. 9947 */ 9948 set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { 9949 9950 const te = this.elements; 9951 9952 te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; 9953 te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; 9954 te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; 9955 te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; 9956 9957 return this; 9958 9959 } 9960 9961 /** 9962 * Sets this matrix to the 4x4 identity matrix. 9963 * 9964 * @return {Matrix4} A reference to this matrix. 9965 */ 9966 identity() { 9967 9968 this.set( 9969 9970 1, 0, 0, 0, 9971 0, 1, 0, 0, 9972 0, 0, 1, 0, 9973 0, 0, 0, 1 9974 9975 ); 9976 9977 return this; 9978 9979 } 9980 9981 /** 9982 * Returns a matrix with copied values from this instance. 9983 * 9984 * @return {Matrix4} A clone of this instance. 9985 */ 9986 clone() { 9987 9988 return new Matrix4().fromArray( this.elements ); 9989 9990 } 9991 9992 /** 9993 * Copies the values of the given matrix to this instance. 9994 * 9995 * @param {Matrix4} m - The matrix to copy. 9996 * @return {Matrix4} A reference to this matrix. 9997 */ 9998 copy( m ) { 9999 10000 const te = this.elements; 10001 const me = m.elements; 10002 10003 te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ]; 10004 te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; 10005 te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ]; 10006 te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ]; 10007 10008 return this; 10009 10010 } 10011 10012 /** 10013 * Copies the translation component of the given matrix 10014 * into this matrix's translation component. 10015 * 10016 * @param {Matrix4} m - The matrix to copy the translation component. 10017 * @return {Matrix4} A reference to this matrix. 10018 */ 10019 copyPosition( m ) { 10020 10021 const te = this.elements, me = m.elements; 10022 10023 te[ 12 ] = me[ 12 ]; 10024 te[ 13 ] = me[ 13 ]; 10025 te[ 14 ] = me[ 14 ]; 10026 10027 return this; 10028 10029 } 10030 10031 /** 10032 * Set the upper 3x3 elements of this matrix to the values of given 3x3 matrix. 10033 * 10034 * @param {Matrix3} m - The 3x3 matrix. 10035 * @return {Matrix4} A reference to this matrix. 10036 */ 10037 setFromMatrix3( m ) { 10038 10039 const me = m.elements; 10040 10041 this.set( 10042 10043 me[ 0 ], me[ 3 ], me[ 6 ], 0, 10044 me[ 1 ], me[ 4 ], me[ 7 ], 0, 10045 me[ 2 ], me[ 5 ], me[ 8 ], 0, 10046 0, 0, 0, 1 10047 10048 ); 10049 10050 return this; 10051 10052 } 10053 10054 /** 10055 * Extracts the basis of this matrix into the three axis vectors provided. 10056 * 10057 * @param {Vector3} xAxis - The basis's x axis. 10058 * @param {Vector3} yAxis - The basis's y axis. 10059 * @param {Vector3} zAxis - The basis's z axis. 10060 * @return {Matrix4} A reference to this matrix. 10061 */ 10062 extractBasis( xAxis, yAxis, zAxis ) { 10063 10064 if ( this.determinant() === 0 ) { 10065 10066 xAxis.set( 1, 0, 0 ); 10067 yAxis.set( 0, 1, 0 ); 10068 zAxis.set( 0, 0, 1 ); 10069 10070 return this; 10071 10072 } 10073 10074 xAxis.setFromMatrixColumn( this, 0 ); 10075 yAxis.setFromMatrixColumn( this, 1 ); 10076 zAxis.setFromMatrixColumn( this, 2 ); 10077 10078 return this; 10079 10080 } 10081 10082 /** 10083 * Sets the given basis vectors to this matrix. 10084 * 10085 * @param {Vector3} xAxis - The basis's x axis. 10086 * @param {Vector3} yAxis - The basis's y axis. 10087 * @param {Vector3} zAxis - The basis's z axis. 10088 * @return {Matrix4} A reference to this matrix. 10089 */ 10090 makeBasis( xAxis, yAxis, zAxis ) { 10091 10092 this.set( 10093 xAxis.x, yAxis.x, zAxis.x, 0, 10094 xAxis.y, yAxis.y, zAxis.y, 0, 10095 xAxis.z, yAxis.z, zAxis.z, 0, 10096 0, 0, 0, 1 10097 ); 10098 10099 return this; 10100 10101 } 10102 10103 /** 10104 * Extracts the rotation component of the given matrix 10105 * into this matrix's rotation component. 10106 * 10107 * Note: This method does not support reflection matrices. 10108 * 10109 * @param {Matrix4} m - The matrix. 10110 * @return {Matrix4} A reference to this matrix. 10111 */ 10112 extractRotation( m ) { 10113 10114 if ( m.determinant() === 0 ) { 10115 10116 return this.identity(); 10117 10118 } 10119 10120 const te = this.elements; 10121 const me = m.elements; 10122 10123 const scaleX = 1 / _v1$7.setFromMatrixColumn( m, 0 ).length(); 10124 const scaleY = 1 / _v1$7.setFromMatrixColumn( m, 1 ).length(); 10125 const scaleZ = 1 / _v1$7.setFromMatrixColumn( m, 2 ).length(); 10126 10127 te[ 0 ] = me[ 0 ] * scaleX; 10128 te[ 1 ] = me[ 1 ] * scaleX; 10129 te[ 2 ] = me[ 2 ] * scaleX; 10130 te[ 3 ] = 0; 10131 10132 te[ 4 ] = me[ 4 ] * scaleY; 10133 te[ 5 ] = me[ 5 ] * scaleY; 10134 te[ 6 ] = me[ 6 ] * scaleY; 10135 te[ 7 ] = 0; 10136 10137 te[ 8 ] = me[ 8 ] * scaleZ; 10138 te[ 9 ] = me[ 9 ] * scaleZ; 10139 te[ 10 ] = me[ 10 ] * scaleZ; 10140 te[ 11 ] = 0; 10141 10142 te[ 12 ] = 0; 10143 te[ 13 ] = 0; 10144 te[ 14 ] = 0; 10145 te[ 15 ] = 1; 10146 10147 return this; 10148 10149 } 10150 10151 /** 10152 * Sets the rotation component (the upper left 3x3 matrix) of this matrix to 10153 * the rotation specified by the given Euler angles. The rest of 10154 * the matrix is set to the identity. Depending on the {@link Euler#order}, 10155 * there are six possible outcomes. See [this page](https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix) 10156 * for a complete list. 10157 * 10158 * @param {Euler} euler - The Euler angles. 10159 * @return {Matrix4} A reference to this matrix. 10160 */ 10161 makeRotationFromEuler( euler ) { 10162 10163 const te = this.elements; 10164 10165 const x = euler.x, y = euler.y, z = euler.z; 10166 const a = Math.cos( x ), b = Math.sin( x ); 10167 const c = Math.cos( y ), d = Math.sin( y ); 10168 const e = Math.cos( z ), f = Math.sin( z ); 10169 10170 if ( euler.order === 'XYZ' ) { 10171 10172 const ae = a * e, af = a * f, be = b * e, bf = b * f; 10173 10174 te[ 0 ] = c * e; 10175 te[ 4 ] = - c * f; 10176 te[ 8 ] = d; 10177 10178 te[ 1 ] = af + be * d; 10179 te[ 5 ] = ae - bf * d; 10180 te[ 9 ] = - b * c; 10181 10182 te[ 2 ] = bf - ae * d; 10183 te[ 6 ] = be + af * d; 10184 te[ 10 ] = a * c; 10185 10186 } else if ( euler.order === 'YXZ' ) { 10187 10188 const ce = c * e, cf = c * f, de = d * e, df = d * f; 10189 10190 te[ 0 ] = ce + df * b; 10191 te[ 4 ] = de * b - cf; 10192 te[ 8 ] = a * d; 10193 10194 te[ 1 ] = a * f; 10195 te[ 5 ] = a * e; 10196 te[ 9 ] = - b; 10197 10198 te[ 2 ] = cf * b - de; 10199 te[ 6 ] = df + ce * b; 10200 te[ 10 ] = a * c; 10201 10202 } else if ( euler.order === 'ZXY' ) { 10203 10204 const ce = c * e, cf = c * f, de = d * e, df = d * f; 10205 10206 te[ 0 ] = ce - df * b; 10207 te[ 4 ] = - a * f; 10208 te[ 8 ] = de + cf * b; 10209 10210 te[ 1 ] = cf + de * b; 10211 te[ 5 ] = a * e; 10212 te[ 9 ] = df - ce * b; 10213 10214 te[ 2 ] = - a * d; 10215 te[ 6 ] = b; 10216 te[ 10 ] = a * c; 10217 10218 } else if ( euler.order === 'ZYX' ) { 10219 10220 const ae = a * e, af = a * f, be = b * e, bf = b * f; 10221 10222 te[ 0 ] = c * e; 10223 te[ 4 ] = be * d - af; 10224 te[ 8 ] = ae * d + bf; 10225 10226 te[ 1 ] = c * f; 10227 te[ 5 ] = bf * d + ae; 10228 te[ 9 ] = af * d - be; 10229 10230 te[ 2 ] = - d; 10231 te[ 6 ] = b * c; 10232 te[ 10 ] = a * c; 10233 10234 } else if ( euler.order === 'YZX' ) { 10235 10236 const ac = a * c, ad = a * d, bc = b * c, bd = b * d; 10237 10238 te[ 0 ] = c * e; 10239 te[ 4 ] = bd - ac * f; 10240 te[ 8 ] = bc * f + ad; 10241 10242 te[ 1 ] = f; 10243 te[ 5 ] = a * e; 10244 te[ 9 ] = - b * e; 10245 10246 te[ 2 ] = - d * e; 10247 te[ 6 ] = ad * f + bc; 10248 te[ 10 ] = ac - bd * f; 10249 10250 } else if ( euler.order === 'XZY' ) { 10251 10252 const ac = a * c, ad = a * d, bc = b * c, bd = b * d; 10253 10254 te[ 0 ] = c * e; 10255 te[ 4 ] = - f; 10256 te[ 8 ] = d * e; 10257 10258 te[ 1 ] = ac * f + bd; 10259 te[ 5 ] = a * e; 10260 te[ 9 ] = ad * f - bc; 10261 10262 te[ 2 ] = bc * f - ad; 10263 te[ 6 ] = b * e; 10264 te[ 10 ] = bd * f + ac; 10265 10266 } 10267 10268 // bottom row 10269 te[ 3 ] = 0; 10270 te[ 7 ] = 0; 10271 te[ 11 ] = 0; 10272 10273 // last column 10274 te[ 12 ] = 0; 10275 te[ 13 ] = 0; 10276 te[ 14 ] = 0; 10277 te[ 15 ] = 1; 10278 10279 return this; 10280 10281 } 10282 10283 /** 10284 * Sets the rotation component of this matrix to the rotation specified by 10285 * the given Quaternion as outlined [here](https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion) 10286 * The rest of the matrix is set to the identity. 10287 * 10288 * @param {Quaternion} q - The Quaternion. 10289 * @return {Matrix4} A reference to this matrix. 10290 */ 10291 makeRotationFromQuaternion( q ) { 10292 10293 return this.compose( _zero, q, _one ); 10294 10295 } 10296 10297 /** 10298 * Sets the rotation component of the transformation matrix, looking from `eye` towards 10299 * `target`, and oriented by the up-direction. 10300 * 10301 * @param {Vector3} eye - The eye vector. 10302 * @param {Vector3} target - The target vector. 10303 * @param {Vector3} up - The up vector. 10304 * @return {Matrix4} A reference to this matrix. 10305 */ 10306 lookAt( eye, target, up ) { 10307 10308 const te = this.elements; 10309 10310 _z.subVectors( eye, target ); 10311 10312 if ( _z.lengthSq() === 0 ) { 10313 10314 // eye and target are in the same position 10315 10316 _z.z = 1; 10317 10318 } 10319 10320 _z.normalize(); 10321 _x.crossVectors( up, _z ); 10322 10323 if ( _x.lengthSq() === 0 ) { 10324 10325 // up and z are parallel 10326 10327 if ( Math.abs( up.z ) === 1 ) { 10328 10329 _z.x += 0.0001; 10330 10331 } else { 10332 10333 _z.z += 0.0001; 10334 10335 } 10336 10337 _z.normalize(); 10338 _x.crossVectors( up, _z ); 10339 10340 } 10341 10342 _x.normalize(); 10343 _y.crossVectors( _z, _x ); 10344 10345 te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x; 10346 te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y; 10347 te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z; 10348 10349 return this; 10350 10351 } 10352 10353 /** 10354 * Post-multiplies this matrix by the given 4x4 matrix. 10355 * 10356 * @param {Matrix4} m - The matrix to multiply with. 10357 * @return {Matrix4} A reference to this matrix. 10358 */ 10359 multiply( m ) { 10360 10361 return this.multiplyMatrices( this, m ); 10362 10363 } 10364 10365 /** 10366 * Pre-multiplies this matrix by the given 4x4 matrix. 10367 * 10368 * @param {Matrix4} m - The matrix to multiply with. 10369 * @return {Matrix4} A reference to this matrix. 10370 */ 10371 premultiply( m ) { 10372 10373 return this.multiplyMatrices( m, this ); 10374 10375 } 10376 10377 /** 10378 * Multiples the given 4x4 matrices and stores the result 10379 * in this matrix. 10380 * 10381 * @param {Matrix4} a - The first matrix. 10382 * @param {Matrix4} b - The second matrix. 10383 * @return {Matrix4} A reference to this matrix. 10384 */ 10385 multiplyMatrices( a, b ) { 10386 10387 const ae = a.elements; 10388 const be = b.elements; 10389 const te = this.elements; 10390 10391 const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; 10392 const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; 10393 const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; 10394 const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; 10395 10396 const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; 10397 const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; 10398 const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; 10399 const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; 10400 10401 te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; 10402 te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; 10403 te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; 10404 te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; 10405 10406 te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; 10407 te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; 10408 te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; 10409 te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; 10410 10411 te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; 10412 te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; 10413 te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; 10414 te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; 10415 10416 te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; 10417 te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; 10418 te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; 10419 te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; 10420 10421 return this; 10422 10423 } 10424 10425 /** 10426 * Multiplies every component of the matrix by the given scalar. 10427 * 10428 * @param {number} s - The scalar. 10429 * @return {Matrix4} A reference to this matrix. 10430 */ 10431 multiplyScalar( s ) { 10432 10433 const te = this.elements; 10434 10435 te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s; 10436 te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s; 10437 te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s; 10438 te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s; 10439 10440 return this; 10441 10442 } 10443 10444 /** 10445 * Computes and returns the determinant of this matrix. 10446 * 10447 * Based on the method outlined [here](http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.html). 10448 * 10449 * @return {number} The determinant. 10450 */ 10451 determinant() { 10452 10453 const te = this.elements; 10454 10455 const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; 10456 const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; 10457 const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; 10458 const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; 10459 10460 const t11 = n23 * n34 - n24 * n33; 10461 const t12 = n22 * n34 - n24 * n32; 10462 const t13 = n22 * n33 - n23 * n32; 10463 10464 const t21 = n21 * n34 - n24 * n31; 10465 const t22 = n21 * n33 - n23 * n31; 10466 const t23 = n21 * n32 - n22 * n31; 10467 10468 return n11 * ( n42 * t11 - n43 * t12 + n44 * t13 ) - 10469 n12 * ( n41 * t11 - n43 * t21 + n44 * t22 ) + 10470 n13 * ( n41 * t12 - n42 * t21 + n44 * t23 ) - 10471 n14 * ( n41 * t13 - n42 * t22 + n43 * t23 ); 10472 10473 } 10474 10475 /** 10476 * Transposes this matrix in place. 10477 * 10478 * @return {Matrix4} A reference to this matrix. 10479 */ 10480 transpose() { 10481 10482 const te = this.elements; 10483 let tmp; 10484 10485 tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp; 10486 tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp; 10487 tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp; 10488 10489 tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp; 10490 tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp; 10491 tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp; 10492 10493 return this; 10494 10495 } 10496 10497 /** 10498 * Sets the position component for this matrix from the given vector, 10499 * without affecting the rest of the matrix. 10500 * 10501 * @param {number|Vector3} x - The x component of the vector or alternatively the vector object. 10502 * @param {number} y - The y component of the vector. 10503 * @param {number} z - The z component of the vector. 10504 * @return {Matrix4} A reference to this matrix. 10505 */ 10506 setPosition( x, y, z ) { 10507 10508 const te = this.elements; 10509 10510 if ( x.isVector3 ) { 10511 10512 te[ 12 ] = x.x; 10513 te[ 13 ] = x.y; 10514 te[ 14 ] = x.z; 10515 10516 } else { 10517 10518 te[ 12 ] = x; 10519 te[ 13 ] = y; 10520 te[ 14 ] = z; 10521 10522 } 10523 10524 return this; 10525 10526 } 10527 10528 /** 10529 * Inverts this matrix, using the [analytic method](https://en.wikipedia.org/wiki/Invertible_matrix#Analytic_solution). 10530 * You can not invert with a determinant of zero. If you attempt this, the method produces 10531 * a zero matrix instead. 10532 * 10533 * @return {Matrix4} A reference to this matrix. 10534 */ 10535 invert() { 10536 10537 // based on https://github.com/toji/gl-matrix 10538 const te = this.elements, 10539 10540 n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ], 10541 n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ], 10542 n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ], 10543 n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ], 10544 10545 t1 = n11 * n22 - n21 * n12, 10546 t2 = n11 * n32 - n31 * n12, 10547 t3 = n11 * n42 - n41 * n12, 10548 t4 = n21 * n32 - n31 * n22, 10549 t5 = n21 * n42 - n41 * n22, 10550 t6 = n31 * n42 - n41 * n32, 10551 t7 = n13 * n24 - n23 * n14, 10552 t8 = n13 * n34 - n33 * n14, 10553 t9 = n13 * n44 - n43 * n14, 10554 t10 = n23 * n34 - n33 * n24, 10555 t11 = n23 * n44 - n43 * n24, 10556 t12 = n33 * n44 - n43 * n34; 10557 10558 const det = t1 * t12 - t2 * t11 + t3 * t10 + t4 * t9 - t5 * t8 + t6 * t7; 10559 10560 if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); 10561 10562 const detInv = 1 / det; 10563 10564 te[ 0 ] = ( n22 * t12 - n32 * t11 + n42 * t10 ) * detInv; 10565 te[ 1 ] = ( n31 * t11 - n21 * t12 - n41 * t10 ) * detInv; 10566 te[ 2 ] = ( n24 * t6 - n34 * t5 + n44 * t4 ) * detInv; 10567 te[ 3 ] = ( n33 * t5 - n23 * t6 - n43 * t4 ) * detInv; 10568 10569 te[ 4 ] = ( n32 * t9 - n12 * t12 - n42 * t8 ) * detInv; 10570 te[ 5 ] = ( n11 * t12 - n31 * t9 + n41 * t8 ) * detInv; 10571 te[ 6 ] = ( n34 * t3 - n14 * t6 - n44 * t2 ) * detInv; 10572 te[ 7 ] = ( n13 * t6 - n33 * t3 + n43 * t2 ) * detInv; 10573 10574 te[ 8 ] = ( n12 * t11 - n22 * t9 + n42 * t7 ) * detInv; 10575 te[ 9 ] = ( n21 * t9 - n11 * t11 - n41 * t7 ) * detInv; 10576 te[ 10 ] = ( n14 * t5 - n24 * t3 + n44 * t1 ) * detInv; 10577 te[ 11 ] = ( n23 * t3 - n13 * t5 - n43 * t1 ) * detInv; 10578 10579 te[ 12 ] = ( n22 * t8 - n12 * t10 - n32 * t7 ) * detInv; 10580 te[ 13 ] = ( n11 * t10 - n21 * t8 + n31 * t7 ) * detInv; 10581 te[ 14 ] = ( n24 * t2 - n14 * t4 - n34 * t1 ) * detInv; 10582 te[ 15 ] = ( n13 * t4 - n23 * t2 + n33 * t1 ) * detInv; 10583 10584 return this; 10585 10586 } 10587 10588 /** 10589 * Multiplies the columns of this matrix by the given vector. 10590 * 10591 * @param {Vector3} v - The scale vector. 10592 * @return {Matrix4} A reference to this matrix. 10593 */ 10594 scale( v ) { 10595 10596 const te = this.elements; 10597 const x = v.x, y = v.y, z = v.z; 10598 10599 te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; 10600 te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; 10601 te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; 10602 te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; 10603 10604 return this; 10605 10606 } 10607 10608 /** 10609 * Gets the maximum scale value of the three axes. 10610 * 10611 * @return {number} The maximum scale. 10612 */ 10613 getMaxScaleOnAxis() { 10614 10615 const te = this.elements; 10616 10617 const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; 10618 const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; 10619 const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; 10620 10621 return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); 10622 10623 } 10624 10625 /** 10626 * Sets this matrix as a translation transform from the given vector. 10627 * 10628 * @param {number|Vector3} x - The amount to translate in the X axis or alternatively a translation vector. 10629 * @param {number} y - The amount to translate in the Y axis. 10630 * @param {number} z - The amount to translate in the z axis. 10631 * @return {Matrix4} A reference to this matrix. 10632 */ 10633 makeTranslation( x, y, z ) { 10634 10635 if ( x.isVector3 ) { 10636 10637 this.set( 10638 10639 1, 0, 0, x.x, 10640 0, 1, 0, x.y, 10641 0, 0, 1, x.z, 10642 0, 0, 0, 1 10643 10644 ); 10645 10646 } else { 10647 10648 this.set( 10649 10650 1, 0, 0, x, 10651 0, 1, 0, y, 10652 0, 0, 1, z, 10653 0, 0, 0, 1 10654 10655 ); 10656 10657 } 10658 10659 return this; 10660 10661 } 10662 10663 /** 10664 * Sets this matrix as a rotational transformation around the X axis by 10665 * the given angle. 10666 * 10667 * @param {number} theta - The rotation in radians. 10668 * @return {Matrix4} A reference to this matrix. 10669 */ 10670 makeRotationX( theta ) { 10671 10672 const c = Math.cos( theta ), s = Math.sin( theta ); 10673 10674 this.set( 10675 10676 1, 0, 0, 0, 10677 0, c, - s, 0, 10678 0, s, c, 0, 10679 0, 0, 0, 1 10680 10681 ); 10682 10683 return this; 10684 10685 } 10686 10687 /** 10688 * Sets this matrix as a rotational transformation around the Y axis by 10689 * the given angle. 10690 * 10691 * @param {number} theta - The rotation in radians. 10692 * @return {Matrix4} A reference to this matrix. 10693 */ 10694 makeRotationY( theta ) { 10695 10696 const c = Math.cos( theta ), s = Math.sin( theta ); 10697 10698 this.set( 10699 10700 c, 0, s, 0, 10701 0, 1, 0, 0, 10702 - s, 0, c, 0, 10703 0, 0, 0, 1 10704 10705 ); 10706 10707 return this; 10708 10709 } 10710 10711 /** 10712 * Sets this matrix as a rotational transformation around the Z axis by 10713 * the given angle. 10714 * 10715 * @param {number} theta - The rotation in radians. 10716 * @return {Matrix4} A reference to this matrix. 10717 */ 10718 makeRotationZ( theta ) { 10719 10720 const c = Math.cos( theta ), s = Math.sin( theta ); 10721 10722 this.set( 10723 10724 c, - s, 0, 0, 10725 s, c, 0, 0, 10726 0, 0, 1, 0, 10727 0, 0, 0, 1 10728 10729 ); 10730 10731 return this; 10732 10733 } 10734 10735 /** 10736 * Sets this matrix as a rotational transformation around the given axis by 10737 * the given angle. 10738 * 10739 * This is a somewhat controversial but mathematically sound alternative to 10740 * rotating via Quaternions. See the discussion [here](https://www.gamedev.net/articles/programming/math-and-physics/do-we-really-need-quaternions-r1199). 10741 * 10742 * @param {Vector3} axis - The normalized rotation axis. 10743 * @param {number} angle - The rotation in radians. 10744 * @return {Matrix4} A reference to this matrix. 10745 */ 10746 makeRotationAxis( axis, angle ) { 10747 10748 // Based on http://www.gamedev.net/reference/articles/article1199.asp 10749 10750 const c = Math.cos( angle ); 10751 const s = Math.sin( angle ); 10752 const t = 1 - c; 10753 const x = axis.x, y = axis.y, z = axis.z; 10754 const tx = t * x, ty = t * y; 10755 10756 this.set( 10757 10758 tx * x + c, tx * y - s * z, tx * z + s * y, 0, 10759 tx * y + s * z, ty * y + c, ty * z - s * x, 0, 10760 tx * z - s * y, ty * z + s * x, t * z * z + c, 0, 10761 0, 0, 0, 1 10762 10763 ); 10764 10765 return this; 10766 10767 } 10768 10769 /** 10770 * Sets this matrix as a scale transformation. 10771 * 10772 * @param {number} x - The amount to scale in the X axis. 10773 * @param {number} y - The amount to scale in the Y axis. 10774 * @param {number} z - The amount to scale in the Z axis. 10775 * @return {Matrix4} A reference to this matrix. 10776 */ 10777 makeScale( x, y, z ) { 10778 10779 this.set( 10780 10781 x, 0, 0, 0, 10782 0, y, 0, 0, 10783 0, 0, z, 0, 10784 0, 0, 0, 1 10785 10786 ); 10787 10788 return this; 10789 10790 } 10791 10792 /** 10793 * Sets this matrix as a shear transformation. 10794 * 10795 * @param {number} xy - The amount to shear X by Y. 10796 * @param {number} xz - The amount to shear X by Z. 10797 * @param {number} yx - The amount to shear Y by X. 10798 * @param {number} yz - The amount to shear Y by Z. 10799 * @param {number} zx - The amount to shear Z by X. 10800 * @param {number} zy - The amount to shear Z by Y. 10801 * @return {Matrix4} A reference to this matrix. 10802 */ 10803 makeShear( xy, xz, yx, yz, zx, zy ) { 10804 10805 this.set( 10806 10807 1, yx, zx, 0, 10808 xy, 1, zy, 0, 10809 xz, yz, 1, 0, 10810 0, 0, 0, 1 10811 10812 ); 10813 10814 return this; 10815 10816 } 10817 10818 /** 10819 * Sets this matrix to the transformation composed of the given position, 10820 * rotation (Quaternion) and scale. 10821 * 10822 * @param {Vector3} position - The position vector. 10823 * @param {Quaternion} quaternion - The rotation as a Quaternion. 10824 * @param {Vector3} scale - The scale vector. 10825 * @return {Matrix4} A reference to this matrix. 10826 */ 10827 compose( position, quaternion, scale ) { 10828 10829 const te = this.elements; 10830 10831 const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w; 10832 const x2 = x + x, y2 = y + y, z2 = z + z; 10833 const xx = x * x2, xy = x * y2, xz = x * z2; 10834 const yy = y * y2, yz = y * z2, zz = z * z2; 10835 const wx = w * x2, wy = w * y2, wz = w * z2; 10836 10837 const sx = scale.x, sy = scale.y, sz = scale.z; 10838 10839 te[ 0 ] = ( 1 - ( yy + zz ) ) * sx; 10840 te[ 1 ] = ( xy + wz ) * sx; 10841 te[ 2 ] = ( xz - wy ) * sx; 10842 te[ 3 ] = 0; 10843 10844 te[ 4 ] = ( xy - wz ) * sy; 10845 te[ 5 ] = ( 1 - ( xx + zz ) ) * sy; 10846 te[ 6 ] = ( yz + wx ) * sy; 10847 te[ 7 ] = 0; 10848 10849 te[ 8 ] = ( xz + wy ) * sz; 10850 te[ 9 ] = ( yz - wx ) * sz; 10851 te[ 10 ] = ( 1 - ( xx + yy ) ) * sz; 10852 te[ 11 ] = 0; 10853 10854 te[ 12 ] = position.x; 10855 te[ 13 ] = position.y; 10856 te[ 14 ] = position.z; 10857 te[ 15 ] = 1; 10858 10859 return this; 10860 10861 } 10862 10863 /** 10864 * Decomposes this matrix into its position, rotation and scale components 10865 * and provides the result in the given objects. 10866 * 10867 * Note: Not all matrices are decomposable in this way. For example, if an 10868 * object has a non-uniformly scaled parent, then the object's world matrix 10869 * may not be decomposable, and this method may not be appropriate. 10870 * 10871 * @param {Vector3} position - The position vector. 10872 * @param {Quaternion} quaternion - The rotation as a Quaternion. 10873 * @param {Vector3} scale - The scale vector. 10874 * @return {Matrix4} A reference to this matrix. 10875 */ 10876 decompose( position, quaternion, scale ) { 10877 10878 const te = this.elements; 10879 10880 position.x = te[ 12 ]; 10881 position.y = te[ 13 ]; 10882 position.z = te[ 14 ]; 10883 10884 const det = this.determinant(); 10885 10886 if ( det === 0 ) { 10887 10888 scale.set( 1, 1, 1 ); 10889 quaternion.identity(); 10890 10891 return this; 10892 10893 } 10894 10895 let sx = _v1$7.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); 10896 const sy = _v1$7.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); 10897 const sz = _v1$7.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); 10898 10899 // if determinant is negative, we need to invert one scale 10900 if ( det < 0 ) sx = - sx; 10901 10902 // scale the rotation part 10903 _m1$2.copy( this ); 10904 10905 const invSX = 1 / sx; 10906 const invSY = 1 / sy; 10907 const invSZ = 1 / sz; 10908 10909 _m1$2.elements[ 0 ] *= invSX; 10910 _m1$2.elements[ 1 ] *= invSX; 10911 _m1$2.elements[ 2 ] *= invSX; 10912 10913 _m1$2.elements[ 4 ] *= invSY; 10914 _m1$2.elements[ 5 ] *= invSY; 10915 _m1$2.elements[ 6 ] *= invSY; 10916 10917 _m1$2.elements[ 8 ] *= invSZ; 10918 _m1$2.elements[ 9 ] *= invSZ; 10919 _m1$2.elements[ 10 ] *= invSZ; 10920 10921 quaternion.setFromRotationMatrix( _m1$2 ); 10922 10923 scale.x = sx; 10924 scale.y = sy; 10925 scale.z = sz; 10926 10927 return this; 10928 10929 } 10930 10931 /** 10932 * Creates a perspective projection matrix. This is used internally by 10933 * {@link PerspectiveCamera#updateProjectionMatrix}. 10934 10935 * @param {number} left - Left boundary of the viewing frustum at the near plane. 10936 * @param {number} right - Right boundary of the viewing frustum at the near plane. 10937 * @param {number} top - Top boundary of the viewing frustum at the near plane. 10938 * @param {number} bottom - Bottom boundary of the viewing frustum at the near plane. 10939 * @param {number} near - The distance from the camera to the near plane. 10940 * @param {number} far - The distance from the camera to the far plane. 10941 * @param {(WebGLCoordinateSystem|WebGPUCoordinateSystem)} [coordinateSystem=WebGLCoordinateSystem] - The coordinate system. 10942 * @param {boolean} [reversedDepth=false] - Whether to use a reversed depth. 10943 * @return {Matrix4} A reference to this matrix. 10944 */ 10945 makePerspective( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem, reversedDepth = false ) { 10946 10947 const te = this.elements; 10948 10949 const x = 2 * near / ( right - left ); 10950 const y = 2 * near / ( top - bottom ); 10951 10952 const a = ( right + left ) / ( right - left ); 10953 const b = ( top + bottom ) / ( top - bottom ); 10954 10955 let c, d; 10956 10957 if ( reversedDepth ) { 10958 10959 c = near / ( far - near ); 10960 d = ( far * near ) / ( far - near ); 10961 10962 } else { 10963 10964 if ( coordinateSystem === WebGLCoordinateSystem ) { 10965 10966 c = - ( far + near ) / ( far - near ); 10967 d = ( -2 * far * near ) / ( far - near ); 10968 10969 } else if ( coordinateSystem === WebGPUCoordinateSystem ) { 10970 10971 c = - far / ( far - near ); 10972 d = ( - far * near ) / ( far - near ); 10973 10974 } else { 10975 10976 throw new Error( 'THREE.Matrix4.makePerspective(): Invalid coordinate system: ' + coordinateSystem ); 10977 10978 } 10979 10980 } 10981 10982 te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; 10983 te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; 10984 te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; 10985 te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = -1; te[ 15 ] = 0; 10986 10987 return this; 10988 10989 } 10990 10991 /** 10992 * Creates a orthographic projection matrix. This is used internally by 10993 * {@link OrthographicCamera#updateProjectionMatrix}. 10994 10995 * @param {number} left - Left boundary of the viewing frustum at the near plane. 10996 * @param {number} right - Right boundary of the viewing frustum at the near plane. 10997 * @param {number} top - Top boundary of the viewing frustum at the near plane. 10998 * @param {number} bottom - Bottom boundary of the viewing frustum at the near plane. 10999 * @param {number} near - The distance from the camera to the near plane. 11000 * @param {number} far - The distance from the camera to the far plane. 11001 * @param {(WebGLCoordinateSystem|WebGPUCoordinateSystem)} [coordinateSystem=WebGLCoordinateSystem] - The coordinate system. 11002 * @param {boolean} [reversedDepth=false] - Whether to use a reversed depth. 11003 * @return {Matrix4} A reference to this matrix. 11004 */ 11005 makeOrthographic( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem, reversedDepth = false ) { 11006 11007 const te = this.elements; 11008 11009 const x = 2 / ( right - left ); 11010 const y = 2 / ( top - bottom ); 11011 11012 const a = - ( right + left ) / ( right - left ); 11013 const b = - ( top + bottom ) / ( top - bottom ); 11014 11015 let c, d; 11016 11017 if ( reversedDepth ) { 11018 11019 c = 1 / ( far - near ); 11020 d = far / ( far - near ); 11021 11022 } else { 11023 11024 if ( coordinateSystem === WebGLCoordinateSystem ) { 11025 11026 c = -2 / ( far - near ); 11027 d = - ( far + near ) / ( far - near ); 11028 11029 } else if ( coordinateSystem === WebGPUCoordinateSystem ) { 11030 11031 c = -1 / ( far - near ); 11032 d = - near / ( far - near ); 11033 11034 } else { 11035 11036 throw new Error( 'THREE.Matrix4.makeOrthographic(): Invalid coordinate system: ' + coordinateSystem ); 11037 11038 } 11039 11040 } 11041 11042 te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = a; 11043 te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = 0; te[ 13 ] = b; 11044 te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; 11045 te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; 11046 11047 return this; 11048 11049 } 11050 11051 /** 11052 * Returns `true` if this matrix is equal with the given one. 11053 * 11054 * @param {Matrix4} matrix - The matrix to test for equality. 11055 * @return {boolean} Whether this matrix is equal with the given one. 11056 */ 11057 equals( matrix ) { 11058 11059 const te = this.elements; 11060 const me = matrix.elements; 11061 11062 for ( let i = 0; i < 16; i ++ ) { 11063 11064 if ( te[ i ] !== me[ i ] ) return false; 11065 11066 } 11067 11068 return true; 11069 11070 } 11071 11072 /** 11073 * Sets the elements of the matrix from the given array. 11074 * 11075 * @param {Array<number>} array - The matrix elements in column-major order. 11076 * @param {number} [offset=0] - Index of the first element in the array. 11077 * @return {Matrix4} A reference to this matrix. 11078 */ 11079 fromArray( array, offset = 0 ) { 11080 11081 for ( let i = 0; i < 16; i ++ ) { 11082 11083 this.elements[ i ] = array[ i + offset ]; 11084 11085 } 11086 11087 return this; 11088 11089 } 11090 11091 /** 11092 * Writes the elements of this matrix to the given array. If no array is provided, 11093 * the method returns a new instance. 11094 * 11095 * @param {Array<number>} [array=[]] - The target array holding the matrix elements in column-major order. 11096 * @param {number} [offset=0] - Index of the first element in the array. 11097 * @return {Array<number>} The matrix elements in column-major order. 11098 */ 11099 toArray( array = [], offset = 0 ) { 11100 11101 const te = this.elements; 11102 11103 array[ offset ] = te[ 0 ]; 11104 array[ offset + 1 ] = te[ 1 ]; 11105 array[ offset + 2 ] = te[ 2 ]; 11106 array[ offset + 3 ] = te[ 3 ]; 11107 11108 array[ offset + 4 ] = te[ 4 ]; 11109 array[ offset + 5 ] = te[ 5 ]; 11110 array[ offset + 6 ] = te[ 6 ]; 11111 array[ offset + 7 ] = te[ 7 ]; 11112 11113 array[ offset + 8 ] = te[ 8 ]; 11114 array[ offset + 9 ] = te[ 9 ]; 11115 array[ offset + 10 ] = te[ 10 ]; 11116 array[ offset + 11 ] = te[ 11 ]; 11117 11118 array[ offset + 12 ] = te[ 12 ]; 11119 array[ offset + 13 ] = te[ 13 ]; 11120 array[ offset + 14 ] = te[ 14 ]; 11121 array[ offset + 15 ] = te[ 15 ]; 11122 11123 return array; 11124 11125 } 11126 11127} 11128 11129const _v1$7 = /*@__PURE__*/ new Vector3(); 11130const _m1$2 = /*@__PURE__*/ new Matrix4(); 11131const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 ); 11132const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 ); 11133const _x = /*@__PURE__*/ new Vector3(); 11134const _y = /*@__PURE__*/ new Vector3(); 11135const _z = /*@__PURE__*/ new Vector3(); 11136 11137const _matrix$2 = /*@__PURE__*/ new Matrix4(); 11138const _quaternion$4 = /*@__PURE__*/ new Quaternion(); 11139 11140/** 11141 * A class representing Euler angles. 11142 * 11143 * Euler angles describe a rotational transformation by rotating an object on 11144 * its various axes in specified amounts per axis, and a specified axis 11145 * order. 11146 * 11147 * Iterating through an instance will yield its components (x, y, z, 11148 * order) in the corresponding order. 11149 * 11150 * ```js 11151 * const a = new THREE.Euler( 0, 1, 1.57, 'XYZ' ); 11152 * const b = new THREE.Vector3( 1, 0, 1 ); 11153 * b.applyEuler(a); 11154 * ``` 11155 */ 11156class Euler { 11157 11158 /** 11159 * Constructs a new euler instance. 11160 * 11161 * @param {number} [x=0] - The angle of the x axis in radians. 11162 * @param {number} [y=0] - The angle of the y axis in radians. 11163 * @param {number} [z=0] - The angle of the z axis in radians. 11164 * @param {string} [order=Euler.DEFAULT_ORDER] - A string representing the order that the rotations are applied. 11165 */ 11166 constructor( x = 0, y = 0, z = 0, order = Euler.DEFAULT_ORDER ) { 11167 11168 /** 11169 * This flag can be used for type testing. 11170 * 11171 * @type {boolean} 11172 * @readonly 11173 * @default true 11174 */ 11175 this.isEuler = true; 11176 11177 this._x = x; 11178 this._y = y; 11179 this._z = z; 11180 this._order = order; 11181 11182 } 11183
vendor: 33,636 bytes, lines 11184-12659
11184 /** 11185 * The angle of the x axis in radians. 11186 * 11187 * @type {number} 11188 * @default 0 11189 */ 11190 get x() { 11191 11192 return this._x; 11193 11194 } 11195 11196 set x( value ) { 11197 11198 this._x = value; 11199 this._onChangeCallback(); 11200 11201 } 11202 11203 /** 11204 * The angle of the y axis in radians. 11205 * 11206 * @type {number} 11207 * @default 0 11208 */ 11209 get y() { 11210 11211 return this._y; 11212 11213 } 11214 11215 set y( value ) { 11216 11217 this._y = value; 11218 this._onChangeCallback(); 11219 11220 } 11221 11222 /** 11223 * The angle of the z axis in radians. 11224 * 11225 * @type {number} 11226 * @default 0 11227 */ 11228 get z() { 11229 11230 return this._z; 11231 11232 } 11233 11234 set z( value ) { 11235 11236 this._z = value; 11237 this._onChangeCallback(); 11238 11239 } 11240 11241 /** 11242 * A string representing the order that the rotations are applied. 11243 * 11244 * @type {string} 11245 * @default 'XYZ' 11246 */ 11247 get order() { 11248 11249 return this._order; 11250 11251 } 11252 11253 set order( value ) { 11254 11255 this._order = value; 11256 this._onChangeCallback(); 11257 11258 } 11259 11260 /** 11261 * Sets the Euler components. 11262 * 11263 * @param {number} x - The angle of the x axis in radians. 11264 * @param {number} y - The angle of the y axis in radians. 11265 * @param {number} z - The angle of the z axis in radians. 11266 * @param {string} [order] - A string representing the order that the rotations are applied. 11267 * @return {Euler} A reference to this Euler instance. 11268 */ 11269 set( x, y, z, order = this._order ) { 11270 11271 this._x = x; 11272 this._y = y; 11273 this._z = z; 11274 this._order = order; 11275 11276 this._onChangeCallback(); 11277 11278 return this; 11279 11280 } 11281 11282 /** 11283 * Returns a new Euler instance with copied values from this instance. 11284 * 11285 * @return {Euler} A clone of this instance. 11286 */ 11287 clone() { 11288 11289 return new this.constructor( this._x, this._y, this._z, this._order ); 11290 11291 } 11292 11293 /** 11294 * Copies the values of the given Euler instance to this instance. 11295 * 11296 * @param {Euler} euler - The Euler instance to copy. 11297 * @return {Euler} A reference to this Euler instance. 11298 */ 11299 copy( euler ) { 11300 11301 this._x = euler._x; 11302 this._y = euler._y; 11303 this._z = euler._z; 11304 this._order = euler._order; 11305 11306 this._onChangeCallback(); 11307 11308 return this; 11309 11310 } 11311 11312 /** 11313 * Sets the angles of this Euler instance from a pure rotation matrix. 11314 * 11315 * @param {Matrix4} m - A 4x4 matrix of which the upper 3x3 of matrix is a pure rotation matrix (i.e. unscaled). 11316 * @param {string} [order] - A string representing the order that the rotations are applied. 11317 * @param {boolean} [update=true] - Whether the internal `onChange` callback should be executed or not. 11318 * @return {Euler} A reference to this Euler instance. 11319 */ 11320 setFromRotationMatrix( m, order = this._order, update = true ) { 11321 11322 const te = m.elements; 11323 const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ]; 11324 const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ]; 11325 const m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; 11326 11327 switch ( order ) { 11328 11329 case 'XYZ': 11330 11331 this._y = Math.asin( clamp( m13, -1, 1 ) ); 11332 11333 if ( Math.abs( m13 ) < 0.9999999 ) { 11334 11335 this._x = Math.atan2( - m23, m33 ); 11336 this._z = Math.atan2( - m12, m11 ); 11337 11338 } else { 11339 11340 this._x = Math.atan2( m32, m22 ); 11341 this._z = 0; 11342 11343 } 11344 11345 break; 11346 11347 case 'YXZ': 11348 11349 this._x = Math.asin( - clamp( m23, -1, 1 ) ); 11350 11351 if ( Math.abs( m23 ) < 0.9999999 ) { 11352 11353 this._y = Math.atan2( m13, m33 ); 11354 this._z = Math.atan2( m21, m22 ); 11355 11356 } else { 11357 11358 this._y = Math.atan2( - m31, m11 ); 11359 this._z = 0; 11360 11361 } 11362 11363 break; 11364 11365 case 'ZXY': 11366 11367 this._x = Math.asin( clamp( m32, -1, 1 ) ); 11368 11369 if ( Math.abs( m32 ) < 0.9999999 ) { 11370 11371 this._y = Math.atan2( - m31, m33 ); 11372 this._z = Math.atan2( - m12, m22 ); 11373 11374 } else { 11375 11376 this._y = 0; 11377 this._z = Math.atan2( m21, m11 ); 11378 11379 } 11380 11381 break; 11382 11383 case 'ZYX': 11384 11385 this._y = Math.asin( - clamp( m31, -1, 1 ) ); 11386 11387 if ( Math.abs( m31 ) < 0.9999999 ) { 11388 11389 this._x = Math.atan2( m32, m33 ); 11390 this._z = Math.atan2( m21, m11 ); 11391 11392 } else { 11393 11394 this._x = 0; 11395 this._z = Math.atan2( - m12, m22 ); 11396 11397 } 11398 11399 break; 11400 11401 case 'YZX': 11402 11403 this._z = Math.asin( clamp( m21, -1, 1 ) ); 11404 11405 if ( Math.abs( m21 ) < 0.9999999 ) { 11406 11407 this._x = Math.atan2( - m23, m22 ); 11408 this._y = Math.atan2( - m31, m11 ); 11409 11410 } else { 11411 11412 this._x = 0; 11413 this._y = Math.atan2( m13, m33 ); 11414 11415 } 11416 11417 break; 11418 11419 case 'XZY': 11420 11421 this._z = Math.asin( - clamp( m12, -1, 1 ) ); 11422 11423 if ( Math.abs( m12 ) < 0.9999999 ) { 11424 11425 this._x = Math.atan2( m32, m22 ); 11426 this._y = Math.atan2( m13, m11 ); 11427 11428 } else { 11429 11430 this._x = Math.atan2( - m23, m33 ); 11431 this._y = 0; 11432 11433 } 11434 11435 break; 11436 11437 default: 11438 11439 warn( 'Euler: .setFromRotationMatrix() encountered an unknown order: ' + order ); 11440 11441 } 11442 11443 this._order = order; 11444 11445 if ( update === true ) this._onChangeCallback(); 11446 11447 return this; 11448 11449 } 11450 11451 /** 11452 * Sets the angles of this Euler instance from a normalized quaternion. 11453 * 11454 * @param {Quaternion} q - A normalized Quaternion. 11455 * @param {string} [order] - A string representing the order that the rotations are applied. 11456 * @param {boolean} [update=true] - Whether the internal `onChange` callback should be executed or not. 11457 * @return {Euler} A reference to this Euler instance. 11458 */ 11459 setFromQuaternion( q, order, update ) { 11460 11461 _matrix$2.makeRotationFromQuaternion( q ); 11462 11463 return this.setFromRotationMatrix( _matrix$2, order, update ); 11464 11465 } 11466 11467 /** 11468 * Sets the angles of this Euler instance from the given vector. 11469 * 11470 * @param {Vector3} v - The vector. 11471 * @param {string} [order] - A string representing the order that the rotations are applied. 11472 * @return {Euler} A reference to this Euler instance. 11473 */ 11474 setFromVector3( v, order = this._order ) { 11475 11476 return this.set( v.x, v.y, v.z, order ); 11477 11478 } 11479 11480 /** 11481 * Resets the euler angle with a new order by creating a quaternion from this 11482 * euler angle and then setting this euler angle with the quaternion and the 11483 * new order. 11484 * 11485 * Warning: This discards revolution information. 11486 * 11487 * @param {string} [newOrder] - A string representing the new order that the rotations are applied. 11488 * @return {Euler} A reference to this Euler instance. 11489 */ 11490 reorder( newOrder ) { 11491 11492 _quaternion$4.setFromEuler( this ); 11493 11494 return this.setFromQuaternion( _quaternion$4, newOrder ); 11495 11496 } 11497 11498 /** 11499 * Returns `true` if this Euler instance is equal with the given one. 11500 * 11501 * @param {Euler} euler - The Euler instance to test for equality. 11502 * @return {boolean} Whether this Euler instance is equal with the given one. 11503 */ 11504 equals( euler ) { 11505 11506 return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); 11507 11508 } 11509 11510 /** 11511 * Sets this Euler instance's components to values from the given array. The first three 11512 * entries of the array are assign to the x,y and z components. An optional fourth entry 11513 * defines the Euler order. 11514 * 11515 * @param {Array<number,number,number,?string>} array - An array holding the Euler component values. 11516 * @return {Euler} A reference to this Euler instance. 11517 */ 11518 fromArray( array ) { 11519 11520 this._x = array[ 0 ]; 11521 this._y = array[ 1 ]; 11522 this._z = array[ 2 ]; 11523 if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; 11524 11525 this._onChangeCallback(); 11526 11527 return this; 11528 11529 } 11530 11531 /** 11532 * Writes the components of this Euler instance to the given array. If no array is provided, 11533 * the method returns a new instance. 11534 * 11535 * @param {Array<number,number,number,string>} [array=[]] - The target array holding the Euler components. 11536 * @param {number} [offset=0] - Index of the first element in the array. 11537 * @return {Array<number,number,number,string>} The Euler components. 11538 */ 11539 toArray( array = [], offset = 0 ) { 11540 11541 array[ offset ] = this._x; 11542 array[ offset + 1 ] = this._y; 11543 array[ offset + 2 ] = this._z; 11544 array[ offset + 3 ] = this._order; 11545 11546 return array; 11547 11548 } 11549 11550 _onChange( callback ) { 11551 11552 this._onChangeCallback = callback; 11553 11554 return this; 11555 11556 } 11557 11558 _onChangeCallback() {} 11559 11560 *[ Symbol.iterator ]() { 11561 11562 yield this._x; 11563 yield this._y; 11564 yield this._z; 11565 yield this._order; 11566 11567 } 11568 11569} 11570 11571/** 11572 * The default Euler angle order. 11573 * 11574 * @static 11575 * @type {string} 11576 * @default 'XYZ' 11577 */ 11578Euler.DEFAULT_ORDER = 'XYZ'; 11579 11580/** 11581 * A layers object assigns an 3D object to 1 or more of 32 11582 * layers numbered `0` to `31` - internally the layers are stored as a 11583 * bit mask], and by default all 3D objects are a member of layer `0`. 11584 * 11585 * This can be used to control visibility - an object must share a layer with 11586 * a camera to be visible when that camera's view is 11587 * rendered. 11588 * 11589 * All classes that inherit from {@link Object3D} have an `layers` property which 11590 * is an instance of this class. 11591 */ 11592class Layers { 11593 11594 /** 11595 * Constructs a new layers instance, with membership 11596 * initially set to layer `0`. 11597 */ 11598 constructor() { 11599 11600 /** 11601 * A bit mask storing which of the 32 layers this layers object is currently 11602 * a member of. 11603 * 11604 * @type {number} 11605 */ 11606 this.mask = 1 | 0; 11607 11608 } 11609 11610 /** 11611 * Sets membership to the given layer, and remove membership all other layers. 11612 * 11613 * @param {number} layer - The layer to set. 11614 */ 11615 set( layer ) { 11616 11617 this.mask = ( 1 << layer | 0 ) >>> 0; 11618 11619 } 11620 11621 /** 11622 * Adds membership of the given layer. 11623 * 11624 * @param {number} layer - The layer to enable. 11625 */ 11626 enable( layer ) { 11627 11628 this.mask |= 1 << layer | 0; 11629 11630 } 11631 11632 /** 11633 * Adds membership to all layers. 11634 */ 11635 enableAll() { 11636 11637 this.mask = 0xffffffff | 0; 11638 11639 } 11640 11641 /** 11642 * Toggles the membership of the given layer. 11643 * 11644 * @param {number} layer - The layer to toggle. 11645 */ 11646 toggle( layer ) { 11647 11648 this.mask ^= 1 << layer | 0; 11649 11650 } 11651 11652 /** 11653 * Removes membership of the given layer. 11654 * 11655 * @param {number} layer - The layer to enable. 11656 */ 11657 disable( layer ) { 11658 11659 this.mask &= ~ ( 1 << layer | 0 ); 11660 11661 } 11662 11663 /** 11664 * Removes the membership from all layers. 11665 */ 11666 disableAll() { 11667 11668 this.mask = 0; 11669 11670 } 11671 11672 /** 11673 * Returns `true` if this and the given layers object have at least one 11674 * layer in common. 11675 * 11676 * @param {Layers} layers - The layers to test. 11677 * @return {boolean } Whether this and the given layers object have at least one layer in common or not. 11678 */ 11679 test( layers ) { 11680 11681 return ( this.mask & layers.mask ) !== 0; 11682 11683 } 11684 11685 /** 11686 * Returns `true` if the given layer is enabled. 11687 * 11688 * @param {number} layer - The layer to test. 11689 * @return {boolean } Whether the given layer is enabled or not. 11690 */ 11691 isEnabled( layer ) { 11692 11693 return ( this.mask & ( 1 << layer | 0 ) ) !== 0; 11694 11695 } 11696 11697} 11698 11699let _object3DId = 0; 11700 11701const _v1$6 = /*@__PURE__*/ new Vector3(); 11702const _q1 = /*@__PURE__*/ new Quaternion(); 11703const _m1$1 = /*@__PURE__*/ new Matrix4(); 11704const _target = /*@__PURE__*/ new Vector3(); 11705 11706const _position$4 = /*@__PURE__*/ new Vector3(); 11707const _scale$3 = /*@__PURE__*/ new Vector3(); 11708const _quaternion$3 = /*@__PURE__*/ new Quaternion(); 11709 11710const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 ); 11711const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 ); 11712const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 ); 11713 11714/** 11715 * Fires when the object has been added to its parent object. 11716 * 11717 * @event Object3D#added 11718 * @type {Object} 11719 */ 11720const _addedEvent = { type: 'added' }; 11721 11722/** 11723 * Fires when the object has been removed from its parent object. 11724 * 11725 * @event Object3D#removed 11726 * @type {Object} 11727 */ 11728const _removedEvent = { type: 'removed' }; 11729 11730/** 11731 * Fires when a new child object has been added. 11732 * 11733 * @event Object3D#childadded 11734 * @type {Object} 11735 */ 11736const _childaddedEvent = { type: 'childadded', child: null }; 11737 11738/** 11739 * Fires when a child object has been removed. 11740 * 11741 * @event Object3D#childremoved 11742 * @type {Object} 11743 */ 11744const _childremovedEvent = { type: 'childremoved', child: null }; 11745 11746/** 11747 * This is the base class for most objects in three.js and provides a set of 11748 * properties and methods for manipulating objects in 3D space. 11749 * 11750 * @augments EventDispatcher 11751 */ 11752class Object3D extends EventDispatcher { 11753 11754 /** 11755 * Constructs a new 3D object. 11756 */ 11757 constructor() { 11758 11759 super(); 11760 11761 /** 11762 * This flag can be used for type testing. 11763 * 11764 * @type {boolean} 11765 * @readonly 11766 * @default true 11767 */ 11768 this.isObject3D = true; 11769 11770 /** 11771 * The ID of the 3D object. 11772 * 11773 * @name Object3D#id 11774 * @type {number} 11775 * @readonly 11776 */ 11777 Object.defineProperty( this, 'id', { value: _object3DId ++ } ); 11778 11779 /** 11780 * The UUID of the 3D object. 11781 * 11782 * @type {string} 11783 * @readonly 11784 */ 11785 this.uuid = generateUUID(); 11786 11787 /** 11788 * The name of the 3D object. 11789 * 11790 * @type {string} 11791 */ 11792 this.name = ''; 11793 11794 /** 11795 * The type property is used for detecting the object type 11796 * in context of serialization/deserialization. 11797 * 11798 * @type {string} 11799 * @readonly 11800 */ 11801 this.type = 'Object3D'; 11802 11803 /** 11804 * A reference to the parent object. 11805 * 11806 * @type {?Object3D} 11807 * @default null 11808 */ 11809 this.parent = null; 11810 11811 /** 11812 * An array holding the child 3D objects of this instance. 11813 * 11814 * @type {Array<Object3D>} 11815 */ 11816 this.children = []; 11817 11818 /** 11819 * Defines the `up` direction of the 3D object which influences 11820 * the orientation via methods like {@link Object3D#lookAt}. 11821 * 11822 * The default values for all 3D objects is defined by `Object3D.DEFAULT_UP`. 11823 * 11824 * @type {Vector3} 11825 */ 11826 this.up = Object3D.DEFAULT_UP.clone(); 11827 11828 const position = new Vector3(); 11829 const rotation = new Euler(); 11830 const quaternion = new Quaternion(); 11831 const scale = new Vector3( 1, 1, 1 ); 11832 11833 function onRotationChange() { 11834 11835 quaternion.setFromEuler( rotation, false ); 11836 11837 } 11838 11839 function onQuaternionChange() { 11840 11841 rotation.setFromQuaternion( quaternion, undefined, false ); 11842 11843 } 11844 11845 rotation._onChange( onRotationChange ); 11846 quaternion._onChange( onQuaternionChange ); 11847 11848 Object.defineProperties( this, { 11849 /** 11850 * Represents the object's local position. 11851 * 11852 * @name Object3D#position 11853 * @type {Vector3} 11854 * @default (0,0,0) 11855 */ 11856 position: { 11857 configurable: true, 11858 enumerable: true, 11859 value: position 11860 }, 11861 /** 11862 * Represents the object's local rotation as Euler angles, in radians. 11863 * 11864 * @name Object3D#rotation 11865 * @type {Euler} 11866 * @default (0,0,0) 11867 */ 11868 rotation: { 11869 configurable: true, 11870 enumerable: true, 11871 value: rotation 11872 }, 11873 /** 11874 * Represents the object's local rotation as Quaternions. 11875 * 11876 * @name Object3D#quaternion 11877 * @type {Quaternion} 11878 */ 11879 quaternion: { 11880 configurable: true, 11881 enumerable: true, 11882 value: quaternion 11883 }, 11884 /** 11885 * Represents the object's local scale. 11886 * 11887 * @name Object3D#scale 11888 * @type {Vector3} 11889 * @default (1,1,1) 11890 */ 11891 scale: { 11892 configurable: true, 11893 enumerable: true, 11894 value: scale 11895 }, 11896 /** 11897 * Represents the object's model-view matrix. 11898 * 11899 * @name Object3D#modelViewMatrix 11900 * @type {Matrix4} 11901 */ 11902 modelViewMatrix: { 11903 value: new Matrix4() 11904 }, 11905 /** 11906 * Represents the object's normal matrix. 11907 * 11908 * @name Object3D#normalMatrix 11909 * @type {Matrix3} 11910 */ 11911 normalMatrix: { 11912 value: new Matrix3() 11913 } 11914 } ); 11915 11916 /** 11917 * Represents the object's transformation matrix in local space. 11918 * 11919 * @type {Matrix4} 11920 */ 11921 this.matrix = new Matrix4(); 11922 11923 /** 11924 * Represents the object's transformation matrix in world space. 11925 * If the 3D object has no parent, then it's identical to the local transformation matrix 11926 * 11927 * @type {Matrix4} 11928 */ 11929 this.matrixWorld = new Matrix4(); 11930 11931 /** 11932 * When set to `true`, the engine automatically computes the local matrix from position, 11933 * rotation and scale every frame. If set to `false`, the app is responsible for recomputing 11934 * the local matrix by calling `updateMatrix()`. 11935 * 11936 * The default values for all 3D objects is defined by `Object3D.DEFAULT_MATRIX_AUTO_UPDATE`. 11937 * 11938 * @type {boolean} 11939 * @default true 11940 */ 11941 this.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE; 11942 11943 /** 11944 * When set to `true`, the engine automatically computes the world matrix from the current local 11945 * matrix and the object's transformation hierarchy. If set to `false`, the app is responsible for 11946 * recomputing the world matrix by directly updating the `matrixWorld` property. 11947 * 11948 * The default values for all 3D objects is defined by `Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE`. 11949 * 11950 * @type {boolean} 11951 * @default true 11952 */ 11953 this.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE; // checked by the renderer 11954 11955 /** 11956 * When set to `true`, it calculates the world matrix in that frame and resets this property 11957 * to `false`. 11958 * 11959 * @type {boolean} 11960 * @default false 11961 */ 11962 this.matrixWorldNeedsUpdate = false; 11963 11964 /** 11965 * The layer membership of the 3D object. The 3D object is only visible if it has 11966 * at least one layer in common with the camera in use. This property can also be 11967 * used to filter out unwanted objects in ray-intersection tests when using {@link Raycaster}. 11968 * 11969 * @type {Layers} 11970 */ 11971 this.layers = new Layers(); 11972 11973 /** 11974 * When set to `true`, the 3D object gets rendered. 11975 * 11976 * @type {boolean} 11977 * @default true 11978 */ 11979 this.visible = true; 11980 11981 /** 11982 * When set to `true`, the 3D object gets rendered into shadow maps. 11983 * 11984 * @type {boolean} 11985 * @default false 11986 */ 11987 this.castShadow = false; 11988 11989 /** 11990 * When set to `true`, the 3D object is affected by shadows in the scene. 11991 * 11992 * @type {boolean} 11993 * @default false 11994 */ 11995 this.receiveShadow = false; 11996 11997 /** 11998 * When set to `true`, the 3D object is honored by view frustum culling. 11999 * 12000 * @type {boolean} 12001 * @default true 12002 */ 12003 this.frustumCulled = true; 12004 12005 /** 12006 * This value allows the default rendering order of scene graph objects to be 12007 * overridden although opaque and transparent objects remain sorted independently. 12008 * When this property is set for an instance of {@link Group},all descendants 12009 * objects will be sorted and rendered together. Sorting is from lowest to highest 12010 * render order. 12011 * 12012 * @type {number} 12013 * @default 0 12014 */ 12015 this.renderOrder = 0; 12016 12017 /** 12018 * An array holding the animation clips of the 3D object. 12019 * 12020 * @type {Array<AnimationClip>} 12021 */ 12022 this.animations = []; 12023 12024 /** 12025 * Custom depth material to be used when rendering to the depth map. Can only be used 12026 * in context of meshes. When shadow-casting with a {@link DirectionalLight} or {@link SpotLight}, 12027 * if you are modifying vertex positions in the vertex shader you must specify a custom depth 12028 * material for proper shadows. 12029 * 12030 * Only relevant in context of {@link WebGLRenderer}. 12031 * 12032 * @type {(Material|undefined)} 12033 * @default undefined 12034 */ 12035 this.customDepthMaterial = undefined; 12036 12037 /** 12038 * Same as {@link Object3D#customDepthMaterial}, but used with {@link PointLight}. 12039 * 12040 * Only relevant in context of {@link WebGLRenderer}. 12041 * 12042 * @type {(Material|undefined)} 12043 * @default undefined 12044 */ 12045 this.customDistanceMaterial = undefined; 12046 12047 /** 12048 * Whether the 3D object is supposed to be static or not. If set to `true`, it means 12049 * the 3D object is not going to be changed after the initial renderer. This includes 12050 * geometry and material settings. A static 3D object can be processed by the renderer 12051 * slightly faster since certain state checks can be bypassed. 12052 * 12053 * Only relevant in context of {@link WebGPURenderer}. 12054 * 12055 * @type {boolean} 12056 * @default false 12057 */ 12058 this.static = false; 12059 12060 /** 12061 * An object that can be used to store custom data about the 3D object. It 12062 * should not hold references to functions as these will not be cloned. 12063 * 12064 * @type {Object} 12065 */ 12066 this.userData = {}; 12067 12068 /** 12069 * The pivot point for rotation and scale transformations. 12070 * When set, rotation and scale are applied around this point 12071 * instead of the object's origin. 12072 * 12073 * @type {?Vector3} 12074 * @default null 12075 */ 12076 this.pivot = null; 12077 12078 } 12079 12080 /** 12081 * A callback that is executed immediately before a 3D object is rendered to a shadow map. 12082 * 12083 * @param {Renderer|WebGLRenderer} renderer - The renderer. 12084 * @param {Object3D} object - The 3D object. 12085 * @param {Camera} camera - The camera that is used to render the scene. 12086 * @param {Camera} shadowCamera - The shadow camera. 12087 * @param {BufferGeometry} geometry - The 3D object's geometry. 12088 * @param {Material} depthMaterial - The depth material. 12089 * @param {Object} group - The geometry group data. 12090 */ 12091 onBeforeShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {} 12092 12093 /** 12094 * A callback that is executed immediately after a 3D object is rendered to a shadow map. 12095 * 12096 * @param {Renderer|WebGLRenderer} renderer - The renderer. 12097 * @param {Object3D} object - The 3D object. 12098 * @param {Camera} camera - The camera that is used to render the scene. 12099 * @param {Camera} shadowCamera - The shadow camera. 12100 * @param {BufferGeometry} geometry - The 3D object's geometry. 12101 * @param {Material} depthMaterial - The depth material. 12102 * @param {Object} group - The geometry group data. 12103 */ 12104 onAfterShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {} 12105 12106 /** 12107 * A callback that is executed immediately before a 3D object is rendered. 12108 * 12109 * @param {Renderer|WebGLRenderer} renderer - The renderer. 12110 * @param {Object3D} object - The 3D object. 12111 * @param {Camera} camera - The camera that is used to render the scene. 12112 * @param {BufferGeometry} geometry - The 3D object's geometry. 12113 * @param {Material} material - The 3D object's material. 12114 * @param {Object} group - The geometry group data. 12115 */ 12116 onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {} 12117 12118 /** 12119 * A callback that is executed immediately after a 3D object is rendered. 12120 * 12121 * @param {Renderer|WebGLRenderer} renderer - The renderer. 12122 * @param {Object3D} object - The 3D object. 12123 * @param {Camera} camera - The camera that is used to render the scene. 12124 * @param {BufferGeometry} geometry - The 3D object's geometry. 12125 * @param {Material} material - The 3D object's material. 12126 * @param {Object} group - The geometry group data. 12127 */ 12128 onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {} 12129 12130 /** 12131 * Applies the given transformation matrix to the object and updates the object's position, 12132 * rotation and scale. 12133 * 12134 * @param {Matrix4} matrix - The transformation matrix. 12135 */ 12136 applyMatrix4( matrix ) { 12137 12138 if ( this.matrixAutoUpdate ) this.updateMatrix(); 12139 12140 this.matrix.premultiply( matrix ); 12141 12142 this.matrix.decompose( this.position, this.quaternion, this.scale ); 12143 12144 } 12145 12146 /** 12147 * Applies a rotation represented by given the quaternion to the 3D object. 12148 * 12149 * @param {Quaternion} q - The quaternion. 12150 * @return {Object3D} A reference to this instance. 12151 */ 12152 applyQuaternion( q ) { 12153 12154 this.quaternion.premultiply( q ); 12155 12156 return this; 12157 12158 } 12159 12160 /** 12161 * Sets the given rotation represented as an axis/angle couple to the 3D object. 12162 * 12163 * @param {Vector3} axis - The (normalized) axis vector. 12164 * @param {number} angle - The angle in radians. 12165 */ 12166 setRotationFromAxisAngle( axis, angle ) { 12167 12168 // assumes axis is normalized 12169 12170 this.quaternion.setFromAxisAngle( axis, angle ); 12171 12172 } 12173 12174 /** 12175 * Sets the given rotation represented as Euler angles to the 3D object. 12176 * 12177 * @param {Euler} euler - The Euler angles. 12178 */ 12179 setRotationFromEuler( euler ) { 12180 12181 this.quaternion.setFromEuler( euler, true ); 12182 12183 } 12184 12185 /** 12186 * Sets the given rotation represented as rotation matrix to the 3D object. 12187 * 12188 * @param {Matrix4} m - Although a 4x4 matrix is expected, the upper 3x3 portion must be 12189 * a pure rotation matrix (i.e, unscaled). 12190 */ 12191 setRotationFromMatrix( m ) { 12192 12193 // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) 12194 12195 this.quaternion.setFromRotationMatrix( m ); 12196 12197 } 12198 12199 /** 12200 * Sets the given rotation represented as a Quaternion to the 3D object. 12201 * 12202 * @param {Quaternion} q - The Quaternion 12203 */ 12204 setRotationFromQuaternion( q ) { 12205 12206 // assumes q is normalized 12207 12208 this.quaternion.copy( q ); 12209 12210 } 12211 12212 /** 12213 * Rotates the 3D object along an axis in local space. 12214 * 12215 * @param {Vector3} axis - The (normalized) axis vector. 12216 * @param {number} angle - The angle in radians. 12217 * @return {Object3D} A reference to this instance. 12218 */ 12219 rotateOnAxis( axis, angle ) { 12220 12221 // rotate object on axis in object space 12222 // axis is assumed to be normalized 12223 12224 _q1.setFromAxisAngle( axis, angle ); 12225 12226 this.quaternion.multiply( _q1 ); 12227 12228 return this; 12229 12230 } 12231 12232 /** 12233 * Rotates the 3D object along an axis in world space. 12234 * 12235 * @param {Vector3} axis - The (normalized) axis vector. 12236 * @param {number} angle - The angle in radians. 12237 * @return {Object3D} A reference to this instance. 12238 */ 12239 rotateOnWorldAxis( axis, angle ) { 12240 12241 // rotate object on axis in world space 12242 // axis is assumed to be normalized 12243 // method assumes no rotated parent 12244 12245 _q1.setFromAxisAngle( axis, angle ); 12246 12247 this.quaternion.premultiply( _q1 ); 12248 12249 return this; 12250 12251 } 12252 12253 /** 12254 * Rotates the 3D object around its X axis in local space. 12255 * 12256 * @param {number} angle - The angle in radians. 12257 * @return {Object3D} A reference to this instance. 12258 */ 12259 rotateX( angle ) { 12260 12261 return this.rotateOnAxis( _xAxis, angle ); 12262 12263 } 12264 12265 /** 12266 * Rotates the 3D object around its Y axis in local space. 12267 * 12268 * @param {number} angle - The angle in radians. 12269 * @return {Object3D} A reference to this instance. 12270 */ 12271 rotateY( angle ) { 12272 12273 return this.rotateOnAxis( _yAxis, angle ); 12274 12275 } 12276 12277 /** 12278 * Rotates the 3D object around its Z axis in local space. 12279 * 12280 * @param {number} angle - The angle in radians. 12281 * @return {Object3D} A reference to this instance. 12282 */ 12283 rotateZ( angle ) { 12284 12285 return this.rotateOnAxis( _zAxis, angle ); 12286 12287 } 12288 12289 /** 12290 * Translate the 3D object by a distance along the given axis in local space. 12291 * 12292 * @param {Vector3} axis - The (normalized) axis vector. 12293 * @param {number} distance - The distance in world units. 12294 * @return {Object3D} A reference to this instance. 12295 */ 12296 translateOnAxis( axis, distance ) { 12297 12298 // translate object by distance along axis in object space 12299 // axis is assumed to be normalized 12300 12301 _v1$6.copy( axis ).applyQuaternion( this.quaternion ); 12302 12303 this.position.add( _v1$6.multiplyScalar( distance ) ); 12304 12305 return this; 12306 12307 } 12308 12309 /** 12310 * Translate the 3D object by a distance along its X-axis in local space. 12311 * 12312 * @param {number} distance - The distance in world units. 12313 * @return {Object3D} A reference to this instance. 12314 */ 12315 translateX( distance ) { 12316 12317 return this.translateOnAxis( _xAxis, distance ); 12318 12319 } 12320 12321 /** 12322 * Translate the 3D object by a distance along its Y-axis in local space. 12323 * 12324 * @param {number} distance - The distance in world units. 12325 * @return {Object3D} A reference to this instance. 12326 */ 12327 translateY( distance ) { 12328 12329 return this.translateOnAxis( _yAxis, distance ); 12330 12331 } 12332 12333 /** 12334 * Translate the 3D object by a distance along its Z-axis in local space. 12335 * 12336 * @param {number} distance - The distance in world units. 12337 * @return {Object3D} A reference to this instance. 12338 */ 12339 translateZ( distance ) { 12340 12341 return this.translateOnAxis( _zAxis, distance ); 12342 12343 } 12344 12345 /** 12346 * Converts the given vector from this 3D object's local space to world space. 12347 * 12348 * @param {Vector3} vector - The vector to convert. 12349 * @return {Vector3} The converted vector. 12350 */ 12351 localToWorld( vector ) { 12352 12353 this.updateWorldMatrix( true, false ); 12354 12355 return vector.applyMatrix4( this.matrixWorld ); 12356 12357 } 12358 12359 /** 12360 * Converts the given vector from this 3D object's world space to local space. 12361 * 12362 * @param {Vector3} vector - The vector to convert. 12363 * @return {Vector3} The converted vector. 12364 */ 12365 worldToLocal( vector ) { 12366 12367 this.updateWorldMatrix( true, false ); 12368 12369 return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() ); 12370 12371 } 12372 12373 /** 12374 * Rotates the object to face a point in world space. 12375 * 12376 * This method does not support objects having non-uniformly-scaled parent(s). 12377 * 12378 * @param {number|Vector3} x - The x coordinate in world space. Alternatively, a vector representing a position in world space 12379 * @param {number} [y] - The y coordinate in world space. 12380 * @param {number} [z] - The z coordinate in world space. 12381 */ 12382 lookAt( x, y, z ) { 12383 12384 // This method does not support objects having non-uniformly-scaled parent(s) 12385 12386 if ( x.isVector3 ) { 12387 12388 _target.copy( x ); 12389 12390 } else { 12391 12392 _target.set( x, y, z ); 12393 12394 } 12395 12396 const parent = this.parent; 12397 12398 this.updateWorldMatrix( true, false ); 12399 12400 _position$4.setFromMatrixPosition( this.matrixWorld ); 12401 12402 if ( this.isCamera || this.isLight ) { 12403 12404 _m1$1.lookAt( _position$4, _target, this.up ); 12405 12406 } else { 12407 12408 _m1$1.lookAt( _target, _position$4, this.up ); 12409 12410 } 12411 12412 this.quaternion.setFromRotationMatrix( _m1$1 ); 12413 12414 if ( parent ) { 12415 12416 _m1$1.extractRotation( parent.matrixWorld ); 12417 _q1.setFromRotationMatrix( _m1$1 ); 12418 this.quaternion.premultiply( _q1.invert() ); 12419 12420 } 12421 12422 } 12423 12424 /** 12425 * Adds the given 3D object as a child to this 3D object. An arbitrary number of 12426 * objects may be added. Any current parent on an object passed in here will be 12427 * removed, since an object can have at most one parent. 12428 * 12429 * @fires Object3D#added 12430 * @fires Object3D#childadded 12431 * @param {Object3D} object - The 3D object to add. 12432 * @return {Object3D} A reference to this instance. 12433 */ 12434 add( object ) { 12435 12436 if ( arguments.length > 1 ) { 12437 12438 for ( let i = 0; i < arguments.length; i ++ ) { 12439 12440 this.add( arguments[ i ] ); 12441 12442 } 12443 12444 return this; 12445 12446 } 12447 12448 if ( object === this ) { 12449 12450 error( 'Object3D.add: object can\'t be added as a child of itself.', object ); 12451 return this; 12452 12453 } 12454 12455 if ( object && object.isObject3D ) { 12456 12457 object.removeFromParent(); 12458 object.parent = this; 12459 this.children.push( object ); 12460 12461 object.dispatchEvent( _addedEvent ); 12462 12463 _childaddedEvent.child = object; 12464 this.dispatchEvent( _childaddedEvent ); 12465 _childaddedEvent.child = null; 12466 12467 } else { 12468 12469 error( 'Object3D.add: object not an instance of THREE.Object3D.', object ); 12470 12471 } 12472 12473 return this; 12474 12475 } 12476 12477 /** 12478 * Removes the given 3D object as child from this 3D object. 12479 * An arbitrary number of objects may be removed. 12480 * 12481 * @fires Object3D#removed 12482 * @fires Object3D#childremoved 12483 * @param {Object3D} object - The 3D object to remove. 12484 * @return {Object3D} A reference to this instance. 12485 */ 12486 remove( object ) { 12487 12488 if ( arguments.length > 1 ) { 12489 12490 for ( let i = 0; i < arguments.length; i ++ ) { 12491 12492 this.remove( arguments[ i ] ); 12493 12494 } 12495 12496 return this; 12497 12498 } 12499 12500 const index = this.children.indexOf( object ); 12501 12502 if ( index !== -1 ) { 12503 12504 object.parent = null; 12505 this.children.splice( index, 1 ); 12506 12507 object.dispatchEvent( _removedEvent ); 12508 12509 _childremovedEvent.child = object; 12510 this.dispatchEvent( _childremovedEvent ); 12511 _childremovedEvent.child = null; 12512 12513 } 12514 12515 return this; 12516 12517 } 12518 12519 /** 12520 * Removes this 3D object from its current parent. 12521 * 12522 * @fires Object3D#removed 12523 * @fires Object3D#childremoved 12524 * @return {Object3D} A reference to this instance. 12525 */ 12526 removeFromParent() { 12527 12528 const parent = this.parent; 12529 12530 if ( parent !== null ) { 12531 12532 parent.remove( this ); 12533 12534 } 12535 12536 return this; 12537 12538 } 12539 12540 /** 12541 * Removes all child objects. 12542 * 12543 * @fires Object3D#removed 12544 * @fires Object3D#childremoved 12545 * @return {Object3D} A reference to this instance. 12546 */ 12547 clear() { 12548 12549 return this.remove( ... this.children ); 12550 12551 } 12552 12553 /** 12554 * Adds the given 3D object as a child of this 3D object, while maintaining the object's world 12555 * transform. This method does not support scene graphs having non-uniformly-scaled nodes(s). 12556 * 12557 * @fires Object3D#added 12558 * @fires Object3D#childadded 12559 * @param {Object3D} object - The 3D object to attach. 12560 * @return {Object3D} A reference to this instance. 12561 */ 12562 attach( object ) { 12563 12564 // adds object as a child of this, while maintaining the object's world transform 12565 12566 // Note: This method does not support scene graphs having non-uniformly-scaled nodes(s) 12567 12568 this.updateWorldMatrix( true, false ); 12569 12570 _m1$1.copy( this.matrixWorld ).invert(); 12571 12572 if ( object.parent !== null ) { 12573 12574 object.parent.updateWorldMatrix( true, false ); 12575 12576 _m1$1.multiply( object.parent.matrixWorld ); 12577 12578 } 12579 12580 object.applyMatrix4( _m1$1 ); 12581 12582 object.removeFromParent(); 12583 object.parent = this; 12584 this.children.push( object ); 12585 12586 object.updateWorldMatrix( false, true ); 12587 12588 object.dispatchEvent( _addedEvent ); 12589 12590 _childaddedEvent.child = object; 12591 this.dispatchEvent( _childaddedEvent ); 12592 _childaddedEvent.child = null; 12593 12594 return this; 12595 12596 } 12597 12598 /** 12599 * Searches through the 3D object and its children, starting with the 3D object 12600 * itself, and returns the first with a matching ID. 12601 * 12602 * @param {number} id - The id. 12603 * @return {Object3D|undefined} The found 3D object. Returns `undefined` if no 3D object has been found. 12604 */ 12605 getObjectById( id ) { 12606 12607 return this.getObjectByProperty( 'id', id ); 12608 12609 } 12610 12611 /** 12612 * Searches through the 3D object and its children, starting with the 3D object 12613 * itself, and returns the first with a matching name. 12614 * 12615 * @param {string} name - The name. 12616 * @return {Object3D|undefined} The found 3D object. Returns `undefined` if no 3D object has been found. 12617 */ 12618 getObjectByName( name ) { 12619 12620 return this.getObjectByProperty( 'name', name ); 12621 12622 } 12623 12624 /** 12625 * Searches through the 3D object and its children, starting with the 3D object 12626 * itself, and returns the first with a matching property value. 12627 * 12628 * @param {string} name - The name of the property. 12629 * @param {any} value - The value. 12630 * @return {Object3D|undefined} The found 3D object. Returns `undefined` if no 3D object has been found. 12631 */ 12632 getObjectByProperty( name, value ) { 12633 12634 if ( this[ name ] === value ) return this; 12635 12636 for ( let i = 0, l = this.children.length; i < l; i ++ ) { 12637 12638 const child = this.children[ i ]; 12639 const object = child.getObjectByProperty( name, value ); 12640 12641 if ( object !== undefined ) { 12642 12643 return object; 12644 12645 } 12646 12647 } 12648 12649 return undefined; 12650 12651 } 12652 12653 /** 12654 * Searches through the 3D object and its children, starting with the 3D object 12655 * itself, and returns all 3D objects with a matching property value. 12656 * 12657 * @param {string} name - The name of the property. 12658 * @param {any} value - The value. 12659 * @param {Array<Object3D>} result - The method stores the result in this array.
vendor: 15,125 bytes, lines 12660-13283
12660 * @return {Array<Object3D>} The found 3D objects. 12661 */ 12662 getObjectsByProperty( name, value, result = [] ) { 12663 12664 if ( this[ name ] === value ) result.push( this ); 12665 12666 const children = this.children; 12667 12668 for ( let i = 0, l = children.length; i < l; i ++ ) { 12669 12670 children[ i ].getObjectsByProperty( name, value, result ); 12671 12672 } 12673 12674 return result; 12675 12676 } 12677 12678 /** 12679 * Returns a vector representing the position of the 3D object in world space. 12680 * 12681 * @param {Vector3} target - The target vector the result is stored to. 12682 * @return {Vector3} The 3D object's position in world space. 12683 */ 12684 getWorldPosition( target ) { 12685 12686 this.updateWorldMatrix( true, false ); 12687 12688 return target.setFromMatrixPosition( this.matrixWorld ); 12689 12690 } 12691 12692 /** 12693 * Returns a Quaternion representing the position of the 3D object in world space. 12694 * 12695 * @param {Quaternion} target - The target Quaternion the result is stored to. 12696 * @return {Quaternion} The 3D object's rotation in world space. 12697 */ 12698 getWorldQuaternion( target ) { 12699 12700 this.updateWorldMatrix( true, false ); 12701 12702 this.matrixWorld.decompose( _position$4, target, _scale$3 ); 12703 12704 return target; 12705 12706 } 12707 12708 /** 12709 * Returns a vector representing the scale of the 3D object in world space. 12710 * 12711 * @param {Vector3} target - The target vector the result is stored to. 12712 * @return {Vector3} The 3D object's scale in world space. 12713 */ 12714 getWorldScale( target ) { 12715 12716 this.updateWorldMatrix( true, false ); 12717 12718 this.matrixWorld.decompose( _position$4, _quaternion$3, target ); 12719 12720 return target; 12721 12722 } 12723 12724 /** 12725 * Returns a vector representing the ("look") direction of the 3D object in world space. 12726 * 12727 * @param {Vector3} target - The target vector the result is stored to. 12728 * @return {Vector3} The 3D object's direction in world space. 12729 */ 12730 getWorldDirection( target ) { 12731 12732 this.updateWorldMatrix( true, false ); 12733 12734 const e = this.matrixWorld.elements; 12735 12736 return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize(); 12737 12738 } 12739 12740 /** 12741 * Abstract method to get intersections between a casted ray and this 12742 * 3D object. Renderable 3D objects such as {@link Mesh}, {@link Line} or {@link Points} 12743 * implement this method in order to use raycasting. 12744 * 12745 * @abstract 12746 * @param {Raycaster} raycaster - The raycaster. 12747 * @param {Array<Object>} intersects - An array holding the result of the method. 12748 */ 12749 raycast( /* raycaster, intersects */ ) {} 12750 12751 /** 12752 * Executes the callback on this 3D object and all descendants. 12753 * 12754 * Note: Modifying the scene graph inside the callback is discouraged. 12755 * 12756 * @param {Function} callback - A callback function that allows to process the current 3D object. 12757 */ 12758 traverse( callback ) { 12759 12760 callback( this ); 12761 12762 const children = this.children; 12763 12764 for ( let i = 0, l = children.length; i < l; i ++ ) { 12765 12766 children[ i ].traverse( callback ); 12767 12768 } 12769 12770 } 12771 12772 /** 12773 * Like {@link Object3D#traverse}, but the callback will only be executed for visible 3D objects. 12774 * Descendants of invisible 3D objects are not traversed. 12775 * 12776 * Note: Modifying the scene graph inside the callback is discouraged. 12777 * 12778 * @param {Function} callback - A callback function that allows to process the current 3D object. 12779 */ 12780 traverseVisible( callback ) { 12781 12782 if ( this.visible === false ) return; 12783 12784 callback( this ); 12785 12786 const children = this.children; 12787 12788 for ( let i = 0, l = children.length; i < l; i ++ ) { 12789 12790 children[ i ].traverseVisible( callback ); 12791 12792 } 12793 12794 } 12795 12796 /** 12797 * Like {@link Object3D#traverse}, but the callback will only be executed for all ancestors. 12798 * 12799 * Note: Modifying the scene graph inside the callback is discouraged. 12800 * 12801 * @param {Function} callback - A callback function that allows to process the current 3D object. 12802 */ 12803 traverseAncestors( callback ) { 12804 12805 const parent = this.parent; 12806 12807 if ( parent !== null ) { 12808 12809 callback( parent ); 12810 12811 parent.traverseAncestors( callback ); 12812 12813 } 12814 12815 } 12816 12817 /** 12818 * Updates the transformation matrix in local space by computing it from the current 12819 * position, rotation and scale values. 12820 */ 12821 updateMatrix() { 12822 12823 this.matrix.compose( this.position, this.quaternion, this.scale ); 12824 12825 const pivot = this.pivot; 12826 12827 if ( pivot !== null ) { 12828 12829 const px = pivot.x, py = pivot.y, pz = pivot.z; 12830 const te = this.matrix.elements; 12831 12832 te[ 12 ] += px - te[ 0 ] * px - te[ 4 ] * py - te[ 8 ] * pz; 12833 te[ 13 ] += py - te[ 1 ] * px - te[ 5 ] * py - te[ 9 ] * pz; 12834 te[ 14 ] += pz - te[ 2 ] * px - te[ 6 ] * py - te[ 10 ] * pz; 12835 12836 } 12837 12838 this.matrixWorldNeedsUpdate = true; 12839 12840 } 12841 12842 /** 12843 * Updates the transformation matrix in world space of this 3D objects and its descendants. 12844 * 12845 * To ensure correct results, this method also recomputes the 3D object's transformation matrix in 12846 * local space. The computation of the local and world matrix can be controlled with the 12847 * {@link Object3D#matrixAutoUpdate} and {@link Object3D#matrixWorldAutoUpdate} flags which are both 12848 * `true` by default. Set these flags to `false` if you need more control over the update matrix process. 12849 * 12850 * @param {boolean} [force=false] - When set to `true`, a recomputation of world matrices is forced even 12851 * when {@link Object3D#matrixWorldNeedsUpdate} is `false`. 12852 */ 12853 updateMatrixWorld( force ) { 12854 12855 if ( this.matrixAutoUpdate ) this.updateMatrix(); 12856 12857 if ( this.matrixWorldNeedsUpdate || force ) { 12858 12859 if ( this.matrixWorldAutoUpdate === true ) { 12860 12861 if ( this.parent === null ) { 12862 12863 this.matrixWorld.copy( this.matrix ); 12864 12865 } else { 12866 12867 this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); 12868 12869 } 12870 12871 } 12872 12873 this.matrixWorldNeedsUpdate = false; 12874 12875 force = true; 12876 12877 } 12878 12879 // make sure descendants are updated if required 12880 12881 const children = this.children; 12882 12883 for ( let i = 0, l = children.length; i < l; i ++ ) { 12884 12885 const child = children[ i ]; 12886 12887 child.updateMatrixWorld( force ); 12888 12889 } 12890 12891 } 12892 12893 /** 12894 * An alternative version of {@link Object3D#updateMatrixWorld} with more control over the 12895 * update of ancestor and descendant nodes. 12896 * 12897 * @param {boolean} [updateParents=false] Whether ancestor nodes should be updated or not. 12898 * @param {boolean} [updateChildren=false] Whether descendant nodes should be updated or not. 12899 */ 12900 updateWorldMatrix( updateParents, updateChildren ) { 12901 12902 const parent = this.parent; 12903 12904 if ( updateParents === true && parent !== null ) { 12905 12906 parent.updateWorldMatrix( true, false ); 12907 12908 } 12909 12910 if ( this.matrixAutoUpdate ) this.updateMatrix(); 12911 12912 if ( this.matrixWorldAutoUpdate === true ) { 12913 12914 if ( this.parent === null ) { 12915 12916 this.matrixWorld.copy( this.matrix ); 12917 12918 } else { 12919 12920 this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); 12921 12922 } 12923 12924 } 12925 12926 // make sure descendants are updated 12927 12928 if ( updateChildren === true ) { 12929 12930 const children = this.children; 12931 12932 for ( let i = 0, l = children.length; i < l; i ++ ) { 12933 12934 const child = children[ i ]; 12935 12936 child.updateWorldMatrix( false, true ); 12937 12938 } 12939 12940 } 12941 12942 } 12943 12944 /** 12945 * Serializes the 3D object into JSON. 12946 * 12947 * @param {?(Object|string)} meta - An optional value holding meta information about the serialization. 12948 * @return {Object} A JSON object representing the serialized 3D object. 12949 * @see {@link ObjectLoader#parse} 12950 */ 12951 toJSON( meta ) { 12952 12953 // meta is a string when called from JSON.stringify 12954 const isRootObject = ( meta === undefined || typeof meta === 'string' ); 12955 12956 const output = {}; 12957 12958 // meta is a hash used to collect geometries, materials. 12959 // not providing it implies that this is the root object 12960 // being serialized. 12961 if ( isRootObject ) { 12962 12963 // initialize meta obj 12964 meta = { 12965 geometries: {}, 12966 materials: {}, 12967 textures: {}, 12968 images: {}, 12969 shapes: {}, 12970 skeletons: {}, 12971 animations: {}, 12972 nodes: {} 12973 }; 12974 12975 output.metadata = { 12976 version: 4.7, 12977 type: 'Object', 12978 generator: 'Object3D.toJSON' 12979 }; 12980 12981 } 12982 12983 // standard Object3D serialization 12984 12985 const object = {}; 12986 12987 object.uuid = this.uuid; 12988 object.type = this.type; 12989 12990 if ( this.name !== '' ) object.name = this.name; 12991 if ( this.castShadow === true ) object.castShadow = true; 12992 if ( this.receiveShadow === true ) object.receiveShadow = true; 12993 if ( this.visible === false ) object.visible = false; 12994 if ( this.frustumCulled === false ) object.frustumCulled = false; 12995 if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder; 12996 if ( this.static !== false ) object.static = this.static; 12997 if ( Object.keys( this.userData ).length > 0 ) object.userData = this.userData; 12998 12999 object.layers = this.layers.mask; 13000 object.matrix = this.matrix.toArray(); 13001 object.up = this.up.toArray(); 13002 13003 if ( this.pivot !== null ) object.pivot = this.pivot.toArray(); 13004 13005 if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false; 13006 13007 if ( this.morphTargetDictionary !== undefined ) object.morphTargetDictionary = Object.assign( {}, this.morphTargetDictionary ); 13008 if ( this.morphTargetInfluences !== undefined ) object.morphTargetInfluences = this.morphTargetInfluences.slice(); 13009 13010 // object specific properties 13011 13012 if ( this.isInstancedMesh ) { 13013 13014 object.type = 'InstancedMesh'; 13015 object.count = this.count; 13016 object.instanceMatrix = this.instanceMatrix.toJSON(); 13017 if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON(); 13018 13019 } 13020 13021 if ( this.isBatchedMesh ) { 13022 13023 object.type = 'BatchedMesh'; 13024 object.perObjectFrustumCulled = this.perObjectFrustumCulled; 13025 object.sortObjects = this.sortObjects; 13026 13027 object.drawRanges = this._drawRanges; 13028 object.reservedRanges = this._reservedRanges; 13029 13030 object.geometryInfo = this._geometryInfo.map( info => ( { 13031 ...info, 13032 boundingBox: info.boundingBox ? info.boundingBox.toJSON() : undefined, 13033 boundingSphere: info.boundingSphere ? info.boundingSphere.toJSON() : undefined 13034 } ) ); 13035 object.instanceInfo = this._instanceInfo.map( info => ( { ...info } ) ); 13036 13037 object.availableInstanceIds = this._availableInstanceIds.slice(); 13038 object.availableGeometryIds = this._availableGeometryIds.slice(); 13039 13040 object.nextIndexStart = this._nextIndexStart; 13041 object.nextVertexStart = this._nextVertexStart; 13042 object.geometryCount = this._geometryCount; 13043 13044 object.maxInstanceCount = this._maxInstanceCount; 13045 object.maxVertexCount = this._maxVertexCount; 13046 object.maxIndexCount = this._maxIndexCount; 13047 13048 object.geometryInitialized = this._geometryInitialized; 13049 13050 object.matricesTexture = this._matricesTexture.toJSON( meta ); 13051 13052 object.indirectTexture = this._indirectTexture.toJSON( meta ); 13053 13054 if ( this._colorsTexture !== null ) { 13055 13056 object.colorsTexture = this._colorsTexture.toJSON( meta ); 13057 13058 } 13059 13060 if ( this.boundingSphere !== null ) { 13061 13062 object.boundingSphere = this.boundingSphere.toJSON(); 13063 13064 } 13065 13066 if ( this.boundingBox !== null ) { 13067 13068 object.boundingBox = this.boundingBox.toJSON(); 13069 13070 } 13071 13072 } 13073 13074 // 13075 13076 function serialize( library, element ) { 13077 13078 if ( library[ element.uuid ] === undefined ) { 13079 13080 library[ element.uuid ] = element.toJSON( meta ); 13081 13082 } 13083 13084 return element.uuid; 13085 13086 } 13087 13088 if ( this.isScene ) { 13089 13090 if ( this.background ) { 13091 13092 if ( this.background.isColor ) { 13093 13094 object.background = this.background.toJSON(); 13095 13096 } else if ( this.background.isTexture ) { 13097 13098 object.background = this.background.toJSON( meta ).uuid; 13099 13100 } 13101 13102 } 13103 13104 if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) { 13105 13106 object.environment = this.environment.toJSON( meta ).uuid; 13107 13108 } 13109 13110 } else if ( this.isMesh || this.isLine || this.isPoints ) { 13111 13112 object.geometry = serialize( meta.geometries, this.geometry ); 13113 13114 const parameters = this.geometry.parameters; 13115 13116 if ( parameters !== undefined && parameters.shapes !== undefined ) { 13117 13118 const shapes = parameters.shapes; 13119 13120 if ( Array.isArray( shapes ) ) { 13121 13122 for ( let i = 0, l = shapes.length; i < l; i ++ ) { 13123 13124 const shape = shapes[ i ]; 13125 13126 serialize( meta.shapes, shape ); 13127 13128 } 13129 13130 } else { 13131 13132 serialize( meta.shapes, shapes ); 13133 13134 } 13135 13136 } 13137 13138 } 13139 13140 if ( this.isSkinnedMesh ) { 13141 13142 object.bindMode = this.bindMode; 13143 object.bindMatrix = this.bindMatrix.toArray(); 13144 13145 if ( this.skeleton !== undefined ) { 13146 13147 serialize( meta.skeletons, this.skeleton ); 13148 13149 object.skeleton = this.skeleton.uuid; 13150 13151 } 13152 13153 } 13154 13155 if ( this.material !== undefined ) { 13156 13157 if ( Array.isArray( this.material ) ) { 13158 13159 const uuids = []; 13160 13161 for ( let i = 0, l = this.material.length; i < l; i ++ ) { 13162 13163 uuids.push( serialize( meta.materials, this.material[ i ] ) ); 13164 13165 } 13166 13167 object.material = uuids; 13168 13169 } else { 13170 13171 object.material = serialize( meta.materials, this.material ); 13172 13173 } 13174 13175 } 13176 13177 // 13178 13179 if ( this.children.length > 0 ) { 13180 13181 object.children = []; 13182 13183 for ( let i = 0; i < this.children.length; i ++ ) { 13184 13185 object.children.push( this.children[ i ].toJSON( meta ).object ); 13186 13187 } 13188 13189 } 13190 13191 // 13192 13193 if ( this.animations.length > 0 ) { 13194 13195 object.animations = []; 13196 13197 for ( let i = 0; i < this.animations.length; i ++ ) { 13198 13199 const animation = this.animations[ i ]; 13200 13201 object.animations.push( serialize( meta.animations, animation ) ); 13202 13203 } 13204 13205 } 13206 13207 if ( isRootObject ) { 13208 13209 const geometries = extractFromCache( meta.geometries ); 13210 const materials = extractFromCache( meta.materials ); 13211 const textures = extractFromCache( meta.textures ); 13212 const images = extractFromCache( meta.images ); 13213 const shapes = extractFromCache( meta.shapes ); 13214 const skeletons = extractFromCache( meta.skeletons ); 13215 const animations = extractFromCache( meta.animations ); 13216 const nodes = extractFromCache( meta.nodes ); 13217 13218 if ( geometries.length > 0 ) output.geometries = geometries; 13219 if ( materials.length > 0 ) output.materials = materials; 13220 if ( textures.length > 0 ) output.textures = textures; 13221 if ( images.length > 0 ) output.images = images; 13222 if ( shapes.length > 0 ) output.shapes = shapes; 13223 if ( skeletons.length > 0 ) output.skeletons = skeletons; 13224 if ( animations.length > 0 ) output.animations = animations; 13225 if ( nodes.length > 0 ) output.nodes = nodes; 13226 13227 } 13228 13229 output.object = object; 13230 13231 return output; 13232 13233 // extract data from the cache hash 13234 // remove metadata on each item 13235 // and return as array 13236 function extractFromCache( cache ) { 13237 13238 const values = []; 13239 for ( const key in cache ) { 13240 13241 const data = cache[ key ]; 13242 delete data.metadata; 13243 values.push( data ); 13244 13245 } 13246 13247 return values; 13248 13249 } 13250 13251 } 13252 13253 /** 13254 * Returns a new 3D object with copied values from this instance. 13255 * 13256 * @param {boolean} [recursive=true] - When set to `true`, descendants of the 3D object are also cloned. 13257 * @return {Object3D} A clone of this instance. 13258 */ 13259 clone( recursive ) { 13260 13261 return new this.constructor().copy( this, recursive ); 13262 13263 } 13264 13265 /** 13266 * Copies the values of the given 3D object to this instance. 13267 * 13268 * @param {Object3D} source - The 3D object to copy. 13269 * @param {boolean} [recursive=true] - When set to `true`, descendants of the 3D object are cloned. 13270 * @return {Object3D} A reference to this instance. 13271 */ 13272 copy( source, recursive = true ) { 13273 13274 this.name = source.name; 13275 13276 this.up.copy( source.up ); 13277 13278 this.position.copy( source.position ); 13279 this.rotation.order = source.rotation.order; 13280 this.quaternion.copy( source.quaternion ); 13281 this.scale.copy( source.scale ); 13282 13283
13283this.pivot = ( source.pivot !== null ) ? source.pivot.clone() : null; 13284 13285 this.matrix.copy( source.matrix ); 13286 this.matrixWorld.copy( source.matrixWorld ); 13287 13288 this.matrixAutoUpdate = source.matrixAutoUpdate; 13289 13290 this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate; 13291 this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; 13292 13293 this.layers.mask = source.layers.mask; 13294 this.visible = source.visible; 13295 13296 this.castShadow = source.castShadow; 13297 this.receiveShadow = source.receiveShadow; 13298 13299 this.frustumCulled = source.frustumCulled; 13300 this.renderOrder = source.renderOrder; 13301 13302 this.static = source.static; 13303 13304 this.animations = source.animations.slice(); 13305 13306 this.userData = JSON.parse( JSON.stringify( source.userData ) ); 13307 13308 if ( recursive === true ) { 13309 13310 for ( let i = 0; i < source.children.length; i ++ ) { 13311 13312 const child = source.children[ i ]; 13313 this.add( child.clone() ); 13314 13315 } 13316 13317 } 13318 13319 return this
vendor: 43,089 bytes, lines 13319-15115
13319; 13320 13321 } 13322 13323} 13324 13325/** 13326 * The default up direction for objects, also used as the default 13327 * position for {@link DirectionalLight} and {@link HemisphereLight}. 13328 * 13329 * @static 13330 * @type {Vector3} 13331 * @default (0,1,0) 13332 */ 13333Object3D.DEFAULT_UP = /*@__PURE__*/ new Vector3( 0, 1, 0 ); 13334 13335/** 13336 * The default setting for {@link Object3D#matrixAutoUpdate} for 13337 * newly created 3D objects. 13338 * 13339 * @static 13340 * @type {boolean} 13341 * @default true 13342 */ 13343Object3D.DEFAULT_MATRIX_AUTO_UPDATE = true; 13344 13345/** 13346 * The default setting for {@link Object3D#matrixWorldAutoUpdate} for 13347 * newly created 3D objects. 13348 * 13349 * @static 13350 * @type {boolean} 13351 * @default true 13352 */ 13353Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = true; 13354 13355/** 13356 * This is almost identical to an {@link Object3D}. Its purpose is to 13357 * make working with groups of objects syntactically clearer. 13358 * 13359 * ```js 13360 * // Create a group and add the two cubes. 13361 * // These cubes can now be rotated / scaled etc as a group. 13362 * const group = new THREE.Group(); 13363 * 13364 * group.add( meshA ); 13365 * group.add( meshB ); 13366 * 13367 * scene.add( group ); 13368 * ``` 13369 * 13370 * @augments Object3D 13371 */ 13372class Group extends Object3D { 13373 13374 constructor() { 13375 13376 super(); 13377 13378 /** 13379 * This flag can be used for type testing. 13380 * 13381 * @type {boolean} 13382 * @readonly 13383 * @default true 13384 */ 13385 this.isGroup = true; 13386 13387 this.type = 'Group'; 13388 13389 } 13390 13391} 13392 13393const _moveEvent = { type: 'move' }; 13394 13395/** 13396 * Class for representing a XR controller with its 13397 * different coordinate systems. 13398 * 13399 * @private 13400 */ 13401class WebXRController { 13402 13403 /** 13404 * Constructs a new XR controller. 13405 */ 13406 constructor() { 13407 13408 /** 13409 * A group representing the target ray space 13410 * of the XR controller. 13411 * 13412 * @private 13413 * @type {?Group} 13414 * @default null 13415 */ 13416 this._targetRay = null; 13417 13418 /** 13419 * A group representing the grip space 13420 * of the XR controller. 13421 * 13422 * @private 13423 * @type {?Group} 13424 * @default null 13425 */ 13426 this._grip = null; 13427 13428 /** 13429 * A group representing the hand space 13430 * of the XR controller. 13431 * 13432 * @private 13433 * @type {?Group} 13434 * @default null 13435 */ 13436 this._hand = null; 13437 13438 } 13439 13440 /** 13441 * Returns a group representing the hand space of the XR controller. 13442 * 13443 * @return {Group} A group representing the hand space of the XR controller. 13444 */ 13445 getHandSpace() { 13446 13447 if ( this._hand === null ) { 13448 13449 this._hand = new Group(); 13450 this._hand.matrixAutoUpdate = false; 13451 this._hand.visible = false; 13452 13453 this._hand.joints = {}; 13454 this._hand.inputState = { pinching: false }; 13455 13456 } 13457 13458 return this._hand; 13459 13460 } 13461 13462 /** 13463 * Returns a group representing the target ray space of the XR controller. 13464 * 13465 * @return {Group} A group representing the target ray space of the XR controller. 13466 */ 13467 getTargetRaySpace() { 13468 13469 if ( this._targetRay === null ) { 13470 13471 this._targetRay = new Group(); 13472 this._targetRay.matrixAutoUpdate = false; 13473 this._targetRay.visible = false; 13474 this._targetRay.hasLinearVelocity = false; 13475 this._targetRay.linearVelocity = new Vector3(); 13476 this._targetRay.hasAngularVelocity = false; 13477 this._targetRay.angularVelocity = new Vector3(); 13478 13479 } 13480 13481 return this._targetRay; 13482 13483 } 13484 13485 /** 13486 * Returns a group representing the grip space of the XR controller. 13487 * 13488 * @return {Group} A group representing the grip space of the XR controller. 13489 */ 13490 getGripSpace() { 13491 13492 if ( this._grip === null ) { 13493 13494 this._grip = new Group(); 13495 this._grip.matrixAutoUpdate = false; 13496 this._grip.visible = false; 13497 this._grip.hasLinearVelocity = false; 13498 this._grip.linearVelocity = new Vector3(); 13499 this._grip.hasAngularVelocity = false; 13500 this._grip.angularVelocity = new Vector3(); 13501 this._grip.eventsEnabled = false; 13502 13503 } 13504 13505 return this._grip; 13506 13507 } 13508 13509 /** 13510 * Dispatches the given event to the groups representing 13511 * the different coordinate spaces of the XR controller. 13512 * 13513 * @param {Object} event - The event to dispatch. 13514 * @return {WebXRController} A reference to this instance. 13515 */ 13516 dispatchEvent( event ) { 13517 13518 if ( this._targetRay !== null ) { 13519 13520 this._targetRay.dispatchEvent( event ); 13521 13522 } 13523 13524 if ( this._grip !== null ) { 13525 13526 this._grip.dispatchEvent( event ); 13527 13528 } 13529 13530 if ( this._hand !== null ) { 13531 13532 this._hand.dispatchEvent( event ); 13533 13534 } 13535 13536 return this; 13537 13538 } 13539 13540 /** 13541 * Connects the controller with the given XR input source. 13542 * 13543 * @param {XRInputSource} inputSource - The input source. 13544 * @return {WebXRController} A reference to this instance. 13545 */ 13546 connect( inputSource ) { 13547 13548 if ( inputSource && inputSource.hand ) { 13549 13550 const hand = this._hand; 13551 13552 if ( hand ) { 13553 13554 for ( const inputjoint of inputSource.hand.values() ) { 13555 13556 // Initialize hand with joints when connected 13557 this._getHandJoint( hand, inputjoint ); 13558 13559 } 13560 13561 } 13562 13563 } 13564 13565 this.dispatchEvent( { type: 'connected', data: inputSource } ); 13566 13567 return this; 13568 13569 } 13570 13571 /** 13572 * Disconnects the controller from the given XR input source. 13573 * 13574 * @param {XRInputSource} inputSource - The input source. 13575 * @return {WebXRController} A reference to this instance. 13576 */ 13577 disconnect( inputSource ) { 13578 13579 this.dispatchEvent( { type: 'disconnected', data: inputSource } ); 13580 13581 if ( this._targetRay !== null ) { 13582 13583 this._targetRay.visible = false; 13584 13585 } 13586 13587 if ( this._grip !== null ) { 13588 13589 this._grip.visible = false; 13590 13591 } 13592 13593 if ( this._hand !== null ) { 13594 13595 this._hand.visible = false; 13596 13597 } 13598 13599 return this; 13600 13601 } 13602 13603 /** 13604 * Updates the controller with the given input source, XR frame and reference space. 13605 * This updates the transformations of the groups that represent the different 13606 * coordinate systems of the controller. 13607 * 13608 * @param {XRInputSource} inputSource - The input source. 13609 * @param {XRFrame} frame - The XR frame. 13610 * @param {XRReferenceSpace} referenceSpace - The reference space. 13611 * @return {WebXRController} A reference to this instance. 13612 */ 13613 update( inputSource, frame, referenceSpace ) { 13614 13615 let inputPose = null; 13616 let gripPose = null; 13617 let handPose = null; 13618 13619 const targetRay = this._targetRay; 13620 const grip = this._grip; 13621 const hand = this._hand; 13622 13623 if ( inputSource && frame.session.visibilityState !== 'visible-blurred' ) { 13624 13625 if ( hand && inputSource.hand ) { 13626 13627 handPose = true; 13628 13629 for ( const inputjoint of inputSource.hand.values() ) { 13630 13631 // Update the joints groups with the XRJoint poses 13632 const jointPose = frame.getJointPose( inputjoint, referenceSpace ); 13633 13634 // The transform of this joint will be updated with the joint pose on each frame 13635 const joint = this._getHandJoint( hand, inputjoint ); 13636 13637 if ( jointPose !== null ) { 13638 13639 joint.matrix.fromArray( jointPose.transform.matrix ); 13640 joint.matrix.decompose( joint.position, joint.rotation, joint.scale ); 13641 joint.matrixWorldNeedsUpdate = true; 13642 joint.jointRadius = jointPose.radius; 13643 13644 } 13645 13646 joint.visible = jointPose !== null; 13647 13648 } 13649 13650 // Custom events 13651 13652 // Check pinchz 13653 const indexTip = hand.joints[ 'index-finger-tip' ]; 13654 const thumbTip = hand.joints[ 'thumb-tip' ]; 13655 const distance = indexTip.position.distanceTo( thumbTip.position ); 13656 13657 const distanceToPinch = 0.02; 13658 const threshold = 0.005; 13659 13660 if ( hand.inputState.pinching && distance > distanceToPinch + threshold ) { 13661 13662 hand.inputState.pinching = false; 13663 this.dispatchEvent( { 13664 type: 'pinchend', 13665 handedness: inputSource.handedness, 13666 target: this 13667 } ); 13668 13669 } else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) { 13670 13671 hand.inputState.pinching = true; 13672 this.dispatchEvent( { 13673 type: 'pinchstart', 13674 handedness: inputSource.handedness, 13675 target: this 13676 } ); 13677 13678 } 13679 13680 } else { 13681 13682 if ( grip !== null && inputSource.gripSpace ) { 13683 13684 gripPose = frame.getPose( inputSource.gripSpace, referenceSpace ); 13685 13686 if ( gripPose !== null ) { 13687 13688 grip.matrix.fromArray( gripPose.transform.matrix ); 13689 grip.matrix.decompose( grip.position, grip.rotation, grip.scale ); 13690 grip.matrixWorldNeedsUpdate = true; 13691 13692 if ( gripPose.linearVelocity ) { 13693 13694 grip.hasLinearVelocity = true; 13695 grip.linearVelocity.copy( gripPose.linearVelocity ); 13696 13697 } else { 13698 13699 grip.hasLinearVelocity = false; 13700 13701 } 13702 13703 if ( gripPose.angularVelocity ) { 13704 13705 grip.hasAngularVelocity = true; 13706 grip.angularVelocity.copy( gripPose.angularVelocity ); 13707 13708 } else { 13709 13710 grip.hasAngularVelocity = false; 13711 13712 } 13713 13714 // grip update event if enabled 13715 if ( grip.eventsEnabled ) { 13716 13717 grip.dispatchEvent( { 13718 type: 'gripUpdated', 13719 data: inputSource, 13720 target: this 13721 } ); 13722 13723 } 13724 13725 } 13726 13727 } 13728 13729 } 13730 13731 if ( targetRay !== null ) { 13732 13733 inputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace ); 13734 13735 // Some runtimes (namely Vive Cosmos with Vive OpenXR Runtime) have only grip space and ray space is equal to it 13736 if ( inputPose === null && gripPose !== null ) { 13737 13738 inputPose = gripPose; 13739 13740 } 13741 13742 if ( inputPose !== null ) { 13743 13744 targetRay.matrix.fromArray( inputPose.transform.matrix ); 13745 targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale ); 13746 targetRay.matrixWorldNeedsUpdate = true; 13747 13748 if ( inputPose.linearVelocity ) { 13749 13750 targetRay.hasLinearVelocity = true; 13751 targetRay.linearVelocity.copy( inputPose.linearVelocity ); 13752 13753 } else { 13754 13755 targetRay.hasLinearVelocity = false; 13756 13757 } 13758 13759 if ( inputPose.angularVelocity ) { 13760 13761 targetRay.hasAngularVelocity = true; 13762 targetRay.angularVelocity.copy( inputPose.angularVelocity ); 13763 13764 } else { 13765 13766 targetRay.hasAngularVelocity = false; 13767 13768 } 13769 13770 this.dispatchEvent( _moveEvent ); 13771 13772 } 13773 13774 } 13775 13776 13777 } 13778 13779 if ( targetRay !== null ) { 13780 13781 targetRay.visible = ( inputPose !== null ); 13782 13783 } 13784 13785 if ( grip !== null ) { 13786 13787 grip.visible = ( gripPose !== null ); 13788 13789 } 13790 13791 if ( hand !== null ) { 13792 13793 hand.visible = ( handPose !== null ); 13794 13795 } 13796 13797 return this; 13798 13799 } 13800 13801 /** 13802 * Returns a group representing the hand joint for the given input joint. 13803 * 13804 * @private 13805 * @param {Group} hand - The group representing the hand space. 13806 * @param {XRJointSpace} inputjoint - The hand joint data. 13807 * @return {Group} A group representing the hand joint for the given input joint. 13808 */ 13809 _getHandJoint( hand, inputjoint ) { 13810 13811 if ( hand.joints[ inputjoint.jointName ] === undefined ) { 13812 13813 const joint = new Group(); 13814 joint.matrixAutoUpdate = false; 13815 joint.visible = false; 13816 hand.joints[ inputjoint.jointName ] = joint; 13817 13818 hand.add( joint ); 13819 13820 } 13821 13822 return hand.joints[ inputjoint.jointName ]; 13823 13824 } 13825 13826} 13827 13828const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, 13829 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, 13830 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, 13831 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, 13832 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, 13833 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, 13834 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, 13835 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, 13836 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, 13837 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, 13838 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, 13839 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, 13840 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, 13841 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, 13842 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, 13843 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, 13844 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, 13845 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, 13846 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, 13847 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, 13848 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, 13849 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, 13850 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, 13851 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; 13852 13853const _hslA = { h: 0, s: 0, l: 0 }; 13854const _hslB = { h: 0, s: 0, l: 0 }; 13855 13856function hue2rgb( p, q, t ) { 13857 13858 if ( t < 0 ) t += 1; 13859 if ( t > 1 ) t -= 1; 13860 if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; 13861 if ( t < 1 / 2 ) return q; 13862 if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); 13863 return p; 13864 13865} 13866 13867/** 13868 * A Color instance is represented by RGB components in the linear <i>working 13869 * color space</i>, which defaults to `LinearSRGBColorSpace`. Inputs 13870 * conventionally using `SRGBColorSpace` (such as hexadecimals and CSS 13871 * strings) are converted to the working color space automatically. 13872 * 13873 * ```js 13874 * // converted automatically from SRGBColorSpace to LinearSRGBColorSpace 13875 * const color = new THREE.Color().setHex( 0x112233 ); 13876 * ``` 13877 * Source color spaces may be specified explicitly, to ensure correct conversions. 13878 * ```js 13879 * // assumed already LinearSRGBColorSpace; no conversion 13880 * const color = new THREE.Color().setRGB( 0.5, 0.5, 0.5 ); 13881 * 13882 * // converted explicitly from SRGBColorSpace to LinearSRGBColorSpace 13883 * const color = new THREE.Color().setRGB( 0.5, 0.5, 0.5, SRGBColorSpace ); 13884 * ``` 13885 * If THREE.ColorManagement is disabled, no conversions occur. For details, 13886 * see <i>Color management</i>. Iterating through a Color instance will yield 13887 * its components (r, g, b) in the corresponding order. A Color can be initialised 13888 * in any of the following ways: 13889 * ```js 13890 * //empty constructor - will default white 13891 * const color1 = new THREE.Color(); 13892 * 13893 * //Hexadecimal color (recommended) 13894 * const color2 = new THREE.Color( 0xff0000 ); 13895 * 13896 * //RGB string 13897 * const color3 = new THREE.Color("rgb(255, 0, 0)"); 13898 * const color4 = new THREE.Color("rgb(100%, 0%, 0%)"); 13899 * 13900 * //X11 color name - all 140 color names are supported. 13901 * //Note the lack of CamelCase in the name 13902 * const color5 = new THREE.Color( 'skyblue' ); 13903 * //HSL string 13904 * const color6 = new THREE.Color("hsl(0, 100%, 50%)"); 13905 * 13906 * //Separate RGB values between 0 and 1 13907 * const color7 = new THREE.Color( 1, 0, 0 ); 13908 * ``` 13909 */ 13910class Color { 13911 13912 /** 13913 * Constructs a new color. 13914 * 13915 * Note that standard method of specifying color in three.js is with a hexadecimal triplet, 13916 * and that method is used throughout the rest of the documentation. 13917 * 13918 * @param {(number|string|Color)} [r] - The red component of the color. If `g` and `b` are 13919 * not provided, it can be hexadecimal triplet, a CSS-style string or another `Color` instance. 13920 * @param {number} [g] - The green component. 13921 * @param {number} [b] - The blue component. 13922 */ 13923 constructor( r, g, b ) { 13924 13925 /** 13926 * This flag can be used for type testing. 13927 * 13928 * @type {boolean} 13929 * @readonly 13930 * @default true 13931 */ 13932 this.isColor = true; 13933 13934 /** 13935 * The red component. 13936 * 13937 * @type {number} 13938 * @default 1 13939 */ 13940 this.r = 1; 13941 13942 /** 13943 * The green component. 13944 * 13945 * @type {number} 13946 * @default 1 13947 */ 13948 this.g = 1; 13949 13950 /** 13951 * The blue component. 13952 * 13953 * @type {number} 13954 * @default 1 13955 */ 13956 this.b = 1; 13957 13958 return this.set( r, g, b ); 13959 13960 } 13961 13962 /** 13963 * Sets the colors's components from the given values. 13964 * 13965 * @param {(number|string|Color)} [r] - The red component of the color. If `g` and `b` are 13966 * not provided, it can be hexadecimal triplet, a CSS-style string or another `Color` instance. 13967 * @param {number} [g] - The green component. 13968 * @param {number} [b] - The blue component. 13969 * @return {Color} A reference to this color. 13970 */ 13971 set( r, g, b ) { 13972 13973 if ( g === undefined && b === undefined ) { 13974 13975 // r is THREE.Color, hex or string 13976 13977 const value = r; 13978 13979 if ( value && value.isColor ) { 13980 13981 this.copy( value ); 13982 13983 } else if ( typeof value === 'number' ) { 13984 13985 this.setHex( value ); 13986 13987 } else if ( typeof value === 'string' ) { 13988 13989 this.setStyle( value ); 13990 13991 } 13992 13993 } else { 13994 13995 this.setRGB( r, g, b ); 13996 13997 } 13998 13999 return this; 14000 14001 } 14002 14003 /** 14004 * Sets the colors's components to the given scalar value. 14005 * 14006 * @param {number} scalar - The scalar value. 14007 * @return {Color} A reference to this color. 14008 */ 14009 setScalar( scalar ) { 14010 14011 this.r = scalar; 14012 this.g = scalar; 14013 this.b = scalar; 14014 14015 return this; 14016 14017 } 14018 14019 /** 14020 * Sets this color from a hexadecimal value. 14021 * 14022 * @param {number} hex - The hexadecimal value. 14023 * @param {string} [colorSpace=SRGBColorSpace] - The color space. 14024 * @return {Color} A reference to this color. 14025 */ 14026 setHex( hex, colorSpace = SRGBColorSpace ) { 14027 14028 hex = Math.floor( hex ); 14029 14030 this.r = ( hex >> 16 & 255 ) / 255; 14031 this.g = ( hex >> 8 & 255 ) / 255; 14032 this.b = ( hex & 255 ) / 255; 14033 14034 ColorManagement.colorSpaceToWorking( this, colorSpace ); 14035 14036 return this; 14037 14038 } 14039 14040 /** 14041 * Sets this color from RGB values. 14042 * 14043 * @param {number} r - Red channel value between `0.0` and `1.0`. 14044 * @param {number} g - Green channel value between `0.0` and `1.0`. 14045 * @param {number} b - Blue channel value between `0.0` and `1.0`. 14046 * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space. 14047 * @return {Color} A reference to this color. 14048 */ 14049 setRGB( r, g, b, colorSpace = ColorManagement.workingColorSpace ) { 14050 14051 this.r = r; 14052 this.g = g; 14053 this.b = b; 14054 14055 ColorManagement.colorSpaceToWorking( this, colorSpace ); 14056 14057 return this; 14058 14059 } 14060 14061 /** 14062 * Sets this color from RGB values. 14063 * 14064 * @param {number} h - Hue value between `0.0` and `1.0`. 14065 * @param {number} s - Saturation value between `0.0` and `1.0`. 14066 * @param {number} l - Lightness value between `0.0` and `1.0`. 14067 * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space. 14068 * @return {Color} A reference to this color. 14069 */ 14070 setHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) { 14071 14072 // h,s,l ranges are in 0.0 - 1.0 14073 h = euclideanModulo( h, 1 ); 14074 s = clamp( s, 0, 1 ); 14075 l = clamp( l, 0, 1 ); 14076 14077 if ( s === 0 ) { 14078 14079 this.r = this.g = this.b = l; 14080 14081 } else { 14082 14083 const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); 14084 const q = ( 2 * l ) - p; 14085 14086 this.r = hue2rgb( q, p, h + 1 / 3 ); 14087 this.g = hue2rgb( q, p, h ); 14088 this.b = hue2rgb( q, p, h - 1 / 3 ); 14089 14090 } 14091 14092 ColorManagement.colorSpaceToWorking( this, colorSpace ); 14093 14094 return this; 14095 14096 } 14097 14098 /** 14099 * Sets this color from a CSS-style string. For example, `rgb(250, 0,0)`, 14100 * `rgb(100%, 0%, 0%)`, `hsl(0, 100%, 50%)`, `#ff0000`, `#f00`, or `red` ( or 14101 * any [X11 color name](https://en.wikipedia.org/wiki/X11_color_names#Color_name_chart) - 14102 * all 140 color names are supported). 14103 * 14104 * @param {string} style - Color as a CSS-style string. 14105 * @param {string} [colorSpace=SRGBColorSpace] - The color space. 14106 * @return {Color} A reference to this color. 14107 */ 14108 setStyle( style, colorSpace = SRGBColorSpace ) { 14109 14110 function handleAlpha( string ) { 14111 14112 if ( string === undefined ) return; 14113 14114 if ( parseFloat( string ) < 1 ) { 14115 14116 warn( 'Color: Alpha component of ' + style + ' will be ignored.' ); 14117 14118 } 14119 14120 } 14121 14122 14123 let m; 14124 14125 if ( m = /^(\w+)\(([^\)]*)\)/.exec( style ) ) { 14126 14127 // rgb / hsl 14128 14129 let color; 14130 const name = m[ 1 ]; 14131 const components = m[ 2 ]; 14132 14133 switch ( name ) { 14134 14135 case 'rgb': 14136 case 'rgba': 14137 14138 if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { 14139 14140 // rgb(255,0,0) rgba(255,0,0,0.5) 14141 14142 handleAlpha( color[ 4 ] ); 14143 14144 return this.setRGB( 14145 Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255, 14146 Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255, 14147 Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255, 14148 colorSpace 14149 ); 14150 14151 } 14152 14153 if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { 14154 14155 // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5) 14156 14157 handleAlpha( color[ 4 ] ); 14158 14159 return this.setRGB( 14160 Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100, 14161 Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100, 14162 Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100, 14163 colorSpace 14164 ); 14165 14166 } 14167 14168 break; 14169 14170 case 'hsl': 14171 case 'hsla': 14172 14173 if ( color = /^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { 14174 14175 // hsl(120,50%,50%) hsla(120,50%,50%,0.5) 14176 14177 handleAlpha( color[ 4 ] ); 14178 14179 return this.setHSL( 14180 parseFloat( color[ 1 ] ) / 360, 14181 parseFloat( color[ 2 ] ) / 100, 14182 parseFloat( color[ 3 ] ) / 100, 14183 colorSpace 14184 ); 14185 14186 } 14187 14188 break; 14189 14190 default: 14191 14192 warn( 'Color: Unknown color model ' + style ); 14193 14194 } 14195 14196 } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) { 14197 14198 // hex color 14199 14200 const hex = m[ 1 ]; 14201 const size = hex.length; 14202 14203 if ( size === 3 ) { 14204 14205 // #ff0 14206 return this.setRGB( 14207 parseInt( hex.charAt( 0 ), 16 ) / 15, 14208 parseInt( hex.charAt( 1 ), 16 ) / 15, 14209 parseInt( hex.charAt( 2 ), 16 ) / 15, 14210 colorSpace 14211 ); 14212 14213 } else if ( size === 6 ) { 14214 14215 // #ff0000 14216 return this.setHex( parseInt( hex, 16 ), colorSpace ); 14217 14218 } else { 14219 14220 warn( 'Color: Invalid hex color ' + style ); 14221 14222 } 14223 14224 } else if ( style && style.length > 0 ) { 14225 14226 return this.setColorName( style, colorSpace ); 14227 14228 } 14229 14230 return this; 14231 14232 } 14233 14234 /** 14235 * Sets this color from a color name. Faster than {@link Color#setStyle} if 14236 * you don't need the other CSS-style formats. 14237 * 14238 * For convenience, the list of names is exposed in `Color.NAMES` as a hash. 14239 * ```js 14240 * Color.NAMES.aliceblue // returns 0xF0F8FF 14241 * ``` 14242 * 14243 * @param {string} style - The color name. 14244 * @param {string} [colorSpace=SRGBColorSpace] - The color space. 14245 * @return {Color} A reference to this color. 14246 */ 14247 setColorName( style, colorSpace = SRGBColorSpace ) { 14248 14249 // color keywords 14250 const hex = _colorKeywords[ style.toLowerCase() ]; 14251 14252 if ( hex !== undefined ) { 14253 14254 // red 14255 this.setHex( hex, colorSpace ); 14256 14257 } else { 14258 14259 // unknown color 14260 warn( 'Color: Unknown color ' + style ); 14261 14262 } 14263 14264 return this; 14265 14266 } 14267 14268 /** 14269 * Returns a new color with copied values from this instance. 14270 * 14271 * @return {Color} A clone of this instance. 14272 */ 14273 clone() { 14274 14275 return new this.constructor( this.r, this.g, this.b ); 14276 14277 } 14278 14279 /** 14280 * Copies the values of the given color to this instance. 14281 * 14282 * @param {Color} color - The color to copy. 14283 * @return {Color} A reference to this color. 14284 */ 14285 copy( color ) { 14286 14287 this.r = color.r; 14288 this.g = color.g; 14289 this.b = color.b; 14290 14291 return this; 14292 14293 } 14294 14295 /** 14296 * Copies the given color into this color, and then converts this color from 14297 * `SRGBColorSpace` to `LinearSRGBColorSpace`. 14298 * 14299 * @param {Color} color - The color to copy/convert. 14300 * @return {Color} A reference to this color. 14301 */ 14302 copySRGBToLinear( color ) { 14303 14304 this.r = SRGBToLinear( color.r ); 14305 this.g = SRGBToLinear( color.g ); 14306 this.b = SRGBToLinear( color.b ); 14307 14308 return this; 14309 14310 } 14311 14312 /** 14313 * Copies the given color into this color, and then converts this color from 14314 * `LinearSRGBColorSpace` to `SRGBColorSpace`. 14315 * 14316 * @param {Color} color - The color to copy/convert. 14317 * @return {Color} A reference to this color. 14318 */ 14319 copyLinearToSRGB( color ) { 14320 14321 this.r = LinearToSRGB( color.r ); 14322 this.g = LinearToSRGB( color.g ); 14323 this.b = LinearToSRGB( color.b ); 14324 14325 return this; 14326 14327 } 14328 14329 /** 14330 * Converts this color from `SRGBColorSpace` to `LinearSRGBColorSpace`. 14331 * 14332 * @return {Color} A reference to this color. 14333 */ 14334 convertSRGBToLinear() { 14335 14336 this.copySRGBToLinear( this ); 14337 14338 return this; 14339 14340 } 14341 14342 /** 14343 * Converts this color from `LinearSRGBColorSpace` to `SRGBColorSpace`. 14344 * 14345 * @return {Color} A reference to this color. 14346 */ 14347 convertLinearToSRGB() { 14348 14349 this.copyLinearToSRGB( this ); 14350 14351 return this; 14352 14353 } 14354 14355 /** 14356 * Returns the hexadecimal value of this color. 14357 * 14358 * @param {string} [colorSpace=SRGBColorSpace] - The color space. 14359 * @return {number} The hexadecimal value. 14360 */ 14361 getHex( colorSpace = SRGBColorSpace ) { 14362 14363 ColorManagement.workingToColorSpace( _color.copy( this ), colorSpace ); 14364 14365 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 ) ); 14366 14367 } 14368 14369 /** 14370 * Returns the hexadecimal value of this color as a string (for example, 'FFFFFF'). 14371 * 14372 * @param {string} [colorSpace=SRGBColorSpace] - The color space. 14373 * @return {string} The hexadecimal value as a string. 14374 */ 14375 getHexString( colorSpace = SRGBColorSpace ) { 14376 14377 return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( -6 ); 14378 14379 } 14380 14381 /** 14382 * Converts the colors RGB values into the HSL format and stores them into the 14383 * given target object. 14384 * 14385 * @param {{h:number,s:number,l:number}} target - The target object that is used to store the method's result. 14386 * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space. 14387 * @return {{h:number,s:number,l:number}} The HSL representation of this color. 14388 */ 14389 getHSL( target, colorSpace = ColorManagement.workingColorSpace ) { 14390 14391 // h,s,l ranges are in 0.0 - 1.0 14392 14393 ColorManagement.workingToColorSpace( _color.copy( this ), colorSpace ); 14394 14395 const r = _color.r, g = _color.g, b = _color.b; 14396 14397 const max = Math.max( r, g, b ); 14398 const min = Math.min( r, g, b ); 14399 14400 let hue, saturation; 14401 const lightness = ( min + max ) / 2.0; 14402 14403 if ( min === max ) { 14404 14405 hue = 0; 14406 saturation = 0; 14407 14408 } else { 14409 14410 const delta = max - min; 14411 14412 saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); 14413 14414 switch ( max ) { 14415 14416 case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; 14417 case g: hue = ( b - r ) / delta + 2; break; 14418 case b: hue = ( r - g ) / delta + 4; break; 14419 14420 } 14421 14422 hue /= 6; 14423 14424 } 14425 14426 target.h = hue; 14427 target.s = saturation; 14428 target.l = lightness; 14429 14430 return target; 14431 14432 } 14433 14434 /** 14435 * Returns the RGB values of this color and stores them into the given target object. 14436 * 14437 * @param {Color} target - The target color that is used to store the method's result. 14438 * @param {string} [colorSpace=ColorManagement.workingColorSpace] - The color space. 14439 * @return {Color} The RGB representation of this color. 14440 */ 14441 getRGB( target, colorSpace = ColorManagement.workingColorSpace ) { 14442 14443 ColorManagement.workingToColorSpace( _color.copy( this ), colorSpace ); 14444 14445 target.r = _color.r; 14446 target.g = _color.g; 14447 target.b = _color.b; 14448 14449 return target; 14450 14451 } 14452 14453 /** 14454 * Returns the value of this color as a CSS style string. Example: `rgb(255,0,0)`. 14455 * 14456 * @param {string} [colorSpace=SRGBColorSpace] - The color space. 14457 * @return {string} The CSS representation of this color. 14458 */ 14459 getStyle( colorSpace = SRGBColorSpace ) { 14460 14461 ColorManagement.workingToColorSpace( _color.copy( this ), colorSpace ); 14462 14463 const r = _color.r, g = _color.g, b = _color.b; 14464 14465 if ( colorSpace !== SRGBColorSpace ) { 14466 14467 // Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/). 14468 return `color(${ colorSpace } ${ r.toFixed( 3 ) } ${ g.toFixed( 3 ) } ${ b.toFixed( 3 ) })`; 14469 14470 } 14471 14472 return `rgb(${ Math.round( r * 255 ) },${ Math.round( g * 255 ) },${ Math.round( b * 255 ) })`; 14473 14474 } 14475 14476 /** 14477 * Adds the given HSL values to this color's values. 14478 * Internally, this converts the color's RGB values to HSL, adds HSL 14479 * and then converts the color back to RGB. 14480 * 14481 * @param {number} h - Hue value between `0.0` and `1.0`. 14482 * @param {number} s - Saturation value between `0.0` and `1.0`. 14483 * @param {number} l - Lightness value between `0.0` and `1.0`. 14484 * @return {Color} A reference to this color. 14485 */ 14486 offsetHSL( h, s, l ) { 14487 14488 this.getHSL( _hslA ); 14489 14490 return this.setHSL( _hslA.h + h, _hslA.s + s, _hslA.l + l ); 14491 14492 } 14493 14494 /** 14495 * Adds the RGB values of the given color to the RGB values of this color. 14496 * 14497 * @param {Color} color - The color to add. 14498 * @return {Color} A reference to this color. 14499 */ 14500 add( color ) { 14501 14502 this.r += color.r; 14503 this.g += color.g; 14504 this.b += color.b; 14505 14506 return this; 14507 14508 } 14509 14510 /** 14511 * Adds the RGB values of the given colors and stores the result in this instance. 14512 * 14513 * @param {Color} color1 - The first color. 14514 * @param {Color} color2 - The second color. 14515 * @return {Color} A reference to this color. 14516 */ 14517 addColors( color1, color2 ) { 14518 14519 this.r = color1.r + color2.r; 14520 this.g = color1.g + color2.g; 14521 this.b = color1.b + color2.b; 14522 14523 return this; 14524 14525 } 14526 14527 /** 14528 * Adds the given scalar value to the RGB values of this color. 14529 * 14530 * @param {number} s - The scalar to add. 14531 * @return {Color} A reference to this color. 14532 */ 14533 addScalar( s ) { 14534 14535 this.r += s; 14536 this.g += s; 14537 this.b += s; 14538 14539 return this; 14540 14541 } 14542 14543 /** 14544 * Subtracts the RGB values of the given color from the RGB values of this color. 14545 * 14546 * @param {Color} color - The color to subtract. 14547 * @return {Color} A reference to this color. 14548 */ 14549 sub( color ) { 14550 14551 this.r = Math.max( 0, this.r - color.r ); 14552 this.g = Math.max( 0, this.g - color.g ); 14553 this.b = Math.max( 0, this.b - color.b ); 14554 14555 return this; 14556 14557 } 14558 14559 /** 14560 * Multiplies the RGB values of the given color with the RGB values of this color. 14561 * 14562 * @param {Color} color - The color to multiply. 14563 * @return {Color} A reference to this color. 14564 */ 14565 multiply( color ) { 14566 14567 this.r *= color.r; 14568 this.g *= color.g; 14569 this.b *= color.b; 14570 14571 return this; 14572 14573 } 14574 14575 /** 14576 * Multiplies the given scalar value with the RGB values of this color. 14577 * 14578 * @param {number} s - The scalar to multiply. 14579 * @return {Color} A reference to this color. 14580 */ 14581 multiplyScalar( s ) { 14582 14583 this.r *= s; 14584 this.g *= s; 14585 this.b *= s; 14586 14587 return this; 14588 14589 } 14590 14591 /** 14592 * Linearly interpolates this color's RGB values toward the RGB values of the 14593 * given color. The alpha argument can be thought of as the ratio between 14594 * the two colors, where `0.0` is this color and `1.0` is the first argument. 14595 * 14596 * @param {Color} color - The color to converge on. 14597 * @param {number} alpha - The interpolation factor in the closed interval `[0,1]`. 14598 * @return {Color} A reference to this color. 14599 */ 14600 lerp( color, alpha ) { 14601 14602 this.r += ( color.r - this.r ) * alpha; 14603 this.g += ( color.g - this.g ) * alpha; 14604 this.b += ( color.b - this.b ) * alpha; 14605 14606 return this; 14607 14608 } 14609 14610 /** 14611 * Linearly interpolates between the given colors and stores the result in this instance. 14612 * The alpha argument can be thought of as the ratio between the two colors, where `0.0` 14613 * is the first and `1.0` is the second color. 14614 * 14615 * @param {Color} color1 - The first color. 14616 * @param {Color} color2 - The second color. 14617 * @param {number} alpha - The interpolation factor in the closed interval `[0,1]`. 14618 * @return {Color} A reference to this color. 14619 */ 14620 lerpColors( color1, color2, alpha ) { 14621 14622 this.r = color1.r + ( color2.r - color1.r ) * alpha; 14623 this.g = color1.g + ( color2.g - color1.g ) * alpha; 14624 this.b = color1.b + ( color2.b - color1.b ) * alpha; 14625 14626 return this; 14627 14628 } 14629 14630 /** 14631 * Linearly interpolates this color's HSL values toward the HSL values of the 14632 * given color. It differs from {@link Color#lerp} by not interpolating straight 14633 * from one color to the other, but instead going through all the hues in between 14634 * those two colors. The alpha argument can be thought of as the ratio between 14635 * the two colors, where 0.0 is this color and 1.0 is the first argument. 14636 * 14637 * @param {Color} color - The color to converge on. 14638 * @param {number} alpha - The interpolation factor in the closed interval `[0,1]`. 14639 * @return {Color} A reference to this color. 14640 */ 14641 lerpHSL( color, alpha ) { 14642 14643 this.getHSL( _hslA ); 14644 color.getHSL( _hslB ); 14645 14646 const h = lerp( _hslA.h, _hslB.h, alpha ); 14647 const s = lerp( _hslA.s, _hslB.s, alpha ); 14648 const l = lerp( _hslA.l, _hslB.l, alpha ); 14649 14650 this.setHSL( h, s, l ); 14651 14652 return this; 14653 14654 } 14655 14656 /** 14657 * Sets the color's RGB components from the given 3D vector. 14658 * 14659 * @param {Vector3} v - The vector to set. 14660 * @return {Color} A reference to this color. 14661 */ 14662 setFromVector3( v ) { 14663 14664 this.r = v.x; 14665 this.g = v.y; 14666 this.b = v.z; 14667 14668 return this; 14669 14670 } 14671 14672 /** 14673 * Transforms this color with the given 3x3 matrix. 14674 * 14675 * @param {Matrix3} m - The matrix. 14676 * @return {Color} A reference to this color. 14677 */ 14678 applyMatrix3( m ) { 14679 14680 const r = this.r, g = this.g, b = this.b; 14681 const e = m.elements; 14682 14683 this.r = e[ 0 ] * r + e[ 3 ] * g + e[ 6 ] * b; 14684 this.g = e[ 1 ] * r + e[ 4 ] * g + e[ 7 ] * b; 14685 this.b = e[ 2 ] * r + e[ 5 ] * g + e[ 8 ] * b; 14686 14687 return this; 14688 14689 } 14690 14691 /** 14692 * Returns `true` if this color is equal with the given one. 14693 * 14694 * @param {Color} c - The color to test for equality. 14695 * @return {boolean} Whether this bounding color is equal with the given one. 14696 */ 14697 equals( c ) { 14698 14699 return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); 14700 14701 } 14702 14703 /** 14704 * Sets this color's RGB components from the given array. 14705 * 14706 * @param {Array<number>} array - An array holding the RGB values. 14707 * @param {number} [offset=0] - The offset into the array. 14708 * @return {Color} A reference to this color. 14709 */ 14710 fromArray( array, offset = 0 ) { 14711 14712 this.r = array[ offset ]; 14713 this.g = array[ offset + 1 ]; 14714 this.b = array[ offset + 2 ]; 14715 14716 return this; 14717 14718 } 14719 14720 /** 14721 * Writes the RGB components of this color to the given array. If no array is provided, 14722 * the method returns a new instance. 14723 * 14724 * @param {Array<number>} [array=[]] - The target array holding the color components. 14725 * @param {number} [offset=0] - Index of the first element in the array. 14726 * @return {Array<number>} The color components. 14727 */ 14728 toArray( array = [], offset = 0 ) { 14729 14730 array[ offset ] = this.r; 14731 array[ offset + 1 ] = this.g; 14732 array[ offset + 2 ] = this.b; 14733 14734 return array; 14735 14736 } 14737 14738 /** 14739 * Sets the components of this color from the given buffer attribute. 14740 * 14741 * @param {BufferAttribute} attribute - The buffer attribute holding color data. 14742 * @param {number} index - The index into the attribute. 14743 * @return {Color} A reference to this color. 14744 */ 14745 fromBufferAttribute( attribute, index ) { 14746 14747 this.r = attribute.getX( index ); 14748 this.g = attribute.getY( index ); 14749 this.b = attribute.getZ( index ); 14750 14751 return this; 14752 14753 } 14754 14755 /** 14756 * This methods defines the serialization result of this class. Returns the color 14757 * as a hexadecimal value. 14758 * 14759 * @return {number} The hexadecimal value. 14760 */ 14761 toJSON() { 14762 14763 return this.getHex(); 14764 14765 } 14766 14767 *[ Symbol.iterator ]() { 14768 14769 yield this.r; 14770 yield this.g; 14771 yield this.b; 14772 14773 } 14774 14775} 14776 14777const _color = /*@__PURE__*/ new Color(); 14778 14779/** 14780 * A dictionary with X11 color names. 14781 * 14782 * Note that multiple words such as Dark Orange become the string 'darkorange'. 14783 * 14784 * @static 14785 * @type {Object} 14786 */ 14787Color.NAMES = _colorKeywords; 14788 14789/** 14790 * This class can be used to define an exponential squared fog, 14791 * which gives a clear view near the camera and a faster than exponentially 14792 * densening fog farther from the camera. 14793 * 14794 * ```js 14795 * const scene = new THREE.Scene(); 14796 * scene.fog = new THREE.FogExp2( 0xcccccc, 0.002 ); 14797 * ``` 14798 */ 14799class FogExp2 { 14800 14801 /** 14802 * Constructs a new fog. 14803 * 14804 * @param {number|Color} color - The fog's color. 14805 * @param {number} [density=0.00025] - Defines how fast the fog will grow dense. 14806 */ 14807 constructor( color, density = 0.00025 ) { 14808 14809 /** 14810 * This flag can be used for type testing. 14811 * 14812 * @type {boolean} 14813 * @readonly 14814 * @default true 14815 */ 14816 this.isFogExp2 = true; 14817 14818 /** 14819 * The name of the fog. 14820 * 14821 * @type {string} 14822 */ 14823 this.name = ''; 14824 14825 /** 14826 * The fog's color. 14827 * 14828 * @type {Color} 14829 */ 14830 this.color = new Color( color ); 14831 14832 /** 14833 * Defines how fast the fog will grow dense. 14834 * 14835 * @type {number} 14836 * @default 0.00025 14837 */ 14838 this.density = density; 14839 14840 } 14841 14842 /** 14843 * Returns a new fog with copied values from this instance. 14844 * 14845 * @return {FogExp2} A clone of this instance. 14846 */ 14847 clone() { 14848 14849 return new FogExp2( this.color, this.density ); 14850 14851 } 14852 14853 /** 14854 * Serializes the fog into JSON. 14855 * 14856 * @param {?(Object|string)} meta - An optional value holding meta information about the serialization. 14857 * @return {Object} A JSON object representing the serialized fog 14858 */ 14859 toJSON( /* meta */ ) { 14860 14861 return { 14862 type: 'FogExp2', 14863 name: this.name, 14864 color: this.color.getHex(), 14865 density: this.density 14866 }; 14867 14868 } 14869 14870} 14871 14872/** 14873 * This class can be used to define a linear fog that grows linearly denser 14874 * with the distance. 14875 * 14876 * ```js 14877 * const scene = new THREE.Scene(); 14878 * scene.fog = new THREE.Fog( 0xcccccc, 10, 15 ); 14879 * ``` 14880 */ 14881class Fog { 14882 14883 /** 14884 * Constructs a new fog. 14885 * 14886 * @param {number|Color} color - The fog's color. 14887 * @param {number} [near=1] - The minimum distance to start applying fog. 14888 * @param {number} [far=1000] - The maximum distance at which fog stops being calculated and applied. 14889 */ 14890 constructor( color, near = 1, far = 1000 ) { 14891 14892 /** 14893 * This flag can be used for type testing. 14894 * 14895 * @type {boolean} 14896 * @readonly 14897 * @default true 14898 */ 14899 this.isFog = true; 14900 14901 /** 14902 * The name of the fog. 14903 * 14904 * @type {string} 14905 */ 14906 this.name = ''; 14907 14908 /** 14909 * The fog's color. 14910 * 14911 * @type {Color} 14912 */ 14913 this.color = new Color( color ); 14914 14915 /** 14916 * The minimum distance to start applying fog. Objects that are less than 14917 * `near` units from the active camera won't be affected by fog. 14918 * 14919 * @type {number} 14920 * @default 1 14921 */ 14922 this.near = near; 14923 14924 /** 14925 * The maximum distance at which fog stops being calculated and applied. 14926 * Objects that are more than `far` units away from the active camera won't 14927 * be affected by fog. 14928 * 14929 * @type {number} 14930 * @default 1000 14931 */ 14932 this.far = far; 14933 14934 } 14935 14936 /** 14937 * Returns a new fog with copied values from this instance. 14938 * 14939 * @return {Fog} A clone of this instance. 14940 */ 14941 clone() { 14942 14943 return new Fog( this.color, this.near, this.far ); 14944 14945 } 14946 14947 /** 14948 * Serializes the fog into JSON. 14949 * 14950 * @param {?(Object|string)} meta - An optional value holding meta information about the serialization. 14951 * @return {Object} A JSON object representing the serialized fog 14952 */ 14953 toJSON( /* meta */ ) { 14954 14955 return { 14956 type: 'Fog', 14957 name: this.name, 14958 color: this.color.getHex(), 14959 near: this.near, 14960 far: this.far 14961 }; 14962 14963 } 14964 14965} 14966 14967/** 14968 * Scenes allow you to set up what is to be rendered and where by three.js. 14969 * This is where you place 3D objects like meshes, lines or lights. 14970 * 14971 * @augments Object3D 14972 */ 14973class Scene extends Object3D { 14974 14975 /** 14976 * Constructs a new scene. 14977 */ 14978 constructor() { 14979 14980 super(); 14981 14982 /** 14983 * This flag can be used for type testing. 14984 * 14985 * @type {boolean} 14986 * @readonly 14987 * @default true 14988 */ 14989 this.isScene = true; 14990 14991 this.type = 'Scene'; 14992 14993 /** 14994 * Defines the background of the scene. Valid inputs are: 14995 * 14996 * - A color for defining a uniform colored background. 14997 * - A texture for defining a (flat) textured background. 14998 * - Cube textures or equirectangular textures for defining a skybox. 14999 * 15000 * @type {?(Color|Texture)} 15001 * @default null 15002 */ 15003 this.background = null; 15004 15005 /** 15006 * Sets the environment map for all physical materials in the scene. However, 15007 * it's not possible to overwrite an existing texture assigned to the `envMap` 15008 * material property. 15009 * 15010 * @type {?Texture} 15011 * @default null 15012 */ 15013 this.environment = null; 15014 15015 /** 15016 * A fog instance defining the type of fog that affects everything 15017 * rendered in the scene. 15018 * 15019 * @type {?(Fog|FogExp2)} 15020 * @default null 15021 */ 15022 this.fog = null; 15023 15024 /** 15025 * Sets the blurriness of the background. Only influences environment maps 15026 * assigned to {@link Scene#background}. Valid input is a float between `0` 15027 * and `1`. 15028 * 15029 * @type {number} 15030 * @default 0 15031 */ 15032 this.backgroundBlurriness = 0; 15033 15034 /** 15035 * Attenuates the color of the background. Only applies to background textures. 15036 * 15037 * @type {number} 15038 * @default 1 15039 */ 15040 this.backgroundIntensity = 1; 15041 15042 /** 15043 * The rotation of the background in radians. Only influences environment maps 15044 * assigned to {@link Scene#background}. 15045 * 15046 * @type {Euler} 15047 * @default (0,0,0) 15048 */ 15049 this.backgroundRotation = new Euler(); 15050 15051 /** 15052 * Attenuates the color of the environment. Only influences environment maps 15053 * assigned to {@link Scene#environment}. 15054 * 15055 * @type {number} 15056 * @default 1 15057 */ 15058 this.environmentIntensity = 1; 15059 15060 /** 15061 * The rotation of the environment map in radians. Only influences physical materials 15062 * in the scene when {@link Scene#environment} is used. 15063 * 15064 * @type {Euler} 15065 * @default (0,0,0) 15066 */ 15067 this.environmentRotation = new Euler(); 15068 15069 /** 15070 * Forces everything in the scene to be rendered with the defined material. It is possible 15071 * to exclude materials from override by setting {@link Material#allowOverride} to `false`. 15072 * 15073 * @type {?Material} 15074 * @default null 15075 */ 15076 this.overrideMaterial = null; 15077 15078 if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { 15079 15080 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); 15081 15082 } 15083 15084 } 15085 15086 copy( source, recursive ) { 15087 15088 super.copy( source, recursive ); 15089 15090 if ( source.background !== null ) this.background = source.background.clone(); 15091 if ( source.environment !== null ) this.environment = source.environment.clone(); 15092 if ( source.fog !== null ) this.fog = source.fog.clone(); 15093 15094 this.backgroundBlurriness = source.backgroundBlurriness; 15095 this.backgroundIntensity = source.backgroundIntensity; 15096 this.backgroundRotation.copy( source.backgroundRotation ); 15097 15098 this.environmentIntensity = source.environmentIntensity; 15099 this.environmentRotation.copy( source.environmentRotation ); 15100 15101 if ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone(); 15102 15103 this.matrixAutoUpdate = source.matrixAutoUpdate; 15104 15105 return this; 15106 15107 } 15108 15109 toJSON( meta ) { 15110 15111 const data = super.toJSON( meta ); 15112 15113 if ( this.fog !== null ) data.object.fog = this.fog.toJSON(); 15114 15115
vendor: 6,676 bytes, lines 15115-15339
15115if ( this.backgroundBlurriness > 0 ) data.object.backgroundBlurriness = this.backgroundBlurriness; 15116 if ( this.backgroundIntensity !== 1 ) data.object.backgroundIntensity = this.backgroundIntensity; 15117 data.object.backgroundRotation = this.backgroundRotation.toArray(); 15118 15119 if ( this.environmentIntensity !== 1 ) data.object.environmentIntensity = this.environmentIntensity; 15120 data.object.environmentRotation = this.environmentRotation.toArray(); 15121 15122 return data; 15123 15124 } 15125 15126} 15127 15128const _v0$2 = /*@__PURE__*/ new Vector3(); 15129const _v1$5 = /*@__PURE__*/ new Vector3(); 15130const _v2$4 = /*@__PURE__*/ new Vector3(); 15131const _v3$2 = /*@__PURE__*/ new Vector3(); 15132 15133const _vab = /*@__PURE__*/ new Vector3(); 15134const _vac = /*@__PURE__*/ new Vector3(); 15135const _vbc = /*@__PURE__*/ new Vector3(); 15136const _vap = /*@__PURE__*/ new Vector3(); 15137const _vbp = /*@__PURE__*/ new Vector3(); 15138const _vcp = /*@__PURE__*/ new Vector3(); 15139 15140const _v40 = /*@__PURE__*/ new Vector4(); 15141const _v41 = /*@__PURE__*/ new Vector4(); 15142const _v42 = /*@__PURE__*/ new Vector4(); 15143 15144/** 15145 * A geometric triangle as defined by three vectors representing its three corners. 15146 */ 15147class Triangle { 15148 15149 /** 15150 * Constructs a new triangle. 15151 * 15152 * @param {Vector3} [a=(0,0,0)] - The first corner of the triangle. 15153 * @param {Vector3} [b=(0,0,0)] - The second corner of the triangle. 15154 * @param {Vector3} [c=(0,0,0)] - The third corner of the triangle. 15155 */ 15156 constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) { 15157 15158 /** 15159 * The first corner of the triangle. 15160 * 15161 * @type {Vector3} 15162 */ 15163 this.a = a; 15164 15165 /** 15166 * The second corner of the triangle. 15167 * 15168 * @type {Vector3} 15169 */ 15170 this.b = b; 15171 15172 /** 15173 * The third corner of the triangle. 15174 * 15175 * @type {Vector3} 15176 */ 15177 this.c = c; 15178 15179 } 15180 15181 /** 15182 * Computes the normal vector of a triangle. 15183 * 15184 * @param {Vector3} a - The first corner of the triangle. 15185 * @param {Vector3} b - The second corner of the triangle. 15186 * @param {Vector3} c - The third corner of the triangle. 15187 * @param {Vector3} target - The target vector that is used to store the method's result. 15188 * @return {Vector3} The triangle's normal. 15189 */ 15190 static getNormal( a, b, c, target ) { 15191 15192 target.subVectors( c, b ); 15193 _v0$2.subVectors( a, b ); 15194 target.cross( _v0$2 ); 15195 15196 const targetLengthSq = target.lengthSq(); 15197 if ( targetLengthSq > 0 ) { 15198 15199 return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) ); 15200 15201 } 15202 15203 return target.set( 0, 0, 0 ); 15204 15205 } 15206 15207 /** 15208 * Computes a barycentric coordinates from the given vector. 15209 * Returns `null` if the triangle is degenerate. 15210 * 15211 * @param {Vector3} point - A point in 3D space. 15212 * @param {Vector3} a - The first corner of the triangle. 15213 * @param {Vector3} b - The second corner of the triangle. 15214 * @param {Vector3} c - The third corner of the triangle. 15215 * @param {Vector3} target - The target vector that is used to store the method's result. 15216 * @return {?Vector3} The barycentric coordinates for the given point 15217 */ 15218 static getBarycoord( point, a, b, c, target ) { 15219 15220 // based on: http://www.blackpawn.com/texts/pointinpoly/default.html 15221 15222 _v0$2.subVectors( c, a ); 15223 _v1$5.subVectors( b, a ); 15224 _v2$4.subVectors( point, a ); 15225 15226 const dot00 = _v0$2.dot( _v0$2 ); 15227 const dot01 = _v0$2.dot( _v1$5 ); 15228 const dot02 = _v0$2.dot( _v2$4 ); 15229 const dot11 = _v1$5.dot( _v1$5 ); 15230 const dot12 = _v1$5.dot( _v2$4 ); 15231 15232 const denom = ( dot00 * dot11 - dot01 * dot01 ); 15233 15234 // collinear or singular triangle 15235 if ( denom === 0 ) { 15236 15237 target.set( 0, 0, 0 ); 15238 return null; 15239 15240 } 15241 15242 const invDenom = 1 / denom; 15243 const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; 15244 const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; 15245 15246 // barycentric coordinates must always sum to 1 15247 return target.set( 1 - u - v, v, u ); 15248 15249 } 15250 15251 /** 15252 * Returns `true` if the given point, when projected onto the plane of the 15253 * triangle, lies within the triangle. 15254 * 15255 * @param {Vector3} point - The point in 3D space to test. 15256 * @param {Vector3} a - The first corner of the triangle. 15257 * @param {Vector3} b - The second corner of the triangle. 15258 * @param {Vector3} c - The third corner of the triangle. 15259 * @return {boolean} Whether the given point, when projected onto the plane of the 15260 * triangle, lies within the triangle or not. 15261 */ 15262 static containsPoint( point, a, b, c ) { 15263 15264 // if the triangle is degenerate then we can't contain a point 15265 if ( this.getBarycoord( point, a, b, c, _v3$2 ) === null ) { 15266 15267 return false; 15268 15269 } 15270 15271 return ( _v3$2.x >= 0 ) && ( _v3$2.y >= 0 ) && ( ( _v3$2.x + _v3$2.y ) <= 1 ); 15272 15273 } 15274 15275 /** 15276 * Computes the value barycentrically interpolated for the given point on the 15277 * triangle. Returns `null` if the triangle is degenerate. 15278 * 15279 * @param {Vector3} point - Position of interpolated point. 15280 * @param {Vector3} p1 - The first corner of the triangle. 15281 * @param {Vector3} p2 - The second corner of the triangle. 15282 * @param {Vector3} p3 - The third corner of the triangle. 15283 * @param {Vector3} v1 - Value to interpolate of first vertex. 15284 * @param {Vector3} v2 - Value to interpolate of second vertex. 15285 * @param {Vector3} v3 - Value to interpolate of third vertex. 15286 * @param {Vector3} target - The target vector that is used to store the method's result. 15287 * @return {?Vector3} The interpolated value. 15288 */ 15289 static getInterpolation( point, p1, p2, p3, v1, v2, v3, target ) { 15290 15291 if ( this.getBarycoord( point, p1, p2, p3, _v3$2 ) === null ) { 15292 15293 target.x = 0; 15294 target.y = 0; 15295 if ( 'z' in target ) target.z = 0; 15296 if ( 'w' in target ) target.w = 0; 15297 return null; 15298 15299 } 15300 15301 target.setScalar( 0 ); 15302 target.addScaledVector( v1, _v3$2.x ); 15303 target.addScaledVector( v2, _v3$2.y ); 15304 target.addScaledVector( v3, _v3$2.z ); 15305 15306 return target; 15307 15308 } 15309 15310 /** 15311 * Computes the value barycentrically interpolated for the given attribute and indices. 15312 * 15313 * @param {BufferAttribute} attr - The attribute to interpolate. 15314 * @param {number} i1 - Index of first vertex. 15315 * @param {number} i2 - Index of second vertex. 15316 * @param {number} i3 - Index of third vertex. 15317 * @param {Vector3} barycoord - The barycoordinate value to use to interpolate. 15318 * @param {Vector3} target - The target vector that is used to store the method's result. 15319 * @return {Vector3} The interpolated attribute value. 15320 */ 15321 static getInterpolatedAttribute( attr, i1, i2, i3, barycoord, target ) { 15322 15323 _v40.setScalar( 0 ); 15324 _v41.setScalar( 0 ); 15325 _v42.setScalar( 0 ); 15326 15327 _v40.fromBufferAttribute( attr, i1 ); 15328 _v41.fromBufferAttribute( attr, i2 ); 15329 _v42.fromBufferAttribute( attr, i3 ); 15330 15331 target.setScalar( 0 ); 15332 target.addScaledVector( _v40, barycoord.x ); 15333 target.addScaledVector( _v41, barycoord.y ); 15334 target.addScaledVector( _v42, barycoord.z ); 15335 15336 return target; 15337 15338 } 15339
vendor: 8,587 bytes, lines 15340-15648
15340 /** 15341 * Returns `true` if the triangle is oriented towards the given direction. 15342 * 15343 * @param {Vector3} a - The first corner of the triangle. 15344 * @param {Vector3} b - The second corner of the triangle. 15345 * @param {Vector3} c - The third corner of the triangle. 15346 * @param {Vector3} direction - The (normalized) direction vector. 15347 * @return {boolean} Whether the triangle is oriented towards the given direction or not. 15348 */ 15349 static isFrontFacing( a, b, c, direction ) { 15350 15351 _v0$2.subVectors( c, b ); 15352 _v1$5.subVectors( a, b ); 15353 15354 // strictly front facing 15355 return _v0$2.cross( _v1$5 ).dot( direction ) < 0; 15356 15357 } 15358 15359 /** 15360 * Sets the triangle's vertices by copying the given values. 15361 * 15362 * @param {Vector3} a - The first corner of the triangle. 15363 * @param {Vector3} b - The second corner of the triangle. 15364 * @param {Vector3} c - The third corner of the triangle. 15365 * @return {Triangle} A reference to this triangle. 15366 */ 15367 set( a, b, c ) { 15368 15369 this.a.copy( a ); 15370 this.b.copy( b ); 15371 this.c.copy( c ); 15372 15373 return this; 15374 15375 } 15376 15377 /** 15378 * Sets the triangle's vertices by copying the given array values. 15379 * 15380 * @param {Array<Vector3>} points - An array with 3D points. 15381 * @param {number} i0 - The array index representing the first corner of the triangle. 15382 * @param {number} i1 - The array index representing the second corner of the triangle. 15383 * @param {number} i2 - The array index representing the third corner of the triangle. 15384 * @return {Triangle} A reference to this triangle. 15385 */ 15386 setFromPointsAndIndices( points, i0, i1, i2 ) { 15387 15388 this.a.copy( points[ i0 ] ); 15389 this.b.copy( points[ i1 ] ); 15390 this.c.copy( points[ i2 ] ); 15391 15392 return this; 15393 15394 } 15395 15396 /** 15397 * Sets the triangle's vertices by copying the given attribute values. 15398 * 15399 * @param {BufferAttribute} attribute - A buffer attribute with 3D points data. 15400 * @param {number} i0 - The attribute index representing the first corner of the triangle. 15401 * @param {number} i1 - The attribute index representing the second corner of the triangle. 15402 * @param {number} i2 - The attribute index representing the third corner of the triangle. 15403 * @return {Triangle} A reference to this triangle. 15404 */ 15405 setFromAttributeAndIndices( attribute, i0, i1, i2 ) { 15406 15407 this.a.fromBufferAttribute( attribute, i0 ); 15408 this.b.fromBufferAttribute( attribute, i1 ); 15409 this.c.fromBufferAttribute( attribute, i2 ); 15410 15411 return this; 15412 15413 } 15414 15415 /** 15416 * Returns a new triangle with copied values from this instance. 15417 * 15418 * @return {Triangle} A clone of this instance. 15419 */ 15420 clone() { 15421 15422 return new this.constructor().copy( this ); 15423 15424 } 15425 15426 /** 15427 * Copies the values of the given triangle to this instance. 15428 * 15429 * @param {Triangle} triangle - The triangle to copy. 15430 * @return {Triangle} A reference to this triangle. 15431 */ 15432 copy( triangle ) { 15433 15434 this.a.copy( triangle.a ); 15435 this.b.copy( triangle.b ); 15436 this.c.copy( triangle.c ); 15437 15438 return this; 15439 15440 } 15441 15442 /** 15443 * Computes the area of the triangle. 15444 * 15445 * @return {number} The triangle's area. 15446 */ 15447 getArea() { 15448 15449 _v0$2.subVectors( this.c, this.b ); 15450 _v1$5.subVectors( this.a, this.b ); 15451 15452 return _v0$2.cross( _v1$5 ).length() * 0.5; 15453 15454 } 15455 15456 /** 15457 * Computes the midpoint of the triangle. 15458 * 15459 * @param {Vector3} target - The target vector that is used to store the method's result. 15460 * @return {Vector3} The triangle's midpoint. 15461 */ 15462 getMidpoint( target ) { 15463 15464 return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); 15465 15466 } 15467 15468 /** 15469 * Computes the normal of the triangle. 15470 * 15471 * @param {Vector3} target - The target vector that is used to store the method's result. 15472 * @return {Vector3} The triangle's normal. 15473 */ 15474 getNormal( target ) { 15475 15476 return Triangle.getNormal( this.a, this.b, this.c, target ); 15477 15478 } 15479 15480 /** 15481 * Computes a plane the triangle lies within. 15482 * 15483 * @param {Plane} target - The target vector that is used to store the method's result. 15484 * @return {Plane} The plane the triangle lies within. 15485 */ 15486 getPlane( target ) { 15487 15488 return target.setFromCoplanarPoints( this.a, this.b, this.c ); 15489 15490 } 15491 15492 /** 15493 * Computes a barycentric coordinates from the given vector. 15494 * Returns `null` if the triangle is degenerate. 15495 * 15496 * @param {Vector3} point - A point in 3D space. 15497 * @param {Vector3} target - The target vector that is used to store the method's result. 15498 * @return {?Vector3} The barycentric coordinates for the given point 15499 */ 15500 getBarycoord( point, target ) { 15501 15502 return Triangle.getBarycoord( point, this.a, this.b, this.c, target ); 15503 15504 } 15505 15506 /** 15507 * Computes the value barycentrically interpolated for the given point on the 15508 * triangle. Returns `null` if the triangle is degenerate. 15509 * 15510 * @param {Vector3} point - Position of interpolated point. 15511 * @param {Vector3} v1 - Value to interpolate of first vertex. 15512 * @param {Vector3} v2 - Value to interpolate of second vertex. 15513 * @param {Vector3} v3 - Value to interpolate of third vertex. 15514 * @param {Vector3} target - The target vector that is used to store the method's result. 15515 * @return {?Vector3} The interpolated value. 15516 */ 15517 getInterpolation( point, v1, v2, v3, target ) { 15518 15519 return Triangle.getInterpolation( point, this.a, this.b, this.c, v1, v2, v3, target ); 15520 15521 } 15522 15523 /** 15524 * Returns `true` if the given point, when projected onto the plane of the 15525 * triangle, lies within the triangle. 15526 * 15527 * @param {Vector3} point - The point in 3D space to test. 15528 * @return {boolean} Whether the given point, when projected onto the plane of the 15529 * triangle, lies within the triangle or not. 15530 */ 15531 containsPoint( point ) { 15532 15533 return Triangle.containsPoint( point, this.a, this.b, this.c ); 15534 15535 } 15536 15537 /** 15538 * Returns `true` if the triangle is oriented towards the given direction. 15539 * 15540 * @param {Vector3} direction - The (normalized) direction vector. 15541 * @return {boolean} Whether the triangle is oriented towards the given direction or not. 15542 */ 15543 isFrontFacing( direction ) { 15544 15545 return Triangle.isFrontFacing( this.a, this.b, this.c, direction ); 15546 15547 } 15548 15549 /** 15550 * Returns `true` if this triangle intersects with the given box. 15551 * 15552 * @param {Box3} box - The box to intersect. 15553 * @return {boolean} Whether this triangle intersects with the given box or not. 15554 */ 15555 intersectsBox( box ) { 15556 15557 return box.intersectsTriangle( this ); 15558 15559 } 15560 15561 /** 15562 * Returns the closest point on the triangle to the given point. 15563 * 15564 * @param {Vector3} p - The point to compute the closest point for. 15565 * @param {Vector3} target - The target vector that is used to store the method's result. 15566 * @return {Vector3} The closest point on the triangle. 15567 */ 15568 closestPointToPoint( p, target ) { 15569 15570 const a = this.a, b = this.b, c = this.c; 15571 let v, w; 15572 15573 // algorithm thanks to Real-Time Collision Detection by Christer Ericson, 15574 // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc., 15575 // under the accompanying license; see chapter 5.1.5 for detailed explanation. 15576 // basically, we're distinguishing which of the voronoi regions of the triangle 15577 // the point lies in with the minimum amount of redundant computation. 15578 15579 _vab.subVectors( b, a ); 15580 _vac.subVectors( c, a ); 15581 _vap.subVectors( p, a ); 15582 const d1 = _vab.dot( _vap ); 15583 const d2 = _vac.dot( _vap ); 15584 if ( d1 <= 0 && d2 <= 0 ) { 15585 15586 // vertex region of A; barycentric coords (1, 0, 0) 15587 return target.copy( a ); 15588 15589 } 15590 15591 _vbp.subVectors( p, b ); 15592 const d3 = _vab.dot( _vbp ); 15593 const d4 = _vac.dot( _vbp ); 15594 if ( d3 >= 0 && d4 <= d3 ) { 15595 15596 // vertex region of B; barycentric coords (0, 1, 0) 15597 return target.copy( b ); 15598 15599 } 15600 15601 const vc = d1 * d4 - d3 * d2; 15602 if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) { 15603 15604 v = d1 / ( d1 - d3 ); 15605 // edge region of AB; barycentric coords (1-v, v, 0) 15606 return target.copy( a ).addScaledVector( _vab, v ); 15607 15608 } 15609 15610 _vcp.subVectors( p, c ); 15611 const d5 = _vab.dot( _vcp ); 15612 const d6 = _vac.dot( _vcp ); 15613 if ( d6 >= 0 && d5 <= d6 ) { 15614 15615 // vertex region of C; barycentric coords (0, 0, 1) 15616 return target.copy( c ); 15617 15618 } 15619 15620 const vb = d5 * d2 - d1 * d6; 15621 if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) { 15622 15623 w = d2 / ( d2 - d6 ); 15624 // edge region of AC; barycentric coords (1-w, 0, w) 15625 return target.copy( a ).addScaledVector( _vac, w ); 15626 15627 } 15628 15629 const va = d3 * d6 - d5 * d4; 15630 if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) { 15631 15632 _vbc.subVectors( c, b ); 15633 w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) ); 15634 // edge region of BC; barycentric coords (0, 1-w, w) 15635 return target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC 15636 15637 } 15638 15639 // face region 15640 const denom = 1 / ( va + vb + vc ); 15641 // u = va * denom 15642 v = vb * denom; 15643 w = vc * denom; 15644 15645 return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w ); 15646 15647 } 15648
vendor: 8,739 bytes, lines 15649-15987
15649 /** 15650 * Returns `true` if this triangle is equal with the given one. 15651 * 15652 * @param {Triangle} triangle - The triangle to test for equality. 15653 * @return {boolean} Whether this triangle is equal with the given one. 15654 */ 15655 equals( triangle ) { 15656 15657 return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); 15658 15659 } 15660 15661} 15662 15663/** 15664 * Represents an axis-aligned bounding box (AABB) in 3D space. 15665 */ 15666class Box3 { 15667 15668 /** 15669 * Constructs a new bounding box. 15670 * 15671 * @param {Vector3} [min=(Infinity,Infinity,Infinity)] - A vector representing the lower boundary of the box. 15672 * @param {Vector3} [max=(-Infinity,-Infinity,-Infinity)] - A vector representing the upper boundary of the box. 15673 */ 15674 constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) { 15675 15676 /** 15677 * This flag can be used for type testing. 15678 * 15679 * @type {boolean} 15680 * @readonly 15681 * @default true 15682 */ 15683 this.isBox3 = true; 15684 15685 /** 15686 * The lower boundary of the box. 15687 * 15688 * @type {Vector3} 15689 */ 15690 this.min = min; 15691 15692 /** 15693 * The upper boundary of the box. 15694 * 15695 * @type {Vector3} 15696 */ 15697 this.max = max; 15698 15699 } 15700 15701 /** 15702 * Sets the lower and upper boundaries of this box. 15703 * Please note that this method only copies the values from the given objects. 15704 * 15705 * @param {Vector3} min - The lower boundary of the box. 15706 * @param {Vector3} max - The upper boundary of the box. 15707 * @return {Box3} A reference to this bounding box. 15708 */ 15709 set( min, max ) { 15710 15711 this.min.copy( min ); 15712 this.max.copy( max ); 15713 15714 return this; 15715 15716 } 15717 15718 /** 15719 * Sets the upper and lower bounds of this box so it encloses the position data 15720 * in the given array. 15721 * 15722 * @param {Array<number>} array - An array holding 3D position data. 15723 * @return {Box3} A reference to this bounding box. 15724 */ 15725 setFromArray( array ) { 15726 15727 this.makeEmpty(); 15728 15729 for ( let i = 0, il = array.length; i < il; i += 3 ) { 15730 15731 this.expandByPoint( _vector$b.fromArray( array, i ) ); 15732 15733 } 15734 15735 return this; 15736 15737 } 15738 15739 /** 15740 * Sets the upper and lower bounds of this box so it encloses the position data 15741 * in the given buffer attribute. 15742 * 15743 * @param {BufferAttribute} attribute - A buffer attribute holding 3D position data. 15744 * @return {Box3} A reference to this bounding box. 15745 */ 15746 setFromBufferAttribute( attribute ) { 15747 15748 this.makeEmpty(); 15749 15750 for ( let i = 0, il = attribute.count; i < il; i ++ ) { 15751 15752 this.expandByPoint( _vector$b.fromBufferAttribute( attribute, i ) ); 15753 15754 } 15755 15756 return this; 15757 15758 } 15759 15760 /** 15761 * Sets the upper and lower bounds of this box so it encloses the position data 15762 * in the given array. 15763 * 15764 * @param {Array<Vector3>} points - An array holding 3D position data as instances of {@link Vector3}. 15765 * @return {Box3} A reference to this bounding box. 15766 */ 15767 setFromPoints( points ) { 15768 15769 this.makeEmpty(); 15770 15771 for ( let i = 0, il = points.length; i < il; i ++ ) { 15772 15773 this.expandByPoint( points[ i ] ); 15774 15775 } 15776 15777 return this; 15778 15779 } 15780 15781 /** 15782 * Centers this box on the given center vector and sets this box's width, height and 15783 * depth to the given size values. 15784 * 15785 * @param {Vector3} center - The center of the box. 15786 * @param {Vector3} size - The x, y and z dimensions of the box. 15787 * @return {Box3} A reference to this bounding box. 15788 */ 15789 setFromCenterAndSize( center, size ) { 15790 15791 const halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 ); 15792 15793 this.min.copy( center ).sub( halfSize ); 15794 this.max.copy( center ).add( halfSize ); 15795 15796 return this; 15797 15798 } 15799 15800 /** 15801 * Computes the world-axis-aligned bounding box for the given 3D object 15802 * (including its children), accounting for the object's, and children's, 15803 * world transforms. The function may result in a larger box than strictly necessary. 15804 * 15805 * @param {Object3D} object - The 3D object to compute the bounding box for. 15806 * @param {boolean} [precise=false] - If set to `true`, the method computes the smallest 15807 * world-axis-aligned bounding box at the expense of more computation. 15808 * @return {Box3} A reference to this bounding box. 15809 */ 15810 setFromObject( object, precise = false ) { 15811 15812 this.makeEmpty(); 15813 15814 return this.expandByObject( object, precise ); 15815 15816 } 15817 15818 /** 15819 * Returns a new box with copied values from this instance. 15820 * 15821 * @return {Box3} A clone of this instance. 15822 */ 15823 clone() { 15824 15825 return new this.constructor().copy( this ); 15826 15827 } 15828 15829 /** 15830 * Copies the values of the given box to this instance. 15831 * 15832 * @param {Box3} box - The box to copy. 15833 * @return {Box3} A reference to this bounding box. 15834 */ 15835 copy( box ) { 15836 15837 this.min.copy( box.min ); 15838 this.max.copy( box.max ); 15839 15840 return this; 15841 15842 } 15843 15844 /** 15845 * Makes this box empty which means in encloses a zero space in 3D. 15846 * 15847 * @return {Box3} A reference to this bounding box. 15848 */ 15849 makeEmpty() { 15850 15851 this.min.x = this.min.y = this.min.z = + Infinity; 15852 this.max.x = this.max.y = this.max.z = - Infinity; 15853 15854 return this; 15855 15856 } 15857 15858 /** 15859 * Returns true if this box includes zero points within its bounds. 15860 * Note that a box with equal lower and upper bounds still includes one 15861 * point, the one both bounds share. 15862 * 15863 * @return {boolean} Whether this box is empty or not. 15864 */ 15865 isEmpty() { 15866 15867 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes 15868 15869 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); 15870 15871 } 15872 15873 /** 15874 * Returns the center point of this box. 15875 * 15876 * @param {Vector3} target - The target vector that is used to store the method's result. 15877 * @return {Vector3} The center point. 15878 */ 15879 getCenter( target ) { 15880 15881 return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); 15882 15883 } 15884 15885 /** 15886 * Returns the dimensions of this box. 15887 * 15888 * @param {Vector3} target - The target vector that is used to store the method's result. 15889 * @return {Vector3} The size. 15890 */ 15891 getSize( target ) { 15892 15893 return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min ); 15894 15895 } 15896 15897 /** 15898 * Expands the boundaries of this box to include the given point. 15899 * 15900 * @param {Vector3} point - The point that should be included by the bounding box. 15901 * @return {Box3} A reference to this bounding box. 15902 */ 15903 expandByPoint( point ) { 15904 15905 this.min.min( point ); 15906 this.max.max( point ); 15907 15908 return this; 15909 15910 } 15911 15912 /** 15913 * Expands this box equilaterally by the given vector. The width of this 15914 * box will be expanded by the x component of the vector in both 15915 * directions. The height of this box will be expanded by the y component of 15916 * the vector in both directions. The depth of this box will be 15917 * expanded by the z component of the vector in both directions. 15918 * 15919 * @param {Vector3} vector - The vector that should expand the bounding box. 15920 * @return {Box3} A reference to this bounding box. 15921 */ 15922 expandByVector( vector ) { 15923 15924 this.min.sub( vector ); 15925 this.max.add( vector ); 15926 15927 return this; 15928 15929 } 15930 15931 /** 15932 * Expands each dimension of the box by the given scalar. If negative, the 15933 * dimensions of the box will be contracted. 15934 * 15935 * @param {number} scalar - The scalar value that should expand the bounding box. 15936 * @return {Box3} A reference to this bounding box. 15937 */ 15938 expandByScalar( scalar ) { 15939 15940 this.min.addScalar( - scalar ); 15941 this.max.addScalar( scalar ); 15942 15943 return this; 15944 15945 } 15946 15947 /** 15948 * Expands the boundaries of this box to include the given 3D object and 15949 * its children, accounting for the object's, and children's, world 15950 * transforms. The function may result in a larger box than strictly 15951 * necessary (unless the precise parameter is set to true). 15952 * 15953 * @param {Object3D} object - The 3D object that should expand the bounding box. 15954 * @param {boolean} precise - If set to `true`, the method expands the bounding box 15955 * as little as necessary at the expense of more computation. 15956 * @return {Box3} A reference to this bounding box. 15957 */ 15958 expandByObject( object, precise = false ) { 15959 15960 // Computes the world-axis-aligned bounding box of an object (including its children), 15961 // accounting for both the object's, and children's, world transforms 15962 15963 object.updateWorldMatrix( false, false ); 15964 15965 const geometry = object.geometry; 15966 15967 if ( geometry !== undefined ) { 15968 15969 const positionAttribute = geometry.getAttribute( 'position' ); 15970 15971 // precise AABB computation based on vertex data requires at least a position attribute. 15972 // instancing isn't supported so far and uses the normal (conservative) code path. 15973 15974 if ( precise === true && positionAttribute !== undefined && object.isInstancedMesh !== true ) { 15975 15976 for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) { 15977 15978 if ( object.isMesh === true ) { 15979 15980 object.getVertexPosition( i, _vector$b ); 15981 15982 } else { 15983 15984 _vector$b.fromBufferAttribute( positionAttribute, i ); 15985 15986 } 15987
vendor: 33,436 bytes, lines 15988-17339
15988 _vector$b.applyMatrix4( object.matrixWorld ); 15989 this.expandByPoint( _vector$b ); 15990 15991 } 15992 15993 } else { 15994 15995 if ( object.boundingBox !== undefined ) { 15996 15997 // object-level bounding box 15998 15999 if ( object.boundingBox === null ) { 16000 16001 object.computeBoundingBox(); 16002 16003 } 16004 16005 _box$4.copy( object.boundingBox ); 16006 16007 16008 } else { 16009 16010 // geometry-level bounding box 16011 16012 if ( geometry.boundingBox === null ) { 16013 16014 geometry.computeBoundingBox(); 16015 16016 } 16017 16018 _box$4.copy( geometry.boundingBox ); 16019 16020 } 16021 16022 _box$4.applyMatrix4( object.matrixWorld ); 16023 16024 this.union( _box$4 ); 16025 16026 } 16027 16028 } 16029 16030 const children = object.children; 16031 16032 for ( let i = 0, l = children.length; i < l; i ++ ) { 16033 16034 this.expandByObject( children[ i ], precise ); 16035 16036 } 16037 16038 return this; 16039 16040 } 16041 16042 /** 16043 * Returns `true` if the given point lies within or on the boundaries of this box. 16044 * 16045 * @param {Vector3} point - The point to test. 16046 * @return {boolean} Whether the bounding box contains the given point or not. 16047 */ 16048 containsPoint( point ) { 16049 16050 return point.x >= this.min.x && point.x <= this.max.x && 16051 point.y >= this.min.y && point.y <= this.max.y && 16052 point.z >= this.min.z && point.z <= this.max.z; 16053 16054 } 16055 16056 /** 16057 * Returns `true` if this bounding box includes the entirety of the given bounding box. 16058 * If this box and the given one are identical, this function also returns `true`. 16059 * 16060 * @param {Box3} box - The bounding box to test. 16061 * @return {boolean} Whether the bounding box contains the given bounding box or not. 16062 */ 16063 containsBox( box ) { 16064 16065 return this.min.x <= box.min.x && box.max.x <= this.max.x && 16066 this.min.y <= box.min.y && box.max.y <= this.max.y && 16067 this.min.z <= box.min.z && box.max.z <= this.max.z; 16068 16069 } 16070 16071 /** 16072 * Returns a point as a proportion of this box's width, height and depth. 16073 * 16074 * @param {Vector3} point - A point in 3D space. 16075 * @param {Vector3} target - The target vector that is used to store the method's result. 16076 * @return {Vector3} A point as a proportion of this box's width, height and depth. 16077 */ 16078 getParameter( point, target ) { 16079 16080 // This can potentially have a divide by zero if the box 16081 // has a size dimension of 0. 16082 16083 return target.set( 16084 ( point.x - this.min.x ) / ( this.max.x - this.min.x ), 16085 ( point.y - this.min.y ) / ( this.max.y - this.min.y ), 16086 ( point.z - this.min.z ) / ( this.max.z - this.min.z ) 16087 ); 16088 16089 } 16090 16091 /** 16092 * Returns `true` if the given bounding box intersects with this bounding box. 16093 * 16094 * @param {Box3} box - The bounding box to test. 16095 * @return {boolean} Whether the given bounding box intersects with this bounding box. 16096 */ 16097 intersectsBox( box ) { 16098 16099 // using 6 splitting planes to rule out intersections. 16100 return box.max.x >= this.min.x && box.min.x <= this.max.x && 16101 box.max.y >= this.min.y && box.min.y <= this.max.y && 16102 box.max.z >= this.min.z && box.min.z <= this.max.z; 16103 16104 } 16105 16106 /** 16107 * Returns `true` if the given bounding sphere intersects with this bounding box. 16108 * 16109 * @param {Sphere} sphere - The bounding sphere to test. 16110 * @return {boolean} Whether the given bounding sphere intersects with this bounding box. 16111 */ 16112 intersectsSphere( sphere ) { 16113 16114 // Find the point on the AABB closest to the sphere center. 16115 this.clampPoint( sphere.center, _vector$b ); 16116 16117 // If that point is inside the sphere, the AABB and sphere intersect. 16118 return _vector$b.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius ); 16119 16120 } 16121 16122 /** 16123 * Returns `true` if the given plane intersects with this bounding box. 16124 * 16125 * @param {Plane} plane - The plane to test. 16126 * @return {boolean} Whether the given plane intersects with this bounding box. 16127 */ 16128 intersectsPlane( plane ) { 16129 16130 // We compute the minimum and maximum dot product values. If those values 16131 // are on the same side (back or front) of the plane, then there is no intersection. 16132 16133 let min, max; 16134 16135 if ( plane.normal.x > 0 ) { 16136 16137 min = plane.normal.x * this.min.x; 16138 max = plane.normal.x * this.max.x; 16139 16140 } else { 16141 16142 min = plane.normal.x * this.max.x; 16143 max = plane.normal.x * this.min.x; 16144 16145 } 16146 16147 if ( plane.normal.y > 0 ) { 16148 16149 min += plane.normal.y * this.min.y; 16150 max += plane.normal.y * this.max.y; 16151 16152 } else { 16153 16154 min += plane.normal.y * this.max.y; 16155 max += plane.normal.y * this.min.y; 16156 16157 } 16158 16159 if ( plane.normal.z > 0 ) { 16160 16161 min += plane.normal.z * this.min.z; 16162 max += plane.normal.z * this.max.z; 16163 16164 } else { 16165 16166 min += plane.normal.z * this.max.z; 16167 max += plane.normal.z * this.min.z; 16168 16169 } 16170 16171 return ( min <= - plane.constant && max >= - plane.constant ); 16172 16173 } 16174 16175 /** 16176 * Returns `true` if the given triangle intersects with this bounding box. 16177 * 16178 * @param {Triangle} triangle - The triangle to test. 16179 * @return {boolean} Whether the given triangle intersects with this bounding box. 16180 */ 16181 intersectsTriangle( triangle ) { 16182 16183 if ( this.isEmpty() ) { 16184 16185 return false; 16186 16187 } 16188 16189 // compute box center and extents 16190 this.getCenter( _center ); 16191 _extents.subVectors( this.max, _center ); 16192 16193 // translate triangle to aabb origin 16194 _v0$1.subVectors( triangle.a, _center ); 16195 _v1$4.subVectors( triangle.b, _center ); 16196 _v2$3.subVectors( triangle.c, _center ); 16197 16198 // compute edge vectors for triangle 16199 _f0.subVectors( _v1$4, _v0$1 ); 16200 _f1.subVectors( _v2$3, _v1$4 ); 16201 _f2.subVectors( _v0$1, _v2$3 ); 16202 16203 // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb 16204 // 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 16205 // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned) 16206 let axes = [ 16207 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y, 16208 _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x, 16209 - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0 16210 ]; 16211 if ( ! satForAxes( axes, _v0$1, _v1$4, _v2$3, _extents ) ) { 16212 16213 return false; 16214 16215 } 16216 16217 // test 3 face normals from the aabb 16218 axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]; 16219 if ( ! satForAxes( axes, _v0$1, _v1$4, _v2$3, _extents ) ) { 16220 16221 return false; 16222 16223 } 16224 16225 // finally testing the face normal of the triangle 16226 // use already existing triangle edge vectors here 16227 _triangleNormal.crossVectors( _f0, _f1 ); 16228 axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ]; 16229 16230 return satForAxes( axes, _v0$1, _v1$4, _v2$3, _extents ); 16231 16232 } 16233 16234 /** 16235 * Clamps the given point within the bounds of this box. 16236 * 16237 * @param {Vector3} point - The point to clamp. 16238 * @param {Vector3} target - The target vector that is used to store the method's result. 16239 * @return {Vector3} The clamped point. 16240 */ 16241 clampPoint( point, target ) { 16242 16243 return target.copy( point ).clamp( this.min, this.max ); 16244 16245 } 16246 16247 /** 16248 * Returns the euclidean distance from any edge of this box to the specified point. If 16249 * the given point lies inside of this box, the distance will be `0`. 16250 * 16251 * @param {Vector3} point - The point to compute the distance to. 16252 * @return {number} The euclidean distance. 16253 */ 16254 distanceToPoint( point ) { 16255 16256 return this.clampPoint( point, _vector$b ).distanceTo( point ); 16257 16258 } 16259 16260 /** 16261 * Returns a bounding sphere that encloses this bounding box. 16262 * 16263 * @param {Sphere} target - The target sphere that is used to store the method's result. 16264 * @return {Sphere} The bounding sphere that encloses this bounding box. 16265 */ 16266 getBoundingSphere( target ) { 16267 16268 if ( this.isEmpty() ) { 16269 16270 target.makeEmpty(); 16271 16272 } else { 16273 16274 this.getCenter( target.center ); 16275 16276 target.radius = this.getSize( _vector$b ).length() * 0.5; 16277 16278 } 16279 16280 return target; 16281 16282 } 16283 16284 /** 16285 * Computes the intersection of this bounding box and the given one, setting the upper 16286 * bound of this box to the lesser of the two boxes' upper bounds and the 16287 * lower bound of this box to the greater of the two boxes' lower bounds. If 16288 * there's no overlap, makes this box empty. 16289 * 16290 * @param {Box3} box - The bounding box to intersect with. 16291 * @return {Box3} A reference to this bounding box. 16292 */ 16293 intersect( box ) { 16294 16295 this.min.max( box.min ); 16296 this.max.min( box.max ); 16297 16298 // 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. 16299 if ( this.isEmpty() ) this.makeEmpty(); 16300 16301 return this; 16302 16303 } 16304 16305 /** 16306 * Computes the union of this box and another and the given one, setting the upper 16307 * bound of this box to the greater of the two boxes' upper bounds and the 16308 * lower bound of this box to the lesser of the two boxes' lower bounds. 16309 * 16310 * @param {Box3} box - The bounding box that will be unioned with this instance. 16311 * @return {Box3} A reference to this bounding box. 16312 */ 16313 union( box ) { 16314 16315 this.min.min( box.min ); 16316 this.max.max( box.max ); 16317 16318 return this; 16319 16320 } 16321 16322 /** 16323 * Transforms this bounding box by the given 4x4 transformation matrix. 16324 * 16325 * @param {Matrix4} matrix - The transformation matrix. 16326 * @return {Box3} A reference to this bounding box. 16327 */ 16328 applyMatrix4( matrix ) { 16329 16330 // transform of empty box is an empty box. 16331 if ( this.isEmpty() ) return this; 16332 16333 // NOTE: I am using a binary pattern to specify all 2^3 combinations below 16334 _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 16335 _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 16336 _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 16337 _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 16338 _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 16339 _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 16340 _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 16341 _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 16342 16343 this.setFromPoints( _points ); 16344 16345 return this; 16346 16347 } 16348 16349 /** 16350 * Adds the given offset to both the upper and lower bounds of this bounding box, 16351 * effectively moving it in 3D space. 16352 * 16353 * @param {Vector3} offset - The offset that should be used to translate the bounding box. 16354 * @return {Box3} A reference to this bounding box. 16355 */ 16356 translate( offset ) { 16357 16358 this.min.add( offset ); 16359 this.max.add( offset ); 16360 16361 return this; 16362 16363 } 16364 16365 /** 16366 * Returns `true` if this bounding box is equal with the given one. 16367 * 16368 * @param {Box3} box - The box to test for equality. 16369 * @return {boolean} Whether this bounding box is equal with the given one. 16370 */ 16371 equals( box ) { 16372 16373 return box.min.equals( this.min ) && box.max.equals( this.max ); 16374 16375 } 16376 16377 /** 16378 * Returns a serialized structure of the bounding box. 16379 * 16380 * @return {Object} Serialized structure with fields representing the object state. 16381 */ 16382 toJSON() { 16383 16384 return { 16385 min: this.min.toArray(), 16386 max: this.max.toArray() 16387 }; 16388 16389 } 16390 16391 /** 16392 * Returns a serialized structure of the bounding box. 16393 * 16394 * @param {Object} json - The serialized json to set the box from. 16395 * @return {Box3} A reference to this bounding box. 16396 */ 16397 fromJSON( json ) { 16398 16399 this.min.fromArray( json.min ); 16400 this.max.fromArray( json.max ); 16401 return this; 16402 16403 } 16404 16405} 16406 16407const _points = [ 16408 /*@__PURE__*/ new Vector3(), 16409 /*@__PURE__*/ new Vector3(), 16410 /*@__PURE__*/ new Vector3(), 16411 /*@__PURE__*/ new Vector3(), 16412 /*@__PURE__*/ new Vector3(), 16413 /*@__PURE__*/ new Vector3(), 16414 /*@__PURE__*/ new Vector3(), 16415 /*@__PURE__*/ new Vector3() 16416]; 16417 16418const _vector$b = /*@__PURE__*/ new Vector3(); 16419 16420const _box$4 = /*@__PURE__*/ new Box3(); 16421 16422// triangle centered vertices 16423 16424const _v0$1 = /*@__PURE__*/ new Vector3(); 16425const _v1$4 = /*@__PURE__*/ new Vector3(); 16426const _v2$3 = /*@__PURE__*/ new Vector3(); 16427 16428// triangle edge vectors 16429 16430const _f0 = /*@__PURE__*/ new Vector3(); 16431const _f1 = /*@__PURE__*/ new Vector3(); 16432const _f2 = /*@__PURE__*/ new Vector3(); 16433 16434const _center = /*@__PURE__*/ new Vector3(); 16435const _extents = /*@__PURE__*/ new Vector3(); 16436const _triangleNormal = /*@__PURE__*/ new Vector3(); 16437const _testAxis = /*@__PURE__*/ new Vector3(); 16438 16439function satForAxes( axes, v0, v1, v2, extents ) { 16440 16441 for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) { 16442 16443 _testAxis.fromArray( axes, i ); 16444 // project the aabb onto the separating axis 16445 const r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z ); 16446 // project all 3 vertices of the triangle onto the separating axis 16447 const p0 = v0.dot( _testAxis ); 16448 const p1 = v1.dot( _testAxis ); 16449 const p2 = v2.dot( _testAxis ); 16450 // actual test, basically see if either of the most extreme of the triangle points intersects r 16451 if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) { 16452 16453 // points of the projected triangle are outside the projected half-length of the aabb 16454 // the axis is separating and we can exit 16455 return false; 16456 16457 } 16458 16459 } 16460 16461 return true; 16462 16463} 16464 16465// Fast Half Float Conversions, http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf 16466 16467const _tables = /*@__PURE__*/ _generateTables(); 16468 16469function _generateTables() { 16470 16471 // float32 to float16 helpers 16472 16473 const buffer = new ArrayBuffer( 4 ); 16474 const floatView = new Float32Array( buffer ); 16475 const uint32View = new Uint32Array( buffer ); 16476 16477 const baseTable = new Uint32Array( 512 ); 16478 const shiftTable = new Uint32Array( 512 ); 16479 16480 for ( let i = 0; i < 256; ++ i ) { 16481 16482 const e = i - 127; 16483 16484 // very small number (0, -0) 16485 16486 if ( e < -27 ) { 16487 16488 baseTable[ i ] = 0x0000; 16489 baseTable[ i | 0x100 ] = 0x8000; 16490 shiftTable[ i ] = 24; 16491 shiftTable[ i | 0x100 ] = 24; 16492 16493 // small number (denorm) 16494 16495 } else if ( e < -14 ) { 16496 16497 baseTable[ i ] = 0x0400 >> ( - e - 14 ); 16498 baseTable[ i | 0x100 ] = ( 0x0400 >> ( - e - 14 ) ) | 0x8000; 16499 shiftTable[ i ] = - e - 1; 16500 shiftTable[ i | 0x100 ] = - e - 1; 16501 16502 // normal number 16503 16504 } else if ( e <= 15 ) { 16505 16506 baseTable[ i ] = ( e + 15 ) << 10; 16507 baseTable[ i | 0x100 ] = ( ( e + 15 ) << 10 ) | 0x8000; 16508 shiftTable[ i ] = 13; 16509 shiftTable[ i | 0x100 ] = 13; 16510 16511 // large number (Infinity, -Infinity) 16512 16513 } else if ( e < 128 ) { 16514 16515 baseTable[ i ] = 0x7c00; 16516 baseTable[ i | 0x100 ] = 0xfc00; 16517 shiftTable[ i ] = 24; 16518 shiftTable[ i | 0x100 ] = 24; 16519 16520 // stay (NaN, Infinity, -Infinity) 16521 16522 } else { 16523 16524 baseTable[ i ] = 0x7c00; 16525 baseTable[ i | 0x100 ] = 0xfc00; 16526 shiftTable[ i ] = 13; 16527 shiftTable[ i | 0x100 ] = 13; 16528 16529 } 16530 16531 } 16532 16533 // float16 to float32 helpers 16534 16535 const mantissaTable = new Uint32Array( 2048 ); 16536 const exponentTable = new Uint32Array( 64 ); 16537 const offsetTable = new Uint32Array( 64 ); 16538 16539 for ( let i = 1; i < 1024; ++ i ) { 16540 16541 let m = i << 13; // zero pad mantissa bits 16542 let e = 0; // zero exponent 16543 16544 // normalized 16545 while ( ( m & 0x00800000 ) === 0 ) { 16546 16547 m <<= 1; 16548 e -= 0x00800000; // decrement exponent 16549 16550 } 16551 16552 m &= -8388609; // clear leading 1 bit 16553 e += 0x38800000; // adjust bias 16554 16555 mantissaTable[ i ] = m | e; 16556 16557 } 16558 16559 for ( let i = 1024; i < 2048; ++ i ) { 16560 16561 mantissaTable[ i ] = 0x38000000 + ( ( i - 1024 ) << 13 ); 16562 16563 } 16564 16565 for ( let i = 1; i < 31; ++ i ) { 16566 16567 exponentTable[ i ] = i << 23; 16568 16569 } 16570 16571 exponentTable[ 31 ] = 0x47800000; 16572 exponentTable[ 32 ] = 0x80000000; 16573 16574 for ( let i = 33; i < 63; ++ i ) { 16575 16576 exponentTable[ i ] = 0x80000000 + ( ( i - 32 ) << 23 ); 16577 16578 } 16579 16580 exponentTable[ 63 ] = 0xc7800000; 16581 16582 for ( let i = 1; i < 64; ++ i ) { 16583 16584 if ( i !== 32 ) { 16585 16586 offsetTable[ i ] = 1024; 16587 16588 } 16589 16590 } 16591 16592 return { 16593 floatView: floatView, 16594 uint32View: uint32View, 16595 baseTable: baseTable, 16596 shiftTable: shiftTable, 16597 mantissaTable: mantissaTable, 16598 exponentTable: exponentTable, 16599 offsetTable: offsetTable 16600 }; 16601 16602} 16603 16604/** 16605 * Returns a half precision floating point value (FP16) from the given single 16606 * precision floating point value (FP32). 16607 * 16608 * @param {number} val - A single precision floating point value. 16609 * @return {number} The FP16 value. 16610 */ 16611function toHalfFloat( val ) { 16612 16613 if ( Math.abs( val ) > 65504 ) warn( 'DataUtils.toHalfFloat(): Value out of range.' ); 16614 16615 val = clamp( val, -65504, 65504 ); 16616 16617 _tables.floatView[ 0 ] = val; 16618 const f = _tables.uint32View[ 0 ]; 16619 const e = ( f >> 23 ) & 0x1ff; 16620 return _tables.baseTable[ e ] + ( ( f & 0x007fffff ) >> _tables.shiftTable[ e ] ); 16621 16622} 16623 16624/** 16625 * Returns a single precision floating point value (FP32) from the given half 16626 * precision floating point value (FP16). 16627 * 16628 * @param {number} val - A half precision floating point value. 16629 * @return {number} The FP32 value. 16630 */ 16631function fromHalfFloat( val ) { 16632 16633 const m = val >> 10; 16634 _tables.uint32View[ 0 ] = _tables.mantissaTable[ _tables.offsetTable[ m ] + ( val & 0x3ff ) ] + _tables.exponentTable[ m ]; 16635 return _tables.floatView[ 0 ]; 16636 16637} 16638 16639/** 16640 * A class containing utility functions for data. 16641 * 16642 * @hideconstructor 16643 */ 16644class DataUtils { 16645 16646 /** 16647 * Returns a half precision floating point value (FP16) from the given single 16648 * precision floating point value (FP32). 16649 * 16650 * @param {number} val - A single precision floating point value. 16651 * @return {number} The FP16 value. 16652 */ 16653 static toHalfFloat( val ) { 16654 16655 return toHalfFloat( val ); 16656 16657 } 16658 16659 /** 16660 * Returns a single precision floating point value (FP32) from the given half 16661 * precision floating point value (FP16). 16662 * 16663 * @param {number} val - A half precision floating point value. 16664 * @return {number} The FP32 value. 16665 */ 16666 static fromHalfFloat( val ) { 16667 16668 return fromHalfFloat( val ); 16669 16670 } 16671 16672} 16673 16674const _vector$a = /*@__PURE__*/ new Vector3(); 16675const _vector2$1 = /*@__PURE__*/ new Vector2(); 16676 16677let _id$2 = 0; 16678 16679/** 16680 * This class stores data for an attribute (such as vertex positions, face 16681 * indices, normals, colors, UVs, and any custom attributes ) associated with 16682 * a geometry, which allows for more efficient passing of data to the GPU. 16683 * 16684 * When working with vector-like data, the `fromBufferAttribute( attribute, index )` 16685 * helper methods on vector and color class might be helpful. E.g. {@link Vector3#fromBufferAttribute}. 16686 */ 16687class BufferAttribute extends EventDispatcher { 16688 16689 /** 16690 * Constructs a new buffer attribute. 16691 * 16692 * @param {TypedArray} array - The array holding the attribute data. 16693 * @param {number} itemSize - The item size. 16694 * @param {boolean} [normalized=false] - Whether the data are normalized or not. 16695 */ 16696 constructor( array, itemSize, normalized = false ) { 16697 16698 super(); 16699 16700 if ( Array.isArray( array ) ) { 16701 16702 throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' ); 16703 16704 } 16705 16706 /** 16707 * This flag can be used for type testing. 16708 * 16709 * @type {boolean} 16710 * @readonly 16711 * @default true 16712 */ 16713 this.isBufferAttribute = true; 16714 16715 /** 16716 * The ID of the buffer attribute. 16717 * 16718 * @name BufferAttribute#id 16719 * @type {number} 16720 * @readonly 16721 */ 16722 Object.defineProperty( this, 'id', { value: _id$2 ++ } ); 16723 16724 /** 16725 * The name of the buffer attribute. 16726 * 16727 * @type {string} 16728 */ 16729 this.name = ''; 16730 16731 /** 16732 * The array holding the attribute data. It should have `itemSize * numVertices` 16733 * elements, where `numVertices` is the number of vertices in the associated geometry. 16734 * 16735 * @type {TypedArray} 16736 */ 16737 this.array = array; 16738 16739 /** 16740 * The number of values of the array that should be associated with a particular vertex. 16741 * For instance, if this attribute is storing a 3-component vector (such as a position, 16742 * normal, or color), then the value should be `3`. 16743 * 16744 * @type {number} 16745 */ 16746 this.itemSize = itemSize; 16747 16748 /** 16749 * Represents the number of items this buffer attribute stores. It is internally computed 16750 * by dividing the `array` length by the `itemSize`. 16751 * 16752 * @type {number} 16753 * @readonly 16754 */ 16755 this.count = array !== undefined ? array.length / itemSize : 0; 16756 16757 /** 16758 * Applies to integer data only. Indicates how the underlying data in the buffer maps to 16759 * the values in the GLSL code. For instance, if `array` is an instance of `UInt16Array`, 16760 * and `normalized` is `true`, the values `0 - +65535` in the array data will be mapped to 16761 * `0.0f - +1.0f` in the GLSL attribute. If `normalized` is `false`, the values will be converted 16762 * to floats unmodified, i.e. `65535` becomes `65535.0f`. 16763 * 16764 * @type {boolean} 16765 */ 16766 this.normalized = normalized; 16767 16768 /** 16769 * Defines the intended usage pattern of the data store for optimization purposes. 16770 * 16771 * Note: After the initial use of a buffer, its usage cannot be changed. Instead, 16772 * instantiate a new one and set the desired usage before the next render. 16773 * 16774 * @type {(StaticDrawUsage|DynamicDrawUsage|StreamDrawUsage|StaticReadUsage|DynamicReadUsage|StreamReadUsage|StaticCopyUsage|DynamicCopyUsage|StreamCopyUsage)} 16775 * @default StaticDrawUsage 16776 */ 16777 this.usage = StaticDrawUsage; 16778 16779 /** 16780 * This can be used to only update some components of stored vectors (for example, just the 16781 * component related to color). Use the `addUpdateRange()` function to add ranges to this array. 16782 * 16783 * @type {Array<Object>} 16784 */ 16785 this.updateRanges = []; 16786 16787 /** 16788 * Configures the bound GPU type for use in shaders. 16789 * 16790 * Note: this only has an effect for integer arrays and is not configurable for float arrays. 16791 * For lower precision float types, use `Float16BufferAttribute`. 16792 * 16793 * @type {(FloatType|IntType)} 16794 * @default FloatType 16795 */ 16796 this.gpuType = FloatType; 16797 16798 /** 16799 * A version number, incremented every time the `needsUpdate` is set to `true`. 16800 * 16801 * @type {number} 16802 */ 16803 this.version = 0; 16804 16805 } 16806 16807 /** 16808 * A callback function that is executed after the renderer has transferred the attribute 16809 * array data to the GPU. 16810 */ 16811 onUploadCallback() {} 16812 16813 /** 16814 * Flag to indicate that this attribute has changed and should be re-sent to 16815 * the GPU. Set this to `true` when you modify the value of the array. 16816 * 16817 * @type {number} 16818 * @default false 16819 * @param {boolean} value 16820 */ 16821 set needsUpdate( value ) { 16822 16823 if ( value === true ) this.version ++; 16824 16825 } 16826 16827 /** 16828 * Sets the usage of this buffer attribute. 16829 * 16830 * @param {(StaticDrawUsage|DynamicDrawUsage|StreamDrawUsage|StaticReadUsage|DynamicReadUsage|StreamReadUsage|StaticCopyUsage|DynamicCopyUsage|StreamCopyUsage)} value - The usage to set. 16831 * @return {BufferAttribute} A reference to this buffer attribute. 16832 */ 16833 setUsage( value ) { 16834 16835 this.usage = value; 16836 16837 return this; 16838 16839 } 16840 16841 /** 16842 * Adds a range of data in the data array to be updated on the GPU. 16843 * 16844 * @param {number} start - Position at which to start update. 16845 * @param {number} count - The number of components to update. 16846 */ 16847 addUpdateRange( start, count ) { 16848 16849 this.updateRanges.push( { start, count } ); 16850 16851 } 16852 16853 /** 16854 * Clears the update ranges. 16855 */ 16856 clearUpdateRanges() { 16857 16858 this.updateRanges.length = 0; 16859 16860 } 16861 16862 /** 16863 * Copies the values of the given buffer attribute to this instance. 16864 * 16865 * @param {BufferAttribute} source - The buffer attribute to copy. 16866 * @return {BufferAttribute} A reference to this instance. 16867 */ 16868 copy( source ) { 16869 16870 this.name = source.name; 16871 this.array = new source.array.constructor( source.array ); 16872 this.itemSize = source.itemSize; 16873 this.count = source.count; 16874 this.normalized = source.normalized; 16875 16876 this.usage = source.usage; 16877 this.gpuType = source.gpuType; 16878 16879 return this; 16880 16881 } 16882 16883 /** 16884 * Copies a vector from the given buffer attribute to this one. The start 16885 * and destination position in the attribute buffers are represented by the 16886 * given indices. 16887 * 16888 * @param {number} index1 - The destination index into this buffer attribute. 16889 * @param {BufferAttribute} attribute - The buffer attribute to copy from. 16890 * @param {number} index2 - The source index into the given buffer attribute. 16891 * @return {BufferAttribute} A reference to this instance. 16892 */ 16893 copyAt( index1, attribute, index2 ) { 16894 16895 index1 *= this.itemSize; 16896 index2 *= attribute.itemSize; 16897 16898 for ( let i = 0, l = this.itemSize; i < l; i ++ ) { 16899 16900 this.array[ index1 + i ] = attribute.array[ index2 + i ]; 16901 16902 } 16903 16904 return this; 16905 16906 } 16907 16908 /** 16909 * Copies the given array data into this buffer attribute. 16910 * 16911 * @param {(TypedArray|Array)} array - The array to copy. 16912 * @return {BufferAttribute} A reference to this instance. 16913 */ 16914 copyArray( array ) { 16915 16916 this.array.set( array ); 16917 16918 return this; 16919 16920 } 16921 16922 /** 16923 * Applies the given 3x3 matrix to the given attribute. Works with 16924 * item size `2` and `3`. 16925 * 16926 * @param {Matrix3} m - The matrix to apply. 16927 * @return {BufferAttribute} A reference to this instance. 16928 */ 16929 applyMatrix3( m ) { 16930 16931 if ( this.itemSize === 2 ) { 16932 16933 for ( let i = 0, l = this.count; i < l; i ++ ) { 16934 16935 _vector2$1.fromBufferAttribute( this, i ); 16936 _vector2$1.applyMatrix3( m ); 16937 16938 this.setXY( i, _vector2$1.x, _vector2$1.y ); 16939 16940 } 16941 16942 } else if ( this.itemSize === 3 ) { 16943 16944 for ( let i = 0, l = this.count; i < l; i ++ ) { 16945 16946 _vector$a.fromBufferAttribute( this, i ); 16947 _vector$a.applyMatrix3( m ); 16948 16949 this.setXYZ( i, _vector$a.x, _vector$a.y, _vector$a.z ); 16950 16951 } 16952 16953 } 16954 16955 return this; 16956 16957 } 16958 16959 /** 16960 * Applies the given 4x4 matrix to the given attribute. Only works with 16961 * item size `3`. 16962 * 16963 * @param {Matrix4} m - The matrix to apply. 16964 * @return {BufferAttribute} A reference to this instance. 16965 */ 16966 applyMatrix4( m ) { 16967 16968 for ( let i = 0, l = this.count; i < l; i ++ ) { 16969 16970 _vector$a.fromBufferAttribute( this, i ); 16971 16972 _vector$a.applyMatrix4( m ); 16973 16974 this.setXYZ( i, _vector$a.x, _vector$a.y, _vector$a.z ); 16975 16976 } 16977 16978 return this; 16979 16980 } 16981 16982 /** 16983 * Applies the given 3x3 normal matrix to the given attribute. Only works with 16984 * item size `3`. 16985 * 16986 * @param {Matrix3} m - The normal matrix to apply. 16987 * @return {BufferAttribute} A reference to this instance. 16988 */ 16989 applyNormalMatrix( m ) { 16990 16991 for ( let i = 0, l = this.count; i < l; i ++ ) { 16992 16993 _vector$a.fromBufferAttribute( this, i ); 16994 16995 _vector$a.applyNormalMatrix( m ); 16996 16997 this.setXYZ( i, _vector$a.x, _vector$a.y, _vector$a.z ); 16998 16999 } 17000 17001 return this; 17002 17003 } 17004 17005 /** 17006 * Applies the given 4x4 matrix to the given attribute. Only works with 17007 * item size `3` and with direction vectors. 17008 * 17009 * @param {Matrix4} m - The matrix to apply. 17010 * @return {BufferAttribute} A reference to this instance. 17011 */ 17012 transformDirection( m ) { 17013 17014 for ( let i = 0, l = this.count; i < l; i ++ ) { 17015 17016 _vector$a.fromBufferAttribute( this, i ); 17017 17018 _vector$a.transformDirection( m ); 17019 17020 this.setXYZ( i, _vector$a.x, _vector$a.y, _vector$a.z ); 17021 17022 } 17023 17024 return this; 17025 17026 } 17027 17028 /** 17029 * Sets the given array data in the buffer attribute. 17030 * 17031 * @param {(TypedArray|Array)} value - The array data to set. 17032 * @param {number} [offset=0] - The offset in this buffer attribute's array. 17033 * @return {BufferAttribute} A reference to this instance. 17034 */ 17035 set( value, offset = 0 ) { 17036 17037 // Matching BufferAttribute constructor, do not normalize the array. 17038 this.array.set( value, offset ); 17039 17040 return this; 17041 17042 } 17043 17044 /** 17045 * Returns the given component of the vector at the given index. 17046 * 17047 * @param {number} index - The index into the buffer attribute. 17048 * @param {number} component - The component index. 17049 * @return {number} The returned value. 17050 */ 17051 getComponent( index, component ) { 17052 17053 let value = this.array[ index * this.itemSize + component ]; 17054 17055 if ( this.normalized ) value = denormalize( value, this.array ); 17056 17057 return value; 17058 17059 } 17060 17061 /** 17062 * Sets the given value to the given component of the vector at the given index. 17063 * 17064 * @param {number} index - The index into the buffer attribute. 17065 * @param {number} component - The component index. 17066 * @param {number} value - The value to set. 17067 * @return {BufferAttribute} A reference to this instance. 17068 */ 17069 setComponent( index, component, value ) { 17070 17071 if ( this.normalized ) value = normalize( value, this.array ); 17072 17073 this.array[ index * this.itemSize + component ] = value; 17074 17075 return this; 17076 17077 } 17078 17079 /** 17080 * Returns the x component of the vector at the given index. 17081 * 17082 * @param {number} index - The index into the buffer attribute. 17083 * @return {number} The x component. 17084 */ 17085 getX( index ) { 17086 17087 let x = this.array[ index * this.itemSize ]; 17088 17089 if ( this.normalized ) x = denormalize( x, this.array ); 17090 17091 return x; 17092 17093 } 17094 17095 /** 17096 * Sets the x component of the vector at the given index. 17097 * 17098 * @param {number} index - The index into the buffer attribute. 17099 * @param {number} x - The value to set. 17100 * @return {BufferAttribute} A reference to this instance. 17101 */ 17102 setX( index, x ) { 17103 17104 if ( this.normalized ) x = normalize( x, this.array ); 17105 17106 this.array[ index * this.itemSize ] = x; 17107 17108 return this; 17109 17110 } 17111 17112 /** 17113 * Returns the y component of the vector at the given index. 17114 * 17115 * @param {number} index - The index into the buffer attribute. 17116 * @return {number} The y component. 17117 */ 17118 getY( index ) { 17119 17120 let y = this.array[ index * this.itemSize + 1 ]; 17121 17122 if ( this.normalized ) y = denormalize( y, this.array ); 17123 17124 return y; 17125 17126 } 17127 17128 /** 17129 * Sets the y component of the vector at the given index. 17130 * 17131 * @param {number} index - The index into the buffer attribute. 17132 * @param {number} y - The value to set. 17133 * @return {BufferAttribute} A reference to this instance. 17134 */ 17135 setY( index, y ) { 17136 17137 if ( this.normalized ) y = normalize( y, this.array ); 17138 17139 this.array[ index * this.itemSize + 1 ] = y; 17140 17141 return this; 17142 17143 } 17144 17145 /** 17146 * Returns the z component of the vector at the given index. 17147 * 17148 * @param {number} index - The index into the buffer attribute. 17149 * @return {number} The z component. 17150 */ 17151 getZ( index ) { 17152 17153 let z = this.array[ index * this.itemSize + 2 ]; 17154 17155 if ( this.normalized ) z = denormalize( z, this.array ); 17156 17157 return z; 17158 17159 } 17160 17161 /** 17162 * Sets the z component of the vector at the given index. 17163 * 17164 * @param {number} index - The index into the buffer attribute. 17165 * @param {number} z - The value to set. 17166 * @return {BufferAttribute} A reference to this instance. 17167 */ 17168 setZ( index, z ) { 17169 17170 if ( this.normalized ) z = normalize( z, this.array ); 17171 17172 this.array[ index * this.itemSize + 2 ] = z; 17173 17174 return this; 17175 17176 } 17177 17178 /** 17179 * Returns the w component of the vector at the given index. 17180 * 17181 * @param {number} index - The index into the buffer attribute. 17182 * @return {number} The w component. 17183 */ 17184 getW( index ) { 17185 17186 let w = this.array[ index * this.itemSize + 3 ]; 17187 17188 if ( this.normalized ) w = denormalize( w, this.array ); 17189 17190 return w; 17191 17192 } 17193 17194 /** 17195 * Sets the w component of the vector at the given index. 17196 * 17197 * @param {number} index - The index into the buffer attribute. 17198 * @param {number} w - The value to set. 17199 * @return {BufferAttribute} A reference to this instance. 17200 */ 17201 setW( index, w ) { 17202 17203 if ( this.normalized ) w = normalize( w, this.array ); 17204 17205 this.array[ index * this.itemSize + 3 ] = w; 17206 17207 return this; 17208 17209 } 17210 17211 /** 17212 * Sets the x and y component of the vector at the given index. 17213 * 17214 * @param {number} index - The index into the buffer attribute. 17215 * @param {number} x - The value for the x component to set. 17216 * @param {number} y - The value for the y component to set. 17217 * @return {BufferAttribute} A reference to this instance. 17218 */ 17219 setXY( index, x, y ) { 17220 17221 index *= this.itemSize; 17222 17223 if ( this.normalized ) { 17224 17225 x = normalize( x, this.array ); 17226 y = normalize( y, this.array ); 17227 17228 } 17229 17230 this.array[ index + 0 ] = x; 17231 this.array[ index + 1 ] = y; 17232 17233 return this; 17234 17235 } 17236 17237 /** 17238 * Sets the x, y and z component of the vector at the given index. 17239 * 17240 * @param {number} index - The index into the buffer attribute. 17241 * @param {number} x - The value for the x component to set. 17242 * @param {number} y - The value for the y component to set. 17243 * @param {number} z - The value for the z component to set. 17244 * @return {BufferAttribute} A reference to this instance. 17245 */ 17246 setXYZ( index, x, y, z ) { 17247 17248 index *= this.itemSize; 17249 17250 if ( this.normalized ) { 17251 17252 x = normalize( x, this.array ); 17253 y = normalize( y, this.array ); 17254 z = normalize( z, this.array ); 17255 17256 } 17257 17258 this.array[ index + 0 ] = x; 17259 this.array[ index + 1 ] = y; 17260 this.array[ index + 2 ] = z; 17261 17262 return this; 17263 17264 } 17265 17266 /** 17267 * Sets the x, y, z and w component of the vector at the given index. 17268 * 17269 * @param {number} index - The index into the buffer attribute. 17270 * @param {number} x - The value for the x component to set. 17271 * @param {number} y - The value for the y component to set. 17272 * @param {number} z - The value for the z component to set. 17273 * @param {number} w - The value for the w component to set. 17274 * @return {BufferAttribute} A reference to this instance. 17275 */ 17276 setXYZW( index, x, y, z, w ) { 17277 17278 index *= this.itemSize; 17279 17280 if ( this.normalized ) { 17281 17282 x = normalize( x, this.array ); 17283 y = normalize( y, this.array ); 17284 z = normalize( z, this.array ); 17285 w = normalize( w, this.array ); 17286 17287 } 17288 17289 this.array[ index + 0 ] = x; 17290 this.array[ index + 1 ] = y; 17291 this.array[ index + 2 ] = z; 17292 this.array[ index + 3 ] = w; 17293 17294 return this; 17295 17296 } 17297 17298 /** 17299 * Sets the given callback function that is executed after the Renderer has transferred 17300 * the attribute array data to the GPU. Can be used to perform clean-up operations after 17301 * the upload when attribute data are not needed anymore on the CPU side. 17302 * 17303 * @param {Function} callback - The `onUpload()` callback. 17304 * @return {BufferAttribute} A reference to this instance. 17305 */ 17306 onUpload( callback ) { 17307 17308 this.onUploadCallback = callback; 17309 17310 return this; 17311 17312 } 17313 17314 /** 17315 * Returns a new buffer attribute with copied values from this instance. 17316 * 17317 * @return {BufferAttribute} A clone of this instance. 17318 */ 17319 clone() { 17320 17321 return new this.constructor( this.array, this.itemSize ).copy( this ); 17322 17323 } 17324 17325 /** 17326 * Serializes the buffer attribute into JSON. 17327 * 17328 * @return {Object} A JSON object representing the serialized buffer attribute. 17329 */ 17330 toJSON() { 17331 17332 const data = { 17333 itemSize: this.itemSize, 17334 type: this.array.constructor.name, 17335 array: Array.from( this.array ), 17336 normalized: this.normalized 17337 }; 17338 17339
17339if ( this.name !== '' ) data.name = this.name; 17340 if ( this.usage !== StaticDrawUsage ) data.usage = this.usag
vendor: 19,224 bytes, lines 17340-18215
17340e; 17341 17342 return data; 17343 17344 } 17345 17346 /** 17347 * Disposes of the buffer attribute. Available only in {@link WebGPURenderer}. 17348 */ 17349 dispose() { 17350 17351 this.dispatchEvent( { type: 'dispose' } ); 17352 17353 } 17354 17355} 17356 17357/** 17358 * Convenient class that can be used when creating a `Int8` buffer attribute with 17359 * a plain `Array` instance. 17360 * 17361 * @augments BufferAttribute 17362 */ 17363class Int8BufferAttribute extends BufferAttribute { 17364 17365 /** 17366 * Constructs a new buffer attribute. 17367 * 17368 * @param {(Array<number>|Int8Array)} array - The array holding the attribute data. 17369 * @param {number} itemSize - The item size. 17370 * @param {boolean} [normalized=false] - Whether the data are normalized or not. 17371 */ 17372 constructor( array, itemSize, normalized ) { 17373 17374 super( new Int8Array( array ), itemSize, normalized ); 17375 17376 } 17377 17378} 17379 17380/** 17381 * Convenient class that can be used when creating a `UInt8` buffer attribute with 17382 * a plain `Array` instance. 17383 * 17384 * @augments BufferAttribute 17385 */ 17386class Uint8BufferAttribute extends BufferAttribute { 17387 17388 /** 17389 * Constructs a new buffer attribute. 17390 * 17391 * @param {(Array<number>|Uint8Array)} array - The array holding the attribute data. 17392 * @param {number} itemSize - The item size. 17393 * @param {boolean} [normalized=false] - Whether the data are normalized or not. 17394 */ 17395 constructor( array, itemSize, normalized ) { 17396 17397 super( new Uint8Array( array ), itemSize, normalized ); 17398 17399 } 17400 17401} 17402 17403/** 17404 * Convenient class that can be used when creating a `UInt8Clamped` buffer attribute with 17405 * a plain `Array` instance. 17406 * 17407 * @augments BufferAttribute 17408 */ 17409class Uint8ClampedBufferAttribute extends BufferAttribute { 17410 17411 /** 17412 * Constructs a new buffer attribute. 17413 * 17414 * @param {(Array<number>|Uint8ClampedArray)} array - The array holding the attribute data. 17415 * @param {number} itemSize - The item size. 17416 * @param {boolean} [normalized=false] - Whether the data are normalized or not. 17417 */ 17418 constructor( array, itemSize, normalized ) { 17419 17420 super( new Uint8ClampedArray( array ), itemSize, normalized ); 17421 17422 } 17423 17424} 17425 17426/** 17427 * Convenient class that can be used when creating a `Int16` buffer attribute with 17428 * a plain `Array` instance. 17429 * 17430 * @augments BufferAttribute 17431 */ 17432class Int16BufferAttribute extends BufferAttribute { 17433 17434 /** 17435 * Constructs a new buffer attribute. 17436 * 17437 * @param {(Array<number>|Int16Array)} array - The array holding the attribute data. 17438 * @param {number} itemSize - The item size. 17439 * @param {boolean} [normalized=false] - Whether the data are normalized or not. 17440 */ 17441 constructor( array, itemSize, normalized ) { 17442 17443 super( new Int16Array( array ), itemSize, normalized ); 17444 17445 } 17446 17447} 17448 17449/** 17450 * Convenient class that can be used when creating a `UInt16` buffer attribute with 17451 * a plain `Array` instance. 17452 * 17453 * @augments BufferAttribute 17454 */ 17455class Uint16BufferAttribute extends BufferAttribute { 17456 17457 /** 17458 * Constructs a new buffer attribute. 17459 * 17460 * @param {(Array<number>|Uint16Array)} array - The array holding the attribute data. 17461 * @param {number} itemSize - The item size. 17462 * @param {boolean} [normalized=false] - Whether the data are normalized or not. 17463 */ 17464 constructor( array, itemSize, normalized ) { 17465 17466 super( new Uint16Array( array ), itemSize, normalized ); 17467 17468 } 17469 17470} 17471 17472/** 17473 * Convenient class that can be used when creating a `Int32` buffer attribute with 17474 * a plain `Array` instance. 17475 * 17476 * @augments BufferAttribute 17477 */ 17478class Int32BufferAttribute extends BufferAttribute { 17479 17480 /** 17481 * Constructs a new buffer attribute. 17482 * 17483 * @param {(Array<number>|Int32Array)} array - The array holding the attribute data. 17484 * @param {number} itemSize - The item size. 17485 * @param {boolean} [normalized=false] - Whether the data are normalized or not. 17486 */ 17487 constructor( array, itemSize, normalized ) { 17488 17489 super( new Int32Array( array ), itemSize, normalized ); 17490 17491 } 17492 17493} 17494 17495/** 17496 * Convenient class that can be used when creating a `UInt32` buffer attribute with 17497 * a plain `Array` instance. 17498 * 17499 * @augments BufferAttribute 17500 */ 17501class Uint32BufferAttribute extends BufferAttribute { 17502 17503 /** 17504 * Constructs a new buffer attribute. 17505 * 17506 * @param {(Array<number>|Uint32Array)} array - The array holding the attribute data. 17507 * @param {number} itemSize - The item size. 17508 * @param {boolean} [normalized=false] - Whether the data are normalized or not. 17509 */ 17510 constructor( array, itemSize, normalized ) { 17511 17512 super( new Uint32Array( array ), itemSize, normalized ); 17513 17514 } 17515 17516} 17517 17518/** 17519 * Convenient class that can be used when creating a `Float16` buffer attribute with 17520 * a plain `Array` instance. 17521 * 17522 * This class automatically converts to and from FP16 via `Uint16Array` since `Float16Array` 17523 * browser support is still problematic. 17524 * 17525 * @augments BufferAttribute 17526 */ 17527class Float16BufferAttribute extends BufferAttribute { 17528 17529 /** 17530 * Constructs a new buffer attribute. 17531 * 17532 * @param {(Array<number>|Uint16Array)} array - The array holding the attribute data. 17533 * @param {number} itemSize - The item size. 17534 * @param {boolean} [normalized=false] - Whether the data are normalized or not. 17535 */ 17536 constructor( array, itemSize, normalized ) { 17537 17538 super( new Uint16Array( array ), itemSize, normalized ); 17539 17540 this.isFloat16BufferAttribute = true; 17541 17542 } 17543 17544 getX( index ) { 17545 17546 let x = fromHalfFloat( this.array[ index * this.itemSize ] ); 17547 17548 if ( this.normalized ) x = denormalize( x, this.array ); 17549 17550 return x; 17551 17552 } 17553 17554 setX( index, x ) { 17555 17556 if ( this.normalized ) x = normalize( x, this.array ); 17557 17558 this.array[ index * this.itemSize ] = toHalfFloat( x ); 17559 17560 return this; 17561 17562 } 17563 17564 getY( index ) { 17565 17566 let y = fromHalfFloat( this.array[ index * this.itemSize + 1 ] ); 17567 17568 if ( this.normalized ) y = denormalize( y, this.array ); 17569 17570 return y; 17571 17572 } 17573 17574 setY( index, y ) { 17575 17576 if ( this.normalized ) y = normalize( y, this.array ); 17577 17578 this.array[ index * this.itemSize + 1 ] = toHalfFloat( y ); 17579 17580 return this; 17581 17582 } 17583 17584 getZ( index ) { 17585 17586 let z = fromHalfFloat( this.array[ index * this.itemSize + 2 ] ); 17587 17588 if ( this.normalized ) z = denormalize( z, this.array ); 17589 17590 return z; 17591 17592 } 17593 17594 setZ( index, z ) { 17595 17596 if ( this.normalized ) z = normalize( z, this.array ); 17597 17598 this.array[ index * this.itemSize + 2 ] = toHalfFloat( z ); 17599 17600 return this; 17601 17602 } 17603 17604 getW( index ) { 17605 17606 let w = fromHalfFloat( this.array[ index * this.itemSize + 3 ] ); 17607 17608 if ( this.normalized ) w = denormalize( w, this.array ); 17609 17610 return w; 17611 17612 } 17613 17614 setW( index, w ) { 17615 17616 if ( this.normalized ) w = normalize( w, this.array ); 17617 17618 this.array[ index * this.itemSize + 3 ] = toHalfFloat( w ); 17619 17620 return this; 17621 17622 } 17623 17624 setXY( index, x, y ) { 17625 17626 index *= this.itemSize; 17627 17628 if ( this.normalized ) { 17629 17630 x = normalize( x, this.array ); 17631 y = normalize( y, this.array ); 17632 17633 } 17634 17635 this.array[ index + 0 ] = toHalfFloat( x ); 17636 this.array[ index + 1 ] = toHalfFloat( y ); 17637 17638 return this; 17639 17640 } 17641 17642 setXYZ( index, x, y, z ) { 17643 17644 index *= this.itemSize; 17645 17646 if ( this.normalized ) { 17647 17648 x = normalize( x, this.array ); 17649 y = normalize( y, this.array ); 17650 z = normalize( z, this.array ); 17651 17652 } 17653 17654 this.array[ index + 0 ] = toHalfFloat( x ); 17655 this.array[ index + 1 ] = toHalfFloat( y ); 17656 this.array[ index + 2 ] = toHalfFloat( z ); 17657 17658 return this; 17659 17660 } 17661 17662 setXYZW( index, x, y, z, w ) { 17663 17664 index *= this.itemSize; 17665 17666 if ( this.normalized ) { 17667 17668 x = normalize( x, this.array ); 17669 y = normalize( y, this.array ); 17670 z = normalize( z, this.array ); 17671 w = normalize( w, this.array ); 17672 17673 } 17674 17675 this.array[ index + 0 ] = toHalfFloat( x ); 17676 this.array[ index + 1 ] = toHalfFloat( y ); 17677 this.array[ index + 2 ] = toHalfFloat( z ); 17678 this.array[ index + 3 ] = toHalfFloat( w ); 17679 17680 return this; 17681 17682 } 17683 17684} 17685 17686/** 17687 * Convenient class that can be used when creating a `Float32` buffer attribute with 17688 * a plain `Array` instance. 17689 * 17690 * @augments BufferAttribute 17691 */ 17692class Float32BufferAttribute extends BufferAttribute { 17693 17694 /** 17695 * Constructs a new buffer attribute. 17696 * 17697 * @param {(Array<number>|Float32Array)} array - The array holding the attribute data. 17698 * @param {number} itemSize - The item size. 17699 * @param {boolean} [normalized=false] - Whether the data are normalized or not. 17700 */ 17701 constructor( array, itemSize, normalized ) { 17702 17703 super( new Float32Array( array ), itemSize, normalized ); 17704 17705 } 17706 17707} 17708 17709const _box$3 = /*@__PURE__*/ new Box3(); 17710const _v1$3 = /*@__PURE__*/ new Vector3(); 17711const _v2$2 = /*@__PURE__*/ new Vector3(); 17712 17713/** 17714 * An analytical 3D sphere defined by a center and radius. This class is mainly 17715 * used as a Bounding Sphere for 3D objects. 17716 */ 17717class Sphere { 17718 17719 /** 17720 * Constructs a new sphere. 17721 * 17722 * @param {Vector3} [center=(0,0,0)] - The center of the sphere 17723 * @param {number} [radius=-1] - The radius of the sphere. 17724 */ 17725 constructor( center = new Vector3(), radius = -1 ) { 17726 17727 /** 17728 * This flag can be used for type testing. 17729 * 17730 * @type {boolean} 17731 * @readonly 17732 * @default true 17733 */ 17734 this.isSphere = true; 17735 17736 /** 17737 * The center of the sphere 17738 * 17739 * @type {Vector3} 17740 */ 17741 this.center = center; 17742 17743 /** 17744 * The radius of the sphere. 17745 * 17746 * @type {number} 17747 */ 17748 this.radius = radius; 17749 17750 } 17751 17752 /** 17753 * Sets the sphere's components by copying the given values. 17754 * 17755 * @param {Vector3} center - The center. 17756 * @param {number} radius - The radius. 17757 * @return {Sphere} A reference to this sphere. 17758 */ 17759 set( center, radius ) { 17760 17761 this.center.copy( center ); 17762 this.radius = radius; 17763 17764 return this; 17765 17766 } 17767 17768 /** 17769 * Computes the minimum bounding sphere for list of points. 17770 * If the optional center point is given, it is used as the sphere's 17771 * center. Otherwise, the center of the axis-aligned bounding box 17772 * encompassing the points is calculated. 17773 * 17774 * @param {Array<Vector3>} points - A list of points in 3D space. 17775 * @param {Vector3} [optionalCenter] - The center of the sphere. 17776 * @return {Sphere} A reference to this sphere. 17777 */ 17778 setFromPoints( points, optionalCenter ) { 17779 17780 const center = this.center; 17781 17782 if ( optionalCenter !== undefined ) { 17783 17784 center.copy( optionalCenter ); 17785 17786 } else { 17787 17788 _box$3.setFromPoints( points ).getCenter( center ); 17789 17790 } 17791 17792 let maxRadiusSq = 0; 17793 17794 for ( let i = 0, il = points.length; i < il; i ++ ) { 17795 17796 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); 17797 17798 } 17799 17800 this.radius = Math.sqrt( maxRadiusSq ); 17801 17802 return this; 17803 17804 } 17805 17806 /** 17807 * Copies the values of the given sphere to this instance. 17808 * 17809 * @param {Sphere} sphere - The sphere to copy. 17810 * @return {Sphere} A reference to this sphere. 17811 */ 17812 copy( sphere ) { 17813 17814 this.center.copy( sphere.center ); 17815 this.radius = sphere.radius; 17816 17817 return this; 17818 17819 } 17820 17821 /** 17822 * Returns `true` if the sphere is empty (the radius set to a negative number). 17823 * 17824 * Spheres with a radius of `0` contain only their center point and are not 17825 * considered to be empty. 17826 * 17827 * @return {boolean} Whether this sphere is empty or not. 17828 */ 17829 isEmpty() { 17830 17831 return ( this.radius < 0 ); 17832 17833 } 17834 17835 /** 17836 * Makes this sphere empty which means in encloses a zero space in 3D. 17837 * 17838 * @return {Sphere} A reference to this sphere. 17839 */ 17840 makeEmpty() { 17841 17842 this.center.set( 0, 0, 0 ); 17843 this.radius = -1; 17844 17845 return this; 17846 17847 } 17848 17849 /** 17850 * Returns `true` if this sphere contains the given point inclusive of 17851 * the surface of the sphere. 17852 * 17853 * @param {Vector3} point - The point to check. 17854 * @return {boolean} Whether this sphere contains the given point or not. 17855 */ 17856 containsPoint( point ) { 17857 17858 return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); 17859 17860 } 17861 17862 /** 17863 * Returns the closest distance from the boundary of the sphere to the 17864 * given point. If the sphere contains the point, the distance will 17865 * be negative. 17866 * 17867 * @param {Vector3} point - The point to compute the distance to. 17868 * @return {number} The distance to the point. 17869 */ 17870 distanceToPoint( point ) { 17871 17872 return ( point.distanceTo( this.center ) - this.radius ); 17873 17874 } 17875 17876 /** 17877 * Returns `true` if this sphere intersects with the given one. 17878 * 17879 * @param {Sphere} sphere - The sphere to test. 17880 * @return {boolean} Whether this sphere intersects with the given one or not. 17881 */ 17882 intersectsSphere( sphere ) { 17883 17884 const radiusSum = this.radius + sphere.radius; 17885 17886 return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); 17887 17888 } 17889 17890 /** 17891 * Returns `true` if this sphere intersects with the given box. 17892 * 17893 * @param {Box3} box - The box to test. 17894 * @return {boolean} Whether this sphere intersects with the given box or not. 17895 */ 17896 intersectsBox( box ) { 17897 17898 return box.intersectsSphere( this ); 17899 17900 } 17901 17902 /** 17903 * Returns `true` if this sphere intersects with the given plane. 17904 * 17905 * @param {Plane} plane - The plane to test. 17906 * @return {boolean} Whether this sphere intersects with the given plane or not. 17907 */ 17908 intersectsPlane( plane ) { 17909 17910 return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; 17911 17912 } 17913 17914 /** 17915 * Clamps a point within the sphere. If the point is outside the sphere, it 17916 * will clamp it to the closest point on the edge of the sphere. Points 17917 * already inside the sphere will not be affected. 17918 * 17919 * @param {Vector3} point - The plane to clamp. 17920 * @param {Vector3} target - The target vector that is used to store the method's result. 17921 * @return {Vector3} The clamped point. 17922 */ 17923 clampPoint( point, target ) { 17924 17925 const deltaLengthSq = this.center.distanceToSquared( point ); 17926 17927 target.copy( point ); 17928 17929 if ( deltaLengthSq > ( this.radius * this.radius ) ) { 17930 17931 target.sub( this.center ).normalize(); 17932 target.multiplyScalar( this.radius ).add( this.center ); 17933 17934 } 17935 17936 return target; 17937 17938 } 17939 17940 /** 17941 * Returns a bounding box that encloses this sphere. 17942 * 17943 * @param {Box3} target - The target box that is used to store the method's result. 17944 * @return {Box3} The bounding box that encloses this sphere. 17945 */ 17946 getBoundingBox( target ) { 17947 17948 if ( this.isEmpty() ) { 17949 17950 // Empty sphere produces empty bounding box 17951 target.makeEmpty(); 17952 return target; 17953 17954 } 17955 17956 target.set( this.center, this.center ); 17957 target.expandByScalar( this.radius ); 17958 17959 return target; 17960 17961 } 17962 17963 /** 17964 * Transforms this sphere with the given 4x4 transformation matrix. 17965 * 17966 * @param {Matrix4} matrix - The transformation matrix. 17967 * @return {Sphere} A reference to this sphere. 17968 */ 17969 applyMatrix4( matrix ) { 17970 17971 this.center.applyMatrix4( matrix ); 17972 this.radius = this.radius * matrix.getMaxScaleOnAxis(); 17973 17974 return this; 17975 17976 } 17977 17978 /** 17979 * Translates the sphere's center by the given offset. 17980 * 17981 * @param {Vector3} offset - The offset. 17982 * @return {Sphere} A reference to this sphere. 17983 */ 17984 translate( offset ) { 17985 17986 this.center.add( offset ); 17987 17988 return this; 17989 17990 } 17991 17992 /** 17993 * Expands the boundaries of this sphere to include the given point. 17994 * 17995 * @param {Vector3} point - The point to include. 17996 * @return {Sphere} A reference to this sphere. 17997 */ 17998 expandByPoint( point ) { 17999 18000 if ( this.isEmpty() ) { 18001 18002 this.center.copy( point ); 18003 18004 this.radius = 0; 18005 18006 return this; 18007 18008 } 18009 18010 _v1$3.subVectors( point, this.center ); 18011 18012 const lengthSq = _v1$3.lengthSq(); 18013 18014 if ( lengthSq > ( this.radius * this.radius ) ) { 18015 18016 // calculate the minimal sphere 18017 18018 const length = Math.sqrt( lengthSq ); 18019 18020 const delta = ( length - this.radius ) * 0.5; 18021 18022 this.center.addScaledVector( _v1$3, delta / length ); 18023 18024 this.radius += delta; 18025 18026 } 18027 18028 return this; 18029 18030 } 18031 18032 /** 18033 * Expands this sphere to enclose both the original sphere and the given sphere. 18034 * 18035 * @param {Sphere} sphere - The sphere to include. 18036 * @return {Sphere} A reference to this sphere. 18037 */ 18038 union( sphere ) { 18039 18040 if ( sphere.isEmpty() ) { 18041 18042 return this; 18043 18044 } 18045 18046 if ( this.isEmpty() ) { 18047 18048 this.copy( sphere ); 18049 18050 return this; 18051 18052 } 18053 18054 if ( this.center.equals( sphere.center ) === true ) { 18055 18056 this.radius = Math.max( this.radius, sphere.radius ); 18057 18058 } else { 18059 18060 _v2$2.subVectors( sphere.center, this.center ).setLength( sphere.radius ); 18061 18062 this.expandByPoint( _v1$3.copy( sphere.center ).add( _v2$2 ) ); 18063 18064 this.expandByPoint( _v1$3.copy( sphere.center ).sub( _v2$2 ) ); 18065 18066 } 18067 18068 return this; 18069 18070 } 18071 18072 /** 18073 * Returns `true` if this sphere is equal with the given one. 18074 * 18075 * @param {Sphere} sphere - The sphere to test for equality. 18076 * @return {boolean} Whether this bounding sphere is equal with the given one. 18077 */ 18078 equals( sphere ) { 18079 18080 return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); 18081 18082 } 18083 18084 /** 18085 * Returns a new sphere with copied values from this instance. 18086 * 18087 * @return {Sphere} A clone of this instance. 18088 */ 18089 clone() { 18090 18091 return new this.constructor().copy( this ); 18092 18093 } 18094 18095 /** 18096 * Returns a serialized structure of the bounding sphere. 18097 * 18098 * @return {Object} Serialized structure with fields representing the object state. 18099 */ 18100 toJSON() { 18101 18102 return { 18103 radius: this.radius, 18104 center: this.center.toArray() 18105 }; 18106 18107 } 18108 18109 /** 18110 * Returns a serialized structure of the bounding sphere. 18111 * 18112 * @param {Object} json - The serialized json to set the sphere from. 18113 * @return {Sphere} A reference to this bounding sphere. 18114 */ 18115 fromJSON( json ) { 18116 18117 this.radius = json.radius; 18118 this.center.fromArray( json.center ); 18119 return this; 18120 18121 } 18122 18123} 18124 18125let _id$1 = 0; 18126 18127const _m1 = /*@__PURE__*/ new Matrix4(); 18128const _obj = /*@__PURE__*/ new Object3D(); 18129const _offset = /*@__PURE__*/ new Vector3(); 18130const _box$2 = /*@__PURE__*/ new Box3(); 18131const _boxMorphTargets = /*@__PURE__*/ new Box3(); 18132const _vector$9 = /*@__PURE__*/ new Vector3(); 18133 18134/** 18135 * A representation of mesh, line, or point geometry. Includes vertex 18136 * positions, face indices, normals, colors, UVs, and custom attributes 18137 * within buffers, reducing the cost of passing all this data to the GPU. 18138 * 18139 * ```js 18140 * const geometry = new THREE.BufferGeometry(); 18141 * // create a simple square shape. We duplicate the top left and bottom right 18142 * // vertices because each vertex needs to appear once per triangle. 18143 * const vertices = new Float32Array( [ 18144 * -1.0, -1.0, 1.0, // v0 18145 * 1.0, -1.0, 1.0, // v1 18146 * 1.0, 1.0, 1.0, // v2 18147 * 18148 * 1.0, 1.0, 1.0, // v3 18149 * -1.0, 1.0, 1.0, // v4 18150 * -1.0, -1.0, 1.0 // v5 18151 * ] ); 18152 * // itemSize = 3 because there are 3 values (components) per vertex 18153 * geometry.setAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) ); 18154 * const material = new THREE.MeshBasicMaterial( { color: 0xff0000 } ); 18155 * const mesh = new THREE.Mesh( geometry, material ); 18156 * ``` 18157 * 18158 * @augments EventDispatcher 18159 */ 18160class BufferGeometry extends EventDispatcher { 18161 18162 /** 18163 * Constructs a new geometry. 18164 */ 18165 constructor() { 18166 18167 super(); 18168 18169 /** 18170 * This flag can be used for type testing. 18171 * 18172 * @type {boolean} 18173 * @readonly 18174 * @default true 18175 */ 18176 this.isBufferGeometry = true; 18177 18178 /** 18179 * The ID of the geometry. 18180 * 18181 * @name BufferGeometry#id 18182 * @type {number} 18183 * @readonly 18184 */ 18185 Object.defineProperty( this, 'id', { value: _id$1 ++ } ); 18186 18187 /** 18188 * The UUID of the geometry. 18189 * 18190 * @type {string} 18191 * @readonly 18192 */ 18193 this.uuid = generateUUID(); 18194 18195 /** 18196 * The name of the geometry. 18197 * 18198 * @type {string} 18199 */ 18200 this.name = ''; 18201 this.type = 'BufferGeometry'; 18202 18203 /** 18204 * Allows for vertices to be re-used across multiple triangles; this is 18205 * called using "indexed triangles". Each triangle is associated with the 18206 * indices of three vertices. This attribute therefore stores the index of 18207 * each vertex for each triangular face. If this attribute is not set, the 18208 * renderer assumes that each three contiguous positions represent a single triangle. 18209 * 18210 * @type {?BufferAttribute} 18211 * @default null 18212 */ 18213 this.index = null; 18214 18215 /**
vendor: 7,679 bytes, lines 18216-18533
18216 * A (storage) buffer attribute which was generated with a compute shader and 18217 * now defines indirect draw calls. 18218 * 18219 * Can only be used with {@link WebGPURenderer} and a WebGPU backend. 18220 * 18221 * @type {?BufferAttribute} 18222 * @default null 18223 */ 18224 this.indirect = null; 18225 18226 /** 18227 * The offset, in bytes, into the indirect drawing buffer where the value data begins. If an array is provided, multiple indirect draw calls will be made for each offset. 18228 * 18229 * Can only be used with {@link WebGPURenderer} and a WebGPU backend. 18230 * 18231 * @type {number|Array<number>} 18232 * @default 0 18233 */ 18234 this.indirectOffset = 0; 18235 18236 /** 18237 * This dictionary has as id the name of the attribute to be set and as value 18238 * the buffer attribute to set it to. Rather than accessing this property directly, 18239 * use `setAttribute()` and `getAttribute()` to access attributes of this geometry. 18240 * 18241 * @type {Object<string,(BufferAttribute|InterleavedBufferAttribute)>} 18242 */ 18243 this.attributes = {}; 18244 18245 /** 18246 * This dictionary holds the morph targets of the geometry. 18247 * 18248 * Note: Once the geometry has been rendered, the morph attribute data cannot 18249 * be changed. You will have to call `dispose()`, and create a new geometry instance. 18250 * 18251 * @type {Object} 18252 */ 18253 this.morphAttributes = {}; 18254 18255 /** 18256 * Used to control the morph target behavior; when set to `true`, the morph 18257 * target data is treated as relative offsets, rather than as absolute 18258 * positions/normals. 18259 * 18260 * @type {boolean} 18261 * @default false 18262 */ 18263 this.morphTargetsRelative = false; 18264 18265 /** 18266 * Split the geometry into groups, each of which will be rendered in a 18267 * separate draw call. This allows an array of materials to be used with the geometry. 18268 * 18269 * Use `addGroup()` and `clearGroups()` to edit groups, rather than modifying this array directly. 18270 * 18271 * Every vertex and index must belong to exactly one group â groups must not share vertices or 18272 * indices, and must not leave vertices or indices unused. 18273 * 18274 * @type {Array<Object>} 18275 */ 18276 this.groups = []; 18277 18278 /** 18279 * Bounding box for the geometry which can be calculated with `computeBoundingBox()`. 18280 * 18281 * @type {?Box3} 18282 * @default null 18283 */ 18284 this.boundingBox = null; 18285 18286 /** 18287 * Bounding sphere for the geometry which can be calculated with `computeBoundingSphere()`. 18288 * 18289 * @type {?Sphere} 18290 * @default null 18291 */ 18292 this.boundingSphere = null; 18293 18294 /** 18295 * Determines the part of the geometry to render. This should not be set directly, 18296 * instead use `setDrawRange()`. 18297 * 18298 * @type {{start:number,count:number}} 18299 */ 18300 this.drawRange = { start: 0, count: Infinity }; 18301 18302 /** 18303 * An object that can be used to store custom data about the geometry. 18304 * It should not hold references to functions as these will not be cloned. 18305 * 18306 * @type {Object} 18307 */ 18308 this.userData = {}; 18309 18310 } 18311 18312 /** 18313 * Returns the index of this geometry. 18314 * 18315 * @return {?BufferAttribute} The index. Returns `null` if no index is defined. 18316 */ 18317 getIndex() { 18318 18319 return this.index; 18320 18321 } 18322 18323 /** 18324 * Sets the given index to this geometry. 18325 * 18326 * @param {Array<number>|BufferAttribute} index - The index to set. 18327 * @return {BufferGeometry} A reference to this instance. 18328 */ 18329 setIndex( index ) { 18330 18331 if ( Array.isArray( index ) ) { 18332 18333 this.index = new ( arrayNeedsUint32( index ) ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 ); 18334 18335 } else { 18336 18337 this.index = index; 18338 18339 } 18340 18341 return this; 18342 18343 } 18344 18345 /** 18346 * Sets the given indirect attribute to this geometry. 18347 * 18348 * @param {BufferAttribute} indirect - The attribute holding indirect draw calls. 18349 * @param {number|Array<number>} [indirectOffset=0] - The offset, in bytes, into the indirect drawing buffer where the value data begins. If an array is provided, multiple indirect draw calls will be made for each offset. 18350 * @return {BufferGeometry} A reference to this instance. 18351 */ 18352 setIndirect( indirect, indirectOffset = 0 ) { 18353 18354 this.indirect = indirect; 18355 this.indirectOffset = indirectOffset; 18356 18357 return this; 18358 18359 } 18360 18361 /** 18362 * Returns the indirect attribute of this geometry. 18363 * 18364 * @return {?BufferAttribute} The indirect attribute. Returns `null` if no indirect attribute is defined. 18365 */ 18366 getIndirect() { 18367 18368 return this.indirect; 18369 18370 } 18371 18372 /** 18373 * Returns the buffer attribute for the given name. 18374 * 18375 * @param {string} name - The attribute name. 18376 * @return {BufferAttribute|InterleavedBufferAttribute|undefined} The buffer attribute. 18377 * Returns `undefined` if not attribute has been found. 18378 */ 18379 getAttribute( name ) { 18380 18381 return this.attributes[ name ]; 18382 18383 } 18384 18385 /** 18386 * Sets the given attribute for the given name. 18387 * 18388 * @param {string} name - The attribute name. 18389 * @param {BufferAttribute|InterleavedBufferAttribute} attribute - The attribute to set. 18390 * @return {BufferGeometry} A reference to this instance. 18391 */ 18392 setAttribute( name, attribute ) { 18393 18394 this.attributes[ name ] = attribute; 18395 18396 return this; 18397 18398 } 18399 18400 /** 18401 * Deletes the attribute for the given name. 18402 * 18403 * @param {string} name - The attribute name to delete. 18404 * @return {BufferGeometry} A reference to this instance. 18405 */ 18406 deleteAttribute( name ) { 18407 18408 delete this.attributes[ name ]; 18409 18410 return this; 18411 18412 } 18413 18414 /** 18415 * Returns `true` if this geometry has an attribute for the given name. 18416 * 18417 * @param {string} name - The attribute name. 18418 * @return {boolean} Whether this geometry has an attribute for the given name or not. 18419 */ 18420 hasAttribute( name ) { 18421 18422 return this.attributes[ name ] !== undefined; 18423 18424 } 18425 18426 /** 18427 * Adds a group to this geometry. 18428 * 18429 * @param {number} start - The first element in this draw call. That is the first 18430 * vertex for non-indexed geometry, otherwise the first triangle index. 18431 * @param {number} count - Specifies how many vertices (or indices) are part of this group. 18432 * @param {number} [materialIndex=0] - The material array index to use. 18433 */ 18434 addGroup( start, count, materialIndex = 0 ) { 18435 18436 this.groups.push( { 18437 18438 start: start, 18439 count: count, 18440 materialIndex: materialIndex 18441 18442 } ); 18443 18444 } 18445 18446 /** 18447 * Clears all groups. 18448 */ 18449 clearGroups() { 18450 18451 this.groups = []; 18452 18453 } 18454 18455 /** 18456 * Sets the draw range for this geometry. 18457 * 18458 * @param {number} start - The first vertex for non-indexed geometry, otherwise the first triangle index. 18459 * @param {number} count - For non-indexed BufferGeometry, `count` is the number of vertices to render. 18460 * For indexed BufferGeometry, `count` is the number of indices to render. 18461 */ 18462 setDrawRange( start, count ) { 18463 18464 this.drawRange.start = start; 18465 this.drawRange.count = count; 18466 18467 } 18468 18469 /** 18470 * Applies the given 4x4 transformation matrix to the geometry. 18471 * 18472 * @param {Matrix4} matrix - The matrix to apply. 18473 * @return {BufferGeometry} A reference to this instance. 18474 */ 18475 applyMatrix4( matrix ) { 18476 18477 const position = this.attributes.position; 18478 18479 if ( position !== undefined ) { 18480 18481 position.applyMatrix4( matrix ); 18482 18483 position.needsUpdate = true; 18484 18485 } 18486 18487 const normal = this.attributes.normal; 18488 18489 if ( normal !== undefined ) { 18490 18491 const normalMatrix = new Matrix3().getNormalMatrix( matrix ); 18492 18493 normal.applyNormalMatrix( normalMatrix ); 18494 18495 normal.needsUpdate = true; 18496 18497 } 18498 18499 const tangent = this.attributes.tangent; 18500 18501 if ( tangent !== undefined ) { 18502 18503 tangent.transformDirection( matrix ); 18504 18505 tangent.needsUpdate = true; 18506 18507 } 18508 18509 if ( this.boundingBox !== null ) { 18510 18511 this.computeBoundingBox(); 18512 18513 } 18514 18515 if ( this.boundingSphere !== null ) { 18516 18517 this.computeBoundingSphere(); 18518 18519 } 18520 18521 return this; 18522 18523 } 18524 18525 /** 18526 * Applies the rotation represented by the Quaternion to the geometry. 18527 * 18528 * @param {Quaternion} q - The Quaternion to apply. 18529 * @return {BufferGeometry} A reference to this instance. 18530 */ 18531 applyQuaternion( q ) { 18532 18533 _m1
vendor: 8,143 bytes, lines 18533-18873
18533.makeRotationFromQuaternion( q ); 18534 18535 this.applyMatrix4( _m1 ); 18536 18537 return this; 18538 18539 } 18540 18541 /** 18542 * Rotates the geometry about the X axis. This is typically done as a one time 18543 * operation, and not during a loop. Use {@link Object3D#rotation} for typical 18544 * real-time mesh rotation. 18545 * 18546 * @param {number} angle - The angle in radians. 18547 * @return {BufferGeometry} A reference to this instance. 18548 */ 18549 rotateX( angle ) { 18550 18551 // rotate geometry around world x-axis 18552 18553 _m1.makeRotationX( angle ); 18554 18555 this.applyMatrix4( _m1 ); 18556 18557 return this; 18558 18559 } 18560 18561 /** 18562 * Rotates the geometry about the Y axis. This is typically done as a one time 18563 * operation, and not during a loop. Use {@link Object3D#rotation} for typical 18564 * real-time mesh rotation. 18565 * 18566 * @param {number} angle - The angle in radians. 18567 * @return {BufferGeometry} A reference to this instance. 18568 */ 18569 rotateY( angle ) { 18570 18571 // rotate geometry around world y-axis 18572 18573 _m1.makeRotationY( angle ); 18574 18575 this.applyMatrix4( _m1 ); 18576 18577 return this; 18578 18579 } 18580 18581 /** 18582 * Rotates the geometry about the Z axis. This is typically done as a one time 18583 * operation, and not during a loop. Use {@link Object3D#rotation} for typical 18584 * real-time mesh rotation. 18585 * 18586 * @param {number} angle - The angle in radians. 18587 * @return {BufferGeometry} A reference to this instance. 18588 */ 18589 rotateZ( angle ) { 18590 18591 // rotate geometry around world z-axis 18592 18593 _m1.makeRotationZ( angle ); 18594 18595 this.applyMatrix4( _m1 ); 18596 18597 return this; 18598 18599 } 18600 18601 /** 18602 * Translates the geometry. This is typically done as a one time 18603 * operation, and not during a loop. Use {@link Object3D#position} for typical 18604 * real-time mesh rotation. 18605 * 18606 * @param {number} x - The x offset. 18607 * @param {number} y - The y offset. 18608 * @param {number} z - The z offset. 18609 * @return {BufferGeometry} A reference to this instance. 18610 */ 18611 translate( x, y, z ) { 18612 18613 // translate geometry 18614 18615 _m1.makeTranslation( x, y, z ); 18616 18617 this.applyMatrix4( _m1 ); 18618 18619 return this; 18620 18621 } 18622 18623 /** 18624 * Scales the geometry. This is typically done as a one time 18625 * operation, and not during a loop. Use {@link Object3D#scale} for typical 18626 * real-time mesh rotation. 18627 * 18628 * @param {number} x - The x scale. 18629 * @param {number} y - The y scale. 18630 * @param {number} z - The z scale. 18631 * @return {BufferGeometry} A reference to this instance. 18632 */ 18633 scale( x, y, z ) { 18634 18635 // scale geometry 18636 18637 _m1.makeScale( x, y, z ); 18638 18639 this.applyMatrix4( _m1 ); 18640 18641 return this; 18642 18643 } 18644 18645 /** 18646 * Rotates the geometry to face a point in 3D space. This is typically done as a one time 18647 * operation, and not during a loop. Use {@link Object3D#lookAt} for typical 18648 * real-time mesh rotation. 18649 * 18650 * @param {Vector3} vector - The target point. 18651 * @return {BufferGeometry} A reference to this instance. 18652 */ 18653 lookAt( vector ) { 18654 18655 _obj.lookAt( vector ); 18656 18657 _obj.updateMatrix(); 18658 18659 this.applyMatrix4( _obj.matrix ); 18660 18661 return this; 18662 18663 } 18664 18665 /** 18666 * Center the geometry based on its bounding box. 18667 * 18668 * @return {BufferGeometry} A reference to this instance. 18669 */ 18670 center() { 18671 18672 this.computeBoundingBox(); 18673 18674 this.boundingBox.getCenter( _offset ).negate(); 18675 18676 this.translate( _offset.x, _offset.y, _offset.z ); 18677 18678 return this; 18679 18680 } 18681 18682 /** 18683 * Defines a geometry by creating a `position` attribute based on the given array of points. The array 18684 * can hold 2D or 3D vectors. When using two-dimensional data, the `z` coordinate for all vertices is 18685 * set to `0`. 18686 * 18687 * If the method is used with an existing `position` attribute, the vertex data are overwritten with the 18688 * data from the array. The length of the array must match the vertex count. 18689 * 18690 * @param {Array<Vector2>|Array<Vector3>} points - The points. 18691 * @return {BufferGeometry} A reference to this instance. 18692 */ 18693 setFromPoints( points ) { 18694 18695 const positionAttribute = this.getAttribute( 'position' ); 18696 18697 if ( positionAttribute === undefined ) { 18698 18699 const position = []; 18700 18701 for ( let i = 0, l = points.length; i < l; i ++ ) { 18702 18703 const point = points[ i ]; 18704 position.push( point.x, point.y, point.z || 0 ); 18705 18706 } 18707 18708 this.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) ); 18709 18710 } else { 18711 18712 const l = Math.min( points.length, positionAttribute.count ); // make sure data do not exceed buffer size 18713 18714 for ( let i = 0; i < l; i ++ ) { 18715 18716 const point = points[ i ]; 18717 positionAttribute.setXYZ( i, point.x, point.y, point.z || 0 ); 18718 18719 } 18720 18721 if ( points.length > positionAttribute.count ) { 18722 18723 warn( 'BufferGeometry: Buffer size too small for points data. Use .dispose() and create a new geometry.' ); 18724 18725 } 18726 18727 positionAttribute.needsUpdate = true; 18728 18729 } 18730 18731 return this; 18732 18733 } 18734 18735 /** 18736 * Computes the bounding box of the geometry, and updates the `boundingBox` member. 18737 * The bounding box is not computed by the engine; it must be computed by your app. 18738 * You may need to recompute the bounding box if the geometry vertices are modified. 18739 */ 18740 computeBoundingBox() { 18741 18742 if ( this.boundingBox === null ) { 18743 18744 this.boundingBox = new Box3(); 18745 18746 } 18747 18748 const position = this.attributes.position; 18749 const morphAttributesPosition = this.morphAttributes.position; 18750 18751 if ( position && position.isGLBufferAttribute ) { 18752 18753 error( 'BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box.', this ); 18754 18755 this.boundingBox.set( 18756 new Vector3( - Infinity, - Infinity, - Infinity ), 18757 new Vector3( + Infinity, + Infinity, + Infinity ) 18758 ); 18759 18760 return; 18761 18762 } 18763 18764 if ( position !== undefined ) { 18765 18766 this.boundingBox.setFromBufferAttribute( position ); 18767 18768 // process morph attributes if present 18769 18770 if ( morphAttributesPosition ) { 18771 18772 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { 18773 18774 const morphAttribute = morphAttributesPosition[ i ]; 18775 _box$2.setFromBufferAttribute( morphAttribute ); 18776 18777 if ( this.morphTargetsRelative ) { 18778 18779 _vector$9.addVectors( this.boundingBox.min, _box$2.min ); 18780 this.boundingBox.expandByPoint( _vector$9 ); 18781 18782 _vector$9.addVectors( this.boundingBox.max, _box$2.max ); 18783 this.boundingBox.expandByPoint( _vector$9 ); 18784 18785 } else { 18786 18787 this.boundingBox.expandByPoint( _box$2.min ); 18788 this.boundingBox.expandByPoint( _box$2.max ); 18789 18790 } 18791 18792 } 18793 18794 } 18795 18796 } else { 18797 18798 this.boundingBox.makeEmpty(); 18799 18800 } 18801 18802 if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) { 18803 18804 error( 'BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this ); 18805 18806 } 18807 18808 } 18809 18810 /** 18811 * Computes the bounding sphere of the geometry, and updates the `boundingSphere` member. 18812 * The engine automatically computes the bounding sphere when it is needed, e.g., for ray casting or view frustum culling. 18813 * You may need to recompute the bounding sphere if the geometry vertices are modified. 18814 */ 18815 computeBoundingSphere() { 18816 18817 if ( this.boundingSphere === null ) { 18818 18819 this.boundingSphere = new Sphere(); 18820 18821 } 18822 18823 const position = this.attributes.position; 18824 const morphAttributesPosition = this.morphAttributes.position; 18825 18826 if ( position && position.isGLBufferAttribute ) { 18827 18828 error( 'BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere.', this ); 18829 18830 this.boundingSphere.set( new Vector3(), Infinity ); 18831 18832 return; 18833 18834 } 18835 18836 if ( position ) { 18837 18838 // first, find the center of the bounding sphere 18839 18840 const center = this.boundingSphere.center; 18841 18842 _box$2.setFromBufferAttribute( position ); 18843 18844 // process morph attributes if present 18845 18846 if ( morphAttributesPosition ) { 18847 18848 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { 18849 18850 const morphAttribute = morphAttributesPosition[ i ]; 18851 _boxMorphTargets.setFromBufferAttribute( morphAttribute ); 18852 18853 if ( this.morphTargetsRelative ) { 18854 18855 _vector$9.addVectors( _box$2.min, _boxMorphTargets.min ); 18856 _box$2.expandByPoint( _vector$9 ); 18857 18858 _vector$9.addVectors( _box$2.max, _boxMorphTargets.max ); 18859 _box$2.expandByPoint( _vector$9 ); 18860 18861 } else { 18862 18863 _box$2.expandByPoint( _boxMorphTargets.min ); 18864 _box$2.expandByPoint( _boxMorphTargets.max ); 18865 18866 } 18867 18868 } 18869 18870 } 18871 18872 _box$2.getCenter( center ); 18873
vendor: 9,252 bytes, lines 18874-19264
18874 // second, try to find a boundingSphere with a radius smaller than the 18875 // boundingSphere of the boundingBox: sqrt(3) smaller in the best case 18876 18877 let maxRadiusSq = 0; 18878 18879 for ( let i = 0, il = position.count; i < il; i ++ ) { 18880 18881 _vector$9.fromBufferAttribute( position, i ); 18882 18883 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$9 ) ); 18884 18885 } 18886 18887 // process morph attributes if present 18888 18889 if ( morphAttributesPosition ) { 18890 18891 for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { 18892 18893 const morphAttribute = morphAttributesPosition[ i ]; 18894 const morphTargetsRelative = this.morphTargetsRelative; 18895 18896 for ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) { 18897 18898 _vector$9.fromBufferAttribute( morphAttribute, j ); 18899 18900 if ( morphTargetsRelative ) { 18901 18902 _offset.fromBufferAttribute( position, j ); 18903 _vector$9.add( _offset ); 18904 18905 } 18906 18907 maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$9 ) ); 18908 18909 } 18910 18911 } 18912 18913 } 18914 18915 this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); 18916 18917 if ( isNaN( this.boundingSphere.radius ) ) { 18918 18919 error( 'BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this ); 18920 18921 } 18922 18923 } 18924 18925 } 18926 18927 /** 18928 * Calculates and adds a tangent attribute to this geometry. 18929 * 18930 * The computation is only supported for indexed geometries and if position, normal, and uv attributes 18931 * are defined. When using a tangent space normal map, prefer the MikkTSpace algorithm provided by 18932 * {@link BufferGeometryUtils#computeMikkTSpaceTangents} instead. 18933 */ 18934 computeTangents() { 18935 18936 const index = this.index; 18937 const attributes = this.attributes; 18938 18939 // based on http://www.terathon.com/code/tangent.html 18940 // (per vertex tangents) 18941 18942 if ( index === null || 18943 attributes.position === undefined || 18944 attributes.normal === undefined || 18945 attributes.uv === undefined ) { 18946 18947 error( 'BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' ); 18948 return; 18949 18950 } 18951 18952 const positionAttribute = attributes.position; 18953 const normalAttribute = attributes.normal; 18954 const uvAttribute = attributes.uv; 18955 18956 if ( this.hasAttribute( 'tangent' ) === false ) { 18957 18958 this.setAttribute( 'tangent', new BufferAttribute( new Float32Array( 4 * positionAttribute.count ), 4 ) ); 18959 18960 } 18961 18962 const tangentAttribute = this.getAttribute( 'tangent' ); 18963 18964 const tan1 = [], tan2 = []; 18965 18966 for ( let i = 0; i < positionAttribute.count; i ++ ) { 18967 18968 tan1[ i ] = new Vector3(); 18969 tan2[ i ] = new Vector3(); 18970 18971 } 18972 18973 const vA = new Vector3(), 18974 vB = new Vector3(), 18975 vC = new Vector3(), 18976 18977 uvA = new Vector2(), 18978 uvB = new Vector2(), 18979 uvC = new Vector2(), 18980 18981 sdir = new Vector3(), 18982 tdir = new Vector3(); 18983 18984 function handleTriangle( a, b, c ) { 18985 18986 vA.fromBufferAttribute( positionAttribute, a ); 18987 vB.fromBufferAttribute( positionAttribute, b ); 18988 vC.fromBufferAttribute( positionAttribute, c ); 18989 18990 uvA.fromBufferAttribute( uvAttribute, a ); 18991 uvB.fromBufferAttribute( uvAttribute, b ); 18992 uvC.fromBufferAttribute( uvAttribute, c ); 18993 18994 vB.sub( vA ); 18995 vC.sub( vA ); 18996 18997 uvB.sub( uvA ); 18998 uvC.sub( uvA ); 18999 19000 const r = 1.0 / ( uvB.x * uvC.y - uvC.x * uvB.y ); 19001 19002 // silently ignore degenerate uv triangles having coincident or colinear vertices 19003 19004 if ( ! isFinite( r ) ) return; 19005 19006 sdir.copy( vB ).multiplyScalar( uvC.y ).addScaledVector( vC, - uvB.y ).multiplyScalar( r ); 19007 tdir.copy( vC ).multiplyScalar( uvB.x ).addScaledVector( vB, - uvC.x ).multiplyScalar( r ); 19008 19009 tan1[ a ].add( sdir ); 19010 tan1[ b ].add( sdir ); 19011 tan1[ c ].add( sdir ); 19012 19013 tan2[ a ].add( tdir ); 19014 tan2[ b ].add( tdir ); 19015 tan2[ c ].add( tdir ); 19016 19017 } 19018 19019 let groups = this.groups; 19020 19021 if ( groups.length === 0 ) { 19022 19023 groups = [ { 19024 start: 0, 19025 count: index.count 19026 } ]; 19027 19028 } 19029 19030 for ( let i = 0, il = groups.length; i < il; ++ i ) { 19031 19032 const group = groups[ i ]; 19033 19034 const start = group.start; 19035 const count = group.count; 19036 19037 for ( let j = start, jl = start + count; j < jl; j += 3 ) { 19038 19039 handleTriangle( 19040 index.getX( j + 0 ), 19041 index.getX( j + 1 ), 19042 index.getX( j + 2 ) 19043 ); 19044 19045 } 19046 19047 } 19048 19049 const tmp = new Vector3(), tmp2 = new Vector3(); 19050 const n = new Vector3(), n2 = new Vector3(); 19051 19052 function handleVertex( v ) { 19053 19054 n.fromBufferAttribute( normalAttribute, v ); 19055 n2.copy( n ); 19056 19057 const t = tan1[ v ]; 19058 19059 // Gram-Schmidt orthogonalize 19060 19061 tmp.copy( t ); 19062 tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); 19063 19064 // Calculate handedness 19065 19066 tmp2.crossVectors( n2, t ); 19067 const test = tmp2.dot( tan2[ v ] ); 19068 const w = ( test < 0.0 ) ? -1 : 1.0; 19069 19070 tangentAttribute.setXYZW( v, tmp.x, tmp.y, tmp.z, w ); 19071 19072 } 19073 19074 for ( let i = 0, il = groups.length; i < il; ++ i ) { 19075 19076 const group = groups[ i ]; 19077 19078 const start = group.start; 19079 const count = group.count; 19080 19081 for ( let j = start, jl = start + count; j < jl; j += 3 ) { 19082 19083 handleVertex( index.getX( j + 0 ) ); 19084 handleVertex( index.getX( j + 1 ) ); 19085 handleVertex( index.getX( j + 2 ) ); 19086 19087 } 19088 19089 } 19090 19091 } 19092 19093 /** 19094 * Computes vertex normals for the given vertex data. For indexed geometries, the method sets 19095 * each vertex normal to be the average of the face normals of the faces that share that vertex. 19096 * For non-indexed geometries, vertices are not shared, and the method sets each vertex normal 19097 * to be the same as the face normal. 19098 */ 19099 computeVertexNormals() { 19100 19101 const index = this.index; 19102 const positionAttribute = this.getAttribute( 'position' ); 19103 19104 if ( positionAttribute !== undefined ) { 19105 19106 let normalAttribute = this.getAttribute( 'normal' ); 19107 19108 if ( normalAttribute === undefined ) { 19109 19110 normalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 ); 19111 this.setAttribute( 'normal', normalAttribute ); 19112 19113 } else { 19114 19115 // reset existing normals to zero 19116 19117 for ( let i = 0, il = normalAttribute.count; i < il; i ++ ) { 19118 19119 normalAttribute.setXYZ( i, 0, 0, 0 ); 19120 19121 } 19122 19123 } 19124 19125 const pA = new Vector3(), pB = new Vector3(), pC = new Vector3(); 19126 const nA = new Vector3(), nB = new Vector3(), nC = new Vector3(); 19127 const cb = new Vector3(), ab = new Vector3(); 19128 19129 // indexed elements 19130 19131 if ( index ) { 19132 19133 for ( let i = 0, il = index.count; i < il; i += 3 ) { 19134 19135 const vA = index.getX( i + 0 ); 19136 const vB = index.getX( i + 1 ); 19137 const vC = index.getX( i + 2 ); 19138 19139 pA.fromBufferAttribute( positionAttribute, vA ); 19140 pB.fromBufferAttribute( positionAttribute, vB ); 19141 pC.fromBufferAttribute( positionAttribute, vC ); 19142 19143 cb.subVectors( pC, pB ); 19144 ab.subVectors( pA, pB ); 19145 cb.cross( ab ); 19146 19147 nA.fromBufferAttribute( normalAttribute, vA ); 19148 nB.fromBufferAttribute( normalAttribute, vB ); 19149 nC.fromBufferAttribute( normalAttribute, vC ); 19150 19151 nA.add( cb ); 19152 nB.add( cb ); 19153 nC.add( cb ); 19154 19155 normalAttribute.setXYZ( vA, nA.x, nA.y, nA.z ); 19156 normalAttribute.setXYZ( vB, nB.x, nB.y, nB.z ); 19157 normalAttribute.setXYZ( vC, nC.x, nC.y, nC.z ); 19158 19159 } 19160 19161 } else { 19162 19163 // non-indexed elements (unconnected triangle soup) 19164 19165 for ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) { 19166 19167 pA.fromBufferAttribute( positionAttribute, i + 0 ); 19168 pB.fromBufferAttribute( positionAttribute, i + 1 ); 19169 pC.fromBufferAttribute( positionAttribute, i + 2 ); 19170 19171 cb.subVectors( pC, pB ); 19172 ab.subVectors( pA, pB ); 19173 cb.cross( ab ); 19174 19175 normalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z ); 19176 normalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z ); 19177 normalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z ); 19178 19179 } 19180 19181 } 19182 19183 this.normalizeNormals(); 19184 19185 normalAttribute.needsUpdate = true; 19186 19187 } 19188 19189 } 19190 19191 /** 19192 * Ensures every normal vector in a geometry will have a magnitude of `1`. This will 19193 * correct lighting on the geometry surfaces. 19194 */ 19195 normalizeNormals() { 19196 19197 const normals = this.attributes.normal; 19198 19199 for ( let i = 0, il = normals.count; i < il; i ++ ) { 19200 19201 _vector$9.fromBufferAttribute( normals, i ); 19202 19203 _vector$9.normalize(); 19204 19205 normals.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z ); 19206 19207 } 19208 19209 } 19210 19211 /** 19212 * Return a new non-index version of this indexed geometry. If the geometry 19213 * is already non-indexed, the method is a NOOP. 19214 * 19215 * @return {BufferGeometry} The non-indexed version of this indexed geometry. 19216 */ 19217 toNonIndexed() { 19218 19219 function convertBufferAttribute( attribute, indices ) { 19220 19221 const array = attribute.array; 19222 const itemSize = attribute.itemSize; 19223 const normalized = attribute.normalized; 19224 19225 const array2 = new array.constructor( indices.length * itemSize ); 19226 19227 let index = 0, index2 = 0; 19228 19229 for ( let i = 0, l = indices.length; i < l; i ++ ) { 19230 19231 if ( attribute.isInterleavedBufferAttribute ) { 19232 19233 index = indices[ i ] * attribute.data.stride + attribute.offset; 19234 19235 } else { 19236 19237 index = indices[ i ] * itemSize; 19238 19239 } 19240 19241 for ( let j = 0; j < itemSize; j ++ ) { 19242 19243 array2[ index2 ++ ] = array[ index ++ ]; 19244 19245 } 19246 19247 } 19248 19249 return new BufferAttribute( array2, itemSize, normalized ); 19250 19251 } 19252 19253 // 19254 19255 if ( this.index === null ) { 19256 19257 warn( 'BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' ); 19258 return this; 19259 19260 } 19261 19262 const geometry2 = new BufferGeometry(); 19263 19264 const indices = this.index.array;
vendor: 1,085 bytes, lines 19265-19318
19265 const attributes = this.attributes; 19266 19267 // attributes 19268 19269 for ( const name in attributes ) { 19270 19271 const attribute = attributes[ name ]; 19272 19273 const newAttribute = convertBufferAttribute( attribute, indices ); 19274 19275 geometry2.setAttribute( name, newAttribute ); 19276 19277 } 19278 19279 // morph attributes 19280 19281 const morphAttributes = this.morphAttributes; 19282 19283 for ( const name in morphAttributes ) { 19284 19285 const morphArray = []; 19286 const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes 19287 19288 for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) { 19289 19290 const attribute = morphAttribute[ i ]; 19291 19292 const newAttribute = convertBufferAttribute( attribute, indices ); 19293 19294 morphArray.push( newAttribute ); 19295 19296 } 19297 19298 geometry2.morphAttributes[ name ] = morphArray; 19299 19300 } 19301 19302 geometry2.morphTargetsRelative = this.morphTargetsRelative; 19303 19304 // groups 19305 19306 const groups = this.groups; 19307 19308 for ( let i = 0, l = groups.length; i < l; i ++ ) { 19309 19310 const group = groups[ i ]; 19311 geometry2.addGroup( group.start, group.count, group.materialIndex ); 19312 19313 } 19314 19315 return geometry2; 19316 19317 } 19318
vendor: 6,721 bytes, lines 19319-19652
19319 /** 19320 * Serializes the geometry into JSON. 19321 * 19322 * @return {Object} A JSON object representing the serialized geometry. 19323 */ 19324 toJSON() { 19325 19326 const data = { 19327 metadata: { 19328 version: 4.7, 19329 type: 'BufferGeometry', 19330 generator: 'BufferGeometry.toJSON' 19331 } 19332 }; 19333 19334 // standard BufferGeometry serialization 19335 19336 data.uuid = this.uuid; 19337 data.type = this.type; 19338 if ( this.name !== '' ) data.name = this.name; 19339 if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData; 19340 19341 if ( this.parameters !== undefined ) { 19342 19343 const parameters = this.parameters; 19344 19345 for ( const key in parameters ) { 19346 19347 if ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ]; 19348 19349 } 19350 19351 return data; 19352 19353 } 19354 19355 // for simplicity the code assumes attributes are not shared across geometries, see #15811 19356 19357 data.data = { attributes: {} }; 19358 19359 const index = this.index; 19360 19361 if ( index !== null ) { 19362 19363 data.data.index = { 19364 type: index.array.constructor.name, 19365 array: Array.prototype.slice.call( index.array ) 19366 }; 19367 19368 } 19369 19370 const attributes = this.attributes; 19371 19372 for ( const key in attributes ) { 19373 19374 const attribute = attributes[ key ]; 19375 19376 data.data.attributes[ key ] = attribute.toJSON( data.data ); 19377 19378 } 19379 19380 const morphAttributes = {}; 19381 let hasMorphAttributes = false; 19382 19383 for ( const key in this.morphAttributes ) { 19384 19385 const attributeArray = this.morphAttributes[ key ]; 19386 19387 const array = []; 19388 19389 for ( let i = 0, il = attributeArray.length; i < il; i ++ ) { 19390 19391 const attribute = attributeArray[ i ]; 19392 19393 array.push( attribute.toJSON( data.data ) ); 19394 19395 } 19396 19397 if ( array.length > 0 ) { 19398 19399 morphAttributes[ key ] = array; 19400 19401 hasMorphAttributes = true; 19402 19403 } 19404 19405 } 19406 19407 if ( hasMorphAttributes ) { 19408 19409 data.data.morphAttributes = morphAttributes; 19410 data.data.morphTargetsRelative = this.morphTargetsRelative; 19411 19412 } 19413 19414 const groups = this.groups; 19415 19416 if ( groups.length > 0 ) { 19417 19418 data.data.groups = JSON.parse( JSON.stringify( groups ) ); 19419 19420 } 19421 19422 const boundingSphere = this.boundingSphere; 19423 19424 if ( boundingSphere !== null ) { 19425 19426 data.data.boundingSphere = boundingSphere.toJSON(); 19427 19428 } 19429 19430 return data; 19431 19432 } 19433 19434 /** 19435 * Returns a new geometry with copied values from this instance. 19436 * 19437 * @return {BufferGeometry} A clone of this instance. 19438 */ 19439 clone() { 19440 19441 return new this.constructor().copy( this ); 19442 19443 } 19444 19445 /** 19446 * Copies the values of the given geometry to this instance. 19447 * 19448 * @param {BufferGeometry} source - The geometry to copy. 19449 * @return {BufferGeometry} A reference to this instance. 19450 */ 19451 copy( source ) { 19452 19453 // reset 19454 19455 this.index = null; 19456 this.attributes = {}; 19457 this.morphAttributes = {}; 19458 this.groups = []; 19459 this.boundingBox = null; 19460 this.boundingSphere = null; 19461 19462 // used for storing cloned, shared data 19463 19464 const data = {}; 19465 19466 // name 19467 19468 this.name = source.name; 19469 19470 // index 19471 19472 const index = source.index; 19473 19474 if ( index !== null ) { 19475 19476 this.setIndex( index.clone() ); 19477 19478 } 19479 19480 // attributes 19481 19482 const attributes = source.attributes; 19483 19484 for ( const name in attributes ) { 19485 19486 const attribute = attributes[ name ]; 19487 this.setAttribute( name, attribute.clone( data ) ); 19488 19489 } 19490 19491 // morph attributes 19492 19493 const morphAttributes = source.morphAttributes; 19494 19495 for ( const name in morphAttributes ) { 19496 19497 const array = []; 19498 const morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes 19499 19500 for ( let i = 0, l = morphAttribute.length; i < l; i ++ ) { 19501 19502 array.push( morphAttribute[ i ].clone( data ) ); 19503 19504 } 19505 19506 this.morphAttributes[ name ] = array; 19507 19508 } 19509 19510 this.morphTargetsRelative = source.morphTargetsRelative; 19511 19512 // groups 19513 19514 const groups = source.groups; 19515 19516 for ( let i = 0, l = groups.length; i < l; i ++ ) { 19517 19518 const group = groups[ i ]; 19519 this.addGroup( group.start, group.count, group.materialIndex ); 19520 19521 } 19522 19523 // bounding box 19524 19525 const boundingBox = source.boundingBox; 19526 19527 if ( boundingBox !== null ) { 19528 19529 this.boundingBox = boundingBox.clone(); 19530 19531 } 19532 19533 // bounding sphere 19534 19535 const boundingSphere = source.boundingSphere; 19536 19537 if ( boundingSphere !== null ) { 19538 19539 this.boundingSphere = boundingSphere.clone(); 19540 19541 } 19542 19543 // draw range 19544 19545 this.drawRange.start = source.drawRange.start; 19546 this.drawRange.count = source.drawRange.count; 19547 19548 // user data 19549 19550 this.userData = source.userData; 19551 19552 return this; 19553 19554 } 19555 19556 /** 19557 * Frees the GPU-related resources allocated by this instance. Call this 19558 * method whenever this instance is no longer used in your app. 19559 * 19560 * @fires BufferGeometry#dispose 19561 */ 19562 dispose() { 19563 19564 this.dispatchEvent( { type: 'dispose' } ); 19565 19566 } 19567 19568} 19569 19570/** 19571 * "Interleaved" means that multiple attributes, possibly of different types, 19572 * (e.g., position, normal, uv, color) are packed into a single array buffer. 19573 * 19574 * An introduction into interleaved arrays can be found here: [Interleaved array basics](https://blog.tojicode.com/2011/05/interleaved-array-basics.html) 19575 */ 19576class InterleavedBuffer { 19577 19578 /** 19579 * Constructs a new interleaved buffer. 19580 * 19581 * @param {TypedArray} array - A typed array with a shared buffer storing attribute data. 19582 * @param {number} stride - The number of typed-array elements per vertex. 19583 */ 19584 constructor( array, stride ) { 19585 19586 /** 19587 * This flag can be used for type testing. 19588 * 19589 * @type {boolean} 19590 * @readonly 19591 * @default true 19592 */ 19593 this.isInterleavedBuffer = true; 19594 19595 /** 19596 * A typed array with a shared buffer storing attribute data. 19597 * 19598 * @type {TypedArray} 19599 */ 19600 this.array = array; 19601 19602 /** 19603 * The number of typed-array elements per vertex. 19604 * 19605 * @type {number} 19606 */ 19607 this.stride = stride; 19608 19609 /** 19610 * The total number of elements in the array 19611 * 19612 * @type {number} 19613 * @readonly 19614 */ 19615 this.count = array !== undefined ? array.length / stride : 0; 19616 19617 /** 19618 * Defines the intended usage pattern of the data store for optimization purposes. 19619 * 19620 * Note: After the initial use of a buffer, its usage cannot be changed. Instead, 19621 * instantiate a new one and set the desired usage before the next render. 19622 * 19623 * @type {(StaticDrawUsage|DynamicDrawUsage|StreamDrawUsage|StaticReadUsage|DynamicReadUsage|StreamReadUsage|StaticCopyUsage|DynamicCopyUsage|StreamCopyUsage)} 19624 * @default StaticDrawUsage 19625 */ 19626 this.usage = StaticDrawUsage; 19627 19628 /** 19629 * This can be used to only update some components of stored vectors (for example, just the 19630 * component related to color). Use the `addUpdateRange()` function to add ranges to this array. 19631 * 19632 * @type {Array<Object>} 19633 */ 19634 this.updateRanges = []; 19635 19636 /** 19637 * A version number, incremented every time the `needsUpdate` is set to `true`. 19638 * 19639 * @type {number} 19640 */ 19641 this.version = 0; 19642 19643 /** 19644 * The UUID of the interleaved buffer. 19645 * 19646 * @type {string} 19647 * @readonly 19648 */ 19649 this.uuid = generateUUID(); 19650 19651 } 19652
vendor: 3,573 bytes, lines 19653-19799
19653 /** 19654 * A callback function that is executed after the renderer has transferred the attribute array 19655 * data to the GPU. 19656 */ 19657 onUploadCallback() {} 19658 19659 /** 19660 * Flag to indicate that this attribute has changed and should be re-sent to 19661 * the GPU. Set this to `true` when you modify the value of the array. 19662 * 19663 * @type {number} 19664 * @default false 19665 * @param {boolean} value 19666 */ 19667 set needsUpdate( value ) { 19668 19669 if ( value === true ) this.version ++; 19670 19671 } 19672 19673 /** 19674 * Sets the usage of this interleaved buffer. 19675 * 19676 * @param {(StaticDrawUsage|DynamicDrawUsage|StreamDrawUsage|StaticReadUsage|DynamicReadUsage|StreamReadUsage|StaticCopyUsage|DynamicCopyUsage|StreamCopyUsage)} value - The usage to set. 19677 * @return {InterleavedBuffer} A reference to this interleaved buffer. 19678 */ 19679 setUsage( value ) { 19680 19681 this.usage = value; 19682 19683 return this; 19684 19685 } 19686 19687 /** 19688 * Adds a range of data in the data array to be updated on the GPU. 19689 * 19690 * @param {number} start - Position at which to start update. 19691 * @param {number} count - The number of components to update. 19692 */ 19693 addUpdateRange( start, count ) { 19694 19695 this.updateRanges.push( { start, count } ); 19696 19697 } 19698 19699 /** 19700 * Clears the update ranges. 19701 */ 19702 clearUpdateRanges() { 19703 19704 this.updateRanges.length = 0; 19705 19706 } 19707 19708 /** 19709 * Copies the values of the given interleaved buffer to this instance. 19710 * 19711 * @param {InterleavedBuffer} source - The interleaved buffer to copy. 19712 * @return {InterleavedBuffer} A reference to this instance. 19713 */ 19714 copy( source ) { 19715 19716 this.array = new source.array.constructor( source.array ); 19717 this.count = source.count; 19718 this.stride = source.stride; 19719 this.usage = source.usage; 19720 19721 return this; 19722 19723 } 19724 19725 /** 19726 * Copies a vector from the given interleaved buffer to this one. The start 19727 * and destination position in the attribute buffers are represented by the 19728 * given indices. 19729 * 19730 * @param {number} index1 - The destination index into this interleaved buffer. 19731 * @param {InterleavedBuffer} interleavedBuffer - The interleaved buffer to copy from. 19732 * @param {number} index2 - The source index into the given interleaved buffer. 19733 * @return {InterleavedBuffer} A reference to this instance. 19734 */ 19735 copyAt( index1, interleavedBuffer, index2 ) { 19736 19737 index1 *= this.stride; 19738 index2 *= interleavedBuffer.stride; 19739 19740 for ( let i = 0, l = this.stride; i < l; i ++ ) { 19741 19742 this.array[ index1 + i ] = interleavedBuffer.array[ index2 + i ]; 19743 19744 } 19745 19746 return this; 19747 19748 } 19749 19750 /** 19751 * Sets the given array data in the interleaved buffer. 19752 * 19753 * @param {(TypedArray|Array)} value - The array data to set. 19754 * @param {number} [offset=0] - The offset in this interleaved buffer's array. 19755 * @return {InterleavedBuffer} A reference to this instance. 19756 */ 19757 set( value, offset = 0 ) { 19758 19759 this.array.set( value, offset ); 19760 19761 return this; 19762 19763 } 19764 19765 /** 19766 * Returns a new interleaved buffer with copied values from this instance. 19767 * 19768 * @param {Object} [data] - An object with shared array buffers that allows to retain shared structures. 19769 * @return {InterleavedBuffer} A clone of this instance. 19770 */ 19771 clone( data ) { 19772 19773 if ( data.arrayBuffers === undefined ) { 19774 19775 data.arrayBuffers = {}; 19776 19777 } 19778 19779 if ( this.array.buffer._uuid === undefined ) { 19780 19781 this.array.buffer._uuid = generateUUID(); 19782 19783 } 19784 19785 if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) { 19786 19787 data.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer; 19788 19789 } 19790 19791 const array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] ); 19792 19793 const ib = new this.constructor( array, this.stride ); 19794 ib.setUsage( this.usage ); 19795 19796 return ib; 19797 19798 } 19799
vendor: 2,927 bytes, lines 19800-19933
19800 /** 19801 * Sets the given callback function that is executed after the Renderer has transferred 19802 * the array data to the GPU. Can be used to perform clean-up operations after 19803 * the upload when data are not needed anymore on the CPU side. 19804 * 19805 * @param {Function} callback - The `onUpload()` callback. 19806 * @return {InterleavedBuffer} A reference to this instance. 19807 */ 19808 onUpload( callback ) { 19809 19810 this.onUploadCallback = callback; 19811 19812 return this; 19813 19814 } 19815 19816 /** 19817 * Serializes the interleaved buffer into JSON. 19818 * 19819 * @param {Object} [data] - An optional value holding meta information about the serialization. 19820 * @return {Object} A JSON object representing the serialized interleaved buffer. 19821 */ 19822 toJSON( data ) { 19823 19824 if ( data.arrayBuffers === undefined ) { 19825 19826 data.arrayBuffers = {}; 19827 19828 } 19829 19830 // generate UUID for array buffer if necessary 19831 19832 if ( this.array.buffer._uuid === undefined ) { 19833 19834 this.array.buffer._uuid = generateUUID(); 19835 19836 } 19837 19838 if ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) { 19839 19840 data.arrayBuffers[ this.array.buffer._uuid ] = Array.from( new Uint32Array( this.array.buffer ) ); 19841 19842 } 19843 19844 // 19845 19846 return { 19847 uuid: this.uuid, 19848 buffer: this.array.buffer._uuid, 19849 type: this.array.constructor.name, 19850 stride: this.stride 19851 }; 19852 19853 } 19854 19855} 19856 19857const _vector$8 = /*@__PURE__*/ new Vector3(); 19858 19859/** 19860 * An alternative version of a buffer attribute with interleaved data. Interleaved 19861 * attributes share a common interleaved data storage ({@link InterleavedBuffer}) and refer with 19862 * different offsets into the buffer. 19863 */ 19864class InterleavedBufferAttribute { 19865 19866 /** 19867 * Constructs a new interleaved buffer attribute. 19868 * 19869 * @param {InterleavedBuffer} interleavedBuffer - The buffer holding the interleaved data. 19870 * @param {number} itemSize - The item size. 19871 * @param {number} offset - The attribute offset into the buffer. 19872 * @param {boolean} [normalized=false] - Whether the data are normalized or not. 19873 */ 19874 constructor( interleavedBuffer, itemSize, offset, normalized = false ) { 19875 19876 /** 19877 * This flag can be used for type testing. 19878 * 19879 * @type {boolean} 19880 * @readonly 19881 * @default true 19882 */ 19883 this.isInterleavedBufferAttribute = true; 19884 19885 /** 19886 * The name of the buffer attribute. 19887 * 19888 * @type {string} 19889 */ 19890 this.name = ''; 19891 19892 /** 19893 * The buffer holding the interleaved data. 19894 * 19895 * @type {InterleavedBuffer} 19896 */ 19897 this.data = interleavedBuffer; 19898 19899 /** 19900 * The item size, see {@link BufferAttribute#itemSize}. 19901 * 19902 * @type {number} 19903 */ 19904 this.itemSize = itemSize; 19905 19906 /** 19907 * The attribute offset into the buffer. 19908 * 19909 * @type {number} 19910 */ 19911 this.offset = offset; 19912 19913 /** 19914 * Whether the data are normalized or not, see {@link BufferAttribute#normalized} 19915 * 19916 * @type {InterleavedBuffer} 19917 */ 19918 this.normalized = normalized; 19919 19920 } 19921 19922 /** 19923 * The item count of this buffer attribute. 19924 * 19925 * @type {number} 19926 * @readonly 19927 */ 19928 get count() { 19929 19930 return this.data.count; 19931 19932 } 19933
vendor: 10,956 bytes, lines 19934-20398
19934 /** 19935 * The array holding the interleaved buffer attribute data. 19936 * 19937 * @type {TypedArray} 19938 */ 19939 get array() { 19940 19941 return this.data.array; 19942 19943 } 19944 19945 /** 19946 * Flag to indicate that this attribute has changed and should be re-sent to 19947 * the GPU. Set this to `true` when you modify the value of the array. 19948 * 19949 * @type {number} 19950 * @default false 19951 * @param {boolean} value 19952 */ 19953 set needsUpdate( value ) { 19954 19955 this.data.needsUpdate = value; 19956 19957 } 19958 19959 /** 19960 * Applies the given 4x4 matrix to the given attribute. Only works with 19961 * item size `3`. 19962 * 19963 * @param {Matrix4} m - The matrix to apply. 19964 * @return {InterleavedBufferAttribute} A reference to this instance. 19965 */ 19966 applyMatrix4( m ) { 19967 19968 for ( let i = 0, l = this.data.count; i < l; i ++ ) { 19969 19970 _vector$8.fromBufferAttribute( this, i ); 19971 19972 _vector$8.applyMatrix4( m ); 19973 19974 this.setXYZ( i, _vector$8.x, _vector$8.y, _vector$8.z ); 19975 19976 } 19977 19978 return this; 19979 19980 } 19981 19982 /** 19983 * Applies the given 3x3 normal matrix to the given attribute. Only works with 19984 * item size `3`. 19985 * 19986 * @param {Matrix3} m - The normal matrix to apply. 19987 * @return {InterleavedBufferAttribute} A reference to this instance. 19988 */ 19989 applyNormalMatrix( m ) { 19990 19991 for ( let i = 0, l = this.count; i < l; i ++ ) { 19992 19993 _vector$8.fromBufferAttribute( this, i ); 19994 19995 _vector$8.applyNormalMatrix( m ); 19996 19997 this.setXYZ( i, _vector$8.x, _vector$8.y, _vector$8.z ); 19998 19999 } 20000 20001 return this; 20002 20003 } 20004 20005 /** 20006 * Applies the given 4x4 matrix to the given attribute. Only works with 20007 * item size `3` and with direction vectors. 20008 * 20009 * @param {Matrix4} m - The matrix to apply. 20010 * @return {InterleavedBufferAttribute} A reference to this instance. 20011 */ 20012 transformDirection( m ) { 20013 20014 for ( let i = 0, l = this.count; i < l; i ++ ) { 20015 20016 _vector$8.fromBufferAttribute( this, i ); 20017 20018 _vector$8.transformDirection( m ); 20019 20020 this.setXYZ( i, _vector$8.x, _vector$8.y, _vector$8.z ); 20021 20022 } 20023 20024 return this; 20025 20026 } 20027 20028 /** 20029 * Returns the given component of the vector at the given index. 20030 * 20031 * @param {number} index - The index into the buffer attribute. 20032 * @param {number} component - The component index. 20033 * @return {number} The returned value. 20034 */ 20035 getComponent( index, component ) { 20036 20037 let value = this.array[ index * this.data.stride + this.offset + component ]; 20038 20039 if ( this.normalized ) value = denormalize( value, this.array ); 20040 20041 return value; 20042 20043 } 20044 20045 /** 20046 * Sets the given value to the given component of the vector at the given index. 20047 * 20048 * @param {number} index - The index into the buffer attribute. 20049 * @param {number} component - The component index. 20050 * @param {number} value - The value to set. 20051 * @return {InterleavedBufferAttribute} A reference to this instance. 20052 */ 20053 setComponent( index, component, value ) { 20054 20055 if ( this.normalized ) value = normalize( value, this.array ); 20056 20057 this.data.array[ index * this.data.stride + this.offset + component ] = value; 20058 20059 return this; 20060 20061 } 20062 20063 /** 20064 * Sets the x component of the vector at the given index. 20065 * 20066 * @param {number} index - The index into the buffer attribute. 20067 * @param {number} x - The value to set. 20068 * @return {InterleavedBufferAttribute} A reference to this instance. 20069 */ 20070 setX( index, x ) { 20071 20072 if ( this.normalized ) x = normalize( x, this.array ); 20073 20074 this.data.array[ index * this.data.stride + this.offset ] = x; 20075 20076 return this; 20077 20078 } 20079 20080 /** 20081 * Sets the y component of the vector at the given index. 20082 * 20083 * @param {number} index - The index into the buffer attribute. 20084 * @param {number} y - The value to set. 20085 * @return {InterleavedBufferAttribute} A reference to this instance. 20086 */ 20087 setY( index, y ) { 20088 20089 if ( this.normalized ) y = normalize( y, this.array ); 20090 20091 this.data.array[ index * this.data.stride + this.offset + 1 ] = y; 20092 20093 return this; 20094 20095 } 20096 20097 /** 20098 * Sets the z component of the vector at the given index. 20099 * 20100 * @param {number} index - The index into the buffer attribute. 20101 * @param {number} z - The value to set. 20102 * @return {InterleavedBufferAttribute} A reference to this instance. 20103 */ 20104 setZ( index, z ) { 20105 20106 if ( this.normalized ) z = normalize( z, this.array ); 20107 20108 this.data.array[ index * this.data.stride + this.offset + 2 ] = z; 20109 20110 return this; 20111 20112 } 20113 20114 /** 20115 * Sets the w component of the vector at the given index. 20116 * 20117 * @param {number} index - The index into the buffer attribute. 20118 * @param {number} w - The value to set. 20119 * @return {InterleavedBufferAttribute} A reference to this instance. 20120 */ 20121 setW( index, w ) { 20122 20123 if ( this.normalized ) w = normalize( w, this.array ); 20124 20125 this.data.array[ index * this.data.stride + this.offset + 3 ] = w; 20126 20127 return this; 20128 20129 } 20130 20131 /** 20132 * Returns the x component of the vector at the given index. 20133 * 20134 * @param {number} index - The index into the buffer attribute. 20135 * @return {number} The x component. 20136 */ 20137 getX( index ) { 20138 20139 let x = this.data.array[ index * this.data.stride + this.offset ]; 20140 20141 if ( this.normalized ) x = denormalize( x, this.array ); 20142 20143 return x; 20144 20145 } 20146 20147 /** 20148 * Returns the y component of the vector at the given index. 20149 * 20150 * @param {number} index - The index into the buffer attribute. 20151 * @return {number} The y component. 20152 */ 20153 getY( index ) { 20154 20155 let y = this.data.array[ index * this.data.stride + this.offset + 1 ]; 20156 20157 if ( this.normalized ) y = denormalize( y, this.array ); 20158 20159 return y; 20160 20161 } 20162 20163 /** 20164 * Returns the z component of the vector at the given index. 20165 * 20166 * @param {number} index - The index into the buffer attribute. 20167 * @return {number} The z component. 20168 */ 20169 getZ( index ) { 20170 20171 let z = this.data.array[ index * this.data.stride + this.offset + 2 ]; 20172 20173 if ( this.normalized ) z = denormalize( z, this.array ); 20174 20175 return z; 20176 20177 } 20178 20179 /** 20180 * Returns the w component of the vector at the given index. 20181 * 20182 * @param {number} index - The index into the buffer attribute. 20183 * @return {number} The w component. 20184 */ 20185 getW( index ) { 20186 20187 let w = this.data.array[ index * this.data.stride + this.offset + 3 ]; 20188 20189 if ( this.normalized ) w = denormalize( w, this.array ); 20190 20191 return w; 20192 20193 } 20194 20195 /** 20196 * Sets the x and y component of the vector at the given index. 20197 * 20198 * @param {number} index - The index into the buffer attribute. 20199 * @param {number} x - The value for the x component to set. 20200 * @param {number} y - The value for the y component to set. 20201 * @return {InterleavedBufferAttribute} A reference to this instance. 20202 */ 20203 setXY( index, x, y ) { 20204 20205 index = index * this.data.stride + this.offset; 20206 20207 if ( this.normalized ) { 20208 20209 x = normalize( x, this.array ); 20210 y = normalize( y, this.array ); 20211 20212 } 20213 20214 this.data.array[ index + 0 ] = x; 20215 this.data.array[ index + 1 ] = y; 20216 20217 return this; 20218 20219 } 20220 20221 /** 20222 * Sets the x, y and z component of the vector at the given index. 20223 * 20224 * @param {number} index - The index into the buffer attribute. 20225 * @param {number} x - The value for the x component to set. 20226 * @param {number} y - The value for the y component to set. 20227 * @param {number} z - The value for the z component to set. 20228 * @return {InterleavedBufferAttribute} A reference to this instance. 20229 */ 20230 setXYZ( index, x, y, z ) { 20231 20232 index = index * this.data.stride + this.offset; 20233 20234 if ( this.normalized ) { 20235 20236 x = normalize( x, this.array ); 20237 y = normalize( y, this.array ); 20238 z = normalize( z, this.array ); 20239 20240 } 20241 20242 this.data.array[ index + 0 ] = x; 20243 this.data.array[ index + 1 ] = y; 20244 this.data.array[ index + 2 ] = z; 20245 20246 return this; 20247 20248 } 20249 20250 /** 20251 * Sets the x, y, z and w component of the vector at the given index. 20252 * 20253 * @param {number} index - The index into the buffer attribute. 20254 * @param {number} x - The value for the x component to set. 20255 * @param {number} y - The value for the y component to set. 20256 * @param {number} z - The value for the z component to set. 20257 * @param {number} w - The value for the w component to set. 20258 * @return {InterleavedBufferAttribute} A reference to this instance. 20259 */ 20260 setXYZW( index, x, y, z, w ) { 20261 20262 index = index * this.data.stride + this.offset; 20263 20264 if ( this.normalized ) { 20265 20266 x = normalize( x, this.array ); 20267 y = normalize( y, this.array ); 20268 z = normalize( z, this.array ); 20269 w = normalize( w, this.array ); 20270 20271 } 20272 20273 this.data.array[ index + 0 ] = x; 20274 this.data.array[ index + 1 ] = y; 20275 this.data.array[ index + 2 ] = z; 20276 this.data.array[ index + 3 ] = w; 20277 20278 return this; 20279 20280 } 20281 20282 /** 20283 * Returns a new buffer attribute with copied values from this instance. 20284 * 20285 * If no parameter is provided, cloning an interleaved buffer attribute will de-interleave buffer data. 20286 * 20287 * @param {Object} [data] - An object with interleaved buffers that allows to retain the interleaved property. 20288 * @return {BufferAttribute|InterleavedBufferAttribute} A clone of this instance. 20289 */ 20290 clone( data ) { 20291 20292 if ( data === undefined ) { 20293 20294 log( 'InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will de-interleave buffer data.' ); 20295 20296 const array = []; 20297 20298 for ( let i = 0; i < this.count; i ++ ) { 20299 20300 const index = i * this.data.stride + this.offset; 20301 20302 for ( let j = 0; j < this.itemSize; j ++ ) { 20303 20304 array.push( this.data.array[ index + j ] ); 20305 20306 } 20307 20308 } 20309 20310 return new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized ); 20311 20312 } else { 20313 20314 if ( data.interleavedBuffers === undefined ) { 20315 20316 data.interleavedBuffers = {}; 20317 20318 } 20319 20320 if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { 20321 20322 data.interleavedBuffers[ this.data.uuid ] = this.data.clone( data ); 20323 20324 } 20325 20326 return new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized ); 20327 20328 } 20329 20330 } 20331 20332 /** 20333 * Serializes the buffer attribute into JSON. 20334 * 20335 * If no parameter is provided, cloning an interleaved buffer attribute will de-interleave buffer data. 20336 * 20337 * @param {Object} [data] - An optional value holding meta information about the serialization. 20338 * @return {Object} A JSON object representing the serialized buffer attribute. 20339 */ 20340 toJSON( data ) { 20341 20342 if ( data === undefined ) { 20343 20344 log( 'InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will de-interleave buffer data.' ); 20345 20346 const array = []; 20347 20348 for ( let i = 0; i < this.count; i ++ ) { 20349 20350 const index = i * this.data.stride + this.offset; 20351 20352 for ( let j = 0; j < this.itemSize; j ++ ) { 20353 20354 array.push( this.data.array[ index + j ] ); 20355 20356 } 20357 20358 } 20359 20360 // de-interleave data and save it as an ordinary buffer attribute for now 20361 20362 return { 20363 itemSize: this.itemSize, 20364 type: this.array.constructor.name, 20365 array: array, 20366 normalized: this.normalized 20367 }; 20368 20369 } else { 20370 20371 // save as true interleaved attribute 20372 20373 if ( data.interleavedBuffers === undefined ) { 20374 20375 data.interleavedBuffers = {}; 20376 20377 } 20378 20379 if ( data.interleavedBuffers[ this.data.uuid ] === undefined ) { 20380 20381 data.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data ); 20382 20383 } 20384 20385 return { 20386 isInterleavedBufferAttribute: true, 20387 itemSize: this.itemSize, 20388 data: this.data.uuid, 20389 offset: this.offset, 20390 normalized: this.normalized 20391 }; 20392 20393 } 20394 20395 } 20396 20397} 20398
20399let _materialId = 0; 20400 20401/** 20402 * Abstract base class for materials. 20403 * 20404 * Materials define the appearance of renderable 3D objects. 20405 * 20406 * @abstract 20407 * @augments EventDispatcher 20408 */
vendor: 8,504 bytes, lines 20409-20689
20409class Material extends EventDispatcher { 20410 20411 /** 20412 * Constructs a new material. 20413 */ 20414 constructor() { 20415 20416 super(); 20417 20418 /** 20419 * This flag can be used for type testing. 20420 * 20421 * @type {boolean} 20422 * @readonly 20423 * @default true 20424 */ 20425 this.isMaterial = true; 20426 20427 /** 20428 * The ID of the material. 20429 * 20430 * @name Material#id 20431 * @type {number} 20432 * @readonly 20433 */ 20434 Object.defineProperty( this, 'id', { value: _materialId ++ } ); 20435 20436 /** 20437 * The UUID of the material. 20438 * 20439 * @type {string} 20440 * @readonly 20441 */ 20442 this.uuid = generateUUID(); 20443 20444 /** 20445 * The name of the material. 20446 * 20447 * @type {string} 20448 */ 20449 this.name = ''; 20450 20451 /** 20452 * The type property is used for detecting the object type 20453 * in context of serialization/deserialization. 20454 * 20455 * @type {string} 20456 * @readonly 20457 */ 20458 this.type = 'Material'; 20459 20460 /** 20461 * Defines the blending type of the material. 20462 * 20463 * It must be set to `CustomBlending` if custom blending properties like 20464 * {@link Material#blendSrc}, {@link Material#blendDst} or {@link Material#blendEquation} 20465 * should have any effect. 20466 * 20467 * @type {(NoBlending|NormalBlending|AdditiveBlending|SubtractiveBlending|MultiplyBlending|CustomBlending)} 20468 * @default NormalBlending 20469 */ 20470 this.blending = NormalBlending; 20471 20472 /** 20473 * Defines which side of faces will be rendered - front, back or both. 20474 * 20475 * @type {(FrontSide|BackSide|DoubleSide)} 20476 * @default FrontSide 20477 */ 20478 this.side = FrontSide; 20479 20480 /** 20481 * If set to `true`, vertex colors should be used. 20482 * 20483 * The engine supports RGB and RGBA vertex colors depending on whether a three (RGB) or 20484 * four (RGBA) component color buffer attribute is used. 20485 * 20486 * @type {boolean} 20487 * @default false 20488 */ 20489 this.vertexColors = false; 20490 20491 /** 20492 * Defines how transparent the material is. 20493 * A value of `0.0` indicates fully transparent, `1.0` is fully opaque. 20494 * 20495 * If the {@link Material#transparent} is not set to `true`, 20496 * the material will remain fully opaque and this value will only affect its color. 20497 * 20498 * @type {number} 20499 * @default 1 20500 */ 20501 this.opacity = 1; 20502 20503 /** 20504 * Defines whether this material is transparent. This has an effect on 20505 * rendering as transparent objects need special treatment and are rendered 20506 * after non-transparent objects. 20507 * 20508 * When set to true, the extent to which the material is transparent is 20509 * controlled by {@link Material#opacity}. 20510 * 20511 * @type {boolean} 20512 * @default false 20513 */ 20514 this.transparent = false; 20515 20516 /** 20517 * Enables alpha hashed transparency, an alternative to {@link Material#transparent} or 20518 * {@link Material#alphaTest}. The material will not be rendered if opacity is lower than 20519 * a random threshold. Randomization introduces some grain or noise, but approximates alpha 20520 * blending without the associated problems of sorting. Using TAA can reduce the resulting noise. 20521 * 20522 * @type {boolean} 20523 * @default false 20524 */ 20525 this.alphaHash = false; 20526 20527 /** 20528 * Defines the blending source factor. 20529 * 20530 * @type {(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)} 20531 * @default SrcAlphaFactor 20532 */ 20533 this.blendSrc = SrcAlphaFactor; 20534 20535 /** 20536 * Defines the blending destination factor. 20537 * 20538 * @type {(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)} 20539 * @default OneMinusSrcAlphaFactor 20540 */ 20541 this.blendDst = OneMinusSrcAlphaFactor; 20542 20543 /** 20544 * Defines the blending equation. 20545 * 20546 * @type {(AddEquation|SubtractEquation|ReverseSubtractEquation|MinEquation|MaxEquation)} 20547 * @default AddEquation 20548 */ 20549 this.blendEquation = AddEquation; 20550 20551 /** 20552 * Defines the blending source alpha factor. 20553 * 20554 * @type {?(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)} 20555 * @default null 20556 */ 20557 this.blendSrcAlpha = null; 20558 20559 /** 20560 * Defines the blending destination alpha factor. 20561 * 20562 * @type {?(ZeroFactor|OneFactor|SrcColorFactor|OneMinusSrcColorFactor|SrcAlphaFactor|OneMinusSrcAlphaFactor|DstAlphaFactor|OneMinusDstAlphaFactor|DstColorFactor|OneMinusDstColorFactor|SrcAlphaSaturateFactor|ConstantColorFactor|OneMinusConstantColorFactor|ConstantAlphaFactor|OneMinusConstantAlphaFactor)} 20563 * @default null 20564 */ 20565 this.blendDstAlpha = null; 20566 20567 /** 20568 * Defines the blending equation of the alpha channel. 20569 * 20570 * @type {?(AddEquation|SubtractEquation|ReverseSubtractEquation|MinEquation|MaxEquation)} 20571 * @default null 20572 */ 20573 this.blendEquationAlpha = null; 20574 20575 /** 20576 * Represents the RGB values of the constant blend color. 20577 * 20578 * This property has only an effect when using custom blending with `ConstantColor` or `OneMinusConstantColor`. 20579 * 20580 * @type {Color} 20581 * @default (0,0,0) 20582 */ 20583 this.blendColor = new Color( 0, 0, 0 ); 20584 20585 /** 20586 * Represents the alpha value of the constant blend color. 20587 * 20588 * This property has only an effect when using custom blending with `ConstantAlpha` or `OneMinusConstantAlpha`. 20589 * 20590 * @type {number} 20591 * @default 0 20592 */ 20593 this.blendAlpha = 0; 20594 20595 /** 20596 * Defines the depth function. 20597 * 20598 * @type {(NeverDepth|AlwaysDepth|LessDepth|LessEqualDepth|EqualDepth|GreaterEqualDepth|GreaterDepth|NotEqualDepth)} 20599 * @default LessEqualDepth 20600 */ 20601 this.depthFunc = LessEqualDepth; 20602 20603 /** 20604 * Whether to have depth test enabled when rendering this material. 20605 * When the depth test is disabled, the depth write will also be implicitly disabled. 20606 * 20607 * @type {boolean} 20608 * @default true 20609 */ 20610 this.depthTest = true; 20611 20612 /** 20613 * Whether rendering this material has any effect on the depth buffer. 20614 * 20615 * When drawing 2D overlays it can be useful to disable the depth writing in 20616 * order to layer several things together without creating z-index artifacts. 20617 * 20618 * @type {boolean} 20619 * @default true 20620 */ 20621 this.depthWrite = true; 20622 20623 /** 20624 * The bit mask to use when writing to the stencil buffer. 20625 * 20626 * @type {number} 20627 * @default 0xff 20628 */ 20629 this.stencilWriteMask = 0xff; 20630 20631 /** 20632 * The stencil comparison function to use. 20633 * 20634 * @type {NeverStencilFunc|LessStencilFunc|EqualStencilFunc|LessEqualStencilFunc|GreaterStencilFunc|NotEqualStencilFunc|GreaterEqualStencilFunc|AlwaysStencilFunc} 20635 * @default AlwaysStencilFunc 20636 */ 20637 this.stencilFunc = AlwaysStencilFunc; 20638 20639 /** 20640 * The value to use when performing stencil comparisons or stencil operations. 20641 * 20642 * @type {number} 20643 * @default 0 20644 */ 20645 this.stencilRef = 0; 20646 20647 /** 20648 * The bit mask to use when comparing against the stencil buffer. 20649 * 20650 * @type {number} 20651 * @default 0xff 20652 */ 20653 this.stencilFuncMask = 0xff; 20654 20655 /** 20656 * Which stencil operation to perform when the comparison function returns `false`. 20657 * 20658 * @type {ZeroStencilOp|KeepStencilOp|ReplaceStencilOp|IncrementStencilOp|DecrementStencilOp|IncrementWrapStencilOp|DecrementWrapStencilOp|InvertStencilOp} 20659 * @default KeepStencilOp 20660 */ 20661 this.stencilFail = KeepStencilOp; 20662 20663 /** 20664 * Which stencil operation to perform when the comparison function returns 20665 * `true` but the depth test fails. 20666 * 20667 * @type {ZeroStencilOp|KeepStencilOp|ReplaceStencilOp|IncrementStencilOp|DecrementStencilOp|IncrementWrapStencilOp|DecrementWrapStencilOp|InvertStencilOp} 20668 * @default KeepStencilOp 20669 */ 20670 this.stencilZFail = KeepStencilOp; 20671 20672 /** 20673 * Which stencil operation to perform when the comparison function returns 20674 * `true` and the depth test passes. 20675 * 20676 * @type {ZeroStencilOp|KeepStencilOp|ReplaceStencilOp|IncrementStencilOp|DecrementStencilOp|IncrementWrapStencilOp|DecrementWrapStencilOp|InvertStencilOp} 20677 * @default KeepStencilOp 20678 */ 20679 this.stencilZPass = KeepStencilOp; 20680 20681 /** 20682 * Whether stencil operations are performed against the stencil buffer. In 20683 * order to perform writes or comparisons against the stencil buffer this 20684 * value must be `true`. 20685 * 20686 * @type {boolean} 20687 * @default false 20688 */ 20689 this.stencilWrite = false;
vendor: 5,079 bytes, lines 20690-20870
20690 20691 /** 20692 * User-defined clipping planes specified as THREE.Plane objects in world 20693 * space. These planes apply to the objects this material is attached to. 20694 * Points in space whose signed distance to the plane is negative are clipped 20695 * (not rendered). This requires {@link WebGLRenderer#localClippingEnabled} to 20696 * be `true`. 20697 * 20698 * @type {?Array<Plane>} 20699 * @default null 20700 */ 20701 this.clippingPlanes = null; 20702 20703 /** 20704 * Changes the behavior of clipping planes so that only their intersection is 20705 * clipped, rather than their union. 20706 * 20707 * @type {boolean} 20708 * @default false 20709 */ 20710 this.clipIntersection = false; 20711 20712 /** 20713 * Defines whether to clip shadows according to the clipping planes specified 20714 * on this material. 20715 * 20716 * @type {boolean} 20717 * @default false 20718 */ 20719 this.clipShadows = false; 20720 20721 /** 20722 * Defines which side of faces cast shadows. If `null`, the side casting shadows 20723 * is determined as follows: 20724 * 20725 * - When {@link Material#side} is set to `FrontSide`, the back side cast shadows. 20726 * - When {@link Material#side} is set to `BackSide`, the front side cast shadows. 20727 * - When {@link Material#side} is set to `DoubleSide`, both sides cast shadows. 20728 * 20729 * @type {?(FrontSide|BackSide|DoubleSide)} 20730 * @default null 20731 */ 20732 this.shadowSide = null; 20733 20734 /** 20735 * Whether to render the material's color. 20736 * 20737 * This can be used in conjunction with {@link Object3D#renderOder} to create invisible 20738 * objects that occlude other objects. 20739 * 20740 * @type {boolean} 20741 * @default true 20742 */ 20743 this.colorWrite = true; 20744 20745 /** 20746 * Override the renderer's default precision for this material. 20747 * 20748 * @type {?('highp'|'mediump'|'lowp')} 20749 * @default null 20750 */ 20751 this.precision = null; 20752 20753 /** 20754 * Whether to use polygon offset or not. When enabled, each fragment's depth value will 20755 * be offset after it is interpolated from the depth values of the appropriate vertices. 20756 * The offset is added before the depth test is performed and before the value is written 20757 * into the depth buffer. 20758 * 20759 * Can be useful for rendering hidden-line images, for applying decals to surfaces, and for 20760 * rendering solids with highlighted edges. 20761 * 20762 * @type {boolean} 20763 * @default false 20764 */ 20765 this.polygonOffset = false; 20766 20767 /** 20768 * Specifies a scale factor that is used to create a variable depth offset for each polygon. 20769 * 20770 * @type {number} 20771 * @default 0 20772 */ 20773 this.polygonOffsetFactor = 0; 20774 20775 /** 20776 * Is multiplied by an implementation-specific value to create a constant depth offset. 20777 * 20778 * @type {number} 20779 * @default 0 20780 */ 20781 this.polygonOffsetUnits = 0; 20782 20783 /** 20784 * Whether to apply dithering to the color to remove the appearance of banding. 20785 * 20786 * @type {boolean} 20787 * @default false 20788 */ 20789 this.dithering = false; 20790 20791 /** 20792 * Whether alpha to coverage should be enabled or not. Can only be used with MSAA-enabled contexts 20793 * (meaning when the renderer was created with *antialias* parameter set to `true`). Enabling this 20794 * will smooth aliasing on clip plane edges and alphaTest-clipped edges. 20795 * 20796 * @type {boolean} 20797 * @default false 20798 */ 20799 this.alphaToCoverage = false; 20800 20801 /** 20802 * Whether to premultiply the alpha (transparency) value. 20803 * 20804 * @type {boolean} 20805 * @default false 20806 */ 20807 this.premultipliedAlpha = false; 20808 20809 /** 20810 * Whether double-sided, transparent objects should be rendered with a single pass or not. 20811 * 20812 * The engine renders double-sided, transparent objects with two draw calls (back faces first, 20813 * then front faces) to mitigate transparency artifacts. There are scenarios however where this 20814 * approach produces no quality gains but still doubles draw calls e.g. when rendering flat 20815 * vegetation like grass sprites. In these cases, set the `forceSinglePass` flag to `true` to 20816 * disable the two pass rendering to avoid performance issues. 20817 * 20818 * @type {boolean} 20819 * @default false 20820 */ 20821 this.forceSinglePass = false; 20822 20823 /** 20824 * Whether it's possible to override the material with {@link Scene#overrideMaterial} or not. 20825 * 20826 * @type {boolean} 20827 * @default true 20828 */ 20829 this.allowOverride = true; 20830 20831 /** 20832 * Defines whether 3D objects using this material are visible. 20833 * 20834 * @type {boolean} 20835 * @default true 20836 */ 20837 this.visible = true; 20838 20839 /** 20840 * Defines whether this material is tone mapped according to the renderer's tone mapping setting. 20841 * 20842 * It is ignored when rendering to a render target or using post processing or when using 20843 * `WebGPURenderer`. In all these cases, all materials are honored by tone mapping. 20844 * 20845 * @type {boolean} 20846 * @default true 20847 */ 20848 this.toneMapped = true; 20849 20850 /** 20851 * An object that can be used to store custom data about the Material. It 20852 * should not hold references to functions as these will not be cloned. 20853 * 20854 * @type {Object} 20855 */ 20856 this.userData = {}; 20857 20858 /** 20859 * This starts at `0` and counts how many times {@link Material#needsUpdate} is set to `true`. 20860 * 20861 * @type {number} 20862 * @readonly 20863 * @default 0 20864 */ 20865 this.version = 0; 20866 20867 this._alphaTest = 0; 20868 20869 } 20870
vendor: 17,626 bytes, lines 20871-21407
20871 /** 20872 * Sets the alpha value to be used when running an alpha test. The material 20873 * will not be rendered if the opacity is lower than this value. 20874 * 20875 * @type {number} 20876 * @readonly 20877 * @default 0 20878 */ 20879 get alphaTest() { 20880 20881 return this._alphaTest; 20882 20883 } 20884 20885 set alphaTest( value ) { 20886 20887 if ( this._alphaTest > 0 !== value > 0 ) { 20888 20889 this.version ++; 20890 20891 } 20892 20893 this._alphaTest = value; 20894 20895 } 20896 20897 /** 20898 * An optional callback that is executed immediately before the material is used to render a 3D object. 20899 * 20900 * This method can only be used when rendering with {@link WebGLRenderer}. 20901 * 20902 * @param {WebGLRenderer} renderer - The renderer. 20903 * @param {Scene} scene - The scene. 20904 * @param {Camera} camera - The camera that is used to render the scene. 20905 * @param {BufferGeometry} geometry - The 3D object's geometry. 20906 * @param {Object3D} object - The 3D object. 20907 * @param {Object} group - The geometry group data. 20908 */ 20909 onBeforeRender( /* renderer, scene, camera, geometry, object, group */ ) {} 20910 20911 /** 20912 * An optional callback that is executed immediately before the shader 20913 * program is compiled. This function is called with the shader source code 20914 * as a parameter. Useful for the modification of built-in materials. 20915 * 20916 * This method can only be used when rendering with {@link WebGLRenderer}. The 20917 * recommended approach when customizing materials is to use `WebGPURenderer` with the new 20918 * Node Material system and [TSL](https://github.com/mrdoob/three.js/wiki/Three.js-Shading-Language). 20919 * 20920 * @param {{vertexShader:string,fragmentShader:string,uniforms:Object}} shaderobject - The object holds the uniforms and the vertex and fragment shader source. 20921 * @param {WebGLRenderer} renderer - A reference to the renderer. 20922 */ 20923 onBeforeCompile( /* shaderobject, renderer */ ) {} 20924 20925 /** 20926 * In case {@link Material#onBeforeCompile} is used, this callback can be used to identify 20927 * values of settings used in `onBeforeCompile()`, so three.js can reuse a cached 20928 * shader or recompile the shader for this material as needed. 20929 * 20930 * This method can only be used when rendering with {@link WebGLRenderer}. 20931 * 20932 * @return {string} The custom program cache key. 20933 */ 20934 customProgramCacheKey() { 20935 20936 return this.onBeforeCompile.toString(); 20937 20938 } 20939 20940 /** 20941 * This method can be used to set default values from parameter objects. 20942 * It is a generic implementation so it can be used with different types 20943 * of materials. 20944 * 20945 * @param {Object} [values] - The material values to set. 20946 */ 20947 setValues( values ) { 20948 20949 if ( values === undefined ) return; 20950 20951 for ( const key in values ) { 20952 20953 const newValue = values[ key ]; 20954 20955 if ( newValue === undefined ) { 20956 20957 warn( `Material: parameter '${ key }' has value of undefined.` ); 20958 continue; 20959 20960 } 20961 20962 const currentValue = this[ key ]; 20963 20964 if ( currentValue === undefined ) { 20965 20966 warn( `Material: '${ key }' is not a property of THREE.${ this.type }.` ); 20967 continue; 20968 20969 } 20970 20971 if ( currentValue && currentValue.isColor ) { 20972 20973 currentValue.set( newValue ); 20974 20975 } else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) { 20976 20977 currentValue.copy( newValue ); 20978 20979 } else { 20980 20981 this[ key ] = newValue; 20982 20983 } 20984 20985 } 20986 20987 } 20988 20989 /** 20990 * Serializes the material into JSON. 20991 * 20992 * @param {?(Object|string)} meta - An optional value holding meta information about the serialization. 20993 * @return {Object} A JSON object representing the serialized material. 20994 * @see {@link ObjectLoader#parse} 20995 */ 20996 toJSON( meta ) { 20997 20998 const isRootObject = ( meta === undefined || typeof meta === 'string' ); 20999 21000 if ( isRootObject ) { 21001 21002 meta = { 21003 textures: {}, 21004 images: {} 21005 }; 21006 21007 } 21008 21009 const data = { 21010 metadata: { 21011 version: 4.7, 21012 type: 'Material', 21013 generator: 'Material.toJSON' 21014 } 21015 }; 21016 21017 // standard Material serialization 21018 data.uuid = this.uuid; 21019 data.type = this.type; 21020 21021 if ( this.name !== '' ) data.name = this.name; 21022 21023 if ( this.color && this.color.isColor ) data.color = this.color.getHex(); 21024 21025 if ( this.roughness !== undefined ) data.roughness = this.roughness; 21026 if ( this.metalness !== undefined ) data.metalness = this.metalness; 21027 21028 if ( this.sheen !== undefined ) data.sheen = this.sheen; 21029 if ( this.sheenColor && this.sheenColor.isColor ) data.sheenColor = this.sheenColor.getHex(); 21030 if ( this.sheenRoughness !== undefined ) data.sheenRoughness = this.sheenRoughness; 21031 if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex(); 21032 if ( this.emissiveIntensity !== undefined && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity; 21033 21034 if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex(); 21035 if ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity; 21036 if ( this.specularColor && this.specularColor.isColor ) data.specularColor = this.specularColor.getHex(); 21037 if ( this.shininess !== undefined ) data.shininess = this.shininess; 21038 if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat; 21039 if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness; 21040 21041 if ( this.clearcoatMap && this.clearcoatMap.isTexture ) { 21042 21043 data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid; 21044 21045 } 21046 21047 if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) { 21048 21049 data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid; 21050 21051 } 21052 21053 if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) { 21054 21055 data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid; 21056 data.clearcoatNormalScale = this.clearcoatNormalScale.toArray(); 21057 21058 } 21059 21060 if ( this.sheenColorMap && this.sheenColorMap.isTexture ) { 21061 21062 data.sheenColorMap = this.sheenColorMap.toJSON( meta ).uuid; 21063 21064 } 21065 21066 if ( this.sheenRoughnessMap && this.sheenRoughnessMap.isTexture ) { 21067 21068 data.sheenRoughnessMap = this.sheenRoughnessMap.toJSON( meta ).uuid; 21069 21070 } 21071 21072 if ( this.dispersion !== undefined ) data.dispersion = this.dispersion; 21073 21074 if ( this.iridescence !== undefined ) data.iridescence = this.iridescence; 21075 if ( this.iridescenceIOR !== undefined ) data.iridescenceIOR = this.iridescenceIOR; 21076 if ( this.iridescenceThicknessRange !== undefined ) data.iridescenceThicknessRange = this.iridescenceThicknessRange; 21077 21078 if ( this.iridescenceMap && this.iridescenceMap.isTexture ) { 21079 21080 data.iridescenceMap = this.iridescenceMap.toJSON( meta ).uuid; 21081 21082 } 21083 21084 if ( this.iridescenceThicknessMap && this.iridescenceThicknessMap.isTexture ) { 21085 21086 data.iridescenceThicknessMap = this.iridescenceThicknessMap.toJSON( meta ).uuid; 21087 21088 } 21089 21090 if ( this.anisotropy !== undefined ) data.anisotropy = this.anisotropy; 21091 if ( this.anisotropyRotation !== undefined ) data.anisotropyRotation = this.anisotropyRotation; 21092 21093 if ( this.anisotropyMap && this.anisotropyMap.isTexture ) { 21094 21095 data.anisotropyMap = this.anisotropyMap.toJSON( meta ).uuid; 21096 21097 } 21098 21099 if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid; 21100 if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid; 21101 if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid; 21102 21103 if ( this.lightMap && this.lightMap.isTexture ) { 21104 21105 data.lightMap = this.lightMap.toJSON( meta ).uuid; 21106 data.lightMapIntensity = this.lightMapIntensity; 21107 21108 } 21109 21110 if ( this.aoMap && this.aoMap.isTexture ) { 21111 21112 data.aoMap = this.aoMap.toJSON( meta ).uuid; 21113 data.aoMapIntensity = this.aoMapIntensity; 21114 21115 } 21116 21117 if ( this.bumpMap && this.bumpMap.isTexture ) { 21118 21119 data.bumpMap = this.bumpMap.toJSON( meta ).uuid; 21120 data.bumpScale = this.bumpScale; 21121 21122 } 21123 21124 if ( this.normalMap && this.normalMap.isTexture ) { 21125 21126 data.normalMap = this.normalMap.toJSON( meta ).uuid; 21127 data.normalMapType = this.normalMapType; 21128 data.normalScale = this.normalScale.toArray(); 21129 21130 } 21131 21132 if ( this.displacementMap && this.displacementMap.isTexture ) { 21133 21134 data.displacementMap = this.displacementMap.toJSON( meta ).uuid; 21135 data.displacementScale = this.displacementScale; 21136 data.displacementBias = this.displacementBias; 21137 21138 } 21139 21140 if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid; 21141 if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid; 21142 21143 if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid; 21144 if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid; 21145 if ( this.specularIntensityMap && this.specularIntensityMap.isTexture ) data.specularIntensityMap = this.specularIntensityMap.toJSON( meta ).uuid; 21146 if ( this.specularColorMap && this.specularColorMap.isTexture ) data.specularColorMap = this.specularColorMap.toJSON( meta ).uuid; 21147 21148 if ( this.envMap && this.envMap.isTexture ) { 21149 21150 data.envMap = this.envMap.toJSON( meta ).uuid; 21151 21152 if ( this.combine !== undefined ) data.combine = this.combine; 21153 21154 } 21155 21156 if ( this.envMapRotation !== undefined ) data.envMapRotation = this.envMapRotation.toArray(); 21157 if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity; 21158 if ( this.reflectivity !== undefined ) data.reflectivity = this.reflectivity; 21159 if ( this.refractionRatio !== undefined ) data.refractionRatio = this.refractionRatio; 21160 21161 if ( this.gradientMap && this.gradientMap.isTexture ) { 21162 21163 data.gradientMap = this.gradientMap.toJSON( meta ).uuid; 21164 21165 } 21166 21167 if ( this.transmission !== undefined ) data.transmission = this.transmission; 21168 if ( this.transmissionMap && this.transmissionMap.isTexture ) data.transmissionMap = this.transmissionMap.toJSON( meta ).uuid; 21169 if ( this.thickness !== undefined ) data.thickness = this.thickness; 21170 if ( this.thicknessMap && this.thicknessMap.isTexture ) data.thicknessMap = this.thicknessMap.toJSON( meta ).uuid; 21171 if ( this.attenuationDistance !== undefined && this.attenuationDistance !== Infinity ) data.attenuationDistance = this.attenuationDistance; 21172 if ( this.attenuationColor !== undefined ) data.attenuationColor = this.attenuationColor.getHex(); 21173 21174 if ( this.size !== undefined ) data.size = this.size; 21175 if ( this.shadowSide !== null ) data.shadowSide = this.shadowSide; 21176 if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation; 21177 21178 if ( this.blending !== NormalBlending ) data.blending = this.blending; 21179 if ( this.side !== FrontSide ) data.side = this.side; 21180 if ( this.vertexColors === true ) data.vertexColors = true; 21181 21182 if ( this.opacity < 1 ) data.opacity = this.opacity; 21183 if ( this.transparent === true ) data.transparent = true; 21184 21185 if ( this.blendSrc !== SrcAlphaFactor ) data.blendSrc = this.blendSrc; 21186 if ( this.blendDst !== OneMinusSrcAlphaFactor ) data.blendDst = this.blendDst; 21187 if ( this.blendEquation !== AddEquation ) data.blendEquation = this.blendEquation; 21188 if ( this.blendSrcAlpha !== null ) data.blendSrcAlpha = this.blendSrcAlpha; 21189 if ( this.blendDstAlpha !== null ) data.blendDstAlpha = this.blendDstAlpha; 21190 if ( this.blendEquationAlpha !== null ) data.blendEquationAlpha = this.blendEquationAlpha; 21191 if ( this.blendColor && this.blendColor.isColor ) data.blendColor = this.blendColor.getHex(); 21192 if ( this.blendAlpha !== 0 ) data.blendAlpha = this.blendAlpha; 21193 21194 if ( this.depthFunc !== LessEqualDepth ) data.depthFunc = this.depthFunc; 21195 if ( this.depthTest === false ) data.depthTest = this.depthTest; 21196 if ( this.depthWrite === false ) data.depthWrite = this.depthWrite; 21197 if ( this.colorWrite === false ) data.colorWrite = this.colorWrite; 21198 21199 if ( this.stencilWriteMask !== 0xff ) data.stencilWriteMask = this.stencilWriteMask; 21200 if ( this.stencilFunc !== AlwaysStencilFunc ) data.stencilFunc = this.stencilFunc; 21201 if ( this.stencilRef !== 0 ) data.stencilRef = this.stencilRef; 21202 if ( this.stencilFuncMask !== 0xff ) data.stencilFuncMask = this.stencilFuncMask; 21203 if ( this.stencilFail !== KeepStencilOp ) data.stencilFail = this.stencilFail; 21204 if ( this.stencilZFail !== KeepStencilOp ) data.stencilZFail = this.stencilZFail; 21205 if ( this.stencilZPass !== KeepStencilOp ) data.stencilZPass = this.stencilZPass; 21206 if ( this.stencilWrite === true ) data.stencilWrite = this.stencilWrite; 21207 21208 // rotation (SpriteMaterial) 21209 if ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation; 21210 21211 if ( this.polygonOffset === true ) data.polygonOffset = true; 21212 if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor; 21213 if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits; 21214 21215 if ( this.linewidth !== undefined && this.linewidth !== 1 ) data.linewidth = this.linewidth; 21216 if ( this.dashSize !== undefined ) data.dashSize = this.dashSize; 21217 if ( this.gapSize !== undefined ) data.gapSize = this.gapSize; 21218 if ( this.scale !== undefined ) data.scale = this.scale; 21219 21220 if ( this.dithering === true ) data.dithering = true; 21221 21222 if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; 21223 if ( this.alphaHash === true ) data.alphaHash = true; 21224 if ( this.alphaToCoverage === true ) data.alphaToCoverage = true; 21225 if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = true; 21226 if ( this.forceSinglePass === true ) data.forceSinglePass = true; 21227 if ( this.allowOverride === false ) data.allowOverride = false; 21228 21229 if ( this.wireframe === true ) data.wireframe = true; 21230 if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth; 21231 if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap; 21232 if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin; 21233 21234 if ( this.flatShading === true ) data.flatShading = true; 21235 21236 if ( this.visible === false ) data.visible = false; 21237 21238 if ( this.toneMapped === false ) data.toneMapped = false; 21239 21240 if ( this.fog === false ) data.fog = false; 21241 21242 if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData; 21243 21244 // TODO: Copied from Object3D.toJSON 21245 21246 function extractFromCache( cache ) { 21247 21248 const values = []; 21249 21250 for ( const key in cache ) { 21251 21252 const data = cache[ key ]; 21253 delete data.metadata; 21254 values.push( data ); 21255 21256 } 21257 21258 return values; 21259 21260 } 21261 21262 if ( isRootObject ) { 21263 21264 const textures = extractFromCache( meta.textures ); 21265 const images = extractFromCache( meta.images ); 21266 21267 if ( textures.length > 0 ) data.textures = textures; 21268 if ( images.length > 0 ) data.images = images; 21269 21270 } 21271 21272 return data; 21273 21274 } 21275 21276 /** 21277 * Returns a new material with copied values from this instance. 21278 * 21279 * @return {Material} A clone of this instance. 21280 */ 21281 clone() { 21282 21283 return new this.constructor().copy( this ); 21284 21285 } 21286 21287 /** 21288 * Copies the values of the given material to this instance. 21289 * 21290 * @param {Material} source - The material to copy. 21291 * @return {Material} A reference to this instance. 21292 */ 21293 copy( source ) { 21294 21295 this.name = source.name; 21296 21297 this.blending = source.blending; 21298 this.side = source.side; 21299 this.vertexColors = source.vertexColors; 21300 21301 this.opacity = source.opacity; 21302 this.transparent = source.transparent; 21303 21304 this.blendSrc = source.blendSrc; 21305 this.blendDst = source.blendDst; 21306 this.blendEquation = source.blendEquation; 21307 this.blendSrcAlpha = source.blendSrcAlpha; 21308 this.blendDstAlpha = source.blendDstAlpha; 21309 this.blendEquationAlpha = source.blendEquationAlpha; 21310 this.blendColor.copy( source.blendColor ); 21311 this.blendAlpha = source.blendAlpha; 21312 21313 this.depthFunc = source.depthFunc; 21314 this.depthTest = source.depthTest; 21315 this.depthWrite = source.depthWrite; 21316 21317 this.stencilWriteMask = source.stencilWriteMask; 21318 this.stencilFunc = source.stencilFunc; 21319 this.stencilRef = source.stencilRef; 21320 this.stencilFuncMask = source.stencilFuncMask; 21321 this.stencilFail = source.stencilFail; 21322 this.stencilZFail = source.stencilZFail; 21323 this.stencilZPass = source.stencilZPass; 21324 this.stencilWrite = source.stencilWrite; 21325 21326 const srcPlanes = source.clippingPlanes; 21327 let dstPlanes = null; 21328 21329 if ( srcPlanes !== null ) { 21330 21331 const n = srcPlanes.length; 21332 dstPlanes = new Array( n ); 21333 21334 for ( let i = 0; i !== n; ++ i ) { 21335 21336 dstPlanes[ i ] = srcPlanes[ i ].clone(); 21337 21338 } 21339 21340 } 21341 21342 this.clippingPlanes = dstPlanes; 21343 this.clipIntersection = source.clipIntersection; 21344 this.clipShadows = source.clipShadows; 21345 21346 this.shadowSide = source.shadowSide; 21347 21348 this.colorWrite = source.colorWrite; 21349 21350 this.precision = source.precision; 21351 21352 this.polygonOffset = source.polygonOffset; 21353 this.polygonOffsetFactor = source.polygonOffsetFactor; 21354 this.polygonOffsetUnits = source.polygonOffsetUnits; 21355 21356 this.dithering = source.dithering; 21357 21358 this.alphaTest = source.alphaTest; 21359 this.alphaHash = source.alphaHash; 21360 this.alphaToCoverage = source.alphaToCoverage; 21361 this.premultipliedAlpha = source.premultipliedAlpha; 21362 this.forceSinglePass = source.forceSinglePass; 21363 this.allowOverride = source.allowOverride; 21364 21365 this.visible = source.visible; 21366 21367 this.toneMapped = source.toneMapped; 21368 21369 this.userData = JSON.parse( JSON.stringify( source.userData ) ); 21370 21371 return this; 21372 21373 } 21374 21375 /** 21376 * Frees the GPU-related resources allocated by this instance. Call this 21377 * method whenever this instance is no longer used in your app. 21378 * 21379 * @fires Material#dispose 21380 */ 21381 dispose() { 21382 21383 /** 21384 * Fires when the material has been disposed of. 21385 * 21386 * @event Material#dispose 21387 * @type {Object} 21388 */ 21389 this.dispatchEvent( { type: 'dispose' } ); 21390 21391 } 21392 21393 /** 21394 * Setting this property to `true` indicates the engine the material 21395 * needs to be recompiled. 21396 * 21397 * @type {boolean} 21398 * @default false 21399 * @param {boolean} value 21400 */ 21401 set needsUpdate( value ) { 21402 21403 if ( value === true ) this.version ++; 21404 21405 } 21406 21407}
21407 21408 21409/** 21410 * A material for rendering instances of {@link Sprite}. 21411 * 21412 * ```js 21413 * const map = new THREE.TextureLoader().load( 'textures/sprite.png' ); 21414 * const material = new THREE.SpriteMaterial( { map: map, color: 0xffffff } ); 21415 * 21416 * const sprite = new THREE.Sprite( material ); 21417 * sprite.scale.set(200, 200, 1) 21418 * scene.add( sprite ); 21419 * ``` 21420 * 21421 * @augments Material 21422 */ 21423class SpriteMaterial extends Material { 21424 21425 /** 21426 * Constructs a new sprite material. 21427 * 21428 * @param {Object} [parameters] - An object with one or more properties 21429 * defining the material's appearance. Any property of the material 21430 * (including any property from inherited materials) can be passed 21431 * in here. Color values can be passed any type of value accepted 21432 * by {@link Color#set}. 21433 */ 21434 constructor( parameters ) { 21435 21436 super(); 21437 21438 /** 21439 * This flag can be used for type testing. 21440 * 21441 * @type {boolean} 21442 * @readonly 21443 * @default true 21444 */ 21445 this.isSpriteMaterial = true; 21446 21447 this.type = 'SpriteMaterial'; 21448 21449 /** 21450 * Color of the material. 21451 * 21452 * @type {Color} 21453 * @default (1,1,1) 21454 */ 21455 this.color = new Color( 0xffffff ); 21456 21457 /** 21458 * The color map. May optionally include an alpha channel, typically combined 21459 * with {@link Material#transparent} or {@link Material#alphaTest}. The texture map 21460 * color is modulated by the diffuse `color`. 21461 * 21462 * @type {?Texture} 21463 * @default null 21464 */ 21465 this.map = null; 21466 21467 /** 21468 * The alpha map is a grayscale texture that controls the opacity across the 21469 * surface (black: fully transparent; white: fully opaque). 21470 * 21471 * Only the color of the texture is used, ignoring the alpha channel if one 21472 * exists. For RGB and RGBA textures, the renderer will use the green channel 21473 * when sampling this texture due to the extra bit of precision provided for 21474 * green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and 21475 * luminance/alpha textures will also still work as expected. 21476 * 21477 * @type {?Texture} 21478 * @default null 21479 */ 21480 this.alphaMap = null; 21481 21482 /** 21483 * The rotation of the sprite in radians. 21484 * 21485 * @type {number} 21486 * @default 0 21487 */ 21488 this.rotation = 0; 21489 21490 /** 21491 * Specifies whether size of the sprite is attenuated by the camera depth (perspective camera only). 21492 * 21493 * @type {boolean} 21494 * @default true 21495 */ 21496 this.sizeAttenuation = true; 21497 21498 /** 21499 * Overwritten since sprite materials are transparent 21500 * by default. 21501 * 21502 * @type {boolean} 21503 * @default true 21504 */ 21505 this.transparent = true; 21506 21507 /** 21508 * Whether the material is affected by fog or not. 21509 * 21510 * @type {boolean} 21511 * @default true 21512 */ 21513 this.fog = true; 21514 21515 this.setValues( parameters ); 21516 21517 } 21518 21519 copy( source ) { 21520 21521 super.copy( source ); 21522 21523 this.color.copy( source.color ); 21524 21525 this.map = source.map; 21526 21527 this.alphaMap = source.alphaMap; 21528 21529 this.rotation = source.rotation; 21530 21531 this.sizeAttenuation = source.sizeAttenuation; 21532
vendor: 2,777 bytes, lines 21533-21648
21533 this.fog = source.fog; 21534 21535 return this; 21536 21537 } 21538 21539} 21540 21541let _geometry; 21542 21543const _intersectPoint = /*@__PURE__*/ new Vector3(); 21544const _worldScale = /*@__PURE__*/ new Vector3(); 21545const _mvPosition = /*@__PURE__*/ new Vector3(); 21546 21547const _alignedPosition = /*@__PURE__*/ new Vector2(); 21548const _rotatedPosition = /*@__PURE__*/ new Vector2(); 21549const _viewWorldMatrix = /*@__PURE__*/ new Matrix4(); 21550 21551const _vA$1 = /*@__PURE__*/ new Vector3(); 21552const _vB$1 = /*@__PURE__*/ new Vector3(); 21553const _vC$1 = /*@__PURE__*/ new Vector3(); 21554 21555const _uvA = /*@__PURE__*/ new Vector2(); 21556const _uvB = /*@__PURE__*/ new Vector2(); 21557const _uvC = /*@__PURE__*/ new Vector2(); 21558 21559/** 21560 * A sprite is a plane that always faces towards the camera, generally with a 21561 * partially transparent texture applied. 21562 * 21563 * Sprites do not cast shadows, setting {@link Object3D#castShadow} to `true` will 21564 * have no effect. 21565 * 21566 * ```js 21567 * const map = new THREE.TextureLoader().load( 'sprite.png' ); 21568 * const material = new THREE.SpriteMaterial( { map: map } ); 21569 * 21570 * const sprite = new THREE.Sprite( material ); 21571 * scene.add( sprite ); 21572 * ``` 21573 * 21574 * @augments Object3D 21575 */ 21576class Sprite extends Object3D { 21577 21578 /** 21579 * Constructs a new sprite. 21580 * 21581 * @param {(SpriteMaterial|SpriteNodeMaterial)} [material] - The sprite material. 21582 */ 21583 constructor( material = new SpriteMaterial() ) { 21584 21585 super(); 21586 21587 /** 21588 * This flag can be used for type testing. 21589 * 21590 * @type {boolean} 21591 * @readonly 21592 * @default true 21593 */ 21594 this.isSprite = true; 21595 21596 this.type = 'Sprite'; 21597 21598 if ( _geometry === undefined ) { 21599 21600 _geometry = new BufferGeometry(); 21601 21602 const float32Array = new Float32Array( [ 21603 -0.5, -0.5, 0, 0, 0, 21604 0.5, -0.5, 0, 1, 0, 21605 0.5, 0.5, 0, 1, 1, 21606 -0.5, 0.5, 0, 0, 1 21607 ] ); 21608 21609 const interleavedBuffer = new InterleavedBuffer( float32Array, 5 ); 21610 21611 _geometry.setIndex( [ 0, 1, 2, 0, 2, 3 ] ); 21612 _geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) ); 21613 _geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) ); 21614 21615 } 21616 21617 /** 21618 * The sprite geometry. 21619 * 21620 * @type {BufferGeometry} 21621 */ 21622 this.geometry = _geometry; 21623 21624 /** 21625 * The sprite material. 21626 * 21627 * @type {(SpriteMaterial|SpriteNodeMaterial)} 21628 */ 21629 this.material = material; 21630 21631 /** 21632 * The sprite's anchor point, and the point around which the sprite rotates. 21633 * A value of `(0.5, 0.5)` corresponds to the midpoint of the sprite. A value 21634 * of `(0, 0)` corresponds to the lower left corner of the sprite. 21635 * 21636 * @type {Vector2} 21637 * @default (0.5,0.5) 21638 */ 21639 this.center = new Vector2( 0.5, 0.5 ); 21640 21641 /** 21642 * The number of instances of this sprite. 21643 * Can only be used with {@link WebGPURenderer}. 21644 * 21645 * @type {number} 21646 * @default 1 21647 */ 21648 this.count = 1
vendor: 9,105 bytes, lines 21648-22074
21648; 21649 21650 } 21651 21652 /** 21653 * Computes intersection points between a casted ray and this sprite. 21654 * 21655 * @param {Raycaster} raycaster - The raycaster. 21656 * @param {Array<Object>} intersects - The target array that holds the intersection points. 21657 */ 21658 raycast( raycaster, intersects ) { 21659 21660 if ( raycaster.camera === null ) { 21661 21662 error( 'Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.' ); 21663 21664 } 21665 21666 _worldScale.setFromMatrixScale( this.matrixWorld ); 21667 21668 _viewWorldMatrix.copy( raycaster.camera.matrixWorld ); 21669 this.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld ); 21670 21671 _mvPosition.setFromMatrixPosition( this.modelViewMatrix ); 21672 21673 if ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) { 21674 21675 _worldScale.multiplyScalar( - _mvPosition.z ); 21676 21677 } 21678 21679 const rotation = this.material.rotation; 21680 let sin, cos; 21681 21682 if ( rotation !== 0 ) { 21683 21684 cos = Math.cos( rotation ); 21685 sin = Math.sin( rotation ); 21686 21687 } 21688 21689 const center = this.center; 21690 21691 transformVertex( _vA$1.set( -0.5, -0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); 21692 transformVertex( _vB$1.set( 0.5, -0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); 21693 transformVertex( _vC$1.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); 21694 21695 _uvA.set( 0, 0 ); 21696 _uvB.set( 1, 0 ); 21697 _uvC.set( 1, 1 ); 21698 21699 // check first triangle 21700 let intersect = raycaster.ray.intersectTriangle( _vA$1, _vB$1, _vC$1, false, _intersectPoint ); 21701 21702 if ( intersect === null ) { 21703 21704 // check second triangle 21705 transformVertex( _vB$1.set( -0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos ); 21706 _uvB.set( 0, 1 ); 21707 21708 intersect = raycaster.ray.intersectTriangle( _vA$1, _vC$1, _vB$1, false, _intersectPoint ); 21709 if ( intersect === null ) { 21710 21711 return; 21712 21713 } 21714 21715 } 21716 21717 const distance = raycaster.ray.origin.distanceTo( _intersectPoint ); 21718 21719 if ( distance < raycaster.near || distance > raycaster.far ) return; 21720 21721 intersects.push( { 21722 21723 distance: distance, 21724 point: _intersectPoint.clone(), 21725 uv: Triangle.getInterpolation( _intersectPoint, _vA$1, _vB$1, _vC$1, _uvA, _uvB, _uvC, new Vector2() ), 21726 face: null, 21727 object: this 21728 21729 } ); 21730 21731 } 21732 21733 copy( source, recursive ) { 21734 21735 super.copy( source, recursive ); 21736 21737 if ( source.center !== undefined ) this.center.copy( source.center ); 21738 21739 this.material = source.material; 21740 21741 return this; 21742 21743 } 21744 21745} 21746 21747function transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) { 21748 21749 // compute position in camera space 21750 _alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale ); 21751 21752 // to check if rotation is not zero 21753 if ( sin !== undefined ) { 21754 21755 _rotatedPosition.x = ( cos * _alignedPosition.x ) - ( sin * _alignedPosition.y ); 21756 _rotatedPosition.y = ( sin * _alignedPosition.x ) + ( cos * _alignedPosition.y ); 21757 21758 } else { 21759 21760 _rotatedPosition.copy( _alignedPosition ); 21761 21762 } 21763 21764 21765 vertexPosition.copy( mvPosition ); 21766 vertexPosition.x += _rotatedPosition.x; 21767 vertexPosition.y += _rotatedPosition.y; 21768 21769 // transform to world space 21770 vertexPosition.applyMatrix4( _viewWorldMatrix ); 21771 21772} 21773 21774const _v1$2 = /*@__PURE__*/ new Vector3(); 21775const _v2$1 = /*@__PURE__*/ new Vector3(); 21776 21777/** 21778 * A component for providing a basic Level of Detail (LOD) mechanism. 21779 * 21780 * Every LOD level is associated with an object, and rendering can be switched 21781 * between them at the distances specified. Typically you would create, say, 21782 * three meshes, one for far away (low detail), one for mid range (medium 21783 * detail) and one for close up (high detail). 21784 * 21785 * ```js 21786 * const lod = new THREE.LOD(); 21787 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); 21788 * 21789 * //Create spheres with 3 levels of detail and create new LOD levels for them 21790 * for( let i = 0; i < 3; i++ ) { 21791 * 21792 * const geometry = new THREE.IcosahedronGeometry( 10, 3 - i ); 21793 * const mesh = new THREE.Mesh( geometry, material ); 21794 * lod.addLevel( mesh, i * 75 ); 21795 * 21796 * } 21797 * 21798 * scene.add( lod ); 21799 * ``` 21800 * 21801 * @augments Object3D 21802 */ 21803class LOD extends Object3D { 21804 21805 /** 21806 * Constructs a new LOD. 21807 */ 21808 constructor() { 21809 21810 super(); 21811 21812 /** 21813 * This flag can be used for type testing. 21814 * 21815 * @type {boolean} 21816 * @readonly 21817 * @default true 21818 */ 21819 this.isLOD = true; 21820 21821 /** 21822 * The current LOD index. 21823 * 21824 * @private 21825 * @type {number} 21826 * @default 0 21827 */ 21828 this._currentLevel = 0; 21829 21830 this.type = 'LOD'; 21831 21832 Object.defineProperties( this, { 21833 /** 21834 * This array holds the LOD levels. 21835 * 21836 * @name LOD#levels 21837 * @type {Array<{object:Object3D,distance:number,hysteresis:number}>} 21838 */ 21839 levels: { 21840 enumerable: true, 21841 value: [] 21842 } 21843 } ); 21844 21845 /** 21846 * Whether the LOD object is updated automatically by the renderer per frame 21847 * or not. If set to `false`, you have to call {@link LOD#update} in the 21848 * render loop by yourself. 21849 * 21850 * @type {boolean} 21851 * @default true 21852 */ 21853 this.autoUpdate = true; 21854 21855 } 21856 21857 copy( source ) { 21858 21859 super.copy( source, false ); 21860 21861 const levels = source.levels; 21862 21863 for ( let i = 0, l = levels.length; i < l; i ++ ) { 21864 21865 const level = levels[ i ]; 21866 21867 this.addLevel( level.object.clone(), level.distance, level.hysteresis ); 21868 21869 } 21870 21871 this.autoUpdate = source.autoUpdate; 21872 21873 return this; 21874 21875 } 21876 21877 /** 21878 * Adds a mesh that will display at a certain distance and greater. Typically 21879 * the further away the distance, the lower the detail on the mesh. 21880 * 21881 * @param {Object3D} object - The 3D object to display at this level. 21882 * @param {number} [distance=0] - The distance at which to display this level of detail. 21883 * @param {number} [hysteresis=0] - Threshold used to avoid flickering at LOD boundaries, as a fraction of distance. 21884 * @return {LOD} A reference to this instance. 21885 */ 21886 addLevel( object, distance = 0, hysteresis = 0 ) { 21887 21888 distance = Math.abs( distance ); 21889 21890 const levels = this.levels; 21891 21892 let l; 21893 21894 for ( l = 0; l < levels.length; l ++ ) { 21895 21896 if ( distance < levels[ l ].distance ) { 21897 21898 break; 21899 21900 } 21901 21902 } 21903 21904 levels.splice( l, 0, { distance: distance, hysteresis: hysteresis, object: object } ); 21905 21906 this.add( object ); 21907 21908 return this; 21909 21910 } 21911 21912 /** 21913 * Removes an existing level, based on the distance from the camera. 21914 * Returns `true` when the level has been removed. Otherwise `false`. 21915 * 21916 * @param {number} distance - Distance of the level to remove. 21917 * @return {boolean} Whether the level has been removed or not. 21918 */ 21919 removeLevel( distance ) { 21920 21921 const levels = this.levels; 21922 21923 for ( let i = 0; i < levels.length; i ++ ) { 21924 21925 if ( levels[ i ].distance === distance ) { 21926 21927 const removedElements = levels.splice( i, 1 ); 21928 this.remove( removedElements[ 0 ].object ); 21929 21930 return true; 21931 21932 } 21933 21934 } 21935 21936 return false; 21937 21938 } 21939 21940 /** 21941 * Returns the currently active LOD level index. 21942 * 21943 * @return {number} The current active LOD level index. 21944 */ 21945 getCurrentLevel() { 21946 21947 return this._currentLevel; 21948 21949 } 21950 21951 /** 21952 * Returns a reference to the first 3D object that is greater than 21953 * the given distance. 21954 * 21955 * @param {number} distance - The LOD distance. 21956 * @return {?Object3D} The found 3D object. `null` if no 3D object has been found. 21957 */ 21958 getObjectForDistance( distance ) { 21959 21960 const levels = this.levels; 21961 21962 if ( levels.length > 0 ) { 21963 21964 let i, l; 21965 21966 for ( i = 1, l = levels.length; i < l; i ++ ) { 21967 21968 let levelDistance = levels[ i ].distance; 21969 21970 if ( levels[ i ].object.visible ) { 21971 21972 levelDistance -= levelDistance * levels[ i ].hysteresis; 21973 21974 } 21975 21976 if ( distance < levelDistance ) { 21977 21978 break; 21979 21980 } 21981 21982 } 21983 21984 return levels[ i - 1 ].object; 21985 21986 } 21987 21988 return null; 21989 21990 } 21991 21992 /** 21993 * Computes intersection points between a casted ray and this LOD. 21994 * 21995 * @param {Raycaster} raycaster - The raycaster. 21996 * @param {Array<Object>} intersects - The target array that holds the intersection points. 21997 */ 21998 raycast( raycaster, intersects ) { 21999 22000 const levels = this.levels; 22001 22002 if ( levels.length > 0 ) { 22003 22004 _v1$2.setFromMatrixPosition( this.matrixWorld ); 22005 22006 const distance = raycaster.ray.origin.distanceTo( _v1$2 ); 22007 22008 this.getObjectForDistance( distance ).raycast( raycaster, intersects ); 22009 22010 } 22011 22012 } 22013 22014 /** 22015 * Updates the LOD by computing which LOD level should be visible according 22016 * to the current distance of the given camera. 22017 * 22018 * @param {Camera} camera - The camera the scene is rendered with. 22019 */ 22020 update( camera ) { 22021 22022 const levels = this.levels; 22023 22024 if ( levels.length > 1 ) { 22025 22026 _v1$2.setFromMatrixPosition( camera.matrixWorld ); 22027 _v2$1.setFromMatrixPosition( this.matrixWorld ); 22028 22029 const distance = _v1$2.distanceTo( _v2$1 ) / camera.zoom; 22030 22031 levels[ 0 ].object.visible = true; 22032 22033 let i, l; 22034 22035 for ( i = 1, l = levels.length; i < l; i ++ ) { 22036 22037 let levelDistance = levels[ i ].distance; 22038 22039 if ( levels[ i ].object.visible ) { 22040 22041 levelDistance -= levelDistance * levels[ i ].hysteresis; 22042 22043 } 22044 22045 if ( distance >= levelDistance ) { 22046 22047 levels[ i - 1 ].object.visible = false; 22048 levels[ i ].object.visible = true; 22049 22050 } else { 22051 22052 break; 22053 22054 } 22055 22056 } 22057 22058 this._currentLevel = i - 1; 22059 22060 for ( ; i < l; i ++ ) { 22061 22062 levels[ i ].object.visible = false; 22063 22064 } 22065 22066 } 22067 22068 } 22069 22070 toJSON( meta ) { 22071 22072 const data = super.toJSON( meta ); 22073 22074
22074if ( this.autoUpdate === false ) data.object.autoUpdate = false; 22075 22076 data.object.levels = []; 22077 22078 const levels = this.levels; 22079 22080 for ( let i = 0, l = levels.length; i < l; i ++ ) { 22081 22082 const level = levels[ i ]; 22083 22084 data.object.levels.push( { 22085 object: level.object.uuid, 22086 distance: level.distance, 22087 hysteresis: level.hysteresis 22088 } ); 22089 22090 } 22091 22092 return data; 22093 22094 } 22095 22096} 22097 22098const _vector$7 = /*@__PURE__*/ new Vector3(); 22099const _segCenter = /*@__PURE__*/ new Vector3(); 22100const _segDir = /*@__PURE__*/ new Vector3(); 22101const _diff = /*@__PURE__*/ new Vector3(); 22102 22103const _edge1 = /*@__PURE__*/ new Vector3(); 22104const _edge2 = /*@__PURE__*/ new Vector3(); 22105const _normal$1
vendor: 7,142 bytes, lines 22105-22397
22105 = /*@__PURE__*/ new Vector3(); 22106 22107/** 22108 * A ray that emits from an origin in a certain direction. The class is used by 22109 * {@link Raycaster} to assist with raycasting. Raycasting is used for 22110 * mouse picking (working out what objects in the 3D space the mouse is over) 22111 * amongst other things. 22112 */ 22113class Ray { 22114 22115 /** 22116 * Constructs a new ray. 22117 * 22118 * @param {Vector3} [origin=(0,0,0)] - The origin of the ray. 22119 * @param {Vector3} [direction=(0,0,-1)] - The (normalized) direction of the ray. 22120 */ 22121 constructor( origin = new Vector3(), direction = new Vector3( 0, 0, -1 ) ) { 22122 22123 /** 22124 * The origin of the ray. 22125 * 22126 * @type {Vector3} 22127 */ 22128 this.origin = origin; 22129 22130 /** 22131 * The (normalized) direction of the ray. 22132 * 22133 * @type {Vector3} 22134 */ 22135 this.direction = direction; 22136 22137 } 22138 22139 /** 22140 * Sets the ray's components by copying the given values. 22141 * 22142 * @param {Vector3} origin - The origin. 22143 * @param {Vector3} direction - The direction. 22144 * @return {Ray} A reference to this ray. 22145 */ 22146 set( origin, direction ) { 22147 22148 this.origin.copy( origin ); 22149 this.direction.copy( direction ); 22150 22151 return this; 22152 22153 } 22154 22155 /** 22156 * Copies the values of the given ray to this instance. 22157 * 22158 * @param {Ray} ray - The ray to copy. 22159 * @return {Ray} A reference to this ray. 22160 */ 22161 copy( ray ) { 22162 22163 this.origin.copy( ray.origin ); 22164 this.direction.copy( ray.direction ); 22165 22166 return this; 22167 22168 } 22169 22170 /** 22171 * Returns a vector that is located at a given distance along this ray. 22172 * 22173 * @param {number} t - The distance along the ray to retrieve a position for. 22174 * @param {Vector3} target - The target vector that is used to store the method's result. 22175 * @return {Vector3} A position on the ray. 22176 */ 22177 at( t, target ) { 22178 22179 return target.copy( this.origin ).addScaledVector( this.direction, t ); 22180 22181 } 22182 22183 /** 22184 * Adjusts the direction of the ray to point at the given vector in world space. 22185 * 22186 * @param {Vector3} v - The target position. 22187 * @return {Ray} A reference to this ray. 22188 */ 22189 lookAt( v ) { 22190 22191 this.direction.copy( v ).sub( this.origin ).normalize(); 22192 22193 return this; 22194 22195 } 22196 22197 /** 22198 * Shift the origin of this ray along its direction by the given distance. 22199 * 22200 * @param {number} t - The distance along the ray to interpolate. 22201 * @return {Ray} A reference to this ray. 22202 */ 22203 recast( t ) { 22204 22205 this.origin.copy( this.at( t, _vector$7 ) ); 22206 22207 return this; 22208 22209 } 22210 22211 /** 22212 * Returns the point along this ray that is closest to the given point. 22213 * 22214 * @param {Vector3} point - A point in 3D space to get the closet location on the ray for. 22215 * @param {Vector3} target - The target vector that is used to store the method's result. 22216 * @return {Vector3} The closest point on this ray. 22217 */ 22218 closestPointToPoint( point, target ) { 22219 22220 target.subVectors( point, this.origin ); 22221 22222 const directionDistance = target.dot( this.direction ); 22223 22224 if ( directionDistance < 0 ) { 22225 22226 return target.copy( this.origin ); 22227 22228 } 22229 22230 return target.copy( this.origin ).addScaledVector( this.direction, directionDistance ); 22231 22232 } 22233 22234 /** 22235 * Returns the distance of the closest approach between this ray and the given point. 22236 * 22237 * @param {Vector3} point - A point in 3D space to compute the distance to. 22238 * @return {number} The distance. 22239 */ 22240 distanceToPoint( point ) { 22241 22242 return Math.sqrt( this.distanceSqToPoint( point ) ); 22243 22244 } 22245 22246 /** 22247 * Returns the squared distance of the closest approach between this ray and the given point. 22248 * 22249 * @param {Vector3} point - A point in 3D space to compute the distance to. 22250 * @return {number} The squared distance. 22251 */ 22252 distanceSqToPoint( point ) { 22253 22254 const directionDistance = _vector$7.subVectors( point, this.origin ).dot( this.direction ); 22255 22256 // point behind the ray 22257 22258 if ( directionDistance < 0 ) { 22259 22260 return this.origin.distanceToSquared( point ); 22261 22262 } 22263 22264 _vector$7.copy( this.origin ).addScaledVector( this.direction, directionDistance ); 22265 22266 return _vector$7.distanceToSquared( point ); 22267 22268 } 22269 22270 /** 22271 * Returns the squared distance between this ray and the given line segment. 22272 * 22273 * @param {Vector3} v0 - The start point of the line segment. 22274 * @param {Vector3} v1 - The end point of the line segment. 22275 * @param {Vector3} [optionalPointOnRay] - When provided, it receives the point on this ray that is closest to the segment. 22276 * @param {Vector3} [optionalPointOnSegment] - When provided, it receives the point on the line segment that is closest to this ray. 22277 * @return {number} The squared distance. 22278 */ 22279 distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { 22280 22281 // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteDistRaySegment.h 22282 // It returns the min distance between the ray and the segment 22283 // defined by v0 and v1 22284 // It can also set two optional targets : 22285 // - The closest point on the ray 22286 // - The closest point on the segment 22287 22288 _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); 22289 _segDir.copy( v1 ).sub( v0 ).normalize(); 22290 _diff.copy( this.origin ).sub( _segCenter ); 22291 22292 const segExtent = v0.distanceTo( v1 ) * 0.5; 22293 const a01 = - this.direction.dot( _segDir ); 22294 const b0 = _diff.dot( this.direction ); 22295 const b1 = - _diff.dot( _segDir ); 22296 const c = _diff.lengthSq(); 22297 const det = Math.abs( 1 - a01 * a01 ); 22298 let s0, s1, sqrDist, extDet; 22299 22300 if ( det > 0 ) { 22301 22302 // The ray and segment are not parallel. 22303 22304 s0 = a01 * b1 - b0; 22305 s1 = a01 * b0 - b1; 22306 extDet = segExtent * det; 22307 22308 if ( s0 >= 0 ) { 22309 22310 if ( s1 >= - extDet ) { 22311 22312 if ( s1 <= extDet ) { 22313 22314 // region 0 22315 // Minimum at interior points of ray and segment. 22316 22317 const invDet = 1 / det; 22318 s0 *= invDet; 22319 s1 *= invDet; 22320 sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; 22321 22322 } else { 22323 22324 // region 1 22325 22326 s1 = segExtent; 22327 s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); 22328 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 22329 22330 } 22331 22332 } else { 22333 22334 // region 5 22335 22336 s1 = - segExtent; 22337 s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); 22338 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 22339 22340 } 22341 22342 } else { 22343 22344 if ( s1 <= - extDet ) { 22345 22346 // region 4 22347 22348 s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); 22349 s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); 22350 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 22351 22352 } else if ( s1 <= extDet ) { 22353 22354 // region 3 22355 22356 s0 = 0; 22357 s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); 22358 sqrDist = s1 * ( s1 + 2 * b1 ) + c; 22359 22360 } else { 22361 22362 // region 2 22363 22364 s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); 22365 s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); 22366 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 22367 22368 } 22369 22370 } 22371 22372 } else { 22373 22374 // Ray and segment are parallel. 22375 22376 s1 = ( a01 > 0 ) ? - segExtent : segExtent; 22377 s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); 22378 sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; 22379 22380 } 22381 22382 if ( optionalPointOnRay ) { 22383 22384 optionalPointOnRay.copy( this.origin ).addScaledVector( this.direction, s0 ); 22385 22386 } 22387 22388 if ( optionalPointOnSegment ) { 22389 22390 optionalPointOnSegment.copy( _segCenter ).addScaledVector( _segDir, s1 ); 22391 22392 } 22393 22394 return sqrDist; 22395 22396 } 22397
vendor: 8,703 bytes, lines 22398-22758
22398 /** 22399 * Intersects this ray with the given sphere, returning the intersection 22400 * point or `null` if there is no intersection. 22401 * 22402 * @param {Sphere} sphere - The sphere to intersect. 22403 * @param {Vector3} target - The target vector that is used to store the method's result. 22404 * @return {?Vector3} The intersection point. 22405 */ 22406 intersectSphere( sphere, target ) { 22407 22408 _vector$7.subVectors( sphere.center, this.origin ); 22409 const tca = _vector$7.dot( this.direction ); 22410 const d2 = _vector$7.dot( _vector$7 ) - tca * tca; 22411 const radius2 = sphere.radius * sphere.radius; 22412 22413 if ( d2 > radius2 ) return null; 22414 22415 const thc = Math.sqrt( radius2 - d2 ); 22416 22417 // t0 = first intersect point - entrance on front of sphere 22418 const t0 = tca - thc; 22419 22420 // t1 = second intersect point - exit point on back of sphere 22421 const t1 = tca + thc; 22422 22423 // test to see if t1 is behind the ray - if so, return null 22424 if ( t1 < 0 ) return null; 22425 22426 // test to see if t0 is behind the ray: 22427 // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, 22428 // in order to always return an intersect point that is in front of the ray. 22429 if ( t0 < 0 ) return this.at( t1, target ); 22430 22431 // else t0 is in front of the ray, so return the first collision point scaled by t0 22432 return this.at( t0, target ); 22433 22434 } 22435 22436 /** 22437 * Returns `true` if this ray intersects with the given sphere. 22438 * 22439 * @param {Sphere} sphere - The sphere to intersect. 22440 * @return {boolean} Whether this ray intersects with the given sphere or not. 22441 */ 22442 intersectsSphere( sphere ) { 22443 22444 if ( sphere.radius < 0 ) return false; // handle empty spheres, see #31187 22445 22446 return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius ); 22447 22448 } 22449 22450 /** 22451 * Computes the distance from the ray's origin to the given plane. Returns `null` if the ray 22452 * does not intersect with the plane. 22453 * 22454 * @param {Plane} plane - The plane to compute the distance to. 22455 * @return {?number} Whether this ray intersects with the given sphere or not. 22456 */ 22457 distanceToPlane( plane ) { 22458 22459 const denominator = plane.normal.dot( this.direction ); 22460 22461 if ( denominator === 0 ) { 22462 22463 // line is coplanar, return origin 22464 if ( plane.distanceToPoint( this.origin ) === 0 ) { 22465 22466 return 0; 22467 22468 } 22469 22470 // Null is preferable to undefined since undefined means.... it is undefined 22471 22472 return null; 22473 22474 } 22475 22476 const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; 22477 22478 // Return if the ray never intersects the plane 22479 22480 return t >= 0 ? t : null; 22481 22482 } 22483 22484 /** 22485 * Intersects this ray with the given plane, returning the intersection 22486 * point or `null` if there is no intersection. 22487 * 22488 * @param {Plane} plane - The plane to intersect. 22489 * @param {Vector3} target - The target vector that is used to store the method's result. 22490 * @return {?Vector3} The intersection point. 22491 */ 22492 intersectPlane( plane, target ) { 22493 22494 const t = this.distanceToPlane( plane ); 22495 22496 if ( t === null ) { 22497 22498 return null; 22499 22500 } 22501 22502 return this.at( t, target ); 22503 22504 } 22505 22506 /** 22507 * Returns `true` if this ray intersects with the given plane. 22508 * 22509 * @param {Plane} plane - The plane to intersect. 22510 * @return {boolean} Whether this ray intersects with the given plane or not. 22511 */ 22512 intersectsPlane( plane ) { 22513 22514 // check if the ray lies on the plane first 22515 22516 const distToPoint = plane.distanceToPoint( this.origin ); 22517 22518 if ( distToPoint === 0 ) { 22519 22520 return true; 22521 22522 } 22523 22524 const denominator = plane.normal.dot( this.direction ); 22525 22526 if ( denominator * distToPoint < 0 ) { 22527 22528 return true; 22529 22530 } 22531 22532 // ray origin is behind the plane (and is pointing behind it) 22533 22534 return false; 22535 22536 } 22537 22538 /** 22539 * Intersects this ray with the given bounding box, returning the intersection 22540 * point or `null` if there is no intersection. 22541 * 22542 * @param {Box3} box - The box to intersect. 22543 * @param {Vector3} target - The target vector that is used to store the method's result. 22544 * @return {?Vector3} The intersection point. 22545 */ 22546 intersectBox( box, target ) { 22547 22548 let tmin, tmax, tymin, tymax, tzmin, tzmax; 22549 22550 const invdirx = 1 / this.direction.x, 22551 invdiry = 1 / this.direction.y, 22552 invdirz = 1 / this.direction.z; 22553 22554 const origin = this.origin; 22555 22556 if ( invdirx >= 0 ) { 22557 22558 tmin = ( box.min.x - origin.x ) * invdirx; 22559 tmax = ( box.max.x - origin.x ) * invdirx; 22560 22561 } else { 22562 22563 tmin = ( box.max.x - origin.x ) * invdirx; 22564 tmax = ( box.min.x - origin.x ) * invdirx; 22565 22566 } 22567 22568 if ( invdiry >= 0 ) { 22569 22570 tymin = ( box.min.y - origin.y ) * invdiry; 22571 tymax = ( box.max.y - origin.y ) * invdiry; 22572 22573 } else { 22574 22575 tymin = ( box.max.y - origin.y ) * invdiry; 22576 tymax = ( box.min.y - origin.y ) * invdiry; 22577 22578 } 22579 22580 if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; 22581 22582 if ( tymin > tmin || isNaN( tmin ) ) tmin = tymin; 22583 22584 if ( tymax < tmax || isNaN( tmax ) ) tmax = tymax; 22585 22586 if ( invdirz >= 0 ) { 22587 22588 tzmin = ( box.min.z - origin.z ) * invdirz; 22589 tzmax = ( box.max.z - origin.z ) * invdirz; 22590 22591 } else { 22592 22593 tzmin = ( box.max.z - origin.z ) * invdirz; 22594 tzmax = ( box.min.z - origin.z ) * invdirz; 22595 22596 } 22597 22598 if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; 22599 22600 if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; 22601 22602 if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; 22603 22604 //return point closest to the ray (positive side) 22605 22606 if ( tmax < 0 ) return null; 22607 22608 return this.at( tmin >= 0 ? tmin : tmax, target ); 22609 22610 } 22611 22612 /** 22613 * Returns `true` if this ray intersects with the given box. 22614 * 22615 * @param {Box3} box - The box to intersect. 22616 * @return {boolean} Whether this ray intersects with the given box or not. 22617 */ 22618 intersectsBox( box ) { 22619 22620 return this.intersectBox( box, _vector$7 ) !== null; 22621 22622 } 22623 22624 /** 22625 * Intersects this ray with the given triangle, returning the intersection 22626 * point or `null` if there is no intersection. 22627 * 22628 * @param {Vector3} a - The first vertex of the triangle. 22629 * @param {Vector3} b - The second vertex of the triangle. 22630 * @param {Vector3} c - The third vertex of the triangle. 22631 * @param {boolean} backfaceCulling - Whether to use backface culling or not. 22632 * @param {Vector3} target - The target vector that is used to store the method's result. 22633 * @return {?Vector3} The intersection point. 22634 */ 22635 intersectTriangle( a, b, c, backfaceCulling, target ) { 22636 22637 // Compute the offset origin, edges, and normal. 22638 22639 // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h 22640 22641 _edge1.subVectors( b, a ); 22642 _edge2.subVectors( c, a ); 22643 _normal$1.crossVectors( _edge1, _edge2 ); 22644 22645 // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, 22646 // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by 22647 // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) 22648 // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) 22649 // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) 22650 let DdN = this.direction.dot( _normal$1 ); 22651 let sign; 22652 22653 if ( DdN > 0 ) { 22654 22655 if ( backfaceCulling ) return null; 22656 sign = 1; 22657 22658 } else if ( DdN < 0 ) { 22659 22660 sign = -1; 22661 DdN = - DdN; 22662 22663 } else { 22664 22665 return null; 22666 22667 } 22668 22669 _diff.subVectors( this.origin, a ); 22670 const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) ); 22671 22672 // b1 < 0, no intersection 22673 if ( DdQxE2 < 0 ) { 22674 22675 return null; 22676 22677 } 22678 22679 const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) ); 22680 22681 // b2 < 0, no intersection 22682 if ( DdE1xQ < 0 ) { 22683 22684 return null; 22685 22686 } 22687 22688 // b1+b2 > 1, no intersection 22689 if ( DdQxE2 + DdE1xQ > DdN ) { 22690 22691 return null; 22692 22693 } 22694 22695 // Line intersects triangle, check if ray does. 22696 const QdN = - sign * _diff.dot( _normal$1 ); 22697 22698 // t < 0, no intersection 22699 if ( QdN < 0 ) { 22700 22701 return null; 22702 22703 } 22704 22705 // Ray intersects triangle. 22706 return this.at( QdN / DdN, target ); 22707 22708 } 22709 22710 /** 22711 * Transforms this ray with the given 4x4 transformation matrix. 22712 * 22713 * @param {Matrix4} matrix4 - The transformation matrix. 22714 * @return {Ray} A reference to this ray. 22715 */ 22716 applyMatrix4( matrix4 ) { 22717 22718 this.origin.applyMatrix4( matrix4 ); 22719 this.direction.transformDirection( matrix4 ); 22720 22721 return this; 22722 22723 } 22724 22725 /** 22726 * Returns `true` if this ray is equal with the given one. 22727 * 22728 * @param {Ray} ray - The ray to test for equality. 22729 * @return {boolean} Whether this ray is equal with the given one. 22730 */ 22731 equals( ray ) { 22732 22733 return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); 22734 22735 } 22736 22737 /** 22738 * Returns a new ray with copied values from this instance. 22739 * 22740 * @return {Ray} A clone of this instance. 22741 */ 22742 clone() { 22743 22744 return new this.constructor().copy( this ); 22745 22746 } 22747 22748} 22749 22750/** 22751 * A material for drawing geometries in a simple shaded (flat or wireframe) way. 22752 * 22753 * This material is not affected by lights. 22754 * 22755 * @augments Material 22756 * @demo scenes/material-browser.html#MeshBasicMaterial 22757 */ 22758class MeshBasicMaterial extends Material
22758 { 22759 22760 /** 22761 * Constructs a new mesh basic material. 22762 * 22763 * @param {Object} [parameters] - An object with one or more properties 22764 * defining the material's appearance. Any property of the material 22765 * (including any property from inherited materials) can be passed 22766 * in here. Color values can be passed any type of value accepted 22767 * by {@link Color#set}. 22768 */ 22769 constructor( parameters ) { 22770 22771 super(); 22772 22773 /** 22774 * This flag can be used for type testing. 22775 * 22776 * @type {boolean} 22777 * @readonly 22778 * @default true 22779 */ 22780 this.isMeshBasicMaterial = true; 22781 22782 this.type = 'MeshBasicMaterial'; 22783 22784 /** 22785 * Color of the material. 22786 * 22787 * @type {Color} 22788 * @default (1,1,1) 22789 */ 22790 this.color = new Color( 0xffffff ); // diffuse 22791 22792 /** 22793 * The color map. May optionally include an alpha channel, typically combined 22794 * with {@link Material#transparent} or {@link Material#alphaTest}. The texture map 22795 * color is modulated by the diffuse `color`. 22796 * 22797 * @type {?Texture} 22798 * @default null 22799 */ 22800 this.map = null; 22801 22802 /** 22803 * The light map. Requires a second set of UVs. 22804 * 22805 * @type {?Texture} 22806 * @default null 22807 */ 22808 this.lightMap = null; 22809 22810 /** 22811 * Intensity of the baked light. 22812 * 22813 * @type {number} 22814 * @default 1 22815 */ 22816 this.lightMapIntensity = 1.0; 22817 22818 /** 22819 * The red channel of this texture is used as the ambient occlusion map. 22820 * Requires a second set of UVs. 22821 * 22822 * @type {?Texture} 22823 * @default null 22824 */ 22825 this.aoMap = null; 22826 22827 /** 22828 * Intensity of the ambient occlusion effect. Range is `[0,1]`, where `0` 22829 * disables ambient occlusion. Where intensity is `1` and the AO map's 22830 * red channel is also `1`, ambient light is fully occluded on a surface. 22831 * 22832 * @type {number} 22833 * @default 1 22834 */ 22835 this.aoMapIntensity = 1.0; 22836 22837 /** 22838 * Specular map used by the material. 22839 * 22840 * @type {?Texture} 22841 * @default null 22842 */ 22843 this.specularMap = null; 22844 22845 /** 22846 * The alpha map is a grayscale texture that controls the opacity across the 22847 * surface (black: fully transparent; white: fully opaque). 22848 * 22849 * Only the color of the texture is used, ignoring the alpha channel if one 22850 * exists. For RGB and RGBA textures, the renderer will use the green channel 22851 * when sampling this texture due to the extra bit of precision provided for 22852 * green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and 22853 * luminance/alpha textures will also still work as expected. 22854 * 22855 * @type {?Texture} 22856 * @default null 22857 */ 22858 this.alphaMap = null; 22859 22860 /** 22861 * The environment map
vendor: 5,823 bytes, lines 22861-23114
22861. 22862 * 22863 * @type {?Texture} 22864 * @default null 22865 */ 22866 this.envMap = null; 22867 22868 /** 22869 * The rotation of the environment map in radians. 22870 * 22871 * @type {Euler} 22872 * @default (0,0,0) 22873 */ 22874 this.envMapRotation = new Euler(); 22875 22876 /** 22877 * How to combine the result of the surface's color with the environment map, if any. 22878 * 22879 * When set to `MixOperation`, the {@link MeshBasicMaterial#reflectivity} is used to 22880 * blend between the two colors. 22881 * 22882 * @type {(MultiplyOperation|MixOperation|AddOperation)} 22883 * @default MultiplyOperation 22884 */ 22885 this.combine = MultiplyOperation; 22886 22887 /** 22888 * How much the environment map affects the surface. 22889 * The valid range is between `0` (no reflections) and `1` (full reflections). 22890 * 22891 * @type {number} 22892 * @default 1 22893 */ 22894 this.reflectivity = 1; 22895 22896 /** 22897 * The index of refraction (IOR) of air (approximately 1) divided by the 22898 * index of refraction of the material. It is used with environment mapping 22899 * modes {@link CubeRefractionMapping} and {@link EquirectangularRefractionMapping}. 22900 * The refraction ratio should not exceed `1`. 22901 * 22902 * @type {number} 22903 * @default 0.98 22904 */ 22905 this.refractionRatio = 0.98; 22906 22907 /** 22908 * Renders the geometry as a wireframe. 22909 * 22910 * @type {boolean} 22911 * @default false 22912 */ 22913 this.wireframe = false; 22914 22915 /** 22916 * Controls the thickness of the wireframe. 22917 * 22918 * Can only be used with {@link SVGRenderer}. 22919 * 22920 * @type {number} 22921 * @default 1 22922 */ 22923 this.wireframeLinewidth = 1; 22924 22925 /** 22926 * Defines appearance of wireframe ends. 22927 * 22928 * Can only be used with {@link SVGRenderer}. 22929 * 22930 * @type {('round'|'bevel'|'miter')} 22931 * @default 'round' 22932 */ 22933 this.wireframeLinecap = 'round'; 22934 22935 /** 22936 * Defines appearance of wireframe joints. 22937 * 22938 * Can only be used with {@link SVGRenderer}. 22939 * 22940 * @type {('round'|'bevel'|'miter')} 22941 * @default 'round' 22942 */ 22943 this.wireframeLinejoin = 'round'; 22944 22945 /** 22946 * Whether the material is affected by fog or not. 22947 * 22948 * @type {boolean} 22949 * @default true 22950 */ 22951 this.fog = true; 22952 22953 this.setValues( parameters ); 22954 22955 } 22956 22957 copy( source ) { 22958 22959 super.copy( source ); 22960 22961 this.color.copy( source.color ); 22962 22963 this.map = source.map; 22964 22965 this.lightMap = source.lightMap; 22966 this.lightMapIntensity = source.lightMapIntensity; 22967 22968 this.aoMap = source.aoMap; 22969 this.aoMapIntensity = source.aoMapIntensity; 22970 22971 this.specularMap = source.specularMap; 22972 22973 this.alphaMap = source.alphaMap; 22974 22975 this.envMap = source.envMap; 22976 this.envMapRotation.copy( source.envMapRotation ); 22977 this.combine = source.combine; 22978 this.reflectivity = source.reflectivity; 22979 this.refractionRatio = source.refractionRatio; 22980 22981 this.wireframe = source.wireframe; 22982 this.wireframeLinewidth = source.wireframeLinewidth; 22983 this.wireframeLinecap = source.wireframeLinecap; 22984 this.wireframeLinejoin = source.wireframeLinejoin; 22985 22986 this.fog = source.fog; 22987 22988 return this; 22989 22990 } 22991 22992} 22993 22994const _inverseMatrix$3 = /*@__PURE__*/ new Matrix4(); 22995const _ray$3 = /*@__PURE__*/ new Ray(); 22996const _sphere$6 = /*@__PURE__*/ new Sphere(); 22997const _sphereHitAt = /*@__PURE__*/ new Vector3(); 22998 22999const _vA = /*@__PURE__*/ new Vector3(); 23000const _vB = /*@__PURE__*/ new Vector3(); 23001const _vC = /*@__PURE__*/ new Vector3(); 23002 23003const _tempA = /*@__PURE__*/ new Vector3(); 23004const _morphA = /*@__PURE__*/ new Vector3(); 23005 23006const _intersectionPoint = /*@__PURE__*/ new Vector3(); 23007const _intersectionPointWorld = /*@__PURE__*/ new Vector3(); 23008 23009/** 23010 * Class representing triangular polygon mesh based objects. 23011 * 23012 * ```js 23013 * const geometry = new THREE.BoxGeometry( 1, 1, 1 ); 23014 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); 23015 * const mesh = new THREE.Mesh( geometry, material ); 23016 * scene.add( mesh ); 23017 * ``` 23018 * 23019 * @augments Object3D 23020 */ 23021class Mesh extends Object3D { 23022 23023 /** 23024 * Constructs a new mesh. 23025 * 23026 * @param {BufferGeometry} [geometry] - The mesh geometry. 23027 * @param {Material|Array<Material>} [material] - The mesh material. 23028 */ 23029 constructor( geometry = new BufferGeometry(), material = new MeshBasicMaterial() ) { 23030 23031 super(); 23032 23033 /** 23034 * This flag can be used for type testing. 23035 * 23036 * @type {boolean} 23037 * @readonly 23038 * @default true 23039 */ 23040 this.isMesh = true; 23041 23042 this.type = 'Mesh'; 23043 23044 /** 23045 * The mesh geometry. 23046 * 23047 * @type {BufferGeometry} 23048 */ 23049 this.geometry = geometry; 23050 23051 /** 23052 * The mesh material. 23053 * 23054 * @type {Material|Array<Material>} 23055 * @default MeshBasicMaterial 23056 */ 23057 this.material = material; 23058 23059 /** 23060 * A dictionary representing the morph targets in the geometry. The key is the 23061 * morph targets name, the value its attribute index. This member is `undefined` 23062 * by default and only set when morph targets are detected in the geometry. 23063 * 23064 * @type {Object<string,number>|undefined} 23065 * @default undefined 23066 */ 23067 this.morphTargetDictionary = undefined; 23068 23069 /** 23070 * An array of weights typically in the range `[0,1]` that specify how much of the morph 23071 * is applied. This member is `undefined` by default and only set when morph targets are 23072 * detected in the geometry. 23073 * 23074 * @type {Array<number>|undefined} 23075 * @default undefined 23076 */ 23077 this.morphTargetInfluences = undefined; 23078 23079 /** 23080 * The number of instances of this mesh. 23081 * Can only be used with {@link WebGPURenderer}. 23082 * 23083 * @type {number} 23084 * @default 1 23085 */ 23086 this.count = 1; 23087 23088 this.updateMorphTargets(); 23089 23090 } 23091 23092 copy( source, recursive ) { 23093 23094 super.copy( source, recursive ); 23095 23096 if ( source.morphTargetInfluences !== undefined ) { 23097 23098 this.morphTargetInfluences = source.morphTargetInfluences.slice(); 23099 23100 } 23101 23102 if ( source.morphTargetDictionary !== undefined ) { 23103 23104 this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary ); 23105 23106 } 23107 23108 this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; 23109 this.geometry = source.geometry; 23110 23111 return this; 23112 23113 } 23114
vendor: 8,480 bytes, lines 23115-23448
23115 /** 23116 * Sets the values of {@link Mesh#morphTargetDictionary} and {@link Mesh#morphTargetInfluences} 23117 * to make sure existing morph targets can influence this 3D object. 23118 */ 23119 updateMorphTargets() { 23120 23121 const geometry = this.geometry; 23122 23123 const morphAttributes = geometry.morphAttributes; 23124 const keys = Object.keys( morphAttributes ); 23125 23126 if ( keys.length > 0 ) { 23127 23128 const morphAttribute = morphAttributes[ keys[ 0 ] ]; 23129 23130 if ( morphAttribute !== undefined ) { 23131 23132 this.morphTargetInfluences = []; 23133 this.morphTargetDictionary = {}; 23134 23135 for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { 23136 23137 const name = morphAttribute[ m ].name || String( m ); 23138 23139 this.morphTargetInfluences.push( 0 ); 23140 this.morphTargetDictionary[ name ] = m; 23141 23142 } 23143 23144 } 23145 23146 } 23147 23148 } 23149 23150 /** 23151 * Returns the local-space position of the vertex at the given index, taking into 23152 * account the current animation state of both morph targets and skinning. 23153 * 23154 * @param {number} index - The vertex index. 23155 * @param {Vector3} target - The target object that is used to store the method's result. 23156 * @return {Vector3} The vertex position in local space. 23157 */ 23158 getVertexPosition( index, target ) { 23159 23160 const geometry = this.geometry; 23161 const position = geometry.attributes.position; 23162 const morphPosition = geometry.morphAttributes.position; 23163 const morphTargetsRelative = geometry.morphTargetsRelative; 23164 23165 target.fromBufferAttribute( position, index ); 23166 23167 const morphInfluences = this.morphTargetInfluences; 23168 23169 if ( morphPosition && morphInfluences ) { 23170 23171 _morphA.set( 0, 0, 0 ); 23172 23173 for ( let i = 0, il = morphPosition.length; i < il; i ++ ) { 23174 23175 const influence = morphInfluences[ i ]; 23176 const morphAttribute = morphPosition[ i ]; 23177 23178 if ( influence === 0 ) continue; 23179 23180 _tempA.fromBufferAttribute( morphAttribute, index ); 23181 23182 if ( morphTargetsRelative ) { 23183 23184 _morphA.addScaledVector( _tempA, influence ); 23185 23186 } else { 23187 23188 _morphA.addScaledVector( _tempA.sub( target ), influence ); 23189 23190 } 23191 23192 } 23193 23194 target.add( _morphA ); 23195 23196 } 23197 23198 return target; 23199 23200 } 23201 23202 /** 23203 * Computes intersection points between a casted ray and this line. 23204 * 23205 * @param {Raycaster} raycaster - The raycaster. 23206 * @param {Array<Object>} intersects - The target array that holds the intersection points. 23207 */ 23208 raycast( raycaster, intersects ) { 23209 23210 const geometry = this.geometry; 23211 const material = this.material; 23212 const matrixWorld = this.matrixWorld; 23213 23214 if ( material === undefined ) return; 23215 23216 // test with bounding sphere in world space 23217 23218 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); 23219 23220 _sphere$6.copy( geometry.boundingSphere ); 23221 _sphere$6.applyMatrix4( matrixWorld ); 23222 23223 // check distance from ray origin to bounding sphere 23224 23225 _ray$3.copy( raycaster.ray ).recast( raycaster.near ); 23226 23227 if ( _sphere$6.containsPoint( _ray$3.origin ) === false ) { 23228 23229 if ( _ray$3.intersectSphere( _sphere$6, _sphereHitAt ) === null ) return; 23230 23231 if ( _ray$3.origin.distanceToSquared( _sphereHitAt ) > ( raycaster.far - raycaster.near ) ** 2 ) return; 23232 23233 } 23234 23235 // convert ray to local space of mesh 23236 23237 _inverseMatrix$3.copy( matrixWorld ).invert(); 23238 _ray$3.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$3 ); 23239 23240 // test with bounding box in local space 23241 23242 if ( geometry.boundingBox !== null ) { 23243 23244 if ( _ray$3.intersectsBox( geometry.boundingBox ) === false ) return; 23245 23246 } 23247 23248 // test for intersections with geometry 23249 23250 this._computeIntersections( raycaster, intersects, _ray$3 ); 23251 23252 } 23253 23254 _computeIntersections( raycaster, intersects, rayLocalSpace ) { 23255 23256 let intersection; 23257 23258 const geometry = this.geometry; 23259 const material = this.material; 23260 23261 const index = geometry.index; 23262 const position = geometry.attributes.position; 23263 const uv = geometry.attributes.uv; 23264 const uv1 = geometry.attributes.uv1; 23265 const normal = geometry.attributes.normal; 23266 const groups = geometry.groups; 23267 const drawRange = geometry.drawRange; 23268 23269 if ( index !== null ) { 23270 23271 // indexed buffer geometry 23272 23273 if ( Array.isArray( material ) ) { 23274 23275 for ( let i = 0, il = groups.length; i < il; i ++ ) { 23276 23277 const group = groups[ i ]; 23278 const groupMaterial = material[ group.materialIndex ]; 23279 23280 const start = Math.max( group.start, drawRange.start ); 23281 const end = Math.min( index.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) ); 23282 23283 for ( let j = start, jl = end; j < jl; j += 3 ) { 23284 23285 const a = index.getX( j ); 23286 const b = index.getX( j + 1 ); 23287 const c = index.getX( j + 2 ); 23288 23289 intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); 23290 23291 if ( intersection ) { 23292 23293 intersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics 23294 intersection.face.materialIndex = group.materialIndex; 23295 intersects.push( intersection ); 23296 23297 } 23298 23299 } 23300 23301 } 23302 23303 } else { 23304 23305 const start = Math.max( 0, drawRange.start ); 23306 const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); 23307 23308 for ( let i = start, il = end; i < il; i += 3 ) { 23309 23310 const a = index.getX( i ); 23311 const b = index.getX( i + 1 ); 23312 const c = index.getX( i + 2 ); 23313 23314 intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); 23315 23316 if ( intersection ) { 23317 23318 intersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics 23319 intersects.push( intersection ); 23320 23321 } 23322 23323 } 23324 23325 } 23326 23327 } else if ( position !== undefined ) { 23328 23329 // non-indexed buffer geometry 23330 23331 if ( Array.isArray( material ) ) { 23332 23333 for ( let i = 0, il = groups.length; i < il; i ++ ) { 23334 23335 const group = groups[ i ]; 23336 const groupMaterial = material[ group.materialIndex ]; 23337 23338 const start = Math.max( group.start, drawRange.start ); 23339 const end = Math.min( position.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) ); 23340 23341 for ( let j = start, jl = end; j < jl; j += 3 ) { 23342 23343 const a = j; 23344 const b = j + 1; 23345 const c = j + 2; 23346 23347 intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); 23348 23349 if ( intersection ) { 23350 23351 intersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics 23352 intersection.face.materialIndex = group.materialIndex; 23353 intersects.push( intersection ); 23354 23355 } 23356 23357 } 23358 23359 } 23360 23361 } else { 23362 23363 const start = Math.max( 0, drawRange.start ); 23364 const end = Math.min( position.count, ( drawRange.start + drawRange.count ) ); 23365 23366 for ( let i = start, il = end; i < il; i += 3 ) { 23367 23368 const a = i; 23369 const b = i + 1; 23370 const c = i + 2; 23371 23372 intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); 23373 23374 if ( intersection ) { 23375 23376 intersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics 23377 intersects.push( intersection ); 23378 23379 } 23380 23381 } 23382 23383 } 23384 23385 } 23386 23387 } 23388 23389} 23390 23391function checkIntersection$1( object, material, raycaster, ray, pA, pB, pC, point ) { 23392 23393 let intersect; 23394 23395 if ( material.side === BackSide ) { 23396 23397 intersect = ray.intersectTriangle( pC, pB, pA, true, point ); 23398 23399 } else { 23400 23401 intersect = ray.intersectTriangle( pA, pB, pC, ( material.side === FrontSide ), point ); 23402 23403 } 23404 23405 if ( intersect === null ) return null; 23406 23407 _intersectionPointWorld.copy( point ); 23408 _intersectionPointWorld.applyMatrix4( object.matrixWorld ); 23409 23410 const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld ); 23411 23412 if ( distance < raycaster.near || distance > raycaster.far ) return null; 23413 23414 return { 23415 distance: distance, 23416 point: _intersectionPointWorld.clone(), 23417 object: object 23418 }; 23419 23420} 23421 23422function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, normal, a, b, c ) { 23423 23424 object.getVertexPosition( a, _vA ); 23425 object.getVertexPosition( b, _vB ); 23426 object.getVertexPosition( c, _vC ); 23427 23428 const intersection = checkIntersection$1( object, material, raycaster, ray, _vA, _vB, _vC, _intersectionPoint ); 23429 23430 if ( intersection ) { 23431 23432 const barycoord = new Vector3(); 23433 Triangle.getBarycoord( _intersectionPoint, _vA, _vB, _vC, barycoord ); 23434 23435 if ( uv ) { 23436 23437 intersection.uv = Triangle.getInterpolatedAttribute( uv, a, b, c, barycoord, new Vector2() ); 23438 23439 } 23440 23441 if ( uv1 ) { 23442 23443 intersection.uv1 = Triangle.getInterpolatedAttribute( uv1, a, b, c, barycoord, new Vector2() ); 23444 23445 } 23446 23447 if ( normal ) { 23448
vendor: 13,640 bytes, lines 23449-24021
23449 intersection.normal = Triangle.getInterpolatedAttribute( normal, a, b, c, barycoord, new Vector3() ); 23450 23451 if ( intersection.normal.dot( ray.direction ) > 0 ) { 23452 23453 intersection.normal.multiplyScalar( -1 ); 23454 23455 } 23456 23457 } 23458 23459 const face = { 23460 a: a, 23461 b: b, 23462 c: c, 23463 normal: new Vector3(), 23464 materialIndex: 0 23465 }; 23466 23467 Triangle.getNormal( _vA, _vB, _vC, face.normal ); 23468 23469 intersection.face = face; 23470 intersection.barycoord = barycoord; 23471 23472 } 23473 23474 return intersection; 23475 23476} 23477 23478const _baseVector = /*@__PURE__*/ new Vector4(); 23479 23480const _skinIndex = /*@__PURE__*/ new Vector4(); 23481const _skinWeight = /*@__PURE__*/ new Vector4(); 23482 23483const _vector4 = /*@__PURE__*/ new Vector4(); 23484const _matrix4 = /*@__PURE__*/ new Matrix4(); 23485const _vertex = /*@__PURE__*/ new Vector3(); 23486 23487const _sphere$5 = /*@__PURE__*/ new Sphere(); 23488const _inverseMatrix$2 = /*@__PURE__*/ new Matrix4(); 23489const _ray$2 = /*@__PURE__*/ new Ray(); 23490 23491/** 23492 * A mesh that has a {@link Skeleton} that can then be used to animate the 23493 * vertices of the geometry with skinning/skeleton animation. 23494 * 23495 * Next to a valid skeleton, the skinned mesh requires skin indices and weights 23496 * as buffer attributes in its geometry. These attribute define which bones affect a single 23497 * vertex to a certain extend. 23498 * 23499 * Typically skinned meshes are not created manually but loaders like {@link GLTFLoader} 23500 * or {@link FBXLoader } import respective models. 23501 * 23502 * @augments Mesh 23503 * @demo scenes/bones-browser.html 23504 */ 23505class SkinnedMesh extends Mesh { 23506 23507 /** 23508 * Constructs a new skinned mesh. 23509 * 23510 * @param {BufferGeometry} [geometry] - The mesh geometry. 23511 * @param {Material|Array<Material>} [material] - The mesh material. 23512 */ 23513 constructor( geometry, material ) { 23514 23515 super( geometry, material ); 23516 23517 /** 23518 * This flag can be used for type testing. 23519 * 23520 * @type {boolean} 23521 * @readonly 23522 * @default true 23523 */ 23524 this.isSkinnedMesh = true; 23525 23526 this.type = 'SkinnedMesh'; 23527 23528 /** 23529 * `AttachedBindMode` means the skinned mesh shares the same world space as the skeleton. 23530 * This is not true when using `DetachedBindMode` which is useful when sharing a skeleton 23531 * across multiple skinned meshes. 23532 * 23533 * @type {(AttachedBindMode|DetachedBindMode)} 23534 * @default AttachedBindMode 23535 */ 23536 this.bindMode = AttachedBindMode; 23537 23538 /** 23539 * The base matrix that is used for the bound bone transforms. 23540 * 23541 * @type {Matrix4} 23542 */ 23543 this.bindMatrix = new Matrix4(); 23544 23545 /** 23546 * The base matrix that is used for resetting the bound bone transforms. 23547 * 23548 * @type {Matrix4} 23549 */ 23550 this.bindMatrixInverse = new Matrix4(); 23551 23552 /** 23553 * The bounding box of the skinned mesh. Can be computed via {@link SkinnedMesh#computeBoundingBox}. 23554 * 23555 * @type {?Box3} 23556 * @default null 23557 */ 23558 this.boundingBox = null; 23559 23560 /** 23561 * The bounding sphere of the skinned mesh. Can be computed via {@link SkinnedMesh#computeBoundingSphere}. 23562 * 23563 * @type {?Sphere} 23564 * @default null 23565 */ 23566 this.boundingSphere = null; 23567 23568 } 23569 23570 /** 23571 * Computes the bounding box of the skinned mesh, and updates {@link SkinnedMesh#boundingBox}. 23572 * The bounding box is not automatically computed by the engine; this method must be called by your app. 23573 * If the skinned mesh is animated, the bounding box should be recomputed per frame in order to reflect 23574 * the current animation state. 23575 */ 23576 computeBoundingBox() { 23577 23578 const geometry = this.geometry; 23579 23580 if ( this.boundingBox === null ) { 23581 23582 this.boundingBox = new Box3(); 23583 23584 } 23585 23586 this.boundingBox.makeEmpty(); 23587 23588 const positionAttribute = geometry.getAttribute( 'position' ); 23589 23590 for ( let i = 0; i < positionAttribute.count; i ++ ) { 23591 23592 this.getVertexPosition( i, _vertex ); 23593 this.boundingBox.expandByPoint( _vertex ); 23594 23595 } 23596 23597 } 23598 23599 /** 23600 * Computes the bounding sphere of the skinned mesh, and updates {@link SkinnedMesh#boundingSphere}. 23601 * The bounding sphere is automatically computed by the engine once when it is needed, e.g., for ray casting 23602 * and view frustum culling. If the skinned mesh is animated, the bounding sphere should be recomputed 23603 * per frame in order to reflect the current animation state. 23604 */ 23605 computeBoundingSphere() { 23606 23607 const geometry = this.geometry; 23608 23609 if ( this.boundingSphere === null ) { 23610 23611 this.boundingSphere = new Sphere(); 23612 23613 } 23614 23615 this.boundingSphere.makeEmpty(); 23616 23617 const positionAttribute = geometry.getAttribute( 'position' ); 23618 23619 for ( let i = 0; i < positionAttribute.count; i ++ ) { 23620 23621 this.getVertexPosition( i, _vertex ); 23622 this.boundingSphere.expandByPoint( _vertex ); 23623 23624 } 23625 23626 } 23627 23628 copy( source, recursive ) { 23629 23630 super.copy( source, recursive ); 23631 23632 this.bindMode = source.bindMode; 23633 this.bindMatrix.copy( source.bindMatrix ); 23634 this.bindMatrixInverse.copy( source.bindMatrixInverse ); 23635 23636 this.skeleton = source.skeleton; 23637 23638 if ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone(); 23639 if ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone(); 23640 23641 return this; 23642 23643 } 23644 23645 raycast( raycaster, intersects ) { 23646 23647 const material = this.material; 23648 const matrixWorld = this.matrixWorld; 23649 23650 if ( material === undefined ) return; 23651 23652 // test with bounding sphere in world space 23653 23654 if ( this.boundingSphere === null ) this.computeBoundingSphere(); 23655 23656 _sphere$5.copy( this.boundingSphere ); 23657 _sphere$5.applyMatrix4( matrixWorld ); 23658 23659 if ( raycaster.ray.intersectsSphere( _sphere$5 ) === false ) return; 23660 23661 // convert ray to local space of skinned mesh 23662 23663 _inverseMatrix$2.copy( matrixWorld ).invert(); 23664 _ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 ); 23665 23666 // test with bounding box in local space 23667 23668 if ( this.boundingBox !== null ) { 23669 23670 if ( _ray$2.intersectsBox( this.boundingBox ) === false ) return; 23671 23672 } 23673 23674 // test for intersections with geometry 23675 23676 this._computeIntersections( raycaster, intersects, _ray$2 ); 23677 23678 } 23679 23680 getVertexPosition( index, target ) { 23681 23682 super.getVertexPosition( index, target ); 23683 23684 this.applyBoneTransform( index, target ); 23685 23686 return target; 23687 23688 } 23689 23690 /** 23691 * Binds the given skeleton to the skinned mesh. 23692 * 23693 * @param {Skeleton} skeleton - The skeleton to bind. 23694 * @param {Matrix4} [bindMatrix] - The bind matrix. If no bind matrix is provided, 23695 * the skinned mesh's world matrix will be used instead. 23696 */ 23697 bind( skeleton, bindMatrix ) { 23698 23699 this.skeleton = skeleton; 23700 23701 if ( bindMatrix === undefined ) { 23702 23703 this.updateMatrixWorld( true ); 23704 23705 this.skeleton.calculateInverses(); 23706 23707 bindMatrix = this.matrixWorld; 23708 23709 } 23710 23711 this.bindMatrix.copy( bindMatrix ); 23712 this.bindMatrixInverse.copy( bindMatrix ).invert(); 23713 23714 } 23715 23716 /** 23717 * This method sets the skinned mesh in the rest pose). 23718 */ 23719 pose() { 23720 23721 this.skeleton.pose(); 23722 23723 } 23724 23725 /** 23726 * Normalizes the skin weights which are defined as a buffer attribute 23727 * in the skinned mesh's geometry. 23728 */ 23729 normalizeSkinWeights() { 23730 23731 const vector = new Vector4(); 23732 23733 const skinWeight = this.geometry.attributes.skinWeight; 23734 23735 for ( let i = 0, l = skinWeight.count; i < l; i ++ ) { 23736 23737 vector.fromBufferAttribute( skinWeight, i ); 23738 23739 const scale = 1.0 / vector.manhattanLength(); 23740 23741 if ( scale !== Infinity ) { 23742 23743 vector.multiplyScalar( scale ); 23744 23745 } else { 23746 23747 vector.set( 1, 0, 0, 0 ); // do something reasonable 23748 23749 } 23750 23751 skinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w ); 23752 23753 } 23754 23755 } 23756 23757 updateMatrixWorld( force ) { 23758 23759 super.updateMatrixWorld( force ); 23760 23761 if ( this.bindMode === AttachedBindMode ) { 23762 23763 this.bindMatrixInverse.copy( this.matrixWorld ).invert(); 23764 23765 } else if ( this.bindMode === DetachedBindMode ) { 23766 23767 this.bindMatrixInverse.copy( this.bindMatrix ).invert(); 23768 23769 } else { 23770 23771 warn( 'SkinnedMesh: Unrecognized bindMode: ' + this.bindMode ); 23772 23773 } 23774 23775 } 23776 23777 /** 23778 * Applies the bone transform associated with the given index to the given 23779 * vector. Can be used to transform positions or direction vectors by providing 23780 * a Vector4 with 1 or 0 in the w component respectively. Returns the updated vector. 23781 * 23782 * @param {number} index - The vertex index. 23783 * @param {Vector3|Vector4} target - The target object that is used to store the method's result. 23784 * @return {Vector3|Vector4} The updated vertex attribute data. 23785 */ 23786 applyBoneTransform( index, target ) { 23787 23788 const skeleton = this.skeleton; 23789 const geometry = this.geometry; 23790 23791 _skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index ); 23792 _skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index ); 23793 23794 if ( target.isVector4 ) { 23795 23796 _baseVector.copy( target ); 23797 target.set( 0, 0, 0, 0 ); 23798 23799 } else { 23800 23801 _baseVector.set( ...target, 1 ); 23802 target.set( 0, 0, 0 ); 23803 23804 } 23805 23806 _baseVector.applyMatrix4( this.bindMatrix ); 23807 23808 for ( let i = 0; i < 4; i ++ ) { 23809 23810 const weight = _skinWeight.getComponent( i ); 23811 23812 if ( weight !== 0 ) { 23813 23814 const boneIndex = _skinIndex.getComponent( i ); 23815 23816 _matrix4.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] ); 23817 23818 target.addScaledVector( _vector4.copy( _baseVector ).applyMatrix4( _matrix4 ), weight ); 23819 23820 } 23821 23822 } 23823 23824 if ( target.isVector4 ) { 23825 23826 // ensure the homogenous coordinate remains unchanged after vector operations 23827 target.w = _baseVector.w; 23828 23829 } 23830 23831 return target.applyMatrix4( this.bindMatrixInverse ); 23832 23833 } 23834 23835} 23836 23837/** 23838 * A bone which is part of a {@link Skeleton}. The skeleton in turn is used by 23839 * the {@link SkinnedMesh}. 23840 * 23841 * ```js 23842 * const root = new THREE.Bone(); 23843 * const child = new THREE.Bone(); 23844 * 23845 * root.add( child ); 23846 * child.position.y = 5; 23847 * ``` 23848 * 23849 * @augments Object3D 23850 */ 23851class Bone extends Object3D { 23852 23853 /** 23854 * Constructs a new bone. 23855 */ 23856 constructor() { 23857 23858 super(); 23859 23860 /** 23861 * This flag can be used for type testing. 23862 * 23863 * @type {boolean} 23864 * @readonly 23865 * @default true 23866 */ 23867 this.isBone = true; 23868 23869 this.type = 'Bone'; 23870 23871 } 23872 23873} 23874 23875/** 23876 * Creates a texture directly from raw buffer data. 23877 * 23878 * The interpretation of the data depends on type and format: If the type is 23879 * `UnsignedByteType`, a `Uint8Array` will be useful for addressing the 23880 * texel data. If the format is `RGBAFormat`, data needs four values for 23881 * one texel; Red, Green, Blue and Alpha (typically the opacity). 23882 * 23883 * @augments Texture 23884 */ 23885class DataTexture extends Texture { 23886 23887 /** 23888 * Constructs a new data texture. 23889 * 23890 * @param {?TypedArray} [data=null] - The buffer data. 23891 * @param {number} [width=1] - The width of the texture. 23892 * @param {number} [height=1] - The height of the texture. 23893 * @param {number} [format=RGBAFormat] - The texture format. 23894 * @param {number} [type=UnsignedByteType] - The texture type. 23895 * @param {number} [mapping=Texture.DEFAULT_MAPPING] - The texture mapping. 23896 * @param {number} [wrapS=ClampToEdgeWrapping] - The wrapS value. 23897 * @param {number} [wrapT=ClampToEdgeWrapping] - The wrapT value. 23898 * @param {number} [magFilter=NearestFilter] - The mag filter value. 23899 * @param {number} [minFilter=NearestFilter] - The min filter value. 23900 * @param {number} [anisotropy=Texture.DEFAULT_ANISOTROPY] - The anisotropy value. 23901 * @param {string} [colorSpace=NoColorSpace] - The color space. 23902 */ 23903 constructor( data = null, width = 1, height = 1, format, type, mapping, wrapS, wrapT, magFilter = NearestFilter, minFilter = NearestFilter, anisotropy, colorSpace ) { 23904 23905 super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ); 23906 23907 /** 23908 * This flag can be used for type testing. 23909 * 23910 * @type {boolean} 23911 * @readonly 23912 * @default true 23913 */ 23914 this.isDataTexture = true; 23915 23916 /** 23917 * The image definition of a data texture. 23918 * 23919 * @type {{data:TypedArray,width:number,height:number}} 23920 */ 23921 this.image = { data: data, width: width, height: height }; 23922 23923 /** 23924 * Whether to generate mipmaps (if possible) for a texture. 23925 * 23926 * Overwritten and set to `false` by default. 23927 * 23928 * @type {boolean} 23929 * @default false 23930 */ 23931 this.generateMipmaps = false; 23932 23933 /** 23934 * If set to `true`, the texture is flipped along the vertical axis when 23935 * uploaded to the GPU. 23936 * 23937 * Overwritten and set to `false` by default. 23938 * 23939 * @type {boolean} 23940 * @default false 23941 */ 23942 this.flipY = false; 23943 23944 /** 23945 * Specifies the alignment requirements for the start of each pixel row in memory. 23946 * 23947 * Overwritten and set to `1` by default. 23948 * 23949 * @type {boolean} 23950 * @default 1 23951 */ 23952 this.unpackAlignment = 1; 23953 23954 } 23955 23956} 23957 23958const _offsetMatrix = /*@__PURE__*/ new Matrix4(); 23959const _identityMatrix = /*@__PURE__*/ new Matrix4(); 23960 23961/** 23962 * Class for representing the armatures in `three.js`. The skeleton 23963 * is defined by a hierarchy of bones. 23964 * 23965 * ```js 23966 * const bones = []; 23967 * 23968 * const shoulder = new THREE.Bone(); 23969 * const elbow = new THREE.Bone(); 23970 * const hand = new THREE.Bone(); 23971 * 23972 * shoulder.add( elbow ); 23973 * elbow.add( hand ); 23974 * 23975 * bones.push( shoulder , elbow, hand); 23976 * 23977 * shoulder.position.y = -5; 23978 * elbow.position.y = 0; 23979 * hand.position.y = 5; 23980 * 23981 * const armSkeleton = new THREE.Skeleton( bones ); 23982 * ``` 23983 */ 23984class Skeleton { 23985 23986 /** 23987 * Constructs a new skeleton. 23988 * 23989 * @param {Array<Bone>} [bones] - An array of bones. 23990 * @param {Array<Matrix4>} [boneInverses] - An array of bone inverse matrices. 23991 * If not provided, these matrices will be computed automatically via {@link Skeleton#calculateInverses}. 23992 */ 23993 constructor( bones = [], boneInverses = [] ) { 23994 23995 this.uuid = generateUUID(); 23996 23997 /** 23998 * An array of bones defining the skeleton. 23999 * 24000 * @type {Array<Bone>} 24001 */ 24002 this.bones = bones.slice( 0 ); 24003 24004 /** 24005 * An array of bone inverse matrices. 24006 * 24007 * @type {Array<Matrix4>} 24008 */ 24009 this.boneInverses = boneInverses; 24010 24011 /** 24012 * An array buffer holding the bone data. 24013 * Input data for {@link Skeleton#boneTexture}. 24014 * 24015 * @type {?Float32Array} 24016 * @default null 24017 */ 24018 this.boneMatrices = null; 24019 24020 /** 24021 * A
vendor: 10,843 bytes, lines 24021-24513
24021n array buffer holding the bone data of the previous frame. 24022 * Required for computing velocity. Maintained in {@link SkinningNode}. 24023 * 24024 * @type {?Float32Array} 24025 * @default null 24026 */ 24027 this.previousBoneMatrices = null; 24028 24029 /** 24030 * A texture holding the bone data for use 24031 * in the vertex shader. 24032 * 24033 * @type {?DataTexture} 24034 * @default null 24035 */ 24036 this.boneTexture = null; 24037 24038 this.init(); 24039 24040 } 24041 24042 /** 24043 * Initializes the skeleton. This method gets automatically called by the constructor 24044 * but depending on how the skeleton is created it might be necessary to call this method 24045 * manually. 24046 */ 24047 init() { 24048 24049 const bones = this.bones; 24050 const boneInverses = this.boneInverses; 24051 24052 this.boneMatrices = new Float32Array( bones.length * 16 ); 24053 24054 // calculate inverse bone matrices if necessary 24055 24056 if ( boneInverses.length === 0 ) { 24057 24058 this.calculateInverses(); 24059 24060 } else { 24061 24062 // handle special case 24063 24064 if ( bones.length !== boneInverses.length ) { 24065 24066 warn( 'Skeleton: Number of inverse bone matrices does not match amount of bones.' ); 24067 24068 this.boneInverses = []; 24069 24070 for ( let i = 0, il = this.bones.length; i < il; i ++ ) { 24071 24072 this.boneInverses.push( new Matrix4() ); 24073 24074 } 24075 24076 } 24077 24078 } 24079 24080 } 24081 24082 /** 24083 * Computes the bone inverse matrices. This method resets {@link Skeleton#boneInverses} 24084 * and fills it with new matrices. 24085 */ 24086 calculateInverses() { 24087 24088 this.boneInverses.length = 0; 24089 24090 for ( let i = 0, il = this.bones.length; i < il; i ++ ) { 24091 24092 const inverse = new Matrix4(); 24093 24094 if ( this.bones[ i ] ) { 24095 24096 inverse.copy( this.bones[ i ].matrixWorld ).invert(); 24097 24098 } 24099 24100 this.boneInverses.push( inverse ); 24101 24102 } 24103 24104 } 24105 24106 /** 24107 * Resets the skeleton to the base pose. 24108 */ 24109 pose() { 24110 24111 // recover the bind-time world matrices 24112 24113 for ( let i = 0, il = this.bones.length; i < il; i ++ ) { 24114 24115 const bone = this.bones[ i ]; 24116 24117 if ( bone ) { 24118 24119 bone.matrixWorld.copy( this.boneInverses[ i ] ).invert(); 24120 24121 } 24122 24123 } 24124 24125 // compute the local matrices, positions, rotations and scales 24126 24127 for ( let i = 0, il = this.bones.length; i < il; i ++ ) { 24128 24129 const bone = this.bones[ i ]; 24130 24131 if ( bone ) { 24132 24133 if ( bone.parent && bone.parent.isBone ) { 24134 24135 bone.matrix.copy( bone.parent.matrixWorld ).invert(); 24136 bone.matrix.multiply( bone.matrixWorld ); 24137 24138 } else { 24139 24140 bone.matrix.copy( bone.matrixWorld ); 24141 24142 } 24143 24144 bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); 24145 24146 } 24147 24148 } 24149 24150 } 24151 24152 /** 24153 * Resets the skeleton to the base pose. 24154 */ 24155 update() { 24156 24157 const bones = this.bones; 24158 const boneInverses = this.boneInverses; 24159 const boneMatrices = this.boneMatrices; 24160 const boneTexture = this.boneTexture; 24161 24162 // flatten bone matrices to array 24163 24164 for ( let i = 0, il = bones.length; i < il; i ++ ) { 24165 24166 // compute the offset between the current and the original transform 24167 24168 const matrix = bones[ i ] ? bones[ i ].matrixWorld : _identityMatrix; 24169 24170 _offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] ); 24171 _offsetMatrix.toArray( boneMatrices, i * 16 ); 24172 24173 } 24174 24175 if ( boneTexture !== null ) { 24176 24177 boneTexture.needsUpdate = true; 24178 24179 } 24180 24181 } 24182 24183 /** 24184 * Returns a new skeleton with copied values from this instance. 24185 * 24186 * @return {Skeleton} A clone of this instance. 24187 */ 24188 clone() { 24189 24190 return new Skeleton( this.bones, this.boneInverses ); 24191 24192 } 24193 24194 /** 24195 * Computes a data texture for passing bone data to the vertex shader. 24196 * 24197 * @return {Skeleton} A reference of this instance. 24198 */ 24199 computeBoneTexture() { 24200 24201 // layout (1 matrix = 4 pixels) 24202 // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) 24203 // with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8) 24204 // 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16) 24205 // 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32) 24206 // 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64) 24207 24208 let size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix 24209 size = Math.ceil( size / 4 ) * 4; 24210 size = Math.max( size, 4 ); 24211 24212 const boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel 24213 boneMatrices.set( this.boneMatrices ); // copy current values 24214 24215 const boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType ); 24216 boneTexture.needsUpdate = true; 24217 24218 this.boneMatrices = boneMatrices; 24219 this.boneTexture = boneTexture; 24220 24221 return this; 24222 24223 } 24224 24225 /** 24226 * Searches through the skeleton's bone array and returns the first with a 24227 * matching name. 24228 * 24229 * @param {string} name - The name of the bone. 24230 * @return {Bone|undefined} The found bone. `undefined` if no bone has been found. 24231 */ 24232 getBoneByName( name ) { 24233 24234 for ( let i = 0, il = this.bones.length; i < il; i ++ ) { 24235 24236 const bone = this.bones[ i ]; 24237 24238 if ( bone.name === name ) { 24239 24240 return bone; 24241 24242 } 24243 24244 } 24245 24246 return undefined; 24247 24248 } 24249 24250 /** 24251 * Frees the GPU-related resources allocated by this instance. Call this 24252 * method whenever this instance is no longer used in your app. 24253 */ 24254 dispose( ) { 24255 24256 if ( this.boneTexture !== null ) { 24257 24258 this.boneTexture.dispose(); 24259 24260 this.boneTexture = null; 24261 24262 } 24263 24264 } 24265 24266 /** 24267 * Setups the skeleton by the given JSON and bones. 24268 * 24269 * @param {Object} json - The skeleton as serialized JSON. 24270 * @param {Object<string, Bone>} bones - An array of bones. 24271 * @return {Skeleton} A reference of this instance. 24272 */ 24273 fromJSON( json, bones ) { 24274 24275 this.uuid = json.uuid; 24276 24277 for ( let i = 0, l = json.bones.length; i < l; i ++ ) { 24278 24279 const uuid = json.bones[ i ]; 24280 let bone = bones[ uuid ]; 24281 24282 if ( bone === undefined ) { 24283 24284 warn( 'Skeleton: No bone found with UUID:', uuid ); 24285 bone = new Bone(); 24286 24287 } 24288 24289 this.bones.push( bone ); 24290 this.boneInverses.push( new Matrix4().fromArray( json.boneInverses[ i ] ) ); 24291 24292 } 24293 24294 this.init(); 24295 24296 return this; 24297 24298 } 24299 24300 /** 24301 * Serializes the skeleton into JSON. 24302 * 24303 * @return {Object} A JSON object representing the serialized skeleton. 24304 * @see {@link ObjectLoader#parse} 24305 */ 24306 toJSON() { 24307 24308 const data = { 24309 metadata: { 24310 version: 4.7, 24311 type: 'Skeleton', 24312 generator: 'Skeleton.toJSON' 24313 }, 24314 bones: [], 24315 boneInverses: [] 24316 }; 24317 24318 data.uuid = this.uuid; 24319 24320 const bones = this.bones; 24321 const boneInverses = this.boneInverses; 24322 24323 for ( let i = 0, l = bones.length; i < l; i ++ ) { 24324 24325 const bone = bones[ i ]; 24326 data.bones.push( bone.uuid ); 24327 24328 const boneInverse = boneInverses[ i ]; 24329 data.boneInverses.push( boneInverse.toArray() ); 24330 24331 } 24332 24333 return data; 24334 24335 } 24336 24337} 24338 24339/** 24340 * An instanced version of a buffer attribute. 24341 * 24342 * @augments BufferAttribute 24343 */ 24344class InstancedBufferAttribute extends BufferAttribute { 24345 24346 /** 24347 * Constructs a new instanced buffer attribute. 24348 * 24349 * @param {TypedArray} array - The array holding the attribute data. 24350 * @param {number} itemSize - The item size. 24351 * @param {boolean} [normalized=false] - Whether the data are normalized or not. 24352 * @param {number} [meshPerAttribute=1] - How often a value of this buffer attribute should be repeated. 24353 */ 24354 constructor( array, itemSize, normalized, meshPerAttribute = 1 ) { 24355 24356 super( array, itemSize, normalized ); 24357 24358 /** 24359 * This flag can be used for type testing. 24360 * 24361 * @type {boolean} 24362 * @readonly 24363 * @default true 24364 */ 24365 this.isInstancedBufferAttribute = true; 24366 24367 /** 24368 * Defines how often a value of this buffer attribute should be repeated. A 24369 * value of one means that each value of the instanced attribute is used for 24370 * a single instance. A value of two means that each value is used for two 24371 * consecutive instances (and so on). 24372 * 24373 * @type {number} 24374 * @default 1 24375 */ 24376 this.meshPerAttribute = meshPerAttribute; 24377 24378 } 24379 24380 copy( source ) { 24381 24382 super.copy( source ); 24383 24384 this.meshPerAttribute = source.meshPerAttribute; 24385 24386 return this; 24387 24388 } 24389 24390 toJSON() { 24391 24392 const data = super.toJSON(); 24393 24394 data.meshPerAttribute = this.meshPerAttribute; 24395 24396 data.isInstancedBufferAttribute = true; 24397 24398 return data; 24399 24400 } 24401 24402} 24403 24404const _instanceLocalMatrix = /*@__PURE__*/ new Matrix4(); 24405const _instanceWorldMatrix = /*@__PURE__*/ new Matrix4(); 24406 24407const _instanceIntersects = []; 24408 24409const _box3 = /*@__PURE__*/ new Box3(); 24410const _identity = /*@__PURE__*/ new Matrix4(); 24411const _mesh$1 = /*@__PURE__*/ new Mesh(); 24412const _sphere$4 = /*@__PURE__*/ new Sphere(); 24413 24414/** 24415 * A special version of a mesh with instanced rendering support. Use 24416 * this class if you have to render a large number of objects with the same 24417 * geometry and material(s) but with different world transformations. The usage 24418 * of 'InstancedMesh' will help you to reduce the number of draw calls and thus 24419 * improve the overall rendering performance in your application. 24420 * 24421 * @augments Mesh 24422 */ 24423class InstancedMesh extends Mesh { 24424 24425 /** 24426 * Constructs a new instanced mesh. 24427 * 24428 * @param {BufferGeometry} [geometry] - The mesh geometry. 24429 * @param {Material|Array<Material>} [material] - The mesh material. 24430 * @param {number} count - The number of instances. 24431 */ 24432 constructor( geometry, material, count ) { 24433 24434 super( geometry, material ); 24435 24436 /** 24437 * This flag can be used for type testing. 24438 * 24439 * @type {boolean} 24440 * @readonly 24441 * @default true 24442 */ 24443 this.isInstancedMesh = true; 24444 24445 /** 24446 * Represents the local transformation of all instances. You have to set its 24447 * {@link BufferAttribute#needsUpdate} flag to true if you modify instanced data 24448 * via {@link InstancedMesh#setMatrixAt}. 24449 * 24450 * @type {InstancedBufferAttribute} 24451 */ 24452 this.instanceMatrix = new InstancedBufferAttribute( new Float32Array( count * 16 ), 16 ); 24453 24454 /** 24455 * Represents the local transformation of all instances of the previous frame. 24456 * Required for computing velocity. Maintained in {@link InstanceNode}. 24457 * 24458 * @type {?InstancedBufferAttribute} 24459 * @default null 24460 */ 24461 this.previousInstanceMatrix = null; 24462 24463 /** 24464 * Represents the color of all instances. You have to set its 24465 * {@link BufferAttribute#needsUpdate} flag to true if you modify instanced data 24466 * via {@link InstancedMesh#setColorAt}. 24467 * 24468 * @type {?InstancedBufferAttribute} 24469 * @default null 24470 */ 24471 this.instanceColor = null; 24472 24473 /** 24474 * Represents the morph target weights of all instances. You have to set its 24475 * {@link Texture#needsUpdate} flag to true if you modify instanced data 24476 * via {@link InstancedMesh#setMorphAt}. 24477 * 24478 * @type {?DataTexture} 24479 * @default null 24480 */ 24481 this.morphTexture = null; 24482 24483 /** 24484 * The number of instances. 24485 * 24486 * @type {number} 24487 */ 24488 this.count = count; 24489 24490 /** 24491 * The bounding box of the instanced mesh. Can be computed via {@link InstancedMesh#computeBoundingBox}. 24492 * 24493 * @type {?Box3} 24494 * @default null 24495 */ 24496 this.boundingBox = null; 24497 24498 /** 24499 * The bounding sphere of the instanced mesh. Can be computed via {@link InstancedMesh#computeBoundingSphere}. 24500 * 24501 * @type {?Sphere} 24502 * @default null 24503 */ 24504 this.boundingSphere = null; 24505 24506 for ( let i = 0; i < count; i ++ ) { 24507 24508 this.setMatrixAt( i, _identity ); 24509 24510 } 24511 24512 } 24513
24514 /** 24515 * Computes the bounding box of the instanced mesh, and updates {@link InstancedMesh#boundingBox}. 24516 * The bounding box is not automatically computed by the engine; this method must be called by your app. 24517 * You may need to recompute the bounding box if an instance is transformed via {@link InstancedMesh#setMatrixAt}. 24518 */ 24519 computeBoundingBox() { 24520 24521 const geometry = this.geometry; 24522 const count = this.count; 24523 24524 if ( this.boundingBox === null ) { 24525 24526 this.boundingBox = new Box3(); 24527 24528 } 24529 24530 if ( geometry.boundingBox === null ) { 24531 24532 geometry.computeBoundingBox(); 24533 24534 } 24535 24536 this.boundingBox.makeEmpty(); 24537 24538 for ( let i = 0; i < count; i ++ ) { 24539 24540 this.getMatrixAt( i, _instanceLocalMatrix ); 24541 24542 _box3.copy( geometry.boundingBox ).applyMatrix4( _instanceLocalMatrix ); 24543 24544 this.boundingBox.union( _box3 ); 24545 24546 } 24547 24548 } 24549 24550 /** 24551 * Computes the bounding sphere of the instanced mesh, and updates {@link InstancedMesh#boundingSphere} 24552 * The engine automatically computes the bounding sphere when it is needed, e.g., for ray casting or view frustum culling. 24553 * You may need to recompute the bounding sphere if an instance is transformed via {@link InstancedMesh#setMatrixAt}. 24554 */ 24555 computeBoundingSphere() { 24556 24557 const geometry = this.geometry; 24558 const count = this.count; 24559 24560 if ( this.boundingSphere === null ) { 24561 24562 this.boundingSphere = new Sphere(); 24563 24564 } 24565 24566 if ( geometry.boundingSphere === null ) { 24567 24568 geometry.computeBoundingSphere(); 24569 24570 } 24571 24572 this.boundingSphere.makeEmpty(); 24573 24574 for ( let i = 0; i < count; i ++ ) { 24575 24576 this.getMatrixAt( i, _instanceLocalMatrix ); 24577 24578 _sphere$4.copy( geometry.boundingSphere ).applyMatrix4( _instanceLocalMatrix ); 24579 24580 this.boundingSphere.union( _sphere$4 ); 24581 24582 } 24583 24584 } 24585 24586 copy( source, recursive ) { 24587 24588 super.copy( source, recursive ); 24589 24590 this.instanceMatrix.copy( source.instanceMatrix ); 24591 24592 if ( source.previousInstanceMatrix !== null ) this.previousInstanceMatrix = source.previousInstanceMatrix.clone(
vendor: 5,489 bytes, lines 24592-24797
24592); 24593 24594 if ( source.morphTexture !== null ) this.morphTexture = source.morphTexture.clone(); 24595 if ( source.instanceColor !== null ) this.instanceColor = source.instanceColor.clone(); 24596 24597 this.count = source.count; 24598 24599 if ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone(); 24600 if ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone(); 24601 24602 return this; 24603 24604 } 24605 24606 /** 24607 * Gets the color of the defined instance. 24608 * 24609 * @param {number} index - The instance index. 24610 * @param {Color} color - The target object that is used to store the method's result. 24611 * @return {Color} A reference to the target color. 24612 */ 24613 getColorAt( index, color ) { 24614 24615 if ( this.instanceColor === null ) { 24616 24617 return color.setRGB( 1, 1, 1 ); 24618 24619 } else { 24620 24621 return color.fromArray( this.instanceColor.array, index * 3 ); 24622 24623 } 24624 24625 } 24626 24627 /** 24628 * Gets the local transformation matrix of the defined instance. 24629 * 24630 * @param {number} index - The instance index. 24631 * @param {Matrix4} matrix - The target object that is used to store the method's result. 24632 * @return {Matrix4} A reference to the target matrix. 24633 */ 24634 getMatrixAt( index, matrix ) { 24635 24636 return matrix.fromArray( this.instanceMatrix.array, index * 16 ); 24637 24638 } 24639 24640 /** 24641 * Gets the morph target weights of the defined instance. 24642 * 24643 * @param {number} index - The instance index. 24644 * @param {Mesh} object - The target object that is used to store the method's result. 24645 */ 24646 getMorphAt( index, object ) { 24647 24648 const objectInfluences = object.morphTargetInfluences; 24649 24650 const array = this.morphTexture.source.data.data; 24651 24652 const len = objectInfluences.length + 1; // All influences + the baseInfluenceSum 24653 24654 const dataIndex = index * len + 1; // Skip the baseInfluenceSum at the beginning 24655 24656 for ( let i = 0; i < objectInfluences.length; i ++ ) { 24657 24658 objectInfluences[ i ] = array[ dataIndex + i ]; 24659 24660 } 24661 24662 } 24663 24664 raycast( raycaster, intersects ) { 24665 24666 const matrixWorld = this.matrixWorld; 24667 const raycastTimes = this.count; 24668 24669 _mesh$1.geometry = this.geometry; 24670 _mesh$1.material = this.material; 24671 24672 if ( _mesh$1.material === undefined ) return; 24673 24674 // test with bounding sphere first 24675 24676 if ( this.boundingSphere === null ) this.computeBoundingSphere(); 24677 24678 _sphere$4.copy( this.boundingSphere ); 24679 _sphere$4.applyMatrix4( matrixWorld ); 24680 24681 if ( raycaster.ray.intersectsSphere( _sphere$4 ) === false ) return; 24682 24683 // now test each instance 24684 24685 for ( let instanceId = 0; instanceId < raycastTimes; instanceId ++ ) { 24686 24687 // calculate the world matrix for each instance 24688 24689 this.getMatrixAt( instanceId, _instanceLocalMatrix ); 24690 24691 _instanceWorldMatrix.multiplyMatrices( matrixWorld, _instanceLocalMatrix ); 24692 24693 // the mesh represents this single instance 24694 24695 _mesh$1.matrixWorld = _instanceWorldMatrix; 24696 24697 _mesh$1.raycast( raycaster, _instanceIntersects ); 24698 24699 // process the result of raycast 24700 24701 for ( let i = 0, l = _instanceIntersects.length; i < l; i ++ ) { 24702 24703 const intersect = _instanceIntersects[ i ]; 24704 intersect.instanceId = instanceId; 24705 intersect.object = this; 24706 intersects.push( intersect ); 24707 24708 } 24709 24710 _instanceIntersects.length = 0; 24711 24712 } 24713 24714 } 24715 24716 /** 24717 * Sets the given color to the defined instance. Make sure you set the `needsUpdate` flag of 24718 * {@link InstancedMesh#instanceColor} to `true` after updating all the colors. 24719 * 24720 * @param {number} index - The instance index. 24721 * @param {Color} color - The instance color. 24722 * @return {InstancedMesh} A reference to this instanced mesh. 24723 */ 24724 setColorAt( index, color ) { 24725 24726 if ( this.instanceColor === null ) { 24727 24728 this.instanceColor = new InstancedBufferAttribute( new Float32Array( this.instanceMatrix.count * 3 ).fill( 1 ), 3 ); 24729 24730 } 24731 24732 color.toArray( this.instanceColor.array, index * 3 ); 24733 return this; 24734 24735 } 24736 24737 /** 24738 * Sets the given local transformation matrix to the defined instance. Make sure you set the `needsUpdate` flag of 24739 * {@link InstancedMesh#instanceMatrix} to `true` after updating all the matrices. 24740 * 24741 * @param {number} index - The instance index. 24742 * @param {Matrix4} matrix - The local transformation. 24743 * @return {InstancedMesh} A reference to this instanced mesh. 24744 */ 24745 setMatrixAt( index, matrix ) { 24746 24747 matrix.toArray( this.instanceMatrix.array, index * 16 ); 24748 return this; 24749 24750 } 24751 24752 /** 24753 * Sets the morph target weights to the defined instance. Make sure you set the `needsUpdate` flag of 24754 * {@link InstancedMesh#morphTexture} to `true` after updating all the influences. 24755 * 24756 * @param {number} index - The instance index. 24757 * @param {Mesh} object - A mesh which `morphTargetInfluences` property containing the morph target weights 24758 * of a single instance. 24759 * @return {InstancedMesh} A reference to this instanced mesh. 24760 */ 24761 setMorphAt( index, object ) { 24762 24763 const objectInfluences = object.morphTargetInfluences; 24764 24765 const len = objectInfluences.length + 1; // morphBaseInfluence + all influences 24766 24767 if ( this.morphTexture === null ) { 24768 24769 this.morphTexture = new DataTexture( new Float32Array( len * this.count ), len, this.count, RedFormat, FloatType ); 24770 24771 } 24772 24773 const array = this.morphTexture.source.data.data; 24774 24775 let morphInfluencesSum = 0; 24776 24777 for ( let i = 0; i < objectInfluences.length; i ++ ) { 24778 24779 morphInfluencesSum += objectInfluences[ i ]; 24780 24781 } 24782 24783 const morphBaseInfluence = this.geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum; 24784 24785 const dataIndex = len * index; 24786 24787 array[ dataIndex ] = morphBaseInfluence; 24788 24789 array.set( objectInfluences, dataIndex + 1 ); 24790 return this; 24791 24792 } 24793 24794 updateMorphTargets() { 24795 24796 } 24797
vendor: 5,463 bytes, lines 24798-25026
24798 /** 24799 * Frees the GPU-related resources allocated by this instance. Call this 24800 * method whenever this instance is no longer used in your app. 24801 */ 24802 dispose() { 24803 24804 this.dispatchEvent( { type: 'dispose' } ); 24805 24806 if ( this.morphTexture !== null ) { 24807 24808 this.morphTexture.dispose(); 24809 this.morphTexture = null; 24810 24811 } 24812 24813 } 24814 24815} 24816 24817const _vector1 = /*@__PURE__*/ new Vector3(); 24818const _vector2 = /*@__PURE__*/ new Vector3(); 24819const _normalMatrix = /*@__PURE__*/ new Matrix3(); 24820 24821/** 24822 * A two dimensional surface that extends infinitely in 3D space, represented 24823 * in [Hessian normal form](http://mathworld.wolfram.com/HessianNormalForm.html) 24824 * by a unit length normal vector and a constant. 24825 */ 24826class Plane { 24827 24828 /** 24829 * Constructs a new plane. 24830 * 24831 * @param {Vector3} [normal=(1,0,0)] - A unit length vector defining the normal of the plane. 24832 * @param {number} [constant=0] - The signed distance from the origin to the plane. 24833 */ 24834 constructor( normal = new Vector3( 1, 0, 0 ), constant = 0 ) { 24835 24836 /** 24837 * This flag can be used for type testing. 24838 * 24839 * @type {boolean} 24840 * @readonly 24841 * @default true 24842 */ 24843 this.isPlane = true; 24844 24845 /** 24846 * A unit length vector defining the normal of the plane. 24847 * 24848 * @type {Vector3} 24849 */ 24850 this.normal = normal; 24851 24852 /** 24853 * The signed distance from the origin to the plane. 24854 * 24855 * @type {number} 24856 * @default 0 24857 */ 24858 this.constant = constant; 24859 24860 } 24861 24862 /** 24863 * Sets the plane components by copying the given values. 24864 * 24865 * @param {Vector3} normal - The normal. 24866 * @param {number} constant - The constant. 24867 * @return {Plane} A reference to this plane. 24868 */ 24869 set( normal, constant ) { 24870 24871 this.normal.copy( normal ); 24872 this.constant = constant; 24873 24874 return this; 24875 24876 } 24877 24878 /** 24879 * Sets the plane components by defining `x`, `y`, `z` as the 24880 * plane normal and `w` as the constant. 24881 * 24882 * @param {number} x - The value for the normal's x component. 24883 * @param {number} y - The value for the normal's y component. 24884 * @param {number} z - The value for the normal's z component. 24885 * @param {number} w - The constant value. 24886 * @return {Plane} A reference to this plane. 24887 */ 24888 setComponents( x, y, z, w ) { 24889 24890 this.normal.set( x, y, z ); 24891 this.constant = w; 24892 24893 return this; 24894 24895 } 24896 24897 /** 24898 * Sets the plane from the given normal and coplanar point (that is a point 24899 * that lies onto the plane). 24900 * 24901 * @param {Vector3} normal - The normal. 24902 * @param {Vector3} point - A coplanar point. 24903 * @return {Plane} A reference to this plane. 24904 */ 24905 setFromNormalAndCoplanarPoint( normal, point ) { 24906 24907 this.normal.copy( normal ); 24908 this.constant = - point.dot( this.normal ); 24909 24910 return this; 24911 24912 } 24913 24914 /** 24915 * Sets the plane from three coplanar points. The winding order is 24916 * assumed to be counter-clockwise, and determines the direction of 24917 * the plane normal. 24918 * 24919 * @param {Vector3} a - The first coplanar point. 24920 * @param {Vector3} b - The second coplanar point. 24921 * @param {Vector3} c - The third coplanar point. 24922 * @return {Plane} A reference to this plane. 24923 */ 24924 setFromCoplanarPoints( a, b, c ) { 24925 24926 const normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize(); 24927 24928 // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? 24929 24930 this.setFromNormalAndCoplanarPoint( normal, a ); 24931 24932 return this; 24933 24934 } 24935 24936 /** 24937 * Copies the values of the given plane to this instance. 24938 * 24939 * @param {Plane} plane - The plane to copy. 24940 * @return {Plane} A reference to this plane. 24941 */ 24942 copy( plane ) { 24943 24944 this.normal.copy( plane.normal ); 24945 this.constant = plane.constant; 24946 24947 return this; 24948 24949 } 24950 24951 /** 24952 * Normalizes the plane normal and adjusts the constant accordingly. 24953 * 24954 * @return {Plane} A reference to this plane. 24955 */ 24956 normalize() { 24957 24958 // Note: will lead to a divide by zero if the plane is invalid. 24959 24960 const inverseNormalLength = 1.0 / this.normal.length(); 24961 this.normal.multiplyScalar( inverseNormalLength ); 24962 this.constant *= inverseNormalLength; 24963 24964 return this; 24965 24966 } 24967 24968 /** 24969 * Negates both the plane normal and the constant. 24970 * 24971 * @return {Plane} A reference to this plane. 24972 */ 24973 negate() { 24974 24975 this.constant *= -1; 24976 this.normal.negate(); 24977 24978 return this; 24979 24980 } 24981 24982 /** 24983 * Returns the signed distance from the given point to this plane. 24984 * 24985 * @param {Vector3} point - The point to compute the distance for. 24986 * @return {number} The signed distance. 24987 */ 24988 distanceToPoint( point ) { 24989 24990 return this.normal.dot( point ) + this.constant; 24991 24992 } 24993 24994 /** 24995 * Returns the signed distance from the given sphere to this plane. 24996 * 24997 * @param {Sphere} sphere - The sphere to compute the distance for. 24998 * @return {number} The signed distance. 24999 */ 25000 distanceToSphere( sphere ) { 25001 25002 return this.distanceToPoint( sphere.center ) - sphere.radius; 25003 25004 } 25005 25006 /** 25007 * Projects a the given point onto the plane. 25008 * 25009 * @param {Vector3} point - The point to project. 25010 * @param {Vector3} target - The target vector that is used to store the method's result. 25011 * @return {Vector3} The projected point on the plane. 25012 */ 25013 projectPoint( point, target ) { 25014 25015 return target.copy( point ).addScaledVector( this.normal, - this.distanceToPoint( point ) ); 25016 25017 } 25018 25019 /** 25020 * Returns the intersection point of the passed line and the plane. Returns 25021 * `null` if the line does not intersect. Returns the line's starting point if 25022 * the line is coplanar with the plane. 25023 * 25024 * @param {Line3} line - The line to compute the intersection for. 25025 * @param {Vector3} target - The target vector that is used to store the method's result. 25026 * @
25026param {boolean} [clampToLine=true] - Whether to clamp the intersection to the line segment. 25027 * @return {?Vector3} The intersection point. Returns `null` if no intersection is detected. 25028 */ 25029 intersectLine( line, target, clampToLine = true ) { 25030 25031 const direction = line.delta( _vector1 ); 25032 25033 const denominator = this.normal.dot( direction ); 25034 25035 if ( denominator === 0 ) { 25036 25037 // line is coplanar, return origin 25038 if ( this.distanceToPoint( line.start ) === 0 ) { 25039 25040 return target.copy( line.start ); 25041 25042 } 25043 25044 // Unsure if this is the correct method to handle this case. 25045 return null; 25046 25047 } 25048 25049 const t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; 25050 25051 if ( ( clampToLine === true ) && ( t < 0 || t > 1 )
vendor: 10,709 bytes, lines 25051-25457
25051 ) { 25052 25053 return null; 25054 25055 } 25056 25057 return target.copy( line.start ).addScaledVector( direction, t ); 25058 25059 } 25060 25061 /** 25062 * Returns `true` if the given line segment intersects with (passes through) the plane. 25063 * 25064 * @param {Line3} line - The line to test. 25065 * @return {boolean} Whether the given line segment intersects with the plane or not. 25066 */ 25067 intersectsLine( line ) { 25068 25069 // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. 25070 25071 const startSign = this.distanceToPoint( line.start ); 25072 const endSign = this.distanceToPoint( line.end ); 25073 25074 return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); 25075 25076 } 25077 25078 /** 25079 * Returns `true` if the given bounding box intersects with the plane. 25080 * 25081 * @param {Box3} box - The bounding box to test. 25082 * @return {boolean} Whether the given bounding box intersects with the plane or not. 25083 */ 25084 intersectsBox( box ) { 25085 25086 return box.intersectsPlane( this ); 25087 25088 } 25089 25090 /** 25091 * Returns `true` if the given bounding sphere intersects with the plane. 25092 * 25093 * @param {Sphere} sphere - The bounding sphere to test. 25094 * @return {boolean} Whether the given bounding sphere intersects with the plane or not. 25095 */ 25096 intersectsSphere( sphere ) { 25097 25098 return sphere.intersectsPlane( this ); 25099 25100 } 25101 25102 /** 25103 * Returns a coplanar vector to the plane, by calculating the 25104 * projection of the normal at the origin onto the plane. 25105 * 25106 * @param {Vector3} target - The target vector that is used to store the method's result. 25107 * @return {Vector3} The coplanar point. 25108 */ 25109 coplanarPoint( target ) { 25110 25111 return target.copy( this.normal ).multiplyScalar( - this.constant ); 25112 25113 } 25114 25115 /** 25116 * Apply a 4x4 matrix to the plane. The matrix must be an affine, homogeneous transform. 25117 * 25118 * The optional normal matrix can be pre-computed like so: 25119 * ```js 25120 * const optionalNormalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); 25121 * ``` 25122 * 25123 * @param {Matrix4} matrix - The transformation matrix. 25124 * @param {Matrix4} [optionalNormalMatrix] - A pre-computed normal matrix. 25125 * @return {Plane} A reference to this plane. 25126 */ 25127 applyMatrix4( matrix, optionalNormalMatrix ) { 25128 25129 const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix ); 25130 25131 const referencePoint = this.coplanarPoint( _vector1 ).applyMatrix4( matrix ); 25132 25133 const normal = this.normal.applyMatrix3( normalMatrix ).normalize(); 25134 25135 this.constant = - referencePoint.dot( normal ); 25136 25137 return this; 25138 25139 } 25140 25141 /** 25142 * Translates the plane by the distance defined by the given offset vector. 25143 * Note that this only affects the plane constant and will not affect the normal vector. 25144 * 25145 * @param {Vector3} offset - The offset vector. 25146 * @return {Plane} A reference to this plane. 25147 */ 25148 translate( offset ) { 25149 25150 this.constant -= offset.dot( this.normal ); 25151 25152 return this; 25153 25154 } 25155 25156 /** 25157 * Returns `true` if this plane is equal with the given one. 25158 * 25159 * @param {Plane} plane - The plane to test for equality. 25160 * @return {boolean} Whether this plane is equal with the given one. 25161 */ 25162 equals( plane ) { 25163 25164 return plane.normal.equals( this.normal ) && ( plane.constant === this.constant ); 25165 25166 } 25167 25168 /** 25169 * Returns a new plane with copied values from this instance. 25170 * 25171 * @return {Plane} A clone of this instance. 25172 */ 25173 clone() { 25174 25175 return new this.constructor().copy( this ); 25176 25177 } 25178 25179} 25180 25181const _sphere$3 = /*@__PURE__*/ new Sphere(); 25182const _defaultSpriteCenter = /*@__PURE__*/ new Vector2( 0.5, 0.5 ); 25183const _vector$6 = /*@__PURE__*/ new Vector3(); 25184 25185/** 25186 * Frustums are used to determine what is inside the camera's field of view. 25187 * They help speed up the rendering process - objects which lie outside a camera's 25188 * frustum can safely be excluded from rendering. 25189 * 25190 * This class is mainly intended for use internally by a renderer. 25191 */ 25192class Frustum { 25193 25194 /** 25195 * Constructs a new frustum. 25196 * 25197 * @param {Plane} [p0] - The first plane that encloses the frustum. 25198 * @param {Plane} [p1] - The second plane that encloses the frustum. 25199 * @param {Plane} [p2] - The third plane that encloses the frustum. 25200 * @param {Plane} [p3] - The fourth plane that encloses the frustum. 25201 * @param {Plane} [p4] - The fifth plane that encloses the frustum. 25202 * @param {Plane} [p5] - The sixth plane that encloses the frustum. 25203 */ 25204 constructor( p0 = new Plane(), p1 = new Plane(), p2 = new Plane(), p3 = new Plane(), p4 = new Plane(), p5 = new Plane() ) { 25205 25206 /** 25207 * This array holds the planes that enclose the frustum. 25208 * 25209 * @type {Array<Plane>} 25210 */ 25211 this.planes = [ p0, p1, p2, p3, p4, p5 ]; 25212 25213 } 25214 25215 /** 25216 * Sets the frustum planes by copying the given planes. 25217 * 25218 * @param {Plane} [p0] - The first plane that encloses the frustum. 25219 * @param {Plane} [p1] - The second plane that encloses the frustum. 25220 * @param {Plane} [p2] - The third plane that encloses the frustum. 25221 * @param {Plane} [p3] - The fourth plane that encloses the frustum. 25222 * @param {Plane} [p4] - The fifth plane that encloses the frustum. 25223 * @param {Plane} [p5] - The sixth plane that encloses the frustum. 25224 * @return {Frustum} A reference to this frustum. 25225 */ 25226 set( p0, p1, p2, p3, p4, p5 ) { 25227 25228 const planes = this.planes; 25229 25230 planes[ 0 ].copy( p0 ); 25231 planes[ 1 ].copy( p1 ); 25232 planes[ 2 ].copy( p2 ); 25233 planes[ 3 ].copy( p3 ); 25234 planes[ 4 ].copy( p4 ); 25235 planes[ 5 ].copy( p5 ); 25236 25237 return this; 25238 25239 } 25240 25241 /** 25242 * Copies the values of the given frustum to this instance. 25243 * 25244 * @param {Frustum} frustum - The frustum to copy. 25245 * @return {Frustum} A reference to this frustum. 25246 */ 25247 copy( frustum ) { 25248 25249 const planes = this.planes; 25250 25251 for ( let i = 0; i < 6; i ++ ) { 25252 25253 planes[ i ].copy( frustum.planes[ i ] ); 25254 25255 } 25256 25257 return this; 25258 25259 } 25260 25261 /** 25262 * Sets the frustum planes from the given projection matrix. 25263 * 25264 * @param {Matrix4} m - The projection matrix. 25265 * @param {(WebGLCoordinateSystem|WebGPUCoordinateSystem)} coordinateSystem - The coordinate system. 25266 * @param {boolean} [reversedDepth=false] - Whether to use a reversed depth. 25267 * @return {Frustum} A reference to this frustum. 25268 */ 25269 setFromProjectionMatrix( m, coordinateSystem = WebGLCoordinateSystem, reversedDepth = false ) { 25270 25271 const planes = this.planes; 25272 const me = m.elements; 25273 const me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ]; 25274 const me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ]; 25275 const me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ]; 25276 const me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ]; 25277 25278 planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize(); 25279 planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize(); 25280 planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); 25281 planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); 25282 25283 if ( reversedDepth ) { 25284 25285 planes[ 4 ].setComponents( me2, me6, me10, me14 ).normalize(); // far 25286 planes[ 5 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); // near 25287 25288 } else { 25289 25290 planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); // far 25291 25292 if ( coordinateSystem === WebGLCoordinateSystem ) { 25293 25294 planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); // near 25295 25296 } else if ( coordinateSystem === WebGPUCoordinateSystem ) { 25297 25298 planes[ 5 ].setComponents( me2, me6, me10, me14 ).normalize(); // near 25299 25300 } else { 25301 25302 throw new Error( 'THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: ' + coordinateSystem ); 25303 25304 } 25305 25306 } 25307 25308 return this; 25309 25310 } 25311 25312 /** 25313 * Returns `true` if the 3D object's bounding sphere is intersecting this frustum. 25314 * 25315 * Note that the 3D object must have a geometry so that the bounding sphere can be calculated. 25316 * 25317 * @param {Object3D} object - The 3D object to test. 25318 * @return {boolean} Whether the 3D object's bounding sphere is intersecting this frustum or not. 25319 */ 25320 intersectsObject( object ) { 25321 25322 if ( object.boundingSphere !== undefined ) { 25323 25324 if ( object.boundingSphere === null ) object.computeBoundingSphere(); 25325 25326 _sphere$3.copy( object.boundingSphere ).applyMatrix4( object.matrixWorld ); 25327 25328 } else { 25329 25330 const geometry = object.geometry; 25331 25332 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); 25333 25334 _sphere$3.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld ); 25335 25336 } 25337 25338 return this.intersectsSphere( _sphere$3 ); 25339 25340 } 25341 25342 /** 25343 * Returns `true` if the given sprite is intersecting this frustum. 25344 * 25345 * @param {Sprite} sprite - The sprite to test. 25346 * @return {boolean} Whether the sprite is intersecting this frustum or not. 25347 */ 25348 intersectsSprite( sprite ) { 25349 25350 _sphere$3.center.set( 0, 0, 0 ); 25351 25352 const offset = _defaultSpriteCenter.distanceTo( sprite.center ); 25353 25354 _sphere$3.radius = 0.7071067811865476 + offset; 25355 _sphere$3.applyMatrix4( sprite.matrixWorld ); 25356 25357 return this.intersectsSphere( _sphere$3 ); 25358 25359 } 25360 25361 /** 25362 * Returns `true` if the given bounding sphere is intersecting this frustum. 25363 * 25364 * @param {Sphere} sphere - The bounding sphere to test. 25365 * @return {boolean} Whether the bounding sphere is intersecting this frustum or not. 25366 */ 25367 intersectsSphere( sphere ) { 25368 25369 const planes = this.planes; 25370 const center = sphere.center; 25371 const negRadius = - sphere.radius; 25372 25373 for ( let i = 0; i < 6; i ++ ) { 25374 25375 const distance = planes[ i ].distanceToPoint( center ); 25376 25377 if ( distance < negRadius ) { 25378 25379 return false; 25380 25381 } 25382 25383 } 25384 25385 return true; 25386 25387 } 25388 25389 /** 25390 * Returns `true` if the given bounding box is intersecting this frustum. 25391 * 25392 * @param {Box3} box - The bounding box to test. 25393 * @return {boolean} Whether the bounding box is intersecting this frustum or not. 25394 */ 25395 intersectsBox( box ) { 25396 25397 const planes = this.planes; 25398 25399 for ( let i = 0; i < 6; i ++ ) { 25400 25401 const plane = planes[ i ]; 25402 25403 // corner at max distance 25404 25405 _vector$6.x = plane.normal.x > 0 ? box.max.x : box.min.x; 25406 _vector$6.y = plane.normal.y > 0 ? box.max.y : box.min.y; 25407 _vector$6.z = plane.normal.z > 0 ? box.max.z : box.min.z; 25408 25409 if ( plane.distanceToPoint( _vector$6 ) < 0 ) { 25410 25411 return false; 25412 25413 } 25414 25415 } 25416 25417 return true; 25418 25419 } 25420 25421 /** 25422 * Returns `true` if the given point lies within the frustum. 25423 * 25424 * @param {Vector3} point - The point to test. 25425 * @return {boolean} Whether the point lies within this frustum or not. 25426 */ 25427 containsPoint( point ) { 25428 25429 const planes = this.planes; 25430 25431 for ( let i = 0; i < 6; i ++ ) { 25432 25433 if ( planes[ i ].distanceToPoint( point ) < 0 ) { 25434 25435 return false; 25436 25437 } 25438 25439 } 25440 25441 return true; 25442 25443 } 25444 25445 /** 25446 * Returns a new frustum with copied values from this instance. 25447 * 25448 * @return {Frustum} A clone of this instance. 25449 */ 25450 clone() { 25451 25452 return new this.constructor().copy( this ); 25453 25454 } 25455 25456} 25457
25458const _projScreenMatrix$1 = /*@__PURE__*/ new Matrix4(); 25459const _frustum$1 = /*@__PURE__*/ new Frustum(); 25460 25461/** 25462 * FrustumArray is used to determine if an object is visible in at least one camera 25463 * from an array of cameras. This is particularly useful for multi-view renderers. 25464*/ 25465class FrustumArray { 25466 25467 /** 25468 * Constructs a new frustum array. 25469 * 25470 */ 25471 constructor() { 25472 25473 /** 25474 * The coordinate system to use. 25475 * 25476 * @type {WebGLCoordinateSystem|WebGPUCoordinateSystem} 25477 * @default WebGLCoordinateSystem 25478 */ 25479 this.coordinateSystem = WebGLCoordinateSystem; 25480 25481 } 25482 25483 /** 25484 * Returns `true` if the 3D object's bounding sphere is intersecting any frustum 25485 * from the camera array. 25486 * 25487 * @param {Object3D} object - The 3D object to test. 25488 * @param {Object} cameraArray - An object with a cameras property containing an array of cameras. 25489 * @return {boolean} Whether the 3D object is visible in any camera. 25490 */ 25491 intersectsObject( object, cameraArray ) { 25492 25493 if ( ! cameraArray.isArrayCamera || cameraArray.cameras.length === 0 ) { 25494 25495 return false; 25496 25497 } 25498 25499 for ( let i = 0; i < cameraArray.cameras.length; i ++ ) { 25500 25501 const camera = cameraArray.cameras[ i ]; 25502 25503 _projScreenMatrix$1.multiplyMatrices( 25504 camera.projectionMatrix, 25505 camera.matrixWorldInverse 25506 ); 25507 25508 _frustum$1.setFromProjectionMatrix( 25509 _projScreenMatrix$1, 25510 camera.coordinateSystem, 25511 camera.reversedDepth 25512 ); 25513 25514 if ( _frustum$1.intersectsObject( object ) ) { 25515 25516 return true; // Object is visible in at least one camera 25517 25518 } 25519 25520 } 25521 25522 return false; // Not visible in any camera 25523 25524 } 25525 25526 /** 25527 * Returns `true` if the given sprite is intersecting any frustum 25528 * from the camera array. 25529 * 25530 * @param {Sprite} sprite - The sprite to test. 25531 * @param {Object} cameraArray - An object with a cameras property containing an array of cameras. 25532 * @return {boolean} Whether the sprite is visible in any camera. 25533 */ 25534 intersectsSprite( sprite, cameraArray ) { 25535 25536 if ( ! cameraArray || ! cameraArray.cameras || cameraArray.cameras.length === 0 ) { 25537 25538 return false; 25539 25540 } 25541 25542 for ( let i = 0; i < cameraArray.cameras.length; i ++ ) { 25543 25544 const camera = cameraArray.cameras[ i ]; 25545 25546 _projScreenMatrix$1.multiplyMatrices( 25547 camera.projectionMatrix, 25548 camera.matrixWorldInverse 25549 ); 25550 25551 _frustum$1.setFromProjectionMatrix( 25552 _projScreenMatrix$1, 25553 camera.coordinateSystem, 25554 camera.reversedDepth 25555 ); 25556 25557 if ( _frustum$1.intersectsSprite( sprite ) ) { 25558 25559 return true; // Sprite is visible in at least one camera 25560 25561 } 25562 25563 } 25564 25565 return false; // Not visible in any camera 25566 25567 } 25568 25569 /** 25570 * Returns `true` if the given bounding sphere is intersecting any frustum 25571 * from the camera array. 25572 * 25573 * @param {Sphere} sphere - The bounding sphere to test. 25574 * @param {Object} cameraArray - An object with a cameras property containing an array of cameras. 25575 * @return {boolean} Whether the sphere is visible in any camera. 25576 */ 25577 intersectsSphere( sphere, cameraArray ) { 25578 25579 if ( ! cameraArray || ! cameraArray.cameras || cameraArray.cameras.length === 0 ) { 25580 25581 return false; 25582 25583 } 25584 25585 for ( let i = 0; i < cameraArray.cameras.length; i ++ ) { 25586 25587 const camera = cameraArray.cameras[ i ]; 25588 25589 _projScreenMatrix$1.multiplyMatrices( 25590 camera.projectionMatrix, 25591 camera.matrixWorldInverse 25592 ); 25593 25594 _frustum$1.setFromProjectionMatrix( 25595 _projScreenMatrix$1, 25596 camera.coordinateSystem, 25597 camera.reversedDepth 25598 ); 25599 25600 if ( _frustum$1.intersectsSphere( sphere ) ) { 25601 25602 return true; // Sphere is visible in at least one camera 25603 25604 } 25605 25606 } 25607 25608 return false; // Not visible in any camera 25609 25610 } 25611 25612 /** 25613 * Returns `true` if the given bounding box is intersecting any frustum 25614 * from the camera array. 25615 * 25616 * @param {Box3} box - The bounding box to test. 25617 * @param {Object} cameraArray - An object with a cameras property containing an array of cameras. 25618 * @return {boolean} Whether the box is visible in any camera. 25619 */ 25620 intersectsBox( box, cameraArray ) { 25621 25622 if ( ! cameraArray || ! cameraArray.cameras || cameraArray.cameras.length === 0 ) { 25623 25624 return false; 25625 25626 } 25627 25628 for ( let i = 0; i < cameraArray.cameras.length; i ++ ) { 25629 25630 const camera = cameraArray.cameras[ i ]; 25631 25632 _projScreenMatrix$1.multiplyMatrices( 25633 camera.projectionMatrix, 25634 camera.matrixWorldInverse 25635 ); 25636 25637 _frustum$1.setFromProjectionMatrix( 25638 _projScreenMatrix$1, 25639 camera.coordinateSystem, 25640 camera.reversedDepth 25641 ); 25642 25643 if ( _frustum$1.intersectsBox( box ) ) { 25644 25645 return true; // Box is visible in at least one camera 25646 25647 } 25648 25649 } 25650 25651 return false; // Not visible in any camera 25652 25653 } 25654
25655 /** 25656 * Returns `true` if the given point lies within any frustum 25657 * from the camera array. 25658 * 25659 * @param {Vector3} point - The point to test. 25660 * @param {Object} cameraArray - An object with a cameras property containing an array of cameras. 25661 * @return {boolean} Whether the point is visible in any camera. 25662 */ 25663 containsPoint( point, cameraArray ) { 25664 25665 if ( ! cameraArray || ! cameraArray.cameras || cameraArray.cameras.length === 0 ) { 25666 25667 return false; 25668 25669 } 25670 25671 for ( let i = 0; i < cameraArray.cameras.length; i ++ ) { 25672 25673 const camera = cameraArray.cameras[ i ]; 25674 25675 _projScreenMatrix$1.multiplyMatrices( 25676 camera.projectionMatrix, 25677 camera.matrixWorldInverse 25678 ); 25679 25680 _frustum$1.setFromProjectionMatrix( 25681 _projScreenMatrix$1, 25682 camera.coordinateSystem, 25683 camera.reversedDepth 25684 ); 25685
vendor: 4,394 bytes, lines 25686-25872
25686 if ( _frustum$1.containsPoint( point ) ) { 25687 25688 return true; // Point is visible in at least one camera 25689 25690 } 25691 25692 } 25693 25694 return false; // Not visible in any camera 25695 25696 } 25697 25698 /** 25699 * Returns a new frustum array with copied values from this instance. 25700 * 25701 * @return {FrustumArray} A clone of this instance. 25702 */ 25703 clone() { 25704 25705 return new FrustumArray(); 25706 25707 } 25708 25709} 25710 25711function ascIdSort( a, b ) { 25712 25713 return a - b; 25714 25715} 25716 25717function sortOpaque( a, b ) { 25718 25719 return a.z - b.z; 25720 25721} 25722 25723function sortTransparent( a, b ) { 25724 25725 return b.z - a.z; 25726 25727} 25728 25729class MultiDrawRenderList { 25730 25731 constructor() { 25732 25733 this.index = 0; 25734 this.pool = []; 25735 this.list = []; 25736 25737 } 25738 25739 push( start, count, z, index ) { 25740 25741 const pool = this.pool; 25742 const list = this.list; 25743 if ( this.index >= pool.length ) { 25744 25745 pool.push( { 25746 25747 start: -1, 25748 count: -1, 25749 z: -1, 25750 index: -1, 25751 25752 } ); 25753 25754 } 25755 25756 const item = pool[ this.index ]; 25757 list.push( item ); 25758 this.index ++; 25759 25760 item.start = start; 25761 item.count = count; 25762 item.z = z; 25763 item.index = index; 25764 25765 } 25766 25767 reset() { 25768 25769 this.list.length = 0; 25770 this.index = 0; 25771 25772 } 25773 25774} 25775 25776const _matrix$1 = /*@__PURE__*/ new Matrix4(); 25777const _whiteColor = /*@__PURE__*/ new Color( 1, 1, 1 ); 25778const _frustum = /*@__PURE__*/ new Frustum(); 25779const _frustumArray = /*@__PURE__*/ new FrustumArray(); 25780const _box$1 = /*@__PURE__*/ new Box3(); 25781const _sphere$2 = /*@__PURE__*/ new Sphere(); 25782const _vector$5 = /*@__PURE__*/ new Vector3(); 25783const _forward$1 = /*@__PURE__*/ new Vector3(); 25784const _temp = /*@__PURE__*/ new Vector3(); 25785const _renderList = /*@__PURE__*/ new MultiDrawRenderList(); 25786const _mesh = /*@__PURE__*/ new Mesh(); 25787const _batchIntersects = []; 25788 25789// copies data from attribute "src" into "target" starting at "targetOffset" 25790function copyAttributeData( src, target, targetOffset = 0 ) { 25791 25792 const itemSize = target.itemSize; 25793 if ( src.isInterleavedBufferAttribute || src.array.constructor !== target.array.constructor ) { 25794 25795 // use the component getters and setters if the array data cannot 25796 // be copied directly 25797 const vertexCount = src.count; 25798 for ( let i = 0; i < vertexCount; i ++ ) { 25799 25800 for ( let c = 0; c < itemSize; c ++ ) { 25801 25802 target.setComponent( i + targetOffset, c, src.getComponent( i, c ) ); 25803 25804 } 25805 25806 } 25807 25808 } else { 25809 25810 // faster copy approach using typed array set function 25811 target.array.set( src.array, targetOffset * itemSize ); 25812 25813 } 25814 25815 target.needsUpdate = true; 25816 25817} 25818 25819// safely copies array contents to a potentially smaller array 25820function copyArrayContents( src, target ) { 25821 25822 if ( src.constructor !== target.constructor ) { 25823 25824 // if arrays are of a different type (eg due to index size increasing) then data must be per-element copied 25825 const len = Math.min( src.length, target.length ); 25826 for ( let i = 0; i < len; i ++ ) { 25827 25828 target[ i ] = src[ i ]; 25829 25830 } 25831 25832 } else { 25833 25834 // if the arrays use the same data layout we can use a fast block copy 25835 const len = Math.min( src.length, target.length ); 25836 target.set( new src.constructor( src.buffer, 0, len ) ); 25837 25838 } 25839 25840} 25841 25842/** 25843 * A special version of a mesh with multi draw batch rendering support. Use 25844 * this class if you have to render a large number of objects with the same 25845 * material but with different geometries or world transformations. The usage of 25846 * `BatchedMesh` will help you to reduce the number of draw calls and thus improve the overall 25847 * rendering performance in your application. 25848 * 25849 * ```js 25850 * const box = new THREE.BoxGeometry( 1, 1, 1 ); 25851 * const sphere = new THREE.SphereGeometry( 1, 12, 12 ); 25852 * const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); 25853 * 25854 * // initialize and add geometries into the batched mesh 25855 * const batchedMesh = new BatchedMesh( 10, 5000, 10000, material ); 25856 * const boxGeometryId = batchedMesh.addGeometry( box ); 25857 * const sphereGeometryId = batchedMesh.addGeometry( sphere ); 25858 * 25859 * // create instances of those geometries 25860 * const boxInstancedId1 = batchedMesh.addInstance( boxGeometryId ); 25861 * const boxInstancedId2 = batchedMesh.addInstance( boxGeometryId ); 25862 * 25863 * const sphereInstancedId1 = batchedMesh.addInstance( sphereGeometryId ); 25864 * const sphereInstancedId2 = batchedMesh.addInstance( sphereGeometryId ); 25865 * 25866 * // position the geometries 25867 * batchedMesh.setMatrixAt( boxInstancedId1, boxMatrix1 ); 25868 * batchedMesh.setMatrixAt( boxInstancedId2, boxMatrix2 ); 25869 * 25870 * batchedMesh.setMatrixAt( sphereInstancedId1, sphereMatrix1 ); 25871 * batchedMesh.setMatrixAt( sphereInstancedId2, sphereMatrix2 ); 25872 *
25873 * scene.add( batchedMesh ); 25874 * ``` 25875 * 25876 * @augments Mesh 25877 */ 25878class BatchedMesh extends Mesh { 25879 25880 /** 25881 * Constructs a new batched mesh. 25882 * 25883 * @param {number} maxInstanceCount - The maximum number of individual instances planned to be added and rendered. 25884 * @param {number} maxVertexCount - The maximum number of vertices to be used by all unique geometries. 25885 * @param {number} [maxIndexCount=maxVertexCount*2] - The maximum number of indices to be used by all unique geometries 25886 * @param {Material|Array<Material>} [material] - The mesh material. 25887 */ 25888 constructor( maxInstanceCount, maxVertexCount, maxIndexCount = maxVertexCount * 2, material ) { 25889 25890 super( new BufferGeometry(), material ); 25891 25892 /** 25893 * This flag can be used for type testing. 25894 * 25895 * @type {boolean} 25896 * @readonly 25897 * @default true 25898 */ 25899 this.isBatchedMesh = true; 25900 25901 /** 25902 * When set ot `true`, the individual objects of a batch are frustum culled. 25903 * 25904 * @type {boolean} 25905 * @default true 25906 */ 25907 this.perObjectFrustumCulled = true; 25908 25909 /** 25910 * When set to `true`, the individual objects of a batch are sorted to improve overdraw-related artifacts. 25911 * If the material is marked as "transparent" objects are rendered back to front and if not then they are 25912 * rendered front to back. 25913 * 25914 * @type {boolean} 25915 * @default true 25916 */ 25917 this.sortObjects = true; 25918 25919 /** 25920 * The bounding box of the batched mesh. Can be computed via {@link BatchedMesh#computeBoundingBox}. 25921 * 25922 * @type {?Box3} 25923 * @default null 25924 */ 25925 this.boundingBox = null; 25926 25927 /** 25928 * The bounding sphere of the batched mesh. Can be computed via {@link BatchedMesh#computeBoundingSphere}. 25929 * 25930 * @type {?Sphere} 25931 * @default null 25932 */ 25933 this.boundingSphere = null; 25934 25935 /** 25936 * Takes a sort a function that is run before render. The function takes a list of instances to 25937 * sort and a camera. The objects in the list include a "z" field to perform a depth-ordered 25938 * sort with. 25939 * 25940 * @type {?Function} 25941 * @default null 25942 */ 25943 this.customSort = null; 25944 25945 // stores visible, active, and geometry id per instance and reserved buffer ranges for geometries 25946 this._instanceInfo = []; 25947 this._geometryInfo = []; 25948 25949 // instance, geometry ids that have been set as inactive, and are available to be overwritten 25950 this._availableInstanceIds = []; 25951 this._availableGeometryIds = []; 25952 25953 // used to track where the next point is that geometry should be inserted 25954 this._nextIndexStart = 0; 25955 this._nextVertexStart = 0; 25956 this._geometryCount = 0; 25957 25958 // flags 25959 this._visibilityChanged = true; 25960 this._geometryInitialized = false; 25961 25962 // cached user options 25963 this._maxInstanceCount = maxInstanceCount; 25964 this._maxVertexCount = maxVertexCount; 25965 this._maxIndexCount = maxIndexCount; 25966 25967 // buffers for multi draw 25968 this._multiDrawCounts = new Int32Array( maxInstanceCount ); 25969 this._multiDrawStarts = new Int32Array( maxInstanceCount ); 25970 this._multiDrawCount = 0
vendor: 25,687 bytes, lines 25970-26901
25970; 25971 25972 // Local matrix per geometry by using data texture 25973 this._matricesTexture = null; 25974 this._indirectTexture = null; 25975 this._colorsTexture = null; 25976 25977 this._initMatricesTexture(); 25978 this._initIndirectTexture(); 25979 25980 } 25981 25982 /** 25983 * The maximum number of individual instances that can be stored in the batch. 25984 * 25985 * @type {number} 25986 * @readonly 25987 */ 25988 get maxInstanceCount() { 25989 25990 return this._maxInstanceCount; 25991 25992 } 25993 25994 /** 25995 * The instance count. 25996 * 25997 * @type {number} 25998 * @readonly 25999 */ 26000 get instanceCount() { 26001 26002 return this._instanceInfo.length - this._availableInstanceIds.length; 26003 26004 } 26005 26006 /** 26007 * The number of unused vertices. 26008 * 26009 * @type {number} 26010 * @readonly 26011 */ 26012 get unusedVertexCount() { 26013 26014 return this._maxVertexCount - this._nextVertexStart; 26015 26016 } 26017 26018 /** 26019 * The number of unused indices. 26020 * 26021 * @type {number} 26022 * @readonly 26023 */ 26024 get unusedIndexCount() { 26025 26026 return this._maxIndexCount - this._nextIndexStart; 26027 26028 } 26029 26030 _initMatricesTexture() { 26031 26032 // layout (1 matrix = 4 pixels) 26033 // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) 26034 // with 8x8 pixel texture max 16 matrices * 4 pixels = (8 * 8) 26035 // 16x16 pixel texture max 64 matrices * 4 pixels = (16 * 16) 26036 // 32x32 pixel texture max 256 matrices * 4 pixels = (32 * 32) 26037 // 64x64 pixel texture max 1024 matrices * 4 pixels = (64 * 64) 26038 26039 let size = Math.sqrt( this._maxInstanceCount * 4 ); // 4 pixels needed for 1 matrix 26040 size = Math.ceil( size / 4 ) * 4; 26041 size = Math.max( size, 4 ); 26042 26043 const matricesArray = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel 26044 const matricesTexture = new DataTexture( matricesArray, size, size, RGBAFormat, FloatType ); 26045 26046 this._matricesTexture = matricesTexture; 26047 26048 } 26049 26050 _initIndirectTexture() { 26051 26052 let size = Math.sqrt( this._maxInstanceCount ); 26053 size = Math.ceil( size ); 26054 26055 const indirectArray = new Uint32Array( size * size ); 26056 const indirectTexture = new DataTexture( indirectArray, size, size, RedIntegerFormat, UnsignedIntType ); 26057 26058 this._indirectTexture = indirectTexture; 26059 26060 } 26061 26062 _initColorsTexture() { 26063 26064 let size = Math.sqrt( this._maxInstanceCount ); 26065 size = Math.ceil( size ); 26066 26067 // 4 floats per RGBA pixel initialized to white 26068 const colorsArray = new Float32Array( size * size * 4 ).fill( 1 ); 26069 const colorsTexture = new DataTexture( colorsArray, size, size, RGBAFormat, FloatType ); 26070 colorsTexture.colorSpace = ColorManagement.workingColorSpace; 26071 26072 this._colorsTexture = colorsTexture; 26073 26074 } 26075 26076 _initializeGeometry( reference ) { 26077 26078 const geometry = this.geometry; 26079 const maxVertexCount = this._maxVertexCount; 26080 const maxIndexCount = this._maxIndexCount; 26081 if ( this._geometryInitialized === false ) { 26082 26083 for ( const attributeName in reference.attributes ) { 26084 26085 const srcAttribute = reference.getAttribute( attributeName ); 26086 const { array, itemSize, normalized } = srcAttribute; 26087 26088 const dstArray = new array.constructor( maxVertexCount * itemSize ); 26089 const dstAttribute = new BufferAttribute( dstArray, itemSize, normalized ); 26090 26091 geometry.setAttribute( attributeName, dstAttribute ); 26092 26093 } 26094 26095 if ( reference.getIndex() !== null ) { 26096 26097 // Reserve last u16 index for primitive restart. 26098 const indexArray = maxVertexCount > 65535 26099 ? new Uint32Array( maxIndexCount ) 26100 : new Uint16Array( maxIndexCount ); 26101 26102 geometry.setIndex( new BufferAttribute( indexArray, 1 ) ); 26103 26104 } 26105 26106 this._geometryInitialized = true; 26107 26108 } 26109 26110 } 26111 26112 // Make sure the geometry is compatible with the existing combined geometry attributes 26113 _validateGeometry( geometry ) { 26114 26115 // check to ensure the geometries are using consistent attributes and indices 26116 const batchGeometry = this.geometry; 26117 if ( Boolean( geometry.getIndex() ) !== Boolean( batchGeometry.getIndex() ) ) { 26118 26119 throw new Error( 'THREE.BatchedMesh: All geometries must consistently have "index".' ); 26120 26121 } 26122 26123 for ( const attributeName in batchGeometry.attributes ) { 26124 26125 if ( ! geometry.hasAttribute( attributeName ) ) { 26126 26127 throw new Error( `THREE.BatchedMesh: Added geometry missing "${ attributeName }". All geometries must have consistent attributes.` ); 26128 26129 } 26130 26131 const srcAttribute = geometry.getAttribute( attributeName ); 26132 const dstAttribute = batchGeometry.getAttribute( attributeName ); 26133 if ( srcAttribute.itemSize !== dstAttribute.itemSize || srcAttribute.normalized !== dstAttribute.normalized ) { 26134 26135 throw new Error( 'THREE.BatchedMesh: All attributes must have a consistent itemSize and normalized value.' ); 26136 26137 } 26138 26139 } 26140 26141 } 26142 26143 /** 26144 * Validates the instance defined by the given ID. 26145 * 26146 * @param {number} instanceId - The instance to validate. 26147 */ 26148 validateInstanceId( instanceId ) { 26149 26150 const instanceInfo = this._instanceInfo; 26151 if ( instanceId < 0 || instanceId >= instanceInfo.length || instanceInfo[ instanceId ].active === false ) { 26152 26153 throw new Error( `THREE.BatchedMesh: Invalid instanceId ${instanceId}. Instance is either out of range or has been deleted.` ); 26154 26155 } 26156 26157 } 26158 26159 /** 26160 * Validates the geometry defined by the given ID. 26161 * 26162 * @param {number} geometryId - The geometry to validate. 26163 */ 26164 validateGeometryId( geometryId ) { 26165 26166 const geometryInfoList = this._geometryInfo; 26167 if ( geometryId < 0 || geometryId >= geometryInfoList.length || geometryInfoList[ geometryId ].active === false ) { 26168 26169 throw new Error( `THREE.BatchedMesh: Invalid geometryId ${geometryId}. Geometry is either out of range or has been deleted.` ); 26170 26171 } 26172 26173 } 26174 26175 /** 26176 * Takes a sort a function that is run before render. The function takes a list of instances to 26177 * sort and a camera. The objects in the list include a "z" field to perform a depth-ordered sort with. 26178 * 26179 * @param {Function} func - The custom sort function. 26180 * @return {BatchedMesh} A reference to this batched mesh. 26181 */ 26182 setCustomSort( func ) { 26183 26184 this.customSort = func; 26185 return this; 26186 26187 } 26188 26189 /** 26190 * Computes the bounding box, updating {@link BatchedMesh#boundingBox}. 26191 * Bounding boxes aren't computed by default. They need to be explicitly computed, 26192 * otherwise they are `null`. 26193 */ 26194 computeBoundingBox() { 26195 26196 if ( this.boundingBox === null ) { 26197 26198 this.boundingBox = new Box3(); 26199 26200 } 26201 26202 const boundingBox = this.boundingBox; 26203 const instanceInfo = this._instanceInfo; 26204 26205 boundingBox.makeEmpty(); 26206 for ( let i = 0, l = instanceInfo.length; i < l; i ++ ) { 26207 26208 if ( instanceInfo[ i ].active === false ) continue; 26209 26210 const geometryId = instanceInfo[ i ].geometryIndex; 26211 this.getMatrixAt( i, _matrix$1 ); 26212 this.getBoundingBoxAt( geometryId, _box$1 ).applyMatrix4( _matrix$1 ); 26213 boundingBox.union( _box$1 ); 26214 26215 } 26216 26217 } 26218 26219 /** 26220 * Computes the bounding sphere, updating {@link BatchedMesh#boundingSphere}. 26221 * Bounding spheres aren't computed by default. They need to be explicitly computed, 26222 * otherwise they are `null`. 26223 */ 26224 computeBoundingSphere() { 26225 26226 if ( this.boundingSphere === null ) { 26227 26228 this.boundingSphere = new Sphere(); 26229 26230 } 26231 26232 const boundingSphere = this.boundingSphere; 26233 const instanceInfo = this._instanceInfo; 26234 26235 boundingSphere.makeEmpty(); 26236 for ( let i = 0, l = instanceInfo.length; i < l; i ++ ) { 26237 26238 if ( instanceInfo[ i ].active === false ) continue; 26239 26240 const geometryId = instanceInfo[ i ].geometryIndex; 26241 this.getMatrixAt( i, _matrix$1 ); 26242 this.getBoundingSphereAt( geometryId, _sphere$2 ).applyMatrix4( _matrix$1 ); 26243 boundingSphere.union( _sphere$2 ); 26244 26245 } 26246 26247 } 26248 26249 /** 26250 * Adds a new instance to the batch using the geometry of the given ID and returns 26251 * a new id referring to the new instance to be used by other functions. 26252 * 26253 * @param {number} geometryId - The ID of a previously added geometry via {@link BatchedMesh#addGeometry}. 26254 * @return {number} The instance ID. 26255 */ 26256 addInstance( geometryId ) { 26257 26258 const atCapacity = this._instanceInfo.length >= this.maxInstanceCount; 26259 26260 // ensure we're not over geometry 26261 if ( atCapacity && this._availableInstanceIds.length === 0 ) { 26262 26263 throw new Error( 'THREE.BatchedMesh: Maximum item count reached.' ); 26264 26265 } 26266 26267 const instanceInfo = { 26268 visible: true, 26269 active: true, 26270 geometryIndex: geometryId, 26271 }; 26272 26273 let drawId = null; 26274 26275 // Prioritize using previously freed instance ids 26276 if ( this._availableInstanceIds.length > 0 ) { 26277 26278 this._availableInstanceIds.sort( ascIdSort ); 26279 26280 drawId = this._availableInstanceIds.shift(); 26281 this._instanceInfo[ drawId ] = instanceInfo; 26282 26283 } else { 26284 26285 drawId = this._instanceInfo.length; 26286 this._instanceInfo.push( instanceInfo ); 26287 26288 } 26289 26290 const matricesTexture = this._matricesTexture; 26291 _matrix$1.identity().toArray( matricesTexture.image.data, drawId * 16 ); 26292 matricesTexture.needsUpdate = true; 26293 26294 const colorsTexture = this._colorsTexture; 26295 if ( colorsTexture ) { 26296 26297 _whiteColor.toArray( colorsTexture.image.data, drawId * 4 ); 26298 colorsTexture.needsUpdate = true; 26299 26300 } 26301 26302 this._visibilityChanged = true; 26303 return drawId; 26304 26305 } 26306 26307 /** 26308 * Adds the given geometry to the batch and returns the associated 26309 * geometry id referring to it to be used in other functions. 26310 * 26311 * @param {BufferGeometry} geometry - The geometry to add. 26312 * @param {number} [reservedVertexCount=-1] - Optional parameter specifying the amount of 26313 * vertex buffer space to reserve for the added geometry. This is necessary if it is planned 26314 * to set a new geometry at this index at a later time that is larger than the original geometry. 26315 * Defaults to the length of the given geometry vertex buffer. 26316 * @param {number} [reservedIndexCount=-1] - Optional parameter specifying the amount of index 26317 * buffer space to reserve for the added geometry. This is necessary if it is planned to set a 26318 * new geometry at this index at a later time that is larger than the original geometry. Defaults to 26319 * the length of the given geometry index buffer. 26320 * @return {number} The geometry ID. 26321 */ 26322 addGeometry( geometry, reservedVertexCount = -1, reservedIndexCount = -1 ) { 26323 26324 this._initializeGeometry( geometry ); 26325 26326 this._validateGeometry( geometry ); 26327 26328 const geometryInfo = { 26329 // geometry information 26330 vertexStart: -1, 26331 vertexCount: -1, 26332 reservedVertexCount: -1, 26333 26334 indexStart: -1, 26335 indexCount: -1, 26336 reservedIndexCount: -1, 26337 26338 // draw range information 26339 start: -1, 26340 count: -1, 26341 26342 // state 26343 boundingBox: null, 26344 boundingSphere: null, 26345 active: true, 26346 }; 26347 26348 const geometryInfoList = this._geometryInfo; 26349 geometryInfo.vertexStart = this._nextVertexStart; 26350 geometryInfo.reservedVertexCount = reservedVertexCount === -1 ? geometry.getAttribute( 'position' ).count : reservedVertexCount; 26351 26352 const index = geometry.getIndex(); 26353 const hasIndex = index !== null; 26354 if ( hasIndex ) { 26355 26356 geometryInfo.indexStart = this._nextIndexStart; 26357 geometryInfo.reservedIndexCount = reservedIndexCount === -1 ? index.count : reservedIndexCount; 26358 26359 } 26360 26361 if ( 26362 geometryInfo.indexStart !== -1 && 26363 geometryInfo.indexStart + geometryInfo.reservedIndexCount > this._maxIndexCount || 26364 geometryInfo.vertexStart + geometryInfo.reservedVertexCount > this._maxVertexCount 26365 ) { 26366 26367 throw new Error( 'THREE.BatchedMesh: Reserved space request exceeds the maximum buffer size.' ); 26368 26369 } 26370 26371 // update id 26372 let geometryId; 26373 if ( this._availableGeometryIds.length > 0 ) { 26374 26375 this._availableGeometryIds.sort( ascIdSort ); 26376 26377 geometryId = this._availableGeometryIds.shift(); 26378 geometryInfoList[ geometryId ] = geometryInfo; 26379 26380 26381 } else { 26382 26383 geometryId = this._geometryCount; 26384 this._geometryCount ++; 26385 geometryInfoList.push( geometryInfo ); 26386 26387 } 26388 26389 // update the geometry 26390 this.setGeometryAt( geometryId, geometry ); 26391 26392 // increment the next geometry position 26393 this._nextIndexStart = geometryInfo.indexStart + geometryInfo.reservedIndexCount; 26394 this._nextVertexStart = geometryInfo.vertexStart + geometryInfo.reservedVertexCount; 26395 26396 return geometryId; 26397 26398 } 26399 26400 /** 26401 * Replaces the geometry at the given ID with the provided geometry. Throws an error if there 26402 * is not enough space reserved for geometry. Calling this will change all instances that are 26403 * rendering that geometry. 26404 * 26405 * @param {number} geometryId - The ID of the geometry that should be replaced with the given geometry. 26406 * @param {BufferGeometry} geometry - The new geometry. 26407 * @return {number} The geometry ID. 26408 */ 26409 setGeometryAt( geometryId, geometry ) { 26410 26411 if ( geometryId >= this._geometryCount ) { 26412 26413 throw new Error( 'THREE.BatchedMesh: Maximum geometry count reached.' ); 26414 26415 } 26416 26417 this._validateGeometry( geometry ); 26418 26419 const batchGeometry = this.geometry; 26420 const hasIndex = batchGeometry.getIndex() !== null; 26421 const dstIndex = batchGeometry.getIndex(); 26422 const srcIndex = geometry.getIndex(); 26423 const geometryInfo = this._geometryInfo[ geometryId ]; 26424 if ( 26425 hasIndex && 26426 srcIndex.count > geometryInfo.reservedIndexCount || 26427 geometry.attributes.position.count > geometryInfo.reservedVertexCount 26428 ) { 26429 26430 throw new Error( 'THREE.BatchedMesh: Reserved space not large enough for provided geometry.' ); 26431 26432 } 26433 26434 // copy geometry buffer data over 26435 const vertexStart = geometryInfo.vertexStart; 26436 const reservedVertexCount = geometryInfo.reservedVertexCount; 26437 geometryInfo.vertexCount = geometry.getAttribute( 'position' ).count; 26438 26439 for ( const attributeName in batchGeometry.attributes ) { 26440 26441 // copy attribute data 26442 const srcAttribute = geometry.getAttribute( attributeName ); 26443 const dstAttribute = batchGeometry.getAttribute( attributeName ); 26444 copyAttributeData( srcAttribute, dstAttribute, vertexStart ); 26445 26446 // fill the rest in with zeroes 26447 const itemSize = srcAttribute.itemSize; 26448 for ( let i = srcAttribute.count, l = reservedVertexCount; i < l; i ++ ) { 26449 26450 const index = vertexStart + i; 26451 for ( let c = 0; c < itemSize; c ++ ) { 26452 26453 dstAttribute.setComponent( index, c, 0 ); 26454 26455 } 26456 26457 } 26458 26459 dstAttribute.needsUpdate = true; 26460 dstAttribute.addUpdateRange( vertexStart * itemSize, reservedVertexCount * itemSize ); 26461 26462 } 26463 26464 // copy index 26465 if ( hasIndex ) { 26466 26467 const indexStart = geometryInfo.indexStart; 26468 const reservedIndexCount = geometryInfo.reservedIndexCount; 26469 geometryInfo.indexCount = geometry.getIndex().count; 26470 26471 // copy index data over 26472 for ( let i = 0; i < srcIndex.count; i ++ ) { 26473 26474 dstIndex.setX( indexStart + i, vertexStart + srcIndex.getX( i ) ); 26475 26476 } 26477 26478 // fill the rest in with zeroes 26479 for ( let i = srcIndex.count, l = reservedIndexCount; i < l; i ++ ) { 26480 26481 dstIndex.setX( indexStart + i, vertexStart ); 26482 26483 } 26484 26485 dstIndex.needsUpdate = true; 26486 dstIndex.addUpdateRange( indexStart, geometryInfo.reservedIndexCount ); 26487 26488 } 26489 26490 // update the draw range 26491 geometryInfo.start = hasIndex ? geometryInfo.indexStart : geometryInfo.vertexStart; 26492 geometryInfo.count = hasIndex ? geometryInfo.indexCount : geometryInfo.vertexCount; 26493 26494 // store the bounding boxes 26495 geometryInfo.boundingBox = null; 26496 if ( geometry.boundingBox !== null ) { 26497 26498 geometryInfo.boundingBox = geometry.boundingBox.clone(); 26499 26500 } 26501 26502 geometryInfo.boundingSphere = null; 26503 if ( geometry.boundingSphere !== null ) { 26504 26505 geometryInfo.boundingSphere = geometry.boundingSphere.clone(); 26506 26507 } 26508 26509 this._visibilityChanged = true; 26510 return geometryId; 26511 26512 } 26513 26514 /** 26515 * Deletes the geometry defined by the given ID from this batch. Any instances referencing 26516 * this geometry will also be removed as a side effect. 26517 * 26518 * @param {number} geometryId - The ID of the geometry to remove from the batch. 26519 * @return {BatchedMesh} A reference to this batched mesh. 26520 */ 26521 deleteGeometry( geometryId ) { 26522 26523 const geometryInfoList = this._geometryInfo; 26524 if ( geometryId >= geometryInfoList.length || geometryInfoList[ geometryId ].active === false ) { 26525 26526 return this; 26527 26528 } 26529 26530 // delete any instances associated with this geometry 26531 const instanceInfo = this._instanceInfo; 26532 for ( let i = 0, l = instanceInfo.length; i < l; i ++ ) { 26533 26534 if ( instanceInfo[ i ].active && instanceInfo[ i ].geometryIndex === geometryId ) { 26535 26536 this.deleteInstance( i ); 26537 26538 } 26539 26540 } 26541 26542 geometryInfoList[ geometryId ].active = false; 26543 this._availableGeometryIds.push( geometryId ); 26544 this._visibilityChanged = true; 26545 26546 return this; 26547 26548 } 26549 26550 /** 26551 * Deletes an existing instance from the batch using the given ID. 26552 * 26553 * @param {number} instanceId - The ID of the instance to remove from the batch. 26554 * @return {BatchedMesh} A reference to this batched mesh. 26555 */ 26556 deleteInstance( instanceId ) { 26557 26558 this.validateInstanceId( instanceId ); 26559 26560 this._instanceInfo[ instanceId ].active = false; 26561 this._availableInstanceIds.push( instanceId ); 26562 this._visibilityChanged = true; 26563 26564 return this; 26565 26566 } 26567 26568 /** 26569 * Repacks the sub geometries in BatchedMesh to remove any unused space remaining from 26570 * previously deleted geometry, freeing up space to add new geometry. 26571 * 26572 * @return {BatchedMesh} A reference to this batched mesh. 26573 */ 26574 optimize() { 26575 26576 // track the next indices to copy data to 26577 let nextVertexStart = 0; 26578 let nextIndexStart = 0; 26579 26580 // Iterate over all geometry ranges in order sorted from earliest in the geometry buffer to latest 26581 // in the geometry buffer. Because draw range objects can be reused there is no guarantee of their order. 26582 const geometryInfoList = this._geometryInfo; 26583 const indices = geometryInfoList 26584 .map( ( e, i ) => i ) 26585 .sort( ( a, b ) => { 26586 26587 return geometryInfoList[ a ].vertexStart - geometryInfoList[ b ].vertexStart; 26588 26589 } ); 26590 26591 const geometry = this.geometry; 26592 for ( let i = 0, l = geometryInfoList.length; i < l; i ++ ) { 26593 26594 // if a geometry range is inactive then don't copy anything 26595 const index = indices[ i ]; 26596 const geometryInfo = geometryInfoList[ index ]; 26597 if ( geometryInfo.active === false ) { 26598 26599 continue; 26600 26601 } 26602 26603 // if a geometry contains an index buffer then shift it, as well 26604 if ( geometry.index !== null ) { 26605 26606 if ( geometryInfo.indexStart !== nextIndexStart ) { 26607 26608 const { indexStart, vertexStart, reservedIndexCount } = geometryInfo; 26609 const index = geometry.index; 26610 const array = index.array; 26611 26612 // shift the index pointers based on how the vertex data will shift 26613 // adjusting the index must happen first so the original vertex start value is available 26614 const elementDelta = nextVertexStart - vertexStart; 26615 for ( let j = indexStart; j < indexStart + reservedIndexCount; j ++ ) { 26616 26617 array[ j ] = array[ j ] + elementDelta; 26618 26619 } 26620 26621 index.array.copyWithin( nextIndexStart, indexStart, indexStart + reservedIndexCount ); 26622 index.addUpdateRange( nextIndexStart, reservedIndexCount ); 26623 index.needsUpdate = true; 26624 26625 geometryInfo.indexStart = nextIndexStart; 26626 26627 } 26628 26629 nextIndexStart += geometryInfo.reservedIndexCount; 26630 26631 } 26632 26633 // if a geometry needs to be moved then copy attribute data to overwrite unused space 26634 if ( geometryInfo.vertexStart !== nextVertexStart ) { 26635 26636 const { vertexStart, reservedVertexCount } = geometryInfo; 26637 const attributes = geometry.attributes; 26638 for ( const key in attributes ) { 26639 26640 const attribute = attributes[ key ]; 26641 const { array, itemSize } = attribute; 26642 array.copyWithin( nextVertexStart * itemSize, vertexStart * itemSize, ( vertexStart + reservedVertexCount ) * itemSize ); 26643 attribute.addUpdateRange( nextVertexStart * itemSize, reservedVertexCount * itemSize ); 26644 attribute.needsUpdate = true; 26645 26646 } 26647 26648 geometryInfo.vertexStart = nextVertexStart; 26649 26650 } 26651 26652 nextVertexStart += geometryInfo.reservedVertexCount; 26653 geometryInfo.start = geometry.index ? geometryInfo.indexStart : geometryInfo.vertexStart; 26654 26655 } 26656 26657 this._nextIndexStart = nextIndexStart; 26658 this._nextVertexStart = nextVertexStart; 26659 this._visibilityChanged = true; 26660 26661 return this; 26662 26663 } 26664 26665 /** 26666 * Returns the bounding box for the given geometry. 26667 * 26668 * @param {number} geometryId - The ID of the geometry to return the bounding box for. 26669 * @param {Box3} target - The target object that is used to store the method's result. 26670 * @return {?Box3} The geometry's bounding box. Returns `null` if no geometry has been found for the given ID. 26671 */ 26672 getBoundingBoxAt( geometryId, target ) { 26673 26674 if ( geometryId >= this._geometryCount ) { 26675 26676 return null; 26677 26678 } 26679 26680 // compute bounding box 26681 const geometry = this.geometry; 26682 const geometryInfo = this._geometryInfo[ geometryId ]; 26683 if ( geometryInfo.boundingBox === null ) { 26684 26685 const box = new Box3(); 26686 const index = geometry.index; 26687 const position = geometry.attributes.position; 26688 for ( let i = geometryInfo.start, l = geometryInfo.start + geometryInfo.count; i < l; i ++ ) { 26689 26690 let iv = i; 26691 if ( index ) { 26692 26693 iv = index.getX( iv ); 26694 26695 } 26696 26697 box.expandByPoint( _vector$5.fromBufferAttribute( position, iv ) ); 26698 26699 } 26700 26701 geometryInfo.boundingBox = box; 26702 26703 } 26704 26705 target.copy( geometryInfo.boundingBox ); 26706 return target; 26707 26708 } 26709 26710 /** 26711 * Returns the bounding sphere for the given geometry. 26712 * 26713 * @param {number} geometryId - The ID of the geometry to return the bounding sphere for. 26714 * @param {Sphere} target - The target object that is used to store the method's result. 26715 * @return {?Sphere} The geometry's bounding sphere. Returns `null` if no geometry has been found for the given ID. 26716 */ 26717 getBoundingSphereAt( geometryId, target ) { 26718 26719 if ( geometryId >= this._geometryCount ) { 26720 26721 return null; 26722 26723 } 26724 26725 // compute bounding sphere 26726 const geometry = this.geometry; 26727 const geometryInfo = this._geometryInfo[ geometryId ]; 26728 if ( geometryInfo.boundingSphere === null ) { 26729 26730 const sphere = new Sphere(); 26731 this.getBoundingBoxAt( geometryId, _box$1 ); 26732 _box$1.getCenter( sphere.center ); 26733 26734 const index = geometry.index; 26735 const position = geometry.attributes.position; 26736 26737 let maxRadiusSq = 0; 26738 for ( let i = geometryInfo.start, l = geometryInfo.start + geometryInfo.count; i < l; i ++ ) { 26739 26740 let iv = i; 26741 if ( index ) { 26742 26743 iv = index.getX( iv ); 26744 26745 } 26746 26747 _vector$5.fromBufferAttribute( position, iv ); 26748 maxRadiusSq = Math.max( maxRadiusSq, sphere.center.distanceToSquared( _vector$5 ) ); 26749 26750 } 26751 26752 sphere.radius = Math.sqrt( maxRadiusSq ); 26753 geometryInfo.boundingSphere = sphere; 26754 26755 } 26756 26757 target.copy( geometryInfo.boundingSphere ); 26758 return target; 26759 26760 } 26761 26762 /** 26763 * Sets the given local transformation matrix to the defined instance. 26764 * Negatively scaled matrices are not supported. 26765 * 26766 * @param {number} instanceId - The ID of an instance to set the matrix of. 26767 * @param {Matrix4} matrix - A 4x4 matrix representing the local transformation of a single instance. 26768 * @return {BatchedMesh} A reference to this batched mesh. 26769 */ 26770 setMatrixAt( instanceId, matrix ) { 26771 26772 this.validateInstanceId( instanceId ); 26773 26774 const matricesTexture = this._matricesTexture; 26775 const matricesArray = this._matricesTexture.image.data; 26776 matrix.toArray( matricesArray, instanceId * 16 ); 26777 matricesTexture.needsUpdate = true; 26778 26779 return this; 26780 26781 } 26782 26783 /** 26784 * Returns the local transformation matrix of the defined instance. 26785 * 26786 * @param {number} instanceId - The ID of an instance to get the matrix of. 26787 * @param {Matrix4} matrix - The target object that is used to store the method's result. 26788 * @return {Matrix4} The instance's local transformation matrix. 26789 */ 26790 getMatrixAt( instanceId, matrix ) { 26791 26792 this.validateInstanceId( instanceId ); 26793 return matrix.fromArray( this._matricesTexture.image.data, instanceId * 16 ); 26794 26795 } 26796 26797 /** 26798 * Sets the given color to the defined instance. 26799 * 26800 * @param {number} instanceId - The ID of an instance to set the color of. 26801 * @param {Color|Vector4} color - The color to set the instance to. Use a `Vector4` to also define alpha. 26802 * @return {BatchedMesh} A reference to this batched mesh. 26803 */ 26804 setColorAt( instanceId, color ) { 26805 26806 this.validateInstanceId( instanceId ); 26807 26808 if ( this._colorsTexture === null ) { 26809 26810 this._initColorsTexture(); 26811 26812 } 26813 26814 color.toArray( this._colorsTexture.image.data, instanceId * 4 ); 26815 this._colorsTexture.needsUpdate = true; 26816 26817 return this; 26818 26819 } 26820 26821 /** 26822 * Returns the color of the defined instance. 26823 * 26824 * @param {number} instanceId - The ID of an instance to get the color of. 26825 * @param {Color|Vector4} color - The target object that is used to store the method's result. 26826 * @return {Color|Vector4} The instance's color. Use a `Vector4` to also retrieve alpha. 26827 */ 26828 getColorAt( instanceId, color ) { 26829 26830 this.validateInstanceId( instanceId ); 26831 if ( this._colorsTexture === null ) { 26832 26833 if ( color.isVector4 ) { 26834 26835 return color.set( 1, 1, 1, 1 ); 26836 26837 } else { 26838 26839 return color.setRGB( 1, 1, 1 ); 26840 26841 } 26842 26843 } else { 26844 26845 return color.fromArray( this._colorsTexture.image.data, instanceId * 4 ); 26846 26847 } 26848 26849 } 26850 26851 /** 26852 * Sets the visibility of the instance. 26853 * 26854 * @param {number} instanceId - The id of the instance to set the visibility of. 26855 * @param {boolean} visible - Whether the instance is visible or not. 26856 * @return {BatchedMesh} A reference to this batched mesh. 26857 */ 26858 setVisibleAt( instanceId, visible ) { 26859 26860 this.validateInstanceId( instanceId ); 26861 26862 if ( this._instanceInfo[ instanceId ].visible === visible ) { 26863 26864 return this; 26865 26866 } 26867 26868 this._instanceInfo[ instanceId ].visible = visible; 26869 this._visibilityChanged = true; 26870 26871 return this; 26872 26873 } 26874 26875 /** 26876 * Returns the visibility state of the defined instance. 26877 * 26878 * @param {number} instanceId - The ID of an instance to get the visibility state of. 26879 * @return {boolean} Whether the instance is visible or not. 26880 */ 26881 getVisibleAt( instanceId ) { 26882 26883 this.validateInstanceId( instanceId ); 26884 26885 return this._instanceInfo[ instanceId ].visible; 26886 26887 } 26888 26889 /** 26890 * Sets the geometry ID of the instance at the given index. 26891 * 26892 * @param {number} instanceId - The ID of the instance to set the geometry ID of. 26893 * @param {number} geometryId - The geometry ID to be use by the instance. 26894 * @return {BatchedMesh} A reference to this batched mesh. 26895 */ 26896 setGeometryIdAt( instanceId, geometryId ) { 26897 26898 this.validateInstanceId( instanceId ); 26899 this.validateGeometryId( geometryId ); 26900 26901 this._instanceInfo[ instanceId ].geometryIndex = geometryId;
26902 26903 return this; 26904 26905 } 26906 26907 /** 26908 * Returns the geometry ID of the defined instance. 26909 * 26910 * @param {number} instanceId - The ID of an instance to get the geometry ID of. 26911 * @return {number} The instance's geometry ID. 26912 */ 26913 getGeometryIdAt( instanceId ) { 26914 26915 this.validateInstanceId( instanceId ); 26916 26917 return this._instanceInfo[ instanceId ].geometryIndex; 26918 26919 } 26920 26921 /** 26922 * Get the range representing the subset of triangles related to the attached geometry, 26923 * indicating the starting offset and count, or `null` if invalid. 26924 * 26925 * @param {number} geometryId - The id of the geometry to get the range of. 26926 * @param {Object} [target] - The target object that is used to store the method's result. 26927 * @return {{ 26928 * vertexStart:number,vertexCount:number,reservedVertexCount:number, 26929 * indexStart:number,indexCount:number,reservedIndexCount:number, 26930 * start:number,count:number 26931 * }} The result object with range data. 26932 */ 26933 getGeometryRangeAt( geometryId, target = {} ) { 26934 26935 this.validateGeometryId( geometryId ); 26936 26937 const geometryInfo = this._geometryInfo[ geometryId ]; 26938 target.vertexStart = geometryInfo.vertexStart; 26939 target.vertexCount = geometryInfo.vertexCount; 26940 target.reservedVertexCount = geometryInfo.reservedVertexCount; 26941 26942 target.indexStart = geometryInfo.indexStart; 26943 target.indexCount = geometryInfo.indexCount; 26944 target.reservedIndexCount = geometryInfo.reservedIndexCount; 26945 26946 target.start = geometryInfo.start; 26947 target.count = geometryInfo.count; 26948 26949 return target; 26950 26951 } 26952 26953 /** 26954 * Resizes the necessary buffers to support the provided number of instances. 26955 * If the provided arguments shrink the number of instances but there are not enough 26956 * unused Ids at the end of the list then an error is thrown. 26957 * 26958 * @param {number} maxInstanceCount - The max number of individual instances that can be added and rendered by the batch. 26959 */
vendor: 7,347 bytes, lines 26960-27189
26960 setInstanceCount( maxInstanceCount ) { 26961 26962 // shrink the available instances as much as possible 26963 const availableInstanceIds = this._availableInstanceIds; 26964 const instanceInfo = this._instanceInfo; 26965 availableInstanceIds.sort( ascIdSort ); 26966 while ( availableInstanceIds[ availableInstanceIds.length - 1 ] === instanceInfo.length - 1 ) { 26967 26968 instanceInfo.pop(); 26969 availableInstanceIds.pop(); 26970 26971 } 26972 26973 // throw an error if it can't be shrunk to the desired size 26974 if ( maxInstanceCount < instanceInfo.length ) { 26975 26976 throw new Error( `BatchedMesh: Instance ids outside the range ${ maxInstanceCount } are being used. Cannot shrink instance count.` ); 26977 26978 } 26979 26980 // copy the multi draw counts 26981 const multiDrawCounts = new Int32Array( maxInstanceCount ); 26982 const multiDrawStarts = new Int32Array( maxInstanceCount ); 26983 copyArrayContents( this._multiDrawCounts, multiDrawCounts ); 26984 copyArrayContents( this._multiDrawStarts, multiDrawStarts ); 26985 26986 this._multiDrawCounts = multiDrawCounts; 26987 this._multiDrawStarts = multiDrawStarts; 26988 this._maxInstanceCount = maxInstanceCount; 26989 26990 // update texture data for instance sampling 26991 const indirectTexture = this._indirectTexture; 26992 const matricesTexture = this._matricesTexture; 26993 const colorsTexture = this._colorsTexture; 26994 26995 indirectTexture.dispose(); 26996 this._initIndirectTexture(); 26997 copyArrayContents( indirectTexture.image.data, this._indirectTexture.image.data ); 26998 26999 matricesTexture.dispose(); 27000 this._initMatricesTexture(); 27001 copyArrayContents( matricesTexture.image.data, this._matricesTexture.image.data ); 27002 27003 if ( colorsTexture ) { 27004 27005 colorsTexture.dispose(); 27006 this._initColorsTexture(); 27007 copyArrayContents( colorsTexture.image.data, this._colorsTexture.image.data ); 27008 27009 } 27010 27011 } 27012 27013 /** 27014 * Resizes the available space in the batch's vertex and index buffer attributes to the provided sizes. 27015 * If the provided arguments shrink the geometry buffers but there is not enough unused space at the 27016 * end of the geometry attributes then an error is thrown. 27017 * 27018 * @param {number} maxVertexCount - The maximum number of vertices to be used by all unique geometries to resize to. 27019 * @param {number} maxIndexCount - The maximum number of indices to be used by all unique geometries to resize to. 27020 */ 27021 setGeometrySize( maxVertexCount, maxIndexCount ) { 27022 27023 // Check if we can shrink to the requested vertex attribute size 27024 const validRanges = [ ...this._geometryInfo ].filter( info => info.active ); 27025 const requiredVertexLength = Math.max( ...validRanges.map( range => range.vertexStart + range.reservedVertexCount ) ); 27026 if ( requiredVertexLength > maxVertexCount ) { 27027 27028 throw new Error( `BatchedMesh: Geometry vertex values are being used outside the range ${ maxIndexCount }. Cannot shrink further.` ); 27029 27030 } 27031 27032 // Check if we can shrink to the requested index attribute size 27033 if ( this.geometry.index ) { 27034 27035 const requiredIndexLength = Math.max( ...validRanges.map( range => range.indexStart + range.reservedIndexCount ) ); 27036 if ( requiredIndexLength > maxIndexCount ) { 27037 27038 throw new Error( `BatchedMesh: Geometry index values are being used outside the range ${ maxIndexCount }. Cannot shrink further.` ); 27039 27040 } 27041 27042 } 27043 27044 // 27045 27046 // dispose of the previous geometry 27047 const oldGeometry = this.geometry; 27048 oldGeometry.dispose(); 27049 27050 // recreate the geometry needed based on the previous variant 27051 this._maxVertexCount = maxVertexCount; 27052 this._maxIndexCount = maxIndexCount; 27053 27054 if ( this._geometryInitialized ) { 27055 27056 this._geometryInitialized = false; 27057 this.geometry = new BufferGeometry(); 27058 this._initializeGeometry( oldGeometry ); 27059 27060 } 27061 27062 // copy data from the previous geometry 27063 const geometry = this.geometry; 27064 if ( oldGeometry.index ) { 27065 27066 copyArrayContents( oldGeometry.index.array, geometry.index.array ); 27067 27068 } 27069 27070 for ( const key in oldGeometry.attributes ) { 27071 27072 copyArrayContents( oldGeometry.attributes[ key ].array, geometry.attributes[ key ].array ); 27073 27074 } 27075 27076 } 27077 27078 raycast( raycaster, intersects ) { 27079 27080 const instanceInfo = this._instanceInfo; 27081 const geometryInfoList = this._geometryInfo; 27082 const matrixWorld = this.matrixWorld; 27083 const batchGeometry = this.geometry; 27084 27085 // iterate over each geometry 27086 _mesh.material = this.material; 27087 _mesh.geometry.index = batchGeometry.index; 27088 _mesh.geometry.attributes = batchGeometry.attributes; 27089 if ( _mesh.geometry.boundingBox === null ) { 27090 27091 _mesh.geometry.boundingBox = new Box3(); 27092 27093 } 27094 27095 if ( _mesh.geometry.boundingSphere === null ) { 27096 27097 _mesh.geometry.boundingSphere = new Sphere(); 27098 27099 } 27100 27101 for ( let i = 0, l = instanceInfo.length; i < l; i ++ ) { 27102 27103 if ( ! instanceInfo[ i ].visible || ! instanceInfo[ i ].active ) { 27104 27105 continue; 27106 27107 } 27108 27109 const geometryId = instanceInfo[ i ].geometryIndex; 27110 const geometryInfo = geometryInfoList[ geometryId ]; 27111 _mesh.geometry.setDrawRange( geometryInfo.start, geometryInfo.count ); 27112 27113 // get the intersects 27114 this.getMatrixAt( i, _mesh.matrixWorld ).premultiply( matrixWorld ); 27115 this.getBoundingBoxAt( geometryId, _mesh.geometry.boundingBox ); 27116 this.getBoundingSphereAt( geometryId, _mesh.geometry.boundingSphere ); 27117 _mesh.raycast( raycaster, _batchIntersects ); 27118 27119 // add batch id to the intersects 27120 for ( let j = 0, l = _batchIntersects.length; j < l; j ++ ) { 27121 27122 const intersect = _batchIntersects[ j ]; 27123 intersect.object = this; 27124 intersect.batchId = i; 27125 intersects.push( intersect ); 27126 27127 } 27128 27129 _batchIntersects.length = 0; 27130 27131 } 27132 27133 _mesh.material = null; 27134 _mesh.geometry.index = null; 27135 _mesh.geometry.attributes = {}; 27136 _mesh.geometry.setDrawRange( 0, Infinity ); 27137 27138 } 27139 27140 copy( source ) { 27141 27142 super.copy( source ); 27143 27144 this.geometry = source.geometry.clone(); 27145 this.perObjectFrustumCulled = source.perObjectFrustumCulled; 27146 this.sortObjects = source.sortObjects; 27147 this.boundingBox = source.boundingBox !== null ? source.boundingBox.clone() : null; 27148 this.boundingSphere = source.boundingSphere !== null ? source.boundingSphere.clone() : null; 27149 27150 this._geometryInfo = source._geometryInfo.map( info => ( { 27151 ...info, 27152 27153 boundingBox: info.boundingBox !== null ? info.boundingBox.clone() : null, 27154 boundingSphere: info.boundingSphere !== null ? info.boundingSphere.clone() : null, 27155 } ) ); 27156 this._instanceInfo = source._instanceInfo.map( info => ( { ...info } ) ); 27157 27158 this._availableInstanceIds = source._availableInstanceIds.slice(); 27159 this._availableGeometryIds = source._availableGeometryIds.slice(); 27160 27161 this._nextIndexStart = source._nextIndexStart; 27162 this._nextVertexStart = source._nextVertexStart; 27163 this._geometryCount = source._geometryCount; 27164 27165 this._maxInstanceCount = source._maxInstanceCount; 27166 this._maxVertexCount = source._maxVertexCount; 27167 this._maxIndexCount = source._maxIndexCount; 27168 27169 this._geometryInitialized = source._geometryInitialized; 27170 this._multiDrawCounts = source._multiDrawCounts.slice(); 27171 this._multiDrawStarts = source._multiDrawStarts.slice(); 27172 27173 this._indirectTexture = source._indirectTexture.clone(); 27174 this._indirectTexture.image.data = this._indirectTexture.image.data.slice(); 27175 27176 this._matricesTexture = source._matricesTexture.clone(); 27177 this._matricesTexture.image.data = this._matricesTexture.image.data.slice(); 27178 27179 if ( this._colorsTexture !== null ) { 27180 27181 this._colorsTexture = source._colorsTexture.clone(); 27182 this._colorsTexture.image.data = this._colorsTexture.image.data.slice(); 27183 27184 } 27185 27186 return this; 27187 27188 } 27189
vendor: 10,171 bytes, lines 27190-27598
27190 /** 27191 * Frees the GPU-related resources allocated by this instance. Call this 27192 * method whenever this instance is no longer used in your app. 27193 */ 27194 dispose() { 27195 27196 // Assuming the geometry is not shared with other meshes 27197 this.geometry.dispose(); 27198 27199 this._matricesTexture.dispose(); 27200 this._matricesTexture = null; 27201 27202 this._indirectTexture.dispose(); 27203 this._indirectTexture = null; 27204 27205 if ( this._colorsTexture !== null ) { 27206 27207 this._colorsTexture.dispose(); 27208 this._colorsTexture = null; 27209 27210 } 27211 27212 } 27213 27214 onBeforeRender( renderer, scene, camera, geometry, material/*, _group*/ ) { 27215 27216 // if visibility has not changed and frustum culling and object sorting is not required 27217 // then skip iterating over all items 27218 if ( ! this._visibilityChanged && ! this.perObjectFrustumCulled && ! this.sortObjects ) { 27219 27220 return; 27221 27222 } 27223 27224 // the indexed version of the multi draw function requires specifying the start 27225 // offset in bytes. 27226 const index = geometry.getIndex(); 27227 let bytesPerElement = index === null ? 1 : index.array.BYTES_PER_ELEMENT; 27228 27229 27230 // the "wireframe" attribute implicitly creates a line attribute in the renderer, which is double 27231 // the vertices to draw (3 lines per triangle) so we multiply the draw counts / starts and make 27232 // assumptions about the index buffer byte size. 27233 let multiDrawMultiplier = 1; 27234 if ( material.wireframe ) { 27235 27236 multiDrawMultiplier = 2; 27237 bytesPerElement = geometry.attributes.position.count > 65535 ? 4 : 2; 27238 27239 } 27240 27241 const instanceInfo = this._instanceInfo; 27242 const multiDrawStarts = this._multiDrawStarts; 27243 const multiDrawCounts = this._multiDrawCounts; 27244 const geometryInfoList = this._geometryInfo; 27245 const perObjectFrustumCulled = this.perObjectFrustumCulled; 27246 const indirectTexture = this._indirectTexture; 27247 const indirectArray = indirectTexture.image.data; 27248 27249 const frustum = camera.isArrayCamera ? _frustumArray : _frustum; 27250 // prepare the frustum in the local frame 27251 if ( perObjectFrustumCulled && ! camera.isArrayCamera ) { 27252 27253 _matrix$1 27254 .multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ) 27255 .multiply( this.matrixWorld ); 27256 27257 _frustum.setFromProjectionMatrix( 27258 _matrix$1, 27259 camera.coordinateSystem, 27260 camera.reversedDepth 27261 ); 27262 27263 } 27264 27265 let multiDrawCount = 0; 27266 if ( this.sortObjects ) { 27267 27268 // get the camera position in the local frame 27269 _matrix$1.copy( this.matrixWorld ).invert(); 27270 _vector$5.setFromMatrixPosition( camera.matrixWorld ).applyMatrix4( _matrix$1 ); 27271 _forward$1.set( 0, 0, -1 ).transformDirection( camera.matrixWorld ).transformDirection( _matrix$1 ); 27272 27273 for ( let i = 0, l = instanceInfo.length; i < l; i ++ ) { 27274 27275 if ( instanceInfo[ i ].visible && instanceInfo[ i ].active ) { 27276 27277 const geometryId = instanceInfo[ i ].geometryIndex; 27278 27279 // get the bounds in world space 27280 this.getMatrixAt( i, _matrix$1 ); 27281 this.getBoundingSphereAt( geometryId, _sphere$2 ).applyMatrix4( _matrix$1 ); 27282 27283 // determine whether the batched geometry is within the frustum 27284 let culled = false; 27285 if ( perObjectFrustumCulled ) { 27286 27287 culled = ! frustum.intersectsSphere( _sphere$2, camera ); 27288 27289 } 27290 27291 if ( ! culled ) { 27292 27293 // get the distance from camera used for sorting 27294 const geometryInfo = geometryInfoList[ geometryId ]; 27295 const z = _temp.subVectors( _sphere$2.center, _vector$5 ).dot( _forward$1 ); 27296 _renderList.push( geometryInfo.start, geometryInfo.count, z, i ); 27297 27298 } 27299 27300 } 27301 27302 } 27303 27304 // Sort the draw ranges and prep for rendering 27305 const list = _renderList.list; 27306 const customSort = this.customSort; 27307 if ( customSort === null ) { 27308 27309 list.sort( material.transparent ? sortTransparent : sortOpaque ); 27310 27311 } else { 27312 27313 customSort.call( this, list, camera ); 27314 27315 } 27316 27317 for ( let i = 0, l = list.length; i < l; i ++ ) { 27318 27319 const item = list[ i ]; 27320 multiDrawStarts[ multiDrawCount ] = item.start * bytesPerElement * multiDrawMultiplier; 27321 multiDrawCounts[ multiDrawCount ] = item.count * multiDrawMultiplier; 27322 indirectArray[ multiDrawCount ] = item.index; 27323 multiDrawCount ++; 27324 27325 } 27326 27327 _renderList.reset(); 27328 27329 } else { 27330 27331 for ( let i = 0, l = instanceInfo.length; i < l; i ++ ) { 27332 27333 if ( instanceInfo[ i ].visible && instanceInfo[ i ].active ) { 27334 27335 const geometryId = instanceInfo[ i ].geometryIndex; 27336 27337 // determine whether the batched geometry is within the frustum 27338 let culled = false; 27339 if ( perObjectFrustumCulled ) { 27340 27341 // get the bounds in world space 27342 this.getMatrixAt( i, _matrix$1 ); 27343 this.getBoundingSphereAt( geometryId, _sphere$2 ).applyMatrix4( _matrix$1 ); 27344 culled = ! frustum.intersectsSphere( _sphere$2, camera ); 27345 27346 } 27347 27348 if ( ! culled ) { 27349 27350 const geometryInfo = geometryInfoList[ geometryId ]; 27351 multiDrawStarts[ multiDrawCount ] = geometryInfo.start * bytesPerElement * multiDrawMultiplier; 27352 multiDrawCounts[ multiDrawCount ] = geometryInfo.count * multiDrawMultiplier; 27353 indirectArray[ multiDrawCount ] = i; 27354 multiDrawCount ++; 27355 27356 } 27357 27358 } 27359 27360 } 27361 27362 } 27363 27364 indirectTexture.needsUpdate = true; 27365 this._multiDrawCount = multiDrawCount; 27366 this._visibilityChanged = false; 27367 27368 } 27369 27370 onBeforeShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial/* , group */ ) { 27371 27372 this.onBeforeRender( renderer, null, shadowCamera, geometry, depthMaterial ); 27373 27374 } 27375 27376} 27377 27378/** 27379 * A material for rendering line primitives. 27380 * 27381 * Materials define the appearance of renderable 3D objects. 27382 * 27383 * ```js 27384 * const material = new THREE.LineBasicMaterial( { color: 0xffffff } ); 27385 * ``` 27386 * 27387 * @augments Material 27388 */ 27389class LineBasicMaterial extends Material { 27390 27391 /** 27392 * Constructs a new line basic material. 27393 * 27394 * @param {Object} [parameters] - An object with one or more properties 27395 * defining the material's appearance. Any property of the material 27396 * (including any property from inherited materials) can be passed 27397 * in here. Color values can be passed any type of value accepted 27398 * by {@link Color#set}. 27399 */ 27400 constructor( parameters ) { 27401 27402 super(); 27403 27404 /** 27405 * This flag can be used for type testing. 27406 * 27407 * @type {boolean} 27408 * @readonly 27409 * @default true 27410 */ 27411 this.isLineBasicMaterial = true; 27412 27413 this.type = 'LineBasicMaterial'; 27414 27415 /** 27416 * Color of the material. 27417 * 27418 * @type {Color} 27419 * @default (1,1,1) 27420 */ 27421 this.color = new Color( 0xffffff ); 27422 27423 /** 27424 * Sets the color of the lines using data from a texture. The texture map 27425 * color is modulated by the diffuse `color`. 27426 * 27427 * @type {?Texture} 27428 * @default null 27429 */ 27430 this.map = null; 27431 27432 /** 27433 * Controls line thickness or lines. 27434 * 27435 * Can only be used with {@link SVGRenderer}. WebGL and WebGPU 27436 * ignore this setting and always render line primitives with a 27437 * width of one pixel. 27438 * 27439 * @type {number} 27440 * @default 1 27441 */ 27442 this.linewidth = 1; 27443 27444 /** 27445 * Defines appearance of line ends. 27446 * 27447 * Can only be used with {@link SVGRenderer}. 27448 * 27449 * @type {('butt'|'round'|'square')} 27450 * @default 'round' 27451 */ 27452 this.linecap = 'round'; 27453 27454 /** 27455 * Defines appearance of line joints. 27456 * 27457 * Can only be used with {@link SVGRenderer}. 27458 * 27459 * @type {('round'|'bevel'|'miter')} 27460 * @default 'round' 27461 */ 27462 this.linejoin = 'round'; 27463 27464 /** 27465 * Whether the material is affected by fog or not. 27466 * 27467 * @type {boolean} 27468 * @default true 27469 */ 27470 this.fog = true; 27471 27472 this.setValues( parameters ); 27473 27474 } 27475 27476 copy( source ) { 27477 27478 super.copy( source ); 27479 27480 this.color.copy( source.color ); 27481 27482 this.map = source.map; 27483 27484 this.linewidth = source.linewidth; 27485 this.linecap = source.linecap; 27486 this.linejoin = source.linejoin; 27487 27488 this.fog = source.fog; 27489 27490 return this; 27491 27492 } 27493 27494} 27495 27496const _vStart = /*@__PURE__*/ new Vector3(); 27497const _vEnd = /*@__PURE__*/ new Vector3(); 27498 27499const _inverseMatrix$1 = /*@__PURE__*/ new Matrix4(); 27500const _ray$1 = /*@__PURE__*/ new Ray(); 27501const _sphere$1 = /*@__PURE__*/ new Sphere(); 27502 27503const _intersectPointOnRay = /*@__PURE__*/ new Vector3(); 27504const _intersectPointOnSegment = /*@__PURE__*/ new Vector3(); 27505 27506/** 27507 * A continuous line. The line are rendered by connecting consecutive 27508 * vertices with straight lines. 27509 * 27510 * ```js 27511 * const material = new THREE.LineBasicMaterial( { color: 0x0000ff } ); 27512 * 27513 * const points = []; 27514 * points.push( new THREE.Vector3( - 10, 0, 0 ) ); 27515 * points.push( new THREE.Vector3( 0, 10, 0 ) ); 27516 * points.push( new THREE.Vector3( 10, 0, 0 ) ); 27517 * 27518 * const geometry = new THREE.BufferGeometry().setFromPoints( points ); 27519 * 27520 * const line = new THREE.Line( geometry, material ); 27521 * scene.add( line ); 27522 * ``` 27523 * 27524 * @augments Object3D 27525 */ 27526class Line extends Object3D { 27527 27528 /** 27529 * Constructs a new line. 27530 * 27531 * @param {BufferGeometry} [geometry] - The line geometry. 27532 * @param {Material|Array<Material>} [material] - The line material. 27533 */ 27534 constructor( geometry = new BufferGeometry(), material = new LineBasicMaterial() ) { 27535 27536 super(); 27537 27538 /** 27539 * This flag can be used for type testing. 27540 * 27541 * @type {boolean} 27542 * @readonly 27543 * @default true 27544 */ 27545 this.isLine = true; 27546 27547 this.type = 'Line'; 27548 27549 /** 27550 * The line geometry. 27551 * 27552 * @type {BufferGeometry} 27553 */ 27554 this.geometry = geometry; 27555 27556 /** 27557 * The line material. 27558 * 27559 * @type {Material|Array<Material>} 27560 * @default LineBasicMaterial 27561 */ 27562 this.material = material; 27563 27564 /** 27565 * A dictionary representing the morph targets in the geometry. The key is the 27566 * morph targets name, the value its attribute index. This member is `undefined` 27567 * by default and only set when morph targets are detected in the geometry. 27568 * 27569 * @type {Object<string,number>|undefined} 27570 * @default undefined 27571 */ 27572 this.morphTargetDictionary = undefined; 27573 27574 /** 27575 * An array of weights typically in the range `[0,1]` that specify how much of the morph 27576 * is applied. This member is `undefined` by default and only set when morph targets are 27577 * detected in the geometry. 27578 * 27579 * @type {Array<number>|undefined} 27580 * @default undefined 27581 */ 27582 this.morphTargetInfluences = undefined; 27583 27584 this.updateMorphTargets(); 27585 27586 } 27587 27588 copy( source, recursive ) { 27589 27590 super.copy( source, recursive ); 27591 27592 this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; 27593 this.geometry = source.geometry; 27594 27595 return this; 27596 27597 } 27598
vendor: 8,195 bytes, lines 27599-27941
27599 /** 27600 * Computes an array of distance values which are necessary for rendering dashed lines. 27601 * For each vertex in the geometry, the method calculates the cumulative length from the 27602 * current point to the very beginning of the line. 27603 * 27604 * @return {Line} A reference to this line. 27605 */ 27606 computeLineDistances() { 27607 27608 const geometry = this.geometry; 27609 27610 // we assume non-indexed geometry 27611 27612 if ( geometry.index === null ) { 27613 27614 const positionAttribute = geometry.attributes.position; 27615 const lineDistances = [ 0 ]; 27616 27617 for ( let i = 1, l = positionAttribute.count; i < l; i ++ ) { 27618 27619 _vStart.fromBufferAttribute( positionAttribute, i - 1 ); 27620 _vEnd.fromBufferAttribute( positionAttribute, i ); 27621 27622 lineDistances[ i ] = lineDistances[ i - 1 ]; 27623 lineDistances[ i ] += _vStart.distanceTo( _vEnd ); 27624 27625 } 27626 27627 geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); 27628 27629 } else { 27630 27631 warn( 'Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); 27632 27633 } 27634 27635 return this; 27636 27637 } 27638 27639 /** 27640 * Computes intersection points between a casted ray and this line. 27641 * 27642 * @param {Raycaster} raycaster - The raycaster. 27643 * @param {Array<Object>} intersects - The target array that holds the intersection points. 27644 */ 27645 raycast( raycaster, intersects ) { 27646 27647 const geometry = this.geometry; 27648 const matrixWorld = this.matrixWorld; 27649 const threshold = raycaster.params.Line.threshold; 27650 const drawRange = geometry.drawRange; 27651 27652 // Checking boundingSphere distance to ray 27653 27654 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); 27655 27656 _sphere$1.copy( geometry.boundingSphere ); 27657 _sphere$1.applyMatrix4( matrixWorld ); 27658 _sphere$1.radius += threshold; 27659 27660 if ( raycaster.ray.intersectsSphere( _sphere$1 ) === false ) return; 27661 27662 // 27663 27664 _inverseMatrix$1.copy( matrixWorld ).invert(); 27665 _ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 ); 27666 27667 const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); 27668 const localThresholdSq = localThreshold * localThreshold; 27669 27670 const step = this.isLineSegments ? 2 : 1; 27671 27672 const index = geometry.index; 27673 const attributes = geometry.attributes; 27674 const positionAttribute = attributes.position; 27675 27676 if ( index !== null ) { 27677 27678 const start = Math.max( 0, drawRange.start ); 27679 const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); 27680 27681 for ( let i = start, l = end - 1; i < l; i += step ) { 27682 27683 const a = index.getX( i ); 27684 const b = index.getX( i + 1 ); 27685 27686 const intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, a, b, i ); 27687 27688 if ( intersect ) { 27689 27690 intersects.push( intersect ); 27691 27692 } 27693 27694 } 27695 27696 if ( this.isLineLoop ) { 27697 27698 const a = index.getX( end - 1 ); 27699 const b = index.getX( start ); 27700 27701 const intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, a, b, end - 1 ); 27702 27703 if ( intersect ) { 27704 27705 intersects.push( intersect ); 27706 27707 } 27708 27709 } 27710 27711 } else { 27712 27713 const start = Math.max( 0, drawRange.start ); 27714 const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) ); 27715 27716 for ( let i = start, l = end - 1; i < l; i += step ) { 27717 27718 const intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, i, i + 1, i ); 27719 27720 if ( intersect ) { 27721 27722 intersects.push( intersect ); 27723 27724 } 27725 27726 } 27727 27728 if ( this.isLineLoop ) { 27729 27730 const intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, end - 1, start, end - 1 ); 27731 27732 if ( intersect ) { 27733 27734 intersects.push( intersect ); 27735 27736 } 27737 27738 } 27739 27740 } 27741 27742 } 27743 27744 /** 27745 * Sets the values of {@link Line#morphTargetDictionary} and {@link Line#morphTargetInfluences} 27746 * to make sure existing morph targets can influence this 3D object. 27747 */ 27748 updateMorphTargets() { 27749 27750 const geometry = this.geometry; 27751 27752 const morphAttributes = geometry.morphAttributes; 27753 const keys = Object.keys( morphAttributes ); 27754 27755 if ( keys.length > 0 ) { 27756 27757 const morphAttribute = morphAttributes[ keys[ 0 ] ]; 27758 27759 if ( morphAttribute !== undefined ) { 27760 27761 this.morphTargetInfluences = []; 27762 this.morphTargetDictionary = {}; 27763 27764 for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { 27765 27766 const name = morphAttribute[ m ].name || String( m ); 27767 27768 this.morphTargetInfluences.push( 0 ); 27769 this.morphTargetDictionary[ name ] = m; 27770 27771 } 27772 27773 } 27774 27775 } 27776 27777 } 27778 27779} 27780 27781function checkIntersection( object, raycaster, ray, thresholdSq, a, b, i ) { 27782 27783 const positionAttribute = object.geometry.attributes.position; 27784 27785 _vStart.fromBufferAttribute( positionAttribute, a ); 27786 _vEnd.fromBufferAttribute( positionAttribute, b ); 27787 27788 const distSq = ray.distanceSqToSegment( _vStart, _vEnd, _intersectPointOnRay, _intersectPointOnSegment ); 27789 27790 if ( distSq > thresholdSq ) return; 27791 27792 _intersectPointOnRay.applyMatrix4( object.matrixWorld ); // Move back to world space for distance calculation 27793 27794 const distance = raycaster.ray.origin.distanceTo( _intersectPointOnRay ); 27795 27796 if ( distance < raycaster.near || distance > raycaster.far ) return; 27797 27798 return { 27799 27800 distance: distance, 27801 // What do we want? intersection point on the ray or on the segment?? 27802 // point: raycaster.ray.at( distance ), 27803 point: _intersectPointOnSegment.clone().applyMatrix4( object.matrixWorld ), 27804 index: i, 27805 face: null, 27806 faceIndex: null, 27807 barycoord: null, 27808 object: object 27809 27810 }; 27811 27812} 27813 27814const _start = /*@__PURE__*/ new Vector3(); 27815const _end = /*@__PURE__*/ new Vector3(); 27816 27817/** 27818 * A series of lines drawn between pairs of vertices. 27819 * 27820 * @augments Line 27821 */ 27822class LineSegments extends Line { 27823 27824 /** 27825 * Constructs a new line segments. 27826 * 27827 * @param {BufferGeometry} [geometry] - The line geometry. 27828 * @param {Material|Array<Material>} [material] - The line material. 27829 */ 27830 constructor( geometry, material ) { 27831 27832 super( geometry, material ); 27833 27834 /** 27835 * This flag can be used for type testing. 27836 * 27837 * @type {boolean} 27838 * @readonly 27839 * @default true 27840 */ 27841 this.isLineSegments = true; 27842 27843 this.type = 'LineSegments'; 27844 27845 } 27846 27847 computeLineDistances() { 27848 27849 const geometry = this.geometry; 27850 27851 // we assume non-indexed geometry 27852 27853 if ( geometry.index === null ) { 27854 27855 const positionAttribute = geometry.attributes.position; 27856 const lineDistances = []; 27857 27858 for ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) { 27859 27860 _start.fromBufferAttribute( positionAttribute, i ); 27861 _end.fromBufferAttribute( positionAttribute, i + 1 ); 27862 27863 lineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ]; 27864 lineDistances[ i + 1 ] = lineDistances[ i ] + _start.distanceTo( _end ); 27865 27866 } 27867 27868 geometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) ); 27869 27870 } else { 27871 27872 warn( 'LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' ); 27873 27874 } 27875 27876 return this; 27877 27878 } 27879 27880} 27881 27882/** 27883 * A continuous line. This is nearly the same as {@link Line} the only difference 27884 * is that the last vertex is connected with the first vertex in order to close 27885 * the line to form a loop. 27886 * 27887 * @augments Line 27888 */ 27889class LineLoop extends Line { 27890 27891 /** 27892 * Constructs a new line loop. 27893 * 27894 * @param {BufferGeometry} [geometry] - The line geometry. 27895 * @param {Material|Array<Material>} [material] - The line material. 27896 */ 27897 constructor( geometry, material ) { 27898 27899 super( geometry, material ); 27900 27901 /** 27902 * This flag can be used for type testing. 27903 * 27904 * @type {boolean} 27905 * @readonly 27906 * @default true 27907 */ 27908 this.isLineLoop = true; 27909 27910 this.type = 'LineLoop'; 27911 27912 } 27913 27914} 27915 27916/** 27917 * A material for rendering point primitives. 27918 * 27919 * Materials define the appearance of renderable 3D objects. 27920 * 27921 * ```js 27922 * const vertices = []; 27923 * 27924 * for ( let i = 0; i < 10000; i ++ ) { 27925 * const x = THREE.MathUtils.randFloatSpread( 2000 ); 27926 * const y = THREE.MathUtils.randFloatSpread( 2000 ); 27927 * const z = THREE.MathUtils.randFloatSpread( 2000 ); 27928 * 27929 * vertices.push( x, y, z ); 27930 * } 27931 * 27932 * const geometry = new THREE.BufferGeometry(); 27933 * geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) ); 27934 * const material = new THREE.PointsMaterial( { color: 0x888888 } ); 27935 * const points = new THREE.Points( geometry, material ); 27936 * scene.add( points ); 27937 * ``` 27938 * 27939 * @augments Material 27940 */ 27941class PointsMaterial extends Material
vendor: 8,535 bytes, lines 27941-28287
27941 { 27942 27943 /** 27944 * Constructs a new points material. 27945 * 27946 * @param {Object} [parameters] - An object with one or more properties 27947 * defining the material's appearance. Any property of the material 27948 * (including any property from inherited materials) can be passed 27949 * in here. Color values can be passed any type of value accepted 27950 * by {@link Color#set}. 27951 */ 27952 constructor( parameters ) { 27953 27954 super(); 27955 27956 /** 27957 * This flag can be used for type testing. 27958 * 27959 * @type {boolean} 27960 * @readonly 27961 * @default true 27962 */ 27963 this.isPointsMaterial = true; 27964 27965 this.type = 'PointsMaterial'; 27966 27967 /** 27968 * Color of the material. 27969 * 27970 * @type {Color} 27971 * @default (1,1,1) 27972 */ 27973 this.color = new Color( 0xffffff ); 27974 27975 /** 27976 * The color map. May optionally include an alpha channel, typically combined 27977 * with {@link Material#transparent} or {@link Material#alphaTest}. The texture map 27978 * color is modulated by the diffuse `color`. 27979 * 27980 * @type {?Texture} 27981 * @default null 27982 */ 27983 this.map = null; 27984 27985 /** 27986 * The alpha map is a grayscale texture that controls the opacity across the 27987 * surface (black: fully transparent; white: fully opaque). 27988 * 27989 * Only the color of the texture is used, ignoring the alpha channel if one 27990 * exists. For RGB and RGBA textures, the renderer will use the green channel 27991 * when sampling this texture due to the extra bit of precision provided for 27992 * green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and 27993 * luminance/alpha textures will also still work as expected. 27994 * 27995 * @type {?Texture} 27996 * @default null 27997 */ 27998 this.alphaMap = null; 27999 28000 /** 28001 * Defines the size of the points in pixels. 28002 * 28003 * Might be capped if the value exceeds hardware dependent parameters like [gl.ALIASED_POINT_SIZE_RANGE](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/getParamete). 28004 * 28005 * @type {number} 28006 * @default 1 28007 */ 28008 this.size = 1; 28009 28010 /** 28011 * Specifies whether size of individual points is attenuated by the camera depth (perspective camera only). 28012 * 28013 * @type {boolean} 28014 * @default true 28015 */ 28016 this.sizeAttenuation = true; 28017 28018 /** 28019 * Whether the material is affected by fog or not. 28020 * 28021 * @type {boolean} 28022 * @default true 28023 */ 28024 this.fog = true; 28025 28026 this.setValues( parameters ); 28027 28028 } 28029 28030 copy( source ) { 28031 28032 super.copy( source ); 28033 28034 this.color.copy( source.color ); 28035 28036 this.map = source.map; 28037 28038 this.alphaMap = source.alphaMap; 28039 28040 this.size = source.size; 28041 this.sizeAttenuation = source.sizeAttenuation; 28042 28043 this.fog = source.fog; 28044 28045 return this; 28046 28047 } 28048 28049} 28050 28051const _inverseMatrix = /*@__PURE__*/ new Matrix4(); 28052const _ray = /*@__PURE__*/ new Ray(); 28053const _sphere = /*@__PURE__*/ new Sphere(); 28054const _position$3 = /*@__PURE__*/ new Vector3(); 28055 28056/** 28057 * A class for displaying points or point clouds. 28058 * 28059 * @augments Object3D 28060 */ 28061class Points extends Object3D { 28062 28063 /** 28064 * Constructs a new point cloud. 28065 * 28066 * @param {BufferGeometry} [geometry] - The points geometry. 28067 * @param {Material|Array<Material>} [material] - The points material. 28068 */ 28069 constructor( geometry = new BufferGeometry(), material = new PointsMaterial() ) { 28070 28071 super(); 28072 28073 /** 28074 * This flag can be used for type testing. 28075 * 28076 * @type {boolean} 28077 * @readonly 28078 * @default true 28079 */ 28080 this.isPoints = true; 28081 28082 this.type = 'Points'; 28083 28084 /** 28085 * The points geometry. 28086 * 28087 * @type {BufferGeometry} 28088 */ 28089 this.geometry = geometry; 28090 28091 /** 28092 * The line material. 28093 * 28094 * @type {Material|Array<Material>} 28095 * @default PointsMaterial 28096 */ 28097 this.material = material; 28098 28099 /** 28100 * A dictionary representing the morph targets in the geometry. The key is the 28101 * morph targets name, the value its attribute index. This member is `undefined` 28102 * by default and only set when morph targets are detected in the geometry. 28103 * 28104 * @type {Object<string,number>|undefined} 28105 * @default undefined 28106 */ 28107 this.morphTargetDictionary = undefined; 28108 28109 /** 28110 * An array of weights typically in the range `[0,1]` that specify how much of the morph 28111 * is applied. This member is `undefined` by default and only set when morph targets are 28112 * detected in the geometry. 28113 * 28114 * @type {Array<number>|undefined} 28115 * @default undefined 28116 */ 28117 this.morphTargetInfluences = undefined; 28118 28119 this.updateMorphTargets(); 28120 28121 } 28122 28123 copy( source, recursive ) { 28124 28125 super.copy( source, recursive ); 28126 28127 this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; 28128 this.geometry = source.geometry; 28129 28130 return this; 28131 28132 } 28133 28134 /** 28135 * Computes intersection points between a casted ray and this point cloud. 28136 * 28137 * @param {Raycaster} raycaster - The raycaster. 28138 * @param {Array<Object>} intersects - The target array that holds the intersection points. 28139 */ 28140 raycast( raycaster, intersects ) { 28141 28142 const geometry = this.geometry; 28143 const matrixWorld = this.matrixWorld; 28144 const threshold = raycaster.params.Points.threshold; 28145 const drawRange = geometry.drawRange; 28146 28147 // Checking boundingSphere distance to ray 28148 28149 if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); 28150 28151 _sphere.copy( geometry.boundingSphere ); 28152 _sphere.applyMatrix4( matrixWorld ); 28153 _sphere.radius += threshold; 28154 28155 if ( raycaster.ray.intersectsSphere( _sphere ) === false ) return; 28156 28157 // 28158 28159 _inverseMatrix.copy( matrixWorld ).invert(); 28160 _ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix ); 28161 28162 const localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 ); 28163 const localThresholdSq = localThreshold * localThreshold; 28164 28165 const index = geometry.index; 28166 const attributes = geometry.attributes; 28167 const positionAttribute = attributes.position; 28168 28169 if ( index !== null ) { 28170 28171 const start = Math.max( 0, drawRange.start ); 28172 const end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); 28173 28174 for ( let i = start, il = end; i < il; i ++ ) { 28175 28176 const a = index.getX( i ); 28177 28178 _position$3.fromBufferAttribute( positionAttribute, a ); 28179 28180 testPoint( _position$3, a, localThresholdSq, matrixWorld, raycaster, intersects, this ); 28181 28182 } 28183 28184 } else { 28185 28186 const start = Math.max( 0, drawRange.start ); 28187 const end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) ); 28188 28189 for ( let i = start, l = end; i < l; i ++ ) { 28190 28191 _position$3.fromBufferAttribute( positionAttribute, i ); 28192 28193 testPoint( _position$3, i, localThresholdSq, matrixWorld, raycaster, intersects, this ); 28194 28195 } 28196 28197 } 28198 28199 } 28200 28201 /** 28202 * Sets the values of {@link Points#morphTargetDictionary} and {@link Points#morphTargetInfluences} 28203 * to make sure existing morph targets can influence this 3D object. 28204 */ 28205 updateMorphTargets() { 28206 28207 const geometry = this.geometry; 28208 28209 const morphAttributes = geometry.morphAttributes; 28210 const keys = Object.keys( morphAttributes ); 28211 28212 if ( keys.length > 0 ) { 28213 28214 const morphAttribute = morphAttributes[ keys[ 0 ] ]; 28215 28216 if ( morphAttribute !== undefined ) { 28217 28218 this.morphTargetInfluences = []; 28219 this.morphTargetDictionary = {}; 28220 28221 for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { 28222 28223 const name = morphAttribute[ m ].name || String( m ); 28224 28225 this.morphTargetInfluences.push( 0 ); 28226 this.morphTargetDictionary[ name ] = m; 28227 28228 } 28229 28230 } 28231 28232 } 28233 28234 } 28235 28236} 28237 28238function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) { 28239 28240 const rayPointDistanceSq = _ray.distanceSqToPoint( point ); 28241 28242 if ( rayPointDistanceSq < localThresholdSq ) { 28243 28244 const intersectPoint = new Vector3(); 28245 28246 _ray.closestPointToPoint( point, intersectPoint ); 28247 intersectPoint.applyMatrix4( matrixWorld ); 28248 28249 const distance = raycaster.ray.origin.distanceTo( intersectPoint ); 28250 28251 if ( distance < raycaster.near || distance > raycaster.far ) return; 28252 28253 intersects.push( { 28254 28255 distance: distance, 28256 distanceToRay: Math.sqrt( rayPointDistanceSq ), 28257 point: intersectPoint, 28258 index: index, 28259 face: null, 28260 faceIndex: null, 28261 barycoord: null, 28262 object: object 28263 28264 } ); 28265 28266 } 28267 28268} 28269 28270/** 28271 * A texture for use with a video. 28272 * 28273 * ```js 28274 * // assuming you have created a HTML video element with id="video" 28275 * const video = document.getElementById( 'video' ); 28276 * const texture = new THREE.VideoTexture( video ); 28277 * ``` 28278 * 28279 * Note: When using video textures with {@link WebGPURenderer}, {@link Texture#colorSpace} must be 28280 * set to THREE.SRGBColorSpace. 28281 * 28282 * Note: After the initial use of a texture, its dimensions, format, and type 28283 * cannot be changed. Instead, call {@link Texture#dispose} on the texture and instantiate a new one. 28284 * 28285 * @augments Texture 28286 */ 28287class VideoTexture extends Texture
vendor: 4,083 bytes, lines 28287-28434
28287 { 28288 28289 /** 28290 * Constructs a new video texture. 28291 * 28292 * @param {HTMLVideoElement} video - The video element to use as a data source for the texture. 28293 * @param {number} [mapping=Texture.DEFAULT_MAPPING] - The texture mapping. 28294 * @param {number} [wrapS=ClampToEdgeWrapping] - The wrapS value. 28295 * @param {number} [wrapT=ClampToEdgeWrapping] - The wrapT value. 28296 * @param {number} [magFilter=LinearFilter] - The mag filter value. 28297 * @param {number} [minFilter=LinearFilter] - The min filter value. 28298 * @param {number} [format=RGBAFormat] - The texture format. 28299 * @param {number} [type=UnsignedByteType] - The texture type. 28300 * @param {number} [anisotropy=Texture.DEFAULT_ANISOTROPY] - The anisotropy value. 28301 */ 28302 constructor( video, mapping, wrapS, wrapT, magFilter = LinearFilter, minFilter = LinearFilter, format, type, anisotropy ) { 28303 28304 super( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); 28305 28306 /** 28307 * This flag can be used for type testing. 28308 * 28309 * @type {boolean} 28310 * @readonly 28311 * @default true 28312 */ 28313 this.isVideoTexture = true; 28314 28315 /** 28316 * Whether to generate mipmaps (if possible) for a texture. 28317 * 28318 * Overwritten and set to `false` by default. 28319 * 28320 * @type {boolean} 28321 * @default false 28322 */ 28323 this.generateMipmaps = false; 28324 28325 /** 28326 * The video frame request callback identifier, which is a positive integer. 28327 * 28328 * Value of 0 represents no scheduled rVFC. 28329 * 28330 * @private 28331 * @type {number} 28332 */ 28333 this._requestVideoFrameCallbackId = 0; 28334 28335 const scope = this; 28336 28337 function updateVideo() { 28338 28339 scope.needsUpdate = true; 28340 scope._requestVideoFrameCallbackId = video.requestVideoFrameCallback( updateVideo ); 28341 28342 } 28343 28344 if ( 'requestVideoFrameCallback' in video ) { 28345 28346 this._requestVideoFrameCallbackId = video.requestVideoFrameCallback( updateVideo ); 28347 28348 } 28349 28350 } 28351 28352 clone() { 28353 28354 return new this.constructor( this.image ).copy( this ); 28355 28356 } 28357 28358 /** 28359 * This method is called automatically by the renderer and sets {@link Texture#needsUpdate} 28360 * to `true` every time a new frame is available. 28361 * 28362 * Only relevant if `requestVideoFrameCallback` is not supported in the browser. 28363 */ 28364 update() { 28365 28366 const video = this.image; 28367 const hasVideoFrameCallback = 'requestVideoFrameCallback' in video; 28368 28369 if ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) { 28370 28371 this.needsUpdate = true; 28372 28373 } 28374 28375 } 28376 28377 dispose() { 28378 28379 if ( this._requestVideoFrameCallbackId !== 0 ) { 28380 28381 this.source.data.cancelVideoFrameCallback( this._requestVideoFrameCallbackId ); 28382 28383 this._requestVideoFrameCallbackId = 0; 28384 28385 } 28386 28387 super.dispose(); 28388 28389 } 28390 28391} 28392 28393/** 28394 * This class can be used as an alternative way to define video data. Instead of using 28395 * an instance of `HTMLVideoElement` like with `VideoTexture`, `VideoFrameTexture` expects each frame is 28396 * defined manually via {@link VideoFrameTexture#setFrame}. A typical use case for this module is when 28397 * video frames are decoded with the WebCodecs API. 28398 * 28399 * ```js 28400 * const texture = new THREE.VideoFrameTexture(); 28401 * texture.setFrame( frame ); 28402 * ``` 28403 * 28404 * @augments VideoTexture 28405 */ 28406class VideoFrameTexture extends VideoTexture { 28407 28408 /** 28409 * Constructs a new video frame texture. 28410 * 28411 * @param {number} [mapping=Texture.DEFAULT_MAPPING] - The texture mapping. 28412 * @param {number} [wrapS=ClampToEdgeWrapping] - The wrapS value. 28413 * @param {number} [wrapT=ClampToEdgeWrapping] - The wrapT value. 28414 * @param {number} [magFilter=LinearFilter] - The mag filter value. 28415 * @param {number} [minFilter=LinearFilter] - The min filter value. 28416 * @param {number} [format=RGBAFormat] - The texture format. 28417 * @param {number} [type=UnsignedByteType] - The texture type. 28418 * @param {number} [anisotropy=Texture.DEFAULT_ANISOTROPY] - The anisotropy value. 28419 */ 28420 constructor( mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { 28421 28422 super( {}, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); 28423 28424 /** 28425 * This flag can be used for type testing. 28426 * 28427 * @type {boolean} 28428 * @readonly 28429 * @default true 28430 */ 28431 this.isVideoFrameTexture = true; 28432 28433 } 28434
28435 /** 28436 * This method overwritten with an empty implementation since 28437 * this type of texture is updated via `setFrame()`. 28438 */ 28439 update() {} 28440 28441 clone() { 28442 28443 return new this.constructor().copy( this ); // restoring Texture.clone() 28444 28445 } 28446 28447 /** 28448 * Sets the current frame of the video. This will automatically update the texture 28449 * so the data can be used for rendering. 28450 * 28451 * @param {VideoFrame} frame - The video frame. 28452 */ 28453 setFrame( frame ) { 28454 28455 this.image = frame; 28456 this.needsUpdate = true; 28457 28458 } 28459 28460} 28461 28462/** 28463 * This class can only be used in combination with `copyFramebufferToTexture()` methods 28464 * of renderers. It extracts the contents of the current bound framebuffer and provides it 28465 * as a texture for further usage. 28466 * 28467 * ```js 28468 * const pixelRatio = window.devicePixelRatio; 28469 * const textureSize = 128 * pixelRatio; 28470 * 28471 * const frameTexture = new FramebufferTexture( textureSize, textureSize ); 28472 * 28473 * // calculate start position for copying part of the frame data 28474 * const vector = new Vector2(); 28475 * vector.x = ( window.innerWidth * pixelRatio / 2 ) - ( textureSize / 2 ); 28476 * vector.y = ( window.innerHeight * pixelRatio / 2 ) - ( textureSize / 2 ); 28477 * 28478 * renderer.render( scene, camera ); 28479 * 28480 * // copy part of the rendered frame into the framebuffer texture 28481 * renderer.copyFramebufferToTexture( frameTexture, vector ); 28482 * ``` 28483 * 28484 * @augments Texture 28485 */ 28486class FramebufferTexture extends Texture { 28487 28488 /** 28489 * Constructs a new framebuffer texture. 28490 * 28491 * @param {number} [width] - The width of the texture. 28492 * @param {number} [height] - The height of the texture. 28493 */ 28494 constructor( width, height ) { 28495 28496 super( { width, height } ); 28497 28498 /** 28499 * This flag can be used for type testing. 28500 * 28501 * @type {boolean} 28502 * @readonly 28503 * @default true 28504 */ 28505 this.isFramebufferTexture = true; 28506 28507 /** 28508 * How the texture is sampled when a texel covers more than one pixel. 28509 * 28510 * Overwritten and set to `NearestFilter` by default to disable filtering. 28511 * 28512 * @type {(NearestFilter|NearestMipmapNearestFilter|NearestMipmapLinearFilter|LinearFilter|LinearMipmapNearestFilter|LinearMipmapLinearFilter)} 28513 * @default NearestFilter 28514 */ 28515 this.magFilter = NearestFilter; 28516 28517 /** 28518 * How the texture is sampled when a texel covers less than one pixel. 28519 * 28520 * Overwritten and set to `NearestFilter` by default to disable filtering. 28521 * 28522 * @type {(NearestFilter|NearestMipmapNearestFilter|NearestMipmapLinearFilter|LinearFilter|LinearMipmapNearestFilter|LinearMipmapLinearFilter)} 28523 * @default NearestFilter 28524 */ 28525 this.minFilter = NearestFilter; 28526 28527 /** 28528 * Whether to generate mipmaps (if possible) for a texture. 28529 * 28530 * Overwritten and set to `false` by default. 28531 * 28532 * @type {boolean} 28533 * @default false 28534 */ 28535 this.generateMipmaps = false; 28536 28537 this.needsUpdate = true; 28538 28539 } 28540 28541} 28542 28543/** 28544 * Creates a texture based on data in compressed form. 28545 * 28546 * These texture are usually loaded with {@link CompressedTextureLoader}. 28547 * 28548 * @augments Texture 28549 */ 28550class CompressedTexture extends Texture { 28551 28552 /** 28553 * Constructs a new compressed texture. 28554 * 28555 * @param {Array<Object>} mipmaps - This array holds for all mipmaps (including the bases mip) 28556 * the data and dimensions. 28557 * @param {number} width - The width of the texture. 28558 * @param {number} height - The height of the texture. 28559 * @param {number} [format=RGBAFormat] - The texture format. 28560 * @param {number} [type=UnsignedByteType] - The texture type. 28561 * @param {number} [mapping=Texture.DEFAULT_MAPPING] - The texture mapping. 28562 * @param {number} [wrapS=ClampToEdgeWrapping] - The wrapS value. 28563 * @param {number} [wrapT=ClampToEdgeWrapping] - The wrapT value. 28564 * @param {number} [magFilter=LinearFilter] - The mag filter value. 28565 * @param {number} [minFilter=LinearMipmapLinearFilter] - The min filter value. 28566 * @param {number} [anisotropy=Texture.DEFAULT_ANISOTROPY] - The anisotropy value. 28567 * @param {string} [colorSpace=NoColorSpace] - The color space. 28568 */ 28569 constructor( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, colorSpace ) { 28570 28571 super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ); 28572 28573 /** 28574 * This flag can be used for type testing. 28575 * 28576 * @type {boolean} 28577 * @readonly 28578 * @default true 28579 */ 28580 this.isCompressedTexture = true; 28581 28582 /** 28583 * The image property of a compressed texture just defines its dimensions. 28584 * 28585 * @type {{width:number,height:number}} 28586 */ 28587 this.image = { width: width, height: height }; 28588 28589 /** 28590 * This array holds for all mipmaps (including the bases mip) the data and dimensions. 28591 * 28592 * @type {Array<Object>} 28593 */ 28594 this.mipmaps = mipmaps; 28595 28596 /** 28597 * If set to `true`, the texture is flipped along the vertical axis when 28598 * uploaded to the GPU. 28599 * 28600 * Overwritten and set to `false` by default since it is not possible to 28601 * flip compressed textures. 28602 * 28603 * @type {boolean} 28604 * @default false 28605 * @readonly 28606 */ 28607 this.flipY = false;
28608 28609 /** 28610 * Whether to generate mipmaps (if possible) for a texture. 28611 * 28612 * Overwritten and set to `false` by default since it is not 28613 * possible to generate mipmaps for compressed data. Mipmaps 28614 * must be embedded in the compressed texture file. 28615 * 28616 * @type {boolean} 28617 * @default false 28618 * @readonly 28619 */ 28620 this.generateMipmaps = false; 28621 28622 } 28623 28624} 28625 28626/** 28627 * Creates a texture 2D array based on data in compressed form. 28628 * 28629 * These texture are usually loaded with {@link CompressedTextureLoader}. 28630 * 28631 * @augments CompressedTexture 28632 */ 28633class CompressedArrayTexture extends CompressedTexture { 28634 28635 /** 28636 * Constructs a new compressed array texture. 28637 * 28638 * @param {Array<Object>} mipmaps - This array holds for all mipmaps (including the bases mip) 28639 * the data and dimensions. 28640 * @param {number} width - The width of the texture. 28641 * @param {number} height - The height of the texture. 28642 * @param {number} depth - The depth of the texture. 28643 * @param {number} [format=RGBAFormat] - The min filter value. 28644 * @param {number} [type=UnsignedByteType] - The min filter value. 28645 */ 28646 constructor( mipmaps, width, height, depth, format, type ) { 28647 28648 super( mipmaps, width, height, format, type ); 28649 28650 /** 28651 * This flag can be used for type testing. 28652 * 28653 * @type {boolean} 28654 * @readonly 28655 * @default true 28656 */ 28657 this.isCompressedArrayTexture = true; 28658 28659 /** 28660 * The image property of a compressed texture just defines its dimensions. 28661 * 28662 * @name CompressedArrayTexture#image 28663 * @type {{width:number,height:number,depth:number}} 28664 */ 28665 this.image.depth = depth; 28666 28667 /** 28668 * This defines how the texture is wrapped in the depth and corresponds to 28669 * *W* in UVW mapping. 28670 * 28671 * @type {(RepeatWrapping|ClampToEdgeWrapping|MirroredRepeatWrapping)} 28672 * @default ClampToEdgeWrapping 28673 */ 28674 this.wrapR = ClampToEdgeWrapping; 28675 28676 /** 28677 * A set of all layers which need to be updated in the texture. 28678 * 28679 * @type {Set<number>} 28680 */ 28681 this.layerUpdates = new Set(); 28682 28683 } 28684 28685 /** 28686 * Describes that a specific layer of the texture needs to be updated. 28687 * Normally when {@link Texture#needsUpdate} is set to `true`, the 28688 * entire compressed texture array is sent to the GPU. Marking specific 28689 * layers will only transmit subsets of all mipmaps associated with a 28690 * specific depth in the array which is often much more performant. 28691 * 28692 * @param {number} layerIndex - The layer index that should be updated. 28693 */ 28694 addLayerUpdate( layerIndex ) { 28695 28696 this.layerUpdates.add( layerIndex ); 28697 28698 } 28699 28700 /** 28701 * Resets the layer updates registry. 28702 */ 28703 clearLayerUpdates() { 28704 28705 this.layerUpdates.clear(); 28706 28707 } 28708 28709} 28710 28711/** 28712 * Creates a cube texture based on data in compressed form. 28713 * 28714 * These texture are usually loaded with {@link CompressedTextureLoader}. 28715 * 28716 * @augments CompressedTexture 28717 */ 28718class CompressedCubeTexture extends CompressedTexture { 28719 28720 /** 28721 * Constructs a new compressed texture. 28722 * 28723 * @param {Array<CompressedTexture>} images - An array of compressed textures. 28724 * @param {number} [format=RGBAFormat] - The texture format. 28725 * @param {number} [type=UnsignedByteType] - The texture type. 28726 */ 28727 constructor( images, format, type ) { 28728 28729 super( undefined, images[ 0 ].width, images[ 0 ].height, format, type, CubeReflectionMapping ); 28730 28731 /** 28732 * This flag can be used for type testing. 28733 * 28734 * @type {boolean} 28735 * @readonly 28736 * @default true 28737 */ 28738 this.isCompressedCubeTexture = true; 28739 28740 /** 28741 * This flag can be used for type testing. 28742 * 28743 * @type {boolean} 28744 * @readonly 28745 * @default true 28746 */ 28747 this.isCubeTexture = true; 28748 28749 this.image = images; 28750 28751 } 28752 28753} 28754 28755/** 28756 * Creates a cube texture made up of six images. 28757 * 28758 * ```js 28759 * const loader = new THREE.CubeTextureLoader(); 28760 * loader.setPath( 'textures/cube/pisa/' ); 28761 * 28762 * const textureCube = loader.load( [ 28763 * 'px.png', 'nx.png', 'py.png', 'ny.png', 'pz.png', 'nz.png' 28764 * ] ); 28765 * 28766 * const material = new THREE.MeshBasicMaterial( { color: 0xffffff, envMap: textureCube } ); 28767 * ``` 28768 * 28769 * @augments Texture 28770 */ 28771class CubeTexture extends Texture { 28772 28773 /** 28774 * Constructs a new cube texture. 28775 * 28776 * @param {Array<Image>} [images=[]] - An array holding a image for each side of a cube. 28777 * @param {number} [mapping=CubeReflectionMapping] - The texture mapping. 28778 * @param {number} [wrapS=ClampToEdgeWrapping] - The wrapS value. 28779 * @param {number} [wrapT=ClampToEdgeWrapping] - The wrapT value. 28780 * @param {number} [magFilter=LinearFilter] - The mag filter value. 28781 * @param {number} [minFilter=LinearMipmapLinearFilter] - The min filter value. 28782 * @param {number} [format=RGBAFormat] - The texture format. 28783 * @param {number} [type=UnsignedByteType] - The texture type. 28784 * @param {number} [anisotropy=Texture.DEFAULT_ANISOTROPY] - The anisotropy value. 28785 * @param {string}
vendor: 5,834 bytes, lines 28785-28998
28785 [colorSpace=NoColorSpace] - The color space value. 28786 */ 28787 constructor( images = [], mapping = CubeReflectionMapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ) { 28788 28789 super( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ); 28790 28791 /** 28792 * This flag can be used for type testing. 28793 * 28794 * @type {boolean} 28795 * @readonly 28796 * @default true 28797 */ 28798 this.isCubeTexture = true; 28799 28800 /** 28801 * If set to `true`, the texture is flipped along the vertical axis when 28802 * uploaded to the GPU. 28803 * 28804 * Overwritten and set to `false` by default. 28805 * 28806 * @type {boolean} 28807 * @default false 28808 */ 28809 this.flipY = false; 28810 28811 } 28812 28813 /** 28814 * Alias for {@link CubeTexture#image}. 28815 * 28816 * @type {Array<Image>} 28817 */ 28818 get images() { 28819 28820 return this.image; 28821 28822 } 28823 28824 set images( value ) { 28825 28826 this.image = value; 28827 28828 } 28829 28830} 28831 28832/** 28833 * Creates a texture from a canvas element. 28834 * 28835 * This is almost the same as the base texture class, except that it sets {@link Texture#needsUpdate} 28836 * to `true` immediately since a canvas can directly be used for rendering. 28837 * 28838 * @augments Texture 28839 */ 28840class CanvasTexture extends Texture { 28841 28842 /** 28843 * Constructs a new texture. 28844 * 28845 * @param {HTMLCanvasElement} [canvas] - The HTML canvas element. 28846 * @param {number} [mapping=Texture.DEFAULT_MAPPING] - The texture mapping. 28847 * @param {number} [wrapS=ClampToEdgeWrapping] - The wrapS value. 28848 * @param {number} [wrapT=ClampToEdgeWrapping] - The wrapT value. 28849 * @param {number} [magFilter=LinearFilter] - The mag filter value. 28850 * @param {number} [minFilter=LinearMipmapLinearFilter] - The min filter value. 28851 * @param {number} [format=RGBAFormat] - The texture format. 28852 * @param {number} [type=UnsignedByteType] - The texture type. 28853 * @param {number} [anisotropy=Texture.DEFAULT_ANISOTROPY] - The anisotropy value. 28854 */ 28855 constructor( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { 28856 28857 super( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); 28858 28859 /** 28860 * This flag can be used for type testing. 28861 * 28862 * @type {boolean} 28863 * @readonly 28864 * @default true 28865 */ 28866 this.isCanvasTexture = true; 28867 28868 this.needsUpdate = true; 28869 28870 } 28871 28872} 28873 28874/** 28875 * Creates a texture from an HTML element. 28876 * 28877 * This is almost the same as the base texture class, except that it sets {@link Texture#needsUpdate} 28878 * to `true` immediately and listens for the parent canvas's paint events to trigger updates. 28879 * 28880 * @augments Texture 28881 */ 28882class HTMLTexture extends Texture { 28883 28884 /** 28885 * Constructs a new texture. 28886 * 28887 * @param {HTMLElement} [element] - The HTML element. 28888 * @param {number} [mapping=Texture.DEFAULT_MAPPING] - The texture mapping. 28889 * @param {number} [wrapS=ClampToEdgeWrapping] - The wrapS value. 28890 * @param {number} [wrapT=ClampToEdgeWrapping] - The wrapT value. 28891 * @param {number} [magFilter=LinearFilter] - The mag filter value. 28892 * @param {number} [minFilter=LinearMipmapLinearFilter] - The min filter value. 28893 * @param {number} [format=RGBAFormat] - The texture format. 28894 * @param {number} [type=UnsignedByteType] - The texture type. 28895 * @param {number} [anisotropy=Texture.DEFAULT_ANISOTROPY] - The anisotropy value. 28896 */ 28897 constructor( element, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { 28898 28899 super( element, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); 28900 28901 /** 28902 * This flag can be used for type testing. 28903 * 28904 * @type {boolean} 28905 * @readonly 28906 * @default true 28907 */ 28908 this.isHTMLTexture = true; 28909 this.generateMipmaps = false; 28910 28911 this.needsUpdate = true; 28912 28913 const parent = element ? element.parentNode : null; 28914 28915 if ( parent !== null && 'requestPaint' in parent ) { 28916 28917 parent.onpaint = () => { 28918 28919 this.needsUpdate = true; 28920 28921 }; 28922 28923 parent.requestPaint(); 28924 28925 } 28926 28927 } 28928 28929 dispose() { 28930 28931 const parent = this.image ? this.image.parentNode : null; 28932 28933 if ( parent !== null && 'onpaint' in parent ) { 28934 28935 parent.onpaint = null; 28936 28937 } 28938 28939 super.dispose(); 28940 28941 } 28942 28943} 28944 28945/** 28946 * This class can be used to automatically save the depth information of a 28947 * rendering into a texture. 28948 * 28949 * @augments Texture 28950 */ 28951class DepthTexture extends Texture { 28952 28953 /** 28954 * Constructs a new depth texture. 28955 * 28956 * @param {number} width - The width of the texture. 28957 * @param {number} height - The height of the texture. 28958 * @param {number} [type=UnsignedIntType] - The texture type. 28959 * @param {number} [mapping=Texture.DEFAULT_MAPPING] - The texture mapping. 28960 * @param {number} [wrapS=ClampToEdgeWrapping] - The wrapS value. 28961 * @param {number} [wrapT=ClampToEdgeWrapping] - The wrapT value. 28962 * @param {number} [magFilter=LinearFilter] - The mag filter value. 28963 * @param {number} [minFilter=LinearFilter] - The min filter value. 28964 * @param {number} [anisotropy=Texture.DEFAULT_ANISOTROPY] - The anisotropy value. 28965 * @param {number} [format=DepthFormat] - The texture format. 28966 * @param {number} [depth=1] - The depth of the texture. 28967 */ 28968 constructor( width, height, type = UnsignedIntType, mapping, wrapS, wrapT, magFilter = NearestFilter, minFilter = NearestFilter, anisotropy, format = DepthFormat, depth = 1 ) { 28969 28970 if ( format !== DepthFormat && format !== DepthStencilFormat ) { 28971 28972 throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ); 28973 28974 } 28975 28976 const image = { width: width, height: height, depth: depth }; 28977 28978 super( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); 28979 28980 /** 28981 * This flag can be used for type testing. 28982 * 28983 * @type {boolean} 28984 * @readonly 28985 * @default true 28986 */ 28987 this.isDepthTexture = true; 28988 28989 /** 28990 * If set to `true`, the texture is flipped along the vertical axis when 28991 * uploaded to the GPU. 28992 * 28993 * Overwritten and set to `false` by default. 28994 * 28995 * @type {boolean} 28996 * @default false 28997 */ 28998 this.flipY = false;
vendor: 3,182 bytes, lines 28999-29123
28999 29000 /** 29001 * Whether to generate mipmaps (if possible) for a texture. 29002 * 29003 * Overwritten and set to `false` by default. 29004 * 29005 * @type {boolean} 29006 * @default false 29007 */ 29008 this.generateMipmaps = false; 29009 29010 /** 29011 * Code corresponding to the depth compare function. 29012 * 29013 * @type {?(NeverCompare|LessCompare|EqualCompare|LessEqualCompare|GreaterCompare|NotEqualCompare|GreaterEqualCompare|AlwaysCompare)} 29014 * @default null 29015 */ 29016 this.compareFunction = null; 29017 29018 } 29019 29020 29021 copy( source ) { 29022 29023 super.copy( source ); 29024 29025 this.source = new Source( Object.assign( {}, source.image ) ); // see #30540 29026 this.compareFunction = source.compareFunction; 29027 29028 return this; 29029 29030 } 29031 29032 toJSON( meta ) { 29033 29034 const data = super.toJSON( meta ); 29035 29036 if ( this.compareFunction !== null ) data.compareFunction = this.compareFunction; 29037 29038 return data; 29039 29040 } 29041 29042} 29043 29044/** 29045 * This class can be used to automatically save the depth information of a 29046 * cube rendering into a cube texture with depth format. Used for PointLight shadows. 29047 * 29048 * @augments DepthTexture 29049 */ 29050class CubeDepthTexture extends DepthTexture { 29051 29052 /** 29053 * Constructs a new cube depth texture. 29054 * 29055 * @param {number} size - The size (width and height) of each cube face. 29056 * @param {number} [type=UnsignedIntType] - The texture type. 29057 * @param {number} [mapping=CubeReflectionMapping] - The texture mapping. 29058 * @param {number} [wrapS=ClampToEdgeWrapping] - The wrapS value. 29059 * @param {number} [wrapT=ClampToEdgeWrapping] - The wrapT value. 29060 * @param {number} [magFilter=NearestFilter] - The mag filter value. 29061 * @param {number} [minFilter=NearestFilter] - The min filter value. 29062 * @param {number} [anisotropy=Texture.DEFAULT_ANISOTROPY] - The anisotropy value. 29063 * @param {number} [format=DepthFormat] - The texture format. 29064 */ 29065 constructor( size, type = UnsignedIntType, mapping = CubeReflectionMapping, wrapS, wrapT, magFilter = NearestFilter, minFilter = NearestFilter, anisotropy, format = DepthFormat ) { 29066 29067 // Create 6 identical image descriptors for the cube faces 29068 const image = { width: size, height: size, depth: 1 }; 29069 const images = [ image, image, image, image, image, image ]; 29070 29071 // Call DepthTexture constructor with width, height 29072 super( size, size, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ); 29073 29074 // Replace the single image with the array of 6 images 29075 this.image = images; 29076 29077 /** 29078 * This flag can be used for type testing. 29079 * 29080 * @type {boolean} 29081 * @readonly 29082 * @default true 29083 */ 29084 this.isCubeDepthTexture = true; 29085 29086 /** 29087 * Set to true for cube texture handling in WebGLTextures. 29088 * 29089 * @type {boolean} 29090 * @readonly 29091 * @default true 29092 */ 29093 this.isCubeTexture = true; 29094 29095 } 29096 29097 /** 29098 * Alias for {@link CubeDepthTexture#image}. 29099 * 29100 * @type {Array<Image>} 29101 */ 29102 get images() { 29103 29104 return this.image; 29105 29106 } 29107 29108 set images( value ) { 29109 29110 this.image = value; 29111 29112 } 29113 29114} 29115 29116/** 29117 * Represents a texture created externally with the same renderer context. 29118 * 29119 * This may be a texture from a protected media stream, device camera feed, 29120 * or other data feeds like a depth sensor. 29121 * 29122 * Note that this class is only supported in {@link WebGLRenderer}, and in 29123 * the {@link WebGPURenderer} WebGPU backend
vendor: 165,892 bytes, lines 29123-36245
29123. 29124 * 29125 * @augments Texture 29126 */ 29127class ExternalTexture extends Texture { 29128 29129 /** 29130 * Creates a new raw texture. 29131 * 29132 * @param {?(WebGLTexture|GPUTexture)} [sourceTexture=null] - The external texture. 29133 */ 29134 constructor( sourceTexture = null ) { 29135 29136 super(); 29137 29138 /** 29139 * The external source texture. 29140 * 29141 * @type {?(WebGLTexture|GPUTexture)} 29142 * @default null 29143 */ 29144 this.sourceTexture = sourceTexture; 29145 29146 /** 29147 * This flag can be used for type testing. 29148 * 29149 * @type {boolean} 29150 * @readonly 29151 * @default true 29152 */ 29153 this.isExternalTexture = true; 29154 29155 } 29156 29157 copy( source ) { 29158 29159 super.copy( source ); 29160 29161 this.sourceTexture = source.sourceTexture; 29162 29163 return this; 29164 29165 } 29166 29167} 29168 29169/** 29170 * A geometry class for a rectangular cuboid with a given width, height, and depth. 29171 * On creation, the cuboid is centred on the origin, with each edge parallel to one 29172 * of the axes. 29173 * 29174 * ```js 29175 * const geometry = new THREE.BoxGeometry( 1, 1, 1 ); 29176 * const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); 29177 * const cube = new THREE.Mesh( geometry, material ); 29178 * scene.add( cube ); 29179 * ``` 29180 * 29181 * @augments BufferGeometry 29182 * @demo scenes/geometry-browser.html#BoxGeometry 29183 */ 29184class BoxGeometry extends BufferGeometry { 29185 29186 /** 29187 * Constructs a new box geometry. 29188 * 29189 * @param {number} [width=1] - The width. That is, the length of the edges parallel to the X axis. 29190 * @param {number} [height=1] - The height. That is, the length of the edges parallel to the Y axis. 29191 * @param {number} [depth=1] - The depth. That is, the length of the edges parallel to the Z axis. 29192 * @param {number} [widthSegments=1] - Number of segmented rectangular faces along the width of the sides. 29193 * @param {number} [heightSegments=1] - Number of segmented rectangular faces along the height of the sides. 29194 * @param {number} [depthSegments=1] - Number of segmented rectangular faces along the depth of the sides. 29195 */ 29196 constructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) { 29197 29198 super(); 29199 29200 this.type = 'BoxGeometry'; 29201 29202 /** 29203 * Holds the constructor parameters that have been 29204 * used to generate the geometry. Any modification 29205 * after instantiation does not change the geometry. 29206 * 29207 * @type {Object} 29208 */ 29209 this.parameters = { 29210 width: width, 29211 height: height, 29212 depth: depth, 29213 widthSegments: widthSegments, 29214 heightSegments: heightSegments, 29215 depthSegments: depthSegments 29216 }; 29217 29218 const scope = this; 29219 29220 // segments 29221 29222 widthSegments = Math.floor( widthSegments ); 29223 heightSegments = Math.floor( heightSegments ); 29224 depthSegments = Math.floor( depthSegments ); 29225 29226 // buffers 29227 29228 const indices = []; 29229 const vertices = []; 29230 const normals = []; 29231 const uvs = []; 29232 29233 // helper variables 29234 29235 let numberOfVertices = 0; 29236 let groupStart = 0; 29237 29238 // build each side of the box geometry 29239 29240 buildPlane( 'z', 'y', 'x', -1, -1, depth, height, width, depthSegments, heightSegments, 0 ); // px 29241 buildPlane( 'z', 'y', 'x', 1, -1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx 29242 buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py 29243 buildPlane( 'x', 'z', 'y', 1, -1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny 29244 buildPlane( 'x', 'y', 'z', 1, -1, width, height, depth, widthSegments, heightSegments, 4 ); // pz 29245 buildPlane( 'x', 'y', 'z', -1, -1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz 29246 29247 // build geometry 29248 29249 this.setIndex( indices ); 29250 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 29251 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 29252 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 29253 29254 function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) { 29255 29256 const segmentWidth = width / gridX; 29257 const segmentHeight = height / gridY; 29258 29259 const widthHalf = width / 2; 29260 const heightHalf = height / 2; 29261 const depthHalf = depth / 2; 29262 29263 const gridX1 = gridX + 1; 29264 const gridY1 = gridY + 1; 29265 29266 let vertexCounter = 0; 29267 let groupCount = 0; 29268 29269 const vector = new Vector3(); 29270 29271 // generate vertices, normals and uvs 29272 29273 for ( let iy = 0; iy < gridY1; iy ++ ) { 29274 29275 const y = iy * segmentHeight - heightHalf; 29276 29277 for ( let ix = 0; ix < gridX1; ix ++ ) { 29278 29279 const x = ix * segmentWidth - widthHalf; 29280 29281 // set values to correct vector component 29282 29283 vector[ u ] = x * udir; 29284 vector[ v ] = y * vdir; 29285 vector[ w ] = depthHalf; 29286 29287 // now apply vector to vertex buffer 29288 29289 vertices.push( vector.x, vector.y, vector.z ); 29290 29291 // set values to correct vector component 29292 29293 vector[ u ] = 0; 29294 vector[ v ] = 0; 29295 vector[ w ] = depth > 0 ? 1 : -1; 29296 29297 // now apply vector to normal buffer 29298 29299 normals.push( vector.x, vector.y, vector.z ); 29300 29301 // uvs 29302 29303 uvs.push( ix / gridX ); 29304 uvs.push( 1 - ( iy / gridY ) ); 29305 29306 // counters 29307 29308 vertexCounter += 1; 29309 29310 } 29311 29312 } 29313 29314 // indices 29315 29316 // 1. you need three indices to draw a single face 29317 // 2. a single segment consists of two faces 29318 // 3. so we need to generate six (2*3) indices per segment 29319 29320 for ( let iy = 0; iy < gridY; iy ++ ) { 29321 29322 for ( let ix = 0; ix < gridX; ix ++ ) { 29323 29324 const a = numberOfVertices + ix + gridX1 * iy; 29325 const b = numberOfVertices + ix + gridX1 * ( iy + 1 ); 29326 const c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 ); 29327 const d = numberOfVertices + ( ix + 1 ) + gridX1 * iy; 29328 29329 // faces 29330 29331 indices.push( a, b, d ); 29332 indices.push( b, c, d ); 29333 29334 // increase counter 29335 29336 groupCount += 6; 29337 29338 } 29339 29340 } 29341 29342 // add a group to the geometry. this will ensure multi material support 29343 29344 scope.addGroup( groupStart, groupCount, materialIndex ); 29345 29346 // calculate new start value for groups 29347 29348 groupStart += groupCount; 29349 29350 // update total number of vertices 29351 29352 numberOfVertices += vertexCounter; 29353 29354 } 29355 29356 } 29357 29358 copy( source ) { 29359 29360 super.copy( source ); 29361 29362 this.parameters = Object.assign( {}, source.parameters ); 29363 29364 return this; 29365 29366 } 29367 29368 /** 29369 * Factory method for creating an instance of this class from the given 29370 * JSON object. 29371 * 29372 * @param {Object} data - A JSON object representing the serialized geometry. 29373 * @return {BoxGeometry} A new instance. 29374 */ 29375 static fromJSON( data ) { 29376 29377 return new BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments ); 29378 29379 } 29380 29381} 29382 29383/** 29384 * A geometry class for representing a capsule. 29385 * 29386 * ```js 29387 * const geometry = new THREE.CapsuleGeometry( 1, 1, 4, 8, 1 ); 29388 * const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); 29389 * const capsule = new THREE.Mesh( geometry, material ); 29390 * scene.add( capsule ); 29391 * ``` 29392 * 29393 * @augments BufferGeometry 29394 * @demo scenes/geometry-browser.html#CapsuleGeometry 29395 */ 29396class CapsuleGeometry extends BufferGeometry { 29397 29398 /** 29399 * Constructs a new capsule geometry. 29400 * 29401 * @param {number} [radius=1] - Radius of the capsule. 29402 * @param {number} [height=1] - Height of the middle section. 29403 * @param {number} [capSegments=4] - Number of curve segments used to build each cap. 29404 * @param {number} [radialSegments=8] - Number of segmented faces around the circumference of the capsule. Must be an integer >= 3. 29405 * @param {number} [heightSegments=1] - Number of rows of faces along the height of the middle section. Must be an integer >= 1. 29406 */ 29407 constructor( radius = 1, height = 1, capSegments = 4, radialSegments = 8, heightSegments = 1 ) { 29408 29409 super(); 29410 29411 this.type = 'CapsuleGeometry'; 29412 29413 /** 29414 * Holds the constructor parameters that have been 29415 * used to generate the geometry. Any modification 29416 * after instantiation does not change the geometry. 29417 * 29418 * @type {Object} 29419 */ 29420 this.parameters = { 29421 radius: radius, 29422 height: height, 29423 capSegments: capSegments, 29424 radialSegments: radialSegments, 29425 heightSegments: heightSegments, 29426 }; 29427 29428 height = Math.max( 0, height ); 29429 capSegments = Math.max( 1, Math.floor( capSegments ) ); 29430 radialSegments = Math.max( 3, Math.floor( radialSegments ) ); 29431 heightSegments = Math.max( 1, Math.floor( heightSegments ) ); 29432 29433 // buffers 29434 29435 const indices = []; 29436 const vertices = []; 29437 const normals = []; 29438 const uvs = []; 29439 29440 // helper variables 29441 29442 const halfHeight = height / 2; 29443 const capArcLength = ( Math.PI / 2 ) * radius; 29444 const cylinderPartLength = height; 29445 const totalArcLength = 2 * capArcLength + cylinderPartLength; 29446 29447 const numVerticalSegments = capSegments * 2 + heightSegments; 29448 const verticesPerRow = radialSegments + 1; 29449 29450 const normal = new Vector3(); 29451 const vertex = new Vector3(); 29452 29453 // generate vertices, normals, and uvs 29454 29455 for ( let iy = 0; iy <= numVerticalSegments; iy ++ ) { 29456 29457 let currentArcLength = 0; 29458 let profileY = 0; 29459 let profileRadius = 0; 29460 let normalYComponent = 0; 29461 29462 if ( iy <= capSegments ) { 29463 29464 // bottom cap 29465 const segmentProgress = iy / capSegments; 29466 const angle = ( segmentProgress * Math.PI ) / 2; 29467 profileY = - halfHeight - radius * Math.cos( angle ); 29468 profileRadius = radius * Math.sin( angle ); 29469 normalYComponent = - radius * Math.cos( angle ); 29470 currentArcLength = segmentProgress * capArcLength; 29471 29472 } else if ( iy <= capSegments + heightSegments ) { 29473 29474 // middle section 29475 const segmentProgress = ( iy - capSegments ) / heightSegments; 29476 profileY = - halfHeight + segmentProgress * height; 29477 profileRadius = radius; 29478 normalYComponent = 0; 29479 currentArcLength = capArcLength + segmentProgress * cylinderPartLength; 29480 29481 } else { 29482 29483 // top cap 29484 const segmentProgress = 29485 ( iy - capSegments - heightSegments ) / capSegments; 29486 const angle = ( segmentProgress * Math.PI ) / 2; 29487 profileY = halfHeight + radius * Math.sin( angle ); 29488 profileRadius = radius * Math.cos( angle ); 29489 normalYComponent = radius * Math.sin( angle ); 29490 currentArcLength = 29491 capArcLength + cylinderPartLength + segmentProgress * capArcLength; 29492 29493 } 29494 29495 const v = Math.max( 0, Math.min( 1, currentArcLength / totalArcLength ) ); 29496 29497 29498 // special case for the poles 29499 29500 let uOffset = 0; 29501 29502 if ( iy === 0 ) { 29503 29504 uOffset = 0.5 / radialSegments; 29505 29506 } else if ( iy === numVerticalSegments ) { 29507 29508 uOffset = -0.5 / radialSegments; 29509 29510 } 29511 29512 for ( let ix = 0; ix <= radialSegments; ix ++ ) { 29513 29514 const u = ix / radialSegments; 29515 const theta = u * Math.PI * 2; 29516 29517 const sinTheta = Math.sin( theta ); 29518 const cosTheta = Math.cos( theta ); 29519 29520 // vertex 29521 29522 vertex.x = - profileRadius * cosTheta; 29523 vertex.y = profileY; 29524 vertex.z = profileRadius * sinTheta; 29525 vertices.push( vertex.x, vertex.y, vertex.z ); 29526 29527 // normal 29528 29529 normal.set( 29530 - profileRadius * cosTheta, 29531 normalYComponent, 29532 profileRadius * sinTheta 29533 ); 29534 normal.normalize(); 29535 normals.push( normal.x, normal.y, normal.z ); 29536 29537 // uv 29538 29539 uvs.push( u + uOffset, v ); 29540 29541 } 29542 29543 if ( iy > 0 ) { 29544 29545 const prevIndexRow = ( iy - 1 ) * verticesPerRow; 29546 for ( let ix = 0; ix < radialSegments; ix ++ ) { 29547 29548 const i1 = prevIndexRow + ix; 29549 const i2 = prevIndexRow + ix + 1; 29550 const i3 = iy * verticesPerRow + ix; 29551 const i4 = iy * verticesPerRow + ix + 1; 29552 29553 indices.push( i1, i2, i3 ); 29554 indices.push( i2, i4, i3 ); 29555 29556 } 29557 29558 } 29559 29560 } 29561 29562 // build geometry 29563 29564 this.setIndex( indices ); 29565 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 29566 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 29567 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 29568 29569 } 29570 29571 copy( source ) { 29572 29573 super.copy( source ); 29574 29575 this.parameters = Object.assign( {}, source.parameters ); 29576 29577 return this; 29578 29579 } 29580 29581 /** 29582 * Factory method for creating an instance of this class from the given 29583 * JSON object. 29584 * 29585 * @param {Object} data - A JSON object representing the serialized geometry. 29586 * @return {CapsuleGeometry} A new instance. 29587 */ 29588 static fromJSON( data ) { 29589 29590 return new CapsuleGeometry( data.radius, data.height, data.capSegments, data.radialSegments, data.heightSegments ); 29591 29592 } 29593 29594} 29595 29596/** 29597 * A simple shape of Euclidean geometry. It is constructed from a 29598 * number of triangular segments that are oriented around a central point and 29599 * extend as far out as a given radius. It is built counter-clockwise from a 29600 * start angle and a given central angle. It can also be used to create 29601 * regular polygons, where the number of segments determines the number of 29602 * sides. 29603 * 29604 * ```js 29605 * const geometry = new THREE.CircleGeometry( 5, 32 ); 29606 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); 29607 * const circle = new THREE.Mesh( geometry, material ); 29608 * scene.add( circle ) 29609 * ``` 29610 * 29611 * @augments BufferGeometry 29612 * @demo scenes/geometry-browser.html#CircleGeometry 29613 */ 29614class CircleGeometry extends BufferGeometry { 29615 29616 /** 29617 * Constructs a new circle geometry. 29618 * 29619 * @param {number} [radius=1] - Radius of the circle. 29620 * @param {number} [segments=32] - Number of segments (triangles), minimum = `3`. 29621 * @param {number} [thetaStart=0] - Start angle for first segment in radians. 29622 * @param {number} [thetaLength=Math.PI*2] - The central angle, often called theta, 29623 * of the circular sector in radians. The default value results in a complete circle. 29624 */ 29625 constructor( radius = 1, segments = 32, thetaStart = 0, thetaLength = Math.PI * 2 ) { 29626 29627 super(); 29628 29629 this.type = 'CircleGeometry'; 29630 29631 /** 29632 * Holds the constructor parameters that have been 29633 * used to generate the geometry. Any modification 29634 * after instantiation does not change the geometry. 29635 * 29636 * @type {Object} 29637 */ 29638 this.parameters = { 29639 radius: radius, 29640 segments: segments, 29641 thetaStart: thetaStart, 29642 thetaLength: thetaLength 29643 }; 29644 29645 segments = Math.max( 3, segments ); 29646 29647 // buffers 29648 29649 const indices = []; 29650 const vertices = []; 29651 const normals = []; 29652 const uvs = []; 29653 29654 // helper variables 29655 29656 const vertex = new Vector3(); 29657 const uv = new Vector2(); 29658 29659 // center point 29660 29661 vertices.push( 0, 0, 0 ); 29662 normals.push( 0, 0, 1 ); 29663 uvs.push( 0.5, 0.5 ); 29664 29665 for ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) { 29666 29667 const segment = thetaStart + s / segments * thetaLength; 29668 29669 // vertex 29670 29671 vertex.x = radius * Math.cos( segment ); 29672 vertex.y = radius * Math.sin( segment ); 29673 29674 vertices.push( vertex.x, vertex.y, vertex.z ); 29675 29676 // normal 29677 29678 normals.push( 0, 0, 1 ); 29679 29680 // uvs 29681 29682 uv.x = ( vertices[ i ] / radius + 1 ) / 2; 29683 uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2; 29684 29685 uvs.push( uv.x, uv.y ); 29686 29687 } 29688 29689 // indices 29690 29691 for ( let i = 1; i <= segments; i ++ ) { 29692 29693 indices.push( i, i + 1, 0 ); 29694 29695 } 29696 29697 // build geometry 29698 29699 this.setIndex( indices ); 29700 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 29701 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 29702 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 29703 29704 } 29705 29706 copy( source ) { 29707 29708 super.copy( source ); 29709 29710 this.parameters = Object.assign( {}, source.parameters ); 29711 29712 return this; 29713 29714 } 29715 29716 /** 29717 * Factory method for creating an instance of this class from the given 29718 * JSON object. 29719 * 29720 * @param {Object} data - A JSON object representing the serialized geometry. 29721 * @return {CircleGeometry} A new instance. 29722 */ 29723 static fromJSON( data ) { 29724 29725 return new CircleGeometry( data.radius, data.segments, data.thetaStart, data.thetaLength ); 29726 29727 } 29728 29729} 29730 29731/** 29732 * A geometry class for representing a cylinder. 29733 * 29734 * ```js 29735 * const geometry = new THREE.CylinderGeometry( 5, 5, 20, 32 ); 29736 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); 29737 * const cylinder = new THREE.Mesh( geometry, material ); 29738 * scene.add( cylinder ); 29739 * ``` 29740 * 29741 * @augments BufferGeometry 29742 * @demo scenes/geometry-browser.html#CylinderGeometry 29743 */ 29744class CylinderGeometry extends BufferGeometry { 29745 29746 /** 29747 * Constructs a new cylinder geometry. 29748 * 29749 * @param {number} [radiusTop=1] - Radius of the cylinder at the top. 29750 * @param {number} [radiusBottom=1] - Radius of the cylinder at the bottom. 29751 * @param {number} [height=1] - Height of the cylinder. 29752 * @param {number} [radialSegments=32] - Number of segmented faces around the circumference of the cylinder. 29753 * @param {number} [heightSegments=1] - Number of rows of faces along the height of the cylinder. 29754 * @param {boolean} [openEnded=false] - Whether the base of the cylinder is open or capped. 29755 * @param {number} [thetaStart=0] - Start angle for first segment, in radians. 29756 * @param {number} [thetaLength=Math.PI*2] - The central angle, often called theta, of the circular sector, in radians. 29757 * The default value results in a complete cylinder. 29758 */ 29759 constructor( radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) { 29760 29761 super(); 29762 29763 this.type = 'CylinderGeometry'; 29764 29765 /** 29766 * Holds the constructor parameters that have been 29767 * used to generate the geometry. Any modification 29768 * after instantiation does not change the geometry. 29769 * 29770 * @type {Object} 29771 */ 29772 this.parameters = { 29773 radiusTop: radiusTop, 29774 radiusBottom: radiusBottom, 29775 height: height, 29776 radialSegments: radialSegments, 29777 heightSegments: heightSegments, 29778 openEnded: openEnded, 29779 thetaStart: thetaStart, 29780 thetaLength: thetaLength 29781 }; 29782 29783 const scope = this; 29784 29785 radialSegments = Math.floor( radialSegments ); 29786 heightSegments = Math.floor( heightSegments ); 29787 29788 // buffers 29789 29790 const indices = []; 29791 const vertices = []; 29792 const normals = []; 29793 const uvs = []; 29794 29795 // helper variables 29796 29797 let index = 0; 29798 const indexArray = []; 29799 const halfHeight = height / 2; 29800 let groupStart = 0; 29801 29802 // generate geometry 29803 29804 generateTorso(); 29805 29806 if ( openEnded === false ) { 29807 29808 if ( radiusTop > 0 ) generateCap( true ); 29809 if ( radiusBottom > 0 ) generateCap( false ); 29810 29811 } 29812 29813 // build geometry 29814 29815 this.setIndex( indices ); 29816 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 29817 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 29818 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 29819 29820 function generateTorso() { 29821 29822 const normal = new Vector3(); 29823 const vertex = new Vector3(); 29824 29825 let groupCount = 0; 29826 29827 // this will be used to calculate the normal 29828 const slope = ( radiusBottom - radiusTop ) / height; 29829 29830 // generate vertices, normals and uvs 29831 29832 for ( let y = 0; y <= heightSegments; y ++ ) { 29833 29834 const indexRow = []; 29835 29836 const v = y / heightSegments; 29837 29838 // calculate the radius of the current row 29839 29840 const radius = v * ( radiusBottom - radiusTop ) + radiusTop; 29841 29842 for ( let x = 0; x <= radialSegments; x ++ ) { 29843 29844 const u = x / radialSegments; 29845 29846 const theta = u * thetaLength + thetaStart; 29847 29848 const sinTheta = Math.sin( theta ); 29849 const cosTheta = Math.cos( theta ); 29850 29851 // vertex 29852 29853 vertex.x = radius * sinTheta; 29854 vertex.y = - v * height + halfHeight; 29855 vertex.z = radius * cosTheta; 29856 vertices.push( vertex.x, vertex.y, vertex.z ); 29857 29858 // normal 29859 29860 normal.set( sinTheta, slope, cosTheta ).normalize(); 29861 normals.push( normal.x, normal.y, normal.z ); 29862 29863 // uv 29864 29865 uvs.push( u, 1 - v ); 29866 29867 // save index of vertex in respective row 29868 29869 indexRow.push( index ++ ); 29870 29871 } 29872 29873 // now save vertices of the row in our index array 29874 29875 indexArray.push( indexRow ); 29876 29877 } 29878 29879 // generate indices 29880 29881 for ( let x = 0; x < radialSegments; x ++ ) { 29882 29883 for ( let y = 0; y < heightSegments; y ++ ) { 29884 29885 // we use the index array to access the correct indices 29886 29887 const a = indexArray[ y ][ x ]; 29888 const b = indexArray[ y + 1 ][ x ]; 29889 const c = indexArray[ y + 1 ][ x + 1 ]; 29890 const d = indexArray[ y ][ x + 1 ]; 29891 29892 // faces 29893 29894 if ( radiusTop > 0 || y !== 0 ) { 29895 29896 indices.push( a, b, d ); 29897 groupCount += 3; 29898 29899 } 29900 29901 if ( radiusBottom > 0 || y !== heightSegments - 1 ) { 29902 29903 indices.push( b, c, d ); 29904 groupCount += 3; 29905 29906 } 29907 29908 } 29909 29910 } 29911 29912 // add a group to the geometry. this will ensure multi material support 29913 29914 scope.addGroup( groupStart, groupCount, 0 ); 29915 29916 // calculate new start value for groups 29917 29918 groupStart += groupCount; 29919 29920 } 29921 29922 function generateCap( top ) { 29923 29924 // save the index of the first center vertex 29925 const centerIndexStart = index; 29926 29927 const uv = new Vector2(); 29928 const vertex = new Vector3(); 29929 29930 let groupCount = 0; 29931 29932 const radius = ( top === true ) ? radiusTop : radiusBottom; 29933 const sign = ( top === true ) ? 1 : -1; 29934 29935 // first we generate the center vertex data of the cap. 29936 // because the geometry needs one set of uvs per face, 29937 // we must generate a center vertex per face/segment 29938 29939 for ( let x = 1; x <= radialSegments; x ++ ) { 29940 29941 // vertex 29942 29943 vertices.push( 0, halfHeight * sign, 0 ); 29944 29945 // normal 29946 29947 normals.push( 0, sign, 0 ); 29948 29949 // uv 29950 29951 uvs.push( 0.5, 0.5 ); 29952 29953 // increase index 29954 29955 index ++; 29956 29957 } 29958 29959 // save the index of the last center vertex 29960 const centerIndexEnd = index; 29961 29962 // now we generate the surrounding vertices, normals and uvs 29963 29964 for ( let x = 0; x <= radialSegments; x ++ ) { 29965 29966 const u = x / radialSegments; 29967 const theta = u * thetaLength + thetaStart; 29968 29969 const cosTheta = Math.cos( theta ); 29970 const sinTheta = Math.sin( theta ); 29971 29972 // vertex 29973 29974 vertex.x = radius * sinTheta; 29975 vertex.y = halfHeight * sign; 29976 vertex.z = radius * cosTheta; 29977 vertices.push( vertex.x, vertex.y, vertex.z ); 29978 29979 // normal 29980 29981 normals.push( 0, sign, 0 ); 29982 29983 // uv 29984 29985 uv.x = ( cosTheta * 0.5 ) + 0.5; 29986 uv.y = ( sinTheta * 0.5 * sign ) + 0.5; 29987 uvs.push( uv.x, uv.y ); 29988 29989 // increase index 29990 29991 index ++; 29992 29993 } 29994 29995 // generate indices 29996 29997 for ( let x = 0; x < radialSegments; x ++ ) { 29998 29999 const c = centerIndexStart + x; 30000 const i = centerIndexEnd + x; 30001 30002 if ( top === true ) { 30003 30004 // face top 30005 30006 indices.push( i, i + 1, c ); 30007 30008 } else { 30009 30010 // face bottom 30011 30012 indices.push( i + 1, i, c ); 30013 30014 } 30015 30016 groupCount += 3; 30017 30018 } 30019 30020 // add a group to the geometry. this will ensure multi material support 30021 30022 scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 ); 30023 30024 // calculate new start value for groups 30025 30026 groupStart += groupCount; 30027 30028 } 30029 30030 } 30031 30032 copy( source ) { 30033 30034 super.copy( source ); 30035 30036 this.parameters = Object.assign( {}, source.parameters ); 30037 30038 return this; 30039 30040 } 30041 30042 /** 30043 * Factory method for creating an instance of this class from the given 30044 * JSON object. 30045 * 30046 * @param {Object} data - A JSON object representing the serialized geometry. 30047 * @return {CylinderGeometry} A new instance. 30048 */ 30049 static fromJSON( data ) { 30050 30051 return new CylinderGeometry( data.radiusTop, data.radiusBottom, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ); 30052 30053 } 30054 30055} 30056 30057/** 30058 * A geometry class for representing a cone. 30059 * 30060 * ```js 30061 * const geometry = new THREE.ConeGeometry( 5, 20, 32 ); 30062 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); 30063 * const cone = new THREE.Mesh(geometry, material ); 30064 * scene.add( cone ); 30065 * ``` 30066 * 30067 * @augments CylinderGeometry 30068 * @demo scenes/geometry-browser.html#ConeGeometry 30069 */ 30070class ConeGeometry extends CylinderGeometry { 30071 30072 /** 30073 * Constructs a new cone geometry. 30074 * 30075 * @param {number} [radius=1] - Radius of the cone base. 30076 * @param {number} [height=1] - Height of the cone. 30077 * @param {number} [radialSegments=32] - Number of segmented faces around the circumference of the cone. 30078 * @param {number} [heightSegments=1] - Number of rows of faces along the height of the cone. 30079 * @param {boolean} [openEnded=false] - Whether the base of the cone is open or capped. 30080 * @param {number} [thetaStart=0] - Start angle for first segment, in radians. 30081 * @param {number} [thetaLength=Math.PI*2] - The central angle, often called theta, of the circular sector, in radians. 30082 * The default value results in a complete cone. 30083 */ 30084 constructor( radius = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) { 30085 30086 super( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ); 30087 30088 this.type = 'ConeGeometry'; 30089 30090 /** 30091 * Holds the constructor parameters that have been 30092 * used to generate the geometry. Any modification 30093 * after instantiation does not change the geometry. 30094 * 30095 * @type {Object} 30096 */ 30097 this.parameters = { 30098 radius: radius, 30099 height: height, 30100 radialSegments: radialSegments, 30101 heightSegments: heightSegments, 30102 openEnded: openEnded, 30103 thetaStart: thetaStart, 30104 thetaLength: thetaLength 30105 }; 30106 30107 } 30108 30109 /** 30110 * Factory method for creating an instance of this class from the given 30111 * JSON object. 30112 * 30113 * @param {Object} data - A JSON object representing the serialized geometry. 30114 * @return {ConeGeometry} A new instance. 30115 */ 30116 static fromJSON( data ) { 30117 30118 return new ConeGeometry( data.radius, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength ); 30119 30120 } 30121 30122} 30123 30124/** 30125 * A polyhedron is a solid in three dimensions with flat faces. This class 30126 * will take an array of vertices, project them onto a sphere, and then 30127 * divide them up to the desired level of detail. 30128 * 30129 * @augments BufferGeometry 30130 */ 30131class PolyhedronGeometry extends BufferGeometry { 30132 30133 /** 30134 * Constructs a new polyhedron geometry. 30135 * 30136 * @param {Array<number>} [vertices] - A flat array of vertices describing the base shape. 30137 * @param {Array<number>} [indices] - A flat array of indices describing the base shape. 30138 * @param {number} [radius=1] - The radius of the shape. 30139 * @param {number} [detail=0] - How many levels to subdivide the geometry. The more detail, the smoother the shape. 30140 */ 30141 constructor( vertices = [], indices = [], radius = 1, detail = 0 ) { 30142 30143 super(); 30144 30145 this.type = 'PolyhedronGeometry'; 30146 30147 /** 30148 * Holds the constructor parameters that have been 30149 * used to generate the geometry. Any modification 30150 * after instantiation does not change the geometry. 30151 * 30152 * @type {Object} 30153 */ 30154 this.parameters = { 30155 vertices: vertices, 30156 indices: indices, 30157 radius: radius, 30158 detail: detail 30159 }; 30160 30161 // default buffer data 30162 30163 const vertexBuffer = []; 30164 const uvBuffer = []; 30165 30166 // the subdivision creates the vertex buffer data 30167 30168 subdivide( detail ); 30169 30170 // all vertices should lie on a conceptual sphere with a given radius 30171 30172 applyRadius( radius ); 30173 30174 // finally, create the uv data 30175 30176 generateUVs(); 30177 30178 // build non-indexed geometry 30179 30180 this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) ); 30181 this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) ); 30182 this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) ); 30183 30184 if ( detail === 0 ) { 30185 30186 this.computeVertexNormals(); // flat normals 30187 30188 } else { 30189 30190 this.normalizeNormals(); // smooth normals 30191 30192 } 30193 30194 // helper functions 30195 30196 function subdivide( detail ) { 30197 30198 const a = new Vector3(); 30199 const b = new Vector3(); 30200 const c = new Vector3(); 30201 30202 // iterate over all faces and apply a subdivision with the given detail value 30203 30204 for ( let i = 0; i < indices.length; i += 3 ) { 30205 30206 // get the vertices of the face 30207 30208 getVertexByIndex( indices[ i + 0 ], a ); 30209 getVertexByIndex( indices[ i + 1 ], b ); 30210 getVertexByIndex( indices[ i + 2 ], c ); 30211 30212 // perform subdivision 30213 30214 subdivideFace( a, b, c, detail ); 30215 30216 } 30217 30218 } 30219 30220 function subdivideFace( a, b, c, detail ) { 30221 30222 const cols = detail + 1; 30223 30224 // we use this multidimensional array as a data structure for creating the subdivision 30225 30226 const v = []; 30227 30228 // construct all of the vertices for this subdivision 30229 30230 for ( let i = 0; i <= cols; i ++ ) { 30231 30232 v[ i ] = []; 30233 30234 const aj = a.clone().lerp( c, i / cols ); 30235 const bj = b.clone().lerp( c, i / cols ); 30236 30237 const rows = cols - i; 30238 30239 for ( let j = 0; j <= rows; j ++ ) { 30240 30241 if ( j === 0 && i === cols ) { 30242 30243 v[ i ][ j ] = aj; 30244 30245 } else { 30246 30247 v[ i ][ j ] = aj.clone().lerp( bj, j / rows ); 30248 30249 } 30250 30251 } 30252 30253 } 30254 30255 // construct all of the faces 30256 30257 for ( let i = 0; i < cols; i ++ ) { 30258 30259 for ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) { 30260 30261 const k = Math.floor( j / 2 ); 30262 30263 if ( j % 2 === 0 ) { 30264 30265 pushVertex( v[ i ][ k + 1 ] ); 30266 pushVertex( v[ i + 1 ][ k ] ); 30267 pushVertex( v[ i ][ k ] ); 30268 30269 } else { 30270 30271 pushVertex( v[ i ][ k + 1 ] ); 30272 pushVertex( v[ i + 1 ][ k + 1 ] ); 30273 pushVertex( v[ i + 1 ][ k ] ); 30274 30275 } 30276 30277 } 30278 30279 } 30280 30281 } 30282 30283 function applyRadius( radius ) { 30284 30285 const vertex = new Vector3(); 30286 30287 // iterate over the entire buffer and apply the radius to each vertex 30288 30289 for ( let i = 0; i < vertexBuffer.length; i += 3 ) { 30290 30291 vertex.x = vertexBuffer[ i + 0 ]; 30292 vertex.y = vertexBuffer[ i + 1 ]; 30293 vertex.z = vertexBuffer[ i + 2 ]; 30294 30295 vertex.normalize().multiplyScalar( radius ); 30296 30297 vertexBuffer[ i + 0 ] = vertex.x; 30298 vertexBuffer[ i + 1 ] = vertex.y; 30299 vertexBuffer[ i + 2 ] = vertex.z; 30300 30301 } 30302 30303 } 30304 30305 function generateUVs() { 30306 30307 const vertex = new Vector3(); 30308 30309 for ( let i = 0; i < vertexBuffer.length; i += 3 ) { 30310 30311 vertex.x = vertexBuffer[ i + 0 ]; 30312 vertex.y = vertexBuffer[ i + 1 ]; 30313 vertex.z = vertexBuffer[ i + 2 ]; 30314 30315 const u = azimuth( vertex ) / 2 / Math.PI + 0.5; 30316 const v = inclination( vertex ) / Math.PI + 0.5; 30317 uvBuffer.push( u, 1 - v ); 30318 30319 } 30320 30321 correctUVs(); 30322 30323 correctSeam(); 30324 30325 } 30326 30327 function correctSeam() { 30328 30329 // handle case when face straddles the seam, see #3269 30330 30331 for ( let i = 0; i < uvBuffer.length; i += 6 ) { 30332 30333 // uv data of a single face 30334 30335 const x0 = uvBuffer[ i + 0 ]; 30336 const x1 = uvBuffer[ i + 2 ]; 30337 const x2 = uvBuffer[ i + 4 ]; 30338 30339 const max = Math.max( x0, x1, x2 ); 30340 const min = Math.min( x0, x1, x2 ); 30341 30342 // 0.9 is somewhat arbitrary 30343 30344 if ( max > 0.9 && min < 0.1 ) { 30345 30346 if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1; 30347 if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1; 30348 if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1; 30349 30350 } 30351 30352 } 30353 30354 } 30355 30356 function pushVertex( vertex ) { 30357 30358 vertexBuffer.push( vertex.x, vertex.y, vertex.z ); 30359 30360 } 30361 30362 function getVertexByIndex( index, vertex ) { 30363 30364 const stride = index * 3; 30365 30366 vertex.x = vertices[ stride + 0 ]; 30367 vertex.y = vertices[ stride + 1 ]; 30368 vertex.z = vertices[ stride + 2 ]; 30369 30370 } 30371 30372 function correctUVs() { 30373 30374 const a = new Vector3(); 30375 const b = new Vector3(); 30376 const c = new Vector3(); 30377 30378 const centroid = new Vector3(); 30379 30380 const uvA = new Vector2(); 30381 const uvB = new Vector2(); 30382 const uvC = new Vector2(); 30383 30384 for ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) { 30385 30386 a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] ); 30387 b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] ); 30388 c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] ); 30389 30390 uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] ); 30391 uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] ); 30392 uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] ); 30393 30394 centroid.copy( a ).add( b ).add( c ).divideScalar( 3 ); 30395 30396 const azi = azimuth( centroid ); 30397 30398 correctUV( uvA, j + 0, a, azi ); 30399 correctUV( uvB, j + 2, b, azi ); 30400 correctUV( uvC, j + 4, c, azi ); 30401 30402 } 30403 30404 } 30405 30406 function correctUV( uv, stride, vector, azimuth ) { 30407 30408 if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) { 30409 30410 uvBuffer[ stride ] = uv.x - 1; 30411 30412 } 30413 30414 if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) { 30415 30416 uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5; 30417 30418 } 30419 30420 } 30421 30422 // Angle around the Y axis, counter-clockwise when looking from above. 30423 30424 function azimuth( vector ) { 30425 30426 return Math.atan2( vector.z, - vector.x ); 30427 30428 } 30429 30430 30431 // Angle above the XZ plane. 30432 30433 function inclination( vector ) { 30434 30435 return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); 30436 30437 } 30438 30439 } 30440 30441 copy( source ) { 30442 30443 super.copy( source ); 30444 30445 this.parameters = Object.assign( {}, source.parameters ); 30446 30447 return this; 30448 30449 } 30450 30451 /** 30452 * Factory method for creating an instance of this class from the given 30453 * JSON object. 30454 * 30455 * @param {Object} data - A JSON object representing the serialized geometry. 30456 * @return {PolyhedronGeometry} A new instance. 30457 */ 30458 static fromJSON( data ) { 30459 30460 return new PolyhedronGeometry( data.vertices, data.indices, data.radius, data.detail ); 30461 30462 } 30463 30464} 30465 30466/** 30467 * A geometry class for representing a dodecahedron. 30468 * 30469 * ```js 30470 * const geometry = new THREE.DodecahedronGeometry(); 30471 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); 30472 * const dodecahedron = new THREE.Mesh( geometry, material ); 30473 * scene.add( dodecahedron ); 30474 * ``` 30475 * 30476 * @augments PolyhedronGeometry 30477 * @demo scenes/geometry-browser.html#DodecahedronGeometry 30478 */ 30479class DodecahedronGeometry extends PolyhedronGeometry { 30480 30481 /** 30482 * Constructs a new dodecahedron geometry. 30483 * 30484 * @param {number} [radius=1] - Radius of the dodecahedron. 30485 * @param {number} [detail=0] - Setting this to a value greater than `0` adds vertices making it no longer a dodecahedron. 30486 */ 30487 constructor( radius = 1, detail = 0 ) { 30488 30489 const t = ( 1 + Math.sqrt( 5 ) ) / 2; 30490 const r = 1 / t; 30491 30492 const vertices = [ 30493 30494 // (±1, ±1, ±1) 30495 -1, -1, -1, -1, -1, 1, 30496 -1, 1, -1, -1, 1, 1, 30497 1, -1, -1, 1, -1, 1, 30498 1, 1, -1, 1, 1, 1, 30499 30500 // (0, ±1/Ï, ±Ï) 30501 0, - r, - t, 0, - r, t, 30502 0, r, - t, 0, r, t, 30503 30504 // (±1/Ï, ±Ï, 0) 30505 - r, - t, 0, - r, t, 0, 30506 r, - t, 0, r, t, 0, 30507 30508 // (±Ï, 0, ±1/Ï) 30509 - t, 0, - r, t, 0, - r, 30510 - t, 0, r, t, 0, r 30511 ]; 30512 30513 const indices = [ 30514 3, 11, 7, 3, 7, 15, 3, 15, 13, 30515 7, 19, 17, 7, 17, 6, 7, 6, 15, 30516 17, 4, 8, 17, 8, 10, 17, 10, 6, 30517 8, 0, 16, 8, 16, 2, 8, 2, 10, 30518 0, 12, 1, 0, 1, 18, 0, 18, 16, 30519 6, 10, 2, 6, 2, 13, 6, 13, 15, 30520 2, 16, 18, 2, 18, 3, 2, 3, 13, 30521 18, 1, 9, 18, 9, 11, 18, 11, 3, 30522 4, 14, 12, 4, 12, 0, 4, 0, 8, 30523 11, 9, 5, 11, 5, 19, 11, 19, 7, 30524 19, 5, 14, 19, 14, 4, 19, 4, 17, 30525 1, 12, 14, 1, 14, 5, 1, 5, 9 30526 ]; 30527 30528 super( vertices, indices, radius, detail ); 30529 30530 this.type = 'DodecahedronGeometry'; 30531 30532 /** 30533 * Holds the constructor parameters that have been 30534 * used to generate the geometry. Any modification 30535 * after instantiation does not change the geometry. 30536 * 30537 * @type {Object} 30538 */ 30539 this.parameters = { 30540 radius: radius, 30541 detail: detail 30542 }; 30543 30544 } 30545 30546 /** 30547 * Factory method for creating an instance of this class from the given 30548 * JSON object. 30549 * 30550 * @param {Object} data - A JSON object representing the serialized geometry. 30551 * @return {DodecahedronGeometry} A new instance. 30552 */ 30553 static fromJSON( data ) { 30554 30555 return new DodecahedronGeometry( data.radius, data.detail ); 30556 30557 } 30558 30559} 30560 30561const _v0 = /*@__PURE__*/ new Vector3(); 30562const _v1$1 = /*@__PURE__*/ new Vector3(); 30563const _normal = /*@__PURE__*/ new Vector3(); 30564const _triangle = /*@__PURE__*/ new Triangle(); 30565 30566/** 30567 * Can be used as a helper object to view the edges of a geometry. 30568 * 30569 * ```js 30570 * const geometry = new THREE.BoxGeometry(); 30571 * const edges = new THREE.EdgesGeometry( geometry ); 30572 * const line = new THREE.LineSegments( edges ); 30573 * scene.add( line ); 30574 * ``` 30575 * 30576 * Note: It is not yet possible to serialize/deserialize instances of this class. 30577 * 30578 * @augments BufferGeometry 30579 */ 30580class EdgesGeometry extends BufferGeometry { 30581 30582 /** 30583 * Constructs a new edges geometry. 30584 * 30585 * @param {?BufferGeometry} [geometry=null] - The geometry. 30586 * @param {number} [thresholdAngle=1] - An edge is only rendered if the angle (in degrees) 30587 * between the face normals of the adjoining faces exceeds this value. 30588 */ 30589 constructor( geometry = null, thresholdAngle = 1 ) { 30590 30591 super(); 30592 30593 this.type = 'EdgesGeometry'; 30594 30595 /** 30596 * Holds the constructor parameters that have been 30597 * used to generate the geometry. Any modification 30598 * after instantiation does not change the geometry. 30599 * 30600 * @type {Object} 30601 */ 30602 this.parameters = { 30603 geometry: geometry, 30604 thresholdAngle: thresholdAngle 30605 }; 30606 30607 if ( geometry !== null ) { 30608 30609 const precisionPoints = 4; 30610 const precision = Math.pow( 10, precisionPoints ); 30611 const thresholdDot = Math.cos( DEG2RAD * thresholdAngle ); 30612 30613 const indexAttr = geometry.getIndex(); 30614 const positionAttr = geometry.getAttribute( 'position' ); 30615 const indexCount = indexAttr ? indexAttr.count : positionAttr.count; 30616 30617 const indexArr = [ 0, 0, 0 ]; 30618 const vertKeys = [ 'a', 'b', 'c' ]; 30619 const hashes = new Array( 3 ); 30620 30621 const edgeData = {}; 30622 const vertices = []; 30623 for ( let i = 0; i < indexCount; i += 3 ) { 30624 30625 if ( indexAttr ) { 30626 30627 indexArr[ 0 ] = indexAttr.getX( i ); 30628 indexArr[ 1 ] = indexAttr.getX( i + 1 ); 30629 indexArr[ 2 ] = indexAttr.getX( i + 2 ); 30630 30631 } else { 30632 30633 indexArr[ 0 ] = i; 30634 indexArr[ 1 ] = i + 1; 30635 indexArr[ 2 ] = i + 2; 30636 30637 } 30638 30639 const { a, b, c } = _triangle; 30640 a.fromBufferAttribute( positionAttr, indexArr[ 0 ] ); 30641 b.fromBufferAttribute( positionAttr, indexArr[ 1 ] ); 30642 c.fromBufferAttribute( positionAttr, indexArr[ 2 ] ); 30643 _triangle.getNormal( _normal ); 30644 30645 // create hashes for the edge from the vertices 30646 hashes[ 0 ] = `${ Math.round( a.x * precision ) },${ Math.round( a.y * precision ) },${ Math.round( a.z * precision ) }`; 30647 hashes[ 1 ] = `${ Math.round( b.x * precision ) },${ Math.round( b.y * precision ) },${ Math.round( b.z * precision ) }`; 30648 hashes[ 2 ] = `${ Math.round( c.x * precision ) },${ Math.round( c.y * precision ) },${ Math.round( c.z * precision ) }`; 30649 30650 // skip degenerate triangles 30651 if ( hashes[ 0 ] === hashes[ 1 ] || hashes[ 1 ] === hashes[ 2 ] || hashes[ 2 ] === hashes[ 0 ] ) { 30652 30653 continue; 30654 30655 } 30656 30657 // iterate over every edge 30658 for ( let j = 0; j < 3; j ++ ) { 30659 30660 // get the first and next vertex making up the edge 30661 const jNext = ( j + 1 ) % 3; 30662 const vecHash0 = hashes[ j ]; 30663 const vecHash1 = hashes[ jNext ]; 30664 const v0 = _triangle[ vertKeys[ j ] ]; 30665 const v1 = _triangle[ vertKeys[ jNext ] ]; 30666 30667 const hash = `${ vecHash0 }_${ vecHash1 }`; 30668 const reverseHash = `${ vecHash1 }_${ vecHash0 }`; 30669 30670 if ( reverseHash in edgeData && edgeData[ reverseHash ] ) { 30671 30672 // if we found a sibling edge add it into the vertex array if 30673 // it meets the angle threshold and delete the edge from the map. 30674 if ( _normal.dot( edgeData[ reverseHash ].normal ) <= thresholdDot ) { 30675 30676 vertices.push( v0.x, v0.y, v0.z ); 30677 vertices.push( v1.x, v1.y, v1.z ); 30678 30679 } 30680 30681 edgeData[ reverseHash ] = null; 30682 30683 } else if ( ! ( hash in edgeData ) ) { 30684 30685 // if we've already got an edge here then skip adding a new one 30686 edgeData[ hash ] = { 30687 30688 index0: indexArr[ j ], 30689 index1: indexArr[ jNext ], 30690 normal: _normal.clone(), 30691 30692 }; 30693 30694 } 30695 30696 } 30697 30698 } 30699 30700 // iterate over all remaining, unmatched edges and add them to the vertex array 30701 for ( const key in edgeData ) { 30702 30703 if ( edgeData[ key ] ) { 30704 30705 const { index0, index1 } = edgeData[ key ]; 30706 _v0.fromBufferAttribute( positionAttr, index0 ); 30707 _v1$1.fromBufferAttribute( positionAttr, index1 ); 30708 30709 vertices.push( _v0.x, _v0.y, _v0.z ); 30710 vertices.push( _v1$1.x, _v1$1.y, _v1$1.z ); 30711 30712 } 30713 30714 } 30715 30716 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 30717 30718 } 30719 30720 } 30721 30722 copy( source ) { 30723 30724 super.copy( source ); 30725 30726 this.parameters = Object.assign( {}, source.parameters ); 30727 30728 return this; 30729 30730 } 30731 30732} 30733 30734/** 30735 * An abstract base class for creating an analytic curve object that contains methods 30736 * for interpolation. 30737 * 30738 * @abstract 30739 */ 30740class Curve { 30741 30742 /** 30743 * Constructs a new curve. 30744 */ 30745 constructor() { 30746 30747 /** 30748 * The type property is used for detecting the object type 30749 * in context of serialization/deserialization. 30750 * 30751 * @type {string} 30752 * @readonly 30753 */ 30754 this.type = 'Curve'; 30755 30756 /** 30757 * This value determines the amount of divisions when calculating the 30758 * cumulative segment lengths of a curve via {@link Curve#getLengths}. To ensure 30759 * precision when using methods like {@link Curve#getSpacedPoints}, it is 30760 * recommended to increase the value of this property if the curve is very large. 30761 * 30762 * @type {number} 30763 * @default 200 30764 */ 30765 this.arcLengthDivisions = 200; 30766 30767 /** 30768 * Must be set to `true` if the curve parameters have changed. 30769 * 30770 * @type {boolean} 30771 * @default false 30772 */ 30773 this.needsUpdate = false; 30774 30775 /** 30776 * An internal cache that holds precomputed curve length values. 30777 * 30778 * @private 30779 * @type {?Array<number>} 30780 * @default null 30781 */ 30782 this.cacheArcLengths = null; 30783 30784 } 30785 30786 /** 30787 * This method returns a vector in 2D or 3D space (depending on the curve definition) 30788 * for the given interpolation factor. 30789 * 30790 * @abstract 30791 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 30792 * @param {(Vector2|Vector3)} [optionalTarget] - The optional target vector the result is written to. 30793 * @return {(Vector2|Vector3)} The position on the curve. It can be a 2D or 3D vector depending on the curve definition. 30794 */ 30795 getPoint( /* t, optionalTarget */ ) { 30796 30797 warn( 'Curve: .getPoint() not implemented.' ); 30798 30799 } 30800 30801 /** 30802 * This method returns a vector in 2D or 3D space (depending on the curve definition) 30803 * for the given interpolation factor. Unlike {@link Curve#getPoint}, this method honors the length 30804 * of the curve which equidistant samples. 30805 * 30806 * @param {number} u - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 30807 * @param {(Vector2|Vector3)} [optionalTarget] - The optional target vector the result is written to. 30808 * @return {(Vector2|Vector3)} The position on the curve. It can be a 2D or 3D vector depending on the curve definition. 30809 */ 30810 getPointAt( u, optionalTarget ) { 30811 30812 const t = this.getUtoTmapping( u ); 30813 return this.getPoint( t, optionalTarget ); 30814 30815 } 30816 30817 /** 30818 * This method samples the curve via {@link Curve#getPoint} and returns an array of points representing 30819 * the curve shape. 30820 * 30821 * @param {number} [divisions=5] - The number of divisions. 30822 * @return {Array<(Vector2|Vector3)>} An array holding the sampled curve values. The number of points is `divisions + 1`. 30823 */ 30824 getPoints( divisions = 5 ) { 30825 30826 const points = []; 30827 30828 for ( let d = 0; d <= divisions; d ++ ) { 30829 30830 points.push( this.getPoint( d / divisions ) ); 30831 30832 } 30833 30834 return points; 30835 30836 } 30837 30838 // Get sequence of points using getPointAt( u ) 30839 30840 /** 30841 * This method samples the curve via {@link Curve#getPointAt} and returns an array of points representing 30842 * the curve shape. Unlike {@link Curve#getPoints}, this method returns equi-spaced points across the entire 30843 * curve. 30844 * 30845 * @param {number} [divisions=5] - The number of divisions. 30846 * @return {Array<(Vector2|Vector3)>} An array holding the sampled curve values. The number of points is `divisions + 1`. 30847 */ 30848 getSpacedPoints( divisions = 5 ) { 30849 30850 const points = []; 30851 30852 for ( let d = 0; d <= divisions; d ++ ) { 30853 30854 points.push( this.getPointAt( d / divisions ) ); 30855 30856 } 30857 30858 return points; 30859 30860 } 30861 30862 /** 30863 * Returns the total arc length of the curve. 30864 * 30865 * @return {number} The length of the curve. 30866 */ 30867 getLength() { 30868 30869 const lengths = this.getLengths(); 30870 return lengths[ lengths.length - 1 ]; 30871 30872 } 30873 30874 /** 30875 * Returns an array of cumulative segment lengths of the curve. 30876 * 30877 * @param {number} [divisions=this.arcLengthDivisions] - The number of divisions. 30878 * @return {Array<number>} An array holding the cumulative segment lengths. 30879 */ 30880 getLengths( divisions = this.arcLengthDivisions ) { 30881 30882 if ( this.cacheArcLengths && 30883 ( this.cacheArcLengths.length === divisions + 1 ) && 30884 ! this.needsUpdate ) { 30885 30886 return this.cacheArcLengths; 30887 30888 } 30889 30890 this.needsUpdate = false; 30891 30892 const cache = []; 30893 let current, last = this.getPoint( 0 ); 30894 let sum = 0; 30895 30896 cache.push( 0 ); 30897 30898 for ( let p = 1; p <= divisions; p ++ ) { 30899 30900 current = this.getPoint( p / divisions ); 30901 sum += current.distanceTo( last ); 30902 cache.push( sum ); 30903 last = current; 30904 30905 } 30906 30907 this.cacheArcLengths = cache; 30908 30909 return cache; // { sums: cache, sum: sum }; Sum is in the last element. 30910 30911 } 30912 30913 /** 30914 * Update the cumulative segment distance cache. The method must be called 30915 * every time curve parameters are changed. If an updated curve is part of a 30916 * composed curve like {@link CurvePath}, this method must be called on the 30917 * composed curve, too. 30918 */ 30919 updateArcLengths() { 30920 30921 this.needsUpdate = true; 30922 this.getLengths(); 30923 30924 } 30925 30926 /** 30927 * Given an interpolation factor in the range `[0,1]`, this method returns an updated 30928 * interpolation factor in the same range that can be ued to sample equidistant points 30929 * from a curve. 30930 * 30931 * @param {number} u - The interpolation factor. 30932 * @param {?number} distance - An optional distance on the curve. 30933 * @return {number} The updated interpolation factor. 30934 */ 30935 getUtoTmapping( u, distance = null ) { 30936 30937 const arcLengths = this.getLengths(); 30938 30939 let i = 0; 30940 const il = arcLengths.length; 30941 30942 let targetArcLength; // The targeted u distance value to get 30943 30944 if ( distance ) { 30945 30946 targetArcLength = distance; 30947 30948 } else { 30949 30950 targetArcLength = u * arcLengths[ il - 1 ]; 30951 30952 } 30953 30954 // binary search for the index with largest value smaller than target u distance 30955 30956 let low = 0, high = il - 1, comparison; 30957 30958 while ( low <= high ) { 30959 30960 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 30961 30962 comparison = arcLengths[ i ] - targetArcLength; 30963 30964 if ( comparison < 0 ) { 30965 30966 low = i + 1; 30967 30968 } else if ( comparison > 0 ) { 30969 30970 high = i - 1; 30971 30972 } else { 30973 30974 high = i; 30975 break; 30976 30977 // DONE 30978 30979 } 30980 30981 } 30982 30983 i = high; 30984 30985 if ( arcLengths[ i ] === targetArcLength ) { 30986 30987 return i / ( il - 1 ); 30988 30989 } 30990 30991 // we could get finer grain at lengths, or use simple interpolation between two points 30992 30993 const lengthBefore = arcLengths[ i ]; 30994 const lengthAfter = arcLengths[ i + 1 ]; 30995 30996 const segmentLength = lengthAfter - lengthBefore; 30997 30998 // determine where we are between the 'before' and 'after' points 30999 31000 const segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; 31001 31002 // add that fractional amount to t 31003 31004 const t = ( i + segmentFraction ) / ( il - 1 ); 31005 31006 return t; 31007 31008 } 31009 31010 /** 31011 * Returns a unit vector tangent for the given interpolation factor. 31012 * If the derived curve does not implement its tangent derivation, 31013 * two points a small delta apart will be used to find its gradient 31014 * which seems to give a reasonable approximation. 31015 * 31016 * @param {number} t - The interpolation factor. 31017 * @param {(Vector2|Vector3)} [optionalTarget] - The optional target vector the result is written to. 31018 * @return {(Vector2|Vector3)} The tangent vector. 31019 */ 31020 getTangent( t, optionalTarget ) { 31021 31022 const delta = 0.0001; 31023 let t1 = t - delta; 31024 let t2 = t + delta; 31025 31026 // Capping in case of danger 31027 31028 if ( t1 < 0 ) t1 = 0; 31029 if ( t2 > 1 ) t2 = 1; 31030 31031 const pt1 = this.getPoint( t1 ); 31032 const pt2 = this.getPoint( t2 ); 31033 31034 const tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() ); 31035 31036 tangent.copy( pt2 ).sub( pt1 ).normalize(); 31037 31038 return tangent; 31039 31040 } 31041 31042 /** 31043 * Same as {@link Curve#getTangent} but with equidistant samples. 31044 * 31045 * @param {number} u - The interpolation factor. 31046 * @param {(Vector2|Vector3)} [optionalTarget] - The optional target vector the result is written to. 31047 * @return {(Vector2|Vector3)} The tangent vector. 31048 * @see {@link Curve#getPointAt} 31049 */ 31050 getTangentAt( u, optionalTarget ) { 31051 31052 const t = this.getUtoTmapping( u ); 31053 return this.getTangent( t, optionalTarget ); 31054 31055 } 31056 31057 /** 31058 * Generates the Frenet Frames. Requires a curve definition in 3D space. Used 31059 * in geometries like {@link TubeGeometry} or {@link ExtrudeGeometry}. 31060 * 31061 * @param {number} segments - The number of segments. 31062 * @param {boolean} [closed=false] - Whether the curve is closed or not. 31063 * @return {{tangents: Array<Vector3>, normals: Array<Vector3>, binormals: Array<Vector3>}} The Frenet Frames. 31064 */ 31065 computeFrenetFrames( segments, closed = false ) { 31066 31067 // see http://www.cs.indiana.edu/pub/techreports/TR425.pdf 31068 31069 const normal = new Vector3(); 31070 31071 const tangents = []; 31072 const normals = []; 31073 const binormals = []; 31074 31075 const vec = new Vector3(); 31076 const mat = new Matrix4(); 31077 31078 // compute the tangent vectors for each segment on the curve 31079 31080 for ( let i = 0; i <= segments; i ++ ) { 31081 31082 const u = i / segments; 31083 31084 tangents[ i ] = this.getTangentAt( u, new Vector3() ); 31085 31086 } 31087 31088 // select an initial normal vector perpendicular to the first tangent vector, 31089 // and in the direction of the minimum tangent xyz component 31090 31091 normals[ 0 ] = new Vector3(); 31092 binormals[ 0 ] = new Vector3(); 31093 let min = Number.MAX_VALUE; 31094 const tx = Math.abs( tangents[ 0 ].x ); 31095 const ty = Math.abs( tangents[ 0 ].y ); 31096 const tz = Math.abs( tangents[ 0 ].z ); 31097 31098 if ( tx <= min ) { 31099 31100 min = tx; 31101 normal.set( 1, 0, 0 ); 31102 31103 } 31104 31105 if ( ty <= min ) { 31106 31107 min = ty; 31108 normal.set( 0, 1, 0 ); 31109 31110 } 31111 31112 if ( tz <= min ) { 31113 31114 normal.set( 0, 0, 1 ); 31115 31116 } 31117 31118 vec.crossVectors( tangents[ 0 ], normal ).normalize(); 31119 31120 normals[ 0 ].crossVectors( tangents[ 0 ], vec ); 31121 binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); 31122 31123 31124 // compute the slowly-varying normal and binormal vectors for each segment on the curve 31125 31126 for ( let i = 1; i <= segments; i ++ ) { 31127 31128 normals[ i ] = normals[ i - 1 ].clone(); 31129 31130 binormals[ i ] = binormals[ i - 1 ].clone(); 31131 31132 vec.crossVectors( tangents[ i - 1 ], tangents[ i ] ); 31133 31134 if ( vec.length() > Number.EPSILON ) { 31135 31136 vec.normalize(); 31137 31138 const theta = Math.acos( clamp( tangents[ i - 1 ].dot( tangents[ i ] ), -1, 1 ) ); // clamp for floating pt errors 31139 31140 normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); 31141 31142 } 31143 31144 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); 31145 31146 } 31147 31148 // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same 31149 31150 if ( closed === true ) { 31151 31152 let theta = Math.acos( clamp( normals[ 0 ].dot( normals[ segments ] ), -1, 1 ) ); 31153 theta /= segments; 31154 31155 if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) { 31156 31157 theta = - theta; 31158 31159 } 31160 31161 for ( let i = 1; i <= segments; i ++ ) { 31162 31163 // twist a little... 31164 normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); 31165 binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); 31166 31167 } 31168 31169 } 31170 31171 return { 31172 tangents: tangents, 31173 normals: normals, 31174 binormals: binormals 31175 }; 31176 31177 } 31178 31179 /** 31180 * Returns a new curve with copied values from this instance. 31181 * 31182 * @return {Curve} A clone of this instance. 31183 */ 31184 clone() { 31185 31186 return new this.constructor().copy( this ); 31187 31188 } 31189 31190 /** 31191 * Copies the values of the given curve to this instance. 31192 * 31193 * @param {Curve} source - The curve to copy. 31194 * @return {Curve} A reference to this curve. 31195 */ 31196 copy( source ) { 31197 31198 this.arcLengthDivisions = source.arcLengthDivisions; 31199 31200 return this; 31201 31202 } 31203 31204 /** 31205 * Serializes the curve into JSON. 31206 * 31207 * @return {Object} A JSON object representing the serialized curve. 31208 * @see {@link ObjectLoader#parse} 31209 */ 31210 toJSON() { 31211 31212 const data = { 31213 metadata: { 31214 version: 4.7, 31215 type: 'Curve', 31216 generator: 'Curve.toJSON' 31217 } 31218 }; 31219 31220 data.arcLengthDivisions = this.arcLengthDivisions; 31221 data.type = this.type; 31222 31223 return data; 31224 31225 } 31226 31227 /** 31228 * Deserializes the curve from the given JSON. 31229 * 31230 * @param {Object} json - The JSON holding the serialized curve. 31231 * @return {Curve} A reference to this curve. 31232 */ 31233 fromJSON( json ) { 31234 31235 this.arcLengthDivisions = json.arcLengthDivisions; 31236 31237 return this; 31238 31239 } 31240 31241} 31242 31243/** 31244 * A curve representing an ellipse. 31245 * 31246 * ```js 31247 * const curve = new THREE.EllipseCurve( 31248 * 0, 0, 31249 * 10, 10, 31250 * 0, 2 * Math.PI, 31251 * false, 31252 * 0 31253 * ); 31254 * 31255 * const points = curve.getPoints( 50 ); 31256 * const geometry = new THREE.BufferGeometry().setFromPoints( points ); 31257 * 31258 * const material = new THREE.LineBasicMaterial( { color: 0xff0000 } ); 31259 * 31260 * // Create the final object to add to the scene 31261 * const ellipse = new THREE.Line( geometry, material ); 31262 * ``` 31263 * 31264 * @augments Curve 31265 */ 31266class EllipseCurve extends Curve { 31267 31268 /** 31269 * Constructs a new ellipse curve. 31270 * 31271 * @param {number} [aX=0] - The X center of the ellipse. 31272 * @param {number} [aY=0] - The Y center of the ellipse. 31273 * @param {number} [xRadius=1] - The radius of the ellipse in the x direction. 31274 * @param {number} [yRadius=1] - The radius of the ellipse in the y direction. 31275 * @param {number} [aStartAngle=0] - The start angle of the curve in radians starting from the positive X axis. 31276 * @param {number} [aEndAngle=Math.PI*2] - The end angle of the curve in radians starting from the positive X axis. 31277 * @param {boolean} [aClockwise=false] - Whether the ellipse is drawn clockwise or not. 31278 * @param {number} [aRotation=0] - The rotation angle of the ellipse in radians, counterclockwise from the positive X axis. 31279 */ 31280 constructor( aX = 0, aY = 0, xRadius = 1, yRadius = 1, aStartAngle = 0, aEndAngle = Math.PI * 2, aClockwise = false, aRotation = 0 ) { 31281 31282 super(); 31283 31284 /** 31285 * This flag can be used for type testing. 31286 * 31287 * @type {boolean} 31288 * @readonly 31289 * @default true 31290 */ 31291 this.isEllipseCurve = true; 31292 31293 this.type = 'EllipseCurve'; 31294 31295 /** 31296 * The X center of the ellipse. 31297 * 31298 * @type {number} 31299 * @default 0 31300 */ 31301 this.aX = aX; 31302 31303 /** 31304 * The Y center of the ellipse. 31305 * 31306 * @type {number} 31307 * @default 0 31308 */ 31309 this.aY = aY; 31310 31311 /** 31312 * The radius of the ellipse in the x direction. 31313 * Setting the this value equal to the {@link EllipseCurve#yRadius} will result in a circle. 31314 * 31315 * @type {number} 31316 * @default 1 31317 */ 31318 this.xRadius = xRadius; 31319 31320 /** 31321 * The radius of the ellipse in the y direction. 31322 * Setting the this value equal to the {@link EllipseCurve#xRadius} will result in a circle. 31323 * 31324 * @type {number} 31325 * @default 1 31326 */ 31327 this.yRadius = yRadius; 31328 31329 /** 31330 * The start angle of the curve in radians starting from the positive X axis. 31331 * 31332 * @type {number} 31333 * @default 0 31334 */ 31335 this.aStartAngle = aStartAngle; 31336 31337 /** 31338 * The end angle of the curve in radians starting from the positive X axis. 31339 * 31340 * @type {number} 31341 * @default Math.PI*2 31342 */ 31343 this.aEndAngle = aEndAngle; 31344 31345 /** 31346 * Whether the ellipse is drawn clockwise or not. 31347 * 31348 * @type {boolean} 31349 * @default false 31350 */ 31351 this.aClockwise = aClockwise; 31352 31353 /** 31354 * The rotation angle of the ellipse in radians, counterclockwise from the positive X axis. 31355 * 31356 * @type {number} 31357 * @default 0 31358 */ 31359 this.aRotation = aRotation; 31360 31361 } 31362 31363 /** 31364 * Returns a point on the curve. 31365 * 31366 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 31367 * @param {Vector2} [optionalTarget] - The optional target vector the result is written to. 31368 * @return {Vector2} The position on the curve. 31369 */ 31370 getPoint( t, optionalTarget = new Vector2() ) { 31371 31372 const point = optionalTarget; 31373 31374 const twoPi = Math.PI * 2; 31375 let deltaAngle = this.aEndAngle - this.aStartAngle; 31376 const samePoints = Math.abs( deltaAngle ) < Number.EPSILON; 31377 31378 // ensures that deltaAngle is 0 .. 2 PI 31379 while ( deltaAngle < 0 ) deltaAngle += twoPi; 31380 while ( deltaAngle > twoPi ) deltaAngle -= twoPi; 31381 31382 if ( deltaAngle < Number.EPSILON ) { 31383 31384 if ( samePoints ) { 31385 31386 deltaAngle = 0; 31387 31388 } else { 31389 31390 deltaAngle = twoPi; 31391 31392 } 31393 31394 } 31395 31396 if ( this.aClockwise === true && ! samePoints ) { 31397 31398 if ( deltaAngle === twoPi ) { 31399 31400 deltaAngle = - twoPi; 31401 31402 } else { 31403 31404 deltaAngle = deltaAngle - twoPi; 31405 31406 } 31407 31408 } 31409 31410 const angle = this.aStartAngle + t * deltaAngle; 31411 let x = this.aX + this.xRadius * Math.cos( angle ); 31412 let y = this.aY + this.yRadius * Math.sin( angle ); 31413 31414 if ( this.aRotation !== 0 ) { 31415 31416 const cos = Math.cos( this.aRotation ); 31417 const sin = Math.sin( this.aRotation ); 31418 31419 const tx = x - this.aX; 31420 const ty = y - this.aY; 31421 31422 // Rotate the point about the center of the ellipse. 31423 x = tx * cos - ty * sin + this.aX; 31424 y = tx * sin + ty * cos + this.aY; 31425 31426 } 31427 31428 return point.set( x, y ); 31429 31430 } 31431 31432 copy( source ) { 31433 31434 super.copy( source ); 31435 31436 this.aX = source.aX; 31437 this.aY = source.aY; 31438 31439 this.xRadius = source.xRadius; 31440 this.yRadius = source.yRadius; 31441 31442 this.aStartAngle = source.aStartAngle; 31443 this.aEndAngle = source.aEndAngle; 31444 31445 this.aClockwise = source.aClockwise; 31446 31447 this.aRotation = source.aRotation; 31448 31449 return this; 31450 31451 } 31452 31453 toJSON() { 31454 31455 const data = super.toJSON(); 31456 31457 data.aX = this.aX; 31458 data.aY = this.aY; 31459 31460 data.xRadius = this.xRadius; 31461 data.yRadius = this.yRadius; 31462 31463 data.aStartAngle = this.aStartAngle; 31464 data.aEndAngle = this.aEndAngle; 31465 31466 data.aClockwise = this.aClockwise; 31467 31468 data.aRotation = this.aRotation; 31469 31470 return data; 31471 31472 } 31473 31474 fromJSON( json ) { 31475 31476 super.fromJSON( json ); 31477 31478 this.aX = json.aX; 31479 this.aY = json.aY; 31480 31481 this.xRadius = json.xRadius; 31482 this.yRadius = json.yRadius; 31483 31484 this.aStartAngle = json.aStartAngle; 31485 this.aEndAngle = json.aEndAngle; 31486 31487 this.aClockwise = json.aClockwise; 31488 31489 this.aRotation = json.aRotation; 31490 31491 return this; 31492 31493 } 31494 31495} 31496 31497/** 31498 * A curve representing an arc. 31499 * 31500 * @augments EllipseCurve 31501 */ 31502class ArcCurve extends EllipseCurve { 31503 31504 /** 31505 * Constructs a new arc curve. 31506 * 31507 * @param {number} [aX=0] - The X center of the ellipse. 31508 * @param {number} [aY=0] - The Y center of the ellipse. 31509 * @param {number} [aRadius=1] - The radius of the ellipse in the x direction. 31510 * @param {number} [aStartAngle=0] - The start angle of the curve in radians starting from the positive X axis. 31511 * @param {number} [aEndAngle=Math.PI*2] - The end angle of the curve in radians starting from the positive X axis. 31512 * @param {boolean} [aClockwise=false] - Whether the ellipse is drawn clockwise or not. 31513 */ 31514 constructor( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { 31515 31516 super( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); 31517 31518 /** 31519 * This flag can be used for type testing. 31520 * 31521 * @type {boolean} 31522 * @readonly 31523 * @default true 31524 */ 31525 this.isArcCurve = true; 31526 31527 this.type = 'ArcCurve'; 31528 31529 } 31530 31531} 31532 31533function CubicPoly() { 31534 31535 /** 31536 * Centripetal CatmullRom Curve - which is useful for avoiding 31537 * cusps and self-intersections in non-uniform catmull rom curves. 31538 * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf 31539 * 31540 * curve.type accepts centripetal(default), chordal and catmullrom 31541 * curve.tension is used for catmullrom which defaults to 0.5 31542 */ 31543 31544 /* 31545 Based on an optimized c++ solution in 31546 - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/ 31547 - http://ideone.com/NoEbVM 31548 31549 This CubicPoly class could be used for reusing some variables and calculations, 31550 but for three.js curve use, it could be possible inlined and flatten into a single function call 31551 which can be placed in CurveUtils. 31552 */ 31553 31554 let c0 = 0, c1 = 0, c2 = 0, c3 = 0; 31555 31556 /* 31557 * Compute coefficients for a cubic polynomial 31558 * p(s) = c0 + c1*s + c2*s^2 + c3*s^3 31559 * such that 31560 * p(0) = x0, p(1) = x1 31561 * and 31562 * p'(0) = t0, p'(1) = t1. 31563 */ 31564 function init( x0, x1, t0, t1 ) { 31565 31566 c0 = x0; 31567 c1 = t0; 31568 c2 = -3 * x0 + 3 * x1 - 2 * t0 - t1; 31569 c3 = 2 * x0 - 2 * x1 + t0 + t1; 31570 31571 } 31572 31573 return { 31574 31575 initCatmullRom: function ( x0, x1, x2, x3, tension ) { 31576 31577 init( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) ); 31578 31579 }, 31580 31581 initNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) { 31582 31583 // compute tangents when parameterized in [t1,t2] 31584 let t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1; 31585 let t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2; 31586 31587 // rescale tangents for parametrization in [0,1] 31588 t1 *= dt1; 31589 t2 *= dt1; 31590 31591 init( x1, x2, t1, t2 ); 31592 31593 }, 31594 31595 calc: function ( t ) { 31596 31597 const t2 = t * t; 31598 const t3 = t2 * t; 31599 return c0 + c1 * t + c2 * t2 + c3 * t3; 31600 31601 } 31602 31603 }; 31604 31605} 31606 31607// 31608 31609const tmp = /*@__PURE__*/ new Vector3(); 31610const tmp2 = /*@__PURE__*/ new Vector3(); 31611const px = /*@__PURE__*/ new CubicPoly(); 31612const py = /*@__PURE__*/ new CubicPoly(); 31613const pz = /*@__PURE__*/ new CubicPoly(); 31614 31615/** 31616 * A curve representing a Catmull-Rom spline. 31617 * 31618 * ```js 31619 * //Create a closed wavey loop 31620 * const curve = new THREE.CatmullRomCurve3( [ 31621 * new THREE.Vector3( -10, 0, 10 ), 31622 * new THREE.Vector3( -5, 5, 5 ), 31623 * new THREE.Vector3( 0, 0, 0 ), 31624 * new THREE.Vector3( 5, -5, 5 ), 31625 * new THREE.Vector3( 10, 0, 10 ) 31626 * ] ); 31627 * 31628 * const points = curve.getPoints( 50 ); 31629 * const geometry = new THREE.BufferGeometry().setFromPoints( points ); 31630 * 31631 * const material = new THREE.LineBasicMaterial( { color: 0xff0000 } ); 31632 * 31633 * // Create the final object to add to the scene 31634 * const curveObject = new THREE.Line( geometry, material ); 31635 * ``` 31636 * 31637 * @augments Curve 31638 */ 31639class CatmullRomCurve3 extends Curve { 31640 31641 /** 31642 * Constructs a new Catmull-Rom curve. 31643 * 31644 * @param {Array<Vector3>} [points] - An array of 3D points defining the curve. 31645 * @param {boolean} [closed=false] - Whether the curve is closed or not. 31646 * @param {('centripetal'|'chordal'|'catmullrom')} [curveType='centripetal'] - The curve type. 31647 * @param {number} [tension=0.5] - Tension of the curve. 31648 */ 31649 constructor( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) { 31650 31651 super(); 31652 31653 /** 31654 * This flag can be used for type testing. 31655 * 31656 * @type {boolean} 31657 * @readonly 31658 * @default true 31659 */ 31660 this.isCatmullRomCurve3 = true; 31661 31662 this.type = 'CatmullRomCurve3'; 31663 31664 /** 31665 * An array of 3D points defining the curve. 31666 * 31667 * @type {Array<Vector3>} 31668 */ 31669 this.points = points; 31670 31671 /** 31672 * Whether the curve is closed or not. 31673 * 31674 * @type {boolean} 31675 * @default false 31676 */ 31677 this.closed = closed; 31678 31679 /** 31680 * The curve type. 31681 * 31682 * @type {('centripetal'|'chordal'|'catmullrom')} 31683 * @default 'centripetal' 31684 */ 31685 this.curveType = curveType; 31686 31687 /** 31688 * Tension of the curve. 31689 * 31690 * @type {number} 31691 * @default 0.5 31692 */ 31693 this.tension = tension; 31694 31695 } 31696 31697 /** 31698 * Returns a point on the curve. 31699 * 31700 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 31701 * @param {Vector3} [optionalTarget] - The optional target vector the result is written to. 31702 * @return {Vector3} The position on the curve. 31703 */ 31704 getPoint( t, optionalTarget = new Vector3() ) { 31705 31706 const point = optionalTarget; 31707 31708 const points = this.points; 31709 const l = points.length; 31710 31711 const p = ( l - ( this.closed ? 0 : 1 ) ) * t; 31712 let intPoint = Math.floor( p ); 31713 let weight = p - intPoint; 31714 31715 if ( this.closed ) { 31716 31717 intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l; 31718 31719 } else if ( weight === 0 && intPoint === l - 1 ) { 31720 31721 intPoint = l - 2; 31722 weight = 1; 31723 31724 } 31725 31726 let p0, p3; // 4 points (p1 & p2 defined below) 31727 31728 if ( this.closed || intPoint > 0 ) { 31729 31730 p0 = points[ ( intPoint - 1 ) % l ]; 31731 31732 } else { 31733 31734 // extrapolate first point 31735 tmp2.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] ); 31736 p0 = tmp2; 31737 31738 } 31739 31740 const p1 = points[ intPoint % l ]; 31741 const p2 = points[ ( intPoint + 1 ) % l ]; 31742 31743 if ( this.closed || intPoint + 2 < l ) { 31744 31745 p3 = points[ ( intPoint + 2 ) % l ]; 31746 31747 } else { 31748 31749 // extrapolate last point 31750 tmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] ); 31751 p3 = tmp; 31752 31753 } 31754 31755 if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) { 31756 31757 // init Centripetal / Chordal Catmull-Rom 31758 const pow = this.curveType === 'chordal' ? 0.5 : 0.25; 31759 let dt0 = Math.pow( p0.distanceToSquared( p1 ), pow ); 31760 let dt1 = Math.pow( p1.distanceToSquared( p2 ), pow ); 31761 let dt2 = Math.pow( p2.distanceToSquared( p3 ), pow ); 31762 31763 // safety check for repeated points 31764 if ( dt1 < 1e-4 ) dt1 = 1.0; 31765 if ( dt0 < 1e-4 ) dt0 = dt1; 31766 if ( dt2 < 1e-4 ) dt2 = dt1; 31767 31768 px.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 ); 31769 py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 ); 31770 pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 ); 31771 31772 } else if ( this.curveType === 'catmullrom' ) { 31773 31774 px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension ); 31775 py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension ); 31776 pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension ); 31777 31778 } 31779 31780 point.set( 31781 px.calc( weight ), 31782 py.calc( weight ), 31783 pz.calc( weight ) 31784 ); 31785 31786 return point; 31787 31788 } 31789 31790 copy( source ) { 31791 31792 super.copy( source ); 31793 31794 this.points = []; 31795 31796 for ( let i = 0, l = source.points.length; i < l; i ++ ) { 31797 31798 const point = source.points[ i ]; 31799 31800 this.points.push( point.clone() ); 31801 31802 } 31803 31804 this.closed = source.closed; 31805 this.curveType = source.curveType; 31806 this.tension = source.tension; 31807 31808 return this; 31809 31810 } 31811 31812 toJSON() { 31813 31814 const data = super.toJSON(); 31815 31816 data.points = []; 31817 31818 for ( let i = 0, l = this.points.length; i < l; i ++ ) { 31819 31820 const point = this.points[ i ]; 31821 data.points.push( point.toArray() ); 31822 31823 } 31824 31825 data.closed = this.closed; 31826 data.curveType = this.curveType; 31827 data.tension = this.tension; 31828 31829 return data; 31830 31831 } 31832 31833 fromJSON( json ) { 31834 31835 super.fromJSON( json ); 31836 31837 this.points = []; 31838 31839 for ( let i = 0, l = json.points.length; i < l; i ++ ) { 31840 31841 const point = json.points[ i ]; 31842 this.points.push( new Vector3().fromArray( point ) ); 31843 31844 } 31845 31846 this.closed = json.closed; 31847 this.curveType = json.curveType; 31848 this.tension = json.tension; 31849 31850 return this; 31851 31852 } 31853 31854} 31855 31856/** 31857 * Interpolations contains spline and Bézier functions internally used by concrete curve classes. 31858 * 31859 * Bezier Curves formulas obtained from: https://en.wikipedia.org/wiki/B%C3%A9zier_curve 31860 * 31861 * @module Interpolations 31862 */ 31863 31864/** 31865 * Computes a point on a Catmull-Rom spline. 31866 * 31867 * @param {number} t - The interpolation factor. 31868 * @param {number} p0 - The first control point. 31869 * @param {number} p1 - The second control point. 31870 * @param {number} p2 - The third control point. 31871 * @param {number} p3 - The fourth control point. 31872 * @return {number} The calculated point on a Catmull-Rom spline. 31873 */ 31874function CatmullRom( t, p0, p1, p2, p3 ) { 31875 31876 const v0 = ( p2 - p0 ) * 0.5; 31877 const v1 = ( p3 - p1 ) * 0.5; 31878 const t2 = t * t; 31879 const t3 = t * t2; 31880 return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( -3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; 31881 31882} 31883 31884// 31885 31886function QuadraticBezierP0( t, p ) { 31887 31888 const k = 1 - t; 31889 return k * k * p; 31890 31891} 31892 31893function QuadraticBezierP1( t, p ) { 31894 31895 return 2 * ( 1 - t ) * t * p; 31896 31897} 31898 31899function QuadraticBezierP2( t, p ) { 31900 31901 return t * t * p; 31902 31903} 31904 31905/** 31906 * Computes a point on a Quadratic Bezier curve. 31907 * 31908 * @param {number} t - The interpolation factor. 31909 * @param {number} p0 - The first control point. 31910 * @param {number} p1 - The second control point. 31911 * @param {number} p2 - The third control point. 31912 * @return {number} The calculated point on a Quadratic Bezier curve. 31913 */ 31914function QuadraticBezier( t, p0, p1, p2 ) { 31915 31916 return QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) + 31917 QuadraticBezierP2( t, p2 ); 31918 31919} 31920 31921// 31922 31923function CubicBezierP0( t, p ) { 31924 31925 const k = 1 - t; 31926 return k * k * k * p; 31927 31928} 31929 31930function CubicBezierP1( t, p ) { 31931 31932 const k = 1 - t; 31933 return 3 * k * k * t * p; 31934 31935} 31936 31937function CubicBezierP2( t, p ) { 31938 31939 return 3 * ( 1 - t ) * t * t * p; 31940 31941} 31942 31943function CubicBezierP3( t, p ) { 31944 31945 return t * t * t * p; 31946 31947} 31948 31949/** 31950 * Computes a point on a Cubic Bezier curve. 31951 * 31952 * @param {number} t - The interpolation factor. 31953 * @param {number} p0 - The first control point. 31954 * @param {number} p1 - The second control point. 31955 * @param {number} p2 - The third control point. 31956 * @param {number} p3 - The fourth control point. 31957 * @return {number} The calculated point on a Cubic Bezier curve. 31958 */ 31959function CubicBezier( t, p0, p1, p2, p3 ) { 31960 31961 return CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) + 31962 CubicBezierP3( t, p3 ); 31963 31964} 31965 31966/** 31967 * A curve representing a 2D Cubic Bezier curve. 31968 * 31969 * ```js 31970 * const curve = new THREE.CubicBezierCurve( 31971 * new THREE.Vector2( - 0, 0 ), 31972 * new THREE.Vector2( - 5, 15 ), 31973 * new THREE.Vector2( 20, 15 ), 31974 * new THREE.Vector2( 10, 0 ) 31975 * ); 31976 * 31977 * const points = curve.getPoints( 50 ); 31978 * const geometry = new THREE.BufferGeometry().setFromPoints( points ); 31979 * 31980 * const material = new THREE.LineBasicMaterial( { color: 0xff0000 } ); 31981 * 31982 * // Create the final object to add to the scene 31983 * const curveObject = new THREE.Line( geometry, material ); 31984 * ``` 31985 * 31986 * @augments Curve 31987 */ 31988class CubicBezierCurve extends Curve { 31989 31990 /** 31991 * Constructs a new Cubic Bezier curve. 31992 * 31993 * @param {Vector2} [v0] - The start point. 31994 * @param {Vector2} [v1] - The first control point. 31995 * @param {Vector2} [v2] - The second control point. 31996 * @param {Vector2} [v3] - The end point. 31997 */ 31998 constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) { 31999 32000 super(); 32001 32002 /** 32003 * This flag can be used for type testing. 32004 * 32005 * @type {boolean} 32006 * @readonly 32007 * @default true 32008 */ 32009 this.isCubicBezierCurve = true; 32010 32011 this.type = 'CubicBezierCurve'; 32012 32013 /** 32014 * The start point. 32015 * 32016 * @type {Vector2} 32017 */ 32018 this.v0 = v0; 32019 32020 /** 32021 * The first control point. 32022 * 32023 * @type {Vector2} 32024 */ 32025 this.v1 = v1; 32026 32027 /** 32028 * The second control point. 32029 * 32030 * @type {Vector2} 32031 */ 32032 this.v2 = v2; 32033 32034 /** 32035 * The end point. 32036 * 32037 * @type {Vector2} 32038 */ 32039 this.v3 = v3; 32040 32041 } 32042 32043 /** 32044 * Returns a point on the curve. 32045 * 32046 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 32047 * @param {Vector2} [optionalTarget] - The optional target vector the result is written to. 32048 * @return {Vector2} The position on the curve. 32049 */ 32050 getPoint( t, optionalTarget = new Vector2() ) { 32051 32052 const point = optionalTarget; 32053 32054 const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; 32055 32056 point.set( 32057 CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), 32058 CubicBezier( t, v0.y, v1.y, v2.y, v3.y ) 32059 ); 32060 32061 return point; 32062 32063 } 32064 32065 copy( source ) { 32066 32067 super.copy( source ); 32068 32069 this.v0.copy( source.v0 ); 32070 this.v1.copy( source.v1 ); 32071 this.v2.copy( source.v2 ); 32072 this.v3.copy( source.v3 ); 32073 32074 return this; 32075 32076 } 32077 32078 toJSON() { 32079 32080 const data = super.toJSON(); 32081 32082 data.v0 = this.v0.toArray(); 32083 data.v1 = this.v1.toArray(); 32084 data.v2 = this.v2.toArray(); 32085 data.v3 = this.v3.toArray(); 32086 32087 return data; 32088 32089 } 32090 32091 fromJSON( json ) { 32092 32093 super.fromJSON( json ); 32094 32095 this.v0.fromArray( json.v0 ); 32096 this.v1.fromArray( json.v1 ); 32097 this.v2.fromArray( json.v2 ); 32098 this.v3.fromArray( json.v3 ); 32099 32100 return this; 32101 32102 } 32103 32104} 32105 32106/** 32107 * A curve representing a 3D Cubic Bezier curve. 32108 * 32109 * @augments Curve 32110 */ 32111class CubicBezierCurve3 extends Curve { 32112 32113 /** 32114 * Constructs a new Cubic Bezier curve. 32115 * 32116 * @param {Vector3} [v0] - The start point. 32117 * @param {Vector3} [v1] - The first control point. 32118 * @param {Vector3} [v2] - The second control point. 32119 * @param {Vector3} [v3] - The end point. 32120 */ 32121 constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) { 32122 32123 super(); 32124 32125 /** 32126 * This flag can be used for type testing. 32127 * 32128 * @type {boolean} 32129 * @readonly 32130 * @default true 32131 */ 32132 this.isCubicBezierCurve3 = true; 32133 32134 this.type = 'CubicBezierCurve3'; 32135 32136 /** 32137 * The start point. 32138 * 32139 * @type {Vector3} 32140 */ 32141 this.v0 = v0; 32142 32143 /** 32144 * The first control point. 32145 * 32146 * @type {Vector3} 32147 */ 32148 this.v1 = v1; 32149 32150 /** 32151 * The second control point. 32152 * 32153 * @type {Vector3} 32154 */ 32155 this.v2 = v2; 32156 32157 /** 32158 * The end point. 32159 * 32160 * @type {Vector3} 32161 */ 32162 this.v3 = v3; 32163 32164 } 32165 32166 /** 32167 * Returns a point on the curve. 32168 * 32169 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 32170 * @param {Vector3} [optionalTarget] - The optional target vector the result is written to. 32171 * @return {Vector3} The position on the curve. 32172 */ 32173 getPoint( t, optionalTarget = new Vector3() ) { 32174 32175 const point = optionalTarget; 32176 32177 const v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3; 32178 32179 point.set( 32180 CubicBezier( t, v0.x, v1.x, v2.x, v3.x ), 32181 CubicBezier( t, v0.y, v1.y, v2.y, v3.y ), 32182 CubicBezier( t, v0.z, v1.z, v2.z, v3.z ) 32183 ); 32184 32185 return point; 32186 32187 } 32188 32189 copy( source ) { 32190 32191 super.copy( source ); 32192 32193 this.v0.copy( source.v0 ); 32194 this.v1.copy( source.v1 ); 32195 this.v2.copy( source.v2 ); 32196 this.v3.copy( source.v3 ); 32197 32198 return this; 32199 32200 } 32201 32202 toJSON() { 32203 32204 const data = super.toJSON(); 32205 32206 data.v0 = this.v0.toArray(); 32207 data.v1 = this.v1.toArray(); 32208 data.v2 = this.v2.toArray(); 32209 data.v3 = this.v3.toArray(); 32210 32211 return data; 32212 32213 } 32214 32215 fromJSON( json ) { 32216 32217 super.fromJSON( json ); 32218 32219 this.v0.fromArray( json.v0 ); 32220 this.v1.fromArray( json.v1 ); 32221 this.v2.fromArray( json.v2 ); 32222 this.v3.fromArray( json.v3 ); 32223 32224 return this; 32225 32226 } 32227 32228} 32229 32230/** 32231 * A curve representing a 2D line segment. 32232 * 32233 * @augments Curve 32234 */ 32235class LineCurve extends Curve { 32236 32237 /** 32238 * Constructs a new line curve. 32239 * 32240 * @param {Vector2} [v1] - The start point. 32241 * @param {Vector2} [v2] - The end point. 32242 */ 32243 constructor( v1 = new Vector2(), v2 = new Vector2() ) { 32244 32245 super(); 32246 32247 /** 32248 * This flag can be used for type testing. 32249 * 32250 * @type {boolean} 32251 * @readonly 32252 * @default true 32253 */ 32254 this.isLineCurve = true; 32255 32256 this.type = 'LineCurve'; 32257 32258 /** 32259 * The start point. 32260 * 32261 * @type {Vector2} 32262 */ 32263 this.v1 = v1; 32264 32265 /** 32266 * The end point. 32267 * 32268 * @type {Vector2} 32269 */ 32270 this.v2 = v2; 32271 32272 } 32273 32274 /** 32275 * Returns a point on the line. 32276 * 32277 * @param {number} t - A interpolation factor representing a position on the line. Must be in the range `[0,1]`. 32278 * @param {Vector2} [optionalTarget] - The optional target vector the result is written to. 32279 * @return {Vector2} The position on the line. 32280 */ 32281 getPoint( t, optionalTarget = new Vector2() ) { 32282 32283 const point = optionalTarget; 32284 32285 if ( t === 1 ) { 32286 32287 point.copy( this.v2 ); 32288 32289 } else { 32290 32291 point.copy( this.v2 ).sub( this.v1 ); 32292 point.multiplyScalar( t ).add( this.v1 ); 32293 32294 } 32295 32296 return point; 32297 32298 } 32299 32300 // Line curve is linear, so we can overwrite default getPointAt 32301 getPointAt( u, optionalTarget ) { 32302 32303 return this.getPoint( u, optionalTarget ); 32304 32305 } 32306 32307 getTangent( t, optionalTarget = new Vector2() ) { 32308 32309 return optionalTarget.subVectors( this.v2, this.v1 ).normalize(); 32310 32311 } 32312 32313 getTangentAt( u, optionalTarget ) { 32314 32315 return this.getTangent( u, optionalTarget ); 32316 32317 } 32318 32319 copy( source ) { 32320 32321 super.copy( source ); 32322 32323 this.v1.copy( source.v1 ); 32324 this.v2.copy( source.v2 ); 32325 32326 return this; 32327 32328 } 32329 32330 toJSON() { 32331 32332 const data = super.toJSON(); 32333 32334 data.v1 = this.v1.toArray(); 32335 data.v2 = this.v2.toArray(); 32336 32337 return data; 32338 32339 } 32340 32341 fromJSON( json ) { 32342 32343 super.fromJSON( json ); 32344 32345 this.v1.fromArray( json.v1 ); 32346 this.v2.fromArray( json.v2 ); 32347 32348 return this; 32349 32350 } 32351 32352} 32353 32354/** 32355 * A curve representing a 3D line segment. 32356 * 32357 * @augments Curve 32358 */ 32359class LineCurve3 extends Curve { 32360 32361 /** 32362 * Constructs a new line curve. 32363 * 32364 * @param {Vector3} [v1] - The start point. 32365 * @param {Vector3} [v2] - The end point. 32366 */ 32367 constructor( v1 = new Vector3(), v2 = new Vector3() ) { 32368 32369 super(); 32370 32371 /** 32372 * This flag can be used for type testing. 32373 * 32374 * @type {boolean} 32375 * @readonly 32376 * @default true 32377 */ 32378 this.isLineCurve3 = true; 32379 32380 this.type = 'LineCurve3'; 32381 32382 /** 32383 * The start point. 32384 * 32385 * @type {Vector3} 32386 */ 32387 this.v1 = v1; 32388 32389 /** 32390 * The end point. 32391 * 32392 * @type {Vector2} 32393 */ 32394 this.v2 = v2; 32395 32396 } 32397 32398 /** 32399 * Returns a point on the line. 32400 * 32401 * @param {number} t - A interpolation factor representing a position on the line. Must be in the range `[0,1]`. 32402 * @param {Vector3} [optionalTarget] - The optional target vector the result is written to. 32403 * @return {Vector3} The position on the line. 32404 */ 32405 getPoint( t, optionalTarget = new Vector3() ) { 32406 32407 const point = optionalTarget; 32408 32409 if ( t === 1 ) { 32410 32411 point.copy( this.v2 ); 32412 32413 } else { 32414 32415 point.copy( this.v2 ).sub( this.v1 ); 32416 point.multiplyScalar( t ).add( this.v1 ); 32417 32418 } 32419 32420 return point; 32421 32422 } 32423 32424 // Line curve is linear, so we can overwrite default getPointAt 32425 getPointAt( u, optionalTarget ) { 32426 32427 return this.getPoint( u, optionalTarget ); 32428 32429 } 32430 32431 getTangent( t, optionalTarget = new Vector3() ) { 32432 32433 return optionalTarget.subVectors( this.v2, this.v1 ).normalize(); 32434 32435 } 32436 32437 getTangentAt( u, optionalTarget ) { 32438 32439 return this.getTangent( u, optionalTarget ); 32440 32441 } 32442 32443 copy( source ) { 32444 32445 super.copy( source ); 32446 32447 this.v1.copy( source.v1 ); 32448 this.v2.copy( source.v2 ); 32449 32450 return this; 32451 32452 } 32453 32454 toJSON() { 32455 32456 const data = super.toJSON(); 32457 32458 data.v1 = this.v1.toArray(); 32459 data.v2 = this.v2.toArray(); 32460 32461 return data; 32462 32463 } 32464 32465 fromJSON( json ) { 32466 32467 super.fromJSON( json ); 32468 32469 this.v1.fromArray( json.v1 ); 32470 this.v2.fromArray( json.v2 ); 32471 32472 return this; 32473 32474 } 32475 32476} 32477 32478/** 32479 * A curve representing a 2D Quadratic Bezier curve. 32480 * 32481 * ```js 32482 * const curve = new THREE.QuadraticBezierCurve( 32483 * new THREE.Vector2( - 10, 0 ), 32484 * new THREE.Vector2( 20, 15 ), 32485 * new THREE.Vector2( 10, 0 ) 32486 * ) 32487 * 32488 * const points = curve.getPoints( 50 ); 32489 * const geometry = new THREE.BufferGeometry().setFromPoints( points ); 32490 * 32491 * const material = new THREE.LineBasicMaterial( { color: 0xff0000 } ); 32492 * 32493 * // Create the final object to add to the scene 32494 * const curveObject = new THREE.Line( geometry, material ); 32495 * ``` 32496 * 32497 * @augments Curve 32498 */ 32499class QuadraticBezierCurve extends Curve { 32500 32501 /** 32502 * Constructs a new Quadratic Bezier curve. 32503 * 32504 * @param {Vector2} [v0] - The start point. 32505 * @param {Vector2} [v1] - The control point. 32506 * @param {Vector2} [v2] - The end point. 32507 */ 32508 constructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) { 32509 32510 super(); 32511 32512 /** 32513 * This flag can be used for type testing. 32514 * 32515 * @type {boolean} 32516 * @readonly 32517 * @default true 32518 */ 32519 this.isQuadraticBezierCurve = true; 32520 32521 this.type = 'QuadraticBezierCurve'; 32522 32523 /** 32524 * The start point. 32525 * 32526 * @type {Vector2} 32527 */ 32528 this.v0 = v0; 32529 32530 /** 32531 * The control point. 32532 * 32533 * @type {Vector2} 32534 */ 32535 this.v1 = v1; 32536 32537 /** 32538 * The end point. 32539 * 32540 * @type {Vector2} 32541 */ 32542 this.v2 = v2; 32543 32544 } 32545 32546 /** 32547 * Returns a point on the curve. 32548 * 32549 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 32550 * @param {Vector2} [optionalTarget] - The optional target vector the result is written to. 32551 * @return {Vector2} The position on the curve. 32552 */ 32553 getPoint( t, optionalTarget = new Vector2() ) { 32554 32555 const point = optionalTarget; 32556 32557 const v0 = this.v0, v1 = this.v1, v2 = this.v2; 32558 32559 point.set( 32560 QuadraticBezier( t, v0.x, v1.x, v2.x ), 32561 QuadraticBezier( t, v0.y, v1.y, v2.y ) 32562 ); 32563 32564 return point; 32565 32566 } 32567 32568 copy( source ) { 32569 32570 super.copy( source ); 32571 32572 this.v0.copy( source.v0 ); 32573 this.v1.copy( source.v1 ); 32574 this.v2.copy( source.v2 ); 32575 32576 return this; 32577 32578 } 32579 32580 toJSON() { 32581 32582 const data = super.toJSON(); 32583 32584 data.v0 = this.v0.toArray(); 32585 data.v1 = this.v1.toArray(); 32586 data.v2 = this.v2.toArray(); 32587 32588 return data; 32589 32590 } 32591 32592 fromJSON( json ) { 32593 32594 super.fromJSON( json ); 32595 32596 this.v0.fromArray( json.v0 ); 32597 this.v1.fromArray( json.v1 ); 32598 this.v2.fromArray( json.v2 ); 32599 32600 return this; 32601 32602 } 32603 32604} 32605 32606/** 32607 * A curve representing a 3D Quadratic Bezier curve. 32608 * 32609 * @augments Curve 32610 */ 32611class QuadraticBezierCurve3 extends Curve { 32612 32613 /** 32614 * Constructs a new Quadratic Bezier curve. 32615 * 32616 * @param {Vector3} [v0] - The start point. 32617 * @param {Vector3} [v1] - The control point. 32618 * @param {Vector3} [v2] - The end point. 32619 */ 32620 constructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) { 32621 32622 super(); 32623 32624 /** 32625 * This flag can be used for type testing. 32626 * 32627 * @type {boolean} 32628 * @readonly 32629 * @default true 32630 */ 32631 this.isQuadraticBezierCurve3 = true; 32632 32633 this.type = 'QuadraticBezierCurve3'; 32634 32635 /** 32636 * The start point. 32637 * 32638 * @type {Vector3} 32639 */ 32640 this.v0 = v0; 32641 32642 /** 32643 * The control point. 32644 * 32645 * @type {Vector3} 32646 */ 32647 this.v1 = v1; 32648 32649 /** 32650 * The end point. 32651 * 32652 * @type {Vector3} 32653 */ 32654 this.v2 = v2; 32655 32656 } 32657 32658 /** 32659 * Returns a point on the curve. 32660 * 32661 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 32662 * @param {Vector3} [optionalTarget] - The optional target vector the result is written to. 32663 * @return {Vector3} The position on the curve. 32664 */ 32665 getPoint( t, optionalTarget = new Vector3() ) { 32666 32667 const point = optionalTarget; 32668 32669 const v0 = this.v0, v1 = this.v1, v2 = this.v2; 32670 32671 point.set( 32672 QuadraticBezier( t, v0.x, v1.x, v2.x ), 32673 QuadraticBezier( t, v0.y, v1.y, v2.y ), 32674 QuadraticBezier( t, v0.z, v1.z, v2.z ) 32675 ); 32676 32677 return point; 32678 32679 } 32680 32681 copy( source ) { 32682 32683 super.copy( source ); 32684 32685 this.v0.copy( source.v0 ); 32686 this.v1.copy( source.v1 ); 32687 this.v2.copy( source.v2 ); 32688 32689 return this; 32690 32691 } 32692 32693 toJSON() { 32694 32695 const data = super.toJSON(); 32696 32697 data.v0 = this.v0.toArray(); 32698 data.v1 = this.v1.toArray(); 32699 data.v2 = this.v2.toArray(); 32700 32701 return data; 32702 32703 } 32704 32705 fromJSON( json ) { 32706 32707 super.fromJSON( json ); 32708 32709 this.v0.fromArray( json.v0 ); 32710 this.v1.fromArray( json.v1 ); 32711 this.v2.fromArray( json.v2 ); 32712 32713 return this; 32714 32715 } 32716 32717} 32718 32719/** 32720 * A curve representing a 2D spline curve. 32721 * 32722 * ```js 32723 * // Create a sine-like wave 32724 * const curve = new THREE.SplineCurve( [ 32725 * new THREE.Vector2( -10, 0 ), 32726 * new THREE.Vector2( -5, 5 ), 32727 * new THREE.Vector2( 0, 0 ), 32728 * new THREE.Vector2( 5, -5 ), 32729 * new THREE.Vector2( 10, 0 ) 32730 * ] ); 32731 * 32732 * const points = curve.getPoints( 50 ); 32733 * const geometry = new THREE.BufferGeometry().setFromPoints( points ); 32734 * 32735 * const material = new THREE.LineBasicMaterial( { color: 0xff0000 } ); 32736 * 32737 * // Create the final object to add to the scene 32738 * const splineObject = new THREE.Line( geometry, material ); 32739 * ``` 32740 * 32741 * @augments Curve 32742 */ 32743class SplineCurve extends Curve { 32744 32745 /** 32746 * Constructs a new 2D spline curve. 32747 * 32748 * @param {Array<Vector2>} [points] - An array of 2D points defining the curve. 32749 */ 32750 constructor( points = [] ) { 32751 32752 super(); 32753 32754 /** 32755 * This flag can be used for type testing. 32756 * 32757 * @type {boolean} 32758 * @readonly 32759 * @default true 32760 */ 32761 this.isSplineCurve = true; 32762 32763 this.type = 'SplineCurve'; 32764 32765 /** 32766 * An array of 2D points defining the curve. 32767 * 32768 * @type {Array<Vector2>} 32769 */ 32770 this.points = points; 32771 32772 } 32773 32774 /** 32775 * Returns a point on the curve. 32776 * 32777 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 32778 * @param {Vector2} [optionalTarget] - The optional target vector the result is written to. 32779 * @return {Vector2} The position on the curve. 32780 */ 32781 getPoint( t, optionalTarget = new Vector2() ) { 32782 32783 const point = optionalTarget; 32784 32785 const points = this.points; 32786 const p = ( points.length - 1 ) * t; 32787 32788 const intPoint = Math.floor( p ); 32789 const weight = p - intPoint; 32790 32791 const p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ]; 32792 const p1 = points[ intPoint ]; 32793 const p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ]; 32794 const p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ]; 32795 32796 point.set( 32797 CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ), 32798 CatmullRom( weight, p0.y, p1.y, p2.y, p3.y ) 32799 ); 32800 32801 return point; 32802 32803 } 32804 32805 copy( source ) { 32806 32807 super.copy( source ); 32808 32809 this.points = []; 32810 32811 for ( let i = 0, l = source.points.length; i < l; i ++ ) { 32812 32813 const point = source.points[ i ]; 32814 32815 this.points.push( point.clone() ); 32816 32817 } 32818 32819 return this; 32820 32821 } 32822 32823 toJSON() { 32824 32825 const data = super.toJSON(); 32826 32827 data.points = []; 32828 32829 for ( let i = 0, l = this.points.length; i < l; i ++ ) { 32830 32831 const point = this.points[ i ]; 32832 data.points.push( point.toArray() ); 32833 32834 } 32835 32836 return data; 32837 32838 } 32839 32840 fromJSON( json ) { 32841 32842 super.fromJSON( json ); 32843 32844 this.points = []; 32845 32846 for ( let i = 0, l = json.points.length; i < l; i ++ ) { 32847 32848 const point = json.points[ i ]; 32849 this.points.push( new Vector2().fromArray( point ) ); 32850 32851 } 32852 32853 return this; 32854 32855 } 32856 32857} 32858 32859var Curves = /*#__PURE__*/Object.freeze({ 32860 __proto__: null, 32861 ArcCurve: ArcCurve, 32862 CatmullRomCurve3: CatmullRomCurve3, 32863 CubicBezierCurve: CubicBezierCurve, 32864 CubicBezierCurve3: CubicBezierCurve3, 32865 EllipseCurve: EllipseCurve, 32866 LineCurve: LineCurve, 32867 LineCurve3: LineCurve3, 32868 QuadraticBezierCurve: QuadraticBezierCurve, 32869 QuadraticBezierCurve3: QuadraticBezierCurve3, 32870 SplineCurve: SplineCurve 32871}); 32872 32873/** 32874 * A base class extending {@link Curve}. `CurvePath` is simply an 32875 * array of connected curves, but retains the API of a curve. 32876 * 32877 * @augments Curve 32878 */ 32879class CurvePath extends Curve { 32880 32881 /** 32882 * Constructs a new curve path. 32883 */ 32884 constructor() { 32885 32886 super(); 32887 32888 this.type = 'CurvePath'; 32889 32890 /** 32891 * An array of curves defining the 32892 * path. 32893 * 32894 * @type {Array<Curve>} 32895 */ 32896 this.curves = []; 32897 32898 /** 32899 * Whether the path should automatically be closed 32900 * by a line curve. 32901 * 32902 * @type {boolean} 32903 * @default false 32904 */ 32905 this.autoClose = false; 32906 32907 } 32908 32909 /** 32910 * Adds a curve to this curve path. 32911 * 32912 * @param {Curve} curve - The curve to add. 32913 */ 32914 add( curve ) { 32915 32916 this.curves.push( curve ); 32917 32918 } 32919 32920 /** 32921 * Adds a line curve to close the path. 32922 * 32923 * @return {CurvePath} A reference to this curve path. 32924 */ 32925 closePath() { 32926 32927 // Add a line curve if start and end of lines are not connected 32928 const startPoint = this.curves[ 0 ].getPoint( 0 ); 32929 const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 ); 32930 32931 if ( ! startPoint.equals( endPoint ) ) { 32932 32933 const lineType = ( startPoint.isVector2 === true ) ? 'LineCurve' : 'LineCurve3'; 32934 this.curves.push( new Curves[ lineType ]( endPoint, startPoint ) ); 32935 32936 } 32937 32938 return this; 32939 32940 } 32941 32942 /** 32943 * This method returns a vector in 2D or 3D space (depending on the curve definitions) 32944 * for the given interpolation factor. 32945 * 32946 * @param {number} t - A interpolation factor representing a position on the curve. Must be in the range `[0,1]`. 32947 * @param {(Vector2|Vector3)} [optionalTarget] - The optional target vector the result is written to. 32948 * @return {?(Vector2|Vector3)} The position on the curve. It can be a 2D or 3D vector depending on the curve definition. 32949 */ 32950 getPoint( t, optionalTarget ) { 32951 32952 // To get accurate point with reference to 32953 // entire path distance at time t, 32954 // following has to be done: 32955 32956 // 1. Length of each sub path have to be known 32957 // 2. Locate and identify type of curve 32958 // 3. Get t for the curve 32959 // 4. Return curve.getPointAt(t') 32960 32961 const d = t * this.getLength(); 32962 const curveLengths = this.getCurveLengths(); 32963 let i = 0; 32964 32965 // To think about boundaries points. 32966 32967 while ( i < curveLengths.length ) { 32968 32969 if ( curveLengths[ i ] >= d ) { 32970 32971 const diff = curveLengths[ i ] - d; 32972 const curve = this.curves[ i ]; 32973 32974 const segmentLength = curve.getLength(); 32975 const u = segmentLength === 0 ? 0 : 1 - diff / segmentLength; 32976 32977 return curve.getPointAt( u, optionalTarget ); 32978 32979 } 32980 32981 i ++; 32982 32983 } 32984 32985 return null; 32986 32987 // loop where sum != 0, sum > d , sum+1 <d 32988 32989 } 32990 32991 getLength() { 32992 32993 // We cannot use the default THREE.Curve getPoint() with getLength() because in 32994 // THREE.Curve, getLength() depends on getPoint() but in THREE.CurvePath 32995 // getPoint() depends on getLength 32996 32997 const lens = this.getCurveLengths(); 32998 return lens[ lens.length - 1 ]; 32999 33000 } 33001 33002 updateArcLengths() { 33003 33004 // cacheLengths must be recalculated. 33005 33006 this.needsUpdate = true; 33007 this.cacheLengths = null; 33008 this.getCurveLengths(); 33009 33010 } 33011 33012 /** 33013 * Returns list of cumulative curve lengths of the defined curves. 33014 * 33015 * @return {Array<number>} The curve lengths. 33016 */ 33017 getCurveLengths() { 33018 33019 // Compute lengths and cache them 33020 // We cannot overwrite getLengths() because UtoT mapping uses it. 33021 // We use cache values if curves and cache array are same length 33022 33023 if ( this.cacheLengths && this.cacheLengths.length === this.curves.length ) { 33024 33025 return this.cacheLengths; 33026 33027 } 33028 33029 // Get length of sub-curve 33030 // Push sums into cached array 33031 33032 const lengths = []; 33033 let sums = 0; 33034 33035 for ( let i = 0, l = this.curves.length; i < l; i ++ ) { 33036 33037 sums += this.curves[ i ].getLength(); 33038 lengths.push( sums ); 33039 33040 } 33041 33042 this.cacheLengths = lengths; 33043 33044 return lengths; 33045 33046 } 33047 33048 getSpacedPoints( divisions = 40 ) { 33049 33050 const points = []; 33051 33052 for ( let i = 0; i <= divisions; i ++ ) { 33053 33054 points.push( this.getPoint( i / divisions ) ); 33055 33056 } 33057 33058 if ( this.autoClose ) { 33059 33060 points.push( points[ 0 ] ); 33061 33062 } 33063 33064 return points; 33065 33066 } 33067 33068 getPoints( divisions = 12 ) { 33069 33070 const points = []; 33071 let last; 33072 33073 for ( let i = 0, curves = this.curves; i < curves.length; i ++ ) { 33074 33075 const curve = curves[ i ]; 33076 const resolution = curve.isEllipseCurve ? divisions * 2 33077 : ( curve.isLineCurve || curve.isLineCurve3 ) ? 1 33078 : curve.isSplineCurve ? divisions * curve.points.length 33079 : divisions; 33080 33081 const pts = curve.getPoints( resolution ); 33082 33083 for ( let j = 0; j < pts.length; j ++ ) { 33084 33085 const point = pts[ j ]; 33086 33087 if ( last && last.equals( point ) ) continue; // ensures no consecutive points are duplicates 33088 33089 points.push( point ); 33090 last = point; 33091 33092 } 33093 33094 } 33095 33096 if ( this.autoClose && points.length > 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) { 33097 33098 points.push( points[ 0 ] ); 33099 33100 } 33101 33102 return points; 33103 33104 } 33105 33106 copy( source ) { 33107 33108 super.copy( source ); 33109 33110 this.curves = []; 33111 33112 for ( let i = 0, l = source.curves.length; i < l; i ++ ) { 33113 33114 const curve = source.curves[ i ]; 33115 33116 this.curves.push( curve.clone() ); 33117 33118 } 33119 33120 this.autoClose = source.autoClose; 33121 33122 return this; 33123 33124 } 33125 33126 toJSON() { 33127 33128 const data = super.toJSON(); 33129 33130 data.autoClose = this.autoClose; 33131 data.curves = []; 33132 33133 for ( let i = 0, l = this.curves.length; i < l; i ++ ) { 33134 33135 const curve = this.curves[ i ]; 33136 data.curves.push( curve.toJSON() ); 33137 33138 } 33139 33140 return data; 33141 33142 } 33143 33144 fromJSON( json ) { 33145 33146 super.fromJSON( json ); 33147 33148 this.autoClose = json.autoClose; 33149 this.curves = []; 33150 33151 for ( let i = 0, l = json.curves.length; i < l; i ++ ) { 33152 33153 const curve = json.curves[ i ]; 33154 this.curves.push( new Curves[ curve.type ]().fromJSON( curve ) ); 33155 33156 } 33157 33158 return this; 33159 33160 } 33161 33162} 33163 33164/** 33165 * A 2D path representation. The class provides methods for creating paths 33166 * and contours of 2D shapes similar to the 2D Canvas API. 33167 * 33168 * ```js 33169 * const path = new THREE.Path(); 33170 * 33171 * path.lineTo( 0, 0.8 ); 33172 * path.quadraticCurveTo( 0, 1, 0.2, 1 ); 33173 * path.lineTo( 1, 1 ); 33174 * 33175 * const points = path.getPoints(); 33176 * 33177 * const geometry = new THREE.BufferGeometry().setFromPoints( points ); 33178 * const material = new THREE.LineBasicMaterial( { color: 0xffffff } ); 33179 * 33180 * const line = new THREE.Line( geometry, material ); 33181 * scene.add( line ); 33182 * ``` 33183 * 33184 * @augments CurvePath 33185 */ 33186class Path extends CurvePath { 33187 33188 /** 33189 * Constructs a new path. 33190 * 33191 * @param {Array<Vector2>} [points] - An array of 2D points defining the path. 33192 */ 33193 constructor( points ) { 33194 33195 super(); 33196 33197 this.type = 'Path'; 33198 33199 /** 33200 * The current offset of the path. Any new curve added will start here. 33201 * 33202 * @type {Vector2} 33203 */ 33204 this.currentPoint = new Vector2(); 33205 33206 if ( points ) { 33207 33208 this.setFromPoints( points ); 33209 33210 } 33211 33212 } 33213 33214 /** 33215 * Creates a path from the given list of points. The points are added 33216 * to the path as instances of {@link LineCurve}. 33217 * 33218 * @param {Array<Vector2>} points - An array of 2D points. 33219 * @return {Path} A reference to this path. 33220 */ 33221 setFromPoints( points ) { 33222 33223 this.moveTo( points[ 0 ].x, points[ 0 ].y ); 33224 33225 for ( let i = 1, l = points.length; i < l; i ++ ) { 33226 33227 this.lineTo( points[ i ].x, points[ i ].y ); 33228 33229 } 33230 33231 return this; 33232 33233 } 33234 33235 /** 33236 * Moves {@link Path#currentPoint} to the given point. 33237 * 33238 * @param {number} x - The x coordinate. 33239 * @param {number} y - The y coordinate. 33240 * @return {Path} A reference to this path. 33241 */ 33242 moveTo( x, y ) { 33243 33244 this.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying? 33245 33246 return this; 33247 33248 } 33249 33250 /** 33251 * Adds an instance of {@link LineCurve} to the path by connecting 33252 * the current point with the given one. 33253 * 33254 * @param {number} x - The x coordinate of the end point. 33255 * @param {number} y - The y coordinate of the end point. 33256 * @return {Path} A reference to this path. 33257 */ 33258 lineTo( x, y ) { 33259 33260 const curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) ); 33261 this.curves.push( curve ); 33262 33263 this.currentPoint.set( x, y ); 33264 33265 return this; 33266 33267 } 33268 33269 /** 33270 * Adds an instance of {@link QuadraticBezierCurve} to the path by connecting 33271 * the current point with the given one. 33272 * 33273 * @param {number} aCPx - The x coordinate of the control point. 33274 * @param {number} aCPy - The y coordinate of the control point. 33275 * @param {number} aX - The x coordinate of the end point. 33276 * @param {number} aY - The y coordinate of the end point. 33277 * @return {Path} A reference to this path. 33278 */ 33279 quadraticCurveTo( aCPx, aCPy, aX, aY ) { 33280 33281 const curve = new QuadraticBezierCurve( 33282 this.currentPoint.clone(), 33283 new Vector2( aCPx, aCPy ), 33284 new Vector2( aX, aY ) 33285 ); 33286 33287 this.curves.push( curve ); 33288 33289 this.currentPoint.set( aX, aY ); 33290 33291 return this; 33292 33293 } 33294 33295 /** 33296 * Adds an instance of {@link CubicBezierCurve} to the path by connecting 33297 * the current point with the given one. 33298 * 33299 * @param {number} aCP1x - The x coordinate of the first control point. 33300 * @param {number} aCP1y - The y coordinate of the first control point. 33301 * @param {number} aCP2x - The x coordinate of the second control point. 33302 * @param {number} aCP2y - The y coordinate of the second control point. 33303 * @param {number} aX - The x coordinate of the end point. 33304 * @param {number} aY - The y coordinate of the end point. 33305 * @return {Path} A reference to this path. 33306 */ 33307 bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { 33308 33309 const curve = new CubicBezierCurve( 33310 this.currentPoint.clone(), 33311 new Vector2( aCP1x, aCP1y ), 33312 new Vector2( aCP2x, aCP2y ), 33313 new Vector2( aX, aY ) 33314 ); 33315 33316 this.curves.push( curve ); 33317 33318 this.currentPoint.set( aX, aY ); 33319 33320 return this; 33321 33322 } 33323 33324 /** 33325 * Adds an instance of {@link SplineCurve} to the path by connecting 33326 * the current point with the given list of points. 33327 * 33328 * @param {Array<Vector2>} pts - An array of points in 2D space. 33329 * @return {Path} A reference to this path. 33330 */ 33331 splineThru( pts ) { 33332 33333 const npts = [ this.currentPoint.clone() ].concat( pts ); 33334 33335 const curve = new SplineCurve( npts ); 33336 this.curves.push( curve ); 33337 33338 this.currentPoint.copy( pts[ pts.length - 1 ] ); 33339 33340 return this; 33341 33342 } 33343 33344 /** 33345 * Adds an arc as an instance of {@link EllipseCurve} to the path, positioned relative 33346 * to the current point. 33347 * 33348 * @param {number} [aX=0] - The x coordinate of the center of the arc offsetted from the previous curve. 33349 * @param {number} [aY=0] - The y coordinate of the center of the arc offsetted from the previous curve. 33350 * @param {number} [aRadius=1] - The radius of the arc. 33351 * @param {number} [aStartAngle=0] - The start angle in radians. 33352 * @param {number} [aEndAngle=Math.PI*2] - The end angle in radians. 33353 * @param {boolean} [aClockwise=false] - Whether to sweep the arc clockwise or not. 33354 * @return {Path} A reference to this path. 33355 */ 33356 arc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { 33357 33358 const x0 = this.currentPoint.x; 33359 const y0 = this.currentPoint.y; 33360 33361 this.absarc( aX + x0, aY + y0, aRadius, 33362 aStartAngle, aEndAngle, aClockwise ); 33363 33364 return this; 33365 33366 } 33367 33368 /** 33369 * Adds an absolutely positioned arc as an instance of {@link EllipseCurve} to the path. 33370 * 33371 * @param {number} [aX=0] - The x coordinate of the center of the arc. 33372 * @param {number} [aY=0] - The y coordinate of the center of the arc. 33373 * @param {number} [aRadius=1] - The radius of the arc. 33374 * @param {number} [aStartAngle=0] - The start angle in radians. 33375 * @param {number} [aEndAngle=Math.PI*2] - The end angle in radians. 33376 * @param {boolean} [aClockwise=false] - Whether to sweep the arc clockwise or not. 33377 * @return {Path} A reference to this path. 33378 */ 33379 absarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { 33380 33381 this.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); 33382 33383 return this; 33384 33385 } 33386 33387 /** 33388 * Adds an ellipse as an instance of {@link EllipseCurve} to the path, positioned relative 33389 * to the current point 33390 * 33391 * @param {number} [aX=0] - The x coordinate of the center of the ellipse offsetted from the previous curve. 33392 * @param {number} [aY=0] - The y coordinate of the center of the ellipse offsetted from the previous curve. 33393 * @param {number} [xRadius=1] - The radius of the ellipse in the x axis. 33394 * @param {number} [yRadius=1] - The radius of the ellipse in the y axis. 33395 * @param {number} [aStartAngle=0] - The start angle in radians. 33396 * @param {number} [aEndAngle=Math.PI*2] - The end angle in radians. 33397 * @param {boolean} [aClockwise=false] - Whether to sweep the ellipse clockwise or not. 33398 * @param {number} [aRotation=0] - The rotation angle of the ellipse in radians, counterclockwise from the positive X axis. 33399 * @return {Path} A reference to this path. 33400 */ 33401 ellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { 33402 33403 const x0 = this.currentPoint.x; 33404 const y0 = this.currentPoint.y; 33405 33406 this.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); 33407 33408 return this; 33409 33410 } 33411 33412 /** 33413 * Adds an absolutely positioned ellipse as an instance of {@link EllipseCurve} to the path. 33414 * 33415 * @param {number} [aX=0] - The x coordinate of the absolute center of the ellipse. 33416 * @param {number} [aY=0] - The y coordinate of the absolute center of the ellipse. 33417 * @param {number} [xRadius=1] - The radius of the ellipse in the x axis. 33418 * @param {number} [yRadius=1] - The radius of the ellipse in the y axis. 33419 * @param {number} [aStartAngle=0] - The start angle in radians. 33420 * @param {number} [aEndAngle=Math.PI*2] - The end angle in radians. 33421 * @param {boolean} [aClockwise=false] - Whether to sweep the ellipse clockwise or not. 33422 * @param {number} [aRotation=0] - The rotation angle of the ellipse in radians, counterclockwise from the positive X axis. 33423 * @return {Path} A reference to this path. 33424 */ 33425 absellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) { 33426 33427 const curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ); 33428 33429 if ( this.curves.length > 0 ) { 33430 33431 // if a previous curve is present, attempt to join 33432 const firstPoint = curve.getPoint( 0 ); 33433 33434 if ( ! firstPoint.equals( this.currentPoint ) ) { 33435 33436 this.lineTo( firstPoint.x, firstPoint.y ); 33437 33438 } 33439 33440 } 33441 33442 this.curves.push( curve ); 33443 33444 const lastPoint = curve.getPoint( 1 ); 33445 this.currentPoint.copy( lastPoint ); 33446 33447 return this; 33448 33449 } 33450 33451 copy( source ) { 33452 33453 super.copy( source ); 33454 33455 this.currentPoint.copy( source.currentPoint ); 33456 33457 return this; 33458 33459 } 33460 33461 toJSON() { 33462 33463 const data = super.toJSON(); 33464 33465 data.currentPoint = this.currentPoint.toArray(); 33466 33467 return data; 33468 33469 } 33470 33471 fromJSON( json ) { 33472 33473 super.fromJSON( json ); 33474 33475 this.currentPoint.fromArray( json.currentPoint ); 33476 33477 return this; 33478 33479 } 33480 33481} 33482 33483/** 33484 * Defines an arbitrary 2d shape plane using paths with optional holes. It 33485 * can be used with {@link ExtrudeGeometry}, {@link ShapeGeometry}, to get 33486 * points, or to get triangulated faces. 33487 * 33488 * ```js 33489 * const heartShape = new THREE.Shape(); 33490 * 33491 * heartShape.moveTo( 25, 25 ); 33492 * heartShape.bezierCurveTo( 25, 25, 20, 0, 0, 0 ); 33493 * heartShape.bezierCurveTo( - 30, 0, - 30, 35, - 30, 35 ); 33494 * heartShape.bezierCurveTo( - 30, 55, - 10, 77, 25, 95 ); 33495 * heartShape.bezierCurveTo( 60, 77, 80, 55, 80, 35 ); 33496 * heartShape.bezierCurveTo( 80, 35, 80, 0, 50, 0 ); 33497 * heartShape.bezierCurveTo( 35, 0, 25, 25, 25, 25 ); 33498 * 33499 * const extrudeSettings = { 33500 * depth: 8, 33501 * bevelEnabled: true, 33502 * bevelSegments: 2, 33503 * steps: 2, 33504 * bevelSize: 1, 33505 * bevelThickness: 1 33506 * }; 33507 * 33508 * const geometry = new THREE.ExtrudeGeometry( heartShape, extrudeSettings ); 33509 * const mesh = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial() ); 33510 * ``` 33511 * 33512 * @augments Path 33513 */ 33514class Shape extends Path { 33515 33516 /** 33517 * Constructs a new shape. 33518 * 33519 * @param {Array<Vector2>} [points] - An array of 2D points defining the shape. 33520 */ 33521 constructor( points ) { 33522 33523 super( points ); 33524 33525 /** 33526 * The UUID of the shape. 33527 * 33528 * @type {string} 33529 * @readonly 33530 */ 33531 this.uuid = generateUUID(); 33532 33533 this.type = 'Shape'; 33534 33535 /** 33536 * Defines the holes in the shape. Hole definitions must use the 33537 * opposite winding order (CW/CCW) than the outer shape. 33538 * 33539 * @type {Array<Path>} 33540 * @readonly 33541 */ 33542 this.holes = []; 33543 33544 } 33545 33546 /** 33547 * Returns an array representing each contour of the holes 33548 * as a list of 2D points. 33549 * 33550 * @param {number} divisions - The fineness of the result. 33551 * @return {Array<Array<Vector2>>} The holes as a series of 2D points. 33552 */ 33553 getPointsHoles( divisions ) { 33554 33555 const holesPts = []; 33556 33557 for ( let i = 0, l = this.holes.length; i < l; i ++ ) { 33558 33559 holesPts[ i ] = this.holes[ i ].getPoints( divisions ); 33560 33561 } 33562 33563 return holesPts; 33564 33565 } 33566 33567 // get points of shape and holes (keypoints based on segments parameter) 33568 33569 /** 33570 * Returns an object that holds contour data for the shape and its holes as 33571 * arrays of 2D points. 33572 * 33573 * @param {number} divisions - The fineness of the result. 33574 * @return {{shape:Array<Vector2>,holes:Array<Array<Vector2>>}} An object with contour data. 33575 */ 33576 extractPoints( divisions ) { 33577 33578 return { 33579 33580 shape: this.getPoints( divisions ), 33581 holes: this.getPointsHoles( divisions ) 33582 33583 }; 33584 33585 } 33586 33587 copy( source ) { 33588 33589 super.copy( source ); 33590 33591 this.holes = []; 33592 33593 for ( let i = 0, l = source.holes.length; i < l; i ++ ) { 33594 33595 const hole = source.holes[ i ]; 33596 33597 this.holes.push( hole.clone() ); 33598 33599 } 33600 33601 return this; 33602 33603 } 33604 33605 toJSON() { 33606 33607 const data = super.toJSON(); 33608 33609 data.uuid = this.uuid; 33610 data.holes = []; 33611 33612 for ( let i = 0, l = this.holes.length; i < l; i ++ ) { 33613 33614 const hole = this.holes[ i ]; 33615 data.holes.push( hole.toJSON() ); 33616 33617 } 33618 33619 return data; 33620 33621 } 33622 33623 fromJSON( json ) { 33624 33625 super.fromJSON( json ); 33626 33627 this.uuid = json.uuid; 33628 this.holes = []; 33629 33630 for ( let i = 0, l = json.holes.length; i < l; i ++ ) { 33631 33632 const hole = json.holes[ i ]; 33633 this.holes.push( new Path().fromJSON( hole ) ); 33634 33635 } 33636 33637 return this; 33638 33639 } 33640 33641} 33642 33643/* eslint-disable */ 33644// copy of mapbox/earcut version 3.0.2 33645// https://github.com/mapbox/earcut/tree/v3.0.2 33646 33647function earcut(data, holeIndices, dim = 2) { 33648 33649 const hasHoles = holeIndices && holeIndices.length; 33650 const outerLen = hasHoles ? holeIndices[0] * dim : data.length; 33651 let outerNode = linkedList(data, 0, outerLen, dim, true); 33652 const triangles = []; 33653 33654 if (!outerNode || outerNode.next === outerNode.prev) return triangles; 33655 33656 let minX, minY, invSize; 33657 33658 if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim); 33659 33660 // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox 33661 if (data.length > 80 * dim) { 33662 minX = data[0]; 33663 minY = data[1]; 33664 let maxX = minX; 33665 let maxY = minY; 33666 33667 for (let i = dim; i < outerLen; i += dim) { 33668 const x = data[i]; 33669 const y = data[i + 1]; 33670 if (x < minX) minX = x; 33671 if (y < minY) minY = y; 33672 if (x > maxX) maxX = x; 33673 if (y > maxY) maxY = y; 33674 } 33675 33676 // minX, minY and invSize are later used to transform coords into integers for z-order calculation 33677 invSize = Math.max(maxX - minX, maxY - minY); 33678 invSize = invSize !== 0 ? 32767 / invSize : 0; 33679 } 33680 33681 earcutLinked(outerNode, triangles, dim, minX, minY, invSize, 0); 33682 33683 return triangles; 33684} 33685 33686// create a circular doubly linked list from polygon points in the specified winding order 33687function linkedList(data, start, end, dim, clockwise) { 33688 let last; 33689 33690 if (clockwise === (signedArea(data, start, end, dim) > 0)) { 33691 for (let i = start; i < end; i += dim) last = insertNode(i / dim | 0, data[i], data[i + 1], last); 33692 } else { 33693 for (let i = end - dim; i >= start; i -= dim) last = insertNode(i / dim | 0, data[i], data[i + 1], last); 33694 } 33695 33696 if (last && equals(last, last.next)) { 33697 removeNode(last); 33698 last = last.next; 33699 } 33700 33701 return last; 33702} 33703 33704// eliminate colinear or duplicate points 33705function filterPoints(start, end) { 33706 if (!start) return start; 33707 if (!end) end = start; 33708 33709 let p = start, 33710 again; 33711 do { 33712 again = false; 33713 33714 if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) { 33715 removeNode(p); 33716 p = end = p.prev; 33717 if (p === p.next) break; 33718 again = true; 33719 33720 } else { 33721 p = p.next; 33722 } 33723 } while (again || p !== end); 33724 33725 return end; 33726} 33727 33728// main ear slicing loop which triangulates a polygon (given as a linked list) 33729function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) { 33730 if (!ear) return; 33731 33732 // interlink polygon nodes in z-order 33733 if (!pass && invSize) indexCurve(ear, minX, minY, invSize); 33734 33735 let stop = ear; 33736 33737 // iterate through ears, slicing them one by one 33738 while (ear.prev !== ear.next) { 33739 const prev = ear.prev; 33740 const next = ear.next; 33741 33742 if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) { 33743 triangles.push(prev.i, ear.i, next.i); // cut off the triangle 33744 33745 removeNode(ear); 33746 33747 // skipping the next vertex leads to less sliver triangles 33748 ear = next.next; 33749 stop = next.next; 33750 33751 continue; 33752 } 33753 33754 ear = next; 33755 33756 // if we looped through the whole remaining polygon and can't find any more ears 33757 if (ear === stop) { 33758 // try filtering points and slicing again 33759 if (!pass) { 33760 earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1); 33761 33762 // if this didn't work, try curing all small self-intersections locally 33763 } else if (pass === 1) { 33764 ear = cureLocalIntersections(filterPoints(ear), triangles); 33765 earcutLinked(ear, triangles, dim, minX, minY, invSize, 2); 33766 33767 // as a last resort, try splitting the remaining polygon into two 33768 } else if (pass === 2) { 33769 splitEarcut(ear, triangles, dim, minX, minY, invSize); 33770 } 33771 33772 break; 33773 } 33774 } 33775} 33776 33777// check whether a polygon node forms a valid ear with adjacent nodes 33778function isEar(ear) { 33779 const a = ear.prev, 33780 b = ear, 33781 c = ear.next; 33782 33783 if (area(a, b, c) >= 0) return false; // reflex, can't be an ear 33784 33785 // now make sure we don't have other points inside the potential ear 33786 const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y; 33787 33788 // triangle bbox 33789 const x0 = Math.min(ax, bx, cx), 33790 y0 = Math.min(ay, by, cy), 33791 x1 = Math.max(ax, bx, cx), 33792 y1 = Math.max(ay, by, cy); 33793 33794 let p = c.next; 33795 while (p !== a) { 33796 if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && 33797 pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) && 33798 area(p.prev, p, p.next) >= 0) return false; 33799 p = p.next; 33800 } 33801 33802 return true; 33803} 33804 33805function isEarHashed(ear, minX, minY, invSize) { 33806 const a = ear.prev, 33807 b = ear, 33808 c = ear.next; 33809 33810 if (area(a, b, c) >= 0) return false; // reflex, can't be an ear 33811 33812 const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y; 33813 33814 // triangle bbox 33815 const x0 = Math.min(ax, bx, cx), 33816 y0 = Math.min(ay, by, cy), 33817 x1 = Math.max(ax, bx, cx), 33818 y1 = Math.max(ay, by, cy); 33819 33820 // z-order range for the current triangle bbox; 33821 const minZ = zOrder(x0, y0, minX, minY, invSize), 33822 maxZ = zOrder(x1, y1, minX, minY, invSize); 33823 33824 let p = ear.prevZ, 33825 n = ear.nextZ; 33826 33827 // look for points inside the triangle in both directions 33828 while (p && p.z >= minZ && n && n.z <= maxZ) { 33829 if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && 33830 pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false; 33831 p = p.prevZ; 33832 33833 if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && 33834 pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false; 33835 n = n.nextZ; 33836 } 33837 33838 // look for remaining points in decreasing z-order 33839 while (p && p.z >= minZ) { 33840 if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c && 33841 pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false; 33842 p = p.prevZ; 33843 } 33844 33845 // look for remaining points in increasing z-order 33846 while (n && n.z <= maxZ) { 33847 if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c && 33848 pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false; 33849 n = n.nextZ; 33850 } 33851 33852 return true; 33853} 33854 33855// go through all polygon nodes and cure small local self-intersections 33856function cureLocalIntersections(start, triangles) { 33857 let p = start; 33858 do { 33859 const a = p.prev, 33860 b = p.next.next; 33861 33862 if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) { 33863 33864 triangles.push(a.i, p.i, b.i); 33865 33866 // remove two nodes involved 33867 removeNode(p); 33868 removeNode(p.next); 33869 33870 p = start = b; 33871 } 33872 p = p.next; 33873 } while (p !== start); 33874 33875 return filterPoints(p); 33876} 33877 33878// try splitting polygon into two and triangulate them independently 33879function splitEarcut(start, triangles, dim, minX, minY, invSize) { 33880 // look for a valid diagonal that divides the polygon into two 33881 let a = start; 33882 do { 33883 let b = a.next.next; 33884 while (b !== a.prev) { 33885 if (a.i !== b.i && isValidDiagonal(a, b)) { 33886 // split the polygon in two by the diagonal 33887 let c = splitPolygon(a, b); 33888 33889 // filter colinear points around the cuts 33890 a = filterPoints(a, a.next); 33891 c = filterPoints(c, c.next); 33892 33893 // run earcut on each half 33894 earcutLinked(a, triangles, dim, minX, minY, invSize, 0); 33895 earcutLinked(c, triangles, dim, minX, minY, invSize, 0); 33896 return; 33897 } 33898 b = b.next; 33899 } 33900 a = a.next; 33901 } while (a !== start); 33902} 33903 33904// link every hole into the outer loop, producing a single-ring polygon without holes 33905function eliminateHoles(data, holeIndices, outerNode, dim) { 33906 const queue = []; 33907 33908 for (let i = 0, len = holeIndices.length; i < len; i++) { 33909 const start = holeIndices[i] * dim; 33910 const end = i < len - 1 ? holeIndices[i + 1] * dim : data.length; 33911 const list = linkedList(data, start, end, dim, false); 33912 if (list === list.next) list.steiner = true; 33913 queue.push(getLeftmost(list)); 33914 } 33915 33916 queue.sort(compareXYSlope); 33917 33918 // process holes from left to right 33919 for (let i = 0; i < queue.length; i++) { 33920 outerNode = eliminateHole(queue[i], outerNode); 33921 } 33922 33923 return outerNode; 33924} 33925 33926function compareXYSlope(a, b) { 33927 let result = a.x - b.x; 33928 // when the left-most point of 2 holes meet at a vertex, sort the holes counterclockwise so that when we find 33929 // the bridge to the outer shell is always the point that they meet at. 33930 if (result === 0) { 33931 result = a.y - b.y; 33932 if (result === 0) { 33933 const aSlope = (a.next.y - a.y) / (a.next.x - a.x); 33934 const bSlope = (b.next.y - b.y) / (b.next.x - b.x); 33935 result = aSlope - bSlope; 33936 } 33937 } 33938 return result; 33939} 33940 33941// find a bridge between vertices that connects hole with an outer ring and link it 33942function eliminateHole(hole, outerNode) { 33943 const bridge = findHoleBridge(hole, outerNode); 33944 if (!bridge) { 33945 return outerNode; 33946 } 33947 33948 const bridgeReverse = splitPolygon(bridge, hole); 33949 33950 // filter collinear points around the cuts 33951 filterPoints(bridgeReverse, bridgeReverse.next); 33952 return filterPoints(bridge, bridge.next); 33953} 33954 33955// David Eberly's algorithm for finding a bridge between hole and outer polygon 33956function findHoleBridge(hole, outerNode) { 33957 let p = outerNode; 33958 const hx = hole.x; 33959 const hy = hole.y; 33960 let qx = -Infinity; 33961 let m; 33962 33963 // find a segment intersected by a ray from the hole's leftmost point to the left; 33964 // segment's endpoint with lesser x will be potential connection point 33965 // unless they intersect at a vertex, then choose the vertex 33966 if (equals(hole, p)) return p; 33967 do { 33968 if (equals(hole, p.next)) return p.next; 33969 else if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) { 33970 const x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y); 33971 if (x <= hx && x > qx) { 33972 qx = x; 33973 m = p.x < p.next.x ? p : p.next; 33974 if (x === hx) return m; // hole touches outer segment; pick leftmost endpoint 33975 } 33976 } 33977 p = p.next; 33978 } while (p !== outerNode); 33979 33980 if (!m) return null; 33981 33982 // look for points inside the triangle of hole point, segment intersection and endpoint; 33983 // if there are no points found, we have a valid connection; 33984 // otherwise choose the point of the minimum angle with the ray as connection point 33985 33986 const stop = m; 33987 const mx = m.x; 33988 const my = m.y; 33989 let tanMin = Infinity; 33990 33991 p = m; 33992 33993 do { 33994 if (hx >= p.x && p.x >= mx && hx !== p.x && 33995 pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) { 33996 33997 const tan = Math.abs(hy - p.y) / (hx - p.x); // tangential 33998 33999 if (locallyInside(p, hole) && 34000 (tan < tanMin || (tan === tanMin && (p.x > m.x || (p.x === m.x && sectorContainsSector(m, p)))))) { 34001 m = p; 34002 tanMin = tan; 34003 } 34004 } 34005 34006 p = p.next; 34007 } while (p !== stop); 34008 34009 return m; 34010} 34011 34012// whether sector in vertex m contains sector in vertex p in the same coordinates 34013function sectorContainsSector(m, p) { 34014 return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0; 34015} 34016 34017// interlink polygon nodes in z-order 34018function indexCurve(start, minX, minY, invSize) { 34019 let p = start; 34020 do { 34021 if (p.z === 0) p.z = zOrder(p.x, p.y, minX, minY, invSize); 34022 p.prevZ = p.prev; 34023 p.nextZ = p.next; 34024 p = p.next; 34025 } while (p !== start); 34026 34027 p.prevZ.nextZ = null; 34028 p.prevZ = null; 34029 34030 sortLinked(p); 34031} 34032 34033// Simon Tatham's linked list merge sort algorithm 34034// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html 34035function sortLinked(list) { 34036 let numMerges; 34037 let inSize = 1; 34038 34039 do { 34040 let p = list; 34041 let e; 34042 list = null; 34043 let tail = null; 34044 numMerges = 0; 34045 34046 while (p) { 34047 numMerges++; 34048 let q = p; 34049 let pSize = 0; 34050 for (let i = 0; i < inSize; i++) { 34051 pSize++; 34052 q = q.nextZ; 34053 if (!q) break; 34054 } 34055 let qSize = inSize; 34056 34057 while (pSize > 0 || (qSize > 0 && q)) { 34058 34059 if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) { 34060 e = p; 34061 p = p.nextZ; 34062 pSize--; 34063 } else { 34064 e = q; 34065 q = q.nextZ; 34066 qSize--; 34067 } 34068 34069 if (tail) tail.nextZ = e; 34070 else list = e; 34071 34072 e.prevZ = tail; 34073 tail = e; 34074 } 34075 34076 p = q; 34077 } 34078 34079 tail.nextZ = null; 34080 inSize *= 2; 34081 34082 } while (numMerges > 1); 34083 34084 return list; 34085} 34086 34087// z-order of a point given coords and inverse of the longer side of data bbox 34088function zOrder(x, y, minX, minY, invSize) { 34089 // coords are transformed into non-negative 15-bit integer range 34090 x = (x - minX) * invSize | 0; 34091 y = (y - minY) * invSize | 0; 34092 34093 x = (x | (x << 8)) & 0x00FF00FF; 34094 x = (x | (x << 4)) & 0x0F0F0F0F; 34095 x = (x | (x << 2)) & 0x33333333; 34096 x = (x | (x << 1)) & 0x55555555; 34097 34098 y = (y | (y << 8)) & 0x00FF00FF; 34099 y = (y | (y << 4)) & 0x0F0F0F0F; 34100 y = (y | (y << 2)) & 0x33333333; 34101 y = (y | (y << 1)) & 0x55555555; 34102 34103 return x | (y << 1); 34104} 34105 34106// find the leftmost node of a polygon ring 34107function getLeftmost(start) { 34108 let p = start, 34109 leftmost = start; 34110 do { 34111 if (p.x < leftmost.x || (p.x === leftmost.x && p.y < leftmost.y)) leftmost = p; 34112 p = p.next; 34113 } while (p !== start); 34114 34115 return leftmost; 34116} 34117 34118// check if a point lies within a convex triangle 34119function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) { 34120 return (cx - px) * (ay - py) >= (ax - px) * (cy - py) && 34121 (ax - px) * (by - py) >= (bx - px) * (ay - py) && 34122 (bx - px) * (cy - py) >= (cx - px) * (by - py); 34123} 34124 34125// check if a point lies within a convex triangle but false if its equal to the first point of the triangle 34126function pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, px, py) { 34127 return !(ax === px && ay === py) && pointInTriangle(ax, ay, bx, by, cx, cy, px, py); 34128} 34129 34130// check if a diagonal between two polygon nodes is valid (lies in polygon interior) 34131function isValidDiagonal(a, b) { 34132 return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && // doesn't intersect other edges 34133 (locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible 34134 (area(a.prev, a, b.prev) || area(a, b.prev, b)) || // does not create opposite-facing sectors 34135 equals(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0); // special zero-length case 34136} 34137 34138// signed area of a triangle 34139function area(p, q, r) { 34140 return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y); 34141} 34142 34143// check if two points are equal 34144function equals(p1, p2) { 34145 return p1.x === p2.x && p1.y === p2.y; 34146} 34147 34148// check if two segments intersect 34149function intersects(p1, q1, p2, q2) { 34150 const o1 = sign(area(p1, q1, p2)); 34151 const o2 = sign(area(p1, q1, q2)); 34152 const o3 = sign(area(p2, q2, p1)); 34153 const o4 = sign(area(p2, q2, q1)); 34154 34155 if (o1 !== o2 && o3 !== o4) return true; // general case 34156 34157 if (o1 === 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1 34158 if (o2 === 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1 34159 if (o3 === 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2 34160 if (o4 === 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2 34161 34162 return false; 34163} 34164 34165// for collinear points p, q, r, check if point q lies on segment pr 34166function onSegment(p, q, r) { 34167 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); 34168} 34169 34170function sign(num) { 34171 return num > 0 ? 1 : num < 0 ? -1 : 0; 34172} 34173 34174// check if a polygon diagonal intersects any polygon segments 34175function intersectsPolygon(a, b) { 34176 let p = a; 34177 do { 34178 if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && 34179 intersects(p, p.next, a, b)) return true; 34180 p = p.next; 34181 } while (p !== a); 34182 34183 return false; 34184} 34185 34186// check if a polygon diagonal is locally inside the polygon 34187function locallyInside(a, b) { 34188 return area(a.prev, a, a.next) < 0 ? 34189 area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 : 34190 area(a, b, a.prev) < 0 || area(a, a.next, b) < 0; 34191} 34192 34193// check if the middle point of a polygon diagonal is inside the polygon 34194function middleInside(a, b) { 34195 let p = a; 34196 let inside = false; 34197 const px = (a.x + b.x) / 2; 34198 const py = (a.y + b.y) / 2; 34199 do { 34200 if (((p.y > py) !== (p.next.y > py)) && p.next.y !== p.y && 34201 (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x)) 34202 inside = !inside; 34203 p = p.next; 34204 } while (p !== a); 34205 34206 return inside; 34207} 34208 34209// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two; 34210// if one belongs to the outer ring and another to a hole, it merges it into a single ring 34211function splitPolygon(a, b) { 34212 const a2 = createNode(a.i, a.x, a.y), 34213 b2 = createNode(b.i, b.x, b.y), 34214 an = a.next, 34215 bp = b.prev; 34216 34217 a.next = b; 34218 b.prev = a; 34219 34220 a2.next = an; 34221 an.prev = a2; 34222 34223 b2.next = a2; 34224 a2.prev = b2; 34225 34226 bp.next = b2; 34227 b2.prev = bp; 34228 34229 return b2; 34230} 34231 34232// create a node and optionally link it with previous one (in a circular doubly linked list) 34233function insertNode(i, x, y, last) { 34234 const p = createNode(i, x, y); 34235 34236 if (!last) { 34237 p.prev = p; 34238 p.next = p; 34239 34240 } else { 34241 p.next = last.next; 34242 p.prev = last; 34243 last.next.prev = p; 34244 last.next = p; 34245 } 34246 return p; 34247} 34248 34249function removeNode(p) { 34250 p.next.prev = p.prev; 34251 p.prev.next = p.next; 34252 34253 if (p.prevZ) p.prevZ.nextZ = p.nextZ; 34254 if (p.nextZ) p.nextZ.prevZ = p.prevZ; 34255} 34256 34257function createNode(i, x, y) { 34258 return { 34259 i, // vertex index in coordinates array 34260 x, y, // vertex coordinates 34261 prev: null, // previous and next vertex nodes in a polygon ring 34262 next: null, 34263 z: 0, // z-order curve value 34264 prevZ: null, // previous and next nodes in z-order 34265 nextZ: null, 34266 steiner: false // indicates whether this is a steiner point 34267 }; 34268} 34269 34270function signedArea(data, start, end, dim) { 34271 let sum = 0; 34272 for (let i = start, j = end - dim; i < end; i += dim) { 34273 sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]); 34274 j = i; 34275 } 34276 return sum; 34277} 34278 34279/** 34280 * An implementation of the earcut polygon triangulation algorithm. 34281 * The code is a port of [mapbox/earcut](https://github.com/mapbox/earcut). 34282 * 34283 * @see https://github.com/mapbox/earcut 34284 */ 34285class Earcut { 34286 34287 /** 34288 * Triangulates the given shape definition by returning an array of triangles. 34289 * 34290 * @param {Array<number>} data - An array with 2D points. 34291 * @param {Array<number>} holeIndices - An array with indices defining holes. 34292 * @param {number} [dim=2] - The number of coordinates per vertex in the input array. 34293 * @return {Array<number>} An array representing the triangulated faces. Each face is defined by three consecutive numbers 34294 * representing vertex indices. 34295 */ 34296 static triangulate( data, holeIndices, dim = 2 ) { 34297 34298 return earcut( data, holeIndices, dim ); 34299 34300 } 34301 34302} 34303 34304/** 34305 * A class containing utility functions for shapes. 34306 * 34307 * @hideconstructor 34308 */ 34309class ShapeUtils { 34310 34311 /** 34312 * Calculate area of a ( 2D ) contour polygon. 34313 * 34314 * @param {Array<Vector2>} contour - An array of 2D points. 34315 * @return {number} The area. 34316 */ 34317 static area( contour ) { 34318 34319 const n = contour.length; 34320 let a = 0.0; 34321 34322 for ( let p = n - 1, q = 0; q < n; p = q ++ ) { 34323 34324 a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; 34325 34326 } 34327 34328 return a * 0.5; 34329 34330 } 34331 34332 /** 34333 * Returns `true` if the given contour uses a clockwise winding order. 34334 * 34335 * @param {Array<Vector2>} pts - An array of 2D points defining a polygon. 34336 * @return {boolean} Whether the given contour uses a clockwise winding order or not. 34337 */ 34338 static isClockWise( pts ) { 34339 34340 return ShapeUtils.area( pts ) < 0; 34341 34342 } 34343 34344 /** 34345 * Triangulates the given shape definition. 34346 * 34347 * @param {Array<Vector2>} contour - An array of 2D points defining the contour. 34348 * @param {Array<Array<Vector2>>} holes - An array that holds arrays of 2D points defining the holes. 34349 * @return {Array<Array<number>>} An array that holds for each face definition an array with three indices. 34350 */ 34351 static triangulateShape( contour, holes ) { 34352 34353 const vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ] 34354 const holeIndices = []; // array of hole indices 34355 const faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ] 34356 34357 removeDupEndPts( contour ); 34358 addContour( vertices, contour ); 34359 34360 // 34361 34362 let holeIndex = contour.length; 34363 34364 holes.forEach( removeDupEndPts ); 34365 34366 for ( let i = 0; i < holes.length; i ++ ) { 34367 34368 holeIndices.push( holeIndex ); 34369 holeIndex += holes[ i ].length; 34370 addContour( vertices, holes[ i ] ); 34371 34372 } 34373 34374 // 34375 34376 const triangles = Earcut.triangulate( vertices, holeIndices ); 34377 34378 // 34379 34380 for ( let i = 0; i < triangles.length; i += 3 ) { 34381 34382 faces.push( triangles.slice( i, i + 3 ) ); 34383 34384 } 34385 34386 return faces; 34387 34388 } 34389 34390} 34391 34392function removeDupEndPts( points ) { 34393 34394 const l = points.length; 34395 34396 if ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) { 34397 34398 points.pop(); 34399 34400 } 34401 34402} 34403 34404function addContour( vertices, contour ) { 34405 34406 for ( let i = 0; i < contour.length; i ++ ) { 34407 34408 vertices.push( contour[ i ].x ); 34409 vertices.push( contour[ i ].y ); 34410 34411 } 34412 34413} 34414 34415/** 34416 * Creates extruded geometry from a path shape. 34417 * 34418 * ```js 34419 * const length = 12, width = 8; 34420 * 34421 * const shape = new THREE.Shape(); 34422 * shape.moveTo( 0,0 ); 34423 * shape.lineTo( 0, width ); 34424 * shape.lineTo( length, width ); 34425 * shape.lineTo( length, 0 ); 34426 * shape.lineTo( 0, 0 ); 34427 * 34428 * const geometry = new THREE.ExtrudeGeometry( shape ); 34429 * const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); 34430 * const mesh = new THREE.Mesh( geometry, material ) ; 34431 * scene.add( mesh ); 34432 * ``` 34433 * 34434 * @augments BufferGeometry 34435 * @demo scenes/geometry-browser.html#ExtrudeGeometry 34436 */ 34437class ExtrudeGeometry extends BufferGeometry { 34438 34439 /** 34440 * Constructs a new extrude geometry. 34441 * 34442 * @param {Shape|Array<Shape>} [shapes] - A shape or an array of shapes. 34443 * @param {ExtrudeGeometry~Options} [options] - The extrude settings. 34444 */ 34445 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 = {} ) { 34446 34447 super(); 34448 34449 this.type = 'ExtrudeGeometry'; 34450 34451 /** 34452 * Holds the constructor parameters that have been 34453 * used to generate the geometry. Any modification 34454 * after instantiation does not change the geometry. 34455 * 34456 * @type {Object} 34457 */ 34458 this.parameters = { 34459 shapes: shapes, 34460 options: options 34461 }; 34462 34463 shapes = Array.isArray( shapes ) ? shapes : [ shapes ]; 34464 34465 const scope = this; 34466 34467 const verticesArray = []; 34468 const uvArray = []; 34469 34470 for ( let i = 0, l = shapes.length; i < l; i ++ ) { 34471 34472 const shape = shapes[ i ]; 34473 addShape( shape ); 34474 34475 } 34476 34477 // build geometry 34478 34479 this.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) ); 34480 this.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) ); 34481 34482 this.computeVertexNormals(); 34483 34484 // functions 34485 34486 function addShape( shape ) { 34487 34488 const placeholder = []; 34489 34490 // options 34491 34492 const curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; 34493 const steps = options.steps !== undefined ? options.steps : 1; 34494 const depth = options.depth !== undefined ? options.depth : 1; 34495 34496 let bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; 34497 let bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 0.2; 34498 let bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 0.1; 34499 let bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0; 34500 let bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; 34501 34502 const extrudePath = options.extrudePath; 34503 34504 const uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator; 34505 34506 // 34507 34508 let extrudePts, extrudeByPath = false; 34509 let splineTube, binormal, normal, position2; 34510 34511 if ( extrudePath ) { 34512 34513 extrudePts = extrudePath.getSpacedPoints( steps ); 34514 34515 extrudeByPath = true; 34516 bevelEnabled = false; // bevels not supported for path extrusion 34517 34518 // SETUP TNB variables 34519 34520 const isClosed = extrudePath.isCatmullRomCurve3 ? extrudePath.closed : false; 34521 34522 splineTube = extrudePath.computeFrenetFrames( steps, isClosed ); 34523 34524 // log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); 34525 34526 binormal = new Vector3(); 34527 normal = new Vector3(); 34528 position2 = new Vector3(); 34529 34530 } 34531 34532 // Safeguards if bevels are not enabled 34533 34534 if ( ! bevelEnabled ) { 34535 34536 bevelSegments = 0; 34537 bevelThickness = 0; 34538 bevelSize = 0; 34539 bevelOffset = 0; 34540 34541 } 34542 34543 // Variables initialization 34544 34545 const shapePoints = shape.extractPoints( curveSegments ); 34546 34547 let vertices = shapePoints.shape; 34548 const holes = shapePoints.holes; 34549 34550 const reverse = ! ShapeUtils.isClockWise( vertices ); 34551 34552 if ( reverse ) { 34553 34554 vertices = vertices.reverse(); 34555 34556 // Maybe we should also check if holes are in the opposite direction, just to be safe ... 34557 34558 for ( let h = 0, hl = holes.length; h < hl; h ++ ) { 34559 34560 const ahole = holes[ h ]; 34561 34562 if ( ShapeUtils.isClockWise( ahole ) ) { 34563 34564 holes[ h ] = ahole.reverse(); 34565 34566 } 34567 34568 } 34569 34570 } 34571 34572 /**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. 34573 * @param {Array<Vector2>} points 34574 */ 34575 function mergeOverlappingPoints( points ) { 34576 34577 const THRESHOLD = 1e-10; 34578 const THRESHOLD_SQ = THRESHOLD * THRESHOLD; 34579 let prevPos = points[ 0 ]; 34580 for ( let i = 1; i <= points.length; i ++ ) { 34581 34582 const currentIndex = i % points.length; 34583 const currentPos = points[ currentIndex ]; 34584 const dx = currentPos.x - prevPos.x; 34585 const dy = currentPos.y - prevPos.y; 34586 const distSq = dx * dx + dy * dy; 34587 34588 const scalingFactorSqrt = Math.max( 34589 Math.abs( currentPos.x ), 34590 Math.abs( currentPos.y ), 34591 Math.abs( prevPos.x ), 34592 Math.abs( prevPos.y ) 34593 ); 34594 const thresholdSqScaled = THRESHOLD_SQ * scalingFactorSqrt * scalingFactorSqrt; 34595 if ( distSq <= thresholdSqScaled ) { 34596 34597 points.splice( currentIndex, 1 ); 34598 i --; 34599 continue; 34600 34601 } 34602 34603 prevPos = currentPos; 34604 34605 } 34606 34607 } 34608 34609 mergeOverlappingPoints( vertices ); 34610 holes.forEach( mergeOverlappingPoints ); 34611 34612 const numHoles = holes.length; 34613 34614 /* Vertices */ 34615 34616 const contour = vertices; // vertices has all points but contour has only points of circumference 34617 34618 for ( let h = 0; h < numHoles; h ++ ) { 34619 34620 const ahole = holes[ h ]; 34621 34622 vertices = vertices.concat( ahole ); 34623 34624 } 34625 34626 34627 function scalePt2( pt, vec, size ) { 34628 34629 if ( ! vec ) error( 'ExtrudeGeometry: vec does not exist' ); 34630 34631 return pt.clone().addScaledVector( vec, size ); 34632 34633 } 34634 34635 const vlen = vertices.length; 34636 34637 34638 // Find directions for point movement 34639 34640 34641 function getBevelVec( inPt, inPrev, inNext ) { 34642 34643 // computes for inPt the corresponding point inPt' on a new contour 34644 // shifted by 1 unit (length of normalized vector) to the left 34645 // if we walk along contour clockwise, this new contour is outside the old one 34646 // 34647 // inPt' is the intersection of the two lines parallel to the two 34648 // adjacent edges of inPt at a distance of 1 unit on the left side. 34649 34650 let v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt 34651 34652 // good reading for geometry algorithms (here: line-line intersection) 34653 // http://geomalgorithms.com/a05-_intersect-1.html 34654 34655 const v_prev_x = inPt.x - inPrev.x, 34656 v_prev_y = inPt.y - inPrev.y; 34657 const v_next_x = inNext.x - inPt.x, 34658 v_next_y = inNext.y - inPt.y; 34659 34660 const v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); 34661 34662 // check for collinear edges 34663 const collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); 34664 34665 if ( Math.abs( collinear0 ) > Number.EPSILON ) { 34666 34667 // not collinear 34668 34669 // length of vectors for normalizing 34670 34671 const v_prev_len = Math.sqrt( v_prev_lensq ); 34672 const v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y ); 34673 34674 // shift adjacent points by unit vectors to the left 34675 34676 const ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); 34677 const ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); 34678 34679 const ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); 34680 const ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); 34681 34682 // scaling factor for v_prev to intersection point 34683 34684 const sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - 34685 ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / 34686 ( v_prev_x * v_next_y - v_prev_y * v_next_x ); 34687 34688 // vector from inPt to intersection point 34689 34690 v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); 34691 v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); 34692 34693 // Don't normalize!, otherwise sharp corners become ugly 34694 // but prevent crazy spikes 34695 const v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ); 34696 if ( v_trans_lensq <= 2 ) { 34697 34698 return new Vector2( v_trans_x, v_trans_y ); 34699 34700 } else { 34701 34702 shrink_by = Math.sqrt( v_trans_lensq / 2 ); 34703 34704 } 34705 34706 } else { 34707 34708 // handle special case of collinear edges 34709 34710 let direction_eq = false; // assumes: opposite 34711 34712 if ( v_prev_x > Number.EPSILON ) { 34713 34714 if ( v_next_x > Number.EPSILON ) { 34715 34716 direction_eq = true; 34717 34718 } 34719 34720 } else { 34721 34722 if ( v_prev_x < - Number.EPSILON ) { 34723 34724 if ( v_next_x < - Number.EPSILON ) { 34725 34726 direction_eq = true; 34727 34728 } 34729 34730 } else { 34731 34732 if ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) { 34733 34734 direction_eq = true; 34735 34736 } 34737 34738 } 34739 34740 } 34741 34742 if ( direction_eq ) { 34743 34744 // log("Warning: lines are a straight sequence"); 34745 v_trans_x = - v_prev_y; 34746 v_trans_y = v_prev_x; 34747 shrink_by = Math.sqrt( v_prev_lensq ); 34748 34749 } else { 34750 34751 // log("Warning: lines are a straight spike"); 34752 v_trans_x = v_prev_x; 34753 v_trans_y = v_prev_y; 34754 shrink_by = Math.sqrt( v_prev_lensq / 2 ); 34755 34756 } 34757 34758 } 34759 34760 return new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); 34761 34762 } 34763 34764 34765 const contourMovements = []; 34766 34767 for ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { 34768 34769 if ( j === il ) j = 0; 34770 if ( k === il ) k = 0; 34771 34772 // (j)---(i)---(k) 34773 // log('i,j,k', i, j , k) 34774 34775 contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); 34776 34777 } 34778 34779 const holesMovements = []; 34780 let oneHoleMovements, verticesMovements = contourMovements.concat(); 34781 34782 for ( let h = 0, hl = numHoles; h < hl; h ++ ) { 34783 34784 const ahole = holes[ h ]; 34785 34786 oneHoleMovements = []; 34787 34788 for ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { 34789 34790 if ( j === il ) j = 0; 34791 if ( k === il ) k = 0; 34792 34793 // (j)---(i)---(k) 34794 oneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); 34795 34796 } 34797 34798 holesMovements.push( oneHoleMovements ); 34799 verticesMovements = verticesMovements.concat( oneHoleMovements ); 34800 34801 } 34802 34803 let faces; 34804 34805 if ( bevelSegments === 0 ) { 34806 34807 faces = ShapeUtils.triangulateShape( contour, holes ); 34808 34809 } else { 34810 34811 const contractedContourVertices = []; 34812 const expandedHoleVertices = []; 34813 34814 // Loop bevelSegments, 1 for the front, 1 for the back 34815 34816 for ( let b = 0; b < bevelSegments; b ++ ) { 34817 34818 //for ( b = bevelSegments; b > 0; b -- ) { 34819 34820 const t = b / bevelSegments; 34821 const z = bevelThickness * Math.cos( t * Math.PI / 2 ); 34822 const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset; 34823 34824 // contract shape 34825 34826 for ( let i = 0, il = contour.length; i < il; i ++ ) { 34827 34828 const vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); 34829 34830 v( vert.x, vert.y, - z ); 34831 if ( t === 0 ) contractedContourVertices.push( vert ); 34832 34833 } 34834 34835 // expand holes 34836 34837 for ( let h = 0, hl = numHoles; h < hl; h ++ ) { 34838 34839 const ahole = holes[ h ]; 34840 oneHoleMovements = holesMovements[ h ]; 34841 const oneHoleVertices = []; 34842 for ( let i = 0, il = ahole.length; i < il; i ++ ) { 34843 34844 const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); 34845 34846 v( vert.x, vert.y, - z ); 34847 if ( t === 0 ) oneHoleVertices.push( vert ); 34848 34849 } 34850 34851 if ( t === 0 ) expandedHoleVertices.push( oneHoleVertices ); 34852 34853 } 34854 34855 } 34856 34857 faces = ShapeUtils.triangulateShape( contractedContourVertices, expandedHoleVertices ); 34858 34859 } 34860 34861 const flen = faces.length; 34862 34863 const bs = bevelSize + bevelOffset; 34864 34865 // Back facing vertices 34866 34867 for ( let i = 0; i < vlen; i ++ ) { 34868 34869 const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; 34870 34871 if ( ! extrudeByPath ) { 34872 34873 v( vert.x, vert.y, 0 ); 34874 34875 } else { 34876 34877 // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); 34878 34879 normal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x ); 34880 binormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y ); 34881 34882 position2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal ); 34883 34884 v( position2.x, position2.y, position2.z ); 34885 34886 } 34887 34888 } 34889 34890 // Add stepped vertices... 34891 // Including front facing vertices 34892 34893 for ( let s = 1; s <= steps; s ++ ) { 34894 34895 for ( let i = 0; i < vlen; i ++ ) { 34896 34897 const vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; 34898 34899 if ( ! extrudeByPath ) { 34900 34901 v( vert.x, vert.y, depth / steps * s ); 34902 34903 } else { 34904 34905 // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); 34906 34907 normal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x ); 34908 binormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y ); 34909 34910 position2.copy( extrudePts[ s ] ).add( normal ).add( binormal ); 34911 34912 v( position2.x, position2.y, position2.z ); 34913 34914 } 34915 34916 } 34917 34918 } 34919 34920 34921 // Add bevel segments planes 34922 34923 //for ( b = 1; b <= bevelSegments; b ++ ) { 34924 for ( let b = bevelSegments - 1; b >= 0; b -- ) { 34925 34926 const t = b / bevelSegments; 34927 const z = bevelThickness * Math.cos( t * Math.PI / 2 ); 34928 const bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset; 34929 34930 // contract shape 34931 34932 for ( let i = 0, il = contour.length; i < il; i ++ ) { 34933 34934 const vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); 34935 v( vert.x, vert.y, depth + z ); 34936 34937 } 34938 34939 // expand holes 34940 34941 for ( let h = 0, hl = holes.length; h < hl; h ++ ) { 34942 34943 const ahole = holes[ h ]; 34944 oneHoleMovements = holesMovements[ h ]; 34945 34946 for ( let i = 0, il = ahole.length; i < il; i ++ ) { 34947 34948 const vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); 34949 34950 if ( ! extrudeByPath ) { 34951 34952 v( vert.x, vert.y, depth + z ); 34953 34954 } else { 34955 34956 v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); 34957 34958 } 34959 34960 } 34961 34962 } 34963 34964 } 34965 34966 /* Faces */ 34967 34968 // Top and bottom faces 34969 34970 buildLidFaces(); 34971 34972 // Sides faces 34973 34974 buildSideFaces(); 34975 34976 34977 ///// Internal functions 34978 34979 function buildLidFaces() { 34980 34981 const start = verticesArray.length / 3; 34982 34983 if ( bevelEnabled ) { 34984 34985 let layer = 0; // steps + 1 34986 let offset = vlen * layer; 34987 34988 // Bottom faces 34989 34990 for ( let i = 0; i < flen; i ++ ) { 34991 34992 const face = faces[ i ]; 34993 f3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset ); 34994 34995 } 34996 34997 layer = steps + bevelSegments * 2; 34998 offset = vlen * layer; 34999 35000 // Top faces 35001 35002 for ( let i = 0; i < flen; i ++ ) { 35003 35004 const face = faces[ i ]; 35005 f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset ); 35006 35007 } 35008 35009 } else { 35010 35011 // Bottom faces 35012 35013 for ( let i = 0; i < flen; i ++ ) { 35014 35015 const face = faces[ i ]; 35016 f3( face[ 2 ], face[ 1 ], face[ 0 ] ); 35017 35018 } 35019 35020 // Top faces 35021 35022 for ( let i = 0; i < flen; i ++ ) { 35023 35024 const face = faces[ i ]; 35025 f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps ); 35026 35027 } 35028 35029 } 35030 35031 scope.addGroup( start, verticesArray.length / 3 - start, 0 ); 35032 35033 } 35034 35035 // Create faces for the z-sides of the shape 35036 35037 function buildSideFaces() { 35038 35039 const start = verticesArray.length / 3; 35040 let layeroffset = 0; 35041 sidewalls( contour, layeroffset ); 35042 layeroffset += contour.length; 35043 35044 for ( let h = 0, hl = holes.length; h < hl; h ++ ) { 35045 35046 const ahole = holes[ h ]; 35047 sidewalls( ahole, layeroffset ); 35048 35049 //, true 35050 layeroffset += ahole.length; 35051 35052 } 35053 35054 35055 scope.addGroup( start, verticesArray.length / 3 - start, 1 ); 35056 35057 35058 } 35059 35060 function sidewalls( contour, layeroffset ) { 35061 35062 let i = contour.length; 35063 35064 while ( -- i >= 0 ) { 35065 35066 const j = i; 35067 let k = i - 1; 35068 if ( k < 0 ) k = contour.length - 1; 35069 35070 //log('b', i,j, i-1, k,vertices.length); 35071 35072 for ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) { 35073 35074 const slen1 = vlen * s; 35075 const slen2 = vlen * ( s + 1 ); 35076 35077 const a = layeroffset + j + slen1, 35078 b = layeroffset + k + slen1, 35079 c = layeroffset + k + slen2, 35080 d = layeroffset + j + slen2; 35081 35082 f4( a, b, c, d ); 35083 35084 } 35085 35086 } 35087 35088 } 35089 35090 function v( x, y, z ) { 35091 35092 placeholder.push( x ); 35093 placeholder.push( y ); 35094 placeholder.push( z ); 35095 35096 } 35097 35098 35099 function f3( a, b, c ) { 35100 35101 addVertex( a ); 35102 addVertex( b ); 35103 addVertex( c ); 35104 35105 const nextIndex = verticesArray.length / 3; 35106 const uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); 35107 35108 addUV( uvs[ 0 ] ); 35109 addUV( uvs[ 1 ] ); 35110 addUV( uvs[ 2 ] ); 35111 35112 } 35113 35114 function f4( a, b, c, d ) { 35115 35116 addVertex( a ); 35117 addVertex( b ); 35118 addVertex( d ); 35119 35120 addVertex( b ); 35121 addVertex( c ); 35122 addVertex( d ); 35123 35124 35125 const nextIndex = verticesArray.length / 3; 35126 const uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 ); 35127 35128 addUV( uvs[ 0 ] ); 35129 addUV( uvs[ 1 ] ); 35130 addUV( uvs[ 3 ] ); 35131 35132 addUV( uvs[ 1 ] ); 35133 addUV( uvs[ 2 ] ); 35134 addUV( uvs[ 3 ] ); 35135 35136 } 35137 35138 function addVertex( index ) { 35139 35140 verticesArray.push( placeholder[ index * 3 + 0 ] ); 35141 verticesArray.push( placeholder[ index * 3 + 1 ] ); 35142 verticesArray.push( placeholder[ index * 3 + 2 ] ); 35143 35144 } 35145 35146 35147 function addUV( vector2 ) { 35148 35149 uvArray.push( vector2.x ); 35150 uvArray.push( vector2.y ); 35151 35152 } 35153 35154 } 35155 35156 } 35157 35158 copy( source ) { 35159 35160 super.copy( source ); 35161 35162 this.parameters = Object.assign( {}, source.parameters ); 35163 35164 return this; 35165 35166 } 35167 35168 toJSON() { 35169 35170 const data = super.toJSON(); 35171 35172 const shapes = this.parameters.shapes; 35173 const options = this.parameters.options; 35174 35175 return toJSON$1( shapes, options, data ); 35176 35177 } 35178 35179 /** 35180 * Factory method for creating an instance of this class from the given 35181 * JSON object. 35182 * 35183 * @param {Object} data - A JSON object representing the serialized geometry. 35184 * @param {Array<Shape>} shapes - An array of shapes. 35185 * @return {ExtrudeGeometry} A new instance. 35186 */ 35187 static fromJSON( data, shapes ) { 35188 35189 const geometryShapes = []; 35190 35191 for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) { 35192 35193 const shape = shapes[ data.shapes[ j ] ]; 35194 35195 geometryShapes.push( shape ); 35196 35197 } 35198 35199 const extrudePath = data.options.extrudePath; 35200 35201 if ( extrudePath !== undefined ) { 35202 35203 data.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath ); 35204 35205 } 35206 35207 return new ExtrudeGeometry( geometryShapes, data.options ); 35208 35209 } 35210 35211} 35212 35213const WorldUVGenerator = { 35214 35215 generateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) { 35216 35217 const a_x = vertices[ indexA * 3 ]; 35218 const a_y = vertices[ indexA * 3 + 1 ]; 35219 const b_x = vertices[ indexB * 3 ]; 35220 const b_y = vertices[ indexB * 3 + 1 ]; 35221 const c_x = vertices[ indexC * 3 ]; 35222 const c_y = vertices[ indexC * 3 + 1 ]; 35223 35224 return [ 35225 new Vector2( a_x, a_y ), 35226 new Vector2( b_x, b_y ), 35227 new Vector2( c_x, c_y ) 35228 ]; 35229 35230 }, 35231 35232 generateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) { 35233 35234 const a_x = vertices[ indexA * 3 ]; 35235 const a_y = vertices[ indexA * 3 + 1 ]; 35236 const a_z = vertices[ indexA * 3 + 2 ]; 35237 const b_x = vertices[ indexB * 3 ]; 35238 const b_y = vertices[ indexB * 3 + 1 ]; 35239 const b_z = vertices[ indexB * 3 + 2 ]; 35240 const c_x = vertices[ indexC * 3 ]; 35241 const c_y = vertices[ indexC * 3 + 1 ]; 35242 const c_z = vertices[ indexC * 3 + 2 ]; 35243 const d_x = vertices[ indexD * 3 ]; 35244 const d_y = vertices[ indexD * 3 + 1 ]; 35245 const d_z = vertices[ indexD * 3 + 2 ]; 35246 35247 if ( Math.abs( a_y - b_y ) < Math.abs( a_x - b_x ) ) { 35248 35249 return [ 35250 new Vector2( a_x, 1 - a_z ), 35251 new Vector2( b_x, 1 - b_z ), 35252 new Vector2( c_x, 1 - c_z ), 35253 new Vector2( d_x, 1 - d_z ) 35254 ]; 35255 35256 } else { 35257 35258 return [ 35259 new Vector2( a_y, 1 - a_z ), 35260 new Vector2( b_y, 1 - b_z ), 35261 new Vector2( c_y, 1 - c_z ), 35262 new Vector2( d_y, 1 - d_z ) 35263 ]; 35264 35265 } 35266 35267 } 35268 35269}; 35270 35271function toJSON$1( shapes, options, data ) { 35272 35273 data.shapes = []; 35274 35275 if ( Array.isArray( shapes ) ) { 35276 35277 for ( let i = 0, l = shapes.length; i < l; i ++ ) { 35278 35279 const shape = shapes[ i ]; 35280 35281 data.shapes.push( shape.uuid ); 35282 35283 } 35284 35285 } else { 35286 35287 data.shapes.push( shapes.uuid ); 35288 35289 } 35290 35291 data.options = Object.assign( {}, options ); 35292 35293 if ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON(); 35294 35295 return data; 35296 35297} 35298 35299/** 35300 * A geometry class for representing an icosahedron. 35301 * 35302 * ```js 35303 * const geometry = new THREE.IcosahedronGeometry(); 35304 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); 35305 * const icosahedron = new THREE.Mesh( geometry, material ); 35306 * scene.add( icosahedron ); 35307 * ``` 35308 * 35309 * @augments PolyhedronGeometry 35310 * @demo scenes/geometry-browser.html#IcosahedronGeometry 35311 */ 35312class IcosahedronGeometry extends PolyhedronGeometry { 35313 35314 /** 35315 * Constructs a new icosahedron geometry. 35316 * 35317 * @param {number} [radius=1] - Radius of the icosahedron. 35318 * @param {number} [detail=0] - Setting this to a value greater than `0` adds vertices making it no longer a icosahedron. 35319 */ 35320 constructor( radius = 1, detail = 0 ) { 35321 35322 const t = ( 1 + Math.sqrt( 5 ) ) / 2; 35323 35324 const vertices = [ 35325 -1, t, 0, 1, t, 0, -1, - t, 0, 1, - t, 0, 35326 0, -1, t, 0, 1, t, 0, -1, - t, 0, 1, - t, 35327 t, 0, -1, t, 0, 1, - t, 0, -1, - t, 0, 1 35328 ]; 35329 35330 const indices = [ 35331 0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11, 35332 1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8, 35333 3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9, 35334 4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1 35335 ]; 35336 35337 super( vertices, indices, radius, detail ); 35338 35339 this.type = 'IcosahedronGeometry'; 35340 35341 /** 35342 * Holds the constructor parameters that have been 35343 * used to generate the geometry. Any modification 35344 * after instantiation does not change the geometry. 35345 * 35346 * @type {Object} 35347 */ 35348 this.parameters = { 35349 radius: radius, 35350 detail: detail 35351 }; 35352 35353 } 35354 35355 /** 35356 * Factory method for creating an instance of this class from the given 35357 * JSON object. 35358 * 35359 * @param {Object} data - A JSON object representing the serialized geometry. 35360 * @return {IcosahedronGeometry} A new instance. 35361 */ 35362 static fromJSON( data ) { 35363 35364 return new IcosahedronGeometry( data.radius, data.detail ); 35365 35366 } 35367 35368} 35369 35370/** 35371 * Creates meshes with axial symmetry like vases. The lathe rotates around the Y axis. 35372 * 35373 * ```js 35374 * const points = []; 35375 * for ( let i = 0; i < 10; i ++ ) { 35376 * points.push( new THREE.Vector2( Math.sin( i * 0.2 ) * 10 + 5, ( i - 5 ) * 2 ) ); 35377 * } 35378 * const geometry = new THREE.LatheGeometry( points ); 35379 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); 35380 * const lathe = new THREE.Mesh( geometry, material ); 35381 * scene.add( lathe ); 35382 * ``` 35383 * 35384 * @augments BufferGeometry 35385 * @demo scenes/geometry-browser.html#LatheGeometry 35386 */ 35387class LatheGeometry extends BufferGeometry { 35388 35389 /** 35390 * Constructs a new lathe geometry. 35391 * 35392 * @param {Array<Vector2|Vector3>} [points] - An array of points in 2D space. The x-coordinate of each point 35393 * must be greater than zero. 35394 * @param {number} [segments=12] - The number of circumference segments to generate. 35395 * @param {number} [phiStart=0] - The starting angle in radians. 35396 * @param {number} [phiLength=Math.PI*2] - The radian (0 to 2PI) range of the lathed section 2PI is a 35397 * closed lathe, less than 2PI is a portion. 35398 */ 35399 constructor( points = [ new Vector2( 0, -0.5 ), new Vector2( 0.5, 0 ), new Vector2( 0, 0.5 ) ], segments = 12, phiStart = 0, phiLength = Math.PI * 2 ) { 35400 35401 super(); 35402 35403 this.type = 'LatheGeometry'; 35404 35405 /** 35406 * Holds the constructor parameters that have been 35407 * used to generate the geometry. Any modification 35408 * after instantiation does not change the geometry. 35409 * 35410 * @type {Object} 35411 */ 35412 this.parameters = { 35413 points: points, 35414 segments: segments, 35415 phiStart: phiStart, 35416 phiLength: phiLength 35417 }; 35418 35419 segments = Math.floor( segments ); 35420 35421 // clamp phiLength so it's in range of [ 0, 2PI ] 35422 35423 phiLength = clamp( phiLength, 0, Math.PI * 2 ); 35424 35425 // buffers 35426 35427 const indices = []; 35428 const vertices = []; 35429 const uvs = []; 35430 const initNormals = []; 35431 const normals = []; 35432 35433 // helper variables 35434 35435 const inverseSegments = 1.0 / segments; 35436 const vertex = new Vector3(); 35437 const uv = new Vector2(); 35438 const normal = new Vector3(); 35439 const curNormal = new Vector3(); 35440 const prevNormal = new Vector3(); 35441 let dx = 0; 35442 let dy = 0; 35443 35444 // pre-compute normals for initial "meridian" 35445 35446 for ( let j = 0; j <= ( points.length - 1 ); j ++ ) { 35447 35448 switch ( j ) { 35449 35450 case 0: // special handling for 1st vertex on path 35451 35452 dx = points[ j + 1 ].x - points[ j ].x; 35453 dy = points[ j + 1 ].y - points[ j ].y; 35454 35455 normal.x = dy * 1.0; 35456 normal.y = - dx; 35457 normal.z = dy * 0.0; 35458 35459 prevNormal.copy( normal ); 35460 35461 normal.normalize(); 35462 35463 initNormals.push( normal.x, normal.y, normal.z ); 35464 35465 break; 35466 35467 case ( points.length - 1 ): // special handling for last Vertex on path 35468 35469 initNormals.push( prevNormal.x, prevNormal.y, prevNormal.z ); 35470 35471 break; 35472 35473 default: // default handling for all vertices in between 35474 35475 dx = points[ j + 1 ].x - points[ j ].x; 35476 dy = points[ j + 1 ].y - points[ j ].y; 35477 35478 normal.x = dy * 1.0; 35479 normal.y = - dx; 35480 normal.z = dy * 0.0; 35481 35482 curNormal.copy( normal ); 35483 35484 normal.x += prevNormal.x; 35485 normal.y += prevNormal.y; 35486 normal.z += prevNormal.z; 35487 35488 normal.normalize(); 35489 35490 initNormals.push( normal.x, normal.y, normal.z ); 35491 35492 prevNormal.copy( curNormal ); 35493 35494 } 35495 35496 } 35497 35498 // generate vertices, uvs and normals 35499 35500 for ( let i = 0; i <= segments; i ++ ) { 35501 35502 const phi = phiStart + i * inverseSegments * phiLength; 35503 35504 const sin = Math.sin( phi ); 35505 const cos = Math.cos( phi ); 35506 35507 for ( let j = 0; j <= ( points.length - 1 ); j ++ ) { 35508 35509 // vertex 35510 35511 vertex.x = points[ j ].x * sin; 35512 vertex.y = points[ j ].y; 35513 vertex.z = points[ j ].x * cos; 35514 35515 vertices.push( vertex.x, vertex.y, vertex.z ); 35516 35517 // uv 35518 35519 uv.x = i / segments; 35520 uv.y = j / ( points.length - 1 ); 35521 35522 uvs.push( uv.x, uv.y ); 35523 35524 // normal 35525 35526 const x = initNormals[ 3 * j + 0 ] * sin; 35527 const y = initNormals[ 3 * j + 1 ]; 35528 const z = initNormals[ 3 * j + 0 ] * cos; 35529 35530 normals.push( x, y, z ); 35531 35532 } 35533 35534 } 35535 35536 // indices 35537 35538 for ( let i = 0; i < segments; i ++ ) { 35539 35540 for ( let j = 0; j < ( points.length - 1 ); j ++ ) { 35541 35542 const base = j + i * points.length; 35543 35544 const a = base; 35545 const b = base + points.length; 35546 const c = base + points.length + 1; 35547 const d = base + 1; 35548 35549 // faces 35550 35551 indices.push( a, b, d ); 35552 indices.push( c, d, b ); 35553 35554 } 35555 35556 } 35557 35558 // build geometry 35559 35560 this.setIndex( indices ); 35561 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 35562 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 35563 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 35564 35565 } 35566 35567 copy( source ) { 35568 35569 super.copy( source ); 35570 35571 this.parameters = Object.assign( {}, source.parameters ); 35572 35573 return this; 35574 35575 } 35576 35577 /** 35578 * Factory method for creating an instance of this class from the given 35579 * JSON object. 35580 * 35581 * @param {Object} data - A JSON object representing the serialized geometry. 35582 * @return {LatheGeometry} A new instance. 35583 */ 35584 static fromJSON( data ) { 35585 35586 return new LatheGeometry( data.points, data.segments, data.phiStart, data.phiLength ); 35587 35588 } 35589 35590} 35591 35592/** 35593 * A geometry class for representing an octahedron. 35594 * 35595 * ```js 35596 * const geometry = new THREE.OctahedronGeometry(); 35597 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); 35598 * const octahedron = new THREE.Mesh( geometry, material ); 35599 * scene.add( octahedron ); 35600 * ``` 35601 * 35602 * @augments PolyhedronGeometry 35603 * @demo scenes/geometry-browser.html#OctahedronGeometry 35604 */ 35605class OctahedronGeometry extends PolyhedronGeometry { 35606 35607 /** 35608 * Constructs a new octahedron geometry. 35609 * 35610 * @param {number} [radius=1] - Radius of the octahedron. 35611 * @param {number} [detail=0] - Setting this to a value greater than `0` adds vertices making it no longer a octahedron. 35612 */ 35613 constructor( radius = 1, detail = 0 ) { 35614 35615 const vertices = [ 35616 1, 0, 0, -1, 0, 0, 0, 1, 0, 35617 0, -1, 0, 0, 0, 1, 0, 0, -1 35618 ]; 35619 35620 const indices = [ 35621 0, 2, 4, 0, 4, 3, 0, 3, 5, 35622 0, 5, 2, 1, 2, 5, 1, 5, 3, 35623 1, 3, 4, 1, 4, 2 35624 ]; 35625 35626 super( vertices, indices, radius, detail ); 35627 35628 this.type = 'OctahedronGeometry'; 35629 35630 /** 35631 * Holds the constructor parameters that have been 35632 * used to generate the geometry. Any modification 35633 * after instantiation does not change the geometry. 35634 * 35635 * @type {Object} 35636 */ 35637 this.parameters = { 35638 radius: radius, 35639 detail: detail 35640 }; 35641 35642 } 35643 35644 /** 35645 * Factory method for creating an instance of this class from the given 35646 * JSON object. 35647 * 35648 * @param {Object} data - A JSON object representing the serialized geometry. 35649 * @return {OctahedronGeometry} A new instance. 35650 */ 35651 static fromJSON( data ) { 35652 35653 return new OctahedronGeometry( data.radius, data.detail ); 35654 35655 } 35656 35657} 35658 35659/** 35660 * A geometry class for representing a plane. 35661 * 35662 * ```js 35663 * const geometry = new THREE.PlaneGeometry( 1, 1 ); 35664 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00, side: THREE.DoubleSide } ); 35665 * const plane = new THREE.Mesh( geometry, material ); 35666 * scene.add( plane ); 35667 * ``` 35668 * 35669 * @augments BufferGeometry 35670 * @demo scenes/geometry-browser.html#PlaneGeometry 35671 */ 35672class PlaneGeometry extends BufferGeometry { 35673 35674 /** 35675 * Constructs a new plane geometry. 35676 * 35677 * @param {number} [width=1] - The width along the X axis. 35678 * @param {number} [height=1] - The height along the Y axis 35679 * @param {number} [widthSegments=1] - The number of segments along the X axis. 35680 * @param {number} [heightSegments=1] - The number of segments along the Y axis. 35681 */ 35682 constructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) { 35683 35684 super(); 35685 35686 this.type = 'PlaneGeometry'; 35687 35688 /** 35689 * Holds the constructor parameters that have been 35690 * used to generate the geometry. Any modification 35691 * after instantiation does not change the geometry. 35692 * 35693 * @type {Object} 35694 */ 35695 this.parameters = { 35696 width: width, 35697 height: height, 35698 widthSegments: widthSegments, 35699 heightSegments: heightSegments 35700 }; 35701 35702 const width_half = width / 2; 35703 const height_half = height / 2; 35704 35705 const gridX = Math.floor( widthSegments ); 35706 const gridY = Math.floor( heightSegments ); 35707 35708 const gridX1 = gridX + 1; 35709 const gridY1 = gridY + 1; 35710 35711 const segment_width = width / gridX; 35712 const segment_height = height / gridY; 35713 35714 // 35715 35716 const indices = []; 35717 const vertices = []; 35718 const normals = []; 35719 const uvs = []; 35720 35721 for ( let iy = 0; iy < gridY1; iy ++ ) { 35722 35723 const y = iy * segment_height - height_half; 35724 35725 for ( let ix = 0; ix < gridX1; ix ++ ) { 35726 35727 const x = ix * segment_width - width_half; 35728 35729 vertices.push( x, - y, 0 ); 35730 35731 normals.push( 0, 0, 1 ); 35732 35733 uvs.push( ix / gridX ); 35734 uvs.push( 1 - ( iy / gridY ) ); 35735 35736 } 35737 35738 } 35739 35740 for ( let iy = 0; iy < gridY; iy ++ ) { 35741 35742 for ( let ix = 0; ix < gridX; ix ++ ) { 35743 35744 const a = ix + gridX1 * iy; 35745 const b = ix + gridX1 * ( iy + 1 ); 35746 const c = ( ix + 1 ) + gridX1 * ( iy + 1 ); 35747 const d = ( ix + 1 ) + gridX1 * iy; 35748 35749 indices.push( a, b, d ); 35750 indices.push( b, c, d ); 35751 35752 } 35753 35754 } 35755 35756 this.setIndex( indices ); 35757 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 35758 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 35759 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 35760 35761 } 35762 35763 copy( source ) { 35764 35765 super.copy( source ); 35766 35767 this.parameters = Object.assign( {}, source.parameters ); 35768 35769 return this; 35770 35771 } 35772 35773 /** 35774 * Factory method for creating an instance of this class from the given 35775 * JSON object. 35776 * 35777 * @param {Object} data - A JSON object representing the serialized geometry. 35778 * @return {PlaneGeometry} A new instance. 35779 */ 35780 static fromJSON( data ) { 35781 35782 return new PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments ); 35783 35784 } 35785 35786} 35787 35788/** 35789 * A class for generating a two-dimensional ring geometry. 35790 * 35791 * ```js 35792 * const geometry = new THREE.RingGeometry( 1, 5, 32 ); 35793 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00, side: THREE.DoubleSide } ); 35794 * const mesh = new THREE.Mesh( geometry, material ); 35795 * scene.add( mesh ); 35796 * ``` 35797 * 35798 * @augments BufferGeometry 35799 * @demo scenes/geometry-browser.html#RingGeometry 35800 */ 35801class RingGeometry extends BufferGeometry { 35802 35803 /** 35804 * Constructs a new ring geometry. 35805 * 35806 * @param {number} [innerRadius=0.5] - The inner radius of the ring. 35807 * @param {number} [outerRadius=1] - The outer radius of the ring. 35808 * @param {number} [thetaSegments=32] - Number of segments. A higher number means the ring will be more round. Minimum is `3`. 35809 * @param {number} [phiSegments=1] - Number of segments per ring segment. Minimum is `1`. 35810 * @param {number} [thetaStart=0] - Starting angle in radians. 35811 * @param {number} [thetaLength=Math.PI*2] - Central angle in radians. 35812 */ 35813 constructor( innerRadius = 0.5, outerRadius = 1, thetaSegments = 32, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2 ) { 35814 35815 super(); 35816 35817 this.type = 'RingGeometry'; 35818 35819 /** 35820 * Holds the constructor parameters that have been 35821 * used to generate the geometry. Any modification 35822 * after instantiation does not change the geometry. 35823 * 35824 * @type {Object} 35825 */ 35826 this.parameters = { 35827 innerRadius: innerRadius, 35828 outerRadius: outerRadius, 35829 thetaSegments: thetaSegments, 35830 phiSegments: phiSegments, 35831 thetaStart: thetaStart, 35832 thetaLength: thetaLength 35833 }; 35834 35835 thetaSegments = Math.max( 3, thetaSegments ); 35836 phiSegments = Math.max( 1, phiSegments ); 35837 35838 // buffers 35839 35840 const indices = []; 35841 const vertices = []; 35842 const normals = []; 35843 const uvs = []; 35844 35845 // some helper variables 35846 35847 let radius = innerRadius; 35848 const radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); 35849 const vertex = new Vector3(); 35850 const uv = new Vector2(); 35851 35852 // generate vertices, normals and uvs 35853 35854 for ( let j = 0; j <= phiSegments; j ++ ) { 35855 35856 for ( let i = 0; i <= thetaSegments; i ++ ) { 35857 35858 // values are generate from the inside of the ring to the outside 35859 35860 const segment = thetaStart + i / thetaSegments * thetaLength; 35861 35862 // vertex 35863 35864 vertex.x = radius * Math.cos( segment ); 35865 vertex.y = radius * Math.sin( segment ); 35866 35867 vertices.push( vertex.x, vertex.y, vertex.z ); 35868 35869 // normal 35870 35871 normals.push( 0, 0, 1 ); 35872 35873 // uv 35874 35875 uv.x = ( vertex.x / outerRadius + 1 ) / 2; 35876 uv.y = ( vertex.y / outerRadius + 1 ) / 2; 35877 35878 uvs.push( uv.x, uv.y ); 35879 35880 } 35881 35882 // increase the radius for next row of vertices 35883 35884 radius += radiusStep; 35885 35886 } 35887 35888 // indices 35889 35890 for ( let j = 0; j < phiSegments; j ++ ) { 35891 35892 const thetaSegmentLevel = j * ( thetaSegments + 1 ); 35893 35894 for ( let i = 0; i < thetaSegments; i ++ ) { 35895 35896 const segment = i + thetaSegmentLevel; 35897 35898 const a = segment; 35899 const b = segment + thetaSegments + 1; 35900 const c = segment + thetaSegments + 2; 35901 const d = segment + 1; 35902 35903 // faces 35904 35905 indices.push( a, b, d ); 35906 indices.push( b, c, d ); 35907 35908 } 35909 35910 } 35911 35912 // build geometry 35913 35914 this.setIndex( indices ); 35915 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 35916 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 35917 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 35918 35919 } 35920 35921 copy( source ) { 35922 35923 super.copy( source ); 35924 35925 this.parameters = Object.assign( {}, source.parameters ); 35926 35927 return this; 35928 35929 } 35930 35931 /** 35932 * Factory method for creating an instance of this class from the given 35933 * JSON object. 35934 * 35935 * @param {Object} data - A JSON object representing the serialized geometry. 35936 * @return {RingGeometry} A new instance. 35937 */ 35938 static fromJSON( data ) { 35939 35940 return new RingGeometry( data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength ); 35941 35942 } 35943 35944} 35945 35946/** 35947 * Creates an one-sided polygonal geometry from one or more path shapes. 35948 * 35949 * ```js 35950 * const arcShape = new THREE.Shape() 35951 * .moveTo( 5, 1 ) 35952 * .absarc( 1, 1, 4, 0, Math.PI * 2, false ); 35953 * 35954 * const geometry = new THREE.ShapeGeometry( arcShape ); 35955 * const material = new THREE.MeshBasicMaterial( { color: 0x00ff00, side: THREE.DoubleSide } ); 35956 * const mesh = new THREE.Mesh( geometry, material ) ; 35957 * scene.add( mesh ); 35958 * ``` 35959 * 35960 * @augments BufferGeometry 35961 * @demo scenes/geometry-browser.html#ShapeGeometry 35962 */ 35963class ShapeGeometry extends BufferGeometry { 35964 35965 /** 35966 * Constructs a new shape geometry. 35967 * 35968 * @param {Shape|Array<Shape>} [shapes] - A shape or an array of shapes. 35969 * @param {number} [curveSegments=12] - Number of segments per shape. 35970 */ 35971 constructor( shapes = new Shape( [ new Vector2( 0, 0.5 ), new Vector2( -0.5, -0.5 ), new Vector2( 0.5, -0.5 ) ] ), curveSegments = 12 ) { 35972 35973 super(); 35974 35975 this.type = 'ShapeGeometry'; 35976 35977 /** 35978 * Holds the constructor parameters that have been 35979 * used to generate the geometry. Any modification 35980 * after instantiation does not change the geometry. 35981 * 35982 * @type {Object} 35983 */ 35984 this.parameters = { 35985 shapes: shapes, 35986 curveSegments: curveSegments 35987 }; 35988 35989 // buffers 35990 35991 const indices = []; 35992 const vertices = []; 35993 const normals = []; 35994 const uvs = []; 35995 35996 // helper variables 35997 35998 let groupStart = 0; 35999 let groupCount = 0; 36000 36001 // allow single and array values for "shapes" parameter 36002 36003 if ( Array.isArray( shapes ) === false ) { 36004 36005 addShape( shapes ); 36006 36007 } else { 36008 36009 for ( let i = 0; i < shapes.length; i ++ ) { 36010 36011 addShape( shapes[ i ] ); 36012 36013 this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support 36014 36015 groupStart += groupCount; 36016 groupCount = 0; 36017 36018 } 36019 36020 } 36021 36022 // build geometry 36023 36024 this.setIndex( indices ); 36025 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 36026 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 36027 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 36028 36029 36030 // helper functions 36031 36032 function addShape( shape ) { 36033 36034 const indexOffset = vertices.length / 3; 36035 const points = shape.extractPoints( curveSegments ); 36036 36037 let shapeVertices = points.shape; 36038 const shapeHoles = points.holes; 36039 36040 // check direction of vertices 36041 36042 if ( ShapeUtils.isClockWise( shapeVertices ) === false ) { 36043 36044 shapeVertices = shapeVertices.reverse(); 36045 36046 } 36047 36048 for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) { 36049 36050 const shapeHole = shapeHoles[ i ]; 36051 36052 if ( ShapeUtils.isClockWise( shapeHole ) === true ) { 36053 36054 shapeHoles[ i ] = shapeHole.reverse(); 36055 36056 } 36057 36058 } 36059 36060 const faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles ); 36061 36062 // join vertices of inner and outer paths to a single array 36063 36064 for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) { 36065 36066 const shapeHole = shapeHoles[ i ]; 36067 shapeVertices = shapeVertices.concat( shapeHole ); 36068 36069 } 36070 36071 // vertices, normals, uvs 36072 36073 for ( let i = 0, l = shapeVertices.length; i < l; i ++ ) { 36074 36075 const vertex = shapeVertices[ i ]; 36076 36077 vertices.push( vertex.x, vertex.y, 0 ); 36078 normals.push( 0, 0, 1 ); 36079 uvs.push( vertex.x, vertex.y ); // world uvs 36080 36081 } 36082 36083 // indices 36084 36085 for ( let i = 0, l = faces.length; i < l; i ++ ) { 36086 36087 const face = faces[ i ]; 36088 36089 const a = face[ 0 ] + indexOffset; 36090 const b = face[ 1 ] + indexOffset; 36091 const c = face[ 2 ] + indexOffset; 36092 36093 indices.push( a, b, c ); 36094 groupCount += 3; 36095 36096 } 36097 36098 } 36099 36100 } 36101 36102 copy( source ) { 36103 36104 super.copy( source ); 36105 36106 this.parameters = Object.assign( {}, source.parameters ); 36107 36108 return this; 36109 36110 } 36111 36112 toJSON() { 36113 36114 const data = super.toJSON(); 36115 36116 const shapes = this.parameters.shapes; 36117 36118 return toJSON( shapes, data ); 36119 36120 } 36121 36122 /** 36123 * Factory method for creating an instance of this class from the given 36124 * JSON object. 36125 * 36126 * @param {Object} data - A JSON object representing the serialized geometry. 36127 * @param {Array<Shape>} shapes - An array of shapes. 36128 * @return {ShapeGeometry} A new instance. 36129 */ 36130 static fromJSON( data, shapes ) { 36131 36132 const geometryShapes = []; 36133 36134 for ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) { 36135 36136 const shape = shapes[ data.shapes[ j ] ]; 36137 36138 geometryShapes.push( shape ); 36139 36140 } 36141 36142 return new ShapeGeometry( geometryShapes, data.curveSegments ); 36143 36144 } 36145 36146} 36147 36148function toJSON( shapes, data ) { 36149 36150 data.shapes = []; 36151 36152 if ( Array.isArray( shapes ) ) { 36153 36154 for ( let i = 0, l = shapes.length; i < l; i ++ ) { 36155 36156 const shape = shapes[ i ]; 36157 36158 data.shapes.push( shape.uuid ); 36159 36160 } 36161 36162 } else { 36163 36164 data.shapes.push( shapes.uuid ); 36165 36166 } 36167 36168 return data; 36169 36170} 36171 36172/** 36173 * A class for generating a sphere geometry. 36174 * 36175 * ```js 36176 * const geometry = new THREE.SphereGeometry( 15, 32, 16 ); 36177 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); 36178 * const sphere = new THREE.Mesh( geometry, material ); 36179 * scene.add( sphere ); 36180 * ``` 36181 * 36182 * @augments BufferGeometry 36183 * @demo scenes/geometry-browser.html#SphereGeometry 36184 */ 36185class SphereGeometry extends BufferGeometry { 36186 36187 /** 36188 * Constructs a new sphere geometry. 36189 * 36190 * @param {number} [radius=1] - The sphere radius. 36191 * @param {number} [widthSegments=32] - The number of horizontal segments. Minimum value is `3`. 36192 * @param {number} [heightSegments=16] - The number of vertical segments. Minimum value is `2`. 36193 * @param {number} [phiStart=0] - The horizontal starting angle in radians. 36194 * @param {number} [phiLength=Math.PI*2] - The horizontal sweep angle size. 36195 * @param {number} [thetaStart=0] - The vertical starting angle in radians. 36196 * @param {number} [thetaLength=Math.PI] - The vertical sweep angle size. 36197 */ 36198 constructor( radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) { 36199 36200 super(); 36201 36202 this.type = 'SphereGeometry'; 36203 36204 /** 36205 * Holds the constructor parameters that have been 36206 * used to generate the geometry. Any modification 36207 * after instantiation does not change the geometry. 36208 * 36209 * @type {Object} 36210 */ 36211 this.parameters = { 36212 radius: radius, 36213 widthSegments: widthSegments, 36214 heightSegments: heightSegments, 36215 phiStart: phiStart, 36216 phiLength: phiLength, 36217 thetaStart: thetaStart, 36218 thetaLength: thetaLength 36219 }; 36220 36221 widthSegments = Math.max( 3, Math.floor( widthSegments ) ); 36222 heightSegments = Math.max( 2, Math.floor( heightSegments ) ); 36223 36224 const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI ); 36225 36226 let index = 0; 36227 const grid = []; 36228 36229 const vertex = new Vector3(); 36230 const normal = new Vector3(); 36231 36232 // buffers 36233 36234 const indices = []; 36235 const vertices = []; 36236 const normals = []; 36237 const uvs = []; 36238 36239 // generate vertices, normals and uvs 36240 36241 for ( let iy = 0; iy <= heightSegments; iy ++ ) { 36242 36243 const verticesRow = []; 36244 36245 const v = iy / heightSegments;
36246 36247 // special case for the poles 36248 36249 let uOffset = 0; 36250 36251 if ( iy === 0 && thetaStart === 0 ) { 36252 36253 uOffset = 0.5 / widthSegments; 36254 36255 } else if ( iy === heightSegments && thetaEnd === Math.PI ) { 36256 36257 uOffset = -0.5 / widthSegments; 36258 36259 } 36260 36261 for ( let ix = 0; ix <= widthSegments; ix ++ ) { 36262 36263 const u = ix / widthSegments; 36264 36265 // vertex 36266 36267 vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); 36268 vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); 36269 vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength
vendor: 34,031 bytes, lines 36269-37694
36269 ); 36270 36271 vertices.push( vertex.x, vertex.y, vertex.z ); 36272 36273 // normal 36274 36275 normal.copy( vertex ).normalize(); 36276 normals.push( normal.x, normal.y, normal.z ); 36277 36278 // uv 36279 36280 uvs.push( u + uOffset, 1 - v ); 36281 36282 verticesRow.push( index ++ ); 36283 36284 } 36285 36286 grid.push( verticesRow ); 36287 36288 } 36289 36290 // indices 36291 36292 for ( let iy = 0; iy < heightSegments; iy ++ ) { 36293 36294 for ( let ix = 0; ix < widthSegments; ix ++ ) { 36295 36296 const a = grid[ iy ][ ix + 1 ]; 36297 const b = grid[ iy ][ ix ]; 36298 const c = grid[ iy + 1 ][ ix ]; 36299 const d = grid[ iy + 1 ][ ix + 1 ]; 36300 36301 if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d ); 36302 if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d ); 36303 36304 } 36305 36306 } 36307 36308 // build geometry 36309 36310 this.setIndex( indices ); 36311 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 36312 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 36313 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 36314 36315 } 36316 36317 copy( source ) { 36318 36319 super.copy( source ); 36320 36321 this.parameters = Object.assign( {}, source.parameters ); 36322 36323 return this; 36324 36325 } 36326 36327 /** 36328 * Factory method for creating an instance of this class from the given 36329 * JSON object. 36330 * 36331 * @param {Object} data - A JSON object representing the serialized geometry. 36332 * @return {SphereGeometry} A new instance. 36333 */ 36334 static fromJSON( data ) { 36335 36336 return new SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength ); 36337 36338 } 36339 36340} 36341 36342/** 36343 * A geometry class for representing an tetrahedron. 36344 * 36345 * ```js 36346 * const geometry = new THREE.TetrahedronGeometry(); 36347 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); 36348 * const tetrahedron = new THREE.Mesh( geometry, material ); 36349 * scene.add( tetrahedron ); 36350 * ``` 36351 * 36352 * @augments PolyhedronGeometry 36353 * @demo scenes/geometry-browser.html#TetrahedronGeometry 36354 */ 36355class TetrahedronGeometry extends PolyhedronGeometry { 36356 36357 /** 36358 * Constructs a new tetrahedron geometry. 36359 * 36360 * @param {number} [radius=1] - Radius of the tetrahedron. 36361 * @param {number} [detail=0] - Setting this to a value greater than `0` adds vertices making it no longer a tetrahedron. 36362 */ 36363 constructor( radius = 1, detail = 0 ) { 36364 36365 const vertices = [ 36366 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1 36367 ]; 36368 36369 const indices = [ 36370 2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1 36371 ]; 36372 36373 super( vertices, indices, radius, detail ); 36374 36375 this.type = 'TetrahedronGeometry'; 36376 36377 /** 36378 * Holds the constructor parameters that have been 36379 * used to generate the geometry. Any modification 36380 * after instantiation does not change the geometry. 36381 * 36382 * @type {Object} 36383 */ 36384 this.parameters = { 36385 radius: radius, 36386 detail: detail 36387 }; 36388 36389 } 36390 36391 /** 36392 * Factory method for creating an instance of this class from the given 36393 * JSON object. 36394 * 36395 * @param {Object} data - A JSON object representing the serialized geometry. 36396 * @return {TetrahedronGeometry} A new instance. 36397 */ 36398 static fromJSON( data ) { 36399 36400 return new TetrahedronGeometry( data.radius, data.detail ); 36401 36402 } 36403 36404} 36405 36406/** 36407 * A geometry class for representing an torus. 36408 * 36409 * ```js 36410 * const geometry = new THREE.TorusGeometry( 10, 3, 16, 100 ); 36411 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); 36412 * const torus = new THREE.Mesh( geometry, material ); 36413 * scene.add( torus ); 36414 * ``` 36415 * 36416 * @augments BufferGeometry 36417 * @demo scenes/geometry-browser.html#TorusGeometry 36418 */ 36419class TorusGeometry extends BufferGeometry { 36420 36421 /** 36422 * Constructs a new torus geometry. 36423 * 36424 * @param {number} [radius=1] - Radius of the torus, from the center of the torus to the center of the tube. 36425 * @param {number} [tube=0.4] - Radius of the tube. Must be smaller than `radius`. 36426 * @param {number} [radialSegments=12] - The number of radial segments. 36427 * @param {number} [tubularSegments=48] - The number of tubular segments. 36428 * @param {number} [arc=Math.PI*2] - Central angle in radians. 36429 * @param {number} [thetaStart=0] - Start of the tubular sweep in radians. 36430 * @param {number} [thetaLength=Math.PI*2] - Length of the tubular sweep in radians. 36431 */ 36432 constructor( radius = 1, tube = 0.4, radialSegments = 12, tubularSegments = 48, arc = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI * 2 ) { 36433 36434 super(); 36435 36436 this.type = 'TorusGeometry'; 36437 36438 /** 36439 * Holds the constructor parameters that have been 36440 * used to generate the geometry. Any modification 36441 * after instantiation does not change the geometry. 36442 * 36443 * @type {Object} 36444 */ 36445 this.parameters = { 36446 radius: radius, 36447 tube: tube, 36448 radialSegments: radialSegments, 36449 tubularSegments: tubularSegments, 36450 arc: arc, 36451 thetaStart: thetaStart, 36452 thetaLength: thetaLength, 36453 }; 36454 36455 radialSegments = Math.floor( radialSegments ); 36456 tubularSegments = Math.floor( tubularSegments ); 36457 36458 // buffers 36459 36460 const indices = []; 36461 const vertices = []; 36462 const normals = []; 36463 const uvs = []; 36464 36465 // helper variables 36466 36467 const center = new Vector3(); 36468 const vertex = new Vector3(); 36469 const normal = new Vector3(); 36470 36471 // generate vertices, normals and uvs 36472 36473 for ( let j = 0; j <= radialSegments; j ++ ) { 36474 36475 const v = thetaStart + ( j / radialSegments ) * thetaLength; 36476 36477 for ( let i = 0; i <= tubularSegments; i ++ ) { 36478 36479 const u = i / tubularSegments * arc; 36480 36481 // vertex 36482 36483 vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u ); 36484 vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u ); 36485 vertex.z = tube * Math.sin( v ); 36486 36487 vertices.push( vertex.x, vertex.y, vertex.z ); 36488 36489 // normal 36490 36491 center.x = radius * Math.cos( u ); 36492 center.y = radius * Math.sin( u ); 36493 normal.subVectors( vertex, center ).normalize(); 36494 36495 normals.push( normal.x, normal.y, normal.z ); 36496 36497 // uv 36498 36499 uvs.push( i / tubularSegments ); 36500 uvs.push( j / radialSegments ); 36501 36502 } 36503 36504 } 36505 36506 // generate indices 36507 36508 for ( let j = 1; j <= radialSegments; j ++ ) { 36509 36510 for ( let i = 1; i <= tubularSegments; i ++ ) { 36511 36512 // indices 36513 36514 const a = ( tubularSegments + 1 ) * j + i - 1; 36515 const b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1; 36516 const c = ( tubularSegments + 1 ) * ( j - 1 ) + i; 36517 const d = ( tubularSegments + 1 ) * j + i; 36518 36519 // faces 36520 36521 indices.push( a, b, d ); 36522 indices.push( b, c, d ); 36523 36524 } 36525 36526 } 36527 36528 // build geometry 36529 36530 this.setIndex( indices ); 36531 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 36532 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 36533 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 36534 36535 } 36536 36537 copy( source ) { 36538 36539 super.copy( source ); 36540 36541 this.parameters = Object.assign( {}, source.parameters ); 36542 36543 return this; 36544 36545 } 36546 36547 /** 36548 * Factory method for creating an instance of this class from the given 36549 * JSON object. 36550 * 36551 * @param {Object} data - A JSON object representing the serialized geometry. 36552 * @return {TorusGeometry} A new instance. 36553 */ 36554 static fromJSON( data ) { 36555 36556 return new TorusGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc ); 36557 36558 } 36559 36560} 36561 36562/** 36563 * Creates a torus knot, the particular shape of which is defined by a pair 36564 * of coprime integers, p and q. If p and q are not coprime, the result will 36565 * be a torus link. 36566 * 36567 * ```js 36568 * const geometry = new THREE.TorusKnotGeometry( 10, 3, 100, 16 ); 36569 * const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); 36570 * const torusKnot = new THREE.Mesh( geometry, material ); 36571 * scene.add( torusKnot ); 36572 * ``` 36573 * 36574 * @augments BufferGeometry 36575 * @demo scenes/geometry-browser.html#TorusKnotGeometry 36576 */ 36577class TorusKnotGeometry extends BufferGeometry { 36578 36579 /** 36580 * Constructs a new torus knot geometry. 36581 * 36582 * @param {number} [radius=1] - Radius of the torus knot. 36583 * @param {number} [tube=0.4] - Radius of the tube. 36584 * @param {number} [tubularSegments=64] - The number of tubular segments. 36585 * @param {number} [radialSegments=8] - The number of radial segments. 36586 * @param {number} [p=2] - This value determines, how many times the geometry winds around its axis of rotational symmetry. 36587 * @param {number} [q=3] - This value determines, how many times the geometry winds around a circle in the interior of the torus. 36588 */ 36589 constructor( radius = 1, tube = 0.4, tubularSegments = 64, radialSegments = 8, p = 2, q = 3 ) { 36590 36591 super(); 36592 36593 this.type = 'TorusKnotGeometry'; 36594 36595 /** 36596 * Holds the constructor parameters that have been 36597 * used to generate the geometry. Any modification 36598 * after instantiation does not change the geometry. 36599 * 36600 * @type {Object} 36601 */ 36602 this.parameters = { 36603 radius: radius, 36604 tube: tube, 36605 tubularSegments: tubularSegments, 36606 radialSegments: radialSegments, 36607 p: p, 36608 q: q 36609 }; 36610 36611 tubularSegments = Math.floor( tubularSegments ); 36612 radialSegments = Math.floor( radialSegments ); 36613 36614 // buffers 36615 36616 const indices = []; 36617 const vertices = []; 36618 const normals = []; 36619 const uvs = []; 36620 36621 // helper variables 36622 36623 const vertex = new Vector3(); 36624 const normal = new Vector3(); 36625 36626 const P1 = new Vector3(); 36627 const P2 = new Vector3(); 36628 36629 const B = new Vector3(); 36630 const T = new Vector3(); 36631 const N = new Vector3(); 36632 36633 // generate vertices, normals and uvs 36634 36635 for ( let i = 0; i <= tubularSegments; ++ i ) { 36636 36637 // the radian "u" is used to calculate the position on the torus curve of the current tubular segment 36638 36639 const u = i / tubularSegments * p * Math.PI * 2; 36640 36641 // now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead. 36642 // these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions 36643 36644 calculatePositionOnCurve( u, p, q, radius, P1 ); 36645 calculatePositionOnCurve( u + 0.01, p, q, radius, P2 ); 36646 36647 // calculate orthonormal basis 36648 36649 T.subVectors( P2, P1 ); 36650 N.addVectors( P2, P1 ); 36651 B.crossVectors( T, N ); 36652 N.crossVectors( B, T ); 36653 36654 // normalize B, N. T can be ignored, we don't use it 36655 36656 B.normalize(); 36657 N.normalize(); 36658 36659 for ( let j = 0; j <= radialSegments; ++ j ) { 36660 36661 // now calculate the vertices. they are nothing more than an extrusion of the torus curve. 36662 // because we extrude a shape in the xy-plane, there is no need to calculate a z-value. 36663 36664 const v = j / radialSegments * Math.PI * 2; 36665 const cx = - tube * Math.cos( v ); 36666 const cy = tube * Math.sin( v ); 36667 36668 // now calculate the final vertex position. 36669 // first we orient the extrusion with our basis vectors, then we add it to the current position on the curve 36670 36671 vertex.x = P1.x + ( cx * N.x + cy * B.x ); 36672 vertex.y = P1.y + ( cx * N.y + cy * B.y ); 36673 vertex.z = P1.z + ( cx * N.z + cy * B.z ); 36674 36675 vertices.push( vertex.x, vertex.y, vertex.z ); 36676 36677 // normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal) 36678 36679 normal.subVectors( vertex, P1 ).normalize(); 36680 36681 normals.push( normal.x, normal.y, normal.z ); 36682 36683 // uv 36684 36685 uvs.push( i / tubularSegments ); 36686 uvs.push( j / radialSegments ); 36687 36688 } 36689 36690 } 36691 36692 // generate indices 36693 36694 for ( let j = 1; j <= tubularSegments; j ++ ) { 36695 36696 for ( let i = 1; i <= radialSegments; i ++ ) { 36697 36698 // indices 36699 36700 const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); 36701 const b = ( radialSegments + 1 ) * j + ( i - 1 ); 36702 const c = ( radialSegments + 1 ) * j + i; 36703 const d = ( radialSegments + 1 ) * ( j - 1 ) + i; 36704 36705 // faces 36706 36707 indices.push( a, b, d ); 36708 indices.push( b, c, d ); 36709 36710 } 36711 36712 } 36713 36714 // build geometry 36715 36716 this.setIndex( indices ); 36717 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 36718 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 36719 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 36720 36721 // this function calculates the current position on the torus curve 36722 36723 function calculatePositionOnCurve( u, p, q, radius, position ) { 36724 36725 const cu = Math.cos( u ); 36726 const su = Math.sin( u ); 36727 const quOverP = q / p * u; 36728 const cs = Math.cos( quOverP ); 36729 36730 position.x = radius * ( 2 + cs ) * 0.5 * cu; 36731 position.y = radius * ( 2 + cs ) * su * 0.5; 36732 position.z = radius * Math.sin( quOverP ) * 0.5; 36733 36734 } 36735 36736 } 36737 36738 copy( source ) { 36739 36740 super.copy( source ); 36741 36742 this.parameters = Object.assign( {}, source.parameters ); 36743 36744 return this; 36745 36746 } 36747 36748 /** 36749 * Factory method for creating an instance of this class from the given 36750 * JSON object. 36751 * 36752 * @param {Object} data - A JSON object representing the serialized geometry. 36753 * @return {TorusKnotGeometry} A new instance. 36754 */ 36755 static fromJSON( data ) { 36756 36757 return new TorusKnotGeometry( data.radius, data.tube, data.tubularSegments, data.radialSegments, data.p, data.q ); 36758 36759 } 36760 36761} 36762 36763/** 36764 * Creates a tube that extrudes along a 3D curve. 36765 * 36766 * ```js 36767 * class CustomSinCurve extends THREE.Curve { 36768 * 36769 * getPoint( t, optionalTarget = new THREE.Vector3() ) { 36770 * 36771 * const tx = t * 3 - 1.5; 36772 * const ty = Math.sin( 2 * Math.PI * t ); 36773 * const tz = 0; 36774 * 36775 * return optionalTarget.set( tx, ty, tz ); 36776 * } 36777 * 36778 * } 36779 * 36780 * const path = new CustomSinCurve( 10 ); 36781 * const geometry = new THREE.TubeGeometry( path, 20, 2, 8, false ); 36782 * const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); 36783 * const mesh = new THREE.Mesh( geometry, material ); 36784 * scene.add( mesh ); 36785 * ``` 36786 * 36787 * @augments BufferGeometry 36788 * @demo scenes/geometry-browser.html#TubeGeometry 36789 */ 36790class TubeGeometry extends BufferGeometry { 36791 36792 /** 36793 * Constructs a new tube geometry. 36794 * 36795 * @param {Curve} [path=QuadraticBezierCurve3] - A 3D curve defining the path of the tube. 36796 * @param {number} [tubularSegments=64] - The number of segments that make up the tube. 36797 * @param {number} [radius=1] -The radius of the tube. 36798 * @param {number} [radialSegments=8] - The number of segments that make up the cross-section. 36799 * @param {boolean} [closed=false] - Whether the tube is closed or not. 36800 */ 36801 constructor( path = new QuadraticBezierCurve3( new Vector3( -1, -1, 0 ), new Vector3( -1, 1, 0 ), new Vector3( 1, 1, 0 ) ), tubularSegments = 64, radius = 1, radialSegments = 8, closed = false ) { 36802 36803 super(); 36804 36805 this.type = 'TubeGeometry'; 36806 36807 /** 36808 * Holds the constructor parameters that have been 36809 * used to generate the geometry. Any modification 36810 * after instantiation does not change the geometry. 36811 * 36812 * @type {Object} 36813 */ 36814 this.parameters = { 36815 path: path, 36816 tubularSegments: tubularSegments, 36817 radius: radius, 36818 radialSegments: radialSegments, 36819 closed: closed 36820 }; 36821 36822 const frames = path.computeFrenetFrames( tubularSegments, closed ); 36823 36824 // expose internals 36825 36826 this.tangents = frames.tangents; 36827 this.normals = frames.normals; 36828 this.binormals = frames.binormals; 36829 36830 // helper variables 36831 36832 const vertex = new Vector3(); 36833 const normal = new Vector3(); 36834 const uv = new Vector2(); 36835 let P = new Vector3(); 36836 36837 // buffer 36838 36839 const vertices = []; 36840 const normals = []; 36841 const uvs = []; 36842 const indices = []; 36843 36844 // create buffer data 36845 36846 generateBufferData(); 36847 36848 // build geometry 36849 36850 this.setIndex( indices ); 36851 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 36852 this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); 36853 this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); 36854 36855 // functions 36856 36857 function generateBufferData() { 36858 36859 for ( let i = 0; i < tubularSegments; i ++ ) { 36860 36861 generateSegment( i ); 36862 36863 } 36864 36865 // if the geometry is not closed, generate the last row of vertices and normals 36866 // at the regular position on the given path 36867 // 36868 // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ) 36869 36870 generateSegment( ( closed === false ) ? tubularSegments : 0 ); 36871 36872 // uvs are generated in a separate function. 36873 // this makes it easy compute correct values for closed geometries 36874 36875 generateUVs(); 36876 36877 // finally create faces 36878 36879 generateIndices(); 36880 36881 } 36882 36883 function generateSegment( i ) { 36884 36885 // we use getPointAt to sample evenly distributed points from the given path 36886 36887 P = path.getPointAt( i / tubularSegments, P ); 36888 36889 // retrieve corresponding normal and binormal 36890 36891 const N = frames.normals[ i ]; 36892 const B = frames.binormals[ i ]; 36893 36894 // generate normals and vertices for the current segment 36895 36896 for ( let j = 0; j <= radialSegments; j ++ ) { 36897 36898 const v = j / radialSegments * Math.PI * 2; 36899 36900 const sin = Math.sin( v ); 36901 const cos = - Math.cos( v ); 36902 36903 // normal 36904 36905 normal.x = ( cos * N.x + sin * B.x ); 36906 normal.y = ( cos * N.y + sin * B.y ); 36907 normal.z = ( cos * N.z + sin * B.z ); 36908 normal.normalize(); 36909 36910 normals.push( normal.x, normal.y, normal.z ); 36911 36912 // vertex 36913 36914 vertex.x = P.x + radius * normal.x; 36915 vertex.y = P.y + radius * normal.y; 36916 vertex.z = P.z + radius * normal.z; 36917 36918 vertices.push( vertex.x, vertex.y, vertex.z ); 36919 36920 } 36921 36922 } 36923 36924 function generateIndices() { 36925 36926 for ( let j = 1; j <= tubularSegments; j ++ ) { 36927 36928 for ( let i = 1; i <= radialSegments; i ++ ) { 36929 36930 const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 ); 36931 const b = ( radialSegments + 1 ) * j + ( i - 1 ); 36932 const c = ( radialSegments + 1 ) * j + i; 36933 const d = ( radialSegments + 1 ) * ( j - 1 ) + i; 36934 36935 // faces 36936 36937 indices.push( a, b, d ); 36938 indices.push( b, c, d ); 36939 36940 } 36941 36942 } 36943 36944 } 36945 36946 function generateUVs() { 36947 36948 for ( let i = 0; i <= tubularSegments; i ++ ) { 36949 36950 for ( let j = 0; j <= radialSegments; j ++ ) { 36951 36952 uv.x = i / tubularSegments; 36953 uv.y = j / radialSegments; 36954 36955 uvs.push( uv.x, uv.y ); 36956 36957 } 36958 36959 } 36960 36961 } 36962 36963 } 36964 36965 copy( source ) { 36966 36967 super.copy( source ); 36968 36969 this.parameters = Object.assign( {}, source.parameters ); 36970 36971 return this; 36972 36973 } 36974 36975 toJSON() { 36976 36977 const data = super.toJSON(); 36978 36979 data.path = this.parameters.path.toJSON(); 36980 36981 return data; 36982 36983 } 36984 36985 /** 36986 * Factory method for creating an instance of this class from the given 36987 * JSON object. 36988 * 36989 * @param {Object} data - A JSON object representing the serialized geometry. 36990 * @return {TubeGeometry} A new instance. 36991 */ 36992 static fromJSON( data ) { 36993 36994 // This only works for built-in curves (e.g. CatmullRomCurve3). 36995 // User defined curves or instances of CurvePath will not be deserialized. 36996 return new TubeGeometry( 36997 new Curves[ data.path.type ]().fromJSON( data.path ), 36998 data.tubularSegments, 36999 data.radius, 37000 data.radialSegments, 37001 data.closed 37002 ); 37003 37004 } 37005 37006} 37007 37008/** 37009 * Can be used as a helper object to visualize a geometry as a wireframe. 37010 * 37011 * ```js 37012 * const geometry = new THREE.SphereGeometry(); 37013 * 37014 * const wireframe = new THREE.WireframeGeometry( geometry ); 37015 * 37016 * const line = new THREE.LineSegments( wireframe ); 37017 * line.material.depthWrite = false; 37018 * line.material.opacity = 0.25; 37019 * line.material.transparent = true; 37020 * 37021 * scene.add( line ); 37022 * ``` 37023 * 37024 * Note: It is not yet possible to serialize/deserialize instances of this class. 37025 * 37026 * @augments BufferGeometry 37027 */ 37028class WireframeGeometry extends BufferGeometry { 37029 37030 /** 37031 * Constructs a new wireframe geometry. 37032 * 37033 * @param {?BufferGeometry} [geometry=null] - The geometry. 37034 */ 37035 constructor( geometry = null ) { 37036 37037 super(); 37038 37039 this.type = 'WireframeGeometry'; 37040 37041 /** 37042 * Holds the constructor parameters that have been 37043 * used to generate the geometry. Any modification 37044 * after instantiation does not change the geometry. 37045 * 37046 * @type {Object} 37047 */ 37048 this.parameters = { 37049 geometry: geometry 37050 }; 37051 37052 if ( geometry !== null ) { 37053 37054 // buffer 37055 37056 const vertices = []; 37057 const edges = new Set(); 37058 37059 // helper variables 37060 37061 const start = new Vector3(); 37062 const end = new Vector3(); 37063 37064 if ( geometry.index !== null ) { 37065 37066 // indexed BufferGeometry 37067 37068 const position = geometry.attributes.position; 37069 const indices = geometry.index; 37070 let groups = geometry.groups; 37071 37072 if ( groups.length === 0 ) { 37073 37074 groups = [ { start: 0, count: indices.count, materialIndex: 0 } ]; 37075 37076 } 37077 37078 // create a data structure that contains all edges without duplicates 37079 37080 for ( let o = 0, ol = groups.length; o < ol; ++ o ) { 37081 37082 const group = groups[ o ]; 37083 37084 const groupStart = group.start; 37085 const groupCount = group.count; 37086 37087 for ( let i = groupStart, l = ( groupStart + groupCount ); i < l; i += 3 ) { 37088 37089 for ( let j = 0; j < 3; j ++ ) { 37090 37091 const index1 = indices.getX( i + j ); 37092 const index2 = indices.getX( i + ( j + 1 ) % 3 ); 37093 37094 start.fromBufferAttribute( position, index1 ); 37095 end.fromBufferAttribute( position, index2 ); 37096 37097 if ( isUniqueEdge( start, end, edges ) === true ) { 37098 37099 vertices.push( start.x, start.y, start.z ); 37100 vertices.push( end.x, end.y, end.z ); 37101 37102 } 37103 37104 } 37105 37106 } 37107 37108 } 37109 37110 } else { 37111 37112 // non-indexed BufferGeometry 37113 37114 const position = geometry.attributes.position; 37115 37116 for ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) { 37117 37118 for ( let j = 0; j < 3; j ++ ) { 37119 37120 // three edges per triangle, an edge is represented as (index1, index2) 37121 // e.g. the first triangle has the following edges: (0,1),(1,2),(2,0) 37122 37123 const index1 = 3 * i + j; 37124 const index2 = 3 * i + ( ( j + 1 ) % 3 ); 37125 37126 start.fromBufferAttribute( position, index1 ); 37127 end.fromBufferAttribute( position, index2 ); 37128 37129 if ( isUniqueEdge( start, end, edges ) === true ) { 37130 37131 vertices.push( start.x, start.y, start.z ); 37132 vertices.push( end.x, end.y, end.z ); 37133 37134 } 37135 37136 } 37137 37138 } 37139 37140 } 37141 37142 // build geometry 37143 37144 this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 37145 37146 } 37147 37148 } 37149 37150 copy( source ) { 37151 37152 super.copy( source ); 37153 37154 this.parameters = Object.assign( {}, source.parameters ); 37155 37156 return this; 37157 37158 } 37159 37160} 37161 37162function isUniqueEdge( start, end, edges ) { 37163 37164 const hash1 = `${start.x},${start.y},${start.z}-${end.x},${end.y},${end.z}`; 37165 const hash2 = `${end.x},${end.y},${end.z}-${start.x},${start.y},${start.z}`; // coincident edge 37166 37167 if ( edges.has( hash1 ) === true || edges.has( hash2 ) === true ) { 37168 37169 return false; 37170 37171 } else { 37172 37173 edges.add( hash1 ); 37174 edges.add( hash2 ); 37175 return true; 37176 37177 } 37178 37179} 37180 37181var Geometries = /*#__PURE__*/Object.freeze({ 37182 __proto__: null, 37183 BoxGeometry: BoxGeometry, 37184 CapsuleGeometry: CapsuleGeometry, 37185 CircleGeometry: CircleGeometry, 37186 ConeGeometry: ConeGeometry, 37187 CylinderGeometry: CylinderGeometry, 37188 DodecahedronGeometry: DodecahedronGeometry, 37189 EdgesGeometry: EdgesGeometry, 37190 ExtrudeGeometry: ExtrudeGeometry, 37191 IcosahedronGeometry: IcosahedronGeometry, 37192 LatheGeometry: LatheGeometry, 37193 OctahedronGeometry: OctahedronGeometry, 37194 PlaneGeometry: PlaneGeometry, 37195 PolyhedronGeometry: PolyhedronGeometry, 37196 RingGeometry: RingGeometry, 37197 ShapeGeometry: ShapeGeometry, 37198 SphereGeometry: SphereGeometry, 37199 TetrahedronGeometry: TetrahedronGeometry, 37200 TorusGeometry: TorusGeometry, 37201 TorusKnotGeometry: TorusKnotGeometry, 37202 TubeGeometry: TubeGeometry, 37203 WireframeGeometry: WireframeGeometry 37204}); 37205 37206/** 37207 * This material can receive shadows, but otherwise is completely transparent. 37208 * 37209 * ```js 37210 * const geometry = new THREE.PlaneGeometry( 2000, 2000 ); 37211 * geometry.rotateX( - Math.PI / 2 ); 37212 * 37213 * const material = new THREE.ShadowMaterial(); 37214 * material.opacity = 0.2; 37215 * 37216 * const plane = new THREE.Mesh( geometry, material ); 37217 * plane.position.y = -200; 37218 * plane.receiveShadow = true; 37219 * scene.add( plane ); 37220 * ``` 37221 * 37222 * @augments Material 37223 */ 37224class ShadowMaterial extends Material { 37225 37226 /** 37227 * Constructs a new shadow material. 37228 * 37229 * @param {Object} [parameters] - An object with one or more properties 37230 * defining the material's appearance. Any property of the material 37231 * (including any property from inherited materials) can be passed 37232 * in here. Color values can be passed any type of value accepted 37233 * by {@link Color#set}. 37234 */ 37235 constructor( parameters ) { 37236 37237 super(); 37238 37239 /** 37240 * This flag can be used for type testing. 37241 * 37242 * @type {boolean} 37243 * @readonly 37244 * @default true 37245 */ 37246 this.isShadowMaterial = true; 37247 37248 this.type = 'ShadowMaterial'; 37249 37250 /** 37251 * Color of the material. 37252 * 37253 * @type {Color} 37254 * @default (0,0,0) 37255 */ 37256 this.color = new Color( 0x000000 ); 37257 37258 /** 37259 * Overwritten since shadow materials are transparent 37260 * by default. 37261 * 37262 * @type {boolean} 37263 * @default true 37264 */ 37265 this.transparent = true; 37266 37267 /** 37268 * Whether the material is affected by fog or not. 37269 * 37270 * @type {boolean} 37271 * @default true 37272 */ 37273 this.fog = true; 37274 37275 this.setValues( parameters ); 37276 37277 } 37278 37279 copy( source ) { 37280 37281 super.copy( source ); 37282 37283 this.color.copy( source.color ); 37284 37285 this.fog = source.fog; 37286 37287 return this; 37288 37289 } 37290 37291} 37292 37293/** 37294 * Provides utility functions for managing uniforms. 37295 * 37296 * @module UniformsUtils 37297 */ 37298 37299/** 37300 * Clones the given uniform definitions by performing a deep-copy. That means 37301 * if the value of a uniform refers to an object like a Vector3 or Texture, 37302 * the cloned uniform will refer to a new object reference. 37303 * 37304 * @param {Object} src - An object representing uniform definitions. 37305 * @return {Object} The cloned uniforms. 37306 */ 37307function cloneUniforms( src ) { 37308 37309 const dst = {}; 37310 37311 for ( const u in src ) { 37312 37313 dst[ u ] = {}; 37314 37315 for ( const p in src[ u ] ) { 37316 37317 const property = src[ u ][ p ]; 37318 37319 if ( isThreeObject( property ) ) { 37320 37321 if ( property.isRenderTargetTexture ) { 37322 37323 warn( 'UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().' ); 37324 dst[ u ][ p ] = null; 37325 37326 } else { 37327 37328 dst[ u ][ p ] = property.clone(); 37329 37330 } 37331 37332 } else if ( Array.isArray( property ) ) { 37333 37334 if ( isThreeObject( property[ 0 ] ) ) { 37335 37336 const clonedProperty = []; 37337 37338 for ( let i = 0, l = property.length; i < l; i ++ ) { 37339 37340 clonedProperty[ i ] = property[ i ].clone(); 37341 37342 } 37343 37344 dst[ u ][ p ] = clonedProperty; 37345 37346 } else { 37347 37348 dst[ u ][ p ] = property.slice(); 37349 37350 } 37351 37352 } else { 37353 37354 dst[ u ][ p ] = property; 37355 37356 } 37357 37358 } 37359 37360 } 37361 37362 return dst; 37363 37364} 37365 37366/** 37367 * Merges the given uniform definitions into a single object. Since the 37368 * method internally uses cloneUniforms(), it performs a deep-copy when 37369 * producing the merged uniform definitions. 37370 * 37371 * @param {Array} uniforms - An array of objects containing uniform definitions. 37372 * @return {Object} The merged uniforms. 37373 */ 37374function mergeUniforms( uniforms ) { 37375 37376 const merged = {}; 37377 37378 for ( let u = 0; u < uniforms.length; u ++ ) { 37379 37380 const tmp = cloneUniforms( uniforms[ u ] ); 37381 37382 for ( const p in tmp ) { 37383 37384 merged[ p ] = tmp[ p ]; 37385 37386 } 37387 37388 } 37389 37390 return merged; 37391 37392} 37393 37394function isThreeObject( property ) { 37395 37396 return ( property && ( property.isColor || 37397 property.isMatrix3 || property.isMatrix4 || 37398 property.isVector2 || property.isVector3 || property.isVector4 || 37399 property.isTexture || property.isQuaternion ) ); 37400 37401} 37402 37403function cloneUniformsGroups( src ) { 37404 37405 const dst = []; 37406 37407 for ( let u = 0; u < src.length; u ++ ) { 37408 37409 dst.push( src[ u ].clone() ); 37410 37411 } 37412 37413 return dst; 37414 37415} 37416 37417function getUnlitUniformColorSpace( renderer ) { 37418 37419 const currentRenderTarget = renderer.getRenderTarget(); 37420 37421 if ( currentRenderTarget === null ) { 37422 37423 // https://github.com/mrdoob/three.js/pull/23937#issuecomment-1111067398 37424 return renderer.outputColorSpace; 37425 37426 } 37427 37428 // https://github.com/mrdoob/three.js/issues/27868 37429 if ( currentRenderTarget.isXRRenderTarget === true ) { 37430 37431 return currentRenderTarget.texture.colorSpace; 37432 37433 } 37434 37435 return ColorManagement.workingColorSpace; 37436 37437} 37438 37439// Legacy 37440 37441const UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms }; 37442 37443var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}"; 37444 37445var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}"; 37446 37447/** 37448 * A material rendered with custom shaders. A shader is a small program written in GLSL. 37449 * that runs on the GPU. You may want to use a custom shader if you need to implement an 37450 * effect not included with any of the built-in materials. 37451 * 37452 * There are the following notes to bear in mind when using a `ShaderMaterial`: 37453 * 37454 * - `ShaderMaterial` can only be used with {@link WebGLRenderer}. 37455 * - Built in attributes and uniforms are passed to the shaders along with your code. If 37456 * you don't want that, use {@link RawShaderMaterial} instead. 37457 * - You can use the directive `#pragma unroll_loop_start` and `#pragma unroll_loop_end` 37458 * in order to unroll a `for` loop in GLSL by the shader preprocessor. The directive has 37459 * to be placed right above the loop. The loop formatting has to correspond to a defined standard. 37460 * - The loop has to be [normalized](https://en.wikipedia.org/wiki/Normalized_loop). 37461 * - The loop variable has to be *i*. 37462 * - The value `UNROLLED_LOOP_INDEX` will be replaced with the explicitly 37463 * value of *i* for the given iteration and can be used in preprocessor 37464 * statements. 37465 * 37466 * ```js 37467 * const material = new THREE.ShaderMaterial( { 37468 * uniforms: { 37469 * time: { value: 1.0 }, 37470 * resolution: { value: new THREE.Vector2() } 37471 * }, 37472 * vertexShader: document.getElementById( 'vertexShader' ).textContent, 37473 * fragmentShader: document.getElementById( 'fragmentShader' ).textContent 37474 * } ); 37475 * ``` 37476 * 37477 * @augments Material 37478 */ 37479class ShaderMaterial extends Material { 37480 37481 /** 37482 * Constructs a new shader material. 37483 * 37484 * @param {Object} [parameters] - An object with one or more properties 37485 * defining the material's appearance. Any property of the material 37486 * (including any property from inherited materials) can be passed 37487 * in here. Color values can be passed any type of value accepted 37488 * by {@link Color#set}. 37489 */ 37490 constructor( parameters ) { 37491 37492 super(); 37493 37494 /** 37495 * This flag can be used for type testing. 37496 * 37497 * @type {boolean} 37498 * @readonly 37499 * @default true 37500 */ 37501 this.isShaderMaterial = true; 37502 37503 this.type = 'ShaderMaterial'; 37504 37505 /** 37506 * Defines custom constants using `#define` directives within the GLSL code 37507 * for both the vertex shader and the fragment shader; each key/value pair 37508 * yields another directive. 37509 * ```js 37510 * defines: { 37511 * FOO: 15, 37512 * BAR: true 37513 * } 37514 * ``` 37515 * Yields the lines: 37516 * ``` 37517 * #define FOO 15 37518 * #define BAR true 37519 * ``` 37520 * 37521 * @type {Object} 37522 */ 37523 this.defines = {}; 37524 37525 /** 37526 * An object of the form: 37527 * ```js 37528 * { 37529 * "uniform1": { value: 1.0 }, 37530 * "uniform2": { value: 2 } 37531 * } 37532 * ``` 37533 * specifying the uniforms to be passed to the shader code; keys are uniform 37534 * names, values are definitions of the form 37535 * ``` 37536 * { 37537 * value: 1.0 37538 * } 37539 * ``` 37540 * where `value` is the value of the uniform. Names must match the name of 37541 * the uniform, as defined in the GLSL code. Note that uniforms are refreshed 37542 * on every frame, so updating the value of the uniform will immediately 37543 * update the value available to the GLSL code. 37544 * 37545 * @type {Object} 37546 */ 37547 this.uniforms = {}; 37548 37549 /** 37550 * An array holding uniforms groups for configuring UBOs. 37551 * 37552 * @type {Array<UniformsGroup>} 37553 */ 37554 this.uniformsGroups = []; 37555 37556 /** 37557 * Vertex shader GLSL code. This is the actual code for the shader. 37558 * 37559 * @type {string} 37560 */ 37561 this.vertexShader = default_vertex; 37562 37563 /** 37564 * Fragment shader GLSL code. This is the actual code for the shader. 37565 * 37566 * @type {string} 37567 */ 37568 this.fragmentShader = default_fragment; 37569 37570 /** 37571 * Controls line thickness or lines. 37572 * 37573 * WebGL and WebGPU ignore this setting and always render line primitives with a 37574 * width of one pixel. 37575 * 37576 * @type {number} 37577 * @default 1 37578 */ 37579 this.linewidth = 1; 37580 37581 /** 37582 * Renders the geometry as a wireframe. 37583 * 37584 * @type {boolean} 37585 * @default false 37586 */ 37587 this.wireframe = false; 37588 37589 /** 37590 * Controls the thickness of the wireframe. 37591 * 37592 * WebGL and WebGPU ignore this property and always render 37593 * 1 pixel wide lines. 37594 * 37595 * @type {number} 37596 * @default 1 37597 */ 37598 this.wireframeLinewidth = 1; 37599 37600 /** 37601 * Defines whether the material color is affected by global fog settings; `true` 37602 * to pass fog uniforms to the shader. 37603 * 37604 * Setting this property to `true` requires the definition of fog uniforms. It is 37605 * recommended to use `UniformsUtils.merge()` to combine the custom shader uniforms 37606 * with predefined fog uniforms. 37607 * 37608 * ```js 37609 * const material = new ShaderMaterial( { 37610 * uniforms: UniformsUtils.merge( [ UniformsLib[ 'fog' ], shaderUniforms ] ); 37611 * vertexShader: vertexShader, 37612 * fragmentShader: fragmentShader, 37613 * fog: true 37614 * } ); 37615 * ``` 37616 * 37617 * @type {boolean} 37618 * @default false 37619 */ 37620 this.fog = false; 37621 37622 /** 37623 * Defines whether this material uses lighting; `true` to pass uniform data 37624 * related to lighting to this shader. 37625 * 37626 * @type {boolean} 37627 * @default false 37628 */ 37629 this.lights = false; 37630 37631 /** 37632 * Defines whether this material supports clipping; `true` to let the renderer 37633 * pass the clippingPlanes uniform. 37634 * 37635 * @type {boolean} 37636 * @default false 37637 */ 37638 this.clipping = false; 37639 37640 /** 37641 * Overwritten and set to `true` by default. 37642 * 37643 * @type {boolean} 37644 * @default true 37645 */ 37646 this.forceSinglePass = true; 37647 37648 /** 37649 * This object allows to enable certain WebGL 2 extensions. 37650 * 37651 * - clipCullDistance: set to `true` to use vertex shader clipping 37652 * - multiDraw: set to `true` to use vertex shader multi_draw / enable gl_DrawID 37653 * 37654 * @type {{clipCullDistance:false,multiDraw:false}} 37655 */ 37656 this.extensions = { 37657 clipCullDistance: false, // set to use vertex shader clipping 37658 multiDraw: false // set to use vertex shader multi_draw / enable gl_DrawID 37659 }; 37660 37661 /** 37662 * When the rendered geometry doesn't include these attributes but the 37663 * material does, these default values will be passed to the shaders. This 37664 * avoids errors when buffer data is missing. 37665 * 37666 * - color: [ 1, 1, 1 ] 37667 * - uv: [ 0, 0 ] 37668 * - uv1: [ 0, 0 ] 37669 * 37670 * @type {Object} 37671 */ 37672 this.defaultAttributeValues = { 37673 'color': [ 1, 1, 1 ], 37674 'uv': [ 0, 0 ], 37675 'uv1': [ 0, 0 ] 37676 }; 37677 37678 /** 37679 * If set, this calls [gl.bindAttribLocation](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/bindAttribLocation) 37680 * to bind a generic vertex index to an attribute variable. 37681 * 37682 * @type {string|undefined} 37683 * @default undefined 37684 */ 37685 this.index0AttributeName = undefined; 37686 37687 /** 37688 * Can be used to force a uniform update while changing uniforms in 37689 * {@link Object3D#onBeforeRender}. 37690 * 37691 * @type {boolean} 37692 * @default false 37693 */ 37694 this.uniformsNeedUpdate = false;
vendor: 28,443 bytes, lines 37695-38830
37695 37696 /** 37697 * Defines the GLSL version of custom shader code. 37698 * 37699 * @type {?(GLSL1|GLSL3)} 37700 * @default null 37701 */ 37702 this.glslVersion = null; 37703 37704 if ( parameters !== undefined ) { 37705 37706 this.setValues( parameters ); 37707 37708 } 37709 37710 } 37711 37712 copy( source ) { 37713 37714 super.copy( source ); 37715 37716 this.fragmentShader = source.fragmentShader; 37717 this.vertexShader = source.vertexShader; 37718 37719 this.uniforms = cloneUniforms( source.uniforms ); 37720 this.uniformsGroups = cloneUniformsGroups( source.uniformsGroups ); 37721 37722 this.defines = Object.assign( {}, source.defines ); 37723 37724 this.wireframe = source.wireframe; 37725 this.wireframeLinewidth = source.wireframeLinewidth; 37726 37727 this.fog = source.fog; 37728 this.lights = source.lights; 37729 this.clipping = source.clipping; 37730 37731 this.extensions = Object.assign( {}, source.extensions ); 37732 37733 this.glslVersion = source.glslVersion; 37734 37735 this.defaultAttributeValues = Object.assign( {}, source.defaultAttributeValues ); 37736 37737 this.index0AttributeName = source.index0AttributeName; 37738 37739 this.uniformsNeedUpdate = source.uniformsNeedUpdate; 37740 37741 return this; 37742 37743 } 37744 37745 toJSON( meta ) { 37746 37747 const data = super.toJSON( meta ); 37748 37749 data.glslVersion = this.glslVersion; 37750 data.uniforms = {}; 37751 37752 for ( const name in this.uniforms ) { 37753 37754 const uniform = this.uniforms[ name ]; 37755 const value = uniform.value; 37756 37757 if ( value && value.isTexture ) { 37758 37759 data.uniforms[ name ] = { 37760 type: 't', 37761 value: value.toJSON( meta ).uuid 37762 }; 37763 37764 } else if ( value && value.isColor ) { 37765 37766 data.uniforms[ name ] = { 37767 type: 'c', 37768 value: value.getHex() 37769 }; 37770 37771 } else if ( value && value.isVector2 ) { 37772 37773 data.uniforms[ name ] = { 37774 type: 'v2', 37775 value: value.toArray() 37776 }; 37777 37778 } else if ( value && value.isVector3 ) { 37779 37780 data.uniforms[ name ] = { 37781 type: 'v3', 37782 value: value.toArray() 37783 }; 37784 37785 } else if ( value && value.isVector4 ) { 37786 37787 data.uniforms[ name ] = { 37788 type: 'v4', 37789 value: value.toArray() 37790 }; 37791 37792 } else if ( value && value.isMatrix3 ) { 37793 37794 data.uniforms[ name ] = { 37795 type: 'm3', 37796 value: value.toArray() 37797 }; 37798 37799 } else if ( value && value.isMatrix4 ) { 37800 37801 data.uniforms[ name ] = { 37802 type: 'm4', 37803 value: value.toArray() 37804 }; 37805 37806 } else { 37807 37808 data.uniforms[ name ] = { 37809 value: value 37810 }; 37811 37812 // note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far 37813 37814 } 37815 37816 } 37817 37818 if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines; 37819 37820 data.vertexShader = this.vertexShader; 37821 data.fragmentShader = this.fragmentShader; 37822 37823 data.lights = this.lights; 37824 data.clipping = this.clipping; 37825 37826 const extensions = {}; 37827 37828 for ( const key in this.extensions ) { 37829 37830 if ( this.extensions[ key ] === true ) extensions[ key ] = true; 37831 37832 } 37833 37834 if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions; 37835 37836 return data; 37837 37838 } 37839 37840} 37841 37842/** 37843 * This class works just like {@link ShaderMaterial}, except that definitions 37844 * of built-in uniforms and attributes are not automatically prepended to the 37845 * GLSL shader code. 37846 * 37847 * `RawShaderMaterial` can only be used with {@link WebGLRenderer}. 37848 * 37849 * @augments ShaderMaterial 37850 */ 37851class RawShaderMaterial extends ShaderMaterial { 37852 37853 /** 37854 * Constructs a new raw shader material. 37855 * 37856 * @param {Object} [parameters] - An object with one or more properties 37857 * defining the material's appearance. Any property of the material 37858 * (including any property from inherited materials) can be passed 37859 * in here. Color values can be passed any type of value accepted 37860 * by {@link Color#set}. 37861 */ 37862 constructor( parameters ) { 37863 37864 super( parameters ); 37865 37866 /** 37867 * This flag can be used for type testing. 37868 * 37869 * @type {boolean} 37870 * @readonly 37871 * @default true 37872 */ 37873 this.isRawShaderMaterial = true; 37874 37875 this.type = 'RawShaderMaterial'; 37876 37877 } 37878 37879} 37880 37881/** 37882 * A standard physically based material, using Metallic-Roughness workflow. 37883 * 37884 * Physically based rendering (PBR) has recently become the standard in many 37885 * 3D applications, such as [Unity](https://blogs.unity3d.com/2014/10/29/physically-based-shading-in-unity-5-a-primer/), 37886 * [Unreal](https://docs.unrealengine.com/latest/INT/Engine/Rendering/Materials/PhysicallyBased/) and 37887 * [3D Studio Max](http://area.autodesk.com/blogs/the-3ds-max-blog/what039s-new-for-rendering-in-3ds-max-2017). 37888 * 37889 * This approach differs from older approaches in that instead of using 37890 * approximations for the way in which light interacts with a surface, a 37891 * physically correct model is used. The idea is that, instead of tweaking 37892 * materials to look good under specific lighting, a material can be created 37893 * that will react 'correctly' under all lighting scenarios. 37894 * 37895 * In practice this gives a more accurate and realistic looking result than 37896 * the {@link MeshLambertMaterial} or {@link MeshPhongMaterial}, at the cost of 37897 * being somewhat more computationally expensive. `MeshStandardMaterial` uses per-fragment 37898 * shading. 37899 * 37900 * Note that for best results you should always specify an environment map when using this material. 37901 * 37902 * For a non-technical introduction to the concept of PBR and how to set up a 37903 * PBR material, check out these articles by the people at [marmoset](https://www.marmoset.co): 37904 * 37905 * - [Basic Theory of Physically Based Rendering](https://www.marmoset.co/posts/basic-theory-of-physically-based-rendering/) 37906 * - [Physically Based Rendering and You Can Too](https://www.marmoset.co/posts/physically-based-rendering-and-you-can-too/) 37907 * 37908 * Technical details of the approach used in three.js (and most other PBR systems) can be found is this 37909 * [paper from Disney](https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf) 37910 * (pdf), by Brent Burley. 37911 * 37912 * @augments Material 37913 * @demo scenes/material-browser.html#MeshStandardMaterial 37914 */ 37915class MeshStandardMaterial extends Material { 37916 37917 /** 37918 * Constructs a new mesh standard material. 37919 * 37920 * @param {Object} [parameters] - An object with one or more properties 37921 * defining the material's appearance. Any property of the material 37922 * (including any property from inherited materials) can be passed 37923 * in here. Color values can be passed any type of value accepted 37924 * by {@link Color#set}. 37925 */ 37926 constructor( parameters ) { 37927 37928 super(); 37929 37930 /** 37931 * This flag can be used for type testing. 37932 * 37933 * @type {boolean} 37934 * @readonly 37935 * @default true 37936 */ 37937 this.isMeshStandardMaterial = true; 37938 37939 this.type = 'MeshStandardMaterial'; 37940 37941 this.defines = { 'STANDARD': '' }; 37942 37943 /** 37944 * Color of the material. 37945 * 37946 * @type {Color} 37947 * @default (1,1,1) 37948 */ 37949 this.color = new Color( 0xffffff ); // diffuse 37950 37951 /** 37952 * How rough the material appears. `0.0` means a smooth mirror reflection, `1.0` 37953 * means fully diffuse. If `roughnessMap` is also provided, 37954 * both values are multiplied. 37955 * 37956 * @type {number} 37957 * @default 1 37958 */ 37959 this.roughness = 1.0; 37960 37961 /** 37962 * How much the material is like a metal. Non-metallic materials such as wood 37963 * or stone use `0.0`, metallic use `1.0`, with nothing (usually) in between. 37964 * A value between `0.0` and `1.0` could be used for a rusty metal look. 37965 * If `metalnessMap` is also provided, both values are multiplied. 37966 * 37967 * @type {number} 37968 * @default 0 37969 */ 37970 this.metalness = 0.0; 37971 37972 /** 37973 * The color map. May optionally include an alpha channel, typically combined 37974 * with {@link Material#transparent} or {@link Material#alphaTest}. The texture map 37975 * color is modulated by the diffuse `color`. 37976 * 37977 * @type {?Texture} 37978 * @default null 37979 */ 37980 this.map = null; 37981 37982 /** 37983 * The light map. Requires a second set of UVs. 37984 * 37985 * @type {?Texture} 37986 * @default null 37987 */ 37988 this.lightMap = null; 37989 37990 /** 37991 * Intensity of the baked light. 37992 * 37993 * @type {number} 37994 * @default 1 37995 */ 37996 this.lightMapIntensity = 1.0; 37997 37998 /** 37999 * The red channel of this texture is used as the ambient occlusion map. 38000 * Requires a second set of UVs. 38001 * 38002 * @type {?Texture} 38003 * @default null 38004 */ 38005 this.aoMap = null; 38006 38007 /** 38008 * Intensity of the ambient occlusion effect. Range is `[0,1]`, where `0` 38009 * disables ambient occlusion. Where intensity is `1` and the AO map's 38010 * red channel is also `1`, ambient light is fully occluded on a surface. 38011 * 38012 * @type {number} 38013 * @default 1 38014 */ 38015 this.aoMapIntensity = 1.0; 38016 38017 /** 38018 * Emissive (light) color of the material, essentially a solid color 38019 * unaffected by other lighting. 38020 * 38021 * @type {Color} 38022 * @default (0,0,0) 38023 */ 38024 this.emissive = new Color( 0x000000 ); 38025 38026 /** 38027 * Intensity of the emissive light. Modulates the emissive color. 38028 * 38029 * @type {number} 38030 * @default 1 38031 */ 38032 this.emissiveIntensity = 1.0; 38033 38034 /** 38035 * Set emissive (glow) map. The emissive map color is modulated by the 38036 * emissive color and the emissive intensity. If you have an emissive map, 38037 * be sure to set the emissive color to something other than black. 38038 * 38039 * @type {?Texture} 38040 * @default null 38041 */ 38042 this.emissiveMap = null; 38043 38044 /** 38045 * The texture to create a bump map. The black and white values map to the 38046 * perceived depth in relation to the lights. Bump doesn't actually affect 38047 * the geometry of the object, only the lighting. If a normal map is defined 38048 * this will be ignored. 38049 * 38050 * @type {?Texture} 38051 * @default null 38052 */ 38053 this.bumpMap = null; 38054 38055 /** 38056 * How much the bump map affects the material. Typical range is `[0,1]`. 38057 * 38058 * @type {number} 38059 * @default 1 38060 */ 38061 this.bumpScale = 1; 38062 38063 /** 38064 * The texture to create a normal map. The RGB values affect the surface 38065 * normal for each pixel fragment and change the way the color is lit. Normal 38066 * maps do not change the actual shape of the surface, only the lighting. In 38067 * case the material has a normal map authored using the left handed 38068 * convention, the `y` component of `normalScale` should be negated to compensate 38069 * for the different handedness. 38070 * 38071 * @type {?Texture} 38072 * @default null 38073 */ 38074 this.normalMap = null; 38075 38076 /** 38077 * The type of normal map. 38078 * 38079 * @type {(TangentSpaceNormalMap|ObjectSpaceNormalMap)} 38080 * @default TangentSpaceNormalMap 38081 */ 38082 this.normalMapType = TangentSpaceNormalMap; 38083 38084 /** 38085 * How much the normal map affects the material. Typical value range is `[0,1]`. 38086 * 38087 * @type {Vector2} 38088 * @default (1,1) 38089 */ 38090 this.normalScale = new Vector2( 1, 1 ); 38091 38092 /** 38093 * The displacement map affects the position of the mesh's vertices. Unlike 38094 * other maps which only affect the light and shade of the material the 38095 * displaced vertices can cast shadows, block other objects, and otherwise 38096 * act as real geometry. The displacement texture is an image where the value 38097 * of each pixel (white being the highest) is mapped against, and 38098 * repositions, the vertices of the mesh. 38099 * 38100 * @type {?Texture} 38101 * @default null 38102 */ 38103 this.displacementMap = null; 38104 38105 /** 38106 * How much the displacement map affects the mesh (where black is no 38107 * displacement, and white is maximum displacement). Without a displacement 38108 * map set, this value is not applied. 38109 * 38110 * @type {number} 38111 * @default 0 38112 */ 38113 this.displacementScale = 1; 38114 38115 /** 38116 * The offset of the displacement map's values on the mesh's vertices. 38117 * The bias is added to the scaled sample of the displacement map. 38118 * Without a displacement map set, this value is not applied. 38119 * 38120 * @type {number} 38121 * @default 0 38122 */ 38123 this.displacementBias = 0; 38124 38125 /** 38126 * The green channel of this texture is used to alter the roughness of the 38127 * material. 38128 * 38129 * @type {?Texture} 38130 * @default null 38131 */ 38132 this.roughnessMap = null; 38133 38134 /** 38135 * The blue channel of this texture is used to alter the metalness of the 38136 * material. 38137 * 38138 * @type {?Texture} 38139 * @default null 38140 */ 38141 this.metalnessMap = null; 38142 38143 /** 38144 * The alpha map is a grayscale texture that controls the opacity across the 38145 * surface (black: fully transparent; white: fully opaque). 38146 * 38147 * Only the color of the texture is used, ignoring the alpha channel if one 38148 * exists. For RGB and RGBA textures, the renderer will use the green channel 38149 * when sampling this texture due to the extra bit of precision provided for 38150 * green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and 38151 * luminance/alpha textures will also still work as expected. 38152 * 38153 * @type {?Texture} 38154 * @default null 38155 */ 38156 this.alphaMap = null; 38157 38158 /** 38159 * The environment map. To ensure a physically correct rendering, environment maps 38160 * are internally pre-processed with {@link PMREMGenerator}. 38161 * 38162 * @type {?Texture} 38163 * @default null 38164 */ 38165 this.envMap = null; 38166 38167 /** 38168 * The rotation of the environment map in radians. 38169 * 38170 * @type {Euler} 38171 * @default (0,0,0) 38172 */ 38173 this.envMapRotation = new Euler(); 38174 38175 /** 38176 * Scales the effect of the environment map by multiplying its color. 38177 * 38178 * @type {number} 38179 * @default 1 38180 */ 38181 this.envMapIntensity = 1.0; 38182 38183 /** 38184 * Renders the geometry as a wireframe. 38185 * 38186 * @type {boolean} 38187 * @default false 38188 */ 38189 this.wireframe = false; 38190 38191 /** 38192 * Controls the thickness of the wireframe. 38193 * 38194 * Can only be used with {@link SVGRenderer}. 38195 * 38196 * @type {number} 38197 * @default 1 38198 */ 38199 this.wireframeLinewidth = 1; 38200 38201 /** 38202 * Defines appearance of wireframe ends. 38203 * 38204 * Can only be used with {@link SVGRenderer}. 38205 * 38206 * @type {('round'|'bevel'|'miter')} 38207 * @default 'round' 38208 */ 38209 this.wireframeLinecap = 'round'; 38210 38211 /** 38212 * Defines appearance of wireframe joints. 38213 * 38214 * Can only be used with {@link SVGRenderer}. 38215 * 38216 * @type {('round'|'bevel'|'miter')} 38217 * @default 'round' 38218 */ 38219 this.wireframeLinejoin = 'round'; 38220 38221 /** 38222 * Whether the material is rendered with flat shading or not. 38223 * 38224 * @type {boolean} 38225 * @default false 38226 */ 38227 this.flatShading = false; 38228 38229 /** 38230 * Whether the material is affected by fog or not. 38231 * 38232 * @type {boolean} 38233 * @default true 38234 */ 38235 this.fog = true; 38236 38237 this.setValues( parameters ); 38238 38239 } 38240 38241 copy( source ) { 38242 38243 super.copy( source ); 38244 38245 this.defines = { 'STANDARD': '' }; 38246 38247 this.color.copy( source.color ); 38248 this.roughness = source.roughness; 38249 this.metalness = source.metalness; 38250 38251 this.map = source.map; 38252 38253 this.lightMap = source.lightMap; 38254 this.lightMapIntensity = source.lightMapIntensity; 38255 38256 this.aoMap = source.aoMap; 38257 this.aoMapIntensity = source.aoMapIntensity; 38258 38259 this.emissive.copy( source.emissive ); 38260 this.emissiveMap = source.emissiveMap; 38261 this.emissiveIntensity = source.emissiveIntensity; 38262 38263 this.bumpMap = source.bumpMap; 38264 this.bumpScale = source.bumpScale; 38265 38266 this.normalMap = source.normalMap; 38267 this.normalMapType = source.normalMapType; 38268 this.normalScale.copy( source.normalScale ); 38269 38270 this.displacementMap = source.displacementMap; 38271 this.displacementScale = source.displacementScale; 38272 this.displacementBias = source.displacementBias; 38273 38274 this.roughnessMap = source.roughnessMap; 38275 38276 this.metalnessMap = source.metalnessMap; 38277 38278 this.alphaMap = source.alphaMap; 38279 38280 this.envMap = source.envMap; 38281 this.envMapRotation.copy( source.envMapRotation ); 38282 this.envMapIntensity = source.envMapIntensity; 38283 38284 this.wireframe = source.wireframe; 38285 this.wireframeLinewidth = source.wireframeLinewidth; 38286 this.wireframeLinecap = source.wireframeLinecap; 38287 this.wireframeLinejoin = source.wireframeLinejoin; 38288 38289 this.flatShading = source.flatShading; 38290 38291 this.fog = source.fog; 38292 38293 return this; 38294 38295 } 38296 38297} 38298 38299/** 38300 * An extension of the {@link MeshStandardMaterial}, providing more advanced 38301 * physically-based rendering properties: 38302 * 38303 * - Anisotropy: Ability to represent the anisotropic property of materials 38304 * as observable with brushed metals. 38305 * - Clearcoat: Some materials â like car paints, carbon fiber, and wet surfaces â require 38306 * a clear, reflective layer on top of another layer that may be irregular or rough. 38307 * Clearcoat approximates this effect, without the need for a separate transparent surface. 38308 * - Iridescence: Allows to render the effect where hue varies depending on the viewing 38309 * angle and illumination angle. This can be seen on soap bubbles, oil films, or on the 38310 * wings of many insects. 38311 * - Physically-based transparency: One limitation of {@link Material#opacity} is that highly 38312 * transparent materials are less reflective. Physically-based transmission provides a more 38313 * realistic option for thin, transparent surfaces like glass. 38314 * - Advanced reflectivity: More flexible reflectivity for non-metallic materials. 38315 * - Sheen: Can be used for representing cloth and fabric materials. 38316 * 38317 * As a result of these complex shading features, `MeshPhysicalMaterial` has a 38318 * higher performance cost, per pixel, than other three.js materials. Most 38319 * effects are disabled by default, and add cost as they are enabled. For 38320 * best results, always specify an environment map when using this material. 38321 * 38322 * @augments MeshStandardMaterial 38323 * @demo scenes/material-browser.html#MeshPhysicalMaterial 38324 */ 38325class MeshPhysicalMaterial extends MeshStandardMaterial { 38326 38327 /** 38328 * Constructs a new mesh physical material. 38329 * 38330 * @param {Object} [parameters] - An object with one or more properties 38331 * defining the material's appearance. Any property of the material 38332 * (including any property from inherited materials) can be passed 38333 * in here. Color values can be passed any type of value accepted 38334 * by {@link Color#set}. 38335 */ 38336 constructor( parameters ) { 38337 38338 super(); 38339 38340 /** 38341 * This flag can be used for type testing. 38342 * 38343 * @type {boolean} 38344 * @readonly 38345 * @default true 38346 */ 38347 this.isMeshPhysicalMaterial = true; 38348 38349 this.defines = { 38350 38351 'STANDARD': '', 38352 'PHYSICAL': '' 38353 38354 }; 38355 38356 this.type = 'MeshPhysicalMaterial'; 38357 38358 /** 38359 * The rotation of the anisotropy in tangent, bitangent space, measured in radians 38360 * counter-clockwise from the tangent. When `anisotropyMap` is present, this 38361 * property provides additional rotation to the vectors in the texture. 38362 * 38363 * @type {number} 38364 * @default 1 38365 */ 38366 this.anisotropyRotation = 0; 38367 38368 /** 38369 * Red and green channels represent the anisotropy direction in `[-1, 1]` tangent, 38370 * bitangent space, to be rotated by `anisotropyRotation`. The blue channel 38371 * contains strength as `[0, 1]` to be multiplied by `anisotropy`. 38372 * 38373 * @type {?Texture} 38374 * @default null 38375 */ 38376 this.anisotropyMap = null; 38377 38378 /** 38379 * The red channel of this texture is multiplied against `clearcoat`, 38380 * for per-pixel control over a coating's intensity. 38381 * 38382 * @type {?Texture} 38383 * @default null 38384 */ 38385 this.clearcoatMap = null; 38386 38387 /** 38388 * Roughness of the clear coat layer, from `0.0` to `1.0`. 38389 * 38390 * @type {number} 38391 * @default 0 38392 */ 38393 this.clearcoatRoughness = 0.0; 38394 38395 /** 38396 * The green channel of this texture is multiplied against 38397 * `clearcoatRoughness`, for per-pixel control over a coating's roughness. 38398 * 38399 * @type {?Texture} 38400 * @default null 38401 */ 38402 this.clearcoatRoughnessMap = null; 38403 38404 /** 38405 * How much `clearcoatNormalMap` affects the clear coat layer, from 38406 * `(0,0)` to `(1,1)`. 38407 * 38408 * @type {Vector2} 38409 * @default (1,1) 38410 */ 38411 this.clearcoatNormalScale = new Vector2( 1, 1 ); 38412 38413 /** 38414 * Can be used to enable independent normals for the clear coat layer. 38415 * 38416 * @type {?Texture} 38417 * @default null 38418 */ 38419 this.clearcoatNormalMap = null; 38420 38421 /** 38422 * Index-of-refraction for non-metallic materials, from `1.0` to `2.333`. 38423 * 38424 * @type {number} 38425 * @default 1.5 38426 */ 38427 this.ior = 1.5; 38428 38429 /** 38430 * Degree of reflectivity, from `0.0` to `1.0`. Default is `0.5`, which 38431 * corresponds to an index-of-refraction of `1.5`. 38432 * 38433 * This models the reflectivity of non-metallic materials. It has no effect 38434 * when `metalness` is `1.0` 38435 * 38436 * @name MeshPhysicalMaterial#reflectivity 38437 * @type {number} 38438 * @default 0.5 38439 */ 38440 Object.defineProperty( this, 'reflectivity', { 38441 get: function () { 38442 38443 return ( clamp( 2.5 * ( this.ior - 1 ) / ( this.ior + 1 ), 0, 1 ) ); 38444 38445 }, 38446 set: function ( reflectivity ) { 38447 38448 this.ior = ( 1 + 0.4 * reflectivity ) / ( 1 - 0.4 * reflectivity ); 38449 38450 } 38451 } ); 38452 38453 /** 38454 * The red channel of this texture is multiplied against `iridescence`, for per-pixel 38455 * control over iridescence. 38456 * 38457 * @type {?Texture} 38458 * @default null 38459 */ 38460 this.iridescenceMap = null; 38461 38462 /** 38463 * Strength of the iridescence RGB color shift effect, represented by an index-of-refraction. 38464 * Between `1.0` to `2.333`. 38465 * 38466 * @type {number} 38467 * @default 1.3 38468 */ 38469 this.iridescenceIOR = 1.3; 38470 38471 /** 38472 *Array of exactly 2 elements, specifying minimum and maximum thickness of the iridescence layer. 38473 Thickness of iridescence layer has an equivalent effect of the one `thickness` has on `ior`. 38474 * 38475 * @type {Array<number,number>} 38476 * @default [100,400] 38477 */ 38478 this.iridescenceThicknessRange = [ 100, 400 ]; 38479 38480 /** 38481 * A texture that defines the thickness of the iridescence layer, stored in the green channel. 38482 * Minimum and maximum values of thickness are defined by `iridescenceThicknessRange` array: 38483 * - `0.0` in the green channel will result in thickness equal to first element of the array. 38484 * - `1.0` in the green channel will result in thickness equal to second element of the array. 38485 * - Values in-between will linearly interpolate between the elements of the array. 38486 * 38487 * @type {?Texture} 38488 * @default null 38489 */ 38490 this.iridescenceThicknessMap = null; 38491 38492 /** 38493 * The sheen tint. 38494 * 38495 * @type {Color} 38496 * @default (0,0,0) 38497 */ 38498 this.sheenColor = new Color( 0x000000 ); 38499 38500 /** 38501 * The RGB channels of this texture are multiplied against `sheenColor`, for per-pixel control 38502 * over sheen tint. 38503 * 38504 * @type {?Texture} 38505 * @default null 38506 */ 38507 this.sheenColorMap = null; 38508 38509 /** 38510 * Roughness of the sheen layer, from `0.0` to `1.0`. 38511 * 38512 * @type {number} 38513 * @default 1 38514 */ 38515 this.sheenRoughness = 1.0; 38516 38517 /** 38518 * The alpha channel of this texture is multiplied against `sheenRoughness`, for per-pixel control 38519 * over sheen roughness. 38520 * 38521 * @type {?Texture} 38522 * @default null 38523 */ 38524 this.sheenRoughnessMap = null; 38525 38526 /** 38527 * The red channel of this texture is multiplied against `transmission`, for per-pixel control over 38528 * optical transparency. 38529 * 38530 * @type {?Texture} 38531 * @default null 38532 */ 38533 this.transmissionMap = null; 38534 38535 /** 38536 * The thickness of the volume beneath the surface. The value is given in the 38537 * coordinate space of the mesh. If the value is `0` the material is 38538 * thin-walled. Otherwise the material is a volume boundary. 38539 * 38540 * @type {number} 38541 * @default 0 38542 */ 38543 this.thickness = 0; 38544 38545 /** 38546 * A texture that defines the thickness, stored in the green channel. This will 38547 * be multiplied by `thickness`. 38548 * 38549 * @type {?Texture} 38550 * @default null 38551 */ 38552 this.thicknessMap = null; 38553 38554 /** 38555 * Density of the medium given as the average distance that light travels in 38556 * the medium before interacting with a particle. The value is given in world 38557 * space units, and must be greater than zero. 38558 * 38559 * @type {number} 38560 * @default Infinity 38561 */ 38562 this.attenuationDistance = Infinity; 38563 38564 /** 38565 * The color that white light turns into due to absorption when reaching the 38566 * attenuation distance. 38567 * 38568 * @type {Color} 38569 * @default (1,1,1) 38570 */ 38571 this.attenuationColor = new Color( 1, 1, 1 ); 38572 38573 /** 38574 * A float that scales the amount of specular reflection for non-metals only. 38575 * When set to zero, the model is effectively Lambertian. From `0.0` to `1.0`. 38576 * 38577 * @type {number} 38578 * @default 1 38579 */ 38580 this.specularIntensity = 1.0; 38581 38582 /** 38583 * The alpha channel of this texture is multiplied against `specularIntensity`, 38584 * for per-pixel control over specular intensity. 38585 * 38586 * @type {?Texture} 38587 * @default null 38588 */ 38589 this.specularIntensityMap = null; 38590 38591 /** 38592 * Tints the specular reflection at normal incidence for non-metals only. 38593 * 38594 * @type {Color} 38595 * @default (1,1,1) 38596 */ 38597 this.specularColor = new Color( 1, 1, 1 ); 38598 38599 /** 38600 * The RGB channels of this texture are multiplied against `specularColor`, 38601 * for per-pixel control over specular color. 38602 * 38603 * @type {?Texture} 38604 * @default null 38605 */ 38606 this.specularColorMap = null; 38607 38608 this._anisotropy = 0; 38609 this._clearcoat = 0; 38610 this._dispersion = 0; 38611 this._iridescence = 0; 38612 this._sheen = 0.0; 38613 this._transmission = 0; 38614 38615 this.setValues( parameters ); 38616 38617 } 38618 38619 /** 38620 * The anisotropy strength, from `0.0` to `1.0`. 38621 * 38622 * @type {number} 38623 * @default 0 38624 */ 38625 get anisotropy() { 38626 38627 return this._anisotropy; 38628 38629 } 38630 38631 set anisotropy( value ) { 38632 38633 if ( this._anisotropy > 0 !== value > 0 ) { 38634 38635 this.version ++; 38636 38637 } 38638 38639 this._anisotropy = value; 38640 38641 } 38642 38643 /** 38644 * Represents the intensity of the clear coat layer, from `0.0` to `1.0`. Use 38645 * clear coat related properties to enable multilayer materials that have a 38646 * thin translucent layer over the base layer. 38647 * 38648 * @type {number} 38649 * @default 0 38650 */ 38651 get clearcoat() { 38652 38653 return this._clearcoat; 38654 38655 } 38656 38657 set clearcoat( value ) { 38658 38659 if ( this._clearcoat > 0 !== value > 0 ) { 38660 38661 this.version ++; 38662 38663 } 38664 38665 this._clearcoat = value; 38666 38667 } 38668 /** 38669 * The intensity of the iridescence layer, simulating RGB color shift based on the angle between 38670 * the surface and the viewer, from `0.0` to `1.0`. 38671 * 38672 * @type {number} 38673 * @default 0 38674 */ 38675 get iridescence() { 38676 38677 return this._iridescence; 38678 38679 } 38680 38681 set iridescence( value ) { 38682 38683 if ( this._iridescence > 0 !== value > 0 ) { 38684 38685 this.version ++; 38686 38687 } 38688 38689 this._iridescence = value; 38690 38691 } 38692 38693 /** 38694 * Defines the strength of the angular separation of colors (chromatic aberration) transmitting 38695 * through a relatively clear volume. Any value zero or larger is valid, the typical range of 38696 * realistic values is `[0, 1]`. This property can be only be used with transmissive objects. 38697 * 38698 * @type {number} 38699 * @default 0 38700 */ 38701 get dispersion() { 38702 38703 return this._dispersion; 38704 38705 } 38706 38707 set dispersion( value ) { 38708 38709 if ( this._dispersion > 0 !== value > 0 ) { 38710 38711 this.version ++; 38712 38713 } 38714 38715 this._dispersion = value; 38716 38717 } 38718 38719 /** 38720 * The intensity of the sheen layer, from `0.0` to `1.0`. 38721 * 38722 * @type {number} 38723 * @default 0 38724 */ 38725 get sheen() { 38726 38727 return this._sheen; 38728 38729 } 38730 38731 set sheen( value ) { 38732 38733 if ( this._sheen > 0 !== value > 0 ) { 38734 38735 this.version ++; 38736 38737 } 38738 38739 this._sheen = value; 38740 38741 } 38742 38743 /** 38744 * Degree of transmission (or optical transparency), from `0.0` to `1.0`. 38745 * 38746 * Thin, transparent or semitransparent, plastic or glass materials remain 38747 * largely reflective even if they are fully transmissive. The transmission 38748 * property can be used to model these materials. 38749 * 38750 * When transmission is non-zero, `opacity` should be set to `1`. 38751 * 38752 * @type {number} 38753 * @default 0 38754 */ 38755 get transmission() { 38756 38757 return this._transmission; 38758 38759 } 38760 38761 set transmission( value ) { 38762 38763 if ( this._transmission > 0 !== value > 0 ) { 38764 38765 this.version ++; 38766 38767 } 38768 38769 this._transmission = value; 38770 38771 } 38772 38773 copy( source ) { 38774 38775 super.copy( source ); 38776 38777 this.defines = { 38778 38779 'STANDARD': '', 38780 'PHYSICAL': '' 38781 38782 }; 38783 38784 this.anisotropy = source.anisotropy; 38785 this.anisotropyRotation = source.anisotropyRotation; 38786 this.anisotropyMap = source.anisotropyMap; 38787 38788 this.clearcoat = source.clearcoat; 38789 this.clearcoatMap = source.clearcoatMap; 38790 this.clearcoatRoughness = source.clearcoatRoughness; 38791 this.clearcoatRoughnessMap = source.clearcoatRoughnessMap; 38792 this.clearcoatNormalMap = source.clearcoatNormalMap; 38793 this.clearcoatNormalScale.copy( source.clearcoatNormalScale ); 38794 38795 this.dispersion = source.dispersion; 38796 this.ior = source.ior; 38797 38798 this.iridescence = source.iridescence; 38799 this.iridescenceMap = source.iridescenceMap; 38800 this.iridescenceIOR = source.iridescenceIOR; 38801 this.iridescenceThicknessRange = [ ...source.iridescenceThicknessRange ]; 38802 this.iridescenceThicknessMap = source.iridescenceThicknessMap; 38803 38804 this.sheen = source.sheen; 38805 this.sheenColor.copy( source.sheenColor ); 38806 this.sheenColorMap = source.sheenColorMap; 38807 this.sheenRoughness = source.sheenRoughness; 38808 this.sheenRoughnessMap = source.sheenRoughnessMap; 38809 38810 this.transmission = source.transmission; 38811 this.transmissionMap = source.transmissionMap; 38812 38813 this.thickness = source.thickness; 38814 this.thicknessMap = source.thicknessMap; 38815 this.attenuationDistance = source.attenuationDistance; 38816 this.attenuationColor.copy( source.attenuationColor ); 38817 38818 this.specularIntensity = source.specularIntensity; 38819 this.specularIntensityMap = source.specularIntensityMap; 38820 this.specularColor.copy( source.specularColor ); 38821 this.specularColorMap = source.specularColorMap; 38822 38823 return this; 38824 38825 } 38826 38827} 38828 38829/** 38830 * A material for
38830shiny surfaces with specular highlights. 38831 * 38832 * The material uses a non-physically based [Blinn-Phong](https://en.wikipedia.org/wiki/Blinn-Phong_shading_model) 38833 * model for calculating reflectance. Unlike the Lambertian model used in the 38834 * {@link MeshLambertMaterial} this can simulate shiny surfaces with specular 38835 * highlights (such as varnished wood). `MeshPhongMaterial` uses per-fragment shading. 38836 * 38837 * Performance will generally be greater when using this material over the 38838 * {@link MeshStandardMaterial} or {@link MeshPhysicalMaterial}, at the cost of 38839 * some graphical accuracy. 38840 * 38841 * @augments Material 38842 * @demo scenes/material-browser.html#MeshPhongMaterial 38843 */ 38844class MeshPhongMaterial extends Material { 38845 38846 /** 38847 * Constructs a new mesh phong material. 38848 * 38849 * @param {Object} [parameters] - An object with one or more properties 38850 * defining the material's appearance. Any property of the material 38851 * (including any property from inherited materials) can be passed 38852 * in here. Color values can be passed any type of value accepted 38853 * by {@link Color#set}. 38854 */ 38855 constructor( parameters ) { 38856 38857 super(); 38858 38859 /** 38860 * This flag can be used for type testing. 38861 * 38862 * @type {boolean} 38863 * @readonly 38864 * @default true 38865 */ 38866 this.isMeshPhongMaterial = true; 38867 38868 this.type = 'MeshPhongMaterial'; 38869 38870 /** 38871 * Color of the material. 38872 * 38873 * @type {Color} 38874 * @default (1,1,1) 38875 */ 38876 this.color = new Color( 0xffffff ); // diffuse 38877 38878 /** 38879 * Specular color of the material. The default color is set to `0x111111` (very dark grey) 38880 * 38881 * This defines how shiny the material is and the color of its shine. 38882 * 38883 * @type {Color} 38884 */ 38885 this.specular = new Color( 0x111111 ); 38886 38887 /** 38888 * How shiny the specular highlight is; a higher value gives a sharper highlight. 38889 * 38890 * @type {number} 38891 * @default 30 38892 */ 38893 this.shininess = 30; 38894 38895 /** 38896 * The color map. May optionally include an alpha channel, typically combined 38897 * with {@link Material#transparent} or {@link Material#alphaTest}. The texture map 38898 * color is modulated by the diffuse `color`. 38899 * 38900 * @type {?Texture} 38901 * @default null 38902 */ 38903 this.map = null; 38904 38905 /** 38906 * The light map. Requires a second set of UVs. 38907 * 38908 * @type {?Texture} 38909 * @default null 38910 */ 38911 this.lightMap = null; 38912 38913 /** 38914 * Intensity of the baked light. 38915 * 38916 * @type {number} 38917 * @default 1 38918 */ 38919 this.lightMapIntensity = 1.0; 38920 38921 /** 38922 * The red channel of this texture is used as the ambient occlusion map. 38923 * Requires a second set of UVs. 38924 * 38925 * @type {?Texture} 38926 * @default null 38927 */ 38928 this.aoMap = null; 38929 38930 /** 38931 * Intensity of the ambient occlusion effect. Range is `[0,1]`, where `0` 38932 * disables ambient occlusion. Where intensity is `1` and the AO map's 38933 * red channel is also `1`, ambient light is fully occluded on a surface. 38934 * 38935 * @type {number} 38936 * @default 1 38937 */ 38938 this.aoMapIntensity = 1.0; 38939 38940 /** 38941 * Emissive (light) color of the material, essentially a solid color 38942 * unaffected by other lighting. 38943 * 38944 * @type {Color} 38945 * @default (0,0,0) 38946 */ 38947 this.emissive = new Color( 0x000000 ); 38948 38949 /** 38950 * Intensity of the emissive light. Modulates the emissive color. 38951 * 38952 * @type {number} 38953 * @default 1 38954 */ 38955 this.emissiveIntensity = 1.0; 38956 38957 /** 38958 * Set emissive (glow) map. The emissive map color is modulated by the 38959 * emissive color and the emissive intensity. If you have an emissive map, 38960 * be sure to set the emissive color to something other than black. 38961 * 38962 * @type {?Texture} 38963 * @default null 38964 */ 38965 this.emissiveMap = null; 38966 38967 /** 38968 * The texture to create a bump map. The black and white values map to the 38969 * perceived depth in relation to the lights. Bump doesn't actually affect 38970 * the geometry of the object, only the lighting. If a normal map is defined 38971 * this will be ignored. 38972 * 38973 * @type {?Texture} 38974 * @default null 38975 */ 38976 this.bumpMap = null; 38977 38978 /** 38979 * How much the bump map affects the material. Typical range is `[0,1]`. 38980 * 38981 * @type {number} 38982 * @default 1 38983 */ 38984 this.bumpScale = 1; 38985 38986 /** 38987 * The texture to create a normal map. The RGB values affect the surface 38988 * normal for each pixel fragment and change the way the color is lit. Normal
38989 * maps do not change the actual shape of the surface, only the lighting. In 38990 * case the material has a normal map authored using the left handed 38991 * convention, the `y` component of `normalScale` should be negated to compensate 38992 * for the different handedness. 38993 * 38994 * @type {?Texture} 38995 * @default null 38996 */ 38997 this.normalMap = null; 38998 38999 /** 39000 * The type of normal map. 39001 * 39002 * @type {(TangentSpaceNormalMap|ObjectSpaceNormalMap)} 39003 * @default TangentSpaceNormalMap 39004 */ 39005 this.normalMapType = TangentSpaceNormalMap; 39006 39007 /** 39008 * How much the normal map affects the material. Typical value range is `[0,1]`. 39009 * 39010 * @type {Vector2} 39011 * @default (1,1) 39012 */ 39013 this.normalScale = new Vector2( 1, 1 ); 39014 39015 /** 39016 * The displacement map affects the position of the mesh's vertices. Unlike 39017 * other maps which only affect the light and shade of the material the 39018 * displaced vertices can cast shadows, block other objects, and otherwise 39019 * act as real geometry. The displacement texture is an image where the value 39020 * of each pixel (white being the highest) is mapped against, and 39021 * repositions, the vertices of the mesh. 39022 * 39023 * @type {?Texture} 39024 * @default null 39025 */ 39026 this.displacementMap = null; 39027 39028 /** 39029 * How much the displacement map affects the mesh (where black is no 39030 * displacement, and white is maximum displacement). Without a displacement 39031 * map set, this value is not applied. 39032 * 39033 * @type {number} 39034 * @default 0 39035 */ 39036 this.displacementScale = 1; 39037 39038 /** 39039 * The offset of the displacement map's values on the mesh's vertices. 39040 * The bias is added to the scaled sample of the displacement map. 39041 * Without a displacement map set, this value is not applied. 39042 * 39043 * @type {number} 39044 * @default 0 39045 */ 39046 this.displacementBias = 0; 39047 39048 /** 39049 * The specular map value affects both how much the specular surface 39050 * highlight contributes and how much of the environment map affects the 39051 * surface. 39052 * 39053 * @type {?Texture} 39054 * @default null 39055 */ 39056 this.specularMap = null; 39057 39058 /** 39059 * The alpha map is a grayscale texture that controls the opacity across the 39060 * surface (black: fully transparent; white: fully opaque). 39061 * 39062 * Only the color of the texture is used, ignoring the alpha channel if one 39063 * exists. For RGB and RGBA textures, the renderer will use the green channel 39064 * when sampling this texture due to the extra bit of precision provided for 39065 * green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and 39066 * luminance/alpha textures will also still work as expected. 39067 * 39068 * @type {?Texture} 39069 * @default null 39070 */ 39071 this.alphaMap = null; 39072 39073 /** 39074 * The environment map. 39075 * 39076 * @type {?Texture} 39077 * @default null 39078 */ 39079 this.envMap = null; 39080 39081 /** 39082 * The rotation of the environment map in radians. 39083 * 39084 * @type {Euler} 39085 * @default (0,0,0) 39086 */ 39087 this.envMapRotation = new Euler(); 39088 39089 /** 39090 * How to combine the result of the surface's color with the environment map, if any. 39091 * 39092 * When set to `MixOperation`, the {@link MeshBasicMaterial#reflectivity} is used to 39093 * blend between the two colors. 39094 * 39095 * @type {(MultiplyOperation|MixOperation|AddOperation)} 39096 * @default MultiplyOperation 39097 */ 39098 this.combine = MultiplyOperation; 39099 39100 /** 39101 * How much the environment map affects the surface. 39102 * The valid range is between `0` (no reflections) and `1` (full reflections). 39103 * 39104 * @type {number} 39105 * @default 1 39106 */ 39107 this.reflectivity = 1; 39108 39109 /** 39110 * Scales the effect of the environment map by multiplying its color. 39111 * 39112 * @type {number} 39113 * @default 1 39114 */ 39115 this.envMapIntensity = 1.0; 39116 39117 /** 39118 * The index of refraction (IOR) of air (approximately 1) divided by the 39119 * index of refraction of the material. It is used with environment mapping 39120 * modes {@link CubeRefractionMapping} and {@link EquirectangularRefractionMapping}. 39121 * The refraction ratio should not exceed `1`. 39122 * 39123 * @type {number} 39124 * @default 0.98 39125 */ 39126 this.refractionRatio = 0.98; 39127 39128 /** 39129 * Renders the geometry as a wireframe. 39130 * 39131 * @type {boolean} 39132 * @default false 39133 */ 39134 this.wireframe = false;
39135 39136 /** 39137 * Controls the thickness of the wireframe. 39138 * 39139 * Can only be used with {@link SVGRenderer}. 39140 * 39141 * @type {number} 39142 * @default 1 39143 */ 39144 this.wireframeLinewidth = 1; 39145 39146 /** 39147 * Defines appearance of wireframe ends. 39148 * 39149 * Can only be used with {@link SVGRenderer}. 39150 * 39151 * @type {('round'|'bevel'|'miter')} 39152 * @default 'round' 39153 */ 39154 this.wireframeLinecap = 'round'; 39155 39156 /** 39157 * Defines appearance of wireframe joints. 39158 * 39159 * Can only be used with {@link SVGRenderer}. 39160 * 39161 * @type {('round'|'bevel'|'miter')} 39162 * @default 'round' 39163 */ 39164 this.wireframeLinejoin = 'round'; 39165 39166 /** 39167 * Whether the material is rendered with flat shading or not. 39168 * 39169 * @type {boolean} 39170 * @default false 39171 */ 39172 this.flatShading = false; 39173 39174 /** 39175 * Whether the material is affected by fog or not. 39176 * 39177 * @type {boolean} 39178 * @default true 39179 */ 39180 this.fog = true; 39181 39182 this.setValues( parameters ); 39183 39184 } 39185 39186 copy( source ) { 39187 39188 super.copy( source ); 39189 39190 this.color.copy( source.color ); 39191 this.specular.copy( source.specular ); 39192 this.shininess = source.shininess; 39193 39194 this.map = source.map; 39195 39196 this.lightMap = source.lightMap; 39197 this.lightMapIntensity = source.lightMapIntensity; 39198 39199 this.aoMap = source.aoMap; 39200 this.aoMapIntensity = source.aoMapIntensity; 39201 39202 this.emissive.copy( source.emissive ); 39203 this.emissiveMap = source.emissiveMap; 39204 this.emissiveIntensity = source.emissiveIntensity; 39205 39206 this.bumpMap = source.bumpMap; 39207 this.bumpScale = source.bumpScale; 39208 39209 this.normalMap = source.normalMap; 39210 this.normalMapType = source.normalMapType; 39211 this.normalScale.copy( source.normalScale ); 39212 39213 this.displacementMap = source.displacementMap; 39214 this.displacementScale = source.displacementScale; 39215 this.displacementBias = source.displacementBias; 39216 39217 this.specularMap = source.specularMap; 39218 39219 this.alphaMap = source.alphaMap; 39220 39221 this.envMap = source.envMap; 39222 this.envMapRotation.copy( source.envMapRotation ); 39223 this.combine = source.combine; 39224 this.reflectivity = source.reflectivity; 39225 this.envMapIntensity = source.envMapIntensity; 39226 this.refractionRatio = source.refractionRatio; 39227 39228 this.wireframe = source.wireframe; 39229 this.wireframeLinewidth = source.wireframeLinewidth; 39230 this.wireframeLinecap = source.wireframeLinecap; 39231 this.wireframeLinejoin = source.wireframeLinejoin; 39232 39233 this.flatShading = source.flatShading; 39234 39235 this.fog = source.fog; 39236 39237 return this; 39238 39239 } 39240 39241} 39242 39243/** 39244 * A material implementing toon shading. 39245 * 39246 * @augments Material 39247 * @demo scenes/material-browser.html#MeshToonMaterial 39248 */ 39249class MeshToonMaterial extends Material { 39250 39251 /** 39252 * Constructs a new mesh toon material. 39253 * 39254 * @param {Object} [parameters] - An object with one or more properties 39255 * defining the material's appearance. Any property of the material 39256 * (including any property from inherited materials) can be passed 39257 * in here. Color values can be passed any type of value accepted 39258 * by {@link Color#set}. 39259 */ 39260 constructor( parameters ) { 39261 39262 super(); 39263 39264 /** 39265 * This flag can be used for type testing. 39266 * 39267 * @type {boolean} 39268 * @readonly 39269 * @default true 39270 */ 39271 this.isMeshToonMaterial = true; 39272 39273 this.defines = { 'TOON': '' }; 39274 39275 this.type = 'MeshToonMaterial'; 39276 39277 /** 39278 * Color of the material. 39279 * 39280 * @type {Color} 39281 * @default (1,1,1) 39282 */ 39283 this.color = new Color( 0xffffff ); 39284 39285 /** 39286 * The color map. May optionally include an alpha channel, typically combined 39287 * with {@link Material#transparent} or {@link Material#alphaTest}. The texture map 39288 * color is modulated by the diffuse `color`. 39289 * 39290 * @type {?Texture} 39291 * @default null 39292 */ 39293 this.map = null; 39294 39295 /** 39296 * Gradient map for toon shading. It's required to set 39297 * {@link Texture#minFilter} and {@link Texture#magFilter} to {@link NearestFilter} 39298 * when using this type of texture. 39299 * 39300 * @type {?Texture} 39301 * @default null 39302 */ 39303 this.gradientMap = null; 39304 39305 /** 39306 * The light map. Requires a second set of UVs. 39307 * 39308 * @type {?Texture} 39309 * @default null 39310 */ 39311 this.lightMap = null; 39312 39313 /** 39314 * Intensity of the baked light. 39315 * 39316 * @type {number} 39317 * @default 1 39318 */ 39319 this.lightMapIntensity = 1.0; 39320 39321 /** 39322 * The red channel of this texture is used as the ambient occlusion map. 39323 * Requires a second set of UVs. 39324 * 39325 * @type {?Texture} 39326 * @default null 39327 */ 39328 this.aoMap = null; 39329 39330 /** 39331 * Intensity of the ambient occlusion effect. Range is `[0,1]`, where `0` 39332 * disables ambient occlusion. Where intensity is `1` and the AO map's 39333 * red channel is also `1`, ambient light is fully occluded on a surface. 39334 * 39335 * @type {number} 39336 * @default 1 39337 */ 39338 this.aoMapIntensity = 1.0; 39339 39340 /** 39341 * Emissive (light) color of the material, essentially a solid color 39342 * unaffected by other lighting. 39343 * 39344 * @type {Color} 39345 * @default (0,0,0) 39346 */ 39347 this.emissive = new Color( 0x000000 ); 39348 39349 /** 39350 * Intensity of the emissive light. Modulates the emissive color. 39351 * 39352 * @type {number} 39353 * @default 1 39354 */ 39355 this.emissiveIntensity = 1.0; 39356 39357 /** 39358 * Set emissive (glow) map. The emissive map color is modulated by the 39359 * emissive color and the emissive intensity. If you have an emissive map, 39360 * be sure to set the emissive color to something other than black. 39361 * 39362 * @type {?Texture} 39363 * @default null 39364 */ 39365 this.emissiveMap = null; 39366 39367 /** 39368 * The texture to create a bump map. The black and white values map to the 39369 * perceived depth in relation to the lights. Bump doesn't actually affect 39370 * the geometry of the object, only the lighting. If a normal map is defined 39371 * this will be ignored. 39372 * 39373 * @type {?Texture} 39374 * @default null 39375 */ 39376 this.bumpMap = null; 39377 39378 /** 39379 * How much the bump map affects the material. Typical range is `[0,1]`. 39380 * 39381 * @type {number} 39382 * @default 1 39383 */ 39384 this.bumpScale = 1; 39385 39386 /** 39387 * The texture to create a normal map. The RGB values affect the surface 39388 * normal for each pixel fragment and change the way the color is lit. Normal
39389 * maps do not change the actual shape of the surface, only the lighting. In 39390 * case the material has a normal map authored using the left handed 39391 * convention, the `y` component of `normalScale` should be negated to compensate 39392 * for the different handedness. 39393 * 39394 * @type {?Texture} 39395 * @default null 39396 */ 39397 this.normalMap = null; 39398 39399 /** 39400 * The type of normal map. 39401 * 39402 * @type {(TangentSpaceNormalMap|ObjectSpaceNormalMap)} 39403 * @default TangentSpaceNormalMap 39404 */ 39405 this.normalMapType = TangentSpaceNormalMap; 39406 39407 /** 39408 * How much the normal map affects the material. Typical value range is `[0,1]`. 39409 * 39410 * @type {Vector2} 39411 * @default (1,1) 39412 */ 39413 this.normalScale = new Vector2( 1, 1 ); 39414 39415 /** 39416 * The displacement map affects the position of the mesh's vertices. Unlike 39417 * other maps which only affect the light and shade of the material the 39418 * displaced vertices can cast shadows, block other objects, and otherwise 39419 * act as real geometry. The displacement texture is an image where the value 39420 * of each pixel (white being the highest) is mapped against, and 39421 * repositions, the vertices of the mesh. 39422 * 39423 * @type {?Texture} 39424 * @default null 39425 */ 39426 this.displacementMap = null; 39427 39428 /** 39429 * How much the displacement map affects the mesh (where black is no 39430 * displacement, and white is maximum displacement). Without a displacement 39431 * map set, this value is not applied. 39432 * 39433 * @type {number} 39434 * @default 0 39435 */ 39436 this.displacementScale = 1; 39437 39438 /** 39439 * The offset of the displacement map's values on the mesh's vertices. 39440 * The bias is added to the scaled sample of the displacement map. 39441 * Without a displacement map set, this value is not applied. 39442 * 39443 * @type {number} 39444 * @default 0 39445 */ 39446 this.displacementBias = 0; 39447 39448 /** 39449 * The alpha map is a grayscale texture that controls the opacity across the 39450 * surface (black: fully transparent; white: fully opaque). 39451 * 39452 * Only the color of the texture is used, ignoring the alpha channel if one 39453 * exists. For RGB and RGBA textures, the renderer will use the green channel 39454 * when sampling this texture due to the extra bit of precision provided for 39455 * green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and 39456 * luminance/alpha textures will also still work as expected. 39457 * 39458 * @type {?Texture} 39459 * @default null 39460 */ 39461 this.alphaMap = null; 39462 39463 /** 39464 * Renders the geometry as a wireframe. 39465 * 39466 * @type {boolean} 39467 * @default false 39468 */ 39469 this.wireframe = false; 39470 39471 /** 39472 * Controls the thickness of the wireframe. 39473 * 39474 * Can only be used with {@link SVGRenderer}. 39475 * 39476 * @type {number} 39477 * @default 1 39478 */ 39479 this.wireframeLinewidth = 1; 39480 39481 /** 39482 * Defines appearance of wireframe ends. 39483 * 39484 * Can only be used with {@link SVGRenderer}. 39485 * 39486 * @type {('round'|'bevel'|'miter')} 39487 * @default 'round' 39488 */ 39489 this.wireframeLinecap = 'round'; 39490 39491 /** 39492 * Defines appearance of wireframe joints. 39493 * 39494 * Can only be used with {@link SVGRenderer}. 39495 * 39496 * @type {('round'|'bevel'|'miter')} 39497 * @default 'round' 39498 */ 39499 this.wireframeLinejoin = 'round'; 39500 39501 /** 39502 * Whether the material is affected by fog or not. 39503 * 39504 * @type {boolean} 39505 * @default true 39506 */ 39507 this.fog = true; 39508 39509 this.setValues( parameters ); 39510 39511 } 39512 39513 copy( source ) { 39514 39515 super.copy( source ); 39516 39517 this.color.copy( source.color ); 39518 39519 this.map = source.map; 39520 this.gradientMap = source.gradientMap; 39521 39522 this.lightMap = source.lightMap; 39523 this.lightMapIntensity = source.lightMapIntensity; 39524 39525 this.aoMap = source.aoMap; 39526 this.aoMapIntensity = source.aoMapIntensity; 39527 39528 this.emissive.copy( source.emissive ); 39529 this.emissiveMap = source.emissiveMap; 39530 this.emissiveIntensity = source.emissiveIntensity; 39531 39532 this.bumpMap = source.bumpMap; 39533 this.bumpScale = source.bumpScale; 39534 39535 this.normalMap = source.normalMap; 39536 this.normalMapType = source.normalMapType; 39537 this.normalScale.copy( source.normalScale ); 39538 39539 this.displacementMap = source.displacementMap; 39540 this.displacementScale = source.displacementScale; 39541 this.displacementBias = source.displacementBias; 39542 39543 this.alphaMap = source.alphaMap; 39544 39545 this.wireframe = source.wireframe; 39546 this.wireframeLinewidth = source.wireframeLinewidth; 39547 this.wireframeLinecap = source.wireframeLinecap; 39548 this.wireframeLinejoin = source.wireframeLinejoin; 39549
39550 this.fog = source.fog; 39551 39552 return this; 39553 39554 } 39555 39556} 39557 39558/** 39559 * A material that maps the normal vectors to RGB colors. 39560 * 39561 * @augments Material 39562 * @demo scenes/material-browser.html#MeshNormalMaterial 39563 */ 39564class MeshNormalMaterial extends Material { 39565 39566 /** 39567 * Constructs a new mesh normal material. 39568 * 39569 * @param {Object} [parameters] - An object with one or more properties 39570 * defining the material's appearance. Any property of the material 39571 * (including any property from inherited materials) can be passed 39572 * in here. Color values can be passed any type of value accepted 39573 * by {@link Color#set}. 39574 */ 39575 constructor( parameters ) { 39576 39577 super(); 39578 39579 /** 39580 * This flag can be used for type testing. 39581 * 39582 * @type {boolean} 39583 * @readonly 39584 * @default true 39585 */ 39586 this.isMeshNormalMaterial = true; 39587 39588 this.type = 'MeshNormalMaterial'; 39589 39590 /** 39591 * The texture to create a bump map. The black and white values map to the 39592 * perceived depth in relation to the lights. Bump doesn't actually affect 39593 * the geometry of the object, only the lighting. If a normal map is defined 39594 * this will be ignored. 39595 * 39596 * @type {?Texture} 39597 * @default null 39598 */ 39599 this.bumpMap = null; 39600 39601 /** 39602 * How much the bump map affects the material. Typical range is `[0,1]`. 39603 * 39604 * @type {number} 39605 * @default 1 39606 */ 39607 this.bumpScale = 1; 39608 39609 /** 39610 * The texture to create a normal map. The RGB values affect the surface 39611 * normal for each pixel fragment and change the way the color is lit. Normal 39612 * maps do not change the actual shape of the surface, only the lighting. In 39613 * case the material has a normal map authored using the left handed 39614 * convention, the `y` component of `normalScale` should be negated to compensate 39615 * for the different handedness. 39616 * 39617 * @type {?Texture} 39618 * @default null 39619 */ 39620 this.normalMap = null; 39621 39622 /** 39623 * The type of normal map. 39624 * 39625 * @type {(TangentSpaceNormalMap|ObjectSpaceNormalMap)} 39626 * @default TangentSpaceNormalMap 39627 */ 39628 this.normalMapType = TangentSpaceNormalMap; 39629 39630 /** 39631 * How much the normal map affects the material. Typical value range is `[0,1]`. 39632 * 39633 * @type {Vector2} 39634 * @default (1,1) 39635 */ 39636 this.normalScale = new Vector2( 1, 1 ); 39637 39638 /** 39639 * The displacement map affects the position of the mesh's vertices. Unlike 39640 * other maps which only affect the light and shade of the material the 39641 * displaced vertices can cast shadows, block other objects, and otherwise 39642 * act as real geometry. The displacement texture is an image where the value 39643 * of each pixel (white being the highest) is mapped against, and 39644 * repositions, the vertices of the mesh. 39645 * 39646 * @type {?Texture} 39647 * @default null 39648 */ 39649 this.displacementMap = null; 39650 39651 /** 39652 * How much the displacement map affects the mesh (where black is no 39653 * displacement, and white is maximum displacement). Without a displacement 39654 * map set, this value is not applied. 39655 * 39656 * @type {number} 39657 * @default 0 39658 */ 39659 this.displacementScale = 1; 39660 39661 /** 39662 * The offset of the displacement map's values on the mesh's vertices. 39663 * The bias is added to the scaled sample of the displacement map. 39664 * Without a displacement map set, this value is not applied. 39665 * 39666 * @type {number} 39667 * @default 0 39668 */ 39669 this.displacementBias = 0; 39670 39671 /** 39672 * Renders the geometry as a wireframe. 39673 * 39674 * @type {boolean} 39675 * @default false 39676 */ 39677 this.wireframe = false; 39678 39679 /** 39680 * Controls the thickness of the wireframe. 39681 * 39682 * WebGL and WebGPU ignore this property and always render 39683 * 1 pixel wide lines. 39684 * 39685 * @type {number} 39686 * @default 1 39687 */ 39688 this.wireframeLinewidth = 1; 39689 39690 /** 39691 * Whether the material is rendered with flat shading or not. 39692 * 39693 * @type {boolean} 39694 * @default false 39695 */ 39696 this.flatShading = false; 39697 39698 this.setValues( parameters ); 39699 39700 } 39701 39702 copy( source ) { 39703 39704 super.copy( source ); 39705 39706 this.bumpMap = source.bumpMap; 39707 this.bumpScale = source.bumpScale; 39708 39709 this.normalMap = source.normalMap; 39710 this.normalMapType = source.normalMapType; 39711 this.normalScale.copy( source.normalScale ); 39712 39713 this.displacementMap = source.displacementMap; 39714 this.displacementScale = source.displacementScale; 39715 this.displacementBias = source.displacementBias; 39716 39717 this.wireframe = source.wireframe; 39718 this.wireframeLinewidth = source.wireframeLinewidth; 39719
39720 this.flatShading = source.flatShading; 39721 39722 return this; 39723 39724 } 39725 39726} 39727 39728/** 39729 * A material for non-shiny surfaces, without specular highlights. 39730 * 39731 * The material uses a non-physically based [Lambertian](https://en.wikipedia.org/wiki/Lambertian_reflectance) 39732 * model for calculating reflectance. This can simulate some surfaces (such 39733 * as untreated wood or stone) well, but cannot simulate shiny surfaces with 39734 * specular highlights (such as varnished wood). `MeshLambertMaterial` uses per-fragment 39735 * shading. 39736 * 39737 * Due to the simplicity of the reflectance and illumination models, 39738 * performance will be greater when using this material over the 39739 * {@link MeshPhongMaterial}, {@link MeshStandardMaterial} or 39740 * {@link MeshPhysicalMaterial}, at the cost of some graphical accuracy. 39741 * 39742 * @augments Material 39743 * @demo scenes/material-browser.html#MeshLambertMaterial 39744 */ 39745class MeshLambertMaterial extends Material { 39746 39747 /** 39748 * Constructs a new mesh lambert material. 39749 * 39750 * @param {Object} [parameters] - An object with one or more properties 39751 * defining the material's appearance. Any property of the material 39752 * (including any property from inherited materials) can be passed 39753 * in here. Color values can be passed any type of value accepted 39754 * by {@link Color#set}. 39755 */ 39756 constructor( parameters ) { 39757 39758 super(); 39759 39760 /** 39761 * This flag can be used for type testing. 39762 * 39763 * @type {boolean} 39764 * @readonly 39765 * @default true 39766 */ 39767 this.isMeshLambertMaterial = true; 39768 39769 this.type = 'MeshLambertMaterial'; 39770 39771 /** 39772 * Color of the material. 39773 * 39774 * @type {Color} 39775 * @default (1,1,1) 39776 */ 39777 this.color = new Color( 0xffffff ); // diffuse 39778 39779 /** 39780 * The color map. May optionally include an alpha channel, typically combined 39781 * with {@link Material#transparent} or {@link Material#alphaTest}. The texture map 39782 * color is modulated by the diffuse `color`. 39783 * 39784 * @type {?Texture} 39785 * @default null 39786 */ 39787 this.map = null; 39788 39789 /** 39790 * The light map. Requires a second set of UVs. 39791 * 39792 * @type {?Texture} 39793 * @default null 39794 */ 39795 this.lightMap = null; 39796 39797 /** 39798 * Intensity of the baked light. 39799 * 39800 * @type {number} 39801 * @default 1 39802 */ 39803 this.lightMapIntensity = 1.0; 39804 39805 /** 39806 * The red channel of this texture is used as the ambient occlusion map. 39807 * Requires a second set of UVs. 39808 * 39809 * @type {?Texture} 39810 * @default null 39811 */ 39812 this.aoMap = null; 39813 39814 /** 39815 * Intensity of the ambient occlusion effect. Range is `[0,1]`, where `0` 39816 * disables ambient occlusion. Where intensity is `1` and the AO map's 39817 * red channel is also `1`, ambient light is fully occluded on a surface. 39818 * 39819 * @type {number} 39820 * @default 1 39821 */ 39822 this.aoMapIntensity = 1.0; 39823 39824 /** 39825 * Emissive (light) color of the material, essentially a solid color 39826 * unaffected by other lighting. 39827 * 39828 * @type {Color} 39829 * @default (0,0,0) 39830 */ 39831 this.emissive = new Color( 0x000000 ); 39832 39833 /** 39834 * Intensity of the emissive light. Modulates the emissive color. 39835 * 39836 * @type {number} 39837 * @default 1 39838 */ 39839 this.emissiveIntensity = 1.0; 39840 39841 /** 39842 * Set emissive (glow) map. The emissive map color is modulated by the 39843 * emissive color and the emissive intensity. If you have an emissive map, 39844 * be sure to set the emissive color to something other than black. 39845 * 39846 * @type {?Texture} 39847 * @default null 39848 */ 39849 this.emissiveMap = null; 39850 39851 /** 39852 * The texture to create a bump map. The black and white values map to the 39853 * perceived depth in relation to the lights. Bump doesn't actually affect 39854 * the geometry of the object, only the lighting. If a normal map is defined 39855 * this will be ignored. 39856 * 39857 * @type {?Texture} 39858 * @default null 39859 */ 39860 this.bumpMap = null; 39861 39862 /** 39863 * How much the bump map affects the material. Typical range is `[0,1]`. 39864 * 39865 * @type {number} 39866 * @default 1 39867 */ 39868 this.bumpScale = 1; 39869 39870 /** 39871 * The texture to create a normal map. The RGB values affect the surface 39872 * normal for each pixel fragment and change the way the color is lit. Normal 39873 * maps do not change the actual shape of the surface, only the lighting. In 39874 * case the material has a normal map authored using the left handed 39875 * convention, the `y` component of `normalScale` should be negated to compensate 39876 * for the different handedness. 39877 * 39878 * @type {?Texture} 39879 * @default null 39880 */ 39881 this.normalMap = null; 39882 39883 /** 39884 * The type of normal map. 39885 * 39886 * @type {(TangentSpaceNormalMap|ObjectSpaceNormalMap)} 39887 * @default TangentSpaceNormalMap 39888 */ 39889 this.normalMapType = TangentSpaceNormalMap; 39890 39891 /** 39892 * How much the normal map affects the material. Typical value range is `[0,1]`. 39893 * 39894 * @type {Vector2} 39895 * @default (1,1) 39896 */ 39897 this.normalScale = new Vector2( 1, 1 ); 39898 39899 /** 39900 * The displacement map affects the position of the mesh's vertices. Unlike 39901 * other maps which only affect the light and shade of the material the 39902 * displaced vertices can cast shadows, block other objects, and otherwise 39903 * act as real geometry. The displacement texture is an image where the value 39904 * of each pixel (white being the highest) is mapped against, and 39905 * repositions, the vertices of the mesh. 39906 * 39907 * @type {?Texture} 39908 * @default null 39909 */ 39910 this.displacementMap = null; 39911 39912 /** 39913 * How much the displacement map affects the mesh (where black is no 39914 * displacement, and white is maximum displacement). Without a displacement 39915 * map set, this value is not applied. 39916 * 39917 * @type {number} 39918 * @default 0 39919 */ 39920 this.displacementScale = 1; 39921 39922 /** 39923 * The offset of the displacement map's values on the mesh's vertices. 39924 * The bias is added to the scaled sample of the displacement map. 39925 * Without a displacement map set, this value is not applied. 39926 * 39927 * @type {number} 39928 * @default 0 39929 */ 39930 this.displacementBias = 0; 39931 39932 /** 39933 * Specular map used by the material. 39934 * 39935 * @type {?Texture} 39936 * @default null 39937 */ 39938 this.specularMap = null; 39939 39940 /** 39941 * The alpha map is a grayscale texture that controls the opacity across the 39942 * surface (black: fully transparent; white: fully opaque). 39943 * 39944 * Only the color of the texture is used, ignoring the alpha channel if one 39945 * exists. For RGB and RGBA textures, the renderer will use the green channel 39946 * when sampling this texture due to the extra bit of precision provided for 39947 * green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and 39948 * luminance/alpha textures will also still work as expected. 39949 * 39950 * @type {?Texture} 39951 * @default null 39952 */ 39953 this.alphaMap = null; 39954 39955 /** 39956 * The environment map. 39957 * 39958 * @type {?Texture} 39959 * @default null 39960 */ 39961 this.envMap = null; 39962 39963 /** 39964 * The rotation of the environment map in radians. 39965 * 39966 * @type {Euler} 39967 * @default (0,0,0) 39968 */ 39969 this.envMapRotation = new Euler(); 39970 39971 /** 39972 * How to combine the result of the surface's color with the environment map, if any. 39973 * 39974 * When set to `MixOperation`, the {@link MeshBasicMaterial#reflectivity} is used to 39975 * blend between the two colors. 39976 * 39977 * @type {(MultiplyOperation|MixOperation|AddOperation)} 39978 * @default MultiplyOperation 39979 */ 39980 this.combine = MultiplyOperation; 39981 39982 /** 39983 * How much the environment map affects the surface. 39984 * The valid range is between `0` (no reflections) and `1` (full reflections). 39985 * 39986 * @type {number} 39987 * @default 1 39988 */ 39989 this.reflectivity = 1; 39990 39991 /** 39992 * Scales the effect of the environment map by multiplying its color. 39993 * 39994 * @type {number} 39995 * @default 1 39996 */ 39997 this.envMapIntensity = 1.0; 39998 39999 /** 40000 * The index of refraction (IOR) of air (approximately 1) divided by the 40001 * index of refraction of the material. It is used with environment mapping 40002 * modes {@link CubeRefractionMapping} and {@link EquirectangularRefractionMapping}. 40003 * The refraction ratio should not exceed `1`. 40004 * 40005 * @type {number} 40006 * @default 0.98 40007 */ 40008 this.refractionRatio = 0.98; 40009 40010 /** 40011 * Renders the geometry as a wireframe. 40012 * 40013 * @type {boolean} 40014 * @default false 40015 */ 40016 this.wireframe = false;
40017 40018 /** 40019 * Controls the thickness of the wireframe. 40020 * 40021 * Can only be used with {@link SVGRenderer}. 40022 * 40023 * @type {number} 40024 * @default 1 40025 */ 40026 this.wireframeLinewidth = 1; 40027 40028 /** 40029 * Defines appearance of wireframe ends. 40030 * 40031 * Can only be used with {@link SVGRenderer}. 40032 * 40033 * @type {('round'|'bevel'|'miter')} 40034 * @default 'round' 40035 */ 40036 this.wireframeLinecap = 'round'; 40037 40038 /** 40039 * Defines appearance of wireframe joints. 40040 * 40041 * Can only be used with {@link SVGRenderer}. 40042 * 40043 * @type {('round'|'bevel'|'miter')} 40044 * @default 'round' 40045 */ 40046 this.wireframeLinejoin = 'round'; 40047 40048 /** 40049 * Whether the material is rendered with flat shading or not. 40050 * 40051 * @type {boolean} 40052 * @default false 40053 */ 40054 this.flatShading = false; 40055 40056 /** 40057 * Whether the material is affected by fog or not. 40058 * 40059 * @type {boolean} 40060 * @default true 40061 */ 40062 this.fog = true; 40063 40064 this.setValues( parameters ); 40065 40066 } 40067 40068 copy( source ) { 40069 40070 super.copy( source ); 40071 40072 this.color.copy( source.color ); 40073 40074 this.map = source.map; 40075 40076 this.lightMap = source.lightMap; 40077 this.lightMapIntensity = source.lightMapIntensity; 40078 40079 this.aoMap = source.aoMap; 40080 this.aoMapIntensity = source.aoMapIntensity; 40081 40082 this.emissive.copy( source.emissive ); 40083 this.emissiveMap = source.emissiveMap; 40084 this.emissiveIntensity = source.emissiveIntensity; 40085 40086 this.bumpMap = source.bumpMap; 40087 this.bumpScale = source.bumpScale; 40088 40089 this.normalMap = source.normalMap; 40090 this.normalMapType = source.normalMapType; 40091 this.normalScale.copy( source.normalScale ); 40092 40093 this.displacementMap = source.displacementMap; 40094 this.displacementScale = source.displacementScale; 40095 this.displacementBias = source.displacementBias; 40096 40097 this.specularMap = source.specularMap; 40098 40099 this.alphaMap = source.alphaMap; 40100 40101 this.envMap = source.envMap; 40102 this.envMapRotation.copy( source.envMapRotation ); 40103 this.combine = source.combine; 40104 this.reflectivity = source.reflectivity; 40105 this.envMapIntensity = source.envMapIntensity; 40106 this.refractionRatio = source.refractionRatio; 40107 40108 this.wireframe = source.wireframe; 40109 this.wireframeLinewidth = source.wireframeLinewidth; 40110 this.wireframeLinecap = source.wireframeLinecap; 40111 this.wireframeLinejoin = source.wireframeLinejoin; 40112 40113 this.flatShading = source.flatShading; 40114 40115 this.fog = source.fog; 40116 40117 return this; 40118 40119 } 40120 40121} 40122 40123/** 40124 * A material for drawing geometry by depth. Depth is based off of the camera 40125 * near and far plane. White is nearest, black is farthest. 40126 * 40127 * @augments Material 40128 * @demo scenes/material-browser.html#MeshDepthMaterial 40129 */ 40130class MeshDepthMaterial extends Material { 40131 40132 /** 40133 * Constructs a new mesh depth material. 40134 * 40135 * @param {Object} [parameters] - An object with one or more properties 40136 * defining the material's appearance. Any property of the material 40137 * (including any property from inherited materials) can be passed 40138 * in here. Color values can be passed any type of value accepted 40139 * by {@link Color#set}. 40140 */ 40141 constructor( parameters ) { 40142 40143 super(); 40144 40145 /** 40146 * This flag can be used for type testing. 40147 * 40148 * @type {boolean} 40149 * @readonly 40150 * @default true 40151 */ 40152 this.isMeshDepthMaterial = true; 40153 40154 this.type = 'MeshDepthMaterial'; 40155 40156 /** 40157 * Type for depth packing. 40158 * 40159 * @type {(BasicDepthPacking|RGBADepthPacking|RGBDepthPacking|RGDepthPacking)} 40160 * @default BasicDepthPacking 40161 */ 40162 this.depthPacking = BasicDepthPacking; 40163 40164 /** 40165 * The color map. May optionally include an alpha channel, typically combined 40166 * with {@link Material#transparent} or {@link Material#alphaTest}. 40167 * 40168 * @type {?Texture} 40169 * @default null 40170 */ 40171 this.map = null; 40172 40173 /** 40174 * The alpha map is a grayscale texture that controls the opacity across the 40175 * surface (black: fully transparent; white: fully opaque). 40176 * 40177 * Only the color of the texture is used, ignoring the alpha channel if one 40178 * exists. For RGB and RGBA textures, the renderer will use the green channel 40179 * when sampling this texture due to the extra bit of precision provided for 40180 * green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and 40181 * luminance/alpha textures will also still work as expected. 40182 * 40183 * @type {?Texture} 40184 * @default null 40185 */ 40186 this.alphaMap = null; 40187 40188 /** 40189 * The displacement map affects the position of the mesh's vertices. Unlike 40190 * other maps which only affect the light and shade of the material the 40191 * displaced vertices can cast shadows, block other objects, and otherwise 40192 * act as real geometry. The displacement texture is an image where the value 40193 * of each pixel (white being the highest) is mapped against, and 40194 * repositions, the vertices of the mesh. 40195 * 40196 * @type {?Texture} 40197 * @default null 40198 */ 40199 this.displacementMap = null; 40200 40201 /** 40202 * How much the displacement map affects the mesh (where black is no 40203 * displacement, and white is maximum displacement). Without a displacement 40204 * map set, this value is not applied. 40205 * 40206 * @type {number} 40207 * @default 0 40208 */ 40209 this.displacementScale = 1; 40210 40211 /** 40212 * The offset of the displacement map's values on the mesh's vertices. 40213 * The bias is added to the scaled sample of the displacement map. 40214 * Without a displacement map set, this value is not applied. 40215 * 40216 * @type {number} 40217 * @default 0 40218 */ 40219 this.displacementBias = 0; 40220 40221 /** 40222 * Renders the geometry as a wireframe. 40223 * 40224 * @type {boolean} 40225 * @default false 40226 */ 40227 this.wireframe = false;
40228 40229 /** 40230 * Controls the thickness of the wireframe. 40231 * 40232 * WebGL and WebGPU ignore this property and always render 40233 * 1 pixel wide lines. 40234 * 40235 * @type {number} 40236 * @default 1 40237 */ 40238 this.wireframeLinewidth = 1; 40239 40240 this.setValues( parameters ); 40241 40242 } 40243 40244 copy( source ) { 40245 40246 super.copy( source ); 40247 40248 this.depthPacking = source.depthPacking; 40249 40250 this.map = source.map; 40251 40252 this.alphaMap = source.alphaMap; 40253 40254 this.displacementMap = source.displacementMap; 40255 this.displacementScale = source.displacementScale; 40256 this.displacementBias = source.displacementBias; 40257 40258 this.wireframe = source.wireframe; 40259 this.wireframeLinewidth = source.wireframeLinewidth; 40260 40261 return this; 40262 40263 } 40264 40265} 40266 40267/** 40268 * A material used internally for implementing shadow mapping with 40269 * point lights. 40270 * 40271 * Can also be used to customize the shadow casting of an object by assigning 40272 * an instance of `MeshDistanceMaterial` to {@link Object3D#customDistanceMaterial}. 40273 * The following examples demonstrates this approach in order to ensure 40274 * transparent parts of objects do not cast shadows. 40275 * 40276 * @augments Material 40277 */ 40278class MeshDistanceMaterial extends Material { 40279 40280 /** 40281 * Constructs a new mesh distance material. 40282 * 40283 * @param {Object} [parameters] - An object with one or more properties 40284 * defining the material's appearance. Any property of the material 40285 * (including any property from inherited materials) can be passed 40286 * in here. Color values can be passed any type of value accepted 40287 * by {@link Color#set}. 40288 */ 40289 constructor( parameters ) { 40290 40291 super(); 40292 40293 /** 40294 * This flag can be used for type testing. 40295 * 40296 * @type {boolean} 40297 * @readonly 40298 * @default true 40299 */ 40300 this.isMeshDistanceMaterial = true; 40301 40302 this.type = 'MeshDistanceMaterial'; 40303 40304 /** 40305 * The color map. May optionally include an alpha channel, typically combined 40306 * with {@link Material#transparent} or {@link Material#alphaTest}. 40307 * 40308 * @type {?Texture} 40309 * @default null 40310 */ 40311 this.map = null; 40312 40313 /** 40314 * The alpha map is a grayscale texture that controls the opacity across the 40315 * surface (black: fully transparent; white: fully opaque). 40316 * 40317 * Only the color of the texture is used, ignoring the alpha channel if one 40318 * exists. For RGB and RGBA textures, the renderer will use the green channel 40319 * when sampling this texture due to the extra bit of precision provided for 40320 * green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and 40321 * luminance/alpha textures will also still work as expected. 40322 * 40323 * @type {?Texture} 40324 * @default null 40325 */ 40326 this.alphaMap = null; 40327 40328 /** 40329 * The displacement map affects the position of the mesh's vertices. Unlike 40330 * other maps which only affect the light and shade of the material the 40331 * displaced vertices can cast shadows, block other objects, and otherwise 40332 * act as real geometry. The displacement texture is an image where the value 40333 * of each pixel (white being the highest) is mapped against, and 40334 * repositions, the vertices of the mesh. 40335 * 40336 * @type {?Texture} 40337 * @default null 40338 */ 40339 this.displacementMap = null; 40340 40341 /** 40342 * How much the displacement map affects the mesh (where black is no 40343 * displacement, and white is maximum displacement). Without a displacement 40344 * map set, this value is not applied. 40345 * 40346 * @type {number} 40347 * @default 0 40348 */ 40349 this.displacementScale = 1; 40350 40351 /** 40352 * The offset of the displacement map's values on the mesh's vertices. 40353 * The bias is added to the scaled sample of the displacement map. 40354 * Without a displacement map set, this value is not applied. 40355 * 40356 * @type {number} 40357 * @default 0 40358 */ 40359 this.displacementBias = 0; 40360 40361 this.setValues( parameters ); 40362 40363 } 40364 40365 copy( source ) { 40366 40367 super.copy( source ); 40368 40369 this.map = source.map; 40370 40371 this.alphaMap = source.alphaMap; 40372 40373 this.displacementMap = source.displacementMap; 40374 this.displacementScale = source.displacementScale; 40375 this.displacementBias = source.displacementBias; 40376 40377 return this; 40378 40379 } 40380 40381} 40382 40383/** 40384 * This material is defined by a MatCap (or Lit Sphere) texture, which encodes the 40385 * material color and shading. 40386 * 40387 * `MeshMatcapMaterial` does not respond to lights since the matcap image file encodes 40388 * baked lighting. It will cast a shadow onto an object that receives shadows 40389 * (and shadow clipping works), but it will not self-shadow or receive 40390 * shadows. 40391 * 40392 * @augments Material 40393 * @demo scenes/material-browser.html#MeshMatcapMaterial 40394 */ 40395class MeshMatcapMaterial extends Material { 40396 40397 /** 40398 * Constructs a new mesh matcap material. 40399 * 40400 * @param {Object} [parameters] - An object with one or more properties 40401 * defining the material's appearance. Any property of the material 40402 * (including any property from inherited materials) can be passed 40403 * in here. Color values can be passed any type of value accepted 40404 * by {@link Color#set}. 40405 */ 40406 constructor( parameters ) { 40407 40408 super(); 40409 40410 /** 40411 * This flag can be used for type testing. 40412 * 40413 * @type {boolean} 40414 * @readonly 40415 * @default true 40416 */
40417 this.isMeshMatcapMaterial = true; 40418 40419 this.defines = { 'MATCAP': '' }; 40420 40421 this.type = 'MeshMatcapMaterial'; 40422 40423 /** 40424 * Color of the material. 40425 * 40426 * @type {Color} 40427 * @default (1,1,1) 40428 */ 40429 this.color = new Color( 0xffffff ); // diffuse 40430 40431 /** 40432 * The matcap map. 40433 * 40434 * @type {?Texture} 40435 * @default null 40436 */ 40437 this.matcap = null; 40438 40439 /** 40440 * The color map. May optionally include an alpha channel, typically combined 40441 * with {@link Material#transparent} or {@link Material#alphaTest}. The texture map 40442 * color is modulated by the diffuse `color`. 40443 * 40444 * @type {?Texture} 40445 * @default null 40446 */ 40447 this.map = null; 40448 40449 /** 40450 * The texture to create a bump map. The black and white values map to the 40451 * perceived depth in relation to the lights. Bump doesn't actually affect 40452 * the geometry of the object, only the lighting. If a normal map is defined 40453 * this will be ignored. 40454 * 40455 * @type {?Texture} 40456 * @default null 40457 */ 40458 this.bumpMap = null; 40459 40460 /** 40461 * How much the bump map affects the material. Typical range is `[0,1]`. 40462 * 40463 * @type {number} 40464 * @default 1 40465 */ 40466 this.bumpScale = 1; 40467 40468 /** 40469 * The texture to create a normal map. The RGB values affect the surface 40470 * normal for each pixel fragment and change the way the color is lit. Normal 40471 * maps do not change the actual shape of the surface, only the lighting. In 40472 * case the material has a normal map authored using the left handed 40473 * convention, the `y` component of `normalScale` should be negated to compensate 40474 * for the different handedness. 40475 * 40476 * @type {?Texture} 40477 * @default null 40478 */ 40479 this.normalMap = null; 40480 40481 /** 40482 * The type of normal map. 40483 * 40484 * @type {(TangentSpaceNormalMap|ObjectSpaceNormalMap)} 40485 * @default TangentSpaceNormalMap 40486 */ 40487 this.normalMapType = TangentSpaceNormalMap; 40488 40489 /** 40490 * How much the normal map affects the material. Typical value range is `[0,1]`. 40491 * 40492 * @type {Vector2} 40493 * @default (1,1) 40494 */ 40495 this.normalScale = new Vector2( 1, 1 ); 40496 40497 /** 40498 * The displacement map affects the position of the mesh's vertices. Unlike 40499 * other maps which only affect the light and shade of the material the 40500 * displaced vertices can cast shadows, block other objects, and otherwise 40501 * act as real geometry. The displacement texture is an image where the value 40502 * of each pixel (white being the highest) is mapped against, and 40503 * repositions, the vertices of the mesh. 40504 * 40505 * @type {?Texture} 40506 * @default null 40507 */ 40508 this.displacementMap = null; 40509 40510 /** 40511 * How much the displacement map affects the mesh (where black is no 40512 * displacement, and white is maximum displacement). Without a displacement 40513 * map set, this value is not applied. 40514 * 40515 * @type {number} 40516 * @default 0 40517 */ 40518 this.displacementScale = 1; 40519 40520 /** 40521 * The offset of the displacement map's values on the mesh's vertices. 40522 * The bias is added to the scaled sample of the displacement map. 40523 * Without a displacement map set, this value is not applied. 40524 * 40525 * @type {number} 40526 * @default 0 40527 */ 40528 this.displacementBias = 0; 40529 40530 /** 40531 * The alpha map is a grayscale texture that controls the opacity across the 40532 * surface (black: fully transparent; white: fully opaque). 40533 * 40534 * Only the color of the texture is used, ignoring the alpha channel if one 40535 * exists. For RGB and RGBA textures, the renderer will use the green channel 40536 * when sampling this texture due to the extra bit of precision provided for 40537 * green in DXT-compressed and uncompressed RGB 565 formats. Luminance-only and 40538 * luminance/alpha textures will also still work as expected. 40539 * 40540 * @type {?Texture} 40541 * @default null 40542 */ 40543 this.alphaMap = null; 40544 40545 /** 40546 * Renders the geometry as a wireframe. 40547 * 40548 * @type {boolean} 40549 * @default false 40550 */ 40551 this.wireframe = false; 40552 40553 /** 40554 * Controls the thickness of the wireframe. 40555 * 40556 * Can only be used with {@link SVGRenderer}. 40557 * 40558 * @type {number} 40559 * @default 1 40560 */ 40561 this.wireframeLinewidth = 1; 40562 40563 /** 40564 * Whether the material is rendered with flat shading or not. 40565 * 40566 * @type {boolean} 40567 * @default false 40568 */ 40569 this.flatShading = false;
vendor: 13,654 bytes, lines 40570-41167
40570 40571 /** 40572 * Whether the material is affected by fog or not. 40573 * 40574 * @type {boolean} 40575 * @default true 40576 */ 40577 this.fog = true; 40578 40579 this.setValues( parameters ); 40580 40581 } 40582 40583 40584 copy( source ) { 40585 40586 super.copy( source ); 40587 40588 this.defines = { 'MATCAP': '' }; 40589 40590 this.color.copy( source.color ); 40591 40592 this.matcap = source.matcap; 40593 40594 this.map = source.map; 40595 40596 this.bumpMap = source.bumpMap; 40597 this.bumpScale = source.bumpScale; 40598 40599 this.normalMap = source.normalMap; 40600 this.normalMapType = source.normalMapType; 40601 this.normalScale.copy( source.normalScale ); 40602 40603 this.displacementMap = source.displacementMap; 40604 this.displacementScale = source.displacementScale; 40605 this.displacementBias = source.displacementBias; 40606 40607 this.alphaMap = source.alphaMap; 40608 40609 this.wireframe = source.wireframe; 40610 this.wireframeLinewidth = source.wireframeLinewidth; 40611 40612 this.flatShading = source.flatShading; 40613 40614 this.fog = source.fog; 40615 40616 return this; 40617 40618 } 40619 40620} 40621 40622/** 40623 * A material for rendering line primitives. 40624 * 40625 * Materials define the appearance of renderable 3D objects. 40626 * 40627 * ```js 40628 * const material = new THREE.LineDashedMaterial( { 40629 * color: 0xffffff, 40630 * scale: 1, 40631 * dashSize: 3, 40632 * gapSize: 1, 40633 * } ); 40634 * ``` 40635 * 40636 * @augments LineBasicMaterial 40637 */ 40638class LineDashedMaterial extends LineBasicMaterial { 40639 40640 /** 40641 * Constructs a new line dashed material. 40642 * 40643 * @param {Object} [parameters] - An object with one or more properties 40644 * defining the material's appearance. Any property of the material 40645 * (including any property from inherited materials) can be passed 40646 * in here. Color values can be passed any type of value accepted 40647 * by {@link Color#set}. 40648 */ 40649 constructor( parameters ) { 40650 40651 super(); 40652 40653 /** 40654 * This flag can be used for type testing. 40655 * 40656 * @type {boolean} 40657 * @readonly 40658 * @default true 40659 */ 40660 this.isLineDashedMaterial = true; 40661 this.type = 'LineDashedMaterial'; 40662 40663 /** 40664 * The scale of the dashed part of a line. 40665 * 40666 * @type {number} 40667 * @default 1 40668 */ 40669 this.scale = 1; 40670 40671 /** 40672 * The size of the dash. This is both the gap with the stroke. 40673 * 40674 * @type {number} 40675 * @default 3 40676 */ 40677 this.dashSize = 3; 40678 40679 /** 40680 * The size of the gap. 40681 * 40682 * @type {number} 40683 * @default 1 40684 */ 40685 this.gapSize = 1; 40686 40687 this.setValues( parameters ); 40688 40689 } 40690 40691 copy( source ) { 40692 40693 super.copy( source ); 40694 40695 this.scale = source.scale; 40696 this.dashSize = source.dashSize; 40697 this.gapSize = source.gapSize; 40698 40699 return this; 40700 40701 } 40702 40703} 40704 40705/** 40706 * Converts an array to a specific type. 40707 * 40708 * @param {TypedArray|Array} array - The array to convert. 40709 * @param {TypedArray.constructor} type - The constructor of a typed array that defines the new type. 40710 * @return {TypedArray} The converted array. 40711 */ 40712function convertArray( array, type ) { 40713 40714 if ( ! array || array.constructor === type ) return array; 40715 40716 if ( typeof type.BYTES_PER_ELEMENT === 'number' ) { 40717 40718 return new type( array ); // create typed array 40719 40720 } 40721 40722 return Array.prototype.slice.call( array ); // create Array 40723 40724} 40725 40726/** 40727 * Returns an array by which times and values can be sorted. 40728 * 40729 * @param {Array<number>} times - The keyframe time values. 40730 * @return {Array<number>} The array. 40731 */ 40732function getKeyframeOrder( times ) { 40733 40734 function compareTime( i, j ) { 40735 40736 return times[ i ] - times[ j ]; 40737 40738 } 40739 40740 const n = times.length; 40741 const result = new Array( n ); 40742 for ( let i = 0; i !== n; ++ i ) result[ i ] = i; 40743 40744 result.sort( compareTime ); 40745 40746 return result; 40747 40748} 40749 40750/** 40751 * Sorts the given array by the previously computed order via `getKeyframeOrder()`. 40752 * 40753 * @param {Array<number>} values - The values to sort. 40754 * @param {number} stride - The stride. 40755 * @param {Array<number>} order - The sort order. 40756 * @return {Array<number>} The sorted values. 40757 */ 40758function sortedArray( values, stride, order ) { 40759 40760 const nValues = values.length; 40761 const result = new values.constructor( nValues ); 40762 40763 for ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) { 40764 40765 const srcOffset = order[ i ] * stride; 40766 40767 for ( let j = 0; j !== stride; ++ j ) { 40768 40769 result[ dstOffset ++ ] = values[ srcOffset + j ]; 40770 40771 } 40772 40773 } 40774 40775 return result; 40776 40777} 40778 40779/** 40780 * Used for parsing AOS keyframe formats. 40781 * 40782 * @param {Array<number>} jsonKeys - A list of JSON keyframes. 40783 * @param {Array<number>} times - This array will be filled with keyframe times by this function. 40784 * @param {Array<number>} values - This array will be filled with keyframe values by this function. 40785 * @param {string} valuePropertyName - The name of the property to use. 40786 */ 40787function flattenJSON( jsonKeys, times, values, valuePropertyName ) { 40788 40789 let i = 1, key = jsonKeys[ 0 ]; 40790 40791 while ( key !== undefined && key[ valuePropertyName ] === undefined ) { 40792 40793 key = jsonKeys[ i ++ ]; 40794 40795 } 40796 40797 if ( key === undefined ) return; // no data 40798 40799 let value = key[ valuePropertyName ]; 40800 if ( value === undefined ) return; // no data 40801 40802 if ( Array.isArray( value ) ) { 40803 40804 do { 40805 40806 value = key[ valuePropertyName ]; 40807 40808 if ( value !== undefined ) { 40809 40810 times.push( key.time ); 40811 values.push( ...value ); // push all elements 40812 40813 } 40814 40815 key = jsonKeys[ i ++ ]; 40816 40817 } while ( key !== undefined ); 40818 40819 } else if ( value.toArray !== undefined ) { 40820 40821 // ...assume THREE.Math-ish 40822 40823 do { 40824 40825 value = key[ valuePropertyName ]; 40826 40827 if ( value !== undefined ) { 40828 40829 times.push( key.time ); 40830 value.toArray( values, values.length ); 40831 40832 } 40833 40834 key = jsonKeys[ i ++ ]; 40835 40836 } while ( key !== undefined ); 40837 40838 } else { 40839 40840 // otherwise push as-is 40841 40842 do { 40843 40844 value = key[ valuePropertyName ]; 40845 40846 if ( value !== undefined ) { 40847 40848 times.push( key.time ); 40849 values.push( value ); 40850 40851 } 40852 40853 key = jsonKeys[ i ++ ]; 40854 40855 } while ( key !== undefined ); 40856 40857 } 40858 40859} 40860 40861/** 40862 * Creates a new clip, containing only the segment of the original clip between the given frames. 40863 * 40864 * @param {AnimationClip} sourceClip - The values to sort. 40865 * @param {string} name - The name of the clip. 40866 * @param {number} startFrame - The start frame. 40867 * @param {number} endFrame - The end frame. 40868 * @param {number} [fps=30] - The FPS. 40869 * @return {AnimationClip} The new sub clip. 40870 */ 40871function subclip( sourceClip, name, startFrame, endFrame, fps = 30 ) { 40872 40873 const clip = sourceClip.clone(); 40874 40875 clip.name = name; 40876 40877 const tracks = []; 40878 40879 for ( let i = 0; i < clip.tracks.length; ++ i ) { 40880 40881 const track = clip.tracks[ i ]; 40882 const valueSize = track.getValueSize(); 40883 40884 const times = []; 40885 const values = []; 40886 40887 for ( let j = 0; j < track.times.length; ++ j ) { 40888 40889 const frame = track.times[ j ] * fps; 40890 40891 if ( frame < startFrame || frame >= endFrame ) continue; 40892 40893 times.push( track.times[ j ] ); 40894 40895 for ( let k = 0; k < valueSize; ++ k ) { 40896 40897 values.push( track.values[ j * valueSize + k ] ); 40898 40899 } 40900 40901 } 40902 40903 if ( times.length === 0 ) continue; 40904 40905 track.times = convertArray( times, track.times.constructor ); 40906 track.values = convertArray( values, track.values.constructor ); 40907 40908 tracks.push( track ); 40909 40910 } 40911 40912 clip.tracks = tracks; 40913 40914 // find minimum .times value across all tracks in the trimmed clip 40915 40916 let minStartTime = Infinity; 40917 40918 for ( let i = 0; i < clip.tracks.length; ++ i ) { 40919 40920 if ( minStartTime > clip.tracks[ i ].times[ 0 ] ) { 40921 40922 minStartTime = clip.tracks[ i ].times[ 0 ]; 40923 40924 } 40925 40926 } 40927 40928 // shift all tracks such that clip begins at t=0 40929 40930 for ( let i = 0; i < clip.tracks.length; ++ i ) { 40931 40932 clip.tracks[ i ].shift( -1 * minStartTime ); 40933 40934 } 40935 40936 clip.resetDuration(); 40937 40938 return clip; 40939 40940} 40941 40942/** 40943 * Converts the keyframes of the given animation clip to an additive format. 40944 * 40945 * @param {AnimationClip} targetClip - The clip to make additive. 40946 * @param {number} [referenceFrame=0] - The reference frame. 40947 * @param {AnimationClip} [referenceClip=targetClip] - The reference clip. 40948 * @param {number} [fps=30] - The FPS. 40949 * @return {AnimationClip} The updated clip which is now additive. 40950 */ 40951function makeClipAdditive( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) { 40952 40953 if ( fps <= 0 ) fps = 30; 40954 40955 const numTracks = referenceClip.tracks.length; 40956 const referenceTime = referenceFrame / fps; 40957 40958 // Make each track's values relative to the values at the reference frame 40959 for ( let i = 0; i < numTracks; ++ i ) { 40960 40961 const referenceTrack = referenceClip.tracks[ i ]; 40962 const referenceTrackType = referenceTrack.ValueTypeName; 40963 40964 // Skip this track if it's non-numeric 40965 if ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue; 40966 40967 // Find the track in the target clip whose name and type matches the reference track 40968 const targetTrack = targetClip.tracks.find( function ( track ) { 40969 40970 return track.name === referenceTrack.name 40971 && track.ValueTypeName === referenceTrackType; 40972 40973 } ); 40974 40975 if ( targetTrack === undefined ) continue; 40976 40977 let referenceOffset = 0; 40978 const referenceValueSize = referenceTrack.getValueSize(); 40979 40980 if ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { 40981 40982 referenceOffset = referenceValueSize / 3; 40983 40984 } 40985 40986 let targetOffset = 0; 40987 const targetValueSize = targetTrack.getValueSize(); 40988 40989 if ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) { 40990 40991 targetOffset = targetValueSize / 3; 40992 40993 } 40994 40995 const lastIndex = referenceTrack.times.length - 1; 40996 let referenceValue; 40997 40998 // Find the value to subtract out of the track 40999 if ( referenceTime <= referenceTrack.times[ 0 ] ) { 41000 41001 // Reference frame is earlier than the first keyframe, so just use the first keyframe 41002 const startIndex = referenceOffset; 41003 const endIndex = referenceValueSize - referenceOffset; 41004 referenceValue = referenceTrack.values.slice( startIndex, endIndex ); 41005 41006 } else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) { 41007 41008 // Reference frame is after the last keyframe, so just use the last keyframe 41009 const startIndex = lastIndex * referenceValueSize + referenceOffset; 41010 const endIndex = startIndex + referenceValueSize - referenceOffset; 41011 referenceValue = referenceTrack.values.slice( startIndex, endIndex ); 41012 41013 } else { 41014 41015 // Interpolate to the reference value 41016 const interpolant = referenceTrack.createInterpolant(); 41017 const startIndex = referenceOffset; 41018 const endIndex = referenceValueSize - referenceOffset; 41019 interpolant.evaluate( referenceTime ); 41020 referenceValue = interpolant.resultBuffer.slice( startIndex, endIndex ); 41021 41022 } 41023 41024 // Conjugate the quaternion 41025 if ( referenceTrackType === 'quaternion' ) { 41026 41027 const referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate(); 41028 referenceQuat.toArray( referenceValue ); 41029 41030 } 41031 41032 // Subtract the reference value from all of the track values 41033 41034 const numTimes = targetTrack.times.length; 41035 for ( let j = 0; j < numTimes; ++ j ) { 41036 41037 const valueStart = j * targetValueSize + targetOffset; 41038 41039 if ( referenceTrackType === 'quaternion' ) { 41040 41041 // Multiply the conjugate for quaternion track types 41042 Quaternion.multiplyQuaternionsFlat( 41043 targetTrack.values, 41044 valueStart, 41045 referenceValue, 41046 0, 41047 targetTrack.values, 41048 valueStart 41049 ); 41050 41051 } else { 41052 41053 const valueEnd = targetValueSize - targetOffset * 2; 41054 41055 // Subtract each value for all other numeric track types 41056 for ( let k = 0; k < valueEnd; ++ k ) { 41057 41058 targetTrack.values[ valueStart + k ] -= referenceValue[ k ]; 41059 41060 } 41061 41062 } 41063 41064 } 41065 41066 } 41067 41068 targetClip.blendMode = AdditiveAnimationBlendMode; 41069 41070 return targetClip; 41071 41072} 41073 41074/** 41075 * A class with various methods to assist with animations. 41076 * 41077 * @hideconstructor 41078 */ 41079class AnimationUtils { 41080 41081 /** 41082 * Converts an array to a specific type 41083 * 41084 * @static 41085 * @param {TypedArray|Array} array - The array to convert. 41086 * @param {TypedArray.constructor} type - The constructor of a type array. 41087 * @return {TypedArray} The converted array 41088 */ 41089 static convertArray( array, type ) { 41090 41091 return convertArray( array, type ); 41092 41093 } 41094 41095 /** 41096 * Returns `true` if the given object is a typed array. 41097 * 41098 * @static 41099 * @param {any} object - The object to check. 41100 * @return {boolean} Whether the given object is a typed array. 41101 */ 41102 static isTypedArray( object ) { 41103 41104 return isTypedArray( object ); 41105 41106 } 41107 41108 /** 41109 * Returns an array by which times and values can be sorted. 41110 * 41111 * @static 41112 * @param {Array<number>} times - The keyframe time values. 41113 * @return {Array<number>} The array. 41114 */ 41115 static getKeyframeOrder( times ) { 41116 41117 return getKeyframeOrder( times ); 41118 41119 } 41120 41121 /** 41122 * Sorts the given array by the previously computed order via `getKeyframeOrder()`. 41123 * 41124 * @static 41125 * @param {Array<number>} values - The values to sort. 41126 * @param {number} stride - The stride. 41127 * @param {Array<number>} order - The sort order. 41128 * @return {Array<number>} The sorted values. 41129 */ 41130 static sortedArray( values, stride, order ) { 41131 41132 return sortedArray( values, stride, order ); 41133 41134 } 41135 41136 /** 41137 * Used for parsing AOS keyframe formats. 41138 * 41139 * @static 41140 * @param {Array<number>} jsonKeys - A list of JSON keyframes. 41141 * @param {Array<number>} times - This array will be filled with keyframe times by this method. 41142 * @param {Array<number>} values - This array will be filled with keyframe values by this method. 41143 * @param {string} valuePropertyName - The name of the property to use. 41144 */ 41145 static flattenJSON( jsonKeys, times, values, valuePropertyName ) { 41146 41147 flattenJSON( jsonKeys, times, values, valuePropertyName ); 41148 41149 } 41150 41151 /** 41152 * Creates a new clip, containing only the segment of the original clip between the given frames. 41153 * 41154 * @static 41155 * @param {AnimationClip} sourceClip - The values to sort. 41156 * @param {string} name - The name of the clip. 41157 * @param {number} startFrame - The start frame. 41158 * @param {number} endFrame - The end frame. 41159 * @param {number} [fps=30] - The FPS. 41160 * @return {AnimationClip} The new sub clip. 41161 */ 41162 static subclip( sourceClip, name, startFrame, endFrame, fps = 30 ) { 41163 41164 return subclip( sourceClip, name, startFrame, endFrame, fps ); 41165 41166 } 41167
41168 /** 41169 * Converts the keyframes of the given animation clip to an additive format. 41170 * 41171 * @static 41172 * @param {AnimationClip} targetClip - The clip to make additive. 41173 * @param {number} [referenceFrame=0] - The reference frame. 41174 * @param {AnimationClip} [referenceClip=targetClip] - The reference clip. 41175 * @param {number} [fps=30] - The FPS. 41176 * @return {AnimationClip} The updated clip which is now additive. 41177 */ 41178 static makeClipAdditive( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) { 41179 41180 return makeClipAdditive( targetClip, referenceFrame, referenceClip, fps
vendor: 34,349 bytes, lines 41180-42758
41180 ); 41181 41182 } 41183 41184} 41185 41186/** 41187 * Abstract base class of interpolants over parametric samples. 41188 * 41189 * The parameter domain is one dimensional, typically the time or a path 41190 * along a curve defined by the data. 41191 * 41192 * The sample values can have any dimensionality and derived classes may 41193 * apply special interpretations to the data. 41194 * 41195 * This class provides the interval seek in a Template Method, deferring 41196 * the actual interpolation to derived classes. 41197 * 41198 * Time complexity is O(1) for linear access crossing at most two points 41199 * and O(log N) for random access, where N is the number of positions. 41200 * 41201 * References: {@link http://www.oodesign.com/template-method-pattern.html} 41202 * 41203 * @abstract 41204 */ 41205class Interpolant { 41206 41207 /** 41208 * Constructs a new interpolant. 41209 * 41210 * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors. 41211 * @param {TypedArray} sampleValues - The sample values. 41212 * @param {number} sampleSize - The sample size 41213 * @param {TypedArray} [resultBuffer] - The result buffer. 41214 */ 41215 constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { 41216 41217 /** 41218 * The parameter positions. 41219 * 41220 * @type {TypedArray} 41221 */ 41222 this.parameterPositions = parameterPositions; 41223 41224 /** 41225 * A cache index. 41226 * 41227 * @private 41228 * @type {number} 41229 * @default 0 41230 */ 41231 this._cachedIndex = 0; 41232 41233 /** 41234 * The result buffer. 41235 * 41236 * @type {TypedArray} 41237 */ 41238 this.resultBuffer = resultBuffer !== undefined ? resultBuffer : new sampleValues.constructor( sampleSize ); 41239 41240 /** 41241 * The sample values. 41242 * 41243 * @type {TypedArray} 41244 */ 41245 this.sampleValues = sampleValues; 41246 41247 /** 41248 * The value size. 41249 * 41250 * @type {TypedArray} 41251 */ 41252 this.valueSize = sampleSize; 41253 41254 /** 41255 * The interpolation settings. 41256 * 41257 * @type {?Object} 41258 * @default null 41259 */ 41260 this.settings = null; 41261 41262 /** 41263 * The default settings object. 41264 * 41265 * @type {Object} 41266 */ 41267 this.DefaultSettings_ = {}; 41268 41269 } 41270 41271 /** 41272 * Evaluate the interpolant at position `t`. 41273 * 41274 * @param {number} t - The interpolation factor. 41275 * @return {TypedArray} The result buffer. 41276 */ 41277 evaluate( t ) { 41278 41279 const pp = this.parameterPositions; 41280 let i1 = this._cachedIndex, 41281 t1 = pp[ i1 ], 41282 t0 = pp[ i1 - 1 ]; 41283 41284 validate_interval: { 41285 41286 seek: { 41287 41288 let right; 41289 41290 linear_scan: { 41291 41292 //- See http://jsperf.com/comparison-to-undefined/3 41293 //- slower code: 41294 //- 41295 //- if ( t >= t1 || t1 === undefined ) { 41296 forward_scan: if ( ! ( t < t1 ) ) { 41297 41298 for ( let giveUpAt = i1 + 2; ; ) { 41299 41300 if ( t1 === undefined ) { 41301 41302 if ( t < t0 ) break forward_scan; 41303 41304 // after end 41305 41306 i1 = pp.length; 41307 this._cachedIndex = i1; 41308 return this.copySampleValue_( i1 - 1 ); 41309 41310 } 41311 41312 if ( i1 === giveUpAt ) break; // this loop 41313 41314 t0 = t1; 41315 t1 = pp[ ++ i1 ]; 41316 41317 if ( t < t1 ) { 41318 41319 // we have arrived at the sought interval 41320 break seek; 41321 41322 } 41323 41324 } 41325 41326 // prepare binary search on the right side of the index 41327 right = pp.length; 41328 break linear_scan; 41329 41330 } 41331 41332 //- slower code: 41333 //- if ( t < t0 || t0 === undefined ) { 41334 if ( ! ( t >= t0 ) ) { 41335 41336 // looping? 41337 41338 const t1global = pp[ 1 ]; 41339 41340 if ( t < t1global ) { 41341 41342 i1 = 2; // + 1, using the scan for the details 41343 t0 = t1global; 41344 41345 } 41346 41347 // linear reverse scan 41348 41349 for ( let giveUpAt = i1 - 2; ; ) { 41350 41351 if ( t0 === undefined ) { 41352 41353 // before start 41354 41355 this._cachedIndex = 0; 41356 return this.copySampleValue_( 0 ); 41357 41358 } 41359 41360 if ( i1 === giveUpAt ) break; // this loop 41361 41362 t1 = t0; 41363 t0 = pp[ -- i1 - 1 ]; 41364 41365 if ( t >= t0 ) { 41366 41367 // we have arrived at the sought interval 41368 break seek; 41369 41370 } 41371 41372 } 41373 41374 // prepare binary search on the left side of the index 41375 right = i1; 41376 i1 = 0; 41377 break linear_scan; 41378 41379 } 41380 41381 // the interval is valid 41382 41383 break validate_interval; 41384 41385 } // linear scan 41386 41387 // binary search 41388 41389 while ( i1 < right ) { 41390 41391 const mid = ( i1 + right ) >>> 1; 41392 41393 if ( t < pp[ mid ] ) { 41394 41395 right = mid; 41396 41397 } else { 41398 41399 i1 = mid + 1; 41400 41401 } 41402 41403 } 41404 41405 t1 = pp[ i1 ]; 41406 t0 = pp[ i1 - 1 ]; 41407 41408 // check boundary cases, again 41409 41410 if ( t0 === undefined ) { 41411 41412 this._cachedIndex = 0; 41413 return this.copySampleValue_( 0 ); 41414 41415 } 41416 41417 if ( t1 === undefined ) { 41418 41419 i1 = pp.length; 41420 this._cachedIndex = i1; 41421 return this.copySampleValue_( i1 - 1 ); 41422 41423 } 41424 41425 } // seek 41426 41427 this._cachedIndex = i1; 41428 41429 this.intervalChanged_( i1, t0, t1 ); 41430 41431 } // validate_interval 41432 41433 return this.interpolate_( i1, t0, t, t1 ); 41434 41435 } 41436 41437 /** 41438 * Returns the interpolation settings. 41439 * 41440 * @return {Object} The interpolation settings. 41441 */ 41442 getSettings_() { 41443 41444 return this.settings || this.DefaultSettings_; 41445 41446 } 41447 41448 /** 41449 * Copies a sample value to the result buffer. 41450 * 41451 * @param {number} index - An index into the sample value buffer. 41452 * @return {TypedArray} The result buffer. 41453 */ 41454 copySampleValue_( index ) { 41455 41456 // copies a sample value to the result buffer 41457 41458 const result = this.resultBuffer, 41459 values = this.sampleValues, 41460 stride = this.valueSize, 41461 offset = index * stride; 41462 41463 for ( let i = 0; i !== stride; ++ i ) { 41464 41465 result[ i ] = values[ offset + i ]; 41466 41467 } 41468 41469 return result; 41470 41471 } 41472 41473 /** 41474 * Copies a sample value to the result buffer. 41475 * 41476 * @abstract 41477 * @param {number} i1 - An index into the sample value buffer. 41478 * @param {number} t0 - The previous interpolation factor. 41479 * @param {number} t - The current interpolation factor. 41480 * @param {number} t1 - The next interpolation factor. 41481 * @return {TypedArray} The result buffer. 41482 */ 41483 interpolate_( /* i1, t0, t, t1 */ ) { 41484 41485 throw new Error( 'call to abstract method' ); 41486 // implementations shall return this.resultBuffer 41487 41488 } 41489 41490 /** 41491 * Optional method that is executed when the interval has changed. 41492 * 41493 * @param {number} i1 - An index into the sample value buffer. 41494 * @param {number} t0 - The previous interpolation factor. 41495 * @param {number} t - The current interpolation factor. 41496 */ 41497 intervalChanged_( /* i1, t0, t1 */ ) { 41498 41499 // empty 41500 41501 } 41502 41503} 41504 41505/** 41506 * Fast and simple cubic spline interpolant. 41507 * 41508 * It was derived from a Hermitian construction setting the first derivative 41509 * at each sample position to the linear slope between neighboring positions 41510 * over their parameter interval. 41511 * 41512 * @augments Interpolant 41513 */ 41514class CubicInterpolant extends Interpolant { 41515 41516 /** 41517 * Constructs a new cubic interpolant. 41518 * 41519 * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors. 41520 * @param {TypedArray} sampleValues - The sample values. 41521 * @param {number} sampleSize - The sample size 41522 * @param {TypedArray} [resultBuffer] - The result buffer. 41523 */ 41524 constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { 41525 41526 super( parameterPositions, sampleValues, sampleSize, resultBuffer ); 41527 41528 this._weightPrev = -0; 41529 this._offsetPrev = -0; 41530 this._weightNext = -0; 41531 this._offsetNext = -0; 41532 41533 this.DefaultSettings_ = { 41534 41535 endingStart: ZeroCurvatureEnding, 41536 endingEnd: ZeroCurvatureEnding 41537 41538 }; 41539 41540 } 41541 41542 intervalChanged_( i1, t0, t1 ) { 41543 41544 const pp = this.parameterPositions; 41545 let iPrev = i1 - 2, 41546 iNext = i1 + 1, 41547 41548 tPrev = pp[ iPrev ], 41549 tNext = pp[ iNext ]; 41550 41551 if ( tPrev === undefined ) { 41552 41553 switch ( this.getSettings_().endingStart ) { 41554 41555 case ZeroSlopeEnding: 41556 41557 // f'(t0) = 0 41558 iPrev = i1; 41559 tPrev = 2 * t0 - t1; 41560 41561 break; 41562 41563 case WrapAroundEnding: 41564 41565 // use the other end of the curve 41566 iPrev = pp.length - 2; 41567 tPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ]; 41568 41569 break; 41570 41571 default: // ZeroCurvatureEnding 41572 41573 // f''(t0) = 0 a.k.a. Natural Spline 41574 iPrev = i1; 41575 tPrev = t1; 41576 41577 } 41578 41579 } 41580 41581 if ( tNext === undefined ) { 41582 41583 switch ( this.getSettings_().endingEnd ) { 41584 41585 case ZeroSlopeEnding: 41586 41587 // f'(tN) = 0 41588 iNext = i1; 41589 tNext = 2 * t1 - t0; 41590 41591 break; 41592 41593 case WrapAroundEnding: 41594 41595 // use the other end of the curve 41596 iNext = 1; 41597 tNext = t1 + pp[ 1 ] - pp[ 0 ]; 41598 41599 break; 41600 41601 default: // ZeroCurvatureEnding 41602 41603 // f''(tN) = 0, a.k.a. Natural Spline 41604 iNext = i1 - 1; 41605 tNext = t0; 41606 41607 } 41608 41609 } 41610 41611 const halfDt = ( t1 - t0 ) * 0.5, 41612 stride = this.valueSize; 41613 41614 this._weightPrev = halfDt / ( t0 - tPrev ); 41615 this._weightNext = halfDt / ( tNext - t1 ); 41616 this._offsetPrev = iPrev * stride; 41617 this._offsetNext = iNext * stride; 41618 41619 } 41620 41621 interpolate_( i1, t0, t, t1 ) { 41622 41623 const result = this.resultBuffer, 41624 values = this.sampleValues, 41625 stride = this.valueSize, 41626 41627 o1 = i1 * stride, o0 = o1 - stride, 41628 oP = this._offsetPrev, oN = this._offsetNext, 41629 wP = this._weightPrev, wN = this._weightNext, 41630 41631 p = ( t - t0 ) / ( t1 - t0 ), 41632 pp = p * p, 41633 ppp = pp * p; 41634 41635 // evaluate polynomials 41636 41637 const sP = - wP * ppp + 2 * wP * pp - wP * p; 41638 const s0 = ( 1 + wP ) * ppp + ( -1.5 - 2 * wP ) * pp + ( -0.5 + wP ) * p + 1; 41639 const s1 = ( -1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p; 41640 const sN = wN * ppp - wN * pp; 41641 41642 // combine data linearly 41643 41644 for ( let i = 0; i !== stride; ++ i ) { 41645 41646 result[ i ] = 41647 sP * values[ oP + i ] + 41648 s0 * values[ o0 + i ] + 41649 s1 * values[ o1 + i ] + 41650 sN * values[ oN + i ]; 41651 41652 } 41653 41654 return result; 41655 41656 } 41657 41658} 41659 41660/** 41661 * A basic linear interpolant. 41662 * 41663 * @augments Interpolant 41664 */ 41665class LinearInterpolant extends Interpolant { 41666 41667 /** 41668 * Constructs a new linear interpolant. 41669 * 41670 * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors. 41671 * @param {TypedArray} sampleValues - The sample values. 41672 * @param {number} sampleSize - The sample size 41673 * @param {TypedArray} [resultBuffer] - The result buffer. 41674 */ 41675 constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { 41676 41677 super( parameterPositions, sampleValues, sampleSize, resultBuffer ); 41678 41679 } 41680 41681 interpolate_( i1, t0, t, t1 ) { 41682 41683 const result = this.resultBuffer, 41684 values = this.sampleValues, 41685 stride = this.valueSize, 41686 41687 offset1 = i1 * stride, 41688 offset0 = offset1 - stride, 41689 41690 weight1 = ( t - t0 ) / ( t1 - t0 ), 41691 weight0 = 1 - weight1; 41692 41693 for ( let i = 0; i !== stride; ++ i ) { 41694 41695 result[ i ] = 41696 values[ offset0 + i ] * weight0 + 41697 values[ offset1 + i ] * weight1; 41698 41699 } 41700 41701 return result; 41702 41703 } 41704 41705} 41706 41707/** 41708 * Interpolant that evaluates to the sample value at the position preceding 41709 * the parameter. 41710 * 41711 * @augments Interpolant 41712 */ 41713class DiscreteInterpolant extends Interpolant { 41714 41715 /** 41716 * Constructs a new discrete interpolant. 41717 * 41718 * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors. 41719 * @param {TypedArray} sampleValues - The sample values. 41720 * @param {number} sampleSize - The sample size 41721 * @param {TypedArray} [resultBuffer] - The result buffer. 41722 */ 41723 constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { 41724 41725 super( parameterPositions, sampleValues, sampleSize, resultBuffer ); 41726 41727 } 41728 41729 interpolate_( i1 /*, t0, t, t1 */ ) { 41730 41731 return this.copySampleValue_( i1 - 1 ); 41732 41733 } 41734 41735} 41736 41737/** 41738 * A Bezier interpolant using cubic Bezier curves with 2D control points. 41739 * 41740 * This interpolant supports the COLLADA/Maya style of Bezier animation where 41741 * each keyframe has explicit in/out tangent control points specified as 41742 * 2D coordinates (time, value). 41743 * 41744 * The tangent data must be provided via the `settings` object: 41745 * - `settings.inTangents`: Float32Array with [time, value] pairs per keyframe per component 41746 * - `settings.outTangents`: Float32Array with [time, value] pairs per keyframe per component 41747 * 41748 * For a track with N keyframes and stride S: 41749 * - Each tangent array has N * S * 2 values 41750 * - Layout: [k0_c0_time, k0_c0_value, k0_c1_time, k0_c1_value, ..., k0_cS_time, k0_cS_value, 41751 * k1_c0_time, k1_c0_value, ...] 41752 * 41753 * @augments Interpolant 41754 */ 41755class BezierInterpolant extends Interpolant { 41756 41757 interpolate_( i1, t0, t, t1 ) { 41758 41759 const result = this.resultBuffer; 41760 const values = this.sampleValues; 41761 const stride = this.valueSize; 41762 41763 const offset1 = i1 * stride; 41764 const offset0 = offset1 - stride; 41765 41766 const settings = this.settings || this.DefaultSettings_; 41767 const inTangents = settings.inTangents; 41768 const outTangents = settings.outTangents; 41769 41770 // If no tangent data, fall back to linear interpolation 41771 if ( ! inTangents || ! outTangents ) { 41772 41773 const weight1 = ( t - t0 ) / ( t1 - t0 ); 41774 const weight0 = 1 - weight1; 41775 41776 for ( let i = 0; i !== stride; ++ i ) { 41777 41778 result[ i ] = values[ offset0 + i ] * weight0 + values[ offset1 + i ] * weight1; 41779 41780 } 41781 41782 return result; 41783 41784 } 41785 41786 const tangentStride = stride * 2; 41787 const i0 = i1 - 1; 41788 41789 for ( let i = 0; i !== stride; ++ i ) { 41790 41791 const v0 = values[ offset0 + i ]; 41792 const v1 = values[ offset1 + i ]; 41793 41794 // outTangent of previous keyframe (C0) 41795 const outTangentOffset = i0 * tangentStride + i * 2; 41796 const c0x = outTangents[ outTangentOffset ]; 41797 const c0y = outTangents[ outTangentOffset + 1 ]; 41798 41799 // inTangent of current keyframe (C1) 41800 const inTangentOffset = i1 * tangentStride + i * 2; 41801 const c1x = inTangents[ inTangentOffset ]; 41802 const c1y = inTangents[ inTangentOffset + 1 ]; 41803 41804 // Solve for Bezier parameter s where Bx(s) = t using Newton-Raphson 41805 let s = ( t - t0 ) / ( t1 - t0 ); 41806 let s2, s3, oneMinusS, oneMinusS2, oneMinusS3; 41807 41808 for ( let iter = 0; iter < 8; iter ++ ) { 41809 41810 s2 = s * s; 41811 s3 = s2 * s; 41812 oneMinusS = 1 - s; 41813 oneMinusS2 = oneMinusS * oneMinusS; 41814 oneMinusS3 = oneMinusS2 * oneMinusS; 41815 41816 // Bezier X(s) = (1-s)³·t0 + 3(1-s)²s·c0x + 3(1-s)s²·c1x + s³·t1 41817 const bx = oneMinusS3 * t0 + 3 * oneMinusS2 * s * c0x + 3 * oneMinusS * s2 * c1x + s3 * t1; 41818 41819 const error = bx - t; 41820 if ( Math.abs( error ) < 1e-10 ) break; 41821 41822 // Derivative dX/ds 41823 const dbx = 3 * oneMinusS2 * ( c0x - t0 ) + 6 * oneMinusS * s * ( c1x - c0x ) + 3 * s2 * ( t1 - c1x ); 41824 if ( Math.abs( dbx ) < 1e-10 ) break; 41825 41826 s = s - error / dbx; 41827 s = Math.max( 0, Math.min( 1, s ) ); 41828 41829 } 41830 41831 // Evaluate Bezier Y(s) 41832 result[ i ] = oneMinusS3 * v0 + 3 * oneMinusS2 * s * c0y + 3 * oneMinusS * s2 * c1y + s3 * v1; 41833 41834 } 41835 41836 return result; 41837 41838 } 41839 41840} 41841 41842/** 41843 * Represents a timed sequence of keyframes, which are composed of lists of 41844 * times and related values, and which are used to animate a specific property 41845 * of an object. 41846 */ 41847class KeyframeTrack { 41848 41849 /** 41850 * Constructs a new keyframe track. 41851 * 41852 * @param {string} name - The keyframe track's name. 41853 * @param {Array<number>} times - A list of keyframe times. 41854 * @param {Array<number|string|boolean>} values - A list of keyframe values. 41855 * @param {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth|InterpolateBezier)} [interpolation] - The interpolation type. 41856 */ 41857 constructor( name, times, values, interpolation ) { 41858 41859 if ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' ); 41860 if ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name ); 41861 41862 /** 41863 * The track's name can refer to morph targets or bones or 41864 * possibly other values within an animated object. See {@link PropertyBinding#parseTrackName} 41865 * for the forms of strings that can be parsed for property binding. 41866 * 41867 * @type {string} 41868 */ 41869 this.name = name; 41870 41871 /** 41872 * The keyframe times. 41873 * 41874 * @type {Float32Array} 41875 */ 41876 this.times = convertArray( times, this.TimeBufferType ); 41877 41878 /** 41879 * The keyframe values. 41880 * 41881 * @type {Float32Array} 41882 */ 41883 this.values = convertArray( values, this.ValueBufferType ); 41884 41885 this.setInterpolation( interpolation || this.DefaultInterpolation ); 41886 41887 } 41888 41889 /** 41890 * Converts the keyframe track to JSON. 41891 * 41892 * @static 41893 * @param {KeyframeTrack} track - The keyframe track to serialize. 41894 * @return {Object} The serialized keyframe track as JSON. 41895 */ 41896 static toJSON( track ) { 41897 41898 const trackType = track.constructor; 41899 41900 let json; 41901 41902 // derived classes can define a static toJSON method 41903 if ( trackType.toJSON !== this.toJSON ) { 41904 41905 json = trackType.toJSON( track ); 41906 41907 } else { 41908 41909 // by default, we assume the data can be serialized as-is 41910 json = { 41911 41912 'name': track.name, 41913 'times': convertArray( track.times, Array ), 41914 'values': convertArray( track.values, Array ) 41915 41916 }; 41917 41918 const interpolation = track.getInterpolation(); 41919 41920 if ( interpolation !== track.DefaultInterpolation ) { 41921 41922 json.interpolation = interpolation; 41923 41924 } 41925 41926 } 41927 41928 json.type = track.ValueTypeName; // mandatory 41929 41930 return json; 41931 41932 } 41933 41934 /** 41935 * Factory method for creating a new discrete interpolant. 41936 * 41937 * @static 41938 * @param {TypedArray} [result] - The result buffer. 41939 * @return {DiscreteInterpolant} The new interpolant. 41940 */ 41941 InterpolantFactoryMethodDiscrete( result ) { 41942 41943 return new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result ); 41944 41945 } 41946 41947 /** 41948 * Factory method for creating a new linear interpolant. 41949 * 41950 * @static 41951 * @param {TypedArray} [result] - The result buffer. 41952 * @return {LinearInterpolant} The new interpolant. 41953 */ 41954 InterpolantFactoryMethodLinear( result ) { 41955 41956 return new LinearInterpolant( this.times, this.values, this.getValueSize(), result ); 41957 41958 } 41959 41960 /** 41961 * Factory method for creating a new smooth interpolant. 41962 * 41963 * @static 41964 * @param {TypedArray} [result] - The result buffer. 41965 * @return {CubicInterpolant} The new interpolant. 41966 */ 41967 InterpolantFactoryMethodSmooth( result ) { 41968 41969 return new CubicInterpolant( this.times, this.values, this.getValueSize(), result ); 41970 41971 } 41972 41973 /** 41974 * Factory method for creating a new Bezier interpolant. 41975 * 41976 * The Bezier interpolant requires tangent data to be set via the `settings` property 41977 * on the track before creating the interpolant. The settings should contain: 41978 * - `inTangents`: Float32Array with [time, value] pairs per keyframe per component 41979 * - `outTangents`: Float32Array with [time, value] pairs per keyframe per component 41980 * 41981 * @static 41982 * @param {TypedArray} [result] - The result buffer. 41983 * @return {BezierInterpolant} The new interpolant. 41984 */ 41985 InterpolantFactoryMethodBezier( result ) { 41986 41987 const interpolant = new BezierInterpolant( this.times, this.values, this.getValueSize(), result ); 41988 41989 // Pass tangent data from track settings to interpolant 41990 if ( this.settings ) { 41991 41992 interpolant.settings = this.settings; 41993 41994 } 41995 41996 return interpolant; 41997 41998 } 41999 42000 /** 42001 * Defines the interpolation factor method for this keyframe track. 42002 * 42003 * @param {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth|InterpolateBezier)} interpolation - The interpolation type. 42004 * @return {KeyframeTrack} A reference to this keyframe track. 42005 */ 42006 setInterpolation( interpolation ) { 42007 42008 let factoryMethod; 42009 42010 switch ( interpolation ) { 42011 42012 case InterpolateDiscrete: 42013 42014 factoryMethod = this.InterpolantFactoryMethodDiscrete; 42015 42016 break; 42017 42018 case InterpolateLinear: 42019 42020 factoryMethod = this.InterpolantFactoryMethodLinear; 42021 42022 break; 42023 42024 case InterpolateSmooth: 42025 42026 factoryMethod = this.InterpolantFactoryMethodSmooth; 42027 42028 break; 42029 42030 case InterpolateBezier: 42031 42032 factoryMethod = this.InterpolantFactoryMethodBezier; 42033 42034 break; 42035 42036 } 42037 42038 if ( factoryMethod === undefined ) { 42039 42040 const message = 'unsupported interpolation for ' + 42041 this.ValueTypeName + ' keyframe track named ' + this.name; 42042 42043 if ( this.createInterpolant === undefined ) { 42044 42045 // fall back to default, unless the default itself is messed up 42046 if ( interpolation !== this.DefaultInterpolation ) { 42047 42048 this.setInterpolation( this.DefaultInterpolation ); 42049 42050 } else { 42051 42052 throw new Error( message ); // fatal, in this case 42053 42054 } 42055 42056 } 42057 42058 warn( 'KeyframeTrack:', message ); 42059 return this; 42060 42061 } 42062 42063 this.createInterpolant = factoryMethod; 42064 42065 return this; 42066 42067 } 42068 42069 /** 42070 * Returns the current interpolation type. 42071 * 42072 * @return {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth|InterpolateBezier)} The interpolation type. 42073 */ 42074 getInterpolation() { 42075 42076 switch ( this.createInterpolant ) { 42077 42078 case this.InterpolantFactoryMethodDiscrete: 42079 42080 return InterpolateDiscrete; 42081 42082 case this.InterpolantFactoryMethodLinear: 42083 42084 return InterpolateLinear; 42085 42086 case this.InterpolantFactoryMethodSmooth: 42087 42088 return InterpolateSmooth; 42089 42090 case this.InterpolantFactoryMethodBezier: 42091 42092 return InterpolateBezier; 42093 42094 } 42095 42096 } 42097 42098 /** 42099 * Returns the value size. 42100 * 42101 * @return {number} The value size. 42102 */ 42103 getValueSize() { 42104 42105 return this.values.length / this.times.length; 42106 42107 } 42108 42109 /** 42110 * Moves all keyframes either forward or backward in time. 42111 * 42112 * @param {number} timeOffset - The offset to move the time values. 42113 * @return {KeyframeTrack} A reference to this keyframe track. 42114 */ 42115 shift( timeOffset ) { 42116 42117 if ( timeOffset !== 0.0 ) { 42118 42119 const times = this.times; 42120 42121 for ( let i = 0, n = times.length; i !== n; ++ i ) { 42122 42123 times[ i ] += timeOffset; 42124 42125 } 42126 42127 } 42128 42129 return this; 42130 42131 } 42132 42133 /** 42134 * Scale all keyframe times by a factor (useful for frame - seconds conversions). 42135 * 42136 * @param {number} timeScale - The time scale. 42137 * @return {KeyframeTrack} A reference to this keyframe track. 42138 */ 42139 scale( timeScale ) { 42140 42141 if ( timeScale !== 1.0 ) { 42142 42143 const times = this.times; 42144 42145 for ( let i = 0, n = times.length; i !== n; ++ i ) { 42146 42147 times[ i ] *= timeScale; 42148 42149 } 42150 42151 } 42152 42153 return this; 42154 42155 } 42156 42157 /** 42158 * Removes keyframes before and after animation without changing any values within the defined time range. 42159 * 42160 * Note: The method does not shift around keys to the start of the track time, because for interpolated 42161 * keys this will change their values 42162 * 42163 * @param {number} startTime - The start time. 42164 * @param {number} endTime - The end time. 42165 * @return {KeyframeTrack} A reference to this keyframe track. 42166 */ 42167 trim( startTime, endTime ) { 42168 42169 const times = this.times, 42170 nKeys = times.length; 42171 42172 let from = 0, 42173 to = nKeys - 1; 42174 42175 while ( from !== nKeys && times[ from ] < startTime ) { 42176 42177 ++ from; 42178 42179 } 42180 42181 while ( to !== -1 && times[ to ] > endTime ) { 42182 42183 -- to; 42184 42185 } 42186 42187 ++ to; // inclusive -> exclusive bound 42188 42189 if ( from !== 0 || to !== nKeys ) { 42190 42191 // empty tracks are forbidden, so keep at least one keyframe 42192 if ( from >= to ) { 42193 42194 to = Math.max( to, 1 ); 42195 from = to - 1; 42196 42197 } 42198 42199 const stride = this.getValueSize(); 42200 this.times = times.slice( from, to ); 42201 this.values = this.values.slice( from * stride, to * stride ); 42202 42203 } 42204 42205 return this; 42206 42207 } 42208 42209 /** 42210 * Performs minimal validation on the keyframe track. Returns `true` if the values 42211 * are valid. 42212 * 42213 * @return {boolean} Whether the keyframes are valid or not. 42214 */ 42215 validate() { 42216 42217 let valid = true; 42218 42219 const valueSize = this.getValueSize(); 42220 if ( valueSize - Math.floor( valueSize ) !== 0 ) { 42221 42222 error( 'KeyframeTrack: Invalid value size in track.', this ); 42223 valid = false; 42224 42225 } 42226 42227 const times = this.times, 42228 values = this.values, 42229 42230 nKeys = times.length; 42231 42232 if ( nKeys === 0 ) { 42233 42234 error( 'KeyframeTrack: Track is empty.', this ); 42235 valid = false; 42236 42237 } 42238 42239 let prevTime = null; 42240 42241 for ( let i = 0; i !== nKeys; i ++ ) { 42242 42243 const currTime = times[ i ]; 42244 42245 if ( typeof currTime === 'number' && isNaN( currTime ) ) { 42246 42247 error( 'KeyframeTrack: Time is not a valid number.', this, i, currTime ); 42248 valid = false; 42249 break; 42250 42251 } 42252 42253 if ( prevTime !== null && prevTime > currTime ) { 42254 42255 error( 'KeyframeTrack: Out of order keys.', this, i, currTime, prevTime ); 42256 valid = false; 42257 break; 42258 42259 } 42260 42261 prevTime = currTime; 42262 42263 } 42264 42265 if ( values !== undefined ) { 42266 42267 if ( isTypedArray( values ) ) { 42268 42269 for ( let i = 0, n = values.length; i !== n; ++ i ) { 42270 42271 const value = values[ i ]; 42272 42273 if ( isNaN( value ) ) { 42274 42275 error( 'KeyframeTrack: Value is not a valid number.', this, i, value ); 42276 valid = false; 42277 break; 42278 42279 } 42280 42281 } 42282 42283 } 42284 42285 } 42286 42287 return valid; 42288 42289 } 42290 42291 /** 42292 * Optimizes this keyframe track by removing equivalent sequential keys (which are 42293 * common in morph target sequences). 42294 * 42295 * @return {KeyframeTrack} A reference to this keyframe track. 42296 */ 42297 optimize() { 42298 42299 // (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --> (0,0,1,1,0,0) 42300 42301 // times or values may be shared with other tracks, so overwriting is unsafe 42302 const times = this.times.slice(), 42303 values = this.values.slice(), 42304 stride = this.getValueSize(), 42305 42306 smoothInterpolation = this.getInterpolation() === InterpolateSmooth, 42307 42308 lastIndex = times.length - 1; 42309 42310 let writeIndex = 1; 42311 42312 for ( let i = 1; i < lastIndex; ++ i ) { 42313 42314 let keep = false; 42315 42316 const time = times[ i ]; 42317 const timeNext = times[ i + 1 ]; 42318 42319 // remove adjacent keyframes scheduled at the same time 42320 42321 if ( time !== timeNext && ( i !== 1 || time !== times[ 0 ] ) ) { 42322 42323 if ( ! smoothInterpolation ) { 42324 42325 // remove unnecessary keyframes same as their neighbors 42326 42327 const offset = i * stride, 42328 offsetP = offset - stride, 42329 offsetN = offset + stride; 42330 42331 for ( let j = 0; j !== stride; ++ j ) { 42332 42333 const value = values[ offset + j ]; 42334 42335 if ( value !== values[ offsetP + j ] || 42336 value !== values[ offsetN + j ] ) { 42337 42338 keep = true; 42339 break; 42340 42341 } 42342 42343 } 42344 42345 } else { 42346 42347 keep = true; 42348 42349 } 42350 42351 } 42352 42353 // in-place compaction 42354 42355 if ( keep ) { 42356 42357 if ( i !== writeIndex ) { 42358 42359 times[ writeIndex ] = times[ i ]; 42360 42361 const readOffset = i * stride, 42362 writeOffset = writeIndex * stride; 42363 42364 for ( let j = 0; j !== stride; ++ j ) { 42365 42366 values[ writeOffset + j ] = values[ readOffset + j ]; 42367 42368 } 42369 42370 } 42371 42372 ++ writeIndex; 42373 42374 } 42375 42376 } 42377 42378 // flush last keyframe (compaction looks ahead) 42379 42380 if ( lastIndex > 0 ) { 42381 42382 times[ writeIndex ] = times[ lastIndex ]; 42383 42384 for ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) { 42385 42386 values[ writeOffset + j ] = values[ readOffset + j ]; 42387 42388 } 42389 42390 ++ writeIndex; 42391 42392 } 42393 42394 if ( writeIndex !== times.length ) { 42395 42396 this.times = times.slice( 0, writeIndex ); 42397 this.values = values.slice( 0, writeIndex * stride ); 42398 42399 } else { 42400 42401 this.times = times; 42402 this.values = values; 42403 42404 } 42405 42406 return this; 42407 42408 } 42409 42410 /** 42411 * Returns a new keyframe track with copied values from this instance. 42412 * 42413 * @return {KeyframeTrack} A clone of this instance. 42414 */ 42415 clone() { 42416 42417 const times = this.times.slice(); 42418 const values = this.values.slice(); 42419 42420 const TypedKeyframeTrack = this.constructor; 42421 const track = new TypedKeyframeTrack( this.name, times, values ); 42422 42423 // Interpolant argument to constructor is not saved, so copy the factory method directly. 42424 track.createInterpolant = this.createInterpolant; 42425 42426 return track; 42427 42428 } 42429 42430} 42431 42432/** 42433 * The value type name. 42434 * 42435 * @type {string} 42436 * @default '' 42437 */ 42438KeyframeTrack.prototype.ValueTypeName = ''; 42439 42440/** 42441 * The time buffer type of this keyframe track. 42442 * 42443 * @type {TypedArray|Array} 42444 * @default Float32Array.constructor 42445 */ 42446KeyframeTrack.prototype.TimeBufferType = Float32Array; 42447 42448/** 42449 * The value buffer type of this keyframe track. 42450 * 42451 * @type {TypedArray|Array} 42452 * @default Float32Array.constructor 42453 */ 42454KeyframeTrack.prototype.ValueBufferType = Float32Array; 42455 42456/** 42457 * The default interpolation type of this keyframe track. 42458 * 42459 * @type {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth|InterpolateBezier)} 42460 * @default InterpolateLinear 42461 */ 42462KeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear; 42463 42464/** 42465 * A track for boolean keyframe values. 42466 * 42467 * @augments KeyframeTrack 42468 */ 42469class BooleanKeyframeTrack extends KeyframeTrack { 42470 42471 /** 42472 * Constructs a new boolean keyframe track. 42473 * 42474 * This keyframe track type has no `interpolation` parameter because the 42475 * interpolation is always discrete. 42476 * 42477 * @param {string} name - The keyframe track's name. 42478 * @param {Array<number>} times - A list of keyframe times. 42479 * @param {Array<boolean>} values - A list of keyframe values. 42480 */ 42481 constructor( name, times, values ) { 42482 42483 super( name, times, values ); 42484 42485 } 42486 42487} 42488 42489/** 42490 * The value type name. 42491 * 42492 * @type {string} 42493 * @default 'bool' 42494 */ 42495BooleanKeyframeTrack.prototype.ValueTypeName = 'bool'; 42496 42497/** 42498 * The value buffer type of this keyframe track. 42499 * 42500 * @type {TypedArray|Array} 42501 * @default Array.constructor 42502 */ 42503BooleanKeyframeTrack.prototype.ValueBufferType = Array; 42504 42505/** 42506 * The default interpolation type of this keyframe track. 42507 * 42508 * @type {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth)} 42509 * @default InterpolateDiscrete 42510 */ 42511BooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; 42512BooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; 42513BooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; 42514 42515/** 42516 * A track for color keyframe values. 42517 * 42518 * @augments KeyframeTrack 42519 */ 42520class ColorKeyframeTrack extends KeyframeTrack { 42521 42522 /** 42523 * Constructs a new color keyframe track. 42524 * 42525 * @param {string} name - The keyframe track's name. 42526 * @param {Array<number>} times - A list of keyframe times. 42527 * @param {Array<number>} values - A list of keyframe values. 42528 * @param {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth)} [interpolation] - The interpolation type. 42529 */ 42530 constructor( name, times, values, interpolation ) { 42531 42532 super( name, times, values, interpolation ); 42533 42534 } 42535 42536} 42537 42538/** 42539 * The value type name. 42540 * 42541 * @type {string} 42542 * @default 'color' 42543 */ 42544ColorKeyframeTrack.prototype.ValueTypeName = 'color'; 42545 42546/** 42547 * A track for numeric keyframe values. 42548 * 42549 * @augments KeyframeTrack 42550 */ 42551class NumberKeyframeTrack extends KeyframeTrack { 42552 42553 /** 42554 * Constructs a new number keyframe track. 42555 * 42556 * @param {string} name - The keyframe track's name. 42557 * @param {Array<number>} times - A list of keyframe times. 42558 * @param {Array<number>} values - A list of keyframe values. 42559 * @param {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth)} [interpolation] - The interpolation type. 42560 */ 42561 constructor( name, times, values, interpolation ) { 42562 42563 super( name, times, values, interpolation ); 42564 42565 } 42566 42567} 42568 42569/** 42570 * The value type name. 42571 * 42572 * @type {string} 42573 * @default 'number' 42574 */ 42575NumberKeyframeTrack.prototype.ValueTypeName = 'number'; 42576 42577/** 42578 * Spherical linear unit quaternion interpolant. 42579 * 42580 * @augments Interpolant 42581 */ 42582class QuaternionLinearInterpolant extends Interpolant { 42583 42584 /** 42585 * Constructs a new SLERP interpolant. 42586 * 42587 * @param {TypedArray} parameterPositions - The parameter positions hold the interpolation factors. 42588 * @param {TypedArray} sampleValues - The sample values. 42589 * @param {number} sampleSize - The sample size 42590 * @param {TypedArray} [resultBuffer] - The result buffer. 42591 */ 42592 constructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) { 42593 42594 super( parameterPositions, sampleValues, sampleSize, resultBuffer ); 42595 42596 } 42597 42598 interpolate_( i1, t0, t, t1 ) { 42599 42600 const result = this.resultBuffer, 42601 values = this.sampleValues, 42602 stride = this.valueSize, 42603 42604 alpha = ( t - t0 ) / ( t1 - t0 ); 42605 42606 let offset = i1 * stride; 42607 42608 for ( let end = offset + stride; offset !== end; offset += 4 ) { 42609 42610 Quaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha ); 42611 42612 } 42613 42614 return result; 42615 42616 } 42617 42618} 42619 42620/** 42621 * A track for Quaternion keyframe values. 42622 * 42623 * @augments KeyframeTrack 42624 */ 42625class QuaternionKeyframeTrack extends KeyframeTrack { 42626 42627 /** 42628 * Constructs a new Quaternion keyframe track. 42629 * 42630 * @param {string} name - The keyframe track's name. 42631 * @param {Array<number>} times - A list of keyframe times. 42632 * @param {Array<number>} values - A list of keyframe values. 42633 * @param {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth)} [interpolation] - The interpolation type. 42634 */ 42635 constructor( name, times, values, interpolation ) { 42636 42637 super( name, times, values, interpolation ); 42638 42639 } 42640 42641 /** 42642 * Overwritten so the method returns Quaternion based interpolant. 42643 * 42644 * @static 42645 * @param {TypedArray} [result] - The result buffer. 42646 * @return {QuaternionLinearInterpolant} The new interpolant. 42647 */ 42648 InterpolantFactoryMethodLinear( result ) { 42649 42650 return new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result ); 42651 42652 } 42653 42654} 42655 42656/** 42657 * The value type name. 42658 * 42659 * @type {string} 42660 * @default 'quaternion' 42661 */ 42662QuaternionKeyframeTrack.prototype.ValueTypeName = 'quaternion'; 42663// ValueBufferType is inherited 42664// DefaultInterpolation is inherited; 42665QuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; 42666 42667/** 42668 * A track for string keyframe values. 42669 * 42670 * @augments KeyframeTrack 42671 */ 42672class StringKeyframeTrack extends KeyframeTrack { 42673 42674 /** 42675 * Constructs a new string keyframe track. 42676 * 42677 * This keyframe track type has no `interpolation` parameter because the 42678 * interpolation is always discrete. 42679 * 42680 * @param {string} name - The keyframe track's name. 42681 * @param {Array<number>} times - A list of keyframe times. 42682 * @param {Array<string>} values - A list of keyframe values. 42683 */ 42684 constructor( name, times, values ) { 42685 42686 super( name, times, values ); 42687 42688 } 42689 42690} 42691 42692/** 42693 * The value type name. 42694 * 42695 * @type {string} 42696 * @default 'string' 42697 */ 42698StringKeyframeTrack.prototype.ValueTypeName = 'string'; 42699 42700/** 42701 * The value buffer type of this keyframe track. 42702 * 42703 * @type {TypedArray|Array} 42704 * @default Array.constructor 42705 */ 42706StringKeyframeTrack.prototype.ValueBufferType = Array; 42707 42708/** 42709 * The default interpolation type of this keyframe track. 42710 * 42711 * @type {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth)} 42712 * @default InterpolateDiscrete 42713 */ 42714StringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete; 42715StringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined; 42716StringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined; 42717 42718/** 42719 * A track for vector keyframe values. 42720 * 42721 * @augments KeyframeTrack 42722 */ 42723class VectorKeyframeTrack extends KeyframeTrack { 42724 42725 /** 42726 * Constructs a new vector keyframe track. 42727 * 42728 * @param {string} name - The keyframe track's name. 42729 * @param {Array<number>} times - A list of keyframe times. 42730 * @param {Array<number>} values - A list of keyframe values. 42731 * @param {(InterpolateLinear|InterpolateDiscrete|InterpolateSmooth)} [interpolation] - The interpolation type. 42732 */ 42733 constructor( name, times, values, interpolation ) { 42734 42735 super( name, times, values, interpolation ); 42736 42737 } 42738 42739} 42740 42741/** 42742 * The value type name. 42743 * 42744 * @type {string} 42745 * @default 'vector' 42746 */ 42747VectorKeyframeTrack.prototype.ValueTypeName = 'vector'; 42748 42749/** 42750 * A reusable set of keyframe tracks which represent an animation. 42751 */ 42752class AnimationClip { 42753 42754 /** 42755 * Constructs a new animation clip. 42756 * 42757 * Note: Instead of instantiating an AnimationClip directly with the constructor, you can 42758 * use the static interface of this class for creating clips. In most cases though, animation clips
vendor: 4,492 bytes, lines 42759-42940
42759 * will automatically be created by loaders when importing animated 3D assets. 42760 * 42761 * @param {string} [name=''] - The clip's name. 42762 * @param {number} [duration=-1] - The clip's duration in seconds. If a negative value is passed, 42763 * the duration will be calculated from the passed keyframes. 42764 * @param {Array<KeyframeTrack>} tracks - An array of keyframe tracks. 42765 * @param {(NormalAnimationBlendMode|AdditiveAnimationBlendMode)} [blendMode=NormalAnimationBlendMode] - Defines how the animation 42766 * is blended/combined when two or more animations are simultaneously played. 42767 */ 42768 constructor( name = '', duration = -1, tracks = [], blendMode = NormalAnimationBlendMode ) { 42769 42770 /** 42771 * The clip's name. 42772 * 42773 * @type {string} 42774 */ 42775 this.name = name; 42776 42777 /** 42778 * An array of keyframe tracks. 42779 * 42780 * @type {Array<KeyframeTrack>} 42781 */ 42782 this.tracks = tracks; 42783 42784 /** 42785 * The clip's duration in seconds. 42786 * 42787 * @type {number} 42788 */ 42789 this.duration = duration; 42790 42791 /** 42792 * Defines how the animation is blended/combined when two or more animations 42793 * are simultaneously played. 42794 * 42795 * @type {(NormalAnimationBlendMode|AdditiveAnimationBlendMode)} 42796 */ 42797 this.blendMode = blendMode; 42798 42799 /** 42800 * The UUID of the animation clip. 42801 * 42802 * @type {string} 42803 * @readonly 42804 */ 42805 this.uuid = generateUUID(); 42806 42807 /** 42808 * An object that can be used to store custom data about the animation clip. 42809 * It should not hold references to functions as these will not be cloned. 42810 * 42811 * @type {Object} 42812 */ 42813 this.userData = {}; 42814 42815 // this means it should figure out its duration by scanning the tracks 42816 if ( this.duration < 0 ) { 42817 42818 this.resetDuration(); 42819 42820 } 42821 42822 } 42823 42824 /** 42825 * Factory method for creating an animation clip from the given JSON. 42826 * 42827 * @static 42828 * @param {Object} json - The serialized animation clip. 42829 * @return {AnimationClip} The new animation clip. 42830 */ 42831 static parse( json ) { 42832 42833 const tracks = [], 42834 jsonTracks = json.tracks, 42835 frameTime = 1.0 / ( json.fps || 1.0 ); 42836 42837 for ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) { 42838 42839 tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) ); 42840 42841 } 42842 42843 const clip = new this( json.name, json.duration, tracks, json.blendMode ); 42844 clip.uuid = json.uuid; 42845 42846 clip.userData = JSON.parse( json.userData || '{}' ); 42847 42848 return clip; 42849 42850 } 42851 42852 /** 42853 * Serializes the given animation clip into JSON. 42854 * 42855 * @static 42856 * @param {AnimationClip} clip - The animation clip to serialize. 42857 * @return {Object} The JSON object. 42858 */ 42859 static toJSON( clip ) { 42860 42861 const tracks = [], 42862 clipTracks = clip.tracks; 42863 42864 const json = { 42865 42866 'name': clip.name, 42867 'duration': clip.duration, 42868 'tracks': tracks, 42869 'uuid': clip.uuid, 42870 'blendMode': clip.blendMode, 42871 'userData': JSON.stringify( clip.userData ), 42872 42873 }; 42874 42875 for ( let i = 0, n = clipTracks.length; i !== n; ++ i ) { 42876 42877 tracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) ); 42878 42879 } 42880 42881 return json; 42882 42883 } 42884 42885 /** 42886 * Returns a new animation clip from the passed morph targets array of a 42887 * geometry, taking a name and the number of frames per second. 42888 * 42889 * Note: The fps parameter is required, but the animation speed can be 42890 * overridden via {@link AnimationAction#setDuration}. 42891 * 42892 * @static 42893 * @param {string} name - The name of the animation clip. 42894 * @param {Array<Object>} morphTargetSequence - A sequence of morph targets. 42895 * @param {number} fps - The Frames-Per-Second value. 42896 * @param {boolean} noLoop - Whether the clip should be no loop or not. 42897 * @return {AnimationClip} The new animation clip. 42898 */ 42899 static CreateFromMorphTargetSequence( name, morphTargetSequence, fps, noLoop ) { 42900 42901 const numMorphTargets = morphTargetSequence.length; 42902 const tracks = []; 42903 42904 for ( let i = 0; i < numMorphTargets; i ++ ) { 42905 42906 let times = []; 42907 let values = []; 42908 42909 times.push( 42910 ( i + numMorphTargets - 1 ) % numMorphTargets, 42911 i, 42912 ( i + 1 ) % numMorphTargets ); 42913 42914 values.push( 0, 1, 0 ); 42915 42916 const order = getKeyframeOrder( times ); 42917 times = sortedArray( times, 1, order ); 42918 values = sortedArray( values, 1, order ); 42919 42920 // if there is a key at the first frame, duplicate it as the 42921 // last frame as well for perfect loop. 42922 if ( ! noLoop && times[ 0 ] === 0 ) { 42923 42924 times.push( numMorphTargets ); 42925 values.push( values[ 0 ] ); 42926 42927 } 42928 42929 tracks.push( 42930 new NumberKeyframeTrack( 42931 '.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']', 42932 times, values 42933 ).scale( 1.0 / fps ) ); 42934 42935 } 42936 42937 return new this( name, -1, tracks ); 42938 42939 } 42940
vendor: 15,646 bytes, lines 42941-43672
42941 /** 42942 * Searches for an animation clip by name, taking as its first parameter 42943 * either an array of clips, or a mesh or geometry that contains an 42944 * array named "animations" property. 42945 * 42946 * @static 42947 * @param {(Array<AnimationClip>|Object3D)} objectOrClipArray - The array or object to search through. 42948 * @param {string} name - The name to search for. 42949 * @return {?AnimationClip} The found animation clip. Returns `null` if no clip has been found. 42950 */ 42951 static findByName( objectOrClipArray, name ) { 42952 42953 let clipArray = objectOrClipArray; 42954 42955 if ( ! Array.isArray( objectOrClipArray ) ) { 42956 42957 const o = objectOrClipArray; 42958 clipArray = o.geometry && o.geometry.animations || o.animations; 42959 42960 } 42961 42962 for ( let i = 0; i < clipArray.length; i ++ ) { 42963 42964 if ( clipArray[ i ].name === name ) { 42965 42966 return clipArray[ i ]; 42967 42968 } 42969 42970 } 42971 42972 return null; 42973 42974 } 42975 42976 /** 42977 * Returns an array of new AnimationClips created from the morph target 42978 * sequences of a geometry, trying to sort morph target names into 42979 * animation-group-based patterns like "Walk_001, Walk_002, Run_001, Run_002...". 42980 * 42981 * See {@link MD2Loader#parse} as an example for how the method should be used. 42982 * 42983 * @static 42984 * @param {Array<Object>} morphTargets - A sequence of morph targets. 42985 * @param {number} fps - The Frames-Per-Second value. 42986 * @param {boolean} noLoop - Whether the clip should be no loop or not. 42987 * @return {Array<AnimationClip>} An array of new animation clips. 42988 */ 42989 static CreateClipsFromMorphTargetSequences( morphTargets, fps, noLoop ) { 42990 42991 const animationToMorphTargets = {}; 42992 42993 // tested with https://regex101.com/ on trick sequences 42994 // such flamingo_flyA_003, flamingo_run1_003, crdeath0059 42995 const pattern = /^([\w-]*?)([\d]+)$/; 42996 42997 // sort morph target names into animation groups based 42998 // patterns like Walk_001, Walk_002, Run_001, Run_002 42999 for ( let i = 0, il = morphTargets.length; i < il; i ++ ) { 43000 43001 const morphTarget = morphTargets[ i ]; 43002 const parts = morphTarget.name.match( pattern ); 43003 43004 if ( parts && parts.length > 1 ) { 43005 43006 const name = parts[ 1 ]; 43007 43008 let animationMorphTargets = animationToMorphTargets[ name ]; 43009 43010 if ( ! animationMorphTargets ) { 43011 43012 animationToMorphTargets[ name ] = animationMorphTargets = []; 43013 43014 } 43015 43016 animationMorphTargets.push( morphTarget ); 43017 43018 } 43019 43020 } 43021 43022 const clips = []; 43023 43024 for ( const name in animationToMorphTargets ) { 43025 43026 clips.push( this.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) ); 43027 43028 } 43029 43030 return clips; 43031 43032 } 43033 43034 /** 43035 * Parses the `animation.hierarchy` format and returns a new animation clip. 43036 * 43037 * @static 43038 * @deprecated since r175. 43039 * @param {Object} animation - A serialized animation clip as JSON. 43040 * @param {Array<Bone>} bones - An array of bones. 43041 * @return {?AnimationClip} The new animation clip. 43042 */ 43043 static parseAnimation( animation, bones ) { 43044 43045 warn( 'AnimationClip: parseAnimation() is deprecated and will be removed with r185' ); 43046 43047 if ( ! animation ) { 43048 43049 error( 'AnimationClip: No animation in JSONLoader data.' ); 43050 return null; 43051 43052 } 43053 43054 const addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) { 43055 43056 // only return track if there are actually keys. 43057 if ( animationKeys.length !== 0 ) { 43058 43059 const times = []; 43060 const values = []; 43061 43062 flattenJSON( animationKeys, times, values, propertyName ); 43063 43064 // empty keys are filtered out, so check again 43065 if ( times.length !== 0 ) { 43066 43067 destTracks.push( new trackType( trackName, times, values ) ); 43068 43069 } 43070 43071 } 43072 43073 }; 43074 43075 const tracks = []; 43076 43077 const clipName = animation.name || 'default'; 43078 const fps = animation.fps || 30; 43079 const blendMode = animation.blendMode; 43080 43081 // automatic length determination in AnimationClip. 43082 let duration = animation.length || -1; 43083 43084 const hierarchyTracks = animation.hierarchy || []; 43085 43086 for ( let h = 0; h < hierarchyTracks.length; h ++ ) { 43087 43088 const animationKeys = hierarchyTracks[ h ].keys; 43089 43090 // skip empty tracks 43091 if ( ! animationKeys || animationKeys.length === 0 ) continue; 43092 43093 // process morph targets 43094 if ( animationKeys[ 0 ].morphTargets ) { 43095 43096 // figure out all morph targets used in this track 43097 const morphTargetNames = {}; 43098 43099 let k; 43100 43101 for ( k = 0; k < animationKeys.length; k ++ ) { 43102 43103 if ( animationKeys[ k ].morphTargets ) { 43104 43105 for ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) { 43106 43107 morphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = -1; 43108 43109 } 43110 43111 } 43112 43113 } 43114 43115 // create a track for each morph target with all zero 43116 // morphTargetInfluences except for the keys in which 43117 // the morphTarget is named. 43118 for ( const morphTargetName in morphTargetNames ) { 43119 43120 const times = []; 43121 const values = []; 43122 43123 for ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) { 43124 43125 const animationKey = animationKeys[ k ]; 43126 43127 times.push( animationKey.time ); 43128 values.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 ); 43129 43130 } 43131 43132 tracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) ); 43133 43134 } 43135 43136 duration = morphTargetNames.length * fps; 43137 43138 } else { 43139 43140 // ...assume skeletal animation 43141 43142 const boneName = '.bones[' + bones[ h ].name + ']'; 43143 43144 addNonemptyTrack( 43145 VectorKeyframeTrack, boneName + '.position', 43146 animationKeys, 'pos', tracks ); 43147 43148 addNonemptyTrack( 43149 QuaternionKeyframeTrack, boneName + '.quaternion', 43150 animationKeys, 'rot', tracks ); 43151 43152 addNonemptyTrack( 43153 VectorKeyframeTrack, boneName + '.scale', 43154 animationKeys, 'scl', tracks ); 43155 43156 } 43157 43158 } 43159 43160 if ( tracks.length === 0 ) { 43161 43162 return null; 43163 43164 } 43165 43166 const clip = new this( clipName, duration, tracks, blendMode ); 43167 43168 return clip; 43169 43170 } 43171 43172 /** 43173 * Sets the duration of this clip to the duration of its longest keyframe track. 43174 * 43175 * @return {AnimationClip} A reference to this animation clip. 43176 */ 43177 resetDuration() { 43178 43179 const tracks = this.tracks; 43180 let duration = 0; 43181 43182 for ( let i = 0, n = tracks.length; i !== n; ++ i ) { 43183 43184 const track = this.tracks[ i ]; 43185 43186 duration = Math.max( duration, track.times[ track.times.length - 1 ] ); 43187 43188 } 43189 43190 this.duration = duration; 43191 43192 return this; 43193 43194 } 43195 43196 /** 43197 * Trims all tracks to the clip's duration. 43198 * 43199 * @return {AnimationClip} A reference to this animation clip. 43200 */ 43201 trim() { 43202 43203 for ( let i = 0; i < this.tracks.length; i ++ ) { 43204 43205 this.tracks[ i ].trim( 0, this.duration ); 43206 43207 } 43208 43209 return this; 43210 43211 } 43212 43213 /** 43214 * Performs minimal validation on each track in the clip. Returns `true` if all 43215 * tracks are valid. 43216 * 43217 * @return {boolean} Whether the clip's keyframes are valid or not. 43218 */ 43219 validate() { 43220 43221 let valid = true; 43222 43223 for ( let i = 0; i < this.tracks.length; i ++ ) { 43224 43225 valid = valid && this.tracks[ i ].validate(); 43226 43227 } 43228 43229 return valid; 43230 43231 } 43232 43233 /** 43234 * Optimizes each track by removing equivalent sequential keys (which are 43235 * common in morph target sequences). 43236 * 43237 * @return {AnimationClip} A reference to this animation clip. 43238 */ 43239 optimize() { 43240 43241 for ( let i = 0; i < this.tracks.length; i ++ ) { 43242 43243 this.tracks[ i ].optimize(); 43244 43245 } 43246 43247 return this; 43248 43249 } 43250 43251 /** 43252 * Returns a new animation clip with copied values from this instance. 43253 * 43254 * @return {AnimationClip} A clone of this instance. 43255 */ 43256 clone() { 43257 43258 const tracks = []; 43259 43260 for ( let i = 0; i < this.tracks.length; i ++ ) { 43261 43262 tracks.push( this.tracks[ i ].clone() ); 43263 43264 } 43265 43266 const clip = new this.constructor( this.name, this.duration, tracks, this.blendMode ); 43267 43268 clip.userData = JSON.parse( JSON.stringify( this.userData ) ); 43269 43270 return clip; 43271 43272 } 43273 43274 /** 43275 * Serializes this animation clip into JSON. 43276 * 43277 * @return {Object} The JSON object. 43278 */ 43279 toJSON() { 43280 43281 return this.constructor.toJSON( this ); 43282 43283 } 43284 43285} 43286 43287function getTrackTypeForValueTypeName( typeName ) { 43288 43289 switch ( typeName.toLowerCase() ) { 43290 43291 case 'scalar': 43292 case 'double': 43293 case 'float': 43294 case 'number': 43295 case 'integer': 43296 43297 return NumberKeyframeTrack; 43298 43299 case 'vector': 43300 case 'vector2': 43301 case 'vector3': 43302 case 'vector4': 43303 43304 return VectorKeyframeTrack; 43305 43306 case 'color': 43307 43308 return ColorKeyframeTrack; 43309 43310 case 'quaternion': 43311 43312 return QuaternionKeyframeTrack; 43313 43314 case 'bool': 43315 case 'boolean': 43316 43317 return BooleanKeyframeTrack; 43318 43319 case 'string': 43320 43321 return StringKeyframeTrack; 43322 43323 } 43324 43325 throw new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName ); 43326 43327} 43328 43329function parseKeyframeTrack( json ) { 43330 43331 if ( json.type === undefined ) { 43332 43333 throw new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' ); 43334 43335 } 43336 43337 const trackType = getTrackTypeForValueTypeName( json.type ); 43338 43339 if ( json.times === undefined ) { 43340 43341 const times = [], values = []; 43342 43343 flattenJSON( json.keys, times, values, 'value' ); 43344 43345 json.times = times; 43346 json.values = values; 43347 43348 } 43349 43350 // derived classes can define a static parse method 43351 if ( trackType.parse !== undefined ) { 43352 43353 return trackType.parse( json ); 43354 43355 } else { 43356 43357 // by default, we assume a constructor compatible with the base 43358 return new trackType( json.name, json.times, json.values, json.interpolation ); 43359 43360 } 43361 43362} 43363 43364/** 43365 * @class 43366 * @classdesc A simple caching system, used internally by {@link FileLoader}. 43367 * To enable caching across all loaders that use {@link FileLoader}, add `THREE.Cache.enabled = true.` once in your app. 43368 * @hideconstructor 43369 */ 43370const Cache = { 43371 43372 /** 43373 * Whether caching is enabled or not. 43374 * 43375 * @static 43376 * @type {boolean} 43377 * @default false 43378 */ 43379 enabled: false, 43380 43381 /** 43382 * A dictionary that holds cached files. 43383 * 43384 * @static 43385 * @type {Object<string,Object>} 43386 */ 43387 files: {}, 43388 43389 /** 43390 * Adds a cache entry with a key to reference the file. If this key already 43391 * holds a file, it is overwritten. 43392 * 43393 * @static 43394 * @param {string} key - The key to reference the cached file. 43395 * @param {Object} file - The file to be cached. 43396 */ 43397 add: function ( key, file ) { 43398 43399 if ( this.enabled === false ) return; 43400 43401 if ( isBlobURL( key ) ) return; 43402 43403 // log( 'Cache', 'Adding key:', key ); 43404 43405 this.files[ key ] = file; 43406 43407 }, 43408 43409 /** 43410 * Gets the cached value for the given key. 43411 * 43412 * @static 43413 * @param {string} key - The key to reference the cached file. 43414 * @return {Object|undefined} The cached file. If the key does not exist `undefined` is returned. 43415 */ 43416 get: function ( key ) { 43417 43418 if ( this.enabled === false ) return; 43419 43420 if ( isBlobURL( key ) ) return; 43421 43422 // log( 'Cache', 'Checking key:', key ); 43423 43424 return this.files[ key ]; 43425 43426 }, 43427 43428 /** 43429 * Removes the cached file associated with the given key. 43430 * 43431 * @static 43432 * @param {string} key - The key to reference the cached file. 43433 */ 43434 remove: function ( key ) { 43435 43436 delete this.files[ key ]; 43437 43438 }, 43439 43440 /** 43441 * Remove all values from the cache. 43442 * 43443 * @static 43444 */ 43445 clear: function () { 43446 43447 this.files = {}; 43448 43449 } 43450 43451}; 43452 43453/** 43454 * Returns true if the given cache key contains the blob: scheme. 43455 * 43456 * @private 43457 * @param {string} key - The cache key. 43458 * @return {boolean} Whether the given cache key contains the blob: scheme or not. 43459 */ 43460function isBlobURL( key ) { 43461 43462 try { 43463 43464 const urlString = key.slice( key.indexOf( ':' ) + 1 ); // remove type identifier 43465 43466 const url = new URL( urlString ); 43467 return url.protocol === 'blob:'; 43468 43469 } catch ( e ) { 43470 43471 // If the string is not a valid URL, it throws an error 43472 return false; 43473 43474 } 43475 43476} 43477 43478/** 43479 * Handles and keeps track of loaded and pending data. A default global 43480 * instance of this class is created and used by loaders if not supplied 43481 * manually. 43482 * 43483 * In general that should be sufficient, however there are times when it can 43484 * be useful to have separate loaders - for example if you want to show 43485 * separate loading bars for objects and textures. 43486 * 43487 * ```js 43488 * const manager = new THREE.LoadingManager(); 43489 * manager.onLoad = () => console.log( 'Loading complete!' ); 43490 * 43491 * const loader1 = new OBJLoader( manager ); 43492 * const loader2 = new ColladaLoader( manager ); 43493 * ``` 43494 */ 43495class LoadingManager { 43496 43497 /** 43498 * Constructs a new loading manager. 43499 * 43500 * @param {Function} [onLoad] - Executes when all items have been loaded. 43501 * @param {Function} [onProgress] - Executes when single items have been loaded. 43502 * @param {Function} [onError] - Executes when an error occurs. 43503 */ 43504 constructor( onLoad, onProgress, onError ) { 43505 43506 const scope = this; 43507 43508 let isLoading = false; 43509 let itemsLoaded = 0; 43510 let itemsTotal = 0; 43511 let urlModifier = undefined; 43512 const handlers = []; 43513 43514 // Refer to #5689 for the reason why we don't set .onStart 43515 // in the constructor 43516 43517 /** 43518 * Executes when an item starts loading. 43519 * 43520 * @type {Function|undefined} 43521 * @default undefined 43522 */ 43523 this.onStart = undefined; 43524 43525 /** 43526 * Executes when all items have been loaded. 43527 * 43528 * @type {Function|undefined} 43529 * @default undefined 43530 */ 43531 this.onLoad = onLoad; 43532 43533 /** 43534 * Executes when single items have been loaded. 43535 * 43536 * @type {Function|undefined} 43537 * @default undefined 43538 */ 43539 this.onProgress = onProgress; 43540 43541 /** 43542 * Executes when an error occurs. 43543 * 43544 * @type {Function|undefined} 43545 * @default undefined 43546 */ 43547 this.onError = onError; 43548 43549 /** 43550 * Used for aborting ongoing requests in loaders using this manager. 43551 * 43552 * @private 43553 * @type {AbortController | null} 43554 */ 43555 this._abortController = null; 43556 43557 /** 43558 * This should be called by any loader using the manager when the loader 43559 * starts loading an item. 43560 * 43561 * @param {string} url - The URL to load. 43562 */ 43563 this.itemStart = function ( url ) { 43564 43565 itemsTotal ++; 43566 43567 if ( isLoading === false ) { 43568 43569 if ( scope.onStart !== undefined ) { 43570 43571 scope.onStart( url, itemsLoaded, itemsTotal ); 43572 43573 } 43574 43575 } 43576 43577 isLoading = true; 43578 43579 }; 43580 43581 /** 43582 * This should be called by any loader using the manager when the loader 43583 * ended loading an item. 43584 * 43585 * @param {string} url - The URL of the loaded item. 43586 */ 43587 this.itemEnd = function ( url ) { 43588 43589 itemsLoaded ++; 43590 43591 if ( scope.onProgress !== undefined ) { 43592 43593 scope.onProgress( url, itemsLoaded, itemsTotal ); 43594 43595 } 43596 43597 if ( itemsLoaded === itemsTotal ) { 43598 43599 isLoading = false; 43600 43601 if ( scope.onLoad !== undefined ) { 43602 43603 scope.onLoad(); 43604 43605 } 43606 43607 } 43608 43609 }; 43610 43611 /** 43612 * This should be called by any loader using the manager when the loader 43613 * encounters an error when loading an item. 43614 * 43615 * @param {string} url - The URL of the item that produces an error. 43616 */ 43617 this.itemError = function ( url ) { 43618 43619 if ( scope.onError !== undefined ) { 43620 43621 scope.onError( url ); 43622 43623 } 43624 43625 }; 43626 43627 /** 43628 * Given a URL, uses the URL modifier callback (if any) and returns a 43629 * resolved URL. If no URL modifier is set, returns the original URL. 43630 * 43631 * @param {string} url - The URL to load. 43632 * @return {string} The resolved URL. 43633 */ 43634 this.resolveURL = function ( url ) { 43635 43636 if ( urlModifier ) { 43637 43638 return urlModifier( url ); 43639 43640 } 43641 43642 return url; 43643 43644 }; 43645 43646 /** 43647 * If provided, the callback will be passed each resource URL before a 43648 * request is sent. The callback may return the original URL, or a new URL to 43649 * override loading behavior. This behavior can be used to load assets from 43650 * .ZIP files, drag-and-drop APIs, and Data URIs. 43651 * 43652 * ```js 43653 * const blobs = {'fish.gltf': blob1, 'diffuse.png': blob2, 'normal.png': blob3}; 43654 * 43655 * const manager = new THREE.LoadingManager(); 43656 * 43657 * // Initialize loading manager with URL callback. 43658 * const objectURLs = []; 43659 * manager.setURLModifier( ( url ) => { 43660 * 43661 * url = URL.createObjectURL( blobs[ url ] ); 43662 * objectURLs.push( url ); 43663 * return url; 43664 * 43665 * } ); 43666 * 43667 * // Load as usual, then revoke the blob URLs. 43668 * const loader = new GLTFLoader( manager ); 43669 * loader.load( 'fish.gltf', (gltf) => { 43670 * 43671 * scene.add( gltf.scene ); 43672 * objectURLs.forEach( ( url ) =>
vendor: 29,134 bytes, lines 43672-44953
43672 URL.revokeObjectURL( url ) ); 43673 * 43674 * } ); 43675 * ``` 43676 * 43677 * @param {function(string):string} transform - URL modifier callback. Called with an URL and must return a resolved URL. 43678 * @return {LoadingManager} A reference to this loading manager. 43679 */ 43680 this.setURLModifier = function ( transform ) { 43681 43682 urlModifier = transform; 43683 43684 return this; 43685 43686 }; 43687 43688 /** 43689 * Registers a loader with the given regular expression. Can be used to 43690 * define what loader should be used in order to load specific files. A 43691 * typical use case is to overwrite the default loader for textures. 43692 * 43693 * ```js 43694 * // add handler for TGA textures 43695 * manager.addHandler( /\.tga$/i, new TGALoader() ); 43696 * ``` 43697 * 43698 * @param {string} regex - A regular expression. 43699 * @param {Loader} loader - A loader that should handle matched cases. 43700 * @return {LoadingManager} A reference to this loading manager. 43701 */ 43702 this.addHandler = function ( regex, loader ) { 43703 43704 handlers.push( regex, loader ); 43705 43706 return this; 43707 43708 }; 43709 43710 /** 43711 * Removes the loader for the given regular expression. 43712 * 43713 * @param {string} regex - A regular expression. 43714 * @return {LoadingManager} A reference to this loading manager. 43715 */ 43716 this.removeHandler = function ( regex ) { 43717 43718 const index = handlers.indexOf( regex ); 43719 43720 if ( index !== -1 ) { 43721 43722 handlers.splice( index, 2 ); 43723 43724 } 43725 43726 return this; 43727 43728 }; 43729 43730 /** 43731 * Can be used to retrieve the registered loader for the given file path. 43732 * 43733 * @param {string} file - The file path. 43734 * @return {?Loader} The registered loader. Returns `null` if no loader was found. 43735 */ 43736 this.getHandler = function ( file ) { 43737 43738 for ( let i = 0, l = handlers.length; i < l; i += 2 ) { 43739 43740 const regex = handlers[ i ]; 43741 const loader = handlers[ i + 1 ]; 43742 43743 if ( regex.global ) regex.lastIndex = 0; // see #17920 43744 43745 if ( regex.test( file ) ) { 43746 43747 return loader; 43748 43749 } 43750 43751 } 43752 43753 return null; 43754 43755 }; 43756 43757 /** 43758 * Can be used to abort ongoing loading requests in loaders using this manager. 43759 * The abort only works if the loaders implement {@link Loader#abort} and `AbortSignal.any()` 43760 * is supported in the browser. 43761 * 43762 * @return {LoadingManager} A reference to this loading manager. 43763 */ 43764 this.abort = function () { 43765 43766 43767 this.abortController.abort(); 43768 this._abortController = null; 43769 43770 return this; 43771 43772 }; 43773 43774 } 43775 43776 // TODO: Revert this back to a single member variable once this issue has been fixed 43777 // https://github.com/cloudflare/workerd/issues/3657 43778 43779 /** 43780 * Used for aborting ongoing requests in loaders using this manager. 43781 * 43782 * @type {AbortController} 43783 */ 43784 get abortController() { 43785 43786 if ( ! this._abortController ) { 43787 43788 this._abortController = new AbortController(); 43789 43790 } 43791 43792 return this._abortController; 43793 43794 } 43795 43796} 43797 43798/** 43799 * The global default loading manager. 43800 * 43801 * @constant 43802 * @type {LoadingManager} 43803 */ 43804const DefaultLoadingManager = /*@__PURE__*/ new LoadingManager(); 43805 43806/** 43807 * Abstract base class for loaders. 43808 * 43809 * @abstract 43810 */ 43811class Loader { 43812 43813 /** 43814 * Constructs a new loader. 43815 * 43816 * @param {LoadingManager} [manager] - The loading manager. 43817 */ 43818 constructor( manager ) { 43819 43820 /** 43821 * The loading manager. 43822 * 43823 * @type {LoadingManager} 43824 * @default DefaultLoadingManager 43825 */ 43826 this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager; 43827 43828 /** 43829 * The crossOrigin string to implement CORS for loading the url from a 43830 * different domain that allows CORS. 43831 * 43832 * @type {string} 43833 * @default 'anonymous' 43834 */ 43835 this.crossOrigin = 'anonymous'; 43836 43837 /** 43838 * Whether the XMLHttpRequest uses credentials. 43839 * 43840 * @type {boolean} 43841 * @default false 43842 */ 43843 this.withCredentials = false; 43844 43845 /** 43846 * The base path from which the asset will be loaded. 43847 * 43848 * @type {string} 43849 */ 43850 this.path = ''; 43851 43852 /** 43853 * The base path from which additional resources like textures will be loaded. 43854 * 43855 * @type {string} 43856 */ 43857 this.resourcePath = ''; 43858 43859 /** 43860 * The [request header](https://developer.mozilla.org/en-US/docs/Glossary/Request_header) 43861 * used in HTTP request. 43862 * 43863 * @type {Object<string, any>} 43864 */ 43865 this.requestHeader = {}; 43866 43867 if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { 43868 43869 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); 43870 43871 } 43872 43873 } 43874 43875 /** 43876 * This method needs to be implemented by all concrete loaders. It holds the 43877 * logic for loading assets from the backend. 43878 * 43879 * @abstract 43880 * @param {string} url - The path/URL of the file to be loaded. 43881 * @param {Function} onLoad - Executed when the loading process has been finished. 43882 * @param {onProgressCallback} [onProgress] - Executed while the loading is in progress. 43883 * @param {onErrorCallback} [onError] - Executed when errors occur. 43884 */ 43885 load( /* url, onLoad, onProgress, onError */ ) {} 43886 43887 /** 43888 * A async version of {@link Loader#load}. 43889 * 43890 * @param {string} url - The path/URL of the file to be loaded. 43891 * @param {onProgressCallback} [onProgress] - Executed while the loading is in progress. 43892 * @return {Promise} A Promise that resolves when the asset has been loaded. 43893 */ 43894 loadAsync( url, onProgress ) { 43895 43896 const scope = this; 43897 43898 return new Promise( function ( resolve, reject ) { 43899 43900 scope.load( url, resolve, onProgress, reject ); 43901 43902 } ); 43903 43904 } 43905 43906 /** 43907 * This method needs to be implemented by all concrete loaders. It holds the 43908 * logic for parsing the asset into three.js entities. 43909 * 43910 * @abstract 43911 * @param {any} data - The data to parse. 43912 */ 43913 parse( /* data */ ) {} 43914 43915 /** 43916 * Sets the `crossOrigin` String to implement CORS for loading the URL 43917 * from a different domain that allows CORS. 43918 * 43919 * @param {string} crossOrigin - The `crossOrigin` value. 43920 * @return {Loader} A reference to this instance. 43921 */ 43922 setCrossOrigin( crossOrigin ) { 43923 43924 this.crossOrigin = crossOrigin; 43925 return this; 43926 43927 } 43928 43929 /** 43930 * Whether the XMLHttpRequest uses credentials such as cookies, authorization 43931 * headers or TLS client certificates, see [XMLHttpRequest.withCredentials](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials). 43932 * 43933 * Note: This setting has no effect if you are loading files locally or from the same domain. 43934 * 43935 * @param {boolean} value - The `withCredentials` value. 43936 * @return {Loader} A reference to this instance. 43937 */ 43938 setWithCredentials( value ) { 43939 43940 this.withCredentials = value; 43941 return this; 43942 43943 } 43944 43945 /** 43946 * Sets the base path for the asset. 43947 * 43948 * @param {string} path - The base path. 43949 * @return {Loader} A reference to this instance. 43950 */ 43951 setPath( path ) { 43952 43953 this.path = path; 43954 return this; 43955 43956 } 43957 43958 /** 43959 * Sets the base path for dependent resources like textures. 43960 * 43961 * @param {string} resourcePath - The resource path. 43962 * @return {Loader} A reference to this instance. 43963 */ 43964 setResourcePath( resourcePath ) { 43965 43966 this.resourcePath = resourcePath; 43967 return this; 43968 43969 } 43970 43971 /** 43972 * Sets the given request header. 43973 * 43974 * @param {Object} requestHeader - A [request header](https://developer.mozilla.org/en-US/docs/Glossary/Request_header) 43975 * for configuring the HTTP request. 43976 * @return {Loader} A reference to this instance. 43977 */ 43978 setRequestHeader( requestHeader ) { 43979 43980 this.requestHeader = requestHeader; 43981 return this; 43982 43983 } 43984 43985 /** 43986 * This method can be implemented in loaders for aborting ongoing requests. 43987 * 43988 * @abstract 43989 * @return {Loader} A reference to this instance. 43990 */ 43991 abort() { 43992 43993 return this; 43994 43995 } 43996 43997} 43998 43999/** 44000 * Callback for onProgress in loaders. 44001 * 44002 * @callback onProgressCallback 44003 * @param {ProgressEvent} event - An instance of `ProgressEvent` that represents the current loading status. 44004 */ 44005 44006/** 44007 * Callback for onError in loaders. 44008 * 44009 * @callback onErrorCallback 44010 * @param {Error} error - The error which occurred during the loading process. 44011 */ 44012 44013/** 44014 * The default material name that is used by loaders 44015 * when creating materials for loaded 3D objects. 44016 * 44017 * Note: Not all loaders might honor this setting. 44018 * 44019 * @static 44020 * @type {string} 44021 * @default '__DEFAULT' 44022 */ 44023Loader.DEFAULT_MATERIAL_NAME = '__DEFAULT'; 44024 44025const loading = {}; 44026 44027class HttpError extends Error { 44028 44029 constructor( message, response ) { 44030 44031 super( message ); 44032 this.response = response; 44033 44034 } 44035 44036} 44037 44038/** 44039 * A low level class for loading resources with the Fetch API, used internally by 44040 * most loaders. It can also be used directly to load any file type that does 44041 * not have a loader. 44042 * 44043 * This loader supports caching. If you want to use it, add `THREE.Cache.enabled = true;` 44044 * once to your application. 44045 * 44046 * ```js 44047 * const loader = new THREE.FileLoader(); 44048 * const data = await loader.loadAsync( 'example.txt' ); 44049 * ``` 44050 * 44051 * @augments Loader 44052 */ 44053class FileLoader extends Loader { 44054 44055 /** 44056 * Constructs a new file loader. 44057 * 44058 * @param {LoadingManager} [manager] - The loading manager. 44059 */ 44060 constructor( manager ) { 44061 44062 super( manager ); 44063 44064 /** 44065 * The expected mime type. Valid values can be found 44066 * [here](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString#mimetype) 44067 * 44068 * @type {string} 44069 */ 44070 this.mimeType = ''; 44071 44072 /** 44073 * The expected response type. 44074 * 44075 * @type {('arraybuffer'|'blob'|'document'|'json'|'')} 44076 * @default '' 44077 */ 44078 this.responseType = ''; 44079 44080 /** 44081 * Used for aborting requests. 44082 * 44083 * @private 44084 * @type {AbortController} 44085 */ 44086 this._abortController = new AbortController(); 44087 44088 } 44089 44090 /** 44091 * Starts loading from the given URL and pass the loaded response to the `onLoad()` callback. 44092 * 44093 * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI. 44094 * @param {function(any)} onLoad - Executed when the loading process has been finished. 44095 * @param {onProgressCallback} [onProgress] - Executed while the loading is in progress. 44096 * @param {onErrorCallback} [onError] - Executed when errors occur. 44097 */ 44098 load( url, onLoad, onProgress, onError ) { 44099 44100 if ( url === undefined ) url = ''; 44101 44102 if ( this.path !== undefined ) url = this.path + url; 44103 44104 url = this.manager.resolveURL( url ); 44105 44106 const cached = Cache.get( `file:${url}` ); 44107 44108 if ( cached !== undefined ) { 44109 44110 this.manager.itemStart( url ); 44111 44112 setTimeout( () => { 44113 44114 if ( onLoad ) onLoad( cached ); 44115 44116 this.manager.itemEnd( url ); 44117 44118 }, 0 ); 44119 44120 return; 44121 44122 } 44123 44124 // Check if request is duplicate 44125 44126 if ( loading[ url ] !== undefined ) { 44127 44128 loading[ url ].push( { 44129 44130 onLoad: onLoad, 44131 onProgress: onProgress, 44132 onError: onError 44133 44134 } ); 44135 44136 return; 44137 44138 } 44139 44140 // Initialise array for duplicate requests 44141 loading[ url ] = []; 44142 44143 loading[ url ].push( { 44144 onLoad: onLoad, 44145 onProgress: onProgress, 44146 onError: onError, 44147 } ); 44148 44149 // create request 44150 const req = new Request( url, { 44151 headers: new Headers( this.requestHeader ), 44152 credentials: this.withCredentials ? 'include' : 'same-origin', 44153 signal: ( typeof AbortSignal.any === 'function' ) ? AbortSignal.any( [ this._abortController.signal, this.manager.abortController.signal ] ) : this._abortController.signal 44154 } ); 44155 44156 // record states ( avoid data race ) 44157 const mimeType = this.mimeType; 44158 const responseType = this.responseType; 44159 44160 // start the fetch 44161 fetch( req ) 44162 .then( response => { 44163 44164 if ( response.status === 200 || response.status === 0 ) { 44165 44166 // Some browsers return HTTP Status 0 when using non-http protocol 44167 // e.g. 'file://' or 'data://'. Handle as success. 44168 44169 if ( response.status === 0 ) { 44170 44171 warn( 'FileLoader: HTTP Status 0 received.' ); 44172 44173 } 44174 44175 // Workaround: Checking if response.body === undefined for Alipay browser #23548 44176 44177 if ( typeof ReadableStream === 'undefined' || response.body === undefined || response.body.getReader === undefined ) { 44178 44179 return response; 44180 44181 } 44182 44183 const callbacks = loading[ url ]; 44184 const reader = response.body.getReader(); 44185 44186 // Nginx needs X-File-Size check 44187 // https://serverfault.com/questions/482875/why-does-nginx-remove-content-length-header-for-chunked-content 44188 const contentLength = response.headers.get( 'X-File-Size' ) || response.headers.get( 'Content-Length' ); 44189 const total = contentLength ? parseInt( contentLength ) : 0; 44190 const lengthComputable = total !== 0; 44191 let loaded = 0; 44192 44193 // periodically read data into the new stream tracking while download progress 44194 const stream = new ReadableStream( { 44195 start( controller ) { 44196 44197 readData(); 44198 44199 function readData() { 44200 44201 reader.read().then( ( { done, value } ) => { 44202 44203 if ( done ) { 44204 44205 controller.close(); 44206 44207 } else { 44208 44209 loaded += value.byteLength; 44210 44211 const event = new ProgressEvent( 'progress', { lengthComputable, loaded, total } ); 44212 for ( let i = 0, il = callbacks.length; i < il; i ++ ) { 44213 44214 const callback = callbacks[ i ]; 44215 if ( callback.onProgress ) callback.onProgress( event ); 44216 44217 } 44218 44219 controller.enqueue( value ); 44220 readData(); 44221 44222 } 44223 44224 }, ( e ) => { 44225 44226 controller.error( e ); 44227 44228 } ); 44229 44230 } 44231 44232 } 44233 44234 } ); 44235 44236 return new Response( stream ); 44237 44238 } else { 44239 44240 throw new HttpError( `fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`, response ); 44241 44242 } 44243 44244 } ) 44245 .then( response => { 44246 44247 switch ( responseType ) { 44248 44249 case 'arraybuffer': 44250 44251 return response.arrayBuffer(); 44252 44253 case 'blob': 44254 44255 return response.blob(); 44256 44257 case 'document': 44258 44259 return response.text() 44260 .then( text => { 44261 44262 const parser = new DOMParser(); 44263 return parser.parseFromString( text, mimeType ); 44264 44265 } ); 44266 44267 case 'json': 44268 44269 return response.json(); 44270 44271 default: 44272 44273 if ( mimeType === '' ) { 44274 44275 return response.text(); 44276 44277 } else { 44278 44279 // sniff encoding 44280 const re = /charset="?([^;"\s]*)"?/i; 44281 const exec = re.exec( mimeType ); 44282 const label = exec && exec[ 1 ] ? exec[ 1 ].toLowerCase() : undefined; 44283 const decoder = new TextDecoder( label ); 44284 return response.arrayBuffer().then( ab => decoder.decode( ab ) ); 44285 44286 } 44287 44288 } 44289 44290 } ) 44291 .then( data => { 44292 44293 // Add to cache only on HTTP success, so that we do not cache 44294 // error response bodies as proper responses to requests. 44295 Cache.add( `file:${url}`, data ); 44296 44297 const callbacks = loading[ url ]; 44298 delete loading[ url ]; 44299 44300 for ( let i = 0, il = callbacks.length; i < il; i ++ ) { 44301 44302 const callback = callbacks[ i ]; 44303 if ( callback.onLoad ) callback.onLoad( data ); 44304 44305 } 44306 44307 } ) 44308 .catch( err => { 44309 44310 // Abort errors and other errors are handled the same 44311 44312 const callbacks = loading[ url ]; 44313 44314 if ( callbacks === undefined ) { 44315 44316 // When onLoad was called and url was deleted in `loading` 44317 this.manager.itemError( url ); 44318 throw err; 44319 44320 } 44321 44322 delete loading[ url ]; 44323 44324 for ( let i = 0, il = callbacks.length; i < il; i ++ ) { 44325 44326 const callback = callbacks[ i ]; 44327 if ( callback.onError ) callback.onError( err ); 44328 44329 } 44330 44331 this.manager.itemError( url ); 44332 44333 } ) 44334 .finally( () => { 44335 44336 this.manager.itemEnd( url ); 44337 44338 } ); 44339 44340 this.manager.itemStart( url ); 44341 44342 } 44343 44344 /** 44345 * Sets the expected response type. 44346 * 44347 * @param {('arraybuffer'|'blob'|'document'|'json'|'')} value - The response type. 44348 * @return {FileLoader} A reference to this file loader. 44349 */ 44350 setResponseType( value ) { 44351 44352 this.responseType = value; 44353 return this; 44354 44355 } 44356 44357 /** 44358 * Sets the expected mime type of the loaded file. 44359 * 44360 * @param {string} value - The mime type. 44361 * @return {FileLoader} A reference to this file loader. 44362 */ 44363 setMimeType( value ) { 44364 44365 this.mimeType = value; 44366 return this; 44367 44368 } 44369 44370 /** 44371 * Aborts ongoing fetch requests. 44372 * 44373 * @return {FileLoader} A reference to this instance. 44374 */ 44375 abort() { 44376 44377 this._abortController.abort(); 44378 this._abortController = new AbortController(); 44379 44380 return this; 44381 44382 } 44383 44384} 44385 44386/** 44387 * Class for loading animation clips in the JSON format. The files are internally 44388 * loaded via {@link FileLoader}. 44389 * 44390 * ```js 44391 * const loader = new THREE.AnimationLoader(); 44392 * const animations = await loader.loadAsync( 'animations/animation.js' ); 44393 * ``` 44394 * 44395 * @augments Loader 44396 */ 44397class AnimationLoader extends Loader { 44398 44399 /** 44400 * Constructs a new animation loader. 44401 * 44402 * @param {LoadingManager} [manager] - The loading manager. 44403 */ 44404 constructor( manager ) { 44405 44406 super( manager ); 44407 44408 } 44409 44410 /** 44411 * Starts loading from the given URL and pass the loaded animations as an array 44412 * holding instances of {@link AnimationClip} to the `onLoad()` callback. 44413 * 44414 * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI. 44415 * @param {function(Array<AnimationClip>)} onLoad - Executed when the loading process has been finished. 44416 * @param {onProgressCallback} onProgress - Executed while the loading is in progress. 44417 * @param {onErrorCallback} onError - Executed when errors occur. 44418 */ 44419 load( url, onLoad, onProgress, onError ) { 44420 44421 const scope = this; 44422 44423 const loader = new FileLoader( this.manager ); 44424 loader.setPath( this.path ); 44425 loader.setRequestHeader( this.requestHeader ); 44426 loader.setWithCredentials( this.withCredentials ); 44427 loader.load( url, function ( text ) { 44428 44429 try { 44430 44431 onLoad( scope.parse( JSON.parse( text ) ) ); 44432 44433 } catch ( e ) { 44434 44435 if ( onError ) { 44436 44437 onError( e ); 44438 44439 } else { 44440 44441 error( e ); 44442 44443 } 44444 44445 scope.manager.itemError( url ); 44446 44447 } 44448 44449 }, onProgress, onError ); 44450 44451 } 44452 44453 /** 44454 * Parses the given JSON object and returns an array of animation clips. 44455 * 44456 * @param {Object} json - The serialized animation clips. 44457 * @return {Array<AnimationClip>} The parsed animation clips. 44458 */ 44459 parse( json ) { 44460 44461 const animations = []; 44462 44463 for ( let i = 0; i < json.length; i ++ ) { 44464 44465 const clip = AnimationClip.parse( json[ i ] ); 44466 44467 animations.push( clip ); 44468 44469 } 44470 44471 return animations; 44472 44473 } 44474 44475} 44476 44477/** 44478 * Abstract base class for loading compressed texture formats S3TC, ASTC or ETC. 44479 * Textures are internally loaded via {@link FileLoader}. 44480 * 44481 * Derived classes have to implement the `parse()` method which holds the parsing 44482 * for the respective format. 44483 * 44484 * @abstract 44485 * @augments Loader 44486 */ 44487class CompressedTextureLoader extends Loader { 44488 44489 /** 44490 * Constructs a new compressed texture loader. 44491 * 44492 * @param {LoadingManager} [manager] - The loading manager. 44493 */ 44494 constructor( manager ) { 44495 44496 super( manager ); 44497 44498 } 44499 44500 /** 44501 * Starts loading from the given URL and passes the loaded compressed texture 44502 * to the `onLoad()` callback. The method also returns a new texture object which can 44503 * directly be used for material creation. If you do it this way, the texture 44504 * may pop up in your scene once the respective loading process is finished. 44505 * 44506 * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI. 44507 * @param {function(CompressedTexture)} onLoad - Executed when the loading process has been finished. 44508 * @param {onProgressCallback} onProgress - Executed while the loading is in progress. 44509 * @param {onErrorCallback} onError - Executed when errors occur. 44510 * @return {CompressedTexture} The compressed texture. 44511 */ 44512 load( url, onLoad, onProgress, onError ) { 44513 44514 const scope = this; 44515 44516 const images = []; 44517 44518 const texture = new CompressedTexture(); 44519 44520 const loader = new FileLoader( this.manager ); 44521 loader.setPath( this.path ); 44522 loader.setResponseType( 'arraybuffer' ); 44523 loader.setRequestHeader( this.requestHeader ); 44524 loader.setWithCredentials( scope.withCredentials ); 44525 44526 let loaded = 0; 44527 44528 function loadTexture( i ) { 44529 44530 loader.load( url[ i ], function ( buffer ) { 44531 44532 const texDatas = scope.parse( buffer, true ); 44533 44534 images[ i ] = { 44535 width: texDatas.width, 44536 height: texDatas.height, 44537 format: texDatas.format, 44538 mipmaps: texDatas.mipmaps 44539 }; 44540 44541 loaded += 1; 44542 44543 if ( loaded === 6 ) { 44544 44545 if ( texDatas.mipmapCount === 1 ) texture.minFilter = LinearFilter; 44546 44547 texture.image = images; 44548 texture.format = texDatas.format; 44549 texture.needsUpdate = true; 44550 44551 if ( onLoad ) onLoad( texture ); 44552 44553 } 44554 44555 }, onProgress, onError ); 44556 44557 } 44558 44559 if ( Array.isArray( url ) ) { 44560 44561 for ( let i = 0, il = url.length; i < il; ++ i ) { 44562 44563 loadTexture( i ); 44564 44565 } 44566 44567 } else { 44568 44569 // compressed cubemap texture stored in a single DDS file 44570 44571 loader.load( url, function ( buffer ) { 44572 44573 const texDatas = scope.parse( buffer, true ); 44574 44575 if ( texDatas.isCubemap ) { 44576 44577 const faces = texDatas.mipmaps.length / texDatas.mipmapCount; 44578 44579 for ( let f = 0; f < faces; f ++ ) { 44580 44581 images[ f ] = { mipmaps: [] }; 44582 44583 for ( let i = 0; i < texDatas.mipmapCount; i ++ ) { 44584 44585 images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] ); 44586 images[ f ].format = texDatas.format; 44587 images[ f ].width = texDatas.width; 44588 images[ f ].height = texDatas.height; 44589 44590 } 44591 44592 } 44593 44594 texture.image = images; 44595 44596 } else { 44597 44598 texture.image.width = texDatas.width; 44599 texture.image.height = texDatas.height; 44600 texture.mipmaps = texDatas.mipmaps; 44601 44602 } 44603 44604 if ( texDatas.mipmapCount === 1 ) { 44605 44606 texture.minFilter = LinearFilter; 44607 44608 } 44609 44610 texture.format = texDatas.format; 44611 texture.needsUpdate = true; 44612 44613 if ( onLoad ) onLoad( texture ); 44614 44615 }, onProgress, onError ); 44616 44617 } 44618 44619 return texture; 44620 44621 } 44622 44623} 44624 44625const _loading = new WeakMap(); 44626 44627/** 44628 * A loader for loading images. The class loads images with the HTML `Image` API. 44629 * 44630 * ```js 44631 * const loader = new THREE.ImageLoader(); 44632 * const image = await loader.loadAsync( 'image.png' ); 44633 * ``` 44634 * Please note that `ImageLoader` has dropped support for progress 44635 * events in `r84`. For an `ImageLoader` that supports progress events, see 44636 * [this thread](https://github.com/mrdoob/three.js/issues/10439#issuecomment-275785639). 44637 * 44638 * @augments Loader 44639 */ 44640class ImageLoader extends Loader { 44641 44642 /** 44643 * Constructs a new image loader. 44644 * 44645 * @param {LoadingManager} [manager] - The loading manager. 44646 */ 44647 constructor( manager ) { 44648 44649 super( manager ); 44650 44651 } 44652 44653 /** 44654 * Starts loading from the given URL and passes the loaded image 44655 * to the `onLoad()` callback. The method also returns a new `Image` object which can 44656 * directly be used for texture creation. If you do it this way, the texture 44657 * may pop up in your scene once the respective loading process is finished. 44658 * 44659 * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI. 44660 * @param {function(Image)} onLoad - Executed when the loading process has been finished. 44661 * @param {onProgressCallback} onProgress - Unsupported in this loader. 44662 * @param {onErrorCallback} onError - Executed when errors occur. 44663 * @return {Image} The image. 44664 */ 44665 load( url, onLoad, onProgress, onError ) { 44666 44667 if ( this.path !== undefined ) url = this.path + url; 44668 44669 url = this.manager.resolveURL( url ); 44670 44671 const scope = this; 44672 44673 const cached = Cache.get( `image:${url}` ); 44674 44675 if ( cached !== undefined ) { 44676 44677 if ( cached.complete === true ) { 44678 44679 scope.manager.itemStart( url ); 44680 44681 setTimeout( function () { 44682 44683 if ( onLoad ) onLoad( cached ); 44684 44685 scope.manager.itemEnd( url ); 44686 44687 }, 0 ); 44688 44689 } else { 44690 44691 let arr = _loading.get( cached ); 44692 44693 if ( arr === undefined ) { 44694 44695 arr = []; 44696 _loading.set( cached, arr ); 44697 44698 } 44699 44700 arr.push( { onLoad, onError } ); 44701 44702 } 44703 44704 return cached; 44705 44706 } 44707 44708 const image = createElementNS( 'img' ); 44709 44710 function onImageLoad() { 44711 44712 removeEventListeners(); 44713 44714 if ( onLoad ) onLoad( this ); 44715 44716 // 44717 44718 const callbacks = _loading.get( this ) || []; 44719 44720 for ( let i = 0; i < callbacks.length; i ++ ) { 44721 44722 const callback = callbacks[ i ]; 44723 if ( callback.onLoad ) callback.onLoad( this ); 44724 44725 } 44726 44727 _loading.delete( this ); 44728 44729 scope.manager.itemEnd( url ); 44730 44731 } 44732 44733 function onImageError( event ) { 44734 44735 removeEventListeners(); 44736 44737 if ( onError ) onError( event ); 44738 44739 Cache.remove( `image:${url}` ); 44740 44741 // 44742 44743 const callbacks = _loading.get( this ) || []; 44744 44745 for ( let i = 0; i < callbacks.length; i ++ ) { 44746 44747 const callback = callbacks[ i ]; 44748 if ( callback.onError ) callback.onError( event ); 44749 44750 } 44751 44752 _loading.delete( this ); 44753 44754 44755 scope.manager.itemError( url ); 44756 scope.manager.itemEnd( url ); 44757 44758 } 44759 44760 function removeEventListeners() { 44761 44762 image.removeEventListener( 'load', onImageLoad, false ); 44763 image.removeEventListener( 'error', onImageError, false ); 44764 44765 } 44766 44767 image.addEventListener( 'load', onImageLoad, false ); 44768 image.addEventListener( 'error', onImageError, false ); 44769 44770 if ( url.slice( 0, 5 ) !== 'data:' ) { 44771 44772 if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; 44773 44774 } 44775 44776 Cache.add( `image:${url}`, image ); 44777 scope.manager.itemStart( url ); 44778 44779 image.src = url; 44780 44781 return image; 44782 44783 } 44784 44785} 44786 44787/** 44788 * Class for loading cube textures. Images are internally loaded via {@link ImageLoader}. 44789 * 44790 * The loader returns an instance of {@link CubeTexture} and expects the cube map to 44791 * be defined as six separate images representing the sides of a cube. Other cube map definitions 44792 * like vertical and horizontal cross, column and row layouts are not supported. 44793 * 44794 * Note that, by convention, cube maps are specified in a coordinate system 44795 * in which positive-x is to the right when looking up the positive-z axis -- 44796 * in other words, using a left-handed coordinate system. Since three.js uses 44797 * a right-handed coordinate system, environment maps used in three.js will 44798 * have pos-x and neg-x swapped. 44799 * 44800 * The loaded cube texture is in sRGB color space. Meaning {@link Texture#colorSpace} 44801 * is set to `SRGBColorSpace` by default. 44802 * 44803 * ```js 44804 * const loader = new THREE.CubeTextureLoader().setPath( 'textures/cubeMaps/' ); 44805 * const cubeTexture = await loader.loadAsync( [ 44806 * 'px.png', 'nx.png', 'py.png', 'ny.png', 'pz.png', 'nz.png' 44807 * ] ); 44808 * scene.background = cubeTexture; 44809 * ``` 44810 * 44811 * @augments Loader 44812 */ 44813class CubeTextureLoader extends Loader { 44814 44815 /** 44816 * Constructs a new cube texture loader. 44817 * 44818 * @param {LoadingManager} [manager] - The loading manager. 44819 */ 44820 constructor( manager ) { 44821 44822 super( manager ); 44823 44824 } 44825 44826 /** 44827 * Starts loading from the given URL and pass the fully loaded cube texture 44828 * to the `onLoad()` callback. The method also returns a new cube texture object which can 44829 * directly be used for material creation. If you do it this way, the cube texture 44830 * may pop up in your scene once the respective loading process is finished. 44831 * 44832 * @param {Array<string>} urls - Array of 6 URLs to images, one for each side of the 44833 * cube texture. The urls should be specified in the following order: pos-x, 44834 * neg-x, pos-y, neg-y, pos-z, neg-z. An array of data URIs are allowed as well. 44835 * @param {function(CubeTexture)} onLoad - Executed when the loading process has been finished. 44836 * @param {onProgressCallback} onProgress - Unsupported in this loader. 44837 * @param {onErrorCallback} onError - Executed when errors occur. 44838 * @return {CubeTexture} The cube texture. 44839 */ 44840 load( urls, onLoad, onProgress, onError ) { 44841 44842 const texture = new CubeTexture(); 44843 texture.colorSpace = SRGBColorSpace; 44844 44845 const loader = new ImageLoader( this.manager ); 44846 loader.setCrossOrigin( this.crossOrigin ); 44847 loader.setPath( this.path ); 44848 44849 let loaded = 0; 44850 44851 function loadTexture( i ) { 44852 44853 loader.load( urls[ i ], function ( image ) { 44854 44855 texture.images[ i ] = image; 44856 44857 loaded ++; 44858 44859 if ( loaded === 6 ) { 44860 44861 texture.needsUpdate = true; 44862 44863 if ( onLoad ) onLoad( texture ); 44864 44865 } 44866 44867 }, undefined, onError ); 44868 44869 } 44870 44871 for ( let i = 0; i < urls.length; ++ i ) { 44872 44873 loadTexture( i ); 44874 44875 } 44876 44877 return texture; 44878 44879 } 44880 44881} 44882 44883/** 44884 * Abstract base class for loading binary texture formats RGBE, EXR or TGA. 44885 * Textures are internally loaded via {@link FileLoader}. 44886 * 44887 * Derived classes have to implement the `parse()` method which holds the parsing 44888 * for the respective format. 44889 * 44890 * @abstract 44891 * @augments Loader 44892 */ 44893class DataTextureLoader extends Loader { 44894 44895 /** 44896 * Constructs a new data texture loader. 44897 * 44898 * @param {LoadingManager} [manager] - The loading manager. 44899 */ 44900 constructor( manager ) { 44901 44902 super( manager ); 44903 44904 } 44905 44906 /** 44907 * Starts loading from the given URL and passes the loaded data texture 44908 * to the `onLoad()` callback. The method also returns a new texture object which can 44909 * directly be used for material creation. If you do it this way, the texture 44910 * may pop up in your scene once the respective loading process is finished. 44911 * 44912 * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI. 44913 * @param {function(DataTexture)} onLoad - Executed when the loading process has been finished. 44914 * @param {onProgressCallback} onProgress - Executed while the loading is in progress. 44915 * @param {onErrorCallback} onError - Executed when errors occur. 44916 * @return {DataTexture} The data texture. 44917 */ 44918 load( url, onLoad, onProgress, onError ) { 44919 44920 const scope = this; 44921 44922 const texture = new DataTexture(); 44923 44924 const loader = new FileLoader( this.manager ); 44925 loader.setResponseType( 'arraybuffer' ); 44926 loader.setRequestHeader( this.requestHeader ); 44927 loader.setPath( this.path ); 44928 loader.setWithCredentials( scope.withCredentials ); 44929 loader.load( url, function ( buffer ) { 44930 44931 let texData; 44932 44933 try { 44934 44935 texData = scope.parse( buffer ); 44936 44937 } catch ( e ) { 44938 44939 if ( onError !== undefined ) { 44940 44941 onError( e ); 44942 44943 } else { 44944 44945 error( e ); 44946 44947 } 44948 44949 return; 44950 44951 } 44952 44953
vendor: 1,839 bytes, lines 44953-45038
44953if ( texData.image !== undefined ) { 44954 44955 texture.image = texData.image; 44956 44957 } else if ( texData.data !== undefined ) { 44958 44959 texture.image.width = texData.width; 44960 texture.image.height = texData.height; 44961 texture.image.data = texData.data; 44962 44963 } 44964 44965 texture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping; 44966 texture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping; 44967 44968 texture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter; 44969 texture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter; 44970 44971 texture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1; 44972 44973 if ( texData.colorSpace !== undefined ) { 44974 44975 texture.colorSpace = texData.colorSpace; 44976 44977 } 44978 44979 if ( texData.flipY !== undefined ) { 44980 44981 texture.flipY = texData.flipY; 44982 44983 } 44984 44985 if ( texData.format !== undefined ) { 44986 44987 texture.format = texData.format; 44988 44989 } 44990 44991 if ( texData.type !== undefined ) { 44992 44993 texture.type = texData.type; 44994 44995 } 44996 44997 if ( texData.mipmaps !== undefined ) { 44998 44999 texture.mipmaps = texData.mipmaps; 45000 texture.minFilter = LinearMipmapLinearFilter; // presumably... 45001 45002 } 45003 45004 if ( texData.mipmapCount === 1 ) { 45005 45006 texture.minFilter = LinearFilter; 45007 45008 } 45009 45010 if ( texData.generateMipmaps !== undefined ) { 45011 45012 texture.generateMipmaps = texData.generateMipmaps; 45013 45014 } 45015 45016 texture.needsUpdate = true; 45017 45018 if ( onLoad ) onLoad( texture, texData ); 45019 45020 }, onProgress, onError ); 45021 45022 45023 return texture; 45024 45025 } 45026 45027} 45028 45029/** 45030 * Class for loading textures. Images are internally 45031 * loaded via {@link ImageLoader}. 45032 * 45033 * ```js 45034 * const loader = new THREE.TextureLoader(); 45035 * const texture = await loader.loadAsync( 'textures/land_ocean_ice_cloud_2048.jpg' ); 45036 * 45037 * const material = new THREE.MeshBasicMaterial( { map:texture } ); 45038 * ```
45039 * Please note that `TextureLoader` has dropped support for progress 45040 * events in `r84`. For a `TextureLoader` that supports progress events, see 45041 * [this thread](https://github.com/mrdoob/three.js/issues/10439#issuecomment-293260145). 45042 * 45043 * @augments Loader 45044 */ 45045class TextureLoader extends Loader { 45046 45047 /** 45048 * Constructs a new texture loader. 45049 * 45050 * @param {LoadingManager} [manager] - The loading manager. 45051 */ 45052 constructor( manager ) { 45053 45054 super( manager ); 45055 45056 } 45057 45058 /** 45059 * Starts loading from the given URL and pass the fully loaded texture 45060 * to the `onLoad()` callback. The method also returns a new texture object which can 45061 * directly be used for material creation. If you do it this way, the texture 45062 * may pop up in your scene once the respective loading process is finished. 45063 * 45064 * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI. 45065 * @param {function(Texture)} onLoad - Executed when the loading process has been finished. 45066 * @param {onProgressCallback} onProgress - Unsupported in this loader. 45067 * @param {onErrorCallback} onError - Executed when errors occur. 45068 * @return {Texture} The texture. 45069 */ 45070 load( url, onLoad, onProgress, onError ) { 45071 45072 const texture = new Texture(); 45073 45074 const loader = new ImageLoader( this.manager ); 45075 loader.setCrossOrigin( this.crossOrigin ); 45076 loader.setPath( this.path ); 45077 45078 loader.load( url, function ( image ) { 45079 45080 texture.image = image; 45081 texture.needsUpdate = true; 45082 45083 if ( onLoad !== undefined ) { 45084 45085 onLoad( texture ); 45086 45087 } 45088 45089 }, onProgress, onError ); 45090 45091 return texture; 45092 45093 } 45094 45095} 45096 45097/** 45098 * Abstract base class for lights - all other light types inherit the 45099 * properties and methods described here. 45100 * 45101 * @abstract 45102 * @augments Object3D 45103 */ 45104class Light extends Object3D { 45105 45106 /** 45107 * Constructs a new light. 45108 * 45109 * @param {(number|Color|string)} [color=0xffffff] - The light's color. 45110 * @param {number} [intensity=1] - The light's strength/intensity. 45111 */ 45112 constructor( color, intensity = 1 ) { 45113 45114 super(); 45115 45116 /** 45117 * This flag can be used for type testing. 45118 * 45119 * @type {boolean} 45120 * @readonly 45121 * @default true 45122 */ 45123 this.isLight = true; 45124 45125 this.type = 'Light'; 45126 45127 /** 45128 * The light's color. 45129 * 45130 * @type {Color} 45131 */ 45132 this.color = new Color( color ); 45133 45134 /** 45135 * The light's intensity. 45136 * 45137 * @type {number} 45138 * @default 1 45139 */ 45140 this.intensity = intensity; 45141 45142 } 45143 45144 /** 45145 * Frees the GPU-related resources allocated by this instance. Call this 45146 * method whenever this instance is no longer used in your app. 45147 */ 45148 dispose() { 45149 45150 this.dispatchEvent( { type: 'dispose' } )
vendor: 6,027 bytes, lines 45150-45427
45150; 45151 45152 } 45153 45154 copy( source, recursive ) { 45155 45156 super.copy( source, recursive ); 45157 45158 this.color.copy( source.color ); 45159 this.intensity = source.intensity; 45160 45161 return this; 45162 45163 } 45164 45165 toJSON( meta ) { 45166 45167 const data = super.toJSON( meta ); 45168 45169 data.object.color = this.color.getHex(); 45170 data.object.intensity = this.intensity; 45171 45172 return data; 45173 45174 } 45175 45176} 45177 45178/** 45179 * A light source positioned directly above the scene, with color fading from 45180 * the sky color to the ground color. 45181 * 45182 * This light cannot be used to cast shadows. 45183 * 45184 * ```js 45185 * const light = new THREE.HemisphereLight( 0xffffbb, 0x080820, 1 ); 45186 * scene.add( light ); 45187 * ``` 45188 * 45189 * @augments Light 45190 */ 45191class HemisphereLight extends Light { 45192 45193 /** 45194 * Constructs a new hemisphere light. 45195 * 45196 * @param {(number|Color|string)} [skyColor=0xffffff] - The light's sky color. 45197 * @param {(number|Color|string)} [groundColor=0xffffff] - The light's ground color. 45198 * @param {number} [intensity=1] - The light's strength/intensity. 45199 */ 45200 constructor( skyColor, groundColor, intensity ) { 45201 45202 super( skyColor, intensity ); 45203 45204 /** 45205 * This flag can be used for type testing. 45206 * 45207 * @type {boolean} 45208 * @readonly 45209 * @default true 45210 */ 45211 this.isHemisphereLight = true; 45212 45213 this.type = 'HemisphereLight'; 45214 45215 this.position.copy( Object3D.DEFAULT_UP ); 45216 this.updateMatrix(); 45217 45218 /** 45219 * The light's ground color. 45220 * 45221 * @type {Color} 45222 */ 45223 this.groundColor = new Color( groundColor ); 45224 45225 } 45226 45227 copy( source, recursive ) { 45228 45229 super.copy( source, recursive ); 45230 45231 this.groundColor.copy( source.groundColor ); 45232 45233 return this; 45234 45235 } 45236 45237 toJSON( meta ) { 45238 45239 const data = super.toJSON( meta ); 45240 45241 data.object.groundColor = this.groundColor.getHex(); 45242 45243 return data; 45244 45245 } 45246 45247} 45248 45249const _projScreenMatrix = /*@__PURE__*/ new Matrix4(); 45250const _lightPositionWorld = /*@__PURE__*/ new Vector3(); 45251const _lookTarget = /*@__PURE__*/ new Vector3(); 45252 45253/** 45254 * Abstract base class for light shadow classes. These classes 45255 * represent the shadow configuration for different light types. 45256 * 45257 * @abstract 45258 */ 45259class LightShadow { 45260 45261 /** 45262 * Constructs a new light shadow. 45263 * 45264 * @param {Camera} camera - The light's view of the world. 45265 */ 45266 constructor( camera ) { 45267 45268 /** 45269 * The light's view of the world. 45270 * 45271 * @type {Camera} 45272 */ 45273 this.camera = camera; 45274 45275 /** 45276 * The intensity of the shadow. The default is `1`. 45277 * Valid values are in the range `[0, 1]`. 45278 * 45279 * @type {number} 45280 * @default 1 45281 */ 45282 this.intensity = 1; 45283 45284 /** 45285 * Shadow map bias, how much to add or subtract from the normalized depth 45286 * when deciding whether a surface is in shadow. 45287 * 45288 * The default is `0`. Very tiny adjustments here (in the order of `0.0001`) 45289 * may help reduce artifacts in shadows. 45290 * 45291 * @type {number} 45292 * @default 0 45293 */ 45294 this.bias = 0; 45295 45296 /** 45297 * A node version of `bias`. Only supported with `WebGPURenderer`. 45298 * 45299 * If a bias node is defined, `bias` has no effect. 45300 * 45301 * @type {?Node<float>} 45302 * @default null 45303 */ 45304 this.biasNode = null; 45305 45306 /** 45307 * Defines how much the position used to query the shadow map is offset along 45308 * the object normal. The default is `0`. Increasing this value can be used to 45309 * reduce shadow acne especially in large scenes where light shines onto 45310 * geometry at a shallow angle. The cost is that shadows may appear distorted. 45311 * 45312 * @type {number} 45313 * @default 0 45314 */ 45315 this.normalBias = 0; 45316 45317 /** 45318 * Setting this to values greater than 1 will blur the edges of the shadow. 45319 * High values will cause unwanted banding effects in the shadows - a greater 45320 * map size will allow for a higher value to be used here before these effects 45321 * become visible. 45322 * 45323 * The property has no effect when the shadow map type is `BasicShadowMap`. 45324 * 45325 * @type {number} 45326 * @default 1 45327 */ 45328 this.radius = 1; 45329 45330 /** 45331 * The amount of samples to use when blurring a VSM shadow map. 45332 * 45333 * @type {number} 45334 * @default 8 45335 */ 45336 this.blurSamples = 8; 45337 45338 /** 45339 * Defines the width and height of the shadow map. Higher values give better quality 45340 * shadows at the cost of computation time. Values must be powers of two. 45341 * 45342 * @type {Vector2} 45343 * @default (512,512) 45344 */ 45345 this.mapSize = new Vector2( 512, 512 ); 45346 45347 /** 45348 * The type of shadow texture. The default is `UnsignedByteType`. 45349 * 45350 * @type {number} 45351 * @default UnsignedByteType 45352 */ 45353 this.mapType = UnsignedByteType; 45354 45355 /** 45356 * The depth map generated using the internal camera; a location beyond a 45357 * pixel's depth is in shadow. Computed internally during rendering. 45358 * 45359 * @type {?RenderTarget} 45360 * @default null 45361 */ 45362 this.map = null; 45363 45364 /** 45365 * The distribution map generated using the internal camera; an occlusion is 45366 * calculated based on the distribution of depths. Computed internally during 45367 * rendering. 45368 * 45369 * @type {?RenderTarget} 45370 * @default null 45371 */ 45372 this.mapPass = null; 45373 45374 /** 45375 * Model to shadow camera space, to compute location and depth in shadow map. 45376 * This is computed internally during rendering. 45377 * 45378 * @type {Matrix4} 45379 */ 45380 this.matrix = new Matrix4(); 45381 45382 /** 45383 * Enables automatic updates of the light's shadow. If you do not require dynamic 45384 * lighting / shadows, you may set this to `false`. 45385 * 45386 * @type {boolean} 45387 * @default true 45388 */ 45389 this.autoUpdate = true; 45390 45391 /** 45392 * When set to `true`, shadow maps will be updated in the next `render` call. 45393 * If you have set {@link LightShadow#autoUpdate} to `false`, you will need to 45394 * set this property to `true` and then make a render call to update the light's shadow. 45395 * 45396 * @type {boolean} 45397 * @default false 45398 */ 45399 this.needsUpdate = false; 45400 45401 this._frustum = new Frustum(); 45402 this._frameExtents = new Vector2( 1, 1 ); 45403 45404 this._viewportCount = 1; 45405 45406 this._viewports = [ 45407 45408 new Vector4( 0, 0, 1, 1 ) 45409 45410 ]; 45411 45412 } 45413 45414 /** 45415 * Used internally by the renderer to get the number of viewports that need 45416 * to be rendered for this shadow. 45417 * 45418 * @return {number} The viewport count. 45419 */ 45420 getViewportCount() { 45421 45422 return this._viewportCount; 45423 45424 } 45425 45426 /** 45427 *
45427Gets the shadow cameras frustum. Used internally by the renderer to cull objects. 45428 * 45429 * @return {Frustum} The shadow camera frustum. 45430 */ 45431 getFrustum() { 45432 45433 return this._frustum; 45434 45435 } 45436 45437 /** 45438 * Update the matrices for the camera and shadow, used internally by the renderer. 45439 * 45440 * @param {Light} light - The light for which the shadow is being rendered. 45441 */ 45442 updateMatrices( light ) { 45443 45444 const shadowCamera = this.camera; 45445 const shadowMatrix = this.matrix; 45446 45447 _lightPositionWorld.setFromMatrixPosition( light.matrixWorld ); 45448 shadowCamera.position.copy( _lightPositionWorld ); 45449 45450 _lookTarget.setFromMatrixPosition( light.target.matrixWorld ); 45451 shadowCamera.lookAt( _lookTarget ); 45452 shadowCamera.updateMatrixWorld(); 45453 45454 _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); 45455 this._frustum.setFromProjectionMatrix( _projScreenMatrix, shadowCamera.coordinateSystem, shadowCamera.reversedDepth ); 45456 45457 if ( shadowCamera.coordinateSystem === WebGPUCoordinateSystem || shadowCamera.reversedDepth ) { 45458 45459 shadowMatrix.set( 45460 0.5, 0.0, 0.0, 0.5, 45461 0.0, 0.5, 0.0, 0.5, 45462 0.0, 0.0, 1.0, 0.0, // Identity Z (preserving the correct [0, 1] range from the projection matrix) 45463 0.0, 0.0, 0.0, 1.0 45464 ); 45465 45466 } else { 45467 45468 shadowMatrix.set( 45469 0.5, 0.0, 0.0, 0.5, 45470 0.0, 0.5, 0.0, 0.5, 45471 0.0, 0.0, 0.5, 0.5, 45472 0.0, 0.0, 0.0, 1.0 45473 ); 45474 45475 } 45476 45477 shadowMatrix.multiply( _projScreenMatrix
vendor: 8,639 bytes, lines 45477-45878
45477 ); 45478 45479 } 45480 45481 /** 45482 * Returns a viewport definition for the given viewport index. 45483 * 45484 * @param {number} viewportIndex - The viewport index. 45485 * @return {Vector4} The viewport. 45486 */ 45487 getViewport( viewportIndex ) { 45488 45489 return this._viewports[ viewportIndex ]; 45490 45491 } 45492 45493 /** 45494 * Returns the frame extends. 45495 * 45496 * @return {Vector2} The frame extends. 45497 */ 45498 getFrameExtents() { 45499 45500 return this._frameExtents; 45501 45502 } 45503 45504 /** 45505 * Frees the GPU-related resources allocated by this instance. Call this 45506 * method whenever this instance is no longer used in your app. 45507 */ 45508 dispose() { 45509 45510 if ( this.map ) { 45511 45512 this.map.dispose(); 45513 45514 } 45515 45516 if ( this.mapPass ) { 45517 45518 this.mapPass.dispose(); 45519 45520 } 45521 45522 } 45523 45524 /** 45525 * Copies the values of the given light shadow instance to this instance. 45526 * 45527 * @param {LightShadow} source - The light shadow to copy. 45528 * @return {LightShadow} A reference to this light shadow instance. 45529 */ 45530 copy( source ) { 45531 45532 this.camera = source.camera.clone(); 45533 45534 this.intensity = source.intensity; 45535 45536 this.bias = source.bias; 45537 this.radius = source.radius; 45538 45539 this.autoUpdate = source.autoUpdate; 45540 this.needsUpdate = source.needsUpdate; 45541 this.normalBias = source.normalBias; 45542 this.blurSamples = source.blurSamples; 45543 45544 this.mapSize.copy( source.mapSize ); 45545 45546 this.biasNode = source.biasNode; 45547 45548 return this; 45549 45550 } 45551 45552 /** 45553 * Returns a new light shadow instance with copied values from this instance. 45554 * 45555 * @return {LightShadow} A clone of this instance. 45556 */ 45557 clone() { 45558 45559 return new this.constructor().copy( this ); 45560 45561 } 45562 45563 /** 45564 * Serializes the light shadow into JSON. 45565 * 45566 * @return {Object} A JSON object representing the serialized light shadow. 45567 * @see {@link ObjectLoader#parse} 45568 */ 45569 toJSON() { 45570 45571 const object = {}; 45572 45573 if ( this.intensity !== 1 ) object.intensity = this.intensity; 45574 if ( this.bias !== 0 ) object.bias = this.bias; 45575 if ( this.normalBias !== 0 ) object.normalBias = this.normalBias; 45576 if ( this.radius !== 1 ) object.radius = this.radius; 45577 if ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray(); 45578 45579 object.camera = this.camera.toJSON( false ).object; 45580 delete object.camera.matrix; 45581 45582 return object; 45583 45584 } 45585 45586} 45587 45588const _position$2 = /*@__PURE__*/ new Vector3(); 45589const _quaternion$2 = /*@__PURE__*/ new Quaternion(); 45590const _scale$2 = /*@__PURE__*/ new Vector3(); 45591 45592/** 45593 * Abstract base class for cameras. This class should always be inherited 45594 * when you build a new camera. 45595 * 45596 * @abstract 45597 * @augments Object3D 45598 */ 45599class Camera extends Object3D { 45600 45601 /** 45602 * Constructs a new camera. 45603 */ 45604 constructor() { 45605 45606 super(); 45607 45608 /** 45609 * This flag can be used for type testing. 45610 * 45611 * @type {boolean} 45612 * @readonly 45613 * @default true 45614 */ 45615 this.isCamera = true; 45616 45617 this.type = 'Camera'; 45618 45619 /** 45620 * The inverse of the camera's world matrix. 45621 * 45622 * @type {Matrix4} 45623 */ 45624 this.matrixWorldInverse = new Matrix4(); 45625 45626 /** 45627 * The camera's projection matrix. 45628 * 45629 * @type {Matrix4} 45630 */ 45631 this.projectionMatrix = new Matrix4(); 45632 45633 /** 45634 * The inverse of the camera's projection matrix. 45635 * 45636 * @type {Matrix4} 45637 */ 45638 this.projectionMatrixInverse = new Matrix4(); 45639 45640 /** 45641 * The coordinate system in which the camera is used. 45642 * 45643 * @type {(WebGLCoordinateSystem|WebGPUCoordinateSystem)} 45644 */ 45645 this.coordinateSystem = WebGLCoordinateSystem; 45646 45647 this._reversedDepth = false; 45648 45649 } 45650 45651 /** 45652 * The flag that indicates whether the camera uses a reversed depth buffer. 45653 * 45654 * @type {boolean} 45655 * @default false 45656 */ 45657 get reversedDepth() { 45658 45659 return this._reversedDepth; 45660 45661 } 45662 45663 copy( source, recursive ) { 45664 45665 super.copy( source, recursive ); 45666 45667 this.matrixWorldInverse.copy( source.matrixWorldInverse ); 45668 45669 this.projectionMatrix.copy( source.projectionMatrix ); 45670 this.projectionMatrixInverse.copy( source.projectionMatrixInverse ); 45671 45672 this.coordinateSystem = source.coordinateSystem; 45673 45674 return this; 45675 45676 } 45677 45678 /** 45679 * Returns a vector representing the ("look") direction of the 3D object in world space. 45680 * 45681 * This method is overwritten since cameras have a different forward vector compared to other 45682 * 3D objects. A camera looks down its local, negative z-axis by default. 45683 * 45684 * @param {Vector3} target - The target vector the result is stored to. 45685 * @return {Vector3} The 3D object's direction in world space. 45686 */ 45687 getWorldDirection( target ) { 45688 45689 return super.getWorldDirection( target ).negate(); 45690 45691 } 45692 45693 updateMatrixWorld( force ) { 45694 45695 super.updateMatrixWorld( force ); 45696 45697 // exclude scale from view matrix to be glTF conform 45698 45699 this.matrixWorld.decompose( _position$2, _quaternion$2, _scale$2 ); 45700 45701 if ( _scale$2.x === 1 && _scale$2.y === 1 && _scale$2.z === 1 ) { 45702 45703 this.matrixWorldInverse.copy( this.matrixWorld ).invert(); 45704 45705 } else { 45706 45707 this.matrixWorldInverse.compose( _position$2, _quaternion$2, _scale$2.set( 1, 1, 1 ) ).invert(); 45708 45709 } 45710 45711 } 45712 45713 updateWorldMatrix( updateParents, updateChildren ) { 45714 45715 super.updateWorldMatrix( updateParents, updateChildren ); 45716 45717 // exclude scale from view matrix to be glTF conform 45718 45719 this.matrixWorld.decompose( _position$2, _quaternion$2, _scale$2 ); 45720 45721 if ( _scale$2.x === 1 && _scale$2.y === 1 && _scale$2.z === 1 ) { 45722 45723 this.matrixWorldInverse.copy( this.matrixWorld ).invert(); 45724 45725 } else { 45726 45727 this.matrixWorldInverse.compose( _position$2, _quaternion$2, _scale$2.set( 1, 1, 1 ) ).invert(); 45728 45729 } 45730 45731 } 45732 45733 clone() { 45734 45735 return new this.constructor().copy( this ); 45736 45737 } 45738 45739} 45740 45741const _v3$1 = /*@__PURE__*/ new Vector3(); 45742const _minTarget = /*@__PURE__*/ new Vector2(); 45743const _maxTarget = /*@__PURE__*/ new Vector2(); 45744 45745/** 45746 * Camera that uses [perspective projection](https://en.wikipedia.org/wiki/Perspective_(graphical)). 45747 * 45748 * This projection mode is designed to mimic the way the human eye sees. It 45749 * is the most common projection mode used for rendering a 3D scene. 45750 * 45751 * ```js 45752 * const camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 ); 45753 * scene.add( camera ); 45754 * ``` 45755 * 45756 * @augments Camera 45757 */ 45758class PerspectiveCamera extends Camera { 45759 45760 /** 45761 * Constructs a new perspective camera. 45762 * 45763 * @param {number} [fov=50] - The vertical field of view. 45764 * @param {number} [aspect=1] - The aspect ratio. 45765 * @param {number} [near=0.1] - The camera's near plane. 45766 * @param {number} [far=2000] - The camera's far plane. 45767 */ 45768 constructor( fov = 50, aspect = 1, near = 0.1, far = 2000 ) { 45769 45770 super(); 45771 45772 /** 45773 * This flag can be used for type testing. 45774 * 45775 * @type {boolean} 45776 * @readonly 45777 * @default true 45778 */ 45779 this.isPerspectiveCamera = true; 45780 45781 this.type = 'PerspectiveCamera'; 45782 45783 /** 45784 * The vertical field of view, from bottom to top of view, 45785 * in degrees. 45786 * 45787 * @type {number} 45788 * @default 50 45789 */ 45790 this.fov = fov; 45791 45792 /** 45793 * The zoom factor of the camera. 45794 * 45795 * @type {number} 45796 * @default 1 45797 */ 45798 this.zoom = 1; 45799 45800 /** 45801 * The camera's near plane. The valid range is greater than `0` 45802 * and less than the current value of {@link PerspectiveCamera#far}. 45803 * 45804 * Note that, unlike for the {@link OrthographicCamera}, `0` is <em>not</em> a 45805 * valid value for a perspective camera's near plane. 45806 * 45807 * @type {number} 45808 * @default 0.1 45809 */ 45810 this.near = near; 45811 45812 /** 45813 * The camera's far plane. Must be greater than the 45814 * current value of {@link PerspectiveCamera#near}. 45815 * 45816 * @type {number} 45817 * @default 2000 45818 */ 45819 this.far = far; 45820 45821 /** 45822 * Object distance used for stereoscopy and depth-of-field effects. This 45823 * parameter does not influence the projection matrix unless a 45824 * {@link StereoCamera} is being used. 45825 * 45826 * @type {number} 45827 * @default 10 45828 */ 45829 this.focus = 10; 45830 45831 /** 45832 * The aspect ratio, usually the canvas width / canvas height. 45833 * 45834 * @type {number} 45835 * @default 1 45836 */ 45837 this.aspect = aspect; 45838 45839 /** 45840 * Represents the frustum window specification. This property should not be edited 45841 * directly but via {@link PerspectiveCamera#setViewOffset} and {@link PerspectiveCamera#clearViewOffset}. 45842 * 45843 * @type {?Object} 45844 * @default null 45845 */ 45846 this.view = null; 45847 45848 /** 45849 * Film size used for the larger axis. Default is `35` (millimeters). This 45850 * parameter does not influence the projection matrix unless {@link PerspectiveCamera#filmOffset} 45851 * is set to a nonzero value. 45852 * 45853 * @type {number} 45854 * @default 35 45855 */ 45856 this.filmGauge = 35; 45857 45858 /** 45859 * Horizontal off-center offset in the same unit as {@link PerspectiveCamera#filmGauge}. 45860 * 45861 * @type {number} 45862 * @default 0 45863 */ 45864 this.filmOffset = 0; 45865 45866 this.updateProjectionMatrix(); 45867 45868 } 45869 45870 copy( source, recursive ) { 45871 45872 super.copy( source, recursive ); 45873 45874 this.fov = source.fov; 45875 this.zoom = source.zoom; 45876 45877 this.near = source.near; 45878 this.far = source.far;
vendor: 5,593 bytes, lines 45879-46068
45879 this.focus = source.focus; 45880 45881 this.aspect = source.aspect; 45882 this.view = source.view === null ? null : Object.assign( {}, source.view ); 45883 45884 this.filmGauge = source.filmGauge; 45885 this.filmOffset = source.filmOffset; 45886 45887 return this; 45888 45889 } 45890 45891 /** 45892 * Sets the FOV by focal length in respect to the current {@link PerspectiveCamera#filmGauge}. 45893 * 45894 * The default film gauge is 35, so that the focal length can be specified for 45895 * a 35mm (full frame) camera. 45896 * 45897 * @param {number} focalLength - Values for focal length and film gauge must have the same unit. 45898 */ 45899 setFocalLength( focalLength ) { 45900 45901 /** see {@link http://www.bobatkins.com/photography/technical/field_of_view.html} */ 45902 const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength; 45903 45904 this.fov = RAD2DEG * 2 * Math.atan( vExtentSlope ); 45905 this.updateProjectionMatrix(); 45906 45907 } 45908 45909 /** 45910 * Returns the focal length from the current {@link PerspectiveCamera#fov} and 45911 * {@link PerspectiveCamera#filmGauge}. 45912 * 45913 * @return {number} The computed focal length. 45914 */ 45915 getFocalLength() { 45916 45917 const vExtentSlope = Math.tan( DEG2RAD * 0.5 * this.fov ); 45918 45919 return 0.5 * this.getFilmHeight() / vExtentSlope; 45920 45921 } 45922 45923 /** 45924 * Returns the current vertical field of view angle in degrees considering {@link PerspectiveCamera#zoom}. 45925 * 45926 * @return {number} The effective FOV. 45927 */ 45928 getEffectiveFOV() { 45929 45930 return RAD2DEG * 2 * Math.atan( 45931 Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom ); 45932 45933 } 45934 45935 /** 45936 * Returns the width of the image on the film. If {@link PerspectiveCamera#aspect} is greater than or 45937 * equal to one (landscape format), the result equals {@link PerspectiveCamera#filmGauge}. 45938 * 45939 * @return {number} The film width. 45940 */ 45941 getFilmWidth() { 45942 45943 // film not completely covered in portrait format (aspect < 1) 45944 return this.filmGauge * Math.min( this.aspect, 1 ); 45945 45946 } 45947 45948 /** 45949 * Returns the height of the image on the film. If {@link PerspectiveCamera#aspect} is greater than or 45950 * equal to one (landscape format), the result equals {@link PerspectiveCamera#filmGauge}. 45951 * 45952 * @return {number} The film width. 45953 */ 45954 getFilmHeight() { 45955 45956 // film not completely covered in landscape format (aspect > 1) 45957 return this.filmGauge / Math.max( this.aspect, 1 ); 45958 45959 } 45960 45961 /** 45962 * Computes the 2D bounds of the camera's viewable rectangle at a given distance along the viewing direction. 45963 * Sets `minTarget` and `maxTarget` to the coordinates of the lower-left and upper-right corners of the view rectangle. 45964 * 45965 * @param {number} distance - The viewing distance. 45966 * @param {Vector2} minTarget - The lower-left corner of the view rectangle is written into this vector. 45967 * @param {Vector2} maxTarget - The upper-right corner of the view rectangle is written into this vector. 45968 */ 45969 getViewBounds( distance, minTarget, maxTarget ) { 45970 45971 _v3$1.set( -1, -1, 0.5 ).applyMatrix4( this.projectionMatrixInverse ); 45972 45973 minTarget.set( _v3$1.x, _v3$1.y ).multiplyScalar( - distance / _v3$1.z ); 45974 45975 _v3$1.set( 1, 1, 0.5 ).applyMatrix4( this.projectionMatrixInverse ); 45976 45977 maxTarget.set( _v3$1.x, _v3$1.y ).multiplyScalar( - distance / _v3$1.z ); 45978 45979 } 45980 45981 /** 45982 * Computes the width and height of the camera's viewable rectangle at a given distance along the viewing direction. 45983 * 45984 * @param {number} distance - The viewing distance. 45985 * @param {Vector2} target - The target vector that is used to store result where x is width and y is height. 45986 * @returns {Vector2} The view size. 45987 */ 45988 getViewSize( distance, target ) { 45989 45990 this.getViewBounds( distance, _minTarget, _maxTarget ); 45991 45992 return target.subVectors( _maxTarget, _minTarget ); 45993 45994 } 45995 45996 /** 45997 * Sets an offset in a larger frustum. This is useful for multi-window or 45998 * multi-monitor/multi-machine setups. 45999 * 46000 * For example, if you have 3x2 monitors and each monitor is 1920x1080 and 46001 * the monitors are in grid like this 46002 *``` 46003 * +---+---+---+ 46004 * | A | B | C | 46005 * +---+---+---+ 46006 * | D | E | F | 46007 * +---+---+---+ 46008 *``` 46009 * then for each monitor you would call it like this: 46010 *```js 46011 * const w = 1920; 46012 * const h = 1080; 46013 * const fullWidth = w * 3; 46014 * const fullHeight = h * 2; 46015 * 46016 * // --A-- 46017 * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); 46018 * // --B-- 46019 * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); 46020 * // --C-- 46021 * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); 46022 * // --D-- 46023 * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); 46024 * // --E-- 46025 * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); 46026 * // --F-- 46027 * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); 46028 * ``` 46029 * 46030 * Note there is no reason monitors have to be the same size or in a grid. 46031 * 46032 * @param {number} fullWidth - The full width of multiview setup. 46033 * @param {number} fullHeight - The full height of multiview setup. 46034 * @param {number} x - The horizontal offset of the subcamera. 46035 * @param {number} y - The vertical offset of the subcamera. 46036 * @param {number} width - The width of subcamera. 46037 * @param {number} height - The height of subcamera. 46038 */ 46039 setViewOffset( fullWidth, fullHeight, x, y, width, height ) { 46040 46041 this.aspect = fullWidth / fullHeight; 46042 46043 if ( this.view === null ) { 46044 46045 this.view = { 46046 enabled: true, 46047 fullWidth: 1, 46048 fullHeight: 1, 46049 offsetX: 0, 46050 offsetY: 0, 46051 width: 1, 46052 height: 1 46053 }; 46054 46055 } 46056 46057 this.view.enabled = true; 46058 this.view.fullWidth = fullWidth; 46059 this.view.fullHeight = fullHeight; 46060 this.view.offsetX = x; 46061 this.view.offsetY = y; 46062 this.view.width = width; 46063 this.view.height = height; 46064 46065 this.updateProjectionMatrix(); 46066 46067 } 46068
vendor: 6,394 bytes, lines 46069-46338
46069 /** 46070 * Removes the view offset from the projection matrix. 46071 */ 46072 clearViewOffset() { 46073 46074 if ( this.view !== null ) { 46075 46076 this.view.enabled = false; 46077 46078 } 46079 46080 this.updateProjectionMatrix(); 46081 46082 } 46083 46084 /** 46085 * Updates the camera's projection matrix. Must be called after any change of 46086 * camera properties. 46087 */ 46088 updateProjectionMatrix() { 46089 46090 const near = this.near; 46091 let top = near * Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom; 46092 let height = 2 * top; 46093 let width = this.aspect * height; 46094 let left = -0.5 * width; 46095 const view = this.view; 46096 46097 if ( this.view !== null && this.view.enabled ) { 46098 46099 const fullWidth = view.fullWidth, 46100 fullHeight = view.fullHeight; 46101 46102 left += view.offsetX * width / fullWidth; 46103 top -= view.offsetY * height / fullHeight; 46104 width *= view.width / fullWidth; 46105 height *= view.height / fullHeight; 46106 46107 } 46108 46109 const skew = this.filmOffset; 46110 if ( skew !== 0 ) left += near * skew / this.getFilmWidth(); 46111 46112 this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far, this.coordinateSystem, this.reversedDepth ); 46113 46114 this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); 46115 46116 } 46117 46118 toJSON( meta ) { 46119 46120 const data = super.toJSON( meta ); 46121 46122 data.object.fov = this.fov; 46123 data.object.zoom = this.zoom; 46124 46125 data.object.near = this.near; 46126 data.object.far = this.far; 46127 data.object.focus = this.focus; 46128 46129 data.object.aspect = this.aspect; 46130 46131 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); 46132 46133 data.object.filmGauge = this.filmGauge; 46134 data.object.filmOffset = this.filmOffset; 46135 46136 return data; 46137 46138 } 46139 46140} 46141 46142/** 46143 * Represents the shadow configuration of directional lights. 46144 * 46145 * @augments LightShadow 46146 */ 46147class SpotLightShadow extends LightShadow { 46148 46149 /** 46150 * Constructs a new spot light shadow. 46151 */ 46152 constructor() { 46153 46154 super( new PerspectiveCamera( 50, 1, 0.5, 500 ) ); 46155 46156 /** 46157 * This flag can be used for type testing. 46158 * 46159 * @type {boolean} 46160 * @readonly 46161 * @default true 46162 */ 46163 this.isSpotLightShadow = true; 46164 46165 /** 46166 * Used to focus the shadow camera. The camera's field of view is set as a 46167 * percentage of the spotlight's field-of-view. Range is `[0, 1]`. 46168 * 46169 * @type {number} 46170 * @default 1 46171 */ 46172 this.focus = 1; 46173 46174 /** 46175 * Texture aspect ratio. 46176 * 46177 * @type {number} 46178 * @default 1 46179 */ 46180 this.aspect = 1; 46181 46182 } 46183 46184 updateMatrices( light ) { 46185 46186 const camera = this.camera; 46187 46188 const fov = RAD2DEG * 2 * light.angle * this.focus; 46189 const aspect = ( this.mapSize.width / this.mapSize.height ) * this.aspect; 46190 const far = light.distance || camera.far; 46191 46192 if ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) { 46193 46194 camera.fov = fov; 46195 camera.aspect = aspect; 46196 camera.far = far; 46197 camera.updateProjectionMatrix(); 46198 46199 } 46200 46201 super.updateMatrices( light ); 46202 46203 } 46204 46205 copy( source ) { 46206 46207 super.copy( source ); 46208 46209 this.focus = source.focus; 46210 46211 return this; 46212 46213 } 46214 46215} 46216 46217/** 46218 * This light gets emitted from a single point in one direction, along a cone 46219 * that increases in size the further from the light it gets. 46220 * 46221 * This light can cast shadows - see the {@link SpotLightShadow} for details. 46222 * 46223 * ```js 46224 * // white spotlight shining from the side, modulated by a texture 46225 * const spotLight = new THREE.SpotLight( 0xffffff ); 46226 * spotLight.position.set( 100, 1000, 100 ); 46227 * spotLight.map = new THREE.TextureLoader().load( url ); 46228 * 46229 * spotLight.castShadow = true; 46230 * spotLight.shadow.mapSize.width = 1024; 46231 * spotLight.shadow.mapSize.height = 1024; 46232 * spotLight.shadow.camera.near = 500; 46233 * spotLight.shadow.camera.far = 4000; 46234 * spotLight.shadow.camera.fov = 30;s 46235 * ``` 46236 * 46237 * @augments Light 46238 */ 46239class SpotLight extends Light { 46240 46241 /** 46242 * Constructs a new spot light. 46243 * 46244 * @param {(number|Color|string)} [color=0xffffff] - The light's color. 46245 * @param {number} [intensity=1] - The light's strength/intensity measured in candela (cd). 46246 * @param {number} [distance=0] - Maximum range of the light. `0` means no limit. 46247 * @param {number} [angle=Math.PI/3] - Maximum angle of light dispersion from its direction whose upper bound is `Math.PI/2`. 46248 * @param {number} [penumbra=0] - Percent of the spotlight cone that is attenuated due to penumbra. Value range is `[0,1]`. 46249 * @param {number} [decay=2] - The amount the light dims along the distance of the light. 46250 */ 46251 constructor( color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 2 ) { 46252 46253 super( color, intensity ); 46254 46255 /** 46256 * This flag can be used for type testing. 46257 * 46258 * @type {boolean} 46259 * @readonly 46260 * @default true 46261 */ 46262 this.isSpotLight = true; 46263 46264 this.type = 'SpotLight'; 46265 46266 this.position.copy( Object3D.DEFAULT_UP ); 46267 this.updateMatrix(); 46268 46269 /** 46270 * The spot light points from its position to the 46271 * target's position. 46272 * 46273 * For the target's position to be changed to anything other 46274 * than the default, it must be added to the scene. 46275 * 46276 * It is also possible to set the target to be another 3D object 46277 * in the scene. The light will now track the target object. 46278 * 46279 * @type {Object3D} 46280 */ 46281 this.target = new Object3D(); 46282 46283 /** 46284 * Maximum range of the light. `0` means no limit. 46285 * 46286 * @type {number} 46287 * @default 0 46288 */ 46289 this.distance = distance; 46290 46291 /** 46292 * Maximum angle of light dispersion from its direction whose upper bound is `Math.PI/2`. 46293 * 46294 * @type {number} 46295 * @default Math.PI/3 46296 */ 46297 this.angle = angle; 46298 46299 /** 46300 * Percent of the spotlight cone that is attenuated due to penumbra. 46301 * Value range is `[0,1]`. 46302 * 46303 * @type {number} 46304 * @default 0 46305 */ 46306 this.penumbra = penumbra; 46307 46308 /** 46309 * The amount the light dims along the distance of the light. In context of 46310 * physically-correct rendering the default value should not be changed. 46311 * 46312 * @type {number} 46313 * @default 2 46314 */ 46315 this.decay = decay; 46316 46317 /** 46318 * A texture used to modulate the color of the light. The spot light 46319 * color is mixed with the RGB value of this texture, with a ratio 46320 * corresponding to its alpha value. The cookie-like masking effect is 46321 * reproduced using pixel values (0, 0, 0, 1-cookie_value). 46322 * 46323 * *Warning*: This property is disabled if {@link Object3D#castShadow} is set to `false`. 46324 * 46325 * @type {?Texture} 46326 * @default null 46327 */ 46328 this.map = null; 46329 46330 /** 46331 * This property holds the light's shadow configuration. 46332 * 46333 * @type {SpotLightShadow} 46334 */ 46335 this.shadow = new SpotLightShadow(); 46336 46337 } 46338
vendor: 26,517 bytes, lines 46339-47496
46339 /** 46340 * The light's power. Power is the luminous power of the light measured in lumens (lm). 46341 * Changing the power will also change the light's intensity. 46342 * 46343 * @type {number} 46344 */ 46345 get power() { 46346 46347 // compute the light's luminous power (in lumens) from its intensity (in candela) 46348 // by convention for a spotlight, luminous power (lm) = Ï * luminous intensity (cd) 46349 return this.intensity * Math.PI; 46350 46351 } 46352 46353 set power( power ) { 46354 46355 // set the light's intensity (in candela) from the desired luminous power (in lumens) 46356 this.intensity = power / Math.PI; 46357 46358 } 46359 46360 dispose() { 46361 46362 super.dispose(); 46363 46364 this.shadow.dispose(); 46365 46366 } 46367 46368 copy( source, recursive ) { 46369 46370 super.copy( source, recursive ); 46371 46372 this.distance = source.distance; 46373 this.angle = source.angle; 46374 this.penumbra = source.penumbra; 46375 this.decay = source.decay; 46376 46377 this.target = source.target.clone(); 46378 this.map = source.map; 46379 this.shadow = source.shadow.clone(); 46380 46381 return this; 46382 46383 } 46384 46385 toJSON( meta ) { 46386 46387 const data = super.toJSON( meta ); 46388 46389 data.object.distance = this.distance; 46390 data.object.angle = this.angle; 46391 data.object.decay = this.decay; 46392 data.object.penumbra = this.penumbra; 46393 46394 data.object.target = this.target.uuid; 46395 46396 if ( this.map && this.map.isTexture ) data.object.map = this.map.toJSON( meta ).uuid; 46397 46398 data.object.shadow = this.shadow.toJSON(); 46399 46400 return data; 46401 46402 } 46403 46404} 46405 46406/** 46407 * Represents the shadow configuration of point lights. 46408 * 46409 * @augments LightShadow 46410 */ 46411class PointLightShadow extends LightShadow { 46412 46413 /** 46414 * Constructs a new point light shadow. 46415 */ 46416 constructor() { 46417 46418 super( new PerspectiveCamera( 90, 1, 0.5, 500 ) ); 46419 46420 /** 46421 * This flag can be used for type testing. 46422 * 46423 * @type {boolean} 46424 * @readonly 46425 * @default true 46426 */ 46427 this.isPointLightShadow = true; 46428 46429 } 46430 46431} 46432 46433/** 46434 * A light that gets emitted from a single point in all directions. A common 46435 * use case for this is to replicate the light emitted from a bare 46436 * lightbulb. 46437 * 46438 * This light can cast shadows - see the {@link PointLightShadow} for details. 46439 * 46440 * ```js 46441 * const light = new THREE.PointLight( 0xff0000, 1, 100 ); 46442 * light.position.set( 50, 50, 50 ); 46443 * scene.add( light ); 46444 * ``` 46445 * 46446 * @augments Light 46447 */ 46448class PointLight extends Light { 46449 46450 /** 46451 * Constructs a new point light. 46452 * 46453 * @param {(number|Color|string)} [color=0xffffff] - The light's color. 46454 * @param {number} [intensity=1] - The light's strength/intensity measured in candela (cd). 46455 * @param {number} [distance=0] - Maximum range of the light. `0` means no limit. 46456 * @param {number} [decay=2] - The amount the light dims along the distance of the light. 46457 */ 46458 constructor( color, intensity, distance = 0, decay = 2 ) { 46459 46460 super( color, intensity ); 46461 46462 /** 46463 * This flag can be used for type testing. 46464 * 46465 * @type {boolean} 46466 * @readonly 46467 * @default true 46468 */ 46469 this.isPointLight = true; 46470 46471 this.type = 'PointLight'; 46472 46473 /** 46474 * When distance is zero, light will attenuate according to inverse-square 46475 * law to infinite distance. When distance is non-zero, light will attenuate 46476 * according to inverse-square law until near the distance cutoff, where it 46477 * will then attenuate quickly and smoothly to 0. Inherently, cutoffs are not 46478 * physically correct. 46479 * 46480 * @type {number} 46481 * @default 0 46482 */ 46483 this.distance = distance; 46484 46485 /** 46486 * The amount the light dims along the distance of the light. In context of 46487 * physically-correct rendering the default value should not be changed. 46488 * 46489 * @type {number} 46490 * @default 2 46491 */ 46492 this.decay = decay; 46493 46494 /** 46495 * This property holds the light's shadow configuration. 46496 * 46497 * @type {PointLightShadow} 46498 */ 46499 this.shadow = new PointLightShadow(); 46500 46501 } 46502 46503 /** 46504 * The light's power. Power is the luminous power of the light measured in lumens (lm). 46505 * Changing the power will also change the light's intensity. 46506 * 46507 * @type {number} 46508 */ 46509 get power() { 46510 46511 // compute the light's luminous power (in lumens) from its intensity (in candela) 46512 // for an isotropic light source, luminous power (lm) = 4 Ï luminous intensity (cd) 46513 return this.intensity * 4 * Math.PI; 46514 46515 } 46516 46517 set power( power ) { 46518 46519 // set the light's intensity (in candela) from the desired luminous power (in lumens) 46520 this.intensity = power / ( 4 * Math.PI ); 46521 46522 } 46523 46524 dispose() { 46525 46526 super.dispose(); 46527 46528 this.shadow.dispose(); 46529 46530 } 46531 46532 copy( source, recursive ) { 46533 46534 super.copy( source, recursive ); 46535 46536 this.distance = source.distance; 46537 this.decay = source.decay; 46538 46539 this.shadow = source.shadow.clone(); 46540 46541 return this; 46542 46543 } 46544 46545 toJSON( meta ) { 46546 46547 const data = super.toJSON( meta ); 46548 46549 data.object.distance = this.distance; 46550 data.object.decay = this.decay; 46551 46552 data.object.shadow = this.shadow.toJSON(); 46553 46554 return data; 46555 46556 } 46557 46558} 46559 46560/** 46561 * Camera that uses [orthographic projection](https://en.wikipedia.org/wiki/Orthographic_projection). 46562 * 46563 * In this projection mode, an object's size in the rendered image stays 46564 * constant regardless of its distance from the camera. This can be useful 46565 * for rendering 2D scenes and UI elements, amongst other things. 46566 * 46567 * ```js 46568 * const camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 1, 1000 ); 46569 * scene.add( camera ); 46570 * ``` 46571 * 46572 * @augments Camera 46573 */ 46574class OrthographicCamera extends Camera { 46575 46576 /** 46577 * Constructs a new orthographic camera. 46578 * 46579 * @param {number} [left=-1] - The left plane of the camera's frustum. 46580 * @param {number} [right=1] - The right plane of the camera's frustum. 46581 * @param {number} [top=1] - The top plane of the camera's frustum. 46582 * @param {number} [bottom=-1] - The bottom plane of the camera's frustum. 46583 * @param {number} [near=0.1] - The camera's near plane. 46584 * @param {number} [far=2000] - The camera's far plane. 46585 */ 46586 constructor( left = -1, right = 1, top = 1, bottom = -1, near = 0.1, far = 2000 ) { 46587 46588 super(); 46589 46590 /** 46591 * This flag can be used for type testing. 46592 * 46593 * @type {boolean} 46594 * @readonly 46595 * @default true 46596 */ 46597 this.isOrthographicCamera = true; 46598 46599 this.type = 'OrthographicCamera'; 46600 46601 /** 46602 * The zoom factor of the camera. 46603 * 46604 * @type {number} 46605 * @default 1 46606 */ 46607 this.zoom = 1; 46608 46609 /** 46610 * Represents the frustum window specification. This property should not be edited 46611 * directly but via {@link PerspectiveCamera#setViewOffset} and {@link PerspectiveCamera#clearViewOffset}. 46612 * 46613 * @type {?Object} 46614 * @default null 46615 */ 46616 this.view = null; 46617 46618 /** 46619 * The left plane of the camera's frustum. 46620 * 46621 * @type {number} 46622 * @default -1 46623 */ 46624 this.left = left; 46625 46626 /** 46627 * The right plane of the camera's frustum. 46628 * 46629 * @type {number} 46630 * @default 1 46631 */ 46632 this.right = right; 46633 46634 /** 46635 * The top plane of the camera's frustum. 46636 * 46637 * @type {number} 46638 * @default 1 46639 */ 46640 this.top = top; 46641 46642 /** 46643 * The bottom plane of the camera's frustum. 46644 * 46645 * @type {number} 46646 * @default -1 46647 */ 46648 this.bottom = bottom; 46649 46650 /** 46651 * The camera's near plane. The valid range is greater than `0` 46652 * and less than the current value of {@link OrthographicCamera#far}. 46653 * 46654 * Note that, unlike for the {@link PerspectiveCamera}, `0` is a 46655 * valid value for an orthographic camera's near plane. 46656 * 46657 * @type {number} 46658 * @default 0.1 46659 */ 46660 this.near = near; 46661 46662 /** 46663 * The camera's far plane. Must be greater than the 46664 * current value of {@link OrthographicCamera#near}. 46665 * 46666 * @type {number} 46667 * @default 2000 46668 */ 46669 this.far = far; 46670 46671 this.updateProjectionMatrix(); 46672 46673 } 46674 46675 copy( source, recursive ) { 46676 46677 super.copy( source, recursive ); 46678 46679 this.left = source.left; 46680 this.right = source.right; 46681 this.top = source.top; 46682 this.bottom = source.bottom; 46683 this.near = source.near; 46684 this.far = source.far; 46685 46686 this.zoom = source.zoom; 46687 this.view = source.view === null ? null : Object.assign( {}, source.view ); 46688 46689 return this; 46690 46691 } 46692 46693 /** 46694 * Sets an offset in a larger frustum. This is useful for multi-window or 46695 * multi-monitor/multi-machine setups. 46696 * 46697 * @param {number} fullWidth - The full width of multiview setup. 46698 * @param {number} fullHeight - The full height of multiview setup. 46699 * @param {number} x - The horizontal offset of the subcamera. 46700 * @param {number} y - The vertical offset of the subcamera. 46701 * @param {number} width - The width of subcamera. 46702 * @param {number} height - The height of subcamera. 46703 * @see {@link PerspectiveCamera#setViewOffset} 46704 */ 46705 setViewOffset( fullWidth, fullHeight, x, y, width, height ) { 46706 46707 if ( this.view === null ) { 46708 46709 this.view = { 46710 enabled: true, 46711 fullWidth: 1, 46712 fullHeight: 1, 46713 offsetX: 0, 46714 offsetY: 0, 46715 width: 1, 46716 height: 1 46717 }; 46718 46719 } 46720 46721 this.view.enabled = true; 46722 this.view.fullWidth = fullWidth; 46723 this.view.fullHeight = fullHeight; 46724 this.view.offsetX = x; 46725 this.view.offsetY = y; 46726 this.view.width = width; 46727 this.view.height = height; 46728 46729 this.updateProjectionMatrix(); 46730 46731 } 46732 46733 /** 46734 * Removes the view offset from the projection matrix. 46735 */ 46736 clearViewOffset() { 46737 46738 if ( this.view !== null ) { 46739 46740 this.view.enabled = false; 46741 46742 } 46743 46744 this.updateProjectionMatrix(); 46745 46746 } 46747 46748 /** 46749 * Updates the camera's projection matrix. Must be called after any change of 46750 * camera properties. 46751 */ 46752 updateProjectionMatrix() { 46753 46754 const dx = ( this.right - this.left ) / ( 2 * this.zoom ); 46755 const dy = ( this.top - this.bottom ) / ( 2 * this.zoom ); 46756 const cx = ( this.right + this.left ) / 2; 46757 const cy = ( this.top + this.bottom ) / 2; 46758 46759 let left = cx - dx; 46760 let right = cx + dx; 46761 let top = cy + dy; 46762 let bottom = cy - dy; 46763 46764 if ( this.view !== null && this.view.enabled ) { 46765 46766 const scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom; 46767 const scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom; 46768 46769 left += scaleW * this.view.offsetX; 46770 right = left + scaleW * this.view.width; 46771 top -= scaleH * this.view.offsetY; 46772 bottom = top - scaleH * this.view.height; 46773 46774 } 46775 46776 this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far, this.coordinateSystem, this.reversedDepth ); 46777 46778 this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); 46779 46780 } 46781 46782 toJSON( meta ) { 46783 46784 const data = super.toJSON( meta ); 46785 46786 data.object.zoom = this.zoom; 46787 data.object.left = this.left; 46788 data.object.right = this.right; 46789 data.object.top = this.top; 46790 data.object.bottom = this.bottom; 46791 data.object.near = this.near; 46792 data.object.far = this.far; 46793 46794 if ( this.view !== null ) data.object.view = Object.assign( {}, this.view ); 46795 46796 return data; 46797 46798 } 46799 46800} 46801 46802/** 46803 * Represents the shadow configuration of directional lights. 46804 * 46805 * @augments LightShadow 46806 */ 46807class DirectionalLightShadow extends LightShadow { 46808 46809 /** 46810 * Constructs a new directional light shadow. 46811 */ 46812 constructor() { 46813 46814 super( new OrthographicCamera( -5, 5, 5, -5, 0.5, 500 ) ); 46815 46816 /** 46817 * This flag can be used for type testing. 46818 * 46819 * @type {boolean} 46820 * @readonly 46821 * @default true 46822 */ 46823 this.isDirectionalLightShadow = true; 46824 46825 } 46826 46827} 46828 46829/** 46830 * A light that gets emitted in a specific direction. This light will behave 46831 * as though it is infinitely far away and the rays produced from it are all 46832 * parallel. The common use case for this is to simulate daylight; the sun is 46833 * far enough away that its position can be considered to be infinite, and 46834 * all light rays coming from it are parallel. 46835 * 46836 * A common point of confusion for directional lights is that setting the 46837 * rotation has no effect. This is because three.js's DirectionalLight is the 46838 * equivalent to what is often called a 'Target Direct Light' in other 46839 * applications. 46840 * 46841 * This means that its direction is calculated as pointing from the light's 46842 * {@link Object3D#position} to the {@link DirectionalLight#target} position 46843 * (as opposed to a 'Free Direct Light' that just has a rotation 46844 * component). 46845 * 46846 * This light can cast shadows - see the {@link DirectionalLightShadow} for details. 46847 * 46848 * ```js 46849 * // White directional light at half intensity shining from the top. 46850 * const directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 ); 46851 * scene.add( directionalLight ); 46852 * ``` 46853 * 46854 * @augments Light 46855 */ 46856class DirectionalLight extends Light { 46857 46858 /** 46859 * Constructs a new directional light. 46860 * 46861 * @param {(number|Color|string)} [color=0xffffff] - The light's color. 46862 * @param {number} [intensity=1] - The light's strength/intensity. 46863 */ 46864 constructor( color, intensity ) { 46865 46866 super( color, intensity ); 46867 46868 /** 46869 * This flag can be used for type testing. 46870 * 46871 * @type {boolean} 46872 * @readonly 46873 * @default true 46874 */ 46875 this.isDirectionalLight = true; 46876 46877 this.type = 'DirectionalLight'; 46878 46879 this.position.copy( Object3D.DEFAULT_UP ); 46880 this.updateMatrix(); 46881 46882 /** 46883 * The directional light points from its position to the 46884 * target's position. 46885 * 46886 * For the target's position to be changed to anything other 46887 * than the default, it must be added to the scene. 46888 * 46889 * It is also possible to set the target to be another 3D object 46890 * in the scene. The light will now track the target object. 46891 * 46892 * @type {Object3D} 46893 */ 46894 this.target = new Object3D(); 46895 46896 /** 46897 * This property holds the light's shadow configuration. 46898 * 46899 * @type {DirectionalLightShadow} 46900 */ 46901 this.shadow = new DirectionalLightShadow(); 46902 46903 } 46904 46905 dispose() { 46906 46907 super.dispose(); 46908 46909 this.shadow.dispose(); 46910 46911 } 46912 46913 copy( source ) { 46914 46915 super.copy( source ); 46916 46917 this.target = source.target.clone(); 46918 this.shadow = source.shadow.clone(); 46919 46920 return this; 46921 46922 } 46923 46924 toJSON( meta ) { 46925 46926 const data = super.toJSON( meta ); 46927 46928 data.object.shadow = this.shadow.toJSON(); 46929 data.object.target = this.target.uuid; 46930 46931 return data; 46932 46933 } 46934 46935} 46936 46937/** 46938 * This light globally illuminates all objects in the scene equally. 46939 * 46940 * It cannot be used to cast shadows as it does not have a direction. 46941 * 46942 * ```js 46943 * const light = new THREE.AmbientLight( 0x404040 ); // soft white light 46944 * scene.add( light ); 46945 * ``` 46946 * 46947 * @augments Light 46948 */ 46949class AmbientLight extends Light { 46950 46951 /** 46952 * Constructs a new ambient light. 46953 * 46954 * @param {(number|Color|string)} [color=0xffffff] - The light's color. 46955 * @param {number} [intensity=1] - The light's strength/intensity. 46956 */ 46957 constructor( color, intensity ) { 46958 46959 super( color, intensity ); 46960 46961 /** 46962 * This flag can be used for type testing. 46963 * 46964 * @type {boolean} 46965 * @readonly 46966 * @default true 46967 */ 46968 this.isAmbientLight = true; 46969 46970 this.type = 'AmbientLight'; 46971 46972 } 46973 46974} 46975 46976/** 46977 * This class emits light uniformly across the face a rectangular plane. 46978 * This light type can be used to simulate light sources such as bright 46979 * windows or strip lighting. 46980 * 46981 * Important Notes: 46982 * 46983 * - There is no shadow support. 46984 * - Only PBR materials are supported. 46985 * - You have to include `RectAreaLightUniformsLib` (`WebGLRenderer`) or `RectAreaLightTexturesLib` (`WebGPURenderer`) 46986 * into your app and init the uniforms/textures. 46987 * 46988 * ```js 46989 * RectAreaLightUniformsLib.init(); // only relevant for WebGLRenderer 46990 * THREE.RectAreaLightNode.setLTC( RectAreaLightTexturesLib.init() ); // only relevant for WebGPURenderer 46991 * 46992 * const intensity = 1; const width = 10; const height = 10; 46993 * const rectLight = new THREE.RectAreaLight( 0xffffff, intensity, width, height ); 46994 * rectLight.position.set( 5, 5, 0 ); 46995 * rectLight.lookAt( 0, 0, 0 ); 46996 * scene.add( rectLight ) 46997 * ``` 46998 * 46999 * @augments Light 47000 */ 47001class RectAreaLight extends Light { 47002 47003 /** 47004 * Constructs a new area light. 47005 * 47006 * @param {(number|Color|string)} [color=0xffffff] - The light's color. 47007 * @param {number} [intensity=1] - The light's strength/intensity. 47008 * @param {number} [width=10] - The width of the light. 47009 * @param {number} [height=10] - The height of the light. 47010 */ 47011 constructor( color, intensity, width = 10, height = 10 ) { 47012 47013 super( color, intensity ); 47014 47015 /** 47016 * This flag can be used for type testing. 47017 * 47018 * @type {boolean} 47019 * @readonly 47020 * @default true 47021 */ 47022 this.isRectAreaLight = true; 47023 47024 this.type = 'RectAreaLight'; 47025 47026 /** 47027 * The width of the light. 47028 * 47029 * @type {number} 47030 * @default 10 47031 */ 47032 this.width = width; 47033 47034 /** 47035 * The height of the light. 47036 * 47037 * @type {number} 47038 * @default 10 47039 */ 47040 this.height = height; 47041 47042 } 47043 47044 /** 47045 * The light's power. Power is the luminous power of the light measured in lumens (lm). 47046 * Changing the power will also change the light's intensity. 47047 * 47048 * @type {number} 47049 */ 47050 get power() { 47051 47052 // compute the light's luminous power (in lumens) from its intensity (in nits) 47053 return this.intensity * this.width * this.height * Math.PI; 47054 47055 } 47056 47057 set power( power ) { 47058 47059 // set the light's intensity (in nits) from the desired luminous power (in lumens) 47060 this.intensity = power / ( this.width * this.height * Math.PI ); 47061 47062 } 47063 47064 copy( source ) { 47065 47066 super.copy( source ); 47067 47068 this.width = source.width; 47069 this.height = source.height; 47070 47071 return this; 47072 47073 } 47074 47075 toJSON( meta ) { 47076 47077 const data = super.toJSON( meta ); 47078 47079 data.object.width = this.width; 47080 data.object.height = this.height; 47081 47082 return data; 47083 47084 } 47085 47086} 47087 47088/** 47089 * Represents a third-order spherical harmonics (SH). Light probes use this class 47090 * to encode lighting information. 47091 * 47092 * - Primary reference: {@link https://graphics.stanford.edu/papers/envmap/envmap.pdf} 47093 * - Secondary reference: {@link https://www.ppsloan.org/publications/StupidSH36.pdf} 47094 */ 47095class SphericalHarmonics3 { 47096 47097 /** 47098 * Constructs a new spherical harmonics. 47099 */ 47100 constructor() { 47101 47102 /** 47103 * This flag can be used for type testing. 47104 * 47105 * @type {boolean} 47106 * @readonly 47107 * @default true 47108 */ 47109 this.isSphericalHarmonics3 = true; 47110 47111 /** 47112 * An array holding the (9) SH coefficients. 47113 * 47114 * @type {Array<Vector3>} 47115 */ 47116 this.coefficients = []; 47117 47118 for ( let i = 0; i < 9; i ++ ) { 47119 47120 this.coefficients.push( new Vector3() ); 47121 47122 } 47123 47124 } 47125 47126 /** 47127 * Sets the given SH coefficients to this instance by copying 47128 * the values. 47129 * 47130 * @param {Array<Vector3>} coefficients - The SH coefficients. 47131 * @return {SphericalHarmonics3} A reference to this spherical harmonics. 47132 */ 47133 set( coefficients ) { 47134 47135 for ( let i = 0; i < 9; i ++ ) { 47136 47137 this.coefficients[ i ].copy( coefficients[ i ] ); 47138 47139 } 47140 47141 return this; 47142 47143 } 47144 47145 /** 47146 * Sets all SH coefficients to `0`. 47147 * 47148 * @return {SphericalHarmonics3} A reference to this spherical harmonics. 47149 */ 47150 zero() { 47151 47152 for ( let i = 0; i < 9; i ++ ) { 47153 47154 this.coefficients[ i ].set( 0, 0, 0 ); 47155 47156 } 47157 47158 return this; 47159 47160 } 47161 47162 /** 47163 * Returns the radiance in the direction of the given normal. 47164 * 47165 * @param {Vector3} normal - The normal vector (assumed to be unit length) 47166 * @param {Vector3} target - The target vector that is used to store the method's result. 47167 * @return {Vector3} The radiance. 47168 */ 47169 getAt( normal, target ) { 47170 47171 // normal is assumed to be unit length 47172 47173 const x = normal.x, y = normal.y, z = normal.z; 47174 47175 const coeff = this.coefficients; 47176 47177 // band 0 47178 target.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 ); 47179 47180 // band 1 47181 target.addScaledVector( coeff[ 1 ], 0.488603 * y ); 47182 target.addScaledVector( coeff[ 2 ], 0.488603 * z ); 47183 target.addScaledVector( coeff[ 3 ], 0.488603 * x ); 47184 47185 // band 2 47186 target.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) ); 47187 target.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) ); 47188 target.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) ); 47189 target.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) ); 47190 target.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) ); 47191 47192 return target; 47193 47194 } 47195 47196 /** 47197 * Returns the irradiance (radiance convolved with cosine lobe) in the 47198 * direction of the given normal. 47199 * 47200 * @param {Vector3} normal - The normal vector (assumed to be unit length) 47201 * @param {Vector3} target - The target vector that is used to store the method's result. 47202 * @return {Vector3} The irradiance. 47203 */ 47204 getIrradianceAt( normal, target ) { 47205 47206 // normal is assumed to be unit length 47207 47208 const x = normal.x, y = normal.y, z = normal.z; 47209 47210 const coeff = this.coefficients; 47211 47212 // band 0 47213 target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // Ï * 0.282095 47214 47215 // band 1 47216 target.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * Ï / 3 ) * 0.488603 47217 target.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z ); 47218 target.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x ); 47219 47220 // band 2 47221 target.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( Ï / 4 ) * 1.092548 47222 target.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z ); 47223 target.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( Ï / 4 ) * 0.315392 * 3 47224 target.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z ); 47225 target.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( Ï / 4 ) * 0.546274 47226 47227 return target; 47228 47229 } 47230 47231 /** 47232 * Adds the given SH to this instance. 47233 * 47234 * @param {SphericalHarmonics3} sh - The SH to add. 47235 * @return {SphericalHarmonics3} A reference to this spherical harmonics. 47236 */ 47237 add( sh ) { 47238 47239 for ( let i = 0; i < 9; i ++ ) { 47240 47241 this.coefficients[ i ].add( sh.coefficients[ i ] ); 47242 47243 } 47244 47245 return this; 47246 47247 } 47248 47249 /** 47250 * A convenience method for performing {@link SphericalHarmonics3#add} and 47251 * {@link SphericalHarmonics3#scale} at once. 47252 * 47253 * @param {SphericalHarmonics3} sh - The SH to add. 47254 * @param {number} s - The scale factor. 47255 * @return {SphericalHarmonics3} A reference to this spherical harmonics. 47256 */ 47257 addScaledSH( sh, s ) { 47258 47259 for ( let i = 0; i < 9; i ++ ) { 47260 47261 this.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s ); 47262 47263 } 47264 47265 return this; 47266 47267 } 47268 47269 /** 47270 * Scales this SH by the given scale factor. 47271 * 47272 * @param {number} s - The scale factor. 47273 * @return {SphericalHarmonics3} A reference to this spherical harmonics. 47274 */ 47275 scale( s ) { 47276 47277 for ( let i = 0; i < 9; i ++ ) { 47278 47279 this.coefficients[ i ].multiplyScalar( s ); 47280 47281 } 47282 47283 return this; 47284 47285 } 47286 47287 /** 47288 * Linear interpolates between the given SH and this instance by the given 47289 * alpha factor. 47290 * 47291 * @param {SphericalHarmonics3} sh - The SH to interpolate with. 47292 * @param {number} alpha - The alpha factor. 47293 * @return {SphericalHarmonics3} A reference to this spherical harmonics. 47294 */ 47295 lerp( sh, alpha ) { 47296 47297 for ( let i = 0; i < 9; i ++ ) { 47298 47299 this.coefficients[ i ].lerp( sh.coefficients[ i ], alpha ); 47300 47301 } 47302 47303 return this; 47304 47305 } 47306 47307 /** 47308 * Returns `true` if this spherical harmonics is equal with the given one. 47309 * 47310 * @param {SphericalHarmonics3} sh - The spherical harmonics to test for equality. 47311 * @return {boolean} Whether this spherical harmonics is equal with the given one. 47312 */ 47313 equals( sh ) { 47314 47315 for ( let i = 0; i < 9; i ++ ) { 47316 47317 if ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) { 47318 47319 return false; 47320 47321 } 47322 47323 } 47324 47325 return true; 47326 47327 } 47328 47329 /** 47330 * Copies the values of the given spherical harmonics to this instance. 47331 * 47332 * @param {SphericalHarmonics3} sh - The spherical harmonics to copy. 47333 * @return {SphericalHarmonics3} A reference to this spherical harmonics. 47334 */ 47335 copy( sh ) { 47336 47337 return this.set( sh.coefficients ); 47338 47339 } 47340 47341 /** 47342 * Returns a new spherical harmonics with copied values from this instance. 47343 * 47344 * @return {SphericalHarmonics3} A clone of this instance. 47345 */ 47346 clone() { 47347 47348 return new this.constructor().copy( this ); 47349 47350 } 47351 47352 /** 47353 * Sets the SH coefficients of this instance from the given array. 47354 * 47355 * @param {Array<number>} array - An array holding the SH coefficients. 47356 * @param {number} [offset=0] - The array offset where to start copying. 47357 * @return {SphericalHarmonics3} A clone of this instance. 47358 */ 47359 fromArray( array, offset = 0 ) { 47360 47361 const coefficients = this.coefficients; 47362 47363 for ( let i = 0; i < 9; i ++ ) { 47364 47365 coefficients[ i ].fromArray( array, offset + ( i * 3 ) ); 47366 47367 } 47368 47369 return this; 47370 47371 } 47372 47373 /** 47374 * Returns an array with the SH coefficients, or copies them into the provided 47375 * array. The coefficients are represented as numbers. 47376 * 47377 * @param {Array<number>} [array=[]] - The target array. 47378 * @param {number} [offset=0] - The array offset where to start copying. 47379 * @return {Array<number>} An array with flat SH coefficients. 47380 */ 47381 toArray( array = [], offset = 0 ) { 47382 47383 const coefficients = this.coefficients; 47384 47385 for ( let i = 0; i < 9; i ++ ) { 47386 47387 coefficients[ i ].toArray( array, offset + ( i * 3 ) ); 47388 47389 } 47390 47391 return array; 47392 47393 } 47394 47395 /** 47396 * Computes the SH basis for the given normal vector. 47397 * 47398 * @param {Vector3} normal - The normal. 47399 * @param {Array<number>} shBasis - The target array holding the SH basis. 47400 */ 47401 static getBasisAt( normal, shBasis ) { 47402 47403 // normal is assumed to be unit length 47404 47405 const x = normal.x, y = normal.y, z = normal.z; 47406 47407 // band 0 47408 shBasis[ 0 ] = 0.282095; 47409 47410 // band 1 47411 shBasis[ 1 ] = 0.488603 * y; 47412 shBasis[ 2 ] = 0.488603 * z; 47413 shBasis[ 3 ] = 0.488603 * x; 47414 47415 // band 2 47416 shBasis[ 4 ] = 1.092548 * x * y; 47417 shBasis[ 5 ] = 1.092548 * y * z; 47418 shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 ); 47419 shBasis[ 7 ] = 1.092548 * x * z; 47420 shBasis[ 8 ] = 0.546274 * ( x * x - y * y ); 47421 47422 } 47423 47424} 47425 47426/** 47427 * Light probes are an alternative way of adding light to a 3D scene. Unlike 47428 * classical light sources (e.g. directional, point or spot lights), light 47429 * probes do not emit light. Instead they store information about light 47430 * passing through 3D space. During rendering, the light that hits a 3D 47431 * object is approximated by using the data from the light probe. 47432 * 47433 * Light probes are usually created from (radiance) environment maps. The 47434 * class {@link LightProbeGenerator} can be used to create light probes from 47435 * cube textures or render targets. However, light estimation data could also 47436 * be provided in other forms e.g. by WebXR. This enables the rendering of 47437 * augmented reality content that reacts to real world lighting. 47438 * 47439 * The current probe implementation in three.js supports so-called diffuse 47440 * light probes. This type of light probe is functionally equivalent to an 47441 * irradiance environment map. 47442 * 47443 * @augments Light 47444 */ 47445class LightProbe extends Light { 47446 47447 /** 47448 * Constructs a new light probe. 47449 * 47450 * @param {SphericalHarmonics3} sh - The spherical harmonics which represents encoded lighting information. 47451 * @param {number} [intensity=1] - The light's strength/intensity. 47452 */ 47453 constructor( sh = new SphericalHarmonics3(), intensity = 1 ) { 47454 47455 super( undefined, intensity ); 47456 47457 /** 47458 * This flag can be used for type testing. 47459 * 47460 * @type {boolean} 47461 * @readonly 47462 * @default true 47463 */ 47464 this.isLightProbe = true; 47465 47466 /** 47467 * A light probe uses spherical harmonics to encode lighting information. 47468 * 47469 * @type {SphericalHarmonics3} 47470 */ 47471 this.sh = sh; 47472 47473 } 47474 47475 copy( source ) { 47476 47477 super.copy( source ); 47478 47479 this.sh.copy( source.sh ); 47480 47481 return this; 47482 47483 } 47484 47485 toJSON( meta ) { 47486 47487 const data = super.toJSON( meta ); 47488 47489 data.object.sh = this.sh.toArray(); 47490 47491 return data; 47492 47493 } 47494 47495} 47496
47497/** 47498 * Class for loading materials. The files are internally 47499 * loaded via {@link FileLoader}. 47500 * 47501 * ```js 47502 * const loader = new THREE.MaterialLoader(); 47503 * const material = await loader.loadAsync( 'material.json' ); 47504 * ``` 47505 * This loader does not support node materials. Use {@link NodeMaterialLoader} instead. 47506 * 47507 * @augments Loader 47508 */ 47509class MaterialLoader extends Loader { 47510 47511 /** 47512 * Constructs a new material loader. 47513 * 47514 * @param {LoadingManager} [manager] - The loading manager. 47515 */ 47516 constructor( manager ) { 47517 47518 super( manager ); 47519 47520 /** 47521 * A dictionary holding textures used by the material. 47522 * 47523 * @type {Object<string,Texture>} 47524 */ 47525 this.textures = {}; 47526 47527 } 47528 47529 /** 47530 * Starts loading from the given URL and pass the loaded material to the `onLoad()` callback. 47531 * 47532 * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI. 47533 * @param {function(Material)} onLoad - Executed when the loading process has been finished. 47534 * @param {onProgressCallback} onProgress - Executed while the loading is in progress. 47535 * @param {onErrorCallback} onError - Executed when errors occur. 47536 */ 47537 load( url, onLoad, onProgress, onError ) { 47538 47539 const scope = this; 47540 47541 const loader = new FileLoader( scope.manager ); 47542 loader.setPath( scope.path ); 47543 loader.setRequestHeader( scope.requestHeader ); 47544 loader.setWithCredentials( scope.withCredentials ); 47545 loader.load( url, function ( text ) { 47546 47547 try { 47548 47549 onLoad( scope.parse( JSON.parse( text ) ) ); 47550 47551 } catch ( e ) { 47552 47553 if ( onError ) { 47554 47555 onError( e ); 47556 47557 } else { 47558 47559 error( e ); 47560 47561 } 47562 47563 scope.manager.itemError( url ); 47564 47565 } 47566 47567 }, onProgress, onError ); 47568 47569 } 47570 47571 /** 47572 * Parses the given JSON object and returns a material. 47573 * 47574 * @param {Object} json - The serialized material. 47575 * @return {Material} The parsed material. 47576 */ 47577 parse( json ) { 47578 47579 const textures = this.textures; 47580 47581 function getTexture( name ) { 47582 47583 if ( textures[ name ] === undefined ) { 47584 47585 warn( 'MaterialLoader: Undefined texture', name ); 47586 47587 } 47588 47589 return textures[ name ]; 47590 47591 } 47592 47593 const material = this.createMaterialFromType( json.type ); 47594 47595 if ( json.uuid !== undefined ) material.uuid = json.uuid; 47596 if ( json.name !== undefined ) material.name = json.name; 47597 if ( json.color !== undefined && material.color !== undefined ) material.color.setHex( json.color ); 47598 if ( json.roughness !== undefined ) material.roughness = json.roughness; 47599 if ( json.metalness !== undefined ) material.metalness = json.metalness; 47600 if ( json.sheen !== undefined ) material.sheen = json.sheen; 47601 if ( json.sheenColor !== undefined ) material.sheenColor = new Color().setHex( json.sheenColor ); 47602 if ( json.sheenRoughness !== undefined ) material.sheenRoughness = json.sheenRoughness; 47603 if ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive ); 47604 if ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular ); 47605 if ( json.specularIntensity !== undefined ) material.specularIntensity = json.specularIntensity; 47606 if ( json.specularColor !== undefined && material.specularColor !== undefined ) material.specularColor.setHex( json.specularColor ); 47607 if ( json.shininess !== undefined ) material.shininess = json.shininess; 47608 if ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat; 47609 if ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness; 47610 if ( json.dispersion !== undefined ) material.dispersion = json.dispersion; 47611 if ( json.iridescence !== undefined ) material.iridescence = json.iridescence; 47612 if ( json.iridescenceIOR !== undefined ) material.iridescenceIOR = json.iridescenceIOR; 47613 if ( json.iridescenceThicknessRange !== undefined ) material.iridescenceThicknessRange = json.iridescenceThicknessRange; 47614 if ( json.transmission !== undefined ) material.transmission = json.transmission; 47615 if ( json.thickness !== undefined ) material.thickness = json.thickness; 47616 if ( json.attenuationDistance !== undefined ) material.attenuationDistance = json.attenuationDistance; 47617 if ( json.attenuationColor !== undefined && material.attenuationColor !== undefined ) material.attenuationColor.setHex( json.attenuationColor ); 47618 if ( json.anisotropy !== undefined ) material.anisotropy = json.anisotropy; 47619 if ( json.anisotropyRotation !== undefined ) material.anisotropyRotation = json.anisotropyRotation; 47620 if ( json.fog !== undefined ) material.fog = json.fog; 47621 if ( json.flatShading !== undefined ) material.flatShading = json.flatShading; 47622 if ( json.blending !== undefined ) material.blending = json.blending; 47623 if ( json.combine !== undefined ) material.combine = json.combine; 47624 if ( json.side !== undefined ) material.side = json.side; 47625 if ( json.shadowSide !== undefined ) material.shadowSide = json.shadowSide; 47626 if ( json.opacity !== undefined ) material.opacity = json.opacity; 47627 if ( json.transparent !== undefined ) material.transparent = json.transparent; 47628 if ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest; 47629 if ( json.alphaHash !== undefined ) material.alphaHash = json.alphaHash; 47630 if ( json.depthFunc !== undefined ) material.depthFunc = json.depthFunc; 47631 if ( json.depthTest !== undefined ) material.depthTest = json.depthTest; 47632 if ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite; 47633 if ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite; 47634 if ( json.blendSrc !== undefined ) material.blendSrc = json.blendSrc; 47635 if ( json.blendDst !== undefined ) material.blendDst = json.blendDst; 47636 if ( json.blendEquation !== undefined ) material.blendEquation = json.blendEquation; 47637 if ( json.blendSrcAlpha !== undefined ) material.blendSrcAlpha = json.blendSrcAlpha; 47638 if ( json.blendDstAlpha !== undefined ) material.blendDstAlpha = json.blendDstAlpha; 47639 if ( json.blendEquationAlpha !== undefined ) material.blendEquationAlpha = json.blendEquationAlpha; 47640 if ( json.blendColor !== undefined && material.blendColor !== undefined ) material.blendColor.setHex( json.blendColor ); 47641 if ( json.blendAlpha !== undefined ) material.blendAlpha = json.blendAlpha; 47642 if ( json.stencilWriteMask !== undefined ) material.stencilWriteMask = json.stencilWriteMask; 47643 if ( json.stencilFunc !== undefined ) material.stencilFunc = json.stencilFunc; 47644 if ( json.stencilRef !== undefined ) material.stencilRef = json.stencilRef; 47645 if ( json.stencilFuncMask !== undefined ) material.stencilFuncMask = json.stencilFuncMask;
vendor: 17,999 bytes, lines 47646-48280
47646 if ( json.stencilFail !== undefined ) material.stencilFail = json.stencilFail; 47647 if ( json.stencilZFail !== undefined ) material.stencilZFail = json.stencilZFail; 47648 if ( json.stencilZPass !== undefined ) material.stencilZPass = json.stencilZPass; 47649 if ( json.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite; 47650 47651 if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; 47652 if ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth; 47653 if ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap; 47654 if ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin; 47655 47656 if ( json.rotation !== undefined ) material.rotation = json.rotation; 47657 47658 if ( json.linewidth !== undefined ) material.linewidth = json.linewidth; 47659 if ( json.dashSize !== undefined ) material.dashSize = json.dashSize; 47660 if ( json.gapSize !== undefined ) material.gapSize = json.gapSize; 47661 if ( json.scale !== undefined ) material.scale = json.scale; 47662 47663 if ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset; 47664 if ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor; 47665 if ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits; 47666 47667 if ( json.dithering !== undefined ) material.dithering = json.dithering; 47668 47669 if ( json.alphaToCoverage !== undefined ) material.alphaToCoverage = json.alphaToCoverage; 47670 if ( json.premultipliedAlpha !== undefined ) material.premultipliedAlpha = json.premultipliedAlpha; 47671 if ( json.forceSinglePass !== undefined ) material.forceSinglePass = json.forceSinglePass; 47672 if ( json.allowOverride !== undefined ) material.allowOverride = json.allowOverride; 47673 47674 if ( json.visible !== undefined ) material.visible = json.visible; 47675 47676 if ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped; 47677 47678 if ( json.userData !== undefined ) material.userData = json.userData; 47679 47680 if ( json.vertexColors !== undefined ) { 47681 47682 if ( typeof json.vertexColors === 'number' ) { 47683 47684 material.vertexColors = json.vertexColors > 0; 47685 47686 } else { 47687 47688 material.vertexColors = json.vertexColors; 47689 47690 } 47691 47692 } 47693 47694 // Shader Material 47695 47696 if ( json.uniforms !== undefined ) { 47697 47698 for ( const name in json.uniforms ) { 47699 47700 const uniform = json.uniforms[ name ]; 47701 47702 material.uniforms[ name ] = {}; 47703 47704 switch ( uniform.type ) { 47705 47706 case 't': 47707 material.uniforms[ name ].value = getTexture( uniform.value ); 47708 break; 47709 47710 case 'c': 47711 material.uniforms[ name ].value = new Color().setHex( uniform.value ); 47712 break; 47713 47714 case 'v2': 47715 material.uniforms[ name ].value = new Vector2().fromArray( uniform.value ); 47716 break; 47717 47718 case 'v3': 47719 material.uniforms[ name ].value = new Vector3().fromArray( uniform.value ); 47720 break; 47721 47722 case 'v4': 47723 material.uniforms[ name ].value = new Vector4().fromArray( uniform.value ); 47724 break; 47725 47726 case 'm3': 47727 material.uniforms[ name ].value = new Matrix3().fromArray( uniform.value ); 47728 break; 47729 47730 case 'm4': 47731 material.uniforms[ name ].value = new Matrix4().fromArray( uniform.value ); 47732 break; 47733 47734 default: 47735 material.uniforms[ name ].value = uniform.value; 47736 47737 } 47738 47739 } 47740 47741 } 47742 47743 if ( json.defines !== undefined ) material.defines = json.defines; 47744 if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader; 47745 if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader; 47746 if ( json.glslVersion !== undefined ) material.glslVersion = json.glslVersion; 47747 47748 if ( json.extensions !== undefined ) { 47749 47750 for ( const key in json.extensions ) { 47751 47752 material.extensions[ key ] = json.extensions[ key ]; 47753 47754 } 47755 47756 } 47757 47758 if ( json.lights !== undefined ) material.lights = json.lights; 47759 if ( json.clipping !== undefined ) material.clipping = json.clipping; 47760 47761 // for PointsMaterial 47762 47763 if ( json.size !== undefined ) material.size = json.size; 47764 if ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation; 47765 47766 // maps 47767 47768 if ( json.map !== undefined ) material.map = getTexture( json.map ); 47769 if ( json.matcap !== undefined ) material.matcap = getTexture( json.matcap ); 47770 47771 if ( json.alphaMap !== undefined ) material.alphaMap = getTexture( json.alphaMap ); 47772 47773 if ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap ); 47774 if ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale; 47775 47776 if ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap ); 47777 if ( json.normalMapType !== undefined ) material.normalMapType = json.normalMapType; 47778 if ( json.normalScale !== undefined ) { 47779 47780 let normalScale = json.normalScale; 47781 47782 if ( Array.isArray( normalScale ) === false ) { 47783 47784 // Blender exporter used to export a scalar. See #7459 47785 47786 normalScale = [ normalScale, normalScale ]; 47787 47788 } 47789 47790 material.normalScale = new Vector2().fromArray( normalScale ); 47791 47792 } 47793 47794 if ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap ); 47795 if ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale; 47796 if ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias; 47797 47798 if ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap ); 47799 if ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap ); 47800 47801 if ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap ); 47802 if ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity; 47803 47804 if ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap ); 47805 if ( json.specularIntensityMap !== undefined ) material.specularIntensityMap = getTexture( json.specularIntensityMap ); 47806 if ( json.specularColorMap !== undefined ) material.specularColorMap = getTexture( json.specularColorMap ); 47807 47808 if ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap ); 47809 if ( json.envMapRotation !== undefined ) material.envMapRotation.fromArray( json.envMapRotation ); 47810 if ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity; 47811 47812 if ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity; 47813 if ( json.refractionRatio !== undefined ) material.refractionRatio = json.refractionRatio; 47814 47815 if ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap ); 47816 if ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity; 47817 47818 if ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap ); 47819 if ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity; 47820 47821 if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap ); 47822 47823 if ( json.clearcoatMap !== undefined ) material.clearcoatMap = getTexture( json.clearcoatMap ); 47824 if ( json.clearcoatRoughnessMap !== undefined ) material.clearcoatRoughnessMap = getTexture( json.clearcoatRoughnessMap ); 47825 if ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap ); 47826 if ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2().fromArray( json.clearcoatNormalScale ); 47827 47828 if ( json.iridescenceMap !== undefined ) material.iridescenceMap = getTexture( json.iridescenceMap ); 47829 if ( json.iridescenceThicknessMap !== undefined ) material.iridescenceThicknessMap = getTexture( json.iridescenceThicknessMap ); 47830 47831 if ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap ); 47832 if ( json.thicknessMap !== undefined ) material.thicknessMap = getTexture( json.thicknessMap ); 47833 47834 if ( json.anisotropyMap !== undefined ) material.anisotropyMap = getTexture( json.anisotropyMap ); 47835 47836 if ( json.sheenColorMap !== undefined ) material.sheenColorMap = getTexture( json.sheenColorMap ); 47837 if ( json.sheenRoughnessMap !== undefined ) material.sheenRoughnessMap = getTexture( json.sheenRoughnessMap ); 47838 47839 return material; 47840 47841 } 47842 47843 /** 47844 * Textures are not embedded in the material JSON so they have 47845 * to be injected before the loading process starts. 47846 * 47847 * @param {Object} value - A dictionary holding textures for material properties. 47848 * @return {MaterialLoader} A reference to this material loader. 47849 */ 47850 setTextures( value ) { 47851 47852 this.textures = value; 47853 return this; 47854 47855 } 47856 47857 /** 47858 * Creates a material for the given type. 47859 * 47860 * @param {string} type - The material type. 47861 * @return {Material} The new material. 47862 */ 47863 createMaterialFromType( type ) { 47864 47865 return MaterialLoader.createMaterialFromType( type ); 47866 47867 } 47868 47869 /** 47870 * Creates a material for the given type. 47871 * 47872 * @static 47873 * @param {string} type - The material type. 47874 * @return {Material} The new material. 47875 */ 47876 static createMaterialFromType( type ) { 47877 47878 const materialLib = { 47879 ShadowMaterial, 47880 SpriteMaterial, 47881 RawShaderMaterial, 47882 ShaderMaterial, 47883 PointsMaterial, 47884 MeshPhysicalMaterial, 47885 MeshStandardMaterial, 47886 MeshPhongMaterial, 47887 MeshToonMaterial, 47888 MeshNormalMaterial, 47889 MeshLambertMaterial, 47890 MeshDepthMaterial, 47891 MeshDistanceMaterial, 47892 MeshBasicMaterial, 47893 MeshMatcapMaterial, 47894 LineDashedMaterial, 47895 LineBasicMaterial, 47896 Material 47897 }; 47898 47899 return new materialLib[ type ](); 47900 47901 } 47902 47903} 47904 47905/** 47906 * A class with loader utility functions. 47907 */ 47908class LoaderUtils { 47909 47910 /** 47911 * Extracts the base URL from the given URL. 47912 * 47913 * @param {string} url -The URL to extract the base URL from. 47914 * @return {string} The extracted base URL. 47915 */ 47916 static extractUrlBase( url ) { 47917 47918 const index = url.lastIndexOf( '/' ); 47919 47920 if ( index === -1 ) return './'; 47921 47922 return url.slice( 0, index + 1 ); 47923 47924 } 47925 47926 /** 47927 * Resolves relative URLs against the given path. Absolute paths, data urls, 47928 * and blob URLs will be returned as is. Invalid URLs will return an empty 47929 * string. 47930 * 47931 * @param {string} url -The URL to resolve. 47932 * @param {string} path - The base path for relative URLs to be resolved against. 47933 * @return {string} The resolved URL. 47934 */ 47935 static resolveURL( url, path ) { 47936 47937 // Invalid URL 47938 if ( typeof url !== 'string' || url === '' ) return ''; 47939 47940 // Host Relative URL 47941 if ( /^https?:\/\//i.test( path ) && /^\//.test( url ) ) { 47942 47943 path = path.replace( /(^https?:\/\/[^\/]+).*/i, '$1' ); 47944 47945 } 47946 47947 // Absolute URL http://,https://,// 47948 if ( /^(https?:)?\/\//i.test( url ) ) return url; 47949 47950 // Data URI 47951 if ( /^data:.*,.*$/i.test( url ) ) return url; 47952 47953 // Blob URL 47954 if ( /^blob:.*$/i.test( url ) ) return url; 47955 47956 // Relative URL 47957 return path + url; 47958 47959 } 47960 47961} 47962 47963/** 47964 * An instanced version of a geometry. 47965 */ 47966class InstancedBufferGeometry extends BufferGeometry { 47967 47968 /** 47969 * Constructs a new instanced buffer geometry. 47970 */ 47971 constructor() { 47972 47973 super(); 47974 47975 /** 47976 * This flag can be used for type testing. 47977 * 47978 * @type {boolean} 47979 * @readonly 47980 * @default true 47981 */ 47982 this.isInstancedBufferGeometry = true; 47983 47984 this.type = 'InstancedBufferGeometry'; 47985 47986 /** 47987 * The instance count. 47988 * 47989 * @type {number} 47990 * @default Infinity 47991 */ 47992 this.instanceCount = Infinity; 47993 47994 } 47995 47996 copy( source ) { 47997 47998 super.copy( source ); 47999 48000 this.instanceCount = source.instanceCount; 48001 48002 return this; 48003 48004 } 48005 48006 toJSON() { 48007 48008 const data = super.toJSON(); 48009 48010 data.instanceCount = this.instanceCount; 48011 48012 data.isInstancedBufferGeometry = true; 48013 48014 return data; 48015 48016 } 48017 48018} 48019 48020/** 48021 * Class for loading geometries. The files are internally 48022 * loaded via {@link FileLoader}. 48023 * 48024 * ```js 48025 * const loader = new THREE.BufferGeometryLoader(); 48026 * const geometry = await loader.loadAsync( 'models/json/pressure.json' ); 48027 * 48028 * const material = new THREE.MeshBasicMaterial( { color: 0xF5F5F5 } ); 48029 * const object = new THREE.Mesh( geometry, material ); 48030 * scene.add( object ); 48031 * ``` 48032 * 48033 * @augments Loader 48034 */ 48035class BufferGeometryLoader extends Loader { 48036 48037 /** 48038 * Constructs a new geometry loader. 48039 * 48040 * @param {LoadingManager} [manager] - The loading manager. 48041 */ 48042 constructor( manager ) { 48043 48044 super( manager ); 48045 48046 } 48047 48048 /** 48049 * Starts loading from the given URL and pass the loaded geometry to the `onLoad()` callback. 48050 * 48051 * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI. 48052 * @param {function(BufferGeometry)} onLoad - Executed when the loading process has been finished. 48053 * @param {onProgressCallback} onProgress - Executed while the loading is in progress. 48054 * @param {onErrorCallback} onError - Executed when errors occur. 48055 */ 48056 load( url, onLoad, onProgress, onError ) { 48057 48058 const scope = this; 48059 48060 const loader = new FileLoader( scope.manager ); 48061 loader.setPath( scope.path ); 48062 loader.setRequestHeader( scope.requestHeader ); 48063 loader.setWithCredentials( scope.withCredentials ); 48064 loader.load( url, function ( text ) { 48065 48066 try { 48067 48068 onLoad( scope.parse( JSON.parse( text ) ) ); 48069 48070 } catch ( e ) { 48071 48072 if ( onError ) { 48073 48074 onError( e ); 48075 48076 } else { 48077 48078 error( e ); 48079 48080 } 48081 48082 scope.manager.itemError( url ); 48083 48084 } 48085 48086 }, onProgress, onError ); 48087 48088 } 48089 48090 /** 48091 * Parses the given JSON object and returns a geometry. 48092 * 48093 * @param {Object} json - The serialized geometry. 48094 * @return {BufferGeometry} The parsed geometry. 48095 */ 48096 parse( json ) { 48097 48098 const interleavedBufferMap = {}; 48099 const arrayBufferMap = {}; 48100 48101 function getInterleavedBuffer( json, uuid ) { 48102 48103 if ( interleavedBufferMap[ uuid ] !== undefined ) return interleavedBufferMap[ uuid ]; 48104 48105 const interleavedBuffers = json.interleavedBuffers; 48106 const interleavedBuffer = interleavedBuffers[ uuid ]; 48107 48108 const buffer = getArrayBuffer( json, interleavedBuffer.buffer ); 48109 48110 const array = getTypedArray( interleavedBuffer.type, buffer ); 48111 const ib = new InterleavedBuffer( array, interleavedBuffer.stride ); 48112 ib.uuid = interleavedBuffer.uuid; 48113 48114 interleavedBufferMap[ uuid ] = ib; 48115 48116 return ib; 48117 48118 } 48119 48120 function getArrayBuffer( json, uuid ) { 48121 48122 if ( arrayBufferMap[ uuid ] !== undefined ) return arrayBufferMap[ uuid ]; 48123 48124 const arrayBuffers = json.arrayBuffers; 48125 const arrayBuffer = arrayBuffers[ uuid ]; 48126 48127 const ab = new Uint32Array( arrayBuffer ).buffer; 48128 48129 arrayBufferMap[ uuid ] = ab; 48130 48131 return ab; 48132 48133 } 48134 48135 const geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry(); 48136 48137 const index = json.data.index; 48138 48139 if ( index !== undefined ) { 48140 48141 const typedArray = getTypedArray( index.type, index.array ); 48142 geometry.setIndex( new BufferAttribute( typedArray, 1 ) ); 48143 48144 } 48145 48146 const attributes = json.data.attributes; 48147 48148 for ( const key in attributes ) { 48149 48150 const attribute = attributes[ key ]; 48151 let bufferAttribute; 48152 48153 if ( attribute.isInterleavedBufferAttribute ) { 48154 48155 const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); 48156 bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); 48157 48158 } else { 48159 48160 const typedArray = getTypedArray( attribute.type, attribute.array ); 48161 const bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute; 48162 bufferAttribute = new bufferAttributeConstr( typedArray, attribute.itemSize, attribute.normalized ); 48163 48164 } 48165 48166 if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; 48167 if ( attribute.usage !== undefined ) bufferAttribute.setUsage( attribute.usage ); 48168 48169 geometry.setAttribute( key, bufferAttribute ); 48170 48171 } 48172 48173 const morphAttributes = json.data.morphAttributes; 48174 48175 if ( morphAttributes ) { 48176 48177 for ( const key in morphAttributes ) { 48178 48179 const attributeArray = morphAttributes[ key ]; 48180 48181 const array = []; 48182 48183 for ( let i = 0, il = attributeArray.length; i < il; i ++ ) { 48184 48185 const attribute = attributeArray[ i ]; 48186 let bufferAttribute; 48187 48188 if ( attribute.isInterleavedBufferAttribute ) { 48189 48190 const interleavedBuffer = getInterleavedBuffer( json.data, attribute.data ); 48191 bufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized ); 48192 48193 } else { 48194 48195 const typedArray = getTypedArray( attribute.type, attribute.array ); 48196 bufferAttribute = new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized ); 48197 48198 } 48199 48200 if ( attribute.name !== undefined ) bufferAttribute.name = attribute.name; 48201 array.push( bufferAttribute ); 48202 48203 } 48204 48205 geometry.morphAttributes[ key ] = array; 48206 48207 } 48208 48209 } 48210 48211 const morphTargetsRelative = json.data.morphTargetsRelative; 48212 48213 if ( morphTargetsRelative ) { 48214 48215 geometry.morphTargetsRelative = true; 48216 48217 } 48218 48219 const groups = json.data.groups || json.data.drawcalls || json.data.offsets; 48220 48221 if ( groups !== undefined ) { 48222 48223 for ( let i = 0, n = groups.length; i !== n; ++ i ) { 48224 48225 const group = groups[ i ]; 48226 48227 geometry.addGroup( group.start, group.count, group.materialIndex ); 48228 48229 } 48230 48231 } 48232 48233 const boundingSphere = json.data.boundingSphere; 48234 48235 if ( boundingSphere !== undefined ) { 48236 48237 geometry.boundingSphere = new Sphere().fromJSON( boundingSphere ); 48238 48239 } 48240 48241 if ( json.name ) geometry.name = json.name; 48242 if ( json.userData ) geometry.userData = json.userData; 48243 48244 return geometry; 48245 48246 } 48247 48248} 48249 48250const _customGeometries = {}; 48251 48252/** 48253 * A loader for loading a JSON resource in the [JSON Object/Scene format](https://github.com/mrdoob/three.js/wiki/JSON-Object-Scene-format-4). 48254 * The files are internally loaded via {@link FileLoader}. 48255 * 48256 * ```js 48257 * const loader = new THREE.ObjectLoader(); 48258 * const obj = await loader.loadAsync( 'models/json/example.json' ); 48259 * scene.add( obj ); 48260 * 48261 * // Alternatively, to parse a previously loaded JSON structure 48262 * const object = await loader.parseAsync( a_json_object ); 48263 * scene.add( object ); 48264 * ``` 48265 * 48266 * @augments Loader 48267 */ 48268class ObjectLoader extends Loader { 48269 48270 /** 48271 * Constructs a new object loader. 48272 * 48273 * @param {LoadingManager} [manager] - The loading manager. 48274 */ 48275 constructor( manager ) { 48276 48277 super( manager ); 48278 48279 } 48280
vendor: 4,038 bytes, lines 48281-48434
48281 /** 48282 * Starts loading from the given URL and pass the loaded 3D object to the `onLoad()` callback. 48283 * 48284 * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI. 48285 * @param {function(Object3D)} onLoad - Executed when the loading process has been finished. 48286 * @param {onProgressCallback} onProgress - Executed while the loading is in progress. 48287 * @param {onErrorCallback} onError - Executed when errors occur. 48288 */ 48289 load( url, onLoad, onProgress, onError ) { 48290 48291 const scope = this; 48292 48293 const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; 48294 this.resourcePath = this.resourcePath || path; 48295 48296 const loader = new FileLoader( this.manager ); 48297 loader.setPath( this.path ); 48298 loader.setRequestHeader( this.requestHeader ); 48299 loader.setWithCredentials( this.withCredentials ); 48300 loader.load( url, function ( text ) { 48301 48302 let json = null; 48303 48304 try { 48305 48306 json = JSON.parse( text ); 48307 48308 } catch ( e ) { 48309 48310 if ( onError !== undefined ) onError( e ); 48311 48312 error( 'ObjectLoader: Can\'t parse ' + url + '.', e.message ); 48313 48314 return; 48315 48316 } 48317 48318 const metadata = json.metadata; 48319 48320 if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { 48321 48322 if ( onError !== undefined ) onError( new Error( 'THREE.ObjectLoader: Can\'t load ' + url ) ); 48323 48324 error( 'ObjectLoader: Can\'t load ' + url ); 48325 return; 48326 48327 } 48328 48329 scope.parse( json, onLoad ); 48330 48331 }, onProgress, onError ); 48332 48333 } 48334 48335 /** 48336 * Async version of {@link ObjectLoader#load}. 48337 * 48338 * @async 48339 * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI. 48340 * @param {onProgressCallback} onProgress - Executed while the loading is in progress. 48341 * @return {Promise<Object3D>} A Promise that resolves with the loaded 3D object. 48342 */ 48343 async loadAsync( url, onProgress ) { 48344 48345 const scope = this; 48346 48347 const path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path; 48348 this.resourcePath = this.resourcePath || path; 48349 48350 const loader = new FileLoader( this.manager ); 48351 loader.setPath( this.path ); 48352 loader.setRequestHeader( this.requestHeader ); 48353 loader.setWithCredentials( this.withCredentials ); 48354 48355 const text = await loader.loadAsync( url, onProgress ); 48356 48357 let json; 48358 48359 try { 48360 48361 json = JSON.parse( text ); 48362 48363 } catch ( e ) { 48364 48365 throw new Error( 'ObjectLoader: Can\'t parse ' + url + '. ' + e.message ); 48366 48367 } 48368 48369 const metadata = json.metadata; 48370 48371 if ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) { 48372 48373 throw new Error( 'THREE.ObjectLoader: Can\'t load ' + url ); 48374 48375 } 48376 48377 return await scope.parseAsync( json ); 48378 48379 } 48380 48381 /** 48382 * Parses the given JSON. This is used internally by {@link ObjectLoader#load} 48383 * but can also be used directly to parse a previously loaded JSON structure. 48384 * 48385 * @param {Object} json - The serialized 3D object. 48386 * @param {onLoad} onLoad - Executed when all resources (e.g. textures) have been fully loaded. 48387 * @return {Object3D} The parsed 3D object. 48388 */ 48389 parse( json, onLoad ) { 48390 48391 const animations = this.parseAnimations( json.animations ); 48392 const shapes = this.parseShapes( json.shapes ); 48393 const geometries = this.parseGeometries( json.geometries, shapes ); 48394 48395 const images = this.parseImages( json.images, function () { 48396 48397 if ( onLoad !== undefined ) onLoad( object ); 48398 48399 } ); 48400 48401 const textures = this.parseTextures( json.textures, images ); 48402 const materials = this.parseMaterials( json.materials, textures ); 48403 48404 const object = this.parseObject( json.object, geometries, materials, textures, animations ); 48405 const skeletons = this.parseSkeletons( json.skeletons, object ); 48406 48407 this.bindSkeletons( object, skeletons ); 48408 this.bindLightTargets( object ); 48409 48410 // 48411 48412 if ( onLoad !== undefined ) { 48413 48414 let hasImages = false; 48415 48416 for ( const uuid in images ) { 48417 48418 if ( images[ uuid ].data instanceof HTMLImageElement ) { 48419 48420 hasImages = true; 48421 break; 48422 48423 } 48424 48425 } 48426 48427 if ( hasImages === false ) onLoad( object ); 48428 48429 } 48430 48431 return object; 48432 48433 } 48434
vendor: 7,474 bytes, lines 48435-48835
48435 /** 48436 * Async version of {@link ObjectLoader#parse}. 48437 * 48438 * @param {Object} json - The serialized 3D object. 48439 * @return {Promise<Object3D>} A Promise that resolves with the parsed 3D object. 48440 */ 48441 async parseAsync( json ) { 48442 48443 const animations = this.parseAnimations( json.animations ); 48444 const shapes = this.parseShapes( json.shapes ); 48445 const geometries = this.parseGeometries( json.geometries, shapes ); 48446 48447 const images = await this.parseImagesAsync( json.images ); 48448 48449 const textures = this.parseTextures( json.textures, images ); 48450 const materials = this.parseMaterials( json.materials, textures ); 48451 48452 const object = this.parseObject( json.object, geometries, materials, textures, animations ); 48453 const skeletons = this.parseSkeletons( json.skeletons, object ); 48454 48455 this.bindSkeletons( object, skeletons ); 48456 this.bindLightTargets( object ); 48457 48458 return object; 48459 48460 } 48461 48462 /** 48463 * Registers the given geometry at the internal 48464 * geometry library. 48465 * 48466 * @static 48467 * @param {string} type - The geometry type. 48468 * @param {BufferGeometry.constructor} geometryClass - The geometry class. 48469 */ 48470 static registerGeometry( type, geometryClass ) { 48471 48472 _customGeometries[ type ] = geometryClass; 48473 48474 } 48475 48476 // internals 48477 48478 parseShapes( json ) { 48479 48480 const shapes = {}; 48481 48482 if ( json !== undefined ) { 48483 48484 for ( let i = 0, l = json.length; i < l; i ++ ) { 48485 48486 const shape = new Shape().fromJSON( json[ i ] ); 48487 48488 shapes[ shape.uuid ] = shape; 48489 48490 } 48491 48492 } 48493 48494 return shapes; 48495 48496 } 48497 48498 parseSkeletons( json, object ) { 48499 48500 const skeletons = {}; 48501 const bones = {}; 48502 48503 // generate bone lookup table 48504 48505 object.traverse( function ( child ) { 48506 48507 if ( child.isBone ) bones[ child.uuid ] = child; 48508 48509 } ); 48510 48511 // create skeletons 48512 48513 if ( json !== undefined ) { 48514 48515 for ( let i = 0, l = json.length; i < l; i ++ ) { 48516 48517 const skeleton = new Skeleton().fromJSON( json[ i ], bones ); 48518 48519 skeletons[ skeleton.uuid ] = skeleton; 48520 48521 } 48522 48523 } 48524 48525 return skeletons; 48526 48527 } 48528 48529 parseGeometries( json, shapes ) { 48530 48531 const geometries = {}; 48532 48533 if ( json !== undefined ) { 48534 48535 const bufferGeometryLoader = new BufferGeometryLoader(); 48536 48537 for ( let i = 0, l = json.length; i < l; i ++ ) { 48538 48539 let geometry; 48540 const data = json[ i ]; 48541 48542 switch ( data.type ) { 48543 48544 case 'BufferGeometry': 48545 case 'InstancedBufferGeometry': 48546 48547 geometry = bufferGeometryLoader.parse( data ); 48548 break; 48549 48550 default: 48551 48552 if ( data.type in Geometries ) { 48553 48554 geometry = Geometries[ data.type ].fromJSON( data, shapes ); 48555 48556 } else if ( data.type in _customGeometries ) { 48557 48558 geometry = _customGeometries[ data.type ].fromJSON( data, shapes ); 48559 48560 } else { 48561 48562 warn( `ObjectLoader: Unknown geometry type "${ data.type }". Use .registerGeometry() before starting the deserialization process.` ); 48563 48564 } 48565 48566 } 48567 48568 geometry.uuid = data.uuid; 48569 48570 if ( data.name !== undefined ) geometry.name = data.name; 48571 if ( data.userData !== undefined ) geometry.userData = data.userData; 48572 48573 geometries[ data.uuid ] = geometry; 48574 48575 } 48576 48577 } 48578 48579 return geometries; 48580 48581 } 48582 48583 parseMaterials( json, textures ) { 48584 48585 const cache = {}; // MultiMaterial 48586 const materials = {}; 48587 48588 if ( json !== undefined ) { 48589 48590 const loader = new MaterialLoader(); 48591 loader.setTextures( textures ); 48592 48593 for ( let i = 0, l = json.length; i < l; i ++ ) { 48594 48595 const data = json[ i ]; 48596 48597 if ( cache[ data.uuid ] === undefined ) { 48598 48599 cache[ data.uuid ] = loader.parse( data ); 48600 48601 } 48602 48603 materials[ data.uuid ] = cache[ data.uuid ]; 48604 48605 } 48606 48607 } 48608 48609 return materials; 48610 48611 } 48612 48613 parseAnimations( json ) { 48614 48615 const animations = {}; 48616 48617 if ( json !== undefined ) { 48618 48619 for ( let i = 0; i < json.length; i ++ ) { 48620 48621 const data = json[ i ]; 48622 48623 const clip = AnimationClip.parse( data ); 48624 48625 animations[ clip.uuid ] = clip; 48626 48627 } 48628 48629 } 48630 48631 return animations; 48632 48633 } 48634 48635 parseImages( json, onLoad ) { 48636 48637 const scope = this; 48638 const images = {}; 48639 48640 let loader; 48641 48642 function loadImage( url ) { 48643 48644 scope.manager.itemStart( url ); 48645 48646 return loader.load( url, function () { 48647 48648 scope.manager.itemEnd( url ); 48649 48650 }, undefined, function () { 48651 48652 scope.manager.itemError( url ); 48653 scope.manager.itemEnd( url ); 48654 48655 } ); 48656 48657 } 48658 48659 function deserializeImage( image ) { 48660 48661 if ( typeof image === 'string' ) { 48662 48663 const url = image; 48664 48665 const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; 48666 48667 return loadImage( path ); 48668 48669 } else { 48670 48671 if ( image.data ) { 48672 48673 return { 48674 data: getTypedArray( image.type, image.data ), 48675 width: image.width, 48676 height: image.height 48677 }; 48678 48679 } else { 48680 48681 return null; 48682 48683 } 48684 48685 } 48686 48687 } 48688 48689 if ( json !== undefined && json.length > 0 ) { 48690 48691 const manager = new LoadingManager( onLoad ); 48692 48693 loader = new ImageLoader( manager ); 48694 loader.setCrossOrigin( this.crossOrigin ); 48695 48696 for ( let i = 0, il = json.length; i < il; i ++ ) { 48697 48698 const image = json[ i ]; 48699 const url = image.url; 48700 48701 if ( Array.isArray( url ) ) { 48702 48703 // load array of images e.g CubeTexture 48704 48705 const imageArray = []; 48706 48707 for ( let j = 0, jl = url.length; j < jl; j ++ ) { 48708 48709 const currentUrl = url[ j ]; 48710 48711 const deserializedImage = deserializeImage( currentUrl ); 48712 48713 if ( deserializedImage !== null ) { 48714 48715 if ( deserializedImage instanceof HTMLImageElement ) { 48716 48717 imageArray.push( deserializedImage ); 48718 48719 } else { 48720 48721 // special case: handle array of data textures for cube textures 48722 48723 imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); 48724 48725 } 48726 48727 } 48728 48729 } 48730 48731 images[ image.uuid ] = new Source( imageArray ); 48732 48733 } else { 48734 48735 // load single image 48736 48737 const deserializedImage = deserializeImage( image.url ); 48738 images[ image.uuid ] = new Source( deserializedImage ); 48739 48740 48741 } 48742 48743 } 48744 48745 } 48746 48747 return images; 48748 48749 } 48750 48751 async parseImagesAsync( json ) { 48752 48753 const scope = this; 48754 const images = {}; 48755 48756 let loader; 48757 48758 async function deserializeImage( image ) { 48759 48760 if ( typeof image === 'string' ) { 48761 48762 const url = image; 48763 48764 const path = /^(\/\/)|([a-z]+:(\/\/)?)/i.test( url ) ? url : scope.resourcePath + url; 48765 48766 return await loader.loadAsync( path ); 48767 48768 } else { 48769 48770 if ( image.data ) { 48771 48772 return { 48773 data: getTypedArray( image.type, image.data ), 48774 width: image.width, 48775 height: image.height 48776 }; 48777 48778 } else { 48779 48780 return null; 48781 48782 } 48783 48784 } 48785 48786 } 48787 48788 if ( json !== undefined && json.length > 0 ) { 48789 48790 loader = new ImageLoader( this.manager ); 48791 loader.setCrossOrigin( this.crossOrigin ); 48792 48793 for ( let i = 0, il = json.length; i < il; i ++ ) { 48794 48795 const image = json[ i ]; 48796 const url = image.url; 48797 48798 if ( Array.isArray( url ) ) { 48799 48800 // load array of images e.g CubeTexture 48801 48802 const imageArray = []; 48803 48804 for ( let j = 0, jl = url.length; j < jl; j ++ ) { 48805 48806 const currentUrl = url[ j ]; 48807 48808 const deserializedImage = await deserializeImage( currentUrl ); 48809 48810 if ( deserializedImage !== null ) { 48811 48812 if ( deserializedImage instanceof HTMLImageElement ) { 48813 48814 imageArray.push( deserializedImage ); 48815 48816 } else { 48817 48818 // special case: handle array of data textures for cube textures 48819 48820 imageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) ); 48821 48822 } 48823 48824 } 48825 48826 } 48827 48828 images[ image.uuid ] = new Source( imageArray ); 48829 48830 } else { 48831 48832 // load single image 48833 48834 const deserializedImage = await deserializeImage( image.url ); 48835 images[ image.uuid ] = new
vendor: 12,909 bytes, lines 48835-49345
48835Source( deserializedImage ); 48836 48837 } 48838 48839 } 48840 48841 } 48842 48843 return images; 48844 48845 } 48846 48847 parseTextures( json, images ) { 48848 48849 function parseConstant( value, type ) { 48850 48851 if ( typeof value === 'number' ) return value; 48852 48853 warn( 'ObjectLoader.parseTexture: Constant should be in numeric form.', value ); 48854 48855 return type[ value ]; 48856 48857 } 48858 48859 const textures = {}; 48860 48861 if ( json !== undefined ) { 48862 48863 for ( let i = 0, l = json.length; i < l; i ++ ) { 48864 48865 const data = json[ i ]; 48866 48867 if ( data.image === undefined ) { 48868 48869 warn( 'ObjectLoader: No "image" specified for', data.uuid ); 48870 48871 } 48872 48873 if ( images[ data.image ] === undefined ) { 48874 48875 warn( 'ObjectLoader: Undefined image', data.image ); 48876 48877 } 48878 48879 const source = images[ data.image ]; 48880 const image = source.data; 48881 48882 let texture; 48883 48884 if ( Array.isArray( image ) ) { 48885 48886 texture = new CubeTexture(); 48887 48888 if ( image.length === 6 ) texture.needsUpdate = true; 48889 48890 } else { 48891 48892 if ( image && image.data ) { 48893 48894 texture = new DataTexture(); 48895 48896 } else { 48897 48898 texture = new Texture(); 48899 48900 } 48901 48902 if ( image ) texture.needsUpdate = true; // textures can have undefined image data 48903 48904 } 48905 48906 texture.source = source; 48907 48908 texture.uuid = data.uuid; 48909 48910 if ( data.name !== undefined ) texture.name = data.name; 48911 48912 if ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING ); 48913 if ( data.channel !== undefined ) texture.channel = data.channel; 48914 48915 if ( data.offset !== undefined ) texture.offset.fromArray( data.offset ); 48916 if ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat ); 48917 if ( data.center !== undefined ) texture.center.fromArray( data.center ); 48918 if ( data.rotation !== undefined ) texture.rotation = data.rotation; 48919 48920 if ( data.wrap !== undefined ) { 48921 48922 texture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING ); 48923 texture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING ); 48924 48925 } 48926 48927 if ( data.format !== undefined ) texture.format = data.format; 48928 if ( data.internalFormat !== undefined ) texture.internalFormat = data.internalFormat; 48929 if ( data.type !== undefined ) texture.type = data.type; 48930 if ( data.colorSpace !== undefined ) texture.colorSpace = data.colorSpace; 48931 48932 if ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER ); 48933 if ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER ); 48934 if ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy; 48935 48936 if ( data.flipY !== undefined ) texture.flipY = data.flipY; 48937 48938 if ( data.generateMipmaps !== undefined ) texture.generateMipmaps = data.generateMipmaps; 48939 if ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha; 48940 if ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment; 48941 if ( data.compareFunction !== undefined ) texture.compareFunction = data.compareFunction; 48942 if ( data.normalized !== undefined ) texture.normalized = data.normalized; 48943 48944 if ( data.userData !== undefined ) texture.userData = data.userData; 48945 48946 textures[ data.uuid ] = texture; 48947 48948 } 48949 48950 } 48951 48952 return textures; 48953 48954 } 48955 48956 parseObject( data, geometries, materials, textures, animations ) { 48957 48958 let object; 48959 48960 function getGeometry( name ) { 48961 48962 if ( geometries[ name ] === undefined ) { 48963 48964 warn( 'ObjectLoader: Undefined geometry', name ); 48965 48966 } 48967 48968 return geometries[ name ]; 48969 48970 } 48971 48972 function getMaterial( name ) { 48973 48974 if ( name === undefined ) return undefined; 48975 48976 if ( Array.isArray( name ) ) { 48977 48978 const array = []; 48979 48980 for ( let i = 0, l = name.length; i < l; i ++ ) { 48981 48982 const uuid = name[ i ]; 48983 48984 if ( materials[ uuid ] === undefined ) { 48985 48986 warn( 'ObjectLoader: Undefined material', uuid ); 48987 48988 } 48989 48990 array.push( materials[ uuid ] ); 48991 48992 } 48993 48994 return array; 48995 48996 } 48997 48998 if ( materials[ name ] === undefined ) { 48999 49000 warn( 'ObjectLoader: Undefined material', name ); 49001 49002 } 49003 49004 return materials[ name ]; 49005 49006 } 49007 49008 function getTexture( uuid ) { 49009 49010 if ( textures[ uuid ] === undefined ) { 49011 49012 warn( 'ObjectLoader: Undefined texture', uuid ); 49013 49014 } 49015 49016 return textures[ uuid ]; 49017 49018 } 49019 49020 let geometry, material; 49021 49022 switch ( data.type ) { 49023 49024 case 'Scene': 49025 49026 object = new Scene(); 49027 49028 if ( data.background !== undefined ) { 49029 49030 if ( Number.isInteger( data.background ) ) { 49031 49032 object.background = new Color( data.background ); 49033 49034 } else { 49035 49036 object.background = getTexture( data.background ); 49037 49038 } 49039 49040 } 49041 49042 if ( data.environment !== undefined ) { 49043 49044 object.environment = getTexture( data.environment ); 49045 49046 } 49047 49048 if ( data.fog !== undefined ) { 49049 49050 if ( data.fog.type === 'Fog' ) { 49051 49052 object.fog = new Fog( data.fog.color, data.fog.near, data.fog.far ); 49053 49054 } else if ( data.fog.type === 'FogExp2' ) { 49055 49056 object.fog = new FogExp2( data.fog.color, data.fog.density ); 49057 49058 } 49059 49060 if ( data.fog.name !== '' ) { 49061 49062 object.fog.name = data.fog.name; 49063 49064 } 49065 49066 } 49067 49068 if ( data.backgroundBlurriness !== undefined ) object.backgroundBlurriness = data.backgroundBlurriness; 49069 if ( data.backgroundIntensity !== undefined ) object.backgroundIntensity = data.backgroundIntensity; 49070 if ( data.backgroundRotation !== undefined ) object.backgroundRotation.fromArray( data.backgroundRotation ); 49071 49072 if ( data.environmentIntensity !== undefined ) object.environmentIntensity = data.environmentIntensity; 49073 if ( data.environmentRotation !== undefined ) object.environmentRotation.fromArray( data.environmentRotation ); 49074 49075 break; 49076 49077 case 'PerspectiveCamera': 49078 49079 object = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); 49080 49081 if ( data.focus !== undefined ) object.focus = data.focus; 49082 if ( data.zoom !== undefined ) object.zoom = data.zoom; 49083 if ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge; 49084 if ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset; 49085 if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); 49086 49087 break; 49088 49089 case 'OrthographicCamera': 49090 49091 object = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); 49092 49093 if ( data.zoom !== undefined ) object.zoom = data.zoom; 49094 if ( data.view !== undefined ) object.view = Object.assign( {}, data.view ); 49095 49096 break; 49097 49098 case 'AmbientLight': 49099 49100 object = new AmbientLight( data.color, data.intensity ); 49101 49102 break; 49103 49104 case 'DirectionalLight': 49105 49106 object = new DirectionalLight( data.color, data.intensity ); 49107 object.target = data.target || ''; 49108 49109 break; 49110 49111 case 'PointLight': 49112 49113 object = new PointLight( data.color, data.intensity, data.distance, data.decay ); 49114 49115 break; 49116 49117 case 'RectAreaLight': 49118 49119 object = new RectAreaLight( data.color, data.intensity, data.width, data.height ); 49120 49121 break; 49122 49123 case 'SpotLight': 49124 49125 object = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay ); 49126 object.target = data.target || ''; 49127 49128 break; 49129 49130 case 'HemisphereLight': 49131 49132 object = new HemisphereLight( data.color, data.groundColor, data.intensity ); 49133 49134 break; 49135 49136 case 'LightProbe': 49137 49138 const sh = new SphericalHarmonics3().fromArray( data.sh ); 49139 object = new LightProbe( sh, data.intensity ); 49140 49141 break; 49142 49143 case 'SkinnedMesh': 49144 49145 geometry = getGeometry( data.geometry ); 49146 material = getMaterial( data.material ); 49147 49148 object = new SkinnedMesh( geometry, material ); 49149 49150 if ( data.bindMode !== undefined ) object.bindMode = data.bindMode; 49151 if ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix ); 49152 if ( data.skeleton !== undefined ) object.skeleton = data.skeleton; 49153 49154 break; 49155 49156 case 'Mesh': 49157 49158 geometry = getGeometry( data.geometry ); 49159 material = getMaterial( data.material ); 49160 49161 object = new Mesh( geometry, material ); 49162 49163 break; 49164 49165 case 'InstancedMesh': 49166 49167 geometry = getGeometry( data.geometry ); 49168 material = getMaterial( data.material ); 49169 const count = data.count; 49170 const instanceMatrix = data.instanceMatrix; 49171 const instanceColor = data.instanceColor; 49172 49173 object = new InstancedMesh( geometry, material, count ); 49174 object.instanceMatrix = new InstancedBufferAttribute( new Float32Array( instanceMatrix.array ), 16 ); 49175 if ( instanceColor !== undefined ) object.instanceColor = new InstancedBufferAttribute( new Float32Array( instanceColor.array ), instanceColor.itemSize ); 49176 49177 break; 49178 49179 case 'BatchedMesh': 49180 49181 geometry = getGeometry( data.geometry ); 49182 material = getMaterial( data.material ); 49183 49184 object = new BatchedMesh( data.maxInstanceCount, data.maxVertexCount, data.maxIndexCount, material ); 49185 object.geometry = geometry; 49186 object.perObjectFrustumCulled = data.perObjectFrustumCulled; 49187 object.sortObjects = data.sortObjects; 49188 49189 object._drawRanges = data.drawRanges; 49190 object._reservedRanges = data.reservedRanges; 49191 49192 object._geometryInfo = data.geometryInfo.map( info => { 49193 49194 let box = null; 49195 let sphere = null; 49196 if ( info.boundingBox !== undefined ) { 49197 49198 box = new Box3().fromJSON( info.boundingBox ); 49199 49200 } 49201 49202 if ( info.boundingSphere !== undefined ) { 49203 49204 sphere = new Sphere().fromJSON( info.boundingSphere ); 49205 49206 } 49207 49208 return { 49209 ...info, 49210 boundingBox: box, 49211 boundingSphere: sphere 49212 }; 49213 49214 } ); 49215 object._instanceInfo = data.instanceInfo; 49216 49217 object._availableInstanceIds = data._availableInstanceIds; 49218 object._availableGeometryIds = data._availableGeometryIds; 49219 49220 object._nextIndexStart = data.nextIndexStart; 49221 object._nextVertexStart = data.nextVertexStart; 49222 object._geometryCount = data.geometryCount; 49223 49224 object._maxInstanceCount = data.maxInstanceCount; 49225 object._maxVertexCount = data.maxVertexCount; 49226 object._maxIndexCount = data.maxIndexCount; 49227 49228 object._geometryInitialized = data.geometryInitialized; 49229 49230 object._matricesTexture = getTexture( data.matricesTexture.uuid ); 49231 49232 object._indirectTexture = getTexture( data.indirectTexture.uuid ); 49233 49234 if ( data.colorsTexture !== undefined ) { 49235 49236 object._colorsTexture = getTexture( data.colorsTexture.uuid ); 49237 49238 } 49239 49240 if ( data.boundingSphere !== undefined ) { 49241 49242 object.boundingSphere = new Sphere().fromJSON( data.boundingSphere ); 49243 49244 } 49245 49246 if ( data.boundingBox !== undefined ) { 49247 49248 object.boundingBox = new Box3().fromJSON( data.boundingBox ); 49249 49250 } 49251 49252 break; 49253 49254 case 'LOD': 49255 49256 object = new LOD(); 49257 49258 break; 49259 49260 case 'Line': 49261 49262 object = new Line( getGeometry( data.geometry ), getMaterial( data.material ) ); 49263 49264 break; 49265 49266 case 'LineLoop': 49267 49268 object = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) ); 49269 49270 break; 49271 49272 case 'LineSegments': 49273 49274 object = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) ); 49275 49276 break; 49277 49278 case 'PointCloud': 49279 case 'Points': 49280 49281 object = new Points( getGeometry( data.geometry ), getMaterial( data.material ) ); 49282 49283 break; 49284 49285 case 'Sprite': 49286 49287 object = new Sprite( getMaterial( data.material ) ); 49288 49289 break; 49290 49291 case 'Group': 49292 49293 object = new Group(); 49294 49295 break; 49296 49297 case 'Bone': 49298 49299 object = new Bone(); 49300 49301 break; 49302 49303 default: 49304 49305 object = new Object3D(); 49306 49307 } 49308 49309 object.uuid = data.uuid; 49310 49311 if ( data.name !== undefined ) object.name = data.name; 49312 49313 if ( data.matrix !== undefined ) { 49314 49315 object.matrix.fromArray( data.matrix ); 49316 49317 if ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate; 49318 if ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale ); 49319 49320 } else { 49321 49322 if ( data.position !== undefined ) object.position.fromArray( data.position ); 49323 if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); 49324 if ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion ); 49325 if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); 49326 49327 } 49328 49329 if ( data.up !== undefined ) object.up.fromArray( data.up ); 49330 49331 if ( data.pivot !== undefined ) object.pivot = new Vector3().fromArray( data.pivot ); 49332 49333 if ( data.morphTargetDictionary !== undefined ) object.morphTargetDictionary = Object.assign( {}, data.morphTargetDictionary ); 49334 if ( data.morphTargetInfluences !== undefined ) object.morphTargetInfluences = data.morphTargetInfluences.slice(); 49335 49336 if ( data.castShadow !== undefined ) object.castShadow = data.castShadow; 49337 if ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow; 49338 49339 if ( data.shadow ) { 49340 49341 if ( data.shadow.intensity !== undefined ) object.shadow.intensity = data.shadow.intensity; 49342 if ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias; 49343 if ( data.shadow.normalBias !== undefined ) object.shadow.normalBias = data.shadow.normalBias; 49344 if ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius; 49345 if ( data.shadow.
vendor: 3,445 bytes, lines 49345-49492
49345mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize ); 49346 if ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera ); 49347 49348 } 49349 49350 if ( data.visible !== undefined ) object.visible = data.visible; 49351 if ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled; 49352 if ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder; 49353 if ( data.static !== undefined ) object.static = data.static; 49354 if ( data.userData !== undefined ) object.userData = data.userData; 49355 if ( data.layers !== undefined ) object.layers.mask = data.layers; 49356 49357 if ( data.children !== undefined ) { 49358 49359 const children = data.children; 49360 49361 for ( let i = 0; i < children.length; i ++ ) { 49362 49363 object.add( this.parseObject( children[ i ], geometries, materials, textures, animations ) ); 49364 49365 } 49366 49367 } 49368 49369 if ( data.animations !== undefined ) { 49370 49371 const objectAnimations = data.animations; 49372 49373 for ( let i = 0; i < objectAnimations.length; i ++ ) { 49374 49375 const uuid = objectAnimations[ i ]; 49376 49377 object.animations.push( animations[ uuid ] ); 49378 49379 } 49380 49381 } 49382 49383 if ( data.type === 'LOD' ) { 49384 49385 if ( data.autoUpdate !== undefined ) object.autoUpdate = data.autoUpdate; 49386 49387 const levels = data.levels; 49388 49389 for ( let l = 0; l < levels.length; l ++ ) { 49390 49391 const level = levels[ l ]; 49392 const child = object.getObjectByProperty( 'uuid', level.object ); 49393 49394 if ( child !== undefined ) { 49395 49396 object.addLevel( child, level.distance, level.hysteresis ); 49397 49398 } 49399 49400 } 49401 49402 } 49403 49404 return object; 49405 49406 } 49407 49408 bindSkeletons( object, skeletons ) { 49409 49410 if ( Object.keys( skeletons ).length === 0 ) return; 49411 49412 object.traverse( function ( child ) { 49413 49414 if ( child.isSkinnedMesh === true && child.skeleton !== undefined ) { 49415 49416 const skeleton = skeletons[ child.skeleton ]; 49417 49418 if ( skeleton === undefined ) { 49419 49420 warn( 'ObjectLoader: No skeleton found with UUID:', child.skeleton ); 49421 49422 } else { 49423 49424 child.bind( skeleton, child.bindMatrix ); 49425 49426 } 49427 49428 } 49429 49430 } ); 49431 49432 } 49433 49434 bindLightTargets( object ) { 49435 49436 object.traverse( function ( child ) { 49437 49438 if ( child.isDirectionalLight || child.isSpotLight ) { 49439 49440 const uuid = child.target; 49441 49442 const target = object.getObjectByProperty( 'uuid', uuid ); 49443 49444 if ( target !== undefined ) { 49445 49446 child.target = target; 49447 49448 } else { 49449 49450 child.target = new Object3D(); 49451 49452 } 49453 49454 } 49455 49456 } ); 49457 49458 } 49459 49460} 49461 49462const TEXTURE_MAPPING = { 49463 UVMapping: UVMapping, 49464 CubeReflectionMapping: CubeReflectionMapping, 49465 CubeRefractionMapping: CubeRefractionMapping, 49466 EquirectangularReflectionMapping: EquirectangularReflectionMapping, 49467 EquirectangularRefractionMapping: EquirectangularRefractionMapping, 49468 CubeUVReflectionMapping: CubeUVReflectionMapping 49469}; 49470 49471const TEXTURE_WRAPPING = { 49472 RepeatWrapping: RepeatWrapping, 49473 ClampToEdgeWrapping: ClampToEdgeWrapping, 49474 MirroredRepeatWrapping: MirroredRepeatWrapping 49475}; 49476 49477const TEXTURE_FILTER = { 49478 NearestFilter: NearestFilter, 49479 NearestMipmapNearestFilter: NearestMipmapNearestFilter, 49480 NearestMipmapLinearFilter: NearestMipmapLinearFilter, 49481 LinearFilter: LinearFilter, 49482 LinearMipmapNearestFilter: LinearMipmapNearestFilter, 49483 LinearMipmapLinearFilter: LinearMipmapLinearFilter 49484}; 49485 49486const _errorMap = new WeakMap(); 49487 49488/** 49489 * A loader for loading images as an [ImageBitmap](https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap). 49490 * An `ImageBitmap` provides an asynchronous and resource efficient pathway to prepare 49491 * textures for rendering. 49492 *
49493 * Note that {@link Texture#flipY} and {@link Texture#premultiplyAlpha} are ignored with image bitmaps. 49494 * These options need to be configured via {@link ImageBitmapLoader#setOptions} prior to loading, 49495 * unlike regular images which can be configured on the Texture to set these options on GPU upload instead. 49496 * 49497 * To match the default behaviour of {@link Texture}, the following options are needed: 49498 * 49499 * ```js 49500 * { imageOrientation: 'flipY', premultiplyAlpha: 'none' } 49501 * ``` 49502 * 49503 * Also note that unlike {@link FileLoader}, this loader will only avoid multiple concurrent requests to the same URL if {@link Cache} is enabled. 49504 * 49505 * ```js 49506 * const loader = new THREE.ImageBitmapLoader(); 49507 * loader.setOptions( { imageOrientation: 'flipY' } ); // set options if needed 49508 * const imageBitmap = await loader.loadAsync( 'image.png' ); 49509 * 49510 * const texture = new THREE.Texture( imageBitmap ); 49511 * texture.needsUpdate = true; 49512 * ``` 49513 * 49514 * @augments Loader 49515 */ 49516class ImageBitmapLoader extends Loader { 49517 49518 /** 49519 * Constructs a new image bitmap loader. 49520 * 49521 * @param {LoadingManager} [manager] - The loading manager. 49522 */ 49523 constructor( manager ) { 49524 49525 super( manager ); 49526 49527 /** 49528 * This flag can be used for type testing. 49529 * 49530 * @type {boolean} 49531 * @readonly 49532 * @default true 49533 */ 49534 this.isImageBitmapLoader = true; 49535 49536 if ( typeof createImageBitmap === 'undefined' ) { 49537 49538 warn( 'ImageBitmapLoader: createImageBitmap() not supported.' ); 49539 49540 } 49541 49542 if ( typeof fetch === 'undefined' ) { 49543 49544 warn( 'ImageBitmapLoader: fetch() not supported.' ); 49545 49546 } 49547 49548 /** 49549 * Represents the loader options. 49550 * 49551 * @type {Object} 49552 * @default {premultiplyAlpha:'none'} 49553 */ 49554 this.options = { premultiplyAlpha: 'none' }; 49555 49556 /** 49557 * Used for aborting requests. 49558 * 49559 * @private 49560 * @type {AbortController} 49561 */ 49562 this._abortController = new AbortController(); 49563 49564 } 49565 49566 /** 49567 * Sets the given loader options. The structure of the object must match the `options` parameter of 49568 * [createImageBitmap](https://developer.mozilla.org/en-US/docs/Web/API/Window/createImageBitmap). 49569 * 49570 * Note: When caching is enabled, the cache key is based on the URL only. Loading the same URL with 49571 * different options will return the cached result of the first request. 49572 * 49573 * @param {Object} options - The loader options to set. 49574 * @return {ImageBitmapLoader} A reference to this image bitmap loader. 49575 */ 49576 setOptions( options ) { 49577 49578 this.options = options; 49579 49580 return this; 49581 49582 } 49583 49584 /** 49585 * Starts loading from the given URL and pass the loaded image bitmap to the `onLoad()` callback. 49586 * 49587 * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI. 49588 * @param {function(ImageBitmap)} onLoad - Executed when the loading process has been finished. 49589 * @param {onProgressCallback} onProgress - Unsupported in this loader. 49590 * @param {onErrorCallback} onError - Executed when errors occur. 49591 */ 49592 load( url, onLoad, onProgress, onError ) { 49593 49594 if ( url === undefined ) url = ''; 49595 49596 if ( this.path !== undefined ) url = this.path + url; 49597 49598 url = this.manager.resolveURL( url ); 49599 49600 const scope = this; 49601 49602 const cached = Cache.get( `image-bitmap:${url}` ); 49603 49604 if ( cached !== undefined ) { 49605 49606 scope.manager.itemStart( url ); 49607 49608 // If cached is a promise, wait for it to resolve 49609 if ( cached.then ) { 49610 49611 cached.then( imageBitmap => { 49612 49613 // check if there is an error for the cached promise 49614 49615 if ( _errorMap.has( cached ) === true ) { 49616 49617 if ( onError ) onError( _errorMap.get( cached ) ); 49618 49619 scope.manager.itemError( url ); 49620 scope.manager.itemEnd( url ); 49621 49622 } else { 49623 49624 if ( onLoad ) onLoad( imageBitmap ); 49625 49626 scope.manager.itemEnd( url ); 49627 49628 } 49629 49630 } ); 49631 49632 return; 49633 49634 } 49635 49636 // If cached is not a promise (i.e., it's already an imageBitmap) 49637 setTimeout( function () { 49638 49639 if ( onLoad ) onLoad( cached ); 49640 49641 scope.manager.itemEnd( url ); 49642 49643 }, 0 ); 49644 49645 return; 49646 49647 } 49648 49649 const fetchOptions = {}; 49650 fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include'; 49651 fetchOptions.headers = this.requestHeader; 49652 fetchOptions.signal = ( typeof AbortSignal.any === 'function' ) ? AbortSignal.any( [ this._abortController.signal, this.manager.abortController.signal ] ) : this._abortController.signal; 49653 49654 const promise = fetch( url, fetchOptions ).then( function ( res ) { 49655 49656 return res.blob(); 49657 49658 } ).then( function ( blob ) { 49659 49660 return createImageBitmap( blob, Object.assign( scope.options, { colorSpaceConversion: 'none' } ) ); 49661 49662 } ).then( function ( imageBitmap ) { 49663 49664 Cache.add( `image-bitmap:${url}`, imageBitmap ); 49665 49666 if ( onLoad ) onLoad( imageBitmap ); 49667 49668 scope.manager.itemEnd( url );
vendor: 7,062 bytes, lines 49668-49978
49668 49669 49670 } ).catch( function ( e ) { 49671 49672 if ( onError ) onError( e ); 49673 49674 _errorMap.set( promise, e ); 49675 49676 Cache.remove( `image-bitmap:${url}` ); 49677 49678 scope.manager.itemError( url ); 49679 scope.manager.itemEnd( url ); 49680 49681 } ); 49682 49683 Cache.add( `image-bitmap:${url}`, promise ); 49684 scope.manager.itemStart( url ); 49685 49686 } 49687 49688 /** 49689 * Aborts ongoing fetch requests. 49690 * 49691 * @return {ImageBitmapLoader} A reference to this instance. 49692 */ 49693 abort() { 49694 49695 this._abortController.abort(); 49696 this._abortController = new AbortController(); 49697 49698 return this; 49699 49700 } 49701 49702} 49703 49704let _context; 49705 49706/** 49707 * Manages the global audio context in the engine. 49708 * 49709 * @hideconstructor 49710 */ 49711class AudioContext { 49712 49713 /** 49714 * Returns the global native audio context. 49715 * 49716 * @return {Window.AudioContext} The native audio context. 49717 */ 49718 static getContext() { 49719 49720 if ( _context === undefined ) { 49721 49722 _context = new ( window.AudioContext || window.webkitAudioContext )(); 49723 49724 } 49725 49726 return _context; 49727 49728 } 49729 49730 /** 49731 * Allows to set the global native audio context from outside. 49732 * 49733 * @param {Window.AudioContext} value - The native context to set. 49734 */ 49735 static setContext( value ) { 49736 49737 _context = value; 49738 49739 } 49740 49741} 49742 49743/** 49744 * Class for loading audio buffers. Audios are internally 49745 * loaded via {@link FileLoader}. 49746 * 49747 * ```js 49748 * const audioListener = new THREE.AudioListener(); 49749 * const ambientSound = new THREE.Audio( audioListener ); 49750 * 49751 * const loader = new THREE.AudioLoader(); 49752 * const audioBuffer = await loader.loadAsync( 'audio/ambient_ocean.ogg' ); 49753 * 49754 * ambientSound.setBuffer( audioBuffer ); 49755 * ambientSound.play(); 49756 * ``` 49757 * 49758 * @augments Loader 49759 */ 49760class AudioLoader extends Loader { 49761 49762 /** 49763 * Constructs a new audio loader. 49764 * 49765 * @param {LoadingManager} [manager] - The loading manager. 49766 */ 49767 constructor( manager ) { 49768 49769 super( manager ); 49770 49771 } 49772 49773 /** 49774 * Starts loading from the given URL and passes the loaded audio buffer 49775 * to the `onLoad()` callback. 49776 * 49777 * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI. 49778 * @param {function(AudioBuffer)} onLoad - Executed when the loading process has been finished. 49779 * @param {onProgressCallback} onProgress - Executed while the loading is in progress. 49780 * @param {onErrorCallback} onError - Executed when errors occur. 49781 */ 49782 load( url, onLoad, onProgress, onError ) { 49783 49784 const scope = this; 49785 49786 const loader = new FileLoader( this.manager ); 49787 loader.setResponseType( 'arraybuffer' ); 49788 loader.setPath( this.path ); 49789 loader.setRequestHeader( this.requestHeader ); 49790 loader.setWithCredentials( this.withCredentials ); 49791 loader.load( url, function ( buffer ) { 49792 49793 try { 49794 49795 // Create a copy of the buffer. The `decodeAudioData` method 49796 // detaches the buffer when complete, preventing reuse. 49797 const bufferCopy = buffer.slice( 0 ); 49798 49799 const context = AudioContext.getContext(); 49800 49801 const decodeUrl = url + '#decode'; 49802 scope.manager.itemStart( decodeUrl ); // prevent loading manager from completing too early, see #33378 49803 49804 context.decodeAudioData( bufferCopy, function ( audioBuffer ) { 49805 49806 onLoad( audioBuffer ); 49807 scope.manager.itemEnd( decodeUrl ); 49808 49809 } ).catch( function ( e ) { 49810 49811 handleError( e ); 49812 scope.manager.itemEnd( decodeUrl ); 49813 49814 } ); 49815 49816 } catch ( e ) { 49817 49818 handleError( e ); 49819 49820 } 49821 49822 }, onProgress, onError ); 49823 49824 function handleError( e ) { 49825 49826 if ( onError ) { 49827 49828 onError( e ); 49829 49830 } else { 49831 49832 error( e ); 49833 49834 } 49835 49836 scope.manager.itemError( url ); 49837 49838 } 49839 49840 } 49841 49842} 49843 49844const _eyeRight = /*@__PURE__*/ new Matrix4(); 49845const _eyeLeft = /*@__PURE__*/ new Matrix4(); 49846const _projectionMatrix = /*@__PURE__*/ new Matrix4(); 49847 49848/** 49849 * A special type of camera that uses two perspective cameras with 49850 * stereoscopic projection. Can be used for rendering stereo effects 49851 * like [3D Anaglyph](https://en.wikipedia.org/wiki/Anaglyph_3D) or 49852 * [Parallax Barrier](https://en.wikipedia.org/wiki/parallax_barrier). 49853 */ 49854class StereoCamera { 49855 49856 /** 49857 * Constructs a new stereo camera. 49858 */ 49859 constructor() { 49860 49861 /** 49862 * The type property is used for detecting the object type 49863 * in context of serialization/deserialization. 49864 * 49865 * @type {string} 49866 * @readonly 49867 */ 49868 this.type = 'StereoCamera'; 49869 49870 /** 49871 * The aspect. 49872 * 49873 * @type {number} 49874 * @default 1 49875 */ 49876 this.aspect = 1; 49877 49878 /** 49879 * The eye separation which represents the distance 49880 * between the left and right camera. 49881 * 49882 * @type {number} 49883 * @default 0.064 49884 */ 49885 this.eyeSep = 0.064; 49886 49887 /** 49888 * The camera representing the left eye. This is added to layer `1` so objects to be 49889 * rendered by the left camera must also be added to this layer. 49890 * 49891 * @type {PerspectiveCamera} 49892 */ 49893 this.cameraL = new PerspectiveCamera(); 49894 this.cameraL.layers.enable( 1 ); 49895 this.cameraL.matrixAutoUpdate = false; 49896 49897 /** 49898 * The camera representing the right eye. This is added to layer `2` so objects to be 49899 * rendered by the right camera must also be added to this layer. 49900 * 49901 * @type {PerspectiveCamera} 49902 */ 49903 this.cameraR = new PerspectiveCamera(); 49904 this.cameraR.layers.enable( 2 ); 49905 this.cameraR.matrixAutoUpdate = false; 49906 49907 this._cache = { 49908 focus: null, 49909 fov: null, 49910 aspect: null, 49911 near: null, 49912 far: null, 49913 zoom: null, 49914 eyeSep: null 49915 }; 49916 49917 } 49918 49919 /** 49920 * Updates the stereo camera based on the given perspective camera. 49921 * 49922 * @param {PerspectiveCamera} camera - The perspective camera. 49923 */ 49924 update( camera ) { 49925 49926 const cache = this._cache; 49927 49928 const needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov || 49929 cache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near || 49930 cache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep; 49931 49932 if ( needsUpdate ) { 49933 49934 cache.focus = camera.focus; 49935 cache.fov = camera.fov; 49936 cache.aspect = camera.aspect * this.aspect; 49937 cache.near = camera.near; 49938 cache.far = camera.far; 49939 cache.zoom = camera.zoom; 49940 cache.eyeSep = this.eyeSep; 49941 49942 // Off-axis stereoscopic effect based on 49943 // http://paulbourke.net/stereographics/stereorender/ 49944 49945 _projectionMatrix.copy( camera.projectionMatrix ); 49946 const eyeSepHalf = cache.eyeSep / 2; 49947 const eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus; 49948 const ymax = ( cache.near * Math.tan( DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom; 49949 let xmin, xmax; 49950 49951 // translate xOffset 49952 49953 _eyeLeft.elements[ 12 ] = - eyeSepHalf; 49954 _eyeRight.elements[ 12 ] = eyeSepHalf; 49955 49956 // for left eye 49957 49958 xmin = - ymax * cache.aspect + eyeSepOnProjection; 49959 xmax = ymax * cache.aspect + eyeSepOnProjection; 49960 49961 _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); 49962 _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); 49963 49964 this.cameraL.projectionMatrix.copy( _projectionMatrix ); 49965 49966 // for right eye 49967 49968 xmin = - ymax * cache.aspect - eyeSepOnProjection; 49969 xmax = ymax * cache.aspect - eyeSepOnProjection; 49970 49971 _projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin ); 49972 _projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin ); 49973 49974 this.cameraR.projectionMatrix.copy( _projectionMatrix ); 49975 49976 } 49977 49978 this.cameraL.matrix
49978World.copy( camera.matrixWorld ).multiply( _eyeLeft ); 49979 this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight )
vendor: 51,290 bytes, lines 49979-52296
49979; 49980 49981 } 49982 49983} 49984 49985const fov = -90; // negative fov is not an error 49986const aspect = 1; 49987 49988/** 49989 * A special type of camera that is positioned in 3D space to render its surroundings into a 49990 * cube render target. The render target can then be used as an environment map for rendering 49991 * realtime reflections in your scene. 49992 * 49993 * ```js 49994 * // Create cube render target 49995 * const cubeRenderTarget = new THREE.WebGLCubeRenderTarget( 256, { generateMipmaps: true, minFilter: THREE.LinearMipmapLinearFilter } ); 49996 * 49997 * // Create cube camera 49998 * const cubeCamera = new THREE.CubeCamera( 1, 100000, cubeRenderTarget ); 49999 * scene.add( cubeCamera ); 50000 * 50001 * // Create car 50002 * const chromeMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff, envMap: cubeRenderTarget.texture } ); 50003 * const car = new THREE.Mesh( carGeometry, chromeMaterial ); 50004 * scene.add( car ); 50005 * 50006 * // Update the render target cube 50007 * car.visible = false; 50008 * cubeCamera.position.copy( car.position ); 50009 * cubeCamera.update( renderer, scene ); 50010 * 50011 * // Render the scene 50012 * car.visible = true; 50013 * renderer.render( scene, camera ); 50014 * ``` 50015 * 50016 * @augments Object3D 50017 */ 50018class CubeCamera extends Object3D { 50019 50020 /** 50021 * Constructs a new cube camera. 50022 * 50023 * @param {number} near - The camera's near plane. 50024 * @param {number} far - The camera's far plane. 50025 * @param {WebGLCubeRenderTarget} renderTarget - The cube render target. 50026 */ 50027 constructor( near, far, renderTarget ) { 50028 50029 super(); 50030 50031 this.type = 'CubeCamera'; 50032 50033 /** 50034 * A reference to the cube render target. 50035 * 50036 * @type {WebGLCubeRenderTarget} 50037 */ 50038 this.renderTarget = renderTarget; 50039 50040 /** 50041 * The current active coordinate system. 50042 * 50043 * @type {?(WebGLCoordinateSystem|WebGPUCoordinateSystem)} 50044 * @default null 50045 */ 50046 this.coordinateSystem = null; 50047 50048 /** 50049 * The current active mipmap level 50050 * 50051 * @type {number} 50052 * @default 0 50053 */ 50054 this.activeMipmapLevel = 0; 50055 50056 const cameraPX = new PerspectiveCamera( fov, aspect, near, far ); 50057 cameraPX.layers = this.layers; 50058 this.add( cameraPX ); 50059 50060 const cameraNX = new PerspectiveCamera( fov, aspect, near, far ); 50061 cameraNX.layers = this.layers; 50062 this.add( cameraNX ); 50063 50064 const cameraPY = new PerspectiveCamera( fov, aspect, near, far ); 50065 cameraPY.layers = this.layers; 50066 this.add( cameraPY ); 50067 50068 const cameraNY = new PerspectiveCamera( fov, aspect, near, far ); 50069 cameraNY.layers = this.layers; 50070 this.add( cameraNY ); 50071 50072 const cameraPZ = new PerspectiveCamera( fov, aspect, near, far ); 50073 cameraPZ.layers = this.layers; 50074 this.add( cameraPZ ); 50075 50076 const cameraNZ = new PerspectiveCamera( fov, aspect, near, far ); 50077 cameraNZ.layers = this.layers; 50078 this.add( cameraNZ ); 50079 50080 } 50081 50082 /** 50083 * Must be called when the coordinate system of the cube camera is changed. 50084 */ 50085 updateCoordinateSystem() { 50086 50087 const coordinateSystem = this.coordinateSystem; 50088 50089 const cameras = this.children.concat(); 50090 50091 const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = cameras; 50092 50093 for ( const camera of cameras ) this.remove( camera ); 50094 50095 if ( coordinateSystem === WebGLCoordinateSystem ) { 50096 50097 cameraPX.up.set( 0, 1, 0 ); 50098 cameraPX.lookAt( 1, 0, 0 ); 50099 50100 cameraNX.up.set( 0, 1, 0 ); 50101 cameraNX.lookAt( -1, 0, 0 ); 50102 50103 cameraPY.up.set( 0, 0, -1 ); 50104 cameraPY.lookAt( 0, 1, 0 ); 50105 50106 cameraNY.up.set( 0, 0, 1 ); 50107 cameraNY.lookAt( 0, -1, 0 ); 50108 50109 cameraPZ.up.set( 0, 1, 0 ); 50110 cameraPZ.lookAt( 0, 0, 1 ); 50111 50112 cameraNZ.up.set( 0, 1, 0 ); 50113 cameraNZ.lookAt( 0, 0, -1 ); 50114 50115 } else if ( coordinateSystem === WebGPUCoordinateSystem ) { 50116 50117 cameraPX.up.set( 0, -1, 0 ); 50118 cameraPX.lookAt( -1, 0, 0 ); 50119 50120 cameraNX.up.set( 0, -1, 0 ); 50121 cameraNX.lookAt( 1, 0, 0 ); 50122 50123 cameraPY.up.set( 0, 0, 1 ); 50124 cameraPY.lookAt( 0, 1, 0 ); 50125 50126 cameraNY.up.set( 0, 0, -1 ); 50127 cameraNY.lookAt( 0, -1, 0 ); 50128 50129 cameraPZ.up.set( 0, -1, 0 ); 50130 cameraPZ.lookAt( 0, 0, 1 ); 50131 50132 cameraNZ.up.set( 0, -1, 0 ); 50133 cameraNZ.lookAt( 0, 0, -1 ); 50134 50135 } else { 50136 50137 throw new Error( 'THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: ' + coordinateSystem ); 50138 50139 } 50140 50141 for ( const camera of cameras ) { 50142 50143 this.add( camera ); 50144 50145 camera.updateMatrixWorld(); 50146 50147 } 50148 50149 } 50150 50151 /** 50152 * Calling this method will render the given scene with the given renderer 50153 * into the cube render target of the camera. 50154 * 50155 * @param {(Renderer|WebGLRenderer)} renderer - The renderer. 50156 * @param {Scene} scene - The scene to render. 50157 */ 50158 update( renderer, scene ) { 50159 50160 if ( this.parent === null ) this.updateMatrixWorld(); 50161 50162 const { renderTarget, activeMipmapLevel } = this; 50163 50164 if ( this.coordinateSystem !== renderer.coordinateSystem ) { 50165 50166 this.coordinateSystem = renderer.coordinateSystem; 50167 50168 this.updateCoordinateSystem(); 50169 50170 } 50171 50172 const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = this.children; 50173 50174 const currentRenderTarget = renderer.getRenderTarget(); 50175 const currentActiveCubeFace = renderer.getActiveCubeFace(); 50176 const currentActiveMipmapLevel = renderer.getActiveMipmapLevel(); 50177 50178 const currentXrEnabled = renderer.xr.enabled; 50179 50180 renderer.xr.enabled = false; 50181 50182 const generateMipmaps = renderTarget.texture.generateMipmaps; 50183 50184 renderTarget.texture.generateMipmaps = false; 50185 50186 // https://github.com/mrdoob/three.js/issues/31413#issuecomment-3095966812 50187 50188 let reversedDepthBuffer = false; 50189 50190 if ( renderer.isWebGLRenderer === true ) { 50191 50192 reversedDepthBuffer = renderer.state.buffers.depth.getReversed(); 50193 50194 } else { 50195 50196 reversedDepthBuffer = renderer.reversedDepthBuffer; 50197 50198 } 50199 50200 renderer.setRenderTarget( renderTarget, 0, activeMipmapLevel ); 50201 if ( reversedDepthBuffer && renderer.autoClear === false ) renderer.clearDepth(); 50202 renderer.render( scene, cameraPX ); 50203 50204 renderer.setRenderTarget( renderTarget, 1, activeMipmapLevel ); 50205 if ( reversedDepthBuffer && renderer.autoClear === false ) renderer.clearDepth(); 50206 renderer.render( scene, cameraNX ); 50207 50208 renderer.setRenderTarget( renderTarget, 2, activeMipmapLevel ); 50209 if ( reversedDepthBuffer && renderer.autoClear === false ) renderer.clearDepth(); 50210 renderer.render( scene, cameraPY ); 50211 50212 renderer.setRenderTarget( renderTarget, 3, activeMipmapLevel ); 50213 if ( reversedDepthBuffer && renderer.autoClear === false ) renderer.clearDepth(); 50214 renderer.render( scene, cameraNY ); 50215 50216 renderer.setRenderTarget( renderTarget, 4, activeMipmapLevel ); 50217 if ( reversedDepthBuffer && renderer.autoClear === false ) renderer.clearDepth(); 50218 renderer.render( scene, cameraPZ ); 50219 50220 // mipmaps are generated during the last call of render() 50221 // at this point, all sides of the cube render target are defined 50222 50223 renderTarget.texture.generateMipmaps = generateMipmaps; 50224 50225 renderer.setRenderTarget( renderTarget, 5, activeMipmapLevel ); 50226 if ( reversedDepthBuffer && renderer.autoClear === false ) renderer.clearDepth(); 50227 renderer.render( scene, cameraNZ ); 50228 50229 renderer.setRenderTarget( currentRenderTarget, currentActiveCubeFace, currentActiveMipmapLevel ); 50230 50231 renderer.xr.enabled = currentXrEnabled; 50232 50233 renderTarget.texture.needsPMREMUpdate = true; 50234 50235 } 50236 50237} 50238 50239/** 50240 * This type of camera can be used in order to efficiently render a scene with a 50241 * predefined set of cameras. This is an important performance aspect for 50242 * rendering VR scenes. 50243 * 50244 * An instance of `ArrayCamera` always has an array of sub cameras. It's mandatory 50245 * to define for each sub camera the `viewport` property which determines the 50246 * part of the viewport that is rendered with this camera. 50247 * 50248 * @augments PerspectiveCamera 50249 */ 50250class ArrayCamera extends PerspectiveCamera { 50251 50252 /** 50253 * Constructs a new array camera. 50254 * 50255 * @param {Array<PerspectiveCamera>} [array=[]] - An array of perspective sub cameras. 50256 */ 50257 constructor( array = [] ) { 50258 50259 super(); 50260 50261 /** 50262 * This flag can be used for type testing. 50263 * 50264 * @type {boolean} 50265 * @readonly 50266 * @default true 50267 */ 50268 this.isArrayCamera = true; 50269 50270 /** 50271 * Whether this camera is used with multiview rendering or not. 50272 * 50273 * @type {boolean} 50274 * @readonly 50275 * @default false 50276 */ 50277 this.isMultiViewCamera = false; 50278 50279 /** 50280 * An array of perspective sub cameras. 50281 * 50282 * @type {Array<PerspectiveCamera>} 50283 */ 50284 this.cameras = array; 50285 50286 } 50287 50288} 50289 50290/** 50291 * This class is an alternative to {@link Clock} with a different API design and behavior. 50292 * The goal is to avoid the conceptual flaws that became apparent in `Clock` over time. 50293 * 50294 * - `Timer` has an `update()` method that updates its internal state. That makes it possible to 50295 * call `getDelta()` and `getElapsed()` multiple times per simulation step without getting different values. 50296 * - The class can make use of the Page Visibility API to avoid large time delta values when the app 50297 * is inactive (e.g. tab switched or browser hidden). 50298 * 50299 * ```js 50300 * const timer = new Timer(); 50301 * timer.connect( document ); // use Page Visibility API 50302 * ``` 50303 */ 50304class Timer { 50305 50306 /** 50307 * Constructs a new timer. 50308 */ 50309 constructor() { 50310 50311 this._previousTime = 0; 50312 this._currentTime = 0; 50313 this._startTime = performance.now(); 50314 50315 this._delta = 0; 50316 this._elapsed = 0; 50317 50318 this._timescale = 1; 50319 50320 this._document = null; 50321 this._pageVisibilityHandler = null; 50322 50323 } 50324 50325 /** 50326 * Connect the timer to the given document.Calling this method is not mandatory to 50327 * use the timer but enables the usage of the Page Visibility API to avoid large time 50328 * delta values. 50329 * 50330 * @param {Document} document - The document. 50331 */ 50332 connect( document ) { 50333 50334 this._document = document; 50335 50336 // use Page Visibility API to avoid large time delta values 50337 50338 if ( document.hidden !== undefined ) { 50339 50340 this._pageVisibilityHandler = handleVisibilityChange.bind( this ); 50341 50342 document.addEventListener( 'visibilitychange', this._pageVisibilityHandler, false ); 50343 50344 } 50345 50346 } 50347 50348 /** 50349 * Disconnects the timer from the DOM and also disables the usage of the Page Visibility API. 50350 */ 50351 disconnect() { 50352 50353 if ( this._pageVisibilityHandler !== null ) { 50354 50355 this._document.removeEventListener( 'visibilitychange', this._pageVisibilityHandler ); 50356 this._pageVisibilityHandler = null; 50357 50358 } 50359 50360 this._document = null; 50361 50362 } 50363 50364 /** 50365 * Returns the time delta in seconds. 50366 * 50367 * @return {number} The time delta in second. 50368 */ 50369 getDelta() { 50370 50371 return this._delta / 1000; 50372 50373 } 50374 50375 /** 50376 * Returns the elapsed time in seconds. 50377 * 50378 * @return {number} The elapsed time in second. 50379 */ 50380 getElapsed() { 50381 50382 return this._elapsed / 1000; 50383 50384 } 50385 50386 /** 50387 * Returns the timescale. 50388 * 50389 * @return {number} The timescale. 50390 */ 50391 getTimescale() { 50392 50393 return this._timescale; 50394 50395 } 50396 50397 /** 50398 * Sets the given timescale which scale the time delta computation 50399 * in `update()`. 50400 * 50401 * @param {number} timescale - The timescale to set. 50402 * @return {Timer} A reference to this timer. 50403 */ 50404 setTimescale( timescale ) { 50405 50406 this._timescale = timescale; 50407 50408 return this; 50409 50410 } 50411 50412 /** 50413 * Resets the time computation for the current simulation step. 50414 * 50415 * @return {Timer} A reference to this timer. 50416 */ 50417 reset() { 50418 50419 this._currentTime = performance.now() - this._startTime; 50420 50421 return this; 50422 50423 } 50424 50425 /** 50426 * Can be used to free all internal resources. Usually called when 50427 * the timer instance isn't required anymore. 50428 */ 50429 dispose() { 50430 50431 this.disconnect(); 50432 50433 } 50434 50435 /** 50436 * Updates the internal state of the timer. This method should be called 50437 * once per simulation step and before you perform queries against the timer 50438 * (e.g. via `getDelta()`). 50439 * 50440 * @param {number} timestamp - The current time in milliseconds. Can be obtained 50441 * from the `requestAnimationFrame` callback argument. If not provided, the current 50442 * time will be determined with `performance.now`. 50443 * @return {Timer} A reference to this timer. 50444 */ 50445 update( timestamp ) { 50446 50447 if ( this._pageVisibilityHandler !== null && this._document.hidden === true ) { 50448 50449 this._delta = 0; 50450 50451 } else { 50452 50453 this._previousTime = this._currentTime; 50454 this._currentTime = ( timestamp !== undefined ? timestamp : performance.now() ) - this._startTime; 50455 50456 this._delta = ( this._currentTime - this._previousTime ) * this._timescale; 50457 this._elapsed += this._delta; // _elapsed is the accumulation of all previous deltas 50458 50459 } 50460 50461 return this; 50462 50463 } 50464 50465} 50466 50467function handleVisibilityChange() { 50468 50469 if ( this._document.hidden === false ) this.reset(); 50470 50471} 50472 50473const _position$1 = /*@__PURE__*/ new Vector3(); 50474const _quaternion$1 = /*@__PURE__*/ new Quaternion(); 50475const _scale$1 = /*@__PURE__*/ new Vector3(); 50476 50477const _forward = /*@__PURE__*/ new Vector3(); 50478const _up = /*@__PURE__*/ new Vector3(); 50479 50480/** 50481 * The class represents a virtual listener of the all positional and non-positional audio effects 50482 * in the scene. A three.js application usually creates a single listener. It is a mandatory 50483 * constructor parameter for audios entities like {@link Audio} and {@link PositionalAudio}. 50484 * 50485 * In most cases, the listener object is a child of the camera. So the 3D transformation of the 50486 * camera represents the 3D transformation of the listener. 50487 * 50488 * @augments Object3D 50489 */ 50490class AudioListener extends Object3D { 50491 50492 /** 50493 * Constructs a new audio listener. 50494 */ 50495 constructor() { 50496 50497 super(); 50498 50499 this.type = 'AudioListener'; 50500 50501 /** 50502 * The native audio context. 50503 * 50504 * @type {AudioContext} 50505 * @readonly 50506 */ 50507 this.context = AudioContext.getContext(); 50508 50509 /** 50510 * The gain node used for volume control. 50511 * 50512 * @type {GainNode} 50513 * @readonly 50514 */ 50515 this.gain = this.context.createGain(); 50516 this.gain.connect( this.context.destination ); 50517 50518 /** 50519 * An optional filter. 50520 * 50521 * Defined via {@link AudioListener#setFilter}. 50522 * 50523 * @type {?AudioNode} 50524 * @default null 50525 * @readonly 50526 */ 50527 this.filter = null; 50528 50529 /** 50530 * Time delta values required for `linearRampToValueAtTime()` usage. 50531 * 50532 * @type {number} 50533 * @default 0 50534 * @readonly 50535 */ 50536 this.timeDelta = 0; 50537 50538 // private 50539 50540 this._timer = new Timer(); 50541 50542 } 50543 50544 /** 50545 * Returns the listener's input node. 50546 * 50547 * This method is used by other audio nodes to connect to this listener. 50548 * 50549 * @return {GainNode} The input node. 50550 */ 50551 getInput() { 50552 50553 return this.gain; 50554 50555 } 50556 50557 /** 50558 * Removes the current filter from this listener. 50559 * 50560 * @return {AudioListener} A reference to this listener. 50561 */ 50562 removeFilter() { 50563 50564 if ( this.filter !== null ) { 50565 50566 this.gain.disconnect( this.filter ); 50567 this.filter.disconnect( this.context.destination ); 50568 this.gain.connect( this.context.destination ); 50569 this.filter = null; 50570 50571 } 50572 50573 return this; 50574 50575 } 50576 50577 /** 50578 * Returns the current set filter. 50579 * 50580 * @return {?AudioNode} The filter. 50581 */ 50582 getFilter() { 50583 50584 return this.filter; 50585 50586 } 50587 50588 /** 50589 * Sets the given filter to this listener. 50590 * 50591 * @param {AudioNode} value - The filter to set. 50592 * @return {AudioListener} A reference to this listener. 50593 */ 50594 setFilter( value ) { 50595 50596 if ( this.filter !== null ) { 50597 50598 this.gain.disconnect( this.filter ); 50599 this.filter.disconnect( this.context.destination ); 50600 50601 } else { 50602 50603 this.gain.disconnect( this.context.destination ); 50604 50605 } 50606 50607 this.filter = value; 50608 this.gain.connect( this.filter ); 50609 this.filter.connect( this.context.destination ); 50610 50611 return this; 50612 50613 } 50614 50615 /** 50616 * Returns the applications master volume. 50617 * 50618 * @return {number} The master volume. 50619 */ 50620 getMasterVolume() { 50621 50622 return this.gain.gain.value; 50623 50624 } 50625 50626 /** 50627 * Sets the applications master volume. This volume setting affects 50628 * all audio nodes in the scene. 50629 * 50630 * @param {number} value - The master volume to set. 50631 * @return {AudioListener} A reference to this listener. 50632 */ 50633 setMasterVolume( value ) { 50634 50635 this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); 50636 50637 return this; 50638 50639 } 50640 50641 updateMatrixWorld( force ) { 50642 50643 super.updateMatrixWorld( force ); 50644 50645 this._timer.update(); 50646 50647 const listener = this.context.listener; 50648 50649 this.timeDelta = this._timer.getDelta(); 50650 50651 this.matrixWorld.decompose( _position$1, _quaternion$1, _scale$1 ); 50652 50653 // the initial forward and up directions must be orthogonal 50654 _forward.set( 0, 0, -1 ).applyQuaternion( _quaternion$1 ); 50655 _up.set( 0, 1, 0 ).applyQuaternion( _quaternion$1 ); 50656 50657 if ( listener.positionX ) { 50658 50659 // code path for Chrome (see #14393) 50660 50661 const endTime = this.context.currentTime + this.timeDelta; 50662 50663 listener.positionX.linearRampToValueAtTime( _position$1.x, endTime ); 50664 listener.positionY.linearRampToValueAtTime( _position$1.y, endTime ); 50665 listener.positionZ.linearRampToValueAtTime( _position$1.z, endTime ); 50666 listener.forwardX.linearRampToValueAtTime( _forward.x, endTime ); 50667 listener.forwardY.linearRampToValueAtTime( _forward.y, endTime ); 50668 listener.forwardZ.linearRampToValueAtTime( _forward.z, endTime ); 50669 listener.upX.linearRampToValueAtTime( _up.x, endTime ); 50670 listener.upY.linearRampToValueAtTime( _up.y, endTime ); 50671 listener.upZ.linearRampToValueAtTime( _up.z, endTime ); 50672 50673 } else { 50674 50675 listener.setPosition( _position$1.x, _position$1.y, _position$1.z ); 50676 listener.setOrientation( _forward.x, _forward.y, _forward.z, _up.x, _up.y, _up.z ); 50677 50678 } 50679 50680 } 50681 50682} 50683 50684/** 50685 * Represents a non-positional ( global ) audio object. 50686 * 50687 * This and related audio modules make use of the [Web Audio API](https://www.w3.org/TR/webaudio-1.1/). 50688 * 50689 * ```js 50690 * // create an AudioListener and add it to the camera 50691 * const listener = new THREE.AudioListener(); 50692 * camera.add( listener ); 50693 * 50694 * // create a global audio source 50695 * const sound = new THREE.Audio( listener ); 50696 * 50697 * // load a sound and set it as the Audio object's buffer 50698 * const audioLoader = new THREE.AudioLoader(); 50699 * audioLoader.load( 'sounds/ambient.ogg', function( buffer ) { 50700 * sound.setBuffer( buffer ); 50701 * sound.setLoop( true ); 50702 * sound.setVolume( 0.5 ); 50703 * sound.play(); 50704 * }); 50705 * ``` 50706 * 50707 * @augments Object3D 50708 */ 50709class Audio extends Object3D { 50710 50711 /** 50712 * Constructs a new audio. 50713 * 50714 * @param {AudioListener} listener - The global audio listener. 50715 */ 50716 constructor( listener ) { 50717 50718 super(); 50719 50720 this.type = 'Audio'; 50721 50722 /** 50723 * The global audio listener. 50724 * 50725 * @type {AudioListener} 50726 * @readonly 50727 */ 50728 this.listener = listener; 50729 50730 /** 50731 * The audio context. 50732 * 50733 * @type {AudioContext} 50734 * @readonly 50735 */ 50736 this.context = listener.context; 50737 50738 /** 50739 * The gain node used for volume control. 50740 * 50741 * @type {GainNode} 50742 * @readonly 50743 */ 50744 this.gain = this.context.createGain(); 50745 this.gain.connect( listener.getInput() ); 50746 50747 /** 50748 * Whether to start playback automatically or not. 50749 * 50750 * @type {boolean} 50751 * @default false 50752 */ 50753 this.autoplay = false; 50754 50755 /** 50756 * A reference to an audio buffer. 50757 * 50758 * Defined via {@link Audio#setBuffer}. 50759 * 50760 * @type {?AudioBuffer} 50761 * @default null 50762 * @readonly 50763 */ 50764 this.buffer = null; 50765 50766 /** 50767 * Modify pitch, measured in cents. +/- 100 is a semitone. 50768 * +/- 1200 is an octave. 50769 * 50770 * Defined via {@link Audio#setDetune}. 50771 * 50772 * @type {number} 50773 * @default 0 50774 * @readonly 50775 */ 50776 this.detune = 0; 50777 50778 /** 50779 * Whether the audio should loop or not. 50780 * 50781 * Defined via {@link Audio#setLoop}. 50782 * 50783 * @type {boolean} 50784 * @default false 50785 * @readonly 50786 */ 50787 this.loop = false; 50788 50789 /** 50790 * Defines where in the audio buffer the replay should 50791 * start, in seconds. 50792 * 50793 * @type {number} 50794 * @default 0 50795 */ 50796 this.loopStart = 0; 50797 50798 /** 50799 * Defines where in the audio buffer the replay should 50800 * stop, in seconds. 50801 * 50802 * @type {number} 50803 * @default 0 50804 */ 50805 this.loopEnd = 0; 50806 50807 /** 50808 * An offset to the time within the audio buffer the playback 50809 * should begin, in seconds. 50810 * 50811 * @type {number} 50812 * @default 0 50813 */ 50814 this.offset = 0; 50815 50816 /** 50817 * Overrides the default duration of the audio. 50818 * 50819 * @type {undefined|number} 50820 * @default undefined 50821 */ 50822 this.duration = undefined; 50823 50824 /** 50825 * The playback speed. 50826 * 50827 * Defined via {@link Audio#setPlaybackRate}. 50828 * 50829 * @type {number} 50830 * @readonly 50831 * @default 1 50832 */ 50833 this.playbackRate = 1; 50834 50835 /** 50836 * Indicates whether the audio is playing or not. 50837 * 50838 * This flag will be automatically set when using {@link Audio#play}, 50839 * {@link Audio#pause}, {@link Audio#stop}. 50840 * 50841 * @type {boolean} 50842 * @readonly 50843 * @default false 50844 */ 50845 this.isPlaying = false; 50846 50847 /** 50848 * Indicates whether the audio playback can be controlled 50849 * with method like {@link Audio#play} or {@link Audio#pause}. 50850 * 50851 * This flag will be automatically set when audio sources are 50852 * defined. 50853 * 50854 * @type {boolean} 50855 * @readonly 50856 * @default true 50857 */ 50858 this.hasPlaybackControl = true; 50859 50860 /** 50861 * Holds a reference to the current audio source. 50862 * 50863 * The property is automatically by one of the `set*()` methods. 50864 * 50865 * @type {?AudioNode} 50866 * @readonly 50867 * @default null 50868 */ 50869 this.source = null; 50870 50871 /** 50872 * Defines the source type. 50873 * 50874 * The property is automatically set by one of the `set*()` methods. 50875 * 50876 * @type {('empty'|'audioNode'|'mediaNode'|'mediaStreamNode'|'buffer')} 50877 * @readonly 50878 * @default 'empty' 50879 */ 50880 this.sourceType = 'empty'; 50881 50882 this._startedAt = 0; 50883 this._progress = 0; 50884 this._connected = false; 50885 50886 /** 50887 * Can be used to apply a variety of low-order filters to create 50888 * more complex sound effects e.g. via `BiquadFilterNode`. 50889 * 50890 * The property is automatically set by {@link Audio#setFilters}. 50891 * 50892 * @type {Array<AudioNode>} 50893 * @readonly 50894 */ 50895 this.filters = []; 50896 50897 } 50898 50899 /** 50900 * Returns the output audio node. 50901 * 50902 * @return {GainNode} The output node. 50903 */ 50904 getOutput() { 50905 50906 return this.gain; 50907 50908 } 50909 50910 /** 50911 * Sets the given audio node as the source of this instance. 50912 * 50913 * {@link Audio#sourceType} is set to `audioNode` and {@link Audio#hasPlaybackControl} to `false`. 50914 * 50915 * @param {AudioNode} audioNode - The audio node like an instance of `OscillatorNode`. 50916 * @return {Audio} A reference to this instance. 50917 */ 50918 setNodeSource( audioNode ) { 50919 50920 this.hasPlaybackControl = false; 50921 this.sourceType = 'audioNode'; 50922 this.source = audioNode; 50923 this.connect(); 50924 50925 return this; 50926 50927 } 50928 50929 /** 50930 * Sets the given media element as the source of this instance. 50931 * 50932 * {@link Audio#sourceType} is set to `mediaNode` and {@link Audio#hasPlaybackControl} to `false`. 50933 * 50934 * @param {HTMLMediaElement} mediaElement - The media element. 50935 * @return {Audio} A reference to this instance. 50936 */ 50937 setMediaElementSource( mediaElement ) { 50938 50939 this.hasPlaybackControl = false; 50940 this.sourceType = 'mediaNode'; 50941 this.source = this.context.createMediaElementSource( mediaElement ); 50942 this.connect(); 50943 50944 return this; 50945 50946 } 50947 50948 /** 50949 * Sets the given media stream as the source of this instance. 50950 * 50951 * {@link Audio#sourceType} is set to `mediaStreamNode` and {@link Audio#hasPlaybackControl} to `false`. 50952 * 50953 * @param {MediaStream} mediaStream - The media stream. 50954 * @return {Audio} A reference to this instance. 50955 */ 50956 setMediaStreamSource( mediaStream ) { 50957 50958 this.hasPlaybackControl = false; 50959 this.sourceType = 'mediaStreamNode'; 50960 this.source = this.context.createMediaStreamSource( mediaStream ); 50961 this.connect(); 50962 50963 return this; 50964 50965 } 50966 50967 /** 50968 * Sets the given audio buffer as the source of this instance. 50969 * 50970 * {@link Audio#sourceType} is set to `buffer` and {@link Audio#hasPlaybackControl} to `true`. 50971 * 50972 * @param {AudioBuffer} audioBuffer - The audio buffer. 50973 * @return {Audio} A reference to this instance. 50974 */ 50975 setBuffer( audioBuffer ) { 50976 50977 this.buffer = audioBuffer; 50978 this.sourceType = 'buffer'; 50979 50980 if ( this.autoplay ) this.play(); 50981 50982 return this; 50983 50984 } 50985 50986 /** 50987 * Starts the playback of the audio. 50988 * 50989 * Can only be used with compatible audio sources that allow playback control. 50990 * 50991 * @param {number} [delay=0] - The delay, in seconds, at which the audio should start playing. 50992 * @return {Audio|undefined} A reference to this instance. 50993 */ 50994 play( delay = 0 ) { 50995 50996 if ( this.isPlaying === true ) { 50997 50998 warn( 'Audio: Audio is already playing.' ); 50999 return; 51000 51001 } 51002 51003 if ( this.hasPlaybackControl === false ) { 51004 51005 warn( 'Audio: this Audio has no playback control.' ); 51006 return; 51007 51008 } 51009 51010 this._startedAt = this.context.currentTime + delay; 51011 51012 const source = this.context.createBufferSource(); 51013 source.buffer = this.buffer; 51014 source.loop = this.loop; 51015 source.loopStart = this.loopStart; 51016 source.loopEnd = this.loopEnd; 51017 source.onended = this.onEnded.bind( this ); 51018 source.start( this._startedAt, this._progress + this.offset, this.duration ); 51019 51020 this.isPlaying = true; 51021 51022 this.source = source; 51023 51024 this.setDetune( this.detune ); 51025 this.setPlaybackRate( this.playbackRate ); 51026 51027 return this.connect(); 51028 51029 } 51030 51031 /** 51032 * Pauses the playback of the audio. 51033 * 51034 * Can only be used with compatible audio sources that allow playback control. 51035 * 51036 * @return {Audio|undefined} A reference to this instance. 51037 */ 51038 pause() { 51039 51040 if ( this.hasPlaybackControl === false ) { 51041 51042 warn( 'Audio: this Audio has no playback control.' ); 51043 return; 51044 51045 } 51046 51047 if ( this.isPlaying === true ) { 51048 51049 // update current progress 51050 51051 this._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate; 51052 51053 if ( this.loop === true ) { 51054 51055 // ensure _progress does not exceed duration with looped audios 51056 51057 this._progress = this._progress % ( this.duration || this.buffer.duration ); 51058 51059 } 51060 51061 this.source.stop(); 51062 this.source.onended = null; 51063 51064 this.isPlaying = false; 51065 51066 } 51067 51068 return this; 51069 51070 } 51071 51072 /** 51073 * Stops the playback of the audio. 51074 * 51075 * Can only be used with compatible audio sources that allow playback control. 51076 * 51077 * @param {number} [delay=0] - The delay, in seconds, at which the audio should stop playing. 51078 * @return {Audio|undefined} A reference to this instance. 51079 */ 51080 stop( delay = 0 ) { 51081 51082 if ( this.hasPlaybackControl === false ) { 51083 51084 warn( 'Audio: this Audio has no playback control.' ); 51085 return; 51086 51087 } 51088 51089 this._progress = 0; 51090 51091 if ( this.source !== null ) { 51092 51093 this.source.stop( this.context.currentTime + delay ); 51094 this.source.onended = null; 51095 51096 } 51097 51098 this.isPlaying = false; 51099 51100 return this; 51101 51102 } 51103 51104 /** 51105 * Connects to the audio source. This is used internally on 51106 * initialisation and when setting / removing filters. 51107 * 51108 * @return {Audio} A reference to this instance. 51109 */ 51110 connect() { 51111 51112 if ( this.filters.length > 0 ) { 51113 51114 this.source.connect( this.filters[ 0 ] ); 51115 51116 for ( let i = 1, l = this.filters.length; i < l; i ++ ) { 51117 51118 this.filters[ i - 1 ].connect( this.filters[ i ] ); 51119 51120 } 51121 51122 this.filters[ this.filters.length - 1 ].connect( this.getOutput() ); 51123 51124 } else { 51125 51126 this.source.connect( this.getOutput() ); 51127 51128 } 51129 51130 this._connected = true; 51131 51132 return this; 51133 51134 } 51135 51136 /** 51137 * Disconnects to the audio source. This is used internally on 51138 * initialisation and when setting / removing filters. 51139 * 51140 * @return {Audio|undefined} A reference to this instance. 51141 */ 51142 disconnect() { 51143 51144 if ( this._connected === false ) { 51145 51146 return; 51147 51148 } 51149 51150 if ( this.filters.length > 0 ) { 51151 51152 this.source.disconnect( this.filters[ 0 ] ); 51153 51154 for ( let i = 1, l = this.filters.length; i < l; i ++ ) { 51155 51156 this.filters[ i - 1 ].disconnect( this.filters[ i ] ); 51157 51158 } 51159 51160 this.filters[ this.filters.length - 1 ].disconnect( this.getOutput() ); 51161 51162 } else { 51163 51164 this.source.disconnect( this.getOutput() ); 51165 51166 } 51167 51168 this._connected = false; 51169 51170 return this; 51171 51172 } 51173 51174 /** 51175 * Returns the current set filters. 51176 * 51177 * @return {Array<AudioNode>} The list of filters. 51178 */ 51179 getFilters() { 51180 51181 return this.filters; 51182 51183 } 51184 51185 /** 51186 * Sets an array of filters and connects them with the audio source. 51187 * 51188 * @param {Array<AudioNode>} [value] - A list of filters. 51189 * @return {Audio} A reference to this instance. 51190 */ 51191 setFilters( value ) { 51192 51193 if ( ! value ) value = []; 51194 51195 if ( this._connected === true ) { 51196 51197 this.disconnect(); 51198 this.filters = value.slice(); 51199 this.connect(); 51200 51201 } else { 51202 51203 this.filters = value.slice(); 51204 51205 } 51206 51207 return this; 51208 51209 } 51210 51211 /** 51212 * Defines the detuning of oscillation in cents. 51213 * 51214 * @param {number} value - The detuning of oscillation in cents. 51215 * @return {Audio} A reference to this instance. 51216 */ 51217 setDetune( value ) { 51218 51219 this.detune = value; 51220 51221 if ( this.isPlaying === true && this.source.detune !== undefined ) { 51222 51223 this.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 ); 51224 51225 } 51226 51227 return this; 51228 51229 } 51230 51231 /** 51232 * Returns the detuning of oscillation in cents. 51233 * 51234 * @return {number} The detuning of oscillation in cents. 51235 */ 51236 getDetune() { 51237 51238 return this.detune; 51239 51240 } 51241 51242 /** 51243 * Returns the first filter in the list of filters. 51244 * 51245 * @return {AudioNode|undefined} The first filter in the list of filters. 51246 */ 51247 getFilter() { 51248 51249 return this.getFilters()[ 0 ]; 51250 51251 } 51252 51253 /** 51254 * Applies a single filter node to the audio. 51255 * 51256 * @param {AudioNode} [filter] - The filter to set. 51257 * @return {Audio} A reference to this instance. 51258 */ 51259 setFilter( filter ) { 51260 51261 return this.setFilters( filter ? [ filter ] : [] ); 51262 51263 } 51264 51265 /** 51266 * Sets the playback rate. 51267 * 51268 * Can only be used with compatible audio sources that allow playback control. 51269 * 51270 * @param {number} [value] - The playback rate to set. 51271 * @return {Audio|undefined} A reference to this instance. 51272 */ 51273 setPlaybackRate( value ) { 51274 51275 if ( this.hasPlaybackControl === false ) { 51276 51277 warn( 'Audio: this Audio has no playback control.' ); 51278 return; 51279 51280 } 51281 51282 this.playbackRate = value; 51283 51284 if ( this.isPlaying === true ) { 51285 51286 this.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 ); 51287 51288 } 51289 51290 return this; 51291 51292 } 51293 51294 /** 51295 * Returns the current playback rate. 51296 51297 * @return {number} The playback rate. 51298 */ 51299 getPlaybackRate() { 51300 51301 return this.playbackRate; 51302 51303 } 51304 51305 /** 51306 * Automatically called when playback finished. 51307 */ 51308 onEnded() { 51309 51310 this.isPlaying = false; 51311 this._progress = 0; 51312 51313 } 51314 51315 /** 51316 * Returns the loop flag. 51317 * 51318 * Can only be used with compatible audio sources that allow playback control. 51319 * 51320 * @return {boolean} Whether the audio should loop or not. 51321 */ 51322 getLoop() { 51323 51324 if ( this.hasPlaybackControl === false ) { 51325 51326 warn( 'Audio: this Audio has no playback control.' ); 51327 return false; 51328 51329 } 51330 51331 return this.loop; 51332 51333 } 51334 51335 /** 51336 * Sets the loop flag. 51337 * 51338 * Can only be used with compatible audio sources that allow playback control. 51339 * 51340 * @param {boolean} value - Whether the audio should loop or not. 51341 * @return {Audio|undefined} A reference to this instance. 51342 */ 51343 setLoop( value ) { 51344 51345 if ( this.hasPlaybackControl === false ) { 51346 51347 warn( 'Audio: this Audio has no playback control.' ); 51348 return; 51349 51350 } 51351 51352 this.loop = value; 51353 51354 if ( this.isPlaying === true ) { 51355 51356 this.source.loop = this.loop; 51357 51358 } 51359 51360 return this; 51361 51362 } 51363 51364 /** 51365 * Sets the loop start value which defines where in the audio buffer the replay should 51366 * start, in seconds. 51367 * 51368 * @param {number} value - The loop start value. 51369 * @return {Audio} A reference to this instance. 51370 */ 51371 setLoopStart( value ) { 51372 51373 this.loopStart = value; 51374 51375 return this; 51376 51377 } 51378 51379 /** 51380 * Sets the loop end value which defines where in the audio buffer the replay should 51381 * stop, in seconds. 51382 * 51383 * @param {number} value - The loop end value. 51384 * @return {Audio} A reference to this instance. 51385 */ 51386 setLoopEnd( value ) { 51387 51388 this.loopEnd = value; 51389 51390 return this; 51391 51392 } 51393 51394 /** 51395 * Returns the volume. 51396 * 51397 * @return {number} The volume. 51398 */ 51399 getVolume() { 51400 51401 return this.gain.gain.value; 51402 51403 } 51404 51405 /** 51406 * Sets the volume. 51407 * 51408 * @param {number} value - The volume to set. 51409 * @return {Audio} A reference to this instance. 51410 */ 51411 setVolume( value ) { 51412 51413 this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 ); 51414 51415 return this; 51416 51417 } 51418 51419 copy( source, recursive ) { 51420 51421 super.copy( source, recursive ); 51422 51423 if ( source.sourceType !== 'buffer' ) { 51424 51425 warn( 'Audio: Audio source type cannot be copied.' ); 51426 51427 return this; 51428 51429 } 51430 51431 this.autoplay = source.autoplay; 51432 51433 this.buffer = source.buffer; 51434 this.detune = source.detune; 51435 this.loop = source.loop; 51436 this.loopStart = source.loopStart; 51437 this.loopEnd = source.loopEnd; 51438 this.offset = source.offset; 51439 this.duration = source.duration; 51440 this.playbackRate = source.playbackRate; 51441 this.hasPlaybackControl = source.hasPlaybackControl; 51442 this.sourceType = source.sourceType; 51443 51444 this.filters = source.filters.slice(); 51445 51446 return this; 51447 51448 } 51449 51450 clone( recursive ) { 51451 51452 return new this.constructor( this.listener ).copy( this, recursive ); 51453 51454 } 51455 51456} 51457 51458const _position = /*@__PURE__*/ new Vector3(); 51459const _quaternion = /*@__PURE__*/ new Quaternion(); 51460const _scale = /*@__PURE__*/ new Vector3(); 51461const _orientation = /*@__PURE__*/ new Vector3(); 51462 51463/** 51464 * Represents a positional audio object. 51465 * 51466 * ```js 51467 * // create an AudioListener and add it to the camera 51468 * const listener = new THREE.AudioListener(); 51469 * camera.add( listener ); 51470 * 51471 * // create the PositionalAudio object (passing in the listener) 51472 * const sound = new THREE.PositionalAudio( listener ); 51473 * 51474 * // load a sound and set it as the PositionalAudio object's buffer 51475 * const audioLoader = new THREE.AudioLoader(); 51476 * audioLoader.load( 'sounds/song.ogg', function( buffer ) { 51477 * sound.setBuffer( buffer ); 51478 * sound.setRefDistance( 20 ); 51479 * sound.play(); 51480 * }); 51481 * 51482 * // create an object for the sound to play from 51483 * const sphere = new THREE.SphereGeometry( 20, 32, 16 ); 51484 * const material = new THREE.MeshPhongMaterial( { color: 0xff2200 } ); 51485 * const mesh = new THREE.Mesh( sphere, material ); 51486 * scene.add( mesh ); 51487 * 51488 * // finally add the sound to the mesh 51489 * mesh.add( sound ); 51490 * 51491 * @augments Audio 51492 */ 51493class PositionalAudio extends Audio { 51494 51495 /** 51496 * Constructs a positional audio. 51497 * 51498 * @param {AudioListener} listener - The global audio listener. 51499 */ 51500 constructor( listener ) { 51501 51502 super( listener ); 51503 51504 /** 51505 * The panner node represents the location, direction, and behavior of an audio 51506 * source in 3D space. 51507 * 51508 * @type {PannerNode} 51509 * @readonly 51510 */ 51511 this.panner = this.context.createPanner(); 51512 this.panner.panningModel = 'HRTF'; 51513 this.panner.connect( this.gain ); 51514 51515 } 51516 51517 connect() { 51518 51519 super.connect(); 51520 51521 this.panner.connect( this.gain ); 51522 51523 return this; 51524 51525 } 51526 51527 disconnect() { 51528 51529 super.disconnect(); 51530 51531 this.panner.disconnect( this.gain ); 51532 51533 return this; 51534 51535 } 51536 51537 getOutput() { 51538 51539 return this.panner; 51540 51541 } 51542 51543 /** 51544 * Returns the current reference distance. 51545 * 51546 * @return {number} The reference distance. 51547 */ 51548 getRefDistance() { 51549 51550 return this.panner.refDistance; 51551 51552 } 51553 51554 /** 51555 * Defines the reference distance for reducing volume as the audio source moves 51556 * further from the listener â i.e. the distance at which the volume reduction 51557 * starts taking effect. 51558 * 51559 * @param {number} value - The reference distance to set. 51560 * @return {PositionalAudio} A reference to this instance. 51561 */ 51562 setRefDistance( value ) { 51563 51564 this.panner.refDistance = value; 51565 51566 return this; 51567 51568 } 51569 51570 /** 51571 * Returns the current rolloff factor. 51572 * 51573 * @return {number} The rolloff factor. 51574 */ 51575 getRolloffFactor() { 51576 51577 return this.panner.rolloffFactor; 51578 51579 } 51580 51581 /** 51582 * Defines how quickly the volume is reduced as the source moves away from the listener. 51583 * 51584 * @param {number} value - The rolloff factor. 51585 * @return {PositionalAudio} A reference to this instance. 51586 */ 51587 setRolloffFactor( value ) { 51588 51589 this.panner.rolloffFactor = value; 51590 51591 return this; 51592 51593 } 51594 51595 /** 51596 * Returns the current distance model. 51597 * 51598 * @return {('linear'|'inverse'|'exponential')} The distance model. 51599 */ 51600 getDistanceModel() { 51601 51602 return this.panner.distanceModel; 51603 51604 } 51605 51606 /** 51607 * Defines which algorithm to use to reduce the volume of the audio source 51608 * as it moves away from the listener. 51609 * 51610 * Read [the spec](https://www.w3.org/TR/webaudio-1.1/#enumdef-distancemodeltype) 51611 * for more details. 51612 * 51613 * @param {('linear'|'inverse'|'exponential')} value - The distance model to set. 51614 * @return {PositionalAudio} A reference to this instance. 51615 */ 51616 setDistanceModel( value ) { 51617 51618 this.panner.distanceModel = value; 51619 51620 return this; 51621 51622 } 51623 51624 /** 51625 * Returns the current max distance. 51626 * 51627 * @return {number} The max distance. 51628 */ 51629 getMaxDistance() { 51630 51631 return this.panner.maxDistance; 51632 51633 } 51634 51635 /** 51636 * Defines the maximum distance between the audio source and the listener, 51637 * after which the volume is not reduced any further. 51638 * 51639 * This value is used only by the `linear` distance model. 51640 * 51641 * @param {number} value - The max distance. 51642 * @return {PositionalAudio} A reference to this instance. 51643 */ 51644 setMaxDistance( value ) { 51645 51646 this.panner.maxDistance = value; 51647 51648 return this; 51649 51650 } 51651 51652 /** 51653 * Sets the directional cone in which the audio can be listened. 51654 * 51655 * @param {number} coneInnerAngle - An angle, in degrees, of a cone inside of which there will be no volume reduction. 51656 * @param {number} coneOuterAngle - An angle, in degrees, of a cone outside of which the volume will be reduced by a constant value, defined by the `coneOuterGain` parameter. 51657 * @param {number} coneOuterGain - The amount of volume reduction outside the cone defined by the `coneOuterAngle`. When set to `0`, no sound can be heard. 51658 * @return {PositionalAudio} A reference to this instance. 51659 */ 51660 setDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) { 51661 51662 this.panner.coneInnerAngle = coneInnerAngle; 51663 this.panner.coneOuterAngle = coneOuterAngle; 51664 this.panner.coneOuterGain = coneOuterGain; 51665 51666 return this; 51667 51668 } 51669 51670 updateMatrixWorld( force ) { 51671 51672 super.updateMatrixWorld( force ); 51673 51674 if ( this.hasPlaybackControl === true && this.isPlaying === false ) return; 51675 51676 this.matrixWorld.decompose( _position, _quaternion, _scale ); 51677 51678 _orientation.set( 0, 0, 1 ).applyQuaternion( _quaternion ); 51679 51680 const panner = this.panner; 51681 51682 if ( panner.positionX ) { 51683 51684 // code path for Chrome and Firefox (see #14393) 51685 51686 const endTime = this.context.currentTime + this.listener.timeDelta; 51687 51688 panner.positionX.linearRampToValueAtTime( _position.x, endTime ); 51689 panner.positionY.linearRampToValueAtTime( _position.y, endTime ); 51690 panner.positionZ.linearRampToValueAtTime( _position.z, endTime ); 51691 panner.orientationX.linearRampToValueAtTime( _orientation.x, endTime ); 51692 panner.orientationY.linearRampToValueAtTime( _orientation.y, endTime ); 51693 panner.orientationZ.linearRampToValueAtTime( _orientation.z, endTime ); 51694 51695 } else { 51696 51697 panner.setPosition( _position.x, _position.y, _position.z ); 51698 panner.setOrientation( _orientation.x, _orientation.y, _orientation.z ); 51699 51700 } 51701 51702 } 51703 51704} 51705 51706/** 51707 * This class can be used to analyse audio data. 51708 * 51709 * ```js 51710 * // create an AudioListener and add it to the camera 51711 * const listener = new THREE.AudioListener(); 51712 * camera.add( listener ); 51713 * 51714 * // create an Audio source 51715 * const sound = new THREE.Audio( listener ); 51716 * 51717 * // load a sound and set it as the Audio object's buffer 51718 * const audioLoader = new THREE.AudioLoader(); 51719 * audioLoader.load( 'sounds/ambient.ogg', function( buffer ) { 51720 * sound.setBuffer( buffer ); 51721 * sound.setLoop(true); 51722 * sound.setVolume(0.5); 51723 * sound.play(); 51724 * }); 51725 * 51726 * // create an AudioAnalyser, passing in the sound and desired fftSize 51727 * const analyser = new THREE.AudioAnalyser( sound, 32 ); 51728 * 51729 * // get the average frequency of the sound 51730 * const data = analyser.getAverageFrequency(); 51731 * ``` 51732 */ 51733class AudioAnalyser { 51734 51735 /** 51736 * Constructs a new audio analyzer. 51737 * 51738 * @param {Audio} audio - The audio to analyze. 51739 * @param {number} [fftSize=2048] - The window size in samples that is used when performing a Fast Fourier Transform (FFT) to get frequency domain data. 51740 */ 51741 constructor( audio, fftSize = 2048 ) { 51742 51743 /** 51744 * The global audio listener. 51745 * 51746 * @type {AnalyserNode} 51747 */ 51748 this.analyser = audio.context.createAnalyser(); 51749 this.analyser.fftSize = fftSize; 51750 51751 /** 51752 * Holds the analyzed data. 51753 * 51754 * @type {Uint8Array} 51755 */ 51756 this.data = new Uint8Array( this.analyser.frequencyBinCount ); 51757 51758 audio.getOutput().connect( this.analyser ); 51759 51760 } 51761 51762 /** 51763 * Returns an array with frequency data of the audio. 51764 * 51765 * Each item in the array represents the decibel value for a specific frequency. 51766 * The frequencies are spread linearly from 0 to 1/2 of the sample rate. 51767 * For example, for 48000 sample rate, the last item of the array will represent 51768 * the decibel value for 24000 Hz. 51769 * 51770 * @return {Uint8Array} The frequency data. 51771 */ 51772 getFrequencyData() { 51773 51774 this.analyser.getByteFrequencyData( this.data ); 51775 51776 return this.data; 51777 51778 } 51779 51780 /** 51781 * Returns the average of the frequencies returned by {@link AudioAnalyser#getFrequencyData}. 51782 * 51783 * @return {number} The average frequency. 51784 */ 51785 getAverageFrequency() { 51786 51787 let value = 0; 51788 const data = this.getFrequencyData(); 51789 51790 for ( let i = 0; i < data.length; i ++ ) { 51791 51792 value += data[ i ]; 51793 51794 } 51795 51796 return value / data.length; 51797 51798 } 51799 51800} 51801 51802/** 51803 * Buffered scene graph property that allows weighted accumulation; used internally. 51804 */ 51805class PropertyMixer { 51806 51807 /** 51808 * Constructs a new property mixer. 51809 * 51810 * @param {PropertyBinding} binding - The property binding. 51811 * @param {string} typeName - The keyframe track type name. 51812 * @param {number} valueSize - The keyframe track value size. 51813 */ 51814 constructor( binding, typeName, valueSize ) { 51815 51816 /** 51817 * The property binding. 51818 * 51819 * @type {PropertyBinding} 51820 */ 51821 this.binding = binding; 51822 51823 /** 51824 * The keyframe track value size. 51825 * 51826 * @type {number} 51827 */ 51828 this.valueSize = valueSize; 51829 51830 let mixFunction, 51831 mixFunctionAdditive, 51832 setIdentity; 51833 51834 // buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ] 51835 // 51836 // interpolators can use .buffer as their .result 51837 // the data then goes to 'incoming' 51838 // 51839 // 'accu0' and 'accu1' are used frame-interleaved for 51840 // the cumulative result and are compared to detect 51841 // changes 51842 // 51843 // 'orig' stores the original state of the property 51844 // 51845 // 'add' is used for additive cumulative results 51846 // 51847 // 'work' is optional and is only present for quaternion types. It is used 51848 // to store intermediate quaternion multiplication results 51849 51850 switch ( typeName ) { 51851 51852 case 'quaternion': 51853 mixFunction = this._slerp; 51854 mixFunctionAdditive = this._slerpAdditive; 51855 setIdentity = this._setAdditiveIdentityQuaternion; 51856 51857 this.buffer = new Float64Array( valueSize * 6 ); 51858 this._workIndex = 5; 51859 break; 51860 51861 case 'string': 51862 case 'bool': 51863 mixFunction = this._select; 51864 51865 // Use the regular mix function and for additive on these types, 51866 // additive is not relevant for non-numeric types 51867 mixFunctionAdditive = this._select; 51868 51869 setIdentity = this._setAdditiveIdentityOther; 51870 51871 this.buffer = new Array( valueSize * 5 ); 51872 break; 51873 51874 default: 51875 mixFunction = this._lerp; 51876 mixFunctionAdditive = this._lerpAdditive; 51877 setIdentity = this._setAdditiveIdentityNumeric; 51878 51879 this.buffer = new Float64Array( valueSize * 5 ); 51880 51881 } 51882 51883 this._mixBufferRegion = mixFunction; 51884 this._mixBufferRegionAdditive = mixFunctionAdditive; 51885 this._setIdentity = setIdentity; 51886 this._origIndex = 3; 51887 this._addIndex = 4; 51888 51889 /** 51890 * Accumulated weight of the property binding. 51891 * 51892 * @type {number} 51893 * @default 0 51894 */ 51895 this.cumulativeWeight = 0; 51896 51897 /** 51898 * Accumulated additive weight of the property binding. 51899 * 51900 * @type {number} 51901 * @default 0 51902 */ 51903 this.cumulativeWeightAdditive = 0; 51904 51905 /** 51906 * Number of active keyframe tracks currently using this property binding. 51907 * 51908 * @type {number} 51909 * @default 0 51910 */ 51911 this.useCount = 0; 51912 51913 /** 51914 * Number of keyframe tracks referencing this property binding. 51915 * 51916 * @type {number} 51917 * @default 0 51918 */ 51919 this.referenceCount = 0; 51920 51921 } 51922 51923 /** 51924 * Accumulates data in the `incoming` region into `accu<i>`. 51925 * 51926 * @param {number} accuIndex - The accumulation index. 51927 * @param {number} weight - The weight. 51928 */ 51929 accumulate( accuIndex, weight ) { 51930 51931 // note: happily accumulating nothing when weight = 0, the caller knows 51932 // the weight and shouldn't have made the call in the first place 51933 51934 const buffer = this.buffer, 51935 stride = this.valueSize, 51936 offset = accuIndex * stride + stride; 51937 51938 let currentWeight = this.cumulativeWeight; 51939 51940 if ( currentWeight === 0 ) { 51941 51942 // accuN := incoming * weight 51943 51944 for ( let i = 0; i !== stride; ++ i ) { 51945 51946 buffer[ offset + i ] = buffer[ i ]; 51947 51948 } 51949 51950 currentWeight = weight; 51951 51952 } else { 51953 51954 // accuN := accuN + incoming * weight 51955 51956 currentWeight += weight; 51957 const mix = weight / currentWeight; 51958 this._mixBufferRegion( buffer, offset, 0, mix, stride ); 51959 51960 } 51961 51962 this.cumulativeWeight = currentWeight; 51963 51964 } 51965 51966 /** 51967 * Accumulates data in the `incoming` region into `add`. 51968 * 51969 * @param {number} weight - The weight. 51970 */ 51971 accumulateAdditive( weight ) { 51972 51973 const buffer = this.buffer, 51974 stride = this.valueSize, 51975 offset = stride * this._addIndex; 51976 51977 if ( this.cumulativeWeightAdditive === 0 ) { 51978 51979 // add = identity 51980 51981 this._setIdentity(); 51982 51983 } 51984 51985 // add := add + incoming * weight 51986 51987 this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride ); 51988 this.cumulativeWeightAdditive += weight; 51989 51990 } 51991 51992 /** 51993 * Applies the state of `accu<i>` to the binding when accus differ. 51994 * 51995 * @param {number} accuIndex - The accumulation index. 51996 */ 51997 apply( accuIndex ) { 51998 51999 const stride = this.valueSize, 52000 buffer = this.buffer, 52001 offset = accuIndex * stride + stride, 52002 52003 weight = this.cumulativeWeight, 52004 weightAdditive = this.cumulativeWeightAdditive, 52005 52006 binding = this.binding; 52007 52008 this.cumulativeWeight = 0; 52009 this.cumulativeWeightAdditive = 0; 52010 52011 if ( weight < 1 ) { 52012 52013 // accuN := accuN + original * ( 1 - cumulativeWeight ) 52014 52015 const originalValueOffset = stride * this._origIndex; 52016 52017 this._mixBufferRegion( 52018 buffer, offset, originalValueOffset, 1 - weight, stride ); 52019 52020 } 52021 52022 if ( weightAdditive > 0 ) { 52023 52024 // accuN := accuN + additive accuN 52025 52026 this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride ); 52027 52028 } 52029 52030 for ( let i = stride, e = stride + stride; i !== e; ++ i ) { 52031 52032 if ( buffer[ i ] !== buffer[ i + stride ] ) { 52033 52034 // value has changed -> update scene graph 52035 52036 binding.setValue( buffer, offset ); 52037 break; 52038 52039 } 52040 52041 } 52042 52043 } 52044 52045 52046 /** 52047 * Remembers the state of the bound property and copy it to both accus. 52048 */ 52049 saveOriginalState() { 52050 52051 const binding = this.binding; 52052 52053 const buffer = this.buffer, 52054 stride = this.valueSize, 52055 52056 originalValueOffset = stride * this._origIndex; 52057 52058 binding.getValue( buffer, originalValueOffset ); 52059 52060 // accu[0..1] := orig -- initially detect changes against the original 52061 for ( let i = stride, e = originalValueOffset; i !== e; ++ i ) { 52062 52063 buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ]; 52064 52065 } 52066 52067 // Add to identity for additive 52068 this._setIdentity(); 52069 52070 this.cumulativeWeight = 0; 52071 this.cumulativeWeightAdditive = 0; 52072 52073 } 52074 52075 /** 52076 * Applies the state previously taken via {@link PropertyMixer#saveOriginalState} to the binding. 52077 */ 52078 restoreOriginalState() { 52079 52080 const originalValueOffset = this.valueSize * 3; 52081 this.binding.setValue( this.buffer, originalValueOffset ); 52082 52083 } 52084 52085 // internals 52086 52087 _setAdditiveIdentityNumeric() { 52088 52089 const startIndex = this._addIndex * this.valueSize; 52090 const endIndex = startIndex + this.valueSize; 52091 52092 for ( let i = startIndex; i < endIndex; i ++ ) { 52093 52094 this.buffer[ i ] = 0; 52095 52096 } 52097 52098 } 52099 52100 _setAdditiveIdentityQuaternion() { 52101 52102 this._setAdditiveIdentityNumeric(); 52103 this.buffer[ this._addIndex * this.valueSize + 3 ] = 1; 52104 52105 } 52106 52107 _setAdditiveIdentityOther() { 52108 52109 const startIndex = this._origIndex * this.valueSize; 52110 const targetIndex = this._addIndex * this.valueSize; 52111 52112 for ( let i = 0; i < this.valueSize; i ++ ) { 52113 52114 this.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ]; 52115 52116 } 52117 52118 } 52119 52120 52121 // mix functions 52122 52123 _select( buffer, dstOffset, srcOffset, t, stride ) { 52124 52125 if ( t >= 0.5 ) { 52126 52127 for ( let i = 0; i !== stride; ++ i ) { 52128 52129 buffer[ dstOffset + i ] = buffer[ srcOffset + i ]; 52130 52131 } 52132 52133 } 52134 52135 } 52136 52137 _slerp( buffer, dstOffset, srcOffset, t ) { 52138 52139 Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t ); 52140 52141 } 52142 52143 _slerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { 52144 52145 const workOffset = this._workIndex * stride; 52146 52147 // Store result in intermediate buffer offset 52148 Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset ); 52149 52150 // Slerp to the intermediate result 52151 Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t ); 52152 52153 } 52154 52155 _lerp( buffer, dstOffset, srcOffset, t, stride ) { 52156 52157 const s = 1 - t; 52158 52159 for ( let i = 0; i !== stride; ++ i ) { 52160 52161 const j = dstOffset + i; 52162 52163 buffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t; 52164 52165 } 52166 52167 } 52168 52169 _lerpAdditive( buffer, dstOffset, srcOffset, t, stride ) { 52170 52171 for ( let i = 0; i !== stride; ++ i ) { 52172 52173 const j = dstOffset + i; 52174 52175 buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t; 52176 52177 } 52178 52179 } 52180 52181} 52182 52183// Characters [].:/ are reserved for track binding syntax. 52184const _RESERVED_CHARS_RE = '\\[\\]\\.:\\/'; 52185const _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' ); 52186 52187// Attempts to allow node names from any language. ES5's `\w` regexp matches 52188// only latin characters, and the unicode \p{L} is not yet supported. So 52189// instead, we exclude reserved characters and match everything else. 52190const _wordChar = '[^' + _RESERVED_CHARS_RE + ']'; 52191const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']'; 52192 52193// Parent directories, delimited by '/' or ':'. Currently unused, but must 52194// be matched to parse the rest of the track name. 52195const _directoryRe = /*@__PURE__*/ /((?:WC+[\/:])*)/.source.replace( 'WC', _wordChar ); 52196 52197// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'. 52198const _nodeRe = /*@__PURE__*/ /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot ); 52199 52200// Object on target node, and accessor. May not contain reserved 52201// characters. Accessor may contain any character except closing bracket. 52202const _objectRe = /*@__PURE__*/ /(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace( 'WC', _wordChar ); 52203 52204// Property and accessor. May not contain reserved characters. Accessor may 52205// contain any non-bracket characters. 52206const _propertyRe = /*@__PURE__*/ /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC', _wordChar ); 52207 52208const _trackRe = new RegExp( '' 52209 + '^' 52210 + _directoryRe 52211 + _nodeRe 52212 + _objectRe 52213 + _propertyRe 52214 + '$' 52215); 52216 52217const _supportedObjectNames = [ 'material', 'materials', 'bones', 'map' ]; 52218 52219class Composite { 52220 52221 constructor( targetGroup, path, optionalParsedPath ) { 52222 52223 const parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path ); 52224 52225 this._targetGroup = targetGroup; 52226 this._bindings = targetGroup.subscribe_( path, parsedPath ); 52227 52228 } 52229 52230 getValue( array, offset ) { 52231 52232 this.bind(); // bind all binding 52233 52234 const firstValidIndex = this._targetGroup.nCachedObjects_, 52235 binding = this._bindings[ firstValidIndex ]; 52236 52237 // and only call .getValue on the first 52238 if ( binding !== undefined ) binding.getValue( array, offset ); 52239 52240 } 52241 52242 setValue( array, offset ) { 52243 52244 const bindings = this._bindings; 52245 52246 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { 52247 52248 bindings[ i ].setValue( array, offset ); 52249 52250 } 52251 52252 } 52253 52254 bind() { 52255 52256 const bindings = this._bindings; 52257 52258 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { 52259 52260 bindings[ i ].bind(); 52261 52262 } 52263 52264 } 52265 52266 unbind() { 52267 52268 const bindings = this._bindings; 52269 52270 for ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) { 52271 52272 bindings[ i ].unbind(); 52273 52274 } 52275 52276 } 52277 52278} 52279 52280// Note: This class uses a State pattern on a per-method basis: 52281// 'bind' sets 'this.getValue' / 'setValue' and shadows the 52282// prototype version of these methods with one that represents 52283// the bound state. When the property is not found, the methods 52284// become no-ops. 52285 52286 52287/** 52288 * This holds a reference to a real property in the scene graph; used internally. 52289 */ 52290class PropertyBinding { 52291 52292 /** 52293 * Constructs a new property binding. 52294 * 52295 * @param {Object} rootNode - The root node. 52296 * @param {string} path - The path.
vendor: 6,443 bytes, lines 52297-52592
52297 * @param {?Object} [parsedPath] - The parsed path. 52298 */ 52299 constructor( rootNode, path, parsedPath ) { 52300 52301 /** 52302 * The object path to the animated property. 52303 * 52304 * @type {string} 52305 */ 52306 this.path = path; 52307 52308 /** 52309 * An object holding information about the path. 52310 * 52311 * @type {Object} 52312 */ 52313 this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path ); 52314 52315 /** 52316 * The object owns the animated property. 52317 * 52318 * @type {?Object} 52319 */ 52320 this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ); 52321 52322 /** 52323 * The root node. 52324 * 52325 * @type {Object3D|Skeleton} 52326 */ 52327 this.rootNode = rootNode; 52328 52329 // initial state of these methods that calls 'bind' 52330 this.getValue = this._getValue_unbound; 52331 this.setValue = this._setValue_unbound; 52332 52333 } 52334 52335 52336 /** 52337 * Factory method for creating a property binding from the given parameters. 52338 * 52339 * @static 52340 * @param {Object} root - The root node. 52341 * @param {string} path - The path. 52342 * @param {?Object} [parsedPath] - The parsed path. 52343 * @return {PropertyBinding|Composite} The created property binding or composite. 52344 */ 52345 static create( root, path, parsedPath ) { 52346 52347 if ( ! ( root && root.isAnimationObjectGroup ) ) { 52348 52349 return new PropertyBinding( root, path, parsedPath ); 52350 52351 } else { 52352 52353 return new PropertyBinding.Composite( root, path, parsedPath ); 52354 52355 } 52356 52357 } 52358 52359 /** 52360 * Replaces spaces with underscores and removes unsupported characters from 52361 * node names, to ensure compatibility with parseTrackName(). 52362 * 52363 * @param {string} name - Node name to be sanitized. 52364 * @return {string} The sanitized node name. 52365 */ 52366 static sanitizeNodeName( name ) { 52367 52368 return name.replace( /\s/g, '_' ).replace( _reservedRe, '' ); 52369 52370 } 52371 52372 /** 52373 * Parses the given track name (an object path to an animated property) and 52374 * returns an object with information about the path. Matches strings in the following forms: 52375 * 52376 * - nodeName.property 52377 * - nodeName.property[accessor] 52378 * - nodeName.material.property[accessor] 52379 * - uuid.property[accessor] 52380 * - uuid.objectName[objectIndex].propertyName[propertyIndex] 52381 * - parentName/nodeName.property 52382 * - parentName/parentName/nodeName.property[index] 52383 * - .bone[Armature.DEF_cog].position 52384 * - scene:helium_balloon_model:helium_balloon_model.position 52385 * 52386 * @static 52387 * @param {string} trackName - The track name to parse. 52388 * @return {Object} The parsed track name as an object. 52389 */ 52390 static parseTrackName( trackName ) { 52391 52392 const matches = _trackRe.exec( trackName ); 52393 52394 if ( matches === null ) { 52395 52396 throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName ); 52397 52398 } 52399 52400 const results = { 52401 // directoryName: matches[ 1 ], // (tschw) currently unused 52402 nodeName: matches[ 2 ], 52403 objectName: matches[ 3 ], 52404 objectIndex: matches[ 4 ], 52405 propertyName: matches[ 5 ], // required 52406 propertyIndex: matches[ 6 ] 52407 }; 52408 52409 const lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' ); 52410 52411 if ( lastDot !== undefined && lastDot !== -1 ) { 52412 52413 const objectName = results.nodeName.substring( lastDot + 1 ); 52414 52415 // Object names must be checked against an allowlist. Otherwise, there 52416 // is no way to parse 'foo.bar.baz': 'baz' must be a property, but 52417 // 'bar' could be the objectName, or part of a nodeName (which can 52418 // include '.' characters). 52419 if ( _supportedObjectNames.indexOf( objectName ) !== -1 ) { 52420 52421 results.nodeName = results.nodeName.substring( 0, lastDot ); 52422 results.objectName = objectName; 52423 52424 } 52425 52426 } 52427 52428 if ( results.propertyName === null || results.propertyName.length === 0 ) { 52429 52430 throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName ); 52431 52432 } 52433 52434 return results; 52435 52436 } 52437 52438 /** 52439 * Searches for a node in the hierarchy of the given root object by the given 52440 * node name. 52441 * 52442 * @static 52443 * @param {Object} root - The root object. 52444 * @param {string|number} nodeName - The name of the node. 52445 * @return {?Object} The found node. Returns `null` if no object was found. 52446 */ 52447 static findNode( root, nodeName ) { 52448 52449 if ( nodeName === undefined || nodeName === '' || nodeName === '.' || nodeName === -1 || nodeName === root.name || nodeName === root.uuid ) { 52450 52451 return root; 52452 52453 } 52454 52455 // search into skeleton bones. 52456 if ( root.skeleton ) { 52457 52458 const bone = root.skeleton.getBoneByName( nodeName ); 52459 52460 if ( bone !== undefined ) { 52461 52462 return bone; 52463 52464 } 52465 52466 } 52467 52468 // search into node subtree. 52469 if ( root.children ) { 52470 52471 const searchNodeSubtree = function ( children ) { 52472 52473 for ( let i = 0; i < children.length; i ++ ) { 52474 52475 const childNode = children[ i ]; 52476 52477 if ( childNode.name === nodeName || childNode.uuid === nodeName ) { 52478 52479 return childNode; 52480 52481 } 52482 52483 const result = searchNodeSubtree( childNode.children ); 52484 52485 if ( result ) return result; 52486 52487 } 52488 52489 return null; 52490 52491 }; 52492 52493 const subTreeNode = searchNodeSubtree( root.children ); 52494 52495 if ( subTreeNode ) { 52496 52497 return subTreeNode; 52498 52499 } 52500 52501 } 52502 52503 return null; 52504 52505 } 52506 52507 // these are used to "bind" a nonexistent property 52508 _getValue_unavailable() {} 52509 _setValue_unavailable() {} 52510 52511 // Getters 52512 52513 _getValue_direct( buffer, offset ) { 52514 52515 buffer[ offset ] = this.targetObject[ this.propertyName ]; 52516 52517 } 52518 52519 _getValue_array( buffer, offset ) { 52520 52521 const source = this.resolvedProperty; 52522 52523 for ( let i = 0, n = source.length; i !== n; ++ i ) { 52524 52525 buffer[ offset ++ ] = source[ i ]; 52526 52527 } 52528 52529 } 52530 52531 _getValue_arrayElement( buffer, offset ) { 52532 52533 buffer[ offset ] = this.resolvedProperty[ this.propertyIndex ]; 52534 52535 } 52536 52537 _getValue_toArray( buffer, offset ) { 52538 52539 this.resolvedProperty.toArray( buffer, offset ); 52540 52541 } 52542 52543 // Direct 52544 52545 _setValue_direct( buffer, offset ) { 52546 52547 this.targetObject[ this.propertyName ] = buffer[ offset ]; 52548 52549 } 52550 52551 _setValue_direct_setNeedsUpdate( buffer, offset ) { 52552 52553 this.targetObject[ this.propertyName ] = buffer[ offset ]; 52554 this.targetObject.needsUpdate = true; 52555 52556 } 52557 52558 _setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) { 52559 52560 this.targetObject[ this.propertyName ] = buffer[ offset ]; 52561 this.targetObject.matrixWorldNeedsUpdate = true; 52562 52563 } 52564 52565 // EntireArray 52566 52567 _setValue_array( buffer, offset ) { 52568 52569 const dest = this.resolvedProperty; 52570 52571 for ( let i = 0, n = dest.length; i !== n; ++ i ) { 52572 52573 dest[ i ] = buffer[ offset ++ ]; 52574 52575 } 52576 52577 } 52578 52579 _setValue_array_setNeedsUpdate( buffer, offset ) { 52580 52581 const dest = this.resolvedProperty; 52582 52583 for ( let i = 0, n = dest.length; i !== n; ++ i ) { 52584 52585 dest[ i ] = buffer[ offset ++ ]; 52586 52587 } 52588 52589 this.targetObject.needsUpdate = true; 52590 52591 } 52592
vendor: 15,184 bytes, lines 52593-53247
52593 _setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) { 52594 52595 const dest = this.resolvedProperty; 52596 52597 for ( let i = 0, n = dest.length; i !== n; ++ i ) { 52598 52599 dest[ i ] = buffer[ offset ++ ]; 52600 52601 } 52602 52603 this.targetObject.matrixWorldNeedsUpdate = true; 52604 52605 } 52606 52607 // ArrayElement 52608 52609 _setValue_arrayElement( buffer, offset ) { 52610 52611 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; 52612 52613 } 52614 52615 _setValue_arrayElement_setNeedsUpdate( buffer, offset ) { 52616 52617 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; 52618 this.targetObject.needsUpdate = true; 52619 52620 } 52621 52622 _setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) { 52623 52624 this.resolvedProperty[ this.propertyIndex ] = buffer[ offset ]; 52625 this.targetObject.matrixWorldNeedsUpdate = true; 52626 52627 } 52628 52629 // HasToFromArray 52630 52631 _setValue_fromArray( buffer, offset ) { 52632 52633 this.resolvedProperty.fromArray( buffer, offset ); 52634 52635 } 52636 52637 _setValue_fromArray_setNeedsUpdate( buffer, offset ) { 52638 52639 this.resolvedProperty.fromArray( buffer, offset ); 52640 this.targetObject.needsUpdate = true; 52641 52642 } 52643 52644 _setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) { 52645 52646 this.resolvedProperty.fromArray( buffer, offset ); 52647 this.targetObject.matrixWorldNeedsUpdate = true; 52648 52649 } 52650 52651 _getValue_unbound( targetArray, offset ) { 52652 52653 this.bind(); 52654 this.getValue( targetArray, offset ); 52655 52656 } 52657 52658 _setValue_unbound( sourceArray, offset ) { 52659 52660 this.bind(); 52661 this.setValue( sourceArray, offset ); 52662 52663 } 52664 52665 /** 52666 * Creates a getter / setter pair for the property tracked by this binding. 52667 */ 52668 bind() { 52669 52670 let targetObject = this.node; 52671 const parsedPath = this.parsedPath; 52672 52673 const objectName = parsedPath.objectName; 52674 const propertyName = parsedPath.propertyName; 52675 let propertyIndex = parsedPath.propertyIndex; 52676 52677 if ( ! targetObject ) { 52678 52679 targetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName ); 52680 52681 this.node = targetObject; 52682 52683 } 52684 52685 // set fail state so we can just 'return' on error 52686 this.getValue = this._getValue_unavailable; 52687 this.setValue = this._setValue_unavailable; 52688 52689 // ensure there is a value node 52690 if ( ! targetObject ) { 52691 52692 warn( 'PropertyBinding: No target node found for track: ' + this.path + '.' ); 52693 return; 52694 52695 } 52696 52697 if ( objectName ) { 52698 52699 let objectIndex = parsedPath.objectIndex; 52700 52701 // special cases were we need to reach deeper into the hierarchy to get the face materials.... 52702 switch ( objectName ) { 52703 52704 case 'materials': 52705 52706 if ( ! targetObject.material ) { 52707 52708 error( 'PropertyBinding: Can not bind to material as node does not have a material.', this ); 52709 return; 52710 52711 } 52712 52713 if ( ! targetObject.material.materials ) { 52714 52715 error( 'PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this ); 52716 return; 52717 52718 } 52719 52720 targetObject = targetObject.material.materials; 52721 52722 break; 52723 52724 case 'bones': 52725 52726 if ( ! targetObject.skeleton ) { 52727 52728 error( 'PropertyBinding: Can not bind to bones as node does not have a skeleton.', this ); 52729 return; 52730 52731 } 52732 52733 // potential future optimization: skip this if propertyIndex is already an integer 52734 // and convert the integer string to a true integer. 52735 52736 targetObject = targetObject.skeleton.bones; 52737 52738 // support resolving morphTarget names into indices. 52739 for ( let i = 0; i < targetObject.length; i ++ ) { 52740 52741 if ( targetObject[ i ].name === objectIndex ) { 52742 52743 objectIndex = i; 52744 break; 52745 52746 } 52747 52748 } 52749 52750 break; 52751 52752 case 'map': 52753 52754 if ( 'map' in targetObject ) { 52755 52756 targetObject = targetObject.map; 52757 break; 52758 52759 } 52760 52761 if ( ! targetObject.material ) { 52762 52763 error( 'PropertyBinding: Can not bind to material as node does not have a material.', this ); 52764 return; 52765 52766 } 52767 52768 if ( ! targetObject.material.map ) { 52769 52770 error( 'PropertyBinding: Can not bind to material.map as node.material does not have a map.', this ); 52771 return; 52772 52773 } 52774 52775 targetObject = targetObject.material.map; 52776 break; 52777 52778 default: 52779 52780 if ( targetObject[ objectName ] === undefined ) { 52781 52782 error( 'PropertyBinding: Can not bind to objectName of node undefined.', this ); 52783 return; 52784 52785 } 52786 52787 targetObject = targetObject[ objectName ]; 52788 52789 } 52790 52791 52792 if ( objectIndex !== undefined ) { 52793 52794 if ( targetObject[ objectIndex ] === undefined ) { 52795 52796 error( 'PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject ); 52797 return; 52798 52799 } 52800 52801 targetObject = targetObject[ objectIndex ]; 52802 52803 } 52804 52805 } 52806 52807 // resolve property 52808 const nodeProperty = targetObject[ propertyName ]; 52809 52810 if ( nodeProperty === undefined ) { 52811 52812 const nodeName = parsedPath.nodeName; 52813 52814 error( 'PropertyBinding: Trying to update property for track: ' + nodeName + 52815 '.' + propertyName + ' but it wasn\'t found.', targetObject ); 52816 return; 52817 52818 } 52819 52820 // determine versioning scheme 52821 let versioning = this.Versioning.None; 52822 52823 this.targetObject = targetObject; 52824 52825 if ( targetObject.isMaterial === true ) { 52826 52827 versioning = this.Versioning.NeedsUpdate; 52828 52829 } else if ( targetObject.isObject3D === true ) { 52830 52831 versioning = this.Versioning.MatrixWorldNeedsUpdate; 52832 52833 } 52834 52835 // determine how the property gets bound 52836 let bindingType = this.BindingType.Direct; 52837 52838 if ( propertyIndex !== undefined ) { 52839 52840 // access a sub element of the property array (only primitives are supported right now) 52841 52842 if ( propertyName === 'morphTargetInfluences' ) { 52843 52844 // potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer. 52845 52846 // support resolving morphTarget names into indices. 52847 if ( ! targetObject.geometry ) { 52848 52849 error( 'PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this ); 52850 return; 52851 52852 } 52853 52854 if ( ! targetObject.geometry.morphAttributes ) { 52855 52856 error( 'PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this ); 52857 return; 52858 52859 } 52860 52861 if ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) { 52862 52863 propertyIndex = targetObject.morphTargetDictionary[ propertyIndex ]; 52864 52865 } 52866 52867 } 52868 52869 bindingType = this.BindingType.ArrayElement; 52870 52871 this.resolvedProperty = nodeProperty; 52872 this.propertyIndex = propertyIndex; 52873 52874 } else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) { 52875 52876 // must use copy for Object3D.Euler/Quaternion 52877 52878 bindingType = this.BindingType.HasFromToArray; 52879 52880 this.resolvedProperty = nodeProperty; 52881 52882 } else if ( Array.isArray( nodeProperty ) ) { 52883 52884 bindingType = this.BindingType.EntireArray; 52885 52886 this.resolvedProperty = nodeProperty; 52887 52888 } else { 52889 52890 this.propertyName = propertyName; 52891 52892 } 52893 52894 // select getter / setter 52895 this.getValue = this.GetterByBindingType[ bindingType ]; 52896 this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ]; 52897 52898 } 52899 52900 /** 52901 * Unbinds the property. 52902 */ 52903 unbind() { 52904 52905 this.node = null; 52906 52907 // back to the prototype version of getValue / setValue 52908 // note: avoiding to mutate the shape of 'this' via 'delete' 52909 this.getValue = this._getValue_unbound; 52910 this.setValue = this._setValue_unbound; 52911 52912 } 52913 52914} 52915 52916PropertyBinding.Composite = Composite; 52917 52918PropertyBinding.prototype.BindingType = { 52919 Direct: 0, 52920 EntireArray: 1, 52921 ArrayElement: 2, 52922 HasFromToArray: 3 52923}; 52924 52925PropertyBinding.prototype.Versioning = { 52926 None: 0, 52927 NeedsUpdate: 1, 52928 MatrixWorldNeedsUpdate: 2 52929}; 52930 52931PropertyBinding.prototype.GetterByBindingType = [ 52932 52933 PropertyBinding.prototype._getValue_direct, 52934 PropertyBinding.prototype._getValue_array, 52935 PropertyBinding.prototype._getValue_arrayElement, 52936 PropertyBinding.prototype._getValue_toArray, 52937 52938]; 52939 52940PropertyBinding.prototype.SetterByBindingTypeAndVersioning = [ 52941 52942 [ 52943 // Direct 52944 PropertyBinding.prototype._setValue_direct, 52945 PropertyBinding.prototype._setValue_direct_setNeedsUpdate, 52946 PropertyBinding.prototype._setValue_direct_setMatrixWorldNeedsUpdate, 52947 52948 ], [ 52949 52950 // EntireArray 52951 52952 PropertyBinding.prototype._setValue_array, 52953 PropertyBinding.prototype._setValue_array_setNeedsUpdate, 52954 PropertyBinding.prototype._setValue_array_setMatrixWorldNeedsUpdate, 52955 52956 ], [ 52957 52958 // ArrayElement 52959 PropertyBinding.prototype._setValue_arrayElement, 52960 PropertyBinding.prototype._setValue_arrayElement_setNeedsUpdate, 52961 PropertyBinding.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate, 52962 52963 ], [ 52964 52965 // HasToFromArray 52966 PropertyBinding.prototype._setValue_fromArray, 52967 PropertyBinding.prototype._setValue_fromArray_setNeedsUpdate, 52968 PropertyBinding.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate, 52969 52970 ] 52971 52972]; 52973 52974/** 52975 * A group of objects that receives a shared animation state. 52976 * 52977 * Usage: 52978 * 52979 * - Add objects you would otherwise pass as 'root' to the 52980 * constructor or the .clipAction method of AnimationMixer. 52981 * - Instead pass this object as 'root'. 52982 * - You can also add and remove objects later when the mixer is running. 52983 * 52984 * Note: 52985 * 52986 * - Objects of this class appear as one object to the mixer, 52987 * so cache control of the individual objects must be done on the group. 52988 * 52989 * Limitation: 52990 * 52991 * - The animated properties must be compatible among the all objects in the group. 52992 * - A single property can either be controlled through a target group or directly, but not both. 52993 */ 52994class AnimationObjectGroup { 52995 52996 /** 52997 * Constructs a new animation group. 52998 * 52999 * @param {...Object3D} arguments - An arbitrary number of 3D objects that share the same animation state. 53000 */ 53001 constructor() { 53002 53003 /** 53004 * This flag can be used for type testing. 53005 * 53006 * @type {boolean} 53007 * @readonly 53008 * @default true 53009 */ 53010 this.isAnimationObjectGroup = true; 53011 53012 /** 53013 * The UUID of the 3D object. 53014 * 53015 * @type {string} 53016 * @readonly 53017 */ 53018 this.uuid = generateUUID(); 53019 53020 // cached objects followed by the active ones 53021 this._objects = Array.prototype.slice.call( arguments ); 53022 53023 this.nCachedObjects_ = 0; // threshold 53024 // note: read by PropertyBinding.Composite 53025 53026 const indices = {}; 53027 this._indicesByUUID = indices; // for bookkeeping 53028 53029 for ( let i = 0, n = arguments.length; i !== n; ++ i ) { 53030 53031 indices[ arguments[ i ].uuid ] = i; 53032 53033 } 53034 53035 this._paths = []; // inside: string 53036 this._parsedPaths = []; // inside: { we don't care, here } 53037 this._bindings = []; // inside: Array< PropertyBinding > 53038 this._bindingsIndicesByPath = {}; // inside: indices in these arrays 53039 53040 const scope = this; 53041 53042 this.stats = { 53043 53044 objects: { 53045 get total() { 53046 53047 return scope._objects.length; 53048 53049 }, 53050 get inUse() { 53051 53052 return this.total - scope.nCachedObjects_; 53053 53054 } 53055 }, 53056 get bindingsPerObject() { 53057 53058 return scope._bindings.length; 53059 53060 } 53061 53062 }; 53063 53064 } 53065 53066 /** 53067 * Adds an arbitrary number of objects to this animation group. 53068 * 53069 * @param {...Object3D} arguments - The 3D objects to add. 53070 */ 53071 add() { 53072 53073 const objects = this._objects, 53074 indicesByUUID = this._indicesByUUID, 53075 paths = this._paths, 53076 parsedPaths = this._parsedPaths, 53077 bindings = this._bindings, 53078 nBindings = bindings.length; 53079 53080 let knownObject = undefined, 53081 nObjects = objects.length, 53082 nCachedObjects = this.nCachedObjects_; 53083 53084 for ( let i = 0, n = arguments.length; i !== n; ++ i ) { 53085 53086 const object = arguments[ i ], 53087 uuid = object.uuid; 53088 let index = indicesByUUID[ uuid ]; 53089 53090 if ( index === undefined ) { 53091 53092 // unknown object -> add it to the ACTIVE region 53093 53094 index = nObjects ++; 53095 indicesByUUID[ uuid ] = index; 53096 objects.push( object ); 53097 53098 // accounting is done, now do the same for all bindings 53099 53100 for ( let j = 0, m = nBindings; j !== m; ++ j ) { 53101 53102 bindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) ); 53103 53104 } 53105 53106 } else if ( index < nCachedObjects ) { 53107 53108 knownObject = objects[ index ]; 53109 53110 // move existing object to the ACTIVE region 53111 53112 const firstActiveIndex = -- nCachedObjects, 53113 lastCachedObject = objects[ firstActiveIndex ]; 53114 53115 indicesByUUID[ lastCachedObject.uuid ] = index; 53116 objects[ index ] = lastCachedObject; 53117 53118 indicesByUUID[ uuid ] = firstActiveIndex; 53119 objects[ firstActiveIndex ] = object; 53120 53121 // accounting is done, now do the same for all bindings 53122 53123 for ( let j = 0, m = nBindings; j !== m; ++ j ) { 53124 53125 const bindingsForPath = bindings[ j ], 53126 lastCached = bindingsForPath[ firstActiveIndex ]; 53127 53128 let binding = bindingsForPath[ index ]; 53129 53130 bindingsForPath[ index ] = lastCached; 53131 53132 if ( binding === undefined ) { 53133 53134 // since we do not bother to create new bindings 53135 // for objects that are cached, the binding may 53136 // or may not exist 53137 53138 binding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ); 53139 53140 } 53141 53142 bindingsForPath[ firstActiveIndex ] = binding; 53143 53144 } 53145 53146 } else if ( objects[ index ] !== knownObject ) { 53147 53148 error( 'AnimationObjectGroup: Different objects with the same UUID ' + 53149 'detected. Clean the caches or recreate your infrastructure when reloading scenes.' ); 53150 53151 } // else the object is already where we want it to be 53152 53153 } // for arguments 53154 53155 this.nCachedObjects_ = nCachedObjects; 53156 53157 } 53158 53159 /** 53160 * Removes an arbitrary number of objects to this animation group 53161 * 53162 * @param {...Object3D} arguments - The 3D objects to remove. 53163 */ 53164 remove() { 53165 53166 const objects = this._objects, 53167 indicesByUUID = this._indicesByUUID, 53168 bindings = this._bindings, 53169 nBindings = bindings.length; 53170 53171 let nCachedObjects = this.nCachedObjects_; 53172 53173 for ( let i = 0, n = arguments.length; i !== n; ++ i ) { 53174 53175 const object = arguments[ i ], 53176 uuid = object.uuid, 53177 index = indicesByUUID[ uuid ]; 53178 53179 if ( index !== undefined && index >= nCachedObjects ) { 53180 53181 // move existing object into the CACHED region 53182 53183 const lastCachedIndex = nCachedObjects ++, 53184 firstActiveObject = objects[ lastCachedIndex ]; 53185 53186 indicesByUUID[ firstActiveObject.uuid ] = index; 53187 objects[ index ] = firstActiveObject; 53188 53189 indicesByUUID[ uuid ] = lastCachedIndex; 53190 objects[ lastCachedIndex ] = object; 53191 53192 // accounting is done, now do the same for all bindings 53193 53194 for ( let j = 0, m = nBindings; j !== m; ++ j ) { 53195 53196 const bindingsForPath = bindings[ j ], 53197 firstActive = bindingsForPath[ lastCachedIndex ], 53198 binding = bindingsForPath[ index ]; 53199 53200 bindingsForPath[ index ] = firstActive; 53201 bindingsForPath[ lastCachedIndex ] = binding; 53202 53203 } 53204 53205 } 53206 53207 } // for arguments 53208 53209 this.nCachedObjects_ = nCachedObjects; 53210 53211 } 53212 53213 /** 53214 * Deallocates all memory resources for the passed 3D objects of this animation group. 53215 * 53216 * @param {...Object3D} arguments - The 3D objects to uncache. 53217 */ 53218 uncache() { 53219 53220 const objects = this._objects, 53221 indicesByUUID = this._indicesByUUID, 53222 bindings = this._bindings, 53223 nBindings = bindings.length; 53224 53225 let nCachedObjects = this.nCachedObjects_, 53226 nObjects = objects.length; 53227 53228 for ( let i = 0, n = arguments.length; i !== n; ++ i ) { 53229 53230 const object = arguments[ i ], 53231 uuid = object.uuid, 53232 index = indicesByUUID[ uuid ]; 53233 53234 if ( index !== undefined ) { 53235 53236 delete indicesByUUID[ uuid ]; 53237 53238 if ( index < nCachedObjects ) { 53239 53240 // object is cached, shrink the CACHED region 53241 53242 const firstActiveIndex = -- nCachedObjects, 53243 lastCachedObject = objects[ firstActiveIndex ], 53244 lastIndex = -- nObjects, 53245 lastObject = objects[ lastIndex ]; 53246 53247
53247// last cached object takes this object's place 53248 indicesByUUID[ lastCachedObject.uuid ] = index; 53249 objects[ index ] = lastCachedObject; 53250 53251 // last object goes to the activated slot and pop 53252 indicesByUUID[ lastObject.uuid ] = firstActiveIndex; 53253 objects[ firstActiveIndex ] = lastObject; 53254 objects.pop(); 53255 53256 // accounting is done, now do the same for all bindings 53257 53258 for ( let j = 0, m = nBindings; j !== m; ++ j ) { 53259 53260 const bindingsForPath = bindings[ j ], 53261 lastCached = bindingsForPath[ firstActiveIndex ], 53262 last = bindingsForPath[ lastIndex ]; 53263 53264 bindingsForPath[ index ] = lastCached; 53265 bindingsForPath[ firstActiveIndex ] = last; 53266 bindingsForPath.pop(); 53267 53268 } 53269 53270 } else { 53271 53272 // object is active, just swap with the last and pop 53273 53274 const lastIndex = -- nObjects, 53275 lastObject = objects[ lastIndex ]; 53276 53277 if ( lastIndex > 0 ) { 53278 53279 indicesByUUID[ lastObject.uuid ] = index; 53280 53281 } 53282 53283 objects[ index ] = lastObject; 53284 objects.pop(); 53285 53286 // accounting is done, now do the same for all bindings 53287 53288 for ( let j = 0, m = nBindings; j !== m; ++ j ) { 53289
vendor: 3,925 bytes, lines 53290-53444
53290 const bindingsForPath = bindings[ j ]; 53291 53292 bindingsForPath[ index ] = bindingsForPath[ lastIndex ]; 53293 bindingsForPath.pop(); 53294 53295 } 53296 53297 } // cached or active 53298 53299 } // if object is known 53300 53301 } // for arguments 53302 53303 this.nCachedObjects_ = nCachedObjects; 53304 53305 } 53306 53307 // Internal interface used by befriended PropertyBinding.Composite: 53308 53309 subscribe_( path, parsedPath ) { 53310 53311 // returns an array of bindings for the given path that is changed 53312 // according to the contained objects in the group 53313 53314 const indicesByPath = this._bindingsIndicesByPath; 53315 let index = indicesByPath[ path ]; 53316 const bindings = this._bindings; 53317 53318 if ( index !== undefined ) return bindings[ index ]; 53319 53320 const paths = this._paths, 53321 parsedPaths = this._parsedPaths, 53322 objects = this._objects, 53323 nObjects = objects.length, 53324 nCachedObjects = this.nCachedObjects_, 53325 bindingsForPath = new Array( nObjects ); 53326 53327 index = bindings.length; 53328 53329 indicesByPath[ path ] = index; 53330 53331 paths.push( path ); 53332 parsedPaths.push( parsedPath ); 53333 bindings.push( bindingsForPath ); 53334 53335 for ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) { 53336 53337 const object = objects[ i ]; 53338 bindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath ); 53339 53340 } 53341 53342 return bindingsForPath; 53343 53344 } 53345 53346 unsubscribe_( path ) { 53347 53348 // tells the group to forget about a property path and no longer 53349 // update the array previously obtained with 'subscribe_' 53350 53351 const indicesByPath = this._bindingsIndicesByPath, 53352 index = indicesByPath[ path ]; 53353 53354 if ( index !== undefined ) { 53355 53356 const paths = this._paths, 53357 parsedPaths = this._parsedPaths, 53358 bindings = this._bindings, 53359 lastBindingsIndex = bindings.length - 1, 53360 lastBindings = bindings[ lastBindingsIndex ], 53361 lastBindingsPath = path[ lastBindingsIndex ]; 53362 53363 indicesByPath[ lastBindingsPath ] = index; 53364 53365 bindings[ index ] = lastBindings; 53366 bindings.pop(); 53367 53368 parsedPaths[ index ] = parsedPaths[ lastBindingsIndex ]; 53369 parsedPaths.pop(); 53370 53371 paths[ index ] = paths[ lastBindingsIndex ]; 53372 paths.pop(); 53373 53374 } 53375 53376 } 53377 53378} 53379 53380/** 53381 * An instance of `AnimationAction` schedules the playback of an animation which is 53382 * stored in {@link AnimationClip}. 53383 */ 53384class AnimationAction { 53385 53386 /** 53387 * Constructs a new animation action. 53388 * 53389 * @param {AnimationMixer} mixer - The mixer that is controlled by this action. 53390 * @param {AnimationClip} clip - The animation clip that holds the actual keyframes. 53391 * @param {?Object3D} [localRoot=null] - The root object on which this action is performed. 53392 * @param {(NormalAnimationBlendMode|AdditiveAnimationBlendMode)} [blendMode] - The blend mode. 53393 */ 53394 constructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) { 53395 53396 this._mixer = mixer; 53397 this._clip = clip; 53398 this._localRoot = localRoot; 53399 53400 /** 53401 * Defines how the animation is blended/combined when two or more animations 53402 * are simultaneously played. 53403 * 53404 * @type {(NormalAnimationBlendMode|AdditiveAnimationBlendMode)} 53405 */ 53406 this.blendMode = blendMode; 53407 53408 const tracks = clip.tracks, 53409 nTracks = tracks.length, 53410 interpolants = new Array( nTracks ); 53411 53412 const interpolantSettings = { 53413 endingStart: ZeroCurvatureEnding, 53414 endingEnd: ZeroCurvatureEnding 53415 }; 53416 53417 for ( let i = 0; i !== nTracks; ++ i ) { 53418 53419 const interpolant = tracks[ i ].createInterpolant( null ); 53420 interpolants[ i ] = interpolant; 53421 53422 // preserve interpolant settings (like tangent data from BezierInterpolant) 53423 53424 if ( interpolant.settings ) { 53425 53426 Object.assign( interpolantSettings, interpolant.settings ); 53427 53428 } 53429 53430 interpolant.settings = interpolantSettings; 53431 53432 } 53433 53434 this._interpolantSettings = interpolantSettings; 53435 53436 this._interpolants = interpolants; // bound by the mixer 53437 53438 // inside: PropertyMixer (managed by the mixer) 53439 this._propertyBindings = new Array( nTracks ); 53440 53441 this._cacheIndex = null; // for the memory manager 53442 this._byClipCacheIndex = null; // for the memory manager 53443 53444 this._timeScaleInterpolant
vendor: 6,016 bytes, lines 53444-53709
53444 = null; 53445 this._weightInterpolant = null; 53446 53447 /** 53448 * The loop mode, set via {@link AnimationAction#setLoop}. 53449 * 53450 * @type {(LoopRepeat|LoopOnce|LoopPingPong)} 53451 * @default LoopRepeat 53452 */ 53453 this.loop = LoopRepeat; 53454 this._loopCount = -1; 53455 53456 // global mixer time when the action is to be started 53457 // it's set back to 'null' upon start of the action 53458 this._startTime = null; 53459 53460 /** 53461 * The local time of this action (in seconds, starting with `0`). 53462 * 53463 * The value gets clamped or wrapped to `[0,clip.duration]` (according to the 53464 * loop state). 53465 * 53466 * @type {number} 53467 * @default Infinity 53468 */ 53469 this.time = 0; 53470 53471 /** 53472 * Scaling factor for the {@link AnimationAction#time}. A value of `0` causes the 53473 * animation to pause. Negative values cause the animation to play backwards. 53474 * 53475 * @type {number} 53476 * @default 1 53477 */ 53478 this.timeScale = 1; 53479 this._effectiveTimeScale = 1; 53480 53481 /** 53482 * The degree of influence of this action (in the interval `[0, 1]`). Values 53483 * between `0` (no impact) and `1` (full impact) can be used to blend between 53484 * several actions. 53485 * 53486 * @type {number} 53487 * @default 1 53488 */ 53489 this.weight = 1; 53490 this._effectiveWeight = 1; 53491 53492 /** 53493 * The number of repetitions of the performed clip over the course of this action. 53494 * Can be set via {@link AnimationAction#setLoop}. 53495 * 53496 * Setting this number has no effect if {@link AnimationAction#loop} is set to 53497 * `THREE:LoopOnce`. 53498 * 53499 * @type {number} 53500 * @default Infinity 53501 */ 53502 this.repetitions = Infinity; 53503 53504 /** 53505 * If set to `true`, the playback of the action is paused. 53506 * 53507 * @type {boolean} 53508 * @default false 53509 */ 53510 this.paused = false; 53511 53512 /** 53513 * If set to `false`, the action is disabled so it has no impact. 53514 * 53515 * When the action is re-enabled, the animation continues from its current 53516 * time (setting `enabled` to `false` doesn't reset the action). 53517 * 53518 * @type {boolean} 53519 * @default true 53520 */ 53521 this.enabled = true; 53522 53523 /** 53524 * If set to true the animation will automatically be paused on its last frame. 53525 * 53526 * If set to false, {@link AnimationAction#enabled} will automatically be switched 53527 * to `false` when the last loop of the action has finished, so that this action has 53528 * no further impact. 53529 * 53530 * Note: This member has no impact if the action is interrupted (it 53531 * has only an effect if its last loop has really finished). 53532 * 53533 * @type {boolean} 53534 * @default false 53535 */ 53536 this.clampWhenFinished = false; 53537 53538 /** 53539 * Enables smooth interpolation without separate clips for start, loop and end. 53540 * 53541 * @type {boolean} 53542 * @default true 53543 */ 53544 this.zeroSlopeAtStart = true; 53545 53546 /** 53547 * Enables smooth interpolation without separate clips for start, loop and end. 53548 * 53549 * @type {boolean} 53550 * @default true 53551 */ 53552 this.zeroSlopeAtEnd = true; 53553 53554 } 53555 53556 /** 53557 * Starts the playback of the animation. 53558 * 53559 * @return {AnimationAction} A reference to this animation action. 53560 */ 53561 play() { 53562 53563 this._mixer._activateAction( this ); 53564 53565 return this; 53566 53567 } 53568 53569 /** 53570 * Stops the playback of the animation. 53571 * 53572 * @return {AnimationAction} A reference to this animation action. 53573 */ 53574 stop() { 53575 53576 this._mixer._deactivateAction( this ); 53577 53578 return this.reset(); 53579 53580 } 53581 53582 /** 53583 * Resets the playback of the animation. 53584 * 53585 * @return {AnimationAction} A reference to this animation action. 53586 */ 53587 reset() { 53588 53589 this.paused = false; 53590 this.enabled = true; 53591 53592 this.time = 0; // restart clip 53593 this._loopCount = -1;// forget previous loops 53594 this._startTime = null;// forget scheduling 53595 53596 return this.stopFading().stopWarping(); 53597 53598 } 53599 53600 /** 53601 * Returns `true` if the animation is running. 53602 * 53603 * @return {boolean} Whether the animation is running or not. 53604 */ 53605 isRunning() { 53606 53607 return this.enabled && ! this.paused && this.timeScale !== 0 && 53608 this._startTime === null && this._mixer._isActiveAction( this ); 53609 53610 } 53611 53612 /** 53613 * Returns `true` when {@link AnimationAction#play} has been called. 53614 * 53615 * @return {boolean} Whether the animation is scheduled or not. 53616 */ 53617 isScheduled() { 53618 53619 return this._mixer._isActiveAction( this ); 53620 53621 } 53622 53623 /** 53624 * Defines the time when the animation should start. 53625 * 53626 * @param {number} time - The start time in seconds. 53627 * @return {AnimationAction} A reference to this animation action. 53628 */ 53629 startAt( time ) { 53630 53631 this._startTime = time; 53632 53633 return this; 53634 53635 } 53636 53637 /** 53638 * Configures the loop settings for this action. 53639 * 53640 * @param {(LoopRepeat|LoopOnce|LoopPingPong)} mode - The loop mode. 53641 * @param {number} repetitions - The number of repetitions. 53642 * @return {AnimationAction} A reference to this animation action. 53643 */ 53644 setLoop( mode, repetitions ) { 53645 53646 this.loop = mode; 53647 this.repetitions = repetitions; 53648 53649 return this; 53650 53651 } 53652 53653 /** 53654 * Sets the effective weight of this action. 53655 * 53656 * An action has no effect and thus an effective weight of zero when the 53657 * action is disabled. 53658 * 53659 * @param {number} weight - The weight to set. 53660 * @return {AnimationAction} A reference to this animation action. 53661 */ 53662 setEffectiveWeight( weight ) { 53663 53664 this.weight = weight; 53665 53666 // note: same logic as when updated at runtime 53667 this._effectiveWeight = this.enabled ? weight : 0; 53668 53669 return this.stopFading(); 53670 53671 } 53672 53673 /** 53674 * Returns the effective weight of this action. 53675 * 53676 * @return {number} The effective weight. 53677 */ 53678 getEffectiveWeight() { 53679 53680 return this._effectiveWeight; 53681 53682 } 53683 53684 /** 53685 * Fades the animation in by increasing its weight gradually from `0` to `1`, 53686 * within the passed time interval. 53687 * 53688 * @param {number} duration - The duration of the fade. 53689 * @return {AnimationAction} A reference to this animation action. 53690 */ 53691 fadeIn( duration ) { 53692 53693 return this._scheduleFading( duration, 0, 1 ); 53694 53695 } 53696 53697 /** 53698 * Fades the animation out by decreasing its weight gradually from `1` to `0`, 53699 * within the passed time interval. 53700 * 53701 * @param {number} duration - The duration of the fade. 53702 * @return {AnimationAction} A reference to this animation action. 53703 */ 53704 fadeOut( duration ) { 53705 53706 return this._scheduleFading( duration, 1, 0 ); 53707 53708 } 53709
vendor: 10,343 bytes, lines 53710-54236
53710 /** 53711 * Causes this action to fade in and the given action to fade out, 53712 * within the passed time interval. 53713 * 53714 * @param {AnimationAction} fadeOutAction - The animation action to fade out. 53715 * @param {number} duration - The duration of the fade. 53716 * @param {boolean} [warp=false] - Whether warping should be used or not. 53717 * @return {AnimationAction} A reference to this animation action. 53718 */ 53719 crossFadeFrom( fadeOutAction, duration, warp = false ) { 53720 53721 fadeOutAction.fadeOut( duration ); 53722 this.fadeIn( duration ); 53723 53724 if ( warp === true ) { 53725 53726 const fadeInDuration = this._clip.duration, 53727 fadeOutDuration = fadeOutAction._clip.duration, 53728 53729 startEndRatio = fadeOutDuration / fadeInDuration, 53730 endStartRatio = fadeInDuration / fadeOutDuration; 53731 53732 fadeOutAction.warp( 1.0, startEndRatio, duration ); 53733 this.warp( endStartRatio, 1.0, duration ); 53734 53735 } 53736 53737 return this; 53738 53739 } 53740 53741 /** 53742 * Causes this action to fade out and the given action to fade in, 53743 * within the passed time interval. 53744 * 53745 * @param {AnimationAction} fadeInAction - The animation action to fade in. 53746 * @param {number} duration - The duration of the fade. 53747 * @param {boolean} [warp=false] - Whether warping should be used or not. 53748 * @return {AnimationAction} A reference to this animation action. 53749 */ 53750 crossFadeTo( fadeInAction, duration, warp = false ) { 53751 53752 return fadeInAction.crossFadeFrom( this, duration, warp ); 53753 53754 } 53755 53756 /** 53757 * Stops any fading which is applied to this action. 53758 * 53759 * @return {AnimationAction} A reference to this animation action. 53760 */ 53761 stopFading() { 53762 53763 const weightInterpolant = this._weightInterpolant; 53764 53765 if ( weightInterpolant !== null ) { 53766 53767 this._weightInterpolant = null; 53768 this._mixer._takeBackControlInterpolant( weightInterpolant ); 53769 53770 } 53771 53772 return this; 53773 53774 } 53775 53776 /** 53777 * Sets the effective time scale of this action. 53778 * 53779 * An action has no effect and thus an effective time scale of zero when the 53780 * action is paused. 53781 * 53782 * @param {number} timeScale - The time scale to set. 53783 * @return {AnimationAction} A reference to this animation action. 53784 */ 53785 setEffectiveTimeScale( timeScale ) { 53786 53787 this.timeScale = timeScale; 53788 this._effectiveTimeScale = this.paused ? 0 : timeScale; 53789 53790 return this.stopWarping(); 53791 53792 } 53793 53794 /** 53795 * Returns the effective time scale of this action. 53796 * 53797 * @return {number} The effective time scale. 53798 */ 53799 getEffectiveTimeScale() { 53800 53801 return this._effectiveTimeScale; 53802 53803 } 53804 53805 /** 53806 * Sets the duration for a single loop of this action. 53807 * 53808 * @param {number} duration - The duration to set. 53809 * @return {AnimationAction} A reference to this animation action. 53810 */ 53811 setDuration( duration ) { 53812 53813 this.timeScale = this._clip.duration / duration; 53814 53815 return this.stopWarping(); 53816 53817 } 53818 53819 /** 53820 * Synchronizes this action with the passed other action. 53821 * 53822 * @param {AnimationAction} action - The action to sync with. 53823 * @return {AnimationAction} A reference to this animation action. 53824 */ 53825 syncWith( action ) { 53826 53827 this.time = action.time; 53828 this.timeScale = action.timeScale; 53829 53830 return this.stopWarping(); 53831 53832 } 53833 53834 /** 53835 * Decelerates this animation's speed to `0` within the passed time interval. 53836 * 53837 * @param {number} duration - The duration. 53838 * @return {AnimationAction} A reference to this animation action. 53839 */ 53840 halt( duration ) { 53841 53842 return this.warp( this._effectiveTimeScale, 0, duration ); 53843 53844 } 53845 53846 /** 53847 * Changes the playback speed, within the passed time interval, by modifying 53848 * {@link AnimationAction#timeScale} gradually from `startTimeScale` to 53849 * `endTimeScale`. 53850 * 53851 * @param {number} startTimeScale - The start time scale. 53852 * @param {number} endTimeScale - The end time scale. 53853 * @param {number} duration - The duration. 53854 * @return {AnimationAction} A reference to this animation action. 53855 */ 53856 warp( startTimeScale, endTimeScale, duration ) { 53857 53858 const mixer = this._mixer, 53859 now = mixer.time, 53860 timeScale = this.timeScale; 53861 53862 let interpolant = this._timeScaleInterpolant; 53863 53864 if ( interpolant === null ) { 53865 53866 interpolant = mixer._lendControlInterpolant(); 53867 this._timeScaleInterpolant = interpolant; 53868 53869 } 53870 53871 const times = interpolant.parameterPositions, 53872 values = interpolant.sampleValues; 53873 53874 times[ 0 ] = now; 53875 times[ 1 ] = now + duration; 53876 53877 values[ 0 ] = startTimeScale / timeScale; 53878 values[ 1 ] = endTimeScale / timeScale; 53879 53880 return this; 53881 53882 } 53883 53884 /** 53885 * Stops any scheduled warping which is applied to this action. 53886 * 53887 * @return {AnimationAction} A reference to this animation action. 53888 */ 53889 stopWarping() { 53890 53891 const timeScaleInterpolant = this._timeScaleInterpolant; 53892 53893 if ( timeScaleInterpolant !== null ) { 53894 53895 this._timeScaleInterpolant = null; 53896 this._mixer._takeBackControlInterpolant( timeScaleInterpolant ); 53897 53898 } 53899 53900 return this; 53901 53902 } 53903 53904 /** 53905 * Returns the animation mixer of this animation action. 53906 * 53907 * @return {AnimationMixer} The animation mixer. 53908 */ 53909 getMixer() { 53910 53911 return this._mixer; 53912 53913 } 53914 53915 /** 53916 * Returns the animation clip of this animation action. 53917 * 53918 * @return {AnimationClip} The animation clip. 53919 */ 53920 getClip() { 53921 53922 return this._clip; 53923 53924 } 53925 53926 /** 53927 * Returns the root object of this animation action. 53928 * 53929 * @return {Object3D} The root object. 53930 */ 53931 getRoot() { 53932 53933 return this._localRoot || this._mixer._root; 53934 53935 } 53936 53937 // Internal 53938 53939 _update( time, deltaTime, timeDirection, accuIndex ) { 53940 53941 // called by the mixer 53942 53943 if ( ! this.enabled ) { 53944 53945 // call ._updateWeight() to update ._effectiveWeight 53946 53947 this._updateWeight( time ); 53948 return; 53949 53950 } 53951 53952 const startTime = this._startTime; 53953 53954 if ( startTime !== null ) { 53955 53956 // check for scheduled start of action 53957 53958 const timeRunning = ( time - startTime ) * timeDirection; 53959 if ( timeRunning < 0 || timeDirection === 0 ) { 53960 53961 deltaTime = 0; 53962 53963 } else { 53964 53965 53966 this._startTime = null; // unschedule 53967 deltaTime = timeDirection * timeRunning; 53968 53969 } 53970 53971 } 53972 53973 // apply time scale and advance time 53974 53975 deltaTime *= this._updateTimeScale( time ); 53976 const clipTime = this._updateTime( deltaTime ); 53977 53978 // note: _updateTime may disable the action resulting in 53979 // an effective weight of 0 53980 53981 const weight = this._updateWeight( time ); 53982 53983 if ( weight > 0 ) { 53984 53985 const interpolants = this._interpolants; 53986 const propertyMixers = this._propertyBindings; 53987 53988 switch ( this.blendMode ) { 53989 53990 case AdditiveAnimationBlendMode: 53991 53992 for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { 53993 53994 interpolants[ j ].evaluate( clipTime ); 53995 propertyMixers[ j ].accumulateAdditive( weight ); 53996 53997 } 53998 53999 break; 54000 54001 case NormalAnimationBlendMode: 54002 default: 54003 54004 for ( let j = 0, m = interpolants.length; j !== m; ++ j ) { 54005 54006 interpolants[ j ].evaluate( clipTime ); 54007 propertyMixers[ j ].accumulate( accuIndex, weight ); 54008 54009 } 54010 54011 } 54012 54013 } 54014 54015 } 54016 54017 _updateWeight( time ) { 54018 54019 let weight = 0; 54020 54021 if ( this.enabled ) { 54022 54023 weight = this.weight; 54024 const interpolant = this._weightInterpolant; 54025 54026 if ( interpolant !== null ) { 54027 54028 const interpolantValue = interpolant.evaluate( time )[ 0 ]; 54029 54030 weight *= interpolantValue; 54031 54032 if ( time > interpolant.parameterPositions[ 1 ] ) { 54033 54034 this.stopFading(); 54035 54036 if ( interpolantValue === 0 ) { 54037 54038 // faded out, disable 54039 this.enabled = false; 54040 54041 } 54042 54043 } 54044 54045 } 54046 54047 } 54048 54049 this._effectiveWeight = weight; 54050 return weight; 54051 54052 } 54053 54054 _updateTimeScale( time ) { 54055 54056 let timeScale = 0; 54057 54058 if ( ! this.paused ) { 54059 54060 timeScale = this.timeScale; 54061 54062 const interpolant = this._timeScaleInterpolant; 54063 54064 if ( interpolant !== null ) { 54065 54066 const interpolantValue = interpolant.evaluate( time )[ 0 ]; 54067 54068 timeScale *= interpolantValue; 54069 54070 if ( time > interpolant.parameterPositions[ 1 ] ) { 54071 54072 this.stopWarping(); 54073 54074 if ( timeScale === 0 ) { 54075 54076 // motion has halted, pause 54077 this.paused = true; 54078 54079 } else { 54080 54081 // warp done - apply final time scale 54082 this.timeScale = timeScale; 54083 54084 } 54085 54086 } 54087 54088 } 54089 54090 } 54091 54092 this._effectiveTimeScale = timeScale; 54093 return timeScale; 54094 54095 } 54096 54097 _updateTime( deltaTime ) { 54098 54099 const duration = this._clip.duration; 54100 const loop = this.loop; 54101 54102 let time = this.time + deltaTime; 54103 let loopCount = this._loopCount; 54104 54105 const pingPong = ( loop === LoopPingPong ); 54106 54107 if ( deltaTime === 0 ) { 54108 54109 if ( loopCount === -1 ) return time; 54110 54111 return ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time; 54112 54113 } 54114 54115 if ( loop === LoopOnce ) { 54116 54117 if ( loopCount === -1 ) { 54118 54119 // just started 54120 54121 this._loopCount = 0; 54122 this._setEndings( true, true, false ); 54123 54124 } 54125 54126 handle_stop: { 54127 54128 if ( time >= duration ) { 54129 54130 time = duration; 54131 54132 } else if ( time < 0 ) { 54133 54134 time = 0; 54135 54136 } else { 54137 54138 this.time = time; 54139 54140 break handle_stop; 54141 54142 } 54143 54144 if ( this.clampWhenFinished ) this.paused = true; 54145 else this.enabled = false; 54146 54147 this.time = time; 54148 54149 this._mixer.dispatchEvent( { 54150 type: 'finished', action: this, 54151 direction: deltaTime < 0 ? -1 : 1 54152 } ); 54153 54154 } 54155 54156 } else { // repetitive Repeat or PingPong 54157 54158 if ( loopCount === -1 ) { 54159 54160 // just started 54161 54162 if ( deltaTime >= 0 ) { 54163 54164 loopCount = 0; 54165 54166 this._setEndings( true, this.repetitions === 0, pingPong ); 54167 54168 } else { 54169 54170 // when looping in reverse direction, the initial 54171 // transition through zero counts as a repetition, 54172 // so leave loopCount at -1 54173 54174 this._setEndings( this.repetitions === 0, true, pingPong ); 54175 54176 } 54177 54178 } 54179 54180 if ( time >= duration || time < 0 ) { 54181 54182 // wrap around 54183 54184 const loopDelta = Math.floor( time / duration ); // signed 54185 time -= duration * loopDelta; 54186 54187 loopCount += Math.abs( loopDelta ); 54188 54189 const pending = this.repetitions - loopCount; 54190 54191 if ( pending <= 0 ) { 54192 54193 // have to stop (switch state, clamp time, fire event) 54194 54195 if ( this.clampWhenFinished ) this.paused = true; 54196 else this.enabled = false; 54197 54198 time = deltaTime > 0 ? duration : 0; 54199 54200 this.time = time; 54201 54202 this._mixer.dispatchEvent( { 54203 type: 'finished', action: this, 54204 direction: deltaTime > 0 ? 1 : -1 54205 } ); 54206 54207 } else { 54208 54209 // keep running 54210 54211 if ( pending === 1 ) { 54212 54213 // entering the last round 54214 54215 const atStart = deltaTime < 0; 54216 this._setEndings( atStart, ! atStart, pingPong ); 54217 54218 } else { 54219 54220 this._setEndings( false, false, pingPong ); 54221 54222 } 54223 54224 this._loopCount = loopCount; 54225 54226 this.time = time; 54227 54228 this._mixer.dispatchEvent( { 54229 type: 'loop', action: this, loopDelta: loopDelta 54230 } ); 54231 54232 } 54233 54234 } else { 54235 54236 this.
vendor: 21,210 bytes, lines 54236-55199
54236_loopCount = loopCount; 54237 this.time = time; 54238 54239 } 54240 54241 if ( pingPong && ( loopCount & 1 ) === 1 ) { 54242 54243 // invert time for the "pong round" 54244 54245 return duration - time; 54246 54247 } 54248 54249 } 54250 54251 return time; 54252 54253 } 54254 54255 _setEndings( atStart, atEnd, pingPong ) { 54256 54257 const settings = this._interpolantSettings; 54258 54259 if ( pingPong ) { 54260 54261 settings.endingStart = ZeroSlopeEnding; 54262 settings.endingEnd = ZeroSlopeEnding; 54263 54264 } else { 54265 54266 // assuming for LoopOnce atStart == atEnd == true 54267 54268 if ( atStart ) { 54269 54270 settings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding; 54271 54272 } else { 54273 54274 settings.endingStart = WrapAroundEnding; 54275 54276 } 54277 54278 if ( atEnd ) { 54279 54280 settings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding; 54281 54282 } else { 54283 54284 settings.endingEnd = WrapAroundEnding; 54285 54286 } 54287 54288 } 54289 54290 } 54291 54292 _scheduleFading( duration, weightNow, weightThen ) { 54293 54294 const mixer = this._mixer, now = mixer.time; 54295 let interpolant = this._weightInterpolant; 54296 54297 if ( interpolant === null ) { 54298 54299 interpolant = mixer._lendControlInterpolant(); 54300 this._weightInterpolant = interpolant; 54301 54302 } 54303 54304 const times = interpolant.parameterPositions, 54305 values = interpolant.sampleValues; 54306 54307 times[ 0 ] = now; 54308 values[ 0 ] = weightNow; 54309 times[ 1 ] = now + duration; 54310 values[ 1 ] = weightThen; 54311 54312 return this; 54313 54314 } 54315 54316} 54317 54318const _controlInterpolantsResultBuffer = new Float32Array( 1 ); 54319 54320/** 54321 * `AnimationMixer` is a player for animations on a particular object in 54322 * the scene. When multiple objects in the scene are animated independently, 54323 * one `AnimationMixer` may be used for each object. 54324 */ 54325class AnimationMixer extends EventDispatcher { 54326 54327 /** 54328 * Constructs a new animation mixer. 54329 * 54330 * @param {Object3D} root - The object whose animations shall be played by this mixer. 54331 */ 54332 constructor( root ) { 54333 54334 super(); 54335 54336 this._root = root; 54337 this._initMemoryManager(); 54338 this._accuIndex = 0; 54339 54340 /** 54341 * The global mixer time (in seconds; starting with `0` on the mixer's creation). 54342 * 54343 * @type {number} 54344 * @default 0 54345 */ 54346 this.time = 0; 54347 54348 /** 54349 * A scaling factor for the global time. 54350 * 54351 * Note: Setting this member to `0` and later back to `1` is a 54352 * possibility to pause/unpause all actions that are controlled by this 54353 * mixer. 54354 * 54355 * @type {number} 54356 * @default 1 54357 */ 54358 this.timeScale = 1.0; 54359 54360 if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { 54361 54362 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); 54363 54364 } 54365 54366 } 54367 54368 _bindAction( action, prototypeAction ) { 54369 54370 const root = action._localRoot || this._root, 54371 tracks = action._clip.tracks, 54372 nTracks = tracks.length, 54373 bindings = action._propertyBindings, 54374 interpolants = action._interpolants, 54375 rootUuid = root.uuid, 54376 bindingsByRoot = this._bindingsByRootAndName; 54377 54378 let bindingsByName = bindingsByRoot[ rootUuid ]; 54379 54380 if ( bindingsByName === undefined ) { 54381 54382 bindingsByName = {}; 54383 bindingsByRoot[ rootUuid ] = bindingsByName; 54384 54385 } 54386 54387 for ( let i = 0; i !== nTracks; ++ i ) { 54388 54389 const track = tracks[ i ], 54390 trackName = track.name; 54391 54392 let binding = bindingsByName[ trackName ]; 54393 54394 if ( binding !== undefined ) { 54395 54396 ++ binding.referenceCount; 54397 bindings[ i ] = binding; 54398 54399 } else { 54400 54401 binding = bindings[ i ]; 54402 54403 if ( binding !== undefined ) { 54404 54405 // existing binding, make sure the cache knows 54406 54407 if ( binding._cacheIndex === null ) { 54408 54409 ++ binding.referenceCount; 54410 this._addInactiveBinding( binding, rootUuid, trackName ); 54411 54412 } 54413 54414 continue; 54415 54416 } 54417 54418 const path = prototypeAction && prototypeAction. 54419 _propertyBindings[ i ].binding.parsedPath; 54420 54421 binding = new PropertyMixer( 54422 PropertyBinding.create( root, trackName, path ), 54423 track.ValueTypeName, track.getValueSize() ); 54424 54425 ++ binding.referenceCount; 54426 this._addInactiveBinding( binding, rootUuid, trackName ); 54427 54428 bindings[ i ] = binding; 54429 54430 } 54431 54432 interpolants[ i ].resultBuffer = binding.buffer; 54433 54434 } 54435 54436 } 54437 54438 _activateAction( action ) { 54439 54440 if ( ! this._isActiveAction( action ) ) { 54441 54442 if ( action._cacheIndex === null ) { 54443 54444 // this action has been forgotten by the cache, but the user 54445 // appears to be still using it -> rebind 54446 54447 const rootUuid = ( action._localRoot || this._root ).uuid, 54448 clipUuid = action._clip.uuid, 54449 actionsForClip = this._actionsByClip[ clipUuid ]; 54450 54451 this._bindAction( action, 54452 actionsForClip && actionsForClip.knownActions[ 0 ] ); 54453 54454 this._addInactiveAction( action, clipUuid, rootUuid ); 54455 54456 } 54457 54458 const bindings = action._propertyBindings; 54459 54460 // increment reference counts / sort out state 54461 for ( let i = 0, n = bindings.length; i !== n; ++ i ) { 54462 54463 const binding = bindings[ i ]; 54464 54465 if ( binding.useCount ++ === 0 ) { 54466 54467 this._lendBinding( binding ); 54468 binding.saveOriginalState(); 54469 54470 } 54471 54472 } 54473 54474 this._lendAction( action ); 54475 54476 } 54477 54478 } 54479 54480 _deactivateAction( action ) { 54481 54482 if ( this._isActiveAction( action ) ) { 54483 54484 const bindings = action._propertyBindings; 54485 54486 // decrement reference counts / sort out state 54487 for ( let i = 0, n = bindings.length; i !== n; ++ i ) { 54488 54489 const binding = bindings[ i ]; 54490 54491 if ( -- binding.useCount === 0 ) { 54492 54493 binding.restoreOriginalState(); 54494 this._takeBackBinding( binding ); 54495 54496 } 54497 54498 } 54499 54500 this._takeBackAction( action ); 54501 54502 } 54503 54504 } 54505 54506 // Memory manager 54507 54508 _initMemoryManager() { 54509 54510 this._actions = []; // 'nActiveActions' followed by inactive ones 54511 this._nActiveActions = 0; 54512 54513 this._actionsByClip = {}; 54514 // inside: 54515 // { 54516 // knownActions: Array< AnimationAction > - used as prototypes 54517 // actionByRoot: AnimationAction - lookup 54518 // } 54519 54520 54521 this._bindings = []; // 'nActiveBindings' followed by inactive ones 54522 this._nActiveBindings = 0; 54523 54524 this._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer > 54525 54526 54527 this._controlInterpolants = []; // same game as above 54528 this._nActiveControlInterpolants = 0; 54529 54530 const scope = this; 54531 54532 this.stats = { 54533 54534 actions: { 54535 get total() { 54536 54537 return scope._actions.length; 54538 54539 }, 54540 get inUse() { 54541 54542 return scope._nActiveActions; 54543 54544 } 54545 }, 54546 bindings: { 54547 get total() { 54548 54549 return scope._bindings.length; 54550 54551 }, 54552 get inUse() { 54553 54554 return scope._nActiveBindings; 54555 54556 } 54557 }, 54558 controlInterpolants: { 54559 get total() { 54560 54561 return scope._controlInterpolants.length; 54562 54563 }, 54564 get inUse() { 54565 54566 return scope._nActiveControlInterpolants; 54567 54568 } 54569 } 54570 54571 }; 54572 54573 } 54574 54575 // Memory management for AnimationAction objects 54576 54577 _isActiveAction( action ) { 54578 54579 const index = action._cacheIndex; 54580 return index !== null && index < this._nActiveActions; 54581 54582 } 54583 54584 _addInactiveAction( action, clipUuid, rootUuid ) { 54585 54586 const actions = this._actions, 54587 actionsByClip = this._actionsByClip; 54588 54589 let actionsForClip = actionsByClip[ clipUuid ]; 54590 54591 if ( actionsForClip === undefined ) { 54592 54593 actionsForClip = { 54594 54595 knownActions: [ action ], 54596 actionByRoot: {} 54597 54598 }; 54599 54600 action._byClipCacheIndex = 0; 54601 54602 actionsByClip[ clipUuid ] = actionsForClip; 54603 54604 } else { 54605 54606 const knownActions = actionsForClip.knownActions; 54607 54608 action._byClipCacheIndex = knownActions.length; 54609 knownActions.push( action ); 54610 54611 } 54612 54613 action._cacheIndex = actions.length; 54614 actions.push( action ); 54615 54616 actionsForClip.actionByRoot[ rootUuid ] = action; 54617 54618 } 54619 54620 _removeInactiveAction( action ) { 54621 54622 const actions = this._actions, 54623 lastInactiveAction = actions[ actions.length - 1 ], 54624 cacheIndex = action._cacheIndex; 54625 54626 lastInactiveAction._cacheIndex = cacheIndex; 54627 actions[ cacheIndex ] = lastInactiveAction; 54628 actions.pop(); 54629 54630 action._cacheIndex = null; 54631 54632 54633 const clipUuid = action._clip.uuid, 54634 actionsByClip = this._actionsByClip, 54635 actionsForClip = actionsByClip[ clipUuid ], 54636 knownActionsForClip = actionsForClip.knownActions, 54637 54638 lastKnownAction = 54639 knownActionsForClip[ knownActionsForClip.length - 1 ], 54640 54641 byClipCacheIndex = action._byClipCacheIndex; 54642 54643 lastKnownAction._byClipCacheIndex = byClipCacheIndex; 54644 knownActionsForClip[ byClipCacheIndex ] = lastKnownAction; 54645 knownActionsForClip.pop(); 54646 54647 action._byClipCacheIndex = null; 54648 54649 54650 const actionByRoot = actionsForClip.actionByRoot, 54651 rootUuid = ( action._localRoot || this._root ).uuid; 54652 54653 delete actionByRoot[ rootUuid ]; 54654 54655 if ( knownActionsForClip.length === 0 ) { 54656 54657 delete actionsByClip[ clipUuid ]; 54658 54659 } 54660 54661 this._removeInactiveBindingsForAction( action ); 54662 54663 } 54664 54665 _removeInactiveBindingsForAction( action ) { 54666 54667 const bindings = action._propertyBindings; 54668 54669 for ( let i = 0, n = bindings.length; i !== n; ++ i ) { 54670 54671 const binding = bindings[ i ]; 54672 54673 if ( -- binding.referenceCount === 0 ) { 54674 54675 this._removeInactiveBinding( binding ); 54676 54677 } 54678 54679 } 54680 54681 } 54682 54683 _lendAction( action ) { 54684 54685 // [ active actions | inactive actions ] 54686 // [ active actions >| inactive actions ] 54687 // s a 54688 // <-swap-> 54689 // a s 54690 54691 const actions = this._actions, 54692 prevIndex = action._cacheIndex, 54693 54694 lastActiveIndex = this._nActiveActions ++, 54695 54696 firstInactiveAction = actions[ lastActiveIndex ]; 54697 54698 action._cacheIndex = lastActiveIndex; 54699 actions[ lastActiveIndex ] = action; 54700 54701 firstInactiveAction._cacheIndex = prevIndex; 54702 actions[ prevIndex ] = firstInactiveAction; 54703 54704 } 54705 54706 _takeBackAction( action ) { 54707 54708 // [ active actions | inactive actions ] 54709 // [ active actions |< inactive actions ] 54710 // a s 54711 // <-swap-> 54712 // s a 54713 54714 const actions = this._actions, 54715 prevIndex = action._cacheIndex, 54716 54717 firstInactiveIndex = -- this._nActiveActions, 54718 54719 lastActiveAction = actions[ firstInactiveIndex ]; 54720 54721 action._cacheIndex = firstInactiveIndex; 54722 actions[ firstInactiveIndex ] = action; 54723 54724 lastActiveAction._cacheIndex = prevIndex; 54725 actions[ prevIndex ] = lastActiveAction; 54726 54727 } 54728 54729 // Memory management for PropertyMixer objects 54730 54731 _addInactiveBinding( binding, rootUuid, trackName ) { 54732 54733 const bindingsByRoot = this._bindingsByRootAndName, 54734 bindings = this._bindings; 54735 54736 let bindingByName = bindingsByRoot[ rootUuid ]; 54737 54738 if ( bindingByName === undefined ) { 54739 54740 bindingByName = {}; 54741 bindingsByRoot[ rootUuid ] = bindingByName; 54742 54743 } 54744 54745 bindingByName[ trackName ] = binding; 54746 54747 binding._cacheIndex = bindings.length; 54748 bindings.push( binding ); 54749 54750 } 54751 54752 _removeInactiveBinding( binding ) { 54753 54754 const bindings = this._bindings, 54755 propBinding = binding.binding, 54756 rootUuid = propBinding.rootNode.uuid, 54757 trackName = propBinding.path, 54758 bindingsByRoot = this._bindingsByRootAndName, 54759 bindingByName = bindingsByRoot[ rootUuid ], 54760 54761 lastInactiveBinding = bindings[ bindings.length - 1 ], 54762 cacheIndex = binding._cacheIndex; 54763 54764 lastInactiveBinding._cacheIndex = cacheIndex; 54765 bindings[ cacheIndex ] = lastInactiveBinding; 54766 bindings.pop(); 54767 54768 delete bindingByName[ trackName ]; 54769 54770 if ( Object.keys( bindingByName ).length === 0 ) { 54771 54772 delete bindingsByRoot[ rootUuid ]; 54773 54774 } 54775 54776 } 54777 54778 _lendBinding( binding ) { 54779 54780 const bindings = this._bindings, 54781 prevIndex = binding._cacheIndex, 54782 54783 lastActiveIndex = this._nActiveBindings ++, 54784 54785 firstInactiveBinding = bindings[ lastActiveIndex ]; 54786 54787 binding._cacheIndex = lastActiveIndex; 54788 bindings[ lastActiveIndex ] = binding; 54789 54790 firstInactiveBinding._cacheIndex = prevIndex; 54791 bindings[ prevIndex ] = firstInactiveBinding; 54792 54793 } 54794 54795 _takeBackBinding( binding ) { 54796 54797 const bindings = this._bindings, 54798 prevIndex = binding._cacheIndex, 54799 54800 firstInactiveIndex = -- this._nActiveBindings, 54801 54802 lastActiveBinding = bindings[ firstInactiveIndex ]; 54803 54804 binding._cacheIndex = firstInactiveIndex; 54805 bindings[ firstInactiveIndex ] = binding; 54806 54807 lastActiveBinding._cacheIndex = prevIndex; 54808 bindings[ prevIndex ] = lastActiveBinding; 54809 54810 } 54811 54812 54813 // Memory management of Interpolants for weight and time scale 54814 54815 _lendControlInterpolant() { 54816 54817 const interpolants = this._controlInterpolants, 54818 lastActiveIndex = this._nActiveControlInterpolants ++; 54819 54820 let interpolant = interpolants[ lastActiveIndex ]; 54821 54822 if ( interpolant === undefined ) { 54823 54824 interpolant = new LinearInterpolant( 54825 new Float32Array( 2 ), new Float32Array( 2 ), 54826 1, _controlInterpolantsResultBuffer ); 54827 54828 interpolant.__cacheIndex = lastActiveIndex; 54829 interpolants[ lastActiveIndex ] = interpolant; 54830 54831 } 54832 54833 return interpolant; 54834 54835 } 54836 54837 _takeBackControlInterpolant( interpolant ) { 54838 54839 const interpolants = this._controlInterpolants, 54840 prevIndex = interpolant.__cacheIndex, 54841 54842 firstInactiveIndex = -- this._nActiveControlInterpolants, 54843 54844 lastActiveInterpolant = interpolants[ firstInactiveIndex ]; 54845 54846 interpolant.__cacheIndex = firstInactiveIndex; 54847 interpolants[ firstInactiveIndex ] = interpolant; 54848 54849 lastActiveInterpolant.__cacheIndex = prevIndex; 54850 interpolants[ prevIndex ] = lastActiveInterpolant; 54851 54852 } 54853 54854 /** 54855 * Returns an instance of {@link AnimationAction} for the passed clip. 54856 * 54857 * If an action fitting the clip and root parameters doesn't yet exist, it 54858 * will be created by this method. Calling this method several times with the 54859 * same clip and root parameters always returns the same action. 54860 * 54861 * @param {AnimationClip|string} clip - An animation clip or alternatively the name of the animation clip. 54862 * @param {Object3D} [optionalRoot] - An alternative root object. 54863 * @param {(NormalAnimationBlendMode|AdditiveAnimationBlendMode)} [blendMode] - The blend mode. 54864 * @return {?AnimationAction} The animation action. 54865 */ 54866 clipAction( clip, optionalRoot, blendMode ) { 54867 54868 const root = optionalRoot || this._root, 54869 rootUuid = root.uuid; 54870 54871 let clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip; 54872 54873 const clipUuid = clipObject !== null ? clipObject.uuid : clip; 54874 54875 const actionsForClip = this._actionsByClip[ clipUuid ]; 54876 let prototypeAction = null; 54877 54878 if ( blendMode === undefined ) { 54879 54880 if ( clipObject !== null ) { 54881 54882 blendMode = clipObject.blendMode; 54883 54884 } else { 54885 54886 blendMode = NormalAnimationBlendMode; 54887 54888 } 54889 54890 } 54891 54892 if ( actionsForClip !== undefined ) { 54893 54894 const existingAction = actionsForClip.actionByRoot[ rootUuid ]; 54895 54896 if ( existingAction !== undefined && existingAction.blendMode === blendMode ) { 54897 54898 return existingAction; 54899 54900 } 54901 54902 // we know the clip, so we don't have to parse all 54903 // the bindings again but can just copy 54904 prototypeAction = actionsForClip.knownActions[ 0 ]; 54905 54906 // also, take the clip from the prototype action 54907 if ( clipObject === null ) 54908 clipObject = prototypeAction._clip; 54909 54910 } 54911 54912 // clip must be known when specified via string 54913 if ( clipObject === null ) return null; 54914 54915 // allocate all resources required to run it 54916 const newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode ); 54917 54918 this._bindAction( newAction, prototypeAction ); 54919 54920 // and make the action known to the memory manager 54921 this._addInactiveAction( newAction, clipUuid, rootUuid ); 54922 54923 return newAction; 54924 54925 } 54926 54927 /** 54928 * Returns an existing animation action for the passed clip. 54929 * 54930 * @param {AnimationClip|string} clip - An animation clip or alternatively the name of the animation clip. 54931 * @param {Object3D} [optionalRoot] - An alternative root object. 54932 * @return {?AnimationAction} The animation action. Returns `null` if no action was found. 54933 */ 54934 existingAction( clip, optionalRoot ) { 54935 54936 const root = optionalRoot || this._root, 54937 rootUuid = root.uuid, 54938 54939 clipObject = typeof clip === 'string' ? 54940 AnimationClip.findByName( root, clip ) : clip, 54941 54942 clipUuid = clipObject ? clipObject.uuid : clip, 54943 54944 actionsForClip = this._actionsByClip[ clipUuid ]; 54945 54946 if ( actionsForClip !== undefined ) { 54947 54948 return actionsForClip.actionByRoot[ rootUuid ] || null; 54949 54950 } 54951 54952 return null; 54953 54954 } 54955 54956 /** 54957 * Deactivates all previously scheduled actions on this mixer. 54958 * 54959 * @return {AnimationMixer} A reference to this animation mixer. 54960 */ 54961 stopAllAction() { 54962 54963 const actions = this._actions, 54964 nActions = this._nActiveActions; 54965 54966 for ( let i = nActions - 1; i >= 0; -- i ) { 54967 54968 actions[ i ].stop(); 54969 54970 } 54971 54972 return this; 54973 54974 } 54975 54976 /** 54977 * Advances the global mixer time and updates the animation. 54978 * 54979 * This is usually done in the render loop by passing the delta 54980 * time from {@link Clock} or {@link Timer}. 54981 * 54982 * @param {number} deltaTime - The delta time in seconds. 54983 * @return {AnimationMixer} A reference to this animation mixer. 54984 */ 54985 update( deltaTime ) { 54986 54987 deltaTime *= this.timeScale; 54988 54989 const actions = this._actions, 54990 nActions = this._nActiveActions, 54991 54992 time = this.time += deltaTime, 54993 timeDirection = Math.sign( deltaTime ), 54994 54995 accuIndex = this._accuIndex ^= 1; 54996 54997 // run active actions 54998 54999 for ( let i = 0; i !== nActions; ++ i ) { 55000 55001 const action = actions[ i ]; 55002 55003 action._update( time, deltaTime, timeDirection, accuIndex ); 55004 55005 } 55006 55007 // update scene graph 55008 55009 const bindings = this._bindings, 55010 nBindings = this._nActiveBindings; 55011 55012 for ( let i = 0; i !== nBindings; ++ i ) { 55013 55014 bindings[ i ].apply( accuIndex ); 55015 55016 } 55017 55018 return this; 55019 55020 } 55021 55022 /** 55023 * Sets the global mixer to a specific time and updates the animation accordingly. 55024 * 55025 * This is useful when you need to jump to an exact time in an animation. The 55026 * input parameter will be scaled by {@link AnimationMixer#timeScale} 55027 * 55028 * @param {number} time - The time to set in seconds. 55029 * @return {AnimationMixer} A reference to this animation mixer. 55030 */ 55031 setTime( time ) { 55032 55033 this.time = 0; // Zero out time attribute for AnimationMixer object; 55034 for ( let i = 0; i < this._actions.length; i ++ ) { 55035 55036 this._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects. 55037 55038 } 55039 55040 return this.update( time ); // Update used to set exact time. Returns "this" AnimationMixer object. 55041 55042 } 55043 55044 /** 55045 * Returns this mixer's root object. 55046 * 55047 * @return {Object3D} The mixer's root object. 55048 */ 55049 getRoot() { 55050 55051 return this._root; 55052 55053 } 55054 55055 /** 55056 * Deallocates all memory resources for a clip. Before using this method make 55057 * sure to call {@link AnimationAction#stop} for all related actions. 55058 * 55059 * @param {AnimationClip} clip - The clip to uncache. 55060 */ 55061 uncacheClip( clip ) { 55062 55063 const actions = this._actions, 55064 clipUuid = clip.uuid, 55065 actionsByClip = this._actionsByClip, 55066 actionsForClip = actionsByClip[ clipUuid ]; 55067 55068 if ( actionsForClip !== undefined ) { 55069 55070 // note: just calling _removeInactiveAction would mess up the 55071 // iteration state and also require updating the state we can 55072 // just throw away 55073 55074 const actionsToRemove = actionsForClip.knownActions; 55075 55076 for ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) { 55077 55078 const action = actionsToRemove[ i ]; 55079 55080 this._deactivateAction( action ); 55081 55082 const cacheIndex = action._cacheIndex, 55083 lastInactiveAction = actions[ actions.length - 1 ]; 55084 55085 action._cacheIndex = null; 55086 action._byClipCacheIndex = null; 55087 55088 lastInactiveAction._cacheIndex = cacheIndex; 55089 actions[ cacheIndex ] = lastInactiveAction; 55090 actions.pop(); 55091 55092 this._removeInactiveBindingsForAction( action ); 55093 55094 } 55095 55096 delete actionsByClip[ clipUuid ]; 55097 55098 } 55099 55100 } 55101 55102 /** 55103 * Deallocates all memory resources for a root object. Before using this 55104 * method make sure to call {@link AnimationAction#stop} for all related 55105 * actions or alternatively {@link AnimationMixer#stopAllAction} when the 55106 * mixer operates on a single root. 55107 * 55108 * @param {Object3D} root - The root object to uncache. 55109 */ 55110 uncacheRoot( root ) { 55111 55112 const rootUuid = root.uuid, 55113 actionsByClip = this._actionsByClip; 55114 55115 for ( const clipUuid in actionsByClip ) { 55116 55117 const actionByRoot = actionsByClip[ clipUuid ].actionByRoot, 55118 action = actionByRoot[ rootUuid ]; 55119 55120 if ( action !== undefined ) { 55121 55122 this._deactivateAction( action ); 55123 this._removeInactiveAction( action ); 55124 55125 } 55126 55127 } 55128 55129 const bindingsByRoot = this._bindingsByRootAndName, 55130 bindingByName = bindingsByRoot[ rootUuid ]; 55131 55132 if ( bindingByName !== undefined ) { 55133 55134 for ( const trackName in bindingByName ) { 55135 55136 const binding = bindingByName[ trackName ]; 55137 binding.restoreOriginalState(); 55138 this._removeInactiveBinding( binding ); 55139 55140 } 55141 55142 } 55143 55144 } 55145 55146 /** 55147 * Deallocates all memory resources for an action. The action is identified by the 55148 * given clip and an optional root object. Before using this method make 55149 * sure to call {@link AnimationAction#stop} to deactivate the action. 55150 * 55151 * @param {AnimationClip|string} clip - An animation clip or alternatively the name of the animation clip. 55152 * @param {Object3D} [optionalRoot] - An alternative root object. 55153 */ 55154 uncacheAction( clip, optionalRoot ) { 55155 55156 const action = this.existingAction( clip, optionalRoot ); 55157 55158 if ( action !== null ) { 55159 55160 this._deactivateAction( action ); 55161 this._removeInactiveAction( action ); 55162 55163 } 55164 55165 } 55166 55167} 55168 55169/** 55170 * Represents a 3D render target. 55171 * 55172 * @augments RenderTarget 55173 */ 55174class RenderTarget3D extends RenderTarget { 55175 55176 /** 55177 * Constructs a new 3D render target. 55178 * 55179 * @param {number} [width=1] - The width of the render target. 55180 * @param {number} [height=1] - The height of the render target. 55181 * @param {number} [depth=1] - The height of the render target. 55182 * @param {RenderTarget~Options} [options] - The configuration object. 55183 */ 55184 constructor( width = 1, height = 1, depth = 1, options = {} ) { 55185 55186 super( width, height, options ); 55187 55188 /** 55189 * This flag can be used for type testing. 55190 * 55191 * @type {boolean} 55192 * @readonly 55193 * @default true 55194 */ 55195 this.isRenderTarget3D = true; 55196 55197 this.depth = depth; 55198 55199 /
55199** 55200 * Overwritten with a different texture type. 55201 * 55202 * @type {Data3DTexture} 55203 */ 55204 this.texture = new Data3DTexture( null, width, height, depth ); 55205 this._setTextureOptions( options ); 55206 55207 this.texture.isRenderTargetTexture = true
vendor: 13,226 bytes, lines 55207-55798
55207; 55208 55209 } 55210 55211} 55212 55213/** 55214 * Represents a uniform which is a global shader variable. They are passed to shader programs. 55215 * 55216 * When declaring a uniform of a {@link ShaderMaterial}, it is declared by value or by object. 55217 * ```js 55218 * uniforms: { 55219 * time: { value: 1.0 }, 55220 * resolution: new Uniform( new Vector2() ) 55221 * }; 55222 * ``` 55223 * Since this class can only be used in context of {@link ShaderMaterial}, it is only supported 55224 * in {@link WebGLRenderer}. 55225 */ 55226class Uniform { 55227 55228 /** 55229 * Constructs a new uniform. 55230 * 55231 * @param {any} value - The uniform value. 55232 */ 55233 constructor( value ) { 55234 55235 /** 55236 * The uniform value. 55237 * 55238 * @type {any} 55239 */ 55240 this.value = value; 55241 55242 } 55243 55244 /** 55245 * Returns a new uniform with copied values from this instance. 55246 * If the value has a `clone()` method, the value is cloned as well. 55247 * 55248 * @return {Uniform} A clone of this instance. 55249 */ 55250 clone() { 55251 55252 return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() ); 55253 55254 } 55255 55256} 55257 55258let _id = 0; 55259 55260/** 55261 * A class for managing multiple uniforms in a single group. The renderer will process 55262 * such a definition as a single UBO. 55263 * 55264 * Since this class can only be used in context of {@link ShaderMaterial}, it is only supported 55265 * in {@link WebGLRenderer}. 55266 * 55267 * @augments EventDispatcher 55268 */ 55269class UniformsGroup extends EventDispatcher { 55270 55271 /** 55272 * Constructs a new uniforms group. 55273 */ 55274 constructor() { 55275 55276 super(); 55277 55278 /** 55279 * This flag can be used for type testing. 55280 * 55281 * @type {boolean} 55282 * @readonly 55283 * @default true 55284 */ 55285 this.isUniformsGroup = true; 55286 55287 /** 55288 * The ID of the 3D object. 55289 * 55290 * @name UniformsGroup#id 55291 * @type {number} 55292 * @readonly 55293 */ 55294 Object.defineProperty( this, 'id', { value: _id ++ } ); 55295 55296 /** 55297 * The name of the uniforms group. 55298 * 55299 * @type {string} 55300 */ 55301 this.name = ''; 55302 55303 /** 55304 * The buffer usage. 55305 * 55306 * @type {(StaticDrawUsage|DynamicDrawUsage|StreamDrawUsage|StaticReadUsage|DynamicReadUsage|StreamReadUsage|StaticCopyUsage|DynamicCopyUsage|StreamCopyUsage)} 55307 * @default StaticDrawUsage 55308 */ 55309 this.usage = StaticDrawUsage; 55310 55311 /** 55312 * An array holding the uniforms. 55313 * 55314 * @type {Array<Uniform>} 55315 */ 55316 this.uniforms = []; 55317 55318 } 55319 55320 /** 55321 * Adds the given uniform to this uniforms group. 55322 * 55323 * @param {Uniform} uniform - The uniform to add. 55324 * @return {UniformsGroup} A reference to this uniforms group. 55325 */ 55326 add( uniform ) { 55327 55328 this.uniforms.push( uniform ); 55329 55330 return this; 55331 55332 } 55333 55334 /** 55335 * Removes the given uniform from this uniforms group. 55336 * 55337 * @param {Uniform} uniform - The uniform to remove. 55338 * @return {UniformsGroup} A reference to this uniforms group. 55339 */ 55340 remove( uniform ) { 55341 55342 const index = this.uniforms.indexOf( uniform ); 55343 55344 if ( index !== -1 ) this.uniforms.splice( index, 1 ); 55345 55346 return this; 55347 55348 } 55349 55350 /** 55351 * Sets the name of this uniforms group. 55352 * 55353 * @param {string} name - The name to set. 55354 * @return {UniformsGroup} A reference to this uniforms group. 55355 */ 55356 setName( name ) { 55357 55358 this.name = name; 55359 55360 return this; 55361 55362 } 55363 55364 /** 55365 * Sets the usage of this uniforms group. 55366 * 55367 * @param {(StaticDrawUsage|DynamicDrawUsage|StreamDrawUsage|StaticReadUsage|DynamicReadUsage|StreamReadUsage|StaticCopyUsage|DynamicCopyUsage|StreamCopyUsage)} value - The usage to set. 55368 * @return {UniformsGroup} A reference to this uniforms group. 55369 */ 55370 setUsage( value ) { 55371 55372 this.usage = value; 55373 55374 return this; 55375 55376 } 55377 55378 /** 55379 * Frees the GPU-related resources allocated by this instance. Call this 55380 * method whenever this instance is no longer used in your app. 55381 * 55382 * @fires Texture#dispose 55383 */ 55384 dispose() { 55385 55386 this.dispatchEvent( { type: 'dispose' } ); 55387 55388 } 55389 55390 /** 55391 * Copies the values of the given uniforms group to this instance. 55392 * 55393 * @param {UniformsGroup} source - The uniforms group to copy. 55394 * @return {UniformsGroup} A reference to this uniforms group. 55395 */ 55396 copy( source ) { 55397 55398 this.name = source.name; 55399 this.usage = source.usage; 55400 55401 const uniformsSource = source.uniforms; 55402 55403 this.uniforms.length = 0; 55404 55405 for ( let i = 0, l = uniformsSource.length; i < l; i ++ ) { 55406 55407 const uniforms = Array.isArray( uniformsSource[ i ] ) ? uniformsSource[ i ] : [ uniformsSource[ i ] ]; 55408 55409 for ( let j = 0; j < uniforms.length; j ++ ) { 55410 55411 this.uniforms.push( uniforms[ j ].clone() ); 55412 55413 } 55414 55415 } 55416 55417 return this; 55418 55419 } 55420 55421 /** 55422 * Returns a new uniforms group with copied values from this instance. 55423 * 55424 * @return {UniformsGroup} A clone of this instance. 55425 */ 55426 clone() { 55427 55428 return new this.constructor().copy( this ); 55429 55430 } 55431 55432} 55433 55434/** 55435 * An instanced version of an interleaved buffer. 55436 * 55437 * @augments InterleavedBuffer 55438 */ 55439class InstancedInterleavedBuffer extends InterleavedBuffer { 55440 55441 /** 55442 * Constructs a new instanced interleaved buffer. 55443 * 55444 * @param {TypedArray} array - A typed array with a shared buffer storing attribute data. 55445 * @param {number} stride - The number of typed-array elements per vertex. 55446 * @param {number} [meshPerAttribute=1] - Defines how often a value of this interleaved buffer should be repeated. 55447 */ 55448 constructor( array, stride, meshPerAttribute = 1 ) { 55449 55450 super( array, stride ); 55451 55452 /** 55453 * This flag can be used for type testing. 55454 * 55455 * @type {boolean} 55456 * @readonly 55457 * @default true 55458 */ 55459 this.isInstancedInterleavedBuffer = true; 55460 55461 /** 55462 * Defines how often a value of this buffer attribute should be repeated, 55463 * see {@link InstancedBufferAttribute#meshPerAttribute}. 55464 * 55465 * @type {number} 55466 * @default 1 55467 */ 55468 this.meshPerAttribute = meshPerAttribute; 55469 55470 } 55471 55472 copy( source ) { 55473 55474 super.copy( source ); 55475 55476 this.meshPerAttribute = source.meshPerAttribute; 55477 55478 return this; 55479 55480 } 55481 55482 clone( data ) { 55483 55484 const ib = super.clone( data ); 55485 55486 ib.meshPerAttribute = this.meshPerAttribute; 55487 55488 return ib; 55489 55490 } 55491 55492 toJSON( data ) { 55493 55494 const json = super.toJSON( data ); 55495 55496 json.isInstancedInterleavedBuffer = true; 55497 json.meshPerAttribute = this.meshPerAttribute; 55498 55499 return json; 55500 55501 } 55502 55503} 55504 55505/** 55506 * An alternative version of a buffer attribute with more control over the VBO. 55507 * 55508 * The renderer does not construct a VBO for this kind of attribute. Instead, it uses 55509 * whatever VBO is passed in constructor and can later be altered via the `buffer` property. 55510 * 55511 * The most common use case for this class is when some kind of GPGPU calculation interferes 55512 * or even produces the VBOs in question. 55513 * 55514 * Notice that this class can only be used with {@link WebGLRenderer}. 55515 */ 55516class GLBufferAttribute { 55517 55518 /** 55519 * Constructs a new GL buffer attribute. 55520 * 55521 * @param {WebGLBuffer} buffer - The native WebGL buffer. 55522 * @param {number} type - The native data type (e.g. `gl.FLOAT`). 55523 * @param {number} itemSize - The item size. 55524 * @param {number} elementSize - The corresponding size (in bytes) for the given `type` parameter. 55525 * @param {number} count - The expected number of vertices in VBO. 55526 * @param {boolean} [normalized=false] - Whether the data are normalized or not. 55527 */ 55528 constructor( buffer, type, itemSize, elementSize, count, normalized = false ) { 55529 55530 /** 55531 * This flag can be used for type testing. 55532 * 55533 * @type {boolean} 55534 * @readonly 55535 * @default true 55536 */ 55537 this.isGLBufferAttribute = true; 55538 55539 /** 55540 * The name of the buffer attribute. 55541 * 55542 * @type {string} 55543 */ 55544 this.name = ''; 55545 55546 /** 55547 * The native WebGL buffer. 55548 * 55549 * @type {WebGLBuffer} 55550 */ 55551 this.buffer = buffer; 55552 55553 /** 55554 * The native data type. 55555 * 55556 * @type {number} 55557 */ 55558 this.type = type; 55559 55560 /** 55561 * The item size, see {@link BufferAttribute#itemSize}. 55562 * 55563 * @type {number} 55564 */ 55565 this.itemSize = itemSize; 55566 55567 /** 55568 * The corresponding size (in bytes) for the given `type` parameter. 55569 * 55570 * @type {number} 55571 */ 55572 this.elementSize = elementSize; 55573 55574 /** 55575 * The expected number of vertices in VBO. 55576 * 55577 * @type {number} 55578 */ 55579 this.count = count; 55580 55581 /** 55582 * Applies to integer data only. Indicates how the underlying data in the buffer maps to 55583 * the values in the GLSL code. For instance, if `buffer` contains data of `gl.UNSIGNED_SHORT`, 55584 * and `normalized` is `true`, the values `0 - +65535` in the buffer data will be mapped to 55585 * `0.0f - +1.0f` in the GLSL attribute. If `normalized` is `false`, the values will be converted 55586 * to floats unmodified, i.e. `65535` becomes `65535.0f`. 55587 * 55588 * @type {boolean} 55589 */ 55590 this.normalized = normalized; 55591 55592 /** 55593 * A version number, incremented every time the `needsUpdate` is set to `true`. 55594 * 55595 * @type {number} 55596 */ 55597 this.version = 0; 55598 55599 } 55600 55601 /** 55602 * Flag to indicate that this attribute has changed and should be re-sent to 55603 * the GPU. Set this to `true` when you modify the value of the array. 55604 * 55605 * @type {number} 55606 * @default false 55607 * @param {boolean} value 55608 */ 55609 set needsUpdate( value ) { 55610 55611 if ( value === true ) this.version ++; 55612 55613 } 55614 55615 /** 55616 * Sets the given native WebGL buffer. 55617 * 55618 * @param {WebGLBuffer} buffer - The buffer to set. 55619 * @return {BufferAttribute} A reference to this instance. 55620 */ 55621 setBuffer( buffer ) { 55622 55623 this.buffer = buffer; 55624 55625 return this; 55626 55627 } 55628 55629 /** 55630 * Sets the given native data type and element size. 55631 * 55632 * @param {number} type - The native data type (e.g. `gl.FLOAT`). 55633 * @param {number} elementSize - The corresponding size (in bytes) for the given `type` parameter. 55634 * @return {BufferAttribute} A reference to this instance. 55635 */ 55636 setType( type, elementSize ) { 55637 55638 this.type = type; 55639 this.elementSize = elementSize; 55640 55641 return this; 55642 55643 } 55644 55645 /** 55646 * Sets the item size. 55647 * 55648 * @param {number} itemSize - The item size. 55649 * @return {BufferAttribute} A reference to this instance. 55650 */ 55651 setItemSize( itemSize ) { 55652 55653 this.itemSize = itemSize; 55654 55655 return this; 55656 55657 } 55658 55659 /** 55660 * Sets the count (the expected number of vertices in VBO). 55661 * 55662 * @param {number} count - The count. 55663 * @return {BufferAttribute} A reference to this instance. 55664 */ 55665 setCount( count ) { 55666 55667 this.count = count; 55668 55669 return this; 55670 55671 } 55672 55673} 55674 55675const _matrix = /*@__PURE__*/ new Matrix4(); 55676 55677/** 55678 * This class is designed to assist with raycasting. Raycasting is used for 55679 * mouse picking (working out what objects in the 3d space the mouse is over) 55680 * amongst other things. 55681 */ 55682class Raycaster { 55683 55684 /** 55685 * Constructs a new raycaster. 55686 * 55687 * @param {Vector3} origin - The origin vector where the ray casts from. 55688 * @param {Vector3} direction - The (normalized) direction vector that gives direction to the ray. 55689 * @param {number} [near=0] - All results returned are further away than near. Near can't be negative. 55690 * @param {number} [far=Infinity] - All results returned are closer than far. Far can't be lower than near. 55691 */ 55692 constructor( origin, direction, near = 0, far = Infinity ) { 55693 55694 /** 55695 * The ray used for raycasting. 55696 * 55697 * @type {Ray} 55698 */ 55699 this.ray = new Ray( origin, direction ); 55700 55701 /** 55702 * All results returned are further away than near. Near can't be negative. 55703 * 55704 * @type {number} 55705 * @default 0 55706 */ 55707 this.near = near; 55708 55709 /** 55710 * All results returned are closer than far. Far can't be lower than near. 55711 * 55712 * @type {number} 55713 * @default Infinity 55714 */ 55715 this.far = far; 55716 55717 /** 55718 * The camera to use when raycasting against view-dependent objects such as 55719 * billboarded objects like sprites. This field can be set manually or 55720 * is set when calling `setFromCamera()`. 55721 * 55722 * @type {?Camera} 55723 * @default null 55724 */ 55725 this.camera = null; 55726 55727 /** 55728 * Allows to selectively ignore 3D objects when performing intersection tests. 55729 * The following code example ensures that only 3D objects on layer `1` will be 55730 * honored by raycaster. 55731 * ```js 55732 * raycaster.layers.set( 1 ); 55733 * object.layers.enable( 1 ); 55734 * ``` 55735 * 55736 * @type {Layers} 55737 */ 55738 this.layers = new Layers(); 55739 55740 55741 /** 55742 * A parameter object that configures the raycasting. It has the structure: 55743 * 55744 * ``` 55745 * { 55746 * Mesh: {}, 55747 * Line: { threshold: 1 }, 55748 * LOD: {}, 55749 * Points: { threshold: 1 }, 55750 * Sprite: {} 55751 * } 55752 * ``` 55753 * Where `threshold` is the precision of the raycaster when intersecting objects, in world units. 55754 * 55755 * @type {Object} 55756 */ 55757 this.params = { 55758 Mesh: {}, 55759 Line: { threshold: 1 }, 55760 LOD: {}, 55761 Points: { threshold: 1 }, 55762 Sprite: {} 55763 }; 55764 55765 } 55766 55767 /** 55768 * Updates the ray with a new origin and direction by copying the values from the arguments. 55769 * 55770 * @param {Vector3} origin - The origin vector where the ray casts from. 55771 * @param {Vector3} direction - The (normalized) direction vector that gives direction to the ray. 55772 */ 55773 set( origin, direction ) { 55774 55775 // direction is assumed to be normalized (for accurate distance calculations) 55776 55777 this.ray.set( origin, direction ); 55778 55779 } 55780 55781 /** 55782 * Uses the given coordinates and camera to compute a new origin and direction for the internal ray. 55783 * 55784 * @param {Vector2} coords - 2D coordinates of the mouse, in normalized device coordinates (NDC). 55785 * X and Y components should be between `-1` and `1`. 55786 * @param {Camera} camera - The camera from which the ray should originate. 55787 */ 55788 setFromCamera( coords, camera ) { 55789 55790 if ( camera.isPerspectiveCamera ) { 55791 55792 this.ray.origin.setFromMatrixPosition( camera.matrixWorld ); 55793 this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize(); 55794 this.camera = camera; 55795 55796 } else if ( camera.isOrthographicCamera ) { 55797 55798 this.ray.origin.set( coords.x, coords.y,
55798( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera 55799 this.ray.direction.set( 0, 0, -1 ).transformDirection( camera.matrixWorld ); 55800 this.camera = camera; 55801 55802 } else { 55803 55804 error( 'Raycaster: Unsupported camera type: ' + camera.type ); 55805 55806 } 55807 55808 } 55809 55810 /** 55811 * Uses the given WebXR controller to compute a new origin and direction for the internal ray. 55812 * 55813 * @param {WebXRController} controller - The controller to copy the position and direction from. 55814 * @return {Raycaster} A reference to this raycaster. 55815 */ 55816 setFromXRController( controller ) { 55817 55818 _matrix.identity().extractRotation( controller.matrixWorld ); 55819 55820 this.ray.origin.setFromMatrixPosition( controller.matrixWorld ); 55821 this.ray.direction.set( 0, 0, -1 ).applyMatrix4( _matrix ); 55822 55823 return this; 55824 55825 } 55826 55827 /** 55828 * The intersection point of a raycaster intersection test. 55829 * @typedef {Object} Raycaster~Intersection 55830 * @property {number} distance - The distance from the ray's origin to the intersection point. 55831 * @property {number} distanceToRay - Some 3D objects e.g. {@link Points} provide the distance of the 55832 * intersection to the nearest point on the ray. For other objects it will be `undefined`. 55833 * @property {Vector3} point - The intersection point, in world coordinates. 55834 * @property {Object} face - The face that has been intersected. 55835 * @property {number} faceIndex - The face index. 55836 * @property {Object3D} object - The 3D object that has been intersected. 55837 * @property {Vector2} uv - U,V coordinates at point of intersection. 55838 * @property {Vector2} uv1 - Second set of U,V coordinates at point of intersection. 55839 * @property {Vector3} normal - Interpolated normal vector at point of intersection. 55840 * @property {number} instanceId - The index number of the instance where the ray 55841 * intersects the {@link InstancedMesh}. 55842 */ 55843 55844 /** 55845 * Checks all intersection between the ray and the object with or without the 55846 * descendants. Intersections are returned sorted by distance, closest first. 55847 * 55848 * `Raycaster` delegates to the `raycast()` method of the passed 3D object, when 55849 * evaluating whether the ray intersects the object or not. This allows meshes to respond 55850 * differently to ray casting than lines or points. 55851 * 55852 * Note that for meshes, faces must be pointed towards the origin of the ray in order 55853 * to be detected; intersections of the ray passing through the back of a face will not 55854 * be detected. To raycast against both faces of an object, you'll want to set {@link Material#side} 55855 * to `THREE.DoubleSide`
vendor: 32,143 bytes, lines 55855-57256
55855. 55856 * 55857 * @param {Object3D} object - The 3D object to check for intersection with the ray. 55858 * @param {boolean} [recursive=true] - If set to `true`, it also checks all descendants. 55859 * Otherwise it only checks intersection with the object. 55860 * @param {Array<Raycaster~Intersection>} [intersects=[]] The target array that holds the result of the method. 55861 * @return {Array<Raycaster~Intersection>} An array holding the intersection points. 55862 */ 55863 intersectObject( object, recursive = true, intersects = [] ) { 55864 55865 intersect( object, this, intersects, recursive ); 55866 55867 intersects.sort( ascSort ); 55868 55869 return intersects; 55870 55871 } 55872 55873 /** 55874 * Checks all intersection between the ray and the objects with or without 55875 * the descendants. Intersections are returned sorted by distance, closest first. 55876 * 55877 * @param {Array<Object3D>} objects - The 3D objects to check for intersection with the ray. 55878 * @param {boolean} [recursive=true] - If set to `true`, it also checks all descendants. 55879 * Otherwise it only checks intersection with the object. 55880 * @param {Array<Raycaster~Intersection>} [intersects=[]] The target array that holds the result of the method. 55881 * @return {Array<Raycaster~Intersection>} An array holding the intersection points. 55882 */ 55883 intersectObjects( objects, recursive = true, intersects = [] ) { 55884 55885 for ( let i = 0, l = objects.length; i < l; i ++ ) { 55886 55887 intersect( objects[ i ], this, intersects, recursive ); 55888 55889 } 55890 55891 intersects.sort( ascSort ); 55892 55893 return intersects; 55894 55895 } 55896 55897} 55898 55899function ascSort( a, b ) { 55900 55901 return a.distance - b.distance; 55902 55903} 55904 55905function intersect( object, raycaster, intersects, recursive ) { 55906 55907 let propagate = true; 55908 55909 if ( object.layers.test( raycaster.layers ) ) { 55910 55911 const result = object.raycast( raycaster, intersects ); 55912 55913 if ( result === false ) propagate = false; 55914 55915 } 55916 55917 if ( propagate === true && recursive === true ) { 55918 55919 const children = object.children; 55920 55921 for ( let i = 0, l = children.length; i < l; i ++ ) { 55922 55923 intersect( children[ i ], raycaster, intersects, true ); 55924 55925 } 55926 55927 } 55928 55929} 55930 55931/** 55932 * Class for keeping track of time. 55933 * 55934 * @deprecated since r183. 55935 */ 55936class Clock { 55937 55938 /** 55939 * Constructs a new clock. 55940 * 55941 * @deprecated since 183. 55942 * @param {boolean} [autoStart=true] - Whether to automatically start the clock when 55943 * `getDelta()` is called for the first time. 55944 */ 55945 constructor( autoStart = true ) { 55946 55947 /** 55948 * If set to `true`, the clock starts automatically when `getDelta()` is called 55949 * for the first time. 55950 * 55951 * @type {boolean} 55952 * @default true 55953 */ 55954 this.autoStart = autoStart; 55955 55956 /** 55957 * Holds the time at which the clock's `start()` method was last called. 55958 * 55959 * @type {number} 55960 * @default 0 55961 */ 55962 this.startTime = 0; 55963 55964 /** 55965 * Holds the time at which the clock's `start()`, `getElapsedTime()` or 55966 * `getDelta()` methods were last called. 55967 * 55968 * @type {number} 55969 * @default 0 55970 */ 55971 this.oldTime = 0; 55972 55973 /** 55974 * Keeps track of the total time that the clock has been running. 55975 * 55976 * @type {number} 55977 * @default 0 55978 */ 55979 this.elapsedTime = 0; 55980 55981 /** 55982 * Whether the clock is running or not. 55983 * 55984 * @type {boolean} 55985 * @default true 55986 */ 55987 this.running = false; 55988 55989 warn( 'Clock: This module has been deprecated. Please use THREE.Timer instead.' ); // @deprecated, r183 55990 55991 } 55992 55993 /** 55994 * Starts the clock. When `autoStart` is set to `true`, the method is automatically 55995 * called by the class. 55996 */ 55997 start() { 55998 55999 this.startTime = performance.now(); 56000 56001 this.oldTime = this.startTime; 56002 this.elapsedTime = 0; 56003 this.running = true; 56004 56005 } 56006 56007 /** 56008 * Stops the clock. 56009 */ 56010 stop() { 56011 56012 this.getElapsedTime(); 56013 this.running = false; 56014 this.autoStart = false; 56015 56016 } 56017 56018 /** 56019 * Returns the elapsed time in seconds. 56020 * 56021 * @return {number} The elapsed time. 56022 */ 56023 getElapsedTime() { 56024 56025 this.getDelta(); 56026 return this.elapsedTime; 56027 56028 } 56029 56030 /** 56031 * Returns the delta time in seconds. 56032 * 56033 * @return {number} The delta time. 56034 */ 56035 getDelta() { 56036 56037 let diff = 0; 56038 56039 if ( this.autoStart && ! this.running ) { 56040 56041 this.start(); 56042 return 0; 56043 56044 } 56045 56046 if ( this.running ) { 56047 56048 const newTime = performance.now(); 56049 56050 diff = ( newTime - this.oldTime ) / 1000; 56051 this.oldTime = newTime; 56052 56053 this.elapsedTime += diff; 56054 56055 } 56056 56057 return diff; 56058 56059 } 56060 56061} 56062 56063/** 56064 * This class can be used to represent points in 3D space as 56065 * [Spherical coordinates](https://en.wikipedia.org/wiki/Spherical_coordinate_system). 56066 */ 56067class Spherical { 56068 56069 /** 56070 * Constructs a new spherical. 56071 * 56072 * @param {number} [radius=1] - The radius, or the Euclidean distance (straight-line distance) from the point to the origin. 56073 * @param {number} [phi=0] - The polar angle in radians from the y (up) axis. 56074 * @param {number} [theta=0] - The equator/azimuthal angle in radians around the y (up) axis. 56075 */ 56076 constructor( radius = 1, phi = 0, theta = 0 ) { 56077 56078 /** 56079 * The radius, or the Euclidean distance (straight-line distance) from the point to the origin. 56080 * 56081 * @type {number} 56082 * @default 1 56083 */ 56084 this.radius = radius; 56085 56086 /** 56087 * The polar angle in radians from the y (up) axis. 56088 * 56089 * @type {number} 56090 * @default 0 56091 */ 56092 this.phi = phi; 56093 56094 /** 56095 * The equator/azimuthal angle in radians around the y (up) axis. 56096 * 56097 * @type {number} 56098 * @default 0 56099 */ 56100 this.theta = theta; 56101 56102 } 56103 56104 /** 56105 * Sets the spherical components by copying the given values. 56106 * 56107 * @param {number} radius - The radius. 56108 * @param {number} phi - The polar angle. 56109 * @param {number} theta - The azimuthal angle. 56110 * @return {Spherical} A reference to this spherical. 56111 */ 56112 set( radius, phi, theta ) { 56113 56114 this.radius = radius; 56115 this.phi = phi; 56116 this.theta = theta; 56117 56118 return this; 56119 56120 } 56121 56122 /** 56123 * Copies the values of the given spherical to this instance. 56124 * 56125 * @param {Spherical} other - The spherical to copy. 56126 * @return {Spherical} A reference to this spherical. 56127 */ 56128 copy( other ) { 56129 56130 this.radius = other.radius; 56131 this.phi = other.phi; 56132 this.theta = other.theta; 56133 56134 return this; 56135 56136 } 56137 56138 /** 56139 * Restricts the polar angle [page:.phi phi] to be between `0.000001` and pi - 56140 * `0.000001`. 56141 * 56142 * @return {Spherical} A reference to this spherical. 56143 */ 56144 makeSafe() { 56145 56146 const EPS = 0.000001; 56147 this.phi = clamp( this.phi, EPS, Math.PI - EPS ); 56148 56149 return this; 56150 56151 } 56152 56153 /** 56154 * Sets the spherical components from the given vector which is assumed to hold 56155 * Cartesian coordinates. 56156 * 56157 * @param {Vector3} v - The vector to set. 56158 * @return {Spherical} A reference to this spherical. 56159 */ 56160 setFromVector3( v ) { 56161 56162 return this.setFromCartesianCoords( v.x, v.y, v.z ); 56163 56164 } 56165 56166 /** 56167 * Sets the spherical components from the given Cartesian coordinates. 56168 * 56169 * @param {number} x - The x value. 56170 * @param {number} y - The y value. 56171 * @param {number} z - The z value. 56172 * @return {Spherical} A reference to this spherical. 56173 */ 56174 setFromCartesianCoords( x, y, z ) { 56175 56176 this.radius = Math.sqrt( x * x + y * y + z * z ); 56177 56178 if ( this.radius === 0 ) { 56179 56180 this.theta = 0; 56181 this.phi = 0; 56182 56183 } else { 56184 56185 this.theta = Math.atan2( x, z ); 56186 this.phi = Math.acos( clamp( y / this.radius, -1, 1 ) ); 56187 56188 } 56189 56190 return this; 56191 56192 } 56193 56194 /** 56195 * Returns a new spherical with copied values from this instance. 56196 * 56197 * @return {Spherical} A clone of this instance. 56198 */ 56199 clone() { 56200 56201 return new this.constructor().copy( this ); 56202 56203 } 56204 56205} 56206 56207/** 56208 * This class can be used to represent points in 3D space as 56209 * [Cylindrical coordinates](https://en.wikipedia.org/wiki/Cylindrical_coordinate_system). 56210 */ 56211class Cylindrical { 56212 56213 /** 56214 * Constructs a new cylindrical. 56215 * 56216 * @param {number} [radius=1] - The distance from the origin to a point in the x-z plane. 56217 * @param {number} [theta=0] - A counterclockwise angle in the x-z plane measured in radians from the positive z-axis. 56218 * @param {number} [y=0] - The height above the x-z plane. 56219 */ 56220 constructor( radius = 1, theta = 0, y = 0 ) { 56221 56222 /** 56223 * The distance from the origin to a point in the x-z plane. 56224 * 56225 * @type {number} 56226 * @default 1 56227 */ 56228 this.radius = radius; 56229 56230 /** 56231 * A counterclockwise angle in the x-z plane measured in radians from the positive z-axis. 56232 * 56233 * @type {number} 56234 * @default 0 56235 */ 56236 this.theta = theta; 56237 56238 /** 56239 * The height above the x-z plane. 56240 * 56241 * @type {number} 56242 * @default 0 56243 */ 56244 this.y = y; 56245 56246 } 56247 56248 /** 56249 * Sets the cylindrical components by copying the given values. 56250 * 56251 * @param {number} radius - The radius. 56252 * @param {number} theta - The theta angle. 56253 * @param {number} y - The height value. 56254 * @return {Cylindrical} A reference to this cylindrical. 56255 */ 56256 set( radius, theta, y ) { 56257 56258 this.radius = radius; 56259 this.theta = theta; 56260 this.y = y; 56261 56262 return this; 56263 56264 } 56265 56266 /** 56267 * Copies the values of the given cylindrical to this instance. 56268 * 56269 * @param {Cylindrical} other - The cylindrical to copy. 56270 * @return {Cylindrical} A reference to this cylindrical. 56271 */ 56272 copy( other ) { 56273 56274 this.radius = other.radius; 56275 this.theta = other.theta; 56276 this.y = other.y; 56277 56278 return this; 56279 56280 } 56281 56282 /** 56283 * Sets the cylindrical components from the given vector which is assumed to hold 56284 * Cartesian coordinates. 56285 * 56286 * @param {Vector3} v - The vector to set. 56287 * @return {Cylindrical} A reference to this cylindrical. 56288 */ 56289 setFromVector3( v ) { 56290 56291 return this.setFromCartesianCoords( v.x, v.y, v.z ); 56292 56293 } 56294 56295 /** 56296 * Sets the cylindrical components from the given Cartesian coordinates. 56297 * 56298 * @param {number} x - The x value. 56299 * @param {number} y - The x value. 56300 * @param {number} z - The x value. 56301 * @return {Cylindrical} A reference to this cylindrical. 56302 */ 56303 setFromCartesianCoords( x, y, z ) { 56304 56305 this.radius = Math.sqrt( x * x + z * z ); 56306 this.theta = Math.atan2( x, z ); 56307 this.y = y; 56308 56309 return this; 56310 56311 } 56312 56313 /** 56314 * Returns a new cylindrical with copied values from this instance. 56315 * 56316 * @return {Cylindrical} A clone of this instance. 56317 */ 56318 clone() { 56319 56320 return new this.constructor().copy( this ); 56321 56322 } 56323 56324} 56325 56326/** 56327 * Represents a 2x2 matrix. 56328 * 56329 * A Note on Row-Major and Column-Major Ordering: 56330 * 56331 * The constructor and {@link Matrix2#set} method take arguments in 56332 * [row-major](https://en.wikipedia.org/wiki/Row-_and_column-major_order#Column-major_order) 56333 * order, while internally they are stored in the {@link Matrix2#elements} array in column-major order. 56334 * This means that calling: 56335 * ```js 56336 * const m = new THREE.Matrix2(); 56337 * m.set( 11, 12, 56338 * 21, 22 ); 56339 * ``` 56340 * will result in the elements array containing: 56341 * ```js 56342 * m.elements = [ 11, 21, 56343 * 12, 22 ]; 56344 * ``` 56345 * and internally all calculations are performed using column-major ordering. 56346 * However, as the actual ordering makes no difference mathematically and 56347 * most people are used to thinking about matrices in row-major order, the 56348 * three.js documentation shows matrices in row-major order. Just bear in 56349 * mind that if you are reading the source code, you'll have to take the 56350 * transpose of any matrices outlined here to make sense of the calculations. 56351 */ 56352class Matrix2 { 56353 56354 static { 56355 56356 /** 56357 * This flag can be used for type testing. 56358 * 56359 * @type {boolean} 56360 * @readonly 56361 * @default true 56362 */ 56363 Matrix2.prototype.isMatrix2 = true; 56364 56365 } 56366 56367 /** 56368 * Constructs a new 2x2 matrix. The arguments are supposed to be 56369 * in row-major order. If no arguments are provided, the constructor 56370 * initializes the matrix as an identity matrix. 56371 * 56372 * @param {number} [n11] - 1-1 matrix element. 56373 * @param {number} [n12] - 1-2 matrix element. 56374 * @param {number} [n21] - 2-1 matrix element. 56375 * @param {number} [n22] - 2-2 matrix element. 56376 */ 56377 constructor( n11, n12, n21, n22 ) { 56378 56379 /** 56380 * A column-major list of matrix values. 56381 * 56382 * @type {Array<number>} 56383 */ 56384 this.elements = [ 56385 1, 0, 56386 0, 1, 56387 ]; 56388 56389 if ( n11 !== undefined ) { 56390 56391 this.set( n11, n12, n21, n22 ); 56392 56393 } 56394 56395 } 56396 56397 /** 56398 * Sets this matrix to the 2x2 identity matrix. 56399 * 56400 * @return {Matrix2} A reference to this matrix. 56401 */ 56402 identity() { 56403 56404 this.set( 56405 1, 0, 56406 0, 1, 56407 ); 56408 56409 return this; 56410 56411 } 56412 56413 /** 56414 * Sets the elements of the matrix from the given array. 56415 * 56416 * @param {Array<number>} array - The matrix elements in column-major order. 56417 * @param {number} [offset=0] - Index of the first element in the array. 56418 * @return {Matrix2} A reference to this matrix. 56419 */ 56420 fromArray( array, offset = 0 ) { 56421 56422 for ( let i = 0; i < 4; i ++ ) { 56423 56424 this.elements[ i ] = array[ i + offset ]; 56425 56426 } 56427 56428 return this; 56429 56430 } 56431 56432 /** 56433 * Sets the elements of the matrix.The arguments are supposed to be 56434 * in row-major order. 56435 * 56436 * @param {number} n11 - 1-1 matrix element. 56437 * @param {number} n12 - 1-2 matrix element. 56438 * @param {number} n21 - 2-1 matrix element. 56439 * @param {number} n22 - 2-2 matrix element. 56440 * @return {Matrix2} A reference to this matrix. 56441 */ 56442 set( n11, n12, n21, n22 ) { 56443 56444 const te = this.elements; 56445 56446 te[ 0 ] = n11; te[ 2 ] = n12; 56447 te[ 1 ] = n21; te[ 3 ] = n22; 56448 56449 return this; 56450 56451 } 56452 56453} 56454 56455const _vector$4 = /*@__PURE__*/ new Vector2(); 56456 56457/** 56458 * Represents an axis-aligned bounding box (AABB) in 2D space. 56459 */ 56460class Box2 { 56461 56462 /** 56463 * Constructs a new bounding box. 56464 * 56465 * @param {Vector2} [min=(Infinity,Infinity)] - A vector representing the lower boundary of the box. 56466 * @param {Vector2} [max=(-Infinity,-Infinity)] - A vector representing the upper boundary of the box. 56467 */ 56468 constructor( min = new Vector2( + Infinity, + Infinity ), max = new Vector2( - Infinity, - Infinity ) ) { 56469 56470 /** 56471 * This flag can be used for type testing. 56472 * 56473 * @type {boolean} 56474 * @readonly 56475 * @default true 56476 */ 56477 this.isBox2 = true; 56478 56479 /** 56480 * The lower boundary of the box. 56481 * 56482 * @type {Vector2} 56483 */ 56484 this.min = min; 56485 56486 /** 56487 * The upper boundary of the box. 56488 * 56489 * @type {Vector2} 56490 */ 56491 this.max = max; 56492 56493 } 56494 56495 /** 56496 * Sets the lower and upper boundaries of this box. 56497 * Please note that this method only copies the values from the given objects. 56498 * 56499 * @param {Vector2} min - The lower boundary of the box. 56500 * @param {Vector2} max - The upper boundary of the box. 56501 * @return {Box2} A reference to this bounding box. 56502 */ 56503 set( min, max ) { 56504 56505 this.min.copy( min ); 56506 this.max.copy( max ); 56507 56508 return this; 56509 56510 } 56511 56512 /** 56513 * Sets the upper and lower bounds of this box so it encloses the position data 56514 * in the given array. 56515 * 56516 * @param {Array<Vector2>} points - An array holding 2D position data as instances of {@link Vector2}. 56517 * @return {Box2} A reference to this bounding box. 56518 */ 56519 setFromPoints( points ) { 56520 56521 this.makeEmpty(); 56522 56523 for ( let i = 0, il = points.length; i < il; i ++ ) { 56524 56525 this.expandByPoint( points[ i ] ); 56526 56527 } 56528 56529 return this; 56530 56531 } 56532 56533 /** 56534 * Centers this box on the given center vector and sets this box's width, height and 56535 * depth to the given size values. 56536 * 56537 * @param {Vector2} center - The center of the box. 56538 * @param {Vector2} size - The x and y dimensions of the box. 56539 * @return {Box2} A reference to this bounding box. 56540 */ 56541 setFromCenterAndSize( center, size ) { 56542 56543 const halfSize = _vector$4.copy( size ).multiplyScalar( 0.5 ); 56544 this.min.copy( center ).sub( halfSize ); 56545 this.max.copy( center ).add( halfSize ); 56546 56547 return this; 56548 56549 } 56550 56551 /** 56552 * Returns a new box with copied values from this instance. 56553 * 56554 * @return {Box2} A clone of this instance. 56555 */ 56556 clone() { 56557 56558 return new this.constructor().copy( this ); 56559 56560 } 56561 56562 /** 56563 * Copies the values of the given box to this instance. 56564 * 56565 * @param {Box2} box - The box to copy. 56566 * @return {Box2} A reference to this bounding box. 56567 */ 56568 copy( box ) { 56569 56570 this.min.copy( box.min ); 56571 this.max.copy( box.max ); 56572 56573 return this; 56574 56575 } 56576 56577 /** 56578 * Makes this box empty which means in encloses a zero space in 2D. 56579 * 56580 * @return {Box2} A reference to this bounding box. 56581 */ 56582 makeEmpty() { 56583 56584 this.min.x = this.min.y = + Infinity; 56585 this.max.x = this.max.y = - Infinity; 56586 56587 return this; 56588 56589 } 56590 56591 /** 56592 * Returns true if this box includes zero points within its bounds. 56593 * Note that a box with equal lower and upper bounds still includes one 56594 * point, the one both bounds share. 56595 * 56596 * @return {boolean} Whether this box is empty or not. 56597 */ 56598 isEmpty() { 56599 56600 // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes 56601 56602 return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); 56603 56604 } 56605 56606 /** 56607 * Returns the center point of this box. 56608 * 56609 * @param {Vector2} target - The target vector that is used to store the method's result. 56610 * @return {Vector2} The center point. 56611 */ 56612 getCenter( target ) { 56613 56614 return this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); 56615 56616 } 56617 56618 /** 56619 * Returns the dimensions of this box. 56620 * 56621 * @param {Vector2} target - The target vector that is used to store the method's result. 56622 * @return {Vector2} The size. 56623 */ 56624 getSize( target ) { 56625 56626 return this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min ); 56627 56628 } 56629 56630 /** 56631 * Expands the boundaries of this box to include the given point. 56632 * 56633 * @param {Vector2} point - The point that should be included by the bounding box. 56634 * @return {Box2} A reference to this bounding box. 56635 */ 56636 expandByPoint( point ) { 56637 56638 this.min.min( point ); 56639 this.max.max( point ); 56640 56641 return this; 56642 56643 } 56644 56645 /** 56646 * Expands this box equilaterally by the given vector. The width of this 56647 * box will be expanded by the x component of the vector in both 56648 * directions. The height of this box will be expanded by the y component of 56649 * the vector in both directions. 56650 * 56651 * @param {Vector2} vector - The vector that should expand the bounding box. 56652 * @return {Box2} A reference to this bounding box. 56653 */ 56654 expandByVector( vector ) { 56655 56656 this.min.sub( vector ); 56657 this.max.add( vector ); 56658 56659 return this; 56660 56661 } 56662 56663 /** 56664 * Expands each dimension of the box by the given scalar. If negative, the 56665 * dimensions of the box will be contracted. 56666 * 56667 * @param {number} scalar - The scalar value that should expand the bounding box. 56668 * @return {Box2} A reference to this bounding box. 56669 */ 56670 expandByScalar( scalar ) { 56671 56672 this.min.addScalar( - scalar ); 56673 this.max.addScalar( scalar ); 56674 56675 return this; 56676 56677 } 56678 56679 /** 56680 * Returns `true` if the given point lies within or on the boundaries of this box. 56681 * 56682 * @param {Vector2} point - The point to test. 56683 * @return {boolean} Whether the bounding box contains the given point or not. 56684 */ 56685 containsPoint( point ) { 56686 56687 return point.x >= this.min.x && point.x <= this.max.x && 56688 point.y >= this.min.y && point.y <= this.max.y; 56689 56690 } 56691 56692 /** 56693 * Returns `true` if this bounding box includes the entirety of the given bounding box. 56694 * If this box and the given one are identical, this function also returns `true`. 56695 * 56696 * @param {Box2} box - The bounding box to test. 56697 * @return {boolean} Whether the bounding box contains the given bounding box or not. 56698 */ 56699 containsBox( box ) { 56700 56701 return this.min.x <= box.min.x && box.max.x <= this.max.x && 56702 this.min.y <= box.min.y && box.max.y <= this.max.y; 56703 56704 } 56705 56706 /** 56707 * Returns a point as a proportion of this box's width and height. 56708 * 56709 * @param {Vector2} point - A point in 2D space. 56710 * @param {Vector2} target - The target vector that is used to store the method's result. 56711 * @return {Vector2} A point as a proportion of this box's width and height. 56712 */ 56713 getParameter( point, target ) { 56714 56715 // This can potentially have a divide by zero if the box 56716 // has a size dimension of 0. 56717 56718 return target.set( 56719 ( point.x - this.min.x ) / ( this.max.x - this.min.x ), 56720 ( point.y - this.min.y ) / ( this.max.y - this.min.y ) 56721 ); 56722 56723 } 56724 56725 /** 56726 * Returns `true` if the given bounding box intersects with this bounding box. 56727 * 56728 * @param {Box2} box - The bounding box to test. 56729 * @return {boolean} Whether the given bounding box intersects with this bounding box. 56730 */ 56731 intersectsBox( box ) { 56732 56733 // using 4 splitting planes to rule out intersections 56734 56735 return box.max.x >= this.min.x && box.min.x <= this.max.x && 56736 box.max.y >= this.min.y && box.min.y <= this.max.y; 56737 56738 } 56739 56740 /** 56741 * Clamps the given point within the bounds of this box. 56742 * 56743 * @param {Vector2} point - The point to clamp. 56744 * @param {Vector2} target - The target vector that is used to store the method's result. 56745 * @return {Vector2} The clamped point. 56746 */ 56747 clampPoint( point, target ) { 56748 56749 return target.copy( point ).clamp( this.min, this.max ); 56750 56751 } 56752 56753 /** 56754 * Returns the euclidean distance from any edge of this box to the specified point. If 56755 * the given point lies inside of this box, the distance will be `0`. 56756 * 56757 * @param {Vector2} point - The point to compute the distance to. 56758 * @return {number} The euclidean distance. 56759 */ 56760 distanceToPoint( point ) { 56761 56762 return this.clampPoint( point, _vector$4 ).distanceTo( point ); 56763 56764 } 56765 56766 /** 56767 * Computes the intersection of this bounding box and the given one, setting the upper 56768 * bound of this box to the lesser of the two boxes' upper bounds and the 56769 * lower bound of this box to the greater of the two boxes' lower bounds. If 56770 * there's no overlap, makes this box empty. 56771 * 56772 * @param {Box2} box - The bounding box to intersect with. 56773 * @return {Box2} A reference to this bounding box. 56774 */ 56775 intersect( box ) { 56776 56777 this.min.max( box.min ); 56778 this.max.min( box.max ); 56779 56780 if ( this.isEmpty() ) this.makeEmpty(); 56781 56782 return this; 56783 56784 } 56785 56786 /** 56787 * Computes the union of this box and another and the given one, setting the upper 56788 * bound of this box to the greater of the two boxes' upper bounds and the 56789 * lower bound of this box to the lesser of the two boxes' lower bounds. 56790 * 56791 * @param {Box2} box - The bounding box that will be unioned with this instance. 56792 * @return {Box2} A reference to this bounding box. 56793 */ 56794 union( box ) { 56795 56796 this.min.min( box.min ); 56797 this.max.max( box.max ); 56798 56799 return this; 56800 56801 } 56802 56803 /** 56804 * Adds the given offset to both the upper and lower bounds of this bounding box, 56805 * effectively moving it in 2D space. 56806 * 56807 * @param {Vector2} offset - The offset that should be used to translate the bounding box. 56808 * @return {Box2} A reference to this bounding box. 56809 */ 56810 translate( offset ) { 56811 56812 this.min.add( offset ); 56813 this.max.add( offset ); 56814 56815 return this; 56816 56817 } 56818 56819 /** 56820 * Returns `true` if this bounding box is equal with the given one. 56821 * 56822 * @param {Box2} box - The box to test for equality. 56823 * @return {boolean} Whether this bounding box is equal with the given one. 56824 */ 56825 equals( box ) { 56826 56827 return box.min.equals( this.min ) && box.max.equals( this.max ); 56828 56829 } 56830 56831} 56832 56833const _startP = /*@__PURE__*/ new Vector3(); 56834const _startEnd = /*@__PURE__*/ new Vector3(); 56835 56836const _d1 = /*@__PURE__*/ new Vector3(); 56837const _d2 = /*@__PURE__*/ new Vector3(); 56838const _r = /*@__PURE__*/ new Vector3(); 56839const _c1 = /*@__PURE__*/ new Vector3(); 56840const _c2 = /*@__PURE__*/ new Vector3(); 56841 56842/** 56843 * An analytical line segment in 3D space represented by a start and end point. 56844 */ 56845class Line3 { 56846 56847 /** 56848 * Constructs a new line segment. 56849 * 56850 * @param {Vector3} [start=(0,0,0)] - Start of the line segment. 56851 * @param {Vector3} [end=(0,0,0)] - End of the line segment. 56852 */ 56853 constructor( start = new Vector3(), end = new Vector3() ) { 56854 56855 /** 56856 * Start of the line segment. 56857 * 56858 * @type {Vector3} 56859 */ 56860 this.start = start; 56861 56862 /** 56863 * End of the line segment. 56864 * 56865 * @type {Vector3} 56866 */ 56867 this.end = end; 56868 56869 } 56870 56871 /** 56872 * Sets the start and end values by copying the given vectors. 56873 * 56874 * @param {Vector3} start - The start point. 56875 * @param {Vector3} end - The end point. 56876 * @return {Line3} A reference to this line segment. 56877 */ 56878 set( start, end ) { 56879 56880 this.start.copy( start ); 56881 this.end.copy( end ); 56882 56883 return this; 56884 56885 } 56886 56887 /** 56888 * Copies the values of the given line segment to this instance. 56889 * 56890 * @param {Line3} line - The line segment to copy. 56891 * @return {Line3} A reference to this line segment. 56892 */ 56893 copy( line ) { 56894 56895 this.start.copy( line.start ); 56896 this.end.copy( line.end ); 56897 56898 return this; 56899 56900 } 56901 56902 /** 56903 * Returns the center of the line segment. 56904 * 56905 * @param {Vector3} target - The target vector that is used to store the method's result. 56906 * @return {Vector3} The center point. 56907 */ 56908 getCenter( target ) { 56909 56910 return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); 56911 56912 } 56913 56914 /** 56915 * Returns the delta vector of the line segment's start and end point. 56916 * 56917 * @param {Vector3} target - The target vector that is used to store the method's result. 56918 * @return {Vector3} The delta vector. 56919 */ 56920 delta( target ) { 56921 56922 return target.subVectors( this.end, this.start ); 56923 56924 } 56925 56926 /** 56927 * Returns the squared Euclidean distance between the line' start and end point. 56928 * 56929 * @return {number} The squared Euclidean distance. 56930 */ 56931 distanceSq() { 56932 56933 return this.start.distanceToSquared( this.end ); 56934 56935 } 56936 56937 /** 56938 * Returns the Euclidean distance between the line' start and end point. 56939 * 56940 * @return {number} The Euclidean distance. 56941 */ 56942 distance() { 56943 56944 return this.start.distanceTo( this.end ); 56945 56946 } 56947 56948 /** 56949 * Returns a vector at a certain position along the line segment. 56950 * 56951 * @param {number} t - A value between `[0,1]` to represent a position along the line segment. 56952 * @param {Vector3} target - The target vector that is used to store the method's result. 56953 * @return {Vector3} The delta vector. 56954 */ 56955 at( t, target ) { 56956 56957 return this.delta( target ).multiplyScalar( t ).add( this.start ); 56958 56959 } 56960 56961 /** 56962 * Returns a point parameter based on the closest point as projected on the line segment. 56963 * 56964 * @param {Vector3} point - The point for which to return a point parameter. 56965 * @param {boolean} clampToLine - Whether to clamp the result to the range `[0,1]` or not. 56966 * @return {number} The point parameter. 56967 */ 56968 closestPointToPointParameter( point, clampToLine ) { 56969 56970 _startP.subVectors( point, this.start ); 56971 _startEnd.subVectors( this.end, this.start ); 56972 56973 const startEnd2 = _startEnd.dot( _startEnd ); 56974 56975 if ( startEnd2 === 0 ) return 0; 56976 56977 const startEnd_startP = _startEnd.dot( _startP ); 56978 56979 let t = startEnd_startP / startEnd2; 56980 56981 if ( clampToLine ) { 56982 56983 t = clamp( t, 0, 1 ); 56984 56985 } 56986 56987 return t; 56988 56989 } 56990 56991 /** 56992 * Returns the closest point on the line for a given point. 56993 * 56994 * @param {Vector3} point - The point to compute the closest point on the line for. 56995 * @param {boolean} clampToLine - Whether to clamp the result to the range `[0,1]` or not. 56996 * @param {Vector3} target - The target vector that is used to store the method's result. 56997 * @return {Vector3} The closest point on the line. 56998 */ 56999 closestPointToPoint( point, clampToLine, target ) { 57000 57001 const t = this.closestPointToPointParameter( point, clampToLine ); 57002 57003 return this.delta( target ).multiplyScalar( t ).add( this.start ); 57004 57005 } 57006 57007 /** 57008 * Returns the closest squared distance between this line segment and the given one. 57009 * 57010 * @param {Line3} line - The line segment to compute the closest squared distance to. 57011 * @param {Vector3} [c1] - The closest point on this line segment. 57012 * @param {Vector3} [c2] - The closest point on the given line segment. 57013 * @return {number} The squared distance between this line segment and the given one. 57014 */ 57015 distanceSqToLine3( line, c1 = _c1, c2 = _c2 ) { 57016 57017 // from Real-Time Collision Detection by Christer Ericson, chapter 5.1.9 57018 57019 // Computes closest points C1 and C2 of S1(s)=P1+s*(Q1-P1) and 57020 // S2(t)=P2+t*(Q2-P2), returning s and t. Function result is squared 57021 // distance between between S1(s) and S2(t) 57022 57023 const EPSILON = 1e-8 * 1e-8; // must be squared since we compare squared length 57024 let s, t; 57025 57026 const p1 = this.start; 57027 const p2 = line.start; 57028 const q1 = this.end; 57029 const q2 = line.end; 57030 57031 _d1.subVectors( q1, p1 ); // Direction vector of segment S1 57032 _d2.subVectors( q2, p2 ); // Direction vector of segment S2 57033 _r.subVectors( p1, p2 ); 57034 57035 const a = _d1.dot( _d1 ); // Squared length of segment S1, always nonnegative 57036 const e = _d2.dot( _d2 ); // Squared length of segment S2, always nonnegative 57037 const f = _d2.dot( _r ); 57038 57039 // Check if either or both segments degenerate into points 57040 57041 if ( a <= EPSILON && e <= EPSILON ) { 57042 57043 // Both segments degenerate into points 57044 57045 c1.copy( p1 ); 57046 c2.copy( p2 ); 57047 57048 c1.sub( c2 ); 57049 57050 return c1.dot( c1 ); 57051 57052 } 57053 57054 if ( a <= EPSILON ) { 57055 57056 // First segment degenerates into a point 57057 57058 s = 0; 57059 t = f / e; // s = 0 => t = (b*s + f) / e = f / e 57060 t = clamp( t, 0, 1 ); 57061 57062 57063 } else { 57064 57065 const c = _d1.dot( _r ); 57066 57067 if ( e <= EPSILON ) { 57068 57069 // Second segment degenerates into a point 57070 57071 t = 0; 57072 s = clamp( - c / a, 0, 1 ); // t = 0 => s = (b*t - c) / a = -c / a 57073 57074 } else { 57075 57076 // The general nondegenerate case starts here 57077 57078 const b = _d1.dot( _d2 ); 57079 const denom = a * e - b * b; // Always nonnegative 57080 57081 // If segments not parallel, compute closest point on L1 to L2 and 57082 // clamp to segment S1. Else pick arbitrary s (here 0) 57083 57084 if ( denom !== 0 ) { 57085 57086 s = clamp( ( b * f - c * e ) / denom, 0, 1 ); 57087 57088 } else { 57089 57090 s = 0; 57091 57092 } 57093 57094 // Compute point on L2 closest to S1(s) using 57095 // t = Dot((P1 + D1*s) - P2,D2) / Dot(D2,D2) = (b*s + f) / e 57096 57097 t = ( b * s + f ) / e; 57098 57099 // If t in [0,1] done. Else clamp t, recompute s for the new value 57100 // of t using s = Dot((P2 + D2*t) - P1,D1) / Dot(D1,D1)= (t*b - c) / a 57101 // and clamp s to [0, 1] 57102 57103 if ( t < 0 ) { 57104 57105 t = 0.; 57106 s = clamp( - c / a, 0, 1 ); 57107 57108 } else if ( t > 1 ) { 57109 57110 t = 1; 57111 s = clamp( ( b - c ) / a, 0, 1 ); 57112 57113 } 57114 57115 } 57116 57117 } 57118 57119 c1.copy( p1 ).addScaledVector( _d1, s ); 57120 c2.copy( p2 ).addScaledVector( _d2, t ); 57121 57122 return c1.distanceToSquared( c2 ); 57123 57124 } 57125 57126 /** 57127 * Applies a 4x4 transformation matrix to this line segment. 57128 * 57129 * @param {Matrix4} matrix - The transformation matrix. 57130 * @return {Line3} A reference to this line segment. 57131 */ 57132 applyMatrix4( matrix ) { 57133 57134 this.start.applyMatrix4( matrix ); 57135 this.end.applyMatrix4( matrix ); 57136 57137 return this; 57138 57139 } 57140 57141 /** 57142 * Returns `true` if this line segment is equal with the given one. 57143 * 57144 * @param {Line3} line - The line segment to test for equality. 57145 * @return {boolean} Whether this line segment is equal with the given one. 57146 */ 57147 equals( line ) { 57148 57149 return line.start.equals( this.start ) && line.end.equals( this.end ); 57150 57151 } 57152 57153 /** 57154 * Returns a new line segment with copied values from this instance. 57155 * 57156 * @return {Line3} A clone of this instance. 57157 */ 57158 clone() { 57159 57160 return new this.constructor().copy( this ); 57161 57162 } 57163 57164} 57165 57166const _vector$3 = /*@__PURE__*/ new Vector3(); 57167 57168/** 57169 * This displays a cone shaped helper object for a {@link SpotLight}. 57170 * 57171 * When the spot light or its target are transformed or light properties are 57172 * changed, it's necessary to call the `update()` method of the respective helper. 57173 * 57174 * ```js 57175 * const spotLight = new THREE.SpotLight( 0xffffff ); 57176 * spotLight.position.set( 10, 10, 10 ); 57177 * scene.add( spotLight ); 57178 * 57179 * const spotLightHelper = new THREE.SpotLightHelper( spotLight ); 57180 * scene.add( spotLightHelper ); 57181 * ``` 57182 * 57183 * @augments Object3D 57184 */ 57185class SpotLightHelper extends Object3D { 57186 57187 /** 57188 * Constructs a new spot light helper. 57189 * 57190 * @param {HemisphereLight} light - The light to be visualized. 57191 * @param {number|Color|string} [color] - The helper's color. If not set, the helper will take 57192 * the color of the light. 57193 */ 57194 constructor( light, color ) { 57195 57196 super(); 57197 57198 /** 57199 * The light being visualized. 57200 * 57201 * @type {SpotLight} 57202 */ 57203 this.light = light; 57204 57205 this.matrixAutoUpdate = false; 57206 57207 /** 57208 * The color parameter passed in the constructor. 57209 * If not set, the helper will take the color of the light. 57210 * 57211 * @type {number|Color|string} 57212 */ 57213 this.color = color; 57214 57215 this.type = 'SpotLightHelper'; 57216 57217 const geometry = new BufferGeometry(); 57218 57219 const positions = [ 57220 0, 0, 0, 0, 0, 1, 57221 0, 0, 0, 1, 0, 1, 57222 0, 0, 0, -1, 0, 1, 57223 0, 0, 0, 0, 1, 1, 57224 0, 0, 0, 0, -1, 1 57225 ]; 57226 57227 for ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) { 57228 57229 const p1 = ( i / l ) * Math.PI * 2; 57230 const p2 = ( j / l ) * Math.PI * 2; 57231 57232 positions.push( 57233 Math.cos( p1 ), Math.sin( p1 ), 1, 57234 Math.cos( p2 ), Math.sin( p2 ), 1 57235 ); 57236 57237 } 57238 57239 geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); 57240 57241 const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); 57242 57243 this.cone = new LineSegments( geometry, material ); 57244 this.add( this.cone ); 57245 57246 this.update(); 57247 57248 } 57249 57250 /** 57251 * Frees the GPU-related resources allocated by this instance. Call this 57252 * method whenever this instance is no longer used in your app. 57253 */ 57254 dispose() { 57255 57256
vendor: 2,946 bytes, lines 57256-57390
57256this.cone.geometry.dispose(); 57257 this.cone.material.dispose(); 57258 57259 } 57260 57261 /** 57262 * Updates the helper to match the position and direction of the 57263 * light being visualized. 57264 */ 57265 update() { 57266 57267 this.light.updateWorldMatrix( true, false ); 57268 this.light.target.updateWorldMatrix( true, false ); 57269 57270 // update the local matrix based on the parent and light target transforms 57271 if ( this.parent ) { 57272 57273 this.parent.updateWorldMatrix( true ); 57274 57275 this.matrix 57276 .copy( this.parent.matrixWorld ) 57277 .invert() 57278 .multiply( this.light.matrixWorld ); 57279 57280 } else { 57281 57282 this.matrix.copy( this.light.matrixWorld ); 57283 57284 } 57285 57286 this.matrixWorld.copy( this.light.matrixWorld ); 57287 57288 const coneLength = this.light.distance ? this.light.distance : 1000; 57289 const coneWidth = coneLength * Math.tan( this.light.angle ); 57290 57291 this.cone.scale.set( coneWidth, coneWidth, coneLength ); 57292 57293 _vector$3.setFromMatrixPosition( this.light.target.matrixWorld ); 57294 57295 this.cone.lookAt( _vector$3 ); 57296 57297 if ( this.color !== undefined ) { 57298 57299 this.cone.material.color.set( this.color ); 57300 57301 } else { 57302 57303 this.cone.material.color.copy( this.light.color ); 57304 57305 } 57306 57307 } 57308 57309} 57310 57311const _vector$2 = /*@__PURE__*/ new Vector3(); 57312const _boneMatrix = /*@__PURE__*/ new Matrix4(); 57313const _matrixWorldInv = /*@__PURE__*/ new Matrix4(); 57314 57315/** 57316 * A helper object to assist with visualizing a {@link Skeleton}. 57317 * 57318 * ```js 57319 * const helper = new THREE.SkeletonHelper( skinnedMesh ); 57320 * scene.add( helper ); 57321 * ``` 57322 * 57323 * @augments LineSegments 57324 */ 57325class SkeletonHelper extends LineSegments { 57326 57327 /** 57328 * Constructs a new skeleton helper. 57329 * 57330 * @param {Object3D} object - Usually an instance of {@link SkinnedMesh}. However, any 3D object 57331 * can be used if it represents a hierarchy of bones (see {@link Bone}). 57332 */ 57333 constructor( object ) { 57334 57335 const bones = getBoneList( object ); 57336 57337 const geometry = new BufferGeometry(); 57338 57339 const vertices = []; 57340 const colors = []; 57341 57342 for ( let i = 0; i < bones.length; i ++ ) { 57343 57344 const bone = bones[ i ]; 57345 57346 if ( bone.parent && bone.parent.isBone ) { 57347 57348 vertices.push( 0, 0, 0 ); 57349 vertices.push( 0, 0, 0 ); 57350 colors.push( 0, 0, 0 ); 57351 colors.push( 0, 0, 0 ); 57352 57353 } 57354 57355 } 57356 57357 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 57358 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); 57359 57360 const material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } ); 57361 57362 super( geometry, material ); 57363 57364 /** 57365 * This flag can be used for type testing. 57366 * 57367 * @type {boolean} 57368 * @readonly 57369 * @default true 57370 */ 57371 this.isSkeletonHelper = true; 57372 57373 this.type = 'SkeletonHelper'; 57374 57375 /** 57376 * The object being visualized. 57377 * 57378 * @type {Object3D} 57379 */ 57380 this.root = object; 57381 57382 /** 57383 * The list of bones that the helper visualizes. 57384 * 57385 * @type {Array<Bone>} 57386 */ 57387 this.bones = bones; 57388 57389 this.matrix = object.matrixWorld; 57390 this.matrixAutoUpdate = false;
vendor: 14,852 bytes, lines 57391-58021
57391 57392 // colors 57393 57394 const color1 = new Color( 0x0000ff ); 57395 const color2 = new Color( 0x00ff00 ); 57396 57397 this.setColors( color1, color2 ); 57398 57399 } 57400 57401 updateMatrixWorld( force ) { 57402 57403 const bones = this.bones; 57404 57405 const geometry = this.geometry; 57406 const position = geometry.getAttribute( 'position' ); 57407 57408 _matrixWorldInv.copy( this.root.matrixWorld ).invert(); 57409 57410 for ( let i = 0, j = 0; i < bones.length; i ++ ) { 57411 57412 const bone = bones[ i ]; 57413 57414 if ( bone.parent && bone.parent.isBone ) { 57415 57416 _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld ); 57417 _vector$2.setFromMatrixPosition( _boneMatrix ); 57418 position.setXYZ( j, _vector$2.x, _vector$2.y, _vector$2.z ); 57419 57420 _boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld ); 57421 _vector$2.setFromMatrixPosition( _boneMatrix ); 57422 position.setXYZ( j + 1, _vector$2.x, _vector$2.y, _vector$2.z ); 57423 57424 j += 2; 57425 57426 } 57427 57428 } 57429 57430 geometry.getAttribute( 'position' ).needsUpdate = true; 57431 57432 super.updateMatrixWorld( force ); 57433 57434 } 57435 57436 /** 57437 * Defines the colors of the helper. 57438 * 57439 * @param {Color} color1 - The first line color for each bone. 57440 * @param {Color} color2 - The second line color for each bone. 57441 * @return {SkeletonHelper} A reference to this helper. 57442 */ 57443 setColors( color1, color2 ) { 57444 57445 const geometry = this.geometry; 57446 const colorAttribute = geometry.getAttribute( 'color' ); 57447 57448 for ( let i = 0; i < colorAttribute.count; i += 2 ) { 57449 57450 colorAttribute.setXYZ( i, color1.r, color1.g, color1.b ); 57451 colorAttribute.setXYZ( i + 1, color2.r, color2.g, color2.b ); 57452 57453 } 57454 57455 colorAttribute.needsUpdate = true; 57456 57457 return this; 57458 57459 } 57460 57461 /** 57462 * Frees the GPU-related resources allocated by this instance. Call this 57463 * method whenever this instance is no longer used in your app. 57464 */ 57465 dispose() { 57466 57467 this.geometry.dispose(); 57468 this.material.dispose(); 57469 57470 } 57471 57472} 57473 57474 57475function getBoneList( object ) { 57476 57477 const boneList = []; 57478 57479 if ( object.isBone === true ) { 57480 57481 boneList.push( object ); 57482 57483 } 57484 57485 for ( let i = 0; i < object.children.length; i ++ ) { 57486 57487 boneList.push( ...getBoneList( object.children[ i ] ) ); 57488 57489 } 57490 57491 return boneList; 57492 57493} 57494 57495/** 57496 * This displays a helper object consisting of a spherical mesh for 57497 * visualizing an instance of {@link PointLight}. 57498 * 57499 * ```js 57500 * const pointLight = new THREE.PointLight( 0xff0000, 1, 100 ); 57501 * pointLight.position.set( 10, 10, 10 ); 57502 * scene.add( pointLight ); 57503 * 57504 * const sphereSize = 1; 57505 * const pointLightHelper = new THREE.PointLightHelper( pointLight, sphereSize ); 57506 * scene.add( pointLightHelper ); 57507 * ``` 57508 * 57509 * @augments Mesh 57510 */ 57511class PointLightHelper extends Mesh { 57512 57513 /** 57514 * Constructs a new point light helper. 57515 * 57516 * @param {PointLight} light - The light to be visualized. 57517 * @param {number} [sphereSize=1] - The size of the sphere helper. 57518 * @param {number|Color|string} [color] - The helper's color. If not set, the helper will take 57519 * the color of the light. 57520 */ 57521 constructor( light, sphereSize, color ) { 57522 57523 const geometry = new SphereGeometry( sphereSize, 4, 2 ); 57524 const material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); 57525 57526 super( geometry, material ); 57527 57528 /** 57529 * The light being visualized. 57530 * 57531 * @type {PointLight} 57532 */ 57533 this.light = light; 57534 57535 /** 57536 * The color parameter passed in the constructor. 57537 * If not set, the helper will take the color of the light. 57538 * 57539 * @type {number|Color|string} 57540 */ 57541 this.color = color; 57542 57543 this.type = 'PointLightHelper'; 57544 57545 this.matrix = this.light.matrixWorld; 57546 this.matrixAutoUpdate = false; 57547 57548 this.update(); 57549 57550 } 57551 57552 /** 57553 * Frees the GPU-related resources allocated by this instance. Call this 57554 * method whenever this instance is no longer used in your app. 57555 */ 57556 dispose() { 57557 57558 this.geometry.dispose(); 57559 this.material.dispose(); 57560 57561 } 57562 57563 /** 57564 * Updates the helper to match the position of the 57565 * light being visualized. 57566 */ 57567 update() { 57568 57569 this.light.updateWorldMatrix( true, false ); 57570 57571 if ( this.color !== undefined ) { 57572 57573 this.material.color.set( this.color ); 57574 57575 } else { 57576 57577 this.material.color.copy( this.light.color ); 57578 57579 } 57580 57581 /* 57582 const d = this.light.distance; 57583 57584 if ( d === 0.0 ) { 57585 57586 this.lightDistance.visible = false; 57587 57588 } else { 57589 57590 this.lightDistance.visible = true; 57591 this.lightDistance.scale.set( d, d, d ); 57592 57593 } 57594 */ 57595 57596 } 57597 57598} 57599 57600const _vector$1 = /*@__PURE__*/ new Vector3(); 57601const _color1 = /*@__PURE__*/ new Color(); 57602const _color2 = /*@__PURE__*/ new Color(); 57603 57604/** 57605 * Creates a visual aid consisting of a spherical mesh for a 57606 * given {@link HemisphereLight}. 57607 * 57608 * When the hemisphere light is transformed or its light properties are changed, 57609 * it's necessary to call the `update()` method of the respective helper. 57610 * 57611 * ```js 57612 * const light = new THREE.HemisphereLight( 0xffffbb, 0x080820, 1 ); 57613 * const helper = new THREE.HemisphereLightHelper( light, 5 ); 57614 * scene.add( helper ); 57615 * ``` 57616 * 57617 * @augments Object3D 57618 */ 57619class HemisphereLightHelper extends Object3D { 57620 57621 /** 57622 * Constructs a new hemisphere light helper. 57623 * 57624 * @param {HemisphereLight} light - The light to be visualized. 57625 * @param {number} [size=1] - The size of the mesh used to visualize the light. 57626 * @param {number|Color|string} [color] - The helper's color. If not set, the helper will take 57627 * the color of the light. 57628 */ 57629 constructor( light, size, color ) { 57630 57631 super(); 57632 57633 /** 57634 * The light being visualized. 57635 * 57636 * @type {HemisphereLight} 57637 */ 57638 this.light = light; 57639 57640 this.matrix = light.matrixWorld; 57641 this.matrixAutoUpdate = false; 57642 57643 /** 57644 * The color parameter passed in the constructor. 57645 * If not set, the helper will take the color of the light. 57646 * 57647 * @type {number|Color|string} 57648 */ 57649 this.color = color; 57650 57651 this.type = 'HemisphereLightHelper'; 57652 57653 const geometry = new OctahedronGeometry( size ); 57654 geometry.rotateY( Math.PI * 0.5 ); 57655 57656 this.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } ); 57657 if ( this.color === undefined ) this.material.vertexColors = true; 57658 57659 const position = geometry.getAttribute( 'position' ); 57660 const colors = new Float32Array( position.count * 3 ); 57661 57662 geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) ); 57663 57664 this.add( new Mesh( geometry, this.material ) ); 57665 57666 this.update(); 57667 57668 } 57669 57670 /** 57671 * Frees the GPU-related resources allocated by this instance. Call this 57672 * method whenever this instance is no longer used in your app. 57673 */ 57674 dispose() { 57675 57676 this.children[ 0 ].geometry.dispose(); 57677 this.children[ 0 ].material.dispose(); 57678 57679 } 57680 57681 /** 57682 * Updates the helper to match the position and direction of the 57683 * light being visualized. 57684 */ 57685 update() { 57686 57687 const mesh = this.children[ 0 ]; 57688 57689 if ( this.color !== undefined ) { 57690 57691 this.material.color.set( this.color ); 57692 57693 } else { 57694 57695 const colors = mesh.geometry.getAttribute( 'color' ); 57696 57697 _color1.copy( this.light.color ); 57698 _color2.copy( this.light.groundColor ); 57699 57700 for ( let i = 0, l = colors.count; i < l; i ++ ) { 57701 57702 const color = ( i < ( l / 2 ) ) ? _color1 : _color2; 57703 57704 colors.setXYZ( i, color.r, color.g, color.b ); 57705 57706 } 57707 57708 colors.needsUpdate = true; 57709 57710 } 57711 57712 this.light.updateWorldMatrix( true, false ); 57713 57714 mesh.lookAt( _vector$1.setFromMatrixPosition( this.light.matrixWorld ).negate() ); 57715 57716 } 57717 57718} 57719 57720/** 57721 * The helper is an object to define grids. Grids are two-dimensional 57722 * arrays of lines. 57723 * 57724 * ```js 57725 * const size = 10; 57726 * const divisions = 10; 57727 * 57728 * const gridHelper = new THREE.GridHelper( size, divisions ); 57729 * scene.add( gridHelper ); 57730 * ``` 57731 * 57732 * @augments LineSegments 57733 */ 57734class GridHelper extends LineSegments { 57735 57736 /** 57737 * Constructs a new grid helper. 57738 * 57739 * @param {number} [size=10] - The size of the grid. 57740 * @param {number} [divisions=10] - The number of divisions across the grid. 57741 * @param {number|Color|string} [color1=0x444444] - The color of the center line. 57742 * @param {number|Color|string} [color2=0x888888] - The color of the lines of the grid. 57743 */ 57744 constructor( size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888 ) { 57745 57746 color1 = new Color( color1 ); 57747 color2 = new Color( color2 ); 57748 57749 const center = divisions / 2; 57750 const step = size / divisions; 57751 const halfSize = size / 2; 57752 57753 const vertices = [], colors = []; 57754 57755 for ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) { 57756 57757 vertices.push( - halfSize, 0, k, halfSize, 0, k ); 57758 vertices.push( k, 0, - halfSize, k, 0, halfSize ); 57759 57760 const color = i === center ? color1 : color2; 57761 57762 color.toArray( colors, j ); j += 3; 57763 color.toArray( colors, j ); j += 3; 57764 color.toArray( colors, j ); j += 3; 57765 color.toArray( colors, j ); j += 3; 57766 57767 } 57768 57769 const geometry = new BufferGeometry(); 57770 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 57771 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); 57772 57773 const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); 57774 57775 super( geometry, material ); 57776 57777 this.type = 'GridHelper'; 57778 57779 } 57780 57781 /** 57782 * Frees the GPU-related resources allocated by this instance. Call this 57783 * method whenever this instance is no longer used in your app. 57784 */ 57785 dispose() { 57786 57787 this.geometry.dispose(); 57788 this.material.dispose(); 57789 57790 } 57791 57792} 57793 57794/** 57795 * This helper is an object to define polar grids. Grids are 57796 * two-dimensional arrays of lines. 57797 * 57798 * ```js 57799 * const radius = 10; 57800 * const sectors = 16; 57801 * const rings = 8; 57802 * const divisions = 64; 57803 * 57804 * const helper = new THREE.PolarGridHelper( radius, sectors, rings, divisions ); 57805 * scene.add( helper ); 57806 * ``` 57807 * 57808 * @augments LineSegments 57809 */ 57810class PolarGridHelper extends LineSegments { 57811 57812 /** 57813 * Constructs a new polar grid helper. 57814 * 57815 * @param {number} [radius=10] - The radius of the polar grid. This can be any positive number. 57816 * @param {number} [sectors=16] - The number of sectors the grid will be divided into. This can be any positive integer. 57817 * @param {number} [rings=16] - The number of rings. This can be any positive integer. 57818 * @param {number} [divisions=64] - The number of line segments used for each circle. This can be any positive integer. 57819 * @param {number|Color|string} [color1=0x444444] - The first color used for grid elements. 57820 * @param {number|Color|string} [color2=0x888888] - The second color used for grid elements. 57821 */ 57822 constructor( radius = 10, sectors = 16, rings = 8, divisions = 64, color1 = 0x444444, color2 = 0x888888 ) { 57823 57824 color1 = new Color( color1 ); 57825 color2 = new Color( color2 ); 57826 57827 const vertices = []; 57828 const colors = []; 57829 57830 // create the sectors 57831 57832 if ( sectors > 1 ) { 57833 57834 for ( let i = 0; i < sectors; i ++ ) { 57835 57836 const v = ( i / sectors ) * ( Math.PI * 2 ); 57837 57838 const x = Math.sin( v ) * radius; 57839 const z = Math.cos( v ) * radius; 57840 57841 vertices.push( 0, 0, 0 ); 57842 vertices.push( x, 0, z ); 57843 57844 const color = ( i & 1 ) ? color1 : color2; 57845 57846 colors.push( color.r, color.g, color.b ); 57847 colors.push( color.r, color.g, color.b ); 57848 57849 } 57850 57851 } 57852 57853 // create the rings 57854 57855 for ( let i = 0; i < rings; i ++ ) { 57856 57857 const color = ( i & 1 ) ? color1 : color2; 57858 57859 const r = radius - ( radius / rings * i ); 57860 57861 for ( let j = 0; j < divisions; j ++ ) { 57862 57863 // first vertex 57864 57865 let v = ( j / divisions ) * ( Math.PI * 2 ); 57866 57867 let x = Math.sin( v ) * r; 57868 let z = Math.cos( v ) * r; 57869 57870 vertices.push( x, 0, z ); 57871 colors.push( color.r, color.g, color.b ); 57872 57873 // second vertex 57874 57875 v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 ); 57876 57877 x = Math.sin( v ) * r; 57878 z = Math.cos( v ) * r; 57879 57880 vertices.push( x, 0, z ); 57881 colors.push( color.r, color.g, color.b ); 57882 57883 } 57884 57885 } 57886 57887 const geometry = new BufferGeometry(); 57888 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 57889 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); 57890 57891 const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); 57892 57893 super( geometry, material ); 57894 57895 this.type = 'PolarGridHelper'; 57896 57897 } 57898 57899 /** 57900 * Frees the GPU-related resources allocated by this instance. Call this 57901 * method whenever this instance is no longer used in your app. 57902 */ 57903 dispose() { 57904 57905 this.geometry.dispose(); 57906 this.material.dispose(); 57907 57908 } 57909 57910} 57911 57912const _v1 = /*@__PURE__*/ new Vector3(); 57913const _v2 = /*@__PURE__*/ new Vector3(); 57914const _v3 = /*@__PURE__*/ new Vector3(); 57915 57916/** 57917 * Helper object to assist with visualizing a {@link DirectionalLight}'s 57918 * effect on the scene. This consists of a plane and a line representing the 57919 * light's position and direction. 57920 * 57921 * When the directional light or its target are transformed or light properties 57922 * are changed, it's necessary to call the `update()` method of the respective helper. 57923 * 57924 * ```js 57925 * const light = new THREE.DirectionalLight( 0xFFFFFF ); 57926 * scene.add( light ); 57927 * 57928 * const helper = new THREE.DirectionalLightHelper( light, 5 ); 57929 * scene.add( helper ); 57930 * ``` 57931 * 57932 * @augments Object3D 57933 */ 57934class DirectionalLightHelper extends Object3D { 57935 57936 /** 57937 * Constructs a new directional light helper. 57938 * 57939 * @param {DirectionalLight} light - The light to be visualized. 57940 * @param {number} [size=1] - The dimensions of the plane. 57941 * @param {number|Color|string} [color] - The helper's color. If not set, the helper will take 57942 * the color of the light. 57943 */ 57944 constructor( light, size, color ) { 57945 57946 super(); 57947 57948 /** 57949 * The light being visualized. 57950 * 57951 * @type {DirectionalLight} 57952 */ 57953 this.light = light; 57954 57955 this.matrix = light.matrixWorld; 57956 this.matrixAutoUpdate = false; 57957 57958 /** 57959 * The color parameter passed in the constructor. 57960 * If not set, the helper will take the color of the light. 57961 * 57962 * @type {number|Color|string} 57963 */ 57964 this.color = color; 57965 57966 this.type = 'DirectionalLightHelper'; 57967 57968 if ( size === undefined ) size = 1; 57969 57970 let geometry = new BufferGeometry(); 57971 geometry.setAttribute( 'position', new Float32BufferAttribute( [ 57972 - size, size, 0, 57973 size, size, 0, 57974 size, - size, 0, 57975 - size, - size, 0, 57976 - size, size, 0 57977 ], 3 ) ); 57978 57979 const material = new LineBasicMaterial( { fog: false, toneMapped: false } ); 57980 57981 /** 57982 * Contains the line showing the location of the directional light. 57983 * 57984 * @type {Line} 57985 */ 57986 this.lightPlane = new Line( geometry, material ); 57987 this.add( this.lightPlane ); 57988 57989 geometry = new BufferGeometry(); 57990 geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) ); 57991 57992 /** 57993 * Represents the target line of the directional light. 57994 * 57995 * @type {Line} 57996 */ 57997 this.targetLine = new Line( geometry, material ); 57998 this.add( this.targetLine ); 57999 58000 this.update(); 58001 58002 } 58003 58004 /** 58005 * Frees the GPU-related resources allocated by this instance. Call this 58006 * method whenever this instance is no longer used in your app. 58007 */ 58008 dispose() { 58009 58010 this.lightPlane.geometry.dispose(); 58011 this.lightPlane.material.dispose(); 58012 this.targetLine.geometry.dispose(); 58013 this.targetLine.material.dispose(); 58014 58015 } 58016 58017 /** 58018 * Updates the helper to match the position and direction of the 58019 * light being visualized. 58020 */ 58021 update() {
vendor: 10,100 bytes, lines 58021-58358
58021 58022 58023 this.light.updateWorldMatrix( true, false ); 58024 this.light.target.updateWorldMatrix( true, false ); 58025 58026 _v1.setFromMatrixPosition( this.light.matrixWorld ); 58027 _v2.setFromMatrixPosition( this.light.target.matrixWorld ); 58028 _v3.subVectors( _v2, _v1 ); 58029 58030 this.lightPlane.lookAt( _v2 ); 58031 58032 if ( this.color !== undefined ) { 58033 58034 this.lightPlane.material.color.set( this.color ); 58035 this.targetLine.material.color.set( this.color ); 58036 58037 } else { 58038 58039 this.lightPlane.material.color.copy( this.light.color ); 58040 this.targetLine.material.color.copy( this.light.color ); 58041 58042 } 58043 58044 this.targetLine.lookAt( _v2 ); 58045 this.targetLine.scale.z = _v3.length(); 58046 58047 } 58048 58049} 58050 58051const _vector = /*@__PURE__*/ new Vector3(); 58052const _camera = /*@__PURE__*/ new Camera(); 58053 58054/** 58055 * This helps with visualizing what a camera contains in its frustum. It 58056 * visualizes the frustum of a camera using a line segments. 58057 * 58058 * Based on frustum visualization in [lightgl.js shadowmap example](https://github.com/evanw/lightgl.js/blob/master/tests/shadowmap.html). 58059 * 58060 * `CameraHelper` must be a child of the scene. 58061 * 58062 * When the camera is transformed or its projection matrix is changed, it's necessary 58063 * to call the `update()` method of the respective helper. 58064 * 58065 * ```js 58066 * const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); 58067 * const helper = new THREE.CameraHelper( camera ); 58068 * scene.add( helper ); 58069 * ``` 58070 * 58071 * @augments LineSegments 58072 */ 58073class CameraHelper extends LineSegments { 58074 58075 /** 58076 * Constructs a new arrow helper. 58077 * 58078 * @param {Camera} camera - The camera to visualize. 58079 */ 58080 constructor( camera ) { 58081 58082 const geometry = new BufferGeometry(); 58083 const material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } ); 58084 58085 const vertices = []; 58086 const colors = []; 58087 58088 const pointMap = {}; 58089 58090 // near 58091 58092 addLine( 'n1', 'n2' ); 58093 addLine( 'n2', 'n4' ); 58094 addLine( 'n4', 'n3' ); 58095 addLine( 'n3', 'n1' ); 58096 58097 // far 58098 58099 addLine( 'f1', 'f2' ); 58100 addLine( 'f2', 'f4' ); 58101 addLine( 'f4', 'f3' ); 58102 addLine( 'f3', 'f1' ); 58103 58104 // sides 58105 58106 addLine( 'n1', 'f1' ); 58107 addLine( 'n2', 'f2' ); 58108 addLine( 'n3', 'f3' ); 58109 addLine( 'n4', 'f4' ); 58110 58111 // cone 58112 58113 addLine( 'p', 'n1' ); 58114 addLine( 'p', 'n2' ); 58115 addLine( 'p', 'n3' ); 58116 addLine( 'p', 'n4' ); 58117 58118 // up 58119 58120 addLine( 'u1', 'u2' ); 58121 addLine( 'u2', 'u3' ); 58122 addLine( 'u3', 'u1' ); 58123 58124 // target 58125 58126 addLine( 'c', 't' ); 58127 addLine( 'p', 'c' ); 58128 58129 // cross 58130 58131 addLine( 'cn1', 'cn2' ); 58132 addLine( 'cn3', 'cn4' ); 58133 58134 addLine( 'cf1', 'cf2' ); 58135 addLine( 'cf3', 'cf4' ); 58136 58137 function addLine( a, b ) { 58138 58139 addPoint( a ); 58140 addPoint( b ); 58141 58142 } 58143 58144 function addPoint( id ) { 58145 58146 vertices.push( 0, 0, 0 ); 58147 colors.push( 0, 0, 0 ); 58148 58149 if ( pointMap[ id ] === undefined ) { 58150 58151 pointMap[ id ] = []; 58152 58153 } 58154 58155 pointMap[ id ].push( ( vertices.length / 3 ) - 1 ); 58156 58157 } 58158 58159 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 58160 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); 58161 58162 super( geometry, material ); 58163 58164 this.type = 'CameraHelper'; 58165 58166 /** 58167 * The camera being visualized. 58168 * 58169 * @type {Camera} 58170 */ 58171 this.camera = camera; 58172 if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix(); 58173 58174 this.matrix = camera.matrixWorld; 58175 this.matrixAutoUpdate = false; 58176 58177 /** 58178 * This contains the points used to visualize the camera. 58179 * 58180 * @type {Object<string,Array<number>>} 58181 */ 58182 this.pointMap = pointMap; 58183 58184 this.update(); 58185 58186 // colors 58187 58188 const colorFrustum = new Color( 0xffaa00 ); 58189 const colorCone = new Color( 0xff0000 ); 58190 const colorUp = new Color( 0x00aaff ); 58191 const colorTarget = new Color( 0xffffff ); 58192 const colorCross = new Color( 0x333333 ); 58193 58194 this.setColors( colorFrustum, colorCone, colorUp, colorTarget, colorCross ); 58195 58196 } 58197 58198 /** 58199 * Defines the colors of the helper. 58200 * 58201 * @param {Color} frustum - The frustum line color. 58202 * @param {Color} cone - The cone line color. 58203 * @param {Color} up - The up line color. 58204 * @param {Color} target - The target line color. 58205 * @param {Color} cross - The cross line color. 58206 * @return {CameraHelper} A reference to this helper. 58207 */ 58208 setColors( frustum, cone, up, target, cross ) { 58209 58210 const geometry = this.geometry; 58211 58212 const colorAttribute = geometry.getAttribute( 'color' ); 58213 58214 // near 58215 58216 colorAttribute.setXYZ( 0, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 1, frustum.r, frustum.g, frustum.b ); // n1, n2 58217 colorAttribute.setXYZ( 2, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 3, frustum.r, frustum.g, frustum.b ); // n2, n4 58218 colorAttribute.setXYZ( 4, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 5, frustum.r, frustum.g, frustum.b ); // n4, n3 58219 colorAttribute.setXYZ( 6, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 7, frustum.r, frustum.g, frustum.b ); // n3, n1 58220 58221 // far 58222 58223 colorAttribute.setXYZ( 8, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 9, frustum.r, frustum.g, frustum.b ); // f1, f2 58224 colorAttribute.setXYZ( 10, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 11, frustum.r, frustum.g, frustum.b ); // f2, f4 58225 colorAttribute.setXYZ( 12, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 13, frustum.r, frustum.g, frustum.b ); // f4, f3 58226 colorAttribute.setXYZ( 14, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 15, frustum.r, frustum.g, frustum.b ); // f3, f1 58227 58228 // sides 58229 58230 colorAttribute.setXYZ( 16, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 17, frustum.r, frustum.g, frustum.b ); // n1, f1 58231 colorAttribute.setXYZ( 18, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 19, frustum.r, frustum.g, frustum.b ); // n2, f2 58232 colorAttribute.setXYZ( 20, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 21, frustum.r, frustum.g, frustum.b ); // n3, f3 58233 colorAttribute.setXYZ( 22, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 23, frustum.r, frustum.g, frustum.b ); // n4, f4 58234 58235 // cone 58236 58237 colorAttribute.setXYZ( 24, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 25, cone.r, cone.g, cone.b ); // p, n1 58238 colorAttribute.setXYZ( 26, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 27, cone.r, cone.g, cone.b ); // p, n2 58239 colorAttribute.setXYZ( 28, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 29, cone.r, cone.g, cone.b ); // p, n3 58240 colorAttribute.setXYZ( 30, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 31, cone.r, cone.g, cone.b ); // p, n4 58241 58242 // up 58243 58244 colorAttribute.setXYZ( 32, up.r, up.g, up.b ); colorAttribute.setXYZ( 33, up.r, up.g, up.b ); // u1, u2 58245 colorAttribute.setXYZ( 34, up.r, up.g, up.b ); colorAttribute.setXYZ( 35, up.r, up.g, up.b ); // u2, u3 58246 colorAttribute.setXYZ( 36, up.r, up.g, up.b ); colorAttribute.setXYZ( 37, up.r, up.g, up.b ); // u3, u1 58247 58248 // target 58249 58250 colorAttribute.setXYZ( 38, target.r, target.g, target.b ); colorAttribute.setXYZ( 39, target.r, target.g, target.b ); // c, t 58251 colorAttribute.setXYZ( 40, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 41, cross.r, cross.g, cross.b ); // p, c 58252 58253 // cross 58254 58255 colorAttribute.setXYZ( 42, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 43, cross.r, cross.g, cross.b ); // cn1, cn2 58256 colorAttribute.setXYZ( 44, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 45, cross.r, cross.g, cross.b ); // cn3, cn4 58257 58258 colorAttribute.setXYZ( 46, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 47, cross.r, cross.g, cross.b ); // cf1, cf2 58259 colorAttribute.setXYZ( 48, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 49, cross.r, cross.g, cross.b ); // cf3, cf4 58260 58261 colorAttribute.needsUpdate = true; 58262 58263 return this; 58264 58265 } 58266 58267 /** 58268 * Updates the helper based on the projection matrix of the camera. 58269 */ 58270 update() { 58271 58272 const geometry = this.geometry; 58273 const pointMap = this.pointMap; 58274 58275 const w = 1, h = 1; 58276 58277 let nearZ, farZ; 58278 58279 // we need just camera projection matrix inverse 58280 // world matrix must be identity 58281 58282 _camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse ); 58283 58284 // Adjust z values based on coordinate system 58285 58286 if ( this.camera.reversedDepth === true ) { 58287 58288 nearZ = 1; 58289 farZ = 0; 58290 58291 } else { 58292 58293 if ( this.camera.coordinateSystem === WebGLCoordinateSystem ) { 58294 58295 nearZ = -1; 58296 farZ = 1; 58297 58298 } else if ( this.camera.coordinateSystem === WebGPUCoordinateSystem ) { 58299 58300 nearZ = 0; 58301 farZ = 1; 58302 58303 } else { 58304 58305 throw new Error( 'THREE.CameraHelper.update(): Invalid coordinate system: ' + this.camera.coordinateSystem ); 58306 58307 } 58308 58309 } 58310 58311 58312 // center / target 58313 setPoint( 'c', pointMap, geometry, _camera, 0, 0, nearZ ); 58314 setPoint( 't', pointMap, geometry, _camera, 0, 0, farZ ); 58315 58316 // near 58317 58318 setPoint( 'n1', pointMap, geometry, _camera, - w, - h, nearZ ); 58319 setPoint( 'n2', pointMap, geometry, _camera, w, - h, nearZ ); 58320 setPoint( 'n3', pointMap, geometry, _camera, - w, h, nearZ ); 58321 setPoint( 'n4', pointMap, geometry, _camera, w, h, nearZ ); 58322 58323 // far 58324 58325 setPoint( 'f1', pointMap, geometry, _camera, - w, - h, farZ ); 58326 setPoint( 'f2', pointMap, geometry, _camera, w, - h, farZ ); 58327 setPoint( 'f3', pointMap, geometry, _camera, - w, h, farZ ); 58328 setPoint( 'f4', pointMap, geometry, _camera, w, h, farZ ); 58329 58330 // up 58331 58332 setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, nearZ ); 58333 setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, nearZ ); 58334 setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, nearZ ); 58335 58336 // cross 58337 58338 setPoint( 'cf1', pointMap, geometry, _camera, - w, 0, farZ ); 58339 setPoint( 'cf2', pointMap, geometry, _camera, w, 0, farZ ); 58340 setPoint( 'cf3', pointMap, geometry, _camera, 0, - h, farZ ); 58341 setPoint( 'cf4', pointMap, geometry, _camera, 0, h, farZ ); 58342 58343 setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, nearZ ); 58344 setPoint( 'cn2', pointMap, geometry, _camera, w, 0, nearZ ); 58345 setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, nearZ ); 58346 setPoint( 'cn4', pointMap, geometry, _camera, 0, h, nearZ ); 58347 58348 geometry.getAttribute( 'position' ).needsUpdate = true; 58349 58350 } 58351 58352 /** 58353 * Frees the GPU-related resources allocated by this instance. Call this 58354 * method whenever this instance is no longer used in your app. 58355 */ 58356 dispose() { 58357 58358
vendor: 12,560 bytes, lines 58358-58895
58358this.geometry.dispose(); 58359 this.material.dispose(); 58360 58361 } 58362 58363} 58364 58365 58366function setPoint( point, pointMap, geometry, camera, x, y, z ) { 58367 58368 _vector.set( x, y, z ).unproject( camera ); 58369 58370 const points = pointMap[ point ]; 58371 58372 if ( points !== undefined ) { 58373 58374 const position = geometry.getAttribute( 'position' ); 58375 58376 for ( let i = 0, l = points.length; i < l; i ++ ) { 58377 58378 position.setXYZ( points[ i ], _vector.x, _vector.y, _vector.z ); 58379 58380 } 58381 58382 } 58383 58384} 58385 58386const _box = /*@__PURE__*/ new Box3(); 58387 58388/** 58389 * Helper object to graphically show the world-axis-aligned bounding box 58390 * around an object. The actual bounding box is handled with {@link Box3}, 58391 * this is just a visual helper for debugging. It can be automatically 58392 * resized with {@link BoxHelper#update} when the object it's created from 58393 * is transformed. Note that the object must have a geometry for this to work, 58394 * so it won't work with sprites. 58395 * 58396 * ```js 58397 * const sphere = new THREE.SphereGeometry(); 58398 * const object = new THREE.Mesh( sphere, new THREE.MeshBasicMaterial( 0xff0000 ) ); 58399 * const box = new THREE.BoxHelper( object, 0xffff00 ); 58400 * scene.add( box ); 58401 * ``` 58402 * 58403 * @augments LineSegments 58404 */ 58405class BoxHelper extends LineSegments { 58406 58407 /** 58408 * Constructs a new box helper. 58409 * 58410 * @param {Object3D} [object] - The 3D object to show the world-axis-aligned bounding box. 58411 * @param {number|Color|string} [color=0xffff00] - The box's color. 58412 */ 58413 constructor( object, color = 0xffff00 ) { 58414 58415 const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); 58416 const positions = new Float32Array( 8 * 3 ); 58417 58418 const geometry = new BufferGeometry(); 58419 geometry.setIndex( new BufferAttribute( indices, 1 ) ); 58420 geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) ); 58421 58422 super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); 58423 58424 /** 58425 * The 3D object being visualized. 58426 * 58427 * @type {Object3D} 58428 */ 58429 this.object = object; 58430 this.type = 'BoxHelper'; 58431 58432 this.matrixAutoUpdate = false; 58433 58434 this.update(); 58435 58436 } 58437 58438 /** 58439 * Updates the helper's geometry to match the dimensions of the object, 58440 * including any children. 58441 */ 58442 update() { 58443 58444 if ( this.object !== undefined ) { 58445 58446 _box.setFromObject( this.object ); 58447 58448 } 58449 58450 if ( _box.isEmpty() ) return; 58451 58452 const min = _box.min; 58453 const max = _box.max; 58454 58455 /* 58456 5____4 58457 1/___0/| 58458 | 6__|_7 58459 2/___3/ 58460 58461 0: max.x, max.y, max.z 58462 1: min.x, max.y, max.z 58463 2: min.x, min.y, max.z 58464 3: max.x, min.y, max.z 58465 4: max.x, max.y, min.z 58466 5: min.x, max.y, min.z 58467 6: min.x, min.y, min.z 58468 7: max.x, min.y, min.z 58469 */ 58470 58471 const position = this.geometry.attributes.position; 58472 const array = position.array; 58473 58474 array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z; 58475 array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z; 58476 array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z; 58477 array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z; 58478 array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z; 58479 array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z; 58480 array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z; 58481 array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z; 58482 58483 position.needsUpdate = true; 58484 58485 this.geometry.computeBoundingSphere(); 58486 58487 } 58488 58489 /** 58490 * Updates the wireframe box for the passed object. 58491 * 58492 * @param {Object3D} object - The 3D object to create the helper for. 58493 * @return {BoxHelper} A reference to this instance. 58494 */ 58495 setFromObject( object ) { 58496 58497 this.object = object; 58498 this.update(); 58499 58500 return this; 58501 58502 } 58503 58504 copy( source, recursive ) { 58505 58506 super.copy( source, recursive ); 58507 58508 this.object = source.object; 58509 58510 return this; 58511 58512 } 58513 58514 /** 58515 * Frees the GPU-related resources allocated by this instance. Call this 58516 * method whenever this instance is no longer used in your app. 58517 */ 58518 dispose() { 58519 58520 this.geometry.dispose(); 58521 this.material.dispose(); 58522 58523 } 58524 58525} 58526 58527/** 58528 * A helper object to visualize an instance of {@link Box3}. 58529 * 58530 * ```js 58531 * const box = new THREE.Box3(); 58532 * box.setFromCenterAndSize( new THREE.Vector3( 1, 1, 1 ), new THREE.Vector3( 2, 1, 3 ) ); 58533 * 58534 * const helper = new THREE.Box3Helper( box, 0xffff00 ); 58535 * scene.add( helper ) 58536 * ``` 58537 * 58538 * @augments LineSegments 58539 */ 58540class Box3Helper extends LineSegments { 58541 58542 /** 58543 * Constructs a new box3 helper. 58544 * 58545 * @param {Box3} box - The box to visualize. 58546 * @param {number|Color|string} [color=0xffff00] - The box's color. 58547 */ 58548 constructor( box, color = 0xffff00 ) { 58549 58550 const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] ); 58551 58552 const positions = [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1 ]; 58553 58554 const geometry = new BufferGeometry(); 58555 58556 geometry.setIndex( new BufferAttribute( indices, 1 ) ); 58557 58558 geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); 58559 58560 super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); 58561 58562 /** 58563 * The box being visualized. 58564 * 58565 * @type {Box3} 58566 */ 58567 this.box = box; 58568 58569 this.type = 'Box3Helper'; 58570 58571 this.geometry.computeBoundingSphere(); 58572 58573 } 58574 58575 updateMatrixWorld( force ) { 58576 58577 const box = this.box; 58578 58579 if ( box.isEmpty() ) return; 58580 58581 box.getCenter( this.position ); 58582 58583 box.getSize( this.scale ); 58584 58585 this.scale.multiplyScalar( 0.5 ); 58586 58587 super.updateMatrixWorld( force ); 58588 58589 } 58590 58591 /** 58592 * Frees the GPU-related resources allocated by this instance. Call this 58593 * method whenever this instance is no longer used in your app. 58594 */ 58595 dispose() { 58596 58597 this.geometry.dispose(); 58598 this.material.dispose(); 58599 58600 } 58601 58602} 58603 58604/** 58605 * A helper object to visualize an instance of {@link Plane}. 58606 * 58607 * ```js 58608 * const plane = new THREE.Plane( new THREE.Vector3( 1, 1, 0.2 ), 3 ); 58609 * const helper = new THREE.PlaneHelper( plane, 1, 0xffff00 ); 58610 * scene.add( helper ); 58611 * ``` 58612 * 58613 * @augments Line 58614 */ 58615class PlaneHelper extends Line { 58616 58617 /** 58618 * Constructs a new plane helper. 58619 * 58620 * @param {Plane} plane - The plane to be visualized. 58621 * @param {number} [size=1] - The side length of plane helper. 58622 * @param {number|Color|string} [hex=0xffff00] - The helper's color. 58623 */ 58624 constructor( plane, size = 1, hex = 0xffff00 ) { 58625 58626 const color = hex; 58627 58628 const positions = [ 1, -1, 0, -1, 1, 0, -1, -1, 0, 1, 1, 0, -1, 1, 0, -1, -1, 0, 1, -1, 0, 1, 1, 0 ]; 58629 58630 const geometry = new BufferGeometry(); 58631 geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); 58632 geometry.computeBoundingSphere(); 58633 58634 super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); 58635 58636 this.type = 'PlaneHelper'; 58637 58638 /** 58639 * The plane being visualized. 58640 * 58641 * @type {Plane} 58642 */ 58643 this.plane = plane; 58644 58645 /** 58646 * The side length of plane helper. 58647 * 58648 * @type {number} 58649 * @default 1 58650 */ 58651 this.size = size; 58652 58653 const positions2 = [ 1, 1, 0, -1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0 ]; 58654 58655 const geometry2 = new BufferGeometry(); 58656 geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) ); 58657 geometry2.computeBoundingSphere(); 58658 58659 this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) ); 58660 58661 } 58662 58663 updateMatrixWorld( force ) { 58664 58665 this.position.set( 0, 0, 0 ); 58666 58667 this.scale.set( 0.5 * this.size, 0.5 * this.size, 1 ); 58668 58669 this.lookAt( this.plane.normal ); 58670 58671 this.translateZ( - this.plane.constant ); 58672 58673 super.updateMatrixWorld( force ); 58674 58675 } 58676 58677 /** 58678 * Updates the helper to match the position and direction of the 58679 * light being visualized. 58680 */ 58681 dispose() { 58682 58683 this.geometry.dispose(); 58684 this.material.dispose(); 58685 this.children[ 0 ].geometry.dispose(); 58686 this.children[ 0 ].material.dispose(); 58687 58688 } 58689 58690} 58691 58692const _axis = /*@__PURE__*/ new Vector3(); 58693let _lineGeometry, _coneGeometry; 58694 58695/** 58696 * An 3D arrow object for visualizing directions. 58697 * 58698 * ```js 58699 * const dir = new THREE.Vector3( 1, 2, 0 ); 58700 * 58701 * //normalize the direction vector (convert to vector of length 1) 58702 * dir.normalize(); 58703 * 58704 * const origin = new THREE.Vector3( 0, 0, 0 ); 58705 * const length = 1; 58706 * const hex = 0xffff00; 58707 * 58708 * const arrowHelper = new THREE.ArrowHelper( dir, origin, length, hex ); 58709 * scene.add( arrowHelper ); 58710 * ``` 58711 * 58712 * @augments Object3D 58713 */ 58714class ArrowHelper extends Object3D { 58715 58716 /** 58717 * Constructs a new arrow helper. 58718 * 58719 * @param {Vector3} [dir=(0, 0, 1)] - The (normalized) direction vector. 58720 * @param {Vector3} [origin=(0, 0, 0)] - Point at which the arrow starts. 58721 * @param {number} [length=1] - Length of the arrow in world units. 58722 * @param {(number|Color|string)} [color=0xffff00] - Color of the arrow. 58723 * @param {number} [headLength=length*0.2] - The length of the head of the arrow. 58724 * @param {number} [headWidth=headLength*0.2] - The width of the head of the arrow. 58725 */ 58726 constructor( dir = new Vector3( 0, 0, 1 ), origin = new Vector3( 0, 0, 0 ), length = 1, color = 0xffff00, headLength = length * 0.2, headWidth = headLength * 0.2 ) { 58727 58728 super(); 58729 58730 this.type = 'ArrowHelper'; 58731 58732 if ( _lineGeometry === undefined ) { 58733 58734 _lineGeometry = new BufferGeometry(); 58735 _lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) ); 58736 58737 _coneGeometry = new ConeGeometry( 0.5, 1, 5, 1 ); 58738 _coneGeometry.translate( 0, -0.5, 0 ); 58739 58740 } 58741 58742 this.position.copy( origin ); 58743 58744 /** 58745 * The line part of the arrow helper. 58746 * 58747 * @type {Line} 58748 */ 58749 this.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) ); 58750 this.line.matrixAutoUpdate = false; 58751 this.add( this.line ); 58752 58753 /** 58754 * The cone part of the arrow helper. 58755 * 58756 * @type {Mesh} 58757 */ 58758 this.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) ); 58759 this.cone.matrixAutoUpdate = false; 58760 this.add( this.cone ); 58761 58762 this.setDirection( dir ); 58763 this.setLength( length, headLength, headWidth ); 58764 58765 } 58766 58767 /** 58768 * Sets the direction of the helper. 58769 * 58770 * @param {Vector3} dir - The normalized direction vector. 58771 */ 58772 setDirection( dir ) { 58773 58774 // dir is assumed to be normalized 58775 58776 if ( dir.y > 0.99999 ) { 58777 58778 this.quaternion.set( 0, 0, 0, 1 ); 58779 58780 } else if ( dir.y < -0.99999 ) { 58781 58782 this.quaternion.set( 1, 0, 0, 0 ); 58783 58784 } else { 58785 58786 _axis.set( dir.z, 0, - dir.x ).normalize(); 58787 58788 const radians = Math.acos( dir.y ); 58789 58790 this.quaternion.setFromAxisAngle( _axis, radians ); 58791 58792 } 58793 58794 } 58795 58796 /** 58797 * Sets the length of the helper. 58798 * 58799 * @param {number} length - Length of the arrow in world units. 58800 * @param {number} [headLength=length*0.2] - The length of the head of the arrow. 58801 * @param {number} [headWidth=headLength*0.2] - The width of the head of the arrow. 58802 */ 58803 setLength( length, headLength = length * 0.2, headWidth = headLength * 0.2 ) { 58804 58805 this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458 58806 this.line.updateMatrix(); 58807 58808 this.cone.scale.set( headWidth, headLength, headWidth ); 58809 this.cone.position.y = length; 58810 this.cone.updateMatrix(); 58811 58812 } 58813 58814 /** 58815 * Sets the color of the helper. 58816 * 58817 * @param {number|Color|string} color - The color to set. 58818 */ 58819 setColor( color ) { 58820 58821 this.line.material.color.set( color ); 58822 this.cone.material.color.set( color ); 58823 58824 } 58825 58826 copy( source ) { 58827 58828 super.copy( source, false ); 58829 58830 this.line.copy( source.line ); 58831 this.cone.copy( source.cone ); 58832 58833 return this; 58834 58835 } 58836 58837 /** 58838 * Frees the GPU-related resources allocated by this instance. Call this 58839 * method whenever this instance is no longer used in your app. 58840 */ 58841 dispose() { 58842 58843 this.line.geometry.dispose(); 58844 this.line.material.dispose(); 58845 this.cone.geometry.dispose(); 58846 this.cone.material.dispose(); 58847 58848 } 58849 58850} 58851 58852/** 58853 * An axis object to visualize the 3 axes in a simple way. 58854 * The X axis is red. The Y axis is green. The Z axis is blue. 58855 * 58856 * ```js 58857 * const axesHelper = new THREE.AxesHelper( 5 ); 58858 * scene.add( axesHelper ); 58859 * ``` 58860 * 58861 * @augments LineSegments 58862 */ 58863class AxesHelper extends LineSegments { 58864 58865 /** 58866 * Constructs a new axes helper. 58867 * 58868 * @param {number} [size=1] - Size of the lines representing the axes. 58869 */ 58870 constructor( size = 1 ) { 58871 58872 const vertices = [ 58873 0, 0, 0, size, 0, 0, 58874 0, 0, 0, 0, size, 0, 58875 0, 0, 0, 0, 0, size 58876 ]; 58877 58878 const colors = [ 58879 1, 0, 0, 1, 0.6, 0, 58880 0, 1, 0, 0.6, 1, 0, 58881 0, 0, 1, 0, 0.6, 1 58882 ]; 58883 58884 const geometry = new BufferGeometry(); 58885 geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); 58886 geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) ); 58887 58888 const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } ); 58889 58890 super( geometry, material ); 58891 58892 this.type = 'AxesHelper'; 58893 58894 } 58895
vendor: 9,197 bytes, lines 58896-59300
58896 /** 58897 * Defines the colors of the axes helper. 58898 * 58899 * @param {number|Color|string} xAxisColor - The color for the x axis. 58900 * @param {number|Color|string} yAxisColor - The color for the y axis. 58901 * @param {number|Color|string} zAxisColor - The color for the z axis. 58902 * @return {AxesHelper} A reference to this axes helper. 58903 */ 58904 setColors( xAxisColor, yAxisColor, zAxisColor ) { 58905 58906 const color = new Color(); 58907 const array = this.geometry.attributes.color.array; 58908 58909 color.set( xAxisColor ); 58910 color.toArray( array, 0 ); 58911 color.toArray( array, 3 ); 58912 58913 color.set( yAxisColor ); 58914 color.toArray( array, 6 ); 58915 color.toArray( array, 9 ); 58916 58917 color.set( zAxisColor ); 58918 color.toArray( array, 12 ); 58919 color.toArray( array, 15 ); 58920 58921 this.geometry.attributes.color.needsUpdate = true; 58922 58923 return this; 58924 58925 } 58926 58927 /** 58928 * Frees the GPU-related resources allocated by this instance. Call this 58929 * method whenever this instance is no longer used in your app. 58930 */ 58931 dispose() { 58932 58933 this.geometry.dispose(); 58934 this.material.dispose(); 58935 58936 } 58937 58938} 58939 58940/** 58941 * This class is used to convert a series of paths to an array of 58942 * shapes. It is specifically used in context of fonts and SVG. 58943 */ 58944class ShapePath { 58945 58946 /** 58947 * Constructs a new shape path. 58948 */ 58949 constructor() { 58950 58951 this.type = 'ShapePath'; 58952 58953 /** 58954 * The color of the shape. 58955 * 58956 * @type {Color} 58957 */ 58958 this.color = new Color(); 58959 58960 /** 58961 * The paths that have been generated for this shape. 58962 * 58963 * @type {Array<Path>} 58964 * @default null 58965 */ 58966 this.subPaths = []; 58967 58968 /** 58969 * The current path that is being generated. 58970 * 58971 * @type {?Path} 58972 * @default null 58973 */ 58974 this.currentPath = null; 58975 58976 } 58977 58978 /** 58979 * Creates a new path and moves it current point to the given one. 58980 * 58981 * @param {number} x - The x coordinate. 58982 * @param {number} y - The y coordinate. 58983 * @return {ShapePath} A reference to this shape path. 58984 */ 58985 moveTo( x, y ) { 58986 58987 this.currentPath = new Path(); 58988 this.subPaths.push( this.currentPath ); 58989 this.currentPath.moveTo( x, y ); 58990 58991 return this; 58992 58993 } 58994 58995 /** 58996 * Adds an instance of {@link LineCurve} to the path by connecting 58997 * the current point with the given one. 58998 * 58999 * @param {number} x - The x coordinate of the end point. 59000 * @param {number} y - The y coordinate of the end point. 59001 * @return {ShapePath} A reference to this shape path. 59002 */ 59003 lineTo( x, y ) { 59004 59005 this.currentPath.lineTo( x, y ); 59006 59007 return this; 59008 59009 } 59010 59011 /** 59012 * Adds an instance of {@link QuadraticBezierCurve} to the path by connecting 59013 * the current point with the given one. 59014 * 59015 * @param {number} aCPx - The x coordinate of the control point. 59016 * @param {number} aCPy - The y coordinate of the control point. 59017 * @param {number} aX - The x coordinate of the end point. 59018 * @param {number} aY - The y coordinate of the end point. 59019 * @return {ShapePath} A reference to this shape path. 59020 */ 59021 quadraticCurveTo( aCPx, aCPy, aX, aY ) { 59022 59023 this.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY ); 59024 59025 return this; 59026 59027 } 59028 59029 /** 59030 * Adds an instance of {@link CubicBezierCurve} to the path by connecting 59031 * the current point with the given one. 59032 * 59033 * @param {number} aCP1x - The x coordinate of the first control point. 59034 * @param {number} aCP1y - The y coordinate of the first control point. 59035 * @param {number} aCP2x - The x coordinate of the second control point. 59036 * @param {number} aCP2y - The y coordinate of the second control point. 59037 * @param {number} aX - The x coordinate of the end point. 59038 * @param {number} aY - The y coordinate of the end point. 59039 * @return {ShapePath} A reference to this shape path. 59040 */ 59041 bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { 59042 59043 this.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ); 59044 59045 return this; 59046 59047 } 59048 59049 /** 59050 * Adds an instance of {@link SplineCurve} to the path by connecting 59051 * the current point with the given list of points. 59052 * 59053 * @param {Array<Vector2>} pts - An array of points in 2D space. 59054 * @return {ShapePath} A reference to this shape path. 59055 */ 59056 splineThru( pts ) { 59057 59058 this.currentPath.splineThru( pts ); 59059 59060 return this; 59061 59062 } 59063 59064 /** 59065 * Converts the paths into an array of shapes. 59066 * 59067 * @param {boolean} isCCW - By default solid shapes are defined clockwise (CW) and holes are defined counterclockwise (CCW). 59068 * If this flag is set to `true`, then those are flipped. 59069 * @return {Array<Shape>} An array of shapes. 59070 */ 59071 toShapes( isCCW ) { 59072 59073 function toShapesNoHoles( inSubpaths ) { 59074 59075 const shapes = []; 59076 59077 for ( let i = 0, l = inSubpaths.length; i < l; i ++ ) { 59078 59079 const tmpPath = inSubpaths[ i ]; 59080 59081 const tmpShape = new Shape(); 59082 tmpShape.curves = tmpPath.curves; 59083 59084 shapes.push( tmpShape ); 59085 59086 } 59087 59088 return shapes; 59089 59090 } 59091 59092 function isPointInsidePolygon( inPt, inPolygon ) { 59093 59094 const polyLen = inPolygon.length; 59095 59096 // inPt on polygon contour => immediate success or 59097 // toggling of inside/outside at every single! intersection point of an edge 59098 // with the horizontal line through inPt, left of inPt 59099 // not counting lowerY endpoints of edges and whole edges on that line 59100 let inside = false; 59101 for ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) { 59102 59103 let edgeLowPt = inPolygon[ p ]; 59104 let edgeHighPt = inPolygon[ q ]; 59105 59106 let edgeDx = edgeHighPt.x - edgeLowPt.x; 59107 let edgeDy = edgeHighPt.y - edgeLowPt.y; 59108 59109 if ( Math.abs( edgeDy ) > Number.EPSILON ) { 59110 59111 // not parallel 59112 if ( edgeDy < 0 ) { 59113 59114 edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx; 59115 edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy; 59116 59117 } 59118 59119 if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; 59120 59121 if ( inPt.y === edgeLowPt.y ) { 59122 59123 if ( inPt.x === edgeLowPt.x ) return true; // inPt is on contour ? 59124 // continue; // no intersection or edgeLowPt => doesn't count !!! 59125 59126 } else { 59127 59128 const perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y ); 59129 if ( perpEdge === 0 ) return true; // inPt is on contour ? 59130 if ( perpEdge < 0 ) continue; 59131 inside = ! inside; // true intersection left of inPt 59132 59133 } 59134 59135 } else { 59136 59137 // parallel or collinear 59138 if ( inPt.y !== edgeLowPt.y ) continue; // parallel 59139 // edge lies on the same horizontal line as inPt 59140 if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) || 59141 ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour ! 59142 // continue; 59143 59144 } 59145 59146 } 59147 59148 return inside; 59149 59150 } 59151 59152 const isClockWise = ShapeUtils.isClockWise; 59153 59154 const subPaths = this.subPaths; 59155 if ( subPaths.length === 0 ) return []; 59156 59157 let solid, tmpPath, tmpShape; 59158 const shapes = []; 59159 59160 if ( subPaths.length === 1 ) { 59161 59162 tmpPath = subPaths[ 0 ]; 59163 tmpShape = new Shape(); 59164 tmpShape.curves = tmpPath.curves; 59165 shapes.push( tmpShape ); 59166 return shapes; 59167 59168 } 59169 59170 let holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() ); 59171 holesFirst = isCCW ? ! holesFirst : holesFirst; 59172 59173 // log("Holes first", holesFirst); 59174 59175 const betterShapeHoles = []; 59176 const newShapes = []; 59177 let newShapeHoles = []; 59178 let mainIdx = 0; 59179 let tmpPoints; 59180 59181 newShapes[ mainIdx ] = undefined; 59182 newShapeHoles[ mainIdx ] = []; 59183 59184 for ( let i = 0, l = subPaths.length; i < l; i ++ ) { 59185 59186 tmpPath = subPaths[ i ]; 59187 tmpPoints = tmpPath.getPoints(); 59188 solid = isClockWise( tmpPoints ); 59189 solid = isCCW ? ! solid : solid; 59190 59191 if ( solid ) { 59192 59193 if ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) ) mainIdx ++; 59194 59195 newShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints }; 59196 newShapes[ mainIdx ].s.curves = tmpPath.curves; 59197 59198 if ( holesFirst ) mainIdx ++; 59199 newShapeHoles[ mainIdx ] = []; 59200 59201 //log('cw', i); 59202 59203 } else { 59204 59205 newShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } ); 59206 59207 //log('ccw', i); 59208 59209 } 59210 59211 } 59212 59213 // only Holes? -> probably all Shapes with wrong orientation 59214 if ( ! newShapes[ 0 ] ) return toShapesNoHoles( subPaths ); 59215 59216 59217 if ( newShapes.length > 1 ) { 59218 59219 let ambiguous = false; 59220 let toChange = 0; 59221 59222 for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { 59223 59224 betterShapeHoles[ sIdx ] = []; 59225 59226 } 59227 59228 for ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) { 59229 59230 const sho = newShapeHoles[ sIdx ]; 59231 59232 for ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) { 59233 59234 const ho = sho[ hIdx ]; 59235 let hole_unassigned = true; 59236 59237 for ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) { 59238 59239 if ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) { 59240 59241 if ( sIdx !== s2Idx ) toChange ++; 59242 59243 if ( hole_unassigned ) { 59244 59245 hole_unassigned = false; 59246 betterShapeHoles[ s2Idx ].push( ho ); 59247 59248 } else { 59249 59250 ambiguous = true; 59251 59252 } 59253 59254 } 59255 59256 } 59257 59258 if ( hole_unassigned ) { 59259 59260 betterShapeHoles[ sIdx ].push( ho ); 59261 59262 } 59263 59264 } 59265 59266 } 59267 59268 if ( toChange > 0 && ambiguous === false ) { 59269 59270 newShapeHoles = betterShapeHoles; 59271 59272 } 59273 59274 } 59275 59276 let tmpHoles; 59277 59278 for ( let i = 0, il = newShapes.length; i < il; i ++ ) { 59279 59280 tmpShape = newShapes[ i ].s; 59281 shapes.push( tmpShape ); 59282 tmpHoles = newShapeHoles[ i ]; 59283 59284 for ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) { 59285 59286 tmpShape.holes.push( tmpHoles[ j ].h ); 59287 59288 } 59289 59290 } 59291 59292 //log("shape", shapes); 59293 59294 return shapes; 59295 59296 } 59297 59298} 59299 59300/**
59301 * Abstract base class for controls. 59302 * 59303 * @abstract 59304 * @augments EventDispatcher 59305 */ 59306class Controls extends EventDispatcher { 59307 59308 /** 59309 * Constructs a new controls instance. 59310 * 59311 * @param {Object3D} object - The object that is managed by the controls. 59312 * @param {?HTMLElement} domElement - The HTML element used for event listeners. 59313 */ 59314 constructor( object, domElement = null ) { 59315 59316 super(); 59317 59318 /** 59319 * The object that is managed by the controls. 59320 * 59321 * @type {Object3D} 59322 */ 59323 this.object = object; 59324 59325 /** 59326 * The HTML element used for event listeners. 59327 * 59328 * @type {?HTMLElement} 59329 * @default null 59330 */ 59331 this.domElement = domElement; 59332 59333 /** 59334 * Whether the controls responds to user input or not. 59335 * 59336 * @type {boolean} 59337 * @default true 59338 */ 59339 this.enabled = true; 59340 59341 /** 59342 * The internal state of the controls. 59343 * 59344 * @type {number} 59345 * @default -1 59346 */ 59347 this.state = -1; 59348 59349 /** 59350 * This object defines the keyboard input of the controls. 59351 * 59352 * @type {Object} 59353 */ 59354 this.keys = {}; 59355 59356 /** 59357 * This object defines what type of actions are assigned to the available mouse buttons. 59358 * It depends on the control implementation what kind of mouse buttons and actions are supported. 59359 * 59360 * @type {{LEFT: ?number, MIDDLE: ?number, RIGHT: ?number}} 59361 */ 59362 this.mouseButtons = { LEFT: null, MIDDLE: null, RIGHT: null }; 59363 59364 /** 59365 * This object defines what type of actions are assigned to what kind of touch interaction. 59366 * It depends on the control implementation what kind of touch interaction and actions are supported. 59367 * 59368 * @type {{ONE: ?number, TWO: ?number}} 59369 */ 59370 this.touches = { ONE: null, TWO: null }; 59371 59372 } 59373 59374 /** 59375 * Connects the controls to the DOM. This method has so called "side effects" since 59376 * it adds the module's event listeners to the DOM. 59377 * 59378 * @param {HTMLElement} element - The DOM element to connect to. 59379 */ 59380 connect( element ) { 59381 59382 if ( element === undefined ) { 59383 59384 warn( 'Controls: connect() now requires an element.' ); // @deprecated, the warning can be removed with r185 59385 return; 59386 59387 }
vendor: 8,049 bytes, lines 59387-59640
59387 59388 59389 if ( this.domElement !== null ) this.disconnect(); 59390 59391 this.domElement = element; 59392 59393 } 59394 59395 /** 59396 * Disconnects the controls from the DOM. 59397 */ 59398 disconnect() {} 59399 59400 /** 59401 * Call this method if you no longer want use to the controls. It frees all internal 59402 * resources and removes all event listeners. 59403 */ 59404 dispose() {} 59405 59406 /** 59407 * Controls should implement this method if they have to update their internal state 59408 * per simulation step. 59409 * 59410 * @param {number} [delta] - The time delta in seconds. 59411 */ 59412 update( /* delta */ ) {} 59413 59414} 59415 59416/** 59417 * Scales the texture as large as possible within its surface without cropping 59418 * or stretching the texture. The method preserves the original aspect ratio of 59419 * the texture. Akin to CSS `object-fit: contain` 59420 * 59421 * @param {Texture} texture - The texture. 59422 * @param {number} aspect - The texture's aspect ratio. 59423 * @return {Texture} The updated texture. 59424 */ 59425function contain( texture, aspect ) { 59426 59427 const imageAspect = ( texture.image && texture.image.width ) ? texture.image.width / texture.image.height : 1; 59428 59429 if ( imageAspect > aspect ) { 59430 59431 texture.repeat.x = 1; 59432 texture.repeat.y = imageAspect / aspect; 59433 59434 texture.offset.x = 0; 59435 texture.offset.y = ( 1 - texture.repeat.y ) / 2; 59436 59437 } else { 59438 59439 texture.repeat.x = aspect / imageAspect; 59440 texture.repeat.y = 1; 59441 59442 texture.offset.x = ( 1 - texture.repeat.x ) / 2; 59443 texture.offset.y = 0; 59444 59445 } 59446 59447 return texture; 59448 59449} 59450 59451/** 59452 * Scales the texture to the smallest possible size to fill the surface, leaving 59453 * no empty space. The method preserves the original aspect ratio of the texture. 59454 * Akin to CSS `object-fit: cover`. 59455 * 59456 * @param {Texture} texture - The texture. 59457 * @param {number} aspect - The texture's aspect ratio. 59458 * @return {Texture} The updated texture. 59459 */ 59460function cover( texture, aspect ) { 59461 59462 const imageAspect = ( texture.image && texture.image.width ) ? texture.image.width / texture.image.height : 1; 59463 59464 if ( imageAspect > aspect ) { 59465 59466 texture.repeat.x = aspect / imageAspect; 59467 texture.repeat.y = 1; 59468 59469 texture.offset.x = ( 1 - texture.repeat.x ) / 2; 59470 texture.offset.y = 0; 59471 59472 } else { 59473 59474 texture.repeat.x = 1; 59475 texture.repeat.y = imageAspect / aspect; 59476 59477 texture.offset.x = 0; 59478 texture.offset.y = ( 1 - texture.repeat.y ) / 2; 59479 59480 } 59481 59482 return texture; 59483 59484} 59485 59486/** 59487 * Configures the texture to the default transformation. Akin to CSS `object-fit: fill`. 59488 * 59489 * @param {Texture} texture - The texture. 59490 * @return {Texture} The updated texture. 59491 */ 59492function fill( texture ) { 59493 59494 texture.repeat.x = 1; 59495 texture.repeat.y = 1; 59496 59497 texture.offset.x = 0; 59498 texture.offset.y = 0; 59499 59500 return texture; 59501 59502} 59503 59504/** 59505 * Determines how many bytes must be used to represent the texture. 59506 * 59507 * @param {number} width - The width of the texture. 59508 * @param {number} height - The height of the texture. 59509 * @param {number} format - The texture's format. 59510 * @param {number} type - The texture's type. 59511 * @return {number} The byte length. 59512 */ 59513function getByteLength( width, height, format, type ) { 59514 59515 const typeByteLength = getTextureTypeByteLength( type ); 59516 59517 switch ( format ) { 59518 59519 // https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml 59520 case AlphaFormat: 59521 return width * height; 59522 case RedFormat: 59523 return ( ( width * height ) / typeByteLength.components ) * typeByteLength.byteLength; 59524 case RedIntegerFormat: 59525 return ( ( width * height ) / typeByteLength.components ) * typeByteLength.byteLength; 59526 case RGFormat: 59527 return ( ( width * height * 2 ) / typeByteLength.components ) * typeByteLength.byteLength; 59528 case RGIntegerFormat: 59529 return ( ( width * height * 2 ) / typeByteLength.components ) * typeByteLength.byteLength; 59530 case RGBFormat: 59531 return ( ( width * height * 3 ) / typeByteLength.components ) * typeByteLength.byteLength; 59532 case RGBAFormat: 59533 return ( ( width * height * 4 ) / typeByteLength.components ) * typeByteLength.byteLength; 59534 case RGBAIntegerFormat: 59535 return ( ( width * height * 4 ) / typeByteLength.components ) * typeByteLength.byteLength; 59536 59537 // https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_s3tc_srgb/ 59538 case RGB_S3TC_DXT1_Format: 59539 case RGBA_S3TC_DXT1_Format: 59540 return Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 8; 59541 case RGBA_S3TC_DXT3_Format: 59542 case RGBA_S3TC_DXT5_Format: 59543 return Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 16; 59544 59545 // https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_pvrtc/ 59546 case RGB_PVRTC_2BPPV1_Format: 59547 case RGBA_PVRTC_2BPPV1_Format: 59548 return ( Math.max( width, 16 ) * Math.max( height, 8 ) ) / 4; 59549 case RGB_PVRTC_4BPPV1_Format: 59550 case RGBA_PVRTC_4BPPV1_Format: 59551 return ( Math.max( width, 8 ) * Math.max( height, 8 ) ) / 2; 59552 59553 // https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_etc/ 59554 case RGB_ETC1_Format: 59555 case RGB_ETC2_Format: 59556 case R11_EAC_Format: 59557 case SIGNED_R11_EAC_Format: 59558 return Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 8; 59559 case RGBA_ETC2_EAC_Format: 59560 case RG11_EAC_Format: 59561 case SIGNED_RG11_EAC_Format: 59562 return Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 16; 59563 59564 // https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_astc/ 59565 case RGBA_ASTC_4x4_Format: 59566 return Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 16; 59567 case RGBA_ASTC_5x4_Format: 59568 return Math.floor( ( width + 4 ) / 5 ) * Math.floor( ( height + 3 ) / 4 ) * 16; 59569 case RGBA_ASTC_5x5_Format: 59570 return Math.floor( ( width + 4 ) / 5 ) * Math.floor( ( height + 4 ) / 5 ) * 16; 59571 case RGBA_ASTC_6x5_Format: 59572 return Math.floor( ( width + 5 ) / 6 ) * Math.floor( ( height + 4 ) / 5 ) * 16; 59573 case RGBA_ASTC_6x6_Format: 59574 return Math.floor( ( width + 5 ) / 6 ) * Math.floor( ( height + 5 ) / 6 ) * 16; 59575 case RGBA_ASTC_8x5_Format: 59576 return Math.floor( ( width + 7 ) / 8 ) * Math.floor( ( height + 4 ) / 5 ) * 16; 59577 case RGBA_ASTC_8x6_Format: 59578 return Math.floor( ( width + 7 ) / 8 ) * Math.floor( ( height + 5 ) / 6 ) * 16; 59579 case RGBA_ASTC_8x8_Format: 59580 return Math.floor( ( width + 7 ) / 8 ) * Math.floor( ( height + 7 ) / 8 ) * 16; 59581 case RGBA_ASTC_10x5_Format: 59582 return Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height + 4 ) / 5 ) * 16; 59583 case RGBA_ASTC_10x6_Format: 59584 return Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height + 5 ) / 6 ) * 16; 59585 case RGBA_ASTC_10x8_Format: 59586 return Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height + 7 ) / 8 ) * 16; 59587 case RGBA_ASTC_10x10_Format: 59588 return Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height + 9 ) / 10 ) * 16; 59589 case RGBA_ASTC_12x10_Format: 59590 return Math.floor( ( width + 11 ) / 12 ) * Math.floor( ( height + 9 ) / 10 ) * 16; 59591 case RGBA_ASTC_12x12_Format: 59592 return Math.floor( ( width + 11 ) / 12 ) * Math.floor( ( height + 11 ) / 12 ) * 16; 59593 59594 // https://registry.khronos.org/webgl/extensions/EXT_texture_compression_bptc/ 59595 case RGBA_BPTC_Format: 59596 case RGB_BPTC_SIGNED_Format: 59597 case RGB_BPTC_UNSIGNED_Format: 59598 return Math.ceil( width / 4 ) * Math.ceil( height / 4 ) * 16; 59599 59600 // https://registry.khronos.org/webgl/extensions/EXT_texture_compression_rgtc/ 59601 case RED_RGTC1_Format: 59602 case SIGNED_RED_RGTC1_Format: 59603 return Math.ceil( width / 4 ) * Math.ceil( height / 4 ) * 8; 59604 case RED_GREEN_RGTC2_Format: 59605 case SIGNED_RED_GREEN_RGTC2_Format: 59606 return Math.ceil( width / 4 ) * Math.ceil( height / 4 ) * 16; 59607 59608 } 59609 59610 throw new Error( 59611 `Unable to determine texture byte length for ${format} format.`, 59612 ); 59613 59614} 59615 59616function getTextureTypeByteLength( type ) { 59617 59618 switch ( type ) { 59619 59620 case UnsignedByteType: 59621 case ByteType: 59622 return { byteLength: 1, components: 1 }; 59623 case UnsignedShortType: 59624 case ShortType: 59625 case HalfFloatType: 59626 return { byteLength: 2, components: 1 }; 59627 case UnsignedShort4444Type: 59628 case UnsignedShort5551Type: 59629 return { byteLength: 2, components: 4 }; 59630 case UnsignedIntType: 59631 case IntType: 59632 case FloatType: 59633 return { byteLength: 4, components: 1 }; 59634 case UnsignedInt5999Type: 59635 case UnsignedInt101111Type: 59636 return { byteLength: 4, components: 3 }; 59637 59638 } 59639 59640 throw new Error( `
59640Unknown texture type ${type}.` ); 59641 59642} 59643 59644/** 59645 * A class containing utility functions for textures. 59646 * 59647 * @hideconstructor 59648 */ 59649class TextureUtils { 59650 59651 /** 59652 * Scales the texture as large as possible within its surface without cropping 59653 * or stretching the texture. The method preserves the original aspect ratio of 59654 * the texture. Akin to CSS `object-fit: contain` 59655 * 59656 * @param {Texture} texture - The texture. 59657 * @param {number} aspect - The texture's aspect ratio. 59658 * @return {Texture} The updated texture. 59659 */ 59660 static contain( texture, aspect ) { 59661 59662 return contain( texture, aspect ); 59663 59664 } 59665 59666 /** 59667 * Scales the texture to the smallest possible size to fill the surface, leaving 59668 * no empty space. The method preserves the original aspect ratio of the texture. 59669 * Akin to CSS `object-fit: cover`. 59670 * 59671 * @param {Texture} texture - The texture. 59672 * @param {number} aspect - The texture's aspect ratio. 59673 * @return {Texture} The updated texture. 59674 */ 59675 static cover( texture, aspect ) { 59676 59677 return cover( texture, aspect ); 59678 59679 } 59680 59681 /** 59682 * Configures the texture to the default transformation. Akin to CSS `object-fit: fill`. 59683 * 59684 * @param {Texture} texture - The texture. 59685 * @return {Texture} The updated texture. 59686 */ 59687 static fill( texture ) { 59688 59689 return fill( texture ); 59690 59691 } 59692 59693 /** 59694 * Determines how many bytes must be used to represent the texture. 59695 * 59696 * @param {number} width - The width of the texture. 59697 * @param {number} height - The height of the texture. 59698 * @param {number} format - The texture's format. 59699 * @param {number} type - The texture's type. 59700 * @return {number} The byte length. 59701 */ 59702 static getByteLength( width, height, format, type ) { 59703 59704 return getByteLength( width, height, format, type ); 59705 59706 } 59707 59708} 59709 59710if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { 59711 59712 __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: { 59713 revision: REVISION, 59714 } } ) ); 59715 59716} 59717 59718if ( typeof window !== 'undefined' ) { 59719 59720 if ( window.__THREE__ ) { 59721 59722 warn( 'WARNING: Multiple instances of Three.js being imported.' ); 59723 59724 } else { 59725 59726 window.__THREE__ = REVISION; 59727 59728 } 59729 59730} 59731 59732export { ACESFilmicToneMapping, AddEquation, AddOperation, AdditiveAnimationBlendMode, AdditiveBlending, AgXToneMapping, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AmbientLight, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrayCamera, ArrowHelper, AttachedBindMode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BackSide, BasicDepthPacking, BasicShadowMap, BatchedMesh, BezierInterpolant, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxGeometry, BoxHelper, BufferAttribute, BufferGeometry, BufferGeometryLoader, ByteType, Cache, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CineonToneMapping, CircleGeometry, ClampToEdgeWrapping, Clock, Color, ColorKeyframeTrack, ColorManagement, Compatibility, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ConeGeometry, ConstantAlphaFactor, ConstantColorFactor, Controls, CubeCamera, CubeDepthTexture, CubeReflectionMapping, CubeRefractionMapping, CubeTexture, CubeTextureLoader, CubeUVReflectionMapping, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceBack, CullFaceFront, CullFaceFrontBack, CullFaceNone, Curve, CurvePath, CustomBlending, CustomToneMapping, CylinderGeometry, Cylindrical, Data3DTexture, DataArrayTexture, DataTexture, DataTextureLoader, DataUtils, DecrementStencilOp, DecrementWrapStencilOp, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DepthTexture, DetachedBindMode, DirectionalLight, DirectionalLightHelper, DiscreteInterpolant, DodecahedronGeometry, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicCopyUsage, DynamicDrawUsage, DynamicReadUsage, EdgesGeometry, EllipseCurve, EqualCompare, EqualDepth, EqualStencilFunc, EquirectangularReflectionMapping, EquirectangularRefractionMapping, Euler, EventDispatcher, ExternalTexture, ExtrudeGeometry, FileLoader, Float16BufferAttribute, Float32BufferAttribute, FloatType, Fog, FogExp2, FramebufferTexture, FrontSide, Frustum, FrustumArray, GLBufferAttribute, GLSL1, GLSL3, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, GridHelper, Group, HTMLTexture, HalfFloatType, HemisphereLight, HemisphereLightHelper, IcosahedronGeometry, ImageBitmapLoader, ImageLoader, ImageUtils, IncrementStencilOp, IncrementWrapStencilOp, InstancedBufferAttribute, InstancedBufferGeometry, InstancedInterleavedBuffer, InstancedMesh, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, IntType, InterleavedBuffer, InterleavedBufferAttribute, Interpolant, InterpolateBezier, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InterpolationSamplingMode, InterpolationSamplingType, InvertStencilOp, KeepStencilOp, KeyframeTrack, LOD, LatheGeometry, Layers, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, Light, LightProbe, Line, Line3, LineBasicMaterial, LineCurve, LineCurve3, LineDashedMaterial, LineLoop, LineSegments, LinearFilter, LinearInterpolant, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping, LinearTransfer, Loader, LoaderUtils, LoadingManager, LoopOnce, LoopPingPong, LoopRepeat, MOUSE, Material, MaterialBlending, MaterialLoader, MathUtils, Matrix2, Matrix3, Matrix4, MaxEquation, Mesh, MeshBasicMaterial, MeshDepthMaterial, MeshDistanceMaterial, MeshLambertMaterial, MeshMatcapMaterial, MeshNormalMaterial, MeshPhongMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshToonMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeutralToneMapping, NeverCompare, NeverDepth, NeverStencilFunc, NoBlending, NoColorSpace, NoNormalPacking, NoToneMapping, NormalAnimationBlendMode, NormalBlending, NormalGAPacking, NormalRGPacking, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, NumberKeyframeTrack, Object3D, ObjectLoader, ObjectSpaceNormalMap, OctahedronGeometry, OneFactor, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, Orthogra
59732phicCamera, PCFShadowMap, PCFSoftShadowMap, Path, PerspectiveCamera, Plane, PlaneGeometry, PlaneHelper, PointLight, PointLightHelper, Points, PointsMaterial, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, Quaternion, QuaternionKeyframeTrack, QuaternionLinearInterpolant, R11_EAC_Format, RAD2DEG, RED_GREEN_RGTC2_Format, RED_RGTC1_Format, REVISION, RG11_EAC_Format, RGBADepthPacking, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBDepthPacking, RGBFormat, RGBIntegerFormat, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGDepthPacking, RGFormat, RGIntegerFormat, RawShaderMaterial, Ray, Raycaster, RectAreaLight, RedFormat, RedIntegerFormat, ReinhardToneMapping, RenderTarget, RenderTarget3D, RepeatWrapping, ReplaceStencilOp, ReverseSubtractEquation, ReversedDepthFuncs, RingGeometry, SIGNED_R11_EAC_Format, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SIGNED_RG11_EAC_Format, SRGBColorSpace, SRGBTransfer, Scene, ShaderMaterial, ShadowMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, ShortType, Skeleton, SkeletonHelper, SkinnedMesh, Source, Sphere, SphereGeometry, Spherical, SphericalHarmonics3, SplineCurve, SpotLight, SpotLightHelper, Sprite, SpriteMaterial, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StaticCopyUsage, StaticDrawUsage, StaticReadUsage, StereoCamera, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, SubtractEquation, SubtractiveBlending, TOUCH, TangentSpaceNormalMap, TetrahedronGeometry, Texture, TextureLoader, TextureUtils, Timer, TimestampQuery, TorusGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsGroup, UniformsUtils, UnsignedByteType, UnsignedInt101111Type, UnsignedInt248Type, UnsignedInt5999Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VSMShadowMap, Vector2, Vector3, Vector4, VectorKeyframeTrack, VideoFrameTexture, VideoTexture, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGLCoordinateSystem, WebGLRenderTarget, WebGPUCoordinateSystem, WebXRController, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroFactor, ZeroSlopeEnding, ZeroStencilOp, cloneUniforms, createCanvasElement, createElementNS, error, getByteLength, getConsoleFunction, getUnlitUniformColorSpace, isTypedArray, log, mergeUniforms, probeAsync, setConsoleFunction, warn, warnOnce, yieldToMain };
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.