如何在Java 3D中旋转对象?

时间:2009-08-25 20:19:23

标签: java opengl graphics java-3d

我有一个使用以下代码在Java 3D中绘制的Cone:

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

提前感谢您的帮助!

5 个答案:

答案 0 :(得分:3)

我现在只是自己学习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度。

找到当前方向与预期方向之间的角度并不太难 - 您可以使用带有angle()方法的Vector3fs。将使用初始方向设置Vector,并在预期中设置另一个。 但是,这并不能告诉您角度所在的轴。这样做需要检查向量以查看设置了哪些段。 [当然,我可能在API中没有意识到这一点]

答案 1 :(得分:2)

这不是java3D的具体答案。

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

1)侧面(或侧面)矢量
2)向上矢量
3)方向矢量
4)位置

4x4矩阵的每一行。

因此,对于一个简单的单位矩阵,我们有以下矩阵(我将定义一个列主矩阵,对于行主矩阵,您需要做的就是交换矩阵索引,使得第2行第3列成为第3行col整个矩阵中的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轴指向(因此是向上向量)。沿Z轴的第三个(0,0,1,0)点(因此是方向矢量)。第四个(0,0,0,1)表示对象根本不移动。

现在我们可以说我们想沿着X轴面对。

显然,这意味着我们的方向向量有一个(1,0,0,0)向量。 Up仍然是(0,1,0,0)并且位置仍然是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很容易形成从vPos到vFocus的向量(vFocus.x - vPos.x,vFocus.y - vPos.y,vFocus.z - vPos.z,vFocus.w - vPos.w) 。请记住,所有位置都应在w位置定义为'1',其中所有方向都应为'0'。当你进行上面的减法时,这会自动处理,因为两个ws中的1将取消并离开0.无论如何,我们现在有一个向量指向vFocus的位置,我们称之为vDir。不幸的是,它具有vPos和vFocus之间的差异长度。但是,如果我们将vDir向量除以其长度(vDir.x / length,vDir.y / length,vDir.z / length,vDir.w / length),那么我们规范化它我们有一个总长度为1的方向。

在这个ponit,我们现在有了矩阵的第3和第4列。现在,让我们假设仍然是(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)向量的点时你会遇到问题,但这应该适用于大多数情况。

答案 2 :(得分:1)

我终于通过使用Quaternions找到了我想做的事情,我在这里了解到: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);
    }

答案 3 :(得分:0)

我认为应该这样做:

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

答案 4 :(得分:0)

你可以给你的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);