Rendering Large Terrain

Okay, so is it possible to use only one very big compressed heightmap texture (i.e. bigger than 4096x4096 pixels) for whole landscape?

I’m sorry I’m engaged at work for more than 12 hours these days and have no time to give a complete answer but I’ll try to help in a few sentences.

This proves you actually don’t understand clipmaps.
For a flat terrain, you need a single texture array for storing heights. The paper is rather old. In those days texture arrays didn’t exist, hence they probably used several textures, a single texture for each level.

Unlike full mipmaps that have exponential growth with each new level, clipmaps have linear growth. They enable caching relevant parts of mipmap levels resulting in consistent display of a texture occupying several pentabytes by using just several hundreds of megabytes.

“Render to texture” is a quite common technique. It is strange you haven’t heard about it. It is not necessary to use “render to texture” with clipmaps. For example, I’m using glTexSubImage3D() for a level update. The rendering to a level enables filling a level with the data of the coarser one and have a consistent draw without waiting for the proper resolution data or disabling level not properly updated yet. All in all, desirable but not mandatory feature for a clipmap update.

I can’t think of any other approach than the obvious two: either you have the whole terrain in memory or you only have chunks and stream the chunks you need (also, with sparse textures this can get very efficient).

For God’s sake, NO!
Clipmaps are a diametrically opposite approach to chunked LOD. The whole terrain, as I’ve already said, can occupy several pentabytes. That cannot be stored even on a hard disk. The point of a clipmap is to cache just portions of the levels of the full mipmap that are relevant for the rendering. The levels are updated toroidally.

IIRC, the clipmaps paper proposes a decompression stage on the GPU (and a compression stage on the CPU) so they can get their complete height-map down to 400 something MBs in VRAM.

They demonstrated a very efficient compression/decompression scheme. My respect! But it is not enough for all purposes. I suggest an out-of-core approach where required data are read from the disk or even network. Also, I suggest using the same approach for the heights as for the texture-overlay.

Not recommended. A single texture array yes, but a single texture certainly not!
512x512 pix height-map levels are pretty acceptable for a full HD displays. The texture overlay should have at least 2048x2048 pix size. 4Kx4K is OK for 4K displays, but the update cost is usually high for the highest possible sharpness of the finest level. Generally, the size of the level should be greater or equal to the screen size in order to have valid display.

Never mind, I am also not frequently on the internet.

“Render to texture” is a quite common technique. It is strange you haven’t heard about it.

Yes of course, I know what it basically means “rendering to a texture”. But I have never heard how to do it in the fragment shader :).

But I think I finally understand the basic idea of clipmaps.
So, I need a single 3D texture or a single 2D texture array where for example the top layer represents ONLY the small square around the viewer in high resolution and the bottom layer represents the coarsest level and In such a way the farthest marginal ring in lowest resolution and therefore the center of the lower layers is never used. And as the viewer moves I should update the heightmap textures by runtime loading data (for example) from a file. Do I understand it correctly?

Basically, yes. You’ve got it. :slight_smile:
But never use 3D texture, just 2D texture array. Also, never update from the hard disk. Use a memory cache instead (make a clipmap also in RAM, update it from the files on a disk and use it to update GPU clipmaps). Update of a GPU clipmap is usually very fine and extremely fast. Sometimes only a 4pix wide strip. While update of the clipmap’s cache stored in the RAM is very coarse and slow (updated using tiles stored in files).

I am also glad I have quite got it :slight_smile:

Use a memory cache instead (make a clipmap also in RAM, update it from the files on a disk and use it to update GPU clipmaps).

Could you explain it more in detail? I am sorry, I am not a professional of your format :smiley: .

Well, let’s say we have a clipmap with the level size of 2048x2048 texels. If we want to go east, we need to update some levels. Also, let’s we have texture tiles on the disk of size 1024x1024 tex. The smallest update of a level is 4x2048 tex. Direct update from the files require 3 tiles read (3x1024x1024), and extracting proper 4 texel wide strip from them. OS certainly caches disk reads, and the files are probably in the memory, if we have already accessed them in the near past. But, that cache is not spatially organized, because Windows knows nothing about our algorithm. Also, there is an additional task to extract required data and repacking.

We would save a lot of time if we create a clipmap in the main memory that contains the certain number of tiles in each level. Instead of fine update, like GPU clipmap requires, RAM cache is updated by the whole tile row or column. It is much coarser, but suitable for disk access.

I am sorry, I haven’t been here for a long time, I was working on the buffers for rendering the levels and I also had another work so I was busy.

Allright, so I should have tiles where I store the heights and from those tiles I should update the final height texture array used for the clipmap and I should copy the pixels /for example/ using glGetTexImage and glTexSubimage3D?

Now I only must invent algorythms for proper updating :smiley:

Why do you need glGetTexImage()?

Why do you need glGetTexImage()?

I thought that I need it to copy pixels from the tile texture to the final height texture used in the clipmap when updating the clipmap. Is there another / simpler / way to do this? I would welcome it.

Or how can I update the clipmap when I am moving across the terrain? Could you please put it simply so I can understand it better?

When I talked about the mem cache, I didn’t mean graphics card memory. The cache is in the main memory. So, use regular way to cut proper rectangle from it and send to the texture.
You won’t have enough memory to keep the cache in the graphics memory. Or, maybe I’m wrong… :slight_smile:
On the other hand, there would be unnecessarily huge transfer to the GPU when new tiles are read from the disk. Dozens of MB instead of few kB required.

Use toroidal update as described in all clipmaps papers. If the viewer’s distance from the center of the current level is greater than some threshold (defined by the border size - the amount of texture reserved for the update), you should send request for the update. The threshold should be checked in both directions (send a separate request for each direction). As an answer to that request, the data provider should check the cache, cut proper strips and send then to the texture level that needs update. In the request/response you should code the direction of update so the level knows which part of the texture should be updated when the response comes.

The cache is in the main memory. So, use regular way to cut proper rectangle from it and send to the texture.
You won’t have enough memory to keep the cache in the graphics memory.

So can I store the heights data for example as an array?

Use toroidal update as described in all clipmaps papers.

Ou yeah, I think I finally understand it :smiley: It looks that as I moves along the height texture for example to the right I must add new heights data (resp. overwrite the old data) on the left border of the texture and as I move on I am simply adding data to the right side of previously added data(resp. overwrite the old data)… And when I reach the right border of the texture I automatically jump to the left border. Do I understand it correctly?