three-base 2.0.27 → 2.0.29

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, 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,7 @@ 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;
36
44
  }).catch(() => {
37
45
  console.error(`${url},加载失败`);
38
46
  });
@@ -43,29 +51,32 @@ export default class MeshBase extends Group {
43
51
  threeUtils.center(modal);
44
52
  threeUtils.alignBottom(modal);
45
53
  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
54
  MeshBase.models.set(url, modal);
58
55
  MeshBase.loadModeling.set(url, false);
59
56
  }
60
57
  // 如果模型还在加载中, 就等待模型加载完成
61
58
  do {
62
- await new Promise(resolve => setTimeout(resolve, 200));
59
+ await new Promise(resolve => setTimeout(resolve, 50));
63
60
  } while (MeshBase.loadModeling.get(url));
64
61
  if (MeshBase.models.get(url)) {
65
- const mesh = MeshBase.models.get(url).clone();
66
62
  this.clear();
67
- this.add(mesh);
68
- this.applyAllTranstion();
63
+ const mesh = MeshBase.models.get(url);
64
+ // 判断是否有动画
65
+ this.hasAnimation = mesh.animations.length > 0;
66
+ if (this.hasAnimation) {
67
+ const model = SkeletonUtils.clone(mesh);
68
+ this.mixer = new AnimationMixer(model);
69
+ this.animationActions = {};
70
+ mesh.animations.map(animation => {
71
+ const animationAction = this.mixer.clipAction(animation).play();
72
+ animationAction.weight = 0;
73
+ this.animationActions[animation.name] = animationAction;
74
+ });
75
+ this.add(model);
76
+ }
77
+ else {
78
+ this.add(mesh);
79
+ }
69
80
  }
70
81
  await new Promise(resolve => requestAnimationFrame(resolve));
71
82
  // 加载完成事件
