我正在根据来自串行设备的输入创建四元数。在处理中,我在以下代码中绕x轴旋转。我的四元数对象接受输入并使用set函数设置值,欧拉角和规格化。数学有问题吗?
我注释了z和y的旋转,但是与x轴相比,基本上该对象旋转得不是很好,或者是抖动的,所以效果很好。我在下面的代码中做错了什么?
作为参考,下面的shape(model)行是使用loadShape加载的.obj文件中加载的3d对象,shape函数将其显示在绘制循环中。
Quaternion q = new Quaternion(s);
q.set(x, y, z, w);
q = q.Euler(q.eulerAngles);
translate(x, y);
rotateX(q.eulerAngles.x);
//rotateY(q.eulerAngles.y);
//rotateZ(q.eulerAngles.z);
shape(model);
rotateX(-q.eulerAngles.x);
translate(-x, -y);
这是四元数类的一部分:
public class Quaternion {
PApplet s;
public float w,x,y,z;
public PVector eulerAngles;
public Quaternion(PApplet s, float x, float y, float z, float w){
this.s = s;
this.x = x;
this.y = y;
this.z = z;
this.w = w;
normalize();
}
public Quaternion(Quaternion q){
this.s = q.s;
this.w = q.w;
this.x = q.x;
this.y = q.y;
this.z = q.z;
}
public Quaternion normalize() {
float magnitude = w*w + x*x + y*y + z*z;
if(magnitude != 0.0 && magnitude != 1.0){
magnitude = 1.0f / s.sqrt(magnitude);
w *= magnitude;
x *= magnitude;
y *= magnitude;
z *= magnitude;
}
eulerAngles = setEulerAngles();
return this;
}
public Quaternion set(float x, float y, float z, float w) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
return normalize();
}
// Returns a rotation that rotates z degrees around
// the z axis, x degrees around the x axis, and y
// degrees around the y axis.
public Quaternion Euler(){
float roll = eulerAngles.x;
float pitch = eulerAngles.y;
float yaw = eulerAngles.z;
float cr = (float)Math.cos(roll * 0.5);
float sr = (float)Math.sin(roll * 0.5);
float cp = (float)Math.cos(pitch * 0.5);
float sp = (float)Math.sin(pitch * 0.5);
float cy = (float)Math.cos(yaw * 0.5);
float sy = (float)Math.sin(yaw * 0.5);
w = cy*cr*cp + sy*sr*sp;
x = cy*sr*cp - sy*cr*sp;
y = cy*cr*sp + sy*sr*cp;
z = sy*cr*cp - cy*sr*sp;
return normalize();
}
// set euler angle representation of
// the rotation in 3-dim PVector
private PVector setEulerAngles(){
// roll: x-axis rotation
float sinr = 2.0f * (w*x + y*z);
float cosr = 1.0f - 2.0f * (x*x + y*y);
float roll = (float)Math.atan2(sinr, cosr);
// pitch: y-axis rotation
float sinp = 2.0f * (w*y - z*x);
float pitch = 0.0f;
if(Math.abs(sinp) >= 1){
pitch = (float)Math.copySign(Math.PI/2, sinp);
} else {
pitch = (float)Math.asin(sinp);
}
// yaw: z-axis rotation
float siny = 2.0f * (w*z + x*y);
float cosy = 1.0f - 2.0f * (y*y + z*z);
float yaw = (float)Math.atan2(siny, cosy);
return new PVector(roll, pitch, yaw);
}
}
答案 0 :(得分:0)
据我所知,从方法中获得的欧拉角应以ZYX顺序而不是XYZ顺序应用。但是无论如何,除非确实需要,否则不要弄乱欧拉角。而在这种情况下,您不会。
相反,convert the quaternion to a rotation matrix并使用applyMatrix()
应用此变换。这里不会有歧义。
要还原变换,请不要应用逆变换(就像对rotateX(-q.eulerAngles.x)
和translate(-x, -y)
所做的那样)。在开发过程中容易混淆顺序或忘记转换。而是使用pushMatrix()
/ popMatrix()
或resetMatrix
。
顺便说一句,我发现您的四元数类的定义非常令人困惑。有些方法返回的值是我不希望返回的值(例如normalize()
)。此外,我不认为将欧拉角表示与四元数一起存储不是一个好主意。而且即使您认为是这样,我也无法理解方法Euler()
的目的,因为它既没有参数,也不能从外部设置欧拉角。