2015-04-07 17 views

risposta

5

Ecco un esempio che utilizza la incorporato JavaFX MediaPlayer e prende istantanee periodiche di una vista sul supporto dell'immagine una texture in mappata su una forma 3D (in questo caso una scatola). Un'animazione di rotazione attorno all'asse Y viene aggiunta in modo che i lati della scatola possano essere visti in prospettiva.

3D video

import javafx.animation.*; 
import javafx.application.*; 
import javafx.geometry.Rectangle2D; 
import javafx.scene.*; 
import javafx.scene.image.WritableImage; 
import javafx.scene.media.*; 
import javafx.scene.paint.*; 
import javafx.scene.shape.*; 
import javafx.scene.transform.Rotate; 
import javafx.stage.Stage; 
import javafx.util.Duration; 

// Display a rotating 3D box with a video projected onto its surface. 
public class ThreeDMedia extends Application { 

    private static final String MEDIA_URL = 
      "http://download.oracle.com/otndocs/products/javafx/oow2010-2.flv"; 

    private static final int SCENE_W = 640; 
    private static final int SCENE_H = 400; 

    private static final double MEDIA_W = 540 * 2/3; 
    private static final double MEDIA_H = 209 * 2/3; 

    private static final Color INDIA_INK = Color.rgb(35, 39, 50); 

    @Override 
    public void start(Stage stage) { 
     // create a 3D box shape on which to project the video. 
     Box box = new Box(MEDIA_W, MEDIA_H, MEDIA_W); 
     box.setTranslateX(SCENE_W/2); 
     box.setTranslateY(SCENE_H/2); 

     // create a media player for the video which loops the video forever. 
     MediaPlayer player = new MediaPlayer(new Media(MEDIA_URL)); 
     player.setCycleCount(MediaPlayer.INDEFINITE); 

     // create a media view for the video, sized to our specifications. 
     MediaView mediaView = new MediaView(player); 
     mediaView.setPreserveRatio(false); 
     mediaView.setFitWidth(MEDIA_W); 
     mediaView.setFitHeight(MEDIA_H); 

     // project the video on to the 3D box. 
     showMediaOnShape3D(box, mediaView); 

     // rotate the box. 
     rotateAroundYAxis(box); 

     // create a point light source a fair way away so lighting is reasonably even. 
     PointLight pointLight = new PointLight(
       Color.WHITE 
     ); 
     pointLight.setTranslateX(SCENE_W/2); 
     pointLight.setTranslateY(SCENE_H/2); 
     pointLight.setTranslateZ(-SCENE_W * 5); 

     // add a bit of ambient light to make the lighting more natural. 
     AmbientLight ambientLight = new AmbientLight(
       Color.rgb(15, 15, 15) 
     ); 

     // place the shape and associated lights in a group. 
     Group group = new Group(
       box, 
       pointLight, 
       ambientLight 
     ); 

     // create a 3D scene with a default perspective camera. 
     Scene scene = new Scene(
       group, 
       SCENE_W, SCENE_H, true, SceneAntialiasing.BALANCED 
     ); 
     scene.setFill(INDIA_INK); 
     PerspectiveCamera camera = new PerspectiveCamera(); 
     scene.setCamera(camera); 

     stage.setScene(scene); 
     stage.setResizable(false); 

     // start playing the media, showing the scene once the media is ready to play. 
     player.setOnReady(stage::show); 
     player.setOnError(Platform::exit); 
     player.play(); 
    } 

     // Project video on to 3D shape. 
    private void showMediaOnShape3D(Shape3D shape3D, final MediaView mediaView) { 
     PhongMaterial material = new PhongMaterial(); 
     shape3D.setMaterial(material); 

     Scene mediaScene = new Scene(
       new Group(mediaView), 
       MEDIA_W, MEDIA_H 
     ); 
     SnapshotParameters snapshotParameters = new SnapshotParameters(); 
     snapshotParameters.setViewport(
       new Rectangle2D(
         0, 0, MEDIA_W, MEDIA_H 
       ) 
     ); 
     WritableImage textureImage = mediaView.snapshot(
       snapshotParameters, 
       null 
     ); 
     material.setDiffuseMap(textureImage); 

     AnimationTimer timer = new AnimationTimer() { 
      @Override 
      public void handle(long now) { 
       mediaView.snapshot(
         snapshotParameters, 
         textureImage 
       ); 
      } 
     }; 
     timer.start(); 
    } 

