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" "" "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 ; 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 ; Thu, 29 Jan 1998 23:15:35 -0600 (CST) X-Sender: steve@lechter.bgm.link.com Reply-To: Steve Baker In-Reply-To: <199801292145.PAA04212@kenai.me.umn.edu> Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII From: Steve Baker To: "Curtis L. Olson" 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" "" "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 ; 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 ; Fri, 30 Jan 1998 14:07:27 -0600 (CST) X-Sender: steve@lechter.bgm.link.com Reply-To: Steve Baker In-Reply-To: <199801301948.NAA25718@kenai.me.umn.edu> Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII From: Steve Baker To: "Curtis L. Olson" 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 ; 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 ; Fri, 30 Jan 1998 22:51:26 -0600 (CST) X-Sender: steve@lechter.bgm.link.com Reply-To: Steve Baker In-Reply-To: <199801302035.OAA26234@kenai.me.umn.edu> Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII From: Steve Baker To: "Curtis L. Olson" 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 ; 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 ; 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: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Precedence: bulk Reply-To: flight-gear@me.umn.edu From: Steve Baker 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 ; 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 ; Mon, 18 May 1998 07:39:26 -0500 (CDT) X-Sender: steve@sutcliffe.bgm.link.com Reply-To: Steve Baker In-Reply-To: <199805152113.QAA12303@kenai.me.umn.edu> Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII From: Steve Baker To: "Curtis L. Olson" 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 ; 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 ; 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: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Precedence: bulk Reply-To: flight-gear@me.umn.edu From: Steve Baker 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".