2013-10-06 20 views
5

Dzięki nowym funkcjom w JavaFX 8 możliwe stało się łączenie obiektów 3D z elementami sterującymi 2D interfejsu użytkownika.JavaFX 3D - Jak ustawić różne kamery dla Grupy z obiektem 3D i SubScene z kontrolkami interfejsu użytkownika?

Użyłem tego dokumentu jako instrukcji: JavaFX Tutorial, Exploring JavaFX 3D.

Więc zrobiłem ten kod:

public class CastAnalytics extends Application { 

    final Group root = new Group(); 
    final Group axisGroup = new Group(); 
    final XForm world = new XForm(); 
    final PerspectiveCamera camera = new PerspectiveCamera(true); 
    final PerspectiveCamera subSceneCamera = new PerspectiveCamera(false); 
    final XForm cameraXForm = new XForm(); 
    final XForm cameraXForm2 = new XForm(); 
    final XForm cameraXForm3 = new XForm(); 
    final double cameraDistance = 450; 
    final XForm moleculeGroup = new XForm(); 
    private Timeline timeline; 
    boolean timelinePlaying = false; 
    double CONTROL_MULTIPLIER = 0.1; 
    double SHIFT_MULTIPLIER = 0.1; 
    double ALT_MULTIPLIER = 0.5; 
    double mousePosX; 
    double mousePosY; 
    double mouseOldX; 
    double mouseOldY; 
    double mouseDeltaX; 
    double mouseDeltaY; 

    @Override 
    public void start(Stage primaryStage) throws Exception{ 
     buildScene(); 
     buildCamera(); 
     buildAxes(); 

     Scene scene = new Scene(root, 1024, 768, true); 
     scene.setFill(Color.GREY); 
     handleKeyboard(scene, world); 
     handleMouse(scene, world); 

     primaryStage.setTitle("Sample Application"); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 


     scene.setCamera(subSceneCamera); 
     scene.setCamera(camera); 
    } 

    private void buildScene() { 
     root.getChildren().add(world); 

     Label label = new Label("123"); 
     HBox hBox = new HBox(); 
     hBox.getChildren().add(label); 
     SubScene subScene = new SubScene(hBox, 200, 200); 
     subScene.setLayoutX(100); 
     subScene.setLayoutY(100); 

     root.getChildren().addAll(subScene); 
    } 

    private void buildCamera() { 
     root.getChildren().addAll(cameraXForm); 
     cameraXForm.getChildren().add(cameraXForm2); 
     cameraXForm2.getChildren().add(cameraXForm3); 
     cameraXForm3.getChildren().add(camera); 
     cameraXForm3.setRotateZ(180.0); 

     camera.setNearClip(0.1); 
     camera.setFarClip(10000.0); 
     camera.setTranslateZ(-cameraDistance); 
     cameraXForm.ry.setAngle(320.0); 
     cameraXForm.rx.setAngle(40); 
    } 

    private void buildAxes() { 
     Box box = new Box(200,200,200); 


     axisGroup.getChildren().addAll(box); 
     world.getChildren().addAll(axisGroup); 
    } 

    private void handleMouse(Scene scene, final Node root) { 
     scene.setOnMousePressed(new EventHandler<MouseEvent>() { 
      @Override public void handle(MouseEvent me) { 
       mousePosX = me.getSceneX(); 
       mousePosY = me.getSceneY(); 
       mouseOldX = me.getSceneX(); 
       mouseOldY = me.getSceneY(); 
      } 
     }); 
     scene.setOnMouseDragged(new EventHandler<MouseEvent>() { 
      @Override 
      public void handle(MouseEvent me) { 
       mouseOldX = mousePosX; 
       mouseOldY = mousePosY; 
       mousePosX = me.getSceneX(); 
       mousePosY = me.getSceneY(); 
       mouseDeltaX = (mousePosX - mouseOldX); 
       mouseDeltaY = (mousePosY - mouseOldY); 

       double modifier = 1.0; 
       double modifierFactor = 0.1; 

       if (me.isControlDown()) { 
        modifier = 0.1; 
       } 
       if (me.isShiftDown()) { 
        modifier = 10.0; 
       } 
       if (me.isPrimaryButtonDown()) { 
        cameraXForm.ry.setAngle(cameraXForm.ry.getAngle() - mouseDeltaX * modifierFactor * modifier * 2.0); // + 
        cameraXForm.rx.setAngle(cameraXForm.rx.getAngle() + mouseDeltaY * modifierFactor * modifier * 2.0); // - 
       } else if (me.isSecondaryButtonDown()) { 
        double z = camera.getTranslateZ(); 
        double newZ = z + mouseDeltaX * modifierFactor * modifier; 
        camera.setTranslateZ(newZ); 
       } else if (me.isMiddleButtonDown()) { 
        cameraXForm2.t.setX(cameraXForm2.t.getX() + mouseDeltaX * modifierFactor * modifier * 0.3); // - 
        cameraXForm2.t.setY(cameraXForm2.t.getY() + mouseDeltaY * modifierFactor * modifier * 0.3); // - 
       } 
      } 
     }); 
    } 

