Sign in to follow this  

Terrain Help

This topic is 4264 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

I am creating a terrain class, the terrain cuts the world into terrainChunks. The terrain has q terrainChunks. A terrainChunk is a simple grid of n*n quads. I dont want to render everything at once, as its fill rate intensive. Instead I only want to render the chunks that are in the cameras frustrum. I want to do this as fast as possible. Possible creteria would be to do it with as few draw calls and with the least amount of locking as possible. <<Using the stencilBuffer to help cut on overdraw A few ideas: 1)Render all the entire terrain every frame. ->No locking, one batch 2)Create a series of vertex/index buffers, one for each terrainChunk. Render every terrainChunk that is in the frustrum. ->maximum of q batches, no locking 3)Create a dynamic vertex/index buffer. Fill it with the terrainChunks in the frustrum, only rewriting if there is a change in what is in the frustrum. ->one drawcall but massive ammounts of locking I am not sure which would be best, or if there is a more optimal method...

Share this post


Link to post
Share on other sites
The single biggest win I've had with terrain rendering is by using the quadtree data structure. You'll need another culling algorithm to work alongside it, so it's more of an optimal arrangment/traversal mechanism for the terrain data. I highly recommend you use it [smile]

As far as Direct3D goes, then tricks with duplicating index data has served me very well before. Index data is relatively small, yet some people still think that any extra data is obviously A Bad Thing™, but the trade-off between a few KB of extra index data and the batching performance is definitely worth it.

Example...

A 16bit index buffer can handle 65536 vertices, which is a 256x256 patch. Primarily you'll want blocks of 256x256 vertices stored in a vertex buffer. You'll need to make a SetStreamSource() each time you change from block-to-block, but otherwise you can traverse the tree without changing the vertex data.

If you also arrange an index buffer to go alongside it and arrange it to match the order of the quadtree traversal you can generate the absolute minimum number of draw calls and state changes. Thus you keep your CPU and GPU happy [smile]

Just to simplify, if we had a 4x4 grid, that generates a one 4x4, four 2x2 and sixteen 1x1 tiles. Generate the index buffer to be something like:

[4x4][2x2][2x2][2x2][2x2][1x1][1x1][1x1][1x1][1x1][1x1][1x1][1x1][1x1][1x1][1x1][1x1][1x1][1x1][1x1][1x1]

Thus with some clever use of offsets you can despatch an entire branch (and not just a node) of the quadtree with a single DrawIndexedPrimitive() call [grin]

Quote:
<<Using the stencilBuffer to help cut on overdraw
A few ideas:
1)Render all the entire terrain every frame.
->No locking, one batch
Wouldn't recommend this one, particularly as terrain rendering tends to be as much transform limited as pixel limited. Early-Z rejection would probably do a better job than any stencil/occlusion based trickery.

Quote:
2)Create a series of vertex/index buffers, one for each terrainChunk. Render every terrainChunk that is in the frustrum.
->maximum of q batches, no locking
This when combined with a QuadTree can work quite well and is easy to implement. What I described previously in my post is an extension/optimization on this to reduce the required state-changes.

Quote:
3)Create a dynamic vertex/index buffer. Fill it with the terrainChunks in the frustrum, only rewriting if there is a change in what is in the frustrum.
->one drawcall but massive ammounts of locking
I don't like the sound of this one - resource manipulation is an absolute last resort option. When there are lots of better techniques for terrain rendering, why even consider it [smile]

hth
Jack

Share this post


Link to post
Share on other sites
It seems that Jack really covered most of what you wanted.
Quote:

1)Render all the entire terrain every frame.
->No locking, one batch

Depends on the terrain size and the contents/entities on the terrain. If you have a small terrain it might be best to just render it all at once. I am talking about terrains like 128x128, like a small island or something.

Quote:

2)Create a series of vertex/index buffers, one for each terrainChunk. Render every terrainChunk that is in the frustrum.
->maximum of q batches, no locking

I did that in a previous version of a terrain engine I coded. I basically had a quadtree type setup where each chunk is 33x33 and they are each placed in their own vertex buffer. I then have a simple view frustum test and then rendered only the chunks that are visible.

Quote:

3)Create a dynamic vertex/index buffer. Fill it with the terrainChunks in the frustrum, only rewriting if there is a change in what is in the frustrum.
->one drawcall but massive ammounts of locking

I agree with Jack on this one,
I would suggest that using dynamic buffers should really be your last resort.

PS: this might seem a bit of a duplicate of Jack's post but really just my opinion on the matters at hand.

I hope this helps.
Take care.

Share this post


Link to post
Share on other sites
I just read this post, and think I'm misunderstanding something.

A 256x256 patch of verts forms a 255x255 group of quads which doesn't break down evenly into more quads.

Do you actually use all 256 verts in the VB or is that just the ideal way to use them?

Thanks,
BennyW

Share this post


Link to post
Share on other sites
Quote:
Original post by Aiursrage2k
I dont want to render everything at once, as its fill rate intensive. Instead I only want to render the chunks that are in the cameras frustrum.

Call me anal retentive, but I'd like to point out that culling things outside the screen doesn't do anything for fill rate, since they're not drawn anyway. View frustum culling is helpful in reducing vertex processing, not pixel processing.

Quote:
Original post by bennyW
I just read this post, and think I'm misunderstanding something.

A 256x256 patch of verts forms a 255x255 group of quads which doesn't break down evenly into more quads.

Do you actually use all 256 verts in the VB or is that just the ideal way to use them?

And to answer another anal retentive guy, 256x256 is just the maximum 16 bit indices can handle. You can use less if you have to, or break any way you want. 255 divides by 15 or 17, BTW, so no need to worry too much.


As for how I'd implement this, it depends on the number of tiles, but probably using a grid array or just going over each tile and testing it (if there are relatively few of them). I prefer my data structures as simple as possible. Usually the overhead of using a complex data structure means it's only worth using it over a certain size.

Share this post


Link to post
Share on other sites

This topic is 4264 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this