    // Rotates a shape around the y axis indefinitely. 
    private void rotateAroundYAxis(Shape3D shape3D) { 
     RotateTransition rotateY = new RotateTransition(
       Duration.seconds(10), 
       shape3D 
     ); 

     rotateY.setAxis(Rotate.Y_AXIS); 
     rotateY.setFromAngle(360); 
     rotateY.setToAngle(0); 
     rotateY.setCycleCount(RotateTransition.INDEFINITE); 
     rotateY.setInterpolator(Interpolator.LINEAR); 

     rotateY.play(); 
    } 

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

E 'molto impressionante vedere che funziona anche quando lo si applica su una sfera o un cilindro. Grazie per averlo condiviso! – Roland

5

In realtà, è possibile riprodurre video su qualsiasi forma 3D.

Esiste un eccellente progetto per la riproduzione di video da @caprica chiamato VLCJ: Un framework Java per il lettore multimediale VLC.

Mentre il progetto è inteso per il rendering in tela AWT, l'autore ha eseguito alcuni tests per renderlo anche in JavaFX Canvas.

Sulla base della sua classe JavaFX, è facile eseguire il rendering del buffer su una forma 3D anziché su un nodo di tela 2D.

Impostazioni

In primo luogo, è necessario installare prima video player VLC.

Quindi sono necessarie alcune dipendenze: vlcj-3.6.0.jar, jna-3.5-2.jar & platform-3.5.2.jar e slfj4j-api.1.7.12.jar.

Inoltre, utilizzerò alcune forme 3D personalizzate dalla libreria FXyz, sebbene sia possibile utilizzare quelle regolari dall'API, ad esempio Box.

Basis

Il trucco per rendere video su una forma 3D utilizza la mappa di diffusione del suo materiale, che realizza un'immagine, e definisce la sua consistenza.

È possibile trovare ulteriori informazioni su questo here o here.

Quindi per ogni fotogramma disponibili creeremo una nuova immagine e impostarlo come la mappa diffusa:

ByteBuffer byteBuffer = nativeBuffer.getByteBuffer(0, nativeBuffer.size()); 
BufferFormat bufferFormat = ((DefaultDirectMediaPlayer) mediaPlayerComponent.getMediaPlayer()).getBufferFormat(); 
WritableImage textureImage = new WritableImage(bufferFormat.getWidth(), bufferFormat.getHeight()); 
if (bufferFormat.getWidth() > 0 && bufferFormat.getHeight() > 0) { 
    textureImage.getPixelWriter().setPixels(0, 0, bufferFormat.getWidth(), bufferFormat.getHeight(), pixelFormat, byteBuffer, bufferFormat.getPitches()[0]); 
    // apply new frame as texture image to the 3D shape's material 
    material.setDiffuseMap(textureImage); 
} 

Un AnimationTimer permetterà l'aggiornamento delle cornici e la texture.

Esempio

Questo è un esempio reale che rende il video su un toro segmentato.

public class Video3D extends Application { 

    static { 
     // path to the VLC video player 
     System.setProperty("jna.library.path", "C:/Program Files/VideoLAN/VLC"); 
    } 

    // http://download.blender.org/peach/bigbuckbunny_movies/ 
    // (c) copyright 2008, Blender Foundation/www.bigbuckbunny.org 
    private static final String VIDEO_FILE = "C:\\BigBuckBunny_320x180.mp4"; 

    private final DirectMediaPlayerComponent mediaPlayerComponent; 
    private final WritablePixelFormat<ByteBuffer> pixelFormat; 

    private final SegmentedTorusMesh torus = new SegmentedTorusMesh(50,40,12,3.2d,4.5d); 
    private final PhongMaterial material = new PhongMaterial(Color.WHEAT); 

    private double mousePosX, mousePosY; 
    private double mouseOldX, mouseOldY; 
    private final Rotate rotateX = new Rotate(-20, Rotate.X_AXIS); 
    private final Rotate rotateY = new Rotate(240, Rotate.Y_AXIS); 

    private final AnimationTimer timer; 

    public TestVLC(){ 
     mediaPlayerComponent = new TestMediaPlayerComponent(); 
     pixelFormat = PixelFormat.getByteBgraInstance(); 
     timer = new AnimationTimer() { 
      @Override 
      public void handle(long now) { 
       renderFrame(); 
      } 
     }; 
    } 
    protected void startTimer() { 
     mediaPlayerComponent.getMediaPlayer().playMedia(VIDEO_FILE); 
     timer.start(); 
    } 

    protected void stopTimer() { 
     mediaPlayerComponent.getMediaPlayer().stop(); 
     timer.stop(); 
    } 

    @Override 
    public void start(Stage primaryStage) { 
     torus.setCullFace(CullFace.NONE); 
     torus.setzOffset(1.4); 
     torus.setMaterial(material); 

     PerspectiveCamera camera = new PerspectiveCamera(true); 
     camera.getTransforms().addAll (rotateX, rotateY, new Translate(0, 0, -30)); 

     Group root3D = new Group(camera,torus); 

     SubScene subScene = new SubScene(root3D, 800, 600, true, SceneAntialiasing.BALANCED); 
     subScene.setFill(Color.AQUAMARINE); 
     subScene.setCamera(camera); 

     BorderPane pane = new BorderPane(); 
     pane.setCenter(subScene); 
     Button play = new Button("Play"); 
     play.setOnAction(e->startTimer()); 
     Button stop = new Button("Stop"); 
     stop.setOnAction(e->stopTimer()); 
     ToolBar toolBar = new ToolBar(play, stop); 
     toolBar.setOrientation(Orientation.VERTICAL); 
     pane.setRight(toolBar); 
     pane.setPrefSize(600,400); 

     Scene scene = new Scene(pane); 

     scene.setOnMousePressed((MouseEvent me) -> { 
      mouseOldX = me.getSceneX(); 
      mouseOldY = me.getSceneY(); 
     }); 
     scene.setOnMouseDragged((MouseEvent me) -> { 
      mousePosX = me.getSceneX(); 
      mousePosY = me.getSceneY(); 
      rotateX.setAngle(rotateX.getAngle()-(mousePosY - mouseOldY)); 
      rotateY.setAngle(rotateY.getAngle()+(mousePosX - mouseOldX)); 
      mouseOldX = mousePosX; 
      mouseOldY = mousePosY; 
     }); 

     primaryStage.setScene(scene); 
     primaryStage.setTitle("Video - JavaFX 3D"); 
     primaryStage.show(); 

    } 

    @Override 
    public final void stop() throws Exception { 
     stopTimer(); 

     mediaPlayerComponent.getMediaPlayer().stop(); 
     mediaPlayerComponent.getMediaPlayer().release(); 
    } 

    /** 
    * Implementation of a direct rendering media player component that renders 
    * the video to a JavaFX canvas. 
    * https://github.com/caprica/vlcj-javafx/blob/master/src/test/java/uk/co/caprica/vlcj/javafx/test/JavaFXDirectRenderingTest.java 
    */ 
    private class TestMediaPlayerComponent extends DirectMediaPlayerComponent { 

     public TestMediaPlayerComponent() { 
      super(new TestBufferFormatCallback()); 
     } 
    } 

    /** 
    * Callback to get the buffer format to use for video playback. 
    */ 
    private class TestBufferFormatCallback implements BufferFormatCallback { 

     @Override 
     public BufferFormat getBufferFormat(int sourceWidth, int sourceHeight) { 
      final int width = sourceWidth; 
      final int height = sourceHeight; 
      Platform.runLater(() -> { 
       torus.setMajorRadius(width/100); 
       torus.setMinorRadius(height/40); 
      }); 
      return new RV32BufferFormat(width, height); 
     } 
    } 

    protected final void renderFrame() { 
     Memory[] nativeBuffers = mediaPlayerComponent.getMediaPlayer().lock(); 
     if (nativeBuffers != null) { 
      Memory nativeBuffer = nativeBuffers[0]; 
      if (nativeBuffer != null) { 
       ByteBuffer byteBuffer = nativeBuffer.getByteBuffer(0, nativeBuffer.size()); 
       BufferFormat bufferFormat = ((DefaultDirectMediaPlayer) mediaPlayerComponent.getMediaPlayer()).getBufferFormat(); 
       WritableImage textureImage = new WritableImage(bufferFormat.getWidth(), bufferFormat.getHeight()); 
       if (bufferFormat.getWidth() > 0 && bufferFormat.getHeight() > 0) { 
        textureImage.getPixelWriter().setPixels(0, 0, bufferFormat.getWidth(), bufferFormat.getHeight(), pixelFormat, byteBuffer, bufferFormat.getPitches()[0]); 
        material.setDiffuseMap(textureImage); 
       } 
      } 
     } 
     mediaPlayerComponent.getMediaPlayer().unlock(); 
    } 

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

} 

E queste sono solo due istantanee di ciò che otterrete.

Pic1

Pic2

2

Oltre a soluzioni più eleganti di José jewelsea di e si potrebbe sempre posizionare un MediaView manualmente in 3d spazio e. g. come 6 facce di un cubo:

public class VideoCubeDemo extends Application { 

    Random rnd = new Random(); 

    // size of the cube 
    double size = 320; 

