3D网格体组成原理




目录

  1. 网格体的属性

  2. 中心点和顶点

  3. Base128:变长整数编码

  4. 复合型网格体

  5. PMC和RMC


本文探讨网格体的压缩存储与背后的信息论,实现数据库与虚幻引擎(UE)解耦,目的是仅仅将UE作为一个渲染器,让数据与渲染分离,以适应千万级构件的项目需求。


网格体的属性

首先需要明确,我们看到的3维模型都是中空的,基本都只是闭合的表面,这一点从“网格体”的名字也能看出。从存储的角度看,网格体只是由一个个顶点组成,既没有“面”也没有“体”:因为平面可以由3个点来确定,立体可以由闭合的面确定,不用额外存储信息,以此达到压缩最大化的目的。所以3维网格体看上去是由若干个三角形组成,存储时都是一些点而已。一个完整的网格体(mesh)可以由一系列基本的几何信息描述,它们包含:

  • 中心点:网格体唯一的中心座标

  • 顶点数组:相对于中心点的相对座标

  • 三角形数组:各个顶点的下标索引,长度是3的倍数

  • 纹理贴图:贴到所有三角形表面上的2维图片

  • UV座标数组:网格体降维映射到贴图上的座标,长度等于顶点数

  • 备用UV座标数组:网格体可以存储多个UV,适应不同贴图

  • 材质属性:除了纹理之外表面的物理属性

  • 切线数组:顶点相切于表面的切线,若不可微则有多条,长度等于顶点数

  • 法线数组:顶点垂直于表面的法线,若非曲面则有多条,长度等于顶点数

  • 顶点色数组:网格体的单调色,长度等于顶点数


其中有些信息是必要的,有些是可选的,有些是必要但可替换的。一般而言,顶点座标信息是首要的,虽然闭合的凸面体可以根据顶点信息演算出来,但这种情况很少,法线和切线可以根据三角形的位置和三点的顺序来确定,如果只考虑纯色材质,顶点色可以取代贴图以节省体积,UV座标和纹理贴图就可有可无了。所以存储在PostGIS或者MongoDB中的每个网格体至少需要以下3个字段:

  • 顶点:网格体的顶点座标列表

  • 三角形:顶点之间组成的面,以及由三角顺序决定的朝向(朝内/朝外)

  • UV座标+贴图:决定网格体纹理的拉伸和平铺

如果想要进一步压缩,纹理贴图可以替换成顶点色数组,但只能实现单调的表面着色,应用场景非常有限,接下来分析这些个字段的存储格式。


中心点和顶点

顶点座标的数据存储比较直观,就是3个float32浮点数为一组,无缝拼接的字节串,字节的数量是12的倍数,倍数=顶点数。


Base128:变长整数编码

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和RMC

PMC指ProceduralMeshComponent,是引擎原生提供的运行时mesh生成环境,它包括基本几何信息和网格体之间的双向转换函数:GetSectionFromStaticMesh和CreateMeshSection,以及在构造函数中混合复用mesh的能力。在PMC的基础之上,官方推荐的插件RMC(RuntimeMeshComponent)做了一些列性能优化和功能升级,包括使用多线程的计算力。



往期回顾


本文分享自微信公众号 - WebHub(myWebHub)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章