Drag3D does not work if the camera is looking across the plane the drag is constrained to..

Software: Away3D 4.x

Mr Margaret Scratcher, Sr. Member
Posted: 19 July 2012 01:08 AM   Total Posts: 344

Hi there,

I have a scene in which the camera is above looking directly down at the scene, and I want to be able to drag a couple of objects, but constrain their movement to either up or down, or left and right (As you look at the screen, so in 3d terms, along the z axis, or along the X axis)

I thought that I should be able to do

(_view, ObjectContainer3D(_sphere),Drag3D.PLANE_XY)

but if I do that, the object does not drag.

If I try it with a slightly modified version of the Dragtest.as code if I set the camera rotationX to 89, it works, albeit obviously dropping up and down quite drasticly as youd expect if you move the mouse up and down:

package 
{
 [SWF
(width="1168"height="630"frameRate="60")
 
 import away3d
.cameras.Camera3D;
 
import away3d.cameras.lenses.PerspectiveLens;
 
import away3d.containers.ObjectContainer3D;
 
import away3d.containers.View3D;
 
import away3d.entities.Mesh;
 
import away3d.loaders.parsers.data.DefaultBitmapData;
 
import away3d.materials.BitmapMaterial;
 
import away3d.materials.ColorMaterial;
 
import away3d.primitives.PlaneGeometry;
 
import away3d.primitives.SphereGeometry;
 
//import away3d.tools.MeshHelper;
 
import away3d.tools.utils.Drag3D;
 
 
import flash.display.BitmapData;
 
import flash.display.Sprite;
 
import flash.events.Event;
  
 public class 
DragTest extends Sprite
 {
  
private var _view View3D;
  var 
_sphere:Mesh
  
private var _sphereGeom SphereGeometry;
  private var 
_drag3D:Drag3D;
   
  public function 
DragTest()
  
{
   _view 
= new View3D();
   
_view.antiAlias 2;
   
_view.backgroundColor 0xCCCCCC;
   var 
camera:Camera3D _view.camera;
   
camera.lens = new PerspectiveLens();
   
//var eps:Number = 0.00000001;
   
camera.0;
   
camera.500;
   
camera.0;
   
camera.rotationX 89
   addChild
(_view);
   
   
populate();
   
   
initDrag();
  
}
   
  
private function populate() : void
  {
   
var pmaterial:ColorMaterial = new ColorMaterial (0x5555ff);
   
   
   var 
PlaneGeom = new PlaneGeometry(1010);
   var 
plane:Mesh= new Mesh(PlaneGeompmaterial);
   
    
_view.scene.addChild(plane);
   
   
//var map:BitmapData = new BitmapData(256,256,true, 0x80FF0000);
   
_sphereGeom = new SphereGeometry();
   var 
smaterial:ColorMaterial = new ColorMaterial (0x555555);
   
_sphere = new Mesh (_sphereGeomsmaterial);
   
    
_view.scene.addChild(_sphere);
    
   
//var radiusObject:Number = MeshHelper.boundingRadius(plane);
   //_view.camera.lookAt(plane.position);
   
_view.camera.moveBackward(100);
   
_view.camera.lens.near 10;
    
_view.camera.lens.far 60000;
    
this.addEventListener(Event.ENTER_FRAMEhandleEnterFrame);
  
}
   
  
private function initDrag() : void
  {
   _drag3D 
= new Drag3D(_viewObjectContainer3D(_sphere),Drag3D.PLANE_XY); //third param optional default plane = xz plane
   //_drag3D.offsetCenter = true;// offsets mouse if true or drag sticks to object center
  
}
   
  
private function handleEnterFrame(e:Event) : void
  {
   
//updating the dragged object on screen
   
_drag3D.updateDrag();
   
_view.render();
  
}
 }


If you try the above code, you’ll see that the sphere is consrained along the x axis, as desired, but obviously as the camera is not totally facing downwards, if you mofe the mouse up or down from the plane, which is a good indication of zero on the y plane, the sphere moves up or down along the y plane.

However, if you change

camera.rotationX = 89

to

camera.rotationX = 90

you’ll see that the sphere isn’t even drawn..

In my projest, where the item to be dragged has an event listener to start the drag when clicked, the object stays at its original location when clicked. If a plane to constrain to is not specified (which, I believe defaults to the XZ plane) then the object can be dragged as expected.

I could possibly kludge this, by making an invisible plane above the one I actually want to drag, and updating the the plane to be dragged’s x value to equal the one that is actuaklly being dragged, but I just wanted to make sure I wasn’t doing anything wrong initally..

Seems like a bug…

 

   

Richard Olsson, Administrator
Posted: 19 July 2012 07:24 AM   Total Posts: 1192   [ # 1 ]

The fact that you can’t drag something on a plane that is perpendicular to the camera/view is not a bug. Drag3D works by casting a ray and finding the place where it collides with the specified plane. Note that we’re not talking about a plane primitive geometry here, but the mathematical definition of a plane, i.e. a theoretically endless two-dimensional expanse.

If that plane is perpendicular with the point of view, the ray could never hit it’s surface. That’s why Drag3D does not work with perpendicular planes. But then again, why would you want to use it at all in that case?

The purpose of Drag3D is to map view-space mouse motion with scene space positions. If you’re trying to drag something straight towards / away from the point of view, there is no way of doing such a mapping, so there is no reason to use Drag3D for that axis. Instead, just map it yourself to the Y motion of the mouse cursor, if you want to.

If you still want the X-motion to be controlled by Drag3D, use the XZ plane, but reset the Z position after updating the Drag3D each frame.

   

Avatar
Fabrice Closier, Administrator
Posted: 19 July 2012 08:40 AM   Total Posts: 1265   [ # 2 ]

Note that the class allows you to use the custom planes too, you can set for instance the planeObject3d and even ask the class to drag using the object “planes”, axis aligned or using the object rotations. You can see the differences if you set the debug on.
Also, (it not in there), you could add a simple setter, to define custom planes that you could update to fit your camera direction. Thinking about it, it could be a nice addon to the class…

   

Avatar
Bas, Newbie
Posted: 19 July 2012 09:32 AM   Total Posts: 23   [ # 3 ]

I tried to figure out how to drag an object relative to the screen. That would be very easy if you could create a plane facing the camera/screen. In 3.6 version i managed to do it with this in a mouseMove event:

..............
var 
dX:Number event.stageX _previousMouseX;
var 
dY:Number event.stageY _previousMouseY;

panCamera(dXdY);

_previousMouseX event.stageX;
_previousMouseY event.stageY;
........... 

and the panCamera function:

public function panCamera(dX:NumberdY:Number):void
{
 cam
.target null;
 
 
//reproducing camera.moveLeft(dX); because we need the transformed and scaled vector to be added to the lookAt
 
var axis:Vector3D Vector3D.X_AXIS;
 
axis.normalize();
 var 
vector:Vector3D cam.transform.deltaTransformVector(axis);    
 
 if(
cam.zoom != 400)
 
{
  
var scaleFactor:Number = (dX/2.5) / (cam.zoom 400);
  
vector.scaleBy(-scaleFactor);
 
}
 
else
  
vector.scaleBy(-dX);//*0.5);
 
 
cam.position cam.position.add(vector);
 
cam.+= (dY/6);
 
 
_camLookAt _camLookAt.add(vector);
 
_camLookAt.+= (dY/6);

Not yet figured it out in 4.0

   

Mr Margaret Scratcher, Sr. Member
Posted: 20 July 2012 01:14 PM   Total Posts: 344   [ # 4 ]

From what Fabice says above, that should be do-able with the drag3D class and speciofying a custom plane.

As for my problem, I figured it out using the suggestion of resetting the z value on every frame, so when the object is clicked (grabhandle, in this case), its z value is captured, and a mouse up listener is added to the stage, as if you drag the mouse up and down, the pointer leaves the object and a mouse up listener of that won’t work:

private function grabDown(e:MouseEvent3D):void
  {
   dragging 
true;
   
trace ("grabhandle clicked");
   
currentDragObject e.target as Object3D;
   
   
//TODO: get rid of this
   //dragPlane = e.target.parent.extra.dragPlane;
   
   
currentDragX e.target.x
   currentDragZ 
e.target.z
   
   initDrag
();
   
    
stage.addEventListener(MouseEvent.MOUSE_UPgrabUp);
  
}
  
  
private function grabUp(e:MouseEvent):void
  {
   stage
.removeEventListener(MouseEvent.MOUSE_UPgrabUp);
   
dragging false;
   
trace ("grabhandle let go");
  

 

and then, in every frame, after the drag is updated the object’s z value is set back to its original.

private function onEnterFrame(ev Event) : void
  {
   
   
   view
.render();
   if (
dragging)
   
{
    _drag3D
.updateDrag();
    
currentDragObject.currentDragZ;
   
}
 
  } 

Works exactly as intended!

   
   

X

Away3D Forum

Member Login

Username

Password

Remember_me



X