three-base 2.0.58 → 2.0.60

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.
@@ -13,7 +13,7 @@ export default class InstancedMeshBase extends MeshBase {
13
13
  static matrix: Matrix4;
14
14
  instanceMatrix: InstancedBufferAttribute;
15
15
  instanceColor: InstancedBufferAttribute;
16
- loadModel(url: string): Promise<void>;
16
+ loadModel(url: string, filename?: string): Promise<void>;
17
17
  computeBoundingSphere: import("lodash").DebouncedFunc<() => void>;
18
18
  setCount(count?: number): void;
19
19
  setMatrixAt(index: number, matrix: Matrix4): void;
@@ -5,7 +5,7 @@
5
5
  * @Last Modified time: 2024-06-07 22:14:53
6
6
  */
7
7
  import { throttle } from "lodash";
8
- import { InstancedBufferAttribute, InstancedMesh, Matrix4, Object3D, Vector3 } from "three";
8
+ import { InstancedBufferAttribute, InstancedMesh, Matrix4, Vector3 } from "three";
9
9
  import MeshBase from "./MeshBase";
10
10
  import threeUtils from "./threeUtils";
11
11
  import threeLoader from "./threeLoader";
@@ -25,7 +25,7 @@ export default class InstancedMeshBase extends MeshBase {
25
25
  instanceMatrix = new InstancedBufferAttribute(new Float32Array(0 * 16), 16);
26
26
  instanceColor = new InstancedBufferAttribute(new Float32Array(0 * 3), 3);
27
27
  // 重构加载模型的方法
28
- async loadModel(url) {
28
+ async loadModel(url, filename = "") {
29
29
  if (!url) {
30
30
  this.clear();
31
31
  return;
@@ -34,25 +34,8 @@ export default class InstancedMeshBase extends MeshBase {
34
34
  // 没有模型并且没有加载任务时就去加载模型
35
35
  if (!MeshBase.models.get(url) && !MeshBase.loadModeling.get(url)) {
36
36
  MeshBase.loadModeling.set(url, true);
37
- let modal = new Object3D();
38
- if (/\.fbx$/i.test(url)) {
39
- await threeLoader.fbxLoader.loadAsync(url).then(res => {
40
- modal = res;
41
- }).catch(() => {
42
- console.error(`${url},加载失败`);
43
- });
44
- }
45
- else if (/\.(gltf|glb)$/i.test(url)) {
46
- await threeLoader.gltfLoader.loadAsync(url).then(res => {
47
- modal = res.scene;
48
- modal.animations = res.animations;
49
- }).catch(() => {
50
- console.error(`${url},加载失败`);
51
- });
52
- }
53
- else {
54
- console.error(`${url},不支持的格式`);
55
- }
37
+ // 万能加载器
38
+ let modal = await threeLoader.loadModal(url, filename);
56
39
  threeUtils.center(modal);
57
40
  threeUtils.alignBottom(modal);
58
41
  modal.updateMatrixWorld(true);
@@ -40,7 +40,7 @@ export default class InstancedMeshBase extends MeshBase {
40
40
  instanceColor = new InstancedBufferAttribute(new Float32Array(0 * 3), 3);
41
41
 
42
42
  // 重构加载模型的方法
43
- async loadModel(url: string) {
43
+ async loadModel(url: string, filename: string = "") {
44
44
  if (!url) {
45
45
  this.clear();
46
46
  return;
@@ -52,24 +52,8 @@ export default class InstancedMeshBase extends MeshBase {
52
52
  if (!MeshBase.models.get(url) && !MeshBase.loadModeling.get(url)) {
53
53
  MeshBase.loadModeling.set(url, true);
54
54
 
55
- let modal = new Object3D();
56
-
57
- if (/\.fbx$/i.test(url)) {
58
- await threeLoader.fbxLoader.loadAsync(url).then(res => {
59
- modal = res;
60
- }).catch(() => {
61
- console.error(`${url},加载失败`);
62
- })
63
- } else if (/\.(gltf|glb)$/i.test(url)) {
64
- await threeLoader.gltfLoader.loadAsync(url).then(res => {
65
- modal = res.scene;
66
- modal.animations = res.animations;
67
- }).catch(() => {
68
- console.error(`${url},加载失败`);
69
- })
70
- } else {
71
- console.error(`${url},不支持的格式`);
72
- }
55
+ // 万能加载器
56
+ let modal = await threeLoader.loadModal(url, filename);
73
57
 
74
58
  threeUtils.center(modal);
75
59
  threeUtils.alignBottom(modal);
package/MeshBase.d.ts CHANGED
@@ -9,7 +9,8 @@ export default class MeshBase extends Group {
9
9
  animationActions: {
10
10
  [key: string]: AnimationAction;
11
11
  };
12
- loadModel(url: string, suffix?: string): Promise<void>;
12
+ getSuffix(filename: string): string;
13
+ loadModel(url: string, filename?: string): Promise<void>;
13
14
  frustumCulled: boolean;
14
15
  castShadow: boolean;
15
16
  receiveShadow: boolean;
@@ -20,7 +21,7 @@ export default class MeshBase extends Group {
20
21
  [key: string]: number;
21
22
  }): Promise<void>;
22
23
  getAnimas(): string[];
23
- play(anima?: string): void;
24
+ setAnimas(anima?: string): void;
24
25
  stop(): void;
25
26
  updateMatrix(): void;
26
27
  getSize(): Promise<Vector3>;
package/MeshBase.js CHANGED
@@ -1,4 +1,4 @@
1
- import { AnimationMixer, Clock, Group, Object3D, Vector3 } from "three";
1
+ import { AnimationMixer, Clock, Group, Vector3 } from "three";
2
2
  import threeUtils from "./threeUtils";
3
3
  import threeLoader from "./threeLoader";
4
4
  import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils';
@@ -20,8 +20,13 @@ export default class MeshBase extends Group {
20
20
  mixer;
21
21
  //动画剪辑对象数组
22
22
  animationActions = {};
23
+ // 获取文件名的后缀
24
+ getSuffix(filename) {
25
+ const match = filename.match(/\.([^\.]+)$/);
26
+ return match ? match[1].toLowerCase() : '';
27
+ }
23
28
  // 如果url 是blob地址的话,就用suffix字段来制定模型的类型
24
- async loadModel(url, suffix = "") {
29
+ async loadModel(url, filename = "") {
25
30
  if (!url) {
26
31
  this.clear();
27
32
  return;
@@ -30,44 +35,8 @@ export default class MeshBase extends Group {
30
35
  // 没有模型并且没有加载任务时就去加载模型
31
36
  if (!MeshBase.models.get(url) && !MeshBase.loadModeling.get(url)) {
32
37
  MeshBase.loadModeling.set(url, true);
33
- let modal = new Object3D();
34
- if (/\.fbx$/i.test(suffix || url)) {
35
- await threeLoader.fbxLoader.loadAsync(url).then(res => {
36
- modal = res;
37
- }).catch(() => {
38
- console.error(`${url},加载失败`);
39
- });
40
- }
41
- else if (/\.(gltf|glb)$/i.test(suffix || url)) {
42
- await threeLoader.gltfLoader.loadAsync(url).then(res => {
43
- modal = res.scene;
44
- modal.animations = res.animations;
45
- }).catch(() => {
46
- console.error(`${url},加载失败`);
47
- });
48
- }
49
- else if (/\.(usdz)$/i.test(suffix || url)) {
50
- await threeLoader.usdzLoader.loadAsync(url).then(res => {
51
- modal = res; // usdz 目前还不支持骨骼动画
52
- modal.animations = res.animations;
53
- modal.traverse(obj => {
54
- const mesh = obj;
55
- if (mesh.isMesh) {
56
- mesh.material.transparent = true;
57
- }
58
- });
59
- }).catch(() => {
60
- console.error(`${url},加载失败`);
61
- });
62
- }
63
- else {
64
- if (suffix) {
65
- console.error(`${suffix},不支持的格式`);
66
- }
67
- else {
68
- console.error(`${url},不支持的格式,请尝试使用 suffix 参数来指定一下格式`);
69
- }
70
- }
38
+ // 万能加载器
39
+ let modal = await threeLoader.loadModal(url, filename);
71
40
  MeshBase.models.set(url, modal);
72
41
  MeshBase.loadModeling.set(url, false);
73
42
  }
@@ -138,7 +107,7 @@ export default class MeshBase extends Group {
138
107
  return Object.keys(this.animationActions);
139
108
  }
140
109
  //播放指定动画
141
- play(anima = "") {
110
+ setAnimas(anima = "") {
142
111
  this.setClipActionWeight({ [anima]: 1 });
143
112
  }
144
113
  //停止所有动画
package/MeshBase.ts CHANGED
@@ -3,6 +3,7 @@ import { AnimationAction, AnimationMixer, Clock, DoubleSide, Group, Material, Me
3
3
  import threeUtils from "./threeUtils";
4
4
  import threeLoader from "./threeLoader";
5
5
  import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils';
6
+ import { get, includes } from "lodash";
6
7
 
7
8
  // 模型基类
8
9
  export default class MeshBase extends Group {
@@ -29,8 +30,14 @@ export default class MeshBase extends Group {
29
30
  //动画剪辑对象数组
30
31
  animationActions: { [key: string]: AnimationAction } = {};
31
32
 
33
+ // 获取文件名的后缀
34
+ getSuffix(filename: string) {
35
+ const match = filename.match(/\.([^\.]+)$/);
36
+ return match ? match[1].toLowerCase() : '';
37
+ }
38
+
32
39
  // 如果url 是blob地址的话,就用suffix字段来制定模型的类型
33
- async loadModel(url: string, suffix: string = "") {
40
+ async loadModel(url: string, filename: string = "") {
34
41
  if (!url) {
35
42
  this.clear();
36
43
  return;
@@ -42,41 +49,8 @@ export default class MeshBase extends Group {
42
49
  if (!MeshBase.models.get(url) && !MeshBase.loadModeling.get(url)) {
43
50
  MeshBase.loadModeling.set(url, true);
44
51
 
45
- let modal = new Object3D();
46
-
47
- if (/\.fbx$/i.test(suffix || url)) {
48
- await threeLoader.fbxLoader.loadAsync(url).then(res => {
49
- modal = res;
50
- }).catch(() => {
51
- console.error(`${url},加载失败`);
52
- })
53
- } else if (/\.(gltf|glb)$/i.test(suffix || url)) {
54
- await threeLoader.gltfLoader.loadAsync(url).then(res => {
55
- modal = res.scene;
56
- modal.animations = res.animations;
57
- }).catch(() => {
58
- console.error(`${url},加载失败`);
59
- })
60
- } else if (/\.(usdz)$/i.test(suffix || url)) {
61
- await threeLoader.usdzLoader.loadAsync(url).then(res => {
62
- modal = res; // usdz 目前还不支持骨骼动画
63
- modal.animations = res.animations;
64
- modal.traverse(obj => {
65
- const mesh = (obj as Mesh);
66
- if (mesh.isMesh) {
67
- (mesh.material as Material).transparent = true;
68
- }
69
- });
70
- }).catch(() => {
71
- console.error(`${url},加载失败`);
72
- })
73
- } else {
74
- if (suffix) {
75
- console.error(`${suffix},不支持的格式`);
76
- } else {
77
- console.error(`${url},不支持的格式,请尝试使用 suffix 参数来指定一下格式`);
78
- }
79
- }
52
+ // 万能加载器
53
+ let modal = await threeLoader.loadModal(url, filename);
80
54
 
81
55
  MeshBase.models.set(url, modal);
82
56
  MeshBase.loadModeling.set(url, false);
@@ -167,7 +141,7 @@ export default class MeshBase extends Group {
167
141
  }
168
142
 
169
143
  //播放指定动画
170
- play(anima: string = "") {
144
+ setAnimas(anima: string = "") {
171
145
  this.setClipActionWeight({ [anima]: 1 });
172
146
  }
173
147
 
package/ThreeBase.d.ts CHANGED
@@ -25,17 +25,17 @@ export default class ThreeBase extends EventDispatcher {
25
25
  setSize(width: number, height: number): void;
26
26
  controlsDistance: Transition<{
27
27
  distance: number;
28
- }>;
28
+ }, "distance">;
29
29
  controlsCenter: Transition<{
30
30
  x: number;
31
31
  y: number;
32
32
  z: number;
33
- }>;
33
+ }, "x" | "y" | "z">;
34
34
  controlsPosition: Transition<{
35
35
  x: number;
36
36
  y: number;
37
37
  z: number;
38
- }>;
38
+ }, "x" | "y" | "z">;
39
39
  gridHelper: GridHelper;
40
40
  axesHelper: AxesHelper;
41
41
  frame: number;
package/Transition.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- export default class Transition<T extends {
1
+ export type TransitionParame = {
2
2
  [key: string]: number;
3
- }> {
3
+ };
4
+ export default class Transition<T extends TransitionParame, K extends Extract<keyof T, string>> {
4
5
  /**
5
6
  *Creates an instance of transition.
6
7
  * @param {{ [key: string]: number }} // 初始值
@@ -9,7 +10,7 @@ export default class Transition<T extends {
9
10
  * @memberof transition
10
11
  */
11
12
  constructor(param: T, bezier?: [number, number, number, number], duration?: number);
12
- _keys: Array<keyof T & string>;
13
+ _keys: Array<Extract<keyof T, string>>;
13
14
  _bezier: [number, number, number, number];
14
15
  _Xbezier: [number, number, number, number];
15
16
  _Ybezier: [number, number, number, number];
@@ -20,26 +21,20 @@ export default class Transition<T extends {
20
21
  setDuration(duration?: number): this;
21
22
  setDelay(delay?: number): this;
22
23
  _: {
23
- [key: string]: number;
24
+ [key in `${K}_start` | `${K}_end` | `${K}_startTime`]: T[K];
24
25
  };
25
26
  private onChangeCall;
27
+ private onDoneCall;
26
28
  run({ timeTemp }: any): this;
27
29
  runbindThis: any;
28
- onChange(onChangeCall: (josn: {
29
- [key in keyof T]: number;
30
- }) => void): this;
31
- get(key: keyof T & string): number;
32
- set(param: {
33
- [key in keyof T & string]: number;
34
- }): Promise<this>;
35
- reset(param: {
36
- [key in keyof T & string]: number;
37
- }): this;
38
- getKeys(): Array<keyof T & string>;
39
- hasKey(key: keyof T & string): boolean;
40
- getJson(): {
41
- [key in keyof T]: number;
42
- };
30
+ onChange(onChangeCall: (josn: T) => void): this;
31
+ onDone(onDoneCall: (josn: T) => void): this;
32
+ get(key: Extract<keyof T, string>): T[K];
33
+ set(param: T): Promise<this>;
34
+ reset(param: Partial<T>): this;
35
+ getKeys(): Array<Extract<keyof T, string>>;
36
+ hasKey(key: Extract<keyof T, string>): boolean;
37
+ getJson(): T;
43
38
  _isDone: boolean;
44
39
  isDone(): boolean;
45
40
  }
package/Transition.js CHANGED
@@ -59,16 +59,18 @@ export default class Transition {
59
59
  }
60
60
  // 存储 每个参数的 起始位置 起始时间 终止位置 终止时间
61
61
  _ = {};
62
+ // 数据改变的事件回调
62
63
  onChangeCall = (josn) => { };
64
+ //结束的事件回调
65
+ onDoneCall = (josn) => { };
63
66
  // 执行过度动画
64
67
  run({ timeTemp }) {
65
68
  this.timeTemp = timeTemp;
66
- if (!this.onChangeCall || this.isDone()) {
69
+ this.onChangeCall(this.getJson());
70
+ if (this.isDone()) {
71
+ this.onDoneCall(this.getJson());
67
72
  threeUtils.removeEventListener("requestAnimationFrame", this.runbindThis);
68
73
  }
69
- else {
70
- this.onChangeCall(this.getJson());
71
- }
72
74
  return this;
73
75
  }
74
76
  runbindThis = this.run.bind(this);
@@ -78,6 +80,11 @@ export default class Transition {
78
80
  this.onChangeCall(this.getJson());
79
81
  return this;
80
82
  }
83
+ //设置动画对象的
84
+ onDone(onDoneCall) {
85
+ this.onDoneCall = onDoneCall;
86
+ return this;
87
+ }
81
88
  // 计算当前 key 的值
82
89
  get(key) {
83
90
  key = String(key);
@@ -104,7 +111,7 @@ export default class Transition {
104
111
  else if (this._keys.includes(key) && this.timeTemp >= (this._[key + "_startTime"] + this._duration)) {
105
112
  return this._[key + "_end"];
106
113
  }
107
- // `没有 ${key} 的值`;
114
+ // `没有 ${ key } 的值`;
108
115
  return 0;
109
116
  }
110
117
  async set(param) {
@@ -112,7 +119,7 @@ export default class Transition {
112
119
  ;
113
120
  for (let key in param) {
114
121
  // 有就赋值
115
- if (this._keys.includes(key) && Math.abs(param[key] - this._[key + "_end"]) > 0.001) {
122
+ if (this._keys.includes(key) && Math.abs(param[key] - this._[key + "_end"]) > 0.0001) {
116
123
  this._[key + "_start"] = this.get(key);
117
124
  this._[key + "_end"] = param[key];
118
125
  // 起始时间
@@ -155,6 +162,7 @@ export default class Transition {
155
162
  }
156
163
  if (this.onChangeCall) {
157
164
  this.onChangeCall(this.getJson());
165
+ this.onDoneCall(this.getJson());
158
166
  }
159
167
  this._isDone = true;
160
168
  return this;
package/Transition.ts CHANGED
@@ -14,8 +14,13 @@ function bezier(arr: [number, number, number, number], t: number) {
14
14
  return result;
15
15
  }
16
16
 
17
+ export type TransitionParame = {
18
+ // [key: string]: number | Vector2 | Vector3 | Color | `#${string}`
19
+ [key: string]: number
20
+ }
21
+
17
22
  // 过渡动画插件
18
- export default class Transition<T extends { [key: string]: number }> {
23
+ export default class Transition<T extends TransitionParame, K extends Extract<keyof T, string>> {
19
24
 
20
25
  /**
21
26
  *Creates an instance of transition.
@@ -38,7 +43,7 @@ export default class Transition<T extends { [key: string]: number }> {
38
43
  }
39
44
 
40
45
  // 所有的 key 的枚举
41
- _keys: Array<keyof T & string> = [];
46
+ _keys: Array<Extract<keyof T, string>> = [];
42
47
 
43
48
  // 贝塞尔曲线
44
49
  _bezier: [number, number, number, number] = [0.8, 0, 0.2, 1];
@@ -80,34 +85,47 @@ export default class Transition<T extends { [key: string]: number }> {
80
85
  }
81
86
 
82
87
  // 存储 每个参数的 起始位置 起始时间 终止位置 终止时间
83
- _: { [key: string]: number } = {};
88
+ _: { [key in `${K}_start` | `${K}_end` | `${K}_startTime`]: T[K] } = {} as { [key in `${K}_start` | `${K}_end` | `${K}_startTime`]: T[K] };
89
+
90
+ // 数据改变的事件回调
91
+ private onChangeCall = (josn: T) => { };
84
92
 
85
- private onChangeCall = (josn: { [key in keyof T]: number }) => { };
93
+ //结束的事件回调
94
+ private onDoneCall = (josn: T) => { };
86
95
 
87
96
  // 执行过度动画
88
97
  run({ timeTemp }: any) {
89
98
  this.timeTemp = timeTemp;
90
- if (!this.onChangeCall || this.isDone()) {
99
+
100
+ this.onChangeCall(this.getJson());
101
+
102
+ if (this.isDone()) {
103
+ this.onDoneCall(this.getJson());
91
104
  threeUtils.removeEventListener("requestAnimationFrame", this.runbindThis);
92
- } else {
93
- this.onChangeCall(this.getJson());
94
105
  }
106
+
95
107
  return this;
96
108
  }
97
109
 
98
110
  runbindThis = this.run.bind(this);
99
111
 
100
112
  // 设置动画对象的回调事件
101
- onChange(onChangeCall: (josn: { [key in keyof T]: number }) => void): this {
113
+ onChange(onChangeCall: (josn: T) => void): this {
102
114
  this.onChangeCall = onChangeCall;
103
115
  this.onChangeCall(this.getJson());
104
116
  return this;
105
117
  }
106
118
 
119
+ //设置动画对象的
120
+ onDone(onDoneCall: (josn: T) => void): this {
121
+ this.onDoneCall = onDoneCall;
122
+ return this;
123
+ }
124
+
107
125
  // 计算当前 key 的值
108
- get(key: keyof T & string): number {
126
+ get(key: Extract<keyof T, string>): T[K] {
109
127
 
110
- key = String(key);
128
+ key = String(key) as Extract<keyof T, string>;
111
129
 
112
130
  if (this._keys.includes(key) && this.timeTemp < (this._[key + "_startTime"] + this._duration)) {
113
131
 
@@ -141,18 +159,18 @@ export default class Transition<T extends { [key: string]: number }> {
141
159
  return this._[key + "_end"];
142
160
  }
143
161
 
144
- // `没有 ${key} 的值`;
145
- return 0;
162
+ // `没有 ${ key } 的值`;
163
+ return 0 as T[K];
146
164
  }
147
165
 
148
- async set(param: { [key in keyof T & string]: number }): Promise<this> {
166
+ async set(param: T): Promise<this> {
149
167
 
150
168
  let timetemp = performance.now() + this._delay;;
151
169
 
152
170
  for (let key in param) {
153
171
 
154
172
  // 有就赋值
155
- if (this._keys.includes(key) && Math.abs(param[key] - this._[key + "_end"]) > 0.001) {
173
+ if (this._keys.includes(key) && Math.abs(param[key] - this._[key + "_end"]) > 0.0001) {
156
174
 
157
175
  this._[key + "_start"] = this.get(key);
158
176
 
@@ -195,7 +213,7 @@ export default class Transition<T extends { [key: string]: number }> {
195
213
  return this;
196
214
  }
197
215
  // 重置起始和终止位置
198
- reset(param: { [key in keyof T & string]: number }): this {
216
+ reset(param: Partial<T>): this {
199
217
 
200
218
  for (let key in param) {
201
219
 
@@ -210,6 +228,7 @@ export default class Transition<T extends { [key: string]: number }> {
210
228
 
211
229
  if (this.onChangeCall) {
212
230
  this.onChangeCall(this.getJson());
231
+ this.onDoneCall(this.getJson());
213
232
  }
214
233
 
215
234
  this._isDone = true;
@@ -217,20 +236,20 @@ export default class Transition<T extends { [key: string]: number }> {
217
236
  }
218
237
 
219
238
  // 获取过渡对象上面的key
220
- getKeys(): Array<keyof T & string> {
239
+ getKeys(): Array<Extract<keyof T, string>> {
221
240
  return [...this._keys];
222
241
  }
223
242
 
224
243
  // 判断是否有这个参数
225
- hasKey(key: keyof T & string): boolean {
244
+ hasKey(key: Extract<keyof T, string>): boolean {
226
245
  return this._keys.includes(key);
227
246
  }
228
247
 
229
248
  // 获取全部参数
230
- getJson(): { [key in keyof T]: number } {
249
+ getJson(): T {
231
250
  let keys = this.getKeys();
232
251
 
233
- let json: { [key in keyof T]: number } = {} as T;
252
+ let json: T = {} as T;
234
253
 
235
254
  keys.map(key => {
236
255
  json[key] = this.get(key);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-base",
3
- "version": "2.0.58",
3
+ "version": "2.0.60",
4
4
  "description": "three 3d three-base",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
package/threeLoader.d.ts CHANGED
@@ -19,7 +19,7 @@ declare class ThreeLoader extends EventDispatcher {
19
19
  gltfLoader: GLTFLoader;
20
20
  usdzLoader: USDZLoader;
21
21
  /** 加载模型支持glb,fbx,stl,obj */
22
- loadModal(url: string): Promise<Object3D<import("three").Object3DEventMap>>;
22
+ loadModal(url: string, filename?: string): Promise<Object3D<import("three").Object3DEventMap>>;
23
23
  onload: boolean;
24
24
  }
25
25
  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, Mesh, MeshLambertMaterial, Object3D, RepeatWrapping, TextureLoader, VideoTexture } from "three";
7
+ import { CanvasTexture, DefaultLoadingManager, EventDispatcher, 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";
@@ -19,6 +19,7 @@ import dracoWasmWrapperJS from "./lib/draco/draco_wasm_wrapper.js?url";
19
19
  import dracoDecoderJS from "./lib/draco/draco_decoder.js?url";
20
20
  //@ts-ignore
21
21
  import dracoDecoderWASM from "./lib/draco/draco_decoder.wasm?url";
22
+ import { get } from "lodash";
22
23
  // 加载器
23
24
  class ThreeLoader extends EventDispatcher {
24
25
  constructor() {
@@ -123,16 +124,18 @@ class ThreeLoader extends EventDispatcher {
123
124
  //usdz加载器
124
125
  usdzLoader = new USDZLoader();
125
126
  /** 加载模型支持glb,fbx,stl,obj */
126
- async loadModal(url) {
127
+ async loadModal(url, filename = "") {
128
+ // 获取后缀
129
+ const suffix = (get((filename || url).match(/\.([^\.]+)$/), [1]) || "").toLowerCase();
127
130
  let Object3d = new Object3D();
128
- if (/\.fbx$/i.test(url)) {
131
+ if (["fbx"].includes(suffix)) {
129
132
  await threeLoader.fbxLoader.loadAsync(url).then(res => {
130
133
  Object3d = res;
131
134
  }).catch(() => {
132
135
  console.error(`${url},加载失败`);
133
136
  });
134
137
  }
135
- else if (/\.(gltf|glb)$/i.test(url)) {
138
+ else if (["gltf", "glb"].includes(suffix)) {
136
139
  await threeLoader.gltfLoader.loadAsync(url).then(res => {
137
140
  Object3d = res.scene;
138
141
  Object3d.animations = res.animations;
@@ -140,16 +143,27 @@ class ThreeLoader extends EventDispatcher {
140
143
  console.error(`${url},加载失败`);
141
144
  });
142
145
  }
143
- else if (/\.stl$/i.test(url)) {
144
- await threeLoader.stlLoader.loadAsync(url).then(geometry => {
145
- const material = new MeshLambertMaterial();
146
- Object3d = new Mesh(geometry, material);
146
+ else if (["usdz"].includes(suffix)) {
147
+ await threeLoader.usdzLoader.loadAsync(url).then(res => {
148
+ Object3d = res; // usdz 目前还不支持骨骼动画
149
+ Object3d.animations = res.animations;
150
+ Object3d.traverse(obj => {
151
+ const mesh = obj;
152
+ if (mesh.isMesh) {
153
+ mesh.material.transparent = true;
154
+ }
155
+ });
147
156
  }).catch(() => {
148
157
  console.error(`${url},加载失败`);
149
158
  });
150
159
  }
151
160
  else {
152
- throw new Error(`${url},不支持的格式`);
161
+ if (suffix) {
162
+ console.error(`${suffix},不支持的格式`);
163
+ }
164
+ else {
165
+ console.error(`${url},不支持的格式,请尝试使用 suffix 参数来指定一下格式`);
166
+ }
153
167
  }
154
168
  return Object3d;
155
169
  }
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, Mesh, MeshLambertMaterial, Object3D, RepeatWrapping, SRGBColorSpace, Texture, TextureLoader, VideoTexture } from "three";
8
+ import { CanvasTexture, DefaultLoadingManager, EventDispatcher, Material, 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";
@@ -22,6 +22,7 @@ import dracoWasmWrapperJS from "./lib/draco/draco_wasm_wrapper.js?url";
22
22
  import dracoDecoderJS from "./lib/draco/draco_decoder.js?url";
23
23
  //@ts-ignore
24
24
  import dracoDecoderWASM from "./lib/draco/draco_decoder.wasm?url";
25
+ import { get } from "lodash";
25
26
 
26
27
  // 加载器
27
28
  class ThreeLoader extends EventDispatcher {
@@ -151,31 +152,45 @@ class ThreeLoader extends EventDispatcher {
151
152
  usdzLoader = new USDZLoader();
152
153
 
153
154
  /** 加载模型支持glb,fbx,stl,obj */
154
- async loadModal(url: string) {
155
+ async loadModal(url: string, filename: string = "") {
156
+
157
+ // 获取后缀
158
+ const suffix = (get((filename || url).match(/\.([^\.]+)$/), [1]) || "").toLowerCase();
159
+
155
160
  let Object3d = new Object3D();
156
161
 
157
- if (/\.fbx$/i.test(url)) {
162
+ if (["fbx"].includes(suffix)) {
158
163
  await threeLoader.fbxLoader.loadAsync(url).then(res => {
159
164
  Object3d = res;
160
165
  }).catch(() => {
161
166
  console.error(`${url},加载失败`);
162
167
  })
163
- } else if (/\.(gltf|glb)$/i.test(url)) {
168
+ } else if (["gltf", "glb"].includes(suffix)) {
164
169
  await threeLoader.gltfLoader.loadAsync(url).then(res => {
165
170
  Object3d = res.scene;
166
171
  Object3d.animations = res.animations;
167
172
  }).catch(() => {
168
173
  console.error(`${url},加载失败`);
169
174
  })
170
- } else if (/\.stl$/i.test(url)) {
171
- await threeLoader.stlLoader.loadAsync(url).then(geometry => {
172
- const material = new MeshLambertMaterial();
173
- Object3d = new Mesh(geometry, material);
175
+ } else if (["usdz"].includes(suffix)) {
176
+ await threeLoader.usdzLoader.loadAsync(url).then(res => {
177
+ Object3d = res; // usdz 目前还不支持骨骼动画
178
+ Object3d.animations = res.animations;
179
+ Object3d.traverse(obj => {
180
+ const mesh = (obj as Mesh);
181
+ if (mesh.isMesh) {
182
+ (mesh.material as Material).transparent = true;
183
+ }
184
+ });
174
185
  }).catch(() => {
175
186
  console.error(`${url},加载失败`);
176
187
  })
177
188
  } else {
178
- throw new Error(`${url},不支持的格式`);
189
+ if (suffix) {
190
+ console.error(`${suffix},不支持的格式`);
191
+ } else {
192
+ console.error(`${url},不支持的格式,请尝试使用 suffix 参数来指定一下格式`);
193
+ }
179
194
  }
180
195
 
181
196
  return Object3d;