在 javaFX 中围绕枢轴旋转对象
Rotate an object about a pivot in javaFX
我正在尝试在 javaFX 中创建一个 Rubik 的立方体,但我正在努力处理面的旋转。到目前为止,我只是将一个面中的 9 个立方体添加到一个组中,然后旋转 90 度以使整个面以正确的方式旋转,但是这种方法似乎不适用于多次旋转。
相反,我想围绕每个面中心的轴心点旋转每个立方体。为此,我尝试使用 Rotate classes 内置的 pivot 参数,但它似乎对旋转没有影响。这是我用来旋转正面的函数的简化版本,其中二维数组 frontFace 包含正面中从左上角到右下角的所有立方体:
public void rotate() {
Rotate r = new Rotate(45, 0, 0, -100, Rotate.Z_AXIS);
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
frontFace[x][y].getCube().getTransforms().add(r);
}
}
}
这会产生以下结果(我已将其旋转 45 度以便更容易看到):
Current Rotation
而我希望它像这样旋转:
Ideal rotation
这是我第一个使用 javaFX 的项目,如有任何帮助,我们将不胜感激!到目前为止的完整项目可以在这里找到:
编辑:
我被要求包括一个最小的、可重现的例子,所以我试图将问题浓缩成一个 class 希望不会混淆,这里是代码:
import javafx.application.Application;
import javafx.geometry.Point3D;
import javafx.scene.AmbientLight;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.DrawMode;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.TriangleMesh;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
public class Example extends Application {
public static final float X_RED = 0.5f / 7f;
public static final float X_GREEN = 1.5f / 7f;
public static final float X_BLUE = 2.5f / 7f;
public static final float X_YELLOW = 3.5f / 7f;
public static final float X_ORANGE = 4.5f / 7f;
public static final float X_WHITE = 5.5f / 7f;
public static final float X_GRAY = 6.5f / 7f;
public static int red = 0;
public static int green = 1;
public static int blue = 2;
public static int yellow = 3;
public static int orange = 4;
public static int white = 5;
public static int grey = 6;
public static int WIDTH = 1400;
public static int HEIGHT = 800;
private static final SmartGroup MainCubeGroup = new SmartGroup();
private static PhongMaterial mat = new PhongMaterial();
MeshView[][] frontFace = new MeshView[3][3];
@Override
public void start(Stage primaryStage) {
ViewCamera camera = new ViewCamera(MainCubeGroup);
mat.setDiffuseMap(new Image(getClass().getResourceAsStream("pallete.png")));
MainCubeGroup.getChildren().addAll(new AmbientLight(Color.WHITE));
Scene scene = new Scene(MainCubeGroup, WIDTH, HEIGHT, true);
//creates just frontFace of cube
frontFace[0][0] = createCube(new Point3D(-100, -100, -100), new int[]{blue, grey, white, grey, red, grey});
frontFace[0][1] = createCube(new Point3D(0, -100, -100), new int[]{blue, grey, white, grey, grey, grey});
frontFace[0][2] = createCube(new Point3D(100, -100, -100), new int[] {blue, green, white, grey, grey, grey});
frontFace[1][0] = createCube(new Point3D(-100, 0, -100), new int[]{blue, grey, grey, grey, red, grey});
frontFace[1][1] = createCube(new Point3D(0, 0, -100), new int[]{blue, grey, grey, grey, grey, grey});
frontFace[1][2] = createCube(new Point3D(100, 0, -100), new int[]{blue, green, grey, grey, grey, grey});
frontFace[2][0] = createCube(new Point3D(-100, 100, -100), new int[]{blue, grey, grey, grey, red, yellow});
frontFace[2][1] = createCube(new Point3D(0, 100, -100), new int[]{blue, grey, grey, grey, grey, yellow});
frontFace[2][2] = createCube(new Point3D(100, 100, -100), new int[]{blue, green, grey, grey, grey, yellow});
rotate(45);
scene.setFill(Color.BLANCHEDALMOND);
scene.setCamera(camera);
primaryStage.setTitle("DDD");
primaryStage.setScene(scene);
MainCubeGroup.translateXProperty().set(WIDTH / 2);
MainCubeGroup.translateYProperty().set(HEIGHT / 2);
primaryStage.show();
camera.initMouseControl(scene, primaryStage);
}
public static void main(String[] args) {launch(args);}
public void rotate(int angle) {
Rotate r = new Rotate(angle, 0, 0, -100, Rotate.Z_AXIS);
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
frontFace[x][y].getTransforms().add(r);
}
}
}
public static MeshView createCube(Point3D position, int[] face){
int sideLength = 90;
TriangleMesh meshCube = new TriangleMesh();
meshCube.getTexCoords().addAll(
X_RED, 0.5f,
X_GREEN, 0.5f,
X_BLUE, 0.5f,
X_YELLOW, 0.5f,
X_ORANGE, 0.5f,
X_WHITE, 0.5f,
X_GRAY, 0.5f
);
meshCube.getPoints().addAll(
sideLength/2, sideLength/2, sideLength/2, //point0
sideLength/2, -sideLength/2, sideLength/2, //point1
sideLength/2, sideLength/2, -sideLength/2, //point2
sideLength/2, -sideLength/2, -sideLength/2, //point3
-sideLength/2, sideLength/2, sideLength/2, //point4
-sideLength/2, -sideLength/2, sideLength/2, //point5
-sideLength/2, sideLength/2, -sideLength/2, //point6
-sideLength/2, -sideLength/2, -sideLength/2 //point7
);
//textures
meshCube.getFaces().addAll(
2,face[0],3,face[0],6,face[0], // F
3,face[0],7,face[0],6,face[0],
0,face[1],1,face[1],2,face[1], // R
2,face[1],1,face[1],3,face[1],
1,face[2],5,face[2],3,face[2], // U
5,face[2],7,face[2],3,face[2],
0,face[3],4,face[3],1,face[3], // B
4,face[3],5,face[3],1,face[3],
4,face[4],6,face[4],5,face[4], // L
6,face[4],7,face[4],5,face[4],
0,face[5],2,face[5],4,face[5], // D
2,face[5],6,face[5],4,face[5]
);
MeshView cube = new MeshView(meshCube);
cube.setDrawMode(DrawMode.FILL);
cube.setMaterial(mat);
cube.setTranslateX(position.getX());
cube.setTranslateY(position.getY());
cube.setTranslateZ(position.getZ());
MainCubeGroup.getChildren().add(cube);
return cube;
}
}
这是图像,pallete.png 如果您想要颜色,可以在代码中使用它,但我认为它与问题无关:
pallete.png
谢谢。
当您将 Rotate 对象 r
附加到 frontFace 节点时,每个这样的节点都会在该节点自己的坐标系中解释 Rotate 对象的坐标。每个立方体都在自己的坐标系中将其中心定义为 (0, 0, -100),因此围绕该轴心点旋转也会使立方体围绕其自己的中心旋转。
你想要的是所有的正面节点都围绕同一坐标系中的一个轴心点旋转——它们的父组的坐标系。
然后您可以使用 parentToLocal 方法重复将该轴心点转换为每个 frontFace 的坐标系,并根据该“本地”轴心点应用一个新的 Rotate 实例。
public void rotate(int angle) {
// These coordinates are in the parent Group's coordinate system.
Point3D pivot = new Point3D(0, 0, -100);
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
Node cube = frontFace[x][y];
Point3D localPivot = cube.parentToLocal(pivot);
Rotate r = new Rotate(angle,
localPivot.getX(), localPivot.getY(), localPivot.getZ(),
Rotate.Z_AXIS);
cube.getTransforms().add(r);
}
}
}
我正在尝试在 javaFX 中创建一个 Rubik 的立方体,但我正在努力处理面的旋转。到目前为止,我只是将一个面中的 9 个立方体添加到一个组中,然后旋转 90 度以使整个面以正确的方式旋转,但是这种方法似乎不适用于多次旋转。
相反,我想围绕每个面中心的轴心点旋转每个立方体。为此,我尝试使用 Rotate classes 内置的 pivot 参数,但它似乎对旋转没有影响。这是我用来旋转正面的函数的简化版本,其中二维数组 frontFace 包含正面中从左上角到右下角的所有立方体:
public void rotate() {
Rotate r = new Rotate(45, 0, 0, -100, Rotate.Z_AXIS);
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
frontFace[x][y].getCube().getTransforms().add(r);
}
}
}
这会产生以下结果(我已将其旋转 45 度以便更容易看到):
Current Rotation
而我希望它像这样旋转:
Ideal rotation
这是我第一个使用 javaFX 的项目,如有任何帮助,我们将不胜感激!到目前为止的完整项目可以在这里找到:
编辑: 我被要求包括一个最小的、可重现的例子,所以我试图将问题浓缩成一个 class 希望不会混淆,这里是代码:
import javafx.application.Application;
import javafx.geometry.Point3D;
import javafx.scene.AmbientLight;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.DrawMode;
import javafx.scene.shape.MeshView;
import javafx.scene.shape.TriangleMesh;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
public class Example extends Application {
public static final float X_RED = 0.5f / 7f;
public static final float X_GREEN = 1.5f / 7f;
public static final float X_BLUE = 2.5f / 7f;
public static final float X_YELLOW = 3.5f / 7f;
public static final float X_ORANGE = 4.5f / 7f;
public static final float X_WHITE = 5.5f / 7f;
public static final float X_GRAY = 6.5f / 7f;
public static int red = 0;
public static int green = 1;
public static int blue = 2;
public static int yellow = 3;
public static int orange = 4;
public static int white = 5;
public static int grey = 6;
public static int WIDTH = 1400;
public static int HEIGHT = 800;
private static final SmartGroup MainCubeGroup = new SmartGroup();
private static PhongMaterial mat = new PhongMaterial();
MeshView[][] frontFace = new MeshView[3][3];
@Override
public void start(Stage primaryStage) {
ViewCamera camera = new ViewCamera(MainCubeGroup);
mat.setDiffuseMap(new Image(getClass().getResourceAsStream("pallete.png")));
MainCubeGroup.getChildren().addAll(new AmbientLight(Color.WHITE));
Scene scene = new Scene(MainCubeGroup, WIDTH, HEIGHT, true);
//creates just frontFace of cube
frontFace[0][0] = createCube(new Point3D(-100, -100, -100), new int[]{blue, grey, white, grey, red, grey});
frontFace[0][1] = createCube(new Point3D(0, -100, -100), new int[]{blue, grey, white, grey, grey, grey});
frontFace[0][2] = createCube(new Point3D(100, -100, -100), new int[] {blue, green, white, grey, grey, grey});
frontFace[1][0] = createCube(new Point3D(-100, 0, -100), new int[]{blue, grey, grey, grey, red, grey});
frontFace[1][1] = createCube(new Point3D(0, 0, -100), new int[]{blue, grey, grey, grey, grey, grey});
frontFace[1][2] = createCube(new Point3D(100, 0, -100), new int[]{blue, green, grey, grey, grey, grey});
frontFace[2][0] = createCube(new Point3D(-100, 100, -100), new int[]{blue, grey, grey, grey, red, yellow});
frontFace[2][1] = createCube(new Point3D(0, 100, -100), new int[]{blue, grey, grey, grey, grey, yellow});
frontFace[2][2] = createCube(new Point3D(100, 100, -100), new int[]{blue, green, grey, grey, grey, yellow});
rotate(45);
scene.setFill(Color.BLANCHEDALMOND);
scene.setCamera(camera);
primaryStage.setTitle("DDD");
primaryStage.setScene(scene);
MainCubeGroup.translateXProperty().set(WIDTH / 2);
MainCubeGroup.translateYProperty().set(HEIGHT / 2);
primaryStage.show();
camera.initMouseControl(scene, primaryStage);
}
public static void main(String[] args) {launch(args);}
public void rotate(int angle) {
Rotate r = new Rotate(angle, 0, 0, -100, Rotate.Z_AXIS);
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
frontFace[x][y].getTransforms().add(r);
}
}
}
public static MeshView createCube(Point3D position, int[] face){
int sideLength = 90;
TriangleMesh meshCube = new TriangleMesh();
meshCube.getTexCoords().addAll(
X_RED, 0.5f,
X_GREEN, 0.5f,
X_BLUE, 0.5f,
X_YELLOW, 0.5f,
X_ORANGE, 0.5f,
X_WHITE, 0.5f,
X_GRAY, 0.5f
);
meshCube.getPoints().addAll(
sideLength/2, sideLength/2, sideLength/2, //point0
sideLength/2, -sideLength/2, sideLength/2, //point1
sideLength/2, sideLength/2, -sideLength/2, //point2
sideLength/2, -sideLength/2, -sideLength/2, //point3
-sideLength/2, sideLength/2, sideLength/2, //point4
-sideLength/2, -sideLength/2, sideLength/2, //point5
-sideLength/2, sideLength/2, -sideLength/2, //point6
-sideLength/2, -sideLength/2, -sideLength/2 //point7
);
//textures
meshCube.getFaces().addAll(
2,face[0],3,face[0],6,face[0], // F
3,face[0],7,face[0],6,face[0],
0,face[1],1,face[1],2,face[1], // R
2,face[1],1,face[1],3,face[1],
1,face[2],5,face[2],3,face[2], // U
5,face[2],7,face[2],3,face[2],
0,face[3],4,face[3],1,face[3], // B
4,face[3],5,face[3],1,face[3],
4,face[4],6,face[4],5,face[4], // L
6,face[4],7,face[4],5,face[4],
0,face[5],2,face[5],4,face[5], // D
2,face[5],6,face[5],4,face[5]
);
MeshView cube = new MeshView(meshCube);
cube.setDrawMode(DrawMode.FILL);
cube.setMaterial(mat);
cube.setTranslateX(position.getX());
cube.setTranslateY(position.getY());
cube.setTranslateZ(position.getZ());
MainCubeGroup.getChildren().add(cube);
return cube;
}
}
这是图像,pallete.png 如果您想要颜色,可以在代码中使用它,但我认为它与问题无关: pallete.png
谢谢。
当您将 Rotate 对象 r
附加到 frontFace 节点时,每个这样的节点都会在该节点自己的坐标系中解释 Rotate 对象的坐标。每个立方体都在自己的坐标系中将其中心定义为 (0, 0, -100),因此围绕该轴心点旋转也会使立方体围绕其自己的中心旋转。
你想要的是所有的正面节点都围绕同一坐标系中的一个轴心点旋转——它们的父组的坐标系。
然后您可以使用 parentToLocal 方法重复将该轴心点转换为每个 frontFace 的坐标系,并根据该“本地”轴心点应用一个新的 Rotate 实例。
public void rotate(int angle) {
// These coordinates are in the parent Group's coordinate system.
Point3D pivot = new Point3D(0, 0, -100);
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
Node cube = frontFace[x][y];
Point3D localPivot = cube.parentToLocal(pivot);
Rotate r = new Rotate(angle,
localPivot.getX(), localPivot.getY(), localPivot.getZ(),
Rotate.Z_AXIS);
cube.getTransforms().add(r);
}
}
}