今天开始学习javaFX 3D图形中的Camera,Camera作为一个节点,可以被添加到场景中,它能允许你在一个3D场景中移动它,不同于二维布局的是,camera总能保持在一个位置上。

在javaFX场景坐标空间中,camera的默认投影平面是在Z=0上。camera的坐标系统如下:

在显示屏上,

X轴指向右边

Y轴指向下面

Z轴的指向是从显示屏到你。

其实这也是java中的坐标系统。

Perspective Camera类


        javaFX提供了一个PerspectiveCamera类,用来渲染3D场景,该类提供了一个视锥,该视锥可以通过fieldOfView属性来改变。

下图显示了两种构造方法来构造PerspectiveCamera

imageview javafx如何 javafx camera_坐标系统

        第二个构造函数,是javaFX8中新加进去的,它允许你控制相机的位置,通过fixedEyeAtCameraZero属性,它将相机呈现在一个3D场景中。因此构建一个3D场景只需将它设置为true即可,此时它的视角位置会固定在坐标空间的(0,0,0)像素处,既电脑显示屏的左上角且不管你如何改变窗体的大小。当fixedEyeAtCameraZero设置为false的时候(默认值),相机有它的起源坐标系统在左上角的面板上。此模式用于2 d UI控件呈现,但对于大多数3 d图形应用程序并不有用。当窗口改变大小时,相机会移动,例如,保持原点在面板的左上角,这正是你想要的2 d UI布局,但在一个3 d的布局中不行。因此,重要的是要记住当你在做的3 d图形改变或移动相机时,设置fixedEyeAtCameraZero属性为true。

创建一个Camera并添加到场景中,可以使用如下代码:

imageview javafx如何 javafx camera_imageview javafx如何_02

使用如下代码添加Camera到scene graph中:

imageview javafx如何 javafx camera_3D_03

旋转Camera并移动CameraGroup

imageview javafx如何 javafx camera_3D_04

Field of View(视野)


设置Camera的视野

imageview javafx如何 javafx camera_3D_05

注意,视野越大,则角度变形和大小差异则增加越多

Fisheye:鱼眼镜头有一个180度的视野。

Normal:正常的镜头有一个40到62度的视野。

Telephoto:长焦镜头有一个1度到30度的视野(或许更少)。

Clipping Planes(裁剪平面)


你可以设置相机裁剪平面附近的坐标系统:

imageview javafx如何 javafx camera_imageview javafx如何_06

设置相机在当前的坐标系统中的裁剪平面:

imageview javafx如何 javafx camera_坐标系统_07

Y-down 与 Y-up


        大多数的2D平面坐标系统的Y轴是沿着你的屏幕向下的,许多3D图形坐标系统的Y轴却是沿着屏幕向上的,还有一些事Z轴向上的,在javaFX中,Camera的坐标系统是Y轴指向下的,X轴指向右边,Z轴指向你。如果你想要改变他们,你可以创建一个Xform节点,给它起个名字root3D,你可以设置rx.setAngle为180度,这样就可以把它颠倒了。然后把你的3D元素添加到root3D中。例子如下:

imageview javafx如何 javafx camera_3D_08

你也可以创建一个叫做cameraXform的Xform,把它放到你的root下,上下颠倒之后,把你的camera放到cameraXform中。代码如下:

imageview javafx如何 javafx camera_3D_09

一种比较好的方式添加一个旋转180度的相机,和上面的方式相比有些许细微的差距。下面的例子是让相机旋转180度然后添加一些子元素到cameraXform中(这里使用Rotate)。

细微的差别是,cameraxform保留非常原始的值它的默认位置,一切归零,包括平移和旋转。

imageview javafx如何 javafx camera_3D_10

Sample Code Using PerspectiveCamera(样品代码)

<span style="font-size:14px;">package simple3dbox;
 
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.SubScene;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.DrawMode;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
 
public class Simple3DBoxApp extends Application {
 
    public Parent createContent() throws Exception {
 
        // Box
        Box testBox = new Box(5, 5, 5);
        testBox.setMaterial(new PhongMaterial(Color.RED));
        testBox.setDrawMode(DrawMode.LINE);
 
        // Create and position camera
        PerspectiveCamera camera = new PerspectiveCamera(true);
        camera.getTransforms().addAll (
                new Rotate(-20, Rotate.Y_AXIS),
                new Rotate(-20, Rotate.X_AXIS),
                new Translate(0, 0, -15));
 
        // Build the Scene Graph
        Group root = new Group();       
        root.getChildren().add(camera);
        root.getChildren().add(testBox);
 
        // Use a SubScene       
        SubScene subScene = new SubScene(root, 300,300);
        subScene.setFill(Color.ALICEBLUE);
        subScene.setCamera(camera);
        Group group = new Group();
        group.getChildren().add(subScene);
        return group;
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        primaryStage.setResizable(false);
        Scene scene = new Scene(createContent());
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * Java main for when running without JavaFX launcher
     */
    public static void main(String[] args) {
        launch(args);
    }
}</span>