Hello,

I am trying to implement an Unproject() method:

public static Ray Unproject(Vector2 Cursor, Vector2 Window, Matrix4 View, Matrix4 Projection) //Cursor is relative to window, Window is window dimensions

{

float clipspacex = ((Cursor.x / Window.x) * 2) - 1;

float clipspacey = ((Cursor.y / Window.y) * 2) - 1;

Vector2 ClipSpaceCursor = new Vector2(clipspacex, -clipspacey);

Vector3 v1 = Unproject(ClipSpaceCursor, 0, View, Projection);

Vector3 v2 = Unproject(ClipSpaceCursor, 1, View, Projection);

return new Ray(v1, v2 - v1);

}

public static Vector3 Unproject(Vector2 ClipSpaceCursor, float z, Matrix4 View, Matrix4 Projection)

{

return (View.Inverse() * (Projection.Inverse() * new Vector4(ClipSpaceCursor, z, 1))).xyz; //Math library uses column vectors

}

However it appears to always project towards (0,0,0), as opposed to into the screen.

The point v1 always sits behind the cursor regardless of the position and orientation of the camera, so that at least is being resolved correctly, but I cannot see why v2 is always resolved closer to (0,0,0); its like (0,0,0) is the vanishing point and its trying to project out of it.

Can anyone see what is wrong with it?

**0**

# Why does my Unproject() method insist on Unprojecting towards 0,0,0?

Started by sebjf, Jan 29 2012 06:32 AM

4 replies to this topic

Sponsor:

###
#2
Members - Reputation: **2137**

Posted 29 January 2012 - 06:55 AM

You will need to divide by w after multiplying Projection.Inverse() * new Vector4(ClipSpaceCursor, z, 1), unless w==1 after that multiplication. (I can't remember if Projection.Inverse() will produce w=1 with those values, so try checking that.)

Me+PC=clb.demon.fi | C++ Math and Geometry library: MathGeoLib, test it live! | C++ Game Networking: kNet | 2D Bin Packing: RectangleBinPack | Use gcc/clang/emcc from VS: vs-tool | Resume+Portfolio | gfxapi, test it live!

###
#3
Members - Reputation: **127**

Posted 29 January 2012 - 08:03 AM

Thank you very much clb! I added the divide by w operation and the (un)projection is now working perfectly. I can say surely it would have been a Long time before I figured that one out.

As I understand it, w is used to control projection, by 'standing in' for z - when the final position is calculated z is moved into w by the projection matrix, and the divide is performed. So is it that, when the inverse of this matrix is taken, that operation is no longer performed and so needs to be done manually/explicitly as it is in my method now?

As I understand it, w is used to control projection, by 'standing in' for z - when the final position is calculated z is moved into w by the projection matrix, and the divide is performed. So is it that, when the inverse of this matrix is taken, that operation is no longer performed and so needs to be done manually/explicitly as it is in my method now?

###
#4
Members - Reputation: **2137**

Posted 29 January 2012 - 08:32 AM

When you multiply a vector by a projection matrix (not only its inverse), you will also have to divide the result by w. This projects the homogeneous coordinates back to the euclidean 3D space, and the step needs to be always done when using 4x4 matrices for transforms (such as the perspective projection) in homogeneous coordinate spaces. This property can explained by mathematical theory of homogeneous coordinates, but if you don't feel like waddling through the theory, one can look at these operations also in more of a "programmer's" terms:

in a 3x3 matrix we can encode operations acting on a vector (x,y,z) that

So, in short, one can think of this "divide by w" step as a mechanism which enables us to use matrices to divide(multiply) vectors by one of the elements of that vector itself, a "trick" just like setting w=1 for points to be able to use matrices to add constants to a vector.

in a 3x3 matrix we can encode operations acting on a vector (x,y,z) that

- multiply any element by a constant
- divide any element by a constant
- add (subtract) one of the inputs x/y/z to any element (+multiples/fractions of x/y/z)

- add (subtract) a constant to any element

- multiply (divide) all elements by any of the inputs.

So, in short, one can think of this "divide by w" step as a mechanism which enables us to use matrices to divide(multiply) vectors by one of the elements of that vector itself, a "trick" just like setting w=1 for points to be able to use matrices to add constants to a vector.

Me+PC=clb.demon.fi | C++ Math and Geometry library: MathGeoLib, test it live! | C++ Game Networking: kNet | 2D Bin Packing: RectangleBinPack | Use gcc/clang/emcc from VS: vs-tool | Resume+Portfolio | gfxapi, test it live!

###
#5
Members - Reputation: **127**

Posted 29 January 2012 - 09:01 AM

I see, I misunderstood it as a feature of the makeup of a projection matrix, as opposed to an agreed implementation.

Thank you very much clb.

The way you explained it, as the capabilities of the are 'built up' with the dimensions of the matrices, is very clear. I understand this convention now, as opposed to simply trying to remember it!

Thank you very much clb.

The way you explained it, as the capabilities of the are 'built up' with the dimensions of the matrices, is very clear. I understand this convention now, as opposed to simply trying to remember it!