dragging a 3d object alternativa3d 8

David Jones
@david3jones
avatar-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. dragging object 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

Downloads

Comments

  • avatar-sharpedge
    # 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?
  • avatar-davidejones
    # 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.
  • avatar-sharpedge
    # 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 :/
  • avatar-davidejones
    # 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">

  • avatar-sharpedge
    # 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.

  • avatar-davidejones
    # 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

  • avatar-sharpedge
    # 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 :/

  • avatar-sharpedge
    # SharpEdge
    Oh i saw that it’s a common problem on Android and IOS, i opened a new issue on git. Thank you anyway.
  • avatar-davidejones
    # davidejones
    ah ok, well at least you are getting closer to it working :)
  • avatar-sharpedge
    # 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.)

  • avatar-sharpedge
    # SharpEdge

    sorry

    Correct: private function uploadResources(resources:Vector.<Resources>)

  • avatar-sharpedge
    # SharpEdge

    sorry again

    Resource not Resources

  • avatar-davidejones
    # 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
  • avatar-martin
    # 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.

    • avatar-davidejones
      # davidejones
      I see what you mean, it wasn’t something i noticed until you pointed it out actually. I’ve put my code here in wonderfl http://wonderfl.net/c/scgK , if i get a chance i will try fork it and see if i can make that work a little better.

Comments are currently closed