Войти
ПрограммированиеСтатьиГрафика

Использование мегатекстур (megatexture, clipmaps).

Автор:

В данной статье пойдет речь о том, как вывести изображение ландшафта, который покрыт одной большой, ну просто огромной текстурой (занимающей мегабайты, а то и гигабайты дискового пространства). И все это на обычных видеокартах. Есть исходники на C++!

Изображение

Введение
Предыдущие подходы к текстурированию больших ландшафтов.
  Подсчет требуемой видеопамяти для растеризации.
Мегатекстура
  Подсчет требуемой видео памяти для растеризации.
  Таблица требуемой видео памяти для разных мегатекстур и размеров clipmap.
Clipmaps.
Оптимизация.
Некоторые схемы технологии clipmaps, говорящие сами за себя.
Персонажи в игре и др. объекты.
Выводы.
Различия технологий Megatexture и Clipmaps.
Скачать.
Вопросы?
Используемый материал.

Введение

Всё, что написано в данной статье, это лично мое мнение, основанное на доступных в Интернете материалах по данной тематике и личном опыте. Но я не претендую на последнюю инстанцию, а лишь надеюсь, что моя статья поможет вам разобраться в трюках мегатекстурирования и понять тот потенциал, который открывается с применением этой технологии.

Предыдущие подходы к текстурированию больших ландшафтов.

1. заливка областей одной текстурой – тайлинг и тайлсеты;
2. альфа-смешивание текстур;
3. вывод на экран относительно небольшой части ландшафта около игрока.

Плюсы:
1. небольшое количество текстур (небольшой объем данных);
2. относительная простота текстурирования.

Минусы:

1. ограниченное количество текстур (тайлов) приводит к сложностям в получении нужного рисунка, возможные комбинации всегда ограничены;
2. много повторяющегося рисунка на ландшафте;
3. ограничение в геометрии (например, только регулярная сетка) или наоборот, необходимость разбиения геометрии для формирования тайлсетов с разными тайлами.

Что будет, если задумать использовать одну текстуру на весь ландшафт?

Плюсы:

1. не будет тайлинга и тайлсетов;
2. не будет необходимости делать альфа смешивания разных текстур для формирования конечного рисунка в рантайме;
3. художник сможет просто рисовать любую часть ландшафта;
4. визуально реализм создаваемого ландшафта может быть увеличен в разы;
5. геометрия ландшафта может быть представлено как регулярной сеткой, так и любым мешем;
6. не будет необходимости бить геометрию для целей текстурирования.

Минусы:
1. объем текстуры для всего ландшафта будет занимать не мало места;
2. для ее подготовки понадобятся специальные инструменты и мощные компьютеры.

Честно говоря, я не уверен, что это явно минусы, так как текстуру можно пожать, а иметь быстрые компьютеры всегда здорово :)

Попробуем вывести ландшафт с уникальным рисунком.

Для этого загрузим в GPU текстуру высокого разрешения всего ландшафта, разумеется, со всеми ее уровнями детализации (mipmaps или лодами) и выведем всю геометрию ландшафта. GPU сам выберет нужный лод для растеризации конкретного пикселя на экране (или несколько лодов, в зависимости от установок). Например, для ближнего к камере пикселя будет выбран пиксель из детализированного лода, для дальнего – наоборот.

Все это понятно, но возьмем пример и подсчитаем необходимые объемы видеопамяти.

Подсчет требуемой видеопамяти для растеризации.

Пусть текстура нашего ландшафта будет иметь размер 4096 на 4096 пикселей. Первое ограничение, на которое мы наталкиваемся, это максимально поддерживаемое разрешение текстуры, которое может обрабатывать GPU. Далеко не все GPU могут работать с разрешением 4096 на 4096 пикселей (дело даже не 4096, т.к. всегда можно подобрать такое разрешение, которое не будет поддерживаться даже самой современной видео картой). Эта проблема может быть решена путем разрезания исходной текстуры на части. Тут довольно все просто, хотя не все! Разрезание может привести к необходимости разделения геометрии в местах стыка разных текстур, чтобы избежать попытки наложения на разные части одного треугольника двух и более текстур (несомненно, это усложнит геометрию, либо внесет дополнительные правила текстурирования). Вторая проблема – это объем памяти занимаемый текстурой. Для несжатой текстуры в нашем случае это:

4096 * 4096 * 4 = 64 Мб (при 32 битах на пиксель)

С лодами текстура займет более 85 Мб. А что делать, если размер исходной текстуры не 4096, а 8192 на 8192 пикселей? Это уже 341 Мб со всеми лодами. А если больше? Например, 1 квадратный км с разрешением 1 пиксель на 10 см будет покрывать мегатекстура с разрешением 10000 на 10000 пикселей. А ведь 1 пиксель на 10 см – это далеко не самое желаемое качество!

Совершено понятно, что при таких объемах GPU умрет. Использование сжатия текстуры не решит проблему кардинально, а лишь изменит максимально возможное разрешение.

Итого: очевидно, что такой способ не имеет общего решения, и его можно применить только в частных случаях для небольших ландшафтов и не больших текстур.

Так что же, забыть об одной детализированной текстуре на весь ландшафт?

Давайте поразмыслим. Мы знаем, что GPU для растеризации дальнего пикселя возьмет лод текстуры более простой, чем для растеризации ближнего пикселя, но в памяти GPU будут находиться все лоды!

