three-zoo 0.5.3 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,6 +19,8 @@
19
19
  - ☀️ **Sun** - Intuitive spherical positioning for directional lights with HDR integration
20
20
  - 🔍 **SceneTraversal** - Find and manipulate objects and materials in scene graphs
21
21
  - 🎭 **SkinnedMeshBaker** - Convert animated meshes to static geometry
22
+ - 🎨 **StandardToLambertConverter** - Convert PBR materials to Lambert with visual compensation
23
+ - ✨ **StandardToBasicConverter** - Convert PBR materials to unlit Basic materials
22
24
 
23
25
  ## Installation
24
26
 
@@ -104,6 +106,39 @@ const frameMesh = SkinnedMeshBaker.bakeAnimationFrame(
104
106
  );
105
107
  ```
106
108
 
109
+ ## Material Converters
110
+
111
+ Convert PBR StandardMaterials to simpler material types while preserving visual appearance:
112
+
113
+ ### StandardToLambertConverter
114
+
115
+ ```typescript
116
+ // Basic conversion
117
+ const lambertMaterial = StandardToLambertConverter.convert(standardMaterial);
118
+
119
+ // With custom options
120
+ const lambertMaterial = StandardToLambertConverter.convert(standardMaterial, {
121
+ preserveName: true,
122
+ roughnessColorFactor: 0.9,
123
+ disposeOriginal: true
124
+ });
125
+ ```
126
+
127
+ ### StandardToBasicConverter
128
+
129
+ ```typescript
130
+ // Convert to unlit material
131
+ const basicMaterial = StandardToBasicConverter.convert(standardMaterial);
132
+
133
+ // With brightness compensation
134
+ const basicMaterial = StandardToBasicConverter.convert(standardMaterial, {
135
+ brightnessFactor: 1.5,
136
+ combineEmissive: true,
137
+ preserveName: true,
138
+ disposeOriginal: false
139
+ });
140
+ ```
141
+
107
142
  ## Requirements
108
143
 
109
144
  - Three.js ^0.175.0 (peer dependency)
@@ -0,0 +1,74 @@
1
+ import type { MeshStandardMaterial } from "three";
2
+ import { MeshBasicMaterial } from "three";
3
+ /**
4
+ * Configuration options for the StandardToBasicConverter
5
+ *
6
+ * @interface StandardToBasicConverterOptions
7
+ */
8
+ export interface StandardToBasicConverterOptions {
9
+ /**
10
+ * Whether to preserve the original material's name
11
+ * @defaultValue true
12
+ */
13
+ preserveName: boolean;
14
+ /**
15
+ * Whether to copy user data from the original material
16
+ * @defaultValue true
17
+ */
18
+ copyUserData: boolean;
19
+ /**
20
+ * Whether to dispose the original material after conversion
21
+ * @defaultValue false
22
+ */
23
+ disposeOriginal: boolean;
24
+ /**
25
+ * Whether to apply emissive color to the base color for brightness compensation
26
+ * @defaultValue true
27
+ */
28
+ combineEmissive: boolean;
29
+ /**
30
+ * Factor for brightness adjustment to compensate for loss of lighting
31
+ * @defaultValue 1.3
32
+ */
33
+ brightnessFactor: number;
34
+ }
35
+ /**
36
+ * Converts Three.js MeshStandardMaterial to MeshBasicMaterial
37
+ *
38
+ * This converter handles the translation from PBR (Physically Based Rendering)
39
+ * StandardMaterial to the unlit BasicMaterial. Since BasicMaterial doesn't respond
40
+ * to lighting, this converter applies various compensation techniques to maintain
41
+ * visual similarity, including brightness adjustments and emissive color combination.
42
+ */
43
+ export declare class StandardToBasicConverter {
44
+ /**
45
+ * Converts a MeshStandardMaterial to MeshBasicMaterial
46
+ *
47
+ * This method performs a comprehensive conversion from PBR StandardMaterial to
48
+ * unlit BasicMaterial while attempting to preserve visual similarity through
49
+ * brightness compensation and intelligent property mapping.
50
+ *
51
+ * @param standardMaterial - The source MeshStandardMaterial to convert
52
+ * @param options - Configuration options for the conversion
53
+ * @returns A new MeshBasicMaterial with properties mapped from the standard material
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * const standardMaterial = new MeshStandardMaterial({
58
+ * color: 0x00ff00,
59
+ * metalness: 0.5,
60
+ * emissive: 0x111111,
61
+ * emissiveIntensity: 0.2
62
+ * });
63
+ *
64
+ * const basicMaterial = StandardToBasicConverter.convert(standardMaterial, {
65
+ * brightnessFactor: 1.4,
66
+ * combineEmissive: true
67
+ * });
68
+ * ```
69
+ *
70
+ * @see {@link StandardToBasicConverterOptions} for available configuration options
71
+ */
72
+ static convert(standardMaterial: MeshStandardMaterial, options?: Partial<StandardToBasicConverterOptions>): MeshBasicMaterial;
73
+ }
74
+ export default StandardToBasicConverter;
@@ -0,0 +1,64 @@
1
+ import type { MeshStandardMaterial } from "three";
2
+ import { MeshLambertMaterial } from "three";
3
+ /**
4
+ * Configuration options for the StandardToLambertConverter
5
+ *
6
+ * @interface StandardToLambertConverterOptions
7
+ */
8
+ export interface StandardToLambertConverterOptions {
9
+ /**
10
+ * Whether to preserve the original material's name
11
+ * @defaultValue true
12
+ */
13
+ preserveName: boolean;
14
+ /**
15
+ * Whether to copy user data from the original material
16
+ * @defaultValue true
17
+ */
18
+ copyUserData: boolean;
19
+ /**
20
+ * Whether to dispose the original material after conversion
21
+ * @defaultValue false
22
+ */
23
+ disposeOriginal: boolean;
24
+ /**
25
+ * Custom color adjustment factor for roughness compensation
26
+ * @defaultValue 0.8
27
+ */
28
+ roughnessColorFactor: number;
29
+ }
30
+ /**
31
+ * Converts Three.js MeshStandardMaterial to MeshLambertMaterial
32
+ *
33
+ * This converter handles the translation between PBR (Physically Based Rendering)
34
+ * properties of StandardMaterial and the simpler Lambertian reflectance model
35
+ * used by LambertMaterial. The conversion preserves visual similarity by applying
36
+ * color compensation based on metalness and roughness values.
37
+ */
38
+ export declare class StandardToLambertConverter {
39
+ /**
40
+ * Converts a MeshStandardMaterial to MeshLambertMaterial
41
+ *
42
+ * This method performs a comprehensive conversion from PBR StandardMaterial to
43
+ * the simpler Lambert lighting model while attempting to preserve visual similarity
44
+ * through intelligent color compensation.
45
+ *
46
+ * @param material - The source MeshStandardMaterial to convert
47
+ * @param options - Configuration options for the conversion
48
+ * @returns A new MeshLambertMaterial with properties mapped from the standard material
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const standardMaterial = new MeshStandardMaterial({
53
+ * color: 0xff0000,
54
+ * metalness: 0.8,
55
+ * roughness: 0.2
56
+ * });
57
+ *
58
+ * const lambertMaterial = StandardToLambertConverter.convert(standardMaterial);
59
+ * ```
60
+ *
61
+ * @see {@link StandardToLambertConverterOptions} for available configuration options
62
+ */
63
+ static convert(material: MeshStandardMaterial, options?: Partial<StandardToLambertConverterOptions>): MeshLambertMaterial;
64
+ }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export * from "./DualFovCamera";
2
2
  export * from "./SceneTraversal";
3
3
  export * from "./SkinnedMeshBaker";
4
+ export * from "./StandardToBasicConverter";
5
+ export * from "./StandardToLambertConverter";
4
6
  export * from "./Sun";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { PerspectiveCamera, MathUtils, Vector3, Mesh, BufferAttribute, AnimationMixer, DirectionalLight, Box3, Spherical, RGBAFormat } from 'three';
1
+ import { PerspectiveCamera, MathUtils, Vector3, Mesh, BufferAttribute, AnimationMixer, MeshBasicMaterial, MeshLambertMaterial, DirectionalLight, Box3, Spherical, RGBAFormat } from 'three';
2
2
 
3
3
  /** Default horizontal field of view in degrees */
4
4
  const DEFAULT_HORIZONTAL_FOV = 90;
@@ -550,6 +550,411 @@ class SkinnedMeshBaker {
550
550
  }
551
551
  }
552
552
 
553
+ /**
554
+ * Converts Three.js MeshStandardMaterial to MeshBasicMaterial
555
+ *
556
+ * This converter handles the translation from PBR (Physically Based Rendering)
557
+ * StandardMaterial to the unlit BasicMaterial. Since BasicMaterial doesn't respond
558
+ * to lighting, this converter applies various compensation techniques to maintain
559
+ * visual similarity, including brightness adjustments and emissive color combination.
560
+ */
561
+ class StandardToBasicConverter {
562
+ /**
563
+ * Converts a MeshStandardMaterial to MeshBasicMaterial
564
+ *
565
+ * This method performs a comprehensive conversion from PBR StandardMaterial to
566
+ * unlit BasicMaterial while attempting to preserve visual similarity through
567
+ * brightness compensation and intelligent property mapping.
568
+ *
569
+ * @param standardMaterial - The source MeshStandardMaterial to convert
570
+ * @param options - Configuration options for the conversion
571
+ * @returns A new MeshBasicMaterial with properties mapped from the standard material
572
+ *
573
+ * @example
574
+ * ```typescript
575
+ * const standardMaterial = new MeshStandardMaterial({
576
+ * color: 0x00ff00,
577
+ * metalness: 0.5,
578
+ * emissive: 0x111111,
579
+ * emissiveIntensity: 0.2
580
+ * });
581
+ *
582
+ * const basicMaterial = StandardToBasicConverter.convert(standardMaterial, {
583
+ * brightnessFactor: 1.4,
584
+ * combineEmissive: true
585
+ * });
586
+ * ```
587
+ *
588
+ * @see {@link StandardToBasicConverterOptions} for available configuration options
589
+ */
590
+ static convert(standardMaterial, options = {}) {
591
+ const config = {
592
+ preserveName: true,
593
+ copyUserData: true,
594
+ disposeOriginal: false,
595
+ combineEmissive: true,
596
+ brightnessFactor: 1.3,
597
+ ...options,
598
+ };
599
+ // Create new Basic material
600
+ const basicMaterial = new MeshBasicMaterial();
601
+ // Copy basic material properties
602
+ this.copyBasicProperties(standardMaterial, basicMaterial, config);
603
+ // Handle color properties with lighting compensation
604
+ this.convertColorProperties(standardMaterial, basicMaterial, config);
605
+ // Handle texture maps
606
+ this.convertTextureMaps(standardMaterial, basicMaterial);
607
+ // Handle transparency and alpha
608
+ this.convertTransparencyProperties(standardMaterial, basicMaterial);
609
+ // Cleanup if requested
610
+ if (config.disposeOriginal) {
611
+ standardMaterial.dispose();
612
+ }
613
+ basicMaterial.needsUpdate = true;
614
+ return basicMaterial;
615
+ }
616
+ /**
617
+ * Copies basic material properties from source to target material
618
+ *
619
+ * Transfers common material properties including rendering settings,
620
+ * visibility, fog interaction, wireframe settings, and user data.
621
+ *
622
+ * @param source - The source MeshStandardMaterial
623
+ * @param target - The target MeshBasicMaterial
624
+ * @param config - The resolved configuration options
625
+ * @internal
626
+ */
627
+ static copyBasicProperties(source, target, config) {
628
+ if (config.preserveName) {
629
+ target.name = source.name;
630
+ }
631
+ target.side = source.side;
632
+ target.visible = source.visible;
633
+ target.fog = source.fog;
634
+ target.wireframe = source.wireframe;
635
+ target.wireframeLinewidth = source.wireframeLinewidth;
636
+ target.vertexColors = source.vertexColors;
637
+ if (config.copyUserData) {
638
+ target.userData = { ...source.userData };
639
+ }
640
+ }
641
+ /**
642
+ * Converts color-related properties with lighting compensation
643
+ *
644
+ * Applies brightness compensation and optional emissive color combination
645
+ * to account for BasicMaterial's lack of lighting response. Metallic materials
646
+ * receive additional brightness adjustment, and colors are clamped to valid ranges.
647
+ *
648
+ * @param source - The source MeshStandardMaterial
649
+ * @param target - The target MeshBasicMaterial
650
+ * @param config - The resolved configuration options
651
+ * @internal
652
+ */
653
+ static convertColorProperties(source, target, config) {
654
+ // Base color conversion with brightness compensation
655
+ target.color = source.color.clone();
656
+ // Apply brightness compensation since BasicMaterial doesn't respond to lighting
657
+ target.color.multiplyScalar(config.brightnessFactor);
658
+ // Adjust for metalness - metallic materials tend to be darker without lighting
659
+ if (source.metalness > 0) {
660
+ const metalnessBrightness = 1 + source.metalness * 0.3;
661
+ target.color.multiplyScalar(metalnessBrightness);
662
+ }
663
+ // Combine emissive color if requested
664
+ if (config.combineEmissive) {
665
+ const emissiveContribution = source.emissive
666
+ .clone()
667
+ .multiplyScalar(source.emissiveIntensity * 0.5);
668
+ target.color.add(emissiveContribution);
669
+ }
670
+ // Ensure color doesn't exceed valid range
671
+ target.color.r = Math.min(target.color.r, 1.0);
672
+ target.color.g = Math.min(target.color.g, 1.0);
673
+ target.color.b = Math.min(target.color.b, 1.0);
674
+ }
675
+ /**
676
+ * Converts and maps texture properties from Standard to Basic material
677
+ *
678
+ * Handles the transfer of compatible texture maps including diffuse, alpha,
679
+ * environment, light, and AO maps. The metalness map is repurposed as a
680
+ * specular map for some reflective effect, and environment map reflectivity
681
+ * is set based on the original material's metalness value.
682
+ *
683
+ * @param source - The source MeshStandardMaterial
684
+ * @param target - The target MeshBasicMaterial
685
+ * @internal
686
+ */
687
+ static convertTextureMaps(source, target) {
688
+ // Main diffuse/albedo map
689
+ if (source.map) {
690
+ target.map = source.map;
691
+ }
692
+ // Alpha map
693
+ if (source.alphaMap) {
694
+ target.alphaMap = source.alphaMap;
695
+ }
696
+ // Environment map (BasicMaterial supports this for reflections)
697
+ if (source.envMap) {
698
+ target.envMap = source.envMap;
699
+ // Use metalness to determine reflectivity
700
+ target.reflectivity = source.metalness;
701
+ }
702
+ // Light map (BasicMaterial supports this)
703
+ if (source.lightMap) {
704
+ target.lightMap = source.lightMap;
705
+ target.lightMapIntensity = source.lightMapIntensity;
706
+ }
707
+ // AO map (BasicMaterial supports this)
708
+ if (source.aoMap) {
709
+ target.aoMap = source.aoMap;
710
+ target.aoMapIntensity = source.aoMapIntensity;
711
+ }
712
+ // Specular map (BasicMaterial supports this)
713
+ if (source.metalnessMap) {
714
+ // Use metalness map as specular map for some reflective effect
715
+ target.specularMap = source.metalnessMap;
716
+ }
717
+ // Copy UV transforms
718
+ this.copyUVTransforms(source, target);
719
+ }
720
+ /**
721
+ * Copies UV transformation properties for texture maps
722
+ *
723
+ * Transfers UV offset, repeat, rotation, and center properties from the
724
+ * source material's main texture map to the target material's map.
725
+ *
726
+ * @param source - The source MeshStandardMaterial
727
+ * @param target - The target MeshBasicMaterial
728
+ * @internal
729
+ */
730
+ static copyUVTransforms(source, target) {
731
+ // Main texture UV transform
732
+ if (source.map && target.map) {
733
+ target.map.offset.copy(source.map.offset);
734
+ target.map.repeat.copy(source.map.repeat);
735
+ target.map.rotation = source.map.rotation;
736
+ target.map.center.copy(source.map.center);
737
+ }
738
+ }
739
+ /**
740
+ * Converts transparency and rendering properties
741
+ *
742
+ * Transfers transparency, opacity, alpha testing, depth testing,
743
+ * depth writing, and blending mode settings from source to target.
744
+ *
745
+ * @param source - The source MeshStandardMaterial
746
+ * @param target - The target MeshBasicMaterial
747
+ * @internal
748
+ */
749
+ static convertTransparencyProperties(source, target) {
750
+ target.transparent = source.transparent;
751
+ target.opacity = source.opacity;
752
+ target.alphaTest = source.alphaTest;
753
+ target.depthTest = source.depthTest;
754
+ target.depthWrite = source.depthWrite;
755
+ target.blending = source.blending;
756
+ }
757
+ }
758
+
759
+ /**
760
+ * Converts Three.js MeshStandardMaterial to MeshLambertMaterial
761
+ *
762
+ * This converter handles the translation between PBR (Physically Based Rendering)
763
+ * properties of StandardMaterial and the simpler Lambertian reflectance model
764
+ * used by LambertMaterial. The conversion preserves visual similarity by applying
765
+ * color compensation based on metalness and roughness values.
766
+ */
767
+ class StandardToLambertConverter {
768
+ /**
769
+ * Converts a MeshStandardMaterial to MeshLambertMaterial
770
+ *
771
+ * This method performs a comprehensive conversion from PBR StandardMaterial to
772
+ * the simpler Lambert lighting model while attempting to preserve visual similarity
773
+ * through intelligent color compensation.
774
+ *
775
+ * @param material - The source MeshStandardMaterial to convert
776
+ * @param options - Configuration options for the conversion
777
+ * @returns A new MeshLambertMaterial with properties mapped from the standard material
778
+ *
779
+ * @example
780
+ * ```typescript
781
+ * const standardMaterial = new MeshStandardMaterial({
782
+ * color: 0xff0000,
783
+ * metalness: 0.8,
784
+ * roughness: 0.2
785
+ * });
786
+ *
787
+ * const lambertMaterial = StandardToLambertConverter.convert(standardMaterial);
788
+ * ```
789
+ *
790
+ * @see {@link StandardToLambertConverterOptions} for available configuration options
791
+ */
792
+ static convert(material, options = {}) {
793
+ const config = {
794
+ preserveName: true,
795
+ copyUserData: true,
796
+ disposeOriginal: false,
797
+ roughnessColorFactor: 0.8,
798
+ ...options,
799
+ };
800
+ // Create new Lambert material
801
+ const lambertMaterial = new MeshLambertMaterial();
802
+ // Copy basic material properties
803
+ this.copyBasicProperties(material, lambertMaterial, config);
804
+ // Handle color properties with roughness compensation
805
+ this.convertColorProperties(material, lambertMaterial, config);
806
+ // Handle texture maps
807
+ this.convertTextureMaps(material, lambertMaterial);
808
+ // Handle transparency and alpha
809
+ this.convertTransparencyProperties(material, lambertMaterial);
810
+ // Cleanup if requested
811
+ if (config.disposeOriginal) {
812
+ material.dispose();
813
+ }
814
+ lambertMaterial.needsUpdate = true;
815
+ return lambertMaterial;
816
+ }
817
+ /**
818
+ * Copies basic material properties from source to target material
819
+ *
820
+ * Transfers common material properties including rendering settings,
821
+ * visibility, fog interaction, wireframe settings, and user data.
822
+ *
823
+ * @param source - The source MeshStandardMaterial
824
+ * @param target - The target MeshLambertMaterial
825
+ * @param config - The resolved configuration options
826
+ * @internal
827
+ */
828
+ static copyBasicProperties(source, target, config) {
829
+ if (config.preserveName) {
830
+ target.name = source.name;
831
+ }
832
+ target.side = source.side;
833
+ target.visible = source.visible;
834
+ target.fog = source.fog;
835
+ target.wireframe = source.wireframe;
836
+ target.wireframeLinewidth = source.wireframeLinewidth;
837
+ target.vertexColors = source.vertexColors;
838
+ target.flatShading = source.flatShading;
839
+ if (config.copyUserData) {
840
+ target.userData = { ...source.userData };
841
+ }
842
+ }
843
+ /**
844
+ * Converts color-related properties with PBR compensation
845
+ *
846
+ * Applies intelligent color adjustments to compensate for the loss of
847
+ * metalness and roughness information when converting to Lambert material.
848
+ * Metallic materials are darkened and rough materials receive additional
849
+ * darkening based on the roughnessColorFactor.
850
+ *
851
+ * @param source - The source MeshStandardMaterial
852
+ * @param target - The target MeshLambertMaterial
853
+ * @param config - The resolved configuration options
854
+ * @internal
855
+ */
856
+ static convertColorProperties(source, target, config) {
857
+ target.color = source.color.clone();
858
+ // Adjust color based on metalness and roughness for better visual match
859
+ if (source.metalness > 0) {
860
+ // Metallic materials tend to be darker in Lambert shading
861
+ const metalnessFactor = 1 - source.metalness * 0.3;
862
+ target.color.multiplyScalar(metalnessFactor);
863
+ }
864
+ if (source.roughness > 0.5) {
865
+ // Rough materials appear slightly darker
866
+ const roughnessFactor = config.roughnessColorFactor + source.roughness * 0.2;
867
+ target.color.multiplyScalar(roughnessFactor);
868
+ }
869
+ target.emissive = source.emissive.clone();
870
+ target.emissiveIntensity = source.emissiveIntensity;
871
+ }
872
+ /**
873
+ * Converts and maps texture properties from Standard to Lambert material
874
+ *
875
+ * Handles the transfer of compatible texture maps including diffuse, normal,
876
+ * emissive, AO, light maps, and environment maps. The environment map
877
+ * reflectivity is set based on the original material's metalness value.
878
+ *
879
+ * @param source - The source MeshStandardMaterial
880
+ * @param target - The target MeshLambertMaterial
881
+ * @internal
882
+ */
883
+ static convertTextureMaps(source, target) {
884
+ // Diffuse/Albedo map
885
+ if (source.map) {
886
+ target.map = source.map;
887
+ }
888
+ // Emissive map
889
+ if (source.emissiveMap) {
890
+ target.emissiveMap = source.emissiveMap;
891
+ }
892
+ // Normal map (Lambert materials support normal mapping)
893
+ if (source.normalMap) {
894
+ target.normalMap = source.normalMap;
895
+ target.normalScale = source.normalScale.clone();
896
+ }
897
+ // Light map
898
+ if (source.lightMap) {
899
+ target.lightMap = source.lightMap;
900
+ target.lightMapIntensity = source.lightMapIntensity;
901
+ }
902
+ // AO map
903
+ if (source.aoMap) {
904
+ target.aoMap = source.aoMap;
905
+ target.aoMapIntensity = source.aoMapIntensity;
906
+ }
907
+ // Environment map (for reflections)
908
+ if (source.envMap) {
909
+ target.envMap = source.envMap;
910
+ target.reflectivity = Math.min(source.metalness + 0.1, 1.0);
911
+ }
912
+ // Alpha map
913
+ if (source.alphaMap) {
914
+ target.alphaMap = source.alphaMap;
915
+ }
916
+ // Copy UV transforms
917
+ this.copyUVTransforms(source, target);
918
+ }
919
+ /**
920
+ * Copies UV transformation properties for texture maps
921
+ *
922
+ * Transfers UV offset, repeat, rotation, and center properties from the
923
+ * source material's main texture map to the target material's map.
924
+ *
925
+ * @param source - The source MeshStandardMaterial
926
+ * @param target - The target MeshLambertMaterial
927
+ * @internal
928
+ */
929
+ static copyUVTransforms(source, target) {
930
+ // Main texture UV transform
931
+ if (source.map && target.map) {
932
+ target.map.offset.copy(source.map.offset);
933
+ target.map.repeat.copy(source.map.repeat);
934
+ target.map.rotation = source.map.rotation;
935
+ target.map.center.copy(source.map.center);
936
+ }
937
+ }
938
+ /**
939
+ * Converts transparency and rendering properties
940
+ *
941
+ * Transfers transparency, opacity, alpha testing, depth testing,
942
+ * depth writing, and blending mode settings from source to target.
943
+ *
944
+ * @param source - The source MeshStandardMaterial
945
+ * @param target - The target MeshLambertMaterial
946
+ * @internal
947
+ */
948
+ static convertTransparencyProperties(source, target) {
949
+ target.transparent = source.transparent;
950
+ target.opacity = source.opacity;
951
+ target.alphaTest = source.alphaTest;
952
+ target.depthTest = source.depthTest;
953
+ target.depthWrite = source.depthWrite;
954
+ target.blending = source.blending;
955
+ }
956
+ }
957
+
553
958
  /** Number of color channels in RGBA format */
554
959
  const RGBA_CHANNEL_COUNT = 4;
555
960
  /** Number of color channels in RGB format */
@@ -711,5 +1116,5 @@ class Sun extends DirectionalLight {
711
1116
  }
712
1117
  }
713
1118
 
