Terrain Rendering

Started by
17 comments, last by amnesiasoft 17 years, 9 months ago
I've just finished my first terrain renderer! A terrain made of 65536 vertices! In the screenshot you can see a terrain made of 65536 vertices! (And yes, I know I used a ridiculously-looking heightmap.) However, I get 20 FPS max. when I run it, so it's time to start optimizing and I was hoping you people could give me some tips. I have three questions for now: 1. I heard that rendering using triangle strips could improve performance. How is it done? 2. I've read the VBO tutorial on NeHe's site. At the end of the tutorial, the author also mentions rendering using triangle strips, but then says it's beyond the scope of the tutorial. So how do I render the terrain using triangle strips with VBOs? 3. In my renderer, every vertex corresponds to one pixel, so insted of using texturemaps I just set the vertex colors to the corresponding pixel colors. Is that faster than using a texturemap? I thought it obviously is, but just to make sure. Thanks in advance, Mr. Big [EDIT] Wait a second, changing the color per vertex means calling glColor3ub 260,100 times. On the other hand, using texturemaps requires 260,100 glTexCoord2f calls. But then, texture coordinates can be stored in a buffer using VBOs... What about per-vertex colors, can the same be done with them? Would using vertex colors be faster then? I'm confused...
Advertisement
If you are using immediate mode to render your terrain, you will get a huge boost by switching to compiled vertex arrrays or VBOs. I haven't used OpenGL in a long time so I don't remember the details. It's not clear which is faster -- an indexed triangle strip vs. an indexed triangle list. So, try an indexed triangle list first because it easier to implement. Using textures is necessary for a good-looking terrain.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
There are lots of tristrip tutorials on the Net.

1&2. Basically, the first 3 vertices define the first triangle, the fourth vertex define the triangle with the second and the third, and so on. You can easily build a whole terrain like this, row by row. Doesn't differ much from GL_TRIANGLES.
Then just call the vertex pointer with GL_TRIANGLE_STRIP parameter.

Tristrips are faster because you need only one vertex for each new triangle, instead of 3 vertices for GL_TRIANGLES

The one thing you need to know is how to connect the rows.
After the last vertex of a current row (V(n,n)), add vertices (V(n,n), V(n+1,0) ) to your tristrip buffer, and then normally continue with adding the next row vertices. V(n+1,0) is a first vertex in the next row.

This would cause the rows to connect with two invisible triangles, without breaking the strip. Those triangles (V(n,n-1),V(n,n),V(n,n) and (V(n,n), V(n,n), V(n+1,0) are called "degenerated triangles"

3. Put a vertex color inside the vertex buffer too, so you don't have to change glColor each time. Then call it with glColorPointer.

You should definitely switch to the VBO approach. Sending that many vertices down per frame is almost certainly your bottleneck.

Using vertex colors, as you're doing, is probably faster than texturing for the number of triangles that you have, but you might get better performance if you used a texture and created fewer triangles (say, one per 4 pixel block).


On modern graphics hardware (ATI at least), strip-ordered triangle lists are just as fast as using the actual strips, because the post transform cache is large enough. I would assume that you'd see a similar thing on Nvidia chips, but I'm not certain. What really matters is not the fact that you're using strips, but the fact that you're drawing triangles in an efficient order. Stripification can give you an efficient rendering order as long as your strips are long enough.

This is assuming you're using VBOs. If you use immediate mode then strips will be faster because you'd have fewer glXXXX() calls, but IMO you should switch to VBOs because they will be faster still.



JB
Joshua Barczak3D Application Research GroupAMD
In a real game you probably won't find that you need to render your entire landscape every frame, as the "from outer space" view you've shown here would be very rare.

So normally you'd have a frustum which didn't encompass the entire landscape. If you were in the centre, the first optimisation would be to only draw parts of the landscape in front of the camera. That would immediately cut the number of polys in half anyway.

Then of course you could do better frustum culling, then have a LoD system as well so that further away parts get rendered in lower quality (this is not particularly straightforward, but an OpenGL book I have "OpenGL Superbible" contains a detailed explanation of it).

---

So yes - by all means use the above methods to get verts into the GPU more efficiently. But the most efficient way of saving time is to render less stuff.

Mark
Quote:Original post by mrbig
I have three questions for now:

Fell for all the wrong ideas

Quote:
1. I heard that rendering using triangle strips could improve performance. How is it done?


This is by far the last thing you should try, because a) a triangle list sorted for cache efficiency will be just as good and b) it's not even likely that supplying vertices is the part of the pipeline that's slowing you down. It's like a factory. Whipping that fast guy to work even faster is useless, if that gonzo two places away takes all day to get his screws in.

