《游戏引擎架构》 笔记(二) 动画系统

每顶点动画技术:存储随时间改变的顶点位置和法线
变形目标动画: 移动网格顶点,仅制作相对少量的固定极端姿势,然后运行时混合姿势,线性差值(LERP),常用于面部动画。
蒙皮动画

游戏引擎会限制每个顶点能绑定的关节数目,典型的限制为每顶点4个关节。
原因如下:首先,4个8位关节索引能方便地包裹为一个32位字,此外,每顶点使用2个、3个及4个关节所产生的质量很容易区分,但大多数人并不能分辨出每个顶点4个关节以上的质量差别。

典型的蒙皮顶点数据结构

蒙皮网格的顶点会追随其绑定的关节而移动。
我们需要求一个矩阵,该矩阵把网格顶点从原来的位置(绑定姿势)变换至骨骼的当前姿势,我们称此矩阵为蒙皮矩阵。
该矩阵把绑定姿势的模型空间变换至当前姿势的模型空间。

蒙皮矩阵
K = 绑定姿势矩阵的逆矩阵 * 当前姿势矩阵

矩阵调色板(Matrix palette)
我们须计算一组蒙皮矩阵Kj,当中每个矩阵对应第j个关节。此数组称为矩阵调色板。
当要渲染一个蒙皮网格时,矩阵调色板便要传送至渲染引擎。渲染器会为每个顶点查找调色板中合适的关节蒙皮矩阵,并用该矩阵把顶点从绑定姿势变换至当前姿势。

假设角色的姿势随时间改变,其当前姿势矩阵便需要每帧更新。然而,绑定姿势逆矩阵在整个游戏中都是常量,因为骨骼的绑定姿势是模型创建时确定下来的。因此绑定姿势逆矩阵通常会缓存于骨骼,并不需要在运行时计算。

每个顶点最终会由模型空间变换至世界空间。因此有些引擎会把蒙皮矩阵调色板预先乘以物体的模型-世界变换。这是个很有用的优化。

动画混合(animation blending)
指能令一个以上的动画片段对角色最终姿势起作用的技术。
混合是把两个或更多的输入姿势结合,产生骨骼的输出姿势。

比如,通过混合负伤及无负伤的步行动画,我们可以生成二者之间不同负伤程度的步行动画。

动画混合可用于对面部表情、身体站姿、运动模式等的极端姿势之间插值。

动画混合也可以用于求出不同时间点的两个已知姿势之间的姿势。
通过在短时间段内把来源动画逐渐混合至目标动画,就能把某动画圆滑地过渡至另一动画。

四元数
线性插值 LERP
球面线性插值 SLERP
详见相关数学知识

为了在不同的动画片段之间平滑过渡:
1.位置连续 C0连续(continuity)
2.速度连续(位置的导数) C1连续,速度及动量的连续性
3.加速度连续(速度的导数)C2连续
若使用更高阶的连续性,角色的动作会显得更佳及更真实。
通常难以达到严格数学上的C1或以上的连续性。
通常使用线性插值(LERP)达到C0动作连续性就可以了。

两种常见的淡入淡出过渡方法
圆滑过渡(smooth transition)
冻结过渡(frozen transition)

β 线性差值中的混合因子
为达到圆滑的过渡,我们可以令β按时间的三次函数变化,例如用一维贝塞尔曲线。
当把这些曲线应用正在淡出的当前片段时,该曲线就称为缓出曲线(ease-out curve);当应用到正在淡入的新片段时,称为缓入曲线(ease-in curve)

无需混合就能产生连续动作的方法:
动画师确保其片段的最后姿势能匹配后续片段的首个姿势。
创作一段圆滑的动画,然后把它切为两个或两个以上的动画片段。

方向性运动
靶向移动 详见书482页,有助于理解unity中的混合树(Blend Tree)
轴转移动

技术清单:
Delaunay三角剖分(Delaunay triangulation)

骨骼分部混合
人可独立控制身体不同部位。例如,可以在步行时挥动右臂,并同时令左臂指着某物。在游戏中实现这种动作的方法之一是,使用名为骨骼分部混合(partial-skeleton blending)的技术。

混合遮罩(blend mask)
unity中也有相关概念,可结合理解。
可以把某些关节的混合百分比设为0,来掩盖那些关节。

现实中,在跑步中挥手时,挥手动作比站立时更“晃动”及不受控制,骨骼分部混合无法实现这样的真实性。另一种更自然的技术:加法混合。

加法混合(additive blending)
区别片段(difference clip)- 代表两段正常动画的区别。
考虑两个输入片段 来源片段(source clip S)、参考片段(reference clip R)
区别片段 D = S – R
若区别片段D加进原来的参考片段,我们就会得到来源片段。
只需要把某百分比的D加进R,我们也可以产生介于R和S之间的动画。就像线性插值。
加法混合技术之美在于:制作一个区别片段之后,可以把该片段加进其他不相关的片段,而不仅限于原来的参考片段。

加法混合相关的数学公式见书489页

动画后期处理(animation post-processing)

OGRE
Ogre::Entity
Ogre::AnimationStateSet
Ogre::AnimationState 对应一个动画片段

约束
注视(look-at):角色能注视环境中的兴趣点。角色可以仅用眼睛注视,又或者同时用眼和头,又或加入上半身的扭动。注视约束有时候是以IK或程序式关节偏移实现的,但更自然的观感可用加法混合实现。
掩护对准(cover registration):角色在掩护时要和掩护物完美对齐,这通常是用参考定位器技术来实现。

动画系统架构
动画管道 animation pipeline
动作状态机 action state machine, ASM
动画控制器 animation controller

《游戏引擎架构》 笔记(一)

游戏团队:工程师、艺术家、游戏设计师、制作人

平台游戏(platformer)
是指基于人物角色的第三人称游戏。
主要的游戏机制是在平台之间跳跃。

第三人称游戏
比较看重主角的能力及运动模式。
需要逼真的全身动画。
复杂的摄像机碰撞系统,以保证视点不会穿过背景几何物体或动态的前景物体。

格斗游戏
丰富的格斗动画
准确的攻击判定
能侦测复杂按钮及摇杆组合的玩家输入系统

竞速游戏
使用许多窍门渲染遥远背景,比如二维纸板形式的树木、山脉
赛道通常切开成较简单的二维区域,称为分区(sector)。用于实现渲染优化、可见性判断。

实时策略游戏(Real-time strategy, RTS)
通常不允许玩家改变视角以观看不同距离的景物,这个限制使开发者能在RTS引擎上采用各种优化。
译注:等角投影 屏幕上3个轴的夹角均为或接近120度。
较低解析度的模型以支持大量单元。

CryEngine
CryTek公司把部分研究成果公开:
http://www.crytek.com/cryengine/presentations

开源引擎:
OGRE
Panda3D 基于脚本的引擎、
Yake 基于OGRE开发的全功能引擎
Crystal Space
Torque
Irrlicht

Boost的在线文档是一个学习计算机科学的好地方。
Loki 是强大的泛型编程模板库。它尤其擅长绞尽你的脑汁。
《C++设计新思维》

有关STL标准在游戏应用的问题及解决方案
EASTL 29页

libgcm是索尼提供给PlayStation3的低阶直接接口,比OpenGL更高效。
Edge 顽皮狗和索尼为PlayStation3制作的强大高效渲染及动画引擎。

物理引擎
Havok
PhysX
Open Dynamics Engine ODE

角色动画工具
Granny
Havok Animation
Edge

人工智能工具
Kynapse

内存管理 内存碎片问题

渲染系统 分层从低到高
1. 低阶渲染器 只负责渲染
图形设备接口 使用DirectX或OpenGL
2. 场景图/剔除优化
3. 视觉效果
粒子系统
贴花系统 decal system 弹孔、脚印等
光照贴图、环境贴图
动态阴影
全屏后期处理效果
HDR光照、敷霜效果bloom
全屏抗锯齿FSAA
4. 前端 UI等

剖析和调试工具
intel VTune
IBM Quantity, Purify
Compuware Bounds Checker

时至今日,很少有公司编写自己的碰撞及物理引擎。取而代之,通常使用第三方的物理SDK。

刚体动力学
软体动力学
流体动力学

动画
精灵/纹理动画
刚体层次结构动画
骨骼动画
顶点动画
变形目标动画

微软音频工具包 XACT

多人游戏
单屏多人
切割屏多人
网络多人

A*寻路算法

