Створення текстури в оперативній пам'яті
Зображення текстур часто зберігаються в файлах. Для прискорення обчислень в OpenGL розміри зображень текстур повинні бути кратні ступеням 2, тобто рівні 2 n x2 m. де n і m цілі числа. Для відображення подібної текстури на об'єкті необхідно виконати кілька послідовних дій:
1) Завантажити зображення текстури в пам'ять з графічного файлу.
2) Створити ідентифікатор (ім'я) текстури.
3) Зробити ідентифікатор текстури активним.
4) Створити текстуру в пам'яті.
5) Встановити властивості текстури.
6) Встановити властивості взаємодії текстури з об'єктом.
7) Дозволити відображення текстур викликом glEnable (GL_TEXTURE_2D).
8) Зв'язати координати текстури з об'єктом.
9) Якщо текстури більше не потрібні, заборонити їх відображення викликом glDisable (GL_TEXTURE_2D).
Розглянемо найпростіший випадок використання текстури - накладення текстури на плоский багатокутник. Для демонстрації роботи з декількома текстурами будемо вважати, що потрібно виконати відображення двох різних текстур на три видимі межі куба (одну текстуру на передню по відношенню до спостерігача грань куба, два примірники іншої текстури - на верхню і бічну грані).
У програмі 7.1 для кожної текстури заведені дві глобальні змінні:
unsigned int falls_tex;
unsigned int sawdust_tex;
Змінні falls_tex і sawdust_tex служать ідентифікаторами текстур, а falls_image і sawdust_image призначені для зберігання зображень текстур з файлів з іменами falls_filename і sawdust_filename. Завантаження зображень в пам'ять проводиться в функції ініціалізації текстур textures_init ():
falls_image = auxDIBImageLoad (falls_filename);
sawdust_image = auxDIBImageLoad (sawdust_filename);
Після завантаження зображень треба створити ідентифікатори текстур. Ідентифікатори - це цілі числа, що дозволяють відрізняти текстури один від одного. Якщо текстура лише одна, то ідентифікатор для неї не обов'язковий. Для створення ідентифікаторів служить функція glGenTextures ():
void glGenTextures (int n, unsigned int * textures);
Параметр n задає кількість створюваних ідентифікаторів текстур, а параметр textures є покажчиком на масив, куди будуть поміщені ці ідентифікатори. Розмір цього масиву повинен бути не менше n. Наприклад, створити десять ідентифікаторів текстур можна викликом:
unsigned int ids [10];
glGenTextures (10, ids);
У масиві зручно зберігати ідентифікатори однотипних текстур, наприклад, різні види трави або листя при імітації ландшафтів. У програмі 7.1 ідентифікатори текстур зберігаються в окремих змінних, тому при ініціалізації текстур створюються два різних ідентифікатора:
glGenTextures (1, falls_tex);
glGenTextures (1, sawdust_tex);
Після створення ідентифікаторів обидві текстури по черзі вибираються активними і для них задаються властивості. Вибір активної текстури виконується функцією glBindTexture ():
void glBindTexture (Glenum target, unsigned int texture);
Параметр target вказує тип текстури - GL_TEXTURE_2D (двовимірна) або GL_TEXTURE_1D (одномірна). Далі будемо розглядати тільки двовимірні текстури. Параметр texture є ідентифікатором текстури, яку треба зробити активною. Наприклад, щоб зробити активної текстуру falls_tex, треба викликати функцію так:
glBindTexture (GL_TEXTURE_2D, falls_tex);
Хоча зображення текстури falls_tex вже завантажено з файлу в змінну falls_image типу AUX_RGBImageRec, але сама текстура ще створена. Крім байт зображення, у текстури є набір властивостей, що впливають на накладення текстури на об'єкт. Наприклад, це рівень деталізації, спосіб масштабування і зв'язування текстури з об'єктом. Ці властивості задаються при створенні текстури.
За допомогою рівня деталізації можна задати кілька зображень для однієї текстури, що дозволяє більш точно накладати текстуру на об'єкти, розміри двовимірних проекцій яких менші розмірів текстури. Нульовий рівень деталізації відповідає вихідного зображення розміром 2 n x2 m. перший рівень - 2 n-1 x2 m-1. k -ий рівень - 2 n-k x2 m-k. Число можливих рівнів дорівнює min (n, m).
Для створення текстури використовується функція glTexImage2D () або gluBuild2DMipmaps ():
void glTexImage2D (GLenum target, int level, int components,
int width, int height, int border, GLenum format,
GLenum type, const void * pixels);
int gluBuild2DMipmaps (GLenum target, int components, int width,
int height, GLenum format, GLenum type, const void * data);
Перша функція створює текстуру одного певного рівня деталізації (level) і працює тільки з зображеннями, розміри яких кратні ступеням 2. Функція gluBuild2DMipmaps () більш універсальна. Вона генерує текстури всіх рівнів деталізації і не накладає обмежень на розміри зображення. Ця функція сама встановлює масштаб зображення необхідним чином, але результати можуть виявитися не надто якісними. Перед першим викликом будь-якої з функцій створення текстури треба обов'язково викликати glPixelStorei (), яка задає спосіб зберігання рядків зображення в пам'яті (на скільки байт вирівнюється рядок).
Розглянемо призначення параметрів функції glTexImage2D ():
target - розмірність текстури (для двовимірної текстури GL_TEXTURE_2D);
level - рівень деталізації. Для вихідного зображення level = 0;
components - кількість компонент кольору в зображенні (для зображення у форматі RGB components = 3);
width і height - ширина і висота зображення;
border - ширина кордону, якщо кордону немає, то border = 0;
format - формат зображення (зазвичай GL_RGB);
type - тип даних пікселів зображення (зазвичай GL_UNSIGNED_BYTE);
pixels - покажчик на масив пікселів зображення.
Наприклад, створення текстури можна виконати так:
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glTexImage2D (GL_TEXTURE_2D, 0, 3,
0, GL_RGB, GL_UNSIGNED_BYTE, falls_image-> data);
Аналогічний результат можна отримати за допомогою функції gluBuild2DMipmaps ():
gluBuild2DMipmaps (GL_TEXTURE_2D, 3,
GL_RGB, GL_UNSIGNED_BYTE, falls_image-> data);
Після створення текстури можна задати її властивості. Для цього є функція:
void glTexParameter [if] (GLenum target, GLenum pname, [int, float] param)
Перший параметр target для двовимірної текстури дорівнює GL_TEXTURE_2D. Другий параметр pname вказує змінюване властивість текстури. Нове значення властивості передається в параметрі param.
Наприклад, якщо текстура створювалася за допомогою glTexImage2D (), то правило підбору текстури для об'єктів з розмірами, що відрізняються від розмірів текстури, можна задавати викликами:
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Цими викликами вказується, що для зменшення і збільшення текстури використовується алгоритм GL_NEAREST. За цим правилом як колір пікселя об'єкта, на який накладається текстура, вибирається колір найближчого тексель. Замість GL_NEAREST можна вказати GL_LINEAR, тоді колір пікселя буде обчислюватися як середнє арифметичне чотирьох найближчих текселов. У OpenGL є ще чотири правила обчислення кольору пікселя шляхом комбінації текселов різних рівнів деталізації.
Крім властивостей текстури, в OpenGL можна задавати властивості взаємодії текстури з об'єктом. Для колірного режиму RGB доступні два режими комбінації кольорів пікселя і тексель. У режимі за замовчуванням (GL_MODULATE) враховується і колір пікселя, і колір тексель. Результуючий колір виходить шляхом множення відповідних компонент пікселя і тексель. Наприклад, якщо колір тексель (Rt. Gt. Bt), а колір пікселя об'єкта, на який накладається текстура, - (Rp. Gp. Bp), то результуючим кольором буде (Rt * Rp. Gt * Gp. Bt * Bp). Якщо об'єкт намальований чорним кольором (0, 0, 0), то текстуру на ньому не буде видно. У другому режимі взаємодії (GL_DECAL) колір об'єкта не враховується, і результуючим кольором завжди буде колір тексель. Ці режими встановлюються таким чином:
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
Після того, як текстури створені і задані з властивості, можна використовувати ці текстури при малюванні примітивів. Накладання текстури здійснюється шляхом зв'язування вершин примітивів і координат текселов. У програмі 7.1 це робиться в функції display (). У ній малюються три квадрата з накладеними текстурами. Функція glTexCoord2d () порівнює координати текселов координатами вершин примітиву.