u-space 0.0.31 → 0.0.33
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 +3 -3
- package/dist/index.js +1174 -938
- package/dist/modelDecodeProtocol-CC2tkS8h.js +405 -0
- package/dist/modelDecodeProtocol-pgjndTph.cjs +1 -0
- package/dist/plugins/u-manager/index.cjs +1 -1
- package/dist/plugins/u-manager/index.js +73 -53
- package/dist/src/loaders/ModelLoaderManager.d.ts +13 -1
- package/dist/src/loaders/modelPersistentCache.d.ts +35 -0
- package/dist/src/objects/Model.d.ts +4 -0
- package/dist/src/worker/decodeGltfModel.d.ts +7 -1
- package/dist/src/worker/modelDecodeProtocol.d.ts +2 -0
- package/dist/worker/model-decoder.cjs +1 -1
- package/dist/worker/model-decoder.js +231 -205
- package/docs/api-effects.md +66 -2
- package/docs/api-objects.md +11 -2
- package/docs/changelog.md +18 -0
- package/docs/examples-guide.md +24 -10
- package/docs/getting-started.md +97 -93
- package/docs/index.md +1 -1
- package/docs/mcp.md +13 -2
- package/package.json +1 -1
- package/dist/modelDecodeProtocol-D1Apm9iG.cjs +0 -1
- package/dist/modelDecodeProtocol-wDB7ksYw.js +0 -56
package/docs/api-objects.md
CHANGED
|
@@ -256,8 +256,10 @@ await myModel.loadAsync(parameters: ModelParameters)
|
|
|
256
256
|
| 属性 | 类型 | 默认值 | 说明 |
|
|
257
257
|
| :----------- | :-------- | :----- | :-------------------------------------------------------------------------------------- |
|
|
258
258
|
| `url` | `string` | — | `.gltf` 或 `.glb` 文件的 URL。 |
|
|
259
|
-
| `cache` | `boolean` | `true` |
|
|
260
|
-
| `persistent` | `boolean` | `true` | 使用浏览器 Cache API
|
|
259
|
+
| `cache` | `boolean` | `true` | 启用内存 LRU 缓存。若同一请求已加载,则直接从内存中获取并克隆;最多保留 32 项。 |
|
|
260
|
+
| `persistent` | `boolean` | `true` | 使用浏览器 Cache API 持久化模型及外部 glTF 依赖;最多保留 64 项或 512 MiB。 |
|
|
261
|
+
| `cacheMode` | `string` | — | 覆盖持久化缓存策略:`no-store`、`reload`、`revalidate` 或 `force-cache`。 |
|
|
262
|
+
| `cacheKey` | `string` | — | 为同一 URL 指定版本化缓存身份;适用于发布后 URL 不变的模型。 |
|
|
261
263
|
|
|
262
264
|
#### 缓存示例
|
|
263
265
|
|
|
@@ -273,8 +275,14 @@ model2.loadAsync({ url: 'model.glb', cache: false });
|
|
|
273
275
|
// 完全禁用缓存
|
|
274
276
|
const model3 = new Model();
|
|
275
277
|
model3.loadAsync({ url: 'model.glb', cache: false, persistent: false });
|
|
278
|
+
|
|
279
|
+
// 发布新模型但 URL 保持不变时,获取网络版本并更新该版本条目
|
|
280
|
+
const model4 = new Model();
|
|
281
|
+
model4.loadAsync({ url: 'model.glb', cacheMode: 'reload', cacheKey: '2026-09-02' });
|
|
276
282
|
```
|
|
277
283
|
|
|
284
|
+
持久化缓存保留响应类型、验证器和真实字节长度。默认无服务端缓存指令的资源可复用 7 天;到期后优先使用 `ETag` / `Last-Modified` 条件验证,断网时可回退到已存在的非空缓存。`no-store` 不读取或写入持久化缓存;`reload` 强制网络请求并更新缓存;`revalidate` 即使缓存仍新鲜也会条件验证;`force-cache` 优先返回已有的非空缓存。`Cache-Control: no-store/private` 与 `Vary: Cookie/*` 响应不会写入缓存。空缓存、截断的外部 buffer、解析失败或缓存命中时未解码的贴图会删除相关缓存资源并重新请求一次。请求头、credentials 模式和 `cacheKey` 共同参与缓存身份,避免不同授权请求或版本共用同一条目。
|
|
285
|
+
|
|
278
286
|
### 动画
|
|
279
287
|
|
|
280
288
|
`Model` 在加载含内置动画的模型(如 glTF/FBX)后,会自动初始化 `AnimationMixer` 并收集 `AnimationClip`。
|
|
@@ -372,6 +380,7 @@ myModel.setMaterial(new MeshStandardMaterial({ color: 0xff0000 }));
|
|
|
372
380
|
|
|
373
381
|
- `Model.clearMemoryCache()`:清除运行时内存缓存。
|
|
374
382
|
- `await Model.clearPersistentCache()`:完全清除浏览器中 `u-space` 模型的持久化缓存。
|
|
383
|
+
- `await ModelLoaderManager.deletePersistentCache(url, { cacheKey })`:仅删除指定 URL 与版本身份的持久化缓存。
|
|
375
384
|
|
|
376
385
|
## 网格
|
|
377
386
|
|
package/docs/changelog.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
## 未发布
|
|
4
4
|
|
|
5
|
+
## 0.0.33
|
|
6
|
+
|
|
7
|
+
### 修复与优化
|
|
8
|
+
|
|
9
|
+
- **模型持久化缓存**:主线程与 decode Worker 统一使用带版本、容量和响应元数据的 Cache Storage 策略,缓存项记录真实 `Content-Length`;模型及外部 glTF buffer/贴图支持过期与 `ETag` / `Last-Modified` 条件验证、离线旧缓存、授权请求隔离和损坏缓存单次自愈。调用方可通过 `cacheMode` 跳过、刷新、重验或强制读取缓存,通过 `cacheKey` 隔离同一 URL 的模型版本并精确删除目标缓存。对象内存缓存改为 32 项 LRU,磁盘缓存限制为 64 项或 512 MiB,并遵循 `no-store/private` 与敏感 `Vary` 响应。
|
|
10
|
+
- **UManager 示例**:目标对象不存在、不是 Mesh 或使用多材质时,示例不再直接写入材质属性而导致页面报错。
|
|
11
|
+
|
|
12
|
+
## 0.0.32
|
|
13
|
+
|
|
14
|
+
### 修复与优化
|
|
15
|
+
|
|
16
|
+
- **Offscreen 在线示例场景源** — 保留本地 `examples/scenes/飞龙吾悦广场` 及其匹配密钥;GitHub 发布流程会在 Vercel 构建前拉取真实 Git LFS 对象,构建脚本也会拒绝仅含 pointer 的场景。超过 Vercel 单文件上限的场景资源会在部署产物中拆成 90 MiB 分片,由 render/decode Worker 流式还原,既避免把 LFS pointer 当作 JSON,也不替换原场景。
|
|
17
|
+
|
|
18
|
+
### 文档
|
|
19
|
+
|
|
20
|
+
- **TSLEffects Outline** — 补齐 `TSLEffects.outline()`、`TSLOutlineOptions`、`TSLOutlineEffect`、RenderPipeline output-effect 接入、`InstanceObject` 渲染对象/bounds proxy 策略、资源释放、`test_outline.html` 在线示例及 MCP/LLM 检索入口。该效果最早随 `0.0.30` 发布,本次补全此前遗漏的文档发布面。
|
|
21
|
+
|
|
5
22
|
## 0.0.31
|
|
6
23
|
|
|
7
24
|
### 新增
|
|
@@ -19,6 +36,7 @@
|
|
|
19
36
|
|
|
20
37
|
### 新增
|
|
21
38
|
|
|
39
|
+
- **TSLEffects Outline** — 新增 `TSLEffects.outline()` 可组合 output effect,支持普通 `Object3D` 与核心 `InstanceObject` 的可见/隐藏边缘描边、运行时选择和样式更新,以及在实例没有直接可描边渲染子树时使用世界包围盒代理;`examples/test_outline.html` 提供交互示例。
|
|
22
40
|
- **AO 示例** — 新增 `examples/test_ao.html`,通过 SSGI 的 `giIntensity: 0` 默认开启纯 AO,并提供遮蔽强度、半径和厚度实时调节。
|
|
23
41
|
- **RenderPipeline SSR** — 新增 `enableSSR()`、`updateSSR()` 和 `disableSSR()`,封装 Stochastic SSR、Temporal Reproject、Recurrent Denoise、velocity 以及双向历史反馈;提供完整 SSR 与降噪参数配置。
|
|
24
42
|
- **Viewer** — 新增可选 `pixelRatio` 构造参数,省略时继续使用 `Math.min(window.devicePixelRatio, 1.5)`。
|
package/docs/examples-guide.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
## 运行方式与版本
|
|
6
6
|
|
|
7
|
-
示例统一通过 `examples/importmap.js` 注入 Import Map。本地通过 `localhost`、`127.0.0.1`、`0.0.0.0` 或 `192.168.x.x` 访问时会加载仓库里的 `../dist/` 构建产物;在线部署或非本地域名访问时会从 jsDelivr 加载当前发布版本 `u-space@0.0.
|
|
7
|
+
示例统一通过 `examples/importmap.js` 注入 Import Map。本地通过 `localhost`、`127.0.0.1`、`0.0.0.0` 或 `192.168.x.x` 访问时会加载仓库里的 `../dist/` 构建产物;在线部署或非本地域名访问时会从 jsDelivr 加载当前发布版本 `u-space@0.0.33`。Vercel 文档部署会继续把 `__VERSION__` 占位符替换为 `package.json` 中的版本号,源码里的 `0.0.33` 作为直接托管 `examples/` 时的 fallback。
|
|
8
8
|
|
|
9
9
|
插件示例可以在页面加载 `importmap.js` 前通过 `window.__IMPORTS__` 声明额外依赖。将 `u-space/plugins/<name>` 的值设为 `true` 时,`importmap.js` 会自动在本地和 CDN 路径之间切换。
|
|
10
10
|
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
|
|
29
29
|
- 使用全局 `Model` 类通过 `Model.prototype.loadAsync()` 异步加载 `.glb` 文件。
|
|
30
30
|
- 理解 `cache: true`(将模型节点保留在内存中,可实现即时克隆/实例化)。
|
|
31
|
-
- 理解 `persistent: true`(使用
|
|
31
|
+
- 理解 `persistent: true`(使用 Cache Storage API 持久化模型及外部 glTF 依赖,无需注册 Service Worker)。
|
|
32
32
|
- 演示如何将这些异步加载的资源安全地注册到 `viewer.objectManager`。
|
|
33
33
|
- 提供通过 `Model.clearMemoryCache()` 和 `Model.clearPersistentCache()` 手动清除缓存的示例。
|
|
34
34
|
|
|
@@ -224,7 +224,21 @@ pnpm example:offscreen
|
|
|
224
224
|
- 使用 `MaterialEffects.fadeOut(object)` / `fadeIn(object)` 执行淡入淡出动画。
|
|
225
225
|
- 使用 `MaterialEffects.removeHighlightColor(object)` 恢复原始材质状态。
|
|
226
226
|
|
|
227
|
-
## 16. `
|
|
227
|
+
## 16. `test_outline.html`:TSLEffects Outline 描边
|
|
228
|
+
|
|
229
|
+
[在线演示](https://u-space-phi.vercel.app/examples/test_outline.html)
|
|
230
|
+
|
|
231
|
+
该示例演示 `TSLEffects.outline()` 作为 RenderPipeline output effect 对普通 Mesh、Group 和核心 `InstanceObject` 进行屏幕空间描边。
|
|
232
|
+
|
|
233
|
+
### 核心要点:
|
|
234
|
+
|
|
235
|
+
- 使用 `viewer.renderPipeline.addOutputEffect(outline)` 叠加 Outline,不修改原始材质,也不占用业务侧 `setOutputComposer()`。
|
|
236
|
+
- 使用 `outline.setSelectedObjects()` 在 Box、Sphere、`InstanceObject`、全部对象和空选择之间切换。
|
|
237
|
+
- 使用 `outline.update()` 实时调整强度、厚度、Glow 和 `instanceBoundsPadding`。
|
|
238
|
+
- `InstanceObject` 有实际渲染对象时直接描边;没有可渲染子树时可通过 `getInstanceBoundingBox()` 自动生成不可见 bounds proxy。
|
|
239
|
+
- 销毁时先调用 `removeOutputEffect(outline)`,再调用 `outline.dispose()` 释放 OutlineNode 与代理资源。
|
|
240
|
+
|
|
241
|
+
## 17. `test_selection.html`:Selection 选择系统
|
|
228
242
|
|
|
229
243
|
该示例演示了对象选择系统的单选和框选功能。
|
|
230
244
|
|
|
@@ -235,7 +249,7 @@ pnpm example:offscreen
|
|
|
235
249
|
- 使用 `selection.enableBoxSelection()` 开启鼠标框选模式。
|
|
236
250
|
- 框选模式下可配合 `viewer.controls.lock()` 避免框选与相机旋转冲突。
|
|
237
251
|
|
|
238
|
-
##
|
|
252
|
+
## 18. `test_measure.html`:MeasureTool 测量工具
|
|
239
253
|
|
|
240
254
|
该示例演示了 3D 场景中的距离、面积和角度测量。
|
|
241
255
|
|
|
@@ -246,7 +260,7 @@ pnpm example:offscreen
|
|
|
246
260
|
- 使用 `measureTool.measureAngle(pointA, vertex, pointC)` 测量夹角。
|
|
247
261
|
- 测量结果以可视化线条渲染到场景中,返回的 `MeasureResult` 包含数值和单位。
|
|
248
262
|
|
|
249
|
-
##
|
|
263
|
+
## 19. `test_annotation.html`:AnnotationManager 标注管理
|
|
250
264
|
|
|
251
265
|
该示例演示了 3D 标注的创建、更新和管理,配合 `CSSRenderer` 实现 HTML 浮动标签。
|
|
252
266
|
|
|
@@ -258,7 +272,7 @@ pnpm example:offscreen
|
|
|
258
272
|
- 使用 `updateContent()` 动态更新标注内容,`updatePosition()` 移动标注位置。
|
|
259
273
|
- 使用 `hideAll()` / `showAll()` 批量控制标注显隐。
|
|
260
274
|
|
|
261
|
-
##
|
|
275
|
+
## 20. `test_clipping.html`:ClippingTool 剖切工具
|
|
262
276
|
|
|
263
277
|
该示例演示了剖切面的创建和实时调整。
|
|
264
278
|
|
|
@@ -269,7 +283,7 @@ pnpm example:offscreen
|
|
|
269
283
|
- 使用滑块通过 `clippingTool.setPlaneConstant()` 实时调整剖切位置。
|
|
270
284
|
- 使用 `showHelper()` / `hideHelper()` 切换剖切面可视化辅助。
|
|
271
285
|
|
|
272
|
-
##
|
|
286
|
+
## 21. `test_lights.html`:LightManager 灯光管理
|
|
273
287
|
|
|
274
288
|
该示例演示了灯光管理器的灯光预设和 Helper 可视化功能。
|
|
275
289
|
|
|
@@ -280,7 +294,7 @@ pnpm example:offscreen
|
|
|
280
294
|
- 使用 `showAllHelpers()` / `hideAllHelpers()` 显示或隐藏灯光辅助可视化。
|
|
281
295
|
- 每种预设会自动清除旧灯光并创建新的灯光组合。
|
|
282
296
|
|
|
283
|
-
##
|
|
297
|
+
## 22. `test_fire.html`:WebGPU 体积火焰
|
|
284
298
|
|
|
285
299
|
该示例演示了 `u-space/plugins/fire` 的 `FireEffect` 插件,封装 Three.js 官方体积火焰示例,在独立 volumetric pass 中模拟火焰和烟雾后叠加到主场景。
|
|
286
300
|
|
|
@@ -292,7 +306,7 @@ pnpm example:offscreen
|
|
|
292
306
|
- 通过 `fire.update()` 实时调整 `fireIntensity`、`smokeLifespan`、`emitterRadius` 等参数。
|
|
293
307
|
- 插件使用 RenderPipeline output effect 接入,不占用业务侧的 `setOutputComposer()`。
|
|
294
308
|
|
|
295
|
-
##
|
|
309
|
+
## 23. `test_ssr.html`:SSR 时空降噪
|
|
296
310
|
|
|
297
311
|
[在线演示](https://u-space-phi.vercel.app/examples/test_ssr.html)
|
|
298
312
|
|
|
@@ -310,7 +324,7 @@ pnpm example:offscreen
|
|
|
310
324
|
- `maxDistance` 从默认值 `0.4` 开始,保留滑块用于观察追踪距离对质量和性能的影响。
|
|
311
325
|
- 移动物体继续生成 velocity,但不投射动态阴影;2048² 方向光阴影只更新一次。
|
|
312
326
|
|
|
313
|
-
##
|
|
327
|
+
## 24. `test_ao.html`:环境光遮蔽
|
|
314
328
|
|
|
315
329
|
[在线演示](https://u-space-phi.vercel.app/examples/test_ao.html)
|
|
316
330
|
|
package/docs/getting-started.md
CHANGED
|
@@ -1,123 +1,127 @@
|
|
|
1
1
|
# 快速上手 `u-space`
|
|
2
2
|
|
|
3
|
-
`u-space` 是一个基于 Three.js 的 WebGPU 3D
|
|
3
|
+
`u-space` 是一个基于 Three.js 的 WebGPU 3D 引擎。本指南使用 React、TypeScript 和 Vite 搭建一个基础应用。
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 创建项目
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
### 1. 初始化 React + Vite
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
pnpm
|
|
10
|
+
pnpm create vite u-space-demo --template react-ts
|
|
11
|
+
cd u-space-demo
|
|
12
|
+
pnpm install
|
|
11
13
|
```
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
### 2. 安装 `u-space`
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
```bash
|
|
18
|
+
pnpm add u-space three camera-controls
|
|
19
|
+
pnpm add -D @types/three
|
|
20
|
+
```
|
|
16
21
|
|
|
17
|
-
|
|
22
|
+
Vite 会直接解析 npm 包及 `three/webgpu`,不需要额外配置模块映射。
|
|
18
23
|
|
|
19
|
-
|
|
24
|
+
## 编写场景组件
|
|
20
25
|
|
|
21
|
-
|
|
22
|
-
<!DOCTYPE html>
|
|
23
|
-
<html lang="zh">
|
|
24
|
-
<head>
|
|
25
|
-
<meta charset="UTF-8" />
|
|
26
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
27
|
-
<title>u-space App</title>
|
|
28
|
-
</head>
|
|
29
|
-
<body style="margin: 0">
|
|
30
|
-
<div id="app" style="width: 100vw; height: 100vh"></div>
|
|
31
|
-
<!-- 脚本放这里 -->
|
|
32
|
-
</body>
|
|
33
|
-
</html>
|
|
34
|
-
```
|
|
26
|
+
### 1. 替换 `src/App.tsx`
|
|
35
27
|
|
|
36
|
-
|
|
28
|
+
下面的组件会初始化 `Viewer`、添加一个可交互的立方体,并在 React 组件卸载时释放资源。
|
|
37
29
|
|
|
38
|
-
|
|
30
|
+
```tsx
|
|
31
|
+
import { useEffect, useRef } from 'react';
|
|
32
|
+
import { BoxGeometry, Color, GridHelper, MeshBasicMaterial } from 'three/webgpu';
|
|
33
|
+
import { BaseMesh, Viewer } from 'u-space';
|
|
39
34
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
35
|
+
export default function App() {
|
|
36
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
37
|
+
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
const container = containerRef.current;
|
|
40
|
+
if (!container) return;
|
|
41
|
+
|
|
42
|
+
let viewer: Viewer | undefined;
|
|
43
|
+
let cancelled = false;
|
|
44
|
+
|
|
45
|
+
async function setup() {
|
|
46
|
+
const nextViewer = new Viewer({
|
|
47
|
+
el: container,
|
|
48
|
+
rendererOptions: { forceWebGL: false },
|
|
49
|
+
});
|
|
50
|
+
await nextViewer.init();
|
|
51
|
+
|
|
52
|
+
// 兼容 React StrictMode 在开发环境中的重复挂载检查
|
|
53
|
+
if (cancelled) {
|
|
54
|
+
nextViewer.dispose();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
53
57
|
|
|
54
|
-
|
|
58
|
+
nextViewer.scene.background = new Color(0x666666);
|
|
59
|
+
nextViewer.scene.add(new GridHelper(10, 10));
|
|
55
60
|
|
|
56
|
-
|
|
61
|
+
const material = new MeshBasicMaterial({ color: 0xff0000 });
|
|
62
|
+
const box = new BaseMesh(new BoxGeometry(1, 1, 1), material);
|
|
63
|
+
box.position.set(0, 0.5, 0);
|
|
64
|
+
nextViewer.scene.add(box);
|
|
57
65
|
|
|
58
|
-
|
|
59
|
-
<script type="module">
|
|
60
|
-
import { Color, GridHelper, Mesh, BoxGeometry, MeshBasicMaterial } from 'three/webgpu';
|
|
61
|
-
import { Viewer } from 'u-space';
|
|
66
|
+
nextViewer.interactionManager.pointerMoveEventsEnabled = true;
|
|
62
67
|
|
|
63
|
-
|
|
68
|
+
box.addEventListener('click', ({ event }) => {
|
|
69
|
+
console.log('点击位置:', event.intersect?.point);
|
|
70
|
+
material.color.set(Math.random() * 0xffffff);
|
|
71
|
+
void nextViewer.render();
|
|
72
|
+
});
|
|
64
73
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
rendererOptions: { forceWebGL: false }, // 优先使用 WebGPU
|
|
69
|
-
});
|
|
70
|
-
await viewer.init();
|
|
74
|
+
box.addEventListener('pointerenter', () => {
|
|
75
|
+
document.body.style.cursor = 'pointer';
|
|
76
|
+
});
|
|
71
77
|
|
|
72
|
-
|
|
73
|
-
|
|
78
|
+
box.addEventListener('pointerleave', () => {
|
|
79
|
+
document.body.style.cursor = 'default';
|
|
80
|
+
});
|
|
74
81
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
82
|
+
viewer = nextViewer;
|
|
83
|
+
void viewer.render();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
void setup();
|
|
78
87
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
88
|
+
return () => {
|
|
89
|
+
cancelled = true;
|
|
90
|
+
document.body.style.cursor = 'default';
|
|
91
|
+
viewer?.dispose();
|
|
92
|
+
};
|
|
93
|
+
}, []);
|
|
85
94
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
</script>
|
|
95
|
+
return <div ref={containerRef} className="viewer" />;
|
|
96
|
+
}
|
|
89
97
|
```
|
|
90
98
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
document.body.style.cursor = 'default';
|
|
115
|
-
material.color.set(0xff0000);
|
|
116
|
-
viewer.render();
|
|
117
|
-
});
|
|
99
|
+
`BaseMesh` 已包含 `u-space` 交互事件类型,因此可以直接监听 `click`、`pointerenter` 和 `pointerleave`。
|
|
100
|
+
|
|
101
|
+
### 2. 替换 `src/index.css`
|
|
102
|
+
|
|
103
|
+
```css
|
|
104
|
+
html,
|
|
105
|
+
body,
|
|
106
|
+
#root,
|
|
107
|
+
.viewer {
|
|
108
|
+
width: 100%;
|
|
109
|
+
height: 100%;
|
|
110
|
+
margin: 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
body {
|
|
114
|
+
overflow: hidden;
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 3. 启动开发服务器
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
pnpm dev
|
|
118
122
|
```
|
|
119
123
|
|
|
120
|
-
|
|
124
|
+
打开 Vite 输出的本地地址,即可看到并操作 `u-space` 场景。
|
|
121
125
|
|
|
122
126
|
## 版本信息
|
|
123
127
|
|
|
@@ -125,7 +129,7 @@ box.addEventListener('pointerleave', (e) => {
|
|
|
125
129
|
|
|
126
130
|
```typescript
|
|
127
131
|
import { version } from 'u-space';
|
|
128
|
-
console.log(version); // e.g. '0.0.
|
|
132
|
+
console.log(version); // e.g. '0.0.33'
|
|
129
133
|
|
|
130
134
|
// 也可以通过全局变量访问
|
|
131
135
|
console.log(window.__USPACE__.version);
|
package/docs/index.md
CHANGED
|
@@ -41,7 +41,7 @@ features:
|
|
|
41
41
|
| [Interactions](./api-interactions) | 交互管理:射线检测、鼠标/触摸事件、框选 |
|
|
42
42
|
| [Managers](./api-managers) | 对象管理、场景管理、灯光管理 |
|
|
43
43
|
| [Animations](./api-animations) | 补间动画:`tweenAnimation`、`Tween`、缓动模式 |
|
|
44
|
-
| [Effects](./api-effects) |
|
|
44
|
+
| [Effects](./api-effects) | 视觉特效:高亮、呼吸、线框、淡入淡出、流动、流体与可组合 Outline(TSL) |
|
|
45
45
|
| [Tools](./api-tools) | 工具:测量(距离/面积/角度)、剖切(面/盒)、标注管理 |
|
|
46
46
|
|
|
47
47
|
### 插件
|
package/docs/mcp.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# u-space MCP
|
|
2
2
|
|
|
3
|
-
`u-space-mcp` 是面向 `u-space` 文档的 Model Context Protocol(MCP)服务器。它把当前文档打包成只读 MCP 工具,方便 Mastra、Claude Desktop、Cursor 等 MCP 客户端在回答 `u-space` API、插件和示例问题时直接检索官方文档,包括实验性 `u-space/worker` OffscreenCanvas runtime、`OffscreenViewerHost`、top-level await `createWorkerViewer()`、Worker command/事件桥接、`ModelLoaderManager.setDecodeWorker()` + `u-space/worker/model-decoder` 嵌套静态模型解码、transferable/ACK backpressure、普通图片超过 WebGPU `8192` 上限时的解码前缩放、Three.js 原生静态场景矩阵策略及其与 `setEditableBatching()` 的组合;核心 `src/batches` 导出的 `ModelInstancedLayer` 与 `EditableGeometryBatchLayer`;`u-manager` 的 `UManagerLoader` 一体化加载入口、`SceneLoader` 语义去重、path-based model instancing 和 scene-specific editable batching adapter、Semantic/Facilities API,以及 atmosphere 和 fire 插件的 WebGPU 效果。
|
|
3
|
+
`u-space-mcp` 是面向 `u-space` 文档的 Model Context Protocol(MCP)服务器。它把当前文档打包成只读 MCP 工具,方便 Mastra、Claude Desktop、Cursor 等 MCP 客户端在回答 `u-space` API、插件和示例问题时直接检索官方文档,包括实验性 `u-space/worker` OffscreenCanvas runtime、`OffscreenViewerHost`、top-level await `createWorkerViewer()`、Worker command/事件桥接、`ModelLoaderManager.setDecodeWorker()` + `u-space/worker/model-decoder` 嵌套静态模型解码、transferable/ACK backpressure、普通图片超过 WebGPU `8192` 上限时的解码前缩放、Three.js 原生静态场景矩阵策略及其与 `setEditableBatching()` 的组合;核心 `src/batches` 导出的 `ModelInstancedLayer` 与 `EditableGeometryBatchLayer`;`TSLEffects.outline()` 可组合描边和 `InstanceObject` bounds proxy;`u-manager` 的 `UManagerLoader` 一体化加载入口、`SceneLoader` 语义去重、path-based model instancing 和 scene-specific editable batching adapter、Semantic/Facilities API,以及 atmosphere 和 fire 插件的 WebGPU 效果。
|
|
4
4
|
|
|
5
5
|
## 安装与启动
|
|
6
6
|
|
|
@@ -86,7 +86,7 @@ export const codingAgent = new Agent({
|
|
|
86
86
|
|
|
87
87
|
## 示例检索
|
|
88
88
|
|
|
89
|
-
MCP 文档索引包含 `examples/test_umanager_loader.html`、`examples/test_umanager_dynamic_instances.html`、`examples/test_umanager2.html` 和 `examples/offscreen/test_umanager2_offscreen.html` 的说明。检索 `UManagerLoader example`、`test_umanager_loader` 或 `UManagerLoader 用法` 可以找到一体化加载示例;检索 `dynamic instances`、`getInstanceById` 或 `test_umanager_dynamic_instances` 可以找到运行时实例编辑示例;检索 `setEditableBatching`、`SceneEditableBatchLayer`、`SceneEditableBatchFallback`、`editable batching`、`materialize` 或 `test_umanager2` 可以找到大型静态场景合批及其与 `SceneInstancedLayer` fallback 的关系;检索 `OffscreenCanvas`、`OffscreenViewerHost`、`host.init`、`initialized`、`ready`、`createWorkerViewer`、`ModelLoaderManager.setDecodeWorker`、`model-decoder`、`decode Worker`、`transferable`、`ACK backpressure`、`ImageBitmapLoader`、`maxTextureDimension2D`、`oversized texture`、`top-level await`、`u-space/worker`、`Worker WebGPU` 或 `test_umanager2_offscreen` 可以找到 Worker 渲染、嵌套静态模型解码、生命周期、事件/command 桥接、超大贴图缩放、editable batching、pipeline 预热和主线程/GPU 性能边界。
|
|
89
|
+
MCP 文档索引包含 `examples/test_outline.html`、`examples/test_umanager_loader.html`、`examples/test_umanager_dynamic_instances.html`、`examples/test_umanager2.html` 和 `examples/offscreen/test_umanager2_offscreen.html` 的说明。检索 `TSLEffects.outline`、`outline effect`、`instanceBoundsProxy` 或 `test_outline` 可以找到描边 API 与交互示例;检索 `UManagerLoader example`、`test_umanager_loader` 或 `UManagerLoader 用法` 可以找到一体化加载示例;检索 `dynamic instances`、`getInstanceById` 或 `test_umanager_dynamic_instances` 可以找到运行时实例编辑示例;检索 `setEditableBatching`、`SceneEditableBatchLayer`、`SceneEditableBatchFallback`、`editable batching`、`materialize` 或 `test_umanager2` 可以找到大型静态场景合批及其与 `SceneInstancedLayer` fallback 的关系;检索 `OffscreenCanvas`、`OffscreenViewerHost`、`host.init`、`initialized`、`ready`、`createWorkerViewer`、`ModelLoaderManager.setDecodeWorker`、`model-decoder`、`decode Worker`、`transferable`、`ACK backpressure`、`ImageBitmapLoader`、`maxTextureDimension2D`、`oversized texture`、`top-level await`、`u-space/worker`、`Worker WebGPU` 或 `test_umanager2_offscreen` 可以找到 Worker 渲染、嵌套静态模型解码、生命周期、事件/command 桥接、超大贴图缩放、editable batching、pipeline 预热和主线程/GPU 性能边界。
|
|
90
90
|
|
|
91
91
|
## OffscreenCanvas Worker 检索范围
|
|
92
92
|
|
|
@@ -119,6 +119,17 @@ MCP 文档索引会同步 `docs/api-objects.md` 中的核心 `InstanceObject` AP
|
|
|
119
119
|
| `FacilityInstancedLayer` | `SemanticGroup.facilityLayer` / `SemanticGroup.getDefaultFacilityLayer()`、`getInstances()`、`getInstanceById()`、`reserveBatch()`、`addInstance()` / `addInstances()`、`removeInstance()` / `removeInstances()`(支持单个 `instanceId` 字符串)、`removeBatch()`、`clearBatches()`、batch 创建条件、`setInstanceCulling()`、动态 Facilities batch、可选按相机视锥压缩 active instances、可选 `minScreenRadius` 屏幕尺寸裁剪、dirty-driven instance buffer 同步和 raycast hit remap。 |
|
|
120
120
|
| `Facilities` | `SemanticLoader` 解析、`FloorMesh.getFacilityById()`、`FacilityInstanceObject.setInstanceOpacity()`、普通 `Model` fallback wrapper 与 scene-level instancing 的一致 API;`SemanticGroup` / `BuildingGroup` / `FloorMesh` 查询使用对象语义 ID、实例 `instanceId` 或显式别名,不扫描 `userData` ID。 |
|
|
121
121
|
|
|
122
|
+
## Effects 检索范围
|
|
123
|
+
|
|
124
|
+
MCP 文档索引会同步 `docs/api-effects.md` 中的 `MaterialEffects` / `TSLEffects` API,以及 `docs/examples-guide.md` 中的 Outline 示例。客户端可以直接检索以下关键词:
|
|
125
|
+
|
|
126
|
+
| 关键词 / API | 可检索内容 |
|
|
127
|
+
| :----------- | :--------- |
|
|
128
|
+
| `TSLEffects.outline` / `TSLOutlineEffect` | 通过 `RenderPipeline.addOutputEffect()` 接入描边、`setSelectedObjects()` 替换选择、`update()` 动态调参,以及 `removeOutputEffect()` 后 `dispose()` 的完整生命周期。 |
|
|
129
|
+
| `TSLOutlineOptions` | 可见/隐藏边缘颜色、强度、厚度、Glow、降采样比例,以及 `instanceBoundsProxy`、padding 和最小尺寸默认值。 |
|
|
130
|
+
| `InstanceObject outline` / `instanceBoundsProxy` | 优先使用实例的实际渲染对象或逻辑对象渲染子树;都不存在时由世界包围盒创建不可见代理,并随 dirty callback 更新。 |
|
|
131
|
+
| `test_outline` | Box、Sphere 与核心 `InstanceObject` 的交互选择、实时参数调整和 output-effect 资源释放示例。 |
|
|
132
|
+
|
|
122
133
|
## fire 检索范围
|
|
123
134
|
|
|
124
135
|
MCP 文档索引会同步 `docs/api-plugin-fire.md` 中的 FireEffect API、参数和示例。客户端可以直接检索以下关键词:
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";function h(n){const r=n.nodes??[];if(r.length>1e5)throw new Error(`Decoded glTF contains ${r.length} nodes; the safe limit is 100000.`);const D=new Uint8Array(r.length);for(let e=0;e<r.length;e++){const d=r[e].children??[],c=new Set;for(const o of d){if(!Number.isInteger(o)||o<0||o>=r.length)throw new Error(`Decoded glTF node ${e} references invalid child ${o}.`);if(c.has(o))throw new Error(`Decoded glTF node ${e} repeats child ${o}.`);if(c.add(o),D[o]++,D[o]>1)throw new Error(`Decoded glTF node ${o} has multiple parents.`)}}const t=new Uint8Array(r.length),E=(e,d)=>{if(d>512)throw new Error("Decoded glTF node graph exceeds the safe depth of 512.");if(t[e]===1)throw new Error(`Decoded glTF node graph contains a cycle at ${e}.`);if(t[e]!==2){t[e]=1;for(const c of r[e].children??[])E(c,d+1);t[e]=2}};for(let e=0;e<r.length;e++)E(e,1);const s=n.scene??0,l=n.scenes?.[s];if(!l)throw new Error(`Decoded glTF references missing scene ${s}.`);const i=new Set;for(const e of l.nodes??[]){if(!Number.isInteger(e)||e<0||e>=r.length)throw new Error(`Decoded glTF scene ${s} references invalid node ${e}.`);if(i.has(e))throw new Error(`Decoded glTF scene ${s} repeats root node ${e}.`);if(i.add(e),D[e]>0)throw new Error(`Decoded glTF scene root ${e} is also referenced as a child.`)}}class a extends Error{name="UnsupportedModelDecodeError";constructor(r){super(r)}}exports.MODEL_DECODE_PROTOCOL_VERSION=3;exports.UnsupportedModelDecodeError=a;exports.validateDecodedGltfNodeGraph=h;
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
const h = 3;
|
|
2
|
-
function a(n) {
|
|
3
|
-
const r = n.nodes ?? [];
|
|
4
|
-
if (r.length > 1e5)
|
|
5
|
-
throw new Error(
|
|
6
|
-
`Decoded glTF contains ${r.length} nodes; the safe limit is 100000.`
|
|
7
|
-
);
|
|
8
|
-
const D = new Uint8Array(r.length);
|
|
9
|
-
for (let e = 0; e < r.length; e++) {
|
|
10
|
-
const c = r[e].children ?? [], d = /* @__PURE__ */ new Set();
|
|
11
|
-
for (const o of c) {
|
|
12
|
-
if (!Number.isInteger(o) || o < 0 || o >= r.length)
|
|
13
|
-
throw new Error(`Decoded glTF node ${e} references invalid child ${o}.`);
|
|
14
|
-
if (d.has(o))
|
|
15
|
-
throw new Error(`Decoded glTF node ${e} repeats child ${o}.`);
|
|
16
|
-
if (d.add(o), D[o]++, D[o] > 1)
|
|
17
|
-
throw new Error(`Decoded glTF node ${o} has multiple parents.`);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
const t = new Uint8Array(r.length), i = (e, c) => {
|
|
21
|
-
if (c > 512)
|
|
22
|
-
throw new Error(
|
|
23
|
-
"Decoded glTF node graph exceeds the safe depth of 512."
|
|
24
|
-
);
|
|
25
|
-
if (t[e] === 1)
|
|
26
|
-
throw new Error(`Decoded glTF node graph contains a cycle at ${e}.`);
|
|
27
|
-
if (t[e] !== 2) {
|
|
28
|
-
t[e] = 1;
|
|
29
|
-
for (const d of r[e].children ?? []) i(d, c + 1);
|
|
30
|
-
t[e] = 2;
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
for (let e = 0; e < r.length; e++) i(e, 1);
|
|
34
|
-
const s = n.scene ?? 0, l = n.scenes?.[s];
|
|
35
|
-
if (!l) throw new Error(`Decoded glTF references missing scene ${s}.`);
|
|
36
|
-
const E = /* @__PURE__ */ new Set();
|
|
37
|
-
for (const e of l.nodes ?? []) {
|
|
38
|
-
if (!Number.isInteger(e) || e < 0 || e >= r.length)
|
|
39
|
-
throw new Error(`Decoded glTF scene ${s} references invalid node ${e}.`);
|
|
40
|
-
if (E.has(e))
|
|
41
|
-
throw new Error(`Decoded glTF scene ${s} repeats root node ${e}.`);
|
|
42
|
-
if (E.add(e), D[e] > 0)
|
|
43
|
-
throw new Error(`Decoded glTF scene root ${e} is also referenced as a child.`);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
class f extends Error {
|
|
47
|
-
name = "UnsupportedModelDecodeError";
|
|
48
|
-
constructor(r) {
|
|
49
|
-
super(r);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
export {
|
|
53
|
-
h as M,
|
|
54
|
-
f as U,
|
|
55
|
-
a as v
|
|
56
|
-
};
|