u-space 0.0.3 → 0.0.5
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/dist/index.cjs +1 -2074
- package/dist/index.js +874 -1507
- package/dist/plugins/u-manager/index.cjs +2 -2
- package/dist/plugins/u-manager/index.js +54 -43
- package/dist/src/objects/Model.d.ts +14 -1
- package/dist/src/objects/Poi.d.ts +4 -0
- package/dist/src/viewers/Viewer.d.ts +4 -0
- package/docs/api-objects.md +58 -0
- package/docs/api-viewer.md +6 -4
- package/docs/examples-guide.md +14 -0
- package/package.json +1 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
|
@@ -3342,16 +3342,27 @@ function requireWhichTypedArray() {
|
|
|
3342
3342
|
var O = r(E);
|
|
3343
3343
|
S = p(O, Symbol.toStringTag);
|
|
3344
3344
|
}
|
|
3345
|
-
|
|
3345
|
+
if (S && S.get) {
|
|
3346
|
+
var C = b(S.get);
|
|
3347
|
+
s[
|
|
3348
|
+
/** @type {`$${import('.').TypedArrayName}`} */
|
|
3349
|
+
"$" + m
|
|
3350
|
+
] = C;
|
|
3351
|
+
}
|
|
3346
3352
|
}
|
|
3347
3353
|
}) : h(n, function(m) {
|
|
3348
3354
|
var A = new t[m](), E = A.slice || A.set;
|
|
3349
|
-
E
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
+
if (E) {
|
|
3356
|
+
var S = (
|
|
3357
|
+
/** @type {import('./types').BoundSlice | import('./types').BoundSet} */
|
|
3358
|
+
// @ts-expect-error TODO FIXME
|
|
3359
|
+
b(E)
|
|
3360
|
+
);
|
|
3361
|
+
s[
|
|
3362
|
+
/** @type {`$${import('.').TypedArrayName}`} */
|
|
3363
|
+
"$" + m
|
|
3364
|
+
] = S;
|
|
3365
|
+
}
|
|
3355
3366
|
});
|
|
3356
3367
|
var l = function(A) {
|
|
3357
3368
|
var E = !1;
|
|
@@ -4591,43 +4602,11 @@ function require_stream_duplex$1() {
|
|
|
4591
4602
|
}
|
|
4592
4603
|
}), _stream_duplex$1;
|
|
4593
4604
|
}
|
|
4594
|
-
var string_decoder = {},
|
|
4595
|
-
function requireSafeBuffer() {
|
|
4596
|
-
return hasRequiredSafeBuffer || (hasRequiredSafeBuffer = 1, (function(h, d) {
|
|
4597
|
-
var b = requireDist(), u = b.Buffer;
|
|
4598
|
-
function p(f, o) {
|
|
4599
|
-
for (var t in f)
|
|
4600
|
-
o[t] = f[t];
|
|
4601
|
-
}
|
|
4602
|
-
u.from && u.alloc && u.allocUnsafe && u.allocUnsafeSlow ? h.exports = b : (p(b, d), d.Buffer = r);
|
|
4603
|
-
function r(f, o, t) {
|
|
4604
|
-
return u(f, o, t);
|
|
4605
|
-
}
|
|
4606
|
-
p(u, r), r.from = function(f, o, t) {
|
|
4607
|
-
if (typeof f == "number")
|
|
4608
|
-
throw new TypeError("Argument must not be a number");
|
|
4609
|
-
return u(f, o, t);
|
|
4610
|
-
}, r.alloc = function(f, o, t) {
|
|
4611
|
-
if (typeof f != "number")
|
|
4612
|
-
throw new TypeError("Argument must be a number");
|
|
4613
|
-
var n = u(f);
|
|
4614
|
-
return o !== void 0 ? typeof t == "string" ? n.fill(o, t) : n.fill(o) : n.fill(0), n;
|
|
4615
|
-
}, r.allocUnsafe = function(f) {
|
|
4616
|
-
if (typeof f != "number")
|
|
4617
|
-
throw new TypeError("Argument must be a number");
|
|
4618
|
-
return u(f);
|
|
4619
|
-
}, r.allocUnsafeSlow = function(f) {
|
|
4620
|
-
if (typeof f != "number")
|
|
4621
|
-
throw new TypeError("Argument must be a number");
|
|
4622
|
-
return b.SlowBuffer(f);
|
|
4623
|
-
};
|
|
4624
|
-
})(safeBuffer, safeBuffer.exports)), safeBuffer.exports;
|
|
4625
|
-
}
|
|
4626
|
-
var hasRequiredString_decoder;
|
|
4605
|
+
var string_decoder = {}, hasRequiredString_decoder;
|
|
4627
4606
|
function requireString_decoder() {
|
|
4628
4607
|
if (hasRequiredString_decoder) return string_decoder;
|
|
4629
4608
|
hasRequiredString_decoder = 1;
|
|
4630
|
-
var h = requireSafeBuffer().Buffer, d = h.isEncoding || function(E) {
|
|
4609
|
+
var h = requireSafeBuffer$1().Buffer, d = h.isEncoding || function(E) {
|
|
4631
4610
|
switch (E = "" + E, E && E.toLowerCase()) {
|
|
4632
4611
|
case "hex":
|
|
4633
4612
|
case "utf8":
|
|
@@ -5688,6 +5667,38 @@ var streamBrowser, hasRequiredStreamBrowser;
|
|
|
5688
5667
|
function requireStreamBrowser() {
|
|
5689
5668
|
return hasRequiredStreamBrowser || (hasRequiredStreamBrowser = 1, streamBrowser = requireEvents().EventEmitter), streamBrowser;
|
|
5690
5669
|
}
|
|
5670
|
+
var safeBuffer = { exports: {} }, hasRequiredSafeBuffer;
|
|
5671
|
+
function requireSafeBuffer() {
|
|
5672
|
+
return hasRequiredSafeBuffer || (hasRequiredSafeBuffer = 1, (function(h, d) {
|
|
5673
|
+
var b = requireDist(), u = b.Buffer;
|
|
5674
|
+
function p(f, o) {
|
|
5675
|
+
for (var t in f)
|
|
5676
|
+
o[t] = f[t];
|
|
5677
|
+
}
|
|
5678
|
+
u.from && u.alloc && u.allocUnsafe && u.allocUnsafeSlow ? h.exports = b : (p(b, d), d.Buffer = r);
|
|
5679
|
+
function r(f, o, t) {
|
|
5680
|
+
return u(f, o, t);
|
|
5681
|
+
}
|
|
5682
|
+
p(u, r), r.from = function(f, o, t) {
|
|
5683
|
+
if (typeof f == "number")
|
|
5684
|
+
throw new TypeError("Argument must not be a number");
|
|
5685
|
+
return u(f, o, t);
|
|
5686
|
+
}, r.alloc = function(f, o, t) {
|
|
5687
|
+
if (typeof f != "number")
|
|
5688
|
+
throw new TypeError("Argument must be a number");
|
|
5689
|
+
var n = u(f);
|
|
5690
|
+
return o !== void 0 ? typeof t == "string" ? n.fill(o, t) : n.fill(o) : n.fill(0), n;
|
|
5691
|
+
}, r.allocUnsafe = function(f) {
|
|
5692
|
+
if (typeof f != "number")
|
|
5693
|
+
throw new TypeError("Argument must be a number");
|
|
5694
|
+
return u(f);
|
|
5695
|
+
}, r.allocUnsafeSlow = function(f) {
|
|
5696
|
+
if (typeof f != "number")
|
|
5697
|
+
throw new TypeError("Argument must be a number");
|
|
5698
|
+
return b.SlowBuffer(f);
|
|
5699
|
+
};
|
|
5700
|
+
})(safeBuffer, safeBuffer.exports)), safeBuffer.exports;
|
|
5701
|
+
}
|
|
5691
5702
|
var util = {}, hasRequiredUtil;
|
|
5692
5703
|
function requireUtil() {
|
|
5693
5704
|
if (hasRequiredUtil) return util;
|
|
@@ -9898,7 +9909,7 @@ function requireBn$1() {
|
|
|
9898
9909
|
var _ = 67108863 ^ 67108863 >>> g << g;
|
|
9899
9910
|
this.words[this.length - 1] &= _;
|
|
9900
9911
|
}
|
|
9901
|
-
return this.strip();
|
|
9912
|
+
return this.length === 0 && (this.words[0] = 0, this.length = 1), this.strip();
|
|
9902
9913
|
}, r.prototype.maskn = function(v) {
|
|
9903
9914
|
return this.clone().imaskn(v);
|
|
9904
9915
|
}, r.prototype.iaddn = function(v) {
|
|
@@ -11279,7 +11290,7 @@ function requireBn() {
|
|
|
11279
11290
|
var q = 67108863 ^ 67108863 >>> _ << _;
|
|
11280
11291
|
this.words[this.length - 1] &= q;
|
|
11281
11292
|
}
|
|
11282
|
-
return this._strip();
|
|
11293
|
+
return this.length === 0 && (this.words[0] = 0, this.length = 1), this._strip();
|
|
11283
11294
|
}, r.prototype.maskn = function(c) {
|
|
11284
11295
|
return this.clone().imaskn(c);
|
|
11285
11296
|
}, r.prototype.iaddn = function(c) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Object3D } from 'three/webgpu';
|
|
1
|
+
import { type Object3D, AnimationMixer, type AnimationAction, type AnimationClip } from 'three/webgpu';
|
|
2
2
|
import { type InteractionEventMap } from '../interactions';
|
|
3
3
|
import { BaseGroup } from './BaseGroup';
|
|
4
4
|
export interface ModelParameters {
|
|
@@ -6,12 +6,25 @@ export interface ModelParameters {
|
|
|
6
6
|
cache?: boolean;
|
|
7
7
|
persistent?: boolean;
|
|
8
8
|
}
|
|
9
|
+
export interface PlayAnimationOptions {
|
|
10
|
+
loop?: boolean;
|
|
11
|
+
repetitions?: number;
|
|
12
|
+
timeScale?: number;
|
|
13
|
+
clampWhenFinished?: boolean;
|
|
14
|
+
}
|
|
9
15
|
export declare class Model extends BaseGroup<InteractionEventMap> {
|
|
10
16
|
readonly isModel = true;
|
|
11
17
|
type: string;
|
|
12
18
|
private static memoryCache;
|
|
19
|
+
mixer: AnimationMixer | null;
|
|
20
|
+
animations: AnimationClip[];
|
|
21
|
+
private actions;
|
|
13
22
|
constructor();
|
|
14
23
|
loadAsync(parameters: ModelParameters): Promise<Object3D<import("three").Object3DEventMap> | null>;
|
|
24
|
+
playAnimation(nameOrIndex?: string | number, options?: PlayAnimationOptions): AnimationAction | null;
|
|
25
|
+
playAllAnimations(options?: PlayAnimationOptions): AnimationAction[];
|
|
26
|
+
stopAnimation(nameOrIndex?: string | number): void;
|
|
27
|
+
updateAnimation(delta: number): void;
|
|
15
28
|
static clearMemoryCache(): void;
|
|
16
29
|
static clearPersistentCache(): Promise<void>;
|
|
17
30
|
}
|
|
@@ -21,11 +21,15 @@ export interface PoiParameters {
|
|
|
21
21
|
borderRadius?: number;
|
|
22
22
|
/** Text position relative to the icon */
|
|
23
23
|
textPosition?: 'top' | 'bottom' | 'left' | 'right';
|
|
24
|
+
/** Scale factor for mapping canvas pixels to world units */
|
|
25
|
+
scaleFactor?: number;
|
|
24
26
|
}
|
|
25
27
|
export declare class Poi extends BaseSprite<InteractionEventMap> {
|
|
26
28
|
readonly isPoi = true;
|
|
27
29
|
type: string;
|
|
28
30
|
parameters: Required<PoiParameters>;
|
|
31
|
+
private _canvas;
|
|
32
|
+
private _lastParametersJSON;
|
|
29
33
|
constructor(parameters?: PoiParameters);
|
|
30
34
|
/**
|
|
31
35
|
* Update the POI with new parameters
|
|
@@ -14,15 +14,19 @@ export interface ViewerOptions {
|
|
|
14
14
|
export interface ViewerEventMap {
|
|
15
15
|
beforeControlsUpdate: {
|
|
16
16
|
time: number;
|
|
17
|
+
delta: number;
|
|
17
18
|
};
|
|
18
19
|
afterControlsUpdate: {
|
|
19
20
|
time: number;
|
|
21
|
+
delta: number;
|
|
20
22
|
};
|
|
21
23
|
beforeRender: {
|
|
22
24
|
time: number;
|
|
25
|
+
delta: number;
|
|
23
26
|
};
|
|
24
27
|
afterRender: {
|
|
25
28
|
time: number;
|
|
29
|
+
delta: number;
|
|
26
30
|
};
|
|
27
31
|
cameraChange: {
|
|
28
32
|
camera: PerspectiveCamera | OrthographicCamera;
|
package/docs/api-objects.md
CHANGED
|
@@ -66,6 +66,64 @@ const model3 = new Model();
|
|
|
66
66
|
model3.loadAsync({ url: 'model.glb', cache: true, persistent: true });
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
+
### 动画
|
|
70
|
+
|
|
71
|
+
`Model` 在加载含内置动画的模型(如 glTF/FBX)后,会自动初始化 `AnimationMixer` 并收集 `AnimationClip`。
|
|
72
|
+
|
|
73
|
+
**属性:**
|
|
74
|
+
|
|
75
|
+
| 属性 | 类型 | 说明 |
|
|
76
|
+
| :----------- | :-------------------------- | :----------------------------------------- |
|
|
77
|
+
| `mixer` | `AnimationMixer \| null` | 动画混合器,加载含动画模型后自动创建。 |
|
|
78
|
+
| `animations` | `AnimationClip[]` | 模型内置的动画片段列表。 |
|
|
79
|
+
|
|
80
|
+
#### `playAnimation(nameOrIndex?, options?)`
|
|
81
|
+
|
|
82
|
+
播放指定动画。不传参时播放第一个动画。
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
// 按名称播放
|
|
86
|
+
model.playAnimation('Walk');
|
|
87
|
+
|
|
88
|
+
// 按索引播放
|
|
89
|
+
model.playAnimation(0);
|
|
90
|
+
|
|
91
|
+
// 带选项
|
|
92
|
+
model.playAnimation('Run', {
|
|
93
|
+
loop: true, // 是否循环(默认 true)
|
|
94
|
+
repetitions: 3, // 循环次数(默认 Infinity)
|
|
95
|
+
timeScale: 1.5, // 播放速度(默认 1)
|
|
96
|
+
clampWhenFinished: true, // 播放结束后停留在最后一帧(默认 false)
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
#### `playAllAnimations(options?)`
|
|
101
|
+
|
|
102
|
+
播放模型所有内置动画。参数同 `playAnimation`。
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
model.playAllAnimations({ timeScale: 2 });
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
#### `stopAnimation(nameOrIndex?)`
|
|
109
|
+
|
|
110
|
+
停止指定动画。不传参时停止所有动画。
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
model.stopAnimation('Walk'); // 停止指定动画
|
|
114
|
+
model.stopAnimation(); // 停止所有动画
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### `updateAnimation(delta)`
|
|
118
|
+
|
|
119
|
+
推进动画时间,需在渲染循环中调用。`delta` 为帧间隔时间(秒),可从 Viewer 事件的 `delta` 属性获取。
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
viewer.addEventListener('beforeRender', (e) => {
|
|
123
|
+
model.updateAnimation(e.delta);
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
69
127
|
### 清除缓存
|
|
70
128
|
|
|
71
129
|
可通过 `Model` 类的静态方法手动清除内部缓存:
|
package/docs/api-viewer.md
CHANGED
|
@@ -158,8 +158,10 @@ viewer.dispose();
|
|
|
158
158
|
|
|
159
159
|
Viewer 继承自 `EventDispatcher`,会触发以下事件:
|
|
160
160
|
|
|
161
|
-
- `beforeControlsUpdate`:在 `CameraControls` 更新之前触发,提供 `{ time: number }`。
|
|
162
|
-
- `afterControlsUpdate`:在 `CameraControls` 更新之后触发,提供 `{ time: number }`。
|
|
163
|
-
- `beforeRender`:在 `renderer.render` 调用之前立即触发,提供 `{ time: number }`。
|
|
164
|
-
- `afterRender`:在 `renderer.render` 完成之后立即触发,提供 `{ time: number }`。
|
|
161
|
+
- `beforeControlsUpdate`:在 `CameraControls` 更新之前触发,提供 `{ time: number; delta: number }`。
|
|
162
|
+
- `afterControlsUpdate`:在 `CameraControls` 更新之后触发,提供 `{ time: number; delta: number }`。
|
|
163
|
+
- `beforeRender`:在 `renderer.render` 调用之前立即触发,提供 `{ time: number; delta: number }`。
|
|
164
|
+
- `afterRender`:在 `renderer.render` 完成之后立即触发,提供 `{ time: number; delta: number }`。
|
|
165
165
|
- `cameraChange`:调用 `setCamera` 时触发,提供 `{ camera: Camera }`。
|
|
166
|
+
|
|
167
|
+
其中 `delta` 为上一帧到当前帧的时间间隔(秒),可用于动画更新等场景。
|
package/docs/examples-guide.md
CHANGED
|
@@ -46,3 +46,17 @@
|
|
|
46
46
|
- 流式传输结构化场景布局,解析场景描述(`SceneLoader`、`TopologiesLoader`)。
|
|
47
47
|
- 使用相机动画(`VisionsLoader` 和 `VisionsParser`)在场景中编排预定义的飞行路径。
|
|
48
48
|
- 获取复杂的节点材质,并自定义 WebGPU 专属的 TSL(Three Shading Language)节点,如 `TSLEffects.fluid()`。
|
|
49
|
+
|
|
50
|
+
## 5. `test_model_animation.html`:模型内置动画
|
|
51
|
+
|
|
52
|
+
[在线演示](https://u-space-phi.vercel.app/examples/test_model_animation.html)
|
|
53
|
+
|
|
54
|
+
该示例演示了如何加载含内置动画的 glTF 模型,并通过 `Model` 类的动画 API 控制播放。
|
|
55
|
+
|
|
56
|
+
### 核心要点:
|
|
57
|
+
|
|
58
|
+
- 使用 `Model.loadAsync()` 加载带动画的 `.glb` 文件,动画片段自动初始化。
|
|
59
|
+
- 使用 `viewer.frameloop = 'always'` 开启持续渲染以驱动动画。
|
|
60
|
+
- 监听 `beforeRender` 事件,通过 `model.updateAnimation(e.delta)` 推进动画时间。
|
|
61
|
+
- 使用 `model.playAnimation(name)` 按名称播放单个动画,`model.playAllAnimations()` 播放全部。
|
|
62
|
+
- 使用 `model.stopAnimation()` 停止动画播放。
|