PDA

View Full Version : Moving Objects



CoolBeanJ
04-20-2011, 03:51 PM
I have picking implemented and working and can move my objects in 3D space with the mouse how ever the mouse moves faster than the object moves and I wanted the mouse to move at the same speed as the object regardless of how zoomed in the screen is.

I'm not sure how to do this currently i'm recording my previous mouse x and y location and calculating the difference and adding it to the objects x or y value.

Thanks for you time.

CoolBeanJ
04-21-2011, 06:01 PM
Nevermind guys I finally worked it out thanks.

CoolBeanJ
04-21-2011, 08:14 PM
Nope i thought i did but it only works in the front view... Has anyone done this before on here?

Kelvin
04-21-2011, 09:27 PM
It sounds like you have a perspective projection, and are translating an object in world space by the number of pixels the mouse moves. But this will make far objects move too slowly, and make near objects move too quickly. You need to convert from pixels to world coordinates.

Try this:

1. Unproject your first click position (e.g. gluUnProject).
2. While moving the mouse, unproject your new mouse position, using the same depth value from step 1. This will give you two points in world space.
3. Compute the vector from the first point to the second point.
4. While drawing the object while moving the mouse, displace the object by this additional vector.
5. When the mouse is released, add the vector permanently into the new object position.

CoolBeanJ
04-21-2011, 09:41 PM
First thank you so much for the reply! Been stuck on this for ages!

I will post my current code to help explain what i'm doing.

When the user clicks the mouse down i call this and keep a record of the posX posY and posZ


byte[] pixel = new byte[3];
int[] viewport = new int[4];

double[] ModelviewMatrix = new double[16];
double[] ProjectionMatrix = new double[16];


Gl.glGetIntegerv(Gl.GL_VIEWPORT, viewport);

Gl.glGetDoublev(Gl.GL_MODELVIEW_MATRIX, ModelviewMatrix);
Gl.glGetDoublev(Gl.GL_PROJECTION_MATRIX, ProjectionMatrix);

Gl.glReadPixels(x, viewport[3] - y, 1, 1, Gl.GL_RGB, Gl.GL_UNSIGNED_BYTE, pixel);
float[] depth = new float[1];
Gl.glReadPixels(x, viewport[3] - y, 1, 1, Gl.GL_DEPTH_COMPONENT, Gl.GL_FLOAT, depth);

Glu.gluUnProject(x, viewport[3] - y, depth[0], ModelviewMatrix, ProjectionMatrix, viewport, out posX, out posY, out posZ);


Now when the mouse moves i call this again saving a the new X Y and Z

then update the x or y or z like this



double worldX2 = 0;
double worldY2 = 0;
double worldZ2 = 0;
world.worldCoord(xrot, yrot, xpos, ypos, zpos, e.X, e.Y, out worldX2, out worldY2, out worldZ2);


if (yrot < 90 &amp;&amp; yrot > -90)
{
objectFound.locX += (Int16)(worldX2 - worldX);
}
else
{
objectFound.locX -= (Int16)(worldX2 - worldX);
}
ObjectData updatedObj = world.UpdateObj(objectFound);
modifiedObjects.Add(updatedObj);
worldX = worldX2;
worldY = worldY2;
worldZ = worldZ2;


Looking at what you have said it would seem that i am doing this wrong as i'm not storing the previous depth and using it for future calculations while moving the mouse.

Is that right or is there another step i'm missing?

Again thank you for the reply i have been up all night trying to figure this out.

EDIT: Ok so it would appear that i'm not calculating the new vector, how exactly would i do this?

CoolBeanJ
04-21-2011, 10:47 PM
Ok new info its for what ever reason the posZ is not working:

It will on some angles but i noticed when the object diapears the positions are as follows:

worldX = 365.21738320025707 (expected)

worldY = 382.60867747923692 (expected)

worldZ = -10000.000222818931 (wrong should be more like 0)

If more description of the problem is needed or more of the code let me know and i can post it.

