在JavaFX中正确地围绕三个轴旋转3D对象

9

到目前为止,我在JavaFX中旋转对象所使用的方法是将其分成三组,每一组都附加了一个旋转并锁定在一个单独的轴上,如下所示:

    Rotate heading, roll, pitch;
    Group normalrotate, rollrotate, verticalrotate;

    heading.setAxis(new Point3D(0,1,0));
    normalrotate.getTransforms().add(heading);

    roll.setAxis(new Point3D(0,0,1));
    rollrotate.getTransforms().add(roll);

    pitch.setAxis(new Point3D(1,0,0));
    verticalrotate.getTransforms().add(pitch);

并且每次需要旋转对象时,我都会做一次setAngle()。这对于仅涉及heading和roll的情况非常有效,直到我决定还需要pitch。现在,许多OpenGL等库的教程都说对于这些类型的旋转最好使用旋转矩阵或四元数,但是JavaDoc缺乏有关此类内容的有用数据。
例如:当我沿y轴将一个对象旋转180度时会发生什么(实际上应该发生透明蓝色部分的旋转)? enter image description here 我的操作是否有误?欢迎提供任何帮助。
2个回答

14

所有的教程都指向旋转矩阵的原因是:在三维中您无法逐个执行同时旋转,您需要一次性执行它们。由于JavaFX仅使用一个角度和一个轴,您必须提供将三个轴上的三个旋转转换为一个角度和一个轴的方法。

有段时间我在我的博客文章中解释了这些操作背后的数学。

所以基本上,从三个旋转:俯仰(绕其X轴),偏航(绕其Y轴)和滚转(绕其Z轴),您可以得到这些矩阵:

Matrices

如果将它们合并,则会得到一个单一的矩阵:

Matrix

不需要进一步解释,可以从以下内容计算角度和旋转单位轴分量:

eigenvalues

可写作:

private void matrixRotateNode(Node n, double alf, double bet, double gam){
    double A11=Math.cos(alf)*Math.cos(gam);
    double A12=Math.cos(bet)*Math.sin(alf)+Math.cos(alf)*Math.sin(bet)*Math.sin(gam);
    double A13=Math.sin(alf)*Math.sin(bet)-Math.cos(alf)*Math.cos(bet)*Math.sin(gam);
    double A21=-Math.cos(gam)*Math.sin(alf);
    double A22=Math.cos(alf)*Math.cos(bet)-Math.sin(alf)*Math.sin(bet)*Math.sin(gam);
    double A23=Math.cos(alf)*Math.sin(bet)+Math.cos(bet)*Math.sin(alf)*Math.sin(gam);
    double A31=Math.sin(gam);
    double A32=-Math.cos(gam)*Math.sin(bet);
    double A33=Math.cos(bet)*Math.cos(gam);

    double d = Math.acos((A11+A22+A33-1d)/2d);
    if(d!=0d){
        double den=2d*Math.sin(d);
        Point3D p= new Point3D((A32-A23)/den,(A13-A31)/den,(A21-A12)/den);
        n.setRotationAxis(p);
        n.setRotate(Math.toDegrees(d));                    
    }
}

其中alf代表滚转,bet代表俯仰,gam代表偏航。

你可以在这里找到完整的项目。


2
另一个很棒的答案!谢谢你,我在这个问题上真的遇到了难题。 - Moff Kalast
1
很不幸,我仍然无法确定相对于场景的累加最终偏航、横滚和俯仰角。http://stackoverflow.com/questions/30817123/javafx-8-transform-to-pitch-yaw-and-roll-rotation-angles - Moff Kalast
1
我看到了你的新问题,我会尝试去看一下。 - José Pereda
@kuhaku 很好的观点。我认为他们可能已经编辑过了?我几年前检查过,标志是相反的。无论如何,根据您输入的偏航、俯仰和滚转角度进行验证和调整很容易。 - José Pereda
2
指出旋转(和矩阵乘法)不满足交换律可能会有所帮助。也就是说,连续旋转的顺序很重要。关于不同轴的任意两个或多个旋转等效于绕复合轴的单个旋转。然而,如果更改旋转的顺序,则复合答案会有所不同。Jose的计算是针对三个矩阵的特定乘积,即按特定顺序旋转。我相信它是A = Az * Ay * Ax,这将首先绕x轴旋转,其次绕y轴旋转,最后绕z轴旋转。 - J.E.Tkaczyk
显示剩余2条评论

1

我可以提供一个解决方案。但这是有点不文明的做法,可能会被反对。

Node[] my3dModel = get3DModel();//the method creates a mesh (I suppose that you used Interactive mesh, but it's not important here)
Pane paneForMyModel = new Pane();
paneForMyModel.getChildren.addAll(my3dModel);//you add your model to this pane
//and now
paneForMyModel.getTransforms().add(new Rotate(angle, axis));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接