Steps3D - Tutorials - Reflective bumpmapping in OpenGL
У стандартному OpenGL підтримується так званийenvironment mapping- коли за допомогою текстури моделюється відображення об'єктом навколишнього середовища. Для цього використовується спеціальний режим обчислення текстурних координат у вершинах і ці значення інтерполуються вздовж граней при їхньому текстуруванні.

Рис 1. Прикладenvironment mapping
Стандартний OpenGL підтримує лише один тип таких текстур - карт відображення (environment maps) - сферичні. Використання розширення ARB_texture_cube_map вводить ще одну карту відображення - кубічні карти.
Кубічні карти, що є просто видом на довкілля в шести напрямках, набагато зручніші, ніж сферичні. Однак і в тому і в іншому випадку текстурні координати відповідають випадку відображення тільки в вершинах, а в інших точках значення текстурних координат виходить шляхом інтерполяції, тобто. є лише наближеними до істинних.
Розглянемо докладніше як відбувається обчислення відбитого вектора і як це може бути реалізовано попиксельно.
Нехай у точціPповерхні об'єкта (рис 2.) заданий одиничний векторvнапрями на спостерігача і одиничний вектор нормаліn.

Рис 2. Обчислення відображеного вектора
Тоді відображений векторr(як легко переконатися, він також буде одиничним) буде задаватися такою формулою:
Якщо хочемо кожному пікселу побудувати точний відбитий вектор, використовуючи карту нормалей, це рівняння необхідно вирішувати кожному пікселу об'єкта.
Можна помітно спростити обчислення відображеного вектора, якщо використовувати таке спрощення - карта нормалей відхиляє векторнормалі від значення нормалі для всієї грані. Це відхилення викликає, у свою чергу, відхилення відбитого вектора від значення, одержуваного в стандартному environment mapping :
Таким чином, можна перейти від використання карти норматей до використанняoffset-тектури, яка використовується для зміни текстурних координат, що відповідають відображеному вектору.
Тому можна змоделювати відображення з урахуванням карти нормалей за допомогою спотворення текстурних координат за допомогоюoffset-тектури. Цей підхід отримав назву Environment Map Bump Mapping або EMBM.
Для його реалізації можна використовувати розширенняNV_texture_shaderта шейдер GL_OFFSET_TEXTURE_2D_NV. Цей шейдер використовує двокомпонентну текстуру (DSDT), де кожна компонента являє собою речове число з діапазону [-1,1], представлене одним байтом (dsабоdt).
Пара чисел (ds,dt) взятих з цієї текстури множиться на задану користувачем речову матрицю розміром 2 на 2 для отримання вектора зсуву, що додається до текстурних координат наступного текстурного блоку.
Використання матриці 2 на 2 дозволяє досягти відразу двох цілей:
- встановити масштабування (оскількиdsіdtзадаються з досить невисокою точністю);
- врахувати поворот грані навколо її вектора нормалі (за рахунок використання матриці повороту на заданий кут)
Об'єднавши масштабування і поворот ми отримаємо матрицю 2 на 2, яка буде служити для відображення значеньoffset-тектури в відхилення текстурних координат для наступного блокуenvironment mapping.
Незважаючи на свою простоту, цей метод дає лише наближення до точного.відображення і добре працює лише для плоских об'єктів та дуже невеликих відхилень.
Крім того, він застосовується лише до сферичних карт відображення.
З іншого боку, використання розширенняNV_texture_shaderдозволяє крім розглянутого наближеного вище способу (EMBM), здійснити точне обчислення значень відображеного вектора для кожного фрагмента і використання отриманого значення для доступу до кубічної карти відображення.
Для цього можна використовувати шейдер GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV. При цьому обчислення використовуються всі чотири кроки текстурування (texturing stages):
- Крок 0. Шейдер GL_TEXTURE_2D. Як текстура використовується карта нормалей
- Крок 1. Шейдер GL_DOT_PRODUCT_NV
- Крок 2. Шейдер GL_DOT_PRODUCT_NV
- Крок 3. Шейдер GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV. Як текстура використовується кубічна карта відображення
При цьому вся інформація, необхідна для обчислення відображеного вектора для кожного фрагмента передається в текстурних координатах перших трьох текстурних кроків (s i , t i , r i , q i ) .
У координатахqiпередаються координати положення спостерігача (eye).
Ми вважаємо, що простір спостерігача (eye-space) збігається з тим простором, у якому задана кубічна карта відображення (cubic environment map), тобто. осі цієї системи координат паралельні ребрам куба, межі якого накладається кубічна текстура (сам спостерігач у своїй перебуває у центрі цього куба).

Рис 3. Орієнтація кубічної системи координат.
Для отримання правильного відображення необхідно перевести вектор нормаліnз дотичного простору (у якомуnзадано в карті нормалей) у простіркубічної карти (у разі воно збігається з простором спостерігача).
Переведення вектораnу простір спостерігача здійснюється за допомогою множення його на матрицю перетворенняT.
Як матрицяTвиступає твір двох матриць - верхньої лівої 3*3 підматрицею матриціmodelview, івертованої та транспонованої (її ми будемо далі позначати якM 3x3 -T) і матриці складеної з базисних векторів дотичного просторуS=(t,b,n):
Рядки цієї матриці і виступають як перші три компоненти текстурних координат для кожного текстурного блоку:
(s 1 ,t 1 ,r 1 )=(T 0,0 ,T 0,1 ,T 0,2 )
(s 2 ,t 2 ,r 2 )=(T 1,0 ,T 1,1 ,T 1,2 )
(s 3 ,t 3 ,r 3 )=(T 2,0 ,T 2,1 ,T 2,2 )
Шейдер GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV за перетвореною за допомогою матриціTнормаліn'(зверніть увагу, що перетворена нормаль може вже не бути одиничною) та положення спостерігачаeyeдля кожного фрагмента обчислює відображений вектор:
Далі відбитий вектор використовується для доступу до кубічної карти відображення.
Розглянемо тепер практичну реалізацію цього підходу - побудова зображення тора, що відбиває навколишнє середовище, поверхню якого накладена карта нормалей.
За основу класу, що використовується для представлення тора, можна взяти клас Torus, використаний нами при обчисленні попіксельного відблисків, додавши в клас Vertex метод, що служить для отримання матриціT:
Вхідним параметром для методуbuildTransformMatrixслужить інвертована і транспонована верхня ліва підматрицяmodelviewматриці (оскільки вона однакова для всіх вершин).
Вихідним параметром є матриця перетворенняT.
Процедура виведення тора виглядає тепер так:
Для роботи програми потрібно правильне налаштування OpenGL - необхідно налаштувати іregister combiner'и таtexture stages.
Нижче наводиться зображення тора з накладеною на нього картою нормалей, що відображає середовище, задане кубічною картою.

Мал. 4. Зображення тора з картою нормалей, з environment mapping
Вихідний код до цієї статті можна завантажити тут.
Під час підготовки статті використовувалися матеріали компанії NVIDIA.
Додаткову інформацію можна знайти на сайті компанії NVIDIA.