layout - 如何像 JavaFX 2.0 演示中那样创建视频墙?

标签 layout javafx javafx-3d

如何像此处的 JavaFX 2.0 演示那样创建视频墙:

https://www.youtube.com/watch?v=UXSmJYFrulY#t=411

首先,它不一定是视频,也可以是图像。我想要的只是像视频中那样放置节点,i。 e.呈弯曲形状,如圆柱体或球体的内部。

或者该演示的源代码在某处可用?

非常感谢。

最佳答案

我研究并找到了一个非常棒的网站,其中包含相关信息:

http://paulbourke.net/geometry/transformationprojection/

相关部分是坐标系转换,特别是笛卡尔坐标和球坐标之间的转换方程。

double x = r * Math.sin(angle1) * Math.cos(angle2);
double y = r * Math.sin(angle1) * Math.sin(angle2);
double z = r * Math.cos(angle1);

在我下面的示例中,公式中没有使用 y,因为图像行是堆叠的。

注意:通过在从 -Math.PI 到 Math.PI 的 2 个嵌套 for 循环中使用这些公式,您可以围绕球体布置节点。关于整个球体的困难部分是将节点旋转到中心,这是我无法弄清楚的。

因为我不熟悉 Java3D,所以我也查看了 Building a 3D Sample Application .

最后搞了个拼接墙,代码缩减成这样:

public class VideoWall extends Application {

    Random rand = new Random();

    Group root = new Group();
    PerspectiveCamera camera;

    private static final double CAMERA_INITIAL_DISTANCE = -850;
    private static final double CAMERA_NEAR_CLIP = 0.1;
    private static final double CAMERA_FAR_CLIP = 10000.0;

    Image[] images = new Image[] {
            new Image("http://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Siberischer_tiger_de_edit02.jpg/320px-Siberischer_tiger_de_edit02.jpg"),
            new Image("http://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/White_Lion.jpg/320px-White_Lion.jpg"),
            new Image("http://upload.wikimedia.org/wikipedia/commons/thumb/4/47/Lion_female.jpg/319px-Lion_female.jpg")

    };

    public VideoWall(){

    }
    public static void main(String[] args) {
        launch(args);
    }

    /**
     * Create ImageView with random Image.
     * @return
     */
    private ImageView createImageView() {

        Image image = images[ rand.nextInt(images.length)];

        ImageView c = new ImageView( image);

        c.setFitWidth(140);
        c.setFitWidth(100);
        c.setPreserveRatio(true);

        return c;
    }

    @Override
    public void start(Stage primaryStage) {

        // build camera
        camera = new PerspectiveCamera(true);
        camera.setNearClip(CAMERA_NEAR_CLIP);
        camera.setFarClip(CAMERA_FAR_CLIP);
        camera.setTranslateZ(CAMERA_INITIAL_DISTANCE);

        // we display any node (imageview, webview, etc)
        Node node;

        // create a single webview; we only add it once because we don't want to flood youtube
        WebView webView = new WebView();
        webView.getEngine().load(
          "http://www.youtube.com/embed/utUPth77L_o?autoplay=1"
        );
        webView.setPrefSize(100, 70);

        // wall. the degrees depend on the distance, image size, translate start points, etc. so these values were just as they fit
        double ringBeginDeg = -30;
        double ringEndDeg = 38;

        double r = 1300; 
        double yOffset = 80; // offset per image row
        double yOffsetInitial = 120; // initial y offset from "floor"

        int count=0;

        for( double angle1=Math.toRadians(ringBeginDeg); angle1 <Math.toRadians(ringEndDeg); angle1+=0.08)
        {

            double angle2 = Math.PI;

            for( int i=-3; i <= 3; i++)
            {

                double x = r * Math.sin(angle1) * Math.cos(angle2);
                // double y = r * Math.sin(angle1) * Math.sin(angle2);
                double z = r * Math.cos(angle1);

                // add 1 webview, the rest imageviews 
                if( count == 16) {
                    node = webView;
                } else {
                    node = createImageView();
                }

                node.setTranslateX(x);
                node.setTranslateY(yOffset * i - yOffsetInitial);
                node.setTranslateZ(z);

                // rotate towards viewer position
                Rotate rx = new Rotate();
                rx.setAxis(Rotate.Y_AXIS);
                rx.setAngle(Math.toDegrees( -angle1));

                node.getTransforms().addAll(rx);

                root.getChildren().add( node);

                count++;
            }

        }

        Scene scene = new Scene(root, 1600, 900, Color.BLACK);

        primaryStage.setScene( scene);
        primaryStage.show();

        scene.setCamera(camera);
    }

}

