【问题标题】:Convert coordinates from 3D scene to 2D overlay将坐标从 3D 场景转换为 2D 叠加
【发布时间】:2019-09-17 04:25:04
【问题描述】:

类似于How to get 2D coordinates on window for 3D object in javafx,但我无法让解决方案发挥作用。

我想为 3d 形状或更像它的投影绘制 2d 边框。我写了这个示例代码供参考:

import javafx.application.Application;
import javafx.geometry.Point3D;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.SceneAntialiasing;
import javafx.scene.SubScene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;

public class CoordinateConversion extends Application {

    @Override
    public void start(Stage stage) {
        var box = new Box(20, 20, 20);
        box.setMaterial(new PhongMaterial(Color.TEAL));
        box.getTransforms().add(new Rotate(45, new Point3D(1, 1, 1)));
        var rootGroup = new Group(box);

        var camera = new PerspectiveCamera(true);
        camera.setFarClip(500);
        camera.setTranslateZ(-100);
        var aaScene = new SubScene(rootGroup, 0, 0, true, SceneAntialiasing.BALANCED);
        aaScene.setCamera(camera);

        var pane3d = new Pane(aaScene);
        pane3d.setBackground(new Background(new BackgroundFill(Color.BEIGE, null, null)));
        aaScene.widthProperty().bind(pane3d.widthProperty());
        aaScene.heightProperty().bind(pane3d.heightProperty());

        var overlay = new AnchorPane();

        var stack = new StackPane(pane3d, overlay); 
        var filler = new Rectangle(0, 0, 100, 50);
        filler.setFill(Color.rgb(0, 255, 0, 0.3));
        var borderPane = new BorderPane();
        borderPane.setCenter(stack);
        borderPane.setTop(filler);
        var scene = new Scene(borderPane);
        stage.setScene(scene);
        stage.setWidth(800);
        stage.setHeight(400);
        stage.show();

        var sceneBounds = box.localToScene(box.getBoundsInLocal(), false);
        var overlayBounds = overlay.sceneToLocal(sceneBounds);
        var rect = new Rectangle(overlayBounds.getMinX(), overlayBounds.getMinY(), overlayBounds.getWidth(), overlayBounds.getHeight());
        rect.setFill(null);
        rect.setStroke(Color.RED);
        overlay.getChildren().add(rect);
    }

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

它在角落绘制红色矩形,而我想要的是我添加的“photoshoped”橙色矩形。

基本思想是将边界从一个父级转换为另一个,因此我从一个父级转换为场景,然后从场景转换为下一个父级,正如我在How to translate a node in a parent's coordinate system? 中所教的那样。关于转型的一些事情我不明白

  1. 如果我使用box.localToScene(box.getBoundsInLocal(), true),我会得到NaN 边界,即使该框位于子场景中并且我想要场景中的坐标。
  2. sceneBoundsoverlayBounds 是相同的,即使覆盖开始时比场景低 50 像素(由于填充物)。如果没有变换,我希望覆盖层和场景之间的每次转换在 y 上都是 +-50。

我还尝试使用box.getParent().localToScene(box.getBoundsInParent()) 获取sceneBounds,但相同。我想这是有道理的,因为我使用父节点来转换父节点中的边界,而不是节点来转换本地边界。

使用 Javafx 12

【问题讨论】:

    标签: java javafx javafx-3d


    【解决方案1】:

    您有一个“时间”问题:您将 subScene 设置为 0x0 尺寸,然后添加绑定,并在显示舞台后为 sceneBounds 进行计算,返回 @987654324 @。

    如果您向pane3d.widthProperty() 添加侦听器,您将看到sceneBounds 在宽度更改之前被解析,因此,您正在使用0x0 子场景。所以你说得太早了。

    可能的解决方案:

    • 移除绑定并为 subScene 维度设置一个值:
    var aaScene = new SubScene(rootGroup, 800, 400, true, SceneAntialiasing.BALANCED);
    stage.show();
    var sceneBounds = box.localToScene(box.getBoundsInLocal(), true);
    ...
    
    • 保留绑定,但为 subScene 的 height 属性(设置在宽度之后)添加一个侦听器:
    aaScene.heightProperty().addListener((obs, ov, nv) -> {
         var sceneBounds = box.localToScene(box.getBoundsInLocal(), true);     
    ...
    });
    

    无论哪种情况,请注意您必须使用localToScene(..., true) 来获取场景坐标:

    如果Node没有任何SubScene或rootScene设置为true,则结果点在getScene()返回的Node的Scene坐标中。

    【讨论】:

      猜你喜欢
      • 2018-05-25
      • 1970-01-01
      • 2015-01-01
      • 1970-01-01
      • 2015-06-29
      • 2014-06-12
      • 2012-03-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多