Використання мегатекстур (megatexture, clipmaps)
Попередні підходи до текстурування великих ландшафтів.
1. заливання областей однією текстурою - тайлінг та тайлсети; 2. альфа-змішування текстур; 3. виведення на екран щодо невеликої частини ландшафту біля гравця.
Плюси: 1. невелика кількість текстур (невеликий обсяг даних); 2. відносна простота текстурування.
1. обмежена кількість текстур (тайлів) призводить до складнощів у отриманні потрібного малюнка, можливі комбінації завжди обмежені; 2. багато малюнку, що повторюється, на ландшафті; 3. обмеження в геометрії (наприклад, лише регулярна сітка) або навпаки, необхідність розбиття геометрії для формування тайлсетів з різними тайлами.
Що буде, якщо замислитись використовувати одну текстуру на весь ландшафт?
1. не буде тайлінгу та тайлсетів; 2. не буде необхідності робити альфа змішування різних текстур на формування кінцевого малюнка в рантаймі; 3. художник зможе просто малювати будь-яку частину ландшафту; 4. візуально реалізм створюваного ландшафту може бути збільшений у рази; 5. геометрія ландшафту може бути представлена як регулярною сіткою, і будь-яким мішом; 6. не буде потреби бити геометрію з метою текстурування.
Мінуси: 1. обсяг текстури для всього ландшафту займатиме чимало місця; 2. для її підготовки знадобляться спеціальні інструменти та потужні комп'ютери.
Чесно кажучи, я не впевнений, що це явно мінуси, так як текстуру можна потиснути, а мати швидкі комп'ютери завжди чудово.
Спробуємо вивести ландшафт із унікальним малюнком.
Для цього завантажимо в GPU текстуру високої роздільної здатності всього ландшафту, зрозуміло, з усіма її рівнями деталізації (mipmaps абоі виведемо всю геометрію ландшафту. GPU сам вибере потрібний човен для розтеризації конкретного пікселя на екрані (або кілька човнів залежно від установок). Наприклад, для ближнього до камери пікселя буде обрано піксель із деталізованого човна, для далекого – навпаки.
4096*4096*4=64 Мб (при 32 бітах на піксель)
З човнами текстура займе понад 85 Мб. Що робити, якщо розмір вихідної текстури не 4096, а 8192 на 8192 пікселів? Це вже 341 Мб з усіма човнами. А якщо більше? Наприклад, 1 квадратний км з роздільною здатністю 1 піксель на 10 см буде покривати мегатекстура з роздільною здатністю 10000 на 10000 пікселів. Адже 1 піксель на 10 см - це далеко не найбажаніша якість!
Цілком зрозуміло, що при таких обсягах GPU помре. Використання стиснення текстури не вирішить проблему кардинально, а лише змінить максимально можливий дозвіл.
Очевидно, що такий спосіб не має спільного рішення, і його можна застосувати тільки в окремих випадках для невеликих ландшафтів і невеликих текстур.
Так що ж, забути про одну детальну текстуру на весь ландшафт?
Давайте поміркуємо. Ми знаємо, що GPU для розтеризації далекого пікселя візьме човен текстури більш простий, ніж для розтеризації ближнього пікселя, але в пам'яті GPU будуть всі човни!
А навіщо тоді вантажити човен високої деталізації у GPU при розтеризації далекого пікселя? Як зробити так, щоб зайві човни не вантажилися? Про це у наступній частині статті.
Мегатекстура
Для більш повного представлення суті питання пропоную завантажити мій приклад з використанням мегатекстури (вихідники програми наприкінці статті): https://github.com/u… gatexture-bin


Сама мегатекстура (textures/mega-8192.tga) маєроздільна здатність 8192 на 8192 і займає 200Мб (24 біт на піксель).
Програма запуску (test.exe) знаходиться в папці bin. У перший запуск програма відкомпілює мегатекстуру, це може зайняти кілька хвилин, не переривайте програму, вона створюватиме файли в папці textures/mega-8192 (і займе ще 260 Мб на гвинті). Після того, як вихідний текстури відкомпілюється, його (textures/mega-8192.tga) можна буде видалити (якщо він Вам не потрібен).
Клавіші керування виводяться в самій програмі на екрані (стрілки курсору, LSHIFT – вгору, LCRTL – вниз, M (англ) – показати/прибрати човни).
Отже, у попередній частині ми з'ясували, що при розтеризації далеких пікселів у GPU бажано не завантажувати деталізовані човни (вони не використовуються для розтеризації), а для розтеризації ближніх пікселів все з точністю навпаки. Інтуїтивно розумієш, що це може заощадити багато пам'яті, але скільки? Давайте прийдемо до цього поступово.
Припустимо, гравець знаходиться в центрі ландшафту, тоді рівні деталізації текстури ландшафту, які потрібні та використовуються GPU для растеризації, будуть виглядати приблизно так:

Зелений квадрат має найкращу деталізацію, далі синій, жовтий та малиновий. Кожен наступний займає площу на ландшафті вчетверо більше і має вчетверо гіршу деталізацію, ніж попередній квадрат. А теперувага, Вам зрозуміло, що роздільна здатність частини текстури, що охоплюється квадратами (з урахуванням її деталізації) однакова? Тобто. текстура, яка буде створена під зелений квадрат, матиме такий самий дозвіл, як і під найбільший – малиновий.
Схема 2 (вид збоку).
Коли я сказав про текстуру для зеленого квадрата, Ви не дочули. Нам не потрібна вся деталізована мегатекстура для того, щобпобудувати вид з очей гравця, що знаходиться у центрі ландшафту. Потрібна лише невелика частина довкола нього. Теж стосується і для інших рівнів деталізації, поки ми не дійдемо до останнього човна, що містить зменшену копію всієї мегатекстури.
Необхідні частини мегатекстури для конкретних рівнів деталізації можна собі уявити з наступної схеми:

Горизонтальні пунктирні лінії показують, яку площу мегатекстури повинні містити відповідні рівні деталізації.
У цій схемі (прикладі) камера знаходиться досить високо над ландшафтом, це призвело до того, що найдеталізованіший рівень (зелене коло на схемі) не стосується ландшафту, отже, його ми може взагалі не вантажити в GPU! Це один із можливих шляхів оптимізації.
Після того як у рантаймі будуть сформовані потрібні частини мегатекстури, залишається тільки вивести для кожного рівня деталізації геометрію ландшафту, яку він охоплює. Можливо, поки що не дуже зрозуміло, але я пропоную зараз не зупинятися на цьому, оскільки в самій технології clipmaps техніка розтеризації буде більш простою.
Нехай гравець стоїть на самому ландшафті, а не літає десь у хмарах (тобто будемо вести підрахунок для всіх рівнів деталізації). Візьмемо розмір clipmap 512 на 512 пікселів (512 clipmap). Clipmap - це область, яка вирізається з мегатекстури навколо гравця для кожного рівня деталізації (лода). Чим вона менша, тим менше деталізованих пікселів бачитиме гравець перед собою, тим швидше рівні деталізації змінюватимуться менш деталізованими. Отже, поїхали:

От і все! Вийшло 5 човнів по 512х512 пікселів кожен. Разом: 512*512*5*4 = 5 Мб (при 32 бітах на піксель). Формула така: ClipmapWidth * ClipmapHeight * LodsNumber * BytesPerPixel.
На мій погляд, найбільш оптимальні розміри clipmap (на поточний момент часу) знаходяться в межах від 1024 до 2048.
До речі, не обов'язково робити розмір clipmap і дозвіл мегатекстури кратним ступеня 2!