Estoy intentando crear una subescena 3D con objetos etiquetados usando Objetos de etiqueta en una superposición 2D. He visto preguntas similares a las mías sobre este tema, y todas apuntan al uso del método Node.localToScene en el nodo que se va a etiquetar en el espacio 3D. Pero esto no parece funcionar para mi caso. Tomé un código de ejemplo del ejemplo de FXyz FloatingLabels aquí:
Los objetos Label deben tener sus posiciones actualizadas a medida que se modifica la escena 3D, lo cual he hecho, pero cuando imprimo las coordenadas devueltas por el método Node.localToScene, son demasiado grandes para estar dentro de la escena de la aplicación, y por lo que las etiquetas nunca son visibles en la escena. Escribí un programa de ejemplo que ilustra el problema, configurado de manera muy similar al código de muestra de FXyz, pero creé un objeto SubScene adicional para contener los objetos SubScene 2D y 3D para colocarlos en una ventana de aplicación más grande con control deslizante. control S. La escena 3D usa una cámara de perspectiva y muestra una gran esfera con esferas de colores a lo largo de los ejes x/y/z, y algunas pequeñas protuberancias adicionales en la superficie como referencia:
import javafx.application.Application; import javafx.application.Platform; import javafx.scene.Group; import javafx.scene.Node; import javafx.scene.PerspectiveCamera; import javafx.scene.SubScene; import javafx.scene.Scene; import javafx.scene.SceneAntialiasing; import javafx.scene.AmbientLight; import javafx.scene.PointLight; import javafx.scene.control.Label; import javafx.scene.control.Slider; import javafx.scene.control.ToolBar; import javafx.scene.layout.GridPane; import javafx.scene.layout.StackPane; import javafx.scene.layout.Priority; import javafx.scene.shape.Sphere; import javafx.scene.paint.Color; import javafx.scene.paint.PhongMaterial; import javafx.scene.transform.Rotate; import javafx.scene.transform.Translate; import javafx.stage.Stage; import javafx.geometry.Point3D; import java.util.Map; import java.util.HashMap; public class LabelTest extends Application { private Map<Node, Label> nodeToLabelMap; @Override public void start (Stage stage) { // Create main scene graph var objects3d = new Group(); Rotate xRotate = new Rotate (0, 0, 0, 0, Rotate.X_AXIS); Rotate yRotate = new Rotate (0, 0, 0, 0, Rotate.Y_AXIS); objects3d.getTransforms().addAll ( xRotate, yRotate ); var root3d = new Group(); root3d.getChildren().add (objects3d); var camera = new PerspectiveCamera (true); camera.setTranslateZ (-25); var scene3d = new SubScene (root3d, 500, 500, true, SceneAntialiasing.BALANCED); scene3d.setFill (Color.rgb (20, 20, 80)); scene3d.setCamera (camera); var sceneRoot = new Group (scene3d); var objects2d = new Group(); sceneRoot.getChildren().add (objects2d); var viewScene = new SubScene (sceneRoot, 500, 500); scene3d.widthProperty().bind (viewScene.widthProperty()); scene3d.heightProperty().bind (viewScene.heightProperty()); // Add lights and objects var ambient = new AmbientLight (Color.color (0.7, 0.7, 0.7)); var point = new PointLight (Color.color (0.3, 0.3, 0.3)); point.setTranslateX (-25); point.setTranslateY (-25); point.setTranslateZ (-50); root3d.getChildren().addAll (ambient, point); var globe = new Sphere (5); globe.setMaterial (new PhongMaterial (Color.color (0.3, 0.3, 0.3))); var xSphere = new Sphere (0.5); xSphere.setMaterial (new PhongMaterial (Color.RED)); xSphere.setTranslateX (5); var ySphere = new Sphere (0.5); ySphere.setMaterial (new PhongMaterial (Color.GREEN)); ySphere.setTranslateY (5); var zSphere = new Sphere (0.5); zSphere.setMaterial (new PhongMaterial (Color.BLUE)); zSphere.setTranslateZ (5); objects3d.getChildren().addAll (globe, xSphere, ySphere, zSphere); var nubMaterial = new PhongMaterial (Color.color (0.2, 0.2, 0.2)); for (int i = 0; i < 200; i++) { var nub = new Sphere (0.125); nub.setMaterial (nubMaterial); var phi = 2*Math.PI*Math.random(); var theta = Math.acos (2*Math.random() - 1); var z = -5 * Math.sin (theta) * Math.cos (phi); var x = 5 * Math.sin (theta) * Math.sin (phi); var y = -5 * Math.cos (theta); nub.setTranslateX (x); nub.setTranslateY (y); nub.setTranslateZ (z); objects3d.getChildren().add (nub); } // for // Add labels var xLabel = new Label ("X axis"); xLabel.setTextFill (Color.RED); var yLabel = new Label ("Y axis"); yLabel.setTextFill (Color.GREEN); var zLabel = new Label ("Z axis"); zLabel.setTextFill (Color.BLUE); objects2d.getChildren().addAll (xLabel, yLabel, zLabel); nodeToLabelMap = new HashMap<>(); nodeToLabelMap.put (xSphere, xLabel); nodeToLabelMap.put (ySphere, yLabel); nodeToLabelMap.put (zSphere, zLabel); xRotate.angleProperty().addListener ((obs, oldVal, newVal) -> updateLabels()); yRotate.angleProperty().addListener ((obs, oldVal, newVal) -> updateLabels()); camera.translateZProperty().addListener ((obs, oldVal, newVal) -> updateLabels()); Platform.runLater (() -> updateLabels()); // Create main pane var gridPane = new GridPane(); var stackPane = new StackPane (viewScene); viewScene.heightProperty().bind (stackPane.heightProperty()); viewScene.widthProperty().bind (stackPane.widthProperty()); viewScene.setManaged (false); gridPane.add (stackPane, 0, 0); gridPane.setVgrow (stackPane, Priority.ALWAYS); gridPane.setHgrow (stackPane, Priority.ALWAYS); // Add controls var xSlider = new Slider (-90, 90, 0); xRotate.angleProperty().bind (xSlider.valueProperty()); var ySlider = new Slider (-180, 180, 0); yRotate.angleProperty().bind (ySlider.valueProperty()); var zSlider = new Slider (-60, -25, -25); camera.translateZProperty().bind (zSlider.valueProperty()); ToolBar toolbar = new ToolBar ( new Label ("X rotation:"), xSlider, new Label ("Y rotation:"), ySlider, new Label ("Z position:"), zSlider ); gridPane.add (toolbar, 0, 1); // Start the show stage.setTitle ("Label Test"); stage.setScene (new Scene (gridPane, 800, 600)); stage.show(); } // start private void updateLabels () { nodeToLabelMap.forEach ((node, label) -> { var coord = node.localToScene (Point3D.ZERO, true); System.out.println ("label = " + label.getText() + ", coord = " + coord); label.getTransforms().setAll (new Translate(coord.getX(), coord.getY())); }); } // updateLabels public static void main (String[] args) { launch (args); } // main } // LabelTest class
Puede compilar y ejecutar el programa LabelTest.java usando este script (estoy usando JavaFX 14 y JDK 14.0.2 en una Mac):
#!/bin/sh set -x export PATH_TO_FX=javafx-sdk-14/lib javac --module-path $PATH_TO_FX --add-modules javafx.controls LabelTest.java if [ $? -ne 0 ] ; then exit 1 fi java -cp . --module-path $PATH_TO_FX --add-modules javafx.controls LabelTest
La salida de mi programa de prueba contiene coordenadas de etiquetas muy grandes que no representan la posición de las esferas del eje de color, por ejemplo:
label = Y axis, coord = Point3D [x = 17448.00808897467, y = 21535.846392310217, z = 0.0] label = X axis, coord = Point3D [x = 26530.33870777918, y = 12453.515773505665, z = 0.0] label = Z axis, coord = Point3D [x = 17448.008088974653, y = 12453.515773505665, z = 0.0]
Mi pantalla se ve así:
donde debería parecerse más al ejemplo de FXyz con etiquetas al lado de las esferas del eje:
Si sigue lo que se ha hecho en el enlace que ha publicado, lo hará funcionar.
Para empezar, hay una subescena, no dos.
Así que he eliminado estas líneas:
- var viewScene = new SubScene (new Group (scene3d), 500, 500); - scene3d.widthProperty().bind (viewScene.widthProperty()); - scene3d.heightProperty().bind (viewScene.heightProperty());
y reemplazó estos:
- var stackPane = new StackPane (viewScene); - viewScene.heightProperty().bind (stackPane.heightProperty()); - viewScene.widthProperty().bind (stackPane.widthProperty()); - viewScene.setManaged (false); + var stackPane = new StackPane (sceneRoot); + scene3d.heightProperty().bind (stackPane.heightProperty()); + scene3d.widthProperty().bind (stackPane.widthProperty());
Eso funciona bien ahora para mí:
label = Z axis, coord = Point3D [x = 613.2085772621016, y = 286.33580935946725, z = 0.0] label = X axis, coord = Point3D [x = 401.67010722785966, y = 219.90328164976754, z = 0.0] label = Y axis, coord = Point3D [x = 400.0, y = 503.57735384935296, z = 0.0]