Sign in to follow this  
FoxHunter2

Terrain + Quadtree Practices - UPDATE #1

Recommended Posts

Hi everybody I've worked myself though the Riemer's tutorials on terrain rendering, you can find them here: http://www.riemers.net/eng/Tutorials/XNA/Csharp/series4.php I refactored them a bit (put into diverse classes) and wrote my own Quadtree implementation based on some suggestions in this forums to do some culling. This is how it looks like (the shader is a bit incorrect right now) But I have some questions here: - Is it a good practice to store a VB and IB for each patch? - How can I remove the visible edges between each patch? I guess it's got something to do with the texture coordinates. If I use one large patch then the terrain looks fine, but I can't do any culling then, of course. regards [Edited by - FoxHunter2 on August 3, 2007 9:35:02 AM]

Share this post


Link to post
Share on other sites
Quote:
Is it a good practice to store a VB and IB for each patch?


I would appreciate an answer to this one myself as it's something I'm working on as well.

The approach I'm currently taking is to use a dynamic index buffer and a single vertex buffer. Traverse the quad tree and assemble the index buffer from the indices stored in the visible patches, then draw.

Share this post


Link to post
Share on other sites
[quote]Original post by FunLogic
Quote:
The approach I'm currently taking is to use a dynamic index buffer and a single vertex buffer. Traverse the quad tree and assemble the index buffer from the indices stored in the visible patches, then draw.


Does that mean you have a large vertexbuffer for the whole terrain and then create the indexbuffer on the fly for all visible patches? Do you read the visible vertices back from the VB or how do you do that?

I think this would be the only proper way to remove the edges in my terrain, but I don't know if it doesn't cost too much performance.

Share this post


Link to post
Share on other sites
To save some memory on the graphics card (and maybe to speed things up a little bit too), I think it is a good idea to just use one index buffer for all the patches, since you draw each patch's triangles in the same order (or do you not?). Additionally you could store the entire terrain piece in one vertex buffer, just one patch after the other and jump into the right patch by offsetting the single index buffer mentioned above. That would result in no buffer changes at all.
Just a few ideas.

Share this post


Link to post
Share on other sites
Quote:
Original post by FoxHunter2

I think this would be the only proper way to remove the edges in my terrain, but I don't know if it doesn't cost too much performance.


The edges are the result of texture tileing. This is a common problem with multi-texturing.

Share this post


Link to post
Share on other sites
So you basically mean just one VB and IB for the whole terrain and then just offsetting the IB? How would that work exactly, i.e. how would I choose the correct offset to only show the visible patches?

Share this post


Link to post
Share on other sites
At first you would check, which patches of your terrain piece are actually visible (by whatever method you like, from easy as view frustrum culling to more elaborate with potential visibility sets (PSV)), by that you just gather a number of indices of which each identifies one of your patches. You then just multiply that number by the number of vertices per patch and this is your offset in the vertex buffer. Of course, the vertex buffer needs to be set up in the right way for that to work too (i.e. one patch after the other), but that's simple to do.

PS: Rereading my first post, I think I didn't make it completely clear what I meant with one index buffer for all the patches: This single index buffer would be holding only the indices to draw a single patch. It would then be reused to draw other patches as well.

Share this post


Link to post
Share on other sites
That sounds really great - in theory. Since this is my first attempt in doing some terrain modelling I'm not sure I can do this without further reading.
It should be fairly easy to create a VB that will store all patches in a row. Actually my recursive quadtree division should do this by itself.
Something in the lines of


Subdivide(x, xx, y, yy, ...)
{
vertexBuffer[x + y...].Vertices = ...
}


Is this correct?
But I yet have to see some code to get a grip on the whole indexing thing...

Share this post


Link to post
Share on other sites
Okay, I managed to get all patches into one large VB and IB and from there just adjust the offset in my DrawIndexedPrimitive call.
Everything works fine and I got a ~200% performance boost, which is nice :)

But I still get the visible edges between each patch. Can I solve this by aligning my patches in a certain way in the VB or IB?

Share this post


Link to post
Share on other sites
My new Terrain engine is divided up in such a way to try and resolve 2 problems.

1 - Not all of the terrain can fit in memory at the same time
2 - Not all of the in-memory terrain should be on screen at the same time.

To resolve the first problem, my terrain is broken up into TerrainTile's. These are fixed-size blocks of Terrain, which can be independently streamed to/from disk and contains the height, color, and UV information for the tile. Basically, each TerrainTile is a model. With my current implementation, the tile the player is currently standing on and the 8 surrounding tiles are always loaded in memory. When the user moves from one tile to the next, some are disposed of, while others are loaded.

Then, to deal with problem two, each TerrainTile is broken up into patches. These are dynamically sized sections of the terrain used for culling and optimizations. The sizes of these patches are based on user settings and performance. Each Patch has its own vertex buffer, index buffer, and segments which can be used for applying different effects, textures, etc...to different parts of the patch. Basically, each patch is a mesh.

So specifically, my new engine looks something like this:


Terrain
IndexList
TerrainTile[]
RootTransform
TerrainPatch[]
Transform
VertexBuffer
IndexBuffer
Effect[]
TerrainSegment[][]
baseVertex
startIndex


Whenever the player moves a call to Terrain.Update(). This updates the LoD, and also makes a call to Terrain.CullToViewFrustrum().

A Terrain.CullToViewFrustrum() call determines which of the tiles are visible, and then which of the patches are visible and marks them as such.

Rendering is a call to Terrain.Draw()

This iterates through each of the TerrainTiles and calls TerrainTile.Draw() on it. If the terrainTile is not visible, it simply returns.

If the TerrainTile is visible it sets the world matrix to the tile's root transform. After that it iterates through each of the patches and calls TerrainPatch.Draw on it.

This then multiplies its transform by the current world transform and sets that on the device. After that it sets the vertex buffer and index buffer on the device. Finally, it iterates through each of the terrain segment sets, rendering each segment by setting the desired material and rendering the triangles of that segment.

All in all, it seems to work ok.

Share this post


Link to post
Share on other sites
The most visible edges look like they're caused by the textures being applied in a way that the adjacent textures don't match up with each other. It looks like rotating or mirroring every other row might fix it.

Share this post


Link to post
Share on other sites
To fix your texture problem you might want to look into two things:
First, do your textures actually tile? Meaning, does the right side put next to the left side leave a noticable seam or not. If so, the texture does not tile. Fix that, if it's an issue.
Second, how do you get your normals for each patch? Especially for the vertices at the edge of the patch? Do they take the patch into account, that would be situated right next to it? If not, this is going to mess you up too.

Share this post


Link to post
Share on other sites
@JWalsh:

My first version also had a VB and IB for each patch, but I noticed that switching them in each Render call cost me about 50% of my fps, despite using a quadtree for culling.
I'm also not sure if I can use streaming on the XBox (I'm developing an XNA program), but I will definately look into that issue when my terrain gets bigger :)

@Vorpy@HansDampf:

Do you mean I should create my textures so that each edge looks the same? I will take a look at it.
Regarding the normals, I use (0,0,1) as a normal for the edges of a patch, I haven't done any testing yet whether is is okay.

Share this post


Link to post
Share on other sites

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