Sign in to follow this  

Dividing Landscapes

This topic is 4557 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 have managed, with the help of members of this site, to get a lovely landscape up and running. Now I want to subdivide the overall landscape into small sectors, so I can perform frustrum tests, and cull out of view sectors. My plan so far has been to generate a large vertex and index buffer for the whole landscape. I then have been trying to copy smaller areas of the INDEX buffer to each sector object, which could be rendered independantly. Psuedo code - terrain::sectorize() lock big world IB for (0 -> number of sectors) { create temporary sector object lock small sector IB copy required entries from big IB to small IB ( not using memcpy yet! ) unlock small sector IB sectorList.pushback(temp sector) } terrain::render() set the vertex stream to big world VB for (0 -> sector vector size) { if (visible) { set the index stream to the sectors IB, drawIndexedPrimitive.} } Unfortunately, my code is letting me down i think! What is the best way of copying part of the large world index buffer to each smaller sector index buffer? I was locking both, then trying to copy a patch over using a double for loop. Not really cutting it! All this happens at init time so speed isnt no1 priority. Thanks in advance! Simon

Share this post


Link to post
Share on other sites
What I did was create the entire vertex buffer for the landscape like you did, only +1 on each axis (when you have two zones, one zone's last vertex on both X and Z must touch the first vertex on the adjacent zone)

(my zone = your sector)

To make it looks like so:

Vertices = new aeDynamicMesh::vertex_t<1>[(m_AxisSize + 1) * (m_AxisSize + 1)];
vb = Vertices;

for (z = 0; z <= m_AxisSize; z++)
{
for (x = 0; x <= m_AxisSize; x++)
{
vb->vertex.x = x * XZ_SCALE;
vb->vertex.y = m_BaseHeight;
vb->vertex.z = z * XZ_SCALE;
vb->vertex.tex[0].u = (x % ZONE_VERTICES) / (float)ZONE_VERTICES;
vb->vertex.tex[0].v = (z % ZONE_VERTICES) / (float)ZONE_VERTICES;
vb ++;
}
}



Then I created a unified index buffer for all zones. This is so that I don't need to change index buffers when a zone is rendered.

//#define ZONE_VERTICES 32
m_ZoneIndices = new unsigned short[ZONE_VERTICES * ZONE_VERTICES * 6];
for (z = 0; z < ZONE_VERTICES; z++)
{
unsigned short *ibx = m_ZoneIndices + (z * ZONE_VERTICES * 6);
for (x = 0; x < ZONE_VERTICES; x++)
{
ibx[0] = z * (ZONE_VERTICES + 1) + x;
ibx[1] = (z + 1) * (ZONE_VERTICES + 1) + (x + 1);
ibx[2] = z * (ZONE_VERTICES + 1) + (x + 1);
ibx[3] = (z + 1) * (ZONE_VERTICES + 1) + (x + 1);
ibx[4] = z * (ZONE_VERTICES + 1) + x;
ibx[5] = (z + 1) * (ZONE_VERTICES + 1) + x;
ibx += 6;
}
}



Now, when I go through each zone, I create a vertex buffer for that zone. I want to copy the vertices from the big buffer into the zone buffer. I do so as follows:

// zx is the index of the zone on the X axis (the second zone on the first row would make zx = 1, for example)
// vz is the index of the zone on the Z axis (second row = 1) multiplied by ZONE_VERTICES.
// create the zone vertex buffer of size 33x33
vb = zonePtr->vertices = new
aeDynamicMesh::vertex_t<1>[(ZONE_VERTICES+1) * (ZONE_VERTICES+1)];
for (z = vz; z <= vz + ZONE_VERTICES; z++)
{
// copy only the row from the vertex buffer that pertains to this zone
memcpy(vb, &Vertices[z * (m_AxisSize + 1) + (zx * ZONE_VERTICES)], sizeof(aeDynamicMesh::vertex_t<1>) * (ZONE_VERTICES + 1));
vb += (ZONE_VERTICES + 1);
}



So now when I render a zone (you can see how you can derive the bounding box of the zone from the 'vz' and subsequently, 'vx' data) I just send the vertex buffer from that zone and the global index buffer I made up above.

Share this post


Link to post
Share on other sites
Thats very interesting.... why did you opt to create a single index buffer? but multiple vertex buffers

Thought multiple index buffers would be smaller.....

Share this post


Link to post
Share on other sites
Since each zone is going to have a vertex buffer, then I don't need to swap out index buffers if all the indices would be the same anyway. This means a larger chance the index buffer will stay in the most frequently used portion of the video card memory and not get opted out by some other index buffer from another zone that contains the same data.

Each index buffer contains 32x32x6 indices (6,144 indices) which makes 2048 triangles (twice as much as D3D's optimal batch size, so the docs say.. I know, I'm looking at getting this down). I'm trying to find a comfortable size for the zone right now. For my app, each zone contains an alpha map for each texture layer ('splatting') and a static lightmap. I don't want to make the zones too large or the textures loose too much fidelity. If I make them too small, there ends up being too many textures. Also have to look at the implications it's going to have on the quad-tree system that runs along side with it.

I'm looking into the possibility of making texture atlases for, say, 2x2 zones so that I could fit more alpha maps and lightmaps into less textures for the same amount of zones. This could mean less texture swaps.

Just need to design it before I code it (which is a first for me in the last 6 months).

Share this post


Link to post
Share on other sites
How are you creating your terrain - from height maps?

If you are then why not just create the small sectors instead of creating a big sector and splitting it.

I coded a VB application which created optomised grids from height maps and created them in sections so that I wouldn't have to deal with any clipping to the quadtree I was using.

I found that approach really easy to do - I can't fault it.

I'd host a screen shot or two of the optomised grids that are created if I had some web space but you can probably find some on the net anyway.

Hope that helps

Matt

Share this post


Link to post
Share on other sites
Yeah I use a 16bit heightmap.

Agreed. Since i'm going zone by zone and copying the vertex buffers, I might as well create the vertices for that specific zone right then and there.

I just haven't gotten around to doing it yet :P It's one of those things I think of for a quick moment, but get lost in something else before I do it or write it down in my To Do list..

I'm going to do that right now while I'm killing time.

Share this post


Link to post
Share on other sites
Did you use a Quad-Tree to divide up your terrain?

What sizes are your heightmap?

Want to post screenshot?

Are you using single or multiple buffers?

Singlebuffers are WAY faster. On a giant terrain 517x517, divided into a quad-tree, frustum culled, with a single buffer it was 10ms faster than multiple buffers.

The single buffering method was easy, I just set up a nice routine to work with one index buffer written to assume the chunks coming in from the quad-tree. So the index buffer never has to change, and it will work on any comp regardless of the MaxVertexIndex, some comps may requires more than one DIP call thats it.

Share this post


Link to post
Share on other sites
A QuadTree is a recursive method of splitting up your heightmap (or 2D representation) of your terrain into nodes. Picture the full heightmap, split it into 4 nodes, then split each node into 4 nodes, and split each one of those nodes into 4 nodes. This picture outlines the first splits of a basic quad tree.



Using this method allows for a very quick culling of nodes. Assume the player is standing in the middle of the large upper-left node. Depending on where he is looking you'll probably only have to run frustum checks on a few nodes. Better yet, collision detection has gone from every triangle in your terrain to only the ones in the node the player is in (and surrounding to be safe).

Both the function which divides the quad-tree and culls the quad-tree should be recursive. As in they call themselves to go into the depth of the quad-tree. This is by far one of the best methods of optimizing any sort of culling needed on a terrain. It is a starting block for almost EVERY terrain engine. Some may use a BSP tree but for the actual terrain, a QUAD-TREE is easier and often allows for more optimization. A BSP tree is good for objects in your world, but thats another lesson.

Here are a few links which scrape the surface:
http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=34
http://home.planet.nl/~monstrous/terrain.html
http://www.qeradiant.com/manual/Terrain_Manual/pages/height_maps.html


One of those articles go into LOD which for a MMORPG AAA game that may be necessary. For now I suggest you restrict your terrain learning curve to Quad-Tree only, once you are familiar with that the other aspects will start to make sense.

Share this post


Link to post
Share on other sites
Quote:
Original post by Halsafar
The single buffering method was easy, I just set up a nice routine to work with one index buffer written to assume the chunks coming in from the quad-tree. So the index buffer never has to change, and it will work on any comp regardless of the MaxVertexIndex, some comps may requires more than one DIP call thats it.


Could you point that method out more clearly? ATM I´m using one large VB and every node of my quadtree contains it´s own index buffer. This needs many buffer changes (in fact every draw call I need one, drawing everything in the buffer). Furthermore it results in more draw calls than would actually be required. So I would really be interested how I can only use one index buffer for every node?

Sordid stated, that 1024 triangles would be the ideal batch size for D3D. Why is that? I only yet have encountered that my terrain runs faster if I use the largest batches possible. Rendering a 513 x 513 terrain with batches of 1024 tris would result in 512 batches, which is way too much in my oppinion?

Share this post


Link to post
Share on other sites

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