在3D的游戏中,用的最多的就是矩阵和向量,矩阵其实就是一个世界,向量就是这个世界的具体位置。每个3D都会有世界坐标和各种局部坐标。一个向量乘上不同的矩阵,就会变成在这个矩阵所代表的世界里。局部坐标是以单个模型为原点设置的坐标系,世界坐标是以整个世界的原点作为坐标系。但是涉及到世界坐标各个物体的计算时,就必须把物体的局部坐标转换为世界坐标,或者反过来计算。其中,4D齐次矩阵就是主要用来计算关于平移的。
局部坐标转换为全局坐标:
V(全局) = V(局部)*W
其中W是一个矩阵,是4x4的:
这是因为在局部坐标系中,会有以自己的中心点为原点的局部坐标系,这里的r,u,f就是局部坐标系里面的三个坐标轴,p是要计算的局部坐标。
如果要计算世界坐标到局部坐标的位置,则就是全局向量乘上W矩阵的逆矩阵:
V(局部) = V(全局)*W(-1)
这个时候,在矩阵间不断变换的向量,出现了一种情况,就是不但要平移,还要旋转,这两者要同时做,怎么办呢。。。所以就出现了四元数。
四元数,其实就是一个4次的向量,这个向量很有意义,因为前三个数字,是代表要变换的向量所要围绕旋转的向量的x,y,z值,最后的那个数字,就是要围绕这个轴旋转多少度。这里,这个角度值应该是被计算为弧度了,在DX中,默认逆时针的旋转方向为正,在OpenGL就反过来。这个时候,要变换的那个向量就必须和它所在的坐标系,世界坐标或者是局部坐标结合成为一个4D齐次矩阵,矩阵前三个向量就是所在矩阵的x,y,z值,最后一个就是要变换的向量。这样成上四元数,就能得到围绕旋转之后的向量。
下图是在同一空间(矩阵)中的向量变换:
计算的时候,局部坐标就要对应局部的四元数来计算,世界坐标就要对应世界的四元数来计算。
不过,在OGRE中,一切都格外简单,仅仅是调用一个函数而已,例如:
Quaternion q = direction.getRotationTo(destination);
nMeshNode->rotate(q);
不过还是有很多细节要注意,具体的函数实现,参考了网上的资料后,我是这样做的:
//
//用于在改变了Destination的值的时候,改变当前节点的X轴朝向(就是旋转一个四元数来变化局部的X轴在世界坐标的位置)
//在转换朝向的时候,不用nMeshNode->setDirection(mNextPosition,Node::TransformSpace::TS_WORLD)的原因是因为这个模型的正前方是X轴
//setDirection是设置Z轴的方向(通常来说都是默认Z轴为正朝向)
void Enimy::RotateXAix(const Vector3 &Destination)
{
Vector3 destination = Destination;//觉得还是在函数里面用一个局部的变量来存储不会改变到参数的值会好一点
//计算当前的节点的朝向,由于模型是以X轴为正前方,所以要乘上Vector3::UNIT_X
Vector3 direction = nMeshNode->getOrientation() * Vector3::UNIT_X;
direction.y = 0;
destination.y = 0;
//记得单位化
direction.normalise();
destination.normalise();
//相差角度为180度的时候,要是用rotate函数是会出现错误的,所以要用yaw函数来处理
if((1.0f + direction.dotProduct(destination)) < 0.00001f)
{
nMeshNode->yaw(Degree(180));
}
else
{
Quaternion q = direction.getRotationTo(destination);
nMeshNode->rotate(q);
}
}