Flash: How to add Video texture in Papervision 3D

April 15th, 2007 by Luis

I have received loads of requests asking how to diaplay a FLV as a texture in Papervision 3D using AS3.

The concept is very basic, you need to snapshot the video object where the video is running using BitmapData.draw(), and then set the result in the texture, and the rest is done by the 3D engine. ( See demo here)

papervideo

Notice in the code below a small hack by Chris Chen to be able to draw a media source in AS3 bypassing security errors.

Code Updated for latest Flash player and PV3D GreatWhite:

Actionscript:
  1. package com.lessrain.projects.luis.pv3dWhite.video3d
  2. {
  3.     import flash.display.BitmapData;
  4.     import flash.display.Sprite;
  5.     import flash.events.AsyncErrorEvent;
  6.     import flash.events.Event;
  7.     import flash.geom.Point;
  8.     import flash.geom.Rectangle;
  9.     import flash.media.Video;
  10.     import flash.net.NetConnection;
  11.     import flash.net.NetStream;
  12.     import flash.system.Security;
  13.  
  14.     import org.papervision3d.cameras.Camera3D;
  15.     import org.papervision3d.materials.BitmapMaterial;
  16.     import org.papervision3d.objects.DisplayObject3D;
  17.     import org.papervision3d.objects.primitives.Plane;
  18.     import org.papervision3d.render.BasicRenderEngine;
  19.     import org.papervision3d.scenes.Scene3D;
  20.     import org.papervision3d.view.Viewport3D;   
  21.  
  22.     /**
  23.      * @author Luis Martinez, Less Rain (luis@lessrain.com)
  24.      */
  25.     public class Video3D
  26.     {
  27.         private var _target : Sprite;
  28.         private var _container : Sprite;
  29.         private var _viewport : Viewport3D;
  30.         private var _renderer : BasicRenderEngine;
  31.         private var _scene3D : Scene3D;
  32.         private var _camera : Camera3D;
  33.         private var _rootNode : DisplayObject3D;
  34.         private var _connection : NetConnection;
  35.         private var _stream : NetStream;
  36.         private var _video : Video;
  37.         private var _videoWidth : Number = 320;
  38.         private var _videoHeight : Number = 240;
  39.         private var _videoTexture : BitmapData;
  40.         private var _planeTexture1 : BitmapData;
  41.         private var _planeTexture2 : BitmapData;
  42.         private var _srcRect1 : Rectangle;
  43.         private var _srcRect2 : Rectangle;
  44.         private var _basePoint : Point = new Point(0, 0);
  45.  
  46.         public function Video3D()
  47.         {
  48.             Security.loadPolicyFile("http://www.yourdomain.com/cross-domain.xml");
  49.         }
  50.  
  51.         public function initialize() : void
  52.         {
  53.             _srcRect1 = new Rectangle(0, 0, _videoWidth>> 1, _videoHeight);
  54.             _srcRect2 = new Rectangle(_videoWidth>> 1, 0, _videoWidth>> 1, _videoHeight);
  55.             _videoTexture = new BitmapData(_videoWidth, _videoHeight);
  56.             _planeTexture1 = new BitmapData(_videoWidth>> 1, _videoHeight);
  57.             _planeTexture2 = new BitmapData(_videoWidth>> 1, _videoHeight);
  58.            
  59.             initialize3D();
  60.             loadVideo();
  61.             createPlanes();
  62.            
  63.             _container.addEventListener(Event.ENTER_FRAME, loop3D);
  64.         }
  65.  
  66.         private function initialize3D() : void
  67.         {
  68.             _container = new Sprite();
  69.             _target.addChild(_container);
  70.             _viewport = new Viewport3D(990, 600, false, false);
  71.             _container.addChild(_viewport);
  72.             _renderer = new BasicRenderEngine();
  73.             _scene3D = new Scene3D();
  74.             _camera = new Camera3D();
  75.             _camera.zoom = 8;
  76.             _camera.focus = 200;
  77.             _rootNode = new DisplayObject3D();
  78.             _scene3D.addChild(_rootNode);
  79.         }
  80.  
  81.         private function loadVideo() : void
  82.         {
  83.  
  84.             var customClient : Object = new Object();
  85.  
  86.             customClient["onCuePoint"] = cuePointHandler;
  87.             customClient["onMetaData"] = metaDataHandler;
  88.            
  89.             _connection = new NetConnection();
  90.             _connection.connect(null);
  91.  
  92.             _stream = new NetStream(_connection);
  93.             _stream.checkPolicyFile = true;
  94.             _stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
  95.             _stream.client = customClient;
  96.             _video = new Video(_videoWidth, _videoHeight);
  97.             _video.attachNetStream(_stream);
  98.        
  99.             _stream.play('http://www.blog.lessrain.com/wp-content/upload/papervideo/myvideo.flv');
  100.         }
  101.  
  102.         private function cuePointHandler(infoObject_ : Object) : void
  103.         {
  104.         }
  105.  
  106.         private function metaDataHandler(infoObject_ : Object) : void
  107.         {
  108.         }
  109.  
  110.         private function asyncErrorHandler(event : AsyncErrorEvent) : void
  111.         {
  112.         }
  113.  
  114.         private function createPlanes() : void
  115.         {
  116.  
  117.             var material1 : BitmapMaterial = new BitmapMaterial(_planeTexture1);
  118.             material1.oneSide = false;
  119.             var plane1 : DisplayObject3D = _rootNode.addChild(new Plane(material1, _videoWidth>> 1, _videoHeight, 4, 4), "plane1");
  120.             plane1.x = -_videoWidth>> 2;
  121.             var material2 : BitmapMaterial = new BitmapMaterial(_planeTexture2);
  122.             material2.oneSide = false;
  123.             var plane2 : DisplayObject3D = _rootNode.addChild(new Plane(material2, _videoWidth>> 1, _videoHeight, 4, 4), "plane2");
  124.             plane2.z = _videoWidth>> 2;
  125.             plane2.rotationY = -90;
  126.         }
  127.  
  128.         private function loop3D(event_ : Event) : void
  129.         {
  130.    
  131.             _rootNode.rotationY += ((-_container.mouseX * 0.5) - _rootNode.rotationY) / 10;
  132.             _rootNode.rotationX += ((-_container.mouseY * 0.5) - _rootNode.rotationX) / 10;
  133.             _videoTexture.draw(_video);
  134.             _planeTexture1.copyPixels(_videoTexture, _srcRect1, _basePoint);
  135.             _planeTexture2.copyPixels(_videoTexture, _srcRect2, _basePoint);
  136.             _renderer.renderScene(_scene3D, _camera, _viewport);
  137.         }
  138.  
  139.         public function get target() : Sprite
  140.         {
  141.             return _target;
  142.         }
  143.  
  144.         public function set target(target_ : Sprite) : void
  145.         {
  146.             _target = target_;
  147.         }
  148.     }
  149. }


