Какие способы оптимизации применить для отрисовки большого terrain?
Что проверяют
Понимаете ли вы, что большой террейн нельзя отрисовать одной сеткой, и знаете ли, как делить его по пространству и по детализации. Следом обычно спрашивают про швы между уровнями LOD и про то, как не ловить фризы при подгрузке.
Как отвечать
Для C# это чаще всего Unity, поэтому покажите и общие алгоритмы, и настройки движка.
- чанки и квадродерево: мир режется на тайлы, дерево быстро отвечает, что видно и с какой детализацией;
- LOD по расстоянию: geomipmapping, CDLOD или geometry clipmaps. Каждый следующий уровень примерно вчетверо беднее по вершинам;
- отсечение: frustum culling по AABB чанка, для гор и крупных построек ещё и occlusion culling;
- высоты на GPU: одна переиспользуемая сетка, вершинный шейдер смещает её по карте высот, вблизи можно добавить тесселяцию;
- текстуры: splatmap смешивает несколько слоёв, слои лежат в
Texture2DArray, для отвесных скал triplanar-проекция; - растительность: GPU instancing через
Graphics.RenderMeshInstanced, для десятков тысяч объектов indirect-вариант, вдали билборды и импостеры; - стриминг: чанки грузятся асинхронно вокруг игрока, генерация сетки уходит в Jobs и Burst через
Mesh.MeshData, главный поток получает только готовый результат; - встроенный
Terrain:heightmapPixelErrorзадаёт агрессивность LOD,drawInstancedснижает число вызовов отрисовки, дальшеbasemapDistanceрисуется запечённая низкодетальная текстура, коллайдер строится по более грубой сетке.
Хороший ответ заканчивается тем, как вы проверяете эффект: Frame Debugger для числа вызовов отрисовки, Profiler для времени кадра на CPU и GPU.
Где спотыкаются
Делают LOD, но забывают про стыки. На границе чанков разной детализации появляются трещины, их закрывают «юбками» по краю или сшиванием соседних сеток.
Генерируют и заливают меши на главном потоке. Средний FPS выглядит прилично, а при каждом подгруженном чанке игра дёргается.
Не думают о точности float. На удалении в десятки километров от начала координат вершины и камера начинают дрожать, и лечится это плавающим началом координат (floating origin), а не ещё одним уровнем LOD.