JavaFX8三维动画
我正在做一个小JavaFX8项目。我需要一些关于如何正确制作动画的建议。关于这个项目。这是一个使带电粒子在磁场中流动的程序。所有需要的值都取自GUI,用户将它们放入文本字段中。单击按钮后,我们将被转移到3D场景,其中我的点显示为球体,所有值都已设置。字段行被打印在它的目录中 问题是如何制作propper动画。我试图使用我的球体X Y Z坐标,但找不到任何方法来设置这些坐标。Z平面中的运动应为线性,且速度相同。而XY平面中的运动应该是圆形的。我可以用路径转换来完成吗JavaFX8三维动画,java,animation,javafx,3d,Java,Animation,Javafx,3d,我正在做一个小JavaFX8项目。我需要一些关于如何正确制作动画的建议。关于这个项目。这是一个使带电粒子在磁场中流动的程序。所有需要的值都取自GUI,用户将它们放入文本字段中。单击按钮后,我们将被转移到3D场景,其中我的点显示为球体,所有值都已设置。字段行被打印在它的目录中 问题是如何制作propper动画。我试图使用我的球体X Y Z坐标,但找不到任何方法来设置这些坐标。Z平面中的运动应为线性,且速度相同。而XY平面中的运动应该是圆形的。我可以用路径转换来完成吗 我的愿景是创建勾号动画,通过路
我的愿景是创建勾号动画,通过路径绘制球体。在进一步勾选的地方,下一个球体将使用平移向量计算的新坐标绘制。这是否可能使用路径转换?不,在javafx中,路径是二维的,但您需要三维移动 注意,球面坐标也不是描述这种运动的好坐标系,因为角度的计算有点复杂 更适合的坐标系是圆柱坐标 您可以使用多个变换,并使用
时间轴
动画设置这些变换的动画,以实现这种运动:
private static void animateSphere(Sphere sphere) {
Rotate rot = new Rotate();
Translate radiusTranslate = new Translate(50, 0, 0);
Translate zMovement = new Translate();
sphere.getTransforms().setAll(zMovement, rot, radiusTranslate);
Timeline tl = new Timeline(
new KeyFrame(Duration.ZERO,
new KeyValue(zMovement.zProperty(), 0d),
new KeyValue(rot.angleProperty(), 0d)),
new KeyFrame(Duration.seconds(4),
new KeyValue(zMovement.zProperty(), 900d, Interpolator.LINEAR),
new KeyValue(rot.angleProperty(), 720, Interpolator.LINEAR))
);
tl.setCycleCount(Timeline.INDEFINITE);
tl.play();
}
@Override
public void start(Stage primaryStage) {
Sphere sphere = new Sphere(30);
Pane root = new Pane(sphere);
Scene scene = new Scene(root, 400, 400, true);
PerspectiveCamera camera = new PerspectiveCamera();
camera.setTranslateZ(-10);
camera.setTranslateX(-500);
camera.setTranslateY(-200);
camera.setRotationAxis(new Point3D(0, 1, 0));
camera.setRotate(45);
scene.setCamera(camera);
animateSphere(sphere);
primaryStage.setScene(scene);
primaryStage.show();
}
您的运动是螺旋运动,因此以下变换组合将适当地移动球体
:
变换列表中出现的顺序相反
或者,您可以编写可与圆柱体坐标参数一起使用的辅助对象,并编写相应的x
、y
和z
值:
public class CylinderCoordinateAdapter {
private final DoubleProperty theta = new SimpleDoubleProperty();
private final DoubleProperty radius = new SimpleDoubleProperty();
private final DoubleProperty h = new SimpleDoubleProperty();
private static final Point3D DEFAULT_AXIS = new Point3D(0, 0, 1);
private Point3D axis2;
private Point3D axis3;
private final ObjectProperty<Point3D> axis = new SimpleObjectProperty<Point3D>() {
@Override
public void set(Point3D newValue) {
newValue = (newValue == null || newValue.equals(Point3D.ZERO)) ? DEFAULT_AXIS : newValue.normalize();
// find first value ortogonal to axis with z = 0
axis2 = newValue.getX() == 0 && newValue.getY() == 0 ? new Point3D(1, 0, 0) : new Point3D(-newValue.getY(), newValue.getX(), 0).normalize();
// find axis ortogonal to the other 2
axis3 = newValue.crossProduct(axis2);
super.set(newValue);
}
};
public CylinderCoordinateAdapter(WritableValue<Number> x, WritableValue<Number> y, WritableValue<Number> z) {
Objects.requireNonNull(x);
Objects.requireNonNull(y);
Objects.requireNonNull(z);
axis.set(DEFAULT_AXIS);
InvalidationListener listener = o -> {
Point3D ax = axis.get();
double h = getH();
double theta = getTheta();
double r = getRadius();
Point3D endPoint = ax.multiply(h).add(axis2.multiply(Math.cos(theta) * r)).add(axis3.multiply(Math.sin(theta) * r));
x.setValue(endPoint.getX());
y.setValue(endPoint.getY());
z.setValue(endPoint.getZ());
};
theta.addListener(listener);
radius.addListener(listener);
h.addListener(listener);
axis.addListener(listener);
listener.invalidated(null);
}
public final Point3D getAxis() {
return this.axis.get();
}
public final void setAxis(Point3D value) {
this.axis.set(value);
}
public final ObjectProperty<Point3D> axisProperty() {
return this.axis;
}
public final double getH() {
return this.h.get();
}
public final void setH(double value) {
this.h.set(value);
}
public final DoubleProperty hProperty() {
return this.h;
}
public final double getRadius() {
return this.radius.get();
}
public final void setRadius(double value) {
this.radius.set(value);
}
public final DoubleProperty radiusProperty() {
return this.radius;
}
public final double getTheta() {
return this.theta.get();
}
public final void setTheta(double value) {
this.theta.set(value);
}
public final DoubleProperty thetaProperty() {
return this.theta;
}
}
非常感谢你!你会在这里回答我进一步的问题吗?@LucasPG如果是关于这个答案的问题,就写一条评论。如果是新问题:我通常每天回答几个问题。如果你写了一个问题,它写得很好,很有趣,没有足够高质量的答案,我知道答案,我可能会发布它。。。不过,也有其他相当有能力的用户可以回答您的问题…您好。在我的应用程序中,用户输入所有neded值。我已经计算了圆周运动的半径,还有XY平面上的速度和通过Z轴的速度。如何将所有这3个值放入animateSphere函数,使移动与用户值兼容?@LucasPG变换以递减的索引顺序应用。第一个将球体从原点移开,这意味着您需要将50
替换为半径。下一个变换是旋转,以将节点移动到x/y窗格中的正确角度。可以使用360*V_xy/(2*PI*r)
计算角速度。最后一个变换沿z方向移动球体。最后两个值通过在给定值之间插值为两帧设置动画。考虑到上述值,找出合适的时间跨度并计算起始和结束时的VAL应该不会太难。我已经计算了所有值。我把半径改为50,把Vz改为900d,把Vxy改为720。这是正确的思维方式吗?
private static void animateSphere(Sphere sphere) {
CylinderCoordinateAdapter adapter = new CylinderCoordinateAdapter(
sphere.translateXProperty(),
sphere.translateYProperty(),
sphere.translateZProperty());
adapter.setRadius(50);
Timeline tl = new Timeline(
new KeyFrame(Duration.ZERO,
new KeyValue(adapter.hProperty(), 0d),
new KeyValue(adapter.thetaProperty(), 0d)),
new KeyFrame(Duration.seconds(4),
new KeyValue(adapter.hProperty(), 900d, Interpolator.LINEAR),
new KeyValue(adapter.thetaProperty(), Math.PI * 4, Interpolator.LINEAR))
);
tl.setCycleCount(Timeline.INDEFINITE);
tl.play();
}