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

Efficient Terrain Rendering

Started by Maddibob Nov 16, 2004 at 7:00 AM 7 replies 900+ views
Original Post
Maddibob
Maddibob
My level editor allows you to construct terrains of any size from any heightmap. For rendering, I also allow selection of 2 textures and a lightmap to modulate the two together, so you can have say grass and rock smoothly interchanged over the terrain. My usual terrain test size is 64 x 64 square polygons (2 tris) over which is stretched a 512 x 512 256 colour heightmap. The terrain is rendered using a standard octree and polygon drawing maxes at around 2000 per frame (out of 4096). I'm batching each Octree node into one draw-pass. Each vertex has 3 texture coordinates, one for the lightmap, one for the grass and one for the rock. This allows me to adjust the resolution of the grass, rock or lightmap giving some nice effects. I'm using 5 texture passes to achieve this and I'm getting some fairly good frame rates (with a fairly decent 256meg video card). My question is whether this is in fact the correct way to do it? I've seen and heard of people using shaders to get the same effect with greater frame rates, and also the ability to use 3 textures modulated together using the RGB of a map which I'd much prefer if I can do it within the same frame time I currently have. Does anyone know if it is worth my time pursuing this different approach, or am I not going to gain much in the way of fps? At present, on my 1800mhz athlon with a 6800 geforce pro (I think, can't remember the card name!), I get 130fps using any size terrain at a fairly good 'ground resolution'. This is obviously going to go down drastically with the addition of everything else (animations, movement, transformations of other objects, etc). Would appreciate an expert opinion on whether you can use shaders for what I've described, and if so, is it a lot faster? Will post pictures later today.... Thanks
Lutz
Lutz
Sorry, last post was me.
janos
janos
reduce the number of draw calls.
on our terrain engine, we reach 80fps with a 0.6 M polys on screen with up to 16 (arbitrarily fixed limitation) materials on the terrain per grid part (avg 3~4), with more than 100 materials on the full terrain. (with shaders etc...)
fps increases a lot if you only see part of the terrain of course.
Act of War - EugenSystems/Atari
janos
janos
to add to what lutz said :
on a modern CPU + graphics board, the limitations are:
75000 batches per second (ideal case)
20M dynamic tris per second (ideal case)
100M static (VBO) triangles per second
around 1 GPixels with shaders with less than 20 instructions

your app will only be as fast as the constraint on which you bump first.

I guess it's batch count in your case. use VBOs (static vb and IB) if possible, and if not, figure out a way, otherwise you will never get very good performance. you could try using large VB to allow to regroup calls. do not render as you traverse the octree; just record what you have to render, then sort per shader/resource, regroup batches that can be regrouped, then render.
Act of War - EugenSystems/Atari
Maddibob
Maddibob
Thanks

Sorry, I got it wrong, my card is a geforce 5700 256mb oc. I'm also using DX with C++.

With reference to the vertex buffer objects, are you talking about holding the entire terrain and lanscape detail objects in a vertex buffer and using that to draw each octree chunk? I did try that and didn't get any performance increase at all. I guess maybe I could revisit the code (as I still have it) and see if I've missed something.

I've just read Janos' reply and noticed that I _am_ rendering each octree node when it's in view, so maybe that's where I'm going wrong. Would you suggest that I hold the entire vertex set in a buffer and hold the indices in the octree nodes? That way, as I traverse and hit a visible node, I can just add that node's indices to the overall indices.

Thanks for all your replies.
janos
janos
imagine you have an infinite VB and an infinite IB (it's not the case in reality, so we'll have to adapt, but first things first)

Know that you can render part of an IB using that start and count parameters.

Now imagine each node references a start and a count in the IB, and
that you have listed nodes A,B,C,F,I to be rendered

where
A : index 0 to 10
B : 11 to 37
C : 38 to 43
F : 55 to 68
I : 73 to 103

then what you need is really to render
index
0 to 43
55 to 68
73 to 103
that's 3 batches

in real life, it will drastically reduce batch count

you can even decide to render useless triangles if it reduces batch count. in the previous example, that would mean rendering nodes D and E because they do not have many triangles so you would have
0 to 68
and 73 to 103

Act of War - EugenSystems/Atari
Maddibob
Maddibob
Great replies, thanks guys, that's exactly what I needed. I have one further question though that is loosely related. If my static landscape uses 3 texture coordinates per vertex, can I use the same vertex structure for vertices that only have 1 texture coordinate say, for instance, dynamic objects that only have one texture pass.

I'm using SetVertexShader and supplying the 1 or 3 texture #define depending on whether I'm drawing 3-texture-objects or 1-texture-objects and it works fine, but am I sending 2 lots of redundant empty texture coordinates to the card when only drawing 1 texture?

I suppose what I'm asking is, do you have a 1 texture coordinate vertex structure _and_ a 3 texture coordinate vertex structure or can you just use the one with 3 texture coordinates for all types of objects?

Thanks
janos
janos
I guess the only way to know is to benchmark
Act of War - EugenSystems/Atari

Topic Locked

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

Sign in to reply to this topic.