Как сделать так, чтобы 3D-фигуры правильно отображались с помощью камеры?

Я пытаюсь заставить несколько фигур «хорошо играть» друг с другом. У меня есть 2 коробки рядом друг с другом и цилиндр "сверху" одной из коробок. Я поместил их в 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);
    }
}

У меня тут 2 проблемы:

  1. порядок Z определяется порядком, в котором я помещаю их в группу. Я хочу, чтобы приказ Z "позаботился о себе". Если у меня есть формы в пространстве с определенными координатами и размерами и камера в определенном положении и под определенным углом, я должен видеть уникальный вид без необходимости указывать порядок. Вот картинка:

    введите здесь описание изображения

    похоже, что зеленая коробка ближе к камере, чем красная, но мой код этого не подразумевает.

  2. цилиндр перемещается относительно коробки при панорамировании камеры. На изображении я отмечаю синими линиями расположение цилиндра на красной рамке:

    введите здесь описание изображения

    и теперь я поворачиваю камеру и получаю

    введите здесь описание изображения

    Я хочу, чтобы относительное расположение фигур не менялось при панорамировании камеры.

  3. Изменить: я удалил это из вопроса и задал его в другом:
    фигуры отображаются поверх границы:

    введите здесь описание изображения

    я думал, что, поскольку фигуры находятся на панели, граница панели будет выше в порядке Z. Я хочу, чтобы граница отображалась сверху.


person Mark    schedule 29.10.2016    source источник


Ответы (2)


Я предполагаю, что на самом деле это ошибка в JavaFX, но, по крайней мере, ее легко исправить. Просто не устанавливайте ближнюю область отсечения камеры на 0. Измените эту строку кода на

camera.setNearClip(10);

решит ваши первые две проблемы.

person mipa    schedule 29.10.2016
comment
О какой из 3-х проблем вы говорите? - person Mark; 29.10.2016
comment
Номер 1, а также номер 2, насколько я понимаю вашу проблему. Номер 3 - это отдельная тема. - person mipa; 29.10.2016
comment
Примечание: если вы считаете, что это ошибка в JavaFX, задайте вопрос здесь: bugs.java.com - person Puce; 29.10.2016
comment
@Puce Лично я не уверен, что какие-либо из упомянутых мною проблем являются ошибками. Вы считаете, что их нужно представить? - person Mark; 29.10.2016
comment
@mipa упомянул, что это, вероятно, ошибка. Я не знаком с этой частью API. - person Puce; 29.10.2016
comment
Ну, является ли это ошибкой в ​​строго техническом смысле, наверное, спорно. Но Oracle уже упоминает о потенциальных проблемах в документации. В JavaDoc для NearClipProperty сказано: Значение, меньшее или равное нулю, рассматривается как очень маленькое положительное число. Таким образом, 0.0 явно является недопустимым значением, но установка его явным образом не привела ни к исключению, ни к сообщению об ошибке, а также не была исправлена ​​в достаточной степени. Кстати, значение этого свойства по умолчанию 0,1 сработало бы. Так что судите сами, считаете ли вы это поведение ошибкой или нет. - person mipa; 29.10.2016
comment
mipa: да, теперь я вижу. Вы правы в том, что это вызывает NearClip, и это похоже на ошибку. Я установил ближний клип на 0.0001, и это вызвало визуальные артефакты повсюду. - person Mark; 29.10.2016
comment
Я знаю. я жду, чтобы увидеть, есть ли у кого-то еще это, и признает ли оракул ошибку. - person Mark; 30.10.2016
comment
Очевидно, это не ошибка: bugs.java.com/bugdatabase/view_bug.do ?bug_id=JDK-8169053. Не знаю, как это не ошибка, потому что документы говорят что-то другое. - person Mark; 17.11.2016

Попробуйте включить тест глубины группы с помощью следующей строки:

 setDepthTest(DepthTest.ENABLE);
person Lucas Wolfgang    schedule 15.05.2017