簡體   English   中英

將坐標從3D場景轉換為2D覆蓋

[英]Convert coordinates from 3D scene to 2D overlay

類似於如何在javafx中獲取3D對象在窗口上的2D坐標,但是我無法獲得解決方案。

我想為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”橙色矩形。

在此處輸入圖片說明

基本思想是將邊界從一個父對象轉換為另一父對象,所以我將如何從一個父對象轉換為場景,然后從場景轉換為下一個父對象,如如何轉換父對象的坐標系中的節點所教 我對轉換不了解的一些事情

  1. 如果我使用box.localToScene(box.getBoundsInLocal(), true)即使框位於子場景中,我也將獲得NaN邊界,並且我希望場景中的坐標。
  2. 即使疊加層的起始位置比場景低50個像素(由於填充), sceneBoundsoverlayBounds也是相同的。 如果沒有轉換,我希望疊加層和場景之間的每次轉換在y上恰好是+ -50。

我也嘗試使用box.getParent().localToScene(box.getBoundsInParent())來獲取sceneBounds ,但是ti是一樣的。 我想這是有道理的,因為我使用父級來轉換父級中的界限,而不是使用節點來轉換本地中的界限。

使用Javafx 12

你有一個“時間”的問題:您設置的子場景和0x0尺寸,然后添加綁定,並做了計算sceneBounds展示的舞台,這回之后 NaN

如果將偵聽器添加到pane3d.widthProperty() ,則會看到更改寬度之前已解決了sceneBounds ,因此,您正在使用0x0 subScene。 所以您稱呼為時過早。

可能的解決方案:

  • 刪除綁定並為subScene尺寸設置一個值:
var aaScene = new SubScene(rootGroup, 800, 400, true, SceneAntialiasing.BALANCED);
stage.show();
var sceneBounds = box.localToScene(box.getBoundsInLocal(), true);
...
  • 保留綁定,但向subScene的height屬性(在width之后設置)添加一個偵聽器:
aaScene.heightProperty().addListener((obs, ov, nv) -> {
     var sceneBounds = box.localToScene(box.getBoundsInLocal(), true);     
...
});

無論哪種情況,請注意,您必須使用localToScene(..., true)來獲取場景坐標:

如果Node沒有任何SubScene或rootScene設置為true,則結果點位於getScene()返回的Node的場景坐標中。

在此處輸入圖片說明

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM