Not logged in, Join Here! or Log In Below:  
News Articles Search    

Submitted by Charlie Van Noland, posted on March 30, 2002

Image Description, by Charlie Van Noland

These are some shots of two ROAM tech-demos I have been working on. I am doing a full-blown investigation on drawing terrain as fast as possible with a high enough level of detail to bring it up to par with current terrain-based games out there.

The top two screenshots are of my more advanced ROAM implementation. It features partial geomorphing where the addition of detail is a gradual change in the shape of the terrain, as opposed to a sudden pop. The reason it is 'partial' geomorphing is because it only morphs when detail is added, not when detail is removed.

I have to keep track of which triangles were force-split by their neighbors so I can unmorph them before unsplitting the culprit triangle.

That implementation also textures the mesh with a 512x512 'colormap' and a 512x512 detail texture. The colormap is basically a huge texture being stretched over the entire mesh. This yields blurry coloring onto the terrain. You can distinguish rock, dirt, grass, etc from eachother but it is extremely blurry. So I tile the detail texture over the entire terrain. I am not using multitexturing at the moment, so I am doing two passes. If I were using multitexturing the polycount would be cut in half and FPS would go up.

The bottom two screenshots are my second implementation of ROAM. Actually, I just took the first one, before I added geomorphing to it, and changed how the texturing worked..

Instead of stretching a texture over the entire terrain, I created rock, grass, and dirt textures. Using a bitmap consisting of red, white and green I drew out where rock grass and dirt are on the terrain.

This yields a higher texture detail, but less variety in the terrain. I am again not using multitexturing so the polycount could easily be a third of what it is on these screenshots.

I am thinking about sticking with the color map and detail texture because almost all cards support up to two textures per pass with multitexturing.

My other option is to make a huge texture (2048x2048) and chop it into 512x512 textures that are put together like a puzzle onto the mesh.

As you can see, I stuck a lens flare in my second tech demo. This isn't a finalized flare or anything. I just was toying with gluProject. I tried to do a sort of complex-corona on the sun. The corona is blended with a texture of a white spot and the center is at 0 alpha. The corona is a triangle fan, with ten 'slices'. Each slice is 36 degrees. Then I use glReadPixels to check and see if the z-buffer has anything at the tip of each slice on the edge of the actual sun. If there is something there, that slice is given an alpha of 0, so that part of the corona is blocked...

This was used in the xbox hit HALO, I just copied it.

For some reason the lens flare is really slow. I think gluProject has some performance issues, or maybe it's just my video card.

These demos actually have a purpose. I am investigating ROAM for a project I am working on with some friends. It's an online FPS similar to Tribes, except we are going to take out the 'cardboard' feel (as I like to call it) and try to make it more realistic feeling. Tribes just had a weird washed-out feeling to me. Maybe it was their fog or simple structural architecture. Whatever it was, we are avoiding it.

Both demos light the terrain using 'slope-lighting', which I wrote an article about and you can find it on

I posted a full-size version of this IOTD at I apologize for the bad quality. I was trying to keep the 2048x1536 at a reasonable size..

If you have any questions/suggestions just drop me a mail, Or leave some comments. Thx! :D

Image of the Day Gallery


Message Center / Reader Comments: ( To Participate in the Discussion, Join the Community )
Archive Notice: This thread is old and no longer active. It is here for reference purposes. This thread was created on an older version of the flipcode forums, before the site closed in 2005. Please keep that in mind as you view this thread, as many of the topics and opinions may be outdated.

March 30, 2002, 04:01 PM

Excellent job.


March 30, 2002, 04:10 PM

Wow ... Looks very cool but ... Something looks strange with the lights in the left bottom screenshot ...

But it's still very impressive !!! Congratulations


March 30, 2002, 04:14 PM

i'm 99% confident your lensflare is slow because of gluReadPixels.


March 30, 2002, 04:22 PM

A raycast should be faster than reading from the Z-buffer for the flare.

Anyway looks neat. Slope lighting isn't new though, there was an IOTD by a 15 year old about half a year back with that trick/hack too.


March 30, 2002, 04:37 PM

slope lighting is embross bumpmapping..
readpixels is fuckin slow

it looks cool..

how about implementing a voxel-engine with triangle-strips? i've seen this one time in a voxtut on flipcode, could be quite fast with todays gpu's.. and would always have perfect lod..


