2015-02-25 21 views
6

Als ich mein erstes 3D-Spiel in JavaFX erstellte - wo Sie Schiffe aus Teilen mit der Maus zusammenbauen könnten. Dies stellt ein Problem dar, da JAVAFX keine systemeigenen Metoden zu verwenden scheint, die zum Konvertieren der 2D-Koordinaten der 2D-Perspektive von PerspectiveCamera in den 3D-Raum der Szene dienen.JavaFX Bewegen von 3D-Objekten mit der Maus auf einer virtuellen Ebene

Hier ist eine Darstellung dessen, was ich versuche zu erreichen. Ein mit der Maus bewegter Block sollte sich auf einer imaginären Ebene bewegen, die immer um 90 gegenüber der Kamera gedreht ist: Representation Ich habe versucht, das Problem mit Trigonometrie ohne viel Erfolg zu lösen. Ich habe kein Code-Snippet angehängt, da ich nach einer allgemeineren mathematischen Lösung suche, diese aber auf Anfrage bereitstellen werde.

Alle Hilfe wäre willkommen!

Wunschergebnis: Before

After

+0

Es ist nicht Teil der publ ic api, aber Sie könnten versuchen CameraHelper zu verwenden. hat 3 Methoden, die, die Sie wollen, ist **.PickProjectionPlane (Kamera, x, y) – jdub1581

Antwort

7

Wie @ jdub1581 weist darauf hin, die Camera ist der Schlüssel Mausbewegung mit 3D objets auf die Szene zu binden.

Für Startert, wir wissen über öffentliche API PickResult, die uns ermöglicht, ein 3D-Objekt mit der Maus, basierend auf Raytracing-Techniken aus der Kameraposition durchgeführt auswählen.

Aber sobald wir ein Objekt haben, ist das Verschieben ein anderes Problem.

Auf der Suche nach einer Lösung für dieses Problem (Verschieben von 3D-Objekten mit einer 2D-Maus im 3D-Raum) vor einer Weile fand ich die Camera3D Klasse im Toys-Projekt auf dem OpenJFX-Repository.

Es hat eine versprechend Methode unProjectDirection genannt:

/* 
* returns 3D direction from the Camera position to the mouse 
* in the Scene space 
*/ 

public Vec3d unProjectDirection(double sceneX, double sceneY, 
           double sWidth, double sHeight) { 
} 

Da Sie für mathematische Erklärung gebeten, diese Methode verwendet die Trigonometrie Sie suchen. Dadurch erhalten Sie einen 3D-Vektor auf Basis von (x, y) Mauskoordinaten, eine private Vec3d-Klasse (die wir mit öffentlichen Point3D ersetzen kann):

double tanOfHalfFOV = Math.tan(Math.toRadians(camera.getFieldOfView()) * 0.5f); 
Vec3d vMouse = new Vec3d(tanOfHalfFOV*(2*sceneX/sWidth-1), tanOfHalfFOV*(2*sceneY/sWidth-sHeight/sWidth), 1); 

Einige weitere Transformationen angewendet werden einen normalisierten Vektor erhalten in Szenenkoordinaten.

Der nächste Schritt wird diesen normalisierten Vektor in echte Koordinaten umwandeln, wobei nur der Abstand von der Kamera zum Objekt verwendet wird, der auf dem Pick-Ergebnis angegeben ist, und die Objektposition transformiert wird.

Grundsätzlich ist dieser Code-Snippet beschreibt den gesamten Prozess ein Objekt ziehen:

scene.setOnMousePressed((MouseEvent me) -> { 
     vecIni = unProjectDirection(me.getSceneX(), me.getSceneY(), 
        scene.getWidth(),scene.getHeight()); 
     distance=me.getPickResult().getIntersectedDistance();   
    }); 

    scene.setOnMouseDragged((MouseEvent me) -> { 
     vecPos = unProjectDirection(mousePosX, mousePosY, 
       scene.getWidth(),scene.getHeight()); 
     Point3D p=vecPos.subtract(vecIni).multiply(distance); 
     node.getTransforms().add(new Translate(p.getX(),p.getY(),p.getZ())); 
     vecIni=vecPos; 
     distance=me.getPickResult().getIntersectedDistance(); 
    }); 

Und das ist ein volles Arbeitsgrund Beispiel:

public class Drag3DObject extends Application { 

    private final Group root = new Group(); 
    private PerspectiveCamera camera; 
    private final double sceneWidth = 800; 
    private final double sceneHeight = 600; 

    private double mousePosX; 
    private double mousePosY; 
    private double mouseOldX; 
    private double mouseOldY; 
    private final Rotate rotateX = new Rotate(-20, Rotate.X_AXIS); 
    private final Rotate rotateY = new Rotate(-20, Rotate.Y_AXIS); 

    private volatile boolean isPicking=false; 
    private Point3D vecIni, vecPos; 
    private double distance; 
    private Sphere s; 

