如何将 3D 表面添加到 AnchorPane
How can I add 3D surface to the AnchorPane
如何将 3D 表面添加到 view.fxml
,Scene Builder 面板上没有 "thing" 之类的表面。
我的场景构建器层次结构如下:
和 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);
}
});
}
}
逻辑class:
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>
我做错了什么?有人可以帮我吗?
这也是 window 之一,我按下按钮进入其中。
@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();
}
您对 PerspectiveCamera
有疑问。它有一个名为 fixedEyeAtCameraZero
的布尔参数,默认情况下为 false,场景的左上角会显示一个非常小的表面。
我们需要将其设置为真,所以:
If fixedEyeAtCameraZero is true, the eye position is fixed at (0, 0, 0) in the local coordinates of the camera
可惜不能设置参数,没有setFixedEyeAtCameraZero()
方法。改变它的唯一方法是使用相机构造函数。
这意味着您必须从 FXML 文件中删除 PerspectiveCamera
,并通过控制器上的代码添加它
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));
}
}
我想将相机保留在 .fxml 文件中。我创建了一个基于 PerspectiveCamera 的自定义控件。
从一个非常简单的开始 class...
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 文件。
打开库 header 上的 'gear' 菜单。
然后导入FXML/Jar。导入新创建的 .jar 文件。将弹出一个对话框,其中列出了您的控件。确认后,该控件将出现在自定义菜单中。您的控件现在可以使用了,就像任何其他控件一样。
'Fixed Eye...' 复选框仍为 read-only,但 将 选中。可以根据需要设置所有其他属性。要设置 fx:id 只需将以下内容添加到您的控制器代码中...
@FXML
public PerspectiveCamera3D cambot;
这里有一个更详细的例子……https://rterp.wordpress.com/2014/07/28/adding-custom-javafx-component-to-scene-builder-2-0-part-2/
我这样做的唯一问题是,当通过单击 Eclipse 中的 .fxml 文件启动 Scene Builder 时会导致异常(我相信这是我计算机上的本地问题,因为我的方式'启动事物及其工作目录)。如果我打开 Scene Builder,然后从 Scene Builder 文件菜单中打开 .fxml 文件,它工作正常。
如何将 3D 表面添加到 view.fxml
,Scene Builder 面板上没有 "thing" 之类的表面。
我的场景构建器层次结构如下:
和 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);
}
});
}
}
逻辑class:
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>
我做错了什么?有人可以帮我吗? 这也是 window 之一,我按下按钮进入其中。
@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();
}
您对 PerspectiveCamera
有疑问。它有一个名为 fixedEyeAtCameraZero
的布尔参数,默认情况下为 false,场景的左上角会显示一个非常小的表面。
我们需要将其设置为真,所以:
If fixedEyeAtCameraZero is true, the eye position is fixed at (0, 0, 0) in the local coordinates of the camera
可惜不能设置参数,没有setFixedEyeAtCameraZero()
方法。改变它的唯一方法是使用相机构造函数。
这意味着您必须从 FXML 文件中删除 PerspectiveCamera
,并通过控制器上的代码添加它
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));
}
}
我想将相机保留在 .fxml 文件中。我创建了一个基于 PerspectiveCamera 的自定义控件。
从一个非常简单的开始 class...
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 文件。
打开库 header 上的 'gear' 菜单。 然后导入FXML/Jar。导入新创建的 .jar 文件。将弹出一个对话框,其中列出了您的控件。确认后,该控件将出现在自定义菜单中。您的控件现在可以使用了,就像任何其他控件一样。
'Fixed Eye...' 复选框仍为 read-only,但 将 选中。可以根据需要设置所有其他属性。要设置 fx:id 只需将以下内容添加到您的控制器代码中...
@FXML
public PerspectiveCamera3D cambot;
这里有一个更详细的例子……https://rterp.wordpress.com/2014/07/28/adding-custom-javafx-component-to-scene-builder-2-0-part-2/
我这样做的唯一问题是,当通过单击 Eclipse 中的 .fxml 文件启动 Scene Builder 时会导致异常(我相信这是我计算机上的本地问题,因为我的方式'启动事物及其工作目录)。如果我打开 Scene Builder,然后从 Scene Builder 文件菜单中打开 .fxml 文件,它工作正常。