Im working on a terrain engine. It generates random hills, on a grid of any given size.
I am using DirectX / C++. I am using Indexed Primitives with Triangle List.
I've been implementing features for a while now, recently got a getHeight() method for terrain following.
Anyway next up is optimization. Ive seen a lot of stuff out there all ready. Ive experimented with my code a little.
I want per triangle/poly culling outside the frustum, and LoD. My priority is the culling. LoD can come later, however I need to look ahead when making design decisions.
What i need to know really is what is the best way forward. Currently I have a vertex and index buffer. I dunno whether I should split them up into a tree structure. If so do I have to actually have separate buffers on each node, or just store the start index etc.
Also I dunno how i would structure any of this.
Terrain Optimisation
The simplest and fastest is usually to divide your terrain into fairly large sections, and cull entire sections only. Culling individual triangles will most likely decrease performance. Say you have a 4096x4096 terrain, divide it into 256x256 sections and draw all sections that are visible, if possible in a single or a few draw-calls per section. There are many techniques for improving upon this technique and for applying different types of LOD, from very simple with less than perfect results, to extremely advanced and complicated techniques, some with excellent results. The easiest is to keep different LODs around for each section, and pick the LOD per section depending on the distance to the player, and then use some tricks to cover up the edges between different levels.
Look over the following searches for some ideas:
http://www.google.com/search?q=terrain+lod+techniques
http://www.google.com/search?q=geoclipmaps
http://www.google.com/search?q=geomipmapping
Look over the following searches for some ideas:
http://www.google.com/search?q=terrain+lod+techniques
http://www.google.com/search?q=geoclipmaps
http://www.google.com/search?q=geomipmapping
OK been having a (quick) look around. I think i wanna start out small like you said. think ill just chop my terrain in 4 and get that working 1st. Still not sure about how to split up the vertex/index buffers.
My options are
- create new (smaller) buffers for each division of the terrain.
- create a new index buffer for each division and keep the vertex buffer in root object.
- keep both buffers and somehow render each bit by specifying start index/primitive counts when drawing (this would be tricky for some sections as not all the indices would be consecutive)
Like I say i have been experimenting already, the last of my options is kind of what i tried. I managed to get it to render with one call half of my terrain, and i can change the start index too, but I had trouble changing the numVertices parameter, If I used anything but the number of vertices in the vertex buffer, it wouldn't draw properly, (triangles flying at the screen kinda thing), trying to change the vertex base or min vertex index, didnt work either.
What do you think would be the best way forward, I'm sure I've seen examples where people don't create new buffers.
thanks again!
My options are
- create new (smaller) buffers for each division of the terrain.
- create a new index buffer for each division and keep the vertex buffer in root object.
- keep both buffers and somehow render each bit by specifying start index/primitive counts when drawing (this would be tricky for some sections as not all the indices would be consecutive)
Like I say i have been experimenting already, the last of my options is kind of what i tried. I managed to get it to render with one call half of my terrain, and i can change the start index too, but I had trouble changing the numVertices parameter, If I used anything but the number of vertices in the vertex buffer, it wouldn't draw properly, (triangles flying at the screen kinda thing), trying to change the vertex base or min vertex index, didnt work either.
What do you think would be the best way forward, I'm sure I've seen examples where people don't create new buffers.
thanks again!
It should work fine to use the same index-buffer for each section with a different start-index, and a single vertex-buffer, depending on how your terrain is laid out in memory. There's nothing wrong with one vertex-buffer for each section either, in which case you can use the exact same draw-call and index buffer for each one, but with the correct vertex buffer set. This might be better if you want really large terrains.
Post your drawing and buffer creation code if you can't get it to work.
Post your drawing and buffer creation code if you can't get it to work.
I want to make it as flexible as possible but yeah I'd like some big terrains. You say its better to have smaller buffers for that case.
the problem ive forseen. is this.
My vertices are layed out in following way
say my grid was 10x10
my vertices are arranged in an array like: (1D array)
and the indices are like
They are generated in loops which will arrange them in that structure.
the problem lies where, if i want to split that 10x10 grid up into 2 halves 10x5 (horizontal split),
its easy. (verts 0 to 49 and 50 to 99)
but the vertical split would be tricky because every 5 primitives it would need to skip 5 and start the row again. follow?
the only way i can think of solving that is to have a loop with several draw calls. I tried that and it was really slow. I couldnt get it to draw properly without giving it the total number of vertices for the numVertices parameter.
ill have another look at my code and may post it if something happens.
Still I think i may end up using new buffers. Ill see what happens
the problem ive forseen. is this.
My vertices are layed out in following way
say my grid was 10x10
my vertices are arranged in an array like: (1D array)
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 ...... etc
and the indices are like
indices[0] = 0;
indices[1] = 1;
indices[2] = 2;
indices[3] = 2;
indices[4] = 1;
indices[5] = 3;
They are generated in loops which will arrange them in that structure.
the problem lies where, if i want to split that 10x10 grid up into 2 halves 10x5 (horizontal split),
its easy. (verts 0 to 49 and 50 to 99)
but the vertical split would be tricky because every 5 primitives it would need to skip 5 and start the row again. follow?
the only way i can think of solving that is to have a loop with several draw calls. I tried that and it was really slow. I couldnt get it to draw properly without giving it the total number of vertices for the numVertices parameter.
ill have another look at my code and may post it if something happens.
Still I think i may end up using new buffers. Ill see what happens
A 10x10 block may not even be worth splitting up, but you could just use different pre-generated index arrays. Index buffers are relatively small and can be shared, so having separate ones for the split blocks doesn't take much extra space. With terrain vertices in a static vertex buffer, it's okay if you don't use all of them since they're already in video memory.
Using a smaller 3x3 array of vertices for demonstration purposes:
To draw the full block:
To draw just the left half
To draw just the right half:
[font="Courier New"][font="Arial"]
[/font][/font]
While the index lists skip over some vertices, they can still be drawn with a single indexed primitive.
Using a smaller 3x3 array of vertices for demonstration purposes:
0 1 2
3 4 5
6 7 8
To draw the full block:
0, 3, 1, 4, 1, 3, 1, 4, 2, 5, 2, 4,
3, 6, 4, 7, 4, 6, 4, 7, 5, 8, 5, 7
To draw just the left half
0, 3, 1, 4, 1, 3,
3, 6, 4, 7, 4, 6,
To draw just the right half:
[font="Courier New"][font="Arial"]
1, 4, 2, 5, 2, 4,
4, 7, 5, 8, 5, 7
[/font][/font]
While the index lists skip over some vertices, they can still be drawn with a single indexed primitive.
I took a look and got my code working fairly certain i could split it up into sections, now without splitting the bufffer but like I said it would result in more draw calls, since it can only draw consecutive primitives.
taking my 10x10 grid, i could split that in to 4 5x5 sections
The upper left section would be
that would mean 5 draw calls, 1 for each row. for each division of the terrain. this is only a 4 way split and with a larger grid it could result in more calls the more i split it up.
I dont know how much this would affect performance. You have more experience so I'm wondering what you would do.
Also. The method takes a vertex offset parameter and a number of vertices parameter. if im drawing a triangle from the above section with the vertices 21, 22, 31, that means putting in 10 vertices just to draw 1 triangle. I seem to think that would effect performance. I know i would not draw each triangle seperately but it would still need for the 1st row/render call to go from 0 to 14.
I did a test, for the theory i just outline. I set up a loop to draw every square it one render call. so only 2 triangles per call. I specified in each call that i would be using the total number vertices. (silly i know) it was horribly slow. I then changed it so it took the minimum number of vertices to draw those 2 triangles in each call (64x64 grid, so it needed 66 per call), the framerate had improved but was still only about 30 fps, compared with the 60 of drawing everything in 1 call. when i increase the grid size further im sure i will have bigger problems. the bigger the rows/more columns i will need to give it more verts per call. drawing 1 triangle on a 1024x1024, would need at least a row of vertices simply because of the index position.
hope I am making sense. I want your opinions. basically im weighing up more draw calls over more buffers.
again thanks for your time.
taking my 10x10 grid, i could split that in to 4 5x5 sections
The upper left section would be
0 1 2 3 4
10 11 12 13 14
20 21 22 23 24
30 31 32 33 34
40 41 42 43 44
that would mean 5 draw calls, 1 for each row. for each division of the terrain. this is only a 4 way split and with a larger grid it could result in more calls the more i split it up.
I dont know how much this would affect performance. You have more experience so I'm wondering what you would do.
Also. The method takes a vertex offset parameter and a number of vertices parameter. if im drawing a triangle from the above section with the vertices 21, 22, 31, that means putting in 10 vertices just to draw 1 triangle. I seem to think that would effect performance. I know i would not draw each triangle seperately but it would still need for the 1st row/render call to go from 0 to 14.
I did a test, for the theory i just outline. I set up a loop to draw every square it one render call. so only 2 triangles per call. I specified in each call that i would be using the total number vertices. (silly i know) it was horribly slow. I then changed it so it took the minimum number of vertices to draw those 2 triangles in each call (64x64 grid, so it needed 66 per call), the framerate had improved but was still only about 30 fps, compared with the 60 of drawing everything in 1 call. when i increase the grid size further im sure i will have bigger problems. the bigger the rows/more columns i will need to give it more verts per call. drawing 1 triangle on a 1024x1024, would need at least a row of vertices simply because of the index position.
hope I am making sense. I want your opinions. basically im weighing up more draw calls over more buffers.
again thanks for your time.
@kdmiller3 good point. i like that idea too. I was writing the above post before i saw that you posted.
Are you sayingI could get by with 1 draw call per subdivision? if they each had their own index buffer.
Are you sayingI could get by with 1 draw call per subdivision? if they each had their own index buffer.
Are you sayingI could get by with 1 draw call per subdivision? if they each had their own index buffer.
Actually, you could recycle the same index buffer by setting the BaseVertexIndex parameter in the DrawIndexedPrimitive call. Since your vertices are laid out as a 2D grid, the BaseVertexIndex would specify where you want to place the zero-index corner of the index buffer geometry "template".
Ah. I see. Interesting. I still want to know how much it will effect me having to specify a large number of vertices as the numVertices parameter. in your 3x3 example drawing the left half i would still need from vertex 0 to vertex 7, even though i would never use 2 or 5. the right half even using base vertex index, id sitll need to say i need 8 vertices (1 to 8) and would never need 3 or 6. On a huge grid will this give me problems?
Also would using this method stop me from implementing LoD further down the line. as i understand it LoD needs new index buffers anyway.
Also would using this method stop me from implementing LoD further down the line. as i understand it LoD needs new index buffers anyway.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement