图形学笔记(六) 模型与网格(加工中)

模型与网格

常见的模型文件格式

什么是三维模型?

网格是由物体的点云连接形成的,点云中的顶点包括坐标、法线、切线等一系列信息。网格通常由三角形、四边形或者其它凸多边形组成,凹多边形会极大的影响渲染效率。一般的建模规范是,在CG领域尽量保持四边形建模,因为四边形网格能更方便的处理各类特效,同时对美术人员来说也易于修改;而在工业领域则应该导出三角形网格,因为三角形网格更加稳定,方便硬件理解。

工业领域的网格必须是封闭几何体,在3Dmax等模型软件中都有封闭性检查算法。而CG领域的网格则不必是封闭集合体,它可以是带有空洞的普通多边形或者面片,在CG领域使用面片和单面模型可以有效降低渲染消耗。

三维模型本身是不可见的,但可以根据线框在不同细节层次渲染。线框数据通过配置材质和纹理,然后经过着色器的渲染才能表现出完整的外观。

OBJ文件是如何储存模型的?

OBJ是一种几何定义文件格式,Wavefront Technologies公司在可视化加强动画包中第一次使用了这个格式,文件格式是公开的,并具有及其优质的兼容性和跨平台、跨行业的通用性,在所有3D应用软件中被支持。

OBJ文件可以以ASCII编码也可以以二进制格式编码,以ASCII格式编码的后缀名为**.obj**,以二进制格式编码的后缀名为**.mod**。OBJ格式的三维网格模型储存了模型的顶点、面片、法向量纹理等几何信息。

OBJ文件使用标准得Polygon储存格式,直接储存顶点坐标和法线等数据,这导致OBJ文件无法导出骨骼动画,只能储存静态模型和材质信息。

下面的例子是一个标准立方体的**.obj**文件表示。

o cube
# List of geometric vertices, with (x,y,z[,w]) coordinates.
v -0.5 -0.5 0.5
v -0.5 -0.5 -0.5
v 0.5 -0.5 -0.5
v 0.5 -0.5 0.5
v -0.5 0.5 0.5
v 0.5 0.5 0.5
v 0.5 0.5 -0.5
v -0.5 0.5 -0.5

# List of texture coordinates, in (u, v [,w]) coordinates
vt 1 0
vt 1 1
vt 0 1
vt 0 0

# List of vertex normals in (x,y,z) form
vn -0.5774 -0.5774 0.5774
vn -0.5774 -0.5774 -0.5774
vn 0.5774 -0.5774 -0.5774
vn 0.5774 -0.5774 0.5774
vn -0.5774 0.5774 0.5774
vn 0.5774 0.5774 0.5774
vn 0.5774 0.5774 -0.5774
vn -0.5774 0.5774 -0.5774

# Polygonal face element
f 1/1/1 2/2/2 3/3/3 4/4/4
f 5/4/5 6/1/6 7/2/7 8/3/8
f 1/4/1 4/1/4 6/2/6 5/3/5
f 4/4/4 3/1/3 7/2/7 6/3/6
f 3/4/3 2/1/2 8/2/8 7/3/7
f 2/4/2 1/1/1 5/2/5 8/3/8

以"#"开头的行是obj格式中的备注。

obj格式中,使用不同的行标志符来开始一行,比如v/vt/vn/f,这些行标识符用来标注不同类型的数据,每行结尾不需要使用分号。

以o开头的行标注一个模型的开始,之后跟上模型的名称。

以g开头的行标注网格组的开始,之后跟上网格组的名称。一个模型中可以使用多个网格组,不同网格组可以分配不同的材质。如果不声明网格组,则整个模型文件使用同一个网格组。

以v开头的行表示顶点,之后跟上x y z [w]的值来储存顶点坐标。W是可选项,默认为1.0。一些应用支持顶点颜色,用x y z r g b [w]的格式来表示顶点,但这样的obj文件在不支持顶点颜色的应用中可能读取失败。

以vt开头的行表示纹理坐标,俗称uv坐标,之后跟上u v [w]的值来储存uv坐标,一般取值范围在0~1,w是可选项,默认值为0.0。

