Geez, Nelson, you started me obsessing over this, and then I couldn't
focus until I'd worked it out. :-)
Here we go. Use a fixed-width font.
First, let's look at the projection matrix. Using something like
gluPerspective, we have a matrix as follows:
With these values (for brevity):
f = cotangent( fovy/2 )
A = ( zNear+zFar )/( zNear-zFar )
B = ( 2*zNear*zFar )/( zNear-zFar )
The generated matrix is
f/aspect 0 0 0
0 f 0 0
0 0 A B
0 0 -1 0
(Please note that's column major, even though I'll use row-major vectors
below.)
OK, given an eye coordinate at the center of the view with a known z value:
ec = ( 0, 0, z, 1 )
The transformed clip coordinate is (vector-matrix multiply):
cc = ( 0, 0, z*A+B, -z )
and the normalized device coordinate (divide by cc w) is:
ndc = ( 0, 0, (z*A+B) / -z )
Next we need the viewport. To make things easy, let's assume a default
depth range of 0.0 to 1.0, and let's also assume 0, 0 for the viewport
xy values. That way we only have to deal with the with and height, which
is the typical case anyway. The window coordinate is:
wc = ( 0.5*w, 0.5*h, ( 0.5*(z*A+B) / -z ) )
Looks ugly, but remember, those are all given values, so you can just
take your known z distance, your viewport, and your projection matrix
and compute that window coordinate with a pencil and a napkin.
Now we know the window coordinate distance subtended by one pixel. That
distance is 1.0 by definition. It's the same for x and y, so let's
ignore y and just add 1 to x to get this new delta window coordinate:
wcD = ( 0.5*w+1, 0.5*h, ( 0.5*(z*A+B) / -z ) )
If we back-transform this into eye space, the resulting eye space x
value is the distance subtended by one pixel. That's what we're after!
We can do this... (I think...)
The delta normalized device coordinate is:
ndcD = ( ((0.5*w+1) / w * 2) - 1, 0, (z*A+B) / -z )
(Tricky: The multiply by 2 and subtract 1 is needed to put us back into
the range -1 to 1.)
The delta clip coordinate is:
ccD = ( (((0.5*w+1) / w * 2) - 1) * -z, 0, z*A+B, -z )
(Multiply by -z, the inverse of dividing by -z.)
And finally the delta eye coordinate is:
ecD = ( (((0.5*w+1) / w * 2) - 1) * -z * (aspect/f), 0, z, 1 )
(Multiply by aspect/f, which is the inverse of multiplying by f/aspect,
which is what we would've had to do at the top of this email to compute
the cc x value.)
In summary, the ec x distance subtended by one pixel in the center of
your window at a given z distance is:
(((0.5*w+1) / w * 2) - 1) * -z * (aspect/f)
To solve, you just need these four values:
* The viewport width
* The given z distance
* The aspect ration in your projection matrix
* And the f value, which is cotangent( fovy/2 ), and fovy also comes
from the projection matrix.
There might be some math errors there, so please check over my work.
Then run some test values through it to verify.
One thing to keep in mind is that eye space z distance is not the same
as world coordinate range. I've created an equation to solve for x
distance at the center of the window, and accuracy will degrade if you
use this same solution for pixels near the edge of the window.
But hopefully you get the idea and you can adapt this to your project.
-Paul
_______________________________________________
osg-users mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org