June 24th, 2008

Several months ago I did a blog post titled Dragging in 3D - The Easy Way. It was an no-math solution to being able to drag an object in 3D in multiple directions using the tools already built into Papervision. By creating an invisible Plane object, you could detect where it was hit by the mouse in 3D space - then move your object to that position.

While that was cool and all - it definitely was just a hack and heavy approach to dragging objects in 3D. This is much more elegant.

I introduced some new functions that make dragging in 3D possible. They have alot greater use than JUST for dragging, so make good use of them! The main function, which is essential to being able drag in 3D - is CameraObject3D.unproject. #unproject does just what the name says: it unprojects coordinates. It takes 2D screen coordinates, and gives you back a vector in world space. In lay terms - this basically shoots a ray from the camera, through where the mouse is, into 3D space. You can then do whatever you want knowing where that ray is. I use it in this demo to find where the ray hits a plane i want to be dragging on. When i find the intersection of the unprojected ray with the plane - i move my object there. Its really that easy. And all of it is built into Papervision3D for you.

So lets look at some code. First thing to note is the unproject function. It only takes 2 parameters which are screenX and screenY. Just pass in the mouse coordinates (relative to viewport.containerSprite) and you will get a Number3D that represents your ray back.

Now that we know the direction the ray is shooting - we can check for an intersection with our plane. To do this, we have to do a few things. First, we must convert our ray into a point in 3D space. This is done by simply adding it to our camera. We then need a Plane3D object. Plane3D is a math utility class in Papervision that lets you perform various operations on "planes" in 3D space. One of the operations is finding where a line intersects the plane. Once we have that intersection, we can move our object to that position. Check it out:

And thats it! All you need to do is project your ray - add it to your camera to get a real point and not just a direction, then find the intersection with your plane! If you don't understand Plane3D.setNormalAndPoint(), imagine it like this: a normal is basically the axis that is perpendicular to your object (plane). Imagine it as a spoke sticking out of the middle of it. If it is 0, 1, 0 - the spoke goes 0 in the x direction, 1 in the y direction, and 0 in the z direction. That means the spoke sticks straight up, so the plane must be horizontal. If the normal was 1, 0, 0 - the spoke would be going down the x-axis - and the plane would be vertical facing down the x-axis as well.

The demo you see here is a little more complex than the code you see above - instead of just setting the object to the intersection, it adds the difference between them to a velocity, which is then added to the object. This gives it that nice flow. Click and drag the sphere to roll it. Hold CONTROL/CMD to switch to a YZ plane (drag the sphere up). I might do a separate blog post on getting the sphere to roll properly - if anyone is interested in that...

Guys, where I can downloading classes, missing in org.papervision3d: .core.layers.RenderLayer?
Thanks for patience,

June 27th, 2008

william t

I have tried a few different versions of papervision and effects. I cannot compile this thing. It complains about getIntersectionLineNumbers which does not exist in any version of PaperVision3d that I can find.

@Bjorn – If you take a look at the link at the beginning of the post – you will see that that is how I accomplished dragging with the old technique. But to pull it off – you have to have a separate plane with multiple segments which are projected, AND you have to update the plane every render. This method lets you accomplish the same thing in 3 lines of code. Plus unproject gives you a ray in real 3D space – not just a hit on a projected 2D surface – which has other applications as well – dragging was just one way to show it off.

June 30th, 2008

golum

please,could you post source code about unproject() function for add it in your source for running it in flash cs3 (not flex) ?

If the camera is lower on y, there is a situation where the ray no longer collides with the plane and there are numerical errors. Do you know if it’s possible to clamp the point on the plane to a region that guarantees and intersection?

I’m using Papervision3D Public Alpha 2.0 – Great White (24.03.08) the latest revision I hope, but when I compile I get the error- 1172: Definition org.papervision3d.cameras:FreeCamera3D could not be found. I only have one Camera3D class file in that folder. Am I missing some files or am I missing something much more major? thanks for any advice.

I was using your old way of dragging on an invisible plane and updated to this new way. Works great! Althought i think the y coordinates might be inverted on Plane3D. Because i was setting my invisible plane y to 120 but i had to set the plane3D y to -120 for it to work the same. So something is probably inverted somewhere.

I am trying this out in Flash CS3. I have used the Classpath to Papervision3D Public Alpha 2.0 – Great White as well as Caurina for Tweener.

I get these three errors:
1045: Interface IEventDispatcher was not found.
5000: The class ‘Dragging3D’ must subclass ‘flash.display.MovieClip’ since it is linked to a library symbol of that type.
5000: The class ‘Dragging3D_texture’ must subclass ‘flash.display.BitmapData’ since it is linked to a library symbol of that type.

How do I fix this?

August 19th, 2008

Confused

I just searched my machine for IEventDispatcher.as and it does not even exist.

Can you or someone please explain how to properly get it working in Flash CS3?

Hey there, the idea behind unproject and the ray is absolute genius! I added the unproject method to an older revision of CameraObject3D and am grabbing a ray now, there were no issues in the addition.

I am wondering if you can get the X,Y,Z position of anything, rather than the intersection on a specific plane. So far, a quick hack job gets me a PLACER that follows the mouse at about 50% the Mouse Position and cannot follow the Z axis. I am currently using PaperBase:

//update camera position
var cameraPosition:Number3D = new Number3D(default_camera.x, default_camera.y, default_camera.z);
//get the direction vector of the mouse position
var ray:Number3D = default_camera.unproject(current_viewport.containerSprite.mouseX, current_viewport.containerSprite.mouseY);
//convert ray to a 3d point in the ray direction from the camera
ray = Number3D.add(ray, cameraPosition);

