问题描述
我目前正在编写自己的游戏引擎,但无法正确实现四元数。我当前的四元数实现如下所示:
/*
CybRender - Quaternion API
*/
#include "CybQuat.h"
//Functions
//=================================================================================
void Cyb_QuatFromAxisAndAngle(Cyb_Vec4 *quat,float x,float y,float z,float angle)
{
quat->x = x * sinf(radians(angle) / 2.0f);
quat->y = y * sinf(radians(angle) / 2.0f);
quat->z = z * sinf(radians(angle) / 2.0f);
quat->w = cosf(radians(angle) / 2.0f);
}
void Cyb_MulQuat(Cyb_Vec4 *c,const Cyb_Vec4 *a,const Cyb_Vec4 *b)
{
c->x = a->w * b->x + a->x * b->w + a->y * b->z - a->z * b->y;
c->y = a->w * b->y - a->x * b->z + a->y * b->w + a->z * b->x;
c->z = a->w * b->z + a->x * b->y - a->y * b->x + a->z * b->w;
c->w = a->w * b->w - a->x * b->x - a->y * b->y - a->z * b->z;
}
void Cyb_QuatToMatrix(Cyb_Mat4 *mat,const Cyb_Vec4 *quat)
{
//Start with the identity matrix
Cyb_Identity(mat);
//Row 1
mat->a = 1 - 2 * quat->y * quat->y - 2 * quat->z * quat->z;
mat->b = 2 * quat->x * quat->y - 2 * quat->w * quat->z;
mat->c = 2 * quat->x * quat->z + 2 * quat->w * quat->y;
//Row 2
mat->e = 2 * quat->x * quat->y + 2 * quat->w * quat->z;
mat->f = 1 - 2 * quat->x * quat->x - 2 * quat->z * quat->z;
mat->g = 2 * quat->y * quat->z + 2 * quat->w * quat->x;
//Row 3
mat->i = 2 * quat->x * quat->z - 2 * quat->w * quat->y;
mat->j = 2 * quat->y * quat->z - 2 * quat->w * quat->x;
mat->k = 1 - 2 * quat->x * quat->x - 2 * quat->y * quat->y;
}
如果我只绕 X、Y 或 Z 轴旋转,它可以正常工作。但是,当我尝试绕任意轴旋转时,会出现奇怪的失真:
我尝试了不同的公式来将四元数转换为矩阵,但每次都会出现类似的失真。我已经测试了我的矩阵实现,以确保它正常工作并且没有发现任何问题。
将四元数转换为矩阵的正确公式是什么?
解决方法
结果证明是将四元数转换为矩阵的函数中的一个小错误。这是更正后的代码:
/*
CybRender - Quaternion API
*/
#include "CybQuat.h"
//Functions
//=================================================================================
void Cyb_QuatFromAxisAndAngle(Cyb_Vec4 *quat,float x,float y,float z,float angle)
{
quat->x = x * sinf(radians(angle) / 2.0f);
quat->y = y * sinf(radians(angle) / 2.0f);
quat->z = z * sinf(radians(angle) / 2.0f);
quat->w = cosf(radians(angle) / 2.0f);
}
void Cyb_MulQuat(Cyb_Vec4 *c,const Cyb_Vec4 *a,const Cyb_Vec4 *b)
{
c->x = a->w * b->x + a->x * b->w + a->y * b->z - a->z * b->y;
c->y = a->w * b->y - a->x * b->z + a->y * b->w + a->z * b->x;
c->z = a->w * b->z + a->x * b->y - a->y * b->x + a->z * b->w;
c->w = a->w * b->w - a->x * b->x - a->y * b->y - a->z * b->z;
}
void Cyb_NormalizeQuat(Cyb_Vec4 *quat)
{
float magnitude = sqrt(quat->x * quat->x + quat->y * quat->y + quat->z * quat->z + quat->w * quat->w);
quat->x /= magnitude;
quat->y /= magnitude;
quat->z /= magnitude;
quat->w /= magnitude;
}
void Cyb_QuatToMatrix(Cyb_Mat4 *mat,const Cyb_Vec4 *quat)
{
//Start with the identity matrix
Cyb_Identity(mat);
//Row 1
mat->a = 1.0f - 2.0f * (quat->y * quat->y + quat->z * quat->z);
mat->b = 2.0f * (quat->x * quat->y - quat->w * quat->z);
mat->c = 2.0f * (quat->x * quat->z + quat->w * quat->y);
//Row 2
mat->e = 2.0f * (quat->x * quat->y + quat->w * quat->z);
mat->f = 1.0f - 2.0f * (quat->x * quat->x + quat->z * quat->z);
mat->g = 2.0f * (quat->y * quat->z - quat->w * quat->x);
//Row 3
mat->i = 2.0f * (quat->x * quat->z - quat->w * quat->y);
mat->j = 2.0f * (quat->y * quat->z + quat->w * quat->x);
mat->k = 1.0f - 2.0f * (quat->x * quat->x + quat->y * quat->y);
}
我希望这能帮助其他需要实现四元数的人。