dragging a 3d object alternativa3d 8
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;
}
}
}
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">
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.
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
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 :/
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.)
sorry
Correct: private function uploadResources(resources:Vector.<Resources>)
sorry again
Resource not Resources
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.