Как я могу добавить 3D-поверхность в AnchorPane

Как я могу добавить 3D-поверхность к view.fxml, на панели Scene Builder нет «вещи», такой как поверхность. Моя иерархия конструктора сцен выглядит так:

Иерархия

И ss приложения - как мы видим, есть что-то в левом верхнем углу, поверхность должна быть посередине. введите здесь описание изображения

Сначала я хотел бы добавить несколько образцов 3D-поверхности: Код моего контроллера:

    package sample.packet3D;

import org.fxyz.cameras.CameraTransformer;

import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.fxml.FXML;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.PointLight;
import javafx.scene.layout.AnchorPane;


public class Window3DController {

    @FXML
    private AnchorPane anchorPane;
    @FXML
    private Group group;

    private Window3DBuilder window3dBuilder;
    private PerspectiveCamera perspectiveCamera;



    @FXML
    public void initialize() {
        perspectiveCamera = new PerspectiveCamera(true);

        window3dBuilder = new Window3DBuilder( group, perspectiveCamera );
        window3dBuilder.createScene();



        group.sceneProperty().addListener(new InvalidationListener() {

            @Override
            public void invalidated(Observable observable) {
                group.getScene().setCamera(perspectiveCamera);
                group.sceneProperty().removeListener(this);
            }
        });
    }
}

Логический класс:

   package sample.packet3D;


import org.fxyz.cameras.CameraTransformer;
import org.fxyz.shapes.primitives.SurfacePlotMesh;

import javafx.geometry.Point3D;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.PointLight;
import javafx.scene.SceneAntialiasing;
import javafx.scene.SubScene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.CullFace;
import javafx.scene.shape.TriangleMesh;
import javafx.scene.transform.Rotate;

public class Window3DBuilder {

    private Group group;
    private SurfacePlotMesh surface;
    private PerspectiveCamera perspectiveCamera;
    private CameraTransformer cameraTransformer;
    private PointLight light;

    public Window3DBuilder( Group group, PerspectiveCamera perspectiveCamera ) {
        this.group = group;
        this.perspectiveCamera = perspectiveCamera;
        cameraTransformer = new CameraTransformer();
    }

    public void createScene() {

        createSurface();
        createLight(); 
        group.getChildren().addAll(surface);

        cameraTransformer.setTranslate(0, 0, 0);
        cameraTransformer.getChildren().addAll(perspectiveCamera);

        perspectiveCamera.setNearClip(0.1);
        perspectiveCamera.setFarClip(100000.0);
        perspectiveCamera.setTranslateX((group.getBoundsInLocal().getMaxX() + group.getBoundsInLocal().getMinX()) / 2d);
        perspectiveCamera.setTranslateY((group.getBoundsInLocal().getMaxY() + group.getBoundsInLocal().getMinY()) / 2d);
        double max = Math.max(group.getBoundsInLocal().getWidth(), group.getBoundsInLocal().getHeight());
        perspectiveCamera.setTranslateZ(-2 * max);

    }

    public void createLight() {
        light = new PointLight(Color.WHITE);
        cameraTransformer.getChildren().add(light);
        light.setTranslateX(perspectiveCamera.getTranslateX());
        light.setTranslateY(perspectiveCamera.getTranslateY());
        light.setTranslateZ(perspectiveCamera.getTranslateZ());
    }

    private void createSurface() {
        surface = new SurfacePlotMesh(
                p-> Math.sin(p.magnitude() + 1e-10) / (p.magnitude() + 1e-10),
                20, 20, 100, 100, 4);
        surface.setCullFace(CullFace.NONE);
        surface.setTextureModeVertices3D(1530, p -> p.magnitude());
        surface.getTransforms().addAll(new Rotate(200, Rotate.X_AXIS), new Rotate(-20, Rotate.Y_AXIS));
    }



}

И просмотр:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.effect.*?>
<?import javafx.scene.canvas.*?>
<?import javafx.scene.*?>
<?import javafx.scene.shape.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.packet3D.Window3DController">
   <children>
      <Group fx:id="group">
         <effect>
            <Lighting>
               <bumpInput>
                  <Shadow />
               </bumpInput>
               <light>
                  <Light.Distant />
               </light>
            </Lighting>
         </effect>
      </Group>
      <PerspectiveCamera fx:id="perspectiveCamera" visible="false" />
   </children>
</AnchorPane>

Что я делаю не так ? Может ли кто-нибудь помочь мне? Также это одно из окон, в которое я вхожу по нажатию кнопки.