March 30, 2002, 05:45 PM

heh.. don't read the zbuffer, you don't wanna do that. calculating line of sight to the sun geometrically is much faster.



March 30, 2002, 06:22 PM

Don't bother with ROAM. Brute force (with crude lod & pvs) is faster with todays gpu's.


March 30, 2002, 06:24 PM

Are you sure coronas work that way?

I thought the corona effect was in the camera lens, and is always completely intact radially, just its intensity varies.

Last time I did a lensflare, I simply checked if the sun center was off screen, if it was, then I determined by how much, and derived intensity from that.

It wasn't a corona per se, just a lensflare (collection of transparent spheres/halos arranged on a line swinging around screencenter), but I believe the same idea holds true for coronas.

Unless you figure that the corona effect is at the source? Now if you were talking a sun's "corona", that would be true!

But not the effect that the sun or lights in a scene cause due to internal lens effects.

Just one readpixel!



March 30, 2002, 06:58 PM

The Problem with Readpixel is that it stalls the Pipeline of the GPU and it is generally a no-no to read something from Video RAM.
The X-Box has a unified memory architekture and I bet that the processor has direct access to the VRAM, so there it may not be slow.
For a PC-Game it is way better to do a simple raycast.

Vander Nunes

March 30, 2002, 07:41 PM

I am particularly interested on the topic of ZBuffer reading, because I did it within my last project.

I chose to do that even knowing about the Pipeline stall, because the benefits are great, like, it is possible to do pretty realistic behaviour (ex: the sun passing behind a complex of clouds, the flares can blink, change intensity, etc). Doing that using ray intersections would be a real pain, afaik. Of course, I am not considering latest hardware like geForce3/4, they aren't the today's reality imho.

I think that above 60fps no one can see any difference in an application, like, I can't see any difference when an app is running at 60fps or 598fps. =)

OK, there are the other aspects of the engine, but I'm saying 60|598fps with ALL planned features implemented.

Vander Nunes

March 30, 2002, 07:50 PM

Nice IOTD, btw. =)

Sebastian Sylvan

March 30, 2002, 09:17 PM

Slope lighting has one major drawback: no shadows. You might as well calculate lighting and shadowing with a better approach (more realistic). There are many ways to do this, try google. If you don't want to modify your landscape or lights in realtime that is.

I too believe that ROAM is dead.

Using many different source textures (like 16-32 or something) and splatting them over the terrain is probably your best bet for texturing. Of course you could keep a limit of 8 per patch or something like that so you could keep the number of alpha textures down. You'll get much better quality (the source textures can be pretty hi-res) and it's pretty cheap on modern hardware.


March 30, 2002, 09:33 PM

yeah, the brain updates the image about 25-30 times per second, so the nyquist frequency is what, 50-60? doesn't really matter above that.
however, as for the ray intersections - for clouds it's practically the same thing, except you're looking up the texture instead of looking up the zbuffer. calculate the intersection point of the ray with the skybox/sphere/plane/whatever, parametrize it, check the texel at that coordinate. literally hundreds of times faster. as for line of sight through geometry.. as long as you have any sort of hierarchical representation of your world, that's trivial, and if you want to do anything with your engine, you'll need LOS anyway for AI.


Division By Zero

March 30, 2002, 09:41 PM



March 30, 2002, 09:58 PM


zed zeek

March 30, 2002, 11:17 PM

contrary to what everyone else has posted
doing a glReadPixels(..) of one pixel should not decrease fps by more than 0.01% on any half decent card.
perhaps youre/theyre not calling it in the right place?

Ben Woodhouse

March 31, 2002, 12:03 AM

glReadPixels was very slow on my TNT. It would take about a second to read a 640x480x32 frame into a buffer. I haven't tried it on my geforce 2, but I suspect it would still be slow unless nvidia have updated that part of the driver since.

Ben Humphrey

March 31, 2002, 02:54 AM

ONE read of the pixels would not slow down the application, of course it would be slow for a full screen grab :) SWEET terrain and effects V!

Jari Komppa

March 31, 2002, 04:15 AM

Checking for obstacles by reading zbuffer is not too wise, considering that different cards have different internal zbuffer formats. I did flare check like that in 'traumatique', a demo of mine, and the z buffer values were completely different on tnt, voodoo2 and voodoo3.

Johannes Böhm

March 31, 2002, 04:25 AM

yep. that was him actually.


March 31, 2002, 04:40 AM

What is the "coherence" value on the screenshots ?

Why don't you combine your two implementations : Use a colormap with detail texture, but blend over the grass, rock, etc. textures ?

BTW, nice work ! ;)


March 31, 2002, 05:20 AM

Reading the framebuffer stalls the entire pipeline, so yes. it is slow, no matter how little you're reading.

Matt Newport

March 31, 2002, 09:30 AM

A better way of achieving the kind of lens flare effects you're talking about (changing intensity when it goes behind clouds etc.) is described in Games Programming Gems II. Basically what you do is use render-to-texture functionality to render a small (16x16) texture with the camera pointing directly at the sun and with the projection matrix set so the sun fills the texture. Then you render the sun in white and render the rest of your geometry in black. You then render each texel of your 16x16 texture additively into a 1x1 texture so you end up with a 1x1 texture who's brightness is proportional to the amount of sun visible. You use this value to modulate the brightness of your flares. This way you don't stall the pipeline of the graphics card by reading back from the z buffer.



March 31, 2002, 09:38 AM

Is this slope lighting done per texel or per vertex?


March 31, 2002, 10:06 AM

You don't get it. ONE read WILL slow down your application, because of the pipeline stall!!!
No matter if you read one or 1000 pixels, the result is a major slowdown.

Sebastian Sylvan

March 31, 2002, 11:04 AM

You can use the extension NV_occlusion_query to find out how many pixels of an object were visible. This is pretty fast since it happens asyncronously. So basically you can render an object and retrive the result later on when you need it (no stalling waiting for the result). So basically you render the lightsource (the sun) and then you query for it NEXT frame. So you use the % of visible pixels from the previous frame to determine the size of the flare on the sun. This is so you can be sure that the query computation is indeed done (it's better to proceed to setting up the next frame and querying it when you need it next time instead of waiting for the query and doing nothing).

I haven't tried this but it should work. Check out the developer site at nvidia, they have some examples on using that extension.


March 31, 2002, 11:35 AM

I don't know that much about how badly reading the zbuffer affects performance... but I just wanted to make sure you people know whats involved in raycasting? It isn't trivial. If you want to raycast, you have to do something like

1) test both triangles in current terrain-cell for collisions
2) test all the walls for exit point of ray
3) move one cell in that direction.
4) goto 1

If the terrain is 1024x1024 you have to do this loop on average around 500 times each frame. I can post code from my terrain renderer if you want, its pretty complicated and long to check for all the possible odd conditions.

I remain unconvinced that reading the zbuffer is slower than raycasting, I think I need to see some more concrete proof or statistics. I know reading the zbuffer stalls the pipeline, but raycasting is pretty darn expensive too!


March 31, 2002, 12:16 PM

but you can raycast while rendering the whole landscape. then its completely paralellized.. and this means you use your time 2 times..

else you simply wait till your landscape is drawn, read back your pixels, and continue drawing then..

no i havent tested it and yes go for occlusion-query..

other way:
draw your sun with depthtest into some other buffer, and blurr this buffer with help of mipmapping.. then additive blend this downsamples over your screen.. really good glow.. ati has some demo of it

but go for occlusion-query or raycasting.. and i think you can do the raycasting quite fast if you have a quadtree..

but i dislike terrain-engines anyways.. for me a terrain is a mesh. and i draw meshes. final point;)


March 31, 2002, 02:54 PM

With octrees raycasting on terrain is pretty quick


March 31, 2002, 07:17 PM

Stretched texture + detail is how Dark Age of Camelot does it. It works, but it's not state of the art.

Look into "texture splatting" and "unique texturing" for alternate methods. Also, on cards with 4 or more texture stages, combining of 3 different tiling terrain textures can be done in hardware in one pass using a fourth "channel weight" texture.

GeForce 3/4 (and possibly others) have occlusion query capability; you render some primitive and can later check how many pixels actually passed the depth test. You can also use render-to-texture to get coronas without stalling the pipeline.

This thread contains 31 messages.
First Previous ( To view more messages, select a page: 0 1 ... out of 1) Next Last
Hosting by Solid Eight Studios, maker of PhotoTangler Collage Maker.