CoolBeanJ
04-22-2011, 07:55 AM
Been at this all day, and i'm still at a loss.

Anyone have any ideas of where i might be going wrong?

Like i was saying it does work on most angles but other not.

CoolBeanJ
04-23-2011, 12:22 AM
Just relealised i never actually use the worldZ anyway, why would it soundly disappear?

Kelvin
04-23-2011, 06:06 PM
I don't really understand what your second code section is trying to do, so I can't offer any specific advice.

But the objects have positions in a world space (x,y,z). This world x, y, and z axes are not, in general, aligned with the screen, because the viewpoint could be rotated. So if you are moving the object, you need to update all three coordinates.

A vector (v_x, v_y, v_z) from point (x0,y0,z0) to point (x1,y1,z1) is computed like so:

v_x = x1 - x0
v_y = y1 - y0
v_z = z1 - z0

Then you can use glTranslate to temporarily offset the object position

glPushMatrix()
glTranslatef(v_x, v_y, v_z)
// draw object
glPopMatrix()

When you have the final position, then update the object position by adding the vector components to the object position components.

By the way - I suggested using the same depth buffer sample for unprojection (while dragging) so the object doesn't get nearer/farther while dragging.

CoolBeanJ
04-24-2011, 07:13 PM
Oh so I need to update all three co ords even though I only want to move in the x axis, or Z axis or Y axis at one at a time.

I don't know what it is that i'm doing wrong but I can't get this to work, Is there any sample or something on net for this?

Its like i was saying it does work to a degree but rotating the scene around and then moving the object sometimes cause the difference to be huge

as in worldY2 (new world point for this move) - worldY can be a huge distance.

Could it be due to the fact that i rotate my scene like this:



Gl.glTranslated(-xpos, -ypos, -zpos); //translate the screen to the position of our camera
Gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f); //rotate our camera on the x-axis (left and right)
Gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f); //rotate our camera on the y-axis (up and down)


Gl.glPushMatrix();



Because it works fine from the front view but any rotation seems to break it after a bit of moving around.

CoolBeanJ
04-25-2011, 06:04 PM
My question I guess is now, do I have to do anything special when I rotate my scene with glrotatef when getting the model view matrix etc.


Because i'm rtating my scene with glrotatef when drawing but not when doing the gluUnproject.

Just not sure what would be involved in it.

Kelvin
04-25-2011, 07:02 PM
Oh so I need to update all three co ords even though I only want to move in the x axis, or Z axis or Y axis at one at a time.

It depends on whether you are trying to move the object along the screen X axis or the world X axis. These are not the same axis once you rotate your view. If you rotate the view, then moving along the screen X axis could be moving along the world Y axis, or along some crazy direction that is not on any world axis. From your description, I was assuming you wanted the object to follow the mouse screen position. To make the object appear to move along a screen axis, you'll have to move in a different world direction.

If you really just want to move along a world axis, just adjust the corresponding object coordinate directly (and maybe hide the mouse pointer).



do I have to do anything special when I rotate my scene with glrotatef when getting the model view matrix etc.

When you unproject, you need the modelview matrix to include any "view" transformations, but not "model" transformations. Basically, include only those transformations you consider to be "moving the camera around".

So if your glRotate is just rotating the object (like turning an apple around in your hand), then don't include it.

But if your glRotate is like having the apple sitting on a table, and you walk around to look at it from a different angle, then do include it.

When transforming the object during drawing, you include both model and view transformations.

This rule applies for all transformations (not just glRotate).

More details:

Conceptually, your vertices start in "object coordinates". Then you multiply by a "model matrix" to transform the vertices into "world coordinates". In world coordinates, everything has a common scale, a common reference origin, and common axes (like you plotted everything out on graph paper).

After that, you multiply by a "view matrix" to tranform the vertices into "eye coordinates" (aka camera coordinates). This moves the world to put your eye point at some world coordinate. In eye coordinates, the eye is always at (0,0,0), by definition.