@FXML
    public void moveTo3DScene(ActionEvent event) throws IOException {
        Stage stage3D = (Stage) ((Node) event.getSource()).getScene().getWindow();
        Parent parent3D = FXMLLoader.load(getClass().getResource("packet3D/Window3DSceneView.fxml"));
        stage3D.setTitle("Animation 3D");
        stage3D.setScene(new Scene(parent3D, 1200, 800));
        stage3D.show();

    }

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


person yerpy    schedule 15.05.2016    source источник


Ответы (2)


У вас проблема с PerspectiveCamera. У него есть логический параметр fixedEyeAtCameraZero, который по умолчанию равен false, а в верхнем левом углу вашей сцены отображается очень маленькая поверхность.

Нам нужно установить его в true, поэтому:

Если fixedEyeAtCameraZero равно true, положение глаза фиксируется на (0, 0, 0) в локальных координатах камеры.

Но, к сожалению, задать параметр нельзя, метода setFixedEyeAtCameraZero() нет. Единственный способ изменить это с помощью конструктора камеры.

Это означает, что вы должны удалить PerspectiveCamera из файла FXML и добавить его с помощью кода на контроллере.

public class Window3DController {

    @FXML
    private AnchorPane anchorPane;
    @FXML
    private Group group;

    private Window3DBuilder window3dBuilder;
    private PerspectiveCamera perspectiveCamera;

    @FXML
    public void initialize() {
        perspectiveCamera = new PerspectiveCamera(true);

        window3dBuilder = new Window3DBuilder(group, perspectiveCamera);
        window3dBuilder.createScene();

        group.sceneProperty().addListener(new InvalidationListener() {
            @Override
            public void invalidated(Observable observable) {
                group.getScene().setCamera(perspectiveCamera);
                group.sceneProperty().removeListener(this);
            }
        });
    } 

}

Последний шаг: вам нужно установить некоторые параметры камеры, в основном ее координату z в зависимости от размера сетки:

public void createScene() {
    createSurface();
    group.getChildren().addAll(surface);

    perspectiveCamera.setNearClip(0.1);
    perspectiveCamera.setFarClip(100000.0);
    perspectiveCamera.setTranslateX((group.getBoundsInLocal().getMaxX() + group.getBoundsInLocal().getMinX()) / 2d);
    perspectiveCamera.setTranslateY((group.getBoundsInLocal().getMaxY() + group.getBoundsInLocal().getMinY()) / 2d);
    double max = Math.max(group.getBoundsInLocal().getWidth(), group.getBoundsInLocal().getHeight());
    perspectiveCamera.setTranslateZ(-2 * max);
}

Это покажет вашу поверхность, но не так, как вы ожидаете: эффекты, которые вы применяете, предназначены для 2D:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.Group?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Window3DController">
   <children>
      <Group fx:id="group" />
   </children>
</AnchorPane>

Удалите эти эффекты и добавьте их с помощью кода, используя PointLight:

public class Window3DBuilder {

    private final Group group;
    private SurfacePlotMesh surface;
    private final CameraTransformer cameraTransformer;
    private final PerspectiveCamera perspectiveCamera;
    private PointLight light;

    public Window3DBuilder( Group group, PerspectiveCamera perspectiveCamera ) {
        this.group = group;
        this.perspectiveCamera = perspectiveCamera;
        cameraTransformer = new CameraTransformer();
    }

    public void createScene() {
        createSurface();
        group.getChildren().addAll(surface, cameraTransformer);

        cameraTransformer.setTranslate(0, 0, 0);
        cameraTransformer.getChildren().addAll(perspectiveCamera);

        perspectiveCamera.setNearClip(0.1);
        perspectiveCamera.setFarClip(100000.0);
        perspectiveCamera.setTranslateX((group.getBoundsInLocal().getMaxX() + group.getBoundsInLocal().getMinX()) / 2d);
        perspectiveCamera.setTranslateY((group.getBoundsInLocal().getMaxY() + group.getBoundsInLocal().getMinY()) / 2d);
        double max = Math.max(group.getBoundsInLocal().getWidth(), group.getBoundsInLocal().getHeight());
        perspectiveCamera.setTranslateZ(-2 * max);
        createLight();
    }

