• Advertisement
Sign in to follow this  

Selecting a cube, orthogonal view

This topic is 4347 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I have a 3D raster, filled with cubes. A little bit like the GTA1/2 editor works. Now I want to select these cubes, or paint on faces by clicking on it. Normally I would calculate the 'mouseVector', as if a ray comes out your cursor. Then trying to intersect with the cubes. But now I have an orthogonal view, and you see the terrain from... Maybe I should make this drawing, lack of english to explain it
    ___
   /_ /|      // a cube 
   |__|/    
===========   // the road
Isometric was the right word? Anyway, I don't know how to calculate that mouse vector, from screen to world. Given are the camera position, direction and mouse X,Y coords. Greetings, Rick

Share this post


Link to post
Share on other sites
Advertisement
This is a typical "picking" problem. I don't think that the orthogonal view should impose a problem...
What you need to do, is express the coordinates of the mouse cursor in normalized screen space and transform them by the inverse view matrix. This will leave you with a direction vector in global coordinates (the direction implied by the mouse cursor). That vector has its tail, (it starts at) the point where the camera lies.

You can also transform the normalized cursor coordinates by the product "inverseWorldMatrix"*"inverseViewMatrix" to find the aforementioned vector and point in the local space (model space) of a specific object. This may allow for easier "ray intersection" check since you'll probably have access to the un-transformed vertices and the axes of the object will be parallel to the X,Y,Z axes...

Some pseudocode:

// The normalized screen-space coordinates of the mouse cursor...
Vector3 v;
v.x = ( (2*cursor.x / ViewportWidth) - 1 ) / ProjectionMatrix(1,1);
v.y = -( (2*cursor.y / ViewportHeight) - 1 ) / ProjectionMatrix(2,2);
v.z = 1.f;

Matrix4x4 m = InverseViewMatrix;
Vector3 direction, origin;

// Calculate the direction implied by the cursor... (global coordinates)
direction.x = v.x*m(1,1) + v.y*m(1,2) + v.z*m(1,3);
direction.y = v.x*m(2,1) + v.y*m(2,2) + v.z*m(2,3);
direction.z = v.x*m(3,1) + v.y*m(3,2) + v.z*m(3,3);

// The "direction" vector passes through this point (in global coordinates)
origin.x = m(4,1);
origin.y = m(4,2);
origin.z = m(4,3);


You can replace the step: Matrix4x4 m = InverseViewMatrix,
with: Matrix4x4 m = InverseWorldMatrix*InverseViewMatrix;

to calculate the direction and origin in the local space of any object, as mentioned above.

edit:
The above snippet assumes column-major vector convention. If you work with row-major transformations instead, use the symmetric of any member of a matrix that I mentioned (just swap the indices), and if you have to use the step:
Matrix4x4 m = InverseWorldMatrix*InverseViewMatrix;

switch the order of the matrices in the right member.

Share this post


Link to post
Share on other sites
Thanks for such a detailed answer!

However, I still get weird results. Probably I did something wrong, I'm really bad with matrices. Well, all vertices are in absolute space, so converting to local space isn't nessesary. Basically I need the 'mouseToScreen' vector, just like you told.

Maybe I'm not finishing it the right way. If I understand your code, you calculate the (global) mouse direction and 'tail' position? Is there something I need to do with both values? I tried to subtract and normalize them to get a final result, but that didn't work. Or is the 'direction' variable the actual mouseVector I can use for stuff like raycasting? The direction variable itself had some very high values (outside -1..+1 range), but normalizing it didn't work either(very small values).

The origin value was the same as the camera position, so I assume that's correct though.

Or maybe I'm using the wrong matrices? I'm using OpenGL so I retrieved the matrices like this:

glGetFloatv( GL_PROJECTION_MATRIX , @pm );
glGetFloatv( GL_MODELVIEW_MATRIX , @imv );
invertMatrix( imv );


Oh, and by the way, I assume you mean the 'first' element of the matrix when you write '[1,1]', right? And the first element would be x/column index, and the second the y/row, right? Or vice versa? Plenty of ways to write down a matrix, so I'd better ask to make sure I didn't mix up numbers!

Thanks for helping!
Rick

Share this post


Link to post
Share on other sites
Hey Rick,
I haven't used openGL, so there may be some detail I'm missing here... Let me see...
First of all, when I write down a member of a matrix as m(x,y) I mean the element at the x-th row and y-th column. I think openGL uses common unidimensional array indices for matrices, so the relation between them should look like:

[ m[0] m[4] m[8] m[12] ]
[ m[1] m[5] m[9] m[13] ]
[ m[2] m[6] m[10] m[14] ]
[ m[3] m[7] m[11] m[15] ]

You can double-check with this, to make sure you got them right.

