2021SC@SDUSC
动画片段
游戏角色的移动必须拆分成大量小粒度的动作。这些动作为动画片段。一般一个角色动作会拆成上千个片段,但是当角色进入游戏的非互动部分是例外。这部分称为非交互连续镜头(NIS)或全动视频(FMV)。
局部时间线
每个动画片段各自有一条局部时间线,使用自变量t表示时间线。t的每个值为时间索引。
片段中一些时间点上有一些重要的姿势,这些姿势称为关键姿势或关键帧,然后计算机会采用线性或基于曲线的插值计算中间的姿势。动画片段的时间是连续的,在计算机中时间变量是实数(浮点数)而非整数。这样可以有足够的分辨率度量时间,而且可以计算帧之间的结果或改变动画播放速率。而且它的比例是可变的。典型的帧持续时间是1/30s或1/60s。
动画片段中的一个时间点称为一个采样。采样的数目和帧数目的关系:
- 若片段非循环,N个帧的动画有N+1个采样;
- 若片段是循环,N个帧的动画有N个采样,最后一个采样是冗余的。
归一化时间有时称为动画的相位。归一化的时间单位u的范围始终是[0,1];当动画在循环时,u有如正弦波的相位。当要同步两个或以上的动画片段,而它们的持续时间有不同,归一化时间就很适合。
全局时间线
游戏中每个角色的全局时间线是从角色在游戏世界中诞生开始。播放一个动画可以看成动画的局部时间映射到角色的全局时间中。可以通过天正时间比例,把片段播放的更快或更慢。只需要把片段映射到全局时间线之前缩放它的比例即可。这称为播放速率R(片段缩小一半时,R = 2;R = -1时,片段倒转播放)。
动画片段映射到全局时间线和下面的相关:
- 全局起始时间τstart
- 播放速率R
- 持续时间T
- 循环次数N
局部时间t和全局时间τ的映射关系:t = R(τ - τstart) τ = τstart + t/R
- 若动画是非循环的(N = 1),应该吧t裁剪到合法的范围[0,T]中:t = clamp[R(τ - τstart)]|0T
- 若动画是无限循环(N = ∞),则 t = (R(τ - τstart))modT
- 若动画是有限循环(1 < N < ∞),则 t = (clamp[R(τ - τstart)]|0NT)modT
若要使用局部时间同步动画,必须保证在完全相同的游戏时间播放它们。实际上这是很困难的,因为动画播放命令可能来自多个不同的子系统,要保证它们的完全同步非常困难。
若使用全局时间同步动画,只需要片段的全局开始时间数值上相同,它们的播放就是完全同步的,若片段的播放速率相同,则会已知同步下去。
动画数据格式
一些关节姿势通常存储为SQT格式。动画的表示方法:
atruct JointPose{...};
struct AnimationSample
{
JointPose* m_aJointPose;
};
struct AnimationClip
{
Skeleton* m_pSkeleton;//由于每个动画片段是为特定的骨骼而设计的,这个可能是骨骼标识,而不是指针
F32 m_framesPerSecond;
U32 m_frameCount;
AnimationSample* m_aSamples;//采样数组
bool m_isLooping;
};
连续通道函数
动画的采样可看做随时间而改变的连续函数;对于采样间的值,许多游戏引擎采用线性插值,这实际上是对连续进行分段线性逼近。
许多游戏允许在动画中加入额外的“元通道”数据。常见的是在多个时间点上存储事件触发器,当动画的局部时间索引进过这些触发器,触发器的事件就会交到游戏引擎,游戏引擎处理这些事件。事件触发器常用于记录在动画的某个时间点播放音效(脚触地时播放脚步声),或粒子效果。另一种是名为定位器的特殊关节,它和骨骼关节一起设置动画。典型的可以吧摄像机和定位器绑定,这样就能得到位置和角度。