    public void createLight() {
        light = new PointLight(Color.WHITE);
        cameraTransformer.getChildren().add(light);
        light.setTranslateX(perspectiveCamera.getTranslateX());
        light.setTranslateY(perspectiveCamera.getTranslateY());
        light.setTranslateZ(perspectiveCamera.getTranslateZ() / 10);
    }

    private void createSurface() {
        surface = new SurfacePlotMesh(
                p-> Math.sin(p.magnitude() + 1e-10) / (p.magnitude() + 1e-10),
                20, 20, 100, 100, 4);
        surface.setCullFace(CullFace.NONE);
        surface.setTextureModeVertices3D(1530, p -> p.magnitude());
        surface.getTransforms().addAll(new Rotate(200, Rotate.X_AXIS), new Rotate(-20, Rotate.Y_AXIS));
    }

}

Поверхность

person José Pereda    schedule 15.05.2016
comment
Я создал метод public void createLight() { light = new PointLight(Color.WHITE); cameraTransformer.getChildren (). Добавить (свет); light.setTranslateX(perspectiveCamera.getTranslateX()); light.setTranslateY(perspectiveCamera.getTranslateY()); light.setTranslateZ(perspectiveCamera.getTranslateZ()); } и вызвать внутри crateScene(), но это не работает, что еще мне нужно? - person yerpy; 15.05.2016
comment
У вас есть cameraTransformer? В противном случае light является узлом, вы должны добавить его в граф сцены, поэтому добавьте его в группу - person José Pereda; 15.05.2016
comment
Да, у меня есть: createSurface(); создатьСвет(); group.getChildren().addAll (поверхность, свет); - person yerpy; 15.05.2016
comment
Добавьте в группу узел cameraTransformer вместо узла light. - person José Pereda; 15.05.2016
comment
Если я добавлю его в метод createLight(), где он у меня есть, все равно не работает, только в этом месте я добавляю узел light к cameraTransformer. Разве это не должно быть похоже на то, что первый световой узел добавляется в cameraTransformer, а затем cameraTransformer в группу? - person yerpy; 15.05.2016
comment
Вам нужно вызвать createLight() после того, как вы настроите камеру, или привяжите свойства перевода света к свойствам камеры. - person José Pereda; 15.05.2016
comment
Я сделал это: light = window3dBuilder.createLight(); group.getChildren().add(light);в Window3DControlller после group.sceneProperty()...но это ничего не изменило ;/ - person yerpy; 15.05.2016
comment
У меня тот же код, но результат другой, все время у меня это есть, добавил ss @up - person yerpy; 15.05.2016
comment
Вы удалили эффекты из файла FXML, как я вам сказал? - person José Pereda; 15.05.2016
comment
Я нашел проблему, все время что-то не сохранялось должным образом, спасибо за помощь! - person yerpy; 15.05.2016

Я хотел сохранить камеру в файле .fxml. Я создал пользовательский элемент управления на основе PerspectiveCamera.

Начните с очень простого класса...

import javafx.scene.PerspectiveCamera;


public class PerspectiveCamera3D extends PerspectiveCamera {

// force 3D
public PerspectiveCamera3D() {
    super(true);
}

// toss the parameter, force 3D
public PerspectiveCamera3D(final boolean fixedEyeAtCameraZero) {
    this();
}
}

Экспорт в файл .jar. Запустите Scene Builder и откройте файл .fxml, где вы хотите разместить камеру.

Откройте меню «шестеренка» в заголовке библиотеки. Затем импортируйте FXML/Jar. Импортируйте только что созданный файл .jar. Появится диалоговое окно с вашим элементом управления в списке. После подтверждения элемент управления появится в пользовательском меню. Теперь ваш элемент управления готов к использованию, как и любой другой.

Флажок "Фиксированный глаз..." по-прежнему будет доступен только для чтения, но он будет установлен. Все остальные свойства можно настроить по желанию. Чтобы установить fx:id, просто добавьте в код контроллера следующее...

@FXML
public PerspectiveCamera3D cambot;

Вот немного более подробный пример... https://rterp.wordpress.com/2014/07/28/adding-custom-javafx-component-to-scene-builder-2-0-part-2/

Единственная проблема, с которой я столкнулся, заключается в том, что при запуске Scene Builder нажатием на файл .fxml в Eclipse возникает исключение (я считаю, что это локальная проблема на моем компьютере из-за того, как я запускаю вещи и их рабочие каталоги). Он отлично работает, если я открываю Scene Builder, а затем открываю файл .fxml из меню «Файл Scene Builder».

person GeekToast    schedule 10.06.2017