@d5techs/3dgs-lib 1.1.0 → 1.1.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 +2948 -349
- package/dist/3dgs-lib.cjs.map +1 -1
- package/dist/3dgs-lib.js +2948 -349
- package/dist/3dgs-lib.js.map +1 -1
- package/dist/App.d.ts +28 -7
- package/dist/core/BoundingBoxRenderer.d.ts +1 -3
- package/dist/core/OrbitControls.d.ts +21 -41
- package/dist/core/gizmo/{TransformGizmoV2.d.ts → TransformGizmo.d.ts} +2 -2
- package/dist/core/{ViewportGizmo.d.ts → gizmo/ViewportGizmo.d.ts} +2 -2
- package/dist/core/gizmo/index.d.ts +3 -2
- package/dist/core/index.d.ts +7 -0
- package/dist/gs/GSSplatRenderer.d.ts +48 -2
- package/dist/gs/GSSplatRendererMobile.d.ts +2 -1
- package/dist/gs/GSSplatSorter.d.ts +3 -0
- package/dist/gs/IGSSplatRenderer.d.ts +31 -2
- package/dist/gs/SOGLoader.d.ts +25 -0
- package/dist/index.d.ts +10 -9
- package/dist/interaction/GizmoManager.d.ts +6 -6
- package/dist/interaction/HotspotManager.d.ts +142 -0
- package/dist/mesh/Mesh.d.ts +4 -8
- package/dist/mesh/MeshRenderer.d.ts +30 -14
- package/dist/scene/SceneManager.d.ts +8 -2
- package/package.json +4 -1
package/dist/3dgs-lib.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"3dgs-lib.js","sources":["../src/types/material.ts","../src/types/splat.ts","../src/utils/device.ts","../src/utils/geometry.ts","../src/utils/texture.ts","../src/core/Renderer.ts","../src/core/Camera.ts","../src/core/OrbitControls.ts","../src/core/ViewportGizmo.ts","../src/core/BoundingBoxRenderer.ts","../src/mesh/Mesh.ts","../src/mesh/MeshRenderer.ts","../src/loaders/GLBLoader.ts","../src/loaders/OBJParser.ts","../src/loaders/MTLParser.ts","../src/loaders/OBJLoader.ts","../src/gs/PLYLoader.ts","../src/gs/PLYLoaderMobile.ts","../src/gs/SplatLoader.ts","../src/gs/GSSplatSorter.ts","../src/gs/GSSplatRenderer.ts","../src/gs/TextureCompressor.ts","../src/gs/GSSplatSorterMobile.ts","../src/gs/GSSplatRendererMobile.ts","../src/scene/SceneManager.ts","../src/scene/proxies/SplatTransformProxy.ts","../src/scene/proxies/MeshGroupProxy.ts","../src/scene/proxies/SplatBoundingBoxProvider.ts","../src/core/math/Vec3.ts","../src/core/math/Ray.ts","../src/core/math/Quat.ts","../src/core/math/Mat4.ts","../src/core/gizmo/Shape.ts","../src/core/gizmo/ArrowShape.ts","../src/core/gizmo/PlaneShape.ts","../src/core/gizmo/SphereShape.ts","../src/core/gizmo/ArcShape.ts","../src/core/gizmo/BoxLineShape.ts","../src/core/gizmo/TransformGizmoV2.ts","../src/interaction/GizmoManager.ts","../src/App.ts"],"sourcesContent":["/**\r\n * 统一的材质类型定义\r\n */\r\n\r\n/**\r\n * 材质数据接口\r\n * 用于 GLB/OBJ 等模型的材质\r\n */\r\nexport interface MaterialData {\r\n /** 基础颜色因子 [r, g, b, a] */\r\n baseColorFactor: [number, number, number, number];\r\n /** 基础颜色纹理 */\r\n baseColorTexture: GPUTexture | null;\r\n /** 金属度因子 */\r\n metallicFactor: number;\r\n /** 粗糙度因子 */\r\n roughnessFactor: number;\r\n /** 是否双面渲染 */\r\n doubleSided: boolean;\r\n}\r\n\r\n/**\r\n * 默认材质\r\n */\r\nexport const DEFAULT_MATERIAL: Readonly<MaterialData> = {\r\n baseColorFactor: [1, 1, 1, 1],\r\n baseColorTexture: null,\r\n metallicFactor: 0,\r\n roughnessFactor: 0.5,\r\n doubleSided: false,\r\n};\r\n\r\n/**\r\n * OBJ 默认材质(双面渲染)\r\n */\r\nexport const DEFAULT_OBJ_MATERIAL: Readonly<MaterialData> = {\r\n baseColorFactor: [1, 1, 1, 1],\r\n baseColorTexture: null,\r\n metallicFactor: 0,\r\n roughnessFactor: 0.5,\r\n doubleSided: true,\r\n};\r\n","/**\r\n * 3D Gaussian Splatting 相关类型定义\r\n */\r\n\r\n/**\r\n * SH 模式枚举 - 球谐函数级别\r\n */\r\nexport enum SHMode {\r\n L0 = 0, // 仅 DC 颜色(最快)\r\n L1 = 1, // DC + L1 SH\r\n L2 = 2, // DC + L1 + L2 SH\r\n L3 = 3, // 完整 SH(最高质量)\r\n}\r\n\r\n/**\r\n * 渲染器能力描述\r\n */\r\nexport interface RendererCapabilities {\r\n /** 支持的最高 SH 模式 */\r\n maxSHMode: SHMode;\r\n /** 是否支持原始 SplatCPU 数据 */\r\n supportsRawData: boolean;\r\n /** 是否为移动端优化版本 */\r\n isMobileOptimized: boolean;\r\n /** 最大支持的 splat 数量(0 表示无限制) */\r\n maxSplatCount: number;\r\n}\r\n","/**\r\n * 设备检测工具函数\r\n */\r\n\r\n/**\r\n * 检测是否为移动设备\r\n * 综合考虑 UA、触摸支持、屏幕尺寸\r\n */\r\nexport function isMobileDevice(): boolean {\r\n if (typeof navigator === \"undefined\" || typeof window === \"undefined\") {\r\n return false;\r\n }\r\n\r\n const ua = navigator.userAgent || navigator.vendor || (window as any).opera || \"\";\r\n \r\n // UA 检测\r\n const isMobileUA = /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(\r\n ua.toLowerCase()\r\n );\r\n \r\n // 触摸支持检测\r\n const hasTouch = \"ontouchstart\" in window || navigator.maxTouchPoints > 0;\r\n \r\n // 屏幕尺寸检测\r\n const isSmallScreen = window.innerWidth <= 768;\r\n \r\n // iPad as Mac 检测(Safari on iPad)\r\n const isIPadAsMac = navigator.platform === \"MacIntel\" && navigator.maxTouchPoints > 1;\r\n \r\n return isMobileUA || isIPadAsMac || (hasTouch && isSmallScreen);\r\n}\r\n\r\n/**\r\n * 获取推荐的设备像素比\r\n * 移动端限制 DPI 以避免性能问题\r\n */\r\nexport function getRecommendedDPR(): number {\r\n const isMobile = isMobileDevice();\r\n const maxDpr = isMobile ? 1.5 : 3;\r\n return Math.min(window.devicePixelRatio || 1, maxDpr);\r\n}\r\n\r\n/**\r\n * 检测 WebGPU 支持\r\n */\r\nexport function isWebGPUSupported(): boolean {\r\n return typeof navigator !== \"undefined\" && \"gpu\" in navigator;\r\n}\r\n","/**\r\n * 几何计算工具函数\r\n */\r\n\r\nimport type { BoundingBox, Vec3Tuple } from '../types';\r\n\r\n/**\r\n * 从顶点位置数组计算包围盒\r\n * @param positions 顶点位置数组 [x0, y0, z0, x1, y1, z1, ...]\r\n * @returns 包围盒信息\r\n */\r\nexport function computeBoundingBox(\r\n positions: ArrayLike<number>\r\n): BoundingBox {\r\n if (positions.length < 3) {\r\n return {\r\n min: [0, 0, 0],\r\n max: [0, 0, 0],\r\n center: [0, 0, 0],\r\n radius: 0,\r\n };\r\n }\r\n\r\n // 初始化为第一个点\r\n const min: Vec3Tuple = [positions[0], positions[1], positions[2]];\r\n const max: Vec3Tuple = [positions[0], positions[1], positions[2]];\r\n\r\n // 遍历所有顶点\r\n for (let i = 3; i < positions.length; i += 3) {\r\n const x = positions[i];\r\n const y = positions[i + 1];\r\n const z = positions[i + 2];\r\n\r\n min[0] = Math.min(min[0], x);\r\n min[1] = Math.min(min[1], y);\r\n min[2] = Math.min(min[2], z);\r\n max[0] = Math.max(max[0], x);\r\n max[1] = Math.max(max[1], y);\r\n max[2] = Math.max(max[2], z);\r\n }\r\n\r\n // 计算中心点\r\n const center: Vec3Tuple = [\r\n (min[0] + max[0]) / 2,\r\n (min[1] + max[1]) / 2,\r\n (min[2] + max[2]) / 2,\r\n ];\r\n\r\n // 计算 bounding sphere 半径\r\n const dx = max[0] - min[0];\r\n const dy = max[1] - min[1];\r\n const dz = max[2] - min[2];\r\n const radius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min, max, center, radius };\r\n}\r\n\r\n/**\r\n * 合并多个包围盒\r\n * @param boxes 包围盒数组\r\n * @returns 合并后的包围盒,如果输入为空则返回 null\r\n */\r\nexport function mergeBoundingBoxes(boxes: BoundingBox[]): BoundingBox | null {\r\n if (boxes.length === 0) return null;\r\n\r\n let combinedMin: Vec3Tuple = [...boxes[0].min];\r\n let combinedMax: Vec3Tuple = [...boxes[0].max];\r\n\r\n for (let i = 1; i < boxes.length; i++) {\r\n const box = boxes[i];\r\n combinedMin[0] = Math.min(combinedMin[0], box.min[0]);\r\n combinedMin[1] = Math.min(combinedMin[1], box.min[1]);\r\n combinedMin[2] = Math.min(combinedMin[2], box.min[2]);\r\n combinedMax[0] = Math.max(combinedMax[0], box.max[0]);\r\n combinedMax[1] = Math.max(combinedMax[1], box.max[1]);\r\n combinedMax[2] = Math.max(combinedMax[2], box.max[2]);\r\n }\r\n\r\n const center: Vec3Tuple = [\r\n (combinedMin[0] + combinedMax[0]) / 2,\r\n (combinedMin[1] + combinedMax[1]) / 2,\r\n (combinedMin[2] + combinedMax[2]) / 2,\r\n ];\r\n\r\n const dx = combinedMax[0] - combinedMin[0];\r\n const dy = combinedMax[1] - combinedMin[1];\r\n const dz = combinedMax[2] - combinedMin[2];\r\n const radius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min: combinedMin, max: combinedMax, center, radius };\r\n}\r\n\r\n/**\r\n * 从 min/max 计算完整的包围盒信息\r\n */\r\nexport function createBoundingBoxFromMinMax(\r\n min: Vec3Tuple,\r\n max: Vec3Tuple\r\n): BoundingBox {\r\n const center: Vec3Tuple = [\r\n (min[0] + max[0]) / 2,\r\n (min[1] + max[1]) / 2,\r\n (min[2] + max[2]) / 2,\r\n ];\r\n\r\n const dx = max[0] - min[0];\r\n const dy = max[1] - min[1];\r\n const dz = max[2] - min[2];\r\n const radius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min, max, center, radius };\r\n}\r\n\r\n/**\r\n * 变换包围盒的 8 个角点并计算新的 AABB\r\n * @param bbox 原始包围盒\r\n * @param modelMatrix 4x4 变换矩阵(列主序)\r\n */\r\nexport function transformBoundingBox(\r\n bbox: BoundingBox,\r\n modelMatrix: Float32Array\r\n): BoundingBox {\r\n // 获取 8 个角点\r\n const corners: Vec3Tuple[] = [\r\n [bbox.min[0], bbox.min[1], bbox.min[2]],\r\n [bbox.max[0], bbox.min[1], bbox.min[2]],\r\n [bbox.min[0], bbox.max[1], bbox.min[2]],\r\n [bbox.max[0], bbox.max[1], bbox.min[2]],\r\n [bbox.min[0], bbox.min[1], bbox.max[2]],\r\n [bbox.max[0], bbox.min[1], bbox.max[2]],\r\n [bbox.min[0], bbox.max[1], bbox.max[2]],\r\n [bbox.max[0], bbox.max[1], bbox.max[2]],\r\n ];\r\n\r\n const m = modelMatrix;\r\n let minX = Infinity, minY = Infinity, minZ = Infinity;\r\n let maxX = -Infinity, maxY = -Infinity, maxZ = -Infinity;\r\n\r\n for (const [x, y, z] of corners) {\r\n // 应用变换(列主序矩阵)\r\n const tx = m[0] * x + m[4] * y + m[8] * z + m[12];\r\n const ty = m[1] * x + m[5] * y + m[9] * z + m[13];\r\n const tz = m[2] * x + m[6] * y + m[10] * z + m[14];\r\n\r\n minX = Math.min(minX, tx);\r\n minY = Math.min(minY, ty);\r\n minZ = Math.min(minZ, tz);\r\n maxX = Math.max(maxX, tx);\r\n maxY = Math.max(maxY, ty);\r\n maxZ = Math.max(maxZ, tz);\r\n }\r\n\r\n return createBoundingBoxFromMinMax(\r\n [minX, minY, minZ],\r\n [maxX, maxY, maxZ]\r\n );\r\n}\r\n","/**\r\n * 纹理加载工具函数\r\n */\r\n\r\n/**\r\n * 从 URL 加载纹理\r\n * @param device GPU 设备\r\n * @param url 纹理 URL\r\n * @returns GPU 纹理或 null(加载失败时)\r\n */\r\nexport async function loadTextureFromURL(\r\n device: GPUDevice,\r\n url: string\r\n): Promise<GPUTexture | null> {\r\n try {\r\n const response = await fetch(url);\r\n if (!response.ok) {\r\n return null;\r\n }\r\n\r\n const blob = await response.blob();\r\n return loadTextureFromBlob(device, blob);\r\n } catch (error) {\r\n console.warn(`Failed to load texture from URL: ${url}`, error);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * 从 Blob 加载纹理\r\n * @param device GPU 设备\r\n * @param blob 图片 Blob\r\n * @returns GPU 纹理或 null(加载失败时)\r\n */\r\nexport async function loadTextureFromBlob(\r\n device: GPUDevice,\r\n blob: Blob\r\n): Promise<GPUTexture | null> {\r\n try {\r\n const imageBitmap = await createImageBitmap(blob);\r\n return createTextureFromImageBitmap(device, imageBitmap);\r\n } catch (error) {\r\n console.warn(`Failed to create texture from blob`, error);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * 从 ArrayBuffer 加载纹理\r\n * @param device GPU 设备\r\n * @param buffer 图片数据\r\n * @param mimeType MIME 类型\r\n * @returns GPU 纹理或 null(加载失败时)\r\n */\r\nexport async function loadTextureFromBuffer(\r\n device: GPUDevice,\r\n buffer: ArrayBuffer | Uint8Array,\r\n mimeType: string = 'image/png'\r\n): Promise<GPUTexture | null> {\r\n try {\r\n // 确保是 Uint8Array 类型用于 Blob 构造\r\n const uint8Array = buffer instanceof Uint8Array \r\n ? buffer \r\n : new Uint8Array(buffer);\r\n // 使用类型断言解决 SharedArrayBuffer 兼容性问题\r\n const blob = new Blob([uint8Array as BlobPart], { type: mimeType });\r\n return loadTextureFromBlob(device, blob);\r\n } catch (error) {\r\n console.warn(`Failed to create texture from buffer`, error);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * 从 ImageBitmap 创建 GPU 纹理\r\n * @param device GPU 设备\r\n * @param imageBitmap ImageBitmap 对象\r\n * @returns GPU 纹理\r\n */\r\nexport function createTextureFromImageBitmap(\r\n device: GPUDevice,\r\n imageBitmap: ImageBitmap\r\n): GPUTexture {\r\n const texture = device.createTexture({\r\n size: [imageBitmap.width, imageBitmap.height, 1],\r\n format: 'rgba8unorm',\r\n usage:\r\n GPUTextureUsage.TEXTURE_BINDING |\r\n GPUTextureUsage.COPY_DST |\r\n GPUTextureUsage.RENDER_ATTACHMENT,\r\n });\r\n\r\n device.queue.copyExternalImageToTexture(\r\n { source: imageBitmap },\r\n { texture },\r\n [imageBitmap.width, imageBitmap.height]\r\n );\r\n\r\n return texture;\r\n}\r\n\r\n/**\r\n * 纹理缓存管理器\r\n */\r\nexport class TextureCache {\r\n private cache: Map<string, GPUTexture> = new Map();\r\n private device: GPUDevice;\r\n\r\n constructor(device: GPUDevice) {\r\n this.device = device;\r\n }\r\n\r\n /**\r\n * 获取或加载纹理\r\n */\r\n async getOrLoad(url: string): Promise<GPUTexture | null> {\r\n if (this.cache.has(url)) {\r\n return this.cache.get(url)!;\r\n }\r\n\r\n const texture = await loadTextureFromURL(this.device, url);\r\n if (texture) {\r\n this.cache.set(url, texture);\r\n }\r\n return texture;\r\n }\r\n\r\n /**\r\n * 检查缓存中是否存在\r\n */\r\n has(url: string): boolean {\r\n return this.cache.has(url);\r\n }\r\n\r\n /**\r\n * 从缓存获取\r\n */\r\n get(url: string): GPUTexture | undefined {\r\n return this.cache.get(url);\r\n }\r\n\r\n /**\r\n * 添加到缓存\r\n */\r\n set(url: string, texture: GPUTexture): void {\r\n this.cache.set(url, texture);\r\n }\r\n\r\n /**\r\n * 清空缓存\r\n */\r\n clear(): void {\r\n this.cache.clear();\r\n }\r\n\r\n /**\r\n * 销毁所有纹理并清空缓存\r\n */\r\n destroy(): void {\r\n for (const texture of this.cache.values()) {\r\n texture.destroy();\r\n }\r\n this.cache.clear();\r\n }\r\n}\r\n","import { isMobileDevice, getRecommendedDPR } from \"../utils\";\r\n\r\n/**\r\n * Renderer - WebGPU 初始化 + 帧提交\r\n * 只负责 WebGPU 设备管理和渲染通道\r\n */\r\nexport class Renderer {\r\n private canvas: HTMLCanvasElement;\r\n private _device!: GPUDevice;\r\n private _context!: GPUCanvasContext;\r\n private _format!: GPUTextureFormat;\r\n private _depthTexture!: GPUTexture;\r\n private _depthTextureView!: GPUTextureView;\r\n \r\n private commandEncoder!: GPUCommandEncoder;\r\n private renderPassEncoder!: GPURenderPassEncoder;\r\n\r\n // ResizeObserver 引用(用于清理)\r\n private resizeObserver: ResizeObserver | null = null;\r\n\r\n // 背景颜色\r\n private _clearColor: GPUColorDict = { r: 0.15, g: 0.15, b: 0.15, a: 1.0 };\r\n\r\n constructor(canvas: HTMLCanvasElement) {\r\n this.canvas = canvas;\r\n }\r\n\r\n /**\r\n * 设置背景颜色\r\n */\r\n setClearColor(r: number, g: number, b: number, a: number = 1.0): void {\r\n this._clearColor = { r, g, b, a };\r\n }\r\n\r\n /**\r\n * 通过十六进制设置背景颜色\r\n */\r\n setClearColorHex(hex: string): void {\r\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\r\n if (result) {\r\n this._clearColor = {\r\n r: parseInt(result[1], 16) / 255,\r\n g: parseInt(result[2], 16) / 255,\r\n b: parseInt(result[3], 16) / 255,\r\n a: 1.0,\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * 获取背景颜色(十六进制)\r\n */\r\n getClearColorHex(): string {\r\n const r = Math.round(this._clearColor.r * 255).toString(16).padStart(2, '0');\r\n const g = Math.round(this._clearColor.g * 255).toString(16).padStart(2, '0');\r\n const b = Math.round(this._clearColor.b * 255).toString(16).padStart(2, '0');\r\n return `#${r}${g}${b}`;\r\n }\r\n\r\n get device(): GPUDevice {\r\n return this._device;\r\n }\r\n\r\n get context(): GPUCanvasContext {\r\n return this._context;\r\n }\r\n\r\n get format(): GPUTextureFormat {\r\n return this._format;\r\n }\r\n\r\n get depthFormat(): GPUTextureFormat {\r\n return 'depth24plus';\r\n }\r\n\r\n /**\r\n * 获取渲染宽度(像素)\r\n */\r\n get width(): number {\r\n return this.canvas.width;\r\n }\r\n\r\n /**\r\n * 获取渲染高度(像素)\r\n */\r\n get height(): number {\r\n return this.canvas.height;\r\n }\r\n\r\n /**\r\n * 初始化 WebGPU\r\n */\r\n async init(): Promise<void> {\r\n // 检查 WebGPU 支持\r\n if (!navigator.gpu) {\r\n throw new Error('WebGPU 不受支持');\r\n }\r\n\r\n // 获取适配器\r\n const adapter = await navigator.gpu.requestAdapter({\r\n powerPreference: 'high-performance',\r\n });\r\n if (!adapter) {\r\n throw new Error('无法获取 GPU 适配器');\r\n }\r\n\r\n // 获取设备,请求更高的缓冲区大小限制以支持大型模型\r\n const adapterLimits = adapter.limits;\r\n this._device = await adapter.requestDevice({\r\n requiredLimits: {\r\n maxBufferSize: adapterLimits.maxBufferSize,\r\n maxStorageBufferBindingSize: adapterLimits.maxStorageBufferBindingSize,\r\n },\r\n });\r\n this._device.lost.then((info) => {\r\n // GPU 设备丢失(静默处理)\r\n });\r\n\r\n // 配置 canvas 上下文\r\n this._context = this.canvas.getContext('webgpu') as GPUCanvasContext;\r\n if (!this._context) {\r\n throw new Error('无法获取 WebGPU 上下文');\r\n }\r\n\r\n this._format = navigator.gpu.getPreferredCanvasFormat();\r\n this._context.configure({\r\n device: this._device,\r\n format: this._format,\r\n alphaMode: 'premultiplied',\r\n colorSpace: 'srgb',\r\n });\r\n\r\n // 创建深度纹理\r\n this.createDepthTexture();\r\n\r\n // 监听 canvas 大小变化\r\n this.setupResizeObserver();\r\n }\r\n\r\n /**\r\n * 创建深度纹理\r\n */\r\n private createDepthTexture(): void {\r\n if (this._depthTexture) {\r\n this._depthTexture.destroy();\r\n }\r\n\r\n this._depthTexture = this._device.createTexture({\r\n size: {\r\n width: this.canvas.width,\r\n height: this.canvas.height,\r\n },\r\n format: this.depthFormat,\r\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\r\n });\r\n this._depthTextureView = this._depthTexture.createView();\r\n }\r\n\r\n /**\r\n * 设置 resize 监听\r\n */\r\n private setupResizeObserver(): void {\r\n this.resizeObserver = new ResizeObserver((entries) => {\r\n for (const entry of entries) {\r\n const { width, height } = entry.contentRect;\r\n \r\n // 使用工具函数获取推荐的 DPR\r\n const dpr = getRecommendedDPR();\r\n \r\n this.canvas.width = Math.floor(width * dpr);\r\n this.canvas.height = Math.floor(height * dpr);\r\n \r\n this.createDepthTexture();\r\n }\r\n });\r\n this.resizeObserver.observe(this.canvas);\r\n }\r\n\r\n /**\r\n * 销毁渲染器资源\r\n */\r\n destroy(): void {\r\n // 断开 ResizeObserver\r\n if (this.resizeObserver) {\r\n this.resizeObserver.disconnect();\r\n this.resizeObserver = null;\r\n }\r\n\r\n // 销毁深度纹理\r\n if (this._depthTexture) {\r\n this._depthTexture.destroy();\r\n }\r\n }\r\n\r\n /**\r\n * 开始帧 - 创建命令编码器和渲染通道\r\n */\r\n beginFrame(): GPURenderPassEncoder {\r\n const colorTexture = this._context.getCurrentTexture();\r\n const colorView = colorTexture.createView();\r\n\r\n this.commandEncoder = this._device.createCommandEncoder();\r\n \r\n this.renderPassEncoder = this.commandEncoder.beginRenderPass({\r\n colorAttachments: [\r\n {\r\n view: colorView,\r\n clearValue: this._clearColor,\r\n loadOp: 'clear',\r\n storeOp: 'store',\r\n },\r\n ],\r\n depthStencilAttachment: {\r\n view: this._depthTextureView,\r\n depthClearValue: 1.0,\r\n depthLoadOp: 'clear',\r\n depthStoreOp: 'store',\r\n },\r\n });\r\n\r\n return this.renderPassEncoder;\r\n }\r\n\r\n /**\r\n * 结束帧 - 提交命令\r\n */\r\n endFrame(): void {\r\n this.renderPassEncoder.end();\r\n this._device.queue.submit([this.commandEncoder.finish()]);\r\n }\r\n\r\n /**\r\n * 获取 canvas 宽高比\r\n */\r\n getAspectRatio(): number {\r\n return this.canvas.width / this.canvas.height;\r\n }\r\n}\r\n","/**\r\n * Camera - 相机矩阵计算\r\n * 只负责视图矩阵和投影矩阵\r\n */\r\nexport class Camera {\r\n // 相机参数\r\n position: Float32Array = new Float32Array([0, 0, 5]);\r\n target: Float32Array = new Float32Array([0, 0, 0]);\r\n up: Float32Array = new Float32Array([0, 1, 0]);\r\n\r\n // 投影参数\r\n fov: number = Math.PI / 4; // 45度\r\n aspect: number = 1;\r\n near: number = 0.1; // 增大近平面以提高深度精度 (参考实现使用 0.1)\r\n far: number = 1000; // 减小远平面以提高深度精度\r\n\r\n // 矩阵\r\n viewMatrix: Float32Array = new Float32Array(16);\r\n projectionMatrix: Float32Array = new Float32Array(16);\r\n viewProjectionMatrix: Float32Array = new Float32Array(16);\r\n\r\n constructor() {\r\n this.updateMatrix();\r\n }\r\n\r\n /**\r\n * 设置宽高比\r\n */\r\n setAspect(aspect: number): void {\r\n this.aspect = aspect;\r\n }\r\n\r\n /**\r\n * 更新视图和投影矩阵\r\n */\r\n updateMatrix(): void {\r\n this.updateViewMatrix();\r\n this.updateProjectionMatrix();\r\n this.multiplyMatrices(\r\n this.viewProjectionMatrix,\r\n this.projectionMatrix,\r\n this.viewMatrix,\r\n );\r\n }\r\n\r\n /**\r\n * 计算视图矩阵 (lookAt)\r\n */\r\n private updateViewMatrix(): void {\r\n const eye = this.position;\r\n const target = this.target;\r\n const up = this.up;\r\n\r\n // 计算相机坐标系\r\n const zAxis = this.normalize(this.subtract(eye, target));\r\n const xAxis = this.normalize(this.cross(up, zAxis));\r\n const yAxis = this.cross(zAxis, xAxis);\r\n\r\n // 构建视图矩阵 (列主序)\r\n this.viewMatrix[0] = xAxis[0];\r\n this.viewMatrix[1] = yAxis[0];\r\n this.viewMatrix[2] = zAxis[0];\r\n this.viewMatrix[3] = 0;\r\n\r\n this.viewMatrix[4] = xAxis[1];\r\n this.viewMatrix[5] = yAxis[1];\r\n this.viewMatrix[6] = zAxis[1];\r\n this.viewMatrix[7] = 0;\r\n\r\n this.viewMatrix[8] = xAxis[2];\r\n this.viewMatrix[9] = yAxis[2];\r\n this.viewMatrix[10] = zAxis[2];\r\n this.viewMatrix[11] = 0;\r\n\r\n this.viewMatrix[12] = -this.dot(xAxis, eye);\r\n this.viewMatrix[13] = -this.dot(yAxis, eye);\r\n this.viewMatrix[14] = -this.dot(zAxis, eye);\r\n this.viewMatrix[15] = 1;\r\n }\r\n\r\n /**\r\n * 计算投影矩阵 (透视投影)\r\n */\r\n private updateProjectionMatrix(): void {\r\n const f = 1.0 / Math.tan(this.fov / 2);\r\n const rangeInv = 1 / (this.near - this.far);\r\n\r\n // 列主序\r\n this.projectionMatrix[0] = f / this.aspect;\r\n this.projectionMatrix[1] = 0;\r\n this.projectionMatrix[2] = 0;\r\n this.projectionMatrix[3] = 0;\r\n\r\n this.projectionMatrix[4] = 0;\r\n this.projectionMatrix[5] = f;\r\n this.projectionMatrix[6] = 0;\r\n this.projectionMatrix[7] = 0;\r\n\r\n this.projectionMatrix[8] = 0;\r\n this.projectionMatrix[9] = 0;\r\n this.projectionMatrix[10] = (this.near + this.far) * rangeInv;\r\n this.projectionMatrix[11] = -1;\r\n\r\n this.projectionMatrix[12] = 0;\r\n this.projectionMatrix[13] = 0;\r\n this.projectionMatrix[14] = this.near * this.far * rangeInv * 2;\r\n this.projectionMatrix[15] = 0;\r\n }\r\n\r\n // ========== 向量/矩阵工具函数 ==========\r\n\r\n private subtract(a: Float32Array, b: Float32Array): Float32Array {\r\n return new Float32Array([a[0] - b[0], a[1] - b[1], a[2] - b[2]]);\r\n }\r\n\r\n private cross(a: Float32Array, b: Float32Array): Float32Array {\r\n return new Float32Array([\r\n a[1] * b[2] - a[2] * b[1],\r\n a[2] * b[0] - a[0] * b[2],\r\n a[0] * b[1] - a[1] * b[0],\r\n ]);\r\n }\r\n\r\n private dot(a: Float32Array, b: Float32Array): number {\r\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\r\n }\r\n\r\n private normalize(v: Float32Array): Float32Array {\r\n const len = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);\r\n if (len < 1e-10) return new Float32Array([0, 0, 1]); // 返回默认方向,避免除零\r\n return new Float32Array([v[0] / len, v[1] / len, v[2] / len]);\r\n }\r\n\r\n private multiplyMatrices(\r\n out: Float32Array,\r\n a: Float32Array,\r\n b: Float32Array,\r\n ): void {\r\n for (let i = 0; i < 4; i++) {\r\n for (let j = 0; j < 4; j++) {\r\n out[i * 4 + j] =\r\n a[j] * b[i * 4] +\r\n a[j + 4] * b[i * 4 + 1] +\r\n a[j + 8] * b[i * 4 + 2] +\r\n a[j + 12] * b[i * 4 + 3];\r\n }\r\n }\r\n }\r\n}\r\n","import { Camera } from \"./Camera\";\r\n\r\n/**\r\n * OrbitControls - 轨道控制器\r\n * 只负责鼠标/触摸输入控制相机\r\n */\r\nexport class OrbitControls {\r\n private camera: Camera;\r\n private canvas: HTMLCanvasElement;\r\n\r\n // 球坐标参数\r\n distance: number = 5;\r\n theta: number = 0; // 水平角 (绕Y轴)\r\n phi: number = Math.PI / 4; // 垂直角 (从Y轴向下)\r\n\r\n // 限制\r\n minDistance: number = 0.001;\r\n maxDistance: number = Infinity;\r\n minPhi: number = 0.01;\r\n maxPhi: number = Math.PI - 0.01;\r\n\r\n // 灵敏度\r\n rotateSpeed: number = 0.005;\r\n zoomSpeed: number = 0.001;\r\n panSpeed: number = 0.005;\r\n \r\n // 移动端触摸灵敏度\r\n touchZoomSpeed: number = 0.01;\r\n touchPanSpeed: number = 0.003;\r\n\r\n // 状态\r\n private isDragging: boolean = false;\r\n private lastX: number = 0;\r\n private lastY: number = 0;\r\n\r\n // 触摸手势状态\r\n private touchMode: 'none' | 'rotate' | 'zoom-pan' = 'none';\r\n private lastTouchDistance: number = 0;\r\n private lastTouchCenter: { x: number; y: number } = { x: 0, y: 0 };\r\n\r\n // 启用/禁用\r\n enabled: boolean = true;\r\n\r\n // 绑定的事件处理函数(用于移除监听器)\r\n private boundOnMouseDown: (e: MouseEvent) => void;\r\n private boundOnMouseMove: (e: MouseEvent) => void;\r\n private boundOnMouseUp: (e: MouseEvent) => void;\r\n private boundOnWheel: (e: WheelEvent) => void;\r\n private boundOnTouchStart: (e: TouchEvent) => void;\r\n private boundOnTouchMove: (e: TouchEvent) => void;\r\n private boundOnTouchEnd: (e: TouchEvent) => void;\r\n private boundOnContextMenu: (e: Event) => void;\r\n\r\n constructor(camera: Camera, canvas: HTMLCanvasElement) {\r\n this.camera = camera;\r\n this.canvas = canvas;\r\n\r\n // 绑定事件处理函数\r\n this.boundOnMouseDown = this.onMouseDown.bind(this);\r\n this.boundOnMouseMove = this.onMouseMove.bind(this);\r\n this.boundOnMouseUp = this.onMouseUp.bind(this);\r\n this.boundOnWheel = this.onWheel.bind(this);\r\n this.boundOnTouchStart = this.onTouchStart.bind(this);\r\n this.boundOnTouchMove = this.onTouchMove.bind(this);\r\n this.boundOnTouchEnd = this.onTouchEnd.bind(this);\r\n this.boundOnContextMenu = (e: Event) => e.preventDefault();\r\n\r\n this.setupEventListeners();\r\n this.update();\r\n }\r\n\r\n /**\r\n * 设置事件监听\r\n */\r\n private setupEventListeners(): void {\r\n // 鼠标事件\r\n this.canvas.addEventListener(\"mousedown\", this.boundOnMouseDown);\r\n this.canvas.addEventListener(\"mousemove\", this.boundOnMouseMove);\r\n this.canvas.addEventListener(\"mouseup\", this.boundOnMouseUp);\r\n this.canvas.addEventListener(\"mouseleave\", this.boundOnMouseUp);\r\n this.canvas.addEventListener(\"wheel\", this.boundOnWheel, {\r\n passive: false,\r\n });\r\n\r\n // 触摸事件\r\n this.canvas.addEventListener(\"touchstart\", this.boundOnTouchStart, {\r\n passive: false,\r\n });\r\n this.canvas.addEventListener(\"touchmove\", this.boundOnTouchMove, {\r\n passive: false,\r\n });\r\n this.canvas.addEventListener(\"touchend\", this.boundOnTouchEnd);\r\n\r\n // 禁用右键菜单\r\n this.canvas.addEventListener(\"contextmenu\", this.boundOnContextMenu);\r\n }\r\n\r\n /**\r\n * 移除事件监听\r\n */\r\n private removeEventListeners(): void {\r\n this.canvas.removeEventListener(\"mousedown\", this.boundOnMouseDown);\r\n this.canvas.removeEventListener(\"mousemove\", this.boundOnMouseMove);\r\n this.canvas.removeEventListener(\"mouseup\", this.boundOnMouseUp);\r\n this.canvas.removeEventListener(\"mouseleave\", this.boundOnMouseUp);\r\n this.canvas.removeEventListener(\"wheel\", this.boundOnWheel);\r\n this.canvas.removeEventListener(\"touchstart\", this.boundOnTouchStart);\r\n this.canvas.removeEventListener(\"touchmove\", this.boundOnTouchMove);\r\n this.canvas.removeEventListener(\"touchend\", this.boundOnTouchEnd);\r\n this.canvas.removeEventListener(\"contextmenu\", this.boundOnContextMenu);\r\n }\r\n\r\n /**\r\n * 销毁控制器\r\n */\r\n destroy(): void {\r\n this.removeEventListeners();\r\n }\r\n\r\n private onMouseDown(e: MouseEvent): void {\r\n if (!this.enabled) return;\r\n this.isDragging = true;\r\n this.lastX = e.clientX;\r\n this.lastY = e.clientY;\r\n }\r\n\r\n private onMouseMove(e: MouseEvent): void {\r\n if (!this.enabled || !this.isDragging) return;\r\n\r\n const deltaX = e.clientX - this.lastX;\r\n const deltaY = e.clientY - this.lastY;\r\n this.lastX = e.clientX;\r\n this.lastY = e.clientY;\r\n\r\n // 左键旋转\r\n if (e.buttons === 1) {\r\n this.theta -= deltaX * this.rotateSpeed;\r\n this.phi -= deltaY * this.rotateSpeed; // 修复:向上拖动时相机向上\r\n this.phi = Math.max(this.minPhi, Math.min(this.maxPhi, this.phi));\r\n }\r\n // 右键平移(拖动场景模式:向上拖动场景向上移动)\r\n else if (e.buttons === 2) {\r\n const panX = -deltaX * this.panSpeed * this.distance;\r\n const panY = deltaY * this.panSpeed * this.distance;\r\n\r\n // 计算平移向量\r\n const sinTheta = Math.sin(this.theta);\r\n const cosTheta = Math.cos(this.theta);\r\n\r\n this.camera.target[0] += panX * cosTheta;\r\n this.camera.target[2] += panX * sinTheta;\r\n this.camera.target[1] += panY;\r\n }\r\n\r\n this.update();\r\n }\r\n\r\n private onMouseUp(): void {\r\n this.isDragging = false;\r\n }\r\n\r\n private onWheel(e: WheelEvent): void {\r\n e.preventDefault();\r\n if (!this.enabled) return;\r\n this.distance += e.deltaY * this.zoomSpeed * this.distance;\r\n this.distance = Math.max(\r\n this.minDistance,\r\n Math.min(this.maxDistance, this.distance),\r\n );\r\n this.update();\r\n }\r\n\r\n private onTouchStart(e: TouchEvent): void {\r\n e.preventDefault();\r\n if (!this.enabled) return;\r\n \r\n if (e.touches.length === 1) {\r\n // 单指:旋转模式\r\n this.touchMode = 'rotate';\r\n this.isDragging = true;\r\n this.lastX = e.touches[0].clientX;\r\n this.lastY = e.touches[0].clientY;\r\n } else if (e.touches.length === 2) {\r\n // 双指:缩放+平移模式\r\n this.touchMode = 'zoom-pan';\r\n this.isDragging = true;\r\n this.lastTouchDistance = this.getTouchDistance(e.touches);\r\n this.lastTouchCenter = this.getTouchCenter(e.touches);\r\n }\r\n }\r\n\r\n private onTouchMove(e: TouchEvent): void {\r\n e.preventDefault();\r\n if (!this.enabled || !this.isDragging) return;\r\n\r\n if (e.touches.length === 1 && this.touchMode === 'rotate') {\r\n // 单指旋转\r\n const deltaX = e.touches[0].clientX - this.lastX;\r\n const deltaY = e.touches[0].clientY - this.lastY;\r\n this.lastX = e.touches[0].clientX;\r\n this.lastY = e.touches[0].clientY;\r\n\r\n this.theta -= deltaX * this.rotateSpeed;\r\n this.phi -= deltaY * this.rotateSpeed;\r\n this.phi = Math.max(this.minPhi, Math.min(this.maxPhi, this.phi));\r\n\r\n this.update();\r\n } else if (e.touches.length === 2) {\r\n // 双指缩放 + 平移\r\n const currentDistance = this.getTouchDistance(e.touches);\r\n const currentCenter = this.getTouchCenter(e.touches);\r\n\r\n // 缩放:基于双指距离变化\r\n if (this.lastTouchDistance > 0) {\r\n const scale = this.lastTouchDistance / currentDistance;\r\n this.distance *= Math.pow(scale, this.touchZoomSpeed * 100);\r\n this.distance = Math.max(\r\n this.minDistance,\r\n Math.min(this.maxDistance, this.distance)\r\n );\r\n }\r\n\r\n // 平移:基于双指中心点移动\r\n const deltaX = currentCenter.x - this.lastTouchCenter.x;\r\n const deltaY = currentCenter.y - this.lastTouchCenter.y;\r\n\r\n const panX = -deltaX * this.touchPanSpeed * this.distance;\r\n const panY = deltaY * this.touchPanSpeed * this.distance;\r\n\r\n // 计算平移向量(考虑相机朝向)\r\n const sinTheta = Math.sin(this.theta);\r\n const cosTheta = Math.cos(this.theta);\r\n\r\n this.camera.target[0] += panX * cosTheta;\r\n this.camera.target[2] += panX * sinTheta;\r\n this.camera.target[1] += panY;\r\n\r\n // 更新上一次的触摸状态\r\n this.lastTouchDistance = currentDistance;\r\n this.lastTouchCenter = currentCenter;\r\n\r\n this.update();\r\n }\r\n }\r\n\r\n private onTouchEnd(e: TouchEvent): void {\r\n if (e.touches.length === 0) {\r\n // 所有手指离开\r\n this.isDragging = false;\r\n this.touchMode = 'none';\r\n this.lastTouchDistance = 0;\r\n } else if (e.touches.length === 1) {\r\n // 从双指变为单指,切换到旋转模式\r\n this.touchMode = 'rotate';\r\n this.lastX = e.touches[0].clientX;\r\n this.lastY = e.touches[0].clientY;\r\n }\r\n }\r\n\r\n /**\r\n * 计算双指之间的距离\r\n */\r\n private getTouchDistance(touches: TouchList): number {\r\n const dx = touches[0].clientX - touches[1].clientX;\r\n const dy = touches[0].clientY - touches[1].clientY;\r\n return Math.sqrt(dx * dx + dy * dy);\r\n }\r\n\r\n /**\r\n * 计算双指的中心点\r\n */\r\n private getTouchCenter(touches: TouchList): { x: number; y: number } {\r\n return {\r\n x: (touches[0].clientX + touches[1].clientX) / 2,\r\n y: (touches[0].clientY + touches[1].clientY) / 2,\r\n };\r\n }\r\n\r\n /**\r\n * 根据球坐标更新相机位置\r\n */\r\n update(): void {\r\n const sinPhi = Math.sin(this.phi);\r\n const cosPhi = Math.cos(this.phi);\r\n const sinTheta = Math.sin(this.theta);\r\n const cosTheta = Math.cos(this.theta);\r\n\r\n // 球坐标转笛卡尔坐标\r\n this.camera.position[0] =\r\n this.camera.target[0] + this.distance * sinPhi * sinTheta;\r\n this.camera.position[1] = this.camera.target[1] + this.distance * cosPhi;\r\n this.camera.position[2] =\r\n this.camera.target[2] + this.distance * sinPhi * cosTheta;\r\n\r\n this.camera.updateMatrix();\r\n }\r\n\r\n /**\r\n * 切换到标准视图\r\n * @param axis 轴 'X' | 'Y' | 'Z'\r\n * @param positive 是否正向\r\n * @param animate 是否动画过渡\r\n */\r\n setViewAxis(axis: string, positive: boolean, animate: boolean = true): void {\r\n let targetTheta = this.theta;\r\n let targetPhi = this.phi;\r\n\r\n switch (axis) {\r\n case \"X\":\r\n // X 轴:从右侧看(正)或从左侧看(负)\r\n targetTheta = positive ? Math.PI / 2 : -Math.PI / 2;\r\n targetPhi = Math.PI / 2;\r\n break;\r\n case \"Y\":\r\n // Y 轴:从上方看(正)或从下方看(负)\r\n targetPhi = positive ? 0.01 : Math.PI - 0.01;\r\n break;\r\n case \"Z\":\r\n // Z 轴:从前方看(正)或从后方看(负)\r\n targetTheta = positive ? 0 : Math.PI;\r\n targetPhi = Math.PI / 2;\r\n break;\r\n }\r\n\r\n if (animate) {\r\n this.animateToView(targetTheta, targetPhi);\r\n } else {\r\n this.theta = targetTheta;\r\n this.phi = targetPhi;\r\n this.update();\r\n }\r\n }\r\n\r\n /**\r\n * 动画过渡到目标视图\r\n */\r\n private animateToView(targetTheta: number, targetPhi: number): void {\r\n const startTheta = this.theta;\r\n const startPhi = this.phi;\r\n const duration = 300; // 毫秒\r\n const startTime = performance.now();\r\n\r\n // 计算最短旋转路径\r\n let deltaTheta = targetTheta - startTheta;\r\n while (deltaTheta > Math.PI) deltaTheta -= Math.PI * 2;\r\n while (deltaTheta < -Math.PI) deltaTheta += Math.PI * 2;\r\n\r\n const animate = (currentTime: number) => {\r\n const elapsed = currentTime - startTime;\r\n const progress = Math.min(elapsed / duration, 1);\r\n\r\n // 使用 ease-out 缓动\r\n const eased = 1 - Math.pow(1 - progress, 3);\r\n\r\n this.theta = startTheta + deltaTheta * eased;\r\n this.phi = startPhi + (targetPhi - startPhi) * eased;\r\n this.update();\r\n\r\n if (progress < 1) {\r\n requestAnimationFrame(animate);\r\n }\r\n };\r\n\r\n requestAnimationFrame(animate);\r\n }\r\n\r\n /**\r\n * 设置相机目标点(控制器旋转中心)\r\n * @param x X 坐标\r\n * @param y Y 坐标\r\n * @param z Z 坐标\r\n */\r\n setTarget(x: number, y: number, z: number): void {\r\n this.camera.target[0] = x;\r\n this.camera.target[1] = y;\r\n this.camera.target[2] = z;\r\n this.update();\r\n }\r\n\r\n /**\r\n * 获取当前目标点\r\n */\r\n getTarget(): [number, number, number] {\r\n return [\r\n this.camera.target[0],\r\n this.camera.target[1],\r\n this.camera.target[2],\r\n ];\r\n }\r\n\r\n /**\r\n * 根据模型参数自动调整相机位置和参数\r\n * @param center 模型中心点\r\n * @param radius 模型包围球半径\r\n * @param animate 是否使用动画过渡\r\n */\r\n frameModel(\r\n center: [number, number, number],\r\n radius: number,\r\n animate: boolean = true,\r\n ): void {\r\n // 计算合适的相机距离:确保模型完全在视野内\r\n // distance = radius / tan(fov/2),加一些余量\r\n const fovRad = this.camera.fov;\r\n const halfFov = fovRad / 2;\r\n const marginFactor = 1.5; // 留一些边距\r\n const targetDistance = (radius / Math.tan(halfFov)) * marginFactor;\r\n\r\n // 确保距离不会太小\r\n const clampedDistance = Math.max(this.minDistance, targetDistance);\r\n\r\n if (animate) {\r\n this.animateToFrame(center, clampedDistance);\r\n } else {\r\n // 直接设置\r\n this.camera.target[0] = center[0];\r\n this.camera.target[1] = center[1];\r\n this.camera.target[2] = center[2];\r\n this.distance = clampedDistance;\r\n this.update();\r\n }\r\n }\r\n\r\n /**\r\n * 动画过渡到目标帧(包含目标点和距离)\r\n */\r\n private animateToFrame(\r\n targetCenter: [number, number, number],\r\n targetDistance: number,\r\n ): void {\r\n const startTarget = [\r\n this.camera.target[0],\r\n this.camera.target[1],\r\n this.camera.target[2],\r\n ];\r\n const startDistance = this.distance;\r\n const duration = 400; // 毫秒\r\n const startTime = performance.now();\r\n\r\n const animate = (currentTime: number) => {\r\n const elapsed = currentTime - startTime;\r\n const progress = Math.min(elapsed / duration, 1);\r\n\r\n // 使用 ease-out 缓动\r\n const eased = 1 - Math.pow(1 - progress, 3);\r\n\r\n // 插值目标点\r\n this.camera.target[0] =\r\n startTarget[0] + (targetCenter[0] - startTarget[0]) * eased;\r\n this.camera.target[1] =\r\n startTarget[1] + (targetCenter[1] - startTarget[1]) * eased;\r\n this.camera.target[2] =\r\n startTarget[2] + (targetCenter[2] - startTarget[2]) * eased;\r\n\r\n // 插值距离\r\n this.distance = startDistance + (targetDistance - startDistance) * eased;\r\n\r\n this.update();\r\n\r\n if (progress < 1) {\r\n requestAnimationFrame(animate);\r\n }\r\n };\r\n\r\n requestAnimationFrame(animate);\r\n }\r\n}\r\n","import { Camera } from \"./Camera\";\r\nimport { Renderer } from \"./Renderer\";\r\n\r\n/**\r\n * Gizmo 轴配置\r\n */\r\ninterface AxisConfig {\r\n direction: [number, number, number];\r\n color: [number, number, number];\r\n label: string;\r\n}\r\n\r\n/**\r\n * WGSL Shader - Gizmo 渲染\r\n */\r\nconst gizmoShaderCode = /* wgsl */ `\r\nstruct Uniforms {\r\n viewMatrix: mat4x4<f32>,\r\n projMatrix: mat4x4<f32>,\r\n}\r\n\r\n@group(0) @binding(0) var<uniform> uniforms: Uniforms;\r\n\r\nstruct VertexInput {\r\n @location(0) position: vec3<f32>,\r\n @location(1) color: vec3<f32>,\r\n}\r\n\r\nstruct VertexOutput {\r\n @builtin(position) position: vec4<f32>,\r\n @location(0) color: vec3<f32>,\r\n}\r\n\r\n@vertex\r\nfn vs_main(input: VertexInput) -> VertexOutput {\r\n var output: VertexOutput;\r\n let worldPos = vec4<f32>(input.position, 1.0);\r\n output.position = uniforms.projMatrix * uniforms.viewMatrix * worldPos;\r\n output.color = input.color;\r\n return output;\r\n}\r\n\r\n@fragment\r\nfn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {\r\n return vec4<f32>(input.color, 1.0);\r\n}\r\n`;\r\n\r\n/**\r\n * ViewportGizmo - 视口坐标轴指示器\r\n * 在画布右上角显示当前相机朝向\r\n */\r\nexport class ViewportGizmo {\r\n private renderer: Renderer;\r\n private camera: Camera;\r\n private canvas: HTMLCanvasElement;\r\n\r\n // 渲染资源\r\n private pipeline!: GPURenderPipeline;\r\n private uniformBuffer!: GPUBuffer;\r\n private bindGroup!: GPUBindGroup;\r\n private vertexBuffer!: GPUBuffer;\r\n private indexBuffer!: GPUBuffer;\r\n private vertexCount: number = 0;\r\n private indexCount: number = 0;\r\n\r\n // Gizmo 配置\r\n private size: number = 200; // Gizmo 尺寸(像素)\r\n private margin: number = 20; // 边距\r\n\r\n // Gizmo 投影矩阵\r\n private projMatrix: Float32Array = new Float32Array(16);\r\n private viewMatrix: Float32Array = new Float32Array(16);\r\n\r\n // 轴配置\r\n private axes: AxisConfig[] = [\r\n { direction: [1, 0, 0], color: [0.9, 0.2, 0.2], label: \"X\" }, // 红色 X\r\n { direction: [0, 1, 0], color: [0.2, 0.9, 0.2], label: \"Y\" }, // 绿色 Y\r\n { direction: [0, 0, 1], color: [0.2, 0.4, 0.9], label: \"Z\" }, // 蓝色 Z\r\n ];\r\n\r\n // 交互回调\r\n private onAxisClick?: (axis: string, positive: boolean) => void;\r\n\r\n constructor(renderer: Renderer, camera: Camera, canvas: HTMLCanvasElement) {\r\n this.renderer = renderer;\r\n this.camera = camera;\r\n this.canvas = canvas;\r\n\r\n this.createPipeline();\r\n this.createGeometry();\r\n this.createUniformBuffer();\r\n this.setupOrthoProjection();\r\n }\r\n\r\n /**\r\n * 设置轴点击回调\r\n */\r\n setOnAxisClick(callback: (axis: string, positive: boolean) => void): void {\r\n this.onAxisClick = callback;\r\n }\r\n\r\n /**\r\n * 创建渲染管线\r\n */\r\n private createPipeline(): void {\r\n const device = this.renderer.device;\r\n\r\n const shaderModule = device.createShaderModule({\r\n code: gizmoShaderCode,\r\n });\r\n\r\n const bindGroupLayout = device.createBindGroupLayout({\r\n entries: [\r\n {\r\n binding: 0,\r\n visibility: GPUShaderStage.VERTEX,\r\n buffer: { type: \"uniform\" },\r\n },\r\n ],\r\n });\r\n\r\n const pipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [bindGroupLayout],\r\n });\r\n\r\n // 顶点布局: position(3) + color(3)\r\n const vertexBufferLayout: GPUVertexBufferLayout = {\r\n arrayStride: 24,\r\n attributes: [\r\n { shaderLocation: 0, offset: 0, format: \"float32x3\" },\r\n { shaderLocation: 1, offset: 12, format: \"float32x3\" },\r\n ],\r\n };\r\n\r\n this.pipeline = device.createRenderPipeline({\r\n layout: pipelineLayout,\r\n vertex: {\r\n module: shaderModule,\r\n entryPoint: \"vs_main\",\r\n buffers: [vertexBufferLayout],\r\n },\r\n fragment: {\r\n module: shaderModule,\r\n entryPoint: \"fs_main\",\r\n targets: [{ format: this.renderer.format }],\r\n },\r\n primitive: {\r\n topology: \"triangle-list\",\r\n cullMode: \"none\",\r\n },\r\n depthStencil: {\r\n format: this.renderer.depthFormat,\r\n depthWriteEnabled: true,\r\n depthCompare: \"less\",\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * 创建 Gizmo 几何体(三个轴 + 箭头)\r\n */\r\n private createGeometry(): void {\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n let vertexOffset = 0;\r\n\r\n const axisLength = 0.8;\r\n const axisRadius = 0.04;\r\n const coneLength = 0.25;\r\n const coneRadius = 0.1;\r\n const segments = 12;\r\n\r\n for (const axis of this.axes) {\r\n const [dx, dy, dz] = axis.direction;\r\n const [r, g, b] = axis.color;\r\n\r\n // 创建轴的圆柱体\r\n const cylResult = this.createCylinder(\r\n [0, 0, 0],\r\n [dx * axisLength, dy * axisLength, dz * axisLength],\r\n axisRadius,\r\n segments,\r\n [r, g, b],\r\n vertexOffset,\r\n );\r\n vertices.push(...cylResult.vertices);\r\n indices.push(...cylResult.indices);\r\n vertexOffset += cylResult.vertexCount;\r\n\r\n // 创建箭头圆锥\r\n const coneStart: [number, number, number] = [\r\n dx * axisLength,\r\n dy * axisLength,\r\n dz * axisLength,\r\n ];\r\n const coneEnd: [number, number, number] = [\r\n dx * (axisLength + coneLength),\r\n dy * (axisLength + coneLength),\r\n dz * (axisLength + coneLength),\r\n ];\r\n const coneResult = this.createCone(\r\n coneStart,\r\n coneEnd,\r\n coneRadius,\r\n segments,\r\n [r, g, b],\r\n vertexOffset,\r\n );\r\n vertices.push(...coneResult.vertices);\r\n indices.push(...coneResult.indices);\r\n vertexOffset += coneResult.vertexCount;\r\n\r\n // 创建负方向的小球\r\n const sphereResult = this.createSphere(\r\n [-dx * 0.15, -dy * 0.15, -dz * 0.15],\r\n 0.08,\r\n 8,\r\n [r * 0.6, g * 0.6, b * 0.6],\r\n vertexOffset,\r\n );\r\n vertices.push(...sphereResult.vertices);\r\n indices.push(...sphereResult.indices);\r\n vertexOffset += sphereResult.vertexCount;\r\n }\r\n\r\n // 创建中心球\r\n const centerResult = this.createSphere(\r\n [0, 0, 0],\r\n 0.1,\r\n 12,\r\n [0.5, 0.5, 0.5],\r\n vertexOffset,\r\n );\r\n vertices.push(...centerResult.vertices);\r\n indices.push(...centerResult.indices);\r\n\r\n this.vertexCount = vertices.length / 6;\r\n this.indexCount = indices.length;\r\n\r\n const vertexData = new Float32Array(vertices);\r\n const indexData = new Uint16Array(indices);\r\n\r\n const device = this.renderer.device;\r\n\r\n this.vertexBuffer = device.createBuffer({\r\n size: vertexData.byteLength,\r\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\r\n });\r\n device.queue.writeBuffer(this.vertexBuffer, 0, vertexData);\r\n\r\n this.indexBuffer = device.createBuffer({\r\n size: indexData.byteLength,\r\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\r\n });\r\n device.queue.writeBuffer(this.indexBuffer, 0, indexData);\r\n }\r\n\r\n /**\r\n * 创建圆柱体几何\r\n */\r\n private createCylinder(\r\n start: [number, number, number],\r\n end: [number, number, number],\r\n radius: number,\r\n segments: number,\r\n color: [number, number, number],\r\n indexOffset: number,\r\n ): { vertices: number[]; indices: number[]; vertexCount: number } {\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n\r\n // 计算方向和长度\r\n const dx = end[0] - start[0];\r\n const dy = end[1] - start[1];\r\n const dz = end[2] - start[2];\r\n const length = Math.sqrt(dx * dx + dy * dy + dz * dz);\r\n\r\n // 计算旋转矩阵\r\n const dir = [dx / length, dy / length, dz / length];\r\n const up = Math.abs(dir[1]) < 0.99 ? [0, 1, 0] : [1, 0, 0];\r\n const right = this.cross(\r\n up as [number, number, number],\r\n dir as [number, number, number],\r\n );\r\n this.normalize(right);\r\n const actualUp = this.cross(dir as [number, number, number], right);\r\n\r\n // 生成圆柱顶点\r\n for (let i = 0; i <= segments; i++) {\r\n const angle = (i / segments) * Math.PI * 2;\r\n const cos = Math.cos(angle);\r\n const sin = Math.sin(angle);\r\n\r\n // 底面\r\n const nx0 = right[0] * cos + actualUp[0] * sin;\r\n const ny0 = right[1] * cos + actualUp[1] * sin;\r\n const nz0 = right[2] * cos + actualUp[2] * sin;\r\n vertices.push(\r\n start[0] + nx0 * radius,\r\n start[1] + ny0 * radius,\r\n start[2] + nz0 * radius,\r\n color[0],\r\n color[1],\r\n color[2],\r\n );\r\n\r\n // 顶面\r\n vertices.push(\r\n end[0] + nx0 * radius,\r\n end[1] + ny0 * radius,\r\n end[2] + nz0 * radius,\r\n color[0],\r\n color[1],\r\n color[2],\r\n );\r\n }\r\n\r\n // 生成索引\r\n for (let i = 0; i < segments; i++) {\r\n const i0 = indexOffset + i * 2;\r\n const i1 = indexOffset + i * 2 + 1;\r\n const i2 = indexOffset + (i + 1) * 2;\r\n const i3 = indexOffset + (i + 1) * 2 + 1;\r\n indices.push(i0, i1, i2, i2, i1, i3);\r\n }\r\n\r\n return { vertices, indices, vertexCount: (segments + 1) * 2 };\r\n }\r\n\r\n /**\r\n * 创建圆锥几何\r\n */\r\n private createCone(\r\n base: [number, number, number],\r\n tip: [number, number, number],\r\n radius: number,\r\n segments: number,\r\n color: [number, number, number],\r\n indexOffset: number,\r\n ): { vertices: number[]; indices: number[]; vertexCount: number } {\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n\r\n const dx = tip[0] - base[0];\r\n const dy = tip[1] - base[1];\r\n const dz = tip[2] - base[2];\r\n const length = Math.sqrt(dx * dx + dy * dy + dz * dz);\r\n const dir = [dx / length, dy / length, dz / length];\r\n\r\n const up = Math.abs(dir[1]) < 0.99 ? [0, 1, 0] : [1, 0, 0];\r\n const right = this.cross(\r\n up as [number, number, number],\r\n dir as [number, number, number],\r\n );\r\n this.normalize(right);\r\n const actualUp = this.cross(dir as [number, number, number], right);\r\n\r\n // 尖端\r\n vertices.push(tip[0], tip[1], tip[2], color[0], color[1], color[2]);\r\n\r\n // 底面圆环\r\n for (let i = 0; i <= segments; i++) {\r\n const angle = (i / segments) * Math.PI * 2;\r\n const cos = Math.cos(angle);\r\n const sin = Math.sin(angle);\r\n const nx = right[0] * cos + actualUp[0] * sin;\r\n const ny = right[1] * cos + actualUp[1] * sin;\r\n const nz = right[2] * cos + actualUp[2] * sin;\r\n vertices.push(\r\n base[0] + nx * radius,\r\n base[1] + ny * radius,\r\n base[2] + nz * radius,\r\n color[0],\r\n color[1],\r\n color[2],\r\n );\r\n }\r\n\r\n // 索引(侧面)\r\n for (let i = 0; i < segments; i++) {\r\n indices.push(indexOffset, indexOffset + i + 1, indexOffset + i + 2);\r\n }\r\n\r\n // 底面中心\r\n const baseCenterIdx = indexOffset + segments + 2;\r\n vertices.push(\r\n base[0],\r\n base[1],\r\n base[2],\r\n color[0] * 0.7,\r\n color[1] * 0.7,\r\n color[2] * 0.7,\r\n );\r\n\r\n // 底面索引\r\n for (let i = 0; i < segments; i++) {\r\n indices.push(baseCenterIdx, indexOffset + i + 2, indexOffset + i + 1);\r\n }\r\n\r\n return { vertices, indices, vertexCount: segments + 3 };\r\n }\r\n\r\n /**\r\n * 创建球体几何\r\n */\r\n private createSphere(\r\n center: [number, number, number],\r\n radius: number,\r\n segments: number,\r\n color: [number, number, number],\r\n indexOffset: number,\r\n ): { vertices: number[]; indices: number[]; vertexCount: number } {\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n const rings = segments / 2;\r\n\r\n for (let ring = 0; ring <= rings; ring++) {\r\n const phi = (ring / rings) * Math.PI;\r\n const sinPhi = Math.sin(phi);\r\n const cosPhi = Math.cos(phi);\r\n\r\n for (let seg = 0; seg <= segments; seg++) {\r\n const theta = (seg / segments) * Math.PI * 2;\r\n const x = center[0] + radius * sinPhi * Math.cos(theta);\r\n const y = center[1] + radius * cosPhi;\r\n const z = center[2] + radius * sinPhi * Math.sin(theta);\r\n vertices.push(x, y, z, color[0], color[1], color[2]);\r\n }\r\n }\r\n\r\n for (let ring = 0; ring < rings; ring++) {\r\n for (let seg = 0; seg < segments; seg++) {\r\n const current = indexOffset + ring * (segments + 1) + seg;\r\n const next = current + segments + 1;\r\n indices.push(current, next, current + 1);\r\n indices.push(current + 1, next, next + 1);\r\n }\r\n }\r\n\r\n return { vertices, indices, vertexCount: (rings + 1) * (segments + 1) };\r\n }\r\n\r\n /**\r\n * 创建 uniform buffer\r\n */\r\n private createUniformBuffer(): void {\r\n const device = this.renderer.device;\r\n\r\n // viewMatrix(64) + projMatrix(64) = 128 bytes\r\n this.uniformBuffer = device.createBuffer({\r\n size: 128,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n\r\n const bindGroupLayout = this.pipeline.getBindGroupLayout(0);\r\n this.bindGroup = device.createBindGroup({\r\n layout: bindGroupLayout,\r\n entries: [{ binding: 0, resource: { buffer: this.uniformBuffer } }],\r\n });\r\n }\r\n\r\n /**\r\n * 设置正交投影矩阵\r\n */\r\n private setupOrthoProjection(): void {\r\n const s = 1.5; // 场景大小\r\n // 正交投影矩阵\r\n this.projMatrix[0] = 1 / s;\r\n this.projMatrix[5] = 1 / s;\r\n this.projMatrix[10] = -1 / 10;\r\n this.projMatrix[14] = 0;\r\n this.projMatrix[15] = 1;\r\n }\r\n\r\n /**\r\n * 更新 Gizmo 视图矩阵(从相机提取旋转部分)\r\n */\r\n private updateViewMatrix(): void {\r\n // 从相机视图矩阵提取旋转部分(去除平移)\r\n const camView = this.camera.viewMatrix;\r\n\r\n // 复制旋转部分\r\n this.viewMatrix[0] = camView[0];\r\n this.viewMatrix[1] = camView[1];\r\n this.viewMatrix[2] = camView[2];\r\n this.viewMatrix[3] = 0;\r\n\r\n this.viewMatrix[4] = camView[4];\r\n this.viewMatrix[5] = camView[5];\r\n this.viewMatrix[6] = camView[6];\r\n this.viewMatrix[7] = 0;\r\n\r\n this.viewMatrix[8] = camView[8];\r\n this.viewMatrix[9] = camView[9];\r\n this.viewMatrix[10] = camView[10];\r\n this.viewMatrix[11] = 0;\r\n\r\n // 设置固定的观察距离\r\n this.viewMatrix[12] = 0;\r\n this.viewMatrix[13] = 0;\r\n this.viewMatrix[14] = -3;\r\n this.viewMatrix[15] = 1;\r\n }\r\n\r\n /**\r\n * 渲染 Gizmo\r\n */\r\n render(pass: GPURenderPassEncoder): void {\r\n // 更新视图矩阵\r\n this.updateViewMatrix();\r\n\r\n // 计算 viewport 位置(右上角)\r\n const dpr = window.devicePixelRatio || 1;\r\n let gizmoSize = Math.floor(this.size * dpr);\r\n const marginX = Math.floor(this.margin * dpr);\r\n const marginY = Math.floor(this.margin * dpr);\r\n\r\n // 确保 Gizmo 不会超出 canvas 范围\r\n const maxSize = Math.min(\r\n this.canvas.width - marginX * 2,\r\n this.canvas.height - marginY * 2,\r\n );\r\n if (maxSize < 50) {\r\n // canvas 太小,跳过渲染\r\n return;\r\n }\r\n gizmoSize = Math.min(gizmoSize, maxSize);\r\n\r\n const x = Math.max(0, this.canvas.width - gizmoSize - marginX);\r\n const y = marginY;\r\n\r\n // 设置 viewport\r\n pass.setViewport(x, y, gizmoSize, gizmoSize, 0, 1);\r\n pass.setScissorRect(x, y, gizmoSize, gizmoSize);\r\n\r\n // 更新 uniform\r\n this.renderer.device.queue.writeBuffer(\r\n this.uniformBuffer,\r\n 0,\r\n new Float32Array(this.viewMatrix),\r\n );\r\n this.renderer.device.queue.writeBuffer(\r\n this.uniformBuffer,\r\n 64,\r\n new Float32Array(this.projMatrix),\r\n );\r\n\r\n // 绘制\r\n pass.setPipeline(this.pipeline);\r\n pass.setBindGroup(0, this.bindGroup);\r\n pass.setVertexBuffer(0, this.vertexBuffer);\r\n pass.setIndexBuffer(this.indexBuffer, \"uint16\");\r\n pass.drawIndexed(this.indexCount);\r\n\r\n // 恢复全屏 viewport\r\n pass.setViewport(0, 0, this.canvas.width, this.canvas.height, 0, 1);\r\n pass.setScissorRect(0, 0, this.canvas.width, this.canvas.height);\r\n }\r\n\r\n /**\r\n * 处理点击事件,检测是否点击了某个轴\r\n */\r\n handleClick(clientX: number, clientY: number): boolean {\r\n const rect = this.canvas.getBoundingClientRect();\r\n const dpr = window.devicePixelRatio || 1;\r\n\r\n // 计算 Gizmo 区域\r\n const gizmoSize = this.size;\r\n const marginX = this.margin;\r\n const marginY = this.margin;\r\n const gizmoLeft = rect.right - gizmoSize - marginX;\r\n const gizmoTop = rect.top + marginY;\r\n const gizmoRight = gizmoLeft + gizmoSize;\r\n const gizmoBottom = gizmoTop + gizmoSize;\r\n\r\n // 检查是否在 Gizmo 区域内\r\n if (\r\n clientX < gizmoLeft ||\r\n clientX > gizmoRight ||\r\n clientY < gizmoTop ||\r\n clientY > gizmoBottom\r\n ) {\r\n return false;\r\n }\r\n\r\n // 计算在 Gizmo 中的相对位置(-1 到 1)\r\n const relX = ((clientX - gizmoLeft) / gizmoSize) * 2 - 1;\r\n const relY = -(((clientY - gizmoTop) / gizmoSize) * 2 - 1);\r\n\r\n // 检测点击的轴\r\n const clickedAxis = this.detectClickedAxis(relX, relY);\r\n if (clickedAxis && this.onAxisClick) {\r\n this.onAxisClick(clickedAxis.axis, clickedAxis.positive);\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * 检测点击了哪个轴\r\n */\r\n private detectClickedAxis(\r\n relX: number,\r\n relY: number,\r\n ): { axis: string; positive: boolean } | null {\r\n // 将屏幕坐标转换为 Gizmo 空间\r\n // 使用视图矩阵的逆来判断\r\n const threshold = 0.4;\r\n\r\n // 计算各轴在屏幕上的投影位置\r\n for (const axis of this.axes) {\r\n const [dx, dy, dz] = axis.direction;\r\n\r\n // 正向轴端点\r\n const posX =\r\n this.viewMatrix[0] * dx +\r\n this.viewMatrix[4] * dy +\r\n this.viewMatrix[8] * dz;\r\n const posY =\r\n this.viewMatrix[1] * dx +\r\n this.viewMatrix[5] * dy +\r\n this.viewMatrix[9] * dz;\r\n\r\n // 检查正向\r\n const distPos = Math.sqrt(\r\n (relX - posX * 0.5) ** 2 + (relY - posY * 0.5) ** 2,\r\n );\r\n if (distPos < threshold) {\r\n return { axis: axis.label, positive: true };\r\n }\r\n\r\n // 检查负向\r\n const distNeg = Math.sqrt(\r\n (relX + posX * 0.15) ** 2 + (relY + posY * 0.15) ** 2,\r\n );\r\n if (distNeg < threshold * 0.5) {\r\n return { axis: axis.label, positive: false };\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n\r\n // 向量工具函数\r\n private cross(\r\n a: [number, number, number],\r\n b: [number, number, number],\r\n ): [number, number, number] {\r\n return [\r\n a[1] * b[2] - a[2] * b[1],\r\n a[2] * b[0] - a[0] * b[2],\r\n a[0] * b[1] - a[1] * b[0],\r\n ];\r\n }\r\n\r\n private normalize(v: [number, number, number]): void {\r\n const len = Math.sqrt(v[0] ** 2 + v[1] ** 2 + v[2] ** 2);\r\n if (len > 0) {\r\n v[0] /= len;\r\n v[1] /= len;\r\n v[2] /= len;\r\n }\r\n }\r\n\r\n /**\r\n * 设置 Gizmo 大小\r\n */\r\n setSize(size: number): void {\r\n this.size = size;\r\n }\r\n\r\n /**\r\n * 设置边距\r\n */\r\n setMargin(margin: number): void {\r\n this.margin = margin;\r\n }\r\n}\r\n","import { Renderer } from \"./Renderer\";\r\nimport { Camera } from \"./Camera\";\r\nimport type { SimpleBoundingBox, BoundingBoxProvider, Vec3Tuple } from \"../types\";\r\n\r\n// 重新导出类型保持向后兼容\r\nexport type { BoundingBoxProvider };\r\nexport type BoundingBox = SimpleBoundingBox;\r\n\r\n/**\r\n * BoundingBoxRenderer - 包围盒线框渲染器\r\n * 用于显示选中对象的包围盒,支持动态跟随\r\n */\r\nexport class BoundingBoxRenderer {\r\n private renderer: Renderer;\r\n private camera: Camera;\r\n \r\n // GPU 资源\r\n private pipeline: GPURenderPipeline | null = null;\r\n private uniformBuffer: GPUBuffer | null = null;\r\n private bindGroup: GPUBindGroup | null = null;\r\n private vertexBuffer: GPUBuffer | null = null;\r\n \r\n // 包围盒数据提供者(动态模式)\r\n private provider: BoundingBoxProvider | null = null;\r\n \r\n // 静态包围盒(备用)\r\n private staticBoundingBox: BoundingBox | null = null;\r\n \r\n // 线条颜色 (白色)\r\n private lineColor: [number, number, number] = [1.0, 1.0, 1.0];\r\n \r\n // 角落线段长度比例 (相对于边长)\r\n private cornerRatio: number = 0.2;\r\n \r\n constructor(renderer: Renderer, camera: Camera) {\r\n this.renderer = renderer;\r\n this.camera = camera;\r\n this.createPipeline();\r\n this.createVertexBuffer();\r\n }\r\n \r\n /**\r\n * 创建渲染管线\r\n */\r\n private createPipeline(): void {\r\n const device = this.renderer.device;\r\n \r\n const shaderCode = `\r\n struct Uniforms {\r\n viewProjection: mat4x4<f32>,\r\n }\r\n\r\n @group(0) @binding(0) var<uniform> uniforms: Uniforms;\r\n\r\n struct VertexInput {\r\n @location(0) position: vec3<f32>,\r\n @location(1) color: vec3<f32>,\r\n }\r\n\r\n struct VertexOutput {\r\n @builtin(position) position: vec4<f32>,\r\n @location(0) color: vec3<f32>,\r\n }\r\n\r\n @vertex\r\n fn vertexMain(input: VertexInput) -> VertexOutput {\r\n var output: VertexOutput;\r\n output.position = uniforms.viewProjection * vec4<f32>(input.position, 1.0);\r\n output.color = input.color;\r\n return output;\r\n }\r\n\r\n @fragment\r\n fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {\r\n return vec4<f32>(input.color, 1.0);\r\n }\r\n `;\r\n \r\n const shaderModule = device.createShaderModule({ code: shaderCode });\r\n \r\n // Uniform buffer: viewProjection (64 bytes)\r\n this.uniformBuffer = device.createBuffer({\r\n size: 64,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n \r\n const bindGroupLayout = device.createBindGroupLayout({\r\n entries: [{\r\n binding: 0,\r\n visibility: GPUShaderStage.VERTEX,\r\n buffer: { type: \"uniform\" },\r\n }],\r\n });\r\n \r\n this.bindGroup = device.createBindGroup({\r\n layout: bindGroupLayout,\r\n entries: [{ binding: 0, resource: { buffer: this.uniformBuffer } }],\r\n });\r\n \r\n const pipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [bindGroupLayout],\r\n });\r\n \r\n this.pipeline = device.createRenderPipeline({\r\n layout: pipelineLayout,\r\n vertex: {\r\n module: shaderModule,\r\n entryPoint: \"vertexMain\",\r\n buffers: [{\r\n arrayStride: 24, // 6 floats * 4 bytes\r\n attributes: [\r\n { shaderLocation: 0, offset: 0, format: \"float32x3\" },\r\n { shaderLocation: 1, offset: 12, format: \"float32x3\" },\r\n ],\r\n }],\r\n },\r\n fragment: {\r\n module: shaderModule,\r\n entryPoint: \"fragmentMain\",\r\n targets: [{\r\n format: this.renderer.format,\r\n }],\r\n },\r\n primitive: {\r\n topology: \"line-list\",\r\n cullMode: \"none\",\r\n },\r\n depthStencil: {\r\n format: this.renderer.depthFormat,\r\n depthWriteEnabled: false,\r\n depthCompare: \"always\", // 始终可见\r\n },\r\n });\r\n }\r\n \r\n /**\r\n * 创建顶点缓冲区(预分配)\r\n */\r\n private createVertexBuffer(): void {\r\n const device = this.renderer.device;\r\n // 48 个顶点 * 6 floats * 4 bytes = 1152 bytes\r\n this.vertexBuffer = device.createBuffer({\r\n size: 1152,\r\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\r\n });\r\n }\r\n \r\n /**\r\n * 设置包围盒数据提供者(动态模式)\r\n * 每帧会从 provider 获取最新的包围盒数据\r\n */\r\n setProvider(provider: BoundingBoxProvider | null): void {\r\n this.provider = provider;\r\n this.staticBoundingBox = null;\r\n }\r\n \r\n /**\r\n * 设置静态包围盒(不会自动更新)\r\n */\r\n setBoundingBox(box: BoundingBox | null): void {\r\n this.staticBoundingBox = box;\r\n this.provider = null;\r\n }\r\n \r\n /**\r\n * 清除包围盒\r\n */\r\n clear(): void {\r\n this.provider = null;\r\n this.staticBoundingBox = null;\r\n }\r\n \r\n /**\r\n * 设置线条颜色\r\n */\r\n setLineColor(r: number, g: number, b: number): void {\r\n this.lineColor = [r, g, b];\r\n }\r\n \r\n /**\r\n * 生成顶点数据\r\n */\r\n private generateVertices(box: BoundingBox): Float32Array {\r\n const { min, max } = box;\r\n const [r, g, b] = this.lineColor;\r\n \r\n // 计算各边长度\r\n const dx = max[0] - min[0];\r\n const dy = max[1] - min[1];\r\n const dz = max[2] - min[2];\r\n \r\n // 角落线段长度\r\n const lx = dx * this.cornerRatio;\r\n const ly = dy * this.cornerRatio;\r\n const lz = dz * this.cornerRatio;\r\n \r\n // 8 个角落,每个角落 3 条线段,每条线段 2 个顶点\r\n // 总共 8 * 3 * 2 = 48 个顶点\r\n const vertices: number[] = [];\r\n \r\n // 辅助函数:添加线段\r\n const addLine = (x1: number, y1: number, z1: number, x2: number, y2: number, z2: number) => {\r\n vertices.push(x1, y1, z1, r, g, b);\r\n vertices.push(x2, y2, z2, r, g, b);\r\n };\r\n \r\n // 角落 0: min, min, min\r\n addLine(min[0], min[1], min[2], min[0] + lx, min[1], min[2]);\r\n addLine(min[0], min[1], min[2], min[0], min[1] + ly, min[2]);\r\n addLine(min[0], min[1], min[2], min[0], min[1], min[2] + lz);\r\n \r\n // 角落 1: max, min, min\r\n addLine(max[0], min[1], min[2], max[0] - lx, min[1], min[2]);\r\n addLine(max[0], min[1], min[2], max[0], min[1] + ly, min[2]);\r\n addLine(max[0], min[1], min[2], max[0], min[1], min[2] + lz);\r\n \r\n // 角落 2: min, max, min\r\n addLine(min[0], max[1], min[2], min[0] + lx, max[1], min[2]);\r\n addLine(min[0], max[1], min[2], min[0], max[1] - ly, min[2]);\r\n addLine(min[0], max[1], min[2], min[0], max[1], min[2] + lz);\r\n \r\n // 角落 3: max, max, min\r\n addLine(max[0], max[1], min[2], max[0] - lx, max[1], min[2]);\r\n addLine(max[0], max[1], min[2], max[0], max[1] - ly, min[2]);\r\n addLine(max[0], max[1], min[2], max[0], max[1], min[2] + lz);\r\n \r\n // 角落 4: min, min, max\r\n addLine(min[0], min[1], max[2], min[0] + lx, min[1], max[2]);\r\n addLine(min[0], min[1], max[2], min[0], min[1] + ly, max[2]);\r\n addLine(min[0], min[1], max[2], min[0], min[1], max[2] - lz);\r\n \r\n // 角落 5: max, min, max\r\n addLine(max[0], min[1], max[2], max[0] - lx, min[1], max[2]);\r\n addLine(max[0], min[1], max[2], max[0], min[1] + ly, max[2]);\r\n addLine(max[0], min[1], max[2], max[0], min[1], max[2] - lz);\r\n \r\n // 角落 6: min, max, max\r\n addLine(min[0], max[1], max[2], min[0] + lx, max[1], max[2]);\r\n addLine(min[0], max[1], max[2], min[0], max[1] - ly, max[2]);\r\n addLine(min[0], max[1], max[2], min[0], max[1], max[2] - lz);\r\n \r\n // 角落 7: max, max, max\r\n addLine(max[0], max[1], max[2], max[0] - lx, max[1], max[2]);\r\n addLine(max[0], max[1], max[2], max[0], max[1] - ly, max[2]);\r\n addLine(max[0], max[1], max[2], max[0], max[1], max[2] - lz);\r\n \r\n return new Float32Array(vertices);\r\n }\r\n \r\n /**\r\n * 渲染包围盒\r\n */\r\n render(pass: GPURenderPassEncoder): void {\r\n if (!this.pipeline || !this.bindGroup || !this.vertexBuffer || !this.uniformBuffer) {\r\n return;\r\n }\r\n \r\n // 获取当前包围盒\r\n let box: BoundingBox | null = null;\r\n \r\n if (this.provider) {\r\n box = this.provider.getBoundingBox();\r\n } else {\r\n box = this.staticBoundingBox;\r\n }\r\n \r\n if (!box) return;\r\n \r\n const device = this.renderer.device;\r\n \r\n // 每帧都更新顶点缓冲区(动态模式)\r\n const vertexData = this.generateVertices(box);\r\n device.queue.writeBuffer(this.vertexBuffer, 0, vertexData.buffer);\r\n \r\n // 更新 uniform buffer\r\n const vpMatrix = new Float32Array(this.camera.viewProjectionMatrix);\r\n device.queue.writeBuffer(this.uniformBuffer, 0, vpMatrix);\r\n \r\n // 渲染\r\n pass.setPipeline(this.pipeline);\r\n pass.setBindGroup(0, this.bindGroup);\r\n pass.setVertexBuffer(0, this.vertexBuffer);\r\n pass.draw(48); // 48 个顶点\r\n }\r\n \r\n /**\r\n * 销毁资源\r\n */\r\n destroy(): void {\r\n if (this.vertexBuffer) {\r\n this.vertexBuffer.destroy();\r\n this.vertexBuffer = null;\r\n }\r\n if (this.uniformBuffer) {\r\n this.uniformBuffer.destroy();\r\n this.uniformBuffer = null;\r\n }\r\n this.pipeline = null;\r\n this.bindGroup = null;\r\n }\r\n}\r\n","import type { BoundingBox, Vec3Tuple } from \"../types\";\r\n\r\n/**\r\n * Mesh 包围盒类型别名(保持向后兼容)\r\n */\r\nexport type MeshBoundingBox = BoundingBox;\r\n\r\n/**\r\n * Mesh - 网格数据结构\r\n * 存储 GPUBuffer + 变换属性\r\n */\r\nexport class Mesh {\r\n vertexBuffer: GPUBuffer;\r\n indexBuffer: GPUBuffer | null;\r\n vertexCount: number;\r\n indexCount: number;\r\n modelMatrix: Float32Array;\r\n\r\n // 顶点格式信息\r\n hasUV: boolean = false;\r\n indexFormat: 'uint16' | 'uint32' = 'uint16';\r\n\r\n // 变换属性(分离存储,便于 Gizmo 操作)\r\n position: Float32Array = new Float32Array([0, 0, 0]);\r\n rotation: Float32Array = new Float32Array([0, 0, 0]); // 欧拉角 (弧度)\r\n scale: Float32Array = new Float32Array([1, 1, 1]);\r\n\r\n // 本地空间的 bounding box(加载时计算,不随变换更新)\r\n private localBoundingBox: MeshBoundingBox | null = null;\r\n\r\n constructor(\r\n vertexBuffer: GPUBuffer,\r\n vertexCount: number,\r\n indexBuffer: GPUBuffer | null = null,\r\n indexCount: number = 0,\r\n boundingBox?: MeshBoundingBox\r\n ) {\r\n this.vertexBuffer = vertexBuffer;\r\n this.vertexCount = vertexCount;\r\n this.indexBuffer = indexBuffer;\r\n this.indexCount = indexCount;\r\n this.modelMatrix = new Float32Array([\r\n 1, 0, 0, 0,\r\n 0, 1, 0, 0,\r\n 0, 0, 1, 0,\r\n 0, 0, 0, 1,\r\n ]);\r\n this.localBoundingBox = boundingBox || null;\r\n }\r\n\r\n /**\r\n * 获取顶点 stride(字节数)\r\n */\r\n getVertexStride(): number {\r\n return this.hasUV ? 32 : 24;\r\n }\r\n\r\n /**\r\n * 设置本地 bounding box\r\n */\r\n setBoundingBox(bbox: MeshBoundingBox): void {\r\n this.localBoundingBox = bbox;\r\n }\r\n\r\n /**\r\n * 获取本地 bounding box\r\n */\r\n getLocalBoundingBox(): MeshBoundingBox | null {\r\n return this.localBoundingBox;\r\n }\r\n\r\n /**\r\n * 获取世界空间的 bounding box(考虑完整变换:缩放、旋转、平移)\r\n */\r\n getWorldBoundingBox(): MeshBoundingBox | null {\r\n if (!this.localBoundingBox) return null;\r\n\r\n const local = this.localBoundingBox;\r\n \r\n // 获取本地包围盒的 8 个角点\r\n const corners: Vec3Tuple[] = [\r\n [local.min[0], local.min[1], local.min[2]],\r\n [local.max[0], local.min[1], local.min[2]],\r\n [local.min[0], local.max[1], local.min[2]],\r\n [local.max[0], local.max[1], local.min[2]],\r\n [local.min[0], local.min[1], local.max[2]],\r\n [local.max[0], local.min[1], local.max[2]],\r\n [local.min[0], local.max[1], local.max[2]],\r\n [local.max[0], local.max[1], local.max[2]],\r\n ];\r\n \r\n // 使用 modelMatrix 变换所有角点\r\n const m = this.modelMatrix;\r\n const transformedCorners: Vec3Tuple[] = corners.map(([x, y, z]) => {\r\n const tx = m[0] * x + m[4] * y + m[8] * z + m[12];\r\n const ty = m[1] * x + m[5] * y + m[9] * z + m[13];\r\n const tz = m[2] * x + m[6] * y + m[10] * z + m[14];\r\n return [tx, ty, tz];\r\n });\r\n \r\n // 计算变换后的 AABB\r\n let minX = Infinity, minY = Infinity, minZ = Infinity;\r\n let maxX = -Infinity, maxY = -Infinity, maxZ = -Infinity;\r\n \r\n for (const [x, y, z] of transformedCorners) {\r\n minX = Math.min(minX, x);\r\n minY = Math.min(minY, y);\r\n minZ = Math.min(minZ, z);\r\n maxX = Math.max(maxX, x);\r\n maxY = Math.max(maxY, y);\r\n maxZ = Math.max(maxZ, z);\r\n }\r\n \r\n const worldMin: Vec3Tuple = [minX, minY, minZ];\r\n const worldMax: Vec3Tuple = [maxX, maxY, maxZ];\r\n const worldCenter: Vec3Tuple = [\r\n (minX + maxX) / 2,\r\n (minY + maxY) / 2,\r\n (minZ + maxZ) / 2,\r\n ];\r\n \r\n const dx = maxX - minX;\r\n const dy = maxY - minY;\r\n const dz = maxZ - minZ;\r\n const worldRadius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min: worldMin, max: worldMax, center: worldCenter, radius: worldRadius };\r\n }\r\n\r\n setPosition(x: number, y: number, z: number): void {\r\n this.position[0] = x;\r\n this.position[1] = y;\r\n this.position[2] = z;\r\n this.updateModelMatrix();\r\n }\r\n\r\n getPosition(): Vec3Tuple {\r\n return [this.position[0], this.position[1], this.position[2]];\r\n }\r\n\r\n setRotation(rx: number, ry: number, rz: number): void {\r\n this.rotation[0] = rx;\r\n this.rotation[1] = ry;\r\n this.rotation[2] = rz;\r\n this.updateModelMatrix();\r\n }\r\n\r\n getRotation(): Vec3Tuple {\r\n return [this.rotation[0], this.rotation[1], this.rotation[2]];\r\n }\r\n\r\n setScale(sx: number, sy: number, sz: number): void {\r\n this.scale[0] = sx;\r\n this.scale[1] = sy;\r\n this.scale[2] = sz;\r\n this.updateModelMatrix();\r\n }\r\n\r\n getScale(): Vec3Tuple {\r\n return [this.scale[0], this.scale[1], this.scale[2]];\r\n }\r\n\r\n updateModelMatrix(): void {\r\n const [sx, sy, sz] = this.scale;\r\n const [rx, ry, rz] = this.rotation;\r\n const [tx, ty, tz] = this.position;\r\n\r\n const cx = Math.cos(rx), sx_ = Math.sin(rx);\r\n const cy = Math.cos(ry), sy_ = Math.sin(ry);\r\n const cz = Math.cos(rz), sz_ = Math.sin(rz);\r\n\r\n this.modelMatrix[0] = sx * (cy * cz);\r\n this.modelMatrix[1] = sx * (cy * sz_);\r\n this.modelMatrix[2] = sx * (-sy_);\r\n this.modelMatrix[3] = 0;\r\n\r\n this.modelMatrix[4] = sy * (sx_ * sy_ * cz - cx * sz_);\r\n this.modelMatrix[5] = sy * (sx_ * sy_ * sz_ + cx * cz);\r\n this.modelMatrix[6] = sy * (sx_ * cy);\r\n this.modelMatrix[7] = 0;\r\n\r\n this.modelMatrix[8] = sz * (cx * sy_ * cz + sx_ * sz_);\r\n this.modelMatrix[9] = sz * (cx * sy_ * sz_ - sx_ * cz);\r\n this.modelMatrix[10] = sz * (cx * cy);\r\n this.modelMatrix[11] = 0;\r\n\r\n this.modelMatrix[12] = tx;\r\n this.modelMatrix[13] = ty;\r\n this.modelMatrix[14] = tz;\r\n this.modelMatrix[15] = 1;\r\n }\r\n\r\n resetTransform(): void {\r\n this.position.set([0, 0, 0]);\r\n this.rotation.set([0, 0, 0]);\r\n this.scale.set([1, 1, 1]);\r\n this.updateModelMatrix();\r\n }\r\n\r\n destroy(): void {\r\n this.vertexBuffer.destroy();\r\n if (this.indexBuffer) {\r\n this.indexBuffer.destroy();\r\n }\r\n }\r\n}\r\n","import { Renderer } from \"../core/Renderer\";\r\nimport { Camera } from \"../core/Camera\";\r\nimport { Mesh, MeshBoundingBox } from \"./Mesh\";\r\nimport { MaterialData } from \"../loaders/GLBLoader\";\r\n\r\n/**\r\n * 带纹理的 Shader\r\n */\r\nconst shaderCodeTextured = /* wgsl */ `\r\nstruct Uniforms {\r\n viewProjection: mat4x4<f32>,\r\n model: mat4x4<f32>,\r\n baseColorFactor: vec4<f32>,\r\n lightDir: vec3<f32>,\r\n ambientIntensity: f32,\r\n}\r\n\r\n@group(0) @binding(0) var<uniform> uniforms: Uniforms;\r\n@group(0) @binding(1) var texSampler: sampler;\r\n@group(0) @binding(2) var baseColorTexture: texture_2d<f32>;\r\n\r\nstruct VertexInput {\r\n @location(0) position: vec3<f32>,\r\n @location(1) normal: vec3<f32>,\r\n @location(2) uv: vec2<f32>,\r\n}\r\n\r\nstruct VertexOutput {\r\n @builtin(position) position: vec4<f32>,\r\n @location(0) normal: vec3<f32>,\r\n @location(1) uv: vec2<f32>,\r\n}\r\n\r\n@vertex\r\nfn vs_main(input: VertexInput) -> VertexOutput {\r\n var output: VertexOutput;\r\n let worldPos = uniforms.model * vec4<f32>(input.position, 1.0);\r\n output.position = uniforms.viewProjection * worldPos;\r\n output.normal = normalize((uniforms.model * vec4<f32>(input.normal, 0.0)).xyz);\r\n output.uv = input.uv;\r\n return output;\r\n}\r\n\r\n@fragment\r\nfn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {\r\n let texColor = textureSample(baseColorTexture, texSampler, input.uv);\r\n let baseColor = texColor * uniforms.baseColorFactor;\r\n \r\n // Lambert 光照 + 环境光\r\n let normal = normalize(input.normal);\r\n let NdotL = max(dot(normal, uniforms.lightDir), 0.0);\r\n let diffuse = NdotL * (1.0 - uniforms.ambientIntensity);\r\n let lighting = uniforms.ambientIntensity + diffuse;\r\n \r\n return vec4<f32>(baseColor.rgb * lighting, baseColor.a);\r\n}\r\n`;\r\n\r\n/**\r\n * 无纹理的 Shader(使用 baseColorFactor)\r\n */\r\nconst shaderCodeUntextured = /* wgsl */ `\r\nstruct Uniforms {\r\n viewProjection: mat4x4<f32>,\r\n model: mat4x4<f32>,\r\n baseColorFactor: vec4<f32>,\r\n lightDir: vec3<f32>,\r\n ambientIntensity: f32,\r\n}\r\n\r\n@group(0) @binding(0) var<uniform> uniforms: Uniforms;\r\n\r\nstruct VertexInput {\r\n @location(0) position: vec3<f32>,\r\n @location(1) normal: vec3<f32>,\r\n}\r\n\r\nstruct VertexOutput {\r\n @builtin(position) position: vec4<f32>,\r\n @location(0) normal: vec3<f32>,\r\n}\r\n\r\n@vertex\r\nfn vs_main(input: VertexInput) -> VertexOutput {\r\n var output: VertexOutput;\r\n let worldPos = uniforms.model * vec4<f32>(input.position, 1.0);\r\n output.position = uniforms.viewProjection * worldPos;\r\n output.normal = normalize((uniforms.model * vec4<f32>(input.normal, 0.0)).xyz);\r\n return output;\r\n}\r\n\r\n@fragment\r\nfn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {\r\n let normal = normalize(input.normal);\r\n let NdotL = max(dot(normal, uniforms.lightDir), 0.0);\r\n let diffuse = NdotL * (1.0 - uniforms.ambientIntensity);\r\n let lighting = uniforms.ambientIntensity + diffuse;\r\n \r\n return vec4<f32>(uniforms.baseColorFactor.rgb * lighting, uniforms.baseColorFactor.a);\r\n}\r\n`;\r\n\r\n// Uniform buffer 大小: viewProjection(64) + model(64) + baseColorFactor(16) + lightDir(12) + ambientIntensity(4) = 160 bytes\r\nconst UNIFORM_BUFFER_SIZE = 160;\r\n\r\n/**\r\n * 渲染项(Mesh + Material + 独立的 uniform buffer)\r\n */\r\ninterface RenderItem {\r\n mesh: Mesh;\r\n material: MaterialData;\r\n uniformBuffer: GPUBuffer;\r\n bindGroup: GPUBindGroup;\r\n}\r\n\r\n/**\r\n * MeshRenderer - 网格渲染器\r\n * 支持纹理和材质,每个 mesh 有独立的 uniform buffer\r\n */\r\nexport class MeshRenderer {\r\n private renderer: Renderer;\r\n private camera: Camera;\r\n private items: RenderItem[] = [];\r\n\r\n // 有纹理的管线\r\n private pipelineTextured!: GPURenderPipeline;\r\n private pipelineTexturedDoubleSided!: GPURenderPipeline;\r\n private bindGroupLayoutTextured!: GPUBindGroupLayout;\r\n\r\n // 无纹理的管线\r\n private pipelineUntextured!: GPURenderPipeline;\r\n private pipelineUntexturedDoubleSided!: GPURenderPipeline;\r\n private bindGroupLayoutUntextured!: GPUBindGroupLayout;\r\n\r\n private sampler!: GPUSampler;\r\n private defaultTexture!: GPUTexture;\r\n\r\n // 光照方向\r\n private lightDir: Float32Array = new Float32Array([0.5, 0.7, 0.5]);\r\n // 环境光强度 (0-1)\r\n private ambientIntensity: number = 0.6;\r\n\r\n constructor(renderer: Renderer, camera: Camera) {\r\n this.renderer = renderer;\r\n this.camera = camera;\r\n this.createResources();\r\n this.createPipelines();\r\n }\r\n\r\n private createResources(): void {\r\n const device = this.renderer.device;\r\n\r\n // 创建采样器\r\n this.sampler = device.createSampler({\r\n magFilter: 'linear',\r\n minFilter: 'linear',\r\n mipmapFilter: 'linear',\r\n addressModeU: 'repeat',\r\n addressModeV: 'repeat',\r\n });\r\n\r\n // 创建默认白色纹理\r\n this.defaultTexture = device.createTexture({\r\n size: [1, 1, 1],\r\n format: 'rgba8unorm',\r\n usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,\r\n });\r\n device.queue.writeTexture(\r\n { texture: this.defaultTexture },\r\n new Uint8Array([255, 255, 255, 255]),\r\n { bytesPerRow: 4 },\r\n [1, 1, 1]\r\n );\r\n }\r\n\r\n private createPipelines(): void {\r\n const device = this.renderer.device;\r\n\r\n // === 有纹理的管线 ===\r\n const shaderModuleTextured = device.createShaderModule({ code: shaderCodeTextured });\r\n\r\n this.bindGroupLayoutTextured = device.createBindGroupLayout({\r\n entries: [\r\n { binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: \"uniform\" } },\r\n { binding: 1, visibility: GPUShaderStage.FRAGMENT, sampler: { type: \"filtering\" } },\r\n { binding: 2, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: \"float\" } },\r\n ],\r\n });\r\n\r\n const pipelineLayoutTextured = device.createPipelineLayout({\r\n bindGroupLayouts: [this.bindGroupLayoutTextured],\r\n });\r\n\r\n const vertexBufferLayoutTextured: GPUVertexBufferLayout = {\r\n arrayStride: 32,\r\n attributes: [\r\n { shaderLocation: 0, offset: 0, format: \"float32x3\" },\r\n { shaderLocation: 1, offset: 12, format: \"float32x3\" },\r\n { shaderLocation: 2, offset: 24, format: \"float32x2\" },\r\n ],\r\n };\r\n\r\n const basePipelineDescTextured: GPURenderPipelineDescriptor = {\r\n layout: pipelineLayoutTextured,\r\n vertex: {\r\n module: shaderModuleTextured,\r\n entryPoint: \"vs_main\",\r\n buffers: [vertexBufferLayoutTextured],\r\n },\r\n fragment: {\r\n module: shaderModuleTextured,\r\n entryPoint: \"fs_main\",\r\n targets: [{ format: this.renderer.format }],\r\n },\r\n primitive: { topology: \"triangle-list\", frontFace: \"ccw\" },\r\n depthStencil: { format: this.renderer.depthFormat, depthWriteEnabled: true, depthCompare: \"less\" },\r\n };\r\n\r\n this.pipelineTextured = device.createRenderPipeline({\r\n ...basePipelineDescTextured,\r\n primitive: { ...basePipelineDescTextured.primitive, cullMode: \"back\" },\r\n });\r\n\r\n this.pipelineTexturedDoubleSided = device.createRenderPipeline({\r\n ...basePipelineDescTextured,\r\n primitive: { ...basePipelineDescTextured.primitive, cullMode: \"none\" },\r\n });\r\n\r\n // === 无纹理的管线 ===\r\n const shaderModuleUntextured = device.createShaderModule({ code: shaderCodeUntextured });\r\n\r\n this.bindGroupLayoutUntextured = device.createBindGroupLayout({\r\n entries: [\r\n { binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: \"uniform\" } },\r\n ],\r\n });\r\n\r\n const pipelineLayoutUntextured = device.createPipelineLayout({\r\n bindGroupLayouts: [this.bindGroupLayoutUntextured],\r\n });\r\n\r\n const vertexBufferLayoutUntextured: GPUVertexBufferLayout = {\r\n arrayStride: 24,\r\n attributes: [\r\n { shaderLocation: 0, offset: 0, format: \"float32x3\" },\r\n { shaderLocation: 1, offset: 12, format: \"float32x3\" },\r\n ],\r\n };\r\n\r\n const basePipelineDescUntextured: GPURenderPipelineDescriptor = {\r\n layout: pipelineLayoutUntextured,\r\n vertex: {\r\n module: shaderModuleUntextured,\r\n entryPoint: \"vs_main\",\r\n buffers: [vertexBufferLayoutUntextured],\r\n },\r\n fragment: {\r\n module: shaderModuleUntextured,\r\n entryPoint: \"fs_main\",\r\n targets: [{ format: this.renderer.format }],\r\n },\r\n primitive: { topology: \"triangle-list\", frontFace: \"ccw\" },\r\n depthStencil: { format: this.renderer.depthFormat, depthWriteEnabled: true, depthCompare: \"less\" },\r\n };\r\n\r\n this.pipelineUntextured = device.createRenderPipeline({\r\n ...basePipelineDescUntextured,\r\n primitive: { ...basePipelineDescUntextured.primitive, cullMode: \"back\" },\r\n });\r\n\r\n this.pipelineUntexturedDoubleSided = device.createRenderPipeline({\r\n ...basePipelineDescUntextured,\r\n primitive: { ...basePipelineDescUntextured.primitive, cullMode: \"none\" },\r\n });\r\n }\r\n\r\n /**\r\n * 添加网格(带材质)- 每个 mesh 创建独立的 uniform buffer\r\n */\r\n addMesh(mesh: Mesh, material?: MaterialData): void {\r\n const device = this.renderer.device;\r\n \r\n const mat = material || {\r\n baseColorFactor: [0.8, 0.8, 0.8, 1] as [number, number, number, number],\r\n baseColorTexture: null,\r\n metallicFactor: 0,\r\n roughnessFactor: 0.5,\r\n doubleSided: false,\r\n };\r\n\r\n // 为每个 mesh 创建独立的 uniform buffer\r\n const uniformBuffer = device.createBuffer({\r\n size: UNIFORM_BUFFER_SIZE,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n\r\n // 创建 bind group\r\n let bindGroup: GPUBindGroup;\r\n \r\n if (mesh.hasUV) {\r\n const texture = mat.baseColorTexture || this.defaultTexture;\r\n bindGroup = device.createBindGroup({\r\n layout: this.bindGroupLayoutTextured,\r\n entries: [\r\n { binding: 0, resource: { buffer: uniformBuffer } },\r\n { binding: 1, resource: this.sampler },\r\n { binding: 2, resource: texture.createView() },\r\n ],\r\n });\r\n } else {\r\n bindGroup = device.createBindGroup({\r\n layout: this.bindGroupLayoutUntextured,\r\n entries: [\r\n { binding: 0, resource: { buffer: uniformBuffer } },\r\n ],\r\n });\r\n }\r\n\r\n this.items.push({ mesh, material: mat, uniformBuffer, bindGroup });\r\n }\r\n\r\n /**\r\n * 移除网格\r\n */\r\n removeMesh(mesh: Mesh): void {\r\n const index = this.items.findIndex(item => item.mesh === mesh);\r\n if (index !== -1) {\r\n const item = this.items[index];\r\n item.mesh.destroy();\r\n item.uniformBuffer.destroy();\r\n this.items.splice(index, 1);\r\n }\r\n }\r\n\r\n /**\r\n * 按索引移除网格\r\n */\r\n removeMeshByIndex(index: number): boolean {\r\n if (index >= 0 && index < this.items.length) {\r\n const item = this.items[index];\r\n item.mesh.destroy();\r\n item.uniformBuffer.destroy();\r\n this.items.splice(index, 1);\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * 清空所有网格\r\n */\r\n clear(): void {\r\n for (const item of this.items) {\r\n item.mesh.destroy();\r\n item.uniformBuffer.destroy();\r\n }\r\n this.items = [];\r\n }\r\n\r\n /**\r\n * 设置光照方向\r\n */\r\n setLightDirection(x: number, y: number, z: number): void {\r\n const len = Math.sqrt(x * x + y * y + z * z);\r\n this.lightDir[0] = x / len;\r\n this.lightDir[1] = y / len;\r\n this.lightDir[2] = z / len;\r\n }\r\n\r\n /**\r\n * 设置环境光强度\r\n */\r\n setAmbientIntensity(intensity: number): void {\r\n this.ambientIntensity = Math.max(0, Math.min(1, intensity));\r\n }\r\n\r\n /**\r\n * 获取环境光强度\r\n */\r\n getAmbientIntensity(): number {\r\n return this.ambientIntensity;\r\n }\r\n\r\n /**\r\n * 渲染所有网格\r\n */\r\n render(pass: GPURenderPassEncoder): void {\r\n if (this.items.length === 0) return;\r\n\r\n const device = this.renderer.device;\r\n const vpMatrix = new Float32Array(this.camera.viewProjectionMatrix);\r\n const lightData = new Float32Array([\r\n this.lightDir[0], this.lightDir[1], this.lightDir[2], this.ambientIntensity\r\n ]);\r\n\r\n for (const item of this.items) {\r\n const { mesh, material, uniformBuffer, bindGroup } = item;\r\n\r\n // 更新该 mesh 的 uniform buffer\r\n device.queue.writeBuffer(uniformBuffer, 0, vpMatrix.buffer);\r\n device.queue.writeBuffer(uniformBuffer, 64, mesh.modelMatrix.buffer);\r\n const colorData = new Float32Array(material.baseColorFactor);\r\n device.queue.writeBuffer(uniformBuffer, 128, colorData.buffer);\r\n device.queue.writeBuffer(uniformBuffer, 144, lightData.buffer);\r\n\r\n // 选择管线\r\n let pipeline: GPURenderPipeline;\r\n if (mesh.hasUV) {\r\n pipeline = material.doubleSided ? this.pipelineTexturedDoubleSided : this.pipelineTextured;\r\n } else {\r\n pipeline = material.doubleSided ? this.pipelineUntexturedDoubleSided : this.pipelineUntextured;\r\n }\r\n\r\n pass.setPipeline(pipeline);\r\n pass.setBindGroup(0, bindGroup);\r\n pass.setVertexBuffer(0, mesh.vertexBuffer);\r\n\r\n if (mesh.indexBuffer && mesh.indexCount > 0) {\r\n pass.setIndexBuffer(mesh.indexBuffer, mesh.indexFormat);\r\n pass.drawIndexed(mesh.indexCount);\r\n } else {\r\n pass.draw(mesh.vertexCount);\r\n }\r\n }\r\n }\r\n\r\n getMeshCount(): number {\r\n return this.items.length;\r\n }\r\n\r\n getMeshByIndex(index: number): Mesh | null {\r\n if (index >= 0 && index < this.items.length) {\r\n return this.items[index].mesh;\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * 获取指定索引网格的材质颜色\r\n */\r\n getMeshColor(index: number): [number, number, number, number] | null {\r\n if (index >= 0 && index < this.items.length) {\r\n return [...this.items[index].material.baseColorFactor] as [number, number, number, number];\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * 设置指定索引网格的材质颜色\r\n */\r\n setMeshColor(index: number, r: number, g: number, b: number, a: number = 1): boolean {\r\n if (index >= 0 && index < this.items.length) {\r\n this.items[index].material.baseColorFactor = [r, g, b, a];\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * 设置指定范围内所有网格的材质颜色\r\n */\r\n setMeshRangeColor(startIndex: number, count: number, r: number, g: number, b: number, a: number = 1): number {\r\n let modified = 0;\r\n for (let i = 0; i < count; i++) {\r\n if (this.setMeshColor(startIndex + i, r, g, b, a)) {\r\n modified++;\r\n }\r\n }\r\n return modified;\r\n }\r\n\r\n getCombinedBoundingBox(): MeshBoundingBox | null {\r\n if (this.items.length === 0) return null;\r\n\r\n let combinedMin: [number, number, number] | null = null;\r\n let combinedMax: [number, number, number] | null = null;\r\n\r\n for (const item of this.items) {\r\n const bbox = item.mesh.getWorldBoundingBox();\r\n if (!bbox) continue;\r\n\r\n if (combinedMin === null || combinedMax === null) {\r\n combinedMin = [...bbox.min];\r\n combinedMax = [...bbox.max];\r\n } else {\r\n combinedMin[0] = Math.min(combinedMin[0], bbox.min[0]);\r\n combinedMin[1] = Math.min(combinedMin[1], bbox.min[1]);\r\n combinedMin[2] = Math.min(combinedMin[2], bbox.min[2]);\r\n combinedMax[0] = Math.max(combinedMax[0], bbox.max[0]);\r\n combinedMax[1] = Math.max(combinedMax[1], bbox.max[1]);\r\n combinedMax[2] = Math.max(combinedMax[2], bbox.max[2]);\r\n }\r\n }\r\n\r\n if (combinedMin === null || combinedMax === null) return null;\r\n\r\n const center: [number, number, number] = [\r\n (combinedMin[0] + combinedMax[0]) / 2,\r\n (combinedMin[1] + combinedMax[1]) / 2,\r\n (combinedMin[2] + combinedMax[2]) / 2,\r\n ];\r\n const dx = combinedMax[0] - combinedMin[0];\r\n const dy = combinedMax[1] - combinedMin[1];\r\n const dz = combinedMax[2] - combinedMin[2];\r\n const radius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min: combinedMin, max: combinedMax, center, radius };\r\n }\r\n\r\n destroy(): void {\r\n this.clear();\r\n if (this.defaultTexture) this.defaultTexture.destroy();\r\n }\r\n}\r\n","import { Mesh, MeshBoundingBox } from '../mesh/Mesh';\r\nimport type { BoundingBox, Vec3Tuple, MaterialData } from '../types';\r\nimport { computeBoundingBox } from '../utils';\r\n\r\n// 重新导出 MaterialData 保持向后兼容\r\nexport type { MaterialData };\r\n\r\n/**\r\n * GLB 文件格式常量\r\n */\r\nconst GLB_MAGIC = 0x46546C67; // 'glTF'\r\nconst GLB_VERSION = 2;\r\nconst CHUNK_TYPE_JSON = 0x4E4F534A; // 'JSON'\r\nconst CHUNK_TYPE_BIN = 0x004E4942; // 'BIN\\0'\r\n\r\n/**\r\n * glTF 访问器组件类型\r\n */\r\nconst COMPONENT_TYPES: Record<number, { size: number; type: 'float' | 'uint8' | 'uint16' | 'uint32' | 'int8' | 'int16' }> = {\r\n 5120: { size: 1, type: 'int8' }, // BYTE\r\n 5121: { size: 1, type: 'uint8' }, // UNSIGNED_BYTE\r\n 5122: { size: 2, type: 'int16' }, // SHORT\r\n 5123: { size: 2, type: 'uint16' }, // UNSIGNED_SHORT\r\n 5125: { size: 4, type: 'uint32' }, // UNSIGNED_INT\r\n 5126: { size: 4, type: 'float' }, // FLOAT\r\n};\r\n\r\n/**\r\n * glTF 类型元素数量\r\n */\r\nconst TYPE_SIZES: Record<string, number> = {\r\n SCALAR: 1,\r\n VEC2: 2,\r\n VEC3: 3,\r\n VEC4: 4,\r\n MAT2: 4,\r\n MAT3: 9,\r\n MAT4: 16,\r\n};\r\n\r\n/**\r\n * 加载后的 Mesh 数据(包含材质)\r\n */\r\nexport interface LoadedMesh {\r\n mesh: Mesh;\r\n material: MaterialData;\r\n}\r\n\r\n/**\r\n * GLBLoader - GLB 文件加载器\r\n * 解析 GLB 文件并生成 Mesh[],支持贴图\r\n */\r\nexport class GLBLoader {\r\n private device: GPUDevice;\r\n private textureCache: Map<number, GPUTexture> = new Map();\r\n\r\n constructor(device: GPUDevice) {\r\n this.device = device;\r\n }\r\n\r\n /**\r\n * 加载 GLB 文件\r\n */\r\n async load(url: string): Promise<LoadedMesh[]> {\r\n const response = await fetch(url);\r\n if (!response.ok) {\r\n throw new Error(`无法加载 GLB 文件: ${url}`);\r\n }\r\n\r\n const arrayBuffer = await response.arrayBuffer();\r\n return this.parse(arrayBuffer);\r\n }\r\n\r\n /**\r\n * 解析 GLB 二进制数据\r\n */\r\n private async parse(buffer: ArrayBuffer): Promise<LoadedMesh[]> {\r\n const dataView = new DataView(buffer);\r\n let offset = 0;\r\n\r\n // 读取 GLB 头部\r\n const magic = dataView.getUint32(offset, true);\r\n offset += 4;\r\n if (magic !== GLB_MAGIC) {\r\n throw new Error('无效的 GLB 文件');\r\n }\r\n\r\n const version = dataView.getUint32(offset, true);\r\n offset += 4;\r\n if (version !== GLB_VERSION) {\r\n throw new Error(`不支持的 GLB 版本: ${version}`);\r\n }\r\n\r\n const _length = dataView.getUint32(offset, true);\r\n offset += 4;\r\n\r\n // 读取 JSON chunk\r\n const jsonChunkLength = dataView.getUint32(offset, true);\r\n offset += 4;\r\n const jsonChunkType = dataView.getUint32(offset, true);\r\n offset += 4;\r\n\r\n if (jsonChunkType !== CHUNK_TYPE_JSON) {\r\n throw new Error('第一个 chunk 必须是 JSON');\r\n }\r\n\r\n const jsonData = new Uint8Array(buffer, offset, jsonChunkLength);\r\n const jsonString = new TextDecoder().decode(jsonData);\r\n const gltf = JSON.parse(jsonString);\r\n offset += jsonChunkLength;\r\n\r\n // 读取 BIN chunk(可选)\r\n let binData: ArrayBuffer | null = null;\r\n if (offset < buffer.byteLength) {\r\n const binChunkLength = dataView.getUint32(offset, true);\r\n offset += 4;\r\n const binChunkType = dataView.getUint32(offset, true);\r\n offset += 4;\r\n\r\n if (binChunkType === CHUNK_TYPE_BIN) {\r\n binData = buffer.slice(offset, offset + binChunkLength);\r\n }\r\n }\r\n\r\n // 清空纹理缓存\r\n this.textureCache.clear();\r\n\r\n // 解析网格\r\n return this.parseMeshes(gltf, binData);\r\n }\r\n\r\n /**\r\n * 解析所有网格\r\n */\r\n private async parseMeshes(gltf: any, binData: ArrayBuffer | null): Promise<LoadedMesh[]> {\r\n const meshes: LoadedMesh[] = [];\r\n\r\n if (!gltf.meshes || !binData) {\r\n return meshes;\r\n }\r\n\r\n for (const gltfMesh of gltf.meshes) {\r\n for (const primitive of gltfMesh.primitives) {\r\n const loadedMesh = await this.parsePrimitive(gltf, primitive, binData);\r\n if (loadedMesh) {\r\n meshes.push(loadedMesh);\r\n }\r\n }\r\n }\r\n\r\n return meshes;\r\n }\r\n\r\n /**\r\n * 解析单个图元\r\n */\r\n private async parsePrimitive(gltf: any, primitive: any, binData: ArrayBuffer): Promise<LoadedMesh | null> {\r\n const attributes = primitive.attributes;\r\n \r\n // 获取位置数据\r\n if (attributes.POSITION === undefined) {\r\n return null;\r\n }\r\n\r\n const positionAccessor = gltf.accessors[attributes.POSITION];\r\n const positions = this.getAccessorData(gltf, positionAccessor, binData);\r\n\r\n // 获取法线数据(可选,如果没有则生成)\r\n let normals: Float32Array;\r\n if (attributes.NORMAL !== undefined) {\r\n const normalAccessor = gltf.accessors[attributes.NORMAL];\r\n const normalData = this.getAccessorData(gltf, normalAccessor, binData);\r\n normals = new Float32Array(normalData);\r\n } else {\r\n // 生成默认法线(指向 +Y)\r\n normals = new Float32Array(positions.length);\r\n for (let i = 0; i < positions.length; i += 3) {\r\n normals[i] = 0;\r\n normals[i + 1] = 1;\r\n normals[i + 2] = 0;\r\n }\r\n }\r\n\r\n // 获取 UV 坐标(可选)\r\n let uvs: Float32Array | null = null;\r\n if (attributes.TEXCOORD_0 !== undefined) {\r\n const uvAccessor = gltf.accessors[attributes.TEXCOORD_0];\r\n const uvData = this.getAccessorData(gltf, uvAccessor, binData);\r\n uvs = new Float32Array(uvData);\r\n }\r\n\r\n // 创建交错顶点数据: position(3) + normal(3) + uv(2)\r\n const vertexCount = positionAccessor.count;\r\n const hasUV = uvs !== null;\r\n const stride = hasUV ? 8 : 6; // 有 UV 时 8 floats,否则 6 floats\r\n const vertexData = new Float32Array(vertexCount * stride);\r\n \r\n for (let i = 0; i < vertexCount; i++) {\r\n const baseIdx = i * stride;\r\n vertexData[baseIdx + 0] = positions[i * 3 + 0];\r\n vertexData[baseIdx + 1] = positions[i * 3 + 1];\r\n vertexData[baseIdx + 2] = positions[i * 3 + 2];\r\n vertexData[baseIdx + 3] = normals[i * 3 + 0];\r\n vertexData[baseIdx + 4] = normals[i * 3 + 1];\r\n vertexData[baseIdx + 5] = normals[i * 3 + 2];\r\n if (hasUV && uvs) {\r\n vertexData[baseIdx + 6] = uvs[i * 2 + 0];\r\n vertexData[baseIdx + 7] = uvs[i * 2 + 1];\r\n }\r\n }\r\n\r\n // 创建顶点缓冲区\r\n const vertexBuffer = this.device.createBuffer({\r\n size: vertexData.byteLength,\r\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\r\n });\r\n this.device.queue.writeBuffer(vertexBuffer, 0, vertexData);\r\n\r\n // 获取索引数据(可选)\r\n let indexBuffer: GPUBuffer | null = null;\r\n let indexCount = 0;\r\n let indexFormat: 'uint16' | 'uint32' = 'uint16';\r\n\r\n if (primitive.indices !== undefined) {\r\n const indexAccessor = gltf.accessors[primitive.indices];\r\n const indices = this.getAccessorData(gltf, indexAccessor, binData);\r\n indexCount = indexAccessor.count;\r\n\r\n // 根据顶点数量决定索引格式\r\n if (vertexCount > 65535) {\r\n indexFormat = 'uint32';\r\n const indexData = new Uint32Array(indexCount);\r\n for (let i = 0; i < indexCount; i++) {\r\n indexData[i] = indices[i];\r\n }\r\n indexBuffer = this.device.createBuffer({\r\n size: indexData.byteLength,\r\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\r\n });\r\n this.device.queue.writeBuffer(indexBuffer, 0, indexData);\r\n } else {\r\n const indexData = new Uint16Array(indexCount);\r\n for (let i = 0; i < indexCount; i++) {\r\n indexData[i] = indices[i];\r\n }\r\n indexBuffer = this.device.createBuffer({\r\n size: indexData.byteLength,\r\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\r\n });\r\n this.device.queue.writeBuffer(indexBuffer, 0, indexData);\r\n }\r\n }\r\n\r\n // 计算 bounding box\r\n const boundingBox = this.computeBoundingBoxFromPositions(positions);\r\n\r\n // 解析材质\r\n const material = await this.parseMaterial(gltf, primitive.material, binData);\r\n\r\n // 创建 Mesh\r\n const mesh = new Mesh(vertexBuffer, vertexCount, indexBuffer, indexCount, boundingBox);\r\n mesh.hasUV = hasUV;\r\n mesh.indexFormat = indexFormat;\r\n\r\n return { mesh, material };\r\n }\r\n\r\n /**\r\n * 解析材质\r\n */\r\n private async parseMaterial(gltf: any, materialIndex: number | undefined, binData: ArrayBuffer): Promise<MaterialData> {\r\n // 默认材质\r\n const defaultMaterial: MaterialData = {\r\n baseColorFactor: [1, 1, 1, 1],\r\n baseColorTexture: null,\r\n metallicFactor: 1,\r\n roughnessFactor: 1,\r\n doubleSided: false,\r\n };\r\n\r\n if (materialIndex === undefined || !gltf.materials) {\r\n return defaultMaterial;\r\n }\r\n\r\n const gltfMaterial = gltf.materials[materialIndex];\r\n if (!gltfMaterial) {\r\n return defaultMaterial;\r\n }\r\n\r\n const material: MaterialData = { ...defaultMaterial };\r\n\r\n // 解析 doubleSided\r\n if (gltfMaterial.doubleSided !== undefined) {\r\n material.doubleSided = gltfMaterial.doubleSided;\r\n }\r\n\r\n // 解析 PBR 材质\r\n const pbr = gltfMaterial.pbrMetallicRoughness;\r\n if (pbr) {\r\n // baseColorFactor\r\n if (pbr.baseColorFactor) {\r\n material.baseColorFactor = pbr.baseColorFactor;\r\n }\r\n\r\n // metallicFactor\r\n if (pbr.metallicFactor !== undefined) {\r\n material.metallicFactor = pbr.metallicFactor;\r\n }\r\n\r\n // roughnessFactor\r\n if (pbr.roughnessFactor !== undefined) {\r\n material.roughnessFactor = pbr.roughnessFactor;\r\n }\r\n\r\n // baseColorTexture\r\n if (pbr.baseColorTexture) {\r\n const textureIndex = pbr.baseColorTexture.index;\r\n material.baseColorTexture = await this.loadTexture(gltf, textureIndex, binData);\r\n }\r\n }\r\n\r\n return material;\r\n }\r\n\r\n /**\r\n * 加载纹理\r\n */\r\n private async loadTexture(gltf: any, textureIndex: number, binData: ArrayBuffer): Promise<GPUTexture | null> {\r\n // 检查缓存\r\n if (this.textureCache.has(textureIndex)) {\r\n return this.textureCache.get(textureIndex)!;\r\n }\r\n\r\n if (!gltf.textures || !gltf.images) {\r\n return null;\r\n }\r\n\r\n const texture = gltf.textures[textureIndex];\r\n if (!texture || texture.source === undefined) {\r\n return null;\r\n }\r\n\r\n const image = gltf.images[texture.source];\r\n if (!image) {\r\n return null;\r\n }\r\n\r\n try {\r\n let imageBitmap: ImageBitmap;\r\n\r\n if (image.bufferView !== undefined) {\r\n // 从 buffer 加载图片\r\n const bufferView = gltf.bufferViews[image.bufferView];\r\n const byteOffset = bufferView.byteOffset || 0;\r\n const byteLength = bufferView.byteLength;\r\n const imageData = new Uint8Array(binData, byteOffset, byteLength);\r\n const blob = new Blob([imageData], { type: image.mimeType || 'image/png' });\r\n imageBitmap = await createImageBitmap(blob);\r\n } else if (image.uri) {\r\n // 从 URI 加载(data URI 或外部 URL)\r\n if (image.uri.startsWith('data:')) {\r\n const response = await fetch(image.uri);\r\n const blob = await response.blob();\r\n imageBitmap = await createImageBitmap(blob);\r\n } else {\r\n // 外部 URL - 这里简化处理,实际可能需要相对路径解析\r\n const response = await fetch(image.uri);\r\n const blob = await response.blob();\r\n imageBitmap = await createImageBitmap(blob);\r\n }\r\n } else {\r\n return null;\r\n }\r\n\r\n // 创建 GPU 纹理\r\n const gpuTexture = this.device.createTexture({\r\n size: [imageBitmap.width, imageBitmap.height, 1],\r\n format: 'rgba8unorm',\r\n usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,\r\n });\r\n\r\n this.device.queue.copyExternalImageToTexture(\r\n { source: imageBitmap },\r\n { texture: gpuTexture },\r\n [imageBitmap.width, imageBitmap.height]\r\n );\r\n\r\n // 缓存纹理\r\n this.textureCache.set(textureIndex, gpuTexture);\r\n\r\n return gpuTexture;\r\n } catch (error) {\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * 计算顶点数据的 bounding box\r\n */\r\n private computeBoundingBoxFromPositions(positions: Float32Array | Uint16Array | Uint32Array | Int8Array | Int16Array | Uint8Array): MeshBoundingBox {\r\n return computeBoundingBox(positions);\r\n }\r\n\r\n /**\r\n * 获取访问器数据 - 修复字节对齐问题\r\n */\r\n private getAccessorData(gltf: any, accessor: any, binData: ArrayBuffer): Float32Array | Uint16Array | Uint32Array | Int8Array | Int16Array | Uint8Array {\r\n const bufferView = gltf.bufferViews[accessor.bufferView];\r\n const componentType = COMPONENT_TYPES[accessor.componentType];\r\n const typeSize = TYPE_SIZES[accessor.type];\r\n const count = accessor.count * typeSize;\r\n\r\n const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);\r\n const byteLength = count * componentType.size;\r\n\r\n // 复制数据到新的 ArrayBuffer 以避免对齐问题\r\n const alignedBuffer = new ArrayBuffer(byteLength);\r\n const srcView = new Uint8Array(binData, byteOffset, byteLength);\r\n const dstView = new Uint8Array(alignedBuffer);\r\n dstView.set(srcView);\r\n\r\n switch (componentType.type) {\r\n case 'float':\r\n return new Float32Array(alignedBuffer);\r\n case 'uint8':\r\n return new Uint8Array(alignedBuffer);\r\n case 'uint16':\r\n return new Uint16Array(alignedBuffer);\r\n case 'uint32':\r\n return new Uint32Array(alignedBuffer);\r\n case 'int8':\r\n return new Int8Array(alignedBuffer);\r\n case 'int16':\r\n return new Int16Array(alignedBuffer);\r\n default:\r\n throw new Error(`不支持的组件类型: ${accessor.componentType}`);\r\n }\r\n }\r\n\r\n /**\r\n * 创建测试立方体(用于调试)\r\n */\r\n createTestCube(): LoadedMesh {\r\n // 立方体顶点数据: position(3) + normal(3) + uv(2)\r\n const vertices = new Float32Array([\r\n // 前面 (z = 0.5)\r\n -0.5, -0.5, 0.5, 0, 0, 1, 0, 1,\r\n 0.5, -0.5, 0.5, 0, 0, 1, 1, 1,\r\n 0.5, 0.5, 0.5, 0, 0, 1, 1, 0,\r\n -0.5, 0.5, 0.5, 0, 0, 1, 0, 0,\r\n // 后面 (z = -0.5)\r\n 0.5, -0.5, -0.5, 0, 0, -1, 0, 1,\r\n -0.5, -0.5, -0.5, 0, 0, -1, 1, 1,\r\n -0.5, 0.5, -0.5, 0, 0, -1, 1, 0,\r\n 0.5, 0.5, -0.5, 0, 0, -1, 0, 0,\r\n // 上面 (y = 0.5)\r\n -0.5, 0.5, 0.5, 0, 1, 0, 0, 1,\r\n 0.5, 0.5, 0.5, 0, 1, 0, 1, 1,\r\n 0.5, 0.5, -0.5, 0, 1, 0, 1, 0,\r\n -0.5, 0.5, -0.5, 0, 1, 0, 0, 0,\r\n // 下面 (y = -0.5)\r\n -0.5, -0.5, -0.5, 0, -1, 0, 0, 1,\r\n 0.5, -0.5, -0.5, 0, -1, 0, 1, 1,\r\n 0.5, -0.5, 0.5, 0, -1, 0, 1, 0,\r\n -0.5, -0.5, 0.5, 0, -1, 0, 0, 0,\r\n // 右面 (x = 0.5)\r\n 0.5, -0.5, 0.5, 1, 0, 0, 0, 1,\r\n 0.5, -0.5, -0.5, 1, 0, 0, 1, 1,\r\n 0.5, 0.5, -0.5, 1, 0, 0, 1, 0,\r\n 0.5, 0.5, 0.5, 1, 0, 0, 0, 0,\r\n // 左面 (x = -0.5)\r\n -0.5, -0.5, -0.5, -1, 0, 0, 0, 1,\r\n -0.5, -0.5, 0.5, -1, 0, 0, 1, 1,\r\n -0.5, 0.5, 0.5, -1, 0, 0, 1, 0,\r\n -0.5, 0.5, -0.5, -1, 0, 0, 0, 0,\r\n ]);\r\n\r\n const indices = new Uint16Array([\r\n 0, 1, 2, 0, 2, 3, // 前\r\n 4, 5, 6, 4, 6, 7, // 后\r\n 8, 9, 10, 8, 10, 11, // 上\r\n 12, 13, 14, 12, 14, 15, // 下\r\n 16, 17, 18, 16, 18, 19, // 右\r\n 20, 21, 22, 20, 22, 23, // 左\r\n ]);\r\n\r\n const vertexBuffer = this.device.createBuffer({\r\n size: vertices.byteLength,\r\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\r\n });\r\n this.device.queue.writeBuffer(vertexBuffer, 0, vertices);\r\n\r\n const indexBuffer = this.device.createBuffer({\r\n size: indices.byteLength,\r\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\r\n });\r\n this.device.queue.writeBuffer(indexBuffer, 0, indices);\r\n\r\n // 立方体 bounding box: -0.5 到 0.5\r\n const cubeBbox: MeshBoundingBox = {\r\n min: [-0.5, -0.5, -0.5],\r\n max: [0.5, 0.5, 0.5],\r\n center: [0, 0, 0],\r\n radius: Math.sqrt(0.75),\r\n };\r\n\r\n const mesh = new Mesh(vertexBuffer, 24, indexBuffer, 36, cubeBbox);\r\n mesh.hasUV = true;\r\n mesh.indexFormat = 'uint16';\r\n\r\n return {\r\n mesh,\r\n material: {\r\n baseColorFactor: [1, 1, 1, 1],\r\n baseColorTexture: null,\r\n metallicFactor: 0,\r\n roughnessFactor: 0.5,\r\n doubleSided: false,\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * 创建测试球体\r\n */\r\n createTestSphere(radius: number = 0.5, segments: number = 32, rings: number = 16): LoadedMesh {\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n\r\n // 生成顶点\r\n for (let ring = 0; ring <= rings; ring++) {\r\n const phi = (ring / rings) * Math.PI;\r\n const sinPhi = Math.sin(phi);\r\n const cosPhi = Math.cos(phi);\r\n\r\n for (let seg = 0; seg <= segments; seg++) {\r\n const theta = (seg / segments) * Math.PI * 2;\r\n const sinTheta = Math.sin(theta);\r\n const cosTheta = Math.cos(theta);\r\n\r\n // 位置\r\n const x = radius * sinPhi * cosTheta;\r\n const y = radius * cosPhi;\r\n const z = radius * sinPhi * sinTheta;\r\n\r\n // 法线(球体法线就是归一化的位置)\r\n const nx = sinPhi * cosTheta;\r\n const ny = cosPhi;\r\n const nz = sinPhi * sinTheta;\r\n\r\n // UV\r\n const u = seg / segments;\r\n const v = ring / rings;\r\n\r\n vertices.push(x, y, z, nx, ny, nz, u, v);\r\n }\r\n }\r\n\r\n // 生成索引\r\n for (let ring = 0; ring < rings; ring++) {\r\n for (let seg = 0; seg < segments; seg++) {\r\n const current = ring * (segments + 1) + seg;\r\n const next = current + segments + 1;\r\n\r\n indices.push(current, next, current + 1);\r\n indices.push(current + 1, next, next + 1);\r\n }\r\n }\r\n\r\n const vertexData = new Float32Array(vertices);\r\n const indexData = new Uint16Array(indices);\r\n\r\n const vertexBuffer = this.device.createBuffer({\r\n size: vertexData.byteLength,\r\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\r\n });\r\n this.device.queue.writeBuffer(vertexBuffer, 0, vertexData);\r\n\r\n const indexBuffer = this.device.createBuffer({\r\n size: indexData.byteLength,\r\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\r\n });\r\n this.device.queue.writeBuffer(indexBuffer, 0, indexData);\r\n\r\n // 球体 bounding box\r\n const sphereBbox: MeshBoundingBox = {\r\n min: [-radius, -radius, -radius],\r\n max: [radius, radius, radius],\r\n center: [0, 0, 0],\r\n radius: radius,\r\n };\r\n\r\n const mesh = new Mesh(vertexBuffer, vertexData.length / 8, indexBuffer, indexData.length, sphereBbox);\r\n mesh.hasUV = true;\r\n mesh.indexFormat = 'uint16';\r\n\r\n return {\r\n mesh,\r\n material: {\r\n baseColorFactor: [1, 1, 1, 1],\r\n baseColorTexture: null,\r\n metallicFactor: 0,\r\n roughnessFactor: 0.5,\r\n doubleSided: false,\r\n },\r\n };\r\n }\r\n}\r\n","/**\r\n * OBJParser - OBJ 文件文本解析器\r\n * 解析 OBJ 文件文本内容,提取几何数据\r\n */\r\n\r\n/**\r\n * 解析后的 OBJ 数据结构\r\n */\r\nexport interface ParsedOBJData {\r\n objects: ParsedObject[];\r\n}\r\n\r\n/**\r\n * 单个对象/组的数据\r\n */\r\nexport interface ParsedObject {\r\n name: string;\r\n positions: number[]; // 展开后的顶点位置 [x,y,z, x,y,z, ...]\r\n normals: number[]; // 展开后的法线 [nx,ny,nz, ...]\r\n uvs: number[]; // 展开后的 UV [u,v, u,v, ...]\r\n indices: number[]; // 三角形索引\r\n materialName: string | null;\r\n}\r\n\r\n/**\r\n * 面顶点索引结构\r\n */\r\ninterface FaceVertex {\r\n positionIndex: number;\r\n uvIndex: number | null;\r\n normalIndex: number | null;\r\n}\r\n\r\n/**\r\n * OBJ 文本解析器\r\n */\r\nexport class OBJParser {\r\n // 全局顶点池\r\n private positions: number[] = []; // v 指令收集的顶点位置\r\n private uvs: number[] = []; // vt 指令收集的纹理坐标\r\n private normals: number[] = []; // vn 指令收集的法线\r\n\r\n // 当前对象数据\r\n private currentObject: ParsedObject | null = null;\r\n private objects: ParsedObject[] = [];\r\n\r\n // 当前材质\r\n private currentMaterial: string | null = null;\r\n\r\n // 顶点去重映射 (用于索引缓冲区)\r\n private vertexMap: Map<string, number> = new Map();\r\n private vertexCount: number = 0;\r\n\r\n // 已警告的不支持指令集合(用于只警告首次)\r\n private warnedDirectives: Set<string> = new Set();\r\n\r\n /**\r\n * 解析 OBJ 文本内容\r\n * @param text OBJ 文件文本\r\n * @returns 解析后的数据结构\r\n */\r\n parse(text: string): ParsedOBJData {\r\n // 重置状态\r\n this.reset();\r\n\r\n // 按行分割文本\r\n const lines = text.split(/\\r?\\n/);\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n const line = lines[i].trim();\r\n \r\n // 跳过空行和注释\r\n if (line === '' || line.startsWith('#')) {\r\n continue;\r\n }\r\n\r\n this.parseLine(line, i + 1);\r\n }\r\n\r\n // 确保最后一个对象被添加\r\n this.finalizeCurrentObject();\r\n\r\n // 如果没有任何对象,但有面数据,创建默认对象\r\n if (this.objects.length === 0 && this.currentObject && this.currentObject.indices.length > 0) {\r\n this.objects.push(this.currentObject);\r\n }\r\n\r\n return { objects: this.objects };\r\n }\r\n\r\n /**\r\n * 重置解析器状态\r\n */\r\n private reset(): void {\r\n this.positions = [];\r\n this.uvs = [];\r\n this.normals = [];\r\n this.currentObject = null;\r\n this.objects = [];\r\n this.currentMaterial = null;\r\n this.vertexMap = new Map();\r\n this.vertexCount = 0;\r\n this.warnedDirectives = new Set();\r\n }\r\n\r\n /**\r\n * 警告不支持的指令(仅首次出现时警告)\r\n * @param directive 指令名称\r\n * @param lineNum 行号\r\n */\r\n private warnUnsupportedDirective(directive: string, lineNum: number): void {\r\n if (!this.warnedDirectives.has(directive)) {\r\n this.warnedDirectives.add(directive);\r\n }\r\n }\r\n\r\n /**\r\n * 解析单行\r\n */\r\n private parseLine(line: string, lineNum: number): void {\r\n // 分割指令和参数\r\n const parts = line.split(/\\s+/);\r\n const directive = parts[0].toLowerCase();\r\n\r\n try {\r\n switch (directive) {\r\n case 'v':\r\n this.parseVertex(parts);\r\n break;\r\n case 'vt':\r\n this.parseTextureCoord(parts);\r\n break;\r\n case 'vn':\r\n this.parseNormal(parts);\r\n break;\r\n case 'f':\r\n this.parseFace(parts, lineNum);\r\n break;\r\n case 'o':\r\n case 'g':\r\n this.parseObjectOrGroup(parts);\r\n break;\r\n case 'usemtl':\r\n this.parseUseMaterial(parts);\r\n break;\r\n case 'mtllib':\r\n // MTL 文件引用,在 OBJLoader 中处理\r\n break;\r\n case 's':\r\n // 平滑组,暂不支持,警告首次\r\n this.warnUnsupportedDirective(directive, lineNum);\r\n break;\r\n default:\r\n // 不支持的指令,警告首次\r\n this.warnUnsupportedDirective(directive, lineNum);\r\n break;\r\n }\r\n } catch (e) {\r\n // 解析错误,跳过该行\r\n }\r\n }\r\n\r\n /**\r\n * 解析顶点位置 (v x y z [w])\r\n */\r\n private parseVertex(parts: string[]): void {\r\n if (parts.length < 4) {\r\n throw new Error('顶点数据不完整');\r\n }\r\n\r\n const x = parseFloat(parts[1]);\r\n const y = parseFloat(parts[2]);\r\n const z = parseFloat(parts[3]);\r\n\r\n if (isNaN(x) || isNaN(y) || isNaN(z)) {\r\n throw new Error('无效的顶点坐标');\r\n }\r\n\r\n this.positions.push(x, y, z);\r\n }\r\n\r\n /**\r\n * 解析纹理坐标 (vt u [v] [w])\r\n */\r\n private parseTextureCoord(parts: string[]): void {\r\n if (parts.length < 2) {\r\n throw new Error('纹理坐标数据不完整');\r\n }\r\n\r\n const u = parseFloat(parts[1]);\r\n const v = parts.length > 2 ? parseFloat(parts[2]) : 0;\r\n\r\n if (isNaN(u) || isNaN(v)) {\r\n throw new Error('无效的纹理坐标');\r\n }\r\n\r\n this.uvs.push(u, v);\r\n }\r\n\r\n /**\r\n * 解析法线 (vn x y z)\r\n */\r\n private parseNormal(parts: string[]): void {\r\n if (parts.length < 4) {\r\n throw new Error('法线数据不完整');\r\n }\r\n\r\n const x = parseFloat(parts[1]);\r\n const y = parseFloat(parts[2]);\r\n const z = parseFloat(parts[3]);\r\n\r\n if (isNaN(x) || isNaN(y) || isNaN(z)) {\r\n throw new Error('无效的法线');\r\n }\r\n\r\n this.normals.push(x, y, z);\r\n }\r\n\r\n /**\r\n * 解析面 (f v1 v2 v3 ...)\r\n * 支持四种格式:\r\n * - f v v v (仅顶点)\r\n * - f v/vt v/vt v/vt (顶点/纹理)\r\n * - f v/vt/vn v/vt/vn v/vt/vn (顶点/纹理/法线)\r\n * - f v//vn v//vn v//vn (顶点//法线)\r\n */\r\n private parseFace(parts: string[], _lineNum: number): void {\r\n if (parts.length < 4) {\r\n throw new Error('面数据不完整,至少需要3个顶点');\r\n }\r\n\r\n // 确保有当前对象\r\n this.ensureCurrentObject();\r\n\r\n // 解析面顶点\r\n const faceVertices: FaceVertex[] = [];\r\n for (let i = 1; i < parts.length; i++) {\r\n const vertex = this.parseFaceVertex(parts[i]);\r\n if (vertex) {\r\n faceVertices.push(vertex);\r\n }\r\n }\r\n\r\n if (faceVertices.length < 3) {\r\n throw new Error('面顶点数量不足');\r\n }\r\n\r\n // 三角化多边形(扇形三角化)\r\n // 对于 n 边形 [v0, v1, v2, ..., vn-1]:\r\n // 生成三角形: (v0, v1, v2), (v0, v2, v3), ..., (v0, vn-2, vn-1)\r\n for (let i = 1; i < faceVertices.length - 1; i++) {\r\n this.addTriangle(faceVertices[0], faceVertices[i], faceVertices[i + 1]);\r\n }\r\n }\r\n\r\n /**\r\n * 解析面顶点索引\r\n * 支持格式: v, v/vt, v/vt/vn, v//vn\r\n */\r\n private parseFaceVertex(vertexStr: string): FaceVertex | null {\r\n const parts = vertexStr.split('/');\r\n \r\n // 解析位置索引(必需)\r\n const positionIndex = this.resolveIndex(parseInt(parts[0]), this.positions.length / 3);\r\n if (isNaN(positionIndex)) {\r\n return null;\r\n }\r\n\r\n // 解析纹理坐标索引(可选)\r\n let uvIndex: number | null = null;\r\n if (parts.length > 1 && parts[1] !== '') {\r\n uvIndex = this.resolveIndex(parseInt(parts[1]), this.uvs.length / 2);\r\n if (isNaN(uvIndex)) {\r\n uvIndex = null;\r\n }\r\n }\r\n\r\n // 解析法线索引(可选)\r\n let normalIndex: number | null = null;\r\n if (parts.length > 2 && parts[2] !== '') {\r\n normalIndex = this.resolveIndex(parseInt(parts[2]), this.normals.length / 3);\r\n if (isNaN(normalIndex)) {\r\n normalIndex = null;\r\n }\r\n }\r\n\r\n return { positionIndex, uvIndex, normalIndex };\r\n }\r\n\r\n /**\r\n * 解析索引,支持负索引\r\n * 负索引表示相对于当前顶点数的偏移(-1 表示最后一个顶点)\r\n */\r\n private resolveIndex(index: number, count: number): number {\r\n if (isNaN(index)) {\r\n return NaN;\r\n }\r\n\r\n if (index < 0) {\r\n // 负索引:-1 表示最后一个,-2 表示倒数第二个\r\n return count + index;\r\n } else {\r\n // 正索引:OBJ 索引从 1 开始\r\n return index - 1;\r\n }\r\n }\r\n\r\n /**\r\n * 添加三角形到当前对象\r\n */\r\n private addTriangle(v0: FaceVertex, v1: FaceVertex, v2: FaceVertex): void {\r\n const idx0 = this.addVertex(v0);\r\n const idx1 = this.addVertex(v1);\r\n const idx2 = this.addVertex(v2);\r\n\r\n this.currentObject!.indices.push(idx0, idx1, idx2);\r\n }\r\n\r\n /**\r\n * 添加顶点到当前对象,返回索引\r\n * 使用顶点去重,相同的顶点组合只添加一次\r\n */\r\n private addVertex(vertex: FaceVertex): number {\r\n // 创建顶点键用于去重\r\n const key = `${vertex.positionIndex}/${vertex.uvIndex ?? ''}/${vertex.normalIndex ?? ''}`;\r\n\r\n // 检查是否已存在\r\n if (this.vertexMap.has(key)) {\r\n return this.vertexMap.get(key)!;\r\n }\r\n\r\n // 添加新顶点\r\n const index = this.vertexCount++;\r\n this.vertexMap.set(key, index);\r\n\r\n // 添加位置数据\r\n const posIdx = vertex.positionIndex * 3;\r\n if (posIdx >= 0 && posIdx + 2 < this.positions.length) {\r\n this.currentObject!.positions.push(\r\n this.positions[posIdx],\r\n this.positions[posIdx + 1],\r\n this.positions[posIdx + 2]\r\n );\r\n } else {\r\n // 无效索引,使用默认值\r\n this.currentObject!.positions.push(0, 0, 0);\r\n }\r\n\r\n // 添加法线数据\r\n if (vertex.normalIndex !== null) {\r\n const normIdx = vertex.normalIndex * 3;\r\n if (normIdx >= 0 && normIdx + 2 < this.normals.length) {\r\n this.currentObject!.normals.push(\r\n this.normals[normIdx],\r\n this.normals[normIdx + 1],\r\n this.normals[normIdx + 2]\r\n );\r\n } else {\r\n this.currentObject!.normals.push(0, 1, 0);\r\n }\r\n }\r\n\r\n // 添加 UV 数据\r\n if (vertex.uvIndex !== null) {\r\n const uvIdx = vertex.uvIndex * 2;\r\n if (uvIdx >= 0 && uvIdx + 1 < this.uvs.length) {\r\n this.currentObject!.uvs.push(\r\n this.uvs[uvIdx],\r\n this.uvs[uvIdx + 1]\r\n );\r\n } else {\r\n this.currentObject!.uvs.push(0, 0);\r\n }\r\n }\r\n\r\n return index;\r\n }\r\n\r\n /**\r\n * 解析对象或组 (o name / g name)\r\n */\r\n private parseObjectOrGroup(parts: string[]): void {\r\n // 完成当前对象\r\n this.finalizeCurrentObject();\r\n\r\n // 创建新对象\r\n const name = parts.length > 1 ? parts.slice(1).join(' ') : 'default';\r\n this.createNewObject(name);\r\n }\r\n\r\n /**\r\n * 解析材质引用 (usemtl name)\r\n */\r\n private parseUseMaterial(parts: string[]): void {\r\n if (parts.length > 1) {\r\n this.currentMaterial = parts.slice(1).join(' ');\r\n \r\n // 如果当前对象已有面数据,需要创建新对象\r\n if (this.currentObject && this.currentObject.indices.length > 0) {\r\n this.finalizeCurrentObject();\r\n this.createNewObject(this.currentObject?.name || 'default');\r\n }\r\n \r\n if (this.currentObject) {\r\n this.currentObject.materialName = this.currentMaterial;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * 确保存在当前对象\r\n */\r\n private ensureCurrentObject(): void {\r\n if (!this.currentObject) {\r\n this.createNewObject('default');\r\n }\r\n }\r\n\r\n /**\r\n * 创建新对象\r\n */\r\n private createNewObject(name: string): void {\r\n this.currentObject = {\r\n name,\r\n positions: [],\r\n normals: [],\r\n uvs: [],\r\n indices: [],\r\n materialName: this.currentMaterial,\r\n };\r\n this.vertexMap = new Map();\r\n this.vertexCount = 0;\r\n }\r\n\r\n /**\r\n * 完成当前对象并添加到列表\r\n */\r\n private finalizeCurrentObject(): void {\r\n if (this.currentObject && this.currentObject.indices.length > 0) {\r\n this.objects.push(this.currentObject);\r\n }\r\n this.currentObject = null;\r\n }\r\n}\r\n","/**\r\n * MTLParser - MTL 材质文件解析器\r\n * 解析 MTL 文件文本内容,提取材质数据\r\n */\r\n\r\n/**\r\n * 解析后的材质数据\r\n */\r\nexport interface ParsedMaterial {\r\n name: string;\r\n diffuseColor: [number, number, number]; // Kd\r\n diffuseTexture: string | null; // map_Kd\r\n opacity: number; // d 或 1-Tr\r\n}\r\n\r\n/**\r\n * MTL 文本解析器\r\n */\r\nexport class MTLParser {\r\n // 当前材质\r\n private currentMaterial: ParsedMaterial | null = null;\r\n private materials: Map<string, ParsedMaterial> = new Map();\r\n\r\n /**\r\n * 解析 MTL 文本内容\r\n * @param text MTL 文件文本\r\n * @returns 材质名称到材质数据的映射\r\n */\r\n parse(text: string): Map<string, ParsedMaterial> {\r\n // 重置状态\r\n this.reset();\r\n\r\n // 按行分割文本\r\n const lines = text.split(/\\r?\\n/);\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n const line = lines[i].trim();\r\n\r\n // 跳过空行和注释\r\n if (line === '' || line.startsWith('#')) {\r\n continue;\r\n }\r\n\r\n this.parseLine(line, i + 1);\r\n }\r\n\r\n // 确保最后一个材质被添加\r\n this.finalizeCurrentMaterial();\r\n\r\n return this.materials;\r\n }\r\n\r\n /**\r\n * 重置解析器状态\r\n */\r\n private reset(): void {\r\n this.currentMaterial = null;\r\n this.materials = new Map();\r\n }\r\n\r\n /**\r\n * 解析单行\r\n */\r\n private parseLine(line: string, lineNum: number): void {\r\n // 分割指令和参数\r\n const parts = line.split(/\\s+/);\r\n const directive = parts[0].toLowerCase();\r\n\r\n try {\r\n switch (directive) {\r\n case 'newmtl':\r\n this.parseNewMaterial(parts);\r\n break;\r\n case 'kd':\r\n this.parseDiffuseColor(parts);\r\n break;\r\n case 'map_kd':\r\n this.parseDiffuseTexture(parts);\r\n break;\r\n case 'd':\r\n this.parseOpacity(parts);\r\n break;\r\n case 'tr':\r\n this.parseTransparency(parts);\r\n break;\r\n default:\r\n // 忽略不支持的指令 (Ka, Ks, Ns, illum, etc.)\r\n break;\r\n }\r\n } catch (e) {\r\n // 解析错误,跳过该行\r\n }\r\n }\r\n\r\n /**\r\n * 解析新材质定义 (newmtl name)\r\n */\r\n private parseNewMaterial(parts: string[]): void {\r\n // 完成当前材质\r\n this.finalizeCurrentMaterial();\r\n\r\n // 创建新材质\r\n const name = parts.length > 1 ? parts.slice(1).join(' ') : 'default';\r\n this.currentMaterial = this.createDefaultMaterial(name);\r\n }\r\n\r\n /**\r\n * 解析漫反射颜色 (Kd r g b)\r\n */\r\n private parseDiffuseColor(parts: string[]): void {\r\n if (!this.currentMaterial) {\r\n return;\r\n }\r\n\r\n if (parts.length < 4) {\r\n throw new Error('漫反射颜色数据不完整');\r\n }\r\n\r\n const r = parseFloat(parts[1]);\r\n const g = parseFloat(parts[2]);\r\n const b = parseFloat(parts[3]);\r\n\r\n if (isNaN(r) || isNaN(g) || isNaN(b)) {\r\n throw new Error('无效的漫反射颜色值');\r\n }\r\n\r\n this.currentMaterial.diffuseColor = [r, g, b];\r\n }\r\n\r\n /**\r\n * 解析漫反射纹理路径 (map_Kd path)\r\n */\r\n private parseDiffuseTexture(parts: string[]): void {\r\n if (!this.currentMaterial) {\r\n return;\r\n }\r\n\r\n if (parts.length < 2) {\r\n throw new Error('漫反射纹理路径不完整');\r\n }\r\n\r\n // 纹理路径可能包含空格,所以需要合并剩余部分\r\n const texturePath = parts.slice(1).join(' ');\r\n this.currentMaterial.diffuseTexture = texturePath;\r\n }\r\n\r\n /**\r\n * 解析透明度 (d factor)\r\n * d = 1.0 表示完全不透明,d = 0.0 表示完全透明\r\n */\r\n private parseOpacity(parts: string[]): void {\r\n if (!this.currentMaterial) {\r\n return;\r\n }\r\n\r\n if (parts.length < 2) {\r\n throw new Error('透明度数据不完整');\r\n }\r\n\r\n const opacity = parseFloat(parts[1]);\r\n\r\n if (isNaN(opacity)) {\r\n throw new Error('无效的透明度值');\r\n }\r\n\r\n this.currentMaterial.opacity = opacity;\r\n }\r\n\r\n /**\r\n * 解析透明度 (Tr factor)\r\n * Tr = 0.0 表示完全不透明,Tr = 1.0 表示完全透明\r\n * 与 d 相反,所以 opacity = 1 - Tr\r\n */\r\n private parseTransparency(parts: string[]): void {\r\n if (!this.currentMaterial) {\r\n return;\r\n }\r\n\r\n if (parts.length < 2) {\r\n throw new Error('透明度数据不完整');\r\n }\r\n\r\n const transparency = parseFloat(parts[1]);\r\n\r\n if (isNaN(transparency)) {\r\n throw new Error('无效的透明度值');\r\n }\r\n\r\n // Tr 是透明度,需要转换为不透明度\r\n this.currentMaterial.opacity = 1 - transparency;\r\n }\r\n\r\n /**\r\n * 创建默认材质\r\n */\r\n private createDefaultMaterial(name: string): ParsedMaterial {\r\n return {\r\n name,\r\n diffuseColor: [1, 1, 1], // 默认白色\r\n diffuseTexture: null,\r\n opacity: 1, // 默认完全不透明\r\n };\r\n }\r\n\r\n /**\r\n * 完成当前材质并添加到映射\r\n */\r\n private finalizeCurrentMaterial(): void {\r\n if (this.currentMaterial) {\r\n this.materials.set(this.currentMaterial.name, this.currentMaterial);\r\n }\r\n this.currentMaterial = null;\r\n }\r\n}\r\n","/**\r\n * OBJLoader - OBJ 文件加载器\r\n * 解析 OBJ 文件并生成 Mesh[],支持 MTL 材质\r\n */\r\n\r\nimport { Mesh, MeshBoundingBox } from '../mesh/Mesh';\r\nimport type { MaterialData } from '../types';\r\nimport { DEFAULT_OBJ_MATERIAL } from '../types';\r\nimport { computeBoundingBox } from '../utils';\r\nimport { LoadedMesh } from './GLBLoader';\r\nimport { OBJParser, ParsedOBJData, ParsedObject } from './OBJParser';\r\nimport { MTLParser, ParsedMaterial } from './MTLParser';\r\n\r\n/**\r\n * OBJLoader - OBJ 文件加载器\r\n * 解析 OBJ 文件并生成 LoadedMesh[]\r\n */\r\nexport class OBJLoader {\r\n private device: GPUDevice;\r\n private textureCache: Map<string, GPUTexture> = new Map();\r\n\r\n constructor(device: GPUDevice) {\r\n this.device = device;\r\n }\r\n\r\n /**\r\n * 加载 OBJ 文件\r\n * @param url OBJ 文件 URL\r\n * @returns 加载后的网格数组\r\n * \r\n * Requirements: 2.1, 2.2, 2.3\r\n */\r\n async load(url: string): Promise<LoadedMesh[]> {\r\n // Requirement 2.1: 获取文件内容\r\n const response = await fetch(url);\r\n \r\n // Requirement 2.2: 处理获取失败\r\n if (!response.ok) {\r\n throw new Error(`无法加载 OBJ 文件: ${url} (HTTP ${response.status})`);\r\n }\r\n\r\n const text = await response.text();\r\n \r\n // 计算基础 URL(用于加载 MTL 和纹理)\r\n const baseUrl = url.substring(0, url.lastIndexOf('/') + 1);\r\n \r\n // Requirement 2.3: 解析并返回 LoadedMesh 数组\r\n return this.parseFromText(text, baseUrl);\r\n }\r\n\r\n /**\r\n * 从文本解析 OBJ(用于直接传入内容)\r\n * @param text OBJ 文本内容\r\n * @param baseUrl 基础 URL(用于加载 MTL 和纹理)\r\n * @returns 加载后的网格数组\r\n * \r\n * Requirements: 2.1, 2.3\r\n */\r\n async parseFromText(text: string, baseUrl?: string): Promise<LoadedMesh[]> {\r\n // 解析 OBJ 文本\r\n const parser = new OBJParser();\r\n const parsedData = parser.parse(text);\r\n\r\n // 提取 MTL 文件引用\r\n const mtlFile = this.extractMTLReference(text);\r\n \r\n // 加载材质(如果有)\r\n let materials: Map<string, ParsedMaterial> = new Map();\r\n if (mtlFile && baseUrl) {\r\n materials = await this.loadMTL(baseUrl + mtlFile);\r\n }\r\n\r\n // 转换为 LoadedMesh 数组\r\n return this.createMeshes(parsedData, materials, baseUrl);\r\n }\r\n\r\n /**\r\n * 提取 MTL 文件引用\r\n */\r\n private extractMTLReference(text: string): string | null {\r\n const lines = text.split(/\\r?\\n/);\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n if (trimmed.startsWith('mtllib ')) {\r\n return trimmed.substring(7).trim();\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * 加载 MTL 材质文件\r\n * Requirement 4.1, 4.4: 加载 MTL 文件,失败时使用默认材质\r\n */\r\n private async loadMTL(url: string): Promise<Map<string, ParsedMaterial>> {\r\n try {\r\n const response = await fetch(url);\r\n if (!response.ok) {\r\n return new Map();\r\n }\r\n const text = await response.text();\r\n const mtlParser = new MTLParser();\r\n return mtlParser.parse(text);\r\n } catch (e) {\r\n return new Map();\r\n }\r\n }\r\n\r\n /**\r\n * 创建 LoadedMesh 数组\r\n */\r\n private async createMeshes(\r\n parsedData: ParsedOBJData,\r\n materials: Map<string, ParsedMaterial>,\r\n baseUrl?: string\r\n ): Promise<LoadedMesh[]> {\r\n const loadedMeshes: LoadedMesh[] = [];\r\n\r\n for (const obj of parsedData.objects) {\r\n // 跳过空对象\r\n if (obj.indices.length === 0) {\r\n continue;\r\n }\r\n\r\n const loadedMesh = await this.createMesh(obj, materials, baseUrl);\r\n if (loadedMesh) {\r\n loadedMeshes.push(loadedMesh);\r\n }\r\n }\r\n\r\n return loadedMeshes;\r\n }\r\n\r\n /**\r\n * 创建单个 Mesh\r\n */\r\n private async createMesh(\r\n obj: ParsedObject,\r\n materials: Map<string, ParsedMaterial>,\r\n baseUrl?: string\r\n ): Promise<LoadedMesh | null> {\r\n const hasNormals = obj.normals.length > 0;\r\n const hasUVs = obj.uvs.length > 0;\r\n const vertexCount = obj.positions.length / 3;\r\n\r\n // 如果没有法线,生成平面法线\r\n let normals = obj.normals;\r\n if (!hasNormals) {\r\n normals = this.generateFlatNormals(obj.positions, obj.indices);\r\n }\r\n\r\n // 创建交错顶点数据: position(3) + normal(3) + uv(2)\r\n const stride = hasUVs ? 8 : 6; // floats per vertex\r\n const vertexData = new Float32Array(vertexCount * stride);\r\n\r\n for (let i = 0; i < vertexCount; i++) {\r\n const baseIdx = i * stride;\r\n // Position\r\n vertexData[baseIdx + 0] = obj.positions[i * 3 + 0];\r\n vertexData[baseIdx + 1] = obj.positions[i * 3 + 1];\r\n vertexData[baseIdx + 2] = obj.positions[i * 3 + 2];\r\n // Normal\r\n vertexData[baseIdx + 3] = normals[i * 3 + 0];\r\n vertexData[baseIdx + 4] = normals[i * 3 + 1];\r\n vertexData[baseIdx + 5] = normals[i * 3 + 2];\r\n // UV (if present)\r\n if (hasUVs) {\r\n vertexData[baseIdx + 6] = obj.uvs[i * 2 + 0];\r\n vertexData[baseIdx + 7] = obj.uvs[i * 2 + 1];\r\n }\r\n }\r\n\r\n // 创建顶点缓冲区\r\n const vertexBuffer = this.device.createBuffer({\r\n size: vertexData.byteLength,\r\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\r\n });\r\n this.device.queue.writeBuffer(vertexBuffer, 0, vertexData);\r\n\r\n // 创建索引缓冲区\r\n // Requirement 3.4: 根据顶点数选择索引格式\r\n const indexCount = obj.indices.length;\r\n let indexBuffer: GPUBuffer;\r\n let indexFormat: 'uint16' | 'uint32' = 'uint16';\r\n\r\n if (vertexCount > 65535) {\r\n indexFormat = 'uint32';\r\n const indexData = new Uint32Array(obj.indices);\r\n indexBuffer = this.device.createBuffer({\r\n size: indexData.byteLength,\r\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\r\n });\r\n this.device.queue.writeBuffer(indexBuffer, 0, indexData);\r\n } else {\r\n const indexData = new Uint16Array(obj.indices);\r\n indexBuffer = this.device.createBuffer({\r\n size: indexData.byteLength,\r\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\r\n });\r\n this.device.queue.writeBuffer(indexBuffer, 0, indexData);\r\n }\r\n\r\n // Requirement 3.5: 计算 bounding box\r\n const boundingBox = this.computeBoundingBoxFromPositions(obj.positions);\r\n\r\n // 创建 Mesh\r\n const mesh = new Mesh(vertexBuffer, vertexCount, indexBuffer, indexCount, boundingBox);\r\n mesh.hasUV = hasUVs;\r\n mesh.indexFormat = indexFormat;\r\n\r\n // 创建材质\r\n const material = await this.createMaterial(obj.materialName, materials, baseUrl);\r\n\r\n return { mesh, material };\r\n }\r\n\r\n /**\r\n * 生成平面法线(当 OBJ 缺少法线数据时)\r\n * Requirement 3.2: 从面几何计算平面法线\r\n */\r\n private generateFlatNormals(positions: number[], indices: number[]): number[] {\r\n const normals = new Array(positions.length).fill(0);\r\n\r\n // 遍历每个三角形\r\n for (let i = 0; i < indices.length; i += 3) {\r\n const i0 = indices[i];\r\n const i1 = indices[i + 1];\r\n const i2 = indices[i + 2];\r\n\r\n // 获取三角形顶点\r\n const v0 = [positions[i0 * 3], positions[i0 * 3 + 1], positions[i0 * 3 + 2]];\r\n const v1 = [positions[i1 * 3], positions[i1 * 3 + 1], positions[i1 * 3 + 2]];\r\n const v2 = [positions[i2 * 3], positions[i2 * 3 + 1], positions[i2 * 3 + 2]];\r\n\r\n // 计算边向量\r\n const edge1 = [v1[0] - v0[0], v1[1] - v0[1], v1[2] - v0[2]];\r\n const edge2 = [v2[0] - v0[0], v2[1] - v0[1], v2[2] - v0[2]];\r\n\r\n // 计算叉积(面法线)\r\n const nx = edge1[1] * edge2[2] - edge1[2] * edge2[1];\r\n const ny = edge1[2] * edge2[0] - edge1[0] * edge2[2];\r\n const nz = edge1[0] * edge2[1] - edge1[1] * edge2[0];\r\n\r\n // 归一化\r\n const len = Math.sqrt(nx * nx + ny * ny + nz * nz);\r\n const normalizedNx = len > 0 ? nx / len : 0;\r\n const normalizedNy = len > 0 ? ny / len : 1;\r\n const normalizedNz = len > 0 ? nz / len : 0;\r\n\r\n // 为三角形的每个顶点设置相同的法线(平面着色)\r\n for (const idx of [i0, i1, i2]) {\r\n normals[idx * 3 + 0] = normalizedNx;\r\n normals[idx * 3 + 1] = normalizedNy;\r\n normals[idx * 3 + 2] = normalizedNz;\r\n }\r\n }\r\n\r\n return normals;\r\n }\r\n\r\n /**\r\n * 计算顶点数据的 bounding box\r\n * Requirement 3.5: 计算并存储 bounding box 信息\r\n */\r\n private computeBoundingBoxFromPositions(positions: number[]): MeshBoundingBox {\r\n return computeBoundingBox(positions);\r\n }\r\n\r\n /**\r\n * 创建材质数据\r\n * Requirement 4.3: 将材质关联到网格\r\n */\r\n private async createMaterial(\r\n materialName: string | null,\r\n materials: Map<string, ParsedMaterial>,\r\n baseUrl?: string\r\n ): Promise<MaterialData> {\r\n if (!materialName || !materials.has(materialName)) {\r\n return { ...DEFAULT_OBJ_MATERIAL };\r\n }\r\n\r\n const parsedMaterial = materials.get(materialName)!;\r\n \r\n // 转换为 MaterialData - OBJ 模型默认双面渲染\r\n const material: MaterialData = {\r\n baseColorFactor: [\r\n parsedMaterial.diffuseColor[0],\r\n parsedMaterial.diffuseColor[1],\r\n parsedMaterial.diffuseColor[2],\r\n parsedMaterial.opacity,\r\n ],\r\n baseColorTexture: null,\r\n metallicFactor: 0,\r\n roughnessFactor: 0.5,\r\n doubleSided: true,\r\n };\r\n\r\n // 加载漫反射纹理\r\n if (parsedMaterial.diffuseTexture && baseUrl) {\r\n material.baseColorTexture = await this.loadTexture(baseUrl + parsedMaterial.diffuseTexture);\r\n }\r\n\r\n return material;\r\n }\r\n\r\n /**\r\n * 加载纹理\r\n * Requirement 4.5, 6.3: 加载纹理,失败时使用 null\r\n */\r\n private async loadTexture(url: string): Promise<GPUTexture | null> {\r\n // 检查缓存\r\n if (this.textureCache.has(url)) {\r\n return this.textureCache.get(url)!;\r\n }\r\n\r\n try {\r\n const response = await fetch(url);\r\n if (!response.ok) {\r\n return null;\r\n }\r\n\r\n const blob = await response.blob();\r\n const imageBitmap = await createImageBitmap(blob);\r\n\r\n // 创建 GPU 纹理\r\n const gpuTexture = this.device.createTexture({\r\n size: [imageBitmap.width, imageBitmap.height, 1],\r\n format: 'rgba8unorm',\r\n usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,\r\n });\r\n\r\n this.device.queue.copyExternalImageToTexture(\r\n { source: imageBitmap },\r\n { texture: gpuTexture },\r\n [imageBitmap.width, imageBitmap.height]\r\n );\r\n\r\n // 缓存纹理\r\n this.textureCache.set(url, gpuTexture);\r\n\r\n return gpuTexture;\r\n } catch (error) {\r\n return null;\r\n }\r\n }\r\n}\r\n","/**\r\n * PLYLoader - 加载 3D Gaussian Splatting 的 PLY 文件\r\n * 支持 binary_little_endian 和 binary_big_endian 格式\r\n * 支持多种数据类型: float, double, int, uint, char, uchar, short, ushort\r\n */\r\n\r\n/**\r\n * CPU 端 Splat 数据结构\r\n */\r\nexport type SplatCPU = {\r\n mean: [number, number, number];\r\n scale: [number, number, number];\r\n rotation: [number, number, number, number]; // 四元数顺序: [w, x, y, z]\r\n colorDC: [number, number, number];\r\n opacity: number;\r\n shRest?: Float32Array; // 完整 SH 系数: L1(9) + L2(15) + L3(21) = 45\r\n};\r\n\r\n/**\r\n * PLY 数据类型到字节大小的映射\r\n */\r\nconst TYPE_SIZES: Record<string, number> = {\r\n char: 1,\r\n uchar: 1,\r\n int8: 1,\r\n uint8: 1,\r\n short: 2,\r\n ushort: 2,\r\n int16: 2,\r\n uint16: 2,\r\n int: 4,\r\n uint: 4,\r\n int32: 4,\r\n uint32: 4,\r\n float: 4,\r\n float32: 4,\r\n double: 8,\r\n float64: 8,\r\n};\r\n\r\n/**\r\n * PLY 文件格式类型\r\n */\r\ntype PLYFormat = \"binary_little_endian\" | \"binary_big_endian\" | \"ascii\";\r\n\r\n/**\r\n * PLY 属性信息\r\n */\r\ntype PropertyInfo = {\r\n name: string;\r\n type: string;\r\n byteOffset: number;\r\n byteSize: number;\r\n};\r\n\r\n/**\r\n * 解析 PLY header\r\n */\r\nfunction parseHeader(headerText: string): {\r\n vertexCount: number;\r\n properties: PropertyInfo[];\r\n stride: number;\r\n format: PLYFormat;\r\n} {\r\n const lines = headerText.split(\"\\n\");\r\n let vertexCount = 0;\r\n let format: PLYFormat = \"binary_little_endian\";\r\n const properties: PropertyInfo[] = [];\r\n let currentOffset = 0;\r\n let inVertexElement = false;\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n\r\n // 解析格式\r\n if (trimmed.startsWith(\"format \")) {\r\n const parts = trimmed.split(/\\s+/);\r\n const formatStr = parts[1];\r\n if (formatStr === \"ascii\") {\r\n format = \"ascii\";\r\n } else if (formatStr === \"binary_big_endian\") {\r\n format = \"binary_big_endian\";\r\n } else if (formatStr === \"binary_little_endian\") {\r\n format = \"binary_little_endian\";\r\n } else {\r\n throw new Error(`不支持的 PLY 格式: ${formatStr}`);\r\n }\r\n }\r\n\r\n // 解析 element vertex N\r\n if (trimmed.startsWith(\"element vertex\")) {\r\n const parts = trimmed.split(/\\s+/);\r\n vertexCount = parseInt(parts[2], 10);\r\n inVertexElement = true;\r\n } else if (trimmed.startsWith(\"element \")) {\r\n // 其他 element 类型,停止收集属性\r\n inVertexElement = false;\r\n }\r\n\r\n // 解析 property <type> <name>(只收集 vertex element 的属性)\r\n if (inVertexElement && trimmed.startsWith(\"property\")) {\r\n const parts = trimmed.split(/\\s+/);\r\n // 跳过 list 类型属性\r\n if (parts[1] === \"list\") {\r\n continue;\r\n }\r\n const type = parts[1];\r\n const name = parts[2];\r\n const byteSize = TYPE_SIZES[type];\r\n\r\n if (byteSize === undefined) {\r\n throw new Error(`不支持的 PLY 属性类型: ${type}`);\r\n }\r\n\r\n properties.push({\r\n name,\r\n type,\r\n byteOffset: currentOffset,\r\n byteSize,\r\n });\r\n\r\n currentOffset += byteSize;\r\n }\r\n }\r\n\r\n return {\r\n vertexCount,\r\n properties,\r\n stride: currentOffset,\r\n format,\r\n };\r\n}\r\n\r\n/**\r\n * 验证 PLY 文件魔数\r\n */\r\nfunction validatePLYMagic(buffer: ArrayBuffer): void {\r\n const bytes = new Uint8Array(buffer, 0, Math.min(buffer.byteLength, 10));\r\n const decoder = new TextDecoder(\"ascii\");\r\n const header = decoder.decode(bytes);\r\n\r\n if (!header.startsWith(\"ply\")) {\r\n throw new Error(\"无效的 PLY 文件: 缺少 'ply' 魔数标识\");\r\n }\r\n}\r\n\r\n/**\r\n * 从 ArrayBuffer 中提取 header 文本和数据起始位置\r\n */\r\nfunction extractHeader(buffer: ArrayBuffer): {\r\n headerText: string;\r\n dataOffset: number;\r\n} {\r\n // 首先验证魔数\r\n validatePLYMagic(buffer);\r\n\r\n const bytes = new Uint8Array(buffer);\r\n const decoder = new TextDecoder(\"ascii\");\r\n\r\n // 查找 \"end_header\\n\" 或 \"end_header\\r\\n\" 标记\r\n const maxHeaderSize = Math.min(bytes.length, 10000); // header 不应超过 10KB\r\n const headerBytes = bytes.slice(0, maxHeaderSize);\r\n const headerText = decoder.decode(headerBytes);\r\n\r\n // 支持 Unix (\\n) 和 Windows (\\r\\n) 换行符\r\n let endIndex = headerText.indexOf(\"end_header\\n\");\r\n let markerLength = \"end_header\\n\".length;\r\n\r\n if (endIndex === -1) {\r\n endIndex = headerText.indexOf(\"end_header\\r\\n\");\r\n markerLength = \"end_header\\r\\n\".length;\r\n }\r\n\r\n if (endIndex === -1) {\r\n throw new Error(\"无法找到 PLY header 结束标记 'end_header'\");\r\n }\r\n\r\n const dataOffset = endIndex + markerLength;\r\n return {\r\n headerText: headerText.substring(0, endIndex),\r\n dataOffset,\r\n };\r\n}\r\n\r\n/**\r\n * 构建属性名到属性信息的映射\r\n */\r\nfunction buildPropertyMap(\r\n properties: PropertyInfo[]\r\n): Map<string, PropertyInfo> {\r\n const map = new Map<string, PropertyInfo>();\r\n for (const prop of properties) {\r\n map.set(prop.name, prop);\r\n }\r\n return map;\r\n}\r\n\r\n/**\r\n * 从 DataView 读取属性值(支持多种数据类型)\r\n */\r\nfunction readProperty(\r\n dataView: DataView,\r\n baseOffset: number,\r\n prop: PropertyInfo | undefined,\r\n littleEndian: boolean\r\n): number {\r\n if (prop === undefined) {\r\n return 0;\r\n }\r\n\r\n const offset = baseOffset + prop.byteOffset;\r\n\r\n switch (prop.type) {\r\n case \"float\":\r\n case \"float32\":\r\n return dataView.getFloat32(offset, littleEndian);\r\n case \"double\":\r\n case \"float64\":\r\n return dataView.getFloat64(offset, littleEndian);\r\n case \"int\":\r\n case \"int32\":\r\n return dataView.getInt32(offset, littleEndian);\r\n case \"uint\":\r\n case \"uint32\":\r\n return dataView.getUint32(offset, littleEndian);\r\n case \"short\":\r\n case \"int16\":\r\n return dataView.getInt16(offset, littleEndian);\r\n case \"ushort\":\r\n case \"uint16\":\r\n return dataView.getUint16(offset, littleEndian);\r\n case \"char\":\r\n case \"int8\":\r\n return dataView.getInt8(offset);\r\n case \"uchar\":\r\n case \"uint8\":\r\n return dataView.getUint8(offset);\r\n default:\r\n return dataView.getFloat32(offset, littleEndian);\r\n }\r\n}\r\n\r\n/**\r\n * Sigmoid 函数,用于将 opacity 从原始值转换为 [0, 1]\r\n */\r\nfunction sigmoid(x: number): number {\r\n return 1 / (1 + Math.exp(-x));\r\n}\r\n\r\n/**\r\n * 加载并解析 PLY 文件\r\n * @param url PLY 文件的 URL\r\n * @returns SplatCPU 数组\r\n */\r\nexport async function loadPLY(url: string): Promise<SplatCPU[]> {\r\n // 获取文件\r\n const response = await fetch(url);\r\n if (!response.ok) {\r\n throw new Error(`无法加载 PLY 文件: ${url}`);\r\n }\r\n const buffer = await response.arrayBuffer();\r\n\r\n // 解析 header\r\n const { headerText, dataOffset } = extractHeader(buffer);\r\n const { vertexCount, properties, stride, format } = parseHeader(headerText);\r\n\r\n // 验证格式\r\n if (format === \"ascii\") {\r\n throw new Error(\"不支持 ASCII 格式的 PLY 文件,请使用 binary_little_endian 或 binary_big_endian 格式\");\r\n }\r\n\r\n const littleEndian = format === \"binary_little_endian\";\r\n\r\n // 构建属性映射\r\n const propMap = buildPropertyMap(properties);\r\n\r\n // 获取各属性的信息\r\n const props = {\r\n x: propMap.get(\"x\"),\r\n y: propMap.get(\"y\"),\r\n z: propMap.get(\"z\"),\r\n scale_0: propMap.get(\"scale_0\"),\r\n scale_1: propMap.get(\"scale_1\"),\r\n scale_2: propMap.get(\"scale_2\"),\r\n rot_0: propMap.get(\"rot_0\"),\r\n rot_1: propMap.get(\"rot_1\"),\r\n rot_2: propMap.get(\"rot_2\"),\r\n rot_3: propMap.get(\"rot_3\"),\r\n f_dc_0: propMap.get(\"f_dc_0\"),\r\n f_dc_1: propMap.get(\"f_dc_1\"),\r\n f_dc_2: propMap.get(\"f_dc_2\"),\r\n opacity: propMap.get(\"opacity\"),\r\n };\r\n\r\n // 收集 f_rest_* 字段并按索引排序(用于 SH 系数)\r\n const shRestProps = properties\r\n .filter((p) => p.name.startsWith(\"f_rest_\"))\r\n .sort((a, b) => {\r\n const idxA = parseInt(a.name.replace(\"f_rest_\", \"\"), 10);\r\n const idxB = parseInt(b.name.replace(\"f_rest_\", \"\"), 10);\r\n return idxA - idxB;\r\n });\r\n\r\n // 打印前几个 f_rest_* 属性的名称,验证排序是否正确\r\n if (shRestProps.length > 0) {\r\n // 属性顺序验证(静默)\r\n }\r\n\r\n // 创建 DataView 用于读取二进制数据\r\n const dataView = new DataView(buffer, dataOffset);\r\n\r\n // 预分配共享的 SH 系数数组(优化内存)\r\n const shRestBuffer = new Float32Array(vertexCount * 45);\r\n\r\n // 解析每个 vertex\r\n const splats: SplatCPU[] = new Array(vertexCount);\r\n const SH_C0 = 0.28209479177387814;\r\n\r\n for (let i = 0; i < vertexCount; i++) {\r\n const base = i * stride;\r\n\r\n // 读取位置\r\n const x = readProperty(dataView, base, props.x, littleEndian);\r\n const y = readProperty(dataView, base, props.y, littleEndian);\r\n const z = readProperty(dataView, base, props.z, littleEndian);\r\n\r\n // 读取缩放 (exp 转换,因为 3DGS 存储的是 log scale)\r\n const scale_0 = Math.exp(readProperty(dataView, base, props.scale_0, littleEndian));\r\n const scale_1 = Math.exp(readProperty(dataView, base, props.scale_1, littleEndian));\r\n const scale_2 = Math.exp(readProperty(dataView, base, props.scale_2, littleEndian));\r\n\r\n // 读取旋转四元数\r\n const rot_0 = readProperty(dataView, base, props.rot_0, littleEndian);\r\n const rot_1 = readProperty(dataView, base, props.rot_1, littleEndian);\r\n const rot_2 = readProperty(dataView, base, props.rot_2, littleEndian);\r\n const rot_3 = readProperty(dataView, base, props.rot_3, littleEndian);\r\n\r\n // 归一化四元数\r\n const qlen = Math.sqrt(\r\n rot_0 * rot_0 + rot_1 * rot_1 + rot_2 * rot_2 + rot_3 * rot_3\r\n );\r\n const qnorm = qlen > 0 ? 1 / qlen : 1;\r\n\r\n // 读取颜色 DC 系数 (SH0)\r\n // 注意:不要在这里 clamp,因为 SH 贡献可能是负数\r\n // 最终颜色会在 shader 中 clamp\r\n const f_dc_0 = readProperty(dataView, base, props.f_dc_0, littleEndian);\r\n const f_dc_1 = readProperty(dataView, base, props.f_dc_1, littleEndian);\r\n const f_dc_2 = readProperty(dataView, base, props.f_dc_2, littleEndian);\r\n\r\n const colorR = 0.5 + SH_C0 * f_dc_0;\r\n const colorG = 0.5 + SH_C0 * f_dc_1;\r\n const colorB = 0.5 + SH_C0 * f_dc_2;\r\n\r\n // 读取 opacity (sigmoid 转换)\r\n const rawOpacity = readProperty(dataView, base, props.opacity, littleEndian);\r\n const opacity = sigmoid(rawOpacity);\r\n\r\n // 读取完整 SH 系数到共享 buffer\r\n const shOffset = i * 45;\r\n const shRest = shRestBuffer.subarray(shOffset, shOffset + 45);\r\n\r\n // PLY 文件中 f_rest_* 的顺序是 channel-first (参考 visionary):\r\n // [R0..R14, G0..G14, B0..B14] - 每通道 15 个系数\r\n // \r\n // 我们转换为 interleaved 格式 (与 visionary 一致):\r\n // [R0,G0,B0, R1,G1,B1, ...] - 每个基函数的 RGB 连续存储\r\n //\r\n // 这样 shader 中可以用 sh_coef(idx) 返回 vec3(R,G,B)\r\n //\r\n // 注意:shRestProps 的数量可能是 45 (完整 SH) 或更少\r\n // 实际 PLY 文件的 f_rest_* 数量 = (shDegree+1)^2 - 1 个系数 × 3 通道\r\n // 例如 shDegree=3 时: (3+1)^2 - 1 = 15 个系数/通道,共 45 个 f_rest_*\r\n\r\n const totalRestCount = shRestProps.length;\r\n const perChannel = Math.floor(totalRestCount / 3); // 每通道的系数数量\r\n \r\n for (let coefIdx = 0; coefIdx < perChannel; coefIdx++) {\r\n // PLY 中: R 在 [0..perChannel-1], G 在 [perChannel..2*perChannel-1], B 在 [2*perChannel..3*perChannel-1]\r\n const srcR = coefIdx;\r\n const srcG = perChannel + coefIdx;\r\n const srcB = 2 * perChannel + coefIdx;\r\n \r\n // 目标: interleaved [R0,G0,B0, R1,G1,B1, ...]\r\n const dstBase = coefIdx * 3;\r\n \r\n shRest[dstBase + 0] = srcR < shRestProps.length ? readProperty(dataView, base, shRestProps[srcR], littleEndian) : 0;\r\n shRest[dstBase + 1] = srcG < shRestProps.length ? readProperty(dataView, base, shRestProps[srcG], littleEndian) : 0;\r\n shRest[dstBase + 2] = srcB < shRestProps.length ? readProperty(dataView, base, shRestProps[srcB], littleEndian) : 0;\r\n }\r\n\r\n // 打印第一个点的 SH 系数用于调试\r\n if (i === 0) {\r\n // 调试信息(静默)\r\n }\r\n\r\n splats[i] = {\r\n mean: [x, y, z],\r\n scale: [scale_0, scale_1, scale_2],\r\n rotation: [\r\n rot_0 * qnorm,\r\n rot_1 * qnorm,\r\n rot_2 * qnorm,\r\n rot_3 * qnorm,\r\n ],\r\n colorDC: [colorR, colorG, colorB],\r\n opacity,\r\n shRest,\r\n };\r\n }\r\n\r\n return splats;\r\n}\r\n","/**\r\n * PLYLoaderMobile - 移动端优化的 PLY 加载器\r\n * \r\n * 优化点:\r\n * 1. 直接输出 GPU buffer 格式,避免中间对象\r\n * 2. 流式降采样,减少内存峰值\r\n * 3. 可选跳过 SH 系数(移动端 L0 模式)\r\n * 4. 使用 TypedArray 而非对象数组\r\n * 5. 支持多种 PLY 数据类型\r\n * 6. 确定性采样(基于文件内容的种子)\r\n */\r\n\r\n/**\r\n * PLY 数据类型到字节大小的映射\r\n */\r\nconst TYPE_SIZES: Record<string, number> = {\r\n char: 1,\r\n uchar: 1,\r\n int8: 1,\r\n uint8: 1,\r\n short: 2,\r\n ushort: 2,\r\n int16: 2,\r\n uint16: 2,\r\n int: 4,\r\n uint: 4,\r\n int32: 4,\r\n uint32: 4,\r\n float: 4,\r\n float32: 4,\r\n double: 8,\r\n float64: 8,\r\n};\r\n\r\n/**\r\n * PLY 文件格式类型\r\n */\r\ntype PLYFormat = \"binary_little_endian\" | \"binary_big_endian\" | \"ascii\";\r\n\r\n/**\r\n * 移动端加载配置\r\n */\r\nexport interface MobileLoadOptions {\r\n /** 最大 splat 数量,超过则降采样 */\r\n maxSplats?: number;\r\n /** 是否加载 SH 系数(false 时只加载 DC 颜色) */\r\n loadSH?: boolean;\r\n /** 进度回调 */\r\n onProgress?: (loaded: number, total: number) => void;\r\n /** 随机种子(用于确定性采样,默认使用文件大小作为种子) */\r\n seed?: number;\r\n}\r\n\r\n/**\r\n * 紧凑 Splat 数据(用于移动端)\r\n * 直接返回 Float32Array,而非对象数组\r\n */\r\nexport interface CompactSplatData {\r\n /** splat 数量 */\r\n count: number;\r\n /** 位置数据 Float32Array [x,y,z, x,y,z, ...] */\r\n positions: Float32Array;\r\n /** 缩放数据 Float32Array [sx,sy,sz, sx,sy,sz, ...] */\r\n scales: Float32Array;\r\n /** 旋转四元数 Float32Array [w,x,y,z, w,x,y,z, ...] */\r\n rotations: Float32Array;\r\n /** DC 颜色 Float32Array [r,g,b, r,g,b, ...] */\r\n colors: Float32Array;\r\n /** 不透明度 Float32Array [a, a, ...] */\r\n opacities: Float32Array;\r\n /** SH 系数(可选)Float32Array,每个 splat 45 个系数 */\r\n shCoeffs?: Float32Array;\r\n}\r\n\r\n/**\r\n * PLY 属性信息\r\n */\r\ninterface PropertyInfo {\r\n name: string;\r\n type: string;\r\n byteOffset: number;\r\n byteSize: number;\r\n}\r\n\r\n/**\r\n * 验证 PLY 文件魔数\r\n */\r\nfunction validatePLYMagic(buffer: ArrayBuffer): void {\r\n const bytes = new Uint8Array(buffer, 0, Math.min(buffer.byteLength, 10));\r\n const decoder = new TextDecoder(\"ascii\");\r\n const header = decoder.decode(bytes);\r\n\r\n if (!header.startsWith(\"ply\")) {\r\n throw new Error(\"无效的 PLY 文件: 缺少 'ply' 魔数标识\");\r\n }\r\n}\r\n\r\n/**\r\n * 解析 PLY header\r\n */\r\nfunction parseHeader(headerText: string): {\r\n vertexCount: number;\r\n properties: PropertyInfo[];\r\n stride: number;\r\n format: PLYFormat;\r\n} {\r\n const lines = headerText.split(\"\\n\");\r\n let vertexCount = 0;\r\n let format: PLYFormat = \"binary_little_endian\";\r\n const properties: PropertyInfo[] = [];\r\n let currentOffset = 0;\r\n let inVertexElement = false;\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n\r\n // 解析格式\r\n if (trimmed.startsWith(\"format \")) {\r\n const parts = trimmed.split(/\\s+/);\r\n const formatStr = parts[1];\r\n if (formatStr === \"ascii\") {\r\n format = \"ascii\";\r\n } else if (formatStr === \"binary_big_endian\") {\r\n format = \"binary_big_endian\";\r\n } else if (formatStr === \"binary_little_endian\") {\r\n format = \"binary_little_endian\";\r\n } else {\r\n throw new Error(`不支持的 PLY 格式: ${formatStr}`);\r\n }\r\n }\r\n\r\n // 解析 element vertex N\r\n if (trimmed.startsWith(\"element vertex\")) {\r\n const parts = trimmed.split(/\\s+/);\r\n vertexCount = parseInt(parts[2], 10);\r\n inVertexElement = true;\r\n } else if (trimmed.startsWith(\"element \")) {\r\n inVertexElement = false;\r\n }\r\n\r\n // 解析 property(只收集 vertex element 的属性)\r\n if (inVertexElement && trimmed.startsWith(\"property\")) {\r\n const parts = trimmed.split(/\\s+/);\r\n if (parts[1] === \"list\") {\r\n continue;\r\n }\r\n const type = parts[1];\r\n const name = parts[2];\r\n const byteSize = TYPE_SIZES[type];\r\n\r\n if (byteSize === undefined) {\r\n throw new Error(`不支持的 PLY 属性类型: ${type}`);\r\n }\r\n\r\n properties.push({\r\n name,\r\n type,\r\n byteOffset: currentOffset,\r\n byteSize,\r\n });\r\n\r\n currentOffset += byteSize;\r\n }\r\n }\r\n\r\n return { vertexCount, properties, stride: currentOffset, format };\r\n}\r\n\r\n/**\r\n * 提取 header\r\n */\r\nfunction extractHeader(buffer: ArrayBuffer): {\r\n headerText: string;\r\n dataOffset: number;\r\n} {\r\n // 首先验证魔数\r\n validatePLYMagic(buffer);\r\n\r\n const bytes = new Uint8Array(buffer);\r\n const decoder = new TextDecoder(\"ascii\");\r\n\r\n const maxHeaderSize = Math.min(bytes.length, 10000);\r\n const headerBytes = bytes.slice(0, maxHeaderSize);\r\n const headerText = decoder.decode(headerBytes);\r\n\r\n // 支持 Unix (\\n) 和 Windows (\\r\\n) 换行符\r\n let endIndex = headerText.indexOf(\"end_header\\n\");\r\n let markerLength = \"end_header\\n\".length;\r\n\r\n if (endIndex === -1) {\r\n endIndex = headerText.indexOf(\"end_header\\r\\n\");\r\n markerLength = \"end_header\\r\\n\".length;\r\n }\r\n\r\n if (endIndex === -1) {\r\n throw new Error(\"无法找到 PLY header 结束标记 'end_header'\");\r\n }\r\n\r\n const dataOffset = endIndex + markerLength;\r\n return {\r\n headerText: headerText.substring(0, endIndex),\r\n dataOffset,\r\n };\r\n}\r\n\r\n/**\r\n * Sigmoid 函数\r\n */\r\nfunction sigmoid(x: number): number {\r\n return 1 / (1 + Math.exp(-x));\r\n}\r\n\r\n/**\r\n * 从 DataView 读取属性值(支持多种数据类型)\r\n */\r\nfunction readProperty(\r\n dataView: DataView,\r\n offset: number,\r\n type: string,\r\n littleEndian: boolean\r\n): number {\r\n switch (type) {\r\n case \"float\":\r\n case \"float32\":\r\n return dataView.getFloat32(offset, littleEndian);\r\n case \"double\":\r\n case \"float64\":\r\n return dataView.getFloat64(offset, littleEndian);\r\n case \"int\":\r\n case \"int32\":\r\n return dataView.getInt32(offset, littleEndian);\r\n case \"uint\":\r\n case \"uint32\":\r\n return dataView.getUint32(offset, littleEndian);\r\n case \"short\":\r\n case \"int16\":\r\n return dataView.getInt16(offset, littleEndian);\r\n case \"ushort\":\r\n case \"uint16\":\r\n return dataView.getUint16(offset, littleEndian);\r\n case \"char\":\r\n case \"int8\":\r\n return dataView.getInt8(offset);\r\n case \"uchar\":\r\n case \"uint8\":\r\n return dataView.getUint8(offset);\r\n default:\r\n return dataView.getFloat32(offset, littleEndian);\r\n }\r\n}\r\n\r\n/**\r\n * 简单的确定性伪随机数生成器 (Mulberry32)\r\n * 给定相同的种子,总是产生相同的序列\r\n */\r\nfunction createSeededRandom(seed: number): () => number {\r\n let state = seed >>> 0;\r\n return () => {\r\n state = (state + 0x6d2b79f5) >>> 0;\r\n let t = state;\r\n t = Math.imul(t ^ (t >>> 15), t | 1);\r\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\r\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\r\n };\r\n}\r\n\r\nconst SH_C0 = 0.28209479177387814;\r\n\r\n/**\r\n * 智能采样:基于重要性(opacity * scale)采样\r\n * 使用 Floyd 采样算法 + 确定性种子,保证相同文件产生相同结果\r\n * 时间复杂度 O(n),空间复杂度 O(k),其中 k 是采样数量\r\n */\r\nfunction computeImportanceSampling(\r\n buffer: ArrayBuffer,\r\n dataOffset: number,\r\n stride: number,\r\n totalCount: number,\r\n sampleCount: number,\r\n opacityOffset: number,\r\n opacityType: string,\r\n scale0Offset: number,\r\n scale0Type: string,\r\n scale1Offset: number,\r\n scale1Type: string,\r\n scale2Offset: number,\r\n scale2Type: string,\r\n littleEndian: boolean,\r\n seed: number\r\n): Uint32Array {\r\n const dataView = new DataView(buffer, dataOffset);\r\n const random = createSeededRandom(seed);\r\n\r\n // 计算每个 splat 的重要性分数\r\n const importance = new Float32Array(totalCount);\r\n let totalImportance = 0;\r\n\r\n for (let i = 0; i < totalCount; i++) {\r\n const base = i * stride;\r\n\r\n // 获取 opacity(需要 sigmoid 转换)\r\n const rawOpacity = opacityOffset >= 0\r\n ? readProperty(dataView, base + opacityOffset, opacityType, littleEndian)\r\n : 0;\r\n const opacity = sigmoid(rawOpacity);\r\n\r\n // 获取 scale(需要 exp 转换)\r\n const s0 = scale0Offset >= 0\r\n ? Math.exp(readProperty(dataView, base + scale0Offset, scale0Type, littleEndian))\r\n : 1;\r\n const s1 = scale1Offset >= 0\r\n ? Math.exp(readProperty(dataView, base + scale1Offset, scale1Type, littleEndian))\r\n : 1;\r\n const s2 = scale2Offset >= 0\r\n ? Math.exp(readProperty(dataView, base + scale2Offset, scale2Type, littleEndian))\r\n : 1;\r\n const maxScale = Math.max(s0, s1, s2);\r\n\r\n // 重要性分数:opacity * scale\r\n importance[i] = opacity * maxScale;\r\n totalImportance += importance[i];\r\n }\r\n\r\n // 使用加权随机采样(Reservoir Sampling with Weights)\r\n // 这是一种 O(n) 的算法,比完整排序更高效\r\n const result = new Uint32Array(sampleCount);\r\n const weights = new Float32Array(sampleCount);\r\n\r\n // 初始化:填充前 sampleCount 个元素\r\n for (let i = 0; i < Math.min(sampleCount, totalCount); i++) {\r\n result[i] = i;\r\n // 使用 -log(random) / weight 作为键值(Efraimidis-Spirakis 算法)\r\n weights[i] = importance[i] > 0 ? -Math.log(random()) / importance[i] : Infinity;\r\n }\r\n\r\n // 构建最小堆(用于维护 top-k)\r\n // 简化实现:直接找最大权重的位置\r\n let maxWeightIdx = 0;\r\n let maxWeight = weights[0];\r\n for (let i = 1; i < sampleCount; i++) {\r\n if (weights[i] > maxWeight) {\r\n maxWeight = weights[i];\r\n maxWeightIdx = i;\r\n }\r\n }\r\n\r\n // 处理剩余元素\r\n for (let i = sampleCount; i < totalCount; i++) {\r\n const key = importance[i] > 0 ? -Math.log(random()) / importance[i] : Infinity;\r\n\r\n // 如果当前元素的键值小于堆中最大的键值,替换它\r\n if (key < maxWeight) {\r\n result[maxWeightIdx] = i;\r\n weights[maxWeightIdx] = key;\r\n\r\n // 重新找最大权重\r\n maxWeight = weights[0];\r\n maxWeightIdx = 0;\r\n for (let j = 1; j < sampleCount; j++) {\r\n if (weights[j] > maxWeight) {\r\n maxWeight = weights[j];\r\n maxWeightIdx = j;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // 按原始顺序排列(保持空间局部性,有利于缓存)\r\n result.sort((a, b) => a - b);\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * 移动端优化的 PLY 加载器\r\n * 直接输出紧凑格式,避免创建大量中间对象\r\n */\r\nexport async function loadPLYMobile(\r\n url: string,\r\n options: MobileLoadOptions = {}\r\n): Promise<CompactSplatData> {\r\n // 获取文件\r\n const response = await fetch(url);\r\n if (!response.ok) {\r\n throw new Error(`无法加载 PLY 文件: ${url}`);\r\n }\r\n const buffer = await response.arrayBuffer();\r\n\r\n return parsePLYBuffer(buffer, options);\r\n}\r\n\r\n/**\r\n * 解析 PLY ArrayBuffer\r\n * 可以直接传入 ArrayBuffer 进行解析,用于本地文件加载\r\n */\r\nexport async function parsePLYBuffer(\r\n buffer: ArrayBuffer,\r\n options: MobileLoadOptions = {}\r\n): Promise<CompactSplatData> {\r\n const {\r\n maxSplats = 200000,\r\n loadSH = false,\r\n onProgress,\r\n } = options;\r\n\r\n // 使用文件大小作为默认种子(确保相同文件产生相同结果)\r\n const seed = options.seed ?? buffer.byteLength;\r\n\r\n // 解析 header\r\n const { headerText, dataOffset } = extractHeader(buffer);\r\n const { vertexCount, properties, stride, format } = parseHeader(headerText);\r\n\r\n // 验证格式\r\n if (format === \"ascii\") {\r\n throw new Error(\"不支持 ASCII 格式的 PLY 文件,请使用 binary_little_endian 或 binary_big_endian 格式\");\r\n }\r\n\r\n const littleEndian = format === \"binary_little_endian\";\r\n\r\n // 构建属性偏移映射\r\n const propMap = new Map<string, PropertyInfo>();\r\n for (const prop of properties) {\r\n propMap.set(prop.name, prop);\r\n }\r\n\r\n // 获取基本属性信息\r\n const getProp = (name: string) => propMap.get(name);\r\n const getOffset = (name: string) => propMap.get(name)?.byteOffset ?? -1;\r\n const getType = (name: string) => propMap.get(name)?.type ?? \"float\";\r\n\r\n const offsets = {\r\n x: getOffset(\"x\"),\r\n y: getOffset(\"y\"),\r\n z: getOffset(\"z\"),\r\n scale_0: getOffset(\"scale_0\"),\r\n scale_1: getOffset(\"scale_1\"),\r\n scale_2: getOffset(\"scale_2\"),\r\n rot_0: getOffset(\"rot_0\"),\r\n rot_1: getOffset(\"rot_1\"),\r\n rot_2: getOffset(\"rot_2\"),\r\n rot_3: getOffset(\"rot_3\"),\r\n f_dc_0: getOffset(\"f_dc_0\"),\r\n f_dc_1: getOffset(\"f_dc_1\"),\r\n f_dc_2: getOffset(\"f_dc_2\"),\r\n opacity: getOffset(\"opacity\"),\r\n };\r\n\r\n const types = {\r\n x: getType(\"x\"),\r\n y: getType(\"y\"),\r\n z: getType(\"z\"),\r\n scale_0: getType(\"scale_0\"),\r\n scale_1: getType(\"scale_1\"),\r\n scale_2: getType(\"scale_2\"),\r\n rot_0: getType(\"rot_0\"),\r\n rot_1: getType(\"rot_1\"),\r\n rot_2: getType(\"rot_2\"),\r\n rot_3: getType(\"rot_3\"),\r\n f_dc_0: getType(\"f_dc_0\"),\r\n f_dc_1: getType(\"f_dc_1\"),\r\n f_dc_2: getType(\"f_dc_2\"),\r\n opacity: getType(\"opacity\"),\r\n };\r\n\r\n // SH 系数属性(可选)\r\n let shProps: PropertyInfo[] = [];\r\n if (loadSH) {\r\n shProps = properties\r\n .filter((p) => p.name.startsWith(\"f_rest_\"))\r\n .sort((a, b) => {\r\n const idxA = parseInt(a.name.replace(\"f_rest_\", \"\"), 10);\r\n const idxB = parseInt(b.name.replace(\"f_rest_\", \"\"), 10);\r\n return idxA - idxB;\r\n });\r\n }\r\n\r\n // 计算实际加载数量\r\n const needSample = vertexCount > maxSplats;\r\n const actualCount = Math.min(vertexCount, maxSplats);\r\n \r\n // 估算内存使用(纹理压缩模式约 52 bytes/splat)\r\n const estimatedMemoryMB = (actualCount * 52) / (1024 * 1024);\r\n \r\n if (estimatedMemoryMB > 300) {\r\n // 高内存警告(静默处理)\r\n }\r\n \r\n // 如果需要降采样,使用智能采样(基于重要性,确定性种子)\r\n let sampleIndices: Uint32Array | null = null;\r\n if (needSample) {\r\n sampleIndices = computeImportanceSampling(\r\n buffer, dataOffset, stride, vertexCount, actualCount,\r\n offsets.opacity, types.opacity,\r\n offsets.scale_0, types.scale_0,\r\n offsets.scale_1, types.scale_1,\r\n offsets.scale_2, types.scale_2,\r\n littleEndian, seed\r\n );\r\n }\r\n\r\n // 预分配输出数组(一次性分配,避免多次扩容)\r\n const positions = new Float32Array(actualCount * 3);\r\n const scales = new Float32Array(actualCount * 3);\r\n const rotations = new Float32Array(actualCount * 4);\r\n const colors = new Float32Array(actualCount * 3);\r\n const opacities = new Float32Array(actualCount);\r\n const shCoeffs = loadSH ? new Float32Array(actualCount * 45) : undefined;\r\n\r\n // 创建 DataView\r\n const dataView = new DataView(buffer, dataOffset);\r\n\r\n // 流式解析\r\n let outputIdx = 0;\r\n let lastProgress = 0;\r\n\r\n for (let i = 0; i < actualCount; i++) {\r\n // 计算源索引:使用智能采样或直接索引\r\n const srcIdx = sampleIndices ? sampleIndices[i] : i;\r\n const base = srcIdx * stride;\r\n\r\n // 位置\r\n positions[outputIdx * 3 + 0] = offsets.x >= 0 ? readProperty(dataView, base + offsets.x, types.x, littleEndian) : 0;\r\n positions[outputIdx * 3 + 1] = offsets.y >= 0 ? readProperty(dataView, base + offsets.y, types.y, littleEndian) : 0;\r\n positions[outputIdx * 3 + 2] = offsets.z >= 0 ? readProperty(dataView, base + offsets.z, types.z, littleEndian) : 0;\r\n\r\n // 缩放(exp 转换)\r\n scales[outputIdx * 3 + 0] = offsets.scale_0 >= 0 ? Math.exp(readProperty(dataView, base + offsets.scale_0, types.scale_0, littleEndian)) : 1;\r\n scales[outputIdx * 3 + 1] = offsets.scale_1 >= 0 ? Math.exp(readProperty(dataView, base + offsets.scale_1, types.scale_1, littleEndian)) : 1;\r\n scales[outputIdx * 3 + 2] = offsets.scale_2 >= 0 ? Math.exp(readProperty(dataView, base + offsets.scale_2, types.scale_2, littleEndian)) : 1;\r\n\r\n // 旋转四元数(归一化)\r\n const rot_0 = offsets.rot_0 >= 0 ? readProperty(dataView, base + offsets.rot_0, types.rot_0, littleEndian) : 1;\r\n const rot_1 = offsets.rot_1 >= 0 ? readProperty(dataView, base + offsets.rot_1, types.rot_1, littleEndian) : 0;\r\n const rot_2 = offsets.rot_2 >= 0 ? readProperty(dataView, base + offsets.rot_2, types.rot_2, littleEndian) : 0;\r\n const rot_3 = offsets.rot_3 >= 0 ? readProperty(dataView, base + offsets.rot_3, types.rot_3, littleEndian) : 0;\r\n const qlen = Math.sqrt(rot_0 * rot_0 + rot_1 * rot_1 + rot_2 * rot_2 + rot_3 * rot_3);\r\n const qnorm = qlen > 0 ? 1 / qlen : 1;\r\n rotations[outputIdx * 4 + 0] = rot_0 * qnorm;\r\n rotations[outputIdx * 4 + 1] = rot_1 * qnorm;\r\n rotations[outputIdx * 4 + 2] = rot_2 * qnorm;\r\n rotations[outputIdx * 4 + 3] = rot_3 * qnorm;\r\n\r\n // DC 颜色(SH0 -> RGB)\r\n // 注意:不要在这里 clamp,因为 SH 贡献可能是负数\r\n // 最终颜色会在 shader 中 clamp\r\n const f_dc_0 = offsets.f_dc_0 >= 0 ? readProperty(dataView, base + offsets.f_dc_0, types.f_dc_0, littleEndian) : 0;\r\n const f_dc_1 = offsets.f_dc_1 >= 0 ? readProperty(dataView, base + offsets.f_dc_1, types.f_dc_1, littleEndian) : 0;\r\n const f_dc_2 = offsets.f_dc_2 >= 0 ? readProperty(dataView, base + offsets.f_dc_2, types.f_dc_2, littleEndian) : 0;\r\n colors[outputIdx * 3 + 0] = 0.5 + SH_C0 * f_dc_0;\r\n colors[outputIdx * 3 + 1] = 0.5 + SH_C0 * f_dc_1;\r\n colors[outputIdx * 3 + 2] = 0.5 + SH_C0 * f_dc_2;\r\n\r\n // 不透明度(sigmoid)\r\n const rawOpacity = offsets.opacity >= 0 ? readProperty(dataView, base + offsets.opacity, types.opacity, littleEndian) : 0;\r\n opacities[outputIdx] = sigmoid(rawOpacity);\r\n\r\n // SH 系数(可选)\r\n // PLY 文件中 f_rest_* 的顺序是 channel-first:\r\n // [R0..R14, G0..G14, B0..B14] - 每通道 15 个系数\r\n // 我们转换为 interleaved 格式: [R0,G0,B0, R1,G1,B1, ...]\r\n if (shCoeffs && shProps.length > 0) {\r\n const shBase = outputIdx * 45;\r\n const perChannel = Math.floor(shProps.length / 3); // 每通道的系数数量\r\n \r\n for (let coefIdx = 0; coefIdx < perChannel && coefIdx < 15; coefIdx++) {\r\n // PLY 中: R 在 [0..perChannel-1], G 在 [perChannel..2*perChannel-1], B 在 [2*perChannel..3*perChannel-1]\r\n const srcR = coefIdx;\r\n const srcG = perChannel + coefIdx;\r\n const srcB = 2 * perChannel + coefIdx;\r\n \r\n // 目标: interleaved [R0,G0,B0, R1,G1,B1, ...]\r\n const dstBase = coefIdx * 3;\r\n \r\n if (srcR < shProps.length) {\r\n const prop = shProps[srcR];\r\n shCoeffs[shBase + dstBase + 0] = readProperty(dataView, base + prop.byteOffset, prop.type, littleEndian);\r\n }\r\n if (srcG < shProps.length) {\r\n const prop = shProps[srcG];\r\n shCoeffs[shBase + dstBase + 1] = readProperty(dataView, base + prop.byteOffset, prop.type, littleEndian);\r\n }\r\n if (srcB < shProps.length) {\r\n const prop = shProps[srcB];\r\n shCoeffs[shBase + dstBase + 2] = readProperty(dataView, base + prop.byteOffset, prop.type, littleEndian);\r\n }\r\n }\r\n }\r\n\r\n outputIdx++;\r\n\r\n // 进度回调\r\n if (onProgress) {\r\n const progress = Math.floor((i / actualCount) * 100);\r\n if (progress > lastProgress) {\r\n lastProgress = progress;\r\n onProgress(i, actualCount);\r\n }\r\n }\r\n }\r\n\r\n return {\r\n count: outputIdx,\r\n positions,\r\n scales,\r\n rotations,\r\n colors,\r\n opacities,\r\n shCoeffs,\r\n };\r\n}\r\n\r\n/**\r\n * 将 CompactSplatData 转换为 GPU buffer 格式\r\n * 直接输出可以上传到 GPU 的 Float32Array\r\n * \r\n * @param data 紧凑 splat 数据\r\n * @param includeFullSH 是否包含完整 SH 系数(256 字节/splat),否则只包含基本数据(64 字节/splat)\r\n */\r\nexport function compactDataToGPUBuffer(\r\n data: CompactSplatData,\r\n includeFullSH: boolean = false\r\n): Float32Array {\r\n const count = data.count;\r\n\r\n if (includeFullSH) {\r\n // 完整格式:256 字节/splat = 64 floats\r\n const buffer = new Float32Array(count * 64);\r\n\r\n for (let i = 0; i < count; i++) {\r\n const offset = i * 64;\r\n\r\n // mean (vec3) + padding\r\n buffer[offset + 0] = data.positions[i * 3 + 0];\r\n buffer[offset + 1] = data.positions[i * 3 + 1];\r\n buffer[offset + 2] = data.positions[i * 3 + 2];\r\n buffer[offset + 3] = 0;\r\n\r\n // scale (vec3) + padding\r\n buffer[offset + 4] = data.scales[i * 3 + 0];\r\n buffer[offset + 5] = data.scales[i * 3 + 1];\r\n buffer[offset + 6] = data.scales[i * 3 + 2];\r\n buffer[offset + 7] = 0;\r\n\r\n // rotation (vec4)\r\n buffer[offset + 8] = data.rotations[i * 4 + 0];\r\n buffer[offset + 9] = data.rotations[i * 4 + 1];\r\n buffer[offset + 10] = data.rotations[i * 4 + 2];\r\n buffer[offset + 11] = data.rotations[i * 4 + 3];\r\n\r\n // colorDC (vec3) + opacity\r\n buffer[offset + 12] = data.colors[i * 3 + 0];\r\n buffer[offset + 13] = data.colors[i * 3 + 1];\r\n buffer[offset + 14] = data.colors[i * 3 + 2];\r\n buffer[offset + 15] = data.opacities[i];\r\n\r\n // SH 系数\r\n if (data.shCoeffs) {\r\n const shBase = i * 45;\r\n // sh1 (9 floats)\r\n for (let j = 0; j < 9; j++) {\r\n buffer[offset + 16 + j] = data.shCoeffs[shBase + j];\r\n }\r\n // sh2 (15 floats)\r\n for (let j = 0; j < 15; j++) {\r\n buffer[offset + 25 + j] = data.shCoeffs[shBase + 9 + j];\r\n }\r\n // sh3 (21 floats)\r\n for (let j = 0; j < 21; j++) {\r\n buffer[offset + 40 + j] = data.shCoeffs[shBase + 24 + j];\r\n }\r\n }\r\n // padding 已经是 0(Float32Array 默认初始化为 0)\r\n }\r\n\r\n return buffer;\r\n } else {\r\n // 紧凑格式:64 字节/splat = 16 floats(只包含基本渲染数据)\r\n const buffer = new Float32Array(count * 64); // 保持 256 字节对齐,但只填充基本数据\r\n \r\n for (let i = 0; i < count; i++) {\r\n const offset = i * 64;\r\n \r\n // mean (vec3) + padding\r\n buffer[offset + 0] = data.positions[i * 3 + 0];\r\n buffer[offset + 1] = data.positions[i * 3 + 1];\r\n buffer[offset + 2] = data.positions[i * 3 + 2];\r\n buffer[offset + 3] = 0;\r\n \r\n // scale (vec3) + padding\r\n buffer[offset + 4] = data.scales[i * 3 + 0];\r\n buffer[offset + 5] = data.scales[i * 3 + 1];\r\n buffer[offset + 6] = data.scales[i * 3 + 2];\r\n buffer[offset + 7] = 0;\r\n \r\n // rotation (vec4)\r\n buffer[offset + 8] = data.rotations[i * 4 + 0];\r\n buffer[offset + 9] = data.rotations[i * 4 + 1];\r\n buffer[offset + 10] = data.rotations[i * 4 + 2];\r\n buffer[offset + 11] = data.rotations[i * 4 + 3];\r\n \r\n // colorDC (vec3) + opacity\r\n buffer[offset + 12] = data.colors[i * 3 + 0];\r\n buffer[offset + 13] = data.colors[i * 3 + 1];\r\n buffer[offset + 14] = data.colors[i * 3 + 2];\r\n buffer[offset + 15] = data.opacities[i];\r\n \r\n // 其余保持为 0(SH 系数为空)\r\n }\r\n \r\n return buffer;\r\n }\r\n}\r\n","/**\r\n * SplatLoader - 加载 .splat 格式的 3D Gaussian Splatting 文件\r\n * \r\n * .splat 格式是一种紧凑的 3DGS 数据格式:\r\n * - 每个 splat 固定 32 字节,无文件头\r\n * - 数据布局: position(12) + scale(12) + color(3) + opacity(1) + rotation(4)\r\n * - 不包含高阶球谐系数,仅 DC 颜色\r\n * \r\n * 四元数顺序: [w, x, y, z](与 PLYLoader 保持一致)\r\n * \r\n * 参考: supersplat/src/loaders/splat.ts\r\n */\r\n\r\nimport { SplatCPU } from \"./PLYLoader\";\r\n\r\n/** .splat 文件每个 splat 的字节大小 */\r\nconst SPLAT_SIZE = 32;\r\n\r\n/** 最小有效文件大小(至少包含一个 splat) */\r\nconst MIN_FILE_SIZE = SPLAT_SIZE;\r\n\r\n/** 最大合理文件大小(防止内存溢出,约 1000 万 splats) */\r\nconst MAX_FILE_SIZE = SPLAT_SIZE * 10_000_000;\r\n\r\n/**\r\n * 验证 .splat 文件格式\r\n * 由于 .splat 没有魔数,只能通过文件大小和数据合理性来验证\r\n */\r\nfunction validateSplatFile(data: ArrayBufferLike): void {\r\n if (data.byteLength < MIN_FILE_SIZE) {\r\n throw new Error(`无效的 Splat 文件: 文件太小 (${data.byteLength} bytes),至少需要 ${MIN_FILE_SIZE} bytes`);\r\n }\r\n\r\n if (data.byteLength > MAX_FILE_SIZE) {\r\n throw new Error(`Splat 文件过大 (${(data.byteLength / 1024 / 1024).toFixed(1)} MB),超过最大限制`);\r\n }\r\n\r\n if (data.byteLength % SPLAT_SIZE !== 0) {\r\n throw new Error(`无效的 Splat 文件: 文件大小 (${data.byteLength} bytes) 不是 ${SPLAT_SIZE} 的整数倍`);\r\n }\r\n\r\n // 抽样检查数据合理性(检查前几个 splat 的位置是否为有效浮点数)\r\n const dataView = new DataView(data);\r\n const samplesToCheck = Math.min(10, Math.floor(data.byteLength / SPLAT_SIZE));\r\n\r\n for (let i = 0; i < samplesToCheck; i++) {\r\n const off = i * SPLAT_SIZE;\r\n const x = dataView.getFloat32(off + 0, true);\r\n const y = dataView.getFloat32(off + 4, true);\r\n const z = dataView.getFloat32(off + 8, true);\r\n\r\n // 检查是否为有效浮点数(非 NaN、非 Infinity)\r\n if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(z)) {\r\n throw new Error(`无效的 Splat 文件: 第 ${i} 个 splat 包含无效的位置数据`);\r\n }\r\n\r\n // 检查位置是否在合理范围内(-10000 到 10000)\r\n const MAX_POS = 10000;\r\n if (Math.abs(x) > MAX_POS || Math.abs(y) > MAX_POS || Math.abs(z) > MAX_POS) {\r\n // 位置超出常规范围\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Sigmoid 函数,与 PLYLoader 保持一致\r\n */\r\nfunction sigmoid(x: number): number {\r\n return 1 / (1 + Math.exp(-x));\r\n}\r\n\r\n/**\r\n * 逆 Sigmoid 函数\r\n * 将 [0, 1] 范围的值转换回原始 logit 值\r\n */\r\nfunction inverseSigmoid(y: number): number {\r\n // 避免 log(0) 和 log(负数)\r\n const clamped = Math.max(0.0001, Math.min(0.9999, y));\r\n return Math.log(clamped / (1 - clamped));\r\n}\r\n\r\n/**\r\n * 加载并解析 .splat 文件\r\n * @param url .splat 文件的 URL\r\n * @returns SplatCPU 数组\r\n */\r\nexport async function loadSplat(url: string): Promise<SplatCPU[]> {\r\n // 获取文件\r\n const response = await fetch(url);\r\n if (!response.ok) {\r\n throw new Error(`无法加载 Splat 文件: ${url}`);\r\n }\r\n const buffer = await response.arrayBuffer();\r\n\r\n return deserializeSplat(buffer);\r\n}\r\n\r\n/**\r\n * 从 ArrayBuffer 解析 splat 数据\r\n * @param data 文件的 ArrayBuffer\r\n * @returns SplatCPU 数组\r\n */\r\nexport function deserializeSplat(data: ArrayBufferLike): SplatCPU[] {\r\n // 验证文件格式\r\n validateSplatFile(data);\r\n\r\n const totalSplats = Math.floor(data.byteLength / SPLAT_SIZE);\r\n\r\n const dataView = new DataView(data);\r\n const splats: SplatCPU[] = new Array(totalSplats);\r\n\r\n // 预分配共享的 SH 系数数组(全为 0,因为 .splat 不包含 SH)\r\n const shRestBuffer = new Float32Array(totalSplats * 45);\r\n\r\n for (let i = 0; i < totalSplats; i++) {\r\n const off = i * SPLAT_SIZE;\r\n\r\n // 读取位置 (float32 × 3 = 12 bytes)\r\n const x = dataView.getFloat32(off + 0, true);\r\n const y = dataView.getFloat32(off + 4, true);\r\n const z = dataView.getFloat32(off + 8, true);\r\n\r\n // 读取缩放 (float32 × 3 = 12 bytes)\r\n // splat 格式存储原始缩放值,直接使用\r\n const scale_0 = dataView.getFloat32(off + 12, true);\r\n const scale_1 = dataView.getFloat32(off + 16, true);\r\n const scale_2 = dataView.getFloat32(off + 20, true);\r\n\r\n // 读取颜色 (uint8 × 3 = 3 bytes)\r\n // splat 格式直接存储 RGB 颜色 [0-255],归一化到 [0-1]\r\n const colorR = dataView.getUint8(off + 24) / 255;\r\n const colorG = dataView.getUint8(off + 25) / 255;\r\n const colorB = dataView.getUint8(off + 26) / 255;\r\n\r\n // 读取透明度 (uint8 × 1 = 1 byte)\r\n // .splat 格式存储的是 sigmoid 后的值 [0-255] 映射到 [0-1]\r\n // 为了与 PLYLoader 的 sigmoid 处理保持一致,我们:\r\n // 1. 先将 uint8 转换为 [0, 1] 范围\r\n // 2. 应用逆 sigmoid 得到原始 logit 值\r\n // 3. 再应用 sigmoid(这样与 PLYLoader 的处理流程一致)\r\n // \r\n // 实际上这等价于直接使用线性归一化,但保持代码逻辑一致性\r\n const opacityUint8 = dataView.getUint8(off + 27);\r\n const opacityNormalized = opacityUint8 / 255;\r\n // 直接使用归一化值作为最终 opacity(因为 .splat 已经是 sigmoid 后的值)\r\n const opacity = opacityNormalized;\r\n\r\n // 读取旋转四元数 (uint8 × 4 = 4 bytes)\r\n // 从 [0, 255] 映射到 [-1, 1]\r\n // 四元数顺序: [w, x, y, z]\r\n const rot_w = (dataView.getUint8(off + 28) - 128) / 128;\r\n const rot_x = (dataView.getUint8(off + 29) - 128) / 128;\r\n const rot_y = (dataView.getUint8(off + 30) - 128) / 128;\r\n const rot_z = (dataView.getUint8(off + 31) - 128) / 128;\r\n\r\n // 归一化四元数\r\n const qlen = Math.sqrt(\r\n rot_w * rot_w + rot_x * rot_x + rot_y * rot_y + rot_z * rot_z\r\n );\r\n const qnorm = qlen > 0 ? 1 / qlen : 1;\r\n\r\n // 使用共享 buffer 的子数组\r\n const shOffset = i * 45;\r\n const shRest = shRestBuffer.subarray(shOffset, shOffset + 45);\r\n\r\n splats[i] = {\r\n mean: [x, y, z],\r\n scale: [scale_0, scale_1, scale_2],\r\n rotation: [\r\n rot_w * qnorm,\r\n rot_x * qnorm,\r\n rot_y * qnorm,\r\n rot_z * qnorm,\r\n ],\r\n colorDC: [colorR, colorG, colorB],\r\n opacity,\r\n shRest,\r\n };\r\n }\r\n\r\n return splats;\r\n}\r\n","/**\r\n * GSSplatSorter - GPU Radix Sort 深度排序器\r\n *\r\n * 基于 rfs-gsplat-render 的 3-Pass Radix Sort 架构实现:\r\n * - 4 个 pass (8-bit 增量,总共 32 位)\r\n * - 每个 pass 包含: Upsweep -> Spine -> Downsweep\r\n * - 稳定排序,解决远距离闪烁问题\r\n *\r\n * 参考: rfs-gsplat-render/assets/shaders/radix_sort.wgsl\r\n */\r\n\r\nconst WORKGROUP_SIZE = 256;\r\nconst RADIX_BITS = 8;\r\nconst RADIX_SIZE = 256; // 2^8\r\nconst ELEMENTS_PER_THREAD = 4;\r\nconst BLOCK_SIZE = WORKGROUP_SIZE * ELEMENTS_PER_THREAD; // 1024\r\n\r\n/**\r\n * 生成 Culling Shader 代码\r\n * 基于 rfs-gsplat-render/assets/shaders/gaussian_splat_cull.wgsl\r\n */\r\nfunction generateCullingShaderCode(): string {\r\n return /* wgsl */ `\r\n/**\r\n * Project & Cull Shader\r\n * 基于 rfs-gsplat-render 实现\r\n */\r\n\r\nstruct Splat {\r\n mean: vec3<f32>,\r\n _pad0: f32,\r\n scale: vec3<f32>,\r\n _pad1: f32,\r\n rotation: vec4<f32>,\r\n colorDC: vec3<f32>,\r\n opacity: f32,\r\n sh1: array<f32, 9>,\r\n sh2: array<f32, 15>,\r\n sh3: array<f32, 21>,\r\n _pad2: array<f32, 3>,\r\n}\r\n\r\nstruct CameraUniforms {\r\n view: mat4x4<f32>,\r\n proj: mat4x4<f32>,\r\n model: mat4x4<f32>,\r\n cameraPos: vec3<f32>,\r\n _pad: f32,\r\n}\r\n\r\nstruct CullingParams {\r\n splatCount: u32,\r\n nearPlane: f32,\r\n farPlane: f32,\r\n screenWidth: f32,\r\n screenHeight: f32,\r\n frustumDilation: f32,\r\n pixelThreshold: f32,\r\n _pad1: f32,\r\n}\r\n\r\n@group(0) @binding(0) var<storage, read> splats: array<Splat>;\r\n@group(0) @binding(1) var<uniform> camera: CameraUniforms;\r\n@group(0) @binding(2) var<uniform> params: CullingParams;\r\n@group(0) @binding(3) var<storage, read_write> depthKeys: array<u32>;\r\n@group(0) @binding(4) var<storage, read_write> visibleIndices: array<u32>;\r\n@group(0) @binding(5) var<storage, read_write> indirectBuffer: array<atomic<u32>, 4>;\r\n\r\nfn maxScale(scale: vec3<f32>) -> f32 {\r\n return max(max(scale.x, scale.y), scale.z);\r\n}\r\n\r\nfn getModelMaxScale(model: mat4x4<f32>) -> f32 {\r\n let sx = length(model[0].xyz);\r\n let sy = length(model[1].xyz);\r\n let sz = length(model[2].xyz);\r\n return max(max(sx, sy), sz);\r\n}\r\n\r\n// IEEE 754 位操作编码浮点数为可排序的 u32\r\n// 参考 rfs-gsplat-render 的 encode_min_max_fp32 实现\r\nfn encodeDepthKey(val: f32) -> u32 {\r\n var bits = bitcast<u32>(val);\r\n bits ^= bitcast<u32>(bitcast<i32>(bits) >> 31) | 0x80000000u;\r\n return bits;\r\n}\r\n\r\n// 视锥剔除检查\r\n// 基于 rfs-gsplat-render 的 is_in_frustum 实现\r\nfn isInFrustum(clipPos: vec4<f32>, frustumDilation: f32) -> bool {\r\n let clip = (1.0 + frustumDilation) * clipPos.w;\r\n \r\n if abs(clipPos.x) > clip { return false; }\r\n if abs(clipPos.y) > clip { return false; }\r\n \r\n let nearThreshold = (0.0 - frustumDilation) * clipPos.w;\r\n if clipPos.z < nearThreshold || clipPos.z > clipPos.w {\r\n return false;\r\n }\r\n \r\n return true;\r\n}\r\n\r\n@compute @workgroup_size(${WORKGROUP_SIZE})\r\nfn projectAndCull(@builtin(global_invocation_id) gid: vec3<u32>) {\r\n let i = gid.x;\r\n if i >= params.splatCount { return; }\r\n \r\n let splat = splats[i];\r\n \r\n // 透明度剔除\r\n if splat.opacity < 0.004 { return; }\r\n \r\n // 变换: Local -> World -> View -> Clip\r\n let worldPos = camera.model * vec4<f32>(splat.mean, 1.0);\r\n let viewPos = camera.view * worldPos;\r\n let clipPos = camera.proj * viewPos;\r\n \r\n // 视锥剔除\r\n if !isInFrustum(clipPos, params.frustumDilation) { return; }\r\n \r\n // 深度编码 (viewPos.z 是负数)\r\n let depth = viewPos.z;\r\n let sortableDepth = encodeDepthKey(depth);\r\n \r\n // 原子增加可见计数并获取索引\r\n // indirectBuffer[1] 是 instance_count\r\n let visibleIdx = atomicAdd(&indirectBuffer[1], 1u);\r\n \r\n // 写入可见点列表\r\n depthKeys[visibleIdx] = sortableDepth;\r\n visibleIndices[visibleIdx] = i;\r\n}\r\n\r\n@compute @workgroup_size(1)\r\nfn initIndirectBuffer() {\r\n // [vertex_count, instance_count, first_vertex, first_instance]\r\n atomicStore(&indirectBuffer[0], 4u);\r\n atomicStore(&indirectBuffer[1], 0u); // instance_count 由 cull shader 填充\r\n atomicStore(&indirectBuffer[2], 0u);\r\n atomicStore(&indirectBuffer[3], 0u);\r\n}\r\n`;\r\n}\r\n\r\n/**\r\n * 生成 Radix Sort Shader 代码\r\n * 完整移植自 rfs-gsplat-render/assets/shaders/radix_sort.wgsl\r\n */\r\nfunction generateRadixSortShaderCode(): string {\r\n return /* wgsl */ `\r\n/**\r\n * GPU Radix Sort - 3-Pass Architecture\r\n * 基于 rfs-gsplat-render 实现\r\n * \r\n * Pass 1: Upsweep - 构建局部直方图并累加到全局\r\n * Pass 2: Spine - 对分区和全局直方图进行前缀和\r\n * Pass 3: Downsweep - 使用计算的偏移量散射元素 (稳定排序)\r\n */\r\n\r\nconst WG: u32 = ${WORKGROUP_SIZE}u;\r\nconst RADIX_BITS: u32 = ${RADIX_BITS}u;\r\nconst RADIX_SIZE: u32 = ${RADIX_SIZE}u;\r\nconst RADIX_MASK: u32 = ${RADIX_SIZE - 1}u;\r\nconst ELEMENTS_PER_THREAD: u32 = ${ELEMENTS_PER_THREAD}u;\r\nconst BLOCK_SIZE: u32 = ${BLOCK_SIZE}u;\r\n\r\nfn divCeil(a: u32, b: u32) -> u32 {\r\n return (a + b - 1u) / b;\r\n}\r\n\r\nstruct SortParams {\r\n maxElementCount: u32,\r\n bitShift: u32,\r\n passIndex: u32,\r\n _padding: u32,\r\n}\r\n\r\n// ============================================================================\r\n// Pass 1: Upsweep - 计数局部直方图并累加到全局\r\n// ============================================================================\r\n\r\n@group(0) @binding(0) var<uniform> upsweepParams: SortParams;\r\n@group(0) @binding(1) var<storage, read> indirectBufferUpsweep: array<u32>;\r\n@group(0) @binding(2) var<storage, read> keysIn: array<u32>;\r\n@group(0) @binding(3) var<storage, read_write> globalHistogram: array<atomic<u32>>;\r\n@group(0) @binding(4) var<storage, read_write> partitionHistogram: array<u32>;\r\n\r\nvar<workgroup> localHistogram: array<atomic<u32>, RADIX_SIZE>;\r\n\r\n@compute @workgroup_size(256, 1, 1)\r\nfn upsweep(\r\n @builtin(local_invocation_id) localId: vec3<u32>,\r\n @builtin(workgroup_id) workgroupId: vec3<u32>,\r\n) {\r\n // 从 indirectBuffer[1] 读取动态可见数量 (instance_count)\r\n let numKeys = indirectBufferUpsweep[1];\r\n let numPartitions = divCeil(numKeys, BLOCK_SIZE);\r\n let partitionId = workgroupId.x;\r\n \r\n if partitionId >= numPartitions { return; }\r\n \r\n let tid = localId.x;\r\n let partitionStart = partitionId * BLOCK_SIZE;\r\n let shift = upsweepParams.bitShift;\r\n let passIdx = upsweepParams.passIndex;\r\n \r\n // 初始化局部直方图\r\n if tid < RADIX_SIZE {\r\n atomicStore(&localHistogram[tid], 0u);\r\n }\r\n workgroupBarrier();\r\n \r\n // 构建局部直方图\r\n for (var j = 0u; j < ELEMENTS_PER_THREAD; j++) {\r\n let keyIdx = partitionStart + tid * ELEMENTS_PER_THREAD + j;\r\n if keyIdx < numKeys {\r\n let key = keysIn[keyIdx];\r\n let bin = (key >> shift) & RADIX_MASK;\r\n atomicAdd(&localHistogram[bin], 1u);\r\n }\r\n }\r\n \r\n workgroupBarrier();\r\n \r\n // 写入分区直方图并累加到全局直方图\r\n if tid < RADIX_SIZE {\r\n let count = atomicLoad(&localHistogram[tid]);\r\n partitionHistogram[RADIX_SIZE * partitionId + tid] = count;\r\n atomicAdd(&globalHistogram[RADIX_SIZE * passIdx + tid], count);\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Pass 2: Spine - 对分区和全局直方图进行前缀和\r\n// ============================================================================\r\n\r\n@group(0) @binding(0) var<storage, read> indirectBufferSpine: array<u32>;\r\n@group(0) @binding(1) var<storage, read_write> globalHistogramSpine: array<u32>;\r\n@group(0) @binding(2) var<storage, read_write> partitionHistogramSpine: array<u32>;\r\n@group(0) @binding(3) var<uniform> spineParams: SortParams;\r\n\r\n// 双缓冲用于无数据竞争的 Hillis-Steele scan\r\nvar<workgroup> scanA: array<u32, 256>;\r\nvar<workgroup> scanB: array<u32, 256>;\r\nvar<workgroup> reductionShared: u32;\r\n\r\n@compute @workgroup_size(256, 1, 1)\r\nfn spine(\r\n @builtin(local_invocation_id) localId: vec3<u32>,\r\n @builtin(workgroup_id) workgroupId: vec3<u32>,\r\n) {\r\n let numKeys = indirectBufferSpine[1];\r\n let numPartitions = divCeil(numKeys, BLOCK_SIZE);\r\n let bin = workgroupId.x;\r\n let tid = localId.x;\r\n \r\n if bin >= RADIX_SIZE { return; }\r\n \r\n // 初始化共享 reduction\r\n if tid == 0u {\r\n reductionShared = 0u;\r\n }\r\n workgroupBarrier();\r\n \r\n // 处理此 bin 的所有分区(分批处理)\r\n let MAX_BATCH_SIZE = 256u;\r\n for (var batchStart = 0u; batchStart < numPartitions; batchStart += MAX_BATCH_SIZE) {\r\n let partitionIdx = batchStart + tid;\r\n let batchSize = min(MAX_BATCH_SIZE, numPartitions - batchStart);\r\n \r\n // 加载此批次的值\r\n if tid < batchSize && partitionIdx < numPartitions {\r\n scanA[tid] = partitionHistogramSpine[RADIX_SIZE * partitionIdx + bin];\r\n } else {\r\n scanA[tid] = 0u;\r\n }\r\n workgroupBarrier();\r\n \r\n // Hillis-Steele inclusive prefix sum (双缓冲避免数据竞争)\r\n var useA = true;\r\n var offset = 1u;\r\n for (var d = 0u; d < 8u; d++) {\r\n if useA {\r\n if tid >= offset {\r\n scanB[tid] = scanA[tid] + scanA[tid - offset];\r\n } else {\r\n scanB[tid] = scanA[tid];\r\n }\r\n } else {\r\n if tid >= offset {\r\n scanA[tid] = scanB[tid] + scanB[tid - offset];\r\n } else {\r\n scanA[tid] = scanB[tid];\r\n }\r\n }\r\n workgroupBarrier();\r\n useA = !useA;\r\n offset <<= 1u;\r\n }\r\n \r\n // 8 次迭代后结果在 scanA 中\r\n \r\n // 写回为 exclusive prefix sum(加上 reduction)\r\n if tid < batchSize && partitionIdx < numPartitions {\r\n var exclusive = reductionShared;\r\n if tid > 0u {\r\n exclusive += scanA[tid - 1u];\r\n }\r\n partitionHistogramSpine[RADIX_SIZE * partitionIdx + bin] = exclusive;\r\n }\r\n \r\n // 更新下一批的 reduction\r\n workgroupBarrier();\r\n if tid == 0u && batchSize > 0u {\r\n reductionShared += scanA[batchSize - 1u];\r\n }\r\n workgroupBarrier();\r\n }\r\n \r\n // Bin 0 的工作组同时处理全局直方图前缀和\r\n if bin == 0u {\r\n let passIdx = spineParams.passIndex;\r\n scanA[tid] = globalHistogramSpine[RADIX_SIZE * passIdx + tid];\r\n workgroupBarrier();\r\n \r\n // Hillis-Steele inclusive scan (双缓冲)\r\n var useA = true;\r\n var offset = 1u;\r\n for (var d = 0u; d < 8u; d++) {\r\n if useA {\r\n if tid >= offset {\r\n scanB[tid] = scanA[tid] + scanA[tid - offset];\r\n } else {\r\n scanB[tid] = scanA[tid];\r\n }\r\n } else {\r\n if tid >= offset {\r\n scanA[tid] = scanB[tid] + scanB[tid - offset];\r\n } else {\r\n scanA[tid] = scanB[tid];\r\n }\r\n }\r\n workgroupBarrier();\r\n useA = !useA;\r\n offset <<= 1u;\r\n }\r\n \r\n // 转换为 exclusive (结果在 scanA 中)\r\n var exclusive = 0u;\r\n if tid > 0u {\r\n exclusive = scanA[tid - 1u];\r\n }\r\n globalHistogramSpine[RADIX_SIZE * passIdx + tid] = exclusive;\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Pass 3: Downsweep - 使用偏移量散射元素 (稳定排序)\r\n// ============================================================================\r\n\r\n@group(0) @binding(0) var<uniform> downsweepParams: SortParams;\r\n@group(0) @binding(1) var<storage, read> indirectBufferDownsweep: array<u32>;\r\n@group(0) @binding(2) var<storage, read> globalHistogramDownsweep: array<u32>;\r\n@group(0) @binding(3) var<storage, read> partitionHistogramDownsweep: array<u32>;\r\n@group(0) @binding(4) var<storage, read> downsweepKeysIn: array<u32>;\r\n@group(0) @binding(5) var<storage, read> downsweepValuesIn: array<u32>;\r\n@group(0) @binding(6) var<storage, read_write> downsweepKeysOut: array<u32>;\r\n@group(0) @binding(7) var<storage, read_write> downsweepValuesOut: array<u32>;\r\n\r\nvar<workgroup> localKeys: array<u32, BLOCK_SIZE>;\r\nvar<workgroup> localValues: array<u32, BLOCK_SIZE>;\r\nvar<workgroup> localBins: array<u32, BLOCK_SIZE>;\r\n\r\n@compute @workgroup_size(256, 1, 1)\r\nfn downsweep(\r\n @builtin(local_invocation_id) localId: vec3<u32>,\r\n @builtin(workgroup_id) workgroupId: vec3<u32>,\r\n) {\r\n let numKeys = indirectBufferDownsweep[1];\r\n let numPartitions = divCeil(numKeys, BLOCK_SIZE);\r\n let partitionId = workgroupId.x;\r\n \r\n if partitionId >= numPartitions { return; }\r\n \r\n let tid = localId.x;\r\n let partitionStart = partitionId * BLOCK_SIZE;\r\n let shift = downsweepParams.bitShift;\r\n \r\n // 加载元素到共享内存\r\n for (var j = 0u; j < ELEMENTS_PER_THREAD; j++) {\r\n let keyIdx = partitionStart + tid * ELEMENTS_PER_THREAD + j;\r\n let localIdx = tid * ELEMENTS_PER_THREAD + j;\r\n \r\n if keyIdx < numKeys {\r\n let key = downsweepKeysIn[keyIdx];\r\n localKeys[localIdx] = key;\r\n localValues[localIdx] = downsweepValuesIn[keyIdx];\r\n localBins[localIdx] = (key >> shift) & RADIX_MASK;\r\n } else {\r\n localBins[localIdx] = 0xFFFFFFFFu;\r\n }\r\n }\r\n \r\n workgroupBarrier();\r\n \r\n // 线程 0 执行顺序散射以保持稳定性\r\n // 这是 rfs-gsplat-render 的关键设计,确保稳定排序\r\n if tid == 0u {\r\n var binWritePos: array<u32, RADIX_SIZE>;\r\n \r\n let passIdx = downsweepParams.passIndex;\r\n \r\n // 从全局 + 分区偏移初始化写入位置\r\n for (var b = 0u; b < RADIX_SIZE; b++) {\r\n binWritePos[b] = globalHistogramDownsweep[RADIX_SIZE * passIdx + b] + \r\n partitionHistogramDownsweep[RADIX_SIZE * partitionId + b];\r\n }\r\n \r\n // 按输入顺序顺序写入 (稳定)\r\n let partitionEnd = min(partitionStart + BLOCK_SIZE, numKeys);\r\n for (var k = 0u; k < BLOCK_SIZE; k++) {\r\n let keyIdx = partitionStart + k;\r\n if keyIdx < partitionEnd {\r\n let b = localBins[k];\r\n if b != 0xFFFFFFFFu {\r\n let writePos = binWritePos[b];\r\n if writePos < numKeys {\r\n downsweepKeysOut[writePos] = localKeys[k];\r\n downsweepValuesOut[writePos] = localValues[k];\r\n binWritePos[b]++;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n}\r\n`;\r\n}\r\n\r\n/**\r\n * 屏幕尺寸信息\r\n */\r\nexport interface ScreenInfo {\r\n width: number;\r\n height: number;\r\n}\r\n\r\n/**\r\n * 剔除参数\r\n */\r\nexport interface CullingOptions {\r\n nearPlane: number;\r\n farPlane: number;\r\n pixelThreshold: number;\r\n frustumDilation?: number;\r\n}\r\n\r\n/**\r\n * 排序器配置选项\r\n */\r\nexport interface SorterOptions {\r\n /** 暂时保留,Radix Sort 不使用桶配置 */\r\n numBuckets?: number;\r\n}\r\n\r\n/**\r\n * GSSplatSorter - GPU Radix Sort 排序器\r\n * 基于 rfs-gsplat-render 的 3-Pass Radix Sort 实现\r\n */\r\nexport class GSSplatSorter {\r\n private device: GPUDevice;\r\n private splatCount: number;\r\n\r\n // Culling Buffers\r\n private cullingParamsBuffer: GPUBuffer;\r\n private depthKeysBuffer: GPUBuffer;\r\n private visibleIndicesBuffer: GPUBuffer;\r\n private indirectBuffer: GPUBuffer;\r\n\r\n // Radix Sort Buffers\r\n private globalHistogramBuffer: GPUBuffer;\r\n private partitionHistogramBuffer: GPUBuffer;\r\n private keysTempBuffer: GPUBuffer;\r\n private valuesTempBuffer: GPUBuffer;\r\n // 每个 pass 独立的参数 buffer (避免竞争)\r\n private sortParamsBuffers: GPUBuffer[] = [];\r\n\r\n // Sorted output\r\n private sortedIndicesBuffer: GPUBuffer;\r\n\r\n // Culling Pipelines\r\n private initIndirectPipeline: GPUComputePipeline;\r\n private projectCullPipeline: GPUComputePipeline;\r\n private cullingBindGroupLayout: GPUBindGroupLayout;\r\n private cullingBindGroup: GPUBindGroup;\r\n\r\n // Radix Sort Pipelines\r\n private upsweepPipeline: GPUComputePipeline;\r\n private spinePipeline: GPUComputePipeline;\r\n private downsweepPipeline: GPUComputePipeline;\r\n private upsweepBindGroupLayout: GPUBindGroupLayout;\r\n private spineBindGroupLayout: GPUBindGroupLayout;\r\n private downsweepBindGroupLayout: GPUBindGroupLayout;\r\n\r\n // Bind groups for each pass (4 passes)\r\n private upsweepBindGroups: GPUBindGroup[] = [];\r\n private spineBindGroups: GPUBindGroup[] = [];\r\n private downsweepBindGroups: GPUBindGroup[] = [];\r\n\r\n private numPartitions: number;\r\n\r\n // 屏幕信息和剔除选项\r\n private screenWidth: number = 1920;\r\n private screenHeight: number = 1080;\r\n private cullingOptions: CullingOptions = {\r\n nearPlane: 0.1,\r\n farPlane: 1000,\r\n pixelThreshold: 0,\r\n frustumDilation: 0.2,\r\n };\r\n\r\n constructor(\r\n device: GPUDevice,\r\n splatCount: number,\r\n splatBuffer: GPUBuffer,\r\n cameraBuffer: GPUBuffer,\r\n _options: SorterOptions = {},\r\n ) {\r\n this.device = device;\r\n this.splatCount = splatCount;\r\n this.numPartitions = Math.ceil(splatCount / BLOCK_SIZE);\r\n\r\n // ============================================\r\n // 创建 Shader 模块\r\n // ============================================\r\n const cullingModule = device.createShaderModule({\r\n code: generateCullingShaderCode(),\r\n label: \"culling-shader\",\r\n });\r\n\r\n const radixSortModule = device.createShaderModule({\r\n code: generateRadixSortShaderCode(),\r\n label: \"radix-sort-shader\",\r\n });\r\n\r\n // ============================================\r\n // 创建 Buffers\r\n // ============================================\r\n\r\n // Culling params: splatCount, nearPlane, farPlane, screenWidth, screenHeight, frustumDilation, pixelThreshold, _pad\r\n this.cullingParamsBuffer = device.createBuffer({\r\n size: 32,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n label: \"culling-params\",\r\n });\r\n\r\n this.depthKeysBuffer = device.createBuffer({\r\n size: splatCount * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n label: \"depth-keys\",\r\n });\r\n\r\n this.visibleIndicesBuffer = device.createBuffer({\r\n size: splatCount * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n label: \"visible-indices\",\r\n });\r\n\r\n // Indirect buffer: [vertex_count, instance_count, first_vertex, first_instance]\r\n this.indirectBuffer = device.createBuffer({\r\n size: 16,\r\n usage:\r\n GPUBufferUsage.STORAGE |\r\n GPUBufferUsage.INDIRECT |\r\n GPUBufferUsage.COPY_DST,\r\n label: \"indirect-buffer\",\r\n });\r\n\r\n // Global histogram: 4 passes * RADIX_SIZE bins\r\n this.globalHistogramBuffer = device.createBuffer({\r\n size: RADIX_SIZE * 4 * 4, // 4 passes * 256 bins * 4 bytes\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n label: \"global-histogram\",\r\n });\r\n\r\n // Partition histogram: numPartitions * RADIX_SIZE\r\n this.partitionHistogramBuffer = device.createBuffer({\r\n size: this.numPartitions * RADIX_SIZE * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n label: \"partition-histogram\",\r\n });\r\n\r\n // Temp buffers for ping-pong\r\n this.keysTempBuffer = device.createBuffer({\r\n size: splatCount * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n label: \"keys-temp\",\r\n });\r\n\r\n this.valuesTempBuffer = device.createBuffer({\r\n size: splatCount * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n label: \"values-temp\",\r\n });\r\n\r\n // 为每个 pass 创建独立的参数 buffer (4 个 pass)\r\n for (let i = 0; i < 4; i++) {\r\n const paramsBuffer = device.createBuffer({\r\n size: 16,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n label: `sort-params-${i}`,\r\n });\r\n this.sortParamsBuffers.push(paramsBuffer);\r\n \r\n // 预填充参数\r\n const sortParams = new ArrayBuffer(16);\r\n const sortView = new DataView(sortParams);\r\n sortView.setUint32(0, splatCount, true); // maxElementCount\r\n sortView.setUint32(4, i * RADIX_BITS, true); // bitShift\r\n sortView.setUint32(8, i, true); // passIndex\r\n sortView.setUint32(12, 0, true); // padding\r\n device.queue.writeBuffer(paramsBuffer, 0, sortParams);\r\n }\r\n\r\n // Final sorted indices\r\n this.sortedIndicesBuffer = device.createBuffer({\r\n size: splatCount * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\r\n label: \"sorted-indices\",\r\n });\r\n\r\n // ============================================\r\n // 创建 Culling Pipelines\r\n // ============================================\r\n this.cullingBindGroupLayout = device.createBindGroupLayout({\r\n label: \"culling-bind-group-layout\",\r\n entries: [\r\n { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"uniform\" } },\r\n { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"uniform\" } },\r\n { binding: 3, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 4, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 5, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n ],\r\n });\r\n\r\n const cullingPipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [this.cullingBindGroupLayout],\r\n });\r\n\r\n this.initIndirectPipeline = device.createComputePipeline({\r\n layout: cullingPipelineLayout,\r\n compute: { module: cullingModule, entryPoint: \"initIndirectBuffer\" },\r\n label: \"init-indirect-pipeline\",\r\n });\r\n\r\n this.projectCullPipeline = device.createComputePipeline({\r\n layout: cullingPipelineLayout,\r\n compute: { module: cullingModule, entryPoint: \"projectAndCull\" },\r\n label: \"project-cull-pipeline\",\r\n });\r\n\r\n this.cullingBindGroup = device.createBindGroup({\r\n layout: this.cullingBindGroupLayout,\r\n entries: [\r\n { binding: 0, resource: { buffer: splatBuffer } },\r\n { binding: 1, resource: { buffer: cameraBuffer } },\r\n { binding: 2, resource: { buffer: this.cullingParamsBuffer } },\r\n { binding: 3, resource: { buffer: this.depthKeysBuffer } },\r\n { binding: 4, resource: { buffer: this.visibleIndicesBuffer } },\r\n { binding: 5, resource: { buffer: this.indirectBuffer } },\r\n ],\r\n label: \"culling-bind-group\",\r\n });\r\n\r\n // ============================================\r\n // 创建 Radix Sort Pipelines\r\n // ============================================\r\n\r\n // Upsweep layout: params, indirect, keys_in, global_histogram, partition_histogram\r\n this.upsweepBindGroupLayout = device.createBindGroupLayout({\r\n label: \"upsweep-layout\",\r\n entries: [\r\n { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"uniform\" } },\r\n { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 3, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 4, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n ],\r\n });\r\n\r\n // Spine layout: indirect, global_histogram, partition_histogram, params\r\n this.spineBindGroupLayout = device.createBindGroupLayout({\r\n label: \"spine-layout\",\r\n entries: [\r\n { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 3, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"uniform\" } },\r\n ],\r\n });\r\n\r\n // Downsweep layout: params, indirect, global_histogram, partition_histogram, keys_in, values_in, keys_out, values_out\r\n this.downsweepBindGroupLayout = device.createBindGroupLayout({\r\n label: \"downsweep-layout\",\r\n entries: [\r\n { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"uniform\" } },\r\n { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 3, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 4, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 5, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 6, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 7, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n ],\r\n });\r\n\r\n this.upsweepPipeline = device.createComputePipeline({\r\n layout: device.createPipelineLayout({ bindGroupLayouts: [this.upsweepBindGroupLayout] }),\r\n compute: { module: radixSortModule, entryPoint: \"upsweep\" },\r\n label: \"upsweep-pipeline\",\r\n });\r\n\r\n this.spinePipeline = device.createComputePipeline({\r\n layout: device.createPipelineLayout({ bindGroupLayouts: [this.spineBindGroupLayout] }),\r\n compute: { module: radixSortModule, entryPoint: \"spine\" },\r\n label: \"spine-pipeline\",\r\n });\r\n\r\n this.downsweepPipeline = device.createComputePipeline({\r\n layout: device.createPipelineLayout({ bindGroupLayouts: [this.downsweepBindGroupLayout] }),\r\n compute: { module: radixSortModule, entryPoint: \"downsweep\" },\r\n label: \"downsweep-pipeline\",\r\n });\r\n\r\n // ============================================\r\n // 为 4 个 pass 创建 bind groups (ping-pong buffers)\r\n // ============================================\r\n this.createRadixSortBindGroups();\r\n }\r\n\r\n /**\r\n * 创建 Radix Sort 的 bind groups\r\n * 4 个 pass,使用 ping-pong buffers\r\n * \r\n * Ping-pong 模式:\r\n * - Pass 0: depthKeys/visibleIndices -> keysTempBuffer/valuesTempBuffer\r\n * - Pass 1: keysTempBuffer/valuesTempBuffer -> depthKeys/visibleIndices\r\n * - Pass 2: depthKeys/visibleIndices -> keysTempBuffer/valuesTempBuffer\r\n * - Pass 3: keysTempBuffer/valuesTempBuffer -> (depthKeys)/sortedIndicesBuffer\r\n */\r\n private createRadixSortBindGroups(): void {\r\n for (let passIdx = 0; passIdx < 4; passIdx++) {\r\n const isEvenPass = passIdx % 2 === 0;\r\n\r\n // Ping-pong: 偶数 pass 从原始 buffer 读取,奇数 pass 从临时 buffer 读取\r\n const keysIn = isEvenPass ? this.depthKeysBuffer : this.keysTempBuffer;\r\n const valuesIn = isEvenPass ? this.visibleIndicesBuffer : this.valuesTempBuffer;\r\n \r\n // 输出: 偶数 pass 写入临时 buffer,奇数 pass 写回原始 buffer\r\n // 最后一个 pass (pass 3) 的 values 输出到 sortedIndicesBuffer\r\n let keysOut: GPUBuffer;\r\n let valuesOut: GPUBuffer;\r\n \r\n if (isEvenPass) {\r\n keysOut = this.keysTempBuffer;\r\n valuesOut = this.valuesTempBuffer;\r\n } else {\r\n keysOut = this.depthKeysBuffer;\r\n // Pass 3 输出最终排序结果\r\n valuesOut = passIdx === 3 ? this.sortedIndicesBuffer : this.visibleIndicesBuffer;\r\n }\r\n\r\n this.upsweepBindGroups[passIdx] = this.device.createBindGroup({\r\n layout: this.upsweepBindGroupLayout,\r\n entries: [\r\n { binding: 0, resource: { buffer: this.sortParamsBuffers[passIdx] } },\r\n { binding: 1, resource: { buffer: this.indirectBuffer } },\r\n { binding: 2, resource: { buffer: keysIn } },\r\n { binding: 3, resource: { buffer: this.globalHistogramBuffer } },\r\n { binding: 4, resource: { buffer: this.partitionHistogramBuffer } },\r\n ],\r\n label: `upsweep-bind-group-${passIdx}`,\r\n });\r\n\r\n this.spineBindGroups[passIdx] = this.device.createBindGroup({\r\n layout: this.spineBindGroupLayout,\r\n entries: [\r\n { binding: 0, resource: { buffer: this.indirectBuffer } },\r\n { binding: 1, resource: { buffer: this.globalHistogramBuffer } },\r\n { binding: 2, resource: { buffer: this.partitionHistogramBuffer } },\r\n { binding: 3, resource: { buffer: this.sortParamsBuffers[passIdx] } },\r\n ],\r\n label: `spine-bind-group-${passIdx}`,\r\n });\r\n\r\n this.downsweepBindGroups[passIdx] = this.device.createBindGroup({\r\n layout: this.downsweepBindGroupLayout,\r\n entries: [\r\n { binding: 0, resource: { buffer: this.sortParamsBuffers[passIdx] } },\r\n { binding: 1, resource: { buffer: this.indirectBuffer } },\r\n { binding: 2, resource: { buffer: this.globalHistogramBuffer } },\r\n { binding: 3, resource: { buffer: this.partitionHistogramBuffer } },\r\n { binding: 4, resource: { buffer: keysIn } },\r\n { binding: 5, resource: { buffer: valuesIn } },\r\n { binding: 6, resource: { buffer: keysOut } },\r\n { binding: 7, resource: { buffer: valuesOut } },\r\n ],\r\n label: `downsweep-bind-group-${passIdx}`,\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * 设置屏幕尺寸\r\n */\r\n setScreenSize(width: number, height: number): void {\r\n this.screenWidth = width;\r\n this.screenHeight = height;\r\n }\r\n\r\n /**\r\n * 设置剔除参数\r\n */\r\n setCullingOptions(options: Partial<CullingOptions>): void {\r\n this.cullingOptions = { ...this.cullingOptions, ...options };\r\n }\r\n\r\n /**\r\n * 执行剔除和排序\r\n * 每帧调用\r\n */\r\n sort(): void {\r\n // ============================================\r\n // 更新 Culling 参数\r\n // ============================================\r\n const cullingParamsData = new ArrayBuffer(32);\r\n const view = new DataView(cullingParamsData);\r\n view.setUint32(0, this.splatCount, true);\r\n view.setFloat32(4, this.cullingOptions.nearPlane, true);\r\n view.setFloat32(8, this.cullingOptions.farPlane, true);\r\n view.setFloat32(12, this.screenWidth, true);\r\n view.setFloat32(16, this.screenHeight, true);\r\n view.setFloat32(20, this.cullingOptions.frustumDilation ?? 0.2, true);\r\n view.setFloat32(24, this.cullingOptions.pixelThreshold, true);\r\n view.setFloat32(28, 0, true);\r\n this.device.queue.writeBuffer(this.cullingParamsBuffer, 0, cullingParamsData);\r\n\r\n const encoder = this.device.createCommandEncoder({ label: \"splat-sort-encoder\" });\r\n\r\n // ============================================\r\n // 清理 buffers (关键! 防止上一帧数据导致闪烁)\r\n // ============================================\r\n encoder.clearBuffer(this.depthKeysBuffer);\r\n encoder.clearBuffer(this.visibleIndicesBuffer);\r\n encoder.clearBuffer(this.keysTempBuffer);\r\n encoder.clearBuffer(this.valuesTempBuffer);\r\n encoder.clearBuffer(this.globalHistogramBuffer);\r\n encoder.clearBuffer(this.partitionHistogramBuffer);\r\n\r\n // ============================================\r\n // Pass 0: 初始化 Indirect Buffer\r\n // ============================================\r\n {\r\n const pass = encoder.beginComputePass({ label: \"init-indirect\" });\r\n pass.setPipeline(this.initIndirectPipeline);\r\n pass.setBindGroup(0, this.cullingBindGroup);\r\n pass.dispatchWorkgroups(1);\r\n pass.end();\r\n }\r\n\r\n // ============================================\r\n // Pass 1: Project & Cull\r\n // ============================================\r\n {\r\n const pass = encoder.beginComputePass({ label: \"project-cull\" });\r\n pass.setPipeline(this.projectCullPipeline);\r\n pass.setBindGroup(0, this.cullingBindGroup);\r\n pass.dispatchWorkgroups(Math.ceil(this.splatCount / WORKGROUP_SIZE));\r\n pass.end();\r\n }\r\n\r\n // ============================================\r\n // Radix Sort: 4 passes (8-bit increments)\r\n // 每个 pass 在独立的 compute pass 中以确保内存同步\r\n // 参数已在构造函数中预填充到独立的 buffer\r\n // ============================================\r\n for (let passIdx = 0; passIdx < 4; passIdx++) {\r\n // Upsweep\r\n {\r\n const pass = encoder.beginComputePass({ label: `upsweep-p${passIdx}` });\r\n pass.setPipeline(this.upsweepPipeline);\r\n pass.setBindGroup(0, this.upsweepBindGroups[passIdx]);\r\n pass.dispatchWorkgroups(this.numPartitions);\r\n pass.end();\r\n }\r\n\r\n // Spine\r\n {\r\n const pass = encoder.beginComputePass({ label: `spine-p${passIdx}` });\r\n pass.setPipeline(this.spinePipeline);\r\n pass.setBindGroup(0, this.spineBindGroups[passIdx]);\r\n pass.dispatchWorkgroups(RADIX_SIZE);\r\n pass.end();\r\n }\r\n\r\n // Downsweep\r\n {\r\n const pass = encoder.beginComputePass({ label: `downsweep-p${passIdx}` });\r\n pass.setPipeline(this.downsweepPipeline);\r\n pass.setBindGroup(0, this.downsweepBindGroups[passIdx]);\r\n pass.dispatchWorkgroups(this.numPartitions);\r\n pass.end();\r\n }\r\n }\r\n\r\n this.device.queue.submit([encoder.finish()]);\r\n }\r\n\r\n /**\r\n * 获取排序后的索引 buffer(用于渲染)\r\n */\r\n getIndicesBuffer(): GPUBuffer {\r\n return this.sortedIndicesBuffer;\r\n }\r\n\r\n /**\r\n * 获取 DrawIndirect buffer\r\n */\r\n getDrawIndirectBuffer(): GPUBuffer {\r\n return this.indirectBuffer;\r\n }\r\n\r\n /**\r\n * 获取 splat 总数量\r\n */\r\n getSplatCount(): number {\r\n return this.splatCount;\r\n }\r\n\r\n /**\r\n * 销毁资源\r\n */\r\n destroy(): void {\r\n this.cullingParamsBuffer.destroy();\r\n this.depthKeysBuffer.destroy();\r\n this.visibleIndicesBuffer.destroy();\r\n this.indirectBuffer.destroy();\r\n this.globalHistogramBuffer.destroy();\r\n this.partitionHistogramBuffer.destroy();\r\n this.keysTempBuffer.destroy();\r\n this.valuesTempBuffer.destroy();\r\n for (const buffer of this.sortParamsBuffers) {\r\n buffer.destroy();\r\n }\r\n this.sortedIndicesBuffer.destroy();\r\n }\r\n}\r\n","/**\r\n * GSSplatRenderer - 优化的 3D Gaussian Splatting 渲染器\r\n * \r\n * 基于 rfs-gsplat-render 的实现进行优化:\r\n * 1. GPU Radix Sort - O(n) 稳定排序\r\n * 2. Normalized Gaussian - 消除边缘雾化\r\n * 3. ClipCorner 优化 - 减少 overdraw\r\n * 4. MipSplatting 抗锯齿\r\n * 5. 改进的视锥剔除\r\n */\r\n\r\nimport { Renderer } from \"../core/Renderer\";\r\nimport { Camera } from \"../core/Camera\";\r\nimport { SplatCPU } from \"./PLYLoader\";\r\nimport { GSSplatSorter } from \"./GSSplatSorter\";\r\nimport { CompactSplatData, compactDataToGPUBuffer } from \"./PLYLoaderMobile\";\r\nimport type { BoundingBox, Vec3Tuple } from \"../types\";\r\nimport { SHMode, RendererCapabilities } from \"../types\";\r\nimport type { IGSSplatRenderer, IGSSplatRendererWithCapabilities } from \"./IGSSplatRenderer\";\r\n\r\n// 优化的 shader (内联)\r\nconst gsOptimizedShader = /* wgsl */ `\r\n/**\r\n * 优化的 3D Gaussian Splatting Shader\r\n * 参考 rfs-gsplat-render 实现,修复颜色和抗锯齿问题\r\n */\r\n\r\nconst SQRT_8: f32 = 2.82842712475;\r\nconst SH_C0: f32 = 0.28209479177387814;\r\nconst SH_C1: f32 = 0.4886025119029199;\r\n// Normalized Gaussian 常量 (匹配 SuperSplat)\r\nconst EXP_NEG4: f32 = 0.01831563888873418;\r\nconst INV_ONE_MINUS_EXP_NEG4: f32 = 1.01865736036377408;\r\n// 低通滤波器 (正则化协方差矩阵)\r\nconst LOW_PASS_FILTER: f32 = 0.3;\r\nconst ALPHA_CULL_THRESHOLD: f32 = 0.00392156863;\r\n\r\nstruct Uniforms {\r\n view: mat4x4<f32>,\r\n proj: mat4x4<f32>,\r\n model: mat4x4<f32>,\r\n cameraPos: vec3<f32>,\r\n _pad: f32,\r\n screenSize: vec2<f32>,\r\n _pad2: vec2<f32>,\r\n}\r\n\r\nstruct Splat {\r\n mean: vec3<f32>, _pad0: f32,\r\n scale: vec3<f32>, _pad1: f32,\r\n rotation: vec4<f32>,\r\n colorDC: vec3<f32>,\r\n opacity: f32,\r\n sh1: array<f32, 9>,\r\n sh2: array<f32, 15>,\r\n sh3: array<f32, 21>,\r\n _pad2: array<f32, 3>,\r\n}\r\n\r\n@group(0) @binding(0) var<uniform> uniforms: Uniforms;\r\n@group(0) @binding(1) var<storage, read> splats: array<Splat>;\r\n@group(0) @binding(2) var<storage, read> sortedIndices: array<u32>;\r\n\r\nstruct VertexOutput {\r\n @builtin(position) position: vec4<f32>,\r\n @location(0) fragPos: vec2<f32>,\r\n @location(1) color: vec3<f32>,\r\n @location(2) opacity: f32,\r\n}\r\n\r\nconst QUAD_POSITIONS = array<vec2<f32>, 4>(\r\n vec2<f32>(-1.0, -1.0), vec2<f32>(-1.0, 1.0),\r\n vec2<f32>(1.0, -1.0), vec2<f32>(1.0, 1.0),\r\n);\r\n\r\n// ClipCorner 优化 (精确匹配 PlayCanvas/SuperSplat)\r\n// 从 PlayCanvas: clip = min(1.0, sqrt(-log(1.0 / (255.0 * alpha))) / 2.0)\r\n// 这根据透明度缩小 quad,排除 alpha < 1/255 的 Gaussian 区域\r\nfn computeClipFactor(alpha: f32) -> f32 {\r\n // 保护非常小的 alpha 值\r\n // 当 alpha <= 1/255 时,splat 不可见\r\n if alpha <= ALPHA_CULL_THRESHOLD { return 0.0; }\r\n // PlayCanvas 公式: clip = min(1.0, sqrt(-log(1.0 / (255.0 * alpha))) / 2.0)\r\n // 简化: -log(1/(255*a)) = log(255*a)\r\n return min(1.0, sqrt(log(255.0 * alpha)) / 2.0);\r\n}\r\n\r\n// 四元数转旋转矩阵 (PLY 格式: w, x, y, z)\r\nfn quatToMat3(q: vec4<f32>) -> mat3x3<f32> {\r\n let r = q.x; let x = q.y; let y = q.z; let z = q.w;\r\n return mat3x3<f32>(\r\n vec3<f32>(1.0 - 2.0 * (y * y + z * z), 2.0 * (x * y + r * z), 2.0 * (x * z - r * y)),\r\n vec3<f32>(2.0 * (x * y - r * z), 1.0 - 2.0 * (x * x + z * z), 2.0 * (y * z + r * x)),\r\n vec3<f32>(2.0 * (x * z + r * y), 2.0 * (y * z - r * x), 1.0 - 2.0 * (x * x + y * y))\r\n );\r\n}\r\n\r\nfn computeCovariance3D(scale: vec3<f32>, rotation: vec4<f32>) -> mat3x3<f32> {\r\n let R = quatToMat3(rotation);\r\n let S = mat3x3<f32>(vec3<f32>(scale.x, 0.0, 0.0), vec3<f32>(0.0, scale.y, 0.0), vec3<f32>(0.0, 0.0, scale.z));\r\n let M = R * S;\r\n return M * transpose(M);\r\n}\r\n\r\n// 协方差投影 (匹配参考实现)\r\n// 注意: viewCenter 是 vec4,直接使用 .xyz (不除以 w)\r\nfn projectCovariance(cov3d: mat3x3<f32>, viewCenter: vec4<f32>, focal: vec2<f32>, modelViewMat: mat4x4<f32>) -> vec3<f32> {\r\n let v = viewCenter.xyz; // 直接使用,不除以 w\r\n let s = 1.0 / (v.z * v.z);\r\n \r\n // Jacobian 矩阵\r\n let J = mat3x3<f32>(\r\n vec3<f32>(focal.x / v.z, 0.0, 0.0),\r\n vec3<f32>(0.0, focal.y / v.z, 0.0),\r\n vec3<f32>(-(focal.x * v.x) * s, -(focal.y * v.y) * s, 0.0)\r\n );\r\n \r\n // 从 model-view 矩阵提取 3x3 旋转部分 (匹配参考实现)\r\n let W = mat3x3<f32>(\r\n vec3<f32>(modelViewMat[0][0], modelViewMat[0][1], modelViewMat[0][2]),\r\n vec3<f32>(modelViewMat[1][0], modelViewMat[1][1], modelViewMat[1][2]),\r\n vec3<f32>(modelViewMat[2][0], modelViewMat[2][1], modelViewMat[2][2])\r\n );\r\n \r\n let T = J * W;\r\n let cov2d = T * cov3d * transpose(T);\r\n return vec3<f32>(cov2d[0][0], cov2d[0][1], cov2d[1][1]);\r\n}\r\n\r\nstruct ExtentResult {\r\n basis: vec4<f32>,\r\n adjustedOpacity: f32,\r\n}\r\n\r\n// 计算 2D 投影范围\r\n// 精确匹配 PlayCanvas/SuperSplat 实现\r\n// 注意: MipSplatting 抗锯齿默认禁用,因为大多数模型不是用 MipSplatting 训练的\r\n// 如果模型是用 MipSplatting 训练的,可以启用 GSPLAT_AA 模式\r\nfn computeExtentBasisAA(cov2dIn: vec3<f32>, opacity: f32, viewportSize: vec2<f32>) -> ExtentResult {\r\n var result: ExtentResult;\r\n var cov2d = cov2dIn;\r\n var alpha = opacity;\r\n \r\n // 添加低通滤波 (正则化) - 匹配 PlayCanvas: +0.3\r\n // 这避免了非常小的特征值导致的数值问题\r\n cov2d.x += LOW_PASS_FILTER;\r\n cov2d.z += LOW_PASS_FILTER;\r\n \r\n // 特征值分解 (使用 PlayCanvas 公式)\r\n let a = cov2d.x; // diagonal1\r\n let d = cov2d.z; // diagonal2\r\n let b = cov2d.y; // offDiagonal\r\n \r\n let mid = 0.5 * (a + d);\r\n let radius = length(vec2<f32>((a - d) * 0.5, b));\r\n \r\n let lambda1 = mid + radius;\r\n let lambda2 = max(mid - radius, 0.1); // PlayCanvas 使用 0.1 最小值\r\n \r\n // 检查特征值是否有效\r\n if lambda2 <= 0.0 { \r\n result.basis = vec4<f32>(0.0);\r\n result.adjustedOpacity = 0.0;\r\n return result;\r\n }\r\n \r\n // 使用基于视口的最大限制 (匹配 PlayCanvas)\r\n let vmin = min(1024.0, min(viewportSize.x, viewportSize.y));\r\n \r\n // 计算轴长度: l = 2.0 * min(sqrt(2.0 * lambda), vmin)\r\n // 这等价于 std_dev * sqrt(lambda),因为 std_dev = sqrt(8) ≈ 2.83\r\n let l1 = 2.0 * min(sqrt(2.0 * lambda1), vmin);\r\n let l2 = 2.0 * min(sqrt(2.0 * lambda2), vmin);\r\n \r\n // 关键: 剔除小于 2 像素的 Gaussian (匹配 PlayCanvas)\r\n // 这消除了导致\"雾化\"伪影的亚像素 splat\r\n if l1 < 2.0 && l2 < 2.0 { \r\n result.basis = vec4<f32>(0.0);\r\n result.adjustedOpacity = 0.0;\r\n return result;\r\n }\r\n \r\n // 从 offDiagonal 和特征值差计算特征向量\r\n // diagonalVector = normalize(vec2(offDiagonal, lambda1 - diagonal1))\r\n let diagVec = normalize(vec2<f32>(b, lambda1 - a));\r\n let eigenvector1 = diagVec;\r\n let eigenvector2 = vec2<f32>(diagVec.y, -diagVec.x);\r\n \r\n // 计算基向量 (不应用额外的 splat_scale,因为我们使用默认值 1.0)\r\n result.basis = vec4<f32>(eigenvector1 * l1, eigenvector2 * l2);\r\n result.adjustedOpacity = alpha;\r\n return result;\r\n}\r\n\r\nfn getModelScale3(model: mat4x4<f32>) -> vec3<f32> {\r\n return vec3<f32>(length(model[0].xyz), length(model[1].xyz), length(model[2].xyz));\r\n}\r\n\r\n@vertex\r\nfn vs_main(@builtin(vertex_index) vertexIndex: u32, @builtin(instance_index) instanceIndex: u32) -> VertexOutput {\r\n var output: VertexOutput;\r\n let splatIndex = sortedIndices[instanceIndex];\r\n let splat = splats[splatIndex];\r\n let quadPos = QUAD_POSITIONS[vertexIndex];\r\n \r\n // 透明度剔除\r\n if splat.opacity < ALPHA_CULL_THRESHOLD { output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output; }\r\n \r\n // 四元数有效性检查\r\n let quatNormSqr = dot(splat.rotation, splat.rotation);\r\n if quatNormSqr < 1e-6 { output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output; }\r\n \r\n // 变换到视图空间 (匹配参考实现: Local -> World -> View -> Clip)\r\n let worldPos = uniforms.model * vec4<f32>(splat.mean, 1.0);\r\n let viewPos = uniforms.view * worldPos; // vec4, 保持 w 分量\r\n let clipPos = uniforms.proj * viewPos;\r\n \r\n // 近平面剔除 (viewPos.z 是负数,相机看向 -Z)\r\n if viewPos.z >= 0.0 { output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output; }\r\n \r\n // NDC 计算\r\n let pW = 1.0 / (clipPos.w + 0.0000001);\r\n let ndcPos = clipPos * pW;\r\n \r\n // 视锥剔除 (放宽边界以避免 pop-in)\r\n let clipBound = 1.3;\r\n if abs(ndcPos.x) > clipBound || abs(ndcPos.y) > clipBound || ndcPos.z < -0.2 || ndcPos.z > 1.0 {\r\n output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output;\r\n }\r\n \r\n // 计算 3D 协方差 (使用原始 scale,模型缩放通过 model-view 矩阵处理)\r\n // 关键: 不要在这里应用模型缩放,协方差投影会通过 model-view 矩阵正确处理\r\n let cov3d = computeCovariance3D(splat.scale, splat.rotation);\r\n \r\n // 计算焦距 (匹配参考实现: abs(proj[0][0]) * 0.5 * width)\r\n let focal = vec2<f32>(\r\n abs(uniforms.proj[0][0]) * 0.5 * uniforms.screenSize.x,\r\n abs(uniforms.proj[1][1]) * 0.5 * uniforms.screenSize.y\r\n );\r\n \r\n // 计算 model-view 矩阵 (匹配参考实现)\r\n let modelViewMat = uniforms.view * uniforms.model;\r\n \r\n // 投影协方差到 2D (传入 viewPos 作为 vec4,不除以 w)\r\n let cov2d = projectCovariance(cov3d, viewPos, focal, modelViewMat);\r\n \r\n // 计算范围基向量 (带抗锯齿)\r\n let extentResult = computeExtentBasisAA(cov2d, splat.opacity, uniforms.screenSize);\r\n let basis = extentResult.basis;\r\n let adjustedOpacity = extentResult.adjustedOpacity;\r\n \r\n if basis.x == 0.0 && basis.y == 0.0 && basis.z == 0.0 && basis.w == 0.0 {\r\n output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output;\r\n }\r\n \r\n // 视锥边缘剔除 (匹配 PlayCanvas)\r\n let maxExtentPixels = max(length(basis.xy), length(basis.zw));\r\n let pixelToClip = vec2<f32>(clipPos.w, clipPos.w) / uniforms.screenSize;\r\n let splatExtentClip = vec2<f32>(maxExtentPixels, maxExtentPixels) * pixelToClip;\r\n if any((abs(clipPos.xy) - splatExtentClip) > vec2<f32>(clipPos.w, clipPos.w)) {\r\n output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output;\r\n }\r\n \r\n // ClipCorner 优化 (匹配 PlayCanvas/SuperSplat)\r\n // 根据透明度缩小 quad,排除 alpha < 1/255 的区域\r\n let clipFactor = computeClipFactor(adjustedOpacity);\r\n if clipFactor <= 0.0 { output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output; }\r\n \r\n // 计算最终顶点位置\r\n // basis_viewport: 从像素转换到 NDC 空间\r\n let basisViewport = vec2<f32>(1.0 / uniforms.screenSize.x, 1.0 / uniforms.screenSize.y);\r\n \r\n // 用 clipFactor 缩放基向量 (缩小 quad)\r\n let basisVector1 = basis.xy * clipFactor;\r\n let basisVector2 = basis.zw * clipFactor;\r\n \r\n // 计算 NDC 偏移\r\n // 注意: quadPos 在 [-1, 1] 范围内,clipFactor 只影响 quad 大小 (basis_vector)\r\n let ndcOffset = (quadPos.x * basisVector1 + quadPos.y * basisVector2) * basisViewport * 2.0;\r\n output.position = vec4<f32>(ndcPos.xy + ndcOffset, ndcPos.z, 1.0);\r\n \r\n // UV 输出 - 用 clipFactor 缩放以获得正确的 Gaussian 权重\r\n output.fragPos = quadPos * clipFactor;\r\n \r\n // 颜色已在 CPU 端预处理为 (dc * SH_C0 + 0.5),直接使用\r\n // 这是 3DGS 的标准颜色格式,在 sRGB 空间中\r\n output.color = splat.colorDC;\r\n output.opacity = adjustedOpacity;\r\n return output;\r\n}\r\n\r\n@fragment\r\nfn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {\r\n if input.opacity <= 0.0 { discard; }\r\n \r\n // A = 到中心的平方距离,在 UV 空间中\r\n // 由于 clipCorner 优化,fragPos 在 [-clip, clip] 范围内\r\n let A = dot(input.fragPos, input.fragPos);\r\n \r\n // 丢弃单位圆外的片段\r\n if A > 1.0 { discard; }\r\n \r\n // Normalized Gaussian 衰减 (精确匹配 SuperSplat normExp)\r\n // 关键修复: 在 A=1 (边界) 时返回精确的 0.0,消除边缘雾化\r\n // 在 A=0 (中心): weight = 1.0\r\n // 在 A=1 (边界): weight = 精确的 0.0 (而不是标准 exp(-4) ≈ 0.018)\r\n let weight = (exp(-4.0 * A) - EXP_NEG4) * INV_ONE_MINUS_EXP_NEG4;\r\n \r\n // 组合 splat 透明度\r\n let opacity = weight * input.opacity;\r\n \r\n // Alpha 阈值丢弃 (匹配 SuperSplat: if (alpha < 1.0 / 255.0) discard)\r\n if opacity < ALPHA_CULL_THRESHOLD { discard; }\r\n \r\n // 颜色 clamp 到有效范围 (防止负值)\r\n let color = max(input.color, vec3<f32>(0.0));\r\n \r\n // 预乘 alpha 输出 (匹配 blend mode: src=ONE, dst=ONE_MINUS_SRC_ALPHA)\r\n // 这是 3DGS 渲染的标准混合模式\r\n return vec4<f32>(color * opacity, opacity);\r\n}\r\n`;\r\n\r\n// 重新导出类型保持向后兼容\r\nexport { SHMode };\r\nexport type { BoundingBox };\r\n\r\nconst SPLAT_BYTE_SIZE = 256;\r\nconst SPLAT_FLOAT_COUNT = 64;\r\n\r\n/**\r\n * GSSplatRendererV2 - 优化的渲染器\r\n */\r\nexport class GSSplatRenderer implements IGSSplatRendererWithCapabilities {\r\n private renderer: Renderer;\r\n private camera: Camera;\r\n\r\n private pipeline!: GPURenderPipeline;\r\n private bindGroupLayout!: GPUBindGroupLayout;\r\n private uniformBuffer!: GPUBuffer;\r\n\r\n private splatBuffer: GPUBuffer | null = null;\r\n private splatCount: number = 0;\r\n private bindGroup: GPUBindGroup | null = null;\r\n\r\n private sorter: GSSplatSorter | null = null;\r\n private shMode: SHMode = SHMode.L0;\r\n private boundingBox: BoundingBox | null = null;\r\n\r\n // Transform\r\n private position: Vec3Tuple = [0, 0, 0];\r\n private rotation: Vec3Tuple = [0, 0, 0];\r\n private scale: Vec3Tuple = [1, 1, 1];\r\n private pivot: Vec3Tuple = [0, 0, 0];\r\n private modelMatrix: Float32Array = new Float32Array(16);\r\n\r\n // 剔除选项\r\n private pixelCullThreshold: number = 1.0;\r\n\r\n constructor(renderer: Renderer, camera: Camera) {\r\n this.renderer = renderer;\r\n this.camera = camera;\r\n this.createPipeline();\r\n this.createUniformBuffer();\r\n this.updateModelMatrix();\r\n }\r\n\r\n private createPipeline(): void {\r\n const device = this.renderer.device;\r\n\r\n const shaderModule = device.createShaderModule({\r\n code: gsOptimizedShader,\r\n });\r\n\r\n this.bindGroupLayout = device.createBindGroupLayout({\r\n entries: [\r\n { binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: \"uniform\" } },\r\n { binding: 1, visibility: GPUShaderStage.VERTEX, buffer: { type: \"read-only-storage\" } },\r\n { binding: 2, visibility: GPUShaderStage.VERTEX, buffer: { type: \"read-only-storage\" } },\r\n ],\r\n });\r\n\r\n const pipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [this.bindGroupLayout],\r\n });\r\n\r\n this.pipeline = device.createRenderPipeline({\r\n layout: pipelineLayout,\r\n vertex: {\r\n module: shaderModule,\r\n entryPoint: \"vs_main\",\r\n buffers: [],\r\n },\r\n fragment: {\r\n module: shaderModule,\r\n entryPoint: \"fs_main\",\r\n targets: [{\r\n format: this.renderer.format,\r\n blend: {\r\n color: {\r\n srcFactor: \"one\",\r\n dstFactor: \"one-minus-src-alpha\",\r\n operation: \"add\",\r\n },\r\n alpha: {\r\n srcFactor: \"one\",\r\n dstFactor: \"one-minus-src-alpha\",\r\n operation: \"add\",\r\n },\r\n },\r\n }],\r\n },\r\n primitive: {\r\n topology: \"triangle-strip\",\r\n },\r\n depthStencil: {\r\n format: this.renderer.depthFormat,\r\n depthWriteEnabled: false,\r\n depthCompare: \"always\",\r\n },\r\n });\r\n }\r\n\r\n private createUniformBuffer(): void {\r\n // view (64) + proj (64) + model (64) + cameraPos (12) + pad (4) + screenSize (8) + pad (8) = 224\r\n this.uniformBuffer = this.renderer.device.createBuffer({\r\n size: 224,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n }\r\n\r\n setPosition(x: number, y: number, z: number): void {\r\n this.position = [x, y, z];\r\n this.updateModelMatrix();\r\n }\r\n\r\n getPosition(): Vec3Tuple {\r\n return [...this.position];\r\n }\r\n\r\n setRotation(x: number, y: number, z: number): void {\r\n this.rotation = [x, y, z];\r\n this.updateModelMatrix();\r\n }\r\n\r\n getRotation(): Vec3Tuple {\r\n return [...this.rotation];\r\n }\r\n\r\n setScale(x: number, y: number, z: number): void {\r\n this.scale = [x, y, z];\r\n this.updateModelMatrix();\r\n }\r\n\r\n getScale(): Vec3Tuple {\r\n return [...this.scale];\r\n }\r\n\r\n setPivot(x: number, y: number, z: number): void {\r\n this.pivot = [x, y, z];\r\n this.updateModelMatrix();\r\n }\r\n\r\n getPivot(): Vec3Tuple {\r\n return [...this.pivot];\r\n }\r\n\r\n private updateModelMatrix(): void {\r\n const [tx, ty, tz] = this.position;\r\n const [rx, ry, rz] = this.rotation;\r\n const [sx, sy, sz] = this.scale;\r\n const [px, py, pz] = this.pivot;\r\n\r\n const cx = Math.cos(rx), sx1 = Math.sin(rx);\r\n const cy = Math.cos(ry), sy1 = Math.sin(ry);\r\n const cz = Math.cos(rz), sz1 = Math.sin(rz);\r\n\r\n const r00 = cy * cz;\r\n const r01 = sx1 * sy1 * cz - cx * sz1;\r\n const r02 = cx * sy1 * cz + sx1 * sz1;\r\n const r10 = cy * sz1;\r\n const r11 = sx1 * sy1 * sz1 + cx * cz;\r\n const r12 = cx * sy1 * sz1 - sx1 * cz;\r\n const r20 = -sy1;\r\n const r21 = sx1 * cy;\r\n const r22 = cx * cy;\r\n\r\n const rs00 = r00 * sx, rs01 = r01 * sy, rs02 = r02 * sz;\r\n const rs10 = r10 * sx, rs11 = r11 * sy, rs12 = r12 * sz;\r\n const rs20 = r20 * sx, rs21 = r21 * sy, rs22 = r22 * sz;\r\n\r\n const dpx = px - (rs00 * px + rs01 * py + rs02 * pz);\r\n const dpy = py - (rs10 * px + rs11 * py + rs12 * pz);\r\n const dpz = pz - (rs20 * px + rs21 * py + rs22 * pz);\r\n\r\n const finalTx = tx + dpx;\r\n const finalTy = ty + dpy;\r\n const finalTz = tz + dpz;\r\n\r\n this.modelMatrix[0] = rs00; this.modelMatrix[1] = rs10; this.modelMatrix[2] = rs20; this.modelMatrix[3] = 0;\r\n this.modelMatrix[4] = rs01; this.modelMatrix[5] = rs11; this.modelMatrix[6] = rs21; this.modelMatrix[7] = 0;\r\n this.modelMatrix[8] = rs02; this.modelMatrix[9] = rs12; this.modelMatrix[10] = rs22; this.modelMatrix[11] = 0;\r\n this.modelMatrix[12] = finalTx; this.modelMatrix[13] = finalTy; this.modelMatrix[14] = finalTz; this.modelMatrix[15] = 1;\r\n }\r\n\r\n getModelMatrix(): Float32Array {\r\n return this.modelMatrix;\r\n }\r\n\r\n setSHMode(mode: SHMode): void {\r\n this.shMode = mode;\r\n }\r\n\r\n getSHMode(): SHMode {\r\n return this.shMode;\r\n }\r\n\r\n setPixelCullThreshold(threshold: number): void {\r\n this.pixelCullThreshold = threshold;\r\n }\r\n\r\n setData(splats: SplatCPU[]): void {\r\n const device = this.renderer.device;\r\n\r\n if (this.splatBuffer) {\r\n this.splatBuffer.destroy();\r\n }\r\n if (this.sorter) {\r\n this.sorter.destroy();\r\n this.sorter = null;\r\n }\r\n\r\n this.splatCount = splats.length;\r\n\r\n if (this.splatCount === 0) {\r\n this.splatBuffer = null;\r\n this.bindGroup = null;\r\n this.boundingBox = null;\r\n return;\r\n }\r\n\r\n this.boundingBox = this.computeBoundingBox(splats);\r\n\r\n const data = new Float32Array(this.splatCount * SPLAT_FLOAT_COUNT);\r\n\r\n for (let i = 0; i < this.splatCount; i++) {\r\n const splat = splats[i];\r\n const offset = i * SPLAT_FLOAT_COUNT;\r\n\r\n data[offset + 0] = splat.mean[0];\r\n data[offset + 1] = splat.mean[1];\r\n data[offset + 2] = splat.mean[2];\r\n data[offset + 3] = 0;\r\n\r\n data[offset + 4] = splat.scale[0];\r\n data[offset + 5] = splat.scale[1];\r\n data[offset + 6] = splat.scale[2];\r\n data[offset + 7] = 0;\r\n\r\n data[offset + 8] = splat.rotation[0];\r\n data[offset + 9] = splat.rotation[1];\r\n data[offset + 10] = splat.rotation[2];\r\n data[offset + 11] = splat.rotation[3];\r\n\r\n data[offset + 12] = splat.colorDC[0];\r\n data[offset + 13] = splat.colorDC[1];\r\n data[offset + 14] = splat.colorDC[2];\r\n data[offset + 15] = splat.opacity;\r\n\r\n const shRest = splat.shRest;\r\n for (let j = 0; j < 9; j++) {\r\n data[offset + 16 + j] = shRest ? shRest[j] : 0;\r\n }\r\n for (let j = 0; j < 15; j++) {\r\n data[offset + 25 + j] = shRest ? shRest[9 + j] : 0;\r\n }\r\n for (let j = 0; j < 21; j++) {\r\n data[offset + 40 + j] = shRest ? shRest[24 + j] : 0;\r\n }\r\n data[offset + 61] = 0;\r\n data[offset + 62] = 0;\r\n data[offset + 63] = 0;\r\n }\r\n\r\n this.splatBuffer = device.createBuffer({\r\n size: data.byteLength,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n });\r\n\r\n device.queue.writeBuffer(this.splatBuffer, 0, data);\r\n\r\n this.sorter = new GSSplatSorter(\r\n device,\r\n this.splatCount,\r\n this.splatBuffer,\r\n this.uniformBuffer,\r\n );\r\n\r\n this.sorter.setScreenSize(this.renderer.width, this.renderer.height);\r\n this.sorter.setCullingOptions({\r\n nearPlane: this.camera.near,\r\n farPlane: this.camera.far,\r\n pixelThreshold: this.pixelCullThreshold,\r\n });\r\n\r\n this.bindGroup = device.createBindGroup({\r\n layout: this.bindGroupLayout,\r\n entries: [\r\n { binding: 0, resource: { buffer: this.uniformBuffer } },\r\n { binding: 1, resource: { buffer: this.splatBuffer } },\r\n { binding: 2, resource: { buffer: this.sorter.getIndicesBuffer() } },\r\n ],\r\n });\r\n }\r\n\r\n setCompactData(compactData: CompactSplatData): void {\r\n const device = this.renderer.device;\r\n\r\n if (this.splatBuffer) {\r\n this.splatBuffer.destroy();\r\n }\r\n if (this.sorter) {\r\n this.sorter.destroy();\r\n this.sorter = null;\r\n }\r\n\r\n this.splatCount = compactData.count;\r\n\r\n if (this.splatCount === 0) {\r\n this.splatBuffer = null;\r\n this.bindGroup = null;\r\n this.boundingBox = null;\r\n return;\r\n }\r\n\r\n this.boundingBox = this.computeBoundingBoxFromCompact(compactData);\r\n\r\n const includeSH = compactData.shCoeffs !== undefined;\r\n const gpuData = compactDataToGPUBuffer(compactData, includeSH);\r\n\r\n this.splatBuffer = device.createBuffer({\r\n size: gpuData.byteLength,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n });\r\n\r\n device.queue.writeBuffer(this.splatBuffer, 0, gpuData.buffer);\r\n\r\n this.sorter = new GSSplatSorter(\r\n device,\r\n this.splatCount,\r\n this.splatBuffer,\r\n this.uniformBuffer,\r\n );\r\n\r\n this.sorter.setScreenSize(this.renderer.width, this.renderer.height);\r\n this.sorter.setCullingOptions({\r\n nearPlane: this.camera.near,\r\n farPlane: this.camera.far,\r\n pixelThreshold: this.pixelCullThreshold,\r\n });\r\n\r\n this.bindGroup = device.createBindGroup({\r\n layout: this.bindGroupLayout,\r\n entries: [\r\n { binding: 0, resource: { buffer: this.uniformBuffer } },\r\n { binding: 1, resource: { buffer: this.splatBuffer } },\r\n { binding: 2, resource: { buffer: this.sorter.getIndicesBuffer() } },\r\n ],\r\n });\r\n }\r\n\r\n render(pass: GPURenderPassEncoder): void {\r\n if (this.splatCount === 0 || !this.bindGroup || !this.sorter) {\r\n return;\r\n }\r\n\r\n // 更新 uniforms\r\n this.renderer.device.queue.writeBuffer(\r\n this.uniformBuffer, 0,\r\n new Float32Array(this.camera.viewMatrix),\r\n );\r\n this.renderer.device.queue.writeBuffer(\r\n this.uniformBuffer, 64,\r\n new Float32Array(this.camera.projectionMatrix),\r\n );\r\n this.renderer.device.queue.writeBuffer(\r\n this.uniformBuffer, 128,\r\n new Float32Array(this.modelMatrix),\r\n );\r\n this.renderer.device.queue.writeBuffer(\r\n this.uniformBuffer, 192,\r\n new Float32Array(this.camera.position),\r\n );\r\n this.renderer.device.queue.writeBuffer(\r\n this.uniformBuffer, 208,\r\n new Float32Array([this.renderer.width, this.renderer.height, 0, 0]),\r\n );\r\n\r\n // 更新排序器参数\r\n this.sorter.setScreenSize(this.renderer.width, this.renderer.height);\r\n this.sorter.setCullingOptions({\r\n nearPlane: this.camera.near,\r\n farPlane: this.camera.far,\r\n pixelThreshold: this.pixelCullThreshold,\r\n });\r\n\r\n // 执行 GPU 排序\r\n this.sorter.sort();\r\n\r\n // 渲染\r\n pass.setPipeline(this.pipeline);\r\n pass.setBindGroup(0, this.bindGroup);\r\n pass.drawIndirect(this.sorter.getDrawIndirectBuffer(), 0);\r\n }\r\n\r\n getSplatCount(): number {\r\n return this.splatCount;\r\n }\r\n\r\n getBoundingBox(): BoundingBox | null {\r\n return this.boundingBox;\r\n }\r\n\r\n private computeBoundingBox(splats: SplatCPU[]): BoundingBox {\r\n if (splats.length === 0) {\r\n return { min: [0, 0, 0], max: [0, 0, 0], center: [0, 0, 0], radius: 0 };\r\n }\r\n\r\n const min: Vec3Tuple = [splats[0].mean[0], splats[0].mean[1], splats[0].mean[2]];\r\n const max: Vec3Tuple = [splats[0].mean[0], splats[0].mean[1], splats[0].mean[2]];\r\n\r\n for (let i = 1; i < splats.length; i++) {\r\n const [x, y, z] = splats[i].mean;\r\n min[0] = Math.min(min[0], x);\r\n min[1] = Math.min(min[1], y);\r\n min[2] = Math.min(min[2], z);\r\n max[0] = Math.max(max[0], x);\r\n max[1] = Math.max(max[1], y);\r\n max[2] = Math.max(max[2], z);\r\n }\r\n\r\n const center: Vec3Tuple = [\r\n (min[0] + max[0]) / 2,\r\n (min[1] + max[1]) / 2,\r\n (min[2] + max[2]) / 2,\r\n ];\r\n\r\n const dx = max[0] - min[0];\r\n const dy = max[1] - min[1];\r\n const dz = max[2] - min[2];\r\n const radius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min, max, center, radius };\r\n }\r\n\r\n private computeBoundingBoxFromCompact(data: CompactSplatData): BoundingBox {\r\n if (data.count === 0) {\r\n return { min: [0, 0, 0], max: [0, 0, 0], center: [0, 0, 0], radius: 0 };\r\n }\r\n\r\n const positions = data.positions;\r\n const min: Vec3Tuple = [positions[0], positions[1], positions[2]];\r\n const max: Vec3Tuple = [positions[0], positions[1], positions[2]];\r\n\r\n for (let i = 1; i < data.count; i++) {\r\n const x = positions[i * 3 + 0];\r\n const y = positions[i * 3 + 1];\r\n const z = positions[i * 3 + 2];\r\n min[0] = Math.min(min[0], x);\r\n min[1] = Math.min(min[1], y);\r\n min[2] = Math.min(min[2], z);\r\n max[0] = Math.max(max[0], x);\r\n max[1] = Math.max(max[1], y);\r\n max[2] = Math.max(max[2], z);\r\n }\r\n\r\n const center: Vec3Tuple = [\r\n (min[0] + max[0]) / 2,\r\n (min[1] + max[1]) / 2,\r\n (min[2] + max[2]) / 2,\r\n ];\r\n\r\n const dx = max[0] - min[0];\r\n const dy = max[1] - min[1];\r\n const dz = max[2] - min[2];\r\n const radius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min, max, center, radius };\r\n }\r\n\r\n supportsSHMode(mode: SHMode): boolean {\r\n return mode >= SHMode.L0 && mode <= SHMode.L3;\r\n }\r\n\r\n getCapabilities(): RendererCapabilities {\r\n return {\r\n maxSHMode: SHMode.L3,\r\n supportsRawData: true,\r\n isMobileOptimized: false,\r\n maxSplatCount: 0,\r\n };\r\n }\r\n\r\n destroy(): void {\r\n if (this.splatBuffer) {\r\n this.splatBuffer.destroy();\r\n this.splatBuffer = null;\r\n }\r\n if (this.sorter) {\r\n this.sorter.destroy();\r\n this.sorter = null;\r\n }\r\n this.uniformBuffer.destroy();\r\n this.splatCount = 0;\r\n this.bindGroup = null;\r\n }\r\n}\r\n","/**\r\n * TextureCompressor - 移动端纹理压缩工具\r\n * 将 splat 数据压缩为纹理格式,大幅减少 GPU 内存占用\r\n *\r\n * 内存对比:\r\n * - 原始 Storage Buffer: 256 bytes/splat\r\n * - 纹理压缩: ~52 bytes/splat (约 5x 压缩)\r\n * \r\n * 数据布局(保证精度):\r\n * - positionTexture (RGBA32Float): x, y, z, unused - 16 bytes\r\n * - scaleRotTexture1 (RGBA32Float): scale_x, scale_y, scale_z, rot_w - 16 bytes\r\n * - scaleRotTexture2 (RGBA32Float): rot_x, rot_y, rot_z, unused - 16 bytes\r\n * - colorTexture (RGBA8Unorm): r, g, b, opacity - 4 bytes\r\n * 总计: 52 bytes/splat\r\n * \r\n * 注意:使用 RGBA32Float 替代 RGBA16Float 以保证 scale 和 rotation 的精度,\r\n * 避免平面等细节渲染出现块状伪影。\r\n */\r\n\r\nimport { CompactSplatData } from \"./PLYLoaderMobile\";\r\n\r\n/**\r\n * 压缩后的纹理数据\r\n */\r\nexport interface CompressedSplatTextures {\r\n // 纹理尺寸\r\n width: number;\r\n height: number;\r\n count: number;\r\n\r\n // 位置纹理 (RGBA32Float) - 完整精度\r\n positionTexture: GPUTexture;\r\n\r\n // 缩放+旋转纹理 (RGBA32Float) - 保证精度\r\n // R: scale_x, G: scale_y, B: scale_z, A: rot_w\r\n scaleRotTexture1: GPUTexture;\r\n // R: rot_x, G: rot_y, B: rot_z, A: unused\r\n scaleRotTexture2: GPUTexture;\r\n\r\n // 颜色+不透明度纹理 (RGBA8Unorm)\r\n // R: color_r, G: color_g, B: color_b, A: opacity\r\n colorTexture: GPUTexture;\r\n\r\n // Bounding box (用于剔除优化)\r\n boundingBox: {\r\n min: [number, number, number];\r\n max: [number, number, number];\r\n };\r\n}\r\n\r\n/**\r\n * 计算纹理尺寸\r\n * 将 splat 数量映射到 2D 纹理尺寸\r\n * @param count splat 数量\r\n * @returns 纹理宽度和高度(向上取整到 4 的倍数)\r\n */\r\nexport function calculateTextureDimensions(count: number): { width: number; height: number } {\r\n if (count <= 0) {\r\n return { width: 4, height: 4 };\r\n }\r\n\r\n // 计算近似的正方形边长\r\n const side = Math.ceil(Math.sqrt(count));\r\n \r\n // 向上取整到 4 的倍数(GPU 纹理对齐优化)\r\n const alignedSide = Math.ceil(side / 4) * 4;\r\n \r\n // 确保能容纳所有 splat\r\n let width = alignedSide;\r\n let height = alignedSide;\r\n \r\n // 如果正方形不够,增加高度\r\n while (width * height < count) {\r\n height += 4;\r\n }\r\n\r\n return { width, height };\r\n}\r\n\r\n/**\r\n * 计算 bounding box\r\n */\r\nfunction computeBoundingBox(positions: Float32Array, count: number): {\r\n min: [number, number, number];\r\n max: [number, number, number];\r\n} {\r\n if (count === 0) {\r\n return {\r\n min: [0, 0, 0],\r\n max: [0, 0, 0],\r\n };\r\n }\r\n\r\n const min: [number, number, number] = [positions[0], positions[1], positions[2]];\r\n const max: [number, number, number] = [positions[0], positions[1], positions[2]];\r\n\r\n for (let i = 1; i < count; i++) {\r\n const x = positions[i * 3 + 0];\r\n const y = positions[i * 3 + 1];\r\n const z = positions[i * 3 + 2];\r\n\r\n min[0] = Math.min(min[0], x);\r\n min[1] = Math.min(min[1], y);\r\n min[2] = Math.min(min[2], z);\r\n max[0] = Math.max(max[0], x);\r\n max[1] = Math.max(max[1], y);\r\n max[2] = Math.max(max[2], z);\r\n }\r\n\r\n return { min, max };\r\n}\r\n\r\n/**\r\n * 将 splat 数据压缩为纹理格式\r\n * @param device GPU 设备\r\n * @param data 紧凑格式的 splat 数据\r\n * @returns 压缩后的纹理数据\r\n */\r\nexport function compressSplatsToTextures(\r\n device: GPUDevice,\r\n data: CompactSplatData\r\n): CompressedSplatTextures {\r\n const count = data.count;\r\n const { width, height } = calculateTextureDimensions(count);\r\n const totalPixels = width * height;\r\n\r\n // 计算 bounding box\r\n const boundingBox = computeBoundingBox(data.positions, count);\r\n\r\n // ============================================\r\n // 准备 CPU 端数据\r\n // ============================================\r\n\r\n // 位置纹理数据 (RGBA32Float) - 使用 Float32Array\r\n const positionData = new Float32Array(totalPixels * 4);\r\n\r\n // 缩放+旋转纹理数据 (RGBA32Float) - 使用 Float32Array 保证精度\r\n const scaleRotData1 = new Float32Array(totalPixels * 4);\r\n const scaleRotData2 = new Float32Array(totalPixels * 4);\r\n\r\n // 颜色纹理数据 (RGBA8Unorm)\r\n const colorData = new Uint8Array(totalPixels * 4);\r\n\r\n // ============================================\r\n // 填充数据\r\n // ============================================\r\n for (let i = 0; i < count; i++) {\r\n const pixelOffset = i * 4;\r\n\r\n // 位置数据 - 直接存储 float32\r\n positionData[pixelOffset + 0] = data.positions[i * 3 + 0];\r\n positionData[pixelOffset + 1] = data.positions[i * 3 + 1];\r\n positionData[pixelOffset + 2] = data.positions[i * 3 + 2];\r\n positionData[pixelOffset + 3] = 0; // unused\r\n\r\n // scaleRotTexture1: scale_x, scale_y, scale_z, rot_w (直接存储 float32)\r\n scaleRotData1[pixelOffset + 0] = data.scales[i * 3 + 0];\r\n scaleRotData1[pixelOffset + 1] = data.scales[i * 3 + 1];\r\n scaleRotData1[pixelOffset + 2] = data.scales[i * 3 + 2];\r\n scaleRotData1[pixelOffset + 3] = data.rotations[i * 4 + 0]; // rot_w\r\n\r\n // scaleRotTexture2: rot_x, rot_y, rot_z, unused (直接存储 float32)\r\n scaleRotData2[pixelOffset + 0] = data.rotations[i * 4 + 1]; // rot_x\r\n scaleRotData2[pixelOffset + 1] = data.rotations[i * 4 + 2]; // rot_y\r\n scaleRotData2[pixelOffset + 2] = data.rotations[i * 4 + 3]; // rot_z\r\n scaleRotData2[pixelOffset + 3] = 0; // unused\r\n\r\n // 颜色数据 (已经是 0-1 范围,转换为 0-255)\r\n const r = data.colors[i * 3 + 0];\r\n const g = data.colors[i * 3 + 1];\r\n const b = data.colors[i * 3 + 2];\r\n const opacity = data.opacities[i];\r\n\r\n colorData[pixelOffset + 0] = Math.round(Math.max(0, Math.min(1, r)) * 255);\r\n colorData[pixelOffset + 1] = Math.round(Math.max(0, Math.min(1, g)) * 255);\r\n colorData[pixelOffset + 2] = Math.round(Math.max(0, Math.min(1, b)) * 255);\r\n colorData[pixelOffset + 3] = Math.round(Math.max(0, Math.min(1, opacity)) * 255);\r\n }\r\n\r\n // ============================================\r\n // 创建 GPU 纹理\r\n // ============================================\r\n const textureUsage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST;\r\n\r\n // 位置纹理 (RGBA32Float) - 完整精度\r\n const positionTexture = device.createTexture({\r\n size: { width, height },\r\n format: \"rgba32float\",\r\n usage: textureUsage,\r\n });\r\n\r\n // 缩放+旋转纹理1 (RGBA32Float) - 保证精度\r\n const scaleRotTexture1 = device.createTexture({\r\n size: { width, height },\r\n format: \"rgba32float\",\r\n usage: textureUsage,\r\n });\r\n\r\n // 缩放+旋转纹理2 (RGBA32Float) - 保证精度\r\n const scaleRotTexture2 = device.createTexture({\r\n size: { width, height },\r\n format: \"rgba32float\",\r\n usage: textureUsage,\r\n });\r\n\r\n // 颜色纹理 (RGBA8Unorm)\r\n const colorTexture = device.createTexture({\r\n size: { width, height },\r\n format: \"rgba8unorm\",\r\n usage: textureUsage,\r\n });\r\n\r\n // ============================================\r\n // 上传数据到 GPU\r\n // ============================================\r\n \r\n // 位置纹理 (RGBA32Float = 16 bytes per pixel)\r\n device.queue.writeTexture(\r\n { texture: positionTexture },\r\n positionData,\r\n { bytesPerRow: width * 16 },\r\n { width, height }\r\n );\r\n\r\n // 缩放+旋转纹理1 (RGBA32Float = 16 bytes per pixel)\r\n device.queue.writeTexture(\r\n { texture: scaleRotTexture1 },\r\n scaleRotData1,\r\n { bytesPerRow: width * 16 },\r\n { width, height }\r\n );\r\n\r\n // 缩放+旋转纹理2 (RGBA32Float = 16 bytes per pixel)\r\n device.queue.writeTexture(\r\n { texture: scaleRotTexture2 },\r\n scaleRotData2,\r\n { bytesPerRow: width * 16 },\r\n { width, height }\r\n );\r\n\r\n // 颜色纹理 (RGBA8Unorm = 4 bytes per pixel)\r\n device.queue.writeTexture(\r\n { texture: colorTexture },\r\n colorData,\r\n { bytesPerRow: width * 4 },\r\n { width, height }\r\n );\r\n\r\n // 计算内存占用\r\n const memoryBytes = \r\n width * height * 16 + // positionTexture (RGBA32Float)\r\n width * height * 16 + // scaleRotTexture1 (RGBA32Float)\r\n width * height * 16 + // scaleRotTexture2 (RGBA32Float)\r\n width * height * 4; // colorTexture (RGBA8Unorm)\r\n const memoryMB = memoryBytes / (1024 * 1024);\r\n const bytesPerSplat = memoryBytes / count;\r\n\r\n return {\r\n width,\r\n height,\r\n count,\r\n positionTexture,\r\n scaleRotTexture1,\r\n scaleRotTexture2,\r\n colorTexture,\r\n boundingBox,\r\n };\r\n}\r\n\r\n/**\r\n * 销毁压缩纹理资源\r\n * @param textures 压缩纹理数据\r\n */\r\nexport function destroyCompressedTextures(textures: CompressedSplatTextures): void {\r\n textures.positionTexture.destroy();\r\n textures.scaleRotTexture1.destroy();\r\n textures.scaleRotTexture2.destroy();\r\n textures.colorTexture.destroy();\r\n}\r\n","/**\r\n * GSSplatSorterMobile - 移动端优化的 GPU 排序器\r\n *\r\n * 与主排序器的区别:\r\n * 1. 使用紧凑的位置数据(仅 xyz,无 scale/rotation)\r\n * 2. 简化的剔除逻辑(移除屏幕尺寸剔除)\r\n * 3. 针对 iOS 优化的桶数量\r\n */\r\n\r\n// 默认配置\r\nconst DEFAULT_NUM_BUCKETS = 65536;\r\nconst IOS_NUM_BUCKETS = 4096;\r\nconst WORKGROUP_SIZE = 256;\r\n\r\n/**\r\n * 排序器配置\r\n */\r\nexport interface SorterOptions {\r\n numBuckets?: number;\r\n}\r\n\r\n/**\r\n * 剔除选项\r\n */\r\nexport interface CullingOptions {\r\n nearPlane: number;\r\n farPlane: number;\r\n pixelThreshold: number;\r\n}\r\n\r\n/**\r\n * 检测是否为 iOS 设备\r\n */\r\nfunction isIOSDevice(): boolean {\r\n if (typeof navigator === \"undefined\") return false;\r\n const ua = navigator.userAgent || \"\";\r\n return (\r\n /iphone|ipad|ipod/i.test(ua.toLowerCase()) ||\r\n (navigator.platform === \"MacIntel\" && navigator.maxTouchPoints > 1)\r\n );\r\n}\r\n\r\n/**\r\n * 生成剔除 Shader(简化版,仅使用位置数据)\r\n */\r\nfunction generateCullingShaderCode(numBuckets: number): string {\r\n const bucketBits = Math.log2(numBuckets);\r\n\r\n return /* wgsl */ `\r\n/**\r\n * Pass 1: 剔除 + 深度计算 + 桶计数(移动端简化版)\r\n * 仅使用位置数据,不包含 scale 剔除\r\n */\r\n\r\nconst NUM_BUCKETS: u32 = ${numBuckets}u;\r\nconst BUCKET_MAX: u32 = ${numBuckets - 1}u;\r\n\r\nstruct CameraUniforms {\r\n view: mat4x4<f32>,\r\n proj: mat4x4<f32>,\r\n model: mat4x4<f32>,\r\n cameraPos: vec3<f32>,\r\n _pad: f32,\r\n}\r\n\r\nstruct CullingParams {\r\n splatCount: u32,\r\n nearPlane: f32,\r\n farPlane: f32,\r\n screenWidth: f32,\r\n screenHeight: f32,\r\n pixelThreshold: f32,\r\n _pad0: f32,\r\n _pad1: f32,\r\n}\r\n\r\nstruct Counters {\r\n visibleCount: atomic<u32>,\r\n}\r\n\r\n// 位置数据:紧密打包格式 [x0,y0,z0,x1,y1,z1,...]\r\n// 注意:不使用 array<vec3<f32>> 因为 vec3 有 16 字节对齐要求\r\n@group(0) @binding(0) var<storage, read> positions: array<f32>;\r\n@group(0) @binding(1) var<uniform> camera: CameraUniforms;\r\n@group(0) @binding(2) var<uniform> params: CullingParams;\r\n@group(0) @binding(3) var<storage, read_write> counters: Counters;\r\n@group(0) @binding(4) var<storage, read_write> visibleIndices: array<u32>;\r\n@group(0) @binding(5) var<storage, read_write> depthKeys: array<u32>;\r\n@group(0) @binding(6) var<storage, read_write> bucketCounts: array<atomic<u32>>;\r\n@group(0) @binding(7) var<storage, read_write> drawIndirect: array<u32>;\r\n\r\n@compute @workgroup_size(${WORKGROUP_SIZE})\r\nfn cullAndCount(@builtin(global_invocation_id) gid: vec3<u32>) {\r\n let i = gid.x;\r\n if (i >= params.splatCount) {\r\n return;\r\n }\r\n \r\n // 手动读取位置(避免 vec3 对齐问题)\r\n let base = i * 3u;\r\n let position = vec3<f32>(positions[base], positions[base + 1u], positions[base + 2u]);\r\n // 先应用模型矩阵变换到世界空间,再变换到视图空间\r\n let worldPos = camera.model * vec4<f32>(position, 1.0);\r\n let viewPos = camera.view * worldPos;\r\n let z = -viewPos.z;\r\n \r\n // 近平面剔除\r\n if (z < params.nearPlane) {\r\n return;\r\n }\r\n \r\n // 远平面剔除\r\n if (z > params.farPlane) {\r\n return;\r\n }\r\n \r\n // 视锥剔除(简化版,不考虑 splat 半径)\r\n let fx = camera.proj[0][0];\r\n let fy = camera.proj[1][1];\r\n let x_ndc = viewPos.x * fx / z;\r\n let y_ndc = viewPos.y * fy / z;\r\n \r\n // 放宽边界以避免边缘裁剪\r\n let margin: f32 = 0.5;\r\n if (x_ndc < -1.0 - margin || x_ndc > 1.0 + margin) {\r\n return;\r\n }\r\n if (y_ndc < -1.0 - margin || y_ndc > 1.0 + margin) {\r\n return;\r\n }\r\n \r\n // 通过剔除,计算深度桶\r\n let depthRange = params.farPlane - params.nearPlane;\r\n let normalizedDepth = clamp((z - params.nearPlane) / depthRange, 0.0, 1.0);\r\n let depthBucket = BUCKET_MAX - u32(normalizedDepth * f32(BUCKET_MAX));\r\n let depthKey = (depthBucket << ${32 - bucketBits}u) | (i & ${(1 << (32 - bucketBits)) - 1}u);\r\n \r\n // 分配可见索引位置\r\n let visibleIdx = atomicAdd(&counters.visibleCount, 1u);\r\n visibleIndices[visibleIdx] = i;\r\n depthKeys[visibleIdx] = depthKey;\r\n \r\n // 统计桶计数\r\n atomicAdd(&bucketCounts[depthBucket], 1u);\r\n}\r\n\r\n@compute @workgroup_size(1)\r\nfn resetCounters() {\r\n atomicStore(&counters.visibleCount, 0u);\r\n}\r\n\r\n@compute @workgroup_size(${WORKGROUP_SIZE})\r\nfn resetBucketCounts(@builtin(global_invocation_id) gid: vec3<u32>) {\r\n let i = gid.x;\r\n if (i < NUM_BUCKETS) {\r\n atomicStore(&bucketCounts[i], 0u);\r\n }\r\n}\r\n\r\n@compute @workgroup_size(1)\r\nfn updateDrawIndirect() {\r\n let count = atomicLoad(&counters.visibleCount);\r\n drawIndirect[0] = 4u;\r\n drawIndirect[1] = count;\r\n drawIndirect[2] = 0u;\r\n drawIndirect[3] = 0u;\r\n}\r\n`;\r\n}\r\n\r\n/**\r\n * 生成前缀和 Shader\r\n */\r\nfunction generatePrefixSumShaderCode(numBuckets: number): string {\r\n return /* wgsl */ `\r\nconst NUM_BUCKETS: u32 = ${numBuckets}u;\r\n\r\n@group(0) @binding(0) var<storage, read_write> bucketCounts: array<u32>;\r\n@group(0) @binding(1) var<storage, read_write> bucketOffsets: array<u32>;\r\n\r\n@compute @workgroup_size(1)\r\nfn prefixSum() {\r\n var sum = 0u;\r\n for (var i = 0u; i < NUM_BUCKETS; i++) {\r\n bucketOffsets[i] = sum;\r\n sum += bucketCounts[i];\r\n }\r\n}\r\n`;\r\n}\r\n\r\n/**\r\n * 生成散射 Shader\r\n */\r\nfunction generateScatterShaderCode(numBuckets: number): string {\r\n const bucketBits = Math.log2(numBuckets);\r\n\r\n return /* wgsl */ `\r\nconst NUM_BUCKETS: u32 = ${numBuckets}u;\r\n\r\nstruct Counters {\r\n visibleCount: u32,\r\n}\r\n\r\n@group(0) @binding(0) var<storage, read> visibleIndices: array<u32>;\r\n@group(0) @binding(1) var<storage, read> depthKeys: array<u32>;\r\n@group(0) @binding(2) var<storage, read> bucketOffsets: array<u32>;\r\n@group(0) @binding(3) var<storage, read_write> bucketPositions: array<atomic<u32>>;\r\n@group(0) @binding(4) var<storage, read_write> sortedIndices: array<u32>;\r\n@group(0) @binding(5) var<storage, read> counters: Counters;\r\n\r\n@compute @workgroup_size(${WORKGROUP_SIZE})\r\nfn scatter(@builtin(global_invocation_id) gid: vec3<u32>) {\r\n let i = gid.x;\r\n if (i >= counters.visibleCount) {\r\n return;\r\n }\r\n \r\n let depthKey = depthKeys[i];\r\n let bucket = depthKey >> ${32 - bucketBits}u;\r\n let baseOffset = bucketOffsets[bucket];\r\n let localOffset = atomicAdd(&bucketPositions[bucket], 1u);\r\n let finalIdx = baseOffset + localOffset;\r\n \r\n sortedIndices[finalIdx] = visibleIndices[i];\r\n}\r\n\r\n@compute @workgroup_size(${WORKGROUP_SIZE})\r\nfn resetBucketPositions(@builtin(global_invocation_id) gid: vec3<u32>) {\r\n let i = gid.x;\r\n if (i < NUM_BUCKETS) {\r\n atomicStore(&bucketPositions[i], 0u);\r\n }\r\n}\r\n`;\r\n}\r\n\r\n/**\r\n * GSSplatSorterMobile - 移动端排序器\r\n */\r\nexport class GSSplatSorterMobile {\r\n private device: GPUDevice;\r\n private splatCount: number;\r\n\r\n // Buffers\r\n private cullingParamsBuffer: GPUBuffer;\r\n private countersBuffer: GPUBuffer;\r\n private visibleIndicesBuffer: GPUBuffer;\r\n private depthKeysBuffer: GPUBuffer;\r\n private bucketCountsBuffer: GPUBuffer;\r\n private bucketOffsetsBuffer: GPUBuffer;\r\n private bucketPositionsBuffer: GPUBuffer;\r\n private sortedIndicesBuffer: GPUBuffer;\r\n private drawIndirectBuffer: GPUBuffer;\r\n\r\n // Pipelines\r\n private resetCountersPipeline: GPUComputePipeline;\r\n private resetBucketCountsPipeline: GPUComputePipeline;\r\n private cullAndCountPipeline: GPUComputePipeline;\r\n private updateDrawIndirectPipeline: GPUComputePipeline;\r\n private prefixSumPipeline: GPUComputePipeline;\r\n private resetBucketPositionsPipeline: GPUComputePipeline;\r\n private scatterPipeline: GPUComputePipeline;\r\n\r\n // Bind Groups\r\n private cullingBindGroupLayout: GPUBindGroupLayout;\r\n private cullingBindGroup: GPUBindGroup;\r\n private prefixSumBindGroupLayout: GPUBindGroupLayout;\r\n private prefixSumBindGroup: GPUBindGroup;\r\n private scatterBindGroupLayout: GPUBindGroupLayout;\r\n private scatterBindGroup: GPUBindGroup;\r\n\r\n private readonly WORKGROUP_SIZE = WORKGROUP_SIZE;\r\n private readonly numBuckets: number;\r\n\r\n // 屏幕信息\r\n private screenWidth: number = 1920;\r\n private screenHeight: number = 1080;\r\n\r\n // 剔除选项\r\n private cullingOptions: CullingOptions = {\r\n nearPlane: 0.1,\r\n farPlane: 1000,\r\n pixelThreshold: 1.0,\r\n };\r\n\r\n constructor(\r\n device: GPUDevice,\r\n splatCount: number,\r\n positionsBuffer: GPUBuffer, // 紧凑位置数据\r\n cameraBuffer: GPUBuffer,\r\n options: SorterOptions = {}\r\n ) {\r\n this.device = device;\r\n this.splatCount = splatCount;\r\n\r\n const isIOS = isIOSDevice();\r\n this.numBuckets = options.numBuckets ?? (isIOS ? IOS_NUM_BUCKETS : DEFAULT_NUM_BUCKETS);\r\n\r\n // 创建 Shader 模块\r\n const cullingModule = device.createShaderModule({\r\n code: generateCullingShaderCode(this.numBuckets),\r\n label: \"mobile-culling-shader\",\r\n });\r\n\r\n const prefixSumModule = device.createShaderModule({\r\n code: generatePrefixSumShaderCode(this.numBuckets),\r\n label: \"mobile-prefix-sum-shader\",\r\n });\r\n\r\n const scatterModule = device.createShaderModule({\r\n code: generateScatterShaderCode(this.numBuckets),\r\n label: \"mobile-scatter-shader\",\r\n });\r\n\r\n // 创建 Buffers\r\n this.cullingParamsBuffer = device.createBuffer({\r\n size: 32,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n\r\n this.countersBuffer = device.createBuffer({\r\n size: 16,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC,\r\n });\r\n\r\n this.visibleIndicesBuffer = device.createBuffer({\r\n size: splatCount * 4,\r\n usage: GPUBufferUsage.STORAGE,\r\n });\r\n\r\n this.depthKeysBuffer = device.createBuffer({\r\n size: splatCount * 4,\r\n usage: GPUBufferUsage.STORAGE,\r\n });\r\n\r\n this.bucketCountsBuffer = device.createBuffer({\r\n size: this.numBuckets * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n });\r\n\r\n this.bucketOffsetsBuffer = device.createBuffer({\r\n size: this.numBuckets * 4,\r\n usage: GPUBufferUsage.STORAGE,\r\n });\r\n\r\n this.bucketPositionsBuffer = device.createBuffer({\r\n size: this.numBuckets * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n });\r\n\r\n this.sortedIndicesBuffer = device.createBuffer({\r\n size: splatCount * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\r\n });\r\n\r\n this.drawIndirectBuffer = device.createBuffer({\r\n size: 16,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.INDIRECT | GPUBufferUsage.COPY_DST,\r\n });\r\n\r\n // 创建 Bind Group Layouts 和 Pipelines\r\n // Culling bind group layout\r\n this.cullingBindGroupLayout = device.createBindGroupLayout({\r\n entries: [\r\n { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"uniform\" } },\r\n { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"uniform\" } },\r\n { binding: 3, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 4, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 5, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 6, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 7, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n ],\r\n });\r\n\r\n const cullingPipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [this.cullingBindGroupLayout],\r\n });\r\n\r\n this.resetCountersPipeline = device.createComputePipeline({\r\n layout: cullingPipelineLayout,\r\n compute: { module: cullingModule, entryPoint: \"resetCounters\" },\r\n });\r\n\r\n this.resetBucketCountsPipeline = device.createComputePipeline({\r\n layout: cullingPipelineLayout,\r\n compute: { module: cullingModule, entryPoint: \"resetBucketCounts\" },\r\n });\r\n\r\n this.cullAndCountPipeline = device.createComputePipeline({\r\n layout: cullingPipelineLayout,\r\n compute: { module: cullingModule, entryPoint: \"cullAndCount\" },\r\n });\r\n\r\n this.updateDrawIndirectPipeline = device.createComputePipeline({\r\n layout: cullingPipelineLayout,\r\n compute: { module: cullingModule, entryPoint: \"updateDrawIndirect\" },\r\n });\r\n\r\n // Prefix sum bind group layout\r\n this.prefixSumBindGroupLayout = device.createBindGroupLayout({\r\n entries: [\r\n { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n ],\r\n });\r\n\r\n const prefixSumPipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [this.prefixSumBindGroupLayout],\r\n });\r\n\r\n this.prefixSumPipeline = device.createComputePipeline({\r\n layout: prefixSumPipelineLayout,\r\n compute: { module: prefixSumModule, entryPoint: \"prefixSum\" },\r\n });\r\n\r\n // Scatter bind group layout\r\n this.scatterBindGroupLayout = device.createBindGroupLayout({\r\n entries: [\r\n { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 3, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 4, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 5, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n ],\r\n });\r\n\r\n const scatterPipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [this.scatterBindGroupLayout],\r\n });\r\n\r\n this.scatterPipeline = device.createComputePipeline({\r\n layout: scatterPipelineLayout,\r\n compute: { module: scatterModule, entryPoint: \"scatter\" },\r\n });\r\n\r\n this.resetBucketPositionsPipeline = device.createComputePipeline({\r\n layout: scatterPipelineLayout,\r\n compute: { module: scatterModule, entryPoint: \"resetBucketPositions\" },\r\n });\r\n\r\n // 创建 Bind Groups\r\n this.cullingBindGroup = device.createBindGroup({\r\n layout: this.cullingBindGroupLayout,\r\n entries: [\r\n { binding: 0, resource: { buffer: positionsBuffer } },\r\n { binding: 1, resource: { buffer: cameraBuffer } },\r\n { binding: 2, resource: { buffer: this.cullingParamsBuffer } },\r\n { binding: 3, resource: { buffer: this.countersBuffer } },\r\n { binding: 4, resource: { buffer: this.visibleIndicesBuffer } },\r\n { binding: 5, resource: { buffer: this.depthKeysBuffer } },\r\n { binding: 6, resource: { buffer: this.bucketCountsBuffer } },\r\n { binding: 7, resource: { buffer: this.drawIndirectBuffer } },\r\n ],\r\n });\r\n\r\n this.prefixSumBindGroup = device.createBindGroup({\r\n layout: this.prefixSumBindGroupLayout,\r\n entries: [\r\n { binding: 0, resource: { buffer: this.bucketCountsBuffer } },\r\n { binding: 1, resource: { buffer: this.bucketOffsetsBuffer } },\r\n ],\r\n });\r\n\r\n this.scatterBindGroup = device.createBindGroup({\r\n layout: this.scatterBindGroupLayout,\r\n entries: [\r\n { binding: 0, resource: { buffer: this.visibleIndicesBuffer } },\r\n { binding: 1, resource: { buffer: this.depthKeysBuffer } },\r\n { binding: 2, resource: { buffer: this.bucketOffsetsBuffer } },\r\n { binding: 3, resource: { buffer: this.bucketPositionsBuffer } },\r\n { binding: 4, resource: { buffer: this.sortedIndicesBuffer } },\r\n { binding: 5, resource: { buffer: this.countersBuffer } },\r\n ],\r\n });\r\n }\r\n\r\n /**\r\n * 设置屏幕尺寸\r\n */\r\n setScreenSize(width: number, height: number): void {\r\n this.screenWidth = width;\r\n this.screenHeight = height;\r\n }\r\n\r\n /**\r\n * 设置剔除选项\r\n */\r\n setCullingOptions(options: Partial<CullingOptions>): void {\r\n this.cullingOptions = { ...this.cullingOptions, ...options };\r\n }\r\n\r\n /**\r\n * 执行排序\r\n */\r\n sort(): void {\r\n try {\r\n // 更新剔除参数\r\n const cullingParamsData = new ArrayBuffer(32);\r\n const cullingParamsView = new DataView(cullingParamsData);\r\n cullingParamsView.setUint32(0, this.splatCount, true);\r\n cullingParamsView.setFloat32(4, this.cullingOptions.nearPlane, true);\r\n cullingParamsView.setFloat32(8, this.cullingOptions.farPlane, true);\r\n cullingParamsView.setFloat32(12, this.screenWidth, true);\r\n cullingParamsView.setFloat32(16, this.screenHeight, true);\r\n cullingParamsView.setFloat32(20, this.cullingOptions.pixelThreshold, true);\r\n cullingParamsView.setFloat32(24, 0, true);\r\n cullingParamsView.setFloat32(28, 0, true);\r\n this.device.queue.writeBuffer(this.cullingParamsBuffer, 0, cullingParamsData);\r\n\r\n const cullWorkgroupCount = Math.ceil(this.splatCount / this.WORKGROUP_SIZE);\r\n const bucketResetWorkgroups = Math.ceil(this.numBuckets / this.WORKGROUP_SIZE);\r\n\r\n const encoder = this.device.createCommandEncoder();\r\n\r\n // Pass 1: 重置计数器\r\n {\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(this.resetCountersPipeline);\r\n pass.setBindGroup(0, this.cullingBindGroup);\r\n pass.dispatchWorkgroups(1);\r\n pass.end();\r\n }\r\n\r\n // Pass 2: 重置桶计数\r\n {\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(this.resetBucketCountsPipeline);\r\n pass.setBindGroup(0, this.cullingBindGroup);\r\n pass.dispatchWorkgroups(bucketResetWorkgroups);\r\n pass.end();\r\n }\r\n\r\n // Pass 3: 剔除 + 深度计算 + 桶计数\r\n {\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(this.cullAndCountPipeline);\r\n pass.setBindGroup(0, this.cullingBindGroup);\r\n pass.dispatchWorkgroups(cullWorkgroupCount);\r\n pass.end();\r\n }\r\n\r\n // Pass 4: 更新 DrawIndirect\r\n {\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(this.updateDrawIndirectPipeline);\r\n pass.setBindGroup(0, this.cullingBindGroup);\r\n pass.dispatchWorkgroups(1);\r\n pass.end();\r\n }\r\n\r\n // Pass 5: 前缀和\r\n {\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(this.prefixSumPipeline);\r\n pass.setBindGroup(0, this.prefixSumBindGroup);\r\n pass.dispatchWorkgroups(1);\r\n pass.end();\r\n }\r\n\r\n // Pass 6: 重置桶位置计数\r\n {\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(this.resetBucketPositionsPipeline);\r\n pass.setBindGroup(0, this.scatterBindGroup);\r\n pass.dispatchWorkgroups(bucketResetWorkgroups);\r\n pass.end();\r\n }\r\n\r\n // Pass 7: 散射到最终位置\r\n {\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(this.scatterPipeline);\r\n pass.setBindGroup(0, this.scatterBindGroup);\r\n pass.dispatchWorkgroups(cullWorkgroupCount);\r\n pass.end();\r\n }\r\n\r\n this.device.queue.submit([encoder.finish()]);\r\n } catch (error) {\r\n // 排序错误(静默处理)\r\n }\r\n }\r\n\r\n /**\r\n * 获取排序后的索引 buffer\r\n */\r\n getIndicesBuffer(): GPUBuffer {\r\n return this.sortedIndicesBuffer;\r\n }\r\n\r\n /**\r\n * 获取 DrawIndirect buffer\r\n */\r\n getDrawIndirectBuffer(): GPUBuffer {\r\n return this.drawIndirectBuffer;\r\n }\r\n\r\n /**\r\n * 获取 splat 数量\r\n */\r\n getSplatCount(): number {\r\n return this.splatCount;\r\n }\r\n\r\n /**\r\n * 销毁资源\r\n */\r\n destroy(): void {\r\n this.cullingParamsBuffer.destroy();\r\n this.countersBuffer.destroy();\r\n this.visibleIndicesBuffer.destroy();\r\n this.depthKeysBuffer.destroy();\r\n this.bucketCountsBuffer.destroy();\r\n this.bucketOffsetsBuffer.destroy();\r\n this.bucketPositionsBuffer.destroy();\r\n this.sortedIndicesBuffer.destroy();\r\n this.drawIndirectBuffer.destroy();\r\n }\r\n}\r\n","/**\r\n * GSSplatRendererMobile - 移动端优化的 3D Gaussian Splatting 渲染器\r\n *\r\n * 优化特点:\r\n * 1. 使用纹理存储 splat 数据,减少 GPU 内存占用 (~52 bytes/splat vs 256 bytes)\r\n * 2. 仅支持 L0 模式(无 SH 计算)\r\n * 3. 从纹理采样获取 splat 属性(使用 RGBA32Float 保证精度)\r\n * 4. 使用简化的排序器\r\n */\r\n\r\nimport { Renderer } from \"../core/Renderer\";\r\nimport { Camera } from \"../core/Camera\";\r\nimport { CompactSplatData } from \"./PLYLoaderMobile\";\r\nimport {\r\n CompressedSplatTextures,\r\n compressSplatsToTextures,\r\n destroyCompressedTextures,\r\n} from \"./TextureCompressor\";\r\nimport { GSSplatSorterMobile } from \"./GSSplatSorterMobile\";\r\nimport type { BoundingBox, Vec3Tuple } from \"../types\";\r\nimport { SHMode, RendererCapabilities } from \"../types\";\r\nimport type { IGSSplatRenderer, IGSSplatRendererWithCapabilities } from \"./IGSSplatRenderer\";\r\n\r\n// 重新导出类型以保持向后兼容\r\nexport type { BoundingBox };\r\n\r\n// ============================================\r\n// 移动端 L0 Shader - 从纹理采样数据(简化版)\r\n// ============================================\r\nconst shaderCodeMobileL0 = /* wgsl */ `\r\nstruct Uniforms {\r\n view: mat4x4<f32>,\r\n proj: mat4x4<f32>,\r\n model: mat4x4<f32>,\r\n cameraPos: vec3<f32>,\r\n _pad: f32,\r\n screenSize: vec2<f32>,\r\n _pad2: vec2<f32>,\r\n textureSize: vec2<f32>, // 纹理尺寸 (用于坐标计算)\r\n _pad3: vec2<f32>,\r\n}\r\n\r\n@group(0) @binding(0) var<uniform> uniforms: Uniforms;\r\n@group(0) @binding(1) var<storage, read> sortedIndices: array<u32>;\r\n\r\n// 纹理绑定 - 4 张纹理(使用 RGBA32Float 保证精度)\r\n@group(1) @binding(0) var positionTex: texture_2d<f32>; // RGBA32Float: xyz + unused\r\n@group(1) @binding(1) var scaleRotTex1: texture_2d<f32>; // RGBA32Float: scale_xyz + rot_w\r\n@group(1) @binding(2) var scaleRotTex2: texture_2d<f32>; // RGBA32Float: rot_xyz + unused\r\n@group(1) @binding(3) var colorTex: texture_2d<f32>; // RGBA8Unorm: rgb + opacity\r\n\r\nstruct VertexOutput {\r\n @builtin(position) position: vec4<f32>,\r\n @location(0) localUV: vec2<f32>,\r\n @location(1) color: vec3<f32>,\r\n @location(2) opacity: f32,\r\n}\r\n\r\nconst QUAD_POSITIONS = array<vec2<f32>, 4>(\r\n vec2<f32>(-1.0, -1.0),\r\n vec2<f32>( 1.0, -1.0),\r\n vec2<f32>(-1.0, 1.0),\r\n vec2<f32>( 1.0, 1.0),\r\n);\r\n\r\nconst ELLIPSE_SCALE: f32 = 3.0;\r\n\r\n// 将索引转换为纹理坐标\r\nfn indexToTexCoord(index: u32) -> vec2<u32> {\r\n let texWidth = u32(uniforms.textureSize.x);\r\n let x = index % texWidth;\r\n let y = index / texWidth;\r\n return vec2<u32>(x, y);\r\n}\r\n\r\n// 四元数转旋转矩阵\r\nfn quatToMat3(q: vec4<f32>) -> mat3x3<f32> {\r\n let w = q[0]; let x = q[1]; let y = q[2]; let z = q[3];\r\n let x2 = x + x; let y2 = y + y; let z2 = z + z;\r\n let xx = x * x2; let xy = x * y2; let xz = x * z2;\r\n let yy = y * y2; let yz = y * z2; let zz = z * z2;\r\n let wx = w * x2; let wy = w * y2; let wz = w * z2;\r\n return mat3x3<f32>(\r\n vec3<f32>(1.0 - (yy + zz), xy + wz, xz - wy),\r\n vec3<f32>(xy - wz, 1.0 - (xx + zz), yz + wx),\r\n vec3<f32>(xz + wy, yz - wx, 1.0 - (xx + yy))\r\n );\r\n}\r\n\r\n// 从模型矩阵提取统一缩放因子(取 X 轴向量长度)\r\nfn getModelScale(model: mat4x4<f32>) -> f32 {\r\n return length(model[0].xyz);\r\n}\r\n\r\n// 计算 2D 协方差\r\nfn computeCov2D(mean: vec3<f32>, scale: vec3<f32>, rotation: vec4<f32>, modelView: mat4x4<f32>, proj: mat4x4<f32>, modelScale: f32) -> vec3<f32> {\r\n let R = quatToMat3(rotation);\r\n // 应用模型缩放到 splat scale\r\n let scaledScale = scale * modelScale;\r\n let s2 = scaledScale * scaledScale;\r\n let M = mat3x3<f32>(R[0] * s2.x, R[1] * s2.y, R[2] * s2.z);\r\n let Sigma = M * transpose(R);\r\n let viewPos = (modelView * vec4<f32>(mean, 1.0)).xyz;\r\n let viewRot = mat3x3<f32>(modelView[0].xyz, modelView[1].xyz, modelView[2].xyz);\r\n let SigmaView = viewRot * Sigma * transpose(viewRot);\r\n let fx = proj[0][0]; let fy = proj[1][1];\r\n let z = -viewPos.z;\r\n let z_clamped = max(z, 0.001);\r\n let z2 = z_clamped * z_clamped;\r\n // 雅可比矩阵: 从相机坐标 (x_cam, y_cam, z_cam) 到 NDC 的偏导数\r\n // x_ndc = fx * x_cam / (-z_cam), 所以 dx_ndc/dz_cam = fx * x_cam / z_cam^2 (正号!)\r\n let j1 = vec3<f32>(fx / z_clamped, 0.0, fx * viewPos.x / z2);\r\n let j2 = vec3<f32>(0.0, fy / z_clamped, fy * viewPos.y / z2);\r\n let Sj1 = SigmaView * j1;\r\n let Sj2 = SigmaView * j2;\r\n return vec3<f32>(dot(j1, Sj1), dot(j1, Sj2), dot(j2, Sj2));\r\n}\r\n\r\n// 计算椭圆轴\r\nfn computeEllipseAxes(cov2D: vec3<f32>) -> mat2x2<f32> {\r\n let a = cov2D.x; let b = cov2D.y; let c = cov2D.z;\r\n let trace = a + c;\r\n let det = a * c - b * b;\r\n let disc = trace * trace - 4.0 * det;\r\n let sqrtDisc = sqrt(max(disc, 0.0));\r\n let lambda1 = max((trace + sqrtDisc) * 0.5, 0.0);\r\n let lambda2 = max((trace - sqrtDisc) * 0.5, 0.0);\r\n let r1 = sqrt(lambda1);\r\n let r2 = sqrt(lambda2);\r\n var axis1: vec2<f32>; var axis2: vec2<f32>;\r\n if (abs(b) > 1e-6) {\r\n axis1 = normalize(vec2<f32>(b, lambda1 - a));\r\n axis2 = vec2<f32>(-axis1.y, axis1.x);\r\n } else {\r\n if (a >= c) { axis1 = vec2<f32>(1.0, 0.0); axis2 = vec2<f32>(0.0, 1.0); }\r\n else { axis1 = vec2<f32>(0.0, 1.0); axis2 = vec2<f32>(1.0, 0.0); }\r\n }\r\n return mat2x2<f32>(axis1 * r1, axis2 * r2);\r\n}\r\n\r\n@vertex\r\nfn vs_main(@builtin(vertex_index) vertexIndex: u32, @builtin(instance_index) instanceIndex: u32) -> VertexOutput {\r\n var output: VertexOutput;\r\n \r\n // 获取排序后的索引\r\n let splatIndex = sortedIndices[instanceIndex];\r\n let texCoord = indexToTexCoord(splatIndex);\r\n \r\n // 从纹理采样位置数据(RGBA32Float,直接读取)\r\n let posSample = textureLoad(positionTex, texCoord, 0);\r\n let mean = posSample.xyz;\r\n \r\n // 从纹理采样缩放和旋转(RGBA16Float,GPU 自动转换为 f32)\r\n let scaleRot1 = textureLoad(scaleRotTex1, texCoord, 0);\r\n let scaleRot2 = textureLoad(scaleRotTex2, texCoord, 0);\r\n \r\n let scale = scaleRot1.xyz;\r\n let rotation = vec4<f32>(scaleRot1.w, scaleRot2.x, scaleRot2.y, scaleRot2.z);\r\n \r\n // 从纹理采样颜色(RGBA8Unorm,GPU 自动归一化到 0-1)\r\n let colorSample = textureLoad(colorTex, texCoord, 0);\r\n let color = colorSample.rgb;\r\n let opacity = colorSample.a;\r\n \r\n // 计算顶点位置\r\n let quadPos = QUAD_POSITIONS[vertexIndex];\r\n output.localUV = quadPos;\r\n \r\n // 计算 modelView 矩阵和模型缩放\r\n let modelView = uniforms.view * uniforms.model;\r\n let modelScale = getModelScale(uniforms.model);\r\n \r\n let cov2D = computeCov2D(mean, scale, rotation, modelView, uniforms.proj, modelScale);\r\n let axes = computeEllipseAxes(cov2D);\r\n let screenOffset = axes[0] * quadPos.x * ELLIPSE_SCALE + axes[1] * quadPos.y * ELLIPSE_SCALE;\r\n \r\n // 应用 model 变换到 splat 位置\r\n let worldPos = uniforms.model * vec4<f32>(mean, 1.0);\r\n let viewPos = uniforms.view * worldPos;\r\n var clipPos = uniforms.proj * viewPos;\r\n clipPos.x = clipPos.x + screenOffset.x * clipPos.w;\r\n clipPos.y = clipPos.y + screenOffset.y * clipPos.w;\r\n output.position = clipPos;\r\n output.color = color;\r\n output.opacity = opacity;\r\n \r\n return output;\r\n}\r\n\r\n@fragment\r\nfn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {\r\n let r = length(input.localUV);\r\n if (r > 1.0) { discard; }\r\n let gaussianWeight = exp(-r * r * 4.0);\r\n let alpha = input.opacity * gaussianWeight;\r\n if (alpha < 0.004) { discard; } // 丢弃几乎透明的像素\r\n let color = clamp(input.color, vec3<f32>(0.0), vec3<f32>(1.0));\r\n return vec4<f32>(color * alpha, alpha);\r\n}\r\n`;\r\n\r\n/**\r\n * GSSplatRendererMobile - 移动端优化渲染器\r\n * 实现 IGSSplatRenderer 接口\r\n */\r\nexport class GSSplatRendererMobile implements IGSSplatRendererWithCapabilities {\r\n private renderer: Renderer;\r\n private camera: Camera;\r\n\r\n // GPU 资源\r\n private pipeline!: GPURenderPipeline;\r\n private uniformBindGroupLayout!: GPUBindGroupLayout;\r\n private textureBindGroupLayout!: GPUBindGroupLayout;\r\n private uniformBuffer!: GPUBuffer;\r\n private uniformBindGroup: GPUBindGroup | null = null;\r\n private textureBindGroup: GPUBindGroup | null = null;\r\n\r\n // 压缩纹理数据\r\n private compressedTextures: CompressedSplatTextures | null = null;\r\n private splatCount: number = 0;\r\n\r\n // 排序器\r\n private sorter: GSSplatSorterMobile | null = null;\r\n\r\n // 位置缓冲区(用于排序)\r\n private positionsBuffer: GPUBuffer | null = null;\r\n\r\n // Bounding box\r\n private boundingBox: BoundingBox | null = null;\r\n\r\n // 帧计数(用于排序频率控制)\r\n private frameCount: number = 0;\r\n private sortEveryNFrames: number = 1;\r\n\r\n // ============================================\r\n // 变换相关 (position, rotation, scale)\r\n // ============================================\r\n private position: Vec3Tuple = [0, 0, 0];\r\n private rotation: Vec3Tuple = [0, 0, 0]; // Euler angles (radians)\r\n private scaleValue: Vec3Tuple = [1, 1, 1];\r\n private pivot: Vec3Tuple = [0, 0, 0]; // 旋转/缩放中心点\r\n private modelMatrix: Float32Array = new Float32Array(16); // 4x4 model matrix\r\n\r\n constructor(renderer: Renderer, camera: Camera) {\r\n this.renderer = renderer;\r\n this.camera = camera;\r\n\r\n this.createPipeline();\r\n this.createUniformBuffer();\r\n this.updateModelMatrix(); // 初始化模型矩阵为单位矩阵\r\n }\r\n\r\n // ============================================\r\n // Transform 方法\r\n // ============================================\r\n\r\n /**\r\n * 设置位置\r\n */\r\n setPosition(x: number, y: number, z: number): void {\r\n this.position = [x, y, z];\r\n this.updateModelMatrix();\r\n }\r\n\r\n /**\r\n * 获取位置\r\n */\r\n getPosition(): Vec3Tuple {\r\n return [...this.position];\r\n }\r\n\r\n /**\r\n * 设置旋转 (欧拉角, 弧度)\r\n */\r\n setRotation(x: number, y: number, z: number): void {\r\n this.rotation = [x, y, z];\r\n this.updateModelMatrix();\r\n }\r\n\r\n /**\r\n * 获取旋转\r\n */\r\n getRotation(): Vec3Tuple {\r\n return [...this.rotation];\r\n }\r\n\r\n /**\r\n * 设置缩放\r\n */\r\n setScale(x: number, y: number, z: number): void {\r\n this.scaleValue = [x, y, z];\r\n this.updateModelMatrix();\r\n }\r\n\r\n /**\r\n * 获取缩放\r\n */\r\n getScale(): Vec3Tuple {\r\n return [...this.scaleValue];\r\n }\r\n\r\n /**\r\n * 设置旋转/缩放中心点 (pivot)\r\n */\r\n setPivot(x: number, y: number, z: number): void {\r\n this.pivot = [x, y, z];\r\n this.updateModelMatrix();\r\n }\r\n\r\n /**\r\n * 获取旋转/缩放中心点 (pivot)\r\n */\r\n getPivot(): Vec3Tuple {\r\n return [...this.pivot];\r\n }\r\n\r\n /**\r\n * 更新模型矩阵\r\n * 变换顺序: T * Tp * R * S * Tp^-1\r\n * 即: 先移到原点,缩放,旋转,再移回pivot,最后应用用户平移\r\n */\r\n private updateModelMatrix(): void {\r\n const [tx, ty, tz] = this.position;\r\n const [rx, ry, rz] = this.rotation;\r\n const [sx, sy, sz] = this.scaleValue;\r\n const [px, py, pz] = this.pivot;\r\n\r\n // 计算旋转矩阵分量 (Euler XYZ 顺序)\r\n const cx = Math.cos(rx), sx1 = Math.sin(rx);\r\n const cy = Math.cos(ry), sy1 = Math.sin(ry);\r\n const cz = Math.cos(rz), sz1 = Math.sin(rz);\r\n\r\n // 组合旋转矩阵 R = Rz * Ry * Rx\r\n const r00 = cy * cz;\r\n const r01 = sx1 * sy1 * cz - cx * sz1;\r\n const r02 = cx * sy1 * cz + sx1 * sz1;\r\n const r10 = cy * sz1;\r\n const r11 = sx1 * sy1 * sz1 + cx * cz;\r\n const r12 = cx * sy1 * sz1 - sx1 * cz;\r\n const r20 = -sy1;\r\n const r21 = sx1 * cy;\r\n const r22 = cx * cy;\r\n\r\n // RS 矩阵 (旋转 * 缩放)\r\n const rs00 = r00 * sx, rs01 = r01 * sy, rs02 = r02 * sz;\r\n const rs10 = r10 * sx, rs11 = r11 * sy, rs12 = r12 * sz;\r\n const rs20 = r20 * sx, rs21 = r21 * sy, rs22 = r22 * sz;\r\n\r\n // 计算 (I - RS) * pivot\r\n const dpx = px - (rs00 * px + rs01 * py + rs02 * pz);\r\n const dpy = py - (rs10 * px + rs11 * py + rs12 * pz);\r\n const dpz = pz - (rs20 * px + rs21 * py + rs22 * pz);\r\n\r\n // 最终平移 = position + (I - RS) * pivot\r\n const finalTx = tx + dpx;\r\n const finalTy = ty + dpy;\r\n const finalTz = tz + dpz;\r\n\r\n // 模型矩阵 (列主序)\r\n this.modelMatrix[0] = rs00;\r\n this.modelMatrix[1] = rs10;\r\n this.modelMatrix[2] = rs20;\r\n this.modelMatrix[3] = 0;\r\n\r\n this.modelMatrix[4] = rs01;\r\n this.modelMatrix[5] = rs11;\r\n this.modelMatrix[6] = rs21;\r\n this.modelMatrix[7] = 0;\r\n\r\n this.modelMatrix[8] = rs02;\r\n this.modelMatrix[9] = rs12;\r\n this.modelMatrix[10] = rs22;\r\n this.modelMatrix[11] = 0;\r\n\r\n this.modelMatrix[12] = finalTx;\r\n this.modelMatrix[13] = finalTy;\r\n this.modelMatrix[14] = finalTz;\r\n this.modelMatrix[15] = 1;\r\n }\r\n\r\n /**\r\n * 获取当前模型矩阵\r\n */\r\n getModelMatrix(): Float32Array {\r\n return this.modelMatrix;\r\n }\r\n\r\n /**\r\n * 创建渲染管线\r\n */\r\n private createPipeline(): void {\r\n const device = this.renderer.device;\r\n\r\n // 创建 shader 模块\r\n const shaderModule = device.createShaderModule({\r\n code: shaderCodeMobileL0,\r\n label: \"mobile-splat-shader\",\r\n });\r\n\r\n // Uniform bind group layout (group 0)\r\n this.uniformBindGroupLayout = device.createBindGroupLayout({\r\n entries: [\r\n {\r\n binding: 0,\r\n visibility: GPUShaderStage.VERTEX,\r\n buffer: { type: \"uniform\" },\r\n },\r\n {\r\n binding: 1,\r\n visibility: GPUShaderStage.VERTEX,\r\n buffer: { type: \"read-only-storage\" },\r\n },\r\n ],\r\n });\r\n\r\n // Texture bind group layout (group 1) - 简化版 4 张纹理\r\n this.textureBindGroupLayout = device.createBindGroupLayout({\r\n entries: [\r\n {\r\n // positionTex (RGBA32Float)\r\n binding: 0,\r\n visibility: GPUShaderStage.VERTEX,\r\n texture: { sampleType: \"unfilterable-float\" },\r\n },\r\n {\r\n // scaleRotTex1 (RGBA32Float)\r\n binding: 1,\r\n visibility: GPUShaderStage.VERTEX,\r\n texture: { sampleType: \"unfilterable-float\" },\r\n },\r\n {\r\n // scaleRotTex2 (RGBA32Float)\r\n binding: 2,\r\n visibility: GPUShaderStage.VERTEX,\r\n texture: { sampleType: \"unfilterable-float\" },\r\n },\r\n {\r\n // colorTex (RGBA8Unorm)\r\n binding: 3,\r\n visibility: GPUShaderStage.VERTEX,\r\n texture: { sampleType: \"unfilterable-float\" },\r\n },\r\n ],\r\n });\r\n\r\n // Pipeline layout\r\n const pipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [this.uniformBindGroupLayout, this.textureBindGroupLayout],\r\n });\r\n\r\n // Blend state\r\n const blendState: GPUBlendState = {\r\n color: {\r\n srcFactor: \"one\",\r\n dstFactor: \"one-minus-src-alpha\",\r\n operation: \"add\",\r\n },\r\n alpha: {\r\n srcFactor: \"one\",\r\n dstFactor: \"one-minus-src-alpha\",\r\n operation: \"add\",\r\n },\r\n };\r\n\r\n // 创建管线\r\n this.pipeline = device.createRenderPipeline({\r\n layout: pipelineLayout,\r\n vertex: {\r\n module: shaderModule,\r\n entryPoint: \"vs_main\",\r\n buffers: [],\r\n },\r\n fragment: {\r\n module: shaderModule,\r\n entryPoint: \"fs_main\",\r\n targets: [\r\n {\r\n format: this.renderer.format,\r\n blend: blendState,\r\n },\r\n ],\r\n },\r\n primitive: {\r\n topology: \"triangle-strip\",\r\n },\r\n depthStencil: {\r\n format: this.renderer.depthFormat,\r\n depthWriteEnabled: false,\r\n depthCompare: \"always\",\r\n },\r\n });\r\n\r\n }\r\n\r\n /**\r\n * 创建 uniform buffer\r\n * 布局: view (64) + proj (64) + model (64) + cameraPos (12) + pad (4) + screenSize (8) + pad (8) + textureSize (8) + pad (8) = 240 bytes\r\n */\r\n private createUniformBuffer(): void {\r\n this.uniformBuffer = this.renderer.device.createBuffer({\r\n size: 240,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n }\r\n\r\n /**\r\n * 设置紧凑格式的 splat 数据\r\n * @param data 紧凑格式的 splat 数据\r\n */\r\n setCompactData(data: CompactSplatData): void {\r\n try {\r\n const device = this.renderer.device;\r\n\r\n // 销毁旧资源\r\n this.destroyInternal();\r\n\r\n this.splatCount = data.count;\r\n this.frameCount = 0;\r\n\r\n if (this.splatCount === 0) {\r\n return;\r\n }\r\n\r\n // 压缩数据到纹理\r\n this.compressedTextures = compressSplatsToTextures(device, data);\r\n\r\n // 计算 bounding box\r\n this.boundingBox = this.computeBoundingBox(data);\r\n\r\n // 创建位置缓冲区(用于排序)\r\n this.positionsBuffer = device.createBuffer({\r\n size: data.count * 12, // 3 floats per position\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n });\r\n // 使用 new Float32Array 确保是标准 ArrayBuffer\r\n device.queue.writeBuffer(this.positionsBuffer, 0, new Float32Array(data.positions));\r\n\r\n // 创建排序器\r\n this.sorter = new GSSplatSorterMobile(\r\n device,\r\n this.splatCount,\r\n this.positionsBuffer,\r\n this.uniformBuffer\r\n );\r\n\r\n this.sorter.setScreenSize(this.renderer.width, this.renderer.height);\r\n this.sorter.setCullingOptions({\r\n nearPlane: this.camera.near,\r\n farPlane: this.camera.far,\r\n pixelThreshold: 1.0,\r\n });\r\n\r\n // 创建 bind groups\r\n this.createBindGroups();\r\n\r\n const memoryMB = (\r\n this.compressedTextures.width *\r\n this.compressedTextures.height *\r\n 52 / // 约 52 bytes per texel (16+16+16+4)\r\n (1024 * 1024)\r\n ).toFixed(2);\r\n } catch (error) {\r\n this.splatCount = 0;\r\n this.compressedTextures = null;\r\n this.sorter = null;\r\n }\r\n }\r\n\r\n /**\r\n * 创建 bind groups\r\n */\r\n private createBindGroups(): void {\r\n if (!this.compressedTextures || !this.sorter) return;\r\n\r\n const device = this.renderer.device;\r\n\r\n // Uniform bind group (group 0)\r\n this.uniformBindGroup = device.createBindGroup({\r\n layout: this.uniformBindGroupLayout,\r\n entries: [\r\n {\r\n binding: 0,\r\n resource: { buffer: this.uniformBuffer },\r\n },\r\n {\r\n binding: 1,\r\n resource: { buffer: this.sorter.getIndicesBuffer() },\r\n },\r\n ],\r\n });\r\n\r\n // Texture bind group (group 1) - 简化版 4 张纹理\r\n this.textureBindGroup = device.createBindGroup({\r\n layout: this.textureBindGroupLayout,\r\n entries: [\r\n {\r\n binding: 0,\r\n resource: this.compressedTextures.positionTexture.createView(),\r\n },\r\n {\r\n binding: 1,\r\n resource: this.compressedTextures.scaleRotTexture1.createView(),\r\n },\r\n {\r\n binding: 2,\r\n resource: this.compressedTextures.scaleRotTexture2.createView(),\r\n },\r\n {\r\n binding: 3,\r\n resource: this.compressedTextures.colorTexture.createView(),\r\n },\r\n ],\r\n });\r\n }\r\n\r\n /**\r\n * 计算 bounding box\r\n */\r\n private computeBoundingBox(data: CompactSplatData): BoundingBox {\r\n if (data.count === 0) {\r\n return { min: [0, 0, 0], max: [0, 0, 0], center: [0, 0, 0], radius: 0 };\r\n }\r\n\r\n const positions = data.positions;\r\n const min: Vec3Tuple = [positions[0], positions[1], positions[2]];\r\n const max: Vec3Tuple = [positions[0], positions[1], positions[2]];\r\n\r\n for (let i = 1; i < data.count; i++) {\r\n const x = positions[i * 3 + 0];\r\n const y = positions[i * 3 + 1];\r\n const z = positions[i * 3 + 2];\r\n min[0] = Math.min(min[0], x);\r\n min[1] = Math.min(min[1], y);\r\n min[2] = Math.min(min[2], z);\r\n max[0] = Math.max(max[0], x);\r\n max[1] = Math.max(max[1], y);\r\n max[2] = Math.max(max[2], z);\r\n }\r\n\r\n const center: Vec3Tuple = [\r\n (min[0] + max[0]) / 2,\r\n (min[1] + max[1]) / 2,\r\n (min[2] + max[2]) / 2,\r\n ];\r\n\r\n const dx = max[0] - min[0];\r\n const dy = max[1] - min[1];\r\n const dz = max[2] - min[2];\r\n const radius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min, max, center, radius };\r\n }\r\n\r\n /**\r\n * 渲染\r\n * @param pass 渲染通道编码器\r\n */\r\n render(pass: GPURenderPassEncoder): void {\r\n if (\r\n this.splatCount === 0 ||\r\n !this.uniformBindGroup ||\r\n !this.textureBindGroup ||\r\n !this.sorter ||\r\n !this.compressedTextures\r\n ) {\r\n return;\r\n }\r\n\r\n this.frameCount++;\r\n\r\n // 更新 uniform buffer\r\n const device = this.renderer.device;\r\n device.queue.writeBuffer(this.uniformBuffer, 0, new Float32Array(this.camera.viewMatrix));\r\n device.queue.writeBuffer(this.uniformBuffer, 64, new Float32Array(this.camera.projectionMatrix));\r\n device.queue.writeBuffer(this.uniformBuffer, 128, new Float32Array(this.modelMatrix));\r\n device.queue.writeBuffer(this.uniformBuffer, 192, new Float32Array(this.camera.position));\r\n device.queue.writeBuffer(\r\n this.uniformBuffer,\r\n 208,\r\n new Float32Array([this.renderer.width, this.renderer.height, 0, 0])\r\n );\r\n device.queue.writeBuffer(\r\n this.uniformBuffer,\r\n 224,\r\n new Float32Array([this.compressedTextures.width, this.compressedTextures.height, 0, 0])\r\n );\r\n\r\n // 更新排序器参数\r\n this.sorter.setScreenSize(this.renderer.width, this.renderer.height);\r\n this.sorter.setCullingOptions({\r\n nearPlane: this.camera.near,\r\n farPlane: this.camera.far,\r\n pixelThreshold: 1.0,\r\n });\r\n\r\n // 排序(第一帧必须排序)\r\n const isFirstFrame = this.frameCount === 1;\r\n const shouldSort = isFirstFrame || this.frameCount % this.sortEveryNFrames === 0;\r\n\r\n if (shouldSort) {\r\n this.sorter.sort();\r\n }\r\n\r\n // 渲染\r\n pass.setPipeline(this.pipeline);\r\n pass.setBindGroup(0, this.uniformBindGroup);\r\n pass.setBindGroup(1, this.textureBindGroup);\r\n pass.drawIndirect(this.sorter.getDrawIndirectBuffer(), 0);\r\n }\r\n\r\n /**\r\n * 获取 splat 数量\r\n */\r\n getSplatCount(): number {\r\n return this.splatCount;\r\n }\r\n\r\n /**\r\n * 获取 bounding box\r\n */\r\n getBoundingBox(): BoundingBox | null {\r\n return this.boundingBox;\r\n }\r\n\r\n /**\r\n * 设置排序频率\r\n * @param n 每 n 帧排序一次\r\n */\r\n setSortFrequency(n: number): void {\r\n this.sortEveryNFrames = Math.max(1, n);\r\n }\r\n\r\n // ============================================\r\n // IGSSplatRenderer 接口实现 - SH 模式\r\n // ============================================\r\n\r\n /**\r\n * 设置 SH 模式(移动端仅支持 L0)\r\n */\r\n setSHMode(mode: SHMode): void {\r\n // 移动端仅支持 L0 模式\r\n }\r\n\r\n /**\r\n * 获取当前 SH 模式\r\n */\r\n getSHMode(): SHMode {\r\n return SHMode.L0;\r\n }\r\n\r\n /**\r\n * 是否支持指定的 SH 模式\r\n */\r\n supportsSHMode(mode: SHMode): boolean {\r\n return mode === SHMode.L0;\r\n }\r\n\r\n /**\r\n * 获取渲染器能力\r\n */\r\n getCapabilities(): RendererCapabilities {\r\n return {\r\n maxSHMode: SHMode.L0,\r\n supportsRawData: false,\r\n isMobileOptimized: true,\r\n maxSplatCount: 0, // 无限制(受 GPU 内存限制)\r\n };\r\n }\r\n\r\n /**\r\n * 内部销毁资源(不销毁管线)\r\n */\r\n private destroyInternal(): void {\r\n if (this.compressedTextures) {\r\n destroyCompressedTextures(this.compressedTextures);\r\n this.compressedTextures = null;\r\n }\r\n\r\n if (this.sorter) {\r\n this.sorter.destroy();\r\n this.sorter = null;\r\n }\r\n\r\n if (this.positionsBuffer) {\r\n this.positionsBuffer.destroy();\r\n this.positionsBuffer = null;\r\n }\r\n\r\n this.uniformBindGroup = null;\r\n this.textureBindGroup = null;\r\n this.splatCount = 0;\r\n this.boundingBox = null;\r\n }\r\n\r\n /**\r\n * 销毁资源\r\n */\r\n destroy(): void {\r\n this.destroyInternal();\r\n }\r\n}\r\n","/**\r\n * SceneManager - 场景管理器\r\n * \r\n * 负责管理场景中的所有对象:\r\n * - Mesh 网格\r\n * - Splat 点云\r\n * - 场景查询(bounding box 等)\r\n */\r\n\r\nimport { Mesh, MeshBoundingBox } from \"../mesh/Mesh\";\r\nimport { MeshRenderer } from \"../mesh/MeshRenderer\";\r\nimport type { IGSSplatRenderer } from \"../gs/IGSSplatRenderer\";\r\nimport type { BoundingBox, Vec3Tuple } from \"../types\";\r\n\r\n/**\r\n * 场景对象类型\r\n */\r\nexport type SceneObjectType = 'mesh' | 'splat' | 'meshGroup';\r\n\r\n/**\r\n * 场景对象信息\r\n */\r\nexport interface SceneObjectInfo {\r\n type: SceneObjectType;\r\n index: number;\r\n name?: string;\r\n}\r\n\r\n/**\r\n * SceneManager - 场景管理器\r\n */\r\nexport class SceneManager {\r\n private meshRenderer: MeshRenderer;\r\n private gsRenderer: IGSSplatRenderer | null = null;\r\n\r\n constructor(meshRenderer: MeshRenderer) {\r\n this.meshRenderer = meshRenderer;\r\n }\r\n\r\n // ============================================\r\n // Splat 渲染器管理\r\n // ============================================\r\n\r\n /**\r\n * 设置 GS Splat 渲染器\r\n */\r\n setGSRenderer(renderer: IGSSplatRenderer | null): void {\r\n this.gsRenderer = renderer;\r\n }\r\n\r\n /**\r\n * 获取 GS Splat 渲染器\r\n */\r\n getGSRenderer(): IGSSplatRenderer | null {\r\n return this.gsRenderer;\r\n }\r\n\r\n /**\r\n * 是否有 Splat 数据\r\n */\r\n hasSplats(): boolean {\r\n return this.gsRenderer !== null && this.gsRenderer.getSplatCount() > 0;\r\n }\r\n\r\n // ============================================\r\n // Mesh 管理(委托给 MeshRenderer)\r\n // ============================================\r\n\r\n /**\r\n * 获取 Mesh 数量\r\n */\r\n getMeshCount(): number {\r\n return this.meshRenderer.getMeshCount();\r\n }\r\n\r\n /**\r\n * 获取指定索引的 Mesh\r\n */\r\n getMeshByIndex(index: number): Mesh | null {\r\n return this.meshRenderer.getMeshByIndex(index);\r\n }\r\n\r\n /**\r\n * 获取指定范围的 Mesh\r\n */\r\n getMeshRange(startIndex: number, count: number): Mesh[] {\r\n const meshes: Mesh[] = [];\r\n for (let i = 0; i < count; i++) {\r\n const mesh = this.meshRenderer.getMeshByIndex(startIndex + i);\r\n if (mesh) {\r\n meshes.push(mesh);\r\n }\r\n }\r\n return meshes;\r\n }\r\n\r\n /**\r\n * 清空所有 Mesh\r\n */\r\n clearMeshes(): void {\r\n this.meshRenderer.clear();\r\n }\r\n\r\n /**\r\n * 按索引移除 Mesh\r\n */\r\n removeMeshByIndex(index: number): boolean {\r\n return this.meshRenderer.removeMeshByIndex(index);\r\n }\r\n\r\n // ============================================\r\n // Splat 管理\r\n // ============================================\r\n\r\n /**\r\n * 获取 Splat 数量\r\n */\r\n getSplatCount(): number {\r\n return this.gsRenderer?.getSplatCount() ?? 0;\r\n }\r\n\r\n /**\r\n * 清空 Splats\r\n */\r\n clearSplats(): void {\r\n if (this.gsRenderer) {\r\n this.gsRenderer.destroy();\r\n this.gsRenderer = null;\r\n }\r\n }\r\n\r\n // ============================================\r\n // Splat 变换\r\n // ============================================\r\n\r\n /**\r\n * 设置 Splat 位置\r\n */\r\n setSplatPosition(x: number, y: number, z: number): void {\r\n this.gsRenderer?.setPosition(x, y, z);\r\n }\r\n\r\n /**\r\n * 获取 Splat 位置\r\n */\r\n getSplatPosition(): Vec3Tuple | null {\r\n return this.gsRenderer?.getPosition() ?? null;\r\n }\r\n\r\n /**\r\n * 设置 Splat 旋转\r\n */\r\n setSplatRotation(x: number, y: number, z: number): void {\r\n this.gsRenderer?.setRotation(x, y, z);\r\n }\r\n\r\n /**\r\n * 获取 Splat 旋转\r\n */\r\n getSplatRotation(): Vec3Tuple | null {\r\n return this.gsRenderer?.getRotation() ?? null;\r\n }\r\n\r\n /**\r\n * 设置 Splat 缩放\r\n */\r\n setSplatScale(x: number, y: number, z: number): void {\r\n this.gsRenderer?.setScale(x, y, z);\r\n }\r\n\r\n /**\r\n * 获取 Splat 缩放\r\n */\r\n getSplatScale(): Vec3Tuple | null {\r\n return this.gsRenderer?.getScale() ?? null;\r\n }\r\n\r\n // ============================================\r\n // SH 模式\r\n // ============================================\r\n\r\n /**\r\n * 设置 SH 模式\r\n */\r\n setSHMode(mode: 0 | 1 | 2 | 3): void {\r\n if (this.gsRenderer?.setSHMode) {\r\n this.gsRenderer.setSHMode(mode);\r\n }\r\n }\r\n\r\n /**\r\n * 获取当前 SH 模式\r\n */\r\n getSHMode(): number {\r\n return this.gsRenderer?.getSHMode?.() ?? 0;\r\n }\r\n\r\n // ============================================\r\n // Bounding Box 查询\r\n // ============================================\r\n\r\n /**\r\n * 获取 Mesh 的组合 bounding box\r\n */\r\n getMeshBoundingBox(): MeshBoundingBox | null {\r\n return this.meshRenderer.getCombinedBoundingBox();\r\n }\r\n\r\n /**\r\n * 获取 Splat 的 bounding box\r\n */\r\n getSplatBoundingBox(): BoundingBox | null {\r\n return this.gsRenderer?.getBoundingBox() ?? null;\r\n }\r\n\r\n /**\r\n * 获取指定 Mesh 范围的组合 bounding box\r\n */\r\n getMeshRangeBoundingBox(startIndex: number, count: number): BoundingBox | null {\r\n const meshes = this.getMeshRange(startIndex, count);\r\n if (meshes.length === 0) return null;\r\n\r\n let combinedMin: Vec3Tuple | null = null;\r\n let combinedMax: Vec3Tuple | null = null;\r\n\r\n for (const mesh of meshes) {\r\n const bbox = mesh.getWorldBoundingBox();\r\n if (!bbox) continue;\r\n\r\n if (combinedMin === null || combinedMax === null) {\r\n combinedMin = [...bbox.min];\r\n combinedMax = [...bbox.max];\r\n } else {\r\n combinedMin[0] = Math.min(combinedMin[0], bbox.min[0]);\r\n combinedMin[1] = Math.min(combinedMin[1], bbox.min[1]);\r\n combinedMin[2] = Math.min(combinedMin[2], bbox.min[2]);\r\n combinedMax[0] = Math.max(combinedMax[0], bbox.max[0]);\r\n combinedMax[1] = Math.max(combinedMax[1], bbox.max[1]);\r\n combinedMax[2] = Math.max(combinedMax[2], bbox.max[2]);\r\n }\r\n }\r\n\r\n if (combinedMin === null || combinedMax === null) return null;\r\n\r\n const center: Vec3Tuple = [\r\n (combinedMin[0] + combinedMax[0]) / 2,\r\n (combinedMin[1] + combinedMax[1]) / 2,\r\n (combinedMin[2] + combinedMax[2]) / 2,\r\n ];\r\n const dx = combinedMax[0] - combinedMin[0];\r\n const dy = combinedMax[1] - combinedMin[1];\r\n const dz = combinedMax[2] - combinedMin[2];\r\n const radius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min: combinedMin, max: combinedMax, center, radius };\r\n }\r\n\r\n /**\r\n * 获取整个场景的组合 bounding box\r\n */\r\n getSceneBoundingBox(): BoundingBox | null {\r\n let combinedMin: Vec3Tuple | null = null;\r\n let combinedMax: Vec3Tuple | null = null;\r\n\r\n // 1. 获取 Mesh 的 bounding box\r\n const meshBBox = this.getMeshBoundingBox();\r\n if (meshBBox) {\r\n combinedMin = [...meshBBox.min];\r\n combinedMax = [...meshBBox.max];\r\n }\r\n\r\n // 2. 获取 Splat 的 bounding box\r\n const splatBBox = this.getSplatBoundingBox();\r\n if (splatBBox) {\r\n if (combinedMin === null || combinedMax === null) {\r\n combinedMin = [...splatBBox.min];\r\n combinedMax = [...splatBBox.max];\r\n } else {\r\n combinedMin[0] = Math.min(combinedMin[0], splatBBox.min[0]);\r\n combinedMin[1] = Math.min(combinedMin[1], splatBBox.min[1]);\r\n combinedMin[2] = Math.min(combinedMin[2], splatBBox.min[2]);\r\n combinedMax[0] = Math.max(combinedMax[0], splatBBox.max[0]);\r\n combinedMax[1] = Math.max(combinedMax[1], splatBBox.max[1]);\r\n combinedMax[2] = Math.max(combinedMax[2], splatBBox.max[2]);\r\n }\r\n }\r\n\r\n if (combinedMin === null || combinedMax === null) {\r\n return null;\r\n }\r\n\r\n const center: Vec3Tuple = [\r\n (combinedMin[0] + combinedMax[0]) / 2,\r\n (combinedMin[1] + combinedMax[1]) / 2,\r\n (combinedMin[2] + combinedMax[2]) / 2,\r\n ];\r\n const dx = combinedMax[0] - combinedMin[0];\r\n const dy = combinedMax[1] - combinedMin[1];\r\n const dz = combinedMax[2] - combinedMin[2];\r\n const radius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min: combinedMin, max: combinedMax, center, radius };\r\n }\r\n\r\n // ============================================\r\n // 材质颜色\r\n // ============================================\r\n\r\n /**\r\n * 获取指定索引 Mesh 的材质颜色\r\n */\r\n getMeshColor(index: number): [number, number, number, number] | null {\r\n return this.meshRenderer.getMeshColor(index);\r\n }\r\n\r\n /**\r\n * 设置指定索引 Mesh 的材质颜色\r\n */\r\n setMeshColor(index: number, r: number, g: number, b: number, a: number = 1): boolean {\r\n return this.meshRenderer.setMeshColor(index, r, g, b, a);\r\n }\r\n\r\n /**\r\n * 设置指定范围内所有 Mesh 的材质颜色\r\n */\r\n setMeshRangeColor(startIndex: number, count: number, r: number, g: number, b: number, a: number = 1): number {\r\n return this.meshRenderer.setMeshRangeColor(startIndex, count, r, g, b, a);\r\n }\r\n\r\n /**\r\n * 销毁场景管理器\r\n */\r\n destroy(): void {\r\n this.clearSplats();\r\n // 注意:meshRenderer 的销毁由 App 负责\r\n }\r\n}\r\n","/**\r\n * SplatTransformProxy - PLY/Splat 变换代理对象\r\n * 实现 TransformableObject 接口,让 TransformGizmo 可以操作 PLY 模型\r\n */\r\n\r\nimport type { TransformableObject, Vec3Tuple } from '../../types';\r\nimport type { IGSSplatRenderer } from '../../gs/IGSSplatRenderer';\r\n\r\nexport class SplatTransformProxy implements TransformableObject {\r\n position: Vec3Tuple;\r\n rotation: Vec3Tuple;\r\n scale: Vec3Tuple;\r\n\r\n private renderer: IGSSplatRenderer;\r\n private center: Vec3Tuple;\r\n\r\n constructor(renderer: IGSSplatRenderer, center: Vec3Tuple) {\r\n this.renderer = renderer;\r\n this.center = [...center];\r\n\r\n // 设置渲染器的 pivot 为包围盒中心\r\n renderer.setPivot(center[0], center[1], center[2]);\r\n\r\n // 初始化为当前渲染器的变换状态\r\n const pos = renderer.getPosition();\r\n const rot = renderer.getRotation();\r\n const scl = renderer.getScale();\r\n\r\n // Gizmo 位置 = 渲染器位置 + 中心点\r\n this.position = [\r\n pos[0] + center[0],\r\n pos[1] + center[1],\r\n pos[2] + center[2],\r\n ];\r\n this.rotation = [...rot];\r\n this.scale = [...scl];\r\n }\r\n\r\n setPosition(x: number, y: number, z: number): void {\r\n this.position = [x, y, z];\r\n // 渲染器位置 = Gizmo 位置 - 中心点\r\n this.renderer.setPosition(\r\n x - this.center[0],\r\n y - this.center[1],\r\n z - this.center[2]\r\n );\r\n }\r\n\r\n setRotation(x: number, y: number, z: number): void {\r\n this.rotation = [x, y, z];\r\n this.renderer.setRotation(x, y, z);\r\n }\r\n\r\n setScale(x: number, y: number, z: number): void {\r\n this.scale = [x, y, z];\r\n this.renderer.setScale(x, y, z);\r\n }\r\n}\r\n","/**\r\n * MeshGroupProxy - 多 Mesh 组变换代理对象\r\n * 让 TransformGizmo 可以同时操作多个 Mesh\r\n */\r\n\r\nimport type { TransformableObject, SimpleBoundingBox, Vec3Tuple } from '../../types';\r\nimport type { Mesh } from '../../mesh/Mesh';\r\n\r\nexport class MeshGroupProxy implements TransformableObject {\r\n position: Vec3Tuple;\r\n rotation: Vec3Tuple;\r\n scale: Vec3Tuple;\r\n\r\n private meshes: Mesh[];\r\n\r\n constructor(meshes: Mesh[]) {\r\n this.meshes = meshes;\r\n\r\n if (meshes.length > 0) {\r\n const firstMesh = meshes[0];\r\n this.position = [\r\n firstMesh.position[0],\r\n firstMesh.position[1],\r\n firstMesh.position[2],\r\n ];\r\n this.rotation = [\r\n firstMesh.rotation[0],\r\n firstMesh.rotation[1],\r\n firstMesh.rotation[2],\r\n ];\r\n this.scale = [\r\n firstMesh.scale[0],\r\n firstMesh.scale[1],\r\n firstMesh.scale[2],\r\n ];\r\n } else {\r\n this.position = [0, 0, 0];\r\n this.rotation = [0, 0, 0];\r\n this.scale = [1, 1, 1];\r\n }\r\n }\r\n\r\n setPosition(x: number, y: number, z: number): void {\r\n this.position = [x, y, z];\r\n for (const mesh of this.meshes) {\r\n mesh.setPosition(x, y, z);\r\n }\r\n }\r\n\r\n setRotation(x: number, y: number, z: number): void {\r\n this.rotation = [x, y, z];\r\n for (const mesh of this.meshes) {\r\n mesh.setRotation(x, y, z);\r\n }\r\n }\r\n\r\n setScale(x: number, y: number, z: number): void {\r\n this.scale = [x, y, z];\r\n for (const mesh of this.meshes) {\r\n mesh.setScale(x, y, z);\r\n }\r\n }\r\n\r\n /**\r\n * 获取组合包围盒\r\n */\r\n getBoundingBox(): SimpleBoundingBox | null {\r\n if (this.meshes.length === 0) return null;\r\n\r\n let combinedMin: Vec3Tuple | null = null;\r\n let combinedMax: Vec3Tuple | null = null;\r\n\r\n for (const mesh of this.meshes) {\r\n const bbox = mesh.getWorldBoundingBox();\r\n if (!bbox) continue;\r\n\r\n if (combinedMin === null || combinedMax === null) {\r\n combinedMin = [...bbox.min];\r\n combinedMax = [...bbox.max];\r\n } else {\r\n combinedMin[0] = Math.min(combinedMin[0], bbox.min[0]);\r\n combinedMin[1] = Math.min(combinedMin[1], bbox.min[1]);\r\n combinedMin[2] = Math.min(combinedMin[2], bbox.min[2]);\r\n combinedMax[0] = Math.max(combinedMax[0], bbox.max[0]);\r\n combinedMax[1] = Math.max(combinedMax[1], bbox.max[1]);\r\n combinedMax[2] = Math.max(combinedMax[2], bbox.max[2]);\r\n }\r\n }\r\n\r\n if (combinedMin === null || combinedMax === null) return null;\r\n\r\n return { min: combinedMin, max: combinedMax };\r\n }\r\n}\r\n","/**\r\n * SplatBoundingBoxProvider - PLY/Splat 包围盒提供者\r\n * 动态获取 PLY 的包围盒(考虑变换)\r\n */\r\n\r\nimport type { BoundingBoxProvider, SimpleBoundingBox, Vec3Tuple } from '../../types';\r\nimport type { IGSSplatRenderer } from '../../gs/IGSSplatRenderer';\r\n\r\nexport class SplatBoundingBoxProvider implements BoundingBoxProvider {\r\n private renderer: IGSSplatRenderer;\r\n\r\n constructor(renderer: IGSSplatRenderer) {\r\n this.renderer = renderer;\r\n }\r\n\r\n getBoundingBox(): SimpleBoundingBox | null {\r\n const bbox = this.renderer.getBoundingBox();\r\n if (!bbox) return null;\r\n\r\n // 获取变换参数\r\n const position = this.renderer.getPosition();\r\n const rotation = this.renderer.getRotation();\r\n const scale = this.renderer.getScale();\r\n const pivot = this.renderer.getPivot();\r\n\r\n // 获取本地包围盒的 8 个角点\r\n const corners: Vec3Tuple[] = [\r\n [bbox.min[0], bbox.min[1], bbox.min[2]],\r\n [bbox.max[0], bbox.min[1], bbox.min[2]],\r\n [bbox.min[0], bbox.max[1], bbox.min[2]],\r\n [bbox.max[0], bbox.max[1], bbox.min[2]],\r\n [bbox.min[0], bbox.min[1], bbox.max[2]],\r\n [bbox.max[0], bbox.min[1], bbox.max[2]],\r\n [bbox.min[0], bbox.max[1], bbox.max[2]],\r\n [bbox.max[0], bbox.max[1], bbox.max[2]],\r\n ];\r\n\r\n // 计算变换矩阵\r\n const [sx, sy, sz] = scale;\r\n const [rx, ry, rz] = rotation;\r\n const [tx, ty, tz] = position;\r\n const [px, py, pz] = pivot;\r\n\r\n const cx = Math.cos(rx), sx1 = Math.sin(rx);\r\n const cy = Math.cos(ry), sy1 = Math.sin(ry);\r\n const cz = Math.cos(rz), sz1 = Math.sin(rz);\r\n\r\n // 组合旋转矩阵 R = Rz * Ry * Rx\r\n const r00 = cy * cz;\r\n const r01 = sx1 * sy1 * cz - cx * sz1;\r\n const r02 = cx * sy1 * cz + sx1 * sz1;\r\n const r10 = cy * sz1;\r\n const r11 = sx1 * sy1 * sz1 + cx * cz;\r\n const r12 = cx * sy1 * sz1 - sx1 * cz;\r\n const r20 = -sy1;\r\n const r21 = sx1 * cy;\r\n const r22 = cx * cy;\r\n\r\n // RS 矩阵 (旋转 * 缩放)\r\n const rs00 = r00 * sx, rs01 = r01 * sy, rs02 = r02 * sz;\r\n const rs10 = r10 * sx, rs11 = r11 * sy, rs12 = r12 * sz;\r\n const rs20 = r20 * sx, rs21 = r21 * sy, rs22 = r22 * sz;\r\n\r\n // 计算 (I - RS) * pivot\r\n const dpx = px - (rs00 * px + rs01 * py + rs02 * pz);\r\n const dpy = py - (rs10 * px + rs11 * py + rs12 * pz);\r\n const dpz = pz - (rs20 * px + rs21 * py + rs22 * pz);\r\n\r\n // 最终平移 = position + (I - RS) * pivot\r\n const finalTx = tx + dpx;\r\n const finalTy = ty + dpy;\r\n const finalTz = tz + dpz;\r\n\r\n // 变换所有角点\r\n let minX = Infinity, minY = Infinity, minZ = Infinity;\r\n let maxX = -Infinity, maxY = -Infinity, maxZ = -Infinity;\r\n\r\n for (const [x, y, z] of corners) {\r\n const wx = rs00 * x + rs01 * y + rs02 * z + finalTx;\r\n const wy = rs10 * x + rs11 * y + rs12 * z + finalTy;\r\n const wz = rs20 * x + rs21 * y + rs22 * z + finalTz;\r\n\r\n minX = Math.min(minX, wx);\r\n minY = Math.min(minY, wy);\r\n minZ = Math.min(minZ, wz);\r\n maxX = Math.max(maxX, wx);\r\n maxY = Math.max(maxY, wy);\r\n maxZ = Math.max(maxZ, wz);\r\n }\r\n\r\n return {\r\n min: [minX, minY, minZ],\r\n max: [maxX, maxY, maxZ],\r\n };\r\n }\r\n}\r\n","/**\r\n * Vec3 - 3D Vector utility class\r\n * Provides vector operations for 3D mathematics\r\n */\r\nexport class Vec3 {\r\n x: number;\r\n y: number;\r\n z: number;\r\n\r\n constructor(x: number = 0, y: number = 0, z: number = 0) {\r\n this.x = x;\r\n this.y = y;\r\n this.z = z;\r\n }\r\n\r\n // Factory methods\r\n static fromArray(arr: Float32Array | number[], offset: number = 0): Vec3 {\r\n return new Vec3(arr[offset], arr[offset + 1], arr[offset + 2]);\r\n }\r\n\r\n static zero(): Vec3 {\r\n return new Vec3(0, 0, 0);\r\n }\r\n\r\n static one(): Vec3 {\r\n return new Vec3(1, 1, 1);\r\n }\r\n\r\n // Basic operations (return new Vec3)\r\n add(v: Vec3): Vec3 {\r\n return new Vec3(this.x + v.x, this.y + v.y, this.z + v.z);\r\n }\r\n\r\n subtract(v: Vec3): Vec3 {\r\n return new Vec3(this.x - v.x, this.y - v.y, this.z - v.z);\r\n }\r\n\r\n multiply(scalar: number): Vec3 {\r\n return new Vec3(this.x * scalar, this.y * scalar, this.z * scalar);\r\n }\r\n\r\n divide(scalar: number): Vec3 {\r\n return new Vec3(this.x / scalar, this.y / scalar, this.z / scalar);\r\n }\r\n\r\n // In-place operations (modify this)\r\n addInPlace(v: Vec3): Vec3 {\r\n this.x += v.x;\r\n this.y += v.y;\r\n this.z += v.z;\r\n return this;\r\n }\r\n\r\n subtractInPlace(v: Vec3): Vec3 {\r\n this.x -= v.x;\r\n this.y -= v.y;\r\n this.z -= v.z;\r\n return this;\r\n }\r\n\r\n multiplyInPlace(scalar: number): Vec3 {\r\n this.x *= scalar;\r\n this.y *= scalar;\r\n this.z *= scalar;\r\n return this;\r\n }\r\n\r\n // Vector operations\r\n dot(v: Vec3): number {\r\n return this.x * v.x + this.y * v.y + this.z * v.z;\r\n }\r\n\r\n cross(v: Vec3): Vec3 {\r\n return new Vec3(\r\n this.y * v.z - this.z * v.y,\r\n this.z * v.x - this.x * v.z,\r\n this.x * v.y - this.y * v.x,\r\n );\r\n }\r\n\r\n length(): number {\r\n return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);\r\n }\r\n\r\n lengthSquared(): number {\r\n return this.x * this.x + this.y * this.y + this.z * this.z;\r\n }\r\n\r\n distance(v: Vec3): number {\r\n const dx = this.x - v.x;\r\n const dy = this.y - v.y;\r\n const dz = this.z - v.z;\r\n return Math.sqrt(dx * dx + dy * dy + dz * dz);\r\n }\r\n\r\n distanceSquared(v: Vec3): number {\r\n const dx = this.x - v.x;\r\n const dy = this.y - v.y;\r\n const dz = this.z - v.z;\r\n return dx * dx + dy * dy + dz * dz;\r\n }\r\n\r\n // Normalization\r\n normalize(): Vec3 {\r\n const len = this.length();\r\n if (len < 1e-10) {\r\n // Handle zero-length vector - return default direction\r\n return new Vec3(0, 0, 1);\r\n }\r\n return new Vec3(this.x / len, this.y / len, this.z / len);\r\n }\r\n\r\n normalizeInPlace(): Vec3 {\r\n const len = this.length();\r\n if (len < 1e-10) {\r\n // Handle zero-length vector - set to default direction\r\n this.x = 0;\r\n this.y = 0;\r\n this.z = 1;\r\n return this;\r\n }\r\n this.x /= len;\r\n this.y /= len;\r\n this.z /= len;\r\n return this;\r\n }\r\n\r\n // Utility\r\n clone(): Vec3 {\r\n return new Vec3(this.x, this.y, this.z);\r\n }\r\n\r\n toArray(): [number, number, number] {\r\n return [this.x, this.y, this.z];\r\n }\r\n\r\n set(x: number, y: number, z: number): Vec3 {\r\n this.x = x;\r\n this.y = y;\r\n this.z = z;\r\n return this;\r\n }\r\n\r\n /**\r\n * Check if this vector equals another vector\r\n */\r\n equals(v: Vec3): boolean {\r\n return this.x === v.x && this.y === v.y && this.z === v.z;\r\n }\r\n\r\n /**\r\n * Check if this vector approximately equals another vector\r\n */\r\n equalsApprox(v: Vec3, epsilon: number = 1e-6): boolean {\r\n return (\r\n Math.abs(this.x - v.x) < epsilon &&\r\n Math.abs(this.y - v.y) < epsilon &&\r\n Math.abs(this.z - v.z) < epsilon\r\n );\r\n }\r\n}\r\n","import { Vec3 } from \"./Vec3\";\r\nimport { Camera } from \"../Camera\";\r\n\r\n/**\r\n * Ray - Ray utility class\r\n * Provides ray operations for 3D picking and intersection tests\r\n */\r\nexport class Ray {\r\n origin: Vec3;\r\n direction: Vec3; // Should be normalized\r\n\r\n constructor(origin: Vec3, direction: Vec3) {\r\n this.origin = origin;\r\n this.direction = direction;\r\n }\r\n\r\n /**\r\n * Create a ray from screen coordinates\r\n * @param screenX - Screen X coordinate (0 to canvasWidth)\r\n * @param screenY - Screen Y coordinate (0 to canvasHeight)\r\n * @param canvasWidth - Canvas width in pixels\r\n * @param canvasHeight - Canvas height in pixels\r\n * @param camera - Camera instance\r\n */\r\n static fromScreenPoint(\r\n screenX: number,\r\n screenY: number,\r\n canvasWidth: number,\r\n canvasHeight: number,\r\n camera: Camera,\r\n ): Ray {\r\n // Convert screen coordinates to normalized device coordinates (-1 to 1)\r\n const ndcX = (screenX / canvasWidth) * 2 - 1;\r\n const ndcY = -(screenY / canvasHeight) * 2 + 1; // Flip Y axis\r\n\r\n // Create inverse view-projection matrix\r\n const invViewProj = Ray.invertMatrix(camera.viewProjectionMatrix);\r\n\r\n // Transform NDC point to world space (near plane)\r\n const nearPoint = Ray.transformPoint(invViewProj, ndcX, ndcY, -1);\r\n const farPoint = Ray.transformPoint(invViewProj, ndcX, ndcY, 1);\r\n\r\n // Ray origin is camera position\r\n const origin = new Vec3(\r\n camera.position[0],\r\n camera.position[1],\r\n camera.position[2],\r\n );\r\n\r\n // Ray direction is from near to far point\r\n const direction = new Vec3(\r\n farPoint.x - nearPoint.x,\r\n farPoint.y - nearPoint.y,\r\n farPoint.z - nearPoint.z,\r\n ).normalize();\r\n\r\n return new Ray(origin, direction);\r\n }\r\n\r\n /**\r\n * Get point at distance along ray\r\n * @param distance - Distance along ray\r\n */\r\n at(distance: number): Vec3 {\r\n return new Vec3(\r\n this.origin.x + this.direction.x * distance,\r\n this.origin.y + this.direction.y * distance,\r\n this.origin.z + this.direction.z * distance,\r\n );\r\n }\r\n\r\n /**\r\n * Intersect ray with plane\r\n * @param planeOrigin - Point on the plane\r\n * @param planeNormal - Normal vector of the plane (should be normalized)\r\n * @returns Distance along ray to intersection, or null if parallel/no intersection\r\n */\r\n intersectPlane(planeOrigin: Vec3, planeNormal: Vec3): number | null {\r\n const denom = this.direction.dot(planeNormal);\r\n\r\n // Check if ray is parallel to plane\r\n if (Math.abs(denom) < 1e-6) {\r\n return null;\r\n }\r\n\r\n const t = planeOrigin.subtract(this.origin).dot(planeNormal) / denom;\r\n\r\n // Return null if intersection is behind ray origin\r\n if (t < 0) {\r\n return null;\r\n }\r\n\r\n return t;\r\n }\r\n\r\n /**\r\n * Compute distance from ray to a point\r\n * @param point - Point in 3D space\r\n */\r\n distanceToPoint(point: Vec3): number {\r\n const v = point.subtract(this.origin);\r\n const t = v.dot(this.direction);\r\n\r\n // If t < 0, closest point is the ray origin\r\n if (t < 0) {\r\n return this.origin.distance(point);\r\n }\r\n\r\n // Closest point on ray\r\n const closestPoint = this.at(t);\r\n return closestPoint.distance(point);\r\n }\r\n\r\n /**\r\n * Compute distance from ray to a line segment (for capsule hit testing)\r\n * @param segmentStart - Start point of line segment\r\n * @param segmentEnd - End point of line segment\r\n */\r\n distanceToSegment(segmentStart: Vec3, segmentEnd: Vec3): number {\r\n const segmentDir = segmentEnd.subtract(segmentStart);\r\n const segmentLength = segmentDir.length();\r\n\r\n // Handle degenerate segment (point)\r\n if (segmentLength < 1e-10) {\r\n return this.distanceToPoint(segmentStart);\r\n }\r\n\r\n const segmentDirNorm = segmentDir.divide(segmentLength);\r\n\r\n // Compute closest points between ray and line segment\r\n const w0 = this.origin.subtract(segmentStart);\r\n const a = this.direction.dot(this.direction);\r\n const b = this.direction.dot(segmentDirNorm);\r\n const c = segmentDirNorm.dot(segmentDirNorm);\r\n const d = this.direction.dot(w0);\r\n const e = segmentDirNorm.dot(w0);\r\n\r\n const denom = a * c - b * b;\r\n let t = 0; // Parameter on ray\r\n let s = 0; // Parameter on segment\r\n\r\n if (Math.abs(denom) < 1e-6) {\r\n // Ray and segment are parallel\r\n t = 0;\r\n s = e / c;\r\n } else {\r\n t = (b * e - c * d) / denom;\r\n s = (a * e - b * d) / denom;\r\n }\r\n\r\n // Clamp t to non-negative (ray starts at origin)\r\n t = Math.max(0, t);\r\n\r\n // Clamp s to segment bounds [0, segmentLength]\r\n s = Math.max(0, Math.min(segmentLength, s));\r\n\r\n const pointOnRay = this.at(t);\r\n const pointOnSegment = segmentStart.add(segmentDirNorm.multiply(s));\r\n\r\n return pointOnRay.distance(pointOnSegment);\r\n }\r\n\r\n /**\r\n * Clone this ray\r\n */\r\n clone(): Ray {\r\n return new Ray(this.origin.clone(), this.direction.clone());\r\n }\r\n\r\n /**\r\n * Transform ray by a matrix\r\n * @param matrix - Transformation matrix\r\n */\r\n transform(matrix: { transformPoint(v: Vec3): Vec3; transformVector(v: Vec3): Vec3 }): Ray {\r\n const newOrigin = matrix.transformPoint(this.origin);\r\n const newDirection = matrix.transformVector(this.direction).normalize();\r\n return new Ray(newOrigin, newDirection);\r\n }\r\n\r\n /**\r\n * Intersect ray with triangle using Möller–Trumbore algorithm\r\n * @param v0 - First vertex of triangle\r\n * @param v1 - Second vertex of triangle\r\n * @param v2 - Third vertex of triangle\r\n * @returns Distance to intersection, or null if no intersection\r\n */\r\n intersectTriangle(v0: Vec3, v1: Vec3, v2: Vec3): number | null {\r\n const EPSILON = 1e-6;\r\n \r\n const edge1 = v1.subtract(v0);\r\n const edge2 = v2.subtract(v0);\r\n \r\n const h = this.direction.cross(edge2);\r\n const a = edge1.dot(h);\r\n \r\n // Ray is parallel to triangle\r\n if (Math.abs(a) < EPSILON) {\r\n return null;\r\n }\r\n \r\n const f = 1.0 / a;\r\n const s = this.origin.subtract(v0);\r\n const u = f * s.dot(h);\r\n \r\n // Intersection is outside triangle\r\n if (u < 0.0 || u > 1.0) {\r\n return null;\r\n }\r\n \r\n const q = s.cross(edge1);\r\n const v = f * this.direction.dot(q);\r\n \r\n // Intersection is outside triangle\r\n if (v < 0.0 || u + v > 1.0) {\r\n return null;\r\n }\r\n \r\n const t = f * edge2.dot(q);\r\n \r\n // Intersection is behind ray origin\r\n if (t < EPSILON) {\r\n return null;\r\n }\r\n \r\n return t;\r\n }\r\n\r\n // Helper methods for matrix operations\r\n private static invertMatrix(m: Float32Array): Float32Array {\r\n const inv = new Float32Array(16);\r\n const e = m;\r\n\r\n inv[0] =\r\n e[5] * e[10] * e[15] -\r\n e[5] * e[11] * e[14] -\r\n e[9] * e[6] * e[15] +\r\n e[9] * e[7] * e[14] +\r\n e[13] * e[6] * e[11] -\r\n e[13] * e[7] * e[10];\r\n inv[4] =\r\n -e[4] * e[10] * e[15] +\r\n e[4] * e[11] * e[14] +\r\n e[8] * e[6] * e[15] -\r\n e[8] * e[7] * e[14] -\r\n e[12] * e[6] * e[11] +\r\n e[12] * e[7] * e[10];\r\n inv[8] =\r\n e[4] * e[9] * e[15] -\r\n e[4] * e[11] * e[13] -\r\n e[8] * e[5] * e[15] +\r\n e[8] * e[7] * e[13] +\r\n e[12] * e[5] * e[11] -\r\n e[12] * e[7] * e[9];\r\n inv[12] =\r\n -e[4] * e[9] * e[14] +\r\n e[4] * e[10] * e[13] +\r\n e[8] * e[5] * e[14] -\r\n e[8] * e[6] * e[13] -\r\n e[12] * e[5] * e[10] +\r\n e[12] * e[6] * e[9];\r\n\r\n inv[1] =\r\n -e[1] * e[10] * e[15] +\r\n e[1] * e[11] * e[14] +\r\n e[9] * e[2] * e[15] -\r\n e[9] * e[3] * e[14] -\r\n e[13] * e[2] * e[11] +\r\n e[13] * e[3] * e[10];\r\n inv[5] =\r\n e[0] * e[10] * e[15] -\r\n e[0] * e[11] * e[14] -\r\n e[8] * e[2] * e[15] +\r\n e[8] * e[3] * e[14] +\r\n e[12] * e[2] * e[11] -\r\n e[12] * e[3] * e[10];\r\n inv[9] =\r\n -e[0] * e[9] * e[15] +\r\n e[0] * e[11] * e[13] +\r\n e[8] * e[1] * e[15] -\r\n e[8] * e[3] * e[13] -\r\n e[12] * e[1] * e[11] +\r\n e[12] * e[3] * e[9];\r\n inv[13] =\r\n e[0] * e[9] * e[14] -\r\n e[0] * e[10] * e[13] -\r\n e[8] * e[1] * e[14] +\r\n e[8] * e[2] * e[13] +\r\n e[12] * e[1] * e[10] -\r\n e[12] * e[2] * e[9];\r\n\r\n inv[2] =\r\n e[1] * e[6] * e[15] -\r\n e[1] * e[7] * e[14] -\r\n e[5] * e[2] * e[15] +\r\n e[5] * e[3] * e[14] +\r\n e[13] * e[2] * e[7] -\r\n e[13] * e[3] * e[6];\r\n inv[6] =\r\n -e[0] * e[6] * e[15] +\r\n e[0] * e[7] * e[14] +\r\n e[4] * e[2] * e[15] -\r\n e[4] * e[3] * e[14] -\r\n e[12] * e[2] * e[7] +\r\n e[12] * e[3] * e[6];\r\n inv[10] =\r\n e[0] * e[5] * e[15] -\r\n e[0] * e[7] * e[13] -\r\n e[4] * e[1] * e[15] +\r\n e[4] * e[3] * e[13] +\r\n e[12] * e[1] * e[7] -\r\n e[12] * e[3] * e[5];\r\n inv[14] =\r\n -e[0] * e[5] * e[14] +\r\n e[0] * e[6] * e[13] +\r\n e[4] * e[1] * e[14] -\r\n e[4] * e[2] * e[13] -\r\n e[12] * e[1] * e[6] +\r\n e[12] * e[2] * e[5];\r\n\r\n inv[3] =\r\n -e[1] * e[6] * e[11] +\r\n e[1] * e[7] * e[10] +\r\n e[5] * e[2] * e[11] -\r\n e[5] * e[3] * e[10] -\r\n e[9] * e[2] * e[7] +\r\n e[9] * e[3] * e[6];\r\n inv[7] =\r\n e[0] * e[6] * e[11] -\r\n e[0] * e[7] * e[10] -\r\n e[4] * e[2] * e[11] +\r\n e[4] * e[3] * e[10] +\r\n e[8] * e[2] * e[7] -\r\n e[8] * e[3] * e[6];\r\n inv[11] =\r\n -e[0] * e[5] * e[11] +\r\n e[0] * e[7] * e[9] +\r\n e[4] * e[1] * e[11] -\r\n e[4] * e[3] * e[9] -\r\n e[8] * e[1] * e[7] +\r\n e[8] * e[3] * e[5];\r\n inv[15] =\r\n e[0] * e[5] * e[10] -\r\n e[0] * e[6] * e[9] -\r\n e[4] * e[1] * e[10] +\r\n e[4] * e[2] * e[9] +\r\n e[8] * e[1] * e[6] -\r\n e[8] * e[2] * e[5];\r\n\r\n const det = e[0] * inv[0] + e[1] * inv[4] + e[2] * inv[8] + e[3] * inv[12];\r\n\r\n if (Math.abs(det) < 1e-10) {\r\n // Return identity if singular\r\n const identity = new Float32Array(16);\r\n identity[0] = identity[5] = identity[10] = identity[15] = 1;\r\n return identity;\r\n }\r\n\r\n const invDet = 1.0 / det;\r\n const result = new Float32Array(16);\r\n for (let i = 0; i < 16; i++) {\r\n result[i] = inv[i] * invDet;\r\n }\r\n\r\n return result;\r\n }\r\n\r\n private static transformPoint(\r\n m: Float32Array,\r\n x: number,\r\n y: number,\r\n z: number,\r\n ): Vec3 {\r\n const w = m[3] * x + m[7] * y + m[11] * z + m[15];\r\n return new Vec3(\r\n (m[0] * x + m[4] * y + m[8] * z + m[12]) / w,\r\n (m[1] * x + m[5] * y + m[9] * z + m[13]) / w,\r\n (m[2] * x + m[6] * y + m[10] * z + m[14]) / w,\r\n );\r\n }\r\n}\r\n","import { Vec3 } from \"./Vec3\";\r\n\r\n/**\r\n * Quat - Quaternion utility class\r\n * Provides quaternion operations for 3D rotations\r\n */\r\nexport class Quat {\r\n x: number;\r\n y: number;\r\n z: number;\r\n w: number;\r\n\r\n constructor(x: number = 0, y: number = 0, z: number = 0, w: number = 1) {\r\n this.x = x;\r\n this.y = y;\r\n this.z = z;\r\n this.w = w;\r\n }\r\n\r\n // Factory methods\r\n static identity(): Quat {\r\n return new Quat(0, 0, 0, 1);\r\n }\r\n\r\n /**\r\n * Create quaternion from Euler angles (ZYX order)\r\n * @param x - Rotation around X axis in radians\r\n * @param y - Rotation around Y axis in radians\r\n * @param z - Rotation around Z axis in radians\r\n */\r\n static fromEuler(x: number, y: number, z: number): Quat {\r\n const cx = Math.cos(x * 0.5);\r\n const cy = Math.cos(y * 0.5);\r\n const cz = Math.cos(z * 0.5);\r\n const sx = Math.sin(x * 0.5);\r\n const sy = Math.sin(y * 0.5);\r\n const sz = Math.sin(z * 0.5);\r\n\r\n // ZYX order\r\n return new Quat(\r\n sx * cy * cz - cx * sy * sz,\r\n cx * sy * cz + sx * cy * sz,\r\n cx * cy * sz - sx * sy * cz,\r\n cx * cy * cz + sx * sy * sz,\r\n );\r\n }\r\n\r\n /**\r\n * Create quaternion from axis-angle representation\r\n * @param axis - Rotation axis (should be normalized)\r\n * @param angle - Rotation angle in radians\r\n */\r\n static fromAxisAngle(axis: Vec3, angle: number): Quat {\r\n const halfAngle = angle * 0.5;\r\n const s = Math.sin(halfAngle);\r\n return new Quat(axis.x * s, axis.y * s, axis.z * s, Math.cos(halfAngle));\r\n }\r\n\r\n // Operations\r\n /**\r\n * Multiply this quaternion by another (this * q)\r\n */\r\n multiply(q: Quat): Quat {\r\n return new Quat(\r\n this.w * q.x + this.x * q.w + this.y * q.z - this.z * q.y,\r\n this.w * q.y - this.x * q.z + this.y * q.w + this.z * q.x,\r\n this.w * q.z + this.x * q.y - this.y * q.x + this.z * q.w,\r\n this.w * q.w - this.x * q.x - this.y * q.y - this.z * q.z,\r\n );\r\n }\r\n\r\n /**\r\n * Convert quaternion to Euler angles (ZYX order)\r\n */\r\n toEuler(): Vec3 {\r\n // Roll (x-axis rotation)\r\n const sinr_cosp = 2 * (this.w * this.x + this.y * this.z);\r\n const cosr_cosp = 1 - 2 * (this.x * this.x + this.y * this.y);\r\n const roll = Math.atan2(sinr_cosp, cosr_cosp);\r\n\r\n // Pitch (y-axis rotation)\r\n const sinp = 2 * (this.w * this.y - this.z * this.x);\r\n let pitch: number;\r\n if (Math.abs(sinp) >= 1) {\r\n pitch = (Math.sign(sinp) * Math.PI) / 2; // Use 90 degrees if out of range\r\n } else {\r\n pitch = Math.asin(sinp);\r\n }\r\n\r\n // Yaw (z-axis rotation)\r\n const siny_cosp = 2 * (this.w * this.z + this.x * this.y);\r\n const cosy_cosp = 1 - 2 * (this.y * this.y + this.z * this.z);\r\n const yaw = Math.atan2(siny_cosp, cosy_cosp);\r\n\r\n return new Vec3(roll, pitch, yaw);\r\n }\r\n\r\n // Normalization\r\n normalize(): Quat {\r\n const len = Math.sqrt(\r\n this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w,\r\n );\r\n if (len < 1e-10) {\r\n return Quat.identity();\r\n }\r\n return new Quat(this.x / len, this.y / len, this.z / len, this.w / len);\r\n }\r\n\r\n normalizeInPlace(): Quat {\r\n const len = Math.sqrt(\r\n this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w,\r\n );\r\n if (len < 1e-10) {\r\n this.x = 0;\r\n this.y = 0;\r\n this.z = 0;\r\n this.w = 1;\r\n return this;\r\n }\r\n this.x /= len;\r\n this.y /= len;\r\n this.z /= len;\r\n this.w /= len;\r\n return this;\r\n }\r\n\r\n // Interpolation\r\n /**\r\n * Spherical linear interpolation between this quaternion and another\r\n * @param q - Target quaternion\r\n * @param t - Interpolation factor (0 to 1)\r\n */\r\n slerp(q: Quat, t: number): Quat {\r\n let dot = this.x * q.x + this.y * q.y + this.z * q.z + this.w * q.w;\r\n\r\n // If the dot product is negative, slerp won't take the shorter path\r\n // Fix by reversing one quaternion\r\n let q2 = q;\r\n if (dot < 0) {\r\n q2 = new Quat(-q.x, -q.y, -q.z, -q.w);\r\n dot = -dot;\r\n }\r\n\r\n // If quaternions are very close, use linear interpolation\r\n if (dot > 0.9995) {\r\n return new Quat(\r\n this.x + t * (q2.x - this.x),\r\n this.y + t * (q2.y - this.y),\r\n this.z + t * (q2.z - this.z),\r\n this.w + t * (q2.w - this.w),\r\n ).normalize();\r\n }\r\n\r\n // Calculate coefficients\r\n const theta = Math.acos(dot);\r\n const sinTheta = Math.sin(theta);\r\n const w1 = Math.sin((1 - t) * theta) / sinTheta;\r\n const w2 = Math.sin(t * theta) / sinTheta;\r\n\r\n return new Quat(\r\n this.x * w1 + q2.x * w2,\r\n this.y * w1 + q2.y * w2,\r\n this.z * w1 + q2.z * w2,\r\n this.w * w1 + q2.w * w2,\r\n );\r\n }\r\n\r\n // Utility\r\n clone(): Quat {\r\n return new Quat(this.x, this.y, this.z, this.w);\r\n }\r\n\r\n /**\r\n * Get the inverse (conjugate for unit quaternions) of this quaternion\r\n */\r\n inverse(): Quat {\r\n const lenSq = this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;\r\n if (lenSq < 1e-10) {\r\n return Quat.identity();\r\n }\r\n const invLen = 1.0 / lenSq;\r\n return new Quat(\r\n -this.x * invLen,\r\n -this.y * invLen,\r\n -this.z * invLen,\r\n this.w * invLen\r\n );\r\n }\r\n\r\n /**\r\n * Transform a vector by this quaternion\r\n * @param v - Vector to transform\r\n */\r\n transformVector(v: Vec3): Vec3 {\r\n // q * v * q^-1\r\n const qx = this.x, qy = this.y, qz = this.z, qw = this.w;\r\n const vx = v.x, vy = v.y, vz = v.z;\r\n\r\n // Calculate quat * vec\r\n const ix = qw * vx + qy * vz - qz * vy;\r\n const iy = qw * vy + qz * vx - qx * vz;\r\n const iz = qw * vz + qx * vy - qy * vx;\r\n const iw = -qx * vx - qy * vy - qz * vz;\r\n\r\n // Calculate result * inverse quat\r\n return new Vec3(\r\n ix * qw + iw * -qx + iy * -qz - iz * -qy,\r\n iy * qw + iw * -qy + iz * -qx - ix * -qz,\r\n iz * qw + iw * -qz + ix * -qy - iy * -qx\r\n );\r\n }\r\n}\r\n","import { Vec3 } from \"./Vec3\";\r\nimport { Quat } from \"./Quat\";\r\n\r\n/**\r\n * Mat4 - 4x4 Matrix utility class\r\n * Provides matrix operations for 3D transformations\r\n * Storage is column-major order (OpenGL/WebGPU convention)\r\n */\r\nexport class Mat4 {\r\n elements: Float32Array; // 16 elements, column-major order\r\n\r\n constructor() {\r\n this.elements = new Float32Array(16);\r\n }\r\n\r\n // Factory methods\r\n static identity(): Mat4 {\r\n const m = new Mat4();\r\n m.elements[0] = 1;\r\n m.elements[5] = 1;\r\n m.elements[10] = 1;\r\n m.elements[15] = 1;\r\n return m;\r\n }\r\n\r\n static fromTranslation(v: Vec3): Mat4 {\r\n const m = Mat4.identity();\r\n m.elements[12] = v.x;\r\n m.elements[13] = v.y;\r\n m.elements[14] = v.z;\r\n return m;\r\n }\r\n\r\n static fromRotation(q: Quat): Mat4 {\r\n const m = new Mat4();\r\n const e = m.elements;\r\n\r\n const x2 = q.x + q.x;\r\n const y2 = q.y + q.y;\r\n const z2 = q.z + q.z;\r\n const xx = q.x * x2;\r\n const xy = q.x * y2;\r\n const xz = q.x * z2;\r\n const yy = q.y * y2;\r\n const yz = q.y * z2;\r\n const zz = q.z * z2;\r\n const wx = q.w * x2;\r\n const wy = q.w * y2;\r\n const wz = q.w * z2;\r\n\r\n e[0] = 1 - (yy + zz);\r\n e[1] = xy + wz;\r\n e[2] = xz - wy;\r\n e[3] = 0;\r\n\r\n e[4] = xy - wz;\r\n e[5] = 1 - (xx + zz);\r\n e[6] = yz + wx;\r\n e[7] = 0;\r\n\r\n e[8] = xz + wy;\r\n e[9] = yz - wx;\r\n e[10] = 1 - (xx + yy);\r\n e[11] = 0;\r\n\r\n e[12] = 0;\r\n e[13] = 0;\r\n e[14] = 0;\r\n e[15] = 1;\r\n\r\n return m;\r\n }\r\n\r\n static fromScale(v: Vec3): Mat4 {\r\n const m = new Mat4();\r\n m.elements[0] = v.x;\r\n m.elements[5] = v.y;\r\n m.elements[10] = v.z;\r\n m.elements[15] = 1;\r\n return m;\r\n }\r\n\r\n static compose(position: Vec3, rotation: Quat, scale: Vec3): Mat4 {\r\n const m = Mat4.fromRotation(rotation);\r\n const e = m.elements;\r\n\r\n // Apply scale\r\n e[0] *= scale.x;\r\n e[1] *= scale.x;\r\n e[2] *= scale.x;\r\n e[4] *= scale.y;\r\n e[5] *= scale.y;\r\n e[6] *= scale.y;\r\n e[8] *= scale.z;\r\n e[9] *= scale.z;\r\n e[10] *= scale.z;\r\n\r\n // Apply translation\r\n e[12] = position.x;\r\n e[13] = position.y;\r\n e[14] = position.z;\r\n\r\n return m;\r\n }\r\n\r\n // Operations\r\n multiply(m: Mat4): Mat4 {\r\n const result = new Mat4();\r\n const a = this.elements;\r\n const b = m.elements;\r\n const r = result.elements;\r\n\r\n for (let i = 0; i < 4; i++) {\r\n for (let j = 0; j < 4; j++) {\r\n r[i * 4 + j] =\r\n a[j] * b[i * 4] +\r\n a[j + 4] * b[i * 4 + 1] +\r\n a[j + 8] * b[i * 4 + 2] +\r\n a[j + 12] * b[i * 4 + 3];\r\n }\r\n }\r\n\r\n return result;\r\n }\r\n\r\n multiplyInPlace(m: Mat4): Mat4 {\r\n const temp = this.multiply(m);\r\n this.elements.set(temp.elements);\r\n return this;\r\n }\r\n\r\n inverse(): Mat4 | null {\r\n const e = this.elements;\r\n const inv = new Float32Array(16);\r\n\r\n inv[0] =\r\n e[5] * e[10] * e[15] -\r\n e[5] * e[11] * e[14] -\r\n e[9] * e[6] * e[15] +\r\n e[9] * e[7] * e[14] +\r\n e[13] * e[6] * e[11] -\r\n e[13] * e[7] * e[10];\r\n inv[4] =\r\n -e[4] * e[10] * e[15] +\r\n e[4] * e[11] * e[14] +\r\n e[8] * e[6] * e[15] -\r\n e[8] * e[7] * e[14] -\r\n e[12] * e[6] * e[11] +\r\n e[12] * e[7] * e[10];\r\n inv[8] =\r\n e[4] * e[9] * e[15] -\r\n e[4] * e[11] * e[13] -\r\n e[8] * e[5] * e[15] +\r\n e[8] * e[7] * e[13] +\r\n e[12] * e[5] * e[11] -\r\n e[12] * e[7] * e[9];\r\n inv[12] =\r\n -e[4] * e[9] * e[14] +\r\n e[4] * e[10] * e[13] +\r\n e[8] * e[5] * e[14] -\r\n e[8] * e[6] * e[13] -\r\n e[12] * e[5] * e[10] +\r\n e[12] * e[6] * e[9];\r\n\r\n inv[1] =\r\n -e[1] * e[10] * e[15] +\r\n e[1] * e[11] * e[14] +\r\n e[9] * e[2] * e[15] -\r\n e[9] * e[3] * e[14] -\r\n e[13] * e[2] * e[11] +\r\n e[13] * e[3] * e[10];\r\n inv[5] =\r\n e[0] * e[10] * e[15] -\r\n e[0] * e[11] * e[14] -\r\n e[8] * e[2] * e[15] +\r\n e[8] * e[3] * e[14] +\r\n e[12] * e[2] * e[11] -\r\n e[12] * e[3] * e[10];\r\n inv[9] =\r\n -e[0] * e[9] * e[15] +\r\n e[0] * e[11] * e[13] +\r\n e[8] * e[1] * e[15] -\r\n e[8] * e[3] * e[13] -\r\n e[12] * e[1] * e[11] +\r\n e[12] * e[3] * e[9];\r\n inv[13] =\r\n e[0] * e[9] * e[14] -\r\n e[0] * e[10] * e[13] -\r\n e[8] * e[1] * e[14] +\r\n e[8] * e[2] * e[13] +\r\n e[12] * e[1] * e[10] -\r\n e[12] * e[2] * e[9];\r\n\r\n inv[2] =\r\n e[1] * e[6] * e[15] -\r\n e[1] * e[7] * e[14] -\r\n e[5] * e[2] * e[15] +\r\n e[5] * e[3] * e[14] +\r\n e[13] * e[2] * e[7] -\r\n e[13] * e[3] * e[6];\r\n inv[6] =\r\n -e[0] * e[6] * e[15] +\r\n e[0] * e[7] * e[14] +\r\n e[4] * e[2] * e[15] -\r\n e[4] * e[3] * e[14] -\r\n e[12] * e[2] * e[7] +\r\n e[12] * e[3] * e[6];\r\n inv[10] =\r\n e[0] * e[5] * e[15] -\r\n e[0] * e[7] * e[13] -\r\n e[4] * e[1] * e[15] +\r\n e[4] * e[3] * e[13] +\r\n e[12] * e[1] * e[7] -\r\n e[12] * e[3] * e[5];\r\n inv[14] =\r\n -e[0] * e[5] * e[14] +\r\n e[0] * e[6] * e[13] +\r\n e[4] * e[1] * e[14] -\r\n e[4] * e[2] * e[13] -\r\n e[12] * e[1] * e[6] +\r\n e[12] * e[2] * e[5];\r\n\r\n inv[3] =\r\n -e[1] * e[6] * e[11] +\r\n e[1] * e[7] * e[10] +\r\n e[5] * e[2] * e[11] -\r\n e[5] * e[3] * e[10] -\r\n e[9] * e[2] * e[7] +\r\n e[9] * e[3] * e[6];\r\n inv[7] =\r\n e[0] * e[6] * e[11] -\r\n e[0] * e[7] * e[10] -\r\n e[4] * e[2] * e[11] +\r\n e[4] * e[3] * e[10] +\r\n e[8] * e[2] * e[7] -\r\n e[8] * e[3] * e[6];\r\n inv[11] =\r\n -e[0] * e[5] * e[11] +\r\n e[0] * e[7] * e[9] +\r\n e[4] * e[1] * e[11] -\r\n e[4] * e[3] * e[9] -\r\n e[8] * e[1] * e[7] +\r\n e[8] * e[3] * e[5];\r\n inv[15] =\r\n e[0] * e[5] * e[10] -\r\n e[0] * e[6] * e[9] -\r\n e[4] * e[1] * e[10] +\r\n e[4] * e[2] * e[9] +\r\n e[8] * e[1] * e[6] -\r\n e[8] * e[2] * e[5];\r\n\r\n const det = e[0] * inv[0] + e[1] * inv[4] + e[2] * inv[8] + e[3] * inv[12];\r\n\r\n if (Math.abs(det) < 1e-10) {\r\n return null; // Matrix is singular\r\n }\r\n\r\n const invDet = 1.0 / det;\r\n const result = new Mat4();\r\n for (let i = 0; i < 16; i++) {\r\n result.elements[i] = inv[i] * invDet;\r\n }\r\n\r\n return result;\r\n }\r\n\r\n transpose(): Mat4 {\r\n const m = new Mat4();\r\n const e = this.elements;\r\n const r = m.elements;\r\n\r\n r[0] = e[0];\r\n r[1] = e[4];\r\n r[2] = e[8];\r\n r[3] = e[12];\r\n r[4] = e[1];\r\n r[5] = e[5];\r\n r[6] = e[9];\r\n r[7] = e[13];\r\n r[8] = e[2];\r\n r[9] = e[6];\r\n r[10] = e[10];\r\n r[11] = e[14];\r\n r[12] = e[3];\r\n r[13] = e[7];\r\n r[14] = e[11];\r\n r[15] = e[15];\r\n\r\n return m;\r\n }\r\n\r\n // Decomposition\r\n decompose(): { position: Vec3; rotation: Quat; scale: Vec3 } | null {\r\n const e = this.elements;\r\n\r\n // Extract translation\r\n const position = new Vec3(e[12], e[13], e[14]);\r\n\r\n // Extract scale\r\n const sx = Math.sqrt(e[0] * e[0] + e[1] * e[1] + e[2] * e[2]);\r\n const sy = Math.sqrt(e[4] * e[4] + e[5] * e[5] + e[6] * e[6]);\r\n const sz = Math.sqrt(e[8] * e[8] + e[9] * e[9] + e[10] * e[10]);\r\n\r\n const scale = new Vec3(sx, sy, sz);\r\n\r\n // Check for zero scale\r\n if (sx < 1e-10 || sy < 1e-10 || sz < 1e-10) {\r\n return null;\r\n }\r\n\r\n // Extract rotation by removing scale\r\n const m11 = e[0] / sx;\r\n const m12 = e[1] / sx;\r\n const m13 = e[2] / sx;\r\n const m21 = e[4] / sy;\r\n const m22 = e[5] / sy;\r\n const m23 = e[6] / sy;\r\n const m31 = e[8] / sz;\r\n const m32 = e[9] / sz;\r\n const m33 = e[10] / sz;\r\n\r\n // Convert rotation matrix to quaternion\r\n const trace = m11 + m22 + m33;\r\n let rotation: Quat;\r\n\r\n if (trace > 0) {\r\n const s = 0.5 / Math.sqrt(trace + 1.0);\r\n rotation = new Quat(\r\n (m23 - m32) * s,\r\n (m31 - m13) * s,\r\n (m12 - m21) * s,\r\n 0.25 / s,\r\n );\r\n } else if (m11 > m22 && m11 > m33) {\r\n const s = 2.0 * Math.sqrt(1.0 + m11 - m22 - m33);\r\n rotation = new Quat(\r\n 0.25 * s,\r\n (m21 + m12) / s,\r\n (m31 + m13) / s,\r\n (m23 - m32) / s,\r\n );\r\n } else if (m22 > m33) {\r\n const s = 2.0 * Math.sqrt(1.0 + m22 - m11 - m33);\r\n rotation = new Quat(\r\n (m21 + m12) / s,\r\n 0.25 * s,\r\n (m32 + m23) / s,\r\n (m31 - m13) / s,\r\n );\r\n } else {\r\n const s = 2.0 * Math.sqrt(1.0 + m33 - m11 - m22);\r\n rotation = new Quat(\r\n (m31 + m13) / s,\r\n (m32 + m23) / s,\r\n 0.25 * s,\r\n (m12 - m21) / s,\r\n );\r\n }\r\n\r\n return { position, rotation, scale };\r\n }\r\n\r\n // Transformation\r\n transformPoint(v: Vec3): Vec3 {\r\n const e = this.elements;\r\n const x = v.x;\r\n const y = v.y;\r\n const z = v.z;\r\n const w = e[3] * x + e[7] * y + e[11] * z + e[15];\r\n\r\n return new Vec3(\r\n (e[0] * x + e[4] * y + e[8] * z + e[12]) / w,\r\n (e[1] * x + e[5] * y + e[9] * z + e[13]) / w,\r\n (e[2] * x + e[6] * y + e[10] * z + e[14]) / w,\r\n );\r\n }\r\n\r\n transformDirection(v: Vec3): Vec3 {\r\n const e = this.elements;\r\n return new Vec3(\r\n e[0] * v.x + e[4] * v.y + e[8] * v.z,\r\n e[1] * v.x + e[5] * v.y + e[9] * v.z,\r\n e[2] * v.x + e[6] * v.y + e[10] * v.z,\r\n );\r\n }\r\n\r\n /**\r\n * Transform a vector (direction) by this matrix (ignores translation)\r\n * Alias for transformDirection for compatibility\r\n */\r\n transformVector(v: Vec3): Vec3 {\r\n return this.transformDirection(v);\r\n }\r\n\r\n /**\r\n * Returns the inverse of this matrix\r\n * Returns identity matrix if singular (non-invertible)\r\n */\r\n invert(): Mat4 {\r\n const result = this.inverse();\r\n if (result === null) {\r\n return Mat4.identity();\r\n }\r\n return result;\r\n }\r\n\r\n // Utility\r\n clone(): Mat4 {\r\n const m = new Mat4();\r\n m.elements.set(this.elements);\r\n return m;\r\n }\r\n}\r\n","import { Vec3 } from \"../math/Vec3\";\r\nimport { Ray } from \"../math/Ray\";\r\nimport { Mat4 } from \"../math/Mat4\";\r\nimport { Quat } from \"../math/Quat\";\r\n\r\n/**\r\n * GizmoAxis - 轴类型枚举\r\n */\r\nexport type GizmoAxisType = 'x' | 'y' | 'z' | 'xy' | 'xz' | 'yz' | 'xyz';\r\n\r\n/**\r\n * Vec4Color - 带透明度的颜色\r\n */\r\nexport interface Vec4Color {\r\n r: number;\r\n g: number;\r\n b: number;\r\n a: number;\r\n}\r\n\r\n/**\r\n * ShapeConfig - Shape 配置\r\n */\r\nexport interface ShapeConfig {\r\n axis: GizmoAxisType;\r\n defaultColor: Vec3;\r\n hoverColor: Vec3;\r\n disabledColor: Vec3;\r\n defaultAlpha?: number; // 默认透明度\r\n hoverAlpha?: number; // hover 透明度\r\n rotation?: Vec3; // 欧拉角旋转\r\n}\r\n\r\n/**\r\n * TriData - 三角形碰撞数据\r\n */\r\nexport interface TriData {\r\n vertices: Float32Array; // 三角形顶点\r\n indices: Uint16Array; // 索引\r\n transform: Mat4; // 局部变换矩阵\r\n priority: number; // 碰撞优先级(越高越优先)\r\n}\r\n\r\n/**\r\n * Shape - Gizmo 形状基类\r\n * 参考 PlayCanvas 引擎的 Shape 实现\r\n */\r\nexport abstract class Shape {\r\n axis: GizmoAxisType;\r\n \r\n // 状态\r\n protected _disabled: boolean = false;\r\n protected _visible: boolean = true;\r\n protected _hovered: boolean = false;\r\n protected _interactable: boolean = true; // 是否可交互(碰撞检测)\r\n \r\n // 颜色\r\n protected _defaultColor: Vec3;\r\n protected _hoverColor: Vec3;\r\n protected _disabledColor: Vec3;\r\n protected _defaultAlpha: number = 1.0;\r\n protected _hoverAlpha: number = 1.0;\r\n \r\n // 变换\r\n protected _position: Vec3 = new Vec3(0, 0, 0);\r\n protected _rotation: Vec3 = new Vec3(0, 0, 0); // 欧拉角\r\n protected _scale: Vec3 = new Vec3(1, 1, 1);\r\n \r\n // 碰撞数据\r\n triData: TriData[] = [];\r\n \r\n // GPU 资源\r\n protected device: GPUDevice | null = null;\r\n protected vertexBuffer: GPUBuffer | null = null;\r\n protected indexBuffer: GPUBuffer | null = null;\r\n protected vertexCount: number = 0;\r\n protected indexCount: number = 0;\r\n \r\n // 翻转状态(用于平面)\r\n flipped: Vec3 = new Vec3(0, 0, 0);\r\n \r\n constructor(config: ShapeConfig) {\r\n this.axis = config.axis;\r\n this._defaultColor = config.defaultColor.clone();\r\n this._hoverColor = config.hoverColor.clone();\r\n this._disabledColor = config.disabledColor.clone();\r\n this._defaultAlpha = config.defaultAlpha ?? 1.0;\r\n this._hoverAlpha = config.hoverAlpha ?? 1.0;\r\n \r\n if (config.rotation) {\r\n this._rotation = config.rotation.clone();\r\n }\r\n }\r\n \r\n get disabled(): boolean {\r\n return this._disabled;\r\n }\r\n \r\n set disabled(value: boolean) {\r\n this._disabled = value;\r\n if (value) {\r\n this._hovered = false;\r\n }\r\n }\r\n \r\n get visible(): boolean {\r\n return this._visible;\r\n }\r\n \r\n set visible(value: boolean) {\r\n this._visible = value;\r\n // 默认情况下,visible 也控制 interactable\r\n // 但可以单独设置 interactable 来覆盖\r\n }\r\n \r\n get interactable(): boolean {\r\n return this._interactable;\r\n }\r\n \r\n set interactable(value: boolean) {\r\n this._interactable = value;\r\n }\r\n \r\n /**\r\n * 设置 hover 状态\r\n */\r\n hover(state: boolean): void {\r\n if (this._disabled) {\r\n this._hovered = false;\r\n return;\r\n }\r\n this._hovered = state;\r\n }\r\n \r\n /**\r\n * 获取当前颜色(包含透明度)\r\n */\r\n getColor(): Vec4Color {\r\n if (this._disabled) {\r\n return { r: this._disabledColor.x, g: this._disabledColor.y, b: this._disabledColor.z, a: 1.0 };\r\n }\r\n if (this._hovered) {\r\n return { r: this._hoverColor.x, g: this._hoverColor.y, b: this._hoverColor.z, a: this._hoverAlpha };\r\n }\r\n return { r: this._defaultColor.x, g: this._defaultColor.y, b: this._defaultColor.z, a: this._defaultAlpha };\r\n }\r\n \r\n /**\r\n * 获取局部变换矩阵\r\n */\r\n getLocalTransform(): Mat4 {\r\n // 将欧拉角(度)转换为弧度\r\n const rotX = this._rotation.x * Math.PI / 180;\r\n const rotY = this._rotation.y * Math.PI / 180;\r\n const rotZ = this._rotation.z * Math.PI / 180;\r\n \r\n const rotation = Quat.fromEuler(rotX, rotY, rotZ);\r\n \r\n // Debug: 输出旋转信息\r\n // console.log(`Shape ${this.axis} rotation (deg):`, this._rotation);\r\n // console.log(`Shape ${this.axis} rotation (rad):`, rotX, rotY, rotZ);\r\n // console.log(`Shape ${this.axis} quaternion:`, rotation);\r\n \r\n return Mat4.compose(this._position, rotation, this._scale);\r\n }\r\n \r\n /**\r\n * 射线碰撞检测\r\n * @param ray - 世界空间射线\r\n * @param parentTransform - 父级变换矩阵(gizmo 的世界变换)\r\n * @returns 碰撞距离,null 表示未碰撞\r\n */\r\n intersect(ray: Ray, parentTransform: Mat4): number | null {\r\n // disabled 或 不可交互时跳过碰撞检测\r\n if (this._disabled || !this._interactable) {\r\n return null;\r\n }\r\n \r\n let closestDist: number | null = null;\r\n let highestPriority = -Infinity;\r\n \r\n for (const tri of this.triData) {\r\n // 计算完整变换:parent * local * triTransform\r\n const localTransform = this.getLocalTransform();\r\n const worldTransform = parentTransform.multiply(localTransform).multiply(tri.transform);\r\n const invTransform = worldTransform.invert();\r\n \r\n // 将射线变换到局部空间\r\n const localRay = ray.transform(invTransform);\r\n \r\n // 与三角形进行碰撞检测\r\n const dist = this.intersectTriangles(localRay, tri.vertices, tri.indices);\r\n \r\n if (dist !== null) {\r\n // 考虑优先级\r\n if (tri.priority > highestPriority || \r\n (tri.priority === highestPriority && (closestDist === null || dist < closestDist))) {\r\n closestDist = dist;\r\n highestPriority = tri.priority;\r\n }\r\n }\r\n }\r\n \r\n return closestDist;\r\n }\r\n \r\n /**\r\n * 射线与三角形列表碰撞检测\r\n */\r\n protected intersectTriangles(\r\n ray: Ray, \r\n vertices: Float32Array, \r\n indices: Uint16Array\r\n ): number | null {\r\n let closestDist: number | null = null;\r\n \r\n for (let i = 0; i < indices.length; i += 3) {\r\n const i0 = indices[i] * 3;\r\n const i1 = indices[i + 1] * 3;\r\n const i2 = indices[i + 2] * 3;\r\n \r\n const v0 = new Vec3(vertices[i0], vertices[i0 + 1], vertices[i0 + 2]);\r\n const v1 = new Vec3(vertices[i1], vertices[i1 + 1], vertices[i1 + 2]);\r\n const v2 = new Vec3(vertices[i2], vertices[i2 + 1], vertices[i2 + 2]);\r\n \r\n const dist = ray.intersectTriangle(v0, v1, v2);\r\n \r\n if (dist !== null && dist > 0) {\r\n if (closestDist === null || dist < closestDist) {\r\n closestDist = dist;\r\n }\r\n }\r\n }\r\n \r\n return closestDist;\r\n }\r\n \r\n /**\r\n * 创建 GPU 资源\r\n */\r\n abstract createGeometry(device: GPUDevice): void;\r\n \r\n /**\r\n * 获取顶点缓冲区\r\n */\r\n getVertexBuffer(): GPUBuffer | null {\r\n return this.vertexBuffer;\r\n }\r\n \r\n /**\r\n * 获取索引缓冲区\r\n */\r\n getIndexBuffer(): GPUBuffer | null {\r\n return this.indexBuffer;\r\n }\r\n \r\n /**\r\n * 获取索引数量\r\n */\r\n getIndexCount(): number {\r\n return this.indexCount;\r\n }\r\n \r\n /**\r\n * 销毁 GPU 资源\r\n */\r\n destroy(): void {\r\n if (this.vertexBuffer) {\r\n this.vertexBuffer.destroy();\r\n this.vertexBuffer = null;\r\n }\r\n if (this.indexBuffer) {\r\n this.indexBuffer.destroy();\r\n this.indexBuffer = null;\r\n }\r\n }\r\n \r\n /**\r\n * 创建 GPU 缓冲区\r\n */\r\n protected createBuffers(\r\n device: GPUDevice,\r\n vertices: Float32Array,\r\n indices: Uint16Array\r\n ): void {\r\n this.device = device;\r\n this.vertexCount = vertices.length / 6;\r\n this.indexCount = indices.length;\r\n \r\n // 创建顶点缓冲区\r\n this.vertexBuffer = device.createBuffer({\r\n size: vertices.byteLength,\r\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\r\n mappedAtCreation: true,\r\n });\r\n new Float32Array(this.vertexBuffer.getMappedRange()).set(vertices);\r\n this.vertexBuffer.unmap();\r\n \r\n // 创建索引缓冲区\r\n this.indexBuffer = device.createBuffer({\r\n size: indices.byteLength,\r\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\r\n mappedAtCreation: true,\r\n });\r\n new Uint16Array(this.indexBuffer.getMappedRange()).set(indices);\r\n this.indexBuffer.unmap();\r\n }\r\n}\r\n","import { Vec3 } from \"../math/Vec3\";\r\nimport { Mat4 } from \"../math/Mat4\";\r\nimport { Quat } from \"../math/Quat\";\r\nimport { Shape, ShapeConfig, TriData } from \"./Shape\";\r\n\r\n/**\r\n * ArrowShapeConfig - 箭头形状配置\r\n */\r\nexport interface ArrowShapeConfig extends ShapeConfig {\r\n gap?: number; // 箭头起点与中心的间距\r\n lineThickness?: number; // 线条粗细\r\n lineLength?: number; // 线条长度\r\n arrowThickness?: number;// 箭头粗细\r\n arrowLength?: number; // 箭头长度\r\n tolerance?: number; // 碰撞检测容差\r\n}\r\n\r\n/**\r\n * ArrowShape - 箭头形状(用于平移 Gizmo)\r\n * 参考 PlayCanvas 引擎的 ArrowShape 实现\r\n */\r\nexport class ArrowShape extends Shape {\r\n private _gap: number = 0;\r\n private _lineThickness: number = 0.02;\r\n private _lineLength: number = 0.5;\r\n private _arrowThickness: number = 0.12;\r\n private _arrowLength: number = 0.18;\r\n private _tolerance: number = 0.1;\r\n \r\n constructor(config: ArrowShapeConfig) {\r\n super(config);\r\n \r\n this._gap = config.gap ?? this._gap;\r\n this._lineThickness = config.lineThickness ?? this._lineThickness;\r\n this._lineLength = config.lineLength ?? this._lineLength;\r\n this._arrowThickness = config.arrowThickness ?? this._arrowThickness;\r\n this._arrowLength = config.arrowLength ?? this._arrowLength;\r\n this._tolerance = config.tolerance ?? this._tolerance;\r\n \r\n this._updateTriData();\r\n }\r\n \r\n get gap(): number { return this._gap; }\r\n set gap(value: number) { this._gap = value; this._updateTriData(); }\r\n \r\n get lineThickness(): number { return this._lineThickness; }\r\n set lineThickness(value: number) { this._lineThickness = value; this._updateTriData(); }\r\n \r\n get lineLength(): number { return this._lineLength; }\r\n set lineLength(value: number) { this._lineLength = value; this._updateTriData(); }\r\n \r\n get arrowThickness(): number { return this._arrowThickness; }\r\n set arrowThickness(value: number) { this._arrowThickness = value; this._updateTriData(); }\r\n \r\n get arrowLength(): number { return this._arrowLength; }\r\n set arrowLength(value: number) { this._arrowLength = value; this._updateTriData(); }\r\n \r\n /**\r\n * 更新碰撞数据\r\n */\r\n private _updateTriData(): void {\r\n // 箭头锥体碰撞数据\r\n const conePos = new Vec3(0, this._gap + this._arrowLength * 0.5 + this._lineLength, 0);\r\n const coneScale = new Vec3(this._arrowThickness, this._arrowLength, this._arrowThickness);\r\n const coneTransform = Mat4.compose(conePos, Quat.identity(), coneScale);\r\n \r\n // 线条圆柱碰撞数据(加上容差)\r\n const linePos = new Vec3(0, this._gap + this._lineLength * 0.5, 0);\r\n const lineScale = new Vec3(\r\n this._lineThickness + this._tolerance,\r\n this._lineLength,\r\n this._lineThickness + this._tolerance\r\n );\r\n const lineTransform = Mat4.compose(linePos, Quat.identity(), lineScale);\r\n \r\n // 生成单位锥体和圆柱的三角形数据\r\n const coneGeo = this.createConeGeometry();\r\n const cylinderGeo = this.createCylinderGeometry();\r\n \r\n this.triData = [\r\n {\r\n vertices: coneGeo.vertices,\r\n indices: coneGeo.indices,\r\n transform: coneTransform,\r\n priority: 0\r\n },\r\n {\r\n vertices: cylinderGeo.vertices,\r\n indices: cylinderGeo.indices,\r\n transform: lineTransform,\r\n priority: 1 // 线条优先级更高,更容易选中\r\n }\r\n ];\r\n }\r\n \r\n /**\r\n * 创建单位锥体几何体(底面半径1,高度1,底面在y=0,顶点在y=1)\r\n */\r\n private createConeGeometry(): { vertices: Float32Array; indices: Uint16Array } {\r\n const segments = 12;\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n \r\n // 底面中心\r\n vertices.push(0, -0.5, 0);\r\n \r\n // 底面顶点\r\n for (let i = 0; i <= segments; i++) {\r\n const angle = (i / segments) * Math.PI * 2;\r\n vertices.push(Math.cos(angle) * 0.5, -0.5, Math.sin(angle) * 0.5);\r\n }\r\n \r\n // 顶点\r\n const tipIndex = vertices.length / 3;\r\n vertices.push(0, 0.5, 0);\r\n \r\n // 底面三角形\r\n for (let i = 1; i <= segments; i++) {\r\n indices.push(0, i + 1, i);\r\n }\r\n \r\n // 侧面三角形\r\n for (let i = 1; i <= segments; i++) {\r\n indices.push(i, i + 1, tipIndex);\r\n }\r\n \r\n return {\r\n vertices: new Float32Array(vertices),\r\n indices: new Uint16Array(indices)\r\n };\r\n }\r\n \r\n /**\r\n * 创建单位圆柱几何体(半径1,高度1,中心在原点)\r\n */\r\n private createCylinderGeometry(): { vertices: Float32Array; indices: Uint16Array } {\r\n const segments = 12;\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n \r\n // 底面和顶面顶点\r\n for (let i = 0; i <= segments; i++) {\r\n const angle = (i / segments) * Math.PI * 2;\r\n const x = Math.cos(angle) * 0.5;\r\n const z = Math.sin(angle) * 0.5;\r\n \r\n // 底面\r\n vertices.push(x, -0.5, z);\r\n // 顶面\r\n vertices.push(x, 0.5, z);\r\n }\r\n \r\n // 侧面三角形\r\n for (let i = 0; i < segments; i++) {\r\n const base = i * 2;\r\n indices.push(base, base + 1, base + 2);\r\n indices.push(base + 1, base + 3, base + 2);\r\n }\r\n \r\n return {\r\n vertices: new Float32Array(vertices),\r\n indices: new Uint16Array(indices)\r\n };\r\n }\r\n \r\n /**\r\n * 创建渲染用的 GPU 几何体\r\n */\r\n createGeometry(device: GPUDevice): void {\r\n const segments = 12;\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n \r\n const color = this._defaultColor;\r\n \r\n // 辅助函数:添加顶点\r\n const addVertex = (x: number, y: number, z: number) => {\r\n vertices.push(x, y, z, color.x, color.y, color.z);\r\n };\r\n \r\n // 计算垂直向量\r\n let perpX: Vec3, perpY: Vec3;\r\n const dir = new Vec3(0, 1, 0); // 默认沿 Y 轴\r\n perpX = new Vec3(1, 0, 0);\r\n perpY = new Vec3(0, 0, 1);\r\n \r\n // 生成圆柱(线条部分)\r\n const cylinderStart = this._gap;\r\n const cylinderEnd = this._gap + this._lineLength;\r\n \r\n for (let i = 0; i <= segments; i++) {\r\n const angle = (i / segments) * Math.PI * 2;\r\n const cos = Math.cos(angle);\r\n const sin = Math.sin(angle);\r\n \r\n const offsetX = cos * this._lineThickness;\r\n const offsetZ = sin * this._lineThickness;\r\n \r\n // 底部顶点\r\n addVertex(offsetX, cylinderStart, offsetZ);\r\n // 顶部顶点\r\n addVertex(offsetX, cylinderEnd, offsetZ);\r\n }\r\n \r\n // 圆柱索引\r\n for (let i = 0; i < segments; i++) {\r\n const base = i * 2;\r\n indices.push(base, base + 1, base + 2);\r\n indices.push(base + 1, base + 3, base + 2);\r\n }\r\n \r\n // 生成锥体(箭头部分)\r\n const coneBase = this._gap + this._lineLength;\r\n const coneTip = coneBase + this._arrowLength;\r\n \r\n const coneBaseIndex = vertices.length / 6;\r\n \r\n // 锥体底面顶点\r\n for (let i = 0; i <= segments; i++) {\r\n const angle = (i / segments) * Math.PI * 2;\r\n const cos = Math.cos(angle);\r\n const sin = Math.sin(angle);\r\n \r\n const offsetX = cos * this._arrowThickness;\r\n const offsetZ = sin * this._arrowThickness;\r\n \r\n addVertex(offsetX, coneBase, offsetZ);\r\n }\r\n \r\n // 锥体顶点\r\n const coneTipIndex = vertices.length / 6;\r\n addVertex(0, coneTip, 0);\r\n \r\n // 锥体索引\r\n for (let i = 0; i < segments; i++) {\r\n indices.push(coneBaseIndex + i, coneTipIndex, coneBaseIndex + i + 1);\r\n }\r\n \r\n this.createBuffers(device, new Float32Array(vertices), new Uint16Array(indices));\r\n }\r\n}\r\n","import { Vec3 } from \"../math/Vec3\";\r\nimport { Mat4 } from \"../math/Mat4\";\r\nimport { Quat } from \"../math/Quat\";\r\nimport { Shape, ShapeConfig } from \"./Shape\";\r\n\r\n/**\r\n * PlaneShapeConfig - 平面形状配置\r\n */\r\nexport interface PlaneShapeConfig extends ShapeConfig {\r\n size?: number; // 平面大小\r\n gap?: number; // 与中心的间距\r\n}\r\n\r\n/**\r\n * PlaneShape - 平面形状(用于双轴平移)\r\n * 参考 PlayCanvas 引擎的 PlaneShape 实现\r\n */\r\nexport class PlaneShape extends Shape {\r\n private _size: number = 0.2;\r\n private _gap: number = 0.1;\r\n \r\n // 缓存不同翻转状态的几何数据\r\n private _geometryCache: Map<string, { vertexBuffer: GPUBuffer; indexBuffer: GPUBuffer }> = new Map();\r\n private _currentFlipKey: string = '0,0,0';\r\n \r\n constructor(config: PlaneShapeConfig) {\r\n super(config);\r\n \r\n this._size = config.size ?? this._size;\r\n this._gap = config.gap ?? this._gap;\r\n \r\n this._updateTriData();\r\n }\r\n \r\n get size(): number { return this._size; }\r\n set size(value: number) { \r\n this._size = value; \r\n this._updateTriData(); \r\n this._clearGeometryCache();\r\n }\r\n \r\n get gap(): number { return this._gap; }\r\n set gap(value: number) { \r\n this._gap = value; \r\n this._updateTriData(); \r\n this._clearGeometryCache();\r\n }\r\n \r\n /**\r\n * 更新碰撞数据\r\n */\r\n private _updateTriData(): void {\r\n const planeGeo = this.createPlaneGeometry();\r\n \r\n // 平面位置(考虑翻转)\r\n const pos = new Vec3(\r\n (this._gap + this._size * 0.5) * (1 - this.flipped.x * 2),\r\n 0,\r\n (this._gap + this._size * 0.5) * (1 - this.flipped.z * 2)\r\n );\r\n \r\n const scale = new Vec3(this._size, 1, this._size);\r\n const transform = Mat4.compose(pos, Quat.identity(), scale);\r\n \r\n this.triData = [{\r\n vertices: planeGeo.vertices,\r\n indices: planeGeo.indices,\r\n transform: transform,\r\n priority: 2\r\n }];\r\n }\r\n \r\n /**\r\n * 创建单位平面几何体\r\n */\r\n private createPlaneGeometry(): { vertices: Float32Array; indices: Uint16Array } {\r\n const vertices = new Float32Array([\r\n -0.5, 0, -0.5,\r\n 0.5, 0, -0.5,\r\n 0.5, 0, 0.5,\r\n -0.5, 0, 0.5\r\n ]);\r\n \r\n const indices = new Uint16Array([\r\n 0, 1, 2,\r\n 0, 2, 3,\r\n 0, 2, 1,\r\n 0, 3, 2\r\n ]);\r\n \r\n return { vertices, indices };\r\n }\r\n \r\n /**\r\n * 创建渲染用的 GPU 几何体\r\n */\r\n createGeometry(device: GPUDevice): void {\r\n this.device = device;\r\n this._currentFlipKey = `${this.flipped.x},${this.flipped.y},${this.flipped.z}`;\r\n \r\n // 检查缓存\r\n if (this._geometryCache.has(this._currentFlipKey)) {\r\n const cached = this._geometryCache.get(this._currentFlipKey)!;\r\n this.vertexBuffer = cached.vertexBuffer;\r\n this.indexBuffer = cached.indexBuffer;\r\n this.indexCount = 12;\r\n return;\r\n }\r\n \r\n const color = this._defaultColor;\r\n \r\n // 计算平面位置(考虑翻转)\r\n const offsetX = (this._gap + this._size * 0.5) * (1 - this.flipped.x * 2);\r\n const offsetZ = (this._gap + this._size * 0.5) * (1 - this.flipped.z * 2);\r\n const halfSize = this._size * 0.5;\r\n \r\n const vertices = new Float32Array([\r\n offsetX - halfSize, 0, offsetZ - halfSize, color.x, color.y, color.z,\r\n offsetX + halfSize, 0, offsetZ - halfSize, color.x, color.y, color.z,\r\n offsetX + halfSize, 0, offsetZ + halfSize, color.x, color.y, color.z,\r\n offsetX - halfSize, 0, offsetZ + halfSize, color.x, color.y, color.z,\r\n ]);\r\n \r\n const indices = new Uint16Array([\r\n 0, 1, 2,\r\n 0, 2, 3,\r\n 0, 2, 1,\r\n 0, 3, 2\r\n ]);\r\n \r\n this.createBuffers(device, vertices, indices);\r\n \r\n // 缓存\r\n if (this.vertexBuffer && this.indexBuffer) {\r\n this._geometryCache.set(this._currentFlipKey, {\r\n vertexBuffer: this.vertexBuffer,\r\n indexBuffer: this.indexBuffer\r\n });\r\n }\r\n }\r\n \r\n /**\r\n * 清除几何缓存\r\n */\r\n private _clearGeometryCache(): void {\r\n for (const cached of this._geometryCache.values()) {\r\n cached.vertexBuffer.destroy();\r\n cached.indexBuffer.destroy();\r\n }\r\n this._geometryCache.clear();\r\n this.vertexBuffer = null;\r\n this.indexBuffer = null;\r\n }\r\n \r\n /**\r\n * 更新翻转状态\r\n */\r\n setFlipped(newFlipped: Vec3): void {\r\n const newKey = `${newFlipped.x},${newFlipped.y},${newFlipped.z}`;\r\n if (this._currentFlipKey === newKey) return;\r\n \r\n this.flipped = newFlipped.clone();\r\n this._updateTriData();\r\n \r\n if (this.device) {\r\n this._currentFlipKey = newKey;\r\n \r\n // 检查缓存\r\n if (this._geometryCache.has(newKey)) {\r\n const cached = this._geometryCache.get(newKey)!;\r\n this.vertexBuffer = cached.vertexBuffer;\r\n this.indexBuffer = cached.indexBuffer;\r\n } else {\r\n // 创建新的几何体\r\n this.createGeometry(this.device);\r\n }\r\n }\r\n }\r\n \r\n /**\r\n * 销毁 GPU 资源\r\n */\r\n override destroy(): void {\r\n this._clearGeometryCache();\r\n super.destroy();\r\n }\r\n}\r\n","import { Vec3 } from \"../math/Vec3\";\r\nimport { Mat4 } from \"../math/Mat4\";\r\nimport { Quat } from \"../math/Quat\";\r\nimport { Shape, ShapeConfig, TriData } from \"./Shape\";\r\n\r\n/**\r\n * SphereShapeConfig - 球体形状配置\r\n */\r\nexport interface SphereShapeConfig extends ShapeConfig {\r\n radius?: number; // 球体半径\r\n}\r\n\r\n/**\r\n * SphereShape - 球体形状(用于统一缩放/中心选择)\r\n * 参考 PlayCanvas 引擎的 SphereShape 实现\r\n */\r\nexport class SphereShape extends Shape {\r\n private _radius: number = 0.1;\r\n \r\n constructor(config: SphereShapeConfig) {\r\n super(config);\r\n \r\n this._radius = config.radius ?? this._radius;\r\n \r\n this._updateTriData();\r\n }\r\n \r\n get radius(): number { return this._radius; }\r\n set radius(value: number) { this._radius = value; this._updateTriData(); }\r\n \r\n /**\r\n * 更新碰撞数据\r\n */\r\n private _updateTriData(): void {\r\n const sphereGeo = this.createSphereGeometry(8, 6);\r\n \r\n const scale = new Vec3(this._radius * 2, this._radius * 2, this._radius * 2);\r\n const transform = Mat4.compose(new Vec3(0, 0, 0), Quat.identity(), scale);\r\n \r\n this.triData = [{\r\n vertices: sphereGeo.vertices,\r\n indices: sphereGeo.indices,\r\n transform: transform,\r\n priority: 3 // 中心球优先级最高\r\n }];\r\n }\r\n \r\n /**\r\n * 创建单位球体几何体(半径0.5,中心在原点)\r\n */\r\n private createSphereGeometry(\r\n segments: number, \r\n rings: number\r\n ): { vertices: Float32Array; indices: Uint16Array } {\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n \r\n // 生成球体顶点\r\n for (let ring = 0; ring <= rings; ring++) {\r\n const phi = (ring / rings) * Math.PI;\r\n const sinPhi = Math.sin(phi);\r\n const cosPhi = Math.cos(phi);\r\n \r\n for (let seg = 0; seg <= segments; seg++) {\r\n const theta = (seg / segments) * Math.PI * 2;\r\n const sinTheta = Math.sin(theta);\r\n const cosTheta = Math.cos(theta);\r\n \r\n const x = 0.5 * sinPhi * cosTheta;\r\n const y = 0.5 * cosPhi;\r\n const z = 0.5 * sinPhi * sinTheta;\r\n \r\n vertices.push(x, y, z);\r\n }\r\n }\r\n \r\n // 生成球体索引\r\n for (let ring = 0; ring < rings; ring++) {\r\n for (let seg = 0; seg < segments; seg++) {\r\n const a = ring * (segments + 1) + seg;\r\n const b = a + segments + 1;\r\n const c = a + 1;\r\n const d = b + 1;\r\n \r\n indices.push(a, b, c);\r\n indices.push(b, d, c);\r\n }\r\n }\r\n \r\n return {\r\n vertices: new Float32Array(vertices),\r\n indices: new Uint16Array(indices)\r\n };\r\n }\r\n \r\n /**\r\n * 创建渲染用的 GPU 几何体\r\n */\r\n createGeometry(device: GPUDevice): void {\r\n const segments = 16;\r\n const rings = 12;\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n \r\n const color = this._defaultColor;\r\n \r\n // 生成球体顶点\r\n for (let ring = 0; ring <= rings; ring++) {\r\n const phi = (ring / rings) * Math.PI;\r\n const sinPhi = Math.sin(phi);\r\n const cosPhi = Math.cos(phi);\r\n \r\n for (let seg = 0; seg <= segments; seg++) {\r\n const theta = (seg / segments) * Math.PI * 2;\r\n const sinTheta = Math.sin(theta);\r\n const cosTheta = Math.cos(theta);\r\n \r\n const x = this._radius * sinPhi * cosTheta;\r\n const y = this._radius * cosPhi;\r\n const z = this._radius * sinPhi * sinTheta;\r\n \r\n vertices.push(x, y, z, color.x, color.y, color.z);\r\n }\r\n }\r\n \r\n // 生成球体索引\r\n for (let ring = 0; ring < rings; ring++) {\r\n for (let seg = 0; seg < segments; seg++) {\r\n const a = ring * (segments + 1) + seg;\r\n const b = a + segments + 1;\r\n const c = a + 1;\r\n const d = b + 1;\r\n \r\n indices.push(a, b, c);\r\n indices.push(b, d, c);\r\n }\r\n }\r\n \r\n this.createBuffers(device, new Float32Array(vertices), new Uint16Array(indices));\r\n }\r\n}\r\n","import { Vec3 } from \"../math/Vec3\";\r\nimport { Mat4 } from \"../math/Mat4\";\r\nimport { Quat } from \"../math/Quat\";\r\nimport { Shape, ShapeConfig } from \"./Shape\";\r\n\r\n/**\r\n * ArcShapeConfig - 圆弧形状配置\r\n */\r\nexport interface ArcShapeConfig extends ShapeConfig {\r\n tubeRadius?: number; // 管道半径(粗细)\r\n ringRadius?: number; // 圆环半径\r\n sectorAngle?: number; // 扇形角度(度)\r\n tolerance?: number; // 碰撞检测容差\r\n}\r\n\r\n/**\r\n * ArcDisplayMode - 圆弧显示模式\r\n */\r\nexport type ArcDisplayMode = 'sector' | 'ring' | 'none';\r\n\r\n/**\r\n * ArcShape - 圆弧形状(用于旋转 Gizmo)\r\n * 参考 PlayCanvas 引擎的 ArcShape 实现\r\n * \r\n * 圆环默认在 XZ 平面上(绕 Y 轴),通过 rotation 旋转到正确的轴\r\n */\r\nexport class ArcShape extends Shape {\r\n private _tubeRadius: number = 0.02;\r\n private _ringRadius: number = 0.5;\r\n private _sectorAngle: number = 180; // 默认半圆弧\r\n private _tolerance: number = 0.05;\r\n \r\n // 显示模式\r\n private _displayMode: ArcDisplayMode = 'sector';\r\n \r\n // 双缓冲:sector 和 ring 的几何数据\r\n private _sectorVertexBuffer: GPUBuffer | null = null;\r\n private _sectorIndexBuffer: GPUBuffer | null = null;\r\n private _sectorIndexCount: number = 0;\r\n private _ringVertexBuffer: GPUBuffer | null = null;\r\n private _ringIndexBuffer: GPUBuffer | null = null;\r\n private _ringIndexCount: number = 0;\r\n \r\n // 动态旋转角度(用于面向相机)\r\n private _dynamicRotation: Vec3 = new Vec3(0, 0, 0);\r\n \r\n constructor(config: ArcShapeConfig) {\r\n super(config);\r\n \r\n this._tubeRadius = config.tubeRadius ?? this._tubeRadius;\r\n this._ringRadius = config.ringRadius ?? this._ringRadius;\r\n this._sectorAngle = config.sectorAngle ?? this._sectorAngle;\r\n this._tolerance = config.tolerance ?? this._tolerance;\r\n \r\n this._updateTriData();\r\n }\r\n \r\n get tubeRadius(): number { return this._tubeRadius; }\r\n set tubeRadius(value: number) { this._tubeRadius = value; this._updateTriData(); }\r\n \r\n get ringRadius(): number { return this._ringRadius; }\r\n set ringRadius(value: number) { this._ringRadius = value; this._updateTriData(); }\r\n \r\n get sectorAngle(): number { return this._sectorAngle; }\r\n set sectorAngle(value: number) { this._sectorAngle = value; this._updateTriData(); }\r\n \r\n get tolerance(): number { return this._tolerance; }\r\n set tolerance(value: number) { this._tolerance = value; this._updateTriData(); }\r\n \r\n get displayMode(): ArcDisplayMode { return this._displayMode; }\r\n \r\n /**\r\n * 设置动态旋转(用于面向相机)\r\n */\r\n setDynamicRotation(rotation: Vec3): void {\r\n this._dynamicRotation = rotation.clone();\r\n }\r\n \r\n /**\r\n * 获取局部变换矩阵(包含动态旋转)\r\n */\r\n override getLocalTransform(): Mat4 {\r\n // 基础旋转\r\n const baseRotX = this._rotation.x * Math.PI / 180;\r\n const baseRotY = this._rotation.y * Math.PI / 180;\r\n const baseRotZ = this._rotation.z * Math.PI / 180;\r\n const baseQuat = Quat.fromEuler(baseRotX, baseRotY, baseRotZ);\r\n \r\n // 动态旋转\r\n const dynRotX = this._dynamicRotation.x * Math.PI / 180;\r\n const dynRotY = this._dynamicRotation.y * Math.PI / 180;\r\n const dynRotZ = this._dynamicRotation.z * Math.PI / 180;\r\n const dynQuat = Quat.fromEuler(dynRotX, dynRotY, dynRotZ);\r\n \r\n // 组合旋转:先应用基础旋转,再应用动态旋转\r\n const finalQuat = baseQuat.multiply(dynQuat);\r\n \r\n return Mat4.compose(this._position, finalQuat, this._scale);\r\n }\r\n \r\n /**\r\n * 更新碰撞数据\r\n */\r\n private _updateTriData(): void {\r\n // 根据显示模式创建碰撞几何体\r\n const angle = this._displayMode === 'ring' ? 360 : this._sectorAngle;\r\n const torusGeo = this.createTorusGeometry(20, 8, this._tubeRadius + this._tolerance, angle);\r\n \r\n const transform = Mat4.identity();\r\n \r\n this.triData = [{\r\n vertices: torusGeo.vertices,\r\n indices: torusGeo.indices,\r\n transform: transform,\r\n priority: 0\r\n }];\r\n }\r\n \r\n /**\r\n * 切换显示模式\r\n */\r\n show(mode: ArcDisplayMode): void {\r\n if (this._displayMode === mode) return;\r\n \r\n this._displayMode = mode;\r\n this._visible = mode !== 'none';\r\n \r\n // 更新碰撞数据\r\n this._updateTriData();\r\n }\r\n \r\n /**\r\n * 创建圆环几何体\r\n */\r\n private createTorusGeometry(\r\n segments: number,\r\n tubeSegments: number,\r\n tubeRadius?: number,\r\n sectorAngle?: number\r\n ): { vertices: Float32Array; indices: Uint16Array } {\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n \r\n const tube = tubeRadius ?? this._tubeRadius;\r\n const ring = this._ringRadius;\r\n const angle = sectorAngle ?? this._sectorAngle;\r\n const sectorRad = (angle * Math.PI) / 180;\r\n \r\n for (let i = 0; i <= segments; i++) {\r\n const u = (i / segments) * sectorRad;\r\n const cosU = Math.cos(u);\r\n const sinU = Math.sin(u);\r\n \r\n for (let j = 0; j <= tubeSegments; j++) {\r\n const v = (j / tubeSegments) * Math.PI * 2;\r\n const cosV = Math.cos(v);\r\n const sinV = Math.sin(v);\r\n \r\n const x = (ring + tube * cosV) * cosU;\r\n const y = tube * sinV;\r\n const z = (ring + tube * cosV) * sinU;\r\n \r\n vertices.push(x, y, z);\r\n }\r\n }\r\n \r\n for (let i = 0; i < segments; i++) {\r\n for (let j = 0; j < tubeSegments; j++) {\r\n const a = i * (tubeSegments + 1) + j;\r\n const b = a + tubeSegments + 1;\r\n const c = a + 1;\r\n const d = b + 1;\r\n \r\n indices.push(a, b, c);\r\n indices.push(b, d, c);\r\n }\r\n }\r\n \r\n return {\r\n vertices: new Float32Array(vertices),\r\n indices: new Uint16Array(indices)\r\n };\r\n }\r\n \r\n /**\r\n * 创建渲染用的 GPU 几何体(同时创建 sector 和 ring 两种)\r\n */\r\n createGeometry(device: GPUDevice): void {\r\n this.device = device;\r\n \r\n // 创建 sector 几何体\r\n const sectorData = this._createTorusMeshData(this._sectorAngle);\r\n this._sectorVertexBuffer = device.createBuffer({\r\n size: sectorData.vertices.byteLength,\r\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\r\n mappedAtCreation: true,\r\n });\r\n new Float32Array(this._sectorVertexBuffer.getMappedRange()).set(sectorData.vertices);\r\n this._sectorVertexBuffer.unmap();\r\n \r\n this._sectorIndexBuffer = device.createBuffer({\r\n size: sectorData.indices.byteLength,\r\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\r\n mappedAtCreation: true,\r\n });\r\n new Uint16Array(this._sectorIndexBuffer.getMappedRange()).set(sectorData.indices);\r\n this._sectorIndexBuffer.unmap();\r\n this._sectorIndexCount = sectorData.indices.length;\r\n \r\n // 创建 ring 几何体(完整圆环)\r\n const ringData = this._createTorusMeshData(360);\r\n this._ringVertexBuffer = device.createBuffer({\r\n size: ringData.vertices.byteLength,\r\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\r\n mappedAtCreation: true,\r\n });\r\n new Float32Array(this._ringVertexBuffer.getMappedRange()).set(ringData.vertices);\r\n this._ringVertexBuffer.unmap();\r\n \r\n this._ringIndexBuffer = device.createBuffer({\r\n size: ringData.indices.byteLength,\r\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\r\n mappedAtCreation: true,\r\n });\r\n new Uint16Array(this._ringIndexBuffer.getMappedRange()).set(ringData.indices);\r\n this._ringIndexBuffer.unmap();\r\n this._ringIndexCount = ringData.indices.length;\r\n \r\n // 默认使用 sector\r\n this.vertexBuffer = this._sectorVertexBuffer;\r\n this.indexBuffer = this._sectorIndexBuffer;\r\n this.indexCount = this._sectorIndexCount;\r\n }\r\n \r\n /**\r\n * 创建圆环网格数据\r\n */\r\n private _createTorusMeshData(sectorAngle: number): { vertices: Float32Array; indices: Uint16Array } {\r\n const segments = 64;\r\n const tubeSegments = 12;\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n \r\n const color = this._defaultColor;\r\n const tube = this._tubeRadius;\r\n const ring = this._ringRadius;\r\n const sectorRad = (sectorAngle * Math.PI) / 180;\r\n \r\n for (let i = 0; i <= segments; i++) {\r\n const u = (i / segments) * sectorRad;\r\n const cosU = Math.cos(u);\r\n const sinU = Math.sin(u);\r\n \r\n for (let j = 0; j <= tubeSegments; j++) {\r\n const v = (j / tubeSegments) * Math.PI * 2;\r\n const cosV = Math.cos(v);\r\n const sinV = Math.sin(v);\r\n \r\n const x = (ring + tube * cosV) * cosU;\r\n const y = tube * sinV;\r\n const z = (ring + tube * cosV) * sinU;\r\n \r\n vertices.push(x, y, z, color.x, color.y, color.z);\r\n }\r\n }\r\n \r\n for (let i = 0; i < segments; i++) {\r\n for (let j = 0; j < tubeSegments; j++) {\r\n const a = i * (tubeSegments + 1) + j;\r\n const b = a + tubeSegments + 1;\r\n const c = a + 1;\r\n const d = b + 1;\r\n \r\n indices.push(a, b, c);\r\n indices.push(b, d, c);\r\n }\r\n }\r\n \r\n return {\r\n vertices: new Float32Array(vertices),\r\n indices: new Uint16Array(indices)\r\n };\r\n }\r\n \r\n /**\r\n * 获取顶点缓冲区(根据显示模式)\r\n */\r\n override getVertexBuffer(): GPUBuffer | null {\r\n if (this._displayMode === 'ring') {\r\n return this._ringVertexBuffer;\r\n }\r\n return this._sectorVertexBuffer;\r\n }\r\n \r\n /**\r\n * 获取索引缓冲区(根据显示模式)\r\n */\r\n override getIndexBuffer(): GPUBuffer | null {\r\n if (this._displayMode === 'ring') {\r\n return this._ringIndexBuffer;\r\n }\r\n return this._sectorIndexBuffer;\r\n }\r\n \r\n /**\r\n * 获取索引数量(根据显示模式)\r\n */\r\n override getIndexCount(): number {\r\n if (this._displayMode === 'ring') {\r\n return this._ringIndexCount;\r\n }\r\n return this._sectorIndexCount;\r\n }\r\n \r\n /**\r\n * 销毁 GPU 资源\r\n */\r\n override destroy(): void {\r\n if (this._sectorVertexBuffer) {\r\n this._sectorVertexBuffer.destroy();\r\n this._sectorVertexBuffer = null;\r\n }\r\n if (this._sectorIndexBuffer) {\r\n this._sectorIndexBuffer.destroy();\r\n this._sectorIndexBuffer = null;\r\n }\r\n if (this._ringVertexBuffer) {\r\n this._ringVertexBuffer.destroy();\r\n this._ringVertexBuffer = null;\r\n }\r\n if (this._ringIndexBuffer) {\r\n this._ringIndexBuffer.destroy();\r\n this._ringIndexBuffer = null;\r\n }\r\n super.destroy();\r\n }\r\n}\r\n","import { Vec3 } from \"../math/Vec3\";\r\nimport { Mat4 } from \"../math/Mat4\";\r\nimport { Quat } from \"../math/Quat\";\r\nimport { Shape, ShapeConfig, TriData } from \"./Shape\";\r\n\r\n/**\r\n * BoxLineShapeConfig - 方块线形状配置(用于缩放 Gizmo)\r\n */\r\nexport interface BoxLineShapeConfig extends ShapeConfig {\r\n gap?: number; // 起点与中心的间距\r\n lineThickness?: number; // 线条粗细\r\n lineLength?: number; // 线条长度\r\n boxSize?: number; // 末端方块大小\r\n tolerance?: number; // 碰撞检测容差\r\n}\r\n\r\n/**\r\n * BoxLineShape - 方块线形状(用于缩放 Gizmo)\r\n * 参考 PlayCanvas 引擎的 BoxLineShape 实现\r\n */\r\nexport class BoxLineShape extends Shape {\r\n private _gap: number = 0;\r\n private _lineThickness: number = 0.02;\r\n private _lineLength: number = 0.5;\r\n private _boxSize: number = 0.1;\r\n private _tolerance: number = 0.1;\r\n \r\n constructor(config: BoxLineShapeConfig) {\r\n super(config);\r\n \r\n this._gap = config.gap ?? this._gap;\r\n this._lineThickness = config.lineThickness ?? this._lineThickness;\r\n this._lineLength = config.lineLength ?? this._lineLength;\r\n this._boxSize = config.boxSize ?? this._boxSize;\r\n this._tolerance = config.tolerance ?? this._tolerance;\r\n \r\n this._updateTriData();\r\n }\r\n \r\n get gap(): number { return this._gap; }\r\n set gap(value: number) { this._gap = value; this._updateTriData(); }\r\n \r\n get lineThickness(): number { return this._lineThickness; }\r\n set lineThickness(value: number) { this._lineThickness = value; this._updateTriData(); }\r\n \r\n get lineLength(): number { return this._lineLength; }\r\n set lineLength(value: number) { this._lineLength = value; this._updateTriData(); }\r\n \r\n get boxSize(): number { return this._boxSize; }\r\n set boxSize(value: number) { this._boxSize = value; this._updateTriData(); }\r\n \r\n /**\r\n * 更新碰撞数据\r\n */\r\n private _updateTriData(): void {\r\n // 方块碰撞数据\r\n const boxPos = new Vec3(0, this._gap + this._lineLength + this._boxSize * 0.5, 0);\r\n const boxScale = new Vec3(this._boxSize, this._boxSize, this._boxSize);\r\n const boxTransform = Mat4.compose(boxPos, Quat.identity(), boxScale);\r\n \r\n // 线条圆柱碰撞数据(加上容差)\r\n const linePos = new Vec3(0, this._gap + this._lineLength * 0.5, 0);\r\n const lineScale = new Vec3(\r\n this._lineThickness + this._tolerance,\r\n this._lineLength,\r\n this._lineThickness + this._tolerance\r\n );\r\n const lineTransform = Mat4.compose(linePos, Quat.identity(), lineScale);\r\n \r\n // 生成单位方块和圆柱的三角形数据\r\n const boxGeo = this.createBoxGeometry();\r\n const cylinderGeo = this.createCylinderGeometry();\r\n \r\n this.triData = [\r\n {\r\n vertices: boxGeo.vertices,\r\n indices: boxGeo.indices,\r\n transform: boxTransform,\r\n priority: 0\r\n },\r\n {\r\n vertices: cylinderGeo.vertices,\r\n indices: cylinderGeo.indices,\r\n transform: lineTransform,\r\n priority: 1\r\n }\r\n ];\r\n }\r\n \r\n /**\r\n * 创建单位方块几何体(边长1,中心在原点)\r\n */\r\n private createBoxGeometry(): { vertices: Float32Array; indices: Uint16Array } {\r\n const h = 0.5;\r\n const vertices = new Float32Array([\r\n // 前面\r\n -h, -h, h,\r\n h, -h, h,\r\n h, h, h,\r\n -h, h, h,\r\n // 后面\r\n -h, -h, -h,\r\n -h, h, -h,\r\n h, h, -h,\r\n h, -h, -h,\r\n ]);\r\n \r\n const indices = new Uint16Array([\r\n // 前\r\n 0, 1, 2, 0, 2, 3,\r\n // 后\r\n 4, 5, 6, 4, 6, 7,\r\n // 上\r\n 3, 2, 6, 3, 6, 5,\r\n // 下\r\n 4, 7, 1, 4, 1, 0,\r\n // 右\r\n 1, 7, 6, 1, 6, 2,\r\n // 左\r\n 4, 0, 3, 4, 3, 5\r\n ]);\r\n \r\n return { vertices, indices };\r\n }\r\n \r\n /**\r\n * 创建单位圆柱几何体\r\n */\r\n private createCylinderGeometry(): { vertices: Float32Array; indices: Uint16Array } {\r\n const segments = 12;\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n \r\n for (let i = 0; i <= segments; i++) {\r\n const angle = (i / segments) * Math.PI * 2;\r\n const x = Math.cos(angle) * 0.5;\r\n const z = Math.sin(angle) * 0.5;\r\n \r\n vertices.push(x, -0.5, z);\r\n vertices.push(x, 0.5, z);\r\n }\r\n \r\n for (let i = 0; i < segments; i++) {\r\n const base = i * 2;\r\n indices.push(base, base + 1, base + 2);\r\n indices.push(base + 1, base + 3, base + 2);\r\n }\r\n \r\n return {\r\n vertices: new Float32Array(vertices),\r\n indices: new Uint16Array(indices)\r\n };\r\n }\r\n \r\n /**\r\n * 创建渲染用的 GPU 几何体\r\n */\r\n createGeometry(device: GPUDevice): void {\r\n const segments = 12;\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n \r\n const color = this._defaultColor;\r\n \r\n // 辅助函数:添加顶点\r\n const addVertex = (x: number, y: number, z: number) => {\r\n vertices.push(x, y, z, color.x, color.y, color.z);\r\n };\r\n \r\n // 生成圆柱(线条部分)\r\n const cylinderStart = this._gap;\r\n const cylinderEnd = this._gap + this._lineLength;\r\n \r\n for (let i = 0; i <= segments; i++) {\r\n const angle = (i / segments) * Math.PI * 2;\r\n const cos = Math.cos(angle);\r\n const sin = Math.sin(angle);\r\n \r\n const offsetX = cos * this._lineThickness;\r\n const offsetZ = sin * this._lineThickness;\r\n \r\n addVertex(offsetX, cylinderStart, offsetZ);\r\n addVertex(offsetX, cylinderEnd, offsetZ);\r\n }\r\n \r\n // 圆柱索引\r\n for (let i = 0; i < segments; i++) {\r\n const base = i * 2;\r\n indices.push(base, base + 1, base + 2);\r\n indices.push(base + 1, base + 3, base + 2);\r\n }\r\n \r\n // 生成方块\r\n const boxCenter = this._gap + this._lineLength + this._boxSize * 0.5;\r\n const h = this._boxSize * 0.5;\r\n \r\n const boxBaseIndex = vertices.length / 6;\r\n \r\n // 方块8个顶点\r\n addVertex(-h, boxCenter - h, h);\r\n addVertex( h, boxCenter - h, h);\r\n addVertex( h, boxCenter + h, h);\r\n addVertex(-h, boxCenter + h, h);\r\n addVertex(-h, boxCenter - h, -h);\r\n addVertex(-h, boxCenter + h, -h);\r\n addVertex( h, boxCenter + h, -h);\r\n addVertex( h, boxCenter - h, -h);\r\n \r\n // 方块索引\r\n const boxIndices = [\r\n 0, 1, 2, 0, 2, 3, // 前\r\n 4, 5, 6, 4, 6, 7, // 后\r\n 3, 2, 6, 3, 6, 5, // 上\r\n 4, 7, 1, 4, 1, 0, // 下\r\n 1, 7, 6, 1, 6, 2, // 右\r\n 4, 0, 3, 4, 3, 5 // 左\r\n ];\r\n \r\n for (const idx of boxIndices) {\r\n indices.push(boxBaseIndex + idx);\r\n }\r\n \r\n this.createBuffers(device, new Float32Array(vertices), new Uint16Array(indices));\r\n }\r\n}\r\n","import { Renderer } from \"../Renderer\";\r\nimport { Camera } from \"../Camera\";\r\nimport { Vec3 } from \"../math/Vec3\";\r\nimport { Ray } from \"../math/Ray\";\r\nimport { Mat4 } from \"../math/Mat4\";\r\nimport { Quat } from \"../math/Quat\";\r\nimport { Shape, GizmoAxisType } from \"./Shape\";\r\nimport { ArrowShape } from \"./ArrowShape\";\r\nimport { PlaneShape } from \"./PlaneShape\";\r\nimport { SphereShape } from \"./SphereShape\";\r\nimport { ArcShape, ArcDisplayMode } from \"./ArcShape\";\r\nimport { BoxLineShape } from \"./BoxLineShape\";\r\n\r\n/**\r\n * GizmoMode - Gizmo 操作模式\r\n */\r\nexport enum GizmoMode {\r\n Translate = 'translate',\r\n Rotate = 'rotate',\r\n Scale = 'scale',\r\n}\r\n\r\n/**\r\n * GizmoSpace - 坐标空间\r\n */\r\nexport type GizmoSpace = 'world' | 'local';\r\n\r\n/**\r\n * GizmoDragMode - 拖拽时的显示模式\r\n */\r\nexport type GizmoDragMode = 'show' | 'hide' | 'selected';\r\n\r\n/**\r\n * TransformableObject - 可变换对象接口\r\n */\r\nexport interface TransformableObject {\r\n position: [number, number, number] | Float32Array;\r\n rotation: [number, number, number] | Float32Array;\r\n scale: [number, number, number] | Float32Array;\r\n setPosition(x: number, y: number, z: number): void;\r\n setRotation(x: number, y: number, z: number): void;\r\n setScale(x: number, y: number, z: number): void;\r\n}\r\n\r\n/**\r\n * GizmoTheme - Gizmo 主题颜色\r\n */\r\nexport interface GizmoTheme {\r\n shapeBase: {\r\n x: Vec3;\r\n y: Vec3;\r\n z: Vec3;\r\n xyz: Vec3;\r\n f: Vec3; // 面向相机的轴\r\n };\r\n shapeHover: {\r\n x: Vec3;\r\n y: Vec3;\r\n z: Vec3;\r\n xyz: Vec3;\r\n f: Vec3;\r\n };\r\n guideBase: {\r\n x: Vec3;\r\n y: Vec3;\r\n z: Vec3;\r\n };\r\n disabled: Vec3;\r\n}\r\n\r\n// 默认主题\r\nconst DEFAULT_THEME: GizmoTheme = {\r\n shapeBase: {\r\n x: new Vec3(0.9, 0.2, 0.2),\r\n y: new Vec3(0.2, 0.9, 0.2),\r\n z: new Vec3(0.2, 0.4, 0.9),\r\n xyz: new Vec3(0.8, 0.8, 0.8),\r\n f: new Vec3(0.8, 0.8, 0.8),\r\n },\r\n shapeHover: {\r\n x: new Vec3(1.0, 0.6, 0.6),\r\n y: new Vec3(0.6, 1.0, 0.6),\r\n z: new Vec3(0.6, 0.6, 1.0),\r\n xyz: new Vec3(1.0, 1.0, 1.0),\r\n f: new Vec3(1.0, 1.0, 1.0),\r\n },\r\n guideBase: {\r\n x: new Vec3(0.9, 0.2, 0.2),\r\n y: new Vec3(0.2, 0.9, 0.2),\r\n z: new Vec3(0.2, 0.4, 0.9),\r\n },\r\n disabled: new Vec3(0.5, 0.5, 0.5),\r\n};\r\n\r\n// 常量\r\nconst GLANCE_EPSILON = 0.01;\r\nconst RING_FACING_EPSILON = 1e-4;\r\nconst PERS_SCALE_RATIO = 0.3;\r\nconst MIN_SCALE = 1e-4;\r\nconst RAD_TO_DEG = 180 / Math.PI;\r\n\r\n/**\r\n * TransformGizmoConfig - Gizmo 配置\r\n */\r\nexport interface TransformGizmoConfig {\r\n renderer: Renderer;\r\n camera: Camera;\r\n canvas: HTMLCanvasElement;\r\n size?: number;\r\n snap?: boolean;\r\n snapIncrement?: number;\r\n}\r\n\r\n/**\r\n * TransformGizmoV2 - 重构后的变换 Gizmo\r\n * 参考 PlayCanvas 引擎的 TransformGizmo 实现\r\n */\r\nexport class TransformGizmoV2 {\r\n private renderer: Renderer;\r\n private camera: Camera;\r\n private canvas: HTMLCanvasElement;\r\n \r\n // 配置\r\n private _size: number = 1.0;\r\n private _scale: number = 1.0;\r\n private _mode: GizmoMode = GizmoMode.Translate;\r\n private _coordSpace: GizmoSpace = 'world';\r\n private _theme: GizmoTheme = DEFAULT_THEME;\r\n \r\n // Snap 功能\r\n snap: boolean = false;\r\n snapIncrement: number = 1;\r\n \r\n // 拖拽模式\r\n dragMode: GizmoDragMode = 'selected';\r\n \r\n // 平面翻转\r\n flipPlanes: boolean = true;\r\n \r\n // 目标对象\r\n private _target: TransformableObject | null = null;\r\n \r\n // 形状\r\n private _shapes: Map<GizmoAxisType | 'f', Shape> = new Map();\r\n \r\n // 交互状态\r\n private _hoverAxis: GizmoAxisType | 'f' | '' = '';\r\n private _selectedAxis: GizmoAxisType | 'f' | '' = '';\r\n private _hoverIsPlane: boolean = false;\r\n private _selectedIsPlane: boolean = false;\r\n private _dragging: boolean = false;\r\n\r\n // 拖拽起始状态\r\n private _rootStartPos: Vec3 = new Vec3();\r\n private _rootStartRot: Quat = Quat.identity();\r\n private _selectionStartPoint: Vec3 = new Vec3();\r\n private _dragStartTransform: {\r\n position: Vec3;\r\n rotation: Vec3;\r\n scale: Vec3;\r\n } | null = null;\r\n \r\n // 面向相机的方向缓存\r\n private _facingDir: Vec3 = new Vec3();\r\n \r\n // 回调\r\n private _onDragStateChange: ((isDragging: boolean) => void) | null = null;\r\n \r\n // GPU 资源\r\n private pipeline: GPURenderPipeline | null = null;\r\n private linePipeline: GPURenderPipeline | null = null;\r\n private uniformBuffer: GPUBuffer | null = null;\r\n private bindGroup: GPUBindGroup | null = null;\r\n private bindGroupLayout: GPUBindGroupLayout | null = null;\r\n \r\n // 每个 Shape 的 uniform buffer 和 bind group\r\n private shapeUniformBuffers: Map<GizmoAxisType | 'f', GPUBuffer> = new Map();\r\n private shapeBindGroups: Map<GizmoAxisType | 'f', GPUBindGroup> = new Map();\r\n \r\n // 辅助线资源\r\n private guideLineBuffer: GPUBuffer | null = null;\r\n private guideLineBindGroup: GPUBindGroup | null = null;\r\n \r\n constructor(config: TransformGizmoConfig) {\r\n this.renderer = config.renderer;\r\n this.camera = config.camera;\r\n this.canvas = config.canvas;\r\n \r\n if (config.size !== undefined) this._size = config.size;\r\n if (config.snap !== undefined) this.snap = config.snap;\r\n if (config.snapIncrement !== undefined) this.snapIncrement = config.snapIncrement;\r\n }\r\n\r\n /**\r\n * 初始化 Gizmo\r\n */\r\n init(): void {\r\n this.createPipeline();\r\n this.createLinePipeline();\r\n this.createShapes();\r\n }\r\n\r\n /**\r\n * 创建 WebGPU 渲染管线\r\n */\r\n private createPipeline(): void {\r\n const device = this.renderer.device;\r\n \r\n // Shader 支持从 uniform 读取颜色(包含透明度)\r\n const shaderCode = `\r\n struct Uniforms {\r\n viewProjection: mat4x4<f32>,\r\n model: mat4x4<f32>,\r\n color: vec4<f32>,\r\n }\r\n\r\n @group(0) @binding(0) var<uniform> uniforms: Uniforms;\r\n\r\n struct VertexInput {\r\n @location(0) position: vec3<f32>,\r\n @location(1) vertexColor: vec3<f32>,\r\n }\r\n\r\n struct VertexOutput {\r\n @builtin(position) position: vec4<f32>,\r\n @location(0) color: vec4<f32>,\r\n }\r\n\r\n @vertex\r\n fn vertexMain(input: VertexInput) -> VertexOutput {\r\n var output: VertexOutput;\r\n let worldPos = uniforms.model * vec4<f32>(input.position, 1.0);\r\n output.position = uniforms.viewProjection * worldPos;\r\n // 使用 uniform 中的颜色,忽略顶点颜色\r\n output.color = uniforms.color;\r\n return output;\r\n }\r\n\r\n @fragment\r\n fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {\r\n // 如果透明度为 0,丢弃片元\r\n if (input.color.a < 0.01) {\r\n discard;\r\n }\r\n return input.color;\r\n }\r\n `;\r\n \r\n const shaderModule = device.createShaderModule({ code: shaderCode });\r\n \r\n this.uniformBuffer = device.createBuffer({\r\n size: 144, // 64 + 64 + 16 = 144 bytes (viewProj + model + color)\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n \r\n this.bindGroupLayout = device.createBindGroupLayout({\r\n entries: [{\r\n binding: 0,\r\n visibility: GPUShaderStage.VERTEX,\r\n buffer: { type: \"uniform\" },\r\n }],\r\n });\r\n\r\n this.bindGroup = device.createBindGroup({\r\n layout: this.bindGroupLayout,\r\n entries: [{ binding: 0, resource: { buffer: this.uniformBuffer } }],\r\n });\r\n \r\n const pipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [this.bindGroupLayout],\r\n });\r\n\r\n this.pipeline = device.createRenderPipeline({\r\n layout: pipelineLayout,\r\n vertex: {\r\n module: shaderModule,\r\n entryPoint: \"vertexMain\",\r\n buffers: [{\r\n arrayStride: 24,\r\n attributes: [\r\n { shaderLocation: 0, offset: 0, format: \"float32x3\" },\r\n { shaderLocation: 1, offset: 12, format: \"float32x3\" },\r\n ],\r\n }],\r\n },\r\n fragment: {\r\n module: shaderModule,\r\n entryPoint: \"fragmentMain\",\r\n targets: [{\r\n format: this.renderer.format,\r\n blend: {\r\n color: { srcFactor: \"src-alpha\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\r\n alpha: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\r\n },\r\n }],\r\n },\r\n primitive: { topology: \"triangle-list\", cullMode: \"none\" },\r\n depthStencil: {\r\n format: this.renderer.depthFormat,\r\n depthWriteEnabled: false,\r\n depthCompare: \"always\",\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * 创建辅助线渲染管线\r\n */\r\n private createLinePipeline(): void {\r\n const device = this.renderer.device;\r\n \r\n const shaderCode = `\r\n struct Uniforms {\r\n viewProjection: mat4x4<f32>,\r\n model: mat4x4<f32>,\r\n }\r\n\r\n @group(0) @binding(0) var<uniform> uniforms: Uniforms;\r\n\r\n struct VertexInput {\r\n @location(0) position: vec3<f32>,\r\n @location(1) color: vec3<f32>,\r\n }\r\n\r\n struct VertexOutput {\r\n @builtin(position) position: vec4<f32>,\r\n @location(0) color: vec3<f32>,\r\n }\r\n\r\n @vertex\r\n fn vertexMain(input: VertexInput) -> VertexOutput {\r\n var output: VertexOutput;\r\n let worldPos = uniforms.model * vec4<f32>(input.position, 1.0);\r\n output.position = uniforms.viewProjection * worldPos;\r\n output.color = input.color;\r\n return output;\r\n }\r\n\r\n @fragment\r\n fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {\r\n return vec4<f32>(input.color, 0.6);\r\n }\r\n `;\r\n \r\n const shaderModule = device.createShaderModule({ code: shaderCode });\r\n \r\n if (!this.bindGroupLayout) return;\r\n \r\n const pipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [this.bindGroupLayout],\r\n });\r\n\r\n this.linePipeline = device.createRenderPipeline({\r\n layout: pipelineLayout,\r\n vertex: {\r\n module: shaderModule,\r\n entryPoint: \"vertexMain\",\r\n buffers: [{\r\n arrayStride: 24,\r\n attributes: [\r\n { shaderLocation: 0, offset: 0, format: \"float32x3\" },\r\n { shaderLocation: 1, offset: 12, format: \"float32x3\" },\r\n ],\r\n }],\r\n },\r\n fragment: {\r\n module: shaderModule,\r\n entryPoint: \"fragmentMain\",\r\n targets: [{\r\n format: this.renderer.format,\r\n blend: {\r\n color: { srcFactor: \"src-alpha\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\r\n alpha: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\r\n },\r\n }],\r\n },\r\n primitive: { topology: \"line-list\", cullMode: \"none\" },\r\n depthStencil: {\r\n format: this.renderer.depthFormat,\r\n depthWriteEnabled: false,\r\n depthCompare: \"always\",\r\n },\r\n });\r\n \r\n // 创建辅助线缓冲区\r\n this.guideLineBuffer = device.createBuffer({\r\n size: 128,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n \r\n this.guideLineBindGroup = device.createBindGroup({\r\n layout: this.bindGroupLayout,\r\n entries: [{ binding: 0, resource: { buffer: this.guideLineBuffer } }],\r\n });\r\n }\r\n\r\n /**\r\n * 创建形状\r\n */\r\n private createShapes(): void {\r\n const device = this.renderer.device;\r\n \r\n // 清除现有形状和资源\r\n for (const shape of this._shapes.values()) {\r\n shape.destroy();\r\n }\r\n this._shapes.clear();\r\n \r\n for (const buffer of this.shapeUniformBuffers.values()) {\r\n buffer.destroy();\r\n }\r\n this.shapeUniformBuffers.clear();\r\n this.shapeBindGroups.clear();\r\n \r\n if (this._mode === GizmoMode.Translate) {\r\n this.createTranslateShapes(device);\r\n } else if (this._mode === GizmoMode.Rotate) {\r\n this.createRotateShapes(device);\r\n } else if (this._mode === GizmoMode.Scale) {\r\n this.createScaleShapes(device);\r\n }\r\n \r\n this.createShapeUniformBuffers(device);\r\n }\r\n \r\n /**\r\n * 为每个 Shape 创建独立的 uniform buffer 和 bind group\r\n */\r\n private createShapeUniformBuffers(device: GPUDevice): void {\r\n if (!this.bindGroupLayout) return;\r\n \r\n for (const [axis] of this._shapes) {\r\n const uniformBuffer = device.createBuffer({\r\n size: 144, // 64 + 64 + 16 = 144 bytes (viewProj + model + color)\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n \r\n const bindGroup = device.createBindGroup({\r\n layout: this.bindGroupLayout,\r\n entries: [{ binding: 0, resource: { buffer: uniformBuffer } }],\r\n });\r\n \r\n this.shapeUniformBuffers.set(axis, uniformBuffer);\r\n this.shapeBindGroups.set(axis, bindGroup);\r\n }\r\n }\r\n\r\n /**\r\n * 创建平移模式的形状\r\n */\r\n private createTranslateShapes(device: GPUDevice): void {\r\n const theme = this._theme;\r\n \r\n // 中心球\r\n const center = new SphereShape({\r\n axis: 'xyz',\r\n defaultColor: theme.shapeBase.xyz,\r\n hoverColor: theme.shapeHover.xyz,\r\n disabledColor: theme.disabled,\r\n radius: 0.1,\r\n });\r\n center.createGeometry(device);\r\n this._shapes.set('xyz', center);\r\n \r\n // X 轴箭头\r\n const xArrow = new ArrowShape({\r\n axis: 'x',\r\n defaultColor: theme.shapeBase.x,\r\n hoverColor: theme.shapeHover.x,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(0, 0, -90),\r\n });\r\n xArrow.createGeometry(device);\r\n this._shapes.set('x', xArrow);\r\n \r\n // Y 轴箭头\r\n const yArrow = new ArrowShape({\r\n axis: 'y',\r\n defaultColor: theme.shapeBase.y,\r\n hoverColor: theme.shapeHover.y,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(0, 0, 0),\r\n });\r\n yArrow.createGeometry(device);\r\n this._shapes.set('y', yArrow);\r\n \r\n // Z 轴箭头\r\n const zArrow = new ArrowShape({\r\n axis: 'z',\r\n defaultColor: theme.shapeBase.z,\r\n hoverColor: theme.shapeHover.z,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(90, 0, 0),\r\n });\r\n zArrow.createGeometry(device);\r\n this._shapes.set('z', zArrow);\r\n \r\n // YZ 平面 (X 轴方向)\r\n const yzPlane = new PlaneShape({\r\n axis: 'yz',\r\n defaultColor: theme.shapeBase.x,\r\n hoverColor: theme.shapeHover.x,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(0, 0, -90),\r\n });\r\n yzPlane.createGeometry(device);\r\n this._shapes.set('yz', yzPlane);\r\n \r\n // XZ 平面 (Y 轴方向)\r\n const xzPlane = new PlaneShape({\r\n axis: 'xz',\r\n defaultColor: theme.shapeBase.y,\r\n hoverColor: theme.shapeHover.y,\r\n disabledColor: theme.disabled,\r\n });\r\n xzPlane.createGeometry(device);\r\n this._shapes.set('xz', xzPlane);\r\n \r\n // XY 平面 (Z 轴方向)\r\n const xyPlane = new PlaneShape({\r\n axis: 'xy',\r\n defaultColor: theme.shapeBase.z,\r\n hoverColor: theme.shapeHover.z,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(90, 0, 0),\r\n });\r\n xyPlane.createGeometry(device);\r\n this._shapes.set('xy', xyPlane);\r\n }\r\n\r\n /**\r\n * 创建旋转模式的形状\r\n */\r\n private createRotateShapes(device: GPUDevice): void {\r\n const theme = this._theme;\r\n \r\n // X 轴旋转环\r\n const xArc = new ArcShape({\r\n axis: 'x',\r\n defaultColor: theme.shapeBase.x,\r\n hoverColor: theme.shapeHover.x,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(0, 0, -90),\r\n ringRadius: 0.5,\r\n tubeRadius: 0.015,\r\n sectorAngle: 180,\r\n tolerance: 0.05,\r\n });\r\n xArc.createGeometry(device);\r\n this._shapes.set('x', xArc);\r\n \r\n // Y 轴旋转环\r\n const yArc = new ArcShape({\r\n axis: 'y',\r\n defaultColor: theme.shapeBase.y,\r\n hoverColor: theme.shapeHover.y,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(0, 0, 0),\r\n ringRadius: 0.5,\r\n tubeRadius: 0.015,\r\n sectorAngle: 180,\r\n tolerance: 0.05,\r\n });\r\n yArc.createGeometry(device);\r\n this._shapes.set('y', yArc);\r\n \r\n // Z 轴旋转环\r\n const zArc = new ArcShape({\r\n axis: 'z',\r\n defaultColor: theme.shapeBase.z,\r\n hoverColor: theme.shapeHover.z,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(90, 0, 90),\r\n ringRadius: 0.5,\r\n tubeRadius: 0.015,\r\n sectorAngle: 180,\r\n tolerance: 0.05,\r\n });\r\n zArc.createGeometry(device);\r\n this._shapes.set('z', zArc);\r\n \r\n // 面向相机的旋转环\r\n const fArc = new ArcShape({\r\n axis: 'xyz', // 使用 xyz 作为内部 axis\r\n defaultColor: theme.shapeBase.f,\r\n hoverColor: theme.shapeHover.f,\r\n disabledColor: theme.disabled,\r\n ringRadius: 0.55,\r\n tubeRadius: 0.015,\r\n sectorAngle: 360,\r\n tolerance: 0.05,\r\n });\r\n fArc.createGeometry(device);\r\n this._shapes.set('f', fArc);\r\n \r\n // 中心球(用于自由旋转)- 默认半透明,hover 时更明显\r\n const center = new SphereShape({\r\n axis: 'xyz',\r\n defaultColor: theme.shapeBase.xyz,\r\n hoverColor: theme.shapeHover.xyz,\r\n disabledColor: theme.disabled,\r\n defaultAlpha: 0.0, // 默认完全透明\r\n hoverAlpha: 0.3, // hover 时半透明\r\n radius: 0.45,\r\n });\r\n center.createGeometry(device);\r\n this._shapes.set('xyz', center);\r\n }\r\n\r\n /**\r\n * 创建缩放模式的形状\r\n */\r\n private createScaleShapes(device: GPUDevice): void {\r\n const theme = this._theme;\r\n \r\n // 中心球(统一缩放)\r\n const center = new SphereShape({\r\n axis: 'xyz',\r\n defaultColor: theme.shapeBase.xyz,\r\n hoverColor: theme.shapeHover.xyz,\r\n disabledColor: theme.disabled,\r\n radius: 0.1,\r\n });\r\n center.createGeometry(device);\r\n this._shapes.set('xyz', center);\r\n \r\n // X 轴缩放\r\n const xBox = new BoxLineShape({\r\n axis: 'x',\r\n defaultColor: theme.shapeBase.x,\r\n hoverColor: theme.shapeHover.x,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(0, 0, -90),\r\n });\r\n xBox.createGeometry(device);\r\n this._shapes.set('x', xBox);\r\n \r\n // Y 轴缩放\r\n const yBox = new BoxLineShape({\r\n axis: 'y',\r\n defaultColor: theme.shapeBase.y,\r\n hoverColor: theme.shapeHover.y,\r\n disabledColor: theme.disabled,\r\n });\r\n yBox.createGeometry(device);\r\n this._shapes.set('y', yBox);\r\n \r\n // Z 轴缩放\r\n const zBox = new BoxLineShape({\r\n axis: 'z',\r\n defaultColor: theme.shapeBase.z,\r\n hoverColor: theme.shapeHover.z,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(90, 0, 0),\r\n });\r\n zBox.createGeometry(device);\r\n this._shapes.set('z', zBox);\r\n }\r\n\r\n // ==================== 属性访问器 ====================\r\n \r\n get mode(): GizmoMode { return this._mode; }\r\n set mode(value: GizmoMode) {\r\n if (this._mode !== value) {\r\n this._mode = value;\r\n this.createShapes();\r\n this._clearInteractionState();\r\n }\r\n }\r\n \r\n get coordSpace(): GizmoSpace { return this._coordSpace; }\r\n set coordSpace(value: GizmoSpace) { this._coordSpace = value; }\r\n \r\n get size(): number { return this._size; }\r\n set size(value: number) { this._size = value; }\r\n \r\n get target(): TransformableObject | null { return this._target; }\r\n \r\n get isDragging(): boolean { return this._dragging; }\r\n\r\n // ==================== 目标管理 ====================\r\n \r\n setTarget(object: TransformableObject | null): void {\r\n this._target = object;\r\n this._clearInteractionState();\r\n }\r\n \r\n setOnDragStateChange(callback: ((isDragging: boolean) => void) | null): void {\r\n this._onDragStateChange = callback;\r\n }\r\n \r\n private _clearInteractionState(): void {\r\n this._hoverAxis = '';\r\n this._selectedAxis = '';\r\n this._hoverIsPlane = false;\r\n this._selectedIsPlane = false;\r\n this._dragging = false;\r\n this._dragStartTransform = null;\r\n \r\n for (const shape of this._shapes.values()) {\r\n shape.hover(false);\r\n }\r\n }\r\n\r\n // ==================== 缩放计算 ====================\r\n \r\n private getGizmoPosition(): Vec3 | null {\r\n if (!this._target) return null;\r\n return new Vec3(\r\n this._target.position[0],\r\n this._target.position[1],\r\n this._target.position[2]\r\n );\r\n }\r\n \r\n /**\r\n * 获取 Gizmo 的视觉旋转(用于渲染形状)\r\n * - 平移模式:根据 coordSpace 设置\r\n * - 旋转模式:始终使用世界坐标(三个轴保持正交)\r\n * - 缩放模式:始终使用本地坐标(跟随物体旋转)\r\n */\r\n private getGizmoRotation(): Quat {\r\n if (this._mode === GizmoMode.Rotate) {\r\n // 旋转模式始终使用世界坐标,保持三个轴正交\r\n return Quat.identity();\r\n }\r\n if (this._mode === GizmoMode.Scale && this._target) {\r\n // 缩放模式始终使用本地坐标\r\n return Quat.fromEuler(\r\n this._target.rotation[0],\r\n this._target.rotation[1],\r\n this._target.rotation[2]\r\n );\r\n }\r\n // 平移模式根据 coordSpace 设置\r\n if (this._coordSpace === 'local' && this._target) {\r\n return Quat.fromEuler(\r\n this._target.rotation[0],\r\n this._target.rotation[1],\r\n this._target.rotation[2]\r\n );\r\n }\r\n return Quat.identity();\r\n }\r\n \r\n private updateScale(): void {\r\n const gizmoPos = this.getGizmoPosition();\r\n if (!gizmoPos) return;\r\n \r\n const cameraPos = new Vec3(\r\n this.camera.position[0],\r\n this.camera.position[1],\r\n this.camera.position[2]\r\n );\r\n \r\n const dist = gizmoPos.distance(cameraPos);\r\n this._scale = Math.tan(0.5 * this.camera.fov) * dist * PERS_SCALE_RATIO;\r\n this._scale = Math.max(this._scale * this._size, MIN_SCALE);\r\n }\r\n \r\n /**\r\n * 获取面向相机的方向(从 Gizmo 指向相机)\r\n */\r\n private getFacingDir(): Vec3 {\r\n const gizmoPos = this.getGizmoPosition();\r\n if (!gizmoPos) return new Vec3(0, 0, 1);\r\n \r\n const cameraPos = new Vec3(\r\n this.camera.position[0],\r\n this.camera.position[1],\r\n this.camera.position[2]\r\n );\r\n \r\n return cameraPos.subtract(gizmoPos).normalize();\r\n }\r\n\r\n // ==================== 动态形状调整 ====================\r\n \r\n /**\r\n * 更新形状以面向相机\r\n * 参考 PlayCanvas 的 _shapesLookAtCamera\r\n */\r\n private _shapesLookAtCamera(): void {\r\n if (this._mode === GizmoMode.Translate) {\r\n this._updateTranslateShapesForCamera();\r\n } else if (this._mode === GizmoMode.Rotate) {\r\n this._updateRotateShapesForCamera();\r\n }\r\n }\r\n \r\n /**\r\n * 更新平移形状\r\n */\r\n private _updateTranslateShapesForCamera(): void {\r\n const facingDir = this.getFacingDir();\r\n const gizmoRot = this.getGizmoRotation();\r\n \r\n // 计算 Gizmo 的三个轴方向\r\n const right = gizmoRot.transformVector(new Vec3(1, 0, 0));\r\n const up = gizmoRot.transformVector(new Vec3(0, 1, 0));\r\n const forward = gizmoRot.transformVector(new Vec3(0, 0, 1));\r\n \r\n // 轴可见性\r\n const xShape = this._shapes.get('x');\r\n if (xShape) {\r\n const dot = Math.abs(facingDir.dot(right));\r\n xShape.visible = (1 - dot) > GLANCE_EPSILON;\r\n }\r\n \r\n const yShape = this._shapes.get('y');\r\n if (yShape) {\r\n const dot = Math.abs(facingDir.dot(up));\r\n yShape.visible = (1 - dot) > GLANCE_EPSILON;\r\n }\r\n \r\n const zShape = this._shapes.get('z');\r\n if (zShape) {\r\n const dot = Math.abs(facingDir.dot(forward));\r\n zShape.visible = (1 - dot) > GLANCE_EPSILON;\r\n }\r\n \r\n // 平面可见性和翻转\r\n const yzPlane = this._shapes.get('yz') as PlaneShape | undefined;\r\n if (yzPlane) {\r\n const cross = facingDir.cross(right);\r\n yzPlane.visible = (1 - cross.length()) > GLANCE_EPSILON;\r\n if (this.flipPlanes) {\r\n const flipped = new Vec3(\r\n 0,\r\n cross.dot(forward) < 0 ? 1 : 0,\r\n cross.dot(up) < 0 ? 1 : 0\r\n );\r\n yzPlane.setFlipped(flipped);\r\n }\r\n }\r\n \r\n const xzPlane = this._shapes.get('xz') as PlaneShape | undefined;\r\n if (xzPlane) {\r\n const cross = facingDir.cross(up);\r\n xzPlane.visible = (1 - cross.length()) > GLANCE_EPSILON;\r\n if (this.flipPlanes) {\r\n const flipped = new Vec3(\r\n cross.dot(forward) > 0 ? 1 : 0,\r\n 0,\r\n cross.dot(right) > 0 ? 1 : 0\r\n );\r\n xzPlane.setFlipped(flipped);\r\n }\r\n }\r\n \r\n const xyPlane = this._shapes.get('xy') as PlaneShape | undefined;\r\n if (xyPlane) {\r\n const cross = facingDir.cross(forward);\r\n xyPlane.visible = (1 - cross.length()) > GLANCE_EPSILON;\r\n if (this.flipPlanes) {\r\n const flipped = new Vec3(\r\n cross.dot(up) < 0 ? 1 : 0,\r\n cross.dot(right) > 0 ? 1 : 0,\r\n 0\r\n );\r\n xyPlane.setFlipped(flipped);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * 更新旋转形状\r\n */\r\n private _updateRotateShapesForCamera(): void {\r\n const facingDir = this.getFacingDir();\r\n const gizmoRot = this.getGizmoRotation();\r\n \r\n // 将面向方向转换到 Gizmo 局部空间\r\n const invRot = gizmoRot.inverse();\r\n const localFacingDir = invRot.transformVector(facingDir.clone());\r\n \r\n // 计算 Gizmo 的三个轴方向\r\n const right = gizmoRot.transformVector(new Vec3(1, 0, 0));\r\n const up = gizmoRot.transformVector(new Vec3(0, 1, 0));\r\n const forward = gizmoRot.transformVector(new Vec3(0, 0, 1));\r\n \r\n // X 轴旋转环\r\n const xArc = this._shapes.get('x') as ArcShape | undefined;\r\n if (xArc) {\r\n const angle = Math.atan2(localFacingDir.z, localFacingDir.y) * RAD_TO_DEG;\r\n xArc.setDynamicRotation(new Vec3(0, angle - 90, 0));\r\n \r\n const dot = facingDir.dot(right);\r\n if (!this._dragging) {\r\n const showSector = 1 - Math.abs(dot) > RING_FACING_EPSILON;\r\n xArc.show(showSector ? 'sector' : 'ring');\r\n }\r\n }\r\n \r\n // Y 轴旋转环\r\n const yArc = this._shapes.get('y') as ArcShape | undefined;\r\n if (yArc) {\r\n const angle = Math.atan2(localFacingDir.x, localFacingDir.z) * RAD_TO_DEG;\r\n yArc.setDynamicRotation(new Vec3(0, angle, 0));\r\n \r\n const dot = facingDir.dot(up);\r\n if (!this._dragging) {\r\n const showSector = 1 - Math.abs(dot) > RING_FACING_EPSILON;\r\n yArc.show(showSector ? 'sector' : 'ring');\r\n }\r\n }\r\n \r\n // Z 轴旋转环\r\n const zArc = this._shapes.get('z') as ArcShape | undefined;\r\n if (zArc) {\r\n const angle = Math.atan2(localFacingDir.y, localFacingDir.x) * RAD_TO_DEG;\r\n zArc.setDynamicRotation(new Vec3(0, 0, angle));\r\n \r\n const dot = facingDir.dot(forward);\r\n if (!this._dragging) {\r\n const showSector = 1 - Math.abs(dot) > RING_FACING_EPSILON;\r\n zArc.show(showSector ? 'sector' : 'ring');\r\n }\r\n }\r\n \r\n // 面向相机的旋转环\r\n const fArc = this._shapes.get('f') as ArcShape | undefined;\r\n if (fArc) {\r\n // 计算面向相机的旋转\r\n const cameraPos = new Vec3(\r\n this.camera.position[0],\r\n this.camera.position[1],\r\n this.camera.position[2]\r\n );\r\n const gizmoPos = this.getGizmoPosition()!;\r\n const dir = cameraPos.subtract(gizmoPos).normalize();\r\n \r\n const elev = Math.atan2(-dir.y, Math.sqrt(dir.x * dir.x + dir.z * dir.z)) * RAD_TO_DEG;\r\n const azim = Math.atan2(-dir.x, -dir.z) * RAD_TO_DEG;\r\n \r\n // 设置面向相机的旋转(覆盖基础旋转)\r\n fArc.setDynamicRotation(new Vec3(-elev + 90, azim, 0));\r\n }\r\n \r\n this._facingDir = facingDir;\r\n }\r\n\r\n /**\r\n * 拖拽时更新形状显示\r\n */\r\n private _updateDragVisibility(isDragging: boolean): void {\r\n if (this._mode === GizmoMode.Rotate) {\r\n this._updateRotateDragVisibility(isDragging);\r\n } else if (this._mode === GizmoMode.Translate) {\r\n this._updateTranslateDragVisibility(isDragging);\r\n } else if (this._mode === GizmoMode.Scale) {\r\n this._updateScaleDragVisibility(isDragging);\r\n }\r\n }\r\n \r\n private _updateRotateDragVisibility(isDragging: boolean): void {\r\n for (const [axis, shape] of this._shapes) {\r\n if (!(shape instanceof ArcShape)) continue;\r\n \r\n switch (this.dragMode) {\r\n case 'show':\r\n break;\r\n case 'hide':\r\n if (isDragging) {\r\n (shape as ArcShape).show(axis === this._selectedAxis ? 'ring' : 'none');\r\n } else {\r\n (shape as ArcShape).show('sector');\r\n }\r\n break;\r\n case 'selected':\r\n if (isDragging) {\r\n (shape as ArcShape).show(axis === this._selectedAxis ? 'ring' : 'sector');\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n \r\n private _updateTranslateDragVisibility(isDragging: boolean): void {\r\n for (const [axis, shape] of this._shapes) {\r\n switch (this.dragMode) {\r\n case 'show':\r\n break;\r\n case 'hide':\r\n shape.visible = !isDragging;\r\n break;\r\n case 'selected':\r\n if (this._selectedAxis === 'xyz') {\r\n shape.visible = isDragging ? axis.length === 1 : true;\r\n } else if (this._selectedIsPlane) {\r\n shape.visible = isDragging ? axis.length === 1 && !axis.includes(this._selectedAxis) : true;\r\n } else {\r\n shape.visible = isDragging ? axis === this._selectedAxis : true;\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n \r\n private _updateScaleDragVisibility(isDragging: boolean): void {\r\n for (const [axis, shape] of this._shapes) {\r\n switch (this.dragMode) {\r\n case 'show':\r\n break;\r\n case 'hide':\r\n shape.visible = !isDragging;\r\n break;\r\n case 'selected':\r\n if (this._selectedAxis === 'xyz') {\r\n shape.visible = isDragging ? axis.length === 1 : true;\r\n } else {\r\n shape.visible = isDragging ? axis === this._selectedAxis : true;\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n\r\n // ==================== 射线转换 ====================\r\n \r\n private screenToRay(screenX: number, screenY: number): Ray {\r\n const rect = this.canvas.getBoundingClientRect();\r\n const canvasX = screenX - rect.left;\r\n const canvasY = screenY - rect.top;\r\n \r\n const scaleX = this.canvas.width / rect.width;\r\n const scaleY = this.canvas.height / rect.height;\r\n \r\n const pixelX = canvasX * scaleX;\r\n const pixelY = canvasY * scaleY;\r\n \r\n return Ray.fromScreenPoint(\r\n pixelX,\r\n pixelY,\r\n this.canvas.width,\r\n this.canvas.height,\r\n this.camera\r\n );\r\n }\r\n \r\n private performHitTest(ray: Ray): { axis: GizmoAxisType | 'f' | ''; isPlane: boolean } {\r\n if (!this._target) {\r\n return { axis: '', isPlane: false };\r\n }\r\n \r\n const gizmoPos = this.getGizmoPosition()!;\r\n const gizmoRot = this.getGizmoRotation();\r\n \r\n const scale = new Vec3(this._scale, this._scale, this._scale);\r\n const worldTransform = Mat4.compose(gizmoPos, gizmoRot, scale);\r\n \r\n let closestDist: number | null = null;\r\n let closestAxis: GizmoAxisType | 'f' | '' = '';\r\n let closestIsPlane = false;\r\n \r\n for (const [axis, shape] of this._shapes) {\r\n // 不检查 visible,让 Shape.intersect() 通过 interactable 属性控制\r\n // 这样透明但可交互的形状(如旋转模式的中心球)仍然可以被选中\r\n if (shape.disabled) continue;\r\n \r\n const dist = shape.intersect(ray, worldTransform);\r\n if (dist !== null && (closestDist === null || dist < closestDist)) {\r\n closestDist = dist;\r\n closestAxis = axis;\r\n closestIsPlane = axis.length === 2;\r\n }\r\n }\r\n \r\n return { axis: closestAxis, isPlane: closestIsPlane };\r\n }\r\n\r\n // ==================== 事件处理 ====================\r\n \r\n onPointerMove(event: PointerEvent): void {\r\n if (!this._target) return;\r\n \r\n const ray = this.screenToRay(event.clientX, event.clientY);\r\n \r\n if (!this._dragging) {\r\n const hit = this.performHitTest(ray);\r\n this._updateHover(hit.axis, hit.isPlane);\r\n } else {\r\n const point = this._screenToPoint(event.clientX, event.clientY);\r\n this._applyTransform(point);\r\n }\r\n }\r\n \r\n onPointerDown(event: PointerEvent): void {\r\n if (!this._target) return;\r\n \r\n const ray = this.screenToRay(event.clientX, event.clientY);\r\n const hit = this.performHitTest(ray);\r\n \r\n if (hit.axis) {\r\n this._selectedAxis = hit.axis;\r\n this._selectedIsPlane = hit.isPlane;\r\n this._dragging = true;\r\n \r\n this._rootStartPos = this.getGizmoPosition()!.clone();\r\n this._rootStartRot = this.getGizmoRotation();\r\n \r\n const point = this._screenToPoint(event.clientX, event.clientY);\r\n this._selectionStartPoint = point.clone();\r\n \r\n this._dragStartTransform = {\r\n position: new Vec3(\r\n this._target.position[0],\r\n this._target.position[1],\r\n this._target.position[2]\r\n ),\r\n rotation: new Vec3(\r\n this._target.rotation[0],\r\n this._target.rotation[1],\r\n this._target.rotation[2]\r\n ),\r\n scale: new Vec3(\r\n this._target.scale[0],\r\n this._target.scale[1],\r\n this._target.scale[2]\r\n ),\r\n };\r\n \r\n this.canvas.setPointerCapture(event.pointerId);\r\n \r\n // 更新拖拽时的形状显示\r\n this._updateDragVisibility(true);\r\n \r\n if (this._onDragStateChange) {\r\n this._onDragStateChange(true);\r\n }\r\n }\r\n }\r\n \r\n onPointerUp(event: PointerEvent): void {\r\n const wasDragging = this._dragging;\r\n \r\n this._dragging = false;\r\n this._selectedAxis = '';\r\n this._selectedIsPlane = false;\r\n this._dragStartTransform = null;\r\n \r\n if (this.canvas.hasPointerCapture(event.pointerId)) {\r\n this.canvas.releasePointerCapture(event.pointerId);\r\n }\r\n \r\n // 恢复形状显示\r\n this._updateDragVisibility(false);\r\n \r\n if (wasDragging && this._onDragStateChange) {\r\n this._onDragStateChange(false);\r\n }\r\n }\r\n\r\n private _updateHover(axis: GizmoAxisType | 'f' | '', isPlane: boolean): void {\r\n if (this._dragging) return;\r\n \r\n if (this._hoverAxis !== axis) {\r\n // 清除之前的 hover 状态\r\n for (const shape of this._shapes.values()) {\r\n shape.hover(false);\r\n }\r\n \r\n this._hoverAxis = axis;\r\n this._hoverIsPlane = isPlane;\r\n \r\n if (axis) {\r\n if (axis === 'xyz') {\r\n this._shapes.get('x')?.hover(true);\r\n this._shapes.get('y')?.hover(true);\r\n this._shapes.get('z')?.hover(true);\r\n this._shapes.get('xyz')?.hover(true);\r\n } else if (axis === 'f') {\r\n this._shapes.get('f')?.hover(true);\r\n } else if (isPlane) {\r\n const shape = this._shapes.get(axis);\r\n shape?.hover(true);\r\n for (const char of axis) {\r\n this._shapes.get(char as GizmoAxisType)?.hover(true);\r\n }\r\n } else {\r\n this._shapes.get(axis)?.hover(true);\r\n }\r\n }\r\n }\r\n }\r\n\r\n // ==================== 变换计算 ====================\r\n \r\n private _screenToPoint(x: number, y: number): Vec3 {\r\n const ray = this.screenToRay(x, y);\r\n const axis = this._selectedAxis;\r\n const isPlane = this._selectedIsPlane;\r\n \r\n // 旋转模式使用不同的平面\r\n if (this._mode === GizmoMode.Rotate && axis && axis !== 'xyz' && axis.length === 1) {\r\n const plane = this._createRotationPlane(axis);\r\n const dist = ray.intersectPlane(plane.point, plane.normal);\r\n if (dist === null) {\r\n return this._rootStartPos.clone();\r\n }\r\n return ray.at(dist);\r\n }\r\n \r\n // 面向相机的旋转\r\n if (this._mode === GizmoMode.Rotate && axis === 'f') {\r\n const plane = this._createFacingPlane();\r\n const dist = ray.intersectPlane(plane.point, plane.normal);\r\n if (dist === null) {\r\n return this._rootStartPos.clone();\r\n }\r\n return ray.at(dist);\r\n }\r\n \r\n const plane = this._createInteractionPlane(axis as GizmoAxisType, isPlane);\r\n \r\n const dist = ray.intersectPlane(plane.point, plane.normal);\r\n if (dist === null) {\r\n return new Vec3(0, 0, 0);\r\n }\r\n \r\n const point = ray.at(dist);\r\n \r\n const localPoint = point.subtract(this._rootStartPos);\r\n const invRot = this._rootStartRot.inverse();\r\n const rotatedPoint = invRot.transformVector(localPoint);\r\n \r\n if (!isPlane && axis !== 'xyz' && axis !== 'f' && axis.length === 1) {\r\n this._projectToAxis(rotatedPoint, axis);\r\n }\r\n \r\n return rotatedPoint;\r\n }\r\n\r\n private _createRotationPlane(axis: string): { point: Vec3; normal: Vec3 } {\r\n const point = this._rootStartPos.clone();\r\n let normal = new Vec3(0, 1, 0);\r\n \r\n if (this._coordSpace === 'local') {\r\n if (axis === 'x') normal = this._rootStartRot.transformVector(new Vec3(1, 0, 0));\r\n else if (axis === 'y') normal = this._rootStartRot.transformVector(new Vec3(0, 1, 0));\r\n else if (axis === 'z') normal = this._rootStartRot.transformVector(new Vec3(0, 0, 1));\r\n } else {\r\n if (axis === 'x') normal = new Vec3(1, 0, 0);\r\n else if (axis === 'y') normal = new Vec3(0, 1, 0);\r\n else if (axis === 'z') normal = new Vec3(0, 0, 1);\r\n }\r\n \r\n return { point, normal };\r\n }\r\n \r\n private _createFacingPlane(): { point: Vec3; normal: Vec3 } {\r\n const point = this._rootStartPos.clone();\r\n const normal = this.getFacingDir().multiply(-1);\r\n return { point, normal };\r\n }\r\n \r\n private _createInteractionPlane(\r\n axis: GizmoAxisType | '', \r\n isPlane: boolean\r\n ): { point: Vec3; normal: Vec3 } {\r\n const point = this._rootStartPos.clone();\r\n let normal = new Vec3(0, 1, 0);\r\n \r\n if (axis === 'xyz' || isPlane) {\r\n const facingDir = this.getFacingDir();\r\n normal = facingDir.multiply(-1);\r\n } else if (axis === 'x') {\r\n const axisDir = this._rootStartRot.transformVector(new Vec3(1, 0, 0));\r\n const cameraDir = this.getFacingDir();\r\n const cross = axisDir.cross(cameraDir);\r\n if (cross.lengthSquared() > 1e-6) {\r\n normal = cross.cross(axisDir).normalize();\r\n } else {\r\n normal = this._rootStartRot.transformVector(new Vec3(0, 1, 0));\r\n }\r\n } else if (axis === 'y') {\r\n const axisDir = this._rootStartRot.transformVector(new Vec3(0, 1, 0));\r\n const cameraDir = this.getFacingDir();\r\n const cross = axisDir.cross(cameraDir);\r\n if (cross.lengthSquared() > 1e-6) {\r\n normal = cross.cross(axisDir).normalize();\r\n } else {\r\n normal = this._rootStartRot.transformVector(new Vec3(1, 0, 0));\r\n }\r\n } else if (axis === 'z') {\r\n const axisDir = this._rootStartRot.transformVector(new Vec3(0, 0, 1));\r\n const cameraDir = this.getFacingDir();\r\n const cross = axisDir.cross(cameraDir);\r\n if (cross.lengthSquared() > 1e-6) {\r\n normal = cross.cross(axisDir).normalize();\r\n } else {\r\n normal = this._rootStartRot.transformVector(new Vec3(0, 1, 0));\r\n }\r\n }\r\n \r\n return { point, normal };\r\n }\r\n \r\n private _projectToAxis(point: Vec3, axis: string): void {\r\n if (axis === 'x') {\r\n point.y = 0;\r\n point.z = 0;\r\n } else if (axis === 'y') {\r\n point.x = 0;\r\n point.z = 0;\r\n } else if (axis === 'z') {\r\n point.x = 0;\r\n point.y = 0;\r\n }\r\n }\r\n\r\n private _applyTransform(point: Vec3): void {\r\n if (!this._target || !this._dragStartTransform) return;\r\n \r\n const delta = point.subtract(this._selectionStartPoint);\r\n \r\n if (this._mode === GizmoMode.Translate) {\r\n this._applyTranslation(delta);\r\n } else if (this._mode === GizmoMode.Rotate) {\r\n this._applyRotation(point);\r\n } else if (this._mode === GizmoMode.Scale) {\r\n this._applyScale(delta);\r\n }\r\n }\r\n \r\n private _applyTranslation(delta: Vec3): void {\r\n if (!this._target || !this._dragStartTransform) return;\r\n \r\n if (this.snap) {\r\n delta.x = Math.round(delta.x / this.snapIncrement) * this.snapIncrement;\r\n delta.y = Math.round(delta.y / this.snapIncrement) * this.snapIncrement;\r\n delta.z = Math.round(delta.z / this.snapIncrement) * this.snapIncrement;\r\n }\r\n \r\n const worldDelta = this._rootStartRot.transformVector(delta);\r\n \r\n const newPos = this._dragStartTransform.position.add(worldDelta);\r\n this._target.setPosition(newPos.x, newPos.y, newPos.z);\r\n }\r\n \r\n private _applyRotation(point: Vec3): void {\r\n if (!this._target || !this._dragStartTransform) return;\r\n \r\n const axis = this._selectedAxis;\r\n if (!axis) return;\r\n \r\n // 面向相机的旋转\r\n if (axis === 'f') {\r\n this._applyFacingRotation(point);\r\n return;\r\n }\r\n \r\n if (axis === 'xyz') return;\r\n \r\n const gizmoPos = this._rootStartPos;\r\n \r\n const startVec = this._selectionStartPoint.subtract(gizmoPos);\r\n const currentVec = point.subtract(gizmoPos);\r\n \r\n let rotAxis = new Vec3(0, 1, 0);\r\n if (this._coordSpace === 'local') {\r\n if (axis === 'x') rotAxis = this._rootStartRot.transformVector(new Vec3(1, 0, 0));\r\n else if (axis === 'y') rotAxis = this._rootStartRot.transformVector(new Vec3(0, 1, 0));\r\n else if (axis === 'z') rotAxis = this._rootStartRot.transformVector(new Vec3(0, 0, 1));\r\n } else {\r\n if (axis === 'x') rotAxis = new Vec3(1, 0, 0);\r\n else if (axis === 'y') rotAxis = new Vec3(0, 1, 0);\r\n else if (axis === 'z') rotAxis = new Vec3(0, 0, 1);\r\n }\r\n \r\n if (startVec.lengthSquared() < 1e-6 || currentVec.lengthSquared() < 1e-6) {\r\n return;\r\n }\r\n \r\n const startNorm = startVec.normalize();\r\n const currentNorm = currentVec.normalize();\r\n \r\n const cosAngle = Math.max(-1, Math.min(1, startNorm.dot(currentNorm)));\r\n const crossVec = startNorm.cross(currentNorm);\r\n const sinAngle = crossVec.dot(rotAxis);\r\n let angleDelta = Math.atan2(sinAngle, cosAngle);\r\n \r\n if (this.snap) {\r\n const snapAngle = this.snapIncrement * Math.PI / 180;\r\n angleDelta = Math.round(angleDelta / snapAngle) * snapAngle;\r\n }\r\n \r\n const deltaQuat = Quat.fromAxisAngle(rotAxis, angleDelta);\r\n \r\n const startRot = Quat.fromEuler(\r\n this._dragStartTransform.rotation.x,\r\n this._dragStartTransform.rotation.y,\r\n this._dragStartTransform.rotation.z\r\n );\r\n \r\n const newRot = deltaQuat.multiply(startRot);\r\n \r\n const euler = newRot.toEuler();\r\n this._target.setRotation(euler.x, euler.y, euler.z);\r\n }\r\n\r\n private _applyFacingRotation(point: Vec3): void {\r\n if (!this._target || !this._dragStartTransform) return;\r\n \r\n const gizmoPos = this._rootStartPos;\r\n \r\n const startVec = this._selectionStartPoint.subtract(gizmoPos);\r\n const currentVec = point.subtract(gizmoPos);\r\n \r\n // 旋转轴是面向相机的方向\r\n const rotAxis = this.getFacingDir();\r\n \r\n if (startVec.lengthSquared() < 1e-6 || currentVec.lengthSquared() < 1e-6) {\r\n return;\r\n }\r\n \r\n const startNorm = startVec.normalize();\r\n const currentNorm = currentVec.normalize();\r\n \r\n const cosAngle = Math.max(-1, Math.min(1, startNorm.dot(currentNorm)));\r\n const crossVec = startNorm.cross(currentNorm);\r\n const sinAngle = crossVec.dot(rotAxis);\r\n let angleDelta = Math.atan2(sinAngle, cosAngle);\r\n \r\n if (this.snap) {\r\n const snapAngle = this.snapIncrement * Math.PI / 180;\r\n angleDelta = Math.round(angleDelta / snapAngle) * snapAngle;\r\n }\r\n \r\n const deltaQuat = Quat.fromAxisAngle(rotAxis, angleDelta);\r\n \r\n const startRot = Quat.fromEuler(\r\n this._dragStartTransform.rotation.x,\r\n this._dragStartTransform.rotation.y,\r\n this._dragStartTransform.rotation.z\r\n );\r\n \r\n const newRot = deltaQuat.multiply(startRot);\r\n \r\n const euler = newRot.toEuler();\r\n this._target.setRotation(euler.x, euler.y, euler.z);\r\n }\r\n \r\n private _applyScale(delta: Vec3): void {\r\n if (!this._target || !this._dragStartTransform) return;\r\n \r\n const axis = this._selectedAxis;\r\n \r\n let scaleFactor = 1.0;\r\n if (axis === 'x') scaleFactor = 1.0 + delta.x;\r\n else if (axis === 'y') scaleFactor = 1.0 + delta.y;\r\n else if (axis === 'z') scaleFactor = 1.0 + delta.z;\r\n else if (axis === 'xyz') scaleFactor = 1.0 + (delta.x + delta.y + delta.z) / 3;\r\n \r\n scaleFactor = Math.max(0.001, scaleFactor);\r\n \r\n if (this.snap) {\r\n scaleFactor = Math.round(scaleFactor / this.snapIncrement) * this.snapIncrement;\r\n scaleFactor = Math.max(0.001, scaleFactor);\r\n }\r\n \r\n const newScale = this._dragStartTransform.scale.clone();\r\n if (axis === 'x') newScale.x *= scaleFactor;\r\n else if (axis === 'y') newScale.y *= scaleFactor;\r\n else if (axis === 'z') newScale.z *= scaleFactor;\r\n else if (axis === 'xyz') {\r\n newScale.x *= scaleFactor;\r\n newScale.y *= scaleFactor;\r\n newScale.z *= scaleFactor;\r\n }\r\n \r\n this._target.setScale(newScale.x, newScale.y, newScale.z);\r\n }\r\n\r\n // ==================== 渲染 ====================\r\n \r\n private getShapeModelMatrix(shape: Shape): Mat4 {\r\n const gizmoPos = this.getGizmoPosition()!;\r\n const gizmoRot = this.getGizmoRotation();\r\n const scale = new Vec3(this._scale, this._scale, this._scale);\r\n \r\n const gizmoMatrix = Mat4.compose(gizmoPos, gizmoRot, scale);\r\n const shapeLocalMatrix = shape.getLocalTransform();\r\n \r\n return gizmoMatrix.multiply(shapeLocalMatrix);\r\n }\r\n \r\n private updateUniformsForShape(axis: GizmoAxisType | 'f', shape: Shape): void {\r\n const uniformBuffer = this.shapeUniformBuffers.get(axis);\r\n if (!uniformBuffer) return;\r\n \r\n const device = this.renderer.device;\r\n \r\n const modelMatrix = this.getShapeModelMatrix(shape);\r\n \r\n const viewProjectionMatrix = new Mat4();\r\n viewProjectionMatrix.elements.set(this.camera.viewProjectionMatrix);\r\n \r\n // 获取当前颜色(包含透明度)\r\n const color = shape.getColor();\r\n \r\n // uniform 数据:viewProj(64) + model(64) + color(16) = 144 bytes\r\n // 但需要 16 字节对齐,所以用 36 个 float\r\n const uniformData = new Float32Array(36);\r\n uniformData.set(viewProjectionMatrix.elements, 0);\r\n uniformData.set(modelMatrix.elements, 16);\r\n uniformData[32] = color.r;\r\n uniformData[33] = color.g;\r\n uniformData[34] = color.b;\r\n uniformData[35] = color.a;\r\n \r\n device.queue.writeBuffer(uniformBuffer, 0, uniformData);\r\n }\r\n \r\n render(pass: GPURenderPassEncoder): void {\r\n if (!this._target) return;\r\n if (!this.pipeline) return;\r\n \r\n this.updateScale();\r\n this._shapesLookAtCamera();\r\n \r\n pass.setPipeline(this.pipeline);\r\n \r\n for (const [axis, shape] of this._shapes) {\r\n if (!shape.visible) continue;\r\n this.updateUniformsForShape(axis, shape);\r\n }\r\n \r\n for (const [axis, shape] of this._shapes) {\r\n if (!shape.visible) continue;\r\n \r\n const vertexBuffer = shape.getVertexBuffer();\r\n const indexBuffer = shape.getIndexBuffer();\r\n const indexCount = shape.getIndexCount();\r\n const bindGroup = this.shapeBindGroups.get(axis);\r\n \r\n if (!vertexBuffer || !indexBuffer || indexCount === 0 || !bindGroup) {\r\n continue;\r\n }\r\n \r\n pass.setBindGroup(0, bindGroup);\r\n pass.setVertexBuffer(0, vertexBuffer);\r\n pass.setIndexBuffer(indexBuffer, \"uint16\");\r\n pass.drawIndexed(indexCount);\r\n }\r\n }\r\n\r\n destroy(): void {\r\n for (const shape of this._shapes.values()) {\r\n shape.destroy();\r\n }\r\n this._shapes.clear();\r\n \r\n for (const buffer of this.shapeUniformBuffers.values()) {\r\n buffer.destroy();\r\n }\r\n this.shapeUniformBuffers.clear();\r\n this.shapeBindGroups.clear();\r\n \r\n if (this.uniformBuffer) {\r\n this.uniformBuffer.destroy();\r\n this.uniformBuffer = null;\r\n }\r\n \r\n if (this.guideLineBuffer) {\r\n this.guideLineBuffer.destroy();\r\n this.guideLineBuffer = null;\r\n }\r\n \r\n this.pipeline = null;\r\n this.linePipeline = null;\r\n this.bindGroup = null;\r\n this.guideLineBindGroup = null;\r\n this.bindGroupLayout = null;\r\n }\r\n}\r\n","/**\r\n * GizmoManager - Gizmo 交互管理器\r\n * \r\n * 负责管理所有 Gizmo 相关的交互:\r\n * - TransformGizmo(变换控制)\r\n * - ViewportGizmo(视口坐标轴)\r\n * - BoundingBoxRenderer(选中对象包围盒)\r\n */\r\n\r\nimport { Renderer } from \"../core/Renderer\";\r\nimport { Camera } from \"../core/Camera\";\r\nimport { OrbitControls } from \"../core/OrbitControls\";\r\nimport { ViewportGizmo } from \"../core/ViewportGizmo\";\r\nimport { TransformGizmoV2, TransformableObject, GizmoMode } from \"../core/gizmo/TransformGizmoV2\";\r\nimport { BoundingBoxRenderer, BoundingBox as RendererBoundingBox, BoundingBoxProvider } from \"../core/BoundingBoxRenderer\";\r\nimport type { IGSSplatRenderer } from \"../gs/IGSSplatRenderer\";\r\nimport type { Mesh } from \"../mesh/Mesh\";\r\n\r\n// 从 scene/proxies 导入代理类\r\nimport { \r\n SplatTransformProxy, \r\n MeshGroupProxy, \r\n SplatBoundingBoxProvider \r\n} from \"../scene/proxies\";\r\n\r\n// 重新导出代理类保持向后兼容\r\nexport { SplatTransformProxy, MeshGroupProxy, SplatBoundingBoxProvider };\r\n\r\n/**\r\n * GizmoManager - Gizmo 交互管理器\r\n */\r\nexport class GizmoManager {\r\n private renderer: Renderer;\r\n private camera: Camera;\r\n private canvas: HTMLCanvasElement;\r\n private controls: OrbitControls;\r\n\r\n private viewportGizmo: ViewportGizmo;\r\n private transformGizmo: TransformGizmoV2;\r\n private boundingBoxRenderer: BoundingBoxRenderer;\r\n\r\n // 事件处理函数引用(用于移除监听器)\r\n private boundOnClick: (e: MouseEvent) => void;\r\n private boundOnPointerMove: (e: PointerEvent) => void;\r\n private boundOnPointerDown: (e: PointerEvent) => void;\r\n private boundOnPointerUp: (e: PointerEvent) => void;\r\n\r\n constructor(\r\n renderer: Renderer,\r\n camera: Camera,\r\n canvas: HTMLCanvasElement,\r\n controls: OrbitControls\r\n ) {\r\n this.renderer = renderer;\r\n this.camera = camera;\r\n this.canvas = canvas;\r\n this.controls = controls;\r\n\r\n // 初始化 Gizmo\r\n this.viewportGizmo = new ViewportGizmo(renderer, camera, canvas);\r\n this.transformGizmo = new TransformGizmoV2({ renderer, camera, canvas });\r\n this.transformGizmo.init();\r\n this.boundingBoxRenderer = new BoundingBoxRenderer(renderer, camera);\r\n\r\n // 设置 Gizmo 拖拽时禁用 OrbitControls\r\n this.transformGizmo.setOnDragStateChange((isDragging) => {\r\n this.controls.enabled = !isDragging;\r\n });\r\n\r\n // 绑定事件处理函数\r\n this.boundOnClick = this.onCanvasClick.bind(this);\r\n this.boundOnPointerMove = this.onPointerMove.bind(this);\r\n this.boundOnPointerDown = this.onPointerDown.bind(this);\r\n this.boundOnPointerUp = this.onPointerUp.bind(this);\r\n\r\n this.setupEventListeners();\r\n }\r\n\r\n /**\r\n * 设置事件监听器\r\n */\r\n private setupEventListeners(): void {\r\n // 设置视口 Gizmo 轴点击回调\r\n this.viewportGizmo.setOnAxisClick((axis, positive) => {\r\n this.controls.setViewAxis(axis, positive, true);\r\n });\r\n\r\n // 监听点击事件\r\n this.canvas.addEventListener(\"click\", this.boundOnClick);\r\n\r\n // 添加变换 Gizmo 的指针事件监听器\r\n this.canvas.addEventListener(\"pointermove\", this.boundOnPointerMove);\r\n this.canvas.addEventListener(\"pointerdown\", this.boundOnPointerDown);\r\n this.canvas.addEventListener(\"pointerup\", this.boundOnPointerUp);\r\n }\r\n\r\n private onCanvasClick(e: MouseEvent): void {\r\n this.viewportGizmo.handleClick(e.clientX, e.clientY);\r\n }\r\n\r\n private onPointerMove(e: PointerEvent): void {\r\n this.transformGizmo.onPointerMove(e);\r\n }\r\n\r\n private onPointerDown(e: PointerEvent): void {\r\n this.transformGizmo.onPointerDown(e);\r\n }\r\n\r\n private onPointerUp(e: PointerEvent): void {\r\n this.transformGizmo.onPointerUp(e);\r\n }\r\n\r\n // ============================================\r\n // 渲染\r\n // ============================================\r\n\r\n /**\r\n * 渲染所有 Gizmo\r\n */\r\n render(pass: GPURenderPassEncoder): void {\r\n // 渲染包围盒\r\n this.boundingBoxRenderer.render(pass);\r\n // 渲染变换 Gizmo\r\n this.transformGizmo.render(pass);\r\n // 渲染视口 Gizmo\r\n this.viewportGizmo.render(pass);\r\n }\r\n\r\n // ============================================\r\n // Transform Gizmo\r\n // ============================================\r\n\r\n /**\r\n * 获取变换 Gizmo\r\n */\r\n getTransformGizmo(): TransformGizmoV2 {\r\n return this.transformGizmo;\r\n }\r\n\r\n /**\r\n * 设置 Gizmo 模式\r\n */\r\n setGizmoMode(mode: GizmoMode): void {\r\n this.transformGizmo.mode = mode;\r\n }\r\n\r\n /**\r\n * 设置 Gizmo 目标对象\r\n */\r\n setGizmoTarget(object: TransformableObject | null): void {\r\n this.transformGizmo.setTarget(object);\r\n }\r\n\r\n // ============================================\r\n // Viewport Gizmo\r\n // ============================================\r\n\r\n /**\r\n * 获取视口 Gizmo\r\n */\r\n getViewportGizmo(): ViewportGizmo {\r\n return this.viewportGizmo;\r\n }\r\n\r\n // ============================================\r\n // Bounding Box\r\n // ============================================\r\n\r\n /**\r\n * 获取包围盒渲染器\r\n */\r\n getBoundingBoxRenderer(): BoundingBoxRenderer {\r\n return this.boundingBoxRenderer;\r\n }\r\n\r\n /**\r\n * 设置选中对象的包围盒(静态模式)\r\n */\r\n setSelectionBoundingBox(box: RendererBoundingBox | null): void {\r\n this.boundingBoxRenderer.setBoundingBox(box);\r\n }\r\n\r\n /**\r\n * 设置选中对象的包围盒提供者(动态模式)\r\n */\r\n setSelectionBoundingBoxProvider(provider: BoundingBoxProvider | null): void {\r\n this.boundingBoxRenderer.setProvider(provider);\r\n }\r\n\r\n /**\r\n * 清除选中对象的包围盒\r\n */\r\n clearSelectionBoundingBox(): void {\r\n this.boundingBoxRenderer.clear();\r\n }\r\n\r\n // ============================================\r\n // 代理对象创建\r\n // ============================================\r\n\r\n /**\r\n * 创建 Splat 变换代理\r\n */\r\n createSplatTransformProxy(renderer: IGSSplatRenderer): SplatTransformProxy | null {\r\n const bbox = renderer.getBoundingBox();\r\n if (!bbox) return null;\r\n return new SplatTransformProxy(renderer, bbox.center);\r\n }\r\n\r\n /**\r\n * 创建 Mesh 组变换代理\r\n */\r\n createMeshGroupProxy(meshes: Mesh[]): MeshGroupProxy | null {\r\n if (meshes.length === 0) return null;\r\n return new MeshGroupProxy(meshes);\r\n }\r\n\r\n /**\r\n * 创建 Splat 包围盒提供者\r\n */\r\n createSplatBoundingBoxProvider(renderer: IGSSplatRenderer): SplatBoundingBoxProvider {\r\n return new SplatBoundingBoxProvider(renderer);\r\n }\r\n\r\n /**\r\n * 销毁\r\n */\r\n destroy(): void {\r\n // 移除事件监听器\r\n this.canvas.removeEventListener(\"click\", this.boundOnClick);\r\n this.canvas.removeEventListener(\"pointermove\", this.boundOnPointerMove);\r\n this.canvas.removeEventListener(\"pointerdown\", this.boundOnPointerDown);\r\n this.canvas.removeEventListener(\"pointerup\", this.boundOnPointerUp);\r\n\r\n // 销毁 Gizmo\r\n this.transformGizmo.destroy();\r\n this.boundingBoxRenderer.destroy();\r\n }\r\n}\r\n","/**\r\n * App - 统一调度入口\r\n * \r\n * 重构后的职责:\r\n * - 初始化和协调各子系统\r\n * - 渲染循环管理\r\n * - 模型加载(委托给加载器)\r\n * - 对外提供简洁的 API\r\n * \r\n * 场景管理委托给 SceneManager\r\n * Gizmo 交互委托给 GizmoManager\r\n */\r\n\r\nimport { Renderer } from \"./core/Renderer\";\r\nimport { Camera } from \"./core/Camera\";\r\nimport { OrbitControls } from \"./core/OrbitControls\";\r\nimport { MeshRenderer } from \"./mesh/MeshRenderer\";\r\nimport { GLBLoader } from \"./loaders/GLBLoader\";\r\nimport { OBJLoader } from \"./loaders/OBJLoader\";\r\nimport { Mesh } from \"./mesh/Mesh\";\r\nimport { GSSplatRenderer } from \"./gs/GSSplatRenderer\";\r\nimport { GSSplatRendererMobile } from \"./gs/GSSplatRendererMobile\";\r\nimport type { IGSSplatRenderer } from \"./gs/IGSSplatRenderer\";\r\nimport type { BoundingBox } from \"./types\";\r\nimport { deserializeSplat } from \"./gs/SplatLoader\";\r\nimport { SceneManager } from \"./scene/SceneManager\";\r\nimport { \r\n GizmoManager, \r\n SplatTransformProxy, \r\n MeshGroupProxy, \r\n SplatBoundingBoxProvider \r\n} from \"./interaction/GizmoManager\";\r\nimport { TransformableObject, GizmoMode } from \"./core/gizmo/TransformGizmoV2\";\r\nimport { BoundingBoxProvider } from \"./core/BoundingBoxRenderer\";\r\nimport { isMobileDevice } from \"./utils\";\r\n\r\n// 重新导出代理类以保持向后兼容\r\nexport { SplatTransformProxy, MeshGroupProxy, SplatBoundingBoxProvider };\r\n\r\n/**\r\n * 统一进度回调类型\r\n * @param progress 进度值 0-100\r\n * @param stage 当前阶段: 'download' | 'parse' | 'upload'\r\n */\r\nexport type ProgressCallback = (progress: number, stage: 'download' | 'parse' | 'upload') => void;\r\n\r\n/**\r\n * App - 统一调度入口\r\n */\r\nexport class App {\r\n private canvas: HTMLCanvasElement;\r\n private renderer!: Renderer;\r\n private camera!: Camera;\r\n private controls!: OrbitControls;\r\n private meshRenderer!: MeshRenderer;\r\n private glbLoader!: GLBLoader;\r\n private objLoader!: OBJLoader;\r\n\r\n // 子系统管理器\r\n private sceneManager!: SceneManager;\r\n private gizmoManager!: GizmoManager;\r\n\r\n private isRunning: boolean = false;\r\n private animationId: number = 0;\r\n\r\n // 是否使用移动端渲染器\r\n private useMobileRenderer: boolean = false;\r\n\r\n // 绑定的事件处理函数\r\n private boundOnResize: () => void;\r\n\r\n constructor(canvas: HTMLCanvasElement) {\r\n this.canvas = canvas;\r\n this.boundOnResize = this.onResize.bind(this);\r\n }\r\n\r\n /**\r\n * 初始化应用\r\n */\r\n async init(): Promise<void> {\r\n // 初始化渲染器\r\n this.renderer = new Renderer(this.canvas);\r\n await this.renderer.init();\r\n\r\n // 初始化相机\r\n this.camera = new Camera();\r\n this.camera.setAspect(this.renderer.getAspectRatio());\r\n\r\n // 初始化控制器\r\n this.controls = new OrbitControls(this.camera, this.canvas);\r\n\r\n // 初始化网格渲染器\r\n this.meshRenderer = new MeshRenderer(this.renderer, this.camera);\r\n\r\n // 初始化加载器\r\n this.glbLoader = new GLBLoader(this.renderer.device);\r\n this.objLoader = new OBJLoader(this.renderer.device);\r\n\r\n // 初始化场景管理器\r\n this.sceneManager = new SceneManager(this.meshRenderer);\r\n\r\n // 初始化 Gizmo 管理器\r\n this.gizmoManager = new GizmoManager(\r\n this.renderer,\r\n this.camera,\r\n this.canvas,\r\n this.controls\r\n );\r\n\r\n // 监听窗口大小变化\r\n window.addEventListener(\"resize\", this.boundOnResize);\r\n }\r\n\r\n // ============================================\r\n // 模型加载\r\n // ============================================\r\n\r\n /**\r\n * 加载 GLB 文件\r\n */\r\n async addGLB(url: string): Promise<number> {\r\n try {\r\n const loadedMeshes = await this.glbLoader.load(url);\r\n for (const { mesh, material } of loadedMeshes) {\r\n this.meshRenderer.addMesh(mesh, material);\r\n }\r\n return loadedMeshes.length;\r\n } catch (error) {\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * 加载 OBJ 文件\r\n */\r\n async addOBJ(url: string): Promise<Mesh[]> {\r\n try {\r\n const loadedMeshes = await this.objLoader.load(url);\r\n const meshes: Mesh[] = [];\r\n for (const { mesh, material } of loadedMeshes) {\r\n this.meshRenderer.addMesh(mesh, material);\r\n meshes.push(mesh);\r\n }\r\n return meshes;\r\n } catch (error) {\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * 加载 PLY 文件 (3D Gaussian Splatting)\r\n */\r\n async addPLY(\r\n urlOrBuffer: string | ArrayBuffer,\r\n onProgress?: ProgressCallback,\r\n isLocalFile: boolean = false,\r\n ): Promise<number> {\r\n try {\r\n const isMobile = isMobileDevice();\r\n let buffer: ArrayBuffer;\r\n\r\n // 下载阶段 (0-50%)\r\n if (typeof urlOrBuffer === 'string') {\r\n buffer = await this.fetchWithProgress(urlOrBuffer, (downloadProgress) => {\r\n if (onProgress) {\r\n onProgress(downloadProgress * 0.5, 'download');\r\n }\r\n });\r\n } else {\r\n buffer = urlOrBuffer;\r\n if (onProgress && isLocalFile) {\r\n onProgress(50, 'download');\r\n }\r\n }\r\n\r\n // 解析阶段 (50-90%)\r\n const parseProgressCallback = (loaded: number, total: number) => {\r\n if (onProgress) {\r\n const parseProgress = (loaded / total) * 40;\r\n onProgress(50 + parseProgress, 'parse');\r\n }\r\n };\r\n\r\n let gsRenderer: IGSSplatRenderer;\r\n\r\n if (isMobile) {\r\n gsRenderer = new GSSplatRendererMobile(this.renderer, this.camera);\r\n this.useMobileRenderer = true;\r\n\r\n const compactData = await this.parsePLYBuffer(buffer, {\r\n maxSplats: Infinity,\r\n loadSH: false,\r\n onProgress: parseProgressCallback,\r\n });\r\n\r\n if (onProgress) onProgress(90, 'upload');\r\n gsRenderer.setCompactData(compactData);\r\n if (onProgress) onProgress(100, 'upload');\r\n\r\n this.sceneManager.setGSRenderer(gsRenderer);\r\n return compactData.count;\r\n } else {\r\n // 桌面端使用优化的 V2 渲染器\r\n gsRenderer = new GSSplatRenderer(this.renderer, this.camera);\r\n this.useMobileRenderer = false;\r\n\r\n const compactData = await this.parsePLYBuffer(buffer, {\r\n maxSplats: Infinity,\r\n loadSH: true,\r\n onProgress: parseProgressCallback,\r\n });\r\n\r\n if (onProgress) onProgress(90, 'upload');\r\n gsRenderer.setCompactData(compactData);\r\n if (onProgress) onProgress(100, 'upload');\r\n\r\n this.sceneManager.setGSRenderer(gsRenderer);\r\n return compactData.count;\r\n }\r\n } catch (error) {\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * 加载 Splat 文件\r\n */\r\n async addSplat(\r\n urlOrBuffer: string | ArrayBuffer,\r\n onProgress?: ProgressCallback,\r\n isLocalFile: boolean = false,\r\n ): Promise<number> {\r\n try {\r\n let buffer: ArrayBuffer;\r\n\r\n if (typeof urlOrBuffer === 'string') {\r\n buffer = await this.fetchWithProgress(urlOrBuffer, (downloadProgress) => {\r\n if (onProgress) {\r\n onProgress(downloadProgress * 0.5, 'download');\r\n }\r\n });\r\n } else {\r\n buffer = urlOrBuffer;\r\n if (onProgress && isLocalFile) {\r\n onProgress(50, 'download');\r\n }\r\n }\r\n\r\n if (onProgress) onProgress(50, 'parse');\r\n const splats = deserializeSplat(buffer);\r\n if (onProgress) onProgress(90, 'parse');\r\n\r\n if (onProgress) onProgress(90, 'upload');\r\n // 使用优化的 V2 渲染器\r\n const gsRenderer = new GSSplatRenderer(this.renderer, this.camera);\r\n gsRenderer.setData(splats);\r\n this.sceneManager.setGSRenderer(gsRenderer);\r\n this.useMobileRenderer = false;\r\n if (onProgress) onProgress(100, 'upload');\r\n\r\n return splats.length;\r\n } catch (error) {\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * 添加测试立方体\r\n */\r\n addTestCube(): void {\r\n const { mesh, material } = this.glbLoader.createTestCube();\r\n this.meshRenderer.addMesh(mesh, material);\r\n }\r\n\r\n /**\r\n * 添加测试球体\r\n */\r\n addTestSphere(): void {\r\n const { mesh, material } = this.glbLoader.createTestSphere();\r\n this.meshRenderer.addMesh(mesh, material);\r\n }\r\n\r\n // ============================================\r\n // 渲染循环\r\n // ============================================\r\n\r\n /**\r\n * 开始渲染循环\r\n */\r\n start(): void {\r\n if (this.isRunning) return;\r\n this.isRunning = true;\r\n this.animate();\r\n }\r\n\r\n /**\r\n * 停止渲染循环\r\n */\r\n stop(): void {\r\n this.isRunning = false;\r\n if (this.animationId) {\r\n cancelAnimationFrame(this.animationId);\r\n this.animationId = 0;\r\n }\r\n }\r\n\r\n private animate(): void {\r\n if (!this.isRunning) return;\r\n this.render();\r\n this.animationId = requestAnimationFrame(this.animate.bind(this));\r\n }\r\n\r\n private render(): void {\r\n this.camera.setAspect(this.renderer.getAspectRatio());\r\n this.camera.updateMatrix();\r\n\r\n const pass = this.renderer.beginFrame();\r\n\r\n // 渲染 3D Gaussian Splatting\r\n const gsRenderer = this.sceneManager.getGSRenderer();\r\n if (gsRenderer) {\r\n gsRenderer.render(pass);\r\n }\r\n\r\n // 渲染网格\r\n this.meshRenderer.render(pass);\r\n\r\n // 渲染 Gizmo\r\n this.gizmoManager.render(pass);\r\n\r\n this.renderer.endFrame();\r\n }\r\n\r\n private onResize(): void {\r\n this.camera.setAspect(this.renderer.getAspectRatio());\r\n this.camera.updateMatrix();\r\n }\r\n\r\n // ============================================\r\n // 场景管理(委托给 SceneManager)\r\n // ============================================\r\n\r\n getMeshCount(): number {\r\n return this.sceneManager.getMeshCount();\r\n }\r\n\r\n getMeshByIndex(index: number): Mesh | null {\r\n return this.sceneManager.getMeshByIndex(index);\r\n }\r\n\r\n getMeshRange(startIndex: number, count: number): Mesh[] {\r\n return this.sceneManager.getMeshRange(startIndex, count);\r\n }\r\n\r\n clearMeshes(): void {\r\n this.sceneManager.clearMeshes();\r\n }\r\n\r\n removeMeshByIndex(index: number): boolean {\r\n const result = this.sceneManager.removeMeshByIndex(index);\r\n return result;\r\n }\r\n\r\n getSplatCount(): number {\r\n return this.sceneManager.getSplatCount();\r\n }\r\n\r\n clearSplats(): void {\r\n this.sceneManager.clearSplats();\r\n this.useMobileRenderer = false;\r\n }\r\n\r\n // ============================================\r\n // Splat 变换(委托给 SceneManager)\r\n // ============================================\r\n\r\n setSplatPosition(x: number, y: number, z: number): void {\r\n this.sceneManager.setSplatPosition(x, y, z);\r\n }\r\n\r\n getSplatPosition(): [number, number, number] | null {\r\n return this.sceneManager.getSplatPosition();\r\n }\r\n\r\n setSplatRotation(x: number, y: number, z: number): void {\r\n this.sceneManager.setSplatRotation(x, y, z);\r\n }\r\n\r\n getSplatRotation(): [number, number, number] | null {\r\n return this.sceneManager.getSplatRotation();\r\n }\r\n\r\n setSplatScale(x: number, y: number, z: number): void {\r\n this.sceneManager.setSplatScale(x, y, z);\r\n }\r\n\r\n getSplatScale(): [number, number, number] | null {\r\n return this.sceneManager.getSplatScale();\r\n }\r\n\r\n // ============================================\r\n // SH 模式\r\n // ============================================\r\n\r\n setSHMode(mode: 0 | 1 | 2 | 3): void {\r\n this.sceneManager.setSHMode(mode);\r\n }\r\n\r\n getSHMode(): number {\r\n return this.sceneManager.getSHMode();\r\n }\r\n\r\n // ============================================\r\n // Bounding Box\r\n // ============================================\r\n\r\n getSplatBoundingBox(): BoundingBox | null {\r\n return this.sceneManager.getSplatBoundingBox();\r\n }\r\n\r\n getMeshRangeBoundingBox(startIndex: number, count: number): BoundingBox | null {\r\n return this.sceneManager.getMeshRangeBoundingBox(startIndex, count);\r\n }\r\n\r\n // ============================================\r\n // 材质颜色\r\n // ============================================\r\n\r\n getMeshColor(index: number): [number, number, number, number] | null {\r\n return this.sceneManager.getMeshColor(index);\r\n }\r\n\r\n setMeshColor(index: number, r: number, g: number, b: number, a: number = 1): boolean {\r\n return this.sceneManager.setMeshColor(index, r, g, b, a);\r\n }\r\n\r\n setMeshRangeColor(startIndex: number, count: number, r: number, g: number, b: number, a: number = 1): number {\r\n return this.sceneManager.setMeshRangeColor(startIndex, count, r, g, b, a);\r\n }\r\n\r\n // ============================================\r\n // 相机控制\r\n // ============================================\r\n\r\n frameCurrentModel(animate: boolean = true): boolean {\r\n const bbox = this.sceneManager.getSceneBoundingBox();\r\n if (!bbox) {\r\n return false;\r\n }\r\n\r\n this.controls.frameModel(bbox.center, bbox.radius, animate);\r\n return true;\r\n }\r\n\r\n // ============================================\r\n // Gizmo(委托给 GizmoManager)\r\n // ============================================\r\n\r\n getTransformGizmo() {\r\n return this.gizmoManager.getTransformGizmo();\r\n }\r\n\r\n getViewportGizmo() {\r\n return this.gizmoManager.getViewportGizmo();\r\n }\r\n\r\n getBoundingBoxRenderer() {\r\n return this.gizmoManager.getBoundingBoxRenderer();\r\n }\r\n\r\n setGizmoMode(mode: GizmoMode): void {\r\n this.gizmoManager.setGizmoMode(mode);\r\n }\r\n\r\n setGizmoTarget(object: TransformableObject | null): void {\r\n this.gizmoManager.setGizmoTarget(object);\r\n }\r\n\r\n setSelectionBoundingBox(box: BoundingBox | null): void {\r\n this.gizmoManager.setSelectionBoundingBox(box);\r\n }\r\n\r\n setSelectionBoundingBoxProvider(provider: BoundingBoxProvider | null): void {\r\n this.gizmoManager.setSelectionBoundingBoxProvider(provider);\r\n }\r\n\r\n clearSelectionBoundingBox(): void {\r\n this.gizmoManager.clearSelectionBoundingBox();\r\n }\r\n\r\n /**\r\n * 创建 Mesh 组的变换代理\r\n */\r\n createMeshGroupProxy(startIndex: number, count: number): MeshGroupProxy | null {\r\n const meshes = this.sceneManager.getMeshRange(startIndex, count);\r\n return this.gizmoManager.createMeshGroupProxy(meshes);\r\n }\r\n\r\n /**\r\n * 获取 Splat 的变换代理\r\n */\r\n getSplatTransformProxy(): SplatTransformProxy | null {\r\n const gsRenderer = this.sceneManager.getGSRenderer();\r\n if (!gsRenderer) return null;\r\n return this.gizmoManager.createSplatTransformProxy(gsRenderer);\r\n }\r\n\r\n /**\r\n * 创建 Splat 包围盒提供者\r\n */\r\n createSplatBoundingBoxProvider(): SplatBoundingBoxProvider | null {\r\n const gsRenderer = this.sceneManager.getGSRenderer();\r\n if (!gsRenderer) return null;\r\n return this.gizmoManager.createSplatBoundingBoxProvider(gsRenderer);\r\n }\r\n\r\n // ============================================\r\n // 子系统访问\r\n // ============================================\r\n\r\n getRenderer(): Renderer {\r\n return this.renderer;\r\n }\r\n\r\n getCamera(): Camera {\r\n return this.camera;\r\n }\r\n\r\n getControls(): OrbitControls {\r\n return this.controls;\r\n }\r\n\r\n getMeshRenderer(): MeshRenderer {\r\n return this.meshRenderer;\r\n }\r\n\r\n getGSRenderer(): GSSplatRenderer | undefined {\r\n const renderer = this.sceneManager.getGSRenderer();\r\n if (renderer && !this.useMobileRenderer) {\r\n return renderer as GSSplatRenderer;\r\n }\r\n return undefined;\r\n }\r\n\r\n getGSRendererMobile(): GSSplatRendererMobile | undefined {\r\n const renderer = this.sceneManager.getGSRenderer();\r\n if (renderer && this.useMobileRenderer) {\r\n return renderer as GSSplatRendererMobile;\r\n }\r\n return undefined;\r\n }\r\n\r\n isUsingMobileRenderer(): boolean {\r\n return this.useMobileRenderer;\r\n }\r\n\r\n // ============================================\r\n // 内部方法\r\n // ============================================\r\n\r\n private async fetchWithProgress(\r\n url: string,\r\n onProgress?: (progress: number) => void\r\n ): Promise<ArrayBuffer> {\r\n const response = await fetch(url);\r\n if (!response.ok) {\r\n throw new Error(`无法加载文件: ${url}`);\r\n }\r\n\r\n const contentLength = response.headers.get('content-length');\r\n if (!contentLength || !response.body) {\r\n const buffer = await response.arrayBuffer();\r\n if (onProgress) onProgress(100);\r\n return buffer;\r\n }\r\n\r\n const total = parseInt(contentLength, 10);\r\n const reader = response.body.getReader();\r\n const chunks: Uint8Array[] = [];\r\n let loaded = 0;\r\n\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n\r\n chunks.push(value);\r\n loaded += value.length;\r\n\r\n if (onProgress) {\r\n onProgress((loaded / total) * 100);\r\n }\r\n }\r\n\r\n const buffer = new ArrayBuffer(loaded);\r\n const view = new Uint8Array(buffer);\r\n let offset = 0;\r\n for (const chunk of chunks) {\r\n view.set(chunk, offset);\r\n offset += chunk.length;\r\n }\r\n\r\n return buffer;\r\n }\r\n\r\n private async parsePLYBuffer(\r\n buffer: ArrayBuffer,\r\n options: { maxSplats?: number; loadSH?: boolean; onProgress?: (loaded: number, total: number) => void }\r\n ): Promise<import('./gs/PLYLoaderMobile').CompactSplatData> {\r\n const { parsePLYBuffer } = await import('./gs/PLYLoaderMobile');\r\n return parsePLYBuffer(buffer, options);\r\n }\r\n\r\n /**\r\n * 销毁应用及所有资源\r\n */\r\n destroy(): void {\r\n this.stop();\r\n window.removeEventListener(\"resize\", this.boundOnResize);\r\n\r\n this.sceneManager.destroy();\r\n this.gizmoManager.destroy();\r\n\r\n if (this.meshRenderer) {\r\n this.meshRenderer.destroy();\r\n }\r\n\r\n if (this.controls) {\r\n this.controls.destroy();\r\n }\r\n\r\n if (this.renderer) {\r\n this.renderer.destroy();\r\n }\r\n }\r\n}\r\n"],"names":["SHMode","computeBoundingBox","TYPE_SIZES","parseHeader","validatePLYMagic","extractHeader","readProperty","sigmoid","SH_C0","WORKGROUP_SIZE","generateCullingShaderCode","GizmoMode","plane","dist","buffer","parsePLYBuffer"],"mappings":"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AC;AAC3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAC3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE;AAG3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;AAC3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAC3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE;AAG3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;AAC3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAC3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE;AAG3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;AAC3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAC3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE;AAG3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;AAC3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAC3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE;AAG3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;AAC3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAC3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE;AAG3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;AAC3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAC3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE;AAG3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;AAC3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAC3D,YAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC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AACF;ACz6BA,MAAM;AAAA;AAAA,EAA+B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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"}
|
|
1
|
+
{"version":3,"file":"3dgs-lib.js","sources":["../src/types/material.ts","../src/types/splat.ts","../src/utils/device.ts","../src/utils/geometry.ts","../src/utils/texture.ts","../src/core/Renderer.ts","../src/core/Camera.ts","../src/core/OrbitControls.ts","../src/core/gizmo/ViewportGizmo.ts","../src/core/BoundingBoxRenderer.ts","../src/mesh/Mesh.ts","../src/mesh/MeshRenderer.ts","../src/loaders/GLBLoader.ts","../src/loaders/OBJParser.ts","../src/loaders/MTLParser.ts","../src/loaders/OBJLoader.ts","../src/gs/PLYLoader.ts","../src/gs/PLYLoaderMobile.ts","../src/gs/SplatLoader.ts","../node_modules/fflate/esm/browser.js","../src/gs/SOGLoader.ts","../src/gs/GSSplatSorter.ts","../src/gs/GSSplatRenderer.ts","../src/gs/TextureCompressor.ts","../src/gs/GSSplatSorterMobile.ts","../src/gs/GSSplatRendererMobile.ts","../src/scene/SceneManager.ts","../src/scene/proxies/SplatTransformProxy.ts","../src/scene/proxies/MeshGroupProxy.ts","../src/scene/proxies/SplatBoundingBoxProvider.ts","../src/core/math/Vec3.ts","../src/core/math/Ray.ts","../src/core/math/Quat.ts","../src/core/math/Mat4.ts","../src/core/gizmo/Shape.ts","../src/core/gizmo/ArrowShape.ts","../src/core/gizmo/PlaneShape.ts","../src/core/gizmo/SphereShape.ts","../src/core/gizmo/ArcShape.ts","../src/core/gizmo/BoxLineShape.ts","../src/core/gizmo/TransformGizmo.ts","../src/interaction/GizmoManager.ts","../src/interaction/HotspotManager.ts","../src/App.ts"],"sourcesContent":["/**\r\n * 统一的材质类型定义\r\n */\r\n\r\n/**\r\n * 材质数据接口\r\n * 用于 GLB/OBJ 等模型的材质\r\n */\r\nexport interface MaterialData {\r\n /** 基础颜色因子 [r, g, b, a] */\r\n baseColorFactor: [number, number, number, number];\r\n /** 基础颜色纹理 */\r\n baseColorTexture: GPUTexture | null;\r\n /** 金属度因子 */\r\n metallicFactor: number;\r\n /** 粗糙度因子 */\r\n roughnessFactor: number;\r\n /** 是否双面渲染 */\r\n doubleSided: boolean;\r\n}\r\n\r\n/**\r\n * 默认材质\r\n */\r\nexport const DEFAULT_MATERIAL: Readonly<MaterialData> = {\r\n baseColorFactor: [1, 1, 1, 1],\r\n baseColorTexture: null,\r\n metallicFactor: 0,\r\n roughnessFactor: 0.5,\r\n doubleSided: false,\r\n};\r\n\r\n/**\r\n * OBJ 默认材质(双面渲染)\r\n */\r\nexport const DEFAULT_OBJ_MATERIAL: Readonly<MaterialData> = {\r\n baseColorFactor: [1, 1, 1, 1],\r\n baseColorTexture: null,\r\n metallicFactor: 0,\r\n roughnessFactor: 0.5,\r\n doubleSided: true,\r\n};\r\n","/**\r\n * 3D Gaussian Splatting 相关类型定义\r\n */\r\n\r\n/**\r\n * SH 模式枚举 - 球谐函数级别\r\n */\r\nexport enum SHMode {\r\n L0 = 0, // 仅 DC 颜色(最快)\r\n L1 = 1, // DC + L1 SH\r\n L2 = 2, // DC + L1 + L2 SH\r\n L3 = 3, // 完整 SH(最高质量)\r\n}\r\n\r\n/**\r\n * 渲染器能力描述\r\n */\r\nexport interface RendererCapabilities {\r\n /** 支持的最高 SH 模式 */\r\n maxSHMode: SHMode;\r\n /** 是否支持原始 SplatCPU 数据 */\r\n supportsRawData: boolean;\r\n /** 是否为移动端优化版本 */\r\n isMobileOptimized: boolean;\r\n /** 最大支持的 splat 数量(0 表示无限制) */\r\n maxSplatCount: number;\r\n}\r\n","/**\r\n * 设备检测工具函数\r\n */\r\n\r\n/**\r\n * 检测是否为移动设备\r\n * 综合考虑 UA、触摸支持、屏幕尺寸\r\n */\r\nexport function isMobileDevice(): boolean {\r\n if (typeof navigator === \"undefined\" || typeof window === \"undefined\") {\r\n return false;\r\n }\r\n\r\n const ua = navigator.userAgent || navigator.vendor || (window as any).opera || \"\";\r\n \r\n // UA 检测\r\n const isMobileUA = /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(\r\n ua.toLowerCase()\r\n );\r\n \r\n // 触摸支持检测\r\n const hasTouch = \"ontouchstart\" in window || navigator.maxTouchPoints > 0;\r\n \r\n // 屏幕尺寸检测\r\n const isSmallScreen = window.innerWidth <= 768;\r\n \r\n // iPad as Mac 检测(Safari on iPad)\r\n const isIPadAsMac = navigator.platform === \"MacIntel\" && navigator.maxTouchPoints > 1;\r\n \r\n return isMobileUA || isIPadAsMac || (hasTouch && isSmallScreen);\r\n}\r\n\r\n/**\r\n * 获取推荐的设备像素比\r\n * 移动端限制 DPI 以避免性能问题\r\n */\r\nexport function getRecommendedDPR(): number {\r\n const isMobile = isMobileDevice();\r\n const maxDpr = isMobile ? 1.5 : 3;\r\n return Math.min(window.devicePixelRatio || 1, maxDpr);\r\n}\r\n\r\n/**\r\n * 检测 WebGPU 支持\r\n */\r\nexport function isWebGPUSupported(): boolean {\r\n return typeof navigator !== \"undefined\" && \"gpu\" in navigator;\r\n}\r\n","/**\r\n * 几何计算工具函数\r\n */\r\n\r\nimport type { BoundingBox, Vec3Tuple } from '../types';\r\n\r\n/**\r\n * 从顶点位置数组计算包围盒\r\n * @param positions 顶点位置数组 [x0, y0, z0, x1, y1, z1, ...]\r\n * @returns 包围盒信息\r\n */\r\nexport function computeBoundingBox(\r\n positions: ArrayLike<number>\r\n): BoundingBox {\r\n if (positions.length < 3) {\r\n return {\r\n min: [0, 0, 0],\r\n max: [0, 0, 0],\r\n center: [0, 0, 0],\r\n radius: 0,\r\n };\r\n }\r\n\r\n // 初始化为第一个点\r\n const min: Vec3Tuple = [positions[0], positions[1], positions[2]];\r\n const max: Vec3Tuple = [positions[0], positions[1], positions[2]];\r\n\r\n // 遍历所有顶点\r\n for (let i = 3; i < positions.length; i += 3) {\r\n const x = positions[i];\r\n const y = positions[i + 1];\r\n const z = positions[i + 2];\r\n\r\n min[0] = Math.min(min[0], x);\r\n min[1] = Math.min(min[1], y);\r\n min[2] = Math.min(min[2], z);\r\n max[0] = Math.max(max[0], x);\r\n max[1] = Math.max(max[1], y);\r\n max[2] = Math.max(max[2], z);\r\n }\r\n\r\n // 计算中心点\r\n const center: Vec3Tuple = [\r\n (min[0] + max[0]) / 2,\r\n (min[1] + max[1]) / 2,\r\n (min[2] + max[2]) / 2,\r\n ];\r\n\r\n // 计算 bounding sphere 半径\r\n const dx = max[0] - min[0];\r\n const dy = max[1] - min[1];\r\n const dz = max[2] - min[2];\r\n const radius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min, max, center, radius };\r\n}\r\n\r\n/**\r\n * 合并多个包围盒\r\n * @param boxes 包围盒数组\r\n * @returns 合并后的包围盒,如果输入为空则返回 null\r\n */\r\nexport function mergeBoundingBoxes(boxes: BoundingBox[]): BoundingBox | null {\r\n if (boxes.length === 0) return null;\r\n\r\n let combinedMin: Vec3Tuple = [...boxes[0].min];\r\n let combinedMax: Vec3Tuple = [...boxes[0].max];\r\n\r\n for (let i = 1; i < boxes.length; i++) {\r\n const box = boxes[i];\r\n combinedMin[0] = Math.min(combinedMin[0], box.min[0]);\r\n combinedMin[1] = Math.min(combinedMin[1], box.min[1]);\r\n combinedMin[2] = Math.min(combinedMin[2], box.min[2]);\r\n combinedMax[0] = Math.max(combinedMax[0], box.max[0]);\r\n combinedMax[1] = Math.max(combinedMax[1], box.max[1]);\r\n combinedMax[2] = Math.max(combinedMax[2], box.max[2]);\r\n }\r\n\r\n const center: Vec3Tuple = [\r\n (combinedMin[0] + combinedMax[0]) / 2,\r\n (combinedMin[1] + combinedMax[1]) / 2,\r\n (combinedMin[2] + combinedMax[2]) / 2,\r\n ];\r\n\r\n const dx = combinedMax[0] - combinedMin[0];\r\n const dy = combinedMax[1] - combinedMin[1];\r\n const dz = combinedMax[2] - combinedMin[2];\r\n const radius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min: combinedMin, max: combinedMax, center, radius };\r\n}\r\n\r\n/**\r\n * 从 min/max 计算完整的包围盒信息\r\n */\r\nexport function createBoundingBoxFromMinMax(\r\n min: Vec3Tuple,\r\n max: Vec3Tuple\r\n): BoundingBox {\r\n const center: Vec3Tuple = [\r\n (min[0] + max[0]) / 2,\r\n (min[1] + max[1]) / 2,\r\n (min[2] + max[2]) / 2,\r\n ];\r\n\r\n const dx = max[0] - min[0];\r\n const dy = max[1] - min[1];\r\n const dz = max[2] - min[2];\r\n const radius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min, max, center, radius };\r\n}\r\n\r\n/**\r\n * 变换包围盒的 8 个角点并计算新的 AABB\r\n * @param bbox 原始包围盒\r\n * @param modelMatrix 4x4 变换矩阵(列主序)\r\n */\r\nexport function transformBoundingBox(\r\n bbox: BoundingBox,\r\n modelMatrix: Float32Array\r\n): BoundingBox {\r\n // 获取 8 个角点\r\n const corners: Vec3Tuple[] = [\r\n [bbox.min[0], bbox.min[1], bbox.min[2]],\r\n [bbox.max[0], bbox.min[1], bbox.min[2]],\r\n [bbox.min[0], bbox.max[1], bbox.min[2]],\r\n [bbox.max[0], bbox.max[1], bbox.min[2]],\r\n [bbox.min[0], bbox.min[1], bbox.max[2]],\r\n [bbox.max[0], bbox.min[1], bbox.max[2]],\r\n [bbox.min[0], bbox.max[1], bbox.max[2]],\r\n [bbox.max[0], bbox.max[1], bbox.max[2]],\r\n ];\r\n\r\n const m = modelMatrix;\r\n let minX = Infinity, minY = Infinity, minZ = Infinity;\r\n let maxX = -Infinity, maxY = -Infinity, maxZ = -Infinity;\r\n\r\n for (const [x, y, z] of corners) {\r\n // 应用变换(列主序矩阵)\r\n const tx = m[0] * x + m[4] * y + m[8] * z + m[12];\r\n const ty = m[1] * x + m[5] * y + m[9] * z + m[13];\r\n const tz = m[2] * x + m[6] * y + m[10] * z + m[14];\r\n\r\n minX = Math.min(minX, tx);\r\n minY = Math.min(minY, ty);\r\n minZ = Math.min(minZ, tz);\r\n maxX = Math.max(maxX, tx);\r\n maxY = Math.max(maxY, ty);\r\n maxZ = Math.max(maxZ, tz);\r\n }\r\n\r\n return createBoundingBoxFromMinMax(\r\n [minX, minY, minZ],\r\n [maxX, maxY, maxZ]\r\n );\r\n}\r\n","/**\r\n * 纹理加载工具函数\r\n */\r\n\r\n/**\r\n * 从 URL 加载纹理\r\n * @param device GPU 设备\r\n * @param url 纹理 URL\r\n * @returns GPU 纹理或 null(加载失败时)\r\n */\r\nexport async function loadTextureFromURL(\r\n device: GPUDevice,\r\n url: string\r\n): Promise<GPUTexture | null> {\r\n try {\r\n const response = await fetch(url);\r\n if (!response.ok) {\r\n return null;\r\n }\r\n\r\n const blob = await response.blob();\r\n return loadTextureFromBlob(device, blob);\r\n } catch (error) {\r\n console.warn(`Failed to load texture from URL: ${url}`, error);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * 从 Blob 加载纹理\r\n * @param device GPU 设备\r\n * @param blob 图片 Blob\r\n * @returns GPU 纹理或 null(加载失败时)\r\n */\r\nexport async function loadTextureFromBlob(\r\n device: GPUDevice,\r\n blob: Blob\r\n): Promise<GPUTexture | null> {\r\n try {\r\n const imageBitmap = await createImageBitmap(blob);\r\n return createTextureFromImageBitmap(device, imageBitmap);\r\n } catch (error) {\r\n console.warn(`Failed to create texture from blob`, error);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * 从 ArrayBuffer 加载纹理\r\n * @param device GPU 设备\r\n * @param buffer 图片数据\r\n * @param mimeType MIME 类型\r\n * @returns GPU 纹理或 null(加载失败时)\r\n */\r\nexport async function loadTextureFromBuffer(\r\n device: GPUDevice,\r\n buffer: ArrayBuffer | Uint8Array,\r\n mimeType: string = 'image/png'\r\n): Promise<GPUTexture | null> {\r\n try {\r\n // 确保是 Uint8Array 类型用于 Blob 构造\r\n const uint8Array = buffer instanceof Uint8Array \r\n ? buffer \r\n : new Uint8Array(buffer);\r\n // 使用类型断言解决 SharedArrayBuffer 兼容性问题\r\n const blob = new Blob([uint8Array as BlobPart], { type: mimeType });\r\n return loadTextureFromBlob(device, blob);\r\n } catch (error) {\r\n console.warn(`Failed to create texture from buffer`, error);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * 从 ImageBitmap 创建 GPU 纹理\r\n * @param device GPU 设备\r\n * @param imageBitmap ImageBitmap 对象\r\n * @returns GPU 纹理\r\n */\r\nexport function createTextureFromImageBitmap(\r\n device: GPUDevice,\r\n imageBitmap: ImageBitmap\r\n): GPUTexture {\r\n const texture = device.createTexture({\r\n size: [imageBitmap.width, imageBitmap.height, 1],\r\n format: 'rgba8unorm',\r\n usage:\r\n GPUTextureUsage.TEXTURE_BINDING |\r\n GPUTextureUsage.COPY_DST |\r\n GPUTextureUsage.RENDER_ATTACHMENT,\r\n });\r\n\r\n device.queue.copyExternalImageToTexture(\r\n { source: imageBitmap },\r\n { texture },\r\n [imageBitmap.width, imageBitmap.height]\r\n );\r\n\r\n return texture;\r\n}\r\n\r\n/**\r\n * 纹理缓存管理器\r\n */\r\nexport class TextureCache {\r\n private cache: Map<string, GPUTexture> = new Map();\r\n private device: GPUDevice;\r\n\r\n constructor(device: GPUDevice) {\r\n this.device = device;\r\n }\r\n\r\n /**\r\n * 获取或加载纹理\r\n */\r\n async getOrLoad(url: string): Promise<GPUTexture | null> {\r\n if (this.cache.has(url)) {\r\n return this.cache.get(url)!;\r\n }\r\n\r\n const texture = await loadTextureFromURL(this.device, url);\r\n if (texture) {\r\n this.cache.set(url, texture);\r\n }\r\n return texture;\r\n }\r\n\r\n /**\r\n * 检查缓存中是否存在\r\n */\r\n has(url: string): boolean {\r\n return this.cache.has(url);\r\n }\r\n\r\n /**\r\n * 从缓存获取\r\n */\r\n get(url: string): GPUTexture | undefined {\r\n return this.cache.get(url);\r\n }\r\n\r\n /**\r\n * 添加到缓存\r\n */\r\n set(url: string, texture: GPUTexture): void {\r\n this.cache.set(url, texture);\r\n }\r\n\r\n /**\r\n * 清空缓存\r\n */\r\n clear(): void {\r\n this.cache.clear();\r\n }\r\n\r\n /**\r\n * 销毁所有纹理并清空缓存\r\n */\r\n destroy(): void {\r\n for (const texture of this.cache.values()) {\r\n texture.destroy();\r\n }\r\n this.cache.clear();\r\n }\r\n}\r\n","import { isMobileDevice, getRecommendedDPR } from \"../utils\";\r\n\r\n/**\r\n * Renderer - WebGPU 初始化 + 帧提交\r\n * 只负责 WebGPU 设备管理和渲染通道\r\n */\r\nexport class Renderer {\r\n private canvas: HTMLCanvasElement;\r\n private _device!: GPUDevice;\r\n private _context!: GPUCanvasContext;\r\n private _format!: GPUTextureFormat;\r\n private _depthTexture!: GPUTexture;\r\n private _depthTextureView!: GPUTextureView;\r\n \r\n private commandEncoder!: GPUCommandEncoder;\r\n private renderPassEncoder!: GPURenderPassEncoder;\r\n\r\n // ResizeObserver 引用(用于清理)\r\n private resizeObserver: ResizeObserver | null = null;\r\n\r\n // 背景颜色\r\n private _clearColor: GPUColorDict = { r: 0.15, g: 0.15, b: 0.15, a: 1.0 };\r\n\r\n constructor(canvas: HTMLCanvasElement) {\r\n this.canvas = canvas;\r\n }\r\n\r\n /**\r\n * 设置背景颜色\r\n */\r\n setClearColor(r: number, g: number, b: number, a: number = 1.0): void {\r\n this._clearColor = { r, g, b, a };\r\n }\r\n\r\n /**\r\n * 通过十六进制设置背景颜色\r\n */\r\n setClearColorHex(hex: string): void {\r\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\r\n if (result) {\r\n this._clearColor = {\r\n r: parseInt(result[1], 16) / 255,\r\n g: parseInt(result[2], 16) / 255,\r\n b: parseInt(result[3], 16) / 255,\r\n a: 1.0,\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * 获取背景颜色(十六进制)\r\n */\r\n getClearColorHex(): string {\r\n const r = Math.round(this._clearColor.r * 255).toString(16).padStart(2, '0');\r\n const g = Math.round(this._clearColor.g * 255).toString(16).padStart(2, '0');\r\n const b = Math.round(this._clearColor.b * 255).toString(16).padStart(2, '0');\r\n return `#${r}${g}${b}`;\r\n }\r\n\r\n get device(): GPUDevice {\r\n return this._device;\r\n }\r\n\r\n get context(): GPUCanvasContext {\r\n return this._context;\r\n }\r\n\r\n get format(): GPUTextureFormat {\r\n return this._format;\r\n }\r\n\r\n get depthFormat(): GPUTextureFormat {\r\n return 'depth24plus';\r\n }\r\n\r\n /**\r\n * 获取渲染宽度(像素)\r\n */\r\n get width(): number {\r\n return this.canvas.width;\r\n }\r\n\r\n /**\r\n * 获取渲染高度(像素)\r\n */\r\n get height(): number {\r\n return this.canvas.height;\r\n }\r\n\r\n /**\r\n * 初始化 WebGPU\r\n */\r\n async init(): Promise<void> {\r\n // 检查 WebGPU 支持\r\n if (!navigator.gpu) {\r\n throw new Error('WebGPU 不受支持');\r\n }\r\n\r\n // 获取适配器\r\n const adapter = await navigator.gpu.requestAdapter({\r\n powerPreference: 'high-performance',\r\n });\r\n if (!adapter) {\r\n throw new Error('无法获取 GPU 适配器');\r\n }\r\n\r\n // 获取设备,请求更高的缓冲区大小限制以支持大型模型\r\n const adapterLimits = adapter.limits;\r\n this._device = await adapter.requestDevice({\r\n requiredLimits: {\r\n maxBufferSize: adapterLimits.maxBufferSize,\r\n maxStorageBufferBindingSize: adapterLimits.maxStorageBufferBindingSize,\r\n },\r\n });\r\n this._device.lost.then((info) => {\r\n // GPU 设备丢失(静默处理)\r\n });\r\n\r\n // 配置 canvas 上下文\r\n this._context = this.canvas.getContext('webgpu') as GPUCanvasContext;\r\n if (!this._context) {\r\n throw new Error('无法获取 WebGPU 上下文');\r\n }\r\n\r\n this._format = navigator.gpu.getPreferredCanvasFormat();\r\n this._context.configure({\r\n device: this._device,\r\n format: this._format,\r\n alphaMode: 'premultiplied',\r\n colorSpace: 'srgb',\r\n });\r\n\r\n // 创建深度纹理\r\n this.createDepthTexture();\r\n\r\n // 监听 canvas 大小变化\r\n this.setupResizeObserver();\r\n }\r\n\r\n /**\r\n * 创建深度纹理\r\n */\r\n private createDepthTexture(): void {\r\n if (this._depthTexture) {\r\n this._depthTexture.destroy();\r\n }\r\n\r\n this._depthTexture = this._device.createTexture({\r\n size: {\r\n width: this.canvas.width,\r\n height: this.canvas.height,\r\n },\r\n format: this.depthFormat,\r\n usage: GPUTextureUsage.RENDER_ATTACHMENT,\r\n });\r\n this._depthTextureView = this._depthTexture.createView();\r\n }\r\n\r\n /**\r\n * 设置 resize 监听\r\n */\r\n private setupResizeObserver(): void {\r\n this.resizeObserver = new ResizeObserver((entries) => {\r\n for (const entry of entries) {\r\n const { width, height } = entry.contentRect;\r\n \r\n // 使用工具函数获取推荐的 DPR\r\n const dpr = getRecommendedDPR();\r\n \r\n this.canvas.width = Math.floor(width * dpr);\r\n this.canvas.height = Math.floor(height * dpr);\r\n \r\n this.createDepthTexture();\r\n }\r\n });\r\n this.resizeObserver.observe(this.canvas);\r\n }\r\n\r\n /**\r\n * 销毁渲染器资源\r\n */\r\n destroy(): void {\r\n // 断开 ResizeObserver\r\n if (this.resizeObserver) {\r\n this.resizeObserver.disconnect();\r\n this.resizeObserver = null;\r\n }\r\n\r\n // 销毁深度纹理\r\n if (this._depthTexture) {\r\n this._depthTexture.destroy();\r\n }\r\n }\r\n\r\n /**\r\n * 开始帧 - 创建命令编码器和渲染通道\r\n */\r\n beginFrame(): GPURenderPassEncoder {\r\n const colorTexture = this._context.getCurrentTexture();\r\n const colorView = colorTexture.createView();\r\n\r\n this.commandEncoder = this._device.createCommandEncoder();\r\n \r\n this.renderPassEncoder = this.commandEncoder.beginRenderPass({\r\n colorAttachments: [\r\n {\r\n view: colorView,\r\n clearValue: this._clearColor,\r\n loadOp: 'clear',\r\n storeOp: 'store',\r\n },\r\n ],\r\n depthStencilAttachment: {\r\n view: this._depthTextureView,\r\n depthClearValue: 1.0,\r\n depthLoadOp: 'clear',\r\n depthStoreOp: 'store',\r\n },\r\n });\r\n\r\n return this.renderPassEncoder;\r\n }\r\n\r\n /**\r\n * 结束帧 - 提交命令\r\n */\r\n endFrame(): void {\r\n this.renderPassEncoder.end();\r\n this._device.queue.submit([this.commandEncoder.finish()]);\r\n }\r\n\r\n /**\r\n * 获取 canvas 宽高比\r\n */\r\n getAspectRatio(): number {\r\n return this.canvas.width / this.canvas.height;\r\n }\r\n}\r\n","/**\r\n * Camera - 相机矩阵计算\r\n * 只负责视图矩阵和投影矩阵\r\n */\r\nexport class Camera {\r\n // 相机参数\r\n position: Float32Array = new Float32Array([0, 0, 5]);\r\n target: Float32Array = new Float32Array([0, 0, 0]);\r\n up: Float32Array = new Float32Array([0, 1, 0]);\r\n\r\n // 投影参数\r\n fov: number = Math.PI / 4; // 45度\r\n aspect: number = 1;\r\n near: number = 0.01;\r\n far: number = 9000;\r\n\r\n // 矩阵\r\n viewMatrix: Float32Array = new Float32Array(16);\r\n projectionMatrix: Float32Array = new Float32Array(16);\r\n viewProjectionMatrix: Float32Array = new Float32Array(16);\r\n\r\n constructor() {\r\n this.updateMatrix();\r\n }\r\n\r\n /**\r\n * 设置宽高比\r\n */\r\n setAspect(aspect: number): void {\r\n this.aspect = aspect;\r\n }\r\n\r\n /**\r\n * 更新视图和投影矩阵\r\n */\r\n updateMatrix(): void {\r\n this.updateViewMatrix();\r\n this.updateProjectionMatrix();\r\n this.multiplyMatrices(\r\n this.viewProjectionMatrix,\r\n this.projectionMatrix,\r\n this.viewMatrix,\r\n );\r\n }\r\n\r\n /**\r\n * 计算视图矩阵 (lookAt)\r\n */\r\n private updateViewMatrix(): void {\r\n const eye = this.position;\r\n const target = this.target;\r\n const up = this.up;\r\n\r\n // 计算相机坐标系\r\n const zAxis = this.normalize(this.subtract(eye, target));\r\n const xAxis = this.normalize(this.cross(up, zAxis));\r\n const yAxis = this.cross(zAxis, xAxis);\r\n\r\n // 构建视图矩阵 (列主序)\r\n this.viewMatrix[0] = xAxis[0];\r\n this.viewMatrix[1] = yAxis[0];\r\n this.viewMatrix[2] = zAxis[0];\r\n this.viewMatrix[3] = 0;\r\n\r\n this.viewMatrix[4] = xAxis[1];\r\n this.viewMatrix[5] = yAxis[1];\r\n this.viewMatrix[6] = zAxis[1];\r\n this.viewMatrix[7] = 0;\r\n\r\n this.viewMatrix[8] = xAxis[2];\r\n this.viewMatrix[9] = yAxis[2];\r\n this.viewMatrix[10] = zAxis[2];\r\n this.viewMatrix[11] = 0;\r\n\r\n this.viewMatrix[12] = -this.dot(xAxis, eye);\r\n this.viewMatrix[13] = -this.dot(yAxis, eye);\r\n this.viewMatrix[14] = -this.dot(zAxis, eye);\r\n this.viewMatrix[15] = 1;\r\n }\r\n\r\n /**\r\n * 计算投影矩阵 (透视投影)\r\n */\r\n private updateProjectionMatrix(): void {\r\n const f = 1.0 / Math.tan(this.fov / 2);\r\n const rangeInv = 1 / (this.near - this.far);\r\n\r\n // 列主序\r\n this.projectionMatrix[0] = f / this.aspect;\r\n this.projectionMatrix[1] = 0;\r\n this.projectionMatrix[2] = 0;\r\n this.projectionMatrix[3] = 0;\r\n\r\n this.projectionMatrix[4] = 0;\r\n this.projectionMatrix[5] = f;\r\n this.projectionMatrix[6] = 0;\r\n this.projectionMatrix[7] = 0;\r\n\r\n this.projectionMatrix[8] = 0;\r\n this.projectionMatrix[9] = 0;\r\n this.projectionMatrix[10] = (this.near + this.far) * rangeInv;\r\n this.projectionMatrix[11] = -1;\r\n\r\n this.projectionMatrix[12] = 0;\r\n this.projectionMatrix[13] = 0;\r\n this.projectionMatrix[14] = this.near * this.far * rangeInv * 2;\r\n this.projectionMatrix[15] = 0;\r\n }\r\n\r\n // ========== 向量/矩阵工具函数 ==========\r\n\r\n private subtract(a: Float32Array, b: Float32Array): Float32Array {\r\n return new Float32Array([a[0] - b[0], a[1] - b[1], a[2] - b[2]]);\r\n }\r\n\r\n private cross(a: Float32Array, b: Float32Array): Float32Array {\r\n return new Float32Array([\r\n a[1] * b[2] - a[2] * b[1],\r\n a[2] * b[0] - a[0] * b[2],\r\n a[0] * b[1] - a[1] * b[0],\r\n ]);\r\n }\r\n\r\n private dot(a: Float32Array, b: Float32Array): number {\r\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\r\n }\r\n\r\n private normalize(v: Float32Array): Float32Array {\r\n const len = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);\r\n if (len < 1e-10) return new Float32Array([0, 0, 1]); // 返回默认方向,避免除零\r\n return new Float32Array([v[0] / len, v[1] / len, v[2] / len]);\r\n }\r\n\r\n private multiplyMatrices(\r\n out: Float32Array,\r\n a: Float32Array,\r\n b: Float32Array,\r\n ): void {\r\n for (let i = 0; i < 4; i++) {\r\n for (let j = 0; j < 4; j++) {\r\n out[i * 4 + j] =\r\n a[j] * b[i * 4] +\r\n a[j + 4] * b[i * 4 + 1] +\r\n a[j + 8] * b[i * 4 + 2] +\r\n a[j + 12] * b[i * 4 + 3];\r\n }\r\n }\r\n }\r\n}\r\n","import { Camera } from \"./Camera\";\r\n\r\n/**\r\n * OrbitControls - 轨道控制器\r\n * 支持阻尼惯性、屏幕空间平移、中键拖拽、指数缩放\r\n */\r\nexport class OrbitControls {\r\n private camera: Camera;\r\n private canvas: HTMLCanvasElement;\r\n\r\n // 球坐标参数\r\n distance: number = 5;\r\n theta: number = 0;\r\n phi: number = Math.PI / 4;\r\n\r\n // 限制\r\n minDistance: number = 0.001;\r\n maxDistance: number = Infinity;\r\n minPhi: number = 0.01;\r\n maxPhi: number = Math.PI - 0.01;\r\n\r\n // 灵敏度\r\n rotateSpeed: number = 0.005;\r\n zoomSpeed: number = 0.001;\r\n panSpeed: number = 0.005;\r\n\r\n // 移动端触摸灵敏度\r\n touchZoomSpeed: number = 0.01;\r\n touchPanSpeed: number = 0.003;\r\n\r\n // 阻尼(值越大越灵敏,越小越丝滑;0.12 约 5 帧消化 50% 增量)\r\n enableDamping: boolean = true;\r\n dampingFactor: number = 0.12;\r\n\r\n // 状态\r\n private isDragging: boolean = false;\r\n private lastX: number = 0;\r\n private lastY: number = 0;\r\n\r\n // 阻尼速度\r\n private velocityTheta: number = 0;\r\n private velocityPhi: number = 0;\r\n private velocityDistance: number = 0;\r\n private velocityPanX: number = 0;\r\n private velocityPanY: number = 0;\r\n private velocityPanZ: number = 0;\r\n\r\n // 触摸手势状态\r\n private touchMode: \"none\" | \"rotate\" | \"zoom-pan\" = \"none\";\r\n private lastTouchDistance: number = 0;\r\n private lastTouchCenter: { x: number; y: number } = { x: 0, y: 0 };\r\n\r\n // 启用/禁用\r\n enabled: boolean = true;\r\n\r\n // 绑定的事件处理函数(用于移除监听器)\r\n private boundOnMouseDown: (e: MouseEvent) => void;\r\n private boundOnMouseMove: (e: MouseEvent) => void;\r\n private boundOnMouseUp: (e: MouseEvent) => void;\r\n private boundOnWheel: (e: WheelEvent) => void;\r\n private boundOnTouchStart: (e: TouchEvent) => void;\r\n private boundOnTouchMove: (e: TouchEvent) => void;\r\n private boundOnTouchEnd: (e: TouchEvent) => void;\r\n private boundOnContextMenu: (e: Event) => void;\r\n\r\n constructor(camera: Camera, canvas: HTMLCanvasElement) {\r\n this.camera = camera;\r\n this.canvas = canvas;\r\n\r\n this.boundOnMouseDown = this.onMouseDown.bind(this);\r\n this.boundOnMouseMove = this.onMouseMove.bind(this);\r\n this.boundOnMouseUp = this.onMouseUp.bind(this);\r\n this.boundOnWheel = this.onWheel.bind(this);\r\n this.boundOnTouchStart = this.onTouchStart.bind(this);\r\n this.boundOnTouchMove = this.onTouchMove.bind(this);\r\n this.boundOnTouchEnd = this.onTouchEnd.bind(this);\r\n this.boundOnContextMenu = (e: Event) => e.preventDefault();\r\n\r\n this.setupEventListeners();\r\n this.applySpherical();\r\n }\r\n\r\n private setupEventListeners(): void {\r\n this.canvas.addEventListener(\"mousedown\", this.boundOnMouseDown);\r\n this.canvas.addEventListener(\"mousemove\", this.boundOnMouseMove);\r\n this.canvas.addEventListener(\"mouseup\", this.boundOnMouseUp);\r\n this.canvas.addEventListener(\"mouseleave\", this.boundOnMouseUp);\r\n this.canvas.addEventListener(\"wheel\", this.boundOnWheel, {\r\n passive: false,\r\n });\r\n\r\n this.canvas.addEventListener(\"touchstart\", this.boundOnTouchStart, {\r\n passive: false,\r\n });\r\n this.canvas.addEventListener(\"touchmove\", this.boundOnTouchMove, {\r\n passive: false,\r\n });\r\n this.canvas.addEventListener(\"touchend\", this.boundOnTouchEnd);\r\n\r\n this.canvas.addEventListener(\"contextmenu\", this.boundOnContextMenu);\r\n }\r\n\r\n private removeEventListeners(): void {\r\n this.canvas.removeEventListener(\"mousedown\", this.boundOnMouseDown);\r\n this.canvas.removeEventListener(\"mousemove\", this.boundOnMouseMove);\r\n this.canvas.removeEventListener(\"mouseup\", this.boundOnMouseUp);\r\n this.canvas.removeEventListener(\"mouseleave\", this.boundOnMouseUp);\r\n this.canvas.removeEventListener(\"wheel\", this.boundOnWheel);\r\n this.canvas.removeEventListener(\"touchstart\", this.boundOnTouchStart);\r\n this.canvas.removeEventListener(\"touchmove\", this.boundOnTouchMove);\r\n this.canvas.removeEventListener(\"touchend\", this.boundOnTouchEnd);\r\n this.canvas.removeEventListener(\"contextmenu\", this.boundOnContextMenu);\r\n }\r\n\r\n destroy(): void {\r\n this.removeEventListeners();\r\n }\r\n\r\n /**\r\n * 从视图矩阵提取相机的 right 和 up 向量,用于屏幕空间平移\r\n */\r\n private getCameraAxes(): {\r\n right: [number, number, number];\r\n up: [number, number, number];\r\n } {\r\n const m = this.camera.viewMatrix;\r\n return {\r\n right: [m[0], m[4], m[8]],\r\n up: [m[1], m[5], m[9]],\r\n };\r\n }\r\n\r\n /**\r\n * 屏幕空间平移:将屏幕 delta 映射到相机 right/up 方向\r\n */\r\n private panByScreenDelta(deltaX: number, deltaY: number): void {\r\n const { right, up } = this.getCameraAxes();\r\n const scale = this.panSpeed * this.distance;\r\n const dx = -deltaX * scale;\r\n const dy = deltaY * scale;\r\n\r\n if (this.enableDamping) {\r\n this.velocityPanX += dx * right[0] + dy * up[0];\r\n this.velocityPanY += dx * right[1] + dy * up[1];\r\n this.velocityPanZ += dx * right[2] + dy * up[2];\r\n } else {\r\n this.camera.target[0] += dx * right[0] + dy * up[0];\r\n this.camera.target[1] += dx * right[1] + dy * up[1];\r\n this.camera.target[2] += dx * right[2] + dy * up[2];\r\n }\r\n }\r\n\r\n private onMouseDown(e: MouseEvent): void {\r\n if (!this.enabled) return;\r\n this.isDragging = true;\r\n this.lastX = e.clientX;\r\n this.lastY = e.clientY;\r\n }\r\n\r\n private onMouseMove(e: MouseEvent): void {\r\n if (!this.enabled || !this.isDragging) return;\r\n\r\n const deltaX = e.clientX - this.lastX;\r\n const deltaY = e.clientY - this.lastY;\r\n this.lastX = e.clientX;\r\n this.lastY = e.clientY;\r\n\r\n // 左键旋转\r\n if (e.buttons === 1) {\r\n if (this.enableDamping) {\r\n this.velocityTheta += -deltaX * this.rotateSpeed;\r\n this.velocityPhi += -deltaY * this.rotateSpeed;\r\n } else {\r\n this.theta -= deltaX * this.rotateSpeed;\r\n this.phi -= deltaY * this.rotateSpeed;\r\n this.phi = Math.max(this.minPhi, Math.min(this.maxPhi, this.phi));\r\n }\r\n }\r\n // 右键或中键平移\r\n else if (e.buttons === 2 || e.buttons === 4) {\r\n this.panByScreenDelta(deltaX, deltaY);\r\n }\r\n\r\n if (!this.enableDamping) {\r\n this.applySpherical();\r\n }\r\n }\r\n\r\n private onMouseUp(): void {\r\n this.isDragging = false;\r\n }\r\n\r\n private onWheel(e: WheelEvent): void {\r\n e.preventDefault();\r\n if (!this.enabled) return;\r\n\r\n const zoomDelta = e.deltaY * this.zoomSpeed;\r\n if (this.enableDamping) {\r\n this.velocityDistance += zoomDelta;\r\n } else {\r\n this.distance *= Math.exp(zoomDelta);\r\n this.distance = Math.max(\r\n this.minDistance,\r\n Math.min(this.maxDistance, this.distance),\r\n );\r\n this.applySpherical();\r\n }\r\n }\r\n\r\n private onTouchStart(e: TouchEvent): void {\r\n e.preventDefault();\r\n if (!this.enabled) return;\r\n\r\n if (e.touches.length === 1) {\r\n this.touchMode = \"rotate\";\r\n this.isDragging = true;\r\n this.lastX = e.touches[0].clientX;\r\n this.lastY = e.touches[0].clientY;\r\n } else if (e.touches.length === 2) {\r\n this.touchMode = \"zoom-pan\";\r\n this.isDragging = true;\r\n this.lastTouchDistance = this.getTouchDistance(e.touches);\r\n this.lastTouchCenter = this.getTouchCenter(e.touches);\r\n }\r\n }\r\n\r\n private onTouchMove(e: TouchEvent): void {\r\n e.preventDefault();\r\n if (!this.enabled || !this.isDragging) return;\r\n\r\n if (e.touches.length === 1 && this.touchMode === \"rotate\") {\r\n const deltaX = e.touches[0].clientX - this.lastX;\r\n const deltaY = e.touches[0].clientY - this.lastY;\r\n this.lastX = e.touches[0].clientX;\r\n this.lastY = e.touches[0].clientY;\r\n\r\n if (this.enableDamping) {\r\n this.velocityTheta += -deltaX * this.rotateSpeed;\r\n this.velocityPhi += -deltaY * this.rotateSpeed;\r\n } else {\r\n this.theta -= deltaX * this.rotateSpeed;\r\n this.phi -= deltaY * this.rotateSpeed;\r\n this.phi = Math.max(this.minPhi, Math.min(this.maxPhi, this.phi));\r\n this.applySpherical();\r\n }\r\n } else if (e.touches.length === 2) {\r\n const currentDistance = this.getTouchDistance(e.touches);\r\n const currentCenter = this.getTouchCenter(e.touches);\r\n\r\n // 缩放\r\n if (this.lastTouchDistance > 0) {\r\n const ratio = currentDistance / this.lastTouchDistance;\r\n const zoomDelta = -Math.log(ratio) / (this.touchZoomSpeed * 100);\r\n if (this.enableDamping) {\r\n this.velocityDistance += zoomDelta;\r\n } else {\r\n this.distance *= Math.exp(zoomDelta);\r\n this.distance = Math.max(\r\n this.minDistance,\r\n Math.min(this.maxDistance, this.distance),\r\n );\r\n }\r\n }\r\n\r\n // 平移\r\n const deltaX = currentCenter.x - this.lastTouchCenter.x;\r\n const deltaY = currentCenter.y - this.lastTouchCenter.y;\r\n\r\n const { right, up } = this.getCameraAxes();\r\n const scale = this.touchPanSpeed * this.distance;\r\n const dx = -deltaX * scale;\r\n const dy = deltaY * scale;\r\n\r\n if (this.enableDamping) {\r\n this.velocityPanX += dx * right[0] + dy * up[0];\r\n this.velocityPanY += dx * right[1] + dy * up[1];\r\n this.velocityPanZ += dx * right[2] + dy * up[2];\r\n } else {\r\n this.camera.target[0] += dx * right[0] + dy * up[0];\r\n this.camera.target[1] += dx * right[1] + dy * up[1];\r\n this.camera.target[2] += dx * right[2] + dy * up[2];\r\n }\r\n\r\n this.lastTouchDistance = currentDistance;\r\n this.lastTouchCenter = currentCenter;\r\n\r\n if (!this.enableDamping) {\r\n this.applySpherical();\r\n }\r\n }\r\n }\r\n\r\n private onTouchEnd(e: TouchEvent): void {\r\n if (e.touches.length === 0) {\r\n this.isDragging = false;\r\n this.touchMode = \"none\";\r\n this.lastTouchDistance = 0;\r\n } else if (e.touches.length === 1) {\r\n this.touchMode = \"rotate\";\r\n this.lastX = e.touches[0].clientX;\r\n this.lastY = e.touches[0].clientY;\r\n }\r\n }\r\n\r\n private getTouchDistance(touches: TouchList): number {\r\n const dx = touches[0].clientX - touches[1].clientX;\r\n const dy = touches[0].clientY - touches[1].clientY;\r\n return Math.sqrt(dx * dx + dy * dy);\r\n }\r\n\r\n private getTouchCenter(touches: TouchList): { x: number; y: number } {\r\n return {\r\n x: (touches[0].clientX + touches[1].clientX) / 2,\r\n y: (touches[0].clientY + touches[1].clientY) / 2,\r\n };\r\n }\r\n\r\n /**\r\n * 将球坐标写入相机位置(内部方法,不处理阻尼)\r\n */\r\n private applySpherical(): void {\r\n const sinPhi = Math.sin(this.phi);\r\n const cosPhi = Math.cos(this.phi);\r\n const sinTheta = Math.sin(this.theta);\r\n const cosTheta = Math.cos(this.theta);\r\n\r\n this.camera.position[0] =\r\n this.camera.target[0] + this.distance * sinPhi * sinTheta;\r\n this.camera.position[1] = this.camera.target[1] + this.distance * cosPhi;\r\n this.camera.position[2] =\r\n this.camera.target[2] + this.distance * sinPhi * cosTheta;\r\n\r\n this.camera.updateMatrix();\r\n }\r\n\r\n /**\r\n * 每帧调用:应用阻尼衰减并更新相机\r\n * 在渲染循环中调用此方法以获得平滑惯性效果\r\n */\r\n update(): void {\r\n if (this.enableDamping) {\r\n const EPS = 1e-6;\r\n const f = this.dampingFactor;\r\n\r\n // 部分应用:每帧只消费 dampingFactor 比例的待处理增量\r\n // 总位移收敛到原始增量(不放大),同时提供平滑惯性\r\n this.theta += this.velocityTheta * f;\r\n this.phi += this.velocityPhi * f;\r\n this.phi = Math.max(this.minPhi, Math.min(this.maxPhi, this.phi));\r\n\r\n this.distance *= Math.exp(this.velocityDistance * f);\r\n this.distance = Math.max(\r\n this.minDistance,\r\n Math.min(this.maxDistance, this.distance),\r\n );\r\n\r\n this.camera.target[0] += this.velocityPanX * f;\r\n this.camera.target[1] += this.velocityPanY * f;\r\n this.camera.target[2] += this.velocityPanZ * f;\r\n\r\n const decay = 1 - f;\r\n this.velocityTheta *= decay;\r\n this.velocityPhi *= decay;\r\n this.velocityDistance *= decay;\r\n this.velocityPanX *= decay;\r\n this.velocityPanY *= decay;\r\n this.velocityPanZ *= decay;\r\n\r\n if (Math.abs(this.velocityTheta) < EPS) this.velocityTheta = 0;\r\n if (Math.abs(this.velocityPhi) < EPS) this.velocityPhi = 0;\r\n if (Math.abs(this.velocityDistance) < EPS) this.velocityDistance = 0;\r\n if (Math.abs(this.velocityPanX) < EPS) this.velocityPanX = 0;\r\n if (Math.abs(this.velocityPanY) < EPS) this.velocityPanY = 0;\r\n if (Math.abs(this.velocityPanZ) < EPS) this.velocityPanZ = 0;\r\n }\r\n\r\n this.applySpherical();\r\n }\r\n\r\n setViewAxis(axis: string, positive: boolean, animate: boolean = true): void {\r\n this.clearVelocity();\r\n\r\n let targetTheta = this.theta;\r\n let targetPhi = this.phi;\r\n\r\n switch (axis) {\r\n case \"X\":\r\n targetTheta = positive ? Math.PI / 2 : -Math.PI / 2;\r\n targetPhi = Math.PI / 2;\r\n break;\r\n case \"Y\":\r\n targetPhi = positive ? 0.01 : Math.PI - 0.01;\r\n break;\r\n case \"Z\":\r\n targetTheta = positive ? 0 : Math.PI;\r\n targetPhi = Math.PI / 2;\r\n break;\r\n }\r\n\r\n if (animate) {\r\n this.animateToView(targetTheta, targetPhi);\r\n } else {\r\n this.theta = targetTheta;\r\n this.phi = targetPhi;\r\n this.applySpherical();\r\n }\r\n }\r\n\r\n private animateToView(targetTheta: number, targetPhi: number): void {\r\n const startTheta = this.theta;\r\n const startPhi = this.phi;\r\n const duration = 300;\r\n const startTime = performance.now();\r\n\r\n let deltaTheta = targetTheta - startTheta;\r\n while (deltaTheta > Math.PI) deltaTheta -= Math.PI * 2;\r\n while (deltaTheta < -Math.PI) deltaTheta += Math.PI * 2;\r\n\r\n const animate = (currentTime: number) => {\r\n const elapsed = currentTime - startTime;\r\n const progress = Math.min(elapsed / duration, 1);\r\n const eased = 1 - Math.pow(1 - progress, 3);\r\n\r\n this.theta = startTheta + deltaTheta * eased;\r\n this.phi = startPhi + (targetPhi - startPhi) * eased;\r\n this.applySpherical();\r\n\r\n if (progress < 1) {\r\n requestAnimationFrame(animate);\r\n }\r\n };\r\n\r\n requestAnimationFrame(animate);\r\n }\r\n\r\n setTarget(x: number, y: number, z: number): void {\r\n this.clearVelocity();\r\n this.camera.target[0] = x;\r\n this.camera.target[1] = y;\r\n this.camera.target[2] = z;\r\n this.applySpherical();\r\n }\r\n\r\n getTarget(): [number, number, number] {\r\n return [\r\n this.camera.target[0],\r\n this.camera.target[1],\r\n this.camera.target[2],\r\n ];\r\n }\r\n\r\n frameModel(\r\n center: [number, number, number],\r\n radius: number,\r\n animate: boolean = true,\r\n ): void {\r\n this.clearVelocity();\r\n\r\n const fovRad = this.camera.fov;\r\n const halfFov = fovRad / 2;\r\n const marginFactor = 1.5;\r\n const targetDistance = (radius / Math.tan(halfFov)) * marginFactor;\r\n const clampedDistance = Math.max(this.minDistance, targetDistance);\r\n\r\n if (animate) {\r\n this.animateToFrame(center, clampedDistance);\r\n } else {\r\n this.camera.target[0] = center[0];\r\n this.camera.target[1] = center[1];\r\n this.camera.target[2] = center[2];\r\n this.distance = clampedDistance;\r\n this.applySpherical();\r\n }\r\n }\r\n\r\n private animateToFrame(\r\n targetCenter: [number, number, number],\r\n targetDistance: number,\r\n ): void {\r\n const startTarget = [\r\n this.camera.target[0],\r\n this.camera.target[1],\r\n this.camera.target[2],\r\n ];\r\n const startDistance = this.distance;\r\n const duration = 400;\r\n const startTime = performance.now();\r\n\r\n const animate = (currentTime: number) => {\r\n const elapsed = currentTime - startTime;\r\n const progress = Math.min(elapsed / duration, 1);\r\n const eased = 1 - Math.pow(1 - progress, 3);\r\n\r\n this.camera.target[0] =\r\n startTarget[0] + (targetCenter[0] - startTarget[0]) * eased;\r\n this.camera.target[1] =\r\n startTarget[1] + (targetCenter[1] - startTarget[1]) * eased;\r\n this.camera.target[2] =\r\n startTarget[2] + (targetCenter[2] - startTarget[2]) * eased;\r\n\r\n this.distance = startDistance + (targetDistance - startDistance) * eased;\r\n\r\n this.applySpherical();\r\n\r\n if (progress < 1) {\r\n requestAnimationFrame(animate);\r\n }\r\n };\r\n\r\n requestAnimationFrame(animate);\r\n }\r\n\r\n clearVelocity(): void {\r\n this.velocityTheta = 0;\r\n this.velocityPhi = 0;\r\n this.velocityDistance = 0;\r\n this.velocityPanX = 0;\r\n this.velocityPanY = 0;\r\n this.velocityPanZ = 0;\r\n }\r\n}\r\n","import { Camera } from \"../Camera\";\r\nimport { Renderer } from \"../Renderer\";\r\n\r\n/**\r\n * Gizmo 轴配置\r\n */\r\ninterface AxisConfig {\r\n direction: [number, number, number];\r\n color: [number, number, number];\r\n label: string;\r\n}\r\n\r\n/**\r\n * WGSL Shader - Gizmo 渲染\r\n */\r\nconst gizmoShaderCode = /* wgsl */ `\r\nstruct Uniforms {\r\n viewMatrix: mat4x4<f32>,\r\n projMatrix: mat4x4<f32>,\r\n}\r\n\r\n@group(0) @binding(0) var<uniform> uniforms: Uniforms;\r\n\r\nstruct VertexInput {\r\n @location(0) position: vec3<f32>,\r\n @location(1) color: vec3<f32>,\r\n}\r\n\r\nstruct VertexOutput {\r\n @builtin(position) position: vec4<f32>,\r\n @location(0) color: vec3<f32>,\r\n}\r\n\r\n@vertex\r\nfn vs_main(input: VertexInput) -> VertexOutput {\r\n var output: VertexOutput;\r\n let worldPos = vec4<f32>(input.position, 1.0);\r\n output.position = uniforms.projMatrix * uniforms.viewMatrix * worldPos;\r\n output.color = input.color;\r\n return output;\r\n}\r\n\r\n@fragment\r\nfn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {\r\n return vec4<f32>(input.color, 1.0);\r\n}\r\n`;\r\n\r\n/**\r\n * ViewportGizmo - 视口坐标轴指示器\r\n * 在画布右上角显示当前相机朝向\r\n */\r\nexport class ViewportGizmo {\r\n private renderer: Renderer;\r\n private camera: Camera;\r\n private canvas: HTMLCanvasElement;\r\n\r\n // 渲染资源\r\n private pipeline!: GPURenderPipeline;\r\n private uniformBuffer!: GPUBuffer;\r\n private bindGroup!: GPUBindGroup;\r\n private vertexBuffer!: GPUBuffer;\r\n private indexBuffer!: GPUBuffer;\r\n private vertexCount: number = 0;\r\n private indexCount: number = 0;\r\n\r\n // Gizmo 配置\r\n private size: number = 200; // Gizmo 尺寸(像素)\r\n private margin: number = 20; // 边距\r\n\r\n // Gizmo 投影矩阵\r\n private projMatrix: Float32Array = new Float32Array(16);\r\n private viewMatrix: Float32Array = new Float32Array(16);\r\n\r\n // 轴配置\r\n private axes: AxisConfig[] = [\r\n { direction: [1, 0, 0], color: [0.9, 0.2, 0.2], label: \"X\" }, // 红色 X\r\n { direction: [0, 1, 0], color: [0.2, 0.9, 0.2], label: \"Y\" }, // 绿色 Y\r\n { direction: [0, 0, 1], color: [0.2, 0.4, 0.9], label: \"Z\" }, // 蓝色 Z\r\n ];\r\n\r\n // 交互回调\r\n private onAxisClick?: (axis: string, positive: boolean) => void;\r\n\r\n constructor(renderer: Renderer, camera: Camera, canvas: HTMLCanvasElement) {\r\n this.renderer = renderer;\r\n this.camera = camera;\r\n this.canvas = canvas;\r\n\r\n this.createPipeline();\r\n this.createGeometry();\r\n this.createUniformBuffer();\r\n this.setupOrthoProjection();\r\n }\r\n\r\n /**\r\n * 设置轴点击回调\r\n */\r\n setOnAxisClick(callback: (axis: string, positive: boolean) => void): void {\r\n this.onAxisClick = callback;\r\n }\r\n\r\n /**\r\n * 创建渲染管线\r\n */\r\n private createPipeline(): void {\r\n const device = this.renderer.device;\r\n\r\n const shaderModule = device.createShaderModule({\r\n code: gizmoShaderCode,\r\n });\r\n\r\n const bindGroupLayout = device.createBindGroupLayout({\r\n entries: [\r\n {\r\n binding: 0,\r\n visibility: GPUShaderStage.VERTEX,\r\n buffer: { type: \"uniform\" },\r\n },\r\n ],\r\n });\r\n\r\n const pipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [bindGroupLayout],\r\n });\r\n\r\n // 顶点布局: position(3) + color(3)\r\n const vertexBufferLayout: GPUVertexBufferLayout = {\r\n arrayStride: 24,\r\n attributes: [\r\n { shaderLocation: 0, offset: 0, format: \"float32x3\" },\r\n { shaderLocation: 1, offset: 12, format: \"float32x3\" },\r\n ],\r\n };\r\n\r\n this.pipeline = device.createRenderPipeline({\r\n layout: pipelineLayout,\r\n vertex: {\r\n module: shaderModule,\r\n entryPoint: \"vs_main\",\r\n buffers: [vertexBufferLayout],\r\n },\r\n fragment: {\r\n module: shaderModule,\r\n entryPoint: \"fs_main\",\r\n targets: [{ format: this.renderer.format }],\r\n },\r\n primitive: {\r\n topology: \"triangle-list\",\r\n cullMode: \"none\",\r\n },\r\n depthStencil: {\r\n format: this.renderer.depthFormat,\r\n depthWriteEnabled: true,\r\n depthCompare: \"less\",\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * 创建 Gizmo 几何体(三个轴 + 箭头)\r\n */\r\n private createGeometry(): void {\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n let vertexOffset = 0;\r\n\r\n const axisLength = 0.8;\r\n const axisRadius = 0.04;\r\n const coneLength = 0.25;\r\n const coneRadius = 0.1;\r\n const segments = 12;\r\n\r\n for (const axis of this.axes) {\r\n const [dx, dy, dz] = axis.direction;\r\n const [r, g, b] = axis.color;\r\n\r\n // 创建轴的圆柱体\r\n const cylResult = this.createCylinder(\r\n [0, 0, 0],\r\n [dx * axisLength, dy * axisLength, dz * axisLength],\r\n axisRadius,\r\n segments,\r\n [r, g, b],\r\n vertexOffset,\r\n );\r\n vertices.push(...cylResult.vertices);\r\n indices.push(...cylResult.indices);\r\n vertexOffset += cylResult.vertexCount;\r\n\r\n // 创建箭头圆锥\r\n const coneStart: [number, number, number] = [\r\n dx * axisLength,\r\n dy * axisLength,\r\n dz * axisLength,\r\n ];\r\n const coneEnd: [number, number, number] = [\r\n dx * (axisLength + coneLength),\r\n dy * (axisLength + coneLength),\r\n dz * (axisLength + coneLength),\r\n ];\r\n const coneResult = this.createCone(\r\n coneStart,\r\n coneEnd,\r\n coneRadius,\r\n segments,\r\n [r, g, b],\r\n vertexOffset,\r\n );\r\n vertices.push(...coneResult.vertices);\r\n indices.push(...coneResult.indices);\r\n vertexOffset += coneResult.vertexCount;\r\n\r\n // 创建负方向的小球\r\n const sphereResult = this.createSphere(\r\n [-dx * 0.15, -dy * 0.15, -dz * 0.15],\r\n 0.08,\r\n 8,\r\n [r * 0.6, g * 0.6, b * 0.6],\r\n vertexOffset,\r\n );\r\n vertices.push(...sphereResult.vertices);\r\n indices.push(...sphereResult.indices);\r\n vertexOffset += sphereResult.vertexCount;\r\n }\r\n\r\n // 创建中心球\r\n const centerResult = this.createSphere(\r\n [0, 0, 0],\r\n 0.1,\r\n 12,\r\n [0.5, 0.5, 0.5],\r\n vertexOffset,\r\n );\r\n vertices.push(...centerResult.vertices);\r\n indices.push(...centerResult.indices);\r\n\r\n this.vertexCount = vertices.length / 6;\r\n this.indexCount = indices.length;\r\n\r\n const vertexData = new Float32Array(vertices);\r\n const indexData = new Uint16Array(indices);\r\n\r\n const device = this.renderer.device;\r\n\r\n this.vertexBuffer = device.createBuffer({\r\n size: vertexData.byteLength,\r\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\r\n });\r\n device.queue.writeBuffer(this.vertexBuffer, 0, vertexData);\r\n\r\n this.indexBuffer = device.createBuffer({\r\n size: indexData.byteLength,\r\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\r\n });\r\n device.queue.writeBuffer(this.indexBuffer, 0, indexData);\r\n }\r\n\r\n /**\r\n * 创建圆柱体几何\r\n */\r\n private createCylinder(\r\n start: [number, number, number],\r\n end: [number, number, number],\r\n radius: number,\r\n segments: number,\r\n color: [number, number, number],\r\n indexOffset: number,\r\n ): { vertices: number[]; indices: number[]; vertexCount: number } {\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n\r\n // 计算方向和长度\r\n const dx = end[0] - start[0];\r\n const dy = end[1] - start[1];\r\n const dz = end[2] - start[2];\r\n const length = Math.sqrt(dx * dx + dy * dy + dz * dz);\r\n\r\n // 计算旋转矩阵\r\n const dir = [dx / length, dy / length, dz / length];\r\n const up = Math.abs(dir[1]) < 0.99 ? [0, 1, 0] : [1, 0, 0];\r\n const right = this.cross(\r\n up as [number, number, number],\r\n dir as [number, number, number],\r\n );\r\n this.normalize(right);\r\n const actualUp = this.cross(dir as [number, number, number], right);\r\n\r\n // 生成圆柱顶点\r\n for (let i = 0; i <= segments; i++) {\r\n const angle = (i / segments) * Math.PI * 2;\r\n const cos = Math.cos(angle);\r\n const sin = Math.sin(angle);\r\n\r\n // 底面\r\n const nx0 = right[0] * cos + actualUp[0] * sin;\r\n const ny0 = right[1] * cos + actualUp[1] * sin;\r\n const nz0 = right[2] * cos + actualUp[2] * sin;\r\n vertices.push(\r\n start[0] + nx0 * radius,\r\n start[1] + ny0 * radius,\r\n start[2] + nz0 * radius,\r\n color[0],\r\n color[1],\r\n color[2],\r\n );\r\n\r\n // 顶面\r\n vertices.push(\r\n end[0] + nx0 * radius,\r\n end[1] + ny0 * radius,\r\n end[2] + nz0 * radius,\r\n color[0],\r\n color[1],\r\n color[2],\r\n );\r\n }\r\n\r\n // 生成索引\r\n for (let i = 0; i < segments; i++) {\r\n const i0 = indexOffset + i * 2;\r\n const i1 = indexOffset + i * 2 + 1;\r\n const i2 = indexOffset + (i + 1) * 2;\r\n const i3 = indexOffset + (i + 1) * 2 + 1;\r\n indices.push(i0, i1, i2, i2, i1, i3);\r\n }\r\n\r\n return { vertices, indices, vertexCount: (segments + 1) * 2 };\r\n }\r\n\r\n /**\r\n * 创建圆锥几何\r\n */\r\n private createCone(\r\n base: [number, number, number],\r\n tip: [number, number, number],\r\n radius: number,\r\n segments: number,\r\n color: [number, number, number],\r\n indexOffset: number,\r\n ): { vertices: number[]; indices: number[]; vertexCount: number } {\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n\r\n const dx = tip[0] - base[0];\r\n const dy = tip[1] - base[1];\r\n const dz = tip[2] - base[2];\r\n const length = Math.sqrt(dx * dx + dy * dy + dz * dz);\r\n const dir = [dx / length, dy / length, dz / length];\r\n\r\n const up = Math.abs(dir[1]) < 0.99 ? [0, 1, 0] : [1, 0, 0];\r\n const right = this.cross(\r\n up as [number, number, number],\r\n dir as [number, number, number],\r\n );\r\n this.normalize(right);\r\n const actualUp = this.cross(dir as [number, number, number], right);\r\n\r\n // 尖端\r\n vertices.push(tip[0], tip[1], tip[2], color[0], color[1], color[2]);\r\n\r\n // 底面圆环\r\n for (let i = 0; i <= segments; i++) {\r\n const angle = (i / segments) * Math.PI * 2;\r\n const cos = Math.cos(angle);\r\n const sin = Math.sin(angle);\r\n const nx = right[0] * cos + actualUp[0] * sin;\r\n const ny = right[1] * cos + actualUp[1] * sin;\r\n const nz = right[2] * cos + actualUp[2] * sin;\r\n vertices.push(\r\n base[0] + nx * radius,\r\n base[1] + ny * radius,\r\n base[2] + nz * radius,\r\n color[0],\r\n color[1],\r\n color[2],\r\n );\r\n }\r\n\r\n // 索引(侧面)\r\n for (let i = 0; i < segments; i++) {\r\n indices.push(indexOffset, indexOffset + i + 1, indexOffset + i + 2);\r\n }\r\n\r\n // 底面中心\r\n const baseCenterIdx = indexOffset + segments + 2;\r\n vertices.push(\r\n base[0],\r\n base[1],\r\n base[2],\r\n color[0] * 0.7,\r\n color[1] * 0.7,\r\n color[2] * 0.7,\r\n );\r\n\r\n // 底面索引\r\n for (let i = 0; i < segments; i++) {\r\n indices.push(baseCenterIdx, indexOffset + i + 2, indexOffset + i + 1);\r\n }\r\n\r\n return { vertices, indices, vertexCount: segments + 3 };\r\n }\r\n\r\n /**\r\n * 创建球体几何\r\n */\r\n private createSphere(\r\n center: [number, number, number],\r\n radius: number,\r\n segments: number,\r\n color: [number, number, number],\r\n indexOffset: number,\r\n ): { vertices: number[]; indices: number[]; vertexCount: number } {\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n const rings = segments / 2;\r\n\r\n for (let ring = 0; ring <= rings; ring++) {\r\n const phi = (ring / rings) * Math.PI;\r\n const sinPhi = Math.sin(phi);\r\n const cosPhi = Math.cos(phi);\r\n\r\n for (let seg = 0; seg <= segments; seg++) {\r\n const theta = (seg / segments) * Math.PI * 2;\r\n const x = center[0] + radius * sinPhi * Math.cos(theta);\r\n const y = center[1] + radius * cosPhi;\r\n const z = center[2] + radius * sinPhi * Math.sin(theta);\r\n vertices.push(x, y, z, color[0], color[1], color[2]);\r\n }\r\n }\r\n\r\n for (let ring = 0; ring < rings; ring++) {\r\n for (let seg = 0; seg < segments; seg++) {\r\n const current = indexOffset + ring * (segments + 1) + seg;\r\n const next = current + segments + 1;\r\n indices.push(current, next, current + 1);\r\n indices.push(current + 1, next, next + 1);\r\n }\r\n }\r\n\r\n return { vertices, indices, vertexCount: (rings + 1) * (segments + 1) };\r\n }\r\n\r\n /**\r\n * 创建 uniform buffer\r\n */\r\n private createUniformBuffer(): void {\r\n const device = this.renderer.device;\r\n\r\n // viewMatrix(64) + projMatrix(64) = 128 bytes\r\n this.uniformBuffer = device.createBuffer({\r\n size: 128,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n\r\n const bindGroupLayout = this.pipeline.getBindGroupLayout(0);\r\n this.bindGroup = device.createBindGroup({\r\n layout: bindGroupLayout,\r\n entries: [{ binding: 0, resource: { buffer: this.uniformBuffer } }],\r\n });\r\n }\r\n\r\n /**\r\n * 设置正交投影矩阵\r\n */\r\n private setupOrthoProjection(): void {\r\n const s = 1.5; // 场景大小\r\n // 正交投影矩阵\r\n this.projMatrix[0] = 1 / s;\r\n this.projMatrix[5] = 1 / s;\r\n this.projMatrix[10] = -1 / 10;\r\n this.projMatrix[14] = 0;\r\n this.projMatrix[15] = 1;\r\n }\r\n\r\n /**\r\n * 更新 Gizmo 视图矩阵(从相机提取旋转部分)\r\n */\r\n private updateViewMatrix(): void {\r\n // 从相机视图矩阵提取旋转部分(去除平移)\r\n const camView = this.camera.viewMatrix;\r\n\r\n // 复制旋转部分\r\n this.viewMatrix[0] = camView[0];\r\n this.viewMatrix[1] = camView[1];\r\n this.viewMatrix[2] = camView[2];\r\n this.viewMatrix[3] = 0;\r\n\r\n this.viewMatrix[4] = camView[4];\r\n this.viewMatrix[5] = camView[5];\r\n this.viewMatrix[6] = camView[6];\r\n this.viewMatrix[7] = 0;\r\n\r\n this.viewMatrix[8] = camView[8];\r\n this.viewMatrix[9] = camView[9];\r\n this.viewMatrix[10] = camView[10];\r\n this.viewMatrix[11] = 0;\r\n\r\n // 设置固定的观察距离\r\n this.viewMatrix[12] = 0;\r\n this.viewMatrix[13] = 0;\r\n this.viewMatrix[14] = -3;\r\n this.viewMatrix[15] = 1;\r\n }\r\n\r\n /**\r\n * 渲染 Gizmo\r\n */\r\n render(pass: GPURenderPassEncoder): void {\r\n // 更新视图矩阵\r\n this.updateViewMatrix();\r\n\r\n // 计算 viewport 位置(右上角)\r\n const dpr = window.devicePixelRatio || 1;\r\n let gizmoSize = Math.floor(this.size * dpr);\r\n const marginX = Math.floor(this.margin * dpr);\r\n const marginY = Math.floor(this.margin * dpr);\r\n\r\n // 确保 Gizmo 不会超出 canvas 范围\r\n const maxSize = Math.min(\r\n this.canvas.width - marginX * 2,\r\n this.canvas.height - marginY * 2,\r\n );\r\n if (maxSize < 50) {\r\n // canvas 太小,跳过渲染\r\n return;\r\n }\r\n gizmoSize = Math.min(gizmoSize, maxSize);\r\n\r\n const x = Math.max(0, this.canvas.width - gizmoSize - marginX);\r\n const y = marginY;\r\n\r\n // 设置 viewport\r\n pass.setViewport(x, y, gizmoSize, gizmoSize, 0, 1);\r\n pass.setScissorRect(x, y, gizmoSize, gizmoSize);\r\n\r\n // 更新 uniform\r\n this.renderer.device.queue.writeBuffer(\r\n this.uniformBuffer,\r\n 0,\r\n new Float32Array(this.viewMatrix),\r\n );\r\n this.renderer.device.queue.writeBuffer(\r\n this.uniformBuffer,\r\n 64,\r\n new Float32Array(this.projMatrix),\r\n );\r\n\r\n // 绘制\r\n pass.setPipeline(this.pipeline);\r\n pass.setBindGroup(0, this.bindGroup);\r\n pass.setVertexBuffer(0, this.vertexBuffer);\r\n pass.setIndexBuffer(this.indexBuffer, \"uint16\");\r\n pass.drawIndexed(this.indexCount);\r\n\r\n // 恢复全屏 viewport\r\n pass.setViewport(0, 0, this.canvas.width, this.canvas.height, 0, 1);\r\n pass.setScissorRect(0, 0, this.canvas.width, this.canvas.height);\r\n }\r\n\r\n /**\r\n * 处理点击事件,检测是否点击了某个轴\r\n */\r\n handleClick(clientX: number, clientY: number): boolean {\r\n const rect = this.canvas.getBoundingClientRect();\r\n const dpr = window.devicePixelRatio || 1;\r\n\r\n // 计算 Gizmo 区域\r\n const gizmoSize = this.size;\r\n const marginX = this.margin;\r\n const marginY = this.margin;\r\n const gizmoLeft = rect.right - gizmoSize - marginX;\r\n const gizmoTop = rect.top + marginY;\r\n const gizmoRight = gizmoLeft + gizmoSize;\r\n const gizmoBottom = gizmoTop + gizmoSize;\r\n\r\n // 检查是否在 Gizmo 区域内\r\n if (\r\n clientX < gizmoLeft ||\r\n clientX > gizmoRight ||\r\n clientY < gizmoTop ||\r\n clientY > gizmoBottom\r\n ) {\r\n return false;\r\n }\r\n\r\n // 计算在 Gizmo 中的相对位置(-1 到 1)\r\n const relX = ((clientX - gizmoLeft) / gizmoSize) * 2 - 1;\r\n const relY = -(((clientY - gizmoTop) / gizmoSize) * 2 - 1);\r\n\r\n // 检测点击的轴\r\n const clickedAxis = this.detectClickedAxis(relX, relY);\r\n if (clickedAxis && this.onAxisClick) {\r\n this.onAxisClick(clickedAxis.axis, clickedAxis.positive);\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * 检测点击了哪个轴\r\n */\r\n private detectClickedAxis(\r\n relX: number,\r\n relY: number,\r\n ): { axis: string; positive: boolean } | null {\r\n // 将屏幕坐标转换为 Gizmo 空间\r\n // 使用视图矩阵的逆来判断\r\n const threshold = 0.4;\r\n\r\n // 计算各轴在屏幕上的投影位置\r\n for (const axis of this.axes) {\r\n const [dx, dy, dz] = axis.direction;\r\n\r\n // 正向轴端点\r\n const posX =\r\n this.viewMatrix[0] * dx +\r\n this.viewMatrix[4] * dy +\r\n this.viewMatrix[8] * dz;\r\n const posY =\r\n this.viewMatrix[1] * dx +\r\n this.viewMatrix[5] * dy +\r\n this.viewMatrix[9] * dz;\r\n\r\n // 检查正向\r\n const distPos = Math.sqrt(\r\n (relX - posX * 0.5) ** 2 + (relY - posY * 0.5) ** 2,\r\n );\r\n if (distPos < threshold) {\r\n return { axis: axis.label, positive: true };\r\n }\r\n\r\n // 检查负向\r\n const distNeg = Math.sqrt(\r\n (relX + posX * 0.15) ** 2 + (relY + posY * 0.15) ** 2,\r\n );\r\n if (distNeg < threshold * 0.5) {\r\n return { axis: axis.label, positive: false };\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n\r\n // 向量工具函数\r\n private cross(\r\n a: [number, number, number],\r\n b: [number, number, number],\r\n ): [number, number, number] {\r\n return [\r\n a[1] * b[2] - a[2] * b[1],\r\n a[2] * b[0] - a[0] * b[2],\r\n a[0] * b[1] - a[1] * b[0],\r\n ];\r\n }\r\n\r\n private normalize(v: [number, number, number]): void {\r\n const len = Math.sqrt(v[0] ** 2 + v[1] ** 2 + v[2] ** 2);\r\n if (len > 0) {\r\n v[0] /= len;\r\n v[1] /= len;\r\n v[2] /= len;\r\n }\r\n }\r\n\r\n /**\r\n * 设置 Gizmo 大小\r\n */\r\n setSize(size: number): void {\r\n this.size = size;\r\n }\r\n\r\n /**\r\n * 设置边距\r\n */\r\n setMargin(margin: number): void {\r\n this.margin = margin;\r\n }\r\n}\r\n","import { Renderer } from \"./Renderer\";\r\nimport { Camera } from \"./Camera\";\r\nimport type { SimpleBoundingBox, BoundingBoxProvider, Vec3Tuple } from \"../types\";\r\n\r\n/**\r\n * BoundingBoxRenderer - 包围盒线框渲染器\r\n * 用于显示选中对象的包围盒,支持动态跟随\r\n */\r\nexport class BoundingBoxRenderer {\r\n private renderer: Renderer;\r\n private camera: Camera;\r\n \r\n // GPU 资源\r\n private pipeline: GPURenderPipeline | null = null;\r\n private uniformBuffer: GPUBuffer | null = null;\r\n private bindGroup: GPUBindGroup | null = null;\r\n private vertexBuffer: GPUBuffer | null = null;\r\n \r\n // 包围盒数据提供者(动态模式)\r\n private provider: BoundingBoxProvider | null = null;\r\n \r\n // 静态包围盒(备用)\r\n private staticBoundingBox: SimpleBoundingBox | null = null;\r\n \r\n // 线条颜色 (白色)\r\n private lineColor: [number, number, number] = [1.0, 1.0, 1.0];\r\n \r\n // 角落线段长度比例 (相对于边长)\r\n private cornerRatio: number = 0.2;\r\n \r\n constructor(renderer: Renderer, camera: Camera) {\r\n this.renderer = renderer;\r\n this.camera = camera;\r\n this.createPipeline();\r\n this.createVertexBuffer();\r\n }\r\n \r\n /**\r\n * 创建渲染管线\r\n */\r\n private createPipeline(): void {\r\n const device = this.renderer.device;\r\n \r\n const shaderCode = `\r\n struct Uniforms {\r\n viewProjection: mat4x4<f32>,\r\n }\r\n\r\n @group(0) @binding(0) var<uniform> uniforms: Uniforms;\r\n\r\n struct VertexInput {\r\n @location(0) position: vec3<f32>,\r\n @location(1) color: vec3<f32>,\r\n }\r\n\r\n struct VertexOutput {\r\n @builtin(position) position: vec4<f32>,\r\n @location(0) color: vec3<f32>,\r\n }\r\n\r\n @vertex\r\n fn vertexMain(input: VertexInput) -> VertexOutput {\r\n var output: VertexOutput;\r\n output.position = uniforms.viewProjection * vec4<f32>(input.position, 1.0);\r\n output.color = input.color;\r\n return output;\r\n }\r\n\r\n @fragment\r\n fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {\r\n return vec4<f32>(input.color, 1.0);\r\n }\r\n `;\r\n \r\n const shaderModule = device.createShaderModule({ code: shaderCode });\r\n \r\n // Uniform buffer: viewProjection (64 bytes)\r\n this.uniformBuffer = device.createBuffer({\r\n size: 64,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n \r\n const bindGroupLayout = device.createBindGroupLayout({\r\n entries: [{\r\n binding: 0,\r\n visibility: GPUShaderStage.VERTEX,\r\n buffer: { type: \"uniform\" },\r\n }],\r\n });\r\n \r\n this.bindGroup = device.createBindGroup({\r\n layout: bindGroupLayout,\r\n entries: [{ binding: 0, resource: { buffer: this.uniformBuffer } }],\r\n });\r\n \r\n const pipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [bindGroupLayout],\r\n });\r\n \r\n this.pipeline = device.createRenderPipeline({\r\n layout: pipelineLayout,\r\n vertex: {\r\n module: shaderModule,\r\n entryPoint: \"vertexMain\",\r\n buffers: [{\r\n arrayStride: 24, // 6 floats * 4 bytes\r\n attributes: [\r\n { shaderLocation: 0, offset: 0, format: \"float32x3\" },\r\n { shaderLocation: 1, offset: 12, format: \"float32x3\" },\r\n ],\r\n }],\r\n },\r\n fragment: {\r\n module: shaderModule,\r\n entryPoint: \"fragmentMain\",\r\n targets: [{\r\n format: this.renderer.format,\r\n }],\r\n },\r\n primitive: {\r\n topology: \"line-list\",\r\n cullMode: \"none\",\r\n },\r\n depthStencil: {\r\n format: this.renderer.depthFormat,\r\n depthWriteEnabled: false,\r\n depthCompare: \"always\", // 始终可见\r\n },\r\n });\r\n }\r\n \r\n /**\r\n * 创建顶点缓冲区(预分配)\r\n */\r\n private createVertexBuffer(): void {\r\n const device = this.renderer.device;\r\n // 48 个顶点 * 6 floats * 4 bytes = 1152 bytes\r\n this.vertexBuffer = device.createBuffer({\r\n size: 1152,\r\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\r\n });\r\n }\r\n \r\n /**\r\n * 设置包围盒数据提供者(动态模式)\r\n * 每帧会从 provider 获取最新的包围盒数据\r\n */\r\n setProvider(provider: BoundingBoxProvider | null): void {\r\n this.provider = provider;\r\n this.staticBoundingBox = null;\r\n }\r\n \r\n /**\r\n * 设置静态包围盒(不会自动更新)\r\n */\r\n setBoundingBox(box: SimpleBoundingBox | null): void {\r\n this.staticBoundingBox = box;\r\n this.provider = null;\r\n }\r\n \r\n /**\r\n * 清除包围盒\r\n */\r\n clear(): void {\r\n this.provider = null;\r\n this.staticBoundingBox = null;\r\n }\r\n \r\n /**\r\n * 设置线条颜色\r\n */\r\n setLineColor(r: number, g: number, b: number): void {\r\n this.lineColor = [r, g, b];\r\n }\r\n \r\n /**\r\n * 生成顶点数据\r\n */\r\n private generateVertices(box: SimpleBoundingBox): Float32Array {\r\n const { min, max } = box;\r\n const [r, g, b] = this.lineColor;\r\n \r\n // 计算各边长度\r\n const dx = max[0] - min[0];\r\n const dy = max[1] - min[1];\r\n const dz = max[2] - min[2];\r\n \r\n // 角落线段长度\r\n const lx = dx * this.cornerRatio;\r\n const ly = dy * this.cornerRatio;\r\n const lz = dz * this.cornerRatio;\r\n \r\n // 8 个角落,每个角落 3 条线段,每条线段 2 个顶点\r\n // 总共 8 * 3 * 2 = 48 个顶点\r\n const vertices: number[] = [];\r\n \r\n // 辅助函数:添加线段\r\n const addLine = (x1: number, y1: number, z1: number, x2: number, y2: number, z2: number) => {\r\n vertices.push(x1, y1, z1, r, g, b);\r\n vertices.push(x2, y2, z2, r, g, b);\r\n };\r\n \r\n // 角落 0: min, min, min\r\n addLine(min[0], min[1], min[2], min[0] + lx, min[1], min[2]);\r\n addLine(min[0], min[1], min[2], min[0], min[1] + ly, min[2]);\r\n addLine(min[0], min[1], min[2], min[0], min[1], min[2] + lz);\r\n \r\n // 角落 1: max, min, min\r\n addLine(max[0], min[1], min[2], max[0] - lx, min[1], min[2]);\r\n addLine(max[0], min[1], min[2], max[0], min[1] + ly, min[2]);\r\n addLine(max[0], min[1], min[2], max[0], min[1], min[2] + lz);\r\n \r\n // 角落 2: min, max, min\r\n addLine(min[0], max[1], min[2], min[0] + lx, max[1], min[2]);\r\n addLine(min[0], max[1], min[2], min[0], max[1] - ly, min[2]);\r\n addLine(min[0], max[1], min[2], min[0], max[1], min[2] + lz);\r\n \r\n // 角落 3: max, max, min\r\n addLine(max[0], max[1], min[2], max[0] - lx, max[1], min[2]);\r\n addLine(max[0], max[1], min[2], max[0], max[1] - ly, min[2]);\r\n addLine(max[0], max[1], min[2], max[0], max[1], min[2] + lz);\r\n \r\n // 角落 4: min, min, max\r\n addLine(min[0], min[1], max[2], min[0] + lx, min[1], max[2]);\r\n addLine(min[0], min[1], max[2], min[0], min[1] + ly, max[2]);\r\n addLine(min[0], min[1], max[2], min[0], min[1], max[2] - lz);\r\n \r\n // 角落 5: max, min, max\r\n addLine(max[0], min[1], max[2], max[0] - lx, min[1], max[2]);\r\n addLine(max[0], min[1], max[2], max[0], min[1] + ly, max[2]);\r\n addLine(max[0], min[1], max[2], max[0], min[1], max[2] - lz);\r\n \r\n // 角落 6: min, max, max\r\n addLine(min[0], max[1], max[2], min[0] + lx, max[1], max[2]);\r\n addLine(min[0], max[1], max[2], min[0], max[1] - ly, max[2]);\r\n addLine(min[0], max[1], max[2], min[0], max[1], max[2] - lz);\r\n \r\n // 角落 7: max, max, max\r\n addLine(max[0], max[1], max[2], max[0] - lx, max[1], max[2]);\r\n addLine(max[0], max[1], max[2], max[0], max[1] - ly, max[2]);\r\n addLine(max[0], max[1], max[2], max[0], max[1], max[2] - lz);\r\n \r\n return new Float32Array(vertices);\r\n }\r\n \r\n /**\r\n * 渲染包围盒\r\n */\r\n render(pass: GPURenderPassEncoder): void {\r\n if (!this.pipeline || !this.bindGroup || !this.vertexBuffer || !this.uniformBuffer) {\r\n return;\r\n }\r\n \r\n // 获取当前包围盒\r\n let box: SimpleBoundingBox | null = null;\r\n \r\n if (this.provider) {\r\n box = this.provider.getBoundingBox();\r\n } else {\r\n box = this.staticBoundingBox;\r\n }\r\n \r\n if (!box) return;\r\n \r\n const device = this.renderer.device;\r\n \r\n // 每帧都更新顶点缓冲区(动态模式)\r\n const vertexData = this.generateVertices(box);\r\n device.queue.writeBuffer(this.vertexBuffer, 0, vertexData.buffer);\r\n \r\n // 更新 uniform buffer\r\n const vpMatrix = new Float32Array(this.camera.viewProjectionMatrix);\r\n device.queue.writeBuffer(this.uniformBuffer, 0, vpMatrix);\r\n \r\n // 渲染\r\n pass.setPipeline(this.pipeline);\r\n pass.setBindGroup(0, this.bindGroup);\r\n pass.setVertexBuffer(0, this.vertexBuffer);\r\n pass.draw(48); // 48 个顶点\r\n }\r\n \r\n /**\r\n * 销毁资源\r\n */\r\n destroy(): void {\r\n if (this.vertexBuffer) {\r\n this.vertexBuffer.destroy();\r\n this.vertexBuffer = null;\r\n }\r\n if (this.uniformBuffer) {\r\n this.uniformBuffer.destroy();\r\n this.uniformBuffer = null;\r\n }\r\n this.pipeline = null;\r\n this.bindGroup = null;\r\n }\r\n}\r\n","import type { BoundingBox, Vec3Tuple } from \"../types\";\r\n\r\n/**\r\n * Mesh - 网格数据结构\r\n * 存储 GPUBuffer + 变换属性\r\n */\r\nexport class Mesh {\r\n vertexBuffer: GPUBuffer;\r\n indexBuffer: GPUBuffer | null;\r\n vertexCount: number;\r\n indexCount: number;\r\n modelMatrix: Float32Array;\r\n\r\n // 顶点格式信息\r\n hasUV: boolean = false;\r\n indexFormat: 'uint16' | 'uint32' = 'uint16';\r\n\r\n // 变换属性(分离存储,便于 Gizmo 操作)\r\n position: Float32Array = new Float32Array([0, 0, 0]);\r\n rotation: Float32Array = new Float32Array([0, 0, 0]); // 欧拉角 (弧度)\r\n scale: Float32Array = new Float32Array([1, 1, 1]);\r\n\r\n // 本地空间的 bounding box(加载时计算,不随变换更新)\r\n private localBoundingBox: BoundingBox | null = null;\r\n\r\n constructor(\r\n vertexBuffer: GPUBuffer,\r\n vertexCount: number,\r\n indexBuffer: GPUBuffer | null = null,\r\n indexCount: number = 0,\r\n boundingBox?: BoundingBox\r\n ) {\r\n this.vertexBuffer = vertexBuffer;\r\n this.vertexCount = vertexCount;\r\n this.indexBuffer = indexBuffer;\r\n this.indexCount = indexCount;\r\n this.modelMatrix = new Float32Array([\r\n 1, 0, 0, 0,\r\n 0, 1, 0, 0,\r\n 0, 0, 1, 0,\r\n 0, 0, 0, 1,\r\n ]);\r\n this.localBoundingBox = boundingBox || null;\r\n }\r\n\r\n /**\r\n * 获取顶点 stride(字节数)\r\n */\r\n getVertexStride(): number {\r\n return this.hasUV ? 32 : 24;\r\n }\r\n\r\n /**\r\n * 设置本地 bounding box\r\n */\r\n setBoundingBox(bbox: BoundingBox): void {\r\n this.localBoundingBox = bbox;\r\n }\r\n\r\n /**\r\n * 获取本地 bounding box\r\n */\r\n getLocalBoundingBox(): BoundingBox | null {\r\n return this.localBoundingBox;\r\n }\r\n\r\n /**\r\n * 获取世界空间的 bounding box(考虑完整变换:缩放、旋转、平移)\r\n */\r\n getWorldBoundingBox(): BoundingBox | null {\r\n if (!this.localBoundingBox) return null;\r\n\r\n const local = this.localBoundingBox;\r\n \r\n // 获取本地包围盒的 8 个角点\r\n const corners: Vec3Tuple[] = [\r\n [local.min[0], local.min[1], local.min[2]],\r\n [local.max[0], local.min[1], local.min[2]],\r\n [local.min[0], local.max[1], local.min[2]],\r\n [local.max[0], local.max[1], local.min[2]],\r\n [local.min[0], local.min[1], local.max[2]],\r\n [local.max[0], local.min[1], local.max[2]],\r\n [local.min[0], local.max[1], local.max[2]],\r\n [local.max[0], local.max[1], local.max[2]],\r\n ];\r\n \r\n // 使用 modelMatrix 变换所有角点\r\n const m = this.modelMatrix;\r\n const transformedCorners: Vec3Tuple[] = corners.map(([x, y, z]) => {\r\n const tx = m[0] * x + m[4] * y + m[8] * z + m[12];\r\n const ty = m[1] * x + m[5] * y + m[9] * z + m[13];\r\n const tz = m[2] * x + m[6] * y + m[10] * z + m[14];\r\n return [tx, ty, tz];\r\n });\r\n \r\n // 计算变换后的 AABB\r\n let minX = Infinity, minY = Infinity, minZ = Infinity;\r\n let maxX = -Infinity, maxY = -Infinity, maxZ = -Infinity;\r\n \r\n for (const [x, y, z] of transformedCorners) {\r\n minX = Math.min(minX, x);\r\n minY = Math.min(minY, y);\r\n minZ = Math.min(minZ, z);\r\n maxX = Math.max(maxX, x);\r\n maxY = Math.max(maxY, y);\r\n maxZ = Math.max(maxZ, z);\r\n }\r\n \r\n const worldMin: Vec3Tuple = [minX, minY, minZ];\r\n const worldMax: Vec3Tuple = [maxX, maxY, maxZ];\r\n const worldCenter: Vec3Tuple = [\r\n (minX + maxX) / 2,\r\n (minY + maxY) / 2,\r\n (minZ + maxZ) / 2,\r\n ];\r\n \r\n const dx = maxX - minX;\r\n const dy = maxY - minY;\r\n const dz = maxZ - minZ;\r\n const worldRadius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min: worldMin, max: worldMax, center: worldCenter, radius: worldRadius };\r\n }\r\n\r\n setPosition(x: number, y: number, z: number): void {\r\n this.position[0] = x;\r\n this.position[1] = y;\r\n this.position[2] = z;\r\n this.updateModelMatrix();\r\n }\r\n\r\n getPosition(): Vec3Tuple {\r\n return [this.position[0], this.position[1], this.position[2]];\r\n }\r\n\r\n setRotation(rx: number, ry: number, rz: number): void {\r\n this.rotation[0] = rx;\r\n this.rotation[1] = ry;\r\n this.rotation[2] = rz;\r\n this.updateModelMatrix();\r\n }\r\n\r\n getRotation(): Vec3Tuple {\r\n return [this.rotation[0], this.rotation[1], this.rotation[2]];\r\n }\r\n\r\n setScale(sx: number, sy: number, sz: number): void {\r\n this.scale[0] = sx;\r\n this.scale[1] = sy;\r\n this.scale[2] = sz;\r\n this.updateModelMatrix();\r\n }\r\n\r\n getScale(): Vec3Tuple {\r\n return [this.scale[0], this.scale[1], this.scale[2]];\r\n }\r\n\r\n updateModelMatrix(): void {\r\n const [sx, sy, sz] = this.scale;\r\n const [rx, ry, rz] = this.rotation;\r\n const [tx, ty, tz] = this.position;\r\n\r\n const cx = Math.cos(rx), sx_ = Math.sin(rx);\r\n const cy = Math.cos(ry), sy_ = Math.sin(ry);\r\n const cz = Math.cos(rz), sz_ = Math.sin(rz);\r\n\r\n this.modelMatrix[0] = sx * (cy * cz);\r\n this.modelMatrix[1] = sx * (cy * sz_);\r\n this.modelMatrix[2] = sx * (-sy_);\r\n this.modelMatrix[3] = 0;\r\n\r\n this.modelMatrix[4] = sy * (sx_ * sy_ * cz - cx * sz_);\r\n this.modelMatrix[5] = sy * (sx_ * sy_ * sz_ + cx * cz);\r\n this.modelMatrix[6] = sy * (sx_ * cy);\r\n this.modelMatrix[7] = 0;\r\n\r\n this.modelMatrix[8] = sz * (cx * sy_ * cz + sx_ * sz_);\r\n this.modelMatrix[9] = sz * (cx * sy_ * sz_ - sx_ * cz);\r\n this.modelMatrix[10] = sz * (cx * cy);\r\n this.modelMatrix[11] = 0;\r\n\r\n this.modelMatrix[12] = tx;\r\n this.modelMatrix[13] = ty;\r\n this.modelMatrix[14] = tz;\r\n this.modelMatrix[15] = 1;\r\n }\r\n\r\n resetTransform(): void {\r\n this.position.set([0, 0, 0]);\r\n this.rotation.set([0, 0, 0]);\r\n this.scale.set([1, 1, 1]);\r\n this.updateModelMatrix();\r\n }\r\n\r\n destroy(): void {\r\n this.vertexBuffer.destroy();\r\n if (this.indexBuffer) {\r\n this.indexBuffer.destroy();\r\n }\r\n }\r\n}\r\n","import { Renderer } from \"../core/Renderer\";\r\nimport { Camera } from \"../core/Camera\";\r\nimport { Mesh } from \"./Mesh\";\r\nimport type { BoundingBox } from \"../types\";\r\nimport { MaterialData } from \"../loaders/GLBLoader\";\r\n\r\n/**\r\n * 带纹理的 Shader\r\n */\r\nconst shaderCodeTextured = /* wgsl */ `\r\nstruct Uniforms {\r\n viewProjection: mat4x4<f32>,\r\n model: mat4x4<f32>,\r\n baseColorFactor: vec4<f32>,\r\n lightDir: vec3<f32>,\r\n ambientIntensity: f32,\r\n}\r\n\r\n@group(0) @binding(0) var<uniform> uniforms: Uniforms;\r\n@group(0) @binding(1) var texSampler: sampler;\r\n@group(0) @binding(2) var baseColorTexture: texture_2d<f32>;\r\n\r\nstruct VertexInput {\r\n @location(0) position: vec3<f32>,\r\n @location(1) normal: vec3<f32>,\r\n @location(2) uv: vec2<f32>,\r\n}\r\n\r\nstruct VertexOutput {\r\n @builtin(position) position: vec4<f32>,\r\n @location(0) normal: vec3<f32>,\r\n @location(1) uv: vec2<f32>,\r\n}\r\n\r\n@vertex\r\nfn vs_main(input: VertexInput) -> VertexOutput {\r\n var output: VertexOutput;\r\n let worldPos = uniforms.model * vec4<f32>(input.position, 1.0);\r\n output.position = uniforms.viewProjection * worldPos;\r\n output.normal = normalize((uniforms.model * vec4<f32>(input.normal, 0.0)).xyz);\r\n output.uv = input.uv;\r\n return output;\r\n}\r\n\r\n@fragment\r\nfn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {\r\n let texColor = textureSample(baseColorTexture, texSampler, input.uv);\r\n let baseColor = texColor * uniforms.baseColorFactor;\r\n \r\n // Lambert 光照 + 环境光\r\n let normal = normalize(input.normal);\r\n let NdotL = max(dot(normal, uniforms.lightDir), 0.0);\r\n let diffuse = NdotL * (1.0 - uniforms.ambientIntensity);\r\n let lighting = uniforms.ambientIntensity + diffuse;\r\n \r\n return vec4<f32>(baseColor.rgb * lighting, baseColor.a);\r\n}\r\n`;\r\n\r\n/**\r\n * 无纹理的 Shader(使用 baseColorFactor)\r\n */\r\nconst shaderCodeUntextured = /* wgsl */ `\r\nstruct Uniforms {\r\n viewProjection: mat4x4<f32>,\r\n model: mat4x4<f32>,\r\n baseColorFactor: vec4<f32>,\r\n lightDir: vec3<f32>,\r\n ambientIntensity: f32,\r\n}\r\n\r\n@group(0) @binding(0) var<uniform> uniforms: Uniforms;\r\n\r\nstruct VertexInput {\r\n @location(0) position: vec3<f32>,\r\n @location(1) normal: vec3<f32>,\r\n}\r\n\r\nstruct VertexOutput {\r\n @builtin(position) position: vec4<f32>,\r\n @location(0) normal: vec3<f32>,\r\n}\r\n\r\n@vertex\r\nfn vs_main(input: VertexInput) -> VertexOutput {\r\n var output: VertexOutput;\r\n let worldPos = uniforms.model * vec4<f32>(input.position, 1.0);\r\n output.position = uniforms.viewProjection * worldPos;\r\n output.normal = normalize((uniforms.model * vec4<f32>(input.normal, 0.0)).xyz);\r\n return output;\r\n}\r\n\r\n@fragment\r\nfn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {\r\n let normal = normalize(input.normal);\r\n let NdotL = max(dot(normal, uniforms.lightDir), 0.0);\r\n let diffuse = NdotL * (1.0 - uniforms.ambientIntensity);\r\n let lighting = uniforms.ambientIntensity + diffuse;\r\n \r\n return vec4<f32>(uniforms.baseColorFactor.rgb * lighting, uniforms.baseColorFactor.a);\r\n}\r\n`;\r\n\r\n// Uniform buffer 大小: viewProjection(64) + model(64) + baseColorFactor(16) + lightDir(12) + ambientIntensity(4) = 160 bytes\r\nconst UNIFORM_BUFFER_SIZE = 160;\r\n\r\n/**\r\n * 渲染项(Mesh + Material + 独立的 uniform buffer)\r\n */\r\ninterface RenderItem {\r\n mesh: Mesh;\r\n material: MaterialData;\r\n uniformBuffer: GPUBuffer;\r\n bindGroup: GPUBindGroup;\r\n}\r\n\r\n/**\r\n * MeshRenderer - 网格渲染器\r\n * 支持纹理和材质,每个 mesh 有独立的 uniform buffer\r\n */\r\nexport class MeshRenderer {\r\n private renderer: Renderer;\r\n private camera: Camera;\r\n private items: RenderItem[] = [];\r\n private overlayItems: RenderItem[] = [];\r\n\r\n // 有纹理的管线\r\n private pipelineTextured!: GPURenderPipeline;\r\n private pipelineTexturedDoubleSided!: GPURenderPipeline;\r\n private bindGroupLayoutTextured!: GPUBindGroupLayout;\r\n\r\n // 无纹理的管线\r\n private pipelineUntextured!: GPURenderPipeline;\r\n private pipelineUntexturedDoubleSided!: GPURenderPipeline;\r\n private bindGroupLayoutUntextured!: GPUBindGroupLayout;\r\n\r\n // 覆盖层管线(带 depthBias,用于贴面热点/指示器)\r\n private overlayPipelineTextured!: GPURenderPipeline;\r\n private overlayPipelineTexturedDoubleSided!: GPURenderPipeline;\r\n private overlayPipelineUntextured!: GPURenderPipeline;\r\n private overlayPipelineUntexturedDoubleSided!: GPURenderPipeline;\r\n\r\n private sampler!: GPUSampler;\r\n private defaultTexture!: GPUTexture;\r\n\r\n // 光照方向\r\n private lightDir: Float32Array = new Float32Array([0.5, 0.7, 0.5]);\r\n // 环境光强度 (0-1)\r\n private ambientIntensity: number = 0.6;\r\n\r\n constructor(renderer: Renderer, camera: Camera) {\r\n this.renderer = renderer;\r\n this.camera = camera;\r\n this.createResources();\r\n this.createPipelines();\r\n }\r\n\r\n private createResources(): void {\r\n const device = this.renderer.device;\r\n\r\n // 创建采样器\r\n this.sampler = device.createSampler({\r\n magFilter: 'linear',\r\n minFilter: 'linear',\r\n mipmapFilter: 'linear',\r\n addressModeU: 'repeat',\r\n addressModeV: 'repeat',\r\n });\r\n\r\n // 创建默认白色纹理\r\n this.defaultTexture = device.createTexture({\r\n size: [1, 1, 1],\r\n format: 'rgba8unorm',\r\n usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST,\r\n });\r\n device.queue.writeTexture(\r\n { texture: this.defaultTexture },\r\n new Uint8Array([255, 255, 255, 255]),\r\n { bytesPerRow: 4 },\r\n [1, 1, 1]\r\n );\r\n }\r\n\r\n private createPipelines(): void {\r\n const device = this.renderer.device;\r\n\r\n // === 有纹理的管线 ===\r\n const shaderModuleTextured = device.createShaderModule({ code: shaderCodeTextured });\r\n\r\n this.bindGroupLayoutTextured = device.createBindGroupLayout({\r\n entries: [\r\n { binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: \"uniform\" } },\r\n { binding: 1, visibility: GPUShaderStage.FRAGMENT, sampler: { type: \"filtering\" } },\r\n { binding: 2, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: \"float\" } },\r\n ],\r\n });\r\n\r\n const pipelineLayoutTextured = device.createPipelineLayout({\r\n bindGroupLayouts: [this.bindGroupLayoutTextured],\r\n });\r\n\r\n const vertexBufferLayoutTextured: GPUVertexBufferLayout = {\r\n arrayStride: 32,\r\n attributes: [\r\n { shaderLocation: 0, offset: 0, format: \"float32x3\" },\r\n { shaderLocation: 1, offset: 12, format: \"float32x3\" },\r\n { shaderLocation: 2, offset: 24, format: \"float32x2\" },\r\n ],\r\n };\r\n\r\n const depthStencilNormal: GPUDepthStencilState = {\r\n format: this.renderer.depthFormat,\r\n depthWriteEnabled: true,\r\n depthCompare: \"less\",\r\n };\r\n\r\n const depthStencilOverlay: GPUDepthStencilState = {\r\n format: this.renderer.depthFormat,\r\n depthWriteEnabled: false,\r\n depthCompare: \"less\",\r\n depthBias: -2000,\r\n depthBiasSlopeScale: -4,\r\n depthBiasClamp: 0,\r\n };\r\n\r\n const basePipelineDescTextured: GPURenderPipelineDescriptor = {\r\n layout: pipelineLayoutTextured,\r\n vertex: {\r\n module: shaderModuleTextured,\r\n entryPoint: \"vs_main\",\r\n buffers: [vertexBufferLayoutTextured],\r\n },\r\n fragment: {\r\n module: shaderModuleTextured,\r\n entryPoint: \"fs_main\",\r\n targets: [{ format: this.renderer.format }],\r\n },\r\n primitive: { topology: \"triangle-list\", frontFace: \"ccw\" },\r\n depthStencil: depthStencilNormal,\r\n };\r\n\r\n this.pipelineTextured = device.createRenderPipeline({\r\n ...basePipelineDescTextured,\r\n primitive: { ...basePipelineDescTextured.primitive, cullMode: \"back\" },\r\n });\r\n\r\n this.pipelineTexturedDoubleSided = device.createRenderPipeline({\r\n ...basePipelineDescTextured,\r\n primitive: { ...basePipelineDescTextured.primitive, cullMode: \"none\" },\r\n });\r\n\r\n // 覆盖层管线(纹理)\r\n const overlayDescTextured = { ...basePipelineDescTextured, depthStencil: depthStencilOverlay };\r\n this.overlayPipelineTextured = device.createRenderPipeline({\r\n ...overlayDescTextured,\r\n primitive: { ...overlayDescTextured.primitive, cullMode: \"back\" },\r\n });\r\n this.overlayPipelineTexturedDoubleSided = device.createRenderPipeline({\r\n ...overlayDescTextured,\r\n primitive: { ...overlayDescTextured.primitive, cullMode: \"none\" },\r\n });\r\n\r\n // === 无纹理的管线 ===\r\n const shaderModuleUntextured = device.createShaderModule({ code: shaderCodeUntextured });\r\n\r\n this.bindGroupLayoutUntextured = device.createBindGroupLayout({\r\n entries: [\r\n { binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: \"uniform\" } },\r\n ],\r\n });\r\n\r\n const pipelineLayoutUntextured = device.createPipelineLayout({\r\n bindGroupLayouts: [this.bindGroupLayoutUntextured],\r\n });\r\n\r\n const vertexBufferLayoutUntextured: GPUVertexBufferLayout = {\r\n arrayStride: 24,\r\n attributes: [\r\n { shaderLocation: 0, offset: 0, format: \"float32x3\" },\r\n { shaderLocation: 1, offset: 12, format: \"float32x3\" },\r\n ],\r\n };\r\n\r\n const basePipelineDescUntextured: GPURenderPipelineDescriptor = {\r\n layout: pipelineLayoutUntextured,\r\n vertex: {\r\n module: shaderModuleUntextured,\r\n entryPoint: \"vs_main\",\r\n buffers: [vertexBufferLayoutUntextured],\r\n },\r\n fragment: {\r\n module: shaderModuleUntextured,\r\n entryPoint: \"fs_main\",\r\n targets: [{ format: this.renderer.format }],\r\n },\r\n primitive: { topology: \"triangle-list\", frontFace: \"ccw\" },\r\n depthStencil: depthStencilNormal,\r\n };\r\n\r\n this.pipelineUntextured = device.createRenderPipeline({\r\n ...basePipelineDescUntextured,\r\n primitive: { ...basePipelineDescUntextured.primitive, cullMode: \"back\" },\r\n });\r\n\r\n this.pipelineUntexturedDoubleSided = device.createRenderPipeline({\r\n ...basePipelineDescUntextured,\r\n primitive: { ...basePipelineDescUntextured.primitive, cullMode: \"none\" },\r\n });\r\n\r\n // 覆盖层管线(无纹理)\r\n const overlayDescUntextured = { ...basePipelineDescUntextured, depthStencil: depthStencilOverlay };\r\n this.overlayPipelineUntextured = device.createRenderPipeline({\r\n ...overlayDescUntextured,\r\n primitive: { ...overlayDescUntextured.primitive, cullMode: \"back\" },\r\n });\r\n this.overlayPipelineUntexturedDoubleSided = device.createRenderPipeline({\r\n ...overlayDescUntextured,\r\n primitive: { ...overlayDescUntextured.primitive, cullMode: \"none\" },\r\n });\r\n }\r\n\r\n /**\r\n * 添加网格(带材质)- 每个 mesh 创建独立的 uniform buffer\r\n */\r\n addMesh(mesh: Mesh, material?: MaterialData): void {\r\n const device = this.renderer.device;\r\n \r\n const mat = material || {\r\n baseColorFactor: [0.8, 0.8, 0.8, 1] as [number, number, number, number],\r\n baseColorTexture: null,\r\n metallicFactor: 0,\r\n roughnessFactor: 0.5,\r\n doubleSided: false,\r\n };\r\n\r\n // 为每个 mesh 创建独立的 uniform buffer\r\n const uniformBuffer = device.createBuffer({\r\n size: UNIFORM_BUFFER_SIZE,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n\r\n // 创建 bind group\r\n let bindGroup: GPUBindGroup;\r\n \r\n if (mesh.hasUV) {\r\n const texture = mat.baseColorTexture || this.defaultTexture;\r\n bindGroup = device.createBindGroup({\r\n layout: this.bindGroupLayoutTextured,\r\n entries: [\r\n { binding: 0, resource: { buffer: uniformBuffer } },\r\n { binding: 1, resource: this.sampler },\r\n { binding: 2, resource: texture.createView() },\r\n ],\r\n });\r\n } else {\r\n bindGroup = device.createBindGroup({\r\n layout: this.bindGroupLayoutUntextured,\r\n entries: [\r\n { binding: 0, resource: { buffer: uniformBuffer } },\r\n ],\r\n });\r\n }\r\n\r\n this.items.push({ mesh, material: mat, uniformBuffer, bindGroup });\r\n }\r\n\r\n /**\r\n * 移除网格(销毁 GPU 资源)\r\n */\r\n removeMesh(mesh: Mesh): void {\r\n const index = this.items.findIndex(item => item.mesh === mesh);\r\n if (index !== -1) {\r\n const item = this.items[index];\r\n item.mesh.destroy();\r\n item.uniformBuffer.destroy();\r\n this.items.splice(index, 1);\r\n }\r\n }\r\n\r\n /**\r\n * 从渲染列表中分离网格(不销毁 GPU 资源,可重新添加)\r\n */\r\n detachMesh(mesh: Mesh): void {\r\n const index = this.items.findIndex(item => item.mesh === mesh);\r\n if (index !== -1) {\r\n const item = this.items[index];\r\n item.uniformBuffer.destroy();\r\n this.items.splice(index, 1);\r\n }\r\n }\r\n\r\n /**\r\n * 添加覆盖层网格(使用带 depthBias 的管线,贴面不被 3DGS 深度遮挡)\r\n */\r\n addOverlayMesh(mesh: Mesh, material?: MaterialData): void {\r\n const device = this.renderer.device;\r\n\r\n const mat = material || {\r\n baseColorFactor: [0.8, 0.8, 0.8, 1] as [number, number, number, number],\r\n baseColorTexture: null,\r\n metallicFactor: 0,\r\n roughnessFactor: 0.5,\r\n doubleSided: false,\r\n };\r\n\r\n const uniformBuffer = device.createBuffer({\r\n size: UNIFORM_BUFFER_SIZE,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n\r\n let bindGroup: GPUBindGroup;\r\n if (mesh.hasUV) {\r\n const texture = mat.baseColorTexture || this.defaultTexture;\r\n bindGroup = device.createBindGroup({\r\n layout: this.bindGroupLayoutTextured,\r\n entries: [\r\n { binding: 0, resource: { buffer: uniformBuffer } },\r\n { binding: 1, resource: this.sampler },\r\n { binding: 2, resource: texture.createView() },\r\n ],\r\n });\r\n } else {\r\n bindGroup = device.createBindGroup({\r\n layout: this.bindGroupLayoutUntextured,\r\n entries: [\r\n { binding: 0, resource: { buffer: uniformBuffer } },\r\n ],\r\n });\r\n }\r\n\r\n this.overlayItems.push({ mesh, material: mat, uniformBuffer, bindGroup });\r\n }\r\n\r\n /**\r\n * 从覆盖层列表中分离网格(不销毁 vertex/index buffer)\r\n */\r\n detachOverlayMesh(mesh: Mesh): void {\r\n const index = this.overlayItems.findIndex(item => item.mesh === mesh);\r\n if (index !== -1) {\r\n const item = this.overlayItems[index];\r\n item.uniformBuffer.destroy();\r\n this.overlayItems.splice(index, 1);\r\n }\r\n }\r\n\r\n /**\r\n * 按索引移除网格\r\n */\r\n removeMeshByIndex(index: number): boolean {\r\n if (index >= 0 && index < this.items.length) {\r\n const item = this.items[index];\r\n item.mesh.destroy();\r\n item.uniformBuffer.destroy();\r\n this.items.splice(index, 1);\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * 清空所有网格(含覆盖层)\r\n */\r\n clear(): void {\r\n for (const item of this.items) {\r\n item.mesh.destroy();\r\n item.uniformBuffer.destroy();\r\n }\r\n this.items = [];\r\n for (const item of this.overlayItems) {\r\n item.mesh.destroy();\r\n item.uniformBuffer.destroy();\r\n }\r\n this.overlayItems = [];\r\n }\r\n\r\n /**\r\n * 设置光照方向\r\n */\r\n setLightDirection(x: number, y: number, z: number): void {\r\n const len = Math.sqrt(x * x + y * y + z * z);\r\n this.lightDir[0] = x / len;\r\n this.lightDir[1] = y / len;\r\n this.lightDir[2] = z / len;\r\n }\r\n\r\n /**\r\n * 设置环境光强度\r\n */\r\n setAmbientIntensity(intensity: number): void {\r\n this.ambientIntensity = Math.max(0, Math.min(1, intensity));\r\n }\r\n\r\n /**\r\n * 获取环境光强度\r\n */\r\n getAmbientIntensity(): number {\r\n return this.ambientIntensity;\r\n }\r\n\r\n /**\r\n * 渲染所有网格(普通 + 覆盖层)\r\n */\r\n render(pass: GPURenderPassEncoder): void {\r\n const device = this.renderer.device;\r\n const vpMatrix = new Float32Array(this.camera.viewProjectionMatrix);\r\n const lightData = new Float32Array([\r\n this.lightDir[0], this.lightDir[1], this.lightDir[2], this.ambientIntensity\r\n ]);\r\n\r\n // 普通网格\r\n this.renderItems(pass, this.items, device, vpMatrix, lightData, false);\r\n // 覆盖层网格(带 depthBias 管线)\r\n this.renderItems(pass, this.overlayItems, device, vpMatrix, lightData, true);\r\n }\r\n\r\n private renderItems(\r\n pass: GPURenderPassEncoder,\r\n items: RenderItem[],\r\n device: GPUDevice,\r\n vpMatrix: Float32Array,\r\n lightData: Float32Array,\r\n overlay: boolean,\r\n ): void {\r\n if (items.length === 0) return;\r\n\r\n for (const item of items) {\r\n const { mesh, material, uniformBuffer, bindGroup } = item;\r\n\r\n device.queue.writeBuffer(uniformBuffer, 0, vpMatrix.buffer);\r\n device.queue.writeBuffer(uniformBuffer, 64, mesh.modelMatrix.buffer);\r\n const colorData = new Float32Array(material.baseColorFactor);\r\n device.queue.writeBuffer(uniformBuffer, 128, colorData.buffer);\r\n device.queue.writeBuffer(uniformBuffer, 144, lightData.buffer);\r\n\r\n let pipeline: GPURenderPipeline;\r\n if (overlay) {\r\n if (mesh.hasUV) {\r\n pipeline = material.doubleSided ? this.overlayPipelineTexturedDoubleSided : this.overlayPipelineTextured;\r\n } else {\r\n pipeline = material.doubleSided ? this.overlayPipelineUntexturedDoubleSided : this.overlayPipelineUntextured;\r\n }\r\n } else {\r\n if (mesh.hasUV) {\r\n pipeline = material.doubleSided ? this.pipelineTexturedDoubleSided : this.pipelineTextured;\r\n } else {\r\n pipeline = material.doubleSided ? this.pipelineUntexturedDoubleSided : this.pipelineUntextured;\r\n }\r\n }\r\n\r\n pass.setPipeline(pipeline);\r\n pass.setBindGroup(0, bindGroup);\r\n pass.setVertexBuffer(0, mesh.vertexBuffer);\r\n\r\n if (mesh.indexBuffer && mesh.indexCount > 0) {\r\n pass.setIndexBuffer(mesh.indexBuffer, mesh.indexFormat);\r\n pass.drawIndexed(mesh.indexCount);\r\n } else {\r\n pass.draw(mesh.vertexCount);\r\n }\r\n }\r\n }\r\n\r\n getMeshCount(): number {\r\n return this.items.length;\r\n }\r\n\r\n getMeshByIndex(index: number): Mesh | null {\r\n if (index >= 0 && index < this.items.length) {\r\n return this.items[index].mesh;\r\n }\r\n return null;\r\n }\r\n\r\n getMeshColor(index: number): [number, number, number, number] | null {\r\n if (index >= 0 && index < this.items.length) {\r\n return [...this.items[index].material.baseColorFactor] as [number, number, number, number];\r\n }\r\n return null;\r\n }\r\n\r\n setMeshColor(index: number, r: number, g: number, b: number, a: number = 1): boolean {\r\n if (index >= 0 && index < this.items.length) {\r\n this.items[index].material.baseColorFactor = [r, g, b, a];\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n setMeshRangeColor(startIndex: number, count: number, r: number, g: number, b: number, a: number = 1): number {\r\n let modified = 0;\r\n for (let i = 0; i < count; i++) {\r\n if (this.setMeshColor(startIndex + i, r, g, b, a)) {\r\n modified++;\r\n }\r\n }\r\n return modified;\r\n }\r\n\r\n // ============================================\r\n // 覆盖层网格查询 / 颜色 / 删除\r\n // ============================================\r\n\r\n getOverlayMeshCount(): number {\r\n return this.overlayItems.length;\r\n }\r\n\r\n getOverlayMeshByIndex(index: number): Mesh | null {\r\n if (index >= 0 && index < this.overlayItems.length) {\r\n return this.overlayItems[index].mesh;\r\n }\r\n return null;\r\n }\r\n\r\n removeOverlayMeshByIndex(index: number): boolean {\r\n if (index >= 0 && index < this.overlayItems.length) {\r\n const item = this.overlayItems[index];\r\n item.mesh.destroy();\r\n item.uniformBuffer.destroy();\r\n this.overlayItems.splice(index, 1);\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n getOverlayMeshColor(index: number): [number, number, number, number] | null {\r\n if (index >= 0 && index < this.overlayItems.length) {\r\n return [...this.overlayItems[index].material.baseColorFactor] as [number, number, number, number];\r\n }\r\n return null;\r\n }\r\n\r\n setOverlayMeshColor(index: number, r: number, g: number, b: number, a: number = 1): boolean {\r\n if (index >= 0 && index < this.overlayItems.length) {\r\n this.overlayItems[index].material.baseColorFactor = [r, g, b, a];\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n setOverlayMeshRangeColor(startIndex: number, count: number, r: number, g: number, b: number, a: number = 1): number {\r\n let modified = 0;\r\n for (let i = 0; i < count; i++) {\r\n if (this.setOverlayMeshColor(startIndex + i, r, g, b, a)) {\r\n modified++;\r\n }\r\n }\r\n return modified;\r\n }\r\n\r\n getCombinedBoundingBox(): BoundingBox | null {\r\n if (this.items.length === 0) return null;\r\n\r\n let combinedMin: [number, number, number] | null = null;\r\n let combinedMax: [number, number, number] | null = null;\r\n\r\n for (const item of this.items) {\r\n const bbox = item.mesh.getWorldBoundingBox();\r\n if (!bbox) continue;\r\n\r\n if (combinedMin === null || combinedMax === null) {\r\n combinedMin = [...bbox.min];\r\n combinedMax = [...bbox.max];\r\n } else {\r\n combinedMin[0] = Math.min(combinedMin[0], bbox.min[0]);\r\n combinedMin[1] = Math.min(combinedMin[1], bbox.min[1]);\r\n combinedMin[2] = Math.min(combinedMin[2], bbox.min[2]);\r\n combinedMax[0] = Math.max(combinedMax[0], bbox.max[0]);\r\n combinedMax[1] = Math.max(combinedMax[1], bbox.max[1]);\r\n combinedMax[2] = Math.max(combinedMax[2], bbox.max[2]);\r\n }\r\n }\r\n\r\n if (combinedMin === null || combinedMax === null) return null;\r\n\r\n const center: [number, number, number] = [\r\n (combinedMin[0] + combinedMax[0]) / 2,\r\n (combinedMin[1] + combinedMax[1]) / 2,\r\n (combinedMin[2] + combinedMax[2]) / 2,\r\n ];\r\n const dx = combinedMax[0] - combinedMin[0];\r\n const dy = combinedMax[1] - combinedMin[1];\r\n const dz = combinedMax[2] - combinedMin[2];\r\n const radius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min: combinedMin, max: combinedMax, center, radius };\r\n }\r\n\r\n destroy(): void {\r\n this.clear();\r\n if (this.defaultTexture) this.defaultTexture.destroy();\r\n }\r\n}\r\n","import { Mesh } from '../mesh/Mesh';\r\nimport type { BoundingBox, Vec3Tuple, MaterialData } from '../types';\r\nimport { computeBoundingBox } from '../utils';\r\n\r\n// 重新导出 MaterialData 保持向后兼容\r\nexport type { MaterialData };\r\n\r\n/**\r\n * GLB 文件格式常量\r\n */\r\nconst GLB_MAGIC = 0x46546C67; // 'glTF'\r\nconst GLB_VERSION = 2;\r\nconst CHUNK_TYPE_JSON = 0x4E4F534A; // 'JSON'\r\nconst CHUNK_TYPE_BIN = 0x004E4942; // 'BIN\\0'\r\n\r\n/**\r\n * glTF 访问器组件类型\r\n */\r\nconst COMPONENT_TYPES: Record<number, { size: number; type: 'float' | 'uint8' | 'uint16' | 'uint32' | 'int8' | 'int16' }> = {\r\n 5120: { size: 1, type: 'int8' }, // BYTE\r\n 5121: { size: 1, type: 'uint8' }, // UNSIGNED_BYTE\r\n 5122: { size: 2, type: 'int16' }, // SHORT\r\n 5123: { size: 2, type: 'uint16' }, // UNSIGNED_SHORT\r\n 5125: { size: 4, type: 'uint32' }, // UNSIGNED_INT\r\n 5126: { size: 4, type: 'float' }, // FLOAT\r\n};\r\n\r\n/**\r\n * glTF 类型元素数量\r\n */\r\nconst TYPE_SIZES: Record<string, number> = {\r\n SCALAR: 1,\r\n VEC2: 2,\r\n VEC3: 3,\r\n VEC4: 4,\r\n MAT2: 4,\r\n MAT3: 9,\r\n MAT4: 16,\r\n};\r\n\r\n/**\r\n * 加载后的 Mesh 数据(包含材质)\r\n */\r\nexport interface LoadedMesh {\r\n mesh: Mesh;\r\n material: MaterialData;\r\n}\r\n\r\n/**\r\n * GLBLoader - GLB 文件加载器\r\n * 解析 GLB 文件并生成 Mesh[],支持贴图\r\n */\r\nexport class GLBLoader {\r\n private device: GPUDevice;\r\n private textureCache: Map<number, GPUTexture> = new Map();\r\n\r\n constructor(device: GPUDevice) {\r\n this.device = device;\r\n }\r\n\r\n /**\r\n * 加载 GLB 文件\r\n */\r\n async load(url: string): Promise<LoadedMesh[]> {\r\n const response = await fetch(url);\r\n if (!response.ok) {\r\n throw new Error(`无法加载 GLB 文件: ${url}`);\r\n }\r\n\r\n const arrayBuffer = await response.arrayBuffer();\r\n return this.parse(arrayBuffer);\r\n }\r\n\r\n /**\r\n * 解析 GLB 二进制数据\r\n */\r\n private async parse(buffer: ArrayBuffer): Promise<LoadedMesh[]> {\r\n const dataView = new DataView(buffer);\r\n let offset = 0;\r\n\r\n // 读取 GLB 头部\r\n const magic = dataView.getUint32(offset, true);\r\n offset += 4;\r\n if (magic !== GLB_MAGIC) {\r\n throw new Error('无效的 GLB 文件');\r\n }\r\n\r\n const version = dataView.getUint32(offset, true);\r\n offset += 4;\r\n if (version !== GLB_VERSION) {\r\n throw new Error(`不支持的 GLB 版本: ${version}`);\r\n }\r\n\r\n const _length = dataView.getUint32(offset, true);\r\n offset += 4;\r\n\r\n // 读取 JSON chunk\r\n const jsonChunkLength = dataView.getUint32(offset, true);\r\n offset += 4;\r\n const jsonChunkType = dataView.getUint32(offset, true);\r\n offset += 4;\r\n\r\n if (jsonChunkType !== CHUNK_TYPE_JSON) {\r\n throw new Error('第一个 chunk 必须是 JSON');\r\n }\r\n\r\n const jsonData = new Uint8Array(buffer, offset, jsonChunkLength);\r\n const jsonString = new TextDecoder().decode(jsonData);\r\n const gltf = JSON.parse(jsonString);\r\n offset += jsonChunkLength;\r\n\r\n // 读取 BIN chunk(可选)\r\n let binData: ArrayBuffer | null = null;\r\n if (offset < buffer.byteLength) {\r\n const binChunkLength = dataView.getUint32(offset, true);\r\n offset += 4;\r\n const binChunkType = dataView.getUint32(offset, true);\r\n offset += 4;\r\n\r\n if (binChunkType === CHUNK_TYPE_BIN) {\r\n binData = buffer.slice(offset, offset + binChunkLength);\r\n }\r\n }\r\n\r\n // 清空纹理缓存\r\n this.textureCache.clear();\r\n\r\n // 解析网格\r\n return this.parseMeshes(gltf, binData);\r\n }\r\n\r\n /**\r\n * 解析所有网格\r\n */\r\n private async parseMeshes(gltf: any, binData: ArrayBuffer | null): Promise<LoadedMesh[]> {\r\n const meshes: LoadedMesh[] = [];\r\n\r\n if (!gltf.meshes || !binData) {\r\n return meshes;\r\n }\r\n\r\n for (const gltfMesh of gltf.meshes) {\r\n for (const primitive of gltfMesh.primitives) {\r\n const loadedMesh = await this.parsePrimitive(gltf, primitive, binData);\r\n if (loadedMesh) {\r\n meshes.push(loadedMesh);\r\n }\r\n }\r\n }\r\n\r\n return meshes;\r\n }\r\n\r\n /**\r\n * 解析单个图元\r\n */\r\n private async parsePrimitive(gltf: any, primitive: any, binData: ArrayBuffer): Promise<LoadedMesh | null> {\r\n const attributes = primitive.attributes;\r\n \r\n // 获取位置数据\r\n if (attributes.POSITION === undefined) {\r\n return null;\r\n }\r\n\r\n const positionAccessor = gltf.accessors[attributes.POSITION];\r\n const positions = this.getAccessorData(gltf, positionAccessor, binData);\r\n\r\n // 获取法线数据(可选,如果没有则生成)\r\n let normals: Float32Array;\r\n if (attributes.NORMAL !== undefined) {\r\n const normalAccessor = gltf.accessors[attributes.NORMAL];\r\n const normalData = this.getAccessorData(gltf, normalAccessor, binData);\r\n normals = new Float32Array(normalData);\r\n } else {\r\n // 生成默认法线(指向 +Y)\r\n normals = new Float32Array(positions.length);\r\n for (let i = 0; i < positions.length; i += 3) {\r\n normals[i] = 0;\r\n normals[i + 1] = 1;\r\n normals[i + 2] = 0;\r\n }\r\n }\r\n\r\n // 获取 UV 坐标(可选)\r\n let uvs: Float32Array | null = null;\r\n if (attributes.TEXCOORD_0 !== undefined) {\r\n const uvAccessor = gltf.accessors[attributes.TEXCOORD_0];\r\n const uvData = this.getAccessorData(gltf, uvAccessor, binData);\r\n uvs = new Float32Array(uvData);\r\n }\r\n\r\n // 创建交错顶点数据: position(3) + normal(3) + uv(2)\r\n const vertexCount = positionAccessor.count;\r\n const hasUV = uvs !== null;\r\n const stride = hasUV ? 8 : 6; // 有 UV 时 8 floats,否则 6 floats\r\n const vertexData = new Float32Array(vertexCount * stride);\r\n \r\n for (let i = 0; i < vertexCount; i++) {\r\n const baseIdx = i * stride;\r\n vertexData[baseIdx + 0] = positions[i * 3 + 0];\r\n vertexData[baseIdx + 1] = positions[i * 3 + 1];\r\n vertexData[baseIdx + 2] = positions[i * 3 + 2];\r\n vertexData[baseIdx + 3] = normals[i * 3 + 0];\r\n vertexData[baseIdx + 4] = normals[i * 3 + 1];\r\n vertexData[baseIdx + 5] = normals[i * 3 + 2];\r\n if (hasUV && uvs) {\r\n vertexData[baseIdx + 6] = uvs[i * 2 + 0];\r\n vertexData[baseIdx + 7] = uvs[i * 2 + 1];\r\n }\r\n }\r\n\r\n // 创建顶点缓冲区\r\n const vertexBuffer = this.device.createBuffer({\r\n size: vertexData.byteLength,\r\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\r\n });\r\n this.device.queue.writeBuffer(vertexBuffer, 0, vertexData);\r\n\r\n // 获取索引数据(可选)\r\n let indexBuffer: GPUBuffer | null = null;\r\n let indexCount = 0;\r\n let indexFormat: 'uint16' | 'uint32' = 'uint16';\r\n\r\n if (primitive.indices !== undefined) {\r\n const indexAccessor = gltf.accessors[primitive.indices];\r\n const indices = this.getAccessorData(gltf, indexAccessor, binData);\r\n indexCount = indexAccessor.count;\r\n\r\n // 根据顶点数量决定索引格式\r\n if (vertexCount > 65535) {\r\n indexFormat = 'uint32';\r\n const indexData = new Uint32Array(indexCount);\r\n for (let i = 0; i < indexCount; i++) {\r\n indexData[i] = indices[i];\r\n }\r\n indexBuffer = this.device.createBuffer({\r\n size: indexData.byteLength,\r\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\r\n });\r\n this.device.queue.writeBuffer(indexBuffer, 0, indexData);\r\n } else {\r\n const indexData = new Uint16Array(indexCount);\r\n for (let i = 0; i < indexCount; i++) {\r\n indexData[i] = indices[i];\r\n }\r\n indexBuffer = this.device.createBuffer({\r\n size: indexData.byteLength,\r\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\r\n });\r\n this.device.queue.writeBuffer(indexBuffer, 0, indexData);\r\n }\r\n }\r\n\r\n // 计算 bounding box\r\n const boundingBox = this.computeBoundingBoxFromPositions(positions);\r\n\r\n // 解析材质\r\n const material = await this.parseMaterial(gltf, primitive.material, binData);\r\n\r\n // 创建 Mesh\r\n const mesh = new Mesh(vertexBuffer, vertexCount, indexBuffer, indexCount, boundingBox);\r\n mesh.hasUV = hasUV;\r\n mesh.indexFormat = indexFormat;\r\n\r\n return { mesh, material };\r\n }\r\n\r\n /**\r\n * 解析材质\r\n */\r\n private async parseMaterial(gltf: any, materialIndex: number | undefined, binData: ArrayBuffer): Promise<MaterialData> {\r\n // 默认材质\r\n const defaultMaterial: MaterialData = {\r\n baseColorFactor: [1, 1, 1, 1],\r\n baseColorTexture: null,\r\n metallicFactor: 1,\r\n roughnessFactor: 1,\r\n doubleSided: false,\r\n };\r\n\r\n if (materialIndex === undefined || !gltf.materials) {\r\n return defaultMaterial;\r\n }\r\n\r\n const gltfMaterial = gltf.materials[materialIndex];\r\n if (!gltfMaterial) {\r\n return defaultMaterial;\r\n }\r\n\r\n const material: MaterialData = { ...defaultMaterial };\r\n\r\n // 解析 doubleSided\r\n if (gltfMaterial.doubleSided !== undefined) {\r\n material.doubleSided = gltfMaterial.doubleSided;\r\n }\r\n\r\n // 解析 PBR 材质\r\n const pbr = gltfMaterial.pbrMetallicRoughness;\r\n if (pbr) {\r\n // baseColorFactor\r\n if (pbr.baseColorFactor) {\r\n material.baseColorFactor = pbr.baseColorFactor;\r\n }\r\n\r\n // metallicFactor\r\n if (pbr.metallicFactor !== undefined) {\r\n material.metallicFactor = pbr.metallicFactor;\r\n }\r\n\r\n // roughnessFactor\r\n if (pbr.roughnessFactor !== undefined) {\r\n material.roughnessFactor = pbr.roughnessFactor;\r\n }\r\n\r\n // baseColorTexture\r\n if (pbr.baseColorTexture) {\r\n const textureIndex = pbr.baseColorTexture.index;\r\n material.baseColorTexture = await this.loadTexture(gltf, textureIndex, binData);\r\n }\r\n }\r\n\r\n return material;\r\n }\r\n\r\n /**\r\n * 加载纹理\r\n */\r\n private async loadTexture(gltf: any, textureIndex: number, binData: ArrayBuffer): Promise<GPUTexture | null> {\r\n // 检查缓存\r\n if (this.textureCache.has(textureIndex)) {\r\n return this.textureCache.get(textureIndex)!;\r\n }\r\n\r\n if (!gltf.textures || !gltf.images) {\r\n return null;\r\n }\r\n\r\n const texture = gltf.textures[textureIndex];\r\n if (!texture || texture.source === undefined) {\r\n return null;\r\n }\r\n\r\n const image = gltf.images[texture.source];\r\n if (!image) {\r\n return null;\r\n }\r\n\r\n try {\r\n let imageBitmap: ImageBitmap;\r\n\r\n if (image.bufferView !== undefined) {\r\n // 从 buffer 加载图片\r\n const bufferView = gltf.bufferViews[image.bufferView];\r\n const byteOffset = bufferView.byteOffset || 0;\r\n const byteLength = bufferView.byteLength;\r\n const imageData = new Uint8Array(binData, byteOffset, byteLength);\r\n const blob = new Blob([imageData], { type: image.mimeType || 'image/png' });\r\n imageBitmap = await createImageBitmap(blob);\r\n } else if (image.uri) {\r\n // 从 URI 加载(data URI 或外部 URL)\r\n if (image.uri.startsWith('data:')) {\r\n const response = await fetch(image.uri);\r\n const blob = await response.blob();\r\n imageBitmap = await createImageBitmap(blob);\r\n } else {\r\n // 外部 URL - 这里简化处理,实际可能需要相对路径解析\r\n const response = await fetch(image.uri);\r\n const blob = await response.blob();\r\n imageBitmap = await createImageBitmap(blob);\r\n }\r\n } else {\r\n return null;\r\n }\r\n\r\n // 创建 GPU 纹理\r\n const gpuTexture = this.device.createTexture({\r\n size: [imageBitmap.width, imageBitmap.height, 1],\r\n format: 'rgba8unorm',\r\n usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,\r\n });\r\n\r\n this.device.queue.copyExternalImageToTexture(\r\n { source: imageBitmap },\r\n { texture: gpuTexture },\r\n [imageBitmap.width, imageBitmap.height]\r\n );\r\n\r\n // 缓存纹理\r\n this.textureCache.set(textureIndex, gpuTexture);\r\n\r\n return gpuTexture;\r\n } catch (error) {\r\n return null;\r\n }\r\n }\r\n\r\n /**\r\n * 计算顶点数据的 bounding box\r\n */\r\n private computeBoundingBoxFromPositions(positions: Float32Array | Uint16Array | Uint32Array | Int8Array | Int16Array | Uint8Array): BoundingBox {\r\n return computeBoundingBox(positions);\r\n }\r\n\r\n /**\r\n * 获取访问器数据 - 修复字节对齐问题\r\n */\r\n private getAccessorData(gltf: any, accessor: any, binData: ArrayBuffer): Float32Array | Uint16Array | Uint32Array | Int8Array | Int16Array | Uint8Array {\r\n const bufferView = gltf.bufferViews[accessor.bufferView];\r\n const componentType = COMPONENT_TYPES[accessor.componentType];\r\n const typeSize = TYPE_SIZES[accessor.type];\r\n const count = accessor.count * typeSize;\r\n\r\n const byteOffset = (bufferView.byteOffset || 0) + (accessor.byteOffset || 0);\r\n const byteLength = count * componentType.size;\r\n\r\n // 复制数据到新的 ArrayBuffer 以避免对齐问题\r\n const alignedBuffer = new ArrayBuffer(byteLength);\r\n const srcView = new Uint8Array(binData, byteOffset, byteLength);\r\n const dstView = new Uint8Array(alignedBuffer);\r\n dstView.set(srcView);\r\n\r\n switch (componentType.type) {\r\n case 'float':\r\n return new Float32Array(alignedBuffer);\r\n case 'uint8':\r\n return new Uint8Array(alignedBuffer);\r\n case 'uint16':\r\n return new Uint16Array(alignedBuffer);\r\n case 'uint32':\r\n return new Uint32Array(alignedBuffer);\r\n case 'int8':\r\n return new Int8Array(alignedBuffer);\r\n case 'int16':\r\n return new Int16Array(alignedBuffer);\r\n default:\r\n throw new Error(`不支持的组件类型: ${accessor.componentType}`);\r\n }\r\n }\r\n\r\n /**\r\n * 创建测试立方体(用于调试)\r\n */\r\n createTestCube(): LoadedMesh {\r\n // 立方体顶点数据: position(3) + normal(3) + uv(2)\r\n const vertices = new Float32Array([\r\n // 前面 (z = 0.5)\r\n -0.5, -0.5, 0.5, 0, 0, 1, 0, 1,\r\n 0.5, -0.5, 0.5, 0, 0, 1, 1, 1,\r\n 0.5, 0.5, 0.5, 0, 0, 1, 1, 0,\r\n -0.5, 0.5, 0.5, 0, 0, 1, 0, 0,\r\n // 后面 (z = -0.5)\r\n 0.5, -0.5, -0.5, 0, 0, -1, 0, 1,\r\n -0.5, -0.5, -0.5, 0, 0, -1, 1, 1,\r\n -0.5, 0.5, -0.5, 0, 0, -1, 1, 0,\r\n 0.5, 0.5, -0.5, 0, 0, -1, 0, 0,\r\n // 上面 (y = 0.5)\r\n -0.5, 0.5, 0.5, 0, 1, 0, 0, 1,\r\n 0.5, 0.5, 0.5, 0, 1, 0, 1, 1,\r\n 0.5, 0.5, -0.5, 0, 1, 0, 1, 0,\r\n -0.5, 0.5, -0.5, 0, 1, 0, 0, 0,\r\n // 下面 (y = -0.5)\r\n -0.5, -0.5, -0.5, 0, -1, 0, 0, 1,\r\n 0.5, -0.5, -0.5, 0, -1, 0, 1, 1,\r\n 0.5, -0.5, 0.5, 0, -1, 0, 1, 0,\r\n -0.5, -0.5, 0.5, 0, -1, 0, 0, 0,\r\n // 右面 (x = 0.5)\r\n 0.5, -0.5, 0.5, 1, 0, 0, 0, 1,\r\n 0.5, -0.5, -0.5, 1, 0, 0, 1, 1,\r\n 0.5, 0.5, -0.5, 1, 0, 0, 1, 0,\r\n 0.5, 0.5, 0.5, 1, 0, 0, 0, 0,\r\n // 左面 (x = -0.5)\r\n -0.5, -0.5, -0.5, -1, 0, 0, 0, 1,\r\n -0.5, -0.5, 0.5, -1, 0, 0, 1, 1,\r\n -0.5, 0.5, 0.5, -1, 0, 0, 1, 0,\r\n -0.5, 0.5, -0.5, -1, 0, 0, 0, 0,\r\n ]);\r\n\r\n const indices = new Uint16Array([\r\n 0, 1, 2, 0, 2, 3, // 前\r\n 4, 5, 6, 4, 6, 7, // 后\r\n 8, 9, 10, 8, 10, 11, // 上\r\n 12, 13, 14, 12, 14, 15, // 下\r\n 16, 17, 18, 16, 18, 19, // 右\r\n 20, 21, 22, 20, 22, 23, // 左\r\n ]);\r\n\r\n const vertexBuffer = this.device.createBuffer({\r\n size: vertices.byteLength,\r\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\r\n });\r\n this.device.queue.writeBuffer(vertexBuffer, 0, vertices);\r\n\r\n const indexBuffer = this.device.createBuffer({\r\n size: indices.byteLength,\r\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\r\n });\r\n this.device.queue.writeBuffer(indexBuffer, 0, indices);\r\n\r\n // 立方体 bounding box: -0.5 到 0.5\r\n const cubeBbox: BoundingBox = {\r\n min: [-0.5, -0.5, -0.5],\r\n max: [0.5, 0.5, 0.5],\r\n center: [0, 0, 0],\r\n radius: Math.sqrt(0.75),\r\n };\r\n\r\n const mesh = new Mesh(vertexBuffer, 24, indexBuffer, 36, cubeBbox);\r\n mesh.hasUV = true;\r\n mesh.indexFormat = 'uint16';\r\n\r\n return {\r\n mesh,\r\n material: {\r\n baseColorFactor: [1, 1, 1, 1],\r\n baseColorTexture: null,\r\n metallicFactor: 0,\r\n roughnessFactor: 0.5,\r\n doubleSided: false,\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * 创建测试球体\r\n */\r\n createTestSphere(radius: number = 0.5, segments: number = 32, rings: number = 16): LoadedMesh {\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n\r\n // 生成顶点\r\n for (let ring = 0; ring <= rings; ring++) {\r\n const phi = (ring / rings) * Math.PI;\r\n const sinPhi = Math.sin(phi);\r\n const cosPhi = Math.cos(phi);\r\n\r\n for (let seg = 0; seg <= segments; seg++) {\r\n const theta = (seg / segments) * Math.PI * 2;\r\n const sinTheta = Math.sin(theta);\r\n const cosTheta = Math.cos(theta);\r\n\r\n // 位置\r\n const x = radius * sinPhi * cosTheta;\r\n const y = radius * cosPhi;\r\n const z = radius * sinPhi * sinTheta;\r\n\r\n // 法线(球体法线就是归一化的位置)\r\n const nx = sinPhi * cosTheta;\r\n const ny = cosPhi;\r\n const nz = sinPhi * sinTheta;\r\n\r\n // UV\r\n const u = seg / segments;\r\n const v = ring / rings;\r\n\r\n vertices.push(x, y, z, nx, ny, nz, u, v);\r\n }\r\n }\r\n\r\n // 生成索引\r\n for (let ring = 0; ring < rings; ring++) {\r\n for (let seg = 0; seg < segments; seg++) {\r\n const current = ring * (segments + 1) + seg;\r\n const next = current + segments + 1;\r\n\r\n indices.push(current, next, current + 1);\r\n indices.push(current + 1, next, next + 1);\r\n }\r\n }\r\n\r\n const vertexData = new Float32Array(vertices);\r\n const indexData = new Uint16Array(indices);\r\n\r\n const vertexBuffer = this.device.createBuffer({\r\n size: vertexData.byteLength,\r\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\r\n });\r\n this.device.queue.writeBuffer(vertexBuffer, 0, vertexData);\r\n\r\n const indexBuffer = this.device.createBuffer({\r\n size: indexData.byteLength,\r\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\r\n });\r\n this.device.queue.writeBuffer(indexBuffer, 0, indexData);\r\n\r\n // 球体 bounding box\r\n const sphereBbox: BoundingBox = {\r\n min: [-radius, -radius, -radius],\r\n max: [radius, radius, radius],\r\n center: [0, 0, 0],\r\n radius: radius,\r\n };\r\n\r\n const mesh = new Mesh(vertexBuffer, vertexData.length / 8, indexBuffer, indexData.length, sphereBbox);\r\n mesh.hasUV = true;\r\n mesh.indexFormat = 'uint16';\r\n\r\n return {\r\n mesh,\r\n material: {\r\n baseColorFactor: [1, 1, 1, 1],\r\n baseColorTexture: null,\r\n metallicFactor: 0,\r\n roughnessFactor: 0.5,\r\n doubleSided: false,\r\n },\r\n };\r\n }\r\n}\r\n","/**\r\n * OBJParser - OBJ 文件文本解析器\r\n * 解析 OBJ 文件文本内容,提取几何数据\r\n */\r\n\r\n/**\r\n * 解析后的 OBJ 数据结构\r\n */\r\nexport interface ParsedOBJData {\r\n objects: ParsedObject[];\r\n}\r\n\r\n/**\r\n * 单个对象/组的数据\r\n */\r\nexport interface ParsedObject {\r\n name: string;\r\n positions: number[]; // 展开后的顶点位置 [x,y,z, x,y,z, ...]\r\n normals: number[]; // 展开后的法线 [nx,ny,nz, ...]\r\n uvs: number[]; // 展开后的 UV [u,v, u,v, ...]\r\n indices: number[]; // 三角形索引\r\n materialName: string | null;\r\n}\r\n\r\n/**\r\n * 面顶点索引结构\r\n */\r\ninterface FaceVertex {\r\n positionIndex: number;\r\n uvIndex: number | null;\r\n normalIndex: number | null;\r\n}\r\n\r\n/**\r\n * OBJ 文本解析器\r\n */\r\nexport class OBJParser {\r\n // 全局顶点池\r\n private positions: number[] = []; // v 指令收集的顶点位置\r\n private uvs: number[] = []; // vt 指令收集的纹理坐标\r\n private normals: number[] = []; // vn 指令收集的法线\r\n\r\n // 当前对象数据\r\n private currentObject: ParsedObject | null = null;\r\n private objects: ParsedObject[] = [];\r\n\r\n // 当前材质\r\n private currentMaterial: string | null = null;\r\n\r\n // 顶点去重映射 (用于索引缓冲区)\r\n private vertexMap: Map<string, number> = new Map();\r\n private vertexCount: number = 0;\r\n\r\n // 已警告的不支持指令集合(用于只警告首次)\r\n private warnedDirectives: Set<string> = new Set();\r\n\r\n /**\r\n * 解析 OBJ 文本内容\r\n * @param text OBJ 文件文本\r\n * @returns 解析后的数据结构\r\n */\r\n parse(text: string): ParsedOBJData {\r\n // 重置状态\r\n this.reset();\r\n\r\n // 按行分割文本\r\n const lines = text.split(/\\r?\\n/);\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n const line = lines[i].trim();\r\n \r\n // 跳过空行和注释\r\n if (line === '' || line.startsWith('#')) {\r\n continue;\r\n }\r\n\r\n this.parseLine(line, i + 1);\r\n }\r\n\r\n // 确保最后一个对象被添加\r\n this.finalizeCurrentObject();\r\n\r\n // 如果没有任何对象,但有面数据,创建默认对象\r\n if (this.objects.length === 0 && this.currentObject && this.currentObject.indices.length > 0) {\r\n this.objects.push(this.currentObject);\r\n }\r\n\r\n return { objects: this.objects };\r\n }\r\n\r\n /**\r\n * 重置解析器状态\r\n */\r\n private reset(): void {\r\n this.positions = [];\r\n this.uvs = [];\r\n this.normals = [];\r\n this.currentObject = null;\r\n this.objects = [];\r\n this.currentMaterial = null;\r\n this.vertexMap = new Map();\r\n this.vertexCount = 0;\r\n this.warnedDirectives = new Set();\r\n }\r\n\r\n /**\r\n * 警告不支持的指令(仅首次出现时警告)\r\n * @param directive 指令名称\r\n * @param lineNum 行号\r\n */\r\n private warnUnsupportedDirective(directive: string, lineNum: number): void {\r\n if (!this.warnedDirectives.has(directive)) {\r\n this.warnedDirectives.add(directive);\r\n }\r\n }\r\n\r\n /**\r\n * 解析单行\r\n */\r\n private parseLine(line: string, lineNum: number): void {\r\n // 分割指令和参数\r\n const parts = line.split(/\\s+/);\r\n const directive = parts[0].toLowerCase();\r\n\r\n try {\r\n switch (directive) {\r\n case 'v':\r\n this.parseVertex(parts);\r\n break;\r\n case 'vt':\r\n this.parseTextureCoord(parts);\r\n break;\r\n case 'vn':\r\n this.parseNormal(parts);\r\n break;\r\n case 'f':\r\n this.parseFace(parts, lineNum);\r\n break;\r\n case 'o':\r\n case 'g':\r\n this.parseObjectOrGroup(parts);\r\n break;\r\n case 'usemtl':\r\n this.parseUseMaterial(parts);\r\n break;\r\n case 'mtllib':\r\n // MTL 文件引用,在 OBJLoader 中处理\r\n break;\r\n case 's':\r\n // 平滑组,暂不支持,警告首次\r\n this.warnUnsupportedDirective(directive, lineNum);\r\n break;\r\n default:\r\n // 不支持的指令,警告首次\r\n this.warnUnsupportedDirective(directive, lineNum);\r\n break;\r\n }\r\n } catch (e) {\r\n // 解析错误,跳过该行\r\n }\r\n }\r\n\r\n /**\r\n * 解析顶点位置 (v x y z [w])\r\n */\r\n private parseVertex(parts: string[]): void {\r\n if (parts.length < 4) {\r\n throw new Error('顶点数据不完整');\r\n }\r\n\r\n const x = parseFloat(parts[1]);\r\n const y = parseFloat(parts[2]);\r\n const z = parseFloat(parts[3]);\r\n\r\n if (isNaN(x) || isNaN(y) || isNaN(z)) {\r\n throw new Error('无效的顶点坐标');\r\n }\r\n\r\n this.positions.push(x, y, z);\r\n }\r\n\r\n /**\r\n * 解析纹理坐标 (vt u [v] [w])\r\n */\r\n private parseTextureCoord(parts: string[]): void {\r\n if (parts.length < 2) {\r\n throw new Error('纹理坐标数据不完整');\r\n }\r\n\r\n const u = parseFloat(parts[1]);\r\n const v = parts.length > 2 ? parseFloat(parts[2]) : 0;\r\n\r\n if (isNaN(u) || isNaN(v)) {\r\n throw new Error('无效的纹理坐标');\r\n }\r\n\r\n this.uvs.push(u, v);\r\n }\r\n\r\n /**\r\n * 解析法线 (vn x y z)\r\n */\r\n private parseNormal(parts: string[]): void {\r\n if (parts.length < 4) {\r\n throw new Error('法线数据不完整');\r\n }\r\n\r\n const x = parseFloat(parts[1]);\r\n const y = parseFloat(parts[2]);\r\n const z = parseFloat(parts[3]);\r\n\r\n if (isNaN(x) || isNaN(y) || isNaN(z)) {\r\n throw new Error('无效的法线');\r\n }\r\n\r\n this.normals.push(x, y, z);\r\n }\r\n\r\n /**\r\n * 解析面 (f v1 v2 v3 ...)\r\n * 支持四种格式:\r\n * - f v v v (仅顶点)\r\n * - f v/vt v/vt v/vt (顶点/纹理)\r\n * - f v/vt/vn v/vt/vn v/vt/vn (顶点/纹理/法线)\r\n * - f v//vn v//vn v//vn (顶点//法线)\r\n */\r\n private parseFace(parts: string[], _lineNum: number): void {\r\n if (parts.length < 4) {\r\n throw new Error('面数据不完整,至少需要3个顶点');\r\n }\r\n\r\n // 确保有当前对象\r\n this.ensureCurrentObject();\r\n\r\n // 解析面顶点\r\n const faceVertices: FaceVertex[] = [];\r\n for (let i = 1; i < parts.length; i++) {\r\n const vertex = this.parseFaceVertex(parts[i]);\r\n if (vertex) {\r\n faceVertices.push(vertex);\r\n }\r\n }\r\n\r\n if (faceVertices.length < 3) {\r\n throw new Error('面顶点数量不足');\r\n }\r\n\r\n // 三角化多边形(扇形三角化)\r\n // 对于 n 边形 [v0, v1, v2, ..., vn-1]:\r\n // 生成三角形: (v0, v1, v2), (v0, v2, v3), ..., (v0, vn-2, vn-1)\r\n for (let i = 1; i < faceVertices.length - 1; i++) {\r\n this.addTriangle(faceVertices[0], faceVertices[i], faceVertices[i + 1]);\r\n }\r\n }\r\n\r\n /**\r\n * 解析面顶点索引\r\n * 支持格式: v, v/vt, v/vt/vn, v//vn\r\n */\r\n private parseFaceVertex(vertexStr: string): FaceVertex | null {\r\n const parts = vertexStr.split('/');\r\n \r\n // 解析位置索引(必需)\r\n const positionIndex = this.resolveIndex(parseInt(parts[0]), this.positions.length / 3);\r\n if (isNaN(positionIndex)) {\r\n return null;\r\n }\r\n\r\n // 解析纹理坐标索引(可选)\r\n let uvIndex: number | null = null;\r\n if (parts.length > 1 && parts[1] !== '') {\r\n uvIndex = this.resolveIndex(parseInt(parts[1]), this.uvs.length / 2);\r\n if (isNaN(uvIndex)) {\r\n uvIndex = null;\r\n }\r\n }\r\n\r\n // 解析法线索引(可选)\r\n let normalIndex: number | null = null;\r\n if (parts.length > 2 && parts[2] !== '') {\r\n normalIndex = this.resolveIndex(parseInt(parts[2]), this.normals.length / 3);\r\n if (isNaN(normalIndex)) {\r\n normalIndex = null;\r\n }\r\n }\r\n\r\n return { positionIndex, uvIndex, normalIndex };\r\n }\r\n\r\n /**\r\n * 解析索引,支持负索引\r\n * 负索引表示相对于当前顶点数的偏移(-1 表示最后一个顶点)\r\n */\r\n private resolveIndex(index: number, count: number): number {\r\n if (isNaN(index)) {\r\n return NaN;\r\n }\r\n\r\n if (index < 0) {\r\n // 负索引:-1 表示最后一个,-2 表示倒数第二个\r\n return count + index;\r\n } else {\r\n // 正索引:OBJ 索引从 1 开始\r\n return index - 1;\r\n }\r\n }\r\n\r\n /**\r\n * 添加三角形到当前对象\r\n */\r\n private addTriangle(v0: FaceVertex, v1: FaceVertex, v2: FaceVertex): void {\r\n const idx0 = this.addVertex(v0);\r\n const idx1 = this.addVertex(v1);\r\n const idx2 = this.addVertex(v2);\r\n\r\n this.currentObject!.indices.push(idx0, idx1, idx2);\r\n }\r\n\r\n /**\r\n * 添加顶点到当前对象,返回索引\r\n * 使用顶点去重,相同的顶点组合只添加一次\r\n */\r\n private addVertex(vertex: FaceVertex): number {\r\n // 创建顶点键用于去重\r\n const key = `${vertex.positionIndex}/${vertex.uvIndex ?? ''}/${vertex.normalIndex ?? ''}`;\r\n\r\n // 检查是否已存在\r\n if (this.vertexMap.has(key)) {\r\n return this.vertexMap.get(key)!;\r\n }\r\n\r\n // 添加新顶点\r\n const index = this.vertexCount++;\r\n this.vertexMap.set(key, index);\r\n\r\n // 添加位置数据\r\n const posIdx = vertex.positionIndex * 3;\r\n if (posIdx >= 0 && posIdx + 2 < this.positions.length) {\r\n this.currentObject!.positions.push(\r\n this.positions[posIdx],\r\n this.positions[posIdx + 1],\r\n this.positions[posIdx + 2]\r\n );\r\n } else {\r\n // 无效索引,使用默认值\r\n this.currentObject!.positions.push(0, 0, 0);\r\n }\r\n\r\n // 添加法线数据\r\n if (vertex.normalIndex !== null) {\r\n const normIdx = vertex.normalIndex * 3;\r\n if (normIdx >= 0 && normIdx + 2 < this.normals.length) {\r\n this.currentObject!.normals.push(\r\n this.normals[normIdx],\r\n this.normals[normIdx + 1],\r\n this.normals[normIdx + 2]\r\n );\r\n } else {\r\n this.currentObject!.normals.push(0, 1, 0);\r\n }\r\n }\r\n\r\n // 添加 UV 数据\r\n if (vertex.uvIndex !== null) {\r\n const uvIdx = vertex.uvIndex * 2;\r\n if (uvIdx >= 0 && uvIdx + 1 < this.uvs.length) {\r\n this.currentObject!.uvs.push(\r\n this.uvs[uvIdx],\r\n this.uvs[uvIdx + 1]\r\n );\r\n } else {\r\n this.currentObject!.uvs.push(0, 0);\r\n }\r\n }\r\n\r\n return index;\r\n }\r\n\r\n /**\r\n * 解析对象或组 (o name / g name)\r\n */\r\n private parseObjectOrGroup(parts: string[]): void {\r\n // 完成当前对象\r\n this.finalizeCurrentObject();\r\n\r\n // 创建新对象\r\n const name = parts.length > 1 ? parts.slice(1).join(' ') : 'default';\r\n this.createNewObject(name);\r\n }\r\n\r\n /**\r\n * 解析材质引用 (usemtl name)\r\n */\r\n private parseUseMaterial(parts: string[]): void {\r\n if (parts.length > 1) {\r\n this.currentMaterial = parts.slice(1).join(' ');\r\n \r\n // 如果当前对象已有面数据,需要创建新对象\r\n if (this.currentObject && this.currentObject.indices.length > 0) {\r\n this.finalizeCurrentObject();\r\n this.createNewObject(this.currentObject?.name || 'default');\r\n }\r\n \r\n if (this.currentObject) {\r\n this.currentObject.materialName = this.currentMaterial;\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * 确保存在当前对象\r\n */\r\n private ensureCurrentObject(): void {\r\n if (!this.currentObject) {\r\n this.createNewObject('default');\r\n }\r\n }\r\n\r\n /**\r\n * 创建新对象\r\n */\r\n private createNewObject(name: string): void {\r\n this.currentObject = {\r\n name,\r\n positions: [],\r\n normals: [],\r\n uvs: [],\r\n indices: [],\r\n materialName: this.currentMaterial,\r\n };\r\n this.vertexMap = new Map();\r\n this.vertexCount = 0;\r\n }\r\n\r\n /**\r\n * 完成当前对象并添加到列表\r\n */\r\n private finalizeCurrentObject(): void {\r\n if (this.currentObject && this.currentObject.indices.length > 0) {\r\n this.objects.push(this.currentObject);\r\n }\r\n this.currentObject = null;\r\n }\r\n}\r\n","/**\r\n * MTLParser - MTL 材质文件解析器\r\n * 解析 MTL 文件文本内容,提取材质数据\r\n */\r\n\r\n/**\r\n * 解析后的材质数据\r\n */\r\nexport interface ParsedMaterial {\r\n name: string;\r\n diffuseColor: [number, number, number]; // Kd\r\n diffuseTexture: string | null; // map_Kd\r\n opacity: number; // d 或 1-Tr\r\n}\r\n\r\n/**\r\n * MTL 文本解析器\r\n */\r\nexport class MTLParser {\r\n // 当前材质\r\n private currentMaterial: ParsedMaterial | null = null;\r\n private materials: Map<string, ParsedMaterial> = new Map();\r\n\r\n /**\r\n * 解析 MTL 文本内容\r\n * @param text MTL 文件文本\r\n * @returns 材质名称到材质数据的映射\r\n */\r\n parse(text: string): Map<string, ParsedMaterial> {\r\n // 重置状态\r\n this.reset();\r\n\r\n // 按行分割文本\r\n const lines = text.split(/\\r?\\n/);\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n const line = lines[i].trim();\r\n\r\n // 跳过空行和注释\r\n if (line === '' || line.startsWith('#')) {\r\n continue;\r\n }\r\n\r\n this.parseLine(line, i + 1);\r\n }\r\n\r\n // 确保最后一个材质被添加\r\n this.finalizeCurrentMaterial();\r\n\r\n return this.materials;\r\n }\r\n\r\n /**\r\n * 重置解析器状态\r\n */\r\n private reset(): void {\r\n this.currentMaterial = null;\r\n this.materials = new Map();\r\n }\r\n\r\n /**\r\n * 解析单行\r\n */\r\n private parseLine(line: string, lineNum: number): void {\r\n // 分割指令和参数\r\n const parts = line.split(/\\s+/);\r\n const directive = parts[0].toLowerCase();\r\n\r\n try {\r\n switch (directive) {\r\n case 'newmtl':\r\n this.parseNewMaterial(parts);\r\n break;\r\n case 'kd':\r\n this.parseDiffuseColor(parts);\r\n break;\r\n case 'map_kd':\r\n this.parseDiffuseTexture(parts);\r\n break;\r\n case 'd':\r\n this.parseOpacity(parts);\r\n break;\r\n case 'tr':\r\n this.parseTransparency(parts);\r\n break;\r\n default:\r\n // 忽略不支持的指令 (Ka, Ks, Ns, illum, etc.)\r\n break;\r\n }\r\n } catch (e) {\r\n // 解析错误,跳过该行\r\n }\r\n }\r\n\r\n /**\r\n * 解析新材质定义 (newmtl name)\r\n */\r\n private parseNewMaterial(parts: string[]): void {\r\n // 完成当前材质\r\n this.finalizeCurrentMaterial();\r\n\r\n // 创建新材质\r\n const name = parts.length > 1 ? parts.slice(1).join(' ') : 'default';\r\n this.currentMaterial = this.createDefaultMaterial(name);\r\n }\r\n\r\n /**\r\n * 解析漫反射颜色 (Kd r g b)\r\n */\r\n private parseDiffuseColor(parts: string[]): void {\r\n if (!this.currentMaterial) {\r\n return;\r\n }\r\n\r\n if (parts.length < 4) {\r\n throw new Error('漫反射颜色数据不完整');\r\n }\r\n\r\n const r = parseFloat(parts[1]);\r\n const g = parseFloat(parts[2]);\r\n const b = parseFloat(parts[3]);\r\n\r\n if (isNaN(r) || isNaN(g) || isNaN(b)) {\r\n throw new Error('无效的漫反射颜色值');\r\n }\r\n\r\n this.currentMaterial.diffuseColor = [r, g, b];\r\n }\r\n\r\n /**\r\n * 解析漫反射纹理路径 (map_Kd path)\r\n */\r\n private parseDiffuseTexture(parts: string[]): void {\r\n if (!this.currentMaterial) {\r\n return;\r\n }\r\n\r\n if (parts.length < 2) {\r\n throw new Error('漫反射纹理路径不完整');\r\n }\r\n\r\n // 纹理路径可能包含空格,所以需要合并剩余部分\r\n const texturePath = parts.slice(1).join(' ');\r\n this.currentMaterial.diffuseTexture = texturePath;\r\n }\r\n\r\n /**\r\n * 解析透明度 (d factor)\r\n * d = 1.0 表示完全不透明,d = 0.0 表示完全透明\r\n */\r\n private parseOpacity(parts: string[]): void {\r\n if (!this.currentMaterial) {\r\n return;\r\n }\r\n\r\n if (parts.length < 2) {\r\n throw new Error('透明度数据不完整');\r\n }\r\n\r\n const opacity = parseFloat(parts[1]);\r\n\r\n if (isNaN(opacity)) {\r\n throw new Error('无效的透明度值');\r\n }\r\n\r\n this.currentMaterial.opacity = opacity;\r\n }\r\n\r\n /**\r\n * 解析透明度 (Tr factor)\r\n * Tr = 0.0 表示完全不透明,Tr = 1.0 表示完全透明\r\n * 与 d 相反,所以 opacity = 1 - Tr\r\n */\r\n private parseTransparency(parts: string[]): void {\r\n if (!this.currentMaterial) {\r\n return;\r\n }\r\n\r\n if (parts.length < 2) {\r\n throw new Error('透明度数据不完整');\r\n }\r\n\r\n const transparency = parseFloat(parts[1]);\r\n\r\n if (isNaN(transparency)) {\r\n throw new Error('无效的透明度值');\r\n }\r\n\r\n // Tr 是透明度,需要转换为不透明度\r\n this.currentMaterial.opacity = 1 - transparency;\r\n }\r\n\r\n /**\r\n * 创建默认材质\r\n */\r\n private createDefaultMaterial(name: string): ParsedMaterial {\r\n return {\r\n name,\r\n diffuseColor: [1, 1, 1], // 默认白色\r\n diffuseTexture: null,\r\n opacity: 1, // 默认完全不透明\r\n };\r\n }\r\n\r\n /**\r\n * 完成当前材质并添加到映射\r\n */\r\n private finalizeCurrentMaterial(): void {\r\n if (this.currentMaterial) {\r\n this.materials.set(this.currentMaterial.name, this.currentMaterial);\r\n }\r\n this.currentMaterial = null;\r\n }\r\n}\r\n","/**\n * OBJLoader - OBJ 文件加载器\n * 解析 OBJ 文件并生成 Mesh[],支持 MTL 材质\n */\n\nimport { Mesh } from '../mesh/Mesh';\nimport type { BoundingBox } from '../types';\nimport type { MaterialData } from '../types';\nimport { DEFAULT_OBJ_MATERIAL } from '../types';\nimport { computeBoundingBox } from '../utils';\nimport { LoadedMesh } from './GLBLoader';\nimport { OBJParser, ParsedOBJData, ParsedObject } from './OBJParser';\nimport { MTLParser, ParsedMaterial } from './MTLParser';\n\n/**\n * OBJLoader - OBJ 文件加载器\n * 解析 OBJ 文件并生成 LoadedMesh[]\n */\nexport class OBJLoader {\n private device: GPUDevice;\n private textureCache: Map<string, GPUTexture> = new Map();\n\n constructor(device: GPUDevice) {\n this.device = device;\n }\n\n /**\n * 加载 OBJ 文件\n * @param url OBJ 文件 URL\n * @returns 加载后的网格数组\n * \n * Requirements: 2.1, 2.2, 2.3\n */\n async load(url: string): Promise<LoadedMesh[]> {\n // Requirement 2.1: 获取文件内容\n const response = await fetch(url);\n \n // Requirement 2.2: 处理获取失败\n if (!response.ok) {\n throw new Error(`无法加载 OBJ 文件: ${url} (HTTP ${response.status})`);\n }\n\n const text = await response.text();\n \n // 计算基础 URL(用于加载 MTL 和纹理)\n const baseUrl = url.substring(0, url.lastIndexOf('/') + 1);\n \n // Requirement 2.3: 解析并返回 LoadedMesh 数组\n return this.parseFromText(text, baseUrl);\n }\n\n /**\n * 从文本解析 OBJ(用于直接传入内容)\n * @param text OBJ 文本内容\n * @param baseUrl 基础 URL(用于加载 MTL 和纹理)\n * @returns 加载后的网格数组\n * \n * Requirements: 2.1, 2.3\n */\n async parseFromText(text: string, baseUrl?: string): Promise<LoadedMesh[]> {\n // 解析 OBJ 文本\n const parser = new OBJParser();\n const parsedData = parser.parse(text);\n\n // 提取 MTL 文件引用\n const mtlFile = this.extractMTLReference(text);\n \n // 加载材质(如果有)\n let materials: Map<string, ParsedMaterial> = new Map();\n if (mtlFile && baseUrl) {\n materials = await this.loadMTL(baseUrl + mtlFile);\n }\n\n // 转换为 LoadedMesh 数组\n return this.createMeshes(parsedData, materials, baseUrl);\n }\n\n /**\n * 提取 MTL 文件引用\n */\n private extractMTLReference(text: string): string | null {\n const lines = text.split(/\\r?\\n/);\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed.startsWith('mtllib ')) {\n return trimmed.substring(7).trim();\n }\n }\n return null;\n }\n\n /**\n * 加载 MTL 材质文件\n * Requirement 4.1, 4.4: 加载 MTL 文件,失败时使用默认材质\n */\n private async loadMTL(url: string): Promise<Map<string, ParsedMaterial>> {\n try {\n const response = await fetch(url);\n if (!response.ok) {\n return new Map();\n }\n const text = await response.text();\n const mtlParser = new MTLParser();\n return mtlParser.parse(text);\n } catch (e) {\n return new Map();\n }\n }\n\n /**\n * 创建 LoadedMesh 数组\n */\n private async createMeshes(\n parsedData: ParsedOBJData,\n materials: Map<string, ParsedMaterial>,\n baseUrl?: string\n ): Promise<LoadedMesh[]> {\n const loadedMeshes: LoadedMesh[] = [];\n\n for (const obj of parsedData.objects) {\n // 跳过空对象\n if (obj.indices.length === 0) {\n continue;\n }\n\n const loadedMesh = await this.createMesh(obj, materials, baseUrl);\n if (loadedMesh) {\n loadedMeshes.push(loadedMesh);\n }\n }\n\n return loadedMeshes;\n }\n\n /**\n * 创建单个 Mesh\n */\n private async createMesh(\n obj: ParsedObject,\n materials: Map<string, ParsedMaterial>,\n baseUrl?: string\n ): Promise<LoadedMesh | null> {\n const hasNormals = obj.normals.length > 0;\n const hasUVs = obj.uvs.length > 0;\n const vertexCount = obj.positions.length / 3;\n\n // 如果没有法线,生成平面法线\n let normals = obj.normals;\n if (!hasNormals) {\n normals = this.generateFlatNormals(obj.positions, obj.indices);\n }\n\n // 创建交错顶点数据: position(3) + normal(3) + uv(2)\n const stride = hasUVs ? 8 : 6; // floats per vertex\n const vertexData = new Float32Array(vertexCount * stride);\n\n for (let i = 0; i < vertexCount; i++) {\n const baseIdx = i * stride;\n // Position\n vertexData[baseIdx + 0] = obj.positions[i * 3 + 0];\n vertexData[baseIdx + 1] = obj.positions[i * 3 + 1];\n vertexData[baseIdx + 2] = obj.positions[i * 3 + 2];\n // Normal\n vertexData[baseIdx + 3] = normals[i * 3 + 0];\n vertexData[baseIdx + 4] = normals[i * 3 + 1];\n vertexData[baseIdx + 5] = normals[i * 3 + 2];\n // UV (if present)\n if (hasUVs) {\n vertexData[baseIdx + 6] = obj.uvs[i * 2 + 0];\n vertexData[baseIdx + 7] = obj.uvs[i * 2 + 1];\n }\n }\n\n // 创建顶点缓冲区\n const vertexBuffer = this.device.createBuffer({\n size: vertexData.byteLength,\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\n });\n this.device.queue.writeBuffer(vertexBuffer, 0, vertexData);\n\n // 创建索引缓冲区\n // Requirement 3.4: 根据顶点数选择索引格式\n const indexCount = obj.indices.length;\n let indexBuffer: GPUBuffer;\n let indexFormat: 'uint16' | 'uint32' = 'uint16';\n\n if (vertexCount > 65535) {\n indexFormat = 'uint32';\n const indexData = new Uint32Array(obj.indices);\n indexBuffer = this.device.createBuffer({\n size: indexData.byteLength,\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\n });\n this.device.queue.writeBuffer(indexBuffer, 0, indexData);\n } else {\n const indexData = new Uint16Array(obj.indices);\n // WebGPU 要求 writeBuffer 的字节数必须是 4 的倍数\n const alignedSize = Math.ceil(indexData.byteLength / 4) * 4;\n const alignedBuffer = new Uint8Array(alignedSize);\n alignedBuffer.set(new Uint8Array(indexData.buffer, indexData.byteOffset, indexData.byteLength));\n indexBuffer = this.device.createBuffer({\n size: alignedSize,\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\n });\n this.device.queue.writeBuffer(indexBuffer, 0, alignedBuffer);\n }\n\n // Requirement 3.5: 计算 bounding box\n const boundingBox = this.computeBoundingBoxFromPositions(obj.positions);\n\n // 创建 Mesh\n const mesh = new Mesh(vertexBuffer, vertexCount, indexBuffer, indexCount, boundingBox);\n mesh.hasUV = hasUVs;\n mesh.indexFormat = indexFormat;\n\n // 创建材质\n const material = await this.createMaterial(obj.materialName, materials, baseUrl);\n\n return { mesh, material };\n }\n\n /**\n * 生成平面法线(当 OBJ 缺少法线数据时)\n * Requirement 3.2: 从面几何计算平面法线\n */\n private generateFlatNormals(positions: number[], indices: number[]): number[] {\n const normals = new Array(positions.length).fill(0);\n\n // 遍历每个三角形\n for (let i = 0; i < indices.length; i += 3) {\n const i0 = indices[i];\n const i1 = indices[i + 1];\n const i2 = indices[i + 2];\n\n // 获取三角形顶点\n const v0 = [positions[i0 * 3], positions[i0 * 3 + 1], positions[i0 * 3 + 2]];\n const v1 = [positions[i1 * 3], positions[i1 * 3 + 1], positions[i1 * 3 + 2]];\n const v2 = [positions[i2 * 3], positions[i2 * 3 + 1], positions[i2 * 3 + 2]];\n\n // 计算边向量\n const edge1 = [v1[0] - v0[0], v1[1] - v0[1], v1[2] - v0[2]];\n const edge2 = [v2[0] - v0[0], v2[1] - v0[1], v2[2] - v0[2]];\n\n // 计算叉积(面法线)\n const nx = edge1[1] * edge2[2] - edge1[2] * edge2[1];\n const ny = edge1[2] * edge2[0] - edge1[0] * edge2[2];\n const nz = edge1[0] * edge2[1] - edge1[1] * edge2[0];\n\n // 归一化\n const len = Math.sqrt(nx * nx + ny * ny + nz * nz);\n const normalizedNx = len > 0 ? nx / len : 0;\n const normalizedNy = len > 0 ? ny / len : 1;\n const normalizedNz = len > 0 ? nz / len : 0;\n\n // 为三角形的每个顶点设置相同的法线(平面着色)\n for (const idx of [i0, i1, i2]) {\n normals[idx * 3 + 0] = normalizedNx;\n normals[idx * 3 + 1] = normalizedNy;\n normals[idx * 3 + 2] = normalizedNz;\n }\n }\n\n return normals;\n }\n\n /**\n * 计算顶点数据的 bounding box\n * Requirement 3.5: 计算并存储 bounding box 信息\n */\n private computeBoundingBoxFromPositions(positions: number[]): BoundingBox {\n return computeBoundingBox(positions);\n }\n\n /**\n * 创建材质数据\n * Requirement 4.3: 将材质关联到网格\n */\n private async createMaterial(\n materialName: string | null,\n materials: Map<string, ParsedMaterial>,\n baseUrl?: string\n ): Promise<MaterialData> {\n if (!materialName || !materials.has(materialName)) {\n return { ...DEFAULT_OBJ_MATERIAL };\n }\n\n const parsedMaterial = materials.get(materialName)!;\n \n // 转换为 MaterialData - OBJ 模型默认双面渲染\n const material: MaterialData = {\n baseColorFactor: [\n parsedMaterial.diffuseColor[0],\n parsedMaterial.diffuseColor[1],\n parsedMaterial.diffuseColor[2],\n parsedMaterial.opacity,\n ],\n baseColorTexture: null,\n metallicFactor: 0,\n roughnessFactor: 0.5,\n doubleSided: true,\n };\n\n // 加载漫反射纹理\n if (parsedMaterial.diffuseTexture && baseUrl) {\n material.baseColorTexture = await this.loadTexture(baseUrl + parsedMaterial.diffuseTexture);\n }\n\n return material;\n }\n\n /**\n * 加载纹理\n * Requirement 4.5, 6.3: 加载纹理,失败时使用 null\n */\n private async loadTexture(url: string): Promise<GPUTexture | null> {\n // 检查缓存\n if (this.textureCache.has(url)) {\n return this.textureCache.get(url)!;\n }\n\n try {\n const response = await fetch(url);\n if (!response.ok) {\n return null;\n }\n\n const blob = await response.blob();\n const imageBitmap = await createImageBitmap(blob);\n\n // 创建 GPU 纹理\n const gpuTexture = this.device.createTexture({\n size: [imageBitmap.width, imageBitmap.height, 1],\n format: 'rgba8unorm',\n usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,\n });\n\n this.device.queue.copyExternalImageToTexture(\n { source: imageBitmap },\n { texture: gpuTexture },\n [imageBitmap.width, imageBitmap.height]\n );\n\n // 缓存纹理\n this.textureCache.set(url, gpuTexture);\n\n return gpuTexture;\n } catch (error) {\n return null;\n }\n }\n}\n","/**\r\n * PLYLoader - 加载 3D Gaussian Splatting 的 PLY 文件\r\n * 支持 binary_little_endian 和 binary_big_endian 格式\r\n * 支持多种数据类型: float, double, int, uint, char, uchar, short, ushort\r\n */\r\n\r\n/**\r\n * CPU 端 Splat 数据结构\r\n */\r\nexport type SplatCPU = {\r\n mean: [number, number, number];\r\n scale: [number, number, number];\r\n rotation: [number, number, number, number]; // 四元数顺序: [w, x, y, z]\r\n colorDC: [number, number, number];\r\n opacity: number;\r\n shRest?: Float32Array; // 完整 SH 系数: L1(9) + L2(15) + L3(21) = 45\r\n};\r\n\r\n/**\r\n * PLY 数据类型到字节大小的映射\r\n */\r\nconst TYPE_SIZES: Record<string, number> = {\r\n char: 1,\r\n uchar: 1,\r\n int8: 1,\r\n uint8: 1,\r\n short: 2,\r\n ushort: 2,\r\n int16: 2,\r\n uint16: 2,\r\n int: 4,\r\n uint: 4,\r\n int32: 4,\r\n uint32: 4,\r\n float: 4,\r\n float32: 4,\r\n double: 8,\r\n float64: 8,\r\n};\r\n\r\n/**\r\n * PLY 文件格式类型\r\n */\r\ntype PLYFormat = \"binary_little_endian\" | \"binary_big_endian\" | \"ascii\";\r\n\r\n/**\r\n * PLY 属性信息\r\n */\r\ntype PropertyInfo = {\r\n name: string;\r\n type: string;\r\n byteOffset: number;\r\n byteSize: number;\r\n};\r\n\r\n/**\r\n * 解析 PLY header\r\n */\r\nfunction parseHeader(headerText: string): {\r\n vertexCount: number;\r\n properties: PropertyInfo[];\r\n stride: number;\r\n format: PLYFormat;\r\n} {\r\n const lines = headerText.split(\"\\n\");\r\n let vertexCount = 0;\r\n let format: PLYFormat = \"binary_little_endian\";\r\n const properties: PropertyInfo[] = [];\r\n let currentOffset = 0;\r\n let inVertexElement = false;\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n\r\n // 解析格式\r\n if (trimmed.startsWith(\"format \")) {\r\n const parts = trimmed.split(/\\s+/);\r\n const formatStr = parts[1];\r\n if (formatStr === \"ascii\") {\r\n format = \"ascii\";\r\n } else if (formatStr === \"binary_big_endian\") {\r\n format = \"binary_big_endian\";\r\n } else if (formatStr === \"binary_little_endian\") {\r\n format = \"binary_little_endian\";\r\n } else {\r\n throw new Error(`不支持的 PLY 格式: ${formatStr}`);\r\n }\r\n }\r\n\r\n // 解析 element vertex N\r\n if (trimmed.startsWith(\"element vertex\")) {\r\n const parts = trimmed.split(/\\s+/);\r\n vertexCount = parseInt(parts[2], 10);\r\n inVertexElement = true;\r\n } else if (trimmed.startsWith(\"element \")) {\r\n // 其他 element 类型,停止收集属性\r\n inVertexElement = false;\r\n }\r\n\r\n // 解析 property <type> <name>(只收集 vertex element 的属性)\r\n if (inVertexElement && trimmed.startsWith(\"property\")) {\r\n const parts = trimmed.split(/\\s+/);\r\n // 跳过 list 类型属性\r\n if (parts[1] === \"list\") {\r\n continue;\r\n }\r\n const type = parts[1];\r\n const name = parts[2];\r\n const byteSize = TYPE_SIZES[type];\r\n\r\n if (byteSize === undefined) {\r\n throw new Error(`不支持的 PLY 属性类型: ${type}`);\r\n }\r\n\r\n properties.push({\r\n name,\r\n type,\r\n byteOffset: currentOffset,\r\n byteSize,\r\n });\r\n\r\n currentOffset += byteSize;\r\n }\r\n }\r\n\r\n return {\r\n vertexCount,\r\n properties,\r\n stride: currentOffset,\r\n format,\r\n };\r\n}\r\n\r\n/**\r\n * 验证 PLY 文件魔数\r\n */\r\nfunction validatePLYMagic(buffer: ArrayBuffer): void {\r\n const bytes = new Uint8Array(buffer, 0, Math.min(buffer.byteLength, 10));\r\n const decoder = new TextDecoder(\"ascii\");\r\n const header = decoder.decode(bytes);\r\n\r\n if (!header.startsWith(\"ply\")) {\r\n throw new Error(\"无效的 PLY 文件: 缺少 'ply' 魔数标识\");\r\n }\r\n}\r\n\r\n/**\r\n * 从 ArrayBuffer 中提取 header 文本和数据起始位置\r\n */\r\nfunction extractHeader(buffer: ArrayBuffer): {\r\n headerText: string;\r\n dataOffset: number;\r\n} {\r\n // 首先验证魔数\r\n validatePLYMagic(buffer);\r\n\r\n const bytes = new Uint8Array(buffer);\r\n const decoder = new TextDecoder(\"ascii\");\r\n\r\n // 查找 \"end_header\\n\" 或 \"end_header\\r\\n\" 标记\r\n const maxHeaderSize = Math.min(bytes.length, 10000); // header 不应超过 10KB\r\n const headerBytes = bytes.slice(0, maxHeaderSize);\r\n const headerText = decoder.decode(headerBytes);\r\n\r\n // 支持 Unix (\\n) 和 Windows (\\r\\n) 换行符\r\n let endIndex = headerText.indexOf(\"end_header\\n\");\r\n let markerLength = \"end_header\\n\".length;\r\n\r\n if (endIndex === -1) {\r\n endIndex = headerText.indexOf(\"end_header\\r\\n\");\r\n markerLength = \"end_header\\r\\n\".length;\r\n }\r\n\r\n if (endIndex === -1) {\r\n throw new Error(\"无法找到 PLY header 结束标记 'end_header'\");\r\n }\r\n\r\n const dataOffset = endIndex + markerLength;\r\n return {\r\n headerText: headerText.substring(0, endIndex),\r\n dataOffset,\r\n };\r\n}\r\n\r\n/**\r\n * 构建属性名到属性信息的映射\r\n */\r\nfunction buildPropertyMap(\r\n properties: PropertyInfo[]\r\n): Map<string, PropertyInfo> {\r\n const map = new Map<string, PropertyInfo>();\r\n for (const prop of properties) {\r\n map.set(prop.name, prop);\r\n }\r\n return map;\r\n}\r\n\r\n/**\r\n * 从 DataView 读取属性值(支持多种数据类型)\r\n */\r\nfunction readProperty(\r\n dataView: DataView,\r\n baseOffset: number,\r\n prop: PropertyInfo | undefined,\r\n littleEndian: boolean\r\n): number {\r\n if (prop === undefined) {\r\n return 0;\r\n }\r\n\r\n const offset = baseOffset + prop.byteOffset;\r\n\r\n switch (prop.type) {\r\n case \"float\":\r\n case \"float32\":\r\n return dataView.getFloat32(offset, littleEndian);\r\n case \"double\":\r\n case \"float64\":\r\n return dataView.getFloat64(offset, littleEndian);\r\n case \"int\":\r\n case \"int32\":\r\n return dataView.getInt32(offset, littleEndian);\r\n case \"uint\":\r\n case \"uint32\":\r\n return dataView.getUint32(offset, littleEndian);\r\n case \"short\":\r\n case \"int16\":\r\n return dataView.getInt16(offset, littleEndian);\r\n case \"ushort\":\r\n case \"uint16\":\r\n return dataView.getUint16(offset, littleEndian);\r\n case \"char\":\r\n case \"int8\":\r\n return dataView.getInt8(offset);\r\n case \"uchar\":\r\n case \"uint8\":\r\n return dataView.getUint8(offset);\r\n default:\r\n return dataView.getFloat32(offset, littleEndian);\r\n }\r\n}\r\n\r\n/**\r\n * Sigmoid 函数,用于将 opacity 从原始值转换为 [0, 1]\r\n */\r\nfunction sigmoid(x: number): number {\r\n return 1 / (1 + Math.exp(-x));\r\n}\r\n\r\n/**\r\n * 加载并解析 PLY 文件\r\n * @param url PLY 文件的 URL\r\n * @returns SplatCPU 数组\r\n */\r\nexport async function loadPLY(url: string): Promise<SplatCPU[]> {\r\n // 获取文件\r\n const response = await fetch(url);\r\n if (!response.ok) {\r\n throw new Error(`无法加载 PLY 文件: ${url}`);\r\n }\r\n const buffer = await response.arrayBuffer();\r\n\r\n // 解析 header\r\n const { headerText, dataOffset } = extractHeader(buffer);\r\n const { vertexCount, properties, stride, format } = parseHeader(headerText);\r\n\r\n // 验证格式\r\n if (format === \"ascii\") {\r\n throw new Error(\"不支持 ASCII 格式的 PLY 文件,请使用 binary_little_endian 或 binary_big_endian 格式\");\r\n }\r\n\r\n const littleEndian = format === \"binary_little_endian\";\r\n\r\n // 构建属性映射\r\n const propMap = buildPropertyMap(properties);\r\n\r\n // 获取各属性的信息\r\n const props = {\r\n x: propMap.get(\"x\"),\r\n y: propMap.get(\"y\"),\r\n z: propMap.get(\"z\"),\r\n scale_0: propMap.get(\"scale_0\"),\r\n scale_1: propMap.get(\"scale_1\"),\r\n scale_2: propMap.get(\"scale_2\"),\r\n rot_0: propMap.get(\"rot_0\"),\r\n rot_1: propMap.get(\"rot_1\"),\r\n rot_2: propMap.get(\"rot_2\"),\r\n rot_3: propMap.get(\"rot_3\"),\r\n f_dc_0: propMap.get(\"f_dc_0\"),\r\n f_dc_1: propMap.get(\"f_dc_1\"),\r\n f_dc_2: propMap.get(\"f_dc_2\"),\r\n opacity: propMap.get(\"opacity\"),\r\n };\r\n\r\n // 收集 f_rest_* 字段并按索引排序(用于 SH 系数)\r\n const shRestProps = properties\r\n .filter((p) => p.name.startsWith(\"f_rest_\"))\r\n .sort((a, b) => {\r\n const idxA = parseInt(a.name.replace(\"f_rest_\", \"\"), 10);\r\n const idxB = parseInt(b.name.replace(\"f_rest_\", \"\"), 10);\r\n return idxA - idxB;\r\n });\r\n\r\n // 打印前几个 f_rest_* 属性的名称,验证排序是否正确\r\n if (shRestProps.length > 0) {\r\n // 属性顺序验证(静默)\r\n }\r\n\r\n // 创建 DataView 用于读取二进制数据\r\n const dataView = new DataView(buffer, dataOffset);\r\n\r\n // 预分配共享的 SH 系数数组(优化内存)\r\n const shRestBuffer = new Float32Array(vertexCount * 45);\r\n\r\n // 解析每个 vertex\r\n const splats: SplatCPU[] = new Array(vertexCount);\r\n const SH_C0 = 0.28209479177387814;\r\n\r\n for (let i = 0; i < vertexCount; i++) {\r\n const base = i * stride;\r\n\r\n // 读取位置\r\n const x = readProperty(dataView, base, props.x, littleEndian);\r\n const y = readProperty(dataView, base, props.y, littleEndian);\r\n const z = readProperty(dataView, base, props.z, littleEndian);\r\n\r\n // 读取缩放 (exp 转换,因为 3DGS 存储的是 log scale)\r\n const scale_0 = Math.exp(readProperty(dataView, base, props.scale_0, littleEndian));\r\n const scale_1 = Math.exp(readProperty(dataView, base, props.scale_1, littleEndian));\r\n const scale_2 = Math.exp(readProperty(dataView, base, props.scale_2, littleEndian));\r\n\r\n // 读取旋转四元数\r\n const rot_0 = readProperty(dataView, base, props.rot_0, littleEndian);\r\n const rot_1 = readProperty(dataView, base, props.rot_1, littleEndian);\r\n const rot_2 = readProperty(dataView, base, props.rot_2, littleEndian);\r\n const rot_3 = readProperty(dataView, base, props.rot_3, littleEndian);\r\n\r\n // 归一化四元数\r\n const qlen = Math.sqrt(\r\n rot_0 * rot_0 + rot_1 * rot_1 + rot_2 * rot_2 + rot_3 * rot_3\r\n );\r\n const qnorm = qlen > 0 ? 1 / qlen : 1;\r\n\r\n // 读取颜色 DC 系数 (SH0)\r\n // 注意:不要在这里 clamp,因为 SH 贡献可能是负数\r\n // 最终颜色会在 shader 中 clamp\r\n const f_dc_0 = readProperty(dataView, base, props.f_dc_0, littleEndian);\r\n const f_dc_1 = readProperty(dataView, base, props.f_dc_1, littleEndian);\r\n const f_dc_2 = readProperty(dataView, base, props.f_dc_2, littleEndian);\r\n\r\n const colorR = 0.5 + SH_C0 * f_dc_0;\r\n const colorG = 0.5 + SH_C0 * f_dc_1;\r\n const colorB = 0.5 + SH_C0 * f_dc_2;\r\n\r\n // 读取 opacity (sigmoid 转换)\r\n const rawOpacity = readProperty(dataView, base, props.opacity, littleEndian);\r\n const opacity = sigmoid(rawOpacity);\r\n\r\n // 读取完整 SH 系数到共享 buffer\r\n const shOffset = i * 45;\r\n const shRest = shRestBuffer.subarray(shOffset, shOffset + 45);\r\n\r\n // PLY 文件中 f_rest_* 的顺序是 channel-first (参考 visionary):\r\n // [R0..R14, G0..G14, B0..B14] - 每通道 15 个系数\r\n // \r\n // 我们转换为 interleaved 格式 (与 visionary 一致):\r\n // [R0,G0,B0, R1,G1,B1, ...] - 每个基函数的 RGB 连续存储\r\n //\r\n // 这样 shader 中可以用 sh_coef(idx) 返回 vec3(R,G,B)\r\n //\r\n // 注意:shRestProps 的数量可能是 45 (完整 SH) 或更少\r\n // 实际 PLY 文件的 f_rest_* 数量 = (shDegree+1)^2 - 1 个系数 × 3 通道\r\n // 例如 shDegree=3 时: (3+1)^2 - 1 = 15 个系数/通道,共 45 个 f_rest_*\r\n\r\n const totalRestCount = shRestProps.length;\r\n const perChannel = Math.floor(totalRestCount / 3); // 每通道的系数数量\r\n \r\n for (let coefIdx = 0; coefIdx < perChannel; coefIdx++) {\r\n // PLY 中: R 在 [0..perChannel-1], G 在 [perChannel..2*perChannel-1], B 在 [2*perChannel..3*perChannel-1]\r\n const srcR = coefIdx;\r\n const srcG = perChannel + coefIdx;\r\n const srcB = 2 * perChannel + coefIdx;\r\n \r\n // 目标: interleaved [R0,G0,B0, R1,G1,B1, ...]\r\n const dstBase = coefIdx * 3;\r\n \r\n shRest[dstBase + 0] = srcR < shRestProps.length ? readProperty(dataView, base, shRestProps[srcR], littleEndian) : 0;\r\n shRest[dstBase + 1] = srcG < shRestProps.length ? readProperty(dataView, base, shRestProps[srcG], littleEndian) : 0;\r\n shRest[dstBase + 2] = srcB < shRestProps.length ? readProperty(dataView, base, shRestProps[srcB], littleEndian) : 0;\r\n }\r\n\r\n // 打印第一个点的 SH 系数用于调试\r\n if (i === 0) {\r\n // 调试信息(静默)\r\n }\r\n\r\n splats[i] = {\r\n mean: [x, y, z],\r\n scale: [scale_0, scale_1, scale_2],\r\n rotation: [\r\n rot_0 * qnorm,\r\n rot_1 * qnorm,\r\n rot_2 * qnorm,\r\n rot_3 * qnorm,\r\n ],\r\n colorDC: [colorR, colorG, colorB],\r\n opacity,\r\n shRest,\r\n };\r\n }\r\n\r\n return splats;\r\n}\r\n","/**\r\n * PLYLoaderMobile - 移动端优化的 PLY 加载器\r\n * \r\n * 优化点:\r\n * 1. 直接输出 GPU buffer 格式,避免中间对象\r\n * 2. 流式降采样,减少内存峰值\r\n * 3. 可选跳过 SH 系数(移动端 L0 模式)\r\n * 4. 使用 TypedArray 而非对象数组\r\n * 5. 支持多种 PLY 数据类型\r\n * 6. 确定性采样(基于文件内容的种子)\r\n */\r\n\r\n/**\r\n * PLY 数据类型到字节大小的映射\r\n */\r\nconst TYPE_SIZES: Record<string, number> = {\r\n char: 1,\r\n uchar: 1,\r\n int8: 1,\r\n uint8: 1,\r\n short: 2,\r\n ushort: 2,\r\n int16: 2,\r\n uint16: 2,\r\n int: 4,\r\n uint: 4,\r\n int32: 4,\r\n uint32: 4,\r\n float: 4,\r\n float32: 4,\r\n double: 8,\r\n float64: 8,\r\n};\r\n\r\n/**\r\n * PLY 文件格式类型\r\n */\r\ntype PLYFormat = \"binary_little_endian\" | \"binary_big_endian\" | \"ascii\";\r\n\r\n/**\r\n * 移动端加载配置\r\n */\r\nexport interface MobileLoadOptions {\r\n /** 最大 splat 数量,超过则降采样 */\r\n maxSplats?: number;\r\n /** 是否加载 SH 系数(false 时只加载 DC 颜色) */\r\n loadSH?: boolean;\r\n /** 进度回调 */\r\n onProgress?: (loaded: number, total: number) => void;\r\n /** 随机种子(用于确定性采样,默认使用文件大小作为种子) */\r\n seed?: number;\r\n}\r\n\r\n/**\r\n * 紧凑 Splat 数据(用于移动端)\r\n * 直接返回 Float32Array,而非对象数组\r\n */\r\nexport interface CompactSplatData {\r\n /** splat 数量 */\r\n count: number;\r\n /** 位置数据 Float32Array [x,y,z, x,y,z, ...] */\r\n positions: Float32Array;\r\n /** 缩放数据 Float32Array [sx,sy,sz, sx,sy,sz, ...] */\r\n scales: Float32Array;\r\n /** 旋转四元数 Float32Array [w,x,y,z, w,x,y,z, ...] */\r\n rotations: Float32Array;\r\n /** DC 颜色 Float32Array [r,g,b, r,g,b, ...] */\r\n colors: Float32Array;\r\n /** 不透明度 Float32Array [a, a, ...] */\r\n opacities: Float32Array;\r\n /** SH 系数(可选)Float32Array,每个 splat 45 个系数 */\r\n shCoeffs?: Float32Array;\r\n}\r\n\r\n/**\r\n * PLY 属性信息\r\n */\r\ninterface PropertyInfo {\r\n name: string;\r\n type: string;\r\n byteOffset: number;\r\n byteSize: number;\r\n}\r\n\r\n/**\r\n * 验证 PLY 文件魔数\r\n */\r\nfunction validatePLYMagic(buffer: ArrayBuffer): void {\r\n const bytes = new Uint8Array(buffer, 0, Math.min(buffer.byteLength, 10));\r\n const decoder = new TextDecoder(\"ascii\");\r\n const header = decoder.decode(bytes);\r\n\r\n if (!header.startsWith(\"ply\")) {\r\n throw new Error(\"无效的 PLY 文件: 缺少 'ply' 魔数标识\");\r\n }\r\n}\r\n\r\n/**\r\n * 解析 PLY header\r\n */\r\nfunction parseHeader(headerText: string): {\r\n vertexCount: number;\r\n properties: PropertyInfo[];\r\n stride: number;\r\n format: PLYFormat;\r\n} {\r\n const lines = headerText.split(\"\\n\");\r\n let vertexCount = 0;\r\n let format: PLYFormat = \"binary_little_endian\";\r\n const properties: PropertyInfo[] = [];\r\n let currentOffset = 0;\r\n let inVertexElement = false;\r\n\r\n for (const line of lines) {\r\n const trimmed = line.trim();\r\n\r\n // 解析格式\r\n if (trimmed.startsWith(\"format \")) {\r\n const parts = trimmed.split(/\\s+/);\r\n const formatStr = parts[1];\r\n if (formatStr === \"ascii\") {\r\n format = \"ascii\";\r\n } else if (formatStr === \"binary_big_endian\") {\r\n format = \"binary_big_endian\";\r\n } else if (formatStr === \"binary_little_endian\") {\r\n format = \"binary_little_endian\";\r\n } else {\r\n throw new Error(`不支持的 PLY 格式: ${formatStr}`);\r\n }\r\n }\r\n\r\n // 解析 element vertex N\r\n if (trimmed.startsWith(\"element vertex\")) {\r\n const parts = trimmed.split(/\\s+/);\r\n vertexCount = parseInt(parts[2], 10);\r\n inVertexElement = true;\r\n } else if (trimmed.startsWith(\"element \")) {\r\n inVertexElement = false;\r\n }\r\n\r\n // 解析 property(只收集 vertex element 的属性)\r\n if (inVertexElement && trimmed.startsWith(\"property\")) {\r\n const parts = trimmed.split(/\\s+/);\r\n if (parts[1] === \"list\") {\r\n continue;\r\n }\r\n const type = parts[1];\r\n const name = parts[2];\r\n const byteSize = TYPE_SIZES[type];\r\n\r\n if (byteSize === undefined) {\r\n throw new Error(`不支持的 PLY 属性类型: ${type}`);\r\n }\r\n\r\n properties.push({\r\n name,\r\n type,\r\n byteOffset: currentOffset,\r\n byteSize,\r\n });\r\n\r\n currentOffset += byteSize;\r\n }\r\n }\r\n\r\n return { vertexCount, properties, stride: currentOffset, format };\r\n}\r\n\r\n/**\r\n * 提取 header\r\n */\r\nfunction extractHeader(buffer: ArrayBuffer): {\r\n headerText: string;\r\n dataOffset: number;\r\n} {\r\n // 首先验证魔数\r\n validatePLYMagic(buffer);\r\n\r\n const bytes = new Uint8Array(buffer);\r\n const decoder = new TextDecoder(\"ascii\");\r\n\r\n const maxHeaderSize = Math.min(bytes.length, 10000);\r\n const headerBytes = bytes.slice(0, maxHeaderSize);\r\n const headerText = decoder.decode(headerBytes);\r\n\r\n // 支持 Unix (\\n) 和 Windows (\\r\\n) 换行符\r\n let endIndex = headerText.indexOf(\"end_header\\n\");\r\n let markerLength = \"end_header\\n\".length;\r\n\r\n if (endIndex === -1) {\r\n endIndex = headerText.indexOf(\"end_header\\r\\n\");\r\n markerLength = \"end_header\\r\\n\".length;\r\n }\r\n\r\n if (endIndex === -1) {\r\n throw new Error(\"无法找到 PLY header 结束标记 'end_header'\");\r\n }\r\n\r\n const dataOffset = endIndex + markerLength;\r\n return {\r\n headerText: headerText.substring(0, endIndex),\r\n dataOffset,\r\n };\r\n}\r\n\r\n/**\r\n * Sigmoid 函数\r\n */\r\nfunction sigmoid(x: number): number {\r\n return 1 / (1 + Math.exp(-x));\r\n}\r\n\r\n/**\r\n * 从 DataView 读取属性值(支持多种数据类型)\r\n */\r\nfunction readProperty(\r\n dataView: DataView,\r\n offset: number,\r\n type: string,\r\n littleEndian: boolean\r\n): number {\r\n switch (type) {\r\n case \"float\":\r\n case \"float32\":\r\n return dataView.getFloat32(offset, littleEndian);\r\n case \"double\":\r\n case \"float64\":\r\n return dataView.getFloat64(offset, littleEndian);\r\n case \"int\":\r\n case \"int32\":\r\n return dataView.getInt32(offset, littleEndian);\r\n case \"uint\":\r\n case \"uint32\":\r\n return dataView.getUint32(offset, littleEndian);\r\n case \"short\":\r\n case \"int16\":\r\n return dataView.getInt16(offset, littleEndian);\r\n case \"ushort\":\r\n case \"uint16\":\r\n return dataView.getUint16(offset, littleEndian);\r\n case \"char\":\r\n case \"int8\":\r\n return dataView.getInt8(offset);\r\n case \"uchar\":\r\n case \"uint8\":\r\n return dataView.getUint8(offset);\r\n default:\r\n return dataView.getFloat32(offset, littleEndian);\r\n }\r\n}\r\n\r\n/**\r\n * 简单的确定性伪随机数生成器 (Mulberry32)\r\n * 给定相同的种子,总是产生相同的序列\r\n */\r\nfunction createSeededRandom(seed: number): () => number {\r\n let state = seed >>> 0;\r\n return () => {\r\n state = (state + 0x6d2b79f5) >>> 0;\r\n let t = state;\r\n t = Math.imul(t ^ (t >>> 15), t | 1);\r\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\r\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\r\n };\r\n}\r\n\r\nconst SH_C0 = 0.28209479177387814;\r\n\r\n/**\r\n * 智能采样:基于重要性(opacity * scale)采样\r\n * 使用 Floyd 采样算法 + 确定性种子,保证相同文件产生相同结果\r\n * 时间复杂度 O(n),空间复杂度 O(k),其中 k 是采样数量\r\n */\r\nfunction computeImportanceSampling(\r\n buffer: ArrayBuffer,\r\n dataOffset: number,\r\n stride: number,\r\n totalCount: number,\r\n sampleCount: number,\r\n opacityOffset: number,\r\n opacityType: string,\r\n scale0Offset: number,\r\n scale0Type: string,\r\n scale1Offset: number,\r\n scale1Type: string,\r\n scale2Offset: number,\r\n scale2Type: string,\r\n littleEndian: boolean,\r\n seed: number\r\n): Uint32Array {\r\n const dataView = new DataView(buffer, dataOffset);\r\n const random = createSeededRandom(seed);\r\n\r\n // 计算每个 splat 的重要性分数\r\n const importance = new Float32Array(totalCount);\r\n let totalImportance = 0;\r\n\r\n for (let i = 0; i < totalCount; i++) {\r\n const base = i * stride;\r\n\r\n // 获取 opacity(需要 sigmoid 转换)\r\n const rawOpacity = opacityOffset >= 0\r\n ? readProperty(dataView, base + opacityOffset, opacityType, littleEndian)\r\n : 0;\r\n const opacity = sigmoid(rawOpacity);\r\n\r\n // 获取 scale(需要 exp 转换)\r\n const s0 = scale0Offset >= 0\r\n ? Math.exp(readProperty(dataView, base + scale0Offset, scale0Type, littleEndian))\r\n : 1;\r\n const s1 = scale1Offset >= 0\r\n ? Math.exp(readProperty(dataView, base + scale1Offset, scale1Type, littleEndian))\r\n : 1;\r\n const s2 = scale2Offset >= 0\r\n ? Math.exp(readProperty(dataView, base + scale2Offset, scale2Type, littleEndian))\r\n : 1;\r\n const maxScale = Math.max(s0, s1, s2);\r\n\r\n // 重要性分数:opacity * scale\r\n importance[i] = opacity * maxScale;\r\n totalImportance += importance[i];\r\n }\r\n\r\n // 使用加权随机采样(Reservoir Sampling with Weights)\r\n // 这是一种 O(n) 的算法,比完整排序更高效\r\n const result = new Uint32Array(sampleCount);\r\n const weights = new Float32Array(sampleCount);\r\n\r\n // 初始化:填充前 sampleCount 个元素\r\n for (let i = 0; i < Math.min(sampleCount, totalCount); i++) {\r\n result[i] = i;\r\n // 使用 -log(random) / weight 作为键值(Efraimidis-Spirakis 算法)\r\n weights[i] = importance[i] > 0 ? -Math.log(random()) / importance[i] : Infinity;\r\n }\r\n\r\n // 构建最小堆(用于维护 top-k)\r\n // 简化实现:直接找最大权重的位置\r\n let maxWeightIdx = 0;\r\n let maxWeight = weights[0];\r\n for (let i = 1; i < sampleCount; i++) {\r\n if (weights[i] > maxWeight) {\r\n maxWeight = weights[i];\r\n maxWeightIdx = i;\r\n }\r\n }\r\n\r\n // 处理剩余元素\r\n for (let i = sampleCount; i < totalCount; i++) {\r\n const key = importance[i] > 0 ? -Math.log(random()) / importance[i] : Infinity;\r\n\r\n // 如果当前元素的键值小于堆中最大的键值,替换它\r\n if (key < maxWeight) {\r\n result[maxWeightIdx] = i;\r\n weights[maxWeightIdx] = key;\r\n\r\n // 重新找最大权重\r\n maxWeight = weights[0];\r\n maxWeightIdx = 0;\r\n for (let j = 1; j < sampleCount; j++) {\r\n if (weights[j] > maxWeight) {\r\n maxWeight = weights[j];\r\n maxWeightIdx = j;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // 按原始顺序排列(保持空间局部性,有利于缓存)\r\n result.sort((a, b) => a - b);\r\n\r\n return result;\r\n}\r\n\r\n/**\r\n * 移动端优化的 PLY 加载器\r\n * 直接输出紧凑格式,避免创建大量中间对象\r\n */\r\nexport async function loadPLYMobile(\r\n url: string,\r\n options: MobileLoadOptions = {}\r\n): Promise<CompactSplatData> {\r\n // 获取文件\r\n const response = await fetch(url);\r\n if (!response.ok) {\r\n throw new Error(`无法加载 PLY 文件: ${url}`);\r\n }\r\n const buffer = await response.arrayBuffer();\r\n\r\n return parsePLYBuffer(buffer, options);\r\n}\r\n\r\n/**\r\n * 解析 PLY ArrayBuffer\r\n * 可以直接传入 ArrayBuffer 进行解析,用于本地文件加载\r\n */\r\nexport async function parsePLYBuffer(\r\n buffer: ArrayBuffer,\r\n options: MobileLoadOptions = {}\r\n): Promise<CompactSplatData> {\r\n const {\r\n maxSplats = 200000,\r\n loadSH = false,\r\n onProgress,\r\n } = options;\r\n\r\n // 使用文件大小作为默认种子(确保相同文件产生相同结果)\r\n const seed = options.seed ?? buffer.byteLength;\r\n\r\n // 解析 header\r\n const { headerText, dataOffset } = extractHeader(buffer);\r\n const { vertexCount, properties, stride, format } = parseHeader(headerText);\r\n\r\n // 验证格式\r\n if (format === \"ascii\") {\r\n throw new Error(\"不支持 ASCII 格式的 PLY 文件,请使用 binary_little_endian 或 binary_big_endian 格式\");\r\n }\r\n\r\n const littleEndian = format === \"binary_little_endian\";\r\n\r\n // 构建属性偏移映射\r\n const propMap = new Map<string, PropertyInfo>();\r\n for (const prop of properties) {\r\n propMap.set(prop.name, prop);\r\n }\r\n\r\n // 获取基本属性信息\r\n const getProp = (name: string) => propMap.get(name);\r\n const getOffset = (name: string) => propMap.get(name)?.byteOffset ?? -1;\r\n const getType = (name: string) => propMap.get(name)?.type ?? \"float\";\r\n\r\n const offsets = {\r\n x: getOffset(\"x\"),\r\n y: getOffset(\"y\"),\r\n z: getOffset(\"z\"),\r\n scale_0: getOffset(\"scale_0\"),\r\n scale_1: getOffset(\"scale_1\"),\r\n scale_2: getOffset(\"scale_2\"),\r\n rot_0: getOffset(\"rot_0\"),\r\n rot_1: getOffset(\"rot_1\"),\r\n rot_2: getOffset(\"rot_2\"),\r\n rot_3: getOffset(\"rot_3\"),\r\n f_dc_0: getOffset(\"f_dc_0\"),\r\n f_dc_1: getOffset(\"f_dc_1\"),\r\n f_dc_2: getOffset(\"f_dc_2\"),\r\n opacity: getOffset(\"opacity\"),\r\n };\r\n\r\n const types = {\r\n x: getType(\"x\"),\r\n y: getType(\"y\"),\r\n z: getType(\"z\"),\r\n scale_0: getType(\"scale_0\"),\r\n scale_1: getType(\"scale_1\"),\r\n scale_2: getType(\"scale_2\"),\r\n rot_0: getType(\"rot_0\"),\r\n rot_1: getType(\"rot_1\"),\r\n rot_2: getType(\"rot_2\"),\r\n rot_3: getType(\"rot_3\"),\r\n f_dc_0: getType(\"f_dc_0\"),\r\n f_dc_1: getType(\"f_dc_1\"),\r\n f_dc_2: getType(\"f_dc_2\"),\r\n opacity: getType(\"opacity\"),\r\n };\r\n\r\n // SH 系数属性(可选)\r\n let shProps: PropertyInfo[] = [];\r\n if (loadSH) {\r\n shProps = properties\r\n .filter((p) => p.name.startsWith(\"f_rest_\"))\r\n .sort((a, b) => {\r\n const idxA = parseInt(a.name.replace(\"f_rest_\", \"\"), 10);\r\n const idxB = parseInt(b.name.replace(\"f_rest_\", \"\"), 10);\r\n return idxA - idxB;\r\n });\r\n }\r\n\r\n // 计算实际加载数量\r\n const needSample = vertexCount > maxSplats;\r\n const actualCount = Math.min(vertexCount, maxSplats);\r\n \r\n // 估算内存使用(纹理压缩模式约 52 bytes/splat)\r\n const estimatedMemoryMB = (actualCount * 52) / (1024 * 1024);\r\n \r\n if (estimatedMemoryMB > 300) {\r\n // 高内存警告(静默处理)\r\n }\r\n \r\n // 如果需要降采样,使用智能采样(基于重要性,确定性种子)\r\n let sampleIndices: Uint32Array | null = null;\r\n if (needSample) {\r\n sampleIndices = computeImportanceSampling(\r\n buffer, dataOffset, stride, vertexCount, actualCount,\r\n offsets.opacity, types.opacity,\r\n offsets.scale_0, types.scale_0,\r\n offsets.scale_1, types.scale_1,\r\n offsets.scale_2, types.scale_2,\r\n littleEndian, seed\r\n );\r\n }\r\n\r\n // 预分配输出数组(一次性分配,避免多次扩容)\r\n const positions = new Float32Array(actualCount * 3);\r\n const scales = new Float32Array(actualCount * 3);\r\n const rotations = new Float32Array(actualCount * 4);\r\n const colors = new Float32Array(actualCount * 3);\r\n const opacities = new Float32Array(actualCount);\r\n const shCoeffs = loadSH ? new Float32Array(actualCount * 45) : undefined;\r\n\r\n // 创建 DataView\r\n const dataView = new DataView(buffer, dataOffset);\r\n\r\n // 流式解析\r\n let outputIdx = 0;\r\n let lastProgress = 0;\r\n\r\n for (let i = 0; i < actualCount; i++) {\r\n // 计算源索引:使用智能采样或直接索引\r\n const srcIdx = sampleIndices ? sampleIndices[i] : i;\r\n const base = srcIdx * stride;\r\n\r\n // 位置\r\n positions[outputIdx * 3 + 0] = offsets.x >= 0 ? readProperty(dataView, base + offsets.x, types.x, littleEndian) : 0;\r\n positions[outputIdx * 3 + 1] = offsets.y >= 0 ? readProperty(dataView, base + offsets.y, types.y, littleEndian) : 0;\r\n positions[outputIdx * 3 + 2] = offsets.z >= 0 ? readProperty(dataView, base + offsets.z, types.z, littleEndian) : 0;\r\n\r\n // 缩放(exp 转换)\r\n scales[outputIdx * 3 + 0] = offsets.scale_0 >= 0 ? Math.exp(readProperty(dataView, base + offsets.scale_0, types.scale_0, littleEndian)) : 1;\r\n scales[outputIdx * 3 + 1] = offsets.scale_1 >= 0 ? Math.exp(readProperty(dataView, base + offsets.scale_1, types.scale_1, littleEndian)) : 1;\r\n scales[outputIdx * 3 + 2] = offsets.scale_2 >= 0 ? Math.exp(readProperty(dataView, base + offsets.scale_2, types.scale_2, littleEndian)) : 1;\r\n\r\n // 旋转四元数(归一化)\r\n const rot_0 = offsets.rot_0 >= 0 ? readProperty(dataView, base + offsets.rot_0, types.rot_0, littleEndian) : 1;\r\n const rot_1 = offsets.rot_1 >= 0 ? readProperty(dataView, base + offsets.rot_1, types.rot_1, littleEndian) : 0;\r\n const rot_2 = offsets.rot_2 >= 0 ? readProperty(dataView, base + offsets.rot_2, types.rot_2, littleEndian) : 0;\r\n const rot_3 = offsets.rot_3 >= 0 ? readProperty(dataView, base + offsets.rot_3, types.rot_3, littleEndian) : 0;\r\n const qlen = Math.sqrt(rot_0 * rot_0 + rot_1 * rot_1 + rot_2 * rot_2 + rot_3 * rot_3);\r\n const qnorm = qlen > 0 ? 1 / qlen : 1;\r\n rotations[outputIdx * 4 + 0] = rot_0 * qnorm;\r\n rotations[outputIdx * 4 + 1] = rot_1 * qnorm;\r\n rotations[outputIdx * 4 + 2] = rot_2 * qnorm;\r\n rotations[outputIdx * 4 + 3] = rot_3 * qnorm;\r\n\r\n // DC 颜色(SH0 -> RGB)\r\n // 注意:不要在这里 clamp,因为 SH 贡献可能是负数\r\n // 最终颜色会在 shader 中 clamp\r\n const f_dc_0 = offsets.f_dc_0 >= 0 ? readProperty(dataView, base + offsets.f_dc_0, types.f_dc_0, littleEndian) : 0;\r\n const f_dc_1 = offsets.f_dc_1 >= 0 ? readProperty(dataView, base + offsets.f_dc_1, types.f_dc_1, littleEndian) : 0;\r\n const f_dc_2 = offsets.f_dc_2 >= 0 ? readProperty(dataView, base + offsets.f_dc_2, types.f_dc_2, littleEndian) : 0;\r\n colors[outputIdx * 3 + 0] = 0.5 + SH_C0 * f_dc_0;\r\n colors[outputIdx * 3 + 1] = 0.5 + SH_C0 * f_dc_1;\r\n colors[outputIdx * 3 + 2] = 0.5 + SH_C0 * f_dc_2;\r\n\r\n // 不透明度(sigmoid)\r\n const rawOpacity = offsets.opacity >= 0 ? readProperty(dataView, base + offsets.opacity, types.opacity, littleEndian) : 0;\r\n opacities[outputIdx] = sigmoid(rawOpacity);\r\n\r\n // SH 系数(可选)\r\n // PLY 文件中 f_rest_* 的顺序是 channel-first:\r\n // [R0..R14, G0..G14, B0..B14] - 每通道 15 个系数\r\n // 我们转换为 interleaved 格式: [R0,G0,B0, R1,G1,B1, ...]\r\n if (shCoeffs && shProps.length > 0) {\r\n const shBase = outputIdx * 45;\r\n const perChannel = Math.floor(shProps.length / 3); // 每通道的系数数量\r\n \r\n for (let coefIdx = 0; coefIdx < perChannel && coefIdx < 15; coefIdx++) {\r\n // PLY 中: R 在 [0..perChannel-1], G 在 [perChannel..2*perChannel-1], B 在 [2*perChannel..3*perChannel-1]\r\n const srcR = coefIdx;\r\n const srcG = perChannel + coefIdx;\r\n const srcB = 2 * perChannel + coefIdx;\r\n \r\n // 目标: interleaved [R0,G0,B0, R1,G1,B1, ...]\r\n const dstBase = coefIdx * 3;\r\n \r\n if (srcR < shProps.length) {\r\n const prop = shProps[srcR];\r\n shCoeffs[shBase + dstBase + 0] = readProperty(dataView, base + prop.byteOffset, prop.type, littleEndian);\r\n }\r\n if (srcG < shProps.length) {\r\n const prop = shProps[srcG];\r\n shCoeffs[shBase + dstBase + 1] = readProperty(dataView, base + prop.byteOffset, prop.type, littleEndian);\r\n }\r\n if (srcB < shProps.length) {\r\n const prop = shProps[srcB];\r\n shCoeffs[shBase + dstBase + 2] = readProperty(dataView, base + prop.byteOffset, prop.type, littleEndian);\r\n }\r\n }\r\n }\r\n\r\n outputIdx++;\r\n\r\n // 进度回调\r\n if (onProgress) {\r\n const progress = Math.floor((i / actualCount) * 100);\r\n if (progress > lastProgress) {\r\n lastProgress = progress;\r\n onProgress(i, actualCount);\r\n }\r\n }\r\n }\r\n\r\n return {\r\n count: outputIdx,\r\n positions,\r\n scales,\r\n rotations,\r\n colors,\r\n opacities,\r\n shCoeffs,\r\n };\r\n}\r\n\r\n/**\r\n * 将 CompactSplatData 转换为 GPU buffer 格式\r\n * 直接输出可以上传到 GPU 的 Float32Array\r\n * \r\n * @param data 紧凑 splat 数据\r\n * @param includeFullSH 是否包含完整 SH 系数(256 字节/splat),否则只包含基本数据(64 字节/splat)\r\n */\r\nexport function compactDataToGPUBuffer(\r\n data: CompactSplatData,\r\n includeFullSH: boolean = false\r\n): Float32Array {\r\n const count = data.count;\r\n\r\n if (includeFullSH) {\r\n // 完整格式:256 字节/splat = 64 floats\r\n const buffer = new Float32Array(count * 64);\r\n\r\n for (let i = 0; i < count; i++) {\r\n const offset = i * 64;\r\n\r\n // mean (vec3) + padding\r\n buffer[offset + 0] = data.positions[i * 3 + 0];\r\n buffer[offset + 1] = data.positions[i * 3 + 1];\r\n buffer[offset + 2] = data.positions[i * 3 + 2];\r\n buffer[offset + 3] = 0;\r\n\r\n // scale (vec3) + padding\r\n buffer[offset + 4] = data.scales[i * 3 + 0];\r\n buffer[offset + 5] = data.scales[i * 3 + 1];\r\n buffer[offset + 6] = data.scales[i * 3 + 2];\r\n buffer[offset + 7] = 0;\r\n\r\n // rotation (vec4)\r\n buffer[offset + 8] = data.rotations[i * 4 + 0];\r\n buffer[offset + 9] = data.rotations[i * 4 + 1];\r\n buffer[offset + 10] = data.rotations[i * 4 + 2];\r\n buffer[offset + 11] = data.rotations[i * 4 + 3];\r\n\r\n // colorDC (vec3) + opacity\r\n buffer[offset + 12] = data.colors[i * 3 + 0];\r\n buffer[offset + 13] = data.colors[i * 3 + 1];\r\n buffer[offset + 14] = data.colors[i * 3 + 2];\r\n buffer[offset + 15] = data.opacities[i];\r\n\r\n // SH 系数\r\n if (data.shCoeffs) {\r\n const shBase = i * 45;\r\n // sh1 (9 floats)\r\n for (let j = 0; j < 9; j++) {\r\n buffer[offset + 16 + j] = data.shCoeffs[shBase + j];\r\n }\r\n // sh2 (15 floats)\r\n for (let j = 0; j < 15; j++) {\r\n buffer[offset + 25 + j] = data.shCoeffs[shBase + 9 + j];\r\n }\r\n // sh3 (21 floats)\r\n for (let j = 0; j < 21; j++) {\r\n buffer[offset + 40 + j] = data.shCoeffs[shBase + 24 + j];\r\n }\r\n }\r\n // padding 已经是 0(Float32Array 默认初始化为 0)\r\n }\r\n\r\n return buffer;\r\n } else {\r\n // 紧凑格式:64 字节/splat = 16 floats(只包含基本渲染数据)\r\n const buffer = new Float32Array(count * 64); // 保持 256 字节对齐,但只填充基本数据\r\n \r\n for (let i = 0; i < count; i++) {\r\n const offset = i * 64;\r\n \r\n // mean (vec3) + padding\r\n buffer[offset + 0] = data.positions[i * 3 + 0];\r\n buffer[offset + 1] = data.positions[i * 3 + 1];\r\n buffer[offset + 2] = data.positions[i * 3 + 2];\r\n buffer[offset + 3] = 0;\r\n \r\n // scale (vec3) + padding\r\n buffer[offset + 4] = data.scales[i * 3 + 0];\r\n buffer[offset + 5] = data.scales[i * 3 + 1];\r\n buffer[offset + 6] = data.scales[i * 3 + 2];\r\n buffer[offset + 7] = 0;\r\n \r\n // rotation (vec4)\r\n buffer[offset + 8] = data.rotations[i * 4 + 0];\r\n buffer[offset + 9] = data.rotations[i * 4 + 1];\r\n buffer[offset + 10] = data.rotations[i * 4 + 2];\r\n buffer[offset + 11] = data.rotations[i * 4 + 3];\r\n \r\n // colorDC (vec3) + opacity\r\n buffer[offset + 12] = data.colors[i * 3 + 0];\r\n buffer[offset + 13] = data.colors[i * 3 + 1];\r\n buffer[offset + 14] = data.colors[i * 3 + 2];\r\n buffer[offset + 15] = data.opacities[i];\r\n \r\n // 其余保持为 0(SH 系数为空)\r\n }\r\n \r\n return buffer;\r\n }\r\n}\r\n","/**\n * SplatLoader - 加载 .splat 格式的 3D Gaussian Splatting 文件\n * \n * .splat 格式是一种紧凑的 3DGS 数据格式:\n * - 每个 splat 固定 32 字节,无文件头\n * - 数据布局: position(12) + scale(12) + color(3) + opacity(1) + rotation(4)\n * - 不包含高阶球谐系数,仅 DC 颜色\n * \n * 四元数顺序: [w, x, y, z](与 PLYLoader 保持一致)\n * \n * 参考: supersplat/src/loaders/splat.ts\n */\n\nimport { SplatCPU } from \"./PLYLoader\";\n\n/** .splat 文件每个 splat 的字节大小 */\nconst SPLAT_SIZE = 32;\n\n/** 最小有效文件大小(至少包含一个 splat) */\nconst MIN_FILE_SIZE = SPLAT_SIZE;\n\n/** 最大合理文件大小(防止内存溢出,约 1000 万 splats) */\nconst MAX_FILE_SIZE = SPLAT_SIZE * 10_000_000;\n\n/**\n * 验证 .splat 文件格式\n * 由于 .splat 没有魔数,只能通过文件大小和数据合理性来验证\n */\nfunction validateSplatFile(data: ArrayBufferLike): void {\n if (data.byteLength < MIN_FILE_SIZE) {\n throw new Error(`无效的 Splat 文件: 文件太小 (${data.byteLength} bytes),至少需要 ${MIN_FILE_SIZE} bytes`);\n }\n\n if (data.byteLength > MAX_FILE_SIZE) {\n throw new Error(`Splat 文件过大 (${(data.byteLength / 1024 / 1024).toFixed(1)} MB),超过最大限制`);\n }\n\n if (data.byteLength % SPLAT_SIZE !== 0) {\n throw new Error(`无效的 Splat 文件: 文件大小 (${data.byteLength} bytes) 不是 ${SPLAT_SIZE} 的整数倍`);\n }\n\n // 抽样检查数据合理性(检查前几个 splat 的位置是否为有效浮点数)\n const dataView = new DataView(data);\n const samplesToCheck = Math.min(10, Math.floor(data.byteLength / SPLAT_SIZE));\n\n for (let i = 0; i < samplesToCheck; i++) {\n const off = i * SPLAT_SIZE;\n const x = dataView.getFloat32(off + 0, true);\n const y = dataView.getFloat32(off + 4, true);\n const z = dataView.getFloat32(off + 8, true);\n\n // 检查是否为有效浮点数(非 NaN、非 Infinity)\n if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(z)) {\n throw new Error(`无效的 Splat 文件: 第 ${i} 个 splat 包含无效的位置数据`);\n }\n\n // 检查位置是否在合理范围内(-10000 到 10000)\n const MAX_POS = 10000;\n if (Math.abs(x) > MAX_POS || Math.abs(y) > MAX_POS || Math.abs(z) > MAX_POS) {\n // 位置超出常规范围\n }\n }\n}\n\n/**\n * Sigmoid 函数,与 PLYLoader 保持一致\n */\nfunction sigmoid(x: number): number {\n return 1 / (1 + Math.exp(-x));\n}\n\n/**\n * 逆 Sigmoid 函数\n * 将 [0, 1] 范围的值转换回原始 logit 值\n */\nfunction inverseSigmoid(y: number): number {\n // 避免 log(0) 和 log(负数)\n const clamped = Math.max(0.0001, Math.min(0.9999, y));\n return Math.log(clamped / (1 - clamped));\n}\n\n/**\n * 加载并解析 .splat 文件\n * @param url .splat 文件的 URL\n * @returns SplatCPU 数组\n */\nexport async function loadSplat(url: string): Promise<SplatCPU[]> {\n // 获取文件\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`无法加载 Splat 文件: ${url}`);\n }\n const buffer = await response.arrayBuffer();\n\n return deserializeSplat(buffer);\n}\n\n/**\n * 从 ArrayBuffer 解析 splat 数据\n * @param data 文件的 ArrayBuffer\n * @returns SplatCPU 数组\n */\nexport function deserializeSplat(data: ArrayBufferLike): SplatCPU[] {\n // 验证文件格式\n validateSplatFile(data);\n\n const totalSplats = Math.floor(data.byteLength / SPLAT_SIZE);\n\n const dataView = new DataView(data);\n const splats: SplatCPU[] = new Array(totalSplats);\n\n // 预分配共享的 SH 系数数组(全为 0,因为 .splat 不包含 SH)\n const shRestBuffer = new Float32Array(totalSplats * 45);\n\n for (let i = 0; i < totalSplats; i++) {\n const off = i * SPLAT_SIZE;\n\n // 读取位置 (float32 × 3 = 12 bytes)\n const x = dataView.getFloat32(off + 0, true);\n const y = dataView.getFloat32(off + 4, true);\n const z = dataView.getFloat32(off + 8, true);\n\n // 读取缩放 (float32 × 3 = 12 bytes)\n // splat 格式存储原始缩放值,直接使用\n const scale_0 = dataView.getFloat32(off + 12, true);\n const scale_1 = dataView.getFloat32(off + 16, true);\n const scale_2 = dataView.getFloat32(off + 20, true);\n\n // 读取颜色 (uint8 × 3 = 3 bytes)\n // splat 格式直接存储 RGB 颜色 [0-255],归一化到 [0-1]\n const colorR = dataView.getUint8(off + 24) / 255;\n const colorG = dataView.getUint8(off + 25) / 255;\n const colorB = dataView.getUint8(off + 26) / 255;\n\n // 读取透明度 (uint8 × 1 = 1 byte)\n // .splat 格式存储的是 sigmoid 后的值 [0-255] 映射到 [0-1]\n // 为了与 PLYLoader 的 sigmoid 处理保持一致,我们:\n // 1. 先将 uint8 转换为 [0, 1] 范围\n // 2. 应用逆 sigmoid 得到原始 logit 值\n // 3. 再应用 sigmoid(这样与 PLYLoader 的处理流程一致)\n // \n // 实际上这等价于直接使用线性归一化,但保持代码逻辑一致性\n const opacityUint8 = dataView.getUint8(off + 27);\n const opacityNormalized = opacityUint8 / 255;\n // 直接使用归一化值作为最终 opacity(因为 .splat 已经是 sigmoid 后的值)\n const opacity = opacityNormalized;\n\n // 读取旋转四元数 (uint8 × 4 = 4 bytes)\n // 从 [0, 255] 映射到 [-1, 1]\n // 四元数顺序: [w, x, y, z]\n const rot_w = (dataView.getUint8(off + 28) - 128) / 128;\n const rot_x = (dataView.getUint8(off + 29) - 128) / 128;\n const rot_y = (dataView.getUint8(off + 30) - 128) / 128;\n const rot_z = (dataView.getUint8(off + 31) - 128) / 128;\n\n // 归一化四元数\n const qlen = Math.sqrt(\n rot_w * rot_w + rot_x * rot_x + rot_y * rot_y + rot_z * rot_z\n );\n const qnorm = qlen > 0 ? 1 / qlen : 1;\n\n // 使用共享 buffer 的子数组\n const shOffset = i * 45;\n const shRest = shRestBuffer.subarray(shOffset, shOffset + 45);\n\n splats[i] = {\n mean: [x, y, z],\n scale: [scale_0, scale_1, scale_2],\n rotation: [\n rot_w * qnorm,\n rot_x * qnorm,\n rot_y * qnorm,\n rot_z * qnorm,\n ],\n colorDC: [colorR, colorG, colorB],\n opacity,\n shRest,\n };\n }\n\n return splats;\n}\n","// DEFLATE is a complex format; to read this code, you should probably check the RFC first:\n// https://tools.ietf.org/html/rfc1951\n// You may also wish to take a look at the guide I made about this program:\n// https://gist.github.com/101arrowz/253f31eb5abc3d9275ab943003ffecad\n// Some of the following code is similar to that of UZIP.js:\n// https://github.com/photopea/UZIP.js\n// However, the vast majority of the codebase has diverged from UZIP.js to increase performance and reduce bundle size.\n// Sometimes 0 will appear where -1 would be more appropriate. This is because using a uint\n// is better for memory in most engines (I *think*).\nvar ch2 = {};\nvar wk = (function (c, id, msg, transfer, cb) {\n var w = new Worker(ch2[id] || (ch2[id] = URL.createObjectURL(new Blob([\n c + ';addEventListener(\"error\",function(e){e=e.error;postMessage({$e$:[e.message,e.code,e.stack]})})'\n ], { type: 'text/javascript' }))));\n w.onmessage = function (e) {\n var d = e.data, ed = d.$e$;\n if (ed) {\n var err = new Error(ed[0]);\n err['code'] = ed[1];\n err.stack = ed[2];\n cb(err, null);\n }\n else\n cb(null, d);\n };\n w.postMessage(msg, transfer);\n return w;\n});\n\n// aliases for shorter compressed code (most minifers don't do this)\nvar u8 = Uint8Array, u16 = Uint16Array, i32 = Int32Array;\n// fixed length extra bits\nvar fleb = new u8([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, /* unused */ 0, 0, /* impossible */ 0]);\n// fixed distance extra bits\nvar fdeb = new u8([0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, /* unused */ 0, 0]);\n// code length index map\nvar clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);\n// get base, reverse index map from extra bits\nvar freb = function (eb, start) {\n var b = new u16(31);\n for (var i = 0; i < 31; ++i) {\n b[i] = start += 1 << eb[i - 1];\n }\n // numbers here are at max 18 bits\n var r = new i32(b[30]);\n for (var i = 1; i < 30; ++i) {\n for (var j = b[i]; j < b[i + 1]; ++j) {\n r[j] = ((j - b[i]) << 5) | i;\n }\n }\n return { b: b, r: r };\n};\nvar _a = freb(fleb, 2), fl = _a.b, revfl = _a.r;\n// we can ignore the fact that the other numbers are wrong; they never happen anyway\nfl[28] = 258, revfl[258] = 28;\nvar _b = freb(fdeb, 0), fd = _b.b, revfd = _b.r;\n// map of value to reverse (assuming 16 bits)\nvar rev = new u16(32768);\nfor (var i = 0; i < 32768; ++i) {\n // reverse table algorithm from SO\n var x = ((i & 0xAAAA) >> 1) | ((i & 0x5555) << 1);\n x = ((x & 0xCCCC) >> 2) | ((x & 0x3333) << 2);\n x = ((x & 0xF0F0) >> 4) | ((x & 0x0F0F) << 4);\n rev[i] = (((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8)) >> 1;\n}\n// create huffman tree from u8 \"map\": index -> code length for code index\n// mb (max bits) must be at most 15\n// TODO: optimize/split up?\nvar hMap = (function (cd, mb, r) {\n var s = cd.length;\n // index\n var i = 0;\n // u16 \"map\": index -> # of codes with bit length = index\n var l = new u16(mb);\n // length of cd must be 288 (total # of codes)\n for (; i < s; ++i) {\n if (cd[i])\n ++l[cd[i] - 1];\n }\n // u16 \"map\": index -> minimum code for bit length = index\n var le = new u16(mb);\n for (i = 1; i < mb; ++i) {\n le[i] = (le[i - 1] + l[i - 1]) << 1;\n }\n var co;\n if (r) {\n // u16 \"map\": index -> number of actual bits, symbol for code\n co = new u16(1 << mb);\n // bits to remove for reverser\n var rvb = 15 - mb;\n for (i = 0; i < s; ++i) {\n // ignore 0 lengths\n if (cd[i]) {\n // num encoding both symbol and bits read\n var sv = (i << 4) | cd[i];\n // free bits\n var r_1 = mb - cd[i];\n // start value\n var v = le[cd[i] - 1]++ << r_1;\n // m is end value\n for (var m = v | ((1 << r_1) - 1); v <= m; ++v) {\n // every 16 bit value starting with the code yields the same result\n co[rev[v] >> rvb] = sv;\n }\n }\n }\n }\n else {\n co = new u16(s);\n for (i = 0; i < s; ++i) {\n if (cd[i]) {\n co[i] = rev[le[cd[i] - 1]++] >> (15 - cd[i]);\n }\n }\n }\n return co;\n});\n// fixed length tree\nvar flt = new u8(288);\nfor (var i = 0; i < 144; ++i)\n flt[i] = 8;\nfor (var i = 144; i < 256; ++i)\n flt[i] = 9;\nfor (var i = 256; i < 280; ++i)\n flt[i] = 7;\nfor (var i = 280; i < 288; ++i)\n flt[i] = 8;\n// fixed distance tree\nvar fdt = new u8(32);\nfor (var i = 0; i < 32; ++i)\n fdt[i] = 5;\n// fixed length map\nvar flm = /*#__PURE__*/ hMap(flt, 9, 0), flrm = /*#__PURE__*/ hMap(flt, 9, 1);\n// fixed distance map\nvar fdm = /*#__PURE__*/ hMap(fdt, 5, 0), fdrm = /*#__PURE__*/ hMap(fdt, 5, 1);\n// find max of array\nvar max = function (a) {\n var m = a[0];\n for (var i = 1; i < a.length; ++i) {\n if (a[i] > m)\n m = a[i];\n }\n return m;\n};\n// read d, starting at bit p and mask with m\nvar bits = function (d, p, m) {\n var o = (p / 8) | 0;\n return ((d[o] | (d[o + 1] << 8)) >> (p & 7)) & m;\n};\n// read d, starting at bit p continuing for at least 16 bits\nvar bits16 = function (d, p) {\n var o = (p / 8) | 0;\n return ((d[o] | (d[o + 1] << 8) | (d[o + 2] << 16)) >> (p & 7));\n};\n// get end of byte\nvar shft = function (p) { return ((p + 7) / 8) | 0; };\n// typed array slice - allows garbage collector to free original reference,\n// while being more compatible than .slice\nvar slc = function (v, s, e) {\n if (s == null || s < 0)\n s = 0;\n if (e == null || e > v.length)\n e = v.length;\n // can't use .constructor in case user-supplied\n return new u8(v.subarray(s, e));\n};\n/**\n * Codes for errors generated within this library\n */\nexport var FlateErrorCode = {\n UnexpectedEOF: 0,\n InvalidBlockType: 1,\n InvalidLengthLiteral: 2,\n InvalidDistance: 3,\n StreamFinished: 4,\n NoStreamHandler: 5,\n InvalidHeader: 6,\n NoCallback: 7,\n InvalidUTF8: 8,\n ExtraFieldTooLong: 9,\n InvalidDate: 10,\n FilenameTooLong: 11,\n StreamFinishing: 12,\n InvalidZipData: 13,\n UnknownCompressionMethod: 14\n};\n// error codes\nvar ec = [\n 'unexpected EOF',\n 'invalid block type',\n 'invalid length/literal',\n 'invalid distance',\n 'stream finished',\n 'no stream handler',\n ,\n 'no callback',\n 'invalid UTF-8 data',\n 'extra field too long',\n 'date not in range 1980-2099',\n 'filename too long',\n 'stream finishing',\n 'invalid zip data'\n // determined by unknown compression method\n];\n;\nvar err = function (ind, msg, nt) {\n var e = new Error(msg || ec[ind]);\n e.code = ind;\n if (Error.captureStackTrace)\n Error.captureStackTrace(e, err);\n if (!nt)\n throw e;\n return e;\n};\n// expands raw DEFLATE data\nvar inflt = function (dat, st, buf, dict) {\n // source length dict length\n var sl = dat.length, dl = dict ? dict.length : 0;\n if (!sl || st.f && !st.l)\n return buf || new u8(0);\n var noBuf = !buf;\n // have to estimate size\n var resize = noBuf || st.i != 2;\n // no state\n var noSt = st.i;\n // Assumes roughly 33% compression ratio average\n if (noBuf)\n buf = new u8(sl * 3);\n // ensure buffer can fit at least l elements\n var cbuf = function (l) {\n var bl = buf.length;\n // need to increase size to fit\n if (l > bl) {\n // Double or set to necessary, whichever is greater\n var nbuf = new u8(Math.max(bl * 2, l));\n nbuf.set(buf);\n buf = nbuf;\n }\n };\n // last chunk bitpos bytes\n var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n;\n // total bits\n var tbts = sl * 8;\n do {\n if (!lm) {\n // BFINAL - this is only 1 when last chunk is next\n final = bits(dat, pos, 1);\n // type: 0 = no compression, 1 = fixed huffman, 2 = dynamic huffman\n var type = bits(dat, pos + 1, 3);\n pos += 3;\n if (!type) {\n // go to end of byte boundary\n var s = shft(pos) + 4, l = dat[s - 4] | (dat[s - 3] << 8), t = s + l;\n if (t > sl) {\n if (noSt)\n err(0);\n break;\n }\n // ensure size\n if (resize)\n cbuf(bt + l);\n // Copy over uncompressed data\n buf.set(dat.subarray(s, t), bt);\n // Get new bitpos, update byte count\n st.b = bt += l, st.p = pos = t * 8, st.f = final;\n continue;\n }\n else if (type == 1)\n lm = flrm, dm = fdrm, lbt = 9, dbt = 5;\n else if (type == 2) {\n // literal lengths\n var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;\n var tl = hLit + bits(dat, pos + 5, 31) + 1;\n pos += 14;\n // length+distance tree\n var ldt = new u8(tl);\n // code length tree\n var clt = new u8(19);\n for (var i = 0; i < hcLen; ++i) {\n // use index map to get real code\n clt[clim[i]] = bits(dat, pos + i * 3, 7);\n }\n pos += hcLen * 3;\n // code lengths bits\n var clb = max(clt), clbmsk = (1 << clb) - 1;\n // code lengths map\n var clm = hMap(clt, clb, 1);\n for (var i = 0; i < tl;) {\n var r = clm[bits(dat, pos, clbmsk)];\n // bits read\n pos += r & 15;\n // symbol\n var s = r >> 4;\n // code length to copy\n if (s < 16) {\n ldt[i++] = s;\n }\n else {\n // copy count\n var c = 0, n = 0;\n if (s == 16)\n n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1];\n else if (s == 17)\n n = 3 + bits(dat, pos, 7), pos += 3;\n else if (s == 18)\n n = 11 + bits(dat, pos, 127), pos += 7;\n while (n--)\n ldt[i++] = c;\n }\n }\n // length tree distance tree\n var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);\n // max length bits\n lbt = max(lt);\n // max dist bits\n dbt = max(dt);\n lm = hMap(lt, lbt, 1);\n dm = hMap(dt, dbt, 1);\n }\n else\n err(1);\n if (pos > tbts) {\n if (noSt)\n err(0);\n break;\n }\n }\n // Make sure the buffer can hold this + the largest possible addition\n // Maximum chunk size (practically, theoretically infinite) is 2^17\n if (resize)\n cbuf(bt + 131072);\n var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;\n var lpos = pos;\n for (;; lpos = pos) {\n // bits read, code\n var c = lm[bits16(dat, pos) & lms], sym = c >> 4;\n pos += c & 15;\n if (pos > tbts) {\n if (noSt)\n err(0);\n break;\n }\n if (!c)\n err(2);\n if (sym < 256)\n buf[bt++] = sym;\n else if (sym == 256) {\n lpos = pos, lm = null;\n break;\n }\n else {\n var add = sym - 254;\n // no extra bits needed if less\n if (sym > 264) {\n // index\n var i = sym - 257, b = fleb[i];\n add = bits(dat, pos, (1 << b) - 1) + fl[i];\n pos += b;\n }\n // dist\n var d = dm[bits16(dat, pos) & dms], dsym = d >> 4;\n if (!d)\n err(3);\n pos += d & 15;\n var dt = fd[dsym];\n if (dsym > 3) {\n var b = fdeb[dsym];\n dt += bits16(dat, pos) & (1 << b) - 1, pos += b;\n }\n if (pos > tbts) {\n if (noSt)\n err(0);\n break;\n }\n if (resize)\n cbuf(bt + 131072);\n var end = bt + add;\n if (bt < dt) {\n var shift = dl - dt, dend = Math.min(dt, end);\n if (shift + bt < 0)\n err(3);\n for (; bt < dend; ++bt)\n buf[bt] = dict[shift + bt];\n }\n for (; bt < end; ++bt)\n buf[bt] = buf[bt - dt];\n }\n }\n st.l = lm, st.p = lpos, st.b = bt, st.f = final;\n if (lm)\n final = 1, st.m = lbt, st.d = dm, st.n = dbt;\n } while (!final);\n // don't reallocate for streams or user buffers\n return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);\n};\n// starting at p, write the minimum number of bits that can hold v to d\nvar wbits = function (d, p, v) {\n v <<= p & 7;\n var o = (p / 8) | 0;\n d[o] |= v;\n d[o + 1] |= v >> 8;\n};\n// starting at p, write the minimum number of bits (>8) that can hold v to d\nvar wbits16 = function (d, p, v) {\n v <<= p & 7;\n var o = (p / 8) | 0;\n d[o] |= v;\n d[o + 1] |= v >> 8;\n d[o + 2] |= v >> 16;\n};\n// creates code lengths from a frequency table\nvar hTree = function (d, mb) {\n // Need extra info to make a tree\n var t = [];\n for (var i = 0; i < d.length; ++i) {\n if (d[i])\n t.push({ s: i, f: d[i] });\n }\n var s = t.length;\n var t2 = t.slice();\n if (!s)\n return { t: et, l: 0 };\n if (s == 1) {\n var v = new u8(t[0].s + 1);\n v[t[0].s] = 1;\n return { t: v, l: 1 };\n }\n t.sort(function (a, b) { return a.f - b.f; });\n // after i2 reaches last ind, will be stopped\n // freq must be greater than largest possible number of symbols\n t.push({ s: -1, f: 25001 });\n var l = t[0], r = t[1], i0 = 0, i1 = 1, i2 = 2;\n t[0] = { s: -1, f: l.f + r.f, l: l, r: r };\n // efficient algorithm from UZIP.js\n // i0 is lookbehind, i2 is lookahead - after processing two low-freq\n // symbols that combined have high freq, will start processing i2 (high-freq,\n // non-composite) symbols instead\n // see https://reddit.com/r/photopea/comments/ikekht/uzipjs_questions/\n while (i1 != s - 1) {\n l = t[t[i0].f < t[i2].f ? i0++ : i2++];\n r = t[i0 != i1 && t[i0].f < t[i2].f ? i0++ : i2++];\n t[i1++] = { s: -1, f: l.f + r.f, l: l, r: r };\n }\n var maxSym = t2[0].s;\n for (var i = 1; i < s; ++i) {\n if (t2[i].s > maxSym)\n maxSym = t2[i].s;\n }\n // code lengths\n var tr = new u16(maxSym + 1);\n // max bits in tree\n var mbt = ln(t[i1 - 1], tr, 0);\n if (mbt > mb) {\n // more algorithms from UZIP.js\n // TODO: find out how this code works (debt)\n // ind debt\n var i = 0, dt = 0;\n // left cost\n var lft = mbt - mb, cst = 1 << lft;\n t2.sort(function (a, b) { return tr[b.s] - tr[a.s] || a.f - b.f; });\n for (; i < s; ++i) {\n var i2_1 = t2[i].s;\n if (tr[i2_1] > mb) {\n dt += cst - (1 << (mbt - tr[i2_1]));\n tr[i2_1] = mb;\n }\n else\n break;\n }\n dt >>= lft;\n while (dt > 0) {\n var i2_2 = t2[i].s;\n if (tr[i2_2] < mb)\n dt -= 1 << (mb - tr[i2_2]++ - 1);\n else\n ++i;\n }\n for (; i >= 0 && dt; --i) {\n var i2_3 = t2[i].s;\n if (tr[i2_3] == mb) {\n --tr[i2_3];\n ++dt;\n }\n }\n mbt = mb;\n }\n return { t: new u8(tr), l: mbt };\n};\n// get the max length and assign length codes\nvar ln = function (n, l, d) {\n return n.s == -1\n ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1))\n : (l[n.s] = d);\n};\n// length codes generation\nvar lc = function (c) {\n var s = c.length;\n // Note that the semicolon was intentional\n while (s && !c[--s])\n ;\n var cl = new u16(++s);\n // ind num streak\n var cli = 0, cln = c[0], cls = 1;\n var w = function (v) { cl[cli++] = v; };\n for (var i = 1; i <= s; ++i) {\n if (c[i] == cln && i != s)\n ++cls;\n else {\n if (!cln && cls > 2) {\n for (; cls > 138; cls -= 138)\n w(32754);\n if (cls > 2) {\n w(cls > 10 ? ((cls - 11) << 5) | 28690 : ((cls - 3) << 5) | 12305);\n cls = 0;\n }\n }\n else if (cls > 3) {\n w(cln), --cls;\n for (; cls > 6; cls -= 6)\n w(8304);\n if (cls > 2)\n w(((cls - 3) << 5) | 8208), cls = 0;\n }\n while (cls--)\n w(cln);\n cls = 1;\n cln = c[i];\n }\n }\n return { c: cl.subarray(0, cli), n: s };\n};\n// calculate the length of output from tree, code lengths\nvar clen = function (cf, cl) {\n var l = 0;\n for (var i = 0; i < cl.length; ++i)\n l += cf[i] * cl[i];\n return l;\n};\n// writes a fixed block\n// returns the new bit pos\nvar wfblk = function (out, pos, dat) {\n // no need to write 00 as type: TypedArray defaults to 0\n var s = dat.length;\n var o = shft(pos + 2);\n out[o] = s & 255;\n out[o + 1] = s >> 8;\n out[o + 2] = out[o] ^ 255;\n out[o + 3] = out[o + 1] ^ 255;\n for (var i = 0; i < s; ++i)\n out[o + i + 4] = dat[i];\n return (o + 4 + s) * 8;\n};\n// writes a block\nvar wblk = function (dat, out, final, syms, lf, df, eb, li, bs, bl, p) {\n wbits(out, p++, final);\n ++lf[256];\n var _a = hTree(lf, 15), dlt = _a.t, mlb = _a.l;\n var _b = hTree(df, 15), ddt = _b.t, mdb = _b.l;\n var _c = lc(dlt), lclt = _c.c, nlc = _c.n;\n var _d = lc(ddt), lcdt = _d.c, ndc = _d.n;\n var lcfreq = new u16(19);\n for (var i = 0; i < lclt.length; ++i)\n ++lcfreq[lclt[i] & 31];\n for (var i = 0; i < lcdt.length; ++i)\n ++lcfreq[lcdt[i] & 31];\n var _e = hTree(lcfreq, 7), lct = _e.t, mlcb = _e.l;\n var nlcc = 19;\n for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc)\n ;\n var flen = (bl + 5) << 3;\n var ftlen = clen(lf, flt) + clen(df, fdt) + eb;\n var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + 2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18];\n if (bs >= 0 && flen <= ftlen && flen <= dtlen)\n return wfblk(out, p, dat.subarray(bs, bs + bl));\n var lm, ll, dm, dl;\n wbits(out, p, 1 + (dtlen < ftlen)), p += 2;\n if (dtlen < ftlen) {\n lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt;\n var llm = hMap(lct, mlcb, 0);\n wbits(out, p, nlc - 257);\n wbits(out, p + 5, ndc - 1);\n wbits(out, p + 10, nlcc - 4);\n p += 14;\n for (var i = 0; i < nlcc; ++i)\n wbits(out, p + 3 * i, lct[clim[i]]);\n p += 3 * nlcc;\n var lcts = [lclt, lcdt];\n for (var it = 0; it < 2; ++it) {\n var clct = lcts[it];\n for (var i = 0; i < clct.length; ++i) {\n var len = clct[i] & 31;\n wbits(out, p, llm[len]), p += lct[len];\n if (len > 15)\n wbits(out, p, (clct[i] >> 5) & 127), p += clct[i] >> 12;\n }\n }\n }\n else {\n lm = flm, ll = flt, dm = fdm, dl = fdt;\n }\n for (var i = 0; i < li; ++i) {\n var sym = syms[i];\n if (sym > 255) {\n var len = (sym >> 18) & 31;\n wbits16(out, p, lm[len + 257]), p += ll[len + 257];\n if (len > 7)\n wbits(out, p, (sym >> 23) & 31), p += fleb[len];\n var dst = sym & 31;\n wbits16(out, p, dm[dst]), p += dl[dst];\n if (dst > 3)\n wbits16(out, p, (sym >> 5) & 8191), p += fdeb[dst];\n }\n else {\n wbits16(out, p, lm[sym]), p += ll[sym];\n }\n }\n wbits16(out, p, lm[256]);\n return p + ll[256];\n};\n// deflate options (nice << 13) | chain\nvar deo = /*#__PURE__*/ new i32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]);\n// empty\nvar et = /*#__PURE__*/ new u8(0);\n// compresses data into a raw DEFLATE buffer\nvar dflt = function (dat, lvl, plvl, pre, post, st) {\n var s = st.z || dat.length;\n var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7000)) + post);\n // writing to this writes to the output buffer\n var w = o.subarray(pre, o.length - post);\n var lst = st.l;\n var pos = (st.r || 0) & 7;\n if (lvl) {\n if (pos)\n w[0] = st.r >> 3;\n var opt = deo[lvl - 1];\n var n = opt >> 13, c = opt & 8191;\n var msk_1 = (1 << plvl) - 1;\n // prev 2-byte val map curr 2-byte val map\n var prev = st.p || new u16(32768), head = st.h || new u16(msk_1 + 1);\n var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1;\n var hsh = function (i) { return (dat[i] ^ (dat[i + 1] << bs1_1) ^ (dat[i + 2] << bs2_1)) & msk_1; };\n // 24576 is an arbitrary number of maximum symbols per block\n // 424 buffer for last block\n var syms = new i32(25000);\n // length/literal freq distance freq\n var lf = new u16(288), df = new u16(32);\n // l/lcnt exbits index l/lind waitdx blkpos\n var lc_1 = 0, eb = 0, i = st.i || 0, li = 0, wi = st.w || 0, bs = 0;\n for (; i + 2 < s; ++i) {\n // hash value\n var hv = hsh(i);\n // index mod 32768 previous index mod\n var imod = i & 32767, pimod = head[hv];\n prev[imod] = pimod;\n head[hv] = imod;\n // We always should modify head and prev, but only add symbols if\n // this data is not yet processed (\"wait\" for wait index)\n if (wi <= i) {\n // bytes remaining\n var rem = s - i;\n if ((lc_1 > 7000 || li > 24576) && (rem > 423 || !lst)) {\n pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i - bs, pos);\n li = lc_1 = eb = 0, bs = i;\n for (var j = 0; j < 286; ++j)\n lf[j] = 0;\n for (var j = 0; j < 30; ++j)\n df[j] = 0;\n }\n // len dist chain\n var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767;\n if (rem > 2 && hv == hsh(i - dif)) {\n var maxn = Math.min(n, rem) - 1;\n var maxd = Math.min(32767, i);\n // max possible length\n // not capped at dif because decompressors implement \"rolling\" index population\n var ml = Math.min(258, rem);\n while (dif <= maxd && --ch_1 && imod != pimod) {\n if (dat[i + l] == dat[i + l - dif]) {\n var nl = 0;\n for (; nl < ml && dat[i + nl] == dat[i + nl - dif]; ++nl)\n ;\n if (nl > l) {\n l = nl, d = dif;\n // break out early when we reach \"nice\" (we are satisfied enough)\n if (nl > maxn)\n break;\n // now, find the rarest 2-byte sequence within this\n // length of literals and search for that instead.\n // Much faster than just using the start\n var mmd = Math.min(dif, nl - 2);\n var md = 0;\n for (var j = 0; j < mmd; ++j) {\n var ti = i - dif + j & 32767;\n var pti = prev[ti];\n var cd = ti - pti & 32767;\n if (cd > md)\n md = cd, pimod = ti;\n }\n }\n }\n // check the previous match\n imod = pimod, pimod = prev[imod];\n dif += imod - pimod & 32767;\n }\n }\n // d will be nonzero only when a match was found\n if (d) {\n // store both dist and len data in one int32\n // Make sure this is recognized as a len/dist with 28th bit (2^28)\n syms[li++] = 268435456 | (revfl[l] << 18) | revfd[d];\n var lin = revfl[l] & 31, din = revfd[d] & 31;\n eb += fleb[lin] + fdeb[din];\n ++lf[257 + lin];\n ++df[din];\n wi = i + l;\n ++lc_1;\n }\n else {\n syms[li++] = dat[i];\n ++lf[dat[i]];\n }\n }\n }\n for (i = Math.max(i, wi); i < s; ++i) {\n syms[li++] = dat[i];\n ++lf[dat[i]];\n }\n pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i - bs, pos);\n if (!lst) {\n st.r = (pos & 7) | w[(pos / 8) | 0] << 3;\n // shft(pos) now 1 less if pos & 7 != 0\n pos -= 7;\n st.h = head, st.p = prev, st.i = i, st.w = wi;\n }\n }\n else {\n for (var i = st.w || 0; i < s + lst; i += 65535) {\n // end\n var e = i + 65535;\n if (e >= s) {\n // write final block\n w[(pos / 8) | 0] = lst;\n e = s;\n }\n pos = wfblk(w, pos + 1, dat.subarray(i, e));\n }\n st.i = s;\n }\n return slc(o, 0, pre + shft(pos) + post);\n};\n// CRC32 table\nvar crct = /*#__PURE__*/ (function () {\n var t = new Int32Array(256);\n for (var i = 0; i < 256; ++i) {\n var c = i, k = 9;\n while (--k)\n c = ((c & 1) && -306674912) ^ (c >>> 1);\n t[i] = c;\n }\n return t;\n})();\n// CRC32\nvar crc = function () {\n var c = -1;\n return {\n p: function (d) {\n // closures have awful performance\n var cr = c;\n for (var i = 0; i < d.length; ++i)\n cr = crct[(cr & 255) ^ d[i]] ^ (cr >>> 8);\n c = cr;\n },\n d: function () { return ~c; }\n };\n};\n// Adler32\nvar adler = function () {\n var a = 1, b = 0;\n return {\n p: function (d) {\n // closures have awful performance\n var n = a, m = b;\n var l = d.length | 0;\n for (var i = 0; i != l;) {\n var e = Math.min(i + 2655, l);\n for (; i < e; ++i)\n m += n += d[i];\n n = (n & 65535) + 15 * (n >> 16), m = (m & 65535) + 15 * (m >> 16);\n }\n a = n, b = m;\n },\n d: function () {\n a %= 65521, b %= 65521;\n return (a & 255) << 24 | (a & 0xFF00) << 8 | (b & 255) << 8 | (b >> 8);\n }\n };\n};\n;\n// deflate with opts\nvar dopt = function (dat, opt, pre, post, st) {\n if (!st) {\n st = { l: 1 };\n if (opt.dictionary) {\n var dict = opt.dictionary.subarray(-32768);\n var newDat = new u8(dict.length + dat.length);\n newDat.set(dict);\n newDat.set(dat, dict.length);\n dat = newDat;\n st.w = dict.length;\n }\n }\n return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? (st.l ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 20) : (12 + opt.mem), pre, post, st);\n};\n// Walmart object spread\nvar mrg = function (a, b) {\n var o = {};\n for (var k in a)\n o[k] = a[k];\n for (var k in b)\n o[k] = b[k];\n return o;\n};\n// worker clone\n// This is possibly the craziest part of the entire codebase, despite how simple it may seem.\n// The only parameter to this function is a closure that returns an array of variables outside of the function scope.\n// We're going to try to figure out the variable names used in the closure as strings because that is crucial for workerization.\n// We will return an object mapping of true variable name to value (basically, the current scope as a JS object).\n// The reason we can't just use the original variable names is minifiers mangling the toplevel scope.\n// This took me three weeks to figure out how to do.\nvar wcln = function (fn, fnStr, td) {\n var dt = fn();\n var st = fn.toString();\n var ks = st.slice(st.indexOf('[') + 1, st.lastIndexOf(']')).replace(/\\s+/g, '').split(',');\n for (var i = 0; i < dt.length; ++i) {\n var v = dt[i], k = ks[i];\n if (typeof v == 'function') {\n fnStr += ';' + k + '=';\n var st_1 = v.toString();\n if (v.prototype) {\n // for global objects\n if (st_1.indexOf('[native code]') != -1) {\n var spInd = st_1.indexOf(' ', 8) + 1;\n fnStr += st_1.slice(spInd, st_1.indexOf('(', spInd));\n }\n else {\n fnStr += st_1;\n for (var t in v.prototype)\n fnStr += ';' + k + '.prototype.' + t + '=' + v.prototype[t].toString();\n }\n }\n else\n fnStr += st_1;\n }\n else\n td[k] = v;\n }\n return fnStr;\n};\nvar ch = [];\n// clone bufs\nvar cbfs = function (v) {\n var tl = [];\n for (var k in v) {\n if (v[k].buffer) {\n tl.push((v[k] = new v[k].constructor(v[k])).buffer);\n }\n }\n return tl;\n};\n// use a worker to execute code\nvar wrkr = function (fns, init, id, cb) {\n if (!ch[id]) {\n var fnStr = '', td_1 = {}, m = fns.length - 1;\n for (var i = 0; i < m; ++i)\n fnStr = wcln(fns[i], fnStr, td_1);\n ch[id] = { c: wcln(fns[m], fnStr, td_1), e: td_1 };\n }\n var td = mrg({}, ch[id].e);\n return wk(ch[id].c + ';onmessage=function(e){for(var k in e.data)self[k]=e.data[k];onmessage=' + init.toString() + '}', id, td, cbfs(td), cb);\n};\n// base async inflate fn\nvar bInflt = function () { return [u8, u16, i32, fleb, fdeb, clim, fl, fd, flrm, fdrm, rev, ec, hMap, max, bits, bits16, shft, slc, err, inflt, inflateSync, pbf, gopt]; };\nvar bDflt = function () { return [u8, u16, i32, fleb, fdeb, clim, revfl, revfd, flm, flt, fdm, fdt, rev, deo, et, hMap, wbits, wbits16, hTree, ln, lc, clen, wfblk, wblk, shft, slc, dflt, dopt, deflateSync, pbf]; };\n// gzip extra\nvar gze = function () { return [gzh, gzhl, wbytes, crc, crct]; };\n// gunzip extra\nvar guze = function () { return [gzs, gzl]; };\n// zlib extra\nvar zle = function () { return [zlh, wbytes, adler]; };\n// unzlib extra\nvar zule = function () { return [zls]; };\n// post buf\nvar pbf = function (msg) { return postMessage(msg, [msg.buffer]); };\n// get opts\nvar gopt = function (o) { return o && {\n out: o.size && new u8(o.size),\n dictionary: o.dictionary\n}; };\n// async helper\nvar cbify = function (dat, opts, fns, init, id, cb) {\n var w = wrkr(fns, init, id, function (err, dat) {\n w.terminate();\n cb(err, dat);\n });\n w.postMessage([dat, opts], opts.consume ? [dat.buffer] : []);\n return function () { w.terminate(); };\n};\n// auto stream\nvar astrm = function (strm) {\n strm.ondata = function (dat, final) { return postMessage([dat, final], [dat.buffer]); };\n return function (ev) {\n if (ev.data.length) {\n strm.push(ev.data[0], ev.data[1]);\n postMessage([ev.data[0].length]);\n }\n else\n strm.flush();\n };\n};\n// async stream attach\nvar astrmify = function (fns, strm, opts, init, id, flush, ext) {\n var t;\n var w = wrkr(fns, init, id, function (err, dat) {\n if (err)\n w.terminate(), strm.ondata.call(strm, err);\n else if (!Array.isArray(dat))\n ext(dat);\n else if (dat.length == 1) {\n strm.queuedSize -= dat[0];\n if (strm.ondrain)\n strm.ondrain(dat[0]);\n }\n else {\n if (dat[1])\n w.terminate();\n strm.ondata.call(strm, err, dat[0], dat[1]);\n }\n });\n w.postMessage(opts);\n strm.queuedSize = 0;\n strm.push = function (d, f) {\n if (!strm.ondata)\n err(5);\n if (t)\n strm.ondata(err(4, 0, 1), null, !!f);\n strm.queuedSize += d.length;\n w.postMessage([d, t = f], [d.buffer]);\n };\n strm.terminate = function () { w.terminate(); };\n if (flush) {\n strm.flush = function () { w.postMessage([]); };\n }\n};\n// read 2 bytes\nvar b2 = function (d, b) { return d[b] | (d[b + 1] << 8); };\n// read 4 bytes\nvar b4 = function (d, b) { return (d[b] | (d[b + 1] << 8) | (d[b + 2] << 16) | (d[b + 3] << 24)) >>> 0; };\nvar b8 = function (d, b) { return b4(d, b) + (b4(d, b + 4) * 4294967296); };\n// write bytes\nvar wbytes = function (d, b, v) {\n for (; v; ++b)\n d[b] = v, v >>>= 8;\n};\n// gzip header\nvar gzh = function (c, o) {\n var fn = o.filename;\n c[0] = 31, c[1] = 139, c[2] = 8, c[8] = o.level < 2 ? 4 : o.level == 9 ? 2 : 0, c[9] = 3; // assume Unix\n if (o.mtime != 0)\n wbytes(c, 4, Math.floor(new Date(o.mtime || Date.now()) / 1000));\n if (fn) {\n c[3] = 8;\n for (var i = 0; i <= fn.length; ++i)\n c[i + 10] = fn.charCodeAt(i);\n }\n};\n// gzip footer: -8 to -4 = CRC, -4 to -0 is length\n// gzip start\nvar gzs = function (d) {\n if (d[0] != 31 || d[1] != 139 || d[2] != 8)\n err(6, 'invalid gzip data');\n var flg = d[3];\n var st = 10;\n if (flg & 4)\n st += (d[10] | d[11] << 8) + 2;\n for (var zs = (flg >> 3 & 1) + (flg >> 4 & 1); zs > 0; zs -= !d[st++])\n ;\n return st + (flg & 2);\n};\n// gzip length\nvar gzl = function (d) {\n var l = d.length;\n return (d[l - 4] | d[l - 3] << 8 | d[l - 2] << 16 | d[l - 1] << 24) >>> 0;\n};\n// gzip header length\nvar gzhl = function (o) { return 10 + (o.filename ? o.filename.length + 1 : 0); };\n// zlib header\nvar zlh = function (c, o) {\n var lv = o.level, fl = lv == 0 ? 0 : lv < 6 ? 1 : lv == 9 ? 3 : 2;\n c[0] = 120, c[1] = (fl << 6) | (o.dictionary && 32);\n c[1] |= 31 - ((c[0] << 8) | c[1]) % 31;\n if (o.dictionary) {\n var h = adler();\n h.p(o.dictionary);\n wbytes(c, 2, h.d());\n }\n};\n// zlib start\nvar zls = function (d, dict) {\n if ((d[0] & 15) != 8 || (d[0] >> 4) > 7 || ((d[0] << 8 | d[1]) % 31))\n err(6, 'invalid zlib data');\n if ((d[1] >> 5 & 1) == +!dict)\n err(6, 'invalid zlib data: ' + (d[1] & 32 ? 'need' : 'unexpected') + ' dictionary');\n return (d[1] >> 3 & 4) + 2;\n};\nfunction StrmOpt(opts, cb) {\n if (typeof opts == 'function')\n cb = opts, opts = {};\n this.ondata = cb;\n return opts;\n}\n/**\n * Streaming DEFLATE compression\n */\nvar Deflate = /*#__PURE__*/ (function () {\n function Deflate(opts, cb) {\n if (typeof opts == 'function')\n cb = opts, opts = {};\n this.ondata = cb;\n this.o = opts || {};\n this.s = { l: 0, i: 32768, w: 32768, z: 32768 };\n // Buffer length must always be 0 mod 32768 for index calculations to be correct when modifying head and prev\n // 98304 = 32768 (lookback) + 65536 (common chunk size)\n this.b = new u8(98304);\n if (this.o.dictionary) {\n var dict = this.o.dictionary.subarray(-32768);\n this.b.set(dict, 32768 - dict.length);\n this.s.i = 32768 - dict.length;\n }\n }\n Deflate.prototype.p = function (c, f) {\n this.ondata(dopt(c, this.o, 0, 0, this.s), f);\n };\n /**\n * Pushes a chunk to be deflated\n * @param chunk The chunk to push\n * @param final Whether this is the last chunk\n */\n Deflate.prototype.push = function (chunk, final) {\n if (!this.ondata)\n err(5);\n if (this.s.l)\n err(4);\n var endLen = chunk.length + this.s.z;\n if (endLen > this.b.length) {\n if (endLen > 2 * this.b.length - 32768) {\n var newBuf = new u8(endLen & -32768);\n newBuf.set(this.b.subarray(0, this.s.z));\n this.b = newBuf;\n }\n var split = this.b.length - this.s.z;\n this.b.set(chunk.subarray(0, split), this.s.z);\n this.s.z = this.b.length;\n this.p(this.b, false);\n this.b.set(this.b.subarray(-32768));\n this.b.set(chunk.subarray(split), 32768);\n this.s.z = chunk.length - split + 32768;\n this.s.i = 32766, this.s.w = 32768;\n }\n else {\n this.b.set(chunk, this.s.z);\n this.s.z += chunk.length;\n }\n this.s.l = final & 1;\n if (this.s.z > this.s.w + 8191 || final) {\n this.p(this.b, final || false);\n this.s.w = this.s.i, this.s.i -= 2;\n }\n };\n /**\n * Flushes buffered uncompressed data. Useful to immediately retrieve the\n * deflated output for small inputs.\n */\n Deflate.prototype.flush = function () {\n if (!this.ondata)\n err(5);\n if (this.s.l)\n err(4);\n this.p(this.b, false);\n this.s.w = this.s.i, this.s.i -= 2;\n };\n return Deflate;\n}());\nexport { Deflate };\n/**\n * Asynchronous streaming DEFLATE compression\n */\nvar AsyncDeflate = /*#__PURE__*/ (function () {\n function AsyncDeflate(opts, cb) {\n astrmify([\n bDflt,\n function () { return [astrm, Deflate]; }\n ], this, StrmOpt.call(this, opts, cb), function (ev) {\n var strm = new Deflate(ev.data);\n onmessage = astrm(strm);\n }, 6, 1);\n }\n return AsyncDeflate;\n}());\nexport { AsyncDeflate };\nexport function deflate(data, opts, cb) {\n if (!cb)\n cb = opts, opts = {};\n if (typeof cb != 'function')\n err(7);\n return cbify(data, opts, [\n bDflt,\n ], function (ev) { return pbf(deflateSync(ev.data[0], ev.data[1])); }, 0, cb);\n}\n/**\n * Compresses data with DEFLATE without any wrapper\n * @param data The data to compress\n * @param opts The compression options\n * @returns The deflated version of the data\n */\nexport function deflateSync(data, opts) {\n return dopt(data, opts || {}, 0, 0);\n}\n/**\n * Streaming DEFLATE decompression\n */\nvar Inflate = /*#__PURE__*/ (function () {\n function Inflate(opts, cb) {\n // no StrmOpt here to avoid adding to workerizer\n if (typeof opts == 'function')\n cb = opts, opts = {};\n this.ondata = cb;\n var dict = opts && opts.dictionary && opts.dictionary.subarray(-32768);\n this.s = { i: 0, b: dict ? dict.length : 0 };\n this.o = new u8(32768);\n this.p = new u8(0);\n if (dict)\n this.o.set(dict);\n }\n Inflate.prototype.e = function (c) {\n if (!this.ondata)\n err(5);\n if (this.d)\n err(4);\n if (!this.p.length)\n this.p = c;\n else if (c.length) {\n var n = new u8(this.p.length + c.length);\n n.set(this.p), n.set(c, this.p.length), this.p = n;\n }\n };\n Inflate.prototype.c = function (final) {\n this.s.i = +(this.d = final || false);\n var bts = this.s.b;\n var dt = inflt(this.p, this.s, this.o);\n this.ondata(slc(dt, bts, this.s.b), this.d);\n this.o = slc(dt, this.s.b - 32768), this.s.b = this.o.length;\n this.p = slc(this.p, (this.s.p / 8) | 0), this.s.p &= 7;\n };\n /**\n * Pushes a chunk to be inflated\n * @param chunk The chunk to push\n * @param final Whether this is the final chunk\n */\n Inflate.prototype.push = function (chunk, final) {\n this.e(chunk), this.c(final);\n };\n return Inflate;\n}());\nexport { Inflate };\n/**\n * Asynchronous streaming DEFLATE decompression\n */\nvar AsyncInflate = /*#__PURE__*/ (function () {\n function AsyncInflate(opts, cb) {\n astrmify([\n bInflt,\n function () { return [astrm, Inflate]; }\n ], this, StrmOpt.call(this, opts, cb), function (ev) {\n var strm = new Inflate(ev.data);\n onmessage = astrm(strm);\n }, 7, 0);\n }\n return AsyncInflate;\n}());\nexport { AsyncInflate };\nexport function inflate(data, opts, cb) {\n if (!cb)\n cb = opts, opts = {};\n if (typeof cb != 'function')\n err(7);\n return cbify(data, opts, [\n bInflt\n ], function (ev) { return pbf(inflateSync(ev.data[0], gopt(ev.data[1]))); }, 1, cb);\n}\n/**\n * Expands DEFLATE data with no wrapper\n * @param data The data to decompress\n * @param opts The decompression options\n * @returns The decompressed version of the data\n */\nexport function inflateSync(data, opts) {\n return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary);\n}\n// before you yell at me for not just using extends, my reason is that TS inheritance is hard to workerize.\n/**\n * Streaming GZIP compression\n */\nvar Gzip = /*#__PURE__*/ (function () {\n function Gzip(opts, cb) {\n this.c = crc();\n this.l = 0;\n this.v = 1;\n Deflate.call(this, opts, cb);\n }\n /**\n * Pushes a chunk to be GZIPped\n * @param chunk The chunk to push\n * @param final Whether this is the last chunk\n */\n Gzip.prototype.push = function (chunk, final) {\n this.c.p(chunk);\n this.l += chunk.length;\n Deflate.prototype.push.call(this, chunk, final);\n };\n Gzip.prototype.p = function (c, f) {\n var raw = dopt(c, this.o, this.v && gzhl(this.o), f && 8, this.s);\n if (this.v)\n gzh(raw, this.o), this.v = 0;\n if (f)\n wbytes(raw, raw.length - 8, this.c.d()), wbytes(raw, raw.length - 4, this.l);\n this.ondata(raw, f);\n };\n /**\n * Flushes buffered uncompressed data. Useful to immediately retrieve the\n * GZIPped output for small inputs.\n */\n Gzip.prototype.flush = function () {\n Deflate.prototype.flush.call(this);\n };\n return Gzip;\n}());\nexport { Gzip };\n/**\n * Asynchronous streaming GZIP compression\n */\nvar AsyncGzip = /*#__PURE__*/ (function () {\n function AsyncGzip(opts, cb) {\n astrmify([\n bDflt,\n gze,\n function () { return [astrm, Deflate, Gzip]; }\n ], this, StrmOpt.call(this, opts, cb), function (ev) {\n var strm = new Gzip(ev.data);\n onmessage = astrm(strm);\n }, 8, 1);\n }\n return AsyncGzip;\n}());\nexport { AsyncGzip };\nexport function gzip(data, opts, cb) {\n if (!cb)\n cb = opts, opts = {};\n if (typeof cb != 'function')\n err(7);\n return cbify(data, opts, [\n bDflt,\n gze,\n function () { return [gzipSync]; }\n ], function (ev) { return pbf(gzipSync(ev.data[0], ev.data[1])); }, 2, cb);\n}\n/**\n * Compresses data with GZIP\n * @param data The data to compress\n * @param opts The compression options\n * @returns The gzipped version of the data\n */\nexport function gzipSync(data, opts) {\n if (!opts)\n opts = {};\n var c = crc(), l = data.length;\n c.p(data);\n var d = dopt(data, opts, gzhl(opts), 8), s = d.length;\n return gzh(d, opts), wbytes(d, s - 8, c.d()), wbytes(d, s - 4, l), d;\n}\n/**\n * Streaming single or multi-member GZIP decompression\n */\nvar Gunzip = /*#__PURE__*/ (function () {\n function Gunzip(opts, cb) {\n this.v = 1;\n this.r = 0;\n Inflate.call(this, opts, cb);\n }\n /**\n * Pushes a chunk to be GUNZIPped\n * @param chunk The chunk to push\n * @param final Whether this is the last chunk\n */\n Gunzip.prototype.push = function (chunk, final) {\n Inflate.prototype.e.call(this, chunk);\n this.r += chunk.length;\n if (this.v) {\n var p = this.p.subarray(this.v - 1);\n var s = p.length > 3 ? gzs(p) : 4;\n if (s > p.length) {\n if (!final)\n return;\n }\n else if (this.v > 1 && this.onmember) {\n this.onmember(this.r - p.length);\n }\n this.p = p.subarray(s), this.v = 0;\n }\n // necessary to prevent TS from using the closure value\n // This allows for workerization to function correctly\n Inflate.prototype.c.call(this, final);\n // process concatenated GZIP\n if (this.s.f && !this.s.l && !final) {\n this.v = shft(this.s.p) + 9;\n this.s = { i: 0 };\n this.o = new u8(0);\n this.push(new u8(0), final);\n }\n };\n return Gunzip;\n}());\nexport { Gunzip };\n/**\n * Asynchronous streaming single or multi-member GZIP decompression\n */\nvar AsyncGunzip = /*#__PURE__*/ (function () {\n function AsyncGunzip(opts, cb) {\n var _this = this;\n astrmify([\n bInflt,\n guze,\n function () { return [astrm, Inflate, Gunzip]; }\n ], this, StrmOpt.call(this, opts, cb), function (ev) {\n var strm = new Gunzip(ev.data);\n strm.onmember = function (offset) { return postMessage(offset); };\n onmessage = astrm(strm);\n }, 9, 0, function (offset) { return _this.onmember && _this.onmember(offset); });\n }\n return AsyncGunzip;\n}());\nexport { AsyncGunzip };\nexport function gunzip(data, opts, cb) {\n if (!cb)\n cb = opts, opts = {};\n if (typeof cb != 'function')\n err(7);\n return cbify(data, opts, [\n bInflt,\n guze,\n function () { return [gunzipSync]; }\n ], function (ev) { return pbf(gunzipSync(ev.data[0], ev.data[1])); }, 3, cb);\n}\n/**\n * Expands GZIP data\n * @param data The data to decompress\n * @param opts The decompression options\n * @returns The decompressed version of the data\n */\nexport function gunzipSync(data, opts) {\n var st = gzs(data);\n if (st + 8 > data.length)\n err(6, 'invalid gzip data');\n return inflt(data.subarray(st, -8), { i: 2 }, opts && opts.out || new u8(gzl(data)), opts && opts.dictionary);\n}\n/**\n * Streaming Zlib compression\n */\nvar Zlib = /*#__PURE__*/ (function () {\n function Zlib(opts, cb) {\n this.c = adler();\n this.v = 1;\n Deflate.call(this, opts, cb);\n }\n /**\n * Pushes a chunk to be zlibbed\n * @param chunk The chunk to push\n * @param final Whether this is the last chunk\n */\n Zlib.prototype.push = function (chunk, final) {\n this.c.p(chunk);\n Deflate.prototype.push.call(this, chunk, final);\n };\n Zlib.prototype.p = function (c, f) {\n var raw = dopt(c, this.o, this.v && (this.o.dictionary ? 6 : 2), f && 4, this.s);\n if (this.v)\n zlh(raw, this.o), this.v = 0;\n if (f)\n wbytes(raw, raw.length - 4, this.c.d());\n this.ondata(raw, f);\n };\n /**\n * Flushes buffered uncompressed data. Useful to immediately retrieve the\n * zlibbed output for small inputs.\n */\n Zlib.prototype.flush = function () {\n Deflate.prototype.flush.call(this);\n };\n return Zlib;\n}());\nexport { Zlib };\n/**\n * Asynchronous streaming Zlib compression\n */\nvar AsyncZlib = /*#__PURE__*/ (function () {\n function AsyncZlib(opts, cb) {\n astrmify([\n bDflt,\n zle,\n function () { return [astrm, Deflate, Zlib]; }\n ], this, StrmOpt.call(this, opts, cb), function (ev) {\n var strm = new Zlib(ev.data);\n onmessage = astrm(strm);\n }, 10, 1);\n }\n return AsyncZlib;\n}());\nexport { AsyncZlib };\nexport function zlib(data, opts, cb) {\n if (!cb)\n cb = opts, opts = {};\n if (typeof cb != 'function')\n err(7);\n return cbify(data, opts, [\n bDflt,\n zle,\n function () { return [zlibSync]; }\n ], function (ev) { return pbf(zlibSync(ev.data[0], ev.data[1])); }, 4, cb);\n}\n/**\n * Compress data with Zlib\n * @param data The data to compress\n * @param opts The compression options\n * @returns The zlib-compressed version of the data\n */\nexport function zlibSync(data, opts) {\n if (!opts)\n opts = {};\n var a = adler();\n a.p(data);\n var d = dopt(data, opts, opts.dictionary ? 6 : 2, 4);\n return zlh(d, opts), wbytes(d, d.length - 4, a.d()), d;\n}\n/**\n * Streaming Zlib decompression\n */\nvar Unzlib = /*#__PURE__*/ (function () {\n function Unzlib(opts, cb) {\n Inflate.call(this, opts, cb);\n this.v = opts && opts.dictionary ? 2 : 1;\n }\n /**\n * Pushes a chunk to be unzlibbed\n * @param chunk The chunk to push\n * @param final Whether this is the last chunk\n */\n Unzlib.prototype.push = function (chunk, final) {\n Inflate.prototype.e.call(this, chunk);\n if (this.v) {\n if (this.p.length < 6 && !final)\n return;\n this.p = this.p.subarray(zls(this.p, this.v - 1)), this.v = 0;\n }\n if (final) {\n if (this.p.length < 4)\n err(6, 'invalid zlib data');\n this.p = this.p.subarray(0, -4);\n }\n // necessary to prevent TS from using the closure value\n // This allows for workerization to function correctly\n Inflate.prototype.c.call(this, final);\n };\n return Unzlib;\n}());\nexport { Unzlib };\n/**\n * Asynchronous streaming Zlib decompression\n */\nvar AsyncUnzlib = /*#__PURE__*/ (function () {\n function AsyncUnzlib(opts, cb) {\n astrmify([\n bInflt,\n zule,\n function () { return [astrm, Inflate, Unzlib]; }\n ], this, StrmOpt.call(this, opts, cb), function (ev) {\n var strm = new Unzlib(ev.data);\n onmessage = astrm(strm);\n }, 11, 0);\n }\n return AsyncUnzlib;\n}());\nexport { AsyncUnzlib };\nexport function unzlib(data, opts, cb) {\n if (!cb)\n cb = opts, opts = {};\n if (typeof cb != 'function')\n err(7);\n return cbify(data, opts, [\n bInflt,\n zule,\n function () { return [unzlibSync]; }\n ], function (ev) { return pbf(unzlibSync(ev.data[0], gopt(ev.data[1]))); }, 5, cb);\n}\n/**\n * Expands Zlib data\n * @param data The data to decompress\n * @param opts The decompression options\n * @returns The decompressed version of the data\n */\nexport function unzlibSync(data, opts) {\n return inflt(data.subarray(zls(data, opts && opts.dictionary), -4), { i: 2 }, opts && opts.out, opts && opts.dictionary);\n}\n// Default algorithm for compression (used because having a known output size allows faster decompression)\nexport { gzip as compress, AsyncGzip as AsyncCompress };\nexport { gzipSync as compressSync, Gzip as Compress };\n/**\n * Streaming GZIP, Zlib, or raw DEFLATE decompression\n */\nvar Decompress = /*#__PURE__*/ (function () {\n function Decompress(opts, cb) {\n this.o = StrmOpt.call(this, opts, cb) || {};\n this.G = Gunzip;\n this.I = Inflate;\n this.Z = Unzlib;\n }\n // init substream\n // overriden by AsyncDecompress\n Decompress.prototype.i = function () {\n var _this = this;\n this.s.ondata = function (dat, final) {\n _this.ondata(dat, final);\n };\n };\n /**\n * Pushes a chunk to be decompressed\n * @param chunk The chunk to push\n * @param final Whether this is the last chunk\n */\n Decompress.prototype.push = function (chunk, final) {\n if (!this.ondata)\n err(5);\n if (!this.s) {\n if (this.p && this.p.length) {\n var n = new u8(this.p.length + chunk.length);\n n.set(this.p), n.set(chunk, this.p.length);\n }\n else\n this.p = chunk;\n if (this.p.length > 2) {\n this.s = (this.p[0] == 31 && this.p[1] == 139 && this.p[2] == 8)\n ? new this.G(this.o)\n : ((this.p[0] & 15) != 8 || (this.p[0] >> 4) > 7 || ((this.p[0] << 8 | this.p[1]) % 31))\n ? new this.I(this.o)\n : new this.Z(this.o);\n this.i();\n this.s.push(this.p, final);\n this.p = null;\n }\n }\n else\n this.s.push(chunk, final);\n };\n return Decompress;\n}());\nexport { Decompress };\n/**\n * Asynchronous streaming GZIP, Zlib, or raw DEFLATE decompression\n */\nvar AsyncDecompress = /*#__PURE__*/ (function () {\n function AsyncDecompress(opts, cb) {\n Decompress.call(this, opts, cb);\n this.queuedSize = 0;\n this.G = AsyncGunzip;\n this.I = AsyncInflate;\n this.Z = AsyncUnzlib;\n }\n AsyncDecompress.prototype.i = function () {\n var _this = this;\n this.s.ondata = function (err, dat, final) {\n _this.ondata(err, dat, final);\n };\n this.s.ondrain = function (size) {\n _this.queuedSize -= size;\n if (_this.ondrain)\n _this.ondrain(size);\n };\n };\n /**\n * Pushes a chunk to be decompressed\n * @param chunk The chunk to push\n * @param final Whether this is the last chunk\n */\n AsyncDecompress.prototype.push = function (chunk, final) {\n this.queuedSize += chunk.length;\n Decompress.prototype.push.call(this, chunk, final);\n };\n return AsyncDecompress;\n}());\nexport { AsyncDecompress };\nexport function decompress(data, opts, cb) {\n if (!cb)\n cb = opts, opts = {};\n if (typeof cb != 'function')\n err(7);\n return (data[0] == 31 && data[1] == 139 && data[2] == 8)\n ? gunzip(data, opts, cb)\n : ((data[0] & 15) != 8 || (data[0] >> 4) > 7 || ((data[0] << 8 | data[1]) % 31))\n ? inflate(data, opts, cb)\n : unzlib(data, opts, cb);\n}\n/**\n * Expands compressed GZIP, Zlib, or raw DEFLATE data, automatically detecting the format\n * @param data The data to decompress\n * @param opts The decompression options\n * @returns The decompressed version of the data\n */\nexport function decompressSync(data, opts) {\n return (data[0] == 31 && data[1] == 139 && data[2] == 8)\n ? gunzipSync(data, opts)\n : ((data[0] & 15) != 8 || (data[0] >> 4) > 7 || ((data[0] << 8 | data[1]) % 31))\n ? inflateSync(data, opts)\n : unzlibSync(data, opts);\n}\n// flatten a directory structure\nvar fltn = function (d, p, t, o) {\n for (var k in d) {\n var val = d[k], n = p + k, op = o;\n if (Array.isArray(val))\n op = mrg(o, val[1]), val = val[0];\n if (val instanceof u8)\n t[n] = [val, op];\n else {\n t[n += '/'] = [new u8(0), op];\n fltn(val, n, t, o);\n }\n }\n};\n// text encoder\nvar te = typeof TextEncoder != 'undefined' && /*#__PURE__*/ new TextEncoder();\n// text decoder\nvar td = typeof TextDecoder != 'undefined' && /*#__PURE__*/ new TextDecoder();\n// text decoder stream\nvar tds = 0;\ntry {\n td.decode(et, { stream: true });\n tds = 1;\n}\ncatch (e) { }\n// decode UTF8\nvar dutf8 = function (d) {\n for (var r = '', i = 0;;) {\n var c = d[i++];\n var eb = (c > 127) + (c > 223) + (c > 239);\n if (i + eb > d.length)\n return { s: r, r: slc(d, i - 1) };\n if (!eb)\n r += String.fromCharCode(c);\n else if (eb == 3) {\n c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | (d[i++] & 63)) - 65536,\n r += String.fromCharCode(55296 | (c >> 10), 56320 | (c & 1023));\n }\n else if (eb & 1)\n r += String.fromCharCode((c & 31) << 6 | (d[i++] & 63));\n else\n r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | (d[i++] & 63));\n }\n};\n/**\n * Streaming UTF-8 decoding\n */\nvar DecodeUTF8 = /*#__PURE__*/ (function () {\n /**\n * Creates a UTF-8 decoding stream\n * @param cb The callback to call whenever data is decoded\n */\n function DecodeUTF8(cb) {\n this.ondata = cb;\n if (tds)\n this.t = new TextDecoder();\n else\n this.p = et;\n }\n /**\n * Pushes a chunk to be decoded from UTF-8 binary\n * @param chunk The chunk to push\n * @param final Whether this is the last chunk\n */\n DecodeUTF8.prototype.push = function (chunk, final) {\n if (!this.ondata)\n err(5);\n final = !!final;\n if (this.t) {\n this.ondata(this.t.decode(chunk, { stream: true }), final);\n if (final) {\n if (this.t.decode().length)\n err(8);\n this.t = null;\n }\n return;\n }\n if (!this.p)\n err(4);\n var dat = new u8(this.p.length + chunk.length);\n dat.set(this.p);\n dat.set(chunk, this.p.length);\n var _a = dutf8(dat), s = _a.s, r = _a.r;\n if (final) {\n if (r.length)\n err(8);\n this.p = null;\n }\n else\n this.p = r;\n this.ondata(s, final);\n };\n return DecodeUTF8;\n}());\nexport { DecodeUTF8 };\n/**\n * Streaming UTF-8 encoding\n */\nvar EncodeUTF8 = /*#__PURE__*/ (function () {\n /**\n * Creates a UTF-8 decoding stream\n * @param cb The callback to call whenever data is encoded\n */\n function EncodeUTF8(cb) {\n this.ondata = cb;\n }\n /**\n * Pushes a chunk to be encoded to UTF-8\n * @param chunk The string data to push\n * @param final Whether this is the last chunk\n */\n EncodeUTF8.prototype.push = function (chunk, final) {\n if (!this.ondata)\n err(5);\n if (this.d)\n err(4);\n this.ondata(strToU8(chunk), this.d = final || false);\n };\n return EncodeUTF8;\n}());\nexport { EncodeUTF8 };\n/**\n * Converts a string into a Uint8Array for use with compression/decompression methods\n * @param str The string to encode\n * @param latin1 Whether or not to interpret the data as Latin-1. This should\n * not need to be true unless decoding a binary string.\n * @returns The string encoded in UTF-8/Latin-1 binary\n */\nexport function strToU8(str, latin1) {\n if (latin1) {\n var ar_1 = new u8(str.length);\n for (var i = 0; i < str.length; ++i)\n ar_1[i] = str.charCodeAt(i);\n return ar_1;\n }\n if (te)\n return te.encode(str);\n var l = str.length;\n var ar = new u8(str.length + (str.length >> 1));\n var ai = 0;\n var w = function (v) { ar[ai++] = v; };\n for (var i = 0; i < l; ++i) {\n if (ai + 5 > ar.length) {\n var n = new u8(ai + 8 + ((l - i) << 1));\n n.set(ar);\n ar = n;\n }\n var c = str.charCodeAt(i);\n if (c < 128 || latin1)\n w(c);\n else if (c < 2048)\n w(192 | (c >> 6)), w(128 | (c & 63));\n else if (c > 55295 && c < 57344)\n c = 65536 + (c & 1023 << 10) | (str.charCodeAt(++i) & 1023),\n w(240 | (c >> 18)), w(128 | ((c >> 12) & 63)), w(128 | ((c >> 6) & 63)), w(128 | (c & 63));\n else\n w(224 | (c >> 12)), w(128 | ((c >> 6) & 63)), w(128 | (c & 63));\n }\n return slc(ar, 0, ai);\n}\n/**\n * Converts a Uint8Array to a string\n * @param dat The data to decode to string\n * @param latin1 Whether or not to interpret the data as Latin-1. This should\n * not need to be true unless encoding to binary string.\n * @returns The original UTF-8/Latin-1 string\n */\nexport function strFromU8(dat, latin1) {\n if (latin1) {\n var r = '';\n for (var i = 0; i < dat.length; i += 16384)\n r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384));\n return r;\n }\n else if (td) {\n return td.decode(dat);\n }\n else {\n var _a = dutf8(dat), s = _a.s, r = _a.r;\n if (r.length)\n err(8);\n return s;\n }\n}\n;\n// deflate bit flag\nvar dbf = function (l) { return l == 1 ? 3 : l < 6 ? 2 : l == 9 ? 1 : 0; };\n// skip local zip header\nvar slzh = function (d, b) { return b + 30 + b2(d, b + 26) + b2(d, b + 28); };\n// read zip header\nvar zh = function (d, b, z) {\n var fnl = b2(d, b + 28), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl, bs = b4(d, b + 20);\n var _a = z && bs == 4294967295 ? z64e(d, es) : [bs, b4(d, b + 24), b4(d, b + 42)], sc = _a[0], su = _a[1], off = _a[2];\n return [b2(d, b + 10), sc, su, fn, es + b2(d, b + 30) + b2(d, b + 32), off];\n};\n// read zip64 extra field\nvar z64e = function (d, b) {\n for (; b2(d, b) != 1; b += 4 + b2(d, b + 2))\n ;\n return [b8(d, b + 12), b8(d, b + 4), b8(d, b + 20)];\n};\n// extra field length\nvar exfl = function (ex) {\n var le = 0;\n if (ex) {\n for (var k in ex) {\n var l = ex[k].length;\n if (l > 65535)\n err(9);\n le += l + 4;\n }\n }\n return le;\n};\n// write zip header\nvar wzh = function (d, b, f, fn, u, c, ce, co) {\n var fl = fn.length, ex = f.extra, col = co && co.length;\n var exl = exfl(ex);\n wbytes(d, b, ce != null ? 0x2014B50 : 0x4034B50), b += 4;\n if (ce != null)\n d[b++] = 20, d[b++] = f.os;\n d[b] = 20, b += 2; // spec compliance? what's that?\n d[b++] = (f.flag << 1) | (c < 0 && 8), d[b++] = u && 8;\n d[b++] = f.compression & 255, d[b++] = f.compression >> 8;\n var dt = new Date(f.mtime == null ? Date.now() : f.mtime), y = dt.getFullYear() - 1980;\n if (y < 0 || y > 119)\n err(10);\n wbytes(d, b, (y << 25) | ((dt.getMonth() + 1) << 21) | (dt.getDate() << 16) | (dt.getHours() << 11) | (dt.getMinutes() << 5) | (dt.getSeconds() >> 1)), b += 4;\n if (c != -1) {\n wbytes(d, b, f.crc);\n wbytes(d, b + 4, c < 0 ? -c - 2 : c);\n wbytes(d, b + 8, f.size);\n }\n wbytes(d, b + 12, fl);\n wbytes(d, b + 14, exl), b += 16;\n if (ce != null) {\n wbytes(d, b, col);\n wbytes(d, b + 6, f.attrs);\n wbytes(d, b + 10, ce), b += 14;\n }\n d.set(fn, b);\n b += fl;\n if (exl) {\n for (var k in ex) {\n var exf = ex[k], l = exf.length;\n wbytes(d, b, +k);\n wbytes(d, b + 2, l);\n d.set(exf, b + 4), b += 4 + l;\n }\n }\n if (col)\n d.set(co, b), b += col;\n return b;\n};\n// write zip footer (end of central directory)\nvar wzf = function (o, b, c, d, e) {\n wbytes(o, b, 0x6054B50); // skip disk\n wbytes(o, b + 8, c);\n wbytes(o, b + 10, c);\n wbytes(o, b + 12, d);\n wbytes(o, b + 16, e);\n};\n/**\n * A pass-through stream to keep data uncompressed in a ZIP archive.\n */\nvar ZipPassThrough = /*#__PURE__*/ (function () {\n /**\n * Creates a pass-through stream that can be added to ZIP archives\n * @param filename The filename to associate with this data stream\n */\n function ZipPassThrough(filename) {\n this.filename = filename;\n this.c = crc();\n this.size = 0;\n this.compression = 0;\n }\n /**\n * Processes a chunk and pushes to the output stream. You can override this\n * method in a subclass for custom behavior, but by default this passes\n * the data through. You must call this.ondata(err, chunk, final) at some\n * point in this method.\n * @param chunk The chunk to process\n * @param final Whether this is the last chunk\n */\n ZipPassThrough.prototype.process = function (chunk, final) {\n this.ondata(null, chunk, final);\n };\n /**\n * Pushes a chunk to be added. If you are subclassing this with a custom\n * compression algorithm, note that you must push data from the source\n * file only, pre-compression.\n * @param chunk The chunk to push\n * @param final Whether this is the last chunk\n */\n ZipPassThrough.prototype.push = function (chunk, final) {\n if (!this.ondata)\n err(5);\n this.c.p(chunk);\n this.size += chunk.length;\n if (final)\n this.crc = this.c.d();\n this.process(chunk, final || false);\n };\n return ZipPassThrough;\n}());\nexport { ZipPassThrough };\n// I don't extend because TypeScript extension adds 1kB of runtime bloat\n/**\n * Streaming DEFLATE compression for ZIP archives. Prefer using AsyncZipDeflate\n * for better performance\n */\nvar ZipDeflate = /*#__PURE__*/ (function () {\n /**\n * Creates a DEFLATE stream that can be added to ZIP archives\n * @param filename The filename to associate with this data stream\n * @param opts The compression options\n */\n function ZipDeflate(filename, opts) {\n var _this = this;\n if (!opts)\n opts = {};\n ZipPassThrough.call(this, filename);\n this.d = new Deflate(opts, function (dat, final) {\n _this.ondata(null, dat, final);\n });\n this.compression = 8;\n this.flag = dbf(opts.level);\n }\n ZipDeflate.prototype.process = function (chunk, final) {\n try {\n this.d.push(chunk, final);\n }\n catch (e) {\n this.ondata(e, null, final);\n }\n };\n /**\n * Pushes a chunk to be deflated\n * @param chunk The chunk to push\n * @param final Whether this is the last chunk\n */\n ZipDeflate.prototype.push = function (chunk, final) {\n ZipPassThrough.prototype.push.call(this, chunk, final);\n };\n return ZipDeflate;\n}());\nexport { ZipDeflate };\n/**\n * Asynchronous streaming DEFLATE compression for ZIP archives\n */\nvar AsyncZipDeflate = /*#__PURE__*/ (function () {\n /**\n * Creates an asynchronous DEFLATE stream that can be added to ZIP archives\n * @param filename The filename to associate with this data stream\n * @param opts The compression options\n */\n function AsyncZipDeflate(filename, opts) {\n var _this = this;\n if (!opts)\n opts = {};\n ZipPassThrough.call(this, filename);\n this.d = new AsyncDeflate(opts, function (err, dat, final) {\n _this.ondata(err, dat, final);\n });\n this.compression = 8;\n this.flag = dbf(opts.level);\n this.terminate = this.d.terminate;\n }\n AsyncZipDeflate.prototype.process = function (chunk, final) {\n this.d.push(chunk, final);\n };\n /**\n * Pushes a chunk to be deflated\n * @param chunk The chunk to push\n * @param final Whether this is the last chunk\n */\n AsyncZipDeflate.prototype.push = function (chunk, final) {\n ZipPassThrough.prototype.push.call(this, chunk, final);\n };\n return AsyncZipDeflate;\n}());\nexport { AsyncZipDeflate };\n// TODO: Better tree shaking\n/**\n * A zippable archive to which files can incrementally be added\n */\nvar Zip = /*#__PURE__*/ (function () {\n /**\n * Creates an empty ZIP archive to which files can be added\n * @param cb The callback to call whenever data for the generated ZIP archive\n * is available\n */\n function Zip(cb) {\n this.ondata = cb;\n this.u = [];\n this.d = 1;\n }\n /**\n * Adds a file to the ZIP archive\n * @param file The file stream to add\n */\n Zip.prototype.add = function (file) {\n var _this = this;\n if (!this.ondata)\n err(5);\n // finishing or finished\n if (this.d & 2)\n this.ondata(err(4 + (this.d & 1) * 8, 0, 1), null, false);\n else {\n var f = strToU8(file.filename), fl_1 = f.length;\n var com = file.comment, o = com && strToU8(com);\n var u = fl_1 != file.filename.length || (o && (com.length != o.length));\n var hl_1 = fl_1 + exfl(file.extra) + 30;\n if (fl_1 > 65535)\n this.ondata(err(11, 0, 1), null, false);\n var header = new u8(hl_1);\n wzh(header, 0, file, f, u, -1);\n var chks_1 = [header];\n var pAll_1 = function () {\n for (var _i = 0, chks_2 = chks_1; _i < chks_2.length; _i++) {\n var chk = chks_2[_i];\n _this.ondata(null, chk, false);\n }\n chks_1 = [];\n };\n var tr_1 = this.d;\n this.d = 0;\n var ind_1 = this.u.length;\n var uf_1 = mrg(file, {\n f: f,\n u: u,\n o: o,\n t: function () {\n if (file.terminate)\n file.terminate();\n },\n r: function () {\n pAll_1();\n if (tr_1) {\n var nxt = _this.u[ind_1 + 1];\n if (nxt)\n nxt.r();\n else\n _this.d = 1;\n }\n tr_1 = 1;\n }\n });\n var cl_1 = 0;\n file.ondata = function (err, dat, final) {\n if (err) {\n _this.ondata(err, dat, final);\n _this.terminate();\n }\n else {\n cl_1 += dat.length;\n chks_1.push(dat);\n if (final) {\n var dd = new u8(16);\n wbytes(dd, 0, 0x8074B50);\n wbytes(dd, 4, file.crc);\n wbytes(dd, 8, cl_1);\n wbytes(dd, 12, file.size);\n chks_1.push(dd);\n uf_1.c = cl_1, uf_1.b = hl_1 + cl_1 + 16, uf_1.crc = file.crc, uf_1.size = file.size;\n if (tr_1)\n uf_1.r();\n tr_1 = 1;\n }\n else if (tr_1)\n pAll_1();\n }\n };\n this.u.push(uf_1);\n }\n };\n /**\n * Ends the process of adding files and prepares to emit the final chunks.\n * This *must* be called after adding all desired files for the resulting\n * ZIP file to work properly.\n */\n Zip.prototype.end = function () {\n var _this = this;\n if (this.d & 2) {\n this.ondata(err(4 + (this.d & 1) * 8, 0, 1), null, true);\n return;\n }\n if (this.d)\n this.e();\n else\n this.u.push({\n r: function () {\n if (!(_this.d & 1))\n return;\n _this.u.splice(-1, 1);\n _this.e();\n },\n t: function () { }\n });\n this.d = 3;\n };\n Zip.prototype.e = function () {\n var bt = 0, l = 0, tl = 0;\n for (var _i = 0, _a = this.u; _i < _a.length; _i++) {\n var f = _a[_i];\n tl += 46 + f.f.length + exfl(f.extra) + (f.o ? f.o.length : 0);\n }\n var out = new u8(tl + 22);\n for (var _b = 0, _c = this.u; _b < _c.length; _b++) {\n var f = _c[_b];\n wzh(out, bt, f, f.f, f.u, -f.c - 2, l, f.o);\n bt += 46 + f.f.length + exfl(f.extra) + (f.o ? f.o.length : 0), l += f.b;\n }\n wzf(out, bt, this.u.length, tl, l);\n this.ondata(null, out, true);\n this.d = 2;\n };\n /**\n * A method to terminate any internal workers used by the stream. Subsequent\n * calls to add() will fail.\n */\n Zip.prototype.terminate = function () {\n for (var _i = 0, _a = this.u; _i < _a.length; _i++) {\n var f = _a[_i];\n f.t();\n }\n this.d = 2;\n };\n return Zip;\n}());\nexport { Zip };\nexport function zip(data, opts, cb) {\n if (!cb)\n cb = opts, opts = {};\n if (typeof cb != 'function')\n err(7);\n var r = {};\n fltn(data, '', r, opts);\n var k = Object.keys(r);\n var lft = k.length, o = 0, tot = 0;\n var slft = lft, files = new Array(lft);\n var term = [];\n var tAll = function () {\n for (var i = 0; i < term.length; ++i)\n term[i]();\n };\n var cbd = function (a, b) {\n mt(function () { cb(a, b); });\n };\n mt(function () { cbd = cb; });\n var cbf = function () {\n var out = new u8(tot + 22), oe = o, cdl = tot - o;\n tot = 0;\n for (var i = 0; i < slft; ++i) {\n var f = files[i];\n try {\n var l = f.c.length;\n wzh(out, tot, f, f.f, f.u, l);\n var badd = 30 + f.f.length + exfl(f.extra);\n var loc = tot + badd;\n out.set(f.c, loc);\n wzh(out, o, f, f.f, f.u, l, tot, f.m), o += 16 + badd + (f.m ? f.m.length : 0), tot = loc + l;\n }\n catch (e) {\n return cbd(e, null);\n }\n }\n wzf(out, o, files.length, cdl, oe);\n cbd(null, out);\n };\n if (!lft)\n cbf();\n var _loop_1 = function (i) {\n var fn = k[i];\n var _a = r[fn], file = _a[0], p = _a[1];\n var c = crc(), size = file.length;\n c.p(file);\n var f = strToU8(fn), s = f.length;\n var com = p.comment, m = com && strToU8(com), ms = m && m.length;\n var exl = exfl(p.extra);\n var compression = p.level == 0 ? 0 : 8;\n var cbl = function (e, d) {\n if (e) {\n tAll();\n cbd(e, null);\n }\n else {\n var l = d.length;\n files[i] = mrg(p, {\n size: size,\n crc: c.d(),\n c: d,\n f: f,\n m: m,\n u: s != fn.length || (m && (com.length != ms)),\n compression: compression\n });\n o += 30 + s + exl + l;\n tot += 76 + 2 * (s + exl) + (ms || 0) + l;\n if (!--lft)\n cbf();\n }\n };\n if (s > 65535)\n cbl(err(11, 0, 1), null);\n if (!compression)\n cbl(null, file);\n else if (size < 160000) {\n try {\n cbl(null, deflateSync(file, p));\n }\n catch (e) {\n cbl(e, null);\n }\n }\n else\n term.push(deflate(file, p, cbl));\n };\n // Cannot use lft because it can decrease\n for (var i = 0; i < slft; ++i) {\n _loop_1(i);\n }\n return tAll;\n}\n/**\n * Synchronously creates a ZIP file. Prefer using `zip` for better performance\n * with more than one file.\n * @param data The directory structure for the ZIP archive\n * @param opts The main options, merged with per-file options\n * @returns The generated ZIP archive\n */\nexport function zipSync(data, opts) {\n if (!opts)\n opts = {};\n var r = {};\n var files = [];\n fltn(data, '', r, opts);\n var o = 0;\n var tot = 0;\n for (var fn in r) {\n var _a = r[fn], file = _a[0], p = _a[1];\n var compression = p.level == 0 ? 0 : 8;\n var f = strToU8(fn), s = f.length;\n var com = p.comment, m = com && strToU8(com), ms = m && m.length;\n var exl = exfl(p.extra);\n if (s > 65535)\n err(11);\n var d = compression ? deflateSync(file, p) : file, l = d.length;\n var c = crc();\n c.p(file);\n files.push(mrg(p, {\n size: file.length,\n crc: c.d(),\n c: d,\n f: f,\n m: m,\n u: s != fn.length || (m && (com.length != ms)),\n o: o,\n compression: compression\n }));\n o += 30 + s + exl + l;\n tot += 76 + 2 * (s + exl) + (ms || 0) + l;\n }\n var out = new u8(tot + 22), oe = o, cdl = tot - o;\n for (var i = 0; i < files.length; ++i) {\n var f = files[i];\n wzh(out, f.o, f, f.f, f.u, f.c.length);\n var badd = 30 + f.f.length + exfl(f.extra);\n out.set(f.c, f.o + badd);\n wzh(out, o, f, f.f, f.u, f.c.length, f.o, f.m), o += 16 + badd + (f.m ? f.m.length : 0);\n }\n wzf(out, o, files.length, cdl, oe);\n return out;\n}\n/**\n * Streaming pass-through decompression for ZIP archives\n */\nvar UnzipPassThrough = /*#__PURE__*/ (function () {\n function UnzipPassThrough() {\n }\n UnzipPassThrough.prototype.push = function (data, final) {\n this.ondata(null, data, final);\n };\n UnzipPassThrough.compression = 0;\n return UnzipPassThrough;\n}());\nexport { UnzipPassThrough };\n/**\n * Streaming DEFLATE decompression for ZIP archives. Prefer AsyncZipInflate for\n * better performance.\n */\nvar UnzipInflate = /*#__PURE__*/ (function () {\n /**\n * Creates a DEFLATE decompression that can be used in ZIP archives\n */\n function UnzipInflate() {\n var _this = this;\n this.i = new Inflate(function (dat, final) {\n _this.ondata(null, dat, final);\n });\n }\n UnzipInflate.prototype.push = function (data, final) {\n try {\n this.i.push(data, final);\n }\n catch (e) {\n this.ondata(e, null, final);\n }\n };\n UnzipInflate.compression = 8;\n return UnzipInflate;\n}());\nexport { UnzipInflate };\n/**\n * Asynchronous streaming DEFLATE decompression for ZIP archives\n */\nvar AsyncUnzipInflate = /*#__PURE__*/ (function () {\n /**\n * Creates a DEFLATE decompression that can be used in ZIP archives\n */\n function AsyncUnzipInflate(_, sz) {\n var _this = this;\n if (sz < 320000) {\n this.i = new Inflate(function (dat, final) {\n _this.ondata(null, dat, final);\n });\n }\n else {\n this.i = new AsyncInflate(function (err, dat, final) {\n _this.ondata(err, dat, final);\n });\n this.terminate = this.i.terminate;\n }\n }\n AsyncUnzipInflate.prototype.push = function (data, final) {\n if (this.i.terminate)\n data = slc(data, 0);\n this.i.push(data, final);\n };\n AsyncUnzipInflate.compression = 8;\n return AsyncUnzipInflate;\n}());\nexport { AsyncUnzipInflate };\n/**\n * A ZIP archive decompression stream that emits files as they are discovered\n */\nvar Unzip = /*#__PURE__*/ (function () {\n /**\n * Creates a ZIP decompression stream\n * @param cb The callback to call whenever a file in the ZIP archive is found\n */\n function Unzip(cb) {\n this.onfile = cb;\n this.k = [];\n this.o = {\n 0: UnzipPassThrough\n };\n this.p = et;\n }\n /**\n * Pushes a chunk to be unzipped\n * @param chunk The chunk to push\n * @param final Whether this is the last chunk\n */\n Unzip.prototype.push = function (chunk, final) {\n var _this = this;\n if (!this.onfile)\n err(5);\n if (!this.p)\n err(4);\n if (this.c > 0) {\n var len = Math.min(this.c, chunk.length);\n var toAdd = chunk.subarray(0, len);\n this.c -= len;\n if (this.d)\n this.d.push(toAdd, !this.c);\n else\n this.k[0].push(toAdd);\n chunk = chunk.subarray(len);\n if (chunk.length)\n return this.push(chunk, final);\n }\n else {\n var f = 0, i = 0, is = void 0, buf = void 0;\n if (!this.p.length)\n buf = chunk;\n else if (!chunk.length)\n buf = this.p;\n else {\n buf = new u8(this.p.length + chunk.length);\n buf.set(this.p), buf.set(chunk, this.p.length);\n }\n var l = buf.length, oc = this.c, add = oc && this.d;\n var _loop_2 = function () {\n var _a;\n var sig = b4(buf, i);\n if (sig == 0x4034B50) {\n f = 1, is = i;\n this_1.d = null;\n this_1.c = 0;\n var bf = b2(buf, i + 6), cmp_1 = b2(buf, i + 8), u = bf & 2048, dd = bf & 8, fnl = b2(buf, i + 26), es = b2(buf, i + 28);\n if (l > i + 30 + fnl + es) {\n var chks_3 = [];\n this_1.k.unshift(chks_3);\n f = 2;\n var sc_1 = b4(buf, i + 18), su_1 = b4(buf, i + 22);\n var fn_1 = strFromU8(buf.subarray(i + 30, i += 30 + fnl), !u);\n if (sc_1 == 4294967295) {\n _a = dd ? [-2] : z64e(buf, i), sc_1 = _a[0], su_1 = _a[1];\n }\n else if (dd)\n sc_1 = -1;\n i += es;\n this_1.c = sc_1;\n var d_1;\n var file_1 = {\n name: fn_1,\n compression: cmp_1,\n start: function () {\n if (!file_1.ondata)\n err(5);\n if (!sc_1)\n file_1.ondata(null, et, true);\n else {\n var ctr = _this.o[cmp_1];\n if (!ctr)\n file_1.ondata(err(14, 'unknown compression type ' + cmp_1, 1), null, false);\n d_1 = sc_1 < 0 ? new ctr(fn_1) : new ctr(fn_1, sc_1, su_1);\n d_1.ondata = function (err, dat, final) { file_1.ondata(err, dat, final); };\n for (var _i = 0, chks_4 = chks_3; _i < chks_4.length; _i++) {\n var dat = chks_4[_i];\n d_1.push(dat, false);\n }\n if (_this.k[0] == chks_3 && _this.c)\n _this.d = d_1;\n else\n d_1.push(et, true);\n }\n },\n terminate: function () {\n if (d_1 && d_1.terminate)\n d_1.terminate();\n }\n };\n if (sc_1 >= 0)\n file_1.size = sc_1, file_1.originalSize = su_1;\n this_1.onfile(file_1);\n }\n return \"break\";\n }\n else if (oc) {\n if (sig == 0x8074B50) {\n is = i += 12 + (oc == -2 && 8), f = 3, this_1.c = 0;\n return \"break\";\n }\n else if (sig == 0x2014B50) {\n is = i -= 4, f = 3, this_1.c = 0;\n return \"break\";\n }\n }\n };\n var this_1 = this;\n for (; i < l - 4; ++i) {\n var state_1 = _loop_2();\n if (state_1 === \"break\")\n break;\n }\n this.p = et;\n if (oc < 0) {\n var dat = f ? buf.subarray(0, is - 12 - (oc == -2 && 8) - (b4(buf, is - 16) == 0x8074B50 && 4)) : buf.subarray(0, i);\n if (add)\n add.push(dat, !!f);\n else\n this.k[+(f == 2)].push(dat);\n }\n if (f & 2)\n return this.push(buf.subarray(i), final);\n this.p = buf.subarray(i);\n }\n if (final) {\n if (this.c)\n err(13);\n this.p = null;\n }\n };\n /**\n * Registers a decoder with the stream, allowing for files compressed with\n * the compression type provided to be expanded correctly\n * @param decoder The decoder constructor\n */\n Unzip.prototype.register = function (decoder) {\n this.o[decoder.compression] = decoder;\n };\n return Unzip;\n}());\nexport { Unzip };\nvar mt = typeof queueMicrotask == 'function' ? queueMicrotask : typeof setTimeout == 'function' ? setTimeout : function (fn) { fn(); };\nexport function unzip(data, opts, cb) {\n if (!cb)\n cb = opts, opts = {};\n if (typeof cb != 'function')\n err(7);\n var term = [];\n var tAll = function () {\n for (var i = 0; i < term.length; ++i)\n term[i]();\n };\n var files = {};\n var cbd = function (a, b) {\n mt(function () { cb(a, b); });\n };\n mt(function () { cbd = cb; });\n var e = data.length - 22;\n for (; b4(data, e) != 0x6054B50; --e) {\n if (!e || data.length - e > 65558) {\n cbd(err(13, 0, 1), null);\n return tAll;\n }\n }\n ;\n var lft = b2(data, e + 8);\n if (lft) {\n var c = lft;\n var o = b4(data, e + 16);\n var z = o == 4294967295 || c == 65535;\n if (z) {\n var ze = b4(data, e - 12);\n z = b4(data, ze) == 0x6064B50;\n if (z) {\n c = lft = b4(data, ze + 32);\n o = b4(data, ze + 48);\n }\n }\n var fltr = opts && opts.filter;\n var _loop_3 = function (i) {\n var _a = zh(data, o, z), c_1 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off);\n o = no;\n var cbl = function (e, d) {\n if (e) {\n tAll();\n cbd(e, null);\n }\n else {\n if (d)\n files[fn] = d;\n if (!--lft)\n cbd(null, files);\n }\n };\n if (!fltr || fltr({\n name: fn,\n size: sc,\n originalSize: su,\n compression: c_1\n })) {\n if (!c_1)\n cbl(null, slc(data, b, b + sc));\n else if (c_1 == 8) {\n var infl = data.subarray(b, b + sc);\n // Synchronously decompress under 512KB, or barely-compressed data\n if (su < 524288 || sc > 0.8 * su) {\n try {\n cbl(null, inflateSync(infl, { out: new u8(su) }));\n }\n catch (e) {\n cbl(e, null);\n }\n }\n else\n term.push(inflate(infl, { size: su }, cbl));\n }\n else\n cbl(err(14, 'unknown compression type ' + c_1, 1), null);\n }\n else\n cbl(null, null);\n };\n for (var i = 0; i < c; ++i) {\n _loop_3(i);\n }\n }\n else\n cbd(null, {});\n return tAll;\n}\n/**\n * Synchronously decompresses a ZIP archive. Prefer using `unzip` for better\n * performance with more than one file.\n * @param data The raw compressed ZIP file\n * @param opts The ZIP extraction options\n * @returns The decompressed files\n */\nexport function unzipSync(data, opts) {\n var files = {};\n var e = data.length - 22;\n for (; b4(data, e) != 0x6054B50; --e) {\n if (!e || data.length - e > 65558)\n err(13);\n }\n ;\n var c = b2(data, e + 8);\n if (!c)\n return {};\n var o = b4(data, e + 16);\n var z = o == 4294967295 || c == 65535;\n if (z) {\n var ze = b4(data, e - 12);\n z = b4(data, ze) == 0x6064B50;\n if (z) {\n c = b4(data, ze + 32);\n o = b4(data, ze + 48);\n }\n }\n var fltr = opts && opts.filter;\n for (var i = 0; i < c; ++i) {\n var _a = zh(data, o, z), c_2 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off);\n o = no;\n if (!fltr || fltr({\n name: fn,\n size: sc,\n originalSize: su,\n compression: c_2\n })) {\n if (!c_2)\n files[fn] = slc(data, b, b + sc);\n else if (c_2 == 8)\n files[fn] = inflateSync(data.subarray(b, b + sc), { out: new u8(su) });\n else\n err(14, 'unknown compression type ' + c_2);\n }\n }\n return files;\n}\n","/**\r\n * SOGLoader - 加载 SOG (Spatially Ordered Gaussians) 格式的 3DGS 文件\r\n *\r\n * SOG 是 PlayCanvas 开源的压缩容器格式,约 15-20x 压缩比 (vs PLY)\r\n * .sog 文件本质是 ZIP 包,内含 meta.json + 多个无损 WebP 图像\r\n *\r\n * 支持:\r\n * - 完整位置解码(16-bit 对称对数量化)\r\n * - Codebook 缩放解码\r\n * - Smallest-three 四元数解码 (26-bit)\r\n * - DC 颜色 + 透明度 (SH L0)\r\n * - 高阶球谐系数 L1-L3(palette + codebook)\r\n *\r\n * 规范 v2: https://developer.playcanvas.com/user-manual/gaussian-splatting/formats/sog/\r\n */\r\n\r\nimport { unzipSync } from 'fflate';\r\nimport type { CompactSplatData } from './PLYLoaderMobile';\r\n\r\n/* ------------------------------------------------------------------ */\r\n/* meta.json 类型 */\r\n/* ------------------------------------------------------------------ */\r\n\r\ninterface SOGMeta {\r\n version: number;\r\n asset?: { generator?: string };\r\n count: number;\r\n antialias: boolean;\r\n means: {\r\n mins: [number, number, number];\r\n maxs: [number, number, number];\r\n files: [string, string];\r\n };\r\n scales: {\r\n codebook: number[];\r\n files: [string];\r\n };\r\n quats: {\r\n files: [string];\r\n };\r\n sh0: {\r\n codebook: number[];\r\n files: [string];\r\n };\r\n shN?: {\r\n count: number;\r\n bands: number; // 1..3\r\n codebook: number[];\r\n files: [string, string]; // [centroids, labels]\r\n };\r\n}\r\n\r\n/* ------------------------------------------------------------------ */\r\n/* 内部工具 */\r\n/* ------------------------------------------------------------------ */\r\n\r\ninterface PixelData {\r\n width: number;\r\n height: number;\r\n data: Uint8ClampedArray; // RGBA row-major\r\n}\r\n\r\nconst SH_C0 = 0.28209479177387814;\r\nconst COEFFS_PER_BAND = [3, 8, 15] as const; // bands 1/2/3\r\n\r\nfunction lerp(a: number, b: number, t: number): number {\r\n return a + (b - a) * t;\r\n}\r\n\r\n/** 对称对数变换的逆变换 */\r\nfunction symUnlog(n: number): number {\r\n return Math.sign(n) * (Math.exp(Math.abs(n)) - 1);\r\n}\r\n\r\n/** 将 WebP 字节解码为原始像素 RGBA */\r\nasync function decodeWebP(bytes: Uint8Array): Promise<PixelData> {\r\n const blob = new Blob([bytes as unknown as ArrayBuffer], { type: 'image/webp' });\r\n const bitmap = await createImageBitmap(blob, {\r\n colorSpaceConversion: 'none',\r\n premultiplyAlpha: 'none',\r\n } as ImageBitmapOptions);\r\n\r\n const w = bitmap.width;\r\n const h = bitmap.height;\r\n const canvas = new OffscreenCanvas(w, h);\r\n const ctx = canvas.getContext('2d')!;\r\n ctx.drawImage(bitmap, 0, 0);\r\n bitmap.close();\r\n\r\n return { width: w, height: h, data: ctx.getImageData(0, 0, w, h).data };\r\n}\r\n\r\n/** 预解码 SH 高阶 palette(避免在主循环中重复查表) */\r\nfunction decodeSHPalette(\r\n centroidsImg: PixelData,\r\n codebook: number[],\r\n paletteSize: number,\r\n bands: number,\r\n): Float32Array[] {\r\n const numCoeffs = COEFFS_PER_BAND[bands - 1];\r\n const palette: Float32Array[] = new Array(paletteSize);\r\n\r\n for (let n = 0; n < paletteSize; n++) {\r\n const entry = new Float32Array(numCoeffs * 3);\r\n for (let c = 0; c < numCoeffs; c++) {\r\n const u = (n % 64) * numCoeffs + c;\r\n const v = Math.floor(n / 64);\r\n const off = (v * centroidsImg.width + u) * 4;\r\n entry[c * 3 + 0] = codebook[centroidsImg.data[off + 0]];\r\n entry[c * 3 + 1] = codebook[centroidsImg.data[off + 1]];\r\n entry[c * 3 + 2] = codebook[centroidsImg.data[off + 2]];\r\n }\r\n palette[n] = entry;\r\n }\r\n return palette;\r\n}\r\n\r\n/* ------------------------------------------------------------------ */\r\n/* 公共 API */\r\n/* ------------------------------------------------------------------ */\r\n\r\nexport type SOGProgressCallback =\r\n (progress: number, stage: 'download' | 'parse' | 'upload') => void;\r\n\r\n/**\r\n * 从 URL 加载 .sog 文件\r\n */\r\nexport async function loadSOG(\r\n url: string,\r\n onProgress?: SOGProgressCallback,\r\n): Promise<CompactSplatData> {\r\n const response = await fetch(url);\r\n if (!response.ok) throw new Error(`无法加载 SOG 文件: ${url}`);\r\n\r\n const buffer = await response.arrayBuffer();\r\n return deserializeSOG(buffer, onProgress);\r\n}\r\n\r\n/**\r\n * 从 ArrayBuffer 解析 SOG 数据\r\n */\r\nexport async function deserializeSOG(\r\n data: ArrayBuffer,\r\n onProgress?: SOGProgressCallback,\r\n): Promise<CompactSplatData> {\r\n /* ---------- 1. 解压 ZIP ---------- */\r\n if (onProgress) onProgress(0, 'parse');\r\n\r\n const zipEntries = unzipSync(new Uint8Array(data));\r\n\r\n const metaKey = Object.keys(zipEntries).find(k => k.endsWith('meta.json'));\r\n if (!metaKey) throw new Error('无效的 SOG 文件: 缺少 meta.json');\r\n\r\n const meta: SOGMeta = JSON.parse(new TextDecoder().decode(zipEntries[metaKey]));\r\n if (meta.version !== 2) {\r\n throw new Error(`不支持的 SOG 版本: ${meta.version},仅支持版本 2`);\r\n }\r\n\r\n // ZIP 内可能带目录前缀\r\n const prefix = metaKey.includes('/')\r\n ? metaKey.substring(0, metaKey.lastIndexOf('/') + 1)\r\n : '';\r\n\r\n const findFile = (name: string): Uint8Array => {\r\n const entry = zipEntries[prefix + name] ?? zipEntries[name];\r\n if (!entry) throw new Error(`SOG 缺少文件: ${name}`);\r\n return entry;\r\n };\r\n\r\n if (onProgress) onProgress(5, 'parse');\r\n\r\n /* ---------- 2. 并行解码 WebP ---------- */\r\n const decodeList: Promise<PixelData>[] = [\r\n decodeWebP(findFile(meta.means.files[0])), // 0: means_l\r\n decodeWebP(findFile(meta.means.files[1])), // 1: means_u\r\n decodeWebP(findFile(meta.scales.files[0])), // 2: scales\r\n decodeWebP(findFile(meta.quats.files[0])), // 3: quats\r\n decodeWebP(findFile(meta.sh0.files[0])), // 4: sh0\r\n ];\r\n\r\n const hasHigherSH = !!meta.shN;\r\n if (hasHigherSH) {\r\n decodeList.push(\r\n decodeWebP(findFile(meta.shN!.files[0])), // 5: shN_centroids\r\n decodeWebP(findFile(meta.shN!.files[1])), // 6: shN_labels\r\n );\r\n }\r\n\r\n const imgs = await Promise.all(decodeList);\r\n const [meansL, meansU, scalesImg, quatsImg, sh0Img] = imgs;\r\n const centroidsImg = hasHigherSH ? imgs[5] : null;\r\n const labelsImg = hasHigherSH ? imgs[6] : null;\r\n\r\n if (onProgress) onProgress(35, 'parse');\r\n\r\n /* ---------- 3. 预解码 SH palette ---------- */\r\n let shPalette: Float32Array[] | null = null;\r\n let shBandCoeffs = 0;\r\n if (meta.shN && centroidsImg) {\r\n shBandCoeffs = COEFFS_PER_BAND[meta.shN.bands - 1];\r\n shPalette = decodeSHPalette(\r\n centroidsImg, meta.shN.codebook, meta.shN.count, meta.shN.bands,\r\n );\r\n }\r\n\r\n if (onProgress) onProgress(45, 'parse');\r\n\r\n /* ---------- 4. 分配输出 ---------- */\r\n const count = meta.count;\r\n const positions = new Float32Array(count * 3);\r\n const scales = new Float32Array(count * 3);\r\n const rotations = new Float32Array(count * 4);\r\n const colors = new Float32Array(count * 3);\r\n const opacities = new Float32Array(count);\r\n const shCoeffs = shPalette ? new Float32Array(count * 45) : undefined;\r\n\r\n // codebook 存的是 log-scale,需要 exp() 转为线性空间\r\n // 参考 Spark: json.scales.codebook.map((x) => Math.exp(x))\r\n const scCBExp = meta.scales.codebook.map(x => Math.exp(x));\r\n const dcCB = meta.sh0.codebook;\r\n const SQRT2 = Math.SQRT2;\r\n\r\n // 四元数分量预计算查找表(避免主循环里重复计算)\r\n const quatLookup = new Float64Array(256);\r\n for (let i = 0; i < 256; i++) {\r\n quatLookup[i] = (i / 255 - 0.5) * SQRT2;\r\n }\r\n\r\n /* ---------- 5. 逐 Gaussian 解码 ---------- */\r\n for (let i = 0; i < count; i++) {\r\n const px = i % meansL.width;\r\n const py = Math.floor(i / meansL.width);\r\n const off = (py * meansL.width + px) * 4;\r\n\r\n // ── 位置 (16-bit, 对称对数量化) ──\r\n const qx = (meansU.data[off + 0] << 8) | meansL.data[off + 0];\r\n const qy = (meansU.data[off + 1] << 8) | meansL.data[off + 1];\r\n const qz = (meansU.data[off + 2] << 8) | meansL.data[off + 2];\r\n\r\n positions[i * 3 + 0] = symUnlog(lerp(meta.means.mins[0], meta.means.maxs[0], qx / 65535));\r\n positions[i * 3 + 1] = symUnlog(lerp(meta.means.mins[1], meta.means.maxs[1], qy / 65535));\r\n positions[i * 3 + 2] = symUnlog(lerp(meta.means.mins[2], meta.means.maxs[2], qz / 65535));\r\n\r\n // ── 缩放 (codebook 存 log-scale, exp 后为线性空间) ──\r\n scales[i * 3 + 0] = scCBExp[scalesImg.data[off + 0]];\r\n scales[i * 3 + 1] = scCBExp[scalesImg.data[off + 1]];\r\n scales[i * 3 + 2] = scCBExp[scalesImg.data[off + 2]];\r\n\r\n // ── 四元数 (smallest-three, 2+8+8+8 bit) ──\r\n // 参考 Spark (sparkjsdev/spark) pcsogs.ts 的验证实现\r\n const r0 = quatLookup[quatsImg.data[off + 0]];\r\n const r1 = quatLookup[quatsImg.data[off + 1]];\r\n const r2 = quatLookup[quatsImg.data[off + 2]];\r\n const rr = Math.sqrt(Math.max(0, 1 - r0 * r0 - r1 * r1 - r2 * r2));\r\n const rOrder = quatsImg.data[off + 3] - 252;\r\n\r\n // rOrder 决定哪个分量被省略并重建 (rr)\r\n // 输出 [x, y, z, w] 格式\r\n const qX = rOrder === 0 ? r0 : rOrder === 1 ? rr : r1;\r\n const qY = rOrder <= 1 ? r1 : rOrder === 2 ? rr : r2;\r\n const qZ = rOrder <= 2 ? r2 : rr;\r\n const qW = rOrder === 0 ? rr : r0;\r\n\r\n // 转为 [w, x, y, z] — 与 PLY/渲染器约定一致\r\n rotations[i * 4 + 0] = qW;\r\n rotations[i * 4 + 1] = qX;\r\n rotations[i * 4 + 2] = qY;\r\n rotations[i * 4 + 3] = qZ;\r\n\r\n // ── DC 颜色 + 不透明度 ──\r\n colors[i * 3 + 0] = 0.5 + dcCB[sh0Img.data[off + 0]] * SH_C0;\r\n colors[i * 3 + 1] = 0.5 + dcCB[sh0Img.data[off + 1]] * SH_C0;\r\n colors[i * 3 + 2] = 0.5 + dcCB[sh0Img.data[off + 2]] * SH_C0;\r\n opacities[i] = sh0Img.data[off + 3] / 255;\r\n\r\n // ── 高阶 SH (L1-L3, palette) ──\r\n if (shCoeffs && shPalette && labelsImg) {\r\n const lOff = (py * labelsImg.width + px) * 4;\r\n const label = labelsImg.data[lOff + 0] | (labelsImg.data[lOff + 1] << 8);\r\n const entry = shPalette[label];\r\n if (entry) {\r\n const base = i * 45;\r\n // entry 已经是 interleaved [R0,G0,B0, R1,G1,B1, ...]\r\n const len = shBandCoeffs * 3;\r\n for (let j = 0; j < len; j++) {\r\n shCoeffs[base + j] = entry[j];\r\n }\r\n }\r\n }\r\n\r\n // 进度回调(每 10 万个报告一次,避免过于频繁)\r\n if (onProgress && (i & 0x1FFFF) === 0) {\r\n onProgress(45 + (i / count) * 50, 'parse');\r\n }\r\n }\r\n\r\n if (onProgress) onProgress(95, 'parse');\r\n\r\n return { count, positions, scales, rotations, colors, opacities, shCoeffs };\r\n}\r\n","/**\r\n * GSSplatSorter - GPU Radix Sort 深度排序器\r\n *\r\n * 基于 rfs-gsplat-render 的 3-Pass Radix Sort 架构实现:\r\n * - 4 个 pass (8-bit 增量,总共 32 位)\r\n * - 每个 pass 包含: Upsweep -> Spine -> Downsweep\r\n * - 稳定排序,解决远距离闪烁问题\r\n *\r\n * 参考: rfs-gsplat-render/assets/shaders/radix_sort.wgsl\r\n */\r\n\r\nconst WORKGROUP_SIZE = 256;\r\nconst RADIX_BITS = 8;\r\nconst RADIX_SIZE = 256; // 2^8\r\nconst ELEMENTS_PER_THREAD = 4;\r\nconst BLOCK_SIZE = WORKGROUP_SIZE * ELEMENTS_PER_THREAD; // 1024\r\n\r\n/**\r\n * 生成 Culling Shader 代码\r\n * 基于 rfs-gsplat-render/assets/shaders/gaussian_splat_cull.wgsl\r\n */\r\nfunction generateCullingShaderCode(): string {\r\n return /* wgsl */ `\r\n/**\r\n * Project & Cull Shader\r\n * 基于 rfs-gsplat-render 实现\r\n */\r\n\r\nstruct Splat {\r\n mean: vec3<f32>,\r\n _pad0: f32,\r\n scale: vec3<f32>,\r\n _pad1: f32,\r\n rotation: vec4<f32>,\r\n colorDC: vec3<f32>,\r\n opacity: f32,\r\n sh1: array<f32, 9>,\r\n sh2: array<f32, 15>,\r\n sh3: array<f32, 21>,\r\n _pad2: array<f32, 3>,\r\n}\r\n\r\nstruct CameraUniforms {\r\n view: mat4x4<f32>,\r\n proj: mat4x4<f32>,\r\n model: mat4x4<f32>,\r\n cameraPos: vec3<f32>,\r\n _pad: f32,\r\n}\r\n\r\nstruct CullingParams {\r\n splatCount: u32,\r\n nearPlane: f32,\r\n farPlane: f32,\r\n screenWidth: f32,\r\n screenHeight: f32,\r\n frustumDilation: f32,\r\n pixelThreshold: f32,\r\n maxVisibleCount: u32,\r\n}\r\n\r\n@group(0) @binding(0) var<storage, read> splats: array<Splat>;\r\n@group(0) @binding(1) var<uniform> camera: CameraUniforms;\r\n@group(0) @binding(2) var<uniform> params: CullingParams;\r\n@group(0) @binding(3) var<storage, read_write> depthKeys: array<u32>;\r\n@group(0) @binding(4) var<storage, read_write> visibleIndices: array<u32>;\r\n@group(0) @binding(5) var<storage, read_write> indirectBuffer: array<atomic<u32>, 4>;\r\n\r\nfn maxScale(scale: vec3<f32>) -> f32 {\r\n return max(max(scale.x, scale.y), scale.z);\r\n}\r\n\r\nfn getModelMaxScale(model: mat4x4<f32>) -> f32 {\r\n let sx = length(model[0].xyz);\r\n let sy = length(model[1].xyz);\r\n let sz = length(model[2].xyz);\r\n return max(max(sx, sy), sz);\r\n}\r\n\r\n// IEEE 754 位操作编码浮点数为可排序的 u32\r\n// 参考 rfs-gsplat-render 的 encode_min_max_fp32 实现\r\nfn encodeDepthKey(val: f32) -> u32 {\r\n var bits = bitcast<u32>(val);\r\n bits ^= bitcast<u32>(bitcast<i32>(bits) >> 31) | 0x80000000u;\r\n return bits;\r\n}\r\n\r\n// 视锥剔除检查\r\n// 基于 rfs-gsplat-render 的 is_in_frustum 实现\r\nfn isInFrustum(clipPos: vec4<f32>, frustumDilation: f32) -> bool {\r\n let clip = (1.0 + frustumDilation) * clipPos.w;\r\n \r\n if abs(clipPos.x) > clip { return false; }\r\n if abs(clipPos.y) > clip { return false; }\r\n \r\n let nearThreshold = (0.0 - frustumDilation) * clipPos.w;\r\n if clipPos.z < nearThreshold || clipPos.z > clipPos.w {\r\n return false;\r\n }\r\n \r\n return true;\r\n}\r\n\r\n@compute @workgroup_size(${WORKGROUP_SIZE})\r\nfn projectAndCull(@builtin(global_invocation_id) gid: vec3<u32>) {\r\n let i = gid.x;\r\n if i >= params.splatCount { return; }\r\n \r\n let splat = splats[i];\r\n \r\n // 透明度剔除\r\n if splat.opacity < 0.004 { return; }\r\n \r\n // 变换: Local -> World -> View -> Clip\r\n let worldPos = camera.model * vec4<f32>(splat.mean, 1.0);\r\n let viewPos = camera.view * worldPos;\r\n let clipPos = camera.proj * viewPos;\r\n \r\n // 视锥剔除\r\n if !isInFrustum(clipPos, params.frustumDilation) { return; }\r\n \r\n // 亚像素剔除:Gaussian 可见范围小于阈值的 splat 跳过渲染和排序\r\n // scale 是 σ(标准差),Gaussian 可见范围约 3σ(覆盖 99.7%)\r\n if params.pixelThreshold > 0.0 {\r\n let splatSigma = maxScale(splat.scale) * getModelMaxScale(camera.model);\r\n let focalY = abs(camera.proj[1][1]) * params.screenHeight * 0.5;\r\n let projectedExtent = splatSigma * 3.0 * focalY / max(abs(viewPos.z), 0.001);\r\n if projectedExtent < params.pixelThreshold { return; }\r\n }\r\n \r\n // 深度编码 (viewPos.z 是负数)\r\n let depth = viewPos.z;\r\n let sortableDepth = encodeDepthKey(depth);\r\n \r\n // 原子增加可见计数并获取索引\r\n // indirectBuffer[1] 是 instance_count\r\n let visibleIdx = atomicAdd(&indirectBuffer[1], 1u);\r\n \r\n // 写入可见点列表\r\n depthKeys[visibleIdx] = sortableDepth;\r\n visibleIndices[visibleIdx] = i;\r\n}\r\n\r\n@compute @workgroup_size(1)\r\nfn initIndirectBuffer() {\r\n // [vertex_count, instance_count, first_vertex, first_instance]\r\n atomicStore(&indirectBuffer[0], 4u);\r\n atomicStore(&indirectBuffer[1], 0u); // instance_count 由 cull shader 填充\r\n atomicStore(&indirectBuffer[2], 0u);\r\n atomicStore(&indirectBuffer[3], 0u);\r\n}\r\n\r\n// 排序后截断:只保留最近的 maxVisibleCount 个 splat\r\n// 因为 radix sort 是按深度从近到远排序,截断尾部等于丢弃被遮挡的远处 splat\r\n@compute @workgroup_size(1)\r\nfn clampDrawCount() {\r\n let maxCount = params.maxVisibleCount;\r\n if maxCount == 0u { return; }\r\n let count = atomicLoad(&indirectBuffer[1]);\r\n if count > maxCount {\r\n atomicStore(&indirectBuffer[1], maxCount);\r\n }\r\n}\r\n`;\r\n}\r\n\r\n/**\r\n * 生成 Radix Sort Shader 代码\r\n * 完整移植自 rfs-gsplat-render/assets/shaders/radix_sort.wgsl\r\n */\r\nfunction generateRadixSortShaderCode(): string {\r\n return /* wgsl */ `\r\n/**\r\n * GPU Radix Sort - 3-Pass Architecture\r\n * 基于 rfs-gsplat-render 实现\r\n * \r\n * Pass 1: Upsweep - 构建局部直方图并累加到全局\r\n * Pass 2: Spine - 对分区和全局直方图进行前缀和\r\n * Pass 3: Downsweep - 使用计算的偏移量散射元素 (稳定排序)\r\n */\r\n\r\nconst WG: u32 = ${WORKGROUP_SIZE}u;\r\nconst RADIX_BITS: u32 = ${RADIX_BITS}u;\r\nconst RADIX_SIZE: u32 = ${RADIX_SIZE}u;\r\nconst RADIX_MASK: u32 = ${RADIX_SIZE - 1}u;\r\nconst ELEMENTS_PER_THREAD: u32 = ${ELEMENTS_PER_THREAD}u;\r\nconst BLOCK_SIZE: u32 = ${BLOCK_SIZE}u;\r\n\r\nfn divCeil(a: u32, b: u32) -> u32 {\r\n return (a + b - 1u) / b;\r\n}\r\n\r\nstruct SortParams {\r\n maxElementCount: u32,\r\n bitShift: u32,\r\n passIndex: u32,\r\n _padding: u32,\r\n}\r\n\r\n// ============================================================================\r\n// Pass 1: Upsweep - 计数局部直方图并累加到全局\r\n// ============================================================================\r\n\r\n@group(0) @binding(0) var<uniform> upsweepParams: SortParams;\r\n@group(0) @binding(1) var<storage, read> indirectBufferUpsweep: array<u32>;\r\n@group(0) @binding(2) var<storage, read> keysIn: array<u32>;\r\n@group(0) @binding(3) var<storage, read_write> globalHistogram: array<atomic<u32>>;\r\n@group(0) @binding(4) var<storage, read_write> partitionHistogram: array<u32>;\r\n\r\nvar<workgroup> localHistogram: array<atomic<u32>, RADIX_SIZE>;\r\n\r\n@compute @workgroup_size(256, 1, 1)\r\nfn upsweep(\r\n @builtin(local_invocation_id) localId: vec3<u32>,\r\n @builtin(workgroup_id) workgroupId: vec3<u32>,\r\n) {\r\n // 从 indirectBuffer[1] 读取动态可见数量 (instance_count)\r\n let numKeys = indirectBufferUpsweep[1];\r\n let numPartitions = divCeil(numKeys, BLOCK_SIZE);\r\n let partitionId = workgroupId.x;\r\n \r\n if partitionId >= numPartitions { return; }\r\n \r\n let tid = localId.x;\r\n let partitionStart = partitionId * BLOCK_SIZE;\r\n let shift = upsweepParams.bitShift;\r\n let passIdx = upsweepParams.passIndex;\r\n \r\n // 初始化局部直方图\r\n if tid < RADIX_SIZE {\r\n atomicStore(&localHistogram[tid], 0u);\r\n }\r\n workgroupBarrier();\r\n \r\n // 构建局部直方图\r\n for (var j = 0u; j < ELEMENTS_PER_THREAD; j++) {\r\n let keyIdx = partitionStart + tid * ELEMENTS_PER_THREAD + j;\r\n if keyIdx < numKeys {\r\n let key = keysIn[keyIdx];\r\n let bin = (key >> shift) & RADIX_MASK;\r\n atomicAdd(&localHistogram[bin], 1u);\r\n }\r\n }\r\n \r\n workgroupBarrier();\r\n \r\n // 写入分区直方图并累加到全局直方图\r\n if tid < RADIX_SIZE {\r\n let count = atomicLoad(&localHistogram[tid]);\r\n partitionHistogram[RADIX_SIZE * partitionId + tid] = count;\r\n atomicAdd(&globalHistogram[RADIX_SIZE * passIdx + tid], count);\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Pass 2: Spine - 对分区和全局直方图进行前缀和\r\n// ============================================================================\r\n\r\n@group(0) @binding(0) var<storage, read> indirectBufferSpine: array<u32>;\r\n@group(0) @binding(1) var<storage, read_write> globalHistogramSpine: array<u32>;\r\n@group(0) @binding(2) var<storage, read_write> partitionHistogramSpine: array<u32>;\r\n@group(0) @binding(3) var<uniform> spineParams: SortParams;\r\n\r\n// 双缓冲用于无数据竞争的 Hillis-Steele scan\r\nvar<workgroup> scanA: array<u32, 256>;\r\nvar<workgroup> scanB: array<u32, 256>;\r\nvar<workgroup> reductionShared: u32;\r\n\r\n@compute @workgroup_size(256, 1, 1)\r\nfn spine(\r\n @builtin(local_invocation_id) localId: vec3<u32>,\r\n @builtin(workgroup_id) workgroupId: vec3<u32>,\r\n) {\r\n let numKeys = indirectBufferSpine[1];\r\n let numPartitions = divCeil(numKeys, BLOCK_SIZE);\r\n let bin = workgroupId.x;\r\n let tid = localId.x;\r\n \r\n if bin >= RADIX_SIZE { return; }\r\n \r\n // 初始化共享 reduction\r\n if tid == 0u {\r\n reductionShared = 0u;\r\n }\r\n workgroupBarrier();\r\n \r\n // 处理此 bin 的所有分区(分批处理)\r\n let MAX_BATCH_SIZE = 256u;\r\n for (var batchStart = 0u; batchStart < numPartitions; batchStart += MAX_BATCH_SIZE) {\r\n let partitionIdx = batchStart + tid;\r\n let batchSize = min(MAX_BATCH_SIZE, numPartitions - batchStart);\r\n \r\n // 加载此批次的值\r\n if tid < batchSize && partitionIdx < numPartitions {\r\n scanA[tid] = partitionHistogramSpine[RADIX_SIZE * partitionIdx + bin];\r\n } else {\r\n scanA[tid] = 0u;\r\n }\r\n workgroupBarrier();\r\n \r\n // Hillis-Steele inclusive prefix sum (双缓冲避免数据竞争)\r\n var useA = true;\r\n var offset = 1u;\r\n for (var d = 0u; d < 8u; d++) {\r\n if useA {\r\n if tid >= offset {\r\n scanB[tid] = scanA[tid] + scanA[tid - offset];\r\n } else {\r\n scanB[tid] = scanA[tid];\r\n }\r\n } else {\r\n if tid >= offset {\r\n scanA[tid] = scanB[tid] + scanB[tid - offset];\r\n } else {\r\n scanA[tid] = scanB[tid];\r\n }\r\n }\r\n workgroupBarrier();\r\n useA = !useA;\r\n offset <<= 1u;\r\n }\r\n \r\n // 8 次迭代后结果在 scanA 中\r\n \r\n // 写回为 exclusive prefix sum(加上 reduction)\r\n if tid < batchSize && partitionIdx < numPartitions {\r\n var exclusive = reductionShared;\r\n if tid > 0u {\r\n exclusive += scanA[tid - 1u];\r\n }\r\n partitionHistogramSpine[RADIX_SIZE * partitionIdx + bin] = exclusive;\r\n }\r\n \r\n // 更新下一批的 reduction\r\n workgroupBarrier();\r\n if tid == 0u && batchSize > 0u {\r\n reductionShared += scanA[batchSize - 1u];\r\n }\r\n workgroupBarrier();\r\n }\r\n \r\n // Bin 0 的工作组同时处理全局直方图前缀和\r\n if bin == 0u {\r\n let passIdx = spineParams.passIndex;\r\n scanA[tid] = globalHistogramSpine[RADIX_SIZE * passIdx + tid];\r\n workgroupBarrier();\r\n \r\n // Hillis-Steele inclusive scan (双缓冲)\r\n var useA = true;\r\n var offset = 1u;\r\n for (var d = 0u; d < 8u; d++) {\r\n if useA {\r\n if tid >= offset {\r\n scanB[tid] = scanA[tid] + scanA[tid - offset];\r\n } else {\r\n scanB[tid] = scanA[tid];\r\n }\r\n } else {\r\n if tid >= offset {\r\n scanA[tid] = scanB[tid] + scanB[tid - offset];\r\n } else {\r\n scanA[tid] = scanB[tid];\r\n }\r\n }\r\n workgroupBarrier();\r\n useA = !useA;\r\n offset <<= 1u;\r\n }\r\n \r\n // 转换为 exclusive (结果在 scanA 中)\r\n var exclusive = 0u;\r\n if tid > 0u {\r\n exclusive = scanA[tid - 1u];\r\n }\r\n globalHistogramSpine[RADIX_SIZE * passIdx + tid] = exclusive;\r\n }\r\n}\r\n\r\n// ============================================================================\r\n// Pass 3: Downsweep - 并行稳定散射\r\n// 所有 256 个线程同时工作,通过局部排名计算保持稳定性\r\n// 相比原始单线程版本,workgroup 完成时间提升约 20-40 倍\r\n// ============================================================================\r\n\r\n@group(0) @binding(0) var<uniform> downsweepParams: SortParams;\r\n@group(0) @binding(1) var<storage, read> indirectBufferDownsweep: array<u32>;\r\n@group(0) @binding(2) var<storage, read> globalHistogramDownsweep: array<u32>;\r\n@group(0) @binding(3) var<storage, read> partitionHistogramDownsweep: array<u32>;\r\n@group(0) @binding(4) var<storage, read> downsweepKeysIn: array<u32>;\r\n@group(0) @binding(5) var<storage, read> downsweepValuesIn: array<u32>;\r\n@group(0) @binding(6) var<storage, read_write> downsweepKeysOut: array<u32>;\r\n@group(0) @binding(7) var<storage, read_write> downsweepValuesOut: array<u32>;\r\n\r\nvar<workgroup> localKeys: array<u32, BLOCK_SIZE>;\r\nvar<workgroup> localValues: array<u32, BLOCK_SIZE>;\r\nvar<workgroup> localBins: array<u32, BLOCK_SIZE>;\r\nvar<workgroup> binBasePos: array<u32, RADIX_SIZE>;\r\n\r\n@compute @workgroup_size(256, 1, 1)\r\nfn downsweep(\r\n @builtin(local_invocation_id) localId: vec3<u32>,\r\n @builtin(workgroup_id) workgroupId: vec3<u32>,\r\n) {\r\n let numKeys = indirectBufferDownsweep[1];\r\n let numPartitions = divCeil(numKeys, BLOCK_SIZE);\r\n let partitionId = workgroupId.x;\r\n \r\n if partitionId >= numPartitions { return; }\r\n \r\n let tid = localId.x;\r\n let partitionStart = partitionId * BLOCK_SIZE;\r\n let shift = downsweepParams.bitShift;\r\n let partitionEnd = min(partitionStart + BLOCK_SIZE, numKeys);\r\n let elemsInPartition = partitionEnd - partitionStart;\r\n \r\n // Phase 1: 所有线程并行加载元素到共享内存\r\n for (var j = 0u; j < ELEMENTS_PER_THREAD; j++) {\r\n let keyIdx = partitionStart + tid * ELEMENTS_PER_THREAD + j;\r\n let localIdx = tid * ELEMENTS_PER_THREAD + j;\r\n \r\n if keyIdx < numKeys {\r\n let key = downsweepKeysIn[keyIdx];\r\n localKeys[localIdx] = key;\r\n localValues[localIdx] = downsweepValuesIn[keyIdx];\r\n localBins[localIdx] = (key >> shift) & RADIX_MASK;\r\n } else {\r\n localBins[localIdx] = 0xFFFFFFFFu;\r\n }\r\n }\r\n \r\n // Phase 2: 初始化 bin 基础写入位置(利用 256 线程并行)\r\n if tid < RADIX_SIZE {\r\n let passIdx = downsweepParams.passIndex;\r\n binBasePos[tid] = globalHistogramDownsweep[RADIX_SIZE * passIdx + tid] + \r\n partitionHistogramDownsweep[RADIX_SIZE * partitionId + tid];\r\n }\r\n \r\n workgroupBarrier();\r\n \r\n // Phase 3: 并行计算排名并散射\r\n // 稳定性保证:rank = 当前元素之前具有相同 bin 的元素数量\r\n // 每个线程处理自己的 4 个元素,通过扫描 localBins 确定排名\r\n for (var j = 0u; j < ELEMENTS_PER_THREAD; j++) {\r\n let localIdx = tid * ELEMENTS_PER_THREAD + j;\r\n if localIdx >= elemsInPartition { break; }\r\n \r\n let b = localBins[localIdx];\r\n if b == 0xFFFFFFFFu { continue; }\r\n \r\n // 计算 rank:扫描本分区中在当前元素之前、且属于同一 bin 的元素数\r\n var rank = 0u;\r\n for (var p = 0u; p < localIdx; p++) {\r\n if localBins[p] == b { rank++; }\r\n }\r\n \r\n let writePos = binBasePos[b] + rank;\r\n if writePos < numKeys {\r\n downsweepKeysOut[writePos] = localKeys[localIdx];\r\n downsweepValuesOut[writePos] = localValues[localIdx];\r\n }\r\n }\r\n}\r\n`;\r\n}\r\n\r\n/**\r\n * 屏幕尺寸信息\r\n */\r\nexport interface ScreenInfo {\r\n width: number;\r\n height: number;\r\n}\r\n\r\n/**\r\n * 剔除参数\r\n */\r\nexport interface CullingOptions {\r\n nearPlane: number;\r\n farPlane: number;\r\n pixelThreshold: number;\r\n frustumDilation?: number;\r\n /** 最大可见 splat 数量(排序后截断),0 = 不限制 */\r\n maxVisibleCount?: number;\r\n}\r\n\r\n/**\r\n * 排序器配置选项\r\n */\r\nexport interface SorterOptions {\r\n /** 暂时保留,Radix Sort 不使用桶配置 */\r\n numBuckets?: number;\r\n}\r\n\r\n/**\r\n * GSSplatSorter - GPU Radix Sort 排序器\r\n * 基于 rfs-gsplat-render 的 3-Pass Radix Sort 实现\r\n */\r\nexport class GSSplatSorter {\r\n private device: GPUDevice;\r\n private splatCount: number;\r\n\r\n // Culling Buffers\r\n private cullingParamsBuffer: GPUBuffer;\r\n private depthKeysBuffer: GPUBuffer;\r\n private visibleIndicesBuffer: GPUBuffer;\r\n private indirectBuffer: GPUBuffer;\r\n\r\n // Radix Sort Buffers\r\n private globalHistogramBuffer: GPUBuffer;\r\n private partitionHistogramBuffer: GPUBuffer;\r\n private keysTempBuffer: GPUBuffer;\r\n private valuesTempBuffer: GPUBuffer;\r\n // 每个 pass 独立的参数 buffer (避免竞争)\r\n private sortParamsBuffers: GPUBuffer[] = [];\r\n\r\n // Sorted output\r\n private sortedIndicesBuffer: GPUBuffer;\r\n\r\n // Culling Pipelines\r\n private initIndirectPipeline: GPUComputePipeline;\r\n private projectCullPipeline: GPUComputePipeline;\r\n private clampDrawCountPipeline: GPUComputePipeline;\r\n private cullingBindGroupLayout: GPUBindGroupLayout;\r\n private cullingBindGroup: GPUBindGroup;\r\n\r\n // Radix Sort Pipelines\r\n private upsweepPipeline: GPUComputePipeline;\r\n private spinePipeline: GPUComputePipeline;\r\n private downsweepPipeline: GPUComputePipeline;\r\n private upsweepBindGroupLayout: GPUBindGroupLayout;\r\n private spineBindGroupLayout: GPUBindGroupLayout;\r\n private downsweepBindGroupLayout: GPUBindGroupLayout;\r\n\r\n // Bind groups for each pass (4 passes)\r\n private upsweepBindGroups: GPUBindGroup[] = [];\r\n private spineBindGroups: GPUBindGroup[] = [];\r\n private downsweepBindGroups: GPUBindGroup[] = [];\r\n\r\n private numPartitions: number;\r\n\r\n // 屏幕信息和剔除选项\r\n private screenWidth: number = 1920;\r\n private screenHeight: number = 1080;\r\n private cullingOptions: CullingOptions = {\r\n nearPlane: 0.1,\r\n farPlane: 1000,\r\n pixelThreshold: 0,\r\n frustumDilation: 0.2,\r\n };\r\n\r\n constructor(\r\n device: GPUDevice,\r\n splatCount: number,\r\n splatBuffer: GPUBuffer,\r\n cameraBuffer: GPUBuffer,\r\n _options: SorterOptions = {},\r\n ) {\r\n this.device = device;\r\n this.splatCount = splatCount;\r\n this.numPartitions = Math.ceil(splatCount / BLOCK_SIZE);\r\n\r\n // ============================================\r\n // 创建 Shader 模块\r\n // ============================================\r\n const cullingModule = device.createShaderModule({\r\n code: generateCullingShaderCode(),\r\n label: \"culling-shader\",\r\n });\r\n\r\n const radixSortModule = device.createShaderModule({\r\n code: generateRadixSortShaderCode(),\r\n label: \"radix-sort-shader\",\r\n });\r\n\r\n // ============================================\r\n // 创建 Buffers\r\n // ============================================\r\n\r\n // Culling params: splatCount, nearPlane, farPlane, screenWidth, screenHeight, frustumDilation, pixelThreshold, _pad\r\n this.cullingParamsBuffer = device.createBuffer({\r\n size: 32,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n label: \"culling-params\",\r\n });\r\n\r\n this.depthKeysBuffer = device.createBuffer({\r\n size: splatCount * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n label: \"depth-keys\",\r\n });\r\n\r\n this.visibleIndicesBuffer = device.createBuffer({\r\n size: splatCount * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n label: \"visible-indices\",\r\n });\r\n\r\n // Indirect buffer: [vertex_count, instance_count, first_vertex, first_instance]\r\n this.indirectBuffer = device.createBuffer({\r\n size: 16,\r\n usage:\r\n GPUBufferUsage.STORAGE |\r\n GPUBufferUsage.INDIRECT |\r\n GPUBufferUsage.COPY_DST,\r\n label: \"indirect-buffer\",\r\n });\r\n\r\n // Global histogram: 4 passes * RADIX_SIZE bins\r\n this.globalHistogramBuffer = device.createBuffer({\r\n size: RADIX_SIZE * 4 * 4, // 4 passes * 256 bins * 4 bytes\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n label: \"global-histogram\",\r\n });\r\n\r\n // Partition histogram: numPartitions * RADIX_SIZE\r\n this.partitionHistogramBuffer = device.createBuffer({\r\n size: this.numPartitions * RADIX_SIZE * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n label: \"partition-histogram\",\r\n });\r\n\r\n // Temp buffers for ping-pong\r\n this.keysTempBuffer = device.createBuffer({\r\n size: splatCount * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n label: \"keys-temp\",\r\n });\r\n\r\n this.valuesTempBuffer = device.createBuffer({\r\n size: splatCount * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n label: \"values-temp\",\r\n });\r\n\r\n // 为每个 pass 创建独立的参数 buffer (4 个 pass)\r\n for (let i = 0; i < 4; i++) {\r\n const paramsBuffer = device.createBuffer({\r\n size: 16,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n label: `sort-params-${i}`,\r\n });\r\n this.sortParamsBuffers.push(paramsBuffer);\r\n \r\n // 预填充参数\r\n const sortParams = new ArrayBuffer(16);\r\n const sortView = new DataView(sortParams);\r\n sortView.setUint32(0, splatCount, true); // maxElementCount\r\n sortView.setUint32(4, i * RADIX_BITS, true); // bitShift\r\n sortView.setUint32(8, i, true); // passIndex\r\n sortView.setUint32(12, 0, true); // padding\r\n device.queue.writeBuffer(paramsBuffer, 0, sortParams);\r\n }\r\n\r\n // Final sorted indices\r\n this.sortedIndicesBuffer = device.createBuffer({\r\n size: splatCount * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\r\n label: \"sorted-indices\",\r\n });\r\n\r\n // ============================================\r\n // 创建 Culling Pipelines\r\n // ============================================\r\n this.cullingBindGroupLayout = device.createBindGroupLayout({\r\n label: \"culling-bind-group-layout\",\r\n entries: [\r\n { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"uniform\" } },\r\n { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"uniform\" } },\r\n { binding: 3, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 4, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 5, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n ],\r\n });\r\n\r\n const cullingPipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [this.cullingBindGroupLayout],\r\n });\r\n\r\n this.initIndirectPipeline = device.createComputePipeline({\r\n layout: cullingPipelineLayout,\r\n compute: { module: cullingModule, entryPoint: \"initIndirectBuffer\" },\r\n label: \"init-indirect-pipeline\",\r\n });\r\n\r\n this.projectCullPipeline = device.createComputePipeline({\r\n layout: cullingPipelineLayout,\r\n compute: { module: cullingModule, entryPoint: \"projectAndCull\" },\r\n label: \"project-cull-pipeline\",\r\n });\r\n\r\n this.clampDrawCountPipeline = device.createComputePipeline({\r\n layout: cullingPipelineLayout,\r\n compute: { module: cullingModule, entryPoint: \"clampDrawCount\" },\r\n label: \"clamp-draw-count-pipeline\",\r\n });\r\n\r\n this.cullingBindGroup = device.createBindGroup({\r\n layout: this.cullingBindGroupLayout,\r\n entries: [\r\n { binding: 0, resource: { buffer: splatBuffer } },\r\n { binding: 1, resource: { buffer: cameraBuffer } },\r\n { binding: 2, resource: { buffer: this.cullingParamsBuffer } },\r\n { binding: 3, resource: { buffer: this.depthKeysBuffer } },\r\n { binding: 4, resource: { buffer: this.visibleIndicesBuffer } },\r\n { binding: 5, resource: { buffer: this.indirectBuffer } },\r\n ],\r\n label: \"culling-bind-group\",\r\n });\r\n\r\n // ============================================\r\n // 创建 Radix Sort Pipelines\r\n // ============================================\r\n\r\n // Upsweep layout: params, indirect, keys_in, global_histogram, partition_histogram\r\n this.upsweepBindGroupLayout = device.createBindGroupLayout({\r\n label: \"upsweep-layout\",\r\n entries: [\r\n { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"uniform\" } },\r\n { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 3, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 4, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n ],\r\n });\r\n\r\n // Spine layout: indirect, global_histogram, partition_histogram, params\r\n this.spineBindGroupLayout = device.createBindGroupLayout({\r\n label: \"spine-layout\",\r\n entries: [\r\n { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 3, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"uniform\" } },\r\n ],\r\n });\r\n\r\n // Downsweep layout: params, indirect, global_histogram, partition_histogram, keys_in, values_in, keys_out, values_out\r\n this.downsweepBindGroupLayout = device.createBindGroupLayout({\r\n label: \"downsweep-layout\",\r\n entries: [\r\n { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"uniform\" } },\r\n { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 3, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 4, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 5, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 6, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 7, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n ],\r\n });\r\n\r\n this.upsweepPipeline = device.createComputePipeline({\r\n layout: device.createPipelineLayout({ bindGroupLayouts: [this.upsweepBindGroupLayout] }),\r\n compute: { module: radixSortModule, entryPoint: \"upsweep\" },\r\n label: \"upsweep-pipeline\",\r\n });\r\n\r\n this.spinePipeline = device.createComputePipeline({\r\n layout: device.createPipelineLayout({ bindGroupLayouts: [this.spineBindGroupLayout] }),\r\n compute: { module: radixSortModule, entryPoint: \"spine\" },\r\n label: \"spine-pipeline\",\r\n });\r\n\r\n this.downsweepPipeline = device.createComputePipeline({\r\n layout: device.createPipelineLayout({ bindGroupLayouts: [this.downsweepBindGroupLayout] }),\r\n compute: { module: radixSortModule, entryPoint: \"downsweep\" },\r\n label: \"downsweep-pipeline\",\r\n });\r\n\r\n // ============================================\r\n // 为 4 个 pass 创建 bind groups (ping-pong buffers)\r\n // ============================================\r\n this.createRadixSortBindGroups();\r\n }\r\n\r\n /**\r\n * 创建 Radix Sort 的 bind groups\r\n * 4 个 pass,使用 ping-pong buffers\r\n * \r\n * Ping-pong 模式:\r\n * - Pass 0: depthKeys/visibleIndices -> keysTempBuffer/valuesTempBuffer\r\n * - Pass 1: keysTempBuffer/valuesTempBuffer -> depthKeys/visibleIndices\r\n * - Pass 2: depthKeys/visibleIndices -> keysTempBuffer/valuesTempBuffer\r\n * - Pass 3: keysTempBuffer/valuesTempBuffer -> (depthKeys)/sortedIndicesBuffer\r\n */\r\n private createRadixSortBindGroups(): void {\r\n for (let passIdx = 0; passIdx < 4; passIdx++) {\r\n const isEvenPass = passIdx % 2 === 0;\r\n\r\n // Ping-pong: 偶数 pass 从原始 buffer 读取,奇数 pass 从临时 buffer 读取\r\n const keysIn = isEvenPass ? this.depthKeysBuffer : this.keysTempBuffer;\r\n const valuesIn = isEvenPass ? this.visibleIndicesBuffer : this.valuesTempBuffer;\r\n \r\n // 输出: 偶数 pass 写入临时 buffer,奇数 pass 写回原始 buffer\r\n // 最后一个 pass (pass 3) 的 values 输出到 sortedIndicesBuffer\r\n let keysOut: GPUBuffer;\r\n let valuesOut: GPUBuffer;\r\n \r\n if (isEvenPass) {\r\n keysOut = this.keysTempBuffer;\r\n valuesOut = this.valuesTempBuffer;\r\n } else {\r\n keysOut = this.depthKeysBuffer;\r\n // Pass 3 输出最终排序结果\r\n valuesOut = passIdx === 3 ? this.sortedIndicesBuffer : this.visibleIndicesBuffer;\r\n }\r\n\r\n this.upsweepBindGroups[passIdx] = this.device.createBindGroup({\r\n layout: this.upsweepBindGroupLayout,\r\n entries: [\r\n { binding: 0, resource: { buffer: this.sortParamsBuffers[passIdx] } },\r\n { binding: 1, resource: { buffer: this.indirectBuffer } },\r\n { binding: 2, resource: { buffer: keysIn } },\r\n { binding: 3, resource: { buffer: this.globalHistogramBuffer } },\r\n { binding: 4, resource: { buffer: this.partitionHistogramBuffer } },\r\n ],\r\n label: `upsweep-bind-group-${passIdx}`,\r\n });\r\n\r\n this.spineBindGroups[passIdx] = this.device.createBindGroup({\r\n layout: this.spineBindGroupLayout,\r\n entries: [\r\n { binding: 0, resource: { buffer: this.indirectBuffer } },\r\n { binding: 1, resource: { buffer: this.globalHistogramBuffer } },\r\n { binding: 2, resource: { buffer: this.partitionHistogramBuffer } },\r\n { binding: 3, resource: { buffer: this.sortParamsBuffers[passIdx] } },\r\n ],\r\n label: `spine-bind-group-${passIdx}`,\r\n });\r\n\r\n this.downsweepBindGroups[passIdx] = this.device.createBindGroup({\r\n layout: this.downsweepBindGroupLayout,\r\n entries: [\r\n { binding: 0, resource: { buffer: this.sortParamsBuffers[passIdx] } },\r\n { binding: 1, resource: { buffer: this.indirectBuffer } },\r\n { binding: 2, resource: { buffer: this.globalHistogramBuffer } },\r\n { binding: 3, resource: { buffer: this.partitionHistogramBuffer } },\r\n { binding: 4, resource: { buffer: keysIn } },\r\n { binding: 5, resource: { buffer: valuesIn } },\r\n { binding: 6, resource: { buffer: keysOut } },\r\n { binding: 7, resource: { buffer: valuesOut } },\r\n ],\r\n label: `downsweep-bind-group-${passIdx}`,\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * 设置屏幕尺寸\r\n */\r\n setScreenSize(width: number, height: number): void {\r\n this.screenWidth = width;\r\n this.screenHeight = height;\r\n }\r\n\r\n /**\r\n * 设置剔除参数\r\n */\r\n setCullingOptions(options: Partial<CullingOptions>): void {\r\n this.cullingOptions = { ...this.cullingOptions, ...options };\r\n }\r\n\r\n /**\r\n * 执行剔除和排序\r\n * 每帧调用\r\n */\r\n sort(): void {\r\n // ============================================\r\n // 更新 Culling 参数\r\n // ============================================\r\n const cullingParamsData = new ArrayBuffer(32);\r\n const view = new DataView(cullingParamsData);\r\n view.setUint32(0, this.splatCount, true);\r\n view.setFloat32(4, this.cullingOptions.nearPlane, true);\r\n view.setFloat32(8, this.cullingOptions.farPlane, true);\r\n view.setFloat32(12, this.screenWidth, true);\r\n view.setFloat32(16, this.screenHeight, true);\r\n view.setFloat32(20, this.cullingOptions.frustumDilation ?? 0.2, true);\r\n view.setFloat32(24, this.cullingOptions.pixelThreshold, true);\r\n view.setUint32(28, this.cullingOptions.maxVisibleCount ?? 0, true);\r\n this.device.queue.writeBuffer(this.cullingParamsBuffer, 0, cullingParamsData);\r\n\r\n const encoder = this.device.createCommandEncoder({ label: \"splat-sort-encoder\" });\r\n\r\n // 只需清零 globalHistogramBuffer(使用 atomicAdd 累加,必须归零)\r\n // 其余 buffer 无需清零:\r\n // - depthKeys/visibleIndices: cull shader 写入 [0, visibleCount),sort 只读这个范围\r\n // - keysTemp/valuesTemp: downsweep 写入 [0, visibleCount),后续 pass 只读这个范围\r\n // - partitionHistogram: upsweep 直接赋值覆盖(非 atomicAdd),未使用的分区不会被读取\r\n encoder.clearBuffer(this.globalHistogramBuffer);\r\n\r\n // ============================================\r\n // Pass 0: 初始化 Indirect Buffer\r\n // ============================================\r\n {\r\n const pass = encoder.beginComputePass({ label: \"init-indirect\" });\r\n pass.setPipeline(this.initIndirectPipeline);\r\n pass.setBindGroup(0, this.cullingBindGroup);\r\n pass.dispatchWorkgroups(1);\r\n pass.end();\r\n }\r\n\r\n // ============================================\r\n // Pass 1: Project & Cull\r\n // ============================================\r\n {\r\n const pass = encoder.beginComputePass({ label: \"project-cull\" });\r\n pass.setPipeline(this.projectCullPipeline);\r\n pass.setBindGroup(0, this.cullingBindGroup);\r\n pass.dispatchWorkgroups(Math.ceil(this.splatCount / WORKGROUP_SIZE));\r\n pass.end();\r\n }\r\n\r\n // ============================================\r\n // Radix Sort: 4 passes (8-bit increments)\r\n // 每个 pass 在独立的 compute pass 中以确保内存同步\r\n // 参数已在构造函数中预填充到独立的 buffer\r\n // ============================================\r\n for (let passIdx = 0; passIdx < 4; passIdx++) {\r\n // Upsweep\r\n {\r\n const pass = encoder.beginComputePass({ label: `upsweep-p${passIdx}` });\r\n pass.setPipeline(this.upsweepPipeline);\r\n pass.setBindGroup(0, this.upsweepBindGroups[passIdx]);\r\n pass.dispatchWorkgroups(this.numPartitions);\r\n pass.end();\r\n }\r\n\r\n // Spine\r\n {\r\n const pass = encoder.beginComputePass({ label: `spine-p${passIdx}` });\r\n pass.setPipeline(this.spinePipeline);\r\n pass.setBindGroup(0, this.spineBindGroups[passIdx]);\r\n pass.dispatchWorkgroups(RADIX_SIZE);\r\n pass.end();\r\n }\r\n\r\n // Downsweep\r\n {\r\n const pass = encoder.beginComputePass({ label: `downsweep-p${passIdx}` });\r\n pass.setPipeline(this.downsweepPipeline);\r\n pass.setBindGroup(0, this.downsweepBindGroups[passIdx]);\r\n pass.dispatchWorkgroups(this.numPartitions);\r\n pass.end();\r\n }\r\n }\r\n\r\n // ============================================\r\n // 排序后截断:丢弃被遮挡的远处 splat\r\n // ============================================\r\n {\r\n const pass = encoder.beginComputePass({ label: \"clamp-draw-count\" });\r\n pass.setPipeline(this.clampDrawCountPipeline);\r\n pass.setBindGroup(0, this.cullingBindGroup);\r\n pass.dispatchWorkgroups(1);\r\n pass.end();\r\n }\r\n\r\n this.device.queue.submit([encoder.finish()]);\r\n }\r\n\r\n /**\r\n * 获取排序后的索引 buffer(用于渲染)\r\n */\r\n getIndicesBuffer(): GPUBuffer {\r\n return this.sortedIndicesBuffer;\r\n }\r\n\r\n /**\r\n * 获取 DrawIndirect buffer\r\n */\r\n getDrawIndirectBuffer(): GPUBuffer {\r\n return this.indirectBuffer;\r\n }\r\n\r\n /**\r\n * 获取 splat 总数量\r\n */\r\n getSplatCount(): number {\r\n return this.splatCount;\r\n }\r\n\r\n /**\r\n * 销毁资源\r\n */\r\n destroy(): void {\r\n this.cullingParamsBuffer.destroy();\r\n this.depthKeysBuffer.destroy();\r\n this.visibleIndicesBuffer.destroy();\r\n this.indirectBuffer.destroy();\r\n this.globalHistogramBuffer.destroy();\r\n this.partitionHistogramBuffer.destroy();\r\n this.keysTempBuffer.destroy();\r\n this.valuesTempBuffer.destroy();\r\n for (const buffer of this.sortParamsBuffers) {\r\n buffer.destroy();\r\n }\r\n this.sortedIndicesBuffer.destroy();\r\n }\r\n}\r\n","/**\r\n * GSSplatRenderer - 优化的 3D Gaussian Splatting 渲染器\r\n *\r\n * 基于 rfs-gsplat-render 的实现进行优化:\r\n * 1. GPU Radix Sort - O(n) 稳定排序\r\n * 2. Normalized Gaussian - 消除边缘雾化\r\n * 3. ClipCorner 优化 - 减少 overdraw\r\n * 4. MipSplatting 抗锯齿\r\n * 5. 改进的视锥剔除\r\n */\r\n\r\nimport { Renderer } from \"../core/Renderer\";\r\nimport { Camera } from \"../core/Camera\";\r\nimport { SplatCPU } from \"./PLYLoader\";\r\nimport { GSSplatSorter } from \"./GSSplatSorter\";\r\nimport { CompactSplatData, compactDataToGPUBuffer } from \"./PLYLoaderMobile\";\r\nimport type { BoundingBox, Vec3Tuple } from \"../types\";\r\nimport { SHMode, RendererCapabilities } from \"../types\";\r\nimport type {\r\n IGSSplatRenderer,\r\n IGSSplatRendererWithCapabilities,\r\n} from \"./IGSSplatRenderer\";\r\n\r\n// 优化的 shader (内联)\r\nconst gsOptimizedShader = /* wgsl */ `\r\n/**\r\n * 优化的 3D Gaussian Splatting Shader\r\n * 支持完整 L3 球谐函数(SH)视角相关颜色\r\n * 参考 rfs-gsplat-render / PlayCanvas SuperSplat 实现\r\n */\r\n\r\nconst SQRT_8: f32 = 2.82842712475;\r\nconst SH_C0: f32 = 0.28209479177387814;\r\nconst SH_C1: f32 = 0.4886025119029199;\r\n// L2 SH 系数\r\nconst SH_C2_0: f32 = 1.0925484305920792;\r\nconst SH_C2_1: f32 = -1.0925484305920792;\r\nconst SH_C2_2: f32 = 0.31539156525252005;\r\nconst SH_C2_3: f32 = -1.0925484305920792;\r\nconst SH_C2_4: f32 = 0.5462742152960396;\r\n// L3 SH 系数\r\nconst SH_C3_0: f32 = -0.5900435899266435;\r\nconst SH_C3_1: f32 = 2.890611442640554;\r\nconst SH_C3_2: f32 = -0.4570457994644658;\r\nconst SH_C3_3: f32 = 0.3731763325901154;\r\nconst SH_C3_4: f32 = -0.4570457994644658;\r\nconst SH_C3_5: f32 = 1.4453057213202769;\r\nconst SH_C3_6: f32 = -0.5900435899266435;\r\n// 低通滤波器 (正则化协方差矩阵,避免数值问题)\r\nconst LOW_PASS_FILTER: f32 = 0.3;\r\n// Alpha 剔除阈值 (1/255)\r\nconst ALPHA_CULL_THRESHOLD: f32 = 0.00392156863;\r\n// Normalized Gaussian 常量 (用于消除边缘雾化)\r\n// 使用 k=4 的 Gaussian: exp(-4*A)\r\n// EXP_NEG_K = exp(-4) ≈ 0.0183\r\n// INV_ONE_MINUS_EXP_NEG_K = 1 / (1 - exp(-4)) ≈ 1.0187\r\nconst GAUSSIAN_K: f32 = 4.0;\r\nconst EXP_NEG_K: f32 = 0.01831563888873418;\r\nconst INV_ONE_MINUS_EXP_NEG_K: f32 = 1.01865736036377408;\r\n\r\nstruct Uniforms {\r\n view: mat4x4<f32>,\r\n proj: mat4x4<f32>,\r\n model: mat4x4<f32>,\r\n cameraPos: vec3<f32>,\r\n _pad: f32,\r\n screenSize: vec2<f32>,\r\n _pad2: vec2<f32>,\r\n}\r\n\r\nstruct Splat {\r\n mean: vec3<f32>, _pad0: f32,\r\n scale: vec3<f32>, _pad1: f32,\r\n rotation: vec4<f32>,\r\n colorDC: vec3<f32>,\r\n opacity: f32,\r\n sh1: array<f32, 9>,\r\n sh2: array<f32, 15>,\r\n sh3: array<f32, 21>,\r\n _pad2: array<f32, 3>,\r\n}\r\n\r\n// 完整 L3 球谐函数求值 (匹配原始 3DGS Python 实现)\r\n// SH 系数以 interleaved 格式存储: [R0,G0,B0, R1,G1,B1, ...]\r\n// dir: 从相机指向 splat 的归一化方向向量(模型空间)\r\nfn evalSH(splat: Splat, dir: vec3<f32>) -> vec3<f32> {\r\n let x = dir.x;\r\n let y = dir.y;\r\n let z = dir.z;\r\n\r\n var result = vec3<f32>(0.0);\r\n\r\n // L1: 3 个基函数\r\n result += (-SH_C1 * y) * vec3<f32>(splat.sh1[0], splat.sh1[1], splat.sh1[2]);\r\n result += ( SH_C1 * z) * vec3<f32>(splat.sh1[3], splat.sh1[4], splat.sh1[5]);\r\n result += (-SH_C1 * x) * vec3<f32>(splat.sh1[6], splat.sh1[7], splat.sh1[8]);\r\n\r\n // L2: 5 个基函数\r\n let xx = x * x; let yy = y * y; let zz = z * z;\r\n let xy = x * y; let yz = y * z; let xz = x * z;\r\n\r\n result += (SH_C2_0 * xy) * vec3<f32>(splat.sh2[0], splat.sh2[1], splat.sh2[2]);\r\n result += (SH_C2_1 * yz) * vec3<f32>(splat.sh2[3], splat.sh2[4], splat.sh2[5]);\r\n result += (SH_C2_2 * (2.0 * zz - xx - yy)) * vec3<f32>(splat.sh2[6], splat.sh2[7], splat.sh2[8]);\r\n result += (SH_C2_3 * xz) * vec3<f32>(splat.sh2[9], splat.sh2[10], splat.sh2[11]);\r\n result += (SH_C2_4 * (xx - yy)) * vec3<f32>(splat.sh2[12], splat.sh2[13], splat.sh2[14]);\r\n\r\n // L3: 7 个基函数\r\n result += (SH_C3_0 * y * (3.0 * xx - yy)) * vec3<f32>(splat.sh3[0], splat.sh3[1], splat.sh3[2]);\r\n result += (SH_C3_1 * xy * z) * vec3<f32>(splat.sh3[3], splat.sh3[4], splat.sh3[5]);\r\n result += (SH_C3_2 * y * (4.0 * zz - xx - yy)) * vec3<f32>(splat.sh3[6], splat.sh3[7], splat.sh3[8]);\r\n result += (SH_C3_3 * z * (2.0 * zz - 3.0 * xx - 3.0 * yy)) * vec3<f32>(splat.sh3[9], splat.sh3[10], splat.sh3[11]);\r\n result += (SH_C3_4 * x * (4.0 * zz - xx - yy)) * vec3<f32>(splat.sh3[12], splat.sh3[13], splat.sh3[14]);\r\n result += (SH_C3_5 * z * (xx - yy)) * vec3<f32>(splat.sh3[15], splat.sh3[16], splat.sh3[17]);\r\n result += (SH_C3_6 * x * (xx - 3.0 * yy)) * vec3<f32>(splat.sh3[18], splat.sh3[19], splat.sh3[20]);\r\n\r\n return result;\r\n}\r\n\r\n@group(0) @binding(0) var<uniform> uniforms: Uniforms;\r\n@group(0) @binding(1) var<storage, read> splats: array<Splat>;\r\n@group(0) @binding(2) var<storage, read> sortedIndices: array<u32>;\r\n\r\nstruct VertexOutput {\r\n @builtin(position) position: vec4<f32>,\r\n @location(0) fragPos: vec2<f32>,\r\n @location(1) color: vec3<f32>,\r\n @location(2) opacity: f32,\r\n}\r\n\r\nconst QUAD_POSITIONS = array<vec2<f32>, 4>(\r\n vec2<f32>(-1.0, -1.0), vec2<f32>(-1.0, 1.0),\r\n vec2<f32>(1.0, -1.0), vec2<f32>(1.0, 1.0),\r\n);\r\n\r\n// ClipCorner 优化:根据透明度缩小 quad,排除低于阈值的 Gaussian 区域\r\n// 使用 Normalized Gaussian: weight = (exp(-k*A) - exp(-k)) / (1 - exp(-k))\r\n// 需要找到 A 使得 alpha * weight >= 1/255\r\n// 即 weight >= 1/(255*alpha)\r\n// (exp(-k*A) - exp(-k)) / (1 - exp(-k)) >= 1/(255*alpha)\r\n// exp(-k*A) >= 1/(255*alpha) * (1 - exp(-k)) + exp(-k)\r\n// -k*A >= ln(1/(255*alpha) * (1 - exp(-k)) + exp(-k))\r\n// A <= -ln(1/(255*alpha) * (1 - exp(-k)) + exp(-k)) / k\r\nfn computeClipFactor(alpha: f32) -> f32 {\r\n if alpha <= ALPHA_CULL_THRESHOLD { return 0.0; }\r\n let threshold = 1.0 / (255.0 * alpha);\r\n // 如果 threshold >= 1.0,整个 splat 都低于可见阈值\r\n if threshold >= 1.0 { return 0.0; }\r\n // 计算 clip 因子:找到 normalized gaussian = threshold 的位置\r\n let targetExp = threshold * (1.0 - EXP_NEG_K) + EXP_NEG_K;\r\n if targetExp >= 1.0 { return 0.0; }\r\n let A = -log(targetExp) / GAUSSIAN_K;\r\n return min(1.0, sqrt(A));\r\n}\r\n\r\n// 四元数转旋转矩阵 (PLY 格式: w, x, y, z)\r\nfn quatToMat3(q: vec4<f32>) -> mat3x3<f32> {\r\n let r = q.x; let x = q.y; let y = q.z; let z = q.w;\r\n return mat3x3<f32>(\r\n vec3<f32>(1.0 - 2.0 * (y * y + z * z), 2.0 * (x * y + r * z), 2.0 * (x * z - r * y)),\r\n vec3<f32>(2.0 * (x * y - r * z), 1.0 - 2.0 * (x * x + z * z), 2.0 * (y * z + r * x)),\r\n vec3<f32>(2.0 * (x * z + r * y), 2.0 * (y * z - r * x), 1.0 - 2.0 * (x * x + y * y))\r\n );\r\n}\r\n\r\nfn computeCovariance3D(scale: vec3<f32>, rotation: vec4<f32>) -> mat3x3<f32> {\r\n let R = quatToMat3(rotation);\r\n let S = mat3x3<f32>(vec3<f32>(scale.x, 0.0, 0.0), vec3<f32>(0.0, scale.y, 0.0), vec3<f32>(0.0, 0.0, scale.z));\r\n let M = R * S;\r\n return M * transpose(M);\r\n}\r\n\r\n// 协方差投影 (匹配参考实现)\r\n// 注意: viewCenter 是 vec4,直接使用 .xyz (不除以 w)\r\nfn projectCovariance(cov3d: mat3x3<f32>, viewCenter: vec4<f32>, focal: vec2<f32>, modelViewMat: mat4x4<f32>) -> vec3<f32> {\r\n let v = viewCenter.xyz; // 直接使用,不除以 w\r\n let s = 1.0 / (v.z * v.z);\r\n \r\n // Jacobian 矩阵\r\n let J = mat3x3<f32>(\r\n vec3<f32>(focal.x / v.z, 0.0, 0.0),\r\n vec3<f32>(0.0, focal.y / v.z, 0.0),\r\n vec3<f32>(-(focal.x * v.x) * s, -(focal.y * v.y) * s, 0.0)\r\n );\r\n \r\n // 从 model-view 矩阵提取 3x3 旋转部分 (匹配参考实现)\r\n let W = mat3x3<f32>(\r\n vec3<f32>(modelViewMat[0][0], modelViewMat[0][1], modelViewMat[0][2]),\r\n vec3<f32>(modelViewMat[1][0], modelViewMat[1][1], modelViewMat[1][2]),\r\n vec3<f32>(modelViewMat[2][0], modelViewMat[2][1], modelViewMat[2][2])\r\n );\r\n \r\n let T = J * W;\r\n let cov2d = T * cov3d * transpose(T);\r\n return vec3<f32>(cov2d[0][0], cov2d[0][1], cov2d[1][1]);\r\n}\r\n\r\nstruct ExtentResult {\r\n basis: vec4<f32>,\r\n adjustedOpacity: f32,\r\n}\r\n\r\n// 计算 2D 投影范围\r\n// 精确匹配 PlayCanvas/SuperSplat 实现\r\n// 注意: MipSplatting 抗锯齿默认禁用,因为大多数模型不是用 MipSplatting 训练的\r\n// 如果模型是用 MipSplatting 训练的,可以启用 GSPLAT_AA 模式\r\nfn computeExtentBasisAA(cov2dIn: vec3<f32>, opacity: f32, viewportSize: vec2<f32>) -> ExtentResult {\r\n var result: ExtentResult;\r\n var cov2d = cov2dIn;\r\n var alpha = opacity;\r\n \r\n // 添加低通滤波 (正则化) - 匹配 PlayCanvas: +0.3\r\n // 这避免了非常小的特征值导致的数值问题\r\n cov2d.x += LOW_PASS_FILTER;\r\n cov2d.z += LOW_PASS_FILTER;\r\n \r\n // 特征值分解 (使用 PlayCanvas 公式)\r\n let a = cov2d.x; // diagonal1\r\n let d = cov2d.z; // diagonal2\r\n let b = cov2d.y; // offDiagonal\r\n \r\n let mid = 0.5 * (a + d);\r\n let radius = length(vec2<f32>((a - d) * 0.5, b));\r\n \r\n let lambda1 = mid + radius;\r\n let lambda2 = mid - radius;\r\n \r\n // 非正定协方差矩阵直接剔除\r\n if lambda2 <= 0.0 { \r\n result.basis = vec4<f32>(0.0);\r\n result.adjustedOpacity = 0.0;\r\n return result;\r\n }\r\n \r\n // 使用基于视口的最大限制 (匹配 PlayCanvas)\r\n let vmin = min(1024.0, min(viewportSize.x, viewportSize.y));\r\n \r\n // 计算轴长度: l = 2 * sqrt(2 * lambda) ≈ 2.83 * sqrt(lambda)\r\n // 这与 GAUSSIAN_K=4 配套使用:\r\n // 在 UV=1 边界,对应 2*sqrt(2) 个标准差的位置\r\n // exp(-4 * 1) = exp(-4) ≈ 0.018,Normalized 后精确为 0\r\n let l1 = min(2.0 * sqrt(2.0 * lambda1), vmin);\r\n let l2 = min(2.0 * sqrt(2.0 * lambda2), vmin);\r\n \r\n // 剔除小于 2 像素的 Gaussian(消除亚像素 splat 造成的雾化)\r\n if l1 < 0.5 && l2 < 0.5 { \r\n result.basis = vec4<f32>(0.0);\r\n result.adjustedOpacity = 0.0;\r\n return result;\r\n }\r\n \r\n // 从 offDiagonal 和特征值差计算特征向量\r\n // diagonalVector = normalize(vec2(offDiagonal, lambda1 - diagonal1))\r\n let diagVec = normalize(vec2<f32>(b, lambda1 - a));\r\n let eigenvector1 = diagVec;\r\n let eigenvector2 = vec2<f32>(diagVec.y, -diagVec.x);\r\n \r\n // 计算基向量 (不应用额外的 splat_scale,因为我们使用默认值 1.0)\r\n result.basis = vec4<f32>(eigenvector1 * l1, eigenvector2 * l2);\r\n result.adjustedOpacity = alpha;\r\n return result;\r\n}\r\n\r\nfn getModelScale3(model: mat4x4<f32>) -> vec3<f32> {\r\n return vec3<f32>(length(model[0].xyz), length(model[1].xyz), length(model[2].xyz));\r\n}\r\n\r\n@vertex\r\nfn vs_main(@builtin(vertex_index) vertexIndex: u32, @builtin(instance_index) instanceIndex: u32) -> VertexOutput {\r\n var output: VertexOutput;\r\n let splatIndex = sortedIndices[instanceIndex];\r\n let splat = splats[splatIndex];\r\n let quadPos = QUAD_POSITIONS[vertexIndex];\r\n \r\n // 透明度剔除\r\n if splat.opacity < ALPHA_CULL_THRESHOLD { output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output; }\r\n \r\n // 四元数有效性检查\r\n let quatNormSqr = dot(splat.rotation, splat.rotation);\r\n if quatNormSqr < 1e-6 { output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output; }\r\n \r\n // 变换到视图空间 (匹配参考实现: Local -> World -> View -> Clip)\r\n let worldPos = uniforms.model * vec4<f32>(splat.mean, 1.0);\r\n let viewPos = uniforms.view * worldPos; // vec4, 保持 w 分量\r\n let clipPos = uniforms.proj * viewPos;\r\n \r\n // 近平面剔除 (viewPos.z 是负数,相机看向 -Z)\r\n if viewPos.z >= 0.0 { output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output; }\r\n \r\n // NDC 计算\r\n let pW = 1.0 / (clipPos.w + 0.0000001);\r\n let ndcPos = clipPos * pW;\r\n \r\n // 视锥剔除 (放宽边界以避免 pop-in)\r\n let clipBound = 1.3;\r\n if abs(ndcPos.x) > clipBound || abs(ndcPos.y) > clipBound || ndcPos.z < -0.2 || ndcPos.z > 1.0 {\r\n output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output;\r\n }\r\n \r\n // 计算 3D 协方差 (使用原始 scale,模型缩放通过 model-view 矩阵处理)\r\n // 关键: 不要在这里应用模型缩放,协方差投影会通过 model-view 矩阵正确处理\r\n let cov3d = computeCovariance3D(splat.scale, splat.rotation);\r\n \r\n // 计算焦距 (匹配参考实现: abs(proj[0][0]) * 0.5 * width)\r\n let focal = vec2<f32>(\r\n abs(uniforms.proj[0][0]) * 0.5 * uniforms.screenSize.x,\r\n abs(uniforms.proj[1][1]) * 0.5 * uniforms.screenSize.y\r\n );\r\n \r\n // 计算 model-view 矩阵 (匹配参考实现)\r\n let modelViewMat = uniforms.view * uniforms.model;\r\n \r\n // 投影协方差到 2D (传入 viewPos 作为 vec4,不除以 w)\r\n let cov2d = projectCovariance(cov3d, viewPos, focal, modelViewMat);\r\n \r\n // 计算范围基向量 (带抗锯齿)\r\n let extentResult = computeExtentBasisAA(cov2d, splat.opacity, uniforms.screenSize);\r\n let basis = extentResult.basis;\r\n let adjustedOpacity = extentResult.adjustedOpacity;\r\n \r\n if basis.x == 0.0 && basis.y == 0.0 && basis.z == 0.0 && basis.w == 0.0 {\r\n output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output;\r\n }\r\n \r\n // 视锥边缘剔除 (匹配 PlayCanvas)\r\n let maxExtentPixels = max(length(basis.xy), length(basis.zw));\r\n let pixelToClip = 2.0 * vec2<f32>(clipPos.w, clipPos.w) / uniforms.screenSize;\r\n let splatExtentClip = vec2<f32>(maxExtentPixels, maxExtentPixels) * pixelToClip;\r\n if any((abs(clipPos.xy) - splatExtentClip) > vec2<f32>(clipPos.w, clipPos.w)) {\r\n output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output;\r\n }\r\n \r\n // ClipCorner 优化 (匹配 PlayCanvas/SuperSplat)\r\n // 根据透明度缩小 quad,排除 alpha < 1/255 的区域\r\n let clipFactor = computeClipFactor(adjustedOpacity);\r\n if clipFactor <= 0.0 { output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output; }\r\n \r\n // 计算最终顶点位置\r\n // basis_viewport: 从像素转换到 NDC 空间\r\n let basisViewport = vec2<f32>(1.0 / uniforms.screenSize.x, 1.0 / uniforms.screenSize.y);\r\n \r\n // 用 clipFactor 缩放基向量 (缩小 quad)\r\n let basisVector1 = basis.xy * clipFactor;\r\n let basisVector2 = basis.zw * clipFactor;\r\n \r\n // 计算 NDC 偏移\r\n // 注意: quadPos 在 [-1, 1] 范围内,clipFactor 只影响 quad 大小 (basis_vector)\r\n let ndcOffset = (quadPos.x * basisVector1 + quadPos.y * basisVector2) * basisViewport * 2.0;\r\n output.position = vec4<f32>(ndcPos.xy + ndcOffset, ndcPos.z, 1.0);\r\n \r\n // UV 输出 - 用 clipFactor 缩放以获得正确的 Gaussian 权重\r\n output.fragPos = quadPos * clipFactor;\r\n \r\n // 球谐函数颜色计算:\r\n // colorDC 已在 CPU 端预处理为 (dc * SH_C0 + 0.5)\r\n // evalSH() 计算 L1~L3 的视角相关色彩贡献\r\n // 方向需要在模型空间计算(SH 系数在模型空间定义)\r\n let shDir = normalize(\r\n vec3<f32>(\r\n dot(worldPos.xyz - uniforms.cameraPos, uniforms.model[0].xyz),\r\n dot(worldPos.xyz - uniforms.cameraPos, uniforms.model[1].xyz),\r\n dot(worldPos.xyz - uniforms.cameraPos, uniforms.model[2].xyz)\r\n )\r\n );\r\n output.color = splat.colorDC + evalSH(splat, shDir);\r\n output.opacity = adjustedOpacity;\r\n return output;\r\n}\r\n\r\n@fragment\r\nfn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {\r\n if input.opacity <= 0.0 { discard; }\r\n \r\n // A = 到中心的平方距离,在 UV 空间中\r\n let A = dot(input.fragPos, input.fragPos);\r\n \r\n // 丢弃单位圆外的片段\r\n if A > 1.0 { discard; }\r\n \r\n // Normalized Gaussian 衰减 (关键:消除边缘雾化)\r\n // 标准 Gaussian exp(-k*A) 在边界 A=1 时不为 0,会产生累积雾化\r\n // Normalized 公式: (exp(-k*A) - exp(-k)) / (1 - exp(-k))\r\n // 在 A=0 时 = 1.0,在 A=1 时 = 精确的 0.0\r\n let weight = (exp(-GAUSSIAN_K * A) - EXP_NEG_K) * INV_ONE_MINUS_EXP_NEG_K;\r\n \r\n // 组合 splat 透明度\r\n let opacity = weight * input.opacity;\r\n \r\n // Alpha 阈值丢弃\r\n if opacity < ALPHA_CULL_THRESHOLD { discard; }\r\n \r\n // 颜色 clamp 到有效范围 (防止负值)\r\n let color = max(input.color, vec3<f32>(0.0));\r\n \r\n // 预乘 alpha 输出 (匹配 blend mode: src=ONE, dst=ONE_MINUS_SRC_ALPHA)\r\n return vec4<f32>(color * opacity, opacity);\r\n}\r\n`;\r\n\r\n\r\nconst gsDepthNormalShader = /* wgsl */ `\r\nconst SQRT_8: f32 = 2.82842712475;\r\nconst LOW_PASS_FILTER: f32 = 0.3;\r\nconst ALPHA_CULL_THRESHOLD: f32 = 0.00392156863;\r\nconst GAUSSIAN_K: f32 = 4.0;\r\nconst EXP_NEG_K: f32 = 0.01831563888873418;\r\nconst INV_ONE_MINUS_EXP_NEG_K: f32 = 1.01865736036377408;\r\n\r\nstruct Uniforms {\r\n view: mat4x4<f32>,\r\n proj: mat4x4<f32>,\r\n model: mat4x4<f32>,\r\n cameraPos: vec3<f32>,\r\n _pad: f32,\r\n screenSize: vec2<f32>,\r\n _pad2: vec2<f32>,\r\n}\r\n\r\nstruct Splat {\r\n mean: vec3<f32>, _pad0: f32,\r\n scale: vec3<f32>, _pad1: f32,\r\n rotation: vec4<f32>,\r\n colorDC: vec3<f32>,\r\n opacity: f32,\r\n sh1: array<f32, 9>,\r\n sh2: array<f32, 15>,\r\n sh3: array<f32, 21>,\r\n _pad2: array<f32, 3>,\r\n}\r\n\r\n@group(0) @binding(0) var<uniform> uniforms: Uniforms;\r\n@group(0) @binding(1) var<storage, read> splats: array<Splat>;\r\n@group(0) @binding(2) var<storage, read> sortedIndices: array<u32>;\r\n\r\nstruct VertexOutput {\r\n @builtin(position) position: vec4<f32>,\r\n @location(0) fragPos: vec2<f32>,\r\n @location(1) opacity: f32,\r\n @location(2) viewDepth: f32,\r\n @location(3) worldNormal: vec3<f32>,\r\n}\r\n\r\nconst QUAD_POSITIONS = array<vec2<f32>, 4>(\r\n vec2<f32>(-1.0, -1.0), vec2<f32>(-1.0, 1.0),\r\n vec2<f32>(1.0, -1.0), vec2<f32>(1.0, 1.0),\r\n);\r\n\r\nfn computeClipFactor(alpha: f32) -> f32 {\r\n if alpha <= ALPHA_CULL_THRESHOLD { return 0.0; }\r\n let threshold = 1.0 / (255.0 * alpha);\r\n if threshold >= 1.0 { return 0.0; }\r\n let targetExp = threshold * (1.0 - EXP_NEG_K) + EXP_NEG_K;\r\n if targetExp >= 1.0 { return 0.0; }\r\n let A = -log(targetExp) / GAUSSIAN_K;\r\n return min(1.0, sqrt(A));\r\n}\r\n\r\nfn quatToMat3(q: vec4<f32>) -> mat3x3<f32> {\r\n let r = q.x; let x = q.y; let y = q.z; let z = q.w;\r\n return mat3x3<f32>(\r\n vec3<f32>(1.0 - 2.0 * (y * y + z * z), 2.0 * (x * y + r * z), 2.0 * (x * z - r * y)),\r\n vec3<f32>(2.0 * (x * y - r * z), 1.0 - 2.0 * (x * x + z * z), 2.0 * (y * z + r * x)),\r\n vec3<f32>(2.0 * (x * z + r * y), 2.0 * (y * z - r * x), 1.0 - 2.0 * (x * x + y * y))\r\n );\r\n}\r\n\r\nfn computeCovariance3D(scale: vec3<f32>, rotation: vec4<f32>) -> mat3x3<f32> {\r\n let R = quatToMat3(rotation);\r\n let S = mat3x3<f32>(vec3<f32>(scale.x, 0.0, 0.0), vec3<f32>(0.0, scale.y, 0.0), vec3<f32>(0.0, 0.0, scale.z));\r\n let M = R * S;\r\n return M * transpose(M);\r\n}\r\n\r\nfn projectCovariance(cov3d: mat3x3<f32>, viewCenter: vec4<f32>, focal: vec2<f32>, modelViewMat: mat4x4<f32>) -> vec3<f32> {\r\n let v = viewCenter.xyz;\r\n let s = 1.0 / (v.z * v.z);\r\n let J = mat3x3<f32>(\r\n vec3<f32>(focal.x / v.z, 0.0, 0.0),\r\n vec3<f32>(0.0, focal.y / v.z, 0.0),\r\n vec3<f32>(-(focal.x * v.x) * s, -(focal.y * v.y) * s, 0.0)\r\n );\r\n let W = mat3x3<f32>(\r\n vec3<f32>(modelViewMat[0][0], modelViewMat[0][1], modelViewMat[0][2]),\r\n vec3<f32>(modelViewMat[1][0], modelViewMat[1][1], modelViewMat[1][2]),\r\n vec3<f32>(modelViewMat[2][0], modelViewMat[2][1], modelViewMat[2][2])\r\n );\r\n let T = J * W;\r\n let cov2d = T * cov3d * transpose(T);\r\n return vec3<f32>(cov2d[0][0], cov2d[0][1], cov2d[1][1]);\r\n}\r\n\r\nstruct ExtentResult {\r\n basis: vec4<f32>,\r\n adjustedOpacity: f32,\r\n}\r\n\r\nfn computeExtentBasisAA(cov2dIn: vec3<f32>, opacity: f32, viewportSize: vec2<f32>) -> ExtentResult {\r\n var result: ExtentResult;\r\n var cov2d = cov2dIn;\r\n var alpha = opacity;\r\n cov2d.x += LOW_PASS_FILTER;\r\n cov2d.z += LOW_PASS_FILTER;\r\n let a = cov2d.x;\r\n let d = cov2d.z;\r\n let b = cov2d.y;\r\n let mid = 0.5 * (a + d);\r\n let radius = length(vec2<f32>((a - d) * 0.5, b));\r\n let lambda1 = mid + radius;\r\n let lambda2 = mid - radius;\r\n if lambda2 <= 0.0 {\r\n result.basis = vec4<f32>(0.0);\r\n result.adjustedOpacity = 0.0;\r\n return result;\r\n }\r\n let vmin = min(1024.0, min(viewportSize.x, viewportSize.y));\r\n let l1 = min(2.0 * sqrt(2.0 * lambda1), vmin);\r\n let l2 = min(2.0 * sqrt(2.0 * lambda2), vmin);\r\n if l1 < 0.5 && l2 < 0.5 {\r\n result.basis = vec4<f32>(0.0);\r\n result.adjustedOpacity = 0.0;\r\n return result;\r\n }\r\n let diagVec = normalize(vec2<f32>(b, lambda1 - a));\r\n let eigenvector1 = diagVec;\r\n let eigenvector2 = vec2<f32>(diagVec.y, -diagVec.x);\r\n result.basis = vec4<f32>(eigenvector1 * l1, eigenvector2 * l2);\r\n result.adjustedOpacity = alpha;\r\n return result;\r\n}\r\n\r\n// Extract the normal of a gaussian ellipsoid from its scale and rotation.\r\n// The normal is the axis corresponding to the smallest scale (shortest axis).\r\n// After rotation, this gives the world-space normal of the local surface.\r\nfn computeSplatNormal(scale: vec3<f32>, rotation: vec4<f32>, modelMat: mat4x4<f32>) -> vec3<f32> {\r\n let R = quatToMat3(rotation);\r\n // Find the axis with smallest scale\r\n var minAxis: vec3<f32>;\r\n if scale.x <= scale.y && scale.x <= scale.z {\r\n minAxis = R[0]; // column 0\r\n } else if scale.y <= scale.z {\r\n minAxis = R[1]; // column 1\r\n } else {\r\n minAxis = R[2]; // column 2\r\n }\r\n // Transform to world space via model matrix 3x3 part\r\n let worldNormal = vec3<f32>(\r\n modelMat[0][0] * minAxis.x + modelMat[1][0] * minAxis.y + modelMat[2][0] * minAxis.z,\r\n modelMat[0][1] * minAxis.x + modelMat[1][1] * minAxis.y + modelMat[2][1] * minAxis.z,\r\n modelMat[0][2] * minAxis.x + modelMat[1][2] * minAxis.y + modelMat[2][2] * minAxis.z\r\n );\r\n let len = length(worldNormal);\r\n if len < 1e-8 { return vec3<f32>(0.0, 1.0, 0.0); }\r\n return worldNormal / len;\r\n}\r\n\r\n@vertex\r\nfn vs_main(@builtin(vertex_index) vertexIndex: u32, @builtin(instance_index) instanceIndex: u32) -> VertexOutput {\r\n var output: VertexOutput;\r\n let splatIndex = sortedIndices[instanceIndex];\r\n let splat = splats[splatIndex];\r\n let quadPos = QUAD_POSITIONS[vertexIndex];\r\n\r\n if splat.opacity < ALPHA_CULL_THRESHOLD { output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output; }\r\n let quatNormSqr = dot(splat.rotation, splat.rotation);\r\n if quatNormSqr < 1e-6 { output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output; }\r\n\r\n let worldPos = uniforms.model * vec4<f32>(splat.mean, 1.0);\r\n let viewPos = uniforms.view * worldPos;\r\n let clipPos = uniforms.proj * viewPos;\r\n\r\n if viewPos.z >= 0.0 { output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output; }\r\n\r\n let pW = 1.0 / (clipPos.w + 0.0000001);\r\n let ndcPos = clipPos * pW;\r\n\r\n let clipBound = 1.3;\r\n if abs(ndcPos.x) > clipBound || abs(ndcPos.y) > clipBound || ndcPos.z < -0.2 || ndcPos.z > 1.0 {\r\n output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output;\r\n }\r\n\r\n let cov3d = computeCovariance3D(splat.scale, splat.rotation);\r\n let focal = vec2<f32>(\r\n abs(uniforms.proj[0][0]) * 0.5 * uniforms.screenSize.x,\r\n abs(uniforms.proj[1][1]) * 0.5 * uniforms.screenSize.y\r\n );\r\n let modelViewMat = uniforms.view * uniforms.model;\r\n let cov2d = projectCovariance(cov3d, viewPos, focal, modelViewMat);\r\n\r\n let extentResult = computeExtentBasisAA(cov2d, splat.opacity, uniforms.screenSize);\r\n let basis = extentResult.basis;\r\n let adjustedOpacity = extentResult.adjustedOpacity;\r\n\r\n if basis.x == 0.0 && basis.y == 0.0 && basis.z == 0.0 && basis.w == 0.0 {\r\n output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output;\r\n }\r\n\r\n let maxExtentPixels = max(length(basis.xy), length(basis.zw));\r\n let pixelToClip = 2.0 * vec2<f32>(clipPos.w, clipPos.w) / uniforms.screenSize;\r\n let splatExtentClip = vec2<f32>(maxExtentPixels, maxExtentPixels) * pixelToClip;\r\n if any((abs(clipPos.xy) - splatExtentClip) > vec2<f32>(clipPos.w, clipPos.w)) {\r\n output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output;\r\n }\r\n\r\n let clipFactor = computeClipFactor(adjustedOpacity);\r\n if clipFactor <= 0.0 { output.position = vec4<f32>(0.0, 0.0, 2.0, 1.0); return output; }\r\n\r\n let basisViewport = vec2<f32>(1.0 / uniforms.screenSize.x, 1.0 / uniforms.screenSize.y);\r\n let basisVector1 = basis.xy * clipFactor;\r\n let basisVector2 = basis.zw * clipFactor;\r\n let ndcOffset = (quadPos.x * basisVector1 + quadPos.y * basisVector2) * basisViewport * 2.0;\r\n output.position = vec4<f32>(ndcPos.xy + ndcOffset, ndcPos.z, 1.0);\r\n\r\n output.fragPos = quadPos * clipFactor;\r\n output.opacity = adjustedOpacity;\r\n output.viewDepth = -viewPos.z;\r\n\r\n // Normal from shortest ellipsoid axis, oriented toward camera\r\n var normal = computeSplatNormal(splat.scale, splat.rotation, uniforms.model);\r\n let toCamera = uniforms.cameraPos - worldPos.xyz;\r\n if dot(normal, toCamera) < 0.0 {\r\n normal = -normal;\r\n }\r\n output.worldNormal = normal;\r\n return output;\r\n}\r\n\r\nstruct FragOutput {\r\n @location(0) depthOut: vec4<f32>,\r\n @location(1) normalOut: vec4<f32>,\r\n}\r\n\r\n@fragment\r\nfn fs_depth_normal(input: VertexOutput) -> FragOutput {\r\n if input.opacity <= 0.0 { discard; }\r\n let A = dot(input.fragPos, input.fragPos);\r\n if A > 1.0 { discard; }\r\n let weight = (exp(-GAUSSIAN_K * A) - EXP_NEG_K) * INV_ONE_MINUS_EXP_NEG_K;\r\n let opacity = weight * input.opacity;\r\n if opacity < ALPHA_CULL_THRESHOLD { discard; }\r\n\r\n var out: FragOutput;\r\n // RT0: depth + opacity — RGB blend 1·src+(1-α)·dst accumulates depth, Alpha blend 0·src+(1-α)·dst accumulates transmittance\r\n out.depthOut = vec4<f32>(input.viewDepth * opacity, 0.0, 0.0, opacity);\r\n // RT1: normal — same blend, RGB accumulates weighted normal, Alpha accumulates transmittance\r\n out.normalOut = vec4<f32>(input.worldNormal * opacity, opacity);\r\n return out;\r\n}\r\n`;\r\n\r\nconst SPLAT_BYTE_SIZE = 256;\r\nconst SPLAT_FLOAT_COUNT = 64;\r\n\r\n/**\r\n * GSSplatRendererV2 - 优化的渲染器\r\n */\r\nexport class GSSplatRenderer implements IGSSplatRendererWithCapabilities {\r\n private renderer: Renderer;\r\n private camera: Camera;\r\n\r\n private pipeline!: GPURenderPipeline;\r\n private bindGroupLayout!: GPUBindGroupLayout;\r\n private uniformBuffer!: GPUBuffer;\r\n\r\n private splatBuffer: GPUBuffer | null = null;\r\n private splatCount: number = 0;\r\n private bindGroup: GPUBindGroup | null = null;\r\n\r\n private sorter: GSSplatSorter | null = null;\r\n private shMode: SHMode = SHMode.L3;\r\n private boundingBox: BoundingBox | null = null;\r\n private cpuPositions: Float32Array | null = null;\r\n\r\n // Transform\r\n private position: Vec3Tuple = [0, 0, 0];\r\n private rotation: Vec3Tuple = [0, 0, 0];\r\n private scale: Vec3Tuple = [1, 1, 1];\r\n private pivot: Vec3Tuple = [0, 0, 0];\r\n private modelMatrix: Float32Array = new Float32Array(16);\r\n\r\n // 剔除选项\r\n private pixelCullThreshold: number = 1.0;\r\n private maxVisibleSplats: number = 0;\r\n\r\n // 排序优化:相机变化检测 + 频率控制\r\n private lastSortViewMatrix: Float32Array = new Float32Array(16);\r\n private lastSortProjMatrix: Float32Array = new Float32Array(16);\r\n private lastSortModelMatrix: Float32Array = new Float32Array(16);\r\n private lastSortWidth: number = 0;\r\n private lastSortHeight: number = 0;\r\n private lastSortPixelThreshold: number = -1;\r\n private lastSortMaxVisible: number = -1;\r\n private sortStateInitialized: boolean = false;\r\n private sortFrequency: number = 1;\r\n private frameCounter: number = 0;\r\n\r\n // 深度法线Pass依赖资源\r\n private depthNormalPipeline: GPURenderPipeline | null = null;\r\n private depthRT: GPUTexture | null = null;\r\n private depthRTView: GPUTextureView | null = null;\r\n private normalRT: GPUTexture | null = null;\r\n private normalRTView: GPUTextureView | null = null;\r\n private dnRTWidth: number = 0;\r\n private dnRTHeight: number = 0;\r\n\r\n // 这一帧的深度法线回读结果,返回指定像素的3*3区域的深度值和法线\r\n private dnResult: {\r\n raw: Uint16Array; vm: Float32Array; proj: Float32Array; cam: Float32Array;\r\n w: number; h: number; px: number; py: number;\r\n // actual copied region (clipped to texture bounds)\r\n copyX: number; copyY: number; copyW: number; copyH: number;\r\n // offset of centre pixel within the copied region\r\n cx: number; cy: number;\r\n } | null = null;\r\n\r\n constructor(renderer: Renderer, camera: Camera) {\r\n this.renderer = renderer;\r\n this.camera = camera;\r\n this.createPipeline();\r\n this.createUniformBuffer();\r\n this.updateModelMatrix();\r\n }\r\n\r\n private createPipeline(): void {\r\n const device = this.renderer.device;\r\n\r\n const shaderModule = device.createShaderModule({\r\n code: gsOptimizedShader,\r\n });\r\n\r\n this.bindGroupLayout = device.createBindGroupLayout({\r\n entries: [\r\n {\r\n binding: 0,\r\n visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,\r\n buffer: { type: \"uniform\" },\r\n },\r\n {\r\n binding: 1,\r\n visibility: GPUShaderStage.VERTEX,\r\n buffer: { type: \"read-only-storage\" },\r\n },\r\n {\r\n binding: 2,\r\n visibility: GPUShaderStage.VERTEX,\r\n buffer: { type: \"read-only-storage\" },\r\n },\r\n ],\r\n });\r\n\r\n const pipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [this.bindGroupLayout],\r\n });\r\n\r\n this.pipeline = device.createRenderPipeline({\r\n layout: pipelineLayout,\r\n vertex: {\r\n module: shaderModule,\r\n entryPoint: \"vs_main\",\r\n buffers: [],\r\n },\r\n fragment: {\r\n module: shaderModule,\r\n entryPoint: \"fs_main\",\r\n targets: [\r\n {\r\n format: this.renderer.format,\r\n blend: {\r\n color: {\r\n srcFactor: \"one\",\r\n dstFactor: \"one-minus-src-alpha\",\r\n operation: \"add\",\r\n },\r\n alpha: {\r\n srcFactor: \"one\",\r\n dstFactor: \"one-minus-src-alpha\",\r\n operation: \"add\",\r\n },\r\n },\r\n },\r\n ],\r\n },\r\n primitive: {\r\n topology: \"triangle-strip\",\r\n },\r\n depthStencil: {\r\n format: this.renderer.depthFormat,\r\n depthWriteEnabled: true,\r\n depthCompare: \"always\",\r\n },\r\n });\r\n }\r\n\r\n private createUniformBuffer(): void {\r\n // view (64) + proj (64) + model (64) + cameraPos (12) + pad (4) + screenSize (8) + pad (8) = 224\r\n this.uniformBuffer = this.renderer.device.createBuffer({\r\n size: 224,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n }\r\n\r\n // 创建深度和法线渲染管线,这个管线用于渲染深度和法线信息,用于后续的拾取操作\r\n // RGB采用\"one add one-minus-src-alpha\"的混合模式对深度和法线做AlphaBlending\r\n // A采用\"zero add one-minus-src-alpha\"的混合模式计算Transmittance\r\n private createDepthNormalPipeline(): void {\r\n const device = this.renderer.device;\r\n const shaderModule = device.createShaderModule({ code: gsDepthNormalShader });\r\n const pipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [this.bindGroupLayout],\r\n });\r\n this.depthNormalPipeline = device.createRenderPipeline({\r\n layout: pipelineLayout,\r\n vertex: {\r\n module: shaderModule,\r\n entryPoint: \"vs_main\",\r\n buffers: [],\r\n },\r\n fragment: {\r\n module: shaderModule,\r\n entryPoint: \"fs_depth_normal\",\r\n targets: [\r\n {\r\n format: \"rgba16float\" as GPUTextureFormat,\r\n blend: {\r\n color: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\r\n alpha: { srcFactor: \"zero\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\r\n },\r\n },\r\n {\r\n format: \"rgba16float\" as GPUTextureFormat,\r\n blend: {\r\n color: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\r\n alpha: { srcFactor: \"zero\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\r\n },\r\n },\r\n ],\r\n },\r\n primitive: { topology: \"triangle-strip\" },\r\n });\r\n }\r\n\r\n private ensureDepthNormalTextures(w: number, h: number): void {\r\n if (this.depthRT && this.dnRTWidth === w && this.dnRTHeight === h) return;\r\n const device = this.renderer.device;\r\n if (this.depthRT) this.depthRT.destroy();\r\n if (this.normalRT) this.normalRT.destroy();\r\n this.depthRT = device.createTexture({\r\n size: { width: w, height: h },\r\n format: \"rgba16float\",\r\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,\r\n });\r\n this.depthRTView = this.depthRT.createView();\r\n this.normalRT = device.createTexture({\r\n size: { width: w, height: h },\r\n format: \"rgba16float\",\r\n usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,\r\n });\r\n this.normalRTView = this.normalRT.createView();\r\n this.dnRTWidth = w;\r\n this.dnRTHeight = h;\r\n }\r\n\r\n setPosition(x: number, y: number, z: number): void {\r\n this.position = [x, y, z];\r\n this.updateModelMatrix();\r\n }\r\n\r\n getPosition(): Vec3Tuple {\r\n return [...this.position];\r\n }\r\n\r\n setRotation(x: number, y: number, z: number): void {\r\n this.rotation = [x, y, z];\r\n this.updateModelMatrix();\r\n }\r\n\r\n getRotation(): Vec3Tuple {\r\n return [...this.rotation];\r\n }\r\n\r\n setScale(x: number, y: number, z: number): void {\r\n this.scale = [x, y, z];\r\n this.updateModelMatrix();\r\n }\r\n\r\n getScale(): Vec3Tuple {\r\n return [...this.scale];\r\n }\r\n\r\n setPivot(x: number, y: number, z: number): void {\r\n this.pivot = [x, y, z];\r\n this.updateModelMatrix();\r\n }\r\n\r\n getPivot(): Vec3Tuple {\r\n return [...this.pivot];\r\n }\r\n\r\n private updateModelMatrix(): void {\r\n const [tx, ty, tz] = this.position;\r\n const [rx, ry, rz] = this.rotation;\r\n const [sx, sy, sz] = this.scale;\r\n const [px, py, pz] = this.pivot;\r\n\r\n const cx = Math.cos(rx),\r\n sx1 = Math.sin(rx);\r\n const cy = Math.cos(ry),\r\n sy1 = Math.sin(ry);\r\n const cz = Math.cos(rz),\r\n sz1 = Math.sin(rz);\r\n\r\n const r00 = cy * cz;\r\n const r01 = sx1 * sy1 * cz - cx * sz1;\r\n const r02 = cx * sy1 * cz + sx1 * sz1;\r\n const r10 = cy * sz1;\r\n const r11 = sx1 * sy1 * sz1 + cx * cz;\r\n const r12 = cx * sy1 * sz1 - sx1 * cz;\r\n const r20 = -sy1;\r\n const r21 = sx1 * cy;\r\n const r22 = cx * cy;\r\n\r\n const rs00 = r00 * sx,\r\n rs01 = r01 * sy,\r\n rs02 = r02 * sz;\r\n const rs10 = r10 * sx,\r\n rs11 = r11 * sy,\r\n rs12 = r12 * sz;\r\n const rs20 = r20 * sx,\r\n rs21 = r21 * sy,\r\n rs22 = r22 * sz;\r\n\r\n const dpx = px - (rs00 * px + rs01 * py + rs02 * pz);\r\n const dpy = py - (rs10 * px + rs11 * py + rs12 * pz);\r\n const dpz = pz - (rs20 * px + rs21 * py + rs22 * pz);\r\n\r\n const finalTx = tx + dpx;\r\n const finalTy = ty + dpy;\r\n const finalTz = tz + dpz;\r\n\r\n this.modelMatrix[0] = rs00;\r\n this.modelMatrix[1] = rs10;\r\n this.modelMatrix[2] = rs20;\r\n this.modelMatrix[3] = 0;\r\n this.modelMatrix[4] = rs01;\r\n this.modelMatrix[5] = rs11;\r\n this.modelMatrix[6] = rs21;\r\n this.modelMatrix[7] = 0;\r\n this.modelMatrix[8] = rs02;\r\n this.modelMatrix[9] = rs12;\r\n this.modelMatrix[10] = rs22;\r\n this.modelMatrix[11] = 0;\r\n this.modelMatrix[12] = finalTx;\r\n this.modelMatrix[13] = finalTy;\r\n this.modelMatrix[14] = finalTz;\r\n this.modelMatrix[15] = 1;\r\n }\r\n\r\n getModelMatrix(): Float32Array {\r\n return this.modelMatrix;\r\n }\r\n\r\n setSHMode(mode: SHMode): void {\r\n this.shMode = mode;\r\n }\r\n\r\n getSHMode(): SHMode {\r\n return this.shMode;\r\n }\r\n\r\n setPixelCullThreshold(threshold: number): void {\r\n this.pixelCullThreshold = threshold;\r\n }\r\n\r\n /**\r\n * 设置最大可见 splat 数量\r\n * 排序后只保留距离最近的 N 个 splat,远处被遮挡的 splat 被丢弃\r\n * 0 = 不限制\r\n */\r\n setMaxVisibleSplats(count: number): void {\r\n this.maxVisibleSplats = count;\r\n }\r\n\r\n getMaxVisibleSplats(): number {\r\n return this.maxVisibleSplats;\r\n }\r\n\r\n /**\r\n * 设置排序频率\r\n * 1 = 每帧排序(默认),2 = 每 2 帧排序一次,以此类推\r\n * 相机静止时自动跳过排序,不受此参数影响\r\n */\r\n setSortFrequency(frequency: number): void {\r\n this.sortFrequency = Math.max(1, Math.round(frequency));\r\n }\r\n\r\n getSortFrequency(): number {\r\n return this.sortFrequency;\r\n }\r\n\r\n private needsSort(): boolean {\r\n const view = this.camera.viewMatrix;\r\n const proj = this.camera.projectionMatrix;\r\n const model = this.modelMatrix;\r\n const w = this.renderer.width;\r\n const h = this.renderer.height;\r\n\r\n if (!this.sortStateInitialized ||\r\n w !== this.lastSortWidth || h !== this.lastSortHeight ||\r\n this.pixelCullThreshold !== this.lastSortPixelThreshold ||\r\n this.maxVisibleSplats !== this.lastSortMaxVisible) {\r\n this.saveSortState(view, proj, model, w, h);\r\n return true;\r\n }\r\n\r\n for (let i = 0; i < 16; i++) {\r\n if (view[i] !== this.lastSortViewMatrix[i] ||\r\n proj[i] !== this.lastSortProjMatrix[i] ||\r\n model[i] !== this.lastSortModelMatrix[i]) {\r\n this.saveSortState(view, proj, model, w, h);\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n }\r\n\r\n private saveSortState(\r\n view: Float32Array, proj: Float32Array, model: Float32Array,\r\n w: number, h: number,\r\n ): void {\r\n this.lastSortViewMatrix.set(view);\r\n this.lastSortProjMatrix.set(proj);\r\n this.lastSortModelMatrix.set(model);\r\n this.lastSortWidth = w;\r\n this.lastSortHeight = h;\r\n this.lastSortPixelThreshold = this.pixelCullThreshold;\r\n this.lastSortMaxVisible = this.maxVisibleSplats;\r\n this.sortStateInitialized = true;\r\n }\r\n\r\n setData(splats: SplatCPU[]): void {\r\n const device = this.renderer.device;\r\n\r\n if (this.splatBuffer) {\r\n this.splatBuffer.destroy();\r\n }\r\n if (this.sorter) {\r\n this.sorter.destroy();\r\n this.sorter = null;\r\n }\r\n\r\n this.splatCount = splats.length;\r\n\r\n if (this.splatCount === 0) {\r\n this.splatBuffer = null;\r\n this.bindGroup = null;\r\n this.boundingBox = null;\r\n return;\r\n }\r\n\r\n this.boundingBox = this.computeBoundingBox(splats);\r\n\r\n const positions = new Float32Array(this.splatCount * 3);\r\n const data = new Float32Array(this.splatCount * SPLAT_FLOAT_COUNT);\r\n\r\n for (let i = 0; i < this.splatCount; i++) {\r\n const splat = splats[i];\r\n const offset = i * SPLAT_FLOAT_COUNT;\r\n\r\n positions[i * 3 + 0] = splat.mean[0];\r\n positions[i * 3 + 1] = splat.mean[1];\r\n positions[i * 3 + 2] = splat.mean[2];\r\n\r\n data[offset + 0] = splat.mean[0];\r\n data[offset + 1] = splat.mean[1];\r\n data[offset + 2] = splat.mean[2];\r\n data[offset + 3] = 0;\r\n\r\n data[offset + 4] = splat.scale[0];\r\n data[offset + 5] = splat.scale[1];\r\n data[offset + 6] = splat.scale[2];\r\n data[offset + 7] = 0;\r\n\r\n data[offset + 8] = splat.rotation[0];\r\n data[offset + 9] = splat.rotation[1];\r\n data[offset + 10] = splat.rotation[2];\r\n data[offset + 11] = splat.rotation[3];\r\n\r\n data[offset + 12] = splat.colorDC[0];\r\n data[offset + 13] = splat.colorDC[1];\r\n data[offset + 14] = splat.colorDC[2];\r\n data[offset + 15] = splat.opacity;\r\n\r\n const shRest = splat.shRest;\r\n for (let j = 0; j < 9; j++) {\r\n data[offset + 16 + j] = shRest ? shRest[j] : 0;\r\n }\r\n for (let j = 0; j < 15; j++) {\r\n data[offset + 25 + j] = shRest ? shRest[9 + j] : 0;\r\n }\r\n for (let j = 0; j < 21; j++) {\r\n data[offset + 40 + j] = shRest ? shRest[24 + j] : 0;\r\n }\r\n data[offset + 61] = 0;\r\n data[offset + 62] = 0;\r\n data[offset + 63] = 0;\r\n }\r\n\r\n this.splatBuffer = device.createBuffer({\r\n size: data.byteLength,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n });\r\n\r\n device.queue.writeBuffer(this.splatBuffer, 0, data);\r\n this.cpuPositions = positions;\r\n\r\n this.sorter = new GSSplatSorter(\r\n device,\r\n this.splatCount,\r\n this.splatBuffer,\r\n this.uniformBuffer,\r\n );\r\n\r\n this.sorter.setScreenSize(this.renderer.width, this.renderer.height);\r\n this.sorter.setCullingOptions({\r\n nearPlane: this.camera.near,\r\n farPlane: this.camera.far,\r\n pixelThreshold: this.pixelCullThreshold,\r\n });\r\n\r\n this.bindGroup = device.createBindGroup({\r\n layout: this.bindGroupLayout,\r\n entries: [\r\n { binding: 0, resource: { buffer: this.uniformBuffer } },\r\n { binding: 1, resource: { buffer: this.splatBuffer } },\r\n { binding: 2, resource: { buffer: this.sorter.getIndicesBuffer() } },\r\n ],\r\n });\r\n }\r\n\r\n setCompactData(compactData: CompactSplatData): void {\r\n const device = this.renderer.device;\r\n\r\n if (this.splatBuffer) {\r\n this.splatBuffer.destroy();\r\n }\r\n if (this.sorter) {\r\n this.sorter.destroy();\r\n this.sorter = null;\r\n }\r\n\r\n this.splatCount = compactData.count;\r\n\r\n if (this.splatCount === 0) {\r\n this.splatBuffer = null;\r\n this.bindGroup = null;\r\n this.boundingBox = null;\r\n return;\r\n }\r\n\r\n this.boundingBox = this.computeBoundingBoxFromCompact(compactData);\r\n this.cpuPositions = new Float32Array(compactData.positions);\r\n\r\n const includeSH = compactData.shCoeffs !== undefined;\r\n const gpuData = compactDataToGPUBuffer(compactData, includeSH);\r\n\r\n this.splatBuffer = device.createBuffer({\r\n size: gpuData.byteLength,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n });\r\n\r\n device.queue.writeBuffer(this.splatBuffer, 0, gpuData.buffer);\r\n\r\n this.sorter = new GSSplatSorter(\r\n device,\r\n this.splatCount,\r\n this.splatBuffer,\r\n this.uniformBuffer,\r\n );\r\n\r\n this.sorter.setScreenSize(this.renderer.width, this.renderer.height);\r\n this.sorter.setCullingOptions({\r\n nearPlane: this.camera.near,\r\n farPlane: this.camera.far,\r\n pixelThreshold: this.pixelCullThreshold,\r\n });\r\n\r\n this.bindGroup = device.createBindGroup({\r\n layout: this.bindGroupLayout,\r\n entries: [\r\n { binding: 0, resource: { buffer: this.uniformBuffer } },\r\n { binding: 1, resource: { buffer: this.splatBuffer } },\r\n { binding: 2, resource: { buffer: this.sorter.getIndicesBuffer() } },\r\n ],\r\n });\r\n }\r\n\r\n render(pass: GPURenderPassEncoder): void {\r\n if (this.splatCount === 0 || !this.bindGroup || !this.sorter) {\r\n return;\r\n }\r\n\r\n // 更新 uniforms\r\n this.renderer.device.queue.writeBuffer(\r\n this.uniformBuffer,\r\n 0,\r\n new Float32Array(this.camera.viewMatrix),\r\n );\r\n this.renderer.device.queue.writeBuffer(\r\n this.uniformBuffer,\r\n 64,\r\n new Float32Array(this.camera.projectionMatrix),\r\n );\r\n this.renderer.device.queue.writeBuffer(\r\n this.uniformBuffer,\r\n 128,\r\n new Float32Array(this.modelMatrix),\r\n );\r\n this.renderer.device.queue.writeBuffer(\r\n this.uniformBuffer,\r\n 192,\r\n new Float32Array(this.camera.position),\r\n );\r\n this.renderer.device.queue.writeBuffer(\r\n this.uniformBuffer,\r\n 208,\r\n new Float32Array([this.renderer.width, this.renderer.height, 0, 0]),\r\n );\r\n\r\n // 排序优化:仅在相机/参数变化时排序,并支持隔帧排序\r\n const changed = this.needsSort();\r\n this.frameCounter++;\r\n\r\n const shouldSort = changed || (\r\n this.sortFrequency > 1 && this.frameCounter % this.sortFrequency === 0\r\n );\r\n\r\n if (shouldSort) {\r\n this.sorter.setScreenSize(this.renderer.width, this.renderer.height);\r\n this.sorter.setCullingOptions({\r\n nearPlane: this.camera.near,\r\n farPlane: this.camera.far,\r\n pixelThreshold: this.pixelCullThreshold,\r\n maxVisibleCount: this.maxVisibleSplats,\r\n });\r\n\r\n this.sorter.sort();\r\n }\r\n\r\n // 渲染\r\n pass.setPipeline(this.pipeline);\r\n pass.setBindGroup(0, this.bindGroup);\r\n pass.drawIndirect(this.sorter.getDrawIndirectBuffer(), 0);\r\n }\r\n\r\n getSplatCount(): number {\r\n return this.splatCount;\r\n }\r\n\r\n getBoundingBox(): BoundingBox | null {\r\n return this.boundingBox;\r\n }\r\n\r\n getCPUPositions(): Float32Array | null {\r\n return this.cpuPositions;\r\n }\r\n\r\n private computeBoundingBox(splats: SplatCPU[]): BoundingBox {\r\n if (splats.length === 0) {\r\n return { min: [0, 0, 0], max: [0, 0, 0], center: [0, 0, 0], radius: 0 };\r\n }\r\n\r\n const min: Vec3Tuple = [\r\n splats[0].mean[0],\r\n splats[0].mean[1],\r\n splats[0].mean[2],\r\n ];\r\n const max: Vec3Tuple = [\r\n splats[0].mean[0],\r\n splats[0].mean[1],\r\n splats[0].mean[2],\r\n ];\r\n\r\n for (let i = 1; i < splats.length; i++) {\r\n const [x, y, z] = splats[i].mean;\r\n min[0] = Math.min(min[0], x);\r\n min[1] = Math.min(min[1], y);\r\n min[2] = Math.min(min[2], z);\r\n max[0] = Math.max(max[0], x);\r\n max[1] = Math.max(max[1], y);\r\n max[2] = Math.max(max[2], z);\r\n }\r\n\r\n const center: Vec3Tuple = [\r\n (min[0] + max[0]) / 2,\r\n (min[1] + max[1]) / 2,\r\n (min[2] + max[2]) / 2,\r\n ];\r\n\r\n const dx = max[0] - min[0];\r\n const dy = max[1] - min[1];\r\n const dz = max[2] - min[2];\r\n const radius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min, max, center, radius };\r\n }\r\n\r\n private computeBoundingBoxFromCompact(data: CompactSplatData): BoundingBox {\r\n if (data.count === 0) {\r\n return { min: [0, 0, 0], max: [0, 0, 0], center: [0, 0, 0], radius: 0 };\r\n }\r\n\r\n const positions = data.positions;\r\n const min: Vec3Tuple = [positions[0], positions[1], positions[2]];\r\n const max: Vec3Tuple = [positions[0], positions[1], positions[2]];\r\n\r\n for (let i = 1; i < data.count; i++) {\r\n const x = positions[i * 3 + 0];\r\n const y = positions[i * 3 + 1];\r\n const z = positions[i * 3 + 2];\r\n min[0] = Math.min(min[0], x);\r\n min[1] = Math.min(min[1], y);\r\n min[2] = Math.min(min[2], z);\r\n max[0] = Math.max(max[0], x);\r\n max[1] = Math.max(max[1], y);\r\n max[2] = Math.max(max[2], z);\r\n }\r\n\r\n const center: Vec3Tuple = [\r\n (min[0] + max[0]) / 2,\r\n (min[1] + max[1]) / 2,\r\n (min[2] + max[2]) / 2,\r\n ];\r\n\r\n const dx = max[0] - min[0];\r\n const dy = max[1] - min[1];\r\n const dz = max[2] - min[2];\r\n const radius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min, max, center, radius };\r\n }\r\n\r\n // 1、提交深度和法线渲染Pass;\r\n // 2、如果px和py不为-1,则表示需要回读指定像素周围3*3区域的深度和法线信息,这一帧的回读结果保存在dnResult中,下一帧可以获取\r\n prepareDepthNormalPass(px: number = -1, py: number = -1): void {\r\n if (this.splatCount === 0 || !this.bindGroup || !this.sorter) return;\r\n if (!this.depthNormalPipeline) this.createDepthNormalPipeline();\r\n\r\n const w = this.renderer.width;\r\n const h = this.renderer.height;\r\n this.ensureDepthNormalTextures(w, h);\r\n\r\n const device = this.renderer.device;\r\n const encoder = device.createCommandEncoder({ label: \"depth-normal-encoder\" });\r\n\r\n // 1. Render depth-normal pass\r\n const pass = encoder.beginRenderPass({\r\n colorAttachments: [\r\n {\r\n view: this.depthRTView!,\r\n clearValue: { r: 0, g: 0, b: 0, a: 1 },\r\n loadOp: \"clear\" as GPULoadOp,\r\n storeOp: \"store\" as GPUStoreOp,\r\n },\r\n {\r\n view: this.normalRTView!,\r\n clearValue: { r: 0, g: 0, b: 0, a: 1 },\r\n loadOp: \"clear\" as GPULoadOp,\r\n storeOp: \"store\" as GPUStoreOp,\r\n },\r\n ],\r\n });\r\n pass.setPipeline(this.depthNormalPipeline!);\r\n pass.setBindGroup(0, this.bindGroup);\r\n pass.drawIndirect(this.sorter.getDrawIndirectBuffer(), 0);\r\n pass.end();\r\n\r\n // 2. If a pixel was requested, copy a 3×3 neighbourhood for robust normal averaging\r\n const ipx = Math.floor(px);\r\n const ipy = Math.floor(py);\r\n\r\n if (ipx >= 0 && ipx < w && ipy >= 0 && ipy < h) {\r\n const x0 = Math.max(0, ipx - 1);\r\n const y0 = Math.max(0, ipy - 1);\r\n const x1 = Math.min(w, ipx + 2); // exclusive\r\n const y1 = Math.min(h, ipy + 2); // exclusive\r\n const copyW = x1 - x0;\r\n const copyH = y1 - y0;\r\n const cx = ipx - x0;\r\n const cy = ipy - y0;\r\n\r\n // 3*3像素区域,每个像素对应RGBA8个字节/4个uint16,这里每行考虑256的对齐字节\r\n const rawBytesPerRow = copyW * 8;\r\n const bytesPerRow = Math.ceil(rawBytesPerRow / 256) * 256;\r\n const sliceBytes = bytesPerRow * copyH;\r\n const buf = device.createBuffer({\r\n size: sliceBytes * 2, // two RT slices (depth + normal)\r\n usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,\r\n });\r\n encoder.copyTextureToBuffer(\r\n { texture: this.depthRT!, origin: { x: x0, y: y0 } },\r\n { buffer: buf, offset: 0, bytesPerRow },\r\n { width: copyW, height: copyH },\r\n );\r\n encoder.copyTextureToBuffer(\r\n { texture: this.normalRT!, origin: { x: x0, y: y0 } },\r\n { buffer: buf, offset: sliceBytes, bytesPerRow },\r\n { width: copyW, height: copyH },\r\n );\r\n device.queue.submit([encoder.finish()]);\r\n\r\n const vm = new Float32Array(this.camera.viewMatrix);\r\n const proj = new Float32Array(this.camera.projectionMatrix);\r\n const cam = new Float32Array(this.camera.position);\r\n\r\n buf.mapAsync(GPUMapMode.READ).then(() => {\r\n const raw = new Uint16Array(buf.getMappedRange().slice(0));\r\n buf.unmap();\r\n buf.destroy();\r\n this.dnResult = { raw, vm, proj, cam, w, h, px: ipx, py: ipy, copyX: x0, copyY: y0, copyW, copyH, cx, cy };\r\n }).catch(() => {\r\n buf.destroy();\r\n });\r\n } else {\r\n device.queue.submit([encoder.finish()]);\r\n }\r\n }\r\n\r\n private static half2Float(h: number): number {\r\n const sign = (h & 0x8000) << 16;\r\n const exponent = (h & 0x7C00) >> 10;\r\n const mantissa = h & 0x03FF;\r\n\r\n if (exponent === 0) {\r\n if (mantissa === 0) {\r\n GSSplatRenderer._f32[0] = 0;\r\n return sign ? -0 : 0;\r\n }\r\n let e = -1;\r\n let m = mantissa;\r\n do { e++; m <<= 1; } while ((m & 0x0400) === 0);\r\n GSSplatRenderer._u32[0] = sign | ((127 - 15 - e) << 23) | ((m & 0x03FF) << 13);\r\n } else if (exponent === 31) {\r\n GSSplatRenderer._u32[0] = sign | 0x7F800000 | (mantissa << 13);\r\n } else {\r\n GSSplatRenderer._u32[0] = sign | ((exponent + 127 - 15) << 23) | (mantissa << 13);\r\n }\r\n return GSSplatRenderer._f32[0];\r\n }\r\n private static _f32 = new Float32Array(1);\r\n private static _u32 = new Uint32Array(GSSplatRenderer._f32.buffer);\r\n\r\n // 通过上一帧的回读结果dnResult,获取深度和法线信息\r\n // 世界位置通过当前像素以及对应深度反向投影计算\r\n // 世界法线使用3×3邻域直接平均以降低噪声敏感度\r\n getDepthNormal(): { depth: number; normal: Vec3Tuple; worldPos: Vec3Tuple } | null {\r\n if (!this.dnResult) return null;\r\n\r\n const { raw, vm, proj, cam, w, h, px, py, copyW, copyH, cx, cy } = this.dnResult;\r\n const rawBytesPerRow = copyW * 8;\r\n const bytesPerRow = Math.ceil(rawBytesPerRow / 256) * 256;\r\n const u16PerRow = bytesPerRow / 2;\r\n const sliceU16 = u16PerRow * copyH;\r\n const h2f = GSSplatRenderer.half2Float;\r\n\r\n // --- centre pixel: depth from RT0 ---\r\n const cOff = cy * u16PerRow + cx * 4;\r\n const accumDepth = h2f(raw[cOff + 0]);\r\n const transmittance = h2f(raw[cOff + 3]);\r\n\r\n const alpha = 1.0 - transmittance;\r\n if (alpha < 1e-6) return null;\r\n // 当前像素的视角深度\r\n const viewDepth = accumDepth / alpha;\r\n\r\n // --- 3×3 direct average normal from RT1 ---\r\n // 这里平均3*3邻域的法线\r\n let snx = 0, sny = 0, snz = 0;\r\n\r\n for (let ky = 0; ky < 3; ky++) {\r\n const ry = cy + ky - 1;\r\n if (ry < 0 || ry >= copyH) continue;\r\n for (let kx = 0; kx < 3; kx++) {\r\n const rx = cx + kx - 1;\r\n if (rx < 0 || rx >= copyW) continue;\r\n\r\n const off = sliceU16 + ry * u16PerRow + rx * 4;\r\n const a = 1.0 - h2f(raw[off + 3]);\r\n if (a < 1e-6) continue;\r\n\r\n snx += h2f(raw[off + 0]) / a;\r\n sny += h2f(raw[off + 1]) / a;\r\n snz += h2f(raw[off + 2]) / a;\r\n }\r\n }\r\n\r\n let nx = snx, ny = sny, nz = snz;\r\n const nLen = Math.sqrt(nx * nx + ny * ny + nz * nz);\r\n if (nLen > 1e-8) {\r\n nx /= nLen; ny /= nLen; nz /= nLen;\r\n } else {\r\n nx = 0; ny = 1; nz = 0;\r\n }\r\n\r\n // --- world position from centre pixel depth ---\r\n // 通过像素计算视角位置,转到世界空间\r\n const ndcX = (px + 0.5) / w * 2.0 - 1.0;\r\n const ndcY = 1.0 - (py + 0.5) / h * 2.0;\r\n const viewX = ndcX * viewDepth / proj[0];\r\n const viewY = ndcY * viewDepth / proj[5];\r\n const viewZ = -viewDepth;\r\n\r\n const wx = vm[0] * viewX + vm[1] * viewY + vm[2] * viewZ + cam[0];\r\n const wy = vm[4] * viewX + vm[5] * viewY + vm[6] * viewZ + cam[1];\r\n const wz = vm[8] * viewX + vm[9] * viewY + vm[10] * viewZ + cam[2];\r\n\r\n // 法线方向判断\r\n const toCamX = cam[0] - wx;\r\n const toCamY = cam[1] - wy;\r\n const toCamZ = cam[2] - wz;\r\n if (nx * toCamX + ny * toCamY + nz * toCamZ < 0) {\r\n nx = -nx; ny = -ny; nz = -nz;\r\n }\r\n\r\n return {\r\n depth: viewDepth,\r\n normal: [nx, ny, nz],\r\n worldPos: [wx, wy, wz],\r\n };\r\n }\r\n\r\n supportsSHMode(mode: SHMode): boolean {\r\n return mode >= SHMode.L0 && mode <= SHMode.L3;\r\n }\r\n\r\n getCapabilities(): RendererCapabilities {\r\n return {\r\n maxSHMode: SHMode.L3,\r\n supportsRawData: true,\r\n isMobileOptimized: false,\r\n maxSplatCount: 0,\r\n };\r\n }\r\n\r\n destroy(): void {\r\n if (this.splatBuffer) {\r\n this.splatBuffer.destroy();\r\n this.splatBuffer = null;\r\n }\r\n if (this.sorter) {\r\n this.sorter.destroy();\r\n this.sorter = null;\r\n }\r\n if (this.depthRT) { this.depthRT.destroy(); this.depthRT = null; }\r\n if (this.normalRT) { this.normalRT.destroy(); this.normalRT = null; }\r\n this.dnResult = null;\r\n this.uniformBuffer.destroy();\r\n this.splatCount = 0;\r\n this.bindGroup = null;\r\n this.depthNormalPipeline = null;\r\n }\r\n}\r\n","/**\n * TextureCompressor - 移动端纹理压缩工具\n * 将 splat 数据压缩为纹理格式,大幅减少 GPU 内存占用\n *\n * 内存对比:\n * - 原始 Storage Buffer: 256 bytes/splat\n * - 纹理压缩: ~52 bytes/splat (约 5x 压缩)\n * \n * 数据布局(保证精度):\n * - positionTexture (RGBA32Float): x, y, z, unused - 16 bytes\n * - scaleRotTexture1 (RGBA32Float): scale_x, scale_y, scale_z, rot_w - 16 bytes\n * - scaleRotTexture2 (RGBA32Float): rot_x, rot_y, rot_z, unused - 16 bytes\n * - colorTexture (RGBA8Unorm): r, g, b, opacity - 4 bytes\n * 总计: 52 bytes/splat\n * \n * 注意:使用 RGBA32Float 替代 RGBA16Float 以保证 scale 和 rotation 的精度,\n * 避免平面等细节渲染出现块状伪影。\n */\n\nimport { CompactSplatData } from \"./PLYLoaderMobile\";\n\n/**\n * 压缩后的纹理数据\n */\nexport interface CompressedSplatTextures {\n // 纹理尺寸\n width: number;\n height: number;\n count: number;\n\n // 位置纹理 (RGBA32Float) - 完整精度\n positionTexture: GPUTexture;\n\n // 缩放+旋转纹理 (RGBA32Float) - 保证精度\n // R: scale_x, G: scale_y, B: scale_z, A: rot_w\n scaleRotTexture1: GPUTexture;\n // R: rot_x, G: rot_y, B: rot_z, A: unused\n scaleRotTexture2: GPUTexture;\n\n // 颜色+不透明度纹理 (RGBA8Unorm)\n // R: color_r, G: color_g, B: color_b, A: opacity\n colorTexture: GPUTexture;\n\n // Bounding box (用于剔除优化)\n boundingBox: {\n min: [number, number, number];\n max: [number, number, number];\n };\n}\n\n/**\n * 计算纹理尺寸\n * 将 splat 数量映射到 2D 纹理尺寸\n * @param count splat 数量\n * @returns 纹理宽度和高度(向上取整到 4 的倍数)\n */\nexport function calculateTextureDimensions(count: number): { width: number; height: number } {\n if (count <= 0) {\n return { width: 4, height: 4 };\n }\n\n // 计算近似的正方形边长\n const side = Math.ceil(Math.sqrt(count));\n \n // 向上取整到 4 的倍数(GPU 纹理对齐优化)\n const alignedSide = Math.ceil(side / 4) * 4;\n \n // 确保能容纳所有 splat\n let width = alignedSide;\n let height = alignedSide;\n \n // 如果正方形不够,增加高度\n while (width * height < count) {\n height += 4;\n }\n\n return { width, height };\n}\n\n/**\n * 计算 bounding box\n */\nfunction computeBoundingBox(positions: Float32Array, count: number): {\n min: [number, number, number];\n max: [number, number, number];\n} {\n if (count === 0) {\n return {\n min: [0, 0, 0],\n max: [0, 0, 0],\n };\n }\n\n const min: [number, number, number] = [positions[0], positions[1], positions[2]];\n const max: [number, number, number] = [positions[0], positions[1], positions[2]];\n\n for (let i = 1; i < count; i++) {\n const x = positions[i * 3 + 0];\n const y = positions[i * 3 + 1];\n const z = positions[i * 3 + 2];\n\n min[0] = Math.min(min[0], x);\n min[1] = Math.min(min[1], y);\n min[2] = Math.min(min[2], z);\n max[0] = Math.max(max[0], x);\n max[1] = Math.max(max[1], y);\n max[2] = Math.max(max[2], z);\n }\n\n return { min, max };\n}\n\n/**\n * 将 splat 数据压缩为纹理格式\n * @param device GPU 设备\n * @param data 紧凑格式的 splat 数据\n * @returns 压缩后的纹理数据\n */\nexport function compressSplatsToTextures(\n device: GPUDevice,\n data: CompactSplatData\n): CompressedSplatTextures {\n const count = data.count;\n const { width, height } = calculateTextureDimensions(count);\n const totalPixels = width * height;\n\n // 计算 bounding box\n const boundingBox = computeBoundingBox(data.positions, count);\n\n // ============================================\n // 准备 CPU 端数据\n // ============================================\n\n // 位置纹理数据 (RGBA32Float) - 使用 Float32Array\n const positionData = new Float32Array(totalPixels * 4);\n\n // 缩放+旋转纹理数据 (RGBA32Float) - 使用 Float32Array 保证精度\n const scaleRotData1 = new Float32Array(totalPixels * 4);\n const scaleRotData2 = new Float32Array(totalPixels * 4);\n\n // 颜色纹理数据 (RGBA8Unorm)\n const colorData = new Uint8Array(totalPixels * 4);\n\n // ============================================\n // 填充数据\n // ============================================\n for (let i = 0; i < count; i++) {\n const pixelOffset = i * 4;\n\n // 位置数据 - 直接存储 float32\n positionData[pixelOffset + 0] = data.positions[i * 3 + 0];\n positionData[pixelOffset + 1] = data.positions[i * 3 + 1];\n positionData[pixelOffset + 2] = data.positions[i * 3 + 2];\n positionData[pixelOffset + 3] = 0; // unused\n\n // scaleRotTexture1: scale_x, scale_y, scale_z, rot_w (直接存储 float32)\n scaleRotData1[pixelOffset + 0] = data.scales[i * 3 + 0];\n scaleRotData1[pixelOffset + 1] = data.scales[i * 3 + 1];\n scaleRotData1[pixelOffset + 2] = data.scales[i * 3 + 2];\n scaleRotData1[pixelOffset + 3] = data.rotations[i * 4 + 0]; // rot_w\n\n // scaleRotTexture2: rot_x, rot_y, rot_z, unused (直接存储 float32)\n scaleRotData2[pixelOffset + 0] = data.rotations[i * 4 + 1]; // rot_x\n scaleRotData2[pixelOffset + 1] = data.rotations[i * 4 + 2]; // rot_y\n scaleRotData2[pixelOffset + 2] = data.rotations[i * 4 + 3]; // rot_z\n scaleRotData2[pixelOffset + 3] = 0; // unused\n\n // 颜色数据 (已经是 0-1 范围,转换为 0-255)\n const r = data.colors[i * 3 + 0];\n const g = data.colors[i * 3 + 1];\n const b = data.colors[i * 3 + 2];\n const opacity = data.opacities[i];\n\n colorData[pixelOffset + 0] = Math.round(Math.max(0, Math.min(1, r)) * 255);\n colorData[pixelOffset + 1] = Math.round(Math.max(0, Math.min(1, g)) * 255);\n colorData[pixelOffset + 2] = Math.round(Math.max(0, Math.min(1, b)) * 255);\n colorData[pixelOffset + 3] = Math.round(Math.max(0, Math.min(1, opacity)) * 255);\n }\n\n // ============================================\n // 创建 GPU 纹理\n // ============================================\n const textureUsage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST;\n\n // 位置纹理 (RGBA32Float) - 完整精度\n const positionTexture = device.createTexture({\n size: { width, height },\n format: \"rgba32float\",\n usage: textureUsage,\n });\n\n // 缩放+旋转纹理1 (RGBA32Float) - 保证精度\n const scaleRotTexture1 = device.createTexture({\n size: { width, height },\n format: \"rgba32float\",\n usage: textureUsage,\n });\n\n // 缩放+旋转纹理2 (RGBA32Float) - 保证精度\n const scaleRotTexture2 = device.createTexture({\n size: { width, height },\n format: \"rgba32float\",\n usage: textureUsage,\n });\n\n // 颜色纹理 (RGBA8Unorm)\n const colorTexture = device.createTexture({\n size: { width, height },\n format: \"rgba8unorm\",\n usage: textureUsage,\n });\n\n // ============================================\n // 上传数据到 GPU\n // ============================================\n \n // 位置纹理 (RGBA32Float = 16 bytes per pixel)\n device.queue.writeTexture(\n { texture: positionTexture },\n positionData,\n { bytesPerRow: width * 16 },\n { width, height }\n );\n\n // 缩放+旋转纹理1 (RGBA32Float = 16 bytes per pixel)\n device.queue.writeTexture(\n { texture: scaleRotTexture1 },\n scaleRotData1,\n { bytesPerRow: width * 16 },\n { width, height }\n );\n\n // 缩放+旋转纹理2 (RGBA32Float = 16 bytes per pixel)\n device.queue.writeTexture(\n { texture: scaleRotTexture2 },\n scaleRotData2,\n { bytesPerRow: width * 16 },\n { width, height }\n );\n\n // 颜色纹理 (RGBA8Unorm = 4 bytes per pixel)\n device.queue.writeTexture(\n { texture: colorTexture },\n colorData,\n { bytesPerRow: width * 4 },\n { width, height }\n );\n\n // 计算内存占用\n const memoryBytes = \n width * height * 16 + // positionTexture (RGBA32Float)\n width * height * 16 + // scaleRotTexture1 (RGBA32Float)\n width * height * 16 + // scaleRotTexture2 (RGBA32Float)\n width * height * 4; // colorTexture (RGBA8Unorm)\n const memoryMB = memoryBytes / (1024 * 1024);\n const bytesPerSplat = memoryBytes / count;\n\n return {\n width,\n height,\n count,\n positionTexture,\n scaleRotTexture1,\n scaleRotTexture2,\n colorTexture,\n boundingBox,\n };\n}\n\n/**\n * 销毁压缩纹理资源\n * @param textures 压缩纹理数据\n */\nexport function destroyCompressedTextures(textures: CompressedSplatTextures): void {\n textures.positionTexture.destroy();\n textures.scaleRotTexture1.destroy();\n textures.scaleRotTexture2.destroy();\n textures.colorTexture.destroy();\n}\n","/**\r\n * GSSplatSorterMobile - 移动端优化的 GPU 排序器\r\n *\r\n * 与主排序器的区别:\r\n * 1. 使用紧凑的位置数据(仅 xyz,无 scale/rotation)\r\n * 2. 简化的剔除逻辑(移除屏幕尺寸剔除)\r\n * 3. 针对 iOS 优化的桶数量\r\n */\r\n\r\n// 默认配置\r\nconst DEFAULT_NUM_BUCKETS = 65536;\r\nconst IOS_NUM_BUCKETS = 4096;\r\nconst WORKGROUP_SIZE = 256;\r\n\r\n/**\r\n * 排序器配置\r\n */\r\nexport interface SorterOptions {\r\n numBuckets?: number;\r\n}\r\n\r\n/**\r\n * 剔除选项\r\n */\r\nexport interface CullingOptions {\r\n nearPlane: number;\r\n farPlane: number;\r\n pixelThreshold: number;\r\n}\r\n\r\n/**\r\n * 检测是否为 iOS 设备\r\n */\r\nfunction isIOSDevice(): boolean {\r\n if (typeof navigator === \"undefined\") return false;\r\n const ua = navigator.userAgent || \"\";\r\n return (\r\n /iphone|ipad|ipod/i.test(ua.toLowerCase()) ||\r\n (navigator.platform === \"MacIntel\" && navigator.maxTouchPoints > 1)\r\n );\r\n}\r\n\r\n/**\r\n * 生成剔除 Shader(简化版,仅使用位置数据)\r\n */\r\nfunction generateCullingShaderCode(numBuckets: number): string {\r\n const bucketBits = Math.log2(numBuckets);\r\n\r\n return /* wgsl */ `\r\n/**\r\n * Pass 1: 剔除 + 深度计算 + 桶计数(移动端简化版)\r\n * 仅使用位置数据,不包含 scale 剔除\r\n */\r\n\r\nconst NUM_BUCKETS: u32 = ${numBuckets}u;\r\nconst BUCKET_MAX: u32 = ${numBuckets - 1}u;\r\n\r\nstruct CameraUniforms {\r\n view: mat4x4<f32>,\r\n proj: mat4x4<f32>,\r\n model: mat4x4<f32>,\r\n cameraPos: vec3<f32>,\r\n _pad: f32,\r\n}\r\n\r\nstruct CullingParams {\r\n splatCount: u32,\r\n nearPlane: f32,\r\n farPlane: f32,\r\n screenWidth: f32,\r\n screenHeight: f32,\r\n pixelThreshold: f32,\r\n _pad0: f32,\r\n _pad1: f32,\r\n}\r\n\r\nstruct Counters {\r\n visibleCount: atomic<u32>,\r\n}\r\n\r\n// 位置数据:紧密打包格式 [x0,y0,z0,x1,y1,z1,...]\r\n// 注意:不使用 array<vec3<f32>> 因为 vec3 有 16 字节对齐要求\r\n@group(0) @binding(0) var<storage, read> positions: array<f32>;\r\n@group(0) @binding(1) var<uniform> camera: CameraUniforms;\r\n@group(0) @binding(2) var<uniform> params: CullingParams;\r\n@group(0) @binding(3) var<storage, read_write> counters: Counters;\r\n@group(0) @binding(4) var<storage, read_write> visibleIndices: array<u32>;\r\n@group(0) @binding(5) var<storage, read_write> depthKeys: array<u32>;\r\n@group(0) @binding(6) var<storage, read_write> bucketCounts: array<atomic<u32>>;\r\n@group(0) @binding(7) var<storage, read_write> drawIndirect: array<u32>;\r\n\r\n@compute @workgroup_size(${WORKGROUP_SIZE})\r\nfn cullAndCount(@builtin(global_invocation_id) gid: vec3<u32>) {\r\n let i = gid.x;\r\n if (i >= params.splatCount) {\r\n return;\r\n }\r\n \r\n // 手动读取位置(避免 vec3 对齐问题)\r\n let base = i * 3u;\r\n let position = vec3<f32>(positions[base], positions[base + 1u], positions[base + 2u]);\r\n // 先应用模型矩阵变换到世界空间,再变换到视图空间\r\n let worldPos = camera.model * vec4<f32>(position, 1.0);\r\n let viewPos = camera.view * worldPos;\r\n let z = -viewPos.z;\r\n \r\n // 近平面剔除\r\n if (z < params.nearPlane) {\r\n return;\r\n }\r\n \r\n // 远平面剔除\r\n if (z > params.farPlane) {\r\n return;\r\n }\r\n \r\n // 视锥剔除(简化版,不考虑 splat 半径)\r\n let fx = camera.proj[0][0];\r\n let fy = camera.proj[1][1];\r\n let x_ndc = viewPos.x * fx / z;\r\n let y_ndc = viewPos.y * fy / z;\r\n \r\n // 放宽边界以避免边缘裁剪\r\n let margin: f32 = 0.5;\r\n if (x_ndc < -1.0 - margin || x_ndc > 1.0 + margin) {\r\n return;\r\n }\r\n if (y_ndc < -1.0 - margin || y_ndc > 1.0 + margin) {\r\n return;\r\n }\r\n \r\n // 通过剔除,计算深度桶\r\n let depthRange = params.farPlane - params.nearPlane;\r\n let normalizedDepth = clamp((z - params.nearPlane) / depthRange, 0.0, 1.0);\r\n let depthBucket = BUCKET_MAX - u32(normalizedDepth * f32(BUCKET_MAX));\r\n let depthKey = (depthBucket << ${32 - bucketBits}u) | (i & ${(1 << (32 - bucketBits)) - 1}u);\r\n \r\n // 分配可见索引位置\r\n let visibleIdx = atomicAdd(&counters.visibleCount, 1u);\r\n visibleIndices[visibleIdx] = i;\r\n depthKeys[visibleIdx] = depthKey;\r\n \r\n // 统计桶计数\r\n atomicAdd(&bucketCounts[depthBucket], 1u);\r\n}\r\n\r\n@compute @workgroup_size(1)\r\nfn resetCounters() {\r\n atomicStore(&counters.visibleCount, 0u);\r\n}\r\n\r\n@compute @workgroup_size(${WORKGROUP_SIZE})\r\nfn resetBucketCounts(@builtin(global_invocation_id) gid: vec3<u32>) {\r\n let i = gid.x;\r\n if (i < NUM_BUCKETS) {\r\n atomicStore(&bucketCounts[i], 0u);\r\n }\r\n}\r\n\r\n@compute @workgroup_size(1)\r\nfn updateDrawIndirect() {\r\n let count = atomicLoad(&counters.visibleCount);\r\n drawIndirect[0] = 4u;\r\n drawIndirect[1] = count;\r\n drawIndirect[2] = 0u;\r\n drawIndirect[3] = 0u;\r\n}\r\n`;\r\n}\r\n\r\n/**\r\n * 生成前缀和 Shader\r\n */\r\nfunction generatePrefixSumShaderCode(numBuckets: number): string {\r\n return /* wgsl */ `\r\nconst NUM_BUCKETS: u32 = ${numBuckets}u;\r\n\r\n@group(0) @binding(0) var<storage, read_write> bucketCounts: array<u32>;\r\n@group(0) @binding(1) var<storage, read_write> bucketOffsets: array<u32>;\r\n\r\n@compute @workgroup_size(1)\r\nfn prefixSum() {\r\n var sum = 0u;\r\n for (var i = 0u; i < NUM_BUCKETS; i++) {\r\n bucketOffsets[i] = sum;\r\n sum += bucketCounts[i];\r\n }\r\n}\r\n`;\r\n}\r\n\r\n/**\r\n * 生成散射 Shader\r\n */\r\nfunction generateScatterShaderCode(numBuckets: number): string {\r\n const bucketBits = Math.log2(numBuckets);\r\n\r\n return /* wgsl */ `\r\nconst NUM_BUCKETS: u32 = ${numBuckets}u;\r\n\r\nstruct Counters {\r\n visibleCount: u32,\r\n}\r\n\r\n@group(0) @binding(0) var<storage, read> visibleIndices: array<u32>;\r\n@group(0) @binding(1) var<storage, read> depthKeys: array<u32>;\r\n@group(0) @binding(2) var<storage, read> bucketOffsets: array<u32>;\r\n@group(0) @binding(3) var<storage, read_write> bucketPositions: array<atomic<u32>>;\r\n@group(0) @binding(4) var<storage, read_write> sortedIndices: array<u32>;\r\n@group(0) @binding(5) var<storage, read> counters: Counters;\r\n\r\n@compute @workgroup_size(${WORKGROUP_SIZE})\r\nfn scatter(@builtin(global_invocation_id) gid: vec3<u32>) {\r\n let i = gid.x;\r\n if (i >= counters.visibleCount) {\r\n return;\r\n }\r\n \r\n let depthKey = depthKeys[i];\r\n let bucket = depthKey >> ${32 - bucketBits}u;\r\n let baseOffset = bucketOffsets[bucket];\r\n let localOffset = atomicAdd(&bucketPositions[bucket], 1u);\r\n let finalIdx = baseOffset + localOffset;\r\n \r\n sortedIndices[finalIdx] = visibleIndices[i];\r\n}\r\n\r\n@compute @workgroup_size(${WORKGROUP_SIZE})\r\nfn resetBucketPositions(@builtin(global_invocation_id) gid: vec3<u32>) {\r\n let i = gid.x;\r\n if (i < NUM_BUCKETS) {\r\n atomicStore(&bucketPositions[i], 0u);\r\n }\r\n}\r\n`;\r\n}\r\n\r\n/**\r\n * GSSplatSorterMobile - 移动端排序器\r\n */\r\nexport class GSSplatSorterMobile {\r\n private device: GPUDevice;\r\n private splatCount: number;\r\n\r\n // Buffers\r\n private cullingParamsBuffer: GPUBuffer;\r\n private countersBuffer: GPUBuffer;\r\n private visibleIndicesBuffer: GPUBuffer;\r\n private depthKeysBuffer: GPUBuffer;\r\n private bucketCountsBuffer: GPUBuffer;\r\n private bucketOffsetsBuffer: GPUBuffer;\r\n private bucketPositionsBuffer: GPUBuffer;\r\n private sortedIndicesBuffer: GPUBuffer;\r\n private drawIndirectBuffer: GPUBuffer;\r\n\r\n // Pipelines\r\n private resetCountersPipeline: GPUComputePipeline;\r\n private resetBucketCountsPipeline: GPUComputePipeline;\r\n private cullAndCountPipeline: GPUComputePipeline;\r\n private updateDrawIndirectPipeline: GPUComputePipeline;\r\n private prefixSumPipeline: GPUComputePipeline;\r\n private resetBucketPositionsPipeline: GPUComputePipeline;\r\n private scatterPipeline: GPUComputePipeline;\r\n\r\n // Bind Groups\r\n private cullingBindGroupLayout: GPUBindGroupLayout;\r\n private cullingBindGroup: GPUBindGroup;\r\n private prefixSumBindGroupLayout: GPUBindGroupLayout;\r\n private prefixSumBindGroup: GPUBindGroup;\r\n private scatterBindGroupLayout: GPUBindGroupLayout;\r\n private scatterBindGroup: GPUBindGroup;\r\n\r\n private readonly WORKGROUP_SIZE = WORKGROUP_SIZE;\r\n private readonly numBuckets: number;\r\n\r\n // 屏幕信息\r\n private screenWidth: number = 1920;\r\n private screenHeight: number = 1080;\r\n\r\n // 剔除选项\r\n private cullingOptions: CullingOptions = {\r\n nearPlane: 0.1,\r\n farPlane: 1000,\r\n pixelThreshold: 1.0,\r\n };\r\n\r\n constructor(\r\n device: GPUDevice,\r\n splatCount: number,\r\n positionsBuffer: GPUBuffer, // 紧凑位置数据\r\n cameraBuffer: GPUBuffer,\r\n options: SorterOptions = {}\r\n ) {\r\n this.device = device;\r\n this.splatCount = splatCount;\r\n\r\n const isIOS = isIOSDevice();\r\n this.numBuckets = options.numBuckets ?? (isIOS ? IOS_NUM_BUCKETS : DEFAULT_NUM_BUCKETS);\r\n\r\n // 创建 Shader 模块\r\n const cullingModule = device.createShaderModule({\r\n code: generateCullingShaderCode(this.numBuckets),\r\n label: \"mobile-culling-shader\",\r\n });\r\n\r\n const prefixSumModule = device.createShaderModule({\r\n code: generatePrefixSumShaderCode(this.numBuckets),\r\n label: \"mobile-prefix-sum-shader\",\r\n });\r\n\r\n const scatterModule = device.createShaderModule({\r\n code: generateScatterShaderCode(this.numBuckets),\r\n label: \"mobile-scatter-shader\",\r\n });\r\n\r\n // 创建 Buffers\r\n this.cullingParamsBuffer = device.createBuffer({\r\n size: 32,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n\r\n this.countersBuffer = device.createBuffer({\r\n size: 16,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC,\r\n });\r\n\r\n this.visibleIndicesBuffer = device.createBuffer({\r\n size: splatCount * 4,\r\n usage: GPUBufferUsage.STORAGE,\r\n });\r\n\r\n this.depthKeysBuffer = device.createBuffer({\r\n size: splatCount * 4,\r\n usage: GPUBufferUsage.STORAGE,\r\n });\r\n\r\n this.bucketCountsBuffer = device.createBuffer({\r\n size: this.numBuckets * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n });\r\n\r\n this.bucketOffsetsBuffer = device.createBuffer({\r\n size: this.numBuckets * 4,\r\n usage: GPUBufferUsage.STORAGE,\r\n });\r\n\r\n this.bucketPositionsBuffer = device.createBuffer({\r\n size: this.numBuckets * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n });\r\n\r\n this.sortedIndicesBuffer = device.createBuffer({\r\n size: splatCount * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\r\n });\r\n\r\n this.drawIndirectBuffer = device.createBuffer({\r\n size: 16,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.INDIRECT | GPUBufferUsage.COPY_DST,\r\n });\r\n\r\n // 创建 Bind Group Layouts 和 Pipelines\r\n // Culling bind group layout\r\n this.cullingBindGroupLayout = device.createBindGroupLayout({\r\n entries: [\r\n { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"uniform\" } },\r\n { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"uniform\" } },\r\n { binding: 3, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 4, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 5, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 6, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 7, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n ],\r\n });\r\n\r\n const cullingPipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [this.cullingBindGroupLayout],\r\n });\r\n\r\n this.resetCountersPipeline = device.createComputePipeline({\r\n layout: cullingPipelineLayout,\r\n compute: { module: cullingModule, entryPoint: \"resetCounters\" },\r\n });\r\n\r\n this.resetBucketCountsPipeline = device.createComputePipeline({\r\n layout: cullingPipelineLayout,\r\n compute: { module: cullingModule, entryPoint: \"resetBucketCounts\" },\r\n });\r\n\r\n this.cullAndCountPipeline = device.createComputePipeline({\r\n layout: cullingPipelineLayout,\r\n compute: { module: cullingModule, entryPoint: \"cullAndCount\" },\r\n });\r\n\r\n this.updateDrawIndirectPipeline = device.createComputePipeline({\r\n layout: cullingPipelineLayout,\r\n compute: { module: cullingModule, entryPoint: \"updateDrawIndirect\" },\r\n });\r\n\r\n // Prefix sum bind group layout\r\n this.prefixSumBindGroupLayout = device.createBindGroupLayout({\r\n entries: [\r\n { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n ],\r\n });\r\n\r\n const prefixSumPipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [this.prefixSumBindGroupLayout],\r\n });\r\n\r\n this.prefixSumPipeline = device.createComputePipeline({\r\n layout: prefixSumPipelineLayout,\r\n compute: { module: prefixSumModule, entryPoint: \"prefixSum\" },\r\n });\r\n\r\n // Scatter bind group layout\r\n this.scatterBindGroupLayout = device.createBindGroupLayout({\r\n entries: [\r\n { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n { binding: 3, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 4, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"storage\" } },\r\n { binding: 5, visibility: GPUShaderStage.COMPUTE, buffer: { type: \"read-only-storage\" } },\r\n ],\r\n });\r\n\r\n const scatterPipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [this.scatterBindGroupLayout],\r\n });\r\n\r\n this.scatterPipeline = device.createComputePipeline({\r\n layout: scatterPipelineLayout,\r\n compute: { module: scatterModule, entryPoint: \"scatter\" },\r\n });\r\n\r\n this.resetBucketPositionsPipeline = device.createComputePipeline({\r\n layout: scatterPipelineLayout,\r\n compute: { module: scatterModule, entryPoint: \"resetBucketPositions\" },\r\n });\r\n\r\n // 创建 Bind Groups\r\n this.cullingBindGroup = device.createBindGroup({\r\n layout: this.cullingBindGroupLayout,\r\n entries: [\r\n { binding: 0, resource: { buffer: positionsBuffer } },\r\n { binding: 1, resource: { buffer: cameraBuffer } },\r\n { binding: 2, resource: { buffer: this.cullingParamsBuffer } },\r\n { binding: 3, resource: { buffer: this.countersBuffer } },\r\n { binding: 4, resource: { buffer: this.visibleIndicesBuffer } },\r\n { binding: 5, resource: { buffer: this.depthKeysBuffer } },\r\n { binding: 6, resource: { buffer: this.bucketCountsBuffer } },\r\n { binding: 7, resource: { buffer: this.drawIndirectBuffer } },\r\n ],\r\n });\r\n\r\n this.prefixSumBindGroup = device.createBindGroup({\r\n layout: this.prefixSumBindGroupLayout,\r\n entries: [\r\n { binding: 0, resource: { buffer: this.bucketCountsBuffer } },\r\n { binding: 1, resource: { buffer: this.bucketOffsetsBuffer } },\r\n ],\r\n });\r\n\r\n this.scatterBindGroup = device.createBindGroup({\r\n layout: this.scatterBindGroupLayout,\r\n entries: [\r\n { binding: 0, resource: { buffer: this.visibleIndicesBuffer } },\r\n { binding: 1, resource: { buffer: this.depthKeysBuffer } },\r\n { binding: 2, resource: { buffer: this.bucketOffsetsBuffer } },\r\n { binding: 3, resource: { buffer: this.bucketPositionsBuffer } },\r\n { binding: 4, resource: { buffer: this.sortedIndicesBuffer } },\r\n { binding: 5, resource: { buffer: this.countersBuffer } },\r\n ],\r\n });\r\n }\r\n\r\n /**\r\n * 设置屏幕尺寸\r\n */\r\n setScreenSize(width: number, height: number): void {\r\n this.screenWidth = width;\r\n this.screenHeight = height;\r\n }\r\n\r\n /**\r\n * 设置剔除选项\r\n */\r\n setCullingOptions(options: Partial<CullingOptions>): void {\r\n this.cullingOptions = { ...this.cullingOptions, ...options };\r\n }\r\n\r\n /**\r\n * 执行排序\r\n */\r\n sort(): void {\r\n try {\r\n // 更新剔除参数\r\n const cullingParamsData = new ArrayBuffer(32);\r\n const cullingParamsView = new DataView(cullingParamsData);\r\n cullingParamsView.setUint32(0, this.splatCount, true);\r\n cullingParamsView.setFloat32(4, this.cullingOptions.nearPlane, true);\r\n cullingParamsView.setFloat32(8, this.cullingOptions.farPlane, true);\r\n cullingParamsView.setFloat32(12, this.screenWidth, true);\r\n cullingParamsView.setFloat32(16, this.screenHeight, true);\r\n cullingParamsView.setFloat32(20, this.cullingOptions.pixelThreshold, true);\r\n cullingParamsView.setFloat32(24, 0, true);\r\n cullingParamsView.setFloat32(28, 0, true);\r\n this.device.queue.writeBuffer(this.cullingParamsBuffer, 0, cullingParamsData);\r\n\r\n const cullWorkgroupCount = Math.ceil(this.splatCount / this.WORKGROUP_SIZE);\r\n const bucketResetWorkgroups = Math.ceil(this.numBuckets / this.WORKGROUP_SIZE);\r\n\r\n const encoder = this.device.createCommandEncoder();\r\n\r\n // Pass 1: 重置计数器\r\n {\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(this.resetCountersPipeline);\r\n pass.setBindGroup(0, this.cullingBindGroup);\r\n pass.dispatchWorkgroups(1);\r\n pass.end();\r\n }\r\n\r\n // Pass 2: 重置桶计数\r\n {\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(this.resetBucketCountsPipeline);\r\n pass.setBindGroup(0, this.cullingBindGroup);\r\n pass.dispatchWorkgroups(bucketResetWorkgroups);\r\n pass.end();\r\n }\r\n\r\n // Pass 3: 剔除 + 深度计算 + 桶计数\r\n {\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(this.cullAndCountPipeline);\r\n pass.setBindGroup(0, this.cullingBindGroup);\r\n pass.dispatchWorkgroups(cullWorkgroupCount);\r\n pass.end();\r\n }\r\n\r\n // Pass 4: 更新 DrawIndirect\r\n {\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(this.updateDrawIndirectPipeline);\r\n pass.setBindGroup(0, this.cullingBindGroup);\r\n pass.dispatchWorkgroups(1);\r\n pass.end();\r\n }\r\n\r\n // Pass 5: 前缀和\r\n {\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(this.prefixSumPipeline);\r\n pass.setBindGroup(0, this.prefixSumBindGroup);\r\n pass.dispatchWorkgroups(1);\r\n pass.end();\r\n }\r\n\r\n // Pass 6: 重置桶位置计数\r\n {\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(this.resetBucketPositionsPipeline);\r\n pass.setBindGroup(0, this.scatterBindGroup);\r\n pass.dispatchWorkgroups(bucketResetWorkgroups);\r\n pass.end();\r\n }\r\n\r\n // Pass 7: 散射到最终位置\r\n {\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(this.scatterPipeline);\r\n pass.setBindGroup(0, this.scatterBindGroup);\r\n pass.dispatchWorkgroups(cullWorkgroupCount);\r\n pass.end();\r\n }\r\n\r\n this.device.queue.submit([encoder.finish()]);\r\n } catch (error) {\r\n // 排序错误(静默处理)\r\n }\r\n }\r\n\r\n /**\r\n * 获取排序后的索引 buffer\r\n */\r\n getIndicesBuffer(): GPUBuffer {\r\n return this.sortedIndicesBuffer;\r\n }\r\n\r\n /**\r\n * 获取 DrawIndirect buffer\r\n */\r\n getDrawIndirectBuffer(): GPUBuffer {\r\n return this.drawIndirectBuffer;\r\n }\r\n\r\n /**\r\n * 获取 splat 数量\r\n */\r\n getSplatCount(): number {\r\n return this.splatCount;\r\n }\r\n\r\n /**\r\n * 销毁资源\r\n */\r\n destroy(): void {\r\n this.cullingParamsBuffer.destroy();\r\n this.countersBuffer.destroy();\r\n this.visibleIndicesBuffer.destroy();\r\n this.depthKeysBuffer.destroy();\r\n this.bucketCountsBuffer.destroy();\r\n this.bucketOffsetsBuffer.destroy();\r\n this.bucketPositionsBuffer.destroy();\r\n this.sortedIndicesBuffer.destroy();\r\n this.drawIndirectBuffer.destroy();\r\n }\r\n}\r\n","/**\r\n * GSSplatRendererMobile - 移动端优化的 3D Gaussian Splatting 渲染器\r\n *\r\n * 优化特点:\r\n * 1. 使用纹理存储 splat 数据,减少 GPU 内存占用 (~52 bytes/splat vs 256 bytes)\r\n * 2. 仅支持 L0 模式(无 SH 计算)\r\n * 3. 从纹理采样获取 splat 属性(使用 RGBA32Float 保证精度)\r\n * 4. 使用简化的排序器\r\n */\r\n\r\nimport { Renderer } from \"../core/Renderer\";\r\nimport { Camera } from \"../core/Camera\";\r\nimport { CompactSplatData } from \"./PLYLoaderMobile\";\r\nimport {\r\n CompressedSplatTextures,\r\n compressSplatsToTextures,\r\n destroyCompressedTextures,\r\n} from \"./TextureCompressor\";\r\nimport { GSSplatSorterMobile } from \"./GSSplatSorterMobile\";\r\nimport type { BoundingBox, Vec3Tuple } from \"../types\";\r\nimport { SHMode, RendererCapabilities } from \"../types\";\r\nimport type { IGSSplatRenderer, IGSSplatRendererWithCapabilities } from \"./IGSSplatRenderer\";\r\n\r\n\r\n// ============================================\r\n// 移动端 L0 Shader - 从纹理采样数据(简化版)\r\n// ============================================\r\nconst shaderCodeMobileL0 = /* wgsl */ `\r\nstruct Uniforms {\r\n view: mat4x4<f32>,\r\n proj: mat4x4<f32>,\r\n model: mat4x4<f32>,\r\n cameraPos: vec3<f32>,\r\n _pad: f32,\r\n screenSize: vec2<f32>,\r\n _pad2: vec2<f32>,\r\n textureSize: vec2<f32>, // 纹理尺寸 (用于坐标计算)\r\n _pad3: vec2<f32>,\r\n}\r\n\r\n@group(0) @binding(0) var<uniform> uniforms: Uniforms;\r\n@group(0) @binding(1) var<storage, read> sortedIndices: array<u32>;\r\n\r\n// 纹理绑定 - 4 张纹理(使用 RGBA32Float 保证精度)\r\n@group(1) @binding(0) var positionTex: texture_2d<f32>; // RGBA32Float: xyz + unused\r\n@group(1) @binding(1) var scaleRotTex1: texture_2d<f32>; // RGBA32Float: scale_xyz + rot_w\r\n@group(1) @binding(2) var scaleRotTex2: texture_2d<f32>; // RGBA32Float: rot_xyz + unused\r\n@group(1) @binding(3) var colorTex: texture_2d<f32>; // RGBA8Unorm: rgb + opacity\r\n\r\nstruct VertexOutput {\r\n @builtin(position) position: vec4<f32>,\r\n @location(0) localUV: vec2<f32>,\r\n @location(1) color: vec3<f32>,\r\n @location(2) opacity: f32,\r\n}\r\n\r\nconst QUAD_POSITIONS = array<vec2<f32>, 4>(\r\n vec2<f32>(-1.0, -1.0),\r\n vec2<f32>( 1.0, -1.0),\r\n vec2<f32>(-1.0, 1.0),\r\n vec2<f32>( 1.0, 1.0),\r\n);\r\n\r\nconst ELLIPSE_SCALE: f32 = 3.0;\r\n\r\n// 将索引转换为纹理坐标\r\nfn indexToTexCoord(index: u32) -> vec2<u32> {\r\n let texWidth = u32(uniforms.textureSize.x);\r\n let x = index % texWidth;\r\n let y = index / texWidth;\r\n return vec2<u32>(x, y);\r\n}\r\n\r\n// 四元数转旋转矩阵\r\nfn quatToMat3(q: vec4<f32>) -> mat3x3<f32> {\r\n let w = q[0]; let x = q[1]; let y = q[2]; let z = q[3];\r\n let x2 = x + x; let y2 = y + y; let z2 = z + z;\r\n let xx = x * x2; let xy = x * y2; let xz = x * z2;\r\n let yy = y * y2; let yz = y * z2; let zz = z * z2;\r\n let wx = w * x2; let wy = w * y2; let wz = w * z2;\r\n return mat3x3<f32>(\r\n vec3<f32>(1.0 - (yy + zz), xy + wz, xz - wy),\r\n vec3<f32>(xy - wz, 1.0 - (xx + zz), yz + wx),\r\n vec3<f32>(xz + wy, yz - wx, 1.0 - (xx + yy))\r\n );\r\n}\r\n\r\n// 从模型矩阵提取统一缩放因子(取 X 轴向量长度)\r\nfn getModelScale(model: mat4x4<f32>) -> f32 {\r\n return length(model[0].xyz);\r\n}\r\n\r\n// 计算 2D 协方差\r\nfn computeCov2D(mean: vec3<f32>, scale: vec3<f32>, rotation: vec4<f32>, modelView: mat4x4<f32>, proj: mat4x4<f32>, modelScale: f32) -> vec3<f32> {\r\n let R = quatToMat3(rotation);\r\n // 应用模型缩放到 splat scale\r\n let scaledScale = scale * modelScale;\r\n let s2 = scaledScale * scaledScale;\r\n let M = mat3x3<f32>(R[0] * s2.x, R[1] * s2.y, R[2] * s2.z);\r\n let Sigma = M * transpose(R);\r\n let viewPos = (modelView * vec4<f32>(mean, 1.0)).xyz;\r\n let viewRot = mat3x3<f32>(modelView[0].xyz, modelView[1].xyz, modelView[2].xyz);\r\n let SigmaView = viewRot * Sigma * transpose(viewRot);\r\n let fx = proj[0][0]; let fy = proj[1][1];\r\n let z = -viewPos.z;\r\n let z_clamped = max(z, 0.001);\r\n let z2 = z_clamped * z_clamped;\r\n // 雅可比矩阵: 从相机坐标 (x_cam, y_cam, z_cam) 到 NDC 的偏导数\r\n // x_ndc = fx * x_cam / (-z_cam), 所以 dx_ndc/dz_cam = fx * x_cam / z_cam^2 (正号!)\r\n let j1 = vec3<f32>(fx / z_clamped, 0.0, fx * viewPos.x / z2);\r\n let j2 = vec3<f32>(0.0, fy / z_clamped, fy * viewPos.y / z2);\r\n let Sj1 = SigmaView * j1;\r\n let Sj2 = SigmaView * j2;\r\n return vec3<f32>(dot(j1, Sj1), dot(j1, Sj2), dot(j2, Sj2));\r\n}\r\n\r\n// 计算椭圆轴\r\nfn computeEllipseAxes(cov2D: vec3<f32>) -> mat2x2<f32> {\r\n let a = cov2D.x; let b = cov2D.y; let c = cov2D.z;\r\n let trace = a + c;\r\n let det = a * c - b * b;\r\n let disc = trace * trace - 4.0 * det;\r\n let sqrtDisc = sqrt(max(disc, 0.0));\r\n let lambda1 = max((trace + sqrtDisc) * 0.5, 0.0);\r\n let lambda2 = max((trace - sqrtDisc) * 0.5, 0.0);\r\n let r1 = sqrt(lambda1);\r\n let r2 = sqrt(lambda2);\r\n var axis1: vec2<f32>; var axis2: vec2<f32>;\r\n if (abs(b) > 1e-6) {\r\n axis1 = normalize(vec2<f32>(b, lambda1 - a));\r\n axis2 = vec2<f32>(-axis1.y, axis1.x);\r\n } else {\r\n if (a >= c) { axis1 = vec2<f32>(1.0, 0.0); axis2 = vec2<f32>(0.0, 1.0); }\r\n else { axis1 = vec2<f32>(0.0, 1.0); axis2 = vec2<f32>(1.0, 0.0); }\r\n }\r\n return mat2x2<f32>(axis1 * r1, axis2 * r2);\r\n}\r\n\r\n@vertex\r\nfn vs_main(@builtin(vertex_index) vertexIndex: u32, @builtin(instance_index) instanceIndex: u32) -> VertexOutput {\r\n var output: VertexOutput;\r\n \r\n // 获取排序后的索引\r\n let splatIndex = sortedIndices[instanceIndex];\r\n let texCoord = indexToTexCoord(splatIndex);\r\n \r\n // 从纹理采样位置数据(RGBA32Float,直接读取)\r\n let posSample = textureLoad(positionTex, texCoord, 0);\r\n let mean = posSample.xyz;\r\n \r\n // 从纹理采样缩放和旋转(RGBA16Float,GPU 自动转换为 f32)\r\n let scaleRot1 = textureLoad(scaleRotTex1, texCoord, 0);\r\n let scaleRot2 = textureLoad(scaleRotTex2, texCoord, 0);\r\n \r\n let scale = scaleRot1.xyz;\r\n let rotation = vec4<f32>(scaleRot1.w, scaleRot2.x, scaleRot2.y, scaleRot2.z);\r\n \r\n // 从纹理采样颜色(RGBA8Unorm,GPU 自动归一化到 0-1)\r\n let colorSample = textureLoad(colorTex, texCoord, 0);\r\n let color = colorSample.rgb;\r\n let opacity = colorSample.a;\r\n \r\n // 计算顶点位置\r\n let quadPos = QUAD_POSITIONS[vertexIndex];\r\n output.localUV = quadPos;\r\n \r\n // 计算 modelView 矩阵和模型缩放\r\n let modelView = uniforms.view * uniforms.model;\r\n let modelScale = getModelScale(uniforms.model);\r\n \r\n let cov2D = computeCov2D(mean, scale, rotation, modelView, uniforms.proj, modelScale);\r\n let axes = computeEllipseAxes(cov2D);\r\n let screenOffset = axes[0] * quadPos.x * ELLIPSE_SCALE + axes[1] * quadPos.y * ELLIPSE_SCALE;\r\n \r\n // 应用 model 变换到 splat 位置\r\n let worldPos = uniforms.model * vec4<f32>(mean, 1.0);\r\n let viewPos = uniforms.view * worldPos;\r\n var clipPos = uniforms.proj * viewPos;\r\n clipPos.x = clipPos.x + screenOffset.x * clipPos.w;\r\n clipPos.y = clipPos.y + screenOffset.y * clipPos.w;\r\n output.position = clipPos;\r\n output.color = color;\r\n output.opacity = opacity;\r\n \r\n return output;\r\n}\r\n\r\n@fragment\r\nfn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {\r\n let r = length(input.localUV);\r\n if (r > 1.0) { discard; }\r\n let gaussianWeight = exp(-r * r * 4.0);\r\n let alpha = input.opacity * gaussianWeight;\r\n if (alpha < 0.004) { discard; } // 丢弃几乎透明的像素\r\n let color = clamp(input.color, vec3<f32>(0.0), vec3<f32>(1.0));\r\n return vec4<f32>(color * alpha, alpha);\r\n}\r\n`;\r\n\r\n/**\r\n * GSSplatRendererMobile - 移动端优化渲染器\r\n * 实现 IGSSplatRenderer 接口\r\n */\r\nexport class GSSplatRendererMobile implements IGSSplatRendererWithCapabilities {\r\n private renderer: Renderer;\r\n private camera: Camera;\r\n\r\n // GPU 资源\r\n private pipeline!: GPURenderPipeline;\r\n private uniformBindGroupLayout!: GPUBindGroupLayout;\r\n private textureBindGroupLayout!: GPUBindGroupLayout;\r\n private uniformBuffer!: GPUBuffer;\r\n private uniformBindGroup: GPUBindGroup | null = null;\r\n private textureBindGroup: GPUBindGroup | null = null;\r\n\r\n // 压缩纹理数据\r\n private compressedTextures: CompressedSplatTextures | null = null;\r\n private splatCount: number = 0;\r\n\r\n // 排序器\r\n private sorter: GSSplatSorterMobile | null = null;\r\n\r\n // 位置缓冲区(用于排序)\r\n private positionsBuffer: GPUBuffer | null = null;\r\n\r\n // Bounding box\r\n private boundingBox: BoundingBox | null = null;\r\n private cpuPositions: Float32Array | null = null;\r\n\r\n // 帧计数(用于排序频率控制)\r\n private frameCount: number = 0;\r\n private sortEveryNFrames: number = 1;\r\n\r\n // ============================================\r\n // 变换相关 (position, rotation, scale)\r\n // ============================================\r\n private position: Vec3Tuple = [0, 0, 0];\r\n private rotation: Vec3Tuple = [0, 0, 0]; // Euler angles (radians)\r\n private scaleValue: Vec3Tuple = [1, 1, 1];\r\n private pivot: Vec3Tuple = [0, 0, 0]; // 旋转/缩放中心点\r\n private modelMatrix: Float32Array = new Float32Array(16); // 4x4 model matrix\r\n\r\n constructor(renderer: Renderer, camera: Camera) {\r\n this.renderer = renderer;\r\n this.camera = camera;\r\n\r\n this.createPipeline();\r\n this.createUniformBuffer();\r\n this.updateModelMatrix(); // 初始化模型矩阵为单位矩阵\r\n }\r\n\r\n // ============================================\r\n // Transform 方法\r\n // ============================================\r\n\r\n /**\r\n * 设置位置\r\n */\r\n setPosition(x: number, y: number, z: number): void {\r\n this.position = [x, y, z];\r\n this.updateModelMatrix();\r\n }\r\n\r\n /**\r\n * 获取位置\r\n */\r\n getPosition(): Vec3Tuple {\r\n return [...this.position];\r\n }\r\n\r\n /**\r\n * 设置旋转 (欧拉角, 弧度)\r\n */\r\n setRotation(x: number, y: number, z: number): void {\r\n this.rotation = [x, y, z];\r\n this.updateModelMatrix();\r\n }\r\n\r\n /**\r\n * 获取旋转\r\n */\r\n getRotation(): Vec3Tuple {\r\n return [...this.rotation];\r\n }\r\n\r\n /**\r\n * 设置缩放\r\n */\r\n setScale(x: number, y: number, z: number): void {\r\n this.scaleValue = [x, y, z];\r\n this.updateModelMatrix();\r\n }\r\n\r\n /**\r\n * 获取缩放\r\n */\r\n getScale(): Vec3Tuple {\r\n return [...this.scaleValue];\r\n }\r\n\r\n /**\r\n * 设置旋转/缩放中心点 (pivot)\r\n */\r\n setPivot(x: number, y: number, z: number): void {\r\n this.pivot = [x, y, z];\r\n this.updateModelMatrix();\r\n }\r\n\r\n /**\r\n * 获取旋转/缩放中心点 (pivot)\r\n */\r\n getPivot(): Vec3Tuple {\r\n return [...this.pivot];\r\n }\r\n\r\n /**\r\n * 更新模型矩阵\r\n * 变换顺序: T * Tp * R * S * Tp^-1\r\n * 即: 先移到原点,缩放,旋转,再移回pivot,最后应用用户平移\r\n */\r\n private updateModelMatrix(): void {\r\n const [tx, ty, tz] = this.position;\r\n const [rx, ry, rz] = this.rotation;\r\n const [sx, sy, sz] = this.scaleValue;\r\n const [px, py, pz] = this.pivot;\r\n\r\n // 计算旋转矩阵分量 (Euler XYZ 顺序)\r\n const cx = Math.cos(rx), sx1 = Math.sin(rx);\r\n const cy = Math.cos(ry), sy1 = Math.sin(ry);\r\n const cz = Math.cos(rz), sz1 = Math.sin(rz);\r\n\r\n // 组合旋转矩阵 R = Rz * Ry * Rx\r\n const r00 = cy * cz;\r\n const r01 = sx1 * sy1 * cz - cx * sz1;\r\n const r02 = cx * sy1 * cz + sx1 * sz1;\r\n const r10 = cy * sz1;\r\n const r11 = sx1 * sy1 * sz1 + cx * cz;\r\n const r12 = cx * sy1 * sz1 - sx1 * cz;\r\n const r20 = -sy1;\r\n const r21 = sx1 * cy;\r\n const r22 = cx * cy;\r\n\r\n // RS 矩阵 (旋转 * 缩放)\r\n const rs00 = r00 * sx, rs01 = r01 * sy, rs02 = r02 * sz;\r\n const rs10 = r10 * sx, rs11 = r11 * sy, rs12 = r12 * sz;\r\n const rs20 = r20 * sx, rs21 = r21 * sy, rs22 = r22 * sz;\r\n\r\n // 计算 (I - RS) * pivot\r\n const dpx = px - (rs00 * px + rs01 * py + rs02 * pz);\r\n const dpy = py - (rs10 * px + rs11 * py + rs12 * pz);\r\n const dpz = pz - (rs20 * px + rs21 * py + rs22 * pz);\r\n\r\n // 最终平移 = position + (I - RS) * pivot\r\n const finalTx = tx + dpx;\r\n const finalTy = ty + dpy;\r\n const finalTz = tz + dpz;\r\n\r\n // 模型矩阵 (列主序)\r\n this.modelMatrix[0] = rs00;\r\n this.modelMatrix[1] = rs10;\r\n this.modelMatrix[2] = rs20;\r\n this.modelMatrix[3] = 0;\r\n\r\n this.modelMatrix[4] = rs01;\r\n this.modelMatrix[5] = rs11;\r\n this.modelMatrix[6] = rs21;\r\n this.modelMatrix[7] = 0;\r\n\r\n this.modelMatrix[8] = rs02;\r\n this.modelMatrix[9] = rs12;\r\n this.modelMatrix[10] = rs22;\r\n this.modelMatrix[11] = 0;\r\n\r\n this.modelMatrix[12] = finalTx;\r\n this.modelMatrix[13] = finalTy;\r\n this.modelMatrix[14] = finalTz;\r\n this.modelMatrix[15] = 1;\r\n }\r\n\r\n /**\r\n * 获取当前模型矩阵\r\n */\r\n getModelMatrix(): Float32Array {\r\n return this.modelMatrix;\r\n }\r\n\r\n /**\r\n * 创建渲染管线\r\n */\r\n private createPipeline(): void {\r\n const device = this.renderer.device;\r\n\r\n // 创建 shader 模块\r\n const shaderModule = device.createShaderModule({\r\n code: shaderCodeMobileL0,\r\n label: \"mobile-splat-shader\",\r\n });\r\n\r\n // Uniform bind group layout (group 0)\r\n this.uniformBindGroupLayout = device.createBindGroupLayout({\r\n entries: [\r\n {\r\n binding: 0,\r\n visibility: GPUShaderStage.VERTEX,\r\n buffer: { type: \"uniform\" },\r\n },\r\n {\r\n binding: 1,\r\n visibility: GPUShaderStage.VERTEX,\r\n buffer: { type: \"read-only-storage\" },\r\n },\r\n ],\r\n });\r\n\r\n // Texture bind group layout (group 1) - 简化版 4 张纹理\r\n this.textureBindGroupLayout = device.createBindGroupLayout({\r\n entries: [\r\n {\r\n // positionTex (RGBA32Float)\r\n binding: 0,\r\n visibility: GPUShaderStage.VERTEX,\r\n texture: { sampleType: \"unfilterable-float\" },\r\n },\r\n {\r\n // scaleRotTex1 (RGBA32Float)\r\n binding: 1,\r\n visibility: GPUShaderStage.VERTEX,\r\n texture: { sampleType: \"unfilterable-float\" },\r\n },\r\n {\r\n // scaleRotTex2 (RGBA32Float)\r\n binding: 2,\r\n visibility: GPUShaderStage.VERTEX,\r\n texture: { sampleType: \"unfilterable-float\" },\r\n },\r\n {\r\n // colorTex (RGBA8Unorm)\r\n binding: 3,\r\n visibility: GPUShaderStage.VERTEX,\r\n texture: { sampleType: \"unfilterable-float\" },\r\n },\r\n ],\r\n });\r\n\r\n // Pipeline layout\r\n const pipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [this.uniformBindGroupLayout, this.textureBindGroupLayout],\r\n });\r\n\r\n // Blend state\r\n const blendState: GPUBlendState = {\r\n color: {\r\n srcFactor: \"one\",\r\n dstFactor: \"one-minus-src-alpha\",\r\n operation: \"add\",\r\n },\r\n alpha: {\r\n srcFactor: \"one\",\r\n dstFactor: \"one-minus-src-alpha\",\r\n operation: \"add\",\r\n },\r\n };\r\n\r\n // 创建管线\r\n this.pipeline = device.createRenderPipeline({\r\n layout: pipelineLayout,\r\n vertex: {\r\n module: shaderModule,\r\n entryPoint: \"vs_main\",\r\n buffers: [],\r\n },\r\n fragment: {\r\n module: shaderModule,\r\n entryPoint: \"fs_main\",\r\n targets: [\r\n {\r\n format: this.renderer.format,\r\n blend: blendState,\r\n },\r\n ],\r\n },\r\n primitive: {\r\n topology: \"triangle-strip\",\r\n },\r\n depthStencil: {\r\n format: this.renderer.depthFormat,\r\n depthWriteEnabled: true,\r\n depthCompare: \"always\",\r\n },\r\n });\r\n\r\n }\r\n\r\n /**\r\n * 创建 uniform buffer\r\n * 布局: view (64) + proj (64) + model (64) + cameraPos (12) + pad (4) + screenSize (8) + pad (8) + textureSize (8) + pad (8) = 240 bytes\r\n */\r\n private createUniformBuffer(): void {\r\n this.uniformBuffer = this.renderer.device.createBuffer({\r\n size: 240,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n }\r\n\r\n /**\r\n * 设置紧凑格式的 splat 数据\r\n * @param data 紧凑格式的 splat 数据\r\n */\r\n setCompactData(data: CompactSplatData): void {\r\n try {\r\n const device = this.renderer.device;\r\n\r\n // 销毁旧资源\r\n this.destroyInternal();\r\n\r\n this.splatCount = data.count;\r\n this.frameCount = 0;\r\n\r\n if (this.splatCount === 0) {\r\n return;\r\n }\r\n\r\n // 压缩数据到纹理\r\n this.compressedTextures = compressSplatsToTextures(device, data);\r\n\r\n // 计算 bounding box\r\n this.boundingBox = this.computeBoundingBox(data);\r\n this.cpuPositions = new Float32Array(data.positions);\r\n\r\n // 创建位置缓冲区(用于排序)\r\n this.positionsBuffer = device.createBuffer({\r\n size: data.count * 12, // 3 floats per position\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,\r\n });\r\n // 使用 new Float32Array 确保是标准 ArrayBuffer\r\n device.queue.writeBuffer(this.positionsBuffer, 0, new Float32Array(data.positions));\r\n\r\n // 创建排序器\r\n this.sorter = new GSSplatSorterMobile(\r\n device,\r\n this.splatCount,\r\n this.positionsBuffer,\r\n this.uniformBuffer\r\n );\r\n\r\n this.sorter.setScreenSize(this.renderer.width, this.renderer.height);\r\n this.sorter.setCullingOptions({\r\n nearPlane: this.camera.near,\r\n farPlane: this.camera.far,\r\n pixelThreshold: 1.0,\r\n });\r\n\r\n // 创建 bind groups\r\n this.createBindGroups();\r\n\r\n const memoryMB = (\r\n this.compressedTextures.width *\r\n this.compressedTextures.height *\r\n 52 / // 约 52 bytes per texel (16+16+16+4)\r\n (1024 * 1024)\r\n ).toFixed(2);\r\n } catch (error) {\r\n this.splatCount = 0;\r\n this.compressedTextures = null;\r\n this.sorter = null;\r\n }\r\n }\r\n\r\n /**\r\n * 创建 bind groups\r\n */\r\n private createBindGroups(): void {\r\n if (!this.compressedTextures || !this.sorter) return;\r\n\r\n const device = this.renderer.device;\r\n\r\n // Uniform bind group (group 0)\r\n this.uniformBindGroup = device.createBindGroup({\r\n layout: this.uniformBindGroupLayout,\r\n entries: [\r\n {\r\n binding: 0,\r\n resource: { buffer: this.uniformBuffer },\r\n },\r\n {\r\n binding: 1,\r\n resource: { buffer: this.sorter.getIndicesBuffer() },\r\n },\r\n ],\r\n });\r\n\r\n // Texture bind group (group 1) - 简化版 4 张纹理\r\n this.textureBindGroup = device.createBindGroup({\r\n layout: this.textureBindGroupLayout,\r\n entries: [\r\n {\r\n binding: 0,\r\n resource: this.compressedTextures.positionTexture.createView(),\r\n },\r\n {\r\n binding: 1,\r\n resource: this.compressedTextures.scaleRotTexture1.createView(),\r\n },\r\n {\r\n binding: 2,\r\n resource: this.compressedTextures.scaleRotTexture2.createView(),\r\n },\r\n {\r\n binding: 3,\r\n resource: this.compressedTextures.colorTexture.createView(),\r\n },\r\n ],\r\n });\r\n }\r\n\r\n /**\r\n * 计算 bounding box\r\n */\r\n private computeBoundingBox(data: CompactSplatData): BoundingBox {\r\n if (data.count === 0) {\r\n return { min: [0, 0, 0], max: [0, 0, 0], center: [0, 0, 0], radius: 0 };\r\n }\r\n\r\n const positions = data.positions;\r\n const min: Vec3Tuple = [positions[0], positions[1], positions[2]];\r\n const max: Vec3Tuple = [positions[0], positions[1], positions[2]];\r\n\r\n for (let i = 1; i < data.count; i++) {\r\n const x = positions[i * 3 + 0];\r\n const y = positions[i * 3 + 1];\r\n const z = positions[i * 3 + 2];\r\n min[0] = Math.min(min[0], x);\r\n min[1] = Math.min(min[1], y);\r\n min[2] = Math.min(min[2], z);\r\n max[0] = Math.max(max[0], x);\r\n max[1] = Math.max(max[1], y);\r\n max[2] = Math.max(max[2], z);\r\n }\r\n\r\n const center: Vec3Tuple = [\r\n (min[0] + max[0]) / 2,\r\n (min[1] + max[1]) / 2,\r\n (min[2] + max[2]) / 2,\r\n ];\r\n\r\n const dx = max[0] - min[0];\r\n const dy = max[1] - min[1];\r\n const dz = max[2] - min[2];\r\n const radius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min, max, center, radius };\r\n }\r\n\r\n /**\r\n * 渲染\r\n * @param pass 渲染通道编码器\r\n */\r\n render(pass: GPURenderPassEncoder): void {\r\n if (\r\n this.splatCount === 0 ||\r\n !this.uniformBindGroup ||\r\n !this.textureBindGroup ||\r\n !this.sorter ||\r\n !this.compressedTextures\r\n ) {\r\n return;\r\n }\r\n\r\n this.frameCount++;\r\n\r\n // 更新 uniform buffer\r\n const device = this.renderer.device;\r\n device.queue.writeBuffer(this.uniformBuffer, 0, new Float32Array(this.camera.viewMatrix));\r\n device.queue.writeBuffer(this.uniformBuffer, 64, new Float32Array(this.camera.projectionMatrix));\r\n device.queue.writeBuffer(this.uniformBuffer, 128, new Float32Array(this.modelMatrix));\r\n device.queue.writeBuffer(this.uniformBuffer, 192, new Float32Array(this.camera.position));\r\n device.queue.writeBuffer(\r\n this.uniformBuffer,\r\n 208,\r\n new Float32Array([this.renderer.width, this.renderer.height, 0, 0])\r\n );\r\n device.queue.writeBuffer(\r\n this.uniformBuffer,\r\n 224,\r\n new Float32Array([this.compressedTextures.width, this.compressedTextures.height, 0, 0])\r\n );\r\n\r\n // 更新排序器参数\r\n this.sorter.setScreenSize(this.renderer.width, this.renderer.height);\r\n this.sorter.setCullingOptions({\r\n nearPlane: this.camera.near,\r\n farPlane: this.camera.far,\r\n pixelThreshold: 1.0,\r\n });\r\n\r\n // 排序(第一帧必须排序)\r\n const isFirstFrame = this.frameCount === 1;\r\n const shouldSort = isFirstFrame || this.frameCount % this.sortEveryNFrames === 0;\r\n\r\n if (shouldSort) {\r\n this.sorter.sort();\r\n }\r\n\r\n // 渲染\r\n pass.setPipeline(this.pipeline);\r\n pass.setBindGroup(0, this.uniformBindGroup);\r\n pass.setBindGroup(1, this.textureBindGroup);\r\n pass.drawIndirect(this.sorter.getDrawIndirectBuffer(), 0);\r\n }\r\n\r\n /**\r\n * 获取 splat 数量\r\n */\r\n getSplatCount(): number {\r\n return this.splatCount;\r\n }\r\n\r\n /**\r\n * 获取 bounding box\r\n */\r\n getBoundingBox(): BoundingBox | null {\r\n return this.boundingBox;\r\n }\r\n\r\n getCPUPositions(): Float32Array | null {\r\n return this.cpuPositions;\r\n }\r\n\r\n /**\r\n * 设置排序频率\r\n * @param n 每 n 帧排序一次\r\n */\r\n setSortFrequency(n: number): void {\r\n this.sortEveryNFrames = Math.max(1, n);\r\n }\r\n\r\n // ============================================\r\n // IGSSplatRenderer 接口实现 - SH 模式\r\n // ============================================\r\n\r\n /**\r\n * 设置 SH 模式(移动端仅支持 L0)\r\n */\r\n setSHMode(mode: SHMode): void {\r\n // 移动端仅支持 L0 模式\r\n }\r\n\r\n /**\r\n * 获取当前 SH 模式\r\n */\r\n getSHMode(): SHMode {\r\n return SHMode.L0;\r\n }\r\n\r\n /**\r\n * 是否支持指定的 SH 模式\r\n */\r\n supportsSHMode(mode: SHMode): boolean {\r\n return mode === SHMode.L0;\r\n }\r\n\r\n /**\r\n * 获取渲染器能力\r\n */\r\n getCapabilities(): RendererCapabilities {\r\n return {\r\n maxSHMode: SHMode.L0,\r\n supportsRawData: false,\r\n isMobileOptimized: true,\r\n maxSplatCount: 0, // 无限制(受 GPU 内存限制)\r\n };\r\n }\r\n\r\n /**\r\n * 内部销毁资源(不销毁管线)\r\n */\r\n private destroyInternal(): void {\r\n if (this.compressedTextures) {\r\n destroyCompressedTextures(this.compressedTextures);\r\n this.compressedTextures = null;\r\n }\r\n\r\n if (this.sorter) {\r\n this.sorter.destroy();\r\n this.sorter = null;\r\n }\r\n\r\n if (this.positionsBuffer) {\r\n this.positionsBuffer.destroy();\r\n this.positionsBuffer = null;\r\n }\r\n\r\n this.uniformBindGroup = null;\r\n this.textureBindGroup = null;\r\n this.splatCount = 0;\r\n this.boundingBox = null;\r\n }\r\n\r\n /**\r\n * 销毁资源\r\n */\r\n destroy(): void {\r\n this.destroyInternal();\r\n }\r\n}\r\n","/**\r\n * SceneManager - 场景管理器\r\n * \r\n * 负责管理场景中的所有对象:\r\n * - Mesh 网格\r\n * - Splat 点云\r\n * - 场景查询(bounding box 等)\r\n */\r\n\r\nimport { Mesh } from \"../mesh/Mesh\";\r\nimport { MeshRenderer } from \"../mesh/MeshRenderer\";\r\nimport type { IGSSplatRenderer } from \"../gs/IGSSplatRenderer\";\r\nimport type { BoundingBox, Vec3Tuple } from \"../types\";\r\n\r\n/**\r\n * 场景对象类型\r\n */\r\nexport type SceneObjectType = 'mesh' | 'splat' | 'meshGroup';\r\n\r\n/**\r\n * 场景对象信息\r\n */\r\nexport interface SceneObjectInfo {\r\n type: SceneObjectType;\r\n index: number;\r\n name?: string;\r\n}\r\n\r\n/**\r\n * SceneManager - 场景管理器\r\n */\r\nexport class SceneManager {\r\n private meshRenderer: MeshRenderer;\r\n private gsRenderer: IGSSplatRenderer | null = null;\r\n\r\n constructor(meshRenderer: MeshRenderer) {\r\n this.meshRenderer = meshRenderer;\r\n }\r\n\r\n // ============================================\r\n // Splat 渲染器管理\r\n // ============================================\r\n\r\n /**\r\n * 设置 GS Splat 渲染器\r\n */\r\n setGSRenderer(renderer: IGSSplatRenderer | null): void {\r\n this.gsRenderer = renderer;\r\n }\r\n\r\n /**\r\n * 获取 GS Splat 渲染器\r\n */\r\n getGSRenderer(): IGSSplatRenderer | null {\r\n return this.gsRenderer;\r\n }\r\n\r\n /**\r\n * 是否有 Splat 数据\r\n */\r\n hasSplats(): boolean {\r\n return this.gsRenderer !== null && this.gsRenderer.getSplatCount() > 0;\r\n }\r\n\r\n // ============================================\r\n // Mesh 管理(委托给 MeshRenderer)\r\n // ============================================\r\n\r\n /**\r\n * 获取 Mesh 数量\r\n */\r\n getMeshCount(): number {\r\n return this.meshRenderer.getMeshCount();\r\n }\r\n\r\n /**\r\n * 获取指定索引的 Mesh\r\n */\r\n getMeshByIndex(index: number): Mesh | null {\r\n return this.meshRenderer.getMeshByIndex(index);\r\n }\r\n\r\n /**\r\n * 获取指定范围的 Mesh\r\n */\r\n getMeshRange(startIndex: number, count: number): Mesh[] {\r\n const meshes: Mesh[] = [];\r\n for (let i = 0; i < count; i++) {\r\n const mesh = this.meshRenderer.getMeshByIndex(startIndex + i);\r\n if (mesh) {\r\n meshes.push(mesh);\r\n }\r\n }\r\n return meshes;\r\n }\r\n\r\n /**\r\n * 清空所有 Mesh\r\n */\r\n clearMeshes(): void {\r\n this.meshRenderer.clear();\r\n }\r\n\r\n /**\r\n * 按索引移除 Mesh\r\n */\r\n removeMeshByIndex(index: number): boolean {\r\n return this.meshRenderer.removeMeshByIndex(index);\r\n }\r\n\r\n // ============================================\r\n // 覆盖层 Mesh 管理(热点等)\r\n // ============================================\r\n\r\n getOverlayMeshCount(): number {\r\n return this.meshRenderer.getOverlayMeshCount();\r\n }\r\n\r\n getOverlayMeshByIndex(index: number): Mesh | null {\r\n return this.meshRenderer.getOverlayMeshByIndex(index);\r\n }\r\n\r\n getOverlayMeshRange(startIndex: number, count: number): Mesh[] {\r\n const meshes: Mesh[] = [];\r\n for (let i = 0; i < count; i++) {\r\n const mesh = this.meshRenderer.getOverlayMeshByIndex(startIndex + i);\r\n if (mesh) meshes.push(mesh);\r\n }\r\n return meshes;\r\n }\r\n\r\n removeOverlayMeshByIndex(index: number): boolean {\r\n return this.meshRenderer.removeOverlayMeshByIndex(index);\r\n }\r\n\r\n getOverlayMeshColor(index: number): [number, number, number, number] | null {\r\n return this.meshRenderer.getOverlayMeshColor(index);\r\n }\r\n\r\n setOverlayMeshRangeColor(startIndex: number, count: number, r: number, g: number, b: number, a: number = 1): number {\r\n return this.meshRenderer.setOverlayMeshRangeColor(startIndex, count, r, g, b, a);\r\n }\r\n\r\n // ============================================\r\n // Splat 管理\r\n // ============================================\r\n\r\n /**\r\n * 获取 Splat 数量\r\n */\r\n getSplatCount(): number {\r\n return this.gsRenderer?.getSplatCount() ?? 0;\r\n }\r\n\r\n /**\r\n * 清空 Splats\r\n */\r\n clearSplats(): void {\r\n if (this.gsRenderer) {\r\n this.gsRenderer.destroy();\r\n this.gsRenderer = null;\r\n }\r\n }\r\n\r\n // ============================================\r\n // Splat 变换\r\n // ============================================\r\n\r\n /**\r\n * 设置 Splat 位置\r\n */\r\n setSplatPosition(x: number, y: number, z: number): void {\r\n this.gsRenderer?.setPosition(x, y, z);\r\n }\r\n\r\n /**\r\n * 获取 Splat 位置\r\n */\r\n getSplatPosition(): Vec3Tuple | null {\r\n return this.gsRenderer?.getPosition() ?? null;\r\n }\r\n\r\n /**\r\n * 设置 Splat 旋转\r\n */\r\n setSplatRotation(x: number, y: number, z: number): void {\r\n this.gsRenderer?.setRotation(x, y, z);\r\n }\r\n\r\n /**\r\n * 获取 Splat 旋转\r\n */\r\n getSplatRotation(): Vec3Tuple | null {\r\n return this.gsRenderer?.getRotation() ?? null;\r\n }\r\n\r\n /**\r\n * 设置 Splat 缩放\r\n */\r\n setSplatScale(x: number, y: number, z: number): void {\r\n this.gsRenderer?.setScale(x, y, z);\r\n }\r\n\r\n /**\r\n * 获取 Splat 缩放\r\n */\r\n getSplatScale(): Vec3Tuple | null {\r\n return this.gsRenderer?.getScale() ?? null;\r\n }\r\n\r\n // ============================================\r\n // SH 模式\r\n // ============================================\r\n\r\n /**\r\n * 设置 SH 模式\r\n */\r\n setSHMode(mode: 0 | 1 | 2 | 3): void {\r\n if (this.gsRenderer?.setSHMode) {\r\n this.gsRenderer.setSHMode(mode);\r\n }\r\n }\r\n\r\n /**\r\n * 获取当前 SH 模式\r\n */\r\n getSHMode(): number {\r\n return this.gsRenderer?.getSHMode?.() ?? 0;\r\n }\r\n\r\n // ============================================\r\n // Bounding Box 查询\r\n // ============================================\r\n\r\n /**\r\n * 获取 Mesh 的组合 bounding box\r\n */\r\n getBoundingBox(): BoundingBox | null {\r\n return this.meshRenderer.getCombinedBoundingBox();\r\n }\r\n\r\n /**\r\n * 获取 Splat 的 bounding box\r\n */\r\n getSplatBoundingBox(): BoundingBox | null {\r\n return this.gsRenderer?.getBoundingBox() ?? null;\r\n }\r\n\r\n /**\r\n * 获取指定 Mesh 范围的组合 bounding box\r\n */\r\n getMeshRangeBoundingBox(startIndex: number, count: number): BoundingBox | null {\r\n const meshes = this.getMeshRange(startIndex, count);\r\n if (meshes.length === 0) return null;\r\n\r\n let combinedMin: Vec3Tuple | null = null;\r\n let combinedMax: Vec3Tuple | null = null;\r\n\r\n for (const mesh of meshes) {\r\n const bbox = mesh.getWorldBoundingBox();\r\n if (!bbox) continue;\r\n\r\n if (combinedMin === null || combinedMax === null) {\r\n combinedMin = [...bbox.min];\r\n combinedMax = [...bbox.max];\r\n } else {\r\n combinedMin[0] = Math.min(combinedMin[0], bbox.min[0]);\r\n combinedMin[1] = Math.min(combinedMin[1], bbox.min[1]);\r\n combinedMin[2] = Math.min(combinedMin[2], bbox.min[2]);\r\n combinedMax[0] = Math.max(combinedMax[0], bbox.max[0]);\r\n combinedMax[1] = Math.max(combinedMax[1], bbox.max[1]);\r\n combinedMax[2] = Math.max(combinedMax[2], bbox.max[2]);\r\n }\r\n }\r\n\r\n if (combinedMin === null || combinedMax === null) return null;\r\n\r\n const center: Vec3Tuple = [\r\n (combinedMin[0] + combinedMax[0]) / 2,\r\n (combinedMin[1] + combinedMax[1]) / 2,\r\n (combinedMin[2] + combinedMax[2]) / 2,\r\n ];\r\n const dx = combinedMax[0] - combinedMin[0];\r\n const dy = combinedMax[1] - combinedMin[1];\r\n const dz = combinedMax[2] - combinedMin[2];\r\n const radius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min: combinedMin, max: combinedMax, center, radius };\r\n }\r\n\r\n /**\r\n * 获取整个场景的组合 bounding box\r\n */\r\n getSceneBoundingBox(): BoundingBox | null {\r\n let combinedMin: Vec3Tuple | null = null;\r\n let combinedMax: Vec3Tuple | null = null;\r\n\r\n // 1. 获取 Mesh 的 bounding box\r\n const meshBBox = this.getBoundingBox();\r\n if (meshBBox) {\r\n combinedMin = [meshBBox.min[0], meshBBox.min[1], meshBBox.min[2]];\r\n combinedMax = [meshBBox.max[0], meshBBox.max[1], meshBBox.max[2]];\r\n }\r\n\r\n // 2. 获取 Splat 的 bounding box\r\n const splatBBox = this.getSplatBoundingBox();\r\n if (splatBBox) {\r\n if (combinedMin === null || combinedMax === null) {\r\n combinedMin = [splatBBox.min[0], splatBBox.min[1], splatBBox.min[2]];\r\n combinedMax = [splatBBox.max[0], splatBBox.max[1], splatBBox.max[2]];\r\n } else {\r\n combinedMin[0] = Math.min(combinedMin[0], splatBBox.min[0]);\r\n combinedMin[1] = Math.min(combinedMin[1], splatBBox.min[1]);\r\n combinedMin[2] = Math.min(combinedMin[2], splatBBox.min[2]);\r\n combinedMax[0] = Math.max(combinedMax[0], splatBBox.max[0]);\r\n combinedMax[1] = Math.max(combinedMax[1], splatBBox.max[1]);\r\n combinedMax[2] = Math.max(combinedMax[2], splatBBox.max[2]);\r\n }\r\n }\r\n\r\n if (combinedMin === null || combinedMax === null) {\r\n return null;\r\n }\r\n\r\n const center: Vec3Tuple = [\r\n (combinedMin[0] + combinedMax[0]) / 2,\r\n (combinedMin[1] + combinedMax[1]) / 2,\r\n (combinedMin[2] + combinedMax[2]) / 2,\r\n ];\r\n const dx = combinedMax[0] - combinedMin[0];\r\n const dy = combinedMax[1] - combinedMin[1];\r\n const dz = combinedMax[2] - combinedMin[2];\r\n const radius = Math.sqrt(dx * dx + dy * dy + dz * dz) / 2;\r\n\r\n return { min: combinedMin, max: combinedMax, center, radius };\r\n }\r\n\r\n // ============================================\r\n // 材质颜色\r\n // ============================================\r\n\r\n /**\r\n * 获取指定索引 Mesh 的材质颜色\r\n */\r\n getMeshColor(index: number): [number, number, number, number] | null {\r\n return this.meshRenderer.getMeshColor(index);\r\n }\r\n\r\n /**\r\n * 设置指定索引 Mesh 的材质颜色\r\n */\r\n setMeshColor(index: number, r: number, g: number, b: number, a: number = 1): boolean {\r\n return this.meshRenderer.setMeshColor(index, r, g, b, a);\r\n }\r\n\r\n /**\r\n * 设置指定范围内所有 Mesh 的材质颜色\r\n */\r\n setMeshRangeColor(startIndex: number, count: number, r: number, g: number, b: number, a: number = 1): number {\r\n return this.meshRenderer.setMeshRangeColor(startIndex, count, r, g, b, a);\r\n }\r\n\r\n /**\r\n * 销毁场景管理器\r\n */\r\n destroy(): void {\r\n this.clearSplats();\r\n // 注意:meshRenderer 的销毁由 App 负责\r\n }\r\n}\r\n","/**\r\n * SplatTransformProxy - PLY/Splat 变换代理对象\r\n * 实现 TransformableObject 接口,让 TransformGizmo 可以操作 PLY 模型\r\n */\r\n\r\nimport type { TransformableObject, Vec3Tuple } from '../../types';\r\nimport type { IGSSplatRenderer } from '../../gs/IGSSplatRenderer';\r\n\r\nexport class SplatTransformProxy implements TransformableObject {\r\n position: Vec3Tuple;\r\n rotation: Vec3Tuple;\r\n scale: Vec3Tuple;\r\n\r\n private renderer: IGSSplatRenderer;\r\n private center: Vec3Tuple;\r\n\r\n constructor(renderer: IGSSplatRenderer, center: Vec3Tuple) {\r\n this.renderer = renderer;\r\n this.center = [...center];\r\n\r\n // 设置渲染器的 pivot 为包围盒中心\r\n renderer.setPivot(center[0], center[1], center[2]);\r\n\r\n // 初始化为当前渲染器的变换状态\r\n const pos = renderer.getPosition();\r\n const rot = renderer.getRotation();\r\n const scl = renderer.getScale();\r\n\r\n // Gizmo 位置 = 渲染器位置 + 中心点\r\n this.position = [\r\n pos[0] + center[0],\r\n pos[1] + center[1],\r\n pos[2] + center[2],\r\n ];\r\n this.rotation = [...rot];\r\n this.scale = [...scl];\r\n }\r\n\r\n setPosition(x: number, y: number, z: number): void {\r\n this.position = [x, y, z];\r\n // 渲染器位置 = Gizmo 位置 - 中心点\r\n this.renderer.setPosition(\r\n x - this.center[0],\r\n y - this.center[1],\r\n z - this.center[2]\r\n );\r\n }\r\n\r\n setRotation(x: number, y: number, z: number): void {\r\n this.rotation = [x, y, z];\r\n this.renderer.setRotation(x, y, z);\r\n }\r\n\r\n setScale(x: number, y: number, z: number): void {\r\n this.scale = [x, y, z];\r\n this.renderer.setScale(x, y, z);\r\n }\r\n}\r\n","/**\r\n * MeshGroupProxy - 多 Mesh 组变换代理对象\r\n * 让 TransformGizmo 可以同时操作多个 Mesh\r\n */\r\n\r\nimport type { TransformableObject, SimpleBoundingBox, Vec3Tuple } from '../../types';\r\nimport type { Mesh } from '../../mesh/Mesh';\r\n\r\nexport class MeshGroupProxy implements TransformableObject {\r\n position: Vec3Tuple;\r\n rotation: Vec3Tuple;\r\n scale: Vec3Tuple;\r\n\r\n private meshes: Mesh[];\r\n\r\n constructor(meshes: Mesh[]) {\r\n this.meshes = meshes;\r\n\r\n if (meshes.length > 0) {\r\n const firstMesh = meshes[0];\r\n this.position = [\r\n firstMesh.position[0],\r\n firstMesh.position[1],\r\n firstMesh.position[2],\r\n ];\r\n this.rotation = [\r\n firstMesh.rotation[0],\r\n firstMesh.rotation[1],\r\n firstMesh.rotation[2],\r\n ];\r\n this.scale = [\r\n firstMesh.scale[0],\r\n firstMesh.scale[1],\r\n firstMesh.scale[2],\r\n ];\r\n } else {\r\n this.position = [0, 0, 0];\r\n this.rotation = [0, 0, 0];\r\n this.scale = [1, 1, 1];\r\n }\r\n }\r\n\r\n setPosition(x: number, y: number, z: number): void {\r\n this.position = [x, y, z];\r\n for (const mesh of this.meshes) {\r\n mesh.setPosition(x, y, z);\r\n }\r\n }\r\n\r\n setRotation(x: number, y: number, z: number): void {\r\n this.rotation = [x, y, z];\r\n for (const mesh of this.meshes) {\r\n mesh.setRotation(x, y, z);\r\n }\r\n }\r\n\r\n setScale(x: number, y: number, z: number): void {\r\n this.scale = [x, y, z];\r\n for (const mesh of this.meshes) {\r\n mesh.setScale(x, y, z);\r\n }\r\n }\r\n\r\n /**\r\n * 获取组合包围盒\r\n */\r\n getBoundingBox(): SimpleBoundingBox | null {\r\n if (this.meshes.length === 0) return null;\r\n\r\n let combinedMin: Vec3Tuple | null = null;\r\n let combinedMax: Vec3Tuple | null = null;\r\n\r\n for (const mesh of this.meshes) {\r\n const bbox = mesh.getWorldBoundingBox();\r\n if (!bbox) continue;\r\n\r\n if (combinedMin === null || combinedMax === null) {\r\n combinedMin = [...bbox.min];\r\n combinedMax = [...bbox.max];\r\n } else {\r\n combinedMin[0] = Math.min(combinedMin[0], bbox.min[0]);\r\n combinedMin[1] = Math.min(combinedMin[1], bbox.min[1]);\r\n combinedMin[2] = Math.min(combinedMin[2], bbox.min[2]);\r\n combinedMax[0] = Math.max(combinedMax[0], bbox.max[0]);\r\n combinedMax[1] = Math.max(combinedMax[1], bbox.max[1]);\r\n combinedMax[2] = Math.max(combinedMax[2], bbox.max[2]);\r\n }\r\n }\r\n\r\n if (combinedMin === null || combinedMax === null) return null;\r\n\r\n return { min: combinedMin, max: combinedMax };\r\n }\r\n}\r\n","/**\r\n * SplatBoundingBoxProvider - PLY/Splat 包围盒提供者\r\n * 动态获取 PLY 的包围盒(考虑变换)\r\n */\r\n\r\nimport type { BoundingBoxProvider, SimpleBoundingBox, Vec3Tuple } from '../../types';\r\nimport type { IGSSplatRenderer } from '../../gs/IGSSplatRenderer';\r\n\r\nexport class SplatBoundingBoxProvider implements BoundingBoxProvider {\r\n private renderer: IGSSplatRenderer;\r\n\r\n constructor(renderer: IGSSplatRenderer) {\r\n this.renderer = renderer;\r\n }\r\n\r\n getBoundingBox(): SimpleBoundingBox | null {\r\n const bbox = this.renderer.getBoundingBox();\r\n if (!bbox) return null;\r\n\r\n // 获取变换参数\r\n const position = this.renderer.getPosition();\r\n const rotation = this.renderer.getRotation();\r\n const scale = this.renderer.getScale();\r\n const pivot = this.renderer.getPivot();\r\n\r\n // 获取本地包围盒的 8 个角点\r\n const corners: Vec3Tuple[] = [\r\n [bbox.min[0], bbox.min[1], bbox.min[2]],\r\n [bbox.max[0], bbox.min[1], bbox.min[2]],\r\n [bbox.min[0], bbox.max[1], bbox.min[2]],\r\n [bbox.max[0], bbox.max[1], bbox.min[2]],\r\n [bbox.min[0], bbox.min[1], bbox.max[2]],\r\n [bbox.max[0], bbox.min[1], bbox.max[2]],\r\n [bbox.min[0], bbox.max[1], bbox.max[2]],\r\n [bbox.max[0], bbox.max[1], bbox.max[2]],\r\n ];\r\n\r\n // 计算变换矩阵\r\n const [sx, sy, sz] = scale;\r\n const [rx, ry, rz] = rotation;\r\n const [tx, ty, tz] = position;\r\n const [px, py, pz] = pivot;\r\n\r\n const cx = Math.cos(rx), sx1 = Math.sin(rx);\r\n const cy = Math.cos(ry), sy1 = Math.sin(ry);\r\n const cz = Math.cos(rz), sz1 = Math.sin(rz);\r\n\r\n // 组合旋转矩阵 R = Rz * Ry * Rx\r\n const r00 = cy * cz;\r\n const r01 = sx1 * sy1 * cz - cx * sz1;\r\n const r02 = cx * sy1 * cz + sx1 * sz1;\r\n const r10 = cy * sz1;\r\n const r11 = sx1 * sy1 * sz1 + cx * cz;\r\n const r12 = cx * sy1 * sz1 - sx1 * cz;\r\n const r20 = -sy1;\r\n const r21 = sx1 * cy;\r\n const r22 = cx * cy;\r\n\r\n // RS 矩阵 (旋转 * 缩放)\r\n const rs00 = r00 * sx, rs01 = r01 * sy, rs02 = r02 * sz;\r\n const rs10 = r10 * sx, rs11 = r11 * sy, rs12 = r12 * sz;\r\n const rs20 = r20 * sx, rs21 = r21 * sy, rs22 = r22 * sz;\r\n\r\n // 计算 (I - RS) * pivot\r\n const dpx = px - (rs00 * px + rs01 * py + rs02 * pz);\r\n const dpy = py - (rs10 * px + rs11 * py + rs12 * pz);\r\n const dpz = pz - (rs20 * px + rs21 * py + rs22 * pz);\r\n\r\n // 最终平移 = position + (I - RS) * pivot\r\n const finalTx = tx + dpx;\r\n const finalTy = ty + dpy;\r\n const finalTz = tz + dpz;\r\n\r\n // 变换所有角点\r\n let minX = Infinity, minY = Infinity, minZ = Infinity;\r\n let maxX = -Infinity, maxY = -Infinity, maxZ = -Infinity;\r\n\r\n for (const [x, y, z] of corners) {\r\n const wx = rs00 * x + rs01 * y + rs02 * z + finalTx;\r\n const wy = rs10 * x + rs11 * y + rs12 * z + finalTy;\r\n const wz = rs20 * x + rs21 * y + rs22 * z + finalTz;\r\n\r\n minX = Math.min(minX, wx);\r\n minY = Math.min(minY, wy);\r\n minZ = Math.min(minZ, wz);\r\n maxX = Math.max(maxX, wx);\r\n maxY = Math.max(maxY, wy);\r\n maxZ = Math.max(maxZ, wz);\r\n }\r\n\r\n return {\r\n min: [minX, minY, minZ],\r\n max: [maxX, maxY, maxZ],\r\n };\r\n }\r\n}\r\n","/**\r\n * Vec3 - 3D Vector utility class\r\n * Provides vector operations for 3D mathematics\r\n */\r\nexport class Vec3 {\r\n x: number;\r\n y: number;\r\n z: number;\r\n\r\n constructor(x: number = 0, y: number = 0, z: number = 0) {\r\n this.x = x;\r\n this.y = y;\r\n this.z = z;\r\n }\r\n\r\n // Factory methods\r\n static fromArray(arr: Float32Array | number[], offset: number = 0): Vec3 {\r\n return new Vec3(arr[offset], arr[offset + 1], arr[offset + 2]);\r\n }\r\n\r\n static zero(): Vec3 {\r\n return new Vec3(0, 0, 0);\r\n }\r\n\r\n static one(): Vec3 {\r\n return new Vec3(1, 1, 1);\r\n }\r\n\r\n // Basic operations (return new Vec3)\r\n add(v: Vec3): Vec3 {\r\n return new Vec3(this.x + v.x, this.y + v.y, this.z + v.z);\r\n }\r\n\r\n subtract(v: Vec3): Vec3 {\r\n return new Vec3(this.x - v.x, this.y - v.y, this.z - v.z);\r\n }\r\n\r\n multiply(scalar: number): Vec3 {\r\n return new Vec3(this.x * scalar, this.y * scalar, this.z * scalar);\r\n }\r\n\r\n divide(scalar: number): Vec3 {\r\n return new Vec3(this.x / scalar, this.y / scalar, this.z / scalar);\r\n }\r\n\r\n // In-place operations (modify this)\r\n addInPlace(v: Vec3): Vec3 {\r\n this.x += v.x;\r\n this.y += v.y;\r\n this.z += v.z;\r\n return this;\r\n }\r\n\r\n subtractInPlace(v: Vec3): Vec3 {\r\n this.x -= v.x;\r\n this.y -= v.y;\r\n this.z -= v.z;\r\n return this;\r\n }\r\n\r\n multiplyInPlace(scalar: number): Vec3 {\r\n this.x *= scalar;\r\n this.y *= scalar;\r\n this.z *= scalar;\r\n return this;\r\n }\r\n\r\n // Vector operations\r\n dot(v: Vec3): number {\r\n return this.x * v.x + this.y * v.y + this.z * v.z;\r\n }\r\n\r\n cross(v: Vec3): Vec3 {\r\n return new Vec3(\r\n this.y * v.z - this.z * v.y,\r\n this.z * v.x - this.x * v.z,\r\n this.x * v.y - this.y * v.x,\r\n );\r\n }\r\n\r\n length(): number {\r\n return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);\r\n }\r\n\r\n lengthSquared(): number {\r\n return this.x * this.x + this.y * this.y + this.z * this.z;\r\n }\r\n\r\n distance(v: Vec3): number {\r\n const dx = this.x - v.x;\r\n const dy = this.y - v.y;\r\n const dz = this.z - v.z;\r\n return Math.sqrt(dx * dx + dy * dy + dz * dz);\r\n }\r\n\r\n distanceSquared(v: Vec3): number {\r\n const dx = this.x - v.x;\r\n const dy = this.y - v.y;\r\n const dz = this.z - v.z;\r\n return dx * dx + dy * dy + dz * dz;\r\n }\r\n\r\n // Normalization\r\n normalize(): Vec3 {\r\n const len = this.length();\r\n if (len < 1e-10) {\r\n // Handle zero-length vector - return default direction\r\n return new Vec3(0, 0, 1);\r\n }\r\n return new Vec3(this.x / len, this.y / len, this.z / len);\r\n }\r\n\r\n normalizeInPlace(): Vec3 {\r\n const len = this.length();\r\n if (len < 1e-10) {\r\n // Handle zero-length vector - set to default direction\r\n this.x = 0;\r\n this.y = 0;\r\n this.z = 1;\r\n return this;\r\n }\r\n this.x /= len;\r\n this.y /= len;\r\n this.z /= len;\r\n return this;\r\n }\r\n\r\n // Utility\r\n clone(): Vec3 {\r\n return new Vec3(this.x, this.y, this.z);\r\n }\r\n\r\n toArray(): [number, number, number] {\r\n return [this.x, this.y, this.z];\r\n }\r\n\r\n set(x: number, y: number, z: number): Vec3 {\r\n this.x = x;\r\n this.y = y;\r\n this.z = z;\r\n return this;\r\n }\r\n\r\n /**\r\n * Check if this vector equals another vector\r\n */\r\n equals(v: Vec3): boolean {\r\n return this.x === v.x && this.y === v.y && this.z === v.z;\r\n }\r\n\r\n /**\r\n * Check if this vector approximately equals another vector\r\n */\r\n equalsApprox(v: Vec3, epsilon: number = 1e-6): boolean {\r\n return (\r\n Math.abs(this.x - v.x) < epsilon &&\r\n Math.abs(this.y - v.y) < epsilon &&\r\n Math.abs(this.z - v.z) < epsilon\r\n );\r\n }\r\n}\r\n","import { Vec3 } from \"./Vec3\";\r\nimport { Camera } from \"../Camera\";\r\n\r\n/**\r\n * Ray - Ray utility class\r\n * Provides ray operations for 3D picking and intersection tests\r\n */\r\nexport class Ray {\r\n origin: Vec3;\r\n direction: Vec3; // Should be normalized\r\n\r\n constructor(origin: Vec3, direction: Vec3) {\r\n this.origin = origin;\r\n this.direction = direction;\r\n }\r\n\r\n /**\r\n * Create a ray from screen coordinates\r\n * @param screenX - Screen X coordinate (0 to canvasWidth)\r\n * @param screenY - Screen Y coordinate (0 to canvasHeight)\r\n * @param canvasWidth - Canvas width in pixels\r\n * @param canvasHeight - Canvas height in pixels\r\n * @param camera - Camera instance\r\n */\r\n static fromScreenPoint(\r\n screenX: number,\r\n screenY: number,\r\n canvasWidth: number,\r\n canvasHeight: number,\r\n camera: Camera,\r\n ): Ray {\r\n // Convert screen coordinates to normalized device coordinates (-1 to 1)\r\n const ndcX = (screenX / canvasWidth) * 2 - 1;\r\n const ndcY = -(screenY / canvasHeight) * 2 + 1; // Flip Y axis\r\n\r\n // Create inverse view-projection matrix\r\n const invViewProj = Ray.invertMatrix(camera.viewProjectionMatrix);\r\n\r\n // Transform NDC point to world space (near plane)\r\n const nearPoint = Ray.transformPoint(invViewProj, ndcX, ndcY, -1);\r\n const farPoint = Ray.transformPoint(invViewProj, ndcX, ndcY, 1);\r\n\r\n // Ray origin is camera position\r\n const origin = new Vec3(\r\n camera.position[0],\r\n camera.position[1],\r\n camera.position[2],\r\n );\r\n\r\n // Ray direction is from near to far point\r\n const direction = new Vec3(\r\n farPoint.x - nearPoint.x,\r\n farPoint.y - nearPoint.y,\r\n farPoint.z - nearPoint.z,\r\n ).normalize();\r\n\r\n return new Ray(origin, direction);\r\n }\r\n\r\n /**\r\n * Get point at distance along ray\r\n * @param distance - Distance along ray\r\n */\r\n at(distance: number): Vec3 {\r\n return new Vec3(\r\n this.origin.x + this.direction.x * distance,\r\n this.origin.y + this.direction.y * distance,\r\n this.origin.z + this.direction.z * distance,\r\n );\r\n }\r\n\r\n /**\r\n * Intersect ray with plane\r\n * @param planeOrigin - Point on the plane\r\n * @param planeNormal - Normal vector of the plane (should be normalized)\r\n * @returns Distance along ray to intersection, or null if parallel/no intersection\r\n */\r\n intersectPlane(planeOrigin: Vec3, planeNormal: Vec3): number | null {\r\n const denom = this.direction.dot(planeNormal);\r\n\r\n // Check if ray is parallel to plane\r\n if (Math.abs(denom) < 1e-6) {\r\n return null;\r\n }\r\n\r\n const t = planeOrigin.subtract(this.origin).dot(planeNormal) / denom;\r\n\r\n // Return null if intersection is behind ray origin\r\n if (t < 0) {\r\n return null;\r\n }\r\n\r\n return t;\r\n }\r\n\r\n /**\r\n * Compute distance from ray to a point\r\n * @param point - Point in 3D space\r\n */\r\n distanceToPoint(point: Vec3): number {\r\n const v = point.subtract(this.origin);\r\n const t = v.dot(this.direction);\r\n\r\n // If t < 0, closest point is the ray origin\r\n if (t < 0) {\r\n return this.origin.distance(point);\r\n }\r\n\r\n // Closest point on ray\r\n const closestPoint = this.at(t);\r\n return closestPoint.distance(point);\r\n }\r\n\r\n /**\r\n * Compute distance from ray to a line segment (for capsule hit testing)\r\n * @param segmentStart - Start point of line segment\r\n * @param segmentEnd - End point of line segment\r\n */\r\n distanceToSegment(segmentStart: Vec3, segmentEnd: Vec3): number {\r\n const segmentDir = segmentEnd.subtract(segmentStart);\r\n const segmentLength = segmentDir.length();\r\n\r\n // Handle degenerate segment (point)\r\n if (segmentLength < 1e-10) {\r\n return this.distanceToPoint(segmentStart);\r\n }\r\n\r\n const segmentDirNorm = segmentDir.divide(segmentLength);\r\n\r\n // Compute closest points between ray and line segment\r\n const w0 = this.origin.subtract(segmentStart);\r\n const a = this.direction.dot(this.direction);\r\n const b = this.direction.dot(segmentDirNorm);\r\n const c = segmentDirNorm.dot(segmentDirNorm);\r\n const d = this.direction.dot(w0);\r\n const e = segmentDirNorm.dot(w0);\r\n\r\n const denom = a * c - b * b;\r\n let t = 0; // Parameter on ray\r\n let s = 0; // Parameter on segment\r\n\r\n if (Math.abs(denom) < 1e-6) {\r\n // Ray and segment are parallel\r\n t = 0;\r\n s = e / c;\r\n } else {\r\n t = (b * e - c * d) / denom;\r\n s = (a * e - b * d) / denom;\r\n }\r\n\r\n // Clamp t to non-negative (ray starts at origin)\r\n t = Math.max(0, t);\r\n\r\n // Clamp s to segment bounds [0, segmentLength]\r\n s = Math.max(0, Math.min(segmentLength, s));\r\n\r\n const pointOnRay = this.at(t);\r\n const pointOnSegment = segmentStart.add(segmentDirNorm.multiply(s));\r\n\r\n return pointOnRay.distance(pointOnSegment);\r\n }\r\n\r\n /**\r\n * Clone this ray\r\n */\r\n clone(): Ray {\r\n return new Ray(this.origin.clone(), this.direction.clone());\r\n }\r\n\r\n /**\r\n * Transform ray by a matrix\r\n * @param matrix - Transformation matrix\r\n */\r\n transform(matrix: { transformPoint(v: Vec3): Vec3; transformVector(v: Vec3): Vec3 }): Ray {\r\n const newOrigin = matrix.transformPoint(this.origin);\r\n const newDirection = matrix.transformVector(this.direction).normalize();\r\n return new Ray(newOrigin, newDirection);\r\n }\r\n\r\n /**\r\n * Intersect ray with triangle using Möller–Trumbore algorithm\r\n * @param v0 - First vertex of triangle\r\n * @param v1 - Second vertex of triangle\r\n * @param v2 - Third vertex of triangle\r\n * @returns Distance to intersection, or null if no intersection\r\n */\r\n intersectTriangle(v0: Vec3, v1: Vec3, v2: Vec3): number | null {\r\n const EPSILON = 1e-6;\r\n \r\n const edge1 = v1.subtract(v0);\r\n const edge2 = v2.subtract(v0);\r\n \r\n const h = this.direction.cross(edge2);\r\n const a = edge1.dot(h);\r\n \r\n // Ray is parallel to triangle\r\n if (Math.abs(a) < EPSILON) {\r\n return null;\r\n }\r\n \r\n const f = 1.0 / a;\r\n const s = this.origin.subtract(v0);\r\n const u = f * s.dot(h);\r\n \r\n // Intersection is outside triangle\r\n if (u < 0.0 || u > 1.0) {\r\n return null;\r\n }\r\n \r\n const q = s.cross(edge1);\r\n const v = f * this.direction.dot(q);\r\n \r\n // Intersection is outside triangle\r\n if (v < 0.0 || u + v > 1.0) {\r\n return null;\r\n }\r\n \r\n const t = f * edge2.dot(q);\r\n \r\n // Intersection is behind ray origin\r\n if (t < EPSILON) {\r\n return null;\r\n }\r\n \r\n return t;\r\n }\r\n\r\n // Helper methods for matrix operations\r\n private static invertMatrix(m: Float32Array): Float32Array {\r\n const inv = new Float32Array(16);\r\n const e = m;\r\n\r\n inv[0] =\r\n e[5] * e[10] * e[15] -\r\n e[5] * e[11] * e[14] -\r\n e[9] * e[6] * e[15] +\r\n e[9] * e[7] * e[14] +\r\n e[13] * e[6] * e[11] -\r\n e[13] * e[7] * e[10];\r\n inv[4] =\r\n -e[4] * e[10] * e[15] +\r\n e[4] * e[11] * e[14] +\r\n e[8] * e[6] * e[15] -\r\n e[8] * e[7] * e[14] -\r\n e[12] * e[6] * e[11] +\r\n e[12] * e[7] * e[10];\r\n inv[8] =\r\n e[4] * e[9] * e[15] -\r\n e[4] * e[11] * e[13] -\r\n e[8] * e[5] * e[15] +\r\n e[8] * e[7] * e[13] +\r\n e[12] * e[5] * e[11] -\r\n e[12] * e[7] * e[9];\r\n inv[12] =\r\n -e[4] * e[9] * e[14] +\r\n e[4] * e[10] * e[13] +\r\n e[8] * e[5] * e[14] -\r\n e[8] * e[6] * e[13] -\r\n e[12] * e[5] * e[10] +\r\n e[12] * e[6] * e[9];\r\n\r\n inv[1] =\r\n -e[1] * e[10] * e[15] +\r\n e[1] * e[11] * e[14] +\r\n e[9] * e[2] * e[15] -\r\n e[9] * e[3] * e[14] -\r\n e[13] * e[2] * e[11] +\r\n e[13] * e[3] * e[10];\r\n inv[5] =\r\n e[0] * e[10] * e[15] -\r\n e[0] * e[11] * e[14] -\r\n e[8] * e[2] * e[15] +\r\n e[8] * e[3] * e[14] +\r\n e[12] * e[2] * e[11] -\r\n e[12] * e[3] * e[10];\r\n inv[9] =\r\n -e[0] * e[9] * e[15] +\r\n e[0] * e[11] * e[13] +\r\n e[8] * e[1] * e[15] -\r\n e[8] * e[3] * e[13] -\r\n e[12] * e[1] * e[11] +\r\n e[12] * e[3] * e[9];\r\n inv[13] =\r\n e[0] * e[9] * e[14] -\r\n e[0] * e[10] * e[13] -\r\n e[8] * e[1] * e[14] +\r\n e[8] * e[2] * e[13] +\r\n e[12] * e[1] * e[10] -\r\n e[12] * e[2] * e[9];\r\n\r\n inv[2] =\r\n e[1] * e[6] * e[15] -\r\n e[1] * e[7] * e[14] -\r\n e[5] * e[2] * e[15] +\r\n e[5] * e[3] * e[14] +\r\n e[13] * e[2] * e[7] -\r\n e[13] * e[3] * e[6];\r\n inv[6] =\r\n -e[0] * e[6] * e[15] +\r\n e[0] * e[7] * e[14] +\r\n e[4] * e[2] * e[15] -\r\n e[4] * e[3] * e[14] -\r\n e[12] * e[2] * e[7] +\r\n e[12] * e[3] * e[6];\r\n inv[10] =\r\n e[0] * e[5] * e[15] -\r\n e[0] * e[7] * e[13] -\r\n e[4] * e[1] * e[15] +\r\n e[4] * e[3] * e[13] +\r\n e[12] * e[1] * e[7] -\r\n e[12] * e[3] * e[5];\r\n inv[14] =\r\n -e[0] * e[5] * e[14] +\r\n e[0] * e[6] * e[13] +\r\n e[4] * e[1] * e[14] -\r\n e[4] * e[2] * e[13] -\r\n e[12] * e[1] * e[6] +\r\n e[12] * e[2] * e[5];\r\n\r\n inv[3] =\r\n -e[1] * e[6] * e[11] +\r\n e[1] * e[7] * e[10] +\r\n e[5] * e[2] * e[11] -\r\n e[5] * e[3] * e[10] -\r\n e[9] * e[2] * e[7] +\r\n e[9] * e[3] * e[6];\r\n inv[7] =\r\n e[0] * e[6] * e[11] -\r\n e[0] * e[7] * e[10] -\r\n e[4] * e[2] * e[11] +\r\n e[4] * e[3] * e[10] +\r\n e[8] * e[2] * e[7] -\r\n e[8] * e[3] * e[6];\r\n inv[11] =\r\n -e[0] * e[5] * e[11] +\r\n e[0] * e[7] * e[9] +\r\n e[4] * e[1] * e[11] -\r\n e[4] * e[3] * e[9] -\r\n e[8] * e[1] * e[7] +\r\n e[8] * e[3] * e[5];\r\n inv[15] =\r\n e[0] * e[5] * e[10] -\r\n e[0] * e[6] * e[9] -\r\n e[4] * e[1] * e[10] +\r\n e[4] * e[2] * e[9] +\r\n e[8] * e[1] * e[6] -\r\n e[8] * e[2] * e[5];\r\n\r\n const det = e[0] * inv[0] + e[1] * inv[4] + e[2] * inv[8] + e[3] * inv[12];\r\n\r\n if (Math.abs(det) < 1e-10) {\r\n // Return identity if singular\r\n const identity = new Float32Array(16);\r\n identity[0] = identity[5] = identity[10] = identity[15] = 1;\r\n return identity;\r\n }\r\n\r\n const invDet = 1.0 / det;\r\n const result = new Float32Array(16);\r\n for (let i = 0; i < 16; i++) {\r\n result[i] = inv[i] * invDet;\r\n }\r\n\r\n return result;\r\n }\r\n\r\n private static transformPoint(\r\n m: Float32Array,\r\n x: number,\r\n y: number,\r\n z: number,\r\n ): Vec3 {\r\n const w = m[3] * x + m[7] * y + m[11] * z + m[15];\r\n return new Vec3(\r\n (m[0] * x + m[4] * y + m[8] * z + m[12]) / w,\r\n (m[1] * x + m[5] * y + m[9] * z + m[13]) / w,\r\n (m[2] * x + m[6] * y + m[10] * z + m[14]) / w,\r\n );\r\n }\r\n}\r\n","import { Vec3 } from \"./Vec3\";\r\n\r\n/**\r\n * Quat - Quaternion utility class\r\n * Provides quaternion operations for 3D rotations\r\n */\r\nexport class Quat {\r\n x: number;\r\n y: number;\r\n z: number;\r\n w: number;\r\n\r\n constructor(x: number = 0, y: number = 0, z: number = 0, w: number = 1) {\r\n this.x = x;\r\n this.y = y;\r\n this.z = z;\r\n this.w = w;\r\n }\r\n\r\n // Factory methods\r\n static identity(): Quat {\r\n return new Quat(0, 0, 0, 1);\r\n }\r\n\r\n /**\r\n * Create quaternion from Euler angles (ZYX order)\r\n * @param x - Rotation around X axis in radians\r\n * @param y - Rotation around Y axis in radians\r\n * @param z - Rotation around Z axis in radians\r\n */\r\n static fromEuler(x: number, y: number, z: number): Quat {\r\n const cx = Math.cos(x * 0.5);\r\n const cy = Math.cos(y * 0.5);\r\n const cz = Math.cos(z * 0.5);\r\n const sx = Math.sin(x * 0.5);\r\n const sy = Math.sin(y * 0.5);\r\n const sz = Math.sin(z * 0.5);\r\n\r\n // ZYX order\r\n return new Quat(\r\n sx * cy * cz - cx * sy * sz,\r\n cx * sy * cz + sx * cy * sz,\r\n cx * cy * sz - sx * sy * cz,\r\n cx * cy * cz + sx * sy * sz,\r\n );\r\n }\r\n\r\n /**\r\n * Create quaternion from axis-angle representation\r\n * @param axis - Rotation axis (should be normalized)\r\n * @param angle - Rotation angle in radians\r\n */\r\n static fromAxisAngle(axis: Vec3, angle: number): Quat {\r\n const halfAngle = angle * 0.5;\r\n const s = Math.sin(halfAngle);\r\n return new Quat(axis.x * s, axis.y * s, axis.z * s, Math.cos(halfAngle));\r\n }\r\n\r\n // Operations\r\n /**\r\n * Multiply this quaternion by another (this * q)\r\n */\r\n multiply(q: Quat): Quat {\r\n return new Quat(\r\n this.w * q.x + this.x * q.w + this.y * q.z - this.z * q.y,\r\n this.w * q.y - this.x * q.z + this.y * q.w + this.z * q.x,\r\n this.w * q.z + this.x * q.y - this.y * q.x + this.z * q.w,\r\n this.w * q.w - this.x * q.x - this.y * q.y - this.z * q.z,\r\n );\r\n }\r\n\r\n /**\r\n * Convert quaternion to Euler angles (ZYX order)\r\n */\r\n toEuler(): Vec3 {\r\n // Roll (x-axis rotation)\r\n const sinr_cosp = 2 * (this.w * this.x + this.y * this.z);\r\n const cosr_cosp = 1 - 2 * (this.x * this.x + this.y * this.y);\r\n const roll = Math.atan2(sinr_cosp, cosr_cosp);\r\n\r\n // Pitch (y-axis rotation)\r\n const sinp = 2 * (this.w * this.y - this.z * this.x);\r\n let pitch: number;\r\n if (Math.abs(sinp) >= 1) {\r\n pitch = (Math.sign(sinp) * Math.PI) / 2; // Use 90 degrees if out of range\r\n } else {\r\n pitch = Math.asin(sinp);\r\n }\r\n\r\n // Yaw (z-axis rotation)\r\n const siny_cosp = 2 * (this.w * this.z + this.x * this.y);\r\n const cosy_cosp = 1 - 2 * (this.y * this.y + this.z * this.z);\r\n const yaw = Math.atan2(siny_cosp, cosy_cosp);\r\n\r\n return new Vec3(roll, pitch, yaw);\r\n }\r\n\r\n // Normalization\r\n normalize(): Quat {\r\n const len = Math.sqrt(\r\n this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w,\r\n );\r\n if (len < 1e-10) {\r\n return Quat.identity();\r\n }\r\n return new Quat(this.x / len, this.y / len, this.z / len, this.w / len);\r\n }\r\n\r\n normalizeInPlace(): Quat {\r\n const len = Math.sqrt(\r\n this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w,\r\n );\r\n if (len < 1e-10) {\r\n this.x = 0;\r\n this.y = 0;\r\n this.z = 0;\r\n this.w = 1;\r\n return this;\r\n }\r\n this.x /= len;\r\n this.y /= len;\r\n this.z /= len;\r\n this.w /= len;\r\n return this;\r\n }\r\n\r\n // Interpolation\r\n /**\r\n * Spherical linear interpolation between this quaternion and another\r\n * @param q - Target quaternion\r\n * @param t - Interpolation factor (0 to 1)\r\n */\r\n slerp(q: Quat, t: number): Quat {\r\n let dot = this.x * q.x + this.y * q.y + this.z * q.z + this.w * q.w;\r\n\r\n // If the dot product is negative, slerp won't take the shorter path\r\n // Fix by reversing one quaternion\r\n let q2 = q;\r\n if (dot < 0) {\r\n q2 = new Quat(-q.x, -q.y, -q.z, -q.w);\r\n dot = -dot;\r\n }\r\n\r\n // If quaternions are very close, use linear interpolation\r\n if (dot > 0.9995) {\r\n return new Quat(\r\n this.x + t * (q2.x - this.x),\r\n this.y + t * (q2.y - this.y),\r\n this.z + t * (q2.z - this.z),\r\n this.w + t * (q2.w - this.w),\r\n ).normalize();\r\n }\r\n\r\n // Calculate coefficients\r\n const theta = Math.acos(dot);\r\n const sinTheta = Math.sin(theta);\r\n const w1 = Math.sin((1 - t) * theta) / sinTheta;\r\n const w2 = Math.sin(t * theta) / sinTheta;\r\n\r\n return new Quat(\r\n this.x * w1 + q2.x * w2,\r\n this.y * w1 + q2.y * w2,\r\n this.z * w1 + q2.z * w2,\r\n this.w * w1 + q2.w * w2,\r\n );\r\n }\r\n\r\n // Utility\r\n clone(): Quat {\r\n return new Quat(this.x, this.y, this.z, this.w);\r\n }\r\n\r\n /**\r\n * Get the inverse (conjugate for unit quaternions) of this quaternion\r\n */\r\n inverse(): Quat {\r\n const lenSq = this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;\r\n if (lenSq < 1e-10) {\r\n return Quat.identity();\r\n }\r\n const invLen = 1.0 / lenSq;\r\n return new Quat(\r\n -this.x * invLen,\r\n -this.y * invLen,\r\n -this.z * invLen,\r\n this.w * invLen\r\n );\r\n }\r\n\r\n /**\r\n * Transform a vector by this quaternion\r\n * @param v - Vector to transform\r\n */\r\n transformVector(v: Vec3): Vec3 {\r\n // q * v * q^-1\r\n const qx = this.x, qy = this.y, qz = this.z, qw = this.w;\r\n const vx = v.x, vy = v.y, vz = v.z;\r\n\r\n // Calculate quat * vec\r\n const ix = qw * vx + qy * vz - qz * vy;\r\n const iy = qw * vy + qz * vx - qx * vz;\r\n const iz = qw * vz + qx * vy - qy * vx;\r\n const iw = -qx * vx - qy * vy - qz * vz;\r\n\r\n // Calculate result * inverse quat\r\n return new Vec3(\r\n ix * qw + iw * -qx + iy * -qz - iz * -qy,\r\n iy * qw + iw * -qy + iz * -qx - ix * -qz,\r\n iz * qw + iw * -qz + ix * -qy - iy * -qx\r\n );\r\n }\r\n}\r\n","import { Vec3 } from \"./Vec3\";\r\nimport { Quat } from \"./Quat\";\r\n\r\n/**\r\n * Mat4 - 4x4 Matrix utility class\r\n * Provides matrix operations for 3D transformations\r\n * Storage is column-major order (OpenGL/WebGPU convention)\r\n */\r\nexport class Mat4 {\r\n elements: Float32Array; // 16 elements, column-major order\r\n\r\n constructor() {\r\n this.elements = new Float32Array(16);\r\n }\r\n\r\n // Factory methods\r\n static identity(): Mat4 {\r\n const m = new Mat4();\r\n m.elements[0] = 1;\r\n m.elements[5] = 1;\r\n m.elements[10] = 1;\r\n m.elements[15] = 1;\r\n return m;\r\n }\r\n\r\n static fromTranslation(v: Vec3): Mat4 {\r\n const m = Mat4.identity();\r\n m.elements[12] = v.x;\r\n m.elements[13] = v.y;\r\n m.elements[14] = v.z;\r\n return m;\r\n }\r\n\r\n static fromRotation(q: Quat): Mat4 {\r\n const m = new Mat4();\r\n const e = m.elements;\r\n\r\n const x2 = q.x + q.x;\r\n const y2 = q.y + q.y;\r\n const z2 = q.z + q.z;\r\n const xx = q.x * x2;\r\n const xy = q.x * y2;\r\n const xz = q.x * z2;\r\n const yy = q.y * y2;\r\n const yz = q.y * z2;\r\n const zz = q.z * z2;\r\n const wx = q.w * x2;\r\n const wy = q.w * y2;\r\n const wz = q.w * z2;\r\n\r\n e[0] = 1 - (yy + zz);\r\n e[1] = xy + wz;\r\n e[2] = xz - wy;\r\n e[3] = 0;\r\n\r\n e[4] = xy - wz;\r\n e[5] = 1 - (xx + zz);\r\n e[6] = yz + wx;\r\n e[7] = 0;\r\n\r\n e[8] = xz + wy;\r\n e[9] = yz - wx;\r\n e[10] = 1 - (xx + yy);\r\n e[11] = 0;\r\n\r\n e[12] = 0;\r\n e[13] = 0;\r\n e[14] = 0;\r\n e[15] = 1;\r\n\r\n return m;\r\n }\r\n\r\n static fromScale(v: Vec3): Mat4 {\r\n const m = new Mat4();\r\n m.elements[0] = v.x;\r\n m.elements[5] = v.y;\r\n m.elements[10] = v.z;\r\n m.elements[15] = 1;\r\n return m;\r\n }\r\n\r\n static compose(position: Vec3, rotation: Quat, scale: Vec3): Mat4 {\r\n const m = Mat4.fromRotation(rotation);\r\n const e = m.elements;\r\n\r\n // Apply scale\r\n e[0] *= scale.x;\r\n e[1] *= scale.x;\r\n e[2] *= scale.x;\r\n e[4] *= scale.y;\r\n e[5] *= scale.y;\r\n e[6] *= scale.y;\r\n e[8] *= scale.z;\r\n e[9] *= scale.z;\r\n e[10] *= scale.z;\r\n\r\n // Apply translation\r\n e[12] = position.x;\r\n e[13] = position.y;\r\n e[14] = position.z;\r\n\r\n return m;\r\n }\r\n\r\n // Operations\r\n multiply(m: Mat4): Mat4 {\r\n const result = new Mat4();\r\n const a = this.elements;\r\n const b = m.elements;\r\n const r = result.elements;\r\n\r\n for (let i = 0; i < 4; i++) {\r\n for (let j = 0; j < 4; j++) {\r\n r[i * 4 + j] =\r\n a[j] * b[i * 4] +\r\n a[j + 4] * b[i * 4 + 1] +\r\n a[j + 8] * b[i * 4 + 2] +\r\n a[j + 12] * b[i * 4 + 3];\r\n }\r\n }\r\n\r\n return result;\r\n }\r\n\r\n multiplyInPlace(m: Mat4): Mat4 {\r\n const temp = this.multiply(m);\r\n this.elements.set(temp.elements);\r\n return this;\r\n }\r\n\r\n inverse(): Mat4 | null {\r\n const e = this.elements;\r\n const inv = new Float32Array(16);\r\n\r\n inv[0] =\r\n e[5] * e[10] * e[15] -\r\n e[5] * e[11] * e[14] -\r\n e[9] * e[6] * e[15] +\r\n e[9] * e[7] * e[14] +\r\n e[13] * e[6] * e[11] -\r\n e[13] * e[7] * e[10];\r\n inv[4] =\r\n -e[4] * e[10] * e[15] +\r\n e[4] * e[11] * e[14] +\r\n e[8] * e[6] * e[15] -\r\n e[8] * e[7] * e[14] -\r\n e[12] * e[6] * e[11] +\r\n e[12] * e[7] * e[10];\r\n inv[8] =\r\n e[4] * e[9] * e[15] -\r\n e[4] * e[11] * e[13] -\r\n e[8] * e[5] * e[15] +\r\n e[8] * e[7] * e[13] +\r\n e[12] * e[5] * e[11] -\r\n e[12] * e[7] * e[9];\r\n inv[12] =\r\n -e[4] * e[9] * e[14] +\r\n e[4] * e[10] * e[13] +\r\n e[8] * e[5] * e[14] -\r\n e[8] * e[6] * e[13] -\r\n e[12] * e[5] * e[10] +\r\n e[12] * e[6] * e[9];\r\n\r\n inv[1] =\r\n -e[1] * e[10] * e[15] +\r\n e[1] * e[11] * e[14] +\r\n e[9] * e[2] * e[15] -\r\n e[9] * e[3] * e[14] -\r\n e[13] * e[2] * e[11] +\r\n e[13] * e[3] * e[10];\r\n inv[5] =\r\n e[0] * e[10] * e[15] -\r\n e[0] * e[11] * e[14] -\r\n e[8] * e[2] * e[15] +\r\n e[8] * e[3] * e[14] +\r\n e[12] * e[2] * e[11] -\r\n e[12] * e[3] * e[10];\r\n inv[9] =\r\n -e[0] * e[9] * e[15] +\r\n e[0] * e[11] * e[13] +\r\n e[8] * e[1] * e[15] -\r\n e[8] * e[3] * e[13] -\r\n e[12] * e[1] * e[11] +\r\n e[12] * e[3] * e[9];\r\n inv[13] =\r\n e[0] * e[9] * e[14] -\r\n e[0] * e[10] * e[13] -\r\n e[8] * e[1] * e[14] +\r\n e[8] * e[2] * e[13] +\r\n e[12] * e[1] * e[10] -\r\n e[12] * e[2] * e[9];\r\n\r\n inv[2] =\r\n e[1] * e[6] * e[15] -\r\n e[1] * e[7] * e[14] -\r\n e[5] * e[2] * e[15] +\r\n e[5] * e[3] * e[14] +\r\n e[13] * e[2] * e[7] -\r\n e[13] * e[3] * e[6];\r\n inv[6] =\r\n -e[0] * e[6] * e[15] +\r\n e[0] * e[7] * e[14] +\r\n e[4] * e[2] * e[15] -\r\n e[4] * e[3] * e[14] -\r\n e[12] * e[2] * e[7] +\r\n e[12] * e[3] * e[6];\r\n inv[10] =\r\n e[0] * e[5] * e[15] -\r\n e[0] * e[7] * e[13] -\r\n e[4] * e[1] * e[15] +\r\n e[4] * e[3] * e[13] +\r\n e[12] * e[1] * e[7] -\r\n e[12] * e[3] * e[5];\r\n inv[14] =\r\n -e[0] * e[5] * e[14] +\r\n e[0] * e[6] * e[13] +\r\n e[4] * e[1] * e[14] -\r\n e[4] * e[2] * e[13] -\r\n e[12] * e[1] * e[6] +\r\n e[12] * e[2] * e[5];\r\n\r\n inv[3] =\r\n -e[1] * e[6] * e[11] +\r\n e[1] * e[7] * e[10] +\r\n e[5] * e[2] * e[11] -\r\n e[5] * e[3] * e[10] -\r\n e[9] * e[2] * e[7] +\r\n e[9] * e[3] * e[6];\r\n inv[7] =\r\n e[0] * e[6] * e[11] -\r\n e[0] * e[7] * e[10] -\r\n e[4] * e[2] * e[11] +\r\n e[4] * e[3] * e[10] +\r\n e[8] * e[2] * e[7] -\r\n e[8] * e[3] * e[6];\r\n inv[11] =\r\n -e[0] * e[5] * e[11] +\r\n e[0] * e[7] * e[9] +\r\n e[4] * e[1] * e[11] -\r\n e[4] * e[3] * e[9] -\r\n e[8] * e[1] * e[7] +\r\n e[8] * e[3] * e[5];\r\n inv[15] =\r\n e[0] * e[5] * e[10] -\r\n e[0] * e[6] * e[9] -\r\n e[4] * e[1] * e[10] +\r\n e[4] * e[2] * e[9] +\r\n e[8] * e[1] * e[6] -\r\n e[8] * e[2] * e[5];\r\n\r\n const det = e[0] * inv[0] + e[1] * inv[4] + e[2] * inv[8] + e[3] * inv[12];\r\n\r\n if (Math.abs(det) < 1e-10) {\r\n return null; // Matrix is singular\r\n }\r\n\r\n const invDet = 1.0 / det;\r\n const result = new Mat4();\r\n for (let i = 0; i < 16; i++) {\r\n result.elements[i] = inv[i] * invDet;\r\n }\r\n\r\n return result;\r\n }\r\n\r\n transpose(): Mat4 {\r\n const m = new Mat4();\r\n const e = this.elements;\r\n const r = m.elements;\r\n\r\n r[0] = e[0];\r\n r[1] = e[4];\r\n r[2] = e[8];\r\n r[3] = e[12];\r\n r[4] = e[1];\r\n r[5] = e[5];\r\n r[6] = e[9];\r\n r[7] = e[13];\r\n r[8] = e[2];\r\n r[9] = e[6];\r\n r[10] = e[10];\r\n r[11] = e[14];\r\n r[12] = e[3];\r\n r[13] = e[7];\r\n r[14] = e[11];\r\n r[15] = e[15];\r\n\r\n return m;\r\n }\r\n\r\n // Decomposition\r\n decompose(): { position: Vec3; rotation: Quat; scale: Vec3 } | null {\r\n const e = this.elements;\r\n\r\n // Extract translation\r\n const position = new Vec3(e[12], e[13], e[14]);\r\n\r\n // Extract scale\r\n const sx = Math.sqrt(e[0] * e[0] + e[1] * e[1] + e[2] * e[2]);\r\n const sy = Math.sqrt(e[4] * e[4] + e[5] * e[5] + e[6] * e[6]);\r\n const sz = Math.sqrt(e[8] * e[8] + e[9] * e[9] + e[10] * e[10]);\r\n\r\n const scale = new Vec3(sx, sy, sz);\r\n\r\n // Check for zero scale\r\n if (sx < 1e-10 || sy < 1e-10 || sz < 1e-10) {\r\n return null;\r\n }\r\n\r\n // Extract rotation by removing scale\r\n const m11 = e[0] / sx;\r\n const m12 = e[1] / sx;\r\n const m13 = e[2] / sx;\r\n const m21 = e[4] / sy;\r\n const m22 = e[5] / sy;\r\n const m23 = e[6] / sy;\r\n const m31 = e[8] / sz;\r\n const m32 = e[9] / sz;\r\n const m33 = e[10] / sz;\r\n\r\n // Convert rotation matrix to quaternion\r\n const trace = m11 + m22 + m33;\r\n let rotation: Quat;\r\n\r\n if (trace > 0) {\r\n const s = 0.5 / Math.sqrt(trace + 1.0);\r\n rotation = new Quat(\r\n (m23 - m32) * s,\r\n (m31 - m13) * s,\r\n (m12 - m21) * s,\r\n 0.25 / s,\r\n );\r\n } else if (m11 > m22 && m11 > m33) {\r\n const s = 2.0 * Math.sqrt(1.0 + m11 - m22 - m33);\r\n rotation = new Quat(\r\n 0.25 * s,\r\n (m21 + m12) / s,\r\n (m31 + m13) / s,\r\n (m23 - m32) / s,\r\n );\r\n } else if (m22 > m33) {\r\n const s = 2.0 * Math.sqrt(1.0 + m22 - m11 - m33);\r\n rotation = new Quat(\r\n (m21 + m12) / s,\r\n 0.25 * s,\r\n (m32 + m23) / s,\r\n (m31 - m13) / s,\r\n );\r\n } else {\r\n const s = 2.0 * Math.sqrt(1.0 + m33 - m11 - m22);\r\n rotation = new Quat(\r\n (m31 + m13) / s,\r\n (m32 + m23) / s,\r\n 0.25 * s,\r\n (m12 - m21) / s,\r\n );\r\n }\r\n\r\n return { position, rotation, scale };\r\n }\r\n\r\n // Transformation\r\n transformPoint(v: Vec3): Vec3 {\r\n const e = this.elements;\r\n const x = v.x;\r\n const y = v.y;\r\n const z = v.z;\r\n const w = e[3] * x + e[7] * y + e[11] * z + e[15];\r\n\r\n return new Vec3(\r\n (e[0] * x + e[4] * y + e[8] * z + e[12]) / w,\r\n (e[1] * x + e[5] * y + e[9] * z + e[13]) / w,\r\n (e[2] * x + e[6] * y + e[10] * z + e[14]) / w,\r\n );\r\n }\r\n\r\n transformDirection(v: Vec3): Vec3 {\r\n const e = this.elements;\r\n return new Vec3(\r\n e[0] * v.x + e[4] * v.y + e[8] * v.z,\r\n e[1] * v.x + e[5] * v.y + e[9] * v.z,\r\n e[2] * v.x + e[6] * v.y + e[10] * v.z,\r\n );\r\n }\r\n\r\n /**\r\n * Transform a vector (direction) by this matrix (ignores translation)\r\n * Alias for transformDirection for compatibility\r\n */\r\n transformVector(v: Vec3): Vec3 {\r\n return this.transformDirection(v);\r\n }\r\n\r\n /**\r\n * Returns the inverse of this matrix\r\n * Returns identity matrix if singular (non-invertible)\r\n */\r\n invert(): Mat4 {\r\n const result = this.inverse();\r\n if (result === null) {\r\n return Mat4.identity();\r\n }\r\n return result;\r\n }\r\n\r\n // Utility\r\n clone(): Mat4 {\r\n const m = new Mat4();\r\n m.elements.set(this.elements);\r\n return m;\r\n }\r\n}\r\n","import { Vec3 } from \"../math/Vec3\";\r\nimport { Ray } from \"../math/Ray\";\r\nimport { Mat4 } from \"../math/Mat4\";\r\nimport { Quat } from \"../math/Quat\";\r\n\r\n/**\r\n * GizmoAxis - 轴类型枚举\r\n */\r\nexport type GizmoAxisType = 'x' | 'y' | 'z' | 'xy' | 'xz' | 'yz' | 'xyz';\r\n\r\n/**\r\n * Vec4Color - 带透明度的颜色\r\n */\r\nexport interface Vec4Color {\r\n r: number;\r\n g: number;\r\n b: number;\r\n a: number;\r\n}\r\n\r\n/**\r\n * ShapeConfig - Shape 配置\r\n */\r\nexport interface ShapeConfig {\r\n axis: GizmoAxisType;\r\n defaultColor: Vec3;\r\n hoverColor: Vec3;\r\n disabledColor: Vec3;\r\n defaultAlpha?: number; // 默认透明度\r\n hoverAlpha?: number; // hover 透明度\r\n rotation?: Vec3; // 欧拉角旋转\r\n}\r\n\r\n/**\r\n * TriData - 三角形碰撞数据\r\n */\r\nexport interface TriData {\r\n vertices: Float32Array; // 三角形顶点\r\n indices: Uint16Array; // 索引\r\n transform: Mat4; // 局部变换矩阵\r\n priority: number; // 碰撞优先级(越高越优先)\r\n}\r\n\r\n/**\r\n * Shape - Gizmo 形状基类\r\n * 参考 PlayCanvas 引擎的 Shape 实现\r\n */\r\nexport abstract class Shape {\r\n axis: GizmoAxisType;\r\n \r\n // 状态\r\n protected _disabled: boolean = false;\r\n protected _visible: boolean = true;\r\n protected _hovered: boolean = false;\r\n protected _interactable: boolean = true; // 是否可交互(碰撞检测)\r\n \r\n // 颜色\r\n protected _defaultColor: Vec3;\r\n protected _hoverColor: Vec3;\r\n protected _disabledColor: Vec3;\r\n protected _defaultAlpha: number = 1.0;\r\n protected _hoverAlpha: number = 1.0;\r\n \r\n // 变换\r\n protected _position: Vec3 = new Vec3(0, 0, 0);\r\n protected _rotation: Vec3 = new Vec3(0, 0, 0); // 欧拉角\r\n protected _scale: Vec3 = new Vec3(1, 1, 1);\r\n \r\n // 碰撞数据\r\n triData: TriData[] = [];\r\n \r\n // GPU 资源\r\n protected device: GPUDevice | null = null;\r\n protected vertexBuffer: GPUBuffer | null = null;\r\n protected indexBuffer: GPUBuffer | null = null;\r\n protected vertexCount: number = 0;\r\n protected indexCount: number = 0;\r\n \r\n // 翻转状态(用于平面)\r\n flipped: Vec3 = new Vec3(0, 0, 0);\r\n \r\n constructor(config: ShapeConfig) {\r\n this.axis = config.axis;\r\n this._defaultColor = config.defaultColor.clone();\r\n this._hoverColor = config.hoverColor.clone();\r\n this._disabledColor = config.disabledColor.clone();\r\n this._defaultAlpha = config.defaultAlpha ?? 1.0;\r\n this._hoverAlpha = config.hoverAlpha ?? 1.0;\r\n \r\n if (config.rotation) {\r\n this._rotation = config.rotation.clone();\r\n }\r\n }\r\n \r\n get disabled(): boolean {\r\n return this._disabled;\r\n }\r\n \r\n set disabled(value: boolean) {\r\n this._disabled = value;\r\n if (value) {\r\n this._hovered = false;\r\n }\r\n }\r\n \r\n get visible(): boolean {\r\n return this._visible;\r\n }\r\n \r\n set visible(value: boolean) {\r\n this._visible = value;\r\n // 默认情况下,visible 也控制 interactable\r\n // 但可以单独设置 interactable 来覆盖\r\n }\r\n \r\n get interactable(): boolean {\r\n return this._interactable;\r\n }\r\n \r\n set interactable(value: boolean) {\r\n this._interactable = value;\r\n }\r\n \r\n /**\r\n * 设置 hover 状态\r\n */\r\n hover(state: boolean): void {\r\n if (this._disabled) {\r\n this._hovered = false;\r\n return;\r\n }\r\n this._hovered = state;\r\n }\r\n \r\n /**\r\n * 获取当前颜色(包含透明度)\r\n */\r\n getColor(): Vec4Color {\r\n if (this._disabled) {\r\n return { r: this._disabledColor.x, g: this._disabledColor.y, b: this._disabledColor.z, a: 1.0 };\r\n }\r\n if (this._hovered) {\r\n return { r: this._hoverColor.x, g: this._hoverColor.y, b: this._hoverColor.z, a: this._hoverAlpha };\r\n }\r\n return { r: this._defaultColor.x, g: this._defaultColor.y, b: this._defaultColor.z, a: this._defaultAlpha };\r\n }\r\n \r\n /**\r\n * 获取局部变换矩阵\r\n */\r\n getLocalTransform(): Mat4 {\r\n // 将欧拉角(度)转换为弧度\r\n const rotX = this._rotation.x * Math.PI / 180;\r\n const rotY = this._rotation.y * Math.PI / 180;\r\n const rotZ = this._rotation.z * Math.PI / 180;\r\n \r\n const rotation = Quat.fromEuler(rotX, rotY, rotZ);\r\n \r\n // Debug: 输出旋转信息\r\n // console.log(`Shape ${this.axis} rotation (deg):`, this._rotation);\r\n // console.log(`Shape ${this.axis} rotation (rad):`, rotX, rotY, rotZ);\r\n // console.log(`Shape ${this.axis} quaternion:`, rotation);\r\n \r\n return Mat4.compose(this._position, rotation, this._scale);\r\n }\r\n \r\n /**\r\n * 射线碰撞检测\r\n * @param ray - 世界空间射线\r\n * @param parentTransform - 父级变换矩阵(gizmo 的世界变换)\r\n * @returns 碰撞距离,null 表示未碰撞\r\n */\r\n intersect(ray: Ray, parentTransform: Mat4): number | null {\r\n // disabled 或 不可交互时跳过碰撞检测\r\n if (this._disabled || !this._interactable) {\r\n return null;\r\n }\r\n \r\n let closestDist: number | null = null;\r\n let highestPriority = -Infinity;\r\n \r\n for (const tri of this.triData) {\r\n // 计算完整变换:parent * local * triTransform\r\n const localTransform = this.getLocalTransform();\r\n const worldTransform = parentTransform.multiply(localTransform).multiply(tri.transform);\r\n const invTransform = worldTransform.invert();\r\n \r\n // 将射线变换到局部空间\r\n const localRay = ray.transform(invTransform);\r\n \r\n // 与三角形进行碰撞检测\r\n const dist = this.intersectTriangles(localRay, tri.vertices, tri.indices);\r\n \r\n if (dist !== null) {\r\n // 考虑优先级\r\n if (tri.priority > highestPriority || \r\n (tri.priority === highestPriority && (closestDist === null || dist < closestDist))) {\r\n closestDist = dist;\r\n highestPriority = tri.priority;\r\n }\r\n }\r\n }\r\n \r\n return closestDist;\r\n }\r\n \r\n /**\r\n * 射线与三角形列表碰撞检测\r\n */\r\n protected intersectTriangles(\r\n ray: Ray, \r\n vertices: Float32Array, \r\n indices: Uint16Array\r\n ): number | null {\r\n let closestDist: number | null = null;\r\n \r\n for (let i = 0; i < indices.length; i += 3) {\r\n const i0 = indices[i] * 3;\r\n const i1 = indices[i + 1] * 3;\r\n const i2 = indices[i + 2] * 3;\r\n \r\n const v0 = new Vec3(vertices[i0], vertices[i0 + 1], vertices[i0 + 2]);\r\n const v1 = new Vec3(vertices[i1], vertices[i1 + 1], vertices[i1 + 2]);\r\n const v2 = new Vec3(vertices[i2], vertices[i2 + 1], vertices[i2 + 2]);\r\n \r\n const dist = ray.intersectTriangle(v0, v1, v2);\r\n \r\n if (dist !== null && dist > 0) {\r\n if (closestDist === null || dist < closestDist) {\r\n closestDist = dist;\r\n }\r\n }\r\n }\r\n \r\n return closestDist;\r\n }\r\n \r\n /**\r\n * 创建 GPU 资源\r\n */\r\n abstract createGeometry(device: GPUDevice): void;\r\n \r\n /**\r\n * 获取顶点缓冲区\r\n */\r\n getVertexBuffer(): GPUBuffer | null {\r\n return this.vertexBuffer;\r\n }\r\n \r\n /**\r\n * 获取索引缓冲区\r\n */\r\n getIndexBuffer(): GPUBuffer | null {\r\n return this.indexBuffer;\r\n }\r\n \r\n /**\r\n * 获取索引数量\r\n */\r\n getIndexCount(): number {\r\n return this.indexCount;\r\n }\r\n \r\n /**\r\n * 销毁 GPU 资源\r\n */\r\n destroy(): void {\r\n if (this.vertexBuffer) {\r\n this.vertexBuffer.destroy();\r\n this.vertexBuffer = null;\r\n }\r\n if (this.indexBuffer) {\r\n this.indexBuffer.destroy();\r\n this.indexBuffer = null;\r\n }\r\n }\r\n \r\n /**\r\n * 创建 GPU 缓冲区\r\n */\r\n protected createBuffers(\r\n device: GPUDevice,\r\n vertices: Float32Array,\r\n indices: Uint16Array\r\n ): void {\r\n this.device = device;\r\n this.vertexCount = vertices.length / 6;\r\n this.indexCount = indices.length;\r\n \r\n // 创建顶点缓冲区\r\n this.vertexBuffer = device.createBuffer({\r\n size: vertices.byteLength,\r\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\r\n mappedAtCreation: true,\r\n });\r\n new Float32Array(this.vertexBuffer.getMappedRange()).set(vertices);\r\n this.vertexBuffer.unmap();\r\n \r\n // 创建索引缓冲区\r\n this.indexBuffer = device.createBuffer({\r\n size: indices.byteLength,\r\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\r\n mappedAtCreation: true,\r\n });\r\n new Uint16Array(this.indexBuffer.getMappedRange()).set(indices);\r\n this.indexBuffer.unmap();\r\n }\r\n}\r\n","import { Vec3 } from \"../math/Vec3\";\r\nimport { Mat4 } from \"../math/Mat4\";\r\nimport { Quat } from \"../math/Quat\";\r\nimport { Shape, ShapeConfig, TriData } from \"./Shape\";\r\n\r\n/**\r\n * ArrowShapeConfig - 箭头形状配置\r\n */\r\nexport interface ArrowShapeConfig extends ShapeConfig {\r\n gap?: number; // 箭头起点与中心的间距\r\n lineThickness?: number; // 线条粗细\r\n lineLength?: number; // 线条长度\r\n arrowThickness?: number;// 箭头粗细\r\n arrowLength?: number; // 箭头长度\r\n tolerance?: number; // 碰撞检测容差\r\n}\r\n\r\n/**\r\n * ArrowShape - 箭头形状(用于平移 Gizmo)\r\n * 参考 PlayCanvas 引擎的 ArrowShape 实现\r\n */\r\nexport class ArrowShape extends Shape {\r\n private _gap: number = 0;\r\n private _lineThickness: number = 0.02;\r\n private _lineLength: number = 0.5;\r\n private _arrowThickness: number = 0.12;\r\n private _arrowLength: number = 0.18;\r\n private _tolerance: number = 0.1;\r\n \r\n constructor(config: ArrowShapeConfig) {\r\n super(config);\r\n \r\n this._gap = config.gap ?? this._gap;\r\n this._lineThickness = config.lineThickness ?? this._lineThickness;\r\n this._lineLength = config.lineLength ?? this._lineLength;\r\n this._arrowThickness = config.arrowThickness ?? this._arrowThickness;\r\n this._arrowLength = config.arrowLength ?? this._arrowLength;\r\n this._tolerance = config.tolerance ?? this._tolerance;\r\n \r\n this._updateTriData();\r\n }\r\n \r\n get gap(): number { return this._gap; }\r\n set gap(value: number) { this._gap = value; this._updateTriData(); }\r\n \r\n get lineThickness(): number { return this._lineThickness; }\r\n set lineThickness(value: number) { this._lineThickness = value; this._updateTriData(); }\r\n \r\n get lineLength(): number { return this._lineLength; }\r\n set lineLength(value: number) { this._lineLength = value; this._updateTriData(); }\r\n \r\n get arrowThickness(): number { return this._arrowThickness; }\r\n set arrowThickness(value: number) { this._arrowThickness = value; this._updateTriData(); }\r\n \r\n get arrowLength(): number { return this._arrowLength; }\r\n set arrowLength(value: number) { this._arrowLength = value; this._updateTriData(); }\r\n \r\n /**\r\n * 更新碰撞数据\r\n */\r\n private _updateTriData(): void {\r\n // 箭头锥体碰撞数据\r\n const conePos = new Vec3(0, this._gap + this._arrowLength * 0.5 + this._lineLength, 0);\r\n const coneScale = new Vec3(this._arrowThickness, this._arrowLength, this._arrowThickness);\r\n const coneTransform = Mat4.compose(conePos, Quat.identity(), coneScale);\r\n \r\n // 线条圆柱碰撞数据(加上容差)\r\n const linePos = new Vec3(0, this._gap + this._lineLength * 0.5, 0);\r\n const lineScale = new Vec3(\r\n this._lineThickness + this._tolerance,\r\n this._lineLength,\r\n this._lineThickness + this._tolerance\r\n );\r\n const lineTransform = Mat4.compose(linePos, Quat.identity(), lineScale);\r\n \r\n // 生成单位锥体和圆柱的三角形数据\r\n const coneGeo = this.createConeGeometry();\r\n const cylinderGeo = this.createCylinderGeometry();\r\n \r\n this.triData = [\r\n {\r\n vertices: coneGeo.vertices,\r\n indices: coneGeo.indices,\r\n transform: coneTransform,\r\n priority: 0\r\n },\r\n {\r\n vertices: cylinderGeo.vertices,\r\n indices: cylinderGeo.indices,\r\n transform: lineTransform,\r\n priority: 1 // 线条优先级更高,更容易选中\r\n }\r\n ];\r\n }\r\n \r\n /**\r\n * 创建单位锥体几何体(底面半径1,高度1,底面在y=0,顶点在y=1)\r\n */\r\n private createConeGeometry(): { vertices: Float32Array; indices: Uint16Array } {\r\n const segments = 12;\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n \r\n // 底面中心\r\n vertices.push(0, -0.5, 0);\r\n \r\n // 底面顶点\r\n for (let i = 0; i <= segments; i++) {\r\n const angle = (i / segments) * Math.PI * 2;\r\n vertices.push(Math.cos(angle) * 0.5, -0.5, Math.sin(angle) * 0.5);\r\n }\r\n \r\n // 顶点\r\n const tipIndex = vertices.length / 3;\r\n vertices.push(0, 0.5, 0);\r\n \r\n // 底面三角形\r\n for (let i = 1; i <= segments; i++) {\r\n indices.push(0, i + 1, i);\r\n }\r\n \r\n // 侧面三角形\r\n for (let i = 1; i <= segments; i++) {\r\n indices.push(i, i + 1, tipIndex);\r\n }\r\n \r\n return {\r\n vertices: new Float32Array(vertices),\r\n indices: new Uint16Array(indices)\r\n };\r\n }\r\n \r\n /**\r\n * 创建单位圆柱几何体(半径1,高度1,中心在原点)\r\n */\r\n private createCylinderGeometry(): { vertices: Float32Array; indices: Uint16Array } {\r\n const segments = 12;\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n \r\n // 底面和顶面顶点\r\n for (let i = 0; i <= segments; i++) {\r\n const angle = (i / segments) * Math.PI * 2;\r\n const x = Math.cos(angle) * 0.5;\r\n const z = Math.sin(angle) * 0.5;\r\n \r\n // 底面\r\n vertices.push(x, -0.5, z);\r\n // 顶面\r\n vertices.push(x, 0.5, z);\r\n }\r\n \r\n // 侧面三角形\r\n for (let i = 0; i < segments; i++) {\r\n const base = i * 2;\r\n indices.push(base, base + 1, base + 2);\r\n indices.push(base + 1, base + 3, base + 2);\r\n }\r\n \r\n return {\r\n vertices: new Float32Array(vertices),\r\n indices: new Uint16Array(indices)\r\n };\r\n }\r\n \r\n /**\r\n * 创建渲染用的 GPU 几何体\r\n */\r\n createGeometry(device: GPUDevice): void {\r\n const segments = 12;\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n \r\n const color = this._defaultColor;\r\n \r\n // 辅助函数:添加顶点\r\n const addVertex = (x: number, y: number, z: number) => {\r\n vertices.push(x, y, z, color.x, color.y, color.z);\r\n };\r\n \r\n // 计算垂直向量\r\n let perpX: Vec3, perpY: Vec3;\r\n const dir = new Vec3(0, 1, 0); // 默认沿 Y 轴\r\n perpX = new Vec3(1, 0, 0);\r\n perpY = new Vec3(0, 0, 1);\r\n \r\n // 生成圆柱(线条部分)\r\n const cylinderStart = this._gap;\r\n const cylinderEnd = this._gap + this._lineLength;\r\n \r\n for (let i = 0; i <= segments; i++) {\r\n const angle = (i / segments) * Math.PI * 2;\r\n const cos = Math.cos(angle);\r\n const sin = Math.sin(angle);\r\n \r\n const offsetX = cos * this._lineThickness;\r\n const offsetZ = sin * this._lineThickness;\r\n \r\n // 底部顶点\r\n addVertex(offsetX, cylinderStart, offsetZ);\r\n // 顶部顶点\r\n addVertex(offsetX, cylinderEnd, offsetZ);\r\n }\r\n \r\n // 圆柱索引\r\n for (let i = 0; i < segments; i++) {\r\n const base = i * 2;\r\n indices.push(base, base + 1, base + 2);\r\n indices.push(base + 1, base + 3, base + 2);\r\n }\r\n \r\n // 生成锥体(箭头部分)\r\n const coneBase = this._gap + this._lineLength;\r\n const coneTip = coneBase + this._arrowLength;\r\n \r\n const coneBaseIndex = vertices.length / 6;\r\n \r\n // 锥体底面顶点\r\n for (let i = 0; i <= segments; i++) {\r\n const angle = (i / segments) * Math.PI * 2;\r\n const cos = Math.cos(angle);\r\n const sin = Math.sin(angle);\r\n \r\n const offsetX = cos * this._arrowThickness;\r\n const offsetZ = sin * this._arrowThickness;\r\n \r\n addVertex(offsetX, coneBase, offsetZ);\r\n }\r\n \r\n // 锥体顶点\r\n const coneTipIndex = vertices.length / 6;\r\n addVertex(0, coneTip, 0);\r\n \r\n // 锥体索引\r\n for (let i = 0; i < segments; i++) {\r\n indices.push(coneBaseIndex + i, coneTipIndex, coneBaseIndex + i + 1);\r\n }\r\n \r\n this.createBuffers(device, new Float32Array(vertices), new Uint16Array(indices));\r\n }\r\n}\r\n","import { Vec3 } from \"../math/Vec3\";\r\nimport { Mat4 } from \"../math/Mat4\";\r\nimport { Quat } from \"../math/Quat\";\r\nimport { Shape, ShapeConfig } from \"./Shape\";\r\n\r\n/**\r\n * PlaneShapeConfig - 平面形状配置\r\n */\r\nexport interface PlaneShapeConfig extends ShapeConfig {\r\n size?: number; // 平面大小\r\n gap?: number; // 与中心的间距\r\n}\r\n\r\n/**\r\n * PlaneShape - 平面形状(用于双轴平移)\r\n * 参考 PlayCanvas 引擎的 PlaneShape 实现\r\n */\r\nexport class PlaneShape extends Shape {\r\n private _size: number = 0.2;\r\n private _gap: number = 0.1;\r\n \r\n // 缓存不同翻转状态的几何数据\r\n private _geometryCache: Map<string, { vertexBuffer: GPUBuffer; indexBuffer: GPUBuffer }> = new Map();\r\n private _currentFlipKey: string = '0,0,0';\r\n \r\n constructor(config: PlaneShapeConfig) {\r\n super(config);\r\n \r\n this._size = config.size ?? this._size;\r\n this._gap = config.gap ?? this._gap;\r\n \r\n this._updateTriData();\r\n }\r\n \r\n get size(): number { return this._size; }\r\n set size(value: number) { \r\n this._size = value; \r\n this._updateTriData(); \r\n this._clearGeometryCache();\r\n }\r\n \r\n get gap(): number { return this._gap; }\r\n set gap(value: number) { \r\n this._gap = value; \r\n this._updateTriData(); \r\n this._clearGeometryCache();\r\n }\r\n \r\n /**\r\n * 更新碰撞数据\r\n */\r\n private _updateTriData(): void {\r\n const planeGeo = this.createPlaneGeometry();\r\n \r\n // 平面位置(考虑翻转)\r\n const pos = new Vec3(\r\n (this._gap + this._size * 0.5) * (1 - this.flipped.x * 2),\r\n 0,\r\n (this._gap + this._size * 0.5) * (1 - this.flipped.z * 2)\r\n );\r\n \r\n const scale = new Vec3(this._size, 1, this._size);\r\n const transform = Mat4.compose(pos, Quat.identity(), scale);\r\n \r\n this.triData = [{\r\n vertices: planeGeo.vertices,\r\n indices: planeGeo.indices,\r\n transform: transform,\r\n priority: 2\r\n }];\r\n }\r\n \r\n /**\r\n * 创建单位平面几何体\r\n */\r\n private createPlaneGeometry(): { vertices: Float32Array; indices: Uint16Array } {\r\n const vertices = new Float32Array([\r\n -0.5, 0, -0.5,\r\n 0.5, 0, -0.5,\r\n 0.5, 0, 0.5,\r\n -0.5, 0, 0.5\r\n ]);\r\n \r\n const indices = new Uint16Array([\r\n 0, 1, 2,\r\n 0, 2, 3,\r\n 0, 2, 1,\r\n 0, 3, 2\r\n ]);\r\n \r\n return { vertices, indices };\r\n }\r\n \r\n /**\r\n * 创建渲染用的 GPU 几何体\r\n */\r\n createGeometry(device: GPUDevice): void {\r\n this.device = device;\r\n this._currentFlipKey = `${this.flipped.x},${this.flipped.y},${this.flipped.z}`;\r\n \r\n // 检查缓存\r\n if (this._geometryCache.has(this._currentFlipKey)) {\r\n const cached = this._geometryCache.get(this._currentFlipKey)!;\r\n this.vertexBuffer = cached.vertexBuffer;\r\n this.indexBuffer = cached.indexBuffer;\r\n this.indexCount = 12;\r\n return;\r\n }\r\n \r\n const color = this._defaultColor;\r\n \r\n // 计算平面位置(考虑翻转)\r\n const offsetX = (this._gap + this._size * 0.5) * (1 - this.flipped.x * 2);\r\n const offsetZ = (this._gap + this._size * 0.5) * (1 - this.flipped.z * 2);\r\n const halfSize = this._size * 0.5;\r\n \r\n const vertices = new Float32Array([\r\n offsetX - halfSize, 0, offsetZ - halfSize, color.x, color.y, color.z,\r\n offsetX + halfSize, 0, offsetZ - halfSize, color.x, color.y, color.z,\r\n offsetX + halfSize, 0, offsetZ + halfSize, color.x, color.y, color.z,\r\n offsetX - halfSize, 0, offsetZ + halfSize, color.x, color.y, color.z,\r\n ]);\r\n \r\n const indices = new Uint16Array([\r\n 0, 1, 2,\r\n 0, 2, 3,\r\n 0, 2, 1,\r\n 0, 3, 2\r\n ]);\r\n \r\n this.createBuffers(device, vertices, indices);\r\n \r\n // 缓存\r\n if (this.vertexBuffer && this.indexBuffer) {\r\n this._geometryCache.set(this._currentFlipKey, {\r\n vertexBuffer: this.vertexBuffer,\r\n indexBuffer: this.indexBuffer\r\n });\r\n }\r\n }\r\n \r\n /**\r\n * 清除几何缓存\r\n */\r\n private _clearGeometryCache(): void {\r\n for (const cached of this._geometryCache.values()) {\r\n cached.vertexBuffer.destroy();\r\n cached.indexBuffer.destroy();\r\n }\r\n this._geometryCache.clear();\r\n this.vertexBuffer = null;\r\n this.indexBuffer = null;\r\n }\r\n \r\n /**\r\n * 更新翻转状态\r\n */\r\n setFlipped(newFlipped: Vec3): void {\r\n const newKey = `${newFlipped.x},${newFlipped.y},${newFlipped.z}`;\r\n if (this._currentFlipKey === newKey) return;\r\n \r\n this.flipped = newFlipped.clone();\r\n this._updateTriData();\r\n \r\n if (this.device) {\r\n this._currentFlipKey = newKey;\r\n \r\n // 检查缓存\r\n if (this._geometryCache.has(newKey)) {\r\n const cached = this._geometryCache.get(newKey)!;\r\n this.vertexBuffer = cached.vertexBuffer;\r\n this.indexBuffer = cached.indexBuffer;\r\n } else {\r\n // 创建新的几何体\r\n this.createGeometry(this.device);\r\n }\r\n }\r\n }\r\n \r\n /**\r\n * 销毁 GPU 资源\r\n */\r\n override destroy(): void {\r\n this._clearGeometryCache();\r\n super.destroy();\r\n }\r\n}\r\n","import { Vec3 } from \"../math/Vec3\";\r\nimport { Mat4 } from \"../math/Mat4\";\r\nimport { Quat } from \"../math/Quat\";\r\nimport { Shape, ShapeConfig, TriData } from \"./Shape\";\r\n\r\n/**\r\n * SphereShapeConfig - 球体形状配置\r\n */\r\nexport interface SphereShapeConfig extends ShapeConfig {\r\n radius?: number; // 球体半径\r\n}\r\n\r\n/**\r\n * SphereShape - 球体形状(用于统一缩放/中心选择)\r\n * 参考 PlayCanvas 引擎的 SphereShape 实现\r\n */\r\nexport class SphereShape extends Shape {\r\n private _radius: number = 0.1;\r\n \r\n constructor(config: SphereShapeConfig) {\r\n super(config);\r\n \r\n this._radius = config.radius ?? this._radius;\r\n \r\n this._updateTriData();\r\n }\r\n \r\n get radius(): number { return this._radius; }\r\n set radius(value: number) { this._radius = value; this._updateTriData(); }\r\n \r\n /**\r\n * 更新碰撞数据\r\n */\r\n private _updateTriData(): void {\r\n const sphereGeo = this.createSphereGeometry(8, 6);\r\n \r\n const scale = new Vec3(this._radius * 2, this._radius * 2, this._radius * 2);\r\n const transform = Mat4.compose(new Vec3(0, 0, 0), Quat.identity(), scale);\r\n \r\n this.triData = [{\r\n vertices: sphereGeo.vertices,\r\n indices: sphereGeo.indices,\r\n transform: transform,\r\n priority: 3 // 中心球优先级最高\r\n }];\r\n }\r\n \r\n /**\r\n * 创建单位球体几何体(半径0.5,中心在原点)\r\n */\r\n private createSphereGeometry(\r\n segments: number, \r\n rings: number\r\n ): { vertices: Float32Array; indices: Uint16Array } {\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n \r\n // 生成球体顶点\r\n for (let ring = 0; ring <= rings; ring++) {\r\n const phi = (ring / rings) * Math.PI;\r\n const sinPhi = Math.sin(phi);\r\n const cosPhi = Math.cos(phi);\r\n \r\n for (let seg = 0; seg <= segments; seg++) {\r\n const theta = (seg / segments) * Math.PI * 2;\r\n const sinTheta = Math.sin(theta);\r\n const cosTheta = Math.cos(theta);\r\n \r\n const x = 0.5 * sinPhi * cosTheta;\r\n const y = 0.5 * cosPhi;\r\n const z = 0.5 * sinPhi * sinTheta;\r\n \r\n vertices.push(x, y, z);\r\n }\r\n }\r\n \r\n // 生成球体索引\r\n for (let ring = 0; ring < rings; ring++) {\r\n for (let seg = 0; seg < segments; seg++) {\r\n const a = ring * (segments + 1) + seg;\r\n const b = a + segments + 1;\r\n const c = a + 1;\r\n const d = b + 1;\r\n \r\n indices.push(a, b, c);\r\n indices.push(b, d, c);\r\n }\r\n }\r\n \r\n return {\r\n vertices: new Float32Array(vertices),\r\n indices: new Uint16Array(indices)\r\n };\r\n }\r\n \r\n /**\r\n * 创建渲染用的 GPU 几何体\r\n */\r\n createGeometry(device: GPUDevice): void {\r\n const segments = 16;\r\n const rings = 12;\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n \r\n const color = this._defaultColor;\r\n \r\n // 生成球体顶点\r\n for (let ring = 0; ring <= rings; ring++) {\r\n const phi = (ring / rings) * Math.PI;\r\n const sinPhi = Math.sin(phi);\r\n const cosPhi = Math.cos(phi);\r\n \r\n for (let seg = 0; seg <= segments; seg++) {\r\n const theta = (seg / segments) * Math.PI * 2;\r\n const sinTheta = Math.sin(theta);\r\n const cosTheta = Math.cos(theta);\r\n \r\n const x = this._radius * sinPhi * cosTheta;\r\n const y = this._radius * cosPhi;\r\n const z = this._radius * sinPhi * sinTheta;\r\n \r\n vertices.push(x, y, z, color.x, color.y, color.z);\r\n }\r\n }\r\n \r\n // 生成球体索引\r\n for (let ring = 0; ring < rings; ring++) {\r\n for (let seg = 0; seg < segments; seg++) {\r\n const a = ring * (segments + 1) + seg;\r\n const b = a + segments + 1;\r\n const c = a + 1;\r\n const d = b + 1;\r\n \r\n indices.push(a, b, c);\r\n indices.push(b, d, c);\r\n }\r\n }\r\n \r\n this.createBuffers(device, new Float32Array(vertices), new Uint16Array(indices));\r\n }\r\n}\r\n","import { Vec3 } from \"../math/Vec3\";\r\nimport { Mat4 } from \"../math/Mat4\";\r\nimport { Quat } from \"../math/Quat\";\r\nimport { Shape, ShapeConfig } from \"./Shape\";\r\n\r\n/**\r\n * ArcShapeConfig - 圆弧形状配置\r\n */\r\nexport interface ArcShapeConfig extends ShapeConfig {\r\n tubeRadius?: number; // 管道半径(粗细)\r\n ringRadius?: number; // 圆环半径\r\n sectorAngle?: number; // 扇形角度(度)\r\n tolerance?: number; // 碰撞检测容差\r\n}\r\n\r\n/**\r\n * ArcDisplayMode - 圆弧显示模式\r\n */\r\nexport type ArcDisplayMode = 'sector' | 'ring' | 'none';\r\n\r\n/**\r\n * ArcShape - 圆弧形状(用于旋转 Gizmo)\r\n * 参考 PlayCanvas 引擎的 ArcShape 实现\r\n * \r\n * 圆环默认在 XZ 平面上(绕 Y 轴),通过 rotation 旋转到正确的轴\r\n */\r\nexport class ArcShape extends Shape {\r\n private _tubeRadius: number = 0.02;\r\n private _ringRadius: number = 0.5;\r\n private _sectorAngle: number = 180; // 默认半圆弧\r\n private _tolerance: number = 0.05;\r\n \r\n // 显示模式\r\n private _displayMode: ArcDisplayMode = 'sector';\r\n \r\n // 双缓冲:sector 和 ring 的几何数据\r\n private _sectorVertexBuffer: GPUBuffer | null = null;\r\n private _sectorIndexBuffer: GPUBuffer | null = null;\r\n private _sectorIndexCount: number = 0;\r\n private _ringVertexBuffer: GPUBuffer | null = null;\r\n private _ringIndexBuffer: GPUBuffer | null = null;\r\n private _ringIndexCount: number = 0;\r\n \r\n // 动态旋转角度(用于面向相机)\r\n private _dynamicRotation: Vec3 = new Vec3(0, 0, 0);\r\n \r\n constructor(config: ArcShapeConfig) {\r\n super(config);\r\n \r\n this._tubeRadius = config.tubeRadius ?? this._tubeRadius;\r\n this._ringRadius = config.ringRadius ?? this._ringRadius;\r\n this._sectorAngle = config.sectorAngle ?? this._sectorAngle;\r\n this._tolerance = config.tolerance ?? this._tolerance;\r\n \r\n this._updateTriData();\r\n }\r\n \r\n get tubeRadius(): number { return this._tubeRadius; }\r\n set tubeRadius(value: number) { this._tubeRadius = value; this._updateTriData(); }\r\n \r\n get ringRadius(): number { return this._ringRadius; }\r\n set ringRadius(value: number) { this._ringRadius = value; this._updateTriData(); }\r\n \r\n get sectorAngle(): number { return this._sectorAngle; }\r\n set sectorAngle(value: number) { this._sectorAngle = value; this._updateTriData(); }\r\n \r\n get tolerance(): number { return this._tolerance; }\r\n set tolerance(value: number) { this._tolerance = value; this._updateTriData(); }\r\n \r\n get displayMode(): ArcDisplayMode { return this._displayMode; }\r\n \r\n /**\r\n * 设置动态旋转(用于面向相机)\r\n */\r\n setDynamicRotation(rotation: Vec3): void {\r\n this._dynamicRotation = rotation.clone();\r\n }\r\n \r\n /**\r\n * 获取局部变换矩阵(包含动态旋转)\r\n */\r\n override getLocalTransform(): Mat4 {\r\n // 基础旋转\r\n const baseRotX = this._rotation.x * Math.PI / 180;\r\n const baseRotY = this._rotation.y * Math.PI / 180;\r\n const baseRotZ = this._rotation.z * Math.PI / 180;\r\n const baseQuat = Quat.fromEuler(baseRotX, baseRotY, baseRotZ);\r\n \r\n // 动态旋转\r\n const dynRotX = this._dynamicRotation.x * Math.PI / 180;\r\n const dynRotY = this._dynamicRotation.y * Math.PI / 180;\r\n const dynRotZ = this._dynamicRotation.z * Math.PI / 180;\r\n const dynQuat = Quat.fromEuler(dynRotX, dynRotY, dynRotZ);\r\n \r\n // 组合旋转:先 base 将环面摆到正确轴平面,再 dyn 绕环轴旋转扇区朝向相机\r\n const finalQuat = dynQuat.multiply(baseQuat);\r\n \r\n return Mat4.compose(this._position, finalQuat, this._scale);\r\n }\r\n \r\n /**\r\n * 更新碰撞数据\r\n */\r\n private _updateTriData(): void {\r\n // 根据显示模式创建碰撞几何体\r\n const angle = this._displayMode === 'ring' ? 360 : this._sectorAngle;\r\n const torusGeo = this.createTorusGeometry(20, 8, this._tubeRadius + this._tolerance, angle);\r\n \r\n const transform = Mat4.identity();\r\n \r\n this.triData = [{\r\n vertices: torusGeo.vertices,\r\n indices: torusGeo.indices,\r\n transform: transform,\r\n priority: 0\r\n }];\r\n }\r\n \r\n /**\r\n * 切换显示模式\r\n */\r\n show(mode: ArcDisplayMode): void {\r\n if (this._displayMode === mode) return;\r\n \r\n this._displayMode = mode;\r\n this._visible = mode !== 'none';\r\n \r\n // 更新碰撞数据\r\n this._updateTriData();\r\n }\r\n \r\n /**\r\n * 创建圆环几何体\r\n */\r\n private createTorusGeometry(\r\n segments: number,\r\n tubeSegments: number,\r\n tubeRadius?: number,\r\n sectorAngle?: number\r\n ): { vertices: Float32Array; indices: Uint16Array } {\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n \r\n const tube = tubeRadius ?? this._tubeRadius;\r\n const ring = this._ringRadius;\r\n const angle = sectorAngle ?? this._sectorAngle;\r\n const sectorRad = (angle * Math.PI) / 180;\r\n \r\n for (let i = 0; i <= segments; i++) {\r\n const u = (i / segments) * sectorRad;\r\n const cosU = Math.cos(u);\r\n const sinU = Math.sin(u);\r\n \r\n for (let j = 0; j <= tubeSegments; j++) {\r\n const v = (j / tubeSegments) * Math.PI * 2;\r\n const cosV = Math.cos(v);\r\n const sinV = Math.sin(v);\r\n \r\n const x = (ring + tube * cosV) * cosU;\r\n const y = tube * sinV;\r\n const z = (ring + tube * cosV) * sinU;\r\n \r\n vertices.push(x, y, z);\r\n }\r\n }\r\n \r\n for (let i = 0; i < segments; i++) {\r\n for (let j = 0; j < tubeSegments; j++) {\r\n const a = i * (tubeSegments + 1) + j;\r\n const b = a + tubeSegments + 1;\r\n const c = a + 1;\r\n const d = b + 1;\r\n \r\n indices.push(a, b, c);\r\n indices.push(b, d, c);\r\n }\r\n }\r\n \r\n return {\r\n vertices: new Float32Array(vertices),\r\n indices: new Uint16Array(indices)\r\n };\r\n }\r\n \r\n /**\r\n * 创建渲染用的 GPU 几何体(同时创建 sector 和 ring 两种)\r\n */\r\n createGeometry(device: GPUDevice): void {\r\n this.device = device;\r\n \r\n // 创建 sector 几何体\r\n const sectorData = this._createTorusMeshData(this._sectorAngle);\r\n this._sectorVertexBuffer = device.createBuffer({\r\n size: sectorData.vertices.byteLength,\r\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\r\n mappedAtCreation: true,\r\n });\r\n new Float32Array(this._sectorVertexBuffer.getMappedRange()).set(sectorData.vertices);\r\n this._sectorVertexBuffer.unmap();\r\n \r\n this._sectorIndexBuffer = device.createBuffer({\r\n size: sectorData.indices.byteLength,\r\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\r\n mappedAtCreation: true,\r\n });\r\n new Uint16Array(this._sectorIndexBuffer.getMappedRange()).set(sectorData.indices);\r\n this._sectorIndexBuffer.unmap();\r\n this._sectorIndexCount = sectorData.indices.length;\r\n \r\n // 创建 ring 几何体(完整圆环)\r\n const ringData = this._createTorusMeshData(360);\r\n this._ringVertexBuffer = device.createBuffer({\r\n size: ringData.vertices.byteLength,\r\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\r\n mappedAtCreation: true,\r\n });\r\n new Float32Array(this._ringVertexBuffer.getMappedRange()).set(ringData.vertices);\r\n this._ringVertexBuffer.unmap();\r\n \r\n this._ringIndexBuffer = device.createBuffer({\r\n size: ringData.indices.byteLength,\r\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\r\n mappedAtCreation: true,\r\n });\r\n new Uint16Array(this._ringIndexBuffer.getMappedRange()).set(ringData.indices);\r\n this._ringIndexBuffer.unmap();\r\n this._ringIndexCount = ringData.indices.length;\r\n \r\n // 默认使用 sector\r\n this.vertexBuffer = this._sectorVertexBuffer;\r\n this.indexBuffer = this._sectorIndexBuffer;\r\n this.indexCount = this._sectorIndexCount;\r\n }\r\n \r\n /**\r\n * 创建圆环网格数据\r\n */\r\n private _createTorusMeshData(sectorAngle: number): { vertices: Float32Array; indices: Uint16Array } {\r\n const segments = 64;\r\n const tubeSegments = 12;\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n \r\n const color = this._defaultColor;\r\n const tube = this._tubeRadius;\r\n const ring = this._ringRadius;\r\n const sectorRad = (sectorAngle * Math.PI) / 180;\r\n \r\n for (let i = 0; i <= segments; i++) {\r\n const u = (i / segments) * sectorRad;\r\n const cosU = Math.cos(u);\r\n const sinU = Math.sin(u);\r\n \r\n for (let j = 0; j <= tubeSegments; j++) {\r\n const v = (j / tubeSegments) * Math.PI * 2;\r\n const cosV = Math.cos(v);\r\n const sinV = Math.sin(v);\r\n \r\n const x = (ring + tube * cosV) * cosU;\r\n const y = tube * sinV;\r\n const z = (ring + tube * cosV) * sinU;\r\n \r\n vertices.push(x, y, z, color.x, color.y, color.z);\r\n }\r\n }\r\n \r\n for (let i = 0; i < segments; i++) {\r\n for (let j = 0; j < tubeSegments; j++) {\r\n const a = i * (tubeSegments + 1) + j;\r\n const b = a + tubeSegments + 1;\r\n const c = a + 1;\r\n const d = b + 1;\r\n \r\n indices.push(a, b, c);\r\n indices.push(b, d, c);\r\n }\r\n }\r\n \r\n return {\r\n vertices: new Float32Array(vertices),\r\n indices: new Uint16Array(indices)\r\n };\r\n }\r\n \r\n /**\r\n * 获取顶点缓冲区(根据显示模式)\r\n */\r\n override getVertexBuffer(): GPUBuffer | null {\r\n if (this._displayMode === 'ring') {\r\n return this._ringVertexBuffer;\r\n }\r\n return this._sectorVertexBuffer;\r\n }\r\n \r\n /**\r\n * 获取索引缓冲区(根据显示模式)\r\n */\r\n override getIndexBuffer(): GPUBuffer | null {\r\n if (this._displayMode === 'ring') {\r\n return this._ringIndexBuffer;\r\n }\r\n return this._sectorIndexBuffer;\r\n }\r\n \r\n /**\r\n * 获取索引数量(根据显示模式)\r\n */\r\n override getIndexCount(): number {\r\n if (this._displayMode === 'ring') {\r\n return this._ringIndexCount;\r\n }\r\n return this._sectorIndexCount;\r\n }\r\n \r\n /**\r\n * 销毁 GPU 资源\r\n */\r\n override destroy(): void {\r\n if (this._sectorVertexBuffer) {\r\n this._sectorVertexBuffer.destroy();\r\n this._sectorVertexBuffer = null;\r\n }\r\n if (this._sectorIndexBuffer) {\r\n this._sectorIndexBuffer.destroy();\r\n this._sectorIndexBuffer = null;\r\n }\r\n if (this._ringVertexBuffer) {\r\n this._ringVertexBuffer.destroy();\r\n this._ringVertexBuffer = null;\r\n }\r\n if (this._ringIndexBuffer) {\r\n this._ringIndexBuffer.destroy();\r\n this._ringIndexBuffer = null;\r\n }\r\n super.destroy();\r\n }\r\n}\r\n","import { Vec3 } from \"../math/Vec3\";\r\nimport { Mat4 } from \"../math/Mat4\";\r\nimport { Quat } from \"../math/Quat\";\r\nimport { Shape, ShapeConfig, TriData } from \"./Shape\";\r\n\r\n/**\r\n * BoxLineShapeConfig - 方块线形状配置(用于缩放 Gizmo)\r\n */\r\nexport interface BoxLineShapeConfig extends ShapeConfig {\r\n gap?: number; // 起点与中心的间距\r\n lineThickness?: number; // 线条粗细\r\n lineLength?: number; // 线条长度\r\n boxSize?: number; // 末端方块大小\r\n tolerance?: number; // 碰撞检测容差\r\n}\r\n\r\n/**\r\n * BoxLineShape - 方块线形状(用于缩放 Gizmo)\r\n * 参考 PlayCanvas 引擎的 BoxLineShape 实现\r\n */\r\nexport class BoxLineShape extends Shape {\r\n private _gap: number = 0;\r\n private _lineThickness: number = 0.02;\r\n private _lineLength: number = 0.5;\r\n private _boxSize: number = 0.1;\r\n private _tolerance: number = 0.1;\r\n \r\n constructor(config: BoxLineShapeConfig) {\r\n super(config);\r\n \r\n this._gap = config.gap ?? this._gap;\r\n this._lineThickness = config.lineThickness ?? this._lineThickness;\r\n this._lineLength = config.lineLength ?? this._lineLength;\r\n this._boxSize = config.boxSize ?? this._boxSize;\r\n this._tolerance = config.tolerance ?? this._tolerance;\r\n \r\n this._updateTriData();\r\n }\r\n \r\n get gap(): number { return this._gap; }\r\n set gap(value: number) { this._gap = value; this._updateTriData(); }\r\n \r\n get lineThickness(): number { return this._lineThickness; }\r\n set lineThickness(value: number) { this._lineThickness = value; this._updateTriData(); }\r\n \r\n get lineLength(): number { return this._lineLength; }\r\n set lineLength(value: number) { this._lineLength = value; this._updateTriData(); }\r\n \r\n get boxSize(): number { return this._boxSize; }\r\n set boxSize(value: number) { this._boxSize = value; this._updateTriData(); }\r\n \r\n /**\r\n * 更新碰撞数据\r\n */\r\n private _updateTriData(): void {\r\n // 方块碰撞数据\r\n const boxPos = new Vec3(0, this._gap + this._lineLength + this._boxSize * 0.5, 0);\r\n const boxScale = new Vec3(this._boxSize, this._boxSize, this._boxSize);\r\n const boxTransform = Mat4.compose(boxPos, Quat.identity(), boxScale);\r\n \r\n // 线条圆柱碰撞数据(加上容差)\r\n const linePos = new Vec3(0, this._gap + this._lineLength * 0.5, 0);\r\n const lineScale = new Vec3(\r\n this._lineThickness + this._tolerance,\r\n this._lineLength,\r\n this._lineThickness + this._tolerance\r\n );\r\n const lineTransform = Mat4.compose(linePos, Quat.identity(), lineScale);\r\n \r\n // 生成单位方块和圆柱的三角形数据\r\n const boxGeo = this.createBoxGeometry();\r\n const cylinderGeo = this.createCylinderGeometry();\r\n \r\n this.triData = [\r\n {\r\n vertices: boxGeo.vertices,\r\n indices: boxGeo.indices,\r\n transform: boxTransform,\r\n priority: 0\r\n },\r\n {\r\n vertices: cylinderGeo.vertices,\r\n indices: cylinderGeo.indices,\r\n transform: lineTransform,\r\n priority: 1\r\n }\r\n ];\r\n }\r\n \r\n /**\r\n * 创建单位方块几何体(边长1,中心在原点)\r\n */\r\n private createBoxGeometry(): { vertices: Float32Array; indices: Uint16Array } {\r\n const h = 0.5;\r\n const vertices = new Float32Array([\r\n // 前面\r\n -h, -h, h,\r\n h, -h, h,\r\n h, h, h,\r\n -h, h, h,\r\n // 后面\r\n -h, -h, -h,\r\n -h, h, -h,\r\n h, h, -h,\r\n h, -h, -h,\r\n ]);\r\n \r\n const indices = new Uint16Array([\r\n // 前\r\n 0, 1, 2, 0, 2, 3,\r\n // 后\r\n 4, 5, 6, 4, 6, 7,\r\n // 上\r\n 3, 2, 6, 3, 6, 5,\r\n // 下\r\n 4, 7, 1, 4, 1, 0,\r\n // 右\r\n 1, 7, 6, 1, 6, 2,\r\n // 左\r\n 4, 0, 3, 4, 3, 5\r\n ]);\r\n \r\n return { vertices, indices };\r\n }\r\n \r\n /**\r\n * 创建单位圆柱几何体\r\n */\r\n private createCylinderGeometry(): { vertices: Float32Array; indices: Uint16Array } {\r\n const segments = 12;\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n \r\n for (let i = 0; i <= segments; i++) {\r\n const angle = (i / segments) * Math.PI * 2;\r\n const x = Math.cos(angle) * 0.5;\r\n const z = Math.sin(angle) * 0.5;\r\n \r\n vertices.push(x, -0.5, z);\r\n vertices.push(x, 0.5, z);\r\n }\r\n \r\n for (let i = 0; i < segments; i++) {\r\n const base = i * 2;\r\n indices.push(base, base + 1, base + 2);\r\n indices.push(base + 1, base + 3, base + 2);\r\n }\r\n \r\n return {\r\n vertices: new Float32Array(vertices),\r\n indices: new Uint16Array(indices)\r\n };\r\n }\r\n \r\n /**\r\n * 创建渲染用的 GPU 几何体\r\n */\r\n createGeometry(device: GPUDevice): void {\r\n const segments = 12;\r\n const vertices: number[] = [];\r\n const indices: number[] = [];\r\n \r\n const color = this._defaultColor;\r\n \r\n // 辅助函数:添加顶点\r\n const addVertex = (x: number, y: number, z: number) => {\r\n vertices.push(x, y, z, color.x, color.y, color.z);\r\n };\r\n \r\n // 生成圆柱(线条部分)\r\n const cylinderStart = this._gap;\r\n const cylinderEnd = this._gap + this._lineLength;\r\n \r\n for (let i = 0; i <= segments; i++) {\r\n const angle = (i / segments) * Math.PI * 2;\r\n const cos = Math.cos(angle);\r\n const sin = Math.sin(angle);\r\n \r\n const offsetX = cos * this._lineThickness;\r\n const offsetZ = sin * this._lineThickness;\r\n \r\n addVertex(offsetX, cylinderStart, offsetZ);\r\n addVertex(offsetX, cylinderEnd, offsetZ);\r\n }\r\n \r\n // 圆柱索引\r\n for (let i = 0; i < segments; i++) {\r\n const base = i * 2;\r\n indices.push(base, base + 1, base + 2);\r\n indices.push(base + 1, base + 3, base + 2);\r\n }\r\n \r\n // 生成方块\r\n const boxCenter = this._gap + this._lineLength + this._boxSize * 0.5;\r\n const h = this._boxSize * 0.5;\r\n \r\n const boxBaseIndex = vertices.length / 6;\r\n \r\n // 方块8个顶点\r\n addVertex(-h, boxCenter - h, h);\r\n addVertex( h, boxCenter - h, h);\r\n addVertex( h, boxCenter + h, h);\r\n addVertex(-h, boxCenter + h, h);\r\n addVertex(-h, boxCenter - h, -h);\r\n addVertex(-h, boxCenter + h, -h);\r\n addVertex( h, boxCenter + h, -h);\r\n addVertex( h, boxCenter - h, -h);\r\n \r\n // 方块索引\r\n const boxIndices = [\r\n 0, 1, 2, 0, 2, 3, // 前\r\n 4, 5, 6, 4, 6, 7, // 后\r\n 3, 2, 6, 3, 6, 5, // 上\r\n 4, 7, 1, 4, 1, 0, // 下\r\n 1, 7, 6, 1, 6, 2, // 右\r\n 4, 0, 3, 4, 3, 5 // 左\r\n ];\r\n \r\n for (const idx of boxIndices) {\r\n indices.push(boxBaseIndex + idx);\r\n }\r\n \r\n this.createBuffers(device, new Float32Array(vertices), new Uint16Array(indices));\r\n }\r\n}\r\n","import { Renderer } from \"../Renderer\";\r\nimport { Camera } from \"../Camera\";\r\nimport { Vec3 } from \"../math/Vec3\";\r\nimport { Ray } from \"../math/Ray\";\r\nimport { Mat4 } from \"../math/Mat4\";\r\nimport { Quat } from \"../math/Quat\";\r\nimport { Shape, GizmoAxisType } from \"./Shape\";\r\nimport { ArrowShape } from \"./ArrowShape\";\r\nimport { PlaneShape } from \"./PlaneShape\";\r\nimport { SphereShape } from \"./SphereShape\";\r\nimport { ArcShape, ArcDisplayMode } from \"./ArcShape\";\r\nimport { BoxLineShape } from \"./BoxLineShape\";\r\n\r\n/**\r\n * GizmoMode - Gizmo 操作模式\r\n */\r\nexport enum GizmoMode {\r\n Translate = 'translate',\r\n Rotate = 'rotate',\r\n Scale = 'scale',\r\n}\r\n\r\n/**\r\n * GizmoSpace - 坐标空间\r\n */\r\nexport type GizmoSpace = 'world' | 'local';\r\n\r\n/**\r\n * GizmoDragMode - 拖拽时的显示模式\r\n */\r\nexport type GizmoDragMode = 'show' | 'hide' | 'selected';\r\n\r\n/**\r\n * TransformableObject - 可变换对象接口\r\n */\r\nexport interface TransformableObject {\r\n position: [number, number, number] | Float32Array;\r\n rotation: [number, number, number] | Float32Array;\r\n scale: [number, number, number] | Float32Array;\r\n setPosition(x: number, y: number, z: number): void;\r\n setRotation(x: number, y: number, z: number): void;\r\n setScale(x: number, y: number, z: number): void;\r\n}\r\n\r\n/**\r\n * GizmoTheme - Gizmo 主题颜色\r\n */\r\nexport interface GizmoTheme {\r\n shapeBase: {\r\n x: Vec3;\r\n y: Vec3;\r\n z: Vec3;\r\n xyz: Vec3;\r\n f: Vec3; // 面向相机的轴\r\n };\r\n shapeHover: {\r\n x: Vec3;\r\n y: Vec3;\r\n z: Vec3;\r\n xyz: Vec3;\r\n f: Vec3;\r\n };\r\n guideBase: {\r\n x: Vec3;\r\n y: Vec3;\r\n z: Vec3;\r\n };\r\n disabled: Vec3;\r\n}\r\n\r\n// 默认主题\r\nconst DEFAULT_THEME: GizmoTheme = {\r\n shapeBase: {\r\n x: new Vec3(0.9, 0.2, 0.2),\r\n y: new Vec3(0.2, 0.9, 0.2),\r\n z: new Vec3(0.2, 0.4, 0.9),\r\n xyz: new Vec3(0.8, 0.8, 0.8),\r\n f: new Vec3(0.8, 0.8, 0.8),\r\n },\r\n shapeHover: {\r\n x: new Vec3(1.0, 0.6, 0.6),\r\n y: new Vec3(0.6, 1.0, 0.6),\r\n z: new Vec3(0.6, 0.6, 1.0),\r\n xyz: new Vec3(1.0, 1.0, 1.0),\r\n f: new Vec3(1.0, 1.0, 1.0),\r\n },\r\n guideBase: {\r\n x: new Vec3(0.9, 0.2, 0.2),\r\n y: new Vec3(0.2, 0.9, 0.2),\r\n z: new Vec3(0.2, 0.4, 0.9),\r\n },\r\n disabled: new Vec3(0.5, 0.5, 0.5),\r\n};\r\n\r\n// 常量\r\nconst GLANCE_EPSILON = 0.01;\r\nconst RING_FACING_EPSILON = 1e-4;\r\nconst PERS_SCALE_RATIO = 0.3;\r\nconst MIN_SCALE = 1e-4;\r\nconst RAD_TO_DEG = 180 / Math.PI;\r\n\r\n/**\r\n * TransformGizmoConfig - Gizmo 配置\r\n */\r\nexport interface TransformGizmoConfig {\r\n renderer: Renderer;\r\n camera: Camera;\r\n canvas: HTMLCanvasElement;\r\n size?: number;\r\n snap?: boolean;\r\n snapIncrement?: number;\r\n}\r\n\r\n/**\r\n * TransformGizmo - 变换 Gizmo\r\n * 参考 PlayCanvas 引擎的 TransformGizmo 实现\r\n */\r\nexport class TransformGizmo {\r\n private renderer: Renderer;\r\n private camera: Camera;\r\n private canvas: HTMLCanvasElement;\r\n \r\n // 配置\r\n private _size: number = 1.0;\r\n private _scale: number = 1.0;\r\n private _mode: GizmoMode = GizmoMode.Translate;\r\n private _coordSpace: GizmoSpace = 'world';\r\n private _theme: GizmoTheme = DEFAULT_THEME;\r\n \r\n // Snap 功能\r\n snap: boolean = false;\r\n snapIncrement: number = 1;\r\n \r\n // 拖拽模式\r\n dragMode: GizmoDragMode = 'selected';\r\n \r\n // 平面翻转\r\n flipPlanes: boolean = true;\r\n \r\n // 目标对象\r\n private _target: TransformableObject | null = null;\r\n \r\n // 形状\r\n private _shapes: Map<GizmoAxisType | 'f', Shape> = new Map();\r\n \r\n // 交互状态\r\n private _hoverAxis: GizmoAxisType | 'f' | '' = '';\r\n private _selectedAxis: GizmoAxisType | 'f' | '' = '';\r\n private _hoverIsPlane: boolean = false;\r\n private _selectedIsPlane: boolean = false;\r\n private _dragging: boolean = false;\r\n\r\n // 拖拽起始状态\r\n private _rootStartPos: Vec3 = new Vec3();\r\n private _rootStartRot: Quat = Quat.identity();\r\n private _selectionStartPoint: Vec3 = new Vec3();\r\n private _dragStartTransform: {\r\n position: Vec3;\r\n rotation: Vec3;\r\n scale: Vec3;\r\n } | null = null;\r\n \r\n // 面向相机的方向缓存\r\n private _facingDir: Vec3 = new Vec3();\r\n \r\n // 回调\r\n private _onDragStateChange: ((isDragging: boolean) => void) | null = null;\r\n \r\n // GPU 资源\r\n private pipeline: GPURenderPipeline | null = null;\r\n private linePipeline: GPURenderPipeline | null = null;\r\n private uniformBuffer: GPUBuffer | null = null;\r\n private bindGroup: GPUBindGroup | null = null;\r\n private bindGroupLayout: GPUBindGroupLayout | null = null;\r\n \r\n // 每个 Shape 的 uniform buffer 和 bind group\r\n private shapeUniformBuffers: Map<GizmoAxisType | 'f', GPUBuffer> = new Map();\r\n private shapeBindGroups: Map<GizmoAxisType | 'f', GPUBindGroup> = new Map();\r\n \r\n // 辅助线资源\r\n private guideLineBuffer: GPUBuffer | null = null;\r\n private guideLineBindGroup: GPUBindGroup | null = null;\r\n \r\n constructor(config: TransformGizmoConfig) {\r\n this.renderer = config.renderer;\r\n this.camera = config.camera;\r\n this.canvas = config.canvas;\r\n \r\n if (config.size !== undefined) this._size = config.size;\r\n if (config.snap !== undefined) this.snap = config.snap;\r\n if (config.snapIncrement !== undefined) this.snapIncrement = config.snapIncrement;\r\n }\r\n\r\n /**\r\n * 初始化 Gizmo\r\n */\r\n init(): void {\r\n this.createPipeline();\r\n this.createLinePipeline();\r\n this.createShapes();\r\n }\r\n\r\n /**\r\n * 创建 WebGPU 渲染管线\r\n */\r\n private createPipeline(): void {\r\n const device = this.renderer.device;\r\n \r\n // Shader 支持从 uniform 读取颜色(包含透明度)\r\n const shaderCode = `\r\n struct Uniforms {\r\n viewProjection: mat4x4<f32>,\r\n model: mat4x4<f32>,\r\n color: vec4<f32>,\r\n }\r\n\r\n @group(0) @binding(0) var<uniform> uniforms: Uniforms;\r\n\r\n struct VertexInput {\r\n @location(0) position: vec3<f32>,\r\n @location(1) vertexColor: vec3<f32>,\r\n }\r\n\r\n struct VertexOutput {\r\n @builtin(position) position: vec4<f32>,\r\n @location(0) color: vec4<f32>,\r\n }\r\n\r\n @vertex\r\n fn vertexMain(input: VertexInput) -> VertexOutput {\r\n var output: VertexOutput;\r\n let worldPos = uniforms.model * vec4<f32>(input.position, 1.0);\r\n output.position = uniforms.viewProjection * worldPos;\r\n // 使用 uniform 中的颜色,忽略顶点颜色\r\n output.color = uniforms.color;\r\n return output;\r\n }\r\n\r\n @fragment\r\n fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {\r\n // 如果透明度为 0,丢弃片元\r\n if (input.color.a < 0.01) {\r\n discard;\r\n }\r\n return input.color;\r\n }\r\n `;\r\n \r\n const shaderModule = device.createShaderModule({ code: shaderCode });\r\n \r\n this.uniformBuffer = device.createBuffer({\r\n size: 144, // 64 + 64 + 16 = 144 bytes (viewProj + model + color)\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n \r\n this.bindGroupLayout = device.createBindGroupLayout({\r\n entries: [{\r\n binding: 0,\r\n visibility: GPUShaderStage.VERTEX,\r\n buffer: { type: \"uniform\" },\r\n }],\r\n });\r\n\r\n this.bindGroup = device.createBindGroup({\r\n layout: this.bindGroupLayout,\r\n entries: [{ binding: 0, resource: { buffer: this.uniformBuffer } }],\r\n });\r\n \r\n const pipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [this.bindGroupLayout],\r\n });\r\n\r\n this.pipeline = device.createRenderPipeline({\r\n layout: pipelineLayout,\r\n vertex: {\r\n module: shaderModule,\r\n entryPoint: \"vertexMain\",\r\n buffers: [{\r\n arrayStride: 24,\r\n attributes: [\r\n { shaderLocation: 0, offset: 0, format: \"float32x3\" },\r\n { shaderLocation: 1, offset: 12, format: \"float32x3\" },\r\n ],\r\n }],\r\n },\r\n fragment: {\r\n module: shaderModule,\r\n entryPoint: \"fragmentMain\",\r\n targets: [{\r\n format: this.renderer.format,\r\n blend: {\r\n color: { srcFactor: \"src-alpha\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\r\n alpha: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\r\n },\r\n }],\r\n },\r\n primitive: { topology: \"triangle-list\", cullMode: \"none\" },\r\n depthStencil: {\r\n format: this.renderer.depthFormat,\r\n depthWriteEnabled: false,\r\n depthCompare: \"always\",\r\n },\r\n });\r\n }\r\n\r\n /**\r\n * 创建辅助线渲染管线\r\n */\r\n private createLinePipeline(): void {\r\n const device = this.renderer.device;\r\n \r\n const shaderCode = `\r\n struct Uniforms {\r\n viewProjection: mat4x4<f32>,\r\n model: mat4x4<f32>,\r\n }\r\n\r\n @group(0) @binding(0) var<uniform> uniforms: Uniforms;\r\n\r\n struct VertexInput {\r\n @location(0) position: vec3<f32>,\r\n @location(1) color: vec3<f32>,\r\n }\r\n\r\n struct VertexOutput {\r\n @builtin(position) position: vec4<f32>,\r\n @location(0) color: vec3<f32>,\r\n }\r\n\r\n @vertex\r\n fn vertexMain(input: VertexInput) -> VertexOutput {\r\n var output: VertexOutput;\r\n let worldPos = uniforms.model * vec4<f32>(input.position, 1.0);\r\n output.position = uniforms.viewProjection * worldPos;\r\n output.color = input.color;\r\n return output;\r\n }\r\n\r\n @fragment\r\n fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {\r\n return vec4<f32>(input.color, 0.6);\r\n }\r\n `;\r\n \r\n const shaderModule = device.createShaderModule({ code: shaderCode });\r\n \r\n if (!this.bindGroupLayout) return;\r\n \r\n const pipelineLayout = device.createPipelineLayout({\r\n bindGroupLayouts: [this.bindGroupLayout],\r\n });\r\n\r\n this.linePipeline = device.createRenderPipeline({\r\n layout: pipelineLayout,\r\n vertex: {\r\n module: shaderModule,\r\n entryPoint: \"vertexMain\",\r\n buffers: [{\r\n arrayStride: 24,\r\n attributes: [\r\n { shaderLocation: 0, offset: 0, format: \"float32x3\" },\r\n { shaderLocation: 1, offset: 12, format: \"float32x3\" },\r\n ],\r\n }],\r\n },\r\n fragment: {\r\n module: shaderModule,\r\n entryPoint: \"fragmentMain\",\r\n targets: [{\r\n format: this.renderer.format,\r\n blend: {\r\n color: { srcFactor: \"src-alpha\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\r\n alpha: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\r\n },\r\n }],\r\n },\r\n primitive: { topology: \"line-list\", cullMode: \"none\" },\r\n depthStencil: {\r\n format: this.renderer.depthFormat,\r\n depthWriteEnabled: false,\r\n depthCompare: \"always\",\r\n },\r\n });\r\n \r\n // 创建辅助线缓冲区\r\n this.guideLineBuffer = device.createBuffer({\r\n size: 128,\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n \r\n this.guideLineBindGroup = device.createBindGroup({\r\n layout: this.bindGroupLayout,\r\n entries: [{ binding: 0, resource: { buffer: this.guideLineBuffer } }],\r\n });\r\n }\r\n\r\n /**\r\n * 创建形状\r\n */\r\n private createShapes(): void {\r\n const device = this.renderer.device;\r\n \r\n // 清除现有形状和资源\r\n for (const shape of this._shapes.values()) {\r\n shape.destroy();\r\n }\r\n this._shapes.clear();\r\n \r\n for (const buffer of this.shapeUniformBuffers.values()) {\r\n buffer.destroy();\r\n }\r\n this.shapeUniformBuffers.clear();\r\n this.shapeBindGroups.clear();\r\n \r\n if (this._mode === GizmoMode.Translate) {\r\n this.createTranslateShapes(device);\r\n } else if (this._mode === GizmoMode.Rotate) {\r\n this.createRotateShapes(device);\r\n } else if (this._mode === GizmoMode.Scale) {\r\n this.createScaleShapes(device);\r\n }\r\n \r\n this.createShapeUniformBuffers(device);\r\n }\r\n \r\n /**\r\n * 为每个 Shape 创建独立的 uniform buffer 和 bind group\r\n */\r\n private createShapeUniformBuffers(device: GPUDevice): void {\r\n if (!this.bindGroupLayout) return;\r\n \r\n for (const [axis] of this._shapes) {\r\n const uniformBuffer = device.createBuffer({\r\n size: 144, // 64 + 64 + 16 = 144 bytes (viewProj + model + color)\r\n usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\r\n });\r\n \r\n const bindGroup = device.createBindGroup({\r\n layout: this.bindGroupLayout,\r\n entries: [{ binding: 0, resource: { buffer: uniformBuffer } }],\r\n });\r\n \r\n this.shapeUniformBuffers.set(axis, uniformBuffer);\r\n this.shapeBindGroups.set(axis, bindGroup);\r\n }\r\n }\r\n\r\n /**\r\n * 创建平移模式的形状\r\n */\r\n private createTranslateShapes(device: GPUDevice): void {\r\n const theme = this._theme;\r\n \r\n // 中心球\r\n const center = new SphereShape({\r\n axis: 'xyz',\r\n defaultColor: theme.shapeBase.xyz,\r\n hoverColor: theme.shapeHover.xyz,\r\n disabledColor: theme.disabled,\r\n radius: 0.1,\r\n });\r\n center.createGeometry(device);\r\n this._shapes.set('xyz', center);\r\n \r\n // X 轴箭头\r\n const xArrow = new ArrowShape({\r\n axis: 'x',\r\n defaultColor: theme.shapeBase.x,\r\n hoverColor: theme.shapeHover.x,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(0, 0, -90),\r\n });\r\n xArrow.createGeometry(device);\r\n this._shapes.set('x', xArrow);\r\n \r\n // Y 轴箭头\r\n const yArrow = new ArrowShape({\r\n axis: 'y',\r\n defaultColor: theme.shapeBase.y,\r\n hoverColor: theme.shapeHover.y,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(0, 0, 0),\r\n });\r\n yArrow.createGeometry(device);\r\n this._shapes.set('y', yArrow);\r\n \r\n // Z 轴箭头\r\n const zArrow = new ArrowShape({\r\n axis: 'z',\r\n defaultColor: theme.shapeBase.z,\r\n hoverColor: theme.shapeHover.z,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(90, 0, 0),\r\n });\r\n zArrow.createGeometry(device);\r\n this._shapes.set('z', zArrow);\r\n \r\n // YZ 平面 (X 轴方向)\r\n const yzPlane = new PlaneShape({\r\n axis: 'yz',\r\n defaultColor: theme.shapeBase.x,\r\n hoverColor: theme.shapeHover.x,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(0, 0, -90),\r\n });\r\n yzPlane.createGeometry(device);\r\n this._shapes.set('yz', yzPlane);\r\n \r\n // XZ 平面 (Y 轴方向)\r\n const xzPlane = new PlaneShape({\r\n axis: 'xz',\r\n defaultColor: theme.shapeBase.y,\r\n hoverColor: theme.shapeHover.y,\r\n disabledColor: theme.disabled,\r\n });\r\n xzPlane.createGeometry(device);\r\n this._shapes.set('xz', xzPlane);\r\n \r\n // XY 平面 (Z 轴方向)\r\n const xyPlane = new PlaneShape({\r\n axis: 'xy',\r\n defaultColor: theme.shapeBase.z,\r\n hoverColor: theme.shapeHover.z,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(90, 0, 0),\r\n });\r\n xyPlane.createGeometry(device);\r\n this._shapes.set('xy', xyPlane);\r\n }\r\n\r\n /**\r\n * 创建旋转模式的形状\r\n */\r\n private createRotateShapes(device: GPUDevice): void {\r\n const theme = this._theme;\r\n \r\n // X 轴旋转环\r\n const xArc = new ArcShape({\r\n axis: 'x',\r\n defaultColor: theme.shapeBase.x,\r\n hoverColor: theme.shapeHover.x,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(0, 0, -90),\r\n ringRadius: 0.5,\r\n tubeRadius: 0.015,\r\n sectorAngle: 180,\r\n tolerance: 0.05,\r\n });\r\n xArc.createGeometry(device);\r\n this._shapes.set('x', xArc);\r\n \r\n // Y 轴旋转环\r\n const yArc = new ArcShape({\r\n axis: 'y',\r\n defaultColor: theme.shapeBase.y,\r\n hoverColor: theme.shapeHover.y,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(0, 0, 0),\r\n ringRadius: 0.5,\r\n tubeRadius: 0.015,\r\n sectorAngle: 180,\r\n tolerance: 0.05,\r\n });\r\n yArc.createGeometry(device);\r\n this._shapes.set('y', yArc);\r\n \r\n // Z 轴旋转环\r\n const zArc = new ArcShape({\r\n axis: 'z',\r\n defaultColor: theme.shapeBase.z,\r\n hoverColor: theme.shapeHover.z,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(90, 0, 90),\r\n ringRadius: 0.5,\r\n tubeRadius: 0.015,\r\n sectorAngle: 180,\r\n tolerance: 0.05,\r\n });\r\n zArc.createGeometry(device);\r\n this._shapes.set('z', zArc);\r\n \r\n // 面向相机的旋转环\r\n const fArc = new ArcShape({\r\n axis: 'xyz', // 使用 xyz 作为内部 axis\r\n defaultColor: theme.shapeBase.f,\r\n hoverColor: theme.shapeHover.f,\r\n disabledColor: theme.disabled,\r\n ringRadius: 0.55,\r\n tubeRadius: 0.015,\r\n sectorAngle: 360,\r\n tolerance: 0.05,\r\n });\r\n fArc.createGeometry(device);\r\n this._shapes.set('f', fArc);\r\n \r\n // 中心球(用于自由旋转)- 默认半透明,hover 时更明显\r\n const center = new SphereShape({\r\n axis: 'xyz',\r\n defaultColor: theme.shapeBase.xyz,\r\n hoverColor: theme.shapeHover.xyz,\r\n disabledColor: theme.disabled,\r\n defaultAlpha: 0.0, // 默认完全透明\r\n hoverAlpha: 0.3, // hover 时半透明\r\n radius: 0.45,\r\n });\r\n center.createGeometry(device);\r\n this._shapes.set('xyz', center);\r\n }\r\n\r\n /**\r\n * 创建缩放模式的形状\r\n */\r\n private createScaleShapes(device: GPUDevice): void {\r\n const theme = this._theme;\r\n \r\n // 中心球(统一缩放)\r\n const center = new SphereShape({\r\n axis: 'xyz',\r\n defaultColor: theme.shapeBase.xyz,\r\n hoverColor: theme.shapeHover.xyz,\r\n disabledColor: theme.disabled,\r\n radius: 0.1,\r\n });\r\n center.createGeometry(device);\r\n this._shapes.set('xyz', center);\r\n \r\n // X 轴缩放\r\n const xBox = new BoxLineShape({\r\n axis: 'x',\r\n defaultColor: theme.shapeBase.x,\r\n hoverColor: theme.shapeHover.x,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(0, 0, -90),\r\n });\r\n xBox.createGeometry(device);\r\n this._shapes.set('x', xBox);\r\n \r\n // Y 轴缩放\r\n const yBox = new BoxLineShape({\r\n axis: 'y',\r\n defaultColor: theme.shapeBase.y,\r\n hoverColor: theme.shapeHover.y,\r\n disabledColor: theme.disabled,\r\n });\r\n yBox.createGeometry(device);\r\n this._shapes.set('y', yBox);\r\n \r\n // Z 轴缩放\r\n const zBox = new BoxLineShape({\r\n axis: 'z',\r\n defaultColor: theme.shapeBase.z,\r\n hoverColor: theme.shapeHover.z,\r\n disabledColor: theme.disabled,\r\n rotation: new Vec3(90, 0, 0),\r\n });\r\n zBox.createGeometry(device);\r\n this._shapes.set('z', zBox);\r\n }\r\n\r\n // ==================== 属性访问器 ====================\r\n \r\n get mode(): GizmoMode { return this._mode; }\r\n set mode(value: GizmoMode) {\r\n if (this._mode !== value) {\r\n this._mode = value;\r\n this.createShapes();\r\n this._clearInteractionState();\r\n }\r\n }\r\n \r\n get coordSpace(): GizmoSpace { return this._coordSpace; }\r\n set coordSpace(value: GizmoSpace) { this._coordSpace = value; }\r\n \r\n get size(): number { return this._size; }\r\n set size(value: number) { this._size = value; }\r\n \r\n get target(): TransformableObject | null { return this._target; }\r\n \r\n get isDragging(): boolean { return this._dragging; }\r\n\r\n // ==================== 目标管理 ====================\r\n \r\n setTarget(object: TransformableObject | null): void {\r\n this._target = object;\r\n this._clearInteractionState();\r\n }\r\n \r\n setOnDragStateChange(callback: ((isDragging: boolean) => void) | null): void {\r\n this._onDragStateChange = callback;\r\n }\r\n \r\n private _clearInteractionState(): void {\r\n this._hoverAxis = '';\r\n this._selectedAxis = '';\r\n this._hoverIsPlane = false;\r\n this._selectedIsPlane = false;\r\n this._dragging = false;\r\n this._dragStartTransform = null;\r\n \r\n for (const shape of this._shapes.values()) {\r\n shape.hover(false);\r\n }\r\n }\r\n\r\n // ==================== 缩放计算 ====================\r\n \r\n private getGizmoPosition(): Vec3 | null {\r\n if (!this._target) return null;\r\n return new Vec3(\r\n this._target.position[0],\r\n this._target.position[1],\r\n this._target.position[2]\r\n );\r\n }\r\n \r\n /**\r\n * 获取 Gizmo 的视觉旋转(用于渲染形状)\r\n * - 平移模式:根据 coordSpace 设置\r\n * - 旋转模式:始终使用世界坐标(三个轴保持正交)\r\n * - 缩放模式:始终使用本地坐标(跟随物体旋转)\r\n */\r\n private getGizmoRotation(): Quat {\r\n if (this._mode === GizmoMode.Rotate) {\r\n // 旋转模式始终使用世界坐标,保持三个轴正交\r\n return Quat.identity();\r\n }\r\n if (this._mode === GizmoMode.Scale && this._target) {\r\n // 缩放模式始终使用本地坐标\r\n return Quat.fromEuler(\r\n this._target.rotation[0],\r\n this._target.rotation[1],\r\n this._target.rotation[2]\r\n );\r\n }\r\n // 平移模式根据 coordSpace 设置\r\n if (this._coordSpace === 'local' && this._target) {\r\n return Quat.fromEuler(\r\n this._target.rotation[0],\r\n this._target.rotation[1],\r\n this._target.rotation[2]\r\n );\r\n }\r\n return Quat.identity();\r\n }\r\n \r\n private updateScale(): void {\r\n const gizmoPos = this.getGizmoPosition();\r\n if (!gizmoPos) return;\r\n \r\n const cameraPos = new Vec3(\r\n this.camera.position[0],\r\n this.camera.position[1],\r\n this.camera.position[2]\r\n );\r\n \r\n const dist = gizmoPos.distance(cameraPos);\r\n this._scale = Math.tan(0.5 * this.camera.fov) * dist * PERS_SCALE_RATIO;\r\n this._scale = Math.max(this._scale * this._size, MIN_SCALE);\r\n }\r\n \r\n /**\r\n * 获取面向相机的方向(从 Gizmo 指向相机)\r\n */\r\n private getFacingDir(): Vec3 {\r\n const gizmoPos = this.getGizmoPosition();\r\n if (!gizmoPos) return new Vec3(0, 0, 1);\r\n \r\n const cameraPos = new Vec3(\r\n this.camera.position[0],\r\n this.camera.position[1],\r\n this.camera.position[2]\r\n );\r\n \r\n return cameraPos.subtract(gizmoPos).normalize();\r\n }\r\n\r\n // ==================== 动态形状调整 ====================\r\n \r\n /**\r\n * 更新形状以面向相机\r\n * 参考 PlayCanvas 的 _shapesLookAtCamera\r\n */\r\n private _shapesLookAtCamera(): void {\r\n if (this._mode === GizmoMode.Translate) {\r\n this._updateTranslateShapesForCamera();\r\n } else if (this._mode === GizmoMode.Rotate) {\r\n this._updateRotateShapesForCamera();\r\n }\r\n }\r\n \r\n /**\r\n * 更新平移形状\r\n */\r\n private _updateTranslateShapesForCamera(): void {\r\n const facingDir = this.getFacingDir();\r\n const gizmoRot = this.getGizmoRotation();\r\n \r\n // 计算 Gizmo 的三个轴方向\r\n const right = gizmoRot.transformVector(new Vec3(1, 0, 0));\r\n const up = gizmoRot.transformVector(new Vec3(0, 1, 0));\r\n const forward = gizmoRot.transformVector(new Vec3(0, 0, 1));\r\n \r\n // 轴可见性\r\n const xShape = this._shapes.get('x');\r\n if (xShape) {\r\n const dot = Math.abs(facingDir.dot(right));\r\n xShape.visible = (1 - dot) > GLANCE_EPSILON;\r\n }\r\n \r\n const yShape = this._shapes.get('y');\r\n if (yShape) {\r\n const dot = Math.abs(facingDir.dot(up));\r\n yShape.visible = (1 - dot) > GLANCE_EPSILON;\r\n }\r\n \r\n const zShape = this._shapes.get('z');\r\n if (zShape) {\r\n const dot = Math.abs(facingDir.dot(forward));\r\n zShape.visible = (1 - dot) > GLANCE_EPSILON;\r\n }\r\n \r\n // 平面可见性和翻转\r\n const yzPlane = this._shapes.get('yz') as PlaneShape | undefined;\r\n if (yzPlane) {\r\n const cross = facingDir.cross(right);\r\n yzPlane.visible = (1 - cross.length()) > GLANCE_EPSILON;\r\n if (this.flipPlanes) {\r\n const flipped = new Vec3(\r\n 0,\r\n cross.dot(forward) < 0 ? 1 : 0,\r\n cross.dot(up) < 0 ? 1 : 0\r\n );\r\n yzPlane.setFlipped(flipped);\r\n }\r\n }\r\n \r\n const xzPlane = this._shapes.get('xz') as PlaneShape | undefined;\r\n if (xzPlane) {\r\n const cross = facingDir.cross(up);\r\n xzPlane.visible = (1 - cross.length()) > GLANCE_EPSILON;\r\n if (this.flipPlanes) {\r\n const flipped = new Vec3(\r\n cross.dot(forward) > 0 ? 1 : 0,\r\n 0,\r\n cross.dot(right) > 0 ? 1 : 0\r\n );\r\n xzPlane.setFlipped(flipped);\r\n }\r\n }\r\n \r\n const xyPlane = this._shapes.get('xy') as PlaneShape | undefined;\r\n if (xyPlane) {\r\n const cross = facingDir.cross(forward);\r\n xyPlane.visible = (1 - cross.length()) > GLANCE_EPSILON;\r\n if (this.flipPlanes) {\r\n const flipped = new Vec3(\r\n cross.dot(up) < 0 ? 1 : 0,\r\n cross.dot(right) > 0 ? 1 : 0,\r\n 0\r\n );\r\n xyPlane.setFlipped(flipped);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * 更新旋转形状\r\n */\r\n private _updateRotateShapesForCamera(): void {\r\n const facingDir = this.getFacingDir();\r\n const gizmoRot = this.getGizmoRotation();\r\n \r\n // 将面向方向转换到 Gizmo 局部空间\r\n const invRot = gizmoRot.inverse();\r\n const localFacingDir = invRot.transformVector(facingDir.clone());\r\n \r\n // 计算 Gizmo 的三个轴方向\r\n const right = gizmoRot.transformVector(new Vec3(1, 0, 0));\r\n const up = gizmoRot.transformVector(new Vec3(0, 1, 0));\r\n const forward = gizmoRot.transformVector(new Vec3(0, 0, 1));\r\n \r\n // X 轴旋转环(环面在 YZ 平面,绕 X 轴旋转扇区朝向相机)\r\n const xArc = this._shapes.get('x') as ArcShape | undefined;\r\n if (xArc) {\r\n const angle = -Math.atan2(localFacingDir.y, localFacingDir.z) * RAD_TO_DEG;\r\n xArc.setDynamicRotation(new Vec3(angle, 0, 0));\r\n \r\n const dot = facingDir.dot(right);\r\n if (!this._dragging) {\r\n const showSector = 1 - Math.abs(dot) > RING_FACING_EPSILON;\r\n xArc.show(showSector ? 'sector' : 'ring');\r\n }\r\n }\r\n \r\n // Y 轴旋转环\r\n const yArc = this._shapes.get('y') as ArcShape | undefined;\r\n if (yArc) {\r\n const angle = Math.atan2(localFacingDir.x, localFacingDir.z) * RAD_TO_DEG;\r\n yArc.setDynamicRotation(new Vec3(0, angle, 0));\r\n \r\n const dot = facingDir.dot(up);\r\n if (!this._dragging) {\r\n const showSector = 1 - Math.abs(dot) > RING_FACING_EPSILON;\r\n yArc.show(showSector ? 'sector' : 'ring');\r\n }\r\n }\r\n \r\n // Z 轴旋转环\r\n const zArc = this._shapes.get('z') as ArcShape | undefined;\r\n if (zArc) {\r\n const angle = Math.atan2(localFacingDir.y, localFacingDir.x) * RAD_TO_DEG;\r\n zArc.setDynamicRotation(new Vec3(0, 0, angle));\r\n \r\n const dot = facingDir.dot(forward);\r\n if (!this._dragging) {\r\n const showSector = 1 - Math.abs(dot) > RING_FACING_EPSILON;\r\n zArc.show(showSector ? 'sector' : 'ring');\r\n }\r\n }\r\n \r\n // 面向相机的旋转环\r\n const fArc = this._shapes.get('f') as ArcShape | undefined;\r\n if (fArc) {\r\n // 计算面向相机的旋转\r\n const cameraPos = new Vec3(\r\n this.camera.position[0],\r\n this.camera.position[1],\r\n this.camera.position[2]\r\n );\r\n const gizmoPos = this.getGizmoPosition()!;\r\n const dir = cameraPos.subtract(gizmoPos).normalize();\r\n \r\n const elev = Math.atan2(-dir.y, Math.sqrt(dir.x * dir.x + dir.z * dir.z)) * RAD_TO_DEG;\r\n const azim = Math.atan2(-dir.x, -dir.z) * RAD_TO_DEG;\r\n \r\n // 设置面向相机的旋转(覆盖基础旋转)\r\n fArc.setDynamicRotation(new Vec3(-elev + 90, azim, 0));\r\n }\r\n \r\n this._facingDir = facingDir;\r\n }\r\n\r\n /**\r\n * 拖拽时更新形状显示\r\n */\r\n private _updateDragVisibility(isDragging: boolean): void {\r\n if (this._mode === GizmoMode.Rotate) {\r\n this._updateRotateDragVisibility(isDragging);\r\n } else if (this._mode === GizmoMode.Translate) {\r\n this._updateTranslateDragVisibility(isDragging);\r\n } else if (this._mode === GizmoMode.Scale) {\r\n this._updateScaleDragVisibility(isDragging);\r\n }\r\n }\r\n \r\n private _updateRotateDragVisibility(isDragging: boolean): void {\r\n for (const [axis, shape] of this._shapes) {\r\n if (!(shape instanceof ArcShape)) continue;\r\n \r\n switch (this.dragMode) {\r\n case 'show':\r\n break;\r\n case 'hide':\r\n if (isDragging) {\r\n (shape as ArcShape).show(axis === this._selectedAxis ? 'ring' : 'none');\r\n } else {\r\n (shape as ArcShape).show('sector');\r\n }\r\n break;\r\n case 'selected':\r\n if (isDragging) {\r\n (shape as ArcShape).show(axis === this._selectedAxis ? 'ring' : 'sector');\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n \r\n private _updateTranslateDragVisibility(isDragging: boolean): void {\r\n for (const [axis, shape] of this._shapes) {\r\n switch (this.dragMode) {\r\n case 'show':\r\n break;\r\n case 'hide':\r\n shape.visible = !isDragging;\r\n break;\r\n case 'selected':\r\n if (this._selectedAxis === 'xyz') {\r\n shape.visible = isDragging ? axis.length === 1 : true;\r\n } else if (this._selectedIsPlane) {\r\n shape.visible = isDragging ? axis.length === 1 && !axis.includes(this._selectedAxis) : true;\r\n } else {\r\n shape.visible = isDragging ? axis === this._selectedAxis : true;\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n \r\n private _updateScaleDragVisibility(isDragging: boolean): void {\r\n for (const [axis, shape] of this._shapes) {\r\n switch (this.dragMode) {\r\n case 'show':\r\n break;\r\n case 'hide':\r\n shape.visible = !isDragging;\r\n break;\r\n case 'selected':\r\n if (this._selectedAxis === 'xyz') {\r\n shape.visible = isDragging ? axis.length === 1 : true;\r\n } else {\r\n shape.visible = isDragging ? axis === this._selectedAxis : true;\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n\r\n // ==================== 射线转换 ====================\r\n \r\n private screenToRay(screenX: number, screenY: number): Ray {\r\n const rect = this.canvas.getBoundingClientRect();\r\n const canvasX = screenX - rect.left;\r\n const canvasY = screenY - rect.top;\r\n \r\n const scaleX = this.canvas.width / rect.width;\r\n const scaleY = this.canvas.height / rect.height;\r\n \r\n const pixelX = canvasX * scaleX;\r\n const pixelY = canvasY * scaleY;\r\n \r\n return Ray.fromScreenPoint(\r\n pixelX,\r\n pixelY,\r\n this.canvas.width,\r\n this.canvas.height,\r\n this.camera\r\n );\r\n }\r\n \r\n private performHitTest(ray: Ray): { axis: GizmoAxisType | 'f' | ''; isPlane: boolean } {\r\n if (!this._target) {\r\n return { axis: '', isPlane: false };\r\n }\r\n \r\n const gizmoPos = this.getGizmoPosition()!;\r\n const gizmoRot = this.getGizmoRotation();\r\n \r\n const scale = new Vec3(this._scale, this._scale, this._scale);\r\n const worldTransform = Mat4.compose(gizmoPos, gizmoRot, scale);\r\n \r\n let closestDist: number | null = null;\r\n let closestAxis: GizmoAxisType | 'f' | '' = '';\r\n let closestIsPlane = false;\r\n \r\n for (const [axis, shape] of this._shapes) {\r\n // 不检查 visible,让 Shape.intersect() 通过 interactable 属性控制\r\n // 这样透明但可交互的形状(如旋转模式的中心球)仍然可以被选中\r\n if (shape.disabled) continue;\r\n \r\n const dist = shape.intersect(ray, worldTransform);\r\n if (dist !== null && (closestDist === null || dist < closestDist)) {\r\n closestDist = dist;\r\n closestAxis = axis;\r\n closestIsPlane = axis.length === 2;\r\n }\r\n }\r\n \r\n return { axis: closestAxis, isPlane: closestIsPlane };\r\n }\r\n\r\n // ==================== 事件处理 ====================\r\n \r\n onPointerMove(event: PointerEvent): void {\r\n if (!this._target) return;\r\n \r\n const ray = this.screenToRay(event.clientX, event.clientY);\r\n \r\n if (!this._dragging) {\r\n const hit = this.performHitTest(ray);\r\n this._updateHover(hit.axis, hit.isPlane);\r\n } else {\r\n const point = this._screenToPoint(event.clientX, event.clientY);\r\n this._applyTransform(point);\r\n }\r\n }\r\n \r\n onPointerDown(event: PointerEvent): void {\r\n if (!this._target) return;\r\n \r\n const ray = this.screenToRay(event.clientX, event.clientY);\r\n const hit = this.performHitTest(ray);\r\n \r\n if (hit.axis) {\r\n this._selectedAxis = hit.axis;\r\n this._selectedIsPlane = hit.isPlane;\r\n this._dragging = true;\r\n \r\n this._rootStartPos = this.getGizmoPosition()!.clone();\r\n this._rootStartRot = this.getGizmoRotation();\r\n \r\n const point = this._screenToPoint(event.clientX, event.clientY);\r\n this._selectionStartPoint = point.clone();\r\n \r\n this._dragStartTransform = {\r\n position: new Vec3(\r\n this._target.position[0],\r\n this._target.position[1],\r\n this._target.position[2]\r\n ),\r\n rotation: new Vec3(\r\n this._target.rotation[0],\r\n this._target.rotation[1],\r\n this._target.rotation[2]\r\n ),\r\n scale: new Vec3(\r\n this._target.scale[0],\r\n this._target.scale[1],\r\n this._target.scale[2]\r\n ),\r\n };\r\n \r\n this.canvas.setPointerCapture(event.pointerId);\r\n \r\n // 更新拖拽时的形状显示\r\n this._updateDragVisibility(true);\r\n \r\n if (this._onDragStateChange) {\r\n this._onDragStateChange(true);\r\n }\r\n }\r\n }\r\n \r\n onPointerUp(event: PointerEvent): void {\r\n const wasDragging = this._dragging;\r\n \r\n this._dragging = false;\r\n this._selectedAxis = '';\r\n this._selectedIsPlane = false;\r\n this._dragStartTransform = null;\r\n \r\n if (this.canvas.hasPointerCapture(event.pointerId)) {\r\n this.canvas.releasePointerCapture(event.pointerId);\r\n }\r\n \r\n // 恢复形状显示\r\n this._updateDragVisibility(false);\r\n \r\n if (wasDragging && this._onDragStateChange) {\r\n this._onDragStateChange(false);\r\n }\r\n }\r\n\r\n private _updateHover(axis: GizmoAxisType | 'f' | '', isPlane: boolean): void {\r\n if (this._dragging) return;\r\n \r\n if (this._hoverAxis !== axis) {\r\n // 清除之前的 hover 状态\r\n for (const shape of this._shapes.values()) {\r\n shape.hover(false);\r\n }\r\n \r\n this._hoverAxis = axis;\r\n this._hoverIsPlane = isPlane;\r\n \r\n if (axis) {\r\n if (axis === 'xyz') {\r\n this._shapes.get('x')?.hover(true);\r\n this._shapes.get('y')?.hover(true);\r\n this._shapes.get('z')?.hover(true);\r\n this._shapes.get('xyz')?.hover(true);\r\n } else if (axis === 'f') {\r\n this._shapes.get('f')?.hover(true);\r\n } else if (isPlane) {\r\n const shape = this._shapes.get(axis);\r\n shape?.hover(true);\r\n for (const char of axis) {\r\n this._shapes.get(char as GizmoAxisType)?.hover(true);\r\n }\r\n } else {\r\n this._shapes.get(axis)?.hover(true);\r\n }\r\n }\r\n }\r\n }\r\n\r\n // ==================== 变换计算 ====================\r\n \r\n private _screenToPoint(x: number, y: number): Vec3 {\r\n const ray = this.screenToRay(x, y);\r\n const axis = this._selectedAxis;\r\n const isPlane = this._selectedIsPlane;\r\n \r\n // 旋转模式使用不同的平面\r\n if (this._mode === GizmoMode.Rotate && axis && axis !== 'xyz' && axis.length === 1) {\r\n const plane = this._createRotationPlane(axis);\r\n const dist = ray.intersectPlane(plane.point, plane.normal);\r\n if (dist === null) {\r\n return this._rootStartPos.clone();\r\n }\r\n return ray.at(dist);\r\n }\r\n \r\n // 面向相机的旋转\r\n if (this._mode === GizmoMode.Rotate && axis === 'f') {\r\n const plane = this._createFacingPlane();\r\n const dist = ray.intersectPlane(plane.point, plane.normal);\r\n if (dist === null) {\r\n return this._rootStartPos.clone();\r\n }\r\n return ray.at(dist);\r\n }\r\n \r\n const plane = this._createInteractionPlane(axis as GizmoAxisType, isPlane);\r\n \r\n const dist = ray.intersectPlane(plane.point, plane.normal);\r\n if (dist === null) {\r\n return new Vec3(0, 0, 0);\r\n }\r\n \r\n const point = ray.at(dist);\r\n \r\n const localPoint = point.subtract(this._rootStartPos);\r\n const invRot = this._rootStartRot.inverse();\r\n const rotatedPoint = invRot.transformVector(localPoint);\r\n \r\n if (!isPlane && axis !== 'xyz' && axis !== 'f' && axis.length === 1) {\r\n this._projectToAxis(rotatedPoint, axis);\r\n }\r\n \r\n return rotatedPoint;\r\n }\r\n\r\n private _createRotationPlane(axis: string): { point: Vec3; normal: Vec3 } {\r\n const point = this._rootStartPos.clone();\r\n let normal = new Vec3(0, 1, 0);\r\n \r\n if (this._coordSpace === 'local') {\r\n if (axis === 'x') normal = this._rootStartRot.transformVector(new Vec3(1, 0, 0));\r\n else if (axis === 'y') normal = this._rootStartRot.transformVector(new Vec3(0, 1, 0));\r\n else if (axis === 'z') normal = this._rootStartRot.transformVector(new Vec3(0, 0, 1));\r\n } else {\r\n if (axis === 'x') normal = new Vec3(1, 0, 0);\r\n else if (axis === 'y') normal = new Vec3(0, 1, 0);\r\n else if (axis === 'z') normal = new Vec3(0, 0, 1);\r\n }\r\n \r\n return { point, normal };\r\n }\r\n \r\n private _createFacingPlane(): { point: Vec3; normal: Vec3 } {\r\n const point = this._rootStartPos.clone();\r\n const normal = this.getFacingDir().multiply(-1);\r\n return { point, normal };\r\n }\r\n \r\n private _createInteractionPlane(\r\n axis: GizmoAxisType | '', \r\n isPlane: boolean\r\n ): { point: Vec3; normal: Vec3 } {\r\n const point = this._rootStartPos.clone();\r\n let normal = new Vec3(0, 1, 0);\r\n \r\n if (axis === 'xyz' || isPlane) {\r\n const facingDir = this.getFacingDir();\r\n normal = facingDir.multiply(-1);\r\n } else if (axis === 'x') {\r\n const axisDir = this._rootStartRot.transformVector(new Vec3(1, 0, 0));\r\n const cameraDir = this.getFacingDir();\r\n const cross = axisDir.cross(cameraDir);\r\n if (cross.lengthSquared() > 1e-6) {\r\n normal = cross.cross(axisDir).normalize();\r\n } else {\r\n normal = this._rootStartRot.transformVector(new Vec3(0, 1, 0));\r\n }\r\n } else if (axis === 'y') {\r\n const axisDir = this._rootStartRot.transformVector(new Vec3(0, 1, 0));\r\n const cameraDir = this.getFacingDir();\r\n const cross = axisDir.cross(cameraDir);\r\n if (cross.lengthSquared() > 1e-6) {\r\n normal = cross.cross(axisDir).normalize();\r\n } else {\r\n normal = this._rootStartRot.transformVector(new Vec3(1, 0, 0));\r\n }\r\n } else if (axis === 'z') {\r\n const axisDir = this._rootStartRot.transformVector(new Vec3(0, 0, 1));\r\n const cameraDir = this.getFacingDir();\r\n const cross = axisDir.cross(cameraDir);\r\n if (cross.lengthSquared() > 1e-6) {\r\n normal = cross.cross(axisDir).normalize();\r\n } else {\r\n normal = this._rootStartRot.transformVector(new Vec3(0, 1, 0));\r\n }\r\n }\r\n \r\n return { point, normal };\r\n }\r\n \r\n private _projectToAxis(point: Vec3, axis: string): void {\r\n if (axis === 'x') {\r\n point.y = 0;\r\n point.z = 0;\r\n } else if (axis === 'y') {\r\n point.x = 0;\r\n point.z = 0;\r\n } else if (axis === 'z') {\r\n point.x = 0;\r\n point.y = 0;\r\n }\r\n }\r\n\r\n private _applyTransform(point: Vec3): void {\r\n if (!this._target || !this._dragStartTransform) return;\r\n \r\n const delta = point.subtract(this._selectionStartPoint);\r\n \r\n if (this._mode === GizmoMode.Translate) {\r\n this._applyTranslation(delta);\r\n } else if (this._mode === GizmoMode.Rotate) {\r\n this._applyRotation(point);\r\n } else if (this._mode === GizmoMode.Scale) {\r\n this._applyScale(delta);\r\n }\r\n }\r\n \r\n private _applyTranslation(delta: Vec3): void {\r\n if (!this._target || !this._dragStartTransform) return;\r\n \r\n if (this.snap) {\r\n delta.x = Math.round(delta.x / this.snapIncrement) * this.snapIncrement;\r\n delta.y = Math.round(delta.y / this.snapIncrement) * this.snapIncrement;\r\n delta.z = Math.round(delta.z / this.snapIncrement) * this.snapIncrement;\r\n }\r\n \r\n const worldDelta = this._rootStartRot.transformVector(delta);\r\n \r\n const newPos = this._dragStartTransform.position.add(worldDelta);\r\n this._target.setPosition(newPos.x, newPos.y, newPos.z);\r\n }\r\n \r\n private _applyRotation(point: Vec3): void {\r\n if (!this._target || !this._dragStartTransform) return;\r\n \r\n const axis = this._selectedAxis;\r\n if (!axis) return;\r\n \r\n // 面向相机的旋转\r\n if (axis === 'f') {\r\n this._applyFacingRotation(point);\r\n return;\r\n }\r\n \r\n if (axis === 'xyz') return;\r\n \r\n const gizmoPos = this._rootStartPos;\r\n \r\n const startVec = this._selectionStartPoint.subtract(gizmoPos);\r\n const currentVec = point.subtract(gizmoPos);\r\n \r\n let rotAxis = new Vec3(0, 1, 0);\r\n if (this._coordSpace === 'local') {\r\n if (axis === 'x') rotAxis = this._rootStartRot.transformVector(new Vec3(1, 0, 0));\r\n else if (axis === 'y') rotAxis = this._rootStartRot.transformVector(new Vec3(0, 1, 0));\r\n else if (axis === 'z') rotAxis = this._rootStartRot.transformVector(new Vec3(0, 0, 1));\r\n } else {\r\n if (axis === 'x') rotAxis = new Vec3(1, 0, 0);\r\n else if (axis === 'y') rotAxis = new Vec3(0, 1, 0);\r\n else if (axis === 'z') rotAxis = new Vec3(0, 0, 1);\r\n }\r\n \r\n if (startVec.lengthSquared() < 1e-6 || currentVec.lengthSquared() < 1e-6) {\r\n return;\r\n }\r\n \r\n const startNorm = startVec.normalize();\r\n const currentNorm = currentVec.normalize();\r\n \r\n const cosAngle = Math.max(-1, Math.min(1, startNorm.dot(currentNorm)));\r\n const crossVec = startNorm.cross(currentNorm);\r\n const sinAngle = crossVec.dot(rotAxis);\r\n let angleDelta = Math.atan2(sinAngle, cosAngle);\r\n \r\n if (this.snap) {\r\n const snapAngle = this.snapIncrement * Math.PI / 180;\r\n angleDelta = Math.round(angleDelta / snapAngle) * snapAngle;\r\n }\r\n \r\n const deltaQuat = Quat.fromAxisAngle(rotAxis, angleDelta);\r\n \r\n const startRot = Quat.fromEuler(\r\n this._dragStartTransform.rotation.x,\r\n this._dragStartTransform.rotation.y,\r\n this._dragStartTransform.rotation.z\r\n );\r\n \r\n const newRot = deltaQuat.multiply(startRot);\r\n \r\n const euler = newRot.toEuler();\r\n this._target.setRotation(euler.x, euler.y, euler.z);\r\n }\r\n\r\n private _applyFacingRotation(point: Vec3): void {\r\n if (!this._target || !this._dragStartTransform) return;\r\n \r\n const gizmoPos = this._rootStartPos;\r\n \r\n const startVec = this._selectionStartPoint.subtract(gizmoPos);\r\n const currentVec = point.subtract(gizmoPos);\r\n \r\n // 旋转轴是面向相机的方向\r\n const rotAxis = this.getFacingDir();\r\n \r\n if (startVec.lengthSquared() < 1e-6 || currentVec.lengthSquared() < 1e-6) {\r\n return;\r\n }\r\n \r\n const startNorm = startVec.normalize();\r\n const currentNorm = currentVec.normalize();\r\n \r\n const cosAngle = Math.max(-1, Math.min(1, startNorm.dot(currentNorm)));\r\n const crossVec = startNorm.cross(currentNorm);\r\n const sinAngle = crossVec.dot(rotAxis);\r\n let angleDelta = Math.atan2(sinAngle, cosAngle);\r\n \r\n if (this.snap) {\r\n const snapAngle = this.snapIncrement * Math.PI / 180;\r\n angleDelta = Math.round(angleDelta / snapAngle) * snapAngle;\r\n }\r\n \r\n const deltaQuat = Quat.fromAxisAngle(rotAxis, angleDelta);\r\n \r\n const startRot = Quat.fromEuler(\r\n this._dragStartTransform.rotation.x,\r\n this._dragStartTransform.rotation.y,\r\n this._dragStartTransform.rotation.z\r\n );\r\n \r\n const newRot = deltaQuat.multiply(startRot);\r\n \r\n const euler = newRot.toEuler();\r\n this._target.setRotation(euler.x, euler.y, euler.z);\r\n }\r\n \r\n private _applyScale(delta: Vec3): void {\r\n if (!this._target || !this._dragStartTransform) return;\r\n \r\n const axis = this._selectedAxis;\r\n \r\n let scaleFactor = 1.0;\r\n if (axis === 'x') scaleFactor = 1.0 + delta.x;\r\n else if (axis === 'y') scaleFactor = 1.0 + delta.y;\r\n else if (axis === 'z') scaleFactor = 1.0 + delta.z;\r\n else if (axis === 'xyz') scaleFactor = 1.0 + (delta.x + delta.y + delta.z) / 3;\r\n \r\n scaleFactor = Math.max(0.001, scaleFactor);\r\n \r\n if (this.snap) {\r\n scaleFactor = Math.round(scaleFactor / this.snapIncrement) * this.snapIncrement;\r\n scaleFactor = Math.max(0.001, scaleFactor);\r\n }\r\n \r\n const newScale = this._dragStartTransform.scale.clone();\r\n if (axis === 'x') newScale.x *= scaleFactor;\r\n else if (axis === 'y') newScale.y *= scaleFactor;\r\n else if (axis === 'z') newScale.z *= scaleFactor;\r\n else if (axis === 'xyz') {\r\n newScale.x *= scaleFactor;\r\n newScale.y *= scaleFactor;\r\n newScale.z *= scaleFactor;\r\n }\r\n \r\n this._target.setScale(newScale.x, newScale.y, newScale.z);\r\n }\r\n\r\n // ==================== 渲染 ====================\r\n \r\n private getShapeModelMatrix(shape: Shape): Mat4 {\r\n const gizmoPos = this.getGizmoPosition()!;\r\n const gizmoRot = this.getGizmoRotation();\r\n const scale = new Vec3(this._scale, this._scale, this._scale);\r\n \r\n const gizmoMatrix = Mat4.compose(gizmoPos, gizmoRot, scale);\r\n const shapeLocalMatrix = shape.getLocalTransform();\r\n \r\n return gizmoMatrix.multiply(shapeLocalMatrix);\r\n }\r\n \r\n private updateUniformsForShape(axis: GizmoAxisType | 'f', shape: Shape): void {\r\n const uniformBuffer = this.shapeUniformBuffers.get(axis);\r\n if (!uniformBuffer) return;\r\n \r\n const device = this.renderer.device;\r\n \r\n const modelMatrix = this.getShapeModelMatrix(shape);\r\n \r\n const viewProjectionMatrix = new Mat4();\r\n viewProjectionMatrix.elements.set(this.camera.viewProjectionMatrix);\r\n \r\n // 获取当前颜色(包含透明度)\r\n const color = shape.getColor();\r\n \r\n // uniform 数据:viewProj(64) + model(64) + color(16) = 144 bytes\r\n // 但需要 16 字节对齐,所以用 36 个 float\r\n const uniformData = new Float32Array(36);\r\n uniformData.set(viewProjectionMatrix.elements, 0);\r\n uniformData.set(modelMatrix.elements, 16);\r\n uniformData[32] = color.r;\r\n uniformData[33] = color.g;\r\n uniformData[34] = color.b;\r\n uniformData[35] = color.a;\r\n \r\n device.queue.writeBuffer(uniformBuffer, 0, uniformData);\r\n }\r\n \r\n render(pass: GPURenderPassEncoder): void {\r\n if (!this._target) return;\r\n if (!this.pipeline) return;\r\n \r\n this.updateScale();\r\n this._shapesLookAtCamera();\r\n \r\n pass.setPipeline(this.pipeline);\r\n \r\n for (const [axis, shape] of this._shapes) {\r\n if (!shape.visible) continue;\r\n this.updateUniformsForShape(axis, shape);\r\n }\r\n \r\n for (const [axis, shape] of this._shapes) {\r\n if (!shape.visible) continue;\r\n \r\n const vertexBuffer = shape.getVertexBuffer();\r\n const indexBuffer = shape.getIndexBuffer();\r\n const indexCount = shape.getIndexCount();\r\n const bindGroup = this.shapeBindGroups.get(axis);\r\n \r\n if (!vertexBuffer || !indexBuffer || indexCount === 0 || !bindGroup) {\r\n continue;\r\n }\r\n \r\n pass.setBindGroup(0, bindGroup);\r\n pass.setVertexBuffer(0, vertexBuffer);\r\n pass.setIndexBuffer(indexBuffer, \"uint16\");\r\n pass.drawIndexed(indexCount);\r\n }\r\n }\r\n\r\n destroy(): void {\r\n for (const shape of this._shapes.values()) {\r\n shape.destroy();\r\n }\r\n this._shapes.clear();\r\n \r\n for (const buffer of this.shapeUniformBuffers.values()) {\r\n buffer.destroy();\r\n }\r\n this.shapeUniformBuffers.clear();\r\n this.shapeBindGroups.clear();\r\n \r\n if (this.uniformBuffer) {\r\n this.uniformBuffer.destroy();\r\n this.uniformBuffer = null;\r\n }\r\n \r\n if (this.guideLineBuffer) {\r\n this.guideLineBuffer.destroy();\r\n this.guideLineBuffer = null;\r\n }\r\n \r\n this.pipeline = null;\r\n this.linePipeline = null;\r\n this.bindGroup = null;\r\n this.guideLineBindGroup = null;\r\n this.bindGroupLayout = null;\r\n }\r\n}\r\n","/**\r\n * GizmoManager - Gizmo 交互管理器\r\n * \r\n * 负责管理所有 Gizmo 相关的交互:\r\n * - TransformGizmo(变换控制)\r\n * - ViewportGizmo(视口坐标轴)\r\n * - BoundingBoxRenderer(选中对象包围盒)\r\n */\r\n\r\nimport { Renderer } from \"../core/Renderer\";\r\nimport { Camera } from \"../core/Camera\";\r\nimport { OrbitControls } from \"../core/OrbitControls\";\r\nimport { ViewportGizmo } from \"../core/gizmo/ViewportGizmo\";\r\nimport { TransformGizmo, TransformableObject, GizmoMode } from \"../core/gizmo/TransformGizmo\";\r\nimport { BoundingBoxRenderer } from \"../core/BoundingBoxRenderer\";\r\nimport type { SimpleBoundingBox, BoundingBoxProvider } from \"../types\";\r\nimport type { IGSSplatRenderer } from \"../gs/IGSSplatRenderer\";\r\nimport type { Mesh } from \"../mesh/Mesh\";\r\n\r\nimport { \r\n SplatTransformProxy, \r\n MeshGroupProxy, \r\n SplatBoundingBoxProvider \r\n} from \"../scene/proxies\";\r\n\r\n/**\r\n * GizmoManager - Gizmo 交互管理器\r\n */\r\nexport class GizmoManager {\r\n private renderer: Renderer;\r\n private camera: Camera;\r\n private canvas: HTMLCanvasElement;\r\n private controls: OrbitControls;\r\n\r\n private viewportGizmo: ViewportGizmo;\r\n private transformGizmo: TransformGizmo;\r\n private boundingBoxRenderer: BoundingBoxRenderer;\r\n\r\n // 事件处理函数引用(用于移除监听器)\r\n private boundOnClick: (e: MouseEvent) => void;\r\n private boundOnPointerMove: (e: PointerEvent) => void;\r\n private boundOnPointerDown: (e: PointerEvent) => void;\r\n private boundOnPointerUp: (e: PointerEvent) => void;\r\n\r\n constructor(\r\n renderer: Renderer,\r\n camera: Camera,\r\n canvas: HTMLCanvasElement,\r\n controls: OrbitControls\r\n ) {\r\n this.renderer = renderer;\r\n this.camera = camera;\r\n this.canvas = canvas;\r\n this.controls = controls;\r\n\r\n // 初始化 Gizmo\r\n this.viewportGizmo = new ViewportGizmo(renderer, camera, canvas);\r\n this.transformGizmo = new TransformGizmo({ renderer, camera, canvas });\r\n this.transformGizmo.init();\r\n this.boundingBoxRenderer = new BoundingBoxRenderer(renderer, camera);\r\n\r\n // 设置 Gizmo 拖拽时禁用 OrbitControls\r\n this.transformGizmo.setOnDragStateChange((isDragging) => {\r\n this.controls.enabled = !isDragging;\r\n });\r\n\r\n // 绑定事件处理函数\r\n this.boundOnClick = this.onCanvasClick.bind(this);\r\n this.boundOnPointerMove = this.onPointerMove.bind(this);\r\n this.boundOnPointerDown = this.onPointerDown.bind(this);\r\n this.boundOnPointerUp = this.onPointerUp.bind(this);\r\n\r\n this.setupEventListeners();\r\n }\r\n\r\n /**\r\n * 设置事件监听器\r\n */\r\n private setupEventListeners(): void {\r\n // 设置视口 Gizmo 轴点击回调\r\n this.viewportGizmo.setOnAxisClick((axis, positive) => {\r\n this.controls.setViewAxis(axis, positive, true);\r\n });\r\n\r\n // 监听点击事件\r\n this.canvas.addEventListener(\"click\", this.boundOnClick);\r\n\r\n // 添加变换 Gizmo 的指针事件监听器\r\n this.canvas.addEventListener(\"pointermove\", this.boundOnPointerMove);\r\n this.canvas.addEventListener(\"pointerdown\", this.boundOnPointerDown);\r\n this.canvas.addEventListener(\"pointerup\", this.boundOnPointerUp);\r\n }\r\n\r\n private onCanvasClick(e: MouseEvent): void {\r\n this.viewportGizmo.handleClick(e.clientX, e.clientY);\r\n }\r\n\r\n private onPointerMove(e: PointerEvent): void {\r\n this.transformGizmo.onPointerMove(e);\r\n }\r\n\r\n private onPointerDown(e: PointerEvent): void {\r\n this.transformGizmo.onPointerDown(e);\r\n }\r\n\r\n private onPointerUp(e: PointerEvent): void {\r\n this.transformGizmo.onPointerUp(e);\r\n }\r\n\r\n // ============================================\r\n // 渲染\r\n // ============================================\r\n\r\n /**\r\n * 渲染所有 Gizmo\r\n */\r\n render(pass: GPURenderPassEncoder): void {\r\n // 渲染包围盒\r\n this.boundingBoxRenderer.render(pass);\r\n // 渲染变换 Gizmo\r\n this.transformGizmo.render(pass);\r\n // 渲染视口 Gizmo\r\n this.viewportGizmo.render(pass);\r\n }\r\n\r\n // ============================================\r\n // Transform Gizmo\r\n // ============================================\r\n\r\n /**\r\n * 获取变换 Gizmo\r\n */\r\n getTransformGizmo(): TransformGizmo {\r\n return this.transformGizmo;\r\n }\r\n\r\n /**\r\n * 设置 Gizmo 模式\r\n */\r\n setGizmoMode(mode: GizmoMode): void {\r\n this.transformGizmo.mode = mode;\r\n }\r\n\r\n /**\r\n * 设置 Gizmo 目标对象\r\n */\r\n setGizmoTarget(object: TransformableObject | null): void {\r\n this.transformGizmo.setTarget(object);\r\n }\r\n\r\n // ============================================\r\n // Viewport Gizmo\r\n // ============================================\r\n\r\n /**\r\n * 获取视口 Gizmo\r\n */\r\n getViewportGizmo(): ViewportGizmo {\r\n return this.viewportGizmo;\r\n }\r\n\r\n // ============================================\r\n // Bounding Box\r\n // ============================================\r\n\r\n /**\r\n * 获取包围盒渲染器\r\n */\r\n getBoundingBoxRenderer(): BoundingBoxRenderer {\r\n return this.boundingBoxRenderer;\r\n }\r\n\r\n /**\r\n * 设置选中对象的包围盒(静态模式)\r\n */\r\n setSelectionBoundingBox(box: SimpleBoundingBox | null): void {\r\n this.boundingBoxRenderer.setBoundingBox(box);\r\n }\r\n\r\n /**\r\n * 设置选中对象的包围盒提供者(动态模式)\r\n */\r\n setSelectionBoundingBoxProvider(provider: BoundingBoxProvider | null): void {\r\n this.boundingBoxRenderer.setProvider(provider);\r\n }\r\n\r\n /**\r\n * 清除选中对象的包围盒\r\n */\r\n clearSelectionBoundingBox(): void {\r\n this.boundingBoxRenderer.clear();\r\n }\r\n\r\n // ============================================\r\n // 代理对象创建\r\n // ============================================\r\n\r\n /**\r\n * 创建 Splat 变换代理\r\n */\r\n createSplatTransformProxy(renderer: IGSSplatRenderer): SplatTransformProxy | null {\r\n const bbox = renderer.getBoundingBox();\r\n if (!bbox) return null;\r\n return new SplatTransformProxy(renderer, bbox.center);\r\n }\r\n\r\n /**\r\n * 创建 Mesh 组变换代理\r\n */\r\n createMeshGroupProxy(meshes: Mesh[]): MeshGroupProxy | null {\r\n if (meshes.length === 0) return null;\r\n return new MeshGroupProxy(meshes);\r\n }\r\n\r\n /**\r\n * 创建 Splat 包围盒提供者\r\n */\r\n createSplatBoundingBoxProvider(renderer: IGSSplatRenderer): SplatBoundingBoxProvider {\r\n return new SplatBoundingBoxProvider(renderer);\r\n }\r\n\r\n /**\r\n * 销毁\r\n */\r\n destroy(): void {\r\n // 移除事件监听器\r\n this.canvas.removeEventListener(\"click\", this.boundOnClick);\r\n this.canvas.removeEventListener(\"pointermove\", this.boundOnPointerMove);\r\n this.canvas.removeEventListener(\"pointerdown\", this.boundOnPointerDown);\r\n this.canvas.removeEventListener(\"pointerup\", this.boundOnPointerUp);\r\n\r\n // 销毁 Gizmo\r\n this.transformGizmo.destroy();\r\n this.boundingBoxRenderer.destroy();\r\n }\r\n}\r\n","/**\r\n * HotspotManager - 热点放置管理器\r\n *\r\n * 在 3DGS 场景中通过射线拾取表面点,计算法线,\r\n * 显示吸附圆圈指示器,并放置 OBJ 模型热点。\r\n */\r\n\r\nimport { Camera } from \"../core/Camera\";\r\nimport { Renderer } from \"../core/Renderer\";\r\nimport { OrbitControls } from \"../core/OrbitControls\";\r\nimport { MeshRenderer } from \"../mesh/MeshRenderer\";\r\nimport { Mesh } from \"../mesh/Mesh\";\r\nimport { OBJLoader } from \"../loaders/OBJLoader\";\r\nimport type { IGSSplatRenderer } from \"../gs/IGSSplatRenderer\";\r\nimport type { Vec3Tuple, MaterialData } from \"../types\";\r\n\r\n/** 热点信息 */\r\nexport interface HotspotInfo {\r\n position: Vec3Tuple;\r\n normal: Vec3Tuple;\r\n meshStartIndex: number;\r\n meshCount: number;\r\n /** 是否始终面向屏幕(billboard 模式),默认 false */\r\n billboard: boolean;\r\n /** 放置时的缩放值(billboard 旋转时需要保持) */\r\n placedScale: number;\r\n /** 放置时的法线偏移量 */\r\n placedNormalOffset: number;\r\n /** 放置时的本地中心偏移 (本地空间) */\r\n placedLocalCenter: Vec3Tuple;\r\n}\r\n\r\n/** 射线拾取结果 */\r\ninterface RayHit {\r\n point: Vec3Tuple;\r\n normal: Vec3Tuple;\r\n distance: number;\r\n}\r\n\r\n/**\r\n * HotspotManager\r\n */\r\nexport class HotspotManager {\r\n private camera: Camera;\r\n private renderer: Renderer;\r\n private controls: OrbitControls;\r\n private meshRenderer: MeshRenderer;\r\n private objLoader: OBJLoader;\r\n private canvas: HTMLCanvasElement;\r\n\r\n private active: boolean = false;\r\n private gsRenderer: IGSSplatRenderer | null = null;\r\n\r\n // 圆圈指示器\r\n private indicatorMesh: Mesh | null = null;\r\n private indicatorAdded: boolean = false;\r\n\r\n // 已放置的热点\r\n private hotspots: HotspotInfo[] = [];\r\n\r\n // 当前命中点缓存\r\n private currentHit: RayHit | null = null;\r\n\r\n // 指示器变换状态缓存(点击时用于热点放置)\r\n private indicatorTransform: {\r\n point: Vec3Tuple;\r\n normal: Vec3Tuple;\r\n right: Vec3Tuple;\r\n forward: Vec3Tuple;\r\n visualDiameter: number;\r\n normalOffset: number;\r\n } | null = null;\r\n\r\n // OBJ 模型 URL\r\n private hotspotOBJUrl: string = \"\";\r\n\r\n // 事件处理函数引用\r\n private boundOnMouseMove: (e: MouseEvent) => void;\r\n private boundOnMouseDown: (e: MouseEvent) => void;\r\n private boundOnMouseUp: (e: MouseEvent) => void;\r\n private boundOnKeyDown: (e: KeyboardEvent) => void;\r\n\r\n // 拖拽检测\r\n private mouseDownPos: { x: number; y: number } | null = null;\r\n private isDragging: boolean = false;\r\n private readonly DRAG_THRESHOLD = 5;\r\n\r\n // rAF 驱动的流畅更新\r\n private pendingMouseX: number = 0;\r\n private pendingMouseY: number = 0;\r\n private hasPendingMove: boolean = false;\r\n private rafId: number = 0;\r\n\r\n // 法线缓存:如果命中点没有大变化则复用上次法线\r\n private lastHitIdx: number = -1;\r\n private lastNormal: Vec3Tuple = [0, 1, 0];\r\n\r\n // 指示器半径(世界空间基准)\r\n private indicatorBaseRadius: number = 0.02;\r\n // 搜索邻域的屏幕空间半径(像素)\r\n private pickRadiusPx: number = 20;\r\n\r\n // 回调\r\n private onHotspotPlaced: ((info: HotspotInfo) => void) | null = null;\r\n private onModeChanged: ((active: boolean) => void) | null = null;\r\n\r\n constructor(\r\n renderer: Renderer,\r\n camera: Camera,\r\n canvas: HTMLCanvasElement,\r\n controls: OrbitControls,\r\n meshRenderer: MeshRenderer,\r\n ) {\r\n this.renderer = renderer;\r\n this.camera = camera;\r\n this.canvas = canvas;\r\n this.controls = controls;\r\n this.meshRenderer = meshRenderer;\r\n this.objLoader = new OBJLoader(renderer.device);\r\n\r\n this.boundOnMouseMove = this.onMouseMove.bind(this);\r\n this.boundOnMouseDown = this.onMouseDown.bind(this);\r\n this.boundOnMouseUp = this.onMouseUp.bind(this);\r\n this.boundOnKeyDown = this.onKeyDown.bind(this);\r\n }\r\n\r\n setGSRenderer(gsRenderer: IGSSplatRenderer | null): void {\r\n this.gsRenderer = gsRenderer;\r\n if (gsRenderer) {\r\n const bbox = gsRenderer.getBoundingBox();\r\n if (bbox) {\r\n this.indicatorBaseRadius = bbox.radius * 0.008;\r\n }\r\n }\r\n }\r\n\r\n setHotspotOBJUrl(url: string): void {\r\n this.hotspotOBJUrl = url;\r\n }\r\n\r\n enter(): void {\r\n if (this.active) return;\r\n if (!this.gsRenderer || !this.gsRenderer.getCPUPositions()) {\r\n console.warn(\"HotspotManager: 没有可用的 GS 数据\");\r\n return;\r\n }\r\n\r\n this.active = true;\r\n this.canvas.style.cursor = \"none\";\r\n\r\n this.createIndicatorMesh();\r\n\r\n this.canvas.addEventListener(\"mousemove\", this.boundOnMouseMove);\r\n this.canvas.addEventListener(\"mousedown\", this.boundOnMouseDown);\r\n this.canvas.addEventListener(\"mouseup\", this.boundOnMouseUp);\r\n window.addEventListener(\"keydown\", this.boundOnKeyDown);\r\n\r\n this.onModeChanged?.(true);\r\n }\r\n\r\n exit(): void {\r\n if (!this.active) return;\r\n this.active = false;\r\n this.canvas.style.cursor = \"\";\r\n\r\n this.canvas.removeEventListener(\"mousemove\", this.boundOnMouseMove);\r\n this.canvas.removeEventListener(\"mousedown\", this.boundOnMouseDown);\r\n this.canvas.removeEventListener(\"mouseup\", this.boundOnMouseUp);\r\n window.removeEventListener(\"keydown\", this.boundOnKeyDown);\r\n\r\n if (this.rafId) {\r\n cancelAnimationFrame(this.rafId);\r\n this.rafId = 0;\r\n }\r\n this.hasPendingMove = false;\r\n\r\n this.hideIndicator();\r\n this.currentHit = null;\r\n this.mouseDownPos = null;\r\n this.isDragging = false;\r\n this.lastHitIdx = -1;\r\n this.pickPixelX = -1;\r\n this.pickPixelY = -1;\r\n this.pickDirty = false;\r\n\r\n this.onModeChanged?.(false);\r\n }\r\n\r\n isActive(): boolean {\r\n return this.active;\r\n }\r\n\r\n getHotspots(): HotspotInfo[] {\r\n return [...this.hotspots];\r\n }\r\n\r\n setOnHotspotPlaced(cb: ((info: HotspotInfo) => void) | null): void {\r\n this.onHotspotPlaced = cb;\r\n }\r\n\r\n setOnModeChanged(cb: ((active: boolean) => void) | null): void {\r\n this.onModeChanged = cb;\r\n }\r\n\r\n // ============================================\r\n // 事件处理\r\n // ============================================\r\n\r\n // Current mouse pixel position in device pixels (for GPU readback request)\r\n private pickPixelX: number = -1;\r\n private pickPixelY: number = -1;\r\n // Last client coords for CPU fallback\r\n private lastClientX: number = 0;\r\n private lastClientY: number = 0;\r\n // True when mouse has moved since last consumeGPUResult that produced a result\r\n private pickDirty: boolean = false;\r\n\r\n /**\r\n * Returns the current pick pixel coordinates in device pixels.\r\n * Called by the render loop to pass to prepareDepthNormalPass.\r\n * Returns [-1, -1] when no pick is needed.\r\n */\r\n getPickPixel(): [number, number] {\r\n return [this.pickPixelX, this.pickPixelY];\r\n }\r\n\r\n private onMouseMove(e: MouseEvent): void {\r\n if (!this.active) return;\r\n\r\n if (this.mouseDownPos) {\r\n const dx = e.clientX - this.mouseDownPos.x;\r\n const dy = e.clientY - this.mouseDownPos.y;\r\n if (dx * dx + dy * dy > this.DRAG_THRESHOLD * this.DRAG_THRESHOLD) {\r\n this.isDragging = true;\r\n }\r\n }\r\n\r\n // 只记录坐标,由 rAF 统一处理(避免高频重复计算)\r\n this.pendingMouseX = e.clientX;\r\n this.pendingMouseY = e.clientY;\r\n if (!this.hasPendingMove) {\r\n this.hasPendingMove = true;\r\n this.rafId = requestAnimationFrame(() => this.processMouseMove());\r\n }\r\n }\r\n\r\n private processMouseMove(): void {\r\n this.hasPendingMove = false;\r\n if (!this.active) return;\r\n\r\n // 记录每帧像素位置,在 App.Render() 调用 consumeGPUResult() 回读对应像素的位置和法线信息,更新指示器\r\n const rect = this.canvas.getBoundingClientRect();\r\n const dpr = this.canvas.width / rect.width;\r\n this.pickPixelX = (this.pendingMouseX - rect.left) * dpr;\r\n this.pickPixelY = (this.pendingMouseY - rect.top) * dpr;\r\n this.lastClientX = this.pendingMouseX;\r\n this.lastClientY = this.pendingMouseY;\r\n this.pickDirty = true;\r\n }\r\n\r\n /**\r\n * 读取上一帧的深度法线GPU回读结果,更新指示器\r\n * 每帧在App.Render()中调用\r\n * 如果GPU没有回读结果,则使用CPU拾取\r\n */\r\n consumeGPUResult(): void {\r\n if (!this.active || !this.pickDirty) return;\r\n\r\n let hit: RayHit | null = null;\r\n\r\n if (this.gsRenderer?.getDepthNormal) {\r\n const result = this.gsRenderer.getDepthNormal();\r\n if (result) {\r\n const dist = Math.sqrt(\r\n (result.worldPos[0] - this.camera.position[0]) ** 2 +\r\n (result.worldPos[1] - this.camera.position[1]) ** 2 +\r\n (result.worldPos[2] - this.camera.position[2]) ** 2,\r\n );\r\n hit = { point: result.worldPos, normal: result.normal, distance: dist };\r\n }\r\n }\r\n\r\n if (!hit) {\r\n hit = this.raycastSplatsCPU(this.lastClientX, this.lastClientY);\r\n }\r\n\r\n this.pickDirty = false;\r\n this.currentHit = hit;\r\n if (hit) {\r\n this.updateIndicator(hit.point, hit.normal);\r\n this.showIndicator();\r\n } else {\r\n this.hideIndicator();\r\n }\r\n }\r\n\r\n private onMouseDown(e: MouseEvent): void {\r\n if (!this.active || e.button !== 0) return;\r\n this.mouseDownPos = { x: e.clientX, y: e.clientY };\r\n this.isDragging = false;\r\n }\r\n\r\n private onMouseUp(e: MouseEvent): void {\r\n if (!this.active || e.button !== 0) return;\r\n\r\n // 只有非拖拽的左键点击才放置热点\r\n if (!this.isDragging && this.currentHit) {\r\n this.placeHotspot(this.currentHit.point, this.currentHit.normal);\r\n }\r\n\r\n this.mouseDownPos = null;\r\n this.isDragging = false;\r\n }\r\n\r\n private onKeyDown(e: KeyboardEvent): void {\r\n if (e.key === \"Escape\") {\r\n this.exit();\r\n }\r\n }\r\n\r\n // ============================================\r\n // 射线拾取\r\n // ============================================\r\n\r\n private raycastSplatsCPU(clientX: number, clientY: number): RayHit | null {\r\n const positions = this.gsRenderer?.getCPUPositions();\r\n if (!positions) return null;\r\n\r\n const rect = this.canvas.getBoundingClientRect();\r\n const ndcX = ((clientX - rect.left) / rect.width) * 2 - 1;\r\n const ndcY = -(((clientY - rect.top) / rect.height) * 2 - 1);\r\n\r\n const rayOrigin = this.camera.position;\r\n const modelMatrix = this.gsRenderer!.getModelMatrix();\r\n const vp = this.camera.viewProjectionMatrix;\r\n const count = positions.length / 3;\r\n\r\n const step = count > 300000 ? Math.ceil(count / 300000) : 1;\r\n\r\n const halfW = rect.width / 2;\r\n const halfH = rect.height / 2;\r\n const pickRadSq = this.pickRadiusPx * this.pickRadiusPx;\r\n\r\n let bestCamDistSq = Infinity;\r\n let bestIdx = -1;\r\n let bestScreenDistSq = Infinity;\r\n\r\n const m0 = modelMatrix[0], m1 = modelMatrix[1], m2 = modelMatrix[2];\r\n const m4 = modelMatrix[4], m5 = modelMatrix[5], m6 = modelMatrix[6];\r\n const m8 = modelMatrix[8], m9 = modelMatrix[9], m10 = modelMatrix[10];\r\n const m12 = modelMatrix[12], m13 = modelMatrix[13], m14 = modelMatrix[14];\r\n const v0 = vp[0], v1 = vp[1], v3 = vp[3];\r\n const v4 = vp[4], v5 = vp[5], v7 = vp[7];\r\n const v8 = vp[8], v9 = vp[9], v11 = vp[11];\r\n const v12 = vp[12], v13 = vp[13], v15 = vp[15];\r\n const rox = rayOrigin[0], roy = rayOrigin[1], roz = rayOrigin[2];\r\n\r\n for (let i = 0; i < count; i += step) {\r\n const i3 = i * 3;\r\n const lx = positions[i3], ly = positions[i3 + 1], lz = positions[i3 + 2];\r\n\r\n const tx = m0 * lx + m4 * ly + m8 * lz + m12;\r\n const ty = m1 * lx + m5 * ly + m9 * lz + m13;\r\n const tz = m2 * lx + m6 * ly + m10 * lz + m14;\r\n\r\n const cw = v3 * tx + v7 * ty + v11 * tz + v15;\r\n if (cw <= 0) continue;\r\n\r\n const invCw = 1 / cw;\r\n const pixX = ((v0 * tx + v4 * ty + v8 * tz + v12) * invCw - ndcX) * halfW;\r\n const pixY = ((v1 * tx + v5 * ty + v9 * tz + v13) * invCw - ndcY) * halfH;\r\n const screenDistSq = pixX * pixX + pixY * pixY;\r\n\r\n if (screenDistSq < pickRadSq) {\r\n const dx = tx - rox, dy = ty - roy, dz = tz - roz;\r\n const camDistSq = dx * dx + dy * dy + dz * dz;\r\n\r\n if (\r\n camDistSq < bestCamDistSq * 0.98 ||\r\n (camDistSq < bestCamDistSq * 1.02 && screenDistSq < bestScreenDistSq)\r\n ) {\r\n bestCamDistSq = camDistSq;\r\n bestScreenDistSq = screenDistSq;\r\n bestIdx = i;\r\n }\r\n }\r\n }\r\n\r\n if (bestIdx < 0) return null;\r\n\r\n const hx = positions[bestIdx * 3], hy = positions[bestIdx * 3 + 1], hz = positions[bestIdx * 3 + 2];\r\n const hitPoint: Vec3Tuple = [\r\n m0 * hx + m4 * hy + m8 * hz + m12,\r\n m1 * hx + m5 * hy + m9 * hz + m13,\r\n m2 * hx + m6 * hy + m10 * hz + m14,\r\n ];\r\n\r\n // 如果命中的 splat 索引没变,复用上次法线(大幅减少开销)\r\n let normal: Vec3Tuple;\r\n if (bestIdx === this.lastHitIdx) {\r\n normal = [...this.lastNormal];\r\n } else {\r\n normal = this.estimateNormal(positions, bestIdx, modelMatrix);\r\n this.lastHitIdx = bestIdx;\r\n this.lastNormal = [...normal];\r\n }\r\n\r\n const toCamX = rox - hitPoint[0], toCamY = roy - hitPoint[1], toCamZ = roz - hitPoint[2];\r\n if (normal[0] * toCamX + normal[1] * toCamY + normal[2] * toCamZ < 0) {\r\n normal[0] = -normal[0]; normal[1] = -normal[1]; normal[2] = -normal[2];\r\n }\r\n\r\n return { point: hitPoint, normal, distance: Math.sqrt(bestCamDistSq) };\r\n }\r\n\r\n // ============================================\r\n // 法线估计 (局部 PCA)\r\n // ============================================\r\n\r\n private estimateNormal(\r\n positions: Float32Array,\r\n centerIdx: number,\r\n modelMatrix: Float32Array,\r\n ): Vec3Tuple {\r\n const count = positions.length / 3;\r\n const m = modelMatrix;\r\n\r\n const cx = positions[centerIdx * 3 + 0];\r\n const cy = positions[centerIdx * 3 + 1];\r\n const cz = positions[centerIdx * 3 + 2];\r\n const wcx = m[0] * cx + m[4] * cy + m[8] * cz + m[12];\r\n const wcy = m[1] * cx + m[5] * cy + m[9] * cz + m[13];\r\n const wcz = m[2] * cx + m[6] * cy + m[10] * cz + m[14];\r\n\r\n const bbox = this.gsRenderer?.getBoundingBox();\r\n // 使用更小的搜索半径以聚焦于真正的局部表面\r\n const searchRadius = bbox ? bbox.radius * 0.015 : 0.3;\r\n const searchRadiusSq = searchRadius * searchRadius;\r\n\r\n const neighbors: { pos: Vec3Tuple; distSq: number }[] = [];\r\n const maxNeighbors = 80;\r\n const step = count > 150000 ? Math.ceil(count / 150000) : 1;\r\n\r\n for (let i = 0; i < count; i += step) {\r\n const px = positions[i * 3 + 0];\r\n const py = positions[i * 3 + 1];\r\n const pz = positions[i * 3 + 2];\r\n\r\n const wpx = m[0] * px + m[4] * py + m[8] * pz + m[12];\r\n const wpy = m[1] * px + m[5] * py + m[9] * pz + m[13];\r\n const wpz = m[2] * px + m[6] * py + m[10] * pz + m[14];\r\n\r\n const dx = wpx - wcx;\r\n const dy = wpy - wcy;\r\n const dz = wpz - wcz;\r\n const distSq = dx * dx + dy * dy + dz * dz;\r\n\r\n if (distSq < searchRadiusSq && distSq > 1e-12) {\r\n neighbors.push({ pos: [wpx, wpy, wpz], distSq });\r\n }\r\n }\r\n\r\n // 如果点太少,放大半径重试一次\r\n if (neighbors.length < 6) {\r\n const bigRadiusSq = searchRadiusSq * 4;\r\n neighbors.length = 0;\r\n for (let i = 0; i < count; i += step) {\r\n const px = positions[i * 3 + 0];\r\n const py = positions[i * 3 + 1];\r\n const pz = positions[i * 3 + 2];\r\n const wpx = m[0] * px + m[4] * py + m[8] * pz + m[12];\r\n const wpy = m[1] * px + m[5] * py + m[9] * pz + m[13];\r\n const wpz = m[2] * px + m[6] * py + m[10] * pz + m[14];\r\n const dx = wpx - wcx;\r\n const dy = wpy - wcy;\r\n const dz = wpz - wcz;\r\n const distSq = dx * dx + dy * dy + dz * dz;\r\n if (distSq < bigRadiusSq && distSq > 1e-12) {\r\n neighbors.push({ pos: [wpx, wpy, wpz], distSq });\r\n }\r\n }\r\n }\r\n\r\n if (neighbors.length < 3) return [0, 1, 0];\r\n\r\n // 按距离排序,只保留最近的 maxNeighbors 个\r\n if (neighbors.length > maxNeighbors) {\r\n neighbors.sort((a, b) => a.distSq - b.distSq);\r\n neighbors.length = maxNeighbors;\r\n }\r\n\r\n // ---------- 第一轮 PCA:距离加权 ----------\r\n const roughNormal = this.weightedPCA(neighbors, wcx, wcy, wcz);\r\n\r\n // ---------- 第二轮:剔除离群点后重新估计 ----------\r\n // 计算每个点到拟合平面的投影距离\r\n const [rnx, rny, rnz] = roughNormal;\r\n const projections: number[] = [];\r\n for (const nb of neighbors) {\r\n const d =\r\n (nb.pos[0] - wcx) * rnx +\r\n (nb.pos[1] - wcy) * rny +\r\n (nb.pos[2] - wcz) * rnz;\r\n projections.push(d);\r\n }\r\n\r\n // 计算中位绝对偏差 (MAD) 作为鲁棒散布估计\r\n const absDev = projections.map((d) => Math.abs(d));\r\n absDev.sort((a, b) => a - b);\r\n const mad = absDev[Math.floor(absDev.length / 2)] || 1e-8;\r\n const inlierThreshold = Math.max(mad * 3, searchRadius * 0.05);\r\n\r\n const inliers = neighbors.filter(\r\n (_, i) => Math.abs(projections[i]) < inlierThreshold,\r\n );\r\n\r\n if (inliers.length < 3) return roughNormal;\r\n\r\n return this.weightedPCA(inliers, wcx, wcy, wcz);\r\n }\r\n\r\n /**\r\n * 距离加权 PCA:离中心越近的点权重越高\r\n */\r\n private weightedPCA(\r\n neighbors: { pos: Vec3Tuple; distSq: number }[],\r\n cx: number,\r\n cy: number,\r\n cz: number,\r\n ): Vec3Tuple {\r\n // 加权质心\r\n let totalW = 0;\r\n let mx = 0,\r\n my = 0,\r\n mz = 0;\r\n for (const nb of neighbors) {\r\n const w = 1 / (nb.distSq + 1e-10);\r\n mx += nb.pos[0] * w;\r\n my += nb.pos[1] * w;\r\n mz += nb.pos[2] * w;\r\n totalW += w;\r\n }\r\n mx /= totalW;\r\n my /= totalW;\r\n mz /= totalW;\r\n\r\n // 加权协方差矩阵\r\n let c00 = 0,\r\n c01 = 0,\r\n c02 = 0;\r\n let c11 = 0,\r\n c12 = 0,\r\n c22 = 0;\r\n for (const nb of neighbors) {\r\n const w = 1 / (nb.distSq + 1e-10);\r\n const dx = nb.pos[0] - mx;\r\n const dy = nb.pos[1] - my;\r\n const dz = nb.pos[2] - mz;\r\n c00 += w * dx * dx;\r\n c01 += w * dx * dy;\r\n c02 += w * dx * dz;\r\n c11 += w * dy * dy;\r\n c12 += w * dy * dz;\r\n c22 += w * dz * dz;\r\n }\r\n c00 /= totalW;\r\n c01 /= totalW;\r\n c02 /= totalW;\r\n c11 /= totalW;\r\n c12 /= totalW;\r\n c22 /= totalW;\r\n\r\n return this.smallestEigenvector(c00, c01, c02, c11, c12, c22);\r\n }\r\n\r\n /**\r\n * 求 3x3 对称矩阵最小特征值对应的特征向量(偏移幂迭代)\r\n */\r\n private smallestEigenvector(\r\n a00: number,\r\n a01: number,\r\n a02: number,\r\n a11: number,\r\n a12: number,\r\n a22: number,\r\n ): Vec3Tuple {\r\n // 幂迭代求最大特征值\r\n let vx = 0.577,\r\n vy = 0.577,\r\n vz = 0.577;\r\n\r\n for (let iter = 0; iter < 30; iter++) {\r\n const nx = a00 * vx + a01 * vy + a02 * vz;\r\n const ny = a01 * vx + a11 * vy + a12 * vz;\r\n const nz = a02 * vx + a12 * vy + a22 * vz;\r\n\r\n const len = Math.sqrt(nx * nx + ny * ny + nz * nz);\r\n if (len < 1e-12) return [0, 1, 0];\r\n vx = nx / len;\r\n vy = ny / len;\r\n vz = nz / len;\r\n }\r\n\r\n const lambdaMax =\r\n a00 * vx * vx +\r\n a11 * vy * vy +\r\n a22 * vz * vz +\r\n 2 * a01 * vx * vy +\r\n 2 * a02 * vx * vz +\r\n 2 * a12 * vy * vz;\r\n\r\n // 偏移矩阵使得最小特征向量变为最大\r\n const b00 = lambdaMax - a00;\r\n const b01 = -a01;\r\n const b02 = -a02;\r\n const b11 = lambdaMax - a11;\r\n const b12 = -a12;\r\n const b22 = lambdaMax - a22;\r\n\r\n vx = 0.577;\r\n vy = 0.577;\r\n vz = 0.577;\r\n for (let iter = 0; iter < 30; iter++) {\r\n const nx = b00 * vx + b01 * vy + b02 * vz;\r\n const ny = b01 * vx + b11 * vy + b12 * vz;\r\n const nz = b02 * vx + b12 * vy + b22 * vz;\r\n\r\n const len = Math.sqrt(nx * nx + ny * ny + nz * nz);\r\n if (len < 1e-12) return [0, 1, 0];\r\n vx = nx / len;\r\n vy = ny / len;\r\n vz = nz / len;\r\n }\r\n\r\n return [vx, vy, vz];\r\n }\r\n\r\n // ============================================\r\n // 圆圈指示器\r\n // ============================================\r\n\r\n private createIndicatorMesh(): void {\r\n if (this.indicatorMesh) return;\r\n\r\n const device = this.renderer.device;\r\n const segments = 48;\r\n const outerRadius = this.indicatorBaseRadius;\r\n const innerRadius = outerRadius * 0.92;\r\n\r\n const vertexCount = segments * 2;\r\n const vertexData = new Float32Array(vertexCount * 6);\r\n\r\n for (let i = 0; i < segments; i++) {\r\n const angle = (i / segments) * Math.PI * 2;\r\n const cos = Math.cos(angle);\r\n const sin = Math.sin(angle);\r\n\r\n const oi = i * 2 * 6;\r\n vertexData[oi] = cos * outerRadius;\r\n vertexData[oi + 1] = sin * outerRadius;\r\n vertexData[oi + 2] = 0;\r\n vertexData[oi + 3] = 0;\r\n vertexData[oi + 4] = 0;\r\n vertexData[oi + 5] = 1;\r\n\r\n const ii = (i * 2 + 1) * 6;\r\n vertexData[ii] = cos * innerRadius;\r\n vertexData[ii + 1] = sin * innerRadius;\r\n vertexData[ii + 2] = 0;\r\n vertexData[ii + 3] = 0;\r\n vertexData[ii + 4] = 0;\r\n vertexData[ii + 5] = 1;\r\n }\r\n\r\n // 每段 2 个三角形连接内外环\r\n const indices: number[] = [];\r\n for (let i = 0; i < segments; i++) {\r\n const o0 = i * 2,\r\n i0 = i * 2 + 1;\r\n const o1 = ((i + 1) % segments) * 2,\r\n i1 = ((i + 1) % segments) * 2 + 1;\r\n indices.push(o0, o1, i0);\r\n indices.push(i0, o1, i1);\r\n }\r\n\r\n const vertexBuffer = device.createBuffer({\r\n size: vertexData.byteLength,\r\n usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,\r\n });\r\n device.queue.writeBuffer(vertexBuffer, 0, vertexData);\r\n\r\n const indexData = new Uint16Array(indices);\r\n const alignedSize = Math.ceil(indexData.byteLength / 4) * 4;\r\n const alignedBuf = new Uint8Array(alignedSize);\r\n alignedBuf.set(\r\n new Uint8Array(\r\n indexData.buffer,\r\n indexData.byteOffset,\r\n indexData.byteLength,\r\n ),\r\n );\r\n const indexBuffer = device.createBuffer({\r\n size: alignedSize,\r\n usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,\r\n });\r\n device.queue.writeBuffer(indexBuffer, 0, alignedBuf);\r\n\r\n const bbox = {\r\n min: [-outerRadius, -outerRadius, 0] as Vec3Tuple,\r\n max: [outerRadius, outerRadius, 0] as Vec3Tuple,\r\n center: [0, 0, 0] as Vec3Tuple,\r\n radius: outerRadius,\r\n };\r\n\r\n this.indicatorMesh = new Mesh(\r\n vertexBuffer,\r\n vertexCount,\r\n indexBuffer,\r\n indices.length,\r\n bbox,\r\n );\r\n this.indicatorMesh.hasUV = false;\r\n this.indicatorMesh.indexFormat = \"uint16\";\r\n }\r\n\r\n private showIndicator(): void {\r\n if (!this.indicatorMesh || this.indicatorAdded) return;\r\n\r\n const material: MaterialData = {\r\n baseColorFactor: [1, 1, 1, 0.85],\r\n baseColorTexture: null,\r\n metallicFactor: 0,\r\n roughnessFactor: 1,\r\n doubleSided: true,\r\n };\r\n this.meshRenderer.addOverlayMesh(this.indicatorMesh, material);\r\n this.indicatorAdded = true;\r\n }\r\n\r\n private hideIndicator(): void {\r\n if (!this.indicatorMesh || !this.indicatorAdded) return;\r\n this.meshRenderer.detachOverlayMesh(this.indicatorMesh);\r\n this.indicatorAdded = false;\r\n }\r\n\r\n private updateIndicator(point: Vec3Tuple, normal: Vec3Tuple): void {\r\n if (!this.indicatorMesh) return;\r\n\r\n const camPos = this.camera.position;\r\n const dist = Math.sqrt(\r\n (point[0] - camPos[0]) ** 2 +\r\n (point[1] - camPos[1]) ** 2 +\r\n (point[2] - camPos[2]) ** 2,\r\n );\r\n // 目标屏幕像素大小(直径)\r\n const targetScreenPx = 40;\r\n const halfVFov = this.camera.fov / 2;\r\n const halfHFov = Math.atan(Math.tan(halfVFov) * this.camera.aspect);\r\n const visualRadius =\r\n dist * Math.tan(halfHFov) * (targetScreenPx / this.canvas.clientWidth);\r\n\r\n const [nx, ny, nz] = normal;\r\n const up: Vec3Tuple = Math.abs(ny) < 0.99 ? [0, 1, 0] : [1, 0, 0];\r\n\r\n // right = up × normal\r\n let rx = up[1] * nz - up[2] * ny;\r\n let ry = up[2] * nx - up[0] * nz;\r\n let rz = up[0] * ny - up[1] * nx;\r\n let rLen = Math.sqrt(rx * rx + ry * ry + rz * rz);\r\n if (rLen < 1e-8) {\r\n rx = 1;\r\n ry = 0;\r\n rz = 0;\r\n rLen = 1;\r\n }\r\n rx /= rLen;\r\n ry /= rLen;\r\n rz /= rLen;\r\n\r\n // forward = normal × right\r\n let fx = ny * rz - nz * ry;\r\n let fy = nz * rx - nx * rz;\r\n let fz = nx * ry - ny * rx;\r\n let fLen = Math.sqrt(fx * fx + fy * fy + fz * fz);\r\n if (fLen < 1e-8) {\r\n fx = 0;\r\n fy = 0;\r\n fz = 1;\r\n fLen = 1;\r\n }\r\n fx /= fLen;\r\n fy /= fLen;\r\n fz /= fLen;\r\n\r\n const scale = visualRadius / this.indicatorBaseRadius;\r\n const m = this.indicatorMesh.modelMatrix;\r\n // 列主序: col0 = X(right), col1 = Y(forward), col2 = Z(normal)\r\n m[0] = rx * scale;\r\n m[1] = ry * scale;\r\n m[2] = rz * scale;\r\n m[3] = 0;\r\n m[4] = fx * scale;\r\n m[5] = fy * scale;\r\n m[6] = fz * scale;\r\n m[7] = 0;\r\n m[8] = nx * scale;\r\n m[9] = ny * scale;\r\n m[10] = nz * scale;\r\n m[11] = 0;\r\n\r\n // 沿法线偏移:需足够大以超过 3DGS splat 深度散布\r\n const normalOffset = dist * 0.02;\r\n m[12] = point[0] + nx * normalOffset;\r\n m[13] = point[1] + ny * normalOffset;\r\n m[14] = point[2] + nz * normalOffset;\r\n m[15] = 1;\r\n\r\n // 缓存指示器状态,放置热点时复用\r\n this.indicatorTransform = {\r\n point: [...point],\r\n normal: [nx, ny, nz],\r\n right: [rx, ry, rz],\r\n forward: [fx, fy, fz],\r\n visualDiameter: visualRadius * 2,\r\n normalOffset,\r\n };\r\n }\r\n\r\n // ============================================\r\n // OBJ 热点放置\r\n // ============================================\r\n\r\n private async placeHotspot(\r\n point: Vec3Tuple,\r\n normal: Vec3Tuple,\r\n ): Promise<void> {\r\n if (!this.hotspotOBJUrl) {\r\n console.warn(\"HotspotManager: 未设置热点 OBJ 模型 URL\");\r\n return;\r\n }\r\n\r\n // 快照当前指示器变换(放置时与吸附状态完全一致)\r\n const snap = this.indicatorTransform;\r\n if (!snap) {\r\n console.warn(\"HotspotManager: 无指示器状态,跳过放置\");\r\n return;\r\n }\r\n\r\n // 先移除指示器以确保 mesh 索引正确\r\n this.hideIndicator();\r\n\r\n try {\r\n const loadedMeshes = await this.objLoader.load(this.hotspotOBJUrl);\r\n if (loadedMeshes.length === 0) {\r\n console.warn(\"HotspotManager: OBJ 加载无网格\");\r\n return;\r\n }\r\n\r\n const meshStartIndex = this.meshRenderer.getMeshCount();\r\n\r\n // 计算一次共享的缩放和中心偏移(第一个 mesh 的 bbox)\r\n let placedScale = 1;\r\n let placedLocalCenter: Vec3Tuple = [0, 0, 0];\r\n const firstBbox = loadedMeshes[0].mesh.getLocalBoundingBox();\r\n if (firstBbox) {\r\n const modelW = firstBbox.max[0] - firstBbox.min[0];\r\n const modelH = firstBbox.max[1] - firstBbox.min[1];\r\n const modelD = firstBbox.max[2] - firstBbox.min[2];\r\n const modelMaxDim = Math.max(modelW, modelH, modelD, 1e-6);\r\n placedScale = snap.visualDiameter / modelMaxDim;\r\n placedLocalCenter = [\r\n (firstBbox.min[0] + firstBbox.max[0]) / 2,\r\n (firstBbox.min[1] + firstBbox.max[1]) / 2,\r\n (firstBbox.min[2] + firstBbox.max[2]) / 2,\r\n ];\r\n }\r\n\r\n for (const { mesh, material } of loadedMeshes) {\r\n this.applyIndicatorTransform(mesh, snap);\r\n this.meshRenderer.addOverlayMesh(mesh, material);\r\n }\r\n\r\n const info: HotspotInfo = {\r\n position: [...snap.point],\r\n normal: [...snap.normal],\r\n meshStartIndex,\r\n meshCount: loadedMeshes.length,\r\n billboard: false,\r\n placedScale,\r\n placedNormalOffset: snap.normalOffset,\r\n placedLocalCenter,\r\n };\r\n\r\n this.hotspots.push(info);\r\n this.onHotspotPlaced?.(info);\r\n\r\n console.log(\r\n `热点已放置: pos=(${snap.point[0].toFixed(3)}, ${snap.point[1].toFixed(3)}, ${snap.point[2].toFixed(3)}) ` +\r\n `normal=(${snap.normal[0].toFixed(3)}, ${snap.normal[1].toFixed(3)}, ${snap.normal[2].toFixed(3)})`,\r\n );\r\n } catch (error) {\r\n console.error(\"HotspotManager: 放置热点失败:\", error);\r\n }\r\n }\r\n\r\n /**\r\n * 将 OBJ mesh 的变换设置为与指示器完全一致的大小、位置、朝向。\r\n *\r\n * 使用指示器缓存的基向量 (right, forward, normal) 和 visualDiameter,\r\n * 将 OBJ 缩放到与指示器圆圈等大,居中放置在相同位置。\r\n */\r\n private applyIndicatorTransform(\r\n mesh: Mesh,\r\n snap: NonNullable<typeof this.indicatorTransform>,\r\n ): void {\r\n const { point, normal, right, forward, visualDiameter, normalOffset } =\r\n snap;\r\n const [nx, ny, nz] = normal;\r\n const [rx, ry, rz] = right;\r\n const [fx, fy, fz] = forward;\r\n\r\n // 缩放:让 OBJ 最大维度 = 指示器直径\r\n const bbox = mesh.getLocalBoundingBox();\r\n let objScale = 1;\r\n if (bbox) {\r\n const modelW = bbox.max[0] - bbox.min[0];\r\n const modelH = bbox.max[1] - bbox.min[1];\r\n const modelD = bbox.max[2] - bbox.min[2];\r\n const modelMaxDim = Math.max(modelW, modelH, modelD, 1e-6);\r\n objScale = visualDiameter / modelMaxDim;\r\n }\r\n\r\n // 模型几何中心偏移补偿(居中放置)\r\n let lcx = 0,\r\n lcy = 0,\r\n lcz = 0;\r\n if (bbox) {\r\n lcx = (bbox.min[0] + bbox.max[0]) / 2;\r\n lcy = (bbox.min[1] + bbox.max[1]) / 2;\r\n lcz = (bbox.min[2] + bbox.max[2]) / 2;\r\n }\r\n\r\n // 本地偏移 → 世界空间偏移(基底与指示器一致:col0=right, col1=forward, col2=normal)\r\n const owx = (rx * lcx + fx * lcy + nx * lcz) * objScale;\r\n const owy = (ry * lcx + fy * lcy + ny * lcz) * objScale;\r\n const owz = (rz * lcx + fz * lcy + nz * lcz) * objScale;\r\n\r\n const m = mesh.modelMatrix;\r\n m[0] = rx * objScale;\r\n m[1] = ry * objScale;\r\n m[2] = rz * objScale;\r\n m[3] = 0;\r\n m[4] = fx * objScale;\r\n m[5] = fy * objScale;\r\n m[6] = fz * objScale;\r\n m[7] = 0;\r\n m[8] = nx * objScale;\r\n m[9] = ny * objScale;\r\n m[10] = nz * objScale;\r\n m[11] = 0;\r\n m[12] = point[0] + nx * normalOffset - owx;\r\n m[13] = point[1] + ny * normalOffset - owy;\r\n m[14] = point[2] + nz * normalOffset - owz;\r\n m[15] = 1;\r\n\r\n // 将 modelMatrix 反向分解到 position/rotation/scale,使 Gizmo 可正常操作\r\n this.decomposeModelMatrix(mesh);\r\n }\r\n\r\n /**\r\n * 从 modelMatrix 反向提取 position / rotation / scale,\r\n * 使 Mesh 的分离属性与矩阵保持同步(Gizmo 需要)。\r\n */\r\n private decomposeModelMatrix(mesh: Mesh): void {\r\n const m = mesh.modelMatrix;\r\n\r\n // 位置\r\n mesh.position[0] = m[12];\r\n mesh.position[1] = m[13];\r\n mesh.position[2] = m[14];\r\n\r\n // 缩放 = 各列向量长度\r\n const sx = Math.sqrt(m[0] * m[0] + m[1] * m[1] + m[2] * m[2]);\r\n const sy = Math.sqrt(m[4] * m[4] + m[5] * m[5] + m[6] * m[6]);\r\n const sz = Math.sqrt(m[8] * m[8] + m[9] * m[9] + m[10] * m[10]);\r\n mesh.scale[0] = sx;\r\n mesh.scale[1] = sy;\r\n mesh.scale[2] = sz;\r\n\r\n // 归一化旋转矩阵\r\n const isx = sx > 1e-8 ? 1 / sx : 0;\r\n const isy = sy > 1e-8 ? 1 / sy : 0;\r\n const isz = sz > 1e-8 ? 1 / sz : 0;\r\n\r\n const r00 = m[0] * isx,\r\n r10 = m[1] * isx,\r\n r20 = m[2] * isx;\r\n const r21 = m[6] * isy;\r\n const r22 = m[10] * isz;\r\n\r\n // Euler XYZ:ry = asin(-r20), rx = atan2(r21, r22), rz = atan2(r10, r00)\r\n const sinRy = -r20;\r\n const ry = Math.asin(Math.max(-1, Math.min(1, sinRy)));\r\n const cosRy = Math.cos(ry);\r\n\r\n let rotX: number, rotZ: number;\r\n if (Math.abs(cosRy) > 1e-6) {\r\n rotX = Math.atan2(r21, r22);\r\n rotZ = Math.atan2(r10, r00);\r\n } else {\r\n rotX = Math.atan2(-m[9] * isz, m[5] * isy);\r\n rotZ = 0;\r\n }\r\n\r\n mesh.rotation[0] = rotX;\r\n mesh.rotation[1] = ry;\r\n mesh.rotation[2] = rotZ;\r\n }\r\n\r\n // ============================================\r\n // Billboard 控制\r\n // ============================================\r\n\r\n /**\r\n * 设置指定热点的 billboard 模式\r\n * @param hotspotIndex 热点索引(在 hotspots 数组中的位置)\r\n * @param enabled 是否启用 billboard\r\n */\r\n setHotspotBillboard(hotspotIndex: number, enabled: boolean): boolean {\r\n if (hotspotIndex < 0 || hotspotIndex >= this.hotspots.length) return false;\r\n const info = this.hotspots[hotspotIndex];\r\n if (info.billboard === enabled) return true;\r\n info.billboard = enabled;\r\n\r\n if (!enabled) {\r\n // 关闭 billboard 时,恢复到放置时的朝向\r\n this.restoreHotspotOrientation(info);\r\n }\r\n return true;\r\n }\r\n\r\n getHotspotBillboard(hotspotIndex: number): boolean {\r\n if (hotspotIndex < 0 || hotspotIndex >= this.hotspots.length) return false;\r\n return this.hotspots[hotspotIndex].billboard;\r\n }\r\n\r\n getHotspotCount(): number {\r\n return this.hotspots.length;\r\n }\r\n\r\n /**\r\n * 通过 overlay mesh 起始索引找到对应的热点索引\r\n */\r\n findHotspotIndexByMeshStart(overlayMeshStartIndex: number): number {\r\n return this.hotspots.findIndex(\r\n (h) => h.meshStartIndex === overlayMeshStartIndex,\r\n );\r\n }\r\n\r\n /**\r\n * 每帧调用:更新所有 billboard 热点朝向相机\r\n */\r\n updateBillboards(): void {\r\n const camPos = this.camera.position;\r\n\r\n for (const info of this.hotspots) {\r\n if (!info.billboard) continue;\r\n\r\n const {\r\n position,\r\n normal,\r\n placedScale,\r\n placedNormalOffset,\r\n placedLocalCenter,\r\n } = info;\r\n const [nx, ny, nz] = normal;\r\n\r\n // 热点世界位置(含法线偏移)\r\n const wx = position[0] + nx * placedNormalOffset;\r\n const wy = position[1] + ny * placedNormalOffset;\r\n const wz = position[2] + nz * placedNormalOffset;\r\n\r\n // 从热点位置到相机的方向作为新的 Z 轴(面向相机)\r\n let zx = camPos[0] - wx;\r\n let zy = camPos[1] - wy;\r\n let zz = camPos[2] - wz;\r\n const zLen = Math.sqrt(zx * zx + zy * zy + zz * zz);\r\n if (zLen < 1e-8) continue;\r\n zx /= zLen;\r\n zy /= zLen;\r\n zz /= zLen;\r\n\r\n // 选择 up 参考向量(避免与 Z 轴平行)\r\n const up: Vec3Tuple = Math.abs(zy) < 0.99 ? [0, 1, 0] : [1, 0, 0];\r\n\r\n // right = up × Z\r\n let rx = up[1] * zz - up[2] * zy;\r\n let ry = up[2] * zx - up[0] * zz;\r\n let rz = up[0] * zy - up[1] * zx;\r\n let rLen = Math.sqrt(rx * rx + ry * ry + rz * rz);\r\n if (rLen < 1e-8) {\r\n rx = 1;\r\n ry = 0;\r\n rz = 0;\r\n rLen = 1;\r\n }\r\n rx /= rLen;\r\n ry /= rLen;\r\n rz /= rLen;\r\n\r\n // forward = Z × right\r\n let fx = zy * rz - zz * ry;\r\n let fy = zz * rx - zx * rz;\r\n let fz = zx * ry - zy * rx;\r\n let fLen = Math.sqrt(fx * fx + fy * fy + fz * fz);\r\n if (fLen < 1e-8) {\r\n fx = 0;\r\n fy = 1;\r\n fz = 0;\r\n fLen = 1;\r\n }\r\n fx /= fLen;\r\n fy /= fLen;\r\n fz /= fLen;\r\n\r\n const s = placedScale;\r\n const [lcx, lcy, lcz] = placedLocalCenter;\r\n const owx = (rx * lcx + fx * lcy + zx * lcz) * s;\r\n const owy = (ry * lcx + fy * lcy + zy * lcz) * s;\r\n const owz = (rz * lcx + fz * lcy + zz * lcz) * s;\r\n\r\n for (let i = 0; i < info.meshCount; i++) {\r\n const mesh = this.meshRenderer.getOverlayMeshByIndex(\r\n info.meshStartIndex + i,\r\n );\r\n if (!mesh) continue;\r\n\r\n const m = mesh.modelMatrix;\r\n m[0] = rx * s;\r\n m[1] = ry * s;\r\n m[2] = rz * s;\r\n m[3] = 0;\r\n m[4] = fx * s;\r\n m[5] = fy * s;\r\n m[6] = fz * s;\r\n m[7] = 0;\r\n m[8] = zx * s;\r\n m[9] = zy * s;\r\n m[10] = zz * s;\r\n m[11] = 0;\r\n m[12] = wx - owx;\r\n m[13] = wy - owy;\r\n m[14] = wz - owz;\r\n m[15] = 1;\r\n\r\n this.decomposeModelMatrix(mesh);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * 关闭 billboard 时恢复到放置时的法线朝向\r\n */\r\n private restoreHotspotOrientation(info: HotspotInfo): void {\r\n const {\r\n position,\r\n normal,\r\n placedScale,\r\n placedNormalOffset,\r\n placedLocalCenter,\r\n } = info;\r\n const [nx, ny, nz] = normal;\r\n\r\n const up: Vec3Tuple = Math.abs(ny) < 0.99 ? [0, 1, 0] : [1, 0, 0];\r\n let rx = up[1] * nz - up[2] * ny;\r\n let ry = up[2] * nx - up[0] * nz;\r\n let rz = up[0] * ny - up[1] * nx;\r\n let rLen = Math.sqrt(rx * rx + ry * ry + rz * rz);\r\n if (rLen < 1e-8) {\r\n rx = 1;\r\n ry = 0;\r\n rz = 0;\r\n rLen = 1;\r\n }\r\n rx /= rLen;\r\n ry /= rLen;\r\n rz /= rLen;\r\n\r\n let fx = ny * rz - nz * ry;\r\n let fy = nz * rx - nx * rz;\r\n let fz = nx * ry - ny * rx;\r\n let fLen = Math.sqrt(fx * fx + fy * fy + fz * fz);\r\n if (fLen < 1e-8) {\r\n fx = 0;\r\n fy = 0;\r\n fz = 1;\r\n fLen = 1;\r\n }\r\n fx /= fLen;\r\n fy /= fLen;\r\n fz /= fLen;\r\n\r\n const s = placedScale;\r\n const [lcx, lcy, lcz] = placedLocalCenter;\r\n const owx = (rx * lcx + fx * lcy + nx * lcz) * s;\r\n const owy = (ry * lcx + fy * lcy + ny * lcz) * s;\r\n const owz = (rz * lcx + fz * lcy + nz * lcz) * s;\r\n\r\n const wx = position[0] + nx * placedNormalOffset;\r\n const wy = position[1] + ny * placedNormalOffset;\r\n const wz = position[2] + nz * placedNormalOffset;\r\n\r\n for (let i = 0; i < info.meshCount; i++) {\r\n const mesh = this.meshRenderer.getOverlayMeshByIndex(\r\n info.meshStartIndex + i,\r\n );\r\n if (!mesh) continue;\r\n\r\n const m = mesh.modelMatrix;\r\n m[0] = rx * s;\r\n m[1] = ry * s;\r\n m[2] = rz * s;\r\n m[3] = 0;\r\n m[4] = fx * s;\r\n m[5] = fy * s;\r\n m[6] = fz * s;\r\n m[7] = 0;\r\n m[8] = nx * s;\r\n m[9] = ny * s;\r\n m[10] = nz * s;\r\n m[11] = 0;\r\n m[12] = wx - owx;\r\n m[13] = wy - owy;\r\n m[14] = wz - owz;\r\n m[15] = 1;\r\n\r\n this.decomposeModelMatrix(mesh);\r\n }\r\n }\r\n\r\n // ============================================\r\n // 生命周期\r\n // ============================================\r\n\r\n destroy(): void {\r\n this.exit();\r\n if (this.indicatorMesh && !this.indicatorAdded) {\r\n this.indicatorMesh.destroy();\r\n }\r\n this.indicatorMesh = null;\r\n this.hotspots = [];\r\n }\r\n}\r\n","/**\r\n * App - 统一调度入口\r\n * \r\n * 重构后的职责:\r\n * - 初始化和协调各子系统\r\n * - 渲染循环管理\r\n * - 模型加载(委托给加载器)\r\n * - 对外提供简洁的 API\r\n * \r\n * 场景管理委托给 SceneManager\r\n * Gizmo 交互委托给 GizmoManager\r\n */\r\n\r\nimport { Renderer } from \"./core/Renderer\";\r\nimport { Camera } from \"./core/Camera\";\r\nimport { OrbitControls } from \"./core/OrbitControls\";\r\nimport { MeshRenderer } from \"./mesh/MeshRenderer\";\r\nimport { GLBLoader } from \"./loaders/GLBLoader\";\r\nimport { OBJLoader } from \"./loaders/OBJLoader\";\r\nimport { Mesh } from \"./mesh/Mesh\";\r\nimport { GSSplatRenderer } from \"./gs/GSSplatRenderer\";\r\nimport { GSSplatRendererMobile } from \"./gs/GSSplatRendererMobile\";\r\nimport type { IGSSplatRenderer } from \"./gs/IGSSplatRenderer\";\r\nimport type { BoundingBox, SimpleBoundingBox } from \"./types\";\r\nimport { deserializeSplat } from \"./gs/SplatLoader\";\r\nimport { deserializeSOG } from \"./gs/SOGLoader\";\r\nimport { SceneManager } from \"./scene/SceneManager\";\r\nimport { GizmoManager } from \"./interaction/GizmoManager\";\r\nimport { HotspotManager } from \"./interaction/HotspotManager\";\r\nimport type { HotspotInfo } from \"./interaction/HotspotManager\";\r\nimport { \r\n SplatTransformProxy, \r\n MeshGroupProxy, \r\n SplatBoundingBoxProvider \r\n} from \"./scene/proxies\";\r\nimport { TransformableObject, GizmoMode } from \"./core/gizmo/TransformGizmo\";\r\nimport type { BoundingBoxProvider } from \"./types\";\r\nimport { isMobileDevice } from \"./utils\";\r\n\r\n/**\r\n * 统一进度回调类型\r\n * @param progress 进度值 0-100\r\n * @param stage 当前阶段: 'download' | 'parse' | 'upload'\r\n */\r\nexport type ProgressCallback = (progress: number, stage: 'download' | 'parse' | 'upload') => void;\r\n\r\n/**\r\n * App - 统一调度入口\r\n */\r\nexport class App {\r\n private canvas: HTMLCanvasElement;\r\n private renderer!: Renderer;\r\n private camera!: Camera;\r\n private controls!: OrbitControls;\r\n private meshRenderer!: MeshRenderer;\r\n private glbLoader!: GLBLoader;\r\n private objLoader!: OBJLoader;\r\n\r\n // 子系统管理器\r\n private sceneManager!: SceneManager;\r\n private gizmoManager!: GizmoManager;\r\n private hotspotManager!: HotspotManager;\r\n\r\n private isRunning: boolean = false;\r\n private animationId: number = 0;\r\n\r\n // 是否使用移动端渲染器\r\n private useMobileRenderer: boolean = false;\r\n\r\n // 绑定的事件处理函数\r\n private boundOnResize: () => void;\r\n\r\n constructor(canvas: HTMLCanvasElement) {\r\n this.canvas = canvas;\r\n this.boundOnResize = this.onResize.bind(this);\r\n }\r\n\r\n /**\r\n * 初始化应用\r\n */\r\n async init(): Promise<void> {\r\n // 初始化渲染器\r\n this.renderer = new Renderer(this.canvas);\r\n await this.renderer.init();\r\n\r\n // 初始化相机\r\n this.camera = new Camera();\r\n this.camera.setAspect(this.renderer.getAspectRatio());\r\n\r\n // 初始化控制器\r\n this.controls = new OrbitControls(this.camera, this.canvas);\r\n\r\n // 初始化网格渲染器\r\n this.meshRenderer = new MeshRenderer(this.renderer, this.camera);\r\n\r\n // 初始化加载器\r\n this.glbLoader = new GLBLoader(this.renderer.device);\r\n this.objLoader = new OBJLoader(this.renderer.device);\r\n\r\n // 初始化场景管理器\r\n this.sceneManager = new SceneManager(this.meshRenderer);\r\n\r\n // 初始化 Gizmo 管理器\r\n this.gizmoManager = new GizmoManager(\r\n this.renderer,\r\n this.camera,\r\n this.canvas,\r\n this.controls\r\n );\r\n\r\n // 初始化热点管理器\r\n this.hotspotManager = new HotspotManager(\r\n this.renderer,\r\n this.camera,\r\n this.canvas,\r\n this.controls,\r\n this.meshRenderer,\r\n );\r\n\r\n // 监听窗口大小变化\r\n window.addEventListener(\"resize\", this.boundOnResize);\r\n }\r\n\r\n // ============================================\r\n // 模型加载\r\n // ============================================\r\n\r\n /**\r\n * 加载 GLB 文件\r\n */\r\n async addGLB(url: string): Promise<number> {\r\n try {\r\n const loadedMeshes = await this.glbLoader.load(url);\r\n for (const { mesh, material } of loadedMeshes) {\r\n this.meshRenderer.addMesh(mesh, material);\r\n }\r\n return loadedMeshes.length;\r\n } catch (error) {\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * 加载 OBJ 文件\r\n */\r\n async addOBJ(url: string): Promise<Mesh[]> {\r\n try {\r\n const loadedMeshes = await this.objLoader.load(url);\r\n const meshes: Mesh[] = [];\r\n for (const { mesh, material } of loadedMeshes) {\r\n this.meshRenderer.addMesh(mesh, material);\r\n meshes.push(mesh);\r\n }\r\n return meshes;\r\n } catch (error) {\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * 加载 PLY 文件 (3D Gaussian Splatting)\r\n */\r\n async addPLY(\r\n urlOrBuffer: string | ArrayBuffer,\r\n onProgress?: ProgressCallback,\r\n isLocalFile: boolean = false,\r\n ): Promise<number> {\r\n try {\r\n const isMobile = isMobileDevice();\r\n let buffer: ArrayBuffer;\r\n\r\n // 下载阶段 (0-50%)\r\n if (typeof urlOrBuffer === 'string') {\r\n buffer = await this.fetchWithProgress(urlOrBuffer, (downloadProgress) => {\r\n if (onProgress) {\r\n onProgress(downloadProgress * 0.5, 'download');\r\n }\r\n });\r\n } else {\r\n buffer = urlOrBuffer;\r\n if (onProgress && isLocalFile) {\r\n onProgress(50, 'download');\r\n }\r\n }\r\n\r\n // 解析阶段 (50-90%)\r\n const parseProgressCallback = (loaded: number, total: number) => {\r\n if (onProgress) {\r\n const parseProgress = (loaded / total) * 40;\r\n onProgress(50 + parseProgress, 'parse');\r\n }\r\n };\r\n\r\n let gsRenderer: IGSSplatRenderer;\r\n\r\n if (isMobile) {\r\n gsRenderer = new GSSplatRendererMobile(this.renderer, this.camera);\r\n this.useMobileRenderer = true;\r\n\r\n const compactData = await this.parsePLYBuffer(buffer, {\r\n maxSplats: Infinity,\r\n loadSH: false,\r\n onProgress: parseProgressCallback,\r\n });\r\n\r\n if (onProgress) onProgress(90, 'upload');\r\n gsRenderer.setCompactData(compactData);\r\n if (onProgress) onProgress(100, 'upload');\r\n\r\n this.sceneManager.setGSRenderer(gsRenderer);\r\n this.hotspotManager.setGSRenderer(gsRenderer);\r\n return compactData.count;\r\n } else {\r\n // 桌面端使用优化的 V2 渲染器\r\n gsRenderer = new GSSplatRenderer(this.renderer, this.camera);\r\n this.useMobileRenderer = false;\r\n\r\n const compactData = await this.parsePLYBuffer(buffer, {\r\n maxSplats: Infinity,\r\n loadSH: true,\r\n onProgress: parseProgressCallback,\r\n });\r\n\r\n if (onProgress) onProgress(90, 'upload');\r\n gsRenderer.setCompactData(compactData);\r\n if (onProgress) onProgress(100, 'upload');\r\n\r\n this.sceneManager.setGSRenderer(gsRenderer);\r\n this.hotspotManager.setGSRenderer(gsRenderer);\r\n return compactData.count;\r\n }\r\n } catch (error) {\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * 加载 Splat 文件\r\n */\r\n async addSplat(\r\n urlOrBuffer: string | ArrayBuffer,\r\n onProgress?: ProgressCallback,\r\n isLocalFile: boolean = false,\r\n ): Promise<number> {\r\n try {\r\n let buffer: ArrayBuffer;\r\n\r\n if (typeof urlOrBuffer === 'string') {\r\n buffer = await this.fetchWithProgress(urlOrBuffer, (downloadProgress) => {\r\n if (onProgress) {\r\n onProgress(downloadProgress * 0.5, 'download');\r\n }\r\n });\r\n } else {\r\n buffer = urlOrBuffer;\r\n if (onProgress && isLocalFile) {\r\n onProgress(50, 'download');\r\n }\r\n }\r\n\r\n if (onProgress) onProgress(50, 'parse');\r\n const splats = deserializeSplat(buffer);\r\n if (onProgress) onProgress(90, 'parse');\r\n\r\n if (onProgress) onProgress(90, 'upload');\r\n // 使用优化的 V2 渲染器\r\n const gsRenderer = new GSSplatRenderer(this.renderer, this.camera);\r\n gsRenderer.setData(splats);\r\n this.sceneManager.setGSRenderer(gsRenderer);\r\n this.hotspotManager.setGSRenderer(gsRenderer);\r\n this.useMobileRenderer = false;\r\n if (onProgress) onProgress(100, 'upload');\r\n\r\n return splats.length;\r\n } catch (error) {\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * 加载 SOG 文件 (Spatially Ordered Gaussians)\r\n */\r\n async addSOG(\r\n urlOrBuffer: string | ArrayBuffer,\r\n onProgress?: ProgressCallback,\r\n isLocalFile: boolean = false,\r\n ): Promise<number> {\r\n try {\r\n const isMobile = isMobileDevice();\r\n let buffer: ArrayBuffer;\r\n\r\n if (typeof urlOrBuffer === 'string') {\r\n buffer = await this.fetchWithProgress(urlOrBuffer, (downloadProgress) => {\r\n if (onProgress) {\r\n onProgress(downloadProgress * 0.5, 'download');\r\n }\r\n });\r\n } else {\r\n buffer = urlOrBuffer;\r\n if (onProgress && isLocalFile) {\r\n onProgress(50, 'download');\r\n }\r\n }\r\n\r\n if (onProgress) onProgress(50, 'parse');\r\n\r\n const compactData = await deserializeSOG(buffer, (p, stage) => {\r\n if (onProgress) {\r\n onProgress(50 + (p / 100) * 40, stage);\r\n }\r\n });\r\n\r\n if (onProgress) onProgress(90, 'upload');\r\n\r\n let gsRenderer: IGSSplatRenderer;\r\n if (isMobile) {\r\n gsRenderer = new GSSplatRendererMobile(this.renderer, this.camera);\r\n this.useMobileRenderer = true;\r\n } else {\r\n gsRenderer = new GSSplatRenderer(this.renderer, this.camera);\r\n this.useMobileRenderer = false;\r\n }\r\n\r\n gsRenderer.setCompactData(compactData);\r\n this.sceneManager.setGSRenderer(gsRenderer);\r\n this.hotspotManager.setGSRenderer(gsRenderer);\r\n\r\n if (onProgress) onProgress(100, 'upload');\r\n return compactData.count;\r\n } catch (error) {\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * 添加测试立方体\r\n */\r\n addTestCube(): void {\r\n const { mesh, material } = this.glbLoader.createTestCube();\r\n this.meshRenderer.addMesh(mesh, material);\r\n }\r\n\r\n /**\r\n * 添加测试球体\r\n */\r\n addTestSphere(): void {\r\n const { mesh, material } = this.glbLoader.createTestSphere();\r\n this.meshRenderer.addMesh(mesh, material);\r\n }\r\n\r\n // ============================================\r\n // 渲染循环\r\n // ============================================\r\n\r\n /**\r\n * 开始渲染循环\r\n */\r\n start(): void {\r\n if (this.isRunning) return;\r\n this.isRunning = true;\r\n this.animate();\r\n }\r\n\r\n /**\r\n * 停止渲染循环\r\n */\r\n stop(): void {\r\n this.isRunning = false;\r\n if (this.animationId) {\r\n cancelAnimationFrame(this.animationId);\r\n this.animationId = 0;\r\n }\r\n }\r\n\r\n private animate(): void {\r\n if (!this.isRunning) return;\r\n this.render();\r\n this.animationId = requestAnimationFrame(this.animate.bind(this));\r\n }\r\n\r\n private render(): void {\r\n this.camera.setAspect(this.renderer.getAspectRatio());\r\n this.controls.update();\r\n\r\n // 每帧更新 billboard 热点朝向\r\n this.hotspotManager.updateBillboards();\r\n\r\n const pass = this.renderer.beginFrame();\r\n\r\n // 渲染 3D Gaussian Splatting\r\n const gsRenderer = this.sceneManager.getGSRenderer();\r\n if (gsRenderer) {\r\n gsRenderer.render(pass);\r\n }\r\n\r\n // 渲染网格\r\n this.meshRenderer.render(pass);\r\n\r\n // 渲染 Gizmo\r\n this.gizmoManager.render(pass);\r\n\r\n this.renderer.endFrame();\r\n\r\n // 在提交新的深度法线渲染Pass之前,读取上一帧的深度法线GPU回读结果,更新指示器\r\n this.hotspotManager.consumeGPUResult();\r\n\r\n // 提交新的深度法线渲染Pass,用于热点拾取(重用排序结果)\r\n if (gsRenderer?.prepareDepthNormalPass) {\r\n const [px, py] = this.hotspotManager.getPickPixel();\r\n gsRenderer.prepareDepthNormalPass(px, py);\r\n }\r\n }\r\n\r\n private onResize(): void {\r\n this.camera.setAspect(this.renderer.getAspectRatio());\r\n this.camera.updateMatrix();\r\n }\r\n\r\n // ============================================\r\n // 场景管理(委托给 SceneManager)\r\n // ============================================\r\n\r\n getMeshCount(): number {\r\n return this.sceneManager.getMeshCount();\r\n }\r\n\r\n getMeshByIndex(index: number): Mesh | null {\r\n return this.sceneManager.getMeshByIndex(index);\r\n }\r\n\r\n getMeshRange(startIndex: number, count: number): Mesh[] {\r\n return this.sceneManager.getMeshRange(startIndex, count);\r\n }\r\n\r\n clearMeshes(): void {\r\n this.sceneManager.clearMeshes();\r\n }\r\n\r\n removeMeshByIndex(index: number): boolean {\r\n const result = this.sceneManager.removeMeshByIndex(index);\r\n return result;\r\n }\r\n\r\n getSplatCount(): number {\r\n return this.sceneManager.getSplatCount();\r\n }\r\n\r\n clearSplats(): void {\r\n this.sceneManager.clearSplats();\r\n this.hotspotManager.setGSRenderer(null);\r\n this.useMobileRenderer = false;\r\n }\r\n\r\n // ============================================\r\n // Splat 变换(委托给 SceneManager)\r\n // ============================================\r\n\r\n setSplatPosition(x: number, y: number, z: number): void {\r\n this.sceneManager.setSplatPosition(x, y, z);\r\n }\r\n\r\n getSplatPosition(): [number, number, number] | null {\r\n return this.sceneManager.getSplatPosition();\r\n }\r\n\r\n setSplatRotation(x: number, y: number, z: number): void {\r\n this.sceneManager.setSplatRotation(x, y, z);\r\n }\r\n\r\n getSplatRotation(): [number, number, number] | null {\r\n return this.sceneManager.getSplatRotation();\r\n }\r\n\r\n setSplatScale(x: number, y: number, z: number): void {\r\n this.sceneManager.setSplatScale(x, y, z);\r\n }\r\n\r\n getSplatScale(): [number, number, number] | null {\r\n return this.sceneManager.getSplatScale();\r\n }\r\n\r\n // ============================================\r\n // SH 模式\r\n // ============================================\r\n\r\n setSHMode(mode: 0 | 1 | 2 | 3): void {\r\n this.sceneManager.setSHMode(mode);\r\n }\r\n\r\n getSHMode(): number {\r\n return this.sceneManager.getSHMode();\r\n }\r\n\r\n // ============================================\r\n // Bounding Box\r\n // ============================================\r\n\r\n getSplatBoundingBox(): BoundingBox | null {\r\n return this.sceneManager.getSplatBoundingBox();\r\n }\r\n\r\n getMeshRangeBoundingBox(startIndex: number, count: number): BoundingBox | null {\r\n return this.sceneManager.getMeshRangeBoundingBox(startIndex, count);\r\n }\r\n\r\n // ============================================\r\n // 材质颜色\r\n // ============================================\r\n\r\n getMeshColor(index: number): [number, number, number, number] | null {\r\n return this.sceneManager.getMeshColor(index);\r\n }\r\n\r\n setMeshColor(index: number, r: number, g: number, b: number, a: number = 1): boolean {\r\n return this.sceneManager.setMeshColor(index, r, g, b, a);\r\n }\r\n\r\n setMeshRangeColor(startIndex: number, count: number, r: number, g: number, b: number, a: number = 1): number {\r\n return this.sceneManager.setMeshRangeColor(startIndex, count, r, g, b, a);\r\n }\r\n\r\n // ============================================\r\n // 覆盖层 Mesh(热点等)\r\n // ============================================\r\n\r\n getOverlayMeshCount(): number {\r\n return this.sceneManager.getOverlayMeshCount();\r\n }\r\n\r\n removeOverlayMeshByIndex(index: number): boolean {\r\n return this.sceneManager.removeOverlayMeshByIndex(index);\r\n }\r\n\r\n getOverlayMeshColor(index: number): [number, number, number, number] | null {\r\n return this.sceneManager.getOverlayMeshColor(index);\r\n }\r\n\r\n setOverlayMeshRangeColor(startIndex: number, count: number, r: number, g: number, b: number, a: number = 1): number {\r\n return this.sceneManager.setOverlayMeshRangeColor(startIndex, count, r, g, b, a);\r\n }\r\n\r\n createOverlayMeshGroupProxy(startIndex: number, count: number): MeshGroupProxy | null {\r\n const meshes = this.sceneManager.getOverlayMeshRange(startIndex, count);\r\n return this.gizmoManager.createMeshGroupProxy(meshes);\r\n }\r\n\r\n // ============================================\r\n // 相机控制\r\n // ============================================\r\n\r\n frameCurrentModel(animate: boolean = true): boolean {\r\n const bbox = this.sceneManager.getSceneBoundingBox();\r\n if (!bbox) {\r\n return false;\r\n }\r\n\r\n this.controls.frameModel(bbox.center, bbox.radius, animate);\r\n return true;\r\n }\r\n\r\n // ============================================\r\n // Gizmo(委托给 GizmoManager)\r\n // ============================================\r\n\r\n getTransformGizmo() {\r\n return this.gizmoManager.getTransformGizmo();\r\n }\r\n\r\n getViewportGizmo() {\r\n return this.gizmoManager.getViewportGizmo();\r\n }\r\n\r\n getBoundingBoxRenderer() {\r\n return this.gizmoManager.getBoundingBoxRenderer();\r\n }\r\n\r\n setGizmoMode(mode: GizmoMode): void {\r\n this.gizmoManager.setGizmoMode(mode);\r\n }\r\n\r\n setGizmoTarget(object: TransformableObject | null): void {\r\n this.gizmoManager.setGizmoTarget(object);\r\n }\r\n\r\n setSelectionBoundingBox(box: SimpleBoundingBox | null): void {\r\n this.gizmoManager.setSelectionBoundingBox(box);\r\n }\r\n\r\n setSelectionBoundingBoxProvider(provider: BoundingBoxProvider | null): void {\r\n this.gizmoManager.setSelectionBoundingBoxProvider(provider);\r\n }\r\n\r\n clearSelectionBoundingBox(): void {\r\n this.gizmoManager.clearSelectionBoundingBox();\r\n }\r\n\r\n /**\r\n * 创建 Mesh 组的变换代理\r\n */\r\n createMeshGroupProxy(startIndex: number, count: number): MeshGroupProxy | null {\r\n const meshes = this.sceneManager.getMeshRange(startIndex, count);\r\n return this.gizmoManager.createMeshGroupProxy(meshes);\r\n }\r\n\r\n /**\r\n * 获取 Splat 的变换代理\r\n */\r\n getSplatTransformProxy(): SplatTransformProxy | null {\r\n const gsRenderer = this.sceneManager.getGSRenderer();\r\n if (!gsRenderer) return null;\r\n return this.gizmoManager.createSplatTransformProxy(gsRenderer);\r\n }\r\n\r\n /**\r\n * 创建 Splat 包围盒提供者\r\n */\r\n createSplatBoundingBoxProvider(): SplatBoundingBoxProvider | null {\r\n const gsRenderer = this.sceneManager.getGSRenderer();\r\n if (!gsRenderer) return null;\r\n return this.gizmoManager.createSplatBoundingBoxProvider(gsRenderer);\r\n }\r\n\r\n // ============================================\r\n // 子系统访问\r\n // ============================================\r\n\r\n getRenderer(): Renderer {\r\n return this.renderer;\r\n }\r\n\r\n getCamera(): Camera {\r\n return this.camera;\r\n }\r\n\r\n getControls(): OrbitControls {\r\n return this.controls;\r\n }\r\n\r\n getMeshRenderer(): MeshRenderer {\r\n return this.meshRenderer;\r\n }\r\n\r\n getGSRenderer(): GSSplatRenderer | undefined {\r\n const renderer = this.sceneManager.getGSRenderer();\r\n if (renderer && !this.useMobileRenderer) {\r\n return renderer as GSSplatRenderer;\r\n }\r\n return undefined;\r\n }\r\n\r\n getGSRendererMobile(): GSSplatRendererMobile | undefined {\r\n const renderer = this.sceneManager.getGSRenderer();\r\n if (renderer && this.useMobileRenderer) {\r\n return renderer as GSSplatRendererMobile;\r\n }\r\n return undefined;\r\n }\r\n\r\n isUsingMobileRenderer(): boolean {\r\n return this.useMobileRenderer;\r\n }\r\n\r\n // ============================================\r\n // 热点管理\r\n // ============================================\r\n\r\n getHotspotManager(): HotspotManager {\r\n return this.hotspotManager;\r\n }\r\n\r\n enterHotspotMode(objUrl: string): void {\r\n this.hotspotManager.setHotspotOBJUrl(objUrl);\r\n this.hotspotManager.enter();\r\n }\r\n\r\n exitHotspotMode(): void {\r\n this.hotspotManager.exit();\r\n }\r\n\r\n isHotspotModeActive(): boolean {\r\n return this.hotspotManager.isActive();\r\n }\r\n\r\n getHotspots(): HotspotInfo[] {\r\n return this.hotspotManager.getHotspots();\r\n }\r\n\r\n setHotspotBillboard(hotspotIndex: number, enabled: boolean): boolean {\r\n return this.hotspotManager.setHotspotBillboard(hotspotIndex, enabled);\r\n }\r\n\r\n getHotspotBillboard(hotspotIndex: number): boolean {\r\n return this.hotspotManager.getHotspotBillboard(hotspotIndex);\r\n }\r\n\r\n getHotspotCount(): number {\r\n return this.hotspotManager.getHotspotCount();\r\n }\r\n\r\n findHotspotIndexByMeshStart(overlayMeshStartIndex: number): number {\r\n return this.hotspotManager.findHotspotIndexByMeshStart(overlayMeshStartIndex);\r\n }\r\n\r\n getOverlayMeshByIndex(index: number): import(\"./mesh/Mesh\").Mesh | null {\r\n return this.sceneManager.getOverlayMeshByIndex(index);\r\n }\r\n\r\n // ============================================\r\n // 内部方法\r\n // ============================================\r\n\r\n private async fetchWithProgress(\r\n url: string,\r\n onProgress?: (progress: number) => void\r\n ): Promise<ArrayBuffer> {\r\n const response = await fetch(url);\r\n if (!response.ok) {\r\n throw new Error(`无法加载文件: ${url}`);\r\n }\r\n\r\n const contentLength = response.headers.get('content-length');\r\n if (!contentLength || !response.body) {\r\n const buffer = await response.arrayBuffer();\r\n if (onProgress) onProgress(100);\r\n return buffer;\r\n }\r\n\r\n const total = parseInt(contentLength, 10);\r\n const reader = response.body.getReader();\r\n const chunks: Uint8Array[] = [];\r\n let loaded = 0;\r\n\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n\r\n chunks.push(value);\r\n loaded += value.length;\r\n\r\n if (onProgress) {\r\n onProgress((loaded / total) * 100);\r\n }\r\n }\r\n\r\n const buffer = new ArrayBuffer(loaded);\r\n const view = new Uint8Array(buffer);\r\n let offset = 0;\r\n for (const chunk of chunks) {\r\n view.set(chunk, offset);\r\n offset += chunk.length;\r\n }\r\n\r\n return buffer;\r\n }\r\n\r\n private async parsePLYBuffer(\r\n buffer: ArrayBuffer,\r\n options: { maxSplats?: number; loadSH?: boolean; onProgress?: (loaded: number, total: number) => void }\r\n ): Promise<import('./gs/PLYLoaderMobile').CompactSplatData> {\r\n const { parsePLYBuffer } = await import('./gs/PLYLoaderMobile');\r\n return parsePLYBuffer(buffer, options);\r\n }\r\n\r\n /**\r\n * 销毁应用及所有资源\r\n */\r\n destroy(): void {\r\n this.stop();\r\n window.removeEventListener(\"resize\", this.boundOnResize);\r\n\r\n this.sceneManager.destroy();\r\n this.gizmoManager.destroy();\r\n this.hotspotManager.destroy();\r\n\r\n if (this.meshRenderer) {\r\n this.meshRenderer.destroy();\r\n }\r\n\r\n if (this.controls) {\r\n this.controls.destroy();\r\n }\r\n\r\n if (this.renderer) {\r\n this.renderer.destroy();\r\n }\r\n }\r\n}\r\n"],"names":["SHMode","computeBoundingBox","max","TYPE_SIZES","_a","parseHeader","validatePLYMagic","extractHeader","readProperty","sigmoid","SH_C0","l","WORKGROUP_SIZE","generateCullingShaderCode","_b","GizmoMode","plane","dist","buffer","parsePLYBuffer"],"mappings":"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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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AAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwXrC,MAAM;AAAA;AAAA,EAAiC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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","x_google_ignoreList":[19]}
|