/* attempt to deal with prototype, bootstrap, jquery conflicts */ /* for dropdown menus */

\$30

### Image of the Day Submit

IOTD | Top Screenshots

### The latest, straight to your Inbox.

Subscribe to GameDev.net's newsletters to receive the latest updates and exclusive content.

Sign up now

## A good heightmap LOD technique (no VTF please)

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

28 replies to this topic

### #1Triad_prague  Members

Posted 09 February 2012 - 10:50 PM

Hi, I'm kinda confused now. I'm trying to make an island with a heightmap of size 1025*1025. It can't be possible without LOD in my PC (p4 2.26 GHZ, GF7300GT, 1GB ram). I've been hearing the geoclipmapping methot mentioned, but when I read the paper it said that it used VTF (vertex texture fetching). That's just inaffordable for me (I downloaded a simple demo consisting of a 128*128 grid with VTF and it just as slow as hell). So I don't think I will use that. Can you suggest any other good methods that use no VTF but still can achieve a huge framerate? (kinda sick when my PC is just too old )

basically I need a LOD scheme with these constraints:
- no VTF
- support at least 1025*1025 (2049*2049 is highly appreciated)
- support terrain editing (my game would be a business simulation game)
- quite simple

currently I'm looking at an article presented by the maker of SoulRidetm, but I need as much reading as I could get, and I run out of keywords here, hehe
the hardest part is the beginning...

### #2Lee A. Stripp  Members

Posted 09 February 2012 - 11:38 PM

Yes I'd like to know too, I've been looking for a while and still don't have a good solution. Its one major feature missing in my engine grrr.

Cheers

Lee

Code is Life
C/C++, ObjC Programmer, 3D Artist, Media Production

Website : www.leestripp.com
Skype : lee.stripp@bigpond.com
Gmail : leestripp@gmail.com

### #3MaxDZ8  Members

Posted 10 February 2012 - 12:01 AM

basically I need a LOD scheme with these constraints:
- no VTF
- support at least 1025*1025 (2049*2049 is highly appreciated)
- support terrain editing (my game would be a business simulation game)
- quite simple

