Создание текстуры в оперативной памяти
Изображения текстур часто хранятся в файлах. Для ускорения вычислений в OpenGL размеры изображений текстур должны быть кратны степеням 2, т.е. равны 2nx2m, где 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; AUX_RGBImageRec* falls_image; unsigned int sawdust_tex; AUX_RGBImageRec* sawdust_image; Переменные 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, но сама текстура еще создана. Кроме байт изображения, у текстуры есть набор свойств, влияющих на наложение текстуры на объект. Например, это уровень детализации, способ масштабирования и связывания текстуры с объектом. Эти свойства задаются при создании текстуры. С помощью уровня детализации можно задать несколько изображений для одной текстуры, что позволяет более точно накладывать текстуру на объекты, размеры двумерных проекций которых меньшие размеров текстуры. Нулевой уровень детализации соответствует исходному изображению размером 2nx2m, первый уровень – 2n-1x2m-1, k -ый уровень – 2n-kx2m-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, falls_image->sizeX, falls_image->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, falls_image->data); Аналогичный результат можно получить с помощью функции gluBuild2DMipmaps(): gluBuild2DMipmaps(GL_TEXTURE_2D, 3, falls_image->sizeX, falls_image->sizeY, 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() сопоставляет координаты текселов координатам вершин примитива.
При использовании функции glTexCoord2d() надо иметь в виду, что левый нижний угол текстуры имеет координаты (0, 0), а верхний правый – координаты (1, 1) (рис. 7.2). Изменив порядок сопоставления координат, можно перевернуть текстуру (рис. 7.3).
#include <windows.h> #include <GL/gl.h> #include <GL/glu.h> #include <GL/glaux.h>
const char* falls_filename = "falls.bmp"; unsigned int falls_tex; AUX_RGBImageRec* falls_image; const char* sawdust_filename = "sawdust.bmp"; unsigned int sawdust_tex; AUX_RGBImageRec* sawdust_image;
void opengl_init() { glEnable(GL_AUTO_NORMAL); glEnable(GL_NORMALIZE); glEnable(GL_DEPTH_TEST); glEnable(GL_ALPHA_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_COLOR_MATERIAL);
float pos[4] = { 0, 3, 5, 1 }; glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_POSITION, pos); }
void textures_init() { glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
falls_image = auxDIBImageLoad(falls_filename); sawdust_image = auxDIBImageLoad(sawdust_filename);
glGenTextures(1, &falls_tex); glGenTextures(1, &sawdust_tex);
glBindTexture(GL_TEXTURE_2D, falls_tex); glTexImage2D(GL_TEXTURE_2D, 0, 3, falls_image->sizeX, falls_image->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, falls_image->data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, sawdust_tex); glTexImage2D(GL_TEXTURE_2D, 0, 3, sawdust_image->sizeX, sawdust_image->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, sawdust_image->data); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); }
void CALLBACK resize(int width, int height) { glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-6,6, -6,6, 2,15); gluLookAt(5,5,5, 0,0,-1.5, 0,1,0); glMatrixMode(GL_MODELVIEW); }
void CALLBACK display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_TEXTURE_2D); glColor3d(1, 1, 1);
glBindTexture(GL_TEXTURE_2D, falls_tex); glBegin(GL_QUADS); glTexCoord2d(0, 0); glVertex3d(-3, -3, 0); glTexCoord2d(0, 1); glVertex3d(-3, 3, 0); glTexCoord2d(1, 1); glVertex3d(3, 3, 0); glTexCoord2d(1, 0); glVertex3d(3, -3, 0); glEnd();
glBindTexture(GL_TEXTURE_2D, sawdust_tex); glBegin(GL_QUADS); glTexCoord2d(0, 0); glVertex3d(-3, 3, 0); glTexCoord2d(0, 1); glVertex3d(-3, 3, -6); glTexCoord2d(1, 1); glVertex3d(3, 3, -6); glTexCoord2d(1, 0); glVertex3d(3, 3, 0); glEnd(); glBegin(GL_QUADS); glTexCoord2d(0, 0); glVertex3d(3, 3, 0); glTexCoord2d(0, 1); glVertex3d(3, 3, -6); glTexCoord2d(1, 1); glVertex3d(3, -3, -6); glTexCoord2d(1, 0); glVertex3d(3, -3, 0); glEnd();
glDisable(GL_TEXTURE_2D); auxSwapBuffers(); }
void main() { auxInitPosition(50, 10, 400, 400); auxInitDisplayMode(AUX_RGB | AUX_DEPTH | AUX_DOUBLE); auxInitWindow("Лекция 7. Программа 7.1."); opengl_init(); textures_init(); auxReshapeFunc(resize); auxMainLoop(display); } Программа 7.1. Наложение текстур на плоские многоугольники.
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|