The "direction" vector as calculated above, is the direction of the ray cast by the mouse cursor in the 3d scene. But this vector -alone- is not enough. You need to also know a point through which it passes, in order to be able to make any use of it. That point is merely the camera's position, which is the point "origin" in the pseudo-code I posted.
You don't need to do anything to these two, like add them, subtract them or something.... You can only use them in a pair. There's no point in knowing a direction, if you don't also know with respect to which point it is measured (origin).

What seems weird to me, is that you're getting big numbers in the "direction" vector... The x/y components of the "v" vector lie in [-1,1] and the third one is 1, which means that its magnitude cannot be greater than sqrt(3).
Also, the part of the matrix "m" that you should use to transform "v" into "direction", has the property that |v| == |direction|. (It preserves the length of the vector it transforms)
This means, that all components of the "direction" should be in the range [-sqrt(3), sqrt(3)]. If you are getting bigger numbers, there's definitely something wrong with the "m" matrix, maybe you don't invert the view matrix correctly?...

I'm pretty sure we can get this to work, because I use it all the time, and it works. If you're certain that you've got it all right, but still you don't get intersections when you should, try setting the Z-component of "v" to -1, instead of 1. I'm not sure, but this could be necessary for openGL.
Also, are you 100% certain that your "ray-cube" intersection function works?

Share this post


Link to post
Share on other sites
The raycasting shouldn't be the problem. It only intersects with the floor plane now, so its code like this:

pos = origin;
while pos.y > 0 do begin
pos.x += direction.x;
pos.y += direction.y;
pos.z += direction.z;
end;

Y is the up vector. When it reaches the ground, I draw a quad on 'pos' and a line between the mouse cursor and 'pos' to check.

I corrected a couple of things, but its still not 100%. I don't get these big numbers anymore, and I removed the subtracting and normalizing stuff. Now the numbers seems to be in [-1..+1] range, although they still get above 1 when the cursor comes near a border. Also Y can become above 0, while I'm looking downwards. Also when the mouse cursor hits the bottom, the Y vector is -1.4 or something. That should not be possible, I'm looking downwards, but on a certain angle (45 degrees or something). That brings me to another question, the 'cursor.y' value, does '0' represent the top of the screen, or the bottom? I assumed that x,y = 0,0 was the top-left corner.

The direction 'follows' my mouse, but too much. So if I keep the mouse in the center of the screen, the result is pretty good, but the more I get away from it, the larger the direction vector becomes, as if it was multiplied with some factor.

I disabled othogonal viewing and changed camera focalLength (from 30 to 50). The results were much better, but still not close enough. Any idea what's going on?

Oh, and I tried -1 to 'v' but that didn't work, the Y vector was pointing up instead down. But I also tried it on direction.z, otherwise it moved exactly the opposite way.

Thanks again for helping!
Rick

Share this post


Link to post
Share on other sites
Quote:

Y is the up vector. When it reaches the ground, I draw a quad on 'pos' and a line between the mouse cursor and 'pos' to check.

What exactly do you mean with "Y is the up vector"? Is it the "pos" vector in the code snippet you posted? Then it should be the vector from the origin to the point where the "direction" intersects the floor.

Quote:

I corrected a couple of things, but its still not 100%. I don't get these big numbers anymore, and I removed the subtracting and normalizing stuff. Now the numbers seems to be in [-1..+1] range, although they still get above 1 when the cursor comes near a border. Also Y can become above 0, while I'm looking downwards. Also when the mouse cursor hits the bottom, the Y vector is -1.4 or something. That should not be possible, I'm looking downwards, but on a certain angle (45 degrees or something).

Sorry about that, my fault. The "v" vector contains normalized screen-space coordinates of the cursor "before" the final division by the elements of the projection matrix. To avoid this division on vectors later, (which adjusts for width and height at the near clipping plane) it's convenient to do it there, so there's no need that its components remain in [-1,1].
I often refer to this vector as "normalized" and forget that it's actualy not, since I stuff those divisions there. Sorry about that.

Quote:

That brings me to another question, the 'cursor.y' value, does '0' represent the top of the screen, or the bottom? I assumed that x,y = 0,0 was the top-left corner.

Yes, it increases from top of the screen to bottom. This is why -to counteract it- you negate v.y; in normalized coordinates it should increase from bottom to top.

Quote:

The direction 'follows' my mouse, but too much. So if I keep the mouse in the center of the screen, the result is pretty good, but the more I get away from it, the larger the direction vector becomes, as if it was multiplied with some factor.

For orthogonal view, try dividing v.x and v.y by 2.
For perspective try dividing them by 2*znear.

If none of these seem to work, post the view & projection matrices you use (the actual numbers you get on the debugger), as well as the values of all parameters used to calculate them, like camera pos/target, FOV angle etc...

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement