Z-buffer and the clip planes-- help me understand them

Started by
9 comments, last by Hawkblood 10 years, 2 months ago
I have a complex render engine that requires the rendering of objects that are spaced apart on the order of magnitude of an entire solar system. If I was rendering just planets and moons, this would be relatively simple, but I have ships and space stations that can be anywhere. Currently I am rendering in stages from far-to-near order, clearing the z-buffer (almost) each stage and changing the near and far clip planes. I’m not clearing the z-buffer each object, just each range chunk.

This is working fine, but this reduces the effectiveness of depth optimization. I tried going in the other direction and not clearing the z-buffer, but it doesn’t work.

The question is: How does the z-buffer work? I have read some technical articles on this, but I don’t understand them. How do the near and far clip planes affect the z-buffer?
Advertisement

The Z buffer records depth in screen-space (normalized floats [0..1], where 0 is equivalent to the near and 1 to the far plane).

As such it will not work if you change your clipping planes as you go along.

So if I render an object with 0.0 as near and 1000.0 as far and it sets z-buff[0,0] to 0.5 (meaning the pixil is at 500.0 depth), then any attempts to render another pixil at +500.0 will fail…. So if I change the clip planes to 500Near and 1500Far and try to render an object at, say 1100.0 then it should still fail, but a render at 999.0 should pass?

The depth axis isn't linear like that (it prioritizes so you get higher resolution near the near plane and less further away towards the far plane), but if your range is 1000.0, your starting point 0.0 and you attempt to draw something at 1000.0 it will be (partially, the parts that lie inside the view frustum will be rendered) clipped.

Your second example is wrong though; if your near plane is at 500, far at 1500, and the object at 1100 (in world space then) it should end up between the planes and not be clipped. The range is between the planes, not from the point of origin.

Ok. Not being linear is not a problem. Is there a correlating relationship between z-depths when the difference between near and far are the same; i.e. 0-100 &500-1500 (both having a difference of 1000)?


Basically, I want to be able to render objects right near the camera and objects at distances of 100Mkm+ without z-fighting. I have already done this by rendering far-to-near, but as I said before, this negates the z-depth optimization….

What is the smallest unit you need to be able to discern between?

If your Z buffer uses 32-bit floats, it has limited precision and if by 100 000 000 000 meters you mean a billion space units too that just won't work out well.

I would recommend finding the smallest size that you need (maybe some asteroid of 10 km or something?) and then divide all your units by that; it should help a good deal and might just be enough that you can pull it off in a single normal pass.

Otherwise you can just sort them by distance (if that is possible, ie. no overlapping objects) and draw them in that order, never minding the Z buffer. Of course you will have to essentially draw everything then since there will be no sense to a depth test if you draw everything from back to front. It depends on your application which approach is best I guess, but that would be my first two approaches to look into.

I've already figured out how to extend it. I created a vector structure with __int64 and float. It works well for a coordinate system. I sort all the objects by distance and find the relative vector to the camera (stored in a float vector). I can't have an infinite (or even very large) far clip plane, so the objects that are REALLY FAR, like distant planets, are scaled using a formula and placed just before the FCP. All the near objects are rendered normally, but still in far-to-near order. I break up the distances several times, changing the far and near best suited for those distances and clear the z-buffer. This works well, but I was hoping to get some optimization by not having to do that.

The game is in real units of 1unit==1meter. I don't have any "zones" except the solar system.

Another option to consider for a far-flung space game with a lot of depth may be a w-buffer instead of a z-buffer. This article is one of the first Google hits that provides a pretty good explanation.

Any time you start getting objects that are "really far" you might instead consider just rendering them to a texture similar to a skybox. Few things will be visible at very large distances, and often when they are visible (like a nearby star) a skybox is more than enough. Something in the "really far" distance is unlikely to visibly change during a scene, but based on your numbers it still might change occasionally. Even if it does need an update every few minutes, it can conserve a lot of processing power to render it once per minute rather than every frame.
Thanks. That is the best explanation of the z-buffer I have seen. As far as using W-buffer, I am concerned about video cards that don’t support RHW clipping. As this is new to me, it may be that this info is out of date, and that all modern cards support it.

The objects that will be visible at great distances will be the local star and relatively nearby planets. The idea of making that into a skybox is not so good because of the way the player can travel in the solar system. Most ships will have a near-light-speed drive (NLS) which makes travel between planets within a star system trivial (and fast). So the amount of change the star and planets relative to the player can be great and quick. Nearby stars (that are visible) are represented using billboards. The number of “visible” stars isn’t that many, so this is not a problem. Even so I could make a skybox for those….

The game is in real units of 1unit==1meter. I don't have any "zones" except the solar system.

The objects that will be visible at great distances will be the local star and relatively nearby planets.

In that case expect all kinds of nasty evil problems. Your scales are not compatible.

Because you say you are relying on traditional rendering systems you will need to ultimately use floating point math. That means you normally get six decimal digits of precision. When you do operations that involve different scales the small numbers are promoted up to the big numbers.

A star is anywhere from 1,000,000,000 to 500,000,000 meters in radius, double for diameter. Our sun is about 1,391,000,000 meters in diameter (thanks Google). So with six digits, you have 1.39100e9.

The radius of the Earth is 6,378,100 meters in radius, or once promoted to the same scale, 0.012275e9

And of course your space ship is probably around 100 meters, or promoted to the same scale, 0.00000e.

Uh-oh.

When you are operating at the scale of stars and planets a spaceship will either cease to exist (actually round to zero) or be the same size as a numeric rounding error.

This isn't to say you cannot have a world at those scales. That type of thing has been done in advanced numeric simulations. It certainly can be done, but the math involved is quite involved and will require you to essentially rewrite the entire rules for rendering in your own notation and then transform your custom rendering system to something compatible to graphics hardware.

You can write it, but you won't spend your time actually making a game.

Most ships will have a near-light-speed drive (NLS) which makes travel between planets within a star system trivial (and fast).

Either you don't understand the distances involved, or your concept of "trivial and fast" as it applies to games is very different than mine.

The travel time from Earth to Sun is just over eight minutes. You could complete a speed run of the entire Super Mario Bros during that time, with enough time left over to fix yourself a sandwich before entering orbit.

The maximum travel time from Earth to Mars is about 25 minutes when we are at opposite ends of the sun. You could complete a speed run of Zelda: Ocarina of Time while you wait to travel.

Or perhaps Earth to Pluto, which can reach 7 hours. You could watch the original star wars trilogy as you travel. Or you could play through all of Portal 1 and Portal 2 as you travel between the two planets.

If you need to travel between two distant planets, such as Pluto and Eris (Eris is the planet that helped Pluto get reclassified as a dwarf planet), you might have a journey of 20 hours. I wouldn't call that "trivial and fast" unless your game is designed around one brief play session every day.

While many games involve interplanetary and interstellar travel, and a few of those games have scripts that hint at things like traveling near light speed, the games internally do not have anything even remotely resembling accurate scales.

This topic is closed to new replies.

Advertisement