2015-02-25 10 views
6

Mentre stavo creando il mio primo gioco 3D in JavaFX - dove si sarebbe in grado di assemblare navi da parti usando il mouse. Questo presenta un problema dal momento che JAVAFX sembra non avere metodi nativi che funzionano per convertire le coordinate 2D della schermata PerspectiveCamera nello spazio 3D della scena.JavaFX Spostamento di oggetti 3D con il mouse su un piano virtuale

Ecco una rappresentazione di ciò che sto cercando di ottenere. Un blocco spostato dal mouse dovrebbe spostarsi su un piano immaginario che è sempre ruotato di 90 rispetto alla telecamera: Representation Ho provato a risolvere il problema con la trigonometria senza molto successo. Non ho allegato uno snippet di codice perché sto cercando una soluzione matematica più generica, ma la fornirò se richiesta.

Tutto l'aiuto sarebbe apprezzato!

risultato desiderato: Before

After

+0

non fa parte della pubbl ic api, ma puoi provare a usare CameraHelper .. ha 3 metodi, quello che vuoi è **.pickProjectionPlane (camera, x, y) – jdub1581

risposta

7

Come @ jdub1581 sottolinea, la Camera è la chiave per legare il movimento del mouse con i tuoi oggetti 3D sulla scena.

Per gli avvii, siamo a conoscenza dell'API pubblica PickResult, che ci consente di selezionare un oggetto 3D con il mouse, sulla base di alcune tecniche di ray tracing eseguite dalla posizione della telecamera.

Ma una volta che abbiamo un oggetto, spostarlo è un problema diverso.

Alla ricerca di una soluzione per questo problema (spostando oggetti 3D con un mouse 2D nello spazio 3D) qualche tempo fa, ho trovato la classe Camera3D nel progetto Toys sul repository OpenJFX.

Ha un metodo promettente chiamato unProjectDirection:

/* 
* 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) { 
} 

Poiché hai chiesto spiegazione matematica, questo metodo utilizza la trigonometria che stavi cercando. Questo vi darà un vettore 3D sulla base di (x, y) coordinate del mouse, utilizzando un Vec3d classe privata (che possiamo sostituire con pubblico Point3D):

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); 

vengono applicate Alcuni ulteriori trasformazioni per ottenere un vettore normalizzato in coordinate della scena.

Il passaggio successivo trasformerà questo vettore normalizzato in coordinate reali, utilizzando semplicemente la distanza dalla telecamera all'oggetto, indicata sul risultato del prelievo e trasformando la posizione dell'oggetto.

In sostanza, questo frammento di codice illustra l'intero processo di trascinare un oggetto:

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(); 
    }); 

E questo è un lavoro completo esempio di base:

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); 
    } 
} 

che vi permetterà di raccogliere e trascinando il sfera sulla scena:

dragging 3d

+0

Wow, ottima risposta! Questo e 'esattamente quello che stavo cercando! : D Molte grazie. –

+0

Grazie. Sicuramente dovrai capire alcune cose per te, ma è un punto di partenza. Nel caso in cui ne abbiate bisogno, date un'occhiata a questo [repository] (https://github.com/FXyz/FXyz), stiamo lavorando su funzionalità avanzate per JavaFX 3D. –

+0

Impressionante, sarò sicuro di dare un'occhiata. –

Problemi correlati