粒子系统工具 Houdini

剖析器(Profiler)
统计式剖析器 – 计算出某函数占整体执行时间的近似百分比,
不影响游戏运行
Intel VTune

测控式剖析器 – 为每个函数安插特殊的初构代码
程序会变得很慢
IBM Rational Quantify (Rational Purify Plus工具套装之一)

混合式剖析器
微软 LOP (Low Overhead Profiler)

检测内存泄露
IBM Rational Purify
Compuware Bounds Checker

合成和聚合
has-a 合成
uses-a 聚合

编码规范
接口为王 保持接口整洁、简单、有良好注释
良好的命名
Effective C++ , Effective STL , Large-Scale C++ Software Design

推荐阅读
http://www.joelonsoftware.com/articles/Wrong.html

Ogre的基本数据类型
uint8 uint16 uint32
Real OGRE_DOUBLE_PRECISION 1 double 0 float
uchar ushort uint ulong
Radian Degree Angle

多字节值及字节序
小端 Intel
大端 Wii Xbox360 PlayStation3
字节序的解决方案:
1. 所有数据以文本方式写入文件
2. 转换字节序,就像网络通信一样

SQLite

SQLite简介

SQLite是一款开源的、嵌入式关系型数据库。

简单地说,SQLite源代码只有三个文件,添加到项目中(此为嵌入式),通过调用SQLite提供的接口函数即可获得使用SQL语句读写数据库的能力,只是该数据库是内存数据库或本地文件数据库。

www.sqlite.org

使用方法

推荐教程

《SQLite权威教程》 Grant Allen

TinyXML

TinyXML是一个优秀的C++ XML解析器。
TinyXML http://sourceforge.net/projects/tinyxml

使用方法

生成一个简单的xml文件

打开文件遍历元素

example4.xml

上面一段代码中,注释部分演示了另外一种遍历方法。

使用TiXmlHandle

通过上面的代码我们看到,获得一个元素后需要判断是否为空指针。
使用TiXmlHandle可以简化编程,使用链式调用的简便语法,效果如下:

总结

TinyXML的使用方法还是相当简单的。源代码只有6个文件,看一下头文件,各种接口一目了然。

gettext

本文来自维基百科:https://en.wikipedia.org/wiki/Gettext

gettext是一种国际化与本地化系统,在类Unix系统中编写多语言程序时经常被使用。gettext的一个常用的实现版本为GNU gettext,1995年发布。

使用方法

编程

源代码中所有需要多语言支持的(需要翻译的)字符串都修改为使用gettext函数包装起来。为了方便也可以使用下划线 _。比如:

gettext函数会使用提供的字符串作为键值去查找当前设置语言对应的翻译版本,如果没有找到则返回原始的字符串。那么怎么制作各种语言的翻译版本呢?

xgettext程序基于源代码文件,会识别出所有使用gettext或 _ 标记的字符串,然后生成 .pot 文件(Portable Object Template)。比如:
源代码中:

(以///开头的注释会有特殊的作用,之后我们会看到)
生成的 .pot 模板文件:

仔细观察生成的 .pot 文件我们会发现其中包含了注释、源文件名和字符串所在行数、源字符串和对应的翻译版本(当然现在是空的)。接下来就是翻译工作。

翻译

使用msginit程序可以由 .pot 模板文件生成一个 .po 文件(Portable Object)。接下来我们将修改 .po 文件,将翻译的文本填进去。
比如一个中文的翻译版本,我们可以运行以下命令:

我们将得到一个 zh_CN.po 文件,编辑 .po 文件可以使用任何文本处理程序手动修改,或者使用 Poedit、Emacs。编辑后的效果如下:

最后,使用msgfmt程序将 .po 文件编译为二进制的 .mo 文件(Machine Object)。GNU gettext 使用 .gmo 扩展名。接下来就可以使用到我们的程序中了。

使用

Unix中,设置环境变量 LC_MESSAGES。Linux中设置环境变量LANGUAGE,如果存在对应的 .mo 文件,程序将使用对应的语言版本。

GNU gettext  https://www.gnu.org/software/gettext/gettext.html

GetText for Windows  http://gnuwin32.sourceforge.net/packages/gettext.htm

wxWidgets

wxWidgets中通过wxLocale实现了gettext。