Ю.М. Баяковский, А.В. Игнатенко - Начальный курс OpenGL (DOC) (1124366), страница 8
Текст из файла (страница 8)
GL LINEAR —интенсивность вычисляется по формуле / = е — z/e — s, где z — расстояние от вершины, в которой вычисляется интенсивность тумана, до точки наблюдения.
Коэффициенты d, e, s задаются с помощью следующих значений аргумента pname:
GL_FOG_DENSITY — param определяет коээфициент d
GL_FOG_START —param определяет коэффициент s
GL FOG END —param определяет коэффициент е.
Цвет тумана задается с помощью аргумента pname, равного GL_FOG_COLOR. В этом случае params — указатель на массив из 4-х компонент цвета.
Приведем пример использования этого эффекта:
GLfloat FogColor[4] = {0.5 ,0.5,0.5,1};
glEnable(GL_FOG);
g 1F о g i (GL_FOG_MODE, GL_LEMEAR);
glFogf (GL_FOG_START, 2 0.0);
glFogf (GL_FOG_END, 100.0);
glFogfv (GL_FOG_COLOR, FogColor );
5.5. Контрольные вопросы
-
Поясните разницу между локальными и бесконечно удаленными источниками света.
-
Для чего служит команда glColorMaterial?
-
Как задать положение источника света таким образом, чтобы он всегда находился в точке положения наблюдателя?
-
Как задать фиксированное положение источника света? Можно ли задавать положение источника относительно локальных координат объекта?
5.5. Контрольные вопросы
75
-
Как задать конусный источник света?
-
Если в сцене включено освещение, но нет источников света, какой цвет будут иметь объекты?
Глава 6. Текстурирование
Под текстурой будем понимать изображение, которое надо определенным образом нанести на объект, например, для придания иллюзии рельефности поверхности.
Для работы с текстурой следует выполнить следующую последовательность действий:
-
выбрать изображение и преобразовать его к нужному формату;
-
передать изображение в OpenGL;
-
определить, как текстура будет наноситься на объект и как она будет с ним взаимодействовать;
-
связать текстуру с объектом.
6.1. Подготовка текстуры
Для использования текстуры необходимо сначала загрузить в память нужное изображение и передать его OpenGL.
77
78
Глава 6. Текстурирование
Считывание графических данных из файла и их преобразование можно проводить вручную. В приложении Б приведен исходный текст функции для загрузки изображения из файла в формате BMP.
Можно также воспользоваться функцией, входящей в состав библиотеки GLAUX (для ее использования надо дополнительно подключить glaux.lib), которая сама проводит необходимые операции. Это функция
AUX_RGBImageRec* auxDIBImageLoad (const char *file)
где file —название файла с расширением *.bmp или *.dib. Функция возвращает указатель на область памяти, где хранятся преобразованные данные.
При создании образа текстуры в памяти следует учитывать указываемые требования. Во-первых, размеры текстуры, как по горизонтали, так и по вертикали должны представлять собой степени двойки. Это требование накладывается для компактного размещения текстуры в текстурной памяти и способствует ее эффективному использованию. Работать только с такими текстурами конечно неудобно, поэтому после загрузки их надо преобразовать. Изменение размеров текстуры можно провести с помощью команды
void gluScalelmage (GLenum format , GLint widthin ,
GL heightin , GLenum typein , const void *datain , GLint widthout ,
GLint heightout , GLenum typeout , void *dataout)
В качестве значения параметра format обычно используется значение GL_RGB или GL_RGBA, определяющее формат хранения информации. Параметры widthin, heightin, widhtout, heightout определяют размеры входного и выходного изображений, а с помощью typein и typeout задается тип элементов массивов, распо-
6.1. Подготовка текстуры
79
ложенных по адресам datain и dataout. Как и обычно, это может быть тип GL_UNSIGNED_BYTE, GL_SHORT, GL_INT и т.д. Результат своей работы функция заносит в область памяти, на которую указывает параметр dataout.
Во-вторых, надо предусмотреть случай, когда объект после растеризации оказывается по размерам значительно меньше наносимой на него текстуры. Чем меньше объект, тем меньше должна быть наносимая на него текстура и поэтому вводится понятие уровней детализации текстуры (mipmap). Каждый уровень детализации задает некоторое изображение, которое является, как правило, уменьшенной в два раза копией оригинала. Такой подход позволяет улучшить качество нанесения текстуры на объект. Например, для изображения размером 2т х 2п можно построить тах(т, п) + 1 уменьшенных изображений, соответствующих различным уровням детализации.
Эти два этапа создания образа текстуры во внутренней памяти OpenGL можно провести с помощью команды
void gluBuild2DMipmaps (GLenum target ,
GLint components , GLint width , GLint height , GLenum format , GLenum type , const void *data)
где параметр target должен быть равен GL_TEXTURE_2D. Параметр components определяет количество цветовых компонент текстуры и может принимать следующие основные значения:
GL_LUMINANCE —одна компонента — яркость (текстура будет монохромной);
GL RGB —красный, синий, зеленый;
GL RGBA —красный, синий, зеленый, альфа (см. п. 7.1).
Параметры width, height, data определяют размеры и расположение текстуры соответственно, a format и type имеют аналогичный смысл, что и в команде gluScalelmageQ.
80
Глава 6. Текстурирование
После выполнения этой команды текстура копируется во внутреннюю память OpenGL, и поэтому память, занимаемую исходным изображением, можно освободить.
В OpenGL допускается использование одномерных текстур, то есть размера 1 х N, однако это всегда надо указывать, задавая в качестве значения target константу GL_TEXTURE_1D. Одномерные текстуры используются достаточно редко, поэтому не будем останавливаться на этом подробно.
При использовании в сцене нескольких текстур, в OpenGL применяется подход, напоминающий создание списков изображений (так называемые текстурные объекты). Сначала с помощью команды
void glGenTextures (GLsizei n, GLuint* textures)
надо создать п идентификаторов текстур, которые будут записаны в массив textures. Перед началом определения свойств очередной текстуры следует сделать ее текущей («привязать» текстуру), вызвав команду
void glBindTexture (GLenum target , GLuint texture)
где target может принимать значения GL_TEXTURE_1D или GL_TEXTURE_2D, а параметр texture должен быть равен идентификатору той текстуры, к которой будут относиться последующие команды. Для того, чтобы в процессе рисования сделать текущей текстуру с некоторым идентификатором, достаточно опять вызвать команду glBindTextureQ с соответствующим значением target и texture. Таким образом, команда glBindTextureQ включает режим создания текстуры с идентификатором texture, если такая текстура еще не создана, либо режим ее использования, то есть делает эту текстуру текущей.
Так как не всякая аппаратура может оперировать текстурами большого размера, целесообразно ограничить размеры текстуры до 256 х 256 или 512 х 512 пикселей. Отметим, что использование небольших текстур повышает эффективность программы.
6.2. Наложение текстуры на объекты
81
6.2. Наложение текстуры на объекты
При наложении текстуры, как уже упоминалось, надо учитывать случай, когда размеры текстуры отличаются от оконных размеров объекта, на который она накладывается. При этом возможно как растяжение, так и сжатие изображения, и то, как будут проводиться эти преобразования, может серьезно повлиять на качество построенного изображения. Для определения положения точки на текстуре используется параметрическая система координат (s,t), причем значения s и t находятся в отрезке [0,1] (см. рисунок 6.1)
(0,1) (1, 1)
(0,0) (1,0)
Рис. 6.1. Текстурные координаты
Для изменения различных параметров текстуры применяются команды:
void glTexParameter [ i f] (GLenum target , GLenum pname,
GLenum param) void glTexParameter [ i f]v (GLenum target , GLenum pname,
Glenum* params)
Параметр target принимает значения GL_TEXTURE_1D или GL_TEXTURE_2D, pname определяет, какое свойство будем менять, а с помощью param или params устанавливается новое значение. Возможные значения pname:
GL TEXTURE MIN FILTER —параметр param опреде-
82
Глава 6. Текстурирование
ляет функцию, которая будет использоваться для сжатия текстуры. При значении GL_NEAREST будет использоваться один (ближайший), а при значении GL_LINEAR — четыре ближайших элемента текстуры.
Значение по умолчанию: GL_LINEAR.
GL_TEXTURE_MAG_FILTER —параметр param определяет функцию, которая будет использоваться для увеличения (растяжения) текстуры. При значении GL_NEAREST будет использоваться один (ближайший), а при значении GL_LINEAR — четыре ближайших элемента текстуры.
Значение по умолчанию: GL_LINEAR.
GL_TEXTURE_WRAP_S —параметр param устанавливает значение координаты s, если оно не входит в отрезок [0,1]. При значении GL_REPEAT целая часть s отбрасывается, и в результате изображение размножается по поверхности. При значении GL_CLAMP используются краевые значения (0 или 1), что удобно использовать, если на объект накладывается один образ.
Значение по умолчанию: GL_REPEAT.
GL_TEXTURE_WRAP_T — аналогично предыдущему значению, только для координаты t.
Использование режима GL_NEAREST повышает скорость наложения текстуры, однако при этом снижается качество, так как, в отличие от GL_LINEAR, интерполяция не производится.
Для того чтобы определить, как текстура будет взаимодействовать с материалом, из которого сделан объект, используются команды
void glTexEnv [ i f] (GLenum target , GLenum pname,
GLtype param)
void glTexEnv [ i f]v (GLenum target , GLenum pname,
GLtype *params)
6.2. Наложение текстуры на объекты
83
Параметр target должен быть равен GL_TEXTURE_ENV, а в качестве pname рассмотрим только одно значение GL_TEXTURE_ENV_MODE, которое применяется наиболее часто.
Наиболее часто используемые значения параметра param:
GL MODULATE — конечный цвет находится как произведение цвета точки на поверхности и цвета соответствующей ей точки на текстуре.
GL REPLACE —в качестве конечного цвета используется цвет точки на текстуре.
Следующий пример кода демонстрирует общий подход к созданию текстур:
/* нужное нам количество текстур */
#define NUM_TEXTURES 10
/* идентификаторы текстур */
int TextureIDs[NUM_TEXTURES] ;
/* образ текстуры */
AUX_RGBImageRec *plmage;
/* 1) получаем идентификаторы текстур */ glGenTextures (NUMJTEXTURES, TexturelDs );
/* 2) выбираем текстуру для модификации параметров */ glBindTexture( TexturelDs [i ]) ; /* 0<=i<NUM_TEXTUBES*/
/* 3) загружаем текстуру.
Размеры текстуры " степень 2 */
pImage=dibImageLoad (" texture .bmp" );
if (Texture!=NULL)
{
/* 4) передаем текстуру OpenGL и задаем параметры*/
84
Глава 6. Текстурирование
/* выравнивание по байту */ glPixelStorei (GLJJNPACK_ ALIGNMENT, 1);
gluBuildMipmaps(GL_TEXTURE_2D,GL_RGB, pImage->sizeX , pImage->sizeY , GL_RGB, GL_UNSIGNED_BYTE, plmage—>data ) ;
g 1T e x P a r a m e t e r f (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, ( float )GL_IJNEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, ( float )GL_IJNEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, ( float )GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, ( float )GL_REPEAT);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, ( float )GL_REPLACE) ;
/* 5) удаляем исходное, изображение.*/ free ( Texture);