three-base 2.0.25 → 2.0.27
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/InstancedGroupMesh.d.ts +5 -4
- package/InstancedGroupMesh.js +23 -8
- package/InstancedGroupMesh.ts +35 -20
- package/MeshBase.d.ts +17 -2
- package/MeshBase.js +151 -9
- package/MeshBase.ts +180 -10
- package/PlaneText.d.ts +3 -3
- package/ThreeBase.js +1 -3
- package/ThreeBase.ts +1 -4
- package/ThreeMouse.d.ts +1 -1
- package/ThreeMouse.js +3 -3
- package/ThreeMouse.ts +3 -3
- package/Transition.js +3 -1
- package/Transition.ts +3 -1
- package/package.json +1 -1
- package/threeLoader.d.ts +3 -1
- package/threeLoader.js +32 -1
- package/threeLoader.ts +33 -1
- package/threeUtils.d.ts +1 -0
- package/threeUtils.js +13 -0
- package/threeUtils.ts +15 -1
package/InstancedGroupMesh.d.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { Group, InstancedMesh, Matrix4, Mesh
|
|
1
|
+
import { Color, Group, InstancedMesh, Matrix4, Mesh } from 'three';
|
|
2
2
|
export default class InstancedGroupMesh extends Mesh {
|
|
3
|
-
|
|
3
|
+
children: InstancedMesh[];
|
|
4
4
|
isInstancedGroupMesh: boolean;
|
|
5
5
|
count: number;
|
|
6
|
-
size: Vector3;
|
|
7
6
|
meshCollect: Record<string, Mesh[]>;
|
|
8
7
|
instanceCollect: Record<string, InstancedMesh>;
|
|
9
|
-
children: InstancedMesh[];
|
|
10
8
|
static matrix: Matrix4;
|
|
11
9
|
constructor(group: Group, count: number);
|
|
12
10
|
computeBoundingSphere: import("lodash").DebouncedFunc<() => void>;
|
|
13
11
|
setMatrixAt(index: number, matrix: Matrix4): void;
|
|
14
12
|
setColorAt(index: number, color: (instancedMesh: InstancedMesh) => Color | undefined): void;
|
|
13
|
+
updateMatrixWorld(force?: boolean): void;
|
|
14
|
+
addEventListener(name: string, callback: (e: any) => void): void;
|
|
15
|
+
removeEventListener(name: string, callback: (e: any) => void): void;
|
|
15
16
|
}
|
package/InstancedGroupMesh.js
CHANGED
|
@@ -2,29 +2,26 @@
|
|
|
2
2
|
* @Author: xiaosihan
|
|
3
3
|
* @Date: 2023-02-21 09:55:52
|
|
4
4
|
* @Last Modified by: xiaosihan
|
|
5
|
-
* @Last Modified time: 2024-01-
|
|
5
|
+
* @Last Modified time: 2024-01-27 17:41:26
|
|
6
6
|
*/
|
|
7
7
|
import { throttle } from 'lodash';
|
|
8
|
-
import { InstancedMesh, Matrix4, Mesh
|
|
9
|
-
import threeUtils from './threeUtils';
|
|
8
|
+
import { InstancedMesh, Matrix4, Mesh } from 'three';
|
|
10
9
|
// 模型组转成 实例对象
|
|
11
10
|
export default class InstancedGroupMesh extends Mesh {
|
|
12
|
-
url = "";
|
|
13
11
|
isInstancedGroupMesh = true;
|
|
14
12
|
count = 0;
|
|
15
|
-
size = new Vector3(1, 1, 1);
|
|
16
13
|
meshCollect = {};
|
|
17
14
|
instanceCollect = {};
|
|
18
15
|
static matrix = new Matrix4();
|
|
19
16
|
constructor(group, count) {
|
|
20
17
|
super();
|
|
21
|
-
this.size.copy(threeUtils.getSize(group));
|
|
22
18
|
this.count = count;
|
|
23
19
|
const { meshCollect, instanceCollect } = this;
|
|
24
20
|
group.updateMatrixWorld(true);
|
|
25
21
|
// collect all mesh counts, in case there are more than one copy of the same mesh in this group
|
|
26
22
|
group.traverse((obj) => {
|
|
27
23
|
const mesh = obj;
|
|
24
|
+
obj.userData = this.userData;
|
|
28
25
|
if (mesh.isMesh) {
|
|
29
26
|
mesh.matrixWorld.decompose(mesh.position, mesh.quaternion, mesh.scale);
|
|
30
27
|
mesh.rotation.setFromQuaternion(mesh.quaternion);
|
|
@@ -49,8 +46,6 @@ export default class InstancedGroupMesh extends Mesh {
|
|
|
49
46
|
const meshes = meshCollect[uuid];
|
|
50
47
|
const mesh = meshes[0];
|
|
51
48
|
const instancedMesh = new InstancedMesh(mesh.geometry, mesh.material, meshes.length * count);
|
|
52
|
-
instancedMesh.name = mesh.name;
|
|
53
|
-
instancedMesh.frustumCulled = false;
|
|
54
49
|
instanceCollect[uuid] = instancedMesh;
|
|
55
50
|
this.add(instancedMesh);
|
|
56
51
|
});
|
|
@@ -88,4 +83,24 @@ export default class InstancedGroupMesh extends Mesh {
|
|
|
88
83
|
});
|
|
89
84
|
});
|
|
90
85
|
}
|
|
86
|
+
// 同步属性
|
|
87
|
+
updateMatrixWorld(force) {
|
|
88
|
+
super.updateMatrixWorld(force);
|
|
89
|
+
const { cursor, enableEvent } = this.userData;
|
|
90
|
+
this.traverse(obj => {
|
|
91
|
+
Object.assign(obj.userData, { cursor, enableEvent });
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
// 事件监听
|
|
95
|
+
addEventListener(name, callback) {
|
|
96
|
+
this.children.map(mesh => {
|
|
97
|
+
mesh.addEventListener(name, callback);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
// 取消事件的监听
|
|
101
|
+
removeEventListener(name, callback) {
|
|
102
|
+
this.children.map(mesh => {
|
|
103
|
+
mesh.removeEventListener(name, callback);
|
|
104
|
+
});
|
|
105
|
+
}
|
|
91
106
|
}
|
package/InstancedGroupMesh.ts
CHANGED
|
@@ -2,37 +2,29 @@
|
|
|
2
2
|
* @Author: xiaosihan
|
|
3
3
|
* @Date: 2023-02-21 09:55:52
|
|
4
4
|
* @Last Modified by: xiaosihan
|
|
5
|
-
* @Last Modified time: 2024-01-
|
|
5
|
+
* @Last Modified time: 2024-01-27 17:41:26
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { throttle } from 'lodash';
|
|
9
|
-
import { Group, InstancedMesh, Material, Matrix4, Mesh
|
|
10
|
-
import threeUtils from './threeUtils';
|
|
9
|
+
import { Color, Group, InstancedMesh, Material, Matrix4, Mesh } from 'three';
|
|
11
10
|
|
|
12
11
|
// 模型组转成 实例对象
|
|
13
12
|
export default class InstancedGroupMesh extends Mesh {
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
declare children: InstancedMesh[];
|
|
16
15
|
|
|
17
16
|
isInstancedGroupMesh = true
|
|
18
17
|
|
|
19
|
-
count: number = 0
|
|
20
|
-
|
|
21
|
-
size = new Vector3(1, 1, 1);
|
|
18
|
+
count: number = 0;
|
|
22
19
|
|
|
23
20
|
meshCollect: Record<string, Mesh[]> = {}
|
|
24
21
|
|
|
25
22
|
instanceCollect: Record<string, InstancedMesh> = {}
|
|
26
23
|
|
|
27
|
-
declare children: InstancedMesh[];
|
|
28
|
-
|
|
29
24
|
static matrix = new Matrix4()
|
|
30
25
|
|
|
31
26
|
constructor(group: Group, count: number) {
|
|
32
27
|
super()
|
|
33
|
-
|
|
34
|
-
this.size.copy(threeUtils.getSize(group));
|
|
35
|
-
|
|
36
28
|
this.count = count
|
|
37
29
|
|
|
38
30
|
const { meshCollect, instanceCollect } = this
|
|
@@ -41,7 +33,10 @@ export default class InstancedGroupMesh extends Mesh {
|
|
|
41
33
|
|
|
42
34
|
// collect all mesh counts, in case there are more than one copy of the same mesh in this group
|
|
43
35
|
group.traverse((obj) => {
|
|
44
|
-
const mesh = obj as Mesh
|
|
36
|
+
const mesh = obj as Mesh;
|
|
37
|
+
|
|
38
|
+
obj.userData = this.userData;
|
|
39
|
+
|
|
45
40
|
if (mesh.isMesh) {
|
|
46
41
|
|
|
47
42
|
mesh.matrixWorld.decompose(mesh.position, mesh.quaternion, mesh.scale);
|
|
@@ -68,15 +63,13 @@ export default class InstancedGroupMesh extends Mesh {
|
|
|
68
63
|
Object.keys(meshCollect).forEach(uuid => {
|
|
69
64
|
const meshes = meshCollect[uuid]
|
|
70
65
|
const mesh = meshes[0]
|
|
66
|
+
|
|
71
67
|
const instancedMesh = new InstancedMesh(mesh.geometry, mesh.material, meshes.length * count)
|
|
72
|
-
|
|
73
|
-
instancedMesh.frustumCulled = false;
|
|
74
|
-
instanceCollect[uuid] = instancedMesh
|
|
68
|
+
instanceCollect[uuid] = instancedMesh;
|
|
75
69
|
this.add(instancedMesh)
|
|
76
70
|
})
|
|
77
71
|
}
|
|
78
72
|
|
|
79
|
-
|
|
80
73
|
// 更新包围盒
|
|
81
74
|
computeBoundingSphere = throttle(() => {
|
|
82
75
|
this.traverse(m => {
|
|
@@ -91,12 +84,10 @@ export default class InstancedGroupMesh extends Mesh {
|
|
|
91
84
|
collect.forEach((mesh: Mesh, i: number) => {
|
|
92
85
|
InstancedGroupMesh.matrix.copy(mesh.matrix)
|
|
93
86
|
InstancedGroupMesh.matrix.premultiply(matrix)
|
|
94
|
-
|
|
95
87
|
instancedMesh.setMatrixAt(collect.length * index + i, InstancedGroupMesh.matrix);
|
|
96
88
|
instancedMesh.instanceMatrix.needsUpdate = true;
|
|
97
89
|
})
|
|
98
90
|
})
|
|
99
|
-
|
|
100
91
|
this.computeBoundingSphere();
|
|
101
92
|
}
|
|
102
93
|
|
|
@@ -115,4 +106,28 @@ export default class InstancedGroupMesh extends Mesh {
|
|
|
115
106
|
})
|
|
116
107
|
}
|
|
117
108
|
|
|
118
|
-
|
|
109
|
+
// 同步属性
|
|
110
|
+
updateMatrixWorld(force?: boolean): void {
|
|
111
|
+
super.updateMatrixWorld(force);
|
|
112
|
+
const { cursor, enableEvent } = this.userData;
|
|
113
|
+
this.traverse(obj => {
|
|
114
|
+
Object.assign(obj.userData, { cursor, enableEvent });
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// 事件监听
|
|
119
|
+
addEventListener(name: string, callback: (e: any) => void) {
|
|
120
|
+
this.children.map(mesh => {
|
|
121
|
+
mesh.addEventListener(name, callback);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 取消事件的监听
|
|
126
|
+
removeEventListener(name: string, callback: (e: any) => void) {
|
|
127
|
+
this.children.map(mesh => {
|
|
128
|
+
mesh.removeEventListener(name, callback);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
}
|
|
133
|
+
|
package/MeshBase.d.ts
CHANGED
|
@@ -1,4 +1,19 @@
|
|
|
1
|
-
import { Group } from "three";
|
|
1
|
+
import { Group, Mesh, Object3D, Vector3 } from "three";
|
|
2
2
|
export default class MeshBase extends Group {
|
|
3
|
-
constructor();
|
|
3
|
+
constructor(url?: string);
|
|
4
|
+
static models: Map<string, Object3D>;
|
|
5
|
+
static loadModeling: Map<string, boolean>;
|
|
6
|
+
loaded: boolean;
|
|
7
|
+
loadModel(url: string): Promise<void>;
|
|
8
|
+
frustumCulled: boolean;
|
|
9
|
+
castShadow: boolean;
|
|
10
|
+
receiveShadow: boolean;
|
|
11
|
+
traverseMesh(callback: (mesh: Mesh) => void): Promise<void>;
|
|
12
|
+
updateMatrix(): void;
|
|
13
|
+
applyAllTranstion(): void;
|
|
14
|
+
getSize(): Vector3;
|
|
15
|
+
center(): void;
|
|
16
|
+
alignBottom(y?: number): void;
|
|
17
|
+
scaleTo(size?: number, key?: Array<"x" | "y" | "z">): void;
|
|
18
|
+
expandBynormal(length: number): void;
|
|
4
19
|
}
|
package/MeshBase.js
CHANGED
|
@@ -1,13 +1,155 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* @Last Modified time: 2024-02-05 09:40:17
|
|
6
|
-
*/
|
|
7
|
-
import { Group } from "three";
|
|
8
|
-
// 基础模型加载对象
|
|
1
|
+
import { DoubleSide, Group, Object3D, Vector3 } from "three";
|
|
2
|
+
import threeUtils from "./threeUtils";
|
|
3
|
+
import threeLoader from "./threeLoader";
|
|
4
|
+
// 模型基类
|
|
9
5
|
export default class MeshBase extends Group {
|
|
10
|
-
constructor() {
|
|
6
|
+
constructor(url) {
|
|
11
7
|
super();
|
|
8
|
+
url && this.loadModel(url);
|
|
9
|
+
}
|
|
10
|
+
// 模型对象
|
|
11
|
+
static models = new Map();
|
|
12
|
+
// 模型是否在加载中
|
|
13
|
+
static loadModeling = new Map();
|
|
14
|
+
// 加载完成
|
|
15
|
+
loaded = false;
|
|
16
|
+
async loadModel(url) {
|
|
17
|
+
if (!url) {
|
|
18
|
+
this.clear();
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
this.loaded = false;
|
|
22
|
+
// 没有模型并且没有加载任务时就去加载模型
|
|
23
|
+
if (!MeshBase.models.get(url) && !MeshBase.loadModeling.get(url)) {
|
|
24
|
+
MeshBase.loadModeling.set(url, true);
|
|
25
|
+
let modal = new Object3D();
|
|
26
|
+
if (/\.fbx$/i.test(url)) {
|
|
27
|
+
await threeLoader.fbxLoader.loadAsync(url).then(res => {
|
|
28
|
+
modal = res;
|
|
29
|
+
}).catch(() => {
|
|
30
|
+
console.error(`${url},加载失败`);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
else if (/\.(gltf|glb)$/i.test(url)) {
|
|
34
|
+
await threeLoader.gltfLoader.loadAsync(url).then(res => {
|
|
35
|
+
modal = res.scene;
|
|
36
|
+
}).catch(() => {
|
|
37
|
+
console.error(`${url},加载失败`);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
console.error(`${url},不支持的格式`);
|
|
42
|
+
}
|
|
43
|
+
threeUtils.center(modal);
|
|
44
|
+
threeUtils.alignBottom(modal);
|
|
45
|
+
modal.updateMatrixWorld(true);
|
|
46
|
+
// 应用全部变换
|
|
47
|
+
modal.traverse(obj => {
|
|
48
|
+
const mesh = obj;
|
|
49
|
+
mesh.position.set(0, 0, 0);
|
|
50
|
+
mesh.rotation.set(0, 0, 0);
|
|
51
|
+
mesh.scale.set(1, 1, 1);
|
|
52
|
+
if (mesh.isMesh) {
|
|
53
|
+
mesh.geometry.applyMatrix4(mesh.matrixWorld);
|
|
54
|
+
mesh.material.side = DoubleSide;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
MeshBase.models.set(url, modal);
|
|
58
|
+
MeshBase.loadModeling.set(url, false);
|
|
59
|
+
}
|
|
60
|
+
// 如果模型还在加载中, 就等待模型加载完成
|
|
61
|
+
do {
|
|
62
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
63
|
+
} while (MeshBase.loadModeling.get(url));
|
|
64
|
+
if (MeshBase.models.get(url)) {
|
|
65
|
+
const mesh = MeshBase.models.get(url).clone();
|
|
66
|
+
this.clear();
|
|
67
|
+
this.add(mesh);
|
|
68
|
+
this.applyAllTranstion();
|
|
69
|
+
}
|
|
70
|
+
await new Promise(resolve => requestAnimationFrame(resolve));
|
|
71
|
+
// 加载完成事件
|
|
72
|
+
this.dispatchEvent({ type: "loaded" });
|
|
73
|
+
this.loaded = true;
|
|
74
|
+
}
|
|
75
|
+
// 超出绘制区域时不绘制
|
|
76
|
+
frustumCulled = false;
|
|
77
|
+
// 创建阴影
|
|
78
|
+
castShadow = false;
|
|
79
|
+
// 接受阴影
|
|
80
|
+
receiveShadow = false;
|
|
81
|
+
//遍历模型
|
|
82
|
+
async traverseMesh(callback) {
|
|
83
|
+
while (!this.loaded) {
|
|
84
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
85
|
+
}
|
|
86
|
+
this.traverse(obj => {
|
|
87
|
+
const mesh = obj;
|
|
88
|
+
if (mesh.isMesh) {
|
|
89
|
+
callback(mesh);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
updateMatrix() {
|
|
94
|
+
// 深度应用属性
|
|
95
|
+
this.traverse(obj => {
|
|
96
|
+
const mesh = obj;
|
|
97
|
+
if (mesh.isMesh) {
|
|
98
|
+
mesh.frustumCulled = this.frustumCulled;
|
|
99
|
+
mesh.castShadow = this.castShadow;
|
|
100
|
+
mesh.receiveShadow = this.receiveShadow;
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
super.updateMatrix();
|
|
104
|
+
}
|
|
105
|
+
// 应用全部变化
|
|
106
|
+
applyAllTranstion() {
|
|
107
|
+
this.updateMatrixWorld(true);
|
|
108
|
+
// 应用全部变换
|
|
109
|
+
this.traverse(obj => {
|
|
110
|
+
const mesh = obj;
|
|
111
|
+
mesh.position.set(0, 0, 0);
|
|
112
|
+
mesh.rotation.set(0, 0, 0);
|
|
113
|
+
mesh.scale.set(1, 1, 1);
|
|
114
|
+
if (mesh.isMesh) {
|
|
115
|
+
mesh.geometry.applyMatrix4(mesh.matrixWorld);
|
|
116
|
+
mesh.material.side = DoubleSide;
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
// 获取模型的尺寸
|
|
121
|
+
getSize() {
|
|
122
|
+
return threeUtils.getSize(this);
|
|
123
|
+
}
|
|
124
|
+
// 居中
|
|
125
|
+
center() {
|
|
126
|
+
threeUtils.center(this);
|
|
127
|
+
}
|
|
128
|
+
//底对齐
|
|
129
|
+
alignBottom(y = 0) {
|
|
130
|
+
threeUtils.alignBottom(this, y);
|
|
131
|
+
}
|
|
132
|
+
// 放大到指定尺寸
|
|
133
|
+
scaleTo(size = 1, key = ["x", "y", "z"]) {
|
|
134
|
+
threeUtils.scaleTo(this, size, key);
|
|
135
|
+
}
|
|
136
|
+
//按照法线拓展
|
|
137
|
+
expandBynormal(length) {
|
|
138
|
+
this.traverseMesh(mesh => {
|
|
139
|
+
// 没有法线就计算法线
|
|
140
|
+
mesh.geometry = mesh.geometry.clone();
|
|
141
|
+
if (!mesh.geometry.getAttribute("normal")) {
|
|
142
|
+
mesh.geometry.computeVertexNormals();
|
|
143
|
+
}
|
|
144
|
+
const normal = mesh.geometry.getAttribute("normal");
|
|
145
|
+
const position = mesh.geometry.getAttribute("position");
|
|
146
|
+
const v3 = new Vector3(0, 0, 0);
|
|
147
|
+
for (let i = 0; i < position.count; i++) {
|
|
148
|
+
v3.set(normal.getX(i), normal.getY(i), normal.getZ(i));
|
|
149
|
+
v3.setLength(length);
|
|
150
|
+
position.setXYZ(i, position.getX(i) + v3.x, position.getY(i) + v3.y, position.getZ(i) + v3.z);
|
|
151
|
+
}
|
|
152
|
+
position.needsUpdate = true;
|
|
153
|
+
});
|
|
12
154
|
}
|
|
13
155
|
}
|
package/MeshBase.ts
CHANGED
|
@@ -1,19 +1,189 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @Author: xiaosihan
|
|
3
|
-
* @Date: 2024-01-29 10:08:40
|
|
4
|
-
* @Last Modified by: xiaosihan
|
|
5
|
-
* @Last Modified time: 2024-02-05 09:40:17
|
|
6
|
-
*/
|
|
7
1
|
|
|
8
|
-
import { Group } from "three";
|
|
2
|
+
import { DoubleSide, Group, Mesh, MeshStandardMaterial, Object3D, Vector3 } from "three";
|
|
3
|
+
import threeUtils from "./threeUtils";
|
|
4
|
+
import threeLoader from "./threeLoader";
|
|
9
5
|
|
|
10
|
-
//
|
|
6
|
+
// 模型基类
|
|
11
7
|
export default class MeshBase extends Group {
|
|
12
|
-
|
|
13
|
-
constructor() {
|
|
8
|
+
constructor(url?: string) {
|
|
14
9
|
super();
|
|
10
|
+
url && this.loadModel(url);
|
|
15
11
|
}
|
|
16
12
|
|
|
13
|
+
// 模型对象
|
|
14
|
+
static models: Map<string, Object3D> = new Map();
|
|
15
|
+
|
|
16
|
+
// 模型是否在加载中
|
|
17
|
+
static loadModeling: Map<string, boolean> = new Map();
|
|
18
|
+
|
|
19
|
+
// 加载完成
|
|
20
|
+
loaded = false;
|
|
21
|
+
|
|
22
|
+
async loadModel(url: string) {
|
|
23
|
+
if (!url) {
|
|
24
|
+
this.clear();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
this.loaded = false;
|
|
29
|
+
|
|
30
|
+
// 没有模型并且没有加载任务时就去加载模型
|
|
31
|
+
if (!MeshBase.models.get(url) && !MeshBase.loadModeling.get(url)) {
|
|
32
|
+
MeshBase.loadModeling.set(url, true);
|
|
33
|
+
|
|
34
|
+
let modal = new Object3D();
|
|
35
|
+
|
|
36
|
+
if (/\.fbx$/i.test(url)) {
|
|
37
|
+
await threeLoader.fbxLoader.loadAsync(url).then(res => {
|
|
38
|
+
modal = res;
|
|
39
|
+
}).catch(() => {
|
|
40
|
+
console.error(`${url},加载失败`);
|
|
41
|
+
})
|
|
42
|
+
} else if (/\.(gltf|glb)$/i.test(url)) {
|
|
43
|
+
await threeLoader.gltfLoader.loadAsync(url).then(res => {
|
|
44
|
+
modal = res.scene;
|
|
45
|
+
}).catch(() => {
|
|
46
|
+
console.error(`${url},加载失败`);
|
|
47
|
+
})
|
|
48
|
+
} else {
|
|
49
|
+
console.error(`${url},不支持的格式`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
threeUtils.center(modal);
|
|
53
|
+
threeUtils.alignBottom(modal);
|
|
54
|
+
modal.updateMatrixWorld(true);
|
|
55
|
+
|
|
56
|
+
// 应用全部变换
|
|
57
|
+
modal.traverse(obj => {
|
|
58
|
+
const mesh = obj as Mesh;
|
|
59
|
+
mesh.position.set(0, 0, 0);
|
|
60
|
+
mesh.rotation.set(0, 0, 0);
|
|
61
|
+
mesh.scale.set(1, 1, 1);
|
|
62
|
+
if (mesh.isMesh) {
|
|
63
|
+
mesh.geometry.applyMatrix4(mesh.matrixWorld);
|
|
64
|
+
(mesh.material as MeshStandardMaterial).side = DoubleSide;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
MeshBase.models.set(url, modal);
|
|
69
|
+
MeshBase.loadModeling.set(url, false);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 如果模型还在加载中, 就等待模型加载完成
|
|
73
|
+
do {
|
|
74
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
75
|
+
} while (MeshBase.loadModeling.get(url));
|
|
76
|
+
|
|
77
|
+
if (MeshBase.models.get(url)) {
|
|
78
|
+
const mesh = MeshBase.models.get(url)!.clone();
|
|
79
|
+
this.clear();
|
|
80
|
+
this.add(mesh);
|
|
81
|
+
this.applyAllTranstion();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
await new Promise(resolve => requestAnimationFrame(resolve));
|
|
85
|
+
|
|
86
|
+
// 加载完成事件
|
|
87
|
+
this.dispatchEvent({ type: "loaded" } as never);
|
|
88
|
+
|
|
89
|
+
this.loaded = true;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 超出绘制区域时不绘制
|
|
93
|
+
frustumCulled = false;
|
|
94
|
+
|
|
95
|
+
// 创建阴影
|
|
96
|
+
castShadow: boolean = false;
|
|
97
|
+
|
|
98
|
+
// 接受阴影
|
|
99
|
+
receiveShadow: boolean = false;
|
|
100
|
+
|
|
101
|
+
//遍历模型
|
|
102
|
+
async traverseMesh(callback: (mesh: Mesh) => void) {
|
|
17
103
|
|
|
104
|
+
while (!this.loaded) {
|
|
105
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
this.traverse(obj => {
|
|
109
|
+
const mesh = obj as Mesh;
|
|
110
|
+
if (mesh.isMesh) {
|
|
111
|
+
callback(mesh);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
updateMatrix(): void {
|
|
117
|
+
|
|
118
|
+
// 深度应用属性
|
|
119
|
+
this.traverse(obj => {
|
|
120
|
+
const mesh = obj as Mesh;
|
|
121
|
+
if (mesh.isMesh) {
|
|
122
|
+
mesh.frustumCulled = this.frustumCulled;
|
|
123
|
+
mesh.castShadow = this.castShadow;
|
|
124
|
+
mesh.receiveShadow = this.receiveShadow;
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
super.updateMatrix();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 应用全部变化
|
|
132
|
+
applyAllTranstion() {
|
|
133
|
+
this.updateMatrixWorld(true);
|
|
134
|
+
// 应用全部变换
|
|
135
|
+
this.traverse(obj => {
|
|
136
|
+
const mesh = obj as Mesh;
|
|
137
|
+
mesh.position.set(0, 0, 0);
|
|
138
|
+
mesh.rotation.set(0, 0, 0);
|
|
139
|
+
mesh.scale.set(1, 1, 1);
|
|
140
|
+
if (mesh.isMesh) {
|
|
141
|
+
mesh.geometry.applyMatrix4(mesh.matrixWorld);
|
|
142
|
+
(mesh.material as MeshStandardMaterial).side = DoubleSide;
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// 获取模型的尺寸
|
|
148
|
+
getSize() {
|
|
149
|
+
return threeUtils.getSize(this);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// 居中
|
|
153
|
+
center() {
|
|
154
|
+
threeUtils.center(this);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
//底对齐
|
|
158
|
+
alignBottom(y: number = 0) {
|
|
159
|
+
threeUtils.alignBottom(this, y);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// 放大到指定尺寸
|
|
163
|
+
scaleTo(size: number = 1, key: Array<"x" | "y" | "z"> = ["x", "y", "z"]) {
|
|
164
|
+
threeUtils.scaleTo(this, size, key);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
//按照法线拓展
|
|
168
|
+
expandBynormal(length: number) {
|
|
169
|
+
this.traverseMesh(mesh => {
|
|
170
|
+
// 没有法线就计算法线
|
|
171
|
+
mesh.geometry = mesh.geometry.clone();
|
|
172
|
+
if (!mesh.geometry.getAttribute("normal")) {
|
|
173
|
+
mesh.geometry.computeVertexNormals();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const normal = mesh.geometry.getAttribute("normal");
|
|
177
|
+
const position = mesh.geometry.getAttribute("position");
|
|
178
|
+
const v3 = new Vector3(0, 0, 0);
|
|
179
|
+
for (let i = 0; i < position.count; i++) {
|
|
180
|
+
v3.set(normal.getX(i), normal.getY(i), normal.getZ(i));
|
|
181
|
+
v3.setLength(length);
|
|
182
|
+
position.setXYZ(i, position.getX(i) + v3.x, position.getY(i) + v3.y, position.getZ(i) + v3.z);
|
|
183
|
+
}
|
|
184
|
+
position.needsUpdate = true;
|
|
185
|
+
|
|
186
|
+
})
|
|
187
|
+
}
|
|
18
188
|
|
|
19
189
|
}
|
package/PlaneText.d.ts
CHANGED
|
@@ -22,15 +22,15 @@ export default class PlaneText extends Mesh {
|
|
|
22
22
|
spriteText: SpriteText;
|
|
23
23
|
material: MeshBasicMaterial;
|
|
24
24
|
set(parame: Props): void;
|
|
25
|
-
get(prop: keyof SpriteText): string | number | boolean | Vector3 | import("three").Object3D<import("three").Object3DEventMap> | import("three").BufferGeometry<import("three").NormalBufferAttributes> | ((force?: boolean) => void) | import("three").Object3D<import("three").Object3DEventMap>
|
|
25
|
+
get(prop: keyof SpriteText): string | number | boolean | Vector3 | import("three").Object3D<import("three").Object3DEventMap> | import("three").BufferGeometry<import("three").NormalBufferAttributes> | ((force?: boolean) => void) | ((callback: (object: import("three").Object3D<import("three").Object3DEventMap>) => any) => void) | import("three").Object3D<import("three").Object3DEventMap>[] | import("three").Euler | import("three").Material | import("three").Quaternion | import("three").Matrix4 | import("three").Matrix3 | import("three").Layers | import("three").AnimationClip[] | Record<string, any> | ((renderer: import("three").WebGLRenderer, scene: import("three").Scene, shadowCamera: import("three").Camera, geometry: import("three").BufferGeometry<import("three").NormalBufferAttributes>, depthMaterial: import("three").Material, group: import("three").Group<import("three").Object3DEventMap>) => void) | ((renderer: import("three").WebGLRenderer, scene: import("three").Scene, shadowCamera: import("three").Camera, geometry: import("three").BufferGeometry<import("three").NormalBufferAttributes>, depthMaterial: import("three").Material, group: import("three").Group<import("three").Object3DEventMap>) => void) | ((renderer: import("three").WebGLRenderer, scene: import("three").Scene, camera: import("three").Camera, geometry: import("three").BufferGeometry<import("three").NormalBufferAttributes>, material: import("three").Material, group: import("three").Group<import("three").Object3DEventMap>) => void) | ((renderer: import("three").WebGLRenderer, scene: import("three").Scene, camera: import("three").Camera, geometry: import("three").BufferGeometry<import("three").NormalBufferAttributes>, material: import("three").Material, group: import("three").Group<import("three").Object3DEventMap>) => void) | ((matrix: import("three").Matrix4) => void) | ((axis: Vector3, angle: number) => void) | ((euler: import("three").Euler) => void) | ((m: import("three").Matrix4) => void) | ((q: import("three").Quaternion) => void) | ((vector: Vector3) => Vector3) | ((vector: Vector3) => Vector3) | {
|
|
26
26
|
(vector: Vector3): void;
|
|
27
27
|
(x: number, y: number, z: number): void;
|
|
28
|
-
} | ((id: number) => import("three").Object3D<import("three").Object3DEventMap>) | ((name: string) => import("three").Object3D<import("three").Object3DEventMap>) | ((name: string, value: any) => import("three").Object3D<import("three").Object3DEventMap>) | ((name: string, value: any, optionalTarget?: import("three").Object3D<import("three").Object3DEventMap>[]) => import("three").Object3D<import("three").Object3DEventMap>[]) | ((target: Vector3) => Vector3) | ((target: import("three").Quaternion) => import("three").Quaternion) | ((target: Vector3) => Vector3) | ((target: Vector3) => Vector3) | ((raycaster: import("three").Raycaster, intersects: import("three").Intersection<import("three").Object3D<import("three").Object3DEventMap>>[]) => void) | ((callback: (object: import("three").Object3D<import("three").Object3DEventMap>) => any) => void) | ((callback: (object: import("three").Object3D<import("three").Object3DEventMap>) => any) => void) | ((
|
|
28
|
+
} | ((id: number) => import("three").Object3D<import("three").Object3DEventMap>) | ((name: string) => import("three").Object3D<import("three").Object3DEventMap>) | ((name: string, value: any) => import("three").Object3D<import("three").Object3DEventMap>) | ((name: string, value: any, optionalTarget?: import("three").Object3D<import("three").Object3DEventMap>[]) => import("three").Object3D<import("three").Object3DEventMap>[]) | ((target: Vector3) => Vector3) | ((target: import("three").Quaternion) => import("three").Quaternion) | ((target: Vector3) => Vector3) | ((target: Vector3) => Vector3) | ((raycaster: import("three").Raycaster, intersects: import("three").Intersection<import("three").Object3D<import("three").Object3DEventMap>>[]) => void) | ((callback: (object: import("three").Object3D<import("three").Object3DEventMap>) => any) => void) | ((callback: (object: import("three").Object3D<import("three").Object3DEventMap>) => any) => void) | (() => void) | ((updateParents: boolean, updateChildren: boolean) => void) | ((meta?: {
|
|
29
29
|
geometries: any;
|
|
30
30
|
materials: any;
|
|
31
31
|
textures: any;
|
|
32
32
|
images: any;
|
|
33
|
-
}) => any) | import("three").SpriteMaterial | ((source: SpriteText, recursive?: boolean) => SpriteText) | (() => void) | ((quaternion: import("three").Quaternion) => SpriteText) | ((axis: Vector3, angle: number) => SpriteText) | ((axis: Vector3, angle: number) => SpriteText) | ((angle: number) => SpriteText) | ((angle: number) => SpriteText) | ((angle: number) => SpriteText) | ((axis: Vector3, distance: number) => SpriteText) | ((distance: number) => SpriteText) | ((distance: number) => SpriteText) | ((distance: number) => SpriteText) | ((...object: import("three").Object3D<import("three").Object3DEventMap>[]) => SpriteText) | ((...object: import("three").Object3D<import("three").Object3DEventMap>[]) => SpriteText) | (() => SpriteText) | (() => SpriteText) | ((object: import("three").Object3D<import("three").Object3DEventMap>) => SpriteText) | ((recursive?: boolean) => SpriteText) | {
|
|
33
|
+
}) => any) | (<T extends keyof import("three").Object3DEventMap>(event: import("three").BaseEvent<T> & import("three").Object3DEventMap[T]) => void) | HTMLCanvasElement | import("three").Vector2 | import("three").SpriteMaterial | ((source: SpriteText, recursive?: boolean) => SpriteText) | (() => void) | ((quaternion: import("three").Quaternion) => SpriteText) | ((axis: Vector3, angle: number) => SpriteText) | ((axis: Vector3, angle: number) => SpriteText) | ((angle: number) => SpriteText) | ((angle: number) => SpriteText) | ((angle: number) => SpriteText) | ((axis: Vector3, distance: number) => SpriteText) | ((distance: number) => SpriteText) | ((distance: number) => SpriteText) | ((distance: number) => SpriteText) | ((...object: import("three").Object3D<import("three").Object3DEventMap>[]) => SpriteText) | ((...object: import("three").Object3D<import("three").Object3DEventMap>[]) => SpriteText) | (() => SpriteText) | (() => SpriteText) | ((object: import("three").Object3D<import("three").Object3DEventMap>) => SpriteText) | ((recursive?: boolean) => SpriteText) | {
|
|
34
34
|
<T_1 extends keyof import("three").Object3DEventMap>(type: T_1, listener: import("three").EventListener<import("three").Object3DEventMap[T_1], T_1, SpriteText>): void;
|
|
35
35
|
<T_2 extends string>(type: T_2, listener: import("three").EventListener<{}, T_2, SpriteText>): void;
|
|
36
36
|
} | {
|
package/ThreeBase.js
CHANGED
|
@@ -294,9 +294,7 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
294
294
|
}
|
|
295
295
|
// 渲染场景
|
|
296
296
|
render() {
|
|
297
|
-
//
|
|
298
|
-
// this.renderer.domElement.style.pointerEvents = (!this.controlsPosition.isDone() || !this.controlsCenter.isDone()) ? "none" : "all";
|
|
299
|
-
// canvas 没有在页面上面的话 就跳过渲染
|
|
297
|
+
// canvas 没有在页面上面的话 就停止渲染
|
|
300
298
|
if (!threeUtils.inDocument(this.renderer.domElement)) {
|
|
301
299
|
this.stopRender();
|
|
302
300
|
return;
|
package/ThreeBase.ts
CHANGED
|
@@ -363,10 +363,7 @@ export default class ThreeBase extends EventDispatcher {
|
|
|
363
363
|
|
|
364
364
|
// 渲染场景
|
|
365
365
|
render() {
|
|
366
|
-
//
|
|
367
|
-
// this.renderer.domElement.style.pointerEvents = (!this.controlsPosition.isDone() || !this.controlsCenter.isDone()) ? "none" : "all";
|
|
368
|
-
|
|
369
|
-
// canvas 没有在页面上面的话 就跳过渲染
|
|
366
|
+
// canvas 没有在页面上面的话 就停止渲染
|
|
370
367
|
if (!threeUtils.inDocument(this.renderer.domElement)) {
|
|
371
368
|
this.stopRender();
|
|
372
369
|
return;
|
package/ThreeMouse.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export interface ThreeMouseEvent extends Intersection {
|
|
|
11
11
|
y: number;
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
14
|
+
* three.js 专用的鼠标拾取模型对象
|
|
15
15
|
*/
|
|
16
16
|
export default class ThreeMouse {
|
|
17
17
|
constructor(renderer: THREE.WebGLRenderer, camera: THREE.Camera, scene: THREE.Scene);
|
package/ThreeMouse.js
CHANGED
|
@@ -8,7 +8,7 @@ import * as THREE from "three";
|
|
|
8
8
|
import { Raycaster } from "three";
|
|
9
9
|
import { debounce } from "lodash";
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* three.js 专用的鼠标拾取模型对象
|
|
12
12
|
*/
|
|
13
13
|
export default class ThreeMouse {
|
|
14
14
|
constructor(renderer, camera, scene) {
|
|
@@ -108,7 +108,7 @@ export default class ThreeMouse {
|
|
|
108
108
|
let intersection = this._getSelected(meshs);
|
|
109
109
|
if (intersection) {
|
|
110
110
|
const { face, object } = intersection;
|
|
111
|
-
face && face.normal.applyMatrix4(object.matrixWorld);
|
|
111
|
+
// face && face.normal.applyMatrix4(object.matrixWorld);
|
|
112
112
|
const MouseEvent = Object.assign(intersection, {
|
|
113
113
|
renderer: this._renderer,
|
|
114
114
|
camera: this._camera,
|
|
@@ -232,7 +232,7 @@ export default class ThreeMouse {
|
|
|
232
232
|
return;
|
|
233
233
|
}
|
|
234
234
|
this._mesh_on = intersection.object;
|
|
235
|
-
if (this.hasEvent(this.
|
|
235
|
+
if (this.hasEvent(this._mesh_on, ["mouseup"])) {
|
|
236
236
|
this._mesh_on.dispatchEvent({
|
|
237
237
|
...intersection,
|
|
238
238
|
renderer: this._renderer,
|
package/ThreeMouse.ts
CHANGED
|
@@ -21,7 +21,7 @@ export interface ThreeMouseEvent extends Intersection {
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
|
-
*
|
|
24
|
+
* three.js 专用的鼠标拾取模型对象
|
|
25
25
|
*/
|
|
26
26
|
export default class ThreeMouse {
|
|
27
27
|
|
|
@@ -152,7 +152,7 @@ export default class ThreeMouse {
|
|
|
152
152
|
|
|
153
153
|
if (intersection) {
|
|
154
154
|
const { face, object } = intersection;
|
|
155
|
-
face && face.normal.applyMatrix4(object.matrixWorld);
|
|
155
|
+
// face && face.normal.applyMatrix4(object.matrixWorld);
|
|
156
156
|
const MouseEvent: ThreeMouseEvent = Object.assign(intersection, { // 将来可能用到的对象
|
|
157
157
|
renderer: this._renderer,
|
|
158
158
|
camera: this._camera,
|
|
@@ -312,7 +312,7 @@ export default class ThreeMouse {
|
|
|
312
312
|
|
|
313
313
|
this._mesh_on = intersection.object as Object3D;
|
|
314
314
|
|
|
315
|
-
if (this.hasEvent(this.
|
|
315
|
+
if (this.hasEvent(this._mesh_on, ["mouseup"])) {
|
|
316
316
|
|
|
317
317
|
this._mesh_on.dispatchEvent({
|
|
318
318
|
...intersection,
|
package/Transition.js
CHANGED
package/Transition.ts
CHANGED
package/package.json
CHANGED
package/threeLoader.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EventDispatcher, Texture, TextureLoader } from "three";
|
|
1
|
+
import { EventDispatcher, Object3D, Texture, TextureLoader } from "three";
|
|
2
2
|
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
|
|
3
3
|
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
|
4
4
|
import { MTLLoader } from "three/examples/jsm/loaders/MTLLoader";
|
|
@@ -16,6 +16,8 @@ declare class ThreeLoader extends EventDispatcher {
|
|
|
16
16
|
stlLoader: STLLoader;
|
|
17
17
|
mtlLoader: MTLLoader;
|
|
18
18
|
gltfLoader: GLTFLoader;
|
|
19
|
+
/** 加载模型支持glb,fbx,stl,obj */
|
|
20
|
+
loadModal(url: string): Promise<Object3D<import("three").Object3DEventMap>>;
|
|
19
21
|
onload: boolean;
|
|
20
22
|
}
|
|
21
23
|
declare const threeLoader: ThreeLoader;
|
package/threeLoader.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @Last Modified by: xiaosihan
|
|
5
5
|
* @Last Modified time: 2023-02-07 11:11:48
|
|
6
6
|
*/
|
|
7
|
-
import { CanvasTexture, DefaultLoadingManager, EventDispatcher, RepeatWrapping, TextureLoader, VideoTexture } from "three";
|
|
7
|
+
import { CanvasTexture, DefaultLoadingManager, EventDispatcher, Mesh, MeshLambertMaterial, Object3D, RepeatWrapping, TextureLoader, VideoTexture } from "three";
|
|
8
8
|
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
|
|
9
9
|
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
|
10
10
|
import { MTLLoader } from "three/examples/jsm/loaders/MTLLoader";
|
|
@@ -114,6 +114,37 @@ class ThreeLoader extends EventDispatcher {
|
|
|
114
114
|
loader.setDRACOLoader(dracoLoader);
|
|
115
115
|
return loader;
|
|
116
116
|
})();
|
|
117
|
+
/** 加载模型支持glb,fbx,stl,obj */
|
|
118
|
+
async loadModal(url) {
|
|
119
|
+
let Object3d = new Object3D();
|
|
120
|
+
if (/\.fbx$/i.test(url)) {
|
|
121
|
+
await threeLoader.fbxLoader.loadAsync(url).then(res => {
|
|
122
|
+
Object3d = res;
|
|
123
|
+
}).catch(() => {
|
|
124
|
+
console.error(`${url},加载失败`);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
else if (/\.(gltf|glb)$/i.test(url)) {
|
|
128
|
+
await threeLoader.gltfLoader.loadAsync(url).then(res => {
|
|
129
|
+
Object3d = res.scene;
|
|
130
|
+
Object3d.animations = res.animations;
|
|
131
|
+
}).catch(() => {
|
|
132
|
+
console.error(`${url},加载失败`);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
else if (/\.stl$/i.test(url)) {
|
|
136
|
+
await threeLoader.stlLoader.loadAsync(url).then(geometry => {
|
|
137
|
+
const material = new MeshLambertMaterial();
|
|
138
|
+
Object3d = new Mesh(geometry, material);
|
|
139
|
+
}).catch(() => {
|
|
140
|
+
console.error(`${url},加载失败`);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
throw new Error(`${url},不支持的格式`);
|
|
145
|
+
}
|
|
146
|
+
return Object3d;
|
|
147
|
+
}
|
|
117
148
|
// 是否加载完成
|
|
118
149
|
onload = true;
|
|
119
150
|
}
|
package/threeLoader.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @Last Modified time: 2023-02-07 11:11:48
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { CanvasTexture, DefaultLoadingManager, EventDispatcher, RepeatWrapping, SRGBColorSpace, Texture, TextureLoader, VideoTexture } from "three";
|
|
8
|
+
import { CanvasTexture, DefaultLoadingManager, EventDispatcher, Mesh, MeshLambertMaterial, Object3D, RepeatWrapping, SRGBColorSpace, Texture, TextureLoader, VideoTexture } from "three";
|
|
9
9
|
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader";
|
|
10
10
|
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
|
|
11
11
|
import { MTLLoader } from "three/examples/jsm/loaders/MTLLoader";
|
|
@@ -141,6 +141,38 @@ class ThreeLoader extends EventDispatcher {
|
|
|
141
141
|
return loader;
|
|
142
142
|
})()
|
|
143
143
|
|
|
144
|
+
|
|
145
|
+
/** 加载模型支持glb,fbx,stl,obj */
|
|
146
|
+
async loadModal(url: string) {
|
|
147
|
+
let Object3d = new Object3D();
|
|
148
|
+
|
|
149
|
+
if (/\.fbx$/i.test(url)) {
|
|
150
|
+
await threeLoader.fbxLoader.loadAsync(url).then(res => {
|
|
151
|
+
Object3d = res;
|
|
152
|
+
}).catch(() => {
|
|
153
|
+
console.error(`${url},加载失败`);
|
|
154
|
+
})
|
|
155
|
+
} else if (/\.(gltf|glb)$/i.test(url)) {
|
|
156
|
+
await threeLoader.gltfLoader.loadAsync(url).then(res => {
|
|
157
|
+
Object3d = res.scene;
|
|
158
|
+
Object3d.animations = res.animations;
|
|
159
|
+
}).catch(() => {
|
|
160
|
+
console.error(`${url},加载失败`);
|
|
161
|
+
})
|
|
162
|
+
} else if (/\.stl$/i.test(url)) {
|
|
163
|
+
await threeLoader.stlLoader.loadAsync(url).then(geometry => {
|
|
164
|
+
const material = new MeshLambertMaterial();
|
|
165
|
+
Object3d = new Mesh(geometry, material);
|
|
166
|
+
}).catch(() => {
|
|
167
|
+
console.error(`${url},加载失败`);
|
|
168
|
+
})
|
|
169
|
+
} else {
|
|
170
|
+
throw new Error(`${url},不支持的格式`);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return Object3d;
|
|
174
|
+
}
|
|
175
|
+
|
|
144
176
|
// 是否加载完成
|
|
145
177
|
onload = true;
|
|
146
178
|
|
package/threeUtils.d.ts
CHANGED
|
@@ -36,6 +36,7 @@ declare class ThreeUtils extends EventDispatcher {
|
|
|
36
36
|
centerObject3D(object3d: Object3D | BufferGeometry): void;
|
|
37
37
|
center(object3d: Object3D | BufferGeometry): void;
|
|
38
38
|
scaleTo(object3d: Object3D | BufferGeometry, size?: number, key?: Array<"x" | "y" | "z">): void;
|
|
39
|
+
applyAllTranstion(object3d: Object3D): void;
|
|
39
40
|
exportGLB(input: Object3D, fileName?: string): void;
|
|
40
41
|
getVolume(geometry: BufferGeometry): number;
|
|
41
42
|
signedVolumeOfTriangle(p1: Vector3, p2: Vector3, p3: Vector3): number;
|
package/threeUtils.js
CHANGED
|
@@ -173,6 +173,19 @@ class ThreeUtils extends EventDispatcher {
|
|
|
173
173
|
object3d.scale(scale, scale, scale);
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
|
+
// 应用全部变化
|
|
177
|
+
applyAllTranstion(object3d) {
|
|
178
|
+
object3d.updateMatrixWorld(true);
|
|
179
|
+
// 应用全部变换
|
|
180
|
+
object3d.traverse(obj => {
|
|
181
|
+
obj.position.set(0, 0, 0);
|
|
182
|
+
obj.rotation.set(0, 0, 0);
|
|
183
|
+
obj.scale.set(1, 1, 1);
|
|
184
|
+
if (obj.isMesh) {
|
|
185
|
+
obj.geometry.applyMatrix4(obj.matrixWorld);
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
}
|
|
176
189
|
// 导出 glb
|
|
177
190
|
exportGLB(input, fileName = "threeUtils.exportGLB") {
|
|
178
191
|
const gltfExporter = new GLTFExporter();
|
package/threeUtils.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @Last Modified time: 2023-05-03 00:36:18
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { Box3, BufferAttribute, BufferGeometry, Clock, EventDispatcher, Object3D, Vector3 } from "three";
|
|
8
|
+
import { Box3, BufferAttribute, BufferGeometry, Clock, EventDispatcher, Mesh, MeshStandardMaterial, Object3D, Vector3 } from "three";
|
|
9
9
|
import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter';
|
|
10
10
|
|
|
11
11
|
class ThreeUtils extends EventDispatcher {
|
|
@@ -200,6 +200,20 @@ class ThreeUtils extends EventDispatcher {
|
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
+
// 应用全部变化
|
|
204
|
+
applyAllTranstion(object3d: Object3D) {
|
|
205
|
+
object3d.updateMatrixWorld(true);
|
|
206
|
+
// 应用全部变换
|
|
207
|
+
object3d.traverse(obj => {
|
|
208
|
+
obj.position.set(0, 0, 0);
|
|
209
|
+
obj.rotation.set(0, 0, 0);
|
|
210
|
+
obj.scale.set(1, 1, 1);
|
|
211
|
+
if ((obj as Mesh).isMesh) {
|
|
212
|
+
(obj as Mesh).geometry.applyMatrix4(obj.matrixWorld);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
203
217
|
// 导出 glb
|
|
204
218
|
exportGLB(input: Object3D, fileName: string = "threeUtils.exportGLB") {
|
|
205
219
|
const gltfExporter = new GLTFExporter();
|