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

发布于 2024-08-02 10:06:42 字数 914 浏览 1 评论 0原文

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

提前感谢所有帮助!

I have a Cone I drew in Java 3D with the following code:

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

Suppose I have the cone sitting at point (1,1,1) and I want the tip of the cone to point down an imaginary line running through (0,0,0) and (1,1,1)... how can I do this?

Here's an example of what I've been trying:

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

Thanks in advance for all help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

朕就是辣么酷 2024-08-09 10:06:42

我目前正在学习 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() 方法。一个向量将按照初始方向设置,另一个向量按照预期方向设置。
但是,这并没有告诉您角度位于哪个轴上。这样做需要检查向量以查看设置了哪些段。 [当然,API中可能还有一些我目前不知道的地方]

I'm just learning Java 3D myself at the moment, and from my current knowledge, the rotation methods set the transform to a rotation about that axis only.
Therefore, if you wish to perform rotations about multiple axes, then you will need to use a second Transform3D.
ie:

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.

As for the reason for Math.PI, this is because it uses radians instead of degrees, where Math.PI is equivalent to 180 degrees.

Finding the angle between your current orientation and your intended orientation isn't too hard - you could use Vector3fs, with the angle() method. A Vector would be set up with the initial orientation, and another in the intended.
However, this doesn't tell you in which axes the angle lies. Doing so would require examination of the vectors to see which segments are set. [of course, there may be something that I am currently unaware of in the API]

暮倦 2024-08-09 10:06:42

这不是 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),位置仍然是 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 / 长度、vDir.y / 长度、vDir.z / 长度、vDir.w / 长度),那么我们对其进行标准化,得到一个方向,总长度为 1。

此时,我们有了矩阵的第三列和第四列。现在,我们假设 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) 向量的点时,您会遇到问题,但这应该适用于 most< /em> 案例。

This is not a java3D specific answer.

In general a matrix can be built such that there are 4 vectors that describe it.

1) A side (or lateral) vector
2) An up vector
3) A direction vector
4) A position

Each row of a 4x4 matrix.

Thus for a simple identity matrix we have the following matrix (I'll define a column major matrix, for a row major matrix all you need to do is swap the matrix indices around such that row 2 col 3 becomes row 3 col 2 throughout the matrix).

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

in this the first column is the side vector. The second column the up vector. The third the direction and the fourth the position.

Logically we can see that the vector (1, 0, 0, 0) points along the x axis (and thus is the side vector). The vector (0, 1, 0, 0) points along the y axis (and thus is the up vector). The third (0, 0, 1, 0) points along the Z-axis (and thus is the direction vector). The fourth (0, 0, 0, 1) indicates that the objects does not move at all.

Now lets say we wanted to face along the X-axis.

Obviously that would mean we have a vector of (1, 0, 0, 0 ) for our direction vector. Up would still be (0, 1, 0, 0) and position still 0, 0, 0 1. So what would our side vector be? Well, logically it would point along the z-axis. But which way? Well hold your fingers such that one finger points forward, one to the side and one up. Now rotate so that the forward finger is facing the same direction as the side pointing finger. Which way is the side pointing finger pointing now? The opposite direction to the original direction pointing finger. Thus the matrix is

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

At this point things seemingly get a little more complicated. It is simple enough to take an arbitrary position and an arbitrary point to look at (I'll call them vPos and vFocus). It is easy enough to form a vector from vPos to vFocus by subtracting vPos from vFocus (vFocus.x - vPos.x, vFocus.y - vPos.y, vFocus.z - vPos.z, vFocus.w - vPos.w ). Bear in mind all positions should be defined with a '1' in the w position where all directions should have a '0'. This is automatically taken care of when you do the subtraction above as the 1 in both ws will cancel out and leave 0. Anyway, we now have a vector pointing from the position towards vFocus we'll call it vDir. Unfortunately it has the length of the difference between vPos and vFocus. However if we divide the vDir vector by its length (vDir.x / length, vDir.y / length, vDir.z / length, vDir.w / length) then we normalise it and we have a direction with a total length of 1.

At this ponit we now have our 3rd and 4th columns of our matrix. Now, lets assuem up is still (0, 1, 0, 0) or vUp. We can assume that the crossproduct of the direction and vUp will produce a vector that is perpendicular (and also of unit length) to the plane formed by vDir and vUp. This gives us our side vector or vLat. Now .. we did kind of assume the up vector so its not strictly correct. We can now calculate it exactly by taking the cross product of vLat and vDir and we have all 4 vectors.

The final matrix is thus defined as follows

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

This isn't strictly the full answer as you will get problems as you look towards a point near to your (0, 1, 0, 0) vector but that should work for most cases.

贪了杯 2024-08-09 10:06:42

我终于弄清楚了我想通过使用四元数来做什么,我在这里了解到: 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);
    }

I finally figured out what I wanted to do by using Quaternions, which I learned about here: http://www.cs.uic.edu/~jbell/Courses/Eng591_F1999/outline_2.html Here's my solution.

Creating the cone:

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

Now, when I want to rotate the cone to point in a certain direction specified as the vector from the point (0,0,0) to (direction.x, direction.y, direction.z), I use:

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);
    }
终弃我 2024-08-09 10:06:42

我认为应该这样做:

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

I think this should do it:

coneTransform.rotX(Math.PI / 4);
coneTransform.rotY(Math.PI / 4);
浅听莫相离 2024-08-09 10:06:42

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

you can give your Transform3D a rotation matrix. you can get a rotation matrix using Rotation matrix calculator online: http://toolserver.org/~dschwen/tools/rotationmatrix.html here's my example:

    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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文