对于初学者,对于JavaFX 3D应用程序,您应该考虑以下几点:
  
  
  
   而你没有这些。
  
  
   您需要启用深度缓冲区,因为您可以看到黄色小框似乎位于大框的顶部(浅黄色的面应该根本看不见):
  
  
   
     
   
  
  
  
  
   根据JavaDoc
   
    Scene
   
   :
  
  
   
    包含3D形状或具有3D变换的2D形状的场景可以使用深度缓冲区支持进行适当的深度排序渲染
   
  
  
   更改:
  
  Scene scene = new Scene(combined, width, height);
  
   收件人:
  
  Scene scene = new Scene(combined, width, height, true, SceneAntialiasing.BALANCED);
  
   一旦你这样做了,你就会意识到当盒子转到z时>0不再可见,顶部的按钮也不再可单击。
  
  
   在同一场景中混合2D和3D不是一个好主意。为此,你需要
   
    SubScene
   
   ,您可以在其中布局3D内容,并将2D保留在场景本身中。此外,还可以将深度缓冲区和抗锯齿选项移动到子场景:
  
  Parent robot = createRobot();
// add subScene
SubScene subScene = new SubScene(robot, width, height, true, SceneAntialiasing.BALANCED);
Parent ui = createUI();
StackPane combined = new StackPane();
combined.getChildren().addAll(ui, subScene);
Scene scene = new Scene(combined, width, height);
  
   现在的问题是布局,方框将显示在左上角,而不是中间。
  
  
   您可以向组中添加翻译:
  
  public XGroup() { 
    super(); 
    getTransforms().addAll(new Translate(width/2, height/2, 0), rz, ry, rx); 
}    
  
   
     
   
  
  
  
  
   现在,您可以看到正确的深度排序渲染,并且可以访问ui按钮。
  
  
   另一个选项是添加相机。您可以删除“平移”变换,也可以“缩放”以查看更大的长方体:
  
  Parent robot = createRobot();
SubScene subScene = new SubScene(robot, width, height, true, SceneAntialiasing.BALANCED);
PerspectiveCamera camera = new PerspectiveCamera(true);
camera.setNearClip(0.01);
camera.setFarClip(100000);
camera.setTranslateZ(-400);
subScene.setCamera(camera);
  
   
     
   
  
  
  
  
   轮换
  
  
   现在,就旋转而言,如果要在长方体的当前状态上应用给定的旋转,并且与“场景”轴无关(我认为您是指三个正交的非旋转轴),则必须在应用新旋转之前考虑之前的状态。
  
  
   在这个
   
    blog post
   
   关于魔方,每个面(由9个小“立方体”组成)可以反复旋转,并且受影响的立方体可以进行之前的多次旋转。可以找到该项目
   
    here
   
   .
  
  
   在这种情况下,使用变换和仿射
   
    prepend
   
   是始终更新3D实体上的局部正交轴的关键。
  
  
   我建议:
  
  private void addRotate(XGroup node, Rotate rotate, double angle) {
    Transform newRotate = new Rotate(angle, rotate.getAxis());
    Affine affine = node.getTransforms().isEmpty() ? new Affine() : new Affine(node.getTransforms().get(0));
    affine.prepend(newRotate);
    node.getTransforms().setAll(affine);
}
  
   尽管如此,新旋转都是在场景正交轴上定义的。
  
  
   如果需要局部轴,可以从仿射矩阵中获取它们。如果你打印
   
    affine
   
   在任何时候,您都可以从列1、2和3中获取x、y、z轴:
  
  
   
     
   
  
  
  
  Affine [
     0.70710678, 0.50000000,  0.50000000, 0.0
     0.00000000, 0.70710678, -0.70710678, 0.0
    -0.70710678, 0.50000000,  0.50000000, 0.0]
  
   一、 e,x轴(蓝色)为
   
    {0.7071, 0.0, -0.7071}
   
   .
  
  
   因此,最后可以将局部轴上的旋转定义为:
  
  private void addRotate(XGroup node, Rotate rotate, double angle) {
    Affine affine = node.getTransforms().isEmpty() ? new Affine() : new Affine(node.getTransforms().get(0));
    double A11 = affine.getMxx(), A12 = affine.getMxy(), A13 = affine.getMxz(); 
    double A21 = affine.getMyx(), A22 = affine.getMyy(), A23 = affine.getMyz(); 
    double A31 = affine.getMzx(), A32 = affine.getMzy(), A33 = affine.getMzz(); 
    // rotations over local axis  
    Rotate newRotateX = new Rotate(angle, new Point3D(A11, A21, A31));
    Rotate newRotateY = new Rotate(angle, new Point3D(A12, A22, A32));
    Rotate newRotateZ = new Rotate(angle, new Point3D(A13, A23, A33));
    // apply rotation
    affine.prepend(rotate.getAxis() == Rotate.X_AXIS ? newRotateX : 
            rotate.getAxis() == Rotate.Y_AXIS ? newRotateY : newRotateZ);
    node.getTransforms().setAll(affine);
}
  
   我相信这会给你你想要的。
  
  
   这是整个修改后的代码:
  
  private final int width = 800;
