创建虚拟轨迹球
使用 JavaFX 我想创建一个虚拟轨迹球设备,其中 X 和 Y 鼠标拖动事件以直观的方式旋转我的虚拟轨迹球。
直观(至少对我而言)意味着,我的场景轴是:
- X 从左到右递增
- Y 从上到下递增
- Z 垂直于屏幕朝向观察者增加
我希望垂直鼠标拖动事件使轨迹球围绕场景 X 轴滚动,并希望鼠标水平拖动事件使轨迹球围绕场景 Y 轴旋转。
从 Oracle JavaFX SmampleApp 3D 开始,我已经修改了一些东西,所以我的场景包括一个固定轴 x:red、y:green、z:blue、一个在轴原点上训练的 PerspectiveCamera 相机和我的轨迹球(现在是一个立方体,以便我们可以观察它在旋转时的行为)。
- 鼠标在X 方向拖动移动,围绕轨迹球的 y 轴旋转轨迹球
- 鼠标在Y 方向拖动移动,围绕 轨迹球的 x 轴旋转轨迹球
首先,我将轨迹球绕 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);
}
}