Jump to content
  • Advertisement
Sign in to follow this  
BauerGL

GeoMipMap - Index Buffer Usage

This topic is 4841 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I recently began to give GeoMipMaps a try and I came up with an idea that I wanted to share. Though it's just an idea so I don't know if it works, which is why I'm posting this. So, with geomipmaps we have one vertex buffer with all the terrain vertices. Then we have the patches, small tiled pieces of terrain. Now each patch can have different LODs, i.e use different amounts of vertices. Depending on which LOD a patch should be rendered at, it uses a specific index buffer. I've seen implementations where each patch has their own index buffers for each LOD. This seems to be a bit of waste to me. Now my idea is that if I would have, say, 4 different LODs for each patch, I would only need to store 4 "global" index buffers and an offset into the vertex buffer for each patch. This is because the layout of the index buffer only differs per LOD and not necessarily per patch. So if I want to render patch01 at LOD1, I'd use the index buffer for LOD1 and then the offset for patch01. This means that I could sort each patch that uses the same LOD and render all those without changing index buffer. Plus it saves on memory. Remember that this is just something that hit me, I haven't given it any research yet. Do you think it's possible or useful at all? Any suggestions welcome!

Share this post


Link to post
Share on other sites
Advertisement
This is exaclty what i do in my GeoMipMapping implementation. You will actually need 16 different index arrangements for each LOD level. Where certain sides are degnerated:
1) Left
2) Right
3) Top
4) Bottom
5) Left-Right
6) Top-Bottom
7) Left-Bottom-Right
8) Bottom-Right-Top
9) Right-Top-Left
10) Top-Left-Bottom
11) Left-Bottom
12) Bottom-Right
13) Right-Top
14) Top-Left
15) All sides
16) No sides

A good idea is to jam every single configuration for every LOD level into 1 large index buffer. Also, if your patches are not too big, you can use 16-bit indices (given that hardware supports it) which saves you both space and bandwidth.

By using one huge buffer, you can reduce the amount of buffer changing/swapping you need to do (buffer-related state changes are the most expensive). Then, Selecting each LOD level is a matter of passing some offsets into the render call. I calculate these offsets while i generate the indexbuffers and store them in a simple array. offset into this arrays is calculated as: 16 * LOD_level + configuration. It works beautifully with good performance. Then i cull super aggresively with a compination of quadtree-frustum and horizon culling techniques.

Good luck with your efforts. ;)

Share this post


Link to post
Share on other sites
Thanks!

samgzman
I can't see why I would need to have index buffers with degenerated sides. Would you care to explain that a bit?

I'm using triangle lists right now which I've heard should be almost as fast as triangle strips when using index buffers. But even if I'd use strips I don't think I'll need to have a whole side with degenerates? I mean, every patch would render itself, line per line of triangles, adding degenerates at the end of each line to begin on the next one. So when it has rendered each line and should start on the next patch, isn't it only necessary to connect two degenerates using the last vertices of the first patch, with the first vertices of the next patch (just like line-to-line degenerates)?

Or do you mean that the different index arrangements are for connecting with odd neighbouring patches? For example, if a patch is being rendered where it's right neighbour has one step (LOD) less detail, it should use the index arrangemements where the right side has one step less detail? So it's not using degenerate triangles, it's actually using fewer vertices to better match upp with it's neighbours?

Share this post


Link to post
Share on other sites
Implemented something like it last year. Except I dont store all possible LOD index buffers (way too many for my implementation) so when two LODs dont match I duplicate the index buffer and generate the degenerate vertecies to make it match.

I also have a cache for these newly generated degenerate index buffers so they are only generated once (until cleared) and can be used by more than one patch at a time. I used a maximum memory threshold, and an LRU scheme to control this cache. Worked quite well.

Share this post


Link to post
Share on other sites
samgzman:

you're talking about one big buffer for the indexes and several buffers for the patches right??

greets
tgar

Share this post


Link to post
Share on other sites
Im sorry. I meant degenerate as in the sides of a patch where neighboring patches are at a different LOD level. Its a good idea to use triangle lists. IIRC, some hardware will only utilize vertex caching when using lists. With that in mind, you might want to try to write your index generator so that it doesnt use super LONG strips on the back and fowarth strips. Thats probably overkill, but im a nutcase O_o. Cards vary on the size of their vertex caches, but i think its about 10-15 on average.

And yes, just one big index buffer. Each patch would be unique hopefully ;).

for patch sizes of 17 or 33 (squared), 16-bit indices should be enough. Anything bigger will probably affect performance adversly (decreasing culling efficiency, potential overdraw, and simply too much per draw call). The next patch size up from 33x33 is 65*65 (2^n+1) which wouuld be 8450 polygons if drawn an full detail. Way too much

Share this post


Link to post
Share on other sites
I store the indices per patch in my terrain. The reason is due to the index modifications that happen in order to prevent cracks on the edges. I'm pretty sure this consumes less memory than storing every possible index buffer, especially because I don't force neighbors to be within a certain LoD difference. So a 3x3 is allowed to border a 33x33. nts' scheme is more sophisticated, since it uses caching, and that'd be the next logical step for me, but the total memory consumption for my indices right now is ~12MB, which I'm willing to accept.

In my own code, I found 65x65 to be optimal patch size. That's 8k polys when drawn at full detail, but it helps to decrease rendering costs when you have a lot of patches at lower detail levels. I also tend to use fairly high horizontal scaling (4x generally); 128x128 might work better if you're using very high detail terrain. As for strips, screw them. It's not worth the time or effort required to generate them, for little or no performance gain.

Share this post


Link to post
Share on other sites
To elaborate on Promit's point, if the number of visible patches is less than the number of possible LOD combinations (minimally 16 * number of LODs) it's better to just have an index buffer per patch. Generating these and uploading to the GPU when the LOD changes shouldn't affect the performance too much.

The "optimal patch size" is much more critical on the low end than the high end. To grossly over-simplify: below a certain size a patch always takes the same amount of time to render, and above that size it takes an amount of time proportional to the number of polygons. Say the number is around 4K. A patch of 1K takes as long as a patch of 4K. A patch of 16K takes four times that. *However*, if that 16K patch is being drawn instead of four adjacent 4K patches it follows that there's no performance hit whatsoever. More importantly, in the next LOD down you're drawing one 4K patch instead of four 1K patches which is four times faster.

Even 64K+ poly patches are just fine in terms of rendering speed as long as you really want to render that much. The reason why you usually don't want patches this big is for frustum culling and LOD reasons. A 256x256 area of terrain in a game is often large enough that you either wouldn't see all of it or the "far side" should be at a low LOD. (In my planet renderer I used huge patches with a variable LOD to do this... geomipmapping 16 sub-patches within each patch to create one index buffer.)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!