以vn开头的行表示法线方向,之后跟上x y z的值来储存顶点法线方向,该法线不一定是单位法线。

以f开头的行表示面片,之后跟上索引语句来将顶点分配给面片,索引语句一共有四种格式:

  • 顶点索引:以f v1 v2 v3 …的格式分配的面片。v1、v2、v3等是顶点序号,以文件中第一个v标志行为1,逐个递增。一个面片至少分配3个顶点,但可以分配超过3个顶点,即obj格式不保证三角面。面中顶点的声明顺序一般按逆时针方向,即遵循右手螺旋定则。
  • 纹理坐标索引:以f v1/vt1 v2/vt2 v3/vt3 …的格式分配的面片。v1、v2、v3等是顶点序号,vt1、vt2、vt3等是对应顶点的纹理坐标序号,序号分配方式和v类似。
  • 顶点法线索引:以f v1//vn1 v2//vn2 v3//vn3 …的格式分配的面片。v1、v2、v3等是顶点序号,vn1、vn2、vn3等是对应顶点的法线方向序号,序号分配方式和v类似。
  • 顶点纹理法线索引:以f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 …的格式分配的面片。v1、v2、v3等是顶点序号,vt1、vt2、vt3等是对应顶点的纹理坐标序号,vn1、vn2、vn3等是对应顶点的法线方向序号。

在OBJ文件中如果希望一个顶点在不同面具有不同的纹理坐标或法线,最好的办法是构造多个重合的顶点。

STL文件是如何储存模型的?

STL格式是美国3D SYSTEM公司提出的三位实体造型斯通的一个接口标准,采用三角形面片离散地近似表示三维模型,目前被工业界认为是3D打印和机械塑性领域地标准描述文件格式,在工程学、医学成像以及文物保护等方面广泛应用。

STL文件和OBJ文件能很好的互相转换。由于STL主要用在工业领域,并不关系材质和纹理,所以不保存纹理坐标,仅保存顶点坐标和面片法线方向。STL格式也有二进制和ASCII两种格式。

STL和OBJ格式的差别在于它不逐顶点的保存法向量而是逐面片的保存法向量。

二进制STL文件起始的80个字节是文件头,用于储藏零件名;紧接着用4个字节的整数描述模型的三角面片个数,后面逐个给出每个三角面片的几何信息。每个三角面片占用50个字节,依次是3个4字节浮点数作为面片法向量,3个4字节浮点数作为第1个顶点坐标,3个4字节浮点数作为第2个顶点坐标,3个4字节浮点数作为第3个顶点坐标,最后两个字节描述三角面片的属性信息。一个完整二进制文件的大小为三角面片数乘以50再加上84个字节的首部。

ASCII版本的STL文件逐行给出三角形面片几何信息,其格式如下:

solid filename cube
facet normal 0 1 0
outer loop
vertex -1 0 -1
vertex 1 0 -1
vertex -1 0 1
endloop
endfacet
facet normal 0 1 0
outer loop
vertex 1 0 -1
vertex -1 0 1
vertex 1 0 1
endloop
endfacet
endsolid filename cube

在facet-endfacet段中定义一个面片,在facet normal 后设置面片的法向量。之后用outer loop-endloop包围三个顶点的定义,在outer loop段中的三个顶点是围绕法向量逆时针定义的。

STL的ASCII码格式所占的空间一般是同一个模型二进制格式的五倍大小。

FBX文件是如何储存模型的?

FBX属于AutoDesk设计的模型格式,因为Unity和UE引擎的使用而备受关注。FBX是封装好的二进制文件,没有真正的ASCII格式。虽然在3Dmax等模型软件中,存在将FBX文件导出成ASCII形式的接口,但导出的ASCII格式没有分析价值,在实际使用中,一般只能使用AutoDesk提供的c++ SDK对FBX进行读写,AutoDesk并没有提供FBX的二进制格式,这也是其饱受诟病的原因之一。

FBX以scene graph的结构来储存模型的信息的,从数据结构的角度讨论可以理解为一个多叉树,这种树形的储存结构和Unity、UE等引擎的场景结构十分匹配,并能很好的储存骨骼动画等信息,这也是FBX类型经常出现在游戏和电影等CG中的原因。

