three-zoo 0.0.1
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/LICENSE +21 -0
- package/dist/InstanceAssembler.d.ts +9 -0
- package/dist/InstanceAssembler.js +39 -0
- package/dist/InstanceAssembler.js.map +1 -0
- package/dist/Object3DToolbox.d.ts +21 -0
- package/dist/Object3DToolbox.js +118 -0
- package/dist/Object3DToolbox.js.map +1 -0
- package/dist/SceneProcessor.d.ts +13 -0
- package/dist/SceneProcessor.js +25 -0
- package/dist/SceneProcessor.js.map +1 -0
- package/dist/Sun.d.ts +21 -0
- package/dist/Sun.js +96 -0
- package/dist/Sun.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/package.json +32 -0
- package/src/InstanceAssembler.ts +56 -0
- package/src/Object3DToolbox.ts +152 -0
- package/src/SceneProcessor.ts +49 -0
- package/src/Sun.ts +137 -0
- package/src/index.ts +4 -0
- package/tsconfig.json +21 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Jango
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { InstancedMesh, Material, Mesh } from "three";
|
|
2
|
+
export class InstanceAssembler {
|
|
3
|
+
static assemble(options) {
|
|
4
|
+
var _a;
|
|
5
|
+
const dictionary = new Map();
|
|
6
|
+
const instancedMeshes = [];
|
|
7
|
+
options.container.traverse((child) => {
|
|
8
|
+
var _a;
|
|
9
|
+
if (child instanceof Mesh &&
|
|
10
|
+
child.material instanceof Material &&
|
|
11
|
+
child.children.length === 0 &&
|
|
12
|
+
(!options.filter || options.filter(child))) {
|
|
13
|
+
const entry = (_a = dictionary.get(child.geometry)) !== null && _a !== void 0 ? _a : [];
|
|
14
|
+
dictionary.set(child.geometry, entry);
|
|
15
|
+
entry.push(child);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
for (const [geometry, meshes] of dictionary) {
|
|
19
|
+
if (meshes.length < 2)
|
|
20
|
+
continue;
|
|
21
|
+
const sortedMeshes = meshes.sort((a, b) => a.name.localeCompare(b.name));
|
|
22
|
+
const defaultMesh = sortedMeshes[0];
|
|
23
|
+
const instancedMesh = new InstancedMesh(geometry, defaultMesh.material, sortedMeshes.length);
|
|
24
|
+
instancedMesh.name = defaultMesh.name;
|
|
25
|
+
for (let i = 0; i < sortedMeshes.length; i++) {
|
|
26
|
+
const mesh = sortedMeshes[i];
|
|
27
|
+
mesh.updateMatrix();
|
|
28
|
+
mesh.updateMatrixWorld(true);
|
|
29
|
+
instancedMesh.setMatrixAt(i, mesh.matrixWorld);
|
|
30
|
+
}
|
|
31
|
+
instancedMeshes.push(instancedMesh);
|
|
32
|
+
for (const mesh of sortedMeshes) {
|
|
33
|
+
(_a = mesh.parent) === null || _a === void 0 ? void 0 : _a.remove(mesh);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
options.container.add(...instancedMeshes);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=InstanceAssembler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InstanceAssembler.js","sourceRoot":"","sources":["../src/InstanceAssembler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,aAAa,EAAE,QAAQ,EAAE,IAAI,EAAY,MAAM,OAAO,CAAC;AAOhF,MAAM,OAAO,iBAAiB;IACrB,MAAM,CAAC,QAAQ,CAAC,OAAiB;;QACtC,MAAM,UAAU,GAAG,IAAI,GAAG,EAA0B,CAAC;QACrD,MAAM,eAAe,GAAoB,EAAE,CAAC;QAE5C,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,KAAe,EAAE,EAAE;;YAC7C,IACE,KAAK,YAAY,IAAI;gBACrB,KAAK,CAAC,QAAQ,YAAY,QAAQ;gBAClC,KAAK,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;gBAC3B,CAAC,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAC1C,CAAC;gBACD,MAAM,KAAK,GAAG,MAAA,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,mCAAI,EAAE,CAAC;gBACnD,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;gBACtC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,KAAK,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;YAC5C,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;gBAAE,SAAS;YAEhC,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YACzE,MAAM,WAAW,GAAG,YAAY,CAAC,CAAC,CAAS,CAAC;YAE5C,MAAM,aAAa,GAAG,IAAI,aAAa,CACrC,QAAQ,EACR,WAAW,CAAC,QAAQ,EACpB,YAAY,CAAC,MAAM,CACpB,CAAC;YAEF,aAAa,CAAC,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC;YAEtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC7C,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAS,CAAC;gBACrC,IAAI,CAAC,YAAY,EAAE,CAAC;gBACpB,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBAC7B,aAAa,CAAC,WAAW,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;YACjD,CAAC;YAED,eAAe,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAEpC,KAAK,MAAM,IAAI,IAAI,YAAY,EAAE,CAAC;gBAChC,MAAA,IAAI,CAAC,MAAM,0CAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;QAED,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,eAAe,CAAC,CAAC;IAC5C,CAAC;CACF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Box3, Material, Object3D, Vector3 } from "three";
|
|
2
|
+
export declare class Object3DToolbox {
|
|
3
|
+
private static tempBox3;
|
|
4
|
+
private static tempVector3;
|
|
5
|
+
static getObjectByName(object: Object3D, name: string): Object3D | null;
|
|
6
|
+
static getMaterialByName(object: Object3D, name: string): Material | null;
|
|
7
|
+
static enumerateObjectsByType<T>(object: Object3D, type: new (...args: any[]) => T, callback: (instance: T) => void): void;
|
|
8
|
+
static enumerateMaterials(object: Object3D, callback: (material: Material) => void): void;
|
|
9
|
+
static calculateBounds(object: Object3D): {
|
|
10
|
+
readonly box: Box3;
|
|
11
|
+
readonly center: Vector3;
|
|
12
|
+
readonly size: Vector3;
|
|
13
|
+
readonly width: number;
|
|
14
|
+
readonly height: number;
|
|
15
|
+
readonly depth: number;
|
|
16
|
+
readonly localWidth: number;
|
|
17
|
+
readonly localHeight: number;
|
|
18
|
+
readonly localDepth: number;
|
|
19
|
+
};
|
|
20
|
+
static setShadowRecursive(object: Object3D, castShadow?: boolean, receiveShadow?: boolean): void;
|
|
21
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Box3, Mesh, Vector3 } from "three";
|
|
2
|
+
export class Object3DToolbox {
|
|
3
|
+
static getObjectByName(object, name) {
|
|
4
|
+
if (object.name === name)
|
|
5
|
+
return object;
|
|
6
|
+
for (const child of object.children) {
|
|
7
|
+
const result = Object3DToolbox.getObjectByName(child, name);
|
|
8
|
+
if (result)
|
|
9
|
+
return result;
|
|
10
|
+
}
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
static getMaterialByName(object, name) {
|
|
14
|
+
if (object instanceof Mesh) {
|
|
15
|
+
if (Array.isArray(object.material)) {
|
|
16
|
+
for (const material of object.material) {
|
|
17
|
+
if (material.name === name)
|
|
18
|
+
return material;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
else if (object.material.name === name) {
|
|
22
|
+
return object.material;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
for (const child of object.children) {
|
|
26
|
+
const material = Object3DToolbox.getMaterialByName(child, name);
|
|
27
|
+
if (material)
|
|
28
|
+
return material;
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
static enumerateObjectsByType(object, type, callback) {
|
|
33
|
+
if (object instanceof type) {
|
|
34
|
+
callback(object);
|
|
35
|
+
}
|
|
36
|
+
for (const child of object.children) {
|
|
37
|
+
Object3DToolbox.enumerateObjectsByType(child, type, callback);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
static enumerateMaterials(object, callback) {
|
|
41
|
+
if (object instanceof Mesh) {
|
|
42
|
+
if (Array.isArray(object.material)) {
|
|
43
|
+
for (const material of object.material) {
|
|
44
|
+
callback(material);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
callback(object.material);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
for (const child of object.children) {
|
|
52
|
+
Object3DToolbox.enumerateMaterials(child, callback);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
static calculateBounds(object) {
|
|
56
|
+
Object3DToolbox.tempBox3.setFromObject(object);
|
|
57
|
+
return {
|
|
58
|
+
get box() {
|
|
59
|
+
return Object3DToolbox.tempBox3.clone();
|
|
60
|
+
},
|
|
61
|
+
get center() {
|
|
62
|
+
return Object3DToolbox.tempBox3
|
|
63
|
+
.getCenter(Object3DToolbox.tempVector3)
|
|
64
|
+
.clone();
|
|
65
|
+
},
|
|
66
|
+
get size() {
|
|
67
|
+
return Object3DToolbox.tempBox3
|
|
68
|
+
.getSize(Object3DToolbox.tempVector3)
|
|
69
|
+
.clone();
|
|
70
|
+
},
|
|
71
|
+
get width() {
|
|
72
|
+
return Object3DToolbox.tempBox3.max.x - Object3DToolbox.tempBox3.min.x;
|
|
73
|
+
},
|
|
74
|
+
get height() {
|
|
75
|
+
return Object3DToolbox.tempBox3.max.y - Object3DToolbox.tempBox3.min.y;
|
|
76
|
+
},
|
|
77
|
+
get depth() {
|
|
78
|
+
return Object3DToolbox.tempBox3.max.z - Object3DToolbox.tempBox3.min.z;
|
|
79
|
+
},
|
|
80
|
+
get localWidth() {
|
|
81
|
+
const worldWidth = Object3DToolbox.tempBox3.max.x - Object3DToolbox.tempBox3.min.x;
|
|
82
|
+
if (!object.parent)
|
|
83
|
+
return worldWidth;
|
|
84
|
+
object.parent.getWorldScale(Object3DToolbox.tempVector3);
|
|
85
|
+
return worldWidth / Object3DToolbox.tempVector3.x;
|
|
86
|
+
},
|
|
87
|
+
get localHeight() {
|
|
88
|
+
const worldHeight = Object3DToolbox.tempBox3.max.y - Object3DToolbox.tempBox3.min.y;
|
|
89
|
+
if (!object.parent)
|
|
90
|
+
return worldHeight;
|
|
91
|
+
object.parent.getWorldScale(Object3DToolbox.tempVector3);
|
|
92
|
+
return worldHeight / Object3DToolbox.tempVector3.y;
|
|
93
|
+
},
|
|
94
|
+
get localDepth() {
|
|
95
|
+
const worldDepth = Object3DToolbox.tempBox3.max.z - Object3DToolbox.tempBox3.min.z;
|
|
96
|
+
if (!object.parent)
|
|
97
|
+
return worldDepth;
|
|
98
|
+
object.parent.getWorldScale(Object3DToolbox.tempVector3);
|
|
99
|
+
return worldDepth / Object3DToolbox.tempVector3.z;
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
static setShadowRecursive(object, castShadow = true, receiveShadow = true) {
|
|
104
|
+
if ("isMesh" in object) {
|
|
105
|
+
object.castShadow = castShadow;
|
|
106
|
+
object.receiveShadow = receiveShadow;
|
|
107
|
+
}
|
|
108
|
+
object.traverse((child) => {
|
|
109
|
+
if ("isMesh" in child) {
|
|
110
|
+
child.castShadow = castShadow;
|
|
111
|
+
child.receiveShadow = receiveShadow;
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
Object3DToolbox.tempBox3 = new Box3();
|
|
117
|
+
Object3DToolbox.tempVector3 = new Vector3();
|
|
118
|
+
//# sourceMappingURL=Object3DToolbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Object3DToolbox.js","sourceRoot":"","sources":["../src/Object3DToolbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Object3D } from "three";
|
|
2
|
+
type IPattern = string | RegExp;
|
|
3
|
+
interface IOptions {
|
|
4
|
+
asset: Object3D;
|
|
5
|
+
castShadowNames?: IPattern[];
|
|
6
|
+
receiveShadowNames?: IPattern[];
|
|
7
|
+
transparentMaterialNames?: IPattern[];
|
|
8
|
+
}
|
|
9
|
+
export declare class SceneProcessor {
|
|
10
|
+
static process(options: IOptions): Object3D[];
|
|
11
|
+
private static matchesAny;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { FrontSide, Mesh } from "three";
|
|
2
|
+
import { InstanceAssembler } from "./InstanceAssembler";
|
|
3
|
+
import { Object3DToolbox } from "./Object3DToolbox";
|
|
4
|
+
export class SceneProcessor {
|
|
5
|
+
static process(options) {
|
|
6
|
+
const container = options.asset.clone();
|
|
7
|
+
InstanceAssembler.assemble({ container: container });
|
|
8
|
+
Object3DToolbox.enumerateMaterials(container, (material) => {
|
|
9
|
+
material.transparent = SceneProcessor.matchesAny(material.name, options.transparentMaterialNames);
|
|
10
|
+
material.side = FrontSide;
|
|
11
|
+
material.forceSinglePass = true;
|
|
12
|
+
material.depthTest = true;
|
|
13
|
+
material.depthWrite = true;
|
|
14
|
+
});
|
|
15
|
+
Object3DToolbox.enumerateObjectsByType(container, Mesh, (child) => {
|
|
16
|
+
child.castShadow = SceneProcessor.matchesAny(child.name, options.castShadowNames);
|
|
17
|
+
child.receiveShadow = SceneProcessor.matchesAny(child.name, options.receiveShadowNames);
|
|
18
|
+
});
|
|
19
|
+
return container.children;
|
|
20
|
+
}
|
|
21
|
+
static matchesAny(value, patterns = []) {
|
|
22
|
+
return patterns.some((p) => typeof p === "string" ? value === p : p.test(value));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=SceneProcessor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SceneProcessor.js","sourceRoot":"","sources":["../src/SceneProcessor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAY,IAAI,EAAY,MAAM,OAAO,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAWpD,MAAM,OAAO,cAAc;IAClB,MAAM,CAAC,OAAO,CAAC,OAAiB;QACrC,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACxC,iBAAiB,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;QAErD,eAAe,CAAC,kBAAkB,CAAC,SAAS,EAAE,CAAC,QAAkB,EAAE,EAAE;YACnE,QAAQ,CAAC,WAAW,GAAG,cAAc,CAAC,UAAU,CAC9C,QAAQ,CAAC,IAAI,EACb,OAAO,CAAC,wBAAwB,CACjC,CAAC;YACF,QAAQ,CAAC,IAAI,GAAG,SAAS,CAAC;YAC1B,QAAQ,CAAC,eAAe,GAAG,IAAI,CAAC;YAChC,QAAQ,CAAC,SAAS,GAAG,IAAI,CAAC;YAC1B,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,eAAe,CAAC,sBAAsB,CAAC,SAAS,EAAE,IAAI,EAAE,CAAC,KAAW,EAAE,EAAE;YACtE,KAAK,CAAC,UAAU,GAAG,cAAc,CAAC,UAAU,CAC1C,KAAK,CAAC,IAAI,EACV,OAAO,CAAC,eAAe,CACxB,CAAC;YACF,KAAK,CAAC,aAAa,GAAG,cAAc,CAAC,UAAU,CAC7C,KAAK,CAAC,IAAI,EACV,OAAO,CAAC,kBAAkB,CAC3B,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,OAAO,SAAS,CAAC,QAAQ,CAAC;IAC5B,CAAC;IAEO,MAAM,CAAC,UAAU,CAAC,KAAa,EAAE,WAAuB,EAAE;QAChE,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CACzB,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CACpD,CAAC;IACJ,CAAC;CACF"}
|
package/dist/Sun.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Box3, DirectionalLight, Texture } from "three";
|
|
2
|
+
export declare class Sun extends DirectionalLight {
|
|
3
|
+
private tempVector3D_0;
|
|
4
|
+
private tempVector3D_1;
|
|
5
|
+
private tempVector3D_2;
|
|
6
|
+
private tempVector3D_3;
|
|
7
|
+
private tempVector3D_4;
|
|
8
|
+
private tempVector3D_5;
|
|
9
|
+
private tempVector3D_6;
|
|
10
|
+
private tempVector3D_7;
|
|
11
|
+
private tempBox3;
|
|
12
|
+
private tempSpherical;
|
|
13
|
+
setShadowMapFromBox3(box3: Box3): void;
|
|
14
|
+
setDirectionFromHDR(texture: Texture, distance?: number): void;
|
|
15
|
+
get distance(): number;
|
|
16
|
+
set distance(value: number);
|
|
17
|
+
get elevation(): number;
|
|
18
|
+
set elevation(value: number);
|
|
19
|
+
get azimuth(): number;
|
|
20
|
+
set azimuth(value: number);
|
|
21
|
+
}
|
package/dist/Sun.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { AxesHelper, Box3, DirectionalLight, RGBAFormat, Spherical, Vector3, } from "three";
|
|
2
|
+
export class Sun extends DirectionalLight {
|
|
3
|
+
constructor() {
|
|
4
|
+
super(...arguments);
|
|
5
|
+
this.tempVector3D_0 = new Vector3();
|
|
6
|
+
this.tempVector3D_1 = new Vector3();
|
|
7
|
+
this.tempVector3D_2 = new Vector3();
|
|
8
|
+
this.tempVector3D_3 = new Vector3();
|
|
9
|
+
this.tempVector3D_4 = new Vector3();
|
|
10
|
+
this.tempVector3D_5 = new Vector3();
|
|
11
|
+
this.tempVector3D_6 = new Vector3();
|
|
12
|
+
this.tempVector3D_7 = new Vector3();
|
|
13
|
+
this.tempBox3 = new Box3();
|
|
14
|
+
this.tempSpherical = new Spherical();
|
|
15
|
+
}
|
|
16
|
+
setShadowMapFromBox3(box3) {
|
|
17
|
+
const camera = this.shadow.camera;
|
|
18
|
+
this.target.updateWorldMatrix(true, false);
|
|
19
|
+
this.lookAt(this.target.getWorldPosition(this.tempVector3D_0));
|
|
20
|
+
this.updateWorldMatrix(true, false);
|
|
21
|
+
const points = [
|
|
22
|
+
this.tempVector3D_0.set(box3.min.x, box3.min.y, box3.min.z),
|
|
23
|
+
this.tempVector3D_1.set(box3.min.x, box3.min.y, box3.max.z),
|
|
24
|
+
this.tempVector3D_2.set(box3.min.x, box3.max.y, box3.min.z),
|
|
25
|
+
this.tempVector3D_3.set(box3.min.x, box3.max.y, box3.max.z),
|
|
26
|
+
this.tempVector3D_4.set(box3.max.x, box3.min.y, box3.min.z),
|
|
27
|
+
this.tempVector3D_5.set(box3.max.x, box3.min.y, box3.max.z),
|
|
28
|
+
this.tempVector3D_6.set(box3.max.x, box3.max.y, box3.min.z),
|
|
29
|
+
this.tempVector3D_7.set(box3.max.x, box3.max.y, box3.max.z),
|
|
30
|
+
];
|
|
31
|
+
const inverseMatrix = this.matrixWorld.clone().invert();
|
|
32
|
+
for (const point of points) {
|
|
33
|
+
point.applyMatrix4(inverseMatrix);
|
|
34
|
+
const axesHelper = new AxesHelper(1);
|
|
35
|
+
axesHelper.position.copy(point);
|
|
36
|
+
this.add(axesHelper);
|
|
37
|
+
}
|
|
38
|
+
const newBox3 = this.tempBox3.setFromPoints(points);
|
|
39
|
+
camera.left = newBox3.min.x;
|
|
40
|
+
camera.bottom = newBox3.min.y;
|
|
41
|
+
camera.near = -newBox3.max.z;
|
|
42
|
+
camera.right = newBox3.max.x;
|
|
43
|
+
camera.top = newBox3.max.y;
|
|
44
|
+
camera.far = -newBox3.min.z;
|
|
45
|
+
camera.updateWorldMatrix(true, false);
|
|
46
|
+
camera.updateProjectionMatrix();
|
|
47
|
+
}
|
|
48
|
+
setDirectionFromHDR(texture, distance = 1) {
|
|
49
|
+
const data = texture.image.data;
|
|
50
|
+
const width = texture.image.width;
|
|
51
|
+
const height = texture.image.height;
|
|
52
|
+
let maxLuminance = 0;
|
|
53
|
+
let maxIndex = 0;
|
|
54
|
+
const step = texture.format === RGBAFormat ? 4 : 3;
|
|
55
|
+
for (let i = 0; i < data.length; i += step) {
|
|
56
|
+
const r = data[i];
|
|
57
|
+
const g = data[i + 1];
|
|
58
|
+
const b = data[i + 2];
|
|
59
|
+
const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
60
|
+
if (luminance > maxLuminance) {
|
|
61
|
+
maxLuminance = luminance;
|
|
62
|
+
maxIndex = i;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const pixelIndex = maxIndex / step;
|
|
66
|
+
const x = pixelIndex % width;
|
|
67
|
+
const y = Math.floor(pixelIndex / width);
|
|
68
|
+
const u = x / width;
|
|
69
|
+
const v = y / height;
|
|
70
|
+
const elevation = v * Math.PI;
|
|
71
|
+
const azimuth = u * -Math.PI * 2 - Math.PI / 2;
|
|
72
|
+
this.position.setFromSphericalCoords(distance, elevation, azimuth);
|
|
73
|
+
}
|
|
74
|
+
get distance() {
|
|
75
|
+
return this.position.length();
|
|
76
|
+
}
|
|
77
|
+
set distance(value) {
|
|
78
|
+
this.tempSpherical.setFromVector3(this.position);
|
|
79
|
+
this.position.setFromSphericalCoords(value, this.tempSpherical.phi, this.tempSpherical.theta);
|
|
80
|
+
}
|
|
81
|
+
get elevation() {
|
|
82
|
+
return this.tempSpherical.setFromVector3(this.position).phi;
|
|
83
|
+
}
|
|
84
|
+
set elevation(value) {
|
|
85
|
+
this.tempSpherical.setFromVector3(this.position);
|
|
86
|
+
this.position.setFromSphericalCoords(this.tempSpherical.radius, value, this.tempSpherical.theta);
|
|
87
|
+
}
|
|
88
|
+
get azimuth() {
|
|
89
|
+
return this.tempSpherical.setFromVector3(this.position).theta;
|
|
90
|
+
}
|
|
91
|
+
set azimuth(value) {
|
|
92
|
+
this.tempSpherical.setFromVector3(this.position);
|
|
93
|
+
this.position.setFromSphericalCoords(this.tempSpherical.radius, this.tempSpherical.phi, value);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=Sun.js.map
|
package/dist/Sun.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Sun.js","sourceRoot":"","sources":["../src/Sun.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,OAAO,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "three-zoo",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "zoo of tiny three js tools",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [],
|
|
17
|
+
"author": "jango",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "https://github.com/jango-git/three-zoo.git"
|
|
22
|
+
},
|
|
23
|
+
"type": "module",
|
|
24
|
+
"dependencies": {},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"three": "^0.176.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/three": "^0.176.0",
|
|
30
|
+
"typescript": "^5.8.3"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { BufferGeometry, InstancedMesh, Material, Mesh, Object3D } from "three";
|
|
2
|
+
|
|
3
|
+
interface IOptions {
|
|
4
|
+
container: Object3D;
|
|
5
|
+
filter?: (child: Object3D) => boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class InstanceAssembler {
|
|
9
|
+
public static assemble(options: IOptions): void {
|
|
10
|
+
const dictionary = new Map<BufferGeometry, Mesh[]>();
|
|
11
|
+
const instancedMeshes: InstancedMesh[] = [];
|
|
12
|
+
|
|
13
|
+
options.container.traverse((child: Object3D) => {
|
|
14
|
+
if (
|
|
15
|
+
child instanceof Mesh &&
|
|
16
|
+
child.material instanceof Material &&
|
|
17
|
+
child.children.length === 0 &&
|
|
18
|
+
(!options.filter || options.filter(child))
|
|
19
|
+
) {
|
|
20
|
+
const entry = dictionary.get(child.geometry) ?? [];
|
|
21
|
+
dictionary.set(child.geometry, entry);
|
|
22
|
+
entry.push(child);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
for (const [geometry, meshes] of dictionary) {
|
|
27
|
+
if (meshes.length < 2) continue;
|
|
28
|
+
|
|
29
|
+
const sortedMeshes = meshes.sort((a, b) => a.name.localeCompare(b.name));
|
|
30
|
+
const defaultMesh = sortedMeshes[0] as Mesh;
|
|
31
|
+
|
|
32
|
+
const instancedMesh = new InstancedMesh(
|
|
33
|
+
geometry,
|
|
34
|
+
defaultMesh.material,
|
|
35
|
+
sortedMeshes.length,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
instancedMesh.name = defaultMesh.name;
|
|
39
|
+
|
|
40
|
+
for (let i = 0; i < sortedMeshes.length; i++) {
|
|
41
|
+
const mesh = sortedMeshes[i] as Mesh;
|
|
42
|
+
mesh.updateMatrix();
|
|
43
|
+
mesh.updateMatrixWorld(true);
|
|
44
|
+
instancedMesh.setMatrixAt(i, mesh.matrixWorld);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
instancedMeshes.push(instancedMesh);
|
|
48
|
+
|
|
49
|
+
for (const mesh of sortedMeshes) {
|
|
50
|
+
mesh.parent?.remove(mesh);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
options.container.add(...instancedMeshes);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { Box3, Material, Mesh, Object3D, Vector3 } from "three";
|
|
2
|
+
|
|
3
|
+
export class Object3DToolbox {
|
|
4
|
+
private static tempBox3 = new Box3();
|
|
5
|
+
private static tempVector3 = new Vector3();
|
|
6
|
+
|
|
7
|
+
public static getObjectByName(
|
|
8
|
+
object: Object3D,
|
|
9
|
+
name: string,
|
|
10
|
+
): Object3D | null {
|
|
11
|
+
if (object.name === name) return object;
|
|
12
|
+
|
|
13
|
+
for (const child of object.children) {
|
|
14
|
+
const result = Object3DToolbox.getObjectByName(child, name);
|
|
15
|
+
if (result) return result;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public static getMaterialByName(
|
|
22
|
+
object: Object3D,
|
|
23
|
+
name: string,
|
|
24
|
+
): Material | null {
|
|
25
|
+
if (object instanceof Mesh) {
|
|
26
|
+
if (Array.isArray(object.material)) {
|
|
27
|
+
for (const material of object.material) {
|
|
28
|
+
if (material.name === name) return material;
|
|
29
|
+
}
|
|
30
|
+
} else if (object.material.name === name) {
|
|
31
|
+
return object.material;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
for (const child of object.children) {
|
|
36
|
+
const material = Object3DToolbox.getMaterialByName(child, name);
|
|
37
|
+
if (material) return material;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public static enumerateObjectsByType<T>(
|
|
44
|
+
object: Object3D,
|
|
45
|
+
type: new (...args: any[]) => T,
|
|
46
|
+
callback: (instance: T) => void,
|
|
47
|
+
): void {
|
|
48
|
+
if (object instanceof type) {
|
|
49
|
+
callback(object);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
for (const child of object.children) {
|
|
53
|
+
Object3DToolbox.enumerateObjectsByType(child, type, callback);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public static enumerateMaterials(
|
|
58
|
+
object: Object3D,
|
|
59
|
+
callback: (material: Material) => void,
|
|
60
|
+
): void {
|
|
61
|
+
if (object instanceof Mesh) {
|
|
62
|
+
if (Array.isArray(object.material)) {
|
|
63
|
+
for (const material of object.material) {
|
|
64
|
+
callback(material);
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
callback(object.material);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
for (const child of object.children) {
|
|
72
|
+
Object3DToolbox.enumerateMaterials(child, callback);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public static calculateBounds(object: Object3D) {
|
|
77
|
+
Object3DToolbox.tempBox3.setFromObject(object);
|
|
78
|
+
return {
|
|
79
|
+
get box() {
|
|
80
|
+
return Object3DToolbox.tempBox3.clone();
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
get center() {
|
|
84
|
+
return Object3DToolbox.tempBox3
|
|
85
|
+
.getCenter(Object3DToolbox.tempVector3)
|
|
86
|
+
.clone();
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
get size() {
|
|
90
|
+
return Object3DToolbox.tempBox3
|
|
91
|
+
.getSize(Object3DToolbox.tempVector3)
|
|
92
|
+
.clone();
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
get width() {
|
|
96
|
+
return Object3DToolbox.tempBox3.max.x - Object3DToolbox.tempBox3.min.x;
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
get height() {
|
|
100
|
+
return Object3DToolbox.tempBox3.max.y - Object3DToolbox.tempBox3.min.y;
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
get depth() {
|
|
104
|
+
return Object3DToolbox.tempBox3.max.z - Object3DToolbox.tempBox3.min.z;
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
get localWidth() {
|
|
108
|
+
const worldWidth =
|
|
109
|
+
Object3DToolbox.tempBox3.max.x - Object3DToolbox.tempBox3.min.x;
|
|
110
|
+
if (!object.parent) return worldWidth;
|
|
111
|
+
|
|
112
|
+
object.parent.getWorldScale(Object3DToolbox.tempVector3);
|
|
113
|
+
return worldWidth / Object3DToolbox.tempVector3.x;
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
get localHeight() {
|
|
117
|
+
const worldHeight =
|
|
118
|
+
Object3DToolbox.tempBox3.max.y - Object3DToolbox.tempBox3.min.y;
|
|
119
|
+
if (!object.parent) return worldHeight;
|
|
120
|
+
|
|
121
|
+
object.parent.getWorldScale(Object3DToolbox.tempVector3);
|
|
122
|
+
return worldHeight / Object3DToolbox.tempVector3.y;
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
get localDepth() {
|
|
126
|
+
const worldDepth =
|
|
127
|
+
Object3DToolbox.tempBox3.max.z - Object3DToolbox.tempBox3.min.z;
|
|
128
|
+
if (!object.parent) return worldDepth;
|
|
129
|
+
|
|
130
|
+
object.parent.getWorldScale(Object3DToolbox.tempVector3);
|
|
131
|
+
return worldDepth / Object3DToolbox.tempVector3.z;
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public static setShadowRecursive(
|
|
137
|
+
object: Object3D,
|
|
138
|
+
castShadow = true,
|
|
139
|
+
receiveShadow = true,
|
|
140
|
+
) {
|
|
141
|
+
if ("isMesh" in object) {
|
|
142
|
+
(object as Mesh).castShadow = castShadow;
|
|
143
|
+
(object as Mesh).receiveShadow = receiveShadow;
|
|
144
|
+
}
|
|
145
|
+
object.traverse((child) => {
|
|
146
|
+
if ("isMesh" in child) {
|
|
147
|
+
(child as Mesh).castShadow = castShadow;
|
|
148
|
+
(child as Mesh).receiveShadow = receiveShadow;
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { FrontSide, Material, Mesh, Object3D } from "three";
|
|
2
|
+
import { InstanceAssembler } from "./InstanceAssembler";
|
|
3
|
+
import { Object3DToolbox } from "./Object3DToolbox";
|
|
4
|
+
|
|
5
|
+
type IPattern = string | RegExp;
|
|
6
|
+
|
|
7
|
+
interface IOptions {
|
|
8
|
+
asset: Object3D;
|
|
9
|
+
castShadowNames?: IPattern[];
|
|
10
|
+
receiveShadowNames?: IPattern[];
|
|
11
|
+
transparentMaterialNames?: IPattern[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class SceneProcessor {
|
|
15
|
+
public static process(options: IOptions): Object3D[] {
|
|
16
|
+
const container = options.asset.clone();
|
|
17
|
+
InstanceAssembler.assemble({ container: container });
|
|
18
|
+
|
|
19
|
+
Object3DToolbox.enumerateMaterials(container, (material: Material) => {
|
|
20
|
+
material.transparent = SceneProcessor.matchesAny(
|
|
21
|
+
material.name,
|
|
22
|
+
options.transparentMaterialNames,
|
|
23
|
+
);
|
|
24
|
+
material.side = FrontSide;
|
|
25
|
+
material.forceSinglePass = true;
|
|
26
|
+
material.depthTest = true;
|
|
27
|
+
material.depthWrite = true;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
Object3DToolbox.enumerateObjectsByType(container, Mesh, (child: Mesh) => {
|
|
31
|
+
child.castShadow = SceneProcessor.matchesAny(
|
|
32
|
+
child.name,
|
|
33
|
+
options.castShadowNames,
|
|
34
|
+
);
|
|
35
|
+
child.receiveShadow = SceneProcessor.matchesAny(
|
|
36
|
+
child.name,
|
|
37
|
+
options.receiveShadowNames,
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return container.children;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private static matchesAny(value: string, patterns: IPattern[] = []): boolean {
|
|
45
|
+
return patterns.some((p) =>
|
|
46
|
+
typeof p === "string" ? value === p : p.test(value),
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
package/src/Sun.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AxesHelper,
|
|
3
|
+
Box3,
|
|
4
|
+
DirectionalLight,
|
|
5
|
+
RGBAFormat,
|
|
6
|
+
Spherical,
|
|
7
|
+
Texture,
|
|
8
|
+
Vector3,
|
|
9
|
+
} from "three";
|
|
10
|
+
|
|
11
|
+
export class Sun extends DirectionalLight {
|
|
12
|
+
private tempVector3D_0 = new Vector3();
|
|
13
|
+
private tempVector3D_1 = new Vector3();
|
|
14
|
+
private tempVector3D_2 = new Vector3();
|
|
15
|
+
private tempVector3D_3 = new Vector3();
|
|
16
|
+
private tempVector3D_4 = new Vector3();
|
|
17
|
+
private tempVector3D_5 = new Vector3();
|
|
18
|
+
private tempVector3D_6 = new Vector3();
|
|
19
|
+
private tempVector3D_7 = new Vector3();
|
|
20
|
+
|
|
21
|
+
private tempBox3 = new Box3();
|
|
22
|
+
private tempSpherical = new Spherical();
|
|
23
|
+
|
|
24
|
+
public setShadowMapFromBox3(box3: Box3): void {
|
|
25
|
+
const camera = this.shadow.camera;
|
|
26
|
+
|
|
27
|
+
this.target.updateWorldMatrix(true, false);
|
|
28
|
+
this.lookAt(this.target.getWorldPosition(this.tempVector3D_0));
|
|
29
|
+
|
|
30
|
+
this.updateWorldMatrix(true, false);
|
|
31
|
+
|
|
32
|
+
const points: Vector3[] = [
|
|
33
|
+
this.tempVector3D_0.set(box3.min.x, box3.min.y, box3.min.z),
|
|
34
|
+
this.tempVector3D_1.set(box3.min.x, box3.min.y, box3.max.z),
|
|
35
|
+
this.tempVector3D_2.set(box3.min.x, box3.max.y, box3.min.z),
|
|
36
|
+
this.tempVector3D_3.set(box3.min.x, box3.max.y, box3.max.z),
|
|
37
|
+
this.tempVector3D_4.set(box3.max.x, box3.min.y, box3.min.z),
|
|
38
|
+
this.tempVector3D_5.set(box3.max.x, box3.min.y, box3.max.z),
|
|
39
|
+
this.tempVector3D_6.set(box3.max.x, box3.max.y, box3.min.z),
|
|
40
|
+
this.tempVector3D_7.set(box3.max.x, box3.max.y, box3.max.z),
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
const inverseMatrix = this.matrixWorld.clone().invert();
|
|
44
|
+
|
|
45
|
+
for (const point of points) {
|
|
46
|
+
point.applyMatrix4(inverseMatrix);
|
|
47
|
+
const axesHelper = new AxesHelper(1);
|
|
48
|
+
axesHelper.position.copy(point);
|
|
49
|
+
this.add(axesHelper);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const newBox3 = this.tempBox3.setFromPoints(points);
|
|
53
|
+
|
|
54
|
+
camera.left = newBox3.min.x;
|
|
55
|
+
camera.bottom = newBox3.min.y;
|
|
56
|
+
camera.near = -newBox3.max.z;
|
|
57
|
+
|
|
58
|
+
camera.right = newBox3.max.x;
|
|
59
|
+
camera.top = newBox3.max.y;
|
|
60
|
+
camera.far = -newBox3.min.z;
|
|
61
|
+
|
|
62
|
+
camera.updateWorldMatrix(true, false);
|
|
63
|
+
camera.updateProjectionMatrix();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public setDirectionFromHDR(texture: Texture, distance: number = 1) {
|
|
67
|
+
const data = texture.image.data;
|
|
68
|
+
const width = texture.image.width;
|
|
69
|
+
const height = texture.image.height;
|
|
70
|
+
|
|
71
|
+
let maxLuminance = 0;
|
|
72
|
+
let maxIndex = 0;
|
|
73
|
+
|
|
74
|
+
const step = texture.format === RGBAFormat ? 4 : 3;
|
|
75
|
+
for (let i = 0; i < data.length; i += step) {
|
|
76
|
+
const r = data[i];
|
|
77
|
+
const g = data[i + 1];
|
|
78
|
+
const b = data[i + 2];
|
|
79
|
+
const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
80
|
+
if (luminance > maxLuminance) {
|
|
81
|
+
maxLuminance = luminance;
|
|
82
|
+
maxIndex = i;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const pixelIndex = maxIndex / step;
|
|
87
|
+
const x = pixelIndex % width;
|
|
88
|
+
const y = Math.floor(pixelIndex / width);
|
|
89
|
+
|
|
90
|
+
const u = x / width;
|
|
91
|
+
const v = y / height;
|
|
92
|
+
|
|
93
|
+
const elevation = v * Math.PI;
|
|
94
|
+
const azimuth = u * -Math.PI * 2 - Math.PI / 2;
|
|
95
|
+
|
|
96
|
+
this.position.setFromSphericalCoords(distance, elevation, azimuth);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public get distance() {
|
|
100
|
+
return this.position.length();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
public set distance(value: number) {
|
|
104
|
+
this.tempSpherical.setFromVector3(this.position);
|
|
105
|
+
this.position.setFromSphericalCoords(
|
|
106
|
+
value,
|
|
107
|
+
this.tempSpherical.phi,
|
|
108
|
+
this.tempSpherical.theta,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
public get elevation() {
|
|
113
|
+
return this.tempSpherical.setFromVector3(this.position).phi;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
public set elevation(value) {
|
|
117
|
+
this.tempSpherical.setFromVector3(this.position);
|
|
118
|
+
this.position.setFromSphericalCoords(
|
|
119
|
+
this.tempSpherical.radius,
|
|
120
|
+
value,
|
|
121
|
+
this.tempSpherical.theta,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
public get azimuth() {
|
|
126
|
+
return this.tempSpherical.setFromVector3(this.position).theta;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public set azimuth(value) {
|
|
130
|
+
this.tempSpherical.setFromVector3(this.position);
|
|
131
|
+
this.position.setFromSphericalCoords(
|
|
132
|
+
this.tempSpherical.radius,
|
|
133
|
+
this.tempSpherical.phi,
|
|
134
|
+
value,
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
}
|
package/src/index.ts
ADDED
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES6",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "Bundler",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"noImplicitAny": true,
|
|
8
|
+
"strictNullChecks": true,
|
|
9
|
+
"strictFunctionTypes": true,
|
|
10
|
+
"strictBindCallApply": true,
|
|
11
|
+
"noImplicitThis": true,
|
|
12
|
+
"alwaysStrict": true,
|
|
13
|
+
"esModuleInterop": true,
|
|
14
|
+
"forceConsistentCasingInFileNames": true,
|
|
15
|
+
"skipLibCheck": false,
|
|
16
|
+
"outDir": "./dist",
|
|
17
|
+
"declaration": true,
|
|
18
|
+
"sourceMap": true
|
|
19
|
+
},
|
|
20
|
+
"include": ["src/**/*"]
|
|
21
|
+
}
|