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.

Thanks in advance. :)

-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

-added a note

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.

Powered by vBulletin® Version 4.2.2 Copyright © 2014 vBulletin Solutions, Inc. All rights reserved.