# draw frustum outlines

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.

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.

``````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),
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

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

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)

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=hwidthfarcam_right;
top=hheightfarcam_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).

Now thatâ€™s exactly what I was looking for!

Thanks to you all!

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.