OpenGL combines these two steps together as the "modelview matrix". Multiplying your object vertices by the "modelview matrix" transforms them directly from object coordinates to eye coordinates, with no stop in-between for world coordinates.

But you can arrange for this intermediate stopping point by loading the modelview matrix with only the "view" transforms. This isn't very useful for drawing, but it should be helpful for unprojecting. The "view" transforms are the first ones you do (if you do any).

This might sound like overkill, but to get very far in OpenGL, you'll need to get used to thinking in different coordinate spaces, and understanding what matrices convert between these spaces.

The OpenGL "Red Book" could be helpful here, and there are lots of other published books, and web tutorials. Just look for ones that have real concept information, not just code. Draw your own diagrams to help yourself understand how points in virtual 3D space are projected to the screen.

CoolBeanJ
04-25-2011, 07:13 PM
Thank you very much for the detailed reply, I'm sorry to keep bugging you but

"If you really just want to move along a world axis, just adjust the corresponding object coordinate directly"

What exactly do you mean by this? Do you mean just with the mouse? i.e difference = mouseX - previousMouseX type of thing?

Also:

"But if your glRotate is like having the apple sitting on a table, and you walk around to look at it from a different angle, then do include it."

Is exactly what its doing i basically use it as a camera and then push, draw my objects and then pop.

Thanks again for the reply and sorry for all the trouble.


_______

This is a bad drawing of the problem (ms paint)

http://img42.imageshack.us/img42/7061/imageofproblem.png


All I want is say you click the blue axis (i can do the picking) and drag the mouse it will move along that axis.

Kelvin
04-25-2011, 08:08 PM
This depends so much on how your wrote your code. You probably don't want to update your object vertex coordinates directly. Usually, you define your object (like a square) to have vertices (-1,-1),(-1,1),(1,1),(1,-1), with (0,0) in the middle (or at some convenient reference point). Then you would use glTranslate to position the square in the world. That way you can move the square around (or draw lots of squares) without changing all those vertex values.

Assuming you move objects with glTranslate:

