@realsee/five-webgpu 1.0.0-alpha.1 → 1.0.0-alpha.3
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/README.md +9 -9
- package/ai_guides/README.md +2 -2
- package/ai_guides/features/clipper.md +1 -1
- package/ai_guides/features/coordinate-system.md +1 -1
- package/ai_guides/features/event.md +1 -1
- package/ai_guides/features/five.md +3 -3
- package/ai_guides/features/gesture.md +2 -2
- package/ai_guides/features/get-screen-pixels.md +1 -1
- package/ai_guides/features/image-options.md +3 -3
- package/ai_guides/features/load-external-model.md +9 -9
- package/ai_guides/features/mode.md +2 -2
- package/ai_guides/features/pano-filter.md +3 -3
- package/ai_guides/features/pano-tile.md +2 -2
- package/ai_guides/features/raycast.md +1 -1
- package/ai_guides/features/screen-project.md +1 -1
- package/ai_guides/features/state.md +1 -1
- package/ai_guides/features/work.md +2 -2
- package/ai_guides/quick-start.md +3 -3
- package/ai_guides/release_notes/6.6.md +2 -2
- package/ai_guides/release_notes/6.7.md +1 -1
- package/ai_guides/release_notes/6.8.md +1 -1
- package/docs/assets/hierarchy.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/classes/index.AdaptiveLuminancePass.html +1 -1
- package/docs/classes/index.EyeDomeLightingPass.html +1 -1
- package/docs/classes/index.FivePass.html +1 -1
- package/docs/classes/index.FlowingFireworks3DPass.html +1 -1
- package/docs/classes/index.FlowingLight2DPass.html +1 -1
- package/docs/classes/index.FlowingLight3DPass.html +1 -1
- package/docs/classes/index.GaussianBlurPass.html +1 -1
- package/docs/classes/index.Model.html +1 -1
- package/docs/classes/index.ModelScene.html +1 -1
- package/docs/classes/index.PBMGaussianSplattingNodeMaterial.html +7 -6
- package/docs/classes/index.PBMGaussianSplattingObject.html +12 -4
- package/docs/classes/index.PBMGaussianSplattingRenderMesh.html +31 -12
- package/docs/classes/index.PBMMeshBasicMaterial.html +1 -1
- package/docs/classes/index.PBMMeshBasicNodeMaterial.html +1 -1
- package/docs/classes/index.PBMMeshPanoOnlyMaterial.html +1 -1
- package/docs/classes/index.PBMMeshPanoOnlyNodeMaterial.html +1 -1
- package/docs/classes/index.PBMMeshPhongMaterial.html +1 -1
- package/docs/classes/index.PBMMeshPhongNodeMaterial.html +1 -1
- package/docs/classes/index.PBMMeshPhysicalMaterial.html +1 -1
- package/docs/classes/index.PBMMeshPhysicalNodeMaterial.html +1 -1
- package/docs/classes/index.PBMPanoFilter.html +1 -1
- package/docs/classes/index.PBMPointCloud.html +1 -1
- package/docs/classes/index.PBMUpdateable.html +1 -1
- package/docs/classes/index.Parameter.html +1 -1
- package/docs/classes/index.Tile3D.html +1 -1
- package/docs/classes/index.TileNode.html +1 -1
- package/docs/classes/index.TrajectoryNode.html +1 -1
- package/docs/classes/index.WorkResolvedObserver.html +1 -1
- package/docs/documents/README.html +2 -2
- package/docs/documents/features_clipper.html +1 -1
- package/docs/documents/features_coordinate-system.html +1 -1
- package/docs/documents/features_event.html +1 -1
- package/docs/documents/features_five.html +3 -3
- package/docs/documents/features_gesture.html +2 -2
- package/docs/documents/features_get-screen-pixels.html +1 -1
- package/docs/documents/features_image-options.html +3 -3
- package/docs/documents/features_load-external-model.html +8 -8
- package/docs/documents/features_mode.html +2 -2
- package/docs/documents/features_pano-filter.html +3 -3
- package/docs/documents/features_pano-tile.html +2 -2
- package/docs/documents/features_raycast.html +1 -1
- package/docs/documents/features_screen-project.html +1 -1
- package/docs/documents/features_state.html +1 -1
- package/docs/documents/features_work.html +2 -2
- package/docs/documents/quick-start.html +2 -2
- package/docs/documents/release_notes_6.6.html +2 -2
- package/docs/documents/release_notes_6.7.html +1 -1
- package/docs/documents/release_notes_6.8.html +1 -1
- package/docs/hierarchy.html +1 -1
- package/docs/index.html +2 -2
- package/docs/interfaces/index.IPBMMaterial.html +1 -1
- package/docs/interfaces/index.LooseWorkWithExtrinsics.html +1 -1
- package/docs/interfaces/index.PBMHDRConfig.html +1 -1
- package/docs/interfaces/index.ParameterMaterialValue.html +1 -1
- package/docs/interfaces/index.ParameterTilesetValue.html +1 -1
- package/docs/interfaces/index.ParameterValue.html +1 -1
- package/docs/interfaces/index.ResolvedParameterValue.html +1 -1
- package/docs/interfaces/index.SplatData.html +10 -5
- package/docs/interfaces/index.ViewLayer.html +1 -1
- package/docs/interfaces/index.WorkCubeImage.html +1 -1
- package/docs/interfaces/index.WorkImage.html +1 -1
- package/docs/interfaces/index.WorkObserver.html +1 -1
- package/docs/interfaces/index.WorkTile.html +1 -1
- package/docs/types/index.ParseOptions.html +1 -1
- package/five/gaussian-splatting/layerRegistry.d.ts +17 -0
- package/five/gaussian-splatting/shStore.d.ts +22 -0
- package/five/gaussian-splatting/splatAssembler.d.ts +69 -0
- package/five/gaussian-splatting/transformStore.d.ts +37 -0
- package/five/gaussian-splatting/wasm/sort.d.ts +4 -3
- package/five/index.js +86 -103
- package/five/index.mjs +3923 -3856
- package/five/model/loaders/spz.d.ts +50 -2
- package/five/model/materials/pbmGaussianSplattingNodeMaterial.d.ts +8 -5
- package/five/model/objects/pbmGaussianSplattingObject.d.ts +21 -4
- package/five/model/objects/pbmGaussianSplattingRenderMesh.d.ts +142 -43
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/plugins/BasePlugin/index.d.ts +1 -1
- package/plugins/GaussianSplattingEntranceAnimationPlugin/Controller.d.ts +1 -1
- package/plugins/GaussianSplattingEntranceAnimationPlugin/index.d.ts +1 -1
- package/plugins/index.js +3 -3
- package/plugins/index.mjs +3 -3
- package/react/context.d.ts +1 -1
- package/react/createProvider.d.ts +1 -1
- package/react/fiveApp.d.ts +1 -1
- package/react/hooks/unsafe__useFiveInstance.d.ts +1 -1
- package/react/hooks/useFiveAction.d.ts +1 -1
- package/react/hooks/useFiveCurrentObserver.d.ts +1 -1
- package/react/hooks/useFiveCurrentState.d.ts +1 -1
- package/react/hooks/useFiveEventCallback.d.ts +1 -1
- package/react/hooks/useFiveModelEffect.d.ts +1 -1
- package/react/hooks/useFiveModelIntersectRaycaster.d.ts +1 -1
- package/react/hooks/useFivePlugin.d.ts +1 -1
- package/react/hooks/useFiveSceneEffect.d.ts +1 -1
- package/react/hooks/useFiveState.d.ts +1 -1
- package/react/hooks/useFiveWork.d.ts +1 -1
- package/react/index.js +3 -3
- package/react/index.mjs +3 -3
- package/react/withFive.d.ts +1 -1
- package/umd/five-plugins.js +3 -3
- package/umd/five-react.js +3 -3
- package/umd/five.js +117 -134
- package/five/gaussian-splatting/util/renderData.d.ts +0 -66
|
@@ -1,8 +1,40 @@
|
|
|
1
1
|
import { Fetcher } from "../../utils/ajax";
|
|
2
|
-
import { PBMGaussianSplattingObject } from '../objects/pbmGaussianSplattingObject';
|
|
2
|
+
import type { PBMGaussianSplattingObject } from '../objects/pbmGaussianSplattingObject';
|
|
3
3
|
import { LoadResultType } from './shared';
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
5
|
+
* SPZ 纯解码的输出:仅包含原始属性数组(无 THREE / DOM 依赖),
|
|
6
|
+
* 因此可在 Worker 中安全运行。`packedData` 预留给后续在 Worker 内
|
|
7
|
+
* 用 WASM pack 后回填(见 Task 1.2)。
|
|
8
|
+
*/
|
|
9
|
+
export interface DecodedSpz {
|
|
10
|
+
numPoints: number;
|
|
11
|
+
shDegree: number;
|
|
12
|
+
positions: Float32Array;
|
|
13
|
+
colors: Uint8Array;
|
|
14
|
+
scales: Float32Array;
|
|
15
|
+
rotations: Float32Array;
|
|
16
|
+
sh1?: Float32Array;
|
|
17
|
+
sh2?: Float32Array;
|
|
18
|
+
sh3?: Float32Array;
|
|
19
|
+
/** Worker 内 WASM pack 好的 8 uint32/splat GPU 数据(Task 1.2 填入)。 */
|
|
20
|
+
packedData?: Uint32Array;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 纯解码函数:把 SPZ 字节流(gzip)解码为原始属性数组。
|
|
24
|
+
*
|
|
25
|
+
* - 不触碰主线程 / DOM,仅使用 `DecompressionStream`、`DataView`、TypedArray,
|
|
26
|
+
* 因此可在 Worker 内直接运行。
|
|
27
|
+
* - 保留 magic / version 校验(非法魔数或不支持的版本会 reject)。
|
|
28
|
+
* - 数据不足(读越界)时由 `GunzipReader` 抛出 `Unexpected EOF` 而 reject。
|
|
29
|
+
*/
|
|
30
|
+
export declare function decodeSpz(fileBytes: Uint8Array | ArrayBuffer): Promise<DecodedSpz>;
|
|
31
|
+
/**
|
|
32
|
+
* 解析 spz 格式数据为 `PBMGaussianSplattingObject`。
|
|
33
|
+
*
|
|
34
|
+
* - 解码 + WASM pack 全部在 `SPZ_Decode_Worker` 内完成,主线程不阻塞、
|
|
35
|
+
* 不重复 decode/pack(多路复用调度见文件末尾第 3 节)。
|
|
36
|
+
* - 仅在主线程动态 import 并构造 `PBMGaussianSplattingObject`(THREE 依赖),
|
|
37
|
+
* 避免把 THREE 打进 worker 包。
|
|
6
38
|
* @returns Promise<PBMGaussianSplattingObject>
|
|
7
39
|
*/
|
|
8
40
|
export declare function parseSpz(fileBytes: Uint8Array | ArrayBuffer): Promise<PBMGaussianSplattingObject>;
|
|
@@ -12,3 +44,19 @@ export declare function loadSpz(url: string, options?: {
|
|
|
12
44
|
fetcher?: Fetcher;
|
|
13
45
|
onDownloadProgress?: (percent: number, loaded?: number, total?: number) => void;
|
|
14
46
|
}): Promise<LoadResultType>;
|
|
47
|
+
/** SPZ_Decode_Worker 的解码请求。 */
|
|
48
|
+
export interface SpzDecodeRequest {
|
|
49
|
+
requestId: number;
|
|
50
|
+
fileBytes: ArrayBuffer;
|
|
51
|
+
}
|
|
52
|
+
/** SPZ_Decode_Worker 的解码响应(成功回传 decoded,失败回传 error)。 */
|
|
53
|
+
export interface SpzDecodeResponse {
|
|
54
|
+
requestId: number;
|
|
55
|
+
decoded?: DecodedSpz;
|
|
56
|
+
error?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 构造一个 SPZ_Decode_Worker 实例(自引用 inline worker)。
|
|
60
|
+
* 主线程的多路复用调度基于该入口创建共享 Worker。
|
|
61
|
+
*/
|
|
62
|
+
export declare function createSpzDecodeWorker(): Worker;
|
|
@@ -8,11 +8,12 @@
|
|
|
8
8
|
* - 2D 椭圆:求 Σ' 特征值 / 特征向量 → 主轴 √(8λ)
|
|
9
9
|
* - 片元透明度:exp(-0.5‖δ‖²) (δ 为贴切空间单位化坐标)
|
|
10
10
|
*
|
|
11
|
-
* 数据通过 DataTexture
|
|
12
|
-
* -
|
|
11
|
+
* 数据通过 DataTexture / 大数据纹理上传(阶段 E / 8 uint32 布局,2 texel/splat):
|
|
12
|
+
* - splatIndex 实例属性(float) — 第 i 实例要绘制的全局点索引 P(CPU reorder 紧凑写入)
|
|
13
|
+
* - dataTexture RGBA32UI (2048 宽) — 每 splat 2 texel:
|
|
14
|
+
* texel0: [posX/Y/Z 的 float32 位模式(bitcast), RGBA(uint8×4) 颜色]
|
|
15
|
+
* texel1: [cov00|cov01, cov02|cov11, cov12|cov22 的 half(unpack2x16float), transformIndex<<16|layerIndex]
|
|
13
16
|
* - u_transforms RGBA32F (9 宽) — 每对象 36 float = matrixWorld16 + selected4 + inverse(matrixWorld)16
|
|
14
|
-
* - u_transformIndices R32UI (1024 宽) — 每 splat 的对象索引
|
|
15
|
-
* - u_layerIndices R32UI (1024 宽) — 每 splat 的 viewlayer 索引
|
|
16
17
|
* - u_shTexture RGBA32F — SH 系数(degree 1/2/3 线性展开)
|
|
17
18
|
*/
|
|
18
19
|
import * as THREE from 'three/webgpu';
|
|
@@ -23,11 +24,12 @@ export interface PBMGaussianSplattingNodeMaterialOptions {
|
|
|
23
24
|
}
|
|
24
25
|
export declare class PBMGaussianSplattingNodeMaterial extends THREE.NodeMaterial {
|
|
25
26
|
readonly isPBMGaussianSplattingMaterial: true;
|
|
26
|
-
dataTexture: THREE.
|
|
27
|
+
dataTexture: THREE.Texture | null;
|
|
27
28
|
transformsTexture: THREE.DataTexture | null;
|
|
28
29
|
transformIndicesTexture: THREE.DataTexture | null;
|
|
29
30
|
layerIndicesTexture: THREE.DataTexture | null;
|
|
30
31
|
shTexture: THREE.DataTexture | null;
|
|
32
|
+
numPoints: number;
|
|
31
33
|
shTextureSize: THREE.Vector2;
|
|
32
34
|
aggregationEnabled: boolean;
|
|
33
35
|
aggregationProgress: number;
|
|
@@ -40,6 +42,7 @@ export declare class PBMGaussianSplattingNodeMaterial extends THREE.NodeMaterial
|
|
|
40
42
|
layerClipperRanges: THREE.Vector2[];
|
|
41
43
|
clipperMatricesInverse: THREE.Matrix4[];
|
|
42
44
|
private _uDataTex;
|
|
45
|
+
private _uNumPoints;
|
|
43
46
|
private _uTransformsTex;
|
|
44
47
|
private _uTransformIndicesTex;
|
|
45
48
|
private _uLayerIndicesTex;
|
|
@@ -2,10 +2,17 @@ import * as THREE from "three/webgpu";
|
|
|
2
2
|
import type { PBMClipperParameter } from "../materials/pbmMaterial";
|
|
3
3
|
export interface SplatData {
|
|
4
4
|
numPoints: number;
|
|
5
|
-
positions
|
|
6
|
-
colors
|
|
7
|
-
scales
|
|
8
|
-
rotations
|
|
5
|
+
positions?: Float32Array;
|
|
6
|
+
colors?: Uint8Array;
|
|
7
|
+
scales?: Float32Array;
|
|
8
|
+
rotations?: Float32Array;
|
|
9
|
+
/**
|
|
10
|
+
* 预 pack 好的 GPU 数据(8 uint32/splat,2 texel RGBA32UI)。
|
|
11
|
+
* texel0: [0..2]=posX/Y/Z float32 位模式, [3]=R|G<<8|B<<16|A<<24;
|
|
12
|
+
* texel1: [4..6]=half 精度协方差上三角 6 分量, [7]=transformIndex<<16|layerIndex。
|
|
13
|
+
* 由 worker 内 WASM `_pack` 生成后回传(见 Task 1.2 / 3.1)。
|
|
14
|
+
*/
|
|
15
|
+
packedData?: Uint32Array;
|
|
9
16
|
sh1?: Float32Array;
|
|
10
17
|
sh2?: Float32Array;
|
|
11
18
|
sh3?: Float32Array;
|
|
@@ -25,6 +32,8 @@ export declare class PBMGaussianSplattingObject extends THREE.Points<THREE.Buffe
|
|
|
25
32
|
usedSHDegree: number;
|
|
26
33
|
gsViewLayerKey: string;
|
|
27
34
|
gsClippers: readonly PBMClipperParameter[];
|
|
35
|
+
/** 加载时在 worker 中预 pack 好的 GPU 数据(8 uint32/splat) */
|
|
36
|
+
packedData: Uint32Array;
|
|
28
37
|
private _selected;
|
|
29
38
|
private _boundingBox;
|
|
30
39
|
lastMatrixWorld: THREE.Matrix4 | null;
|
|
@@ -42,6 +51,14 @@ export declare class PBMGaussianSplattingObject extends THREE.Points<THREE.Buffe
|
|
|
42
51
|
get selected(): boolean;
|
|
43
52
|
set selected(selected: boolean);
|
|
44
53
|
get boundingBox(): THREE.Box3;
|
|
54
|
+
/**
|
|
55
|
+
* 从 packedData 即时解码第 index 个 splat 的 3D 协方差矩阵(half-precision → float)。
|
|
56
|
+
* 用于 BVH 法线拟合——只在命中点按需解码。
|
|
57
|
+
* packedData texel1 布局:[4]=cov00|cov01(half2), [5]=cov02|cov11(half2), [6]=cov12|cov22(half2)。
|
|
58
|
+
* pack 端遵循 Cov4_Convention(协方差整体 ×4),此处除以 4 还原真实 Σ。
|
|
59
|
+
* 返回 6 个上三角分量 [s00, s01, s02, s11, s12, s22],数据不足时返回 null。
|
|
60
|
+
*/
|
|
61
|
+
decodeCov3D(index: number): Float32Array | null;
|
|
45
62
|
dispose(): void;
|
|
46
63
|
raycast(raycaster: THREE.Raycaster, intersects: THREE.Intersection[]): void;
|
|
47
64
|
}
|
|
@@ -1,73 +1,172 @@
|
|
|
1
1
|
import * as THREE from 'three/webgpu';
|
|
2
|
-
import { RenderData } from '../../gaussian-splatting/util/renderData';
|
|
3
2
|
import { PBMGaussianSplattingNodeMaterial } from '../materials/pbmGaussianSplattingNodeMaterial';
|
|
4
3
|
/**
|
|
5
|
-
* 3DGS 渲染 Mesh(WebGPU / TSL
|
|
4
|
+
* 3DGS 渲染 Mesh(WebGPU / TSL 版,纯 CPU 数据准备)
|
|
6
5
|
*
|
|
7
|
-
*
|
|
8
|
-
* -
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* 主循环用四个协作者准备数据(**无任何 compute shader**):
|
|
7
|
+
* - `SplatAssembler`:per-object region 增量 diff + **CPU 拼装** 大数据纹理
|
|
8
|
+
* (把各对象 packedData 紧凑拷进 CPU 缓冲,写 transformIndex/layerIndex 到 texel1.w;
|
|
9
|
+
* 经 THREE.DataTexture 上传供主材质采样)
|
|
10
|
+
* - `TransformStore`:细粒度 transform 更新(9 texel/对象,含 CPU 预算 inverse)+ 排序用 20 float/对象
|
|
11
|
+
* - `LayerRegistry`:layerKey → 稳定 layerIndex
|
|
12
|
+
* - `SHStore`:按对象顺序连续写入 SH 纹理
|
|
11
13
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
14
|
+
* 布局三一致(Requirements 13.1 / 13.2):`SplatAssembler.regionList` 顺序 ≡ `TransformStore`
|
|
15
|
+
* 索引顺序 ≡ `SHStore` 写入顺序。四个协作者都从**同一有序 `objects` 数组、同一顺序**同步,
|
|
16
|
+
* 因此不会产生 transformIndex / SH 错位;`onBeforeRender` 中另加防御性一致性断言兜底。
|
|
17
|
+
*
|
|
18
|
+
* 排序:把 `SplatAssembler.extractSortInputs()`(世界坐标 + transformIndex)与
|
|
19
|
+
* `TransformStore.transforms`(20 float/对象)喂给 Sort_Worker,回传的 `depthIndex`
|
|
20
|
+
* 保存为 `orderData`。每帧(order 或布局变化时)在 **CPU 端** 用「旧布局→当前布局」段表
|
|
21
|
+
* 把 orderData remap 到当前布局,紧凑写入 `splatIndex` 实例属性,材质用 `splatIndex` 取点驱动
|
|
22
|
+
* instanced draw(tile 增删布局变化时保持排序与大纹理映射一致、不闪烁)。
|
|
23
|
+
*
|
|
24
|
+
* 大数据纹理:
|
|
25
|
+
* - `SplatAssembler` 在对象集合变化时在 **CPU** 端把各对象 packedData 紧凑拼进一张
|
|
26
|
+
* `rgba32uint` 大纹理缓冲(2 texel/splat,texel1.w = transformIndex<<16|layerIndex),
|
|
27
|
+
* 经 `THREE.DataTexture` 上传由主材质 `textureLoad` 采样(见 `assembler.dataTexture`)。
|
|
28
|
+
* 仅在 tile 集合变化时组装一次;相机移动帧不重组装。
|
|
29
|
+
* - per-splat 的 transformIndicesTexture / layerIndicesTexture 已折叠进大纹理 texel1.w,不再单独产出;
|
|
30
|
+
* `transformsTexture` 与 `shTexture` 由对应 store 直接提供,布局与既有材质一致。
|
|
16
31
|
*/
|
|
17
32
|
declare class PBMGaussianSplattingRenderMesh extends THREE.Mesh<THREE.InstancedBufferGeometry, PBMGaussianSplattingNodeMaterial> {
|
|
18
33
|
private gsSceneState;
|
|
19
|
-
renderData: RenderData | null;
|
|
20
34
|
needsRender: boolean;
|
|
35
|
+
private assembler;
|
|
36
|
+
private transformStore;
|
|
37
|
+
private layerRegistry;
|
|
38
|
+
private shStore;
|
|
21
39
|
private sortWorker;
|
|
22
|
-
|
|
40
|
+
/**
|
|
41
|
+
* 大纹理待组装标记:tile 集合变化(rebuildScene)时置 true;onBeforeRender 中即调用
|
|
42
|
+
* `assembler.assemble()`(CPU 拼装 + DataTexture 上传)并清除。相机移动帧不置位(不重组装)。
|
|
43
|
+
*/
|
|
44
|
+
private assemblePending;
|
|
45
|
+
/** splatIndex 实例属性的当前容量(点数);不足时按 2 的幂扩容。 */
|
|
23
46
|
private splatIndexCapacity;
|
|
24
|
-
|
|
25
|
-
private
|
|
26
|
-
|
|
47
|
+
/** 单调递增的排序请求代;每代记录其所基于的布局快照,回传时按代取回(防异步错配)。 */
|
|
48
|
+
private sortGeneration;
|
|
49
|
+
/** 当前排序输入是否已上传给 worker(场景/transform 变化时置 false 触发重传)。 */
|
|
50
|
+
private sortDataUploaded;
|
|
51
|
+
/** 排序输入(布局 / transform)自上次上传后是否已变化——脏则强制重排并重传。 */
|
|
52
|
+
private sortInputsDirty;
|
|
27
53
|
private forceClipperUniformRefresh;
|
|
28
|
-
|
|
29
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Sort_Worker 是否已进入不可恢复的失败态(WASM 加载失败)。一旦置位,Render_Mesh
|
|
56
|
+
* 持续降级为空绘制(instanceCount=0),不再尝试消费排序结果(Requirement 18.1)。
|
|
57
|
+
*/
|
|
58
|
+
private sortWorkerFailed;
|
|
59
|
+
/** 当前 order 长度(= 最近一次排序回传的 depthIndex 长度 = 该次排序时 vertexCount)。 */
|
|
60
|
+
private orderCount;
|
|
61
|
+
/**
|
|
62
|
+
* 最近一次排序回传的 depthIndex 副本(基于 orderBaseSnapshot 布局的全局点索引 P 的排列)。
|
|
63
|
+
* 作为 CPU reorder 的输入源:`applyReorderCPU` 用「orderBaseSnapshot → 当前布局」段表把它
|
|
64
|
+
* remap 到当前布局,紧凑写入 splatIndex 实例属性,从而在 tile 增删(布局变化)时保持排序与
|
|
65
|
+
* 大纹理映射一致、不闪烁。
|
|
66
|
+
*/
|
|
67
|
+
private orderData;
|
|
68
|
+
/** order 内容变化(新排序回传)→ 需重跑 CPU reorder。 */
|
|
69
|
+
private orderDirty;
|
|
70
|
+
/** 布局变化(LOD 增删 / 场景重建)→ 需以新布局(新段表)重跑 CPU reorder。 */
|
|
71
|
+
private layoutDirty;
|
|
72
|
+
/** 当前存活实例数(= 最近一次 applyReorderCPU 写入 splatIndex 的点数)。 */
|
|
73
|
+
private aliveCount;
|
|
74
|
+
/** 当前 order 所基于的布局快照(= 该次排序发起时的布局)。 */
|
|
75
|
+
private orderBaseSnapshot;
|
|
76
|
+
/** generation → 该次排序发起时的布局快照。 */
|
|
77
|
+
private snapshotByGen;
|
|
78
|
+
private prevSortCameraMatrix;
|
|
79
|
+
/** 平移增量阈值(世界单位):超过才重排。 */
|
|
80
|
+
sortCameraDistance: number;
|
|
81
|
+
/** 姿态相似度阈值(|quat 点积|):低于才重排(0.99 ≈ 约 16° 内不重排)。 */
|
|
82
|
+
sortCameraCoorient: number;
|
|
83
|
+
/** 最小重排间隔(ms):即使脏也不超过此频率,0=不限。 */
|
|
84
|
+
sortMinIntervalMs: number;
|
|
85
|
+
private sortLastTime;
|
|
30
86
|
private _scratchViewProj;
|
|
31
|
-
private dataTexture;
|
|
32
|
-
private transformsTexture;
|
|
33
|
-
private transformIndicesTexture;
|
|
34
|
-
private layerIndicesTexture;
|
|
35
|
-
private shTexture;
|
|
36
87
|
private usedSHDegree;
|
|
37
88
|
constructor();
|
|
38
|
-
private ensureSplatIndexCapacity;
|
|
39
|
-
private getExpandedCapacity;
|
|
40
89
|
private createGeometry;
|
|
90
|
+
/**
|
|
91
|
+
* 确保 splatIndex 实例属性容量 >= requiredCount;不足时按 2 的幂扩容(保留旧内容)。
|
|
92
|
+
* 返回当前(可能是新建的)属性。
|
|
93
|
+
*/
|
|
94
|
+
private ensureSplatIndexCapacity;
|
|
41
95
|
private createMaterial;
|
|
42
96
|
private createDefaultLayerClipperRanges;
|
|
43
97
|
private createDefaultClipperMatrices;
|
|
44
|
-
private createTextures;
|
|
45
|
-
private createSHTexture;
|
|
46
98
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
99
|
+
* 应用排序结果:
|
|
100
|
+
* 1. 保存 depthIndex 副本到 `orderData`(作为 CPU reorder 的输入源;实际 remap 在
|
|
101
|
+
* onBeforeRender 中由 applyReorderCPU 完成,此处不写 splatIndex)。
|
|
102
|
+
* 2. 置 orderDirty(新排序回传 → 需重跑 CPU reorder)。
|
|
103
|
+
* 3. 按 generation 取回该次排序真正基于的布局快照,作为 reorder 基准,并清理更旧快照
|
|
104
|
+
* (worker 结果按 generation 单调返回,更旧快照不会再用到)。
|
|
105
|
+
* 保证:每次回传的 depthIndex 恒为「该代排序时 totalPoints」的一个排列,点数守恒。
|
|
49
106
|
*/
|
|
50
|
-
private setMaxShDegree;
|
|
51
|
-
private bindSlotTextures;
|
|
52
|
-
private disposeSlot;
|
|
53
|
-
private recycleSlot;
|
|
54
|
-
private disposeTextures;
|
|
55
107
|
private applyDepthIndex;
|
|
56
|
-
|
|
57
|
-
private
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
108
|
+
/** 捕获当前布局:assembler.regions 的 {object, start, count}(顺序即全局点区间顺序)。 */
|
|
109
|
+
private snapshotLayout;
|
|
110
|
+
/**
|
|
111
|
+
* 用「排序时旧布局 → 当前布局」构造 reorder 段表:
|
|
112
|
+
* - 存活对象:{ oldStart, oldEnd, delta = 当前 start - 旧 start, removed: false }
|
|
113
|
+
* - 被删对象:{ oldStart, oldEnd, delta: 0, removed: true }
|
|
114
|
+
* 段按 oldStart 升序(base 已按 start 升序)、区间不重叠;相邻同类段(同 removed 且
|
|
115
|
+
* removed 或 delta 相同、且首尾相接)合并以压低段数(供 applyReorderCPU 二分查找)。
|
|
116
|
+
*/
|
|
117
|
+
private buildSegments;
|
|
118
|
+
/**
|
|
119
|
+
* 二分查找覆盖全局点索引 P 的段(段按 oldStart 升序、区间 [oldStart,oldEnd) 连续无重叠)。
|
|
120
|
+
* 找不到(P 越界,理论上不会发生)返回 null。
|
|
121
|
+
*/
|
|
122
|
+
private findSegment;
|
|
123
|
+
/**
|
|
124
|
+
* CPU reorder:把最近一次排序回传的 depthIndex(orderData,基于 orderBaseSnapshot 旧布局的
|
|
125
|
+
* 全局点索引 P 的排列)用「旧布局 → 当前布局」段表 remap 到当前布局,紧凑写入 splatIndex 实例属性:
|
|
126
|
+
* - 存活对象点 P → 写入 P + delta;
|
|
127
|
+
* - 被删对象点(removed)→ 跳过(不写,实例数不计)。
|
|
128
|
+
* 从而在 tile 增删(布局变化)时保持排序顺序与大纹理映射一致、不闪烁(等价 five 的 ReorderPass)。
|
|
129
|
+
* 结果实例数写入 `geometry.instanceCount`(= 存活点数 n)。material.numPoints 设为当前布局总点数
|
|
130
|
+
* 作 shader 端 P>=numPoints 的保护性剔除(正常情况下存活区都 < numPoints)。
|
|
131
|
+
*/
|
|
132
|
+
private applyReorderCPU;
|
|
63
133
|
private collectObjects;
|
|
64
134
|
private isSceneNeedsRebuild;
|
|
65
135
|
private getClipperHash;
|
|
66
136
|
private updateClipperCounts;
|
|
137
|
+
/**
|
|
138
|
+
* clipper uniforms 直接来自 `LayerRegistry`(不再依赖 RenderData)。layerKey 取值与
|
|
139
|
+
* LayerRegistry 一致(`gsViewLayerKey || uuid`),保证 layerIndex ↔ clipper 区间对齐。
|
|
140
|
+
*/
|
|
67
141
|
private updateClipperUniforms;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
142
|
+
/**
|
|
143
|
+
* 场景变化时按**同一有序 objects**依次同步四个协作者,保证布局三一致:
|
|
144
|
+
* layerRegistry / transformStore 先行(assembler 的 resolveIndices 依赖二者的 indexOf/layerIndexOf),
|
|
145
|
+
* 再 assembler.sync(增量 diff + 连续 start 偏移,不触碰 GPU)→ shStore.sync;大纹理 GPU 组装
|
|
146
|
+
* 延迟到 onBeforeRender 中 device 就绪时的 assembler.assemble(device)。
|
|
147
|
+
*/
|
|
148
|
+
private rebuildScene;
|
|
149
|
+
/**
|
|
150
|
+
* 防御性断言:regionList 顺序 ≡ objects 顺序 ≡ TransformStore 索引顺序(Requirements 13.1/13.2)。
|
|
151
|
+
* 四者由 rebuildScene 从同一 objects 同序同步,正常情况下恒成立;不成立即视为错误状态并告警。
|
|
152
|
+
*/
|
|
153
|
+
private assertLayoutConsistency;
|
|
154
|
+
/**
|
|
155
|
+
* 把排序输入喂给 Sort_Worker:位置 + transformIndex 来自 assembler.extractSortInputs(),
|
|
156
|
+
* 变换矩阵来自 transformStore.transforms(20 float/对象,与 sort.cpp `_sort` 步长一致)。
|
|
157
|
+
* 每次上传 ++generation,回传时据此丢弃过期结果。
|
|
158
|
+
*/
|
|
159
|
+
private postSortData;
|
|
160
|
+
/**
|
|
161
|
+
* 是否需要重排:
|
|
162
|
+
* - 排序输入脏(布局 / transform 变化)或尚未上传过 → 强制重排;
|
|
163
|
+
* - 否则比较相机相对「上次排序时快照」的平移 / 姿态增量,均小于阈值则跳过(小角度节流)。
|
|
164
|
+
*/
|
|
165
|
+
private shouldSort;
|
|
166
|
+
private requestSort;
|
|
167
|
+
/** 把 store 产出的纹理与 SH 阶数同步到材质。 */
|
|
168
|
+
private syncMaterialTextures;
|
|
169
|
+
onBeforeRender: (renderer: any, scene: THREE.Scene, camera: THREE.Camera, ..._rest: any[]) => void;
|
|
71
170
|
dispose(): void;
|
|
72
171
|
}
|
|
73
172
|
export { PBMGaussianSplattingRenderMesh };
|
package/llms.txt
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Five is a 3D space rendering SDK by Realsee. This index is optimized for AI agents to locate relevant documentation.
|
|
4
4
|
|
|
5
|
-
** Documentation for @realsee/five is located in the `ai_guides/` directory. Do NOT use docs/ **
|
|
5
|
+
** Documentation for @realsee/five-webgpu is located in the `ai_guides/` directory. Do NOT use docs/ **
|
|
6
6
|
|
|
7
7
|
## Context & Guidelines
|
|
8
8
|
|
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Five } from '@realsee/five';
|
|
1
|
+
import type { Five } from '@realsee/five-webgpu';
|
|
2
2
|
import type * as GaussianSplattingEntranceAnimationPluginType from './typing';
|
|
3
3
|
import { Controller } from './Controller';
|
|
4
4
|
export declare const GaussianSplattingEntranceAnimationPlugin: (five: Five, config?: GaussianSplattingEntranceAnimationPluginType.Config) => Controller;
|
package/plugins/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
3
|
* @realsee/five-webgpu
|
|
4
|
-
* Generated: 2026/
|
|
5
|
-
* Version: 1.0.0-alpha.
|
|
4
|
+
* Generated: 2026/8/11
|
|
5
|
+
* Version: 1.0.0-alpha.3
|
|
6
6
|
* Terms:
|
|
7
7
|
* Realsee SDK License Agreement
|
|
8
8
|
* Update: July 28, 2021
|
|
@@ -252,4 +252,4 @@
|
|
|
252
252
|
* No amendment to or modification of this Agreement will be binding unless in
|
|
253
253
|
* writing and signed by Realsee. You and Realsee hereto confirm that this
|
|
254
254
|
* Agreement and all related documents shall be drafted in English.
|
|
255
|
-
*/Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require("@realsee/five"),l=require("three/webgpu");l=s(l,1);function u(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||(n=Promise))(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})}function d(e){return/^https?:\/\/|^\/\//.test(e)||/^data:/.test(e)}function f(e,t){return d(t)?t:`${e}${t}`}var p;(function(e){class t{constructor(e,t){this.hooks=new c.Subscribe,this.staticPrefix=`//vr-image-4.realsee-cdn.cn`,this.five=e,t!=null&&t.staticPrefix&&(this.staticPrefix=t.staticPrefix)}getCurrentState(){return this.state}absoluteUrl(e){return f(this.staticPrefix,e)}}e.Controller=t})(p||(p={}));var m=class{constructor(e,t,n,r,i){this.R=e,this.Q=t,this.A=n,this.B=r,this.C=i,this.cov=NaN,this.x=NaN}filter(e,t=0){if(isNaN(this.x))this.x=1/this.C*e,this.cov=1/this.C*this.Q*(1/this.C);else{let n=this.A*this.x+this.B*t,r=this.A*this.cov*this.A+this.R,i=r*this.C*(1/(this.C*r*this.C+this.Q));this.x=n+i*(e-this.C*n),this.cov=r-i*this.C*r}return this.x}},h=class extends p.Controller{updateState(e,t){let n=this.state;this.state=Object.assign(Object.assign({},this.state),e),this.hooks.emit(`stateChange`,{state:this.state,prevState:n,userAction:t})}constructor(e,t){var n,r,i;super(e),this.boundingAABB=null,this.cancelAnimation=null,this.boundsSet=!1,this.keyframes=[],this.five=e,this.state={enabled:!0,visible:!0},this.duration=(n=t==null?void 0:t.duration)==null?5e3:n,this.curveHeight=(r=t==null?void 0:t.curveHeight)==null?1.5:r,this.pointDuration=(i=t==null?void 0:t.pointDuration)==null?3e3:i}load(){return u(this,void 0,void 0,function*(){})}enable(e){var t;if(this.state.enabled)return;let n=(t=e==null?void 0:e.userAction)==null?!0:t;this.updateState({enabled:!0},n)}disable(e){var t;if(this.state.enabled===!1)return;let n=(t=e==null?void 0:e.userAction)==null?!0:t;this.updateState({enabled:!1},n)}dispose(){this.disable(),this.cancelAnimation&&(this.cancelAnimation(),this.cancelAnimation=null);try{let e=this.findRenderMesh();e&&(e.material.aggregationEnabled=!1,e.material.aggregationProgress=1)}catch(e){}}extractKeyframes(e){let t=[];if(!e.content.data)throw Error(`轨迹数据未加载`);let n=e.content.data.positionArray,r=n.length/3,i=.01,a=.1,o=new m(i,a,1,0,1),s=new m(i,a,1,0,1),c=new m(i,a,1,0,1),u=new Float32Array(r);for(let e=0;e<r;e++)if(e===0)u[e]=0;else{let t=new l.Vector3(n[(e-1)*3],n[(e-1)*3+1],n[(e-1)*3+2]);u[e]=new l.Vector3(n[e*3],n[e*3+1],n[e*3+2]).distanceTo(t)+u[e-1]}for(let i=0;i<r;i++){let a=new l.Vector3(0,0,0),d=0;for(let e=i-5;e<i+6;e++)e>=0&&e<r&&(a.add(new l.Vector3(n[e*3],n[e*3+1],n[e*3+2])),d++);a.divideScalar(d).applyMatrix4(e.transform);let f=o.filter(a.x),p=s.filter(a.y),m=c.filter(a.z);t.push({position:new l.Vector3(f,p,m),location:u[i]})}return t}computeAABB2D(e){let t=1/0,n=-1/0,r=1/0,i=-1/0;for(let a of e)a.position.x<t&&(t=a.position.x),a.position.x>n&&(n=a.position.x),a.position.z<r&&(r=a.position.z),a.position.z>i&&(i=a.position.z);return{min:new l.Vector2(t,r),max:new l.Vector2(n,i)}}findClosestKeyframeToRay(e,t){let n=1/0,r=t[0].position.clone(),i=new l.Vector3;for(let a of t){e.closestPointToPoint(a.position,i);let t=i.distanceTo(a.position);t<n&&(n=t,r=a.position.clone())}return r}findRenderMesh(){let e=null;if(this.five.scene.traverse(t=>{if(e)return;let n=t,r=n.material;r&&r.isPBMGaussianSplattingMaterial&&(e=n)}),!e)throw Error(`未找到 GaussianSplatting 渲染网格`);return e}loadTrajectoryDataIfNeeded(e){return u(this,void 0,void 0,function*(){var t,n,r,i,a,o,s,l;if((t=e.content)!=null&&t.data)return;if(((n=e.content)==null?void 0:n.loadState)===`LOADING`){yield new Promise(t=>{let n=c.AnimationFrameLoop.shared.add(()=>{var r;let i=(r=e.content)==null?void 0:r.loadState;(i===`READY`||i===`FAILED`||i===`UNLOADED`)&&(n(),t())})});return}let u=(r=this.five.model.viewLayers)==null?void 0:r[0],d=u==null?void 0:u.fetcher,f=u==null?void 0:u.search,p=(i=e.content)==null?void 0:i.uri;if(!d||!p)return;let m=f?p.includes(`?`)?`${p}&${f.replace(/^\?/,``)}`:`${p}${f.startsWith(`?`)?f:`?${f}`}`:p;e.content.loadState=`LOADING`;try{let t=yield(0,c.loadPly)(m,{type:`geometry`,customPropertyMapping:{time:{itemType:`uint32`,itemNames:[`time_milisec`]}},fetcher:d}),n=t.scene,r=n.getAttribute(`position`),i=n.getAttribute(`time`),u=(a=r==null?void 0:r.array)==null?new Float32Array:a,f=(o=i==null?void 0:i.array)==null?new Uint32Array:o;e.content.data={uri:m,byteLength:(s=t.byteLength)==null?0:s,memoryUsage:(l=t.memoryUsage)==null?0:l,positionArray:u,timeArray:f,object:null},e.content.loadState=`READY`}catch(t){console.warn(`[GaussianSplattingEntranceAnimationPlugin] trajectory ply 加载失败,将使用 3DGS AABB 回退`,t),e.content.data=void 0,e.content.loadState=`FAILED`}})}computeGSSceneBounds(){let e=new l.Box3,t=new l.Box3;return this.five.scene.traverse(n=>{let r=n;(r==null?void 0:r.boundingBox)instanceof l.Box3&&!r.boundingBox.isEmpty()&&(t.copy(r.boundingBox),r.matrixWorld&&t.applyMatrix4(r.matrixWorld),e.union(t))}),e.isEmpty()?null:e}getCameraCurve(){return u(this,void 0,void 0,function*(){var e,t,n,r,i,a,o,s,c,u;let d=(r=(n=(t=(e=this.five.model.viewLayers)==null?void 0:e[0])==null?void 0:t.trajectories)==null?void 0:n[0])==null?(s=(o=(a=(i=this.five.model.viewLayers)==null?void 0:i[0])==null?void 0:a.scene)==null?void 0:o.trajectories)==null?void 0:s[0]:r,f=null,p=null;if(d&&(yield this.loadTrajectoryDataIfNeeded(d),(c=d.content)!=null&&c.data&&((u=d.content.data.positionArray)==null?void 0:u.length)>=6&&(f=this.extractKeyframes(d),f.length>=2?p=this.computeAABB2D(f):f=null)),!f||!p){let e=this.computeGSSceneBounds();if(!e)throw Error(`未找到可用于计算入场曲线的 3DGS 边界或轨迹`);p={min:new l.Vector2(e.min.x,e.min.z),max:new l.Vector2(e.max.x,e.max.z)};let t=(p.min.x+p.max.x)/2,n=(p.min.y+p.max.y)/2,r=(e.min.y+e.max.y)/2,i=Math.max(p.max.x-p.min.x,p.max.y-p.min.y)*.5;f=[];let a=0,o=null;for(let e=0;e<16;e++){let s=e/16*Math.PI*2,c=new l.Vector3(t+Math.cos(s)*i,r,n+Math.sin(s)*i);o&&(a+=c.distanceTo(o)),f.push({position:c,location:a}),o=c}}this.keyframes=f,this.boundingAABB=p;let m=this.curveHeight,h=new l.Vector3((p.min.x+p.max.x)/2,m,(p.min.y+p.max.y)/2),g=(p.max.x-p.min.x)/2,_=(p.max.y-p.min.y)/2,v=Math.sqrt(g*g+_*_),y=e=>{let t=new l.Vector3().subVectors(e,h);return t.length()<.001&&t.set(1,0,0),h.clone().add(t.normalize().multiplyScalar(v))},b=new l.Vector3(f[0].position.x,m,f[0].position.z),x=y(b),S=new l.Vector3().subVectors(h,b).normalize(),C=new l.Ray(b,S),w=new l.Vector3(-S.z,0,S.x).normalize(),T=new l.Ray(h,w),E=this.findClosestKeyframeToRay(T,f),D=y(new l.Vector3(E.x,m,E.z)),O=this.findClosestKeyframeToRay(C,f),k=y(new l.Vector3(O.x,m,O.z));return new l.CatmullRomCurve3([x,D,k],!1,`centripetal`,.5)})}setBounding(e,t,n){let r=this.findRenderMesh();r.material.aggregationBoundsMin.copy(e),r.material.aggregationBoundsMax.copy(t),this.boundsSet=!0}setBounds(){if(!this.boundingAABB)throw Error(`请先调用 getCameraCurve 计算轨迹边界`);let e=this.boundingAABB,t=this.findRenderMesh(),n=new l.Vector3(e.min.x,0,e.min.y),r=new l.Vector3(e.max.x,3,e.max.y);t.material.aggregationBoundsMin.copy(n),t.material.aggregationBoundsMax.copy(r),this.boundsSet=!0}normalizedPointDuration(){let e=this.pointDuration;return e<=0?.01:Math.min(e<=1?e:e/this.duration,1)}resetToPointCloud(){return u(this,void 0,void 0,function*(){this.boundingAABB||(yield this.getCameraCurve()),this.setBounds();let e=this.findRenderMesh().material;e.aggregationEnabled=!0,e.aggregationProgress=0,e.aggregationPointDuration=this.normalizedPointDuration(),this.five.needsRender=!0,this.five.modelSceneNeedsRender=!0})}startAggregation(){if(!this.boundsSet)throw Error(`请先调用 setBounds 设置聚合边界`);let e=this.findRenderMesh().material;e.aggregationEnabled=!0,e.aggregationProgress=0,e.aggregationPointDuration=this.normalizedPointDuration(),this.five.needsRender=!0;let t=performance.now(),n=this.duration;this.cancelAnimation=c.AnimationFrameLoop.shared.add(()=>{let r=performance.now()-t,i=Math.min(r/n,1);e.aggregationProgress=i*i*(3-2*i),this.five.needsRender=!0,this.five.modelSceneNeedsRender=!0,i>=1&&(e.aggregationEnabled=!1,this.cancelAnimation&&(this.cancelAnimation(),this.cancelAnimation=null))})}playEntrance(){return u(this,void 0,void 0,function*(){let e=yield this.getCameraCurve(),t=this.boundingAABB,n=new l.Vector3((t.min.x+t.max.x)/2,this.curveHeight,(t.min.y+t.max.y)/2),r=e.getPointAt(0),i=new c.Camera(90).copy(this.five.camera);i.position.copy(r),i.lookAt(n),i.computePose(0),this.five.setState(Object.assign({},i.pose)),this.setBounds();let a=this.findRenderMesh().material;a.aggregationEnabled=!0,a.aggregationProgress=0,a.aggregationPointDuration=this.normalizedPointDuration(),this.five.needsRender=!0;let o=this.duration,s=performance.now();return new Promise(t=>{this.cancelAnimation=c.AnimationFrameLoop.shared.add(()=>{let r=performance.now()-s,c=Math.min(r/o,1),l=c*c*(3-2*c);a.aggregationProgress=l,this.five.modelSceneNeedsRender=!0;let u=e.getPointAt(l);i.position.copy(u),i.lookAt(n),i.computePose(0),this.five.setState(Object.assign({},i.pose)),this.five.needsRender=!0,c>=1&&(a.aggregationEnabled=!1,a.aggregationProgress=1,this.cancelAnimation&&(this.cancelAnimation(),this.cancelAnimation=null),t())})})})}},g=(e,t)=>new h(e,t);Object.defineProperty(exports,"BasePlugin",{enumerable:!0,get:function(){return p}}),exports.GaussianSplattingEntranceAnimationPlugin=g;
|
|
255
|
+
*/Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require("@realsee/five-webgpu"),l=require("three/webgpu");l=s(l,1);function u(e,t,n,r){function i(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||(n=Promise))(function(n,a){function o(e){try{c(r.next(e))}catch(e){a(e)}}function s(e){try{c(r.throw(e))}catch(e){a(e)}}function c(e){e.done?n(e.value):i(e.value).then(o,s)}c((r=r.apply(e,t||[])).next())})}function d(e){return/^https?:\/\/|^\/\//.test(e)||/^data:/.test(e)}function f(e,t){return d(t)?t:`${e}${t}`}var p;(function(e){class t{constructor(e,t){this.hooks=new c.Subscribe,this.staticPrefix=`//vr-image-4.realsee-cdn.cn`,this.five=e,t!=null&&t.staticPrefix&&(this.staticPrefix=t.staticPrefix)}getCurrentState(){return this.state}absoluteUrl(e){return f(this.staticPrefix,e)}}e.Controller=t})(p||(p={}));var m=class{constructor(e,t,n,r,i){this.R=e,this.Q=t,this.A=n,this.B=r,this.C=i,this.cov=NaN,this.x=NaN}filter(e,t=0){if(isNaN(this.x))this.x=1/this.C*e,this.cov=1/this.C*this.Q*(1/this.C);else{let n=this.A*this.x+this.B*t,r=this.A*this.cov*this.A+this.R,i=r*this.C*(1/(this.C*r*this.C+this.Q));this.x=n+i*(e-this.C*n),this.cov=r-i*this.C*r}return this.x}},h=class extends p.Controller{updateState(e,t){let n=this.state;this.state=Object.assign(Object.assign({},this.state),e),this.hooks.emit(`stateChange`,{state:this.state,prevState:n,userAction:t})}constructor(e,t){var n,r,i;super(e),this.boundingAABB=null,this.cancelAnimation=null,this.boundsSet=!1,this.keyframes=[],this.five=e,this.state={enabled:!0,visible:!0},this.duration=(n=t==null?void 0:t.duration)==null?5e3:n,this.curveHeight=(r=t==null?void 0:t.curveHeight)==null?1.5:r,this.pointDuration=(i=t==null?void 0:t.pointDuration)==null?3e3:i}load(){return u(this,void 0,void 0,function*(){})}enable(e){var t;if(this.state.enabled)return;let n=(t=e==null?void 0:e.userAction)==null?!0:t;this.updateState({enabled:!0},n)}disable(e){var t;if(this.state.enabled===!1)return;let n=(t=e==null?void 0:e.userAction)==null?!0:t;this.updateState({enabled:!1},n)}dispose(){this.disable(),this.cancelAnimation&&(this.cancelAnimation(),this.cancelAnimation=null);try{let e=this.findRenderMesh();e&&(e.material.aggregationEnabled=!1,e.material.aggregationProgress=1)}catch(e){}}extractKeyframes(e){let t=[];if(!e.content.data)throw Error(`轨迹数据未加载`);let n=e.content.data.positionArray,r=n.length/3,i=.01,a=.1,o=new m(i,a,1,0,1),s=new m(i,a,1,0,1),c=new m(i,a,1,0,1),u=new Float32Array(r);for(let e=0;e<r;e++)if(e===0)u[e]=0;else{let t=new l.Vector3(n[(e-1)*3],n[(e-1)*3+1],n[(e-1)*3+2]);u[e]=new l.Vector3(n[e*3],n[e*3+1],n[e*3+2]).distanceTo(t)+u[e-1]}for(let i=0;i<r;i++){let a=new l.Vector3(0,0,0),d=0;for(let e=i-5;e<i+6;e++)e>=0&&e<r&&(a.add(new l.Vector3(n[e*3],n[e*3+1],n[e*3+2])),d++);a.divideScalar(d).applyMatrix4(e.transform);let f=o.filter(a.x),p=s.filter(a.y),m=c.filter(a.z);t.push({position:new l.Vector3(f,p,m),location:u[i]})}return t}computeAABB2D(e){let t=1/0,n=-1/0,r=1/0,i=-1/0;for(let a of e)a.position.x<t&&(t=a.position.x),a.position.x>n&&(n=a.position.x),a.position.z<r&&(r=a.position.z),a.position.z>i&&(i=a.position.z);return{min:new l.Vector2(t,r),max:new l.Vector2(n,i)}}findClosestKeyframeToRay(e,t){let n=1/0,r=t[0].position.clone(),i=new l.Vector3;for(let a of t){e.closestPointToPoint(a.position,i);let t=i.distanceTo(a.position);t<n&&(n=t,r=a.position.clone())}return r}findRenderMesh(){let e=null;if(this.five.scene.traverse(t=>{if(e)return;let n=t,r=n.material;r&&r.isPBMGaussianSplattingMaterial&&(e=n)}),!e)throw Error(`未找到 GaussianSplatting 渲染网格`);return e}loadTrajectoryDataIfNeeded(e){return u(this,void 0,void 0,function*(){var t,n,r,i,a,o,s,l;if((t=e.content)!=null&&t.data)return;if(((n=e.content)==null?void 0:n.loadState)===`LOADING`){yield new Promise(t=>{let n=c.AnimationFrameLoop.shared.add(()=>{var r;let i=(r=e.content)==null?void 0:r.loadState;(i===`READY`||i===`FAILED`||i===`UNLOADED`)&&(n(),t())})});return}let u=(r=this.five.model.viewLayers)==null?void 0:r[0],d=u==null?void 0:u.fetcher,f=u==null?void 0:u.search,p=(i=e.content)==null?void 0:i.uri;if(!d||!p)return;let m=f?p.includes(`?`)?`${p}&${f.replace(/^\?/,``)}`:`${p}${f.startsWith(`?`)?f:`?${f}`}`:p;e.content.loadState=`LOADING`;try{let t=yield(0,c.loadPly)(m,{type:`geometry`,customPropertyMapping:{time:{itemType:`uint32`,itemNames:[`time_milisec`]}},fetcher:d}),n=t.scene,r=n.getAttribute(`position`),i=n.getAttribute(`time`),u=(a=r==null?void 0:r.array)==null?new Float32Array:a,f=(o=i==null?void 0:i.array)==null?new Uint32Array:o;e.content.data={uri:m,byteLength:(s=t.byteLength)==null?0:s,memoryUsage:(l=t.memoryUsage)==null?0:l,positionArray:u,timeArray:f,object:null},e.content.loadState=`READY`}catch(t){console.warn(`[GaussianSplattingEntranceAnimationPlugin] trajectory ply 加载失败,将使用 3DGS AABB 回退`,t),e.content.data=void 0,e.content.loadState=`FAILED`}})}computeGSSceneBounds(){let e=new l.Box3,t=new l.Box3;return this.five.scene.traverse(n=>{let r=n;(r==null?void 0:r.boundingBox)instanceof l.Box3&&!r.boundingBox.isEmpty()&&(t.copy(r.boundingBox),r.matrixWorld&&t.applyMatrix4(r.matrixWorld),e.union(t))}),e.isEmpty()?null:e}getCameraCurve(){return u(this,void 0,void 0,function*(){var e,t,n,r,i,a,o,s,c,u;let d=(r=(n=(t=(e=this.five.model.viewLayers)==null?void 0:e[0])==null?void 0:t.trajectories)==null?void 0:n[0])==null?(s=(o=(a=(i=this.five.model.viewLayers)==null?void 0:i[0])==null?void 0:a.scene)==null?void 0:o.trajectories)==null?void 0:s[0]:r,f=null,p=null;if(d&&(yield this.loadTrajectoryDataIfNeeded(d),(c=d.content)!=null&&c.data&&((u=d.content.data.positionArray)==null?void 0:u.length)>=6&&(f=this.extractKeyframes(d),f.length>=2?p=this.computeAABB2D(f):f=null)),!f||!p){let e=this.computeGSSceneBounds();if(!e)throw Error(`未找到可用于计算入场曲线的 3DGS 边界或轨迹`);p={min:new l.Vector2(e.min.x,e.min.z),max:new l.Vector2(e.max.x,e.max.z)};let t=(p.min.x+p.max.x)/2,n=(p.min.y+p.max.y)/2,r=(e.min.y+e.max.y)/2,i=Math.max(p.max.x-p.min.x,p.max.y-p.min.y)*.5;f=[];let a=0,o=null;for(let e=0;e<16;e++){let s=e/16*Math.PI*2,c=new l.Vector3(t+Math.cos(s)*i,r,n+Math.sin(s)*i);o&&(a+=c.distanceTo(o)),f.push({position:c,location:a}),o=c}}this.keyframes=f,this.boundingAABB=p;let m=this.curveHeight,h=new l.Vector3((p.min.x+p.max.x)/2,m,(p.min.y+p.max.y)/2),g=(p.max.x-p.min.x)/2,_=(p.max.y-p.min.y)/2,v=Math.sqrt(g*g+_*_),y=e=>{let t=new l.Vector3().subVectors(e,h);return t.length()<.001&&t.set(1,0,0),h.clone().add(t.normalize().multiplyScalar(v))},b=new l.Vector3(f[0].position.x,m,f[0].position.z),x=y(b),S=new l.Vector3().subVectors(h,b).normalize(),C=new l.Ray(b,S),w=new l.Vector3(-S.z,0,S.x).normalize(),T=new l.Ray(h,w),E=this.findClosestKeyframeToRay(T,f),D=y(new l.Vector3(E.x,m,E.z)),O=this.findClosestKeyframeToRay(C,f),k=y(new l.Vector3(O.x,m,O.z));return new l.CatmullRomCurve3([x,D,k],!1,`centripetal`,.5)})}setBounding(e,t,n){let r=this.findRenderMesh();r.material.aggregationBoundsMin.copy(e),r.material.aggregationBoundsMax.copy(t),this.boundsSet=!0}setBounds(){if(!this.boundingAABB)throw Error(`请先调用 getCameraCurve 计算轨迹边界`);let e=this.boundingAABB,t=this.findRenderMesh(),n=new l.Vector3(e.min.x,0,e.min.y),r=new l.Vector3(e.max.x,3,e.max.y);t.material.aggregationBoundsMin.copy(n),t.material.aggregationBoundsMax.copy(r),this.boundsSet=!0}normalizedPointDuration(){let e=this.pointDuration;return e<=0?.01:Math.min(e<=1?e:e/this.duration,1)}resetToPointCloud(){return u(this,void 0,void 0,function*(){this.boundingAABB||(yield this.getCameraCurve()),this.setBounds();let e=this.findRenderMesh().material;e.aggregationEnabled=!0,e.aggregationProgress=0,e.aggregationPointDuration=this.normalizedPointDuration(),this.five.needsRender=!0,this.five.modelSceneNeedsRender=!0})}startAggregation(){if(!this.boundsSet)throw Error(`请先调用 setBounds 设置聚合边界`);let e=this.findRenderMesh().material;e.aggregationEnabled=!0,e.aggregationProgress=0,e.aggregationPointDuration=this.normalizedPointDuration(),this.five.needsRender=!0;let t=performance.now(),n=this.duration;this.cancelAnimation=c.AnimationFrameLoop.shared.add(()=>{let r=performance.now()-t,i=Math.min(r/n,1);e.aggregationProgress=i*i*(3-2*i),this.five.needsRender=!0,this.five.modelSceneNeedsRender=!0,i>=1&&(e.aggregationEnabled=!1,this.cancelAnimation&&(this.cancelAnimation(),this.cancelAnimation=null))})}playEntrance(){return u(this,void 0,void 0,function*(){let e=yield this.getCameraCurve(),t=this.boundingAABB,n=new l.Vector3((t.min.x+t.max.x)/2,this.curveHeight,(t.min.y+t.max.y)/2),r=e.getPointAt(0),i=new c.Camera(90).copy(this.five.camera);i.position.copy(r),i.lookAt(n),i.computePose(0),this.five.setState(Object.assign({},i.pose)),this.setBounds();let a=this.findRenderMesh().material;a.aggregationEnabled=!0,a.aggregationProgress=0,a.aggregationPointDuration=this.normalizedPointDuration(),this.five.needsRender=!0;let o=this.duration,s=performance.now();return new Promise(t=>{this.cancelAnimation=c.AnimationFrameLoop.shared.add(()=>{let r=performance.now()-s,c=Math.min(r/o,1),l=c*c*(3-2*c);a.aggregationProgress=l,this.five.modelSceneNeedsRender=!0;let u=e.getPointAt(l);i.position.copy(u),i.lookAt(n),i.computePose(0),this.five.setState(Object.assign({},i.pose)),this.five.needsRender=!0,c>=1&&(a.aggregationEnabled=!1,a.aggregationProgress=1,this.cancelAnimation&&(this.cancelAnimation(),this.cancelAnimation=null),t())})})})}},g=(e,t)=>new h(e,t);Object.defineProperty(exports,"BasePlugin",{enumerable:!0,get:function(){return p}}),exports.GaussianSplattingEntranceAnimationPlugin=g;
|
package/plugins/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
3
|
* @realsee/five-webgpu
|
|
4
|
-
* Generated: 2026/
|
|
5
|
-
* Version: 1.0.0-alpha.
|
|
4
|
+
* Generated: 2026/8/11
|
|
5
|
+
* Version: 1.0.0-alpha.3
|
|
6
6
|
* Terms:
|
|
7
7
|
* Realsee SDK License Agreement
|
|
8
8
|
* Update: July 28, 2021
|
|
@@ -252,7 +252,7 @@
|
|
|
252
252
|
* No amendment to or modification of this Agreement will be binding unless in
|
|
253
253
|
* writing and signed by Realsee. You and Realsee hereto confirm that this
|
|
254
254
|
* Agreement and all related documents shall be drafted in English.
|
|
255
|
-
*/import { AnimationFrameLoop as e, Camera as t, Subscribe as n, loadPly as r } from "@realsee/five";
|
|
255
|
+
*/import { AnimationFrameLoop as e, Camera as t, Subscribe as n, loadPly as r } from "@realsee/five-webgpu";
|
|
256
256
|
import * as i from "three/webgpu";
|
|
257
257
|
//#region node_modules/tslib/tslib.es6.mjs
|
|
258
258
|
function a(e, t, n, r) {
|
package/react/context.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as THREE from "three/webgpu";
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
import { Five, Work, State, FiveLoadOptions } from "@realsee/five";
|
|
3
|
+
import { Five, Work, State, FiveLoadOptions } from "@realsee/five-webgpu";
|
|
4
4
|
type ContextType = null | {
|
|
5
5
|
renderer?: THREE.WebGPURenderer;
|
|
6
6
|
five: Five;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as THREE from "three/webgpu";
|
|
3
|
-
import { Five, FiveInitArgs, FiveLoadOptions, Work, Works, State } from "@realsee/five";
|
|
3
|
+
import { Five, FiveInitArgs, FiveLoadOptions, Work, Works, State } from "@realsee/five-webgpu";
|
|
4
4
|
type FiveProviderPropTypes = {
|
|
5
5
|
work?: Work | Work[];
|
|
6
6
|
initialWork?: Work | Work[];
|
package/react/fiveApp.d.ts
CHANGED