Skip to main content
GameDev.net gamedev.net
🔒 Locked

Planet Rendering: Part 1 - The Basics

Started by technobot Apr 4, 2003 at 4:02 PM 62 replies 54.2k views
Original Post
technobot
technobot
<< WARNING: Long! >> Introduction: As some of you might have noticed from other threads on this forum, I am developing a planetary-scale 3D graphics engine for our game, "The Keepers" (link in my signature). The game will involve the simulation of an entire planet. On the engine's side, this will involve procedural generation of terrain features (including features such as vegetation coverage, rivers, etcetera), real-time deformation of the terrain, simulation of water (seas and oceans in partcular), weather simulation, and rendering of the terrain, plants, water, and atmosphere based on the generated data. The engine is currently in early stages of development, and the planetary simulation/rendering part of the engine is in design stages. Following my own interest in the area, and the interest expressed in this recent thread, I have decided to initiate a series of threads, each focusing on a different aspect of the realistic simulation and rendering of a virtual planet. In the beginning of each thread, I will provide a references section with links to previous threads in the series and other threads, articles, papers, and so on, which are relevant to that particlar thread. This series is intended to serve as a reference for everyone developing a terrain engine, particularly those interested in procedural worlds, contineuous ("infinite") terrain, and/or planetary scale engines (somewhat like this famous sky thread). The success of this series depends entirely on your participation and cooperation. Note: I suppose this would be a good time to ask everyone who decides to participate to stick to the topic of the corresponding thread. PS: Did you notice the icon I used for this thread? Get it?
References: The Virtual Terrain Project [website] Infinite world. tiling maps [gamedev thread] - includes basis for geo-quadtree idea (see below). Spherical Trees [gamedev thread] Geomipmaping [paper] Octrees [tutorial] Adaptive Binary Trees [gamedev thread] (some posts down the thread) Quaternions [article] Anyone knows some good links regarding quadtrees (I don't need them myself, but other people that read this thread might need them)? Some more links regarding octrees are also welcome (as well as any other link you think is relevant).
Ok. Let's begin. As stated by the title, this thread is about the basics of planet rendering, which means the following:
  • The concepts of continuous and semi-continuous data representation .
  • Basic data structures and representation. Note that additional data structures may be discussed in following threads, if necessary.
  • Basic algorthims (LOD, frustum culling, etc.), in the context of that data representation.
An important assumption that I'll be making throughout the dicussion is that all distances and sizes are scaled realistically (e.g an object 100 meters in diameter should be exactly 5 times larger than another object that is 20 meters in diameter). First, let's define continuous data representation . Continuous data representation, is a data representation which does not introduce borders to the data. Such a representation is probably the most comfortable when dealing with continuous data, such as the hight data of the surface of a planet. Unforetunately, I am not familiar with any continous (or semi-contuous, defined below) data representations in the comupter science or 3D graphics literature (altough I have some of my own thoughts on the topic, which I'll describe later in this post), so I cannot bring examples (other than what I'll describe below). If anyone is familiar with such data representations, please post some links and/or a description of the basic ideas behind those schemes. As a famous example for a non-continuous data representation, consider a heightmap. Clearly, it introduces boundaries to the data, since one could only move so far in any direction along the heightmap (e.g. one can't move more than 255 pixels to the right, starting at the top-left pixel of a 256x256 pixel heightmap). A semi-continuous data representation is a data representation that is continuous along at least one dimension, and non-continuous along at least one other dimention (note that this implies multi-dimentional data, e.g. 3D data). An example of data that will benefit from a semi-continuous representation is wheather parameters ditribution in the atmosphere of a planet (temperature, pressure, humidity, and air-flow vectors are examples of such parameters). Such data is semi-continuous because an atmosphere is continuous in the horizontal dimensions (the dimensions paralel to the planet's surface), but limited in the vertical dimension (it has a minimum and maximum altitudes). All of the data that will be used for the simulation and rendering of our virtual planet will most likely need to be represented in either continuous or semi-continuous form. As originally suggested in this thread, I have considered the use of spherical polar coordinates to contuously represent the various data of the planet. This would consist of an ordinary octtree, quadtree, or ABT, built and maintained in sperical polar coordinates. However, I have reached the conclusion that, while a significant improvement (for the purpose of planet simulation and rendering) over the cartesian versions of these structures, the polar-coordinate versions would still suffer from the same non-continuity problems as their cartesian counterparts. This is in part due to the non-continuity of the polar coordinates themselves (e.g. once you reach 180 degrees longtitude, you'd have to wrap back to -180 degrees to continue). A better solution would be a geosphere like structure. The basic idea of the structure is the same as a quadtree, but with the following adjustments:
  • The nodes of the tree would represent triangular areas, rather than rectangular areas as in a conventional quadtree.
  • While the root node would represent the entire planet, as you would probably do with an ordinary quadtree, its four child nodes would represent the four faces of a trangular piramid which is the basis for the geosphere, as suggested by TerranFury in this thread.
  • The nodes would subdivide as decribed in the same thread.
  • Each node would store pointers to its three neighbours, in addition to the regular child (and possibly parent) pointers. This is crucial for the continuity of the data representation.
  • Each node would have a minimum and maximum altitude.
Note that each node completely contains its children, in terms of volume and position. Since each node is connected with its neighbors in a continuous fashion, there is probably little or no sence in destinguishing the "center" child of a node from the "corner" children. For data requiring a 3D representation, rather than a 2D one, the structure can be extended to an octtree, by subdividing along the altitude vector as well (it would then become a semi-continuous representation, since the data is limited along the altitude vector). For lack of a better name, I will call this structure a geo-quadtree , and its corresponding octtree version a geo-octtree . Issues that should be discussed regarding these structures:
  • How to handle neighbor pointers between nodes of different subdivision levels?
  • How to represent the volume of each node? Positions of the corners? Some other method?
  • Other?
Other solutions are also welcome. For the frame of reference, a right-hand cartesian system seems adequate, whereas its origin is at the center of the planet, and its "up" axis (y in OpenGL) points towards the north pole of the planet. Representing positions, orientation, etc. Again, polar coordinates (lattitude, longtitude, altitude) were considered for the representation of positions. However, due to their discontinuity (mentioned above), and the problems of converting between cartesian coordinates and polar coordinates, they seem rather inadequate. A different option would be to use quaternions and altitude values, whereas the quaternion would specifiy the "horizontal" position and the altitude would specify the "vertical" position. Quaternions are particularly handy in that one could easily (and continuously) traverse the surface of the planet by interpolating between the source and destination quaternions. However, it may be somewhat problematic to do physical simulations if positions are (partially) represented as quaternions. Question: how can one find the angle between two quaternions (not sure this makes much sence as such, since quaternions are essentially 4D, but it does make sence to find the angle between two positions/orientations that are represented by quaternions)? Another option is to use an axis-angle pair instead of the quaternions. For positions combined with an orientation, the axis should probably be perpendicular to the "forward" vector of the object and to the radius vector (the vector from the center of the planet to the object). For "pure" positions (i.e. no orientation), any axis that is perpendicular to the radius vector will do. This may be more comfortable for physics, but interpolation gets more tricky... then again, interpolation might not be necessary in the first place... It may be possible that a standard cartesian vector, possibly in unit-vector+length form, would be sufficient, but I am not sure as to the continuity of such a representation. If it is sufficient, it would, by far, be the most convinient for physics. Whatever the representation, it should have the following properties:
  • Continuous
  • Easy to find angle between two positions (the more efficient, the better - this is important for horizon culling, which is described below)
  • Easy to work with when it comes to physics. For example, if polar coordinates didn't have their other problems, they could have been used directly in physics, since on the local scale the two are almost the same (since the angles involved are extremely small)
Any thoughts on this matter? This brings us to orientations. It would seem that any method would do here, including a second quaternion, a roll/pitch/yaw triplet, and others. Feel free to correct me. The standard vector and plane representations will probably do as well (a couple of small adjustments may be needed for planes). Again, correct me if I'm wrong. A few extra words regarding planes. As you should know, the standard equation for a plane is Ax+By+Cz+D=0, or Ax+By+Cz = -D. Conviniently enough, (A,B,C) is the normal vector of the plane, and if it is normalized, then |D| is the distance of the plane from the origin. In other words, if the (A,B,C) vector is normalized, then in our frame of reference (which I mentioned above) (A,B,C) is a vector on the surface of a unit sphere, which is concentric with our planet, and |D| is the altitude of the plane. This will come in handy later. So to represent a plane, we should probably add two constraints: a) the (A,B,C) vector must be kept normalized (this restriction also simplifies point-distance-from-plane calculations), and b) we will use the slightly modified plane equation Ax+By+Cz-D=0, and require that D>0. This implies that the (A,B,C) vector must always point away from the origin (and never towards it), and that a paralel plane that is the same distance away from the origin but on its other side, will be given by (-A)x+(-B)y+(-C)z-D=0. This allows us to introduce two new concepts, which are demonstrated by the following image: The circle represents our planet, with its center being the origin. The blue line represent the D(A,B,C) vector, and the red line represents the plane. Everything within the white region is considered to be on the inner side of the plane , and everything in the gray region is considered to be on the outer side of the plane . As before, other ideas are welcome. Some basic algorithms Horizon culling: The first thing to do for horizon culling is to compute the angle between the camera and any one object. Any object that is farther than a known angle theta from the camera can be culled away. By calculating the angle between the camera and the vertices of each node of our geo-quadtree, heirarchial horizon culling can be acheived. The angle theta is a direct function of the altitude of the camera, and can be easily precalculated and stored in a LUT. It is imporatnt to note, that since some objects (such as high mountains) can be seen beyond the horizon, theta should be larger than the angle from the camera to the horizon: As can be seen from the image, theta is given by: theta = arccos(R/h) + arccos(R/H), where R is the radius of the planet, not including the atmosphere (i.e. the minimum surface altitude, measured from the center of the planet), h is the altitude of the camera (measured from the center of the planet), and H is the maximum altitude that an object can reach (again, measured from the center). Frustum culling: Frustum culling may be done in one of two ways. The first one is to convert the whatever-position-representation of the geo-quadtree nodes' vertices to conventional cartesian coordinates, and proceed as normal. The other way is to take advantage of the way we represent our planes: The gray area represents the geo-quadtree node we are testing. The culling against each of the frustum's planes is done by calculating two treshold values for the plane's D parameter, using the formula D=R*cos(theta), where R is the minimum/maximum radius of the volume we're testing, and theta is the angle between the plane's (A,B,C) vector and the coorsponding side of the volume (marked in blue in the image). If the plane's actual D is lower than the minimum treshold, than the volume is entirely on the outer side of the plane. If the plane's actual D is higher than the maximum treshold, than the volume is entirely on the inner side of the plane. Otherwise, the plane intersects the volume. I am not sure which of the two methods is more efficient, and which optimization are possible with each one... As always, comments, suggetions, etcetera are welcome. Occlusion culling: I am not yet sure exactly how to acheive this, but a possible way may involve the culling of geo-octree nodes against other geo-octree nodes that are known to be underground. LOD: This can be done in one of many different methods, but geomipmamping seems a good choice here, with the adjustment that we work with traingular regions instead of rectangular ones: The red lines represent the pach boundaries. An inportant issue to consider here, is how would one handle large level-of-detail changes, e.g. to represent the height data of a river shore, which runs though a large relatively flat area... Let the discussions begin! Michael K., Designer and Graphics Programmer of "The Keepers"
We come in peace... surrender or die! [edited by - technobot on April 4, 2003 7:08:42 PM]
Michael K.
Eelco
Eelco
wow youve really thought about this it seems

i have been working on an implementation of teranfurys algo yesterday, and it worked somewhat, but far from perfect yet. i hope i can make it bugfree today. its not in c++ though: im way too much of a beginner in c++ for such things, but when i get it working ill try to port it.
technobot
technobot
quote:
Original post by Eelco
i have been working on an implementation of teranfurys algo yesterday, and it worked somewhat, but far from perfect yet. i hope i can make it bugfree today.

Heh.. I guess I beat you to it. I just finshed my version based on some old code of mine... It''s in Delphi + OpenGL. I''ll post a link to it later, when I upload it.

It shows pretty clearly that while the general idea works, a tetrahedron (tirangular piramid) may not be the optimal starting point, since it generates a rather irregular triangle distribution... not exactly a geosphere, to say the least.



Michael K.,
Designer and Graphics Programmer of "The Keepers"



We come in peace... surrender or die!
Michael K.
Eelco
Eelco
dunno if you beat me... i got it right only about half an hour after i posted that
anyway i also concluded a tetrahedron is indeed not the best starting primitive. the size of the centre tris varys significantly from those on the edges of a face.
octahredon''s though are MUCH better in this aspect. they still suffer from the same phenomena, but its much less obvious yet.
maybe there is an even better primitive to start with, a cube for example with each face split up in four tris for example...
mind though that perfect uniformity is impossible.
ill keep playing with it a little longer
technobot
technobot
quote:
Original post by Eelco
maybe there is an even better primitive to start with, a cube for example with each face split up in four tris for example...
mind though that perfect uniformity is impossible.

My original code demonstrated a cube. The new version still suports it, so you can compare. It does look much much more uniform with a cube...
As for perfect uniformity - you get that (or at least very very very close to it) with a correct geosphere. I think a dodecahedron or something like that is the right starting geomtry for that (not sure).

PS: will upload soon...



Michael K.,
Co-designer and Graphics Programmer of "The Keepers"



We come in peace... surrender or die!
Michael K.
Eelco
Eelco
i finally found the name of the primitive is was looking for: a icosahedral, consisting of 20 triangles equal in size.
have to find a way to calulate the vertices of this thing though, and its quite a lot harder than an octahredon or a tetrahedron im affraid, but i think it will be worth the effort.
Eelco
Eelco
i did it, and it looks perfect now, tris are all practicly the same size

heres the code i used to set up the isocahedral, or whatever its exact name is:

;setup isocahedron
a#=2.0/(1.0+Sqr(5.0)) ;a=a*radius
b#=1.0/Sqr((3.0+Sqr(5.0)) / (1.0+Sqr(5.0))) ;1/sqr=radius/sqr

v01=AddVertex(surf, 0, a, b)
v02=AddVertex(surf, 0, a, -b)
v03=AddVertex(surf, 0, -a, b)
v04=AddVertex(surf, 0, -a, -b)
v05=AddVertex(surf, a, b, 0)
v06=AddVertex(surf, a, -b, 0)
v07=AddVertex(surf, -a, b, 0)
v08=AddVertex(surf, -a, -b, 0)
v09=AddVertex(surf, b, 0, a)
v10=AddVertex(surf, b, 0, -a)
v11=AddVertex(surf, -b, 0, a)
v12=AddVertex(surf, -b, 0, -a)

detail#=5
sub(v02,v05,v07,detail)
sub(v01,v07,v05,detail)
sub(v01,v03,v11,detail)
sub(v01,v09,v03,detail)
sub(v02,v04,v10,detail)
sub(v02,v12,v04,detail)
sub(v03,v06,v08,detail)
sub(v04,v08,v06,detail)
sub(v07,v11,v12,detail)
sub(v08,v12,v11,detail)
sub(v05,v10,v09,detail)
sub(v06,v09,v10,detail)
sub(v01,v11,v07,detail)
sub(v01,v05,v09,detail)
sub(v02,v07,v12,detail)
sub(v02,v10,v05,detail)
sub(v04,v12,v08,detail)
sub(v04,v06,v10,detail)
sub(v03,v08,v11,detail)
sub(v03,v09,v06,detail)
technobot
technobot
See if you can make sense of this mathematical description of an icosahedron...
My demo: source, binary.

EDIT: Hmm... Ok, I'll try adding that to my demo and will upload the new version.

Michael K.,
Co-designer and Graphics Programmer of "The Keepers"



We come in peace... surrender or die!

[edited by - technobot on April 5, 2003 8:57:23 AM]
Michael K.
Eelco
Eelco
starting off with a cube doesnt look bad either, but an isocahedron is even better i think.

oh btw i should note that in this code snippet is posted ';'s are comments. sub() is a recursive function that splits up a tri in detail% steps. the rest should be obvious.

EDIT: i was looking a bit in your code, and i was you mention your routine also creates double vertices when splitting. i didnt bother with something more complicated to solve this either yet, but if were going to make a terrain out of this we definily want this solved: its faster and it allows more easy manipulation of the height of the terrain.

i imaging that when editing you could have a hill/valley brush, with witch you can move the vertices under it along their normal vector from the origin of the model, but not away from this line so as not to destroy the uniformness of the terrain.

[edited by - eelco on April 5, 2003 10:03:42 AM]
Eelco
Eelco
looks really good, that game. they provide little information about it though. they seem a bit desperate for beta testers too: all the links on their sites lead to the beta testers signup..

anyway, back to the topic: i think the whole concept of a sphere greatly reduces the problem of culling, since plain backfaceculling does all the work for you, as long as the observer is close to the surface of the planet. a good sized planet will take a serious amount of tris though, witch is even too much to backfacecull im affraid. therefore it would be wise to split up in regions i think, witch are not all loaded at the same time, and besides a good lod system would be great too. ive never done anything with lod systems though, so ill leave that to others..

[edited by - eelco on April 5, 2003 12:09:50 PM]
Ysaneya
Ysaneya
That''s funny, i''ve started working on a 3D engine a few days ago that should render planets with a high level of detail.

Basically, i want to be able to zoom-in from outter-space up to the meter level, and be able to see grass, plants, trees, etc.. that''s a real challenge.

At the moment i''ve got a LOD algorithm working (not very well, i''ve coded it in a few hours), and i use earth data maps for everything above the kilometer level. Under that scale, everything is displaced by a multifractal noise.

It''s pretty fast when you''re flying slowly, or fast above 1 km, but everything else causes lots of vertices to be recomputed on-the-fly, so i''m playing with the idea to use a separate thread to generate the procedural terrain. There''s no texturing or lighting yet, and these will add a lot of overhead.. hum. Back to work now

Y.
Eelco
Eelco
hmm it appeared my old isocahedron routine was plain crap: set the detail level to 0 and see the irregularity for yourself. i found another way to do it, and this time it does work correctly


;setup isocahedron
v01=AddVertex(surf,0,0,-1) ;top
v12=AddVertex(surf,0,0, 1) ;bottom

r#=(2*Sqr(5))/5
h#=Sqr(5)/5

v02=AddVertex(surf,Cos(72*0.0)*r,Sin(72*0.0)*r,-h)
v03=AddVertex(surf,Cos(72*1.0)*r,Sin(72*1.0)*r,-h)
v04=AddVertex(surf,Cos(72*2.0)*r,Sin(72*2.0)*r,-h)
v05=AddVertex(surf,Cos(72*3.0)*r,Sin(72*3.0)*r,-h)
v06=AddVertex(surf,Cos(72*4.0)*r,Sin(72*4.0)*r,-h)

v07=AddVertex(surf,Cos(72*0.5)*r,Sin(72*0.5)*r,h)
v08=AddVertex(surf,Cos(72*1.5)*r,Sin(72*1.5)*r,h)
v09=AddVertex(surf,Cos(72*2.5)*r,Sin(72*2.5)*r,h)
v10=AddVertex(surf,Cos(72*3.5)*r,Sin(72*3.5)*r,h)
v11=AddVertex(surf,Cos(72*4.5)*r,Sin(72*4.5)*r,h)


detail=5

;top
sub(v01,v02,v03,detail)
sub(v01,v03,v04,detail)
sub(v01,v04,v05,detail)
sub(v01,v05,v06,detail)
sub(v01,v06,v02,detail)

sub(v02,v07,v03,detail)
sub(v03,v08,v04,detail)
sub(v04,v09,v05,detail)
sub(v05,v10,v06,detail)
sub(v06,v11,v02,detail)

;bottom
sub(v12,v11,v10,detail)
sub(v12,v10,v09,detail)
sub(v12,v09,v08,detail)
sub(v12,v08,v07,detail)
sub(v12,v07,v11,detail)

sub(v08,v03,v07,detail)
sub(v09,v04,v08,detail)
sub(v10,v05,v09,detail)
sub(v11,v06,v10,detail)
sub(v07,v02,v11,detail)
technobot
technobot
quote:
Original post by Eelco
EDIT: i was looking a bit in your code, and i was you mention your routine also creates double vertices when splitting. i didnt bother with something more complicated to solve this either yet, but if were going to make a terrain out of this we definily want this solved: its faster and it allows more easy manipulation of the height of the terrain.

The simplest solution would be to use connectivity info for the mesh. The 3D engine I'm writing for "The Keepers" already has this feature. The demo I uploaded is based on roughly 2 year old code, so no connectivity there...
Btw, you messed up some of the vertex indices in your icosahedron code (some of your edges are in the wrong direction). Also, your faces are CW, whereas I had to make them CCW in the demo (OpenGL default).

EDIT: I was refering to your original code. See my updated code (same links) for a working version.

quote:

i think the whole concept of a sphere greatly reduces the problem of culling, since plain backfaceculling does all the work for you, as long as the observer is close to the surface of the planet. a good sized planet will take a serious amount of tris though, witch is even too much to backfacecull im affraid. therefore it would be wise to split up in regions i think, witch are not all loaded at the same time, and besides a good lod system would be great too. ive never done anything with lod systems though, so ill leave that to others..

Backface culling will help you if you're looking at the planet from orbit (in which case you'll have few faces, assuming a decent LOD scheme). Otherwise, as you said, you'll have too many faces to cull. In this case we resort to a combination of horizon culling, frustum culling, and LOD (we still leave the backface culling on, of course).
The culling is performed on the nodes of our geo-quadtree, which is what divides the planet into "regions", as you say. Regarding LOD: as I stated in the starting post, I think GeoMipMapping (see the link in the references section in the first post for a paper on GeoMipMapping) will probably be a good choice, whereas each patch of the mipmapped terrain is stored in a geo-quadtree node at some known level (the level at which the nodes are of the suitable size). For viewing the planet from high altitudes, a set of larger patches can be used, since the "regular" patches would be too small to remain useful. For viewing the planet from even higher altitudes (i.e. from orbit), a single mesh can be used with standard mesh LOD techniques. An imposter is sufficient for viewing the planet from a distance.

Ysaneya: what LOD scheme are you using?

A few words regarding the geo-quadtree:
If we're using an icosahedron as the starting primitive (and we should, as the demo clearly shows), then we'll have 20 faces to start with, rather than the 4 of the originally suggested tetrahedron. It is possible to break up the icosahedron into 4 sections, each of 5 faces, such that the 1st-level nodes of the geo-quadtree (the root being level 0) would have 5 child nodes (one for each of the original faces) rather than 4... But then considering that those 20 nodes are only a fraction of the nodes that we'll be processing, the added complexity does not seem to be worth the tiny speed-up. So I think that the root node of the geo-quadtree should just contain all the 20 nodes that make up the icosahedron.

Michael K.,
Co-designer and Graphics Programmer of "The Keepers"



We come in peace... surrender or die!

[edited by - technobot on April 6, 2003 7:22:21 AM]
Michael K.
Ysaneya
Ysaneya
I''m using a chunk-based LOD quadtree, but i slightly modified it to handle infinite zooms. There''s an overview of the basic technic here:

http://www.cix.co.uk/~glennc/gdcetalk_files/frame.htm

(See around slide 17, but i fixed the problem mentionned in slide 18).

Here''s 5 screenshots of what i have so far:

http://www.fl-tw.com/planet/zoom1.jpg (200 km)
http://www.fl-tw.com/planet/zoom2.jpg (100 km)
http://www.fl-tw.com/planet/zoom3.jpg (50 km)
http://www.fl-tw.com/planet/zoom4.jpg (10 km)
http://www.fl-tw.com/planet/zoom5.jpg (meter level)

Polycount is generally around 75k at the ground level. I''ll increase the details a bit when everything will be working well (still have to fix the cracks, then do the texture mapping).

Y.
Eelco
Eelco
i have been looking into lod techniques today a little, and as far as ive seen all these systems are based on heightmaps. assuming this is true for all algos that are usefull to us, we are going to need triangular heightmaps (jagged 2d arrays?). since they are 2d maps, i dont think its wise to use the original tris of the isocahdron, (i refer to those as continents), but first subdivide a few times (2-3) so you have a little more flat surfaces, (lands for example), and then do a lod geoquadtree thingy on each of the lands'' heightmaps of the lands that are not backfaceculled or frustrumculled. this works regardless of wheter youre standing on the planet, or 300000km above it.

i dont know how far this is the same as what you are saying, but whats the horizon culling good for? everything thats over the horizon will be excluded by the backfaceculling of the lands, and backfaceculling is a very fast test, only one dotproduct.. so why bother with horizonculling? or are you referring to the backfaceculling of lands as horizon culling?

anyway lets make something cool out of this!
Ysaneya
Ysaneya
Something you must realize: backface culling is done per-face, requires the geometry to be sent to the video card *and* transformed.

By doing horizon culling, you are culling a group of triangles on the CPU, and you don''t have to send them to the video card. This saves bandwidth and the triangles don''t have to be transformed.

Btw, some faces might be front-facing, but could still be horizon culled. Think about the front faces of a mountain that is behind the horizon.

Y.
Eelco
Eelco
yup, thats right, but doing a backfacecull on the cpu for the lands takes no time at all, just the dot product of the lands'' normal and the unit vector of the camera''s orientation.
and im aware of the fact lands are not perfectly flat, thus they could be backfaceculled while a mountain still peeks over the horizon. but for this it is only good you have to do the backfaceculling of the lands on the cpu, cos you can add a tolerance to the culling, so instead of: if (normal . camera)>0 then backfacecull, do: if (normal . camera)>theta then backfacecull.
this way youll also include lands that are actually slightly over the horizon (or a lot over the horizon, depending on theta)
Ysaneya
Ysaneya
quote:

but doing a backfacecull on the cpu for the lands takes no time at all



The backface culling operation is pretty light, but when you start playing in the 100'' thousands of triangles per frame, it''s globally no longer a light operation.

You also forget that you''ll have to stream the results with a dynamic VB or a dynamic IB. It''s no longer possible to store everything statically.

All in all, when you start considering these problems, backface culling on the CPU no longer gives any performance advantage, so it''s useless.

Y.
Eelco
Eelco
read more carefully

i said backfaceculling on the lands, not the triangles, where lands are defined as triangular terrains lying on the globe.
there will be only about at most a thousand of those, so thats not really a problem. all the lands that remain after backface- and frustrumculling (on the cpu) are then lodded and then sent to the gpu. so it will be in the gpu that the triangles themselves are actually backfaceculled. or so i had in mind. if there is a problem with that, or there are simply better methods, please enlighten me
technobot
technobot
quote:
Original post by Ysaneya
I'm using a chunk-based LOD quadtree, but i slightly modified it to handle infinite zooms. There's an overview of the basic technic here:

http://www.cix.co.uk/~glennc/gdcetalk_files/frame.htm

I like the screenshots, especially the 1st one.

What they describe in slides 17-24 (in particular slides 20-24) is very similar to GeoMipMapping, if not the same... The texturing system they describe in slides 31-35 is also rather interesting, but we'll get to texturing in one of the following threads... Slide 37 is especially relevant to us. It deals with the adaption of the system to a triangle mesh, or in our case - a triangular grid (or rather - tree).
What modifications did you make to handle infinite zooms?
quote:
Original post by Eelco
i have been looking into lod techniques today a little, and as far as ive seen all these systems are based on heightmaps. assuming this is true for all algos that are usefull to us, we are going to need triangular heightmaps (jagged 2d arrays?).

We don't need heightmaps at all - we can use the geo-quadtree directly.
quote:

i said backfaceculling on the lands, not the triangles, where lands are defined as triangular terrains lying on the globe.

Backface-culling the "lands", as you call them, is essentially the same as horizon culling. More on that below.

I've been thinking about some of the other issues the past day, and I've reached some conclusions:

  • Position Representation: cartesian coordinates in the standard (x,y,z) format seem perfectly suitable. They indeed have all three of the required properties: Continuity - they continuously cover all R3 space; Ease of finding angle - a simple dot product, divided by both vector lengths give the cosine of the angle between the two vectors; Ease for physics - either use directly or bias by the camera's position.
    Further, since horizon culling is performed on the geo-qudtree nodes, rather than individual objects, the angle requirement is far less critical for generic positions. Note that due to percision issues, the position vectors should be stored as doubles. If necessary, they can be biased to the camera position (i.e. object_pos = object_pos - camera_pos) during physics simulation and/or rendering, and the result is then small enough to be stored as singles with reasonable percission.

  • Geo-QuadTree Node Representation: other than all the pointers (children, neightbors, and parent) and whatever other data, each node would contain three normalized cartesian vectors (3 singles for each vector) and three altitude values (each stored as a double) - one vector and one altitude for each vertex. It would also store a half-angle (as a single), which will help as during horizon culling. These describe the node volume as shown in the image below.

  • Plane Representation: it seems the restrictions on our plane representation are not very useful, and may even do more harm than good, especially for frustum culling... I suggest we scrap that and just use the standard representation.





The bottom corner corresponds to the center of our planet. The red vectors are the 3 unit vectors that describe the direction of each of the top vertices. The three altitudes are the lengths of the corresponding edges (e.g the altitude that relates to the leftmost vertex is the length of the leftmost "vertical" edge), or in other words the distance of the vertices from the planet's center. The blue line is the center-vector-line of the node, and is colinear with the average of the three red unit-vectors. The blue angle is the half-angle that I mentioned earlier, and it happens to be the same between the center vector and each of the red vectors.

Now, here's an outline of how I imagine this whole thing to work:

We start of with our original 20 geo-quadtree nodes that make up the icosahedron. We spilt those a few times, to get some better resolution. We shouldn't split too much though, since we only need a minimum resolution at this stage. I think 4-5 splits or so will do. Once we've done that, each edge in our geo-quadtree is a few hundred kilometers long (from this point onwards I only refer to the edges that lie on the surface of the planet - the edges that go into its center are not interesting here), and we have a several thousand faces - or lands, if you will - that are arranged in a tree-like hierarchy. As we do these splits, we adjust the altitides of the vertices, to create our basic low-detail height data of the planet. The altitudes can be loaded from an external source (e.g. height data of the earth) or generated procidurally (we'll discuss data generation more in depth in the next thread). This data can be pre-generated, and saved to a file for later use.

After we've first generated/loaded the tree from the previous paragraph, and whenever the camera moves, we do the following steps:
1. Perform hierarchial horizon culling on the geo-quadtree to find the nodes that can be seen from our current viewpoint. This will discard most of the nodes.
2. Perform frustum culling on the remaining nodes. This will reduce the set even further. At ground level, we will never have more than 6 nodes left, and usually not more than one.
3. Subdivide the remaining nodes to a high-enough resolution, and generate geomipmap patches. Note that as we subdivide, we fustum cull each new node so that we won't do any unnecessary processing. We add height data as we go, again either from an extenal source or procedurally. Note that this step has a lot of room for optimization. For example, we'll probbaly have some geomipmap patches ready from before the camera moved, since it usually doesn't move very far.
4. For each visble geomipmap patch, determine the level of detail, and select the appropriate index buffer.

Performing the horizon culling:
After we've normalized the camera's position vector, for each node of the geo-quadtree, we do the following:
1. Add the three vertex vectors together, to get the center vector. It is not normalized at this stage, so we must divide it by some factor (the vector's length) to normalize it. Since we know our three vertex vectors are unit-vectors, we can pre-calculate this factor as a function of the half-angle, and store that in a LUT.
2. Once we've normalized the node's center vector, we calculate the dot-product between that vector and the camera's normalized position vector. This gives us the cosine of the angle between the camera and the center of the node.
3. We compare the value we got with the minimum value that we get from a 2D LUT as a function of the camera's altitude and the node's half-angle. I described the basic idea for calculating this LUT in the fisrt post - we just need to adjust that as a function of the half-angle, like so: cos(theta) = cos(arccos(R/h) + arccos(R/H) + half_angle), where h and half_angle are the indices into the LUT. Note that we can extract the camera's altitude while we normalize its position vector. Also note that it may be beneficial to merge the two look-up tables togther, for better cache friendliness. This is rather straight forward to do, considerring that they both have a mutual parameter - the half-angle.
4. If the value we calculated is lower than the value we got from the LUT, we ignore the node. Otherwise, we repeat the process for its children.

Btw, a few of formulas:

The length of each edge as a function of the number of subdivisions:
l = L/(5*2n)
l is the length of each edge, L is the circumference of the planet (i.e. the length of the equator), and n is the number of subdivisions.

The number of lands as a function of the number of subdivisions:
N = 20*4n
N is the number of lands, and n is the number of subdivisions.

It can also be derived that the number of lands as a function of the length of each edge is given by:
N = 4/5 * (L/l)2

EDIT: Another long post to start a new page...

Michael K.,
Co-designer and Graphics Programmer of "The Keepers"



We come in peace... surrender or die!

[edited by - technobot on April 7, 2003 10:02:48 AM]
Michael K.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.