World coordinates to screen coordinates.

NoteMe

Newcomer
This is more of a pure math question, so please move it or toast it if it is not suited here..:)


I am trying to draw some 3D objects from scratch here. Not using OpenGL or DirectX.

But I have forgot most of my math books back in Norway, and I can't remember exactly how to go about this. I am using a left handed coordinat system (sorry OGL guys). I guess I first have to translate from world coordinates to eye/camera coordinates, right? And then from eye/camera to screen coordinates? I think the second step should be easy, but what about the first one? How is that done again? Do I have to do something like this?':

Eye-coordinates = Camera-Matrix * World-Coordinate

But how is the rows and colums in the Camera Matrix looking then? What goes into what rows and colums.

Or am I totaly wrong about this. Please advice me. Thanks.
- ØØ -
 
If you were using the same coordinate system as OpenGL it'd be easy. You could just look at the code for the gluUnproject function. Do you think it might still help you, though?
 
Left VS Right hand coords doesn't really make a lot of difference - all you are doing is deciding (say) whether Z increases or decreases going into the screen (so you can fix that by flipping the sign of a coordinate).

Perhaps of more importance is whether your vectors are in row or column form, because that then determines whether you do Vector*Matrix or Matrix*vector, which in turn determines the order you use when concatenating matrices.
 
Think about it in reverse, and build the matrix to convert from view-space to world-space.
The view-to-world matrix contains the right, up, forward and position vector of the camera in the rows. (I assumed you use row vectors.)

That is:
Code:
[cam_right.x,    cam_right.y,    cam_right.z,     0]
[cam_up.x,       cam_up.y,       cam_up.z,        0]
[cam_forward.x,  cam_forward.y,  cam_forward.z,   0]
[cam_position.x, cam_position.y, cam_position.z,  1]

To convert from world-space to view-space invert the matrix.
 
To convert from view-space to screen-space: (assuming perspective transformation)

screen.x = screen.width/2 + view.x / view.z / tan(h_fov/2) * screen.width/2;
screen.y = screen.height/2 - view.y / view.z / tan(h_fov/2) * screen.width/2;

where h_fov is the horizontal fov of the screen (in radians of course).
And no - having screen.width at the second row is not a typo.
 
To convert from view-space to screen-space: (assuming perspective transformation)

screen.x = screen.width/2 + view.x / view.z / tan(h_fov/2) * screen.width/2;
screen.y = screen.height/2 - view.y / view.z / tan(h_fov/2) * screen.width/2;

where h_fov is the horizontal fov of the screen (in radians of course).
And no - having screen.width at the second row is not a typo.

that was a very original way to say that the hight factor gets canceled ; )
 
Hyp-X said:
To convert from view-space to screen-space: (assuming perspective transformation)

screen.x = screen.width/2 + view.x / view.z / tan(h_fov/2) * screen.width/2;
screen.y = screen.height/2 - view.y / view.z / tan(h_fov/2) * screen.width/2;

where h_fov is the horizontal fov of the screen (in radians of course).
And no - having screen.width at the second row is not a typo.


Wow...so that is it?...sounds to good to be true...but could you please add some parentheses there....? I asume that * has a higher "priority"/precedence then / but there is still chaos in there..:)

And just to be sure. when you say h_fov. That means the angle in radians in the "view" point between the two lines going to the right side and the left side of the far and/or near plane...It has to be I guess...probably just dumb question.

But it is still weird to see that you have h_fov on both lines and screen.width. But if you say so I belive you and will try it out when I wake up tomorrow. Right now we are drinking at work..:)...so...:)...


- ØØ -
 
Last edited by a moderator:
Hyp-X said:
Think about it in reverse, and build the matrix to convert from view-space to world-space.
The view-to-world matrix contains the right, up, forward and position vector of the camera in the rows. (I assumed you use row vectors.)

That is:
Code:
[cam_right.x,    cam_right.y,    cam_right.z,     0]
[cam_up.x,       cam_up.y,       cam_up.z,        0]
[cam_forward.x,  cam_forward.y,  cam_forward.z,   0]
[cam_position.x, cam_position.y, cam_position.z,  1]

