three-base 2.0.27 → 2.0.30

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/MeshBase.d.ts CHANGED
@@ -1,19 +1,28 @@
1
- import { Group, Mesh, Object3D, Vector3 } from "three";
1
+ import { AnimationAction, AnimationMixer, Clock, Group, Mesh, Object3D, Vector3 } from "three";
2
2
  export default class MeshBase extends Group {
3
3
  constructor(url?: string);
4
4
  static models: Map<string, Object3D>;
5
5
  static loadModeling: Map<string, boolean>;
6
6
  loaded: boolean;
7
+ hasAnimation: boolean;
8
+ mixer?: AnimationMixer;
9
+ animationActions: {
10
+ [key: string]: AnimationAction;
11
+ };
7
12
  loadModel(url: string): Promise<void>;
8
13
  frustumCulled: boolean;
9
14
  castShadow: boolean;
10
15
  receiveShadow: boolean;
16
+ awaitLoaded(callback?: Function): Promise<void>;
11
17
  traverseMesh(callback: (mesh: Mesh) => void): Promise<void>;
18
+ clock: Clock;
19
+ setClipActionWeight(weights?: {
20
+ [key: string]: number;
21
+ }): Promise<void>;
12
22
  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;
23
+ getSize(): Promise<Vector3>;
24
+ center(): Promise<void>;
25
+ alignBottom(y?: number): Promise<void>;
26
+ scaleTo(size?: number, key?: Array<"x" | "y" | "z">): Promise<void>;
18
27
  expandBynormal(length: number): void;
19
28
  }
package/MeshBase.js CHANGED
@@ -1,6 +1,7 @@
1
- import { DoubleSide, Group, Object3D, Vector3 } from "three";
1
+ import { AnimationMixer, Clock, Group, Mesh, Object3D, Vector3 } from "three";
2
2
  import threeUtils from "./threeUtils";
3
3
  import threeLoader from "./threeLoader";
4
+ import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils';
4
5
  // 模型基类