А зачем тогда грузить лод высокой детализации в GPU при растеризации дальнего пикселя? Как сделать так, чтобы лишние лоды не грузились? Об этом в следующей части статьи.

Мегатекстура

Для более полного представления сути вопроса, предлагаю загрузить мой пример с использованием мегатекстуры (исходники программы в конце статьи):
https://github.com/unitpoint/xform-megatexture-bin

xForm2-mega-01 | Использование мегатекстур (megatexture, clipmaps).

xForm2-mega-02 | Использование мегатекстур (megatexture, clipmaps).

Сама мегатекстура (textures/mega-8192.tga) имеет разрешение 8192 на 8192 и занимает 200Мб (24 бит на пиксель).

Программа для запуска (test.exe) находится в папке bin. В первый запуск программа откомпилирует мегатекстуру, это может занять несколько минут, не прерывайте программу, она будет создавать файлы в папке textures/mega-8192 (и займет еще 260 Мб на «винте»). После того, как исходник текстуры откомпилируется, его (textures/mega-8192.tga) можно будет удалить (если он Вам не нужен).

Клавиши управления выводятся в самой программе на экране (стрелки курсора, LSHIFT – вверх, LCRTL – вниз, M (анг) – показать/убрать лоды).

Итак, в предыдущей части мы выяснили, что при  растеризации дальних пикселей в GPU желательно не загружать детализированные лоды (они не используются для растеризации), а для растеризации ближних пикселей все с точностью наоборот. Интуитивно понимаешь, что это может сэкономить много памяти, но сколько? Давайте придем к этому постепенно.

Предположим, игрок находится в центре ландшафта, тогда уровни детализации текстуры ландшафта, требуемые и используемые GPU для растеризации, будут выглядеть примерно так:

mega-01-lo | Использование мегатекстур (megatexture, clipmaps).
Схема 1.

Зеленый квадрат имеет самую лучшую детализацию, далее синий, желтый и малиновый. Каждый последующий занимает площадь на ландшафте в четыре раза больше и имеет в четыре раза худшую детализацию, чем предыдущий квадрат. А теперь внимание, Вам понятно, что разрешение части текстуры, охватываемой квадратами (с учетом ее детализации) одинаковое? Т.е. текстура, которая будет создана под зеленый квадрат, будет иметь такое же разрешение, как и под самый большой – малиновый.

Изображение
Схема 2 (вид сбоку).

Когда я сказал про текстуру для зеленого квадрата, Вы не ослышались. Нам не нужна вся детализированная мегатекстура для того, чтобы построить вид из глаз игрока, находящегося в центре ландшафта. Нужна лишь небольшая часть вокруг него. Тоже касается и для остальных уровней детализации, пока мы не дойдем до последнего лода, который содержит уменьшенную копию всей мегатекстуры.

Необходимые части мегатекстуры для конкретных уровней детализации можно себе представить исходя из следующей схемы:

mega-03-lo | Использование мегатекстур (megatexture, clipmaps).
Схема 3.

Горизонтальные пунктирные линии показывают, какую площадь мегатекстуры должны содержать соответствующие уровни детализации.

В данной схеме (примере) камера находится достаточно высоко над ландшафтом, это привело к тому, что самый детализированный уровень (зеленый круг на схеме) не касается  ландшафта, значит, его мы может вообще не грузить в GPU! Это один из возможных путей оптимизации.

После того как в рантайме будут сформированы нужные части мегатекстуры, остается только вывести для каждого используемого уровня детализации геометрию ландшафта, которую он охватывает. Возможно, пока не очень понятно, но я предлагаю сейчас не останавливаться на этом, так как в самой технологии clipmaps техника растеризации будет более простой.

Подсчет требуемой видео памяти для растеризации.

Теперь давайте подсчитаем, сколько понадобиться видеопамяти для растеризации ландшафта покрытого мегатекстурой 8192 на 8192 пикселей.

Пусть игрок стоит на самом ландшафте, а не летает где-то в облаках (т.е. будем вести подсчет для всех уровней детализации). Возьмем размер clipmap 512 на 512 пикселей (512 clipmap). Clipmap – это область, которая вырезается из мегатекстуры вокруг игрока для каждого уровня детализации (лода). Чем она меньше, тем меньше детализированных пикселей будет видеть игрок перед собой, тем быстрее уровни детализации будут сменяться менее детализированными. Итак, поехали:

Изображение

Вот и все!
Получилось 5 лодов по 512х512 пикселей каждый. Итого: 512 * 512 * 5 * 4 = 5 Мб (при 32 битах на пиксель). Формула следующая:
ClipmapWidth * ClipmapHeight * LodsNumber * BytesPerPixel.

Таблица требуемой видео памяти для разных мегатекстур и размеров clipmap.

Изображение

На мой взгляд, наиболее оптимальные размеры clipmap (на текущий момент времени) находятся в приделах от 1024 до 2048.

Кстати, совершено не обязательно делать размер clipmap и разрешение мегатекстуры кратным степени 2!

Страницы: 1 2 Следующая »

#clipmaps, #cliptexture, #megatexture, #мегатекстура

9 ноября 2007 (Обновление: 30 июля 2014)

Комментарии [509]