@nebula-spatial/viewer 0.4.0 → 0.4.1
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/CHANGELOG.md +6 -0
- package/README.md +19 -16
- package/dist/assets/types.d.ts +6 -5
- package/dist/{index-Lsk3kHNe.js → index-D0lW4RQP.js} +3 -3
- package/dist/index.js +1 -1
- package/dist/session-B4uKXhdV.js +266 -0
- package/dist/{session-B_UiRctl.js → session-DNMxzxd5.js} +2 -2
- package/dist/{stage-BxROW_dP.js → stage-CFr9ZkwQ.js} +1 -1
- package/dist/{usd-session-Dcd20Z6G.js → usd-session-DDWM5msM.js} +2 -2
- package/package.json +57 -57
- package/dist/session-CGaj14lM.js +0 -93
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this package are documented in this file.
|
|
4
4
|
|
|
5
|
+
## 0.4.1
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- 内置普通模型预览新增 FBX 格式,支持按 `.fbx` 扩展名自动识别,并复用模型舞台、相机适配、up-axis 切换和资源释放契约;FBX 优先按文件 `GlobalSettings` 的正向 Y/Z up-axis 声明转换到 Viewer 的 Z-up 世界,无法判断时回退 Y-up,并可由显式 `upAxis` 覆盖;FBXLoader 生成的传统 Lambert/Phong 材质会转换为可由 Viewer 环境光照明的 PBR 材质。
|
|
10
|
+
|
|
5
11
|
## 0.4.0
|
|
6
12
|
|
|
7
13
|
0.4.0 将 Viewer 从以 CAD 为主的 facade 扩展为统一资产预览器,并把 3D 模型与仿真资产接入同一个 Three.js 场景、相机、渲染器和帧循环。CAD 专属状态仍保留在 `viewer.cad`,但资产生命周期、内置 UI、加载状态和扩展机制已统一。
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @nebula-spatial/viewer
|
|
2
2
|
|
|
3
3
|
浏览器侧只读 Three.js 统一资产 Viewer Facade。负责场景运行时、相机、输入、拾取、渲染循环和
|
|
4
|
-
资源释放;`openAsset()` 统一加载 CAD、GLB/glTF、URDF、MJCF 与 USD,`viewer.cad` 保留与
|
|
4
|
+
资源释放;`openAsset()` 统一加载 CAD、GLB/glTF、FBX、URDF、MJCF 与 USD,`viewer.cad` 保留与
|
|
5
5
|
`@nebula-spatial/cad-loader` 集成的兼容能力。
|
|
6
6
|
|
|
7
7
|
Viewer 不解析 DXF/DWG,也不提供编辑命令、历史记录或业务状态管理。
|
|
@@ -211,6 +211,8 @@ Three.js Camera。应用成功后会同步发布 `camera-change` 和 `viewport-c
|
|
|
211
211
|
|
|
212
212
|
```ts
|
|
213
213
|
const preview = viewer.openAsset('/models/robot.glb', { format: 'auto' });
|
|
214
|
+
// .fbx 扩展名同样可自动识别:
|
|
215
|
+
const fbxPreview = viewer.openAsset('/models/chair.fbx');
|
|
214
216
|
const stop = preview.subscribe((snapshot) => updateLoadingUi(snapshot));
|
|
215
217
|
await preview.ready;
|
|
216
218
|
await preview.close();
|
|
@@ -221,7 +223,7 @@ stop();
|
|
|
221
223
|
旧句柄的 `close()` 只等待自己的资源清理,不会关闭后来打开的资产。`closeAsset()` 关闭调用瞬间
|
|
222
224
|
的活动资产。普通模型以 borrowed 方式挂入唯一 scene runtime,GPU 资源只由模型 session 释放。
|
|
223
225
|
|
|
224
|
-
GLB/glTF
|
|
226
|
+
GLB/glTF 与 FBX 模型的 authored up 轴在 Viewer 中统一由 `upAxis` 声明。预览世界固定 Z-up;FBX 会先读取 `GlobalSettings` 中正向的 Y/Z `UpAxis` 与 `UpAxisSign` 声明,声明缺失、损坏或当前不支持时才回退到 Y-up。显式传入的 `upAxis` 始终优先;GLB/glTF 为兼容 CAD-kernel 导出继续默认使用 Z-up;
|
|
225
227
|
对轴向错误的模型传 `upAxis: 'y'` 打开(仅旋转资产根节点,不移动相机与世界),或运行期用
|
|
226
228
|
`preview.setUpAxis('y' | 'z')` / `preview.getUpAxis()` 切换(切换后自动重铺地面并重新适配
|
|
227
229
|
相机,不平移贴地)。能力标志为 `capabilities.canReorientUpAxis`。仿真资产的格式自带 up 轴,
|
|
@@ -286,21 +288,22 @@ const preview = viewer.openAsset('https://cdn.example.com/robot/scene.xml', {
|
|
|
286
288
|
},
|
|
287
289
|
},
|
|
288
290
|
});
|
|
289
|
-
await preview.ready;
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
对于私有 OSS/S3/CDN,常见的预签名 URL 只授权一个具体 Object Key。`root.usd` 的签名通常不能
|
|
293
|
-
复用于 `asset.usdc`、`physics/physics.usda`、纹理等兄弟资源,也不能把入口 URL 的 query
|
|
294
|
-
原样拼接到其他路径。`resourceResolver.resolve(path)` 必须为每个 `path` 返回独立有效的签名 URL
|
|
295
|
-
或已经取得的 `Blob`;入口 URL 自身也必须仍在有效期内。USD loader 会先提取分层 USD 的外部
|
|
296
|
-
引用,再通过该 resolver 递归取得 layer、mesh、material 和 texture 资源;任一依赖返回 401/403
|
|
297
|
-
都会作为鉴权加载失败报告,不会进入视觉降级流程。
|
|
298
|
-
|
|
299
|
-
`{ kind: 'files', files, entry }` 只表示浏览器已经持有的本地 `File | Blob` 文件包,不能把远端
|
|
291
|
+
await preview.ready;
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
对于私有 OSS/S3/CDN,常见的预签名 URL 只授权一个具体 Object Key。`root.usd` 的签名通常不能
|
|
295
|
+
复用于 `asset.usdc`、`physics/physics.usda`、纹理等兄弟资源,也不能把入口 URL 的 query
|
|
296
|
+
原样拼接到其他路径。`resourceResolver.resolve(path)` 必须为每个 `path` 返回独立有效的签名 URL
|
|
297
|
+
或已经取得的 `Blob`;入口 URL 自身也必须仍在有效期内。USD loader 会先提取分层 USD 的外部
|
|
298
|
+
引用,再通过该 resolver 递归取得 layer、mesh、material 和 texture 资源;任一依赖返回 401/403
|
|
299
|
+
都会作为鉴权加载失败报告,不会进入视觉降级流程。
|
|
300
|
+
|
|
301
|
+
`{ kind: 'files', files, entry }` 只表示浏览器已经持有的本地 `File | Blob` 文件包,不能把远端
|
|
300
302
|
URL 字符串放进 `files[].file`。业务层负责入口选择、必要的格式判断、鉴权和依赖映射;不能只依赖
|
|
301
|
-
Viewer 自动识别所有资产形态,也不能把本地样本验证等同于任意远端资产都兼容。普通 glTF 的
|
|
302
|
-
|
|
303
|
-
私有 glTF
|
|
303
|
+
Viewer 自动识别所有资产形态,也不能把本地样本验证等同于任意远端资产都兼容。普通 glTF 与 FBX 的
|
|
304
|
+
外部资源仍由对应 Three.js loader 按 URL 请求,不应假设这些格式的子资源都经过 `resourceResolver`;
|
|
305
|
+
私有 glTF/FBX 资产优先采用同源或可独立鉴权的资源目录。单个本地 FBX 文件适合使用内嵌纹理;
|
|
306
|
+
若纹理是外置文件,应使用可保持相对目录结构的远端 URL。
|
|
304
307
|
|
|
305
308
|
OpenUSD 使用 pthread WASM,部署必须在安全上下文中提供以下响应头:
|
|
306
309
|
|
package/dist/assets/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Object3D, WebGLRenderer, Scene, Camera, Box3, ColorRepresentation
|
|
|
2
2
|
import type { CadLoadSource, CadOpenOptions } from '../cad/types';
|
|
3
3
|
import type { ViewerViewMode } from '../types';
|
|
4
4
|
export type AssetPreviewKind = 'cad' | 'model' | 'simulation';
|
|
5
|
-
export type BuiltinAssetFormat = 'cad' | 'glb' | 'gltf' | 'urdf' | 'mjcf' | 'usd' | 'usda' | 'usdc' | 'usdz';
|
|
5
|
+
export type BuiltinAssetFormat = 'cad' | 'glb' | 'gltf' | 'fbx' | 'urdf' | 'mjcf' | 'usd' | 'usda' | 'usdc' | 'usdz';
|
|
6
6
|
export type AssetFormat = BuiltinAssetFormat | (string & {});
|
|
7
7
|
export interface AssetFileEntry {
|
|
8
8
|
readonly path: string;
|
|
@@ -37,10 +37,11 @@ export interface OpenAssetOptions {
|
|
|
37
37
|
readonly mujocoBaseUrl?: string;
|
|
38
38
|
readonly openUsdBaseUrl?: string;
|
|
39
39
|
/**
|
|
40
|
-
* Which authored axis is "up" for a plain model asset.
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
40
|
+
* Which authored axis is "up" for a plain model asset. FBX first uses a
|
|
41
|
+
* supported positive Y/Z declaration from GlobalSettings, then falls back to
|
|
42
|
+
* 'y' when it is missing or cannot be read. GLB/glTF retain the existing 'z'
|
|
43
|
+
* default for CAD-kernel compatibility. An explicit value always wins. 'y'
|
|
44
|
+
* rotates the model root into world +Z.
|
|
44
45
|
* Ignored by simulation assets, whose formats declare their own up axis.
|
|
45
46
|
*/
|
|
46
47
|
readonly upAxis?: AssetUpAxis;
|
|
@@ -5758,7 +5758,7 @@ const ss = {
|
|
|
5758
5758
|
kind: "asset-loader",
|
|
5759
5759
|
id: "nebula.model-loader",
|
|
5760
5760
|
assetKind: "model",
|
|
5761
|
-
formats: ["glb", "gltf"],
|
|
5761
|
+
formats: ["glb", "gltf", "fbx"],
|
|
5762
5762
|
presentation: {
|
|
5763
5763
|
preferredViewMode: "3d",
|
|
5764
5764
|
interactionMode: "object",
|
|
@@ -5769,7 +5769,7 @@ const ss = {
|
|
|
5769
5769
|
clearColor: B.dark
|
|
5770
5770
|
},
|
|
5771
5771
|
async createSession(e, t) {
|
|
5772
|
-
const { createModelSession: i } = await import("./session-
|
|
5772
|
+
const { createModelSession: i } = await import("./session-B4uKXhdV.js");
|
|
5773
5773
|
return i(e, t);
|
|
5774
5774
|
}
|
|
5775
5775
|
});
|
|
@@ -5853,7 +5853,7 @@ const cs = {
|
|
|
5853
5853
|
clearColor: B.dark
|
|
5854
5854
|
},
|
|
5855
5855
|
async createSession(e, t) {
|
|
5856
|
-
const { createSimulationSession: i } = await import("./session-
|
|
5856
|
+
const { createSimulationSession: i } = await import("./session-DNMxzxd5.js").then((r) => r.s);
|
|
5857
5857
|
return i(e, t);
|
|
5858
5858
|
}
|
|
5859
5859
|
});
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { Mesh as F, MeshPhongMaterial as m, MeshLambertMaterial as D, MeshStandardMaterial as L, Color as A, Quaternion as w, Vector3 as B, Group as E, LoaderUtils as C, Box3 as N } from "three";
|
|
2
|
+
import { DRACOLoader as v } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
3
|
+
import { FBXLoader as G } from "three/examples/jsm/loaders/FBXLoader.js";
|
|
4
|
+
import { GLTFLoader as _ } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
5
|
+
import { S as R, d as O } from "./stage-CFr9ZkwQ.js";
|
|
6
|
+
const b = "Kaydara FBX Binary \0", X = /(?:^|[\r\n])\s*P:\s*"UpAxis"\s*,\s*"int"\s*,\s*"Integer"\s*,\s*""\s*,\s*(-?\d+)/i, z = /(?:^|[\r\n])\s*P:\s*"UpAxisSign"\s*,\s*"int"\s*,\s*"Integer"\s*,\s*""\s*,\s*(-?\d+)/i;
|
|
7
|
+
function V(e) {
|
|
8
|
+
try {
|
|
9
|
+
const n = new Uint8Array(e), r = q(n) ? Y(e) : W(new TextDecoder().decode(n));
|
|
10
|
+
return !r || r.sign !== 1 ? null : r.axis === 1 ? "y" : r.axis === 2 ? "z" : null;
|
|
11
|
+
} catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function q(e) {
|
|
16
|
+
if (e.byteLength < b.length) return !1;
|
|
17
|
+
for (let n = 0; n < b.length; n += 1)
|
|
18
|
+
if (e[n] !== b.charCodeAt(n)) return !1;
|
|
19
|
+
return !0;
|
|
20
|
+
}
|
|
21
|
+
function W(e) {
|
|
22
|
+
var t, i;
|
|
23
|
+
const n = Number.parseInt(((t = X.exec(e)) == null ? void 0 : t[1]) ?? "", 10);
|
|
24
|
+
if (!Number.isInteger(n)) return null;
|
|
25
|
+
const r = (i = z.exec(e)) == null ? void 0 : i[1], s = r === void 0 ? 1 : Number.parseInt(r, 10);
|
|
26
|
+
return Number.isInteger(s) ? { axis: n, sign: s } : null;
|
|
27
|
+
}
|
|
28
|
+
function Y(e) {
|
|
29
|
+
const n = new DataView(e);
|
|
30
|
+
if (n.byteLength < 27) return null;
|
|
31
|
+
const r = n.getUint32(23, !0) >= 7500;
|
|
32
|
+
let s = 27;
|
|
33
|
+
for (; s < n.byteLength; ) {
|
|
34
|
+
const t = T(n, s, r, !1);
|
|
35
|
+
if (!t) break;
|
|
36
|
+
if (t.name === "GlobalSettings") return P(n, t.childrenOffset, t.endOffset, r);
|
|
37
|
+
s = t.endOffset;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
function P(e, n, r, s) {
|
|
42
|
+
let t = n, i = null, l = 1;
|
|
43
|
+
for (; t < r; ) {
|
|
44
|
+
const a = T(e, t, s, !0);
|
|
45
|
+
if (!a) break;
|
|
46
|
+
if (a.name === "P") {
|
|
47
|
+
const [u, , , , o] = a.properties;
|
|
48
|
+
u === "UpAxis" && typeof o == "number" && (i = o), u === "UpAxisSign" && typeof o == "number" && (l = o);
|
|
49
|
+
}
|
|
50
|
+
if (a.childrenOffset < a.endOffset) {
|
|
51
|
+
const u = P(e, a.childrenOffset, a.endOffset, s);
|
|
52
|
+
u && (i ?? (i = u.axis), l = u.sign);
|
|
53
|
+
}
|
|
54
|
+
t = a.endOffset;
|
|
55
|
+
}
|
|
56
|
+
return i === null ? null : { axis: i, sign: l };
|
|
57
|
+
}
|
|
58
|
+
function T(e, n, r, s) {
|
|
59
|
+
const t = r ? 25 : 13;
|
|
60
|
+
if (n + t > e.byteLength) return null;
|
|
61
|
+
const i = M(e, n, r), l = M(e, n + (r ? 8 : 4), r), a = M(e, n + (r ? 16 : 8), r), u = e.getUint8(n + (r ? 24 : 12));
|
|
62
|
+
if (i === 0) return null;
|
|
63
|
+
const o = n + t, c = o + u, f = c + a;
|
|
64
|
+
if (i > e.byteLength || f > i) return null;
|
|
65
|
+
const d = new TextDecoder().decode(new Uint8Array(e.buffer, e.byteOffset + o, u)), p = [];
|
|
66
|
+
if (s) {
|
|
67
|
+
let h = c;
|
|
68
|
+
for (let y = 0; y < l; y += 1) {
|
|
69
|
+
const g = $(e, h);
|
|
70
|
+
if (p.push(g.value), h = g.nextOffset, h > f) return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return { name: d, endOffset: i, childrenOffset: f, properties: p };
|
|
74
|
+
}
|
|
75
|
+
function M(e, n, r) {
|
|
76
|
+
if (!r) return e.getUint32(n, !0);
|
|
77
|
+
const s = e.getBigUint64(n, !0);
|
|
78
|
+
if (s > BigInt(Number.MAX_SAFE_INTEGER)) throw new Error("FBX offset exceeds the safe integer range.");
|
|
79
|
+
return Number(s);
|
|
80
|
+
}
|
|
81
|
+
function $(e, n) {
|
|
82
|
+
const r = String.fromCharCode(e.getUint8(n));
|
|
83
|
+
switch (r) {
|
|
84
|
+
case "Y":
|
|
85
|
+
return { value: e.getInt16(n + 1, !0), nextOffset: n + 3 };
|
|
86
|
+
case "C":
|
|
87
|
+
return { value: e.getUint8(n + 1) !== 0, nextOffset: n + 2 };
|
|
88
|
+
case "I":
|
|
89
|
+
return { value: e.getInt32(n + 1, !0), nextOffset: n + 5 };
|
|
90
|
+
case "F":
|
|
91
|
+
return { value: e.getFloat32(n + 1, !0), nextOffset: n + 5 };
|
|
92
|
+
case "D":
|
|
93
|
+
return { value: e.getFloat64(n + 1, !0), nextOffset: n + 9 };
|
|
94
|
+
case "L":
|
|
95
|
+
return { value: Number(e.getBigInt64(n + 1, !0)), nextOffset: n + 9 };
|
|
96
|
+
case "S":
|
|
97
|
+
case "R": {
|
|
98
|
+
const s = e.getUint32(n + 1, !0), t = n + 5, i = new Uint8Array(e.buffer, e.byteOffset + t, s);
|
|
99
|
+
return { value: r === "S" ? new TextDecoder().decode(i) : i, nextOffset: t + s };
|
|
100
|
+
}
|
|
101
|
+
case "f":
|
|
102
|
+
case "d":
|
|
103
|
+
case "l":
|
|
104
|
+
case "i":
|
|
105
|
+
case "b":
|
|
106
|
+
case "c": {
|
|
107
|
+
const s = e.getUint32(n + 9, !0);
|
|
108
|
+
return { value: null, nextOffset: n + 13 + s };
|
|
109
|
+
}
|
|
110
|
+
default:
|
|
111
|
+
throw new Error(`Unsupported FBX property type: ${r}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function j(e) {
|
|
115
|
+
const n = /* @__PURE__ */ new Map();
|
|
116
|
+
e.traverse((r) => {
|
|
117
|
+
r instanceof F && (Array.isArray(r.material) ? r.material = r.material.map((s) => S(s, n)) : r.material = S(r.material, n));
|
|
118
|
+
});
|
|
119
|
+
for (const [r, s] of n)
|
|
120
|
+
r !== s && r.dispose();
|
|
121
|
+
}
|
|
122
|
+
function S(e, n) {
|
|
123
|
+
var i, l, a;
|
|
124
|
+
const r = n.get(e);
|
|
125
|
+
if (r) return r;
|
|
126
|
+
if (!(e instanceof m) && !(e instanceof D))
|
|
127
|
+
return n.set(e, e), e;
|
|
128
|
+
const s = e instanceof m ? e : null, t = new L({
|
|
129
|
+
name: e.name,
|
|
130
|
+
color: ((i = e.color) == null ? void 0 : i.clone()) ?? new A(16777215),
|
|
131
|
+
map: e.map,
|
|
132
|
+
emissive: ((l = e.emissive) == null ? void 0 : l.clone()) ?? new A(0),
|
|
133
|
+
emissiveMap: e.emissiveMap,
|
|
134
|
+
emissiveIntensity: e.emissiveIntensity,
|
|
135
|
+
normalMap: e.normalMap,
|
|
136
|
+
normalMapType: e.normalMapType,
|
|
137
|
+
normalScale: (a = e.normalScale) == null ? void 0 : a.clone(),
|
|
138
|
+
bumpMap: e.bumpMap,
|
|
139
|
+
bumpScale: e.bumpScale,
|
|
140
|
+
displacementMap: e.displacementMap,
|
|
141
|
+
displacementScale: e.displacementScale,
|
|
142
|
+
displacementBias: e.displacementBias,
|
|
143
|
+
aoMap: e.aoMap,
|
|
144
|
+
aoMapIntensity: e.aoMapIntensity,
|
|
145
|
+
alphaMap: e.alphaMap,
|
|
146
|
+
opacity: e.opacity,
|
|
147
|
+
transparent: e.transparent,
|
|
148
|
+
alphaTest: e.alphaTest,
|
|
149
|
+
side: e.side,
|
|
150
|
+
depthTest: e.depthTest,
|
|
151
|
+
depthWrite: e.depthWrite,
|
|
152
|
+
vertexColors: e.vertexColors,
|
|
153
|
+
wireframe: e.wireframe,
|
|
154
|
+
flatShading: e.flatShading,
|
|
155
|
+
metalness: 0,
|
|
156
|
+
// Approximate the Blinn-Phong exponent as perceptual roughness. This keeps
|
|
157
|
+
// glossy FBX materials glossy without pretending they carry metalness data.
|
|
158
|
+
roughness: s ? Math.min(1, Math.max(0.04, Math.sqrt(2 / (s.shininess + 2)))) : 1
|
|
159
|
+
});
|
|
160
|
+
return t.userData = { ...e.userData }, t.visible = e.visible, t.toneMapped = e.toneMapped, t.clippingPlanes = e.clippingPlanes, t.clipIntersection = e.clipIntersection, t.clipShadows = e.clipShadows, t.polygonOffset = e.polygonOffset, t.polygonOffsetFactor = e.polygonOffsetFactor, t.polygonOffsetUnits = e.polygonOffsetUnits, t.dithering = e.dithering, t.needsUpdate = !0, n.set(e, t), t;
|
|
161
|
+
}
|
|
162
|
+
const k = new w().setFromAxisAngle(new B(1, 0, 0), Math.PI / 2), Q = new w();
|
|
163
|
+
function U(e) {
|
|
164
|
+
return e === "fbx" ? "y" : "z";
|
|
165
|
+
}
|
|
166
|
+
function K(e) {
|
|
167
|
+
return e === "y" ? k : Q;
|
|
168
|
+
}
|
|
169
|
+
function I(e, n) {
|
|
170
|
+
const r = K(n);
|
|
171
|
+
return r.equals(e.quaternion) ? !1 : (e.quaternion.copy(r), e.updateMatrixWorld(!0), !0);
|
|
172
|
+
}
|
|
173
|
+
function re(e, n) {
|
|
174
|
+
let r = !1, s = null, t = null, i = "z", l;
|
|
175
|
+
const a = () => {
|
|
176
|
+
r = !0;
|
|
177
|
+
}, u = (async () => {
|
|
178
|
+
i = n.options.upAxis ?? U(n.format);
|
|
179
|
+
let o = null;
|
|
180
|
+
try {
|
|
181
|
+
if (r || n.signal.aborted) throw x();
|
|
182
|
+
const c = e.url ?? await e.resolve(e.entryPath ?? "");
|
|
183
|
+
if (o = new E(), o.name = "viewer-model-root", n.format === "fbx") {
|
|
184
|
+
const d = await fetch(c, { signal: n.signal });
|
|
185
|
+
if (!d.ok) throw new Error(`FBX request failed: ${d.status} ${d.statusText}`);
|
|
186
|
+
const p = await d.arrayBuffer();
|
|
187
|
+
i = n.options.upAxis ?? V(p) ?? U(n.format), o.add(new G().parse(p, C.extractUrlBase(c))), j(o);
|
|
188
|
+
} else {
|
|
189
|
+
const d = new v(), p = new _();
|
|
190
|
+
try {
|
|
191
|
+
n.options.dracoDecoderPath && d.setDecoderPath(n.options.dracoDecoderPath), p.setDRACOLoader(d);
|
|
192
|
+
const h = await p.loadAsync(c), y = h.scenes.filter((g) => g !== h.scene);
|
|
193
|
+
if (o.add(h.scene), r || n.signal.aborted) {
|
|
194
|
+
for (const g of y) o.add(g);
|
|
195
|
+
throw x();
|
|
196
|
+
}
|
|
197
|
+
} finally {
|
|
198
|
+
d.dispose();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (r || n.signal.aborted) throw x();
|
|
202
|
+
I(o, i), Z(o);
|
|
203
|
+
const f = new R(o, n.options.simulationTheme, void 0, "model");
|
|
204
|
+
s = o, t = f, o = null;
|
|
205
|
+
} finally {
|
|
206
|
+
o && O(o);
|
|
207
|
+
}
|
|
208
|
+
})();
|
|
209
|
+
return u.catch(() => {
|
|
210
|
+
}), {
|
|
211
|
+
id: `model-${Math.random().toString(36).slice(2)}`,
|
|
212
|
+
opened: u,
|
|
213
|
+
get root() {
|
|
214
|
+
return (t == null ? void 0 : t.root) ?? null;
|
|
215
|
+
},
|
|
216
|
+
getFitBounds() {
|
|
217
|
+
return (t == null ? void 0 : t.getModelBounds()) ?? null;
|
|
218
|
+
},
|
|
219
|
+
beforeRender(o, c, f) {
|
|
220
|
+
return t == null ? void 0 : t.beforeRender(o, c, f);
|
|
221
|
+
},
|
|
222
|
+
capabilities: { canPlay: !1, canPause: !1, canReset: !1, hasPhysics: !1, canReorientUpAxis: !0, canToggleGround: !0 },
|
|
223
|
+
// Session presentation overrides are only consulted for `interactionMode`
|
|
224
|
+
// and `fitPolicy`; the UI group comes from the loader descriptor. Keep the
|
|
225
|
+
// two in sync so the override never reads as a contradictory value.
|
|
226
|
+
presentation: { preferredViewMode: "3d", interactionMode: "object", uiProfile: "model", fitPolicy: "fit-on-ready" },
|
|
227
|
+
getUpAxis() {
|
|
228
|
+
return s ? i : null;
|
|
229
|
+
},
|
|
230
|
+
setTheme(o) {
|
|
231
|
+
t == null || t.setTheme(o);
|
|
232
|
+
},
|
|
233
|
+
setGroundVisible(o) {
|
|
234
|
+
t == null || t.setGroundVisible(o);
|
|
235
|
+
},
|
|
236
|
+
getGroundVisible() {
|
|
237
|
+
return (t == null ? void 0 : t.getGroundVisible()) ?? !0;
|
|
238
|
+
},
|
|
239
|
+
setUpAxis(o) {
|
|
240
|
+
if (r || !s || !t || !I(s, o)) return;
|
|
241
|
+
i = o, t.reseatGround();
|
|
242
|
+
const c = t.getModelBounds();
|
|
243
|
+
n.requestRender(), n.fit(c, { padding: 1.15 });
|
|
244
|
+
},
|
|
245
|
+
beginDispose: a,
|
|
246
|
+
dispose() {
|
|
247
|
+
return a(), l ?? (l = u.catch(() => {
|
|
248
|
+
}).then(() => {
|
|
249
|
+
t == null || t.dispose(), t = null, s && O(s), s = null;
|
|
250
|
+
})), l;
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function Z(e) {
|
|
255
|
+
e.updateMatrixWorld(!0);
|
|
256
|
+
const n = new N().setFromObject(e);
|
|
257
|
+
if (n.isEmpty()) throw new Error("模型不包含可显示的几何内容。");
|
|
258
|
+
const r = n.getSize(new B()), s = Math.max(r.x, r.y, r.z);
|
|
259
|
+
if (!Number.isFinite(s) || s <= 0) throw new Error("模型尺寸无效。");
|
|
260
|
+
}
|
|
261
|
+
function x() {
|
|
262
|
+
return Object.assign(new Error("Model load aborted."), { name: "AbortError", code: "E_ABORTED" });
|
|
263
|
+
}
|
|
264
|
+
export {
|
|
265
|
+
re as createModelSession
|
|
266
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
var Ee = Object.defineProperty;
|
|
2
2
|
var Se = (o, e, t) => e in o ? Ee(o, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[e] = t;
|
|
3
3
|
var D = (o, e, t) => Se(o, typeof e != "symbol" ? e + "" : e, t);
|
|
4
|
-
import { d as Ae, S as le } from "./stage-
|
|
4
|
+
import { d as Ae, S as le } from "./stage-CFr9ZkwQ.js";
|
|
5
5
|
import { ConvexGeometry as ve } from "three/examples/jsm/geometries/ConvexGeometry.js";
|
|
6
6
|
import { LineBasicMaterial as Me, LineSegments as Oe, EdgesGeometry as $e, Group as z, MeshStandardMaterial as he, Mesh as I, PlaneGeometry as Re, BoxGeometry as X, SphereGeometry as ee, CylinderGeometry as te, CapsuleGeometry as ye, Vector3 as T, BufferGeometry as Pe, BufferAttribute as ue, Euler as J, MathUtils as Ue, Matrix3 as ce, Matrix4 as k, Quaternion as be, LoadingManager as Fe } from "three";
|
|
7
7
|
import { GLTFLoader as qe } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
@@ -626,7 +626,7 @@ function ut(o, e) {
|
|
|
626
626
|
const O = e.format;
|
|
627
627
|
if (O === "usd" || O === "usda" || O === "usdc" || O === "usdz") {
|
|
628
628
|
(y = e.reportProgress) == null || y.call(e, "usd", "正在解析 USD 场景与物理刚体...");
|
|
629
|
-
const E = await (await import("./usd-session-
|
|
629
|
+
const E = await (await import("./usd-session-DDWM5msM.js")).loadUsdSimulation(o, e, t);
|
|
630
630
|
if (i || e.signal.aborted)
|
|
631
631
|
throw E.dispose(), _e();
|
|
632
632
|
p = E.asset, n = E.binding, l = E.dispose, u = E.hasPhysics ? E.step : null, c = E.reset, s = E.hasPhysics, m = E.hasPhysics, b = E.fallback ? { ...E.fallback, stage: "physics-fallback" } : null, (g = e.reportProgress) == null || g.call(e, "stage", "正在构建三维场景与环境光影..."), f = new le(n.root, e.options.simulationTheme, E.runtime), E.runtime ? (r = E.runtime, a = new W(r, Y(r, !0))) : a = E.collision ?? null, a && (a.root.visible = !1, f.attachAuxiliary(a.root));
|
|
@@ -2,7 +2,7 @@ var v = Object.defineProperty;
|
|
|
2
2
|
var y = (c, e, t) => e in c ? v(c, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : c[e] = t;
|
|
3
3
|
var a = (c, e, t) => y(c, typeof e != "symbol" ? e + "" : e, t);
|
|
4
4
|
import * as o from "three";
|
|
5
|
-
import { V as p } from "./index-
|
|
5
|
+
import { V as p } from "./index-D0lW4RQP.js";
|
|
6
6
|
const x = 1, b = (
|
|
7
7
|
/* glsl */
|
|
8
8
|
`
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Group as ot, Mesh as at, Vector3 as _, Quaternion as j, Matrix4 as X, Box3 as ht } from "three";
|
|
2
2
|
import { USDLoader as It } from "@openusd-wasm/three-loader";
|
|
3
3
|
import { PXR as $t } from "@openusd-wasm/pxr";
|
|
4
|
-
import { c as Rt, a as xt, b as At, d as Nt, S as Mt } from "./session-
|
|
5
|
-
import { d as _t } from "./stage-
|
|
4
|
+
import { c as Rt, a as xt, b as At, d as Nt, S as Mt } from "./session-DNMxzxd5.js";
|
|
5
|
+
import { d as _t } from "./stage-CFr9ZkwQ.js";
|
|
6
6
|
async function ee(t, e, n) {
|
|
7
7
|
var w;
|
|
8
8
|
Bt();
|
package/package.json
CHANGED
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@nebula-spatial/viewer",
|
|
3
|
-
"version": "0.4.
|
|
4
|
-
"description": "Read-only Three.js viewer facade",
|
|
5
|
-
"license": "ISC",
|
|
6
|
-
"engines": {
|
|
7
|
-
"node": ">=18"
|
|
8
|
-
},
|
|
9
|
-
"type": "module",
|
|
10
|
-
"files": [
|
|
11
|
-
"dist",
|
|
12
|
-
"README.md",
|
|
13
|
-
"CHANGELOG.md",
|
|
14
|
-
"package.json"
|
|
15
|
-
],
|
|
16
|
-
"main": "./dist/index.js",
|
|
17
|
-
"module": "./dist/index.js",
|
|
18
|
-
"types": "./dist/index.d.ts",
|
|
19
|
-
"exports": {
|
|
20
|
-
".": {
|
|
21
|
-
"types": "./dist/index.d.ts",
|
|
22
|
-
"import": "./dist/index.js",
|
|
23
|
-
"default": "./dist/index.js"
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
"sideEffects": false,
|
|
27
|
-
"scripts": {
|
|
28
|
-
"build": "npm run check:boundary && npm run typecheck && npm run build:bundle && npm run build:types && npm run check:dist",
|
|
29
|
-
"build:bundle": "vite build --config vite.config.ts",
|
|
30
|
-
"build:types": "tsc --project tsconfig.build.json && node scripts/prune-dist-types.mjs",
|
|
31
|
-
"check:boundary": "node scripts/check-boundary.mjs",
|
|
32
|
-
"check:dist": "node scripts/check-dist.mjs",
|
|
33
|
-
"typecheck": "tsc --project tsconfig.json --noEmit",
|
|
34
|
-
"test": "vitest run --config vitest.config.ts",
|
|
35
|
-
"pack:dry": "npm pack --dry-run",
|
|
36
|
-
"prepack": "npm run build"
|
|
37
|
-
},
|
|
38
|
-
"dependencies": {
|
|
39
|
-
"@mujoco/mujoco": "^3.12.0",
|
|
40
|
-
"@nebula-spatial/cad-loader": "^0.3.0",
|
|
41
|
-
"@openusd-wasm/pxr": "0.0.13",
|
|
42
|
-
"@openusd-wasm/three-loader": "^0.0.13"
|
|
43
|
-
},
|
|
44
|
-
"peerDependencies": {
|
|
45
|
-
"three": "0.182.0"
|
|
46
|
-
},
|
|
47
|
-
"devDependencies": {
|
|
48
|
-
"@types/jsdom": "^27.0.0",
|
|
49
|
-
"@types/node": "^25.6.0",
|
|
50
|
-
"@types/three": "0.182.0",
|
|
51
|
-
"jsdom": "^29.0.2",
|
|
52
|
-
"three": "0.182.0",
|
|
53
|
-
"typescript": "^5.6.3",
|
|
54
|
-
"vite": "^5.4.10",
|
|
55
|
-
"vitest": "^2.1.8"
|
|
56
|
-
}
|
|
57
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@nebula-spatial/viewer",
|
|
3
|
+
"version": "0.4.1",
|
|
4
|
+
"description": "Read-only Three.js viewer facade",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=18"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md",
|
|
13
|
+
"CHANGELOG.md",
|
|
14
|
+
"package.json"
|
|
15
|
+
],
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
|
+
"module": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/index.js",
|
|
23
|
+
"default": "./dist/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "npm run check:boundary && npm run typecheck && npm run build:bundle && npm run build:types && npm run check:dist",
|
|
29
|
+
"build:bundle": "vite build --config vite.config.ts",
|
|
30
|
+
"build:types": "tsc --project tsconfig.build.json && node scripts/prune-dist-types.mjs",
|
|
31
|
+
"check:boundary": "node scripts/check-boundary.mjs",
|
|
32
|
+
"check:dist": "node scripts/check-dist.mjs",
|
|
33
|
+
"typecheck": "tsc --project tsconfig.json --noEmit",
|
|
34
|
+
"test": "vitest run --config vitest.config.ts",
|
|
35
|
+
"pack:dry": "npm pack --dry-run",
|
|
36
|
+
"prepack": "npm run build"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@mujoco/mujoco": "^3.12.0",
|
|
40
|
+
"@nebula-spatial/cad-loader": "^0.3.0",
|
|
41
|
+
"@openusd-wasm/pxr": "0.0.13",
|
|
42
|
+
"@openusd-wasm/three-loader": "^0.0.13"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"three": "0.182.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/jsdom": "^27.0.0",
|
|
49
|
+
"@types/node": "^25.6.0",
|
|
50
|
+
"@types/three": "0.182.0",
|
|
51
|
+
"jsdom": "^29.0.2",
|
|
52
|
+
"three": "0.182.0",
|
|
53
|
+
"typescript": "^5.6.3",
|
|
54
|
+
"vite": "^5.4.10",
|
|
55
|
+
"vitest": "^2.1.8"
|
|
56
|
+
}
|
|
57
|
+
}
|
package/dist/session-CGaj14lM.js
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { Quaternion as y, Vector3 as M, Group as P, Box3 as T } from "three";
|
|
2
|
-
import { DRACOLoader as x } from "three/examples/jsm/loaders/DRACOLoader.js";
|
|
3
|
-
import { GLTFLoader as D } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
4
|
-
import { S as E, d as w } from "./stage-BxROW_dP.js";
|
|
5
|
-
const G = new y().setFromAxisAngle(new M(1, 0, 0), Math.PI / 2), R = new y();
|
|
6
|
-
function S(r) {
|
|
7
|
-
return r === "y" ? G : R;
|
|
8
|
-
}
|
|
9
|
-
function b(r, n) {
|
|
10
|
-
const t = S(n);
|
|
11
|
-
return t.equals(r.quaternion) ? !1 : (r.quaternion.copy(t), r.updateMatrixWorld(!0), !0);
|
|
12
|
-
}
|
|
13
|
-
function z(r, n) {
|
|
14
|
-
let t = !1, i = null, e = null, d = "z", f;
|
|
15
|
-
const l = new x(), p = new D(), m = () => {
|
|
16
|
-
t = !0;
|
|
17
|
-
}, a = (async () => {
|
|
18
|
-
d = n.options.upAxis ?? "z", n.options.dracoDecoderPath && l.setDecoderPath(n.options.dracoDecoderPath), p.setDRACOLoader(l);
|
|
19
|
-
let o = null;
|
|
20
|
-
try {
|
|
21
|
-
if (t || n.signal.aborted) throw h();
|
|
22
|
-
const s = await p.loadAsync(r.url ?? await r.resolve(r.entryPath ?? ""));
|
|
23
|
-
o = new P(), o.name = "viewer-model-root";
|
|
24
|
-
const u = s.scenes.filter((c) => c !== s.scene);
|
|
25
|
-
if (o.add(s.scene), t || n.signal.aborted) {
|
|
26
|
-
for (const c of u) o.add(c);
|
|
27
|
-
throw h();
|
|
28
|
-
}
|
|
29
|
-
b(o, d), g(o);
|
|
30
|
-
const A = new E(o, n.options.simulationTheme, void 0, "model");
|
|
31
|
-
i = o, e = A, o = null;
|
|
32
|
-
} finally {
|
|
33
|
-
o && w(o), l.dispose();
|
|
34
|
-
}
|
|
35
|
-
})();
|
|
36
|
-
return a.catch(() => {
|
|
37
|
-
}), {
|
|
38
|
-
id: `model-${Math.random().toString(36).slice(2)}`,
|
|
39
|
-
opened: a,
|
|
40
|
-
get root() {
|
|
41
|
-
return (e == null ? void 0 : e.root) ?? null;
|
|
42
|
-
},
|
|
43
|
-
getFitBounds() {
|
|
44
|
-
return (e == null ? void 0 : e.getModelBounds()) ?? null;
|
|
45
|
-
},
|
|
46
|
-
beforeRender(o, s, u) {
|
|
47
|
-
return e == null ? void 0 : e.beforeRender(o, s, u);
|
|
48
|
-
},
|
|
49
|
-
capabilities: { canPlay: !1, canPause: !1, canReset: !1, hasPhysics: !1, canReorientUpAxis: !0, canToggleGround: !0 },
|
|
50
|
-
// Session presentation overrides are only consulted for `interactionMode`
|
|
51
|
-
// and `fitPolicy`; the UI group comes from the loader descriptor. Keep the
|
|
52
|
-
// two in sync so the override never reads as a contradictory value.
|
|
53
|
-
presentation: { preferredViewMode: "3d", interactionMode: "object", uiProfile: "model", fitPolicy: "fit-on-ready" },
|
|
54
|
-
getUpAxis() {
|
|
55
|
-
return i ? d : null;
|
|
56
|
-
},
|
|
57
|
-
setTheme(o) {
|
|
58
|
-
e == null || e.setTheme(o);
|
|
59
|
-
},
|
|
60
|
-
setGroundVisible(o) {
|
|
61
|
-
e == null || e.setGroundVisible(o);
|
|
62
|
-
},
|
|
63
|
-
getGroundVisible() {
|
|
64
|
-
return (e == null ? void 0 : e.getGroundVisible()) ?? !0;
|
|
65
|
-
},
|
|
66
|
-
setUpAxis(o) {
|
|
67
|
-
if (t || !i || !e || !b(i, o)) return;
|
|
68
|
-
d = o, e.reseatGround();
|
|
69
|
-
const s = e.getModelBounds();
|
|
70
|
-
n.requestRender(), n.fit(s, { padding: 1.15 });
|
|
71
|
-
},
|
|
72
|
-
beginDispose: m,
|
|
73
|
-
dispose() {
|
|
74
|
-
return m(), f ?? (f = a.catch(() => {
|
|
75
|
-
}).then(() => {
|
|
76
|
-
e == null || e.dispose(), e = null, i && w(i), i = null;
|
|
77
|
-
})), f;
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
function g(r) {
|
|
82
|
-
r.updateMatrixWorld(!0);
|
|
83
|
-
const n = new T().setFromObject(r);
|
|
84
|
-
if (n.isEmpty()) throw new Error("模型不包含可显示的几何内容。");
|
|
85
|
-
const t = n.getSize(new M()), i = Math.max(t.x, t.y, t.z);
|
|
86
|
-
if (!Number.isFinite(i) || i <= 0) throw new Error("模型尺寸无效。");
|
|
87
|
-
}
|
|
88
|
-
function h() {
|
|
89
|
-
return Object.assign(new Error("Model load aborted."), { name: "AbortError", code: "E_ABORTED" });
|
|
90
|
-
}
|
|
91
|
-
export {
|
|
92
|
-
z as createModelSession
|
|
93
|
-
};
|