【问题标题】:How to rotate an object in Java 3D?如何在 Java 3D 中旋转对象?
【发布时间】:2010-11-22 18:38:36
【问题描述】:

我有一个用 Java 3D 绘制的圆锥体,代码如下:

Cone cone = new Cone(2f, 3f);

Transform3D t3d = new Transform3D();
TransformGroup coneTransform = new TransformGroup(t3d);
coneTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

t3d.setTranslation(new Vector3f(0f,0f,0f);
coneTransform.setTransform(t3d);
coneTransform.addChild(cone);

this.addChild(coneTransform);

假设我的圆锥位于点 (1,1,1),并且我希望圆锥的尖端指向一条穿过 (0,0,0) 和 (1,1,1) 的假想线。 .. 我该怎么做?

这是我一直在尝试的一个示例:

Transform3D t3d = new Transform3D();  

Vector3f direction = new Vector3f(1,2,1);    

final double angleX = direction.angle(new Vector3f(1,0,0));
final double angleY = direction.angle(new Vector3f(0,1,0));
final double angleZ = direction.angle(new Vector3f(0,0,1));

t3d.rotX(angleX);
t3d.rotY(angleY);
t3d.rotZ(angleZ);

t3d.setTranslation(direction);

coneTransform.setTransform(t3d);

提前感谢所有帮助!

【问题讨论】:

    标签: java opengl graphics java-3d


    【解决方案1】:

    目前我自己正在学习 Java 3D,根据我目前的知识,旋转方法将变换设置为仅围绕该轴进行旋转。 因此,如果您希望围绕多个轴执行旋转,则需要使用第二个 Transform3D。
    即:

    Transform3D rotation = new Transform3D();
    Transform3D temp = new Transform3D();
    
    rotation.rotX(Math.PI/2);
    temp.rotZ(Math.PI/2);
    rotation.mul(temp); // multiply the 2 transformation matrices together.
    

    至于 Math.PI 的原因,是因为它使用弧度而不是度数,其中 Math.PI 相当于 180 度。

    找到当前方向和预期方向之间的角度并不难 - 您可以使用 Vector3fs 和 angle() 方法。一个 Vector 将设置为初始方向,另一个设置为预期方向。 但是,这并不能告诉您角度位于哪个轴上。这样做需要检查向量以查看设置了哪些段。 [当然,API 中可能有一些我目前不知道的东西]

    【讨论】:

    • 啊...所以我需要为每个要旋转的轴单独的 Transform3D?我试图使用相同的 Transform3D 实例并在其上执行 rotX()、rotY()、rotZ()。我会试试看。
    • 我使用四元数进行旋转。围绕 x 和 y 旋转只会给我带来不可靠的问题。显然,万向节锁并不是 100% 可以避免的。四元数避免了这种情况。
    【解决方案2】:

    这不是 java3D 特定的答案。

    通常可以构建一个矩阵,以便有 4 个向量来描述它。

    1) 侧面(或横向)矢量
    2) 向上向量
    3) 一个方向向量
    4) 一个职位

    4x4 矩阵的每一行。

    因此,对于一个简单的单位矩阵,我们有以下矩阵(我将定义一个列主矩阵,对于一个行主矩阵,您只需交换矩阵索引,使第 2 列第 3 行变为第 3 列列2 整个矩阵)。

    1 0 0 0
    0 1 0 0
    0 0 1 0
    0 0 0 1
    

    在此第一列是侧向量。第二列向上向量。第三个方向,第四个位置。

    从逻辑上我们可以看到向量 (1, 0, 0, 0) 指向 x 轴(因此是边向量)。向量 (0, 1, 0, 0) 沿 y 轴指向(因此是向上向量)。第三个 (0, 0, 1, 0) 点沿 Z 轴(因此是方向向量)。第四个 (0, 0, 0, 1) 表示对象根本不动。

    现在假设我们要面向 X 轴。

    显然,这意味着我们的方向向量有一个 (1, 0, 0, 0 ) 向量。 Up 仍然是 (0, 1, 0, 0) 并且 position 仍然是 0, 0, 0 1。那么我们的边向量是什么?好吧,从逻辑上讲,它会指向 z 轴。但是哪条路?握住你的手指,一个手指指向前方,一个指向侧面,一个指向上方。现在旋转,使前指与侧指指向相同的方向。侧指指点现在哪个方向?指向手指的原始方向的相反方向。因此矩阵是

     0 0 1 0
     0 1 0 0
    -1 0 0 0
     0 0 0 1
    

    在这一点上,事情似乎变得有点复杂。取任意位置和任意点进行查看非常简单(我将它们称为 vPos 和 vFocus)。通过从 vFocus 中减去 vPos(vFocus.x - vPos.x,vFocus.y - vPos.y,vFocus.z - vPos.z,vFocus.w - vPos.w),很容易形成从 vPos 到 vFocus 的向量.请记住,所有位置都应在 w 位置定义为“1”,所有方向都应为“0”。当您执行上述减法时,这会自动处理,因为两个 ws 中的 1 将抵消并留下 0。无论如何,我们现在有一个从该位置指向 vFocus 的向量,我们将其称为 vDir。不幸的是,它具有 vPos 和 vFocus 之间差异的长度。但是,如果我们将 vDir 向量除以其长度(vDir.x / 长度,vDir.y / 长度,vDir.z / 长度,vDir.w / 长度)然后我们规范化它,我们有一个方向,总长度为 1。

    在这个点上,我们现在有了矩阵的第 3 列和第 4 列。现在,让我们假设 up 仍然是 (0, 1, 0, 0) 或 vUp。我们可以假设方向和 vUp 的叉积将产生一个垂直于(也是单位长度)由 vDir 和 vUp 形成的平面的向量。这给了我们侧向量或 vLat。现在..我们确实假设了向上向量,所以它不是严格正确的。我们现在可以通过 vLat 和 vDir 的叉积来精确计算它,我们有所有 4 个向量。

    因此最终的矩阵定义如下

    vLat.x vUp.x vDir.x vPos.x
    vLat.y vUp.y vDir.y vPos.y
    vLat.z vUp.z vDir.z vPos.z
    vLat.w vUp.w vDir.w vPos.w
    

    严格来说,这并不是完整的答案,因为当您查看靠近 (0, 1, 0, 0) 向量的点时会遇到问题,但这应该适用于大多数情况

    【讨论】:

      【解决方案3】:

      我终于通过使用四元数弄清楚了我想做什么,我在这里了解到:http://www.cs.uic.edu/~jbell/Courses/Eng591_F1999/outline_2.html 这是我的解决方案。

      创建圆锥体:

       private void attachCone(float size) {
              Cone cone = new Cone(size, size* 2);
      
              // The group for rotation
              arrowheadRotationGroup = new TransformGroup();
              arrowheadRotationGroup.
                   setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
              arrowheadRotationGroup.addChild(cone);
      
              // The group for positioning the cone
              arrowheadPositionGroup = new TransformGroup();
              arrowheadPositionGroup. 
                    setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
              arrowheadPositionGroup.addChild(arrowheadRotationGroup);
      
              super.addChild(arrowheadPositionGroup);
          }
      

      现在,当我想旋转圆锥指向某个方向时,该方向指定为从点 (0,0,0) 到 (direction.x, direction.y, direction.z) 的向量,我使用:

      private final Vector3f yAxis = new Vector3f(0f, 1f, 0f);
      private Vector3f direction; 
      
      private void rotateCone() {
              // Get the normalized axis perpendicular to the direction 
              Vector3f axis = new Vector3f();
              axis.cross(yAxis, direction);
              axis.normalize();
      
              // When the intended direction is a point on the yAxis, rotate on x
              if (Float.isNaN(axis.x) && Float.isNaN(axis.y) && Float.isNaN(axis.z)) 
              {
                  axis.x = 1f;
                  axis.y = 0f;
                  axis.z = 0f;
              }
              // Compute the quaternion transformations
              final float angleX = yAxis.angle(direction);
              final float a = axis.x * (float) Math.sin(angleX / 2f);
              final float b = axis.y * (float) Math.sin(angleX / 2f);
              final float c = axis.z * (float) Math.sin(angleX / 2f);
              final float d = (float) Math.cos(angleX / 2f);
      
              Transform3D t3d = new Transform3D();
              Quat4f quat = new Quat4f(a, b, c, d);
              t3d.set(quat);
              arrowheadRotationGroup.setTransform(t3d);
      
              Transform3D translateToTarget = new Transform3D();
              translateToTarget.setTranslation(this.direction);
              arrowheadPositionGroup.setTransform(translateToTarget);
          }
      

      【讨论】:

        【解决方案4】:

        我认为应该这样做:

        coneTransform.rotX(Math.PI / 4);
        coneTransform.rotY(Math.PI / 4);
        

        【讨论】:

        • 谢谢。 t3d.rotX(数学.PI / 2);同样对于 Y,Z 将旋转圆锥。您能否描述如何计算旋转 X 和 Y 的角度?例如,如果我有一条从 (0,0,0) 到 (1,1,1) 的线,如何计算旋转量?
        • 旋转函数以弧度值作为输入。有 2*PI 一整圈,或垂直线之间的 PI/2 度(这意味着我错了,您只需要旋转 PI/4)。一般来说,您不需要沿所有三个角度旋转,因为您可以通过沿两个轴旋转来描述任何旋转。
        • 哈哈——我只是意识到我不需要全部 3 个旋转。我现在正在纸上研究如何计算我需要的角度。感谢您的帮助。
        • 围绕 x 和 y 旋转一直给我带来不可靠的问题。我最终发现了一种方法,您可以在我发布的答案中看到。
        【解决方案5】:

        你可以给你的 Transform3D 一个旋转矩阵。您可以使用在线旋转矩阵计算器获得旋转矩阵:http://toolserver.org/~dschwen/tools/rotationmatrix.html 这是我的示例:

            Matrix3f mat = new Matrix3f(0.492403876506104f, 0.586824088833465f,
                    -0.642787609686539f, 0.413175911166535f, 0.492403876506104f,
                    0.766044443118978f, 0.766044443118978f, -0.642787609686539f, 0f);
        
            Transform3D trans = new Transform3D();
        
            trans.set(mat);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-06-19
          • 1970-01-01
          • 2015-09-14
          • 2013-09-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多