【免费下载链接】splat-transform
CLI tool and library for 3D Gaussian splat processing and conversion
如果你处理过大型 3D 高斯 splat 文件,大概率遇到过这样的现象:同样是几千万个点,有的文件加载快、压缩比高、LOD 切换流畅,有的却怎么都不行。splat-transform 给出了一个朴素却极其有效的答案——用Morton 码排序(Z-order 曲线)重排高斯点,换取更好的空间局部性。
本文带你搞清楚三件事:Morton 码到底是什么、为什么它能让高斯点云"听话",以及 splat-transform 是如何在一条命令行里完成这套排序的。
什么是 Morton 码:把三维空间"折叠"成一条线
想象你有一张 4×4×4 的三维网格,想把里面的格子排成一条一维的线。最笨的办法是沿 x 轴排完再换行,但这样相邻格子经常"跳"到很远的地方。
Morton 码的做法很巧妙:把三个坐标的二进制位交错排列。比如坐标(x, y, z)的位序x2 x1 x0/y2 y1 y0/z2 z1 z0,交错后得到z2 y2 x2 z1 y1 x1 z0 y0 x0。空间上相邻的点,其 Morton 码数值差通常很小;数值接近的点,空间上也往往挨着。
这样,三维的"邻居关系"就被"折叠"进了一维的"先后关系"。在 splat-transform 源码中,这个编码逻辑见 morton-order.ts:先将每根轴归一化到 0~1023(10 位),再用位运算把三位坐标交织成一个 30 位的 Morton 码。
为什么高斯点需要按 Morton 码排序
训练出来的原始 splat 文件(比如 PLY)里的点,顺序往往由训练过程决定,本质上接近随机。这带来几个实际问题:
| 场景 | 随机顺序的痛点 | Morton 排序后 |
|---|---|---|
| 顺序读盘/读内存 | 缓存命中差,随机跳跃访问 | 相邻索引 = 相邻空间位置,预读命中率高 |
| 分块(chunk)存储 | 一个块可能散落在全场景 | 每个块只覆盖一小块区域,按需加载更精准 |
| 体块/八叉树构建 | 块归属分散,树构建低效 | 同父节点的块在码序上天然聚在一起 |
| 简化(decimate) | 读到的行碎片化,空间相干性差 | 每个块的源行形成少数连续段,读放大显著下降 |
一句话:排序不改变任何点的属性,只改变它们的存放顺序,却能让后续所有"按空间范围取数据"的操作都变成顺序访问。这就是所谓空间局部性。
一条命令完成 Morton 码排序
splat-transform 的 CLI 把这件事包装成了一个 action:-m, --morton-order。
splat-transform input.ply -m output.ply- 输入可以是任意已支持格式(
.ply、.spz、.sog等),-m会在流水线中重排所有高斯点; - 排序基于点当前的世界坐标,若之前做过
-t/-r/-s变换,记得按"先变换、后排序"的顺序书写; - 处理逻辑见 process.ts:先生成 0..N-1 的索引数组,调用
sortMortonOrder原地排好序,再用permuteRowsInPlace一次性置换整张数据表,无需逐行拷贝。
数据表层面的适配器在 morton-order.ts,只需 x/y/z 三列即可工作。
源码拆解:30 位码 + 基数排序 + 递归细化
splat-transform 的排序核心在 morton-order.ts,设计上有三个值得注意的点:
自适应量化:先扫一遍点云求出包围盒(min/max),再按各轴实际跨度把坐标映射到 10 位整数,保证分辨率"用满"而不是被固定网格浪费。
LSD 基数排序:30 位 Morton 码拆成三段,做三轮各 10 位的稳定基数排序(前缀和定桶 + 稳定散列),复杂度 O(n),避免逐对比较的 O(n log n) 开销。稳定排序保证码相同的点保持原始相对顺序。
递归细化(这是精髓):1024×1024×1024 的网格装不下千万级点,同一码下可能挤着几百个点。实现里会找出所有"码相同且超过 256 个"的桶,对这个子区间重新求包围盒、重新量化、再排一遍——相当于对拥挤区域自动放大地图,直到点被真正分开。见 morton-order.ts。
同一套内核还提供列式与交错式两个入口(sortMortonColumns/sortMortonInterleaved),分别服务数据表列存储和 GPU 纹理行缓冲,避免无谓的数据重排拷贝。
Morton 码在 splat-transform 里的"隐藏用途"
-m只是显式入口,Morton 排序其实贯穿了多条输出管线:
- Compressed PLY 默认就排好序:写出压缩 PLY 前会先做一次 Morton 排序,让每个压缩 chunk 只覆盖场景的一小块区域。见 write-compressed-ply.ts。
- LOD 分块靠它定位:生成 Streamed SOG(
lod-meta.json)时,按空间 extent 划分 chunk 的 partition/bounds 流程全部依赖 Morton 有序的数据。见 write-lod.ts。 - 稀疏八叉树的骨架:碰撞体输出的
.voxel.json把体块坐标编码成 51 位 Morton 码(每轴 17 位,支持 13 万块/轴),码序即八叉树的紧凑遍历顺序。见 morton.ts 与 sparse-octree.ts。 - 简化管线的"体检报告":decimate 的分区模块会统计每个块的源行形成多少连续段(coherence runs)——Morton 有序的文件每个块只有少数几段,而训练顺序文件几乎一行一段。此时它会建议你做一次
--morton-order预排序。见 partition.ts。
小结
回到开头的问题:为什么高斯点要用 Morton 码排序?因为空间局部性是图形数据的第一生产力。一次 O(n) 的重排,就能让后续读盘、压缩、LOD 分块、八叉树构建、几何简化全部受益,而点的颜色、形状、位置一个都没变。
如果你的 splat 文件体积偏大、加载偏慢,不妨先试一条命令:
splat-transform input.ply -m output.ply再配合--stats观察各列统计,感受空间有序带来的变化。更多用法可查阅 README.md 中的 Actions 与 CLI Options 章节。
【免费下载链接】splat-transform
CLI tool and library for 3D Gaussian splat processing and conversion
相关推荐
为什么你的Android应用性能不佳?android-tips-tricks调试技巧揭秘
为什么你的Android应用性能不佳?android tips tricks调试技巧揭秘 你是否经常遇到Android应用卡顿、耗电快、内存泄漏等问题?😫 这
文档教程移动开发为什么高级开发都需要Coder-Kung-Fu?揭秘系统性能优化的底层密码
为什么高级开发都需要Coder Kung Fu?揭秘系统性能优化的底层密码 在当今高速发展的技术时代, 系统性能优化 已成为每个高级开发工程师必须掌握的核心技能
技术博客操作系统文档Intel ME安全威胁揭秘:为什么你需要me_cleaner
在当今数字时代,隐私和安全已成为每个用户最关心的问题。你可能不知道的是,几乎所有2006年后生产的Intel主板都内置了一个名为Intel ME(Managem
网络安全嵌入式
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考