游戏动画的挑战
交互式动态动画,因人而异。与其他游戏系统合作。在复杂环境中进行调整。
每秒的动画都是实时的,动画越细腻,数据越多。
真实感
2D动画技术
Sprite Animation
一开始是通过播放一张一张的图片来实现游戏角色的动作,然后发展出了通过一张一张不同角度的图片来表现一个3d效果的伪3D动画技术,这项技术Sprite Animation在现在的游戏中也经常使用。
Live 2D
首先把角色的各个部位设计成图元,然后给各个图元加上深度来确定这个部分是否显示,每个图片元素设计一个控制网格来控制各个部分的形态。
3D动画技术
DoF(Degrees of Freedom) 自由度
指系统的自变量或参数,6个自由度是指3个方向平移,3个方向旋转。
Rigid Hierarchical Animation 刚性层次动画
把角色的关节设计成树状的可动的部分。
Per-vertex Animation 顶点动画
3D Skinned Animation 三维皮肤动画
核心思想:皮肤由多个骨骼同时作用,可以保证对象在运动的时候不会穿插,保证了它的水密性。
在2D中野有相似的技术,2D Skinned Animation 技术。
Physics-based Animation 物理动画
比较重要的一个动画技术。
若何创造动画
一个是手动一个一个动作去设计的动画,另外一个就是动捕。
Skinned Animation Implementation 蒙皮动画实现
Create mesh for a binding pose 为绑定位姿创建网格
Create a binding skeleton for the mesh 为网格创建绑定框架(骨骼)
“Paint" per-vertices skinning weights to related skeleton油漆”每一个顶点剥皮重量到相关骨骼-Animate skeleton to desired pose “动物骨骼到想要的姿势
Animate skinned vertices by skeleton and skinning weights 用骨架和蒙皮权来绘制皮肤顶点
3个坐标系
世界坐标系,模型坐标系,局部坐标系。模型坐标系到世界坐标系是通过6个自由度的变化的。
场景中的每个物体都有自己的局部坐标系,比如我们在建立一个立方体时,往往会把局部坐标系的原点放在立方体的体心或一个顶点上。用于构建物体内部间的位置关系。
骨架
一般是通过胯骨来作为起点。
bone是由2个joint定义的,joint有很多自由度而bone没有。在游戏引擎中一般说存放骨骼,其实就是存放joint。
Bind Animation for Objects 绑定对象动画
在2个物体上分别设置一个绑定骨骼,绑定后,2个物体就类似一个物体了,在一个物体执行动作时,另外一个物体也会执行相应的动作。
pose
在joint pose中有9个自由度,出了3平移3旋转还有3放缩。
Math of 3D Rotation 三维旋转数学
欧拉角必须要按xyz的顺序。
四元数
Joint Pose
在大部分的动作中,Joint一般都是通过旋转完成。但是也有通过空间位置改变的动作,例如人蹲下。
为什么要把模型坐标系转为局部坐标系,是因为模型坐标系在2点之间是直线,而世界坐标系是一个符合物理正常规律的曲线。如图2
Affine Matrix
有了三维旋转的表达方法后我们就可以利用关节的姿态来控制角色模型的运动。具体来说,我们每个关节的姿态可以分为平移、旋转和缩放三个部分,把它们组合到一起就可以通过一个仿射矩阵(affine matrix)来描述关节的姿态。平移比如 root 骨骼固定在地面位置嘛,然后与胯部之间的位置会实时变缩放比如面部骨骼,对于骨骼上的每一个关节,我们实际上只需要存储它相对于父节点的相对姿态。这样在计算绝对姿态时可以利用仿射矩阵的传递性从根节点出发进行累乘即可。这种利用相对坐标系来描述位姿关系的好处在于它可以正确地对角色动作进行插值,而如果直接从绝对坐标系进行插值则会得到错误的结果。
Skinning Matrix
在前面我们介绍过模型的每个顶点是附着在骨骼上的,因此在关节姿态发生变化后顶点会跟着关节一起运动。
Skinning Matrix 包含两个矩阵, 第一个对应的是当前时刻的 pose; 第二个对应的是 bind pose, 是固定不变的, 所以可以预先计算好存下来
Skinning Matrix Palette
角色身上的顶点数会有几万个,但是骨骼数就几十个,所以蒙皮矩阵要被调用很多次,所以要先算好先把所有骨骼的位置算好,然后再把所有骨骼的蒙皮矩阵算好。所有骨骼的蒙皮矩阵还要乘上一个模型坐标系到世界坐标系的仿射矩阵
Weighted Skinning with Multi-joints
对于同一个顶点绑定到多个骨骼的情况则需要通过插值进行处理。此时顶点V VV会同时存储它所绑定到的关节以及对应的权重,其在世界坐标系下的坐标为它在每个关节上定义的局部坐标转换到世界坐标后的加权和。插值是在模型空间中插值
Clip
在120帧的动画中,不可能插入120张图片,这时就需要使用插值法“模拟产生”一些新的但又比较靠谱的数据来满足需求,这就是插值的作用。
Interpolation between Poses
Simple Interpolation of Translation and Scale
线性插值是最基本的插值方法,我们可以通过对关节姿态的插值来计算中间帧上的模型运动。
Quaternion Interpolation of Rotation
对于三维旋转的插值要相对复杂一些,不过我们可以借助四元数的运算来进行处理。要获得插值后的旋转只需要对四元数直接进行线性插值,然后再进行归一化即可,这样的方法称为 NLERP。
一般的插值是沿着最短路的,这里做一个运算,如果是大于 0 就直接插值,如果是小于 0,那么反向插值,来避免一直找最短路
3种插值方法介绍:https://blog.youkuaiyun.com/littlefrogyq/article/details/127272335
NLERP 并不是真的对旋转进行线性插值。当动画的帧数较高时 NLERP 会有明显的违和感,这是由于它没有考虑旋转并不是线性空间。
想要真的对旋转进行线性插值可以使用SLERP这样的算法,不过SLERP的计算代价要比NLERP要大一些。
因为这里用到了反三角函数,反三角函数会比较费,因为它的计算需要查表
又因为 θ \thetaθ 很小的时候,θ ∼ sin θ \theta \sim \sin\thetaθ∼sinθ,它作为分母可能不稳定
所以一般旋转角 θ \thetaθ 比较大的时候使用 SLERP,旋转角比较小的时候使用 NLERP
Animation Clip Storage 动画剪辑存储
动画压缩的方法
Catmull-Rom 曲线
在p1和p2外延伸了p0和p3,可以用该曲线一点一点去逼近真实的曲线。这个计算是离散的。
Float Quantization
把一个范围的数据映射到0到1之间,然后就可以通过这个0到1的数据映射更高精度的数据中,如下图。
四元数压缩
把四元数归一化可以发现去除最大的数其余的数不会超过根号2分之一,然后通过2个bit存储最大的数,在通过15bit存其余较小的数就可以通过归一化的反向算法求出原来的四元数。
通常使用该方法6字节就可以完成,而使用浮点数则是32个字节
动画压缩可能造成的错误
很难计算出每个顶点的视觉误差。计算量大
估计视觉误差
假顶点:与关节固定距离处的两个正交虚拟顶点(不与关节旋转轴共线)。
伪顶点距离逼近
特征骨2~10厘米
.大型动画物体1~10米
误差补偿:在上方的骨骼出现误差的时候,这个骨骼就会补偿,但容易会在末端骨骼造成高频信号从而造成抖动。