@d5techs/3dgs-lib 1.3.0 → 1.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/dist/3dgs-lib.cjs +3626 -1380
- package/dist/3dgs-lib.cjs.map +1 -1
- package/dist/3dgs-lib.js +3626 -1380
- package/dist/3dgs-lib.js.map +1 -1
- package/dist/App.d.ts +35 -3
- package/dist/core/gizmo/TransformGizmo.d.ts +2 -0
- package/dist/editor/EditHistory.d.ts +13 -0
- package/dist/editor/EditOps.d.ts +56 -0
- package/dist/editor/Events.d.ts +13 -0
- package/dist/editor/SplatEditor.d.ts +80 -0
- package/dist/editor/SplatExporter.d.ts +6 -0
- package/dist/editor/SplatState.d.ts +18 -0
- package/dist/editor/index.d.ts +7 -0
- package/dist/editor/tools/BrushSelection.d.ts +21 -0
- package/dist/editor/tools/EyedropperSelection.d.ts +21 -0
- package/dist/editor/tools/FloodSelection.d.ts +22 -0
- package/dist/editor/tools/LassoSelection.d.ts +24 -0
- package/dist/editor/tools/PolygonSelection.d.ts +22 -0
- package/dist/editor/tools/RectSelection.d.ts +24 -0
- package/dist/editor/tools/ToolManager.d.ts +14 -0
- package/dist/gs/GSSplatRenderer.d.ts +21 -0
- package/dist/index.d.ts +8 -1
- package/dist/interaction/GizmoManager.d.ts +1 -0
- package/dist/interaction/HotspotManager.d.ts +57 -0
- package/package.json +1 -1
package/dist/App.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ import { GSSplatRenderer } from "./gs/GSSplatRenderer";
|
|
|
19
19
|
import { GSSplatRendererMobile } from "./gs/GSSplatRendererMobile";
|
|
20
20
|
import type { BoundingBox, SimpleBoundingBox } from "./types";
|
|
21
21
|
import { HotspotManager } from "./interaction/HotspotManager";
|
|
22
|
-
import type { HotspotInfo } from "./interaction/HotspotManager";
|
|
22
|
+
import type { HotspotInfo, HotspotLabelPosition, HotspotLabelConfig } from "./interaction/HotspotManager";
|
|
23
23
|
import { SplatTransformProxy, MeshGroupProxy, SplatBoundingBoxProvider } from "./scene/proxies";
|
|
24
24
|
import { TransformableObject, GizmoMode } from "./core/gizmo/TransformGizmo";
|
|
25
25
|
import type { BoundingBoxProvider } from "./types";
|
|
@@ -49,6 +49,7 @@ export declare class App {
|
|
|
49
49
|
private isRunning;
|
|
50
50
|
private animationId;
|
|
51
51
|
private useMobileRenderer;
|
|
52
|
+
private lastCompactData;
|
|
52
53
|
private boundOnResize;
|
|
53
54
|
constructor(canvas: HTMLCanvasElement);
|
|
54
55
|
/**
|
|
@@ -73,12 +74,14 @@ export declare class App {
|
|
|
73
74
|
addPLY(urlOrBuffer: string | ArrayBuffer, onProgress?: ProgressCallback, isLocalFile?: boolean, coordinateSystem?: CoordinateSystem): Promise<number>;
|
|
74
75
|
/**
|
|
75
76
|
* 加载 Splat 文件
|
|
77
|
+
* @param coordinateSystem 源数据坐标系,默认 'blender'(Z-up → Y-up 自动转换)
|
|
76
78
|
*/
|
|
77
|
-
addSplat(urlOrBuffer: string | ArrayBuffer, onProgress?: ProgressCallback, isLocalFile?: boolean): Promise<number>;
|
|
79
|
+
addSplat(urlOrBuffer: string | ArrayBuffer, onProgress?: ProgressCallback, isLocalFile?: boolean, coordinateSystem?: CoordinateSystem): Promise<number>;
|
|
78
80
|
/**
|
|
79
81
|
* 加载 SOG 文件 (Spatially Ordered Gaussians)
|
|
82
|
+
* @param coordinateSystem 源数据坐标系,默认 'blender'(Z-up → Y-up 自动转换)
|
|
80
83
|
*/
|
|
81
|
-
addSOG(urlOrBuffer: string | ArrayBuffer, onProgress?: ProgressCallback, isLocalFile?: boolean): Promise<number>;
|
|
84
|
+
addSOG(urlOrBuffer: string | ArrayBuffer, onProgress?: ProgressCallback, isLocalFile?: boolean, coordinateSystem?: CoordinateSystem): Promise<number>;
|
|
82
85
|
/**
|
|
83
86
|
* 添加测试立方体
|
|
84
87
|
*/
|
|
@@ -128,6 +131,7 @@ export declare class App {
|
|
|
128
131
|
getViewportGizmo(): import(".").ViewportGizmo;
|
|
129
132
|
getBoundingBoxRenderer(): import(".").BoundingBoxRenderer;
|
|
130
133
|
setGizmoMode(mode: GizmoMode): void;
|
|
134
|
+
setUniformScaleOnly(enabled: boolean): void;
|
|
131
135
|
setGizmoTarget(object: TransformableObject | null): void;
|
|
132
136
|
setSelectionBoundingBox(box: SimpleBoundingBox | null): void;
|
|
133
137
|
setSelectionBoundingBoxProvider(provider: BoundingBoxProvider | null): void;
|
|
@@ -151,6 +155,8 @@ export declare class App {
|
|
|
151
155
|
getGSRenderer(): GSSplatRenderer | undefined;
|
|
152
156
|
getGSRendererMobile(): GSSplatRendererMobile | undefined;
|
|
153
157
|
isUsingMobileRenderer(): boolean;
|
|
158
|
+
getLastCompactData(): import('./gs/PLYLoaderMobile').CompactSplatData | null;
|
|
159
|
+
setLastCompactData(data: import('./gs/PLYLoaderMobile').CompactSplatData): void;
|
|
154
160
|
getHotspotManager(): HotspotManager;
|
|
155
161
|
enterHotspotMode(objUrl: string): void;
|
|
156
162
|
exitHotspotMode(): void;
|
|
@@ -160,7 +166,33 @@ export declare class App {
|
|
|
160
166
|
getHotspotBillboard(hotspotIndex: number): boolean;
|
|
161
167
|
getHotspotCount(): number;
|
|
162
168
|
findHotspotIndexByMeshStart(overlayMeshStartIndex: number): number;
|
|
169
|
+
placeHotspotAt(objUrl: string, position: [number, number, number], normal: [number, number, number], visualDiameter?: number, normalOffset?: number, overrideScale?: number): Promise<HotspotInfo | null>;
|
|
163
170
|
getOverlayMeshByIndex(index: number): import("./mesh/Mesh").Mesh | null;
|
|
171
|
+
/**
|
|
172
|
+
* 检测给定屏幕坐标命中了哪个热点
|
|
173
|
+
* @returns 热点索引,-1 表示未命中
|
|
174
|
+
*/
|
|
175
|
+
hitTestHotspot(clientX: number, clientY: number): number;
|
|
176
|
+
/**
|
|
177
|
+
* 设置热点点击回调(非放置模式下生效)
|
|
178
|
+
*/
|
|
179
|
+
setOnHotspotClicked(cb: ((hotspotIndex: number, info: HotspotInfo) => void) | null): void;
|
|
180
|
+
/**
|
|
181
|
+
* 设置热点点击命中半径(NDC 空间,默认 0.05)
|
|
182
|
+
*/
|
|
183
|
+
setHotspotHitRadius(radius: number): void;
|
|
184
|
+
/**
|
|
185
|
+
* 设置热点文字标签
|
|
186
|
+
*/
|
|
187
|
+
setHotspotLabel(hotspotIndex: number, text: string, position?: HotspotLabelPosition, fontSize?: number, visible?: boolean): boolean;
|
|
188
|
+
/**
|
|
189
|
+
* 设置热点标签可见性
|
|
190
|
+
*/
|
|
191
|
+
setHotspotLabelVisible(hotspotIndex: number, visible: boolean): boolean;
|
|
192
|
+
/**
|
|
193
|
+
* 获取热点标签配置
|
|
194
|
+
*/
|
|
195
|
+
getHotspotLabel(hotspotIndex: number): HotspotLabelConfig | null;
|
|
164
196
|
private fetchWithProgress;
|
|
165
197
|
private parsePLYBuffer;
|
|
166
198
|
setGridVisible(visible: boolean): void;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { EditOp } from './EditOps';
|
|
2
|
+
export declare class EditHistory {
|
|
3
|
+
private history;
|
|
4
|
+
private cursor;
|
|
5
|
+
private onChange?;
|
|
6
|
+
constructor(onChange?: () => void);
|
|
7
|
+
add(op: EditOp): void;
|
|
8
|
+
canUndo(): boolean;
|
|
9
|
+
canRedo(): boolean;
|
|
10
|
+
undo(): void;
|
|
11
|
+
redo(): void;
|
|
12
|
+
clear(): void;
|
|
13
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { SplatState } from './SplatState';
|
|
2
|
+
export interface EditOp {
|
|
3
|
+
name: string;
|
|
4
|
+
do(): void;
|
|
5
|
+
undo(): void;
|
|
6
|
+
destroy?(): void;
|
|
7
|
+
}
|
|
8
|
+
export declare class SelectOp implements EditOp {
|
|
9
|
+
name: string;
|
|
10
|
+
private inner;
|
|
11
|
+
constructor(state: SplatState, op: 'add' | 'remove' | 'set', predicate: (i: number) => boolean);
|
|
12
|
+
do(): void;
|
|
13
|
+
undo(): void;
|
|
14
|
+
}
|
|
15
|
+
export declare class SelectAllOp implements EditOp {
|
|
16
|
+
name: string;
|
|
17
|
+
private inner;
|
|
18
|
+
constructor(state: SplatState);
|
|
19
|
+
do(): void;
|
|
20
|
+
undo(): void;
|
|
21
|
+
}
|
|
22
|
+
export declare class SelectNoneOp implements EditOp {
|
|
23
|
+
name: string;
|
|
24
|
+
private inner;
|
|
25
|
+
constructor(state: SplatState);
|
|
26
|
+
do(): void;
|
|
27
|
+
undo(): void;
|
|
28
|
+
}
|
|
29
|
+
export declare class SelectInvertOp implements EditOp {
|
|
30
|
+
name: string;
|
|
31
|
+
private inner;
|
|
32
|
+
constructor(state: SplatState);
|
|
33
|
+
do(): void;
|
|
34
|
+
undo(): void;
|
|
35
|
+
}
|
|
36
|
+
export declare class DeleteSelectionOp implements EditOp {
|
|
37
|
+
name: string;
|
|
38
|
+
private inner;
|
|
39
|
+
constructor(state: SplatState);
|
|
40
|
+
do(): void;
|
|
41
|
+
undo(): void;
|
|
42
|
+
}
|
|
43
|
+
export declare class HideSelectionOp implements EditOp {
|
|
44
|
+
name: string;
|
|
45
|
+
private inner;
|
|
46
|
+
constructor(state: SplatState);
|
|
47
|
+
do(): void;
|
|
48
|
+
undo(): void;
|
|
49
|
+
}
|
|
50
|
+
export declare class UnhideAllOp implements EditOp {
|
|
51
|
+
name: string;
|
|
52
|
+
private inner;
|
|
53
|
+
constructor(state: SplatState);
|
|
54
|
+
do(): void;
|
|
55
|
+
undo(): void;
|
|
56
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type Listener = (...args: any[]) => void;
|
|
2
|
+
type AsyncListener = (...args: any[]) => Promise<any>;
|
|
3
|
+
export declare class Events {
|
|
4
|
+
private listeners;
|
|
5
|
+
private asyncHandlers;
|
|
6
|
+
on(event: string, fn: Listener): () => void;
|
|
7
|
+
off(event: string, fn: Listener): void;
|
|
8
|
+
fire(event: string, ...args: any[]): void;
|
|
9
|
+
handler(event: string, fn: AsyncListener): void;
|
|
10
|
+
invoke(event: string, ...args: any[]): Promise<any>;
|
|
11
|
+
destroy(): void;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SplatEditor - 3DGS 模型编辑器核心类
|
|
3
|
+
*
|
|
4
|
+
* 协调选择工具、编辑历史、状态管理和渲染器集成。
|
|
5
|
+
* 将 splat 中心投影到屏幕空间来判断哪些 splat 在选区内。
|
|
6
|
+
*/
|
|
7
|
+
import type { Camera } from '../core/Camera';
|
|
8
|
+
import type { GSSplatRenderer } from '../gs/GSSplatRenderer';
|
|
9
|
+
import type { CompactSplatData } from '../gs/PLYLoaderMobile';
|
|
10
|
+
import { SplatState } from './SplatState';
|
|
11
|
+
import { EditHistory } from './EditHistory';
|
|
12
|
+
import { ToolManager } from './tools/ToolManager';
|
|
13
|
+
export interface SplatEditorCallbacks {
|
|
14
|
+
onStateChanged?: () => void;
|
|
15
|
+
onToolChanged?: (tool: string | null) => void;
|
|
16
|
+
onHistoryChanged?: (canUndo: boolean, canRedo: boolean) => void;
|
|
17
|
+
/** 退出编辑模式时调用,传回精简后的 CompactSplatData(已剔除删除的 splat) */
|
|
18
|
+
onApplyEdits?: (newData: CompactSplatData) => void;
|
|
19
|
+
}
|
|
20
|
+
export declare class SplatEditor {
|
|
21
|
+
private camera;
|
|
22
|
+
private gsRenderer;
|
|
23
|
+
private container;
|
|
24
|
+
private splatState;
|
|
25
|
+
private editHistory;
|
|
26
|
+
private toolManager;
|
|
27
|
+
private compactData;
|
|
28
|
+
private callbacks;
|
|
29
|
+
private maskCanvas;
|
|
30
|
+
private maskCtx;
|
|
31
|
+
private toolOverlay;
|
|
32
|
+
private projectedPositions;
|
|
33
|
+
private projDirty;
|
|
34
|
+
private _active;
|
|
35
|
+
private overlayCleanup;
|
|
36
|
+
constructor(camera: Camera, gsRenderer: GSSplatRenderer, container: HTMLElement, callbacks?: SplatEditorCallbacks);
|
|
37
|
+
get active(): boolean;
|
|
38
|
+
get state(): SplatState;
|
|
39
|
+
get history(): EditHistory;
|
|
40
|
+
get tools(): ToolManager;
|
|
41
|
+
/**
|
|
42
|
+
* 设置 compact 数据引用(用于导出和颜色匹配)
|
|
43
|
+
*/
|
|
44
|
+
setCompactData(data: CompactSplatData): void;
|
|
45
|
+
/**
|
|
46
|
+
* 进入编辑模式
|
|
47
|
+
*/
|
|
48
|
+
enter(): void;
|
|
49
|
+
/**
|
|
50
|
+
* 退出编辑模式,将编辑结果永久写入渲染数据
|
|
51
|
+
*/
|
|
52
|
+
exit(): void;
|
|
53
|
+
/**
|
|
54
|
+
* 将编辑结果写回渲染器:从 CompactSplatData 中剔除被标记为 deleted 的 splat,
|
|
55
|
+
* 用精简数据重建 GPU 缓冲区。
|
|
56
|
+
*/
|
|
57
|
+
private applyEditsToRenderer;
|
|
58
|
+
selectAll(): void;
|
|
59
|
+
selectNone(): void;
|
|
60
|
+
selectInvert(): void;
|
|
61
|
+
deleteSelection(): void;
|
|
62
|
+
hideSelection(): void;
|
|
63
|
+
unhideAll(): void;
|
|
64
|
+
undo(): void;
|
|
65
|
+
redo(): void;
|
|
66
|
+
exportPLY(): ArrayBuffer | null;
|
|
67
|
+
downloadPLY(filename?: string): void;
|
|
68
|
+
private selectByRect;
|
|
69
|
+
private selectByMask;
|
|
70
|
+
private selectByColor;
|
|
71
|
+
/**
|
|
72
|
+
* 每帧调用,标记投影需要更新
|
|
73
|
+
*/
|
|
74
|
+
markProjectionDirty(): void;
|
|
75
|
+
private ensureProjection;
|
|
76
|
+
private onStateChanged;
|
|
77
|
+
private setupOverlayEventForwarding;
|
|
78
|
+
private _keyHandler;
|
|
79
|
+
private _onKeyDown;
|
|
80
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { SplatState } from './SplatState';
|
|
2
|
+
/**
|
|
3
|
+
* 将编辑后的 splat 数据导出为 PLY 文件
|
|
4
|
+
* 仅包含未删除的 splats
|
|
5
|
+
*/
|
|
6
|
+
export declare function exportEditedPLY(positions: Float32Array, scales: Float32Array, rotations: Float32Array, colors: Float32Array, opacities: Float32Array, shCoeffs: Float32Array | null, state: SplatState): ArrayBuffer;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare enum State {
|
|
2
|
+
selected = 1,
|
|
3
|
+
hidden = 2,
|
|
4
|
+
deleted = 4
|
|
5
|
+
}
|
|
6
|
+
export declare class SplatState {
|
|
7
|
+
readonly count: number;
|
|
8
|
+
readonly data: Uint8Array;
|
|
9
|
+
private _numSelected;
|
|
10
|
+
private _numHidden;
|
|
11
|
+
private _numDeleted;
|
|
12
|
+
constructor(count: number);
|
|
13
|
+
get numSelected(): number;
|
|
14
|
+
get numHidden(): number;
|
|
15
|
+
get numDeleted(): number;
|
|
16
|
+
recalcCounts(): void;
|
|
17
|
+
clear(): void;
|
|
18
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { SplatEditor } from './SplatEditor';
|
|
2
|
+
export type { SplatEditorCallbacks } from './SplatEditor';
|
|
3
|
+
export { SplatState, State } from './SplatState';
|
|
4
|
+
export { EditHistory } from './EditHistory';
|
|
5
|
+
export { ToolManager } from './tools/ToolManager';
|
|
6
|
+
export type { Tool } from './tools/ToolManager';
|
|
7
|
+
export { exportEditedPLY } from './SplatExporter';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Tool } from './ToolManager';
|
|
2
|
+
export declare class BrushSelection implements Tool {
|
|
3
|
+
private parent;
|
|
4
|
+
private svg;
|
|
5
|
+
private circle;
|
|
6
|
+
private maskCanvas;
|
|
7
|
+
private maskCtx;
|
|
8
|
+
private onMaskSelect;
|
|
9
|
+
private radius;
|
|
10
|
+
private prev;
|
|
11
|
+
private dragId;
|
|
12
|
+
constructor(parent: HTMLElement, maskCanvas: HTMLCanvasElement, maskCtx: CanvasRenderingContext2D, onMaskSelect: (op: 'add' | 'remove' | 'set', canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D) => void);
|
|
13
|
+
activate(): void;
|
|
14
|
+
deactivate(): void;
|
|
15
|
+
private update;
|
|
16
|
+
private pointerdown;
|
|
17
|
+
private pointermove;
|
|
18
|
+
private dragEnd;
|
|
19
|
+
private pointerup;
|
|
20
|
+
private wheel;
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Tool } from './ToolManager';
|
|
2
|
+
/**
|
|
3
|
+
* EyedropperSelection - 吸管/颜色匹配选择工具
|
|
4
|
+
* 点击拾取一个 splat 的颜色,然后选择所有颜色相似的 splats
|
|
5
|
+
*/
|
|
6
|
+
export declare class EyedropperSelection implements Tool {
|
|
7
|
+
private parent;
|
|
8
|
+
private onColorMatch;
|
|
9
|
+
private thresholdEl;
|
|
10
|
+
private threshold;
|
|
11
|
+
private pointerId;
|
|
12
|
+
constructor(parent: HTMLElement, onColorMatch: (op: 'add' | 'remove' | 'set', normalizedPoint: {
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
}, threshold: number) => void);
|
|
16
|
+
activate(): void;
|
|
17
|
+
deactivate(): void;
|
|
18
|
+
private pointerdown;
|
|
19
|
+
private pointermove;
|
|
20
|
+
private pointerup;
|
|
21
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Tool } from './ToolManager';
|
|
2
|
+
/**
|
|
3
|
+
* FloodSelection - 基于不透明度的洪水填充选择工具
|
|
4
|
+
* 从点击位置开始,向相邻像素扩展,选择不透明度相近的区域
|
|
5
|
+
*/
|
|
6
|
+
export declare class FloodSelection implements Tool {
|
|
7
|
+
private parent;
|
|
8
|
+
private maskCanvas;
|
|
9
|
+
private maskCtx;
|
|
10
|
+
private onMaskSelect;
|
|
11
|
+
private getOffscreenImage;
|
|
12
|
+
private thresholdEl;
|
|
13
|
+
private threshold;
|
|
14
|
+
private clicked;
|
|
15
|
+
private imageData;
|
|
16
|
+
constructor(parent: HTMLElement, maskCanvas: HTMLCanvasElement, maskCtx: CanvasRenderingContext2D, onMaskSelect: (op: 'add' | 'remove' | 'set', canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D) => void, getOffscreenImage: (width: number, height: number) => Uint8Array | null);
|
|
17
|
+
activate(): void;
|
|
18
|
+
deactivate(): void;
|
|
19
|
+
private pointerdown;
|
|
20
|
+
private pointermove;
|
|
21
|
+
private pointerup;
|
|
22
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Tool } from './ToolManager';
|
|
2
|
+
export declare class LassoSelection implements Tool {
|
|
3
|
+
private parent;
|
|
4
|
+
private svg;
|
|
5
|
+
private polygon;
|
|
6
|
+
private maskCanvas;
|
|
7
|
+
private maskCtx;
|
|
8
|
+
private onMaskSelect;
|
|
9
|
+
private points;
|
|
10
|
+
private currentPoint;
|
|
11
|
+
private lastPointTime;
|
|
12
|
+
private dragId;
|
|
13
|
+
constructor(parent: HTMLElement, maskCanvas: HTMLCanvasElement, maskCtx: CanvasRenderingContext2D, onMaskSelect: (op: 'add' | 'remove' | 'set', canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D) => void);
|
|
14
|
+
activate(): void;
|
|
15
|
+
deactivate(): void;
|
|
16
|
+
private dist;
|
|
17
|
+
private paint;
|
|
18
|
+
private update;
|
|
19
|
+
private commitSelection;
|
|
20
|
+
private pointerdown;
|
|
21
|
+
private pointermove;
|
|
22
|
+
private dragEnd;
|
|
23
|
+
private pointerup;
|
|
24
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Tool } from './ToolManager';
|
|
2
|
+
export declare class PolygonSelection implements Tool {
|
|
3
|
+
private parent;
|
|
4
|
+
private svg;
|
|
5
|
+
private polyline;
|
|
6
|
+
private maskCanvas;
|
|
7
|
+
private maskCtx;
|
|
8
|
+
private onMaskSelect;
|
|
9
|
+
private points;
|
|
10
|
+
private currentPoint;
|
|
11
|
+
constructor(parent: HTMLElement, maskCanvas: HTMLCanvasElement, maskCtx: CanvasRenderingContext2D, onMaskSelect: (op: 'add' | 'remove' | 'set', canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D) => void);
|
|
12
|
+
activate(): void;
|
|
13
|
+
deactivate(): void;
|
|
14
|
+
private dist;
|
|
15
|
+
private isClosed;
|
|
16
|
+
private paint;
|
|
17
|
+
private commitSelection;
|
|
18
|
+
private pointerdown;
|
|
19
|
+
private pointermove;
|
|
20
|
+
private pointerup;
|
|
21
|
+
private dblclick;
|
|
22
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Tool } from './ToolManager';
|
|
2
|
+
export declare class RectSelection implements Tool {
|
|
3
|
+
private parent;
|
|
4
|
+
private svg;
|
|
5
|
+
private rect;
|
|
6
|
+
private onSelect;
|
|
7
|
+
private start;
|
|
8
|
+
private end;
|
|
9
|
+
private dragId;
|
|
10
|
+
private dragMoved;
|
|
11
|
+
constructor(parent: HTMLElement, onSelect: (op: 'add' | 'remove' | 'set', rect: {
|
|
12
|
+
startX: number;
|
|
13
|
+
startY: number;
|
|
14
|
+
endX: number;
|
|
15
|
+
endY: number;
|
|
16
|
+
}) => void);
|
|
17
|
+
activate(): void;
|
|
18
|
+
deactivate(): void;
|
|
19
|
+
private updateRect;
|
|
20
|
+
private pointerdown;
|
|
21
|
+
private pointermove;
|
|
22
|
+
private dragEnd;
|
|
23
|
+
private pointerup;
|
|
24
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface Tool {
|
|
2
|
+
activate(): void;
|
|
3
|
+
deactivate(): void;
|
|
4
|
+
}
|
|
5
|
+
export declare class ToolManager {
|
|
6
|
+
private tools;
|
|
7
|
+
private _active;
|
|
8
|
+
private onToolChanged?;
|
|
9
|
+
constructor(onToolChanged?: (name: string | null) => void);
|
|
10
|
+
get active(): string | null;
|
|
11
|
+
register(name: string, tool: Tool): void;
|
|
12
|
+
activate(name: string | null): void;
|
|
13
|
+
deactivateAll(): void;
|
|
14
|
+
}
|
|
@@ -48,6 +48,11 @@ export declare class GSSplatRenderer implements IGSSplatRendererWithCapabilities
|
|
|
48
48
|
private sortStateInitialized;
|
|
49
49
|
private sortFrequency;
|
|
50
50
|
private frameCounter;
|
|
51
|
+
private editorStateBuffer;
|
|
52
|
+
private editorPipeline;
|
|
53
|
+
private editorBindGroupLayout;
|
|
54
|
+
private editorBindGroup;
|
|
55
|
+
private editorEnabled;
|
|
51
56
|
private depthNormalPipeline;
|
|
52
57
|
private depthRT;
|
|
53
58
|
private depthRTView;
|
|
@@ -109,5 +114,21 @@ export declare class GSSplatRenderer implements IGSSplatRendererWithCapabilities
|
|
|
109
114
|
} | null;
|
|
110
115
|
supportsSHMode(mode: SHMode): boolean;
|
|
111
116
|
getCapabilities(): RendererCapabilities;
|
|
117
|
+
/**
|
|
118
|
+
* 启用编辑器模式,传入每个 splat 的状态数据
|
|
119
|
+
*/
|
|
120
|
+
setEditorState(stateData: Uint8Array): void;
|
|
121
|
+
/**
|
|
122
|
+
* 更新编辑器状态数据
|
|
123
|
+
*/
|
|
124
|
+
updateEditorState(stateData: Uint8Array): void;
|
|
125
|
+
private alignStateData;
|
|
126
|
+
/**
|
|
127
|
+
* 禁用编辑器模式
|
|
128
|
+
*/
|
|
129
|
+
clearEditorState(): void;
|
|
130
|
+
private createEditorPipeline;
|
|
131
|
+
private rebuildEditorBindGroup;
|
|
132
|
+
private buildEditorShader;
|
|
112
133
|
destroy(): void;
|
|
113
134
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -41,9 +41,16 @@ export type { SceneObjectType, SceneObjectInfo } from './scene/SceneManager';
|
|
|
41
41
|
export { SplatTransformProxy, MeshGroupProxy, SplatBoundingBoxProvider, } from './scene/proxies';
|
|
42
42
|
export { GizmoManager } from './interaction/GizmoManager';
|
|
43
43
|
export { HotspotManager } from './interaction/HotspotManager';
|
|
44
|
-
export type { HotspotInfo } from './interaction/HotspotManager';
|
|
44
|
+
export type { HotspotInfo, HotspotLabelConfig, HotspotLabelPosition } from './interaction/HotspotManager';
|
|
45
45
|
export type { TransformableObject } from './core/gizmo/TransformGizmo';
|
|
46
46
|
export { TransformGizmo, GizmoMode } from './core/gizmo/TransformGizmo';
|
|
47
47
|
export type { GizmoTheme, TransformGizmoConfig, GizmoSpace } from './core/gizmo/TransformGizmo';
|
|
48
|
+
export { SplatEditor } from './editor/SplatEditor';
|
|
49
|
+
export type { SplatEditorCallbacks } from './editor/SplatEditor';
|
|
50
|
+
export { SplatState, State } from './editor/SplatState';
|
|
51
|
+
export { EditHistory } from './editor/EditHistory';
|
|
52
|
+
export { ToolManager } from './editor/tools/ToolManager';
|
|
53
|
+
export type { Tool } from './editor/tools/ToolManager';
|
|
54
|
+
export { exportEditedPLY } from './editor/SplatExporter';
|
|
48
55
|
export { App } from './App';
|
|
49
56
|
export type { ProgressCallback } from './App';
|
|
@@ -10,6 +10,15 @@ import { OrbitControls } from "../core/OrbitControls";
|
|
|
10
10
|
import { MeshRenderer } from "../mesh/MeshRenderer";
|
|
11
11
|
import type { IGSSplatRenderer } from "../gs/IGSSplatRenderer";
|
|
12
12
|
import type { Vec3Tuple } from "../types";
|
|
13
|
+
/** 热点标签位置 */
|
|
14
|
+
export type HotspotLabelPosition = 'top' | 'left' | 'right';
|
|
15
|
+
/** 热点标签配置 */
|
|
16
|
+
export interface HotspotLabelConfig {
|
|
17
|
+
text: string;
|
|
18
|
+
position: HotspotLabelPosition;
|
|
19
|
+
fontSize: number;
|
|
20
|
+
visible: boolean;
|
|
21
|
+
}
|
|
13
22
|
/** 热点信息 */
|
|
14
23
|
export interface HotspotInfo {
|
|
15
24
|
position: Vec3Tuple;
|
|
@@ -24,6 +33,10 @@ export interface HotspotInfo {
|
|
|
24
33
|
placedNormalOffset: number;
|
|
25
34
|
/** 放置时的本地中心偏移 (本地空间) */
|
|
26
35
|
placedLocalCenter: Vec3Tuple;
|
|
36
|
+
/** 文字标签配置 */
|
|
37
|
+
label?: HotspotLabelConfig;
|
|
38
|
+
/** 标签 DOM 元素(内部使用) */
|
|
39
|
+
_labelElement?: HTMLDivElement;
|
|
27
40
|
}
|
|
28
41
|
/**
|
|
29
42
|
* HotspotManager
|
|
@@ -58,6 +71,9 @@ export declare class HotspotManager {
|
|
|
58
71
|
private lastNormal;
|
|
59
72
|
private indicatorBaseRadius;
|
|
60
73
|
private pickRadiusPx;
|
|
74
|
+
private labelContainer;
|
|
75
|
+
private onHotspotClicked;
|
|
76
|
+
private hotspotHitRadius;
|
|
61
77
|
private onHotspotPlaced;
|
|
62
78
|
private onModeChanged;
|
|
63
79
|
constructor(renderer: Renderer, camera: Camera, canvas: HTMLCanvasElement, controls: OrbitControls, meshRenderer: MeshRenderer);
|
|
@@ -69,6 +85,41 @@ export declare class HotspotManager {
|
|
|
69
85
|
getHotspots(): HotspotInfo[];
|
|
70
86
|
setOnHotspotPlaced(cb: ((info: HotspotInfo) => void) | null): void;
|
|
71
87
|
setOnModeChanged(cb: ((active: boolean) => void) | null): void;
|
|
88
|
+
private initLabelContainer;
|
|
89
|
+
/**
|
|
90
|
+
* 设置热点标签
|
|
91
|
+
*/
|
|
92
|
+
setHotspotLabel(hotspotIndex: number, text: string, position?: HotspotLabelPosition, fontSize?: number, visible?: boolean): boolean;
|
|
93
|
+
/**
|
|
94
|
+
* 设置热点标签可见性
|
|
95
|
+
*/
|
|
96
|
+
setHotspotLabelVisible(hotspotIndex: number, visible: boolean): boolean;
|
|
97
|
+
/**
|
|
98
|
+
* 获取热点标签配置
|
|
99
|
+
*/
|
|
100
|
+
getHotspotLabel(hotspotIndex: number): HotspotLabelConfig | null;
|
|
101
|
+
private ensureLabelElement;
|
|
102
|
+
private applyLabelStyle;
|
|
103
|
+
/**
|
|
104
|
+
* 每帧更新所有标签的屏幕位置
|
|
105
|
+
*/
|
|
106
|
+
updateLabels(): void;
|
|
107
|
+
/**
|
|
108
|
+
* 设置热点点击回调
|
|
109
|
+
*/
|
|
110
|
+
setOnHotspotClicked(cb: ((hotspotIndex: number, info: HotspotInfo) => void) | null): void;
|
|
111
|
+
private _clickListenerBound;
|
|
112
|
+
private _boundOnCanvasClick;
|
|
113
|
+
private _onCanvasClick;
|
|
114
|
+
/**
|
|
115
|
+
* 检测给定屏幕坐标命中了哪个热点
|
|
116
|
+
* @returns 热点索引,-1 表示未命中
|
|
117
|
+
*/
|
|
118
|
+
hitTestHotspot(clientX: number, clientY: number): number;
|
|
119
|
+
/**
|
|
120
|
+
* 设置热点点击命中半径(NDC 空间,默认 0.05)
|
|
121
|
+
*/
|
|
122
|
+
setHotspotHitRadius(radius: number): void;
|
|
72
123
|
private pickPixelX;
|
|
73
124
|
private pickPixelY;
|
|
74
125
|
private lastClientX;
|
|
@@ -130,6 +181,12 @@ export declare class HotspotManager {
|
|
|
130
181
|
* 通过 overlay mesh 起始索引找到对应的热点索引
|
|
131
182
|
*/
|
|
132
183
|
findHotspotIndexByMeshStart(overlayMeshStartIndex: number): number;
|
|
184
|
+
/**
|
|
185
|
+
* 在指定位置和法线方向程序化放置一个热点(用于从保存数据恢复)。
|
|
186
|
+
* 逻辑与交互放置一致:加载 OBJ → 计算朝向矩阵 → addOverlayMesh → 注册到内部列表。
|
|
187
|
+
* @returns 放置后的 HotspotInfo,失败返回 null
|
|
188
|
+
*/
|
|
189
|
+
placeHotspotAt(objUrl: string, position: Vec3Tuple, normal: Vec3Tuple, visualDiameter?: number, normalOffset?: number, overrideScale?: number): Promise<HotspotInfo | null>;
|
|
133
190
|
/**
|
|
134
191
|
* 每帧调用:更新所有 billboard 热点朝向相机
|
|
135
192
|
*/
|