5
6
  export default class MeshBase extends Group {
6
7
  constructor(url) {
@@ -13,6 +14,12 @@ export default class MeshBase extends Group {
13
14
  static loadModeling = new Map();
14
15
  // 加载完成
15
16
  loaded = false;
17
+ // 是否有动画
18
+ hasAnimation = false;
19
+ //动画混合器
20
+ mixer;
21
+ //动画剪辑对象数组
22
+ animationActions = {};
16
23
  async loadModel(url) {
17
24
  if (!url) {
18
25
  this.clear();
@@ -33,6 +40,14 @@ export default class MeshBase extends Group {
33
40
  else if (/\.(gltf|glb)$/i.test(url)) {
34
41
  await threeLoader.gltfLoader.loadAsync(url).then(res => {
35
42
  modal = res.scene;
43
+ modal.animations = res.animations;
44
+ }).catch(() => {
45
+ console.error(`${url},加载失败`);
46
+ });
47
+ }
48
+ else if (/\.stl$/i.test(url)) {
49
+ await threeLoader.stlLoader.loadAsync(url).then(stlGeo => {
50
+ modal = new Mesh(stlGeo);
36
51
  }).catch(() => {
37
52
  console.error(`${url},加载失败`);
38
53
  });
@@ -43,29 +58,32 @@ export default class MeshBase extends Group {
43
58
  threeUtils.center(modal);
44
59
  threeUtils.alignBottom(modal);
45
60
  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
61
  MeshBase.models.set(url, modal);
58
62
  MeshBase.loadModeling.set(url, false);
59
63
  }
60
64
  // 如果模型还在加载中, 就等待模型加载完成
61
65
  do {
62
- await new Promise(resolve => setTimeout(resolve, 200));
66
+ await new Promise(resolve => setTimeout(resolve, 50));
63
67
  } while (MeshBase.loadModeling.get(url));
64
68
  if (MeshBase.models.get(url)) {
65
- const mesh = MeshBase.models.get(url).clone();
66
69
  this.clear();
67
- this.add(mesh);
68
- this.applyAllTranstion();
70
+ const mesh = MeshBase.models.get(url);
71
+ // 判断是否有动画
72
+ this.hasAnimation = mesh.animations.length > 0;
73
+ if (this.hasAnimation) {
74
+ const model = SkeletonUtils.clone(mesh);
75
+ this.mixer = new AnimationMixer(model);
76
+ this.animationActions = {};
77
+ mesh.animations.map(animation => {
78
+ const animationAction = this.mixer.clipAction(animation).play();
79
+ animationAction.weight = 0;
80
+ this.animationActions[animation.name] = animationAction;
81
+ });
82
+ this.add(model);
83
+ }
84
+ else {
85
+ this.add(mesh.clone());
86
+ }
69
87
  }
70
88
  await new Promise(resolve => requestAnimationFrame(resolve));
71
89
  // 加载完成事件
@@ -78,11 +96,17 @@ export default class MeshBase extends Group {
78
96
  castShadow = false;
79
97
  // 接受阴影
80
98
  receiveShadow = false;
81
- //遍历模型
82
- async traverseMesh(callback) {
99
+ // 等待加载加载完成
100
+ async awaitLoaded(callback) {
83
101
  while (!this.loaded) {
84
- await new Promise(resolve => setTimeout(resolve, 100));
102
+ await new Promise(resolve => setTimeout(resolve, 50));
85
103
  }
104
+ callback && callback();
105
+ }
106
+ //遍历模型
107
+ async traverseMesh(callback) {
108
+ // 等待加载完成
109
+ await this.awaitLoaded();
86
110
  this.traverse(obj => {
87
111
  const mesh = obj;
88
112
  if (mesh.isMesh) {
@@ -90,7 +114,20 @@ export default class MeshBase extends Group {
90
114
  }
91
115
  });
92
116
  }
117
+ clock = new Clock();
118
+ //设置动画的权重
119
+ async setClipActionWeight(weights = {}) {
120
+ // 等待加载完成
121
+ await this.awaitLoaded();
122
+ for (let key in this.animationActions) {
123
+ this.animationActions[key].weight = weights[key] || 0;
124
+ }
125
+ }
93
126
  updateMatrix() {
127
+ //播放动画
128
+ if (this.mixer) {
129
+ this.mixer.update(this.clock.getDelta());
130
+ }
94
131
  // 深度应用属性
95
132
  this.traverse(obj => {
96
133
  const mesh = obj;
@@ -102,35 +139,24 @@ export default class MeshBase extends Group {
102
139
  });
103
140
  super.updateMatrix();
104
141
  }
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
142
  // 获取模型的尺寸
121
- getSize() {
143
+ async getSize() {
144
+ await this.awaitLoaded();
122
145
  return threeUtils.getSize(this);
123
146
  }
124
147
  // 居中
125
- center() {
148
+ async center() {
149
+ await this.awaitLoaded();
126
150
  threeUtils.center(this);
127
151
  }
128
152
  //底对齐
129
- alignBottom(y = 0) {
153
+ async alignBottom(y = 0) {
154
+ await this.awaitLoaded();
130
155
  threeUtils.alignBottom(this, y);
131
156
  }
132
157
  // 放大到指定尺寸
133
- scaleTo(size = 1, key = ["x", "y", "z"]) {
158
+ async scaleTo(size = 1, key = ["x", "y", "z"]) {
159
+ await this.awaitLoaded();
134
160
  threeUtils.scaleTo(this, size, key);
135
161
  }
136
162
  //按照法线拓展
package/MeshBase.ts CHANGED
@@ -1,7 +1,8 @@
1
1
 
2
- import { DoubleSide, Group, Mesh, MeshStandardMaterial, Object3D, Vector3 } from "three";
2
+ import { AnimationAction, AnimationMixer, Clock, DoubleSide, Group, Mesh, MeshStandardMaterial, Object3D, Vector3 } from "three";
3
3
  import threeUtils from "./threeUtils";
4
4
  import threeLoader from "./threeLoader";
5
+ import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils';
5
6
 
6
7
  // 模型基类
7
8
  export default class MeshBase extends Group {
@@ -19,6 +20,15 @@ export default class MeshBase extends Group {
19
20
  // 加载完成
20
21
  loaded = false;
21
22
 
23
+ // 是否有动画
24
+ hasAnimation = false;
25
+
26
+ //动画混合器
27
+ mixer?: AnimationMixer;
28
+
29
+ //动画剪辑对象数组
30
+ animationActions: { [key: string]: AnimationAction } = {};
31
+
22
32
  async loadModel(url: string) {
23
33
  if (!url) {
24
34
  this.clear();
@@ -42,6 +52,13 @@ export default class MeshBase extends Group {
42
52
  } else if (/\.(gltf|glb)$/i.test(url)) {
43
53
  await threeLoader.gltfLoader.loadAsync(url).then(res => {
44
54
  modal = res.scene;
55
+ modal.animations = res.animations;
56
+ }).catch(() => {
57
+ console.error(`${url},加载失败`);
58
+ })
59
+ } else if (/\.stl$/i.test(url)) {
60
+ await threeLoader.stlLoader.loadAsync(url).then(stlGeo => {
61
+ modal = new Mesh(stlGeo);
45
62
  }).catch(() => {
46
63
  console.error(`${url},加载失败`);
47
64
  })
@@ -53,32 +70,38 @@ export default class MeshBase extends Group {
53
70
  threeUtils.alignBottom(modal);
54
71
  modal.updateMatrixWorld(true);
55
72
 
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
73
  MeshBase.models.set(url, modal);
69
74
  MeshBase.loadModeling.set(url, false);
70
75
  }
71
76
 
72
77
  // 如果模型还在加载中, 就等待模型加载完成
73
78
  do {
74
- await new Promise(resolve => setTimeout(resolve, 200));
79
+ await new Promise(resolve => setTimeout(resolve, 50));
75
80
  } while (MeshBase.loadModeling.get(url));
76
81
 
77
82
  if (MeshBase.models.get(url)) {
78
- const mesh = MeshBase.models.get(url)!.clone();
83
+
79
84
  this.clear();
80
- this.add(mesh);
81
- this.applyAllTranstion();
85
+ const mesh = MeshBase.models.get(url);
86
+ // 判断是否有动画
87
+ this.hasAnimation = mesh.animations.length > 0;
88
+
89
+ if (this.hasAnimation) {
90
+ const model = SkeletonUtils.clone(mesh);
91
+ this.mixer = new AnimationMixer(model);
92
+
93
+ this.animationActions = {};
94
+ mesh.animations.map(animation => {
95
+ const animationAction = this.mixer.clipAction(animation).play();
96
+ animationAction.weight = 0;
97
+ this.animationActions[animation.name] = animationAction;
98
+ });
99
+
100
+ this.add(model);
101
+ } else {
102
+ this.add(mesh.clone());
103
+ }
104
+
82
105
  }
83
106
 
84
107
  await new Promise(resolve => requestAnimationFrame(resolve));
@@ -98,12 +121,18 @@ export default class MeshBase extends Group {
98
121
  // 接受阴影
99
122
  receiveShadow: boolean = false;
100
123
 
101
- //遍历模型
102
- async traverseMesh(callback: (mesh: Mesh) => void) {
103
-
124
+ // 等待加载加载完成
125
+ async awaitLoaded(callback?: Function) {
104
126
  while (!this.loaded) {
105
- await new Promise(resolve => setTimeout(resolve, 100));
127
+ await new Promise(resolve => setTimeout(resolve, 50));
106
128
  }
129
+ callback && callback();
130
+ }
131
+
132
+ //遍历模型
133
+ async traverseMesh(callback: (mesh: Mesh) => void) {
134
+ // 等待加载完成
135
+ await this.awaitLoaded();
107
136
 
108
137
  this.traverse(obj => {
109
138
  const mesh = obj as Mesh;
@@ -113,8 +142,22 @@ export default class MeshBase extends Group {
113
142
  });
114
143
  }
115
144
 
116
- updateMatrix(): void {
145
+ clock = new Clock();
146
+
147
+ //设置动画的权重
148
+ async setClipActionWeight(weights: { [key: string]: number } = {}) {
149
+ // 等待加载完成
150
+ await this.awaitLoaded();
151
+ for (let key in this.animationActions) {
152
+ this.animationActions[key].weight = weights[key] || 0;
153
+ }
154
+ }
117
155
 
156
+ updateMatrix(): void {
157
+ //播放动画
158
+ if (this.mixer) {
159
+ this.mixer.update(this.clock.getDelta());
160
+ }
118
161
  // 深度应用属性
119
162
  this.traverse(obj => {
120
163
  const mesh = obj as Mesh;
@@ -128,39 +171,27 @@ export default class MeshBase extends Group {
128
171
  super.updateMatrix();
129
172
  }
130
173
 
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
174
  // 获取模型的尺寸
148
- getSize() {
175
+ async getSize() {
176
+ await this.awaitLoaded();
149
177
  return threeUtils.getSize(this);
150
178
  }
151
179
 
152
180
  // 居中
153
- center() {
181
+ async center() {
182
+ await this.awaitLoaded();
154
183
  threeUtils.center(this);
155
184
  }
156
185
 
157
186
  //底对齐
158
- alignBottom(y: number = 0) {
187
+ async alignBottom(y: number = 0) {
188
+ await this.awaitLoaded();
159
189
  threeUtils.alignBottom(this, y);
160
190
  }
161
191
 
162
192
  // 放大到指定尺寸
163
- scaleTo(size: number = 1, key: Array<"x" | "y" | "z"> = ["x", "y", "z"]) {
193
+ async scaleTo(size: number = 1, key: Array<"x" | "y" | "z"> = ["x", "y", "z"]) {
194
+ await this.awaitLoaded();
164
195
  threeUtils.scaleTo(this, size, key);
165
196
  }
166
197
 
package/ThreeBase.js CHANGED
@@ -187,7 +187,12 @@ export default class ThreeBase extends EventDispatcher {
187
187
  frame = 50;
188
188
  init() {
189
189
  // 资源加载进度有更新时, 需要渲染
190
- threeLoader.addEventListener("progress", () => {
190
+ threeLoader.addEventListener("loadding", () => {
191
+ this.dispatchEvent({ type: "loadding" });
192
+ this.needRender = true;
193
+ });
194
+ threeLoader.addEventListener("onLoad", () => {
195
+ this.dispatchEvent({ type: "onLoad" });
191
196
  this.needRender = true;
192
197
  });
193
198
  }
package/ThreeBase.ts CHANGED
@@ -227,7 +227,13 @@ export default class ThreeBase extends EventDispatcher {
227
227
 
228
228
  init() {
229
229
  // 资源加载进度有更新时, 需要渲染
230
- threeLoader.addEventListener("progress", () => {
230
+ threeLoader.addEventListener("loadding", () => {
231
+ this.dispatchEvent({ type: "loadding" } as never);
232
+ this.needRender = true;
233
+ });
234
+
235
+ threeLoader.addEventListener("onLoad", () => {
236
+ this.dispatchEvent({ type: "onLoad" } as never);
231
237
  this.needRender = true;
232
238
  });
233
239
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-base",
3
- "version": "2.0.27",
3
+ "version": "2.0.30",
4
4
  "description": "three 3d three-base",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
package/threeLoader.js CHANGED
@@ -26,8 +26,13 @@ class ThreeLoader extends EventDispatcher {
26
26
  this.onload = false;
27
27
  };
28
28
  // 有资源加载完成时通知渲染器
29
- DefaultLoadingManager.onProgress = () => {
30
- this.dispatchEvent({ type: "progress" });
29
+ DefaultLoadingManager.onProgress = (url, loaded, total) => {
30
+ if (loaded < total) {
31
+ this.dispatchEvent({ type: "loadding" });
32
+ }
33
+ else if (loaded === total) {
34
+ this.dispatchEvent({ type: "onLoad" });
35
+ }
31
36
  };
32
37
  DefaultLoadingManager.onLoad = () => {
33
38
  this.onload = true;
package/threeLoader.ts CHANGED
@@ -32,8 +32,12 @@ class ThreeLoader extends EventDispatcher {
32
32
  }
33
33
 
34
34
  // 有资源加载完成时通知渲染器
35
- DefaultLoadingManager.onProgress = () => {
36
- this.dispatchEvent({ type: "progress" } as never);
35
+ DefaultLoadingManager.onProgress = (url: string, loaded: number, total: number) => {
36
+ if (loaded < total) {
37
+ this.dispatchEvent({ type: "loadding" } as never);
38
+ } else if (loaded === total) {
39
+ this.dispatchEvent({ type: "onLoad" } as never);
40
+ }
37
41
  }
38
42
 
39
43
  DefaultLoadingManager.onLoad = () => {