javaFX初探(Camera)

52 篇文章 0 订阅
47 篇文章 3 订阅

本节主要介绍Camera API

Camera在javaFX场景中作为一个节点,并且允许围绕3D UI 布局进行旋转,这和2D布局中不同,2D布局中Camera只能停留在一个位置,

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

 X轴指向右边

 Y轴指向下边

 Z轴指向里边

视角Camera

javaFX提供了一个视角相机来呈现3D场景,这个视角相机定义了一个视锥,通过改变fieldOfView属性,就可以改变视锥。

下面代码可以创建一个视角相机

PerspectiveCamera()

PerspectiveCamera(boolean fixedEyeAtCameraZero)

后边的构造函数式javaFX8新添加的,通过一个参数fixedEyeAtCameraZero来指定你是否能控制这个相机的位置,被这个相机渲染的东西就

会呈现在3D场景中,
下面的代码经常会出现在3D图形的编程中:

PerspectiveCamera(true);


 

当fixedEyeAtCameraZero 这个参数设置成true的时候,这个视角相机的坐标是(0,0,0),不管你怎么改变窗口大小它都在那里。
当fixedEyeAtCameraZero 这个参数这只成false的时候,这个相机的坐标原点在面板的左上角,这个模型被用于2D UI 控件选中中,在3D

图形应用中不怎么使用。当屏幕大小改变的时候这个相机的位置也就改变了,因为要保持在面板的左上角,这正好是2DUI布局想要的,但

不是3D布局想要的。所以当你在处理3D图形变化的时候一定要设置这个属性的值为true。

创建一个相机并把它添加到场景中,使用下面的代码:

Camera camera = new PerspectiveCamera(true);
     scene.setCamera(camera);

使用下面的代码把一个相机添加到场景图中

Group cameraGroup = new Group();
     cameraGroup.getChildren().add(camera);
     root.getChildren().add(cameraGroup);

使用下面的代码旋转相机

camera.rotate(45);
     cameraGroup.setTranslateZ(-75);


视野

相机的视野可以通过下面的方法设置:
camera.setFieldOfView(double value);


视场越大,角度变形和大小差异增加越多。

 Fisheye 是一个180度的镜头

 Normal 是一个40到62度的镜头

 Telephoto  是一个1到30度的镜头

你可以设置相机的剪切面附近的坐标系如下:

camera.setNearClip(double value);

你可以设置相机的剪切面远距离的局部坐标系如下:

camera.setFarClip(double value);

设置近或远的切面决定了视锥,如果近的切面太大,就会开始在场景的前面,如果设置的太小就会开始在场景的后面:

 注意:
  不要设置太小的近切面,也不要设置太大的远切面,否则就会出现奇怪的视觉效果。

切面的设置能使场景可见,但是可视范围不应该被设置的太大,否则会出现数值误差,如果近切面太大场景就会被切割,但是如果近切面太小,就会因为这个值过于接近零而出现不同的视觉效果。如果远切面太大,也会出现数值误差,尤其是在近切面设置太小的时候。


Y-down 和 Y-up

很多2D图形坐标系统都会在你向下拉屏幕的时候Y轴就会增加,比如PhotoShop.javaFX和IIIustrator。基本上所有的2D都以这种方式工作

。很所3D图形坐标系统是当你向上拉屏幕的时候Y轴就会增加。

Y down 和 Y up都是正确的。JavaFX中的相机坐标系统是Y-down,这就意味着,x轴指向右边,Y轴指向下边,Z轴执行屏幕里面。


我们考虑一个3D场景是Y-up的情况,创建一个Xform节点root3D,设置rx.setAngle属性为180度,把它颠倒一下。然后,给root3D增加3D的元

素或者把相机放到root3D下。代码如下:

root3D = new Xform();
root3D.rx.setAngle(180.0);
root.getChildren().add(root3D);
root3D.getChildren().add(...); // add all your 3D nodes here


你也可以向下面这样写:

Camera camera = new PerspectiveCamera(true);
Xform cameraXform = new Xform();
root.getChildren().add(cameraXform);
cameraXform.getChildren().add(camera);
cameraXform.rz.setAngle(180.0);