1st step: consider brute force it (albeit the hardware limit for your video card could be around 1 Mega points, I don't remember).
I'm not familiar with 7300 but GeForce4 could render 256k vertices with ease in a single batch. 6600 could do 2-4 vertices per pixel and still run interactive!
Anyway, look into geo-mipmapping. It is simple. It has basically no limit on point count. It runs on everything (CPU-based, preprocessing).
It does not natively support terrain modification but it's fairly close. Hopefully it will allow an incremental operation on data structures.

As a side note VTF is very viable on midrange GeForce since generation 6xxx (albeit initial drivers were a bit slow).
When it comes to 7300 I'm afraid it either does not support the feature or it is extremely bandwidth-constrained (if memory serves VTF required 32bit float channels).

Previously "Krohm"

### #4Promit  Senior Moderators

Posted 10 February 2012 - 12:24 AM

Geomipmapping should work fairly well... 1025 is not a large terrain.
SlimDX | Shark Eaters for iOS | Ventspace Blog | Twitter | Proud supporter of diversity and inclusiveness in game development

### #5Benoit Vimont  Members

Posted 10 February 2012 - 08:47 AM

You may use same vertex buffer but with different index buffer for LoD > 0.

For example, If your terrain is split into 16x16 sectors.

LOD0 IB = 16x16 cells
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,33,34,...

LOD1 IB = 8x8 cells
0,2,4,6,8,10,12,14,16
17,19,21,23,...

LOD2 IB = 4x4 cells..

### #6turch  Members

Posted 10 February 2012 - 11:49 AM

Geomipmapping should work fairly well... 1025 is not a large terrain.

I've got a geomipmapping geoclipmapping (doh) implementation that can render 128km square terrain with 1m the highest resolution on weaker cards at 10ms/frame (100fps). And thats with a terribly inefficient, unoptimized implementation. As long as the card supports SM3.0 you geomipmapping should work great.

### #7dave j  Members

Posted 10 February 2012 - 02:26 PM

The original geometry clipmaps paper didn't use VTF.
It's more work on the CPU though - so it still might not be usable.

### #8Cornstalks  Members

Posted 10 February 2012 - 02:53 PM

The original geometry clipmaps paper didn't use VTF.
It's more work on the CPU though - so it still might not be usable.

There's a footnote on that page with a link to here and an explanation that they were able to move pretty much all the work to the GPU.
[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

### #9Lee A. Stripp  Members

Posted 10 February 2012 - 08:31 PM

Great paper, has anyone thought of using disc shapes instead of grids and just scale with view height?

Cheers

Lee

Code is Life
C/C++, ObjC Programmer, 3D Artist, Media Production

Website : www.leestripp.com
Skype : lee.stripp@bigpond.com
Gmail : leestripp@gmail.com

### #10TiagoCosta  Members

Posted 11 February 2012 - 04:21 AM

Great paper, has anyone thought of using disc shapes instead of grids and just scale with view height?

Hi Lee , the point of using a grid is its simplicity... How would you implement something similar to the L-Shaped strip that is used to reduce flickering of vertices?

There is also CDLOD.

### #11dave j  Members

Posted 11 February 2012 - 04:38 AM

The original geometry clipmaps paper didn't use VTF.
It's more work on the CPU though - so it still might not be usable.

There's a footnote on that page with a link to here and an explanation that they were able to move pretty much all the work to the GPU.

I know - but that requires VFT which the OP doesn't want to use. Hence the link to the original paper.

### #12Cornstalks  Members

Posted 11 February 2012 - 08:54 AM

The original geometry clipmaps paper didn't use VTF.
It's more work on the CPU though - so it still might not be usable.

There's a footnote on that page with a link to here and an explanation that they were able to move pretty much all the work to the GPU.

I know - but that requires VFT which the OP doesn't want to use. Hence the link to the original paper.

You're totally right. This is when doing a quick text search for "VFT" in a paper, and assuming that since it doesn't contain "VFT," it must not use VFT, is a stupid assumption. Thanks.
[ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

### #13MaxDZ8  Members

Posted 11 February 2012 - 08:55 AM

There is also CDLOD.

I'm not quite sold on that. By the way, the author presents it as "Continuous Distance-Dependent Level of Detail for Rendering Heightmaps" but at its core it's just an interpolated discrete lod. Both geomipmapping and geoclipmapping feature some kind of interpolation: that does not make it a continuous metod.
Perhaps I am misunderstanding it big way but...
Let me quote:

{1} Using CDLOD, each vertex is morphed individually based on its own LOD metric unlike the method in [Ulrich 02], where the morph is performed per-node (per-chunk).
...
{2} First, the approximate distance between the observer and the vertex is calculated to determine the amount of morph required
...
{3} Finally, the z-component is obtained by sampling the heightmap with texture coordinates calculated from x and y components using a bilinear filter (filtering is only needed for vertices in the morph region). When all vertices of a node are morphed to this low-detail state, the mesh then effectively contains four times fewer triangles and exactly matches the one from the lower LOD layer; hence it can be seamlessly replaced by it.
...
{4} Settings used to generate the quadtree and run the algorithm need to be carefully chosen to match terrain dataset characteristics while providing the best performance. In the accompanying examples, each dataset defines its own settings.
...
{5} Since the LOD works in three dimensions, this problem will be enhanced when using extremely rough terrain with large height differences: thus, different settings might be required for each dataset.
In the provided data examples, LOD settings are tuned so that the ranges are always acceptable...
...
{6} Two example projects are provided: BasicCDLOD and StreamingCDLOD. Both projects are written in C++, using DirectX9 and HLSL, and should work on most GPUs that support vertex shader texture sampling, i.e., ones supporting Shader Model 3.0
...
{7} The performance bottleneck on the GPU is either the vertex texture fetch cost (used for displacement of terrain vertices), or the triangle rasterization and pixel shader cost. This mostly depends on the settings, GPU hardware, and display resolution.

• He's actually suggesting geoclipmaps to be bad? Or limited? This is a bit odd to me. Nyquist theorem anyone?
• I seriously hope this is not going to happen on CPU! The only possible way to do so is VTF.
• Please note how he's basically admitting the algorithm to be interpolated across discrete states. Having worked on a method that was based on displacing vertices similarly, I am surprised it does not produce consistent wobble.
• I don't know what he means by carefully. I am against everything that requires careful tuning. Note: neither geomipmapping nor geoclipmaps require to be carefully tuned in my opinion (albeit clipmapping requires some tuning and streaming needs tuning as well).
• Note similar issues happen when using geomipmapping (probably because it's doing something very similar?)
• Geomipmapping runs on everything. If SM3 is required, I suppose I might just bite the bullet and use clipmapping.
• Sure, it would have been nice to post the shaders. A simple fill will give no troubles to anyone.
Anyway, I downloaded the 210MiBs required to look at the system. It required me to build the data set on my system. The non-interactive program uses a single core and took like 2 minutes to run. It then took a few minutes (I'd say close to 15m) at runtime to start. Again, single-core. The program blowed about 210 MiBs of RAM to produce around 1 Gig of data. When running, it takes about 180 MiBs.
The method has been "tuned" so most triangles are about... I'd say 4 pixels wide.
Basically what it shows is the algorithm converges to a correct result... at an extreme cost.
I'd take it with some salt.

I look forward to tune this iteratively!

Edited by Krohm, 11 February 2012 - 08:58 AM.

Previously "Krohm"

### #14qwerty7  Members

Posted 13 February 2012 - 03:07 PM

at its core it's just an interpolated discrete lod. Both geomipmapping and geoclipmapping feature some kind of interpolation: that does not make it a continuous metod.

There's a big difference though, the interpolation method is seamless and continuous (thus the name): one segment is morphed completely into another before it's 'swapped', with no seams between LOD levels. Geoclipmaps, geomipmaps (and ChunkedLOD) have T seams between LOD levels and require 'stitching strips' on one hand, and on the other the morphing method only works (reasonably) well for heights but you're still swapping between two different meshes so there's inevitable popping if you're vertex fetching and trying to interpolate other data types (such as normals).
(Another difference is that CDLOD interpolates completely predictably based on the 3D distance between the vertex and the camera, unlike geoclipmaps/chunkedlod.)

I seriously hope this is not going to happen on CPU! The only possible way to do so is VTF.

No, of course, vertex texture fetching is used, read the paper.

Please note how he's basically admitting the algorithm to be interpolated across discrete states. Having worked on a method that was based on displacing vertices similarly, I am surprised it does not produce consistent wobble.

It doesn't wobble because it's not morphing it in a simplistic way: all morph levels are pre-generated to avoid that. (Seriously, try reading the paper? )

I don't understand what would satisfy your definition of a continuous algorithm - ROAM maybe? Whatever you do it still has to be discretized into render calls unless you can store all the heightmap, normalmap and other data into one big buffer and render from it using tessellation or something similar?

Anyway, I downloaded the 210MiBs required to look at the system. It required me to build the data set on my system. The non-interactive program uses a single core and took like 2 minutes to run. It then took a few minutes (I'd say close to 15m) at runtime to start. Again, single-core. The program blowed about 210 MiBs of RAM to produce around 1 Gig of data. When running, it takes about 180 MiBs.

The method has been "tuned" so most triangles are about... I'd say 4 pixels wide.

Well if the triangles are 4 pixels wide on your device then why not try dropping the quality level? You're hardware is probably not the 'target audience' (for example, on my monitor they look around 10ish pixels wide, probably the same dataset): there's a button on the HUD saying "Render grid size:" - drop that one notch and reduce the viewing distance. If you want to save on memory, drop the HeightmapLODOffset and NormalmapLODOffset by one, should reduce the memory use to approx 30-40% of the current. Also, the demo you mention uses a texture splatting technique which must take at least 10MiB RAM without any terrain data loaded - remove that and you've saved some more.

### #15Lee A. Stripp  Members

Posted 13 February 2012 - 08:22 PM

Great paper, has anyone thought of using disc shapes instead of grids and just scale with view height?

Hi Lee , the point of using a grid is its simplicity... How would you implement something similar to the L-Shaped strip that is used to reduce flickering of vertices?

There is also CDLOD.

I was thinking simple.. build the disc shape in advance, the natral expanding of the shape itself creates LOD (But do this with some care) anyway and then split into sections for frustum cull.. I was just making an observation, I haven't done any tests on that at all.

Cheers

Lee

Code is Life
C/C++, ObjC Programmer, 3D Artist, Media Production

Website : www.leestripp.com
Skype : lee.stripp@bigpond.com
Gmail : leestripp@gmail.com

### #16skytiger  Members

Posted 15 February 2012 - 06:25 PM

CDLOD paper was interesting BUT
he makes no mention of what data is transferred, how and when to the GPU
I can't believe he is transferring a screen full every frame?
my current sketch for VTF-less terrain works by loading all the potentially visible vertices into the gpu
using a vertex buffer managed as a heap of blocks, with deallocated blocks waiting 3 frames before being made available for reallocation (to save buffer space on gpu)
the index buffer is tiny and just contains a generic pattern for each LOD level (draw with a vertexoffset to address the correct block of vertices)
this means I only send terrain data to the GPU when it becomes potentially visible
(using a simple modulo grid - which is also used for frustum culling - just project the frustum into "grid space" and you have a list of visible blocks - essentially spatial index query by rasterization!)
(and changing the LOD level of a block just comes down to changing the indexbuffer start offset)
the downside is a large number of draw calls - which I don't think is a real problem as there are no resource changes between them
given the choice of 50 draw calls versus sending 100,000 vertices ... (too lazy to actually profile that right now)

### #17skytiger  Members

Posted 17 February 2012 - 06:18 AM

Here is an idea that is simple to code and highly performant:

1) create a static vertex buffer with the same layout as the height texture (scan lines of texels become contiguous vertices)
2) create a static index buffer containing a disk split into 8 segments (so each disk can be rendered by setting index buffer offset and count) this disk has a concentric LOD pattern
3) now you can move the disk around the height map by calculating vertex offset = pos.x + pos.z * stride and using 1 draw call for each section of the disk that is visible

for a square terrain of 1024 texels and a vertex size of 16 bytes you will need 16MiB, for 2048 64MiB

you can use ushort4 for position and ushort4 for normal - leaving 3 ushorts spare for other things ... texture coords are derived from position

this is very similar to my vtf terrain - but I am swapping vtf for using more video memory

### #18turch  Members

Posted 17 February 2012 - 08:12 AM

Here is an idea that is simple to code and highly performant:

1) create a static vertex buffer with the same layout as the height texture (scan lines of texels become contiguous vertices)
2) create a static index buffer containing a disk split into 8 segments (so each disk can be rendered by setting index buffer offset and count) this disk has a concentric LOD pattern
3) now you can move the disk around the height map by calculating vertex offset = pos.x + pos.z * stride and using 1 draw call for each section of the disk that is visible