    private void handleKeyboard(Scene scene, final Node root) { 
     final boolean moveCamera = true; 
     scene.setOnKeyPressed(new EventHandler<KeyEvent>() { 
      @Override 
      public void handle(KeyEvent event) { 
       Duration currentTime; 
       switch (event.getCode()) { 
        case Z: 
         if (event.isShiftDown()) { 
          cameraXForm.ry.setAngle(0.0); 
          cameraXForm.rx.setAngle(0.0); 
          camera.setTranslateZ(-300.0); 
         } 
         cameraXForm2.t.setX(0.0); 
         cameraXForm2.t.setY(0.0); 
         break; 
        case X: 
         if (event.isControlDown()) { 
          if (axisGroup.isVisible()) { 
           axisGroup.setVisible(false); 
          } else { 
           axisGroup.setVisible(true); 
          } 
         } 
         break; 
        case S: 
         if (event.isControlDown()) { 
          if (moleculeGroup.isVisible()) { 
           moleculeGroup.setVisible(false); 
          } else { 
           moleculeGroup.setVisible(true); 
          } 
         } 
         break; 
        case SPACE: 
         if (timelinePlaying) { 
          timeline.pause(); 
          timelinePlaying = false; 
         } else { 
          timeline.play(); 
          timelinePlaying = true; 
         } 
         break; 
        case UP: 
         if (event.isControlDown() && event.isShiftDown()) { 
          cameraXForm2.t.setY(cameraXForm2.t.getY() - 10.0 * CONTROL_MULTIPLIER); 
         } else if (event.isAltDown() && event.isShiftDown()) { 
          cameraXForm.rx.setAngle(cameraXForm.rx.getAngle() - 10.0 * ALT_MULTIPLIER); 
         } else if (event.isControlDown()) { 
          cameraXForm2.t.setY(cameraXForm2.t.getY() - 1.0 * CONTROL_MULTIPLIER); 
         } else if (event.isAltDown()) { 
          cameraXForm.rx.setAngle(cameraXForm.rx.getAngle() - 2.0 * ALT_MULTIPLIER); 
         } else if (event.isShiftDown()) { 
          double z = camera.getTranslateZ(); 
          double newZ = z + 5.0 * SHIFT_MULTIPLIER; 
          camera.setTranslateZ(newZ); 
         } 
         break; 
        case DOWN: 
         if (event.isControlDown() && event.isShiftDown()) { 
          cameraXForm2.t.setY(cameraXForm2.t.getY() + 10.0 * CONTROL_MULTIPLIER); 
         } else if (event.isAltDown() && event.isShiftDown()) { 
          cameraXForm.rx.setAngle(cameraXForm.rx.getAngle() + 10.0 * ALT_MULTIPLIER); 
         } else if (event.isControlDown()) { 
          cameraXForm2.t.setY(cameraXForm2.t.getY() + 1.0 * CONTROL_MULTIPLIER); 
         } else if (event.isAltDown()) { 
          cameraXForm.rx.setAngle(cameraXForm.rx.getAngle() + 2.0 * ALT_MULTIPLIER); 
         } else if (event.isShiftDown()) { 
          double z = camera.getTranslateZ(); 
          double newZ = z - 5.0 * SHIFT_MULTIPLIER; 
          camera.setTranslateZ(newZ); 
         } 
         break; 
        case RIGHT: 
         if (event.isControlDown() && event.isShiftDown()) { 
          cameraXForm2.t.setX(cameraXForm2.t.getX() + 10.0 * CONTROL_MULTIPLIER); 
         } else if (event.isAltDown() && event.isShiftDown()) { 
          cameraXForm.ry.setAngle(cameraXForm.ry.getAngle() - 10.0 * ALT_MULTIPLIER); 
         } else if (event.isControlDown()) { 
          cameraXForm2.t.setX(cameraXForm2.t.getX() + 1.0 * CONTROL_MULTIPLIER); 
         } else if (event.isAltDown()) { 
          cameraXForm.ry.setAngle(cameraXForm.ry.getAngle() - 2.0 * ALT_MULTIPLIER); 
         } 
         break; 
        case LEFT: 
         if (event.isControlDown() && event.isShiftDown()) { 
          cameraXForm2.t.setX(cameraXForm2.t.getX() - 10.0 * CONTROL_MULTIPLIER); 
         } else if (event.isAltDown() && event.isShiftDown()) { 
          cameraXForm.ry.setAngle(cameraXForm.ry.getAngle() + 10.0 * ALT_MULTIPLIER); // - 
         } else if (event.isControlDown()) { 
          cameraXForm2.t.setX(cameraXForm2.t.getX() - 1.0 * CONTROL_MULTIPLIER); 
         } else if (event.isAltDown()) { 
          cameraXForm.ry.setAngle(cameraXForm.ry.getAngle() + 2.0 * ALT_MULTIPLIER); // - 
         } 
         break; 
       } 
      } 
     }); 
    } 



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

Ale te wynik nie jest to, czego się spodziewałem. Chciałem mieć Pane do kontroli UI powyżej obiektu 3D, ale co mam to:

enter image description here

Co robię źle?

Odpowiedz

0

Problemem jest tutaj:

scene.setCamera(subSceneCamera); 
    scene.setCamera(camera); 

Można ustawić tylko jedną kamerę w sceny (lub SubScene). Musisz ustawić drugą kamerę w SubScene. Spróbuj czegoś takiego:

@Override 
public void start(Stage primaryStage) throws Exception{ 
    ... 
    primaryStage.show(); 
    scene.setCamera(camera); 
} 
private void buildScene() { 
    ... 
    subScene.setLayoutX(100); 
    subScene.setLayoutY(100); 
    subScene.setCamera(subSceneCamera); 
    root.getChildren().addAll(subScene); 
} 
+1

Próbowałem ten wariant też. I właśnie spróbowałem tego ponownie. Niestety, ten sam wynik. – Eugene

+0

Istnieje działająca podscena w aplikacji Ineractive Mesh FXTuxCube. Próbowałem przenieść to do MoleculaSampleApp z Oracle, ale jak dotąd nie udało się. Niezależnie od tego, jak starałem się właściwie obrócić kamerę podsceny, nadal wyglądało to jak na powyższym zrzucie ekranu. Ale możesz po prostu spróbować dowiedzieć się, co zrobił sierpień w TuxCube. Mam nadzieję, że trochę pomaga. – ajeh

+2

Z tego, co podłożyłem w Tux Cube, używa on tylko 1 kamery zarówno do sceny, jak i subsceny, i stosuje transformację do głównej sceny zamiast do kamery. Wydaje mi się, że Oracle bardzo nie przysłużył się uczącym się JavaFX 3D poprzez zwolnienie MoleculeSampleApp, który ukrył transformację w ich własnej klasie Xform. – ajeh

1

Z tego co rozumiem z (ograniczona) testów I zrobili, są dwie opcje:

