Компьютерная графика
Terrain и LOD: ландшафт от планеты до травинки
Microsoft Flight Simulator 2020 рендерит всю поверхность Земли - 510 миллионов км². На ноутбуке. Без подгрузок по несколько минут. Это возможно благодаря тому, что в каждый момент рендерится не вся планета, а только те тайлы и полигоны, которые реально нужны - остальное спрятано за quadtree LOD и tile streaming.
- Microsoft Flight Simulator 2020: Bing Maps Elevation + tile streaming + LOD на поверхности Земли в реальном времени
- Ghost of Tsushima: 11 км² острова с 1 м/пиксель в 60 fps через LRU tile cache и aggressive LOD
- The Witcher 3: quadtree LOD с 6 уровнями, видимость 1.5 км без просадок FPS
- Unreal Engine 5 Nanite: виртуальная геометрия без ручного LOD - автоматический cluster-based LOD для любых мешей
Heightmap: планета из одной текстуры
Microsoft Flight Simulator 2020 рендерит всю поверхность Земли - 510 миллионов км². Единственный способ хранить такой ландшафт: heightmap. 16-битное значение на пиксель - высота в метрах. 1024x1024 текстура с 1 м/пиксель = 1 км² территории. Вся планета на Bing Maps Elevation: 32 ТБ тайлов.
**Из heightmap в меш.** Тривиальный подход - сгенерировать grid из N×N вершин, каждая с высотой из текстуры. Проблема: 4096×4096 grid = 16 миллионов вершин. С tessellation шейдером можно передать CPU только грубый 64×64 grid и дать GPU добавить вершины вблизи камеры в реальном времени.
**R16 vs R32F heightmap.** 16-битный integer (65536 уровней) даёт разрешение ~1.5 мм на 100 м высоты - достаточно для игр. 32-битный float нужен для геодезически точных систем. USGS Elevation Data (публичные DEM) распространяется в формате GeoTIFF: R32F с CRS-координатами.
Почему для terrain нормали вычисляют из heightmap, а не хранят отдельно?
Quadtree LOD: меньше полигонов вдали
The Witcher 3 имеет зону видимости 1.5 км. Если рендерить весь terrain в максимальном разрешении, это 2.25 км² × 1 вершина/м² = 2.25 миллиона вершин. Глаз не различает полигоны на расстоянии 500 м. Quadtree LOD делит terrain на патчи и выбирает плотность сетки в зависимости от расстояния.
**T-junction проблема.** На границе между патчами разного LOD-уровня возникают T-junction артефакты - щели в сетке, через которые виден фон. Два решения: 1) skirts - опустить край патча вниз так, чтобы перекрыть щель; 2) морфинг - плавно двигать вершины высокодетального патча к позициям низкодетального при приближении к границе LOD.
Какую проблему решают 'skirts' в terrain quadtree LOD?
GPU Tessellation: полигоны из воздуха
DirectX 11 ввёл tessellation pipeline в 2009 году. Суть: вместо отправки миллионов вершин с CPU, отправляем грубую сетку (patch), а GPU Hull Shader задаёт фактор деления, Tessellator делит геометрически, Domain Shader читает heightmap и смещает каждую новую вершину. Результат: detail on demand без CPU-overhead.
**Displacement mapping vs normal mapping.** Normal map меняет только шейдинг нормали - силуэт объекта не меняется. Displacement mapping (через tessellation) реально смещает геометрию - объект обретает объём на краях. Для terrain это критично: скалы на горизонте должны иметь правильный силуэт. Комбинация: tessellation + displacement для крупных форм, normal map для мелких деталей.
Чем tessellation + displacement отличается от normal mapping?
Terrain Streaming: мир больше VRAM
Ghost of Tsushima имеет остров площадью 11 км² с разрешением 1 м/пиксель. 16-битный heightmap = 11 × 10^6 × 2 байт = 22 МБ только для высоты. С normal maps, albedo, roughness, splat maps - 500+ МБ. В VRAM 8 ГБ. Решение: tile-based streaming - загружать только тайлы вокруг камеры.
**Virtual Texturing (Sparse Textures).** DirectX 11.2 / OpenGL 4.4 поддерживают sparse textures - одна гигантская виртуальная текстура (128K × 128K пикселей) без аллокации всей VRAM. GPU отображает видимые тайлы в физическую память по требованию. Unreal Engine 5 использует Virtual Shadow Maps по тому же принципу для теней. Terrain virtual texturing в Assassin's Creed: Origins: одна 16K × 16K albedo карта для всего Египта.
Больше полигонов = лучше выглядит
Правило LOD: оптимальная детализация - та, где дополнительные полигоны неразличимы на целевом расстоянии. Terrain quadtree + tessellation дают нужную деталь там, где глаз видит, и экономят на остальном.
Ghost of Tsushima рендерит весь остров в 60 fps на PS4 Pro не за счёт мощи железа, а за счёт агрессивного LOD: 1 полигон/м² на расстоянии 1 км вместо 1 полигона/см². Бюджет полигонов распределён там, где нужен.
Почему terrain tile streaming использует LRU eviction вместо простой очистки при выходе из зоны видимости?
Ключевые идеи
- Heightmap: R16 текстура с высотой, нормали из центральной разности - дешевле отдельного normal map
- Quadtree LOD: рекурсивное деление патчей до Camera Distance < 2 * patch.size - меньше полигонов вдали
- T-junctions: skirts (опустить край вниз) или морфинг вершин - обязательны на LOD границах
- Tessellation: Hull Shader задаёт фактор, Domain Shader читает heightmap для каждой новой вершины
- Streaming: LRU кеш тайлов в VRAM, async load по HTTP, virtual texturing для мегатекстур
Связанные темы
Terrain LOD завершает основной цикл геометрического рендеринга.
- GPU Graphics Pipeline — Tessellation шейдеры - Hull, Tessellator, Domain - стадии GPU pipeline
- Пост-обработка — Terrain рендерится в HDR G-буфер и проходит через bloom, tone mapping
- Анимация: скелетная и морф — Растительность на terrain анимируется с учётом LOD уровня текущего патча
Вопросы для размышления
- Unreal Engine 5 Nanite убирает необходимость ручного LOD. Какой ценой? Что Nanite не может сделать, что умеет традиционный quadtree terrain?
- Как реализовать deformable terrain (воронки от взрывов) с учётом quadtree LOD и необходимости обновить нормали?
- Virtual texturing решает проблему мегатекстур. Какие новые проблемы он создаёт (feedback buffer, mip selection, latency)?
Связанные уроки
- cg-15 — Terrain проходит через тот же HDR пост-пайплайн: bloom, tone mapping
- cg-08 — Tessellation шейдер - это часть GPU graphics pipeline между VS и PS
- alg-10 — Quadtree LOD - это пространственное дерево: те же BFS/DFS обходы для culling
- cg-17 — Анимация растительности на terrain требует знания LOD уровня каждого меша
- arch-08-memory-hierarchy