章3-角色(二、三维角色人体模型,场景建模)讲解
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第三章角色
3.1 前言
“角色”一词的源于戏剧,自1934年米德(G.H.Mead)首先运用角色的概念来说明个体在社会舞台上的身份及其行以后,角色的概念被广泛应用于社会学与心理学的研究中。
社会学对角色的定义是“与社会地位相一致的社会限度的特征和期望的集合体”。
角色是一个抽象的概念,不是具体的个人,它本质上反映一种社会关系,具体的个人是一定角色的扮演者。
而在我们动漫产业中,角色更是一个非常重要的元素,没有一个吸引人的角色,就出不了一个好的作品。
我们本章来介绍角色的建模。
3.2 骨骼动画原理
骨骼动画(Skeletal Animation)[9]又叫Bone Animation,它与关键帧动画(Key-frame Animation)相比,占用空间小,因为它不需要像关键帧动画那样在每一帧中存储各个顶点的数据,而只需要存储骨骼变换数据,骨骼与顶点相比,当然要少得多。
所以骨骼动画有很多优势,当然其技术难度也很高。
骨骼动画在计算机图形学中是一个十分重要的内容,不管是在游戏、电影动画还是虚拟现实中,生动逼真的角色动画(人、动物等)会使其增色不少。
骨骼动画的实现思路是从人的身体的运动方式而来的。
动画模型的身体是一个网格(Mesh)模型,网格的内部是一个骨架结构。
当人物
的骨架运动时,身体就会跟着骨架一起运动。
骨架是由一定数目的骨骼组成的层次结构,每一个骨骼的排列和连接关系对整个骨架的运动有很重要的影响。
每一个骨骼数据都包含其自身的动画数据。
和每个骨架相关联的是一个“蒙皮”(Skin)模型,它提供动画绘制所需要的几何模型信息(Vertex信息,Normal信息等)和纹理材质信息。
每个顶点都有相应的一组权值(Weight),这些权值定义了骨骼的运动对有关顶点的影响因子。
当把动画人物的姿势和全局运动信息作用到骨架上时,这个“蒙皮”模型就会跟随骨架一起运动。
3.2.1实时角色动画
由于骨骼动画是从另外两种实时角色动画发展演变而来,因此,为了更好的理解骨骼动画的原理,就很有必要对它们进行研究分析。
角色动画是计算机动画技术的一个重要组成部分,也是计算机图形学的一个重要分支。
在实时渲染环境下,主要应用于虚拟现实,视频游戏,甚至是建模软件,动画制作软件。
现在,随着计算机硬件技术的发展,特别是带有硬件加速功能的显卡性能的提高,实时渲染的角色动画技术得到了较快的发展且被广泛的应用。
目前,实时角色动画技术大体可分为三种类型。
图2-1关节动画组织结构图
第一类是关节动画(Joint Animation)。
关节动画中的角色模型由若干相互独立的部分组成(如图2-1)。
每一部分对应一个独立的网格模型,相应的对应于某一个身体关节,不同的部分按照角色的身体特征组织成一个层次结构。
比如说,一个人体模型可以由头,身体,右上臂,右小臂,右手,左上臂,左小臂,左手,右大腿,右小腿,右脚,左大腿,左小腿,左脚等各部分组成。
而某个部分,可能是另一个部分的子节点,同时又是另一个部分的父节点。
通过改变不同关节之间的相对位移和夹角等,就可以实现所需要的各种动画效果。
这类动画的优点是:
在动画的每个关键帧中只需存储关节之间的相对变化,因此动画文件需要的存储空间很小。
关节动画的缺点是:在关节之间的连接处往往会有很明显的接缝,这会对模型的真实感造成严重影响。
目前关节动画的应用范围主要在辅助教学领域。
第二类是关键帧动画(Key-frame Animation)也叫顶点动画(Vertex Animation)。
关键帧动画中的角色模型由一系列的渐变网格构成。
在动画序列的每一关键帧中记录着每个顶点的当前位置信息。
通过在相邻关键帧之间插值来更新网格模型中顶点的位置就可以实现动画效果。
相对于关节动画,关键帧动画不存在关节动画的接缝问题,角色也更逼真。
由于顶点的位置是直接获得的,相对于关节动画其计算量也很小。
但是,这类动画的灵活性很差,很难来使角色实时的与环境进行交互。
另一方面,由于关键帧中要存储所有顶点的信息,动画文件的存储空间很大。
目前,关键帧动画的主要应用对象是一些顶点数目有限的角色模型,并且需要的动画简单单一,比如游戏中的小动物等,此时用不大的空间开销来换取计算时间的节省,是比较有效的方法。
第三类是骨骼动画(SkeletalAnimation)。
骨骼动画可以看作是关节动画和关键帧动画的结合。
他同时兼有关节动画的灵活和关键帧动画的逼真。
后面将详细介绍骨骼蒙皮动画的技术细节。
3.2.2 骨骼动画简介
骨骼动画(SkeletalAnimation,又叫BoneAnimation)可以看作是关节动画和关键帧动画的结合。
骨骼动画兼具了两类动画的优点又克服了它们的缺点。
骨骼动画的实现思路是从人身体的运动方式而来的,它基于面模型的方法把角色建模为两层:骨架层(Skeleton layer)和皮肤层(Skin layer),与基于层次式模型方法不同,骨骼动画建
模不考虑中间的脂肪层(Fat layer)和肌肉层(Muslce layer)。
骨骼层描述了角色的骨架结构(如图2-2左),类似于关节动画中的关节,骨骼动画中的骨骼按照角色的身体特征组成一个层次结构。
相邻的骨骼通过关节相连,并且可以做相对的运动。
通过改变相邻骨骼间的夹角,位移,组成角色的骨骼就可以通过影响外面的皮肤层模拟出不同的动作,从而实现各种动画效果。
图2-2骨骼动画的骨骼结构图(左)和角色模型图(右)
蒙在骨骼之上的皮肤层,它是一个蒙皮(skin)模型(如图2-2右),它提供动画绘制所需要的几何模型信息,定义了角色的外观。
这里的皮肤不是固定不变的刚性网格,而是可以在骨骼影响下可变形的网格。
类似于关键帧中的顶点网格,每个角色模型只需要保存一个网格模型的数据;不同于关键帧动画,在动画文件中不需要在每个关键帧中保存顶点信息。
3.2.3 骨骼动画创建
骨骼动画的创建过程其实就是预处理的过程,这一过程是由美术创作者完成的,必要的时候可能会分别由3D建模工程师和3D动画工程师分别完成模型造型和动画制作工作。
但也需要跟程序开发者有良好的沟通,比如模型的骨架层次定义、模型子网格划分等等。
下面就对模型造型和动画制作分别予以讨论。
因为本文的目的是研究骨骼动画技术,因此,本文完全没有涉及动画领域的艺术性问题。
讨论美术创作者的工作也是为了便于讨论骨骼动画所涉及到的原始数据构成,以方便对骨骼动画有完整的理解。
角色模型的创建:角色静态模型一般是指骨骼动画中用来被骨骼动画参考的静态模型,它是一个单一网格模型。
所有的动画将基于该静态模型创建,即动画数据中的平移旋转信息均是相对于该静态模型的。
对于该网格的创建,有一些要求,比如在关节处的顶点数目应该多一些(如图2-2右)。
角色骨骼层次也要对应的创建起来,并且骨骼的大小和位置关系应该与皮肤网格相适应。
另外最重要的一点,还要指定网格上的顶点到骨骼的映射关系以及相应的影响权值。
每块骨骼都一个影响范围,在这个范围内的顶点都要受到该骨骼的影响。
每个顶点至少要受到一块骨骼的影响,但在关节处的顶点往往可能会受到多块骨骼的影响,这些骨骼通过对应的权值来叠加作用到该顶点。
因此在指定权值时,一般需要有经验的动画师来实现。
动画的创建:即通过操作骨架结构的变换来构建角色动画。
设置每块骨骼的运动信息,使其带动网格模型上各个顶点运动,从而形成
动画。
可见,动画的创建过程就是对骨骼变换的过程。
上述两种数据的创建都可以通过专业的3D动画编辑软件如3DMAX、Maya等实现,但合适逼真的角色动画工作需要建模师和动画师有相当多的经验。
3.2.3 骨骼动画数据信息
在美术师们完成了原始数据的创建之后,一般这些数据还是以3D动画编辑软件内部的数据结构进行存储,比如3DMAX采用的.max 文件结构。
要使得这些数据被应用程序使用,还需要程序开发者将它们转化为适合于程序使用的数据结构。
这就需要编写导出插件,用于将原始数据转化为需要的形式。
例如Panda XExporter就是一个广为人知的导出插件,它可以将.max文件转换为.x文件所要求的数据格式。
一般来说,每个游戏厂商都会有自己的骨骼动画引擎,相应的就需要有对应的插件来实现数据结构的转换。
由于这些涉及到3D动画编辑软件内部的数据存储管理,对本文讨论的主题没有太多的意义,因此本文不会涉及这些插件技术的内部细节。
为了便于后面的讨论,下面将会对转换后的骨骼动画信息进行归纳总结。
对应于原始数据,在通过插件导出之后,一般通过两种不同的文件结构分别保存角色模型数据和角色动画数据,下面分别对它们进入分析。
一、角色模型数据
由于骨骼动画的需要,在静态角色模型中,不仅仅要包含角色网
格模型信息,而且还要包含用于骨骼动画的相关信息。
这些信息包括:角色网格数据:包括所有皮肤顶点信息,每个蒙皮顶点中包含的信息至少包括:与该顶点相关联的骨骼索引组,以及每个骨骼的影响权重值组,顶点初始位置信息(注:还有可能包含其他的信息比如纹理坐标信息,顶点颜色信息,顶点法线信息等等,但本文在此只关注骨骼顶点相关的信息)。
由于是单一网格模型,对每个顶点来说,对应的信息只需保存一次。
模型索引数据:索引数据主要是用来保存顶点之间的连接关系,每三个顶点构成一个三角形面,而三角形面即是用于渲染的基本图元,索引数据每三个为一组记录的这种三角面关系。
骨骼层次信息:每个角色都有一个骨架层次结构,一般是树形结构。
对所有的骨骼要有一个统一的编号,每块骨骼都要记录其父骨骼。
二、角色动画数据
从动画师的角度看,动画就是可视化的骨骼变换操作。
从程序开发者的角度来看,每个动画文件中要保存的信息如下:
1、每块骨骼的关键帧编号。
对于一块骨骼而言,它的变换信息是通过关键帧的形式保存的,比如需要在第一、三、七、十帧中记录一块骨骼的变换信息,那么第一、三、七、十帧就是需要保存的关键帧。
2、每个关键帧的变换信息。
对于一块特定骨骼的特定关键帧来说,需要记录其变换信息,一般是通过矩阵记录的。
3.2.3 骨骼动画的载入
1.先来看看静态模型的载入。
由上文的论述可知,静态模型的载入过程实际上是对网格数据、索引数据以
及骨架层次三类信息的载入过程。
如何对这三个信息予以管理以便于骨骼动画的实现是骨骼动画实现的基础,因为骨骼动画的驱动过程就是依靠这些结构来实现的,下面将对它们分别予以分析。
1、网格数据的载入和管理
对于单个顶点来说,可能需要保持的信息是相当多的,比如纹理坐标信息,颜色信息,顶点信息等等,这用于渲染的顶点信息是对称的,即每个顶点所需要的存储空间是一样的。
此外,为了实现骨骼动画算法,顶点需要保持与骨骼动画相关的信息,如与该顶点相关联的骨骼索引组,以及每个骨骼的影响权值组等等。
值得一提的是,并不是所有皮肤顶点所关联的骨骼数目都是统一的,比如在关节处的顶点所关联的骨骼数肯定要多于非关节处顶点所关联的骨骼数目。
因此可以通过两个不同的顶点结构来保存两者。
这样做的好处在于,用于渲染的顶点结构,它直接记录了渲染所需要的信息;而用于骨骼动画计算的顶点信息,它包含了骨骼动画实时运算所需要的顶点数据。
2、索引数据的载入和管理
索引数据主要是用来保存顶点之间的连接关系,每三个顶点构成
一个三角形面,而三角形面既是用于渲染的基本图元,索引数据每三个为一组记录了这种三角面关系。
3、骨骼层次信息的载入管理
为了实现骨骼动画,每个角色都有一个骨架层次结构,一般是树形结构。
如图2-3所示是角色模型的骨架层次结构,按照不同的细节要求可以对骨架进行更细微的分解。
其中向下箭头表示父子关系,向右箭头表示兄弟关系。
图2-3人体骨骼组织结构图
对所有的骨骼要有一个统一的编号。
在载入过程中,只需记录每块骨骼的父骨骼信息和子骨骼信息,这实际上是一个双向链式树形结构。
这样,当在应用程序实时运行的时候,一旦需要获得父骨骼的平移旋转信息,凭借父骨骼编号,就可以迅速的找到对应的父骨骼节点。
可以定义下面的数据结构予以保存
骨骼数据结构
{
骨骼编号;
父骨骼;
局部变换矩阵;
全局变换矩阵;
};
在后面的章节中将会看到,骨骼动画驱动的过程中,将通过动画数据更新该结构中的局部变换矩阵,借以更新全局变换矩阵,最终,通过该结构中的数据来更新皮肤顶点信息,实现动画效果。
2.再来看看动画数据的载入。
基于上节中讨论过的动画信息可知,要对以下几类信息进行管理。
针对动画所涉及到的每块骨骼,要保存其关键帧数据。
每个关键帧数据的内容包括:该帧的编号,该帧中该骨骼相对于父骨骼的平移信息以及旋转信息。
由于此类信息上文中已经做出总结,这里就不再多加讨论。
动画数据可能有很多,比如在一个典型的高尔夫游戏中,其中一个角色,可能需要他的各种动画,比如走动、击球、推杆、捡球、庆祝动作等等。
对于个人角色扮演类的游戏应用,可能需要的动作更多,如果每个动画对应于一个文件,那么就可能需要很多个文件来保存动画数据。
对于这些数据,选择适当的时机对其进行载入是一个比较重要的问题,因为,一款游戏可能有许多不同的角色,如果是在应用程序启动的时候一次装载所有的数据,那么会造成比较慢的启动速度,最重要的,他们将会占用大量的内存,导致内存开销过大。
有些角色
可能从前到后就没有使用过,就造成了内存资源的浪费。
因此,要在合适的时间内对数据进行载入。
比如在游戏应用中,一般会有人物选择界面,可以根据用户的选择来动态的载入角色的全部动画或者部分动画。
3.2.3 骨骼动画的驱动
在应用程序播放某一具体的动画的过程中,骨骼动画引擎需要动态的根据指定的动画按照播放速度的要求正常驱动动画效果的产生,骨骼动画的驱动过程就是骨骼动画实时计算的过程。
在交互式应用中,一般是在用户输入某些控制命令后,角色模型开始完成相应动画。
这就要求应用程序在接受到命令后,需要动态实时的完成这些工作。
当确定了需要的动画之后,对于某一个具体的动画而言,在某一具体的时刻,其驱动步骤可以分为:
1、对骨骼局部变换信息进行更新。
确定该动画在该该时刻的两个插值关键帧,即找到该时刻之前之后的两个关键帧。
然后按照时间对这两个关键帧进行插值(应用中使用最多的是对其进行线性插值),从而确定每一块骨骼该时刻在父骨骼坐标系下的变换信息(平移和旋转信息)。
2、对骨骼全局变换信息进行更新。
对骨架层次结构进行遍历,从根骨骼开始,计算每一块骨骼相对于身体坐标的全局变换信息(一般是用矩阵形式来表示),这一步骤是基于上一步骤完成的,由于第一步中已经得出了每一块骨骼的相对变换信息,本步骤中只需从根进
行递归遍历即可。
3、对网格顶点进行更新。
对于皮肤网格中的所有顶点,计算其在身体坐标系下的位置和法线信息。
根据每个顶点所关联的骨骼以及对应的权值,就可以利用每块骨骼的全局变换信息来对顶点进行变换。
再来看看驱动的过程。
每根骨骼存在两个相关的变换矩阵:局部变换矩阵和全局变换矩阵。
局部变换矩阵记录了该骨骼在父骨骼坐标系空间中的位置和朝向。
全局变换矩阵用来决定该骨骼在整个角色空间中的位置和朝向。
在骨骼动画动画文件中存储的是骨骼的局部变换矩阵序列,骨骼的全局变换矩阵则需要通过另外的计算来获得。
由于骨骼的运动实现是通过层次结构互相影响的,所以全局变换矩阵不能一步就能获得。
图2-4父子骨骼变换关系
下面举例说明一下全局变换矩阵的获得,如图2-4。
首先看旋转
变换,在图中有两块骨骼,左边的父骨骼和右边的子骨骼。
要获得两个骨骼的全局变换矩阵来用于皮肤顶点的更新。
子骨骼的局部变换矩阵保存的是它相对于父骨骼旋转信息。
但其父骨骼也有自己的变换信息,也做了一些旋转,因此,要获得子骨骼对于整个角色的全局变换矩阵,就需要将其局部变换矩阵与父骨骼的变换矩阵相乘。
如果矩阵中加入了平移变换,同样的过程也要被执行。
从例子中可以了解到父骨骼的局部变换矩阵不仅会影响到其自身,而且还会影响到它的子骨骼。
根骨骼的全局变换矩阵等于其自身的局部变换矩阵。
这样旋转、平移变换在骨架层次结构中依次被继承下来。
一、骨骼局部变换更新
首先是查找关键帧,对于特定动画的某一骨骼而言,需要在该骨骼的所有关键帧序列中找到最合适的一个关键帧或者两个关键帧。
其次是对关键帧插值。
如果合适关键帧为两个,就需要对其进行插值。
插值的算法有很多,在这里采用(平移,旋转)对分别插值进行处理。
对平移信息的插值采用简单的线性插值即可。
对旋转信息而言,通过四元数[19]的球面线性插值(Slerp Linear interpolation)来实现,球面线性插值可以实现对旋转信息的线性插值。
设p,q是需要插值的两个四元数,t为0到1之间的参数值。
则球面插值(Slerp Linear interpolation)的公式为:
psin((1−t)θ)+qsin(tθ)
Slerp(p,q,t)=
插值工作完成之后,利用插值好的平移和旋转信息计算获得对应
变换矩阵,保存在该骨骼数据结构的局部变换矩阵中。
至此,对骨骼的局部变换更新已经完成。
二、骨骼全局变换更新
骨骼的全局变换依赖于局部变换,对于每一块骨骼来说,他的全局变换矩阵就等于父骨骼的全局变换矩阵乘以本骨骼的局部变换矩阵。
因此,要计算骨骼的全局变换矩阵就要先计算其父骨骼的全局变换矩阵。
可以通过对骨架层次的深度遍历计算得出所有骨骼的当前全局变换矩阵。
下面给出一种通过递归遍历实现算法。
计算全局变换矩阵函数(骨骼数据结构)
{
如果骨骼没有父骨骼:
全局变换矩阵=本骨骼的局部变换矩阵;
否则
{
如果父骨骼全局变换矩阵没有计算:
计算全局变换矩阵函数(父骨骼);
全局变换矩阵=本骨骼的局部变换矩阵*父骨骼全局变换矩阵;
}
}
从前面的论述可知,当局部变换矩阵更新完成之后,调用此函数对每个骨骼进行全局矩阵变换矩阵更新即可。
三、皮肤顶点更新
这里本文采用传统的“蒙皮”算法,该算法的缺陷以及改进将在后面的章节进行研究。
这个过程对每个顶点而言,需要根据它所关联骨骼的全局变换矩阵基于骨骼影响权值对顶点进行变换.
“蒙皮”算法的本质是一种插值算法,它的基本思想是使关节处的皮肤顶点受到与关节邻近的几块关联骨骼的影响,影响的大小由权值确定。
其基本公式为:
v =∑ωi ∁i v i n i=1 其中 ∑ωi n i=1=1
其中,v i 是顶点在第i 个关联骨骼子空间的局部坐标,∁i 是第i 个关联骨骼的全局变换矩阵,ωi 是第i 个关联骨骼的权值,它们的和为1。
至此,骨骼动画顶点信息已更新完毕,可以对更新后的网格数据进行渲染。
需要说明的一点是,本文之前的讨论并没有涉及到角色的材质以及纹理信息。
骨骼蒙皮动画结合细腻的纹理甚至光照计算,会使角色更为生动逼真。
3.3 场景建模管理
如何很好地表示出包含着成千上万物体的复杂场景,是设计系统必须要考虑的。
这也是场景管理需要做得,给场景提供良好的层次关系,以便更好地进行筛选和隐藏面消除。
场景管理涉及到可视性处理和碰撞检测,系统需要判断场景的哪些部分在视见约束体之内,另外如果两个物体有碰撞关系,则需要计算碰撞点的值。
为了达到好的实时效果,传统的技术不可能适用,因为场景己经非常复杂,如果只采用Z缓冲的方法进行可见性处理是不现实的。
目前己经有了将场景分层的方法,可以把辅助数据结构应用于场景中,先把场景分区,再分物体,甚至一直分割到多边形。
如在室内场景管理中有两个经常用到的层次体系:BSP(Binary Space Partitioning)树,这是八叉树的推广,和包围体树(Boundingvolume tree)。
前者用于加速剔除,而后者主要用于碰撞检测。
本节简单讨论如何使用层次体系进行更加高效的筛选以及可以
采用什么样的数据结构来组织场景。
3.3.1 场景的组织和管理
场景的组织结构是渲染系统最基础和最重要的部分,也是一个实现的难点。
它的决定会决定很多后续的工作,如碰撞检测,消隐,阴影等。
首先要涉及到的概念是空间细分,空间细分考虑整个物体空间并且根据物体的空间占有(Object occupancy)对空间中的每一个点进
行分类。
可以把世界空间中的物体细分为立方体素(voxel),再对体素进行分类。
八叉树(octree)是一种描述三维空间的树状数据结构,它可以描述一个三维场景内物体的分布情况,并简单地将体素安排在层次结构中。
因此场景管理可以在预处理的时候建立一棵树,这里可以忽略物体的表示方法,而把焦点集中在场景的划分上。
在树建立起来之后,。