  1. Ustaw aparat na sub-sceny i dodać, że sub -scene do katalogu głównego. Będziesz używał tylko jednej kamery. Twój świat będzie musiał być oddzielną grupą, a latanie/obracanie widoku kamery będzie musiało zostać dokonane poprzez przekształcenie grupy światowej.

  2. Zgłoś błąd w aplikacji JavaFX jira.

Nie udało mi się użyć oddzielnego aparatu jako kamery do sceny dodatkowej. Żadne transformacje zastosowane w kamerze ani sama scena podrzędna nigdy nie obróciły sceny dodatkowej od domyślnej pozycji podobnej do tej na zrzucie ekranu. W tym momencie, gdy Oracle nie udostępnia żadnej dokumentacji podstropowej, możemy tylko poczekać, aż wyjdą czyste i wypełnić luki. Do tego czasu możemy uznać obsługę podscenową w JavaFX 3D za uszkodzoną.

0

Oto Rozwiązanie

public class rotate3Dwithpanel extends Application 
{ 
    private double mouseOldX, mouseOldY = 0; 
    private Rotate rotateX = new Rotate(0, Rotate.X_AXIS); 
    private Rotate rotateY = new Rotate(0, Rotate.Y_AXIS); 
    private Rotate rotateZ = new Rotate(0, Rotate.Z_AXIS); 

    @Override 
    public void start(Stage stage) throws Exception 
    { 
     final PhongMaterial redMaterial = new PhongMaterial(); 
     redMaterial.setSpecularColor(Color.ORANGE); 
     redMaterial.setDiffuseColor(Color.RED); 

     Box myBox = new Box(100, 100, 100); 
     myBox.setTranslateX(400); 
     myBox.setTranslateY(300); 
     myBox.setTranslateZ(400); 
     myBox.setMaterial(redMaterial); 

     Rectangle rectangle = new Rectangle(); 
     rectangle.setX(200); 
     rectangle.setY(600); 
     rectangle.setWidth(200); 
     rectangle.setHeight(100); 
     rectangle.setFill(Color.GREY); 

     // to Set pivot points 
     rotateX.setPivotX(400); 
     rotateX.setPivotY(300); 
     rotateX.setPivotZ(400); 

     rotateY.setPivotX(400); 
     rotateY.setPivotY(300); 
     rotateY.setPivotZ(400); 

     rotateZ.setPivotX(400); 
     rotateZ.setPivotY(300); 
     rotateZ.setPivotZ(400); 


     // initialize the camera 
     PerspectiveCamera camera = new PerspectiveCamera(false); 
     camera.getTransforms().addAll (rotateX, rotateY, new Translate(0, 0, 0)); 

     Group root = new Group(); 
     Group subRoot = new Group(); 

     root.getChildren().add(rectangle); 

     Scene scene = new Scene(root, 1000, 1000, true); 
     SubScene subScene = new SubScene(subRoot, 800, 800, true, SceneAntialiasing.BALANCED); 

     subScene.setCamera(camera); 
     subRoot.getChildren().add(myBox); 
     root.getChildren().add(subScene); 

     // events for rotation 
     rectangle.setOnMousePressed(event -> { 
      mouseOldX = event.getSceneX(); 
      mouseOldY = event.getSceneY(); 
     }); 

     rectangle.setOnMouseDragged(event -> { 
      if(event.isPrimaryButtonDown()) 
      { 
       rotateX.setAngle(rotateX.getAngle() - (event.getSceneY() - mouseOldY)); 
       rotateY.setAngle(rotateY.getAngle() + (event.getSceneX() - mouseOldX)); 
       mouseOldX = event.getSceneX(); 
       mouseOldY = event.getSceneY(); 
      } 
     }); 

     stage.setTitle("JavaFX 3D Object"); 
     stage.setScene(scene); 
     stage.show(); 
    } 

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

}