private final int height = 500;
private XGroup torsoGroup;
private final double torsoX = 50;
private final double torsoY = 80;
public Parent createRobot() {
    Box torso = new Box(torsoX, torsoY, 20);
    torso.setMaterial(new PhongMaterial(Color.RED));
    Box head = new Box(20, 20, 20);
    head.setMaterial(new PhongMaterial(Color.YELLOW.darker()));
    head.setTranslateY(-torsoY / 2 -10);
    Box x = new Box(200, 2, 2);
    x.setMaterial(new PhongMaterial(Color.BLUE));
    Box y = new Box(2, 200, 2);
    y.setMaterial(new PhongMaterial(Color.BLUEVIOLET));
    Box z = new Box(2, 2, 200);
    z.setMaterial(new PhongMaterial(Color.BURLYWOOD));
    torsoGroup = new XGroup();
    torsoGroup.getChildren().addAll(torso, head, x, y, z);
    return torsoGroup;
}
public Parent createUI() {
    HBox buttonBox = new HBox();
    Button b;
    buttonBox.getChildren().add(b = new Button("Exit"));
    b.setOnAction( (ActionEvent arg0) -> { Platform.exit(); } );
    buttonBox.getChildren().add(b = new Button("pitch up"));
    b.setOnAction(new TurnAction(torsoGroup.rx, -15) );
    buttonBox.getChildren().add(b = new Button("pitch down"));
    b.setOnAction(new TurnAction(torsoGroup.rx, 15) );
    buttonBox.getChildren().add(b = new Button("Yaw left"));
    b.setOnAction(new TurnAction(torsoGroup.ry, -15) );
    buttonBox.getChildren().add(b = new Button("Yaw right"));
    b.setOnAction(new TurnAction(torsoGroup.ry, 15) );
    buttonBox.getChildren().add(b = new Button("Roll right"));
    b.setOnAction(new TurnAction(torsoGroup.rz, -15) );
    buttonBox.getChildren().add(b = new Button("Roll left"));
    b.setOnAction(new TurnAction(torsoGroup.rz, 15) );
    return buttonBox;
}
class TurnAction implements EventHandler<ActionEvent> {
    final Rotate rotate;
    double deltaAngle;
    public TurnAction(Rotate rotate, double targetAngle) {
        this.rotate = rotate;
        this.deltaAngle = targetAngle;
    }
    @Override
    public void handle(ActionEvent arg0) {
        addRotate(torsoGroup, rotate, deltaAngle);
    } 
}
private void addRotate(XGroup node, Rotate rotate, double angle) {
    Affine affine = node.getTransforms().isEmpty() ? new Affine() : new Affine(node.getTransforms().get(0));
    double A11 = affine.getMxx(), A12 = affine.getMxy(), A13 = affine.getMxz(); 
    double A21 = affine.getMyx(), A22 = affine.getMyy(), A23 = affine.getMyz(); 
    double A31 = affine.getMzx(), A32 = affine.getMzy(), A33 = affine.getMzz(); 
    Rotate newRotateX = new Rotate(angle, new Point3D(A11, A21, A31));
    Rotate newRotateY = new Rotate(angle, new Point3D(A12, A22, A32));
    Rotate newRotateZ = new Rotate(angle, new Point3D(A13, A23, A33));
    affine.prepend(rotate.getAxis() == Rotate.X_AXIS ? newRotateX : 
            rotate.getAxis() == Rotate.Y_AXIS ? newRotateY : newRotateZ);
    node.getTransforms().setAll(affine);
}
public class XGroup extends Group {
    public Rotate rx = new Rotate(0, Rotate.X_AXIS);
    public Rotate ry = new Rotate(0, Rotate.Y_AXIS);
    public Rotate rz = new Rotate(0, Rotate.Z_AXIS);
}
@Override 
public void start(Stage stage) throws Exception {
    Parent robot = createRobot();
    SubScene subScene = new SubScene(robot, width, height, true, SceneAntialiasing.BALANCED);
    PerspectiveCamera camera = new PerspectiveCamera(true);
    camera.setNearClip(0.01);
    camera.setFarClip(100000);
    camera.setTranslateZ(-400);
    subScene.setCamera(camera);
    Parent ui = createUI();
    StackPane combined = new StackPane(ui, subScene);
    combined.setStyle("-fx-background-color: linear-gradient(to bottom, cornsilk, midnightblue);");
    Scene scene = new Scene(combined, width, height);
    stage.setScene(scene);
    stage.show();
}