I’ve often been asked this question and it’s come up quite a few times on the PV3D list, so I thought I’d post about it just for archive sake if anything else.
Right now, in PV3D, you have the ability to use MovieClips/Sprites for Materials on 3D objects. The 2 materials you would use for this are MovieMaterial and MovieAssetMaterial (Asset means that it’s in the Flash IDE library rather than an instance on stage). When you create these materials, they have reference to a MovieClip/Sprite container.
Often times, you need to communicate with these MovieClips via ActionScript, and I’m going to show you how you can do this with a basic sample that uses a sub class that extends MovieClip, and then later we try to access that MovieClip with some strong typing.
First, let’s create a sub class that extends MovieClip and you would use that to assign to a MovieClip in the Flash IDE library:
[as]
package com.rockonflash.pv3d.materials
{
import flash.display.MovieClip;
public class SpecialSauce extends MovieClip
{
public function SpecialSauce()
{
// constructor
}
public function animate():void
{
gotoAndPlay(”animate”);
}
}
}[/as]
Next, we need to create a MovieAssetMaterial, and then create a reference to it so we can talk to it via ActionScript. First we’re going to call setupScene() and create a plane object that has scope in this class. When we call doAnimation(), we cast the material of the plane object first to make sure it’s a MovieAssetMaterial. This helps avoid any RTE’s obviously, but its necessary since Plane’s material property is set to MaterialObject3D. So, if you tried to access the “movie” property of plane.material, you’d get an compile error since plane.material is thought to be a MaterialObject3D.
In the next part of doAnimation(), we cast the movie property as SpecialSauce. This is for the compiler as well since we want to call a custom method called “animate” that doesn’t exist on MovieClip alone. If the cast is successful, mov.animate() will fire and bingo, you’re in business!
[as]
import com.rockonflash.pv3d.materials.SpecialSauce;
protected var plane:Plane;
public function setupScene():void
{
var mat:MovieAssetMaterial = new MovieAssetMaterial(”com.rockonflash.pv3d.materials.SpecialSauce”, true, true, true);
plane = new Plane(mat, 256, 256, 3, 3);
}
public function doAnimation():void
{
// cast as MovieAssetMaterial, then test for null
var mat:MovieAssetMaterial = plane.material as MovieAssetMaterial;
if( mat )
{
// cast as our sub class, then test for null
var mov:SpecialSauce = mat.movie as SpecialSauce;
if( mov )
{
// now you’re talking to the instance directly
mov.animate();
}
}
}[/as]
Now one last thing to note is the 4th argument on MovieAssetMaterial: unique:Boolean. If set to true, you will get a unique instance of the MovieAssetMaterial. You might think that when you create a MovieAssetMaterial, you’d be creating a unique instance, but in reality, you’re not. By default, Papervision3D re-uses instances of MovieAssetMaterials if they’ve already been created – UNLESS you tell it to create a unique instance. We do that to save on memory and in some cases speed.
hope this helps!
UPDATE - interactivity
So, now to take it a bit further, if you want to get Mouse interactivity going with your MovieClip (SpecialSauce), all you have to do is:
1. set your viewport object’s “interactive” property to true
2. set your material’s “interactive property to true
3. addEventListener to your objects inside of your class or to the class itself:
[as]protected var viewport::Viewport3D;
protected var plane:Plane;
public function setupScene():void
{
// forth argument is ‘interactive’
viewport = new Viewport3D(1200, 600, false, true, true, true);
var mat:MovieAssetMaterial = new MovieAssetMaterial(SpecialSauce, true, true, true);
mat.interactive = true;
mat.movie.addEventListener(MouseEvent.CLICK, handleClick);
plane = new Plane(mat, 256, 256, 3, 3);
}
public function handleClick(e:MouseEvent):void
{
trace(”clicked”);
}
[/as]
At this point, you should see ‘clicked’ in the trace output.
There you go!


February 5, 2008 at 12:50 am
Nice stuff thanks ,
John is there anyway to draw directly to materials in 2.0 helloMouse3D example was great but couldn’t work out how to port it to 2.0 so much has changed
I guess this might not be ready yet.
February 8, 2008 at 7:31 am
Don’t worry figured it out.
For anyone else these is how you get the 2.0 current 3d object coordinates
my3dobject.addEventListener(InteractiveScene3DEvent.OBJECT_MOVE, onMouseMove);
function onMouseMove(event:InteractiveScene3DEvent):void {
trace(”Coords ” + event.x +” / “+ event.y);
}
doh!
February 13, 2008 at 11:44 pm
I’m afraid I’m lost on how this would be coded. Is the second step everything that would be needed in the code?
I’m getting the errors :The protected attribute can only be used on class property definitions
and
1114: The public attribute can only be used inside a package.
February 14, 2008 at 3:25 am
@Brian: No, you need to put this code in your own class, that’s why you’re getting those error messages – hth
February 14, 2008 at 5:20 pm
Ok, I got confused because I didn’t see the package declaration in the second two sections of code. What did you name the class in this case? Thanks for the help, I’m still learning classes so I appreciate your help.
February 14, 2008 at 7:14 pm
package
{
public class Main extends MovieClip
{
public function Main()
{
// constructor
}
}
}
this is what a basic class looks like that you can use with a Flash IDE FLA as the main document or with a Flex actionscript project
hth,
John
February 14, 2008 at 10:27 pm
Very nice.
You can skip the plane if you are working with a cube. My code looks like this:
private function clickHandler(e:MouseEvent):void
{
var mov:SpecialSauce = vm.movie as SpecialSauce;
if( mov )
{
mov.animate();
}
}
…here, vm is my MovieAssetMaterial that I defined at the constructor level.
I wasn’t using a plane so all I had to do was call this; no need to convert it from a normal Material. I also had a movieclip already in my library which I attached the SpecialSauce class to. Made it real easy!
Thanks a lot!
-A
March 15, 2008 at 8:07 am
Hi John,
Can this be used with MovieMaterial? I’m loading an external SWF file as a MovieMaterial, and accessing it through material.movie (which when traced does return [object MovieClip], but it’s just not hearing the gotoAndStop() command that I’m sending it.
I’m strict typing all the way:
var sidePlane:Plane = item.getChildByName(nextSide) as Plane;
trace(”sidePlane: ” + sidePlane);
var sideMat:MovieMaterial = sidePlane.material as MovieMaterial;
if (sideMat) {
trace(”sideMat: ” + sideMat);
var matMovie:MovieClip = sideMat.movie as MovieClip;
if (matMovie) {
trace(”matMovie: ” + matMovie); // returns matMovie: [object MovieClip]
direction == “forward” ? matMovie.nextFrame() : matMovie.prevFrame();
}
}
I’ve tried matMovie.nextFrame(), matMovie.play(), .gotoandStop, etc.. no results.
I pulled this in from the Library as a MovieAssetMaterial and gave it a class of its own “SpecialSauce” and everything worked, but I need to be loading an external SWF, not embedding one in the Library.
Thanks!
-Wes
March 30, 2008 at 8:45 am
Wes, did you make your material animated?
sideMat.animated = true;
Daniel
June 4, 2009 at 10:26 am
Hi John,
Sorry, I am the new starter on PV3D, but i really meet the same problem as your topic. I need to call movie material to play.
But I totally have no idea about where can i call the “package com.rockonflash.pv3d.materials” and “import com.rockonflash.pv3d.materials.SpecialSauce;”.
> What is the viewport come from?
> I can set “true, true, true” in MovieAssetMaterial agruement.
> There’s no interactive parameter can set too.
Hope to see your reply soon!
Million thanks!
Swan