Transforming 3d verts to 2d

Started by
6 comments, last by PumpkinPieman 16 years, 10 months ago
If I were up on my matrix math I wouldn't have too much of a problem with this, but I haven't done much in a while. Alright, what I want to do is take a point in 3d space and transform it to 2d space. The main reason I'm doing this is because once the ground is drawn I need the position offset on the 32x32 grid to offset the 2d sprite. The only thing I can think of is take the PxVxW matrices, invert them and transform all the vertices. But I tried that and it doesn't seem to work. Example: Free Image Hosting at www.ImageShack.us
Advertisement
If the columns of matrix A represent an orthonormal basis for the 2D plane (i.e. two 3D vectors that specify the X and Y axis of the plane, resulting in a 3x2 matrix), and the coordinate 'b' is the 3D point, then ATb should give you the 2D coordinate of the point on the plane. If the origin of this system (call it 'o') isn't the zero vector, then just subtract it from 'b' first.

If the basis isn't orthonormal, then there's a pre-multiplication of (ATA)-1 first (that would have otherwise been identity). Thus the fully generalized projection equation is (ATA)-1AT(b - o).

That might be hard to follow if you don't have a solid linear algebra background, but AT(b - o) should do for your purposes.
Assuming you want a vector in screen space (pixel coordinates) just use D3DXVec3Project. It'll automagically take into account the Viewport, as well.
Sirob Yes.» - status: Work-O-Rama.
Quote:Original post by sirob
Assuming you want a vector in screen space (pixel coordinates) just use D3DXVec3Project. It'll automagically take into account the Viewport, as well.

Thanks, but I don't particularly want to be bound to API specific methods if there is another way. I may want to go back and modify my code for OGL as well. :)

Quote:Original post by Zipster
If the columns of matrix A represent an orthonormal basis for the 2D plane (i.e. two 3D vectors that specify the X and Y axis of the plane, resulting in a 3x2 matrix), and the coordinate 'b' is the 3D point, then ATb should give you the 2D coordinate of the point on the plane. If the origin of this system (call it 'o') isn't the zero vector, then just subtract it from 'b' first.

If the basis isn't orthonormal, then there's a pre-multiplication of (ATA)-1 first (that would have otherwise been identity). Thus the fully generalized projection equation is (ATA)-1AT(b - o).

That might be hard to follow if you don't have a solid linear algebra background, but AT(b - o) should do for your purposes.


Yeah, I understand for the most part. There are a few things I'm unsure about.

My assumption is that the matrix A is a combination of the Projection*View*World matrices. Is this right? Now given a point b in 3d space, Ab would give the screen coordinate? By origin do you mean the 3d origin or the 2d origin?
Quote:Original post by PumpkinPieman
My assumption is that the matrix A is a combination of the Projection*View*World matrices. Is this right? Now given a point b in 3d space, Ab would give the screen coordinate? By origin do you mean the 3d origin or the 2d origin?

The result of WVP x pos is in Homogenous Clip Space. That is, values are in the ranges ([-1..1], [-1..1], [0..1], 1) * w. Note the * w portion, which you'll need to divide by if you are doing this yourself.

Now, D3DX provides several functions to help you do these things. You can use anything from D3DXVec3Project (which takes care of everything for you, including transforming from Homogenous Clip Space into screen space, using the viewport).
To a lesser degree, you can use D3DXVec3TransformCoordinate, which takes care of the division by w, and truncates the 4th element, which you wouldn't need anyways.
The most basic method is D3DXVec3Transform, which simply multiplies the matrix you give it, and the position vector you provide. You could also do this multiplication yourself. From here to screen space, you'll need to:
1) Divide by w.
2) multiply by 0.5, add 0.5 to both X and Y.
3) multiply by the viewport width and height.

Hope this helps.
Sirob Yes.» - status: Work-O-Rama.
Quote:Original post by sirob
Quote:Original post by PumpkinPieman
My assumption is that the matrix A is a combination of the Projection*View*World matrices. Is this right? Now given a point b in 3d space, Ab would give the screen coordinate? By origin do you mean the 3d origin or the 2d origin?

The result of WVP x pos is in Homogenous Clip Space. That is, values are in the ranges ([-1..1], [-1..1], [0..1], 1) * w. Note the * w portion, which you'll need to divide by if you are doing this yourself.

Now, D3DX provides several functions to help you do these things. You can use anything from D3DXVec3Project (which takes care of everything for you, including transforming from Homogenous Clip Space into screen space, using the viewport).
To a lesser degree, you can use D3DXVec3TransformCoordinate, which takes care of the division by w, and truncates the 4th element, which you wouldn't need anyways.
The most basic method is D3DXVec3Transform, which simply multiplies the matrix you give it, and the position vector you provide. You could also do this multiplication yourself. From here to screen space, you'll need to:
1) Divide by w.
2) multiply by 0.5, add 0.5 to both X and Y.
3) multiply by the viewport width and height.

Hope this helps.


Alright. I gave that a try and my values are way off from acceptable values. Maybe I'm doing something horribly wrong. What would W be?
	matrix4 matrix = driver->getTransform(ETS_WORLD);	matrix *= driver->getTransform(ETS_VIEW);	matrix *= driver->getTransform(ETS_PROJECTION);	vector3df pt(cellX, 0, cellY);	float vfl[4];	float w = 0;	matrix.transformVect(&vfl[0], pt);	for(int i = 0; i < 3; i++)		if(vfl > w)			w = vfl;	for(int i = 0; i < 3; i++){		vfl /= w;  // W?//		vfl /= camera->getFOV();		vfl *= 0.5;	}	core::dimension2d<s32> ssize = driver->getScreenSize();	vfl[0] += 0.5;	vfl[1] += 0.5;	vfl[0] *= ssize.Width;	vfl[1] *= ssize.Height;
The W element is the 4th element of the vector. When you pass the input to the transformation, you'll need a value of 1.0 for w. After transformation, you'll need to divide your 4-element vector by w, after which w will again be 1.0.

Also, you're dividing the Z element by 0.5 after transformation, though you shouldn't (unless you want to, for some reason).

There may be other issues, I don't feel to comfortable with all the details of how this is done exactly. I'm pretty sure you could get some more help in GP&T, since you're doing everything you can to avoid using D3DX [smile].

Hope this helps.
Sirob Yes.» - status: Work-O-Rama.
Quote:Original post by sirob
The W element is the 4th element of the vector. When you pass the input to the transformation, you'll need a value of 1.0 for w. After transformation, you'll need to divide your 4-element vector by w, after which w will again be 1.0.

Also, you're dividing the Z element by 0.5 after transformation, though you shouldn't (unless you want to, for some reason).

There may be other issues, I don't feel to comfortable with all the details of how this is done exactly. I'm pretty sure you could get some more help in GP&T, since you're doing everything you can to avoid using D3DX [smile].

Hope this helps.

Yeah, I've gotten too used to using built in functions for things and no so much the math. I figured it's about time that I need to because of the stuff leading off of these tests.

(Actually, I found out a resolution to the problem I was having on the Irrlicht board (I'm using Irr\DX). I was directed to a set of hidden functions that I didn't know about. :D)
Thanks for your help. Rate+!

This topic is closed to new replies.

Advertisement