Javafx:如何使用3D路径生成动画? [英] Javafx : How can I produce an animation with 3D path?

查看:197
本文介绍了Javafx:如何使用3D路径生成动画?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