这个树从根节点Root开始,每个结点是一个KFbxNode类型的对象。每个KFbxNode维持一个双向的指针,也就是说子结点可以索引到父节点,父节点也可以索引到子结点。KFbxNode拥有一个字段NodeAttribute储存结点的类型,这些类型包括eMesh、eLight、eCamera、eSkeleton等,这个字段可以使用SDK轻松的访问到。

FBX中的Mesh可以使用多种不同得格式储存,包括Nurbes、Polygon、Triangle等。网格中的属性主要包括:顶点坐标、顶点颜色、顶点法向量、顶点切向量、UV坐标等。

在使用FBX SDK时,可以通过任意遍历树的算法来遍历KFbxNode,从中取出需要的数据。如遍历一个Mesh结点后,将它的所有顶点信息取出并整合,就可以把网格信息送往GPU进行渲染了。

Unity中是如何储存模型的?

Unity引擎中用C#实现的Mesh类具有显著的面向对象特性。作为一个引擎,Unity的Mesh类负责将多种不同类型的模型文件封装成适合面向对象编程的Mesh对象。

Unity的Mesh类中最重要的成员包括顶点坐标数组vertices,uv坐标数组uv,三角形索引数组triangles,顶点法线数组normals,顶点切线数组tangents。除此之外,还有顶点颜色数组colors,骨骼数组bones等。

在Unity中,MeshFilter和MeshRenderer这两个脚本被用来实现Draw Call,其中MeshFilter用于装载顶点,而MeshRenderer用于设置渲染状态,Mesh数据必须与这两个脚本配合才能产生渲染效果。

GPU是如何储存模型的?

目前的GPU可以通过被不同的API调用,处理不同结构的顶点数据。如在GLSL中,可以指定包括顶点数组、表面法线数组、颜色数组在内的大量数组作为缓冲区,然后通过不同的API调用实现对不同结构的处理。

最早期的GPU顶点缓冲只使用单个缓冲区(三角形列表)记录顶点信息,一个网格如果包含n个三角形,缓冲区中则有3n个顶点坐标,也就是9n个浮点数,如前文中的STL文件的储存方式,这种方式被称为非索引的三角形列表。在CPU向GPU传送数据时,将顶点坐标储存在连续的数组中,GPU会将每9个连续的浮点数作为一个三角形处理。在最新的DirectX和OpenGL库中依然保留了这样的顶点输入方式。

非索引的三角形列表是直观的,但顶点信息一般都存在冗余。如一个分段数为32的球体网格含有482个顶点和512个多边形,其中有64个三角面和448个四边形面,在传入GPU时这448个四边形面都需要转化为三角面,使用非索引的三角形列表时,GPU将接受总计64 + 448 * 2 = 960个三角形的数组,也就是2880个顶点的数组。而这其中有两个顶点被32个面共用,有480个顶点被6个面共用,总共产生了2 * 31 + 480 * 5 = 2462条冗余顶点信息,达到了惊人的85.5%。

为了减少冗余,可以使用顶点在顶点列表中的索引来代替顶点构建三角形,这就形成了含索引的三角形列表。CPU将提供两份数组,第一份是所有顶点的坐标,第二份是由索引构成的三角形数组。在含有n个顶点、m个三角形的网格中,使用3n个浮点数记录顶点,3m个整数索引记录三角形。GPU会通过3个连续的索引获得3个顶点信息来获得一个待处理的三角形。这有效减少了CPU向GPU传输数据的时间,而间接内存访问带来的GPU的消耗上升对高并行高带宽的GPU来说不值一提。

在分段数为32的球体网格示例中,需要2880 * 3 * 4B = 33.75KB来实现非索引的三角形列表,而只需要482 * 3 * 4B + 512 * 3 * 4B = 16.90KB来实现含索引的三角形列表,空间节省了接近一半。在更复杂、顶点更密集的网格中,冗余数据的减少量会更加客观。

在实际应用中还需要向GPU传递顶点法线数组和纹理坐标数组,它们一般来说和顶点数组长度一致,GPU可以通过索引三角形列表中的同一个索引同时访问三个数组的对应信息。

网格变形算法

什么是Remesh?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值