714
- export { DualFovCamera, SceneTraversal, SkinnedMeshBaker, Sun };
1119
+ export { DualFovCamera, SceneTraversal, SkinnedMeshBaker, StandardToBasicConverter, StandardToLambertConverter, Sun };
715
1120
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/DualFovCamera.ts","../src/SceneTraversal.ts","../src/SkinnedMeshBaker.ts","../src/Sun.ts"],"sourcesContent":["import type { Box3, BufferAttribute, SkinnedMesh } from \"three\";\nimport { MathUtils, PerspectiveCamera, Vector3 } from \"three\";\n\n/** Default horizontal field of view in degrees */\nconst DEFAULT_HORIZONTAL_FOV = 90;\n/** Default vertical field of view in degrees */\nconst DEFAULT_VERTICAL_FOV = 90;\n/** Default aspect ratio (width/height) */\nconst DEFAULT_ASPECT = 1;\n/** Default near clipping plane distance */\nconst DEFAULT_NEAR = 1;\n/** Default far clipping plane distance */\nconst DEFAULT_FAR = 1000;\n\n/** Minimum allowed field of view in degrees */\nconst MIN_FOV = 1;\n/** Maximum allowed field of view in degrees */\nconst MAX_FOV = 179;\n\n/**\n * A camera that supports independent horizontal and vertical FOV settings.\n * Extends Three.js PerspectiveCamera to allow separate control over horizontal\n * and vertical fields of view.\n */\nexport class DualFovCamera extends PerspectiveCamera {\n /** Internal storage for horizontal field of view in degrees */\n private horizontalFovInternal: number;\n /** Internal storage for vertical field of view in degrees */\n private verticalFovInternal: number;\n\n /**\n * Creates a new DualFovCamera instance with independent horizontal and vertical FOV control.\n *\n * @param horizontalFov - Horizontal field of view in degrees. Must be between 1° and 179°. Defaults to 90°.\n * @param verticalFov - Vertical field of view in degrees. Must be between 1° and 179°. Defaults to 90°.\n * @param aspect - Camera aspect ratio (width/height). Defaults to 1.\n * @param near - Near clipping plane distance. Must be greater than 0. Defaults to 1.\n * @param far - Far clipping plane distance. Must be greater than near plane. Defaults to 1000.\n */\n constructor(\n horizontalFov = DEFAULT_HORIZONTAL_FOV,\n verticalFov = DEFAULT_VERTICAL_FOV,\n aspect = DEFAULT_ASPECT,\n near = DEFAULT_NEAR,\n far = DEFAULT_FAR,\n ) {\n super(verticalFov, aspect, near, far);\n this.horizontalFovInternal = horizontalFov;\n this.verticalFovInternal = verticalFov;\n this.updateProjectionMatrix();\n }\n\n /**\n * Gets the current horizontal field of view in degrees.\n *\n * @returns The horizontal FOV value between 1° and 179°\n */\n public get horizontalFov(): number {\n return this.horizontalFovInternal;\n }\n\n /**\n * Gets the current vertical field of view in degrees.\n *\n * @returns The vertical FOV value between 1° and 179°\n */\n public get verticalFov(): number {\n return this.verticalFovInternal;\n }\n\n /**\n * Sets the horizontal field of view in degrees.\n *\n * @param value - The horizontal FOV value in degrees. Will be clamped between 1° and 179°.\n */\n public set horizontalFov(value: number) {\n this.horizontalFovInternal = MathUtils.clamp(value, MIN_FOV, MAX_FOV);\n this.updateProjectionMatrix();\n }\n\n /**\n * Sets the vertical field of view in degrees.\n *\n * @param value - The vertical FOV value in degrees. Will be clamped between 1° and 179°.\n */\n public set verticalFov(value: number) {\n this.verticalFovInternal = MathUtils.clamp(value, MIN_FOV, MAX_FOV);\n this.updateProjectionMatrix();\n }\n\n /**\n * Updates both horizontal and vertical field of view values simultaneously.\n *\n * @param horizontal - Horizontal FOV in degrees. Will be clamped between 1° and 179°.\n * @param vertical - Vertical FOV in degrees. Will be clamped between 1° and 179°.\n */\n public setFov(horizontal: number, vertical: number): void {\n this.horizontalFovInternal = MathUtils.clamp(horizontal, MIN_FOV, MAX_FOV);\n this.verticalFovInternal = MathUtils.clamp(vertical, MIN_FOV, MAX_FOV);\n this.updateProjectionMatrix();\n }\n\n /**\n * Copies the field of view settings from another DualFovCamera instance.\n *\n * @param source - The DualFovCamera instance to copy FOV settings from.\n */\n public copyFovSettings(source: DualFovCamera): void {\n this.horizontalFovInternal = source.horizontalFov;\n this.verticalFovInternal = source.verticalFov;\n this.updateProjectionMatrix();\n }\n\n /**\n * Updates the projection matrix based on current FOV settings and aspect ratio.\n *\n * The behavior differs based on orientation:\n * - **Landscape mode (aspect > 1)**: Preserves horizontal FOV, calculates vertical FOV\n * - **Portrait mode (aspect ≤ 1)**: Preserves vertical FOV, calculates horizontal FOV\n *\n * This method is automatically called when FOV values or aspect ratio changes.\n *\n * @override\n */\n public override updateProjectionMatrix(): void {\n if (this.aspect > 1) {\n // Landscape orientation: preserve horizontal FOV\n const radians = MathUtils.degToRad(this.horizontalFovInternal);\n this.fov = MathUtils.radToDeg(\n Math.atan(Math.tan(radians / 2) / this.aspect) * 2,\n );\n } else {\n // Portrait orientation: preserve vertical FOV\n this.fov = this.verticalFovInternal;\n }\n\n super.updateProjectionMatrix();\n }\n\n /**\n * Gets the actual horizontal field of view after aspect ratio adjustments.\n *\n * In landscape mode, this returns the set horizontal FOV.\n * In portrait mode, this calculates the actual horizontal FOV based on the vertical FOV and aspect ratio.\n *\n * @returns The actual horizontal FOV in degrees\n */\n public getActualHorizontalFov(): number {\n if (this.aspect >= 1) {\n return this.horizontalFovInternal;\n }\n const verticalRadians = MathUtils.degToRad(this.verticalFovInternal);\n return MathUtils.radToDeg(\n Math.atan(Math.tan(verticalRadians / 2) * this.aspect) * 2,\n );\n }\n\n /**\n * Gets the actual vertical field of view after aspect ratio adjustments.\n *\n * In portrait mode, this returns the set vertical FOV.\n * In landscape mode, this calculates the actual vertical FOV based on the horizontal FOV and aspect ratio.\n *\n * @returns The actual vertical FOV in degrees\n */\n public getActualVerticalFov(): number {\n if (this.aspect < 1) {\n return this.verticalFovInternal;\n }\n const horizontalRadians = MathUtils.degToRad(this.horizontalFovInternal);\n return MathUtils.radToDeg(\n Math.atan(Math.tan(horizontalRadians / 2) / this.aspect) * 2,\n );\n }\n\n /**\n * Adjusts the vertical field of view to fit all specified points within the camera's view.\n *\n * This method calculates the required vertical FOV to ensure all provided vertices\n * are visible within the vertical bounds of the camera's frustum.\n *\n * @param vertices - Array of 3D points (in world coordinates) that should fit within the camera's vertical view\n */\n public fitVerticalFovToPoints(vertices: Vector3[]): void {\n const up = new Vector3(0, 1, 0).applyQuaternion(this.quaternion);\n\n let maxVerticalAngle = 0;\n\n for (const vertex of vertices) {\n const vertexToCam = this.position.clone().sub(vertex);\n const vertexDirection = vertexToCam.normalize();\n\n const verticalAngle =\n Math.asin(Math.abs(vertexDirection.dot(up))) *\n Math.sign(vertexDirection.dot(up));\n\n if (Math.abs(verticalAngle) > maxVerticalAngle) {\n maxVerticalAngle = Math.abs(verticalAngle);\n }\n }\n\n const requiredFov = MathUtils.radToDeg(2 * maxVerticalAngle);\n\n this.verticalFovInternal = MathUtils.clamp(requiredFov, MIN_FOV, MAX_FOV);\n this.updateProjectionMatrix();\n }\n\n /**\n * Adjusts the vertical field of view to fit a bounding box within the camera's view.\n *\n * This method calculates the required vertical FOV to ensure the entire bounding box\n * is visible within the vertical bounds of the camera's frustum.\n *\n * @param box - The 3D bounding box (in world coordinates) that should fit within the camera's vertical view\n */\n public fitVerticalFovToBox(box: Box3): void {\n this.fitVerticalFovToPoints([\n new Vector3(box.min.x, box.min.y, box.min.z),\n new Vector3(box.min.x, box.min.y, box.max.z),\n new Vector3(box.min.x, box.max.y, box.min.z),\n new Vector3(box.min.x, box.max.y, box.max.z),\n new Vector3(box.max.x, box.min.y, box.min.z),\n new Vector3(box.max.x, box.min.y, box.max.z),\n new Vector3(box.max.x, box.max.y, box.min.z),\n new Vector3(box.max.x, box.max.y, box.max.z),\n ]);\n }\n\n /**\n * Adjusts the vertical field of view to fit a skinned mesh within the camera's view.\n *\n * This method updates the mesh's skeleton, applies bone transformations to all vertices,\n * and then calculates the required vertical FOV to ensure the entire deformed mesh\n * is visible within the vertical bounds of the camera's frustum.\n *\n * @param skinnedMesh - The skinned mesh (with active skeleton) that should fit within the camera's vertical view\n */\n public fitVerticalFovToMesh(skinnedMesh: SkinnedMesh): void {\n skinnedMesh.updateWorldMatrix(true, true);\n skinnedMesh.skeleton.update();\n\n const bakedGeometry = skinnedMesh.geometry;\n const position = bakedGeometry.attributes[\"position\"] as BufferAttribute;\n const target = new Vector3();\n\n const points = [];\n\n for (let i = 0; i < position.count; i++) {\n target.fromBufferAttribute(position, i);\n skinnedMesh.applyBoneTransform(i, target);\n points.push(target.clone());\n }\n\n this.fitVerticalFovToPoints(points);\n }\n\n /**\n * Points the camera to look at the center of mass of a skinned mesh.\n *\n * This method updates the mesh's skeleton, applies bone transformations to all vertices,\n * calculates the center of mass using a clustering algorithm, and then orients the camera\n * to look at that point.\n *\n * The center of mass calculation uses an iterative clustering approach to find the\n * main concentration of vertices, which provides better results than a simple average\n * for complex meshes.\n *\n * @param skinnedMesh - The skinned mesh (with active skeleton) whose center of mass should be the camera's target\n */\n public lookAtMeshCenterOfMass(skinnedMesh: SkinnedMesh): void {\n skinnedMesh.updateWorldMatrix(true, true);\n skinnedMesh.skeleton.update();\n\n const bakedGeometry = skinnedMesh.geometry;\n const position = bakedGeometry.attributes.position as BufferAttribute;\n const target = new Vector3();\n const points: Vector3[] = [];\n\n for (let i = 0; i < position.count; i++) {\n target.fromBufferAttribute(position, i);\n skinnedMesh.applyBoneTransform(i, target);\n points.push(target.clone());\n }\n\n /**\n * Finds the main cluster center of a set of 3D points using iterative refinement.\n *\n * @param points - Array of 3D points to cluster\n * @param iterations - Number of refinement iterations to perform\n * @returns The calculated center point of the main cluster\n */\n const findMainCluster = (points: Vector3[], iterations = 3): Vector3 => {\n if (points.length === 0) {\n return new Vector3();\n }\n\n let center = points[Math.floor(points.length / 2)].clone();\n\n for (let i = 0; i < iterations; i++) {\n let total = new Vector3();\n let count = 0;\n\n for (const point of points) {\n if (\n point.distanceTo(center) < point.distanceTo(total) ||\n count === 0\n ) {\n total.add(point);\n count++;\n }\n }\n\n if (count > 0) {\n center = total.divideScalar(count);\n }\n }\n\n return center;\n };\n\n const centerOfMass = findMainCluster(points);\n this.lookAt(centerOfMass);\n }\n\n /**\n * Creates a deep copy of this DualFovCamera instance.\n *\n * The cloned camera will have identical FOV settings, position, rotation,\n * and all other camera properties.\n *\n * @returns A new DualFovCamera instance that is an exact copy of this one\n * @override\n */\n public override clone(): this {\n const camera = new DualFovCamera(\n this.horizontalFovInternal,\n this.verticalFovInternal,\n this.aspect,\n this.near,\n this.far,\n ) as this;\n\n camera.copy(this, true);\n return camera;\n }\n}\n","import type { Material, Object3D } from \"three\";\nimport { Mesh } from \"three\";\n\n/**\n * Constructor type for type-safe scene traversal operations.\n *\n * This type represents any constructor function that can be used to create instances of type T.\n * It's used for runtime type checking when filtering objects by their constructor type.\n *\n * @template T - The type that the constructor creates\n */\nexport type Constructor<T> = abstract new (...args: never[]) => T;\n\n/**\n * Utility class for finding and modifying objects in a Three.js scene graph.\n *\n * This class provides static methods for traversing Three.js scene hierarchies,\n * searching for specific objects or materials, and performing batch operations\n * on collections of scene objects.\n *\n * All methods perform depth-first traversal of the scene graph starting from\n * the provided root object and recursively processing all children.\n */\nexport class SceneTraversal {\n /**\n * Finds the first object in the scene hierarchy with an exact name match.\n *\n * Performs a depth-first search through the scene graph starting from the provided\n * root object. Returns the first object encountered whose name property exactly\n * matches the search string.\n *\n * @param object - The root Object3D to start searching from\n * @param name - The exact name to search for (case-sensitive)\n * @returns The first matching Object3D, or null if no match is found\n\n */\n public static getObjectByName(\n object: Object3D,\n name: string,\n ): Object3D | null {\n if (object.name === name) {\n return object;\n }\n\n for (const child of object.children) {\n const result = SceneTraversal.getObjectByName(child, name);\n if (result) {\n return result;\n }\n }\n\n return null;\n }\n\n /**\n * Finds the first material in the scene hierarchy with an exact name match.\n *\n * Performs a depth-first search through the scene graph, examining materials\n * attached to Mesh objects. Handles both single materials and material arrays.\n * Returns the first material encountered whose name property exactly matches\n * the search string.\n *\n * @param object - The root Object3D to start searching from\n * @param name - The exact material name to search for (case-sensitive)\n * @returns The first matching Material, or null if no match is found\n\n */\n public static getMaterialByName(\n object: Object3D,\n name: string,\n ): Material | null {\n if (object instanceof Mesh) {\n if (Array.isArray(object.material)) {\n for (const material of object.material) {\n if (material.name === name) {\n return material;\n }\n }\n } else if (object.material.name === name) {\n return object.material;\n }\n }\n\n for (const child of object.children) {\n const material = SceneTraversal.getMaterialByName(child, name);\n if (material) {\n return material;\n }\n }\n\n return null;\n }\n\n /**\n * Processes all objects of a specific type in the scene hierarchy.\n *\n * Performs a depth-first traversal and executes the provided callback function\n * for every object that is an instance of the specified type. This is useful\n * for batch operations on specific object types (e.g., all lights, all meshes, etc.).\n *\n * @template T - The type of objects to process\n * @param object - The root Object3D to start searching from\n * @param type - The constructor/class to filter by (e.g., DirectionalLight, Mesh)\n * @param callback - Function to execute for each matching object instance\n\n */\n public static enumerateObjectsByType<T>(\n object: Object3D,\n type: Constructor<T>,\n callback: (instance: T) => void,\n ): void {\n if (object instanceof type) {\n callback(object);\n }\n\n for (const child of object.children) {\n SceneTraversal.enumerateObjectsByType(child, type, callback);\n }\n }\n\n /**\n * Processes all materials found in mesh objects within the scene hierarchy.\n *\n * Performs a depth-first traversal, finding all Mesh objects and executing\n * the provided callback function for each material. Handles both single\n * materials and material arrays properly.\n *\n * @param object - The root Object3D to start searching from\n * @param callback - Function to execute for each material found\n\n */\n public static enumerateMaterials(\n object: Object3D,\n callback: (material: Material) => void,\n ): void {\n if (object instanceof Mesh) {\n if (Array.isArray(object.material)) {\n for (const material of object.material) {\n callback(material);\n }\n } else {\n callback(object.material);\n }\n }\n\n for (const child of object.children) {\n SceneTraversal.enumerateMaterials(child, callback);\n }\n }\n\n /**\n * Finds all objects in the scene hierarchy that match the specified filter criteria.\n *\n * Performs a depth-first search and collects all objects that either match\n * a regular expression pattern (applied to the object's name) or satisfy\n * a custom predicate function.\n *\n * @param object - The root Object3D to start searching from\n * @param filter - Either a RegExp to test against object names, or a predicate function\n * @returns Array of all matching Object3D instances\n\n */\n public static filterObjects(\n object: Object3D,\n filter: RegExp | ((object: Object3D) => boolean),\n ): Object3D[] {\n let result: Object3D[] = [];\n\n if (typeof filter === \"function\") {\n if (filter(object)) {\n result.push(object);\n }\n } else {\n if (object.name && filter.test(object.name)) {\n result.push(object);\n }\n }\n\n for (const child of object.children) {\n result = result.concat(SceneTraversal.filterObjects(child, filter));\n }\n\n return result;\n }\n\n /**\n * Finds all materials in the scene hierarchy whose names match a regular expression pattern.\n *\n * Performs a depth-first search through all Mesh objects and collects materials\n * whose name property matches the provided regular expression. Handles both\n * single materials and material arrays properly.\n *\n * @param object - The root Object3D to start searching from\n * @param name - Regular expression pattern to test against material names\n * @returns Array of all matching Material instances\n\n */\n public static filterMaterials(object: Object3D, name: RegExp): Material[] {\n let result: Material[] = [];\n\n if (object instanceof Mesh) {\n if (Array.isArray(object.material)) {\n for (const material of object.material) {\n if (material.name && name.test(material.name)) {\n result.push(material);\n }\n }\n } else {\n if (object.material.name && name.test(object.material.name)) {\n result.push(object.material);\n }\n }\n }\n\n for (const child of object.children) {\n result = result.concat(SceneTraversal.filterMaterials(child, name));\n }\n\n return result;\n }\n\n /**\n * Finds all objects (mesh users) that use materials with names matching a regular expression pattern.\n *\n * Performs a depth-first search through all Mesh objects and collects the mesh objects\n * whose materials have names that match the provided regular expression. This is useful\n * for finding all objects that use specific material types or naming patterns.\n *\n * @param object - The root Object3D to start searching from\n * @param materialName - Regular expression pattern to test against material names\n * @returns Array of all Mesh objects that use materials with matching names\n */\n public static findMaterialUsers(\n object: Object3D,\n materialName: RegExp,\n ): Mesh[] {\n let result: Mesh[] = [];\n\n if (object instanceof Mesh) {\n let hasMatchingMaterial = false;\n\n if (Array.isArray(object.material)) {\n for (const material of object.material) {\n if (material.name && materialName.test(material.name)) {\n hasMatchingMaterial = true;\n break;\n }\n }\n } else {\n if (object.material.name && materialName.test(object.material.name)) {\n hasMatchingMaterial = true;\n }\n }\n\n if (hasMatchingMaterial) {\n result.push(object);\n }\n }\n\n for (const child of object.children) {\n result = result.concat(\n SceneTraversal.findMaterialUsers(child, materialName),\n );\n }\n\n return result;\n }\n}\n","import type { AnimationClip, Object3D, SkinnedMesh } from \"three\";\nimport { AnimationMixer, BufferAttribute, Mesh, Vector3 } from \"three\";\n\n/** Number of components per vertex */\nconst COMPONENT_COUNT = 3;\n\n/** Convert skinned meshes to regular static meshes */\nexport class SkinnedMeshBaker {\n /**\n * Convert a skinned mesh to a regular mesh in its current pose.\n * The resulting mesh will have no bones but look identical.\n * \n * @param skinnedMesh - Mesh to convert\n * @returns Static mesh with baked vertex positions\n */\n public static bakePose(skinnedMesh: SkinnedMesh): Mesh {\n const bakedGeometry = skinnedMesh.geometry.clone();\n const position = bakedGeometry.attributes[\"position\"] as BufferAttribute;\n const newPositions = new Float32Array(position.count * COMPONENT_COUNT);\n const target = new Vector3();\n\n for (let i = 0; i < position.count; i++) {\n target.fromBufferAttribute(position, i);\n skinnedMesh.applyBoneTransform(i, target);\n newPositions[i * COMPONENT_COUNT + 0] = target.x;\n newPositions[i * COMPONENT_COUNT + 1] = target.y;\n newPositions[i * COMPONENT_COUNT + 2] = target.z;\n }\n\n bakedGeometry.setAttribute(\n \"position\",\n new BufferAttribute(newPositions, COMPONENT_COUNT),\n );\n bakedGeometry.computeVertexNormals();\n bakedGeometry.deleteAttribute(\"skinIndex\");\n bakedGeometry.deleteAttribute(\"skinWeight\");\n\n const mesh = new Mesh(bakedGeometry, skinnedMesh.material);\n mesh.name = skinnedMesh.name;\n return mesh;\n }\n\n /**\n * Bake a single frame from an animation into a static mesh.\n * \n * @param armature - Root object with bones (usually from GLTF)\n * @param skinnedMesh - Mesh to convert\n * @param timeOffset - Time in seconds within the animation\n * @param clip - Animation to get the pose from\n * @returns Static mesh with baked vertex positions\n */\n public static bakeAnimationFrame(\n armature: Object3D,\n skinnedMesh: SkinnedMesh,\n timeOffset: number,\n clip: AnimationClip,\n ): Mesh {\n const mixer = new AnimationMixer(armature);\n const action = mixer.clipAction(clip);\n action.play();\n mixer.setTime(timeOffset);\n\n armature.updateWorldMatrix(true, true);\n skinnedMesh.skeleton.update();\n\n return this.bakePose(skinnedMesh);\n }\n}","import type { Texture } from \"three\";\nimport { Box3, DirectionalLight, RGBAFormat, Spherical, Vector3 } from \"three\";\n\n/** Number of color channels in RGBA format */\nconst RGBA_CHANNEL_COUNT = 4;\n/** Number of color channels in RGB format */\nconst RGB_CHANNEL_COUNT = 3;\n\n/** Red channel weight for luminance calculation (ITU-R BT.709) */\nconst LUMINANCE_R = 0.2126;\n/** Green channel weight for luminance calculation (ITU-R BT.709) */\nconst LUMINANCE_G = 0.7152;\n/** Blue channel weight for luminance calculation (ITU-R BT.709) */\nconst LUMINANCE_B = 0.0722;\n\n/**\n * A directional light with spherical positioning controls and advanced shadow mapping.\n *\n * Extends Three.js DirectionalLight to provide intuitive spherical coordinate control\n * (distance, elevation, azimuth) and automatic shadow map configuration for bounding boxes.\n * Also supports automatic sun direction calculation from HDR environment maps.\n */\nexport class Sun extends DirectionalLight {\n /** Internal vectors to avoid garbage collection during calculations */\n private readonly tempVector3D0 = new Vector3();\n private readonly tempVector3D1 = new Vector3();\n private readonly tempVector3D2 = new Vector3();\n private readonly tempVector3D3 = new Vector3();\n private readonly tempVector3D4 = new Vector3();\n private readonly tempVector3D5 = new Vector3();\n private readonly tempVector3D6 = new Vector3();\n private readonly tempVector3D7 = new Vector3();\n private readonly tempBox3 = new Box3();\n private readonly tempSpherical = new Spherical();\n\n /**\n * Gets the distance from the light to its target (origin).\n *\n * @returns The distance in world units\n */\n public get distance(): number {\n return this.position.length();\n }\n\n /**\n * Gets the elevation angle (vertical angle from the horizontal plane).\n *\n * @returns The elevation angle in radians (0 = horizontal, π/2 = directly above)\n */\n public get elevation(): number {\n return this.tempSpherical.setFromVector3(this.position).phi;\n }\n\n /**\n * Gets the azimuth angle (horizontal rotation around the target).\n *\n * @returns The azimuth angle in radians (0 = positive X axis, π/2 = positive Z axis)\n */\n public get azimuth(): number {\n return this.tempSpherical.setFromVector3(this.position).theta;\n }\n\n /**\n * Sets the distance while preserving current elevation and azimuth angles.\n *\n * @param value - The new distance in world units\n */\n public set distance(value: number) {\n this.tempSpherical.setFromVector3(this.position);\n this.position.setFromSphericalCoords(\n value,\n this.tempSpherical.phi,\n this.tempSpherical.theta,\n );\n }\n\n /**\n * Sets the elevation angle while preserving current distance and azimuth.\n *\n * @param value - The new elevation angle in radians (0 = horizontal, π/2 = directly above)\n */\n public set elevation(value: number) {\n this.tempSpherical.setFromVector3(this.position);\n this.position.setFromSphericalCoords(\n this.tempSpherical.radius,\n value,\n this.tempSpherical.theta,\n );\n }\n\n /**\n * Sets the azimuth angle while preserving current distance and elevation.\n *\n * @param value - The new azimuth angle in radians (0 = positive X axis, π/2 = positive Z axis)\n */\n public set azimuth(value: number) {\n this.tempSpherical.setFromVector3(this.position);\n this.position.setFromSphericalCoords(\n this.tempSpherical.radius,\n this.tempSpherical.phi,\n value,\n );\n }\n\n /**\n * Configures the shadow camera to optimally cover a bounding box.\n *\n * This method automatically adjusts the directional light's shadow camera frustum\n * to perfectly encompass the provided bounding box, ensuring efficient shadow map\n * usage and eliminating shadow clipping issues.\n *\n * @param box3 - The 3D bounding box to cover with shadows\n */\n public configureShadowsForBoundingBox(box3: Box3): void {\n const camera = this.shadow.camera;\n\n this.target.updateWorldMatrix(true, false);\n this.lookAt(this.target.getWorldPosition(this.tempVector3D0));\n\n this.updateWorldMatrix(true, false);\n\n const points: Vector3[] = [\n this.tempVector3D0.set(box3.min.x, box3.min.y, box3.min.z),\n this.tempVector3D1.set(box3.min.x, box3.min.y, box3.max.z),\n this.tempVector3D2.set(box3.min.x, box3.max.y, box3.min.z),\n this.tempVector3D3.set(box3.min.x, box3.max.y, box3.max.z),\n this.tempVector3D4.set(box3.max.x, box3.min.y, box3.min.z),\n this.tempVector3D5.set(box3.max.x, box3.min.y, box3.max.z),\n this.tempVector3D6.set(box3.max.x, box3.max.y, box3.min.z),\n this.tempVector3D7.set(box3.max.x, box3.max.y, box3.max.z),\n ];\n\n const inverseMatrix = this.matrixWorld.clone().invert();\n\n for (const point of points) {\n point.applyMatrix4(inverseMatrix);\n }\n\n const newBox3 = this.tempBox3.setFromPoints(points);\n\n camera.left = newBox3.min.x;\n camera.bottom = newBox3.min.y;\n camera.near = -newBox3.max.z;\n\n camera.right = newBox3.max.x;\n camera.top = newBox3.max.y;\n camera.far = -newBox3.min.z;\n\n camera.updateWorldMatrix(true, false);\n camera.updateProjectionMatrix();\n }\n\n /**\n * Sets the sun's direction based on the brightest point in an HDR environment map.\n *\n * This method analyzes an HDR texture to find the pixel with the highest luminance\n * value and positions the sun to shine from that direction. This is useful for\n * creating realistic lighting that matches HDR environment maps.\n *\n * @param texture - The HDR texture to analyze (must have image data available)\n * @param distance - The distance to place the sun from the origin (defaults to 1)\n */\n public setDirectionFromHDRTexture(texture: Texture, distance = 1): void {\n const data = texture.image.data;\n const width = texture.image.width;\n const height = texture.image.height;\n\n let maxLuminance = 0;\n let maxIndex = 0;\n\n // Find brightest pixel\n\n const step =\n texture.format === RGBAFormat ? RGBA_CHANNEL_COUNT : RGB_CHANNEL_COUNT;\n for (let i = 0; i < data.length; i += step) {\n const r = data[i];\n const g = data[i + 1];\n const b = data[i + 2];\n const luminance = LUMINANCE_R * r + LUMINANCE_G * g + LUMINANCE_B * b;\n if (luminance > maxLuminance) {\n maxLuminance = luminance;\n maxIndex = i;\n }\n }\n\n // Convert to spherical coordinates\n const pixelIndex = maxIndex / step;\n const x = pixelIndex % width;\n const y = Math.floor(pixelIndex / width);\n\n const u = x / width;\n const v = y / height;\n\n const elevation = v * Math.PI;\n const azimuth = u * -Math.PI * 2 - Math.PI / 2;\n\n this.position.setFromSphericalCoords(distance, elevation, azimuth);\n }\n}\n"],"names":[],"mappings":";;AAGA;AACA,MAAM,sBAAsB,GAAG,EAAE;AACjC;AACA,MAAM,oBAAoB,GAAG,EAAE;AAC/B;AACA,MAAM,cAAc,GAAG,CAAC;AACxB;AACA,MAAM,YAAY,GAAG,CAAC;AACtB;AACA,MAAM,WAAW,GAAG,IAAI;AAExB;AACA,MAAM,OAAO,GAAG,CAAC;AACjB;AACA,MAAM,OAAO,GAAG,GAAG;AAEnB;;;;AAIG;AACG,MAAO,aAAc,SAAQ,iBAAiB,CAAA;AAMlD;;;;;;;;AAQG;AACH,IAAA,WAAA,CACE,aAAa,GAAG,sBAAsB,EACtC,WAAW,GAAG,oBAAoB,EAClC,MAAM,GAAG,cAAc,EACvB,IAAI,GAAG,YAAY,EACnB,GAAG,GAAG,WAAW,EAAA;QAEjB,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC;QACrC,IAAI,CAAA,8BAAA,GAAyB,aAAa;QAC1C,IAAI,CAAA,4BAAA,GAAuB,WAAW;QACtC,IAAI,CAAC,sBAAsB,EAAE;IAC/B;AAEA;;;;AAIG;AACH,IAAA,IAAW,aAAa,GAAA;AACtB,QAAA,OAAO,IAAI,CAAA,8BAAA;IACb;AAEA;;;;AAIG;AACH,IAAA,IAAW,WAAW,GAAA;AACpB,QAAA,OAAO,IAAI,CAAA,4BAAA;IACb;AAEA;;;;AAIG;IACH,IAAW,aAAa,CAAC,KAAa,EAAA;QACpC,IAAI,CAAA,8BAAA,GAAyB,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC;QACrE,IAAI,CAAC,sBAAsB,EAAE;IAC/B;AAEA;;;;AAIG;IACH,IAAW,WAAW,CAAC,KAAa,EAAA;QAClC,IAAI,CAAA,4BAAA,GAAuB,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC;QACnE,IAAI,CAAC,sBAAsB,EAAE;IAC/B;AAEA;;;;;AAKG;IACI,MAAM,CAAC,UAAkB,EAAE,QAAgB,EAAA;QAChD,IAAI,CAAA,8BAAA,GAAyB,SAAS,CAAC,KAAK,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC;QAC1E,IAAI,CAAA,4BAAA,GAAuB,SAAS,CAAC,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC;QACtE,IAAI,CAAC,sBAAsB,EAAE;IAC/B;AAEA;;;;AAIG;AACI,IAAA,eAAe,CAAC,MAAqB,EAAA;AAC1C,QAAA,IAAI,CAAA,8BAAA,GAAyB,MAAM,CAAC,aAAa;AACjD,QAAA,IAAI,CAAA,4BAAA,GAAuB,MAAM,CAAC,WAAW;QAC7C,IAAI,CAAC,sBAAsB,EAAE;IAC/B;AAEA;;;;;;;;;;AAUG;IACa,sBAAsB,GAAA;AACpC,QAAA,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;;YAEnB,MAAM,OAAO,GAAG,SAAS,CAAC,QAAQ,CAAC,IAAI,gCAAuB;YAC9D,IAAI,CAAC,GAAG,GAAG,SAAS,CAAC,QAAQ,CAC3B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CACnD;QACH;aAAO;;AAEL,YAAA,IAAI,CAAC,GAAG,GAAG,IAAI,6BAAoB;QACrC;QAEA,KAAK,CAAC,sBAAsB,EAAE;IAChC;AAEA;;;;;;;AAOG;IACI,sBAAsB,GAAA;AAC3B,QAAA,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE;AACpB,YAAA,OAAO,IAAI,CAAA,8BAAA;QACb;QACA,MAAM,eAAe,GAAG,SAAS,CAAC,QAAQ,CAAC,IAAI,8BAAqB;QACpE,OAAO,SAAS,CAAC,QAAQ,CACvB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAC3D;IACH;AAEA;;;;;;;AAOG;IACI,oBAAoB,GAAA;AACzB,QAAA,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE;AACnB,YAAA,OAAO,IAAI,CAAA,4BAAA;QACb;QACA,MAAM,iBAAiB,GAAG,SAAS,CAAC,QAAQ,CAAC,IAAI,gCAAuB;QACxE,OAAO,SAAS,CAAC,QAAQ,CACvB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,iBAAiB,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAC7D;IACH;AAEA;;;;;;;AAOG;AACI,IAAA,sBAAsB,CAAC,QAAmB,EAAA;AAC/C,QAAA,MAAM,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC;QAEhE,IAAI,gBAAgB,GAAG,CAAC;AAExB,QAAA,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE;AAC7B,YAAA,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC;AACrD,YAAA,MAAM,eAAe,GAAG,WAAW,CAAC,SAAS,EAAE;AAE/C,YAAA,MAAM,aAAa,GACjB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC5C,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAEpC,IAAI,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,gBAAgB,EAAE;AAC9C,gBAAA,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC;YAC5C;QACF;QAEA,MAAM,WAAW,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC,GAAG,gBAAgB,CAAC;QAE5D,IAAI,CAAA,4BAAA,GAAuB,SAAS,CAAC,KAAK,CAAC,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC;QACzE,IAAI,CAAC,sBAAsB,EAAE;IAC/B;AAEA;;;;;;;AAOG;AACI,IAAA,mBAAmB,CAAC,GAAS,EAAA;QAClC,IAAI,CAAC,sBAAsB,CAAC;AAC1B,YAAA,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5C,YAAA,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5C,YAAA,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5C,YAAA,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5C,YAAA,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5C,YAAA,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5C,YAAA,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5C,YAAA,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7C,SAAA,CAAC;IACJ;AAEA;;;;;;;;AAQG;AACI,IAAA,oBAAoB,CAAC,WAAwB,EAAA;AAClD,QAAA,WAAW,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC;AACzC,QAAA,WAAW,CAAC,QAAQ,CAAC,MAAM,EAAE;AAE7B,QAAA,MAAM,aAAa,GAAG,WAAW,CAAC,QAAQ;QAC1C,MAAM,QAAQ,GAAG,aAAa,CAAC,UAAU,CAAC,UAAU,CAAoB;AACxE,QAAA,MAAM,MAAM,GAAG,IAAI,OAAO,EAAE;QAE5B,MAAM,MAAM,GAAG,EAAE;AAEjB,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;AACvC,YAAA,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,CAAC,CAAC;AACvC,YAAA,WAAW,CAAC,kBAAkB,CAAC,CAAC,EAAE,MAAM,CAAC;YACzC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC7B;AAEA,QAAA,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC;IACrC;AAEA;;;;;;;;;;;;AAYG;AACI,IAAA,sBAAsB,CAAC,WAAwB,EAAA;AACpD,QAAA,WAAW,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC;AACzC,QAAA,WAAW,CAAC,QAAQ,CAAC,MAAM,EAAE;AAE7B,QAAA,MAAM,aAAa,GAAG,WAAW,CAAC,QAAQ;AAC1C,QAAA,MAAM,QAAQ,GAAG,aAAa,CAAC,UAAU,CAAC,QAA2B;AACrE,QAAA,MAAM,MAAM,GAAG,IAAI,OAAO,EAAE;QAC5B,MAAM,MAAM,GAAc,EAAE;AAE5B,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;AACvC,YAAA,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,CAAC,CAAC;AACvC,YAAA,WAAW,CAAC,kBAAkB,CAAC,CAAC,EAAE,MAAM,CAAC;YACzC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC7B;AAEA;;;;;;AAMG;QACH,MAAM,eAAe,GAAG,CAAC,MAAiB,EAAE,UAAU,GAAG,CAAC,KAAa;AACrE,YAAA,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE;gBACvB,OAAO,IAAI,OAAO,EAAE;YACtB;AAEA,YAAA,IAAI,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE;AAE1D,YAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,EAAE;AACnC,gBAAA,IAAI,KAAK,GAAG,IAAI,OAAO,EAAE;gBACzB,IAAI,KAAK,GAAG,CAAC;AAEb,gBAAA,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE;AAC1B,oBAAA,IACE,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;wBAClD,KAAK,KAAK,CAAC,EACX;AACA,wBAAA,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;AAChB,wBAAA,KAAK,EAAE;oBACT;gBACF;AAEA,gBAAA,IAAI,KAAK,GAAG,CAAC,EAAE;AACb,oBAAA,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC;gBACpC;YACF;AAEA,YAAA,OAAO,MAAM;AACf,QAAA,CAAC;AAED,QAAA,MAAM,YAAY,GAAG,eAAe,CAAC,MAAM,CAAC;AAC5C,QAAA,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;IAC3B;AAEA;;;;;;;;AAQG;IACa,KAAK,GAAA;QACnB,MAAM,MAAM,GAAG,IAAI,aAAa,CAC9B,IAAI,CAAA,8BAAA,EACJ,IAAI,CAAA,4BAAA,EACJ,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,GAAG,CACD;AAET,QAAA,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC;AACvB,QAAA,OAAO,MAAM;IACf;AACD;;AC5UD;;;;;;;;;AASG;MACU,cAAc,CAAA;AACzB;;;;;;;;;;;AAWG;AACI,IAAA,OAAO,eAAe,CAC3B,MAAgB,EAChB,IAAY,EAAA;AAEZ,QAAA,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI,EAAE;AACxB,YAAA,OAAO,MAAM;QACf;AAEA,QAAA,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,EAAE;YACnC,MAAM,MAAM,GAAG,cAAc,CAAC,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC;YAC1D,IAAI,MAAM,EAAE;AACV,gBAAA,OAAO,MAAM;YACf;QACF;AAEA,QAAA,OAAO,IAAI;IACb;AAEA;;;;;;;;;;;;AAYG;AACI,IAAA,OAAO,iBAAiB,CAC7B,MAAgB,EAChB,IAAY,EAAA;AAEZ,QAAA,IAAI,MAAM,YAAY,IAAI,EAAE;YAC1B,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE;AAClC,gBAAA,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE;AACtC,oBAAA,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI,EAAE;AAC1B,wBAAA,OAAO,QAAQ;oBACjB;gBACF;YACF;iBAAO,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,IAAI,EAAE;gBACxC,OAAO,MAAM,CAAC,QAAQ;YACxB;QACF;AAEA,QAAA,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,EAAE;YACnC,MAAM,QAAQ,GAAG,cAAc,CAAC,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC;YAC9D,IAAI,QAAQ,EAAE;AACZ,gBAAA,OAAO,QAAQ;YACjB;QACF;AAEA,QAAA,OAAO,IAAI;IACb;AAEA;;;;;;;;;;;;AAYG;AACI,IAAA,OAAO,sBAAsB,CAClC,MAAgB,EAChB,IAAoB,EACpB,QAA+B,EAAA;AAE/B,QAAA,IAAI,MAAM,YAAY,IAAI,EAAE;YAC1B,QAAQ,CAAC,MAAM,CAAC;QAClB;AAEA,QAAA,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,EAAE;YACnC,cAAc,CAAC,sBAAsB,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC;QAC9D;IACF;AAEA;;;;;;;;;;AAUG;AACI,IAAA,OAAO,kBAAkB,CAC9B,MAAgB,EAChB,QAAsC,EAAA;AAEtC,QAAA,IAAI,MAAM,YAAY,IAAI,EAAE;YAC1B,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE;AAClC,gBAAA,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE;oBACtC,QAAQ,CAAC,QAAQ,CAAC;gBACpB;YACF;iBAAO;AACL,gBAAA,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC;YAC3B;QACF;AAEA,QAAA,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,EAAE;AACnC,YAAA,cAAc,CAAC,kBAAkB,CAAC,KAAK,EAAE,QAAQ,CAAC;QACpD;IACF;AAEA;;;;;;;;;;;AAWG;AACI,IAAA,OAAO,aAAa,CACzB,MAAgB,EAChB,MAAgD,EAAA;QAEhD,IAAI,MAAM,GAAe,EAAE;AAE3B,QAAA,IAAI,OAAO,MAAM,KAAK,UAAU,EAAE;AAChC,YAAA,IAAI,MAAM,CAAC,MAAM,CAAC,EAAE;AAClB,gBAAA,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;YACrB;QACF;aAAO;AACL,YAAA,IAAI,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;AAC3C,gBAAA,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;YACrB;QACF;AAEA,QAAA,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,EAAE;AACnC,YAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACrE;AAEA,QAAA,OAAO,MAAM;IACf;AAEA;;;;;;;;;;;AAWG;AACI,IAAA,OAAO,eAAe,CAAC,MAAgB,EAAE,IAAY,EAAA;QAC1D,IAAI,MAAM,GAAe,EAAE;AAE3B,QAAA,IAAI,MAAM,YAAY,IAAI,EAAE;YAC1B,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE;AAClC,gBAAA,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE;AACtC,oBAAA,IAAI,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AAC7C,wBAAA,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;oBACvB;gBACF;YACF;iBAAO;AACL,gBAAA,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AAC3D,oBAAA,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;gBAC9B;YACF;QACF;AAEA,QAAA,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,EAAE;AACnC,YAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACrE;AAEA,QAAA,OAAO,MAAM;IACf;AAEA;;;;;;;;;;AAUG;AACI,IAAA,OAAO,iBAAiB,CAC7B,MAAgB,EAChB,YAAoB,EAAA;QAEpB,IAAI,MAAM,GAAW,EAAE;AAEvB,QAAA,IAAI,MAAM,YAAY,IAAI,EAAE;YAC1B,IAAI,mBAAmB,GAAG,KAAK;YAE/B,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE;AAClC,gBAAA,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE;AACtC,oBAAA,IAAI,QAAQ,CAAC,IAAI,IAAI,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;wBACrD,mBAAmB,GAAG,IAAI;wBAC1B;oBACF;gBACF;YACF;iBAAO;AACL,gBAAA,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,IAAI,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;oBACnE,mBAAmB,GAAG,IAAI;gBAC5B;YACF;YAEA,IAAI,mBAAmB,EAAE;AACvB,gBAAA,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;YACrB;QACF;AAEA,QAAA,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,EAAE;AACnC,YAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CACpB,cAAc,CAAC,iBAAiB,CAAC,KAAK,EAAE,YAAY,CAAC,CACtD;QACH;AAEA,QAAA,OAAO,MAAM;IACf;AACD;;ACxQD;AACA,MAAM,eAAe,GAAG,CAAC;AAEzB;MACa,gBAAgB,CAAA;AAC3B;;;;;;AAMG;IACI,OAAO,QAAQ,CAAC,WAAwB,EAAA;QAC7C,MAAM,aAAa,GAAG,WAAW,CAAC,QAAQ,CAAC,KAAK,EAAE;QAClD,MAAM,QAAQ,GAAG,aAAa,CAAC,UAAU,CAAC,UAAU,CAAoB;QACxE,MAAM,YAAY,GAAG,IAAI,YAAY,CAAC,QAAQ,CAAC,KAAK,GAAG,eAAe,CAAC;AACvE,QAAA,MAAM,MAAM,GAAG,IAAI,OAAO,EAAE;AAE5B,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;AACvC,YAAA,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,CAAC,CAAC;AACvC,YAAA,WAAW,CAAC,kBAAkB,CAAC,CAAC,EAAE,MAAM,CAAC;YACzC,YAAY,CAAC,CAAC,GAAG,eAAe,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;YAChD,YAAY,CAAC,CAAC,GAAG,eAAe,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;YAChD,YAAY,CAAC,CAAC,GAAG,eAAe,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;QAClD;AAEA,QAAA,aAAa,CAAC,YAAY,CACxB,UAAU,EACV,IAAI,eAAe,CAAC,YAAY,EAAE,eAAe,CAAC,CACnD;QACD,aAAa,CAAC,oBAAoB,EAAE;AACpC,QAAA,aAAa,CAAC,eAAe,CAAC,WAAW,CAAC;AAC1C,QAAA,aAAa,CAAC,eAAe,CAAC,YAAY,CAAC;QAE3C,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,QAAQ,CAAC;AAC1D,QAAA,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC,IAAI;AAC5B,QAAA,OAAO,IAAI;IACb;AAEA;;;;;;;;AAQG;IACI,OAAO,kBAAkB,CAC9B,QAAkB,EAClB,WAAwB,EACxB,UAAkB,EAClB,IAAmB,EAAA;AAEnB,QAAA,MAAM,KAAK,GAAG,IAAI,cAAc,CAAC,QAAQ,CAAC;QAC1C,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;QACrC,MAAM,CAAC,IAAI,EAAE;AACb,QAAA,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;AAEzB,QAAA,QAAQ,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC;AACtC,QAAA,WAAW,CAAC,QAAQ,CAAC,MAAM,EAAE;AAE7B,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC;IACnC;AACD;;AChED;AACA,MAAM,kBAAkB,GAAG,CAAC;AAC5B;AACA,MAAM,iBAAiB,GAAG,CAAC;AAE3B;AACA,MAAM,WAAW,GAAG,MAAM;AAC1B;AACA,MAAM,WAAW,GAAG,MAAM;AAC1B;AACA,MAAM,WAAW,GAAG,MAAM;AAE1B;;;;;;AAMG;AACG,MAAO,GAAI,SAAQ,gBAAgB,CAAA;AAAzC,IAAA,WAAA,GAAA;;;sCAEmC,IAAI,OAAO,EAAE;sCACb,IAAI,OAAO,EAAE;sCACb,IAAI,OAAO,EAAE;sCACb,IAAI,OAAO,EAAE;sCACb,IAAI,OAAO,EAAE;sCACb,IAAI,OAAO,EAAE;sCACb,IAAI,OAAO,EAAE;sCACb,IAAI,OAAO,EAAE;iCAClB,IAAI,IAAI,EAAE;sCACL,IAAI,SAAS,EAAE;IAqKlD;AAnKE;;;;AAIG;AACH,IAAA,IAAW,QAAQ,GAAA;AACjB,QAAA,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE;IAC/B;AAEA;;;;AAIG;AACH,IAAA,IAAW,SAAS,GAAA;QAClB,OAAO,IAAI,CAAA,sBAAA,CAAe,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG;IAC7D;AAEA;;;;AAIG;AACH,IAAA,IAAW,OAAO,GAAA;QAChB,OAAO,IAAI,CAAA,sBAAA,CAAe,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK;IAC/D;AAEA;;;;AAIG;IACH,IAAW,QAAQ,CAAC,KAAa,EAAA;AAC/B,QAAA,IAAI,wBAAe,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC;AAChD,QAAA,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAClC,KAAK,EACL,IAAI,CAAA,sBAAA,CAAe,GAAG,EACtB,IAAI,CAAA,sBAAA,CAAe,KAAK,CACzB;IACH;AAEA;;;;AAIG;IACH,IAAW,SAAS,CAAC,KAAa,EAAA;AAChC,QAAA,IAAI,wBAAe,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC;AAChD,QAAA,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAClC,IAAI,CAAA,sBAAA,CAAe,MAAM,EACzB,KAAK,EACL,IAAI,CAAA,sBAAA,CAAe,KAAK,CACzB;IACH;AAEA;;;;AAIG;IACH,IAAW,OAAO,CAAC,KAAa,EAAA;AAC9B,QAAA,IAAI,wBAAe,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC;AAChD,QAAA,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAClC,IAAI,CAAA,sBAAA,CAAe,MAAM,EACzB,IAAI,CAAA,sBAAA,CAAe,GAAG,EACtB,KAAK,CACN;IACH;AAEA;;;;;;;;AAQG;AACI,IAAA,8BAA8B,CAAC,IAAU,EAAA;AAC9C,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM;QAEjC,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC;AAC1C,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAA,sBAAA,CAAe,CAAC;AAE7D,QAAA,IAAI,CAAC,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC;AAEnC,QAAA,MAAM,MAAM,GAAc;YACxB,IAAI,CAAA,sBAAA,CAAe,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1D,IAAI,CAAA,sBAAA,CAAe,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1D,IAAI,CAAA,sBAAA,CAAe,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1D,IAAI,CAAA,sBAAA,CAAe,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1D,IAAI,CAAA,sBAAA,CAAe,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1D,IAAI,CAAA,sBAAA,CAAe,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1D,IAAI,CAAA,sBAAA,CAAe,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1D,IAAI,CAAA,sBAAA,CAAe,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;SAC3D;QAED,MAAM,aAAa,GAAG,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE;AAEvD,QAAA,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE;AAC1B,YAAA,KAAK,CAAC,YAAY,CAAC,aAAa,CAAC;QACnC;QAEA,MAAM,OAAO,GAAG,IAAI,CAAA,iBAAA,CAAU,aAAa,CAAC,MAAM,CAAC;QAEnD,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC3B,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7B,MAAM,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAE5B,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,MAAM,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC1B,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AAE3B,QAAA,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC;QACrC,MAAM,CAAC,sBAAsB,EAAE;IACjC;AAEA;;;;;;;;;AASG;AACI,IAAA,0BAA0B,CAAC,OAAgB,EAAE,QAAQ,GAAG,CAAC,EAAA;AAC9D,QAAA,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI;AAC/B,QAAA,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK;AACjC,QAAA,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM;QAEnC,IAAI,YAAY,GAAG,CAAC;QACpB,IAAI,QAAQ,GAAG,CAAC;;AAIhB,QAAA,MAAM,IAAI,GACR,OAAO,CAAC,MAAM,KAAK,UAAU,GAAG,kBAAkB,GAAG,iBAAiB;AACxE,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,IAAI,EAAE;AAC1C,YAAA,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;YACjB,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YACrB,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;AACrB,YAAA,MAAM,SAAS,GAAG,WAAW,GAAG,CAAC,GAAG,WAAW,GAAG,CAAC,GAAG,WAAW,GAAG,CAAC;AACrE,YAAA,IAAI,SAAS,GAAG,YAAY,EAAE;gBAC5B,YAAY,GAAG,SAAS;gBACxB,QAAQ,GAAG,CAAC;YACd;QACF;;AAGA,QAAA,MAAM,UAAU,GAAG,QAAQ,GAAG,IAAI;AAClC,QAAA,MAAM,CAAC,GAAG,UAAU,GAAG,KAAK;QAC5B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC;AAExC,QAAA,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK;AACnB,QAAA,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM;AAEpB,QAAA,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE;AAC7B,QAAA,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,CAAC;QAE9C,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC;IACpE;AACD;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../src/DualFovCamera.ts","../src/SceneTraversal.ts","../src/SkinnedMeshBaker.ts","../src/StandardToBasicConverter.ts","../src/StandardToLambertConverter.ts","../src/Sun.ts"],"sourcesContent":["import type { Box3, BufferAttribute, SkinnedMesh } from \"three\";\nimport { MathUtils, PerspectiveCamera, Vector3 } from \"three\";\n\n/** Default horizontal field of view in degrees */\nconst DEFAULT_HORIZONTAL_FOV = 90;\n/** Default vertical field of view in degrees */\nconst DEFAULT_VERTICAL_FOV = 90;\n/** Default aspect ratio (width/height) */\nconst DEFAULT_ASPECT = 1;\n/** Default near clipping plane distance */\nconst DEFAULT_NEAR = 1;\n/** Default far clipping plane distance */\nconst DEFAULT_FAR = 1000;\n\n/** Minimum allowed field of view in degrees */\nconst MIN_FOV = 1;\n/** Maximum allowed field of view in degrees */\nconst MAX_FOV = 179;\n\n/**\n * A camera that supports independent horizontal and vertical FOV settings.\n * Extends Three.js PerspectiveCamera to allow separate control over horizontal\n * and vertical fields of view.\n */\nexport class DualFovCamera extends PerspectiveCamera {\n /** Internal storage for horizontal field of view in degrees */\n private horizontalFovInternal: number;\n /** Internal storage for vertical field of view in degrees */\n private verticalFovInternal: number;\n\n /**\n * Creates a new DualFovCamera instance with independent horizontal and vertical FOV control.\n *\n * @param horizontalFov - Horizontal field of view in degrees. Must be between 1° and 179°. Defaults to 90°.\n * @param verticalFov - Vertical field of view in degrees. Must be between 1° and 179°. Defaults to 90°.\n * @param aspect - Camera aspect ratio (width/height). Defaults to 1.\n * @param near - Near clipping plane distance. Must be greater than 0. Defaults to 1.\n * @param far - Far clipping plane distance. Must be greater than near plane. Defaults to 1000.\n */\n constructor(\n horizontalFov = DEFAULT_HORIZONTAL_FOV,\n verticalFov = DEFAULT_VERTICAL_FOV,\n aspect = DEFAULT_ASPECT,\n near = DEFAULT_NEAR,\n far = DEFAULT_FAR,\n ) {\n super(verticalFov, aspect, near, far);\n this.horizontalFovInternal = horizontalFov;\n this.verticalFovInternal = verticalFov;\n this.updateProjectionMatrix();\n }\n\n /**\n * Gets the current horizontal field of view in degrees.\n *\n * @returns The horizontal FOV value between 1° and 179°\n */\n public get horizontalFov(): number {\n return this.horizontalFovInternal;\n }\n\n /**\n * Gets the current vertical field of view in degrees.\n *\n * @returns The vertical FOV value between 1° and 179°\n */\n public get verticalFov(): number {\n return this.verticalFovInternal;\n }\n\n /**\n * Sets the horizontal field of view in degrees.\n *\n * @param value - The horizontal FOV value in degrees. Will be clamped between 1° and 179°.\n */\n public set horizontalFov(value: number) {\n this.horizontalFovInternal = MathUtils.clamp(value, MIN_FOV, MAX_FOV);\n this.updateProjectionMatrix();\n }\n\n /**\n * Sets the vertical field of view in degrees.\n *\n * @param value - The vertical FOV value in degrees. Will be clamped between 1° and 179°.\n */\n public set verticalFov(value: number) {\n this.verticalFovInternal = MathUtils.clamp(value, MIN_FOV, MAX_FOV);\n this.updateProjectionMatrix();\n }\n\n /**\n * Updates both horizontal and vertical field of view values simultaneously.\n *\n * @param horizontal - Horizontal FOV in degrees. Will be clamped between 1° and 179°.\n * @param vertical - Vertical FOV in degrees. Will be clamped between 1° and 179°.\n */\n public setFov(horizontal: number, vertical: number): void {\n this.horizontalFovInternal = MathUtils.clamp(horizontal, MIN_FOV, MAX_FOV);\n this.verticalFovInternal = MathUtils.clamp(vertical, MIN_FOV, MAX_FOV);\n this.updateProjectionMatrix();\n }\n\n /**\n * Copies the field of view settings from another DualFovCamera instance.\n *\n * @param source - The DualFovCamera instance to copy FOV settings from.\n */\n public copyFovSettings(source: DualFovCamera): void {\n this.horizontalFovInternal = source.horizontalFov;\n this.verticalFovInternal = source.verticalFov;\n this.updateProjectionMatrix();\n }\n\n /**\n * Updates the projection matrix based on current FOV settings and aspect ratio.\n *\n * The behavior differs based on orientation:\n * - **Landscape mode (aspect > 1)**: Preserves horizontal FOV, calculates vertical FOV\n * - **Portrait mode (aspect ≤ 1)**: Preserves vertical FOV, calculates horizontal FOV\n *\n * This method is automatically called when FOV values or aspect ratio changes.\n *\n * @override\n */\n public override updateProjectionMatrix(): void {\n if (this.aspect > 1) {\n // Landscape orientation: preserve horizontal FOV\n const radians = MathUtils.degToRad(this.horizontalFovInternal);\n this.fov = MathUtils.radToDeg(\n Math.atan(Math.tan(radians / 2) / this.aspect) * 2,\n );\n } else {\n // Portrait orientation: preserve vertical FOV\n this.fov = this.verticalFovInternal;\n }\n\n super.updateProjectionMatrix();\n }\n\n /**\n * Gets the actual horizontal field of view after aspect ratio adjustments.\n *\n * In landscape mode, this returns the set horizontal FOV.\n * In portrait mode, this calculates the actual horizontal FOV based on the vertical FOV and aspect ratio.\n *\n * @returns The actual horizontal FOV in degrees\n */\n public getActualHorizontalFov(): number {\n if (this.aspect >= 1) {\n return this.horizontalFovInternal;\n }\n const verticalRadians = MathUtils.degToRad(this.verticalFovInternal);\n return MathUtils.radToDeg(\n Math.atan(Math.tan(verticalRadians / 2) * this.aspect) * 2,\n );\n }\n\n /**\n * Gets the actual vertical field of view after aspect ratio adjustments.\n *\n * In portrait mode, this returns the set vertical FOV.\n * In landscape mode, this calculates the actual vertical FOV based on the horizontal FOV and aspect ratio.\n *\n * @returns The actual vertical FOV in degrees\n */\n public getActualVerticalFov(): number {\n if (this.aspect < 1) {\n return this.verticalFovInternal;\n }\n const horizontalRadians = MathUtils.degToRad(this.horizontalFovInternal);\n return MathUtils.radToDeg(\n Math.atan(Math.tan(horizontalRadians / 2) / this.aspect) * 2,\n );\n }\n\n /**\n * Adjusts the vertical field of view to fit all specified points within the camera's view.\n *\n * This method calculates the required vertical FOV to ensure all provided vertices\n * are visible within the vertical bounds of the camera's frustum.\n *\n * @param vertices - Array of 3D points (in world coordinates) that should fit within the camera's vertical view\n */\n public fitVerticalFovToPoints(vertices: Vector3[]): void {\n const up = new Vector3(0, 1, 0).applyQuaternion(this.quaternion);\n\n let maxVerticalAngle = 0;\n\n for (const vertex of vertices) {\n const vertexToCam = this.position.clone().sub(vertex);\n const vertexDirection = vertexToCam.normalize();\n\n const verticalAngle =\n Math.asin(Math.abs(vertexDirection.dot(up))) *\n Math.sign(vertexDirection.dot(up));\n\n if (Math.abs(verticalAngle) > maxVerticalAngle) {\n maxVerticalAngle = Math.abs(verticalAngle);\n }\n }\n\n const requiredFov = MathUtils.radToDeg(2 * maxVerticalAngle);\n\n this.verticalFovInternal = MathUtils.clamp(requiredFov, MIN_FOV, MAX_FOV);\n this.updateProjectionMatrix();\n }\n\n /**\n * Adjusts the vertical field of view to fit a bounding box within the camera's view.\n *\n * This method calculates the required vertical FOV to ensure the entire bounding box\n * is visible within the vertical bounds of the camera's frustum.\n *\n * @param box - The 3D bounding box (in world coordinates) that should fit within the camera's vertical view\n */\n public fitVerticalFovToBox(box: Box3): void {\n this.fitVerticalFovToPoints([\n new Vector3(box.min.x, box.min.y, box.min.z),\n new Vector3(box.min.x, box.min.y, box.max.z),\n new Vector3(box.min.x, box.max.y, box.min.z),\n new Vector3(box.min.x, box.max.y, box.max.z),\n new Vector3(box.max.x, box.min.y, box.min.z),\n new Vector3(box.max.x, box.min.y, box.max.z),\n new Vector3(box.max.x, box.max.y, box.min.z),\n new Vector3(box.max.x, box.max.y, box.max.z),\n ]);\n }\n\n /**\n * Adjusts the vertical field of view to fit a skinned mesh within the camera's view.\n *\n * This method updates the mesh's skeleton, applies bone transformations to all vertices,\n * and then calculates the required vertical FOV to ensure the entire deformed mesh\n * is visible within the vertical bounds of the camera's frustum.\n *\n * @param skinnedMesh - The skinned mesh (with active skeleton) that should fit within the camera's vertical view\n */\n public fitVerticalFovToMesh(skinnedMesh: SkinnedMesh): void {\n skinnedMesh.updateWorldMatrix(true, true);\n skinnedMesh.skeleton.update();\n\n const bakedGeometry = skinnedMesh.geometry;\n const position = bakedGeometry.attributes[\"position\"] as BufferAttribute;\n const target = new Vector3();\n\n const points = [];\n\n for (let i = 0; i < position.count; i++) {\n target.fromBufferAttribute(position, i);\n skinnedMesh.applyBoneTransform(i, target);\n points.push(target.clone());\n }\n\n this.fitVerticalFovToPoints(points);\n }\n\n /**\n * Points the camera to look at the center of mass of a skinned mesh.\n *\n * This method updates the mesh's skeleton, applies bone transformations to all vertices,\n * calculates the center of mass using a clustering algorithm, and then orients the camera\n * to look at that point.\n *\n * The center of mass calculation uses an iterative clustering approach to find the\n * main concentration of vertices, which provides better results than a simple average\n * for complex meshes.\n *\n * @param skinnedMesh - The skinned mesh (with active skeleton) whose center of mass should be the camera's target\n */\n public lookAtMeshCenterOfMass(skinnedMesh: SkinnedMesh): void {\n skinnedMesh.updateWorldMatrix(true, true);\n skinnedMesh.skeleton.update();\n\n const bakedGeometry = skinnedMesh.geometry;\n const position = bakedGeometry.attributes.position as BufferAttribute;\n const target = new Vector3();\n const points: Vector3[] = [];\n\n for (let i = 0; i < position.count; i++) {\n target.fromBufferAttribute(position, i);\n skinnedMesh.applyBoneTransform(i, target);\n points.push(target.clone());\n }\n\n /**\n * Finds the main cluster center of a set of 3D points using iterative refinement.\n *\n * @param points - Array of 3D points to cluster\n * @param iterations - Number of refinement iterations to perform\n * @returns The calculated center point of the main cluster\n */\n const findMainCluster = (points: Vector3[], iterations = 3): Vector3 => {\n if (points.length === 0) {\n return new Vector3();\n }\n\n let center = points[Math.floor(points.length / 2)].clone();\n\n for (let i = 0; i < iterations; i++) {\n let total = new Vector3();\n let count = 0;\n\n for (const point of points) {\n if (\n point.distanceTo(center) < point.distanceTo(total) ||\n count === 0\n ) {\n total.add(point);\n count++;\n }\n }\n\n if (count > 0) {\n center = total.divideScalar(count);\n }\n }\n\n return center;\n };\n\n const centerOfMass = findMainCluster(points);\n this.lookAt(centerOfMass);\n }\n\n /**\n * Creates a deep copy of this DualFovCamera instance.\n *\n * The cloned camera will have identical FOV settings, position, rotation,\n * and all other camera properties.\n *\n * @returns A new DualFovCamera instance that is an exact copy of this one\n * @override\n */\n public override clone(): this {\n const camera = new DualFovCamera(\n this.horizontalFovInternal,\n this.verticalFovInternal,\n this.aspect,\n this.near,\n this.far,\n ) as this;\n\n camera.copy(this, true);\n return camera;\n }\n}\n","import type { Material, Object3D } from \"three\";\nimport { Mesh } from \"three\";\n\n/**\n * Constructor type for type-safe scene traversal operations.\n *\n * This type represents any constructor function that can be used to create instances of type T.\n * It's used for runtime type checking when filtering objects by their constructor type.\n *\n * @template T - The type that the constructor creates\n */\nexport type Constructor<T> = abstract new (...args: never[]) => T;\n\n/**\n * Utility class for finding and modifying objects in a Three.js scene graph.\n *\n * This class provides static methods for traversing Three.js scene hierarchies,\n * searching for specific objects or materials, and performing batch operations\n * on collections of scene objects.\n *\n * All methods perform depth-first traversal of the scene graph starting from\n * the provided root object and recursively processing all children.\n */\nexport class SceneTraversal {\n /**\n * Finds the first object in the scene hierarchy with an exact name match.\n *\n * Performs a depth-first search through the scene graph starting from the provided\n * root object. Returns the first object encountered whose name property exactly\n * matches the search string.\n *\n * @param object - The root Object3D to start searching from\n * @param name - The exact name to search for (case-sensitive)\n * @returns The first matching Object3D, or null if no match is found\n\n */\n public static getObjectByName(\n object: Object3D,\n name: string,\n ): Object3D | null {\n if (object.name === name) {\n return object;\n }\n\n for (const child of object.children) {\n const result = SceneTraversal.getObjectByName(child, name);\n if (result) {\n return result;\n }\n }\n\n return null;\n }\n\n /**\n * Finds the first material in the scene hierarchy with an exact name match.\n *\n * Performs a depth-first search through the scene graph, examining materials\n * attached to Mesh objects. Handles both single materials and material arrays.\n * Returns the first material encountered whose name property exactly matches\n * the search string.\n *\n * @param object - The root Object3D to start searching from\n * @param name - The exact material name to search for (case-sensitive)\n * @returns The first matching Material, or null if no match is found\n\n */\n public static getMaterialByName(\n object: Object3D,\n name: string,\n ): Material | null {\n if (object instanceof Mesh) {\n if (Array.isArray(object.material)) {\n for (const material of object.material) {\n if (material.name === name) {\n return material;\n }\n }\n } else if (object.material.name === name) {\n return object.material;\n }\n }\n\n for (const child of object.children) {\n const material = SceneTraversal.getMaterialByName(child, name);\n if (material) {\n return material;\n }\n }\n\n return null;\n }\n\n /**\n * Processes all objects of a specific type in the scene hierarchy.\n *\n * Performs a depth-first traversal and executes the provided callback function\n * for every object that is an instance of the specified type. This is useful\n * for batch operations on specific object types (e.g., all lights, all meshes, etc.).\n *\n * @template T - The type of objects to process\n * @param object - The root Object3D to start searching from\n * @param type - The constructor/class to filter by (e.g., DirectionalLight, Mesh)\n * @param callback - Function to execute for each matching object instance\n\n */\n public static enumerateObjectsByType<T>(\n object: Object3D,\n type: Constructor<T>,\n callback: (instance: T) => void,\n ): void {\n if (object instanceof type) {\n callback(object);\n }\n\n for (const child of object.children) {\n SceneTraversal.enumerateObjectsByType(child, type, callback);\n }\n }\n\n /**\n * Processes all materials found in mesh objects within the scene hierarchy.\n *\n * Performs a depth-first traversal, finding all Mesh objects and executing\n * the provided callback function for each material. Handles both single\n * materials and material arrays properly.\n *\n * @param object - The root Object3D to start searching from\n * @param callback - Function to execute for each material found\n\n */\n public static enumerateMaterials(\n object: Object3D,\n callback: (material: Material) => void,\n ): void {\n if (object instanceof Mesh) {\n if (Array.isArray(object.material)) {\n for (const material of object.material) {\n callback(material);\n }\n } else {\n callback(object.material);\n }\n }\n\n for (const child of object.children) {\n SceneTraversal.enumerateMaterials(child, callback);\n }\n }\n\n /**\n * Finds all objects in the scene hierarchy that match the specified filter criteria.\n *\n * Performs a depth-first search and collects all objects that either match\n * a regular expression pattern (applied to the object's name) or satisfy\n * a custom predicate function.\n *\n * @param object - The root Object3D to start searching from\n * @param filter - Either a RegExp to test against object names, or a predicate function\n * @returns Array of all matching Object3D instances\n\n */\n public static filterObjects(\n object: Object3D,\n filter: RegExp | ((object: Object3D) => boolean),\n ): Object3D[] {\n let result: Object3D[] = [];\n\n if (typeof filter === \"function\") {\n if (filter(object)) {\n result.push(object);\n }\n } else {\n if (object.name && filter.test(object.name)) {\n result.push(object);\n }\n }\n\n for (const child of object.children) {\n result = result.concat(SceneTraversal.filterObjects(child, filter));\n }\n\n return result;\n }\n\n /**\n * Finds all materials in the scene hierarchy whose names match a regular expression pattern.\n *\n * Performs a depth-first search through all Mesh objects and collects materials\n * whose name property matches the provided regular expression. Handles both\n * single materials and material arrays properly.\n *\n * @param object - The root Object3D to start searching from\n * @param name - Regular expression pattern to test against material names\n * @returns Array of all matching Material instances\n\n */\n public static filterMaterials(object: Object3D, name: RegExp): Material[] {\n let result: Material[] = [];\n\n if (object instanceof Mesh) {\n if (Array.isArray(object.material)) {\n for (const material of object.material) {\n if (material.name && name.test(material.name)) {\n result.push(material);\n }\n }\n } else {\n if (object.material.name && name.test(object.material.name)) {\n result.push(object.material);\n }\n }\n }\n\n for (const child of object.children) {\n result = result.concat(SceneTraversal.filterMaterials(child, name));\n }\n\n return result;\n }\n\n /**\n * Finds all objects (mesh users) that use materials with names matching a regular expression pattern.\n *\n * Performs a depth-first search through all Mesh objects and collects the mesh objects\n * whose materials have names that match the provided regular expression. This is useful\n * for finding all objects that use specific material types or naming patterns.\n *\n * @param object - The root Object3D to start searching from\n * @param materialName - Regular expression pattern to test against material names\n * @returns Array of all Mesh objects that use materials with matching names\n */\n public static findMaterialUsers(\n object: Object3D,\n materialName: RegExp,\n ): Mesh[] {\n let result: Mesh[] = [];\n\n if (object instanceof Mesh) {\n let hasMatchingMaterial = false;\n\n if (Array.isArray(object.material)) {\n for (const material of object.material) {\n if (material.name && materialName.test(material.name)) {\n hasMatchingMaterial = true;\n break;\n }\n }\n } else {\n if (object.material.name && materialName.test(object.material.name)) {\n hasMatchingMaterial = true;\n }\n }\n\n if (hasMatchingMaterial) {\n result.push(object);\n }\n }\n\n for (const child of object.children) {\n result = result.concat(\n SceneTraversal.findMaterialUsers(child, materialName),\n );\n }\n\n return result;\n }\n}\n","import type { AnimationClip, Object3D, SkinnedMesh } from \"three\";\nimport { AnimationMixer, BufferAttribute, Mesh, Vector3 } from \"three\";\n\n/** Number of components per vertex */\nconst COMPONENT_COUNT = 3;\n\n/** Convert skinned meshes to regular static meshes */\nexport class SkinnedMeshBaker {\n /**\n * Convert a skinned mesh to a regular mesh in its current pose.\n * The resulting mesh will have no bones but look identical.\n *\n * @param skinnedMesh - Mesh to convert\n * @returns Static mesh with baked vertex positions\n */\n public static bakePose(skinnedMesh: SkinnedMesh): Mesh {\n const bakedGeometry = skinnedMesh.geometry.clone();\n const position = bakedGeometry.attributes[\"position\"] as BufferAttribute;\n const newPositions = new Float32Array(position.count * COMPONENT_COUNT);\n const target = new Vector3();\n\n for (let i = 0; i < position.count; i++) {\n target.fromBufferAttribute(position, i);\n skinnedMesh.applyBoneTransform(i, target);\n newPositions[i * COMPONENT_COUNT + 0] = target.x;\n newPositions[i * COMPONENT_COUNT + 1] = target.y;\n newPositions[i * COMPONENT_COUNT + 2] = target.z;\n }\n\n bakedGeometry.setAttribute(\n \"position\",\n new BufferAttribute(newPositions, COMPONENT_COUNT),\n );\n bakedGeometry.computeVertexNormals();\n bakedGeometry.deleteAttribute(\"skinIndex\");\n bakedGeometry.deleteAttribute(\"skinWeight\");\n\n const mesh = new Mesh(bakedGeometry, skinnedMesh.material);\n mesh.name = skinnedMesh.name;\n return mesh;\n }\n\n /**\n * Bake a single frame from an animation into a static mesh.\n *\n * @param armature - Root object with bones (usually from GLTF)\n * @param skinnedMesh - Mesh to convert\n * @param timeOffset - Time in seconds within the animation\n * @param clip - Animation to get the pose from\n * @returns Static mesh with baked vertex positions\n */\n public static bakeAnimationFrame(\n armature: Object3D,\n skinnedMesh: SkinnedMesh,\n timeOffset: number,\n clip: AnimationClip,\n ): Mesh {\n const mixer = new AnimationMixer(armature);\n const action = mixer.clipAction(clip);\n action.play();\n mixer.setTime(timeOffset);\n\n armature.updateWorldMatrix(true, true);\n skinnedMesh.skeleton.update();\n\n return this.bakePose(skinnedMesh);\n }\n}\n","import type { MeshStandardMaterial } from \"three\";\nimport { MeshBasicMaterial } from \"three\";\n\n/**\n * Configuration options for the StandardToBasicConverter\n *\n * @interface StandardToBasicConverterOptions\n */\nexport interface StandardToBasicConverterOptions {\n /**\n * Whether to preserve the original material's name\n * @defaultValue true\n */\n preserveName: boolean;\n /**\n * Whether to copy user data from the original material\n * @defaultValue true\n */\n copyUserData: boolean;\n /**\n * Whether to dispose the original material after conversion\n * @defaultValue false\n */\n disposeOriginal: boolean;\n /**\n * Whether to apply emissive color to the base color for brightness compensation\n * @defaultValue true\n */\n combineEmissive: boolean;\n /**\n * Factor for brightness adjustment to compensate for loss of lighting\n * @defaultValue 1.3\n */\n brightnessFactor: number;\n}\n\n/**\n * Converts Three.js MeshStandardMaterial to MeshBasicMaterial\n *\n * This converter handles the translation from PBR (Physically Based Rendering)\n * StandardMaterial to the unlit BasicMaterial. Since BasicMaterial doesn't respond\n * to lighting, this converter applies various compensation techniques to maintain\n * visual similarity, including brightness adjustments and emissive color combination.\n */\nexport class StandardToBasicConverter {\n /**\n * Converts a MeshStandardMaterial to MeshBasicMaterial\n *\n * This method performs a comprehensive conversion from PBR StandardMaterial to\n * unlit BasicMaterial while attempting to preserve visual similarity through\n * brightness compensation and intelligent property mapping.\n *\n * @param standardMaterial - The source MeshStandardMaterial to convert\n * @param options - Configuration options for the conversion\n * @returns A new MeshBasicMaterial with properties mapped from the standard material\n *\n * @example\n * ```typescript\n * const standardMaterial = new MeshStandardMaterial({\n * color: 0x00ff00,\n * metalness: 0.5,\n * emissive: 0x111111,\n * emissiveIntensity: 0.2\n * });\n *\n * const basicMaterial = StandardToBasicConverter.convert(standardMaterial, {\n * brightnessFactor: 1.4,\n * combineEmissive: true\n * });\n * ```\n *\n * @see {@link StandardToBasicConverterOptions} for available configuration options\n */\n public static convert(\n standardMaterial: MeshStandardMaterial,\n options: Partial<StandardToBasicConverterOptions> = {},\n ): MeshBasicMaterial {\n const config = {\n preserveName: true,\n copyUserData: true,\n disposeOriginal: false,\n combineEmissive: true,\n brightnessFactor: 1.3,\n ...options,\n };\n\n // Create new Basic material\n const basicMaterial = new MeshBasicMaterial();\n\n // Copy basic material properties\n this.copyBasicProperties(standardMaterial, basicMaterial, config);\n\n // Handle color properties with lighting compensation\n this.convertColorProperties(standardMaterial, basicMaterial, config);\n\n // Handle texture maps\n this.convertTextureMaps(standardMaterial, basicMaterial);\n\n // Handle transparency and alpha\n this.convertTransparencyProperties(standardMaterial, basicMaterial);\n\n // Cleanup if requested\n if (config.disposeOriginal) {\n standardMaterial.dispose();\n }\n\n basicMaterial.needsUpdate = true;\n return basicMaterial;\n }\n\n /**\n * Copies basic material properties from source to target material\n *\n * Transfers common material properties including rendering settings,\n * visibility, fog interaction, wireframe settings, and user data.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshBasicMaterial\n * @param config - The resolved configuration options\n * @internal\n */\n private static copyBasicProperties(\n source: MeshStandardMaterial,\n target: MeshBasicMaterial,\n config: Required<StandardToBasicConverterOptions>,\n ): void {\n if (config.preserveName) {\n target.name = source.name;\n }\n\n target.side = source.side;\n target.visible = source.visible;\n target.fog = source.fog;\n target.wireframe = source.wireframe;\n target.wireframeLinewidth = source.wireframeLinewidth;\n target.vertexColors = source.vertexColors;\n\n if (config.copyUserData) {\n target.userData = { ...source.userData };\n }\n }\n\n /**\n * Converts color-related properties with lighting compensation\n *\n * Applies brightness compensation and optional emissive color combination\n * to account for BasicMaterial's lack of lighting response. Metallic materials\n * receive additional brightness adjustment, and colors are clamped to valid ranges.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshBasicMaterial\n * @param config - The resolved configuration options\n * @internal\n */\n private static convertColorProperties(\n source: MeshStandardMaterial,\n target: MeshBasicMaterial,\n config: Required<StandardToBasicConverterOptions>,\n ): void {\n // Base color conversion with brightness compensation\n target.color = source.color.clone();\n\n // Apply brightness compensation since BasicMaterial doesn't respond to lighting\n target.color.multiplyScalar(config.brightnessFactor);\n\n // Adjust for metalness - metallic materials tend to be darker without lighting\n if (source.metalness > 0) {\n const metalnessBrightness = 1 + source.metalness * 0.3;\n target.color.multiplyScalar(metalnessBrightness);\n }\n\n // Combine emissive color if requested\n if (config.combineEmissive) {\n const emissiveContribution = source.emissive\n .clone()\n .multiplyScalar(source.emissiveIntensity * 0.5);\n target.color.add(emissiveContribution);\n }\n\n // Ensure color doesn't exceed valid range\n target.color.r = Math.min(target.color.r, 1.0);\n target.color.g = Math.min(target.color.g, 1.0);\n target.color.b = Math.min(target.color.b, 1.0);\n }\n\n /**\n * Converts and maps texture properties from Standard to Basic material\n *\n * Handles the transfer of compatible texture maps including diffuse, alpha,\n * environment, light, and AO maps. The metalness map is repurposed as a\n * specular map for some reflective effect, and environment map reflectivity\n * is set based on the original material's metalness value.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshBasicMaterial\n * @internal\n */\n private static convertTextureMaps(\n source: MeshStandardMaterial,\n target: MeshBasicMaterial,\n ): void {\n // Main diffuse/albedo map\n if (source.map) {\n target.map = source.map;\n }\n\n // Alpha map\n if (source.alphaMap) {\n target.alphaMap = source.alphaMap;\n }\n\n // Environment map (BasicMaterial supports this for reflections)\n if (source.envMap) {\n target.envMap = source.envMap;\n // Use metalness to determine reflectivity\n target.reflectivity = source.metalness;\n }\n\n // Light map (BasicMaterial supports this)\n if (source.lightMap) {\n target.lightMap = source.lightMap;\n target.lightMapIntensity = source.lightMapIntensity;\n }\n\n // AO map (BasicMaterial supports this)\n if (source.aoMap) {\n target.aoMap = source.aoMap;\n target.aoMapIntensity = source.aoMapIntensity;\n }\n\n // Specular map (BasicMaterial supports this)\n if (source.metalnessMap) {\n // Use metalness map as specular map for some reflective effect\n target.specularMap = source.metalnessMap;\n }\n\n // Copy UV transforms\n this.copyUVTransforms(source, target);\n }\n\n /**\n * Copies UV transformation properties for texture maps\n *\n * Transfers UV offset, repeat, rotation, and center properties from the\n * source material's main texture map to the target material's map.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshBasicMaterial\n * @internal\n */\n private static copyUVTransforms(\n source: MeshStandardMaterial,\n target: MeshBasicMaterial,\n ): void {\n // Main texture UV transform\n if (source.map && target.map) {\n target.map.offset.copy(source.map.offset);\n target.map.repeat.copy(source.map.repeat);\n target.map.rotation = source.map.rotation;\n target.map.center.copy(source.map.center);\n }\n }\n\n /**\n * Converts transparency and rendering properties\n *\n * Transfers transparency, opacity, alpha testing, depth testing,\n * depth writing, and blending mode settings from source to target.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshBasicMaterial\n * @internal\n */\n private static convertTransparencyProperties(\n source: MeshStandardMaterial,\n target: MeshBasicMaterial,\n ): void {\n target.transparent = source.transparent;\n target.opacity = source.opacity;\n target.alphaTest = source.alphaTest;\n target.depthTest = source.depthTest;\n target.depthWrite = source.depthWrite;\n target.blending = source.blending;\n }\n}\n\nexport default StandardToBasicConverter;\n","import type { MeshStandardMaterial } from \"three\";\nimport { MeshLambertMaterial } from \"three\";\n\n/**\n * Configuration options for the StandardToLambertConverter\n *\n * @interface StandardToLambertConverterOptions\n */\nexport interface StandardToLambertConverterOptions {\n /**\n * Whether to preserve the original material's name\n * @defaultValue true\n */\n preserveName: boolean;\n /**\n * Whether to copy user data from the original material\n * @defaultValue true\n */\n copyUserData: boolean;\n /**\n * Whether to dispose the original material after conversion\n * @defaultValue false\n */\n disposeOriginal: boolean;\n /**\n * Custom color adjustment factor for roughness compensation\n * @defaultValue 0.8\n */\n roughnessColorFactor: number;\n}\n\n/**\n * Converts Three.js MeshStandardMaterial to MeshLambertMaterial\n *\n * This converter handles the translation between PBR (Physically Based Rendering)\n * properties of StandardMaterial and the simpler Lambertian reflectance model\n * used by LambertMaterial. The conversion preserves visual similarity by applying\n * color compensation based on metalness and roughness values.\n */\nexport class StandardToLambertConverter {\n /**\n * Converts a MeshStandardMaterial to MeshLambertMaterial\n *\n * This method performs a comprehensive conversion from PBR StandardMaterial to\n * the simpler Lambert lighting model while attempting to preserve visual similarity\n * through intelligent color compensation.\n *\n * @param material - The source MeshStandardMaterial to convert\n * @param options - Configuration options for the conversion\n * @returns A new MeshLambertMaterial with properties mapped from the standard material\n *\n * @example\n * ```typescript\n * const standardMaterial = new MeshStandardMaterial({\n * color: 0xff0000,\n * metalness: 0.8,\n * roughness: 0.2\n * });\n *\n * const lambertMaterial = StandardToLambertConverter.convert(standardMaterial);\n * ```\n *\n * @see {@link StandardToLambertConverterOptions} for available configuration options\n */\n public static convert(\n material: MeshStandardMaterial,\n options: Partial<StandardToLambertConverterOptions> = {},\n ): MeshLambertMaterial {\n const config = {\n preserveName: true,\n copyUserData: true,\n disposeOriginal: false,\n roughnessColorFactor: 0.8,\n ...options,\n };\n\n // Create new Lambert material\n const lambertMaterial = new MeshLambertMaterial();\n\n // Copy basic material properties\n this.copyBasicProperties(material, lambertMaterial, config);\n\n // Handle color properties with roughness compensation\n this.convertColorProperties(material, lambertMaterial, config);\n\n // Handle texture maps\n this.convertTextureMaps(material, lambertMaterial);\n\n // Handle transparency and alpha\n this.convertTransparencyProperties(material, lambertMaterial);\n\n // Cleanup if requested\n if (config.disposeOriginal) {\n material.dispose();\n }\n\n lambertMaterial.needsUpdate = true;\n return lambertMaterial;\n }\n\n /**\n * Copies basic material properties from source to target material\n *\n * Transfers common material properties including rendering settings,\n * visibility, fog interaction, wireframe settings, and user data.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshLambertMaterial\n * @param config - The resolved configuration options\n * @internal\n */\n private static copyBasicProperties(\n source: MeshStandardMaterial,\n target: MeshLambertMaterial,\n config: Required<StandardToLambertConverterOptions>,\n ): void {\n if (config.preserveName) {\n target.name = source.name;\n }\n\n target.side = source.side;\n target.visible = source.visible;\n target.fog = source.fog;\n target.wireframe = source.wireframe;\n target.wireframeLinewidth = source.wireframeLinewidth;\n target.vertexColors = source.vertexColors;\n target.flatShading = source.flatShading;\n\n if (config.copyUserData) {\n target.userData = { ...source.userData };\n }\n }\n\n /**\n * Converts color-related properties with PBR compensation\n *\n * Applies intelligent color adjustments to compensate for the loss of\n * metalness and roughness information when converting to Lambert material.\n * Metallic materials are darkened and rough materials receive additional\n * darkening based on the roughnessColorFactor.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshLambertMaterial\n * @param config - The resolved configuration options\n * @internal\n */\n private static convertColorProperties(\n source: MeshStandardMaterial,\n target: MeshLambertMaterial,\n config: Required<StandardToLambertConverterOptions>,\n ): void {\n target.color = source.color.clone();\n\n // Adjust color based on metalness and roughness for better visual match\n if (source.metalness > 0) {\n // Metallic materials tend to be darker in Lambert shading\n const metalnessFactor = 1 - source.metalness * 0.3;\n target.color.multiplyScalar(metalnessFactor);\n }\n\n if (source.roughness > 0.5) {\n // Rough materials appear slightly darker\n const roughnessFactor =\n config.roughnessColorFactor + source.roughness * 0.2;\n target.color.multiplyScalar(roughnessFactor);\n }\n\n target.emissive = source.emissive.clone();\n target.emissiveIntensity = source.emissiveIntensity;\n }\n\n /**\n * Converts and maps texture properties from Standard to Lambert material\n *\n * Handles the transfer of compatible texture maps including diffuse, normal,\n * emissive, AO, light maps, and environment maps. The environment map\n * reflectivity is set based on the original material's metalness value.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshLambertMaterial\n * @internal\n */\n private static convertTextureMaps(\n source: MeshStandardMaterial,\n target: MeshLambertMaterial,\n ): void {\n // Diffuse/Albedo map\n if (source.map) {\n target.map = source.map;\n }\n\n // Emissive map\n if (source.emissiveMap) {\n target.emissiveMap = source.emissiveMap;\n }\n\n // Normal map (Lambert materials support normal mapping)\n if (source.normalMap) {\n target.normalMap = source.normalMap;\n target.normalScale = source.normalScale.clone();\n }\n\n // Light map\n if (source.lightMap) {\n target.lightMap = source.lightMap;\n target.lightMapIntensity = source.lightMapIntensity;\n }\n\n // AO map\n if (source.aoMap) {\n target.aoMap = source.aoMap;\n target.aoMapIntensity = source.aoMapIntensity;\n }\n\n // Environment map (for reflections)\n if (source.envMap) {\n target.envMap = source.envMap;\n target.reflectivity = Math.min(source.metalness + 0.1, 1.0);\n }\n\n // Alpha map\n if (source.alphaMap) {\n target.alphaMap = source.alphaMap;\n }\n\n // Copy UV transforms\n this.copyUVTransforms(source, target);\n }\n\n /**\n * Copies UV transformation properties for texture maps\n *\n * Transfers UV offset, repeat, rotation, and center properties from the\n * source material's main texture map to the target material's map.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshLambertMaterial\n * @internal\n */\n private static copyUVTransforms(\n source: MeshStandardMaterial,\n target: MeshLambertMaterial,\n ): void {\n // Main texture UV transform\n if (source.map && target.map) {\n target.map.offset.copy(source.map.offset);\n target.map.repeat.copy(source.map.repeat);\n target.map.rotation = source.map.rotation;\n target.map.center.copy(source.map.center);\n }\n }\n\n /**\n * Converts transparency and rendering properties\n *\n * Transfers transparency, opacity, alpha testing, depth testing,\n * depth writing, and blending mode settings from source to target.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshLambertMaterial\n * @internal\n */\n private static convertTransparencyProperties(\n source: MeshStandardMaterial,\n target: MeshLambertMaterial,\n ): void {\n target.transparent = source.transparent;\n target.opacity = source.opacity;\n target.alphaTest = source.alphaTest;\n target.depthTest = source.depthTest;\n target.depthWrite = source.depthWrite;\n target.blending = source.blending;\n }\n}\n","import type { Texture } from \"three\";\nimport { Box3, DirectionalLight, RGBAFormat, Spherical, Vector3 } from \"three\";\n\n/** Number of color channels in RGBA format */\nconst RGBA_CHANNEL_COUNT = 4;\n/** Number of color channels in RGB format */\nconst RGB_CHANNEL_COUNT = 3;\n\n/** Red channel weight for luminance calculation (ITU-R BT.709) */\nconst LUMINANCE_R = 0.2126;\n/** Green channel weight for luminance calculation (ITU-R BT.709) */\nconst LUMINANCE_G = 0.7152;\n/** Blue channel weight for luminance calculation (ITU-R BT.709) */\nconst LUMINANCE_B = 0.0722;\n\n/**\n * A directional light with spherical positioning controls and advanced shadow mapping.\n *\n * Extends Three.js DirectionalLight to provide intuitive spherical coordinate control\n * (distance, elevation, azimuth) and automatic shadow map configuration for bounding boxes.\n * Also supports automatic sun direction calculation from HDR environment maps.\n */\nexport class Sun extends DirectionalLight {\n /** Internal vectors to avoid garbage collection during calculations */\n private readonly tempVector3D0 = new Vector3();\n private readonly tempVector3D1 = new Vector3();\n private readonly tempVector3D2 = new Vector3();\n private readonly tempVector3D3 = new Vector3();\n private readonly tempVector3D4 = new Vector3();\n private readonly tempVector3D5 = new Vector3();\n private readonly tempVector3D6 = new Vector3();\n private readonly tempVector3D7 = new Vector3();\n private readonly tempBox3 = new Box3();\n private readonly tempSpherical = new Spherical();\n\n /**\n * Gets the distance from the light to its target (origin).\n *\n * @returns The distance in world units\n */\n public get distance(): number {\n return this.position.length();\n }\n\n /**\n * Gets the elevation angle (vertical angle from the horizontal plane).\n *\n * @returns The elevation angle in radians (0 = horizontal, π/2 = directly above)\n */\n public get elevation(): number {\n return this.tempSpherical.setFromVector3(this.position).phi;\n }\n\n /**\n * Gets the azimuth angle (horizontal rotation around the target).\n *\n * @returns The azimuth angle in radians (0 = positive X axis, π/2 = positive Z axis)\n */\n public get azimuth(): number {\n return this.tempSpherical.setFromVector3(this.position).theta;\n }\n\n /**\n * Sets the distance while preserving current elevation and azimuth angles.\n *\n * @param value - The new distance in world units\n */\n public set distance(value: number) {\n this.tempSpherical.setFromVector3(this.position);\n this.position.setFromSphericalCoords(\n value,\n this.tempSpherical.phi,\n this.tempSpherical.theta,\n );\n }\n\n /**\n * Sets the elevation angle while preserving current distance and azimuth.\n *\n * @param value - The new elevation angle in radians (0 = horizontal, π/2 = directly above)\n */\n public set elevation(value: number) {\n this.tempSpherical.setFromVector3(this.position);\n this.position.setFromSphericalCoords(\n this.tempSpherical.radius,\n value,\n this.tempSpherical.theta,\n );\n }\n\n /**\n * Sets the azimuth angle while preserving current distance and elevation.\n *\n * @param value - The new azimuth angle in radians (0 = positive X axis, π/2 = positive Z axis)\n */\n public set azimuth(value: number) {\n this.tempSpherical.setFromVector3(this.position);\n this.position.setFromSphericalCoords(\n this.tempSpherical.radius,\n this.tempSpherical.phi,\n value,\n );\n }\n\n /**\n * Configures the shadow camera to optimally cover a bounding box.\n *\n * This method automatically adjusts the directional light's shadow camera frustum\n * to perfectly encompass the provided bounding box, ensuring efficient shadow map\n * usage and eliminating shadow clipping issues.\n *\n * @param box3 - The 3D bounding box to cover with shadows\n */\n public configureShadowsForBoundingBox(box3: Box3): void {\n const camera = this.shadow.camera;\n\n this.target.updateWorldMatrix(true, false);\n this.lookAt(this.target.getWorldPosition(this.tempVector3D0));\n\n this.updateWorldMatrix(true, false);\n\n const points: Vector3[] = [\n this.tempVector3D0.set(box3.min.x, box3.min.y, box3.min.z),\n this.tempVector3D1.set(box3.min.x, box3.min.y, box3.max.z),\n this.tempVector3D2.set(box3.min.x, box3.max.y, box3.min.z),\n this.tempVector3D3.set(box3.min.x, box3.max.y, box3.max.z),\n this.tempVector3D4.set(box3.max.x, box3.min.y, box3.min.z),\n this.tempVector3D5.set(box3.max.x, box3.min.y, box3.max.z),\n this.tempVector3D6.set(box3.max.x, box3.max.y, box3.min.z),\n this.tempVector3D7.set(box3.max.x, box3.max.y, box3.max.z),\n ];\n\n const inverseMatrix = this.matrixWorld.clone().invert();\n\n for (const point of points) {\n point.applyMatrix4(inverseMatrix);\n }\n\n const newBox3 = this.tempBox3.setFromPoints(points);\n\n camera.left = newBox3.min.x;\n camera.bottom = newBox3.min.y;\n camera.near = -newBox3.max.z;\n\n camera.right = newBox3.max.x;\n camera.top = newBox3.max.y;\n camera.far = -newBox3.min.z;\n\n camera.updateWorldMatrix(true, false);\n camera.updateProjectionMatrix();\n }\n\n /**\n * Sets the sun's direction based on the brightest point in an HDR environment map.\n *\n * This method analyzes an HDR texture to find the pixel with the highest luminance\n * value and positions the sun to shine from that direction. This is useful for\n * creating realistic lighting that matches HDR environment maps.\n *\n * @param texture - The HDR texture to analyze (must have image data available)\n * @param distance - The distance to place the sun from the origin (defaults to 1)\n */\n public setDirectionFromHDRTexture(texture: Texture, distance = 1): void {\n const data = texture.image.data;\n const width = texture.image.width;\n const height = texture.image.height;\n\n let maxLuminance = 0;\n let maxIndex = 0;\n\n // Find brightest pixel\n\n const step =\n texture.format === RGBAFormat ? RGBA_CHANNEL_COUNT : RGB_CHANNEL_COUNT;\n for (let i = 0; i < data.length; i += step) {\n const r = data[i];\n const g = data[i + 1];\n const b = data[i + 2];\n const luminance = LUMINANCE_R * r + LUMINANCE_G * g + LUMINANCE_B * b;\n if (luminance > maxLuminance) {\n maxLuminance = luminance;\n maxIndex = i;\n }\n }\n\n // Convert to spherical coordinates\n const pixelIndex = maxIndex / step;\n const x = pixelIndex % width;\n const y = Math.floor(pixelIndex / width);\n\n const u = x / width;\n const v = y / height;\n\n const elevation = v * Math.PI;\n const azimuth = u * -Math.PI * 2 - Math.PI / 2;\n\n this.position.setFromSphericalCoords(distance, elevation, azimuth);\n }\n}\n"],"names":[],"mappings":"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"}
package/dist/index.min.js CHANGED
@@ -1,2 +1,2 @@
1
- import{PerspectiveCamera as t,MathUtils as s,Vector3 as i,Mesh as e,BufferAttribute as n,AnimationMixer as o,DirectionalLight as r,Box3 as h,Spherical as a,RGBAFormat as c}from"three";const f=179;class l extends t{constructor(t=90,s=90,i=1,e=1,n=1e3){super(s,i,e,n),this.t=t,this.i=s,this.updateProjectionMatrix()}get horizontalFov(){return this.t}get verticalFov(){return this.i}set horizontalFov(t){this.t=s.clamp(t,1,f),this.updateProjectionMatrix()}set verticalFov(t){this.i=s.clamp(t,1,f),this.updateProjectionMatrix()}setFov(t,i){this.t=s.clamp(t,1,f),this.i=s.clamp(i,1,f),this.updateProjectionMatrix()}copyFovSettings(t){this.t=t.horizontalFov,this.i=t.verticalFov,this.updateProjectionMatrix()}updateProjectionMatrix(){if(this.aspect>1){const t=s.degToRad(this.t);this.fov=s.radToDeg(2*Math.atan(Math.tan(t/2)/this.aspect))}else this.fov=this.i;super.updateProjectionMatrix()}getActualHorizontalFov(){if(this.aspect>=1)return this.t;const t=s.degToRad(this.i);return s.radToDeg(2*Math.atan(Math.tan(t/2)*this.aspect))}getActualVerticalFov(){if(1>this.aspect)return this.i;const t=s.degToRad(this.t);return s.radToDeg(2*Math.atan(Math.tan(t/2)/this.aspect))}fitVerticalFovToPoints(t){const e=new i(0,1,0).applyQuaternion(this.quaternion);let n=0;for(const s of t){const t=this.position.clone().sub(s).normalize(),i=Math.asin(Math.abs(t.dot(e)))*Math.sign(t.dot(e));Math.abs(i)>n&&(n=Math.abs(i))}const o=s.radToDeg(2*n);this.i=s.clamp(o,1,f),this.updateProjectionMatrix()}fitVerticalFovToBox(t){this.fitVerticalFovToPoints([new i(t.min.x,t.min.y,t.min.z),new i(t.min.x,t.min.y,t.max.z),new i(t.min.x,t.max.y,t.min.z),new i(t.min.x,t.max.y,t.max.z),new i(t.max.x,t.min.y,t.min.z),new i(t.max.x,t.min.y,t.max.z),new i(t.max.x,t.max.y,t.min.z),new i(t.max.x,t.max.y,t.max.z)])}fitVerticalFovToMesh(t){t.updateWorldMatrix(!0,!0),t.skeleton.update();const s=t.geometry.attributes.position,e=new i,n=[];for(let i=0;s.count>i;i++)e.fromBufferAttribute(s,i),t.applyBoneTransform(i,e),n.push(e.clone());this.fitVerticalFovToPoints(n)}lookAtMeshCenterOfMass(t){t.updateWorldMatrix(!0,!0),t.skeleton.update();const s=t.geometry.attributes.position,e=new i,n=[];for(let i=0;s.count>i;i++)e.fromBufferAttribute(s,i),t.applyBoneTransform(i,e),n.push(e.clone());const o=((t,s=3)=>{if(0===t.length)return new i;let e=t[Math.floor(t.length/2)].clone();for(let n=0;s>n;n++){let s=new i,n=0;for(const i of t)(i.distanceTo(e)<i.distanceTo(s)||0===n)&&(s.add(i),n++);n>0&&(e=s.divideScalar(n))}return e})(n);this.lookAt(o)}clone(){const t=new l(this.t,this.i,this.aspect,this.near,this.far);return t.copy(this,!0),t}}class u{static getObjectByName(t,s){if(t.name===s)return t;for(const i of t.children){const t=u.getObjectByName(i,s);if(t)return t}return null}static getMaterialByName(t,s){if(t instanceof e)if(Array.isArray(t.material)){for(const i of t.material)if(i.name===s)return i}else if(t.material.name===s)return t.material;for(const i of t.children){const t=u.getMaterialByName(i,s);if(t)return t}return null}static enumerateObjectsByType(t,s,i){t instanceof s&&i(t);for(const e of t.children)u.enumerateObjectsByType(e,s,i)}static enumerateMaterials(t,s){if(t instanceof e)if(Array.isArray(t.material))for(const i of t.material)s(i);else s(t.material);for(const i of t.children)u.enumerateMaterials(i,s)}static filterObjects(t,s){let i=[];"function"==typeof s?s(t)&&i.push(t):t.name&&s.test(t.name)&&i.push(t);for(const e of t.children)i=i.concat(u.filterObjects(e,s));return i}static filterMaterials(t,s){let i=[];if(t instanceof e)if(Array.isArray(t.material))for(const e of t.material)e.name&&s.test(e.name)&&i.push(e);else t.material.name&&s.test(t.material.name)&&i.push(t.material);for(const e of t.children)i=i.concat(u.filterMaterials(e,s));return i}static findMaterialUsers(t,s){let i=[];if(t instanceof e){let e=!1;if(Array.isArray(t.material)){for(const i of t.material)if(i.name&&s.test(i.name)){e=!0;break}}else t.material.name&&s.test(t.material.name)&&(e=!0);e&&i.push(t)}for(const e of t.children)i=i.concat(u.findMaterialUsers(e,s));return i}}class w{static bakePose(t){const s=t.geometry.clone(),o=s.attributes.position,r=new Float32Array(3*o.count),h=new i;for(let s=0;o.count>s;s++)h.fromBufferAttribute(o,s),t.applyBoneTransform(s,h),r[3*s+0]=h.x,r[3*s+1]=h.y,r[3*s+2]=h.z;s.setAttribute("position",new n(r,3)),s.computeVertexNormals(),s.deleteAttribute("skinIndex"),s.deleteAttribute("skinWeight");const a=new e(s,t.material);return a.name=t.name,a}static bakeAnimationFrame(t,s,i,e){const n=new o(t);return n.clipAction(e).play(),n.setTime(i),t.updateWorldMatrix(!0,!0),s.skeleton.update(),this.bakePose(s)}}class M extends r{constructor(){super(...arguments),this.o=new i,this.h=new i,this.l=new i,this.u=new i,this.M=new i,this.v=new i,this.F=new i,this.m=new i,this.p=new h,this.A=new a}get distance(){return this.position.length()}get elevation(){return this.A.setFromVector3(this.position).phi}get azimuth(){return this.A.setFromVector3(this.position).theta}set distance(t){this.A.setFromVector3(this.position),this.position.setFromSphericalCoords(t,this.A.phi,this.A.theta)}set elevation(t){this.A.setFromVector3(this.position),this.position.setFromSphericalCoords(this.A.radius,t,this.A.theta)}set azimuth(t){this.A.setFromVector3(this.position),this.position.setFromSphericalCoords(this.A.radius,this.A.phi,t)}configureShadowsForBoundingBox(t){const s=this.shadow.camera;this.target.updateWorldMatrix(!0,!1),this.lookAt(this.target.getWorldPosition(this.o)),this.updateWorldMatrix(!0,!1);const i=[this.o.set(t.min.x,t.min.y,t.min.z),this.h.set(t.min.x,t.min.y,t.max.z),this.l.set(t.min.x,t.max.y,t.min.z),this.u.set(t.min.x,t.max.y,t.max.z),this.M.set(t.max.x,t.min.y,t.min.z),this.v.set(t.max.x,t.min.y,t.max.z),this.F.set(t.max.x,t.max.y,t.min.z),this.m.set(t.max.x,t.max.y,t.max.z)],e=this.matrixWorld.clone().invert();for(const t of i)t.applyMatrix4(e);const n=this.p.setFromPoints(i);s.left=n.min.x,s.bottom=n.min.y,s.near=-n.max.z,s.right=n.max.x,s.top=n.max.y,s.far=-n.min.z,s.updateWorldMatrix(!0,!1),s.updateProjectionMatrix()}setDirectionFromHDRTexture(t,s=1){const i=t.image.data,e=t.image.width,n=t.image.height;let o=0,r=0;const h=t.format===c?4:3;for(let t=0;i.length>t;t+=h){const s=.2126*i[t]+.7152*i[t+1]+.0722*i[t+2];s>o&&(o=s,r=t)}const a=r/h,f=a%e;this.position.setFromSphericalCoords(s,Math.floor(a/e)/n*Math.PI,f/e*-Math.PI*2-Math.PI/2)}}export{l as DualFovCamera,u as SceneTraversal,w as SkinnedMeshBaker,M as Sun};
1
+ import{PerspectiveCamera as t,MathUtils as s,Vector3 as e,Mesh as i,BufferAttribute as r,AnimationMixer as o,MeshBasicMaterial as n,MeshLambertMaterial as h,DirectionalLight as a,Box3 as c,Spherical as f,RGBAFormat as l}from"three";const u=179;class w extends t{constructor(t=90,s=90,e=1,i=1,r=1e3){super(s,e,i,r),this.t=t,this.i=s,this.updateProjectionMatrix()}get horizontalFov(){return this.t}get verticalFov(){return this.i}set horizontalFov(t){this.t=s.clamp(t,1,u),this.updateProjectionMatrix()}set verticalFov(t){this.i=s.clamp(t,1,u),this.updateProjectionMatrix()}setFov(t,e){this.t=s.clamp(t,1,u),this.i=s.clamp(e,1,u),this.updateProjectionMatrix()}copyFovSettings(t){this.t=t.horizontalFov,this.i=t.verticalFov,this.updateProjectionMatrix()}updateProjectionMatrix(){if(this.aspect>1){const t=s.degToRad(this.t);this.fov=s.radToDeg(2*Math.atan(Math.tan(t/2)/this.aspect))}else this.fov=this.i;super.updateProjectionMatrix()}getActualHorizontalFov(){if(this.aspect>=1)return this.t;const t=s.degToRad(this.i);return s.radToDeg(2*Math.atan(Math.tan(t/2)*this.aspect))}getActualVerticalFov(){if(1>this.aspect)return this.i;const t=s.degToRad(this.t);return s.radToDeg(2*Math.atan(Math.tan(t/2)/this.aspect))}fitVerticalFovToPoints(t){const i=new e(0,1,0).applyQuaternion(this.quaternion);let r=0;for(const s of t){const t=this.position.clone().sub(s).normalize(),e=Math.asin(Math.abs(t.dot(i)))*Math.sign(t.dot(i));Math.abs(e)>r&&(r=Math.abs(e))}const o=s.radToDeg(2*r);this.i=s.clamp(o,1,u),this.updateProjectionMatrix()}fitVerticalFovToBox(t){this.fitVerticalFovToPoints([new e(t.min.x,t.min.y,t.min.z),new e(t.min.x,t.min.y,t.max.z),new e(t.min.x,t.max.y,t.min.z),new e(t.min.x,t.max.y,t.max.z),new e(t.max.x,t.min.y,t.min.z),new e(t.max.x,t.min.y,t.max.z),new e(t.max.x,t.max.y,t.min.z),new e(t.max.x,t.max.y,t.max.z)])}fitVerticalFovToMesh(t){t.updateWorldMatrix(!0,!0),t.skeleton.update();const s=t.geometry.attributes.position,i=new e,r=[];for(let e=0;s.count>e;e++)i.fromBufferAttribute(s,e),t.applyBoneTransform(e,i),r.push(i.clone());this.fitVerticalFovToPoints(r)}lookAtMeshCenterOfMass(t){t.updateWorldMatrix(!0,!0),t.skeleton.update();const s=t.geometry.attributes.position,i=new e,r=[];for(let e=0;s.count>e;e++)i.fromBufferAttribute(s,e),t.applyBoneTransform(e,i),r.push(i.clone());const o=((t,s=3)=>{if(0===t.length)return new e;let i=t[Math.floor(t.length/2)].clone();for(let r=0;s>r;r++){let s=new e,r=0;for(const e of t)(e.distanceTo(i)<e.distanceTo(s)||0===r)&&(s.add(e),r++);r>0&&(i=s.divideScalar(r))}return i})(r);this.lookAt(o)}clone(){const t=new w(this.t,this.i,this.aspect,this.near,this.far);return t.copy(this,!0),t}}class p{static getObjectByName(t,s){if(t.name===s)return t;for(const e of t.children){const t=p.getObjectByName(e,s);if(t)return t}return null}static getMaterialByName(t,s){if(t instanceof i)if(Array.isArray(t.material)){for(const e of t.material)if(e.name===s)return e}else if(t.material.name===s)return t.material;for(const e of t.children){const t=p.getMaterialByName(e,s);if(t)return t}return null}static enumerateObjectsByType(t,s,e){t instanceof s&&e(t);for(const i of t.children)p.enumerateObjectsByType(i,s,e)}static enumerateMaterials(t,s){if(t instanceof i)if(Array.isArray(t.material))for(const e of t.material)s(e);else s(t.material);for(const e of t.children)p.enumerateMaterials(e,s)}static filterObjects(t,s){let e=[];"function"==typeof s?s(t)&&e.push(t):t.name&&s.test(t.name)&&e.push(t);for(const i of t.children)e=e.concat(p.filterObjects(i,s));return e}static filterMaterials(t,s){let e=[];if(t instanceof i)if(Array.isArray(t.material))for(const i of t.material)i.name&&s.test(i.name)&&e.push(i);else t.material.name&&s.test(t.material.name)&&e.push(t.material);for(const i of t.children)e=e.concat(p.filterMaterials(i,s));return e}static findMaterialUsers(t,s){let e=[];if(t instanceof i){let i=!1;if(Array.isArray(t.material)){for(const e of t.material)if(e.name&&s.test(e.name)){i=!0;break}}else t.material.name&&s.test(t.material.name)&&(i=!0);i&&e.push(t)}for(const i of t.children)e=e.concat(p.findMaterialUsers(i,s));return e}}class M{static bakePose(t){const s=t.geometry.clone(),o=s.attributes.position,n=new Float32Array(3*o.count),h=new e;for(let s=0;o.count>s;s++)h.fromBufferAttribute(o,s),t.applyBoneTransform(s,h),n[3*s+0]=h.x,n[3*s+1]=h.y,n[3*s+2]=h.z;s.setAttribute("position",new r(n,3)),s.computeVertexNormals(),s.deleteAttribute("skinIndex"),s.deleteAttribute("skinWeight");const a=new i(s,t.material);return a.name=t.name,a}static bakeAnimationFrame(t,s,e,i){const r=new o(t);return r.clipAction(i).play(),r.setTime(e),t.updateWorldMatrix(!0,!0),s.skeleton.update(),this.bakePose(s)}}class v{static convert(t,s={}){const e={preserveName:!0,copyUserData:!0,disposeOriginal:!1,combineEmissive:!0,brightnessFactor:1.3,...s},i=new n;return this.copyBasicProperties(t,i,e),this.convertColorProperties(t,i,e),this.convertTextureMaps(t,i),this.convertTransparencyProperties(t,i),e.disposeOriginal&&t.dispose(),i.needsUpdate=!0,i}static copyBasicProperties(t,s,e){e.preserveName&&(s.name=t.name),s.side=t.side,s.visible=t.visible,s.fog=t.fog,s.wireframe=t.wireframe,s.wireframeLinewidth=t.wireframeLinewidth,s.vertexColors=t.vertexColors,e.copyUserData&&(s.userData={...t.userData})}static convertColorProperties(t,s,e){if(s.color=t.color.clone(),s.color.multiplyScalar(e.brightnessFactor),t.metalness>0&&s.color.multiplyScalar(1+.3*t.metalness),e.combineEmissive){const e=t.emissive.clone().multiplyScalar(.5*t.emissiveIntensity);s.color.add(e)}s.color.r=Math.min(s.color.r,1),s.color.g=Math.min(s.color.g,1),s.color.b=Math.min(s.color.b,1)}static convertTextureMaps(t,s){t.map&&(s.map=t.map),t.alphaMap&&(s.alphaMap=t.alphaMap),t.envMap&&(s.envMap=t.envMap,s.reflectivity=t.metalness),t.lightMap&&(s.lightMap=t.lightMap,s.lightMapIntensity=t.lightMapIntensity),t.aoMap&&(s.aoMap=t.aoMap,s.aoMapIntensity=t.aoMapIntensity),t.metalnessMap&&(s.specularMap=t.metalnessMap),this.copyUVTransforms(t,s)}static copyUVTransforms(t,s){t.map&&s.map&&(s.map.offset.copy(t.map.offset),s.map.repeat.copy(t.map.repeat),s.map.rotation=t.map.rotation,s.map.center.copy(t.map.center))}static convertTransparencyProperties(t,s){s.transparent=t.transparent,s.opacity=t.opacity,s.alphaTest=t.alphaTest,s.depthTest=t.depthTest,s.depthWrite=t.depthWrite,s.blending=t.blending}}class y{static convert(t,s={}){const e={preserveName:!0,copyUserData:!0,disposeOriginal:!1,roughnessColorFactor:.8,...s},i=new h;return this.copyBasicProperties(t,i,e),this.convertColorProperties(t,i,e),this.convertTextureMaps(t,i),this.convertTransparencyProperties(t,i),e.disposeOriginal&&t.dispose(),i.needsUpdate=!0,i}static copyBasicProperties(t,s,e){e.preserveName&&(s.name=t.name),s.side=t.side,s.visible=t.visible,s.fog=t.fog,s.wireframe=t.wireframe,s.wireframeLinewidth=t.wireframeLinewidth,s.vertexColors=t.vertexColors,s.flatShading=t.flatShading,e.copyUserData&&(s.userData={...t.userData})}static convertColorProperties(t,s,e){s.color=t.color.clone(),t.metalness>0&&s.color.multiplyScalar(1-.3*t.metalness),t.roughness>.5&&s.color.multiplyScalar(e.roughnessColorFactor+.2*t.roughness),s.emissive=t.emissive.clone(),s.emissiveIntensity=t.emissiveIntensity}static convertTextureMaps(t,s){t.map&&(s.map=t.map),t.emissiveMap&&(s.emissiveMap=t.emissiveMap),t.normalMap&&(s.normalMap=t.normalMap,s.normalScale=t.normalScale.clone()),t.lightMap&&(s.lightMap=t.lightMap,s.lightMapIntensity=t.lightMapIntensity),t.aoMap&&(s.aoMap=t.aoMap,s.aoMapIntensity=t.aoMapIntensity),t.envMap&&(s.envMap=t.envMap,s.reflectivity=Math.min(t.metalness+.1,1)),t.alphaMap&&(s.alphaMap=t.alphaMap),this.copyUVTransforms(t,s)}static copyUVTransforms(t,s){t.map&&s.map&&(s.map.offset.copy(t.map.offset),s.map.repeat.copy(t.map.repeat),s.map.rotation=t.map.rotation,s.map.center.copy(t.map.center))}static convertTransparencyProperties(t,s){s.transparent=t.transparent,s.opacity=t.opacity,s.alphaTest=t.alphaTest,s.depthTest=t.depthTest,s.depthWrite=t.depthWrite,s.blending=t.blending}}class g extends a{constructor(){super(...arguments),this.o=new e,this.h=new e,this.l=new e,this.u=new e,this.p=new e,this.M=new e,this.v=new e,this.m=new e,this.F=new c,this.T=new f}get distance(){return this.position.length()}get elevation(){return this.T.setFromVector3(this.position).phi}get azimuth(){return this.T.setFromVector3(this.position).theta}set distance(t){this.T.setFromVector3(this.position),this.position.setFromSphericalCoords(t,this.T.phi,this.T.theta)}set elevation(t){this.T.setFromVector3(this.position),this.position.setFromSphericalCoords(this.T.radius,t,this.T.theta)}set azimuth(t){this.T.setFromVector3(this.position),this.position.setFromSphericalCoords(this.T.radius,this.T.phi,t)}configureShadowsForBoundingBox(t){const s=this.shadow.camera;this.target.updateWorldMatrix(!0,!1),this.lookAt(this.target.getWorldPosition(this.o)),this.updateWorldMatrix(!0,!1);const e=[this.o.set(t.min.x,t.min.y,t.min.z),this.h.set(t.min.x,t.min.y,t.max.z),this.l.set(t.min.x,t.max.y,t.min.z),this.u.set(t.min.x,t.max.y,t.max.z),this.p.set(t.max.x,t.min.y,t.min.z),this.M.set(t.max.x,t.min.y,t.max.z),this.v.set(t.max.x,t.max.y,t.min.z),this.m.set(t.max.x,t.max.y,t.max.z)],i=this.matrixWorld.clone().invert();for(const t of e)t.applyMatrix4(i);const r=this.F.setFromPoints(e);s.left=r.min.x,s.bottom=r.min.y,s.near=-r.max.z,s.right=r.max.x,s.top=r.max.y,s.far=-r.min.z,s.updateWorldMatrix(!0,!1),s.updateProjectionMatrix()}setDirectionFromHDRTexture(t,s=1){const e=t.image.data,i=t.image.width,r=t.image.height;let o=0,n=0;const h=t.format===l?4:3;for(let t=0;e.length>t;t+=h){const s=.2126*e[t]+.7152*e[t+1]+.0722*e[t+2];s>o&&(o=s,n=t)}const a=n/h,c=a%i;this.position.setFromSphericalCoords(s,Math.floor(a/i)/r*Math.PI,c/i*-Math.PI*2-Math.PI/2)}}export{w as DualFovCamera,p as SceneTraversal,M as SkinnedMeshBaker,v as StandardToBasicConverter,y as StandardToLambertConverter,g as Sun};
2
2
  //# sourceMappingURL=index.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.min.js","sources":["../src/DualFovCamera.ts","../src/SceneTraversal.ts","../src/SkinnedMeshBaker.ts","../src/Sun.ts"],"sourcesContent":["import type { Box3, BufferAttribute, SkinnedMesh } from \"three\";\nimport { MathUtils, PerspectiveCamera, Vector3 } from \"three\";\n\n/** Default horizontal field of view in degrees */\nconst DEFAULT_HORIZONTAL_FOV = 90;\n/** Default vertical field of view in degrees */\nconst DEFAULT_VERTICAL_FOV = 90;\n/** Default aspect ratio (width/height) */\nconst DEFAULT_ASPECT = 1;\n/** Default near clipping plane distance */\nconst DEFAULT_NEAR = 1;\n/** Default far clipping plane distance */\nconst DEFAULT_FAR = 1000;\n\n/** Minimum allowed field of view in degrees */\nconst MIN_FOV = 1;\n/** Maximum allowed field of view in degrees */\nconst MAX_FOV = 179;\n\n/**\n * A camera that supports independent horizontal and vertical FOV settings.\n * Extends Three.js PerspectiveCamera to allow separate control over horizontal\n * and vertical fields of view.\n */\nexport class DualFovCamera extends PerspectiveCamera {\n /** Internal storage for horizontal field of view in degrees */\n private horizontalFovInternal: number;\n /** Internal storage for vertical field of view in degrees */\n private verticalFovInternal: number;\n\n /**\n * Creates a new DualFovCamera instance with independent horizontal and vertical FOV control.\n *\n * @param horizontalFov - Horizontal field of view in degrees. Must be between 1° and 179°. Defaults to 90°.\n * @param verticalFov - Vertical field of view in degrees. Must be between 1° and 179°. Defaults to 90°.\n * @param aspect - Camera aspect ratio (width/height). Defaults to 1.\n * @param near - Near clipping plane distance. Must be greater than 0. Defaults to 1.\n * @param far - Far clipping plane distance. Must be greater than near plane. Defaults to 1000.\n */\n constructor(\n horizontalFov = DEFAULT_HORIZONTAL_FOV,\n verticalFov = DEFAULT_VERTICAL_FOV,\n aspect = DEFAULT_ASPECT,\n near = DEFAULT_NEAR,\n far = DEFAULT_FAR,\n ) {\n super(verticalFov, aspect, near, far);\n this.horizontalFovInternal = horizontalFov;\n this.verticalFovInternal = verticalFov;\n this.updateProjectionMatrix();\n }\n\n /**\n * Gets the current horizontal field of view in degrees.\n *\n * @returns The horizontal FOV value between 1° and 179°\n */\n public get horizontalFov(): number {\n return this.horizontalFovInternal;\n }\n\n /**\n * Gets the current vertical field of view in degrees.\n *\n * @returns The vertical FOV value between 1° and 179°\n */\n public get verticalFov(): number {\n return this.verticalFovInternal;\n }\n\n /**\n * Sets the horizontal field of view in degrees.\n *\n * @param value - The horizontal FOV value in degrees. Will be clamped between 1° and 179°.\n */\n public set horizontalFov(value: number) {\n this.horizontalFovInternal = MathUtils.clamp(value, MIN_FOV, MAX_FOV);\n this.updateProjectionMatrix();\n }\n\n /**\n * Sets the vertical field of view in degrees.\n *\n * @param value - The vertical FOV value in degrees. Will be clamped between 1° and 179°.\n */\n public set verticalFov(value: number) {\n this.verticalFovInternal = MathUtils.clamp(value, MIN_FOV, MAX_FOV);\n this.updateProjectionMatrix();\n }\n\n /**\n * Updates both horizontal and vertical field of view values simultaneously.\n *\n * @param horizontal - Horizontal FOV in degrees. Will be clamped between 1° and 179°.\n * @param vertical - Vertical FOV in degrees. Will be clamped between 1° and 179°.\n */\n public setFov(horizontal: number, vertical: number): void {\n this.horizontalFovInternal = MathUtils.clamp(horizontal, MIN_FOV, MAX_FOV);\n this.verticalFovInternal = MathUtils.clamp(vertical, MIN_FOV, MAX_FOV);\n this.updateProjectionMatrix();\n }\n\n /**\n * Copies the field of view settings from another DualFovCamera instance.\n *\n * @param source - The DualFovCamera instance to copy FOV settings from.\n */\n public copyFovSettings(source: DualFovCamera): void {\n this.horizontalFovInternal = source.horizontalFov;\n this.verticalFovInternal = source.verticalFov;\n this.updateProjectionMatrix();\n }\n\n /**\n * Updates the projection matrix based on current FOV settings and aspect ratio.\n *\n * The behavior differs based on orientation:\n * - **Landscape mode (aspect > 1)**: Preserves horizontal FOV, calculates vertical FOV\n * - **Portrait mode (aspect ≤ 1)**: Preserves vertical FOV, calculates horizontal FOV\n *\n * This method is automatically called when FOV values or aspect ratio changes.\n *\n * @override\n */\n public override updateProjectionMatrix(): void {\n if (this.aspect > 1) {\n // Landscape orientation: preserve horizontal FOV\n const radians = MathUtils.degToRad(this.horizontalFovInternal);\n this.fov = MathUtils.radToDeg(\n Math.atan(Math.tan(radians / 2) / this.aspect) * 2,\n );\n } else {\n // Portrait orientation: preserve vertical FOV\n this.fov = this.verticalFovInternal;\n }\n\n super.updateProjectionMatrix();\n }\n\n /**\n * Gets the actual horizontal field of view after aspect ratio adjustments.\n *\n * In landscape mode, this returns the set horizontal FOV.\n * In portrait mode, this calculates the actual horizontal FOV based on the vertical FOV and aspect ratio.\n *\n * @returns The actual horizontal FOV in degrees\n */\n public getActualHorizontalFov(): number {\n if (this.aspect >= 1) {\n return this.horizontalFovInternal;\n }\n const verticalRadians = MathUtils.degToRad(this.verticalFovInternal);\n return MathUtils.radToDeg(\n Math.atan(Math.tan(verticalRadians / 2) * this.aspect) * 2,\n );\n }\n\n /**\n * Gets the actual vertical field of view after aspect ratio adjustments.\n *\n * In portrait mode, this returns the set vertical FOV.\n * In landscape mode, this calculates the actual vertical FOV based on the horizontal FOV and aspect ratio.\n *\n * @returns The actual vertical FOV in degrees\n */\n public getActualVerticalFov(): number {\n if (this.aspect < 1) {\n return this.verticalFovInternal;\n }\n const horizontalRadians = MathUtils.degToRad(this.horizontalFovInternal);\n return MathUtils.radToDeg(\n Math.atan(Math.tan(horizontalRadians / 2) / this.aspect) * 2,\n );\n }\n\n /**\n * Adjusts the vertical field of view to fit all specified points within the camera's view.\n *\n * This method calculates the required vertical FOV to ensure all provided vertices\n * are visible within the vertical bounds of the camera's frustum.\n *\n * @param vertices - Array of 3D points (in world coordinates) that should fit within the camera's vertical view\n */\n public fitVerticalFovToPoints(vertices: Vector3[]): void {\n const up = new Vector3(0, 1, 0).applyQuaternion(this.quaternion);\n\n let maxVerticalAngle = 0;\n\n for (const vertex of vertices) {\n const vertexToCam = this.position.clone().sub(vertex);\n const vertexDirection = vertexToCam.normalize();\n\n const verticalAngle =\n Math.asin(Math.abs(vertexDirection.dot(up))) *\n Math.sign(vertexDirection.dot(up));\n\n if (Math.abs(verticalAngle) > maxVerticalAngle) {\n maxVerticalAngle = Math.abs(verticalAngle);\n }\n }\n\n const requiredFov = MathUtils.radToDeg(2 * maxVerticalAngle);\n\n this.verticalFovInternal = MathUtils.clamp(requiredFov, MIN_FOV, MAX_FOV);\n this.updateProjectionMatrix();\n }\n\n /**\n * Adjusts the vertical field of view to fit a bounding box within the camera's view.\n *\n * This method calculates the required vertical FOV to ensure the entire bounding box\n * is visible within the vertical bounds of the camera's frustum.\n *\n * @param box - The 3D bounding box (in world coordinates) that should fit within the camera's vertical view\n */\n public fitVerticalFovToBox(box: Box3): void {\n this.fitVerticalFovToPoints([\n new Vector3(box.min.x, box.min.y, box.min.z),\n new Vector3(box.min.x, box.min.y, box.max.z),\n new Vector3(box.min.x, box.max.y, box.min.z),\n new Vector3(box.min.x, box.max.y, box.max.z),\n new Vector3(box.max.x, box.min.y, box.min.z),\n new Vector3(box.max.x, box.min.y, box.max.z),\n new Vector3(box.max.x, box.max.y, box.min.z),\n new Vector3(box.max.x, box.max.y, box.max.z),\n ]);\n }\n\n /**\n * Adjusts the vertical field of view to fit a skinned mesh within the camera's view.\n *\n * This method updates the mesh's skeleton, applies bone transformations to all vertices,\n * and then calculates the required vertical FOV to ensure the entire deformed mesh\n * is visible within the vertical bounds of the camera's frustum.\n *\n * @param skinnedMesh - The skinned mesh (with active skeleton) that should fit within the camera's vertical view\n */\n public fitVerticalFovToMesh(skinnedMesh: SkinnedMesh): void {\n skinnedMesh.updateWorldMatrix(true, true);\n skinnedMesh.skeleton.update();\n\n const bakedGeometry = skinnedMesh.geometry;\n const position = bakedGeometry.attributes[\"position\"] as BufferAttribute;\n const target = new Vector3();\n\n const points = [];\n\n for (let i = 0; i < position.count; i++) {\n target.fromBufferAttribute(position, i);\n skinnedMesh.applyBoneTransform(i, target);\n points.push(target.clone());\n }\n\n this.fitVerticalFovToPoints(points);\n }\n\n /**\n * Points the camera to look at the center of mass of a skinned mesh.\n *\n * This method updates the mesh's skeleton, applies bone transformations to all vertices,\n * calculates the center of mass using a clustering algorithm, and then orients the camera\n * to look at that point.\n *\n * The center of mass calculation uses an iterative clustering approach to find the\n * main concentration of vertices, which provides better results than a simple average\n * for complex meshes.\n *\n * @param skinnedMesh - The skinned mesh (with active skeleton) whose center of mass should be the camera's target\n */\n public lookAtMeshCenterOfMass(skinnedMesh: SkinnedMesh): void {\n skinnedMesh.updateWorldMatrix(true, true);\n skinnedMesh.skeleton.update();\n\n const bakedGeometry = skinnedMesh.geometry;\n const position = bakedGeometry.attributes.position as BufferAttribute;\n const target = new Vector3();\n const points: Vector3[] = [];\n\n for (let i = 0; i < position.count; i++) {\n target.fromBufferAttribute(position, i);\n skinnedMesh.applyBoneTransform(i, target);\n points.push(target.clone());\n }\n\n /**\n * Finds the main cluster center of a set of 3D points using iterative refinement.\n *\n * @param points - Array of 3D points to cluster\n * @param iterations - Number of refinement iterations to perform\n * @returns The calculated center point of the main cluster\n */\n const findMainCluster = (points: Vector3[], iterations = 3): Vector3 => {\n if (points.length === 0) {\n return new Vector3();\n }\n\n let center = points[Math.floor(points.length / 2)].clone();\n\n for (let i = 0; i < iterations; i++) {\n let total = new Vector3();\n let count = 0;\n\n for (const point of points) {\n if (\n point.distanceTo(center) < point.distanceTo(total) ||\n count === 0\n ) {\n total.add(point);\n count++;\n }\n }\n\n if (count > 0) {\n center = total.divideScalar(count);\n }\n }\n\n return center;\n };\n\n const centerOfMass = findMainCluster(points);\n this.lookAt(centerOfMass);\n }\n\n /**\n * Creates a deep copy of this DualFovCamera instance.\n *\n * The cloned camera will have identical FOV settings, position, rotation,\n * and all other camera properties.\n *\n * @returns A new DualFovCamera instance that is an exact copy of this one\n * @override\n */\n public override clone(): this {\n const camera = new DualFovCamera(\n this.horizontalFovInternal,\n this.verticalFovInternal,\n this.aspect,\n this.near,\n this.far,\n ) as this;\n\n camera.copy(this, true);\n return camera;\n }\n}\n","import type { Material, Object3D } from \"three\";\nimport { Mesh } from \"three\";\n\n/**\n * Constructor type for type-safe scene traversal operations.\n *\n * This type represents any constructor function that can be used to create instances of type T.\n * It's used for runtime type checking when filtering objects by their constructor type.\n *\n * @template T - The type that the constructor creates\n */\nexport type Constructor<T> = abstract new (...args: never[]) => T;\n\n/**\n * Utility class for finding and modifying objects in a Three.js scene graph.\n *\n * This class provides static methods for traversing Three.js scene hierarchies,\n * searching for specific objects or materials, and performing batch operations\n * on collections of scene objects.\n *\n * All methods perform depth-first traversal of the scene graph starting from\n * the provided root object and recursively processing all children.\n */\nexport class SceneTraversal {\n /**\n * Finds the first object in the scene hierarchy with an exact name match.\n *\n * Performs a depth-first search through the scene graph starting from the provided\n * root object. Returns the first object encountered whose name property exactly\n * matches the search string.\n *\n * @param object - The root Object3D to start searching from\n * @param name - The exact name to search for (case-sensitive)\n * @returns The first matching Object3D, or null if no match is found\n\n */\n public static getObjectByName(\n object: Object3D,\n name: string,\n ): Object3D | null {\n if (object.name === name) {\n return object;\n }\n\n for (const child of object.children) {\n const result = SceneTraversal.getObjectByName(child, name);\n if (result) {\n return result;\n }\n }\n\n return null;\n }\n\n /**\n * Finds the first material in the scene hierarchy with an exact name match.\n *\n * Performs a depth-first search through the scene graph, examining materials\n * attached to Mesh objects. Handles both single materials and material arrays.\n * Returns the first material encountered whose name property exactly matches\n * the search string.\n *\n * @param object - The root Object3D to start searching from\n * @param name - The exact material name to search for (case-sensitive)\n * @returns The first matching Material, or null if no match is found\n\n */\n public static getMaterialByName(\n object: Object3D,\n name: string,\n ): Material | null {\n if (object instanceof Mesh) {\n if (Array.isArray(object.material)) {\n for (const material of object.material) {\n if (material.name === name) {\n return material;\n }\n }\n } else if (object.material.name === name) {\n return object.material;\n }\n }\n\n for (const child of object.children) {\n const material = SceneTraversal.getMaterialByName(child, name);\n if (material) {\n return material;\n }\n }\n\n return null;\n }\n\n /**\n * Processes all objects of a specific type in the scene hierarchy.\n *\n * Performs a depth-first traversal and executes the provided callback function\n * for every object that is an instance of the specified type. This is useful\n * for batch operations on specific object types (e.g., all lights, all meshes, etc.).\n *\n * @template T - The type of objects to process\n * @param object - The root Object3D to start searching from\n * @param type - The constructor/class to filter by (e.g., DirectionalLight, Mesh)\n * @param callback - Function to execute for each matching object instance\n\n */\n public static enumerateObjectsByType<T>(\n object: Object3D,\n type: Constructor<T>,\n callback: (instance: T) => void,\n ): void {\n if (object instanceof type) {\n callback(object);\n }\n\n for (const child of object.children) {\n SceneTraversal.enumerateObjectsByType(child, type, callback);\n }\n }\n\n /**\n * Processes all materials found in mesh objects within the scene hierarchy.\n *\n * Performs a depth-first traversal, finding all Mesh objects and executing\n * the provided callback function for each material. Handles both single\n * materials and material arrays properly.\n *\n * @param object - The root Object3D to start searching from\n * @param callback - Function to execute for each material found\n\n */\n public static enumerateMaterials(\n object: Object3D,\n callback: (material: Material) => void,\n ): void {\n if (object instanceof Mesh) {\n if (Array.isArray(object.material)) {\n for (const material of object.material) {\n callback(material);\n }\n } else {\n callback(object.material);\n }\n }\n\n for (const child of object.children) {\n SceneTraversal.enumerateMaterials(child, callback);\n }\n }\n\n /**\n * Finds all objects in the scene hierarchy that match the specified filter criteria.\n *\n * Performs a depth-first search and collects all objects that either match\n * a regular expression pattern (applied to the object's name) or satisfy\n * a custom predicate function.\n *\n * @param object - The root Object3D to start searching from\n * @param filter - Either a RegExp to test against object names, or a predicate function\n * @returns Array of all matching Object3D instances\n\n */\n public static filterObjects(\n object: Object3D,\n filter: RegExp | ((object: Object3D) => boolean),\n ): Object3D[] {\n let result: Object3D[] = [];\n\n if (typeof filter === \"function\") {\n if (filter(object)) {\n result.push(object);\n }\n } else {\n if (object.name && filter.test(object.name)) {\n result.push(object);\n }\n }\n\n for (const child of object.children) {\n result = result.concat(SceneTraversal.filterObjects(child, filter));\n }\n\n return result;\n }\n\n /**\n * Finds all materials in the scene hierarchy whose names match a regular expression pattern.\n *\n * Performs a depth-first search through all Mesh objects and collects materials\n * whose name property matches the provided regular expression. Handles both\n * single materials and material arrays properly.\n *\n * @param object - The root Object3D to start searching from\n * @param name - Regular expression pattern to test against material names\n * @returns Array of all matching Material instances\n\n */\n public static filterMaterials(object: Object3D, name: RegExp): Material[] {\n let result: Material[] = [];\n\n if (object instanceof Mesh) {\n if (Array.isArray(object.material)) {\n for (const material of object.material) {\n if (material.name && name.test(material.name)) {\n result.push(material);\n }\n }\n } else {\n if (object.material.name && name.test(object.material.name)) {\n result.push(object.material);\n }\n }\n }\n\n for (const child of object.children) {\n result = result.concat(SceneTraversal.filterMaterials(child, name));\n }\n\n return result;\n }\n\n /**\n * Finds all objects (mesh users) that use materials with names matching a regular expression pattern.\n *\n * Performs a depth-first search through all Mesh objects and collects the mesh objects\n * whose materials have names that match the provided regular expression. This is useful\n * for finding all objects that use specific material types or naming patterns.\n *\n * @param object - The root Object3D to start searching from\n * @param materialName - Regular expression pattern to test against material names\n * @returns Array of all Mesh objects that use materials with matching names\n */\n public static findMaterialUsers(\n object: Object3D,\n materialName: RegExp,\n ): Mesh[] {\n let result: Mesh[] = [];\n\n if (object instanceof Mesh) {\n let hasMatchingMaterial = false;\n\n if (Array.isArray(object.material)) {\n for (const material of object.material) {\n if (material.name && materialName.test(material.name)) {\n hasMatchingMaterial = true;\n break;\n }\n }\n } else {\n if (object.material.name && materialName.test(object.material.name)) {\n hasMatchingMaterial = true;\n }\n }\n\n if (hasMatchingMaterial) {\n result.push(object);\n }\n }\n\n for (const child of object.children) {\n result = result.concat(\n SceneTraversal.findMaterialUsers(child, materialName),\n );\n }\n\n return result;\n }\n}\n","import type { AnimationClip, Object3D, SkinnedMesh } from \"three\";\nimport { AnimationMixer, BufferAttribute, Mesh, Vector3 } from \"three\";\n\n/** Number of components per vertex */\nconst COMPONENT_COUNT = 3;\n\n/** Convert skinned meshes to regular static meshes */\nexport class SkinnedMeshBaker {\n /**\n * Convert a skinned mesh to a regular mesh in its current pose.\n * The resulting mesh will have no bones but look identical.\n * \n * @param skinnedMesh - Mesh to convert\n * @returns Static mesh with baked vertex positions\n */\n public static bakePose(skinnedMesh: SkinnedMesh): Mesh {\n const bakedGeometry = skinnedMesh.geometry.clone();\n const position = bakedGeometry.attributes[\"position\"] as BufferAttribute;\n const newPositions = new Float32Array(position.count * COMPONENT_COUNT);\n const target = new Vector3();\n\n for (let i = 0; i < position.count; i++) {\n target.fromBufferAttribute(position, i);\n skinnedMesh.applyBoneTransform(i, target);\n newPositions[i * COMPONENT_COUNT + 0] = target.x;\n newPositions[i * COMPONENT_COUNT + 1] = target.y;\n newPositions[i * COMPONENT_COUNT + 2] = target.z;\n }\n\n bakedGeometry.setAttribute(\n \"position\",\n new BufferAttribute(newPositions, COMPONENT_COUNT),\n );\n bakedGeometry.computeVertexNormals();\n bakedGeometry.deleteAttribute(\"skinIndex\");\n bakedGeometry.deleteAttribute(\"skinWeight\");\n\n const mesh = new Mesh(bakedGeometry, skinnedMesh.material);\n mesh.name = skinnedMesh.name;\n return mesh;\n }\n\n /**\n * Bake a single frame from an animation into a static mesh.\n * \n * @param armature - Root object with bones (usually from GLTF)\n * @param skinnedMesh - Mesh to convert\n * @param timeOffset - Time in seconds within the animation\n * @param clip - Animation to get the pose from\n * @returns Static mesh with baked vertex positions\n */\n public static bakeAnimationFrame(\n armature: Object3D,\n skinnedMesh: SkinnedMesh,\n timeOffset: number,\n clip: AnimationClip,\n ): Mesh {\n const mixer = new AnimationMixer(armature);\n const action = mixer.clipAction(clip);\n action.play();\n mixer.setTime(timeOffset);\n\n armature.updateWorldMatrix(true, true);\n skinnedMesh.skeleton.update();\n\n return this.bakePose(skinnedMesh);\n }\n}","import type { Texture } from \"three\";\nimport { Box3, DirectionalLight, RGBAFormat, Spherical, Vector3 } from \"three\";\n\n/** Number of color channels in RGBA format */\nconst RGBA_CHANNEL_COUNT = 4;\n/** Number of color channels in RGB format */\nconst RGB_CHANNEL_COUNT = 3;\n\n/** Red channel weight for luminance calculation (ITU-R BT.709) */\nconst LUMINANCE_R = 0.2126;\n/** Green channel weight for luminance calculation (ITU-R BT.709) */\nconst LUMINANCE_G = 0.7152;\n/** Blue channel weight for luminance calculation (ITU-R BT.709) */\nconst LUMINANCE_B = 0.0722;\n\n/**\n * A directional light with spherical positioning controls and advanced shadow mapping.\n *\n * Extends Three.js DirectionalLight to provide intuitive spherical coordinate control\n * (distance, elevation, azimuth) and automatic shadow map configuration for bounding boxes.\n * Also supports automatic sun direction calculation from HDR environment maps.\n */\nexport class Sun extends DirectionalLight {\n /** Internal vectors to avoid garbage collection during calculations */\n private readonly tempVector3D0 = new Vector3();\n private readonly tempVector3D1 = new Vector3();\n private readonly tempVector3D2 = new Vector3();\n private readonly tempVector3D3 = new Vector3();\n private readonly tempVector3D4 = new Vector3();\n private readonly tempVector3D5 = new Vector3();\n private readonly tempVector3D6 = new Vector3();\n private readonly tempVector3D7 = new Vector3();\n private readonly tempBox3 = new Box3();\n private readonly tempSpherical = new Spherical();\n\n /**\n * Gets the distance from the light to its target (origin).\n *\n * @returns The distance in world units\n */\n public get distance(): number {\n return this.position.length();\n }\n\n /**\n * Gets the elevation angle (vertical angle from the horizontal plane).\n *\n * @returns The elevation angle in radians (0 = horizontal, π/2 = directly above)\n */\n public get elevation(): number {\n return this.tempSpherical.setFromVector3(this.position).phi;\n }\n\n /**\n * Gets the azimuth angle (horizontal rotation around the target).\n *\n * @returns The azimuth angle in radians (0 = positive X axis, π/2 = positive Z axis)\n */\n public get azimuth(): number {\n return this.tempSpherical.setFromVector3(this.position).theta;\n }\n\n /**\n * Sets the distance while preserving current elevation and azimuth angles.\n *\n * @param value - The new distance in world units\n */\n public set distance(value: number) {\n this.tempSpherical.setFromVector3(this.position);\n this.position.setFromSphericalCoords(\n value,\n this.tempSpherical.phi,\n this.tempSpherical.theta,\n );\n }\n\n /**\n * Sets the elevation angle while preserving current distance and azimuth.\n *\n * @param value - The new elevation angle in radians (0 = horizontal, π/2 = directly above)\n */\n public set elevation(value: number) {\n this.tempSpherical.setFromVector3(this.position);\n this.position.setFromSphericalCoords(\n this.tempSpherical.radius,\n value,\n this.tempSpherical.theta,\n );\n }\n\n /**\n * Sets the azimuth angle while preserving current distance and elevation.\n *\n * @param value - The new azimuth angle in radians (0 = positive X axis, π/2 = positive Z axis)\n */\n public set azimuth(value: number) {\n this.tempSpherical.setFromVector3(this.position);\n this.position.setFromSphericalCoords(\n this.tempSpherical.radius,\n this.tempSpherical.phi,\n value,\n );\n }\n\n /**\n * Configures the shadow camera to optimally cover a bounding box.\n *\n * This method automatically adjusts the directional light's shadow camera frustum\n * to perfectly encompass the provided bounding box, ensuring efficient shadow map\n * usage and eliminating shadow clipping issues.\n *\n * @param box3 - The 3D bounding box to cover with shadows\n */\n public configureShadowsForBoundingBox(box3: Box3): void {\n const camera = this.shadow.camera;\n\n this.target.updateWorldMatrix(true, false);\n this.lookAt(this.target.getWorldPosition(this.tempVector3D0));\n\n this.updateWorldMatrix(true, false);\n\n const points: Vector3[] = [\n this.tempVector3D0.set(box3.min.x, box3.min.y, box3.min.z),\n this.tempVector3D1.set(box3.min.x, box3.min.y, box3.max.z),\n this.tempVector3D2.set(box3.min.x, box3.max.y, box3.min.z),\n this.tempVector3D3.set(box3.min.x, box3.max.y, box3.max.z),\n this.tempVector3D4.set(box3.max.x, box3.min.y, box3.min.z),\n this.tempVector3D5.set(box3.max.x, box3.min.y, box3.max.z),\n this.tempVector3D6.set(box3.max.x, box3.max.y, box3.min.z),\n this.tempVector3D7.set(box3.max.x, box3.max.y, box3.max.z),\n ];\n\n const inverseMatrix = this.matrixWorld.clone().invert();\n\n for (const point of points) {\n point.applyMatrix4(inverseMatrix);\n }\n\n const newBox3 = this.tempBox3.setFromPoints(points);\n\n camera.left = newBox3.min.x;\n camera.bottom = newBox3.min.y;\n camera.near = -newBox3.max.z;\n\n camera.right = newBox3.max.x;\n camera.top = newBox3.max.y;\n camera.far = -newBox3.min.z;\n\n camera.updateWorldMatrix(true, false);\n camera.updateProjectionMatrix();\n }\n\n /**\n * Sets the sun's direction based on the brightest point in an HDR environment map.\n *\n * This method analyzes an HDR texture to find the pixel with the highest luminance\n * value and positions the sun to shine from that direction. This is useful for\n * creating realistic lighting that matches HDR environment maps.\n *\n * @param texture - The HDR texture to analyze (must have image data available)\n * @param distance - The distance to place the sun from the origin (defaults to 1)\n */\n public setDirectionFromHDRTexture(texture: Texture, distance = 1): void {\n const data = texture.image.data;\n const width = texture.image.width;\n const height = texture.image.height;\n\n let maxLuminance = 0;\n let maxIndex = 0;\n\n // Find brightest pixel\n\n const step =\n texture.format === RGBAFormat ? RGBA_CHANNEL_COUNT : RGB_CHANNEL_COUNT;\n for (let i = 0; i < data.length; i += step) {\n const r = data[i];\n const g = data[i + 1];\n const b = data[i + 2];\n const luminance = LUMINANCE_R * r + LUMINANCE_G * g + LUMINANCE_B * b;\n if (luminance > maxLuminance) {\n maxLuminance = luminance;\n maxIndex = i;\n }\n }\n\n // Convert to spherical coordinates\n const pixelIndex = maxIndex / step;\n const x = pixelIndex % width;\n const y = Math.floor(pixelIndex / width);\n\n const u = x / width;\n const v = y / height;\n\n const elevation = v * Math.PI;\n const azimuth = u * -Math.PI * 2 - Math.PI / 2;\n\n this.position.setFromSphericalCoords(distance, elevation, azimuth);\n }\n}\n"],"names":["MAX_FOV","DualFovCamera","PerspectiveCamera","constructor","horizontalFov","verticalFov","aspect","near","far","super","this","_private_horizontalFovInternal","_private_verticalFovInternal","updateProjectionMatrix","value","MathUtils","clamp","setFov","horizontal","vertical","copyFovSettings","source","radians","degToRad","fov","radToDeg","Math","atan","tan","getActualHorizontalFov","verticalRadians","getActualVerticalFov","horizontalRadians","fitVerticalFovToPoints","vertices","up","Vector3","applyQuaternion","quaternion","maxVerticalAngle","vertex","vertexDirection","position","clone","sub","normalize","verticalAngle","asin","abs","dot","sign","requiredFov","fitVerticalFovToBox","box","min","x","y","z","max","fitVerticalFovToMesh","skinnedMesh","updateWorldMatrix","skeleton","update","geometry","attributes","target","points","i","count","fromBufferAttribute","applyBoneTransform","push","lookAtMeshCenterOfMass","centerOfMass","iterations","length","center","floor","total","point","distanceTo","add","divideScalar","findMainCluster","lookAt","camera","copy","SceneTraversal","getObjectByName","object","name","child","children","result","getMaterialByName","Mesh","Array","isArray","material","enumerateObjectsByType","type","callback","enumerateMaterials","filterObjects","filter","test","concat","filterMaterials","findMaterialUsers","materialName","hasMatchingMaterial","SkinnedMeshBaker","bakePose","bakedGeometry","newPositions","Float32Array","setAttribute","BufferAttribute","computeVertexNormals","deleteAttribute","mesh","bakeAnimationFrame","armature","timeOffset","clip","mixer","AnimationMixer","clipAction","play","setTime","Sun","DirectionalLight","Box3","Spherical","distance","elevation","_private_tempSpherical","setFromVector3","phi","azimuth","theta","setFromSphericalCoords","radius","configureShadowsForBoundingBox","box3","shadow","getWorldPosition","_private_tempVector3D0","set","_private_tempVector3D1","_private_tempVector3D2","_private_tempVector3D3","_private_tempVector3D4","_private_tempVector3D5","_private_tempVector3D6","_private_tempVector3D7","inverseMatrix","matrixWorld","invert","applyMatrix4","newBox3","_private_tempBox3","setFromPoints","left","bottom","right","top","setDirectionFromHDRTexture","texture","data","image","width","height","maxLuminance","maxIndex","step","format","RGBAFormat","luminance","pixelIndex","PI"],"mappings":"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"}