PLACER.x = ray.x;
PLACER.y = ray.y;
PLACER.z = ray.z;

//find the intersection of the line defined by the camera and the ray position with the plane3D
/*for each (var c in default_scene.children){
//var intersect:Number3D = c.getIntersectionLineNumbers(cameraPosition, ray);
for each (var cc in c.children){
///trace(cc.extra.p3D+”:”+cameraPosition);
var intersect:Number3D = cc.extra.p3D.getIntersectionLineNumbers(cameraPosition, ray);
//trace(intersect);
}
}*/

This is a great piece of code. It doesn’t work in the generic case, for instance when your object is a child of another object. I made some modifications to convert from parent relative coordinates to world coordinates. Here are the changes needed to drag a Cube along the plane formed by its front face

TypeError: Error #1007: Instantiation attempted on a non-constructor.
at Dragging3D$iinit()

Getting the above error and I’m working in Flash. Is this example workable in Flash? What should I be doing?

Many thanks

October 23rd, 2008

David

I find that when import the PV3D:
There is some version difference appear, between PV1.5 and PV2.0.
I discover that you use PV2.0, but put in FreeCamera3D.as(is in PV1.5).
However this cause other error, I cannot fix it. Such as the Matrix3D.as and the Number3D.as. All this need to import other src from the PV2.0 it makes me mess up.
Can you provide yr src of PV2.0 with yr modification for me. Thanks.
David.
BTW I am new for PV.

October 25th, 2008

David

Dragging in 3D. It is Cool!
However, I cannot find the PV3D src code that you use in this work.
Because they changed their version. I cannot get the one b4.
So can you let me know where I can find it. Thanks

October 26th, 2008

Ruben

That’s awesome man. Thak you very muy for helping us to learn

December 6th, 2008

Icek

Great work, but how to access stage, viewport and camera from within do3d?
Do I need to do everything inside BasicView/IView?

My problem is: I created do3d named Book. Inside Book, there are several BookPages (also do3d), and inside BookPages i got another do3d, and inside this do3d i want to do some dragging actions. Now I need to transmit variables (stage, viewport and camera) via each do3d constructor, but i think, that this method sucks. Other way is to use Singleton as Variable Locators, but this also doesn’t sound good.
So, how to this?

“A few months ago, Andy Zupko added some methods to Papervision3D which facilitated the ability to drag objects in 3d space. I collected those methods and placed them in a static class called RayTracer. The class currently has only one method which returns a Number3D object with the coordinates in 3D space based on the position of your mouse on a Plane3D object.”

February 23rd, 2009

strata

is it possible to drag a collada file????if it is, what i have to change in source code???

Ok, it’s been awhile and I think this is the best way to handle a drag.
/*This function gets the intersection on a temporary plane, change the normals on KeyDown or other Event to change the Axis of Drag */
public function getIntersection(vw:Viewport3D, c:Camera3D, normal:Number3D, origin:Number3D = 0,0,0):Number3D
{ var plane3D:Plane3D = new Plane3D(normal, origin);

/*CameraProperties.pitch refers to the new pitch of the orbit function of a Camera3D, this simulates a normal ( AXIS ) change based on where the camera is. Maybe the next version will blend the two AXIS based on the percentage of Pitch to MinPitch and MaxPitch */
if(CameraProperties.pitch<55){//Camera is below Isometric 45 degree angle
var intersect = getIntersection(default_viewport, default_camera, new Number3D(0,1,0), new Number3D(0,0,0)); //This locks drag on X and Z axis.
}else{
intersect = getIntersection(default_viewport, default_camera, new Number3D(0,0,1), new Number3D(target.x,target.y,target.z)); //This locks drag on Y axis and origin on dragging object.
}

April 28th, 2009

shalimar

Hi, i know this is about a year old. but does someone have a fully functional FLA file for this? Or maybe just a list of what is needed. I have been trying to get my papervision (2.0) folder to have all the necessary files but it wont compile without errors.

Im getting an error in the FreeCamera3D.as
1023: Incompatible override.

June 16th, 2009

Diyafury

Hi, I’m a complete novice when it comes to papervision…

Basically what I’ve got is a drag object which acts as a handle for a scrub bar which sits in the material for a plane.

I add the plane as a child of a displayObject3D (added to the scene), and add the handle as a child of the plane, hoping that somehow the dragging will be restricted to the width and the height of the plane… which ofcourse it isn’t…so my questions are:

1. how do i set boundaries for my handle so that it will only drag along the x between 2 specified points on my plane?

2. how can i get the 3D coords from a movieclip inside the plane’s material (ie. the scrub bar’s x,y,z) to use as boundaries?

Impressive!
Have you considered adding some live ActionScript class diagrams to your code? Please check my address and think about.

September 28th, 2010

Erdem

I’ve a question;

I’m trying to calculate 3D position of a mouse click position by detected marker’s plane. Is there any easy way to find 3D postion on the marker’s plane? I’ve tried to intersect 2D position with marker’s plane. I can get the ray vector fo the mouse click position by flarCamera3D’s unproject method. I also can get the marker’s 3D position. But I need to find the normal vector of the marker’s plane. So I can build a plane3D with setNormalAndPoint method. Then I can intersect the ray with this plane and the result will be the 3D position of the 2D mouse position.
My codes are here: