Використання Vertex Textures в XNA - Все про XNA - Статті
Вступ
Вершинні текстури
- Білінійна (Bilinear) та трилінійна (Trilinear) фільтрація не підтримується на апаратному рівні. Далі буде розглянуто, як реалізувати білінійну фільтрацію у вершинному шейдері.
- Анізотропна (Anisotropic) фільтрація не підтримується на апаратному рівні.
- Автоматичний розрахунок mipmap рівня не проводиться і, якщо необхідно, розрахунок потрібно реалізовувати самим.
Необхідні ресурси та код
Ці ресурси будуть використані в цьому уроці, і вихідний код міститиме посилання на ці файли. Grid.cs
Цей клас реалізує геометрію сітки і буде використаний у Heightmap Rendering, Terrain Morphing та Steps in Snow. Властивість CellSize відповідає, наскільки більшими будуть комірки сітки, а властивість Dimension контролює розмірність сітки (скільки рядків, стовпців). Кожна вершина містить інформацію про позицію, нормалі та відповідну текстурну координату. Таким чином, кожна вершина посилається (мапиться) на піксель у текстурі і це буде використано у вершинному шейдері для маніпуляції вершинами. Механізм асоціації між вершиною та пікселем текстури є ключовим при використанні VTF. Спочатку висота для всіх вершин встановлена в 0, так що ми маємо ідеально гладку поверхню, в цьому можна переконатися, подивившись у функцію GenerateStructures (рядок 46, Grid.cs).
I. Відображення ландшафту, використовуючи карту висот
Тепер додаємо дві нові змінні до класу Game1: одну для камери та одну для сітки. Ініціалізуємо їх та вказуємо параметри у конструкторі класу. Камера має бути додана до списку компонентів, т.к. є ігровим компонентом та за зміни станів камери та її оновленнятепер відповідатиме компонентна модель XNA. Також ми маємо задати параметри сітки CellSize і Dimension, 4 і 256 відповідно. Ви можете програтися з параметром CellSize і виставляти йому різні параметри просто заради спортивного інтересу «А що буде?». Про те, що станеться якщо виставити інші параметри якості Dimension, ми поговоримо пізніше. Тепер у методі LoadGraphicsContent додайте виклик grid.LoadGraphicsContent().
Отже, у нас є геометрія, тепер нам необхідно створити файл ефекту (шейдера), який нам створить і відресує ландшафт. Додайте в проект нову папку з ім'ям "Shaders", потім до цієї папки додайте новий текстовий файл (Add -> New Item. ) з іменем "VTFDisplacement.fx". Відкрийте його і почнемо написання коду шейдера мовою HLSL (High Level Shading Language).
Нам необхідні 3 параметри матриці, для матриць світу (world), виду (view) та проекції (projection). Потім ми повинні будемо додати карту висот з ім'ям displacementMap (карта зміщення, оскільки саме в ній міститься інформація про зміщення вершин щодо площини XZ) та самплер дня її. Самплер використовуватиметься для читання даних висоти з карти висот у вершинному шейдері. Для всіх фільтрів з плеєра використовується значення Point, т.к. лінійний (Linear) та анізотропний (Anisotropic) не підтримується для вершинних текстур. Навіть якщо прописати інше значення для фільтрів, ніяких повідомлень про помилки виїдено не буде, але використовуватиметься значення Point.
Далі створимо дві структури, одна описуватиме дані, що надходять на вхід вершинному шейдеру, друга дані на виході з нього. На вхід ми будемо подавати розташування вершини (position) та її текстурні координати (uv), на виході ми отримуватимемо трансформовані вершини впросторі, а також будемо передавати в піксельний шейдер ще один «комплект» координат вершини в змінній worldPos для «розфарбовування» ґрунтуючись на даних висоти вершин. Текстурні координати просто «тунелюватимемо» через вершинний шейдер у піксельний, залишаючи без змін.
Код вершинного шейдера виглядає так:
Функція tex2Dlod читає дані висот із текстури, використовуючи текстурні координати, які створюються в класі Grid.cs. Перед тим, як координати вершини будуть перемножені з усіма матрицями для виведення на екран, ми підмінимо дані координати Y, на цьому етапі вершини будуть збудовані по висоті відповідно до даних карти висот і тільки потім відбудеться перетворення вершин в екранні координати. Усі ці дії виконує графічний процесор.
Настав час подбати про піксельного шейдера. Ми просто малюємо ландшафт розфарбовуючи у відтінки сірого, світліші тони нагорі, темні внизу. Техніка (technique) шейдера має лише один прохід (pass), що містить два наших шейдери. У параметрах компіляції вказуємо vs_3_0 та ps_3_0, т.к. VTF є функціональністю Shader Model 3.0.
Після того як ми закінчили з шейдером, повернімося до класу Game. Створіть у проекті ще одну папку з ім'ям Textures і додайте до неї файл height1.dds з архіву resources, встановіть для файлу контент процесор Texture(mipmapped). Далі нам необхідно додати до класу поля для шейдера (ефекту) та текстури.
У методі LoadGraphicsContent завантажуємо ефект та текстуру.
До методу Draw додаємо код, що встановлює параметри ефекту та код малювання сітки. Ми поміщаємо наш ландшафт у центр віртуального світу, тому матрицю світу (world) залишаємо одиничною (Identity), матриці виду (view) та проекції (projection)одержуємо з компонента камери.
На даному етапі наш додаток вдало скомпілюється і запуститься, і ви побачите щось на кшталт цього:

Поки все виглядає чудово, але давайте подивимося що станеться, якщо ми збільшимо розмір ландшафту, встановіть значення властивостей grid.CellSize = 8, grid.Dimension = 512 і значення змінної maxHeight передається в шейдер = 512. Отримуємо щось подібне до цього:

Дивимося і жахаємося, звідки у нас такі «чудові» сходи? Карта висот у нас має розмір 256 на 256 пікселів, тому поки розмірність сітки була 256, то кожен піксель текстури проектувався на одну вершину в сітці, і було все чудово. Але після того, як ми збільшили розмір сітки, один піксель став проектуватись на 2 вершини, які насправді повинні мати різну висоту, але вийшло так, що вони знаходяться на одній висоті. Якби у нас була білінійна фільтрація, то графічний процесор автоматично розрахував би середнє значення на основі даних 4 сусідніх пікселів, і поверхня була б більш згладженою. Але оскільки вершинні текстури не підтримують фільтрації, то нам доведеться самим реалізовувати білінійну фільтрацію в шейдері. Отже, відкрийте файл VTFDisplacement.fx і додамо наступний код.
Цей код реалізує білінійну фільтрацію, береться 4 прикордонні пікселі від поточних текстурних координат і між ними проводиться інтерполяція, таким чином, знаходиться середнє значення висоти вершини.
Для використання білінійної фільтрації у вершинному шейдері замініть