您可以添加您喜欢的任何节点。我添加了一个 youtube webview 进行测试。它播放,但视频没有加载,所以你看到的只是静态噪音(屏幕截图中的灰色方 block )。所以从理论上讲,您可以使用 youtube 视频使节点成为所有 webview,但这意味着充斥 youtube。最好使用一些离线视频。

截图如下:

enter image description here

我还玩弄了完整的 3d 示例并创建了一个戒指。这就是它从外部 View 看起来的样子(始终具有相同的图像):

enter image description here

将相机放在中央,您可以很好地滚动环。

如果有人想玩,here's a quick & dirty gist with the navigable ring .使用鼠标左/右/中键进行导航。

如果你想玩弄一个完整的球体,你可以使用这个:

// full sphere
for (double angle1 = -Math.PI; angle1 <= Math.PI; angle1 += 0.15) {
    for (double angle2 = -Math.PI; angle2 <= Math.PI; angle2 += 0.15) {

        double x = r * Math.sin(angle1) * Math.cos(angle2);
        double y = r * Math.sin(angle1) * Math.sin(angle2);
        double z = r * Math.cos(angle1);

        c = createImageView();

        c.setTranslateX(x);
        c.setTranslateY(y);
        c.setTranslateZ(z);

        Rotate rx = new Rotate();
        rx.setAxis(Rotate.Y_AXIS);
        rx.setAngle(Math.toDegrees(-angle1));

        c.getTransforms().addAll(rx);

        world.getChildren().add(c);
    }
}

看起来像这样:

enter image description here

但如前所述,我还没有想出如何旋转所有图 block ,使它们朝向中心。他们需要平均分配。但这只是为了好玩和题外话。


因为它是我问题中视频的一部分,所以只需要保留一个平行过渡列表来创建图 block 的“构建”动画。底行现在有反射。

enter image description here

扩展代码:

public class VideoWall extends Application {

    Random rand = new Random();

    Group root = new Group();
    PerspectiveCamera camera;

    private static final double CAMERA_INITIAL_DISTANCE = -850;
    private static final double CAMERA_NEAR_CLIP = 0.1;
    private static final double CAMERA_FAR_CLIP = 10000.0;

    Image[] images = new Image[] {
            new Image("http://upload.wikimedia.org/wikipedia/commons/thumb/4/41/Siberischer_tiger_de_edit02.jpg/320px-Siberischer_tiger_de_edit02.jpg"),
            new Image("http://upload.wikimedia.org/wikipedia/commons/thumb/e/e7/White_Lion.jpg/320px-White_Lion.jpg"),
            new Image("http://upload.wikimedia.org/wikipedia/commons/thumb/4/47/Lion_female.jpg/319px-Lion_female.jpg")

    };

    List<ParallelTransition> transitionList = new ArrayList<>();

    public VideoWall(){

    }
    public static void main(String[] args) {
        launch(args);
    }

    /**
     * Create ImageView with random Image.
     * @return
     */
    private ImageView createImageView() {

        Image image = images[ rand.nextInt(images.length)];

        ImageView c = new ImageView( image);

        c.setFitWidth(140);
        c.setFitWidth(100);
        c.setPreserveRatio(true);

        return c;
    }

    @Override
    public void start(Stage primaryStage) {

        // build camera
        camera = new PerspectiveCamera(true);
        camera.setNearClip(CAMERA_NEAR_CLIP);
        camera.setFarClip(CAMERA_FAR_CLIP);
        camera.setTranslateZ(CAMERA_INITIAL_DISTANCE);

        // we display any node (imageview, webview, etc)
        Node node;

        // wall. the degrees depend on the distance, image size, translate start points, etc. so these values were just as they fit
        double ringBeginDeg = -30;
        double ringEndDeg = 38;

        double r = 1300; 
        double yOffset = 80; // offset per image row
        double yOffsetInitial = 120; // initial y offset from "floor"

        int min = -3;
        int max = 3;

        for( double angle1=Math.toRadians(ringBeginDeg); angle1 <Math.toRadians(ringEndDeg); angle1+=0.08)
        {

            double angle2 = Math.PI;

            for( int i=min; i <= max; i++)
            {

                double x = r * Math.sin(angle1) * Math.cos(angle2);
                // double y = r * Math.sin(angle1) * Math.sin(angle2);
                double z = r * Math.cos(angle1);

                node = createImageView();

                node.setTranslateX(x);
                node.setTranslateY(yOffset * i - yOffsetInitial);
                node.setTranslateZ(z);

                // rotate towards viewer position
                Rotate rx = new Rotate();
                rx.setAxis(Rotate.Y_AXIS);
                rx.setAngle(Math.toDegrees( -angle1));

                node.getTransforms().addAll(rx);

                // reflection on bottom row
                if( i==max) {
                    Reflection refl = new Reflection();
                    refl.setFraction(0.8f);
                    node.setEffect(refl);
                }

                // build the wall using a transition 
                node.setVisible(false);
                transitionList.add( createTransition( node));

                root.getChildren().add( node);

            }

        }

        Scene scene = new Scene(root, 1600, 900, Color.BLACK);

        primaryStage.setScene( scene);
        primaryStage.show();

        scene.setCamera(camera);

        AnimationTimer timer = createAnimation();
        timer.start();

    }

    private AnimationTimer createAnimation() {

        Collections.sort(transitionList, new Comparator<ParallelTransition>() {

            @Override
            public int compare(ParallelTransition arg0, ParallelTransition arg1) {

                // bottom right to top left
                Point2D ref = new Point2D(1000,1000);
                Point2D pt0 = new Point2D( arg0.getNode().getTranslateX(), arg0.getNode().getTranslateY());
                Point2D pt1 = new Point2D( arg1.getNode().getTranslateX(), arg1.getNode().getTranslateY());

                return Double.compare(ref.distance(pt0), ref.distance(pt1));

                // bottom row first
                // return -Double.compare( arg0.getNode().getTranslateY(), arg1.getNode().getTranslateY());

            }

        });


        AnimationTimer timer = new AnimationTimer() {

            long last = 0;

            @Override
            public void handle(long now) {

                //if( (now - last) > 1_000_000_000) 
                if( (now - last) >   40_000_000) 
                {
                    if( transitionList.size() > 0) {

                        ParallelTransition t = transitionList.remove(0);
                        t.getNode().setVisible(true);
                        t.play();

                    }
                    last = now;

                }

                if( transitionList.size() == 0) {
                    stop();
                }
            }

        };

        return timer;
    }

    private ParallelTransition createTransition( final Node node) {

        Path path = new Path();
        path.getElements().add(new MoveToAbs( node, node.getTranslateX() - 1000, node.getTranslateY() - 900));
        path.getElements().add(new LineToAbs( node, node.getTranslateX(), node.getTranslateY()));

        Duration duration = Duration.millis(1500);

        PathTransition pt = new PathTransition( duration, path, node);

        RotateTransition rt = new RotateTransition( duration, node);
        rt.setByAngle(720);
        rt.setAutoReverse(true);

        ParallelTransition parallelTransition = new ParallelTransition();
        parallelTransition.setNode(node);
        parallelTransition.getChildren().addAll(pt, rt);

        return parallelTransition;

    }

    public static class MoveToAbs extends MoveTo {

        public MoveToAbs( Node node, double x, double y) {
            super( x - node.getLayoutX() + node.getLayoutBounds().getWidth() / 2, y - node.getLayoutY() + node.getLayoutBounds().getHeight() / 2);
        }

    }

    public static class LineToAbs extends LineTo {

        public LineToAbs( Node node, double x, double y) {
            super( x - node.getLayoutX() + node.getLayoutBounds().getWidth() / 2, y - node.getLayoutY() + node.getLayoutBounds().getHeight() / 2);
        }

    }   

}

关于layout - 如何像 JavaFX 2.0 演示中那样创建视频墙?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28230755/

相关文章:

android - Android 中的可关闭横幅

android - 布局可能没用 - 不,它不是

java - 在java swing中调整窗口大小时如何使按钮粘在一个地方?

java - FX TextField 禁用节点事件

intellij-idea - JavaFX:警告自动关闭对话框

JavaFX 8 作为 3D 游戏引擎?

java - 将标签添加到 BoxLayout 的下一行

JavaFX MediaPlayer 不播放 M4A 文件

3d - javafx 3d 向 fxml 导出/导入不正确或不完整

java - 在 JavaFX 中导入 STL 文件