1
+ {"version":3,"file":"index.min.js","sources":["../src/DualFovCamera.ts","../src/SceneTraversal.ts","../src/SkinnedMeshBaker.ts","../src/StandardToBasicConverter.ts","../src/StandardToLambertConverter.ts","../src/Sun.ts"],"sourcesContent":["import type { Box3, BufferAttribute, SkinnedMesh } from \"three\";\nimport { MathUtils, PerspectiveCamera, Vector3 } from \"three\";\n\n/** Default horizontal field of view in degrees */\nconst DEFAULT_HORIZONTAL_FOV = 90;\n/** Default vertical field of view in degrees */\nconst DEFAULT_VERTICAL_FOV = 90;\n/** Default aspect ratio (width/height) */\nconst DEFAULT_ASPECT = 1;\n/** Default near clipping plane distance */\nconst DEFAULT_NEAR = 1;\n/** Default far clipping plane distance */\nconst DEFAULT_FAR = 1000;\n\n/** Minimum allowed field of view in degrees */\nconst MIN_FOV = 1;\n/** Maximum allowed field of view in degrees */\nconst MAX_FOV = 179;\n\n/**\n * A camera that supports independent horizontal and vertical FOV settings.\n * Extends Three.js PerspectiveCamera to allow separate control over horizontal\n * and vertical fields of view.\n */\nexport class DualFovCamera extends PerspectiveCamera {\n /** Internal storage for horizontal field of view in degrees */\n private horizontalFovInternal: number;\n /** Internal storage for vertical field of view in degrees */\n private verticalFovInternal: number;\n\n /**\n * Creates a new DualFovCamera instance with independent horizontal and vertical FOV control.\n *\n * @param horizontalFov - Horizontal field of view in degrees. Must be between 1° and 179°. Defaults to 90°.\n * @param verticalFov - Vertical field of view in degrees. Must be between 1° and 179°. Defaults to 90°.\n * @param aspect - Camera aspect ratio (width/height). Defaults to 1.\n * @param near - Near clipping plane distance. Must be greater than 0. Defaults to 1.\n * @param far - Far clipping plane distance. Must be greater than near plane. Defaults to 1000.\n */\n constructor(\n horizontalFov = DEFAULT_HORIZONTAL_FOV,\n verticalFov = DEFAULT_VERTICAL_FOV,\n aspect = DEFAULT_ASPECT,\n near = DEFAULT_NEAR,\n far = DEFAULT_FAR,\n ) {\n super(verticalFov, aspect, near, far);\n this.horizontalFovInternal = horizontalFov;\n this.verticalFovInternal = verticalFov;\n this.updateProjectionMatrix();\n }\n\n /**\n * Gets the current horizontal field of view in degrees.\n *\n * @returns The horizontal FOV value between 1° and 179°\n */\n public get horizontalFov(): number {\n return this.horizontalFovInternal;\n }\n\n /**\n * Gets the current vertical field of view in degrees.\n *\n * @returns The vertical FOV value between 1° and 179°\n */\n public get verticalFov(): number {\n return this.verticalFovInternal;\n }\n\n /**\n * Sets the horizontal field of view in degrees.\n *\n * @param value - The horizontal FOV value in degrees. Will be clamped between 1° and 179°.\n */\n public set horizontalFov(value: number) {\n this.horizontalFovInternal = MathUtils.clamp(value, MIN_FOV, MAX_FOV);\n this.updateProjectionMatrix();\n }\n\n /**\n * Sets the vertical field of view in degrees.\n *\n * @param value - The vertical FOV value in degrees. Will be clamped between 1° and 179°.\n */\n public set verticalFov(value: number) {\n this.verticalFovInternal = MathUtils.clamp(value, MIN_FOV, MAX_FOV);\n this.updateProjectionMatrix();\n }\n\n /**\n * Updates both horizontal and vertical field of view values simultaneously.\n *\n * @param horizontal - Horizontal FOV in degrees. Will be clamped between 1° and 179°.\n * @param vertical - Vertical FOV in degrees. Will be clamped between 1° and 179°.\n */\n public setFov(horizontal: number, vertical: number): void {\n this.horizontalFovInternal = MathUtils.clamp(horizontal, MIN_FOV, MAX_FOV);\n this.verticalFovInternal = MathUtils.clamp(vertical, MIN_FOV, MAX_FOV);\n this.updateProjectionMatrix();\n }\n\n /**\n * Copies the field of view settings from another DualFovCamera instance.\n *\n * @param source - The DualFovCamera instance to copy FOV settings from.\n */\n public copyFovSettings(source: DualFovCamera): void {\n this.horizontalFovInternal = source.horizontalFov;\n this.verticalFovInternal = source.verticalFov;\n this.updateProjectionMatrix();\n }\n\n /**\n * Updates the projection matrix based on current FOV settings and aspect ratio.\n *\n * The behavior differs based on orientation:\n * - **Landscape mode (aspect > 1)**: Preserves horizontal FOV, calculates vertical FOV\n * - **Portrait mode (aspect ≤ 1)**: Preserves vertical FOV, calculates horizontal FOV\n *\n * This method is automatically called when FOV values or aspect ratio changes.\n *\n * @override\n */\n public override updateProjectionMatrix(): void {\n if (this.aspect > 1) {\n // Landscape orientation: preserve horizontal FOV\n const radians = MathUtils.degToRad(this.horizontalFovInternal);\n this.fov = MathUtils.radToDeg(\n Math.atan(Math.tan(radians / 2) / this.aspect) * 2,\n );\n } else {\n // Portrait orientation: preserve vertical FOV\n this.fov = this.verticalFovInternal;\n }\n\n super.updateProjectionMatrix();\n }\n\n /**\n * Gets the actual horizontal field of view after aspect ratio adjustments.\n *\n * In landscape mode, this returns the set horizontal FOV.\n * In portrait mode, this calculates the actual horizontal FOV based on the vertical FOV and aspect ratio.\n *\n * @returns The actual horizontal FOV in degrees\n */\n public getActualHorizontalFov(): number {\n if (this.aspect >= 1) {\n return this.horizontalFovInternal;\n }\n const verticalRadians = MathUtils.degToRad(this.verticalFovInternal);\n return MathUtils.radToDeg(\n Math.atan(Math.tan(verticalRadians / 2) * this.aspect) * 2,\n );\n }\n\n /**\n * Gets the actual vertical field of view after aspect ratio adjustments.\n *\n * In portrait mode, this returns the set vertical FOV.\n * In landscape mode, this calculates the actual vertical FOV based on the horizontal FOV and aspect ratio.\n *\n * @returns The actual vertical FOV in degrees\n */\n public getActualVerticalFov(): number {\n if (this.aspect < 1) {\n return this.verticalFovInternal;\n }\n const horizontalRadians = MathUtils.degToRad(this.horizontalFovInternal);\n return MathUtils.radToDeg(\n Math.atan(Math.tan(horizontalRadians / 2) / this.aspect) * 2,\n );\n }\n\n /**\n * Adjusts the vertical field of view to fit all specified points within the camera's view.\n *\n * This method calculates the required vertical FOV to ensure all provided vertices\n * are visible within the vertical bounds of the camera's frustum.\n *\n * @param vertices - Array of 3D points (in world coordinates) that should fit within the camera's vertical view\n */\n public fitVerticalFovToPoints(vertices: Vector3[]): void {\n const up = new Vector3(0, 1, 0).applyQuaternion(this.quaternion);\n\n let maxVerticalAngle = 0;\n\n for (const vertex of vertices) {\n const vertexToCam = this.position.clone().sub(vertex);\n const vertexDirection = vertexToCam.normalize();\n\n const verticalAngle =\n Math.asin(Math.abs(vertexDirection.dot(up))) *\n Math.sign(vertexDirection.dot(up));\n\n if (Math.abs(verticalAngle) > maxVerticalAngle) {\n maxVerticalAngle = Math.abs(verticalAngle);\n }\n }\n\n const requiredFov = MathUtils.radToDeg(2 * maxVerticalAngle);\n\n this.verticalFovInternal = MathUtils.clamp(requiredFov, MIN_FOV, MAX_FOV);\n this.updateProjectionMatrix();\n }\n\n /**\n * Adjusts the vertical field of view to fit a bounding box within the camera's view.\n *\n * This method calculates the required vertical FOV to ensure the entire bounding box\n * is visible within the vertical bounds of the camera's frustum.\n *\n * @param box - The 3D bounding box (in world coordinates) that should fit within the camera's vertical view\n */\n public fitVerticalFovToBox(box: Box3): void {\n this.fitVerticalFovToPoints([\n new Vector3(box.min.x, box.min.y, box.min.z),\n new Vector3(box.min.x, box.min.y, box.max.z),\n new Vector3(box.min.x, box.max.y, box.min.z),\n new Vector3(box.min.x, box.max.y, box.max.z),\n new Vector3(box.max.x, box.min.y, box.min.z),\n new Vector3(box.max.x, box.min.y, box.max.z),\n new Vector3(box.max.x, box.max.y, box.min.z),\n new Vector3(box.max.x, box.max.y, box.max.z),\n ]);\n }\n\n /**\n * Adjusts the vertical field of view to fit a skinned mesh within the camera's view.\n *\n * This method updates the mesh's skeleton, applies bone transformations to all vertices,\n * and then calculates the required vertical FOV to ensure the entire deformed mesh\n * is visible within the vertical bounds of the camera's frustum.\n *\n * @param skinnedMesh - The skinned mesh (with active skeleton) that should fit within the camera's vertical view\n */\n public fitVerticalFovToMesh(skinnedMesh: SkinnedMesh): void {\n skinnedMesh.updateWorldMatrix(true, true);\n skinnedMesh.skeleton.update();\n\n const bakedGeometry = skinnedMesh.geometry;\n const position = bakedGeometry.attributes[\"position\"] as BufferAttribute;\n const target = new Vector3();\n\n const points = [];\n\n for (let i = 0; i < position.count; i++) {\n target.fromBufferAttribute(position, i);\n skinnedMesh.applyBoneTransform(i, target);\n points.push(target.clone());\n }\n\n this.fitVerticalFovToPoints(points);\n }\n\n /**\n * Points the camera to look at the center of mass of a skinned mesh.\n *\n * This method updates the mesh's skeleton, applies bone transformations to all vertices,\n * calculates the center of mass using a clustering algorithm, and then orients the camera\n * to look at that point.\n *\n * The center of mass calculation uses an iterative clustering approach to find the\n * main concentration of vertices, which provides better results than a simple average\n * for complex meshes.\n *\n * @param skinnedMesh - The skinned mesh (with active skeleton) whose center of mass should be the camera's target\n */\n public lookAtMeshCenterOfMass(skinnedMesh: SkinnedMesh): void {\n skinnedMesh.updateWorldMatrix(true, true);\n skinnedMesh.skeleton.update();\n\n const bakedGeometry = skinnedMesh.geometry;\n const position = bakedGeometry.attributes.position as BufferAttribute;\n const target = new Vector3();\n const points: Vector3[] = [];\n\n for (let i = 0; i < position.count; i++) {\n target.fromBufferAttribute(position, i);\n skinnedMesh.applyBoneTransform(i, target);\n points.push(target.clone());\n }\n\n /**\n * Finds the main cluster center of a set of 3D points using iterative refinement.\n *\n * @param points - Array of 3D points to cluster\n * @param iterations - Number of refinement iterations to perform\n * @returns The calculated center point of the main cluster\n */\n const findMainCluster = (points: Vector3[], iterations = 3): Vector3 => {\n if (points.length === 0) {\n return new Vector3();\n }\n\n let center = points[Math.floor(points.length / 2)].clone();\n\n for (let i = 0; i < iterations; i++) {\n let total = new Vector3();\n let count = 0;\n\n for (const point of points) {\n if (\n point.distanceTo(center) < point.distanceTo(total) ||\n count === 0\n ) {\n total.add(point);\n count++;\n }\n }\n\n if (count > 0) {\n center = total.divideScalar(count);\n }\n }\n\n return center;\n };\n\n const centerOfMass = findMainCluster(points);\n this.lookAt(centerOfMass);\n }\n\n /**\n * Creates a deep copy of this DualFovCamera instance.\n *\n * The cloned camera will have identical FOV settings, position, rotation,\n * and all other camera properties.\n *\n * @returns A new DualFovCamera instance that is an exact copy of this one\n * @override\n */\n public override clone(): this {\n const camera = new DualFovCamera(\n this.horizontalFovInternal,\n this.verticalFovInternal,\n this.aspect,\n this.near,\n this.far,\n ) as this;\n\n camera.copy(this, true);\n return camera;\n }\n}\n","import type { Material, Object3D } from \"three\";\nimport { Mesh } from \"three\";\n\n/**\n * Constructor type for type-safe scene traversal operations.\n *\n * This type represents any constructor function that can be used to create instances of type T.\n * It's used for runtime type checking when filtering objects by their constructor type.\n *\n * @template T - The type that the constructor creates\n */\nexport type Constructor<T> = abstract new (...args: never[]) => T;\n\n/**\n * Utility class for finding and modifying objects in a Three.js scene graph.\n *\n * This class provides static methods for traversing Three.js scene hierarchies,\n * searching for specific objects or materials, and performing batch operations\n * on collections of scene objects.\n *\n * All methods perform depth-first traversal of the scene graph starting from\n * the provided root object and recursively processing all children.\n */\nexport class SceneTraversal {\n /**\n * Finds the first object in the scene hierarchy with an exact name match.\n *\n * Performs a depth-first search through the scene graph starting from the provided\n * root object. Returns the first object encountered whose name property exactly\n * matches the search string.\n *\n * @param object - The root Object3D to start searching from\n * @param name - The exact name to search for (case-sensitive)\n * @returns The first matching Object3D, or null if no match is found\n\n */\n public static getObjectByName(\n object: Object3D,\n name: string,\n ): Object3D | null {\n if (object.name === name) {\n return object;\n }\n\n for (const child of object.children) {\n const result = SceneTraversal.getObjectByName(child, name);\n if (result) {\n return result;\n }\n }\n\n return null;\n }\n\n /**\n * Finds the first material in the scene hierarchy with an exact name match.\n *\n * Performs a depth-first search through the scene graph, examining materials\n * attached to Mesh objects. Handles both single materials and material arrays.\n * Returns the first material encountered whose name property exactly matches\n * the search string.\n *\n * @param object - The root Object3D to start searching from\n * @param name - The exact material name to search for (case-sensitive)\n * @returns The first matching Material, or null if no match is found\n\n */\n public static getMaterialByName(\n object: Object3D,\n name: string,\n ): Material | null {\n if (object instanceof Mesh) {\n if (Array.isArray(object.material)) {\n for (const material of object.material) {\n if (material.name === name) {\n return material;\n }\n }\n } else if (object.material.name === name) {\n return object.material;\n }\n }\n\n for (const child of object.children) {\n const material = SceneTraversal.getMaterialByName(child, name);\n if (material) {\n return material;\n }\n }\n\n return null;\n }\n\n /**\n * Processes all objects of a specific type in the scene hierarchy.\n *\n * Performs a depth-first traversal and executes the provided callback function\n * for every object that is an instance of the specified type. This is useful\n * for batch operations on specific object types (e.g., all lights, all meshes, etc.).\n *\n * @template T - The type of objects to process\n * @param object - The root Object3D to start searching from\n * @param type - The constructor/class to filter by (e.g., DirectionalLight, Mesh)\n * @param callback - Function to execute for each matching object instance\n\n */\n public static enumerateObjectsByType<T>(\n object: Object3D,\n type: Constructor<T>,\n callback: (instance: T) => void,\n ): void {\n if (object instanceof type) {\n callback(object);\n }\n\n for (const child of object.children) {\n SceneTraversal.enumerateObjectsByType(child, type, callback);\n }\n }\n\n /**\n * Processes all materials found in mesh objects within the scene hierarchy.\n *\n * Performs a depth-first traversal, finding all Mesh objects and executing\n * the provided callback function for each material. Handles both single\n * materials and material arrays properly.\n *\n * @param object - The root Object3D to start searching from\n * @param callback - Function to execute for each material found\n\n */\n public static enumerateMaterials(\n object: Object3D,\n callback: (material: Material) => void,\n ): void {\n if (object instanceof Mesh) {\n if (Array.isArray(object.material)) {\n for (const material of object.material) {\n callback(material);\n }\n } else {\n callback(object.material);\n }\n }\n\n for (const child of object.children) {\n SceneTraversal.enumerateMaterials(child, callback);\n }\n }\n\n /**\n * Finds all objects in the scene hierarchy that match the specified filter criteria.\n *\n * Performs a depth-first search and collects all objects that either match\n * a regular expression pattern (applied to the object's name) or satisfy\n * a custom predicate function.\n *\n * @param object - The root Object3D to start searching from\n * @param filter - Either a RegExp to test against object names, or a predicate function\n * @returns Array of all matching Object3D instances\n\n */\n public static filterObjects(\n object: Object3D,\n filter: RegExp | ((object: Object3D) => boolean),\n ): Object3D[] {\n let result: Object3D[] = [];\n\n if (typeof filter === \"function\") {\n if (filter(object)) {\n result.push(object);\n }\n } else {\n if (object.name && filter.test(object.name)) {\n result.push(object);\n }\n }\n\n for (const child of object.children) {\n result = result.concat(SceneTraversal.filterObjects(child, filter));\n }\n\n return result;\n }\n\n /**\n * Finds all materials in the scene hierarchy whose names match a regular expression pattern.\n *\n * Performs a depth-first search through all Mesh objects and collects materials\n * whose name property matches the provided regular expression. Handles both\n * single materials and material arrays properly.\n *\n * @param object - The root Object3D to start searching from\n * @param name - Regular expression pattern to test against material names\n * @returns Array of all matching Material instances\n\n */\n public static filterMaterials(object: Object3D, name: RegExp): Material[] {\n let result: Material[] = [];\n\n if (object instanceof Mesh) {\n if (Array.isArray(object.material)) {\n for (const material of object.material) {\n if (material.name && name.test(material.name)) {\n result.push(material);\n }\n }\n } else {\n if (object.material.name && name.test(object.material.name)) {\n result.push(object.material);\n }\n }\n }\n\n for (const child of object.children) {\n result = result.concat(SceneTraversal.filterMaterials(child, name));\n }\n\n return result;\n }\n\n /**\n * Finds all objects (mesh users) that use materials with names matching a regular expression pattern.\n *\n * Performs a depth-first search through all Mesh objects and collects the mesh objects\n * whose materials have names that match the provided regular expression. This is useful\n * for finding all objects that use specific material types or naming patterns.\n *\n * @param object - The root Object3D to start searching from\n * @param materialName - Regular expression pattern to test against material names\n * @returns Array of all Mesh objects that use materials with matching names\n */\n public static findMaterialUsers(\n object: Object3D,\n materialName: RegExp,\n ): Mesh[] {\n let result: Mesh[] = [];\n\n if (object instanceof Mesh) {\n let hasMatchingMaterial = false;\n\n if (Array.isArray(object.material)) {\n for (const material of object.material) {\n if (material.name && materialName.test(material.name)) {\n hasMatchingMaterial = true;\n break;\n }\n }\n } else {\n if (object.material.name && materialName.test(object.material.name)) {\n hasMatchingMaterial = true;\n }\n }\n\n if (hasMatchingMaterial) {\n result.push(object);\n }\n }\n\n for (const child of object.children) {\n result = result.concat(\n SceneTraversal.findMaterialUsers(child, materialName),\n );\n }\n\n return result;\n }\n}\n","import type { AnimationClip, Object3D, SkinnedMesh } from \"three\";\nimport { AnimationMixer, BufferAttribute, Mesh, Vector3 } from \"three\";\n\n/** Number of components per vertex */\nconst COMPONENT_COUNT = 3;\n\n/** Convert skinned meshes to regular static meshes */\nexport class SkinnedMeshBaker {\n /**\n * Convert a skinned mesh to a regular mesh in its current pose.\n * The resulting mesh will have no bones but look identical.\n *\n * @param skinnedMesh - Mesh to convert\n * @returns Static mesh with baked vertex positions\n */\n public static bakePose(skinnedMesh: SkinnedMesh): Mesh {\n const bakedGeometry = skinnedMesh.geometry.clone();\n const position = bakedGeometry.attributes[\"position\"] as BufferAttribute;\n const newPositions = new Float32Array(position.count * COMPONENT_COUNT);\n const target = new Vector3();\n\n for (let i = 0; i < position.count; i++) {\n target.fromBufferAttribute(position, i);\n skinnedMesh.applyBoneTransform(i, target);\n newPositions[i * COMPONENT_COUNT + 0] = target.x;\n newPositions[i * COMPONENT_COUNT + 1] = target.y;\n newPositions[i * COMPONENT_COUNT + 2] = target.z;\n }\n\n bakedGeometry.setAttribute(\n \"position\",\n new BufferAttribute(newPositions, COMPONENT_COUNT),\n );\n bakedGeometry.computeVertexNormals();\n bakedGeometry.deleteAttribute(\"skinIndex\");\n bakedGeometry.deleteAttribute(\"skinWeight\");\n\n const mesh = new Mesh(bakedGeometry, skinnedMesh.material);\n mesh.name = skinnedMesh.name;\n return mesh;\n }\n\n /**\n * Bake a single frame from an animation into a static mesh.\n *\n * @param armature - Root object with bones (usually from GLTF)\n * @param skinnedMesh - Mesh to convert\n * @param timeOffset - Time in seconds within the animation\n * @param clip - Animation to get the pose from\n * @returns Static mesh with baked vertex positions\n */\n public static bakeAnimationFrame(\n armature: Object3D,\n skinnedMesh: SkinnedMesh,\n timeOffset: number,\n clip: AnimationClip,\n ): Mesh {\n const mixer = new AnimationMixer(armature);\n const action = mixer.clipAction(clip);\n action.play();\n mixer.setTime(timeOffset);\n\n armature.updateWorldMatrix(true, true);\n skinnedMesh.skeleton.update();\n\n return this.bakePose(skinnedMesh);\n }\n}\n","import type { MeshStandardMaterial } from \"three\";\nimport { MeshBasicMaterial } from \"three\";\n\n/**\n * Configuration options for the StandardToBasicConverter\n *\n * @interface StandardToBasicConverterOptions\n */\nexport interface StandardToBasicConverterOptions {\n /**\n * Whether to preserve the original material's name\n * @defaultValue true\n */\n preserveName: boolean;\n /**\n * Whether to copy user data from the original material\n * @defaultValue true\n */\n copyUserData: boolean;\n /**\n * Whether to dispose the original material after conversion\n * @defaultValue false\n */\n disposeOriginal: boolean;\n /**\n * Whether to apply emissive color to the base color for brightness compensation\n * @defaultValue true\n */\n combineEmissive: boolean;\n /**\n * Factor for brightness adjustment to compensate for loss of lighting\n * @defaultValue 1.3\n */\n brightnessFactor: number;\n}\n\n/**\n * Converts Three.js MeshStandardMaterial to MeshBasicMaterial\n *\n * This converter handles the translation from PBR (Physically Based Rendering)\n * StandardMaterial to the unlit BasicMaterial. Since BasicMaterial doesn't respond\n * to lighting, this converter applies various compensation techniques to maintain\n * visual similarity, including brightness adjustments and emissive color combination.\n */\nexport class StandardToBasicConverter {\n /**\n * Converts a MeshStandardMaterial to MeshBasicMaterial\n *\n * This method performs a comprehensive conversion from PBR StandardMaterial to\n * unlit BasicMaterial while attempting to preserve visual similarity through\n * brightness compensation and intelligent property mapping.\n *\n * @param standardMaterial - The source MeshStandardMaterial to convert\n * @param options - Configuration options for the conversion\n * @returns A new MeshBasicMaterial with properties mapped from the standard material\n *\n * @example\n * ```typescript\n * const standardMaterial = new MeshStandardMaterial({\n * color: 0x00ff00,\n * metalness: 0.5,\n * emissive: 0x111111,\n * emissiveIntensity: 0.2\n * });\n *\n * const basicMaterial = StandardToBasicConverter.convert(standardMaterial, {\n * brightnessFactor: 1.4,\n * combineEmissive: true\n * });\n * ```\n *\n * @see {@link StandardToBasicConverterOptions} for available configuration options\n */\n public static convert(\n standardMaterial: MeshStandardMaterial,\n options: Partial<StandardToBasicConverterOptions> = {},\n ): MeshBasicMaterial {\n const config = {\n preserveName: true,\n copyUserData: true,\n disposeOriginal: false,\n combineEmissive: true,\n brightnessFactor: 1.3,\n ...options,\n };\n\n // Create new Basic material\n const basicMaterial = new MeshBasicMaterial();\n\n // Copy basic material properties\n this.copyBasicProperties(standardMaterial, basicMaterial, config);\n\n // Handle color properties with lighting compensation\n this.convertColorProperties(standardMaterial, basicMaterial, config);\n\n // Handle texture maps\n this.convertTextureMaps(standardMaterial, basicMaterial);\n\n // Handle transparency and alpha\n this.convertTransparencyProperties(standardMaterial, basicMaterial);\n\n // Cleanup if requested\n if (config.disposeOriginal) {\n standardMaterial.dispose();\n }\n\n basicMaterial.needsUpdate = true;\n return basicMaterial;\n }\n\n /**\n * Copies basic material properties from source to target material\n *\n * Transfers common material properties including rendering settings,\n * visibility, fog interaction, wireframe settings, and user data.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshBasicMaterial\n * @param config - The resolved configuration options\n * @internal\n */\n private static copyBasicProperties(\n source: MeshStandardMaterial,\n target: MeshBasicMaterial,\n config: Required<StandardToBasicConverterOptions>,\n ): void {\n if (config.preserveName) {\n target.name = source.name;\n }\n\n target.side = source.side;\n target.visible = source.visible;\n target.fog = source.fog;\n target.wireframe = source.wireframe;\n target.wireframeLinewidth = source.wireframeLinewidth;\n target.vertexColors = source.vertexColors;\n\n if (config.copyUserData) {\n target.userData = { ...source.userData };\n }\n }\n\n /**\n * Converts color-related properties with lighting compensation\n *\n * Applies brightness compensation and optional emissive color combination\n * to account for BasicMaterial's lack of lighting response. Metallic materials\n * receive additional brightness adjustment, and colors are clamped to valid ranges.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshBasicMaterial\n * @param config - The resolved configuration options\n * @internal\n */\n private static convertColorProperties(\n source: MeshStandardMaterial,\n target: MeshBasicMaterial,\n config: Required<StandardToBasicConverterOptions>,\n ): void {\n // Base color conversion with brightness compensation\n target.color = source.color.clone();\n\n // Apply brightness compensation since BasicMaterial doesn't respond to lighting\n target.color.multiplyScalar(config.brightnessFactor);\n\n // Adjust for metalness - metallic materials tend to be darker without lighting\n if (source.metalness > 0) {\n const metalnessBrightness = 1 + source.metalness * 0.3;\n target.color.multiplyScalar(metalnessBrightness);\n }\n\n // Combine emissive color if requested\n if (config.combineEmissive) {\n const emissiveContribution = source.emissive\n .clone()\n .multiplyScalar(source.emissiveIntensity * 0.5);\n target.color.add(emissiveContribution);\n }\n\n // Ensure color doesn't exceed valid range\n target.color.r = Math.min(target.color.r, 1.0);\n target.color.g = Math.min(target.color.g, 1.0);\n target.color.b = Math.min(target.color.b, 1.0);\n }\n\n /**\n * Converts and maps texture properties from Standard to Basic material\n *\n * Handles the transfer of compatible texture maps including diffuse, alpha,\n * environment, light, and AO maps. The metalness map is repurposed as a\n * specular map for some reflective effect, and environment map reflectivity\n * is set based on the original material's metalness value.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshBasicMaterial\n * @internal\n */\n private static convertTextureMaps(\n source: MeshStandardMaterial,\n target: MeshBasicMaterial,\n ): void {\n // Main diffuse/albedo map\n if (source.map) {\n target.map = source.map;\n }\n\n // Alpha map\n if (source.alphaMap) {\n target.alphaMap = source.alphaMap;\n }\n\n // Environment map (BasicMaterial supports this for reflections)\n if (source.envMap) {\n target.envMap = source.envMap;\n // Use metalness to determine reflectivity\n target.reflectivity = source.metalness;\n }\n\n // Light map (BasicMaterial supports this)\n if (source.lightMap) {\n target.lightMap = source.lightMap;\n target.lightMapIntensity = source.lightMapIntensity;\n }\n\n // AO map (BasicMaterial supports this)\n if (source.aoMap) {\n target.aoMap = source.aoMap;\n target.aoMapIntensity = source.aoMapIntensity;\n }\n\n // Specular map (BasicMaterial supports this)\n if (source.metalnessMap) {\n // Use metalness map as specular map for some reflective effect\n target.specularMap = source.metalnessMap;\n }\n\n // Copy UV transforms\n this.copyUVTransforms(source, target);\n }\n\n /**\n * Copies UV transformation properties for texture maps\n *\n * Transfers UV offset, repeat, rotation, and center properties from the\n * source material's main texture map to the target material's map.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshBasicMaterial\n * @internal\n */\n private static copyUVTransforms(\n source: MeshStandardMaterial,\n target: MeshBasicMaterial,\n ): void {\n // Main texture UV transform\n if (source.map && target.map) {\n target.map.offset.copy(source.map.offset);\n target.map.repeat.copy(source.map.repeat);\n target.map.rotation = source.map.rotation;\n target.map.center.copy(source.map.center);\n }\n }\n\n /**\n * Converts transparency and rendering properties\n *\n * Transfers transparency, opacity, alpha testing, depth testing,\n * depth writing, and blending mode settings from source to target.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshBasicMaterial\n * @internal\n */\n private static convertTransparencyProperties(\n source: MeshStandardMaterial,\n target: MeshBasicMaterial,\n ): void {\n target.transparent = source.transparent;\n target.opacity = source.opacity;\n target.alphaTest = source.alphaTest;\n target.depthTest = source.depthTest;\n target.depthWrite = source.depthWrite;\n target.blending = source.blending;\n }\n}\n\nexport default StandardToBasicConverter;\n","import type { MeshStandardMaterial } from \"three\";\nimport { MeshLambertMaterial } from \"three\";\n\n/**\n * Configuration options for the StandardToLambertConverter\n *\n * @interface StandardToLambertConverterOptions\n */\nexport interface StandardToLambertConverterOptions {\n /**\n * Whether to preserve the original material's name\n * @defaultValue true\n */\n preserveName: boolean;\n /**\n * Whether to copy user data from the original material\n * @defaultValue true\n */\n copyUserData: boolean;\n /**\n * Whether to dispose the original material after conversion\n * @defaultValue false\n */\n disposeOriginal: boolean;\n /**\n * Custom color adjustment factor for roughness compensation\n * @defaultValue 0.8\n */\n roughnessColorFactor: number;\n}\n\n/**\n * Converts Three.js MeshStandardMaterial to MeshLambertMaterial\n *\n * This converter handles the translation between PBR (Physically Based Rendering)\n * properties of StandardMaterial and the simpler Lambertian reflectance model\n * used by LambertMaterial. The conversion preserves visual similarity by applying\n * color compensation based on metalness and roughness values.\n */\nexport class StandardToLambertConverter {\n /**\n * Converts a MeshStandardMaterial to MeshLambertMaterial\n *\n * This method performs a comprehensive conversion from PBR StandardMaterial to\n * the simpler Lambert lighting model while attempting to preserve visual similarity\n * through intelligent color compensation.\n *\n * @param material - The source MeshStandardMaterial to convert\n * @param options - Configuration options for the conversion\n * @returns A new MeshLambertMaterial with properties mapped from the standard material\n *\n * @example\n * ```typescript\n * const standardMaterial = new MeshStandardMaterial({\n * color: 0xff0000,\n * metalness: 0.8,\n * roughness: 0.2\n * });\n *\n * const lambertMaterial = StandardToLambertConverter.convert(standardMaterial);\n * ```\n *\n * @see {@link StandardToLambertConverterOptions} for available configuration options\n */\n public static convert(\n material: MeshStandardMaterial,\n options: Partial<StandardToLambertConverterOptions> = {},\n ): MeshLambertMaterial {\n const config = {\n preserveName: true,\n copyUserData: true,\n disposeOriginal: false,\n roughnessColorFactor: 0.8,\n ...options,\n };\n\n // Create new Lambert material\n const lambertMaterial = new MeshLambertMaterial();\n\n // Copy basic material properties\n this.copyBasicProperties(material, lambertMaterial, config);\n\n // Handle color properties with roughness compensation\n this.convertColorProperties(material, lambertMaterial, config);\n\n // Handle texture maps\n this.convertTextureMaps(material, lambertMaterial);\n\n // Handle transparency and alpha\n this.convertTransparencyProperties(material, lambertMaterial);\n\n // Cleanup if requested\n if (config.disposeOriginal) {\n material.dispose();\n }\n\n lambertMaterial.needsUpdate = true;\n return lambertMaterial;\n }\n\n /**\n * Copies basic material properties from source to target material\n *\n * Transfers common material properties including rendering settings,\n * visibility, fog interaction, wireframe settings, and user data.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshLambertMaterial\n * @param config - The resolved configuration options\n * @internal\n */\n private static copyBasicProperties(\n source: MeshStandardMaterial,\n target: MeshLambertMaterial,\n config: Required<StandardToLambertConverterOptions>,\n ): void {\n if (config.preserveName) {\n target.name = source.name;\n }\n\n target.side = source.side;\n target.visible = source.visible;\n target.fog = source.fog;\n target.wireframe = source.wireframe;\n target.wireframeLinewidth = source.wireframeLinewidth;\n target.vertexColors = source.vertexColors;\n target.flatShading = source.flatShading;\n\n if (config.copyUserData) {\n target.userData = { ...source.userData };\n }\n }\n\n /**\n * Converts color-related properties with PBR compensation\n *\n * Applies intelligent color adjustments to compensate for the loss of\n * metalness and roughness information when converting to Lambert material.\n * Metallic materials are darkened and rough materials receive additional\n * darkening based on the roughnessColorFactor.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshLambertMaterial\n * @param config - The resolved configuration options\n * @internal\n */\n private static convertColorProperties(\n source: MeshStandardMaterial,\n target: MeshLambertMaterial,\n config: Required<StandardToLambertConverterOptions>,\n ): void {\n target.color = source.color.clone();\n\n // Adjust color based on metalness and roughness for better visual match\n if (source.metalness > 0) {\n // Metallic materials tend to be darker in Lambert shading\n const metalnessFactor = 1 - source.metalness * 0.3;\n target.color.multiplyScalar(metalnessFactor);\n }\n\n if (source.roughness > 0.5) {\n // Rough materials appear slightly darker\n const roughnessFactor =\n config.roughnessColorFactor + source.roughness * 0.2;\n target.color.multiplyScalar(roughnessFactor);\n }\n\n target.emissive = source.emissive.clone();\n target.emissiveIntensity = source.emissiveIntensity;\n }\n\n /**\n * Converts and maps texture properties from Standard to Lambert material\n *\n * Handles the transfer of compatible texture maps including diffuse, normal,\n * emissive, AO, light maps, and environment maps. The environment map\n * reflectivity is set based on the original material's metalness value.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshLambertMaterial\n * @internal\n */\n private static convertTextureMaps(\n source: MeshStandardMaterial,\n target: MeshLambertMaterial,\n ): void {\n // Diffuse/Albedo map\n if (source.map) {\n target.map = source.map;\n }\n\n // Emissive map\n if (source.emissiveMap) {\n target.emissiveMap = source.emissiveMap;\n }\n\n // Normal map (Lambert materials support normal mapping)\n if (source.normalMap) {\n target.normalMap = source.normalMap;\n target.normalScale = source.normalScale.clone();\n }\n\n // Light map\n if (source.lightMap) {\n target.lightMap = source.lightMap;\n target.lightMapIntensity = source.lightMapIntensity;\n }\n\n // AO map\n if (source.aoMap) {\n target.aoMap = source.aoMap;\n target.aoMapIntensity = source.aoMapIntensity;\n }\n\n // Environment map (for reflections)\n if (source.envMap) {\n target.envMap = source.envMap;\n target.reflectivity = Math.min(source.metalness + 0.1, 1.0);\n }\n\n // Alpha map\n if (source.alphaMap) {\n target.alphaMap = source.alphaMap;\n }\n\n // Copy UV transforms\n this.copyUVTransforms(source, target);\n }\n\n /**\n * Copies UV transformation properties for texture maps\n *\n * Transfers UV offset, repeat, rotation, and center properties from the\n * source material's main texture map to the target material's map.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshLambertMaterial\n * @internal\n */\n private static copyUVTransforms(\n source: MeshStandardMaterial,\n target: MeshLambertMaterial,\n ): void {\n // Main texture UV transform\n if (source.map && target.map) {\n target.map.offset.copy(source.map.offset);\n target.map.repeat.copy(source.map.repeat);\n target.map.rotation = source.map.rotation;\n target.map.center.copy(source.map.center);\n }\n }\n\n /**\n * Converts transparency and rendering properties\n *\n * Transfers transparency, opacity, alpha testing, depth testing,\n * depth writing, and blending mode settings from source to target.\n *\n * @param source - The source MeshStandardMaterial\n * @param target - The target MeshLambertMaterial\n * @internal\n */\n private static convertTransparencyProperties(\n source: MeshStandardMaterial,\n target: MeshLambertMaterial,\n ): void {\n target.transparent = source.transparent;\n target.opacity = source.opacity;\n target.alphaTest = source.alphaTest;\n target.depthTest = source.depthTest;\n target.depthWrite = source.depthWrite;\n target.blending = source.blending;\n }\n}\n","import type { Texture } from \"three\";\nimport { Box3, DirectionalLight, RGBAFormat, Spherical, Vector3 } from \"three\";\n\n/** Number of color channels in RGBA format */\nconst RGBA_CHANNEL_COUNT = 4;\n/** Number of color channels in RGB format */\nconst RGB_CHANNEL_COUNT = 3;\n\n/** Red channel weight for luminance calculation (ITU-R BT.709) */\nconst LUMINANCE_R = 0.2126;\n/** Green channel weight for luminance calculation (ITU-R BT.709) */\nconst LUMINANCE_G = 0.7152;\n/** Blue channel weight for luminance calculation (ITU-R BT.709) */\nconst LUMINANCE_B = 0.0722;\n\n/**\n * A directional light with spherical positioning controls and advanced shadow mapping.\n *\n * Extends Three.js DirectionalLight to provide intuitive spherical coordinate control\n * (distance, elevation, azimuth) and automatic shadow map configuration for bounding boxes.\n * Also supports automatic sun direction calculation from HDR environment maps.\n */\nexport class Sun extends DirectionalLight {\n /** Internal vectors to avoid garbage collection during calculations */\n private readonly tempVector3D0 = new Vector3();\n private readonly tempVector3D1 = new Vector3();\n private readonly tempVector3D2 = new Vector3();\n private readonly tempVector3D3 = new Vector3();\n private readonly tempVector3D4 = new Vector3();\n private readonly tempVector3D5 = new Vector3();\n private readonly tempVector3D6 = new Vector3();\n private readonly tempVector3D7 = new Vector3();\n private readonly tempBox3 = new Box3();\n private readonly tempSpherical = new Spherical();\n\n /**\n * Gets the distance from the light to its target (origin).\n *\n * @returns The distance in world units\n */\n public get distance(): number {\n return this.position.length();\n }\n\n /**\n * Gets the elevation angle (vertical angle from the horizontal plane).\n *\n * @returns The elevation angle in radians (0 = horizontal, π/2 = directly above)\n */\n public get elevation(): number {\n return this.tempSpherical.setFromVector3(this.position).phi;\n }\n\n /**\n * Gets the azimuth angle (horizontal rotation around the target).\n *\n * @returns The azimuth angle in radians (0 = positive X axis, π/2 = positive Z axis)\n */\n public get azimuth(): number {\n return this.tempSpherical.setFromVector3(this.position).theta;\n }\n\n /**\n * Sets the distance while preserving current elevation and azimuth angles.\n *\n * @param value - The new distance in world units\n */\n public set distance(value: number) {\n this.tempSpherical.setFromVector3(this.position);\n this.position.setFromSphericalCoords(\n value,\n this.tempSpherical.phi,\n this.tempSpherical.theta,\n );\n }\n\n /**\n * Sets the elevation angle while preserving current distance and azimuth.\n *\n * @param value - The new elevation angle in radians (0 = horizontal, π/2 = directly above)\n */\n public set elevation(value: number) {\n this.tempSpherical.setFromVector3(this.position);\n this.position.setFromSphericalCoords(\n this.tempSpherical.radius,\n value,\n this.tempSpherical.theta,\n );\n }\n\n /**\n * Sets the azimuth angle while preserving current distance and elevation.\n *\n * @param value - The new azimuth angle in radians (0 = positive X axis, π/2 = positive Z axis)\n */\n public set azimuth(value: number) {\n this.tempSpherical.setFromVector3(this.position);\n this.position.setFromSphericalCoords(\n this.tempSpherical.radius,\n this.tempSpherical.phi,\n value,\n );\n }\n\n /**\n * Configures the shadow camera to optimally cover a bounding box.\n *\n * This method automatically adjusts the directional light's shadow camera frustum\n * to perfectly encompass the provided bounding box, ensuring efficient shadow map\n * usage and eliminating shadow clipping issues.\n *\n * @param box3 - The 3D bounding box to cover with shadows\n */\n public configureShadowsForBoundingBox(box3: Box3): void {\n const camera = this.shadow.camera;\n\n this.target.updateWorldMatrix(true, false);\n this.lookAt(this.target.getWorldPosition(this.tempVector3D0));\n\n this.updateWorldMatrix(true, false);\n\n const points: Vector3[] = [\n this.tempVector3D0.set(box3.min.x, box3.min.y, box3.min.z),\n this.tempVector3D1.set(box3.min.x, box3.min.y, box3.max.z),\n this.tempVector3D2.set(box3.min.x, box3.max.y, box3.min.z),\n this.tempVector3D3.set(box3.min.x, box3.max.y, box3.max.z),\n this.tempVector3D4.set(box3.max.x, box3.min.y, box3.min.z),\n this.tempVector3D5.set(box3.max.x, box3.min.y, box3.max.z),\n this.tempVector3D6.set(box3.max.x, box3.max.y, box3.min.z),\n this.tempVector3D7.set(box3.max.x, box3.max.y, box3.max.z),\n ];\n\n const inverseMatrix = this.matrixWorld.clone().invert();\n\n for (const point of points) {\n point.applyMatrix4(inverseMatrix);\n }\n\n const newBox3 = this.tempBox3.setFromPoints(points);\n\n camera.left = newBox3.min.x;\n camera.bottom = newBox3.min.y;\n camera.near = -newBox3.max.z;\n\n camera.right = newBox3.max.x;\n camera.top = newBox3.max.y;\n camera.far = -newBox3.min.z;\n\n camera.updateWorldMatrix(true, false);\n camera.updateProjectionMatrix();\n }\n\n /**\n * Sets the sun's direction based on the brightest point in an HDR environment map.\n *\n * This method analyzes an HDR texture to find the pixel with the highest luminance\n * value and positions the sun to shine from that direction. This is useful for\n * creating realistic lighting that matches HDR environment maps.\n *\n * @param texture - The HDR texture to analyze (must have image data available)\n * @param distance - The distance to place the sun from the origin (defaults to 1)\n */\n public setDirectionFromHDRTexture(texture: Texture, distance = 1): void {\n const data = texture.image.data;\n const width = texture.image.width;\n const height = texture.image.height;\n\n let maxLuminance = 0;\n let maxIndex = 0;\n\n // Find brightest pixel\n\n const step =\n texture.format === RGBAFormat ? RGBA_CHANNEL_COUNT : RGB_CHANNEL_COUNT;\n for (let i = 0; i < data.length; i += step) {\n const r = data[i];\n const g = data[i + 1];\n const b = data[i + 2];\n const luminance = LUMINANCE_R * r + LUMINANCE_G * g + LUMINANCE_B * b;\n if (luminance > maxLuminance) {\n maxLuminance = luminance;\n maxIndex = i;\n }\n }\n\n // Convert to spherical coordinates\n const pixelIndex = maxIndex / step;\n const x = pixelIndex % width;\n const y = Math.floor(pixelIndex / width);\n\n const u = x / width;\n const v = y / height;\n\n const elevation = v * Math.PI;\n const azimuth = u * -Math.PI * 2 - Math.PI / 2;\n\n this.position.setFromSphericalCoords(distance, elevation, azimuth);\n }\n}\n"],"names":["MAX_FOV","DualFovCamera","PerspectiveCamera","constructor","horizontalFov","verticalFov","aspect","near","far","super","this","_private_horizontalFovInternal","_private_verticalFovInternal","updateProjectionMatrix","value","MathUtils","clamp","setFov","horizontal","vertical","copyFovSettings","source","radians","degToRad","fov","radToDeg","Math","atan","tan","getActualHorizontalFov","verticalRadians","getActualVerticalFov","horizontalRadians","fitVerticalFovToPoints","vertices","up","Vector3","applyQuaternion","quaternion","maxVerticalAngle","vertex","vertexDirection","position","clone","sub","normalize","verticalAngle","asin","abs","dot","sign","requiredFov","fitVerticalFovToBox","box","min","x","y","z","max","fitVerticalFovToMesh","skinnedMesh","updateWorldMatrix","skeleton","update","geometry","attributes","target","points","i","count","fromBufferAttribute","applyBoneTransform","push","lookAtMeshCenterOfMass","centerOfMass","iterations","length","center","floor","total","point","distanceTo","add","divideScalar","findMainCluster","lookAt","camera","copy","SceneTraversal","getObjectByName","object","name","child","children","result","getMaterialByName","Mesh","Array","isArray","material","enumerateObjectsByType","type","callback","enumerateMaterials","filterObjects","filter","test","concat","filterMaterials","findMaterialUsers","materialName","hasMatchingMaterial","SkinnedMeshBaker","bakePose","bakedGeometry","newPositions","Float32Array","setAttribute","BufferAttribute","computeVertexNormals","deleteAttribute","mesh","bakeAnimationFrame","armature","timeOffset","clip","mixer","AnimationMixer","clipAction","play","setTime","StandardToBasicConverter","convert","standardMaterial","options","config","preserveName","copyUserData","disposeOriginal","combineEmissive","brightnessFactor","basicMaterial","MeshBasicMaterial","copyBasicProperties","convertColorProperties","convertTextureMaps","convertTransparencyProperties","dispose","needsUpdate","side","visible","fog","wireframe","wireframeLinewidth","vertexColors","userData","color","multiplyScalar","metalness","emissiveContribution","emissive","emissiveIntensity","r","g","b","map","alphaMap","envMap","reflectivity","lightMap","lightMapIntensity","aoMap","aoMapIntensity","metalnessMap","specularMap","copyUVTransforms","offset","repeat","rotation","transparent","opacity","alphaTest","depthTest","depthWrite","blending","StandardToLambertConverter","roughnessColorFactor","lambertMaterial","MeshLambertMaterial","flatShading","roughness","emissiveMap","normalMap","normalScale","Sun","DirectionalLight","Box3","Spherical","distance","elevation","_private_tempSpherical","setFromVector3","phi","azimuth","theta","setFromSphericalCoords","radius","configureShadowsForBoundingBox","box3","shadow","getWorldPosition","_private_tempVector3D0","set","_private_tempVector3D1","_private_tempVector3D2","_private_tempVector3D3","_private_tempVector3D4","_private_tempVector3D5","_private_tempVector3D6","_private_tempVector3D7","inverseMatrix","matrixWorld","invert","applyMatrix4","newBox3","_private_tempBox3","setFromPoints","left","bottom","right","top","setDirectionFromHDRTexture","texture","data","image","width","height","maxLuminance","maxIndex","step","format","RGBAFormat","luminance","pixelIndex","PI"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-zoo",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "description": "Some reusable bits for building things with Three.js ",
5
5
  "scripts": {
6
6
  "clean": "rm -rf dist",