    @Override 
    public void start(Stage stage) { 
     Box floor = new Box(1500, 10, 1500); 
     floor.setMaterial(new PhongMaterial(Color.GRAY)); 
     floor.setTranslateY(150); 
     root.getChildren().add(floor); 

     Sphere sphere = new Sphere(150); 
     sphere.setMaterial(new PhongMaterial(Color.RED)); 
     sphere.setTranslateY(-5); 
     root.getChildren().add(sphere); 

     Scene scene = new Scene(root, sceneWidth, sceneHeight, true, SceneAntialiasing.BALANCED); 
     scene.setFill(Color.web("3d3d3d")); 

     camera = new PerspectiveCamera(true); 
     camera.setVerticalFieldOfView(false); 

     camera.setNearClip(0.1); 
     camera.setFarClip(100000.0); 
     camera.getTransforms().addAll (rotateX, rotateY, new Translate(0, 0, -3000)); 

     PointLight light = new PointLight(Color.GAINSBORO); 
     root.getChildren().add(light); 
     root.getChildren().add(new AmbientLight(Color.WHITE)); 
     scene.setCamera(camera); 

     scene.setOnMousePressed((MouseEvent me) -> { 
      mousePosX = me.getSceneX(); 
      mousePosY = me.getSceneY(); 
      PickResult pr = me.getPickResult(); 
      if(pr!=null && pr.getIntersectedNode() != null && pr.getIntersectedNode() instanceof Sphere){ 
       distance=pr.getIntersectedDistance(); 
       s = (Sphere) pr.getIntersectedNode(); 
       isPicking=true; 
       vecIni = unProjectDirection(mousePosX, mousePosY, scene.getWidth(),scene.getHeight()); 
      } 
     }); 
     scene.setOnMouseDragged((MouseEvent me) -> { 
      mousePosX = me.getSceneX(); 
      mousePosY = me.getSceneY(); 
      if(isPicking){ 
       vecPos = unProjectDirection(mousePosX, mousePosY, scene.getWidth(),scene.getHeight()); 
       Point3D p=vecPos.subtract(vecIni).multiply(distance); 
       s.getTransforms().add(new Translate(p.getX(),p.getY(),p.getZ())); 
       vecIni=vecPos; 
       PickResult pr = me.getPickResult(); 
       if(pr!=null && pr.getIntersectedNode() != null && pr.getIntersectedNode()==s){ 
        distance=pr.getIntersectedDistance(); 
       } else { 
        isPicking=false; 
       } 
      } else { 
       rotateX.setAngle(rotateX.getAngle()-(mousePosY - mouseOldY)); 
       rotateY.setAngle(rotateY.getAngle()+(mousePosX - mouseOldX)); 
       mouseOldX = mousePosX; 
       mouseOldY = mousePosY; 
      } 
     }); 
     scene.setOnMouseReleased((MouseEvent me)->{ 
      if(isPicking){ 
       isPicking=false; 
      } 
     }); 

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

    /* 
    From fx83dfeatures.Camera3D 
    http://hg.openjdk.java.net/openjfx/8u-dev/rt/file/5d371a34ddf1/apps/toys/FX8-3DFeatures/src/fx83dfeatures/Camera3D.java 
    */ 
    public Point3D unProjectDirection(double sceneX, double sceneY, double sWidth, double sHeight) { 
     double tanHFov = Math.tan(Math.toRadians(camera.getFieldOfView()) * 0.5f); 
     Point3D vMouse = new Point3D(tanHFov*(2*sceneX/sWidth-1), tanHFov*(2*sceneY/sWidth-sHeight/sWidth), 1); 

     Point3D result = localToSceneDirection(vMouse); 
     return result.normalize(); 
    } 

    public Point3D localToScene(Point3D pt) { 
     Point3D res = camera.localToParentTransformProperty().get().transform(pt); 
     if (camera.getParent() != null) { 
      res = camera.getParent().localToSceneTransformProperty().get().transform(res); 
     } 
     return res; 
    } 

    public Point3D localToSceneDirection(Point3D dir) { 
     Point3D res = localToScene(dir); 
     return res.subtract(localToScene(new Point3D(0, 0, 0))); 
    } 

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

Dass Sie Kommissionierung und Ziehen ermöglicht es die Kugel auf der Szene:

dragging 3d

+0

Wow, tolle Antwort! Genau das habe ich gesucht! : D Vielen Dank. –

+0

Danke. Sicher werden Sie einige Dinge für sich selbst herausfinden müssen, aber es ist ein Ausgangspunkt. Falls Sie es benötigen, schauen Sie sich dieses [repository] (https://github.com/FXyz/FXyz) an, wir arbeiten an erweiterten Funktionen für JavaFX 3D. –

+0

Super, ich werde sicher sein, es zu überprüfen. –

Verwandte Themen