目录 | 网格体的属性中心点和顶点Base128:变长整数编码复合型网格体PMC和RMC |
---|
本文探讨网格体的压缩存储与背后的信息论,实现数据库与虚幻引擎(UE)解耦,目的是仅仅将UE作为一个渲染器,让数据与渲染分离,以适应千万级构件的项目需求。
首先需要明确,我们看到的3维模型都是中空的,基本都只是闭合的表面,这一点从“网格体”的名字也能看出。从存储的角度看,网格体只是由一个个顶点组成,既没有“面”也没有“体”:因为平面可以由3个点来确定,立体可以由闭合的面确定,不用额外存储信息,以此达到压缩最大化的目的。所以3维网格体看上去是由若干个三角形组成,存储时都是一些点而已。一个完整的网格体(mesh)可以由一系列基本的几何信息描述,它们包含:
其中有些信息是必要的,有些是可选的,有些是必要但可替换的。一般而言,顶点坐标信息是首要的,虽然闭合的凸面体可以根据顶点信息演算出来,但这种情况很少,法线和切线可以根据三角形的位置和三点的顺序来确定,如果只考虑纯色材质,顶点色可以取代贴图以节省体积,UV坐标和纹理贴图就可有可无了。所以存储在PostGIS或者MongoDB中的每个网格体至少需要以下3个字段:
如果想要进一步压缩,纹理贴图可以替换成顶点色数组,但只能实现单调的表面着色,应用场景非常有限,接下来分析这些个字段的存储格式。
顶点坐标的数据存储比较直观,就是3个float32浮点数为一组,无缝拼接的字节串,字节的数量是12的倍数,倍数=顶点数。
GPU接收的三角形数组是以顶点编号为基础,3个1组传递来实现的,所以三角形数组的长度是3的整数倍,倍数就是三角形的数量。因为顶点编号是从0开始的自然数,所以三角形数组是一个自然数组,对于每个自然数,如果用定长整数编码比如int16或int32无疑会造成空间浪费,这里应当使用变长自然数编码:Variable Length Quantity 或者叫Base128编码。这种编码可以将更小的自然数存储在更短的字节中,比如0~127的整数只占1个字节,原理并不复杂,可以参考这个规范:
https://github.com/zipack/spec/blob/master/spec.md#the-biased-vlq-natural-number
对于结构上有公共部分,或者呈包含关系的多个网格体,在PostGIS中需要通过引用的方式存储公共组件,虚幻引擎中也应该通过继承等方式复用公共组件,从而以达到节省内存/外存的目的。虚幻引擎中,对于只有transformation属性不同的同一种网格体,应当使用InstancedStaticMesh来暗示编译器实现最大化的复用率,
PMC指ProceduralMeshComponent,是引擎原生提供的运行时mesh生成环境,它包括基本几何信息和网格体之间的双向转换函数:GetSectionFromStaticMesh和CreateMeshSection,以及在构造函数中混合复用mesh的能力。在PMC的基础之上,官方推荐的插件RMC(RuntimeMeshComponent)做了一些列性能优化和功能升级,包括使用多线程的计算力。