2015-07-13 165 views
1

我的問題是:JavaFX的3D旋轉

  1. 下面的代碼是基於從Oracle教程網站的「MolecularSampleApp」,但非常簡單。它只顯示一個盒子和一個紅色的球體用於定位。旋轉的順序圍繞x軸,然後是y軸,最後是z軸。在旋轉之後顯然是在隨着旋轉而旋轉的座標軸中完成的。因此,當用戶使用鼠標旋轉攝像機視圖時,這是非常不直觀的,因爲在圍繞垂直屏幕軸旋轉後,旋轉行爲會發生變化(因爲水平軸也將被旋轉)。 請使用下面的代碼或MolecularSampleApp嘗試它 - 它具有相同的不自然感覺。有沒有簡單的方法來克服這個問題?
  2. 但我甚至不明白的是mousePressed-code執行時的行爲:在這裏,相機總是在固定系統中旋轉!儘管其基本上相同的代碼(除了旋轉角度當然不在這裏累積),軸不會與相機一起旋轉。任何人都知道這可能如何?
package trafotest; 

import javafx.application.Application; 
import static javafx.application.Application.launch; 
import javafx.scene.DepthTest; 
import javafx.scene.Group; 
import javafx.scene.PerspectiveCamera; 
import javafx.scene.Scene; 
import javafx.scene.input.MouseEvent; 
import javafx.scene.paint.Color; 
import javafx.scene.paint.PhongMaterial; 
import javafx.scene.shape.Box; 
import javafx.scene.shape.Sphere; 
import javafx.scene.transform.Rotate; 
import javafx.scene.transform.Translate; 
import javafx.stage.Stage; 

public class TrafoTest extends Application { 

    final Group root = new Group(); 
    final XformWorld world = new XformWorld(); 
    final PerspectiveCamera camera = new PerspectiveCamera(true); 
    final XformCamera cameraXform = new XformCamera(); 
    private static final double CAMERA_INITIAL_DISTANCE = -1000; 
    private static final double CAMERA_NEAR_CLIP = 0.1; 
    private static final double CAMERA_FAR_CLIP = 10000.0; 
    double mousePosX, mousePosY, mouseOldX, mouseOldY, mouseDeltaX, mouseDeltaY; 

    @Override 
    public void start(Stage primaryStage) { 
     root.getChildren().add(world); 
     root.setDepthTest(DepthTest.ENABLE); 
     buildCamera(); 
     buildBodySystem(); 
     Scene scene = new Scene(root, 800, 600, true); 
     scene.setFill(Color.GREY); 
     handleMouse(scene); 
     primaryStage.setTitle("Transformationen"); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
     scene.setCamera(camera); 
    } 

    private void buildCamera() { 
     root.getChildren().add(cameraXform); 
     cameraXform.getChildren().add(camera); 
     camera.setNearClip(CAMERA_NEAR_CLIP); 
     camera.setFarClip(CAMERA_FAR_CLIP); 
     camera.setTranslateZ(CAMERA_INITIAL_DISTANCE); 
    } 

    private void buildBodySystem() { 
     PhongMaterial whiteMaterial = new PhongMaterial(); 
     whiteMaterial.setDiffuseColor(Color.WHITE); 
     whiteMaterial.setSpecularColor(Color.LIGHTBLUE); 
     Box box = new Box(400, 200, 100); 
     box.setMaterial(whiteMaterial); 
     PhongMaterial redMaterial = new PhongMaterial(); 
     redMaterial.setDiffuseColor(Color.DARKRED); 
     redMaterial.setSpecularColor(Color.RED); 
     Sphere sphere = new Sphere(5); 
     sphere.setMaterial(redMaterial); 
     sphere.setTranslateZ(-50.0); 
     world.getChildren().addAll(box); 
     world.getChildren().addAll(sphere); 
    } 

