|
|
前一段时间打算使用四元数来存储角位移,书上说明四元数存储方位使用了四个数,而矩阵则需要“浪费”九个数,事实真的如此吗?
四元数可以说在动态物体中一无是处,首先,动态物体伴随着旋转、平移、缩放等;其次,动态物体具有三个朝向,而四元数仅能连接针对向量的多次旋转,最后,每一桢动态物体经过少量的运动变换便总是要转换到基向量矩阵以便输出给渲染系统。
若要完整的表现动态物体的方位问题,共需要对三个朝向进行旋转,至于插值问题,仍需要从动态物体的状态中抽取向量,不仅各个轴向均要参与计算,要使得多个轴向均符合插值需要,仍要计算两组。鉴于四元数不是动态物体状态的标准表达形式,和其难于使用的特点,并且比矩阵更难于捉摸的误差累积,使得相机动画等设计实现受到了限制。
旋转矩阵使用了九个数,这在存储上处于劣势,但是对于动态物体,这点损失可以忽略,具体的旋转连接,四元数展开的运算和矩阵的任意轴旋转是一样的,但因为只反映一个向量的旋转,所以不像矩阵那样作用于三个向量,而事实上 UVN 系统要求旋转连接对应于三个向量而非一个,所以四元数在这里便失去了连接以优化效率的作用,并且矩阵用法在结合平移的时候,避免了表达方式之间的转换。四元数是一种古怪的使用四个数替代了原本共需要完整的九个数反映三个向量的旋转、平移、缩放的连接来处理单个向量的旋转连接的系统。
看来 slerp 插值成为了使用四元数的决定性因素,其实,在考虑使用四元数之前,我便解决了矩阵的插值问题,我认为矩阵不仅可以插值,并且更好地反映了插值的本质。另有一个优势,矩阵的单位基向量对于四元数来说是零角位移,而四元数则无法使用零角位移参与连接,必须连接对象的模为单位长度,只能通过外部指定,缺乏封装的特性。
void SystemUVN::Match_N(const Vector3& p)
{
if (p.Mod() < Epsilon)
return;
Vector3 N(_Axis._31, _Axis._32, _Axis._33);
N.Normalize();
Vector3 P = p.Normalize();
float dot = N * P;
Vector3 n;
if (dot > 0.99999f) // cos(Angle(0.25).ToRadian())
return;
if (dot < -0.99999f)
{
dot = std::max(dot, -1.0f);
n = (Get_U() - Get_V()).Normalize();
}
else n = N.CrossProduct(P).Normalize();
_Axis *= Matrix().BuildRotation(n, Radian(acos(dot)).ToAngle());
_CheckOrthogonalization();
} |
|