If you unproject using only view transformations (i.e. don't include that glTranslate), you'll get world coordinates, and you can calculate the unprojected differences for each world coordinate axis. Then you would add those differences to the values passed to glTranslate.

When I said "adjust the corresponding object coordinate directly", I meant adjusting the "X" value in the glTtranslate call (or adjusting whichever world axis you want to move along). You can adjust it by the amount of mouse movement. Just don't expect the object position to follow the mouse pointer on the screen (it might even move in the opposite direction). I don't think this will do what you want, but you can try it for fun.

It sounds like your glRotate is a "camera move," so it should be included in the modelview matrix when you do the unproject to get world coordinates.

Assuming you move objects by adjusting the object vertex values directly:

In this case you need to include the same modelview transformations in the modelview matrix that you used while drawing the object. In this case, the unproject will give you values in object coordinates, and you would update the object vertices directly with the differences.

If you adjusted only the X (or Y or Z) coordinate in the object vertices, then the object will move "to the object's right" (or left or whatever). Which is also probably not what you want.

Kelvin
04-25-2011, 08:33 PM
Hmm, from your new picture, I see you don't have a free-moving object position that follows the mouse. You have to choose the axis first.

FYI, this would have been a good picture to post with your first question. Along with whether those axes are "attached" to the cube (object axes), or whether they are world XYZ axes (or maybe they are attached to the cube, but always aligned with the world XYZ axes.

The object will always be moving along the axis, so it won't follow the mouse pointer if the pointer moves away from the axis. But I guess you want to object to follow the mouse if the mouse is staying on the axis.

Unfortunately for my explanations, this is a totally different scenario than what I had guessed you were asking about. So my suggestion about re-using the depth value, and maybe even using unproject at all is not useful.

Although I'm sure this can be done, I don't have the proper approach off the top of my head. It seems like you probably do just want to update only the X, Y, or Z value though (depending on the axis clicked), and assuming those are world (or world-axis-aligned) axes.

CoolBeanJ
04-25-2011, 09:02 PM
I see, I'm terribly sorry for wasting your time.

The way that i'm drawing the axis is like this

set scene up with gltranslate and rotate

push

translate to the objects X Y and Z
Rotate to the objects X Y and Z value
draw the object
Draw the axis marker, the blue line, green line and red line. (this has the same translation and rotation as the object)

pop

I do not mind if the mouse is not tied to the axis as long as once selected (say the blue) you moving the mouse to the left will make it move negative on that axis and positive when moving it right.

Again i want to appologize, you have been nothing but helpful to me and i've stuffed you arround by not posting a proper description. Sorry.

Kelvin
04-26-2011, 02:02 AM
Well, I did jump in with a suggestion for what I could tell was an incomplete problem statement. Any time wasted of mine is ultimately my fault, not yours, but I do appreciate the sentiment. The real pros here will often respond with "you need to give us more information if you want help" if they're being generous (the alternative being to just ignore the post). Your last couple of posts were great though -- they really got to the heart of the problem. Asking a question that way is more likely to be answered, and more likely to be answered usefully.

Sadly, I don't have an actual answer, but here's some further thinking, and some possible approaches:

Since your axes share the same translation and rotation as your object, they are "local" object axes, not world axes. If you want to move the object along a local object axis, you'll need to introduce another translate.


scene translate
scene rotate
push (matrix)
translate object (and axes)
rotate object (and axes)
draw axes
translate object // movement along local axis would go here
draw object
pop

Since you already know the desired direction of movement in obect space, we have to figure out what that direction is in window ("mouse") space. The object's "X" axis could be facing any old direction in window space, depending on both the object rotation and the view rotation.

Just like "Unproject" can work backwards, we can work forwards instead. One way is to use GL feedback mode to get the origin and the tip of your desired axis (use a unit vector) in window coordinates space. Alternatively, you can manually do the pipeline transformation yourself (v' = PMv, then perspective divide, then viewport scaling). Either way, you've now got two points in window space, and you can determine the direction of the object axis on the window.

This should be enough information to at least get the mouse and the object moving in the same direction. (I.e. if the object X vector is actually pointing left on the window, make "mouse left" increase object coordinate X.

There's probably a better way to get the window vector directly by transforming the object vector, instead of transforming endpoints. And I've ignored potential problems with clipping.

Getting the object movement to exactly track the mouse movement would require knowing how much object distance to move per mouse movement -- and that amount won't be constant if you are using perpective projecion. If you're using orthographic projection, it will at least be constant during one mouse drag, but you'd have to figure the correct scale factor every time. You can use perpendicular projection from the mouse point to the selected axis on the screen to find a sensible point on the line regardless of where the mouse pointer is (or you could just use the major axis: use mouse X if the object axis is mostly horizontal on screen; use mouse Y if the object axis is mostly vertical). But finding the object movement is harder.

Basically, you've got two lines -- the line on the window that you follow with the mouse, and the line the object will move along. Or rather, you have two views of the same line. You want a formula that will tell you the movement in one space, when given the movement in another. I think you could write a parametric vector equation for the line in object coordinates (the line that is the extension of the selected axis), and transform the equation with the same matrices, etc. used for point transformation (using algebra, not raw numbers). This should result in an equation for window space movement given object space movement (backwards from what you actually want). But ultimately after some additional fooling around, you should be able to get an equation that says mouse movement from a to b along the window line means object movement from a' to b' along the desired object axis. Not that easy to say, but still easier said than done :).

It's an interesting problem; it's certainly harder to do than it seems. I'll probably have to give up here, but I wish you luck.

CoolBeanJ
04-26-2011, 06:00 AM
Well i have some ideas now, thank you very much I think i'll simplfy my problem and just work my way up.

Thanks for all the help and advice, you have been amazing!