986 lines
38 KiB
Text
986 lines
38 KiB
Text
From sbaker@link.com Thu Jan 29 23:16:07 1998
|
|
X-VM-v5-Data: ([nil nil nil nil t nil nil nil nil]
|
|
["5377" "Thu" "29" "January" "1998" "23:16:36" "-0600" "Steve Baker" "sbaker@link.com" "<Pine.SGI.3.96.980129224404.29062A-100000@lechter.bgm.link.com>" "139" "Re: View frustum culling" "^From:" nil nil "1" nil nil nil nil nil]
|
|
nil)
|
|
Received: from lfkw10.bgm.link.com (bgm.link.com [130.210.2.10])
|
|
by meserv.me.umn.edu (8.8.8/8.8.6) with ESMTP id XAA03024
|
|
for <curt@me.umn.edu>; Thu, 29 Jan 1998 23:16:06 -0600 (CST)
|
|
Received: from lechter.bgm.link.com (lechter.bgm.link.com [130.210.239.45])
|
|
by lfkw10.bgm.link.com (8.8.6/HTI-Hack-8.8.4) with SMTP
|
|
id XAA18220 for <curt@me.umn.edu>; Thu, 29 Jan 1998 23:15:35 -0600 (CST)
|
|
X-Sender: steve@lechter.bgm.link.com
|
|
Reply-To: Steve Baker <sbaker@link.com>
|
|
In-Reply-To: <199801292145.PAA04212@kenai.me.umn.edu>
|
|
Message-ID: <Pine.SGI.3.96.980129224404.29062A-100000@lechter.bgm.link.com>
|
|
MIME-Version: 1.0
|
|
Content-Type: TEXT/PLAIN; charset=US-ASCII
|
|
From: Steve Baker <sbaker@link.com>
|
|
To: "Curtis L. Olson" <curt@me.umn.edu>
|
|
Subject: Re: View frustum culling
|
|
Date: Thu, 29 Jan 1998 23:16:36 -0600 (CST)
|
|
|
|
On Thu, 29 Jan 1998, Curtis L. Olson wrote:
|
|
|
|
> Questions ...
|
|
>
|
|
> Let's say I know the following:
|
|
>
|
|
> Eye pt. = (0, 0, 0)
|
|
> "look at" vector
|
|
> "view up" vector
|
|
> field of view angle
|
|
> Assume a "square" view volume cross section (i.e. the far clip plane
|
|
> would be a square)
|
|
|
|
(That is almost never the case since you want the image to fit the
|
|
screen shape - but OK - for argument's sake, same HFOV as VFOV).
|
|
|
|
> I can calcuation the near and far clip planes pretty easily with this
|
|
> info.
|
|
|
|
Assuming you know the near and far clip ranges - yes.
|
|
|
|
> Now, to calculate the left and right planes I could rotate the look at
|
|
> vector about the view up vector by -1/2 * fov and +1/2 * fov
|
|
> respectively. The view up vector already lies in both these planes,
|
|
> so then I'd have two vectors in each plane and then I could calculate
|
|
> the normals to get the equations of these planes
|
|
|
|
Yes, that would work.
|
|
|
|
> Then to calculate the top and bottom planes I could rotate the view up
|
|
> vector by 90 degrees about the look at vector to get a vector in both
|
|
> these planes, then I could rotate the look at vector about this new
|
|
> vector by -1/2 * fov and +1/2 * fov to get the second vector in each
|
|
> of these planes, and crunch the math just like I did for the left and
|
|
> right planes.
|
|
|
|
...or you could just rotate the left or right plane normal by 90 degrees
|
|
about the lookat vector (but only for your hypothetical square FOV).
|
|
|
|
> Does this sound reasonable, or am I missing some obvious tricks?
|
|
|
|
It's *reasonable* if you want the view planes in the coordinate system
|
|
of the world. However, I'd argue about that premise.
|
|
|
|
I did the opposite - I keep the view frustum in the coordinate system
|
|
of the eye and rotate the world into that coordinate system. This
|
|
costs at most one extra transform (by the inverse of the eye-rel-world
|
|
matrix) per frame (at the root of the database tree).
|
|
|
|
The advantages are *huge* in the clipping code (which is where I
|
|
assume you are going with this question) since the plane equations
|
|
for the near and far planes (in eye coordinates) are trivial:
|
|
|
|
General Equation of a Plane:
|
|
|
|
Ax + By + Cz + D == 0
|
|
|
|
Far clip plane:
|
|
|
|
A == 0 ;
|
|
B == 0 ;
|
|
C == -1 ;
|
|
D == far_clip_range ;
|
|
|
|
Near clip plane:
|
|
|
|
A == 0 ;
|
|
B == 0 ;
|
|
C == 1 ;
|
|
D == -near_clip_range ;
|
|
|
|
Also, since the left and right clip planes are now vertical, we
|
|
know that B==0 and for the top and bottom planes, A==0.
|
|
|
|
In addition, because of symmetry about the Z axis, the A of
|
|
the left plane is equal to -A for the right, and the B of
|
|
the top plane is equal to -B of the bottom.
|
|
|
|
Furthermore, since D is just the distance of the closest
|
|
point of the plane to the origin - and all four planes
|
|
go through the eyepoint - and that *is* the origin - that
|
|
means that the 'D' component of all four edge equations is
|
|
always zero.
|
|
|
|
Notice that since the frustum is in eye coordinates,
|
|
there is no need to worry about lookat or viewup vectors
|
|
since these are 0,0,1 and 0,1,0 respectively - and the
|
|
eye point is always at 0,0,0 by definition. This also
|
|
means that you only need to calculate those plane equations
|
|
once - rather than once per frame as with your scheme.
|
|
|
|
When you come to ask the question: "Is this bounding sphere
|
|
cleanly inside the frustum, cleanly outside the frustum or
|
|
(annoyingly) straddling it?", you will want to insert the
|
|
x,y,z of the center of the sphere (relative to the eye
|
|
in the 'eye' coordinate system) into each of the
|
|
six plane equations in turn to compute the distance from the
|
|
sphere center to the plane - and compare that to the radius
|
|
of the sphere. When you write out the math for this, using
|
|
the full plane equations (as you would have to do with your
|
|
scheme), you find that all those zeros and symmetry effects
|
|
result in some pretty amazing optimisations.
|
|
|
|
Additionally, this is the OpenGL way. You stuff your frustum
|
|
matrix into the 'PROJECTION_MATRIX', put the inverse of
|
|
your eyepoint transform into the MODELVIEW_MATRIX and proceed
|
|
to push/multiply/pop the transforms of each of the models onto
|
|
that same matrix. Notice that the frustum is never transformed
|
|
into world space.
|
|
|
|
I suggest you go back and re-read the last L-O-N-G email I
|
|
sent about clipping, I explain my suggested method there
|
|
in more detail.
|
|
|
|
Note that I'm not saying that what you propose is wrong -
|
|
just that IMHO (and *only* IMHO), my way is going to be
|
|
a lot simpler and cheaper to implement. However, there may
|
|
be other reasons to want to do it your way.
|
|
|
|
The complexity of MANY 3D graphics problems often depends
|
|
critically on your choice of coordinate system. For
|
|
clipping, doing the math in the eye coordinate system
|
|
results in a *tiny* amount of math per sphere tested.
|
|
|
|
If you ever need to do lighting calculations, then
|
|
carrying them out in a coordinate system with the
|
|
light source at the origin makes life a gazillion
|
|
times easier too. The same kinds of things will also
|
|
crop up in collision detection as well.
|
|
|
|
|
|
Steve Baker 817-619-8776 (Vox/Vox-Mail)
|
|
Raytheon Systems Inc. 817-619-4028 (Fax)
|
|
2200 Arlington Downs Road SBaker@link.com (eMail)
|
|
Arlington, Texas. TX 76005-6171 SJBaker1@airmail.net (Personal eMail)
|
|
http://www.hti.com http://web2.airmail.net/sjbaker1 (personal)
|
|
|
|
** Beware of Geeks bearing GIF's. **
|
|
|
|
|
|
From sbaker@link.com Fri Jan 30 14:08:05 1998
|
|
X-VM-v5-Data: ([nil nil nil nil t nil nil nil nil]
|
|
["4594" "Fri" "30" "January" "1998" "14:08:27" "-0600" "Steve Baker" "sbaker@link.com" "<Pine.SGI.3.96.980130135437.20130B-100000@lechter.bgm.link.com>" "120" "Re: View frustum culling" "^From:" nil nil "1" nil nil nil nil nil]
|
|
nil)
|
|
Received: from lfkw10.bgm.link.com (bgm.link.com [130.210.2.10])
|
|
by meserv.me.umn.edu (8.8.8/8.8.6) with ESMTP id OAA21393
|
|
for <curt@me.umn.edu>; Fri, 30 Jan 1998 14:08:03 -0600 (CST)
|
|
Received: from lechter.bgm.link.com (lechter.bgm.link.com [130.210.239.45])
|
|
by lfkw10.bgm.link.com (8.8.6/HTI-Hack-8.8.4) with SMTP
|
|
id OAA10811 for <curt@me.umn.edu>; Fri, 30 Jan 1998 14:07:27 -0600 (CST)
|
|
X-Sender: steve@lechter.bgm.link.com
|
|
Reply-To: Steve Baker <sbaker@link.com>
|
|
In-Reply-To: <199801301948.NAA25718@kenai.me.umn.edu>
|
|
Message-ID: <Pine.SGI.3.96.980130135437.20130B-100000@lechter.bgm.link.com>
|
|
MIME-Version: 1.0
|
|
Content-Type: TEXT/PLAIN; charset=US-ASCII
|
|
From: Steve Baker <sbaker@link.com>
|
|
To: "Curtis L. Olson" <curt@me.umn.edu>
|
|
Subject: Re: View frustum culling
|
|
Date: Fri, 30 Jan 1998 14:08:27 -0600 (CST)
|
|
|
|
On Fri, 30 Jan 1998, Curtis L. Olson wrote:
|
|
|
|
> Steve Baker writes:
|
|
> > I did the opposite - I keep the view frustum in the coordinate
|
|
> > system of the eye and rotate the world into that coordinate
|
|
> > system. This costs at most one extra transform (by the inverse of
|
|
> > the eye-rel-world matrix) per frame (at the root of the database
|
|
> > tree).
|
|
> >
|
|
> > I suggest you go back and re-read the last L-O-N-G email I sent
|
|
> > about clipping, I explain my suggested method there in more detail.
|
|
>
|
|
> Yes I have that in front of me. I guess it wasn't clear to me that
|
|
> you were using this greatly simplifed view frustum specially placed in
|
|
> eye coordinates.
|
|
|
|
That's the key to doing this stuff *quickly*.
|
|
|
|
> > The complexity of MANY 3D graphics problems often depends critically
|
|
> > on your choice of coordinate system. For clipping, doing the math in
|
|
> > the eye coordinate system results in a *tiny* amount of math per
|
|
> > sphere tested.
|
|
>
|
|
> Yes ... your description all makes sense and looks like it makes view
|
|
> frustum culling very simple to implement.
|
|
>
|
|
> Ok, so now I'm going to try to zero in a bit more on the source of my
|
|
> confusion, which involves getting from my world to your eye
|
|
> coordinates.
|
|
|
|
Let's adopt a naming convention for matrices here:
|
|
|
|
A_rel_B
|
|
|
|
means the matrix that positions objects in A relative to
|
|
the object B.
|
|
|
|
Some facts:
|
|
|
|
B_rel_A is just the inverse of A_rel_B.
|
|
|
|
A_rel_B * B_rel_C == A_rel_C
|
|
|
|
Hence: (for a flat-earth world - just for the moment)
|
|
|
|
If the eyepoint is 10km east of the origin (eyepoint.x == 10,000)
|
|
then:
|
|
|
|
eye_rel_world is a matrix that translates by 10000m in the X
|
|
direction.
|
|
|
|
world_rel_eye is the inverse of eye_rel_world - which in this
|
|
case is just a matrix that translates by -10000m in X.
|
|
|
|
Taking the inverse of a general matrix isn't nice - but for simple
|
|
rotate/translate matrices it isn't too bad - and you only do it
|
|
once per frame anyway.
|
|
|
|
> Lets say that I have a bunch of scenery tiles that are properly
|
|
> oriented, but translated to near (0, 0, 0) to avoid problems with
|
|
> "float" precision.
|
|
>
|
|
> I assume based on your previous message that you define your view
|
|
> frustum once at the beginning of your program in eye coordinates to
|
|
> simplify all this math.
|
|
|
|
Yep - you *might* want to allow the user to change it sometimes - but
|
|
basically, it's always the same number unless you resize the window,
|
|
zoom the image, etc.
|
|
|
|
> This moves the "hard" part to generating a transformation matrix that
|
|
> maps world coordinates into eye coordinates.
|
|
|
|
But world_rel_eye is just the inverse of eye_rel_world - and that's
|
|
just the rotation/translation of the eyepoint relative to some
|
|
arbitary point.
|
|
|
|
> You say ...
|
|
>
|
|
> > Additionally, this is the OpenGL way. You stuff your frustum matrix
|
|
> > into the 'PROJECTION_MATRIX', put the inverse of your eyepoint
|
|
> > transform into the MODELVIEW_MATRIX and proceed to push/multiply/pop
|
|
> > the transforms of each of the models onto that same matrix. Notice
|
|
> > that the frustum is never transformed into world space.
|
|
>
|
|
> Ok, so does this mean that every iteration I have to generate the
|
|
> world -> eye transformation matrix by hand ... i.e. calculate the
|
|
> first translation matrix, calculate the rotation matrix, calculate the
|
|
> second translation matrix, calculate the shear matrix, calculate the
|
|
> scaling matrix, and then combine all these together, then invert it
|
|
> and stuff it on the MODELVIEW stack?
|
|
|
|
Yes - except that the eye_rel_world isn't usually scaled or sheared or
|
|
anything. Just heading/pitch/roll/x/y/z.
|
|
|
|
> Or is there a way to get OpenGL to do this work for me?
|
|
|
|
No - not really - there is no glInvertMatrix (AFAIK) - and in any
|
|
case, on machines with geometry accelleration doing a glGetMatrix
|
|
is *death* to performance.
|
|
|
|
> If not, can I at least use OpenGL's rotates,
|
|
> and transformations to avoid spending two weeks debugging picky math
|
|
> routines?
|
|
|
|
No - don't debug new math routines either - let me find some out on the
|
|
web for you. I'm sure I know of a good set. I'll email you from home
|
|
tonight - I'm a bit busy right now.
|
|
|
|
Flight Gear will definitely need a good, robust set of math routines -
|
|
better to have a solid library than to try to kludge something in OpenGL.
|
|
|
|
Steve Baker 817-619-8776 (Vox/Vox-Mail)
|
|
Raytheon Systems Inc. 817-619-4028 (Fax)
|
|
2200 Arlington Downs Road SBaker@link.com (eMail)
|
|
Arlington, Texas. TX 76005-6171 SJBaker1@airmail.net (Personal eMail)
|
|
http://www.hti.com http://web2.airmail.net/sjbaker1 (personal)
|
|
|
|
** Beware of Geeks bearing GIF's. **
|
|
|
|
|
|
From sbaker@link.com Fri Jan 30 22:51:59 1998
|
|
X-VM-v5-Data: ([nil nil nil nil nil nil nil nil nil]
|
|
["4301" "Fri" "30" "January" "1998" "22:52:31" "-0600" "Steve Baker" "sbaker@link.com" nil "103" "Re: View frustum culling" "^From:" nil nil "1" nil nil nil nil nil]
|
|
nil)
|
|
Received: from lfkw10.bgm.link.com (bgm.link.com [130.210.2.10])
|
|
by meserv.me.umn.edu (8.8.8/8.8.6) with ESMTP id WAA03743
|
|
for <curt@me.umn.edu>; Fri, 30 Jan 1998 22:51:58 -0600 (CST)
|
|
Received: from lechter.bgm.link.com (lechter.bgm.link.com [130.210.239.45])
|
|
by lfkw10.bgm.link.com (8.8.6/HTI-Hack-8.8.4) with SMTP
|
|
id WAA08997 for <curt@me.umn.edu>; Fri, 30 Jan 1998 22:51:26 -0600 (CST)
|
|
X-Sender: steve@lechter.bgm.link.com
|
|
Reply-To: Steve Baker <sbaker@link.com>
|
|
In-Reply-To: <199801302035.OAA26234@kenai.me.umn.edu>
|
|
Message-ID: <Pine.SGI.3.96.980130223546.27307A-100000@lechter.bgm.link.com>
|
|
MIME-Version: 1.0
|
|
Content-Type: TEXT/PLAIN; charset=US-ASCII
|
|
From: Steve Baker <sbaker@link.com>
|
|
To: "Curtis L. Olson" <curt@me.umn.edu>
|
|
Subject: Re: View frustum culling
|
|
Date: Fri, 30 Jan 1998 22:52:31 -0600 (CST)
|
|
|
|
On Fri, 30 Jan 1998, Curtis L. Olson wrote:
|
|
|
|
> Steve Baker writes:
|
|
> > But world_rel_eye is just the inverse of eye_rel_world - and that's
|
|
> > just the rotation/translation of the eyepoint relative to some
|
|
> > arbitary point.
|
|
>
|
|
> Ok, from what you are saying, if I think about it, I've probably
|
|
> already got a suitable matrix or something close to it laying around
|
|
> someplace. I have a matrix that does the proper rotations to align
|
|
> world coordinates with the local "up" for the aircraft. I'd probably
|
|
> just need to pre-multiply the proper translation matrix with that
|
|
> rotate matrix, then invert it, and stuff it onto the MODELVIEW stack.
|
|
|
|
You *must* be doing the right thing at the start of the frame - or
|
|
how else would the graphics be coming out right? (Oh - unless you
|
|
are using that weird OpenGL 'lookat' function or something).
|
|
|
|
> > No - don't debug new math routines either - let me find some out on
|
|
> > the web for you. I'm sure I know of a good set. I'll email you from
|
|
> > home tonight - I'm a bit busy right now.
|
|
> >
|
|
> > Flight Gear will definitely need a good, robust set of math routines
|
|
> > - better to have a solid library than to try to kludge something in
|
|
> > OpenGL.
|
|
>
|
|
> You may scream when you hear this, or not, I'm not sure ... but I've
|
|
> been using the matrix and vector routines from SRGP and SPHIGS.
|
|
|
|
I don't know these - but it's hard to imagine how anyone could screw
|
|
up the implementation of a matrix math library - so they are probably OK.
|
|
|
|
I have accumulated by own matrix/quaternion library that I've used
|
|
for the last 10 years - every new project starts with it - and adds to
|
|
it, so now I don't even have to think about how to drive it. That's
|
|
a very liberating thing.
|
|
|
|
Another good source for a matrix lib is inside the Mesa sources. These
|
|
are particularly interesting because the latest Beta release has
|
|
super-optimised machine code for Intel CPU's under Linux as a conditional
|
|
compiled option. You'd need to copy and change the names of the routines
|
|
though to avoid the names clashing with the real Mesa routines.
|
|
|
|
One *IMPORTANT* thing is that when you invert the eye_rel_world matrix
|
|
to get world_rel_eye, don't use a general purpose matrix invert routine
|
|
since those are *REALLY* inefficient bits of code for matrices that
|
|
are guaranteed to be pure rotate/translate. Instead, just do this:
|
|
|
|
/*
|
|
This definition of a matrix is
|
|
easier to deal with than a float[16] -
|
|
but you can safely pass this kind
|
|
of matrix directly to OpenGL routines
|
|
like glMultMatrix and glLoadMatrix.
|
|
*/
|
|
|
|
typedef float fgMat [ 4 ][ 4 ] ;
|
|
|
|
/*
|
|
Transpose/Negate is a poor man's invert.
|
|
It can *only* be used when matrix is a
|
|
simple rotate-translate - but it's a
|
|
gazillion times faster than a full-blown
|
|
invert.
|
|
*/
|
|
|
|
void fgTransposeNegateMat( fgMat dst, fgMat src )
|
|
{
|
|
/* Transpose the 3x3 rotation sub-matrix */
|
|
|
|
dst[0][0] = src[0][0] ; dst[0][1] = src[1][0] ; dst[0][2] = src[2][0] ;
|
|
dst[1][0] = src[0][1] ; dst[1][1] = src[1][1] ; dst[1][2] = src[2][1] ;
|
|
dst[2][0] = src[0][2] ; dst[2][1] = src[1][2] ; dst[2][2] = src[2][2] ;
|
|
|
|
/* Negate the translate part */
|
|
|
|
dst[3][0] = -src[3][0] ; dst[3][1] = -src[3][1] ; dst[3][2] = -src[3][2] ;
|
|
|
|
/* Populate the rest */
|
|
|
|
dst[0][3] = dst[1][3] = dst[2][3] = 0.0f ; dst[3][3] = 1.0f ;
|
|
}
|
|
|
|
> Debugging the low level routines, though, is sometimes the easy part,
|
|
> debugging the usage of them is where it can often get hairy ... :-)
|
|
|
|
I agree - matrices are truly horrible to get your head around. Have
|
|
you looked into Quaternions yet? They are v.interesting for the
|
|
flight dynamics people because they don't suffer from 'gymbal lock'
|
|
like H,P,R angles and are easier to renormalize than matrices.
|
|
|
|
You don't want to use Quaternions for the main graphics code - but
|
|
it's easy to form a Matrix from a Quaternion - and Quaternions are
|
|
a much better way to represent rotation than the usual three angles.
|
|
|
|
Steve Baker 817-619-8776 (Vox/Vox-Mail)
|
|
Raytheon Systems Inc. 817-619-4028 (Fax)
|
|
2200 Arlington Downs Road SBaker@link.com (eMail)
|
|
Arlington, Texas. TX 76005-6171 SJBaker1@airmail.net (Personal eMail)
|
|
http://www.hti.com http://web2.airmail.net/sjbaker1 (personal)
|
|
|
|
** Beware of Geeks bearing GIF's. **
|
|
|
|
|
|
From owner-flight-gear@me.umn.edu Tue May 19 07:45:59 1998
|
|
X-VM-v5-Data: ([nil nil nil nil nil nil nil nil nil]
|
|
["4413" "Tue" "19" "May" "1998" "07:44:47" "-0500" "Steve Baker" "sbaker@link.com" nil "116" "Re: [FGFS] View Frustum Culling" "^From:" nil nil "5" nil nil nil nil nil]
|
|
nil)
|
|
Received: (from majordom@localhost)
|
|
by meserv.me.umn.edu (8.8.8/8.8.8) id HAA04944
|
|
for flight-gear-outgoing; Tue, 19 May 1998 07:45:59 -0500 (CDT)
|
|
X-Authentication-Warning: meserv.me.umn.edu: majordom set sender to owner-flight-gear@me.umn.edu using -f
|
|
Received: from lfkw10.bgm.link.com (bgm.link.com [130.210.2.10])
|
|
by meserv.me.umn.edu (8.8.8/8.8.8) with ESMTP id HAA04940
|
|
for <flight-gear@me.umn.edu>; Tue, 19 May 1998 07:45:55 -0500 (CDT)
|
|
Received: from borgus.bgm.link.com (borgus.bgm.link.com [130.210.236.13])
|
|
by lfkw10.bgm.link.com (8.8.6/HTI-Hack-8.8.4) with SMTP
|
|
id HAA29586 for <flight-gear@me.umn.edu>; Tue, 19 May 1998 07:45:23 -0500 (CDT)
|
|
X-Sender: steve@borgus.bgm.link.com
|
|
In-Reply-To: <199805182119.QAA04388@kenai.me.umn.edu>
|
|
Message-ID: <Pine.SGI.3.96.980519070916.5720B-100000@borgus.bgm.link.com>
|
|
MIME-Version: 1.0
|
|
Content-Type: TEXT/PLAIN; charset=US-ASCII
|
|
Precedence: bulk
|
|
Reply-To: flight-gear@me.umn.edu
|
|
From: Steve Baker <sbaker@link.com>
|
|
Sender: owner-flight-gear@me.umn.edu
|
|
To: flight-gear@me.umn.edu
|
|
Subject: Re: [FGFS] View Frustum Culling
|
|
Date: Tue, 19 May 1998 07:44:47 -0500 (CDT)
|
|
|
|
On Mon, 18 May 1998, Curtis L. Olson wrote:
|
|
|
|
> Steve Baker writes:
|
|
> > Are you only planning to cull at the tile level? You probably ought
|
|
> > to cull at the triangle strip level (at least on machines without
|
|
> > geometry hardware).
|
|
>
|
|
> You are always trying to make things more complicated ... :-)
|
|
|
|
It's my experience that things are perfectly capable of getting
|
|
more complicated without any help from me :-)
|
|
|
|
> > You can check a bounding sphere against the view frustum in about 4
|
|
> > multiplies and four additions - and you only need to do that for
|
|
> > spheres inside tiles that straddle the frustum. Each test that
|
|
> > excludes a tstrip will save a bunch of vertex transforms - so you
|
|
> > should get another big win in doing that.
|
|
>
|
|
> Ok, a couple of questions. Do you recommend pre-calculating and
|
|
> storing the bounding sphere info for each tri-strip in the data file,
|
|
> or should I calculate it at load time?
|
|
|
|
Well, since you only have one CPU to use for both rendering and
|
|
realtime database paging, you'll want to minimise the amount of
|
|
calculations when loading. The bounding sphere calculation
|
|
that most people do is very simple - you probably would want to do it
|
|
offline eventually - but you can probably do it on loading the database
|
|
for now just so you can get the culling stuff finished. So long as you
|
|
don't do it every frame you'll be OK in the short term.
|
|
|
|
The basic bounding sphere algorithm that most people (including me)
|
|
use is v.simple. Just find the maximum and minimum x, y and z values
|
|
in the data set, position the center of the sphere halfway between
|
|
the minimum and maximum in each axis - then go through the points
|
|
to find the one thats furthest from that center point - that distance
|
|
is the radius. (You can compare the square of the ranges to get the
|
|
longest range - so you only need to do one sqrt per sphere when you
|
|
need to compute the actual radius).
|
|
|
|
There has been some discussion of 'better' algorithms that (presumable)
|
|
produce tighter spheres than the simple method described above. On
|
|
my 'to do' list here at work is to evaluate these various algorithms to
|
|
see which actually produces the tightest spheres.
|
|
|
|
tighter spheres == better culling == lower polygon counts.
|
|
|
|
I'm pretty sceptical about these algorithms being *significantly*
|
|
better than the simple one - but even a few percent improvement
|
|
is worth having if I can do it offline and steal the code from
|
|
someone who can do 'math'.
|
|
|
|
This one looks interesting:
|
|
|
|
http://vision.ucsd.edu/~dwhite/ball.html
|
|
|
|
...although being iterative, I wouldn't want to do it in my
|
|
database loader code.
|
|
|
|
Same applies to this one:
|
|
|
|
http://cm.bell-labs.com/who/clarkson/center.html
|
|
|
|
Both have source code - which is just as well since I can't understand
|
|
the math behind either of them!
|
|
|
|
If your culling math starts to take too much time then you'll want to
|
|
do a hierarchical cull. If I were you though I'd probably just
|
|
do this:
|
|
|
|
for each terrain tile
|
|
{
|
|
if ( outside the frustum )
|
|
continue ;
|
|
|
|
if ( inside the frustum )
|
|
draw all the tristrips
|
|
else /* straddling the frustum */
|
|
{
|
|
for each tristrip
|
|
if ( inside or straddling the frustum )
|
|
draw the tristrip
|
|
}
|
|
}
|
|
|
|
(Of course 'draw the tristrip' might actually mean 'add the tristrip to
|
|
the appropriate bucket so we can draw it later')
|
|
|
|
> To impliment this sort of
|
|
> scheme I suppose I would need to keep each tri-strip in it's own
|
|
> display list.
|
|
|
|
Yep - but you need to do that so that you can....
|
|
|
|
> ...sort the objects into buckets by material properties.
|
|
|
|
Definitely. Switching material properties (especially texture map)
|
|
is very costly on most hardware OpenGL's. Sorting is an absolute
|
|
must once you start you use more than one kind of texture on the
|
|
terrain skin.
|
|
|
|
> I suppose this would entail defining material properties in the data
|
|
> file and otherwise sprucing up the data file format (and internal data
|
|
> structures) a bit.
|
|
|
|
Eventually.
|
|
|
|
|
|
Steve Baker (817)619-8776 (Vox/Vox-Mail)
|
|
Raytheon Systems Inc. (817)619-4028 (Fax)
|
|
Work: SBaker@link.com http://www.hti.com
|
|
Home: SJBaker1@airmail.net http://web2.airmail.net/sjbaker1
|
|
|
|
-------------------------------------
|
|
Please visit the FGFS web page: http://www.menet.umn.edu/~curt/fgfs/
|
|
For help on using this list (especially unsubscribing), send a message to
|
|
"flight-gear-request@me.umn.edu" with a single line of text: "help".
|
|
|
|
From sbaker@link.com Mon May 18 07:39:58 1998
|
|
X-VM-v5-Data: ([nil nil nil nil nil nil nil nil nil]
|
|
["10518" "Mon" "18" "May" "1998" "07:39:06" "-0500" "Steve Baker" "sbaker@link.com" nil "295" "Re: view frustum culling" "^From:" nil nil "5" nil nil nil nil nil]
|
|
nil)
|
|
Received: from lfkw10.bgm.link.com (bgm.link.com [130.210.2.10])
|
|
by meserv.me.umn.edu (8.8.8/8.8.8) with ESMTP id HAA01318
|
|
for <curt@me.umn.edu>; Mon, 18 May 1998 07:39:57 -0500 (CDT)
|
|
Received: from sutcliffe.bgm.link.com (sutcliffe.bgm.link.com [130.210.236.18])
|
|
by lfkw10.bgm.link.com (8.8.6/HTI-Hack-8.8.4) with SMTP
|
|
id HAA03232 for <curt@me.umn.edu>; Mon, 18 May 1998 07:39:26 -0500 (CDT)
|
|
X-Sender: steve@sutcliffe.bgm.link.com
|
|
Reply-To: Steve Baker <sbaker@link.com>
|
|
In-Reply-To: <199805152113.QAA12303@kenai.me.umn.edu>
|
|
Message-ID: <Pine.SGI.3.96.980518071249.21179A-100000@sutcliffe.bgm.link.com>
|
|
MIME-Version: 1.0
|
|
Content-Type: TEXT/PLAIN; charset=US-ASCII
|
|
From: Steve Baker <sbaker@link.com>
|
|
To: "Curtis L. Olson" <curt@me.umn.edu>
|
|
Subject: Re: view frustum culling
|
|
Date: Mon, 18 May 1998 07:39:06 -0500 (CDT)
|
|
|
|
On Fri, 15 May 1998, Curtis L. Olson wrote:
|
|
|
|
> I was just planning to work out the math myself, but it's not coming
|
|
> out nearly as simple as what you had. The near/far clipping plane is
|
|
> trivial, but I was working through the sides and started to see a few
|
|
> sqrt()'s and such start to creep in, and I don't remember seeing this
|
|
> with your pseudo-code.
|
|
|
|
Certainly shouldn't need sqrt's.
|
|
|
|
How about this:
|
|
|
|
You said:
|
|
|
|
> Anyone know anything about view frustum culling?
|
|
|
|
Yep.
|
|
|
|
Two issues:
|
|
|
|
1) Scene hierarchy generation (offline).
|
|
|
|
2) Runtime culling.
|
|
|
|
Hierarchy:
|
|
==========
|
|
|
|
There are lots of ways to do this. I usually build an heirerchical description
|
|
of each terrain tile. I typically build a tree structure that's organized
|
|
as follows:
|
|
|
|
| The World.
|
|
|
|
|
___________________|___
|
|
| | | | | | |
|
|
* * * * * * * Terrain tiles currently loaded
|
|
| | | | | | |
|
|
|
|
|
|
|
|
_____|_____
|
|
| | | |
|
|
* * * * Quarter-tiles
|
|
| | | |
|
|
|
|
|
|
|
|
_____|_____
|
|
| | | |
|
|
* * * * Sixteenth-tiles
|
|
| | | |
|
|
|
|
...and so on down until the number of polygons in each 'object' gets 'small enough'.
|
|
|
|
When you do this, don't try to split polygons when they cross a quarter or a
|
|
sixteenth tile boundary - just dump each polygon into the nearest 'bucket' to
|
|
it's centroid.
|
|
|
|
Do your tri-stripping on the leaf nodes of this tree - so that each tristrip
|
|
is contained entirely within one bucket.
|
|
|
|
Eventually, you will need to include buildings, roads, rivers, etc. Since these
|
|
need to be culled by level of detail, it is often useful to put them into a separate
|
|
tree structure that parallels the terrain 'skin' structure.
|
|
|
|
Finally, compute a bounding sphere around each leaf node, find the best fit
|
|
sphere by finding the maximum and minimim x, y and z of the tristrips in that
|
|
leaf node, taking the mid-point and then finding the vertex that is furthest
|
|
from that center point and using it as the radius.
|
|
|
|
Compute the bounding sphere for each level in the tree (everywhere where there is
|
|
a '*' in my diagram).
|
|
|
|
Runtime:
|
|
========
|
|
|
|
At runtime, you walk that tree every frame, testing the bounding sphere against
|
|
the view frustum.
|
|
|
|
* If the sphere lies entirely outside the view frustum then stop traversal
|
|
for that node. There is no need to test any of the nodes beneath this one
|
|
(we know that none of their leaf tristrips are visible).
|
|
|
|
* If the sphere lies entirely inside the view frustum then traverse immediately
|
|
to all of the leaves below this node without doing any more sphere testing
|
|
on them - draw all of the tristrips that are there. (We know they are all visible)
|
|
|
|
* If the sphere straddles the view frustum then check each daughter node in
|
|
turn by applying this algorithm on them recursively. If a leaf node straddles
|
|
the view frustrum then it's bad luck, you just draw all the tristrips it
|
|
contains and let OpenGL do the work.
|
|
|
|
You might also want to put a 'transition range' onto each node and if it
|
|
lies beyond that range cull it. You can also use this to conveniently
|
|
switch levels of detail by having multiple versions of each object in
|
|
the tree.
|
|
|
|
Testing a sphere against the View Frustum:
|
|
==========================================
|
|
|
|
In most cases, we can describe the volume of space that you can see
|
|
through the little glass window on the front of your CRT using a
|
|
Frustum (frequently mis-spelled as Frustrum or Fustrum even in some
|
|
text books).
|
|
|
|
A frustum is a truncated pyramid - which typically bounded by six
|
|
planes called:
|
|
|
|
NEAR, FAR, LEFT, RIGHT, TOP, BOTTOM
|
|
|
|
There are applications that require additional clipping planes (eg for
|
|
non-rectangular screens) - extending the work described in this
|
|
to cater for that is not hard).
|
|
|
|
In principal, all six planes can be constructed as general plane
|
|
equations:
|
|
|
|
A x + B y + C z + D == 0
|
|
|
|
However, for most applications, NEAR and FAR are parallel to the
|
|
screen, LEFT, RIGHT,TOP and BOTTOM all meet at the eye and the eye lies
|
|
along a vector that extends out from the center of the screen and is
|
|
perpendicular to it. This simplifies the equations considerably for
|
|
practical applications.
|
|
|
|
Transforms.
|
|
~~~~~~~~~~~
|
|
|
|
It is easiest to perform culling in a coordinate system where the
|
|
eyepoint is at the origin and the line from the eye through the center
|
|
of the screen lies along one major axis with the edges of the screen
|
|
parallel to the remaining two axes. This coordinate system is called
|
|
'Eye Space'.
|
|
|
|
Testing a Sphere against a Frustum.
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
The most important thing to bear in mind about culling is that the
|
|
first trivial-reject test you apply is by far the most time-critical.
|
|
This test is always applied to more nodes than any of the subsequent
|
|
tests.
|
|
|
|
So, do the cheapest test first.
|
|
|
|
This is typically the NEAR plane test. Everything behind the viewers
|
|
head gets chopped out - and it's an especially cheap test.
|
|
|
|
|
|
if ( obj_sphere.center.z < near_plane - obj_sphere.radius )
|
|
REJECT!!
|
|
|
|
|
|
...next do the second cheapest test (assuming you know that your
|
|
database could possibly extend beyond the far clip plane)...
|
|
|
|
|
|
if ( obj_sphere.center.z - obj_sphere.radius > far_plane )
|
|
REJECT!!
|
|
|
|
|
|
...and *then* (for each of the other 4 planes) do...
|
|
|
|
|
|
if ( distance( obj.position, plane ) <= obj_sphere.radius )
|
|
REJECT!!
|
|
|
|
|
|
(The algorithm for computing that 'distance()' function is described
|
|
below).
|
|
|
|
It's also useful to know that in many applications, you cull more
|
|
objects from the left and right faces of the frustum than you do from
|
|
the top and bottom - so test left, then right, then bottom then top.
|
|
|
|
Also, with bounding sphere tests, you shouldn't forget to do
|
|
total-accept as well as total-reject tests. Once you know that an
|
|
object's sphere is TOTALLY on screen, you don't have to descend into
|
|
the daughter objects to cull-test them...you *know* they are all
|
|
on-screen.
|
|
|
|
Another way to look at that it to remember which of the six possible
|
|
plane tests didn't even touch the sphere - as you work your way down
|
|
the object hierarchy, you can accumulate those flags and avoid even
|
|
testing those planes that a parent sphere has already cleanly passed.
|
|
If you do this then a vast percentage of your spheres will only need to
|
|
be tested against one plane. However, for the normal case of a simple
|
|
frustum - when you examine the fully optimised
|
|
distance-of-point-from-plane code (below), you may well conclude that
|
|
this additional logic doesn't justify the paltry amount of additional
|
|
math that it might save.
|
|
|
|
Computing the Distance from Sphere Center to Clipping Plane.
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
A plane can be represented by the equation
|
|
|
|
|
|
Ax + By + Cz + D = 0 ;
|
|
|
|
|
|
A,B,C is just the surface normal of the plane and D is the shortest
|
|
distance from the origin to the plane.
|
|
|
|
So, if you need to find the distance of a point from the plane, just
|
|
imagine a new plane that goes through your test point and is parallel
|
|
to the plane you want to test. The plane equation of that new plane
|
|
would be:
|
|
|
|
|
|
A'x + B'y + C'z + D' = 0 ;
|
|
|
|
|
|
Since the two planes are parallel, their surface normals are the same,
|
|
so
|
|
|
|
|
|
A' == A B' == B C' == C D' == D + distance_between_the_two_planes
|
|
|
|
|
|
...the only thing that's different is their D values - which differ by
|
|
the distance of your test point from the original plane.
|
|
|
|
So, for a point (x,y,z), the distance 'd' from the plane (A,B,C,D) is
|
|
derived as:
|
|
|
|
|
|
d = D' - D
|
|
= -A'x - B'y - C'z - D
|
|
= -Ax - By - Cz - D
|
|
= -( [ABC]dot[xyz] + D )
|
|
|
|
|
|
A dot-product of the point and the surface normal of the plane, plus
|
|
the distance from the plane to the origin. Three multiplies, three
|
|
additions and a negation.
|
|
|
|
As an aside - if you consider the point (x,y,z) as a FOUR element
|
|
homogeneous vector (x,y,z,w) then 'w' is 1.0 and you can compute the
|
|
distance by simply taking the four element dot-product of (A,B,C,D)
|
|
with (x,y,z,w). If you have fast 4x4 matrix math hardware in your
|
|
machine then you can use it to compute the distance from a point to all
|
|
four planes in a single operation!
|
|
|
|
That's the general result for an arbitary plane - but culling to the
|
|
view frustum is a very special case. If you are working in eye-relative
|
|
coordinates (IMHO this is best), then since all TOP,BOTTOM,LEFT,RIGHT
|
|
planes of the frustum meet at the eye - and since the eye is at the
|
|
origin (by definition), then D is always zero for those planes and that
|
|
saves you a subtract.
|
|
|
|
If you are feeling even more in need of optimisation - then you can
|
|
save one multiply per plane by realising that (for rectangular screens)
|
|
one of the three components of the plane equation will always be zero.
|
|
|
|
So, for the LEFT clip plane, the Y component of the normal of the plane
|
|
is zero, so the distance to the left or right plane is just
|
|
|
|
|
|
d = -( Ax + Cz )
|
|
|
|
|
|
...and to the top or bottom plane it's just:
|
|
|
|
|
|
d = -( By + Cz )
|
|
|
|
|
|
Furthermore, we know that the A component for the LEFT plane is just
|
|
the negation of the A component of the RIGHT plane, and the C component
|
|
is the same for both LEFT and RIGHT (and similarly, the B component of
|
|
the TOP plane, is the negation of the B component for the BOTTOM plane
|
|
and the C component is the same for both TOP and BOTTOM). This means
|
|
that you only need four multiplies and four additions to do the entire
|
|
job. (Since you are only using this for culling, you don't need the
|
|
minus sign - just reverse the conditional).
|
|
|
|
The NEAR and FAR planes are typically parallel to the X/Y plane. That
|
|
means that A and B are both zero and C is one (or minus-one) - but D is
|
|
not zero, so the math boils down to an add and a negate:
|
|
|
|
|
|
d = -(z + D)
|
|
|
|
|
|
Conclusions.
|
|
~~~~~~~~~~~~
|
|
|
|
Sphere-based culling can be extremely cost-effective. It's so cheap
|
|
that even if you feel the need to use a bounding cubeoid (or even a yet
|
|
more complex shape), it's still worth doing a sphere-based cull first
|
|
just to get rid of the trivial accept and reject cases.
|
|
|
|
|
|
Steve Baker (817)619-8776 (Vox/Vox-Mail)
|
|
Raytheon Systems Inc. (817)619-4028 (Fax)
|
|
Work: SBaker@link.com http://www.hti.com
|
|
Home: SJBaker1@airmail.net http://web2.airmail.net/sjbaker1
|
|
|
|
From owner-flight-gear@me.umn.edu Tue May 26 08:43:36 1998
|
|
X-VM-v5-Data: ([nil nil nil nil nil nil nil nil nil]
|
|
["2090" "Tue" "26" "May" "1998" "08:42:09" "-0500" "Steve Baker" "sbaker@link.com" nil "69" "Re: [FGFS] View frustum culling" "^From:" nil nil "5" nil nil nil nil nil]
|
|
nil)
|
|
Received: (from majordom@localhost)
|
|
by meserv.me.umn.edu (8.8.8/8.8.8) id IAA29744
|
|
for flight-gear-outgoing; Tue, 26 May 1998 08:43:36 -0500 (CDT)
|
|
X-Authentication-Warning: meserv.me.umn.edu: majordom set sender to owner-flight-gear@me.umn.edu using -f
|
|
Received: from lfkw10.bgm.link.com (bgm.link.com [130.210.2.10])
|
|
by meserv.me.umn.edu (8.8.8/8.8.8) with ESMTP id IAA29740
|
|
for <flight-gear@me.umn.edu>; Tue, 26 May 1998 08:43:31 -0500 (CDT)
|
|
Received: from borgus.bgm.link.com (borgus.bgm.link.com [130.210.236.13])
|
|
by lfkw10.bgm.link.com (8.8.6/HTI-Hack-8.8.4) with SMTP
|
|
id IAA02170 for <flight-gear@me.umn.edu>; Tue, 26 May 1998 08:43:01 -0500 (CDT)
|
|
X-Sender: steve@borgus.bgm.link.com
|
|
In-Reply-To: <199805240245.VAA00603@kenai.me.umn.edu>
|
|
Message-ID: <Pine.SGI.3.96.980526083427.2282G-100000@borgus.bgm.link.com>
|
|
MIME-Version: 1.0
|
|
Content-Type: TEXT/PLAIN; charset=US-ASCII
|
|
Precedence: bulk
|
|
Reply-To: flight-gear@me.umn.edu
|
|
From: Steve Baker <sbaker@link.com>
|
|
Sender: owner-flight-gear@me.umn.edu
|
|
To: flight-gear@me.umn.edu
|
|
Subject: Re: [FGFS] View frustum culling
|
|
Date: Tue, 26 May 1998 08:42:09 -0500 (CDT)
|
|
|
|
On Sat, 23 May 1998, Curtis L. Olson wrote:
|
|
|
|
> Gene Buckle writes:
|
|
> > If you want to email me a cygnus/mesa binary, I'd be happy to give
|
|
> > you new speed figures.
|
|
>
|
|
> Gene,
|
|
>
|
|
> The new binaries expect a modified scenery format. My impression for
|
|
> now based on culled vs. drawn percentages is that there was a much
|
|
> bigger jump between no culling and tile culling, than between tile
|
|
> culling and fragment culling.
|
|
|
|
That's to be expected...
|
|
|
|
(The eye is in the center of the diagram - looking up:
|
|
|
|
No Culling - draw this much:
|
|
|
|
________\_____________/________
|
|
| | \ | / | |
|
|
| | \ | / | |
|
|
|_______|___\___|___/___|_______|
|
|
| | \ | / | |
|
|
| | \ | / | |
|
|
|_______|______\|/______|_______|
|
|
| | | | |
|
|
| | | | |
|
|
|_______|_______|_______|_______|
|
|
| | | | |
|
|
| | | | |
|
|
|_______|_______|_______|_______|
|
|
|
|
|
|
Tile culling - draw this much:
|
|
|
|
_\_____________/_
|
|
| \ | / |
|
|
| \ | / |
|
|
|___\___|___/___|
|
|
| \ | / |
|
|
| \ | / |
|
|
|______\|/______|
|
|
|
|
|
|
Tile *and* tstrip culling - draw maybe this much:
|
|
|
|
\_____________/_
|
|
|_\ | /_|
|
|
|_\ | / |
|
|
|_\___|___/__|
|
|
|\ | /_|
|
|
|_\ | /_|
|
|
|\|/|
|
|
|
|
Clearly most of the savings were in the tile culling, but providing the
|
|
culling itself is done reasonably efficiently, the tstrip culling is
|
|
still worth-while.
|
|
|
|
|
|
Steve Baker (817)619-8776 (Vox/Vox-Mail)
|
|
Raytheon Systems Inc. (817)619-4028 (Fax)
|
|
Work: SBaker@link.com http://www.hti.com
|
|
Home: SJBaker1@airmail.net http://web2.airmail.net/sjbaker1
|
|
|
|
-------------------------------------
|
|
Please visit the FGFS web page: http://www.menet.umn.edu/~curt/fgfs/
|
|
For help on using this list (especially unsubscribing), send a message to
|
|
"flight-gear-request@me.umn.edu" with a single line of text: "help".
|
|
|