3D高斯飞溅数据压缩[高斯飞溅]
2023-11-15 本站作者 【 字体:大 中 小 】
上一篇文章,我开始研究3D高斯喷溅。它的一个问题是数据集不小。渲染看起来不错。
而“自行车”,“卡车”,“花园”数据集分别是1.42GB,0.59GB,1.35GB的PLY文件。它们几乎是作为一个巨大的结构化缓冲区加载到GPU内存中的,因此至少需要那么多VRAM,再加上更多用于排序,在官方的查看器实现中,平铺splat光栅化使用了数百MB。
我可以告诉你,我可以把数据缩小19倍(分别是78 MB,32 MB,74 MB),但是看起来不怎么样。还是可以辨认的,但是真的不好——不过,这些伪影不是典型的“低LOD多边形网格渲染”,它们更像是“空间中的JPG伪影”:
然而,在这两个极端之间,还有其他配置可以使数据小五到十倍,同时又很好看。
因此,我们从每个splat 248字节开始,我们希望减少它。注意:这里我将探讨存储和运行时内存的使用,即不是“文件压缩”!相反,我还想降低GPU的内存消耗。减少运行时数据的副作用也会让磁盘上的数据变小,但是“存储大小”是另一个完全独立的话题。也许改天吧!
对splat数据要做的一件显而易见且简单的事情是注意到“正常的”(12字节)是完全未使用的。但是省不了多少。然后当然可以尝试把所有的数字都设置成Float16而不是Float32,这样也不错,但是只会让数据变小两倍。
也可以丢弃所有球谐数据,只留下“原色” (SH0),这样数据大小会减少75%!这确实改变了照明,消除了一些“反射和”,在运动中更明显,但逐渐减少质量等级较低的SH波段(或逐渐加载)是简单而明智的。
当然,让我们看看我们还能做些什么:)
线上工具推荐:Three.js AI纹理开发工具包- YOLO合成数据生成器- GLTF/GLB在线编辑- 3D模型格式在线转换-可编程3D场景编辑器。
1.重新排序和剪切的数据文件中的splats的顺序并不重要;无论如何,渲染的时候我们都会按距离排序。在层数据文件中,它们实际上是随机的,其中每个点是一个块,颜色是基于点索引的渐变:
但是我们可以按照“位置”(或者其他任何标准)重新排序。例如,按3D Morton顺序对它们进行排序通常会使空间中的相邻点在数据阵列中彼此靠近:
然后,我可以将splats分组为N个块(N = 256是我的选择),并希望因为它们通常靠得很近,所以可能它们的数据方差很低,或者至少它们的数据可以以某种方式表示更少的比特。如果我想象块边界框,它们通常很小并且分散在整个场景中:
这差不多是幻灯片1的112-11-从失败中学习”梦想演讲。
未来工作:尝试希尔伯特曲线排序代替莫顿。也可以尝试“部分填充块”打破块边界,每次莫顿曲线翻转到另一边都会出现这种情况。
顺便说一下,Morton重新排序还可以使渲染速度更快,因为即使按距离排序后,附近的点也更有可能位于原始数据数组附近。当然,你可以在Fabian的博客上找到好的代码来执行Morton计算,而不依赖于身体质量指数或类似的CPU指令,并在这里为64位结果进行调整:
//基于https://fgiesen . WordPress . com/2009/12/13/decoding -Morton -codes/ //在x的21个低位后插入两个0位 静态ulong MortonPart1By2(ulong x) { x & = 0x1fffff x =(x ^(x & lt;& lt32))& 0x1f 00000000 fffful; x =(x ^(x & lt;& lt16))& 0x1f 0000 ff 0000 fful; x =(x ^(x & lt;& lt8))& 0x 100 f 00 f 00 f 00 f 00 ful; x =(x ^(x & lt;& lt4))& 0x 10 c 30 c 30 c 30 c 30 c 3 ul; x =(x ^(x & lt;& lt2))& 0x 1249249249249249 ul; 返回x; } //将三个21-位整数编码成3D Morton顺序 公共静态ulong mortone code 3(uint 3v) { return(Morton part 1 by 2(v . z)& lt;& lt2)|(Morton part 1 by 2(v . y)& lt;& lt1)| Morton part 1 by 2(v . x); }2.将所有数据设为0..1相对于块。现在所有的块都被切割成256块大小的块。我们可以计算所有内容的最小和最大数据值(位置、比例、颜色、SH等。)并存储它们。我们不在乎数据大小(还是?);把它们存储在一个完整的浮点数中。
现在,调整splat数据,使所有数字都在0的范围内..1在块的最小值和最大值之间。如果像以前一样将它保存在Float32中,它不会以任何明显的方式真正改变精度,只是在渲染着色器中添加一些间接数据(为了计算最终的splat数据,您需要获得块min和max,并根据splat值在它们之间进行插值)。
哦,对于旋转,我把四元数编码成“最小三个”的格式(存储最小三个分量,加上最大分量的索引)。
既然数据都在0的范围内..1,我们可以尝试用比完整Float更小的数据类型来表示它32!
但是首先,所有的0..1数据长什么样?以下是以RGB颜色显示的各种数据,每张图片一个像素,以行为主顺序。通过位置,可以清楚地看到它以大小为256的块为单位变化(每条水平线有两个块):
旋转确实有一些水平条纹,但更随机:
也有一些比例的横向模式,但我们也可以看到,大多数比例都倾向于较小的值:
颜色(SH0)如下所示:
不透明度通常是几乎透明或几乎不透明:
球谐带很多,往往看起来很乱,所以这是其中之一:
3.嘿,这个数据看起来像纹理!我们为每个“事物”提供了3或4个值(位置、颜色、旋转...),而现在这些值都在0的范围内..1.我知道!让我们把它们放到纹理中,每个splat一个纹理元素。那么我们就可以很容易地尝试在它们上面使用各种纹理格式,让GPU纹理采样硬件来完成所有将数据转换成数字的繁重工作。
我不知道,我们甚至可以用一些疯狂的东西,比如在这些纹理上使用压缩纹理格式(比如BC1或者BC7)。这样有效吗?事实证明,不是立即。在这里,所有的数据(位置,旋转,比例,颜色/不透明度,SH)都被转换成BC7压缩纹理。数据只有122MB(小12倍),但PSNR与完整的Float32数据相比低至21.71:
然而,我们知道GPU纹理压缩格式是基于块的。例如,在典型的PC上,BCn压缩格式都基于4x4纹理像素块。但是我们的纹理数据是以256x1条纹的splat块的形式排列的,一个接一个。我们再把它们重新排序一下,也就是把每个块排列成一个16x16的texel正方形,再按Morton顺序排列。
uint encodemorton 2d _ 16x 16(uint 2c) { uint t =((c . y & 0xF)& lt;& lt8)|(c . x & 0xF);// ----EFGH----ABCD t =(t ^(t & lt;& lt2))& 0x 3333;// --EF--GH--AB--CD t =(t ^(t & lt;& lt1))& 0x 5555;// -E-F-G-H-A-B-C-D return(t |(t & gt;& gt7))& 0x ff;//---------EAFBGCHD } uint 2 decodemoton 2d _ 16x 16(uint t)//-------EAFBGCHD { t =(t & 0x ff)|((t & 0x Fe)& lt;& lt7);// -EAFBGCHEAFBGCHD t & = 0x5555// -E-F-G-H-A-B-C-D ^(t & gt;& gt1))& 0x 3333;// --EF--GH--AB--CD ^(t & gt;& gt2))& 0x 0 f 0f;// ----EFGH----ABCD return uint2(t & 0xF,t & gt& gt8);//---------EFGHABCD }如果我们以这种方式重新排列所有的纹理数据,它现在将看起来像这样(位置、旋转、缩放、颜色、不透明度、SH1):
把这些都编码成BC7可以大大提高质量(PSNR 21.71→24.18):
4.那么我应该使用什么纹理格式呢?在尝试了很多可能的设置后,这是我得出的质量设置水平。格式如下表所示:
F32x4:4x Float32(128 (128位))。由于GPU通常没有三通道Float32纹理格式,在这种情况下,我在只需要三个分量的情况下扩展数据是没有用的。F16fx4: 4xfloat 16 (64位)。类似于以上四个组件的扩展。Norm10_2:无符号标准化10.10.10.2(32位)。GPU确实支持这个,Unity也差不多支持-。它公开了格式枚举成员,但实际上不允许你使用格式创建纹理(哈哈!)。所以我模拟了一下纹理,假装是单组件Float32格式,在着色器中手动“解包”。Norm11:无符号标准化11.10.11(32位)。GPU没有,但是既然我反正是在模拟一个类似的格式(见上),为什么我们只需要三个组件的时候不用更多的位呢?Norm 8x4: 4x无符号标准化字节(32位)。Norm565:无符号标准化5.6.5(16位)。BC7和BC1:很明显,分别是8位和4位。质量
刷卡机
腐烂
Scl
山口
嘘
压缩机
PSNR
极高
F32x4
F32x4
F32x4
F32x4
F32x4
0.8倍
高的
F16x4
Norm10_2
Norm11
F16x4
Norm11
2.9x
54.82
中间
Norm11
Norm10_2
Norm11
Norm8x4
Norm565
5.2倍
47.82
低的
Norm11
Norm10_2
Norm565
BC7
BC1
12.2倍
34.79
极低
BC7
BC7
BC7
BC7
BC1
18.7倍
24.02
5.结论和未来工作高斯飞溅数据的大小(磁盘上和内存中)可以很容易地减少5倍到12倍,渲染质量水平是完全可以接受的。比如“花园”场景,1.35GB的数据文件“ Gee,听起来有点过分的”,但是到了110-260MB,就变得更有意思了。肯定不小,但是比较实用。
我觉得很有意思的是,“以某种方式排列splat数据”,然后不仅通过将每个splat单独编码成更小数量的比特来压缩它们,还在邻域”中压缩“(例如使用BC7或BC1)。特别是即使BC1压缩,球谐数据看起来也相当不错(不像“明显误差”的旋转或缩放,有助于判断球谐系数何时出错:)。
我可以尝试许多小事:
重新排序splat:不仅按照位置重新排序Splat,还按照“其他内容”重新排序Splat。试试希尔伯特曲线而不是莫顿曲线。每次曲线翻转到另一边时,尽量使用大小为256的不完全块。颜色/不透明度编码:将它们放在两个独立的纹理中,而不是试图让BC7压缩它们,这可能是值得的。我很想知道如何降低纹理分辨率,可能是针对某些组件(球谐?颜色如果不透明度是独立的?您可以使用较低分辨率的纹理,即每个splat少于1个纹理元素。当然,还有一个更大的问题,在某种意义上,这种减少数据量的方式是否明智。也许像“纹理的随机存取神经压缩”(Vaidyanathan,萨尔维,Wronski 2023)这样的东西会起作用?要是懂点“神经/机器学习”:)就好了
我上面所有的代码都在github上的这个PR里。
原文链接:http://www.bimant.com/blog/3d-Gaussian -splatting -压缩/
猜你喜欢
为什么还有人回收旧DVD碟片?旧的DVD碟片有什么价值?
还是看不懂BIOS?详细的中英文对照表,进入BIOS如此简单,值得收藏!
如何打开一个ZIP文件
怎么找回删除的微信好友,这些方法助你快速找回
手机屏幕一闪一闪的是怎么回事?
淘宝直播有杂音怎么解决
手机“一个人”有什么用?抛开具体体验,就一文不值了!
相比700元,小米14有必要升级14 Pro吗?一条短信告诉你答案。
手机wps怎么压缩文件?
如何解除小米手机开机密码
华为哪款手机玩游戏性能最好
扩音器什么品牌音质最好(哪个品牌的扩音器音质最佳?)
铠侠固态硬盘怎么样(铠侠固态硬盘的表现如何?)
公认最静音的电风扇(国内10大电风扇品牌排行)
光信号闪红灯会自己好吗(路由器闪红灯是怎么回事)
联想k29为什么是神机(联想k29怎么样)
国内冰箱排名前十的品牌(质量最好的10大冰箱品牌)
凯夫拉手机壳怎么样(凯夫拉手机壳的表现如何?)
键盘突然没反应是怎么回事
垃圾处理器有必要买吗(垃圾处理器值得买吗)