Categories
General

Changing a cube’s material dynamically in Papervision3D

It’s long been a bug bear that you can’t dynamically change a cube’s materials, so I’ve just committed a simple update that has simply moved Tim Knip’s clever material swapping methods from the DAE object into the DisplayObject3D. So now we can call replaceMaterialsByName on any DisplayObject3D!

So you can use it by calling :

cube.replaceMaterialByName(new ColorMaterial(0xff0000,1), "front"); 

Note that this will only work if each material in the MaterialsList is unique. In other words when you set up the cube’s material list, you need to assign a different material to each of the sides of the cube.

Here’s a quick demo :

[kml_flashembed movie=”/wp-content/uploads/manual/2008/cubetest.swf” width=”445″ height=”340″ FVERSION=”9″ QUALITY=”high” /]

And here’s the source :
(Sorry about the lack of comments!)


package {
	import flash.events.Event;

	import org.papervision3d.cameras.CameraType;
	import org.papervision3d.core.effects.view.ReflectionView;
	import org.papervision3d.materials.ColorMaterial;
	import org.papervision3d.materials.WireframeMaterial;
	import org.papervision3d.materials.utils.MaterialsList;
	import org.papervision3d.objects.primitives.Cube;

	[SWF (width="640", height="480", backgroundColor="0x111111", frameRate="30")]

	public class CubeTest extends ReflectionView
	{

		private var cube : Cube;
		private var counter:int = 0;
		private var facelist : Array = ["left", "back", "right", "top", "front", "bottom"];
		private var currentFace :uint = 0;
		private var colorMaterials : Array = new Array();
		private var wireframeMaterials : Array = new Array();
		private var materials : Array = new Array();
		private var currentMaterial:int = 0;

		public function CubeTest()
		{
			super(640,480);
			surfaceHeight = -150;
			camera.fov = 30;
			camera.y = 200;


			var ml : MaterialsList = new MaterialsList();

			for (var i:int = 0; i<6; i++)
			{

				var colorMaterial : ColorMaterial = new ColorMaterial(0xff0000,0.4+(i/10));
				colorMaterial.doubleSided = true;
				colorMaterials.push(colorMaterial);

				var wireframeMaterial : WireframeMaterial = new WireframeMaterial(0xff0000,0.4+(i/10));
				wireframeMaterial.doubleSided = true;
				wireframeMaterials.push(wireframeMaterial);


			}
			materials = [wireframeMaterials, colorMaterials];

			ml.addMaterial(colorMaterials[0], "left");
			ml.addMaterial(colorMaterials[1], "back");
			ml.addMaterial(colorMaterials[2], "top");
			ml.addMaterial(colorMaterials[3], "right");
			ml.addMaterial(colorMaterials[4], "bottom");
  			ml.addMaterial(colorMaterials[5], "front");

            cube = new Cube(ml,150,150,150,5,5,5);
			scene.addChild(cube);

			addEventListener(Event.ENTER_FRAME, enterFrame);

		}

		public function enterFrame(e:Event) : void
		{

			if(counter%10==0)
			{
				trace("replacing ", facelist[currentFace], "with material number ", currentMaterial);

				cube.replaceMaterialByName(materials[currentMaterial][currentFace], facelist[currentFace]);
				currentFace++;

				if(currentFace==facelist.length)
				{
					currentFace = 0;
					currentMaterial++;
					if(currentMaterial==materials.length)
					{
						currentMaterial = 0;
					}

				}
			}

			cube.yaw(-1);
			cube.y=(120-(mouseY/2));
			if(cube.y<0) cube.y = 0;

			singleRender();
			counter++;

		}

	}
}

30 replies on “Changing a cube’s material dynamically in Papervision3D”

It seems that the replaceMaterialByName is no longer available in the latest version of Papervision. I’ve got a workaround by using:

cube.materials.getMaterialByName( “front” ).copy( newMaterial );

Where newMaterial could be any extension of MaterialObject3D.

Hope that helps.

Thanks Izaias, I’m not sure when that change was made but it makes a lot more sense for it to be there rather than in the base DisplayObject3D as many DO3Ds don’t even have a materials list.

