创建虚拟轨迹球
使用JavaFX我想创建一个虚拟轨迹球设备,其中X和Y鼠标拖动事件以直观的方式旋转我的虚拟轨迹球。
直观(至少对我来说)意味着,我的场景轴是:
我想要垂直鼠标拖动事件以使轨迹球在周围滚动 场景X轴和鼠标水平拖动事件导致轨迹球 围绕场景Y轴旋转。
从Oracle JavaFX SmampleApp 3D开始,我修改了我的场景 包括固定轴x:红色,y:绿色,z:蓝色,相机是PerspectiveCamera 在轴上进行训练,以及我的轨迹球(现在它是一个立方体,所以我们 可以观看它在旋转时的表现。)
首先我将轨迹球围绕Y轴旋转45度(通过拖动 鼠标水平)。然后,如果我垂直拖动鼠标,轨迹球 围绕它的X轴旋转。然而,轨迹球的X轴现在已经存在 前一次旋转旋转45度,我没有得到我想要的行为,即围绕固定的X轴旋转轨迹球(即我场景中出现的固定红轴)
此代码基于以下原始代码: 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
我如何更改代码以实现目标?
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);
}
}
答案 0 :(得分:1)
感谢这篇文章中的bronkowitz:JavaFX 3D rotations带领我走向这个解决方案!
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());
}
}
答案 1 :(得分:0)
如果我正确理解你的问题,你唯一要做的就是更换这一行。
Xform cameraXform = new Xform(RotateOrder.ZYX);
这会改变单个旋转的旋转顺序,并且应该为您提供所需的内容。