Previous articles summary :
- First steps in Papervision3D : Part 1
Creation of a new Papervision3D project within eclipse or Flex Builder 3 and a simple example of a 3D scene illustrating some basic Papervision3D classes. - First steps in Papervision3D : Part 2
Illustration of use of new Papervision3D v2.0 class BasicView that encapsulates essential elements to rapidly start developing new 3D scenes. - First steps in Papervision3D : Part 3 – animation
Adding some basic animation to the scene by modifying 3D object parameters when entering a frame. - First steps in Papervision3D : Part 4 – lighting and shading
A point light source is added to the scene. Fours materials with different characteristics are added to spheres to illustrate how Papervision3D performs shading. - First steps in Papervision3D : Part 5 – scene interaction
Listen to mouse events to interact with the scene and with individual rendered objects.
In this article I’d like to start taking a look at texture mapping : taking bitmap data and mapping it to a surface. In the previous animations in this series, the objects have had materials of a particular colour, enhanced by different shading models. Using bitmap data we can add much more realism to a scene.
To start with some useful links that provide a good overview of texture mapping with Papervision3D :
- dispatchEvent() : Papervision3D Part2 : Features
Provides a good introduction to some of the essentials of texture mapping (as well as other features in Papervision3D) - insideRIA : Textures (WireFrame, Bitmap, MovieAsset, Video, etc.) PaperVision3D
Lots of useful information on different material types including some essential texture mapping details.
I’d really recommend reading the first of these links because it gives a good description of UV coordinates related with images, allowing us to map rectangular images to displayed triangles. This is also an important concept involved in tiling. Tiling allows us to have a particular image repeated over a surface.
What I’d like to do in this article is to start off very simply and show how to add a bitmap texture to cubes and spheres, with and without tiling. So, no shading for the moment – that’ll be covered in the next article – and lets just see how to cover a shape with a bitmap material.
The code below is based on code from the previous article. However, I’m removing the light source for the time being, adding cubes as well as spheres and, of course, changing the materials to use bitmap data.
package { import caurina.transitions.Tweener; import flash.display.Bitmap; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; import flash.events.MouseEvent; import org.papervision3d.events.InteractiveScene3DEvent; import org.papervision3d.materials.BitmapMaterial; import org.papervision3d.materials.utils.MaterialsList; import org.papervision3d.objects.DisplayObject3D; import org.papervision3d.objects.primitives.Cube; import org.papervision3d.objects.primitives.Sphere; import org.papervision3d.view.BasicView; public class Example006 extends BasicView { [Embed(source="/../assets/pv3d.png")] private var MyTextureImage:Class; private static const ORBITAL_RADIUS:Number = 200; private var bitmap:Bitmap = new MyTextureImage(); private var cube1:Cube; private var cube2:Cube; private var sphere1:Sphere; private var sphere2:Sphere; private var objectGroup:DisplayObject3D; private var doRotation:Boolean = false; private var lastMouseX:int; private var lastMouseY:int; private var cameraPitch:Number = 60; private var cameraYaw:Number = -60; public function Example006() { super(0, 0, true, true); // set up the stage stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; // Initialise Papervision3D init3D(); // Create the 3D objects createScene(); // Listen to mouse up and down events on the stage stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); // Start rendering the scene startRendering(); } private function init3D():void { // position the camera camera.z = -500; camera.orbit(60, -60); } private function createScene():void { // create interactive bitmap material var bitmapMaterial:BitmapMaterial = new BitmapMaterial(bitmap.bitmapData, false); bitmapMaterial.interactive = true; // create an interactive tiled bitmap material (bitmap tiled as 2 x 2) var tiledBitmapMaterial:BitmapMaterial = new BitmapMaterial(bitmap.bitmapData, false); tiledBitmapMaterial.interactive = true; tiledBitmapMaterial.tiled = true; tiledBitmapMaterial.maxU = 2; tiledBitmapMaterial.maxV = 2; // create cube with simple bitmap material cube1 = new Cube(getBitmapMaterials(bitmapMaterial), 100, 100, 100); cube1.x = ORBITAL_RADIUS; // create cube with tiled bitmap material cube2 = new Cube(getBitmapMaterials(tiledBitmapMaterial), 100, 100, 100); cube2.x = -ORBITAL_RADIUS; // create sphere with simple bitmap material sphere1 = new Sphere(bitmapMaterial, 50, 10, 10); sphere1.z = ORBITAL_RADIUS; // create sphere with tiled bitmap material sphere2 = new Sphere(tiledBitmapMaterial, 50, 10, 10); sphere2.z = -ORBITAL_RADIUS; // Create a 3D object to group the spheres objectGroup = new DisplayObject3D(); objectGroup.addChild(cube1); objectGroup.addChild(cube2); objectGroup.addChild(sphere1); objectGroup.addChild(sphere2); // Add a listener to each of the spheres to listen to InteractiveScene3DEvent events cube1.addEventListener(InteractiveScene3DEvent.OBJECT_CLICK, onMouseDownOnObject); cube2.addEventListener(InteractiveScene3DEvent.OBJECT_CLICK, onMouseDownOnObject); sphere1.addEventListener(InteractiveScene3DEvent.OBJECT_CLICK, onMouseDownOnObject); sphere2.addEventListener(InteractiveScene3DEvent.OBJECT_CLICK, onMouseDownOnObject); // Add the light and spheres to the scene scene.addChild(objectGroup); } private function getBitmapMaterials(bitmapMaterial:BitmapMaterial):MaterialsList { // create list of materials for all faces of the cube, // all with the same bitmap material var materials:MaterialsList = new MaterialsList(); materials.addMaterial(bitmapMaterial, "all"); return materials; } override protected function onRenderTick(event:Event=null):void { // rotate the objects cube1.yaw(-3); cube2.yaw(-3); sphere1.yaw(-3); sphere2.yaw(-3); // rotate the group of objects objectGroup.yaw(1); // If the mouse button has been clicked then update the camera position if (doRotation) { // convert the change in mouse position into a change in camera angle var dPitch:Number = (mouseY - lastMouseY) / 2; var dYaw:Number = (mouseX - lastMouseX) / 2; // update the camera angles cameraPitch -= dPitch; cameraYaw -= dYaw; // limit the pitch of the camera if (cameraPitch <= 0) { cameraPitch = 0.1; } else if (cameraPitch >= 180) { cameraPitch = 179.9; } // reset the last mouse position lastMouseX = mouseX; lastMouseY = mouseY; // reposition the camera camera.orbit(cameraPitch, cameraYaw); } // call the renderer super.onRenderTick(event); } // called when mouse down on stage private function onMouseDown(event:MouseEvent):void { doRotation = true; lastMouseX = event.stageX; lastMouseY = event.stageY; } // called when mouse up on stage private function onMouseUp(event:MouseEvent):void { doRotation = false; } // called when mouse down on a sphere private function onMouseDownOnObject(event:InteractiveScene3DEvent):void { var object:DisplayObject3D = event.displayObject3D; Tweener.addTween(object, {y:200, time:1, transition:"easeOutSine", onComplete:function():void {goBack(object);} }); } // called when a tween created in onMouseDownOnObject has terminated private function goBack(object:DisplayObject3D):void { Tweener.addTween(object, {y:0, time:2, transition:"easeOutBounce"}); } } }
This produces the following Flash animation (click on image below) where we see the four spinning objects rotating about the origin. As with Part 5, you can interact with the scene by clicking and moving the mouse (to rotate the scene) and by clicking on the objects to make them jump. What we now see though are the objects covered with a material using bitmap data.
The first thing to note with this code is the embedding of an image in the compiled Flash file :
[Embed(source="/../assets/pv3d.png")] private var MyTextureImage:Class;
This is then converted into a Bitmap as follows :
private var bitmap:Bitmap = new MyTextureImage();
The embed meta-tag allows assets to be embedded in to the swf file. Rather than going into the details of embedding here, you can find some useful links at assertTrue and with the Flex livedocs. You’ll note that the source is “../assets” : this is because I have my assets folder at the same level as the src folder – when the Actionscript is compiled, the root folder is the src folder. If you want to compile the above source then simply create an assets folder, put any image file in it and change the above line to point to your own image.
The constructor, intialisation of the the 3D and the event handlers are all identical to the previous article in this series so I won’t go into details here. The main changes are in the createScene method.
Rather than coat our objects with shaded materials, we are going to create BitmapMaterials. A BitmapMaterial simply takes bitmap data (which comes from our embedded image) :
// create interactive bitmap material var bitmapMaterial:BitmapMaterial = new BitmapMaterial(bitmap.bitmapData, false); bitmapMaterial.interactive = true;
The BitmapMaterial constructor takes the bitmap data from the image we created earlier and a boolean value to indicate whether we want normal or accurate rendering to occur. Texture mapping requires a lot of CPU so Papervision3D gives the possibility to speed up the rendering at the cost of less accurate perspective. You can see an example of the distortion that occurs with this Papervision3D demo. I’ve selected false here to have quick rendering.
To create a tiled bitmap material, we create another BitmapMaterial and modify certain parameters :
// create an interactive tiled bitmap material (bitmap tiled as 2 x 2) var tiledBitmapMaterial:BitmapMaterial = new BitmapMaterial(bitmap.bitmapData, false); tiledBitmapMaterial.interactive = true; tiledBitmapMaterial.tiled = true; tiledBitmapMaterial.maxU = 2; tiledBitmapMaterial.maxV = 2;
Here we set tiled to true to allow tiling to occur. maxU and maxV are then modified to indicate how many tiles we want to cover the material. I’ve specified 2 by 2 tiling.
These materials are then simply added to the cubes and spheres exactly as we did with the shaded materials before.
// create cube with simple bitmap material cube1 = new Cube(getBitmapMaterials(bitmapMaterial), 100, 100, 100); cube1.x = ORBITAL_RADIUS; // create cube with tiled bitmap material cube2 = new Cube(getBitmapMaterials(tiledBitmapMaterial), 100, 100, 100); cube2.x = -ORBITAL_RADIUS; // create sphere with simple bitmap material sphere1 = new Sphere(bitmapMaterial, 50, 10, 10); sphere1.z = ORBITAL_RADIUS; // create sphere with tiled bitmap material sphere2 = new Sphere(tiledBitmapMaterial, 50, 10, 10); sphere2.z = -ORBITAL_RADIUS;
Actually, this is the first time that I’ve put a cube into one of these examples and I should note that rather than taking a simple material object, they take a MaterialsList that allows us to specify a different material for each face. For this demo I want all the faces to be the same so the material is added to the list using the “all” tag.
private function getBitmapMaterials(bitmapMaterial:BitmapMaterial):MaterialsList { // create list of materials for all faces of the cube, // all with the same bitmap material var materials:MaterialsList = new MaterialsList(); materials.addMaterial(bitmapMaterial, "all"); return materials; }
You can add different materials using “front”, “back”, “top”, “bottom”, “left” and “right” tags.
So, at its very simplest, that’s all there is to do to create texture mapped objects. As always I’d recommend taking a look at the Papervision3D sources as there’s a lot of stuff not covered here. For example you’ll see that there are a number of different Bitmap materials in the org.papervision3d.materials package, for example the BitmapFileMaterial that allows you to load a bitmap at run time from a URL.
In the next article I’ll introduce (or rather put back) shading on top of the texture map. To do this we need in effect a kind of composite material : one that has the texture map and another that has the shaded colour… anyway, I’ll leave that for next time! I hope at least that for the time being this gives some help in getting started!
Next article:
- First steps in Papervision3D : Part 7 – Texture mapping with lighting, bump mapping and environment mapping
Advanced materials using specific shaders to enhance texture mapped materials with bump mapping and environment mapping.

to ppl who is following this tutorial from flash and not from flex, note that instead of using the embed:
[Embed(source="/../assets/pv3d.png")] private var MyTextureImage:Class;
private var bitmap:Bitmap = new MyTextureImage();
u should use:
private var bitmap:Bitmap;
bitmap = new Bitmap(new MyTextureImage(200,200));
where “MyTextureImage” is a linkage from your library.
cya!
Thanks Roy – good to have your contribution!
I can’t comlile example from Flash IDE.Have a next error:
TypeError: Error #1007: Instantiation attempted on a non-constructor.
at Example006$iinit()
Who can say why?
I don’t know why, but every time I try to export an image for Actionscript in Flash and create a linkage from the library, the class is not created and I end up creating the class by myself or using a loader.
I create the class using this code:
package
{
import flash.display.BitmapData;
public class MyTextureImage extends BitmapData
{
public function MyTextureImage()
{
super(0,0);
}
}
}
and as Roy said, I replaced:
[Embed(source="/../assets/pv3d.png")] private var MyTextureImage:Class;
for:
private var _myTextureImage:MyTextureImage= new MyTextureImage;
private var bitmap:Bitmap= new Bitmap(_myTextureImage);
if i want to use “loader” to load pic ,how to write?thanks
hi, my object_click doesn’t fire every time i click my object, sometimes I would have to click all over it and/or repeatedly. my object uses BitmapMaterial and PhongShader combined into a ShadedMaterial (this is the proper way right?) and I have the ShadedMaterial interactive set to true. object_over and object_out both work perfectly but object_click just doesn’t fire each and every time, what am I doing wrong? please help, thank you
To get this to work in Flash, remove the following like Roy said:
[Embed(source="/../assets/pv3d.png")] private var MyTextureImage:Class;
private var bitmap:Bitmap = new MyTextureImage();
Then add the following:
// Declared with the other variables
private var myTextureImage:MyTextureImage;
private var bitmap:Bitmap;
// Added in the Constructor
myTextureImage = new MyTextureImage(0,0);
bitmap = new Bitmap(myTextureImage);
[...] Texture Mapping: http://blog.tartiflop.com/2008/08/first-steps-in-papervision3d-part-6-texture-mapping/ Basic Shapes and Texture Mapping: [...]