Quote:
2. I've read the VBO tutorial on NeHe's site. At the end of the tutorial, the author also mentions rendering using triangle strips, but then says it's beyond the scope of the tutorial. So how do I render the terrain using triangle strips with VBOs?


Worry about how to use VBOs and absolutely forget about triangle strips for now. If you tried everything else and you are really SURE that vertex submission is the bottle neck, THEN you can worry about strips.

Quote:
3. In my renderer, every vertex corresponds to one pixel,


That's hard to imagine unless you are using parallel projection or your terrain is absolutely flat and you're looking straight down at it (and in that case, yes, it would be completely dumb to draw a gazillion vertices instead of a textured quad).
Apart from that, vertex colors will be fine, but unless you're aiming for a terrain renderer where you never actually get close to the terrain the simple reason to use texture maps would be the utter lack of detail with only vertex colors.

Without even knowing what you want to use the terrain for, it is pretty impossible to give useful advice, but generally you should cover all the basic "optimizations" before you even worry about strips or whether vertex colors might be .1% faster or slower than a texture. What about culling? And is there even any use for culling or do you plan to always have the whole terrain visible anyway? And in that case: how large do you plan to make it?

How are you drawing it now? The fact that you talk about glColor and glTexCoord calls somehow suggests you are the using the most basic, but also most awefully slow and inefficient hand feeding (ie. immediate mode) and should switch to vertex arrays in the very least (VBO would be better, but if it's too much for you, do vertex arrays first). If the terrain isn't supposed to change you could even try display lists (which are the opposite of flexible, but sometimes even faster than VBO).
f@dzhttp://festini.device-zero.de
Original post by Trienco
Quote:Original post by mrbig
3. In my renderer, every vertex corresponds to one pixel,


That's hard to imagine unless you are using parallel projection or your terrain is absolutely flat.../quote]

He is talking about how the terrain image is stored, not how the result looks on the screen.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
@trienco: could you please elaborate why index triangle strips optimized for vertex cache efficiency should be the last option for pipeline optimization?

I held a seminar about vertex cache efficient triangle strips last winter and I can t agree with statements that claim that index triangle lists sorted for vertex cache efficiency can perform nearly as fast as optimized tri strips.

There s been an article at toms hardware sometime ago, but his judgement was kind of subjective without scientific value.

The only reason I see that one should start with index tri lists is because almost all index tri strip generators require exactly this storage format for strip generation.

http://www.8ung.at/basiror/theironcross.html
So basically, you guys are saying that I should forget about such minor optimizations for now and go do something serious, right?
I know very well about terrain subdivision and frustum culling, but I have good reasons to implement the minor optimizations first:

A. Since I'm doing everything inefficiently, this is exactly the time to test how minor optimizations affect the overall performance.
B. They're simple.
C. If I got it right, using triangle strips and VBOs requires a special arrangement of the triangles. I'd really prefer to do that right away.

Oh and another thing, how do you guys associate a 256x256 texture on a huge terrain with "detail"? ;)
I won't get any detail from such a small texturemap on such a huge mesh, not metter how I use it.
I'm using it merely to define the general colors of the terrain, not for detail, so why bother texturemapping 131,072 triangles?
I'm going to use texture splatting and detail maps, so having defined the general colors of the map also allows me to use greyscales for the textures and detailmaps themselves, which means a little bit less data on the hard-drive and GPU RAM. Oh, there I go again, micro-optimizing...

[EDIT]

Oh, by the way, nobody mentioned backface culling.
Almost forgot about it.
Backface culling is OpenGL Rendering 101, you should be doing it anyways unless you have a good reason not to [smile]

This topic is closed to new replies.

Advertisement