最好的方法是给相机添加一个180度的旋转,然后把相机添加到cameraXform。不同之处在于cameraXform会保持在原始的值的默认位置。
代码如下:

Camera camera = new PerspectiveCamera(true);
Xform cameraXform = new Xform();
root.getChildren().add(cameraXform);
cameraXform.getChildren().add(camera);
Rotate rz = new Rotate(180.0, Rotate.Z_AXIS);
camera.getTransforms().add(rz);

下面是使用视角Camera的两个简单实例:

package com.chu.helloworld;
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);
    }
}

效果如下:

package com.chu.helloworld;

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.application.ConditionalFeature;
import javafx.application.Platform;
import javafx.geometry.Point3D;
import javafx.scene.AmbientLight;
import javafx.scene.Camera;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.PerspectiveCamera;
import javafx.scene.PointLight;
import javafx.scene.Scene;
import javafx.scene.SceneAntialiasing;
import javafx.scene.SubScene;
import javafx.scene.control.Slider;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Cylinder;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class MSAAApp extends Application {

	@Override
	public void start(Stage stage) {
		if (!Platform.isSupported(ConditionalFeature.SCENE3D)) {
			throw new RuntimeException(
					"*** ERROR: common conditional SCENE3D is not supported");
		}

		stage.setTitle("JavaFX MSAA demo");

		Group root = new Group();
		Scene scene = new Scene(root, 1000, 800);
		scene.setFill(Color.color(0.2, 0.2, 0.2, 1.0));

		HBox hbox = new HBox();
		hbox.setLayoutX(75);
		hbox.setLayoutY(200);

		PhongMaterial phongMaterial = new PhongMaterial(Color.color(1.0, 0.7,
				0.8));
		Cylinder cylinder1 = new Cylinder(100, 200);
		cylinder1.setMaterial(phongMaterial);
		SubScene noMsaa = createSubScene("MSAA = false", cylinder1,
				Color.TRANSPARENT, new PerspectiveCamera(), false);
		hbox.getChildren().add(noMsaa);

		Cylinder cylinder2 = new Cylinder(100, 200);
		cylinder2.setMaterial(phongMaterial);
		SubScene msaa = createSubScene("MSAA = true", cylinder2,
				Color.TRANSPARENT, new PerspectiveCamera(), true);
		hbox.getChildren().add(msaa);

		Slider slider = new Slider(0, 360, 0);
		slider.setBlockIncrement(1);
		slider.setTranslateX(425);
		slider.setTranslateY(625);
		cylinder1.rotateProperty().bind(slider.valueProperty());
		cylinder2.rotateProperty().bind(slider.valueProperty());
		root.getChildren().addAll(hbox, slider);

		stage.setScene(scene);
		stage.show();
	}

	private static Parent setTitle(String str) {
		final VBox vbox = new VBox();
		final Text text = new Text(str);
		text.setFont(Font.font("Times New Roman", 24));
		text.setFill(Color.WHEAT);
		vbox.getChildren().add(text);
		return vbox;
	}

	private static SubScene createSubScene(String title, Node node,
			Paint fillPaint, Camera camera, boolean msaa) {
		Group root = new Group();

		PointLight light = new PointLight(Color.WHITE);
		light.setTranslateX(50);
		light.setTranslateY(-300);
		light.setTranslateZ(-400);
		PointLight light2 = new PointLight(Color.color(0.6, 0.3, 0.4));
		light2.setTranslateX(400);
		light2.setTranslateY(0);
		light2.setTranslateZ(-400);

		AmbientLight ambientLight = new AmbientLight(Color.color(0.2, 0.2, 0.2));
		node.setRotationAxis(new Point3D(2, 1, 0).normalize());
		node.setTranslateX(180);
		node.setTranslateY(180);
		root.getChildren().addAll(setTitle(title), ambientLight, light, light2,
				node);

		SubScene subScene = new SubScene(root, 500, 400, true,
				msaa ? SceneAntialiasing.BALANCED : SceneAntialiasing.DISABLED);
		subScene.setFill(fillPaint);
		subScene.setCamera(camera);

		return subScene;
	}

	/**
	 * @param args
	 *            the command line arguments
	 */
	public static void main(String[] args) {
		launch(args);
	}
}


效果如下:




 



 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值