如何使用相机正确显示3D形状?

时间:2016-10-29 07:44:56

标签: java javafx javafx-8 javafx-3d

我正试图让一些形状相互“玩得很好”。我有两个彼此相邻的盒子和一个盒子“顶部”的圆柱体。我将它们放在SubScene的相机中,可以通过滚动操作进行放大和缩小,然后通过拖动进行平移。这是我的MCVE:

import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.SceneAntialiasing;
import javafx.scene.SubScene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.Cylinder;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;

public class MyApp extends Application {

    DoubleProperty transX = new SimpleDoubleProperty();
    DoubleProperty transY = new SimpleDoubleProperty();
    DoubleProperty transZ = new SimpleDoubleProperty();

    double startX, startY, curX, curY;

    @Override
    public void start(Stage stage) throws Exception {

        Box box1 = new Box(30, 30, 5);
        box1.setMaterial(new PhongMaterial(Color.RED));
        Box box2 = new Box(30, 30, 5);
        box2.setMaterial(new PhongMaterial(Color.GREEN));
        box2.setTranslateX(32);
        Cylinder cyn = new Cylinder(5, 15);

        Group root = new Group(box1, box2, cyn);
        root.getTransforms().addAll(new Translate(0, 0, 200),
                                    new Rotate(-60, Rotate.X_AXIS),
                                    new Rotate(-45, Rotate.Z_AXIS));

        SubScene subs = new SubScene(root, 0, 0, true, SceneAntialiasing.BALANCED);

        PerspectiveCamera camera = new PerspectiveCamera(true);
        camera.setFarClip(1000);
        camera.setNearClip(0);
        camera.translateZProperty().bind(transZ);
        camera.translateXProperty().bind(transX);
        camera.translateYProperty().bind(transY);
        subs.setCamera(camera);

        Pane pane = new Pane(subs);
        pane.setStyle("-fx-border-color: red;" + 
                      "-fx-border-width: 3;");
        subs.widthProperty().bind(pane.widthProperty());
        subs.heightProperty().bind(pane.heightProperty());

        pane.setOnScroll(e -> transZ.set(transZ.get() + e.getDeltaY() * 0.2));
        pane.setOnMousePressed(e -> {
            startX = curX = e.getX();
            startY = curY = e.getY();
        });
        pane.setOnMouseDragged(e -> {
            startX = curX;
            startY = curY;
            curX = e.getX();
            curY = e.getY();
            double deltaX = curX - startX;
            double deltaY = curY - startY;
            double deltaZ = deltaY * Math.sqrt(3);
            transX.set(transX.get() - deltaX);
            transY.set(transY.get() - deltaY);
            transZ.set(transZ.get() + deltaZ);
        });

        Scene scene = new Scene(pane, 500, 500);
        stage.setScene(scene);
        stage.sizeToScene();
        stage.show();
    }

    public static void main(String[] args) throws Exception {

        launch(args);
    }
}

我有两个问题:

  1. Z顺序由我将它们放入组中的顺序指定。我希望Z命令“照顾好自己”。如果我在空间中具有特定坐标和大小的形状以及在特定位置和角度的相机,我应该看到一个独特的视图而无需指定顺序。这是一张图片:

    enter image description here

    看起来绿色框比红色框更靠近相机,但我的代码并不暗示这一点。

  2. 当相机平移时,气缸相对于盒子移动。在图像中,我用蓝线标记红色框上圆柱的位置:

    enter image description here

    现在我平移相机并获得

    enter image description here

    我想在平移相机时不改变形状的相对位置。

  3. 编辑:我从问题中删除了这个并在另一个问题中提出: 形状显示在边框的顶部:

    enter image description here

    我认为因为形状在窗格中,所以窗格的边框在Z顺序中会更高。我希望边框显示在顶部。

2 个答案:

答案 0 :(得分:1)

我想这实际上是JavaFX中的一个错误,但至少它很容易修复。只是不要将摄像机的近剪裁窗格设置为0.将代码的这一行改为

$(document).on('change','#birthday',function(){
    if($('#birthday').val()!==''){
        $('#birthday').addClass('hasValue');
    }else{
        $('#birthday').removeClass('hasValue');
    }
})

将解决您的前两个问题。

答案 1 :(得分:0)

尝试使用以下行启用Group Depth测试:

 setDepthTest(DepthTest.ENABLE);