    @Override 
    public void start(Stage primaryStage) throws MalformedURLException { 

     // create media views 
     List<String> videoFiles = new ArrayList<>(); 

     videoFiles.add(getClass().getResource("funny_cats_compilation_2012.mp4").toExternalForm()); 
     videoFiles.add(getClass().getResource("funny_cats_compilation_2012.mp4").toExternalForm()); 
     videoFiles.add(getClass().getResource("funny_cats_compilation_2012.mp4").toExternalForm()); 
     videoFiles.add(getClass().getResource("funny_cats_compilation_2012.mp4").toExternalForm()); 
     videoFiles.add(getClass().getResource("funny_cats_compilation_2012.mp4").toExternalForm()); 
     videoFiles.add(getClass().getResource("funny_cats_compilation_2012.mp4").toExternalForm()); 

     // create faces for the cube 
     // original cube face code from http://www.javafxapps.in/tutorial/Creating-3D-Cube-in-javafx.html 
     MediaView r; 
     int videoIndex; 

     Group cube = new Group(); 

     List<MediaView> cubeFaces = new ArrayList<>(); 

     // back face 
     videoIndex = 0; 
     r = createMediaView(videoFiles.get(videoIndex)); 
     r.setTranslateX(-0.5 * size); 
     r.setTranslateY(-0.5 * size); 
     r.setTranslateZ(0.5 * size); 

     cubeFaces.add(r); 

     // bottom face 
     videoIndex = 1; 
     r = createMediaView(videoFiles.get(videoIndex)); 
     r.setTranslateX(-0.5 * size); 
     r.setTranslateY(0); 
     r.setRotationAxis(Rotate.X_AXIS); 
     r.setRotate(90); 

     cubeFaces.add(r); 

     // right face 
     videoIndex = 2; 
     r = createMediaView(videoFiles.get(videoIndex)); 
     r.setTranslateX(-1 * size); 
     r.setTranslateY(-0.5 * size); 
     r.setRotationAxis(Rotate.Y_AXIS); 
     r.setRotate(90); 

     cubeFaces.add(r); 

     // left face 
     videoIndex = 3; 
     r = createMediaView(videoFiles.get(videoIndex)); 
     r.setTranslateX(0); 
     r.setTranslateY(-0.5 * size); 
     r.setRotationAxis(Rotate.Y_AXIS); 
     r.setRotate(90); 

     cubeFaces.add(r); 

     // top face 
     videoIndex = 4; 
     r = createMediaView(videoFiles.get(videoIndex)); 
     r.setTranslateX(-0.5 * size); 
     r.setTranslateY(-1 * size); 
     r.setRotationAxis(Rotate.X_AXIS); 
     r.setRotate(90); 

     cubeFaces.add(r); 

     // front face 
     videoIndex = 5; 
     r = createMediaView(videoFiles.get(videoIndex)); 
     r.setTranslateX(-0.5 * size); 
     r.setTranslateY(-0.5 * size); 
     r.setTranslateZ(-0.5 * size); 

     cubeFaces.add(r); 

     // create cube with all faces 
     cube.getChildren().addAll(cubeFaces); 

     // initial cube rotation 
     cube.getTransforms().addAll(new Rotate(45, Rotate.X_AXIS), new Rotate(45, Rotate.Y_AXIS)); 

     // animate cube 
     Point3D rotateAxis = new Point3D(1,1,1); // rotate around X, Y and Z 
     Timeline animation = new Timeline(); 
     animation.getKeyFrames().addAll(
       new KeyFrame(Duration.ZERO, new KeyValue(cube.rotationAxisProperty(), rotateAxis), new KeyValue(cube.rotateProperty(), 0d)), 
       new KeyFrame(Duration.seconds(5), new KeyValue(cube.rotationAxisProperty(), rotateAxis), new KeyValue(cube.rotateProperty(), 360d)) 
       ); 
     animation.setCycleCount(Animation.INDEFINITE); 

     // add objects to scene 
     StackPane root = new StackPane(); 
     root.getChildren().add(cube); 

     Scene scene = new Scene(root, 1600, 900, true, SceneAntialiasing.BALANCED); 
     scene.setFill(Color.BLACK); 
     scene.setCamera(new PerspectiveCamera()); 

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

     // play videos and animation 
     for(MediaView mediaPlayer: cubeFaces) { 
      mediaPlayer.getMediaPlayer().play(); 
     } 
     animation.play(); 

    } 

    private MediaView createMediaView(String path) { 

     Media media = new Media(path); 
     MediaPlayer mediaPlayer = new MediaPlayer(media); 
     mediaPlayer.setVolume(0.8); 
     mediaPlayer.setCycleCount(MediaPlayer.INDEFINITE); 

     MediaView mediaView = new MediaView(mediaPlayer); 
     mediaView.setFitHeight(size); 
     mediaView.setFitWidth(size); 
     mediaView.setPreserveRatio(false); 

     return mediaView; 
    } 

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

enter image description here

Problemi correlati