JavaFX 3D围绕场景固定轴的旋转 [英] JavaFX 3D Rotation around Scene Fixed Axes
问题描述
创建虚拟轨迹球
使用JavaFX我想创建一个虚拟轨迹球设备,其中X和Y鼠标拖动事件以直观的方式旋转我的虚拟轨迹球。
Using JavaFX I want to create a virtual trackball device where X and Y mouse drag events rotate my virtual trackball in an intuitive way.
直观(至少对我来说)意味着,我的场景轴为:
Intuitive (at least to me) means, with my scene axes being:
- X从左到右增加
- Y从上到下增加
- Z垂直于屏幕朝向观看者的方向增加
我希望垂直鼠标拖动事件导致轨迹球绕
场景X轴滚动,而鼠标水平拖动事件导致轨迹球向
绕场景Y轴旋转。
I want vertical mouse drag events to cause the trackball to roll around the scene X axis, and mouse horizontal drag events to cause the trackball to rotate around the scene Y axis.
从Oracle JavaFX SmampleApp 3D开始,我已经进行了一些修改,因此我的场景
包含一个固定轴x:red,y :绿色,z:蓝色,一台在轴原点上受训的PerspectiveCamera
相机和我的轨迹球(目前是一个立方体,因此我们
可以观察它在旋转时的行为)。
Starting with the Oracle JavaFX SmampleApp 3D, I have modified things so my scene comprises a fixed axis x:red, y:green, z:blue, a camera a PerspectiveCamera trained on the axis origin, and my trackball (which, for now is a cube so we can watch how it behaves when rotated).
- 鼠标沿 X方向拖动运动,使
轨迹球绕轨迹球的y轴 - 鼠标拖动的运动
沿 Y方向,围绕
轨迹球的x轴
- Mouse dragged movement in the X direction, rotates the trackball around the trackball's y-axis
- Mouse dragged movement in the Y direction, rotates the trackball around the trackball's x-axis
首先,我将轨迹球绕Y轴旋转45度(通过水平拖动
鼠标)。然后,如果我垂直拖动鼠标,轨迹球
将绕其X轴旋转。但是,轨迹球的X轴现在已经通过上一旋转
旋转了45度,而我没有得到我想要的行为,那就是围绕固定的X轴(即,固定的红色轴)旋转轨迹球。
First I Rotate the trackball 45 degress around the Y axis (by dragging the mouse horizontally). Then if I drag the mouse vertically, the trackball rotates about it's X axis. However, the trackball's X axis has now been rotated through 45 degrees by the previous rotation, and I do not get the behaviour that I want, which is to rotate the trackball around the fixed X axis (i.e. the fixed red axis as it appears in my scene)
此代码基于以下来源的原始代码:
https://docs.oracle.com/javase/8/javafx/graphics-tutorial/sampleapp3d.htm
This code is based on original code from: https://docs.oracle.com/javase/8/javafx/graphics-tutorial/sampleapp3d.htm
XForm的代码位于 https://docs.oracle.com/javase/8/javafx/graphics-tutorial/sampleapp3d-code.htm#CJAGGIFG
The code for XForm is at https://docs.oracle.com/javase/8/javafx/graphics-tutorial/sampleapp3d-code.htm#CJAGGIFG
我需要如何更改代码以实现自己的目标?
How do I need to change my code to achieve my aims?
package moleculesampleapp;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.Shape3D;
public class MoleculeSampleApp1 extends Application {
Group root = new Group();
Xform axisXForm = new Xform();
Xform boxXForm = new Xform();
Xform worldXForm = new Xform();
Xform cameraXform = new Xform();
PhongMaterial redMaterial,greenMaterial,blueMaterial;
PerspectiveCamera camera = new PerspectiveCamera(true);
private static double CAMERA_INITIAL_DISTANCE = -450;
private static double CAMERA_INITIAL_X_ANGLE = -10.0;
private static double CAMERA_INITIAL_Y_ANGLE = 0.0;
private static double CAMERA_NEAR_CLIP = 0.1;
private static double CAMERA_FAR_CLIP = 10000.0;
private static double AXIS_LENGTH = 250.0;
private static double MOUSE_SPEED = 0.1;
private static double ROTATION_SPEED = 2.0;
double mousePosX, mousePosY;
double mouseOldX, mouseOldY;
double mouseDeltaX, mouseDeltaY;
private void handleMouse(Scene scene) {
scene.setOnMousePressed(me -> {
mousePosX = me.getSceneX();
mousePosY = me.getSceneY();
mouseOldX = me.getSceneX();
mouseOldY = me.getSceneY();
});
scene.setOnMouseDragged(me -> {
mouseOldX = mousePosX;
mouseOldY = mousePosY;
mousePosX = me.getSceneX();
mousePosY = me.getSceneY();
mouseDeltaX = (mousePosX - mouseOldX);
mouseDeltaY = (mousePosY - mouseOldY);
if (me.isPrimaryButtonDown()) {
boxXForm.ry.setAngle(boxXForm.ry.getAngle() - mouseDeltaX * MOUSE_SPEED * ROTATION_SPEED); // left right
boxXForm.rx.setAngle(boxXForm.rx.getAngle() + mouseDeltaY * MOUSE_SPEED * ROTATION_SPEED); // up down
}
});
}
private void handleKeyboard(Scene scene) {
scene.setOnKeyPressed(event -> {
switch (event.getCode()) {
case Z:
camera.setTranslateZ(CAMERA_INITIAL_DISTANCE);
cameraXform.ry.setAngle(CAMERA_INITIAL_Y_ANGLE);
cameraXform.rx.setAngle(CAMERA_INITIAL_X_ANGLE);
boxXForm.reset();
break;
}
});
}
PhongMaterial createMaterial(Color diffuseColor, Color specularColor) {
PhongMaterial material = new PhongMaterial(diffuseColor);
material.setSpecularColor(specularColor);
return material;
}
@Override
public void start(Stage primaryStage) {
root.getChildren().add(worldXForm);
root.setDepthTest(DepthTest.ENABLE);
// Create materials
redMaterial = createMaterial(Color.DARKRED,Color.RED);
greenMaterial = createMaterial(Color.DARKGREEN,Color.GREEN);
blueMaterial = createMaterial(Color.DARKBLUE,Color.BLUE);
// Build Camera
root.getChildren().add(camera);
cameraXform.getChildren().add(camera);
camera.setNearClip(CAMERA_NEAR_CLIP);
camera.setFarClip(CAMERA_FAR_CLIP);
camera.setTranslateZ(CAMERA_INITIAL_DISTANCE);
cameraXform.ry.setAngle(CAMERA_INITIAL_Y_ANGLE);
cameraXform.rx.setAngle(CAMERA_INITIAL_X_ANGLE);
// Build Axes
Box xAxis = new Box(AXIS_LENGTH, 1, 1);
Box yAxis = new Box(1, AXIS_LENGTH, 1);
Box zAxis = new Box(1, 1, AXIS_LENGTH);
xAxis.setMaterial(redMaterial);
yAxis.setMaterial(greenMaterial);
zAxis.setMaterial(blueMaterial);
axisXForm.getChildren().addAll(xAxis, yAxis, zAxis);
worldXForm.getChildren().addAll(axisXForm);
// Build shiney red box
Shape3D box = new Box(80, 80, 80);
box.setMaterial(redMaterial);
boxXForm.getChildren().add(box);
worldXForm.getChildren().addAll(boxXForm);
Scene scene = new Scene(root, 1024, 768, true);
scene.setFill(Color.GREY);
handleKeyboard(scene);
handleMouse(scene);
primaryStage.setTitle("Molecule Sample Application");
primaryStage.setScene(scene);
primaryStage.show();
scene.setCamera(camera);
}
public static void main(String[] args) {
launch(args);
}
}
推荐答案
感谢这篇文章中的bronkowitz: JavaFX 3D旋转使我走向此解决方案!
Thanks to bronkowitz in this post here: JavaFX 3D rotations for leading me towards this solution!
package moleculesampleapp;
import javafx.application.Application;
import javafx.geometry.Point3D;
import javafx.scene.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.DrawMode;
import javafx.scene.shape.Shape3D;
import javafx.scene.shape.Sphere;
import javafx.scene.transform.Affine;
import javafx.scene.transform.Rotate;
public class MoleculeSampleApp1 extends Application {
Group root = new Group();
XformBox cameraXform = new XformBox();
XformBox ballXForm = new XformBox();
Shape3D ball;
PhongMaterial redMaterial, greenMaterial, blueMaterial;
PerspectiveCamera camera = new PerspectiveCamera(true);
private static double CAMERA_INITIAL_DISTANCE = -450;
private static double CAMERA_INITIAL_X_ANGLE = -10.0;
private static double CAMERA_INITIAL_Y_ANGLE = 0.0;
private static double CAMERA_NEAR_CLIP = 0.1;
private static double CAMERA_FAR_CLIP = 10000.0;
private static double AXIS_LENGTH = 250.0;
private static double MOUSE_SPEED = 0.1;
private static double ROTATION_SPEED = 2.0;
double mouseStartPosX, mouseStartPosY;
double mousePosX, mousePosY;
double mouseOldX, mouseOldY;
double mouseDeltaX, mouseDeltaY;
private void handleMouse(Scene scene) {
System.out.printf("handleMouse%n");
scene.setOnMousePressed(me -> {
mouseStartPosX = me.getSceneX();
mouseStartPosY = me.getSceneY();
mousePosX = me.getSceneX();
mousePosY = me.getSceneY();
mouseOldX = me.getSceneX();
mouseOldY = me.getSceneY();
});
scene.setOnMouseDragged(me -> {
mouseOldX = mousePosX;
mouseOldY = mousePosY;
mousePosX = me.getSceneX();
mousePosY = me.getSceneY();
mouseDeltaX = (mousePosX - mouseOldX);
mouseDeltaY = (mousePosY - mouseOldY);
if (me.isPrimaryButtonDown()) {
ballXForm.addRotation(-mouseDeltaX * MOUSE_SPEED * ROTATION_SPEED, Rotate.Y_AXIS);
ballXForm.addRotation(mouseDeltaY * MOUSE_SPEED * ROTATION_SPEED, Rotate.X_AXIS);
}
});
}
private void handleKeyboard(Scene scene) {
scene.setOnKeyPressed(event -> ballXForm.reset());
}
PhongMaterial createMaterial(Color diffuseColor, Color specularColor) {
PhongMaterial material = new PhongMaterial(diffuseColor);
material.setSpecularColor(specularColor);
return material;
}
@Override
public void start(Stage primaryStage) {
System.out.printf("start%n");
root.setDepthTest(DepthTest.ENABLE);
// Create materials
redMaterial = createMaterial(Color.DARKRED, Color.RED);
greenMaterial = createMaterial(Color.DARKGREEN, Color.GREEN);
blueMaterial = createMaterial(Color.DARKBLUE, Color.BLUE);
// Build Camera
root.getChildren().add(camera);
cameraXform.getChildren().add(camera);
camera.setNearClip(CAMERA_NEAR_CLIP);
camera.setFarClip(CAMERA_FAR_CLIP);
camera.setTranslateZ(CAMERA_INITIAL_DISTANCE);
camera.setTranslateZ(CAMERA_INITIAL_DISTANCE);
cameraXform.addRotation(CAMERA_INITIAL_X_ANGLE, Rotate.X_AXIS);
cameraXform.addRotation(CAMERA_INITIAL_Y_ANGLE, Rotate.Y_AXIS);
// Build Axes
Box xAxis = new Box(AXIS_LENGTH, 1, 1);
Box yAxis = new Box(1, AXIS_LENGTH, 1);
Box zAxis = new Box(1, 1, AXIS_LENGTH);
xAxis.setMaterial(redMaterial);
yAxis.setMaterial(greenMaterial);
zAxis.setMaterial(blueMaterial);
root.getChildren().addAll(xAxis, yAxis, zAxis);
// Build shiney red ball
ball = new Sphere(50);
ball.setDrawMode(DrawMode.LINE); // draw mesh so we can watch how it rotates
ballXForm.getChildren().add(ball);
root.getChildren().addAll(ballXForm);
Scene scene = new Scene(root, 1024, 768, true);
scene.setFill(Color.GREY);
handleKeyboard(scene);
handleMouse(scene);
primaryStage.setTitle("TrackBall");
primaryStage.setScene(scene);
primaryStage.show();
scene.setCamera(camera);
}
public static void main(String[] args) {
launch(args);
}
}
class XformBox extends Group {
XformBox() {
super();
getTransforms().add(new Affine());
}
/**
* Accumulate rotation about specified axis
*
* @param angle
* @param axis
*/
public void addRotation(double angle, Point3D axis) {
Rotate r = new Rotate(angle, axis);
/**
* This is the important bit and thanks to bronkowitz in this post
* https://stackoverflow.com/questions/31382634/javafx-3d-rotations for
* getting me to the solution that the rotations need accumulated in
* this way
*/
getTransforms().set(0, r.createConcatenation(getTransforms().get(0)));
}
/**
* Reset transform to identity transform
*/
public void reset() {
getTransforms().set(0, new Affine());
}
}
这篇关于JavaFX 3D围绕场景固定轴的旋转的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!