首页 > 解决方案 > 将四元数转换为矩阵的正确公式是什么

问题描述

我目前正在编写自己的游戏引擎,但无法正确实现四元数。我当前的四元数实现如下所示:

/*
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 轴旋转,它可以正常工作。但是,当我尝试绕任意轴旋转时,会出现奇怪的失真:

图片

我尝试了不同的公式将我的四元数转换为矩阵,但每次我得到类似的失真。我已经测试了我的矩阵实现以确保它正常工作并且没有发现任何问题。

将四元数转换为矩阵的正确公式是什么?

标签: c3dopengl-3

解决方案


结果证明这是将四元数转换为矩阵的函数中的一个小错误。这是更正后的代码:

/*
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);
}

我希望这将有助于其他需要实现四元数的人。


推荐阅读