Javafx:如何使用3D路径生成动画? [英] Javafx : How can I produce an animation with 3D path?
问题描述
我是JavaFX的新手,在尝试处理动画时遇到了问题。
我知道类 PathTransition
提供了按类 Path
在任意曲线上的两点之间移动节点的方法;但似乎所有与 PathTransition
相关的类,如 Path
和 MoveTo
和 CubicCurveTo
并包括其自身,只能在 xy 平面上工作。如果我想在 yz 平面或 xz 平面中移动节点,该怎么办?我在互联网上找不到任何关于它的信息。任何建议都将不胜感激。
如
import javafx.animation.Animation;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.ParallelTransition;
import javafx.animation.PathTransition;
import javafx.animation.PathTransition.OrientationType;
import javafx.animation.Timeline;
import javafx.animation.Transition;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.effect.Bloom;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Shape;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.util.Duration;
/ **
* @see http://stackoverflow.com/a/37370840/230513
* /
公共类Helix扩展应用程序{
私有静态最终双SIZE = 300;
私人最终内容内容= Content.create(SIZE);
public void play(){
content.animation.play();
}
private static final class Content {
private static final Duration DURATION = Duration.seconds(4);
private static final Color COLOR = Color.AQUA;
私有静态最终双倍WIDTH = 3;
private final Group group = new Group();
private final旋转rx = new旋转(0,Rotate.X_AXIS);
private final旋转ry = new Rotate(0,Rotate.Y_AXIS);
private final旋转rz = new旋转(0,Rotate.Z_AXIS);
私人决赛Box xAxis;
私人决赛Box yAxis;
私人决赛Box zAxis;
私人最终形状圈;
私人最终形状箭头;
私人最终动画动画;
private static内容创建(双倍大小){
内容c =新内容(大小);
c.group.getChildren()。addAll(c.arrow,c.circle,
c.xAxis,c.yAxis,c.zAxis);
c.group.getTransforms()。addAll(c.rz,c.ry,c.rx);
c.group.setTranslateX(-size / 2);
c.group.setTranslateY(-size / 2);
c.group.setTranslateZ(size / 2);
c.rx.setAngle(35);
c.ry.setAngle(-45);
返回c;
}
私有内容(双倍大小){
xAxis = createBox(size,WIDTH,WIDTH);
yAxis = createBox(WIDTH,size,WIDTH);
zAxis = createBox(WIDTH,WIDTH,size);
circle = createCircle(size);
arrow = createShape();
animation = new ParallelTransition(
createTransition(circle,arrow),
createTimeline(size / 2));
}
private Circle createCircle(double size){
Circle c = new Circle(size / 4);
c.setFill(Color.TRANSPARENT);
c.setStroke(COLOR);
返回c;
}
私人Box createBox(双w,双h,双d){
方框b =新方框(w,h,d);
b.setMaterial(新PhongMaterial(COLOR));
返回b;
}
private Shape createShape(){
Shape s = new Polygon(0,0,-10,-10,10,0,-10,10);
s.setStrokeWidth(WIDTH);
s.setStrokeLineCap(StrokeLineCap.ROUND);
s.setStroke(COLOR);
s.setEffect(new Bloom());
返回s;
}
private Transition createTransition(Shape path,Shape node){
PathTransition t = new PathTransition(DURATION,path,node);
t.setOrientation(OrientationType.ORTHOGONAL_TO_TANGENT);
t.setCycleCount(Timeline.INDEFINITE);
t.setInterpolator(Interpolator.LINEAR);
返回t;
}
私人时间线createTimeline(双倍大小){
时间轴t =新时间轴();
t.setCycleCount(Timeline.INDEFINITE);
t.setAutoReverse(true);
KeyValue keyX = new KeyValue(group.translateXProperty(),size);
KeyValue keyY = new KeyValue(group.translateYProperty(),size);
KeyValue keyZ = new KeyValue(group.translateZProperty(), - size);
KeyFrame keyFrame = new KeyFrame(DURATION.divide(2),keyX,keyY,keyZ);
t.getKeyFrames()。add(keyFrame);
返回t;
}
}
@Override
public void start(Stage primaryStage)抛出异常{
primaryStage.setTitle(JavaFX 3D);
场景场景=新场景(content.group,SIZE * 2,SIZE * 2,true);
primaryStage.setScene(scene);
scene.setFill(Color.BLACK);
scene.setOnMouseMoved((final MouseEvent e) - > {
content.rx.setAngle(e.getSceneY()* 360 / scene.getHeight());
content.ry。 setAngle(e.getSceneX()* 360 / scene.getWidth());
});
PerspectiveCamera camera = new PerspectiveCamera(true);
camera.setFarClip(SIZE * 6);
camera.setTranslateZ(-3 * SIZE);
scene.setCamera(相机);
scene.setOnScroll((final ScrollEvent e) - > {
camera.setTranslateZ(camera.getTranslateZ()+ e.getDeltaY());
});
primaryStage.show();
play();
}
public static void main(String [] args){
launch(args);
}
}
在此相关的
cube.setOnMouseMoved(new EventHandler< MouseEvent>( ){
@Override
public void handle(final MouseEvent e){
animation = new Timeline();
animation.getKeyFrames()。addAll(
new KeyFrame) (new Duration(2000),
new KeyValue(cube.rx.angleProperty(),e.getY()),
new KeyValue(cube.ry.angleProperty(), - e.getX() ),
新钥匙值(cube.rz.angleProperty(),e.getY())
));
animation.play();
}
});
...
pathBackFaceTransition = new PathTransition();
pathBackFaceTransition.setPath(rectangleBackFace);
...
pathFrontFaceTransition = new PathTransition();
pathFrontFaceTransition.setPath(rectangleFrontFace);
...
public void play(){
pathBackFaceTransition.play();
pathFrontFaceTransition.play();
}
最后,你可以模拟沿 x,y的运动和 z 轴使用 KeyValue
来定位比例和转换属性。再次参考
//使用工厂创建一个keyValue:缩放圈子2次
KeyValue keyValueX = new KeyValue(stack.scaleXProperty(),2);
KeyValue keyValueY = new KeyValue(stack.scaleYProperty(),2);
KeyValue keyTransX = new KeyValue(stack.translateXProperty(),100);
KeyValue keyTransY = new KeyValue(stack.translateYProperty(),100);
//创建一个keyFrame,在2s时达到keyValue
持续时间= Duration.millis(2000);
//当达到关键帧时,可以添加特定操作
EventHandler< ActionEvent> onFinished = new EventHandler< ActionEvent>(){
@Override
public void handle(ActionEvent t){
// reset counter
i = 0;
}
};
KeyFrame keyFrame = new KeyFrame(duration,onFinished,
keyValueX,keyValueY,keyTransX,keyTransY);
I'm new to JavaFX, and I encountered a problem when trying to deal with animation.
I know class PathTransition
provides methods to move a node between two points along an arbitrary curve by class Path
; but it seems that all the classes that are related to PathTransition
, like Path
and MoveTo
and CubicCurveTo
and including itself, can only work in the xy plane. What if I want to move a node in the yz plane or xz plane? I just can't find any information about it on the internet. Any advice would be appreciated.
As shown in Animation Basics, Animations
, you can compose multiple kinds of Transition
, including PathTransition
, in a SequentialTransition
or ParallelTransition
. The approach is especially convenient when the equation of motion can be expressed in parametric form. Motion along a helix, shown below, uses a ParallelTransition
to combine a PathTransition
along a Circle
with a Timeline
along a line.
animation = new ParallelTransition(
createTransition(circle, arrow),
createTimeline(size / 2));
import javafx.animation.Animation;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.ParallelTransition;
import javafx.animation.PathTransition;
import javafx.animation.PathTransition.OrientationType;
import javafx.animation.Timeline;
import javafx.animation.Transition;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.PerspectiveCamera;
import javafx.scene.Scene;
import javafx.scene.effect.Bloom;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Polygon;
import javafx.scene.shape.Shape;
import javafx.scene.shape.StrokeLineCap;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.util.Duration;
/**
* @see http://stackoverflow.com/a/37370840/230513
*/
public class Helix extends Application {
private static final double SIZE = 300;
private final Content content = Content.create(SIZE);
public void play() {
content.animation.play();
}
private static final class Content {
private static final Duration DURATION = Duration.seconds(4);
private static final Color COLOR = Color.AQUA;
private static final double WIDTH = 3;
private final Group group = new Group();
private final Rotate rx = new Rotate(0, Rotate.X_AXIS);
private final Rotate ry = new Rotate(0, Rotate.Y_AXIS);
private final Rotate rz = new Rotate(0, Rotate.Z_AXIS);
private final Box xAxis;
private final Box yAxis;
private final Box zAxis;
private final Shape circle;
private final Shape arrow;
private final Animation animation;
private static Content create(double size) {
Content c = new Content(size);
c.group.getChildren().addAll(c.arrow, c.circle,
c.xAxis, c.yAxis, c.zAxis);
c.group.getTransforms().addAll(c.rz, c.ry, c.rx);
c.group.setTranslateX(-size / 2);
c.group.setTranslateY(-size / 2);
c.group.setTranslateZ(size / 2);
c.rx.setAngle(35);
c.ry.setAngle(-45);
return c;
}
private Content(double size) {
xAxis = createBox(size, WIDTH, WIDTH);
yAxis = createBox(WIDTH, size, WIDTH);
zAxis = createBox(WIDTH, WIDTH, size);
circle = createCircle(size);
arrow = createShape();
animation = new ParallelTransition(
createTransition(circle, arrow),
createTimeline(size / 2));
}
private Circle createCircle(double size) {
Circle c = new Circle(size / 4);
c.setFill(Color.TRANSPARENT);
c.setStroke(COLOR);
return c;
}
private Box createBox(double w, double h, double d) {
Box b = new Box(w, h, d);
b.setMaterial(new PhongMaterial(COLOR));
return b;
}
private Shape createShape() {
Shape s = new Polygon(0, 0, -10, -10, 10, 0, -10, 10);
s.setStrokeWidth(WIDTH);
s.setStrokeLineCap(StrokeLineCap.ROUND);
s.setStroke(COLOR);
s.setEffect(new Bloom());
return s;
}
private Transition createTransition(Shape path, Shape node) {
PathTransition t = new PathTransition(DURATION, path, node);
t.setOrientation(OrientationType.ORTHOGONAL_TO_TANGENT);
t.setCycleCount(Timeline.INDEFINITE);
t.setInterpolator(Interpolator.LINEAR);
return t;
}
private Timeline createTimeline(double size) {
Timeline t = new Timeline();
t.setCycleCount(Timeline.INDEFINITE);
t.setAutoReverse(true);
KeyValue keyX = new KeyValue(group.translateXProperty(), size);
KeyValue keyY = new KeyValue(group.translateYProperty(), size);
KeyValue keyZ = new KeyValue(group.translateZProperty(), -size);
KeyFrame keyFrame = new KeyFrame(DURATION.divide(2), keyX, keyY, keyZ);
t.getKeyFrames().add(keyFrame);
return t;
}
}
@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("JavaFX 3D");
Scene scene = new Scene(content.group, SIZE * 2, SIZE * 2, true);
primaryStage.setScene(scene);
scene.setFill(Color.BLACK);
scene.setOnMouseMoved((final MouseEvent e) -> {
content.rx.setAngle(e.getSceneY() * 360 / scene.getHeight());
content.ry.setAngle(e.getSceneX() * 360 / scene.getWidth());
});
PerspectiveCamera camera = new PerspectiveCamera(true);
camera.setFarClip(SIZE * 6);
camera.setTranslateZ(-3 * SIZE);
scene.setCamera(camera);
scene.setOnScroll((final ScrollEvent e) -> {
camera.setTranslateZ(camera.getTranslateZ() + e.getDeltaY());
});
primaryStage.show();
play();
}
public static void main(String[] args) {
launch(args);
}
}
In this related example, the yellow shapes follow a Timeline
animation comprised of rotations of the cube's orthogonal axes, while also following a PathTransition
along the edges of a cube's face.
cube.setOnMouseMoved(new EventHandler<MouseEvent>() {
@Override
public void handle(final MouseEvent e) {
animation = new Timeline();
animation.getKeyFrames().addAll(
new KeyFrame(new Duration(2000),
new KeyValue(cube.rx.angleProperty(), e.getY()),
new KeyValue(cube.ry.angleProperty(), -e.getX()),
new KeyValue(cube.rz.angleProperty(), e.getY())
));
animation.play();
}
});
…
pathBackFaceTransition = new PathTransition();
pathBackFaceTransition.setPath(rectangleBackFace);
…
pathFrontFaceTransition = new PathTransition();
pathFrontFaceTransition.setPath(rectangleFrontFace);
…
public void play() {
pathBackFaceTransition.play();
pathFrontFaceTransition.play();
}
Finally, you can simulate motion along the x, y and z axes by using a KeyValue
that targets the scale and translate properties. Referring again to Animation Basics, the following change to TimelineEvents
creates the illusion of a 3-D shape moving to and fro.
//create a keyValue with factory: scaling the circle 2times
KeyValue keyValueX = new KeyValue(stack.scaleXProperty(), 2);
KeyValue keyValueY = new KeyValue(stack.scaleYProperty(), 2);
KeyValue keyTransX = new KeyValue(stack.translateXProperty(), 100);
KeyValue keyTransY = new KeyValue(stack.translateYProperty(), 100);
//create a keyFrame, the keyValue is reached at time 2s
Duration duration = Duration.millis(2000);
//one can add a specific action when the keyframe is reached
EventHandler<ActionEvent> onFinished = new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent t) {
//reset counter
i = 0;
}
};
KeyFrame keyFrame = new KeyFrame(duration, onFinished,
keyValueX, keyValueY, keyTransX, keyTransY);
这篇关于Javafx:如何使用3D路径生成动画?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!