    private void handleMouse(Scene scene) { 
     scene.setOnMousePressed((MouseEvent me) -> { 
      mousePosX = me.getSceneX(); 
      mousePosY = me.getSceneY(); 
      mouseOldX = me.getSceneX(); 
      mouseOldY = me.getSceneY(); 
      // this is done after clicking and the rotations are apearently 
      // performed in coordinates that are NOT rotated with the camera. 
      // (pls activate the two lines below for clicking) 
      //cameraXform.rx.setAngle(-90.0); 
      //cameraXform.ry.setAngle(180.0); 
     }); 
     scene.setOnMouseDragged((MouseEvent me) -> { 
      mouseOldX = mousePosX; 
      mouseOldY = mousePosY; 
      mousePosX = me.getSceneX(); 
      mousePosY = me.getSceneY(); 
      mouseDeltaX = (mousePosX - mouseOldX); 
      mouseDeltaY = (mousePosY - mouseOldY); 
      if (me.isPrimaryButtonDown()) { 
       // this is done when the mouse is dragged and each rotation is 
       // performed in coordinates, that are rotated with the camera.    
       cameraXform.ry.setAngle(cameraXform.ry.getAngle() + mouseDeltaX * 0.2); 
       cameraXform.rx.setAngle(cameraXform.rx.getAngle() - mouseDeltaY * 0.2);     
      } 
     }); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 

} 

class XformWorld extends Group { 

    final Translate t = new Translate(0.0, 0.0, 0.0); 
    final Rotate rx = new Rotate(0, 0, 0, 0, Rotate.X_AXIS); 
    final Rotate ry = new Rotate(0, 0, 0, 0, Rotate.Y_AXIS); 
    final Rotate rz = new Rotate(0, 0, 0, 0, Rotate.Z_AXIS); 

    public XformWorld() { 
     super(); 
     this.getTransforms().addAll(t, rx, ry, rz); 
    } 

} 

class XformCamera extends Group { 

    final Translate t = new Translate(0.0, 0.0, 0.0); 
    final Rotate rx = new Rotate(0, 0, 0, 0, Rotate.X_AXIS); 
    final Rotate ry = new Rotate(0, 0, 0, 0, Rotate.Y_AXIS); 
    final Rotate rz = new Rotate(0, 0, 0, 0, Rotate.Z_AXIS); 

    public XformCamera() { 
     super(); 
     this.getTransforms().addAll(t, rx, ry, rz); 
    } 

} 
+0

歡迎StackOverflow上。請閱讀此http://stackoverflow.com/help/how-to-ask以瞭解如何提出正確的問題。你應該儘量隔離代碼,以激勵他人閱讀它。 –

回答

7

我發現對我的作品,以防萬一別人有興趣上的解決方案:

package trafotest; 

import javafx.application.Application; 
import static javafx.application.Application.launch; 
import javafx.geometry.Point3D; 
import javafx.scene.DepthTest; 
import javafx.scene.Group; 
import javafx.scene.PerspectiveCamera; 
import javafx.scene.Scene; 
import javafx.scene.input.MouseEvent; 
import javafx.scene.paint.Color; 
import javafx.scene.paint.PhongMaterial; 
import javafx.scene.shape.Box; 
import javafx.scene.shape.Sphere; 
import javafx.scene.transform.Rotate; 
import javafx.scene.transform.Transform; 
import javafx.scene.transform.Translate; 
import javafx.stage.Stage; 

public class TrafoTest extends Application { 
    final Group root = new Group(); 
    final XformWorld world = new XformWorld(); 
    final PerspectiveCamera camera = new PerspectiveCamera(true); 
    final XformCamera cameraXform = new XformCamera(); 
    private static final double CAMERA_INITIAL_DISTANCE = -1000; 
    private static final double CAMERA_NEAR_CLIP = 0.1; 
    private static final double CAMERA_FAR_CLIP = 10000.0; 
    double mousePosX, mousePosY, mouseOldX, mouseOldY, mouseDeltaX, mouseDeltaY; 
    double mouseFactorX, mouseFactorY; 

    @Override 
    public void start(Stage primaryStage) { 
     root.getChildren().add(world); 
     root.setDepthTest(DepthTest.ENABLE); 
     buildCamera(); 
     buildBodySystem(); 
     Scene scene = new Scene(root, 800, 600, true); 
     scene.setFill(Color.GREY); 
     handleMouse(scene); 
     primaryStage.setTitle("TrafoTest"); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
     scene.setCamera(camera); 
     mouseFactorX = 180.0/scene.getWidth(); 
     mouseFactorY = 180.0/scene.getHeight(); 
    } 

    private void buildCamera() { 
     root.getChildren().add(cameraXform); 
     cameraXform.getChildren().add(camera); 
     camera.setNearClip(CAMERA_NEAR_CLIP); 
     camera.setFarClip(CAMERA_FAR_CLIP); 
     camera.setTranslateZ(CAMERA_INITIAL_DISTANCE); 
    } 

    private void buildBodySystem() { 
     PhongMaterial whiteMaterial = new PhongMaterial(); 
     whiteMaterial.setDiffuseColor(Color.WHITE); 
     whiteMaterial.setSpecularColor(Color.LIGHTBLUE); 
     Box box = new Box(400, 200, 100); 
     box.setMaterial(whiteMaterial); 
     PhongMaterial redMaterial = new PhongMaterial(); 
     redMaterial.setDiffuseColor(Color.DARKRED); 
     redMaterial.setSpecularColor(Color.RED); 
     Sphere sphere = new Sphere(5); 
     sphere.setMaterial(redMaterial); 
     sphere.setTranslateX(200.0); 
     sphere.setTranslateY(-100.0); 
     sphere.setTranslateZ(-50.0); 
     world.getChildren().addAll(box); 
     world.getChildren().addAll(sphere); 
    } 

    private void handleMouse(Scene scene) { 
     scene.setOnMousePressed((MouseEvent me) -> { 
      mousePosX = me.getSceneX(); 
      mousePosY = me.getSceneY(); 
      mouseOldX = me.getSceneX(); 
      mouseOldY = me.getSceneY(); 
     }); 
     scene.setOnMouseDragged((MouseEvent me) -> { 
      mouseOldX = mousePosX; 
      mouseOldY = mousePosY; 
      mousePosX = me.getSceneX(); 
      mousePosY = me.getSceneY(); 
      mouseDeltaX = (mousePosX - mouseOldX); 
      mouseDeltaY = (mousePosY - mouseOldY); 
      if (me.isPrimaryButtonDown()) { 
       cameraXform.ry(mouseDeltaX * 180.0/scene.getWidth()); 
       cameraXform.rx(-mouseDeltaY * 180.0/scene.getHeight()); 
      } else if (me.isSecondaryButtonDown()) { 
       camera.setTranslateZ(camera.getTranslateZ() + mouseDeltaY); 
      } 
     }); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 

} 

class XformWorld extends Group { 
    final Translate t = new Translate(0.0, 0.0, 0.0); 
    final Rotate rx = new Rotate(0, 0, 0, 0, Rotate.X_AXIS); 
    final Rotate ry = new Rotate(0, 0, 0, 0, Rotate.Y_AXIS); 
    final Rotate rz = new Rotate(0, 0, 0, 0, Rotate.Z_AXIS); 

    public XformWorld() { 
     super(); 
     this.getTransforms().addAll(t, rx, ry, rz); 
    } 
} 

class XformCamera extends Group { 
    Point3D px = new Point3D(1.0, 0.0, 0.0); 
    Point3D py = new Point3D(0.0, 1.0, 0.0); 
    Rotate r; 
    Transform t = new Rotate(); 

    public XformCamera() { 
     super(); 
    } 

    public void rx(double angle) { 
     r = new Rotate(angle, px); 
     this.t = t.createConcatenation(r); 
     this.getTransforms().clear(); 
     this.getTransforms().addAll(t); 
    } 

    public void ry(double angle) { 
     r = new Rotate(angle, py); 
     this.t = t.createConcatenation(r); 
     this.getTransforms().clear(); 
     this.getTransforms().addAll(t); 
    } 

} 
+0

非常感謝你。它導致我在這裏解決我自己的問題:https://stackoverflow.com/questions/46176489/javafx-3d-rotation-around-scene-fixed-axes –