【转】学习总结之3D模型
最近在学习3D模型方面的知识,先是大致调研了一些流行的3D格式,调研结果见这里。无意间发现了本专门讲这个主题的书Focus on 3D Models,讲得挺不错,推荐下。
3D模型是一个挺有意思的技术主题。在2D游戏中,我们全部靠类似于GameLoft的AuroraGT,这样的动画编辑器,搞定角色的样子和场景中大部分物体。其实用到的技术点很简单:纹理贴图而已,没啥复杂的东西。进入到3D模型里面,才真正领会到图形学的魅力,明白为啥图形学里结合了数学和物理的知识。
有图有真相,先看下面一张图:
可以看出,通过一些面(三角形,多边形,曲面,多为三角形)去构造一个人物的立体轮廓,但是,如何能让这个人物看着更加形象和真实呢?想想,我们可以给他加上纹理材质,不能老杵在哪里,可以有些动作和表情。3D模型就主要解决这些问题。那它是怎么做到的呢?
要想回答这个问题,我们必须思考下面几个问题:
1. 需要包含那些信息?
2. 如何存储这些信息?
3. 如何让模型动起来?
模型数据
由图看以看出,顶点(Vertex)和由顶点构成的面(Face)是比不可少的。根据模型结构的需要我们还会把面分成组,称之为(mesh),比如人的头,身体,腿均是mesh。为了表现得真实和生动显然我们需要纹理和材质。材质的存在就避免不了光照和法线这些信息。进而需要存储动画数据来显示模型的不同行为。动画是3D模型中最为核心的地方,后续专门讲。
存储格式
我们不可能在游戏中动态地生成一个3D模型。一般是美术通过3D工具,比如3DMax,Maya,Blender等编辑好,然后在放在引擎中渲染的。这样就存在一个数据交换的问题:3D工具把编辑好的模型数据存在文件中,引擎读入数据渲染。我们如何去设计和实现数据存储呢?
为了解决这个问题,随着技术的发展出现过各种数据格式。常见的数据格式可以见我上次的调研。总结这些数据格式会发现,常见的存储格式有Binary-Based,ASCII-Based,XML-Based三种。这样跟其设计初衷和满足的需求有关系。
- 解析效率:当然是Binary-Based的最高,所以它经常是最终引擎直接读入的数据。典型代表:MS3D。3DS虽然是基于Binary的,但其chunk式 的结构有很强的扩展性,值得学习。
- 可读性:Binary显然很差。
- 开放性:有些格式是商业软件特有的,没有公开其格式的规范。比如fbx,但有提供相应的SDK. 显然这种一般基于Binary的。
- 交换格式: 由于各种3D软件彼此定义的格式各不一样,没法相互读取。所以存在一些中间交换性质的格式。比如fbx, collada。负责不同软件之间数据的转换。显然可见,为了转换不同的格式,其格式规范必将趋向复杂,解析效率有限。不适合引擎最终读取。
- 静态vs动态:想最早期数据格式-obj,是不支持动画的,所以称之为静态格式。支持动画的称之为动态格式。到如此,设计一个静态格式肯定没多少意义了。而且动态格式一般也兼容静态。没必要单独弄一个出来。
动画实现
作为写过2D游戏的码农,动画其实很简单,就像放电影一样,每个动画由很多帧(Frame)组成。动画的制作工作完全由编辑器完成,导出某种数据格式,引擎只要负责简单的播放而已。到了3D模型动画,引擎不再是一个简单地播放器,需要去做很多计算,实现丰富的效果。在这里数学终于走上舞台,一展其魅力。
先谈关键帧(Key Frame)的概念。在2D中,每一帧都需要编辑器来制作。但在3D中我们采用关键帧技术,只需要存储间断地存储一些帧的信息,中间的其他帧采取插值(Interpolation)来实现。因而,此时游戏引擎不在是一个简单的播放器,而是需要计算很多中间值。具体是采取线性插值的技术。
论及插值,是一个在图形学中经常会遇到的名词。比如我们在纹理渲染中,当纹理大小跟贴图区域不一致是就需要采取线性或双线性插值。线性插值很容易从直观上进行理解,看下图:
在二维平面上存在两个点(x1,y1), (x2,y2), 但我们需要确定第三个点,而且知道其y值,找第三个点的过程就是插值。最简单的就是交点,看下图:
交点处,就是我们需要插入的点。线性插值的基本原理就是如此简单,初中数学知识就能搞定。在实际引擎中,y就是时间t,我们记录两个关键帧的播放时间,中间某个时间t对应的值就非常容易计算。
接上面的话谈,中间的某个值到底是什么呢?这也相当于关键帧里面存储得到底是啥信息?
直观上我们很容易将2D的技术延伸,在2D里面每帧里面就是所有顶点和纹理信息,3D里面我们照样如此,关键帧中存储3D模型中的顶点和面信息,具体可以参考md2格式的动画存储,它就是这么做的。这种3D动画技术一般称之为顶点动画。
技术处于发展之中。总有些聪明人能想去更好的办法解决现有的问题。顶点动画存在什么问题呢?首先我们看关键帧技术存在的意义。由于3D模型的数据量很大,动辄好几百个点,上千个面,如果像2D技术那样去存储每一帧的信息将是非常浪费的事情,所以才有了采取插值计算的方式,去模拟中间过程。但顶点动画的每帧还是存储了每帧所需要的顶点和面信息,而且这种简单的线性插值在模拟动作的过程中,其逼真性也存在一点的问题,动画制作人员也很苦逼,需要针对每帧建模。
没有细心去查阅图形学的发展历史,不知道那个NB人把图形学和物理中的动力学结合起来,创造出一种新的技术:骨骼动画。看到没,其实混搭一直就非常流行。在学习这个技术的时候,我亲自去找美术求教过。他随时弄了个模型,填上几根骨骼,给骨骼管理响应的mesh一把,设置一下权重,模型就可以按照想象的样子动起来。估计没这玩意儿,他们的工作可没如此轻松。
骨骼动画从直观上看其实很简单,你胳膊甩一下的时候,手臂,手肘,手腕,手,手指头是不是跟着一起动呢?他们之间显然是相互关联,存在一个父子关系的,老子动了,儿子必须跟着动。骨头之间的点称之为连接点。我们只需要把整个父子关系维护起来,然后相应关节的位置和旋转角度即可。但我们动的是骨头,真正的皮肉怎么办?很简单骨肉相连,我们只需要把骨头跟相应的皮肉关联起来(这就是所谓的蒙皮),骨头动了,皮肉自然也就动。有图有真相,看下面:
是不是很容易理解?骨骼动画更加符合生物学原理,实现的动画效果也会更加真实。更重要,这个时候每个关键帧只需要存储位置和旋转角度,无须3D模型的mesh数据,存储信息也大大减少。具体实现的时候就存在一些问题。
1. 位置信息用什么表示?
2. 旋转用什么表示?
3. 关键帧之间如何做插值?
4. 最终的顶点坐标如何计算?
这是几个比较关键的问题。在Focus on 3D Models中,专门花了两章的内容,一个讲理论,一个讲具体实现来阐述这些问题。其间涉及不少数学知识,主要是矩阵变换和四元数,比较复杂无法一一阐述。特别是四元数,它主要是在旋转的时候方便做插值。这里无法用简单的线性插值,因为旋转的时候物体是绕着一个点做曲面运动。这方面在3D数学基础中阐述得非常详细。
我理解的3D模型相关的技术要点大致这么多,大都泛泛而论,具体还需要多实践,动手写代码。不对之处还请指出。
《理解矩阵》导读
在学习OpenGL视图部分开始,对各种变换看着云遮雾绕的,始终不得要领。一堆的坐标系,视图变换,模型变换,投影变换各种搅合在一起。三种基本变换:transfer, rotate, scale.一会儿说是在变换物体,一会儿说是变换坐标系,真是晕得慌。
红宝书讲述视图的章节,我至少看了两遍,才敢在分享OpenGL的时候敢讲一讲,但感觉还是讲得不清楚。顺带还看了一本经典的3D数学基础,才有那么一点点感觉,本书最大的好处在把纯粹的向量和矩阵的数学运算与形象的几何变换之间建立一种联系,阐述得很详细。但总觉得还差了那么一点。
偶然间遇到孟岩的《理解矩阵》系列文章。终于有点茅塞顿开的感觉。非常认同他关于数学直觉性建立的必要性。数学在逐步发展过程中不可避免越来越抽象化。但这对于普通人来说,一些抽象化的定义和运算,只是在应付考试时起到作用。没有建立直觉性认识,就无法运用数学去解决实际的问题。
比如搜索引擎技术中,我们经常利用特征值向量去量化两篇文档的相似度。其背后的数学意义就在于向量内积跟两个向量之间夹角的cos值关联在一起。当时学习的时候只是记住这样去做,但并不理解。还有经常提及的贝叶斯,这玩意儿好像能用到好多好多地方,但我一直无法从直观上去理解它,也就很难应用在实践中。
所以,直觉性对于数学的实践非常重要。《理解矩阵》系列文章就在阐述矩阵的直觉性认识。让我们想起矩阵不仅仅是想到一坨排在一起的数字和古怪的乘法运算法则。这种理解,对于3D程序员非常有意义。
一些3D模型格式介绍
常用3D模型的相关资源整理。
MS3D
- wiki
http://zh.wikipedia.org/wiki/MilkShape_3D - 说明
它主要用于低多边形游戏角色的建模和动作编辑。支持多种游戏中的模型文件,可以打开例如《半条命》、《Quake》、《反恐精英》等。比较简单和常用。 - 解析
http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=31
OBJ
-
说明
由Wavefront公司在其Advanced Visualizer动画包中定义的。是一个开放的格式,被很多3D软件所支持。它只是定义了一个无题的3D几何模型而已,包括:顶点位置,材质坐标,法线。不涉及骨骼动画的东西。 - 格式
http://www.martinreddy.net/gfx/3d/OBJ.spec - 资源: http://people.sc.fsu.edu/~jburkardt/data/obj/obj.html
3DS
- wik
http://en.wikipedia.org/wiki/.3ds - 时间
1990年。 -
说明
3dsmax的前身3dsutido的格式。当时业界的通用标准格式之一。能够稳定地保存模型mesh信息和uv信息,也兼容基础骨骼和基本动画。现在主要用来存储mesh模型。所有3D软件通用。 一种二进制存储格式。基于chunk -
解析
http://anony3721.blog.163.com/blog/static/5119742011525103920153/
http://www.gamedev.net/topic/313126-3ds-parsing-tutorial/http://www.spacesimulator.net/wiki/index.php?title=Tutorials:3ds_Loader
MD2
- wiki
http://en.wikipedia.org/wiki/MD2_(file_format)) -
说明
QuakeII引擎使用。主要用来支持动画模型,但也可以存储静态模型数据。通过加入关键帧来实现动画,关键帧存储在模型数据中,引擎复杂插值计算。 -
解析
http://wenku.baidu.com/view/6b42cb2bcfc789eb172dc841.htmlhttp://wenku.baidu.com/view/8a50c58183d049649b665840.html (非常详尽)
MD3
- wiki
http://en.wikipedia.org/wiki/MD3_(file_format) - 说明
QuakeIII引擎使用。MD2升级版本,不支持骨骼动画。仍然是关键帧动画的模式。在一个MD3模型动画系统中,通常有.md3,.skin,*.cfg以及一些图片格式文件组成,如(animation.cfg、head.md3、head_default.skin、lower.md3、lower_default.skin、upper.md3、upper_default.skin、band.tga、cigar.tga)。MD3文件为二进制格式文件,.skin,.cfg为文本文件。
FBX:
- wiki
http://en.wikipedia.org/wiki/FBX - 时间
1996年FilmBox1.5 -
说明
FBX是Autodesk的一个用于跨平台的免费三维数据交换的格式(最早是由Kaydara在FilmBox中开发,但后来被AutoDesk其收购),目前被众多的标准建模软件所支持,在游戏开发领域也常用来作为各种建模工具的标准导出格式。Autodesk提供了基于C++(还有Python)的SDK来实现对FBX格式的各种读写、修改以及转换等操作,之所以如此是因为FBX的格式不是公开的,这也是FBX的诟病之一。与FBX相对的则是格式开源的Collada,它的应用也很广泛 -
格式
非开源,无完成格式描述文档。可以用AutoDesk提供的SDK进行读写,也有一些三方的Library支持。 -
解析
http://blog.csdn.net/bugrunner/article/details/7210511http://openendedgroup.com/field/LoadingFBXFiles
Collada
- wiki
http://en.wikipedia.org/wiki/COLLADA - 说明
- 开放文档标准,基于XML。数字内容的中间交换格式,绝大多数3D软件和很多3D游戏引擎都支持。
- COLLAborative Design Activity 的缩写
- 一般的文件后缀: .dae(digital asset exchange)
- 最早由Sony创建的,现归Khronos Group(OpenGL之类也是这个组织的)
-
编程方式类似于COM
-
解析
http://www.cnblogs.com/Jedimaster/archive/2007/12/01/979256.html
http://opencollada.org/ -
资源
gamedev上面的讨论collada vs fbx: http://www.gamedev.net/topic/467753-collada-vs-autodesk-fbx/
对coolada,fbx的评价:http://stackoverflow.com/questions/441388/most-common-3d-model-format
二者均属于交换性质的格式,为了尽量支持更多的格式,在设计上不可避免地陷入复杂,因而导致效率底下。所以应用程序在实际的时候会转化为自有格式,以提高效率。