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.
- package/InstancedMeshBase.d.ts +1 -1
- package/InstancedMeshBase.js +4 -21
- package/InstancedMeshBase.ts +3 -19
- package/MeshBase.d.ts +3 -2
- package/MeshBase.js +10 -41
- package/MeshBase.ts +11 -37
- package/ThreeBase.d.ts +3 -3
- package/Transition.d.ts +14 -19
- package/Transition.js +14 -6
- package/Transition.ts +38 -19
- package/package.json +1 -1
- package/threeLoader.d.ts +1 -1
- package/threeLoader.js +23 -9
- package/threeLoader.ts +24 -9
package/InstancedMeshBase.d.ts
CHANGED
|
@@ -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;
|
package/InstancedMeshBase.js
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
38
|
-
|
|
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);
|
package/InstancedMeshBase.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
34
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
93
|
+
//结束的事件回调
|
|
94
|
+
private onDoneCall = (josn: T) => { };
|
|
86
95
|
|
|
87
96
|
// 执行过度动画
|
|
88
97
|
run({ timeTemp }: any) {
|
|
89
98
|
this.timeTemp = timeTemp;
|
|
90
|
-
|
|
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:
|
|
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
|
|
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:
|
|
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.
|
|
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:
|
|
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
|
|
239
|
+
getKeys(): Array<Extract<keyof T, string>> {
|
|
221
240
|
return [...this._keys];
|
|
222
241
|
}
|
|
223
242
|
|
|
224
243
|
// 判断是否有这个参数
|
|
225
|
-
hasKey(key: keyof T
|
|
244
|
+
hasKey(key: Extract<keyof T, string>): boolean {
|
|
226
245
|
return this._keys.includes(key);
|
|
227
246
|
}
|
|
228
247
|
|
|
229
248
|
// 获取全部参数
|
|
230
|
-
getJson():
|
|
249
|
+
getJson(): T {
|
|
231
250
|
let keys = this.getKeys();
|
|
232
251
|
|
|
233
|
-
let json:
|
|
252
|
+
let json: T = {} as T;
|
|
234
253
|
|
|
235
254
|
keys.map(key => {
|
|
236
255
|
json[key] = this.get(key);
|
package/package.json
CHANGED
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,
|
|
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 (
|
|
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 (
|
|
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 (
|
|
144
|
-
await threeLoader.
|
|
145
|
-
|
|
146
|
-
Object3d =
|
|
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
|
-
|
|
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 (
|
|
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 (
|
|
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 (
|
|
171
|
-
await threeLoader.
|
|
172
|
-
|
|
173
|
-
Object3d =
|
|
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
|
-
|
|
189
|
+
if (suffix) {
|
|
190
|
+
console.error(`${suffix},不支持的格式`);
|
|
191
|
+
} else {
|
|
192
|
+
console.error(`${url},不支持的格式,请尝试使用 suffix 参数来指定一下格式`);
|
|
193
|
+
}
|
|
179
194
|
}
|
|
180
195
|
|
|
181
196
|
return Object3d;
|