|
Features

A
Real-Time Procedural Universe, Part Three: Matters of Scale
Problems of Scale:
Z-Buffer Precision
I've already explained how to expand your Z-Buffer's precision by scaling
planets down both by distance and by size. However, this won't solve all
your Z-Buffer problems. You'll find that in scaling large numbers down,
small changes in distance are lost. A moon that should be behind a planet
may be rendered in front of it, or vice versa. Even when you're close
to a planet, you can still have triangles break through the Z-Buffer because
the far clipping plane is to far away. Bringing it in farther just makes
those other problems worse.
Since you can't change the hardware in your video card, and since it's
unlikely that chipset designers will provide a 64-bit Z-Buffer, this is
a tough problem to solve. I have found that using impostor rendering makes
this problem much easier to manage. To create an impostor, you render
an object all by itself to the back buffer (or to a separate pixel buffer),
then copy (or bind) that object into a texture map. Then the object is
rendered as a single rectangle using the generated texture map. Because
most objects look different from different viewpoints, the texture map
must be updated as the camera moves around. In essence, an impostor is
just a billboard that is generated in real-time as needed.
At this point many of you will be wondering how this helps you with Z-Buffer
precision. The answer lies in the fact that you must use a special projection
matrix when rendering your impostor texture, and this projection matrix
has its own front and back clipping planes. This projection matrix creates
a view frustum that fits tightly around your object on all 6 sides, which
gives you the best Z-Buffer precision you can have for that object alone.
Once that texture map is generated for a planet, you really don't need
to worry about Z-Buffer precision. Because impostor texture maps are partially
transparent, you need to render them in reverse Z order. This means that
you can turn the Z-Buffer off completely when drawing the impostored planets.
Problems with Impostors
Impostors not only improve Z-Buffer precision for the objects being rendered
as impostors, they also offer great performance improvements. Instead
of rendering every planet in your scene every frame, you only need to
render two triangles per planet on most frames. Every now and then you
will have to update an impostor texture, but even then you will rarely
need to update more than one planet's impostor in any given frame, and
most frames won't need anything updated at all. Since you're not rendering
all those triangles, you also don't need to check their ROAM priorities
or update their triangle meshes.
Unfortunately, nothing comes without a price. There are a few problems
that can crop up when using impostors. The first problem is that differences
between the resolution of the impostor and the screen resolution can cause
aliasing artifacts. This can be minimized by choosing an appropriate texture
size based on the amount of view angle or screen space taken up by the
object. Changing the texture resolution for an object will cause a visual
shift that looks like the video card switching between mip-map levels.
Because you can control the resolution/size trade-off, this problem is
usually acceptable. However, this problem can become really bad when the
camera gets so close that the object's edges extend beyond the edges of
the screen.
Impostors can also cause problems related to the Z-Buffer. Because you're
taking a 3D object and rendering it as a 2D rectangle, you are changing
the Z-Buffer values that the object would normally generate. Worse yet,
you are changing the Z-Buffer values for the entire rectangle, including
the transparent portions of it. This can cause some really bad problems
when an impostor gets too close to other objects. The rectangle can end
up hiding objects that should be visible. It can even chop objects in
half that lie in the rectangle's plane.
Luckily, these problems aren't too bad when dealing with planets. Inter-planetary
distances are so large that we really only have to worry about these problems
when the camera gets close to a planet. Even then we don't have to worry
about objects being drawn on the surface of the planet, or in the planet's
atmosphere, as these can all be rendered directly into the impostor if
necessary. Still, at some point using the impostor will become more trouble
than it's worth. The easiest way to deal with this is to switch from impostor
rendering to normal rendering when the camera gets within a certain distance
of the planet. In my demo I switch to normal rendering when a planet takes
up 90 degrees or more of the field of view.
I have one last thing to mention about impostors. They are also used for
rendering clouds, forests, cities, and several other large-scale details
that you might want to render on a planet. But care must be taken in how
you manage them, or you will quickly find yourself out of video memory.
In my demo, I choose impostor resolutions from 512x512 all the way down
to 8x8 based on the planet's distance to the camera. If I start to use
impostors more extensively, I will need to create a texture cache for
them.
______________________________________________________
|