PDA

View Full Version : draw frustum outlines

remdul
05-07-2004, 12:53 AM
Hi,

I have a world in which I have a bunch of cameras. I want to draw each camera view frustum as lines. In order to do that I need to know the (world-space) coordinates of the 8 vertices that make up the near- and far-plane polygons. How can I calculate these? I have the position, rotation/viewing direction vector/up vector, aspect ratio, farplane/nearplane distance etc.

-NiCo-
05-07-2004, 01:10 AM
As you, know the viewing frustum projects the viewvolume to the range [-1,1]x[-1,1]

Just try defining 4 vertices:

(-1,-1,scale,1.0);
(-1,1,scale,1.0);
(1,1,scale,1.0);
(1,-1,scale,1.0);

and multiply them them with the inverse of the projection matrix, that should do the trick.

N.

plasmonster
05-07-2004, 03:33 AM
The transformed clip space position c of a
world space vertex v is obtained by transforming
v with the product of the projection matrix P
and the modelview matrix MV

c = P MV v

So, if we could solve for v, then we could
genrerate vertex positions by plugging in clip
space positions. For your frustum, one line
would be between the clip space positions

(-1,-1,near) and (-1,-1,far),

the lower left edge of the frustum, for example.

NB: If you would like to mix normalized device
coords (x,y) and eye space coords (near,far),
you need an additional step here. Modify your
clip position as follows

c' = (c.x * c.z, c.y * c.z, c.z, c.z)

otherwise you would need to supply both the z
and w for c, which might be inconvenient. Simply
use c' instead of c below.

To solve for v, multiply both sides of the equation above with

-1
(P MV)

This gives

-1
(P MV) c = v

This is equivalent to

-1 -1
MV P c = v

-1
P is given by

|(r-l)/(2n) 0 0 (r+l)/(2n) |
| 0 (t-b)/(2n) 0 (t+b)/(2n) |
| 0 0 0 -1 |
| 0 0 -(f-n)/(2fn) (f+n)/(2fn)|

where l, r, t, b, n, and f are the parameters in the glFrustum() call.

If you don't want to fool with inverting the
model matrix, the info you already have can be
used instead: the forward, right, and up
vectors, in addition to the eye position.

First, go from clip space to eye space

-1
e = P c

Next go from eye space to world space

v = eyePos - forward*e.z + right*e.x + up*e.y

assuming x = right, y = up, and -z = forward.edit:

-tried to reformat

yooyo
05-09-2004, 05:02 PM
Try something like this:

Assume proj contains projection matrix and mv contains modelview matrix...
Matrix4 proj, mv, temp, inv;
temp = proj * mv;
inv = inverse(temp); // compute inverse of matrix

VECTOR4 fr[8]=
{
// near
{-1, -1, -1, 1}, { 1, -1, -1, 1}, { 1, 1, -1, 1}, {-1, 1, -1, 1},
// far
{-1, -1, 1, 1}, { 1, -1, 1, 1}, { 1, 1, 1, 1}, {-1, 1, 1, 1}
};
// Transform all vertices:
// multiply vertex array (fr) by matrix. result is transformed vertex array (tfr)
VECTOR4 tfr[8];
transform_points(fr, 8, inv, tfr);

int i;
for (i=0; i<8; i++)
{
tfr[i].x /= tfr[i].w;
tfr[i].y /= tfr[i].w;
tfr[i].z /= tfr[i].w;
tfr[i].w = 1.0f;
}

glBegin(GL_LINES);
connect tfr points as follow:
0-1, 1-2, 2-3, 3-0,
4-5, 5-6, 6-7, 7-4,
0-4, 1-5, 2-6, 3-7
glEnd();This is a pseudo code. I suppose that you already have your math library with matrix and vector functions (inverse, transform_points and matrix_mult (*).

yooyo

plasmonster
05-10-2004, 01:46 AM
Here's a little code to demonstrate the idea
above:

Vector xyzToWorld( Vector xyz, Vector eye, Vector forward, Vector right, Vector up ) {

// xyz is normalized device (x,y) and eye space z
// eye, forward, right, and up constitute the
// eye origin and basis vectors, respectively.

// frustum info
float nearZ = 4;
float farZ = 10000;
float fovX = 90;

// frutum setup
float projZ = nearZ * tan( fovX * PI / 360 );
float aspect = screenHeight / screenWidth;
float l = -projZ;
float r = +projZ;
float b = -projZ * aspect;
float t = +projZ * aspect;
float n = nearZ;
float f = farZ;

// inverse of projection matrix
// based on the parameters above - the same
// values use in the glFrustum() call.

float P[16] = {
(r-l)/(2*n), 0, 0, (r+l)/(2*n),
0, (t-b)/(2*n), 0, (t+b)/(2*n),
0, 0, 0, -1,
0, 0, -(f-n)/(2*f*n), (f+n)/(2*f*n)
};

// undo divide with w (eye space z)
float px = xyz.x * xyz.z;
float py = xyz.y * xyz.z;
float pw = xyz.z;

// move into eye space
float ex = P[0] * px + P[1] * py + P[3] * pw;
float ey = P[4] * px + P[5] * py + P[7] * pw;
float ez = P[8] * px + P[9] * py + P[11]* pw;

// move into world space
return eye - forward*ez + right*ex + up*ey;
}So, for your frustum problem, you could supply these values for xyx:
(-1,-1,nearZ) (-1,-1,farZ)
(-1,+1,nearZ) (-1,+1,farZ)
(+1,+1,nearZ) (+1,+1,farZ)
(+1,-1,nearZ) (+1,-1,farZ)

Jared
05-11-2004, 12:00 AM
with all the methods posted ill just add one more variation.

fovy, near, far are given

hheight = tan(fovy/2); //half the height of the frustum at z=1;
hwidth = hheight * aspect; //same for width

so assuming you know your cameras forward/up/right vectors (ie, using a "matrix camera" or simply invert the view matrix).

right=hwidth*far*cam_right;
top=hheight*far*cam_up;
center=cam_pos + far*cam_forward;

nice to have (vectors from the center of the far plane to the sides/corners)

ftl = center - right + top; //far top left
fbr = center + right - top; //far bottom right

and so on.
no need to touch any opengl matrices if you dont do anything fancy, know your fov and the cameras vectors (ok, that IS a matrix, but you usually manage that one yourself).

remdul
05-17-2004, 09:14 PM
Now that's exactly what I was looking for!

Thanks to you all! :)

cuboidMan
05-17-2004, 11:25 PM
One thing always puzzled me - why do people use the vertical field of view to define a perspective matrix?
The more intuitive axis would be the horizontal field of view....for me at least.