vbence
vbence

Reputation: 20333

How to reverse-project 2D coordinates to a z=n plane in 3D

I want to "unproject" 2D coordinates back to 3D space, to a given z plane. (Where z is known, so are the projected 2D coorinates and the pMatrix and mvMatrix used).

Web search only shows up with gluUnProject's variants which has a comletely different use.

Upvotes: 1

Views: 431

Answers (1)

vbence
vbence

Reputation: 20333

First make sure that your screen-coordinates are in the right coordinate-space, that is between -1 and 1.

Then you need to combine projection and model-view matrices into a single one. Sample code using Javascript and glMatrix for convenience:

var m = mat4.create();
mat4.multiply(m, pMatrix, mvMatrix);

On Wikipedia you can find the basic formula used with projection. Factoring out those multiplications and solving them for x and y will give you (screenshot from mxMaxima):

Perspective matrix solved for x and y Note the column-major format in indexes.

The JS version of this formula (with x2 and y2 being the projected 2d coordinates, x and y being the original 3d ones and original z was known):

var x=-((m[8]*(m[5]-m[6]*y2)+m[4]*(m[10]*y2-m[9])+(m[6]*m[9]-m[10]*m[5])*x2)*z+m[4]*(m[14]*y2-m[13])-m[12]*m[6]*y2+(m[13]*m[6]-m[14]*m[5])*x2+m[12]*m[5])/(m[4]*(m[2]*y2-m[1])-m[0]*m[6]*y2+(m[1]*m[6]-m[2]*m[5])*x2+m[0]*m[5]);
var y=((m[8]*(m[1]-m[2]*y2)+m[0]*m[10]*y2+(m[2]*m[9]-m[1]*m[10])*x2-m[0]*m[9])*z-m[12]*m[2]*y2+m[0]*m[14]*y2+(m[13]*m[2]-m[1]*m[14])*x2-m[0]*m[13]+m[1]*m[12])/(m[4]*(m[2]*y2-m[1])-m[0]*m[6]*y2+(m[1]*m[6]-m[2]*m[5])*x2+m[0]*m[5]);

As a bonus you can get the distance from the projection plane with:

var w = m[10]*z+m[6]*y+m[2]*x+m[14];

Upvotes: 1

Related Questions