Seb

[…] Changing a cube’s material dynamically in Papervision3D […]

My apology and risk to look like stupid, but i cant use this method because it’s missing.
Yes, I have lastest version of GreatWhite, update with SVN with link from your instruction but it’s not there(the method). I’m so confuse. What am i trying but nothing.
If you want to help me, send your version of GreatWhite to my mail(pensionera@gyuvetch.bg) or help me other way if you can

I have been using the reflectionview recently and run couple of issues. It is standard project with cubes and reflection, but i want my reflection too look like on a Plane so
1. Can I make the plain object not to have reflection
2. Can i make it under the reflections

Thanks

I can not open “//papervision3d.googlecode.com/svn/trunk/branches/GreatWhite/src/”, please make sure is it here?

This is a fantastic bit of functionality, but how are old BitmapMaterials destroyed when replaced using replaceMaterialByName? Does this have to be done explicitly or is it taken care of within the Great White DisplayObject3D code? (I’m having trouble with memory usage accumulation and am not sure I’ve really got my head around destroying the bitmapData … I’ve read your other post at //www.sebleedelisle.com/?p=309 and have updated my PV3D accordingly)

Thanks Seb
Nick

Hi All V. interesting …

But what happens when you add other objects, eg

Thiss is the same code as above but with another cude added, cube1, offset y =200
and the same swap materials applied to it, and yet its remains unaltered. Am I over simplifiying here?

Love to know your thoughts

Uni-boy

package {
import flash.events.Event;

import org.papervision3d.cameras.CameraType;
import org.papervision3d.core.effects.view.ReflectionView;
import org.papervision3d.materials.ColorMaterial;
import org.papervision3d.materials.WireframeMaterial;
import org.papervision3d.materials.utils.MaterialsList;
import org.papervision3d.objects.primitives.Cube;

[SWF (width=”640″, height=”480″, backgroundColor=”0x111111″, frameRate=”30″)]

public class CubeTest extends ReflectionView
{

private var cube : Cube;
///
private var cube1 : Cube;
///
private var counter:int = 0;
private var facelist : Array = [“left”, “back”, “right”, “top”, “front”, “bottom”];
private var currentFace :uint = 0;
private var colorMaterials : Array = new Array();
private var wireframeMaterials : Array = new Array();
private var materials : Array = new Array();
private var currentMaterial:int = 0;

public function CubeTest()
{
super(640,480);
surfaceHeight = -150;
camera.fov = 30;
camera.y = 200;

var ml : MaterialsList = new MaterialsList();

for (var i:int = 0; i<6; i++)
{

var colorMaterial : ColorMaterial = new ColorMaterial(0xff0000,0.4+(i/10));
colorMaterial.doubleSided = true;
colorMaterials.push(colorMaterial);

var wireframeMaterial : WireframeMaterial = new WireframeMaterial(0xff0000,0.4+(i/10));
wireframeMaterial.doubleSided = true;
wireframeMaterials.push(wireframeMaterial);

}
materials = [wireframeMaterials, colorMaterials];

ml.addMaterial(colorMaterials[0], “left”);
ml.addMaterial(colorMaterials[1], “back”);
ml.addMaterial(colorMaterials[2], “top”);
ml.addMaterial(colorMaterials[3], “right”);
ml.addMaterial(colorMaterials[4], “bottom”);
ml.addMaterial(colorMaterials[5], “front”);

cube = new Cube(ml,150,150,150,5,5,5);
///
cube1 = new Cube(ml,150,150,150,5,5,5);
cube1.x =200;
scene.addChild(cube1);
///
scene.addChild(cube);

addEventListener(Event.ENTER_FRAME, enterFrame);

}

public function enterFrame(e:Event) : void
{

if(counter%10==0)
{
trace(“replacing “, facelist[currentFace], “with material number “, currentMaterial);

cube.replaceMaterialByName(materials[currentMaterial][currentFace], facelist[currentFace]);
/// cube1.replaceMaterialByName(materials[currentMaterial][currentFace], facelist[currentFace]);
///
currentFace++;

if(currentFace==facelist.length)
{
currentFace = 0;
currentMaterial++;
if(currentMaterial==materials.length)
{
currentMaterial = 0;
}

}
}

cube.yaw(-1);
cube.y=(120-(mouseY/2));
if(cube.y<0) cube.y = 0;
cube1.yaw(-5);
////
cube1.y=(120-(mouseY/2));
if(cube1.y<0) cube1.y = 0;
////
singleRender();
counter++;

}

}
}

Hi, just wondering, why is it sometimes, when I use replaceMaterialByName and mentioning one of the name of the face of a cube, it change all the cube face into that new face. e.g. cube.replaceMaterialByName(material1, “front”); sometimes all the side change into material1 … is there something wrong that I did, or is it a bug? Cheers

Het Seb Lee-Delisle,

I am working on my own site and i needed to switch my cubesides dynamicely. I am working with the newest version of papervision (downloaded with svn) and i work with flash cs4. The only problem is that the replacematerialbyname isnt working on my cube. Is it because i am working with cs4 or do you have any clue wat the problem is ? You can mail me on jjoosten@live.nl.

Greets Juul Joosten

Jow Seb Lee…

Never mind about my previous question…. I have replaced my papervision classes with the trunk classes and know its good to use 😀 😛 tanks for these brilliant classes 😀 😛 (reflection and material change) 😀

I’got same problem with Samiaji Adiasasmito & Juul
is there any idea?
just because of cs4?

[…] Changing a cube’s material dynamically in Papervision3D […]

I want to ask you some question.
Can I paint some points in this cute in this demo?
paint some lines in this cute?

Awesome! i was trying overwrite whatever the original material like so: cube.materials.addMaterial(material, “front”);

this concise post solved the problem in 2 seconds flat.

Thanks Seb for this tuts, really big fun of your work.
Im trying to change cone colorMaterial at runtime i have tried used replaceMaterialByName it did work for me. any solution?

Cheers,

Hi Seb

Thanks for the infos you share! I really appreciate!
The method doesn’t seem to work on multiple do3d. Only the first call is executed, any workaround? Here is my code :

package {

import flash.display.*;
import flash.display.BitmapData;
import flash.events.MouseEvent;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.events.Event
import flash.net.URLRequest

import flash.utils.getDefinitionByName

import gs.TweenMax;
import gs.easing.Quad;

import org.papervision3d.materials.BitmapMaterial;
import org.papervision3d.materials.ColorMaterial;
import org.papervision3d.materials.utils.MaterialsList;
import org.papervision3d.objects.primitives.Cube;
import org.papervision3d.view.BasicView;

public class theCube extends MovieClip {

public function theCube(_id:int):void {

super()

addEventListener(Event.ADDED_TO_STAGE, init)

_id = id
//init()

}

public var view:BasicView = new BasicView()
private var materialsList = new MaterialsList
private var id:int
public var cubes:Array
public var theface:int
public var facelist:Array =[“back”,”top”,”front”,”bottom”]
public var currentFace:int = 1
public var materials:Array
public var replaceTwoDone:Boolean = false
public var replaceZeroDone:Boolean = false
public var replaceOneDone:Boolean = false
private var targetRotation:Number = 0;

private function init(e:Event):void {

removeEventListener(Event.ADDED_TO_STAGE, init)

view = new BasicView(stage.stageWidth,stage.stageHeight)

view.opaqueBackground = 0x000000;
view.camera.focus = 100;
view.camera.zoom = 10;
view.camera.ortho = false;

addChild(view)

materialsList = new MaterialsList()
materialsList.addMaterial(createBitmapMaterialFromAsset(“front”, 0, 240, true), “front”);
materialsList.addMaterial(createBitmapMaterialFromAsset(“back”, 0, 240), “back”);
materialsList.addMaterial(createBitmapMaterialFromAsset(“top”, 0, 240), “top”);
materialsList.addMaterial(createBitmapMaterialFromAsset(“bottom”, 0, 240, true), “bottom”);
materialsList.addMaterial(new ColorMaterial(0xff0f00), “right”);
materialsList.addMaterial(new ColorMaterial(0xff00cc), “left”);

var bmpMat:BitmapMaterial = createBitmapMaterialFromAsset(“new”, 0, 240);
var bmpMat2:BitmapMaterial = createBitmapMaterialFromAsset(“new”, 0, 240);
var bmpMat3:BitmapMaterial = createBitmapMaterialFromAsset(“new”, 0, 240, true);
var bmpMat4:BitmapMaterial = createBitmapMaterialFromAsset(“new”, 0, 240, true);

materials = [bmpMat, bmpMat2, bmpMat3, bmpMat4]

cubes = []

for(var i:int=0; i<3; ++i) {
var cube:Cube = new Cube(materialsList, 240, 240, 240);
cube.x = (250*i)-240
cube.z = 240;
view.scene.addChild(cube);
cubes.push(cube) as Cube
}

view.startRendering();

addEventListener(MouseEvent.CLICK, mouseDownHandler);

}

private function createBitmapMaterialFromAsset(asset:String, sliceX:Number, sliceWidth:Number, isFlipped:Boolean = false):BitmapMaterial
{
var _asset:Class = getDefinitionByName(asset) as Class

trace (getDefinitionByName(asset) as Class)

var bitmap:Bitmap = new Bitmap(new _asset)
var bitmapData:BitmapData = new BitmapData(240, 300, false, 0xcc0000);
if(isFlipped)
{
var sliceMatrix:Matrix = new Matrix();
sliceMatrix.translate(-240, 0);
sliceMatrix.rotate(Math.PI);
sliceMatrix.translate(sliceX, 300);
bitmapData.draw(bitmap.bitmapData, sliceMatrix);

}
else
{
bitmapData.copyPixels(bitmap.bitmapData, new Rectangle(0, 0, 240, 300), new Point());
}
var material:BitmapMaterial = new BitmapMaterial(bitmapData, true);

return material;
}

private function mouseDownHandler(event:MouseEvent):void
{

if(currentFace == 4) {

currentFace = 0
}

//trace (facelist[currentFace])

theface = currentFace

for(var i:int=0; i<cubes.length; ++i) {
replaceMat(currentFace, i)

}

rotate()

//I suppose the method had not had enough time, so I delayed call. It doesn't work anyway.

//replaceMatZero(currentFace)

//replaceMatOne(currentFace)

//replaceMatTwo(currentFace)

//addEventListener(Event.ENTER_FRAME, checkChange)

currentFace++;

}

private function replaceMat(_cf:int, _id:int):void {

Cube(cubes[_id]).replaceMaterialByName(materials[_cf], facelist[_cf]);

trace (typeof(cubes[id]))

}

private function replaceMatZero(_cf:int):void {

cubes[0].replaceMaterialByName(materials[_cf], facelist[_cf]);

replaceZeroDone = true

}

private function replaceMatOne(_cf:int):void {

cubes[1].replaceMaterialByName(materials[_cf], facelist[_cf]);

replaceOneDone = true

}

private function replaceMatTwo(_cf:int):void {

cubes[2].replaceMaterialByName(materials[_cf], facelist[_cf])

replaceTwoDone = true

}

private function checkChange(e:Event):void {

if(replaceZeroDone) {

replaceMatOne(theface)

if(replaceOneDone) {

replaceMatTwo(theface)

if(replaceTwoDone) {

replaceZeroDone = false
replaceOneDone = false
replaceTwoDone = false

removeEventListener(Event.ENTER_FRAME, checkChange)

rotate()
}

}
}

}

private function rotate():void {

targetRotation -= 450
cubes.forEach(cubes_forEachCallback);
}

private function cubes_forEachCallback(cube:Cube, index:int, array:Array):void
{
index++;
var time:Number = .3 * index;
TweenMax.to(cube, time, {rotationX:targetRotation, ease:Quad.easeInOut});
}

}
}

Thanks in advance

Netto

//www.publicismodem.it
//www.fazefactory.com

Comments are closed.