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

问题描述

我是 JavaFX 的新手,在尝试处理动画时遇到了问题.我知道 class PathTransition 提供了通过 class Path 沿着任意曲线在两点之间移动节点的方法;但似乎所有与 PathTransition 相关的类,如 PathMoveToCubicCurveTo 并包括它自己, 只能在 xy 平面上工作.如果我想在 yz 平面或 xz 平面中移动节点怎么办?我只是在互联网上找不到任何关于它的信息.任何建议将不胜感激.

解决方案

import javafx.animation.Animation;导入 javafx.animation.Interpolator;导入 javafx.animation.KeyFrame;导入 javafx.animation.KeyValue;导入 javafx.animation.ParallelTransition;导入 javafx.animation.PathTransition;导入 javafx.animation.PathTransition.OrientationType;导入 javafx.animation.Timeline;导入 javafx.animation.Transition;导入 javafx.application.Application;导入 javafx.scene.Group;导入 javafx.scene.PerspectiveCamera;导入 javafx.scene.Scene;导入 javafx.scene.effect.Bloom;导入 javafx.scene.input.MouseEvent;导入 javafx.scene.input.ScrollEvent;导入 javafx.scene.paint.Color;导入 javafx.scene.paint.PhongMaterial;导入 javafx.scene.shape.Box;导入 javafx.scene.shape.Circle;导入 javafx.scene.shape.Polygon;导入 javafx.scene.shape.Shape;导入 javafx.scene.shape.StrokeLineCap;导入 javafx.scene.transform.Rotate;导入 javafx.stage.Stage;导入 javafx.util.Duration;/*** @see http://stackoverflow.com/a/37370840/230513*/公共类螺旋扩展应用程序{私有静态最终双大小 = 300;私有最终内容内容 = Content.create(SIZE);公共无效播放(){content.animation.play();}私有静态最终类内容{私有静态最终持续时间 DURATION = Duration.seconds(4);private static final Color COLOR = Color.AQUA;私有静态最终双 WIDTH = 3;私人最终组组=新组();私人最终旋转 rx = new Rotate(0, Rotate.X_AXIS);私人最终旋转 ry = new Rotate(0, Rotate.Y_AXIS);私人最终旋转 rz = new Rotate(0, Rotate.Z_AXIS);私人最终 Box xAxis;私人最终框 yAxis;私人最终盒 zAxis;私人最终形状圈;私人最终形状箭头;私人最终动画动画;私有静态内容创建(双倍大小){内容 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(大小/2);c.rx.setAngle(35);c.ry.setAngle(-45);返回 c;}私人内容(双倍大小){xAxis = createBox(大小,宽度,宽度);yAxis = createBox(WIDTH, size, WIDTH);zAxis = createBox(WIDTH, WIDTH, size);圆 = 创建圆(大小);箭头 = createShape();动画 = 新的 ParallelTransition(createTransition(圆圈,箭头),创建时间线(大小/2));}私人圈 createCircle(双倍大小){圆 c = 新圆(大小/4);c.setFill(颜色.透明);c.setStroke(COLOR);返回 c;}私人盒子 createBox(双 w,双 h,双 d){框 b = 新框 (w, h, d);b.setMaterial(new PhongMaterial(COLOR));返回 b;}私有形状 createShape() {Shape s = new Polygon(0, 0, -10, -10, 10, 0, -10, 10);s.setStrokeWidth(WIDTH);s.setStrokeLineCap(StrokeLineCap.ROUND);s.setStroke(颜色);s.setEffect(new Bloom());返回 s;}私有过渡 createTransition(形状路径,形状节点){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;}}@覆盖public void start(Stage primaryStage) 抛出异常 {primaryStage.setTitle("JavaFX 3D");场景场景 = 新场景(内容组,大小 * 2,大小 * 2,真);primaryStage.setScene(场景);场景.setFill(颜色.黑色);scene.setOnMouseMoved((final MouseEvent e) -> {content.rx.setAngle(e.getSceneY() * 360/scene.getHeight());content.ry.setAngle(e.getSceneX() * 360/scene.getWidth());});PerspectiveCamera 相机 = new PerspectiveCamera(true);camera.setFarClip(SIZE * 6);相机.setTranslateZ(-3 * SIZE);场景.setCamera(相机);scene.setOnScroll((final ScrollEvent e) -> {camera.setTranslateZ(camera.getTranslateZ() + e.getDeltaY());});primaryStage.show();玩();}公共静态无效主(字符串 [] args){发射(参数);}}

在这个相关的

cube.setOnMouseMoved(new EventHandler() {@覆盖公共无效句柄(最终鼠标事件 e){动画 = 新时间线();animation.getKeyFrames().addAll(新的关键帧(新的持续时间(2000),新 KeyValue(cube.rx.angleProperty(), e.getY()),新 KeyValue(cube.ry.angleProperty(), -e.getX()),新的 KeyValue(cube.rz.angleProperty(), e.getY())));动画播放();}});…pathBackFaceTransition = new PathTransition();pathBackFaceTransition.setPath(rectangleBackFace);…pathFrontFaceTransition = new PathTransition();pathFrontFaceTransition.setPath(rectangleFrontFace);…公共无效播放(){pathBackFaceTransition.play();pathFrontFaceTransition.play();}

最后,您可以使用针对缩放和平移属性的 KeyValue 模拟沿 x、yz 轴的运动.再次参考

//用工厂创建一个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,keyValue在时间2s到达持续时间 = Duration.millis(2000);//可以在到达关键帧时添加特定动作EventHandleronFinished = new EventHandler() {@覆盖公共无效句柄(ActionEvent t){//重置计数器我 = 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 路径的动画?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-01 23:21