Javafx:如何使用3D路径生成动画?

时间:2016-05-21 18:22:47

标签: animation javafx

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

1 个答案:

答案 0 :(得分:4)

Animation BasicsAnimations所示,您可以在{{1}中撰写多种Transition,包括PathTransition }或SequentialTransition。当运动方程可以用parametric form表示时,该方法特别方便。沿helix移动,如下所示,使用ParallelTransitionParallelTransition沿PathTransitionCircle沿着一条线组合。

Timeline

image

animation = new ParallelTransition(
    createTransition(circle, arrow),
    createTimeline(size / 2));

在这个相关的example中,黄色形状遵循一个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); } } 动画,该动画由立方体正交轴的旋转组成,同时沿着立方体面的边缘跟随Timeline。 / p>

image

PathTransition

最后,您可以使用定位缩放和平移属性的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(); } 来模拟沿 x,y z 轴的运动。再次提到Animation Basics,对KeyValue的以下更改会产生三维形状来回移动的错觉。

image

TimelineEvents