To convert from world-space to view-space invert the matrix.

That sounds simple enough. Hmmm..well to asume that I use row vectors, is more like telling me to use row vectors at this point..:)..as it says in the first post...:)

So I will invert this matrix and then multiply it with the coordinates of the objects or? (object coordinates in world space I mean), and then they are in view space?
 
Another easy way to get the matrix is to look at what the matrix does to unit vectors. You can also multiply multiple matricies to do more complicated things.

Also, the OpenGL spec describes a number of matrices for performing basic operations (though it's easier to think of rotation matrices in the manner I wrote above than the OpenGL way).
 
Chalnoth said:
Another easy way to get the matrix is to look at what the matrix does to unit vectors. You can also multiply multiple matricies to do more complicated things.


I am not getting you here. How can I look at what it does to unit vectors when I don't have the projection matrix all ready?

And yeah, I know I can multipy matrices. But speaking of that. I woke up this night and had an idea. Is what I am looking for actualy just a rotation and then a translation transformation. To get it into view space?

I mean, if I have a point (3,4) in world space. Can I just rotate it with the "look at" vector, and then translate it according to the "position" of the camera? Will that get it from world space to view space?


- ØØ -
 
NoteMe said:
Can I just rotate it with the "look at" vector?

Nope, just one vector is insufficient for rotation.
Think about it; you can roll your head while still looking at the same place (same look at vector), but the result is obviously different.
A "look at" and an "up" vector is sufficient where "up" can be constant (eg. (0, 1, 0)) if you don't want to apply roll.
To get the vectors in my description:

cam_forward = normalize(look_at);
cam_right = normalize(cross(cam_forward, up));
cam_up = cross(cam_right, cam_forward);

Note that this is an orthonormal set of vectors where the inverse of the view-to-world matrix takes the special form:

Code:
[cam_right.x, cam_up.x, cam_forward.x, 0]
[cam_right.y, cam_up.y, cam_forward.y, 0]
[cam_right.z, cam_up.z, cam_forward.z, 0]
[dot(cam_right, -cam_position), dot(cam_up, -cam_position), dot(cam_forward, -cam_position), 1]
 
Hmm...that looks so easy...but I must be doing something wrong here. Lets say that we have a scenario like this:

world.JPG


All these coordinates is in world coordinates. The dot with the arrow is the camera, pointing in the direction you can see the arrow points. The X is the point that I want to transform from world space to view space.

The cameras lookAt vector is (-1,0,0) (it is a free/zero vector right, and not a point?), and up is (0,1,0) since this is a FPS camera.

Shouldn't the coodinates to transformed object there become (0,2,0)? I can't get that result at all. I am a bit confused about the rows and columns here, so I guess that is what makes this go wrong, but I have tried to change them, but still I can't get (0,2,0). BTW I should use W too right?
 
Last edited by a moderator:
BTW if anyone has the time and energy, here is my code at least the importent stuff (coded in C#..sorry).

Code:
[color=#3333FF]public[/color][color=#FF6633] float[/color][b][color=#000000] this[/color][/b][b][color=#663300][[/color][/b][color=#FF6633]int[/color] Row[b][color=#663300],[/color][/b][color=#FF6633] int[/color] Col[b][color=#663300]] {[/color][/b]
	get[b][color=#663300]{[/color][/b][color=#3333FF]return[/color][b][color=#000000] this[/color][/b][b][color=#663300].[/color][/b]m_matrix[b][color=#663300][[/color][/b]Row[b][color=#663300],[/color][/b] Col[b][color=#663300]];}[/color][/b]
	set[b][color=#663300]{[/color][/b][b][color=#000000]this[/color][/b][b][color=#663300].[/color][/b]m_matrix[b][color=#663300][[/color][/b]Row[b][color=#663300],[/color][/b]Col[b][color=#663300]] =[/color][/b] value[b][color=#663300];}
}[/color][/b][color=#3333FF]


public static[/color] Vector[color=#3333FF] operator[/color][b][color=#663300] *([/color][/b]Matrix m1[b][color=#663300],[/color][/b] Vector v1[b][color=#663300]){[/color][/b]
	Vector trans[b][color=#663300] =[/color][/b][color=#3333FF] new[/color] Vector[b][color=#663300]();[/color][/b]
	trans[b][color=#663300].[/color][/b]X[b][color=#663300] = ([/color][/b]v1[b][color=#663300].[/color][/b]X[b][color=#663300] *[/color][/b] m1[b][color=#663300][[/color][/b][color=#999900]0[/color][b][color=#663300],[/color][/b][color=#999900]0[/color][b][color=#663300]]) + ([/color][/b]v1[b][color=#663300].[/color][/b]Y[b][color=#663300] *[/color][/b] m1[b][color=#663300][[/color][/b][color=#999900]1[/color][b][color=#663300],[/color][/b][color=#999900]0[/color][b][color=#663300]]) + ([/color][/b]v1[b][color=#663300].[/color][/b]Z[b][color=#663300] *[/color][/b] m1[b][color=#663300][[/color][/b][color=#999900]2[/color][b][color=#663300],[/color][/b][color=#999900]0[/color][b][color=#663300]]) + ([/color][/b]v1[b][color=#663300].[/color][/b]W[b][color=#663300] *[/color][/b] m1[b][color=#663300][[/color][/b][color=#999900]3[/color][b][color=#663300],[/color][/b][color=#999900]0[/color][b][color=#663300]]);[/color][/b]
	trans[b][color=#663300].[/color][/b]Y[b][color=#663300] = ([/color][/b]v1[b][color=#663300].[/color][/b]X[b][color=#663300] *[/color][/b] m1[b][color=#663300][[/color][/b][color=#999900]0[/color][b][color=#663300],[/color][/b][color=#999900]1[/color][b][color=#663300]]) + ([/color][/b]v1[b][color=#663300].[/color][/b]Y[b][color=#663300] *[/color][/b] m1[b][color=#663300][[/color][/b][color=#999900]1[/color][b][color=#663300],[/color][/b][color=#999900]1[/color][b][color=#663300]]) + ([/color][/b]v1[b][color=#663300].[/color][/b]Z[b][color=#663300] *[/color][/b] m1[b][color=#663300][[/color][/b][color=#999900]2[/color][b][color=#663300],[/color][/b][color=#999900]1[/color][b][color=#663300]]) + ([/color][/b]v1[b][color=#663300].[/color][/b]W[b][color=#663300] *[/color][/b] m1[b][color=#663300][[/color][/b][color=#999900]3[/color][b][color=#663300],[/color][/b][color=#999900]1[/color][b][color=#663300]]);[/color][/b]
	trans[b][color=#663300].[/color][/b]Z[b][color=#663300] = ([/color][/b]v1[b][color=#663300].[/color][/b]X[b][color=#663300] *[/color][/b] m1[b][color=#663300][[/color][/b][color=#999900]0[/color][b][color=#663300],[/color][/b][color=#999900]2[/color][b][color=#663300]]) + ([/color][/b]v1[b][color=#663300].[/color][/b]Y[b][color=#663300] *[/color][/b] m1[b][color=#663300][[/color][/b][color=#999900]1[/color][b][color=#663300],[/color][/b][color=#999900]2[/color][b][color=#663300]]) + ([/color][/b]v1[b][color=#663300].[/color][/b]Z[b][color=#663300] *[/color][/b] m1[b][color=#663300][[/color][/b][color=#999900]2[/color][b][color=#663300],[/color][/b][color=#999900]2[/color][b][color=#663300]]) + ([/color][/b]v1[b][color=#663300].[/color][/b]W[b][color=#663300] *[/color][/b] m1[b][color=#663300][[/color][/b][color=#999900]3[/color][b][color=#663300],[/color][/b][color=#999900]2[/color][b][color=#663300]]);[/color][/b]
	trans[b][color=#663300].[/color][/b]W[b][color=#663300] = ([/color][/b]v1[b][color=#663300].[/color][/b]X[b][color=#663300] *[/color][/b] m1[b][color=#663300][[/color][/b][color=#999900]0[/color][b][color=#663300],[/color][/b][color=#999900]3[/color][b][color=#663300]]) + ([/color][/b]v1[b][color=#663300].[/color][/b]Y[b][color=#663300] *[/color][/b] m1[b][color=#663300][[/color][/b][color=#999900]1[/color][b][color=#663300],[/color][/b][color=#999900]3[/color][b][color=#663300]]) + ([/color][/b]v1[b][color=#663300].[/color][/b]Z[b][color=#663300] *[/color][/b] m1[b][color=#663300][[/color][/b][color=#999900]2[/color][b][color=#663300],[/color][/b][color=#999900]3[/color][b][color=#663300]]) + ([/color][/b]v1[b][color=#663300].[/color][/b]W[b][color=#663300] *[/color][/b] m1[b][color=#663300][[/color][/b][color=#999900]3[/color][b][color=#663300],[/color][/b][color=#999900]3[/color][b][color=#663300]]);[/color][/b][color=#3333FF]
	return[/color] trans[b][color=#663300];
}[/color][/b]


and:
Code:
Vector cam_forward[b][color=#663300] =[/color][/b][color=#3333FF] new[/color] Vector[b][color=#663300]();[/color][/b]
Vector cam_right[b][color=#663300] =[/color][/b][color=#3333FF] new[/color] Vector[b][color=#663300]();[/color][/b]
Vector cam_up[b][color=#663300] =[/color][/b][color=#3333FF] new[/color] Vector[b][color=#663300]([/color][/b][color=#999900]0[/color][b][color=#663300],[/color][/b][color=#999900]1[/color][b][color=#663300],[/color][/b][color=#999900]0[/color][b][color=#663300]);[/color][/b]

Vector look_at[b][color=#663300] =[/color][/b][color=#3333FF] new[/color] Vector[b][color=#663300](-[/color][/b][color=#999900]1[/color][b][color=#663300],[/color][/b][color=#999900] 0[/color][b][color=#663300],[/color][/b][color=#999900] 0[/color][b][color=#663300]);[/color][/b]
Vector position[b][color=#663300] =[/color][/b][color=#3333FF] new[/color] Vector[b][color=#663300]([/color][/b][color=#999900]3[/color][b][color=#663300],[/color][/b][color=#999900] 2[/color][b][color=#663300],[/color][/b][color=#999900] 0[/color][b][color=#663300]);[/color][/b]
Vector myObject[b][color=#663300] =[/color][/b][color=#3333FF] new[/color] Vector[b][color=#663300]([/color][/b][color=#999900]1[/color][b][color=#663300],[/color][/b][color=#999900] 2[/color][b][color=#663300],[/color][/b][color=#999900] 0[/color][b][color=#663300]);[/color][/b]

cam_forward[b][color=#663300] =[/color][/b] look_at[b][color=#663300].[/color][/b]Normalise[b][color=#663300]();[/color][/b]
cam_right[b][color=#663300] =[/color][/b] cam_forward[b][color=#663300].[/color][/b]CrossProd[b][color=#663300]([/color][/b]cam_up[b][color=#663300]).[/color][/b]Normalise[b][color=#663300]();[/color][/b]
cam_up[b][color=#663300] =[/color][/b] cam_right[b][color=#663300].[/color][/b]CrossProd[b][color=#663300]([/color][/b]cam_forward[b][color=#663300]);[/color][/b]

Matrix view[b][color=#663300] =[/color][/b][color=#3333FF] new[/color] Matrix[b][color=#663300]([/color][/b][color=#999900]4[/color][b][color=#663300]);[/color][/b]
view[b][color=#663300][[/color][/b][color=#999900]0[/color][b][color=#663300],[/color][/b][color=#999900]0[/color][b][color=#663300]] =[/color][/b] cam_right[b][color=#663300].[/color][/b]X[b][color=#663300];[/color][/b]
view[b][color=#663300][[/color][/b][color=#999900]0[/color][b][color=#663300],[/color][/b][color=#999900]1[/color][b][color=#663300]] =[/color][/b] cam_right[b][color=#663300].[/color][/b]Y[b][color=#663300];[/color][/b]
view[b][color=#663300][[/color][/b][color=#999900]0[/color][b][color=#663300],[/color][/b][color=#999900]2[/color][b][color=#663300]] =[/color][/b] cam_right[b][color=#663300].[/color][/b]Z[b][color=#663300];[/color][/b]

view[b][color=#663300][[/color][/b][color=#999900]1[/color][b][color=#663300],[/color][/b][color=#999900]0[/color][b][color=#663300]] =[/color][/b] cam_up[b][color=#663300].[/color][/b]X[b][color=#663300];[/color][/b]
view[b][color=#663300][[/color][/b][color=#999900]1[/color][b][color=#663300],[/color][/b][color=#999900]1[/color][b][color=#663300]] =[/color][/b] cam_up[b][color=#663300].[/color][/b]Y[b][color=#663300];[/color][/b]
view[b][color=#663300][[/color][/b][color=#999900]1[/color][b][color=#663300],[/color][/b][color=#999900]2[/color][b][color=#663300]] =[/color][/b] cam_up[b][color=#663300].[/color][/b]Z[b][color=#663300];[/color][/b]

view[b][color=#663300][[/color][/b][color=#999900]2[/color][b][color=#663300],[/color][/b][color=#999900]0[/color][b][color=#663300]] =[/color][/b] cam_forward[b][color=#663300].[/color][/b]X[b][color=#663300];[/color][/b]
view[b][color=#663300][[/color][/b][color=#999900]2[/color][b][color=#663300],[/color][/b][color=#999900]1[/color][b][color=#663300]] =[/color][/b] cam_forward[b][color=#663300].[/color][/b]Y[b][color=#663300];[/color][/b]
view[b][color=#663300][[/color][/b][color=#999900]2[/color][b][color=#663300],[/color][/b][color=#999900]2[/color][b][color=#663300]] =[/color][/b] cam_forward[b][color=#663300].[/color][/b]Z[b][color=#663300];[/color][/b]

view[b][color=#663300][[/color][/b][color=#999900]3[/color][b][color=#663300],[/color][/b][color=#999900]0[/color][b][color=#663300]] =[/color][/b][color=#999900] 0[/color][b][color=#663300];[/color][/b]
view[b][color=#663300][[/color][/b][color=#999900]3[/color][b][color=#663300],[/color][/b][color=#999900]1[/color][b][color=#663300]] =[/color][/b][color=#999900] 0[/color][b][color=#663300];[/color][/b]
view[b][color=#663300][[/color][/b][color=#999900]3[/color][b][color=#663300],[/color][/b][color=#999900]2[/color][b][color=#663300]] =[/color][/b][color=#999900] 0[/color][b][color=#663300];[/color][/b]
view[b][color=#663300][[/color][/b][color=#999900]3[/color][b][color=#663300],[/color][/b][color=#999900]3[/color][b][color=#663300]] =[/color][/b][color=#999900] 1[/color][b][color=#663300];[/color][/b]

view[b][color=#663300][[/color][/b][color=#999900]0[/color][b][color=#663300],[/color][/b][color=#999900]3[/color][b][color=#663300]] =[/color][/b] cam_right[b][color=#663300].[/color][/b]DotProd[b][color=#663300](-[/color][/b]position[b][color=#663300]);[/color][/b]
view[b][color=#663300][[/color][/b][color=#999900]0[/color][b][color=#663300],[/color][/b][color=#999900]3[/color][b][color=#663300]] =[/color][/b] cam_up[b][color=#663300].[/color][/b]DotProd[b][color=#663300](-[/color][/b]position[b][color=#663300]);[/color][/b]
view[b][color=#663300][[/color][/b][color=#999900]0[/color][b][color=#663300],[/color][/b][color=#999900]3[/color][b][color=#663300]] =[/color][/b] cam_forward[b][color=#663300].[/color][/b]DotProd[b][color=#663300](-[/color][/b]position[b][color=#663300]);[/color][/b]

Vector test[b][color=#663300] =[/color][/b] view[b][color=#663300] *[/color][/b] myObject[b][color=#663300];[/color][/b]
test[b][color=#663300].[/color][/b]Print[b][color=#663300]();[/color][/b]
 
Last edited by a moderator:
NoteMe said:
Hmm...that looks so easy...but I must be doing something wrong here. Lets say that we have a scenario like this:

world.JPG


All these coordinates is in world coordinates. The dot with the arrow is the camera, pointing in the direction you can see the arrow points. The X is the point that I want to transform from world space to view space.

The cameras lookAt vector is (-1,0,0) (it is a free/zero vector right, and not a point?), and up is (0,1,0) since this is a FPS camera.

Shouldn't the coodinates to transformed object there become (0,2,0)?

No, that should be (0,0,2) since in view space Z is going away from the camera.

And it works out just fine:
Code:
              [0,  0, -1, 0]
              [0,  1,  0, 0]
              [1,  0,  0, 0]
              [0, -2,  3, 1]
(1, 2, 0, 1)  (0,  0,  2, 1)
 
Last edited by a moderator:
Thanks thanks thanks thanks. I got it working now. It was REALLY easy to debug when I saw the answer..:)..it was my DotProduct that made the wrong result. Sloppy code..:(

I am so greatfull for your patiense. Really admire that. Wish I could help you back, but I guess you are in an other dimension. Thanks again. Great help.



PS: I can't belive that I edited my post from (0,0,2) to (0,2,0). That is what I call a brain fart..:)


[Edit] And the world to screen coordinates went as a dream too. Didn't quit use your method though. I used symetri. Guess that is the same as you have done, even if I don't 100% recognize it from what I did.


Øyvind Østlund
 
Last edited by a moderator:
NoteMe said:
Wow...so that is it?...sounds to good to be true...but could you please add some parentheses there....? I asume that * has a higher "priority"/precedence then / but there is still chaos in there..:)
* and / have the same precedence and are left-associative, i.e. evaluated from left to right.
 
NoteMe said:
I am not getting you here. How can I look at what it does to unit vectors when I don't have the projection matrix all ready?
Been a while, but might as well reply to this.

You just put in general variables for the elements of the projection matrix. When you multiply said projection matrix against a unit vector, you'll find that doing this singles out particular elements of the projection matrix, so you can analyze relatively simply what said projection matrix should be.

All that you need to know, then, are the new directions that your current x, y, and z vector should point after transformation.
 
Chalnoth said:
All that you need to know, then, are the new directions that your current x, y, and z vector should point after transformation.

won't do. a (prespective) projection transform does not produce exaclty 3d homogeneous coordinates*, and passing a basis through it would not produce a meaningful 3d homogeneous basis. futher on, you cannot rely on w-division to get your basis vectors back to 3d space as that would automatically leave you with singularities for both your x and y vectors.

* although for historical reasons the space produced after it is often referred as 'homogeneous clipping space'.
 
darkblu said:
won't do. a (prespective) projection transform does not produce exaclty 3d homogeneous coordinates*, and passing a basis through it would not produce a meaningful 3d homogeneous basis. futher on, you cannot rely on w-division to get your basis vectors back to 3d space as that would automatically leave you with singularities for both your x and y vectors.
Right, not for a perspective transform. But works fine for rotation and translation. I don't think anybody here was suggesting doing a fullblown perspective transform analytically just yet.

Granted, you could still use the technique to apply a perspective transform, but you'd need to have a much better idea of where you're headed, which isn't nearly as easy to figure out as it is with translation/rotation. Me, I'd just rip out one of the perspective transformation matrices that are listed in the OpenGL specs.
 
Last edited by a moderator:
Chalnoth said:
Right, not for a perspective transform. But works fine for rotation and translation. I don't think anybody here was suggesting doing a fullblown perspective transform analytically just yet.

actually hyp-x did provide an analytical perspective transform several posts earlier.

Granted, you could still use the technique to apply a perspective transform, but you'd need to have a much better idea of where you're headed, which isn't nearly as easy to figure out as it is with translation/rotation. Me, I'd just rip out one of the perspective transformation matrices that are listed in the OpenGL specs.

a wise approach :cool:
 
Back
Top