Tuesday, January 20, 2009

Using far-clipping, part 1

Why using far-clipping

Far-clipping is commonly used in every game that take place outdoor. Most of time, grass geometry are clipped (meaning not rendered) every time it is too far away from the camera's point of view.
This is used for performance issue, cause your CPU doesn't have to send this geometry to your video card, and your video card don't have to render them.

Far-clipping can be used in place where fails the famous Q3's Potential Visibility Set (known as PVS, computed by q3map2 at VIS stage). The PVS is very efficient indoor, for game just like Q3, with map that consist of rooms and corridors. Far-clipping is efficient outdoor, for big landscape, allowing nice details close to the camera, while skipping those that are too far away. It can be used too if you have some detailed objects inside a house that can't be skipped using the VIS-stage because your house has too many windows, or this object stand in front of one of them... so specifying a clipping distance allow you to remove it from the render scene, if farther than the clipping distance, only few pixels of this object remain visible.

Well, I'm sure most of you are thinking "wait a minute, I have never seen far-clipping in Q3 engine", and you are right... But I have just coded this for Smokin' Guns. And that will be available with the next release! (if you can't wait, just compile your own qvm from smokinguns.sourceforge.net)

Basic tutorial of far-clipping

Open your favorite testbox map with Radiant.
Create some brushes, add some textures to them.
Create an origin brush (a brush with the texture: common/origin). This origin brush is _very_ important, cause this will be the reference for computing distance to the camera.
Select all your newly created brushes and the origin brush, and turn them into a func_static (right-click, choose func->func_static in the menu entry).

Now open the entity window (hit the 'n' key). Add a new key for this entity: "farclip". Enter a value for this key: "sphere 800" (and hit 'return'). You should have something that looks like that:

Compile your map as you usually do, launch the game, and look at your func_static entity: every time you get close to it, it appears, every time you move far away from it, it disappears...

Setting farclip to "sphere 800" means that your func_static is magically clipped every time you are farther than 800 game units (same unit used by Radiant) from it.

Here what you get in-game:

You may want your func_static to cast shadows (unlike those screenshots), just open the entity window, and add the key "_cs" (or "_castshadows", it is the same) with a value of 1.

If you want a cubic clipping, change the value of the farclip key to "cube 800".
Here is the clipping frontier you get:

How to use far-clipping with a model

For instance only func_static support far-clipping. If you want to attach a model as func_static, you have 2 ways of doing it. First you specify this model in a "model2" key you add to a func_static entity, but this is weird cause you can't adjust anything with that.
The second way I discovered recently just consists to target your func_static. It is easy, just deselect all, select your model, select a brush which is part of the func_static, and hit Ctrl-K: an arrow will be displayed from your model to the func_static entity. If you open the entity window, you will see that your func_static has now a key named "targetname" with the same value that you will found in your model's entity window under the "target" key. Repeat this for all models you want to be part of the func_static entity (don't forget to deselect all by pressing the escape key before starting to include the next model).

Note that including one or more models to an entity works for most of entity type (including for example SG's specific entity like func_door_rotating).

Now if you want that your models cast shadows, don't forget to add "_cs" key with a value of 1 to your func_static entity!!! If you don't do that, even if you specify _cs=1 in your model pseudo-entity window, it will not work.

Here screenshots of the entity window for the func_static (left) and for the model window (right):

Here what you get in-game:

Of course, those example look stupid, but here an example where far-clipping is usefull, in the big house of Alamo, there is a lot of object that have many polys:

From these point of view they are really small, but still have the same amount of tris:

And this can't be helped by hintbrushing... because there are too many windows, not enough VIS-blocker wall...
So in the next release of Alamo, all this stuff will be clipped if you are too far away.

Important note about the origin brush!

Q3 engine assume for all entities that their bounding box are symetric along all axis!
So when you are about positionning the origin brush, move it exactly at the center of your entity, in the middle of both brushes and models that target your func_static.
If you don't do that, your entity's bounding box will be extended to get this axial symetry.
During the VIS-processing, if any part of the bounding box is visible from a cluster, all your entity will be visible too from this cluster even if there is no part of the geometry that is actually visible, but just the bounding box.

About Cvar that controle far-clipping

You can controle far-clipping in-game with three Cvar:
  • cg_farclip to enable/disable far-clipping (default value is 1, enable), useful if you don't mind far-clipping because you have a powerful computer, or for various reason (if you want to compare what you gain with far-clipping, if you want to record a nice video, etc).
  • cg_farclipValue will multiply all distances by this value (default is 1, can't be lesser than 1), if you want that clipping occurs twice farther, set it to 2.
  • cg_farclipZoomValue: the same for the sharp rifle zoom mode (default is 3, can't be lesser than 1), it is usefull to have a different value, otherwise you will be able to notice those missing brushes while zooming.

That's all for today, see you soon for the advanced far-clipping tutorial!

1 comment: