四元數與複數
複數 平面幾何意義一個向量 (2D)
複數做乘法 幾何上是一個新的向量 向量旋轉一定的角度 (2D)
擴展到3D 3個虛部的複數 四元數
[w (x y z)] = w+xi+yj+zk
i j k 的平方爲-1 三個虛部
四元數與軸-角對
繞着任意旋轉軸旋轉任意角度
負四元數 全部取反
單位四元數 表示沒有
四元數的模
模爲1的四元數 規範化的四元數
共軛
3d數學中使用的四元數 模都爲1 四元數的逆等於 四元數的共軛 旋轉方向相反
四元數叉乘
四元數的旋轉
P用q旋轉 p用a b依次旋轉 如果不習慣ba順序 可以修改叉乘的計算方式 (下圖計算 w x y z 錯誤 應該是
w = w1w2-x12-y1y2-z1z2
x = w1 x2 + x1w2 + z1y2 - y1z2
y = w1y2 + y1w2 + x1z2 - z1x2
z = w1z2 + z1w2+ y1x2 - x1y2)
四元數角位移 四元數的差 數學上四元數的除法
方位a 與方位b之間的夾角 d
旋轉角的倍數 q旋轉30 q的三分之一冪就是10度
#pragma once
#include "Vector3.h"
class Quaternion
{
public:
float w, x, y, z;
void Identify() { w = 1; x = 0; y = 0; z = 0; } //單位四元數
void setToRotateAboutX(float theta);
void setToRotateAboutY(float theta);
void setToRotateAboutZ(float theta);
void setToRotateAboutAxis(const Vector3 &axis,float theta);
float getRotationAngle() const;
Vector3 getRotationAxis() const;
};
extern const Quaternion kQuaternionIdentify;
#include "pch.h"
#include "Quaternion.h"
#include <math.h>
#include <assert.h>
#include "MathUtil.h"
const Quaternion kQuaternionIdentify = { 1.0f,0.0f,0.0f,0.0f };
void Quaternion::setToRotateAboutX(float theta)
{
//計算半角
float thetaOver2 = theta * 0.5f;
//計算w
w = cos(thetaOver2);
x = sin(thetaOver2)*1;
y = 0.0f;
z = 0.0f;
}
void Quaternion::setToRotateAboutY(float theta)
{
//計算半角
float thetaOver2 = theta * 0.5f;
//計算w
w = cos(thetaOver2);
x = 0.0f;
y = sin(thetaOver2) * 1;
z = 0.0f;
}
void Quaternion::setToRotateAboutZ(float theta)
{
//計算半角
float thetaOver2 = theta * 0.5f;
//計算w
w = cos(thetaOver2);
x = 0.0f;
y = 0.0f;
z = sin(thetaOver2) * 1;
}
void Quaternion::setToRotateAboutAxis(const Vector3 &axis, float theta)
{
assert(fabs(VecMag(axis) - 1.0f) < 0.01f);
float thetaOver2 = theta * 0.5f;
float sinThetaOver2 = sin(thetaOver2);
w = cos(thetaOver2);
x = axis.x*sinThetaOver2;
y = axis.y*sinThetaOver2;
z = axis.z*sinThetaOver2;
}
//四元數算出旋轉角
float Quaternion::getRotationAngle() const
{
//根據w 算出半角
float thetaOver2 = safeAcos(w);
return 2 * thetaOver2;
}
//四元數算出旋轉軸
Vector3 Quaternion::getRotationAxis() const
{
float sinThetaOver2Sq = 1.0f - w * w;
float sinThetaOver2 = sqrt(sinThetaOver2Sq);
float oneOverSinThetaOver2 = 1 / sinThetaOver2;
float nx = x* oneOverSinThetaOver2;
float ny = y * oneOverSinThetaOver2;
float nz = z* oneOverSinThetaOver2;
return Vector3(nx,ny,nz);
}