因此,我最近一直在学习四元数,并决定自己实现。我试图使它简单,但我仍然找不出我的错误。x/y/z轴旋转本身工作得很好,y/z旋转功也很好,但是第二次我把x轴加到其他任何一个,我得到一个奇怪的拉伸输出。我将附上以下轮转的重要代码:(请注意,我对cpp非常陌生)。
下面是我对四元数的描述(据我理解,因为它们是单位四元数,所以不需要虚数):
struct Quaternion {
float w, x, y, z;
};四元数的乘法规则:
Quaternion operator* (Quaternion n, Quaternion p) {
Quaternion o;
// implements quaternion multiplication rules:
o.w = n.w * p.w - n.x * p.x - n.y * p.y - n.z * p.z;
o.x = n.w * p.x + n.x * p.w + n.y * p.z - n.z * p.y;
o.y = n.w * p.y - n.x * p.z + n.y * p.w + n.z * p.x;
o.z = n.w * p.z + n.x * p.y - n.y * p.x + n.z * p.w;
return o;
}生成旋转四元数,使整个旋转乘以:
Quaternion rotate(float w, float x, float y, float z) {
Quaternion n;
n.w = cosf(w/2);
n.x = x * sinf(w/2);
n.y = y * sinf(w/2);
n.z = z * sinf(w/2);
return n;
}最后,将四元数转换为x/y/z位置的矩阵计算:
inline vector<float> quaternion_matrix(Quaternion total, vector<float> vec) {
float x = vec[0], y = vec[1], z = vec[2];
// implementation of 3x3 quaternion rotation matrix:
vec[0] = (1 - 2 * pow(total.y, 2) - 2 * pow(total.z, 2))*x + (2 * total.x * total.y - 2 * total.w * total.z)*y + (2 * total.x * total.z + 2 * total.w * total.y)*z;
vec[1] = (2 * total.x * total.y + 2 * total.w * total.z)*x + (1 - 2 * pow(total.x, 2) - 2 * pow(total.z, 2))*y + (2 * total.y * total.z + 2 * total.w * total.x)*z;
vec[2] = (2 * total.x * total.z - 2 * total.w * total.y)*x + (2 * total.y * total.z - 2 * total.w * total.x)*y + (1 - 2 * pow(total.x, 2) - 2 * pow(total.y, 2))*z;
return vec;
}差不多就是这样了(我还有一个规范函数来处理浮点错误),我将所有对象初始化为:W= 1,x= 0,y= 0,z= 0。我使用这样的表达式旋转四元数:
obj.rotation = rotate(angle, x-axis, y-axis, z-axis) * obj.rotation其中obj.rotation是对象的总四元数旋转值。
如果有人知道出了什么问题,或者以前也经历过这个问题,我很感激能在这个问题上得到任何帮助。谢谢
编辑:乘以这些四元数输出预期的旋转:
rotate(angle,1,0,0)
rotate(angle,0,1,0)
rotate(angle,0,0,1)
rotate(angle,0,1,1)然而,任何这样的旋转都会使模型奇怪地伸展开来:
rotate(angle,1,1,0)
rotate(angle,1,0,1)EDIT2:这里是我用来规范四元数的规范化函数:
Quaternion normalize(Quaternion n, double tolerance) {
// adds all squares of quaternion values, if normalized, total will be 1:
double total = pow(n.w, 2) + pow(n.x, 2) + pow(n.y, 2) + pow(n.z, 2);
if (total > 1 + tolerance || total < 1 - tolerance) {
// normalizes value of quaternion if it exceeds a certain tolerance value:
n.w /= (float) sqrt(total);
n.x /= (float) sqrt(total);
n.y /= (float) sqrt(total);
n.z /= (float) sqrt(total);
}
return n;
}发布于 2021-09-15 22:15:41
要按顺序实现两个旋转,您需要两个基本旋转的四元数乘积。每个初等旋转由一个轴和一个角度指定。但是,在您的代码中,您没有确保您有一个单位向量(方向向量)的轴线。
做下面的修改
Quaternion rotate(float w, float x, float y, float z) {
Quaternion n;
float f = 1/sqrtf(x*x+y*y+z*z)
n.w = cosf(w/2);
n.x = f * x * sinf(w/2);
n.y = f * y * sinf(w/2);
n.z = f * z * sinf(w/2);
return n;
}然后按以下方式使用
Quaternion n = rotate(angle1,1,0,0) * rotate(angle2,0,1,0)angle1与x轴的组合旋转,y轴的angle2旋转.
发布于 2021-09-15 21:19:21
正如注释中所指出的,您没有正确地初始化您的四元数。
下列四元数不是轮调:
rotate(angle,0,1,1)
rotate(angle,1,1,0)
rotate(angle,1,0,1)原因是轴没有归一化,例如,向量(0,1,1)没有归一化。也要确保你的角度是弧度。
https://stackoverflow.com/questions/69075254
复制相似问题