处理:使用四元数旋转3D对象适用于x轴,但不适用于y或z轴吗? [英] Processing: Rotating a 3D object using Quaternions works for x-axis, but not for y or z axis?

查看:138
本文介绍了处理:使用四元数旋转3D对象适用于x轴,但不适用于y或z轴吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在根据来自串行设备的输入创建四元数.在处理"中,我在下面的代码中绕x轴旋转.我的四元数对象接受输入并使用set函数设置值,欧拉角和规格化.数学有问题吗?

I'm creating a Quaternion from input from a serial device. In Processing I rotate around the x-axis in the code below. My Quaternion object takes the input and uses the set function to set the values, euler angles, and normalize. Is there something wrong with the math?

我注释掉了z和y的旋转,但是与x轴相比,基本上该对象旋转得不是很好,或者是抖动的,所以效果很好.我在下面的代码中做错了什么?

I commented out rotation for z and y, but basically the object doesn't rotate around very well or is jerky compared to the x-axis, which works perfectly. What am I doing wrong in the code below?

作为参考,下面的shape(model)行是使用loadShape加载的.obj文件中加载的3d对象,shape函数将其显示在绘制循环中.

For reference, the shape(model) line below is the loaded 3d object from a .obj file loaded in using loadShape and the shape function displays it in the draw loop.

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);

这是四元数类的一部分:

This is part of the Quaternion class:

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

推荐答案

据我所知,从方法中获得的欧拉角应以ZYX顺序而不是XYZ顺序应用.但是无论如何,除非确实需要,否则不要弄乱欧拉角.而在这种情况下,您不会.

As far as I can tell, the Euler angles that you get from your method should be applied in ZYX order rather than XYZ. But anyway, do not mess around with Euler angles unless you really have to. And in this case you don't.

相反,将四元数转换为旋转矩阵并使用 applyMatrix() 应用此转换.这里不会有歧义.

Instead, convert the quaternion to a rotation matrix and apply this transform using applyMatrix(). There will be no ambiguity here.

要还原变换,请不要应用逆变换(就像对rotateX(-q.eulerAngles.x)translate(-x, -y)所做的那样).在开发过程中容易混淆顺序或忘记转换.而是使用 pushMatrix() / resetMatrix .

To revert a transform, do not apply the inverse transform (like you did with rotateX(-q.eulerAngles.x) and translate(-x, -y)). It is very easy to confuse the order or forget a transform during development. Instead, use pushMatrix() / popMatrix() or resetMatrix.

顺便说一句,我发现您的四元数类的定义非常令人困惑.某些方法返回的值我不希望返回任何值(例如normalize()).此外,我不认为将欧拉角表示与四元数一起存储不是一个好主意.即使您认为是正确的,我也不理解方法Euler()的目的,因为它既没有参数,也不能从外部设置欧拉角.

Btw, I find the definition of your quaternion class very confusing. Some methods return values that I would not expect to return anything (e.g. normalize()). Furthermore, I do not think that having an Euler angle representation stored with the quaternion is a good idea. And even if you think it is, I don't understand the purpose of the method Euler() since it neither has parameters, nor can you set the Euler angles from outside.

这篇关于处理:使用四元数旋转3D对象适用于x轴,但不适用于y或z轴吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