@@ -78,11 +89,17 @@ export default class MeshBase extends Group {
78
89
  castShadow = false;
79
90
  // 接受阴影
80
91
  receiveShadow = false;
81
- //遍历模型
82
- async traverseMesh(callback) {
92
+ // 等待加载加载完成
93
+ async awaitLoaded(callback) {
83
94
  while (!this.loaded) {
84
- await new Promise(resolve => setTimeout(resolve, 100));
95
+ await new Promise(resolve => setTimeout(resolve, 50));
85
96
  }
97
+ callback && callback();
98
+ }
99
+ //遍历模型
100
+ async traverseMesh(callback) {
101
+ // 等待加载完成
102
+ await this.awaitLoaded();
86
103
  this.traverse(obj => {
87
104
  const mesh = obj;
88
105
  if (mesh.isMesh) {
@@ -90,7 +107,20 @@ export default class MeshBase extends Group {
90
107
  }
91
108
  });
92
109
  }
110
+ clock = new Clock();
111
+ //设置动画的权重
112
+ async setClipActionWeight(weights = {}) {
113
+ // 等待加载完成
114
+ await this.awaitLoaded();
115
+ for (let key in this.animationActions) {
116
+ this.animationActions[key].weight = weights[key] || 0;
117
+ }
118
+ }
93
119
  updateMatrix() {
120
+ //播放动画
121
+ if (this.mixer) {
122
+ this.mixer.update(this.clock.getDelta());
123
+ }
94
124
  // 深度应用属性
95
125
  this.traverse(obj => {
96
126
  const mesh = obj;
@@ -102,35 +132,24 @@ export default class MeshBase extends Group {
102
132
  });
103
133
  super.updateMatrix();
104
134
  }
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
135
  // 获取模型的尺寸
121
- getSize() {
136
+ async getSize() {
137
+ await this.awaitLoaded();
122
138
  return threeUtils.getSize(this);
123
139
  }
124
140
  // 居中
125
- center() {
141
+ async center() {
142
+ await this.awaitLoaded();
126
143
  threeUtils.center(this);
127
144
  }
128
145
  //底对齐
129
- alignBottom(y = 0) {
146
+ async alignBottom(y = 0) {
147
+ await this.awaitLoaded();
130
148
  threeUtils.alignBottom(this, y);
131
149
  }
132
150
  // 放大到指定尺寸
133
- scaleTo(size = 1, key = ["x", "y", "z"]) {
151
+ async scaleTo(size = 1, key = ["x", "y", "z"]) {
152
+ await this.awaitLoaded();
134
153
  threeUtils.scaleTo(this, size, key);
135
154
  }
136
155
  //按照法线拓展
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,7 @@ 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;
45
56
  }).catch(() => {
46
57
  console.error(`${url},加载失败`);
47
58
  })
@@ -53,32 +64,38 @@ export default class MeshBase extends Group {
53
64
  threeUtils.alignBottom(modal);
54
65
  modal.updateMatrixWorld(true);
55
66
 
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
67
  MeshBase.models.set(url, modal);
69
68
  MeshBase.loadModeling.set(url, false);
70
69
  }
71
70
 
72
71
  // 如果模型还在加载中, 就等待模型加载完成
73
72
  do {
74
- await new Promise(resolve => setTimeout(resolve, 200));
73
+ await new Promise(resolve => setTimeout(resolve, 50));
75
74
  } while (MeshBase.loadModeling.get(url));
76
75
 
77
76
  if (MeshBase.models.get(url)) {
78
- const mesh = MeshBase.models.get(url)!.clone();
77
+
79
78
  this.clear();
80
- this.add(mesh);
81
- this.applyAllTranstion();
79
+ const mesh = MeshBase.models.get(url);
80
+ // 判断是否有动画
81
+ this.hasAnimation = mesh.animations.length > 0;
82
+
83
+ if (this.hasAnimation) {
84
+ const model = SkeletonUtils.clone(mesh);
85
+ this.mixer = new AnimationMixer(model);
86
+
87
+ this.animationActions = {};
88
+ mesh.animations.map(animation => {
89
+ const animationAction = this.mixer.clipAction(animation).play();
90
+ animationAction.weight = 0;
91
+ this.animationActions[animation.name] = animationAction;
92
+ });
93
+
94
+ this.add(model);
95
+ } else {
96
+ this.add(mesh);
97
+ }
98
+
82
99
  }
83
100
 
84
101
  await new Promise(resolve => requestAnimationFrame(resolve));
@@ -98,12 +115,18 @@ export default class MeshBase extends Group {
98
115
  // 接受阴影
99
116
  receiveShadow: boolean = false;
100
117
 
101
- //遍历模型
102
- async traverseMesh(callback: (mesh: Mesh) => void) {
103
-
118
+ // 等待加载加载完成
119
+ async awaitLoaded(callback?: Function) {
104
120
  while (!this.loaded) {
105
- await new Promise(resolve => setTimeout(resolve, 100));
121
+ await new Promise(resolve => setTimeout(resolve, 50));
106
122
  }
123
+ callback && callback();
124
+ }
125
+
126
+ //遍历模型
127
+ async traverseMesh(callback: (mesh: Mesh) => void) {
128
+ // 等待加载完成
129
+ await this.awaitLoaded();
107
130
 
108
131
  this.traverse(obj => {
109
132
  const mesh = obj as Mesh;
@@ -113,8 +136,22 @@ export default class MeshBase extends Group {
113
136
  });
114
137
  }
115
138
 
116
- updateMatrix(): void {
139
+ clock = new Clock();
117
140
 
141
+ //设置动画的权重
142
+ async setClipActionWeight(weights: { [key: string]: number } = {}) {
143
+ // 等待加载完成
144
+ await this.awaitLoaded();
145
+ for (let key in this.animationActions) {
146
+ this.animationActions[key].weight = weights[key] || 0;
147
+ }
148
+ }
149
+
150
+ updateMatrix(): void {
151
+ //播放动画
152
+ if (this.mixer) {
153
+ this.mixer.update(this.clock.getDelta());
154
+ }
118
155
  // 深度应用属性
119
156
  this.traverse(obj => {
120
157
  const mesh = obj as Mesh;
@@ -128,39 +165,27 @@ export default class MeshBase extends Group {
128
165
  super.updateMatrix();
129
166
  }
130
167
 
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
168
  // 获取模型的尺寸
148
- getSize() {
169
+ async getSize() {
170
+ await this.awaitLoaded();
149
171
  return threeUtils.getSize(this);
150
172
  }
151
173
 
152
174
  // 居中
153
- center() {
175
+ async center() {
176
+ await this.awaitLoaded();
154
177
  threeUtils.center(this);
155
178
  }
156
179
 
157
180
  //底对齐
158
- alignBottom(y: number = 0) {
181
+ async alignBottom(y: number = 0) {
182
+ await this.awaitLoaded();
159
183
  threeUtils.alignBottom(this, y);
160
184
  }
161
185
 
162
186
  // 放大到指定尺寸
163
- scaleTo(size: number = 1, key: Array<"x" | "y" | "z"> = ["x", "y", "z"]) {
187
+ async scaleTo(size: number = 1, key: Array<"x" | "y" | "z"> = ["x", "y", "z"]) {
188
+ await this.awaitLoaded();
164
189
  threeUtils.scaleTo(this, size, key);
165
190
  }
166
191
 
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.29",
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 = () => {