for a square terrain of 1024 texels and a vertex size of 16 bytes you will need 16MiB, for 2048 64MiB

you can use ushort4 for position and ushort4 for normal - leaving 3 ushorts spare for other things ... texture coords are derived from position

this is very similar to my vtf terrain - but I am swapping vtf for using more video memory

That is exactly what geomipmapping geoclipmapping is. You don't mention how you update the vertex heights; in the original algorithm heights were calculated on the cpu, that was later moved to the gpu by using vtf.

### #19skytiger  Members

Posted 17 February 2012 - 10:20 AM

That is exactly what geomipmapping is. You don't mention how you update the vertex heights; in the original algorithm heights were calculated on the cpu, that was later moved to the gpu by using vtf.

You need to re-read my post. It isn't geomipmapping.

The reason I didn't mention HOW I update the vertex heights is because I DON'T update them, ever. This is 100% static technique.

(edit) a pseudocode sample will help illuminate things:
DrawIndexedPrimitives(
BaseVertexIndex = (use this to position the mesh in world space using = Origin.X + Origin.Z * Stride)
,   StartIndex	  = (use this to pick a segment of the disk // the index buffer includes 360 + 180 degrees of disk)
,   PrimitiveCount  = (use this to pick how many segments to render)
)


The index buffer is a "pattern" that is positioned over the the uniform grid of vertices - I have moved the height data from a texture into a vertex buffer and instead of sampling it I use offsets to map indices to the correct vertices.

There is a good explanation here:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb147325%28v=vs.85%29.aspx

### #20turch  Members

Posted 17 February 2012 - 01:43 PM

Ah, I misunderstood what you said. So instead of storing a grid of heights in a texture you store in a vertex buffer.

In that case, what are the 8 segments that you split a disk into?

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.