drawing on material alternativa3d

Posted by davidejones

I’ve been working on a tool just a couple of days ago that involves being able to draw or paint on a 3d object. It’s something that I’ve done before for previous versions of alternativa3d but in the latest version I came across a few problems.

Drawing on an object is very simple its just a matter of applying the bitmap to the objects material based on its uv to mouse position. I’m not entirely sure why but it didn’t always seem to work as easily. It may be down to my blender a3d exporter or possibly the scene setup I had with multiple children either way I had to change the space of the object/camera for it to match up.

I was expecting to be able to do something like this, calling the intersect ray on the camera to mouse position and then drawing to it but when I tried this with various alternativa primitives and my own 3d files it didn’t quite work.

if (paintMode) {
	var drawBitmapData:BitmapData = currentBmd;
	
	var origin:Vector3D = new Vector3D();  
	var direction:Vector3D = new Vector3D();

	camera.calculateRay(origin, direction, stage.mouseX, stage.mouseY);
	var data:RayIntersectionData = me.intersectRay(origin, direction);
	
	if (data != null) {
		drawMatrix.tx = data.uv.x * drawBitmapData.width - (brush.bitmapData.width >> 1); 
		drawMatrix.ty =	data.uv.y * drawBitmapData.height - (brush.bitmapData.height >> 1);
		drawBitmapData.draw(brush, drawMatrix);

		var material: TextureMaterial = new TextureMaterial( new BitmapTextureResource ( drawBitmapData ));
		me.setMaterialToAllSurfaces(material);
		material.diffuseMap.upload(stage3D.context3D);
	}
}

In the end I actually found a snippet of code which changes the space of the object and this helped align the drawing.

var invMatrix:Matrix3D = me.matrix.clone();
invMatrix.invert();
var newOrigin:Vector3D = invMatrix.transformVector(origin);
var newDir:Vector3D = invMatrix.transformVector(direction);
var data:RayIntersectionData = me.intersectRay(newOrigin, newDir);

Here is the full code

package 
{
	import alternativa.engine3d.objects.Mesh;
	import alternativa.engine3d.primitives.Box;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.IEventDispatcher;
	import flash.geom.Matrix;
	import alternativa.engine3d.core.events.MouseEvent3D;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import alternativa.engine3d.core.Resource;
	import alternativa.engine3d.controllers.SimpleObjectController;
	import alternativa.engine3d.core.Camera3D;
	import alternativa.engine3d.core.Object3D;
	import alternativa.engine3d.core.View;
	import alternativa.engine3d.materials.TextureMaterial;
	import flash.display.Stage3D;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.geom.Matrix3D;
	import flash.geom.Vector3D;
	import alternativa.engine3d.primitives.Box;
	import alternativa.engine3d.materials.FillMaterial;
	import alternativa.engine3d.resources.BitmapTextureResource;
	import alternativa.engine3d.resources.Geometry;
	import alternativa.engine3d.core.RayIntersectionData;
	import alternativa.engine3d.loaders.ParserA3D;
	
	/**
	 * ...
	 * @author David E Jones
	 */
	
	[SWF(backgroundColor = "#000000", frameRate = "60", width = "800", height = "600")]
	 
	public class Main extends Sprite 
	{		
		private var paintMode:Boolean = false;
		private var drawMatrix:Matrix = new Matrix();
		private var brush:Bitmap = new Bitmap(new BitmapData(10, 10, false, 0xFF0000));
		private var box:Box;
		private var scene:Object3D = new Object3D();
		private var camera:Camera3D;
		private var controller:SimpleObjectController;
		private var stage3D:Stage3D;
		private var bmd:BitmapData = new BitmapData ( 256 , 256 , false , 0xFFFFFF );
		private var currentBmd:BitmapData;
		
		public function Main():void 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		private function init(e:Event = null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
						
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
			
			camera = new Camera3D(1, 1000);
			camera.view = new View(stage.stageWidth, stage.stageHeight, false, 0, 0, 4);
			camera.view.backgroundColor = 0x000000;
			addChild(camera.view);
			addChild(camera.diagram);
			
			camera.x = -30;
			camera.y = -30;
			camera.z = 0;
			controller = new SimpleObjectController(stage, camera, 200);
			controller.lookAt(new Vector3D(0,0,0));
			scene.addChild(camera);
			
			stage3D = stage.stage3Ds[0];
			stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreate);
			stage3D.requestContext3D();
		}
		
		private function onContextCreate(e:Event):void {
			stage3D.removeEventListener(Event.CONTEXT3D_CREATE, onContextCreate);
						
			box = new Box(10, 10, 10, 1, 1, 1, false, null);
			var material: TextureMaterial = new TextureMaterial( new BitmapTextureResource ( bmd ));
			box.setMaterialToAllSurfaces(material);
			scene.addChild(box);
			uploadResources(box.getResources(true));
			registerDrawing(box);
			
			currentBmd = bmd;
			
			stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
			stage.addEventListener(Event.RESIZE, onResize);
			onResize();
		}
		
		private function registerDrawing(a:IEventDispatcher):void
		{
			a.addEventListener(MouseEvent3D.MOUSE_DOWN, onMouseDown);
			a.addEventListener(MouseEvent3D.MOUSE_UP, onMouseUp);
			a.addEventListener(MouseEvent3D.MOUSE_MOVE, onMouseMove);
		}
		
		private function unregisterDrawing(a:IEventDispatcher):void
		{
			a.removeEventListener(MouseEvent3D.MOUSE_DOWN, onMouseDown);
			a.removeEventListener(MouseEvent3D.MOUSE_UP, onMouseUp);
			a.removeEventListener(MouseEvent3D.MOUSE_MOVE, onMouseMove);
		}
		
		private function onMouseDown(e:MouseEvent3D):void {

			paintMode = true;
		}

		private function onMouseUp(e:MouseEvent3D):void {
			
			paintMode = false;
		}
		
		private function onMouseMove(e:MouseEvent3D):void 
		{
			var obj:Object3D = e.target as Object3D;
			var me:Mesh = e.target as Mesh;
			
			if (paintMode) {
				var drawBitmapData:BitmapData = currentBmd;
				
				var origin:Vector3D = new Vector3D();  
				var direction:Vector3D = new Vector3D();

				camera.calculateRay(origin, direction, stage.mouseX, stage.mouseY);
				//var data:RayIntersectionData = me.intersectRay(origin, direction);
				
				var invMatrix:Matrix3D = me.matrix.clone();
				invMatrix.invert();
				var newOrigin:Vector3D = invMatrix.transformVector(origin);
				var newDir:Vector3D = invMatrix.transformVector(direction);
				var data:RayIntersectionData = me.intersectRay(newOrigin, newDir);

				if (data != null) {
					drawMatrix.tx = data.uv.x * drawBitmapData.width - (brush.bitmapData.width >> 1); 
					drawMatrix.ty =	data.uv.y * drawBitmapData.height - (brush.bitmapData.height >> 1);
					drawBitmapData.draw(brush, drawMatrix);

					var material: TextureMaterial = new TextureMaterial( new BitmapTextureResource ( drawBitmapData ));
					me.setMaterialToAllSurfaces(material);
					material.diffuseMap.upload(stage3D.context3D);
				}
			}
		}
		
		private function uploadResources(resources:Vector.):void {
			for each (var resource:Resource in resources) {
				resource.upload(stage3D.context3D);
			}
		}
		
		private function onEnterFrame(e:Event):void {
			box.rotationZ += 0.01;
			camera.render(stage3D);
		}
		
		private function onResize(e:Event = null):void {
			camera.view.width = stage.stageWidth;
			camera.view.height = stage.stageHeight;
		}
		
	}
	
}

You can download the example files here

Trackback URL for this post: http://davidejones.com/blog/1556-drawing-material-alternativa3d/trackback/

Being Sociable...

  • If you like this article then please share it on your favourite social network and follow me on twitter for the latest updates

One Response to drawing on material alternativa3d

  • Pingback: Stage3D developer tips « 岩屋(乐在其中)

  • Leave a Reply

    Your email address will not be published. Required fields are marked *

    You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>