33 Responses to “Flash: How to add Video texture in Papervision 3D”

  1. katopz Says:

    that’s cool indeed,thx for sharing! ;D

  2. Biffer Says:

    Is this possible within the AS2 version of Papervision3d too? :)

  3. Luis Says:

    Yes it does work in AS2 too:

    http://www.blog.lessrain.com/?p=525

  4. reele Says:

    hows the song called? :)

  5. Luis Says:

    My friends kill my folks by Herman Düne,

    my friends kill my folks in front of me
    my friends kill my folks and they’re not even sorry
    they say the line is thick between crying and crying
    they say the line is thick between dying and dying

    i hardly ever listen and i don’t steer
    but i do hear and i often peer
    at the features of men through my glasses
    through my pictures and through their faces
    it’s the only thing that keeps me awake
    through some nights and all kinds of mornings
    when you hate yourself it’s the mirror you break
    you won’t find ears that fit your earrings

    i once was used to killing and double talking
    i wasn’t writing then, not even smoking
    so i know how it feels to hate your own guts
    and rest your sick ego on ifs and buts
    and i don’t see a line and i don’t give a damn
    i see a surface and i feel its thickness
    and what i see from where i am
    is so obvious not seeing it is a sickness

  6. Sean Says:

    Cool tune! Speed runs well too.

  7. Thomas Says:

    nice example!
    to make the sample code work with any kind of movie you have to change the line:
    _video = new Video(); to
    _video = new Video(videoWidth, _videoHeight);
    as the Video object doesn’t resize to the video dimensions but stays with the default values (320×240).

  8. How to start working 3D with Papervision 3D - Update « Flash Enabled - Get Ready With Flash… Says:

    […] ervision home - OS Flash Update How to add Video texture in Papervision 3D: http://www.blog.lessrain.com/?p=552 Best Regards, CP 2 Comments » RSS […]

  9. Studiowhiz.com » Blog Archive » How to start working 3D with Papervision 3D - Update Says:

    […] els and texturing; - Papervision home - OS Flash Update How to add Video texture in Papervision 3D: http://www.blog.lessrain.com/?p=552 Best Regards, CP This entry was posted on Monday, April 30th, 2007 at 4:43 am […]

  10. fontvir.us Says:

    hey,
    this is really tight.
    im just getting into flex and pv3d, thanx a lot for this tutorial.
    i made a demo version (http://the.fontvir.us/pv3d/vidCube/)

    the code works, but i keep getting an error

    from the null connection in the loadVideo() function…

    _connection.connect(null);

    Error #2044: Unhandled AsyncErrorEvent:. text=Error #2095: flash.net.NetStream was unable to invoke callback onMetaData. error=ReferenceError: Error #1069: Property onMetaData not found on flash.net.NetStream and there is no default value.
    at main/::loadVideo()
    at main$iinit()

    i know is is already a h4x but have any ideas?

  11. B Says:

    I tried compiling and running this through Flash. The plane rendering is working and I can hear the video playing but it’s not showing up on the plane.

  12. Rohan Says:

    Buddy ur code ” no work” fix ur

    Error #2044: Unhandled AsyncErrorEvent:. text=Error #2095: flash.net.NetStream was unable to invoke callback onMetaData. error=ReferenceError: Error #1069: Property onMetaData not found on flash.net.NetStream and there is no default value.
    at main/::loadVideo()
    at main$iinit()

    then repost.
    Thanks

  13. Luis Says:

    It works for me in Flex builder 2 and FLex Builder 3 with the sample video I have. The error you are getting is probably becuase your flv has cue points or other kind of metadata and the asyncError is dispatched and informs you that the NetStream class was unable to invoke the callback onMetaData and onCuePoint. I’m not taking care of this in my code.

    One of the easiest ways to handle the asyncError event dispatched by the NetStream object is to listen for the event using the addEventListener() method. This allows you to either handle or ignore the event. ( I have just added a listener for the asyncError in the loadVideo method in the code above).

    stream.addEventListener(AsyncErrorEvent.ASYNCERROR, asyncErrorHandler);

    private function asyncErrorHandler(event:AsyncErrorEvent):void {}

    Try again…

  14. Luis Says:

    Another option if you don’t want to get the error and you want to read the metadata or the cuepoints is to add something like this:

    var customClient:Object = new Object();

    customClient.onCuePoint = cuePointHandler;

    customClient.onMetaData = metaDataHandler;

    _stream.client = customClient;

    private function cuePointHandler(infoObject:Object):void
    {
    trace(”cuePoint”);
    }
    private function metaDataHandler(infoObject
    :Object):void
    {
    trace(”metaData”);
    }

    Is up to you…

  15. Rick Says:

    I just tried building and running your example. I can hear the sound but the video is just a white (bent) box. I’m using the latest Flash Player 9.0.47 and the 1.5 version of PaperVision and I’ve tried it on both Mac and Windows. Any ideas?

  16. irie Says:

    Hi I have the same prob as B… The video texture is not visible but the sound is working… Anyone an idea???

  17. Drissou Says:

    Hi,

    I had the same problem as Rick and irie. After some struggling (i.e. a lot), I was able to solve this by setting material1 and material2 as global variables, and setting their bitmap property to _planeTexture1 and _planeTexture2 in the loop3D function just before the scene rendering as follows:

            _planeTexture1.copyPixels(_videoTexture, _srcRect1,_basePoint);
            _planeTexture2.copyPixels(_videoTexture, _srcRect2,_basePoint);
    

    //added code
    material1.bitmap=planeTexture1;
    material2.bitmap=
    planeTexture2;
    //end added code

            _scene3D.renderCamera(_camera );
    

    Let me know if that helps.

  18. Rick Says:

    That worked — thanks.

    I made some other simplifications — see the ‘loop3D’ function, below.

    Here’s my final code:
    package
    {
    import flash.display.;
    import flash.events.
    ;
    import flash.media.Video;
    import flash.net.;
    import flash.geom.
    ;
    //You need papervision 3D framework
    import org.papervision3d.scenes.;
    import org.papervision3d.cameras.
    ;
    import org.papervision3d.objects.;
    import org.papervision3d.materials.
    ;

    [SWF(width="800", height="600", frameRate="31", backgroundColor="#292929")]
    public class MainVideoSample extends Sprite
    {
        private var _container : Sprite;
        private var _scene3D : Scene3D;
        private var _camera: Camera3D;
        private var _rootNode: DisplayObject3D;
        private var _connection : NetConnection;
        private var _stream : NetStream;
        private var _video : Video;
        private var _videoSprite : Sprite;
        private var _videoWidth : Number;
        private var _videoHeight : Number;
        private var _videoTexture: BitmapData;
        private var _planeTexture1 : BitmapData;
        private var _planeTexture2 : BitmapData;
        private var _srcRect1 : Rectangle;
        private var _srcRect2 : Rectangle;
        private var _basePoint : Point;
        private var _material1          :BitmapMaterial;
        private var _material2          :BitmapMaterial;
    
        public function MainVideoSample()
        {
            stage.quality = "MEDIUM";
            stage.scaleMode = "noScale";
            _videoWidth=320;
            _videoHeight=240;
            _basePoint = new Point (0, 0);
            _srcRect1 = new Rectangle( 0, 0, _videoWidth/2, _videoHeight);
            _srcRect2 = new Rectangle(_videoWidth/2, 0, _videoWidth/2, _videoHeight);
            _videoTexture= new BitmapData (_videoWidth,_videoHeight);
            _planeTexture1 = new BitmapData (_videoWidth/2,_videoHeight);
            _planeTexture2 = new BitmapData (_videoWidth/2,_videoHeight);
            init3D();
            loadVideo();
            createPlanes();
            addEventListener( Event.ENTER_FRAME, loop3D );
        }
        private function init3D():void
        {
            _container = new Sprite();
            addChild( _container );
            _container.x = 400;
            _container.y = 300;
            _scene3D = new Scene3D( _container );
            _camera = new Camera3D();
            _camera.zoom = 10;
            _camera.focus = 200;
            _rootNode = _scene3D.addChild( new DisplayObject3D( "_rootNode" ) );
        }
        private function loadVideo():void
        {
            _connection = new NetConnection();
            _connection.connect(null);
            _stream = new NetStream(_connection);
            _stream.client = new Object();  //prevents error message about not catching onMetaData, which we don't need.
            _video = new Video(_videoWidth, _videoHeight);
            _stream.play('assets/myvideo.flv');
            _video.attachNetStream(_stream);
        }
        private function createPlanes():void
        {
            _material1 = new BitmapMaterial( _planeTexture1);
            _material1.oneSide=false;
            var plane1:DisplayObject3D = _rootNode.addChild( new Plane( _material1, _videoWidth/2, _videoHeight, 4, 4 ), "plane1" );
            plane1.x = -_videoWidth/4;
            _material2 = new BitmapMaterial(_planeTexture2);
            _material2.oneSide=false;
            var plane2:DisplayObject3D = _rootNode.addChild( new Plane( _material2, _videoWidth/2, _videoHeight, 4, 4 ), "plane2" );
            plane2.z = _videoWidth/4;
            plane2.rotationY = -90;
        }
        private function loop3D(event:Event):void
        {
            _camera.x += ( ( -_container.mouseX * 5 ) - _camera.x ) / 10;
            _camera.y += ( ( -_container.mouseY * 5 ) - _camera.y ) / 10;
            _videoTexture.draw(_video);
            _planeTexture1.copyPixels(_videoTexture, _srcRect1, _basePoint);
            _planeTexture2.copyPixels(_videoTexture, _srcRect2, _basePoint);
            _material1.bitmap = _planeTexture1;
            _material2.bitmap = _planeTexture2;
            _scene3D.renderCamera(_camera );
        }
    }
    

    }

  19. rowery Says:

    I just tried building and running your example. I can hear the sound but the video is just a white (bent) box.

  20. chichilatte Says:

    Thank you rick, that works perfectly for me. impressive!

  21. ed Says:

    Working fine but how would you make the planes clickable? Any ideas?

  22. Adam Says:

    I like, it is very nice :) I can see almost endless possibilities with this tool.

  23. Video wall mark 1 at all that flash Says:

    […] This is not something which I made from scratch, however during reading this guys stuff I have now made myself familiar with: Loading video into Flex. Strea […]

  24. bilety lotnicze Says:

    “Flash: How to add Video texture in Papervision 3D” - Good work. Cogratulations

  25. Rob Says:

    As of this time, it will not work with the release candidate Flash player (version 64 with hardware acceleration), but it does work with version 47.

  26. root.op » Blog Archive » Papervision3D / VideoCubes Says:

    […] 17; and source after the click. heavly inspired by Robots w/Lasers and the lessrain log. the video footage is taken from the excellent documentary “Good Copy Bad Copy”, see […]

  27. Peter Says:

    just done a small demo ( http://www.rootop.de/?p=128 ) inspired by your bitmap.draw example… your blog saved me hours of unnecessary headaches, thanks a lot…
    mentioned you in my blog - if you don’t mind.

    kind regards, peter

  28. Ohm Says:

    Hi, nice example !

    But like in some other tuts I found around, there’s always a problem with the “renderCamera” function…???
    Would you have an idea why ?

    Thx

  29. xero / fontvir.us Says:

    thanx for updating this for 2.0/GW compatability!

  30. itch Says:

    What about loading a swf as texture for a plane ? Do you know if this is possible ? I searched on google, but google’s not my friend today with this requests… ;)

    Thx !

  31. Thomas Says:

    @itch: try searching for MovieMaterial. you’ll have to load the swf first though.

  32. mikew909 Says:

    great post! anyone able to get the video to stop (including audio?) when i try stop the video the audio keeps going - anyone have an idea there?

    cheers! :)

  33. Eduardo Says:

    Hello.
    I`m noob on flex and still cannot configure a project runing this AS file.
    Any help please?.

    I try also this example http://www.adobe.com/devnet/flash/articles/flashvideo3d_print.html and with this the problem is the object just with gray, no video texture (audio is running)

Leave a Reply