dragging a 3d object alternativa3d 8

Posted by davidejones

A couple of days ago I answered an old post I saw on stackexchange about dragging around an object in alternativa3d 7. The user was asking about an example here http://wonderfl.net/c/hrsq/ and how it can be achieved in version 8. I put together a quick example for him and thought I’d also make a post on my blog about it.

Here is the code, basically a plane primitive and a box primitive is added to the scene. When the mouse clicks on the box the position is obtained using calculate ray and ray intersect. This position is used to offset the movement. So if we clicked the corner of the cube it still moves in the same fashion. When the mouse moves another intersect is calculated based on the original click and where the mouse is relative to the scene on the y and z axis.

package 
{
	import alternativa.engine3d.core.events.MouseEvent3D;
	import alternativa.engine3d.core.RayIntersectionData;
	import alternativa.engine3d.primitives.Plane;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.display.Stage3D;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import alternativa.engine3d.primitives.Box;
	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.FillMaterial;
	import flash.events.MouseEvent;
	import flash.geom.Vector3D;
	
	/**
	 * ...
	 * @author David E Jones
	 */
	public class Main extends Sprite 
	{
		private var scene:Object3D = new Object3D();
		private var camera:Camera3D;
		private var controller:SimpleObjectController;
		private var stage3D:Stage3D;
		private var box:Box;
		private var boxSelected:Boolean = false;
		private var startPoint:Vector3D;
		
		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, 100000);
			camera.x = 0;
			camera.y = 500;
			camera.z = -800;
			camera.view = new View(stage.stageWidth, stage.stageHeight, false, 0, 0, 4);
			camera.view.backgroundColor = 0x000000;
			addChild(camera.view);
			addChild(camera.diagram);
			
			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);
			
			var plane:Plane = new Plane(1500, 1500, 1, 1);
			plane.setMaterialToAllSurfaces(new FillMaterial( 0x00FF00 ));
			plane.rotationX = 90 * Math.PI / 180;
			plane.y = -50;
			scene.addChild(plane);
			uploadResources(plane.getResources(true));
						
			box = new Box(100, 100, 100, 1, 1, 1, false, null);
			var material:FillMaterial = new FillMaterial( 0xFF0000 );
			box.setMaterialToAllSurfaces(material);
			scene.addChild(box);
			uploadResources(box.getResources(true));
			
			box.addEventListener(MouseEvent3D.MOUSE_DOWN, onMouseDown);
			
			stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
			stage.addEventListener(Event.RESIZE, onResize);
			onResize();
		}
		
		private function onMouseDown(e:MouseEvent3D):void 
		{
			stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
            stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
			
			var object:Object3D = e.target as Object3D;
			var origin:Vector3D = new Vector3D();
			var direction:Vector3D = new Vector3D();
			camera.calculateRay(origin, direction, stage.mouseX, stage.mouseY);
			var data:RayIntersectionData = object.intersectRay(origin, direction);
			
			if (data != null) {
				startPoint = data.point;
			}
		}
		
		private function onMouseUp(e:MouseEvent):void
        {
            stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
            stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
        }
        
        private function onMouseMove(e:MouseEvent):void
        {
			if (startPoint != null)
			{
				var origin:Vector3D = new Vector3D;
				var directionA:Vector3D = new Vector3D;
				var directionB:Vector3D = new Vector3D;
				var direction:Vector3D = new Vector3D;
				
				camera.calculateRay(origin, directionA, camera.view.width/2, camera.view.height/2);
				camera.calculateRay(origin, directionB, mouseX, mouseY);
				
				var pos : Vector3D = intersectionPoint(origin, directionB, new Vector3D(0, startPoint.y, 0), new Vector3D(0, 1, 0));
				box.x = pos.x-startPoint.x;
				box.y = pos.y-startPoint.y;
				box.z = pos.z - startPoint.z;
			}
        }
		
		public static function intersectionPoint(lineStart:Vector3D, lineDirection:Vector3D, planePosition:Vector3D, planeNormal:Vector3D):Vector3D {
            
            var result:Vector3D = new Vector3D();
            var w:Vector3D = lineStart.subtract(planePosition);
            var d:Number = planeNormal.dotProduct(lineDirection);
            var n:Number = -planeNormal.dotProduct(w);
            
            if (Math.abs(d) < 0.0000001) return result;    
            
            var sI:Number = n / d;
            
            result.x = lineStart.x + (lineDirection.x * sI);
            result.y = lineStart.y + (lineDirection.y * sI);
            result.z = lineStart.z + (lineDirection.z * sI);

            return result;    
        }

		
		
		private function onMouse9Move(e:MouseEvent3D):void 
		{
			if (boxSelected) {
				var object:Object3D = e.target as Object3D;
				//var target:Vector3D = object.localToGlobal(new Vector3D(e.localX, e.localY, e.localZ));
				//var target:Vector3D = object.globalToLocal(new Vector3D(e.localX, e.localY, e.localZ));
				//object.x = e.localX;
				//object.y = e.localY;
				//object.z = object.z;
				//object.x = target.x;
				//object.y = target.y;
				//object.z = target.z;
				//trace(box.x);
				//trace(e.localX);
				//trace(target.x);
			}
		}
		
		private function onClick(e:MouseEvent3D):void
		{
			var box:Box = new Box(50,50,50,1,1,1,false,new FillMaterial(0xFF0000));
			box.x = e.localX;
			box.y = e.localY;
			box.z = e.localZ + 25;
			scene.addChild(box);

			uploadResources(box.getResources());
		}

		private function uploadResources(resources:Vector.):void {
			for each (var resource:Resource in resources) {
				resource.upload(stage3D.context3D);
			}
		}
		
		private function onEnterFrame(e:Event):void {
			if (boxSelected) {
				
			}
			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/1566-dragging-3d-object-alternativa3d-8/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

15 Responses to dragging a 3d object alternativa3d 8

SharpEdge

I’m trying this example on android and i think i’ve found a bug:
On the emulator it’s working as expected but on the device, the same code, cause the box to be under the plane!
Some suggestion?

davidejones

you could try setting box.y = 0; in the onMouseMove function instead of box.y = pos.y-startPoint.y; and see if that helps.

SharpEdge

Already done, and i’ve also checked the coordinates with a watch point during the execution, there are no errors, but the cube seems to be under the plane!!
As i’ve just said in the emulator it’s working but on the device not :/

davidejones

hmm I’m not sure, do you have these in your air app?

<depthAndStencil>true</depthAndStencil>

and making sure the application xmlns is 3.2 or later as these will help and sorting problems that can seem to come up

<application xmlns=”http://ns.adobe.com/air/application/3.2″>

SharpEdge

I’m using AIR 3.3 updated to the last build, but actually i didn’t set the tag to true, i’m going to try it!

Request:
It would be cool if you could do a tutorial like this but make the movement restricted to cells, like “The Sims”.

P.S.: Sorry for my english i’m from Italy.

davidejones

Hope it works, let me know if it did.

That’s a good idea, if I get the time I can try do something like that

SharpEdge

It’s Working!
I had completely forgotten the depthandstencil, Thank you!

Now new problem, if the cube is on the plane it doesn’t fire mouse_down event :/

SharpEdge

oh i forgot to tell you that at line 180 therere is probably a typing error:

Original:
private function uploadResources(resources:Vector.)

Corrected:
private function uploadResources(resources:Vector.)

davidejones

Thanks I understand the fixes. The code i posted is a mess it has some unused stuff in it, I just threw it online real quick I’ll try fix it shortly

Martin

Hi David, I do appreciate your work but this solution is not working properly :(

In the example http://wonderfl.net/c/hrsq/read
you can drag the box from any of its corners, and each time you click it it will be moved from the newly clicked area as its ‘anchor’.

In your example however you can only drag the Box from the initial ‘startPoint’ which cannot be changed. if you try to reset the ‘startPoint’ by trying to intersect the Box with another Ray it will not register.

In fact if you move the Box from 0,0,0 then it will not be possible to hit it with a ray at all. It is as if the ‘intersectRay’ only works for ‘localspace’, but no matter what I tried, even if converting the ray into localspace it will still not register.

I’ve been struggling with this problem for a whole day, and I’ve came across your post in the hope that you have fixed it, but it appears you couldn’t either.

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>